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->BufSize==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 00313 Thead=Open->Bhead; 00314 Ttail=Open->Btail; 00315 TLastByte=Open->BLastByte; 00316 00317 IF_LOUD(DbgPrint("NPF: NPF_SaveCurrentBuffer.\n");) 00318 00319 // Get the address of the buffer 00320 CurrBuff=Open->Buffer; 00321 // 00322 // Fill the application buffer 00323 // 00324 if( Ttail < Thead ) 00325 { 00326 if(Open->MaxDumpBytes && 00327 (UINT)Open->DumpOffset.QuadPart + GetBuffOccupation(Open) > Open->MaxDumpBytes) 00328 { 00329 // Size limit reached 00330 UINT PktLen; 00331 00332 SizeToDump = 0; 00333 00334 // Scan the buffer to detect the exact amount of data to save 00335 while(TRUE){ 00336 PktLen = ((struct sf_pkthdr*)(CurrBuff + Thead + SizeToDump))->caplen + sizeof(struct sf_pkthdr); 00337 00338 if((UINT)Open->DumpOffset.QuadPart + SizeToDump + PktLen > Open->MaxDumpBytes) 00339 break; 00340 00341 SizeToDump += PktLen; 00342 } 00343 00344 } 00345 else 00346 SizeToDump = TLastByte-Thead; 00347 00348 lMdl=IoAllocateMdl(CurrBuff+Thead, SizeToDump, FALSE, FALSE, NULL); 00349 if (lMdl == NULL) 00350 { 00351 // No memory: stop dump 00352 IF_LOUD(DbgPrint("NPF: dump thread: Failed to allocate Mdl\n");) 00353 return STATUS_UNSUCCESSFUL; 00354 } 00355 00356 MmBuildMdlForNonPagedPool(lMdl); 00357 00358 // Write to disk 00359 NPF_WriteDumpFile(Open->DumpFileObject, 00360 &Open->DumpOffset, 00361 SizeToDump, 00362 lMdl, 00363 &IoStatus); 00364 00365 IoFreeMdl(lMdl); 00366 00367 if(!NT_SUCCESS(IoStatus.Status)){ 00368 // Error 00369 return STATUS_UNSUCCESSFUL; 00370 } 00371 00372 if(SizeToDump != TLastByte-Thead){ 00373 // Size limit reached. 00374 Open->DumpLimitReached = TRUE; 00375 00376 // Awake the application 00377 KeSetEvent(Open->ReadEvent,0,FALSE); 00378 00379 return STATUS_UNSUCCESSFUL; 00380 } 00381 00382 // Update the packet buffer 00383 Open->DumpOffset.QuadPart+=(TLastByte-Thead); 00384 Open->BLastByte=Ttail; 00385 Open->Bhead=0; 00386 } 00387 00388 if( Ttail > Thead ){ 00389 00390 if(Open->MaxDumpBytes && 00391 (UINT)Open->DumpOffset.QuadPart + GetBuffOccupation(Open) > Open->MaxDumpBytes) 00392 { 00393 // Size limit reached 00394 UINT PktLen; 00395 00396 SizeToDump = 0; 00397 00398 // Scan the buffer to detect the exact amount of data to save 00399 while(Thead + SizeToDump < Ttail){ 00400 00401 PktLen = ((struct sf_pkthdr*)(CurrBuff + Thead + SizeToDump))->caplen + sizeof(struct sf_pkthdr); 00402 00403 if((UINT)Open->DumpOffset.QuadPart + SizeToDump + PktLen > Open->MaxDumpBytes) 00404 break; 00405 00406 SizeToDump += PktLen; 00407 } 00408 00409 } 00410 else 00411 SizeToDump = Ttail-Thead; 00412 00413 lMdl=IoAllocateMdl(CurrBuff+Thead, SizeToDump, FALSE, FALSE, NULL); 00414 if (lMdl == NULL) 00415 { 00416 // No memory: stop dump 00417 IF_LOUD(DbgPrint("NPF: dump thread: Failed to allocate Mdl\n");) 00418 return STATUS_UNSUCCESSFUL; 00419 } 00420 00421 MmBuildMdlForNonPagedPool(lMdl); 00422 00423 // Write to disk 00424 NPF_WriteDumpFile(Open->DumpFileObject, 00425 &Open->DumpOffset, 00426 SizeToDump, 00427 lMdl, 00428 &IoStatus); 00429 00430 IoFreeMdl(lMdl); 00431 00432 if(!NT_SUCCESS(IoStatus.Status)){ 00433 // Error 00434 return STATUS_UNSUCCESSFUL; 00435 } 00436 00437 if(SizeToDump != Ttail-Thead){ 00438 // Size limit reached. 00439 Open->DumpLimitReached = TRUE; 00440 00441 // Awake the application 00442 KeSetEvent(Open->ReadEvent,0,FALSE); 00443 00444 return STATUS_UNSUCCESSFUL; 00445 } 00446 00447 // Update the packet buffer 00448 Open->DumpOffset.QuadPart+=(Ttail-Thead); 00449 Open->Bhead=Ttail; 00450 00451 } 00452 00453 return STATUS_SUCCESS; 00454 } 00455 00456 //------------------------------------------------------------------- 00457 00458 NTSTATUS NPF_CloseDumpFile(POPEN_INSTANCE Open){ 00459 NTSTATUS ntStatus; 00460 IO_STATUS_BLOCK IoStatus; 00461 PMDL WriteMdl; 00462 PUCHAR VMBuff; 00463 UINT VMBufLen; 00464 00465 00466 IF_LOUD(DbgPrint("NPF: NPF_CloseDumpFile.\n");) 00467 IF_LOUD(DbgPrint("Dumpoffset=%d\n",Open->DumpOffset.QuadPart);) 00468 00469 DbgPrint("1\n"); 00470 // Consistency check 00471 if(Open->DumpFileHandle == NULL) 00472 return STATUS_UNSUCCESSFUL; 00473 00474 DbgPrint("2\n"); 00475 ZwClose( Open->DumpFileHandle ); 00476 00477 ObDereferenceObject(Open->DumpFileObject); 00478 /* 00479 if(Open->DumpLimitReached == TRUE) 00480 // Limit already reached: don't save the rest of the buffer. 00481 return STATUS_SUCCESS; 00482 */ 00483 DbgPrint("3\n"); 00484 00485 NPF_OpenDumpFile(Open,&Open->DumpFileName, TRUE); 00486 00487 // Flush the buffer to file 00488 NPF_SaveCurrentBuffer(Open); 00489 00490 // Close The file 00491 ObDereferenceObject(Open->DumpFileObject); 00492 ZwClose( Open->DumpFileHandle ); 00493 00494 Open->DumpFileHandle = NULL; 00495 00496 ObDereferenceObject(Open->DumpFileObject); 00497 00498 return STATUS_SUCCESS; 00499 } 00500 00501 //------------------------------------------------------------------- 00502 00503 static NTSTATUS PacketDumpCompletion(PDEVICE_OBJECT DeviceObject, 00504 PIRP Irp, 00505 PVOID Context) 00506 { 00507 00508 // Copy the status information back into the "user" IOSB 00509 *Irp->UserIosb = Irp->IoStatus; 00510 00511 // Wake up the mainline code 00512 KeSetEvent(Irp->UserEvent, 0, FALSE); 00513 00514 return STATUS_MORE_PROCESSING_REQUIRED; 00515 } 00516 00517 //------------------------------------------------------------------- 00518 00519 VOID NPF_WriteDumpFile(PFILE_OBJECT FileObject, 00520 PLARGE_INTEGER Offset, 00521 ULONG Length, 00522 PMDL Mdl, 00523 PIO_STATUS_BLOCK IoStatusBlock) 00524 { 00525 PIRP irp; 00526 KEVENT event; 00527 PIO_STACK_LOCATION ioStackLocation; 00528 PDEVICE_OBJECT fsdDevice = IoGetRelatedDeviceObject(FileObject); 00529 NTSTATUS Status; 00530 00531 // Set up the event we'll use 00532 KeInitializeEvent(&event, SynchronizationEvent, FALSE); 00533 00534 // Allocate and build the IRP we'll be sending to the FSD 00535 irp = IoAllocateIrp(fsdDevice->StackSize, FALSE); 00536 00537 if (!irp) { 00538 // Allocation failed, presumably due to memory allocation failure 00539 IoStatusBlock->Status = STATUS_INSUFFICIENT_RESOURCES; 00540 IoStatusBlock->Information = 0; 00541 00542 return; 00543 } 00544 00545 irp->MdlAddress = Mdl; 00546 irp->UserEvent = &event; 00547 irp->UserIosb = IoStatusBlock; 00548 irp->Tail.Overlay.Thread = PsGetCurrentThread(); 00549 irp->Tail.Overlay.OriginalFileObject= FileObject; 00550 irp->RequestorMode = KernelMode; 00551 00552 // Indicate that this is a WRITE operation 00553 irp->Flags = IRP_WRITE_OPERATION; 00554 00555 // Set up the next I/O stack location 00556 ioStackLocation = IoGetNextIrpStackLocation(irp); 00557 ioStackLocation->MajorFunction = IRP_MJ_WRITE; 00558 ioStackLocation->MinorFunction = 0; 00559 ioStackLocation->DeviceObject = fsdDevice; 00560 ioStackLocation->FileObject = FileObject; 00561 IoSetCompletionRoutine(irp, PacketDumpCompletion, 0, TRUE, TRUE, TRUE); 00562 ioStackLocation->Parameters.Write.Length = Length; 00563 ioStackLocation->Parameters.Write.ByteOffset = *Offset; 00564 00565 00566 // Send it on. Ignore the return code 00567 (void) IoCallDriver(fsdDevice, irp); 00568 00569 // Wait for the I/O to complete. 00570 KeWaitForSingleObject(&event, Executive, KernelMode, TRUE, 0); 00571 00572 // Free the IRP now that we are done with it 00573 IoFreeIrp(irp); 00574 00575 return; 00576 00577 }
documentation. Copyright (c) 2002 Politecnico di Torino. All rights reserved.