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