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