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