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