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 //-------------------------------------------------------------------
43 NPF_OpenDumpFile(POPEN_INSTANCE Open , PUNICODE_STRING fileName, BOOLEAN Append)
46 IO_STATUS_BLOCK IoStatus;
47 OBJECT_ATTRIBUTES ObjectAttributes;
50 UNICODE_STRING FullFileName;
51 ULONG FullFileNameLength;
52 PDEVICE_OBJECT fsdDevice;
54 FILE_STANDARD_INFORMATION StandardInfo;
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;
161 NDIS_REQUEST pRequest;
163 OBJECT_ATTRIBUTES ObjectAttributes;
165 IF_LOUD(DbgPrint("NPF: StartDump.\n");)
167 // Init the file header
168 hdr.magic = TCPDUMP_MAGIC;
169 hdr.version_major = PCAP_VERSION_MAJOR;
170 hdr.version_minor = PCAP_VERSION_MINOR;
171 hdr.thiszone = 0; /*Currently not set*/
175 // Detect the medium type
176 switch (Open->Medium){
179 hdr.linktype = DLT_EN10MB;
182 case NdisMedium802_3:
183 hdr.linktype = DLT_EN10MB;
187 hdr.linktype = DLT_FDDI;
190 case NdisMedium802_5:
191 hdr.linktype = DLT_IEEE802;
194 case NdisMediumArcnet878_2:
195 hdr.linktype = DLT_ARCNET;
199 hdr.linktype = DLT_ATM_RFC1483;
203 hdr.linktype = DLT_EN10MB;
207 // We can use ZwWriteFile because we are in the context of the application
208 ntStatus = ZwWriteFile(Open->DumpFileHandle,
219 if ( !NT_SUCCESS( ntStatus ) )
221 IF_LOUD(DbgPrint("NPF: Error dumping file %x\n", ntStatus);)
223 ZwClose( Open->DumpFileHandle );
224 Open->DumpFileHandle=NULL;
226 ntStatus = STATUS_NO_SUCH_FILE;
230 Open->DumpOffset.QuadPart=24;
232 ntStatus = PsCreateSystemThread(&Open->DumpThreadHandle,
237 (PKSTART_ROUTINE)NPF_DumpThread,
240 if ( !NT_SUCCESS( ntStatus ) )
242 IF_LOUD(DbgPrint("NPF: Error creating dump thread, status=%x\n", ntStatus);)
244 ZwClose( Open->DumpFileHandle );
245 Open->DumpFileHandle=NULL;
249 ntStatus = ObReferenceObjectByHandle(Open->DumpThreadHandle,
253 (PVOID*)&Open->DumpThreadObject,
255 if ( !NT_SUCCESS( ntStatus ) )
257 IF_LOUD(DbgPrint("NPF: Error creating dump thread, status=%x\n", ntStatus);)
259 ObDereferenceObject(Open->DumpFileObject);
260 ZwClose( Open->DumpFileHandle );
261 Open->DumpFileHandle=NULL;
270 //-------------------------------------------------------------------
272 //-------------------------------------------------------------------
274 VOID NPF_DumpThread(POPEN_INSTANCE Open)
278 IF_LOUD(DbgPrint("NPF: In the work routine. Parameter = 0x%0x\n",Open);)
282 // Wait until some packets arrive or the timeout expires
283 NdisWaitEvent(&Open->DumpEvent, 5000);
285 IF_LOUD(DbgPrint("NPF: Worker Thread - event signalled\n");)
287 if(Open->DumpLimitReached ||
288 Open->BufSize==0){ // BufSize=0 means that this instance was closed, or that the buffer is too
289 // small for any capture. In both cases it is better to end the dump
291 IF_LOUD(DbgPrint("NPF: Worker Thread - Exiting happily\n");)
292 IF_LOUD(DbgPrint("Thread: Dumpoffset=%I64d\n",Open->DumpOffset.QuadPart);)
294 PsTerminateSystemThread(STATUS_SUCCESS);
298 NdisResetEvent(&Open->DumpEvent);
300 // Write the content of the buffer to the file
301 if(NPF_SaveCurrentBuffer(Open) != STATUS_SUCCESS){
302 PsTerminateSystemThread(STATUS_SUCCESS);
310 //-------------------------------------------------------------------
312 NTSTATUS NPF_SaveCurrentBuffer(POPEN_INSTANCE Open)
319 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 //-------------------------------------------------------------------
519 PacketDumpCompletion(PDEVICE_OBJECT DeviceObject,
524 // Copy the status information back into the "user" IOSB
525 *Irp->UserIosb = Irp->IoStatus;
527 // Wake up the mainline code
528 KeSetEvent(Irp->UserEvent, 0, FALSE);
530 return STATUS_MORE_PROCESSING_REQUIRED;
533 //-------------------------------------------------------------------
535 VOID NPF_WriteDumpFile(PFILE_OBJECT FileObject,
536 PLARGE_INTEGER Offset,
539 PIO_STATUS_BLOCK IoStatusBlock)
543 PIO_STACK_LOCATION ioStackLocation;
544 PDEVICE_OBJECT fsdDevice = IoGetRelatedDeviceObject(FileObject);
547 // Set up the event we'll use
548 KeInitializeEvent(&event, SynchronizationEvent, FALSE);
550 // Allocate and build the IRP we'll be sending to the FSD
551 irp = IoAllocateIrp(fsdDevice->StackSize, FALSE);
554 // Allocation failed, presumably due to memory allocation failure
555 IoStatusBlock->Status = STATUS_INSUFFICIENT_RESOURCES;
556 IoStatusBlock->Information = 0;
561 irp->MdlAddress = Mdl;
562 irp->UserEvent = &event;
563 irp->UserIosb = IoStatusBlock;
564 irp->Tail.Overlay.Thread = PsGetCurrentThread();
565 irp->Tail.Overlay.OriginalFileObject= FileObject;
566 irp->RequestorMode = KernelMode;
568 // Indicate that this is a WRITE operation
569 irp->Flags = IRP_WRITE_OPERATION;
571 // Set up the next I/O stack location
572 ioStackLocation = IoGetNextIrpStackLocation(irp);
573 ioStackLocation->MajorFunction = IRP_MJ_WRITE;
574 ioStackLocation->MinorFunction = 0;
575 ioStackLocation->DeviceObject = fsdDevice;
576 ioStackLocation->FileObject = FileObject;
577 IoSetCompletionRoutine(irp, PacketDumpCompletion, 0, TRUE, TRUE, TRUE);
578 ioStackLocation->Parameters.Write.Length = Length;
579 ioStackLocation->Parameters.Write.ByteOffset = *Offset;
582 // Send it on. Ignore the return code
583 (void) IoCallDriver(fsdDevice, irp);
585 // Wait for the I/O to complete.
586 KeWaitForSingleObject(&event, Executive, KernelMode, TRUE, 0);
588 // Free the IRP now that we are done with it