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.