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.