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 00038 #include "debug.h" 00039 #include "packet.h" 00040 00041 00042 //------------------------------------------------------------------- 00043 00044 NTSTATUS 00045 NPF_Write( 00046 IN PDEVICE_OBJECT DeviceObject, 00047 IN PIRP Irp 00048 ) 00049 00050 { 00051 POPEN_INSTANCE Open; 00052 PIO_STACK_LOCATION IrpSp; 00053 PNDIS_PACKET pPacket; 00054 UINT i; 00055 NDIS_STATUS Status; 00056 00057 IF_LOUD(DbgPrint("NPF_Write\n");) 00058 00059 IrpSp = IoGetCurrentIrpStackLocation(Irp); 00060 00061 00062 Open=IrpSp->FileObject->FsContext; 00063 00064 if( Open->Bound == FALSE ) 00065 { 00066 // The Network adapter was removed. 00067 EXIT_FAILURE(0); 00068 } 00069 00070 NdisAcquireSpinLock(&Open->WriteLock); 00071 if(Open->WriteInProgress) 00072 { 00073 // Another write operation is currently in progress 00074 EXIT_FAILURE(0); 00075 } 00076 else 00077 { 00078 Open->WriteInProgress = TRUE; 00079 } 00080 NdisReleaseSpinLock(&Open->WriteLock); 00081 00082 IF_LOUD(DbgPrint("Max frame size = %d\n", Open->MaxFrameSize);) 00083 00084 00085 if(IrpSp->Parameters.Write.Length == 0 || // Check that the buffer provided by the user is not empty 00086 Open->MaxFrameSize == 0 || // Check that the MaxFrameSize is correctly initialized 00087 IrpSp->Parameters.Write.Length > Open->MaxFrameSize) // Check that the fame size is smaller that the MTU 00088 { 00089 IF_LOUD(DbgPrint("frame size out of range, send aborted\n");) 00090 00091 EXIT_FAILURE(0); 00092 } 00093 00094 00095 IoMarkIrpPending(Irp); 00096 00097 Open->Multiple_Write_Counter=Open->Nwrites; 00098 00099 NdisResetEvent(&Open->WriteEvent); 00100 00101 00102 for(i=0;i<Open->Nwrites;i++){ 00103 00104 // Try to get a packet from our list of free ones 00105 NdisAllocatePacket( 00106 &Status, 00107 &pPacket, 00108 Open->PacketPool 00109 ); 00110 00111 if (Status != NDIS_STATUS_SUCCESS) { 00112 00113 // No free packets 00114 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 00115 IoCompleteRequest (Irp, IO_NO_INCREMENT); 00116 return STATUS_INSUFFICIENT_RESOURCES; 00117 } 00118 00119 // The packet hasn't a buffer that needs not to be freed after every single write 00120 RESERVED(pPacket)->FreeBufAfterWrite = FALSE; 00121 00122 // Save the IRP associated with the packet 00123 RESERVED(pPacket)->Irp=Irp; 00124 00125 // Attach the writes buffer to the packet 00126 NdisChainBufferAtFront(pPacket,Irp->MdlAddress); 00127 00128 // Call the MAC 00129 NdisSend( 00130 &Status, 00131 Open->AdapterHandle, 00132 pPacket); 00133 00134 if (Status != NDIS_STATUS_PENDING) { 00135 // The send didn't pend so call the completion handler now 00136 NPF_SendComplete( 00137 Open, 00138 pPacket, 00139 Status 00140 ); 00141 00142 } 00143 00144 if(i%100==99){ 00145 NdisWaitEvent(&Open->WriteEvent,1000); 00146 NdisResetEvent(&Open->WriteEvent); 00147 } 00148 } 00149 00150 return(STATUS_PENDING); 00151 } 00152 00153 //------------------------------------------------------------------- 00154 00155 INT 00156 NPF_BufferedWrite( 00157 IN PIRP Irp, 00158 IN PCHAR UserBuff, 00159 IN ULONG UserBuffSize, 00160 BOOLEAN Sync) 00161 { 00162 POPEN_INSTANCE Open; 00163 PIO_STACK_LOCATION IrpSp; 00164 PNDIS_PACKET pPacket; 00165 UINT i; 00166 NDIS_STATUS Status; 00167 LARGE_INTEGER StartTicks, CurTicks, TargetTicks; 00168 LARGE_INTEGER TimeFreq; 00169 struct timeval BufStartTime; 00170 struct sf_pkthdr *winpcap_hdr; 00171 PMDL TmpMdl; 00172 PCHAR CurPos; 00173 PCHAR EndOfUserBuff = UserBuff + UserBuffSize; 00174 00175 IF_LOUD(DbgPrint("NPF: BufferedWrite, UserBuff=%x, Size=%u\n", UserBuff, UserBuffSize);) 00176 00177 IrpSp = IoGetCurrentIrpStackLocation(Irp); 00178 00179 Open=IrpSp->FileObject->FsContext; 00180 00181 if( Open->Bound == FALSE ){ 00182 // The Network adapter was removed. 00183 return 0; 00184 } 00185 00186 // Sanity check on the user buffer 00187 if(UserBuff==0) 00188 { 00189 return 0; 00190 } 00191 00192 // Check that the MaxFrameSize is correctly initialized 00193 if(Open->MaxFrameSize == 0) 00194 { 00195 IF_LOUD(DbgPrint("BufferedWrite: Open->MaxFrameSize not initialized, probably because of a problem in the OID query\n");) 00196 00197 return 0; 00198 } 00199 00200 // Reset the event used to synchronize packet allocation 00201 NdisResetEvent(&Open->WriteEvent); 00202 00203 // Reset the pending packets counter 00204 Open->Multiple_Write_Counter = 0; 00205 00206 // Start from the first packet 00207 winpcap_hdr = (struct sf_pkthdr*)UserBuff; 00208 00209 // Retrieve the time references 00210 StartTicks = KeQueryPerformanceCounter(&TimeFreq); 00211 BufStartTime.tv_sec = winpcap_hdr->ts.tv_sec; 00212 BufStartTime.tv_usec = winpcap_hdr->ts.tv_usec; 00213 00214 // Chech the consistency of the user buffer 00215 if( (PCHAR)winpcap_hdr + winpcap_hdr->caplen + sizeof(struct sf_pkthdr) > EndOfUserBuff ) 00216 { 00217 IF_LOUD(DbgPrint("Buffered Write: bogus packet buffer\n");) 00218 00219 return -1; 00220 } 00221 00222 // Save the current time stamp counter 00223 CurTicks = KeQueryPerformanceCounter(NULL); 00224 00225 // 00226 // Main loop: send the buffer to the wire 00227 // 00228 while(TRUE) 00229 { 00230 00231 if(winpcap_hdr->caplen ==0 || winpcap_hdr->caplen > Open->MaxFrameSize) 00232 { 00233 // Malformed header 00234 IF_LOUD(DbgPrint("NPF_BufferedWrite: malformed or bogus user buffer, aborting write.\n");) 00235 00236 return -1; 00237 } 00238 00239 // Allocate an MDL to map the packet data 00240 TmpMdl = IoAllocateMdl((PCHAR)winpcap_hdr + sizeof(struct sf_pkthdr), 00241 winpcap_hdr->caplen, 00242 FALSE, 00243 FALSE, 00244 NULL); 00245 00246 if (TmpMdl == NULL) 00247 { 00248 // Unable to map the memory: packet lost 00249 IF_LOUD(DbgPrint("NPF_BufferedWrite: unable to allocate the MDL.\n");) 00250 00251 return -1; 00252 } 00253 00254 MmBuildMdlForNonPagedPool(TmpMdl); // XXX can this line be removed? 00255 00256 // Allocate a packet from our free list 00257 NdisAllocatePacket( &Status, &pPacket, Open->PacketPool); 00258 00259 if (Status != NDIS_STATUS_SUCCESS) { 00260 // No more free packets 00261 IF_LOUD(DbgPrint("NPF_BufferedWrite: no more free packets, returning.\n");) 00262 00263 NdisResetEvent(&Open->WriteEvent); 00264 00265 NdisWaitEvent(&Open->WriteEvent, 1000); 00266 00267 // Try again to allocate a packet 00268 NdisAllocatePacket( &Status, &pPacket, Open->PacketPool); 00269 00270 if (Status != NDIS_STATUS_SUCCESS) { 00271 // Second failure, report an error 00272 IoFreeMdl(TmpMdl); 00273 return -1; 00274 } 00275 00276 // IoFreeMdl(TmpMdl); 00277 // return (PCHAR)winpcap_hdr - UserBuff; 00278 } 00279 00280 00281 // The packet has a buffer that needs to be freed after every single write 00282 RESERVED(pPacket)->FreeBufAfterWrite = TRUE; 00283 00284 TmpMdl->Next = NULL; 00285 00286 // Attach the MDL to the packet 00287 NdisChainBufferAtFront(pPacket, TmpMdl); 00288 00289 // Increment the number of pending sends 00290 InterlockedIncrement(&Open->Multiple_Write_Counter); 00291 00292 // Call the MAC 00293 NdisSend( &Status, Open->AdapterHandle, pPacket); 00294 00295 if (Status != NDIS_STATUS_PENDING) { 00296 // The send didn't pend so call the completion handler now 00297 NPF_SendComplete( 00298 Open, 00299 pPacket, 00300 Status 00301 ); 00302 } 00303 00304 // Step to the next packet in the buffer 00305 (PCHAR)winpcap_hdr += winpcap_hdr->caplen + sizeof(struct sf_pkthdr); 00306 00307 // Check if the end of the user buffer has been reached 00308 if( (PCHAR)winpcap_hdr >= EndOfUserBuff ) 00309 { 00310 IF_LOUD(DbgPrint("NPF_BufferedWrite: End of buffer.\n");) 00311 00312 // Wait the completion of pending sends 00313 NPF_WaitEndOfBufferedWrite(Open); 00314 00315 return (PCHAR)winpcap_hdr - UserBuff; 00316 } 00317 00318 if( Sync ){ 00319 00320 // Release the application if it has been blocked for approximately more than 1 seconds 00321 if( winpcap_hdr->ts.tv_sec - BufStartTime.tv_sec > 1 ) 00322 { 00323 IF_LOUD(DbgPrint("NPF_BufferedWrite: timestamp elapsed, returning.\n");) 00324 00325 // Wait the completion of pending sends 00326 NPF_WaitEndOfBufferedWrite(Open); 00327 00328 return (PCHAR)winpcap_hdr - UserBuff; 00329 } 00330 00331 // Calculate the time interval to wait before sending the next packet 00332 TargetTicks.QuadPart = StartTicks.QuadPart + 00333 (LONGLONG)((winpcap_hdr->ts.tv_sec - BufStartTime.tv_sec) * 1000000 + 00334 winpcap_hdr->ts.tv_usec - BufStartTime.tv_usec) * 00335 (TimeFreq.QuadPart) / 1000000; 00336 00337 // Wait until the time interval has elapsed 00338 while( CurTicks.QuadPart <= TargetTicks.QuadPart ) 00339 CurTicks = KeQueryPerformanceCounter(NULL); 00340 } 00341 00342 } 00343 00344 return (PCHAR)winpcap_hdr - UserBuff; 00345 } 00346 00347 //------------------------------------------------------------------- 00348 00349 VOID NPF_WaitEndOfBufferedWrite(POPEN_INSTANCE Open) 00350 { 00351 UINT i; 00352 00353 NdisResetEvent(&Open->WriteEvent); 00354 00355 for(i=0; Open->Multiple_Write_Counter > 0 && i < TRANSMIT_PACKETS; i++) 00356 { 00357 NdisWaitEvent(&Open->WriteEvent, 100); 00358 NdisResetEvent(&Open->WriteEvent); 00359 } 00360 00361 return; 00362 } 00363 00364 //------------------------------------------------------------------- 00365 00366 VOID 00367 NPF_SendComplete( 00368 IN NDIS_HANDLE ProtocolBindingContext, 00369 IN PNDIS_PACKET pPacket, 00370 IN NDIS_STATUS Status 00371 ) 00372 00373 { 00374 PIRP Irp; 00375 PIO_STACK_LOCATION irpSp; 00376 POPEN_INSTANCE Open; 00377 PMDL TmpMdl; 00378 00379 IF_LOUD(DbgPrint("NPF: SendComplete, BindingContext=%d\n",ProtocolBindingContext);) 00380 00381 Open= (POPEN_INSTANCE)ProtocolBindingContext; 00382 00383 if( RESERVED(pPacket)->FreeBufAfterWrite ) 00384 { 00385 // 00386 // Packet sent by NPF_BufferedWrite() 00387 // 00388 00389 00390 // Free the MDL associated with the packet 00391 NdisUnchainBufferAtFront(pPacket, &TmpMdl); 00392 00393 IoFreeMdl(TmpMdl); 00394 00395 // recyle the packet 00396 // NdisReinitializePacket(pPacket); 00397 00398 NdisFreePacket(pPacket); 00399 00400 // Increment the number of pending sends 00401 InterlockedDecrement(&Open->Multiple_Write_Counter); 00402 00403 NdisSetEvent(&Open->WriteEvent); 00404 00405 return; 00406 } 00407 else 00408 { 00409 // 00410 // Packet sent by NPF_Write() 00411 // 00412 00413 if((Open->Nwrites - Open->Multiple_Write_Counter) %100 == 99) 00414 NdisSetEvent(&Open->WriteEvent); 00415 00416 Open->Multiple_Write_Counter--; 00417 00418 if(Open->Multiple_Write_Counter == 0){ 00419 // Release the buffer and awake the application 00420 NdisUnchainBufferAtFront(pPacket, &TmpMdl); 00421 00422 // Complete the request 00423 Irp=RESERVED(pPacket)->Irp; 00424 irpSp = IoGetCurrentIrpStackLocation(Irp); 00425 00426 Irp->IoStatus.Status = Status; 00427 Irp->IoStatus.Information = irpSp->Parameters.Write.Length; 00428 IoCompleteRequest(Irp, IO_NO_INCREMENT); 00429 00430 NdisAcquireSpinLock(&Open->WriteLock); 00431 Open->WriteInProgress = FALSE; 00432 NdisReleaseSpinLock(&Open->WriteLock); 00433 } 00434 00435 // Put the packet back on the free list 00436 NdisFreePacket(pPacket); 00437 00438 return; 00439 } 00440 00441 }
documentation. Copyright (c) 2002-2003 Politecnico di Torino. All rights reserved.