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