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