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