changed callbacks to use stdcall
[reactos.git] / reactos / drivers / net / ndis / ndis / protocol.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS NDIS library
4 * FILE: ndis/protocol.c
5 * PURPOSE: Routines used by NDIS protocol drivers
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * Vizzini (vizzini@plasmic.com)
8 * REVISIONS:
9 * CSH 01/08-2000 Created
10 * 09-13-2003 Vizzini Updates for SendPackets support
11 */
12 #include <ndissys.h>
13 #include <miniport.h>
14 #include <protocol.h>
15 #include <buffer.h>
16
17 #define SERVICES_KEY L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"
18 #define LINKAGE_KEY L"\\Linkage"
19 #define PARAMETERS_KEY L"\\Parameters\\"
20
21 LIST_ENTRY ProtocolListHead;
22 KSPIN_LOCK ProtocolListLock;
23
24 \f
25 /*
26 * @implemented
27 */
28 VOID
29 EXPORT
30 NdisCompleteBindAdapter(
31 IN NDIS_HANDLE BindAdapterContext,
32 IN NDIS_STATUS Status,
33 IN NDIS_STATUS OpenStatus)
34 /*
35 * FUNCTION: Indicates a packet to bound protocols
36 * ARGUMENTS:
37 * Adapter = Pointer to logical adapter
38 * Packet = Pointer to packet to indicate
39 * RETURNS:
40 * Status of operation
41 * NOTES:
42 * - FIXME: partially-implemented
43 */
44 {
45 PROTOCOL_BINDING *Protocol = (PROTOCOL_BINDING *)BindAdapterContext;
46
47 /* Put protocol binding struct on global list */
48 ExInterlockedInsertTailList(&ProtocolListHead, &Protocol->ListEntry, &ProtocolListLock);
49 }
50
51 \f
52 NDIS_STATUS
53 ProIndicatePacket(
54 PLOGICAL_ADAPTER Adapter,
55 PNDIS_PACKET Packet)
56 /*
57 * FUNCTION: Indicates a packet to bound protocols
58 * ARGUMENTS:
59 * Adapter = Pointer to logical adapter
60 * Packet = Pointer to packet to indicate
61 * RETURNS:
62 * STATUS_SUCCESS in all cases
63 * NOTES:
64 * - XXX ATM, this only handles loopback packets - is that its designed function?
65 */
66 {
67 KIRQL OldIrql;
68 UINT BufferedLength;
69 UINT PacketLength;
70
71 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
72
73 #ifdef DBG
74 MiniDisplayPacket(Packet);
75 #endif
76
77 NdisQueryPacket(Packet, NULL, NULL, NULL, &PacketLength);
78
79 KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
80 {
81 Adapter->LoopPacket = Packet;
82 BufferedLength = CopyPacketToBuffer(Adapter->LookaheadBuffer, Packet, 0, Adapter->CurLookaheadLength);
83 }
84 KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
85
86 if (BufferedLength > Adapter->MediumHeaderSize)
87 {
88 /* XXX Change this to call SendPackets so we don't have to duplicate this wacky logic */
89 MiniIndicateData(Adapter, NULL, Adapter->LookaheadBuffer, Adapter->MediumHeaderSize,
90 &Adapter->LookaheadBuffer[Adapter->MediumHeaderSize], BufferedLength - Adapter->MediumHeaderSize,
91 PacketLength - Adapter->MediumHeaderSize);
92 }
93 else
94 {
95 MiniIndicateData(Adapter, NULL, Adapter->LookaheadBuffer, Adapter->MediumHeaderSize, NULL, 0, 0);
96 }
97
98 KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
99 {
100 Adapter->LoopPacket = NULL;
101 }
102 KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
103
104 return STATUS_SUCCESS;
105 }
106
107 \f
108 NDIS_STATUS
109 ProRequest(
110 IN NDIS_HANDLE MacBindingHandle,
111 IN PNDIS_REQUEST NdisRequest)
112 /*
113 * FUNCTION: Forwards a request to an NDIS miniport
114 * ARGUMENTS:
115 * MacBindingHandle = Adapter binding handle
116 * NdisRequest = Pointer to request to perform
117 * RETURNS:
118 * Status of operation
119 */
120 {
121 KIRQL OldIrql;
122 BOOLEAN QueueWorkItem;
123 NDIS_STATUS NdisStatus;
124 PADAPTER_BINDING AdapterBinding;
125 PLOGICAL_ADAPTER Adapter;
126
127 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
128
129 ASSERT(MacBindingHandle);
130 AdapterBinding = GET_ADAPTER_BINDING(MacBindingHandle);
131
132 ASSERT(AdapterBinding->Adapter);
133 Adapter = AdapterBinding->Adapter;
134
135 /*
136 * If the miniport is already busy, queue a workitem
137 */
138 KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
139 {
140 if(Adapter->MiniportBusy)
141 QueueWorkItem = TRUE;
142 else
143 Adapter->MiniportBusy = TRUE;
144 }
145 KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
146
147 if (QueueWorkItem)
148 {
149 MiniQueueWorkItem(Adapter, NdisWorkItemRequest, (PVOID)NdisRequest, (NDIS_HANDLE)AdapterBinding);
150 return NDIS_STATUS_PENDING;
151 }
152
153 /* MiniportQueryInformation (called by MiniDoRequest) runs at DISPATCH_LEVEL */
154 /* TODO (?): move the irql raise into MiniDoRequest */
155 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
156 {
157 NdisStatus = MiniDoRequest(Adapter, NdisRequest);
158
159 KeAcquireSpinLockAtDpcLevel(&Adapter->NdisMiniportBlock.Lock);
160 {
161 Adapter->MiniportBusy = FALSE;
162
163 if (Adapter->WorkQueueHead)
164 KeInsertQueueDpc(&Adapter->MiniportDpc, NULL, NULL);
165 }
166 KeReleaseSpinLockFromDpcLevel(&Adapter->NdisMiniportBlock.Lock);
167 }
168 KeLowerIrql(OldIrql);
169
170 return NdisStatus;
171 }
172
173 \f
174 NDIS_STATUS
175 ProReset(
176 IN NDIS_HANDLE MacBindingHandle)
177 {
178 UNIMPLEMENTED
179
180 return NDIS_STATUS_FAILURE;
181 }
182
183 \f
184 NDIS_STATUS
185 ProSend(
186 IN NDIS_HANDLE MacBindingHandle,
187 IN PNDIS_PACKET Packet)
188 /*
189 * FUNCTION: Forwards a request to send a packet to an NDIS miniport
190 * ARGUMENTS:
191 * MacBindingHandle = Adapter binding handle
192 * Packet = Pointer to NDIS packet descriptor
193 * RETURNS:
194 * NDIS_STATUS_SUCCESS always
195 * NOTES:
196 * TODO:
197 * - Fix return values
198 * - Should queue packet if miniport returns NDIS_STATUS_RESOURCES
199 * - Queue packets directly on the adapters when possible (i.e.
200 * when miniports not busy)
201 * - Break this up
202 */
203 {
204 KIRQL RaiseOldIrql, SpinOldIrql;
205 BOOLEAN QueueWorkItem;
206 NDIS_STATUS NdisStatus;
207 PADAPTER_BINDING AdapterBinding;
208 PLOGICAL_ADAPTER Adapter;
209
210 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
211
212 ASSERT(MacBindingHandle);
213 AdapterBinding = GET_ADAPTER_BINDING(MacBindingHandle);
214
215 ASSERT(AdapterBinding);
216 Adapter = AdapterBinding->Adapter;
217
218 ASSERT(Adapter);
219
220 /* if the following is not true, KeRaiseIrql() below will break */
221 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
222
223 /* XXX what is this crazy black magic? */
224 Packet->Reserved[0] = (ULONG_PTR)MacBindingHandle;
225
226 /*
227 * Acquire this lock in order to see if the miniport is busy.
228 * If it is not busy, we mark it as busy and release the lock.
229 * Else we don't do anything because we have to queue a workitem
230 * anyway.
231 */
232 KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &SpinOldIrql);
233 {
234 /*
235 * if the miniport is marked as busy, we queue the packet as a work item,
236 * else we send the packet directly to the miniport. Sending to the miniport
237 * makes it busy.
238 */
239 if (Adapter->MiniportBusy)
240 QueueWorkItem = TRUE;
241 else
242 Adapter->MiniportBusy = TRUE;
243 }
244 KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, SpinOldIrql);
245
246 /*
247 * Test the packet to see if it is a MAC loopback.
248 *
249 * We may have to loop this packet if miniport cannot.
250 * If dest MAC address of packet == MAC address of adapter,
251 * this is a loopback frame.
252 */
253 if ((Adapter->NdisMiniportBlock.MacOptions & NDIS_MAC_OPTION_NO_LOOPBACK) &&
254 MiniAdapterHasAddress(Adapter, Packet))
255 {
256 NDIS_DbgPrint(MIN_TRACE, ("Looping packet.\n"));
257
258 if (QueueWorkItem)
259 {
260 MiniQueueWorkItem(Adapter, NdisWorkItemSendLoopback, (PVOID)Packet, (NDIS_HANDLE)AdapterBinding);
261 return NDIS_STATUS_PENDING;
262 }
263
264 KeRaiseIrql(DISPATCH_LEVEL, &RaiseOldIrql);
265 {
266 /*
267 * atm this *only* handles loopback packets - it calls MiniIndicateData to
268 * send back to the protocol. FIXME: this will need to be adjusted a bit.
269 * Also, I'm not sure you really have to be at dispatch level for this. It
270 * might use a ReceivePackets handler, which can run <= DISPATCH_LEVEL.
271 */
272 NdisStatus = ProIndicatePacket(Adapter, Packet);
273
274 KeAcquireSpinLockAtDpcLevel(&Adapter->NdisMiniportBlock.Lock);
275 {
276 Adapter->MiniportBusy = FALSE;
277
278 if (Adapter->WorkQueueHead)
279 KeInsertQueueDpc(&Adapter->MiniportDpc, NULL, NULL);
280 else
281 NDIS_DbgPrint(MID_TRACE,("Failed to insert packet into work queue\n"));
282 }
283 KeReleaseSpinLockFromDpcLevel(&Adapter->NdisMiniportBlock.Lock);
284 }
285 KeLowerIrql(RaiseOldIrql);
286
287 return NdisStatus;
288 }
289 else
290 NDIS_DbgPrint(MID_TRACE,("Not a loopback packet\n"));
291
292 /* This is a normal send packet, not a loopback packet. */
293 if (QueueWorkItem)
294 {
295 MiniQueueWorkItem(Adapter, NdisWorkItemSend, (PVOID)Packet, (NDIS_HANDLE)AdapterBinding);
296 NDIS_DbgPrint(MAX_TRACE, ("Queued a work item and returning\n"));
297 return NDIS_STATUS_PENDING;
298 }
299
300 ASSERT(Adapter->Miniport);
301
302 /*
303 * Call the appropriate send handler
304 *
305 * If a miniport provides a SendPackets handler, we always call it. If not, we call the
306 * Send handler.
307 */
308 if(Adapter->Miniport->Chars.SendPacketsHandler)
309 {
310 /* TODO: support deserialized miniports by checking for attributes */
311 /* SendPackets is called at DISPATCH_LEVEL for all serialized miniports */
312 KeRaiseIrql(DISPATCH_LEVEL, &RaiseOldIrql);
313 {
314 NDIS_DbgPrint(MAX_TRACE, ("Calling miniport's SendPackets handler\n"));
315 (*Adapter->Miniport->Chars.SendPacketsHandler)(Adapter->NdisMiniportBlock.MiniportAdapterContext, &Packet, 1);
316 }
317 KeLowerIrql(RaiseOldIrql);
318
319 /* XXX why the hell do we do this? */
320 KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &SpinOldIrql);
321 {
322 if (Adapter->WorkQueueHead)
323 KeInsertQueueDpc(&Adapter->MiniportDpc, NULL, NULL);
324 }
325 KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, SpinOldIrql);
326
327 NDIS_DbgPrint(MAX_TRACE, ("MiniportDpc queued; returning NDIS_STATUS_SCUCESS\n"));
328
329 /* SendPackets handlers return void - they always "succeed" */
330 NdisStatus = NDIS_STATUS_SUCCESS;
331 }
332 else
333 {
334 /* Send handlers always run at DISPATCH_LEVEL so we raise here */
335 KeRaiseIrql(DISPATCH_LEVEL, &RaiseOldIrql);
336 {
337 /* XXX FIXME THIS IS WRONG */
338 /* uh oh... forgot why i thought that... */
339
340 NDIS_DbgPrint(MAX_TRACE, ("Calling miniport's Send handler\n"));
341 NdisStatus = (*Adapter->Miniport->Chars.u1.SendHandler)(Adapter->NdisMiniportBlock.MiniportAdapterContext, Packet, 0);
342 NDIS_DbgPrint(MAX_TRACE, ("back from miniport's send handler\n"));
343
344 /* XXX why the hell do we do this? */
345 KeAcquireSpinLockAtDpcLevel(&Adapter->NdisMiniportBlock.Lock);
346 {
347 if (Adapter->WorkQueueHead)
348 KeInsertQueueDpc(&Adapter->MiniportDpc, NULL, NULL);
349 }
350 KeReleaseSpinLockFromDpcLevel(&Adapter->NdisMiniportBlock.Lock);
351 }
352 KeLowerIrql(RaiseOldIrql);
353 }
354
355 NDIS_DbgPrint(MAX_TRACE, ("returning 0x%x\n", NdisStatus));
356 return NdisStatus;
357 }
358
359 \f
360 VOID
361 ProSendPackets(
362 IN NDIS_HANDLE NdisBindingHandle,
363 IN PPNDIS_PACKET PacketArray,
364 IN UINT NumberOfPackets)
365 {
366 UNIMPLEMENTED
367 }
368
369 \f
370 NDIS_STATUS
371 ProTransferData(
372 IN NDIS_HANDLE MacBindingHandle,
373 IN NDIS_HANDLE MacReceiveContext,
374 IN UINT ByteOffset,
375 IN UINT BytesToTransfer,
376 IN OUT PNDIS_PACKET Packet,
377 OUT PUINT BytesTransferred)
378 /*
379 * FUNCTION: Forwards a request to copy received data into a protocol-supplied packet
380 * ARGUMENTS:
381 * MacBindingHandle = Adapter binding handle
382 * MacReceiveContext = MAC receive context
383 * ByteOffset = Offset in packet to place data
384 * BytesToTransfer = Number of bytes to copy into packet
385 * Packet = Pointer to NDIS packet descriptor
386 * BytesTransferred = Address of buffer to place number of bytes copied
387 */
388 {
389 PADAPTER_BINDING AdapterBinding = GET_ADAPTER_BINDING(MacBindingHandle);
390 PLOGICAL_ADAPTER Adapter = AdapterBinding->Adapter;
391
392 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
393
394 /* FIXME: Interrupts must be disabled for adapter */
395 /* XXX sd - why is that true? */
396
397 if (Packet == Adapter->LoopPacket) {
398 /* NDIS is responsible for looping this packet */
399 NdisCopyFromPacketToPacket(Packet,
400 ByteOffset,
401 BytesToTransfer,
402 Adapter->LoopPacket,
403 0,
404 BytesTransferred);
405 return NDIS_STATUS_SUCCESS;
406 }
407
408 return (*Adapter->Miniport->Chars.u2.TransferDataHandler)(
409 Packet,
410 BytesTransferred,
411 Adapter->NdisMiniportBlock.MiniportAdapterContext,
412 MacReceiveContext,
413 ByteOffset,
414 BytesToTransfer);
415 }
416
417
418
419 /*
420 * @implemented
421 */
422 VOID
423 EXPORT
424 NdisCloseAdapter(
425 OUT PNDIS_STATUS Status,
426 IN NDIS_HANDLE NdisBindingHandle)
427 /*
428 * FUNCTION: Closes an adapter opened with NdisOpenAdapter
429 * ARGUMENTS:
430 * Status = Address of buffer for status information
431 * NdisBindingHandle = Handle returned by NdisOpenAdapter
432 */
433 {
434 KIRQL OldIrql;
435 PADAPTER_BINDING AdapterBinding = GET_ADAPTER_BINDING(NdisBindingHandle);
436
437 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
438
439 /* Remove from protocol's bound adapters list */
440 KeAcquireSpinLock(&AdapterBinding->ProtocolBinding->Lock, &OldIrql);
441 RemoveEntryList(&AdapterBinding->ProtocolListEntry);
442 KeReleaseSpinLock(&AdapterBinding->ProtocolBinding->Lock, OldIrql);
443
444 /* Remove protocol from adapter's bound protocols list */
445 KeAcquireSpinLock(&AdapterBinding->Adapter->NdisMiniportBlock.Lock, &OldIrql);
446 RemoveEntryList(&AdapterBinding->AdapterListEntry);
447 KeReleaseSpinLock(&AdapterBinding->Adapter->NdisMiniportBlock.Lock, OldIrql);
448
449 ExFreePool(AdapterBinding);
450
451 *Status = NDIS_STATUS_SUCCESS;
452 }
453
454
455 /*
456 * @implemented
457 */
458 VOID
459 EXPORT
460 NdisDeregisterProtocol(
461 OUT PNDIS_STATUS Status,
462 IN NDIS_HANDLE NdisProtocolHandle)
463 /*
464 * FUNCTION: Releases the resources allocated by NdisRegisterProtocol
465 * ARGUMENTS:
466 * Status = Address of buffer for status information
467 * NdisProtocolHandle = Handle returned by NdisRegisterProtocol
468 */
469 {
470 KIRQL OldIrql;
471 PPROTOCOL_BINDING Protocol = GET_PROTOCOL_BINDING(NdisProtocolHandle);
472
473 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
474
475 /* FIXME: Make sure no adapter bindings exist */
476
477 /* Remove protocol from global list */
478 KeAcquireSpinLock(&ProtocolListLock, &OldIrql);
479 RemoveEntryList(&Protocol->ListEntry);
480 KeReleaseSpinLock(&ProtocolListLock, OldIrql);
481
482 ExFreePool(Protocol);
483
484 *Status = NDIS_STATUS_SUCCESS;
485 }
486
487
488 /*
489 * @implemented
490 */
491 VOID
492 EXPORT
493 NdisOpenAdapter(
494 OUT PNDIS_STATUS Status,
495 OUT PNDIS_STATUS OpenErrorStatus,
496 OUT PNDIS_HANDLE NdisBindingHandle,
497 OUT PUINT SelectedMediumIndex,
498 IN PNDIS_MEDIUM MediumArray,
499 IN UINT MediumArraySize,
500 IN NDIS_HANDLE NdisProtocolHandle,
501 IN NDIS_HANDLE ProtocolBindingContext,
502 IN PNDIS_STRING AdapterName,
503 IN UINT OpenOptions,
504 IN PSTRING AddressingInformation OPTIONAL)
505 /*
506 * FUNCTION: Opens an adapter for communication
507 * ARGUMENTS:
508 * Status = Address of buffer for status information
509 * OpenErrorStatus = Address of buffer for secondary error code
510 * NdisBindingHandle = Address of buffer for adapter binding handle
511 * SelectedMediumIndex = Address of buffer for selected medium
512 * MediumArray = Pointer to an array of NDIS_MEDIUMs called can support
513 * MediumArraySize = Number of elements in MediumArray
514 * NdisProtocolHandle = Handle returned by NdisRegisterProtocol
515 * ProtocolBindingContext = Pointer to caller suplied context area
516 * AdapterName = Pointer to buffer with name of adapter
517 * OpenOptions = Bitmask with flags passed to next-lower driver
518 * AddressingInformation = Optional pointer to buffer with NIC specific information
519 */
520 {
521 UINT i;
522 BOOLEAN Found;
523 PLOGICAL_ADAPTER Adapter;
524 PADAPTER_BINDING AdapterBinding;
525 PPROTOCOL_BINDING Protocol = GET_PROTOCOL_BINDING(NdisProtocolHandle);
526
527 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
528
529 if(!NdisProtocolHandle)
530 {
531 NDIS_DbgPrint(MAX_TRACE, ("NdisProtocolHandle is NULL\n"));
532 *OpenErrorStatus = *Status = NDIS_STATUS_FAILURE;
533 return;
534 }
535
536 Adapter = MiniLocateDevice(AdapterName);
537 if (!Adapter) {
538 NDIS_DbgPrint(MIN_TRACE, ("Adapter not found.\n"));
539 *Status = NDIS_STATUS_ADAPTER_NOT_FOUND;
540 return;
541 }
542
543 /* Find the media type in the list provided by the protocol driver */
544 Found = FALSE;
545 for (i = 0; i < MediumArraySize; i++) {
546 if (Adapter->NdisMiniportBlock.MediaType == MediumArray[i]) {
547 *SelectedMediumIndex = i;
548 Found = TRUE;
549 break;
550 }
551 }
552
553 if (!Found) {
554 NDIS_DbgPrint(MIN_TRACE, ("Medium is not supported.\n"));
555 *Status = NDIS_STATUS_UNSUPPORTED_MEDIA;
556 return;
557 }
558
559 AdapterBinding = ExAllocatePool(NonPagedPool, sizeof(ADAPTER_BINDING));
560 if (!AdapterBinding) {
561 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
562 *Status = NDIS_STATUS_RESOURCES;
563 return;
564 }
565
566 RtlZeroMemory(AdapterBinding, sizeof(ADAPTER_BINDING));
567
568 AdapterBinding->ProtocolBinding = Protocol;
569 AdapterBinding->Adapter = Adapter;
570 AdapterBinding->NdisOpenBlock.ProtocolBindingContext = ProtocolBindingContext;
571
572 /* Set fields required by some NDIS macros */
573 AdapterBinding->NdisOpenBlock.MacBindingHandle = (NDIS_HANDLE)AdapterBinding;
574
575 /* Set handlers (some NDIS macros require these) */
576
577 AdapterBinding->NdisOpenBlock.RequestHandler = ProRequest;
578 AdapterBinding->NdisOpenBlock.ResetHandler = ProReset;
579 AdapterBinding->NdisOpenBlock.u1.SendHandler = ProSend;
580 AdapterBinding->NdisOpenBlock.SendPacketsHandler = ProSendPackets;
581 AdapterBinding->NdisOpenBlock.TransferDataHandler = ProTransferData;
582
583 #if 0
584 /* XXX this looks fishy */
585 /* OK, this really *is* fishy - it bugchecks */
586 /* Put on protocol's bound adapters list */
587 ExInterlockedInsertTailList(&Protocol->AdapterListHead,
588 &AdapterBinding->ProtocolListEntry,
589 &Protocol->Lock);
590 #endif
591 /* XXX so does this */
592 /* Put protocol on adapter's bound protocols list */
593 ExInterlockedInsertTailList(&Adapter->ProtocolListHead,
594 &AdapterBinding->AdapterListEntry,
595 &Adapter->NdisMiniportBlock.Lock);
596
597 *NdisBindingHandle = (NDIS_HANDLE)AdapterBinding;
598
599 *Status = NDIS_STATUS_SUCCESS;
600 }
601
602
603 /*
604 * @implemented
605 */
606 VOID
607 EXPORT
608 NdisRegisterProtocol(
609 OUT PNDIS_STATUS Status,
610 OUT PNDIS_HANDLE NdisProtocolHandle,
611 IN PNDIS_PROTOCOL_CHARACTERISTICS ProtocolCharacteristics,
612 IN UINT CharacteristicsLength)
613 /*
614 * FUNCTION: Registers an NDIS driver's ProtocolXxx entry points
615 * ARGUMENTS:
616 * Status = Address of buffer for status information
617 * NdisProtocolHandle = Address of buffer for handle used to identify the driver
618 * ProtocolCharacteristics = Pointer to NDIS_PROTOCOL_CHARACTERISTICS structure
619 * CharacteristicsLength = Size of structure which ProtocolCharacteristics targets
620 * NOTES:
621 * - you *must* set NdisProtocolHandle before doing anything that could wind up
622 * getting BindAdapterHandler, as it will probably call OpenAdapter with this handle
623 * - the above implies that the initialization of the protocol block must be complete
624 * by then
625 * TODO:
626 * - break this function up - probably do a 'ndisRefreshProtocolBindings' function
627 * - make this thing able to handle >1 protocol
628 */
629 {
630 PPROTOCOL_BINDING Protocol;
631 NTSTATUS NtStatus;
632 UINT MinSize;
633 HANDLE DriverKeyHandle = NULL;
634 PKEY_VALUE_PARTIAL_INFORMATION KeyInformation = NULL;
635 UINT DataOffset = 0;
636
637 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
638
639 /* first validate the PROTOCOL_CHARACTERISTICS */
640 switch (ProtocolCharacteristics->MajorNdisVersion)
641 {
642 case 0x03:
643 /* we don't really want to support ndis3 drivers - so we complain for now */
644 NDIS_DbgPrint(MID_TRACE, ("NDIS 3 protocol attempting to register\n"));
645 MinSize = sizeof(NDIS30_PROTOCOL_CHARACTERISTICS_S);
646 break;
647
648 case 0x04:
649 MinSize = sizeof(NDIS40_PROTOCOL_CHARACTERISTICS_S);
650 break;
651
652 case 0x05:
653 MinSize = sizeof(NDIS50_PROTOCOL_CHARACTERISTICS_S);
654 break;
655
656 default:
657 *Status = NDIS_STATUS_BAD_VERSION;
658 NDIS_DbgPrint(MIN_TRACE, ("Incorrect characteristics size\n"));
659 return;
660 }
661
662 if (CharacteristicsLength < MinSize)
663 {
664 NDIS_DbgPrint(DEBUG_PROTOCOL, ("Bad protocol characteristics.\n"));
665 *Status = NDIS_STATUS_BAD_CHARACTERISTICS;
666 return;
667 }
668
669 /* set up the protocol block */
670 Protocol = ExAllocatePool(NonPagedPool, sizeof(PROTOCOL_BINDING));
671 if (!Protocol)
672 {
673 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
674 *Status = NDIS_STATUS_RESOURCES;
675 return;
676 }
677
678 RtlZeroMemory(Protocol, sizeof(PROTOCOL_BINDING));
679 RtlCopyMemory(&Protocol->Chars, ProtocolCharacteristics, MinSize);
680
681 NtStatus = RtlUpcaseUnicodeString(&Protocol->Chars.Name, &ProtocolCharacteristics->Name, TRUE);
682 if (!NT_SUCCESS(NtStatus))
683 {
684 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
685 ExFreePool(Protocol);
686 *Status = NDIS_STATUS_RESOURCES;
687 return;
688 }
689
690 KeInitializeSpinLock(&Protocol->Lock);
691
692 Protocol->RefCount = 1;
693
694 InitializeListHead(&Protocol->AdapterListHead);
695
696 /*
697 * bind the adapter to all of its miniports
698 *
699 * open registry path
700 * get list of devices from Bind key
701 * call BindAdapterHandler for each
702 */
703 {
704 OBJECT_ATTRIBUTES ObjectAttributes;
705 UNICODE_STRING RegistryPath;
706 WCHAR *RegistryPathStr;
707
708 RegistryPathStr = ExAllocatePool(PagedPool, sizeof(SERVICES_KEY) + ProtocolCharacteristics->Name.Length + sizeof(LINKAGE_KEY));
709 if(!RegistryPathStr)
710 {
711 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
712 ExFreePool(Protocol);
713 *Status = NDIS_STATUS_RESOURCES;
714 return;
715 }
716
717 wcscpy(RegistryPathStr, SERVICES_KEY);
718 wcsncat(RegistryPathStr, ((WCHAR *)ProtocolCharacteristics->Name.Buffer), ProtocolCharacteristics->Name.Length / sizeof(WCHAR));
719 RegistryPathStr[wcslen(SERVICES_KEY)+ProtocolCharacteristics->Name.Length/sizeof(WCHAR)] = 0;
720 wcscat(RegistryPathStr, LINKAGE_KEY);
721
722 RtlInitUnicodeString(&RegistryPath, RegistryPathStr);
723 NDIS_DbgPrint(MAX_TRACE, ("Opening configuration key: %wZ\n", &RegistryPath));
724
725 InitializeObjectAttributes(&ObjectAttributes, &RegistryPath, OBJ_CASE_INSENSITIVE, NULL, NULL);
726 NtStatus = ZwOpenKey(&DriverKeyHandle, KEY_READ, &ObjectAttributes);
727
728 ExFreePool(RegistryPathStr);
729
730 if(!NT_SUCCESS(NtStatus))
731 {
732 NDIS_DbgPrint(MID_TRACE, ("Unable to open protocol configuration\n"));
733 ExFreePool(Protocol);
734 *Status = NDIS_STATUS_FAILURE;
735 return;
736 }
737 }
738
739 NDIS_DbgPrint(MAX_TRACE, ("Successfully opened the registry configuration\n"));
740
741 {
742 UNICODE_STRING ValueName;
743 ULONG ResultLength;
744
745 RtlInitUnicodeString(&ValueName, L"Bind");
746
747 NtStatus = ZwQueryValueKey(DriverKeyHandle, &ValueName, KeyValuePartialInformation, NULL, 0, &ResultLength);
748 if(NtStatus != STATUS_BUFFER_OVERFLOW && NtStatus != STATUS_BUFFER_TOO_SMALL)
749 {
750 NDIS_DbgPrint(MID_TRACE, ("Unable to query the Bind value for size\n"));
751 ZwClose(DriverKeyHandle);
752 ExFreePool(Protocol);
753 *Status = NDIS_STATUS_FAILURE;
754 return;
755 }
756
757 KeyInformation = ExAllocatePool(PagedPool, sizeof(KEY_VALUE_PARTIAL_INFORMATION) + ResultLength);
758 if(!KeyInformation)
759 {
760 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
761 ZwClose(DriverKeyHandle);
762 ExFreePool(Protocol);
763 *Status = NDIS_STATUS_FAILURE;
764 return;
765 }
766
767 NtStatus = ZwQueryValueKey(DriverKeyHandle, &ValueName, KeyValuePartialInformation, KeyInformation,
768 sizeof(KEY_VALUE_PARTIAL_INFORMATION) + ResultLength, &ResultLength);
769
770 if(!NT_SUCCESS(NtStatus))
771 {
772 NDIS_DbgPrint(MIN_TRACE, ("Unable to query the Bind value\n"));
773 ZwClose(DriverKeyHandle);
774 ExFreePool(KeyInformation);
775 ExFreePool(Protocol);
776 *Status = NDIS_STATUS_FAILURE;
777 return;
778 }
779 }
780
781 DataOffset = 0;
782 while((KeyInformation->Data)[DataOffset])
783 {
784 /* BindContext is for tracking pending binding operations */
785 VOID *BindContext = 0;
786 NDIS_STRING DeviceName;
787 NDIS_STRING RegistryPath;
788 WCHAR *RegistryPathStr = NULL;
789 ULONG PathLength = 0;
790
791 RtlInitUnicodeString(&DeviceName, (WCHAR *)KeyInformation->Data); /* we know this is 0-term */
792
793 /*
794 * RegistryPath should be:
795 * \Registry\Machine\System\CurrentControlSet\Services\Nic1\Parameters\Tcpip
796 *
797 * This is constructed as follows:
798 * SERVICES_KEY + extracted device name + Protocol name from characteristics
799 */
800
801 PathLength = sizeof(SERVICES_KEY) + /* \Registry\Machine\System\CurrentControlSet\Services\ */
802 wcslen( ((WCHAR *)KeyInformation->Data)+8 ) * sizeof(WCHAR) + /* Adapter1 (extracted from \Device\Adapter1) */
803 sizeof(PARAMETERS_KEY) + /* \Parameters\ */
804 ProtocolCharacteristics->Name.Length; /* Tcpip */
805
806 RegistryPathStr = ExAllocatePool(PagedPool, PathLength);
807 if(!RegistryPathStr)
808 {
809 NDIS_DbgPrint(MIN_TRACE, ("insufficient resources.\n"));
810 ExFreePool(KeyInformation);
811 ExFreePool(Protocol);
812 *Status = NDIS_STATUS_RESOURCES;
813 return;
814 }
815
816 wcscpy(RegistryPathStr, SERVICES_KEY);
817 wcscat(RegistryPathStr, (((WCHAR *)(KeyInformation->Data)) +8 ));
818 wcscat(RegistryPathStr, PARAMETERS_KEY);
819 wcsncat(RegistryPathStr, ProtocolCharacteristics->Name.Buffer, ProtocolCharacteristics->Name.Length / sizeof(WCHAR) );
820
821 RegistryPathStr[PathLength/sizeof(WCHAR) - 1] = 0;
822
823 RtlInitUnicodeString(&RegistryPath, RegistryPathStr);
824
825 NDIS_DbgPrint(MAX_TRACE, ("Calling protocol's BindAdapter handler with DeviceName %wZ and RegistryPath %wZ\n",
826 &DeviceName, &RegistryPath));
827
828 /* XXX SD must do something with bind context */
829 *NdisProtocolHandle = Protocol;
830
831 {
832 BIND_HANDLER BindHandler = ProtocolCharacteristics->BindAdapterHandler;
833 if(BindHandler)
834 BindHandler(Status, BindContext, &DeviceName, &RegistryPath, 0);
835 else
836 NDIS_DbgPrint(MID_TRACE, ("No protocol bind handler specified\n"));
837 }
838
839 /*
840 (*(Protocol->Chars.BindAdapterHandler))(Status, BindContext, &DeviceName, &RegistryPath, 0);
841 */
842
843 if(*Status == NDIS_STATUS_SUCCESS)
844 {
845 /* Put protocol binding struct on global list */
846 ExInterlockedInsertTailList(&ProtocolListHead, &Protocol->ListEntry, &ProtocolListLock);
847 }
848
849 /*
850 else if(*Status != NDIS_STATUS_PENDING)
851 {
852 // what to do here?
853 }
854 */
855
856 DataOffset += wcslen((WCHAR *)KeyInformation->Data);
857 }
858
859 *Status = NDIS_STATUS_SUCCESS;
860 }
861
862 \f
863 /*
864 * @implemented
865 */
866 VOID
867 EXPORT
868 NdisRequest(
869 OUT PNDIS_STATUS Status,
870 IN NDIS_HANDLE NdisBindingHandle,
871 IN PNDIS_REQUEST NdisRequest)
872 /*
873 * FUNCTION: Forwards a request to an NDIS driver
874 * ARGUMENTS:
875 * Status = Address of buffer for status information
876 * NdisBindingHandle = Adapter binding handle
877 * NdisRequest = Pointer to request to perform
878 */
879 {
880 *Status = ProRequest(NdisBindingHandle, NdisRequest);
881 }
882
883 \f
884 /*
885 * @implemented
886 */
887 VOID
888 EXPORT
889 NdisReset(
890 OUT PNDIS_STATUS Status,
891 IN NDIS_HANDLE NdisBindingHandle)
892 {
893 *Status = ProReset(NdisBindingHandle);
894 }
895
896 \f
897 /*
898 * @implemented
899 */
900 VOID
901 EXPORT
902 NdisSend(
903 OUT PNDIS_STATUS Status,
904 IN NDIS_HANDLE NdisBindingHandle,
905 IN PNDIS_PACKET Packet)
906 /*
907 * FUNCTION: Forwards a request to send a packet
908 * ARGUMENTS:
909 * Status = Address of buffer for status information
910 * NdisBindingHandle = Adapter binding handle
911 * Packet = Pointer to NDIS packet descriptor
912 */
913 {
914 *Status = ProSend(NdisBindingHandle, Packet);
915 }
916
917 \f
918 /*
919 * @implemented
920 */
921 VOID
922 EXPORT
923 NdisSendPackets(
924 IN NDIS_HANDLE NdisBindingHandle,
925 IN PPNDIS_PACKET PacketArray,
926 IN UINT NumberOfPackets)
927 {
928 ProSendPackets(NdisBindingHandle, PacketArray, NumberOfPackets);
929 }
930
931 \f
932 /*
933 * @implemented
934 */
935 VOID
936 EXPORT
937 NdisTransferData(
938 OUT PNDIS_STATUS Status,
939 IN NDIS_HANDLE NdisBindingHandle,
940 IN NDIS_HANDLE MacReceiveContext,
941 IN UINT ByteOffset,
942 IN UINT BytesToTransfer,
943 IN OUT PNDIS_PACKET Packet,
944 OUT PUINT BytesTransferred)
945 /*
946 * FUNCTION: Forwards a request to copy received data into a protocol-supplied packet
947 * ARGUMENTS:
948 * Status = Address of buffer for status information
949 * NdisBindingHandle = Adapter binding handle
950 * MacReceiveContext = MAC receive context
951 * ByteOffset = Offset in packet to place data
952 * BytesToTransfer = Number of bytes to copy into packet
953 * Packet = Pointer to NDIS packet descriptor
954 * BytesTransferred = Address of buffer to place number of bytes copied
955 */
956 {
957 *Status = ProTransferData(NdisBindingHandle,
958 MacReceiveContext,
959 ByteOffset,
960 BytesToTransfer,
961 Packet,
962 BytesTransferred);
963 }
964
965 /* EOF */