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