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.