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