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.