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