2 * Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy)
3 * Copyright (c) 2005 - 2007 CACE Technologies, Davis (California)
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the Politecnico di Torino, CACE Technologies
16 * nor the names of its contributors may be used to endorse or promote
17 * products derived from this software without specific prior written
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 //-------------------------------------------------------------------
44 NPF_OpenDumpFile(POPEN_INSTANCE Open
, PUNICODE_STRING fileName
, BOOLEAN Append
)
47 IO_STATUS_BLOCK IoStatus
;
48 OBJECT_ATTRIBUTES ObjectAttributes
;
51 UNICODE_STRING FullFileName
;
52 ULONG FullFileNameLength
;
53 PDEVICE_OBJECT fsdDevice
;
55 FILE_STANDARD_INFORMATION StandardInfo
;
57 IF_LOUD(DbgPrint("NPF: OpenDumpFile.\n");)
59 if(fileName
->Buffer
[0] == L
'\\' &&
60 fileName
->Buffer
[1] == L
'?' &&
61 fileName
->Buffer
[2] == L
'?' &&
62 fileName
->Buffer
[3] == L
'\\'
67 PathPrefix
= L
"\\??\\";
71 // Insert the correct path prefix.
72 FullFileNameLength
= PathLen
+ fileName
->MaximumLength
;
74 FullFileName
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
78 if (FullFileName
.Buffer
== NULL
) {
79 ntStatus
= STATUS_INSUFFICIENT_RESOURCES
;
83 FullFileName
.Length
= PathLen
;
84 FullFileName
.MaximumLength
= (USHORT
)FullFileNameLength
;
87 RtlMoveMemory (FullFileName
.Buffer
, PathPrefix
, PathLen
);
89 RtlAppendUnicodeStringToString (&FullFileName
, fileName
);
91 IF_LOUD(DbgPrint( "Packet: Attempting to open %wZ\n", &FullFileName
);)
93 InitializeObjectAttributes ( &ObjectAttributes
,
99 // Create the dump file
100 ntStatus
= ZwCreateFile( &Open
->DumpFileHandle
,
101 SYNCHRONIZE
| FILE_WRITE_DATA
,
105 FILE_ATTRIBUTE_NORMAL
,
107 (Append
)?FILE_OPEN_IF
:FILE_SUPERSEDE
,
108 FILE_SYNCHRONOUS_IO_NONALERT
,
112 if ( !NT_SUCCESS( ntStatus
) )
114 IF_LOUD(DbgPrint("NPF: Error opening file %x\n", ntStatus
);)
116 ExFreePool(FullFileName
.Buffer
);
117 Open
->DumpFileHandle
=NULL
;
118 ntStatus
= STATUS_NO_SUCH_FILE
;
122 ExFreePool(FullFileName
.Buffer
);
124 ntStatus
= ObReferenceObjectByHandle(Open
->DumpFileHandle
,
128 &Open
->DumpFileObject
,
131 if ( !NT_SUCCESS( ntStatus
) )
133 IF_LOUD(DbgPrint("NPF: Error creating file, status=%x\n", ntStatus
);)
135 ZwClose( Open
->DumpFileHandle
);
136 Open
->DumpFileHandle
=NULL
;
138 ntStatus
= STATUS_NO_SUCH_FILE
;
142 fsdDevice
= IoGetRelatedDeviceObject(Open
->DumpFileObject
);
144 IF_LOUD(DbgPrint("NPF: Dump: write file created succesfully, status=%d \n",ntStatus
);)
149 //-------------------------------------------------------------------
152 NPF_StartDump(POPEN_INSTANCE Open
)
155 struct packet_file_header hdr
;
156 IO_STATUS_BLOCK IoStatus
;
157 NDIS_REQUEST pRequest
;
159 OBJECT_ATTRIBUTES ObjectAttributes
;
161 IF_LOUD(DbgPrint("NPF: StartDump.\n");)
163 // Init the file header
164 hdr
.magic
= TCPDUMP_MAGIC
;
165 hdr
.version_major
= PCAP_VERSION_MAJOR
;
166 hdr
.version_minor
= PCAP_VERSION_MINOR
;
167 hdr
.thiszone
= 0; /*Currently not set*/
171 // Detect the medium type
172 switch (Open
->Medium
){
175 hdr
.linktype
= DLT_EN10MB
;
178 case NdisMedium802_3
:
179 hdr
.linktype
= DLT_EN10MB
;
183 hdr
.linktype
= DLT_FDDI
;
186 case NdisMedium802_5
:
187 hdr
.linktype
= DLT_IEEE802
;
190 case NdisMediumArcnet878_2
:
191 hdr
.linktype
= DLT_ARCNET
;
195 hdr
.linktype
= DLT_ATM_RFC1483
;
199 hdr
.linktype
= DLT_EN10MB
;
203 // We can use ZwWriteFile because we are in the context of the application
204 ntStatus
= ZwWriteFile(Open
->DumpFileHandle
,
215 if ( !NT_SUCCESS( ntStatus
) )
217 IF_LOUD(DbgPrint("NPF: Error dumping file %x\n", ntStatus
);)
219 ZwClose( Open
->DumpFileHandle
);
220 Open
->DumpFileHandle
=NULL
;
222 ntStatus
= STATUS_NO_SUCH_FILE
;
226 Open
->DumpOffset
.QuadPart
=24;
228 ntStatus
= PsCreateSystemThread(&Open
->DumpThreadHandle
,
236 if ( !NT_SUCCESS( ntStatus
) )
238 IF_LOUD(DbgPrint("NPF: Error creating dump thread, status=%x\n", ntStatus
);)
240 ZwClose( Open
->DumpFileHandle
);
241 Open
->DumpFileHandle
=NULL
;
246 ntStatus
= ObReferenceObjectByHandle(Open
->DumpThreadHandle
,
250 &Open
->DumpThreadObject
,
253 if ( !NT_SUCCESS( ntStatus
) )
255 IF_LOUD(DbgPrint("NPF: Error creating dump thread, status=%x\n", ntStatus
);)
257 ObDereferenceObject(Open
->DumpFileObject
);
258 ZwClose( Open
->DumpFileHandle
);
259 Open
->DumpFileHandle
=NULL
;
269 //-------------------------------------------------------------------
271 //-------------------------------------------------------------------
273 VOID
NPF_DumpThread(POPEN_INSTANCE Open
)
277 IF_LOUD(DbgPrint("NPF: In the work routine. Parameter = 0x%p\n",Open
);)
281 // Wait until some packets arrive or the timeout expires
282 NdisWaitEvent(&Open
->DumpEvent
, 5000);
284 IF_LOUD(DbgPrint("NPF: Worker Thread - event signalled\n");)
286 if(Open
->DumpLimitReached
||
287 Open
->Size
==0){ // BufSize=0 means that this instance was closed, or that the buffer is too
288 // small for any capture. In both cases it is better to end the dump
290 IF_LOUD(DbgPrint("NPF: Worker Thread - Exiting happily\n");)
291 IF_LOUD(DbgPrint("Thread: Dumpoffset=%I64d\n",Open
->DumpOffset
.QuadPart
);)
293 PsTerminateSystemThread(STATUS_SUCCESS
);
297 NdisResetEvent(&Open
->DumpEvent
);
299 // Write the content of the buffer to the file
300 if(NPF_SaveCurrentBuffer(Open
) != STATUS_SUCCESS
){
301 PsTerminateSystemThread(STATUS_SUCCESS
);
309 //-------------------------------------------------------------------
311 NTSTATUS
NPF_SaveCurrentBuffer(POPEN_INSTANCE Open
)
318 IO_STATUS_BLOCK IoStatus
;
326 TLastByte
=Open
->BLastByte
;
328 IF_LOUD(DbgPrint("NPF: NPF_SaveCurrentBuffer.\n");)
330 // Get the address of the buffer
331 CurrBuff
=Open
->Buffer
;
333 // Fill the application buffer
337 if(Open
->MaxDumpBytes
&&
338 (UINT
)Open
->DumpOffset
.QuadPart
/*+ GetBuffOccupation(Open)*/ > Open
->MaxDumpBytes
)
340 // Size limit reached
345 // Scan the buffer to detect the exact amount of data to save
347 PktLen
= ((struct sf_pkthdr
*)(CurrBuff
+ Thead
+ SizeToDump
))->caplen
+ sizeof(struct sf_pkthdr
);
349 if((UINT
)Open
->DumpOffset
.QuadPart
+ SizeToDump
+ PktLen
> Open
->MaxDumpBytes
)
352 SizeToDump
+= PktLen
;
357 SizeToDump
= TLastByte
-Thead
;
359 lMdl
=IoAllocateMdl(CurrBuff
+Thead
, SizeToDump
, FALSE
, FALSE
, NULL
);
362 // No memory: stop dump
363 IF_LOUD(DbgPrint("NPF: dump thread: Failed to allocate Mdl\n");)
364 return STATUS_UNSUCCESSFUL
;
367 MmBuildMdlForNonPagedPool(lMdl
);
370 NPF_WriteDumpFile(Open
->DumpFileObject
,
378 if(!NT_SUCCESS(IoStatus
.Status
)){
380 return STATUS_UNSUCCESSFUL
;
383 if(SizeToDump
!= TLastByte
-Thead
){
384 // Size limit reached.
385 Open
->DumpLimitReached
= TRUE
;
387 // Awake the application
388 KeSetEvent(Open
->ReadEvent
,0,FALSE
);
390 return STATUS_UNSUCCESSFUL
;
393 // Update the packet buffer
394 Open
->DumpOffset
.QuadPart
+=(TLastByte
-Thead
);
395 Open
->BLastByte
=Ttail
;
401 if(Open
->MaxDumpBytes
&&
402 (UINT
)Open
->DumpOffset
.QuadPart
/* +GetBuffOccupation(Open)*/ > Open
->MaxDumpBytes
)
404 // Size limit reached
409 // Scan the buffer to detect the exact amount of data to save
410 while(Thead
+ SizeToDump
< Ttail
){
412 PktLen
= ((struct sf_pkthdr
*)(CurrBuff
+ Thead
+ SizeToDump
))->caplen
+ sizeof(struct sf_pkthdr
);
414 if((UINT
)Open
->DumpOffset
.QuadPart
+ SizeToDump
+ PktLen
> Open
->MaxDumpBytes
)
417 SizeToDump
+= PktLen
;
422 SizeToDump
= Ttail
-Thead
;
424 lMdl
=IoAllocateMdl(CurrBuff
+Thead
, SizeToDump
, FALSE
, FALSE
, NULL
);
427 // No memory: stop dump
428 IF_LOUD(DbgPrint("NPF: dump thread: Failed to allocate Mdl\n");)
429 return STATUS_UNSUCCESSFUL
;
432 MmBuildMdlForNonPagedPool(lMdl
);
435 NPF_WriteDumpFile(Open
->DumpFileObject
,
443 if(!NT_SUCCESS(IoStatus
.Status
)){
445 return STATUS_UNSUCCESSFUL
;
448 if(SizeToDump
!= Ttail
-Thead
){
449 // Size limit reached.
450 Open
->DumpLimitReached
= TRUE
;
452 // Awake the application
453 KeSetEvent(Open
->ReadEvent
,0,FALSE
);
455 return STATUS_UNSUCCESSFUL
;
458 // Update the packet buffer
459 Open
->DumpOffset
.QuadPart
+=(Ttail
-Thead
);
464 return STATUS_SUCCESS
;
467 //-------------------------------------------------------------------
469 NTSTATUS
NPF_CloseDumpFile(POPEN_INSTANCE Open
){
471 IO_STATUS_BLOCK IoStatus
;
477 IF_LOUD(DbgPrint("NPF: NPF_CloseDumpFile.\n");)
478 IF_LOUD(DbgPrint("Dumpoffset=%d\n",Open
->DumpOffset
.QuadPart
);)
482 if(Open
->DumpFileHandle
== NULL
)
483 return STATUS_UNSUCCESSFUL
;
486 ZwClose( Open
->DumpFileHandle
);
488 ObDereferenceObject(Open
->DumpFileObject
);
490 if(Open->DumpLimitReached == TRUE)
491 // Limit already reached: don't save the rest of the buffer.
492 return STATUS_SUCCESS;
496 NPF_OpenDumpFile(Open
,&Open
->DumpFileName
, TRUE
);
498 // Flush the buffer to file
499 NPF_SaveCurrentBuffer(Open
);
502 ObDereferenceObject(Open
->DumpFileObject
);
503 ZwClose( Open
->DumpFileHandle
);
505 Open
->DumpFileHandle
= NULL
;
507 ObDereferenceObject(Open
->DumpFileObject
);
509 return STATUS_SUCCESS
;
512 //-------------------------------------------------------------------
514 static NTSTATUS
PacketDumpCompletion(PDEVICE_OBJECT DeviceObject
,
519 // Copy the status information back into the "user" IOSB
520 *Irp
->UserIosb
= Irp
->IoStatus
;
522 // Wake up the mainline code
523 KeSetEvent(Irp
->UserEvent
, 0, FALSE
);
525 return STATUS_MORE_PROCESSING_REQUIRED
;
528 //-------------------------------------------------------------------
530 VOID
NPF_WriteDumpFile(PFILE_OBJECT FileObject
,
531 PLARGE_INTEGER Offset
,
534 PIO_STATUS_BLOCK IoStatusBlock
)
538 PIO_STACK_LOCATION ioStackLocation
;
539 PDEVICE_OBJECT fsdDevice
= IoGetRelatedDeviceObject(FileObject
);
542 // Set up the event we'll use
543 KeInitializeEvent(&event
, SynchronizationEvent
, FALSE
);
545 // Allocate and build the IRP we'll be sending to the FSD
546 irp
= IoAllocateIrp(fsdDevice
->StackSize
, FALSE
);
549 // Allocation failed, presumably due to memory allocation failure
550 IoStatusBlock
->Status
= STATUS_INSUFFICIENT_RESOURCES
;
551 IoStatusBlock
->Information
= 0;
556 irp
->MdlAddress
= Mdl
;
557 irp
->UserEvent
= &event
;
558 irp
->UserIosb
= IoStatusBlock
;
559 irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
560 irp
->Tail
.Overlay
.OriginalFileObject
= FileObject
;
561 irp
->RequestorMode
= KernelMode
;
563 // Indicate that this is a WRITE operation
564 irp
->Flags
= IRP_WRITE_OPERATION
;
566 // Set up the next I/O stack location
567 ioStackLocation
= IoGetNextIrpStackLocation(irp
);
568 ioStackLocation
->MajorFunction
= IRP_MJ_WRITE
;
569 ioStackLocation
->MinorFunction
= 0;
570 ioStackLocation
->DeviceObject
= fsdDevice
;
571 ioStackLocation
->FileObject
= FileObject
;
572 IoSetCompletionRoutine(irp
, PacketDumpCompletion
, 0, TRUE
, TRUE
, TRUE
);
573 ioStackLocation
->Parameters
.Write
.Length
= Length
;
574 ioStackLocation
->Parameters
.Write
.ByteOffset
= *Offset
;
577 // Send it on. Ignore the return code
578 (void) IoCallDriver(fsdDevice
, irp
);
580 // Wait for the I/O to complete.
581 KeWaitForSingleObject(&event
, Executive
, KernelMode
, TRUE
, 0);
583 // Free the IRP now that we are done with it