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