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