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