minor corrections by M.Taguchi
[reactos.git] / reactos / drivers / net / npf / dump.c
1 /*
2 * Copyright (c) 1999, 2000
3 * Politecnico di Torino. All rights reserved.
4 *
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
16 * written permission.
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.
20 */
21
22 #ifdef _MSC_VER
23 #include "stdarg.h"
24 #include "ntddk.h"
25 #include "ntiologc.h"
26 #include "ndis.h"
27 #else
28 #include <ddk/ntddk.h>
29 #include <net/ndis.h>
30 //#define PsGetCurrentProcess() IoGetCurrentProcess()
31 #ifndef PsGetCurrentThread
32 #define PsGetCurrentThread() ((PETHREAD) (KeGetCurrentThread()))
33 #endif
34 #endif
35
36 #include "debug.h"
37 #include "packet.h"
38 #include "win_bpf.h"
39
40 #define assert(exp) ((void)0)
41 //-------------------------------------------------------------------
42
43 NTSTATUS
44 NPF_OpenDumpFile(POPEN_INSTANCE Open , PUNICODE_STRING fileName, BOOLEAN Append)
45 {
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;
54
55 IF_LOUD(DbgPrint("NPF: OpenDumpFile.\n");)
56
57 if(fileName->Buffer[0] == L'\\' &&
58 fileName->Buffer[1] == L'?' &&
59 fileName->Buffer[2] == L'?' &&
60 fileName->Buffer[3] == L'\\'
61 ){
62 PathLen = 0;
63 }
64 else{
65 PathPrefix = L"\\??\\";
66 PathLen = 8;
67 }
68
69 // Insert the correct path prefix.
70 FullFileNameLength = PathLen + fileName->MaximumLength;
71
72 #define NPF_TAG_FILENAME TAG('0', 'D', 'W', 'A')
73 FullFileName.Buffer = ExAllocatePoolWithTag(NonPagedPool,
74 FullFileNameLength,
75 NPF_TAG_FILENAME);
76
77 if (FullFileName.Buffer == NULL) {
78 ntStatus = STATUS_INSUFFICIENT_RESOURCES;
79 return ntStatus;
80 }
81
82 FullFileName.Length = PathLen;
83 FullFileName.MaximumLength = (USHORT)FullFileNameLength;
84
85 if(PathLen)
86 RtlMoveMemory (FullFileName.Buffer, PathPrefix, PathLen);
87
88 RtlAppendUnicodeStringToString (&FullFileName, fileName);
89
90 IF_LOUD(DbgPrint( "Packet: Attempting to open %wZ\n", &FullFileName);)
91
92 InitializeObjectAttributes ( &ObjectAttributes,
93 &FullFileName,
94 OBJ_CASE_INSENSITIVE,
95 NULL,
96 NULL );
97
98 // Create the dump file
99 ntStatus = ZwCreateFile( &Open->DumpFileHandle,
100 SYNCHRONIZE | FILE_WRITE_DATA,
101 &ObjectAttributes,
102 &IoStatus,
103 NULL,
104 FILE_ATTRIBUTE_NORMAL,
105 FILE_SHARE_READ,
106 (Append)?FILE_OPEN_IF:FILE_SUPERSEDE,
107 FILE_SYNCHRONOUS_IO_NONALERT,
108 NULL,
109 0 );
110
111 if ( !NT_SUCCESS( ntStatus ) )
112 {
113 IF_LOUD(DbgPrint("NPF: Error opening file %x\n", ntStatus);)
114
115 ExFreePool(FullFileName.Buffer);
116 Open->DumpFileHandle=NULL;
117 ntStatus = STATUS_NO_SUCH_FILE;
118 return ntStatus;
119 }
120
121 ExFreePool(FullFileName.Buffer);
122
123 ntStatus = ObReferenceObjectByHandle(Open->DumpFileHandle,
124 FILE_WRITE_ACCESS,
125 #ifndef __GNUC__
126 *IoFileObjectType,
127 #else
128 IoFileObjectType,
129 #endif
130 KernelMode,
131 (PVOID)&Open->DumpFileObject,
132 0);
133
134 if ( !NT_SUCCESS( ntStatus ) )
135 {
136 IF_LOUD(DbgPrint("NPF: Error creating file, status=%x\n", ntStatus);)
137
138 ZwClose( Open->DumpFileHandle );
139 Open->DumpFileHandle=NULL;
140
141 ntStatus = STATUS_NO_SUCH_FILE;
142 return ntStatus;
143 }
144
145 fsdDevice = IoGetRelatedDeviceObject(Open->DumpFileObject);
146
147 IF_LOUD(DbgPrint("NPF: Dump: write file created succesfully, status=%d \n",ntStatus);)
148
149 return ntStatus;
150 }
151
152 //-------------------------------------------------------------------
153
154 NTSTATUS
155 NPF_StartDump(POPEN_INSTANCE Open)
156 {
157 NTSTATUS ntStatus;
158 struct packet_file_header hdr;
159 IO_STATUS_BLOCK IoStatus;
160
161 IF_LOUD(DbgPrint("NPF: StartDump.\n");)
162
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;
170
171 // Detect the medium type
172 switch (Open->Medium){
173
174 case NdisMediumWan:
175 hdr.linktype = DLT_EN10MB;
176 break;
177
178 case NdisMedium802_3:
179 hdr.linktype = DLT_EN10MB;
180 break;
181
182 case NdisMediumFddi:
183 hdr.linktype = DLT_FDDI;
184 break;
185
186 case NdisMedium802_5:
187 hdr.linktype = DLT_IEEE802;
188 break;
189
190 case NdisMediumArcnet878_2:
191 hdr.linktype = DLT_ARCNET;
192 break;
193
194 case NdisMediumAtm:
195 hdr.linktype = DLT_ATM_RFC1483;
196 break;
197
198 default:
199 hdr.linktype = DLT_EN10MB;
200 }
201
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 );
213
214
215 if ( !NT_SUCCESS( ntStatus ) )
216 {
217 IF_LOUD(DbgPrint("NPF: Error dumping file %x\n", ntStatus);)
218
219 ZwClose( Open->DumpFileHandle );
220 Open->DumpFileHandle=NULL;
221
222 ntStatus = STATUS_NO_SUCH_FILE;
223 return ntStatus;
224 }
225
226 Open->DumpOffset.QuadPart=24;
227
228 ntStatus = PsCreateSystemThread(&Open->DumpThreadHandle,
229 THREAD_ALL_ACCESS,
230 (ACCESS_MASK)0L,
231 0,
232 0,
233 (PKSTART_ROUTINE)NPF_DumpThread,
234 Open);
235
236 if ( !NT_SUCCESS( ntStatus ) )
237 {
238 IF_LOUD(DbgPrint("NPF: Error creating dump thread, status=%x\n", ntStatus);)
239
240 ZwClose( Open->DumpFileHandle );
241 Open->DumpFileHandle=NULL;
242
243 return ntStatus;
244 }
245 ntStatus = ObReferenceObjectByHandle(Open->DumpThreadHandle,
246 THREAD_ALL_ACCESS,
247 NULL,
248 KernelMode,
249 (PVOID*)&Open->DumpThreadObject,
250 0);
251 if ( !NT_SUCCESS( ntStatus ) )
252 {
253 IF_LOUD(DbgPrint("NPF: Error creating dump thread, status=%x\n", ntStatus);)
254
255 ObDereferenceObject(Open->DumpFileObject);
256 ZwClose( Open->DumpFileHandle );
257 Open->DumpFileHandle=NULL;
258
259 return ntStatus;
260 }
261
262 return ntStatus;
263
264 }
265
266 //-------------------------------------------------------------------
267 // Dump Thread
268 //-------------------------------------------------------------------
269
270 VOID NPF_DumpThread(POPEN_INSTANCE Open)
271 {
272
273 IF_LOUD(DbgPrint("NPF: In the work routine. Parameter = 0x%0x\n",Open);)
274
275 while(TRUE){
276
277 // Wait until some packets arrive or the timeout expires
278 NdisWaitEvent(&Open->DumpEvent, 5000);
279
280 IF_LOUD(DbgPrint("NPF: Worker Thread - event signalled\n");)
281
282 if(Open->DumpLimitReached ||
283 Open->BufSize==0){ // BufSize=0 means that this instance was closed, or that the buffer is too
284 // small for any capture. In both cases it is better to end the dump
285
286 IF_LOUD(DbgPrint("NPF: Worker Thread - Exiting happily\n");)
287 IF_LOUD(DbgPrint("Thread: Dumpoffset=%I64d\n",Open->DumpOffset.QuadPart);)
288
289 PsTerminateSystemThread(STATUS_SUCCESS);
290 return;
291 }
292
293 NdisResetEvent(&Open->DumpEvent);
294
295 // Write the content of the buffer to the file
296 if(NPF_SaveCurrentBuffer(Open) != STATUS_SUCCESS){
297 PsTerminateSystemThread(STATUS_SUCCESS);
298 return;
299 }
300
301 }
302
303 }
304
305 //-------------------------------------------------------------------
306
307 NTSTATUS NPF_SaveCurrentBuffer(POPEN_INSTANCE Open)
308 {
309 UINT Thead;
310 UINT Ttail;
311 UINT TLastByte;
312 PUCHAR CurrBuff;
313 IO_STATUS_BLOCK IoStatus;
314 PMDL lMdl;
315 UINT SizeToDump;
316
317
318 Thead=Open->Bhead;
319 Ttail=Open->Btail;
320 TLastByte=Open->BLastByte;
321
322 IF_LOUD(DbgPrint("NPF: NPF_SaveCurrentBuffer.\n");)
323
324 // Get the address of the buffer
325 CurrBuff=Open->Buffer;
326 //
327 // Fill the application buffer
328 //
329 if( Ttail < Thead )
330 {
331 if(Open->MaxDumpBytes &&
332 (UINT)Open->DumpOffset.QuadPart + GetBuffOccupation(Open) > Open->MaxDumpBytes)
333 {
334 // Size limit reached
335 UINT PktLen;
336
337 SizeToDump = 0;
338
339 // Scan the buffer to detect the exact amount of data to save
340 while(TRUE){
341 PktLen = ((struct sf_pkthdr*)(CurrBuff + Thead + SizeToDump))->caplen + sizeof(struct sf_pkthdr);
342
343 if((UINT)Open->DumpOffset.QuadPart + SizeToDump + PktLen > Open->MaxDumpBytes)
344 break;
345
346 SizeToDump += PktLen;
347 }
348
349 }
350 else
351 SizeToDump = TLastByte-Thead;
352
353 lMdl=IoAllocateMdl(CurrBuff+Thead, SizeToDump, FALSE, FALSE, NULL);
354 if (lMdl == NULL)
355 {
356 // No memory: stop dump
357 IF_LOUD(DbgPrint("NPF: dump thread: Failed to allocate Mdl\n");)
358 return STATUS_UNSUCCESSFUL;
359 }
360
361 MmBuildMdlForNonPagedPool(lMdl);
362
363 // Write to disk
364 NPF_WriteDumpFile(Open->DumpFileObject,
365 &Open->DumpOffset,
366 SizeToDump,
367 lMdl,
368 &IoStatus);
369
370 IoFreeMdl(lMdl);
371
372 if(!NT_SUCCESS(IoStatus.Status)){
373 // Error
374 return STATUS_UNSUCCESSFUL;
375 }
376
377 if(SizeToDump != TLastByte-Thead){
378 // Size limit reached.
379 Open->DumpLimitReached = TRUE;
380
381 // Awake the application
382 KeSetEvent(Open->ReadEvent,0,FALSE);
383
384 return STATUS_UNSUCCESSFUL;
385 }
386
387 // Update the packet buffer
388 Open->DumpOffset.QuadPart+=(TLastByte-Thead);
389 Open->BLastByte=Ttail;
390 Open->Bhead=0;
391 }
392
393 if( Ttail > Thead ){
394
395 if(Open->MaxDumpBytes &&
396 (UINT)Open->DumpOffset.QuadPart + GetBuffOccupation(Open) > Open->MaxDumpBytes)
397 {
398 // Size limit reached
399 UINT PktLen;
400
401 SizeToDump = 0;
402
403 // Scan the buffer to detect the exact amount of data to save
404 while(Thead + SizeToDump < Ttail){
405
406 PktLen = ((struct sf_pkthdr*)(CurrBuff + Thead + SizeToDump))->caplen + sizeof(struct sf_pkthdr);
407
408 if((UINT)Open->DumpOffset.QuadPart + SizeToDump + PktLen > Open->MaxDumpBytes)
409 break;
410
411 SizeToDump += PktLen;
412 }
413
414 }
415 else
416 SizeToDump = Ttail-Thead;
417
418 lMdl=IoAllocateMdl(CurrBuff+Thead, SizeToDump, FALSE, FALSE, NULL);
419 if (lMdl == NULL)
420 {
421 // No memory: stop dump
422 IF_LOUD(DbgPrint("NPF: dump thread: Failed to allocate Mdl\n");)
423 return STATUS_UNSUCCESSFUL;
424 }
425
426 MmBuildMdlForNonPagedPool(lMdl);
427
428 // Write to disk
429 NPF_WriteDumpFile(Open->DumpFileObject,
430 &Open->DumpOffset,
431 SizeToDump,
432 lMdl,
433 &IoStatus);
434
435 IoFreeMdl(lMdl);
436
437 if(!NT_SUCCESS(IoStatus.Status)){
438 // Error
439 return STATUS_UNSUCCESSFUL;
440 }
441
442 if(SizeToDump != Ttail-Thead){
443 // Size limit reached.
444 Open->DumpLimitReached = TRUE;
445
446 // Awake the application
447 KeSetEvent(Open->ReadEvent,0,FALSE);
448
449 return STATUS_UNSUCCESSFUL;
450 }
451
452 // Update the packet buffer
453 Open->DumpOffset.QuadPart+=(Ttail-Thead);
454 Open->Bhead=Ttail;
455
456 }
457
458 return STATUS_SUCCESS;
459 }
460
461 //-------------------------------------------------------------------
462
463 NTSTATUS NPF_CloseDumpFile(POPEN_INSTANCE Open){
464
465 IF_LOUD(DbgPrint("NPF: NPF_CloseDumpFile.\n");)
466 IF_LOUD(DbgPrint("Dumpoffset=%d\n",Open->DumpOffset.QuadPart);)
467
468 DbgPrint("1\n");
469 // Consistency check
470 if(Open->DumpFileHandle == NULL)
471 return STATUS_UNSUCCESSFUL;
472
473 DbgPrint("2\n");
474 ZwClose( Open->DumpFileHandle );
475
476 ObDereferenceObject(Open->DumpFileObject);
477 /*
478 if(Open->DumpLimitReached == TRUE)
479 // Limit already reached: don't save the rest of the buffer.
480 return STATUS_SUCCESS;
481 */
482 DbgPrint("3\n");
483
484 NPF_OpenDumpFile(Open,&Open->DumpFileName, TRUE);
485
486 // Flush the buffer to file
487 NPF_SaveCurrentBuffer(Open);
488
489 // Close The file
490 ObDereferenceObject(Open->DumpFileObject);
491 ZwClose( Open->DumpFileHandle );
492
493 Open->DumpFileHandle = NULL;
494
495 ObDereferenceObject(Open->DumpFileObject);
496
497 return STATUS_SUCCESS;
498 }
499
500 //-------------------------------------------------------------------
501
502 #ifndef __GNUC__
503 static NTSTATUS
504 #else
505 NTSTATUS STDCALL
506 #endif
507 PacketDumpCompletion(PDEVICE_OBJECT DeviceObject,
508 PIRP Irp,
509 PVOID Context)
510 {
511
512 // Copy the status information back into the "user" IOSB
513 *Irp->UserIosb = Irp->IoStatus;
514
515 // Wake up the mainline code
516 KeSetEvent(Irp->UserEvent, 0, FALSE);
517
518 return STATUS_MORE_PROCESSING_REQUIRED;
519 }
520
521 //-------------------------------------------------------------------
522
523 VOID NPF_WriteDumpFile(PFILE_OBJECT FileObject,
524 PLARGE_INTEGER Offset,
525 ULONG Length,
526 PMDL Mdl,
527 PIO_STATUS_BLOCK IoStatusBlock)
528 {
529 PIRP irp;
530 KEVENT event;
531 PIO_STACK_LOCATION ioStackLocation;
532 PDEVICE_OBJECT fsdDevice = IoGetRelatedDeviceObject(FileObject);
533
534 // Set up the event we'll use
535 KeInitializeEvent(&event, SynchronizationEvent, FALSE);
536
537 // Allocate and build the IRP we'll be sending to the FSD
538 irp = IoAllocateIrp(fsdDevice->StackSize, FALSE);
539
540 if (!irp) {
541 // Allocation failed, presumably due to memory allocation failure
542 IoStatusBlock->Status = STATUS_INSUFFICIENT_RESOURCES;
543 IoStatusBlock->Information = 0;
544
545 return;
546 }
547
548 irp->MdlAddress = Mdl;
549 irp->UserEvent = &event;
550 irp->UserIosb = IoStatusBlock;
551 irp->Tail.Overlay.Thread = PsGetCurrentThread();
552 irp->Tail.Overlay.OriginalFileObject= FileObject;
553 irp->RequestorMode = KernelMode;
554
555 // Indicate that this is a WRITE operation
556 irp->Flags = IRP_WRITE_OPERATION;
557
558 // Set up the next I/O stack location
559 ioStackLocation = IoGetNextIrpStackLocation(irp);
560 ioStackLocation->MajorFunction = IRP_MJ_WRITE;
561 ioStackLocation->MinorFunction = 0;
562 ioStackLocation->DeviceObject = fsdDevice;
563 ioStackLocation->FileObject = FileObject;
564 IoSetCompletionRoutine(irp, PacketDumpCompletion, 0, TRUE, TRUE, TRUE);
565 ioStackLocation->Parameters.Write.Length = Length;
566 ioStackLocation->Parameters.Write.ByteOffset = *Offset;
567
568
569 // Send it on. Ignore the return code
570 (void) IoCallDriver(fsdDevice, irp);
571
572 // Wait for the I/O to complete.
573 KeWaitForSingleObject(&event, Executive, KernelMode, TRUE, 0);
574
575 // Free the IRP now that we are done with it
576 IoFreeIrp(irp);
577
578 return;
579 }