Main Page   Modules   Data Structures   File List   Data Fields   Globals   Related Pages  

dump.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 1999 - 2003
00003  * NetGroup, Politecnico di Torino (Italy)
00004  * All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  *
00010  * 1. Redistributions of source code must retain the above copyright
00011  * notice, this list of conditions and the following disclaimer.
00012  * 2. Redistributions in binary form must reproduce the above copyright
00013  * notice, this list of conditions and the following disclaimer in the
00014  * documentation and/or other materials provided with the distribution.
00015  * 3. Neither the name of the Politecnico di Torino nor the names of its
00016  * contributors may be used to endorse or promote products derived from
00017  * this software without specific prior written permission.
00018  *
00019  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00020  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00021  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
00022  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
00023  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00024  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00025  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00026  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00027  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00028  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00029  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00030  *
00031  */
00032 
00033 #include <stdarg.h>
00034 #include <ntddk.h>
00035 #include <ntiologc.h>
00036 #include <ndis.h>
00037 #include "debug.h"
00038 #include "packet.h"
00039 
00040 #include "win_bpf.h"
00041 
00042 //-------------------------------------------------------------------
00043 
00044 NTSTATUS
00045 NPF_OpenDumpFile(POPEN_INSTANCE Open , PUNICODE_STRING fileName, BOOLEAN Append)
00046 {
00047     NTSTATUS ntStatus;
00048     IO_STATUS_BLOCK IoStatus;
00049     OBJECT_ATTRIBUTES ObjectAttributes;
00050     PWCHAR PathPrefix;
00051     USHORT PathLen;
00052     UNICODE_STRING FullFileName;
00053     ULONG FullFileNameLength;
00054     PDEVICE_OBJECT fsdDevice;
00055 
00056     FILE_STANDARD_INFORMATION StandardInfo;
00057     
00058     IF_LOUD(DbgPrint("NPF: OpenDumpFile.\n");)
00059 
00060     if(fileName->Buffer[0] == L'\\' &&
00061         fileName->Buffer[1] == L'?' &&
00062         fileName->Buffer[2] == L'?' &&
00063         fileName->Buffer[3] == L'\\'
00064     ){
00065         PathLen = 0;
00066     }
00067     else{
00068         PathPrefix = L"\\??\\";
00069         PathLen = 8;
00070     }
00071     
00072     // Insert the correct path prefix.
00073     FullFileNameLength = PathLen + fileName->MaximumLength;
00074     
00075     FullFileName.Buffer = ExAllocatePoolWithTag(NonPagedPool, 
00076         FullFileNameLength,
00077         '0DWA');
00078     
00079     if (FullFileName.Buffer == NULL) {
00080         ntStatus = STATUS_INSUFFICIENT_RESOURCES;
00081         return ntStatus;
00082     }
00083     
00084     FullFileName.Length = PathLen;
00085     FullFileName.MaximumLength = (USHORT)FullFileNameLength;
00086     
00087     if(PathLen)
00088         RtlMoveMemory (FullFileName.Buffer, PathPrefix, PathLen);
00089     
00090     RtlAppendUnicodeStringToString (&FullFileName, fileName);
00091     
00092     IF_LOUD(DbgPrint( "Packet: Attempting to open %wZ\n", &FullFileName);)
00093     
00094     InitializeObjectAttributes ( &ObjectAttributes,
00095         &FullFileName,
00096         OBJ_CASE_INSENSITIVE,
00097         NULL,
00098         NULL );
00099     
00100     // Create the dump file
00101     ntStatus = ZwCreateFile( &Open->DumpFileHandle,
00102         SYNCHRONIZE | FILE_WRITE_DATA,
00103         &ObjectAttributes,
00104         &IoStatus,
00105         NULL,
00106         FILE_ATTRIBUTE_NORMAL,
00107         FILE_SHARE_READ,
00108         (Append)?FILE_OPEN_IF:FILE_SUPERSEDE,
00109         FILE_SYNCHRONOUS_IO_NONALERT,
00110         NULL,
00111         0 );
00112 
00113     if ( !NT_SUCCESS( ntStatus ) )
00114     {
00115         IF_LOUD(DbgPrint("NPF: Error opening file %x\n", ntStatus);)
00116         
00117         ExFreePool(FullFileName.Buffer);
00118         Open->DumpFileHandle=NULL;
00119         ntStatus = STATUS_NO_SUCH_FILE;
00120         return ntStatus;
00121     }
00122     
00123     ExFreePool(FullFileName.Buffer);
00124     
00125     ntStatus = ObReferenceObjectByHandle(Open->DumpFileHandle,
00126         FILE_WRITE_ACCESS,
00127         *IoFileObjectType,
00128         KernelMode,
00129         &Open->DumpFileObject,
00130         0);
00131     
00132     if ( !NT_SUCCESS( ntStatus ) )
00133     {
00134         IF_LOUD(DbgPrint("NPF: Error creating file, status=%x\n", ntStatus);)
00135             
00136         ZwClose( Open->DumpFileHandle );
00137         Open->DumpFileHandle=NULL;
00138         
00139         ntStatus = STATUS_NO_SUCH_FILE;
00140         return ntStatus;
00141     }
00142     
00143     fsdDevice = IoGetRelatedDeviceObject(Open->DumpFileObject);
00144 
00145     IF_LOUD(DbgPrint("NPF: Dump: write file created succesfully, status=%d \n",ntStatus);)
00146 
00147     return ntStatus;
00148 }   
00149 
00150 //-------------------------------------------------------------------
00151 
00152 NTSTATUS
00153 NPF_StartDump(POPEN_INSTANCE Open)
00154 {
00155     NTSTATUS ntStatus;
00156     struct packet_file_header hdr;
00157     IO_STATUS_BLOCK IoStatus;
00158     NDIS_REQUEST pRequest;
00159     ULONG MediaType;
00160     OBJECT_ATTRIBUTES ObjectAttributes;
00161 
00162     IF_LOUD(DbgPrint("NPF: StartDump.\n");)
00163 
00164     // Init the file header
00165     hdr.magic = TCPDUMP_MAGIC;
00166     hdr.version_major = PCAP_VERSION_MAJOR;
00167     hdr.version_minor = PCAP_VERSION_MINOR;
00168     hdr.thiszone = 0; /*Currently not set*/
00169     hdr.snaplen = 1514;
00170     hdr.sigfigs = 0;
00171 
00172     // Detect the medium type
00173     switch (Open->Medium){
00174         
00175     case NdisMediumWan:
00176         hdr.linktype = DLT_EN10MB;
00177         break;
00178         
00179     case NdisMedium802_3:
00180         hdr.linktype = DLT_EN10MB;
00181         break;
00182         
00183     case NdisMediumFddi:
00184         hdr.linktype = DLT_FDDI;
00185         break;
00186         
00187     case NdisMedium802_5:           
00188         hdr.linktype = DLT_IEEE802; 
00189         break;
00190         
00191     case NdisMediumArcnet878_2:
00192         hdr.linktype = DLT_ARCNET;
00193         break;
00194         
00195     case NdisMediumAtm:
00196         hdr.linktype = DLT_ATM_RFC1483;
00197         break;
00198         
00199     default:
00200         hdr.linktype = DLT_EN10MB;
00201     }
00202 
00203     // Write the header.
00204     // We can use ZwWriteFile because we are in the context of the application
00205     ntStatus = ZwWriteFile(Open->DumpFileHandle,
00206         NULL,
00207         NULL,
00208         NULL,
00209         &IoStatus,
00210         &hdr,
00211         sizeof(hdr),
00212         NULL,
00213         NULL );
00214 
00215     
00216     if ( !NT_SUCCESS( ntStatus ) )
00217     {
00218         IF_LOUD(DbgPrint("NPF: Error dumping file %x\n", ntStatus);)
00219         
00220         ZwClose( Open->DumpFileHandle );
00221         Open->DumpFileHandle=NULL;
00222         
00223         ntStatus = STATUS_NO_SUCH_FILE;
00224         return ntStatus;
00225     }
00226 
00227     Open->DumpOffset.QuadPart=24;
00228             
00229     ntStatus = PsCreateSystemThread(&Open->DumpThreadHandle,
00230         THREAD_ALL_ACCESS,
00231         (ACCESS_MASK)0L,
00232         0,
00233         0,
00234         NPF_DumpThread,
00235         Open);
00236     
00237     if ( !NT_SUCCESS( ntStatus ) )
00238     {
00239         IF_LOUD(DbgPrint("NPF: Error creating dump thread, status=%x\n", ntStatus);)
00240         
00241         ZwClose( Open->DumpFileHandle );
00242         Open->DumpFileHandle=NULL;
00243 
00244         return ntStatus;
00245     }  
00246 
00247     ntStatus = ObReferenceObjectByHandle(Open->DumpThreadHandle,
00248         THREAD_ALL_ACCESS,
00249         NULL,
00250         KernelMode,
00251         &Open->DumpThreadObject,
00252         0);
00253 
00254     if ( !NT_SUCCESS( ntStatus ) )
00255     {
00256         IF_LOUD(DbgPrint("NPF: Error creating dump thread, status=%x\n", ntStatus);)
00257         
00258         ObDereferenceObject(Open->DumpFileObject);
00259         ZwClose( Open->DumpFileHandle );
00260         Open->DumpFileHandle=NULL;
00261 
00262         return ntStatus;
00263     }  
00264 
00265     
00266     return ntStatus;
00267     
00268 }
00269 
00270 //-------------------------------------------------------------------
00271 // Dump Thread
00272 //-------------------------------------------------------------------
00273 
00274 VOID NPF_DumpThread(POPEN_INSTANCE Open)
00275 {
00276     ULONG       FrozenNic;
00277 
00278     IF_LOUD(DbgPrint("NPF: In the work routine.  Parameter = 0x%0x\n",Open);)
00279 
00280     while(TRUE){
00281 
00282         // Wait until some packets arrive or the timeout expires
00283         NdisWaitEvent(&Open->DumpEvent, 5000);  
00284 
00285         IF_LOUD(DbgPrint("NPF: Worker Thread - event signalled\n");)
00286             
00287         if(Open->DumpLimitReached ||
00288             Open->Size==0){     // BufSize=0 means that this instance was closed, or that the buffer is too
00289                                     // small for any capture. In both cases it is better to end the dump
00290 
00291             IF_LOUD(DbgPrint("NPF: Worker Thread - Exiting happily\n");)
00292             IF_LOUD(DbgPrint("Thread: Dumpoffset=%I64d\n",Open->DumpOffset.QuadPart);)
00293 
00294             PsTerminateSystemThread(STATUS_SUCCESS);
00295             return;
00296         }
00297         
00298         NdisResetEvent(&Open->DumpEvent);
00299 
00300         // Write the content of the buffer to the file
00301         if(NPF_SaveCurrentBuffer(Open) != STATUS_SUCCESS){
00302             PsTerminateSystemThread(STATUS_SUCCESS);
00303             return;
00304         }
00305     
00306     }
00307 
00308 }
00309 
00310 //-------------------------------------------------------------------
00311 
00312 NTSTATUS NPF_SaveCurrentBuffer(POPEN_INSTANCE Open)
00313 {
00314     UINT        Thead;
00315     UINT        Ttail;
00316     UINT        TLastByte;
00317     PUCHAR      CurrBuff;
00318     NTSTATUS    ntStatus;
00319     IO_STATUS_BLOCK IoStatus;
00320     PMDL        lMdl;
00321     UINT        SizeToDump;
00322 
00323 #if 0
00324 
00325     Thead=Open->Bhead;
00326     Ttail=Open->Btail;
00327     TLastByte=Open->BLastByte;
00328     
00329     IF_LOUD(DbgPrint("NPF: NPF_SaveCurrentBuffer.\n");)
00330 
00331     // Get the address of the buffer
00332     CurrBuff=Open->Buffer;
00333     //
00334     // Fill the application buffer
00335     //
00336     if( Ttail < Thead )
00337     {
00338         if(Open->MaxDumpBytes &&
00339             (UINT)Open->DumpOffset.QuadPart /*+ GetBuffOccupation(Open)*/ > Open->MaxDumpBytes)
00340         {
00341             // Size limit reached
00342             UINT PktLen;
00343             
00344             SizeToDump = 0;
00345             
00346             // Scan the buffer to detect the exact amount of data to save
00347             while(TRUE){
00348                 PktLen = ((struct sf_pkthdr*)(CurrBuff + Thead + SizeToDump))->caplen + sizeof(struct sf_pkthdr);
00349                 
00350                 if((UINT)Open->DumpOffset.QuadPart + SizeToDump + PktLen > Open->MaxDumpBytes)
00351                     break;
00352                 
00353                 SizeToDump += PktLen;
00354             }
00355             
00356         }
00357         else
00358             SizeToDump = TLastByte-Thead;
00359         
00360         lMdl=IoAllocateMdl(CurrBuff+Thead, SizeToDump, FALSE, FALSE, NULL);
00361         if (lMdl == NULL)
00362         {
00363             // No memory: stop dump
00364             IF_LOUD(DbgPrint("NPF: dump thread: Failed to allocate Mdl\n");)
00365             return STATUS_UNSUCCESSFUL;
00366         }
00367         
00368         MmBuildMdlForNonPagedPool(lMdl);
00369         
00370         // Write to disk
00371         NPF_WriteDumpFile(Open->DumpFileObject,
00372             &Open->DumpOffset,
00373             SizeToDump,
00374             lMdl,
00375             &IoStatus);
00376         
00377         IoFreeMdl(lMdl);
00378         
00379         if(!NT_SUCCESS(IoStatus.Status)){
00380             // Error
00381             return STATUS_UNSUCCESSFUL;
00382         }
00383         
00384         if(SizeToDump != TLastByte-Thead){
00385             // Size limit reached.
00386             Open->DumpLimitReached = TRUE;
00387     
00388             // Awake the application
00389             KeSetEvent(Open->ReadEvent,0,FALSE);
00390 
00391             return STATUS_UNSUCCESSFUL;
00392         }
00393         
00394         // Update the packet buffer
00395         Open->DumpOffset.QuadPart+=(TLastByte-Thead);
00396         Open->BLastByte=Ttail;
00397         Open->Bhead=0;
00398     }
00399 
00400     if( Ttail > Thead ){
00401         
00402         if(Open->MaxDumpBytes &&
00403             (UINT)Open->DumpOffset.QuadPart /* +GetBuffOccupation(Open)*/ > Open->MaxDumpBytes)
00404         {
00405             // Size limit reached
00406             UINT PktLen;
00407                         
00408             SizeToDump = 0;
00409             
00410             // Scan the buffer to detect the exact amount of data to save
00411             while(Thead + SizeToDump < Ttail){
00412 
00413                 PktLen = ((struct sf_pkthdr*)(CurrBuff + Thead + SizeToDump))->caplen + sizeof(struct sf_pkthdr);
00414                 
00415                 if((UINT)Open->DumpOffset.QuadPart + SizeToDump + PktLen > Open->MaxDumpBytes)
00416                     break;
00417                 
00418                 SizeToDump += PktLen;
00419             }
00420             
00421         }
00422         else
00423             SizeToDump = Ttail-Thead;
00424                 
00425         lMdl=IoAllocateMdl(CurrBuff+Thead, SizeToDump, FALSE, FALSE, NULL);
00426         if (lMdl == NULL)
00427         {
00428             // No memory: stop dump
00429             IF_LOUD(DbgPrint("NPF: dump thread: Failed to allocate Mdl\n");)
00430             return STATUS_UNSUCCESSFUL;
00431         }
00432         
00433         MmBuildMdlForNonPagedPool(lMdl);
00434         
00435         // Write to disk
00436         NPF_WriteDumpFile(Open->DumpFileObject,
00437             &Open->DumpOffset,
00438             SizeToDump,
00439             lMdl,
00440             &IoStatus);
00441         
00442         IoFreeMdl(lMdl);
00443         
00444         if(!NT_SUCCESS(IoStatus.Status)){
00445             // Error
00446             return STATUS_UNSUCCESSFUL;
00447         }
00448         
00449         if(SizeToDump != Ttail-Thead){
00450             // Size limit reached.
00451             Open->DumpLimitReached = TRUE;
00452 
00453             // Awake the application
00454             KeSetEvent(Open->ReadEvent,0,FALSE);
00455             
00456             return STATUS_UNSUCCESSFUL;
00457         }
00458         
00459         // Update the packet buffer
00460         Open->DumpOffset.QuadPart+=(Ttail-Thead);           
00461         Open->Bhead=Ttail;
00462         
00463     }
00464 #endif
00465     return STATUS_SUCCESS;
00466 }
00467 
00468 //-------------------------------------------------------------------
00469 
00470 NTSTATUS NPF_CloseDumpFile(POPEN_INSTANCE Open){
00471     NTSTATUS    ntStatus;
00472     IO_STATUS_BLOCK IoStatus;
00473     PMDL        WriteMdl;
00474     PUCHAR      VMBuff;
00475     UINT        VMBufLen;
00476 
00477 #if 0
00478     IF_LOUD(DbgPrint("NPF: NPF_CloseDumpFile.\n");)
00479     IF_LOUD(DbgPrint("Dumpoffset=%d\n",Open->DumpOffset.QuadPart);)
00480 
00481 DbgPrint("1\n");
00482     // Consistency check
00483     if(Open->DumpFileHandle == NULL)
00484         return STATUS_UNSUCCESSFUL;
00485 
00486 DbgPrint("2\n");
00487     ZwClose( Open->DumpFileHandle );
00488 
00489     ObDereferenceObject(Open->DumpFileObject);
00490 /*
00491     if(Open->DumpLimitReached == TRUE)
00492         // Limit already reached: don't save the rest of the buffer.
00493         return STATUS_SUCCESS;
00494 */
00495 DbgPrint("3\n");
00496 
00497     NPF_OpenDumpFile(Open,&Open->DumpFileName, TRUE);
00498 
00499     // Flush the buffer to file 
00500     NPF_SaveCurrentBuffer(Open);
00501 
00502     // Close The file
00503     ObDereferenceObject(Open->DumpFileObject);
00504     ZwClose( Open->DumpFileHandle );
00505     
00506     Open->DumpFileHandle = NULL;
00507 
00508     ObDereferenceObject(Open->DumpFileObject);
00509 #endif
00510     return STATUS_SUCCESS;
00511 }
00512 
00513 //-------------------------------------------------------------------
00514 
00515 static NTSTATUS PacketDumpCompletion(PDEVICE_OBJECT DeviceObject,
00516                                 PIRP Irp,
00517                                 PVOID Context)
00518 {
00519 
00520     // Copy the status information back into the "user" IOSB
00521     *Irp->UserIosb = Irp->IoStatus;
00522     
00523     // Wake up the mainline code
00524     KeSetEvent(Irp->UserEvent, 0, FALSE);
00525           
00526     return STATUS_MORE_PROCESSING_REQUIRED;
00527 }
00528 
00529 //-------------------------------------------------------------------
00530 
00531 VOID NPF_WriteDumpFile(PFILE_OBJECT FileObject,
00532                                 PLARGE_INTEGER Offset,
00533                                 ULONG Length,
00534                                 PMDL Mdl,
00535                                 PIO_STATUS_BLOCK IoStatusBlock)
00536 {
00537     PIRP irp;
00538     KEVENT event;
00539     PIO_STACK_LOCATION ioStackLocation;
00540     PDEVICE_OBJECT fsdDevice = IoGetRelatedDeviceObject(FileObject);
00541     NTSTATUS Status;
00542  
00543     // Set up the event we'll use
00544     KeInitializeEvent(&event, SynchronizationEvent, FALSE);
00545     
00546     // Allocate and build the IRP we'll be sending to the FSD
00547     irp = IoAllocateIrp(fsdDevice->StackSize, FALSE);
00548 
00549     if (!irp) {
00550         // Allocation failed, presumably due to memory allocation failure
00551         IoStatusBlock->Status = STATUS_INSUFFICIENT_RESOURCES;
00552         IoStatusBlock->Information = 0;
00553 
00554         return;
00555     }
00556     
00557     irp->MdlAddress = Mdl;
00558     irp->UserEvent = &event;
00559     irp->UserIosb = IoStatusBlock;
00560     irp->Tail.Overlay.Thread = PsGetCurrentThread();
00561     irp->Tail.Overlay.OriginalFileObject= FileObject;    
00562     irp->RequestorMode = KernelMode;
00563     
00564     // Indicate that this is a WRITE operation
00565     irp->Flags = IRP_WRITE_OPERATION;    
00566     
00567     // Set up the next I/O stack location
00568     ioStackLocation = IoGetNextIrpStackLocation(irp);
00569     ioStackLocation->MajorFunction = IRP_MJ_WRITE;
00570     ioStackLocation->MinorFunction = 0;
00571     ioStackLocation->DeviceObject = fsdDevice;
00572     ioStackLocation->FileObject = FileObject;
00573     IoSetCompletionRoutine(irp, PacketDumpCompletion, 0, TRUE, TRUE, TRUE);    
00574     ioStackLocation->Parameters.Write.Length = Length;    
00575     ioStackLocation->Parameters.Write.ByteOffset = *Offset;
00576     
00577 
00578     // Send it on.  Ignore the return code
00579     (void) IoCallDriver(fsdDevice, irp);
00580      
00581     // Wait for the I/O to complete.
00582     KeWaitForSingleObject(&event, Executive, KernelMode, TRUE, 0);
00583 
00584     // Free the IRP now that we are done with it
00585     IoFreeIrp(irp);
00586 
00587     return;
00588 
00589 }

documentation. Copyright (c) 2002-2003 Politecnico di Torino. All rights reserved.