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