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