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