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