ac23a8a127df62c3e70092de1c4d4205d0ee0d09
[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
503 */
504 {
505 /* we get to ignore BindContext because we will never pend an operation with NDIS */
506 DbgPrint(("tcpip!ProtocolBindAdapter called\n"));
507 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
508 *Status = LANRegisterAdapter(DeviceName);
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 /*
597 * FUNCTION: Binds a LAN adapter to IP layer
598 * ARGUMENTS:
599 * Adapter = Pointer to LAN_ADAPTER structure
600 * NOTES:
601 * We set the lookahead buffer size, set the packet filter and
602 * bind the adapter to IP layer
603 */
604 {
605 INT i;
606 PIP_INTERFACE IF;
607 PIP_ADDRESS Address;
608 PNDIS_PACKET Packet;
609 NDIS_STATUS NdisStatus;
610 LLIP_BIND_INFO BindInfo;
611 ULONG Lookahead = LOOKAHEAD_SIZE;
612
613 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
614
615 Adapter->State = LAN_STATE_OPENING;
616
617 NdisStatus = NDISCall(Adapter,
618 NdisRequestSetInformation,
619 OID_GEN_CURRENT_LOOKAHEAD,
620 &Lookahead,
621 sizeof(ULONG));
622 if (NdisStatus != NDIS_STATUS_SUCCESS) {
623 TI_DbgPrint(MID_TRACE, ("Could not set lookahead buffer size (0x%X).\n", NdisStatus));
624 return;
625 }
626
627 /* Allocate packets for NdisTransferData */
628 /* FIXME: How many should we allocate? */
629 Adapter->TDPackets = NULL;
630 for (i = 0; i < 2; i++) {
631 Packet = AllocateTDPacket(Adapter);
632 PC(Packet)->Context = Adapter->TDPackets;
633 Adapter->TDPackets = Packet;
634 if (!Packet) {
635 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
636 FreeTDPackets(Adapter);
637 return;
638 }
639 }
640
641 /* Bind the adapter to IP layer */
642 BindInfo.Context = Adapter;
643 BindInfo.HeaderSize = Adapter->HeaderSize;
644 BindInfo.MinFrameSize = Adapter->MinFrameSize;
645 BindInfo.MTU = Adapter->MTU;
646 BindInfo.Address = (PUCHAR)&Adapter->HWAddress;
647 BindInfo.AddressLength = Adapter->HWAddressLength;
648 BindInfo.Transmit = LANTransmit;
649
650 IF = IPCreateInterface(&BindInfo);
651 if (!IF) {
652 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
653 FreeTDPackets(Adapter);
654 return;
655 }
656
657 /* FIXME: Get address from registry.
658 For now just use a private address, eg. 10.0.0.100 */
659 Address = AddrBuildIPv4(0x6400000A);
660 // Address = AddrBuildIPv4(0x6048F2D1); // 209.242.72.96
661 if (!Address) {
662 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
663 FreeTDPackets(Adapter);
664 IPDestroyInterface(Adapter->Context);
665 return;
666 }
667 /* Create a net table entry for this interface */
668 if (!IPCreateNTE(IF, Address, 8)) {
669 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
670 FreeTDPackets(Adapter);
671 IPDestroyInterface(IF);
672 return;
673 }
674
675 /* Reference the interface for the NTE. The reference
676 for the address is just passed on to the NTE */
677 ReferenceObject(IF);
678
679 /* Register interface with IP layer */
680 IPRegisterInterface(IF);
681
682 /* Set packet filter so we can send and receive packets */
683 NdisStatus = NDISCall(Adapter,
684 NdisRequestSetInformation,
685 OID_GEN_CURRENT_PACKET_FILTER,
686 &Adapter->PacketFilter,
687 sizeof(UINT));
688 if (NdisStatus != NDIS_STATUS_SUCCESS) {
689 TI_DbgPrint(MID_TRACE, ("Could not set packet filter (0x%X).\n", NdisStatus));
690 FreeTDPackets(Adapter);
691 IPDestroyInterface(IF);
692 return;
693 }
694
695 Adapter->Context = IF;
696
697 Adapter->State = LAN_STATE_STARTED;
698 }
699
700
701 VOID UnbindAdapter(
702 PLAN_ADAPTER Adapter)
703 /*
704 * FUNCTION: Unbinds a LAN adapter from IP layer
705 * ARGUMENTS:
706 * Adapter = Pointer to LAN_ADAPTER structure
707 */
708 {
709 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
710
711 if (Adapter->State == LAN_STATE_STARTED) {
712 PIP_INTERFACE IF = Adapter->Context;
713
714 IPUnregisterInterface(IF);
715
716 IPDestroyInterface(IF);
717
718 /* Free transfer data packets */
719 FreeTDPackets(Adapter);
720 }
721 }
722
723
724 NDIS_STATUS LANRegisterAdapter(
725 PNDIS_STRING AdapterName)
726 /*
727 * FUNCTION: Registers protocol with an NDIS adapter
728 * ARGUMENTS:
729 * AdapterName = Pointer to string with name of adapter to register
730 * Adapter = Address of pointer to a LAN_ADAPTER structure
731 * RETURNS:
732 * Status of operation
733 */
734 {
735 PLAN_ADAPTER IF;
736 NDIS_STATUS NdisStatus;
737 NDIS_STATUS OpenStatus;
738 UINT MediaIndex;
739 NDIS_MEDIUM MediaArray[MAX_MEDIA];
740 UINT AddressOID;
741 UINT Speed;
742
743 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
744
745 IF = ExAllocatePool(NonPagedPool, sizeof(LAN_ADAPTER));
746 if (!IF) {
747 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
748 return NDIS_STATUS_RESOURCES;
749 }
750
751 RtlZeroMemory(IF, sizeof(LAN_ADAPTER));
752
753 /* Put adapter in stopped state */
754 IF->State = LAN_STATE_STOPPED;
755
756 /* Initialize protecting spin lock */
757 KeInitializeSpinLock(&IF->Lock);
758
759 KeInitializeEvent(&IF->Event, SynchronizationEvent, FALSE);
760
761 /* Initialize array with media IDs we support */
762 MediaArray[MEDIA_ETH] = NdisMedium802_3;
763
764 /* Open the adapter. */
765 NdisOpenAdapter(&NdisStatus,
766 &OpenStatus,
767 &IF->NdisHandle,
768 &MediaIndex,
769 MediaArray,
770 MAX_MEDIA,
771 NdisProtocolHandle,
772 IF,
773 AdapterName,
774 0,
775 NULL);
776
777 /* Wait until the adapter is opened */
778 if (NdisStatus == NDIS_STATUS_PENDING)
779 KeWaitForSingleObject(&IF->Event, UserRequest, KernelMode, FALSE, NULL);
780 else if (NdisStatus != NDIS_STATUS_SUCCESS) {
781 ExFreePool(IF);
782 return NdisStatus;
783 }
784
785 IF->Media = MediaArray[MediaIndex];
786
787 /* Fill LAN_ADAPTER structure with some adapter specific information */
788 switch (IF->Media) {
789 case NdisMedium802_3:
790 IF->HWAddressLength = IEEE_802_ADDR_LENGTH;
791 IF->BCastMask = BCAST_ETH_MASK;
792 IF->BCastCheck = BCAST_ETH_CHECK;
793 IF->BCastOffset = BCAST_ETH_OFFSET;
794 IF->HeaderSize = sizeof(ETH_HEADER);
795 IF->MinFrameSize = 60;
796 AddressOID = OID_802_3_CURRENT_ADDRESS;
797 IF->PacketFilter =
798 NDIS_PACKET_TYPE_BROADCAST |
799 NDIS_PACKET_TYPE_DIRECTED |
800 NDIS_PACKET_TYPE_MULTICAST;
801 break;
802
803 default:
804 /* Unsupported media */
805 TI_DbgPrint(MIN_TRACE, ("Unsupported media.\n"));
806 ExFreePool(IF);
807 return NDIS_STATUS_NOT_SUPPORTED;
808 }
809
810 /* Get maximum frame size */
811 NdisStatus = NDISCall(IF,
812 NdisRequestQueryInformation,
813 OID_GEN_MAXIMUM_FRAME_SIZE,
814 &IF->MTU,
815 sizeof(UINT));
816 if (NdisStatus != NDIS_STATUS_SUCCESS) {
817 ExFreePool(IF);
818 return NdisStatus;
819 }
820
821 /* Get maximum packet size */
822 NdisStatus = NDISCall(IF,
823 NdisRequestQueryInformation,
824 OID_GEN_MAXIMUM_TOTAL_SIZE,
825 &IF->MaxPacketSize,
826 sizeof(UINT));
827 if (NdisStatus != NDIS_STATUS_SUCCESS) {
828 TI_DbgPrint(MIN_TRACE, ("Query for maximum packet size failed.\n"));
829 ExFreePool(IF);
830 return NdisStatus;
831 }
832
833 /* Get maximum number of packets we can pass to NdisSend(Packets) at one time */
834 NdisStatus = NDISCall(IF,
835 NdisRequestQueryInformation,
836 OID_GEN_MAXIMUM_SEND_PACKETS,
837 &IF->MaxSendPackets,
838 sizeof(UINT));
839 if (NdisStatus != NDIS_STATUS_SUCCESS)
840 /* Legacy NIC drivers may not support this query, if it fails we
841 assume it can send at least one packet per call to NdisSend(Packets) */
842 IF->MaxSendPackets = 1;
843
844 /* Get current hardware address */
845 NdisStatus = NDISCall(IF,
846 NdisRequestQueryInformation,
847 AddressOID,
848 &IF->HWAddress,
849 IF->HWAddressLength);
850 if (NdisStatus != NDIS_STATUS_SUCCESS) {
851 TI_DbgPrint(MIN_TRACE, ("Query for current hardware address failed.\n"));
852 ExFreePool(IF);
853 return NdisStatus;
854 }
855
856 /* Get maximum link speed */
857 NdisStatus = NDISCall(IF,
858 NdisRequestQueryInformation,
859 OID_GEN_LINK_SPEED,
860 &Speed,
861 sizeof(UINT));
862 if (NdisStatus != NDIS_STATUS_SUCCESS) {
863 TI_DbgPrint(MIN_TRACE, ("Query for maximum link speed failed.\n"));
864 ExFreePool(IF);
865 return NdisStatus;
866 }
867
868 /* Convert returned link speed to bps (it is in 100bps increments) */
869 IF->Speed = Speed * 100L;
870
871 /* Add adapter to the adapter list */
872 ExInterlockedInsertTailList(&AdapterListHead,
873 &IF->ListEntry,
874 &AdapterListLock);
875
876 /* Bind adapter to IP layer */
877 BindAdapter(IF);
878
879 TI_DbgPrint(DEBUG_DATALINK, ("Leaving.\n"));
880
881 return NDIS_STATUS_SUCCESS;
882 }
883
884
885 NDIS_STATUS LANUnregisterAdapter(
886 PLAN_ADAPTER Adapter)
887 /*
888 * FUNCTION: Unregisters protocol with NDIS adapter
889 * ARGUMENTS:
890 * Adapter = Pointer to a LAN_ADAPTER structure
891 * RETURNS:
892 * Status of operation
893 */
894 {
895 KIRQL OldIrql;
896 NDIS_HANDLE NdisHandle;
897 NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS;
898
899 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
900
901 /* Unlink the adapter from the list */
902 RemoveEntryList(&Adapter->ListEntry);
903
904 /* Unbind adapter from IP layer */
905 UnbindAdapter(Adapter);
906
907 KeAcquireSpinLock(&Adapter->Lock, &OldIrql);
908 NdisHandle = Adapter->NdisHandle;
909 if (NdisHandle) {
910 Adapter->NdisHandle = NULL;
911 KeReleaseSpinLock(&Adapter->Lock, OldIrql);
912
913 NdisCloseAdapter(&NdisStatus, NdisHandle);
914 if (NdisStatus == NDIS_STATUS_PENDING) {
915 KeWaitForSingleObject(&Adapter->Event,
916 UserRequest,
917 KernelMode,
918 FALSE,
919 NULL);
920 NdisStatus = Adapter->NdisStatus;
921 }
922 } else
923 KeReleaseSpinLock(&Adapter->Lock, OldIrql);
924
925 FreeAdapter(Adapter);
926
927 return NDIS_STATUS_SUCCESS;
928 }
929
930
931 NTSTATUS LANRegisterProtocol(
932 PNDIS_STRING Name)
933 /*
934 * FUNCTION: Registers this protocol driver with NDIS
935 * ARGUMENTS:
936 * Name = Name of this protocol driver
937 * RETURNS:
938 * Status of operation
939 */
940 {
941 NDIS_STATUS NdisStatus;
942 NDIS_PROTOCOL_CHARACTERISTICS ProtChars;
943
944 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
945
946 InitializeListHead(&AdapterListHead);
947 KeInitializeSpinLock(&AdapterListLock);
948
949 /* Set up protocol characteristics */
950 RtlZeroMemory(&ProtChars, sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
951 ProtChars.MajorNdisVersion = NDIS_VERSION_MAJOR;
952 ProtChars.MinorNdisVersion = NDIS_VERSION_MINOR;
953 ProtChars.Name.Length = Name->Length;
954 ProtChars.Name.Buffer = Name->Buffer;
955 ProtChars.Name.MaximumLength = Name->MaximumLength;
956 ProtChars.OpenAdapterCompleteHandler = ProtocolOpenAdapterComplete;
957 ProtChars.CloseAdapterCompleteHandler = ProtocolCloseAdapterComplete;
958 ProtChars.ResetCompleteHandler = ProtocolResetComplete;
959 ProtChars.RequestCompleteHandler = ProtocolRequestComplete;
960 ProtChars.u2.SendCompleteHandler = ProtocolSendComplete;
961 ProtChars.u3.TransferDataCompleteHandler = ProtocolTransferDataComplete;
962 ProtChars.u4.ReceiveHandler = ProtocolReceive;
963 ProtChars.ReceiveCompleteHandler = ProtocolReceiveComplete;
964 ProtChars.StatusHandler = ProtocolStatus;
965 ProtChars.StatusCompleteHandler = ProtocolStatusComplete;
966 ProtChars.BindAdapterHandler = ProtocolBindAdapter;
967
968 /* Try to register protocol */
969 NdisRegisterProtocol(&NdisStatus,
970 &NdisProtocolHandle,
971 &ProtChars,
972 sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
973 if (NdisStatus != NDIS_STATUS_SUCCESS)
974 {
975 TI_DbgPrint(MID_TRACE, ("NdisRegisterProtocol failed, status 0x%x\n", NdisStatus));
976 return (NTSTATUS)NdisStatus;
977 }
978
979 ProtocolRegistered = TRUE;
980
981 return STATUS_SUCCESS;
982 }
983
984
985 VOID LANUnregisterProtocol(
986 VOID)
987 /*
988 * FUNCTION: Unregisters this protocol driver with NDIS
989 * NOTES: Does not care wether we are already registered
990 */
991 {
992 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
993
994 if (ProtocolRegistered) {
995 NDIS_STATUS NdisStatus;
996 PLIST_ENTRY CurrentEntry;
997 PLIST_ENTRY NextEntry;
998 PLAN_ADAPTER Current;
999 KIRQL OldIrql;
1000
1001 KeAcquireSpinLock(&AdapterListLock, &OldIrql);
1002
1003 /* Search the list and remove every adapter we find */
1004 CurrentEntry = AdapterListHead.Flink;
1005 while (CurrentEntry != &AdapterListHead) {
1006 NextEntry = CurrentEntry->Flink;
1007 Current = CONTAINING_RECORD(CurrentEntry, LAN_ADAPTER, ListEntry);
1008 /* Unregister it */
1009 LANUnregisterAdapter(Current);
1010 CurrentEntry = NextEntry;
1011 }
1012
1013 KeReleaseSpinLock(&AdapterListLock, OldIrql);
1014
1015 NdisDeregisterProtocol(&NdisStatus, NdisProtocolHandle);
1016 ProtocolRegistered = FALSE;
1017 }
1018 }
1019
1020 /* EOF */