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