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

# User Rev Content
1 asvitkine 1.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     }