Filip and I have hopefully fixed the ndis completion problem on sends.
[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 NdisMSendComplete( Adapter, Packet, NdisStatus );
371 Adapter->MiniportBusy = FALSE;
372 }
373 KeLowerIrql(RaiseOldIrql);
374 }
375 }
376
377 /* XXX why the hell do we do this? */
378 NDIS_DbgPrint(MAX_TRACE, ("acquiring miniport block lock\n"));
379 KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &SpinOldIrql);
380 {
381 if (Adapter->WorkQueueHead)
382 {
383 KeInsertQueueDpc(&Adapter->MiniportDpc, NULL, NULL);
384 NDIS_DbgPrint(MAX_TRACE, ("MiniportDpc queued; returning NDIS_STATUS_SUCCESS\n"));
385 }
386 }
387 KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, SpinOldIrql);
388
389 NDIS_DbgPrint(MAX_TRACE, ("returning 0x%x\n", NdisStatus));
390 return NdisStatus;
391 }
392
393 \f
394 VOID STDCALL
395 ProSendPackets(
396 IN NDIS_HANDLE NdisBindingHandle,
397 IN PPNDIS_PACKET PacketArray,
398 IN UINT NumberOfPackets)
399 {
400 UNIMPLEMENTED
401 }
402
403 \f
404 NDIS_STATUS STDCALL
405 ProTransferData(
406 IN NDIS_HANDLE MacBindingHandle,
407 IN NDIS_HANDLE MacReceiveContext,
408 IN UINT ByteOffset,
409 IN UINT BytesToTransfer,
410 IN OUT PNDIS_PACKET Packet,
411 OUT PUINT BytesTransferred)
412 /*
413 * FUNCTION: Forwards a request to copy received data into a protocol-supplied packet
414 * ARGUMENTS:
415 * MacBindingHandle = Adapter binding handle
416 * MacReceiveContext = MAC receive context
417 * ByteOffset = Offset in packet to place data
418 * BytesToTransfer = Number of bytes to copy into packet
419 * Packet = Pointer to NDIS packet descriptor
420 * BytesTransferred = Address of buffer to place number of bytes copied
421 */
422 {
423 PADAPTER_BINDING AdapterBinding = GET_ADAPTER_BINDING(MacBindingHandle);
424 PLOGICAL_ADAPTER Adapter = AdapterBinding->Adapter;
425
426 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
427
428 /* FIXME: Interrupts must be disabled for adapter */
429 /* XXX sd - why is that true? */
430
431 if (Packet == Adapter->LoopPacket) {
432 NDIS_DbgPrint(MAX_TRACE, ("LoopPacket\n"));
433 /* NDIS is responsible for looping this packet */
434 NdisCopyFromPacketToPacket(Packet,
435 ByteOffset,
436 BytesToTransfer,
437 Adapter->LoopPacket,
438 0,
439 BytesTransferred);
440 return NDIS_STATUS_SUCCESS;
441 }
442
443 return (*Adapter->Miniport->Chars.TransferDataHandler)(
444 Packet,
445 BytesTransferred,
446 Adapter->NdisMiniportBlock.MiniportAdapterContext,
447 MacReceiveContext,
448 ByteOffset,
449 BytesToTransfer);
450 }
451
452
453
454 /*
455 * @implemented
456 */
457 VOID
458 EXPORT
459 NdisCloseAdapter(
460 OUT PNDIS_STATUS Status,
461 IN NDIS_HANDLE NdisBindingHandle)
462 /*
463 * FUNCTION: Closes an adapter opened with NdisOpenAdapter
464 * ARGUMENTS:
465 * Status = Address of buffer for status information
466 * NdisBindingHandle = Handle returned by NdisOpenAdapter
467 */
468 {
469 KIRQL OldIrql;
470 PADAPTER_BINDING AdapterBinding = GET_ADAPTER_BINDING(NdisBindingHandle);
471
472 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
473
474 /* Remove from protocol's bound adapters list */
475 KeAcquireSpinLock(&AdapterBinding->ProtocolBinding->Lock, &OldIrql);
476 RemoveEntryList(&AdapterBinding->ProtocolListEntry);
477 KeReleaseSpinLock(&AdapterBinding->ProtocolBinding->Lock, OldIrql);
478
479 /* Remove protocol from adapter's bound protocols list */
480 NDIS_DbgPrint(MAX_TRACE, ("acquiring miniport block lock\n"));
481 KeAcquireSpinLock(&AdapterBinding->Adapter->NdisMiniportBlock.Lock, &OldIrql);
482 RemoveEntryList(&AdapterBinding->AdapterListEntry);
483 KeReleaseSpinLock(&AdapterBinding->Adapter->NdisMiniportBlock.Lock, OldIrql);
484
485 ExFreePool(AdapterBinding);
486
487 *Status = NDIS_STATUS_SUCCESS;
488 }
489
490
491 /*
492 * @implemented
493 */
494 VOID
495 EXPORT
496 NdisDeregisterProtocol(
497 OUT PNDIS_STATUS Status,
498 IN NDIS_HANDLE NdisProtocolHandle)
499 /*
500 * FUNCTION: Releases the resources allocated by NdisRegisterProtocol
501 * ARGUMENTS:
502 * Status = Address of buffer for status information
503 * NdisProtocolHandle = Handle returned by NdisRegisterProtocol
504 */
505 {
506 KIRQL OldIrql;
507 PPROTOCOL_BINDING Protocol = GET_PROTOCOL_BINDING(NdisProtocolHandle);
508
509 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
510
511 /* FIXME: Make sure no adapter bindings exist */
512
513 /* Remove protocol from global list */
514 KeAcquireSpinLock(&ProtocolListLock, &OldIrql);
515 RemoveEntryList(&Protocol->ListEntry);
516 KeReleaseSpinLock(&ProtocolListLock, OldIrql);
517
518 ExFreePool(Protocol);
519
520 *Status = NDIS_STATUS_SUCCESS;
521 }
522
523
524 /*
525 * @implemented
526 */
527 VOID
528 EXPORT
529 NdisOpenAdapter(
530 OUT PNDIS_STATUS Status,
531 OUT PNDIS_STATUS OpenErrorStatus,
532 OUT PNDIS_HANDLE NdisBindingHandle,
533 OUT PUINT SelectedMediumIndex,
534 IN PNDIS_MEDIUM MediumArray,
535 IN UINT MediumArraySize,
536 IN NDIS_HANDLE NdisProtocolHandle,
537 IN NDIS_HANDLE ProtocolBindingContext,
538 IN PNDIS_STRING AdapterName,
539 IN UINT OpenOptions,
540 IN PSTRING AddressingInformation OPTIONAL)
541 /*
542 * FUNCTION: Opens an adapter for communication
543 * ARGUMENTS:
544 * Status = Address of buffer for status information
545 * OpenErrorStatus = Address of buffer for secondary error code
546 * NdisBindingHandle = Address of buffer for adapter binding handle
547 * SelectedMediumIndex = Address of buffer for selected medium
548 * MediumArray = Pointer to an array of NDIS_MEDIUMs called can support
549 * MediumArraySize = Number of elements in MediumArray
550 * NdisProtocolHandle = Handle returned by NdisRegisterProtocol
551 * ProtocolBindingContext = Pointer to caller suplied context area
552 * AdapterName = Pointer to buffer with name of adapter
553 * OpenOptions = Bitmask with flags passed to next-lower driver
554 * AddressingInformation = Optional pointer to buffer with NIC specific information
555 */
556 {
557 UINT i;
558 BOOLEAN Found;
559 PLOGICAL_ADAPTER Adapter;
560 PADAPTER_BINDING AdapterBinding;
561 PPROTOCOL_BINDING Protocol = GET_PROTOCOL_BINDING(NdisProtocolHandle);
562
563 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
564
565 if(!NdisProtocolHandle)
566 {
567 NDIS_DbgPrint(MAX_TRACE, ("NdisProtocolHandle is NULL\n"));
568 *OpenErrorStatus = *Status = NDIS_STATUS_FAILURE;
569 return;
570 }
571
572 Adapter = MiniLocateDevice(AdapterName);
573 if (!Adapter)
574 {
575 NDIS_DbgPrint(MIN_TRACE, ("Adapter not found.\n"));
576 *Status = NDIS_STATUS_ADAPTER_NOT_FOUND;
577 return;
578 }
579
580 /* Find the media type in the list provided by the protocol driver */
581 Found = FALSE;
582 for (i = 0; i < MediumArraySize; i++)
583 {
584 if (Adapter->NdisMiniportBlock.MediaType == MediumArray[i])
585 {
586 *SelectedMediumIndex = i;
587 Found = TRUE;
588 break;
589 }
590 }
591
592 if (!Found)
593 {
594 NDIS_DbgPrint(MIN_TRACE, ("Medium is not supported.\n"));
595 *Status = NDIS_STATUS_UNSUPPORTED_MEDIA;
596 return;
597 }
598
599 /* Now that we have confirmed that the adapter can be opened, create a binding */
600
601 AdapterBinding = ExAllocatePool(NonPagedPool, sizeof(ADAPTER_BINDING));
602 if (!AdapterBinding)
603 {
604 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
605 *Status = NDIS_STATUS_RESOURCES;
606 return;
607 }
608
609 RtlZeroMemory(AdapterBinding, sizeof(ADAPTER_BINDING));
610
611 AdapterBinding->ProtocolBinding = Protocol;
612 AdapterBinding->Adapter = Adapter;
613 AdapterBinding->NdisOpenBlock.NdisCommonOpenBlock.ProtocolBindingContext = ProtocolBindingContext;
614
615 /* Set fields required by some NDIS macros */
616 AdapterBinding->NdisOpenBlock.NdisCommonOpenBlock.BindingHandle = (NDIS_HANDLE)AdapterBinding;
617
618 /* Set handlers (some NDIS macros require these) */
619
620 AdapterBinding->NdisOpenBlock.NdisCommonOpenBlock.RequestHandler = ProRequest;
621 AdapterBinding->NdisOpenBlock.NdisCommonOpenBlock.ResetHandler = ProReset;
622 AdapterBinding->NdisOpenBlock.NdisCommonOpenBlock.SendHandler = ProSend;
623 AdapterBinding->NdisOpenBlock.NdisCommonOpenBlock.SendPacketsHandler = ProSendPackets;
624 AdapterBinding->NdisOpenBlock.NdisCommonOpenBlock.TransferDataHandler = ProTransferData;
625
626 #if 0
627 /* XXX this looks fishy */
628 /* OK, this really *is* fishy - it bugchecks */
629 /* Put on protocol's bound adapters list */
630 ExInterlockedInsertTailList(&Protocol->AdapterListHead, &AdapterBinding->ProtocolListEntry, &Protocol->Lock);
631 #endif
632
633 /* XXX so does this */
634 /* Put protocol on adapter's bound protocols list */
635 NDIS_DbgPrint(MAX_TRACE, ("acquiring miniport block lock\n"));
636 ExInterlockedInsertTailList(&Adapter->ProtocolListHead, &AdapterBinding->AdapterListEntry, &Adapter->NdisMiniportBlock.Lock);
637
638 *NdisBindingHandle = (NDIS_HANDLE)AdapterBinding;
639
640 *Status = NDIS_STATUS_SUCCESS;
641 }
642
643
644 /*
645 * @implemented
646 */
647 VOID
648 EXPORT
649 NdisRegisterProtocol(
650 OUT PNDIS_STATUS Status,
651 OUT PNDIS_HANDLE NdisProtocolHandle,
652 IN PNDIS_PROTOCOL_CHARACTERISTICS ProtocolCharacteristics,
653 IN UINT CharacteristicsLength)
654 /*
655 * FUNCTION: Registers an NDIS driver's ProtocolXxx entry points
656 * ARGUMENTS:
657 * Status = Address of buffer for status information
658 * NdisProtocolHandle = Address of buffer for handle used to identify the driver
659 * ProtocolCharacteristics = Pointer to NDIS_PROTOCOL_CHARACTERISTICS structure
660 * CharacteristicsLength = Size of structure which ProtocolCharacteristics targets
661 * NOTES:
662 * - you *must* set NdisProtocolHandle before doing anything that could wind up
663 * getting BindAdapterHandler, as it will probably call OpenAdapter with this handle
664 * - the above implies that the initialization of the protocol block must be complete
665 * by then
666 * TODO:
667 * - break this function up - probably do a 'ndisRefreshProtocolBindings' function
668 * - make this thing able to handle >1 protocol
669 */
670 {
671 PPROTOCOL_BINDING Protocol;
672 NTSTATUS NtStatus;
673 UINT MinSize;
674 HANDLE DriverKeyHandle = NULL;
675 PKEY_VALUE_PARTIAL_INFORMATION KeyInformation = NULL;
676 WCHAR *DataPtr;
677
678 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
679
680 /* first validate the PROTOCOL_CHARACTERISTICS */
681 switch (ProtocolCharacteristics->MajorNdisVersion)
682 {
683 case 0x03:
684 /* we don't really want to support ndis3 drivers - so we complain for now */
685 NDIS_DbgPrint(MID_TRACE, ("NDIS 3 protocol attempting to register\n"));
686 MinSize = sizeof(NDIS30_PROTOCOL_CHARACTERISTICS);
687 break;
688
689 case 0x04:
690 MinSize = sizeof(NDIS40_PROTOCOL_CHARACTERISTICS);
691 break;
692
693 case 0x05:
694 MinSize = sizeof(NDIS50_PROTOCOL_CHARACTERISTICS);
695 break;
696
697 default:
698 *Status = NDIS_STATUS_BAD_VERSION;
699 NDIS_DbgPrint(MIN_TRACE, ("Incorrect characteristics size\n"));
700 return;
701 }
702
703 if (CharacteristicsLength < MinSize)
704 {
705 NDIS_DbgPrint(DEBUG_PROTOCOL, ("Bad protocol characteristics.\n"));
706 *Status = NDIS_STATUS_BAD_CHARACTERISTICS;
707 return;
708 }
709
710 /* set up the protocol block */
711 Protocol = ExAllocatePool(NonPagedPool, sizeof(PROTOCOL_BINDING));
712 if (!Protocol)
713 {
714 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
715 *Status = NDIS_STATUS_RESOURCES;
716 return;
717 }
718
719 RtlZeroMemory(Protocol, sizeof(PROTOCOL_BINDING));
720 RtlCopyMemory(&Protocol->Chars, ProtocolCharacteristics, MinSize);
721
722 NtStatus = RtlUpcaseUnicodeString(&Protocol->Chars.Name, &ProtocolCharacteristics->Name, TRUE);
723 if (!NT_SUCCESS(NtStatus))
724 {
725 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
726 ExFreePool(Protocol);
727 *Status = NDIS_STATUS_RESOURCES;
728 return;
729 }
730
731 KeInitializeSpinLock(&Protocol->Lock);
732
733 Protocol->RefCount = 1;
734
735 InitializeListHead(&Protocol->AdapterListHead);
736
737 /*
738 * bind the protocol to all of its miniports
739 *
740 * open registry path
741 * get list of devices from Bind key
742 * call BindAdapterHandler for each
743 */
744 {
745 OBJECT_ATTRIBUTES ObjectAttributes;
746 UNICODE_STRING RegistryPath;
747 WCHAR *RegistryPathStr;
748
749 RegistryPathStr = ExAllocatePoolWithTag(PagedPool, sizeof(SERVICES_KEY) + ProtocolCharacteristics->Name.Length + sizeof(LINKAGE_KEY), NDIS_TAG + __LINE__);
750 if(!RegistryPathStr)
751 {
752 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
753 ExFreePool(Protocol);
754 *Status = NDIS_STATUS_RESOURCES;
755 return;
756 }
757
758 wcscpy(RegistryPathStr, SERVICES_KEY);
759 wcsncat(RegistryPathStr, ((WCHAR *)ProtocolCharacteristics->Name.Buffer), ProtocolCharacteristics->Name.Length / sizeof(WCHAR));
760 RegistryPathStr[wcslen(SERVICES_KEY)+ProtocolCharacteristics->Name.Length/sizeof(WCHAR)] = 0;
761 wcscat(RegistryPathStr, LINKAGE_KEY);
762
763 RtlInitUnicodeString(&RegistryPath, RegistryPathStr);
764 NDIS_DbgPrint(MAX_TRACE, ("Opening configuration key: %wZ\n", &RegistryPath));
765
766 InitializeObjectAttributes(&ObjectAttributes, &RegistryPath, OBJ_CASE_INSENSITIVE, NULL, NULL);
767 NtStatus = ZwOpenKey(&DriverKeyHandle, KEY_READ, &ObjectAttributes);
768
769 ExFreePool(RegistryPathStr);
770
771 if(!NT_SUCCESS(NtStatus))
772 {
773 NDIS_DbgPrint(MID_TRACE, ("Unable to open protocol configuration\n"));
774 ExFreePool(Protocol);
775 *Status = NDIS_STATUS_FAILURE;
776 return;
777 }
778 }
779
780 NDIS_DbgPrint(MAX_TRACE, ("Successfully opened the registry configuration\n"));
781
782 {
783 UNICODE_STRING ValueName;
784 ULONG ResultLength;
785
786 RtlInitUnicodeString(&ValueName, L"Bind");
787
788 NtStatus = ZwQueryValueKey(DriverKeyHandle, &ValueName, KeyValuePartialInformation, NULL, 0, &ResultLength);
789 if(NtStatus != STATUS_BUFFER_OVERFLOW && NtStatus != STATUS_BUFFER_TOO_SMALL)
790 {
791 NDIS_DbgPrint(MID_TRACE, ("Unable to query the Bind value for size\n"));
792 ZwClose(DriverKeyHandle);
793 ExFreePool(Protocol);
794 *Status = NDIS_STATUS_FAILURE;
795 return;
796 }
797
798 KeyInformation = ExAllocatePoolWithTag(PagedPool, sizeof(KEY_VALUE_PARTIAL_INFORMATION) + ResultLength, NDIS_TAG + __LINE__);
799 if(!KeyInformation)
800 {
801 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
802 ZwClose(DriverKeyHandle);
803 ExFreePool(Protocol);
804 *Status = NDIS_STATUS_FAILURE;
805 return;
806 }
807
808 NtStatus = ZwQueryValueKey(DriverKeyHandle, &ValueName, KeyValuePartialInformation, KeyInformation,
809 sizeof(KEY_VALUE_PARTIAL_INFORMATION) + ResultLength, &ResultLength);
810
811 if(!NT_SUCCESS(NtStatus))
812 {
813 NDIS_DbgPrint(MIN_TRACE, ("Unable to query the Bind value\n"));
814 ZwClose(DriverKeyHandle);
815 ExFreePool(KeyInformation);
816 ExFreePool(Protocol);
817 *Status = NDIS_STATUS_FAILURE;
818 return;
819 }
820 }
821
822 for (DataPtr = (WCHAR *)KeyInformation->Data;
823 *DataPtr != 0;
824 DataPtr += wcslen(DataPtr) + 1)
825 {
826 /* BindContext is for tracking pending binding operations */
827 VOID *BindContext = 0;
828 NDIS_STRING DeviceName;
829 NDIS_STRING RegistryPath;
830 WCHAR *RegistryPathStr = NULL;
831 ULONG PathLength = 0;
832
833 RtlInitUnicodeString(&DeviceName, DataPtr); /* we know this is 0-term */
834
835 /*
836 * RegistryPath should be:
837 * \Registry\Machine\System\CurrentControlSet\Services\Nic1\Parameters\Tcpip
838 *
839 * This is constructed as follows:
840 * SERVICES_KEY + extracted device name + Protocol name from characteristics
841 */
842
843 PathLength = sizeof(SERVICES_KEY) + /* \Registry\Machine\System\CurrentControlSet\Services\ */
844 wcslen( DataPtr + 8 ) * sizeof(WCHAR) + /* Adapter1 (extracted from \Device\Adapter1) */
845 sizeof(PARAMETERS_KEY) + /* \Parameters\ */
846 ProtocolCharacteristics->Name.Length + sizeof(WCHAR); /* Tcpip */
847
848 RegistryPathStr = ExAllocatePool(PagedPool, PathLength);
849 if(!RegistryPathStr)
850 {
851 NDIS_DbgPrint(MIN_TRACE, ("insufficient resources.\n"));
852 ExFreePool(KeyInformation);
853 ExFreePool(Protocol);
854 *Status = NDIS_STATUS_RESOURCES;
855 return;
856 }
857
858 wcscpy(RegistryPathStr, SERVICES_KEY);
859 wcscat(RegistryPathStr, (((WCHAR *)(KeyInformation->Data)) +8 ));
860 wcscat(RegistryPathStr, PARAMETERS_KEY);
861 wcsncat(RegistryPathStr, ProtocolCharacteristics->Name.Buffer, ProtocolCharacteristics->Name.Length / sizeof(WCHAR) );
862
863 RegistryPathStr[PathLength/sizeof(WCHAR) - 1] = 0;
864
865 RtlInitUnicodeString(&RegistryPath, RegistryPathStr);
866
867 NDIS_DbgPrint(MAX_TRACE, ("Calling protocol's BindAdapter handler with DeviceName %wZ and RegistryPath %wZ\n",
868 &DeviceName, &RegistryPath));
869
870 /* XXX SD must do something with bind context */
871 *NdisProtocolHandle = Protocol;
872
873 {
874 BIND_HANDLER BindHandler = ProtocolCharacteristics->BindAdapterHandler;
875 if(BindHandler)
876 BindHandler(Status, BindContext, &DeviceName, &RegistryPath, 0);
877 else
878 NDIS_DbgPrint(MID_TRACE, ("No protocol bind handler specified\n"));
879 }
880
881 /*
882 (*(Protocol->Chars.BindAdapterHandler))(Status, BindContext, &DeviceName, &RegistryPath, 0);
883 */
884
885 if(*Status == NDIS_STATUS_SUCCESS)
886 {
887 /* Put protocol binding struct on global list */
888 ExInterlockedInsertTailList(&ProtocolListHead, &Protocol->ListEntry, &ProtocolListLock);
889 }
890
891 /*
892 else if(*Status != NDIS_STATUS_PENDING)
893 {
894 // what to do here?
895 }
896 */
897 }
898
899 *Status = NDIS_STATUS_SUCCESS;
900 }
901
902 \f
903 /*
904 * @implemented
905 */
906 VOID
907 EXPORT
908 NdisRequest(
909 OUT PNDIS_STATUS Status,
910 IN NDIS_HANDLE NdisBindingHandle,
911 IN PNDIS_REQUEST NdisRequest)
912 /*
913 * FUNCTION: Forwards a request to an NDIS driver
914 * ARGUMENTS:
915 * Status = Address of buffer for status information
916 * NdisBindingHandle = Adapter binding handle
917 * NdisRequest = Pointer to request to perform
918 */
919 {
920 *Status = ProRequest(NdisBindingHandle, NdisRequest);
921 }
922
923 \f
924 /*
925 * @implemented
926 */
927 VOID
928 EXPORT
929 NdisReset(
930 OUT PNDIS_STATUS Status,
931 IN NDIS_HANDLE NdisBindingHandle)
932 {
933 *Status = ProReset(NdisBindingHandle);
934 }
935
936 \f
937 /*
938 * @implemented
939 */
940 VOID
941 EXPORT
942 NdisSend(
943 OUT PNDIS_STATUS Status,
944 IN NDIS_HANDLE NdisBindingHandle,
945 IN PNDIS_PACKET Packet)
946 /*
947 * FUNCTION: Forwards a request to send a packet
948 * ARGUMENTS:
949 * Status = Address of buffer for status information
950 * NdisBindingHandle = Adapter binding handle
951 * Packet = Pointer to NDIS packet descriptor
952 */
953 {
954 *Status = ProSend(NdisBindingHandle, Packet);
955 }
956
957 \f
958 /*
959 * @implemented
960 */
961 VOID
962 EXPORT
963 NdisSendPackets(
964 IN NDIS_HANDLE NdisBindingHandle,
965 IN PPNDIS_PACKET PacketArray,
966 IN UINT NumberOfPackets)
967 {
968 ProSendPackets(NdisBindingHandle, PacketArray, NumberOfPackets);
969 }
970
971 \f
972 /*
973 * @implemented
974 */
975 VOID
976 EXPORT
977 NdisTransferData(
978 OUT PNDIS_STATUS Status,
979 IN NDIS_HANDLE NdisBindingHandle,
980 IN NDIS_HANDLE MacReceiveContext,
981 IN UINT ByteOffset,
982 IN UINT BytesToTransfer,
983 IN OUT PNDIS_PACKET Packet,
984 OUT PUINT BytesTransferred)
985 /*
986 * FUNCTION: Forwards a request to copy received data into a protocol-supplied packet
987 * ARGUMENTS:
988 * Status = Address of buffer for status information
989 * NdisBindingHandle = Adapter binding handle
990 * MacReceiveContext = MAC receive context
991 * ByteOffset = Offset in packet to place data
992 * BytesToTransfer = Number of bytes to copy into packet
993 * Packet = Pointer to NDIS packet descriptor
994 * BytesTransferred = Address of buffer to place number of bytes copied
995 */
996 {
997 *Status = ProTransferData(NdisBindingHandle,
998 MacReceiveContext,
999 ByteOffset,
1000 BytesToTransfer,
1001 Packet,
1002 BytesTransferred);
1003 }
1004
1005 /* EOF */