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