2 * Copyright (c) 1999, 2000
3 * Politecnico di Torino. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that: (1) source code distributions
7 * retain the above copyright notice and this paragraph in its entirety, (2)
8 * distributions including binary code include the above copyright notice and
9 * this paragraph in its entirety in the documentation or other materials
10 * provided with the distribution, and (3) all advertising materials mentioning
11 * features or use of this software display the following acknowledgement:
12 * ``This product includes software developed by the Politecnico
13 * di Torino, and its contributors.'' Neither the name of
14 * the University nor the names of its contributors may be used to endorse
15 * or promote products derived from this software without specific prior
17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
28 #include <ddk/ntddk.h>
30 //#define PsGetCurrentProcess() IoGetCurrentProcess()
31 #ifndef PsGetCurrentThread
32 #define PsGetCurrentThread() ((PETHREAD) (KeGetCurrentThread()))
40 #define assert(exp) ((void)0)
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 IF_LOUD(DbgPrint("NPF: OpenDumpFile.\n");)
57 if(fileName
->Buffer
[0] == L
'\\' &&
58 fileName
->Buffer
[1] == L
'?' &&
59 fileName
->Buffer
[2] == L
'?' &&
60 fileName
->Buffer
[3] == L
'\\'
65 PathPrefix
= L
"\\??\\";
69 // Insert the correct path prefix.
70 FullFileNameLength
= PathLen
+ fileName
->MaximumLength
;
72 #define NPF_TAG_FILENAME TAG('0', 'D', 'W', 'A')
73 FullFileName
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
77 if (FullFileName
.Buffer
== NULL
) {
78 ntStatus
= STATUS_INSUFFICIENT_RESOURCES
;
82 FullFileName
.Length
= PathLen
;
83 FullFileName
.MaximumLength
= (USHORT
)FullFileNameLength
;
86 RtlMoveMemory (FullFileName
.Buffer
, PathPrefix
, PathLen
);
88 RtlAppendUnicodeStringToString (&FullFileName
, fileName
);
90 IF_LOUD(DbgPrint( "Packet: Attempting to open %wZ\n", &FullFileName
);)
92 InitializeObjectAttributes ( &ObjectAttributes
,
98 // Create the dump file
99 ntStatus
= ZwCreateFile( &Open
->DumpFileHandle
,
100 SYNCHRONIZE
| FILE_WRITE_DATA
,
104 FILE_ATTRIBUTE_NORMAL
,
106 (Append
)?FILE_OPEN_IF
:FILE_SUPERSEDE
,
107 FILE_SYNCHRONOUS_IO_NONALERT
,
111 if ( !NT_SUCCESS( ntStatus
) )
113 IF_LOUD(DbgPrint("NPF: Error opening file %x\n", ntStatus
);)
115 ExFreePool(FullFileName
.Buffer
);
116 Open
->DumpFileHandle
=NULL
;
117 ntStatus
= STATUS_NO_SUCH_FILE
;
121 ExFreePool(FullFileName
.Buffer
);
123 ntStatus
= ObReferenceObjectByHandle(Open
->DumpFileHandle
,
131 (PVOID
)&Open
->DumpFileObject
,
134 if ( !NT_SUCCESS( ntStatus
) )
136 IF_LOUD(DbgPrint("NPF: Error creating file, status=%x\n", ntStatus
);)
138 ZwClose( Open
->DumpFileHandle
);
139 Open
->DumpFileHandle
=NULL
;
141 ntStatus
= STATUS_NO_SUCH_FILE
;
145 fsdDevice
= IoGetRelatedDeviceObject(Open
->DumpFileObject
);
147 IF_LOUD(DbgPrint("NPF: Dump: write file created succesfully, status=%d \n",ntStatus
);)
152 //-------------------------------------------------------------------
155 NPF_StartDump(POPEN_INSTANCE Open
)
158 struct packet_file_header hdr
;
159 IO_STATUS_BLOCK IoStatus
;
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
,
233 (PKSTART_ROUTINE
)NPF_DumpThread
,
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
;
245 ntStatus
= ObReferenceObjectByHandle(Open
->DumpThreadHandle
,
249 (PVOID
*)&Open
->DumpThreadObject
,
251 if ( !NT_SUCCESS( ntStatus
) )
253 IF_LOUD(DbgPrint("NPF: Error creating dump thread, status=%x\n", ntStatus
);)
255 ObDereferenceObject(Open
->DumpFileObject
);
256 ZwClose( Open
->DumpFileHandle
);
257 Open
->DumpFileHandle
=NULL
;
266 //-------------------------------------------------------------------
268 //-------------------------------------------------------------------
270 VOID
NPF_DumpThread(POPEN_INSTANCE Open
)
273 IF_LOUD(DbgPrint("NPF: In the work routine. Parameter = 0x%0x\n",Open
);)
277 // Wait until some packets arrive or the timeout expires
278 NdisWaitEvent(&Open
->DumpEvent
, 5000);
280 IF_LOUD(DbgPrint("NPF: Worker Thread - event signalled\n");)
282 if(Open
->DumpLimitReached
||
283 Open
->BufSize
==0){ // BufSize=0 means that this instance was closed, or that the buffer is too
284 // small for any capture. In both cases it is better to end the dump
286 IF_LOUD(DbgPrint("NPF: Worker Thread - Exiting happily\n");)
287 IF_LOUD(DbgPrint("Thread: Dumpoffset=%I64d\n",Open
->DumpOffset
.QuadPart
);)
289 PsTerminateSystemThread(STATUS_SUCCESS
);
293 NdisResetEvent(&Open
->DumpEvent
);
295 // Write the content of the buffer to the file
296 if(NPF_SaveCurrentBuffer(Open
) != STATUS_SUCCESS
){
297 PsTerminateSystemThread(STATUS_SUCCESS
);
305 //-------------------------------------------------------------------
307 NTSTATUS
NPF_SaveCurrentBuffer(POPEN_INSTANCE Open
)
313 IO_STATUS_BLOCK IoStatus
;
320 TLastByte
=Open
->BLastByte
;
322 IF_LOUD(DbgPrint("NPF: NPF_SaveCurrentBuffer.\n");)
324 // Get the address of the buffer
325 CurrBuff
=Open
->Buffer
;
327 // Fill the application buffer
331 if(Open
->MaxDumpBytes
&&
332 (UINT
)Open
->DumpOffset
.QuadPart
+ GetBuffOccupation(Open
) > Open
->MaxDumpBytes
)
334 // Size limit reached
339 // Scan the buffer to detect the exact amount of data to save
341 PktLen
= ((struct sf_pkthdr
*)(CurrBuff
+ Thead
+ SizeToDump
))->caplen
+ sizeof(struct sf_pkthdr
);
343 if((UINT
)Open
->DumpOffset
.QuadPart
+ SizeToDump
+ PktLen
> Open
->MaxDumpBytes
)
346 SizeToDump
+= PktLen
;
351 SizeToDump
= TLastByte
-Thead
;
353 lMdl
=IoAllocateMdl(CurrBuff
+Thead
, SizeToDump
, FALSE
, FALSE
, NULL
);
356 // No memory: stop dump
357 IF_LOUD(DbgPrint("NPF: dump thread: Failed to allocate Mdl\n");)
358 return STATUS_UNSUCCESSFUL
;
361 MmBuildMdlForNonPagedPool(lMdl
);
364 NPF_WriteDumpFile(Open
->DumpFileObject
,
372 if(!NT_SUCCESS(IoStatus
.Status
)){
374 return STATUS_UNSUCCESSFUL
;
377 if(SizeToDump
!= TLastByte
-Thead
){
378 // Size limit reached.
379 Open
->DumpLimitReached
= TRUE
;
381 // Awake the application
382 KeSetEvent(Open
->ReadEvent
,0,FALSE
);
384 return STATUS_UNSUCCESSFUL
;
387 // Update the packet buffer
388 Open
->DumpOffset
.QuadPart
+=(TLastByte
-Thead
);
389 Open
->BLastByte
=Ttail
;
395 if(Open
->MaxDumpBytes
&&
396 (UINT
)Open
->DumpOffset
.QuadPart
+ GetBuffOccupation(Open
) > Open
->MaxDumpBytes
)
398 // Size limit reached
403 // Scan the buffer to detect the exact amount of data to save
404 while(Thead
+ SizeToDump
< Ttail
){
406 PktLen
= ((struct sf_pkthdr
*)(CurrBuff
+ Thead
+ SizeToDump
))->caplen
+ sizeof(struct sf_pkthdr
);
408 if((UINT
)Open
->DumpOffset
.QuadPart
+ SizeToDump
+ PktLen
> Open
->MaxDumpBytes
)
411 SizeToDump
+= PktLen
;
416 SizeToDump
= Ttail
-Thead
;
418 lMdl
=IoAllocateMdl(CurrBuff
+Thead
, SizeToDump
, FALSE
, FALSE
, NULL
);
421 // No memory: stop dump
422 IF_LOUD(DbgPrint("NPF: dump thread: Failed to allocate Mdl\n");)
423 return STATUS_UNSUCCESSFUL
;
426 MmBuildMdlForNonPagedPool(lMdl
);
429 NPF_WriteDumpFile(Open
->DumpFileObject
,
437 if(!NT_SUCCESS(IoStatus
.Status
)){
439 return STATUS_UNSUCCESSFUL
;
442 if(SizeToDump
!= Ttail
-Thead
){
443 // Size limit reached.
444 Open
->DumpLimitReached
= TRUE
;
446 // Awake the application
447 KeSetEvent(Open
->ReadEvent
,0,FALSE
);
449 return STATUS_UNSUCCESSFUL
;
452 // Update the packet buffer
453 Open
->DumpOffset
.QuadPart
+=(Ttail
-Thead
);
458 return STATUS_SUCCESS
;
461 //-------------------------------------------------------------------
463 NTSTATUS
NPF_CloseDumpFile(POPEN_INSTANCE Open
){
465 IF_LOUD(DbgPrint("NPF: NPF_CloseDumpFile.\n");)
466 IF_LOUD(DbgPrint("Dumpoffset=%d\n",Open
->DumpOffset
.QuadPart
);)
470 if(Open
->DumpFileHandle
== NULL
)
471 return STATUS_UNSUCCESSFUL
;
474 ZwClose( Open
->DumpFileHandle
);
476 ObDereferenceObject(Open
->DumpFileObject
);
478 if(Open->DumpLimitReached == TRUE)
479 // Limit already reached: don't save the rest of the buffer.
480 return STATUS_SUCCESS;
484 NPF_OpenDumpFile(Open
,&Open
->DumpFileName
, TRUE
);
486 // Flush the buffer to file
487 NPF_SaveCurrentBuffer(Open
);
490 ObDereferenceObject(Open
->DumpFileObject
);
491 ZwClose( Open
->DumpFileHandle
);
493 Open
->DumpFileHandle
= NULL
;
495 ObDereferenceObject(Open
->DumpFileObject
);
497 return STATUS_SUCCESS
;
500 //-------------------------------------------------------------------
507 PacketDumpCompletion(PDEVICE_OBJECT DeviceObject
,
512 // Copy the status information back into the "user" IOSB
513 *Irp
->UserIosb
= Irp
->IoStatus
;
515 // Wake up the mainline code
516 KeSetEvent(Irp
->UserEvent
, 0, FALSE
);
518 return STATUS_MORE_PROCESSING_REQUIRED
;
521 //-------------------------------------------------------------------
523 VOID
NPF_WriteDumpFile(PFILE_OBJECT FileObject
,
524 PLARGE_INTEGER Offset
,
527 PIO_STATUS_BLOCK IoStatusBlock
)
531 PIO_STACK_LOCATION ioStackLocation
;
532 PDEVICE_OBJECT fsdDevice
= IoGetRelatedDeviceObject(FileObject
);
534 // Set up the event we'll use
535 KeInitializeEvent(&event
, SynchronizationEvent
, FALSE
);
537 // Allocate and build the IRP we'll be sending to the FSD
538 irp
= IoAllocateIrp(fsdDevice
->StackSize
, FALSE
);
541 // Allocation failed, presumably due to memory allocation failure
542 IoStatusBlock
->Status
= STATUS_INSUFFICIENT_RESOURCES
;
543 IoStatusBlock
->Information
= 0;
548 irp
->MdlAddress
= Mdl
;
549 irp
->UserEvent
= &event
;
550 irp
->UserIosb
= IoStatusBlock
;
551 irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
552 irp
->Tail
.Overlay
.OriginalFileObject
= FileObject
;
553 irp
->RequestorMode
= KernelMode
;
555 // Indicate that this is a WRITE operation
556 irp
->Flags
= IRP_WRITE_OPERATION
;
558 // Set up the next I/O stack location
559 ioStackLocation
= IoGetNextIrpStackLocation(irp
);
560 ioStackLocation
->MajorFunction
= IRP_MJ_WRITE
;
561 ioStackLocation
->MinorFunction
= 0;
562 ioStackLocation
->DeviceObject
= fsdDevice
;
563 ioStackLocation
->FileObject
= FileObject
;
564 IoSetCompletionRoutine(irp
, PacketDumpCompletion
, 0, TRUE
, TRUE
, TRUE
);
565 ioStackLocation
->Parameters
.Write
.Length
= Length
;
566 ioStackLocation
->Parameters
.Write
.ByteOffset
= *Offset
;
569 // Send it on. Ignore the return code
570 (void) IoCallDriver(fsdDevice
, irp
);
572 // Wait for the I/O to complete.
573 KeWaitForSingleObject(&event
, Executive
, KernelMode
, TRUE
, 0);
575 // Free the IRP now that we are done with it