- Merge aicom-network-fixes up to r36337
[reactos.git] / reactos / drivers / network / ndis / ndis / miniport.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS NDIS library
4 * FILE: ndis/miniport.c
5 * PURPOSE: Routines used by NDIS miniport drivers
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * Vizzini (vizzini@plasmic.com)
8 * REVISIONS:
9 * CSH 01/08-2000 Created
10 * 20 Aug 2003 vizzini - DMA support
11 * 3 Oct 2003 vizzini - SendPackets support
12 */
13
14 #include "ndissys.h"
15 #include "efilter.h"
16
17 #ifdef DBG
18 #include <buffer.h>
19 #endif /* DBG */
20
21 #undef NdisMSendComplete
22 VOID
23 EXPORT
24 NdisMSendComplete(
25 IN NDIS_HANDLE MiniportAdapterHandle,
26 IN PNDIS_PACKET Packet,
27 IN NDIS_STATUS Status);
28
29 /* Root of the scm database */
30 #define SERVICES_ROOT L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"
31
32 /*
33 * Define to 1 to get a debugger breakpoint at the end of NdisInitializeWrapper
34 * for each new miniport starting up
35 */
36 #define BREAK_ON_MINIPORT_INIT 0
37
38 /*
39 * This has to be big enough to hold the results of querying the Route value
40 * from the Linkage key. Please re-code me to determine this dynamically.
41 */
42 #define ROUTE_DATA_SIZE 256
43
44 /* Number of media we know */
45 #define MEDIA_ARRAY_SIZE 15
46
47 static NDIS_MEDIUM MediaArray[MEDIA_ARRAY_SIZE] =
48 {
49 NdisMedium802_3,
50 NdisMedium802_5,
51 NdisMediumFddi,
52 NdisMediumWan,
53 NdisMediumLocalTalk,
54 NdisMediumDix,
55 NdisMediumArcnetRaw,
56 NdisMediumArcnet878_2,
57 NdisMediumAtm,
58 NdisMediumWirelessWan,
59 NdisMediumIrda,
60 NdisMediumBpc,
61 NdisMediumCoWan,
62 NdisMedium1394,
63 NdisMediumMax
64 };
65
66 /* global list and lock of Miniports NDIS has registered */
67 LIST_ENTRY MiniportListHead;
68 KSPIN_LOCK MiniportListLock;
69
70 /* global list and lock of adapters NDIS has registered */
71 LIST_ENTRY AdapterListHead;
72 KSPIN_LOCK AdapterListLock;
73
74 VOID
75 MiniDisplayPacket(
76 PNDIS_PACKET Packet)
77 {
78 #ifdef DBG
79 ULONG i, Length;
80 UCHAR Buffer[64];
81 if ((DebugTraceLevel & DEBUG_PACKET) > 0) {
82 Length = CopyPacketToBuffer(
83 Buffer,
84 Packet,
85 0,
86 64);
87
88 DbgPrint("*** PACKET START ***");
89
90 for (i = 0; i < Length; i++) {
91 if (i % 12 == 0)
92 DbgPrint("\n%04X ", i);
93 DbgPrint("%02X ", Buffer[i]);
94 }
95
96 DbgPrint("*** PACKET STOP ***\n");
97 }
98 #endif /* DBG */
99 }
100
101 VOID
102 MiniDisplayPacket2(
103 PVOID HeaderBuffer,
104 UINT HeaderBufferSize,
105 PVOID LookaheadBuffer,
106 UINT LookaheadBufferSize)
107 {
108 #ifdef DBG
109 if ((DebugTraceLevel & DEBUG_PACKET) > 0) {
110 ULONG i, Length;
111 PUCHAR p;
112
113 DbgPrint("*** RECEIVE PACKET START ***\n");
114 DbgPrint("HEADER:");
115 p = HeaderBuffer;
116 for (i = 0; i < HeaderBufferSize; i++) {
117 if (i % 16 == 0)
118 DbgPrint("\n%04X ", i);
119 DbgPrint("%02X ", *p++);
120 }
121
122 DbgPrint("\nFRAME:");
123
124 p = LookaheadBuffer;
125 Length = (LookaheadBufferSize < 64)? LookaheadBufferSize : 64;
126 for (i = 0; i < Length; i++) {
127 if (i % 16 == 0)
128 DbgPrint("\n%04X ", i);
129 DbgPrint("%02X ", *p++);
130 }
131
132 DbgPrint("\n*** RECEIVE PACKET STOP ***\n");
133 }
134 #endif /* DBG */
135 }
136
137 \f
138 VOID
139 MiniIndicateData(
140 PLOGICAL_ADAPTER Adapter,
141 NDIS_HANDLE MacReceiveContext,
142 PVOID HeaderBuffer,
143 UINT HeaderBufferSize,
144 PVOID LookaheadBuffer,
145 UINT LookaheadBufferSize,
146 UINT PacketSize)
147 /*
148 * FUNCTION: Indicate received data to bound protocols
149 * ARGUMENTS:
150 * Adapter = Pointer to logical adapter
151 * MacReceiveContext = MAC receive context handle
152 * HeaderBuffer = Pointer to header buffer
153 * HeaderBufferSize = Size of header buffer
154 * LookaheadBuffer = Pointer to lookahead buffer
155 * LookaheadBufferSize = Size of lookahead buffer
156 * PacketSize = Total size of received packet
157 */
158 {
159 KIRQL OldIrql;
160 PLIST_ENTRY CurrentEntry;
161 PADAPTER_BINDING AdapterBinding;
162
163 NDIS_DbgPrint(DEBUG_MINIPORT, ("Called. Adapter (0x%X) HeaderBuffer (0x%X) "
164 "HeaderBufferSize (0x%X) LookaheadBuffer (0x%X) LookaheadBufferSize (0x%X).\n",
165 Adapter, HeaderBuffer, HeaderBufferSize, LookaheadBuffer, LookaheadBufferSize));
166
167 MiniDisplayPacket2(HeaderBuffer, HeaderBufferSize, LookaheadBuffer, LookaheadBufferSize);
168
169 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
822 if( NdisStatus == NDIS_STATUS_RESOURCES )
823 MiniQueueWorkItem(Adapter, WorkItemType, WorkItemContext);
824 else if( NdisStatus != NDIS_STATUS_PENDING ) {
825 NdisMSendComplete
826 ( Adapter, (PNDIS_PACKET)WorkItemContext, NdisStatus );
827 Adapter->MiniportBusy = FALSE;
828 }
829 break;
830
831 case NdisWorkItemSendLoopback:
832 /*
833 * called by ProSend when protocols want to send loopback packets
834 */
835 /* XXX atm ProIndicatePacket sends a packet up via the loopback adapter only */
836 NdisStatus = ProIndicatePacket(Adapter, (PNDIS_PACKET)WorkItemContext);
837 MiniSendComplete((NDIS_HANDLE)Adapter, (PNDIS_PACKET)WorkItemContext, NdisStatus);
838 break;
839
840 case NdisWorkItemReturnPackets:
841 break;
842
843 case NdisWorkItemResetRequested:
844 break;
845
846 case NdisWorkItemResetInProgress:
847 break;
848
849 case NdisWorkItemMiniportCallback:
850 break;
851
852 case NdisWorkItemRequest:
853 NdisStatus = MiniDoRequest(&Adapter->NdisMiniportBlock, (PNDIS_REQUEST)WorkItemContext);
854
855 if (NdisStatus == NDIS_STATUS_PENDING)
856 break;
857
858 switch (((PNDIS_REQUEST)WorkItemContext)->RequestType)
859 {
860 case NdisRequestQueryInformation:
861 NdisMQueryInformationComplete((NDIS_HANDLE)Adapter, NdisStatus);
862 MiniRequestComplete( &Adapter->NdisMiniportBlock, (PNDIS_REQUEST)WorkItemContext, NdisStatus );
863 break;
864
865 case NdisRequestSetInformation:
866 NdisMSetInformationComplete((NDIS_HANDLE)Adapter, NdisStatus);
867 MiniRequestComplete( &Adapter->NdisMiniportBlock, (PNDIS_REQUEST)WorkItemContext, NdisStatus );
868 break;
869
870 default:
871 NDIS_DbgPrint(MIN_TRACE, ("Unknown NDIS request type.\n"));
872 break;
873 }
874 break;
875
876 default:
877 NDIS_DbgPrint(MIN_TRACE, ("Unknown NDIS work item type (%d).\n", WorkItemType));
878 break;
879 }
880 }
881
882 ExFreePool(WorkItem);
883 }
884
885
886 \f
887 VOID NTAPI MiniportDpc(
888 IN PKDPC Dpc,
889 IN PVOID DeferredContext,
890 IN PVOID SystemArgument1,
891 IN PVOID SystemArgument2)
892 /*
893 * FUNCTION: Deferred routine to handle serialization
894 * ARGUMENTS:
895 * Dpc = Pointer to DPC object
896 * DeferredContext = Pointer to context information (LOGICAL_ADAPTER)
897 * SystemArgument1 = Unused
898 * SystemArgument2 = Unused
899 */
900 {
901 PNDIS_WORK_ITEM NdisWorkItem;
902 PWORK_QUEUE_ITEM WorkItem;
903
904 NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
905
906 NdisWorkItem = ExAllocatePool(NonPagedPool, sizeof(NDIS_WORK_ITEM));
907
908 WorkItem = (PWORK_QUEUE_ITEM)NdisWorkItem->WrapperReserved;
909
910 NdisWorkItem->Context = DeferredContext;
911
912 ExInitializeWorkItem(WorkItem, MiniportWorker, NdisWorkItem);
913
914 ExQueueWorkItem(WorkItem, CriticalWorkQueue);
915 }
916
917 \f
918 VOID
919 NTAPI
920 MiniStatus(
921 IN NDIS_HANDLE MiniportHandle,
922 IN NDIS_STATUS GeneralStatus,
923 IN PVOID StatusBuffer,
924 IN UINT StatusBufferSize)
925 {
926 UNIMPLEMENTED
927 }
928
929 \f
930 VOID
931 NTAPI
932 MiniStatusComplete(
933 IN NDIS_HANDLE MiniportAdapterHandle)
934 {
935 UNIMPLEMENTED
936 }
937
938 \f
939 /*
940 * @unimplemented
941 */
942 VOID
943 EXPORT
944 NdisMCloseLog(
945 IN NDIS_HANDLE LogHandle)
946 {
947 UNIMPLEMENTED
948 }
949
950 \f
951 /*
952 * @unimplemented
953 */
954 NDIS_STATUS
955 EXPORT
956 NdisMCreateLog(
957 IN NDIS_HANDLE MiniportAdapterHandle,
958 IN UINT Size,
959 OUT PNDIS_HANDLE LogHandle)
960 {
961 UNIMPLEMENTED
962
963 return NDIS_STATUS_FAILURE;
964 }
965
966 \f
967 /*
968 * @implemented
969 */
970 VOID
971 EXPORT
972 NdisMDeregisterAdapterShutdownHandler(
973 IN NDIS_HANDLE MiniportHandle)
974 /*
975 * FUNCTION: de-registers a shutdown handler
976 * ARGUMENTS: MiniportHandle: Handle passed into MiniportInitialize
977 */
978 {
979 PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)MiniportHandle;
980
981 NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
982
983 if(Adapter->BugcheckContext->ShutdownHandler)
984 KeDeregisterBugCheckCallback(Adapter->BugcheckContext->CallbackRecord);
985 }
986
987 \f
988 /*
989 * @unimplemented
990 */
991 VOID
992 EXPORT
993 NdisMFlushLog(
994 IN NDIS_HANDLE LogHandle)
995 {
996 UNIMPLEMENTED
997 }
998
999 /*
1000 * @unimplemented
1001 */
1002 #undef NdisMIndicateStatus
1003 VOID
1004 EXPORT
1005 NdisMIndicateStatus(
1006 IN NDIS_HANDLE MiniportAdapterHandle,
1007 IN NDIS_STATUS GeneralStatus,
1008 IN PVOID StatusBuffer,
1009 IN UINT StatusBufferSize)
1010 {
1011 UNIMPLEMENTED
1012 }
1013
1014 /*
1015 * @unimplemented
1016 */
1017 #undef NdisMIndicateStatusComplete
1018 VOID
1019 EXPORT
1020 NdisMIndicateStatusComplete(
1021 IN NDIS_HANDLE MiniportAdapterHandle)
1022 {
1023 UNIMPLEMENTED
1024 }
1025
1026 \f
1027 /*
1028 * @implemented
1029 */
1030 VOID
1031 EXPORT
1032 NdisInitializeWrapper(
1033 OUT PNDIS_HANDLE NdisWrapperHandle,
1034 IN PVOID SystemSpecific1,
1035 IN PVOID SystemSpecific2,
1036 IN PVOID SystemSpecific3)
1037 /*
1038 * FUNCTION: Notifies the NDIS library that a new miniport is initializing
1039 * ARGUMENTS:
1040 * NdisWrapperHandle = Address of buffer to place NDIS wrapper handle
1041 * SystemSpecific1 = Pointer to the driver's driver object
1042 * SystemSpecific2 = Pointer to the driver's registry path
1043 * SystemSpecific3 = Always NULL
1044 * NOTES:
1045 * - SystemSpecific2 goes invalid so we copy it
1046 */
1047 {
1048 PNDIS_M_DRIVER_BLOCK Miniport;
1049 PUNICODE_STRING RegistryPath;
1050 WCHAR *RegistryBuffer;
1051
1052 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
1053
1054 ASSERT(NdisWrapperHandle);
1055
1056 *NdisWrapperHandle = NULL;
1057
1058 #if BREAK_ON_MINIPORT_INIT
1059 __asm__ ("int $3\n");
1060 #endif
1061
1062 Miniport = ExAllocatePool(NonPagedPool, sizeof(NDIS_M_DRIVER_BLOCK));
1063
1064 if (!Miniport)
1065 {
1066 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
1067 return;
1068 }
1069
1070 RtlZeroMemory(Miniport, sizeof(NDIS_M_DRIVER_BLOCK));
1071
1072 KeInitializeSpinLock(&Miniport->Lock);
1073
1074 Miniport->DriverObject = (PDRIVER_OBJECT)SystemSpecific1;
1075
1076 /* set the miniport's driver registry path */
1077 RegistryPath = ExAllocatePool(PagedPool, sizeof(UNICODE_STRING));
1078 if(!RegistryPath)
1079 {
1080 ExFreePool(Miniport);
1081 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
1082 return;
1083 }
1084
1085 RegistryPath->Length = ((PUNICODE_STRING)SystemSpecific2)->Length;
1086 RegistryPath->MaximumLength = RegistryPath->Length + sizeof(WCHAR); /* room for 0-term */
1087
1088 RegistryBuffer = ExAllocatePool(PagedPool, RegistryPath->MaximumLength);
1089 if(!RegistryBuffer)
1090 {
1091 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
1092 ExFreePool(Miniport);
1093 ExFreePool(RegistryPath);
1094 return;
1095 }
1096
1097 RtlCopyMemory(RegistryBuffer, ((PUNICODE_STRING)SystemSpecific2)->Buffer, RegistryPath->Length);
1098 RegistryBuffer[RegistryPath->Length/sizeof(WCHAR)] = 0;
1099
1100 RegistryPath->Buffer = RegistryBuffer;
1101 Miniport->RegistryPath = RegistryPath;
1102
1103 InitializeListHead(&Miniport->DeviceList);
1104
1105 /* Put miniport in global miniport list */
1106 ExInterlockedInsertTailList(&MiniportListHead, &Miniport->ListEntry, &MiniportListLock);
1107
1108 *NdisWrapperHandle = Miniport;
1109 }
1110
1111 \f
1112 VOID NTAPI NdisIBugcheckCallback(
1113 IN PVOID Buffer,
1114 IN ULONG Length)
1115 /*
1116 * FUNCTION: Internal callback for handling bugchecks - calls adapter's shutdown handler
1117 * ARGUMENTS:
1118 * Buffer: Pointer to a bugcheck callback context
1119 * Length: Unused
1120 */
1121 {
1122 PMINIPORT_BUGCHECK_CONTEXT Context = (PMINIPORT_BUGCHECK_CONTEXT)Buffer;
1123 ADAPTER_SHUTDOWN_HANDLER sh = (ADAPTER_SHUTDOWN_HANDLER)Context->ShutdownHandler;
1124
1125 NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
1126
1127 if(sh)
1128 sh(Context->DriverContext);
1129 }
1130
1131 \f
1132 /*
1133 * @implemented
1134 */
1135 VOID
1136 EXPORT
1137 NdisMRegisterAdapterShutdownHandler(
1138 IN NDIS_HANDLE MiniportHandle,
1139 IN PVOID ShutdownContext,
1140 IN ADAPTER_SHUTDOWN_HANDLER ShutdownHandler)
1141 /*
1142 * FUNCTION: Register a shutdown handler for an adapter
1143 * ARGUMENTS:
1144 * MiniportHandle: Handle originally passed into MiniportInitialize
1145 * ShutdownContext: Pre-initialized bugcheck context
1146 * ShutdownHandler: Function to call to handle the bugcheck
1147 * NOTES:
1148 * - I'm not sure about ShutdownContext
1149 */
1150 {
1151 PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)MiniportHandle;
1152 PMINIPORT_BUGCHECK_CONTEXT BugcheckContext = Adapter->BugcheckContext;
1153
1154 NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
1155
1156 if(BugcheckContext)
1157 return;
1158
1159 BugcheckContext = ExAllocatePool(NonPagedPool, sizeof(MINIPORT_BUGCHECK_CONTEXT));
1160 if(!BugcheckContext)
1161 {
1162 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
1163 return;
1164 }
1165
1166 BugcheckContext->ShutdownHandler = ShutdownHandler;
1167 BugcheckContext->DriverContext = ShutdownContext;
1168
1169 BugcheckContext->CallbackRecord = ExAllocatePool(NonPagedPool, sizeof(KBUGCHECK_CALLBACK_RECORD));
1170
1171 KeInitializeCallbackRecord(BugcheckContext->CallbackRecord);
1172
1173 KeRegisterBugCheckCallback(BugcheckContext->CallbackRecord, NdisIBugcheckCallback,
1174 BugcheckContext, sizeof(BugcheckContext), (PUCHAR)"Ndis Miniport");
1175 }
1176
1177 \f
1178 NDIS_STATUS
1179 DoQueries(
1180 PLOGICAL_ADAPTER Adapter,
1181 NDIS_OID AddressOID)
1182 /*
1183 * FUNCTION: Queries miniport for information
1184 * ARGUMENTS:
1185 * Adapter = Pointer to logical adapter
1186 * AddressOID = OID to use to query for current address
1187 * RETURNS:
1188 * Status of operation
1189 */
1190 {
1191 ULONG BytesWritten;
1192 NDIS_STATUS NdisStatus;
1193
1194 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
1195
1196 /* Get MAC options for adapter */
1197 NdisStatus = MiniQueryInformation(Adapter, OID_GEN_MAC_OPTIONS, sizeof(UINT),
1198 &Adapter->NdisMiniportBlock.MacOptions,
1199 &BytesWritten);
1200
1201 if (NdisStatus != NDIS_STATUS_SUCCESS)
1202 {
1203 NDIS_DbgPrint(MIN_TRACE, ("OID_GEN_MAC_OPTIONS failed. NdisStatus (0x%X).\n", NdisStatus));
1204 return NdisStatus;
1205 }
1206
1207 NDIS_DbgPrint(DEBUG_MINIPORT, ("MacOptions (0x%X).\n", Adapter->NdisMiniportBlock.MacOptions));
1208
1209 /* Get current hardware address of adapter */
1210 NdisStatus = MiniQueryInformation(Adapter, AddressOID, Adapter->AddressLength,
1211 &Adapter->Address, &BytesWritten);
1212
1213 if (NdisStatus != NDIS_STATUS_SUCCESS)
1214 {
1215 NDIS_DbgPrint(MIN_TRACE, ("Address OID (0x%X) failed. NdisStatus (0x%X).\n", AddressOID, NdisStatus));
1216 return NdisStatus;
1217 }
1218
1219 #ifdef DBG
1220 {
1221 /* 802.3 only */
1222
1223 PUCHAR A = (PUCHAR)&Adapter->Address.Type.Medium802_3;
1224
1225 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]));
1226 }
1227 #endif /* DBG */
1228
1229 /* Get maximum lookahead buffer size of adapter */
1230 NdisStatus = MiniQueryInformation(Adapter, OID_GEN_MAXIMUM_LOOKAHEAD, sizeof(ULONG),
1231 &Adapter->NdisMiniportBlock.MaximumLookahead, &BytesWritten);
1232
1233 if (NdisStatus != NDIS_STATUS_SUCCESS)
1234 {
1235 NDIS_DbgPrint(MIN_TRACE, ("OID_GEN_MAXIMUM_LOOKAHEAD failed. NdisStatus (0x%X).\n", NdisStatus));
1236 return NdisStatus;
1237 }
1238
1239 NDIS_DbgPrint(DEBUG_MINIPORT, ("MaxLookaheadLength (0x%X).\n", Adapter->NdisMiniportBlock.MaximumLookahead));
1240
1241 /* Get current lookahead buffer size of adapter */
1242 NdisStatus = MiniQueryInformation(Adapter, OID_GEN_CURRENT_LOOKAHEAD, sizeof(ULONG),
1243 &Adapter->NdisMiniportBlock.CurrentLookahead, &BytesWritten);
1244
1245 if (NdisStatus != NDIS_STATUS_SUCCESS)
1246 {
1247 NDIS_DbgPrint(MIN_TRACE, ("OID_GEN_CURRENT_LOOKAHEAD failed. NdisStatus (0x%X).\n", NdisStatus));
1248 return NdisStatus;
1249 }
1250
1251 NdisStatus = MiniQueryInformation(Adapter, OID_GEN_MAXIMUM_SEND_PACKETS, sizeof(ULONG),
1252 &Adapter->NdisMiniportBlock.MaxSendPackets, &BytesWritten);
1253
1254 if (NdisStatus != NDIS_STATUS_SUCCESS)
1255 {
1256 NDIS_DbgPrint(MIN_TRACE, ("OID_GEN_MAXIMUM_SEND_PACKETS failed. NdisStatus (0x%X).\n", NdisStatus));
1257
1258 /* Set it to 1 if it fails because some drivers don't support this (?)*/
1259 Adapter->NdisMiniportBlock.MaxSendPackets = 1;
1260 }
1261
1262 NDIS_DbgPrint(DEBUG_MINIPORT, ("CurLookaheadLength (0x%X).\n", Adapter->NdisMiniportBlock.CurrentLookahead));
1263
1264 if (Adapter->NdisMiniportBlock.MaximumLookahead != 0)
1265 {
1266 Adapter->LookaheadLength = Adapter->NdisMiniportBlock.MaximumLookahead + Adapter->MediumHeaderSize;
1267 Adapter->LookaheadBuffer = ExAllocatePool(NonPagedPool, Adapter->LookaheadLength);
1268
1269 if (!Adapter->LookaheadBuffer)
1270 return NDIS_STATUS_RESOURCES;
1271 }
1272
1273 return STATUS_SUCCESS;
1274 }
1275
1276 \f
1277 NTSTATUS
1278 NTAPI
1279 NdisIForwardIrpAndWaitCompletionRoutine(
1280 PDEVICE_OBJECT Fdo,
1281 PIRP Irp,
1282 PVOID Context)
1283 {
1284 PKEVENT Event = Context;
1285
1286 if (Irp->PendingReturned)
1287 KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
1288
1289 return STATUS_MORE_PROCESSING_REQUIRED;
1290 }
1291
1292 \f
1293 NTSTATUS
1294 NTAPI
1295 NdisIForwardIrpAndWait(PLOGICAL_ADAPTER Adapter, PIRP Irp)
1296 {
1297 KEVENT Event;
1298 NTSTATUS Status;
1299
1300 KeInitializeEvent(&Event, NotificationEvent, FALSE);
1301 IoCopyCurrentIrpStackLocationToNext(Irp);
1302 IoSetCompletionRoutine(Irp, NdisIForwardIrpAndWaitCompletionRoutine, &Event,
1303 TRUE, TRUE, TRUE);
1304 Status = IoCallDriver(Adapter->NdisMiniportBlock.NextDeviceObject, Irp);
1305 if (Status == STATUS_PENDING)
1306 {
1307 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
1308 Status = Irp->IoStatus.Status;
1309 }
1310 return Status;
1311 }
1312
1313 \f
1314 NTSTATUS
1315 NTAPI
1316 NdisIPnPStartDevice(
1317 IN PDEVICE_OBJECT DeviceObject,
1318 PIRP Irp)
1319 /*
1320 * FUNCTION: Handle the PnP start device event
1321 * ARGUMENTS:
1322 * DeviceObejct = Functional Device Object
1323 * Irp = IRP_MN_START_DEVICE I/O request packet
1324 * RETURNS:
1325 * Status of operation
1326 */
1327 {
1328 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
1329 PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)DeviceObject->DeviceExtension;
1330 NDIS_WRAPPER_CONTEXT WrapperContext;
1331 NDIS_STATUS NdisStatus;
1332 NDIS_STATUS OpenErrorStatus;
1333 NTSTATUS Status;
1334 UINT SelectedMediumIndex = 0;
1335 NDIS_OID AddressOID;
1336 BOOLEAN Success = FALSE;
1337 ULONG ResourceCount;
1338 ULONG ResourceListSize;
1339 UNICODE_STRING ParamName;
1340 PNDIS_CONFIGURATION_PARAMETER ConfigParam;
1341 NDIS_HANDLE ConfigHandle;
1342 ULONG Size;
1343 /* FIXME - KIRQL OldIrql; */
1344
1345 /*
1346 * Prepare wrapper context used by HW and configuration routines.
1347 */
1348
1349 NDIS_DbgPrint(DEBUG_MINIPORT, ("Start Device %wZ\n", &Adapter->NdisMiniportBlock.MiniportName));
1350
1351 NDIS_DbgPrint(MAX_TRACE, ("Inserting adapter 0x%x into adapter list\n", Adapter));
1352
1353 /* Put adapter in global adapter list */
1354 ExInterlockedInsertTailList(&AdapterListHead, &Adapter->ListEntry, &AdapterListLock);
1355
1356 Status = IoOpenDeviceRegistryKey(
1357 Adapter->NdisMiniportBlock.PhysicalDeviceObject, PLUGPLAY_REGKEY_DRIVER,
1358 KEY_ALL_ACCESS, &WrapperContext.RegistryHandle);
1359 if (!NT_SUCCESS(Status))
1360 {
1361 NDIS_DbgPrint(MIN_TRACE,("failed to open adapter-specific reg key\n"));
1362 ExInterlockedRemoveEntryList( &Adapter->ListEntry, &AdapterListLock );
1363 return Status;
1364 }
1365
1366 NDIS_DbgPrint(MAX_TRACE, ("opened device reg key\n"));
1367
1368 WrapperContext.DeviceObject = Adapter->NdisMiniportBlock.DeviceObject;
1369
1370 /*
1371 * Store the adapter resources used by HW routines such as
1372 * NdisMQueryAdapterResources.
1373 */
1374
1375 if (Stack->Parameters.StartDevice.AllocatedResources != NULL)
1376 {
1377 ResourceCount = Stack->Parameters.StartDevice.AllocatedResources->List[0].
1378 PartialResourceList.Count;
1379 ResourceListSize =
1380 FIELD_OFFSET(CM_RESOURCE_LIST, List[0].PartialResourceList.
1381 PartialDescriptors[ResourceCount]);
1382
1383 Adapter->NdisMiniportBlock.AllocatedResources =
1384 ExAllocatePool(PagedPool, ResourceListSize);
1385 if (Adapter->NdisMiniportBlock.AllocatedResources == NULL)
1386 {
1387 ExInterlockedRemoveEntryList( &Adapter->ListEntry, &AdapterListLock );
1388 return STATUS_INSUFFICIENT_RESOURCES;
1389 }
1390
1391 RtlCopyMemory(Adapter->NdisMiniportBlock.AllocatedResources,
1392 Stack->Parameters.StartDevice.AllocatedResources,
1393 ResourceListSize);
1394 }
1395
1396 if (Stack->Parameters.StartDevice.AllocatedResourcesTranslated != NULL)
1397 {
1398 ResourceCount = Stack->Parameters.StartDevice.AllocatedResources->List[0].
1399 PartialResourceList.Count;
1400 ResourceListSize =
1401 FIELD_OFFSET(CM_RESOURCE_LIST, List[0].PartialResourceList.
1402 PartialDescriptors[ResourceCount]);
1403
1404 Adapter->NdisMiniportBlock.AllocatedResourcesTranslated =
1405 ExAllocatePool(PagedPool, ResourceListSize);
1406 if (Adapter->NdisMiniportBlock.AllocatedResourcesTranslated == NULL)
1407 {
1408 ExInterlockedRemoveEntryList( &Adapter->ListEntry, &AdapterListLock );
1409 return STATUS_INSUFFICIENT_RESOURCES;
1410 }
1411
1412 RtlCopyMemory(Adapter->NdisMiniportBlock.AllocatedResourcesTranslated,
1413 Stack->Parameters.StartDevice.AllocatedResourcesTranslated,
1414 ResourceListSize);
1415 }
1416
1417 /*
1418 * Store the Bus Type, Bus Number and Slot information. It's used by
1419 * the hardware routines then.
1420 */
1421
1422 NdisOpenConfiguration(&NdisStatus, &ConfigHandle, (NDIS_HANDLE)&WrapperContext);
1423
1424 Size = sizeof(ULONG);
1425 Status = IoGetDeviceProperty(Adapter->NdisMiniportBlock.PhysicalDeviceObject,
1426 DevicePropertyLegacyBusType, Size,
1427 &Adapter->NdisMiniportBlock.BusType, &Size);
1428 if (!NT_SUCCESS(Status) || (INTERFACE_TYPE)Adapter->NdisMiniportBlock.BusType == InterfaceTypeUndefined)
1429 {
1430 NdisInitUnicodeString(&ParamName, L"BusType");
1431 NdisReadConfiguration(&NdisStatus, &ConfigParam, ConfigHandle,
1432 &ParamName, NdisParameterInteger);
1433 if (NdisStatus == NDIS_STATUS_SUCCESS)
1434 Adapter->NdisMiniportBlock.BusType = ConfigParam->ParameterData.IntegerData;
1435 else
1436 Adapter->NdisMiniportBlock.BusType = Isa;
1437 }
1438
1439 Status = IoGetDeviceProperty(Adapter->NdisMiniportBlock.PhysicalDeviceObject,
1440 DevicePropertyBusNumber, Size,
1441 &Adapter->NdisMiniportBlock.BusNumber, &Size);
1442 if (!NT_SUCCESS(Status) || Adapter->NdisMiniportBlock.BusNumber == 0xFFFFFFF0)
1443 {
1444 NdisInitUnicodeString(&ParamName, L"BusNumber");
1445 NdisReadConfiguration(&NdisStatus, &ConfigParam, ConfigHandle,
1446 &ParamName, NdisParameterInteger);
1447 if (NdisStatus == NDIS_STATUS_SUCCESS)
1448 Adapter->NdisMiniportBlock.BusNumber = ConfigParam->ParameterData.IntegerData;
1449 else
1450 Adapter->NdisMiniportBlock.BusNumber = 0;
1451 }
1452 WrapperContext.BusNumber = Adapter->NdisMiniportBlock.BusNumber;
1453
1454 Status = IoGetDeviceProperty(Adapter->NdisMiniportBlock.PhysicalDeviceObject,
1455 DevicePropertyAddress, Size,
1456 &Adapter->NdisMiniportBlock.SlotNumber, &Size);
1457 if (!NT_SUCCESS(Status) || Adapter->NdisMiniportBlock.SlotNumber == (NDIS_INTERFACE_TYPE)-1)
1458 {
1459 NdisInitUnicodeString(&ParamName, L"SlotNumber");
1460 NdisReadConfiguration(&NdisStatus, &ConfigParam, ConfigHandle,
1461 &ParamName, NdisParameterInteger);
1462 if (NdisStatus == NDIS_STATUS_SUCCESS)
1463 Adapter->NdisMiniportBlock.SlotNumber = ConfigParam->ParameterData.IntegerData;
1464 else
1465 Adapter->NdisMiniportBlock.SlotNumber = 0;
1466 }
1467 else
1468 {
1469 /* Convert slotnumber to PCI_SLOT_NUMBER */
1470 ULONG PciSlotNumber = Adapter->NdisMiniportBlock.SlotNumber;
1471 PCI_SLOT_NUMBER SlotNumber;
1472
1473 SlotNumber.u.AsULONG = 0;
1474 SlotNumber.u.bits.DeviceNumber = (PciSlotNumber >> 16) & 0xFFFF;
1475 SlotNumber.u.bits.FunctionNumber = PciSlotNumber & 0xFFFF;
1476
1477 Adapter->NdisMiniportBlock.SlotNumber = SlotNumber.u.AsULONG;
1478 }
1479 NdisCloseConfiguration(ConfigHandle);
1480
1481 /* Set handlers (some NDIS macros require these) */
1482 Adapter->NdisMiniportBlock.EthRxCompleteHandler = EthFilterDprIndicateReceiveComplete;
1483 Adapter->NdisMiniportBlock.EthRxIndicateHandler = EthFilterDprIndicateReceive;
1484 Adapter->NdisMiniportBlock.SendCompleteHandler = MiniSendComplete;
1485 Adapter->NdisMiniportBlock.SendResourcesHandler = MiniSendResourcesAvailable;
1486 Adapter->NdisMiniportBlock.ResetCompleteHandler = MiniResetComplete;
1487 Adapter->NdisMiniportBlock.TDCompleteHandler = MiniTransferDataComplete;
1488 Adapter->NdisMiniportBlock.PacketIndicateHandler= MiniIndicateReceivePacket;
1489 Adapter->NdisMiniportBlock.StatusHandler = MiniStatus;
1490 Adapter->NdisMiniportBlock.StatusCompleteHandler= MiniStatusComplete;
1491
1492 /*
1493 * Call MiniportInitialize.
1494 */
1495
1496 NDIS_DbgPrint(MID_TRACE, ("calling MiniportInitialize\n"));
1497 NdisStatus = (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.InitializeHandler)(
1498 &OpenErrorStatus, &SelectedMediumIndex, &MediaArray[0],
1499 MEDIA_ARRAY_SIZE, Adapter, (NDIS_HANDLE)&WrapperContext);
1500
1501 ZwClose(WrapperContext.RegistryHandle);
1502
1503 if (NdisStatus != NDIS_STATUS_SUCCESS ||
1504 SelectedMediumIndex >= MEDIA_ARRAY_SIZE)
1505 {
1506 NDIS_DbgPrint(MIN_TRACE, ("MiniportInitialize() failed for an adapter.\n"));
1507 ExInterlockedRemoveEntryList( &Adapter->ListEntry, &AdapterListLock );
1508 if (NdisStatus == NDIS_STATUS_SUCCESS) NdisStatus = NDIS_STATUS_FAILURE;
1509 return (NTSTATUS)NdisStatus;
1510 }
1511
1512 Adapter->NdisMiniportBlock.MediaType = MediaArray[SelectedMediumIndex];
1513
1514 switch (Adapter->NdisMiniportBlock.MediaType)
1515 {
1516 case NdisMedium802_3:
1517 Adapter->MediumHeaderSize = 14; /* XXX figure out what to do about LLC */
1518 AddressOID = OID_802_3_CURRENT_ADDRESS;
1519 Adapter->AddressLength = ETH_LENGTH_OF_ADDRESS;
1520 NdisStatus = DoQueries(Adapter, AddressOID);
1521 if (NdisStatus == NDIS_STATUS_SUCCESS)
1522 {
1523 Success = EthCreateFilter(32, /* FIXME: Query this from miniport. */
1524 Adapter->Address.Type.Medium802_3,
1525 &Adapter->NdisMiniportBlock.EthDB);
1526 if (Success)
1527 ((PETHI_FILTER)Adapter->NdisMiniportBlock.EthDB)->Miniport = (PNDIS_MINIPORT_BLOCK)Adapter;
1528 else
1529 NdisStatus = NDIS_STATUS_RESOURCES;
1530 }
1531 break;
1532
1533 default:
1534 /* FIXME: Support other types of media */
1535 NDIS_DbgPrint(MIN_TRACE, ("error: unsupported media\n"));
1536 ASSERT(FALSE);
1537 /* FIXME - KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql); */
1538 ExInterlockedRemoveEntryList( &Adapter->ListEntry, &AdapterListLock );
1539 return STATUS_UNSUCCESSFUL;
1540 }
1541
1542 if (!Success || NdisStatus != NDIS_STATUS_SUCCESS)
1543 {
1544 NDIS_DbgPrint(MAX_TRACE, ("couldn't create filter (%x)\n", NdisStatus));
1545 if (Adapter->LookaheadBuffer)
1546 {
1547 ExFreePool(Adapter->LookaheadBuffer);
1548 Adapter->LookaheadBuffer = NULL;
1549 }
1550 ExInterlockedRemoveEntryList( &Adapter->ListEntry, &AdapterListLock );
1551 if (NdisStatus == NDIS_STATUS_SUCCESS) NdisStatus = NDIS_STATUS_FAILURE;
1552 return (NTSTATUS)NdisStatus;
1553 }
1554
1555 Adapter->NdisMiniportBlock.OldPnPDeviceState = Adapter->NdisMiniportBlock.PnPDeviceState;
1556 Adapter->NdisMiniportBlock.PnPDeviceState = NdisPnPDeviceStarted;
1557
1558 /* Put adapter in adapter list for this miniport */
1559 ExInterlockedInsertTailList(&Adapter->NdisMiniportBlock.DriverHandle->DeviceList, &Adapter->MiniportListEntry, &Adapter->NdisMiniportBlock.DriverHandle->Lock);
1560
1561 return STATUS_SUCCESS;
1562 }
1563
1564 \f
1565 NTSTATUS
1566 NTAPI
1567 NdisIPnPStopDevice(
1568 IN PDEVICE_OBJECT DeviceObject,
1569 PIRP Irp)
1570 /*
1571 * FUNCTION: Handle the PnP stop device event
1572 * ARGUMENTS:
1573 * DeviceObejct = Functional Device Object
1574 * Irp = IRP_MN_STOP_DEVICE I/O request packet
1575 * RETURNS:
1576 * Status of operation
1577 */
1578 {
1579 PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)DeviceObject->DeviceExtension;
1580 KIRQL OldIrql;
1581
1582 /* Remove adapter from adapter list for this miniport */
1583 KeAcquireSpinLock(&Adapter->NdisMiniportBlock.DriverHandle->Lock, &OldIrql);
1584 RemoveEntryList(&Adapter->MiniportListEntry);
1585 KeReleaseSpinLock(&Adapter->NdisMiniportBlock.DriverHandle->Lock, OldIrql);
1586
1587 /* Remove adapter from global adapter list */
1588 KeAcquireSpinLock(&AdapterListLock, &OldIrql);
1589 RemoveEntryList(&Adapter->ListEntry);
1590 KeReleaseSpinLock(&AdapterListLock, OldIrql);
1591
1592 (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.HaltHandler)(Adapter);
1593
1594 if (Adapter->LookaheadBuffer)
1595 {
1596 ExFreePool(Adapter->LookaheadBuffer);
1597 Adapter->LookaheadBuffer = NULL;
1598 }
1599 if (Adapter->NdisMiniportBlock.AllocatedResources)
1600 {
1601 ExFreePool(Adapter->NdisMiniportBlock.AllocatedResources);
1602 Adapter->NdisMiniportBlock.AllocatedResources = NULL;
1603 }
1604 if (Adapter->NdisMiniportBlock.AllocatedResourcesTranslated)
1605 {
1606 ExFreePool(Adapter->NdisMiniportBlock.AllocatedResourcesTranslated);
1607 Adapter->NdisMiniportBlock.AllocatedResourcesTranslated = NULL;
1608 }
1609
1610 Adapter->NdisMiniportBlock.OldPnPDeviceState = Adapter->NdisMiniportBlock.PnPDeviceState;
1611 Adapter->NdisMiniportBlock.PnPDeviceState = NdisPnPDeviceStopped;
1612
1613 return STATUS_SUCCESS;
1614 }
1615
1616 \f
1617 NTSTATUS
1618 NTAPI
1619 NdisIDispatchPnp(
1620 IN PDEVICE_OBJECT DeviceObject,
1621 PIRP Irp)
1622 {
1623 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
1624 PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)DeviceObject->DeviceExtension;
1625 NTSTATUS Status;
1626
1627 switch (Stack->MinorFunction)
1628 {
1629 case IRP_MN_START_DEVICE:
1630 Status = NdisIForwardIrpAndWait(Adapter, Irp);
1631 if (NT_SUCCESS(Status) && NT_SUCCESS(Irp->IoStatus.Status))
1632 {
1633 Status = NdisIPnPStartDevice(DeviceObject, Irp);
1634 }
1635 Irp->IoStatus.Status = Status;
1636 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1637 break;
1638
1639 case IRP_MN_STOP_DEVICE:
1640 Status = NdisIForwardIrpAndWait(Adapter, Irp);
1641 if (NT_SUCCESS(Status) && NT_SUCCESS(Irp->IoStatus.Status))
1642 {
1643 Status = NdisIPnPStopDevice(DeviceObject, Irp);
1644 }
1645 Irp->IoStatus.Status = Status;
1646 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1647 break;
1648
1649 case IRP_MN_QUERY_DEVICE_RELATIONS:
1650 Status = STATUS_NOT_SUPPORTED;
1651 Irp->IoStatus.Status = Status;
1652 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1653 break;
1654
1655 default:
1656 IoSkipCurrentIrpStackLocation(Irp);
1657 Status = IoCallDriver(Adapter->NdisMiniportBlock.NextDeviceObject, Irp);
1658 break;
1659 }
1660
1661 return Status;
1662 }
1663
1664 \f
1665 NTSTATUS
1666 NTAPI
1667 NdisIAddDevice(
1668 IN PDRIVER_OBJECT DriverObject,
1669 IN PDEVICE_OBJECT PhysicalDeviceObject)
1670 /*
1671 * FUNCTION: Create a device for an adapter found using PnP
1672 * ARGUMENTS:
1673 * DriverObject = Pointer to the miniport driver object
1674 * PhysicalDeviceObject = Pointer to the PDO for our adapter
1675 */
1676 {
1677 static const WCHAR ClassKeyName[] = {'C','l','a','s','s','\\'};
1678 static const WCHAR LinkageKeyName[] = {'\\','L','i','n','k','a','g','e',0};
1679 PNDIS_M_DRIVER_BLOCK Miniport;
1680 PNDIS_M_DRIVER_BLOCK *MiniportPtr;
1681 WCHAR *LinkageKeyBuffer;
1682 ULONG DriverKeyLength;
1683 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
1684 UNICODE_STRING ExportName;
1685 PDEVICE_OBJECT DeviceObject;
1686 PLOGICAL_ADAPTER Adapter;
1687 NTSTATUS Status;
1688
1689 /*
1690 * Gain the access to the miniport data structure first.
1691 */
1692
1693 MiniportPtr = IoGetDriverObjectExtension(DriverObject, (PVOID)TAG('D','I','M','N'));
1694 if (MiniportPtr == NULL)
1695 {
1696 NDIS_DbgPrint(DEBUG_MINIPORT, ("Can't get driver object extension.\n"));
1697 return STATUS_UNSUCCESSFUL;
1698 }
1699 Miniport = *MiniportPtr;
1700
1701 /*
1702 * Get name of the Linkage registry key for our adapter. It's located under
1703 * the driver key for our driver and so we have basicly two ways to do it.
1704 * Either we can use IoOpenDriverRegistryKey or compose it using information
1705 * gathered by IoGetDeviceProperty. I choosed the second because
1706 * IoOpenDriverRegistryKey wasn't implemented at the time of writing.
1707 */
1708
1709 Status = IoGetDeviceProperty(PhysicalDeviceObject, DevicePropertyDriverKeyName,
1710 0, NULL, &DriverKeyLength);
1711 if (Status != STATUS_BUFFER_TOO_SMALL && Status != STATUS_BUFFER_OVERFLOW && Status != STATUS_SUCCESS)
1712 {
1713 NDIS_DbgPrint(DEBUG_MINIPORT, ("Can't get miniport driver key length.\n"));
1714 return Status;
1715 }
1716
1717 LinkageKeyBuffer = ExAllocatePool(PagedPool, DriverKeyLength +
1718 sizeof(ClassKeyName) + sizeof(LinkageKeyName));
1719 if (LinkageKeyBuffer == NULL)
1720 {
1721 NDIS_DbgPrint(DEBUG_MINIPORT, ("Can't allocate memory for driver key name.\n"));
1722 return STATUS_INSUFFICIENT_RESOURCES;
1723 }
1724
1725 Status = IoGetDeviceProperty(PhysicalDeviceObject, DevicePropertyDriverKeyName,
1726 DriverKeyLength, LinkageKeyBuffer +
1727 (sizeof(ClassKeyName) / sizeof(WCHAR)),
1728 &DriverKeyLength);
1729 if (!NT_SUCCESS(Status))
1730 {
1731 NDIS_DbgPrint(DEBUG_MINIPORT, ("Can't get miniport driver key.\n"));
1732 ExFreePool(LinkageKeyBuffer);
1733 return Status;
1734 }
1735
1736 /* Compose the linkage key name. */
1737 RtlCopyMemory(LinkageKeyBuffer, ClassKeyName, sizeof(ClassKeyName));
1738 RtlCopyMemory(LinkageKeyBuffer + ((sizeof(ClassKeyName) + DriverKeyLength) /
1739 sizeof(WCHAR)) - 1, LinkageKeyName, sizeof(LinkageKeyName));
1740
1741 NDIS_DbgPrint(DEBUG_MINIPORT, ("LinkageKey: %S.\n", LinkageKeyBuffer));
1742
1743 /*
1744 * Now open the linkage key and read the "Export" and "RootDevice" values
1745 * which contains device name and root service respectively.
1746 */
1747
1748 RtlZeroMemory(QueryTable, sizeof(QueryTable));
1749 RtlInitUnicodeString(&ExportName, NULL);
1750 QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_DIRECT;
1751 QueryTable[0].Name = L"Export";
1752 QueryTable[0].EntryContext = &ExportName;
1753
1754 Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL, LinkageKeyBuffer,
1755 QueryTable, NULL, NULL);
1756 ExFreePool(LinkageKeyBuffer);
1757 if (!NT_SUCCESS(Status))
1758 {
1759 NDIS_DbgPrint(DEBUG_MINIPORT, ("Can't get miniport device name. (%x)\n", Status));
1760 return Status;
1761 }
1762
1763 /*
1764 * Create the device object.
1765 */
1766
1767 NDIS_DbgPrint(MAX_TRACE, ("creating device %wZ\n", &ExportName));
1768
1769 Status = IoCreateDevice(Miniport->DriverObject, sizeof(LOGICAL_ADAPTER),
1770 &ExportName, FILE_DEVICE_PHYSICAL_NETCARD,
1771 0, FALSE, &DeviceObject);
1772 if (!NT_SUCCESS(Status))
1773 {
1774 NDIS_DbgPrint(MIN_TRACE, ("Could not create device object.\n"));
1775 RtlFreeUnicodeString(&ExportName);
1776 return Status;
1777 }
1778
1779 /*
1780 * Initialize the adapter structure.
1781 */
1782
1783 Adapter = (PLOGICAL_ADAPTER)DeviceObject->DeviceExtension;
1784 KeInitializeSpinLock(&Adapter->NdisMiniportBlock.Lock);
1785 InitializeListHead(&Adapter->ProtocolListHead);
1786 Adapter->NdisMiniportBlock.DriverHandle = Miniport;
1787
1788 Adapter->NdisMiniportBlock.MiniportName = ExportName;
1789
1790 Adapter->NdisMiniportBlock.DeviceObject = DeviceObject;
1791 Adapter->NdisMiniportBlock.PhysicalDeviceObject = PhysicalDeviceObject;
1792 Adapter->NdisMiniportBlock.NextDeviceObject =
1793 IoAttachDeviceToDeviceStack(Adapter->NdisMiniportBlock.DeviceObject,
1794 PhysicalDeviceObject);
1795
1796 Adapter->NdisMiniportBlock.OldPnPDeviceState = 0;
1797 Adapter->NdisMiniportBlock.PnPDeviceState = NdisPnPDeviceAdded;
1798
1799 KeInitializeDpc(&Adapter->NdisMiniportBlock.DeferredDpc, MiniportDpc, (PVOID)Adapter);
1800
1801 DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
1802
1803 return STATUS_SUCCESS;
1804 }
1805
1806 \f
1807 /*
1808 * @implemented
1809 */
1810 NDIS_STATUS
1811 EXPORT
1812 NdisMRegisterMiniport(
1813 IN NDIS_HANDLE NdisWrapperHandle,
1814 IN PNDIS_MINIPORT_CHARACTERISTICS MiniportCharacteristics,
1815 IN UINT CharacteristicsLength)
1816 /*
1817 * FUNCTION: Registers a miniport's MiniportXxx entry points with the NDIS library
1818 * ARGUMENTS:
1819 * NdisWrapperHandle = Pointer to handle returned by NdisMInitializeWrapper
1820 * MiniportCharacteristics = Pointer to a buffer with miniport characteristics
1821 * CharacteristicsLength = Number of bytes in characteristics buffer
1822 * RETURNS:
1823 * Status of operation
1824 */
1825 {
1826 UINT MinSize;
1827 PNDIS_M_DRIVER_BLOCK Miniport = GET_MINIPORT_DRIVER(NdisWrapperHandle);
1828 PNDIS_M_DRIVER_BLOCK *MiniportPtr;
1829 NTSTATUS Status;
1830
1831 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
1832
1833 switch (MiniportCharacteristics->MajorNdisVersion)
1834 {
1835 case 0x03:
1836 MinSize = sizeof(NDIS30_MINIPORT_CHARACTERISTICS);
1837 break;
1838
1839 case 0x04:
1840 MinSize = sizeof(NDIS40_MINIPORT_CHARACTERISTICS);
1841 break;
1842
1843 case 0x05:
1844 MinSize = sizeof(NDIS50_MINIPORT_CHARACTERISTICS);
1845 break;
1846
1847 default:
1848 NDIS_DbgPrint(DEBUG_MINIPORT, ("Bad miniport characteristics version.\n"));
1849 return NDIS_STATUS_BAD_VERSION;
1850 }
1851
1852 if (CharacteristicsLength < MinSize)
1853 {
1854 NDIS_DbgPrint(DEBUG_MINIPORT, ("Bad miniport characteristics.\n"));
1855 return NDIS_STATUS_BAD_CHARACTERISTICS;
1856 }
1857
1858 /* Check if mandatory MiniportXxx functions are specified */
1859 if ((!MiniportCharacteristics->HaltHandler) ||
1860 (!MiniportCharacteristics->InitializeHandler)||
1861 (!MiniportCharacteristics->QueryInformationHandler) ||
1862 (!MiniportCharacteristics->ResetHandler) ||
1863 (!MiniportCharacteristics->SetInformationHandler))
1864 {
1865 NDIS_DbgPrint(DEBUG_MINIPORT, ("Bad miniport characteristics.\n"));
1866 return NDIS_STATUS_BAD_CHARACTERISTICS;
1867 }
1868
1869 if (MiniportCharacteristics->MajorNdisVersion == 0x03)
1870 {
1871 if (!MiniportCharacteristics->SendHandler)
1872 {
1873 NDIS_DbgPrint(DEBUG_MINIPORT, ("Bad miniport characteristics.\n"));
1874 return NDIS_STATUS_BAD_CHARACTERISTICS;
1875 }
1876 }
1877 else if (MiniportCharacteristics->MajorNdisVersion >= 0x04)
1878 {
1879 /* NDIS 4.0+ */
1880 if ((!MiniportCharacteristics->SendHandler) &&
1881 (!MiniportCharacteristics->SendPacketsHandler))
1882 {
1883 NDIS_DbgPrint(DEBUG_MINIPORT, ("Bad miniport characteristics.\n"));
1884 return NDIS_STATUS_BAD_CHARACTERISTICS;
1885 }
1886 }
1887
1888 /* TODO: verify NDIS5 and NDIS5.1 */
1889
1890 RtlCopyMemory(&Miniport->MiniportCharacteristics, MiniportCharacteristics, MinSize);
1891
1892 /*
1893 * NOTE: This is VERY unoptimal! Should we store the NDIS_M_DRIVER_BLOCK
1894 * structure in the driver extension or what?
1895 */
1896
1897 Status = IoAllocateDriverObjectExtension(Miniport->DriverObject, (PVOID)TAG('D','I','M','N'),
1898 sizeof(PNDIS_M_DRIVER_BLOCK), (PVOID*)&MiniportPtr);
1899 if (!NT_SUCCESS(Status))
1900 {
1901 NDIS_DbgPrint(DEBUG_MINIPORT, ("Can't allocate driver object extension.\n"));
1902 return NDIS_STATUS_RESOURCES;
1903 }
1904
1905 *MiniportPtr = Miniport;
1906
1907 Miniport->DriverObject->MajorFunction[IRP_MJ_PNP] = NdisIDispatchPnp;
1908 Miniport->DriverObject->DriverExtension->AddDevice = NdisIAddDevice;
1909
1910 return NDIS_STATUS_SUCCESS;
1911 }
1912
1913 \f
1914 /*
1915 * @implemented
1916 */
1917 #undef NdisMResetComplete
1918 VOID
1919 EXPORT
1920 NdisMResetComplete(
1921 IN NDIS_HANDLE MiniportAdapterHandle,
1922 IN NDIS_STATUS Status,
1923 IN BOOLEAN AddressingReset)
1924 {
1925 MiniResetComplete(MiniportAdapterHandle, Status, AddressingReset);
1926 }
1927
1928 \f
1929 /*
1930 * @implemented
1931 */
1932 #undef NdisMSendComplete
1933 VOID
1934 EXPORT
1935 NdisMSendComplete(
1936 IN NDIS_HANDLE MiniportAdapterHandle,
1937 IN PNDIS_PACKET Packet,
1938 IN NDIS_STATUS Status)
1939 /*
1940 * FUNCTION: Forwards a message to the initiating protocol saying
1941 * that a packet was handled
1942 * ARGUMENTS:
1943 * NdisAdapterHandle = Handle input to MiniportInitialize
1944 * Packet = Pointer to NDIS packet that was sent
1945 * Status = Status of send operation
1946 */
1947 {
1948 MiniSendComplete(MiniportAdapterHandle, Packet, Status);
1949 }
1950
1951 \f
1952 /*
1953 * @implemented
1954 */
1955 #undef NdisMSendResourcesAvailable
1956 VOID
1957 EXPORT
1958 NdisMSendResourcesAvailable(
1959 IN NDIS_HANDLE MiniportAdapterHandle)
1960 {
1961 MiniSendResourcesAvailable(MiniportAdapterHandle);
1962 }
1963
1964 \f
1965 /*
1966 * @implemented
1967 */
1968 #undef NdisMTransferDataComplete
1969 VOID
1970 EXPORT
1971 NdisMTransferDataComplete(
1972 IN NDIS_HANDLE MiniportAdapterHandle,
1973 IN PNDIS_PACKET Packet,
1974 IN NDIS_STATUS Status,
1975 IN UINT BytesTransferred)
1976 {
1977 MiniTransferDataComplete(MiniportAdapterHandle, Packet, Status, BytesTransferred);
1978 }
1979
1980 \f
1981 /*
1982 * @implemented
1983 */
1984 #undef NdisMSetInformationComplete
1985 VOID
1986 EXPORT
1987 NdisMSetInformationComplete(
1988 IN NDIS_HANDLE MiniportAdapterHandle,
1989 IN NDIS_STATUS Status)
1990 {
1991 KIRQL OldIrql;
1992 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
1993 (*((PNDIS_MINIPORT_BLOCK)(MiniportAdapterHandle))->SetCompleteHandler)(MiniportAdapterHandle, Status);
1994 KeLowerIrql(OldIrql);
1995 }
1996
1997 \f
1998 /*
1999 * @implemented
2000 */
2001 #undef NdisMSetAttributes
2002 VOID
2003 EXPORT
2004 NdisMSetAttributes(
2005 IN NDIS_HANDLE MiniportAdapterHandle,
2006 IN NDIS_HANDLE MiniportAdapterContext,
2007 IN BOOLEAN BusMaster,
2008 IN NDIS_INTERFACE_TYPE AdapterType)
2009 /*
2010 * FUNCTION: Informs the NDIS library of significant features of the caller's NIC
2011 * ARGUMENTS:
2012 * MiniportAdapterHandle = Handle input to MiniportInitialize
2013 * MiniportAdapterContext = Pointer to context information
2014 * BusMaster = Specifies TRUE if the caller's NIC is a busmaster DMA device
2015 * AdapterType = Specifies the I/O bus interface of the caller's NIC
2016 */
2017 {
2018 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
2019 NdisMSetAttributesEx(MiniportAdapterHandle, MiniportAdapterContext, 0,
2020 BusMaster ? NDIS_ATTRIBUTE_BUS_MASTER : 0,
2021 AdapterType);
2022 }
2023
2024 \f
2025 /*
2026 * @implemented
2027 */
2028 VOID
2029 EXPORT
2030 NdisMSetAttributesEx(
2031 IN NDIS_HANDLE MiniportAdapterHandle,
2032 IN NDIS_HANDLE MiniportAdapterContext,
2033 IN UINT CheckForHangTimeInSeconds OPTIONAL,
2034 IN ULONG AttributeFlags,
2035 IN NDIS_INTERFACE_TYPE AdapterType)
2036 /*
2037 * FUNCTION: Informs the NDIS library of significant features of the caller's NIC
2038 * ARGUMENTS:
2039 * MiniportAdapterHandle = Handle input to MiniportInitialize
2040 * MiniportAdapterContext = Pointer to context information
2041 * CheckForHangTimeInSeconds = Specifies interval in seconds at which
2042 * MiniportCheckForHang should be called
2043 * AttributeFlags = Bitmask that indicates specific attributes
2044 * AdapterType = Specifies the I/O bus interface of the caller's NIC
2045 */
2046 {
2047 /* TODO: Take CheckForHandTimeInSeconds into account! */
2048
2049 PLOGICAL_ADAPTER Adapter = GET_LOGICAL_ADAPTER(MiniportAdapterHandle);
2050
2051 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
2052
2053 Adapter->NdisMiniportBlock.MiniportAdapterContext = MiniportAdapterContext;
2054 Adapter->NdisMiniportBlock.Flags = AttributeFlags;
2055 Adapter->NdisMiniportBlock.AdapterType = AdapterType;
2056 if (AttributeFlags & NDIS_ATTRIBUTE_INTERMEDIATE_DRIVER)
2057 NDIS_DbgPrint(MAX_TRACE, ("Intermediate drivers not supported yet.\n"));
2058 }
2059
2060 \f
2061 /*
2062 * @implemented
2063 */
2064 VOID
2065 EXPORT
2066 NdisMSleep(
2067 IN ULONG MicrosecondsToSleep)
2068 /*
2069 * FUNCTION: delay the thread's execution for MicrosecondsToSleep
2070 * ARGUMENTS:
2071 * MicrosecondsToSleep: duh...
2072 * NOTES:
2073 * - Because this is a blocking call, current IRQL must be < DISPATCH_LEVEL
2074 */
2075 {
2076 KTIMER Timer;
2077 LARGE_INTEGER DueTime;
2078
2079 PAGED_CODE();
2080
2081 DueTime.QuadPart = (-1) * 10 * MicrosecondsToSleep;
2082
2083 KeInitializeTimer(&Timer);
2084 KeSetTimer(&Timer, DueTime, 0);
2085 KeWaitForSingleObject(&Timer, Executive, KernelMode, FALSE, 0);
2086 }
2087
2088 \f
2089 /*
2090 * @implemented
2091 */
2092 BOOLEAN
2093 EXPORT
2094 NdisMSynchronizeWithInterrupt(
2095 IN PNDIS_MINIPORT_INTERRUPT Interrupt,
2096 IN PVOID SynchronizeFunction,
2097 IN PVOID SynchronizeContext)
2098 {
2099 return(KeSynchronizeExecution(Interrupt->InterruptObject,
2100 (PKSYNCHRONIZE_ROUTINE)SynchronizeFunction,
2101 SynchronizeContext));
2102 }
2103
2104 \f
2105 /*
2106 * @unimplemented
2107 */
2108 NDIS_STATUS
2109 EXPORT
2110 NdisMWriteLogData(
2111 IN NDIS_HANDLE LogHandle,
2112 IN PVOID LogBuffer,
2113 IN UINT LogBufferSize)
2114 {
2115 PUCHAR Buffer = LogBuffer;
2116 UINT i, j, idx;
2117
2118 UNIMPLEMENTED;
2119 for (i = 0; i < LogBufferSize; i += 16)
2120 {
2121 DbgPrint("%08x |", i);
2122 for (j = 0; j < 16; j++)
2123 {
2124 idx = i + j;
2125 if (idx < LogBufferSize)
2126 DbgPrint(" %02x", Buffer[idx]);
2127 else
2128 DbgPrint(" ");
2129 }
2130 DbgPrint(" | ");
2131 for (j = 0; j < 16; j++)
2132 {
2133 idx = i + j;
2134 if (idx == LogBufferSize)
2135 break;
2136 if (Buffer[idx] >= ' ') /* FIXME: not portable! replace by if (isprint(Buffer[idx])) ? */
2137 DbgPrint("%c", Buffer[idx]);
2138 else
2139 DbgPrint(".");
2140 }
2141 DbgPrint("\n");
2142 }
2143
2144 return NDIS_STATUS_FAILURE;
2145 }
2146
2147 \f
2148 /*
2149 * @implemented
2150 */
2151 VOID
2152 EXPORT
2153 NdisTerminateWrapper(
2154 IN NDIS_HANDLE NdisWrapperHandle,
2155 IN PVOID SystemSpecific)
2156 /*
2157 * FUNCTION: Releases resources allocated by a call to NdisInitializeWrapper
2158 * ARGUMENTS:
2159 * NdisWrapperHandle = Handle returned by NdisInitializeWrapper (NDIS_M_DRIVER_BLOCK)
2160 * SystemSpecific = Always NULL
2161 */
2162 {
2163 PNDIS_M_DRIVER_BLOCK Miniport = GET_MINIPORT_DRIVER(NdisWrapperHandle);
2164
2165 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
2166
2167 ExFreePool(Miniport->RegistryPath->Buffer);
2168 ExFreePool(Miniport->RegistryPath);
2169 ExFreePool(Miniport);
2170 }
2171
2172 /* EOF */
2173