Main Page   Modules   Data Structures   File List   Data Fields   Globals   Related Pages  

Write.c

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

documentation. Copyright (c) 2002-2003 Politecnico di Torino. All rights reserved.