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, 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->Size==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 #if 0
    00313
    00314     Thead=Open->Bhead;
    00315     Ttail=Open->Btail;
    00316     TLastByte=Open->BLastByte;
    00317
    00318     IF_LOUD(DbgPrint("NPF: NPF_SaveCurrentBuffer.\n");)
    00319
    00320     // Get the address of the buffer
    00321     CurrBuff=Open->Buffer;
    00322     //
    00323     // Fill the application buffer
    00324     //
    00325     if( Ttail < Thead )
    00326     {
    00327         if(Open->MaxDumpBytes &&
    00328             (UINT)Open->DumpOffset.QuadPart /*+ GetBuffOccupation(Open)*/ > Open->MaxDumpBytes)
    00329         {
    00330             // Size limit reached
    00331             UINT PktLen;
    00332
    00333             SizeToDump = 0;
    00334
    00335             // Scan the buffer to detect the exact amount of data to save
    00336             while(TRUE){
    00337                 PktLen = ((struct sf_pkthdr*)(CurrBuff + Thead + SizeToDump))->caplen + sizeof(struct sf_pkthdr);
    00338
    00339                 if((UINT)Open->DumpOffset.QuadPart + SizeToDump + PktLen > Open->MaxDumpBytes)
    00340                     break;
    00341
    00342                 SizeToDump += PktLen;
    00343             }
    00344
    00345         }
    00346         else
    00347             SizeToDump = TLastByte-Thead;
    00348
    00349         lMdl=IoAllocateMdl(CurrBuff+Thead, SizeToDump, FALSE, FALSE, NULL);
    00350         if (lMdl == NULL)
    00351         {
    00352             // No memory: stop dump
    00353             IF_LOUD(DbgPrint("NPF: dump thread: Failed to allocate Mdl\n");)
    00354             return STATUS_UNSUCCESSFUL;
    00355         }
    00356
    00357         MmBuildMdlForNonPagedPool(lMdl);
    00358
    00359         // Write to disk
    00360         NPF_WriteDumpFile(Open->DumpFileObject,
    00361             &Open->DumpOffset,
    00362             SizeToDump,
    00363             lMdl,
    00364             &IoStatus);
    00365
    00366         IoFreeMdl(lMdl);
    00367
    00368         if(!NT_SUCCESS(IoStatus.Status)){
    00369             // Error
    00370             return STATUS_UNSUCCESSFUL;
    00371         }
    00372
    00373         if(SizeToDump != TLastByte-Thead){
    00374             // Size limit reached.
    00375             Open->DumpLimitReached = TRUE;
    00376
    00377             // Awake the application
    00378             KeSetEvent(Open->ReadEvent,0,FALSE);
    00379
    00380             return STATUS_UNSUCCESSFUL;
    00381         }
    00382
    00383         // Update the packet buffer
    00384         Open->DumpOffset.QuadPart+=(TLastByte-Thead);
    00385         Open->BLastByte=Ttail;
    00386         Open->Bhead=0;
    00387     }
    00388
    00389     if( Ttail > Thead ){
    00390
    00391         if(Open->MaxDumpBytes &&
    00392             (UINT)Open->DumpOffset.QuadPart /* +GetBuffOccupation(Open)*/ > Open->MaxDumpBytes)
    00393         {
    00394             // Size limit reached
    00395             UINT PktLen;
    00396
    00397             SizeToDump = 0;
    00398
    00399             // Scan the buffer to detect the exact amount of data to save
    00400             while(Thead + SizeToDump < Ttail){
    00401
    00402                 PktLen = ((struct sf_pkthdr*)(CurrBuff + Thead + SizeToDump))->caplen + sizeof(struct sf_pkthdr);
    00403
    00404                 if((UINT)Open->DumpOffset.QuadPart + SizeToDump + PktLen > Open->MaxDumpBytes)
    00405                     break;
    00406
    00407                 SizeToDump += PktLen;
    00408             }
    00409
    00410         }
    00411         else
    00412             SizeToDump = Ttail-Thead;
    00413
    00414         lMdl=IoAllocateMdl(CurrBuff+Thead, SizeToDump, FALSE, FALSE, NULL);
    00415         if (lMdl == NULL)
    00416         {
    00417             // No memory: stop dump
    00418             IF_LOUD(DbgPrint("NPF: dump thread: Failed to allocate Mdl\n");)
    00419             return STATUS_UNSUCCESSFUL;
    00420         }
    00421
    00422         MmBuildMdlForNonPagedPool(lMdl);
    00423
    00424         // Write to disk
    00425         NPF_WriteDumpFile(Open->DumpFileObject,
    00426             &Open->DumpOffset,
    00427             SizeToDump,
    00428             lMdl,
    00429             &IoStatus);
    00430
    00431         IoFreeMdl(lMdl);
    00432
    00433         if(!NT_SUCCESS(IoStatus.Status)){
    00434             // Error
    00435             return STATUS_UNSUCCESSFUL;
    00436         }
    00437
    00438         if(SizeToDump != Ttail-Thead){
    00439             // Size limit reached.
    00440             Open->DumpLimitReached = TRUE;
    00441
    00442             // Awake the application
    00443             KeSetEvent(Open->ReadEvent,0,FALSE);
    00444
    00445             return STATUS_UNSUCCESSFUL;
    00446         }
    00447
    00448         // Update the packet buffer
    00449         Open->DumpOffset.QuadPart+=(Ttail-Thead);
    00450         Open->Bhead=Ttail;
    00451
    00452     }
    00453 #endif
    00454     return STATUS_SUCCESS;
    00455 }
    00456
    00457 //-------------------------------------------------------------------
    00458
    00459 NTSTATUS NPF_CloseDumpFile(POPEN_INSTANCE Open){
    00460     NTSTATUS    ntStatus;
    00461     IO_STATUS_BLOCK IoStatus;
    00462     PMDL        WriteMdl;
    00463     PUCHAR      VMBuff;
    00464     UINT        VMBufLen;
    00465
    00466 #if 0
    00467     IF_LOUD(DbgPrint("NPF: NPF_CloseDumpFile.\n");)
    00468     IF_LOUD(DbgPrint("Dumpoffset=%d\n",Open->DumpOffset.QuadPart);)
    00469
    00470 DbgPrint("1\n");
    00471     // Consistency check
    00472     if(Open->DumpFileHandle == NULL)
    00473         return STATUS_UNSUCCESSFUL;
    00474
    00475 DbgPrint("2\n");
    00476     ZwClose( Open->DumpFileHandle );
    00477
    00478     ObDereferenceObject(Open->DumpFileObject);
    00479 /*
    00480     if(Open->DumpLimitReached == TRUE)
    00481         // Limit already reached: don't save the rest of the buffer.
    00482         return STATUS_SUCCESS;
    00483 */
    00484 DbgPrint("3\n");
    00485
    00486     NPF_OpenDumpFile(Open,&Open->DumpFileName, TRUE);
    00487
    00488     // Flush the buffer to file
    00489     NPF_SaveCurrentBuffer(Open);
    00490
    00491     // Close The file
    00492     ObDereferenceObject(Open->DumpFileObject);
    00493     ZwClose( Open->DumpFileHandle );
    00494
    00495     Open->DumpFileHandle = NULL;
    00496
    00497     ObDereferenceObject(Open->DumpFileObject);
    00498 #endif
    00499     return STATUS_SUCCESS;
    00500 }
    00501
    00502 //-------------------------------------------------------------------
    00503
    00504 static NTSTATUS PacketDumpCompletion(PDEVICE_OBJECT DeviceObject,
    00505                                 PIRP Irp,
    00506                                 PVOID Context)
    00507 {
    00508
    00509     // Copy the status information back into the "user" IOSB
    00510     *Irp->UserIosb = Irp->IoStatus;
    00511
    00512     // Wake up the mainline code
    00513     KeSetEvent(Irp->UserEvent, 0, FALSE);
    00514
    00515     return STATUS_MORE_PROCESSING_REQUIRED;
    00516 }
    00517
    00518 //-------------------------------------------------------------------
    00519
    00520 VOID NPF_WriteDumpFile(PFILE_OBJECT FileObject,
    00521                                 PLARGE_INTEGER Offset,
    00522                                 ULONG Length,
    00523                                 PMDL Mdl,
    00524                                 PIO_STATUS_BLOCK IoStatusBlock)
    00525 {
    00526     PIRP irp;
    00527     KEVENT event;
    00528     PIO_STACK_LOCATION ioStackLocation;
    00529     PDEVICE_OBJECT fsdDevice = IoGetRelatedDeviceObject(FileObject);
    00530     NTSTATUS Status;
    00531
    00532     // Set up the event we'll use
    00533     KeInitializeEvent(&event, SynchronizationEvent, FALSE);
    00534
    00535     // Allocate and build the IRP we'll be sending to the FSD
    00536     irp = IoAllocateIrp(fsdDevice->StackSize, FALSE);
    00537
    00538     if (!irp) {
    00539         // Allocation failed, presumably due to memory allocation failure
    00540         IoStatusBlock->Status = STATUS_INSUFFICIENT_RESOURCES;
    00541         IoStatusBlock->Information = 0;
    00542
    00543         return;
    00544     }
    00545
    00546     irp->MdlAddress = Mdl;
    00547     irp->UserEvent = &event;
    00548     irp->UserIosb = IoStatusBlock;
    00549     irp->Tail.Overlay.Thread = PsGetCurrentThread();
    00550     irp->Tail.Overlay.OriginalFileObject= FileObject;
    00551     irp->RequestorMode = KernelMode;
    00552
    00553     // Indicate that this is a WRITE operation
    00554     irp->Flags = IRP_WRITE_OPERATION;
    00555
    00556     // Set up the next I/O stack location
    00557     ioStackLocation = IoGetNextIrpStackLocation(irp);
    00558     ioStackLocation->MajorFunction = IRP_MJ_WRITE;
    00559     ioStackLocation->MinorFunction = 0;
    00560     ioStackLocation->DeviceObject = fsdDevice;
    00561     ioStackLocation->FileObject = FileObject;
    00562     IoSetCompletionRoutine(irp, PacketDumpCompletion, 0, TRUE, TRUE, TRUE);
    00563     ioStackLocation->Parameters.Write.Length = Length;
    00564     ioStackLocation->Parameters.Write.ByteOffset = *Offset;
    00565
    00566
    00567     // Send it on.  Ignore the return code
    00568     (void) IoCallDriver(fsdDevice, irp);
    00569
    00570     // Wait for the I/O to complete.
    00571     KeWaitForSingleObject(&event, Executive, KernelMode, TRUE, 0);
    00572
    00573     // Free the IRP now that we are done with it
    00574     IoFreeIrp(irp);
    00575
    00576     return;
    00577
    00578 }

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