1 /*
2  * Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy)
3  * Copyright (c) 2005 CACE Technologies, Davis (California)
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in the
14  * documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the Politecnico di Torino, CACE Technologies
16  * nor the names of its contributors may be used to endorse or promote
17  * products derived from this software without specific prior written
18  * permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  *
32  */
33 
34 #include <GlobalConst.h>
35 
36 #include "stdarg.h"
37 #include "ntddk.h"
38 #include "ntiologc.h"
39 #include "ndis.h"
40 
41 #include "debug.h"
42 #include "packet.h"
43 
44 
45 void *test_addr = NULL;
46 
47 //-------------------------------------------------------------------
48 
49 NTSTATUS
NPF_Write(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)50 NPF_Write(
51 	IN PDEVICE_OBJECT DeviceObject,
52     IN PIRP Irp
53     )
54 
55 {
56     POPEN_INSTANCE		Open;
57     PIO_STACK_LOCATION	IrpSp;
58     PNDIS_PACKET		pPacket;
59 	UINT				i;
60     NDIS_STATUS		    Status;
61 
62 	IF_LOUD(DbgPrint("NPF_Write\n");)
63 
64 	IrpSp = IoGetCurrentIrpStackLocation(Irp);
65 
66 
67     Open=IrpSp->FileObject->FsContext;
68 
69 	if( Open->Bound == FALSE )
70 	{
71 		// The Network adapter was removed.
72 		EXIT_FAILURE(0);
73 	}
74 
75 	NdisAcquireSpinLock(&Open->WriteLock);
76 	if(Open->WriteInProgress)
77 	{
78 		// Another write operation is currently in progress
79 		NdisReleaseSpinLock(&Open->WriteLock);
80 		EXIT_FAILURE(0);
81 	}
82 	else
83 	{
84 		Open->WriteInProgress = TRUE;
85 	}
86 
87 	NdisReleaseSpinLock(&Open->WriteLock);
88 
89 	IF_LOUD(DbgPrint("Max frame size = %d, packet size = %d\n", Open->MaxFrameSize, IrpSp->Parameters.Write.Length);)
90 
91 
92 	if(IrpSp->Parameters.Write.Length == 0 || 	// Check that the buffer provided by the user is not empty
93 		Open->MaxFrameSize == 0/* ||	// Check that the MaxFrameSize is correctly initialized
94 		IrpSp->Parameters.Write.Length > Open->MaxFrameSize*/) // Check that the fame size is smaller that the MTU
95 	{
96 		IF_LOUD(DbgPrint("frame size out of range, send aborted\n");)
97 
98 		EXIT_FAILURE(0);
99 	}
100 
101 
102     IoMarkIrpPending(Irp);
103 
104 	Open->Multiple_Write_Counter=Open->Nwrites;
105 
106 	NdisResetEvent(&Open->WriteEvent);
107 
108 
109 	for(i=0;i<Open->Nwrites;i++){
110 
111 		//  Try to get a packet from our list of free ones
112 		NdisAllocatePacket(
113 			&Status,
114 			&pPacket,
115 			Open->PacketPool
116 			);
117 
118 		if (Status != NDIS_STATUS_SUCCESS) {
119 
120 			//  No free packets
121 			Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
122 			IoCompleteRequest (Irp, IO_NO_INCREMENT);
123 			return STATUS_INSUFFICIENT_RESOURCES;
124 		}
125 
126 		if(Open->SkipSentPackets)
127 		{
128 			NdisSetPacketFlags(
129 				pPacket,
130 				g_SendPacketFlags);
131 		}
132 
133 		// The packet hasn't a buffer that needs not to be freed after every single write
134 		RESERVED(pPacket)->FreeBufAfterWrite = FALSE;
135 
136 		// Save the IRP associated with the packet
137 		RESERVED(pPacket)->Irp=Irp;
138 
139 		//  Attach the writes buffer to the packet
140 		NdisChainBufferAtFront(pPacket,Irp->MdlAddress);
141 
142 		test_addr = MmGetMdlVirtualAddress(Irp->MdlAddress);
143 
144 		//  Call the MAC
145 		NdisSend(
146 			&Status,
147 			Open->AdapterHandle,
148 			pPacket);
149 
150 		if (Status != NDIS_STATUS_PENDING) {
151 			//  The send didn't pend so call the completion handler now
152 			NPF_SendComplete(
153 				Open,
154 				pPacket,
155 				Status
156 				);
157 
158 		}
159 
160 		if(i%100==99){
161 			NdisWaitEvent(&Open->WriteEvent,1000);
162 			NdisResetEvent(&Open->WriteEvent);
163 		}
164 	}
165 
166     return(STATUS_PENDING);
167 }
168 
169 //-------------------------------------------------------------------
170 
171 INT
NPF_BufferedWrite(IN PIRP Irp,IN PCHAR UserBuff,IN ULONG UserBuffSize,BOOLEAN Sync)172 NPF_BufferedWrite(
173 	IN PIRP Irp,
174 	IN PCHAR UserBuff,
175 	IN ULONG UserBuffSize,
176 	BOOLEAN Sync)
177 {
178     POPEN_INSTANCE		Open;
179     PIO_STACK_LOCATION	IrpSp;
180     PNDIS_PACKET		pPacket;
181     NDIS_STATUS		    Status;
182 	struct sf_pkthdr	*winpcap_hdr;
183 	PMDL				TmpMdl;
184 	PCHAR				EndOfUserBuff = UserBuff + UserBuffSize;
185 
186     IF_LOUD(DbgPrint("NPF: BufferedWrite, UserBuff=%x, Size=%u\n", UserBuff, UserBuffSize);)
187 
188 	IrpSp = IoGetCurrentIrpStackLocation(Irp);
189 
190     Open=IrpSp->FileObject->FsContext;
191 
192 	if( Open->Bound == FALSE ){
193 		// The Network adapter was removed.
194 		return 0;
195 	}
196 
197 	// Sanity check on the user buffer
198 	if(UserBuff == NULL)
199 	{
200 		return 0;
201 	}
202 
203 	// Check that the MaxFrameSize is correctly initialized
204 	if(Open->MaxFrameSize == 0)
205 	{
206 		IF_LOUD(DbgPrint("BufferedWrite: Open->MaxFrameSize not initialized, probably because of a problem in the OID query\n");)
207 
208 		return 0;
209 	}
210 
211 	// Reset the event used to synchronize packet allocation
212 	NdisResetEvent(&Open->WriteEvent);
213 
214 	// Reset the pending packets counter
215 	Open->Multiple_Write_Counter = 0;
216 
217 	// Start from the first packet
218 	winpcap_hdr = (struct sf_pkthdr*)UserBuff;
219 
220 	// Check the consistency of the user buffer
221 	if( (PCHAR)winpcap_hdr + winpcap_hdr->caplen + sizeof(struct sf_pkthdr) > EndOfUserBuff )
222 	{
223 		IF_LOUD(DbgPrint("Buffered Write: bogus packet buffer\n");)
224 
225 		return -1;
226 	}
227 
228 	//
229 	// Main loop: send the buffer to the wire
230 	//
231 	while(TRUE)
232 	{
233 
234 		if(winpcap_hdr->caplen ==0/* || winpcap_hdr->caplen > Open->MaxFrameSize*/)
235 		{
236 			// Malformed header
237 			IF_LOUD(DbgPrint("NPF_BufferedWrite: malformed or bogus user buffer, aborting write.\n");)
238 
239 			return -1;
240 		}
241 
242 		// Allocate an MDL to map the packet data
243 		TmpMdl = IoAllocateMdl((PCHAR)winpcap_hdr + sizeof(struct sf_pkthdr),
244 			winpcap_hdr->caplen,
245 			FALSE,
246 			FALSE,
247 			NULL);
248 
249 		if (TmpMdl == NULL)
250 		{
251 			// Unable to map the memory: packet lost
252 			IF_LOUD(DbgPrint("NPF_BufferedWrite: unable to allocate the MDL.\n");)
253 
254 			return -1;
255 		}
256 
257 		MmBuildMdlForNonPagedPool(TmpMdl);	// XXX can this line be removed?
258 
259 		// Allocate a packet from our free list
260 		NdisAllocatePacket( &Status, &pPacket, Open->PacketPool);
261 
262 		if (Status != NDIS_STATUS_SUCCESS) {
263 			//  No more free packets
264 			IF_LOUD(DbgPrint("NPF_BufferedWrite: no more free packets, returning.\n");)
265 
266 			NdisResetEvent(&Open->WriteEvent);
267 
268 			NdisWaitEvent(&Open->WriteEvent, 1000);
269 
270 			// Try again to allocate a packet
271 			NdisAllocatePacket( &Status, &pPacket, Open->PacketPool);
272 
273 			if (Status != NDIS_STATUS_SUCCESS) {
274 				// Second failure, report an error
275 				IoFreeMdl(TmpMdl);
276 				return -1;
277 			}
278 
279 //			IoFreeMdl(TmpMdl);
280 //			return (PCHAR)winpcap_hdr - UserBuff;
281 		}
282 
283 		if(Open->SkipSentPackets)
284 		{
285 			NdisSetPacketFlags(
286 				pPacket,
287 				g_SendPacketFlags);
288 		}
289 
290 		// The packet has a buffer that needs to be freed after every single write
291 		RESERVED(pPacket)->FreeBufAfterWrite = TRUE;
292 
293         TmpMdl->Next = NULL;
294 
295 		// Attach the MDL to the packet
296 		NdisChainBufferAtFront(pPacket, TmpMdl);
297 
298 		// Increment the number of pending sends
299 		InterlockedIncrement(&Open->Multiple_Write_Counter);
300 
301 		// Call the MAC
302 		NdisSend( &Status, Open->AdapterHandle,	pPacket);
303 
304 		if (Status != NDIS_STATUS_PENDING) {
305 			// The send didn't pend so call the completion handler now
306 			NPF_SendComplete(
307 				Open,
308 				pPacket,
309 				Status
310 				);
311 		}
312 
313 		// Step to the next packet in the buffer
314 		(PCHAR)winpcap_hdr += winpcap_hdr->caplen + sizeof(struct sf_pkthdr);
315 
316 		// Check if the end of the user buffer has been reached
317 		if( (PCHAR)winpcap_hdr >= EndOfUserBuff )
318 		{
319 			IF_LOUD(DbgPrint("NPF_BufferedWrite: End of buffer.\n");)
320 
321 			// Wait the completion of pending sends
322 			NPF_WaitEndOfBufferedWrite(Open);
323 
324 			return (INT)((PCHAR)winpcap_hdr - UserBuff);
325 		}
326 
327 	}
328 
329 	return (INT)((PCHAR)winpcap_hdr - UserBuff);
330 }
331 
332 //-------------------------------------------------------------------
333 
NPF_WaitEndOfBufferedWrite(POPEN_INSTANCE Open)334 VOID NPF_WaitEndOfBufferedWrite(POPEN_INSTANCE Open)
335 {
336 	UINT i;
337 
338 	NdisResetEvent(&Open->WriteEvent);
339 
340 	for(i=0; Open->Multiple_Write_Counter > 0 && i < TRANSMIT_PACKETS; i++)
341 	{
342 		NdisWaitEvent(&Open->WriteEvent, 100);
343 		NdisResetEvent(&Open->WriteEvent);
344 	}
345 
346 	return;
347 }
348 
349 //-------------------------------------------------------------------
350 
351 VOID
NPF_SendComplete(IN NDIS_HANDLE ProtocolBindingContext,IN PNDIS_PACKET pPacket,IN NDIS_STATUS Status)352 NPF_SendComplete(
353 				   IN NDIS_HANDLE   ProtocolBindingContext,
354 				   IN PNDIS_PACKET  pPacket,
355 				   IN NDIS_STATUS   Status
356 				   )
357 
358 {
359 	PIRP              Irp;
360 	PIO_STACK_LOCATION  irpSp;
361 	POPEN_INSTANCE      Open;
362 	PMDL TmpMdl;
363 
364 	IF_LOUD(DbgPrint("NPF: SendComplete, BindingContext=%d\n",ProtocolBindingContext);)
365 
366 	Open= (POPEN_INSTANCE)ProtocolBindingContext;
367 
368 	if( RESERVED(pPacket)->FreeBufAfterWrite )
369 	{
370 		//
371 		// Packet sent by NPF_BufferedWrite()
372 		//
373 
374 
375 		// Free the MDL associated with the packet
376 		NdisUnchainBufferAtFront(pPacket, &TmpMdl);
377 
378 		IoFreeMdl(TmpMdl);
379 
380 		//  recyle the packet
381 		//	NdisReinitializePacket(pPacket);
382 
383 		NdisFreePacket(pPacket);
384 
385 		// Increment the number of pending sends
386 		InterlockedDecrement(&Open->Multiple_Write_Counter);
387 
388 		NdisSetEvent(&Open->WriteEvent);
389 
390 		return;
391 	}
392 	else
393 	{
394 		//
395 		// Packet sent by NPF_Write()
396 		//
397 
398 		if((Open->Nwrites - Open->Multiple_Write_Counter) %100 == 99)
399 			NdisSetEvent(&Open->WriteEvent);
400 
401 		Open->Multiple_Write_Counter--;
402 
403 		if(Open->Multiple_Write_Counter == 0){
404 			// Release the buffer and awake the application
405 			NdisUnchainBufferAtFront(pPacket, &TmpMdl);
406 
407 			// Complete the request
408 			Irp=RESERVED(pPacket)->Irp;
409 			irpSp = IoGetCurrentIrpStackLocation(Irp);
410 
411 			Irp->IoStatus.Status = Status;
412 			Irp->IoStatus.Information = irpSp->Parameters.Write.Length;
413 			IoCompleteRequest(Irp, IO_NO_INCREMENT);
414 
415 			NdisAcquireSpinLock(&Open->WriteLock);
416 			Open->WriteInProgress = FALSE;
417 			NdisReleaseSpinLock(&Open->WriteLock);
418 		}
419 
420 		//  Put the packet back on the free list
421 		NdisFreePacket(pPacket);
422 
423 		return;
424 	}
425 
426 }
427