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