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.
30 //#define PsGetCurrentProcess() IoGetCurrentProcess()
31 #ifndef PsGetCurrentThread
32 #define PsGetCurrentThread() ((PETHREAD) (KeGetCurrentThread()))
36 #define TAG(A, B, C, D) (ULONG)(((A)<<0) + ((B)<<8) + ((C)<<16) + ((D)<<24))
42 //-------------------------------------------------------------------
45 NPF_OpenDumpFile(POPEN_INSTANCE Open
, PUNICODE_STRING fileName
, BOOLEAN Append
)
48 IO_STATUS_BLOCK IoStatus
;
49 OBJECT_ATTRIBUTES ObjectAttributes
;
50 PWCHAR PathPrefix
= NULL
;
52 UNICODE_STRING FullFileName
;
53 ULONG FullFileNameLength
;
54 PDEVICE_OBJECT fsdDevice
;
56 IF_LOUD(DbgPrint("NPF: OpenDumpFile.\n");)
58 if(fileName
->Buffer
[0] == L
'\\' &&
59 fileName
->Buffer
[1] == L
'?' &&
60 fileName
->Buffer
[2] == L
'?' &&
61 fileName
->Buffer
[3] == L
'\\'
66 PathPrefix
= L
"\\??\\";
70 // Insert the correct path prefix.
71 FullFileNameLength
= PathLen
+ fileName
->MaximumLength
;
73 #define NPF_TAG_FILENAME TAG('0', 'D', 'W', 'A')
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
,
132 (PVOID
)&Open
->DumpFileObject
,
135 if ( !NT_SUCCESS( ntStatus
) )
137 IF_LOUD(DbgPrint("NPF: Error creating file, status=%x\n", ntStatus
);)
139 ZwClose( Open
->DumpFileHandle
);
140 Open
->DumpFileHandle
=NULL
;
142 ntStatus
= STATUS_NO_SUCH_FILE
;
146 fsdDevice
= IoGetRelatedDeviceObject(Open
->DumpFileObject
);
148 IF_LOUD(DbgPrint("NPF: Dump: write file created succesfully, status=%d \n",ntStatus
);)
153 //-------------------------------------------------------------------
156 NPF_StartDump(POPEN_INSTANCE Open
)
159 struct packet_file_header hdr
;
160 IO_STATUS_BLOCK IoStatus
;
162 IF_LOUD(DbgPrint("NPF: StartDump.\n");)
164 // Init the file header
165 hdr
.magic
= TCPDUMP_MAGIC
;
166 hdr
.version_major
= PCAP_VERSION_MAJOR
;
167 hdr
.version_minor
= PCAP_VERSION_MINOR
;
168 hdr
.thiszone
= 0; /*Currently not set*/
172 // Detect the medium type
173 switch (Open
->Medium
){
176 hdr
.linktype
= DLT_EN10MB
;
179 case NdisMedium802_3
:
180 hdr
.linktype
= DLT_EN10MB
;
184 hdr
.linktype
= DLT_FDDI
;
187 case NdisMedium802_5
:
188 hdr
.linktype
= DLT_IEEE802
;
191 case NdisMediumArcnet878_2
:
192 hdr
.linktype
= DLT_ARCNET
;
196 hdr
.linktype
= DLT_ATM_RFC1483
;
200 hdr
.linktype
= DLT_EN10MB
;
204 // We can use ZwWriteFile because we are in the context of the application
205 ntStatus
= ZwWriteFile(Open
->DumpFileHandle
,
216 if ( !NT_SUCCESS( ntStatus
) )
218 IF_LOUD(DbgPrint("NPF: Error dumping file %x\n", ntStatus
);)
220 ZwClose( Open
->DumpFileHandle
);
221 Open
->DumpFileHandle
=NULL
;
223 ntStatus
= STATUS_NO_SUCH_FILE
;
227 Open
->DumpOffset
.QuadPart
=24;
229 ntStatus
= PsCreateSystemThread(&Open
->DumpThreadHandle
,
234 (PKSTART_ROUTINE
)NPF_DumpThread
,
237 if ( !NT_SUCCESS( ntStatus
) )
239 IF_LOUD(DbgPrint("NPF: Error creating dump thread, status=%x\n", ntStatus
);)
241 ZwClose( Open
->DumpFileHandle
);
242 Open
->DumpFileHandle
=NULL
;
246 ntStatus
= ObReferenceObjectByHandle(Open
->DumpThreadHandle
,
250 (PVOID
*)&Open
->DumpThreadObject
,
252 if ( !NT_SUCCESS( ntStatus
) )
254 IF_LOUD(DbgPrint("NPF: Error creating dump thread, status=%x\n", ntStatus
);)
256 ObDereferenceObject(Open
->DumpFileObject
);
257 ZwClose( Open
->DumpFileHandle
);
258 Open
->DumpFileHandle
=NULL
;
267 //-------------------------------------------------------------------
269 //-------------------------------------------------------------------
271 VOID
NPF_DumpThread(POPEN_INSTANCE Open
)
274 IF_LOUD(DbgPrint("NPF: In the work routine. Parameter = 0x%0x\n",Open
);)
278 // Wait until some packets arrive or the timeout expires
279 NdisWaitEvent(&Open
->DumpEvent
, 5000);
281 IF_LOUD(DbgPrint("NPF: Worker Thread - event signalled\n");)
283 if(Open
->DumpLimitReached
||
284 Open
->BufSize
==0){ // BufSize=0 means that this instance was closed, or that the buffer is too
285 // small for any capture. In both cases it is better to end the dump
287 IF_LOUD(DbgPrint("NPF: Worker Thread - Exiting happily\n");)
288 IF_LOUD(DbgPrint("Thread: Dumpoffset=%I64d\n",Open
->DumpOffset
.QuadPart
);)
290 PsTerminateSystemThread(STATUS_SUCCESS
);
294 NdisResetEvent(&Open
->DumpEvent
);
296 // Write the content of the buffer to the file
297 if(NPF_SaveCurrentBuffer(Open
) != STATUS_SUCCESS
){
298 PsTerminateSystemThread(STATUS_SUCCESS
);
306 //-------------------------------------------------------------------
308 NTSTATUS
NPF_SaveCurrentBuffer(POPEN_INSTANCE Open
)
314 IO_STATUS_BLOCK IoStatus
;
321 TLastByte
=Open
->BLastByte
;
323 IF_LOUD(DbgPrint("NPF: NPF_SaveCurrentBuffer.\n");)
325 // Get the address of the buffer
326 CurrBuff
=Open
->Buffer
;
328 // Fill the application buffer
332 if(Open
->MaxDumpBytes
&&
333 (UINT
)Open
->DumpOffset
.QuadPart
+ GetBuffOccupation(Open
) > Open
->MaxDumpBytes
)
335 // Size limit reached
340 // Scan the buffer to detect the exact amount of data to save
342 PktLen
= ((struct sf_pkthdr
*)(CurrBuff
+ Thead
+ SizeToDump
))->caplen
+ sizeof(struct sf_pkthdr
);
344 if((UINT
)Open
->DumpOffset
.QuadPart
+ SizeToDump
+ PktLen
> Open
->MaxDumpBytes
)
347 SizeToDump
+= PktLen
;
352 SizeToDump
= TLastByte
-Thead
;
354 lMdl
=IoAllocateMdl(CurrBuff
+Thead
, SizeToDump
, FALSE
, FALSE
, NULL
);
357 // No memory: stop dump
358 IF_LOUD(DbgPrint("NPF: dump thread: Failed to allocate Mdl\n");)
359 return STATUS_UNSUCCESSFUL
;
362 MmBuildMdlForNonPagedPool(lMdl
);
365 NPF_WriteDumpFile(Open
->DumpFileObject
,
373 if(!NT_SUCCESS(IoStatus
.Status
)){
375 return STATUS_UNSUCCESSFUL
;
378 if(SizeToDump
!= TLastByte
-Thead
){
379 // Size limit reached.
380 Open
->DumpLimitReached
= TRUE
;
382 // Awake the application
383 KeSetEvent(Open
->ReadEvent
,0,FALSE
);
385 return STATUS_UNSUCCESSFUL
;
388 // Update the packet buffer
389 Open
->DumpOffset
.QuadPart
+=(TLastByte
-Thead
);
390 Open
->BLastByte
=Ttail
;
396 if(Open
->MaxDumpBytes
&&
397 (UINT
)Open
->DumpOffset
.QuadPart
+ GetBuffOccupation(Open
) > Open
->MaxDumpBytes
)
399 // Size limit reached
404 // Scan the buffer to detect the exact amount of data to save
405 while(Thead
+ SizeToDump
< Ttail
){
407 PktLen
= ((struct sf_pkthdr
*)(CurrBuff
+ Thead
+ SizeToDump
))->caplen
+ sizeof(struct sf_pkthdr
);
409 if((UINT
)Open
->DumpOffset
.QuadPart
+ SizeToDump
+ PktLen
> Open
->MaxDumpBytes
)
412 SizeToDump
+= PktLen
;
417 SizeToDump
= Ttail
-Thead
;
419 lMdl
=IoAllocateMdl(CurrBuff
+Thead
, SizeToDump
, FALSE
, FALSE
, NULL
);
422 // No memory: stop dump
423 IF_LOUD(DbgPrint("NPF: dump thread: Failed to allocate Mdl\n");)
424 return STATUS_UNSUCCESSFUL
;
427 MmBuildMdlForNonPagedPool(lMdl
);
430 NPF_WriteDumpFile(Open
->DumpFileObject
,
438 if(!NT_SUCCESS(IoStatus
.Status
)){
440 return STATUS_UNSUCCESSFUL
;
443 if(SizeToDump
!= Ttail
-Thead
){
444 // Size limit reached.
445 Open
->DumpLimitReached
= TRUE
;
447 // Awake the application
448 KeSetEvent(Open
->ReadEvent
,0,FALSE
);
450 return STATUS_UNSUCCESSFUL
;
453 // Update the packet buffer
454 Open
->DumpOffset
.QuadPart
+=(Ttail
-Thead
);
459 return STATUS_SUCCESS
;
462 //-------------------------------------------------------------------
464 NTSTATUS
NPF_CloseDumpFile(POPEN_INSTANCE Open
){
466 IF_LOUD(DbgPrint("NPF: NPF_CloseDumpFile.\n");)
467 IF_LOUD(DbgPrint("Dumpoffset=%d\n",Open
->DumpOffset
.QuadPart
);)
471 if(Open
->DumpFileHandle
== NULL
)
472 return STATUS_UNSUCCESSFUL
;
475 ZwClose( Open
->DumpFileHandle
);
477 ObDereferenceObject(Open
->DumpFileObject
);
479 if(Open->DumpLimitReached == TRUE)
480 // Limit already reached: don't save the rest of the buffer.
481 return STATUS_SUCCESS;
485 NPF_OpenDumpFile(Open
,&Open
->DumpFileName
, TRUE
);
487 // Flush the buffer to file
488 NPF_SaveCurrentBuffer(Open
);
491 ObDereferenceObject(Open
->DumpFileObject
);
492 ZwClose( Open
->DumpFileHandle
);
494 Open
->DumpFileHandle
= NULL
;
496 ObDereferenceObject(Open
->DumpFileObject
);
498 return STATUS_SUCCESS
;
501 //-------------------------------------------------------------------
508 PacketDumpCompletion(PDEVICE_OBJECT DeviceObject
,
513 // Copy the status information back into the "user" IOSB
514 *Irp
->UserIosb
= Irp
->IoStatus
;
516 // Wake up the mainline code
517 KeSetEvent(Irp
->UserEvent
, 0, FALSE
);
519 return STATUS_MORE_PROCESSING_REQUIRED
;
522 //-------------------------------------------------------------------
524 VOID
NPF_WriteDumpFile(PFILE_OBJECT FileObject
,
525 PLARGE_INTEGER Offset
,
528 PIO_STATUS_BLOCK IoStatusBlock
)
532 PIO_STACK_LOCATION ioStackLocation
;
533 PDEVICE_OBJECT fsdDevice
= IoGetRelatedDeviceObject(FileObject
);
535 // Set up the event we'll use
536 KeInitializeEvent(&event
, SynchronizationEvent
, FALSE
);
538 // Allocate and build the IRP we'll be sending to the FSD
539 irp
= IoAllocateIrp(fsdDevice
->StackSize
, FALSE
);
542 // Allocation failed, presumably due to memory allocation failure
543 IoStatusBlock
->Status
= STATUS_INSUFFICIENT_RESOURCES
;
544 IoStatusBlock
->Information
= 0;
549 irp
->MdlAddress
= Mdl
;
550 irp
->UserEvent
= &event
;
551 irp
->UserIosb
= IoStatusBlock
;
552 irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
553 irp
->Tail
.Overlay
.OriginalFileObject
= FileObject
;
554 irp
->RequestorMode
= KernelMode
;
556 // Indicate that this is a WRITE operation
557 irp
->Flags
= IRP_WRITE_OPERATION
;
559 // Set up the next I/O stack location
560 ioStackLocation
= IoGetNextIrpStackLocation(irp
);
561 ioStackLocation
->MajorFunction
= IRP_MJ_WRITE
;
562 ioStackLocation
->MinorFunction
= 0;
563 ioStackLocation
->DeviceObject
= fsdDevice
;
564 ioStackLocation
->FileObject
= FileObject
;
565 IoSetCompletionRoutine(irp
, PacketDumpCompletion
, 0, TRUE
, TRUE
, TRUE
);
566 ioStackLocation
->Parameters
.Write
.Length
= Length
;
567 ioStackLocation
->Parameters
.Write
.ByteOffset
= *Offset
;
570 // Send it on. Ignore the return code
571 (void) IoCallDriver(fsdDevice
, irp
);
573 // Wait for the I/O to complete.
574 KeWaitForSingleObject(&event
, Executive
, KernelMode
, TRUE
, 0);
576 // Free the IRP now that we are done with it