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