add winpcap 4.0.2 from url http://www.winpcap.org/
[natblaster.git] / winpcap / packetNtx / driver / dump.c
blob8ec72f742ac2bf0388d5ab22bfd1082c6bee7f72
1 /*
2 * Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy)
3 * Copyright (c) 2005 - 2007 CACE Technologies, Davis (California)
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the Politecnico di Torino, CACE Technologies
16 * nor the names of its contributors may be used to endorse or promote
17 * products derived from this software without specific prior written
18 * permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 #include <ntddk.h>
35 #include <ndis.h>
37 #include "debug.h"
38 #include "packet.h"
39 #include "win_bpf.h"
41 //-------------------------------------------------------------------
43 NTSTATUS
44 NPF_OpenDumpFile(POPEN_INSTANCE Open , PUNICODE_STRING fileName, BOOLEAN Append)
46 NTSTATUS ntStatus;
47 IO_STATUS_BLOCK IoStatus;
48 OBJECT_ATTRIBUTES ObjectAttributes;
49 PWCHAR PathPrefix;
50 USHORT PathLen;
51 UNICODE_STRING FullFileName;
52 ULONG FullFileNameLength;
53 PDEVICE_OBJECT fsdDevice;
55 FILE_STANDARD_INFORMATION StandardInfo;
57 IF_LOUD(DbgPrint("NPF: OpenDumpFile.\n");)
59 if(fileName->Buffer[0] == L'\\' &&
60 fileName->Buffer[1] == L'?' &&
61 fileName->Buffer[2] == L'?' &&
62 fileName->Buffer[3] == L'\\'
64 PathLen = 0;
66 else{
67 PathPrefix = L"\\??\\";
68 PathLen = 8;
71 // Insert the correct path prefix.
72 FullFileNameLength = PathLen + fileName->MaximumLength;
74 FullFileName.Buffer = ExAllocatePoolWithTag(NonPagedPool,
75 FullFileNameLength,
76 '0DWA');
78 if (FullFileName.Buffer == NULL) {
79 ntStatus = STATUS_INSUFFICIENT_RESOURCES;
80 return ntStatus;
83 FullFileName.Length = PathLen;
84 FullFileName.MaximumLength = (USHORT)FullFileNameLength;
86 if(PathLen)
87 RtlMoveMemory (FullFileName.Buffer, PathPrefix, PathLen);
89 RtlAppendUnicodeStringToString (&FullFileName, fileName);
91 IF_LOUD(DbgPrint( "Packet: Attempting to open %wZ\n", &FullFileName);)
93 InitializeObjectAttributes ( &ObjectAttributes,
94 &FullFileName,
95 OBJ_CASE_INSENSITIVE,
96 NULL,
97 NULL );
99 // Create the dump file
100 ntStatus = ZwCreateFile( &Open->DumpFileHandle,
101 SYNCHRONIZE | FILE_WRITE_DATA,
102 &ObjectAttributes,
103 &IoStatus,
104 NULL,
105 FILE_ATTRIBUTE_NORMAL,
106 FILE_SHARE_READ,
107 (Append)?FILE_OPEN_IF:FILE_SUPERSEDE,
108 FILE_SYNCHRONOUS_IO_NONALERT,
109 NULL,
110 0 );
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;
119 return ntStatus;
122 ExFreePool(FullFileName.Buffer);
124 ntStatus = ObReferenceObjectByHandle(Open->DumpFileHandle,
125 FILE_WRITE_ACCESS,
126 *IoFileObjectType,
127 KernelMode,
128 &Open->DumpFileObject,
131 if ( !NT_SUCCESS( ntStatus ) )
133 IF_LOUD(DbgPrint("NPF: Error creating file, status=%x\n", ntStatus);)
135 ZwClose( Open->DumpFileHandle );
136 Open->DumpFileHandle=NULL;
138 ntStatus = STATUS_NO_SUCH_FILE;
139 return ntStatus;
142 fsdDevice = IoGetRelatedDeviceObject(Open->DumpFileObject);
144 IF_LOUD(DbgPrint("NPF: Dump: write file created succesfully, status=%d \n",ntStatus);)
146 return ntStatus;
149 //-------------------------------------------------------------------
151 NTSTATUS
152 NPF_StartDump(POPEN_INSTANCE Open)
154 NTSTATUS ntStatus;
155 struct packet_file_header hdr;
156 IO_STATUS_BLOCK IoStatus;
157 NDIS_REQUEST pRequest;
158 ULONG MediaType;
159 OBJECT_ATTRIBUTES ObjectAttributes;
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*/
168 hdr.snaplen = 1514;
169 hdr.sigfigs = 0;
171 // Detect the medium type
172 switch (Open->Medium){
174 case NdisMediumWan:
175 hdr.linktype = DLT_EN10MB;
176 break;
178 case NdisMedium802_3:
179 hdr.linktype = DLT_EN10MB;
180 break;
182 case NdisMediumFddi:
183 hdr.linktype = DLT_FDDI;
184 break;
186 case NdisMedium802_5:
187 hdr.linktype = DLT_IEEE802;
188 break;
190 case NdisMediumArcnet878_2:
191 hdr.linktype = DLT_ARCNET;
192 break;
194 case NdisMediumAtm:
195 hdr.linktype = DLT_ATM_RFC1483;
196 break;
198 default:
199 hdr.linktype = DLT_EN10MB;
202 // Write the header.
203 // We can use ZwWriteFile because we are in the context of the application
204 ntStatus = ZwWriteFile(Open->DumpFileHandle,
205 NULL,
206 NULL,
207 NULL,
208 &IoStatus,
209 &hdr,
210 sizeof(hdr),
211 NULL,
212 NULL );
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;
223 return ntStatus;
226 Open->DumpOffset.QuadPart=24;
228 ntStatus = PsCreateSystemThread(&Open->DumpThreadHandle,
229 THREAD_ALL_ACCESS,
230 (ACCESS_MASK)0L,
233 NPF_DumpThread,
234 Open);
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;
243 return ntStatus;
246 ntStatus = ObReferenceObjectByHandle(Open->DumpThreadHandle,
247 THREAD_ALL_ACCESS,
248 NULL,
249 KernelMode,
250 &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;
261 return ntStatus;
265 return ntStatus;
269 //-------------------------------------------------------------------
270 // Dump Thread
271 //-------------------------------------------------------------------
273 VOID NPF_DumpThread(POPEN_INSTANCE Open)
275 ULONG FrozenNic;
277 IF_LOUD(DbgPrint("NPF: In the work routine. Parameter = 0x%p\n",Open);)
279 while(TRUE){
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->Size==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);
294 return;
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);
302 return;
309 //-------------------------------------------------------------------
311 NTSTATUS NPF_SaveCurrentBuffer(POPEN_INSTANCE Open)
313 UINT Thead;
314 UINT Ttail;
315 UINT TLastByte;
316 PUCHAR CurrBuff;
317 NTSTATUS ntStatus;
318 IO_STATUS_BLOCK IoStatus;
319 PMDL lMdl;
320 UINT SizeToDump;
322 #if 0
324 Thead=Open->Bhead;
325 Ttail=Open->Btail;
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
335 if( Ttail < Thead )
337 if(Open->MaxDumpBytes &&
338 (UINT)Open->DumpOffset.QuadPart /*+ GetBuffOccupation(Open)*/ > Open->MaxDumpBytes)
340 // Size limit reached
341 UINT PktLen;
343 SizeToDump = 0;
345 // Scan the buffer to detect the exact amount of data to save
346 while(TRUE){
347 PktLen = ((struct sf_pkthdr*)(CurrBuff + Thead + SizeToDump))->caplen + sizeof(struct sf_pkthdr);
349 if((UINT)Open->DumpOffset.QuadPart + SizeToDump + PktLen > Open->MaxDumpBytes)
350 break;
352 SizeToDump += PktLen;
356 else
357 SizeToDump = TLastByte-Thead;
359 lMdl=IoAllocateMdl(CurrBuff+Thead, SizeToDump, FALSE, FALSE, NULL);
360 if (lMdl == 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);
369 // Write to disk
370 NPF_WriteDumpFile(Open->DumpFileObject,
371 &Open->DumpOffset,
372 SizeToDump,
373 lMdl,
374 &IoStatus);
376 IoFreeMdl(lMdl);
378 if(!NT_SUCCESS(IoStatus.Status)){
379 // Error
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;
396 Open->Bhead=0;
399 if( Ttail > Thead ){
401 if(Open->MaxDumpBytes &&
402 (UINT)Open->DumpOffset.QuadPart /* +GetBuffOccupation(Open)*/ > Open->MaxDumpBytes)
404 // Size limit reached
405 UINT PktLen;
407 SizeToDump = 0;
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)
415 break;
417 SizeToDump += PktLen;
421 else
422 SizeToDump = Ttail-Thead;
424 lMdl=IoAllocateMdl(CurrBuff+Thead, SizeToDump, FALSE, FALSE, NULL);
425 if (lMdl == 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);
434 // Write to disk
435 NPF_WriteDumpFile(Open->DumpFileObject,
436 &Open->DumpOffset,
437 SizeToDump,
438 lMdl,
439 &IoStatus);
441 IoFreeMdl(lMdl);
443 if(!NT_SUCCESS(IoStatus.Status)){
444 // Error
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);
460 Open->Bhead=Ttail;
463 #endif
464 return STATUS_SUCCESS;
467 //-------------------------------------------------------------------
469 NTSTATUS NPF_CloseDumpFile(POPEN_INSTANCE Open){
470 NTSTATUS ntStatus;
471 IO_STATUS_BLOCK IoStatus;
472 PMDL WriteMdl;
473 PUCHAR VMBuff;
474 UINT VMBufLen;
476 #if 0
477 IF_LOUD(DbgPrint("NPF: NPF_CloseDumpFile.\n");)
478 IF_LOUD(DbgPrint("Dumpoffset=%d\n",Open->DumpOffset.QuadPart);)
480 DbgPrint("1\n");
481 // Consistency check
482 if(Open->DumpFileHandle == NULL)
483 return STATUS_UNSUCCESSFUL;
485 DbgPrint("2\n");
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;
494 DbgPrint("3\n");
496 NPF_OpenDumpFile(Open,&Open->DumpFileName, TRUE);
498 // Flush the buffer to file
499 NPF_SaveCurrentBuffer(Open);
501 // Close The file
502 ObDereferenceObject(Open->DumpFileObject);
503 ZwClose( Open->DumpFileHandle );
505 Open->DumpFileHandle = NULL;
507 ObDereferenceObject(Open->DumpFileObject);
508 #endif
509 return STATUS_SUCCESS;
512 //-------------------------------------------------------------------
514 static NTSTATUS PacketDumpCompletion(PDEVICE_OBJECT DeviceObject,
515 PIRP Irp,
516 PVOID Context)
519 // Copy the status information back into the "user" IOSB
520 *Irp->UserIosb = Irp->IoStatus;
522 // Wake up the mainline code
523 KeSetEvent(Irp->UserEvent, 0, FALSE);
525 return STATUS_MORE_PROCESSING_REQUIRED;
528 //-------------------------------------------------------------------
530 VOID NPF_WriteDumpFile(PFILE_OBJECT FileObject,
531 PLARGE_INTEGER Offset,
532 ULONG Length,
533 PMDL Mdl,
534 PIO_STATUS_BLOCK IoStatusBlock)
536 PIRP irp;
537 KEVENT event;
538 PIO_STACK_LOCATION ioStackLocation;
539 PDEVICE_OBJECT fsdDevice = IoGetRelatedDeviceObject(FileObject);
540 NTSTATUS Status;
542 // Set up the event we'll use
543 KeInitializeEvent(&event, SynchronizationEvent, FALSE);
545 // Allocate and build the IRP we'll be sending to the FSD
546 irp = IoAllocateIrp(fsdDevice->StackSize, FALSE);
548 if (!irp) {
549 // Allocation failed, presumably due to memory allocation failure
550 IoStatusBlock->Status = STATUS_INSUFFICIENT_RESOURCES;
551 IoStatusBlock->Information = 0;
553 return;
556 irp->MdlAddress = Mdl;
557 irp->UserEvent = &event;
558 irp->UserIosb = IoStatusBlock;
559 irp->Tail.Overlay.Thread = PsGetCurrentThread();
560 irp->Tail.Overlay.OriginalFileObject= FileObject;
561 irp->RequestorMode = KernelMode;
563 // Indicate that this is a WRITE operation
564 irp->Flags = IRP_WRITE_OPERATION;
566 // Set up the next I/O stack location
567 ioStackLocation = IoGetNextIrpStackLocation(irp);
568 ioStackLocation->MajorFunction = IRP_MJ_WRITE;
569 ioStackLocation->MinorFunction = 0;
570 ioStackLocation->DeviceObject = fsdDevice;
571 ioStackLocation->FileObject = FileObject;
572 IoSetCompletionRoutine(irp, PacketDumpCompletion, 0, TRUE, TRUE, TRUE);
573 ioStackLocation->Parameters.Write.Length = Length;
574 ioStackLocation->Parameters.Write.ByteOffset = *Offset;
577 // Send it on. Ignore the return code
578 (void) IoCallDriver(fsdDevice, irp);
580 // Wait for the I/O to complete.
581 KeWaitForSingleObject(&event, Executive, KernelMode, TRUE, 0);
583 // Free the IRP now that we are done with it
584 IoFreeIrp(irp);
586 return;