- Call the ProtocolReceive handler at DISPATCH_LEVEL
[reactos.git] / drivers / network / ndis / ndis / miniport.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS NDIS library
4 * FILE: ndis/miniport.c
5 * PURPOSE: Routines used by NDIS miniport drivers
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * Vizzini (vizzini@plasmic.com)
8 * REVISIONS:
9 * CSH 01/08-2000 Created
10 * 20 Aug 2003 vizzini - DMA support
11 * 3 Oct 2003 vizzini - SendPackets support
12 */
13
14 #include "ndissys.h"
15 #include "efilter.h"
16
17 #ifdef DBG
18 #include <buffer.h>
19 #endif /* DBG */
20
21 #undef NdisMSendComplete
22 VOID
23 EXPORT
24 NdisMSendComplete(
25 IN NDIS_HANDLE MiniportAdapterHandle,
26 IN PNDIS_PACKET Packet,
27 IN NDIS_STATUS Status);
28
29 /* Root of the scm database */
30 #define SERVICES_ROOT L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"
31
32 /*
33 * Define to 1 to get a debugger breakpoint at the end of NdisInitializeWrapper
34 * for each new miniport starting up
35 */
36 #define BREAK_ON_MINIPORT_INIT 0
37
38 /*
39 * This has to be big enough to hold the results of querying the Route value
40 * from the Linkage key. Please re-code me to determine this dynamically.
41 */
42 #define ROUTE_DATA_SIZE 256
43
44 /* Number of media we know */
45 #define MEDIA_ARRAY_SIZE 15
46
47 static NDIS_MEDIUM MediaArray[MEDIA_ARRAY_SIZE] =
48 {
49 NdisMedium802_3,
50 NdisMedium802_5,
51 NdisMediumFddi,
52 NdisMediumWan,
53 NdisMediumLocalTalk,
54 NdisMediumDix,
55 NdisMediumArcnetRaw,
56 NdisMediumArcnet878_2,
57 NdisMediumAtm,
58 NdisMediumWirelessWan,
59 NdisMediumIrda,
60 NdisMediumBpc,
61 NdisMediumCoWan,
62 NdisMedium1394,
63 NdisMediumMax
64 };
65
66 /* global list and lock of Miniports NDIS has registered */
67 LIST_ENTRY MiniportListHead;
68 KSPIN_LOCK MiniportListLock;
69
70 /* global list and lock of adapters NDIS has registered */
71 LIST_ENTRY AdapterListHead;
72 KSPIN_LOCK AdapterListLock;
73
74 VOID
75 MiniDisplayPacket(
76 PNDIS_PACKET Packet)
77 {
78 #ifdef DBG
79 ULONG i, Length;
80 UCHAR Buffer[64];
81 if ((DebugTraceLevel & DEBUG_PACKET) > 0) {
82 Length = CopyPacketToBuffer(
83 Buffer,
84 Packet,
85 0,
86 64);
87
88 DbgPrint("*** PACKET START ***");
89
90 for (i = 0; i < Length; i++) {
91 if (i % 12 == 0)
92 DbgPrint("\n%04X ", i);
93 DbgPrint("%02X ", Buffer[i]);
94 }
95
96 DbgPrint("*** PACKET STOP ***\n");
97 }
98 #endif /* DBG */
99 }
100
101 VOID
102 MiniDisplayPacket2(
103 PVOID HeaderBuffer,
104 UINT HeaderBufferSize,
105 PVOID LookaheadBuffer,
106 UINT LookaheadBufferSize)
107 {
108 #ifdef DBG
109 if ((DebugTraceLevel & DEBUG_PACKET) > 0) {
110 ULONG i, Length;
111 PUCHAR p;
112
113 DbgPrint("*** RECEIVE PACKET START ***\n");
114 DbgPrint("HEADER:");
115 p = HeaderBuffer;
116 for (i = 0; i < HeaderBufferSize; i++) {
117 if (i % 16 == 0)
118 DbgPrint("\n%04X ", i);
119 DbgPrint("%02X ", *p++);
120 }
121
122 DbgPrint("\nFRAME:");
123
124 p = LookaheadBuffer;
125 Length = (LookaheadBufferSize < 64)? LookaheadBufferSize : 64;
126 for (i = 0; i < Length; i++) {
127 if (i % 16 == 0)
128 DbgPrint("\n%04X ", i);
129 DbgPrint("%02X ", *p++);
130 }
131
132 DbgPrint("\n*** RECEIVE PACKET STOP ***\n");
133 }
134 #endif /* DBG */
135 }
136
137 \f
138 VOID
139 MiniIndicateData(
140 PLOGICAL_ADAPTER Adapter,
141 NDIS_HANDLE MacReceiveContext,
142 PVOID HeaderBuffer,
143 UINT HeaderBufferSize,
144 PVOID LookaheadBuffer,
145 UINT LookaheadBufferSize,
146 UINT PacketSize)
147 /*
148 * FUNCTION: Indicate received data to bound protocols
149 * ARGUMENTS:
150 * Adapter = Pointer to logical adapter
151 * MacReceiveContext = MAC receive context handle
152 * HeaderBuffer = Pointer to header buffer
153 * HeaderBufferSize = Size of header buffer
154 * LookaheadBuffer = Pointer to lookahead buffer
155 * LookaheadBufferSize = Size of lookahead buffer
156 * PacketSize = Total size of received packet
157 */
158 {
159 KIRQL OldIrql;
160 PLIST_ENTRY CurrentEntry;
161 PADAPTER_BINDING AdapterBinding;
162
163 NDIS_DbgPrint(DEBUG_MINIPORT, ("Called. Adapter (0x%X) HeaderBuffer (0x%X) "
164 "HeaderBufferSize (0x%X) LookaheadBuffer (0x%X) LookaheadBufferSize (0x%X).\n",
165 Adapter, HeaderBuffer, HeaderBufferSize, LookaheadBuffer, LookaheadBufferSize));
166
167 MiniDisplayPacket2(HeaderBuffer, HeaderBufferSize, LookaheadBuffer, LookaheadBufferSize);
168
169 NDIS_DbgPrint(MAX_TRACE, ("acquiring miniport block lock\n"));
170 KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
171 {
172 CurrentEntry = Adapter->ProtocolListHead.Flink;
173 NDIS_DbgPrint(DEBUG_MINIPORT, ("CurrentEntry = %x\n", CurrentEntry));
174
175 if (CurrentEntry == &Adapter->ProtocolListHead)
176 {
177 NDIS_DbgPrint(DEBUG_MINIPORT, ("WARNING: No upper protocol layer.\n"));
178 }
179
180 while (CurrentEntry != &Adapter->ProtocolListHead)
181 {
182 AdapterBinding = CONTAINING_RECORD(CurrentEntry, ADAPTER_BINDING, AdapterListEntry);
183 NDIS_DbgPrint(DEBUG_MINIPORT, ("AdapterBinding = %x\n", AdapterBinding));
184
185 #ifdef DBG
186 if(!AdapterBinding)
187 {
188 NDIS_DbgPrint(MIN_TRACE, ("AdapterBinding was null\n"));
189 break;
190 }
191
192 if(!AdapterBinding->ProtocolBinding)
193 {
194 NDIS_DbgPrint(MIN_TRACE, ("AdapterBinding->ProtocolBinding was null\n"));
195 break;
196 }
197
198 if(!AdapterBinding->ProtocolBinding->Chars.ReceiveHandler)
199 {
200 NDIS_DbgPrint(MIN_TRACE, ("AdapterBinding->ProtocolBinding->Chars.ReceiveHandler was null\n"));
201 break;
202 }
203 #endif
204
205 NDIS_DbgPrint
206 (MID_TRACE,
207 ("XXX (%x) %x %x %x %x %x %x %x XXX\n",
208 *AdapterBinding->ProtocolBinding->Chars.ReceiveHandler,
209 AdapterBinding->NdisOpenBlock.ProtocolBindingContext,
210 MacReceiveContext,
211 HeaderBuffer,
212 HeaderBufferSize,
213 LookaheadBuffer,
214 LookaheadBufferSize,
215 PacketSize));
216
217 /* call the receive handler */
218 (*AdapterBinding->ProtocolBinding->Chars.ReceiveHandler)(
219 AdapterBinding->NdisOpenBlock.ProtocolBindingContext,
220 MacReceiveContext,
221 HeaderBuffer,
222 HeaderBufferSize,
223 LookaheadBuffer,
224 LookaheadBufferSize,
225 PacketSize);
226
227 CurrentEntry = CurrentEntry->Flink;
228 }
229 }
230 KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
231
232 NDIS_DbgPrint(MAX_TRACE, ("Leaving.\n"));
233 }
234
235 \f
236 VOID NTAPI
237 MiniIndicateReceivePacket(
238 IN NDIS_HANDLE Miniport,
239 IN PPNDIS_PACKET PacketArray,
240 IN UINT NumberOfPackets)
241 /*
242 * FUNCTION: receives miniport packet array indications
243 * ARGUMENTS:
244 * Miniport: Miniport handle for the adapter
245 * PacketArray: pointer to a list of packet pointers to indicate
246 * NumberOfPackets: number of packets to indicate
247 * NOTES:
248 * - This currently is a big temporary hack. In the future this should
249 * call ProtocolReceivePacket() on each bound protocol if it exists.
250 * For now it just mimics NdisMEthIndicateReceive.
251 */
252 {
253 UINT i;
254
255 for(i = 0; i < NumberOfPackets; i++)
256 {
257 PCHAR PacketBuffer = 0;
258 UINT PacketLength = 0;
259 PNDIS_BUFFER NdisBuffer = 0;
260
261 #define PACKET_TAG (('k' << 24) + ('P' << 16) + ('D' << 8) + 'N')
262
263 NdisAllocateMemoryWithTag((PVOID)&PacketBuffer, 1518, PACKET_TAG);
264 if(!PacketBuffer)
265 {
266 NDIS_DbgPrint(MIN_TRACE, ("insufficient resources\n"));
267 return;
268 }
269
270 NdisQueryPacket(PacketArray[i], NULL, NULL, &NdisBuffer, NULL);
271
272 while(NdisBuffer)
273 {
274 PNDIS_BUFFER CurrentBuffer;
275 PVOID BufferVa;
276 UINT BufferLen;
277
278 NdisQueryBuffer(NdisBuffer, &BufferVa, &BufferLen);
279 memcpy(PacketBuffer + PacketLength, BufferVa, BufferLen);
280 PacketLength += BufferLen;
281
282 CurrentBuffer = NdisBuffer;
283 NdisGetNextBuffer(CurrentBuffer, &NdisBuffer);
284 }
285
286 NDIS_DbgPrint(MID_TRACE, ("indicating a %d-byte packet\n", PacketLength));
287
288 MiniIndicateData(Miniport, NULL, PacketBuffer, 14, PacketBuffer+14, PacketLength-14, PacketLength-14);
289
290 NdisFreeMemory(PacketBuffer, 0, 0);
291 }
292 }
293
294 \f
295 VOID NTAPI
296 MiniResetComplete(
297 IN NDIS_HANDLE MiniportAdapterHandle,
298 IN NDIS_STATUS Status,
299 IN BOOLEAN AddressingReset)
300 {
301 UNIMPLEMENTED
302 }
303
304
305 \f
306 VOID NTAPI
307 MiniRequestComplete(
308 IN PNDIS_HANDLE MiniportAdapterHandle,
309 IN PNDIS_REQUEST Request,
310 IN NDIS_STATUS Status)
311 {
312 PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)MiniportAdapterHandle;
313 PNDIS_REQUEST_MAC_BLOCK MacBlock = (PNDIS_REQUEST_MAC_BLOCK)Request->MacReserved;
314 KIRQL OldIrql;
315
316 NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
317
318 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
319 if( MacBlock->Binding->RequestCompleteHandler ) {
320 (*MacBlock->Binding->RequestCompleteHandler)(
321 MacBlock->Binding->ProtocolBindingContext,
322 Request,
323 Status);
324 }
325 KeAcquireSpinLockAtDpcLevel(&Adapter->NdisMiniportBlock.Lock);
326 Adapter->MiniportBusy = FALSE;
327 KeReleaseSpinLockFromDpcLevel(&Adapter->NdisMiniportBlock.Lock);
328 KeLowerIrql(OldIrql);
329 }
330
331 VOID NTAPI
332 MiniSendComplete(
333 IN NDIS_HANDLE MiniportAdapterHandle,
334 IN PNDIS_PACKET Packet,
335 IN NDIS_STATUS Status)
336 /*
337 * FUNCTION: Forwards a message to the initiating protocol saying
338 * that a packet was handled
339 * ARGUMENTS:
340 * NdisAdapterHandle = Handle input to MiniportInitialize
341 * Packet = Pointer to NDIS packet that was sent
342 * Status = Status of send operation
343 */
344 {
345 PLOGICAL_ADAPTER Adapter = MiniportAdapterHandle;
346 PADAPTER_BINDING AdapterBinding;
347 KIRQL OldIrql;
348
349 NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
350
351 AdapterBinding = (PADAPTER_BINDING)Packet->Reserved[0];
352
353 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
354 (*AdapterBinding->ProtocolBinding->Chars.SendCompleteHandler)(
355 AdapterBinding->NdisOpenBlock.ProtocolBindingContext,
356 Packet,
357 Status);
358 KeAcquireSpinLockAtDpcLevel(&Adapter->NdisMiniportBlock.Lock);
359 Adapter->MiniportBusy = FALSE;
360 KeReleaseSpinLockFromDpcLevel(&Adapter->NdisMiniportBlock.Lock);
361 KeLowerIrql(OldIrql);
362 }
363
364
365 VOID NTAPI
366 MiniSendResourcesAvailable(
367 IN NDIS_HANDLE MiniportAdapterHandle)
368 {
369 /*
370 UNIMPLEMENTED
371 */
372 }
373
374
375 VOID NTAPI
376 MiniTransferDataComplete(
377 IN NDIS_HANDLE MiniportAdapterHandle,
378 IN PNDIS_PACKET Packet,
379 IN NDIS_STATUS Status,
380 IN UINT BytesTransferred)
381 {
382 PLOGICAL_ADAPTER Adapter = MiniportAdapterHandle;
383 PADAPTER_BINDING AdapterBinding;
384 KIRQL OldIrql;
385
386 NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
387
388 AdapterBinding = (PADAPTER_BINDING)Packet->Reserved[0];
389
390 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
391 (*AdapterBinding->ProtocolBinding->Chars.SendCompleteHandler)(
392 AdapterBinding->NdisOpenBlock.ProtocolBindingContext,
393 Packet,
394 Status);
395 KeAcquireSpinLockAtDpcLevel(&Adapter->NdisMiniportBlock.Lock);
396 Adapter->MiniportBusy = FALSE;
397 KeReleaseSpinLockFromDpcLevel(&Adapter->NdisMiniportBlock.Lock);
398 KeLowerIrql(OldIrql);
399 }
400
401 \f
402 BOOLEAN
403 MiniAdapterHasAddress(
404 PLOGICAL_ADAPTER Adapter,
405 PNDIS_PACKET Packet)
406 /*
407 * FUNCTION: Determines whether a packet has the same destination address as an adapter
408 * ARGUMENTS:
409 * Adapter = Pointer to logical adapter object
410 * Packet = Pointer to NDIS packet
411 * RETURNS:
412 * TRUE if the destination address is that of the adapter, FALSE if not
413 */
414 {
415 UINT Length;
416 PUCHAR Start1;
417 PUCHAR Start2;
418 PNDIS_BUFFER NdisBuffer;
419 UINT BufferLength;
420
421 NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
422
423 #ifdef DBG
424 if(!Adapter)
425 {
426 NDIS_DbgPrint(MID_TRACE, ("Adapter object was null\n"));
427 return FALSE;
428 }
429
430 if(!Packet)
431 {
432 NDIS_DbgPrint(MID_TRACE, ("Packet was null\n"));
433 return FALSE;
434 }
435 #endif
436
437 NdisQueryPacket(Packet, NULL, NULL, &NdisBuffer, NULL);
438
439 if (!NdisBuffer)
440 {
441 NDIS_DbgPrint(MID_TRACE, ("Packet contains no buffers.\n"));
442 return FALSE;
443 }
444
445 NdisQueryBuffer(NdisBuffer, (PVOID)&Start2, &BufferLength);
446
447 /* FIXME: Should handle fragmented packets */
448
449 switch (Adapter->NdisMiniportBlock.MediaType)
450 {
451 case NdisMedium802_3:
452 Length = ETH_LENGTH_OF_ADDRESS;
453 /* Destination address is the first field */
454 break;
455
456 default:
457 NDIS_DbgPrint(MIN_TRACE, ("Adapter has unsupported media type (0x%X).\n", Adapter->NdisMiniportBlock.MediaType));
458 return FALSE;
459 }
460
461 if (BufferLength < Length)
462 {
463 NDIS_DbgPrint(MID_TRACE, ("Buffer is too small.\n"));
464 return FALSE;
465 }
466
467 Start1 = (PUCHAR)&Adapter->Address;
468 NDIS_DbgPrint(MAX_TRACE, ("packet address: %x:%x:%x:%x:%x:%x adapter address: %x:%x:%x:%x:%x:%x\n",
469 *((char *)Start1), *(((char *)Start1)+1), *(((char *)Start1)+2), *(((char *)Start1)+3), *(((char *)Start1)+4), *(((char *)Start1)+5),
470 *((char *)Start2), *(((char *)Start2)+1), *(((char *)Start2)+2), *(((char *)Start2)+3), *(((char *)Start2)+4), *(((char *)Start2)+5))
471 );
472
473 return (RtlCompareMemory((PVOID)Start1, (PVOID)Start2, Length) == Length);
474 }
475
476 \f
477 PLOGICAL_ADAPTER
478 MiniLocateDevice(
479 PNDIS_STRING AdapterName)
480 /*
481 * FUNCTION: Finds an adapter object by name
482 * ARGUMENTS:
483 * AdapterName = Pointer to name of adapter
484 * RETURNS:
485 * Pointer to logical adapter object, or NULL if none was found.
486 * If found, the adapter is referenced for the caller. The caller
487 * is responsible for dereferencing after use
488 */
489 {
490 KIRQL OldIrql;
491 PLIST_ENTRY CurrentEntry;
492 PLOGICAL_ADAPTER Adapter = 0;
493
494 ASSERT(AdapterName);
495
496 NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
497
498 if(IsListEmpty(&AdapterListHead))
499 {
500 NDIS_DbgPrint(DEBUG_MINIPORT, ("No registered miniports for protocol to bind to\n"));
501 return NULL;
502 }
503
504 KeAcquireSpinLock(&AdapterListLock, &OldIrql);
505 {
506 CurrentEntry = AdapterListHead.Flink;
507
508 while (CurrentEntry != &AdapterListHead)
509 {
510 Adapter = CONTAINING_RECORD(CurrentEntry, LOGICAL_ADAPTER, ListEntry);
511
512 ASSERT(Adapter);
513
514 NDIS_DbgPrint(DEBUG_MINIPORT, ("Examining adapter 0x%lx\n", Adapter));
515 NDIS_DbgPrint(DEBUG_MINIPORT, ("AdapterName = %wZ\n", AdapterName));
516 NDIS_DbgPrint(DEBUG_MINIPORT, ("DeviceName = %wZ\n", &Adapter->NdisMiniportBlock.MiniportName));
517
518 if (RtlCompareUnicodeString(AdapterName, &Adapter->NdisMiniportBlock.MiniportName, TRUE) == 0)
519 {
520 break;
521 }
522
523 Adapter = NULL;
524 CurrentEntry = CurrentEntry->Flink;
525 }
526 }
527 KeReleaseSpinLock(&AdapterListLock, OldIrql);
528
529 if(Adapter)
530 {
531 NDIS_DbgPrint(DEBUG_MINIPORT, ("Leaving. Adapter found at 0x%x\n", Adapter));
532 }
533 else
534 {
535 NDIS_DbgPrint(DEBUG_MINIPORT, ("Leaving (adapter not found).\n"));
536 }
537
538 return Adapter;
539 }
540
541 \f
542 NDIS_STATUS
543 MiniQueryInformation(
544 PLOGICAL_ADAPTER Adapter,
545 NDIS_OID Oid,
546 ULONG Size,
547 PVOID Buffer,
548 PULONG BytesWritten)
549 /*
550 * FUNCTION: Queries a logical adapter for properties
551 * ARGUMENTS:
552 * Adapter = Pointer to the logical adapter object to query
553 * Oid = Specifies the Object ID to query for
554 * Size = Size of the passed buffer
555 * Buffer = Buffer for the output
556 * BytesWritten = Address of buffer to place number of bytes written
557 * NOTES:
558 * If the specified buffer is too small, a new buffer is allocated,
559 * and the query is attempted again
560 * RETURNS:
561 * Status of operation
562 * TODO:
563 * Is there any way to use the buffer provided by the protocol?
564 */
565 {
566 NDIS_STATUS NdisStatus;
567 ULONG BytesNeeded;
568 KIRQL OldIrql;
569
570 NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
571
572 /* call the miniport's queryinfo handler */
573 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
574 NdisStatus = (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.QueryInformationHandler)(
575 Adapter->NdisMiniportBlock.MiniportAdapterContext,
576 Oid,
577 Buffer,
578 Size,
579 BytesWritten,
580 &BytesNeeded);
581 KeLowerIrql(OldIrql);
582
583 /* FIXME: Wait in pending case! */
584
585 return NdisStatus;
586 }
587
588 BOOLEAN
589 MiniCheckForHang( PLOGICAL_ADAPTER Adapter )
590 /*
591 * FUNCTION: Checks to see if the miniport is hung
592 * ARGUMENTS:
593 * Adapter = Pointer to the logical adapter object
594 * RETURNS:
595 * TRUE if the miniport is hung
596 * FALSE if the miniport is not hung
597 */
598 {
599 BOOLEAN Ret = FALSE;
600 KIRQL OldIrql;
601
602 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
603 if (Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.CheckForHangHandler)
604 Ret = (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.CheckForHangHandler)(
605 Adapter->NdisMiniportBlock.MiniportAdapterContext);
606 KeLowerIrql(OldIrql);
607
608 return Ret;
609 }
610
611 NDIS_STATUS
612 MiniReset(
613 PLOGICAL_ADAPTER Adapter,
614 PBOOLEAN AddressingReset)
615 /*
616 * FUNCTION: Resets the miniport
617 * ARGUMENTS:
618 * Adapter = Pointer to the logical adapter object
619 * AddressingReset = Set to TRUE if we need to call MiniportSetInformation later
620 * RETURNS:
621 * Status of the operation
622 */
623 {
624 NDIS_STATUS Status;
625 KIRQL OldIrql;
626
627 if (Adapter->MiniportBusy) {
628 KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
629 MiniQueueWorkItem(Adapter, NdisWorkItemResetRequested, NULL);
630 KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
631 return NDIS_STATUS_PENDING;
632 }
633
634 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
635 Status = (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.ResetHandler)(
636 Adapter->NdisMiniportBlock.MiniportAdapterContext,
637 AddressingReset);
638 KeLowerIrql(OldIrql);
639
640 return Status;
641 }
642
643 VOID STDCALL
644 MiniportHangDpc(
645 PKDPC Dpc,
646 PVOID DeferredContext,
647 PVOID SystemArgument1,
648 PVOID SystemArgument2)
649 {
650 PLOGICAL_ADAPTER Adapter = DeferredContext;
651 BOOLEAN AddressingReset = FALSE;
652
653
654 if (MiniCheckForHang(Adapter)) {
655 NDIS_DbgPrint(MIN_TRACE, ("Miniport detected adapter hang\n"));
656 MiniReset(Adapter, &AddressingReset);
657 }
658
659 /* FIXME: We should call MiniportSetInformation if AddressingReset is TRUE */
660 }
661
662 \f
663 NDIS_STATUS
664 FASTCALL
665 MiniQueueWorkItem(
666 PLOGICAL_ADAPTER Adapter,
667 NDIS_WORK_ITEM_TYPE WorkItemType,
668 PVOID WorkItemContext)
669 /*
670 * FUNCTION: Queues a work item for execution at a later time
671 * ARGUMENTS:
672 * Adapter = Pointer to the logical adapter object to queue work item on
673 * WorkItemType = Type of work item to queue
674 * WorkItemContext = Pointer to context information for work item
675 * NOTES:
676 * Adapter lock must be held when called
677 * RETURNS:
678 * Status of operation
679 */
680 {
681 PNDIS_MINIPORT_WORK_ITEM Item;
682
683 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
684
685 ASSERT(Adapter);
686 ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL);
687
688 Item = ExAllocatePool(NonPagedPool, sizeof(NDIS_MINIPORT_WORK_ITEM));
689 if (Item == NULL)
690 {
691 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
692 return NDIS_STATUS_RESOURCES;
693 }
694
695 Item->WorkItemType = WorkItemType;
696 Item->WorkItemContext = WorkItemContext;
697
698 /* safe due to adapter lock held */
699 Item->Link.Next = NULL;
700 if (!Adapter->WorkQueueHead)
701 {
702 Adapter->WorkQueueHead = Item;
703 Adapter->WorkQueueTail = Item;
704 }
705 else
706 {
707 Adapter->WorkQueueTail->Link.Next = (PSINGLE_LIST_ENTRY)Item;
708 Adapter->WorkQueueTail = Item;
709 }
710
711 KeInsertQueueDpc(&Adapter->NdisMiniportBlock.DeferredDpc, NULL, NULL);
712
713 return NDIS_STATUS_SUCCESS;
714 }
715
716 \f
717 NDIS_STATUS
718 FASTCALL
719 MiniDequeueWorkItem(
720 PLOGICAL_ADAPTER Adapter,
721 NDIS_WORK_ITEM_TYPE *WorkItemType,
722 PVOID *WorkItemContext)
723 /*
724 * FUNCTION: Dequeues a work item from the work queue of a logical adapter
725 * ARGUMENTS:
726 * Adapter = Pointer to the logical adapter object to dequeue work item from
727 * AdapterBinding = Address of buffer for adapter binding for this request
728 * WorkItemType = Address of buffer for work item type
729 * WorkItemContext = Address of buffer for pointer to context information
730 * NOTES:
731 * Adapter lock must be held when called
732 * RETURNS:
733 * Status of operation
734 */
735 {
736 PNDIS_MINIPORT_WORK_ITEM Item;
737
738 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
739
740 if (Adapter->MiniportBusy) {
741 NDIS_DbgPrint(MID_TRACE, ("Waiting for miniport to become free.\n"));
742 KeInsertQueueDpc(&Adapter->NdisMiniportBlock.DeferredDpc, NULL, NULL);
743 return NDIS_STATUS_FAILURE;
744 }
745
746 Item = Adapter->WorkQueueHead;
747
748 if (Item)
749 {
750 /* safe due to adapter lock held */
751 Adapter->WorkQueueHead = (PNDIS_MINIPORT_WORK_ITEM)Item->Link.Next;
752
753 if (Item == Adapter->WorkQueueTail)
754 Adapter->WorkQueueTail = NULL;
755
756 *WorkItemType = Item->WorkItemType;
757 *WorkItemContext = Item->WorkItemContext;
758
759 ExFreePool(Item);
760
761 Adapter->MiniportBusy = TRUE;
762
763 return NDIS_STATUS_SUCCESS;
764 }
765
766 return NDIS_STATUS_FAILURE;
767 }
768
769 \f
770 NDIS_STATUS
771 MiniDoRequest(
772 PLOGICAL_ADAPTER Adapter,
773 PNDIS_REQUEST NdisRequest)
774 /*
775 * FUNCTION: Sends a request to a miniport
776 * ARGUMENTS:
777 * AdapterBinding = Pointer to binding used in the request
778 * NdisRequest = Pointer to NDIS request structure describing request
779 * RETURNS:
780 * Status of operation
781 */
782 {
783 NDIS_STATUS Status;
784 KIRQL OldIrql;
785 NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
786
787 Adapter->NdisMiniportBlock.MediaRequest = NdisRequest;
788
789 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
790 switch (NdisRequest->RequestType)
791 {
792 case NdisRequestQueryInformation:
793 Status = (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.QueryInformationHandler)(
794 Adapter->NdisMiniportBlock.MiniportAdapterContext,
795 NdisRequest->DATA.QUERY_INFORMATION.Oid,
796 NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer,
797 NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength,
798 (PULONG)&NdisRequest->DATA.QUERY_INFORMATION.BytesWritten,
799 (PULONG)&NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded);
800 break;
801
802 case NdisRequestSetInformation:
803 Status = (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SetInformationHandler)(
804 Adapter->NdisMiniportBlock.MiniportAdapterContext,
805 NdisRequest->DATA.SET_INFORMATION.Oid,
806 NdisRequest->DATA.SET_INFORMATION.InformationBuffer,
807 NdisRequest->DATA.SET_INFORMATION.InformationBufferLength,
808 (PULONG)&NdisRequest->DATA.SET_INFORMATION.BytesRead,
809 (PULONG)&NdisRequest->DATA.SET_INFORMATION.BytesNeeded);
810 break;
811
812 default:
813 Status = NDIS_STATUS_FAILURE;
814 }
815
816 if (Status == NDIS_STATUS_PENDING) {
817 KeAcquireSpinLockAtDpcLevel(&Adapter->NdisMiniportBlock.Lock);
818 Adapter->MiniportBusy = TRUE;
819 KeReleaseSpinLockFromDpcLevel(&Adapter->NdisMiniportBlock.Lock);
820 }
821
822 KeLowerIrql(OldIrql);
823 return Status;
824 }
825
826 \f
827 /*
828 * @implemented
829 */
830 #undef NdisMQueryInformationComplete
831 VOID
832 EXPORT
833 NdisMQueryInformationComplete(
834 IN NDIS_HANDLE MiniportAdapterHandle,
835 IN NDIS_STATUS Status)
836 {
837 PLOGICAL_ADAPTER Adapter =
838 (PLOGICAL_ADAPTER)MiniportAdapterHandle;
839 KIRQL OldIrql;
840 ASSERT(Adapter);
841 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
842 if( Adapter->NdisMiniportBlock.QueryCompleteHandler )
843 (Adapter->NdisMiniportBlock.QueryCompleteHandler)(MiniportAdapterHandle, Status);
844 KeAcquireSpinLockAtDpcLevel(&Adapter->NdisMiniportBlock.Lock);
845 Adapter->MiniportBusy = FALSE;
846 KeReleaseSpinLockFromDpcLevel(&Adapter->NdisMiniportBlock.Lock);
847 KeLowerIrql(OldIrql);
848 }
849
850 VOID NTAPI MiniportWorker(IN PVOID WorkItem)
851 {
852 PNDIS_WORK_ITEM NdisWorkItem = WorkItem;
853 PLOGICAL_ADAPTER Adapter = GET_LOGICAL_ADAPTER(NdisWorkItem->Context);
854 KIRQL OldIrql, RaiseOldIrql;
855 NDIS_STATUS NdisStatus;
856 PVOID WorkItemContext;
857 NDIS_WORK_ITEM_TYPE WorkItemType;
858 BOOLEAN AddressingReset;
859
860 KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
861
862 NdisStatus =
863 MiniDequeueWorkItem
864 (Adapter, &WorkItemType, &WorkItemContext);
865
866 KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
867
868 if (NdisStatus == NDIS_STATUS_SUCCESS)
869 {
870 switch (WorkItemType)
871 {
872 case NdisWorkItemSend:
873 /*
874 * called by ProSend when protocols want to send packets to the miniport
875 */
876 #ifdef DBG
877 MiniDisplayPacket((PNDIS_PACKET)WorkItemContext);
878 #endif
879 if(Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendPacketsHandler)
880 {
881 if(Adapter->NdisMiniportBlock.Flags & NDIS_ATTRIBUTE_DESERIALIZE)
882 {
883 NDIS_DbgPrint(MAX_TRACE, ("Calling miniport's SendPackets handler\n"));
884 (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendPacketsHandler)(
885 Adapter->NdisMiniportBlock.MiniportAdapterContext, (PPNDIS_PACKET)&WorkItemContext, 1);
886 NdisStatus = NDIS_GET_PACKET_STATUS((PNDIS_PACKET)WorkItemContext);
887 }
888 else
889 {
890 /* SendPackets is called at DISPATCH_LEVEL for all serialized miniports */
891 KeRaiseIrql(DISPATCH_LEVEL, &RaiseOldIrql);
892 {
893 NDIS_DbgPrint(MAX_TRACE, ("Calling miniport's SendPackets handler\n"));
894 (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendPacketsHandler)(
895 Adapter->NdisMiniportBlock.MiniportAdapterContext, (PPNDIS_PACKET)&WorkItemContext, 1);
896 }
897 KeLowerIrql(RaiseOldIrql);
898
899 NdisStatus = NDIS_GET_PACKET_STATUS((PNDIS_PACKET)WorkItemContext);
900 if( NdisStatus == NDIS_STATUS_RESOURCES ) {
901 KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
902 MiniQueueWorkItem(Adapter, WorkItemType, WorkItemContext);
903 KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
904 break;
905 }
906 }
907 }
908 else
909 {
910 if(Adapter->NdisMiniportBlock.Flags & NDIS_ATTRIBUTE_DESERIALIZE)
911 {
912 NDIS_DbgPrint(MAX_TRACE, ("Calling miniport's Send handler\n"));
913 NdisStatus = (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendHandler)(
914 Adapter->NdisMiniportBlock.MiniportAdapterContext, (PNDIS_PACKET)WorkItemContext, 0);
915 NDIS_DbgPrint(MAX_TRACE, ("back from miniport's send handler\n"));
916 }
917 else
918 {
919 /* Send is called at DISPATCH_LEVEL for all serialized miniports */
920 KeRaiseIrql(DISPATCH_LEVEL, &RaiseOldIrql);
921 NDIS_DbgPrint(MAX_TRACE, ("Calling miniport's Send handler\n"));
922 NdisStatus = (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendHandler)(
923 Adapter->NdisMiniportBlock.MiniportAdapterContext, (PNDIS_PACKET)WorkItemContext, 0);
924 NDIS_DbgPrint(MAX_TRACE, ("back from miniport's send handler\n"));
925 KeLowerIrql(RaiseOldIrql);
926 if( NdisStatus == NDIS_STATUS_RESOURCES ) {
927 KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
928 MiniQueueWorkItem(Adapter, WorkItemType, WorkItemContext);
929 KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
930 break;
931 }
932 }
933 }
934
935 if( NdisStatus != NDIS_STATUS_PENDING ) {
936 NdisMSendComplete
937 ( Adapter, (PNDIS_PACKET)WorkItemContext, NdisStatus );
938 }
939 break;
940
941 case NdisWorkItemSendLoopback:
942 /*
943 * called by ProSend when protocols want to send loopback packets
944 */
945 /* XXX atm ProIndicatePacket sends a packet up via the loopback adapter only */
946 NdisStatus = ProIndicatePacket(Adapter, (PNDIS_PACKET)WorkItemContext);
947
948 if( NdisStatus != NDIS_STATUS_PENDING )
949 MiniSendComplete((NDIS_HANDLE)Adapter, (PNDIS_PACKET)WorkItemContext, NdisStatus);
950 break;
951
952 case NdisWorkItemReturnPackets:
953 break;
954
955 case NdisWorkItemResetRequested:
956 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
957 NdisStatus = (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.ResetHandler)(
958 Adapter->NdisMiniportBlock.MiniportAdapterContext,
959 &AddressingReset);
960 KeLowerIrql(OldIrql);
961
962 if (NdisStatus == NDIS_STATUS_PENDING)
963 break;
964
965 MiniResetComplete(Adapter, NdisStatus, AddressingReset);
966 break;
967
968 case NdisWorkItemResetInProgress:
969 break;
970
971 case NdisWorkItemMiniportCallback:
972 break;
973
974 case NdisWorkItemRequest:
975 NdisStatus = MiniDoRequest(Adapter, (PNDIS_REQUEST)WorkItemContext);
976
977 if (NdisStatus == NDIS_STATUS_PENDING)
978 break;
979
980 switch (((PNDIS_REQUEST)WorkItemContext)->RequestType)
981 {
982 case NdisRequestQueryInformation:
983 NdisMQueryInformationComplete((NDIS_HANDLE)Adapter, NdisStatus);
984 MiniRequestComplete( (NDIS_HANDLE)Adapter, (PNDIS_REQUEST)WorkItemContext, NdisStatus );
985 break;
986
987 case NdisRequestSetInformation:
988 NdisMSetInformationComplete((NDIS_HANDLE)Adapter, NdisStatus);
989 MiniRequestComplete( (NDIS_HANDLE)Adapter, (PNDIS_REQUEST)WorkItemContext, NdisStatus );
990 break;
991
992 default:
993 NDIS_DbgPrint(MIN_TRACE, ("Unknown NDIS request type.\n"));
994 break;
995 }
996 break;
997
998 default:
999 NDIS_DbgPrint(MIN_TRACE, ("Unknown NDIS work item type (%d).\n", WorkItemType));
1000 break;
1001 }
1002 }
1003
1004 if( NdisStatus != NDIS_STATUS_PENDING ) {
1005 KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
1006 Adapter->MiniportBusy = FALSE;
1007 KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
1008 }
1009
1010 ExFreePool(WorkItem);
1011 }
1012
1013
1014 \f
1015 VOID NTAPI MiniportDpc(
1016 IN PKDPC Dpc,
1017 IN PVOID DeferredContext,
1018 IN PVOID SystemArgument1,
1019 IN PVOID SystemArgument2)
1020 /*
1021 * FUNCTION: Deferred routine to handle serialization
1022 * ARGUMENTS:
1023 * Dpc = Pointer to DPC object
1024 * DeferredContext = Pointer to context information (LOGICAL_ADAPTER)
1025 * SystemArgument1 = Unused
1026 * SystemArgument2 = Unused
1027 */
1028 {
1029 PNDIS_WORK_ITEM NdisWorkItem;
1030 PWORK_QUEUE_ITEM WorkItem;
1031
1032 NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
1033
1034 NdisWorkItem = ExAllocatePool(NonPagedPool, sizeof(NDIS_WORK_ITEM));
1035 if (!NdisWorkItem) return;
1036
1037 WorkItem = (PWORK_QUEUE_ITEM)NdisWorkItem->WrapperReserved;
1038
1039 NdisWorkItem->Context = DeferredContext;
1040
1041 ExInitializeWorkItem(WorkItem, MiniportWorker, NdisWorkItem);
1042
1043 ExQueueWorkItem(WorkItem, CriticalWorkQueue);
1044 }
1045
1046 \f
1047 VOID
1048 NTAPI
1049 MiniStatus(
1050 IN NDIS_HANDLE MiniportHandle,
1051 IN NDIS_STATUS GeneralStatus,
1052 IN PVOID StatusBuffer,
1053 IN UINT StatusBufferSize)
1054 {
1055 UNIMPLEMENTED
1056 }
1057
1058 \f
1059 VOID
1060 NTAPI
1061 MiniStatusComplete(
1062 IN NDIS_HANDLE MiniportAdapterHandle)
1063 {
1064 UNIMPLEMENTED
1065 }
1066
1067 \f
1068 /*
1069 * @unimplemented
1070 */
1071 VOID
1072 EXPORT
1073 NdisMCloseLog(
1074 IN NDIS_HANDLE LogHandle)
1075 {
1076 UNIMPLEMENTED
1077 }
1078
1079 \f
1080 /*
1081 * @unimplemented
1082 */
1083 NDIS_STATUS
1084 EXPORT
1085 NdisMCreateLog(
1086 IN NDIS_HANDLE MiniportAdapterHandle,
1087 IN UINT Size,
1088 OUT PNDIS_HANDLE LogHandle)
1089 {
1090 UNIMPLEMENTED
1091
1092 return NDIS_STATUS_FAILURE;
1093 }
1094
1095 \f
1096 /*
1097 * @implemented
1098 */
1099 VOID
1100 EXPORT
1101 NdisMDeregisterAdapterShutdownHandler(
1102 IN NDIS_HANDLE MiniportHandle)
1103 /*
1104 * FUNCTION: de-registers a shutdown handler
1105 * ARGUMENTS: MiniportHandle: Handle passed into MiniportInitialize
1106 */
1107 {
1108 PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)MiniportHandle;
1109
1110 NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
1111
1112 if(Adapter->BugcheckContext->ShutdownHandler)
1113 KeDeregisterBugCheckCallback(Adapter->BugcheckContext->CallbackRecord);
1114 }
1115
1116 \f
1117 /*
1118 * @unimplemented
1119 */
1120 VOID
1121 EXPORT
1122 NdisMFlushLog(
1123 IN NDIS_HANDLE LogHandle)
1124 {
1125 UNIMPLEMENTED
1126 }
1127
1128 /*
1129 * @unimplemented
1130 */
1131 #undef NdisMIndicateStatus
1132 VOID
1133 EXPORT
1134 NdisMIndicateStatus(
1135 IN NDIS_HANDLE MiniportAdapterHandle,
1136 IN NDIS_STATUS GeneralStatus,
1137 IN PVOID StatusBuffer,
1138 IN UINT StatusBufferSize)
1139 {
1140 UNIMPLEMENTED
1141 }
1142
1143 /*
1144 * @unimplemented
1145 */
1146 #undef NdisMIndicateStatusComplete
1147 VOID
1148 EXPORT
1149 NdisMIndicateStatusComplete(
1150 IN NDIS_HANDLE MiniportAdapterHandle)
1151 {
1152 UNIMPLEMENTED
1153 }
1154
1155 \f
1156 /*
1157 * @implemented
1158 */
1159 VOID
1160 EXPORT
1161 NdisInitializeWrapper(
1162 OUT PNDIS_HANDLE NdisWrapperHandle,
1163 IN PVOID SystemSpecific1,
1164 IN PVOID SystemSpecific2,
1165 IN PVOID SystemSpecific3)
1166 /*
1167 * FUNCTION: Notifies the NDIS library that a new miniport is initializing
1168 * ARGUMENTS:
1169 * NdisWrapperHandle = Address of buffer to place NDIS wrapper handle
1170 * SystemSpecific1 = Pointer to the driver's driver object
1171 * SystemSpecific2 = Pointer to the driver's registry path
1172 * SystemSpecific3 = Always NULL
1173 * NOTES:
1174 * - SystemSpecific2 goes invalid so we copy it
1175 */
1176 {
1177 PNDIS_M_DRIVER_BLOCK Miniport;
1178 PUNICODE_STRING RegistryPath;
1179 WCHAR *RegistryBuffer;
1180
1181 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
1182
1183 ASSERT(NdisWrapperHandle);
1184
1185 *NdisWrapperHandle = NULL;
1186
1187 #if BREAK_ON_MINIPORT_INIT
1188 __asm__ ("int $3\n");
1189 #endif
1190
1191 Miniport = ExAllocatePool(NonPagedPool, sizeof(NDIS_M_DRIVER_BLOCK));
1192
1193 if (!Miniport)
1194 {
1195 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
1196 return;
1197 }
1198
1199 RtlZeroMemory(Miniport, sizeof(NDIS_M_DRIVER_BLOCK));
1200
1201 KeInitializeSpinLock(&Miniport->Lock);
1202
1203 Miniport->DriverObject = (PDRIVER_OBJECT)SystemSpecific1;
1204
1205 /* set the miniport's driver registry path */
1206 RegistryPath = ExAllocatePool(PagedPool, sizeof(UNICODE_STRING));
1207 if(!RegistryPath)
1208 {
1209 ExFreePool(Miniport);
1210 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
1211 return;
1212 }
1213
1214 RegistryPath->Length = ((PUNICODE_STRING)SystemSpecific2)->Length;
1215 RegistryPath->MaximumLength = RegistryPath->Length + sizeof(WCHAR); /* room for 0-term */
1216
1217 RegistryBuffer = ExAllocatePool(PagedPool, RegistryPath->MaximumLength);
1218 if(!RegistryBuffer)
1219 {
1220 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
1221 ExFreePool(Miniport);
1222 ExFreePool(RegistryPath);
1223 return;
1224 }
1225
1226 RtlCopyMemory(RegistryBuffer, ((PUNICODE_STRING)SystemSpecific2)->Buffer, RegistryPath->Length);
1227 RegistryBuffer[RegistryPath->Length/sizeof(WCHAR)] = 0;
1228
1229 RegistryPath->Buffer = RegistryBuffer;
1230 Miniport->RegistryPath = RegistryPath;
1231
1232 InitializeListHead(&Miniport->DeviceList);
1233
1234 /* Put miniport in global miniport list */
1235 ExInterlockedInsertTailList(&MiniportListHead, &Miniport->ListEntry, &MiniportListLock);
1236
1237 *NdisWrapperHandle = Miniport;
1238 }
1239
1240 \f
1241 VOID NTAPI NdisIBugcheckCallback(
1242 IN PVOID Buffer,
1243 IN ULONG Length)
1244 /*
1245 * FUNCTION: Internal callback for handling bugchecks - calls adapter's shutdown handler
1246 * ARGUMENTS:
1247 * Buffer: Pointer to a bugcheck callback context
1248 * Length: Unused
1249 */
1250 {
1251 PMINIPORT_BUGCHECK_CONTEXT Context = (PMINIPORT_BUGCHECK_CONTEXT)Buffer;
1252 ADAPTER_SHUTDOWN_HANDLER sh = (ADAPTER_SHUTDOWN_HANDLER)Context->ShutdownHandler;
1253
1254 NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
1255
1256 if(sh)
1257 sh(Context->DriverContext);
1258 }
1259
1260 \f
1261 /*
1262 * @implemented
1263 */
1264 VOID
1265 EXPORT
1266 NdisMRegisterAdapterShutdownHandler(
1267 IN NDIS_HANDLE MiniportHandle,
1268 IN PVOID ShutdownContext,
1269 IN ADAPTER_SHUTDOWN_HANDLER ShutdownHandler)
1270 /*
1271 * FUNCTION: Register a shutdown handler for an adapter
1272 * ARGUMENTS:
1273 * MiniportHandle: Handle originally passed into MiniportInitialize
1274 * ShutdownContext: Pre-initialized bugcheck context
1275 * ShutdownHandler: Function to call to handle the bugcheck
1276 * NOTES:
1277 * - I'm not sure about ShutdownContext
1278 */
1279 {
1280 PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)MiniportHandle;
1281 PMINIPORT_BUGCHECK_CONTEXT BugcheckContext = Adapter->BugcheckContext;
1282
1283 NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
1284
1285 if(BugcheckContext)
1286 return;
1287
1288 BugcheckContext = ExAllocatePool(NonPagedPool, sizeof(MINIPORT_BUGCHECK_CONTEXT));
1289 if(!BugcheckContext)
1290 {
1291 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
1292 return;
1293 }
1294
1295 BugcheckContext->ShutdownHandler = ShutdownHandler;
1296 BugcheckContext->DriverContext = ShutdownContext;
1297
1298 BugcheckContext->CallbackRecord = ExAllocatePool(NonPagedPool, sizeof(KBUGCHECK_CALLBACK_RECORD));
1299
1300 KeInitializeCallbackRecord(BugcheckContext->CallbackRecord);
1301
1302 KeRegisterBugCheckCallback(BugcheckContext->CallbackRecord, NdisIBugcheckCallback,
1303 BugcheckContext, sizeof(BugcheckContext), (PUCHAR)"Ndis Miniport");
1304 }
1305
1306 \f
1307 NDIS_STATUS
1308 DoQueries(
1309 PLOGICAL_ADAPTER Adapter,
1310 NDIS_OID AddressOID)
1311 /*
1312 * FUNCTION: Queries miniport for information
1313 * ARGUMENTS:
1314 * Adapter = Pointer to logical adapter
1315 * AddressOID = OID to use to query for current address
1316 * RETURNS:
1317 * Status of operation
1318 */
1319 {
1320 ULONG BytesWritten;
1321 NDIS_STATUS NdisStatus;
1322
1323 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
1324
1325 /* Get MAC options for adapter */
1326 NdisStatus = MiniQueryInformation(Adapter, OID_GEN_MAC_OPTIONS, sizeof(UINT),
1327 &Adapter->NdisMiniportBlock.MacOptions,
1328 &BytesWritten);
1329
1330 if (NdisStatus != NDIS_STATUS_SUCCESS)
1331 {
1332 NDIS_DbgPrint(MIN_TRACE, ("OID_GEN_MAC_OPTIONS failed. NdisStatus (0x%X).\n", NdisStatus));
1333 return NdisStatus;
1334 }
1335
1336 NDIS_DbgPrint(DEBUG_MINIPORT, ("MacOptions (0x%X).\n", Adapter->NdisMiniportBlock.MacOptions));
1337
1338 /* Get current hardware address of adapter */
1339 NdisStatus = MiniQueryInformation(Adapter, AddressOID, Adapter->AddressLength,
1340 &Adapter->Address, &BytesWritten);
1341
1342 if (NdisStatus != NDIS_STATUS_SUCCESS)
1343 {
1344 NDIS_DbgPrint(MIN_TRACE, ("Address OID (0x%X) failed. NdisStatus (0x%X).\n", AddressOID, NdisStatus));
1345 return NdisStatus;
1346 }
1347
1348 #ifdef DBG
1349 {
1350 /* 802.3 only */
1351
1352 PUCHAR A = (PUCHAR)&Adapter->Address.Type.Medium802_3;
1353
1354 NDIS_DbgPrint(MAX_TRACE, ("Adapter address is (%02X %02X %02X %02X %02X %02X).\n", A[0], A[1], A[2], A[3], A[4], A[5]));
1355 }
1356 #endif /* DBG */
1357
1358 /* Get maximum lookahead buffer size of adapter */
1359 NdisStatus = MiniQueryInformation(Adapter, OID_GEN_MAXIMUM_LOOKAHEAD, sizeof(ULONG),
1360 &Adapter->NdisMiniportBlock.MaximumLookahead, &BytesWritten);
1361
1362 if (NdisStatus != NDIS_STATUS_SUCCESS)
1363 {
1364 NDIS_DbgPrint(MIN_TRACE, ("OID_GEN_MAXIMUM_LOOKAHEAD failed. NdisStatus (0x%X).\n", NdisStatus));
1365 return NdisStatus;
1366 }
1367
1368 NDIS_DbgPrint(DEBUG_MINIPORT, ("MaxLookaheadLength (0x%X).\n", Adapter->NdisMiniportBlock.MaximumLookahead));
1369
1370 /* Get current lookahead buffer size of adapter */
1371 NdisStatus = MiniQueryInformation(Adapter, OID_GEN_CURRENT_LOOKAHEAD, sizeof(ULONG),
1372 &Adapter->NdisMiniportBlock.CurrentLookahead, &BytesWritten);
1373
1374 if (NdisStatus != NDIS_STATUS_SUCCESS)
1375 {
1376 NDIS_DbgPrint(MIN_TRACE, ("OID_GEN_CURRENT_LOOKAHEAD failed. NdisStatus (0x%X).\n", NdisStatus));
1377 return NdisStatus;
1378 }
1379
1380 NdisStatus = MiniQueryInformation(Adapter, OID_GEN_MAXIMUM_SEND_PACKETS, sizeof(ULONG),
1381 &Adapter->NdisMiniportBlock.MaxSendPackets, &BytesWritten);
1382
1383 if (NdisStatus != NDIS_STATUS_SUCCESS)
1384 {
1385 NDIS_DbgPrint(MIN_TRACE, ("OID_GEN_MAXIMUM_SEND_PACKETS failed. NdisStatus (0x%X).\n", NdisStatus));
1386
1387 /* Set it to 1 if it fails because some drivers don't support this (?)*/
1388 Adapter->NdisMiniportBlock.MaxSendPackets = 1;
1389 }
1390
1391 NDIS_DbgPrint(DEBUG_MINIPORT, ("CurLookaheadLength (0x%X).\n", Adapter->NdisMiniportBlock.CurrentLookahead));
1392
1393 if (Adapter->NdisMiniportBlock.MaximumLookahead != 0)
1394 {
1395 Adapter->LookaheadLength = Adapter->NdisMiniportBlock.MaximumLookahead + Adapter->MediumHeaderSize;
1396 Adapter->LookaheadBuffer = ExAllocatePool(NonPagedPool, Adapter->LookaheadLength);
1397
1398 if (!Adapter->LookaheadBuffer)
1399 return NDIS_STATUS_RESOURCES;
1400 }
1401
1402 return STATUS_SUCCESS;
1403 }
1404
1405 \f
1406 NTSTATUS
1407 NTAPI
1408 NdisIForwardIrpAndWaitCompletionRoutine(
1409 PDEVICE_OBJECT Fdo,
1410 PIRP Irp,
1411 PVOID Context)
1412 {
1413 PKEVENT Event = Context;
1414
1415 if (Irp->PendingReturned)
1416 KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
1417
1418 return STATUS_MORE_PROCESSING_REQUIRED;
1419 }
1420
1421 \f
1422 NTSTATUS
1423 NTAPI
1424 NdisIForwardIrpAndWait(PLOGICAL_ADAPTER Adapter, PIRP Irp)
1425 {
1426 KEVENT Event;
1427 NTSTATUS Status;
1428
1429 KeInitializeEvent(&Event, NotificationEvent, FALSE);
1430 IoCopyCurrentIrpStackLocationToNext(Irp);
1431 IoSetCompletionRoutine(Irp, NdisIForwardIrpAndWaitCompletionRoutine, &Event,
1432 TRUE, TRUE, TRUE);
1433 Status = IoCallDriver(Adapter->NdisMiniportBlock.NextDeviceObject, Irp);
1434 if (Status == STATUS_PENDING)
1435 {
1436 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
1437 Status = Irp->IoStatus.Status;
1438 }
1439 return Status;
1440 }
1441
1442 \f
1443 NTSTATUS
1444 NTAPI
1445 NdisIPnPStartDevice(
1446 IN PDEVICE_OBJECT DeviceObject,
1447 PIRP Irp)
1448 /*
1449 * FUNCTION: Handle the PnP start device event
1450 * ARGUMENTS:
1451 * DeviceObejct = Functional Device Object
1452 * Irp = IRP_MN_START_DEVICE I/O request packet
1453 * RETURNS:
1454 * Status of operation
1455 */
1456 {
1457 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
1458 PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)DeviceObject->DeviceExtension;
1459 NDIS_WRAPPER_CONTEXT WrapperContext;
1460 NDIS_STATUS NdisStatus;
1461 NDIS_STATUS OpenErrorStatus;
1462 NTSTATUS Status;
1463 UINT SelectedMediumIndex = 0;
1464 NDIS_OID AddressOID;
1465 BOOLEAN Success = FALSE;
1466 ULONG ResourceCount;
1467 ULONG ResourceListSize;
1468 UNICODE_STRING ParamName;
1469 PNDIS_CONFIGURATION_PARAMETER ConfigParam;
1470 NDIS_HANDLE ConfigHandle;
1471 ULONG Size;
1472 LARGE_INTEGER Timeout;
1473 /* FIXME - KIRQL OldIrql; */
1474
1475 /*
1476 * Prepare wrapper context used by HW and configuration routines.
1477 */
1478
1479 NDIS_DbgPrint(DEBUG_MINIPORT, ("Start Device %wZ\n", &Adapter->NdisMiniportBlock.MiniportName));
1480
1481 NDIS_DbgPrint(MAX_TRACE, ("Inserting adapter 0x%x into adapter list\n", Adapter));
1482
1483 /* Put adapter in global adapter list */
1484 ExInterlockedInsertTailList(&AdapterListHead, &Adapter->ListEntry, &AdapterListLock);
1485
1486 Status = IoOpenDeviceRegistryKey(
1487 Adapter->NdisMiniportBlock.PhysicalDeviceObject, PLUGPLAY_REGKEY_DRIVER,
1488 KEY_ALL_ACCESS, &WrapperContext.RegistryHandle);
1489 if (!NT_SUCCESS(Status))
1490 {
1491 NDIS_DbgPrint(MIN_TRACE,("failed to open adapter-specific reg key\n"));
1492 ExInterlockedRemoveEntryList( &Adapter->ListEntry, &AdapterListLock );
1493 return Status;
1494 }
1495
1496 NDIS_DbgPrint(MAX_TRACE, ("opened device reg key\n"));
1497
1498 WrapperContext.DeviceObject = Adapter->NdisMiniportBlock.DeviceObject;
1499
1500 /*
1501 * Store the adapter resources used by HW routines such as
1502 * NdisMQueryAdapterResources.
1503 */
1504
1505 if (Stack->Parameters.StartDevice.AllocatedResources != NULL)
1506 {
1507 ResourceCount = Stack->Parameters.StartDevice.AllocatedResources->List[0].
1508 PartialResourceList.Count;
1509 ResourceListSize =
1510 FIELD_OFFSET(CM_RESOURCE_LIST, List[0].PartialResourceList.
1511 PartialDescriptors[ResourceCount]);
1512
1513 Adapter->NdisMiniportBlock.AllocatedResources =
1514 ExAllocatePool(PagedPool, ResourceListSize);
1515 if (Adapter->NdisMiniportBlock.AllocatedResources == NULL)
1516 {
1517 ExInterlockedRemoveEntryList( &Adapter->ListEntry, &AdapterListLock );
1518 return STATUS_INSUFFICIENT_RESOURCES;
1519 }
1520
1521 RtlCopyMemory(Adapter->NdisMiniportBlock.AllocatedResources,
1522 Stack->Parameters.StartDevice.AllocatedResources,
1523 ResourceListSize);
1524 }
1525
1526 if (Stack->Parameters.StartDevice.AllocatedResourcesTranslated != NULL)
1527 {
1528 ResourceCount = Stack->Parameters.StartDevice.AllocatedResourcesTranslated->List[0].
1529 PartialResourceList.Count;
1530 ResourceListSize =
1531 FIELD_OFFSET(CM_RESOURCE_LIST, List[0].PartialResourceList.
1532 PartialDescriptors[ResourceCount]);
1533
1534 Adapter->NdisMiniportBlock.AllocatedResourcesTranslated =
1535 ExAllocatePool(PagedPool, ResourceListSize);
1536 if (Adapter->NdisMiniportBlock.AllocatedResourcesTranslated == NULL)
1537 {
1538 ExInterlockedRemoveEntryList( &Adapter->ListEntry, &AdapterListLock );
1539 return STATUS_INSUFFICIENT_RESOURCES;
1540 }
1541
1542 RtlCopyMemory(Adapter->NdisMiniportBlock.AllocatedResourcesTranslated,
1543 Stack->Parameters.StartDevice.AllocatedResourcesTranslated,
1544 ResourceListSize);
1545 }
1546
1547 /*
1548 * Store the Bus Type, Bus Number and Slot information. It's used by
1549 * the hardware routines then.
1550 */
1551
1552 NdisOpenConfiguration(&NdisStatus, &ConfigHandle, (NDIS_HANDLE)&WrapperContext);
1553
1554 Size = sizeof(ULONG);
1555 Status = IoGetDeviceProperty(Adapter->NdisMiniportBlock.PhysicalDeviceObject,
1556 DevicePropertyLegacyBusType, Size,
1557 &Adapter->NdisMiniportBlock.BusType, &Size);
1558 if (!NT_SUCCESS(Status) || (INTERFACE_TYPE)Adapter->NdisMiniportBlock.BusType == InterfaceTypeUndefined)
1559 {
1560 NdisInitUnicodeString(&ParamName, L"BusType");
1561 NdisReadConfiguration(&NdisStatus, &ConfigParam, ConfigHandle,
1562 &ParamName, NdisParameterInteger);
1563 if (NdisStatus == NDIS_STATUS_SUCCESS)
1564 Adapter->NdisMiniportBlock.BusType = ConfigParam->ParameterData.IntegerData;
1565 else
1566 Adapter->NdisMiniportBlock.BusType = Isa;
1567 }
1568
1569 Status = IoGetDeviceProperty(Adapter->NdisMiniportBlock.PhysicalDeviceObject,
1570 DevicePropertyBusNumber, Size,
1571 &Adapter->NdisMiniportBlock.BusNumber, &Size);
1572 if (!NT_SUCCESS(Status) || Adapter->NdisMiniportBlock.BusNumber == 0xFFFFFFF0)
1573 {
1574 NdisInitUnicodeString(&ParamName, L"BusNumber");
1575 NdisReadConfiguration(&NdisStatus, &ConfigParam, ConfigHandle,
1576 &ParamName, NdisParameterInteger);
1577 if (NdisStatus == NDIS_STATUS_SUCCESS)
1578 Adapter->NdisMiniportBlock.BusNumber = ConfigParam->ParameterData.IntegerData;
1579 else
1580 Adapter->NdisMiniportBlock.BusNumber = 0;
1581 }
1582 WrapperContext.BusNumber = Adapter->NdisMiniportBlock.BusNumber;
1583
1584 Status = IoGetDeviceProperty(Adapter->NdisMiniportBlock.PhysicalDeviceObject,
1585 DevicePropertyAddress, Size,
1586 &Adapter->NdisMiniportBlock.SlotNumber, &Size);
1587 if (!NT_SUCCESS(Status) || Adapter->NdisMiniportBlock.SlotNumber == (NDIS_INTERFACE_TYPE)-1)
1588 {
1589 NdisInitUnicodeString(&ParamName, L"SlotNumber");
1590 NdisReadConfiguration(&NdisStatus, &ConfigParam, ConfigHandle,
1591 &ParamName, NdisParameterInteger);
1592 if (NdisStatus == NDIS_STATUS_SUCCESS)
1593 Adapter->NdisMiniportBlock.SlotNumber = ConfigParam->ParameterData.IntegerData;
1594 else
1595 Adapter->NdisMiniportBlock.SlotNumber = 0;
1596 }
1597 else
1598 {
1599 /* Convert slotnumber to PCI_SLOT_NUMBER */
1600 ULONG PciSlotNumber = Adapter->NdisMiniportBlock.SlotNumber;
1601 PCI_SLOT_NUMBER SlotNumber;
1602
1603 SlotNumber.u.AsULONG = 0;
1604 SlotNumber.u.bits.DeviceNumber = (PciSlotNumber >> 16) & 0xFFFF;
1605 SlotNumber.u.bits.FunctionNumber = PciSlotNumber & 0xFFFF;
1606
1607 Adapter->NdisMiniportBlock.SlotNumber = SlotNumber.u.AsULONG;
1608 }
1609 NdisCloseConfiguration(ConfigHandle);
1610
1611 /* Set handlers (some NDIS macros require these) */
1612 Adapter->NdisMiniportBlock.EthRxCompleteHandler = EthFilterDprIndicateReceiveComplete;
1613 Adapter->NdisMiniportBlock.EthRxIndicateHandler = EthFilterDprIndicateReceive;
1614 Adapter->NdisMiniportBlock.SendCompleteHandler = MiniSendComplete;
1615 Adapter->NdisMiniportBlock.SendResourcesHandler = MiniSendResourcesAvailable;
1616 Adapter->NdisMiniportBlock.ResetCompleteHandler = MiniResetComplete;
1617 Adapter->NdisMiniportBlock.TDCompleteHandler = MiniTransferDataComplete;
1618 Adapter->NdisMiniportBlock.PacketIndicateHandler= MiniIndicateReceivePacket;
1619 Adapter->NdisMiniportBlock.StatusHandler = MiniStatus;
1620 Adapter->NdisMiniportBlock.StatusCompleteHandler= MiniStatusComplete;
1621
1622 /*
1623 * Call MiniportInitialize.
1624 */
1625
1626 NDIS_DbgPrint(MID_TRACE, ("calling MiniportInitialize\n"));
1627 NdisStatus = (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.InitializeHandler)(
1628 &OpenErrorStatus, &SelectedMediumIndex, &MediaArray[0],
1629 MEDIA_ARRAY_SIZE, Adapter, (NDIS_HANDLE)&WrapperContext);
1630
1631 ZwClose(WrapperContext.RegistryHandle);
1632
1633 if (NdisStatus != NDIS_STATUS_SUCCESS ||
1634 SelectedMediumIndex >= MEDIA_ARRAY_SIZE)
1635 {
1636 NDIS_DbgPrint(MIN_TRACE, ("MiniportInitialize() failed for an adapter.\n"));
1637 ExInterlockedRemoveEntryList( &Adapter->ListEntry, &AdapterListLock );
1638 if (NdisStatus == NDIS_STATUS_SUCCESS) NdisStatus = NDIS_STATUS_FAILURE;
1639 return (NTSTATUS)NdisStatus;
1640 }
1641
1642 Adapter->NdisMiniportBlock.MediaType = MediaArray[SelectedMediumIndex];
1643
1644 switch (Adapter->NdisMiniportBlock.MediaType)
1645 {
1646 case NdisMedium802_3:
1647 Adapter->MediumHeaderSize = 14; /* XXX figure out what to do about LLC */
1648 AddressOID = OID_802_3_CURRENT_ADDRESS;
1649 Adapter->AddressLength = ETH_LENGTH_OF_ADDRESS;
1650 NdisStatus = DoQueries(Adapter, AddressOID);
1651 if (NdisStatus == NDIS_STATUS_SUCCESS)
1652 {
1653 Success = EthCreateFilter(32, /* FIXME: Query this from miniport. */
1654 Adapter->Address.Type.Medium802_3,
1655 &Adapter->NdisMiniportBlock.EthDB);
1656 if (Success)
1657 ((PETHI_FILTER)Adapter->NdisMiniportBlock.EthDB)->Miniport = (PNDIS_MINIPORT_BLOCK)Adapter;
1658 else
1659 NdisStatus = NDIS_STATUS_RESOURCES;
1660 }
1661 break;
1662
1663 default:
1664 /* FIXME: Support other types of media */
1665 NDIS_DbgPrint(MIN_TRACE, ("error: unsupported media\n"));
1666 ASSERT(FALSE);
1667 /* FIXME - KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql); */
1668 ExInterlockedRemoveEntryList( &Adapter->ListEntry, &AdapterListLock );
1669 return STATUS_UNSUCCESSFUL;
1670 }
1671
1672 if (!Success || NdisStatus != NDIS_STATUS_SUCCESS)
1673 {
1674 NDIS_DbgPrint(MAX_TRACE, ("couldn't create filter (%x)\n", NdisStatus));
1675 if (Adapter->LookaheadBuffer)
1676 {
1677 ExFreePool(Adapter->LookaheadBuffer);
1678 Adapter->LookaheadBuffer = NULL;
1679 }
1680 ExInterlockedRemoveEntryList( &Adapter->ListEntry, &AdapterListLock );
1681 if (NdisStatus == NDIS_STATUS_SUCCESS) NdisStatus = NDIS_STATUS_FAILURE;
1682 return (NTSTATUS)NdisStatus;
1683 }
1684
1685 /* Check for a hang every two seconds if it wasn't set in MiniportInitialize */
1686 if (Adapter->NdisMiniportBlock.CheckForHangSeconds == 0)
1687 Adapter->NdisMiniportBlock.CheckForHangSeconds = 2;
1688
1689 Adapter->NdisMiniportBlock.OldPnPDeviceState = Adapter->NdisMiniportBlock.PnPDeviceState;
1690 Adapter->NdisMiniportBlock.PnPDeviceState = NdisPnPDeviceStarted;
1691
1692 Timeout.QuadPart = (LONGLONG)Adapter->NdisMiniportBlock.CheckForHangSeconds * -1000000;
1693 KeSetTimerEx(&Adapter->NdisMiniportBlock.WakeUpDpcTimer.Timer, Timeout,
1694 Adapter->NdisMiniportBlock.CheckForHangSeconds * 1000,
1695 &Adapter->NdisMiniportBlock.WakeUpDpcTimer.Dpc);
1696
1697 /* Put adapter in adapter list for this miniport */
1698 ExInterlockedInsertTailList(&Adapter->NdisMiniportBlock.DriverHandle->DeviceList, &Adapter->MiniportListEntry, &Adapter->NdisMiniportBlock.DriverHandle->Lock);
1699
1700 return STATUS_SUCCESS;
1701 }
1702
1703 \f
1704 NTSTATUS
1705 NTAPI
1706 NdisIPnPStopDevice(
1707 IN PDEVICE_OBJECT DeviceObject,
1708 PIRP Irp)
1709 /*
1710 * FUNCTION: Handle the PnP stop device event
1711 * ARGUMENTS:
1712 * DeviceObejct = Functional Device Object
1713 * Irp = IRP_MN_STOP_DEVICE I/O request packet
1714 * RETURNS:
1715 * Status of operation
1716 */
1717 {
1718 PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)DeviceObject->DeviceExtension;
1719 KIRQL OldIrql;
1720
1721 /* Remove adapter from adapter list for this miniport */
1722 KeAcquireSpinLock(&Adapter->NdisMiniportBlock.DriverHandle->Lock, &OldIrql);
1723 RemoveEntryList(&Adapter->MiniportListEntry);
1724 KeReleaseSpinLock(&Adapter->NdisMiniportBlock.DriverHandle->Lock, OldIrql);
1725
1726 /* Remove adapter from global adapter list */
1727 KeAcquireSpinLock(&AdapterListLock, &OldIrql);
1728 RemoveEntryList(&Adapter->ListEntry);
1729 KeReleaseSpinLock(&AdapterListLock, OldIrql);
1730
1731 (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.HaltHandler)(Adapter);
1732
1733 if (Adapter->LookaheadBuffer)
1734 {
1735 ExFreePool(Adapter->LookaheadBuffer);
1736 Adapter->LookaheadBuffer = NULL;
1737 }
1738 if (Adapter->NdisMiniportBlock.AllocatedResources)
1739 {
1740 ExFreePool(Adapter->NdisMiniportBlock.AllocatedResources);
1741 Adapter->NdisMiniportBlock.AllocatedResources = NULL;
1742 }
1743 if (Adapter->NdisMiniportBlock.AllocatedResourcesTranslated)
1744 {
1745 ExFreePool(Adapter->NdisMiniportBlock.AllocatedResourcesTranslated);
1746 Adapter->NdisMiniportBlock.AllocatedResourcesTranslated = NULL;
1747 }
1748
1749 Adapter->NdisMiniportBlock.OldPnPDeviceState = Adapter->NdisMiniportBlock.PnPDeviceState;
1750 Adapter->NdisMiniportBlock.PnPDeviceState = NdisPnPDeviceStopped;
1751
1752 KeCancelTimer(&Adapter->NdisMiniportBlock.WakeUpDpcTimer.Timer);
1753
1754 return STATUS_SUCCESS;
1755 }
1756
1757 \f
1758 NTSTATUS
1759 NTAPI
1760 NdisIDispatchPnp(
1761 IN PDEVICE_OBJECT DeviceObject,
1762 PIRP Irp)
1763 {
1764 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
1765 PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)DeviceObject->DeviceExtension;
1766 NTSTATUS Status;
1767
1768 switch (Stack->MinorFunction)
1769 {
1770 case IRP_MN_START_DEVICE:
1771 Status = NdisIForwardIrpAndWait(Adapter, Irp);
1772 if (NT_SUCCESS(Status) && NT_SUCCESS(Irp->IoStatus.Status))
1773 {
1774 Status = NdisIPnPStartDevice(DeviceObject, Irp);
1775 }
1776 Irp->IoStatus.Status = Status;
1777 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1778 break;
1779
1780 case IRP_MN_STOP_DEVICE:
1781 Status = NdisIForwardIrpAndWait(Adapter, Irp);
1782 if (NT_SUCCESS(Status) && NT_SUCCESS(Irp->IoStatus.Status))
1783 {
1784 Status = NdisIPnPStopDevice(DeviceObject, Irp);
1785 }
1786 Irp->IoStatus.Status = Status;
1787 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1788 break;
1789
1790 case IRP_MN_QUERY_DEVICE_RELATIONS:
1791 Status = STATUS_NOT_SUPPORTED;
1792 Irp->IoStatus.Status = Status;
1793 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1794 break;
1795
1796 default:
1797 IoSkipCurrentIrpStackLocation(Irp);
1798 Status = IoCallDriver(Adapter->NdisMiniportBlock.NextDeviceObject, Irp);
1799 break;
1800 }
1801
1802 return Status;
1803 }
1804
1805 \f
1806 NTSTATUS
1807 NTAPI
1808 NdisIAddDevice(
1809 IN PDRIVER_OBJECT DriverObject,
1810 IN PDEVICE_OBJECT PhysicalDeviceObject)
1811 /*
1812 * FUNCTION: Create a device for an adapter found using PnP
1813 * ARGUMENTS:
1814 * DriverObject = Pointer to the miniport driver object
1815 * PhysicalDeviceObject = Pointer to the PDO for our adapter
1816 */
1817 {
1818 static const WCHAR ClassKeyName[] = {'C','l','a','s','s','\\'};
1819 static const WCHAR LinkageKeyName[] = {'\\','L','i','n','k','a','g','e',0};
1820 PNDIS_M_DRIVER_BLOCK Miniport;
1821 PNDIS_M_DRIVER_BLOCK *MiniportPtr;
1822 WCHAR *LinkageKeyBuffer;
1823 ULONG DriverKeyLength;
1824 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
1825 UNICODE_STRING ExportName;
1826 PDEVICE_OBJECT DeviceObject;
1827 PLOGICAL_ADAPTER Adapter;
1828 NTSTATUS Status;
1829
1830 /*
1831 * Gain the access to the miniport data structure first.
1832 */
1833
1834 MiniportPtr = IoGetDriverObjectExtension(DriverObject, (PVOID)TAG('D','I','M','N'));
1835 if (MiniportPtr == NULL)
1836 {
1837 NDIS_DbgPrint(DEBUG_MINIPORT, ("Can't get driver object extension.\n"));
1838 return STATUS_UNSUCCESSFUL;
1839 }
1840 Miniport = *MiniportPtr;
1841
1842 /*
1843 * Get name of the Linkage registry key for our adapter. It's located under
1844 * the driver key for our driver and so we have basicly two ways to do it.
1845 * Either we can use IoOpenDriverRegistryKey or compose it using information
1846 * gathered by IoGetDeviceProperty. I choosed the second because
1847 * IoOpenDriverRegistryKey wasn't implemented at the time of writing.
1848 */
1849
1850 Status = IoGetDeviceProperty(PhysicalDeviceObject, DevicePropertyDriverKeyName,
1851 0, NULL, &DriverKeyLength);
1852 if (Status != STATUS_BUFFER_TOO_SMALL && Status != STATUS_BUFFER_OVERFLOW && Status != STATUS_SUCCESS)
1853 {
1854 NDIS_DbgPrint(DEBUG_MINIPORT, ("Can't get miniport driver key length.\n"));
1855 return Status;
1856 }
1857
1858 LinkageKeyBuffer = ExAllocatePool(PagedPool, DriverKeyLength +
1859 sizeof(ClassKeyName) + sizeof(LinkageKeyName));
1860 if (LinkageKeyBuffer == NULL)
1861 {
1862 NDIS_DbgPrint(DEBUG_MINIPORT, ("Can't allocate memory for driver key name.\n"));
1863 return STATUS_INSUFFICIENT_RESOURCES;
1864 }
1865
1866 Status = IoGetDeviceProperty(PhysicalDeviceObject, DevicePropertyDriverKeyName,
1867 DriverKeyLength, LinkageKeyBuffer +
1868 (sizeof(ClassKeyName) / sizeof(WCHAR)),
1869 &DriverKeyLength);
1870 if (!NT_SUCCESS(Status))
1871 {
1872 NDIS_DbgPrint(DEBUG_MINIPORT, ("Can't get miniport driver key.\n"));
1873 ExFreePool(LinkageKeyBuffer);
1874 return Status;
1875 }
1876
1877 /* Compose the linkage key name. */
1878 RtlCopyMemory(LinkageKeyBuffer, ClassKeyName, sizeof(ClassKeyName));
1879 RtlCopyMemory(LinkageKeyBuffer + ((sizeof(ClassKeyName) + DriverKeyLength) /
1880 sizeof(WCHAR)) - 1, LinkageKeyName, sizeof(LinkageKeyName));
1881
1882 NDIS_DbgPrint(DEBUG_MINIPORT, ("LinkageKey: %S.\n", LinkageKeyBuffer));
1883
1884 /*
1885 * Now open the linkage key and read the "Export" and "RootDevice" values
1886 * which contains device name and root service respectively.
1887 */
1888
1889 RtlZeroMemory(QueryTable, sizeof(QueryTable));
1890 RtlInitUnicodeString(&ExportName, NULL);
1891 QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_DIRECT;
1892 QueryTable[0].Name = L"Export";
1893 QueryTable[0].EntryContext = &ExportName;
1894
1895 Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL, LinkageKeyBuffer,
1896 QueryTable, NULL, NULL);
1897 ExFreePool(LinkageKeyBuffer);
1898 if (!NT_SUCCESS(Status))
1899 {
1900 NDIS_DbgPrint(DEBUG_MINIPORT, ("Can't get miniport device name. (%x)\n", Status));
1901 return Status;
1902 }
1903
1904 /*
1905 * Create the device object.
1906 */
1907
1908 NDIS_DbgPrint(MAX_TRACE, ("creating device %wZ\n", &ExportName));
1909
1910 Status = IoCreateDevice(Miniport->DriverObject, sizeof(LOGICAL_ADAPTER),
1911 &ExportName, FILE_DEVICE_PHYSICAL_NETCARD,
1912 0, FALSE, &DeviceObject);
1913 if (!NT_SUCCESS(Status))
1914 {
1915 NDIS_DbgPrint(MIN_TRACE, ("Could not create device object.\n"));
1916 RtlFreeUnicodeString(&ExportName);
1917 return Status;
1918 }
1919
1920 /*
1921 * Initialize the adapter structure.
1922 */
1923
1924 Adapter = (PLOGICAL_ADAPTER)DeviceObject->DeviceExtension;
1925 KeInitializeSpinLock(&Adapter->NdisMiniportBlock.Lock);
1926 InitializeListHead(&Adapter->ProtocolListHead);
1927 Adapter->NdisMiniportBlock.DriverHandle = Miniport;
1928
1929 Adapter->NdisMiniportBlock.MiniportName = ExportName;
1930
1931 Adapter->NdisMiniportBlock.DeviceObject = DeviceObject;
1932 Adapter->NdisMiniportBlock.PhysicalDeviceObject = PhysicalDeviceObject;
1933 Adapter->NdisMiniportBlock.NextDeviceObject =
1934 IoAttachDeviceToDeviceStack(Adapter->NdisMiniportBlock.DeviceObject,
1935 PhysicalDeviceObject);
1936
1937 Adapter->NdisMiniportBlock.OldPnPDeviceState = 0;
1938 Adapter->NdisMiniportBlock.PnPDeviceState = NdisPnPDeviceAdded;
1939
1940 KeInitializeTimer(&Adapter->NdisMiniportBlock.WakeUpDpcTimer.Timer);
1941 KeInitializeDpc(&Adapter->NdisMiniportBlock.WakeUpDpcTimer.Dpc, MiniportHangDpc, Adapter);
1942 KeInitializeDpc(&Adapter->NdisMiniportBlock.DeferredDpc, MiniportDpc, Adapter);
1943
1944 DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
1945
1946 return STATUS_SUCCESS;
1947 }
1948
1949 \f
1950 /*
1951 * @implemented
1952 */
1953 NDIS_STATUS
1954 EXPORT
1955 NdisMRegisterMiniport(
1956 IN NDIS_HANDLE NdisWrapperHandle,
1957 IN PNDIS_MINIPORT_CHARACTERISTICS MiniportCharacteristics,
1958 IN UINT CharacteristicsLength)
1959 /*
1960 * FUNCTION: Registers a miniport's MiniportXxx entry points with the NDIS library
1961 * ARGUMENTS:
1962 * NdisWrapperHandle = Pointer to handle returned by NdisMInitializeWrapper
1963 * MiniportCharacteristics = Pointer to a buffer with miniport characteristics
1964 * CharacteristicsLength = Number of bytes in characteristics buffer
1965 * RETURNS:
1966 * Status of operation
1967 */
1968 {
1969 UINT MinSize;
1970 PNDIS_M_DRIVER_BLOCK Miniport = GET_MINIPORT_DRIVER(NdisWrapperHandle);
1971 PNDIS_M_DRIVER_BLOCK *MiniportPtr;
1972 NTSTATUS Status;
1973
1974 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
1975
1976 switch (MiniportCharacteristics->MajorNdisVersion)
1977 {
1978 case 0x03:
1979 MinSize = sizeof(NDIS30_MINIPORT_CHARACTERISTICS);
1980 break;
1981
1982 case 0x04:
1983 MinSize = sizeof(NDIS40_MINIPORT_CHARACTERISTICS);
1984 break;
1985
1986 case 0x05:
1987 MinSize = sizeof(NDIS50_MINIPORT_CHARACTERISTICS);
1988 break;
1989
1990 default:
1991 NDIS_DbgPrint(DEBUG_MINIPORT, ("Bad miniport characteristics version.\n"));
1992 return NDIS_STATUS_BAD_VERSION;
1993 }
1994
1995 if (CharacteristicsLength < MinSize)
1996 {
1997 NDIS_DbgPrint(DEBUG_MINIPORT, ("Bad miniport characteristics.\n"));
1998 return NDIS_STATUS_BAD_CHARACTERISTICS;
1999 }
2000
2001 /* Check if mandatory MiniportXxx functions are specified */
2002 if ((!MiniportCharacteristics->HaltHandler) ||
2003 (!MiniportCharacteristics->InitializeHandler)||
2004 (!MiniportCharacteristics->QueryInformationHandler) ||
2005 (!MiniportCharacteristics->ResetHandler) ||
2006 (!MiniportCharacteristics->SetInformationHandler))
2007 {
2008 NDIS_DbgPrint(DEBUG_MINIPORT, ("Bad miniport characteristics.\n"));
2009 return NDIS_STATUS_BAD_CHARACTERISTICS;
2010 }
2011
2012 if (MiniportCharacteristics->MajorNdisVersion == 0x03)
2013 {
2014 if (!MiniportCharacteristics->SendHandler)
2015 {
2016 NDIS_DbgPrint(DEBUG_MINIPORT, ("Bad miniport characteristics.\n"));
2017 return NDIS_STATUS_BAD_CHARACTERISTICS;
2018 }
2019 }
2020 else if (MiniportCharacteristics->MajorNdisVersion >= 0x04)
2021 {
2022 /* NDIS 4.0+ */
2023 if ((!MiniportCharacteristics->SendHandler) &&
2024 (!MiniportCharacteristics->SendPacketsHandler))
2025 {
2026 NDIS_DbgPrint(DEBUG_MINIPORT, ("Bad miniport characteristics.\n"));
2027 return NDIS_STATUS_BAD_CHARACTERISTICS;
2028 }
2029 }
2030
2031 /* TODO: verify NDIS5 and NDIS5.1 */
2032
2033 RtlCopyMemory(&Miniport->MiniportCharacteristics, MiniportCharacteristics, MinSize);
2034
2035 /*
2036 * NOTE: This is VERY unoptimal! Should we store the NDIS_M_DRIVER_BLOCK
2037 * structure in the driver extension or what?
2038 */
2039
2040 Status = IoAllocateDriverObjectExtension(Miniport->DriverObject, (PVOID)TAG('D','I','M','N'),
2041 sizeof(PNDIS_M_DRIVER_BLOCK), (PVOID*)&MiniportPtr);
2042 if (!NT_SUCCESS(Status))
2043 {
2044 NDIS_DbgPrint(DEBUG_MINIPORT, ("Can't allocate driver object extension.\n"));
2045 return NDIS_STATUS_RESOURCES;
2046 }
2047
2048 *MiniportPtr = Miniport;
2049
2050 Miniport->DriverObject->MajorFunction[IRP_MJ_PNP] = NdisIDispatchPnp;
2051 Miniport->DriverObject->DriverExtension->AddDevice = NdisIAddDevice;
2052
2053 return NDIS_STATUS_SUCCESS;
2054 }
2055
2056 \f
2057 /*
2058 * @implemented
2059 */
2060 #undef NdisMResetComplete
2061 VOID
2062 EXPORT
2063 NdisMResetComplete(
2064 IN NDIS_HANDLE MiniportAdapterHandle,
2065 IN NDIS_STATUS Status,
2066 IN BOOLEAN AddressingReset)
2067 {
2068 MiniResetComplete(MiniportAdapterHandle, Status, AddressingReset);
2069 }
2070
2071 \f
2072 /*
2073 * @implemented
2074 */
2075 #undef NdisMSendComplete
2076 VOID
2077 EXPORT
2078 NdisMSendComplete(
2079 IN NDIS_HANDLE MiniportAdapterHandle,
2080 IN PNDIS_PACKET Packet,
2081 IN NDIS_STATUS Status)
2082 /*
2083 * FUNCTION: Forwards a message to the initiating protocol saying
2084 * that a packet was handled
2085 * ARGUMENTS:
2086 * NdisAdapterHandle = Handle input to MiniportInitialize
2087 * Packet = Pointer to NDIS packet that was sent
2088 * Status = Status of send operation
2089 */
2090 {
2091 MiniSendComplete(MiniportAdapterHandle, Packet, Status);
2092 }
2093
2094 \f
2095 /*
2096 * @implemented
2097 */
2098 #undef NdisMSendResourcesAvailable
2099 VOID
2100 EXPORT
2101 NdisMSendResourcesAvailable(
2102 IN NDIS_HANDLE MiniportAdapterHandle)
2103 {
2104 MiniSendResourcesAvailable(MiniportAdapterHandle);
2105 }
2106
2107 \f
2108 /*
2109 * @implemented
2110 */
2111 #undef NdisMTransferDataComplete
2112 VOID
2113 EXPORT
2114 NdisMTransferDataComplete(
2115 IN NDIS_HANDLE MiniportAdapterHandle,
2116 IN PNDIS_PACKET Packet,
2117 IN NDIS_STATUS Status,
2118 IN UINT BytesTransferred)
2119 {
2120 MiniTransferDataComplete(MiniportAdapterHandle, Packet, Status, BytesTransferred);
2121 }
2122
2123 \f
2124 /*
2125 * @implemented
2126 */
2127 #undef NdisMSetInformationComplete
2128 VOID
2129 EXPORT
2130 NdisMSetInformationComplete(
2131 IN NDIS_HANDLE MiniportAdapterHandle,
2132 IN NDIS_STATUS Status)
2133 {
2134 PLOGICAL_ADAPTER Adapter =
2135 (PLOGICAL_ADAPTER)MiniportAdapterHandle;
2136 KIRQL OldIrql;
2137 ASSERT(Adapter);
2138 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
2139 (Adapter->NdisMiniportBlock.SetCompleteHandler)(MiniportAdapterHandle, Status);
2140 KeAcquireSpinLockAtDpcLevel(&Adapter->NdisMiniportBlock.Lock);
2141 Adapter->MiniportBusy = FALSE;
2142 KeReleaseSpinLockFromDpcLevel(&Adapter->NdisMiniportBlock.Lock);
2143 KeLowerIrql(OldIrql);
2144 }
2145
2146 \f
2147 /*
2148 * @implemented
2149 */
2150 #undef NdisMSetAttributes
2151 VOID
2152 EXPORT
2153 NdisMSetAttributes(
2154 IN NDIS_HANDLE MiniportAdapterHandle,
2155 IN NDIS_HANDLE MiniportAdapterContext,
2156 IN BOOLEAN BusMaster,
2157 IN NDIS_INTERFACE_TYPE AdapterType)
2158 /*
2159 * FUNCTION: Informs the NDIS library of significant features of the caller's NIC
2160 * ARGUMENTS:
2161 * MiniportAdapterHandle = Handle input to MiniportInitialize
2162 * MiniportAdapterContext = Pointer to context information
2163 * BusMaster = Specifies TRUE if the caller's NIC is a busmaster DMA device
2164 * AdapterType = Specifies the I/O bus interface of the caller's NIC
2165 */
2166 {
2167 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
2168 NdisMSetAttributesEx(MiniportAdapterHandle, MiniportAdapterContext, 0,
2169 BusMaster ? NDIS_ATTRIBUTE_BUS_MASTER : 0,
2170 AdapterType);
2171 }
2172
2173 \f
2174 /*
2175 * @implemented
2176 */
2177 VOID
2178 EXPORT
2179 NdisMSetAttributesEx(
2180 IN NDIS_HANDLE MiniportAdapterHandle,
2181 IN NDIS_HANDLE MiniportAdapterContext,
2182 IN UINT CheckForHangTimeInSeconds OPTIONAL,
2183 IN ULONG AttributeFlags,
2184 IN NDIS_INTERFACE_TYPE AdapterType)
2185 /*
2186 * FUNCTION: Informs the NDIS library of significant features of the caller's NIC
2187 * ARGUMENTS:
2188 * MiniportAdapterHandle = Handle input to MiniportInitialize
2189 * MiniportAdapterContext = Pointer to context information
2190 * CheckForHangTimeInSeconds = Specifies interval in seconds at which
2191 * MiniportCheckForHang should be called
2192 * AttributeFlags = Bitmask that indicates specific attributes
2193 * AdapterType = Specifies the I/O bus interface of the caller's NIC
2194 */
2195 {
2196 PLOGICAL_ADAPTER Adapter = GET_LOGICAL_ADAPTER(MiniportAdapterHandle);
2197
2198 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
2199
2200 Adapter->NdisMiniportBlock.MiniportAdapterContext = MiniportAdapterContext;
2201 Adapter->NdisMiniportBlock.Flags = AttributeFlags;
2202 Adapter->NdisMiniportBlock.AdapterType = AdapterType;
2203 if (CheckForHangTimeInSeconds > 0)
2204 Adapter->NdisMiniportBlock.CheckForHangSeconds = CheckForHangTimeInSeconds;
2205 if (AttributeFlags & NDIS_ATTRIBUTE_INTERMEDIATE_DRIVER)
2206 NDIS_DbgPrint(MAX_TRACE, ("Intermediate drivers not supported yet.\n"));
2207 }
2208
2209 \f
2210 /*
2211 * @implemented
2212 */
2213 VOID
2214 EXPORT
2215 NdisMSleep(
2216 IN ULONG MicrosecondsToSleep)
2217 /*
2218 * FUNCTION: delay the thread's execution for MicrosecondsToSleep
2219 * ARGUMENTS:
2220 * MicrosecondsToSleep: duh...
2221 * NOTES:
2222 * - Because this is a blocking call, current IRQL must be < DISPATCH_LEVEL
2223 */
2224 {
2225 KTIMER Timer;
2226 LARGE_INTEGER DueTime;
2227
2228 PAGED_CODE();
2229
2230 DueTime.QuadPart = (-1) * 10 * MicrosecondsToSleep;
2231
2232 KeInitializeTimer(&Timer);
2233 KeSetTimer(&Timer, DueTime, 0);
2234 KeWaitForSingleObject(&Timer, Executive, KernelMode, FALSE, 0);
2235 }
2236
2237 \f
2238 /*
2239 * @implemented
2240 */
2241 BOOLEAN
2242 EXPORT
2243 NdisMSynchronizeWithInterrupt(
2244 IN PNDIS_MINIPORT_INTERRUPT Interrupt,
2245 IN PVOID SynchronizeFunction,
2246 IN PVOID SynchronizeContext)
2247 {
2248 return(KeSynchronizeExecution(Interrupt->InterruptObject,
2249 (PKSYNCHRONIZE_ROUTINE)SynchronizeFunction,
2250 SynchronizeContext));
2251 }
2252
2253 \f
2254 /*
2255 * @unimplemented
2256 */
2257 NDIS_STATUS
2258 EXPORT
2259 NdisMWriteLogData(
2260 IN NDIS_HANDLE LogHandle,
2261 IN PVOID LogBuffer,
2262 IN UINT LogBufferSize)
2263 {
2264 PUCHAR Buffer = LogBuffer;
2265 UINT i, j, idx;
2266
2267 UNIMPLEMENTED;
2268 for (i = 0; i < LogBufferSize; i += 16)
2269 {
2270 DbgPrint("%08x |", i);
2271 for (j = 0; j < 16; j++)
2272 {
2273 idx = i + j;
2274 if (idx < LogBufferSize)
2275 DbgPrint(" %02x", Buffer[idx]);
2276 else
2277 DbgPrint(" ");
2278 }
2279 DbgPrint(" | ");
2280 for (j = 0; j < 16; j++)
2281 {
2282 idx = i + j;
2283 if (idx == LogBufferSize)
2284 break;
2285 if (Buffer[idx] >= ' ') /* FIXME: not portable! replace by if (isprint(Buffer[idx])) ? */
2286 DbgPrint("%c", Buffer[idx]);
2287 else
2288 DbgPrint(".");
2289 }
2290 DbgPrint("\n");
2291 }
2292
2293 return NDIS_STATUS_FAILURE;
2294 }
2295
2296 \f
2297 /*
2298 * @implemented
2299 */
2300 VOID
2301 EXPORT
2302 NdisTerminateWrapper(
2303 IN NDIS_HANDLE NdisWrapperHandle,
2304 IN PVOID SystemSpecific)
2305 /*
2306 * FUNCTION: Releases resources allocated by a call to NdisInitializeWrapper
2307 * ARGUMENTS:
2308 * NdisWrapperHandle = Handle returned by NdisInitializeWrapper (NDIS_M_DRIVER_BLOCK)
2309 * SystemSpecific = Always NULL
2310 */
2311 {
2312 PNDIS_M_DRIVER_BLOCK Miniport = GET_MINIPORT_DRIVER(NdisWrapperHandle);
2313
2314 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
2315
2316 ExFreePool(Miniport->RegistryPath->Buffer);
2317 ExFreePool(Miniport->RegistryPath);
2318 ExFreePool(Miniport);
2319 }
2320
2321 /* EOF */
2322