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