ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Windows/b2ether/nt5/b2ether_read.c
Revision: 1.1
Committed: 2012-04-22T03:13:32Z (12 years, 6 months ago) by asvitkine
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Log Message:
Import nt5 version of the ethernet driver from 2001 sources.

File Contents

# Content
1 /*
2 * b2ether driver -- derived from DDK packet driver sample
3 *
4 * Basilisk II (C) 1997-1999 Christian Bauer
5 *
6 * Windows platform specific code copyright (C) Lauri Pesonen
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23 #include "ntddk.h"
24 #include "ndis.h"
25 #include "b2ether.h"
26
27
28 NTSTATUS PacketRead( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp )
29 {
30 POPEN_INSTANCE open;
31 PNDIS_PACKET pPacket;
32 NDIS_STATUS status;
33 NTSTATUS ntStatus;
34 PIO_STACK_LOCATION irpSp;
35
36 // DebugPrint(("Read\n"));
37
38 open = DeviceObject->DeviceExtension;
39
40 IoIncrement(open);
41
42 if(!open->Bound) {
43 ntStatus = STATUS_DEVICE_NOT_READY;
44 goto ERROR;
45 }
46
47 irpSp = IoGetCurrentIrpStackLocation(Irp);
48
49 if (irpSp->Parameters.Read.Length < ETHERNET_HEADER_LENGTH) {
50 ntStatus = STATUS_BUFFER_TOO_SMALL;
51 goto ERROR;
52 }
53
54 NdisAllocatePacket( &status, &pPacket, open->PacketPool );
55 if (status != NDIS_STATUS_SUCCESS) {
56 // DebugPrint(("Packet: Read- No free packets\n"));
57 ntStatus = STATUS_INSUFFICIENT_RESOURCES;
58 goto ERROR;
59 }
60
61 RESERVED(pPacket)->Irp=Irp;
62 RESERVED(pPacket)->pMdl=NULL;
63 IoMarkIrpPending(Irp);
64
65 IoSetCancelRoutine(Irp, PacketCancelRoutine);
66
67 ExInterlockedInsertTailList(
68 &open->RcvList,
69 &RESERVED(pPacket)->ListElement,
70 &open->RcvQSpinLock);
71
72 return STATUS_PENDING;
73
74 ERROR:
75 Irp->IoStatus.Status = ntStatus;
76 IoCompleteRequest (Irp, IO_NO_INCREMENT);
77 IoDecrement(open);
78 return ntStatus;
79 }
80
81
82
83 NDIS_STATUS
84 PacketReceiveIndicate (
85 IN NDIS_HANDLE ProtocolBindingContext,
86 IN NDIS_HANDLE MacReceiveContext,
87 IN PVOID HeaderBuffer,
88 IN UINT HeaderBufferSize,
89 IN PVOID LookAheadBuffer,
90 IN UINT LookaheadBufferSize,
91 IN UINT PacketSize
92 )
93 {
94 POPEN_INSTANCE open;
95 PIO_STACK_LOCATION irpSp;
96 PIRP irp;
97 PLIST_ENTRY packetListEntry;
98 PNDIS_PACKET pPacket;
99 ULONG sizeToTransfer;
100 NDIS_STATUS status;
101 UINT bytesTransfered = 0;
102 ULONG bufferLength;
103 PPACKET_RESERVED reserved;
104 PMDL pMdl;
105
106 // DebugPrint(("ReceiveIndicate\n"));
107
108 open= (POPEN_INSTANCE)ProtocolBindingContext;
109
110 if (HeaderBufferSize > ETHERNET_HEADER_LENGTH) {
111 return NDIS_STATUS_SUCCESS;
112 }
113
114 // See if there are any pending read that we can satisfy
115 packetListEntry = ExInterlockedRemoveHeadList( &open->RcvList, &open->RcvQSpinLock );
116
117 if (packetListEntry == NULL) {
118 // DebugPrint(("No pending read, dropping packets\n"));
119 return NDIS_STATUS_NOT_ACCEPTED;
120 }
121
122 reserved = CONTAINING_RECORD(packetListEntry,PACKET_RESERVED,ListElement);
123 pPacket = CONTAINING_RECORD(reserved,NDIS_PACKET,ProtocolReserved);
124
125 irp = RESERVED(pPacket)->Irp;
126 irpSp = IoGetCurrentIrpStackLocation(irp);
127
128 // We don't have to worry about the situation where the IRP is cancelled
129 // after we remove it from the queue and before we reset the cancel
130 // routine because the cancel routine has been coded to cancel an IRP
131 // only if it's in the queue.
132
133 IoSetCancelRoutine(irp, NULL);
134
135 bufferLength = irpSp->Parameters.Read.Length-ETHERNET_HEADER_LENGTH;
136
137 sizeToTransfer = (PacketSize < bufferLength) ? PacketSize : bufferLength;
138
139 NdisMoveMappedMemory(
140 MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority),
141 HeaderBuffer,
142 HeaderBufferSize
143 );
144
145 pMdl=IoAllocateMdl(
146 MmGetMdlVirtualAddress(irp->MdlAddress),
147 MmGetMdlByteCount(irp->MdlAddress),
148 FALSE,
149 FALSE,
150 NULL
151 );
152
153 if (pMdl == NULL) {
154 // DebugPrint(("Packet: Read-Failed to allocate Mdl\n"));
155 status = NDIS_STATUS_RESOURCES;
156 goto ERROR;
157 }
158
159 IoBuildPartialMdl(
160 irp->MdlAddress,
161 pMdl,
162 ((PUCHAR)MmGetMdlVirtualAddress(irp->MdlAddress))+ETHERNET_HEADER_LENGTH,
163 0
164 );
165
166 pMdl->Next = NULL;
167
168 RESERVED(pPacket)->pMdl=pMdl;
169
170 NdisChainBufferAtFront(pPacket,pMdl);
171
172 NdisTransferData(
173 &status,
174 open->AdapterHandle,
175 MacReceiveContext,
176 0,
177 sizeToTransfer,
178 pPacket,
179 &bytesTransfered
180 );
181
182 if (status == NDIS_STATUS_PENDING) {
183 return NDIS_STATUS_SUCCESS;
184 }
185
186 ERROR:
187 PacketTransferDataComplete( open, pPacket, status, bytesTransfered );
188 return NDIS_STATUS_SUCCESS;
189 }
190
191
192 VOID
193 PacketTransferDataComplete (
194 IN NDIS_HANDLE ProtocolBindingContext,
195 IN PNDIS_PACKET pPacket,
196 IN NDIS_STATUS Status,
197 IN UINT BytesTransfered
198 )
199 {
200 PIO_STACK_LOCATION irpSp;
201 POPEN_INSTANCE open;
202 PIRP irp;
203 PMDL pMdl;
204
205 // DebugPrint(("Packet: TransferDataComplete\n"));
206
207 open = (POPEN_INSTANCE)ProtocolBindingContext;
208 irp = RESERVED(pPacket)->Irp;
209 irpSp = IoGetCurrentIrpStackLocation(irp);
210 pMdl = RESERVED(pPacket)->pMdl;
211
212
213 if(pMdl) IoFreeMdl(pMdl);
214
215 NdisFreePacket(pPacket);
216
217 if(Status == NDIS_STATUS_SUCCESS) {
218 irp->IoStatus.Status = STATUS_SUCCESS;
219 irp->IoStatus.Information = BytesTransfered+ETHERNET_HEADER_LENGTH;
220 } else {
221 irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
222 irp->IoStatus.Information = 0;
223 }
224
225 // DebugPrint(("BytesTransfered:%d\n", irp->IoStatus.Information));
226
227 IoCompleteRequest(irp, IO_NO_INCREMENT);
228 IoDecrement(open);
229 }
230
231 VOID PacketReceiveComplete( IN NDIS_HANDLE ProtocolBindingContext )
232 {
233 }
234
235 INT
236 PacketReceivePacket(
237 IN NDIS_HANDLE ProtocolBindingContext,
238 IN PNDIS_PACKET Packet
239 )
240 {
241 UINT bytesTransfered = 0;
242 POPEN_INSTANCE open;
243 PIRP irp;
244 PNDIS_PACKET myPacket;
245 PLIST_ENTRY packetListEntry;
246 ULONG bufferLength;
247 PPACKET_RESERVED reserved;
248 PIO_STACK_LOCATION irpSp;
249 PMDL mdl;
250 PVOID startAddress;
251 NTSTATUS status;
252
253 // DebugPrint(("PacketReceivePacket\n"));
254
255 open = (POPEN_INSTANCE)ProtocolBindingContext;
256
257 packetListEntry = ExInterlockedRemoveHeadList(
258 &open->RcvList,
259 &open->RcvQSpinLock
260 );
261
262 if (packetListEntry == NULL) {
263 // DebugPrint(("No pending read, dropping packets\n"));
264 return 0;
265 }
266
267 reserved = CONTAINING_RECORD(packetListEntry,PACKET_RESERVED,ListElement);
268 myPacket = CONTAINING_RECORD(reserved,NDIS_PACKET,ProtocolReserved);
269
270 irp = RESERVED(myPacket)->Irp;
271 irpSp = IoGetCurrentIrpStackLocation(irp);
272
273 // We don't have to worry about the situation where the IRP is cancelled
274 // after we remove it from the queue and before we reset the cancel
275 // routine because the cancel routine has been coded to cancel an IRP
276 // only if it's in the queue.
277
278 IoSetCancelRoutine(irp, NULL);
279
280 // Following block of code locks the destination packet
281 // MDLs in a safe manner. This is a temporary workaround
282 // for NdisCopyFromPacketToPacket that currently doesn't use
283 // safe functions to lock pages of MDL. This is required to
284 // prevent system from bugchecking under low memory resources.
285 //
286 {
287 PVOID virtualAddress;
288 PNDIS_BUFFER firstBuffer, nextBuffer;
289 ULONG totalLength;
290
291 NdisQueryPacket(Packet, NULL, NULL, &firstBuffer, &totalLength);
292 while( firstBuffer ) {
293 NdisQueryBufferSafe( firstBuffer, &virtualAddress, &totalLength, NormalPagePriority );
294 if(!virtualAddress) {
295 status = STATUS_INSUFFICIENT_RESOURCES;
296 goto CleanExit;
297 }
298 NdisGetNextBuffer(firstBuffer, &nextBuffer);
299 firstBuffer = nextBuffer;
300 }
301 }
302
303 NdisChainBufferAtFront( myPacket, irp->MdlAddress );
304 bufferLength=irpSp->Parameters.Read.Length;
305 NdisCopyFromPacketToPacket( myPacket, 0, bufferLength, Packet, 0, &bytesTransfered );
306
307 CleanExit:
308 NdisFreePacket(myPacket);
309 irp->IoStatus.Status = status;
310 irp->IoStatus.Information = bytesTransfered;
311 IoCompleteRequest(irp, IO_NO_INCREMENT);
312 // DebugPrint(("BytesTransfered:%d\n", bytesTransfered));
313 IoDecrement(open);
314 return 0;
315 }
316
317
318 VOID
319 PacketCancelRoutine (
320 IN PDEVICE_OBJECT DeviceObject,
321 IN PIRP Irp
322 )
323
324 {
325 POPEN_INSTANCE open = DeviceObject->DeviceExtension;
326 KIRQL oldIrql;
327 PIRP irpToComplete = NULL;
328 PLIST_ENTRY thisEntry, listHead;
329 PIRP pendingIrp;
330 PNDIS_PACKET myPacket = NULL;
331 PPACKET_RESERVED reserved;
332 PMDL mdl;
333
334 // Don't assume that the IRP being cancelled is in the queue.
335 // Only complete the IRP if it IS in the queue.
336 //
337 // Must acquire the local spinlock before releasing
338 // the global cancel spinlock
339 //
340 // DebugPrint(("PacketCancelRoutine\n"));
341
342 oldIrql = Irp->CancelIrql;
343
344 // One should not intermix KeAcquireSpinLock(AtDpcLevel)
345 // and ExInterlocked...List() functions on the same spinlock if the
346 // routines that use the lock run at IRQL > DISPATCH_LEVEL.
347 // After acquiring the lock using Ke function, if we got interrupted
348 // and entered into an ISR and tried to manipulate the list using
349 // ExInterlocked...List function with the same lock, we deadlock.
350 // In this sample we can safely do that because none of our routines
351 // will be called at IRQL > DISPATCH_LEVEL.
352
353 KeAcquireSpinLockAtDpcLevel(&open->RcvQSpinLock);
354 IoReleaseCancelSpinLock( KeGetCurrentIrql() );
355
356 listHead = &open->RcvList;
357 for( thisEntry = listHead->Flink; thisEntry != listHead; thisEntry = thisEntry->Flink ) {
358 reserved=CONTAINING_RECORD(thisEntry,PACKET_RESERVED,ListElement);
359 myPacket=CONTAINING_RECORD(reserved,NDIS_PACKET,ProtocolReserved);
360 pendingIrp = RESERVED(myPacket)->Irp;
361 if (pendingIrp == Irp) {
362 RemoveEntryList(thisEntry);
363 irpToComplete = pendingIrp;
364 break;
365 }
366 }
367
368 KeReleaseSpinLock(&open->RcvQSpinLock, oldIrql);
369
370 if(irpToComplete) {
371 // DebugPrint(("Cancelling IRP\n"));
372 // ASSERT(myPacket);
373
374 NdisFreePacket(myPacket);
375
376 irpToComplete->IoStatus.Status = STATUS_CANCELLED;
377 irpToComplete->IoStatus.Information = 0;
378 IoCompleteRequest(irpToComplete, IO_NO_INCREMENT);
379 IoDecrement(open);
380 }
381 }
382
383
384 NTSTATUS PacketCancelReadIrps( IN PDEVICE_OBJECT DeviceObject )
385 {
386 POPEN_INSTANCE open = DeviceObject->DeviceExtension;
387 PLIST_ENTRY thisEntry;
388 PIRP pendingIrp;
389 PNDIS_PACKET myPacket = NULL;
390 PPACKET_RESERVED reserved;
391 PMDL mdl;
392
393 // DebugPrint(("PacketCancelReadIrps\n"));
394
395 // Walk through the RcvList and cancel all read IRPs.
396
397 while( thisEntry = ExInterlockedRemoveHeadList( &open->RcvList, &open->RcvQSpinLock )) {
398 reserved=CONTAINING_RECORD(thisEntry,PACKET_RESERVED,ListElement);
399 myPacket=CONTAINING_RECORD(reserved,NDIS_PACKET,ProtocolReserved);
400
401 ASSERT(myPacket);
402
403 pendingIrp = RESERVED(myPacket)->Irp;
404
405 NdisFreePacket(myPacket);
406
407 // DebugPrint(("Cancelled : 0%0x\n", pendingIrp));
408
409 IoSetCancelRoutine(pendingIrp, NULL);
410
411 pendingIrp->IoStatus.Information = 0;
412 pendingIrp->IoStatus.Status = STATUS_CANCELLED;
413 IoCompleteRequest(pendingIrp, IO_NO_INCREMENT);
414 IoDecrement(open);
415 }
416
417 return STATUS_SUCCESS;
418 }