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