- Remove some extra junk
[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 NdisCloseConfiguration(ConfigHandle);
1821
1822 /* Set handlers (some NDIS macros require these) */
1823 Adapter->NdisMiniportBlock.EthRxCompleteHandler = EthFilterDprIndicateReceiveComplete;
1824 Adapter->NdisMiniportBlock.EthRxIndicateHandler = EthFilterDprIndicateReceive;
1825 Adapter->NdisMiniportBlock.SendCompleteHandler = MiniSendComplete;
1826 Adapter->NdisMiniportBlock.SendResourcesHandler = MiniSendResourcesAvailable;
1827 Adapter->NdisMiniportBlock.ResetCompleteHandler = MiniResetComplete;
1828 Adapter->NdisMiniportBlock.TDCompleteHandler = MiniTransferDataComplete;
1829 Adapter->NdisMiniportBlock.PacketIndicateHandler= MiniIndicateReceivePacket;
1830 Adapter->NdisMiniportBlock.StatusHandler = MiniStatus;
1831 Adapter->NdisMiniportBlock.StatusCompleteHandler= MiniStatusComplete;
1832 Adapter->NdisMiniportBlock.SendPacketsHandler = ProSendPackets;
1833 Adapter->NdisMiniportBlock.QueryCompleteHandler = MiniRequestComplete;
1834 Adapter->NdisMiniportBlock.SetCompleteHandler = MiniRequestComplete;
1835
1836 /*
1837 * Call MiniportInitialize.
1838 */
1839
1840 NDIS_DbgPrint(MID_TRACE, ("calling MiniportInitialize\n"));
1841 NdisStatus = (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.InitializeHandler)(
1842 &OpenErrorStatus, &SelectedMediumIndex, &MediaArray[0],
1843 MEDIA_ARRAY_SIZE, Adapter, (NDIS_HANDLE)&WrapperContext);
1844
1845 ZwClose(WrapperContext.RegistryHandle);
1846
1847 if (NdisStatus != NDIS_STATUS_SUCCESS)
1848 {
1849 NDIS_DbgPrint(MIN_TRACE, ("MiniportInitialize() failed for an adapter.\n"));
1850 ExInterlockedRemoveEntryList( &Adapter->ListEntry, &AdapterListLock );
1851 return NdisStatus;
1852 }
1853
1854 if (SelectedMediumIndex >= MEDIA_ARRAY_SIZE)
1855 {
1856 NDIS_DbgPrint(MIN_TRACE, ("MiniportInitialize() failed for an adapter\n"));
1857 ExInterlockedRemoveEntryList( &Adapter->ListEntry, &AdapterListLock );
1858 return NDIS_STATUS_UNSUPPORTED_MEDIA;
1859 }
1860
1861 Adapter->NdisMiniportBlock.MediaType = MediaArray[SelectedMediumIndex];
1862
1863 switch (Adapter->NdisMiniportBlock.MediaType)
1864 {
1865 case NdisMedium802_3:
1866 Adapter->MediumHeaderSize = 14; /* XXX figure out what to do about LLC */
1867 AddressOID = OID_802_3_CURRENT_ADDRESS;
1868 Adapter->AddressLength = ETH_LENGTH_OF_ADDRESS;
1869 NdisStatus = DoQueries(Adapter, AddressOID);
1870 if (NdisStatus == NDIS_STATUS_SUCCESS)
1871 {
1872 NdisStatus = MiniQueryInformation(Adapter, OID_802_3_MAXIMUM_LIST_SIZE, sizeof(UINT),
1873 &MaxMulticastAddresses, &BytesWritten);
1874
1875 if (NdisStatus != NDIS_STATUS_SUCCESS)
1876 {
1877 ExInterlockedRemoveEntryList( &Adapter->ListEntry, &AdapterListLock );
1878 NDIS_DbgPrint(MAX_TRACE, ("MiniQueryInformation failed (%x)\n", NdisStatus));
1879 return NdisStatus;
1880 }
1881
1882 Success = EthCreateFilter(MaxMulticastAddresses,
1883 Adapter->Address.Type.Medium802_3,
1884 &Adapter->NdisMiniportBlock.EthDB);
1885 if (Success)
1886 ((PETHI_FILTER)Adapter->NdisMiniportBlock.EthDB)->Miniport = (PNDIS_MINIPORT_BLOCK)Adapter;
1887 else
1888 NdisStatus = NDIS_STATUS_RESOURCES;
1889 }
1890 break;
1891
1892 default:
1893 /* FIXME: Support other types of media */
1894 NDIS_DbgPrint(MIN_TRACE, ("error: unsupported media\n"));
1895 ASSERT(FALSE);
1896 /* FIXME - KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql); */
1897 ExInterlockedRemoveEntryList( &Adapter->ListEntry, &AdapterListLock );
1898 return STATUS_UNSUCCESSFUL;
1899 }
1900
1901 if (NdisStatus != NDIS_STATUS_SUCCESS)
1902 {
1903 NDIS_DbgPrint(MAX_TRACE, ("couldn't create filter (%x)\n", NdisStatus));
1904 return NdisStatus;
1905 }
1906
1907 /* Check for a hang every two seconds if it wasn't set in MiniportInitialize */
1908 if (Adapter->NdisMiniportBlock.CheckForHangSeconds == 0)
1909 Adapter->NdisMiniportBlock.CheckForHangSeconds = 2;
1910
1911 Adapter->NdisMiniportBlock.OldPnPDeviceState = Adapter->NdisMiniportBlock.PnPDeviceState;
1912 Adapter->NdisMiniportBlock.PnPDeviceState = NdisPnPDeviceStarted;
1913
1914 Timeout.QuadPart = Int32x32To64(Adapter->NdisMiniportBlock.CheckForHangSeconds, -1000000);
1915 KeSetTimerEx(&Adapter->NdisMiniportBlock.WakeUpDpcTimer.Timer, Timeout,
1916 Adapter->NdisMiniportBlock.CheckForHangSeconds * 1000,
1917 &Adapter->NdisMiniportBlock.WakeUpDpcTimer.Dpc);
1918
1919 /* Put adapter in adapter list for this miniport */
1920 ExInterlockedInsertTailList(&Adapter->NdisMiniportBlock.DriverHandle->DeviceList, &Adapter->MiniportListEntry, &Adapter->NdisMiniportBlock.DriverHandle->Lock);
1921
1922 return STATUS_SUCCESS;
1923 }
1924
1925 \f
1926 NTSTATUS
1927 NTAPI
1928 NdisIPnPStopDevice(
1929 IN PDEVICE_OBJECT DeviceObject,
1930 PIRP Irp)
1931 /*
1932 * FUNCTION: Handle the PnP stop device event
1933 * ARGUMENTS:
1934 * DeviceObejct = Functional Device Object
1935 * Irp = IRP_MN_STOP_DEVICE I/O request packet
1936 * RETURNS:
1937 * Status of operation
1938 */
1939 {
1940 PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)DeviceObject->DeviceExtension;
1941
1942 /* Remove adapter from adapter list for this miniport */
1943 ExInterlockedRemoveEntryList(&Adapter->MiniportListEntry, &Adapter->NdisMiniportBlock.DriverHandle->Lock);
1944
1945 /* Remove adapter from global adapter list */
1946 ExInterlockedRemoveEntryList(&Adapter->ListEntry, &AdapterListLock);
1947
1948 KeCancelTimer(&Adapter->NdisMiniportBlock.WakeUpDpcTimer.Timer);
1949
1950 (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.HaltHandler)(Adapter);
1951
1952 if (Adapter->NdisMiniportBlock.AllocatedResources)
1953 {
1954 ExFreePool(Adapter->NdisMiniportBlock.AllocatedResources);
1955 Adapter->NdisMiniportBlock.AllocatedResources = NULL;
1956 }
1957 if (Adapter->NdisMiniportBlock.AllocatedResourcesTranslated)
1958 {
1959 ExFreePool(Adapter->NdisMiniportBlock.AllocatedResourcesTranslated);
1960 Adapter->NdisMiniportBlock.AllocatedResourcesTranslated = NULL;
1961 }
1962
1963 if (Adapter->NdisMiniportBlock.Resources)
1964 {
1965 ExFreePool(Adapter->NdisMiniportBlock.Resources);
1966 Adapter->NdisMiniportBlock.Resources = NULL;
1967 }
1968
1969 if (Adapter->NdisMiniportBlock.EthDB)
1970 {
1971 EthDeleteFilter(Adapter->NdisMiniportBlock.EthDB);
1972 Adapter->NdisMiniportBlock.EthDB = NULL;
1973 }
1974
1975 Adapter->NdisMiniportBlock.OldPnPDeviceState = Adapter->NdisMiniportBlock.PnPDeviceState;
1976 Adapter->NdisMiniportBlock.PnPDeviceState = NdisPnPDeviceStopped;
1977
1978 return STATUS_SUCCESS;
1979 }
1980
1981 NTSTATUS
1982 NTAPI
1983 NdisIShutdown(
1984 IN PDEVICE_OBJECT DeviceObject,
1985 PIRP Irp)
1986 {
1987 PLOGICAL_ADAPTER Adapter = DeviceObject->DeviceExtension;
1988 PMINIPORT_BUGCHECK_CONTEXT Context = Adapter->BugcheckContext;
1989 ADAPTER_SHUTDOWN_HANDLER ShutdownHandler = Context->ShutdownHandler;
1990
1991 ASSERT(ShutdownHandler);
1992
1993 ShutdownHandler(Context->DriverContext);
1994
1995 Irp->IoStatus.Status = STATUS_SUCCESS;
1996 Irp->IoStatus.Information = 0;
1997
1998 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1999
2000 return STATUS_SUCCESS;
2001 }
2002
2003 NTSTATUS
2004 NTAPI
2005 NdisIDeviceIoControl(
2006 IN PDEVICE_OBJECT DeviceObject,
2007 PIRP Irp)
2008 {
2009 PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)DeviceObject->DeviceExtension;
2010 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
2011 NDIS_STATUS Status = STATUS_NOT_SUPPORTED;
2012
2013 Irp->IoStatus.Information = 0;
2014
2015 ASSERT(Adapter);
2016
2017 switch (Stack->Parameters.DeviceIoControl.IoControlCode)
2018 {
2019 case IOCTL_NDIS_QUERY_GLOBAL_STATS:
2020 Status = MiniQueryInformation(Adapter,
2021 (NDIS_OID)Irp->AssociatedIrp.SystemBuffer,
2022 Stack->Parameters.DeviceIoControl.OutputBufferLength,
2023 MmGetSystemAddressForMdl(Irp->MdlAddress),
2024 &Irp->IoStatus.Information);
2025 break;
2026
2027 default:
2028 ASSERT(FALSE);
2029 break;
2030 }
2031
2032 if (Status != NDIS_STATUS_PENDING)
2033 {
2034 Irp->IoStatus.Status = Status;
2035 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2036 }
2037 else
2038 IoMarkIrpPending(Irp);
2039
2040 return Status;
2041 }
2042
2043 \f
2044 NTSTATUS
2045 NTAPI
2046 NdisIDispatchPnp(
2047 IN PDEVICE_OBJECT DeviceObject,
2048 PIRP Irp)
2049 {
2050 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
2051 PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)DeviceObject->DeviceExtension;
2052 NTSTATUS Status;
2053
2054 switch (Stack->MinorFunction)
2055 {
2056 case IRP_MN_START_DEVICE:
2057 Status = NdisIForwardIrpAndWait(Adapter, Irp);
2058 if (NT_SUCCESS(Status) && NT_SUCCESS(Irp->IoStatus.Status))
2059 {
2060 Status = NdisIPnPStartDevice(DeviceObject, Irp);
2061 }
2062 Irp->IoStatus.Status = Status;
2063 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2064 break;
2065
2066 case IRP_MN_STOP_DEVICE:
2067 Status = NdisIForwardIrpAndWait(Adapter, Irp);
2068 if (NT_SUCCESS(Status) && NT_SUCCESS(Irp->IoStatus.Status))
2069 {
2070 Status = NdisIPnPStopDevice(DeviceObject, Irp);
2071 }
2072 Irp->IoStatus.Status = Status;
2073 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2074 break;
2075
2076 case IRP_MN_QUERY_REMOVE_DEVICE:
2077 case IRP_MN_QUERY_STOP_DEVICE:
2078 Status = NdisIPnPQueryStopDevice(DeviceObject, Irp);
2079 Irp->IoStatus.Status = Status;
2080 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2081 break;
2082
2083 case IRP_MN_CANCEL_REMOVE_DEVICE:
2084 case IRP_MN_CANCEL_STOP_DEVICE:
2085 Status = NdisIPnPCancelStopDevice(DeviceObject, Irp);
2086 Irp->IoStatus.Status = Status;
2087 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2088 break;
2089
2090 default:
2091 IoSkipCurrentIrpStackLocation(Irp);
2092 Status = IoCallDriver(Adapter->NdisMiniportBlock.NextDeviceObject, Irp);
2093 break;
2094 }
2095
2096 return Status;
2097 }
2098
2099 \f
2100 NTSTATUS
2101 NTAPI
2102 NdisIAddDevice(
2103 IN PDRIVER_OBJECT DriverObject,
2104 IN PDEVICE_OBJECT PhysicalDeviceObject)
2105 /*
2106 * FUNCTION: Create a device for an adapter found using PnP
2107 * ARGUMENTS:
2108 * DriverObject = Pointer to the miniport driver object
2109 * PhysicalDeviceObject = Pointer to the PDO for our adapter
2110 */
2111 {
2112 static const WCHAR ClassKeyName[] = {'C','l','a','s','s','\\'};
2113 static const WCHAR LinkageKeyName[] = {'\\','L','i','n','k','a','g','e',0};
2114 PNDIS_M_DRIVER_BLOCK Miniport;
2115 PNDIS_M_DRIVER_BLOCK *MiniportPtr;
2116 WCHAR *LinkageKeyBuffer;
2117 ULONG DriverKeyLength;
2118 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
2119 UNICODE_STRING ExportName;
2120 PDEVICE_OBJECT DeviceObject;
2121 PLOGICAL_ADAPTER Adapter;
2122 NTSTATUS Status;
2123
2124 /*
2125 * Gain the access to the miniport data structure first.
2126 */
2127
2128 MiniportPtr = IoGetDriverObjectExtension(DriverObject, (PVOID)TAG('D','I','M','N'));
2129 if (MiniportPtr == NULL)
2130 {
2131 NDIS_DbgPrint(DEBUG_MINIPORT, ("Can't get driver object extension.\n"));
2132 return STATUS_UNSUCCESSFUL;
2133 }
2134 Miniport = *MiniportPtr;
2135
2136 /*
2137 * Get name of the Linkage registry key for our adapter. It's located under
2138 * the driver key for our driver and so we have basicly two ways to do it.
2139 * Either we can use IoOpenDriverRegistryKey or compose it using information
2140 * gathered by IoGetDeviceProperty. I choosed the second because
2141 * IoOpenDriverRegistryKey wasn't implemented at the time of writing.
2142 */
2143
2144 Status = IoGetDeviceProperty(PhysicalDeviceObject, DevicePropertyDriverKeyName,
2145 0, NULL, &DriverKeyLength);
2146 if (Status != STATUS_BUFFER_TOO_SMALL && Status != STATUS_BUFFER_OVERFLOW && Status != STATUS_SUCCESS)
2147 {
2148 NDIS_DbgPrint(DEBUG_MINIPORT, ("Can't get miniport driver key length.\n"));
2149 return Status;
2150 }
2151
2152 LinkageKeyBuffer = ExAllocatePool(PagedPool, DriverKeyLength +
2153 sizeof(ClassKeyName) + sizeof(LinkageKeyName));
2154 if (LinkageKeyBuffer == NULL)
2155 {
2156 NDIS_DbgPrint(DEBUG_MINIPORT, ("Can't allocate memory for driver key name.\n"));
2157 return STATUS_INSUFFICIENT_RESOURCES;
2158 }
2159
2160 Status = IoGetDeviceProperty(PhysicalDeviceObject, DevicePropertyDriverKeyName,
2161 DriverKeyLength, LinkageKeyBuffer +
2162 (sizeof(ClassKeyName) / sizeof(WCHAR)),
2163 &DriverKeyLength);
2164 if (!NT_SUCCESS(Status))
2165 {
2166 NDIS_DbgPrint(DEBUG_MINIPORT, ("Can't get miniport driver key.\n"));
2167 ExFreePool(LinkageKeyBuffer);
2168 return Status;
2169 }
2170
2171 /* Compose the linkage key name. */
2172 RtlCopyMemory(LinkageKeyBuffer, ClassKeyName, sizeof(ClassKeyName));
2173 RtlCopyMemory(LinkageKeyBuffer + ((sizeof(ClassKeyName) + DriverKeyLength) /
2174 sizeof(WCHAR)) - 1, LinkageKeyName, sizeof(LinkageKeyName));
2175
2176 NDIS_DbgPrint(DEBUG_MINIPORT, ("LinkageKey: %S.\n", LinkageKeyBuffer));
2177
2178 /*
2179 * Now open the linkage key and read the "Export" and "RootDevice" values
2180 * which contains device name and root service respectively.
2181 */
2182
2183 RtlZeroMemory(QueryTable, sizeof(QueryTable));
2184 RtlInitUnicodeString(&ExportName, NULL);
2185 QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_DIRECT;
2186 QueryTable[0].Name = L"Export";
2187 QueryTable[0].EntryContext = &ExportName;
2188
2189 Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL, LinkageKeyBuffer,
2190 QueryTable, NULL, NULL);
2191 ExFreePool(LinkageKeyBuffer);
2192 if (!NT_SUCCESS(Status))
2193 {
2194 NDIS_DbgPrint(DEBUG_MINIPORT, ("Can't get miniport device name. (%x)\n", Status));
2195 return Status;
2196 }
2197
2198 /*
2199 * Create the device object.
2200 */
2201
2202 NDIS_DbgPrint(MAX_TRACE, ("creating device %wZ\n", &ExportName));
2203
2204 Status = IoCreateDevice(Miniport->DriverObject, sizeof(LOGICAL_ADAPTER),
2205 &ExportName, FILE_DEVICE_PHYSICAL_NETCARD,
2206 0, FALSE, &DeviceObject);
2207 if (!NT_SUCCESS(Status))
2208 {
2209 NDIS_DbgPrint(MIN_TRACE, ("Could not create device object.\n"));
2210 RtlFreeUnicodeString(&ExportName);
2211 return Status;
2212 }
2213
2214 /*
2215 * Initialize the adapter structure.
2216 */
2217
2218 Adapter = (PLOGICAL_ADAPTER)DeviceObject->DeviceExtension;
2219 KeInitializeSpinLock(&Adapter->NdisMiniportBlock.Lock);
2220 InitializeListHead(&Adapter->ProtocolListHead);
2221 Adapter->NdisMiniportBlock.DriverHandle = Miniport;
2222
2223 Adapter->NdisMiniportBlock.MiniportName = ExportName;
2224
2225 Adapter->NdisMiniportBlock.DeviceObject = DeviceObject;
2226 Adapter->NdisMiniportBlock.PhysicalDeviceObject = PhysicalDeviceObject;
2227 Adapter->NdisMiniportBlock.NextDeviceObject =
2228 IoAttachDeviceToDeviceStack(Adapter->NdisMiniportBlock.DeviceObject,
2229 PhysicalDeviceObject);
2230
2231 Adapter->NdisMiniportBlock.OldPnPDeviceState = 0;
2232 Adapter->NdisMiniportBlock.PnPDeviceState = NdisPnPDeviceAdded;
2233
2234 KeInitializeTimer(&Adapter->NdisMiniportBlock.WakeUpDpcTimer.Timer);
2235 KeInitializeDpc(&Adapter->NdisMiniportBlock.WakeUpDpcTimer.Dpc, MiniportHangDpc, Adapter);
2236
2237 DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
2238
2239 return STATUS_SUCCESS;
2240 }
2241
2242 \f
2243 /*
2244 * @implemented
2245 */
2246 NDIS_STATUS
2247 EXPORT
2248 NdisMRegisterMiniport(
2249 IN NDIS_HANDLE NdisWrapperHandle,
2250 IN PNDIS_MINIPORT_CHARACTERISTICS MiniportCharacteristics,
2251 IN UINT CharacteristicsLength)
2252 /*
2253 * FUNCTION: Registers a miniport's MiniportXxx entry points with the NDIS library
2254 * ARGUMENTS:
2255 * NdisWrapperHandle = Pointer to handle returned by NdisMInitializeWrapper
2256 * MiniportCharacteristics = Pointer to a buffer with miniport characteristics
2257 * CharacteristicsLength = Number of bytes in characteristics buffer
2258 * RETURNS:
2259 * Status of operation
2260 */
2261 {
2262 UINT MinSize;
2263 PNDIS_M_DRIVER_BLOCK Miniport = GET_MINIPORT_DRIVER(NdisWrapperHandle);
2264 PNDIS_M_DRIVER_BLOCK *MiniportPtr;
2265 NTSTATUS Status;
2266
2267 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
2268
2269 switch (MiniportCharacteristics->MajorNdisVersion)
2270 {
2271 case 0x03:
2272 MinSize = sizeof(NDIS30_MINIPORT_CHARACTERISTICS);
2273 break;
2274
2275 case 0x04:
2276 MinSize = sizeof(NDIS40_MINIPORT_CHARACTERISTICS);
2277 break;
2278
2279 case 0x05:
2280 MinSize = sizeof(NDIS50_MINIPORT_CHARACTERISTICS);
2281 break;
2282
2283 default:
2284 NDIS_DbgPrint(DEBUG_MINIPORT, ("Bad miniport characteristics version.\n"));
2285 return NDIS_STATUS_BAD_VERSION;
2286 }
2287
2288 if (CharacteristicsLength < MinSize)
2289 {
2290 NDIS_DbgPrint(DEBUG_MINIPORT, ("Bad miniport characteristics.\n"));
2291 return NDIS_STATUS_BAD_CHARACTERISTICS;
2292 }
2293
2294 /* Check if mandatory MiniportXxx functions are specified */
2295 if ((!MiniportCharacteristics->HaltHandler) ||
2296 (!MiniportCharacteristics->InitializeHandler)||
2297 (!MiniportCharacteristics->QueryInformationHandler) ||
2298 (!MiniportCharacteristics->ResetHandler) ||
2299 (!MiniportCharacteristics->SetInformationHandler))
2300 {
2301 NDIS_DbgPrint(DEBUG_MINIPORT, ("Bad miniport characteristics.\n"));
2302 return NDIS_STATUS_BAD_CHARACTERISTICS;
2303 }
2304
2305 if (MiniportCharacteristics->MajorNdisVersion == 0x03)
2306 {
2307 if (!MiniportCharacteristics->SendHandler)
2308 {
2309 NDIS_DbgPrint(DEBUG_MINIPORT, ("Bad miniport characteristics.\n"));
2310 return NDIS_STATUS_BAD_CHARACTERISTICS;
2311 }
2312 }
2313 else if (MiniportCharacteristics->MajorNdisVersion >= 0x04)
2314 {
2315 /* NDIS 4.0+ */
2316 if ((!MiniportCharacteristics->SendHandler) &&
2317 (!MiniportCharacteristics->SendPacketsHandler))
2318 {
2319 NDIS_DbgPrint(DEBUG_MINIPORT, ("Bad miniport characteristics.\n"));
2320 return NDIS_STATUS_BAD_CHARACTERISTICS;
2321 }
2322 }
2323
2324 /* TODO: verify NDIS5 and NDIS5.1 */
2325
2326 RtlCopyMemory(&Miniport->MiniportCharacteristics, MiniportCharacteristics, MinSize);
2327
2328 /*
2329 * NOTE: This is VERY unoptimal! Should we store the NDIS_M_DRIVER_BLOCK
2330 * structure in the driver extension or what?
2331 */
2332
2333 Status = IoAllocateDriverObjectExtension(Miniport->DriverObject, (PVOID)TAG('D','I','M','N'),
2334 sizeof(PNDIS_M_DRIVER_BLOCK), (PVOID*)&MiniportPtr);
2335 if (!NT_SUCCESS(Status))
2336 {
2337 NDIS_DbgPrint(DEBUG_MINIPORT, ("Can't allocate driver object extension.\n"));
2338 return NDIS_STATUS_RESOURCES;
2339 }
2340
2341 *MiniportPtr = Miniport;
2342
2343 Miniport->DriverObject->MajorFunction[IRP_MJ_PNP] = NdisIDispatchPnp;
2344 Miniport->DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = NdisIShutdown;
2345 Miniport->DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = NdisIDeviceIoControl;
2346 Miniport->DriverObject->DriverExtension->AddDevice = NdisIAddDevice;
2347
2348 return NDIS_STATUS_SUCCESS;
2349 }
2350
2351 \f
2352 /*
2353 * @implemented
2354 */
2355 #undef NdisMResetComplete
2356 VOID
2357 EXPORT
2358 NdisMResetComplete(
2359 IN NDIS_HANDLE MiniportAdapterHandle,
2360 IN NDIS_STATUS Status,
2361 IN BOOLEAN AddressingReset)
2362 {
2363 MiniResetComplete(MiniportAdapterHandle, Status, AddressingReset);
2364 }
2365
2366 \f
2367 /*
2368 * @implemented
2369 */
2370 #undef NdisMSendComplete
2371 VOID
2372 EXPORT
2373 NdisMSendComplete(
2374 IN NDIS_HANDLE MiniportAdapterHandle,
2375 IN PNDIS_PACKET Packet,
2376 IN NDIS_STATUS Status)
2377 /*
2378 * FUNCTION: Forwards a message to the initiating protocol saying
2379 * that a packet was handled
2380 * ARGUMENTS:
2381 * NdisAdapterHandle = Handle input to MiniportInitialize
2382 * Packet = Pointer to NDIS packet that was sent
2383 * Status = Status of send operation
2384 */
2385 {
2386 MiniSendComplete(MiniportAdapterHandle, Packet, Status);
2387 }
2388
2389 \f
2390 /*
2391 * @implemented
2392 */
2393 #undef NdisMSendResourcesAvailable
2394 VOID
2395 EXPORT
2396 NdisMSendResourcesAvailable(
2397 IN NDIS_HANDLE MiniportAdapterHandle)
2398 {
2399 MiniSendResourcesAvailable(MiniportAdapterHandle);
2400 }
2401
2402 \f
2403 /*
2404 * @implemented
2405 */
2406 #undef NdisMTransferDataComplete
2407 VOID
2408 EXPORT
2409 NdisMTransferDataComplete(
2410 IN NDIS_HANDLE MiniportAdapterHandle,
2411 IN PNDIS_PACKET Packet,
2412 IN NDIS_STATUS Status,
2413 IN UINT BytesTransferred)
2414 {
2415 MiniTransferDataComplete(MiniportAdapterHandle, Packet, Status, BytesTransferred);
2416 }
2417
2418 \f
2419 /*
2420 * @implemented
2421 */
2422 #undef NdisMSetAttributes
2423 VOID
2424 EXPORT
2425 NdisMSetAttributes(
2426 IN NDIS_HANDLE MiniportAdapterHandle,
2427 IN NDIS_HANDLE MiniportAdapterContext,
2428 IN BOOLEAN BusMaster,
2429 IN NDIS_INTERFACE_TYPE AdapterType)
2430 /*
2431 * FUNCTION: Informs the NDIS library of significant features of the caller's NIC
2432 * ARGUMENTS:
2433 * MiniportAdapterHandle = Handle input to MiniportInitialize
2434 * MiniportAdapterContext = Pointer to context information
2435 * BusMaster = Specifies TRUE if the caller's NIC is a busmaster DMA device
2436 * AdapterType = Specifies the I/O bus interface of the caller's NIC
2437 */
2438 {
2439 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
2440 NdisMSetAttributesEx(MiniportAdapterHandle, MiniportAdapterContext, 0,
2441 BusMaster ? NDIS_ATTRIBUTE_BUS_MASTER : 0,
2442 AdapterType);
2443 }
2444
2445 \f
2446 /*
2447 * @implemented
2448 */
2449 VOID
2450 EXPORT
2451 NdisMSetAttributesEx(
2452 IN NDIS_HANDLE MiniportAdapterHandle,
2453 IN NDIS_HANDLE MiniportAdapterContext,
2454 IN UINT CheckForHangTimeInSeconds OPTIONAL,
2455 IN ULONG AttributeFlags,
2456 IN NDIS_INTERFACE_TYPE AdapterType)
2457 /*
2458 * FUNCTION: Informs the NDIS library of significant features of the caller's NIC
2459 * ARGUMENTS:
2460 * MiniportAdapterHandle = Handle input to MiniportInitialize
2461 * MiniportAdapterContext = Pointer to context information
2462 * CheckForHangTimeInSeconds = Specifies interval in seconds at which
2463 * MiniportCheckForHang should be called
2464 * AttributeFlags = Bitmask that indicates specific attributes
2465 * AdapterType = Specifies the I/O bus interface of the caller's NIC
2466 */
2467 {
2468 PLOGICAL_ADAPTER Adapter = GET_LOGICAL_ADAPTER(MiniportAdapterHandle);
2469
2470 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
2471
2472 Adapter->NdisMiniportBlock.MiniportAdapterContext = MiniportAdapterContext;
2473 Adapter->NdisMiniportBlock.Flags = AttributeFlags;
2474 Adapter->NdisMiniportBlock.AdapterType = AdapterType;
2475 if (CheckForHangTimeInSeconds > 0)
2476 Adapter->NdisMiniportBlock.CheckForHangSeconds = CheckForHangTimeInSeconds;
2477 if (AttributeFlags & NDIS_ATTRIBUTE_INTERMEDIATE_DRIVER)
2478 NDIS_DbgPrint(MAX_TRACE, ("Intermediate drivers not supported yet.\n"));
2479 }
2480
2481 \f
2482 /*
2483 * @implemented
2484 */
2485 VOID
2486 EXPORT
2487 NdisMSleep(
2488 IN ULONG MicrosecondsToSleep)
2489 /*
2490 * FUNCTION: delay the thread's execution for MicrosecondsToSleep
2491 * ARGUMENTS:
2492 * MicrosecondsToSleep: duh...
2493 * NOTES:
2494 * - Because this is a blocking call, current IRQL must be < DISPATCH_LEVEL
2495 */
2496 {
2497 KTIMER Timer;
2498 LARGE_INTEGER DueTime;
2499
2500 PAGED_CODE();
2501
2502 DueTime.QuadPart = (-1) * 10 * MicrosecondsToSleep;
2503
2504 KeInitializeTimer(&Timer);
2505 KeSetTimer(&Timer, DueTime, 0);
2506 KeWaitForSingleObject(&Timer, Executive, KernelMode, FALSE, 0);
2507 }
2508
2509 \f
2510 /*
2511 * @implemented
2512 */
2513 BOOLEAN
2514 EXPORT
2515 NdisMSynchronizeWithInterrupt(
2516 IN PNDIS_MINIPORT_INTERRUPT Interrupt,
2517 IN PVOID SynchronizeFunction,
2518 IN PVOID SynchronizeContext)
2519 {
2520 return(KeSynchronizeExecution(Interrupt->InterruptObject,
2521 (PKSYNCHRONIZE_ROUTINE)SynchronizeFunction,
2522 SynchronizeContext));
2523 }
2524
2525 \f
2526 /*
2527 * @unimplemented
2528 */
2529 NDIS_STATUS
2530 EXPORT
2531 NdisMWriteLogData(
2532 IN NDIS_HANDLE LogHandle,
2533 IN PVOID LogBuffer,
2534 IN UINT LogBufferSize)
2535 {
2536 PUCHAR Buffer = LogBuffer;
2537 UINT i, j, idx;
2538
2539 UNIMPLEMENTED;
2540 for (i = 0; i < LogBufferSize; i += 16)
2541 {
2542 DbgPrint("%08x |", i);
2543 for (j = 0; j < 16; j++)
2544 {
2545 idx = i + j;
2546 if (idx < LogBufferSize)
2547 DbgPrint(" %02x", Buffer[idx]);
2548 else
2549 DbgPrint(" ");
2550 }
2551 DbgPrint(" | ");
2552 for (j = 0; j < 16; j++)
2553 {
2554 idx = i + j;
2555 if (idx == LogBufferSize)
2556 break;
2557 if (Buffer[idx] >= ' ') /* FIXME: not portable! replace by if (isprint(Buffer[idx])) ? */
2558 DbgPrint("%c", Buffer[idx]);
2559 else
2560 DbgPrint(".");
2561 }
2562 DbgPrint("\n");
2563 }
2564
2565 return NDIS_STATUS_FAILURE;
2566 }
2567
2568 \f
2569 /*
2570 * @implemented
2571 */
2572 VOID
2573 EXPORT
2574 NdisTerminateWrapper(
2575 IN NDIS_HANDLE NdisWrapperHandle,
2576 IN PVOID SystemSpecific)
2577 /*
2578 * FUNCTION: Releases resources allocated by a call to NdisInitializeWrapper
2579 * ARGUMENTS:
2580 * NdisWrapperHandle = Handle returned by NdisInitializeWrapper (NDIS_M_DRIVER_BLOCK)
2581 * SystemSpecific = Always NULL
2582 */
2583 {
2584 PNDIS_M_DRIVER_BLOCK Miniport = GET_MINIPORT_DRIVER(NdisWrapperHandle);
2585
2586 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
2587
2588 ExFreePool(Miniport->RegistryPath->Buffer);
2589 ExFreePool(Miniport->RegistryPath);
2590 ExInterlockedRemoveEntryList(&Miniport->ListEntry, &MiniportListLock);
2591 ExFreePool(Miniport);
2592 }
2593
2594
2595 /*
2596 * @implemented
2597 */
2598 NDIS_STATUS
2599 EXPORT
2600 NdisMQueryAdapterInstanceName(
2601 OUT PNDIS_STRING AdapterInstanceName,
2602 IN NDIS_HANDLE MiniportAdapterHandle)
2603 /*
2604 * FUNCTION:
2605 * ARGUMENTS:
2606 * NOTES:
2607 * NDIS 5.0
2608 */
2609 {
2610 PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)MiniportAdapterHandle;
2611 UNICODE_STRING AdapterName;
2612
2613 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
2614
2615 AdapterName.Length = 0;
2616 AdapterName.MaximumLength = Adapter->NdisMiniportBlock.MiniportName.MaximumLength;
2617 AdapterName.Buffer = ExAllocatePool(PagedPool, AdapterName.MaximumLength);
2618 if (!AdapterName.Buffer)
2619 return NDIS_STATUS_RESOURCES;
2620
2621 RtlCopyUnicodeString(&AdapterName, &Adapter->NdisMiniportBlock.MiniportName);
2622
2623 *AdapterInstanceName = AdapterName;
2624
2625 return NDIS_STATUS_SUCCESS;
2626 }
2627
2628 /*
2629 * @implemented
2630 */
2631 VOID
2632 EXPORT
2633 NdisDeregisterAdapterShutdownHandler(
2634 IN NDIS_HANDLE NdisAdapterHandle)
2635 /*
2636 * FUNCTION:
2637 * ARGUMENTS:
2638 * NOTES:
2639 * NDIS 4.0
2640 */
2641 {
2642 NdisMDeregisterAdapterShutdownHandler(NdisAdapterHandle);
2643 }
2644
2645
2646 /*
2647 * @implemented
2648 */
2649 VOID
2650 EXPORT
2651 NdisRegisterAdapterShutdownHandler(
2652 IN NDIS_HANDLE NdisAdapterHandle,
2653 IN PVOID ShutdownContext,
2654 IN ADAPTER_SHUTDOWN_HANDLER ShutdownHandler)
2655 /*
2656 * FUNCTION:
2657 * ARGUMENTS:
2658 * NOTES:
2659 * NDIS 4.0
2660 */
2661 {
2662 NdisMRegisterAdapterShutdownHandler(NdisAdapterHandle,
2663 ShutdownContext,
2664 ShutdownHandler);
2665 }
2666
2667 /*
2668 * @implemented
2669 */
2670 VOID
2671 EXPORT
2672 NdisMGetDeviceProperty(
2673 IN NDIS_HANDLE MiniportAdapterHandle,
2674 IN OUT PDEVICE_OBJECT *PhysicalDeviceObject OPTIONAL,
2675 IN OUT PDEVICE_OBJECT *FunctionalDeviceObject OPTIONAL,
2676 IN OUT PDEVICE_OBJECT *NextDeviceObject OPTIONAL,
2677 IN OUT PCM_RESOURCE_LIST *AllocatedResources OPTIONAL,
2678 IN OUT PCM_RESOURCE_LIST *AllocatedResourcesTranslated OPTIONAL)
2679 /*
2680 * FUNCTION:
2681 * ARGUMENTS:
2682 * NOTES:
2683 * NDIS 5.0
2684 */
2685 {
2686 PLOGICAL_ADAPTER Adapter = MiniportAdapterHandle;
2687
2688 NDIS_DbgPrint(MAX_TRACE, ("Called\n"));
2689
2690 if (PhysicalDeviceObject != NULL)
2691 *PhysicalDeviceObject = Adapter->NdisMiniportBlock.PhysicalDeviceObject;
2692
2693 if (FunctionalDeviceObject != NULL)
2694 *FunctionalDeviceObject = Adapter->NdisMiniportBlock.DeviceObject;
2695
2696 if (NextDeviceObject != NULL)
2697 *NextDeviceObject = Adapter->NdisMiniportBlock.NextDeviceObject;
2698
2699 if (AllocatedResources != NULL)
2700 *AllocatedResources = Adapter->NdisMiniportBlock.AllocatedResources;
2701
2702 if (AllocatedResourcesTranslated != NULL)
2703 *AllocatedResourcesTranslated = Adapter->NdisMiniportBlock.AllocatedResourcesTranslated;
2704 }
2705
2706 /*
2707 * @implemented
2708 */
2709 VOID
2710 EXPORT
2711 NdisMRegisterUnloadHandler(
2712 IN NDIS_HANDLE NdisWrapperHandle,
2713 IN PDRIVER_UNLOAD UnloadHandler)
2714 /*
2715 * FUNCTION:
2716 * ARGUMENTS:
2717 * NOTES:
2718 * NDIS 5.0
2719 */
2720 {
2721 PNDIS_M_DRIVER_BLOCK DriverBlock = NdisWrapperHandle;
2722
2723 NDIS_DbgPrint(MAX_TRACE, ("Miniport registered unload handler\n"));
2724
2725 DriverBlock->DriverObject->DriverUnload = UnloadHandler;
2726 }
2727
2728 /*
2729 * @implemented
2730 */
2731 NDIS_STATUS
2732 EXPORT
2733 NdisMRegisterDevice(
2734 IN NDIS_HANDLE NdisWrapperHandle,
2735 IN PNDIS_STRING DeviceName,
2736 IN PNDIS_STRING SymbolicName,
2737 IN PDRIVER_DISPATCH MajorFunctions[],
2738 OUT PDEVICE_OBJECT *pDeviceObject,
2739 OUT NDIS_HANDLE *NdisDeviceHandle)
2740 /*
2741 * FUNCTION:
2742 * ARGUMENTS:
2743 * NOTES:
2744 * NDIS 5.0
2745 */
2746 {
2747 PNDIS_M_DRIVER_BLOCK DriverBlock = NdisWrapperHandle;
2748 PNDIS_M_DEVICE_BLOCK DeviceBlock;
2749 PDEVICE_OBJECT DeviceObject;
2750 NDIS_STATUS Status;
2751 UINT i;
2752
2753 NDIS_DbgPrint(MAX_TRACE, ("Called\n"));
2754
2755 Status = IoCreateDevice(DriverBlock->DriverObject,
2756 0, /* This space is reserved for us. Should we use it? */
2757 DeviceName,
2758 FILE_DEVICE_NETWORK,
2759 0,
2760 FALSE,
2761 &DeviceObject);
2762
2763 if (!NT_SUCCESS(Status))
2764 {
2765 return Status;
2766 }
2767
2768 Status = IoCreateSymbolicLink(SymbolicName, DeviceName);
2769
2770 if (!NT_SUCCESS(Status))
2771 {
2772 IoDeleteDevice(DeviceObject);
2773 return Status;
2774 }
2775
2776 DeviceBlock = ExAllocatePool(NonPagedPool, sizeof(NDIS_M_DEVICE_BLOCK));
2777
2778 if (!DeviceBlock)
2779 {
2780 IoDeleteDevice(DeviceObject);
2781 IoDeleteSymbolicLink(SymbolicName);
2782 return NDIS_STATUS_RESOURCES;
2783 }
2784
2785 for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
2786 DriverBlock->DriverObject->MajorFunction[i] = MajorFunctions[i];
2787
2788 DriverBlock->DriverObject->MajorFunction[IRP_MJ_PNP] = NdisIDispatchPnp;
2789 DriverBlock->DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = NdisIShutdown;
2790 DriverBlock->DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = NdisIDeviceIoControl;
2791
2792 DeviceBlock->DeviceObject = DeviceObject;
2793 DeviceBlock->SymbolicName = SymbolicName;
2794
2795 *pDeviceObject = DeviceObject;
2796 *NdisDeviceHandle = DeviceBlock;
2797
2798 return NDIS_STATUS_SUCCESS;
2799 }
2800
2801 /*
2802 * @implemented
2803 */
2804 NDIS_STATUS
2805 EXPORT
2806 NdisMDeregisterDevice(
2807 IN NDIS_HANDLE NdisDeviceHandle)
2808 /*
2809 * FUNCTION:
2810 * ARGUMENTS:
2811 * NOTES:
2812 * NDIS 5.0
2813 */
2814 {
2815 PNDIS_M_DEVICE_BLOCK DeviceBlock = NdisDeviceHandle;
2816
2817 IoDeleteDevice(DeviceBlock->DeviceObject);
2818
2819 IoDeleteSymbolicLink(DeviceBlock->SymbolicName);
2820
2821 ExFreePool(DeviceBlock);
2822
2823 return NDIS_STATUS_SUCCESS;
2824 }
2825
2826 /*
2827 * @implemented
2828 */
2829 NDIS_STATUS
2830 EXPORT
2831 NdisQueryAdapterInstanceName(
2832 OUT PNDIS_STRING AdapterInstanceName,
2833 IN NDIS_HANDLE NdisBindingHandle)
2834 /*
2835 * FUNCTION:
2836 * ARGUMENTS:
2837 * NOTES:
2838 * NDIS 5.0
2839 */
2840 {
2841 PADAPTER_BINDING AdapterBinding = NdisBindingHandle;
2842 PLOGICAL_ADAPTER Adapter = AdapterBinding->Adapter;
2843
2844 return NdisMQueryAdapterInstanceName(AdapterInstanceName,
2845 Adapter);
2846 }
2847
2848 /*
2849 * @implemented
2850 */
2851 VOID
2852 EXPORT
2853 NdisCompletePnPEvent(
2854 IN NDIS_STATUS Status,
2855 IN NDIS_HANDLE NdisBindingHandle,
2856 IN PNET_PNP_EVENT NetPnPEvent)
2857 /*
2858 * FUNCTION:
2859 * ARGUMENTS:
2860 * NOTES:
2861 * NDIS 5.0
2862 */
2863 {
2864 PIRP Irp = (PIRP)NetPnPEvent->NdisReserved[0];
2865 PLIST_ENTRY CurrentEntry = (PLIST_ENTRY)NetPnPEvent->NdisReserved[1];
2866 PADAPTER_BINDING AdapterBinding = NdisBindingHandle;
2867 PLOGICAL_ADAPTER Adapter = AdapterBinding->Adapter;
2868 NDIS_STATUS NdisStatus;
2869
2870 if (Status != NDIS_STATUS_SUCCESS)
2871 {
2872 if (NetPnPEvent->Buffer) ExFreePool(NetPnPEvent->Buffer);
2873 ExFreePool(NetPnPEvent);
2874 Irp->IoStatus.Status = Status;
2875 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2876 return;
2877 }
2878
2879 while (CurrentEntry != &Adapter->ProtocolListHead)
2880 {
2881 AdapterBinding = CONTAINING_RECORD(CurrentEntry, ADAPTER_BINDING, AdapterListEntry);
2882
2883 NdisStatus = (*AdapterBinding->ProtocolBinding->Chars.PnPEventHandler)(
2884 AdapterBinding->NdisOpenBlock.ProtocolBindingContext,
2885 NetPnPEvent);
2886
2887 if (NdisStatus == NDIS_STATUS_PENDING)
2888 {
2889 NetPnPEvent->NdisReserved[1] = (ULONG_PTR)CurrentEntry->Flink;
2890 return;
2891 }
2892 else if (NdisStatus != NDIS_STATUS_SUCCESS)
2893 {
2894 if (NetPnPEvent->Buffer) ExFreePool(NetPnPEvent->Buffer);
2895 ExFreePool(NetPnPEvent);
2896 Irp->IoStatus.Status = NdisStatus;
2897 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2898 return;
2899 }
2900
2901 CurrentEntry = CurrentEntry->Flink;
2902 }
2903
2904 if (NetPnPEvent->Buffer) ExFreePool(NetPnPEvent->Buffer);
2905 ExFreePool(NetPnPEvent);
2906
2907 Irp->IoStatus.Status = NDIS_STATUS_SUCCESS;
2908 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2909 }
2910
2911 /* EOF */
2912