f418b08076ca8cbc77188585c1563b84a1ed1ea4
[reactos.git] / reactos / drivers / net / tcpip / datalink / lan.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS TCP/IP protocol driver
4 * FILE: datalink/lan.c
5 * PURPOSE: Local Area Network media routines
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * REVISIONS:
8 * CSH 01/08-2000 Created
9 */
10 #include <tcpip.h>
11 #include <lan.h>
12 #include <address.h>
13 #include <routines.h>
14 #include <transmit.h>
15 #include <receive.h>
16 #include <arp.h>
17
18
19 NDIS_HANDLE NdisProtocolHandle = (NDIS_HANDLE)NULL;
20 BOOLEAN ProtocolRegistered = FALSE;
21 LIST_ENTRY AdapterListHead;
22 KSPIN_LOCK AdapterListLock;
23
24
25 NDIS_STATUS NDISCall(
26 PLAN_ADAPTER Adapter,
27 NDIS_REQUEST_TYPE Type,
28 NDIS_OID OID,
29 PVOID Buffer,
30 UINT Length)
31 /*
32 * FUNCTION: Send a request to NDIS
33 * ARGUMENTS:
34 * Adapter = Pointer to a LAN_ADAPTER structure
35 * Type = Type of request (Set or Query)
36 * OID = Value to be set/queried for
37 * Buffer = Pointer to a buffer to use
38 * Length = Number of bytes in Buffer
39 * RETURNS:
40 * Status of operation
41 */
42 {
43 NDIS_REQUEST Request;
44 NDIS_STATUS NdisStatus;
45
46 Request.RequestType = Type;
47 if (Type == NdisRequestSetInformation) {
48 Request.DATA.SET_INFORMATION.Oid = OID;
49 Request.DATA.SET_INFORMATION.InformationBuffer = Buffer;
50 Request.DATA.SET_INFORMATION.InformationBufferLength = Length;
51 } else {
52 Request.DATA.QUERY_INFORMATION.Oid = OID;
53 Request.DATA.QUERY_INFORMATION.InformationBuffer = Buffer;
54 Request.DATA.QUERY_INFORMATION.InformationBufferLength = Length;
55 }
56
57 if (Adapter->State != LAN_STATE_RESETTING) {
58 NdisRequest(&NdisStatus, Adapter->NdisHandle, &Request);
59 } else {
60 NdisStatus = NDIS_STATUS_NOT_ACCEPTED;
61 }
62
63 /* Wait for NDIS to complete the request */
64 if (NdisStatus == NDIS_STATUS_PENDING) {
65 KeWaitForSingleObject(&Adapter->Event,
66 UserRequest,
67 KernelMode,
68 FALSE,
69 NULL);
70 NdisStatus = Adapter->NdisStatus;
71 }
72
73 return NdisStatus;
74 }
75
76
77 PNDIS_PACKET AllocateTDPacket(
78 PLAN_ADAPTER Adapter)
79 /*
80 * FUNCTION: Allocates an NDIS packet for NdisTransferData
81 * ARGUMENTS:
82 * Adapter = Pointer to LAN_ADAPTER structure
83 * RETURNS:
84 * Pointer to NDIS packet or NULL if there was not enough free
85 * non-paged memory
86 */
87 {
88 NDIS_STATUS NdisStatus;
89 PNDIS_PACKET NdisPacket;
90 PNDIS_BUFFER Buffer;
91 PVOID Data;
92
93 NdisAllocatePacket(&NdisStatus, &NdisPacket, GlobalPacketPool);
94 if (NdisStatus != NDIS_STATUS_SUCCESS)
95 return NULL;
96
97 Data = ExAllocatePool(NonPagedPool, Adapter->MTU);
98 if (!Data) {
99 NdisFreePacket(NdisPacket);
100 return NULL;
101 }
102
103 NdisAllocateBuffer(&NdisStatus,
104 &Buffer,
105 GlobalBufferPool,
106 Data,
107 Adapter->MTU);
108 if (NdisStatus != NDIS_STATUS_SUCCESS) {
109 NdisFreePacket(NdisPacket);
110 ExFreePool(Data);
111 return NULL;
112 }
113
114 NdisChainBufferAtFront(NdisPacket, Buffer);
115
116 PC(NdisPacket)->Context = NULL; /* End of list */
117
118 return NdisPacket;
119 }
120
121
122 VOID FreeTDPackets(
123 PLAN_ADAPTER Adapter)
124 /*
125 * FUNCTION: Frees transfer data packets
126 * ARGUMENTS:
127 * Adapter = Pointer to LAN_ADAPTER structure
128 */
129 {
130 PNDIS_PACKET NdisPacket, Next;
131
132 /* Release transfer data packets */
133 NdisPacket = Adapter->TDPackets;
134 while (NdisPacket) {
135 Next = PC(NdisPacket)->Context;
136 FreeNdisPacket(NdisPacket);
137 NdisPacket = Next;
138 }
139 Adapter->TDPackets = NULL;
140 }
141
142
143 VOID FreeAdapter(
144 PLAN_ADAPTER Adapter)
145 /*
146 * FUNCTION: Frees memory for a LAN_ADAPTER structure
147 * ARGUMENTS:
148 * Adapter = Pointer to LAN_ADAPTER structure to free
149 */
150 {
151 FreeTDPackets(Adapter);
152 ExFreePool(Adapter);
153 }
154
155
156 VOID ProtocolOpenAdapterComplete(
157 NDIS_HANDLE BindingContext,
158 NDIS_STATUS Status,
159 NDIS_STATUS OpenErrorStatus)
160 /*
161 * FUNCTION: Called by NDIS to complete opening of an adapter
162 * ARGUMENTS:
163 * BindingContext = Pointer to a device context (LAN_ADAPTER)
164 * Status = Status of the operation
165 * OpenErrorStatus = Additional status information
166 */
167 {
168 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
169
170 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
171
172 KeSetEvent(&Adapter->Event, 0, FALSE);
173 }
174
175
176 VOID ProtocolCloseAdapterComplete(
177 NDIS_HANDLE BindingContext,
178 NDIS_STATUS Status)
179 /*
180 * FUNCTION: Called by NDIS to complete closing an adapter
181 * ARGUMENTS:
182 * BindingContext = Pointer to a device context (LAN_ADAPTER)
183 * Status = Status of the operation
184 */
185 {
186 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
187
188 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
189
190 Adapter->NdisStatus = Status;
191
192 KeSetEvent(&Adapter->Event, 0, FALSE);
193 }
194
195
196 VOID ProtocolResetComplete(
197 NDIS_HANDLE BindingContext,
198 NDIS_STATUS Status)
199 /*
200 * FUNCTION: Called by NDIS to complete resetting an adapter
201 * ARGUMENTS:
202 * BindingContext = Pointer to a device context (LAN_ADAPTER)
203 * Status = Status of the operation
204 */
205 {
206 TI_DbgPrint(MID_TRACE, ("Called.\n"));
207 }
208
209
210 VOID ProtocolRequestComplete(
211 NDIS_HANDLE BindingContext,
212 PNDIS_REQUEST NdisRequest,
213 NDIS_STATUS Status)
214 /*
215 * FUNCTION: Called by NDIS to complete a request
216 * ARGUMENTS:
217 * BindingContext = Pointer to a device context (LAN_ADAPTER)
218 * NdisRequest = Pointer to an object describing the request
219 * Status = Status of the operation
220 */
221 {
222 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
223
224 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
225
226 /* Save status of request and signal an event */
227 Adapter->NdisStatus = Status;
228
229 KeSetEvent(&Adapter->Event, 0, FALSE);
230 }
231
232
233 VOID ProtocolSendComplete(
234 NDIS_HANDLE BindingContext,
235 PNDIS_PACKET Packet,
236 NDIS_STATUS Status)
237 /*
238 * FUNCTION: Called by NDIS to complete sending process
239 * ARGUMENTS:
240 * BindingContext = Pointer to a device context (LAN_ADAPTER)
241 * Packet = Pointer to a packet descriptor
242 * Status = Status of the operation
243 */
244 {
245 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
246
247 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
248
249 AdjustPacket(Packet, Adapter->HeaderSize, PC(Packet)->DLOffset);
250
251 (*PC(Packet)->DLComplete)(Adapter->Context, Packet, Status);
252 }
253
254
255 VOID ProtocolTransferDataComplete(
256 NDIS_HANDLE BindingContext,
257 PNDIS_PACKET Packet,
258 NDIS_STATUS Status,
259 UINT BytesTransferred)
260 /*
261 * FUNCTION: Called by NDIS to complete reception of data
262 * ARGUMENTS:
263 * BindingContext = Pointer to a device context (LAN_ADAPTER)
264 * Packet = Pointer to a packet descriptor
265 * Status = Status of the operation
266 * BytesTransferred = Number of bytes transferred
267 * NOTES:
268 * If the packet was successfully received, determine the protocol
269 * type and pass it to the correct receive handler
270 */
271 {
272 UINT PacketType;
273 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
274
275 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
276
277 if (Status == NDIS_STATUS_SUCCESS) {
278 PNDIS_BUFFER NdisBuffer;
279 IP_PACKET IPPacket;
280
281 IPPacket.NdisPacket = Packet;
282
283 NdisGetFirstBufferFromPacket(Packet,
284 &NdisBuffer,
285 &IPPacket.Header,
286 &IPPacket.ContigSize,
287 &IPPacket.TotalSize);
288
289 /* Determine which upper layer protocol that should receive
290 this packet and pass it to the correct receive handler */
291 PacketType = ((PETH_HEADER)IPPacket.Header)->EType;
292 switch (PacketType) {
293 case ETYPE_IPv4:
294 case ETYPE_IPv6:
295 IPReceive(Adapter->Context, &IPPacket);
296 break;
297 case ETYPE_ARP:
298 ARPReceive(Adapter->Context, &IPPacket);
299 default:
300 break;
301 }
302 }
303
304 /* Release the packet descriptor */
305 KeAcquireSpinLockAtDpcLevel(&Adapter->Lock);
306
307 PC(Packet)->Context = Adapter->TDPackets;
308 Adapter->TDPackets = Packet;
309
310 KeReleaseSpinLockFromDpcLevel(&Adapter->Lock);
311 }
312
313
314 NDIS_STATUS ProtocolReceive(
315 NDIS_HANDLE BindingContext,
316 NDIS_HANDLE MacReceiveContext,
317 PVOID HeaderBuffer,
318 UINT HeaderBufferSize,
319 PVOID LookaheadBuffer,
320 UINT LookaheadBufferSize,
321 UINT PacketSize)
322 /*
323 * FUNCTION: Called by NDIS when a packet has been received on the physical link
324 * ARGUMENTS:
325 * BindingContext = Pointer to a device context (LAN_ADAPTER)
326 * MacReceiveContext = Handle used by underlying NIC driver
327 * HeaderBuffer = Pointer to a buffer containing the packet header
328 * HeaderBufferSize = Number of bytes in HeaderBuffer
329 * LookaheadBuffer = Pointer to a buffer containing buffered packet data
330 * LookaheadBufferSize = Size of LookaheadBuffer. May be less than asked for
331 * PacketSize = Overall size of the packet (not including header)
332 * RETURNS:
333 * Status of operation
334 */
335 {
336 USHORT EType;
337 UINT PacketType;
338 IP_PACKET IPPacket;
339 PNDIS_PACKET NdisPacket;
340 PNDIS_BUFFER NdisBuffer;
341 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
342 PETH_HEADER EHeader = (PETH_HEADER)HeaderBuffer;
343
344 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
345
346 if (Adapter->State != LAN_STATE_STARTED) {
347 TI_DbgPrint(DEBUG_DATALINK, ("Adapter is stopped.\n"));
348 return NDIS_STATUS_NOT_ACCEPTED;
349 }
350
351 if (HeaderBufferSize < Adapter->HeaderSize) {
352 TI_DbgPrint(DEBUG_DATALINK, ("Runt frame received.\n"));
353 return NDIS_STATUS_NOT_ACCEPTED;
354 }
355
356 if (Adapter->Media == NdisMedium802_3) {
357 /* Ethernet and IEEE 802.3 frames can be destinguished by
358 looking at the IEEE 802.3 length field. This field is
359 less than or equal to 1500 for a valid IEEE 802.3 frame
360 and larger than 1500 is it's a valid EtherType value.
361 See RFC 1122, section 2.3.3 for more information */
362 /* FIXME: Test for Ethernet and IEEE 802.3 frame */
363 if (((EType = EHeader->EType) != ETYPE_IPv4) && (EType != ETYPE_ARP)) {
364 TI_DbgPrint(DEBUG_DATALINK, ("Not IP or ARP frame. EtherType (0x%X).\n", EType));
365 return NDIS_STATUS_NOT_ACCEPTED;
366 }
367 /* We use EtherType constants to destinguish packet types */
368 PacketType = EType;
369 } else {
370 TI_DbgPrint(MIN_TRACE, ("Unsupported media.\n"));
371 /* FIXME: Support other medias */
372 return NDIS_STATUS_NOT_ACCEPTED;
373 }
374
375 /* Get a transfer data packet */
376
377 KeAcquireSpinLockAtDpcLevel(&Adapter->Lock);
378
379 NdisPacket = Adapter->TDPackets;
380 if (NdisPacket == (PNDIS_PACKET)NULL) {
381 TI_DbgPrint(DEBUG_DATALINK, ("No available packet descriptors.\n"));
382 /* We don't have a free packet descriptor. Drop the packet */
383 KeReleaseSpinLockFromDpcLevel(&Adapter->Lock);
384 return NDIS_STATUS_SUCCESS;
385 }
386 Adapter->TDPackets = PC(NdisPacket)->Context;
387
388 KeReleaseSpinLockFromDpcLevel(&Adapter->Lock);
389
390 if (LookaheadBufferSize < PacketSize) {
391 NDIS_STATUS NdisStatus;
392 UINT BytesTransferred;
393
394 /* Get the data */
395 NdisTransferData(&NdisStatus,
396 Adapter->NdisHandle,
397 MacReceiveContext,
398 0,
399 PacketSize,
400 NdisPacket,
401 &BytesTransferred);
402 if (NdisStatus != NDIS_STATUS_PENDING)
403 ProtocolTransferDataComplete(BindingContext,
404 NdisPacket,
405 NdisStatus,
406 BytesTransferred);
407
408 return NDIS_STATUS_SUCCESS;
409 }
410
411 /* We got all the data in the lookahead buffer */
412
413 IPPacket.NdisPacket = NdisPacket;
414
415 NdisGetFirstBufferFromPacket(NdisPacket,
416 &NdisBuffer,
417 &IPPacket.Header,
418 &IPPacket.ContigSize,
419 &IPPacket.TotalSize);
420
421 RtlCopyMemory(IPPacket.Header, LookaheadBuffer, PacketSize);
422
423 switch (PacketType) {
424 case ETYPE_IPv4:
425 case ETYPE_IPv6:
426 IPReceive(Adapter->Context, &IPPacket);
427 break;
428 case ETYPE_ARP:
429 ARPReceive(Adapter->Context, &IPPacket);
430 break;
431 default:
432 break;
433 }
434
435 /* Release the packet descriptor */
436 KeAcquireSpinLockAtDpcLevel(&Adapter->Lock);
437
438 PC(NdisPacket)->Context = Adapter->TDPackets;
439 Adapter->TDPackets = NdisPacket;
440
441 KeReleaseSpinLockFromDpcLevel(&Adapter->Lock);
442
443 return NDIS_STATUS_SUCCESS;
444 }
445
446
447 VOID ProtocolReceiveComplete(
448 NDIS_HANDLE BindingContext)
449 /*
450 * FUNCTION: Called by NDIS when we're done receiving data
451 * ARGUMENTS:
452 * BindingContext = Pointer to a device context (LAN_ADAPTER)
453 */
454 {
455 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
456 }
457
458
459 VOID ProtocolStatus(
460 NDIS_HANDLE BindingContext,
461 NDIS_STATUS GenerelStatus,
462 PVOID StatusBuffer,
463 UINT StatusBufferSize)
464 /*
465 * FUNCTION: Called by NDIS when the underlying driver has changed state
466 * ARGUMENTS:
467 * BindingContext = Pointer to a device context (LAN_ADAPTER)
468 * GenerelStatus = A generel status code
469 * StatusBuffer = Pointer to a buffer with medium-specific data
470 * StatusBufferSize = Number of bytes in StatusBuffer
471 */
472 {
473 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
474 }
475
476
477 VOID ProtocolStatusComplete(
478 NDIS_HANDLE NdisBindingContext)
479 /*
480 * FUNCTION: Called by NDIS when a status-change has occurred
481 * ARGUMENTS:
482 * BindingContext = Pointer to a device context (LAN_ADAPTER)
483 */
484 {
485 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
486 }
487
488 VOID ProtocolBindAdapter(
489 OUT PNDIS_STATUS Status,
490 IN NDIS_HANDLE BindContext,
491 IN PNDIS_STRING DeviceName,
492 IN PVOID SystemSpecific1,
493 IN PVOID SystemSpecific2)
494 /*
495 * FUNCTION: Called by NDIS during NdisRegisterProtocol to set up initial
496 * bindings, and periodically thereafer as new adapters come online
497 * ARGUMENTS:
498 * Status: Return value to NDIS
499 * BindContext: Handle provided by NDIS to track pending binding operations
500 * DeviceName: Name of the miniport device to bind to
501 * SystemSpecific1: Pointer to a registry path with protocol-specific configuration information
502 * SystemSpecific2: Unused & must not be touched
503 */
504 {
505 /* XXX confirm that this is still true, or re-word the following comment */
506 /* we get to ignore BindContext because we will never pend an operation with NDIS */
507 TI_DbgPrint(DEBUG_DATALINK, ("Called with registry path %wZ\n", SystemSpecific1));
508 *Status = LANRegisterAdapter(DeviceName, SystemSpecific1);
509 }
510
511
512 VOID LANTransmit(
513 PVOID Context,
514 PNDIS_PACKET NdisPacket,
515 UINT Offset,
516 PVOID LinkAddress,
517 USHORT Type)
518 /*
519 * FUNCTION: Transmits a packet
520 * ARGUMENTS:
521 * Context = Pointer to context information (LAN_ADAPTER)
522 * NdisPacket = Pointer to NDIS packet to send
523 * Offset = Offset in packet where data starts
524 * LinkAddress = Pointer to link address of destination (NULL = broadcast)
525 * Type = LAN protocol type (LAN_PROTO_*)
526 */
527 {
528 NDIS_STATUS NdisStatus;
529 PETH_HEADER EHeader;
530 PVOID Data;
531 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)Context;
532
533 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
534
535 /* NDIS send routines don't have an offset argument so we
536 must offset the data in upper layers and adjust the
537 packet here. We save the offset in the packet context
538 area so it can be undone before we release the packet */
539 Data = AdjustPacket(NdisPacket, Offset, Adapter->HeaderSize);
540 PC(NdisPacket)->DLOffset = Offset;
541
542 if (Adapter->State == LAN_STATE_STARTED) {
543 switch (Adapter->Media) {
544 case NdisMedium802_3:
545 EHeader = (PETH_HEADER)Data;
546
547 if (LinkAddress) {
548 /* Unicast address */
549 RtlCopyMemory(EHeader->DstAddr, LinkAddress, IEEE_802_ADDR_LENGTH);
550 } else {
551 /* Broadcast address */
552 RtlFillMemory(EHeader->DstAddr, IEEE_802_ADDR_LENGTH, 0xFF);
553 }
554
555 RtlCopyMemory(EHeader->SrcAddr, Adapter->HWAddress, IEEE_802_ADDR_LENGTH);
556
557 switch (Type) {
558 case LAN_PROTO_IPv4:
559 EHeader->EType = ETYPE_IPv4;
560 break;
561 case LAN_PROTO_ARP:
562 EHeader->EType = ETYPE_ARP;
563 break;
564 case LAN_PROTO_IPv6:
565 EHeader->EType = ETYPE_IPv6;
566 break;
567 default:
568 #ifdef DBG
569 /* Should not happen */
570 TI_DbgPrint(MIN_TRACE, ("Unknown LAN protocol.\n"));
571
572 ProtocolSendComplete((NDIS_HANDLE)Context,
573 NdisPacket,
574 NDIS_STATUS_FAILURE);
575 #endif
576 return;
577 }
578 break;
579
580 default:
581 /* FIXME: Support other medias */
582 break;
583 }
584
585 NdisSend(&NdisStatus, Adapter->NdisHandle, NdisPacket);
586 if (NdisStatus != NDIS_STATUS_PENDING)
587 ProtocolSendComplete((NDIS_HANDLE)Context, NdisPacket, NdisStatus);
588 } else {
589 ProtocolSendComplete((NDIS_HANDLE)Context, NdisPacket, NDIS_STATUS_CLOSED);
590 }
591 }
592
593
594 VOID BindAdapter(
595 PLAN_ADAPTER Adapter,
596 PNDIS_STRING RegistryPath)
597 /*
598 * FUNCTION: Binds a LAN adapter to IP layer
599 * ARGUMENTS:
600 * Adapter = Pointer to LAN_ADAPTER structure
601 * NOTES:
602 * We set the lookahead buffer size, set the packet filter and
603 * bind the adapter to IP layer
604 */
605 {
606 INT i;
607 PIP_INTERFACE IF;
608 PIP_ADDRESS Address;
609 PNDIS_PACKET Packet;
610 NDIS_STATUS NdisStatus;
611 LLIP_BIND_INFO BindInfo;
612 ULONG Lookahead = LOOKAHEAD_SIZE;
613
614 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
615
616 Adapter->State = LAN_STATE_OPENING;
617
618 NdisStatus = NDISCall(Adapter,
619 NdisRequestSetInformation,
620 OID_GEN_CURRENT_LOOKAHEAD,
621 &Lookahead,
622 sizeof(ULONG));
623 if (NdisStatus != NDIS_STATUS_SUCCESS) {
624 TI_DbgPrint(MID_TRACE, ("Could not set lookahead buffer size (0x%X).\n", NdisStatus));
625 return;
626 }
627
628 /* Allocate packets for NdisTransferData */
629 /* FIXME: How many should we allocate? */
630 Adapter->TDPackets = NULL;
631 for (i = 0; i < 2; i++) {
632 Packet = AllocateTDPacket(Adapter);
633 if (!Packet) {
634 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
635 FreeTDPackets(Adapter);
636 return;
637 }
638 PC(Packet)->Context = Adapter->TDPackets;
639 Adapter->TDPackets = Packet;
640 }
641
642 /* Bind the adapter to IP layer */
643 BindInfo.Context = Adapter;
644 BindInfo.HeaderSize = Adapter->HeaderSize;
645 BindInfo.MinFrameSize = Adapter->MinFrameSize;
646 BindInfo.MTU = Adapter->MTU;
647 BindInfo.Address = (PUCHAR)&Adapter->HWAddress;
648 BindInfo.AddressLength = Adapter->HWAddressLength;
649 BindInfo.Transmit = LANTransmit;
650
651 IF = IPCreateInterface(&BindInfo);
652 if (!IF) {
653 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
654 FreeTDPackets(Adapter);
655 return;
656 }
657
658 {
659 /*
660 * Query per-adapter configuration from the registry
661 * In case anyone is curious: there *is* an Ndis configuration api
662 * for this sort of thing, but it doesn't really support things like
663 * REG_MULTI_SZ very well, and there is a note in the DDK that says that
664 * protocol drivers developed for win2k and above just use the native
665 * services (ZwOpenKey, etc).
666 */
667
668 OBJECT_ATTRIBUTES Attributes;
669 HANDLE RegHandle;
670 NTSTATUS Status;
671 UNICODE_STRING ValueName;
672 UCHAR buf[1024];
673 PKEY_VALUE_PARTIAL_INFORMATION Information = (PKEY_VALUE_PARTIAL_INFORMATION)buf;
674 ULONG ResultLength;
675 ANSI_STRING AnsiAddress;
676 UNICODE_STRING UnicodeAddress;
677 ULONG AnsiLen;
678
679 InitializeObjectAttributes(&Attributes, RegistryPath, OBJ_CASE_INSENSITIVE, 0, 0);
680 Status = ZwOpenKey(&RegHandle, GENERIC_READ, &Attributes);
681
682 if(!NT_SUCCESS(Status))
683 {
684 TI_DbgPrint(MIN_TRACE, ("Unable to open protocol-specific registry key: 0x%x\n", Status));
685
686 /* XXX how do we proceed? No ip address, no parameters... do we guess? */
687 FreeTDPackets(Adapter);
688 IPDestroyInterface(Adapter->Context);
689 return;
690 }
691
692 RtlInitUnicodeString(&ValueName, L"IPAddress");
693 ZwQueryValueKey(RegHandle, &ValueName, KeyValuePartialInformation, Information, sizeof(buf), &ResultLength);
694 ZwClose(RegHandle);
695
696 /* IP address is stored as a REG_MULTI_SZ - we only pay attention to the first one though */
697 TI_DbgPrint(MIN_TRACE, ("Information DataLength: 0x%x\n", Information->DataLength));
698
699 UnicodeAddress.Buffer = (PWCHAR)&Information->Data;
700 UnicodeAddress.Length = Information->DataLength;
701 UnicodeAddress.MaximumLength = Information->DataLength;
702
703 AnsiLen = RtlUnicodeStringToAnsiSize(&UnicodeAddress);
704 if(!AnsiLen)
705 {
706 TI_DbgPrint(MIN_TRACE, ("Unable to calculate address length\n"));
707 FreeTDPackets(Adapter);
708 IPDestroyInterface(Adapter->Context);
709 return;
710 }
711
712 AnsiAddress.Buffer = ExAllocatePoolWithTag(PagedPool, AnsiLen, 0x01020304);
713 if(!AnsiAddress.Buffer)
714 {
715 TI_DbgPrint(MIN_TRACE, ("ExAllocatePoolWithTag() failed.\n"));
716 FreeTDPackets(Adapter);
717 IPDestroyInterface(Adapter->Context);
718 return;
719 }
720 AnsiAddress.Length = AnsiLen;
721 AnsiAddress.MaximumLength = AnsiLen;
722
723 Status = RtlUnicodeStringToAnsiString(&AnsiAddress, &UnicodeAddress, FALSE);
724 if (!NT_SUCCESS(Status))
725 {
726 TI_DbgPrint(MIN_TRACE, ("RtlUnicodeStringToAnsiString() failed with Status 0x%lx.\n", Status));
727 FreeTDPackets(Adapter);
728 IPDestroyInterface(Adapter->Context);
729 return;
730 }
731
732 AnsiAddress.Buffer[AnsiAddress.Length] = 0;
733 Address = AddrBuildIPv4(inet_addr(AnsiAddress.Buffer));
734 if (!Address) {
735 TI_DbgPrint(MIN_TRACE, ("AddrBuildIPv4() failed.\n"));
736 FreeTDPackets(Adapter);
737 IPDestroyInterface(Adapter->Context);
738 return;
739 }
740
741 TI_DbgPrint(MID_TRACE, ("--> Our IP address on this interface: '%s'\n", A2S(Address)));
742 }
743
744 /* Create a net table entry for this interface */
745 if (!IPCreateNTE(IF, Address, 8)) {
746 TI_DbgPrint(MIN_TRACE, ("IPCreateNTE() failed.\n"));
747 FreeTDPackets(Adapter);
748 IPDestroyInterface(IF);
749 return;
750 }
751
752 /* Reference the interface for the NTE. The reference
753 for the address is just passed on to the NTE */
754 ReferenceObject(IF);
755
756 /* Register interface with IP layer */
757 IPRegisterInterface(IF);
758
759 /* Set packet filter so we can send and receive packets */
760 NdisStatus = NDISCall(Adapter,
761 NdisRequestSetInformation,
762 OID_GEN_CURRENT_PACKET_FILTER,
763 &Adapter->PacketFilter,
764 sizeof(UINT));
765 if (NdisStatus != NDIS_STATUS_SUCCESS) {
766 TI_DbgPrint(MID_TRACE, ("Could not set packet filter (0x%X).\n", NdisStatus));
767 FreeTDPackets(Adapter);
768 IPDestroyInterface(IF);
769 return;
770 }
771
772 Adapter->Context = IF;
773
774 Adapter->State = LAN_STATE_STARTED;
775 }
776
777
778 VOID UnbindAdapter(
779 PLAN_ADAPTER Adapter)
780 /*
781 * FUNCTION: Unbinds a LAN adapter from IP layer
782 * ARGUMENTS:
783 * Adapter = Pointer to LAN_ADAPTER structure
784 */
785 {
786 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
787
788 if (Adapter->State == LAN_STATE_STARTED) {
789 PIP_INTERFACE IF = Adapter->Context;
790
791 IPUnregisterInterface(IF);
792
793 IPDestroyInterface(IF);
794
795 /* Free transfer data packets */
796 FreeTDPackets(Adapter);
797 }
798 }
799
800
801 NDIS_STATUS LANRegisterAdapter(
802 PNDIS_STRING AdapterName,
803 PNDIS_STRING RegistryPath)
804 /*
805 * FUNCTION: Registers protocol with an NDIS adapter
806 * ARGUMENTS:
807 * AdapterName = Pointer to string with name of adapter to register
808 * Adapter = Address of pointer to a LAN_ADAPTER structure
809 * RETURNS:
810 * Status of operation
811 */
812 {
813 PLAN_ADAPTER IF;
814 NDIS_STATUS NdisStatus;
815 NDIS_STATUS OpenStatus;
816 PNDIS_CONFIGURATION_PARAMETER Parameter;
817 UINT MediaIndex;
818 NDIS_MEDIUM MediaArray[MAX_MEDIA];
819 UINT AddressOID;
820 UINT Speed;
821
822 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
823
824 IF = ExAllocatePool(NonPagedPool, sizeof(LAN_ADAPTER));
825 if (!IF) {
826 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
827 return NDIS_STATUS_RESOURCES;
828 }
829
830 RtlZeroMemory(IF, sizeof(LAN_ADAPTER));
831
832 /* Put adapter in stopped state */
833 IF->State = LAN_STATE_STOPPED;
834
835 /* Initialize protecting spin lock */
836 KeInitializeSpinLock(&IF->Lock);
837
838 KeInitializeEvent(&IF->Event, SynchronizationEvent, FALSE);
839
840 /* Initialize array with media IDs we support */
841 MediaArray[MEDIA_ETH] = NdisMedium802_3;
842
843 TI_DbgPrint(DEBUG_DATALINK,("opening adapter %wZ\n", AdapterName));
844 /* Open the adapter. */
845 NdisOpenAdapter(&NdisStatus,
846 &OpenStatus,
847 &IF->NdisHandle,
848 &MediaIndex,
849 MediaArray,
850 MAX_MEDIA,
851 NdisProtocolHandle,
852 IF,
853 AdapterName,
854 0,
855 NULL);
856
857 /* Wait until the adapter is opened */
858 if (NdisStatus == NDIS_STATUS_PENDING)
859 KeWaitForSingleObject(&IF->Event, UserRequest, KernelMode, FALSE, NULL);
860 else if (NdisStatus != NDIS_STATUS_SUCCESS) {
861 ExFreePool(IF);
862 return NdisStatus;
863 }
864
865 IF->Media = MediaArray[MediaIndex];
866
867 /* Fill LAN_ADAPTER structure with some adapter specific information */
868 switch (IF->Media) {
869 case NdisMedium802_3:
870 IF->HWAddressLength = IEEE_802_ADDR_LENGTH;
871 IF->BCastMask = BCAST_ETH_MASK;
872 IF->BCastCheck = BCAST_ETH_CHECK;
873 IF->BCastOffset = BCAST_ETH_OFFSET;
874 IF->HeaderSize = sizeof(ETH_HEADER);
875 IF->MinFrameSize = 60;
876 AddressOID = OID_802_3_CURRENT_ADDRESS;
877 IF->PacketFilter =
878 NDIS_PACKET_TYPE_BROADCAST |
879 NDIS_PACKET_TYPE_DIRECTED |
880 NDIS_PACKET_TYPE_MULTICAST;
881 break;
882
883 default:
884 /* Unsupported media */
885 TI_DbgPrint(MIN_TRACE, ("Unsupported media.\n"));
886 ExFreePool(IF);
887 return NDIS_STATUS_NOT_SUPPORTED;
888 }
889
890 /* Get maximum frame size */
891 NdisStatus = NDISCall(IF,
892 NdisRequestQueryInformation,
893 OID_GEN_MAXIMUM_FRAME_SIZE,
894 &IF->MTU,
895 sizeof(UINT));
896 if (NdisStatus != NDIS_STATUS_SUCCESS) {
897 ExFreePool(IF);
898 return NdisStatus;
899 }
900
901 /* Get maximum packet size */
902 NdisStatus = NDISCall(IF,
903 NdisRequestQueryInformation,
904 OID_GEN_MAXIMUM_TOTAL_SIZE,
905 &IF->MaxPacketSize,
906 sizeof(UINT));
907 if (NdisStatus != NDIS_STATUS_SUCCESS) {
908 TI_DbgPrint(MIN_TRACE, ("Query for maximum packet size failed.\n"));
909 ExFreePool(IF);
910 return NdisStatus;
911 }
912
913 /* Get maximum number of packets we can pass to NdisSend(Packets) at one time */
914 NdisStatus = NDISCall(IF,
915 NdisRequestQueryInformation,
916 OID_GEN_MAXIMUM_SEND_PACKETS,
917 &IF->MaxSendPackets,
918 sizeof(UINT));
919 if (NdisStatus != NDIS_STATUS_SUCCESS)
920 /* Legacy NIC drivers may not support this query, if it fails we
921 assume it can send at least one packet per call to NdisSend(Packets) */
922 IF->MaxSendPackets = 1;
923
924 /* Get current hardware address */
925 NdisStatus = NDISCall(IF,
926 NdisRequestQueryInformation,
927 AddressOID,
928 &IF->HWAddress,
929 IF->HWAddressLength);
930 if (NdisStatus != NDIS_STATUS_SUCCESS) {
931 TI_DbgPrint(MIN_TRACE, ("Query for current hardware address failed.\n"));
932 ExFreePool(IF);
933 return NdisStatus;
934 }
935
936 /* Get maximum link speed */
937 NdisStatus = NDISCall(IF,
938 NdisRequestQueryInformation,
939 OID_GEN_LINK_SPEED,
940 &Speed,
941 sizeof(UINT));
942 if (NdisStatus != NDIS_STATUS_SUCCESS) {
943 TI_DbgPrint(MIN_TRACE, ("Query for maximum link speed failed.\n"));
944 ExFreePool(IF);
945 return NdisStatus;
946 }
947
948 /* Convert returned link speed to bps (it is in 100bps increments) */
949 IF->Speed = Speed * 100L;
950
951 /* Add adapter to the adapter list */
952 ExInterlockedInsertTailList(&AdapterListHead,
953 &IF->ListEntry,
954 &AdapterListLock);
955
956 /* Bind adapter to IP layer */
957 BindAdapter(IF, RegistryPath);
958
959 TI_DbgPrint(DEBUG_DATALINK, ("Leaving.\n"));
960
961 return NDIS_STATUS_SUCCESS;
962 }
963
964
965 NDIS_STATUS LANUnregisterAdapter(
966 PLAN_ADAPTER Adapter)
967 /*
968 * FUNCTION: Unregisters protocol with NDIS adapter
969 * ARGUMENTS:
970 * Adapter = Pointer to a LAN_ADAPTER structure
971 * RETURNS:
972 * Status of operation
973 */
974 {
975 KIRQL OldIrql;
976 NDIS_HANDLE NdisHandle;
977 NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS;
978
979 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
980
981 /* Unlink the adapter from the list */
982 RemoveEntryList(&Adapter->ListEntry);
983
984 /* Unbind adapter from IP layer */
985 UnbindAdapter(Adapter);
986
987 KeAcquireSpinLock(&Adapter->Lock, &OldIrql);
988 NdisHandle = Adapter->NdisHandle;
989 if (NdisHandle) {
990 Adapter->NdisHandle = NULL;
991 KeReleaseSpinLock(&Adapter->Lock, OldIrql);
992
993 NdisCloseAdapter(&NdisStatus, NdisHandle);
994 if (NdisStatus == NDIS_STATUS_PENDING) {
995 KeWaitForSingleObject(&Adapter->Event,
996 UserRequest,
997 KernelMode,
998 FALSE,
999 NULL);
1000 NdisStatus = Adapter->NdisStatus;
1001 }
1002 } else
1003 KeReleaseSpinLock(&Adapter->Lock, OldIrql);
1004
1005 FreeAdapter(Adapter);
1006
1007 return NDIS_STATUS_SUCCESS;
1008 }
1009
1010
1011 NTSTATUS LANRegisterProtocol(
1012 PNDIS_STRING Name)
1013 /*
1014 * FUNCTION: Registers this protocol driver with NDIS
1015 * ARGUMENTS:
1016 * Name = Name of this protocol driver
1017 * RETURNS:
1018 * Status of operation
1019 */
1020 {
1021 NDIS_STATUS NdisStatus;
1022 NDIS_PROTOCOL_CHARACTERISTICS ProtChars;
1023
1024 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
1025
1026 InitializeListHead(&AdapterListHead);
1027 KeInitializeSpinLock(&AdapterListLock);
1028
1029 /* Set up protocol characteristics */
1030 RtlZeroMemory(&ProtChars, sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
1031 ProtChars.MajorNdisVersion = NDIS_VERSION_MAJOR;
1032 ProtChars.MinorNdisVersion = NDIS_VERSION_MINOR;
1033 ProtChars.Name.Length = Name->Length;
1034 ProtChars.Name.Buffer = Name->Buffer;
1035 ProtChars.Name.MaximumLength = Name->MaximumLength;
1036 ProtChars.OpenAdapterCompleteHandler = ProtocolOpenAdapterComplete;
1037 ProtChars.CloseAdapterCompleteHandler = ProtocolCloseAdapterComplete;
1038 ProtChars.ResetCompleteHandler = ProtocolResetComplete;
1039 ProtChars.RequestCompleteHandler = ProtocolRequestComplete;
1040 ProtChars.u2.SendCompleteHandler = ProtocolSendComplete;
1041 ProtChars.u3.TransferDataCompleteHandler = ProtocolTransferDataComplete;
1042 ProtChars.u4.ReceiveHandler = ProtocolReceive;
1043 ProtChars.ReceiveCompleteHandler = ProtocolReceiveComplete;
1044 ProtChars.StatusHandler = ProtocolStatus;
1045 ProtChars.StatusCompleteHandler = ProtocolStatusComplete;
1046 ProtChars.BindAdapterHandler = ProtocolBindAdapter;
1047
1048 /* Try to register protocol */
1049 NdisRegisterProtocol(&NdisStatus,
1050 &NdisProtocolHandle,
1051 &ProtChars,
1052 sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
1053 if (NdisStatus != NDIS_STATUS_SUCCESS)
1054 {
1055 TI_DbgPrint(MID_TRACE, ("NdisRegisterProtocol failed, status 0x%x\n", NdisStatus));
1056 return (NTSTATUS)NdisStatus;
1057 }
1058
1059 ProtocolRegistered = TRUE;
1060
1061 return STATUS_SUCCESS;
1062 }
1063
1064
1065 VOID LANUnregisterProtocol(
1066 VOID)
1067 /*
1068 * FUNCTION: Unregisters this protocol driver with NDIS
1069 * NOTES: Does not care wether we are already registered
1070 */
1071 {
1072 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
1073
1074 if (ProtocolRegistered) {
1075 NDIS_STATUS NdisStatus;
1076 PLIST_ENTRY CurrentEntry;
1077 PLIST_ENTRY NextEntry;
1078 PLAN_ADAPTER Current;
1079 KIRQL OldIrql;
1080
1081 KeAcquireSpinLock(&AdapterListLock, &OldIrql);
1082
1083 /* Search the list and remove every adapter we find */
1084 CurrentEntry = AdapterListHead.Flink;
1085 while (CurrentEntry != &AdapterListHead) {
1086 NextEntry = CurrentEntry->Flink;
1087 Current = CONTAINING_RECORD(CurrentEntry, LAN_ADAPTER, ListEntry);
1088 /* Unregister it */
1089 LANUnregisterAdapter(Current);
1090 CurrentEntry = NextEntry;
1091 }
1092
1093 KeReleaseSpinLock(&AdapterListLock, OldIrql);
1094
1095 NdisDeregisterProtocol(&NdisStatus, NdisProtocolHandle);
1096 ProtocolRegistered = FALSE;
1097 }
1098 }
1099
1100 /* EOF */