* Sync up to trunk head (r65270).
[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);
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 if(MiniIsBusy(Adapter, NdisWorkItemSend)) {
399 MiniQueueWorkItem(Adapter, NdisWorkItemSend, Packet, FALSE);
400 return NDIS_STATUS_PENDING;
401 }
402
403 if(Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendPacketsHandler)
404 {
405 if(Adapter->NdisMiniportBlock.Flags & NDIS_ATTRIBUTE_DESERIALIZE)
406 {
407 NDIS_DbgPrint(MAX_TRACE, ("Calling miniport's SendPackets handler\n"));
408 (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendPacketsHandler)(
409 Adapter->NdisMiniportBlock.MiniportAdapterContext, &Packet, 1);
410 NdisStatus = NDIS_STATUS_PENDING;
411 } else {
412 /* SendPackets is called at DISPATCH_LEVEL for all serialized miniports */
413 KeRaiseIrql(DISPATCH_LEVEL, &RaiseOldIrql);
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 }
419 KeLowerIrql(RaiseOldIrql);
420
421 NdisStatus = NDIS_GET_PACKET_STATUS(Packet);
422 if (NdisStatus == NDIS_STATUS_RESOURCES) {
423 MiniQueueWorkItem(Adapter, NdisWorkItemSend, Packet, TRUE);
424 NdisStatus = NDIS_STATUS_PENDING;
425 }
426 }
427
428 if (NdisStatus != NDIS_STATUS_PENDING) {
429 MiniWorkItemComplete(Adapter, NdisWorkItemSend);
430 }
431
432 return NdisStatus;
433 } else {
434 if(Adapter->NdisMiniportBlock.Flags & NDIS_ATTRIBUTE_DESERIALIZE)
435 {
436 NDIS_DbgPrint(MAX_TRACE, ("Calling miniport's Send handler\n"));
437 NdisStatus = (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendHandler)(
438 Adapter->NdisMiniportBlock.MiniportAdapterContext, Packet, Packet->Private.Flags);
439 NDIS_DbgPrint(MAX_TRACE, ("back from miniport's send handler\n"));
440 } else {
441 /* Send is called at DISPATCH_LEVEL for all serialized miniports */
442 KeRaiseIrql(DISPATCH_LEVEL, &RaiseOldIrql);
443 NDIS_DbgPrint(MAX_TRACE, ("Calling miniport's Send handler\n"));
444 NdisStatus = (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendHandler)(
445 Adapter->NdisMiniportBlock.MiniportAdapterContext, Packet, Packet->Private.Flags);
446 NDIS_DbgPrint(MAX_TRACE, ("back from miniport's send handler\n"));
447 KeLowerIrql(RaiseOldIrql);
448
449 if (NdisStatus == NDIS_STATUS_RESOURCES) {
450 MiniQueueWorkItem(Adapter, NdisWorkItemSend, Packet, TRUE);
451 NdisStatus = NDIS_STATUS_PENDING;
452 }
453 }
454
455 if (NdisStatus != NDIS_STATUS_PENDING) {
456 MiniWorkItemComplete(Adapter, NdisWorkItemSend);
457 }
458
459 return NdisStatus;
460 }
461 #endif
462 }
463
464 NDIS_STATUS NTAPI
465 ProSend(
466 IN NDIS_HANDLE MacBindingHandle,
467 IN PNDIS_PACKET Packet)
468 /*
469 * FUNCTION: Forwards a request to send a packet to an NDIS miniport
470 * ARGUMENTS:
471 * MacBindingHandle = Adapter binding handle
472 * Packet = Pointer to NDIS packet descriptor
473 * RETURNS:
474 * NDIS_STATUS_SUCCESS if the packet was successfully sent
475 * NDIS_STATUS_PENDING if the miniport was busy or a serialized miniport returned NDIS_STATUS_RESOURCES
476 */
477 {
478 PADAPTER_BINDING AdapterBinding;
479 PLOGICAL_ADAPTER Adapter;
480 PNDIS_BUFFER NdisBuffer;
481 PDMA_CONTEXT Context;
482 NDIS_STATUS NdisStatus;
483 UINT PacketLength;
484 KIRQL OldIrql;
485
486 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
487
488 ASSERT(MacBindingHandle);
489 AdapterBinding = GET_ADAPTER_BINDING(MacBindingHandle);
490
491 ASSERT(AdapterBinding);
492 Adapter = AdapterBinding->Adapter;
493
494 ASSERT(Adapter);
495
496 /* if the following is not true, KeRaiseIrql() below will break */
497 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
498
499 /* XXX what is this crazy black magic? */
500 Packet->Reserved[1] = (ULONG_PTR)MacBindingHandle;
501
502 /*
503 * Test the packet to see if it is a MAC loopback.
504 *
505 * We may have to loop this packet if miniport cannot.
506 * If dest MAC address of packet == MAC address of adapter,
507 * this is a loopback frame.
508 */
509
510 if ((Adapter->NdisMiniportBlock.MacOptions & NDIS_MAC_OPTION_NO_LOOPBACK) &&
511 MiniAdapterHasAddress(Adapter, Packet))
512 {
513 #if WORKER_TEST
514 MiniQueueWorkItem(Adapter, NdisWorkItemSendLoopback, Packet, FALSE);
515 return NDIS_STATUS_PENDING;
516 #else
517 return ProIndicatePacket(Adapter, Packet);
518 #endif
519 } else {
520 if (Adapter->NdisMiniportBlock.ScatterGatherListSize != 0)
521 {
522 NDIS_DbgPrint(MID_TRACE, ("Using Scatter/Gather DMA\n"));
523
524 NdisQueryPacket(Packet,
525 NULL,
526 NULL,
527 &NdisBuffer,
528 &PacketLength);
529
530 Context = ExAllocatePool(NonPagedPool, sizeof(DMA_CONTEXT));
531 if (!Context) {
532 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources\n"));
533 return NDIS_STATUS_RESOURCES;
534 }
535
536 Context->Adapter = Adapter;
537 Context->Packet = Packet;
538
539 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
540
541 KeFlushIoBuffers(NdisBuffer, FALSE, TRUE);
542
543 NdisStatus = Adapter->NdisMiniportBlock.SystemAdapterObject->DmaOperations->GetScatterGatherList(
544 Adapter->NdisMiniportBlock.SystemAdapterObject,
545 Adapter->NdisMiniportBlock.PhysicalDeviceObject,
546 NdisBuffer,
547 MmGetMdlVirtualAddress(NdisBuffer),
548 PacketLength,
549 ScatterGatherSendPacket,
550 Context,
551 TRUE);
552
553 KeLowerIrql(OldIrql);
554
555 if (!NT_SUCCESS(NdisStatus)) {
556 NDIS_DbgPrint(MIN_TRACE, ("GetScatterGatherList failed! (%x)\n", NdisStatus));
557 return NdisStatus;
558 }
559
560 return NDIS_STATUS_PENDING;
561 }
562
563
564 return proSendPacketToMiniport(Adapter, Packet);
565 }
566 }
567
568 VOID NTAPI
569 ProSendPackets(
570 IN NDIS_HANDLE NdisBindingHandle,
571 IN PPNDIS_PACKET PacketArray,
572 IN UINT NumberOfPackets)
573 {
574 PADAPTER_BINDING AdapterBinding = NdisBindingHandle;
575 PLOGICAL_ADAPTER Adapter = AdapterBinding->Adapter;
576 KIRQL RaiseOldIrql;
577 NDIS_STATUS NdisStatus;
578 UINT i;
579
580 if(Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendPacketsHandler)
581 {
582 if(Adapter->NdisMiniportBlock.Flags & NDIS_ATTRIBUTE_DESERIALIZE)
583 {
584 (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendPacketsHandler)(
585 Adapter->NdisMiniportBlock.MiniportAdapterContext, PacketArray, NumberOfPackets);
586 }
587 else
588 {
589 /* SendPackets is called at DISPATCH_LEVEL for all serialized miniports */
590 KeRaiseIrql(DISPATCH_LEVEL, &RaiseOldIrql);
591 (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendPacketsHandler)(
592 Adapter->NdisMiniportBlock.MiniportAdapterContext, PacketArray, NumberOfPackets);
593 KeLowerIrql(RaiseOldIrql);
594 for (i = 0; i < NumberOfPackets; i++)
595 {
596 NdisStatus = NDIS_GET_PACKET_STATUS(PacketArray[i]);
597 if (NdisStatus != NDIS_STATUS_PENDING)
598 MiniSendComplete(Adapter, PacketArray[i], NdisStatus);
599 }
600 }
601 }
602 else
603 {
604 if(Adapter->NdisMiniportBlock.Flags & NDIS_ATTRIBUTE_DESERIALIZE)
605 {
606 for (i = 0; i < NumberOfPackets; i++)
607 {
608 NdisStatus = (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendHandler)(
609 Adapter->NdisMiniportBlock.MiniportAdapterContext, PacketArray[i], PacketArray[i]->Private.Flags);
610 if (NdisStatus != NDIS_STATUS_PENDING)
611 MiniSendComplete(Adapter, PacketArray[i], NdisStatus);
612 }
613 }
614 else
615 {
616 /* Send is called at DISPATCH_LEVEL for all serialized miniports */
617 KeRaiseIrql(DISPATCH_LEVEL, &RaiseOldIrql);
618 for (i = 0; i < NumberOfPackets; i++)
619 {
620 NdisStatus = (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendHandler)(
621 Adapter->NdisMiniportBlock.MiniportAdapterContext, PacketArray[i], PacketArray[i]->Private.Flags);
622 if (NdisStatus != NDIS_STATUS_PENDING)
623 MiniSendComplete(Adapter, PacketArray[i], NdisStatus);
624 }
625 KeLowerIrql(RaiseOldIrql);
626 }
627 }
628 }
629
630 NDIS_STATUS NTAPI
631 ProTransferData(
632 IN NDIS_HANDLE MacBindingHandle,
633 IN NDIS_HANDLE MacReceiveContext,
634 IN UINT ByteOffset,
635 IN UINT BytesToTransfer,
636 IN OUT PNDIS_PACKET Packet,
637 OUT PUINT BytesTransferred)
638 /*
639 * FUNCTION: Forwards a request to copy received data into a protocol-supplied packet
640 * ARGUMENTS:
641 * MacBindingHandle = Adapter binding handle
642 * MacReceiveContext = MAC receive context
643 * ByteOffset = Offset in packet to place data
644 * BytesToTransfer = Number of bytes to copy into packet
645 * Packet = Pointer to NDIS packet descriptor
646 * BytesTransferred = Address of buffer to place number of bytes copied
647 */
648 {
649 PADAPTER_BINDING AdapterBinding = GET_ADAPTER_BINDING(MacBindingHandle);
650 PLOGICAL_ADAPTER Adapter = AdapterBinding->Adapter;
651 NDIS_STATUS Status;
652 KIRQL OldIrql;
653
654 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
655
656 /* FIXME: Interrupts must be disabled for adapter */
657 /* XXX sd - why is that true? */
658
659 if (Adapter->NdisMiniportBlock.IndicatedPacket[KeGetCurrentProcessorNumber()]) {
660 NDIS_DbgPrint(MAX_TRACE, ("LoopPacket\n"));
661 /* NDIS is responsible for looping this packet */
662 NdisCopyFromPacketToPacket(Packet,
663 ByteOffset + Adapter->MediumHeaderSize,
664 BytesToTransfer + Adapter->MediumHeaderSize,
665 Adapter->NdisMiniportBlock.IndicatedPacket[KeGetCurrentProcessorNumber()],
666 0,
667 BytesTransferred);
668 return NDIS_STATUS_SUCCESS;
669 }
670
671 ASSERT(Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.TransferDataHandler);
672
673 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
674
675 Status = (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.TransferDataHandler)(
676 Packet,
677 BytesTransferred,
678 Adapter->NdisMiniportBlock.MiniportAdapterContext,
679 MacReceiveContext,
680 ByteOffset,
681 BytesToTransfer);
682
683 KeLowerIrql(OldIrql);
684
685 return Status;
686 }
687
688
689
690 /*
691 * @implemented
692 */
693 VOID
694 EXPORT
695 NdisCloseAdapter(
696 OUT PNDIS_STATUS Status,
697 IN NDIS_HANDLE NdisBindingHandle)
698 /*
699 * FUNCTION: Closes an adapter opened with NdisOpenAdapter
700 * ARGUMENTS:
701 * Status = Address of buffer for status information
702 * NdisBindingHandle = Handle returned by NdisOpenAdapter
703 */
704 {
705 PADAPTER_BINDING AdapterBinding = GET_ADAPTER_BINDING(NdisBindingHandle);
706
707 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
708
709 /* Remove from protocol's bound adapters list */
710 ExInterlockedRemoveEntryList(&AdapterBinding->ProtocolListEntry, &AdapterBinding->ProtocolBinding->Lock);
711
712 /* Remove protocol from adapter's bound protocols list */
713 ExInterlockedRemoveEntryList(&AdapterBinding->AdapterListEntry, &AdapterBinding->Adapter->NdisMiniportBlock.Lock);
714
715 ExFreePool(AdapterBinding);
716
717 *Status = NDIS_STATUS_SUCCESS;
718 }
719
720
721 /*
722 * @implemented
723 */
724 VOID
725 EXPORT
726 NdisDeregisterProtocol(
727 OUT PNDIS_STATUS Status,
728 IN NDIS_HANDLE NdisProtocolHandle)
729 /*
730 * FUNCTION: Releases the resources allocated by NdisRegisterProtocol
731 * ARGUMENTS:
732 * Status = Address of buffer for status information
733 * NdisProtocolHandle = Handle returned by NdisRegisterProtocol
734 */
735 {
736 PPROTOCOL_BINDING Protocol = GET_PROTOCOL_BINDING(NdisProtocolHandle);
737
738 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
739
740 /* FIXME: Make sure no adapter bindings exist */
741
742 /* Remove protocol from global list */
743 ExInterlockedRemoveEntryList(&Protocol->ListEntry, &ProtocolListLock);
744
745 ExFreePool(Protocol);
746
747 *Status = NDIS_STATUS_SUCCESS;
748 }
749
750
751 /*
752 * @implemented
753 */
754 VOID
755 EXPORT
756 NdisOpenAdapter(
757 OUT PNDIS_STATUS Status,
758 OUT PNDIS_STATUS OpenErrorStatus,
759 OUT PNDIS_HANDLE NdisBindingHandle,
760 OUT PUINT SelectedMediumIndex,
761 IN PNDIS_MEDIUM MediumArray,
762 IN UINT MediumArraySize,
763 IN NDIS_HANDLE NdisProtocolHandle,
764 IN NDIS_HANDLE ProtocolBindingContext,
765 IN PNDIS_STRING AdapterName,
766 IN UINT OpenOptions,
767 IN PSTRING AddressingInformation OPTIONAL)
768 /*
769 * FUNCTION: Opens an adapter for communication
770 * ARGUMENTS:
771 * Status = Address of buffer for status information
772 * OpenErrorStatus = Address of buffer for secondary error code
773 * NdisBindingHandle = Address of buffer for adapter binding handle
774 * SelectedMediumIndex = Address of buffer for selected medium
775 * MediumArray = Pointer to an array of NDIS_MEDIUMs called can support
776 * MediumArraySize = Number of elements in MediumArray
777 * NdisProtocolHandle = Handle returned by NdisRegisterProtocol
778 * ProtocolBindingContext = Pointer to caller suplied context area
779 * AdapterName = Pointer to buffer with name of adapter
780 * OpenOptions = Bitmask with flags passed to next-lower driver
781 * AddressingInformation = Optional pointer to buffer with NIC specific information
782 */
783 {
784 UINT i;
785 BOOLEAN Found;
786 PLOGICAL_ADAPTER Adapter;
787 PADAPTER_BINDING AdapterBinding;
788 PPROTOCOL_BINDING Protocol = GET_PROTOCOL_BINDING(NdisProtocolHandle);
789
790 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
791
792 if(!NdisProtocolHandle)
793 {
794 NDIS_DbgPrint(MIN_TRACE, ("NdisProtocolHandle is NULL\n"));
795 *OpenErrorStatus = *Status = NDIS_STATUS_FAILURE;
796 return;
797 }
798
799 Adapter = MiniLocateDevice(AdapterName);
800 if (!Adapter)
801 {
802 NDIS_DbgPrint(MIN_TRACE, ("Adapter not found.\n"));
803 *Status = NDIS_STATUS_ADAPTER_NOT_FOUND;
804 return;
805 }
806
807 /* Find the media type in the list provided by the protocol driver */
808 Found = FALSE;
809 for (i = 0; i < MediumArraySize; i++)
810 {
811 if (Adapter->NdisMiniportBlock.MediaType == MediumArray[i])
812 {
813 *SelectedMediumIndex = i;
814 Found = TRUE;
815 break;
816 }
817 }
818
819 if (!Found)
820 {
821 NDIS_DbgPrint(MIN_TRACE, ("Medium is not supported.\n"));
822 *Status = NDIS_STATUS_UNSUPPORTED_MEDIA;
823 return;
824 }
825
826 /* Now that we have confirmed that the adapter can be opened, create a binding */
827
828 AdapterBinding = ExAllocatePool(NonPagedPool, sizeof(ADAPTER_BINDING));
829 if (!AdapterBinding)
830 {
831 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
832 *Status = NDIS_STATUS_RESOURCES;
833 return;
834 }
835
836 RtlZeroMemory(AdapterBinding, sizeof(ADAPTER_BINDING));
837
838 AdapterBinding->ProtocolBinding = Protocol;
839 AdapterBinding->Adapter = Adapter;
840 AdapterBinding->NdisOpenBlock.ProtocolBindingContext = ProtocolBindingContext;
841
842 /* Set fields required by some NDIS macros */
843 AdapterBinding->NdisOpenBlock.BindingHandle = (NDIS_HANDLE)AdapterBinding;
844
845 /* Set handlers (some NDIS macros require these) */
846
847 AdapterBinding->NdisOpenBlock.RequestHandler = ProRequest;
848 AdapterBinding->NdisOpenBlock.ResetHandler = ProReset;
849 AdapterBinding->NdisOpenBlock.SendHandler = ProSend;
850 AdapterBinding->NdisOpenBlock.SendPacketsHandler = ProSendPackets;
851 AdapterBinding->NdisOpenBlock.TransferDataHandler = ProTransferData;
852
853 AdapterBinding->NdisOpenBlock.RequestCompleteHandler =
854 Protocol->Chars.RequestCompleteHandler;
855
856 /* Put on protocol's bound adapters list */
857 ExInterlockedInsertTailList(&Protocol->AdapterListHead, &AdapterBinding->ProtocolListEntry, &Protocol->Lock);
858
859 /* Put protocol on adapter's bound protocols list */
860 NDIS_DbgPrint(MAX_TRACE, ("acquiring miniport block lock\n"));
861 ExInterlockedInsertTailList(&Adapter->ProtocolListHead, &AdapterBinding->AdapterListEntry, &Adapter->NdisMiniportBlock.Lock);
862
863 *NdisBindingHandle = (NDIS_HANDLE)AdapterBinding;
864
865 *Status = NDIS_STATUS_SUCCESS;
866 }
867
868 PADAPTER_BINDING
869 NTAPI
870 LocateAdapterBindingByName(IN PPROTOCOL_BINDING ProtocolBinding, IN PNDIS_STRING AdapterName)
871 {
872 PLIST_ENTRY CurrentEntry;
873 PADAPTER_BINDING AdapterBinding;
874 KIRQL OldIrql;
875
876 KeAcquireSpinLock(&ProtocolBinding->Lock, &OldIrql);
877
878 CurrentEntry = ProtocolBinding->AdapterListHead.Flink;
879
880 while (CurrentEntry != &ProtocolBinding->AdapterListHead)
881 {
882 AdapterBinding = CONTAINING_RECORD(CurrentEntry, ADAPTER_BINDING, ProtocolListEntry);
883
884 if (RtlCompareUnicodeString(AdapterName, &AdapterBinding->Adapter->NdisMiniportBlock.MiniportName, TRUE) == 0)
885 {
886 KeReleaseSpinLock(&ProtocolBinding->Lock, OldIrql);
887 return AdapterBinding;
888 }
889
890 CurrentEntry = CurrentEntry->Flink;
891 }
892
893 KeReleaseSpinLock(&ProtocolBinding->Lock, OldIrql);
894
895 return NULL;
896 }
897
898 VOID
899 NTAPI
900 ndisBindMiniportsToProtocol(OUT PNDIS_STATUS Status, IN PPROTOCOL_BINDING Protocol)
901 {
902 /*
903 * bind the protocol to all of its miniports
904 *
905 * open registry path
906 * get list of devices from Bind key
907 * call BindAdapterHandler for each
908 */
909 OBJECT_ATTRIBUTES ObjectAttributes;
910 UNICODE_STRING RegistryPath;
911 WCHAR *RegistryPathStr, *DataPtr = NULL;
912 NTSTATUS NtStatus;
913 HANDLE DriverKeyHandle = NULL;
914 PKEY_VALUE_PARTIAL_INFORMATION KeyInformation = NULL;
915 PNDIS_PROTOCOL_CHARACTERISTICS ProtocolCharacteristics = &Protocol->Chars;
916 UNICODE_STRING ValueName;
917 ULONG ResultLength;
918 PLIST_ENTRY CurrentEntry = NULL;
919
920 RegistryPathStr = ExAllocatePoolWithTag(PagedPool, sizeof(SERVICES_KEY) + ProtocolCharacteristics->Name.Length + sizeof(LINKAGE_KEY), NDIS_TAG + __LINE__);
921 if(!RegistryPathStr)
922 {
923 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
924 *Status = NDIS_STATUS_RESOURCES;
925 return;
926 }
927
928 wcscpy(RegistryPathStr, SERVICES_KEY);
929 wcsncat(RegistryPathStr, ((WCHAR *)ProtocolCharacteristics->Name.Buffer), ProtocolCharacteristics->Name.Length / sizeof(WCHAR));
930 RegistryPathStr[wcslen(SERVICES_KEY)+ProtocolCharacteristics->Name.Length/sizeof(WCHAR)] = 0;
931 wcscat(RegistryPathStr, LINKAGE_KEY);
932
933 RtlInitUnicodeString(&RegistryPath, RegistryPathStr);
934 NDIS_DbgPrint(MAX_TRACE, ("Opening configuration key: %wZ\n", &RegistryPath));
935
936 InitializeObjectAttributes(&ObjectAttributes, &RegistryPath, OBJ_CASE_INSENSITIVE, NULL, NULL);
937 NtStatus = ZwOpenKey(&DriverKeyHandle, KEY_READ, &ObjectAttributes);
938
939 ExFreePool(RegistryPathStr);
940
941 if(NT_SUCCESS(NtStatus))
942 {
943 NDIS_DbgPrint(MAX_TRACE, ("Successfully opened the registry configuration\n"));
944
945 RtlInitUnicodeString(&ValueName, L"Bind");
946
947 NtStatus = ZwQueryValueKey(DriverKeyHandle, &ValueName, KeyValuePartialInformation, NULL, 0, &ResultLength);
948 if(NtStatus != STATUS_BUFFER_OVERFLOW && NtStatus != STATUS_BUFFER_TOO_SMALL && NtStatus != STATUS_SUCCESS)
949 {
950 NDIS_DbgPrint(MIN_TRACE, ("Unable to query the Bind value for size\n"));
951 ZwClose(DriverKeyHandle);
952 }
953 else
954 {
955 KeyInformation = ExAllocatePoolWithTag(PagedPool, sizeof(KEY_VALUE_PARTIAL_INFORMATION) + ResultLength, NDIS_TAG + __LINE__);
956 if(!KeyInformation)
957 {
958 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
959 ZwClose(DriverKeyHandle);
960 NtStatus = STATUS_NO_MEMORY;
961 }
962 else
963 {
964 NtStatus = ZwQueryValueKey(DriverKeyHandle, &ValueName, KeyValuePartialInformation, KeyInformation,
965 sizeof(KEY_VALUE_PARTIAL_INFORMATION) + ResultLength, &ResultLength);
966
967 ZwClose(DriverKeyHandle);
968
969 if(!NT_SUCCESS(NtStatus))
970 {
971 NDIS_DbgPrint(MIN_TRACE, ("Unable to query the Bind value\n"));
972 ExFreePool(KeyInformation);
973 KeyInformation = NULL;
974 }
975 }
976 }
977 }
978
979 if (!NT_SUCCESS(NtStatus))
980 {
981 NDIS_DbgPrint(MID_TRACE, ("Performing global bind for protocol '%wZ'\n", &ProtocolCharacteristics->Name));
982 KeyInformation = NULL;
983
984 CurrentEntry = AdapterListHead.Flink;
985 }
986 else
987 {
988 NDIS_DbgPrint(MID_TRACE, ("Performing standard bind for protocol '%wZ'\n", &ProtocolCharacteristics->Name));
989
990 DataPtr = (WCHAR*)KeyInformation->Data;
991 }
992
993 /* Assume success for now */
994 *Status = NDIS_STATUS_SUCCESS;
995
996 while (TRUE)
997 {
998 /* BindContext is for tracking pending binding operations */
999 VOID *BindContext = 0;
1000 NDIS_STRING DeviceName;
1001 NDIS_STRING RegistryPath;
1002 WCHAR *RegistryPathStr = NULL;
1003 ULONG PathLength = 0;
1004 PLOGICAL_ADAPTER Adapter;
1005
1006 if (KeyInformation)
1007 {
1008 /* Parse the REG_MULTI_SZ entry for device names */
1009 if (!(*DataPtr))
1010 break;
1011
1012 RtlInitUnicodeString(&DeviceName, DataPtr);
1013 }
1014 else
1015 {
1016 /* Use the device name from the global adapter list */
1017 if (CurrentEntry == &AdapterListHead)
1018 break;
1019
1020 Adapter = CONTAINING_RECORD(CurrentEntry, LOGICAL_ADAPTER, ListEntry);
1021
1022 DeviceName = Adapter->NdisMiniportBlock.MiniportName;
1023 }
1024
1025 /* Make sure the adapter has started */
1026 if (!MiniLocateDevice(&DeviceName))
1027 {
1028 /* It wasn't in the global miniport list, so skip the bind entry */
1029 goto next;
1030 }
1031
1032 /* Make sure this device isn't already bound to this protocol */
1033 if (LocateAdapterBindingByName(Protocol, &DeviceName))
1034 {
1035 /* It was already in this protocol's bound adapter list, so skip the bind entry */
1036 goto next;
1037 }
1038
1039 /*
1040 * RegistryPath should be:
1041 * \Registry\Machine\System\CurrentControlSet\Services\Nic1\Parameters\Tcpip
1042 *
1043 * This is constructed as follows:
1044 * SERVICES_KEY + extracted device name + Protocol name from characteristics
1045 */
1046
1047 PathLength = sizeof(SERVICES_KEY) + /* \Registry\Machine\System\CurrentControlSet\Services\ */
1048 wcslen( DeviceName.Buffer + 8 ) * sizeof(WCHAR) + /* Adapter1 (extracted from \Device\Adapter1) */
1049 sizeof(PARAMETERS_KEY) + /* \Parameters\ */
1050 ProtocolCharacteristics->Name.Length + sizeof(WCHAR); /* Tcpip */
1051
1052 RegistryPathStr = ExAllocatePool(PagedPool, PathLength);
1053 if(!RegistryPathStr)
1054 {
1055 NDIS_DbgPrint(MIN_TRACE, ("insufficient resources.\n"));
1056 *Status = NDIS_STATUS_RESOURCES;
1057 break;
1058 }
1059
1060 wcscpy(RegistryPathStr, SERVICES_KEY);
1061 wcscat(RegistryPathStr, DeviceName.Buffer + 8 );
1062 wcscat(RegistryPathStr, PARAMETERS_KEY);
1063 wcsncat(RegistryPathStr, ProtocolCharacteristics->Name.Buffer, ProtocolCharacteristics->Name.Length / sizeof(WCHAR) );
1064
1065 RegistryPathStr[PathLength/sizeof(WCHAR) - 1] = 0;
1066
1067 RtlInitUnicodeString(&RegistryPath, RegistryPathStr);
1068
1069 NDIS_DbgPrint(MAX_TRACE, ("Calling protocol's BindAdapter handler with DeviceName %wZ and RegistryPath %wZ\n",
1070 &DeviceName, &RegistryPath));
1071
1072 {
1073 BIND_HANDLER BindHandler = ProtocolCharacteristics->BindAdapterHandler;
1074 if(BindHandler)
1075 {
1076 BindHandler(Status, BindContext, &DeviceName, &RegistryPath, 0);
1077 NDIS_DbgPrint(MID_TRACE, ("%wZ's BindAdapter handler returned 0x%x for %wZ\n", &ProtocolCharacteristics->Name, *Status, &DeviceName));
1078 }
1079 else
1080 NDIS_DbgPrint(MID_TRACE, ("No protocol bind handler specified\n"));
1081 }
1082
1083 next:
1084 if (KeyInformation)
1085 {
1086 /* Advance to the next adapter in the REG_MULTI_SZ */
1087 DataPtr += (DeviceName.Length / sizeof(WCHAR)) + 1;
1088 }
1089 else
1090 {
1091 /* Advance to the next adapter in the global list */
1092 CurrentEntry = CurrentEntry->Flink;
1093 }
1094 }
1095
1096 if (KeyInformation)
1097 {
1098 ExFreePool(KeyInformation);
1099 }
1100 }
1101
1102 /*
1103 * @implemented
1104 */
1105 VOID
1106 EXPORT
1107 NdisRegisterProtocol(
1108 OUT PNDIS_STATUS Status,
1109 OUT PNDIS_HANDLE NdisProtocolHandle,
1110 IN PNDIS_PROTOCOL_CHARACTERISTICS ProtocolCharacteristics,
1111 IN UINT CharacteristicsLength)
1112 /*
1113 * FUNCTION: Registers an NDIS driver's ProtocolXxx entry points
1114 * ARGUMENTS:
1115 * Status = Address of buffer for status information
1116 * NdisProtocolHandle = Address of buffer for handle used to identify the driver
1117 * ProtocolCharacteristics = Pointer to NDIS_PROTOCOL_CHARACTERISTICS structure
1118 * CharacteristicsLength = Size of structure which ProtocolCharacteristics targets
1119 * NOTES:
1120 * - you *must* set NdisProtocolHandle before doing anything that could wind up
1121 * getting BindAdapterHandler, as it will probably call OpenAdapter with this handle
1122 * - the above implies that the initialization of the protocol block must be complete
1123 * by then
1124 * TODO:
1125 * - break this function up - probably do a 'ndisRefreshProtocolBindings' function
1126 * - make this thing able to handle >1 protocol
1127 */
1128 {
1129 PPROTOCOL_BINDING Protocol;
1130 NTSTATUS NtStatus;
1131 UINT MinSize;
1132 PNET_PNP_EVENT PnPEvent;
1133
1134 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
1135
1136 *NdisProtocolHandle = NULL;
1137
1138 /* first validate the PROTOCOL_CHARACTERISTICS */
1139 switch (ProtocolCharacteristics->MajorNdisVersion)
1140 {
1141 case 0x03:
1142 /* we don't really want to support ndis3 drivers - so we complain for now */
1143 NDIS_DbgPrint(MID_TRACE, ("NDIS 3 protocol attempting to register\n"));
1144 MinSize = sizeof(NDIS30_PROTOCOL_CHARACTERISTICS);
1145 break;
1146
1147 case 0x04:
1148 MinSize = sizeof(NDIS40_PROTOCOL_CHARACTERISTICS);
1149 break;
1150
1151 case 0x05:
1152 MinSize = sizeof(NDIS50_PROTOCOL_CHARACTERISTICS);
1153 break;
1154
1155 default:
1156 *Status = NDIS_STATUS_BAD_VERSION;
1157 NDIS_DbgPrint(MIN_TRACE, ("Incorrect characteristics size\n"));
1158 return;
1159 }
1160
1161 if (CharacteristicsLength < MinSize)
1162 {
1163 NDIS_DbgPrint(MIN_TRACE, ("Bad protocol characteristics.\n"));
1164 *Status = NDIS_STATUS_BAD_CHARACTERISTICS;
1165 return;
1166 }
1167
1168 /* set up the protocol block */
1169 Protocol = ExAllocatePool(NonPagedPool, sizeof(PROTOCOL_BINDING));
1170 if (!Protocol)
1171 {
1172 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
1173 *Status = NDIS_STATUS_RESOURCES;
1174 return;
1175 }
1176
1177 RtlZeroMemory(Protocol, sizeof(PROTOCOL_BINDING));
1178 RtlCopyMemory(&Protocol->Chars, ProtocolCharacteristics, MinSize);
1179
1180 NtStatus = RtlUpcaseUnicodeString(&Protocol->Chars.Name, &ProtocolCharacteristics->Name, TRUE);
1181 if (!NT_SUCCESS(NtStatus))
1182 {
1183 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
1184 ExFreePool(Protocol);
1185 *Status = NDIS_STATUS_RESOURCES;
1186 return;
1187 }
1188
1189 KeInitializeSpinLock(&Protocol->Lock);
1190
1191 InitializeListHead(&Protocol->AdapterListHead);
1192
1193 /* We must set this before the call to ndisBindMiniportsToProtocol because the protocol's
1194 * BindAdapter handler might need it */
1195
1196 *NdisProtocolHandle = Protocol;
1197
1198 ndisBindMiniportsToProtocol(Status, Protocol);
1199
1200 /* Should we only send this if ndisBindMiniportsToProtocol succeeds? */
1201 PnPEvent = ProSetupPnPEvent(NetEventBindsComplete, NULL, 0);
1202 if (PnPEvent)
1203 {
1204 if (Protocol->Chars.PnPEventHandler)
1205 {
1206 /* We call this with a NULL binding context because it affects all bindings */
1207 NtStatus = (*Protocol->Chars.PnPEventHandler)(NULL,
1208 PnPEvent);
1209
1210 /* FIXME: We don't support this yet */
1211 ASSERT(NtStatus != NDIS_STATUS_PENDING);
1212 }
1213
1214 ExFreePool(PnPEvent);
1215 }
1216
1217 if (*Status == NDIS_STATUS_SUCCESS) {
1218 ExInterlockedInsertTailList(&ProtocolListHead, &Protocol->ListEntry, &ProtocolListLock);
1219 } else {
1220 NDIS_DbgPrint(MIN_TRACE, ("Binding failed (%x)\n", *Status));
1221 ExFreePool(Protocol);
1222 *NdisProtocolHandle = NULL;
1223 }
1224 }
1225
1226 /*
1227 * @implemented
1228 */
1229 VOID
1230 EXPORT
1231 NdisRequest(
1232 OUT PNDIS_STATUS Status,
1233 IN NDIS_HANDLE NdisBindingHandle,
1234 IN PNDIS_REQUEST NdisRequest)
1235 /*
1236 * FUNCTION: Forwards a request to an NDIS driver
1237 * ARGUMENTS:
1238 * Status = Address of buffer for status information
1239 * NdisBindingHandle = Adapter binding handle
1240 * NdisRequest = Pointer to request to perform
1241 */
1242 {
1243 *Status = ProRequest(NdisBindingHandle, NdisRequest);
1244 }
1245
1246 /*
1247 * @implemented
1248 */
1249 VOID
1250 EXPORT
1251 NdisReset(
1252 OUT PNDIS_STATUS Status,
1253 IN NDIS_HANDLE NdisBindingHandle)
1254 {
1255 *Status = ProReset(NdisBindingHandle);
1256 }
1257
1258 /*
1259 * @implemented
1260 */
1261 #undef NdisSend
1262 VOID
1263 EXPORT
1264 NdisSend(
1265 OUT PNDIS_STATUS Status,
1266 IN NDIS_HANDLE NdisBindingHandle,
1267 IN PNDIS_PACKET Packet)
1268 /*
1269 * FUNCTION: Forwards a request to send a packet
1270 * ARGUMENTS:
1271 * Status = Address of buffer for status information
1272 * NdisBindingHandle = Adapter binding handle
1273 * Packet = Pointer to NDIS packet descriptor
1274 */
1275 {
1276 *Status = ProSend(NdisBindingHandle, Packet);
1277 }
1278
1279 /*
1280 * @implemented
1281 */
1282 #undef NdisSendPackets
1283 VOID
1284 EXPORT
1285 NdisSendPackets(
1286 IN NDIS_HANDLE NdisBindingHandle,
1287 IN PPNDIS_PACKET PacketArray,
1288 IN UINT NumberOfPackets)
1289 {
1290 ProSendPackets(NdisBindingHandle, PacketArray, NumberOfPackets);
1291 }
1292
1293 /*
1294 * @implemented
1295 */
1296 #undef NdisTransferData
1297 VOID
1298 EXPORT
1299 NdisTransferData(
1300 OUT PNDIS_STATUS Status,
1301 IN NDIS_HANDLE NdisBindingHandle,
1302 IN NDIS_HANDLE MacReceiveContext,
1303 IN UINT ByteOffset,
1304 IN UINT BytesToTransfer,
1305 IN OUT PNDIS_PACKET Packet,
1306 OUT PUINT BytesTransferred)
1307 /*
1308 * FUNCTION: Forwards a request to copy received data into a protocol-supplied packet
1309 * ARGUMENTS:
1310 * Status = Address of buffer for status information
1311 * NdisBindingHandle = Adapter binding handle
1312 * MacReceiveContext = MAC receive context
1313 * ByteOffset = Offset in packet to place data
1314 * BytesToTransfer = Number of bytes to copy into packet
1315 * Packet = Pointer to NDIS packet descriptor
1316 * BytesTransferred = Address of buffer to place number of bytes copied
1317 */
1318 {
1319 *Status = ProTransferData(NdisBindingHandle,
1320 MacReceiveContext,
1321 ByteOffset,
1322 BytesToTransfer,
1323 Packet,
1324 BytesTransferred);
1325 }
1326
1327 /*
1328 * @implemented
1329 */
1330 VOID
1331 NTAPI
1332 NdisReEnumerateProtocolBindings(IN NDIS_HANDLE NdisProtocolHandle)
1333 {
1334 NDIS_STATUS NdisStatus;
1335
1336 ndisBindMiniportsToProtocol(&NdisStatus, NdisProtocolHandle);
1337 }
1338
1339
1340 /*
1341 * @implemented
1342 */
1343 VOID
1344 EXPORT
1345 NdisGetDriverHandle(
1346 IN PNDIS_HANDLE NdisBindingHandle,
1347 OUT PNDIS_HANDLE NdisDriverHandle)
1348 /*
1349 * FUNCTION:
1350 * ARGUMENTS:
1351 * NOTES:
1352 * NDIS 5.0
1353 */
1354 {
1355 PADAPTER_BINDING Binding = (PADAPTER_BINDING)NdisBindingHandle;
1356
1357 if (!Binding)
1358 {
1359 NDIS_DbgPrint(MIN_TRACE, ("Bad binding handle\n"));
1360 *NdisDriverHandle = NULL;
1361 return;
1362 }
1363
1364 *NdisDriverHandle = Binding->Adapter->NdisMiniportBlock.DriverHandle;
1365 }
1366
1367 /* EOF */