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.