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         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.