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 #define PsGetCurrentThread() ((PETHREAD) (KeGetCurrentThread()))
38 //-------------------------------------------------------------------
41 NPF_OpenDumpFile(POPEN_INSTANCE Open , PUNICODE_STRING fileName, BOOLEAN Append)
44 IO_STATUS_BLOCK IoStatus;
45 OBJECT_ATTRIBUTES ObjectAttributes;
48 UNICODE_STRING FullFileName;
49 ULONG FullFileNameLength;
50 PDEVICE_OBJECT fsdDevice;
52 FILE_STANDARD_INFORMATION StandardInfo;
54 IF_LOUD(DbgPrint("NPF: OpenDumpFile.\n");)
56 if(fileName->Buffer[0] == L'\\' &&
57 fileName->Buffer[1] == L'?' &&
58 fileName->Buffer[2] == L'?' &&
59 fileName->Buffer[3] == L'\\'
64 PathPrefix = L"\\??\\";
68 // Insert the correct path prefix.
69 FullFileNameLength = PathLen + fileName->MaximumLength;
71 #define NPF_TAG_FILENAME TAG('0', 'D', 'W', 'A')
72 FullFileName.Buffer = ExAllocatePoolWithTag(NonPagedPool,
76 if (FullFileName.Buffer == NULL) {
77 ntStatus = STATUS_INSUFFICIENT_RESOURCES;
81 FullFileName.Length = PathLen;
82 FullFileName.MaximumLength = (USHORT)FullFileNameLength;
85 RtlMoveMemory (FullFileName.Buffer, PathPrefix, PathLen);
87 RtlAppendUnicodeStringToString (&FullFileName, fileName);
89 IF_LOUD(DbgPrint( "Packet: Attempting to open %wZ\n", &FullFileName);)
91 InitializeObjectAttributes ( &ObjectAttributes,
97 // Create the dump file
98 ntStatus = ZwCreateFile( &Open->DumpFileHandle,
99 SYNCHRONIZE | FILE_WRITE_DATA,
103 FILE_ATTRIBUTE_NORMAL,
105 (Append)?FILE_OPEN_IF:FILE_SUPERSEDE,
106 FILE_SYNCHRONOUS_IO_NONALERT,
110 if ( !NT_SUCCESS( ntStatus ) )
112 IF_LOUD(DbgPrint("NPF: Error opening file %x\n", ntStatus);)
114 ExFreePool(FullFileName.Buffer);
115 Open->DumpFileHandle=NULL;
116 ntStatus = STATUS_NO_SUCH_FILE;
120 ExFreePool(FullFileName.Buffer);
122 ntStatus = ObReferenceObjectByHandle(Open->DumpFileHandle,
130 (PVOID)&Open->DumpFileObject,
133 if ( !NT_SUCCESS( ntStatus ) )
135 IF_LOUD(DbgPrint("NPF: Error creating file, status=%x\n", ntStatus);)
137 ZwClose( Open->DumpFileHandle );
138 Open->DumpFileHandle=NULL;
140 ntStatus = STATUS_NO_SUCH_FILE;
144 fsdDevice = IoGetRelatedDeviceObject(Open->DumpFileObject);
146 IF_LOUD(DbgPrint("NPF: Dump: write file created succesfully, status=%d \n",ntStatus);)
151 //-------------------------------------------------------------------
154 NPF_StartDump(POPEN_INSTANCE Open)
157 struct packet_file_header hdr;
158 IO_STATUS_BLOCK IoStatus;
159 NDIS_REQUEST pRequest;
161 OBJECT_ATTRIBUTES ObjectAttributes;
163 IF_LOUD(DbgPrint("NPF: StartDump.\n");)
165 // Init the file header
166 hdr.magic = TCPDUMP_MAGIC;
167 hdr.version_major = PCAP_VERSION_MAJOR;
168 hdr.version_minor = PCAP_VERSION_MINOR;
169 hdr.thiszone = 0; /*Currently not set*/
173 // Detect the medium type
174 switch (Open->Medium){
177 hdr.linktype = DLT_EN10MB;
180 case NdisMedium802_3:
181 hdr.linktype = DLT_EN10MB;
185 hdr.linktype = DLT_FDDI;
188 case NdisMedium802_5:
189 hdr.linktype = DLT_IEEE802;
192 case NdisMediumArcnet878_2:
193 hdr.linktype = DLT_ARCNET;
197 hdr.linktype = DLT_ATM_RFC1483;
201 hdr.linktype = DLT_EN10MB;
205 // We can use ZwWriteFile because we are in the context of the application
206 ntStatus = ZwWriteFile(Open->DumpFileHandle,
217 if ( !NT_SUCCESS( ntStatus ) )
219 IF_LOUD(DbgPrint("NPF: Error dumping file %x\n", ntStatus);)
221 ZwClose( Open->DumpFileHandle );
222 Open->DumpFileHandle=NULL;
224 ntStatus = STATUS_NO_SUCH_FILE;
228 Open->DumpOffset.QuadPart=24;
230 ntStatus = PsCreateSystemThread(&Open->DumpThreadHandle,
235 (PKSTART_ROUTINE)NPF_DumpThread,
238 if ( !NT_SUCCESS( ntStatus ) )
240 IF_LOUD(DbgPrint("NPF: Error creating dump thread, status=%x\n", ntStatus);)
242 ZwClose( Open->DumpFileHandle );
243 Open->DumpFileHandle=NULL;
247 ntStatus = ObReferenceObjectByHandle(Open->DumpThreadHandle,
251 (PVOID*)&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;
268 //-------------------------------------------------------------------
270 //-------------------------------------------------------------------
272 VOID NPF_DumpThread(POPEN_INSTANCE Open)
276 IF_LOUD(DbgPrint("NPF: In the work routine. Parameter = 0x%0x\n",Open);)
280 // Wait until some packets arrive or the timeout expires
281 NdisWaitEvent(&Open->DumpEvent, 5000);
283 IF_LOUD(DbgPrint("NPF: Worker Thread - event signalled\n");)
285 if(Open->DumpLimitReached ||
286 Open->BufSize==0){ // BufSize=0 means that this instance was closed, or that the buffer is too
287 // small for any capture. In both cases it is better to end the dump
289 IF_LOUD(DbgPrint("NPF: Worker Thread - Exiting happily\n");)
290 IF_LOUD(DbgPrint("Thread: Dumpoffset=%I64d\n",Open->DumpOffset.QuadPart);)
292 PsTerminateSystemThread(STATUS_SUCCESS);
296 NdisResetEvent(&Open->DumpEvent);
298 // Write the content of the buffer to the file
299 if(NPF_SaveCurrentBuffer(Open) != STATUS_SUCCESS){
300 PsTerminateSystemThread(STATUS_SUCCESS);
308 //-------------------------------------------------------------------
310 NTSTATUS NPF_SaveCurrentBuffer(POPEN_INSTANCE Open)
317 IO_STATUS_BLOCK IoStatus;
324 TLastByte=Open->BLastByte;
326 IF_LOUD(DbgPrint("NPF: NPF_SaveCurrentBuffer.\n");)
328 // Get the address of the buffer
329 CurrBuff=Open->Buffer;
331 // Fill the application buffer
335 if(Open->MaxDumpBytes &&
336 (UINT)Open->DumpOffset.QuadPart + GetBuffOccupation(Open) > Open->MaxDumpBytes)
338 // Size limit reached
343 // Scan the buffer to detect the exact amount of data to save
345 PktLen = ((struct sf_pkthdr*)(CurrBuff + Thead + SizeToDump))->caplen + sizeof(struct sf_pkthdr);
347 if((UINT)Open->DumpOffset.QuadPart + SizeToDump + PktLen > Open->MaxDumpBytes)
350 SizeToDump += PktLen;
355 SizeToDump = TLastByte-Thead;
357 lMdl=IoAllocateMdl(CurrBuff+Thead, SizeToDump, FALSE, FALSE, NULL);
360 // No memory: stop dump
361 IF_LOUD(DbgPrint("NPF: dump thread: Failed to allocate Mdl\n");)
362 return STATUS_UNSUCCESSFUL;
365 MmBuildMdlForNonPagedPool(lMdl);
368 NPF_WriteDumpFile(Open->DumpFileObject,
376 if(!NT_SUCCESS(IoStatus.Status)){
378 return STATUS_UNSUCCESSFUL;
381 if(SizeToDump != TLastByte-Thead){
382 // Size limit reached.
383 Open->DumpLimitReached = TRUE;
385 // Awake the application
386 KeSetEvent(Open->ReadEvent,0,FALSE);
388 return STATUS_UNSUCCESSFUL;
391 // Update the packet buffer
392 Open->DumpOffset.QuadPart+=(TLastByte-Thead);
393 Open->BLastByte=Ttail;
399 if(Open->MaxDumpBytes &&
400 (UINT)Open->DumpOffset.QuadPart + GetBuffOccupation(Open) > Open->MaxDumpBytes)
402 // Size limit reached
407 // Scan the buffer to detect the exact amount of data to save
408 while(Thead + SizeToDump < Ttail){
410 PktLen = ((struct sf_pkthdr*)(CurrBuff + Thead + SizeToDump))->caplen + sizeof(struct sf_pkthdr);
412 if((UINT)Open->DumpOffset.QuadPart + SizeToDump + PktLen > Open->MaxDumpBytes)
415 SizeToDump += PktLen;
420 SizeToDump = Ttail-Thead;
422 lMdl=IoAllocateMdl(CurrBuff+Thead, SizeToDump, FALSE, FALSE, NULL);
425 // No memory: stop dump
426 IF_LOUD(DbgPrint("NPF: dump thread: Failed to allocate Mdl\n");)
427 return STATUS_UNSUCCESSFUL;
430 MmBuildMdlForNonPagedPool(lMdl);
433 NPF_WriteDumpFile(Open->DumpFileObject,
441 if(!NT_SUCCESS(IoStatus.Status)){
443 return STATUS_UNSUCCESSFUL;
446 if(SizeToDump != Ttail-Thead){
447 // Size limit reached.
448 Open->DumpLimitReached = TRUE;
450 // Awake the application
451 KeSetEvent(Open->ReadEvent,0,FALSE);
453 return STATUS_UNSUCCESSFUL;
456 // Update the packet buffer
457 Open->DumpOffset.QuadPart+=(Ttail-Thead);
462 return STATUS_SUCCESS;
465 //-------------------------------------------------------------------
467 NTSTATUS NPF_CloseDumpFile(POPEN_INSTANCE Open){
469 IO_STATUS_BLOCK IoStatus;
475 IF_LOUD(DbgPrint("NPF: NPF_CloseDumpFile.\n");)
476 IF_LOUD(DbgPrint("Dumpoffset=%d\n",Open->DumpOffset.QuadPart);)
480 if(Open->DumpFileHandle == NULL)
481 return STATUS_UNSUCCESSFUL;
484 ZwClose( Open->DumpFileHandle );
486 ObDereferenceObject(Open->DumpFileObject);
488 if(Open->DumpLimitReached == TRUE)
489 // Limit already reached: don't save the rest of the buffer.
490 return STATUS_SUCCESS;
494 NPF_OpenDumpFile(Open,&Open->DumpFileName, TRUE);
496 // Flush the buffer to file
497 NPF_SaveCurrentBuffer(Open);
500 ObDereferenceObject(Open->DumpFileObject);
501 ZwClose( Open->DumpFileHandle );
503 Open->DumpFileHandle = NULL;
505 ObDereferenceObject(Open->DumpFileObject);
507 return STATUS_SUCCESS;
510 //-------------------------------------------------------------------
517 PacketDumpCompletion(PDEVICE_OBJECT DeviceObject,
522 // Copy the status information back into the "user" IOSB
523 *Irp->UserIosb = Irp->IoStatus;
525 // Wake up the mainline code
526 KeSetEvent(Irp->UserEvent, 0, FALSE);
528 return STATUS_MORE_PROCESSING_REQUIRED;
531 //-------------------------------------------------------------------
533 VOID NPF_WriteDumpFile(PFILE_OBJECT FileObject,
534 PLARGE_INTEGER Offset,
537 PIO_STATUS_BLOCK IoStatusBlock)
541 PIO_STACK_LOCATION ioStackLocation;
542 PDEVICE_OBJECT fsdDevice = IoGetRelatedDeviceObject(FileObject);
545 // Set up the event we'll use
546 KeInitializeEvent(&event, SynchronizationEvent, FALSE);
548 // Allocate and build the IRP we'll be sending to the FSD
549 irp = IoAllocateIrp(fsdDevice->StackSize, FALSE);
552 // Allocation failed, presumably due to memory allocation failure
553 IoStatusBlock->Status = STATUS_INSUFFICIENT_RESOURCES;
554 IoStatusBlock->Information = 0;
559 irp->MdlAddress = Mdl;
560 irp->UserEvent = &event;
561 irp->UserIosb = IoStatusBlock;
562 irp->Tail.Overlay.Thread = PsGetCurrentThread();
563 irp->Tail.Overlay.OriginalFileObject= FileObject;
564 irp->RequestorMode = KernelMode;
566 // Indicate that this is a WRITE operation
567 irp->Flags = IRP_WRITE_OPERATION;
569 // Set up the next I/O stack location
570 ioStackLocation = IoGetNextIrpStackLocation(irp);
571 ioStackLocation->MajorFunction = IRP_MJ_WRITE;
572 ioStackLocation->MinorFunction = 0;
573 ioStackLocation->DeviceObject = fsdDevice;
574 ioStackLocation->FileObject = FileObject;
575 IoSetCompletionRoutine(irp, PacketDumpCompletion, 0, TRUE, TRUE, TRUE);
576 ioStackLocation->Parameters.Write.Length = Length;
577 ioStackLocation->Parameters.Write.ByteOffset = *Offset;
580 // Send it on. Ignore the return code
581 (void) IoCallDriver(fsdDevice, irp);
583 // Wait for the I/O to complete.
584 KeWaitForSingleObject(&event, Executive, KernelMode, TRUE, 0);
586 // Free the IRP now that we are done with it