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