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>
36 //-------------------------------------------------------------------
39 NPF_OpenDumpFile(POPEN_INSTANCE Open , PUNICODE_STRING fileName, BOOLEAN Append)
42 IO_STATUS_BLOCK IoStatus;
43 OBJECT_ATTRIBUTES ObjectAttributes;
46 UNICODE_STRING FullFileName;
47 ULONG FullFileNameLength;
48 PDEVICE_OBJECT fsdDevice;
50 FILE_STANDARD_INFORMATION StandardInfo;
52 IF_LOUD(DbgPrint("NPF: OpenDumpFile.\n");)
54 if(fileName->Buffer[0] == L'\\' &&
55 fileName->Buffer[1] == L'?' &&
56 fileName->Buffer[2] == L'?' &&
57 fileName->Buffer[3] == L'\\'
62 PathPrefix = L"\\??\\";
66 // Insert the correct path prefix.
67 FullFileNameLength = PathLen + fileName->MaximumLength;
69 FullFileName.Buffer = ExAllocatePoolWithTag(NonPagedPool,
73 if (FullFileName.Buffer == NULL) {
74 ntStatus = STATUS_INSUFFICIENT_RESOURCES;
78 FullFileName.Length = PathLen;
79 FullFileName.MaximumLength = (USHORT)FullFileNameLength;
82 RtlMoveMemory (FullFileName.Buffer, PathPrefix, PathLen);
84 RtlAppendUnicodeStringToString (&FullFileName, fileName);
86 IF_LOUD(DbgPrint( "Packet: Attempting to open %wZ\n", &FullFileName);)
88 InitializeObjectAttributes ( &ObjectAttributes,
94 // Create the dump file
95 ntStatus = ZwCreateFile( &Open->DumpFileHandle,
96 SYNCHRONIZE | FILE_WRITE_DATA,
100 FILE_ATTRIBUTE_NORMAL,
102 (Append)?FILE_OPEN_IF:FILE_SUPERSEDE,
103 FILE_SYNCHRONOUS_IO_NONALERT,
107 if ( !NT_SUCCESS( ntStatus ) )
109 IF_LOUD(DbgPrint("NPF: Error opening file %x\n", ntStatus);)
111 ExFreePool(FullFileName.Buffer);
112 Open->DumpFileHandle=NULL;
113 ntStatus = STATUS_NO_SUCH_FILE;
117 ExFreePool(FullFileName.Buffer);
119 ntStatus = ObReferenceObjectByHandle(Open->DumpFileHandle,
127 &Open->DumpFileObject,
130 if ( !NT_SUCCESS( ntStatus ) )
132 IF_LOUD(DbgPrint("NPF: Error creating file, status=%x\n", ntStatus);)
134 ZwClose( Open->DumpFileHandle );
135 Open->DumpFileHandle=NULL;
137 ntStatus = STATUS_NO_SUCH_FILE;
141 fsdDevice = IoGetRelatedDeviceObject(Open->DumpFileObject);
143 IF_LOUD(DbgPrint("NPF: Dump: write file created succesfully, status=%d \n",ntStatus);)
148 //-------------------------------------------------------------------
151 NPF_StartDump(POPEN_INSTANCE Open)
154 struct packet_file_header hdr;
155 IO_STATUS_BLOCK IoStatus;
156 NDIS_REQUEST pRequest;
158 OBJECT_ATTRIBUTES ObjectAttributes;
160 IF_LOUD(DbgPrint("NPF: StartDump.\n");)
162 // Init the file header
163 hdr.magic = TCPDUMP_MAGIC;
164 hdr.version_major = PCAP_VERSION_MAJOR;
165 hdr.version_minor = PCAP_VERSION_MINOR;
166 hdr.thiszone = 0; /*Currently not set*/
170 // Detect the medium type
171 switch (Open->Medium){
174 hdr.linktype = DLT_EN10MB;
177 case NdisMedium802_3:
178 hdr.linktype = DLT_EN10MB;
182 hdr.linktype = DLT_FDDI;
185 case NdisMedium802_5:
186 hdr.linktype = DLT_IEEE802;
189 case NdisMediumArcnet878_2:
190 hdr.linktype = DLT_ARCNET;
194 hdr.linktype = DLT_ATM_RFC1483;
198 hdr.linktype = DLT_EN10MB;
202 // We can use ZwWriteFile because we are in the context of the application
203 ntStatus = ZwWriteFile(Open->DumpFileHandle,
214 if ( !NT_SUCCESS( ntStatus ) )
216 IF_LOUD(DbgPrint("NPF: Error dumping file %x\n", ntStatus);)
218 ZwClose( Open->DumpFileHandle );
219 Open->DumpFileHandle=NULL;
221 ntStatus = STATUS_NO_SUCH_FILE;
225 Open->DumpOffset.QuadPart=24;
227 ntStatus = PsCreateSystemThread(&Open->DumpThreadHandle,
235 if ( !NT_SUCCESS( ntStatus ) )
237 IF_LOUD(DbgPrint("NPF: Error creating dump thread, status=%x\n", ntStatus);)
239 ZwClose( Open->DumpFileHandle );
240 Open->DumpFileHandle=NULL;
245 ntStatus = ObReferenceObjectByHandle(Open->DumpThreadHandle,
249 &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%0x\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->BufSize==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;
325 TLastByte=Open->BLastByte;
327 IF_LOUD(DbgPrint("NPF: NPF_SaveCurrentBuffer.\n");)
329 // Get the address of the buffer
330 CurrBuff=Open->Buffer;
332 // Fill the application buffer
336 if(Open->MaxDumpBytes &&
337 (UINT)Open->DumpOffset.QuadPart + GetBuffOccupation(Open) > Open->MaxDumpBytes)
339 // Size limit reached
344 // Scan the buffer to detect the exact amount of data to save
346 PktLen = ((struct sf_pkthdr*)(CurrBuff + Thead + SizeToDump))->caplen + sizeof(struct sf_pkthdr);
348 if((UINT)Open->DumpOffset.QuadPart + SizeToDump + PktLen > Open->MaxDumpBytes)
351 SizeToDump += PktLen;
356 SizeToDump = TLastByte-Thead;
358 lMdl=IoAllocateMdl(CurrBuff+Thead, SizeToDump, FALSE, FALSE, NULL);
361 // No memory: stop dump
362 IF_LOUD(DbgPrint("NPF: dump thread: Failed to allocate Mdl\n");)
363 return STATUS_UNSUCCESSFUL;
366 MmBuildMdlForNonPagedPool(lMdl);
369 NPF_WriteDumpFile(Open->DumpFileObject,
377 if(!NT_SUCCESS(IoStatus.Status)){
379 return STATUS_UNSUCCESSFUL;
382 if(SizeToDump != TLastByte-Thead){
383 // Size limit reached.
384 Open->DumpLimitReached = TRUE;
386 // Awake the application
387 KeSetEvent(Open->ReadEvent,0,FALSE);
389 return STATUS_UNSUCCESSFUL;
392 // Update the packet buffer
393 Open->DumpOffset.QuadPart+=(TLastByte-Thead);
394 Open->BLastByte=Ttail;
400 if(Open->MaxDumpBytes &&
401 (UINT)Open->DumpOffset.QuadPart + GetBuffOccupation(Open) > Open->MaxDumpBytes)
403 // Size limit reached
408 // Scan the buffer to detect the exact amount of data to save
409 while(Thead + SizeToDump < Ttail){
411 PktLen = ((struct sf_pkthdr*)(CurrBuff + Thead + SizeToDump))->caplen + sizeof(struct sf_pkthdr);
413 if((UINT)Open->DumpOffset.QuadPart + SizeToDump + PktLen > Open->MaxDumpBytes)
416 SizeToDump += PktLen;
421 SizeToDump = Ttail-Thead;
423 lMdl=IoAllocateMdl(CurrBuff+Thead, SizeToDump, FALSE, FALSE, NULL);
426 // No memory: stop dump
427 IF_LOUD(DbgPrint("NPF: dump thread: Failed to allocate Mdl\n");)
428 return STATUS_UNSUCCESSFUL;
431 MmBuildMdlForNonPagedPool(lMdl);
434 NPF_WriteDumpFile(Open->DumpFileObject,
442 if(!NT_SUCCESS(IoStatus.Status)){
444 return STATUS_UNSUCCESSFUL;
447 if(SizeToDump != Ttail-Thead){
448 // Size limit reached.
449 Open->DumpLimitReached = TRUE;
451 // Awake the application
452 KeSetEvent(Open->ReadEvent,0,FALSE);
454 return STATUS_UNSUCCESSFUL;
457 // Update the packet buffer
458 Open->DumpOffset.QuadPart+=(Ttail-Thead);
463 return STATUS_SUCCESS;
466 //-------------------------------------------------------------------
468 NTSTATUS NPF_CloseDumpFile(POPEN_INSTANCE Open){
470 IO_STATUS_BLOCK IoStatus;
476 IF_LOUD(DbgPrint("NPF: NPF_CloseDumpFile.\n");)
477 IF_LOUD(DbgPrint("Dumpoffset=%d\n",Open->DumpOffset.QuadPart);)
481 if(Open->DumpFileHandle == NULL)
482 return STATUS_UNSUCCESSFUL;
485 ZwClose( Open->DumpFileHandle );
487 ObDereferenceObject(Open->DumpFileObject);
489 if(Open->DumpLimitReached == TRUE)
490 // Limit already reached: don't save the rest of the buffer.
491 return STATUS_SUCCESS;
495 NPF_OpenDumpFile(Open,&Open->DumpFileName, TRUE);
497 // Flush the buffer to file
498 NPF_SaveCurrentBuffer(Open);
501 ObDereferenceObject(Open->DumpFileObject);
502 ZwClose( Open->DumpFileHandle );
504 Open->DumpFileHandle = NULL;
506 ObDereferenceObject(Open->DumpFileObject);
508 return STATUS_SUCCESS;
511 //-------------------------------------------------------------------
513 static NTSTATUS PacketDumpCompletion(PDEVICE_OBJECT DeviceObject,
518 // Copy the status information back into the "user" IOSB
519 *Irp->UserIosb = Irp->IoStatus;
521 // Wake up the mainline code
522 KeSetEvent(Irp->UserEvent, 0, FALSE);
524 return STATUS_MORE_PROCESSING_REQUIRED;
527 //-------------------------------------------------------------------
529 VOID NPF_WriteDumpFile(PFILE_OBJECT FileObject,
530 PLARGE_INTEGER Offset,
533 PIO_STATUS_BLOCK IoStatusBlock)
537 PIO_STACK_LOCATION ioStackLocation;
538 PDEVICE_OBJECT fsdDevice = IoGetRelatedDeviceObject(FileObject);
541 // Set up the event we'll use
542 KeInitializeEvent(&event, SynchronizationEvent, FALSE);
544 // Allocate and build the IRP we'll be sending to the FSD
545 irp = IoAllocateIrp(fsdDevice->StackSize, FALSE);
548 // Allocation failed, presumably due to memory allocation failure
549 IoStatusBlock->Status = STATUS_INSUFFICIENT_RESOURCES;
550 IoStatusBlock->Information = 0;
555 irp->MdlAddress = Mdl;
556 irp->UserEvent = &event;
557 irp->UserIosb = IoStatusBlock;
558 irp->Tail.Overlay.Thread = PsGetCurrentThread();
559 irp->Tail.Overlay.OriginalFileObject= FileObject;
560 irp->RequestorMode = KernelMode;
562 // Indicate that this is a WRITE operation
563 irp->Flags = IRP_WRITE_OPERATION;
565 // Set up the next I/O stack location
566 ioStackLocation = IoGetNextIrpStackLocation(irp);
567 ioStackLocation->MajorFunction = IRP_MJ_WRITE;
568 ioStackLocation->MinorFunction = 0;
569 ioStackLocation->DeviceObject = fsdDevice;
570 ioStackLocation->FileObject = FileObject;
571 IoSetCompletionRoutine(irp, PacketDumpCompletion, 0, TRUE, TRUE, TRUE);
572 ioStackLocation->Parameters.Write.Length = Length;
573 ioStackLocation->Parameters.Write.ByteOffset = *Offset;
576 // Send it on. Ignore the return code
577 (void) IoCallDriver(fsdDevice, irp);
579 // Wait for the I/O to complete.
580 KeWaitForSingleObject(&event, Executive, KernelMode, TRUE, 0);
582 // Free the IRP now that we are done with it