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