Merge 15329:15546 from trunk
[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 #include <roscfg.h>
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.NdisCommonOpenBlock.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.NdisCommonOpenBlock.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 STDCALL
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 STDCALL
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 STDCALL
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.NdisCommonOpenBlock.ProtocolBindingContext,
342 Request,
343 Status);
344 }
345 }
346
347 VOID STDCALL
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.NdisCommonOpenBlock.ProtocolBindingContext,
369 Packet,
370 Status);
371 }
372
373
374 VOID STDCALL
375 MiniSendResourcesAvailable(
376 IN NDIS_HANDLE MiniportAdapterHandle)
377 {
378 UNIMPLEMENTED
379 }
380
381
382 VOID STDCALL
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.NdisCommonOpenBlock.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 #undef NdisMQueryInformationComplete
793 /*
794 * @implemented
795 */
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 STDCALL 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 NdisWorkItemHalt:
897 break;
898
899 case NdisWorkItemMiniportCallback:
900 break;
901
902 case NdisWorkItemRequest:
903 NdisStatus = MiniDoRequest(AdapterBinding, (PNDIS_REQUEST)WorkItemContext);
904
905 if (NdisStatus == NDIS_STATUS_PENDING)
906 break;
907
908 switch (((PNDIS_REQUEST)WorkItemContext)->RequestType)
909 {
910 case NdisRequestQueryInformation:
911 NdisMQueryInformationComplete((NDIS_HANDLE)Adapter, NdisStatus);
912 MiniRequestComplete( AdapterBinding, (PNDIS_REQUEST)WorkItemContext, NdisStatus );
913 break;
914
915 case NdisRequestSetInformation:
916 NdisMSetInformationComplete((NDIS_HANDLE)Adapter, NdisStatus);
917 MiniRequestComplete( AdapterBinding, (PNDIS_REQUEST)WorkItemContext, NdisStatus );
918 break;
919
920 default:
921 NDIS_DbgPrint(MIN_TRACE, ("Unknown NDIS request type.\n"));
922 break;
923 }
924 break;
925
926 default:
927 NDIS_DbgPrint(MIN_TRACE, ("Unknown NDIS work item type (%d).\n", WorkItemType));
928 break;
929 }
930 }
931 }
932
933 \f
934 /*
935 * @unimplemented
936 */
937 VOID
938 EXPORT
939 NdisMCloseLog(
940 IN NDIS_HANDLE LogHandle)
941 {
942 UNIMPLEMENTED
943 }
944
945 \f
946 /*
947 * @unimplemented
948 */
949 NDIS_STATUS
950 EXPORT
951 NdisMCreateLog(
952 IN NDIS_HANDLE MiniportAdapterHandle,
953 IN UINT Size,
954 OUT PNDIS_HANDLE LogHandle)
955 {
956 UNIMPLEMENTED
957
958 return NDIS_STATUS_FAILURE;
959 }
960
961 \f
962 /*
963 * @implemented
964 */
965 VOID
966 EXPORT
967 NdisMDeregisterAdapterShutdownHandler(
968 IN NDIS_HANDLE MiniportHandle)
969 /*
970 * FUNCTION: de-registers a shutdown handler
971 * ARGUMENTS: MiniportHandle: Handle passed into MiniportInitialize
972 */
973 {
974 NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
975 PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)MiniportHandle;
976
977 if(Adapter->BugcheckContext->ShutdownHandler)
978 KeDeregisterBugCheckCallback(Adapter->BugcheckContext->CallbackRecord);
979 }
980
981 \f
982 /*
983 * @unimplemented
984 */
985 VOID
986 EXPORT
987 NdisMFlushLog(
988 IN NDIS_HANDLE LogHandle)
989 {
990 UNIMPLEMENTED
991 }
992
993 #undef NdisMIndicateStatus
994
995 /*
996 * @unimplemented
997 */
998 VOID
999 EXPORT
1000 NdisMIndicateStatus(
1001 IN NDIS_HANDLE MiniportAdapterHandle,
1002 IN NDIS_STATUS GeneralStatus,
1003 IN PVOID StatusBuffer,
1004 IN UINT StatusBufferSize)
1005 {
1006 UNIMPLEMENTED
1007 }
1008
1009 #undef NdisMIndicateStatusComplete
1010
1011 /*
1012 * @unimplemented
1013 */
1014 VOID
1015 EXPORT
1016 NdisMIndicateStatusComplete(
1017 IN NDIS_HANDLE MiniportAdapterHandle)
1018 {
1019 UNIMPLEMENTED
1020 }
1021
1022 \f
1023 /*
1024 * @implemented
1025 */
1026 VOID
1027 EXPORT
1028 NdisInitializeWrapper(
1029 OUT PNDIS_HANDLE NdisWrapperHandle,
1030 IN PVOID SystemSpecific1,
1031 IN PVOID SystemSpecific2,
1032 IN PVOID SystemSpecific3)
1033 /*
1034 * FUNCTION: Notifies the NDIS library that a new miniport is initializing
1035 * ARGUMENTS:
1036 * NdisWrapperHandle = Address of buffer to place NDIS wrapper handle
1037 * SystemSpecific1 = Pointer to the driver's driver object
1038 * SystemSpecific2 = Pointer to the driver's registry path
1039 * SystemSpecific3 = Always NULL
1040 * NOTES:
1041 * - SystemSpecific2 goes invalid so we copy it
1042 */
1043 {
1044 PMINIPORT_DRIVER Miniport;
1045 PUNICODE_STRING RegistryPath;
1046 WCHAR *RegistryBuffer;
1047
1048 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
1049
1050 ASSERT(NdisWrapperHandle);
1051
1052 *NdisWrapperHandle = NULL;
1053
1054 #if BREAK_ON_MINIPORT_INIT
1055 __asm__ ("int $3\n");
1056 #endif
1057
1058 Miniport = ExAllocatePool(NonPagedPool, sizeof(MINIPORT_DRIVER));
1059
1060 if (!Miniport)
1061 {
1062 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
1063 return;
1064 }
1065
1066 RtlZeroMemory(Miniport, sizeof(MINIPORT_DRIVER));
1067
1068 KeInitializeSpinLock(&Miniport->Lock);
1069
1070 Miniport->RefCount = 1;
1071
1072 Miniport->DriverObject = (PDRIVER_OBJECT)SystemSpecific1;
1073
1074 /* set the miniport's driver registry path */
1075 RegistryPath = ExAllocatePool(PagedPool, sizeof(UNICODE_STRING));
1076 if(!RegistryPath)
1077 {
1078 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
1079 return;
1080 }
1081
1082 RegistryPath->Length = ((PUNICODE_STRING)SystemSpecific2)->Length;
1083 RegistryPath->MaximumLength = RegistryPath->Length + sizeof(WCHAR); /* room for 0-term */
1084
1085 RegistryBuffer = ExAllocatePool(PagedPool, RegistryPath->MaximumLength);
1086 if(!RegistryBuffer)
1087 {
1088 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
1089 return;
1090 }
1091
1092 RtlCopyMemory(RegistryBuffer, ((PUNICODE_STRING)SystemSpecific2)->Buffer, RegistryPath->Length);
1093 RegistryBuffer[RegistryPath->Length/sizeof(WCHAR)] = 0;
1094
1095 RegistryPath->Buffer = RegistryBuffer;
1096 Miniport->RegistryPath = RegistryPath;
1097
1098 InitializeListHead(&Miniport->AdapterListHead);
1099
1100 /* Put miniport in global miniport list */
1101 ExInterlockedInsertTailList(&MiniportListHead, &Miniport->ListEntry, &MiniportListLock);
1102
1103 *NdisWrapperHandle = Miniport;
1104 }
1105
1106 \f
1107 VOID STDCALL NdisIBugcheckCallback(
1108 IN PVOID Buffer,
1109 IN ULONG Length)
1110 /*
1111 * FUNCTION: Internal callback for handling bugchecks - calls adapter's shutdown handler
1112 * ARGUMENTS:
1113 * Buffer: Pointer to a bugcheck callback context
1114 * Length: Unused
1115 */
1116 {
1117 PMINIPORT_BUGCHECK_CONTEXT Context = (PMINIPORT_BUGCHECK_CONTEXT)Buffer;
1118 ADAPTER_SHUTDOWN_HANDLER sh = (ADAPTER_SHUTDOWN_HANDLER)Context->ShutdownHandler;
1119
1120 NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
1121
1122 if(sh)
1123 sh(Context->DriverContext);
1124 }
1125
1126 \f
1127 /*
1128 * @implemented
1129 */
1130 VOID
1131 EXPORT
1132 NdisMRegisterAdapterShutdownHandler(
1133 IN NDIS_HANDLE MiniportHandle,
1134 IN PVOID ShutdownContext,
1135 IN ADAPTER_SHUTDOWN_HANDLER ShutdownHandler)
1136 /*
1137 * FUNCTION: Register a shutdown handler for an adapter
1138 * ARGUMENTS:
1139 * MiniportHandle: Handle originally passed into MiniportInitialize
1140 * ShutdownContext: Pre-initialized bugcheck context
1141 * ShutdownHandler: Function to call to handle the bugcheck
1142 * NOTES:
1143 * - I'm not sure about ShutdownContext
1144 * - FIXME - memory leak below
1145 */
1146 {
1147 PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)MiniportHandle;
1148 PMINIPORT_BUGCHECK_CONTEXT BugcheckContext = Adapter->BugcheckContext;
1149
1150 NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
1151
1152 if(BugcheckContext)
1153 return;
1154
1155 BugcheckContext = ExAllocatePool(NonPagedPool, sizeof(MINIPORT_BUGCHECK_CONTEXT));
1156 if(!BugcheckContext)
1157 {
1158 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
1159 return;
1160 }
1161
1162 BugcheckContext->ShutdownHandler = ShutdownHandler;
1163 BugcheckContext->DriverContext = ShutdownContext;
1164
1165 /* not sure if this needs to be initialized or not... oh well, it's a leak. */
1166 BugcheckContext->CallbackRecord = ExAllocatePool(NonPagedPool, sizeof(KBUGCHECK_CALLBACK_RECORD));
1167
1168 KeRegisterBugCheckCallback(BugcheckContext->CallbackRecord, NdisIBugcheckCallback,
1169 BugcheckContext, sizeof(BugcheckContext), (PUCHAR)"Ndis Miniport");
1170 }
1171
1172 \f
1173 NDIS_STATUS
1174 DoQueries(
1175 PLOGICAL_ADAPTER Adapter,
1176 NDIS_OID AddressOID)
1177 /*
1178 * FUNCTION: Queries miniport for information
1179 * ARGUMENTS:
1180 * Adapter = Pointer to logical adapter
1181 * AddressOID = OID to use to query for current address
1182 * RETURNS:
1183 * Status of operation
1184 */
1185 {
1186 ULONG BytesWritten;
1187 NDIS_STATUS NdisStatus;
1188
1189 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
1190
1191 /* Get MAC options for adapter */
1192 NdisStatus = MiniQueryInformation(Adapter, OID_GEN_MAC_OPTIONS, 0, &BytesWritten);
1193
1194 if (NdisStatus != NDIS_STATUS_SUCCESS)
1195 {
1196 NDIS_DbgPrint(MIN_TRACE, ("OID_GEN_MAC_OPTIONS failed. NdisStatus (0x%X).\n", NdisStatus));
1197 return NdisStatus;
1198 }
1199
1200 RtlCopyMemory(&Adapter->NdisMiniportBlock.MacOptions, Adapter->QueryBuffer, sizeof(UINT));
1201
1202 NDIS_DbgPrint(DEBUG_MINIPORT, ("MacOptions (0x%X).\n", Adapter->NdisMiniportBlock.MacOptions));
1203
1204 /* Get current hardware address of adapter */
1205 NdisStatus = MiniQueryInformation(Adapter, AddressOID, 0, &BytesWritten);
1206
1207 if (NdisStatus != NDIS_STATUS_SUCCESS)
1208 {
1209 NDIS_DbgPrint(MIN_TRACE, ("Address OID (0x%X) failed. NdisStatus (0x%X).\n", AddressOID, NdisStatus));
1210 return NdisStatus;
1211 }
1212
1213 RtlCopyMemory(&Adapter->Address, Adapter->QueryBuffer, Adapter->AddressLength);
1214 #ifdef DBG
1215 {
1216 /* 802.3 only */
1217
1218 PUCHAR A = (PUCHAR)&Adapter->Address.Type.Medium802_3;
1219
1220 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]));
1221 }
1222 #endif /* DBG */
1223
1224 /* Get maximum lookahead buffer size of adapter */
1225 NdisStatus = MiniQueryInformation(Adapter, OID_GEN_MAXIMUM_LOOKAHEAD, 0, &BytesWritten);
1226
1227 if (NdisStatus != NDIS_STATUS_SUCCESS)
1228 {
1229 NDIS_DbgPrint(MIN_TRACE, ("OID_GEN_MAXIMUM_LOOKAHEAD failed. NdisStatus (0x%X).\n", NdisStatus));
1230 return NdisStatus;
1231 }
1232
1233 Adapter->NdisMiniportBlock.MaximumLookahead = *((PULONG)Adapter->QueryBuffer);
1234
1235 NDIS_DbgPrint(DEBUG_MINIPORT, ("MaxLookaheadLength (0x%X).\n", Adapter->NdisMiniportBlock.MaximumLookahead));
1236
1237 /* Get current lookahead buffer size of adapter */
1238 NdisStatus = MiniQueryInformation(Adapter, OID_GEN_CURRENT_LOOKAHEAD, 0, &BytesWritten);
1239
1240 if (NdisStatus != NDIS_STATUS_SUCCESS)
1241 {
1242 NDIS_DbgPrint(MIN_TRACE, ("OID_GEN_CURRENT_LOOKAHEAD failed. NdisStatus (0x%X).\n", NdisStatus));
1243 return NdisStatus;
1244 }
1245
1246 Adapter->NdisMiniportBlock.CurrentLookahead = *((PULONG)Adapter->QueryBuffer);
1247
1248 NDIS_DbgPrint(DEBUG_MINIPORT, ("CurLookaheadLength (0x%X).\n", Adapter->NdisMiniportBlock.CurrentLookahead));
1249
1250 if (Adapter->NdisMiniportBlock.MaximumLookahead != 0)
1251 {
1252 Adapter->LookaheadLength = Adapter->NdisMiniportBlock.MaximumLookahead + Adapter->MediumHeaderSize;
1253 Adapter->LookaheadBuffer = ExAllocatePool(NonPagedPool, Adapter->LookaheadLength);
1254
1255 if (!Adapter->LookaheadBuffer)
1256 return NDIS_STATUS_RESOURCES;
1257 }
1258
1259 return STATUS_SUCCESS;
1260 }
1261
1262 \f
1263 NTSTATUS
1264 STDCALL
1265 NdisIForwardIrpAndWaitCompletionRoutine(
1266 PDEVICE_OBJECT Fdo,
1267 PIRP Irp,
1268 PVOID Context)
1269 {
1270 PKEVENT Event = Context;
1271
1272 if (Irp->PendingReturned)
1273 KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
1274
1275 return STATUS_MORE_PROCESSING_REQUIRED;
1276 }
1277
1278 \f
1279 NTSTATUS
1280 STDCALL
1281 NdisIForwardIrpAndWait(PLOGICAL_ADAPTER Adapter, PIRP Irp)
1282 {
1283 KEVENT Event;
1284 NTSTATUS Status;
1285
1286 KeInitializeEvent(&Event, NotificationEvent, FALSE);
1287 IoCopyCurrentIrpStackLocationToNext(Irp);
1288 IoSetCompletionRoutine(Irp, NdisIForwardIrpAndWaitCompletionRoutine, &Event,
1289 TRUE, TRUE, TRUE);
1290 Status = IoCallDriver(Adapter->NdisMiniportBlock.NextDeviceObject, Irp);
1291 if (Status == STATUS_PENDING)
1292 {
1293 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
1294 Status = Irp->IoStatus.Status;
1295 }
1296 return Status;
1297 }
1298
1299 \f
1300 NTSTATUS
1301 STDCALL
1302 NdisIPnPStartDevice(
1303 IN PDEVICE_OBJECT DeviceObject,
1304 PIRP Irp)
1305 /*
1306 * FUNCTION: Handle the PnP start device event
1307 * ARGUMENTS:
1308 * DeviceObejct = Functional Device Object
1309 * Irp = IRP_MN_START_DEVICE I/O request packet
1310 * RETURNS:
1311 * Status of operation
1312 */
1313 {
1314 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
1315 PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)DeviceObject->DeviceExtension;
1316 NDIS_WRAPPER_CONTEXT WrapperContext;
1317 NDIS_STATUS NdisStatus;
1318 NDIS_STATUS OpenErrorStatus;
1319 NTSTATUS Status;
1320 UINT SelectedMediumIndex = 0;
1321 NDIS_OID AddressOID;
1322 BOOLEAN Success = FALSE;
1323 ULONG ResourceCount;
1324 ULONG ResourceListSize;
1325 UNICODE_STRING ParamName;
1326 PNDIS_CONFIGURATION_PARAMETER ConfigParam;
1327 NDIS_HANDLE ConfigHandle;
1328 ULONG Size;
1329 /* FIXME - KIRQL OldIrql; */
1330
1331 /*
1332 * Prepare wrapper context used by HW and configuration routines.
1333 */
1334
1335 Status = IoOpenDeviceRegistryKey(
1336 Adapter->NdisMiniportBlock.PhysicalDeviceObject, PLUGPLAY_REGKEY_DRIVER,
1337 KEY_ALL_ACCESS, &WrapperContext.RegistryHandle);
1338 if (!NT_SUCCESS(Status))
1339 {
1340 NDIS_DbgPrint(MIN_TRACE,("failed to open adapter-specific reg key\n"));
1341 return Status;
1342 }
1343
1344 NDIS_DbgPrint(MAX_TRACE, ("opened device reg key\n"));
1345
1346 WrapperContext.DeviceObject = Adapter->NdisMiniportBlock.DeviceObject;
1347
1348 /*
1349 * Store the adapter resources used by HW routines such as
1350 * NdisMQueryAdapterResources.
1351 */
1352
1353 if (Stack->Parameters.StartDevice.AllocatedResources != NULL &&
1354 Stack->Parameters.StartDevice.AllocatedResourcesTranslated != NULL)
1355 {
1356 ResourceCount = Stack->Parameters.StartDevice.AllocatedResources->List[0].
1357 PartialResourceList.Count;
1358 ResourceListSize =
1359 FIELD_OFFSET(CM_RESOURCE_LIST, List[0].PartialResourceList.
1360 PartialDescriptors[ResourceCount]);
1361
1362 Adapter->NdisMiniportBlock.AllocatedResources =
1363 ExAllocatePool(PagedPool, ResourceListSize);
1364 if (Adapter->NdisMiniportBlock.AllocatedResources == NULL)
1365 {
1366 return STATUS_INSUFFICIENT_RESOURCES;
1367 }
1368
1369 Adapter->NdisMiniportBlock.AllocatedResourcesTranslated =
1370 ExAllocatePool(PagedPool, ResourceListSize);
1371 if (Adapter->NdisMiniportBlock.AllocatedResourcesTranslated == NULL)
1372 {
1373 ExFreePool(Adapter->NdisMiniportBlock.AllocatedResources);
1374 Adapter->NdisMiniportBlock.AllocatedResources = NULL;
1375 return STATUS_INSUFFICIENT_RESOURCES;
1376 }
1377
1378 RtlCopyMemory(Adapter->NdisMiniportBlock.AllocatedResources,
1379 Stack->Parameters.StartDevice.AllocatedResources,
1380 ResourceListSize);
1381
1382 RtlCopyMemory(Adapter->NdisMiniportBlock.AllocatedResourcesTranslated,
1383 Stack->Parameters.StartDevice.AllocatedResourcesTranslated,
1384 ResourceListSize);
1385 }
1386
1387 /*
1388 * Store the Bus Type, Bus Number and Slot information. It's used by
1389 * the hardware routines then.
1390 */
1391
1392 NdisOpenConfiguration(&NdisStatus, &ConfigHandle, (NDIS_HANDLE)&WrapperContext);
1393
1394 Size = sizeof(ULONG);
1395 Status = IoGetDeviceProperty(Adapter->NdisMiniportBlock.PhysicalDeviceObject,
1396 DevicePropertyLegacyBusType, Size,
1397 &Adapter->NdisMiniportBlock.BusType, &Size);
1398 if (!NT_SUCCESS(Status) || Adapter->NdisMiniportBlock.BusType == -1)
1399 {
1400 NdisInitUnicodeString(&ParamName, L"BusType");
1401 NdisReadConfiguration(&NdisStatus, &ConfigParam, ConfigHandle,
1402 &ParamName, NdisParameterInteger);
1403 if (NdisStatus == NDIS_STATUS_SUCCESS)
1404 Adapter->NdisMiniportBlock.BusType = ConfigParam->ParameterData.IntegerData;
1405 else
1406 Adapter->NdisMiniportBlock.BusType = Isa;
1407 }
1408
1409 Status = IoGetDeviceProperty(Adapter->NdisMiniportBlock.PhysicalDeviceObject,
1410 DevicePropertyBusNumber, Size,
1411 &Adapter->NdisMiniportBlock.BusNumber, &Size);
1412 if (!NT_SUCCESS(Status) || Adapter->NdisMiniportBlock.BusNumber == -1)
1413 {
1414 NdisInitUnicodeString(&ParamName, L"BusNumber");
1415 NdisReadConfiguration(&NdisStatus, &ConfigParam, ConfigHandle,
1416 &ParamName, NdisParameterInteger);
1417 if (NdisStatus == NDIS_STATUS_SUCCESS)
1418 Adapter->NdisMiniportBlock.BusNumber = ConfigParam->ParameterData.IntegerData;
1419 else
1420 Adapter->NdisMiniportBlock.BusNumber = 0;
1421 }
1422 WrapperContext.BusNumber = Adapter->NdisMiniportBlock.BusNumber;
1423
1424 Status = IoGetDeviceProperty(Adapter->NdisMiniportBlock.PhysicalDeviceObject,
1425 DevicePropertyAddress, Size,
1426 &Adapter->NdisMiniportBlock.SlotNumber, &Size);
1427 if (!NT_SUCCESS(Status) || Adapter->NdisMiniportBlock.SlotNumber == -1)
1428 {
1429 NdisInitUnicodeString(&ParamName, L"SlotNumber");
1430 NdisReadConfiguration(&NdisStatus, &ConfigParam, ConfigHandle,
1431 &ParamName, NdisParameterInteger);
1432 if (NdisStatus == NDIS_STATUS_SUCCESS)
1433 Adapter->NdisMiniportBlock.SlotNumber = ConfigParam->ParameterData.IntegerData;
1434 else
1435 Adapter->NdisMiniportBlock.SlotNumber = 0;
1436 }
1437
1438 NdisCloseConfiguration(ConfigHandle);
1439
1440 /*
1441 * Call MiniportInitialize.
1442 */
1443
1444 NDIS_DbgPrint(MID_TRACE, ("calling MiniportInitialize\n"));
1445 NdisStatus = (*Adapter->Miniport->Chars.InitializeHandler)(
1446 &OpenErrorStatus, &SelectedMediumIndex, &MediaArray[0],
1447 MEDIA_ARRAY_SIZE, Adapter, (NDIS_HANDLE)&WrapperContext);
1448
1449 ZwClose(WrapperContext.RegistryHandle);
1450
1451 if (NdisStatus != NDIS_STATUS_SUCCESS ||
1452 SelectedMediumIndex >= MEDIA_ARRAY_SIZE)
1453 {
1454 NDIS_DbgPrint(MIN_TRACE, ("MiniportInitialize() failed for an adapter.\n"));
1455 return (NTSTATUS)NdisStatus;
1456 }
1457
1458 /* Set handlers (some NDIS macros require these) */
1459
1460 Adapter->NdisMiniportBlock.EthRxCompleteHandler = EthFilterDprIndicateReceiveComplete;
1461 Adapter->NdisMiniportBlock.EthRxIndicateHandler = EthFilterDprIndicateReceive;
1462 Adapter->NdisMiniportBlock.SendCompleteHandler = MiniSendComplete;
1463 Adapter->NdisMiniportBlock.SendResourcesHandler = MiniSendResourcesAvailable;
1464 Adapter->NdisMiniportBlock.ResetCompleteHandler = MiniResetComplete;
1465 Adapter->NdisMiniportBlock.TDCompleteHandler = MiniTransferDataComplete;
1466 Adapter->NdisMiniportBlock.PacketIndicateHandler= MiniIndicateReceivePacket;
1467
1468 Adapter->NdisMiniportBlock.MediaType = MediaArray[SelectedMediumIndex];
1469
1470 switch (Adapter->NdisMiniportBlock.MediaType)
1471 {
1472 case NdisMedium802_3:
1473 Adapter->MediumHeaderSize = 14; /* XXX figure out what to do about LLC */
1474 AddressOID = OID_802_3_CURRENT_ADDRESS;
1475 Adapter->AddressLength = ETH_LENGTH_OF_ADDRESS;
1476 NdisStatus = DoQueries(Adapter, AddressOID);
1477 if (NdisStatus == NDIS_STATUS_SUCCESS)
1478 {
1479 Success = EthCreateFilter(32, /* FIXME: Query this from miniport. */
1480 Adapter->Address.Type.Medium802_3,
1481 &Adapter->NdisMiniportBlock.FilterDbs.EthDB);
1482 if (Success)
1483 Adapter->NdisMiniportBlock.FilterDbs.EthDB->Miniport = (PNDIS_MINIPORT_BLOCK)Adapter;
1484 else
1485 NdisStatus = NDIS_STATUS_RESOURCES;
1486 }
1487 break;
1488
1489 default:
1490 /* FIXME: Support other types of media */
1491 NDIS_DbgPrint(MIN_TRACE, ("error: unsupported media\n"));
1492 ASSERT(FALSE);
1493 /* FIXME - KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql); */
1494 return STATUS_UNSUCCESSFUL;
1495 }
1496
1497 if (!Success || NdisStatus != NDIS_STATUS_SUCCESS)
1498 {
1499 NDIS_DbgPrint(MAX_TRACE, ("couldn't create filter (%x)\n", NdisStatus));
1500 if (Adapter->LookaheadBuffer)
1501 {
1502 ExFreePool(Adapter->LookaheadBuffer);
1503 Adapter->LookaheadBuffer = NULL;
1504 }
1505 return (NTSTATUS)NdisStatus;
1506 }
1507
1508 Adapter->NdisMiniportBlock.OldPnPDeviceState = Adapter->NdisMiniportBlock.PnPDeviceState;
1509 Adapter->NdisMiniportBlock.PnPDeviceState = NdisPnPDeviceStarted;
1510
1511 /* Put adapter in adapter list for this miniport */
1512 ExInterlockedInsertTailList(&Adapter->Miniport->AdapterListHead, &Adapter->MiniportListEntry, &Adapter->Miniport->Lock);
1513
1514 /* Put adapter in global adapter list */
1515 ExInterlockedInsertTailList(&AdapterListHead, &Adapter->ListEntry, &AdapterListLock);
1516
1517 return STATUS_SUCCESS;
1518 }
1519
1520 \f
1521 NTSTATUS
1522 STDCALL
1523 NdisIPnPStopDevice(
1524 IN PDEVICE_OBJECT DeviceObject,
1525 PIRP Irp)
1526 /*
1527 * FUNCTION: Handle the PnP stop device event
1528 * ARGUMENTS:
1529 * DeviceObejct = Functional Device Object
1530 * Irp = IRP_MN_STOP_DEVICE I/O request packet
1531 * RETURNS:
1532 * Status of operation
1533 */
1534 {
1535 PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)DeviceObject->DeviceExtension;
1536 KIRQL OldIrql;
1537
1538 /* Remove adapter from adapter list for this miniport */
1539 KeAcquireSpinLock(&Adapter->Miniport->Lock, &OldIrql);
1540 RemoveEntryList(&Adapter->MiniportListEntry);
1541 KeReleaseSpinLock(&Adapter->Miniport->Lock, OldIrql);
1542
1543 /* Remove adapter from global adapter list */
1544 KeAcquireSpinLock(&AdapterListLock, &OldIrql);
1545 RemoveEntryList(&Adapter->ListEntry);
1546 KeReleaseSpinLock(&AdapterListLock, OldIrql);
1547
1548 (*Adapter->Miniport->Chars.HaltHandler)(Adapter);
1549
1550 if (Adapter->LookaheadBuffer)
1551 {
1552 ExFreePool(Adapter->LookaheadBuffer);
1553 Adapter->LookaheadBuffer = NULL;
1554 }
1555 if (Adapter->NdisMiniportBlock.AllocatedResources)
1556 {
1557 ExFreePool(Adapter->NdisMiniportBlock.AllocatedResources);
1558 Adapter->NdisMiniportBlock.AllocatedResources = NULL;
1559 }
1560 if (Adapter->NdisMiniportBlock.AllocatedResourcesTranslated)
1561 {
1562 ExFreePool(Adapter->NdisMiniportBlock.AllocatedResourcesTranslated);
1563 Adapter->NdisMiniportBlock.AllocatedResourcesTranslated = NULL;
1564 }
1565
1566 Adapter->NdisMiniportBlock.OldPnPDeviceState = Adapter->NdisMiniportBlock.PnPDeviceState;
1567 Adapter->NdisMiniportBlock.PnPDeviceState = NdisPnPDeviceStopped;
1568
1569 return STATUS_SUCCESS;
1570 }
1571
1572 \f
1573 NTSTATUS
1574 STDCALL
1575 NdisIDispatchPnp(
1576 IN PDEVICE_OBJECT DeviceObject,
1577 PIRP Irp)
1578 {
1579 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
1580 PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)DeviceObject->DeviceExtension;
1581 NTSTATUS Status;
1582
1583 switch (Stack->MinorFunction)
1584 {
1585 case IRP_MN_START_DEVICE:
1586 Status = NdisIForwardIrpAndWait(Adapter, Irp);
1587 if (NT_SUCCESS(Status) && NT_SUCCESS(Irp->IoStatus.Status))
1588 {
1589 Status = NdisIPnPStartDevice(DeviceObject, Irp);
1590 }
1591 Irp->IoStatus.Status = Status;
1592 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1593 break;
1594
1595 case IRP_MN_STOP_DEVICE:
1596 /* FIXME */
1597 Status = STATUS_UNSUCCESSFUL;
1598 break;
1599 Status = NdisIForwardIrpAndWait(Adapter, Irp);
1600 if (NT_SUCCESS(Status) && NT_SUCCESS(Irp->IoStatus.Status))
1601 {
1602 Status = NdisIPnPStopDevice(DeviceObject, Irp);
1603 }
1604 Irp->IoStatus.Status = Status;
1605 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1606 break;
1607
1608 default:
1609 IoSkipCurrentIrpStackLocation(Irp);
1610 Status = IoCallDriver(Adapter->NdisMiniportBlock.NextDeviceObject, Irp);
1611 break;
1612 }
1613
1614 return Status;
1615 }
1616
1617 \f
1618 NTSTATUS
1619 STDCALL
1620 NdisIAddDevice(
1621 IN PDRIVER_OBJECT DriverObject,
1622 IN PDEVICE_OBJECT PhysicalDeviceObject)
1623 /*
1624 * FUNCTION: Create a device for an adapter found using PnP
1625 * ARGUMENTS:
1626 * DriverObject = Pointer to the miniport driver object
1627 * PhysicalDeviceObject = Pointer to the PDO for our adapter
1628 */
1629 {
1630 static const WCHAR ClassKeyName[] = {'C','l','a','s','s','\\'};
1631 static const WCHAR LinkageKeyName[] = {'\\','L','i','n','k','a','g','e',0};
1632 PMINIPORT_DRIVER Miniport;
1633 PMINIPORT_DRIVER *MiniportPtr;
1634 WCHAR *LinkageKeyBuffer;
1635 ULONG DriverKeyLength;
1636 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
1637 UNICODE_STRING ExportName;
1638 PDEVICE_OBJECT DeviceObject;
1639 PLOGICAL_ADAPTER Adapter;
1640 NTSTATUS Status;
1641
1642 /*
1643 * Gain the access to the miniport data structure first.
1644 */
1645
1646 MiniportPtr = IoGetDriverObjectExtension(DriverObject, (PVOID)TAG('D','I','M','N'));
1647 if (MiniportPtr == NULL)
1648 {
1649 NDIS_DbgPrint(DEBUG_MINIPORT, ("Can't get driver object extension.\n"));
1650 return STATUS_UNSUCCESSFUL;
1651 }
1652 Miniport = *MiniportPtr;
1653
1654 /*
1655 * Get name of the Linkage registry key for our adapter. It's located under
1656 * the driver key for our driver and so we have basicly two ways to do it.
1657 * Either we can use IoOpenDriverRegistryKey or compose it using information
1658 * gathered by IoGetDeviceProperty. I choosed the second because
1659 * IoOpenDriverRegistryKey wasn't implemented at the time of writing.
1660 */
1661
1662 Status = IoGetDeviceProperty(PhysicalDeviceObject, DevicePropertyDriverKeyName,
1663 0, NULL, &DriverKeyLength);
1664 if (Status != STATUS_BUFFER_TOO_SMALL)
1665 {
1666 NDIS_DbgPrint(DEBUG_MINIPORT, ("Can't get miniport driver key length.\n"));
1667 return Status;
1668 }
1669
1670 LinkageKeyBuffer = ExAllocatePool(PagedPool, DriverKeyLength +
1671 sizeof(ClassKeyName) + sizeof(LinkageKeyName));
1672 if (LinkageKeyBuffer == NULL)
1673 {
1674 NDIS_DbgPrint(DEBUG_MINIPORT, ("Can't allocate memory for driver key name.\n"));
1675 return STATUS_INSUFFICIENT_RESOURCES;
1676 }
1677
1678 Status = IoGetDeviceProperty(PhysicalDeviceObject, DevicePropertyDriverKeyName,
1679 DriverKeyLength, LinkageKeyBuffer +
1680 (sizeof(ClassKeyName) / sizeof(WCHAR)),
1681 &DriverKeyLength);
1682 if (!NT_SUCCESS(Status))
1683 {
1684 NDIS_DbgPrint(DEBUG_MINIPORT, ("Can't get miniport driver key.\n"));
1685 ExFreePool(LinkageKeyBuffer);
1686 return Status;
1687 }
1688
1689 /* Compose the linkage key name. */
1690 RtlCopyMemory(LinkageKeyBuffer, ClassKeyName, sizeof(ClassKeyName));
1691 RtlCopyMemory(LinkageKeyBuffer + ((sizeof(ClassKeyName) + DriverKeyLength) /
1692 sizeof(WCHAR)) - 1, LinkageKeyName, sizeof(LinkageKeyName));
1693
1694 NDIS_DbgPrint(DEBUG_MINIPORT, ("LinkageKey: %S.\n", LinkageKeyBuffer));
1695
1696 /*
1697 * Now open the linkage key and read the "Export" and "RootDevice" values
1698 * which contains device name and root service respectively.
1699 */
1700
1701 RtlZeroMemory(QueryTable, sizeof(QueryTable));
1702 RtlInitUnicodeString(&ExportName, NULL);
1703 QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_DIRECT;
1704 QueryTable[0].Name = L"Export";
1705 QueryTable[0].EntryContext = &ExportName;
1706
1707 Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL, LinkageKeyBuffer,
1708 QueryTable, NULL, NULL);
1709 ExFreePool(LinkageKeyBuffer);
1710 if (!NT_SUCCESS(Status))
1711 {
1712 NDIS_DbgPrint(DEBUG_MINIPORT, ("Can't get miniport device name. (%x)\n", Status));
1713 return Status;
1714 }
1715
1716 /*
1717 * Create the device object.
1718 */
1719
1720 NDIS_DbgPrint(MAX_TRACE, ("creating device %wZ\n", &ExportName));
1721
1722 Status = IoCreateDevice(Miniport->DriverObject, sizeof(LOGICAL_ADAPTER),
1723 &ExportName, FILE_DEVICE_PHYSICAL_NETCARD,
1724 0, FALSE, &DeviceObject);
1725 if (!NT_SUCCESS(Status))
1726 {
1727 NDIS_DbgPrint(MIN_TRACE, ("Could not create device object.\n"));
1728 RtlFreeUnicodeString(&ExportName);
1729 return Status;
1730 }
1731
1732 /*
1733 * Initialize the adapter structure.
1734 */
1735
1736 Adapter = (PLOGICAL_ADAPTER)DeviceObject->DeviceExtension;
1737 KeInitializeSpinLock(&Adapter->NdisMiniportBlock.Lock);
1738 InitializeListHead(&Adapter->ProtocolListHead);
1739 Adapter->RefCount = 1;
1740 Adapter->Miniport = Miniport;
1741
1742 Adapter->NdisMiniportBlock.MiniportName = ExportName;
1743
1744 Adapter->NdisMiniportBlock.DeviceObject = DeviceObject;
1745 Adapter->NdisMiniportBlock.PhysicalDeviceObject = PhysicalDeviceObject;
1746 Adapter->NdisMiniportBlock.NextDeviceObject =
1747 IoAttachDeviceToDeviceStack(Adapter->NdisMiniportBlock.DeviceObject,
1748 PhysicalDeviceObject);
1749
1750 Adapter->NdisMiniportBlock.OldPnPDeviceState = 0;
1751 Adapter->NdisMiniportBlock.PnPDeviceState = NdisPnPDeviceAdded;
1752
1753 KeInitializeDpc(&Adapter->MiniportDpc, MiniportDpc, (PVOID)Adapter);
1754
1755 DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
1756
1757 return STATUS_SUCCESS;
1758 }
1759
1760 \f
1761 /*
1762 * @implemented
1763 */
1764 NDIS_STATUS
1765 EXPORT
1766 NdisMRegisterMiniport(
1767 IN NDIS_HANDLE NdisWrapperHandle,
1768 IN PNDIS_MINIPORT_CHARACTERISTICS MiniportCharacteristics,
1769 IN UINT CharacteristicsLength)
1770 /*
1771 * FUNCTION: Registers a miniport's MiniportXxx entry points with the NDIS library
1772 * ARGUMENTS:
1773 * NdisWrapperHandle = Pointer to handle returned by NdisMInitializeWrapper
1774 * MiniportCharacteristics = Pointer to a buffer with miniport characteristics
1775 * CharacteristicsLength = Number of bytes in characteristics buffer
1776 * RETURNS:
1777 * Status of operation
1778 */
1779 {
1780 UINT MinSize;
1781 PMINIPORT_DRIVER Miniport = GET_MINIPORT_DRIVER(NdisWrapperHandle);
1782 PMINIPORT_DRIVER *MiniportPtr;
1783 NTSTATUS Status;
1784
1785 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
1786
1787 switch (MiniportCharacteristics->MajorNdisVersion)
1788 {
1789 case 0x03:
1790 MinSize = sizeof(NDIS30_MINIPORT_CHARACTERISTICS);
1791 break;
1792
1793 case 0x04:
1794 MinSize = sizeof(NDIS40_MINIPORT_CHARACTERISTICS);
1795 break;
1796
1797 case 0x05:
1798 MinSize = sizeof(NDIS50_MINIPORT_CHARACTERISTICS);
1799 break;
1800
1801 default:
1802 NDIS_DbgPrint(DEBUG_MINIPORT, ("Bad miniport characteristics version.\n"));
1803 return NDIS_STATUS_BAD_VERSION;
1804 }
1805
1806 if (CharacteristicsLength < MinSize)
1807 {
1808 NDIS_DbgPrint(DEBUG_MINIPORT, ("Bad miniport characteristics.\n"));
1809 return NDIS_STATUS_BAD_CHARACTERISTICS;
1810 }
1811
1812 /* Check if mandatory MiniportXxx functions are specified */
1813 if ((!MiniportCharacteristics->HaltHandler) ||
1814 (!MiniportCharacteristics->InitializeHandler)||
1815 (!MiniportCharacteristics->QueryInformationHandler) ||
1816 (!MiniportCharacteristics->ResetHandler) ||
1817 (!MiniportCharacteristics->SetInformationHandler))
1818 {
1819 NDIS_DbgPrint(DEBUG_MINIPORT, ("Bad miniport characteristics.\n"));
1820 return NDIS_STATUS_BAD_CHARACTERISTICS;
1821 }
1822
1823 if (MiniportCharacteristics->MajorNdisVersion == 0x03)
1824 {
1825 if (!MiniportCharacteristics->SendHandler)
1826 {
1827 NDIS_DbgPrint(DEBUG_MINIPORT, ("Bad miniport characteristics.\n"));
1828 return NDIS_STATUS_BAD_CHARACTERISTICS;
1829 }
1830 }
1831 else if (MiniportCharacteristics->MajorNdisVersion >= 0x04)
1832 {
1833 /* NDIS 4.0+ */
1834 if ((!MiniportCharacteristics->SendHandler) &&
1835 (!MiniportCharacteristics->SendPacketsHandler))
1836 {
1837 NDIS_DbgPrint(DEBUG_MINIPORT, ("Bad miniport characteristics.\n"));
1838 return NDIS_STATUS_BAD_CHARACTERISTICS;
1839 }
1840 }
1841
1842 /* TODO: verify NDIS5 and NDIS5.1 */
1843
1844 RtlCopyMemory(&Miniport->Chars, MiniportCharacteristics, MinSize);
1845
1846 /*
1847 * NOTE: This is VERY unoptimal! Should we store the MINIPORT_DRIVER
1848 * struture in the driver extension or what?
1849 */
1850
1851 Status = IoAllocateDriverObjectExtension(Miniport->DriverObject, (PVOID)TAG('D','I','M','N'),
1852 sizeof(PMINIPORT_DRIVER), (PVOID*)&MiniportPtr);
1853 if (!NT_SUCCESS(Status))
1854 {
1855 NDIS_DbgPrint(DEBUG_MINIPORT, ("Can't allocate driver object extension.\n"));
1856 return NDIS_STATUS_RESOURCES;
1857 }
1858
1859 *MiniportPtr = Miniport;
1860
1861 Miniport->DriverObject->MajorFunction[IRP_MJ_PNP] = NdisIDispatchPnp;
1862 Miniport->DriverObject->DriverExtension->AddDevice = NdisIAddDevice;
1863
1864 return NDIS_STATUS_SUCCESS;
1865 }
1866
1867 \f
1868 /*
1869 * @implemented
1870 */
1871 VOID
1872 EXPORT
1873 NdisMResetComplete(
1874 IN NDIS_HANDLE MiniportAdapterHandle,
1875 IN NDIS_STATUS Status,
1876 IN BOOLEAN AddressingReset)
1877 {
1878 MiniResetComplete(MiniportAdapterHandle, Status, AddressingReset);
1879 }
1880
1881 \f
1882 /*
1883 * @implemented
1884 */
1885 VOID
1886 EXPORT
1887 NdisMSendComplete(
1888 IN NDIS_HANDLE MiniportAdapterHandle,
1889 IN PNDIS_PACKET Packet,
1890 IN NDIS_STATUS Status)
1891 /*
1892 * FUNCTION: Forwards a message to the initiating protocol saying
1893 * that a packet was handled
1894 * ARGUMENTS:
1895 * NdisAdapterHandle = Handle input to MiniportInitialize
1896 * Packet = Pointer to NDIS packet that was sent
1897 * Status = Status of send operation
1898 */
1899 {
1900 MiniSendComplete(MiniportAdapterHandle, Packet, Status);
1901 }
1902
1903 \f
1904 /*
1905 * @implemented
1906 */
1907 VOID
1908 EXPORT
1909 NdisMSendResourcesAvailable(
1910 IN NDIS_HANDLE MiniportAdapterHandle)
1911 {
1912 MiniSendResourcesAvailable(MiniportAdapterHandle);
1913 }
1914
1915 \f
1916 /*
1917 * @implemented
1918 */
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 #undef NdisMSetInformationComplete
1931
1932 \f
1933 /*
1934 * @implemented
1935 */
1936 VOID
1937 EXPORT
1938 NdisMSetInformationComplete(
1939 IN NDIS_HANDLE MiniportAdapterHandle,
1940 IN NDIS_STATUS Status)
1941 {
1942 (*((PNDIS_MINIPORT_BLOCK)(MiniportAdapterHandle))->SetCompleteHandler)(MiniportAdapterHandle, Status);
1943 }
1944
1945 #undef NdisMSetAttributes
1946
1947 \f
1948 /*
1949 * @implemented
1950 */
1951 VOID
1952 EXPORT
1953 NdisMSetAttributes(
1954 IN NDIS_HANDLE MiniportAdapterHandle,
1955 IN NDIS_HANDLE MiniportAdapterContext,
1956 IN BOOLEAN BusMaster,
1957 IN NDIS_INTERFACE_TYPE AdapterType)
1958 /*
1959 * FUNCTION: Informs the NDIS library of significant features of the caller's NIC
1960 * ARGUMENTS:
1961 * MiniportAdapterHandle = Handle input to MiniportInitialize
1962 * MiniportAdapterContext = Pointer to context information
1963 * BusMaster = Specifies TRUE if the caller's NIC is a busmaster DMA device
1964 * AdapterType = Specifies the I/O bus interface of the caller's NIC
1965 */
1966 {
1967 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
1968 NdisMSetAttributesEx(MiniportAdapterHandle, MiniportAdapterContext, 0,
1969 BusMaster ? NDIS_ATTRIBUTE_BUS_MASTER : 0,
1970 AdapterType);
1971 }
1972
1973 \f
1974 /*
1975 * @implemented
1976 */
1977 VOID
1978 EXPORT
1979 NdisMSetAttributesEx(
1980 IN NDIS_HANDLE MiniportAdapterHandle,
1981 IN NDIS_HANDLE MiniportAdapterContext,
1982 IN UINT CheckForHangTimeInSeconds OPTIONAL,
1983 IN ULONG AttributeFlags,
1984 IN NDIS_INTERFACE_TYPE AdapterType)
1985 /*
1986 * FUNCTION: Informs the NDIS library of significant features of the caller's NIC
1987 * ARGUMENTS:
1988 * MiniportAdapterHandle = Handle input to MiniportInitialize
1989 * MiniportAdapterContext = Pointer to context information
1990 * CheckForHangTimeInSeconds = Specifies interval in seconds at which
1991 * MiniportCheckForHang should be called
1992 * AttributeFlags = Bitmask that indicates specific attributes
1993 * AdapterType = Specifies the I/O bus interface of the caller's NIC
1994 */
1995 {
1996 /* TODO: Take CheckForHandTimeInSeconds into account! */
1997
1998 PLOGICAL_ADAPTER Adapter = GET_LOGICAL_ADAPTER(MiniportAdapterHandle);
1999
2000 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
2001
2002 Adapter->NdisMiniportBlock.MiniportAdapterContext = MiniportAdapterContext;
2003 Adapter->NdisMiniportBlock.Flags = AttributeFlags;
2004 Adapter->NdisMiniportBlock.AdapterType = AdapterType;
2005 Adapter->AttributesSet = TRUE;
2006 if (AttributeFlags & NDIS_ATTRIBUTE_INTERMEDIATE_DRIVER)
2007 NDIS_DbgPrint(MAX_TRACE, ("Intermediate drivers not supported yet.\n"));
2008 }
2009
2010 \f
2011 /*
2012 * @implemented
2013 */
2014 VOID
2015 EXPORT
2016 NdisMSleep(
2017 IN ULONG MicrosecondsToSleep)
2018 /*
2019 * FUNCTION: delay the thread's execution for MicrosecondsToSleep
2020 * ARGUMENTS:
2021 * MicrosecondsToSleep: duh...
2022 * NOTES:
2023 * - Because this is a blocking call, current IRQL must be < DISPATCH_LEVEL
2024 */
2025 {
2026 KTIMER Timer;
2027 LARGE_INTEGER DueTime;
2028
2029 PAGED_CODE();
2030
2031 DueTime.QuadPart = (-1) * 10 * MicrosecondsToSleep;
2032
2033 KeInitializeTimer(&Timer);
2034 KeSetTimer(&Timer, DueTime, 0);
2035 KeWaitForSingleObject(&Timer, Executive, KernelMode, FALSE, 0);
2036 }
2037
2038 \f
2039 /*
2040 * @implemented
2041 */
2042 BOOLEAN
2043 EXPORT
2044 NdisMSynchronizeWithInterrupt(
2045 IN PNDIS_MINIPORT_INTERRUPT Interrupt,
2046 IN PVOID SynchronizeFunction,
2047 IN PVOID SynchronizeContext)
2048 {
2049 return(KeSynchronizeExecution(Interrupt->InterruptObject,
2050 (PKSYNCHRONIZE_ROUTINE)SynchronizeFunction,
2051 SynchronizeContext));
2052 }
2053
2054 \f
2055 /*
2056 * @unimplemented
2057 */
2058 NDIS_STATUS
2059 EXPORT
2060 NdisMWriteLogData(
2061 IN NDIS_HANDLE LogHandle,
2062 IN PVOID LogBuffer,
2063 IN UINT LogBufferSize)
2064 {
2065 UNIMPLEMENTED
2066
2067 return NDIS_STATUS_FAILURE;
2068 }
2069
2070 \f
2071 /*
2072 * @implemented
2073 */
2074 VOID
2075 EXPORT
2076 NdisTerminateWrapper(
2077 IN NDIS_HANDLE NdisWrapperHandle,
2078 IN PVOID SystemSpecific)
2079 /*
2080 * FUNCTION: Releases resources allocated by a call to NdisInitializeWrapper
2081 * ARGUMENTS:
2082 * NdisWrapperHandle = Handle returned by NdisInitializeWrapper (MINIPORT_DRIVER)
2083 * SystemSpecific = Always NULL
2084 */
2085 {
2086 PMINIPORT_DRIVER Miniport = GET_MINIPORT_DRIVER(NdisWrapperHandle);
2087
2088 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
2089
2090 ExFreePool(Miniport->RegistryPath->Buffer);
2091 ExFreePool(Miniport->RegistryPath);
2092 ExFreePool(Miniport);
2093 }
2094
2095 /* EOF */
2096