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, 2000
00003  *  Politecnico di Torino.  All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that: (1) source code distributions
00007  * retain the above copyright notice and this paragraph in its entirety, (2)
00008  * distributions including binary code include the above copyright notice and
00009  * this paragraph in its entirety in the documentation or other materials
00010  * provided with the distribution, and (3) all advertising materials mentioning
00011  * features or use of this software display the following acknowledgement:
00012  * ``This product includes software developed by the Politecnico
00013  * di Torino, and its contributors.'' Neither the name of
00014  * the University nor the names of its contributors may be used to endorse
00015  * or promote products derived from this software without specific prior
00016  * written permission.
00017  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
00018  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
00019  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00020  */
00021 
00022 #include "stdarg.h"
00023 #include "ntddk.h"
00024 #include "ntiologc.h"
00025 #include "ndis.h"
00026 
00027 #include "debug.h"
00028 #include "packet.h"
00029 
00030 
00031 //-------------------------------------------------------------------
00032 
00033 NTSTATUS
00034 NPF_Write(
00035     IN PDEVICE_OBJECT DeviceObject,
00036     IN PIRP Irp
00037     )
00038 
00039 {
00040     POPEN_INSTANCE      Open;
00041     PIO_STACK_LOCATION  IrpSp;
00042     PNDIS_PACKET        pPacket;
00043     UINT                i;
00044     NDIS_STATUS         Status;
00045 
00046     IF_LOUD(DbgPrint("NPF_Write\n");)
00047 
00048     IrpSp = IoGetCurrentIrpStackLocation(Irp);
00049 
00050 
00051     Open=IrpSp->FileObject->FsContext;
00052     
00053     if( Open->Bound == FALSE ){ 
00054         // The Network adapter was removed. 
00055         EXIT_FAILURE(0); 
00056     } 
00057     
00058     IF_LOUD(DbgPrint("Max frame size = %d\n", Open->MaxFrameSize);)
00059 
00060 
00061     if(IrpSp->Parameters.Write.Length == 0 ||   // Check that the buffer provided by the user is not empty
00062         Open->MaxFrameSize == 0 ||  // Check that the MaxFrameSize is correctly initialized
00063         IrpSp->Parameters.Write.Length > Open->MaxFrameSize) // Check that the fame size is smaller that the MTU
00064     {
00065         IF_LOUD(DbgPrint("frame size out of range, send aborted\n");)
00066 
00067         Irp->IoStatus.Status = NDIS_STATUS_SUCCESS;
00068         IoCompleteRequest (Irp, IO_NO_INCREMENT);
00069         return NDIS_STATUS_SUCCESS;
00070     }
00071 
00072 
00073     IoMarkIrpPending(Irp);
00074 
00075     Open->Multiple_Write_Counter=Open->Nwrites;
00076 
00077     NdisResetEvent(&Open->WriteEvent);
00078 
00079 
00080     for(i=0;i<Open->Nwrites;i++){
00081         
00082         //  Try to get a packet from our list of free ones
00083         NdisAllocatePacket(
00084             &Status,
00085             &pPacket,
00086             Open->PacketPool
00087             );
00088         
00089         if (Status != NDIS_STATUS_SUCCESS) {
00090             
00091             //  No free packets
00092             Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
00093             IoCompleteRequest (Irp, IO_NO_INCREMENT);
00094             return STATUS_INSUFFICIENT_RESOURCES;
00095         }
00096         
00097         // The packet has a buffer that needs not to be freed after every single write
00098         RESERVED(pPacket)->FreeBufAfterWrite = FALSE;
00099 
00100         // Save the IRP associated with the packet
00101         RESERVED(pPacket)->Irp=Irp;
00102         
00103         //  Attach the writes buffer to the packet
00104         NdisChainBufferAtFront(pPacket,Irp->MdlAddress);
00105         
00106         //  Call the MAC
00107         NdisSend(
00108             &Status,
00109             Open->AdapterHandle,
00110             pPacket);
00111 
00112         if (Status != NDIS_STATUS_PENDING) {
00113             //  The send didn't pend so call the completion handler now
00114             NPF_SendComplete(
00115                 Open,
00116                 pPacket,
00117                 Status
00118                 );
00119             
00120         }
00121         
00122         if(i%100==99){
00123             NdisWaitEvent(&Open->WriteEvent,1000);  
00124             NdisResetEvent(&Open->WriteEvent);
00125         }
00126     }
00127     
00128     return(STATUS_PENDING);
00129 
00130 }
00131 
00132 
00133 //-------------------------------------------------------------------
00134 
00135 INT
00136 NPF_BufferedWrite(
00137     IN PIRP Irp, 
00138     IN PCHAR UserBuff, 
00139     IN ULONG UserBuffSize, 
00140     BOOLEAN Sync)
00141 {
00142     POPEN_INSTANCE      Open;
00143     PIO_STACK_LOCATION  IrpSp;
00144     PNDIS_PACKET        pPacket;
00145     UINT                i;
00146     NDIS_STATUS         Status;
00147     LARGE_INTEGER       StartTicks, CurTicks, TargetTicks;
00148     LARGE_INTEGER       TimeFreq;
00149     struct timeval      BufStartTime;
00150     struct sf_pkthdr    *winpcap_hdr;
00151     PMDL                TmpMdl;
00152     PCHAR               CurPos;
00153     PCHAR               EndOfUserBuff = UserBuff + UserBuffSize;
00154     
00155     IF_LOUD(DbgPrint("NPF: BufferedWrite, UserBuff=%x, Size=%u\n", UserBuff, UserBuffSize);)
00156         
00157     IrpSp = IoGetCurrentIrpStackLocation(Irp);
00158     
00159     Open=IrpSp->FileObject->FsContext;
00160     
00161     if( Open->Bound == FALSE ){ 
00162         // The Network adapter was removed. 
00163         return 0; 
00164     } 
00165 
00166     // Sanity check on the user buffer
00167     if(UserBuff==0)
00168     {
00169         return 0;
00170     }
00171 
00172     // Check that the MaxFrameSize is correctly initialized
00173     if(Open->MaxFrameSize == 0)
00174     {
00175         IF_LOUD(DbgPrint("BufferedWrite: Open->MaxFrameSize not initialized, probably because of a problem in the OID query\n");)
00176 
00177         return 0;
00178     }
00179 
00180     
00181     // Start from the first packet
00182     winpcap_hdr = (struct sf_pkthdr*)UserBuff;
00183     
00184     // Retrieve the time references
00185     StartTicks = KeQueryPerformanceCounter(&TimeFreq);
00186     BufStartTime.tv_sec = winpcap_hdr->ts.tv_sec;
00187     BufStartTime.tv_usec = winpcap_hdr->ts.tv_usec;
00188     
00189     // Chech the consistency of the user buffer
00190     if( (PCHAR)winpcap_hdr + winpcap_hdr->caplen + sizeof(struct sf_pkthdr) > EndOfUserBuff )
00191     {
00192         IF_LOUD(DbgPrint("Buffered Write: bogus packet buffer\n");)
00193 
00194         return -1;
00195     }
00196     
00197     // Save the current time stamp counter
00198     CurTicks = KeQueryPerformanceCounter(NULL);
00199     
00200     // Main loop: send the buffer to the wire
00201     while( TRUE ){
00202         
00203         if(winpcap_hdr->caplen ==0 || winpcap_hdr->caplen > Open->MaxFrameSize)
00204         {
00205             // Malformed header
00206             IF_LOUD(DbgPrint("NPF_BufferedWrite: malformed or bogus user buffer, aborting write.\n");)
00207             
00208             return -1;
00209         }
00210         
00211         // Allocate an MDL to map the packet data
00212         TmpMdl=IoAllocateMdl((PCHAR)winpcap_hdr + sizeof(struct sf_pkthdr),
00213             winpcap_hdr->caplen,
00214             FALSE,
00215             FALSE,
00216             NULL);
00217         
00218         if (TmpMdl == NULL)
00219         {
00220             // Unable to map the memory: packet lost
00221             IF_LOUD(DbgPrint("NPF_BufferedWrite: unable to allocate the MDL.\n");)
00222 
00223             return -1;
00224         }
00225         
00226         MmBuildMdlForNonPagedPool(TmpMdl);  // XXX can this line be removed?
00227         
00228         // Allocate a packet from our free list
00229         NdisAllocatePacket( &Status, &pPacket, Open->PacketPool);
00230         
00231         if (Status != NDIS_STATUS_SUCCESS) {
00232             //  No free packets
00233             IF_LOUD(DbgPrint("NPF_BufferedWrite: no more free packets, returning.\n");)
00234 
00235             return (PCHAR)winpcap_hdr - UserBuff;
00236         }
00237         
00238         // The packet has a buffer that needs to be freed after every single write
00239         RESERVED(pPacket)->FreeBufAfterWrite = TRUE;
00240         
00241         // Attach the MDL to the packet
00242         NdisChainBufferAtFront(pPacket,TmpMdl);
00243         
00244         // Call the MAC
00245         NdisSend( &Status, Open->AdapterHandle, pPacket);
00246         
00247         if (Status != NDIS_STATUS_PENDING) {
00248             // The send didn't pend so call the completion handler now
00249             NPF_SendComplete(
00250                 Open,
00251                 pPacket,
00252                 Status
00253                 );              
00254         }
00255         
00256         // Step to the next packet in the buffer
00257         (PCHAR)winpcap_hdr += winpcap_hdr->caplen + sizeof(struct sf_pkthdr);
00258         
00259         // Check if the end of the user buffer has been reached
00260         if( (PCHAR)winpcap_hdr >= EndOfUserBuff )
00261         {
00262             IF_LOUD(DbgPrint("NPF_BufferedWrite: End of buffer.\n");)
00263 
00264             return (PCHAR)winpcap_hdr - UserBuff;
00265         }
00266         
00267         if( Sync ){
00268             
00269             // Release the application if it has been blocked for approximately more than 1 seconds
00270             if( winpcap_hdr->ts.tv_sec - BufStartTime.tv_sec > 1 )
00271             {
00272                 IF_LOUD(DbgPrint("NPF_BufferedWrite: timestamp elapsed, returning.\n");)
00273                     
00274                 return (PCHAR)winpcap_hdr - UserBuff;
00275             }
00276             
00277             // Calculate the time interval to wait before sending the next packet
00278             TargetTicks.QuadPart = StartTicks.QuadPart +
00279                 (LONGLONG)((winpcap_hdr->ts.tv_sec - BufStartTime.tv_sec) * 1000000 +
00280                 winpcap_hdr->ts.tv_usec - BufStartTime.tv_usec) *
00281                 (TimeFreq.QuadPart) / 1000000;
00282             
00283             // Wait until the time interval has elapsed
00284             while( CurTicks.QuadPart <= TargetTicks.QuadPart )
00285                 CurTicks = KeQueryPerformanceCounter(NULL);
00286         }
00287         
00288     }
00289                 
00290     return (PCHAR)winpcap_hdr - UserBuff;
00291         
00292 }
00293 
00294 
00295 //-------------------------------------------------------------------
00296 
00297 VOID
00298 NPF_SendComplete(
00299                    IN NDIS_HANDLE   ProtocolBindingContext,
00300                    IN PNDIS_PACKET  pPacket,
00301                    IN NDIS_STATUS   Status
00302                    )
00303                    
00304 {
00305     PIRP              Irp;
00306     PIO_STACK_LOCATION  irpSp;
00307     POPEN_INSTANCE      Open;
00308     PMDL TmpMdl;
00309     
00310     IF_LOUD(DbgPrint("NPF: SendComplete, BindingContext=%d\n",ProtocolBindingContext);)
00311         
00312     Open= (POPEN_INSTANCE)ProtocolBindingContext;
00313     
00314     if( RESERVED(pPacket)->FreeBufAfterWrite ){
00315         
00316         // Free the MDL associated with the packet
00317         NdisUnchainBufferAtFront(pPacket, &TmpMdl);
00318         IoFreeMdl(TmpMdl);
00319     }
00320     else{
00321         if((Open->Nwrites - Open->Multiple_Write_Counter) %100 == 99)
00322             NdisSetEvent(&Open->WriteEvent);
00323         
00324         Open->Multiple_Write_Counter--;
00325 
00326         if(Open->Multiple_Write_Counter == 0){
00327             // Release the buffer and awake the application
00328             NdisUnchainBufferAtFront(pPacket, &TmpMdl);
00329             
00330             // Complete the request
00331             Irp=RESERVED(pPacket)->Irp;
00332             irpSp = IoGetCurrentIrpStackLocation(Irp);
00333 
00334             Irp->IoStatus.Status = Status;
00335             Irp->IoStatus.Information = irpSp->Parameters.Write.Length;
00336             IoCompleteRequest(Irp, IO_NO_INCREMENT);
00337             
00338         }
00339     }
00340         
00341     //  recyle the packet
00342     NdisReinitializePacket(pPacket);
00343     
00344     //  Put the packet back on the free list
00345     NdisFreePacket(pPacket);
00346 
00347 
00348     return;
00349 }

documentation. Copyright (c) 2002-2003 Politecnico di Torino. All rights reserved.