Main Page   Modules   Data Structures   File List   Data Fields   Globals  

dump.c

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

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