2 * Copyright (c) 1999, 2000
3 * Politecnico di Torino. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that: (1) source code distributions
7 * retain the above copyright notice and this paragraph in its entirety, (2)
8 * distributions including binary code include the above copyright notice and
9 * this paragraph in its entirety in the documentation or other materials
10 * provided with the distribution, and (3) all advertising materials mentioning
11 * features or use of this software display the following acknowledgement:
12 * ``This product includes software developed by the Politecnico
13 * di Torino, and its contributors.'' Neither the name of
14 * the University nor the names of its contributors may be used to endorse
15 * or promote products derived from this software without specific prior
17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
28 #include <ddk/ntddk.h>
30 #define NdisReinitializePacket(Packet) \
32 (Packet)->Private.Head = (PNDIS_BUFFER)NULL; \
33 (Packet)->Private.ValidCounts = FALSE; \
42 //-------------------------------------------------------------------
46 IN PDEVICE_OBJECT DeviceObject,
52 PIO_STACK_LOCATION IrpSp;
57 IF_LOUD(DbgPrint("NPF_Write\n");)
59 IrpSp = IoGetCurrentIrpStackLocation(Irp);
62 Open=IrpSp->FileObject->FsContext;
64 IF_LOUD(DbgPrint("Max frame size = %d\n", Open->MaxFrameSize);)
67 if(IrpSp->Parameters.Write.Length == 0 || // Check that the buffer provided by the user is not empty
68 Open->MaxFrameSize == 0 || // Check that the MaxFrameSize is correctly initialized
69 IrpSp->Parameters.Write.Length > Open->MaxFrameSize) // Check that the fame size is smaller that the MTU
71 IF_LOUD(DbgPrint("frame size out of range, send aborted\n");)
73 Irp->IoStatus.Status = NDIS_STATUS_SUCCESS;
74 IoCompleteRequest (Irp, IO_NO_INCREMENT);
75 return NDIS_STATUS_SUCCESS;
79 IoMarkIrpPending(Irp);
81 Open->Multiple_Write_Counter=Open->Nwrites;
83 NdisResetEvent(&Open->WriteEvent);
86 for(i=0;i<Open->Nwrites;i++){
88 // Try to get a packet from our list of free ones
95 if (Status != NDIS_STATUS_SUCCESS) {
98 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
99 IoCompleteRequest (Irp, IO_NO_INCREMENT);
100 return STATUS_INSUFFICIENT_RESOURCES;
103 // The packet has a buffer that needs not to be freed after every single write
104 RESERVED(pPacket)->FreeBufAfterWrite = FALSE;
106 // Save the IRP associated with the packet
107 RESERVED(pPacket)->Irp=Irp;
109 // Attach the writes buffer to the packet
110 NdisChainBufferAtFront(pPacket,Irp->MdlAddress);
118 if (Status != NDIS_STATUS_PENDING) {
119 // The send didn't pend so call the completion handler now
129 NdisWaitEvent(&Open->WriteEvent,1000);
130 NdisResetEvent(&Open->WriteEvent);
134 return(STATUS_PENDING);
139 //-------------------------------------------------------------------
145 IN ULONG UserBuffSize,
149 PIO_STACK_LOCATION IrpSp;
150 PNDIS_PACKET pPacket;
153 LARGE_INTEGER StartTicks, CurTicks, TargetTicks;
154 LARGE_INTEGER TimeFreq;
155 struct timeval BufStartTime;
156 struct sf_pkthdr *winpcap_hdr;
159 PCHAR EndOfUserBuff = UserBuff + UserBuffSize;
161 IF_LOUD(DbgPrint("NPF: BufferedWrite, UserBuff=%x, Size=%u\n", UserBuff, UserBuffSize);)
163 IrpSp = IoGetCurrentIrpStackLocation(Irp);
165 Open=IrpSp->FileObject->FsContext;
167 // Security check on the length of the user buffer
173 // Check that the MaxFrameSize is correctly initialized
174 if(Open->MaxFrameSize == 0)
176 IF_LOUD(DbgPrint("BufferedWrite: Open->MaxFrameSize not initialized, probably because of a problem in the OID query\n");)
182 // Start from the first packet
183 winpcap_hdr = (struct sf_pkthdr*)UserBuff;
185 // Retrieve the time references
186 StartTicks = KeQueryPerformanceCounter(&TimeFreq);
187 BufStartTime.tv_sec = winpcap_hdr->ts.tv_sec;
188 BufStartTime.tv_usec = winpcap_hdr->ts.tv_usec;
190 // Chech the consistency of the user buffer
191 if( (PCHAR)winpcap_hdr + winpcap_hdr->caplen + sizeof(struct sf_pkthdr) > EndOfUserBuff )
193 IF_LOUD(DbgPrint("Buffered Write: bogus packet buffer\n");)
198 // Save the current time stamp counter
199 CurTicks = KeQueryPerformanceCounter(NULL);
201 // Main loop: send the buffer to the wire
204 if(winpcap_hdr->caplen ==0 || winpcap_hdr->caplen > Open->MaxFrameSize)
207 IF_LOUD(DbgPrint("NPF_BufferedWrite: malformed or bogus user buffer, aborting write.\n");)
212 // Allocate an MDL to map the packet data
213 TmpMdl=IoAllocateMdl((PCHAR)winpcap_hdr + sizeof(struct sf_pkthdr),
221 // Unable to map the memory: packet lost
222 IF_LOUD(DbgPrint("NPF_BufferedWrite: unable to allocate the MDL.\n");)
227 MmBuildMdlForNonPagedPool(TmpMdl); // XXX can this line be removed?
229 // Allocate a packet from our free list
230 NdisAllocatePacket( &Status, &pPacket, Open->PacketPool);
232 if (Status != NDIS_STATUS_SUCCESS) {
234 IF_LOUD(DbgPrint("NPF_BufferedWrite: no more free packets, returning.\n");)
236 return (PCHAR)winpcap_hdr - UserBuff;
239 // The packet has a buffer that needs to be freed after every single write
240 RESERVED(pPacket)->FreeBufAfterWrite = TRUE;
242 // Attach the MDL to the packet
243 NdisChainBufferAtFront(pPacket,TmpMdl);
246 NdisSend( &Status, Open->AdapterHandle, pPacket);
248 if (Status != NDIS_STATUS_PENDING) {
249 // The send didn't pend so call the completion handler now
257 // Step to the next packet in the buffer
258 (PCHAR)winpcap_hdr += winpcap_hdr->caplen + sizeof(struct sf_pkthdr);
260 // Check if the end of the user buffer has been reached
261 if( (PCHAR)winpcap_hdr >= EndOfUserBuff )
263 IF_LOUD(DbgPrint("NPF_BufferedWrite: End of buffer.\n");)
265 return (PCHAR)winpcap_hdr - UserBuff;
270 // Release the application if it has been blocked for approximately more than 1 seconds
271 if( winpcap_hdr->ts.tv_sec - BufStartTime.tv_sec > 1 )
273 IF_LOUD(DbgPrint("NPF_BufferedWrite: timestamp elapsed, returning.\n");)
275 return (PCHAR)winpcap_hdr - UserBuff;
279 // Calculate the time interval to wait before sending the next packet
280 TargetTicks.QuadPart = StartTicks.QuadPart +
281 (LONGLONG)((winpcap_hdr->ts.tv_sec - BufStartTime.tv_sec) * 1000000 +
282 winpcap_hdr->ts.tv_usec - BufStartTime.tv_usec) *
283 (TimeFreq.QuadPart) / 1000000;
285 // Wait until the time interval has elapsed
286 while( CurTicks.QuadPart <= TargetTicks.QuadPart )
287 CurTicks = KeQueryPerformanceCounter(NULL);
294 return (PCHAR)winpcap_hdr - UserBuff;
299 //-------------------------------------------------------------------
303 IN NDIS_HANDLE ProtocolBindingContext,
304 IN PNDIS_PACKET pPacket,
305 IN NDIS_STATUS Status
310 PIO_STACK_LOCATION irpSp;
314 IF_LOUD(DbgPrint("NPF: SendComplete, BindingContext=%d\n",ProtocolBindingContext);)
316 Open= (POPEN_INSTANCE)ProtocolBindingContext;
318 if( RESERVED(pPacket)->FreeBufAfterWrite ){
319 // Free the MDL associated with the packet
320 NdisUnchainBufferAtFront(pPacket, &TmpMdl);
324 if((Open->Nwrites - Open->Multiple_Write_Counter) %100 == 99)
325 NdisSetEvent(&Open->WriteEvent);
327 Open->Multiple_Write_Counter--;
331 NdisReinitializePacket(pPacket);
333 // Put the packet back on the free list
334 NdisFreePacket(pPacket);
336 if( !(RESERVED(pPacket)->FreeBufAfterWrite) ){
337 if(Open->Multiple_Write_Counter==0){
338 // Release the buffer and awake the application
339 NdisUnchainBufferAtFront(pPacket, &TmpMdl);
341 Irp=RESERVED(pPacket)->Irp;
342 irpSp = IoGetCurrentIrpStackLocation(Irp);
344 Irp->IoStatus.Status = Status;
345 Irp->IoStatus.Information = irpSp->Parameters.Write.Length;
346 IoCompleteRequest(Irp, IO_NO_INCREMENT);