update for HEAD-2003091401
[reactos.git] / 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         TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
507         *Status = LANRegisterAdapter(DeviceName);
508 }
509
510
511 VOID LANTransmit(
512     PVOID Context,
513     PNDIS_PACKET NdisPacket,
514     UINT Offset,
515     PVOID LinkAddress,
516     USHORT Type)
517 /*
518  * FUNCTION: Transmits a packet
519  * ARGUMENTS:
520  *     Context     = Pointer to context information (LAN_ADAPTER)
521  *     NdisPacket  = Pointer to NDIS packet to send
522  *     Offset      = Offset in packet where data starts
523  *     LinkAddress = Pointer to link address of destination (NULL = broadcast)
524  *     Type        = LAN protocol type (LAN_PROTO_*)
525  */
526 {
527     NDIS_STATUS NdisStatus;
528     PETH_HEADER EHeader;
529     PVOID Data;
530     PLAN_ADAPTER Adapter = (PLAN_ADAPTER)Context;
531
532     TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
533
534     /* NDIS send routines don't have an offset argument so we
535        must offset the data in upper layers and adjust the
536        packet here. We save the offset in the packet context
537        area so it can be undone before we release the packet */
538     Data = AdjustPacket(NdisPacket, Offset, Adapter->HeaderSize);
539     PC(NdisPacket)->DLOffset = Offset;
540
541     if (Adapter->State == LAN_STATE_STARTED) {
542         switch (Adapter->Media) {
543         case NdisMedium802_3:
544             EHeader = (PETH_HEADER)Data;
545
546             if (LinkAddress) {
547                 /* Unicast address */
548                 RtlCopyMemory(EHeader->DstAddr, LinkAddress, IEEE_802_ADDR_LENGTH);
549             } else {
550                 /* Broadcast address */
551                 RtlFillMemory(EHeader->DstAddr, IEEE_802_ADDR_LENGTH, 0xFF);
552             }
553
554             RtlCopyMemory(EHeader->SrcAddr, Adapter->HWAddress, IEEE_802_ADDR_LENGTH);
555
556             switch (Type) {
557                 case LAN_PROTO_IPv4:
558                     EHeader->EType = ETYPE_IPv4;
559                     break;
560                 case LAN_PROTO_ARP:
561                     EHeader->EType = ETYPE_ARP;
562                     break;
563                 case LAN_PROTO_IPv6:
564                     EHeader->EType = ETYPE_IPv6;
565                     break;
566                 default:
567 #ifdef DBG
568                     /* Should not happen */
569                     TI_DbgPrint(MIN_TRACE, ("Unknown LAN protocol.\n"));
570
571                     ProtocolSendComplete((NDIS_HANDLE)Context,
572                                          NdisPacket,
573                                          NDIS_STATUS_FAILURE);
574 #endif
575                     return;
576             }
577             break;
578
579         default:
580             /* FIXME: Support other medias */
581             break;
582         }
583
584         NdisSend(&NdisStatus, Adapter->NdisHandle, NdisPacket);
585         if (NdisStatus != NDIS_STATUS_PENDING)
586             ProtocolSendComplete((NDIS_HANDLE)Context, NdisPacket, NdisStatus);
587     } else {
588         ProtocolSendComplete((NDIS_HANDLE)Context, NdisPacket, NDIS_STATUS_CLOSED);
589     }
590 }
591
592
593 VOID BindAdapter(
594     PLAN_ADAPTER Adapter)
595 /*
596  * FUNCTION: Binds a LAN adapter to IP layer
597  * ARGUMENTS:
598  *     Adapter = Pointer to LAN_ADAPTER structure
599  * NOTES:
600  *    We set the lookahead buffer size, set the packet filter and
601  *    bind the adapter to IP layer
602  */
603 {
604     INT i;
605     PIP_INTERFACE IF;
606     PIP_ADDRESS Address;
607     PNDIS_PACKET Packet;
608     NDIS_STATUS NdisStatus;
609     LLIP_BIND_INFO BindInfo;
610     ULONG Lookahead = LOOKAHEAD_SIZE;
611
612     TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
613
614     Adapter->State = LAN_STATE_OPENING;
615
616     NdisStatus = NDISCall(Adapter,
617                           NdisRequestSetInformation,
618                           OID_GEN_CURRENT_LOOKAHEAD,
619                           &Lookahead,
620                           sizeof(ULONG));
621     if (NdisStatus != NDIS_STATUS_SUCCESS) {
622         TI_DbgPrint(MID_TRACE, ("Could not set lookahead buffer size (0x%X).\n", NdisStatus));
623         return;
624     }
625
626     /* Allocate packets for NdisTransferData */
627     /* FIXME: How many should we allocate? */
628     Adapter->TDPackets = NULL;
629     for (i = 0; i < 2; i++) {
630         Packet              = AllocateTDPacket(Adapter);
631         if (!Packet) {
632             TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
633             FreeTDPackets(Adapter);
634             return;
635         }
636         PC(Packet)->Context = Adapter->TDPackets;
637         Adapter->TDPackets  = Packet;
638     }
639
640     /* Bind the adapter to IP layer */
641     BindInfo.Context       = Adapter;
642     BindInfo.HeaderSize    = Adapter->HeaderSize;
643     BindInfo.MinFrameSize  = Adapter->MinFrameSize;
644     BindInfo.MTU           = Adapter->MTU;
645     BindInfo.Address       = (PUCHAR)&Adapter->HWAddress;
646     BindInfo.AddressLength = Adapter->HWAddressLength;
647     BindInfo.Transmit      = LANTransmit;
648
649     IF = IPCreateInterface(&BindInfo);
650     if (!IF) {
651         TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
652         FreeTDPackets(Adapter);
653         return;
654     }
655
656     /* FIXME: Get address from registry.
657        For now just use a private address, eg. 10.0.0.100 */
658     Address = AddrBuildIPv4(0x6400000A);
659  //   Address = AddrBuildIPv4(0x6048F2D1);      // 209.242.72.96
660     if (!Address) {
661         TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
662         FreeTDPackets(Adapter);
663         IPDestroyInterface(Adapter->Context);
664         return;
665     }
666     /* Create a net table entry for this interface */
667     if (!IPCreateNTE(IF, Address, 8)) {
668         TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
669         FreeTDPackets(Adapter);
670         IPDestroyInterface(IF);
671         return;
672     }
673
674     /* Reference the interface for the NTE. The reference
675        for the address is just passed on to the NTE */
676     ReferenceObject(IF);
677
678     /* Register interface with IP layer */
679     IPRegisterInterface(IF);
680
681     /* Set packet filter so we can send and receive packets */
682     NdisStatus = NDISCall(Adapter,
683                           NdisRequestSetInformation,
684                           OID_GEN_CURRENT_PACKET_FILTER,
685                           &Adapter->PacketFilter,
686                           sizeof(UINT));
687     if (NdisStatus != NDIS_STATUS_SUCCESS) {
688         TI_DbgPrint(MID_TRACE, ("Could not set packet filter (0x%X).\n", NdisStatus));
689         FreeTDPackets(Adapter);
690         IPDestroyInterface(IF);
691         return;
692     }
693
694     Adapter->Context = IF;
695
696     Adapter->State = LAN_STATE_STARTED;
697 }
698
699
700 VOID UnbindAdapter(
701     PLAN_ADAPTER Adapter)
702 /*
703  * FUNCTION: Unbinds a LAN adapter from IP layer
704  * ARGUMENTS:
705  *     Adapter = Pointer to LAN_ADAPTER structure
706  */
707 {
708     TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
709
710     if (Adapter->State == LAN_STATE_STARTED) {
711         PIP_INTERFACE IF = Adapter->Context;
712
713         IPUnregisterInterface(IF);
714
715         IPDestroyInterface(IF);
716
717         /* Free transfer data packets */
718         FreeTDPackets(Adapter);
719     }
720 }
721
722
723 NDIS_STATUS LANRegisterAdapter(
724     PNDIS_STRING AdapterName)
725 /*
726  * FUNCTION: Registers protocol with an NDIS adapter
727  * ARGUMENTS:
728  *     AdapterName = Pointer to string with name of adapter to register
729  *     Adapter     = Address of pointer to a LAN_ADAPTER structure
730  * RETURNS:
731  *     Status of operation
732  */
733 {
734     PLAN_ADAPTER IF;
735     NDIS_STATUS NdisStatus;
736     NDIS_STATUS OpenStatus;
737     UINT MediaIndex;
738     NDIS_MEDIUM MediaArray[MAX_MEDIA];
739     UINT AddressOID;
740     UINT Speed;
741
742     TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
743
744     IF = ExAllocatePool(NonPagedPool, sizeof(LAN_ADAPTER));
745     if (!IF) {
746         TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
747         return NDIS_STATUS_RESOURCES;
748     }
749
750     RtlZeroMemory(IF, sizeof(LAN_ADAPTER));
751
752     /* Put adapter in stopped state */
753     IF->State = LAN_STATE_STOPPED;
754
755     /* Initialize protecting spin lock */
756     KeInitializeSpinLock(&IF->Lock);
757
758     KeInitializeEvent(&IF->Event, SynchronizationEvent, FALSE);
759
760     /* Initialize array with media IDs we support */
761     MediaArray[MEDIA_ETH] = NdisMedium802_3;
762
763     TI_DbgPrint(DEBUG_DATALINK,("opening adapter %wZ\n", AdapterName));
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 */