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