00001 /* 00002 * Copyright (c) 1999, 2000 00003 * Politecnico di Torino. All rights reserved. 00004 * 00005 * Redistribution and use in source and binary forms, with or without 00006 * modification, are permitted provided that: (1) source code distributions 00007 * retain the above copyright notice and this paragraph in its entirety, (2) 00008 * distributions including binary code include the above copyright notice and 00009 * this paragraph in its entirety in the documentation or other materials 00010 * provided with the distribution, and (3) all advertising materials mentioning 00011 * features or use of this software display the following acknowledgement: 00012 * ``This product includes software developed by the Politecnico 00013 * di Torino, and its contributors.'' Neither the name of 00014 * the University nor the names of its contributors may be used to endorse 00015 * or promote products derived from this software without specific prior 00016 * written permission. 00017 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 00018 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 00019 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 00020 */ 00021 00022 #include <stdarg.h> 00023 #include <ntddk.h> 00024 #include <ntiologc.h> 00025 #include <ndis.h> 00026 #include "debug.h" 00027 #include "packet.h" 00028 00029 #include "win_bpf.h" 00030 00031 //------------------------------------------------------------------- 00032 00033 NTSTATUS 00034 NPF_OpenDumpFile(POPEN_INSTANCE Open , PUNICODE_STRING fileName, BOOLEAN Append) 00035 { 00036 NTSTATUS ntStatus; 00037 IO_STATUS_BLOCK IoStatus; 00038 OBJECT_ATTRIBUTES ObjectAttributes; 00039 PWCHAR PathPrefix; 00040 USHORT PathLen; 00041 UNICODE_STRING FullFileName; 00042 ULONG FullFileNameLength; 00043 PDEVICE_OBJECT fsdDevice; 00044 00045 FILE_STANDARD_INFORMATION StandardInfo; 00046 00047 IF_LOUD(DbgPrint("NPF: OpenDumpFile.\n");) 00048 00049 if(fileName->Buffer[0] == L'\\' && 00050 fileName->Buffer[1] == L'?' && 00051 fileName->Buffer[2] == L'?' && 00052 fileName->Buffer[3] == L'\\' 00053 ){ 00054 PathLen = 0; 00055 } 00056 else{ 00057 PathPrefix = L"\\??\\"; 00058 PathLen = 8; 00059 } 00060 00061 // Insert the correct path prefix. 00062 FullFileNameLength = PathLen + fileName->MaximumLength; 00063 00064 FullFileName.Buffer = ExAllocatePoolWithTag(NonPagedPool, 00065 FullFileNameLength, 00066 '0DWA'); 00067 00068 if (FullFileName.Buffer == NULL) { 00069 ntStatus = STATUS_INSUFFICIENT_RESOURCES; 00070 return ntStatus; 00071 } 00072 00073 FullFileName.Length = PathLen; 00074 FullFileName.MaximumLength = (USHORT)FullFileNameLength; 00075 00076 if(PathLen) 00077 RtlMoveMemory (FullFileName.Buffer, PathPrefix, PathLen); 00078 00079 RtlAppendUnicodeStringToString (&FullFileName, fileName); 00080 00081 IF_LOUD(DbgPrint( "Packet: Attempting to open %wZ\n", &FullFileName);) 00082 00083 InitializeObjectAttributes ( &ObjectAttributes, 00084 &FullFileName, 00085 OBJ_CASE_INSENSITIVE, 00086 NULL, 00087 NULL ); 00088 00089 // Create the dump file 00090 ntStatus = ZwCreateFile( &Open->DumpFileHandle, 00091 SYNCHRONIZE | FILE_WRITE_DATA, 00092 &ObjectAttributes, 00093 &IoStatus, 00094 NULL, 00095 FILE_ATTRIBUTE_NORMAL, 00096 FILE_SHARE_READ, 00097 (Append)?FILE_OPEN_IF:FILE_SUPERSEDE, 00098 FILE_SYNCHRONOUS_IO_NONALERT, 00099 NULL, 00100 0 ); 00101 00102 if ( !NT_SUCCESS( ntStatus ) ) 00103 { 00104 IF_LOUD(DbgPrint("NPF: Error opening file %x\n", ntStatus);) 00105 00106 ExFreePool(FullFileName.Buffer); 00107 Open->DumpFileHandle=NULL; 00108 ntStatus = STATUS_NO_SUCH_FILE; 00109 return ntStatus; 00110 } 00111 00112 ExFreePool(FullFileName.Buffer); 00113 00114 ntStatus = ObReferenceObjectByHandle(Open->DumpFileHandle, 00115 FILE_WRITE_ACCESS, 00116 *IoFileObjectType, 00117 KernelMode, 00118 &Open->DumpFileObject, 00119 0); 00120 00121 if ( !NT_SUCCESS( ntStatus ) ) 00122 { 00123 IF_LOUD(DbgPrint("NPF: Error creating file, status=%x\n", ntStatus);) 00124 00125 ZwClose( Open->DumpFileHandle ); 00126 Open->DumpFileHandle=NULL; 00127 00128 ntStatus = STATUS_NO_SUCH_FILE; 00129 return ntStatus; 00130 } 00131 00132 fsdDevice = IoGetRelatedDeviceObject(Open->DumpFileObject); 00133 00134 IF_LOUD(DbgPrint("NPF: Dump: write file created succesfully, status=%d \n",ntStatus);) 00135 00136 return ntStatus; 00137 } 00138 00139 //------------------------------------------------------------------- 00140 00141 NTSTATUS 00142 NPF_StartDump(POPEN_INSTANCE Open) 00143 { 00144 NTSTATUS ntStatus; 00145 struct packet_file_header hdr; 00146 IO_STATUS_BLOCK IoStatus; 00147 NDIS_REQUEST pRequest; 00148 ULONG MediaType; 00149 OBJECT_ATTRIBUTES ObjectAttributes; 00150 00151 IF_LOUD(DbgPrint("NPF: StartDump.\n");) 00152 00153 // Init the file header 00154 hdr.magic = TCPDUMP_MAGIC; 00155 hdr.version_major = PCAP_VERSION_MAJOR; 00156 hdr.version_minor = PCAP_VERSION_MINOR; 00157 hdr.thiszone = 0; /*Currently not set*/ 00158 hdr.snaplen = 1514; 00159 hdr.sigfigs = 0; 00160 00161 // Detect the medium type 00162 switch (Open->Medium){ 00163 00164 case NdisMediumWan: 00165 hdr.linktype = DLT_EN10MB; 00166 break; 00167 00168 case NdisMedium802_3: 00169 hdr.linktype = DLT_EN10MB; 00170 break; 00171 00172 case NdisMediumFddi: 00173 hdr.linktype = DLT_FDDI; 00174 break; 00175 00176 case NdisMedium802_5: 00177 hdr.linktype = DLT_IEEE802; 00178 break; 00179 00180 case NdisMediumArcnet878_2: 00181 hdr.linktype = DLT_ARCNET; 00182 break; 00183 00184 case NdisMediumAtm: 00185 hdr.linktype = DLT_ATM_RFC1483; 00186 break; 00187 00188 default: 00189 hdr.linktype = DLT_EN10MB; 00190 } 00191 00192 // Write the header. 00193 // We can use ZwWriteFile because we are in the context of the application 00194 ntStatus = ZwWriteFile(Open->DumpFileHandle, 00195 NULL, 00196 NULL, 00197 NULL, 00198 &IoStatus, 00199 &hdr, 00200 sizeof(hdr), 00201 NULL, 00202 NULL ); 00203 00204 00205 if ( !NT_SUCCESS( ntStatus ) ) 00206 { 00207 IF_LOUD(DbgPrint("NPF: Error dumping file %x\n", ntStatus);) 00208 00209 ZwClose( Open->DumpFileHandle ); 00210 Open->DumpFileHandle=NULL; 00211 00212 ntStatus = STATUS_NO_SUCH_FILE; 00213 return ntStatus; 00214 } 00215 00216 Open->DumpOffset.QuadPart=24; 00217 00218 ntStatus = PsCreateSystemThread(&Open->DumpThreadHandle, 00219 THREAD_ALL_ACCESS, 00220 (ACCESS_MASK)0L, 00221 0, 00222 0, 00223 NPF_DumpThread, 00224 Open); 00225 00226 if ( !NT_SUCCESS( ntStatus ) ) 00227 { 00228 IF_LOUD(DbgPrint("NPF: Error creating dump thread, status=%x\n", ntStatus);) 00229 00230 ZwClose( Open->DumpFileHandle ); 00231 Open->DumpFileHandle=NULL; 00232 00233 return ntStatus; 00234 } 00235 00236 ntStatus = ObReferenceObjectByHandle(Open->DumpThreadHandle, 00237 THREAD_ALL_ACCESS, 00238 NULL, 00239 KernelMode, 00240 &Open->DumpThreadObject, 00241 0); 00242 00243 if ( !NT_SUCCESS( ntStatus ) ) 00244 { 00245 IF_LOUD(DbgPrint("NPF: Error creating dump thread, status=%x\n", ntStatus);) 00246 00247 ObDereferenceObject(Open->DumpFileObject); 00248 ZwClose( Open->DumpFileHandle ); 00249 Open->DumpFileHandle=NULL; 00250 00251 return ntStatus; 00252 } 00253 00254 00255 return ntStatus; 00256 00257 } 00258 00259 //------------------------------------------------------------------- 00260 // Dump Thread 00261 //------------------------------------------------------------------- 00262 00263 VOID NPF_DumpThread(POPEN_INSTANCE Open) 00264 { 00265 ULONG FrozenNic; 00266 00267 IF_LOUD(DbgPrint("NPF: In the work routine. Parameter = 0x%0x\n",Open);) 00268 00269 while(TRUE){ 00270 00271 // Wait until some packets arrive or the timeout expires 00272 NdisWaitEvent(&Open->DumpEvent, 5000); 00273 00274 IF_LOUD(DbgPrint("NPF: Worker Thread - event signalled\n");) 00275 00276 if(Open->DumpLimitReached || 00277 Open->Size==0){ // BufSize=0 means that this instance was closed, or that the buffer is too 00278 // small for any capture. In both cases it is better to end the dump 00279 00280 IF_LOUD(DbgPrint("NPF: Worker Thread - Exiting happily\n");) 00281 IF_LOUD(DbgPrint("Thread: Dumpoffset=%I64d\n",Open->DumpOffset.QuadPart);) 00282 00283 PsTerminateSystemThread(STATUS_SUCCESS); 00284 return; 00285 } 00286 00287 NdisResetEvent(&Open->DumpEvent); 00288 00289 // Write the content of the buffer to the file 00290 if(NPF_SaveCurrentBuffer(Open) != STATUS_SUCCESS){ 00291 PsTerminateSystemThread(STATUS_SUCCESS); 00292 return; 00293 } 00294 00295 } 00296 00297 } 00298 00299 //------------------------------------------------------------------- 00300 00301 NTSTATUS NPF_SaveCurrentBuffer(POPEN_INSTANCE Open) 00302 { 00303 UINT Thead; 00304 UINT Ttail; 00305 UINT TLastByte; 00306 PUCHAR CurrBuff; 00307 NTSTATUS ntStatus; 00308 IO_STATUS_BLOCK IoStatus; 00309 PMDL lMdl; 00310 UINT SizeToDump; 00311 00312 #if 0 00313 00314 Thead=Open->Bhead; 00315 Ttail=Open->Btail; 00316 TLastByte=Open->BLastByte; 00317 00318 IF_LOUD(DbgPrint("NPF: NPF_SaveCurrentBuffer.\n");) 00319 00320 // Get the address of the buffer 00321 CurrBuff=Open->Buffer; 00322 // 00323 // Fill the application buffer 00324 // 00325 if( Ttail < Thead ) 00326 { 00327 if(Open->MaxDumpBytes && 00328 (UINT)Open->DumpOffset.QuadPart /*+ GetBuffOccupation(Open)*/ > Open->MaxDumpBytes) 00329 { 00330 // Size limit reached 00331 UINT PktLen; 00332 00333 SizeToDump = 0; 00334 00335 // Scan the buffer to detect the exact amount of data to save 00336 while(TRUE){ 00337 PktLen = ((struct sf_pkthdr*)(CurrBuff + Thead + SizeToDump))->caplen + sizeof(struct sf_pkthdr); 00338 00339 if((UINT)Open->DumpOffset.QuadPart + SizeToDump + PktLen > Open->MaxDumpBytes) 00340 break; 00341 00342 SizeToDump += PktLen; 00343 } 00344 00345 } 00346 else 00347 SizeToDump = TLastByte-Thead; 00348 00349 lMdl=IoAllocateMdl(CurrBuff+Thead, SizeToDump, FALSE, FALSE, NULL); 00350 if (lMdl == NULL) 00351 { 00352 // No memory: stop dump 00353 IF_LOUD(DbgPrint("NPF: dump thread: Failed to allocate Mdl\n");) 00354 return STATUS_UNSUCCESSFUL; 00355 } 00356 00357 MmBuildMdlForNonPagedPool(lMdl); 00358 00359 // Write to disk 00360 NPF_WriteDumpFile(Open->DumpFileObject, 00361 &Open->DumpOffset, 00362 SizeToDump, 00363 lMdl, 00364 &IoStatus); 00365 00366 IoFreeMdl(lMdl); 00367 00368 if(!NT_SUCCESS(IoStatus.Status)){ 00369 // Error 00370 return STATUS_UNSUCCESSFUL; 00371 } 00372 00373 if(SizeToDump != TLastByte-Thead){ 00374 // Size limit reached. 00375 Open->DumpLimitReached = TRUE; 00376 00377 // Awake the application 00378 KeSetEvent(Open->ReadEvent,0,FALSE); 00379 00380 return STATUS_UNSUCCESSFUL; 00381 } 00382 00383 // Update the packet buffer 00384 Open->DumpOffset.QuadPart+=(TLastByte-Thead); 00385 Open->BLastByte=Ttail; 00386 Open->Bhead=0; 00387 } 00388 00389 if( Ttail > Thead ){ 00390 00391 if(Open->MaxDumpBytes && 00392 (UINT)Open->DumpOffset.QuadPart /* +GetBuffOccupation(Open)*/ > Open->MaxDumpBytes) 00393 { 00394 // Size limit reached 00395 UINT PktLen; 00396 00397 SizeToDump = 0; 00398 00399 // Scan the buffer to detect the exact amount of data to save 00400 while(Thead + SizeToDump < Ttail){ 00401 00402 PktLen = ((struct sf_pkthdr*)(CurrBuff + Thead + SizeToDump))->caplen + sizeof(struct sf_pkthdr); 00403 00404 if((UINT)Open->DumpOffset.QuadPart + SizeToDump + PktLen > Open->MaxDumpBytes) 00405 break; 00406 00407 SizeToDump += PktLen; 00408 } 00409 00410 } 00411 else 00412 SizeToDump = Ttail-Thead; 00413 00414 lMdl=IoAllocateMdl(CurrBuff+Thead, SizeToDump, FALSE, FALSE, NULL); 00415 if (lMdl == NULL) 00416 { 00417 // No memory: stop dump 00418 IF_LOUD(DbgPrint("NPF: dump thread: Failed to allocate Mdl\n");) 00419 return STATUS_UNSUCCESSFUL; 00420 } 00421 00422 MmBuildMdlForNonPagedPool(lMdl); 00423 00424 // Write to disk 00425 NPF_WriteDumpFile(Open->DumpFileObject, 00426 &Open->DumpOffset, 00427 SizeToDump, 00428 lMdl, 00429 &IoStatus); 00430 00431 IoFreeMdl(lMdl); 00432 00433 if(!NT_SUCCESS(IoStatus.Status)){ 00434 // Error 00435 return STATUS_UNSUCCESSFUL; 00436 } 00437 00438 if(SizeToDump != Ttail-Thead){ 00439 // Size limit reached. 00440 Open->DumpLimitReached = TRUE; 00441 00442 // Awake the application 00443 KeSetEvent(Open->ReadEvent,0,FALSE); 00444 00445 return STATUS_UNSUCCESSFUL; 00446 } 00447 00448 // Update the packet buffer 00449 Open->DumpOffset.QuadPart+=(Ttail-Thead); 00450 Open->Bhead=Ttail; 00451 00452 } 00453 #endif 00454 return STATUS_SUCCESS; 00455 } 00456 00457 //------------------------------------------------------------------- 00458 00459 NTSTATUS NPF_CloseDumpFile(POPEN_INSTANCE Open){ 00460 NTSTATUS ntStatus; 00461 IO_STATUS_BLOCK IoStatus; 00462 PMDL WriteMdl; 00463 PUCHAR VMBuff; 00464 UINT VMBufLen; 00465 00466 #if 0 00467 IF_LOUD(DbgPrint("NPF: NPF_CloseDumpFile.\n");) 00468 IF_LOUD(DbgPrint("Dumpoffset=%d\n",Open->DumpOffset.QuadPart);) 00469 00470 DbgPrint("1\n"); 00471 // Consistency check 00472 if(Open->DumpFileHandle == NULL) 00473 return STATUS_UNSUCCESSFUL; 00474 00475 DbgPrint("2\n"); 00476 ZwClose( Open->DumpFileHandle ); 00477 00478 ObDereferenceObject(Open->DumpFileObject); 00479 /* 00480 if(Open->DumpLimitReached == TRUE) 00481 // Limit already reached: don't save the rest of the buffer. 00482 return STATUS_SUCCESS; 00483 */ 00484 DbgPrint("3\n"); 00485 00486 NPF_OpenDumpFile(Open,&Open->DumpFileName, TRUE); 00487 00488 // Flush the buffer to file 00489 NPF_SaveCurrentBuffer(Open); 00490 00491 // Close The file 00492 ObDereferenceObject(Open->DumpFileObject); 00493 ZwClose( Open->DumpFileHandle ); 00494 00495 Open->DumpFileHandle = NULL; 00496 00497 ObDereferenceObject(Open->DumpFileObject); 00498 #endif 00499 return STATUS_SUCCESS; 00500 } 00501 00502 //------------------------------------------------------------------- 00503 00504 static NTSTATUS PacketDumpCompletion(PDEVICE_OBJECT DeviceObject, 00505 PIRP Irp, 00506 PVOID Context) 00507 { 00508 00509 // Copy the status information back into the "user" IOSB 00510 *Irp->UserIosb = Irp->IoStatus; 00511 00512 // Wake up the mainline code 00513 KeSetEvent(Irp->UserEvent, 0, FALSE); 00514 00515 return STATUS_MORE_PROCESSING_REQUIRED; 00516 } 00517 00518 //------------------------------------------------------------------- 00519 00520 VOID NPF_WriteDumpFile(PFILE_OBJECT FileObject, 00521 PLARGE_INTEGER Offset, 00522 ULONG Length, 00523 PMDL Mdl, 00524 PIO_STATUS_BLOCK IoStatusBlock) 00525 { 00526 PIRP irp; 00527 KEVENT event; 00528 PIO_STACK_LOCATION ioStackLocation; 00529 PDEVICE_OBJECT fsdDevice = IoGetRelatedDeviceObject(FileObject); 00530 NTSTATUS Status; 00531 00532 // Set up the event we'll use 00533 KeInitializeEvent(&event, SynchronizationEvent, FALSE); 00534 00535 // Allocate and build the IRP we'll be sending to the FSD 00536 irp = IoAllocateIrp(fsdDevice->StackSize, FALSE); 00537 00538 if (!irp) { 00539 // Allocation failed, presumably due to memory allocation failure 00540 IoStatusBlock->Status = STATUS_INSUFFICIENT_RESOURCES; 00541 IoStatusBlock->Information = 0; 00542 00543 return; 00544 } 00545 00546 irp->MdlAddress = Mdl; 00547 irp->UserEvent = &event; 00548 irp->UserIosb = IoStatusBlock; 00549 irp->Tail.Overlay.Thread = PsGetCurrentThread(); 00550 irp->Tail.Overlay.OriginalFileObject= FileObject; 00551 irp->RequestorMode = KernelMode; 00552 00553 // Indicate that this is a WRITE operation 00554 irp->Flags = IRP_WRITE_OPERATION; 00555 00556 // Set up the next I/O stack location 00557 ioStackLocation = IoGetNextIrpStackLocation(irp); 00558 ioStackLocation->MajorFunction = IRP_MJ_WRITE; 00559 ioStackLocation->MinorFunction = 0; 00560 ioStackLocation->DeviceObject = fsdDevice; 00561 ioStackLocation->FileObject = FileObject; 00562 IoSetCompletionRoutine(irp, PacketDumpCompletion, 0, TRUE, TRUE, TRUE); 00563 ioStackLocation->Parameters.Write.Length = Length; 00564 ioStackLocation->Parameters.Write.ByteOffset = *Offset; 00565 00566 00567 // Send it on. Ignore the return code 00568 (void) IoCallDriver(fsdDevice, irp); 00569 00570 // Wait for the I/O to complete. 00571 KeWaitForSingleObject(&event, Executive, KernelMode, TRUE, 0); 00572 00573 // Free the IRP now that we are done with it 00574 IoFreeIrp(irp); 00575 00576 return; 00577 00578 }
documentation. Copyright (c) 2002-2003 Politecnico di Torino. All rights reserved.