:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[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
489 VOID LANTransmit(
490     PVOID Context,
491     PNDIS_PACKET NdisPacket,
492     UINT Offset,
493     PVOID LinkAddress,
494     USHORT Type)
495 /*
496  * FUNCTION: Transmits a packet
497  * ARGUMENTS:
498  *     Context     = Pointer to context information (LAN_ADAPTER)
499  *     NdisPacket  = Pointer to NDIS packet to send
500  *     Offset      = Offset in packet where data starts
501  *     LinkAddress = Pointer to link address of destination (NULL = broadcast)
502  *     Type        = LAN protocol type (LAN_PROTO_*)
503  */
504 {
505     NDIS_STATUS NdisStatus;
506     PETH_HEADER EHeader;
507     PVOID Data;
508     PLAN_ADAPTER Adapter = (PLAN_ADAPTER)Context;
509
510     TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
511
512     /* NDIS send routines don't have an offset argument so we
513        must offset the data in upper layers and adjust the
514        packet here. We save the offset in the packet context
515        area so it can be undone before we release the packet */
516     Data = AdjustPacket(NdisPacket, Offset, Adapter->HeaderSize);
517     PC(NdisPacket)->DLOffset = Offset;
518
519     if (Adapter->State == LAN_STATE_STARTED) {
520         switch (Adapter->Media) {
521         case NdisMedium802_3:
522             EHeader = (PETH_HEADER)Data;
523
524             if (LinkAddress) {
525                 /* Unicast address */
526                 RtlCopyMemory(EHeader->DstAddr, LinkAddress, IEEE_802_ADDR_LENGTH);
527             } else {
528                 /* Broadcast address */
529                 RtlFillMemory(EHeader->DstAddr, IEEE_802_ADDR_LENGTH, 0xFF);
530             }
531
532             RtlCopyMemory(EHeader->SrcAddr, Adapter->HWAddress, IEEE_802_ADDR_LENGTH);
533
534             switch (Type) {
535                 case LAN_PROTO_IPv4:
536                     EHeader->EType = ETYPE_IPv4;
537                     break;
538                 case LAN_PROTO_ARP:
539                     EHeader->EType = ETYPE_ARP;
540                     break;
541                 case LAN_PROTO_IPv6:
542                     EHeader->EType = ETYPE_IPv6;
543                     break;
544                 default:
545 #ifdef DBG
546                     /* Should not happen */
547                     TI_DbgPrint(MIN_TRACE, ("Unknown LAN protocol.\n"));
548
549                     ProtocolSendComplete((NDIS_HANDLE)Context,
550                                          NdisPacket,
551                                          NDIS_STATUS_FAILURE);
552 #endif
553                     return;
554             }
555             break;
556
557         default:
558             /* FIXME: Support other medias */
559             break;
560         }
561
562         NdisSend(&NdisStatus, Adapter->NdisHandle, NdisPacket);
563         if (NdisStatus != NDIS_STATUS_PENDING)
564             ProtocolSendComplete((NDIS_HANDLE)Context, NdisPacket, NdisStatus);
565     } else {
566         ProtocolSendComplete((NDIS_HANDLE)Context, NdisPacket, NDIS_STATUS_CLOSED);
567     }
568 }
569
570
571 VOID BindAdapter(
572     PLAN_ADAPTER Adapter)
573 /*
574  * FUNCTION: Binds a LAN adapter to IP layer
575  * ARGUMENTS:
576  *     Adapter = Pointer to LAN_ADAPTER structure
577  * NOTES:
578  *    We set the lookahead buffer size, set the packet filter and
579  *    bind the adapter to IP layer
580  */
581 {
582     INT i;
583     PIP_INTERFACE IF;
584     PIP_ADDRESS Address;
585     PNDIS_PACKET Packet;
586     NDIS_STATUS NdisStatus;
587     LLIP_BIND_INFO BindInfo;
588     ULONG Lookahead = LOOKAHEAD_SIZE;
589
590     TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
591
592     Adapter->State = LAN_STATE_OPENING;
593
594     NdisStatus = NDISCall(Adapter,
595                           NdisRequestSetInformation,
596                           OID_GEN_CURRENT_LOOKAHEAD,
597                           &Lookahead,
598                           sizeof(ULONG));
599     if (NdisStatus != NDIS_STATUS_SUCCESS) {
600         TI_DbgPrint(MID_TRACE, ("Could not set lookahead buffer size (0x%X).\n", NdisStatus));
601         return;
602     }
603
604     /* Allocate packets for NdisTransferData */
605     /* FIXME: How many should we allocate? */
606     Adapter->TDPackets = NULL;
607     for (i = 0; i < 2; i++) {
608         Packet              = AllocateTDPacket(Adapter);
609         PC(Packet)->Context = Adapter->TDPackets;
610         Adapter->TDPackets  = Packet;
611         if (!Packet) {
612             TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
613             FreeTDPackets(Adapter);
614             return;
615         }
616     }
617
618     /* Bind the adapter to IP layer */
619     BindInfo.Context       = Adapter;
620     BindInfo.HeaderSize    = Adapter->HeaderSize;
621     BindInfo.MinFrameSize  = Adapter->MinFrameSize;
622     BindInfo.MTU           = Adapter->MTU;
623     BindInfo.Address       = (PUCHAR)&Adapter->HWAddress;
624     BindInfo.AddressLength = Adapter->HWAddressLength;
625     BindInfo.Transmit      = LANTransmit;
626
627     IF = IPCreateInterface(&BindInfo);
628     if (!IF) {
629         TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
630         FreeTDPackets(Adapter);
631         return;
632     }
633
634     /* FIXME: Get address from registry.
635        For now just use a private address, eg. 10.0.0.100 */
636     Address = AddrBuildIPv4(0x6400000A);
637     if (!Address) {
638         TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
639         FreeTDPackets(Adapter);
640         IPDestroyInterface(Adapter->Context);
641         return;
642     }
643     /* Create a net table entry for this interface */
644     if (!IPCreateNTE(IF, Address, 8)) {
645         TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
646         FreeTDPackets(Adapter);
647         IPDestroyInterface(IF);
648         return;
649     }
650
651     /* Reference the interface for the NTE. The reference
652        for the address is just passed on to the NTE */
653     ReferenceObject(IF);
654
655     /* Register interface with IP layer */
656     IPRegisterInterface(IF);
657
658     /* Set packet filter so we can send and receive packets */
659     NdisStatus = NDISCall(Adapter,
660                           NdisRequestSetInformation,
661                           OID_GEN_CURRENT_PACKET_FILTER,
662                           &Adapter->PacketFilter,
663                           sizeof(UINT));
664     if (NdisStatus != NDIS_STATUS_SUCCESS) {
665         TI_DbgPrint(MID_TRACE, ("Could not set packet filter (0x%X).\n", NdisStatus));
666         FreeTDPackets(Adapter);
667         IPDestroyInterface(IF);
668         return;
669     }
670
671     Adapter->Context = IF;
672
673     Adapter->State = LAN_STATE_STARTED;
674 }
675
676
677 VOID UnbindAdapter(
678     PLAN_ADAPTER Adapter)
679 /*
680  * FUNCTION: Unbinds a LAN adapter from IP layer
681  * ARGUMENTS:
682  *     Adapter = Pointer to LAN_ADAPTER structure
683  */
684 {
685     TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
686
687     if (Adapter->State == LAN_STATE_STARTED) {
688         PIP_INTERFACE IF = Adapter->Context;
689
690         IPUnregisterInterface(IF);
691
692         IPDestroyInterface(IF);
693
694         /* Free transfer data packets */
695         FreeTDPackets(Adapter);
696     }
697 }
698
699
700 NDIS_STATUS LANRegisterAdapter(
701     PNDIS_STRING AdapterName,
702     PLAN_ADAPTER *Adapter)
703 /*
704  * FUNCTION: Registers protocol with an NDIS adapter
705  * ARGUMENTS:
706  *     AdapterName = Pointer to string with name of adapter to register
707  *     Adapter     = Address of pointer to a LAN_ADAPTER structure
708  * RETURNS:
709  *     Status of operation
710  */
711 {
712     PLAN_ADAPTER IF;
713     NDIS_STATUS NdisStatus;
714     NDIS_STATUS OpenStatus;
715     UINT MediaIndex;
716     NDIS_MEDIUM MediaArray[MAX_MEDIA];
717     UINT AddressOID;
718     UINT Speed;
719
720     TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
721
722     IF = ExAllocatePool(NonPagedPool, sizeof(LAN_ADAPTER));
723     if (!IF) {
724         TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
725         return NDIS_STATUS_RESOURCES;
726     }
727
728     RtlZeroMemory(IF, sizeof(LAN_ADAPTER));
729
730     /* Put adapter in stopped state */
731     IF->State = LAN_STATE_STOPPED;
732
733     /* Initialize protecting spin lock */
734     KeInitializeSpinLock(&IF->Lock);
735
736     KeInitializeEvent(&IF->Event, SynchronizationEvent, FALSE);
737
738     /* Initialize array with media IDs we support */
739     MediaArray[MEDIA_ETH] = NdisMedium802_3;
740
741     /* Open the adapter. */
742     NdisOpenAdapter(&NdisStatus,
743                     &OpenStatus,
744                     &IF->NdisHandle,
745                     &MediaIndex,
746                     MediaArray,
747                     MAX_MEDIA,
748                     NdisProtocolHandle,
749                     IF,
750                     AdapterName,
751                     0,
752                     NULL);
753
754     /* Wait until the adapter is opened */
755     if (NdisStatus == NDIS_STATUS_PENDING)
756         KeWaitForSingleObject(&IF->Event, UserRequest, KernelMode, FALSE, NULL);
757     else if (NdisStatus != NDIS_STATUS_SUCCESS) {
758         ExFreePool(IF);
759         return NdisStatus;
760     }
761
762     IF->Media = MediaArray[MediaIndex];
763
764     /* Fill LAN_ADAPTER structure with some adapter specific information */
765     switch (IF->Media) {
766     case NdisMedium802_3:
767         IF->HWAddressLength = IEEE_802_ADDR_LENGTH;
768         IF->BCastMask       = BCAST_ETH_MASK;
769         IF->BCastCheck      = BCAST_ETH_CHECK;
770         IF->BCastOffset     = BCAST_ETH_OFFSET;
771         IF->HeaderSize      = sizeof(ETH_HEADER);
772         IF->MinFrameSize    = 60;
773         AddressOID          = OID_802_3_CURRENT_ADDRESS;
774         IF->PacketFilter    = 
775             NDIS_PACKET_TYPE_BROADCAST |
776             NDIS_PACKET_TYPE_DIRECTED  |
777             NDIS_PACKET_TYPE_MULTICAST;
778         break;
779
780     default:
781         /* Unsupported media */
782         TI_DbgPrint(MIN_TRACE, ("Unsupported media.\n"));
783         ExFreePool(IF);
784         return NDIS_STATUS_NOT_SUPPORTED;
785     }
786
787     /* Get maximum frame size */
788     NdisStatus = NDISCall(IF,
789                           NdisRequestQueryInformation,
790                           OID_GEN_MAXIMUM_FRAME_SIZE,
791                           &IF->MTU,
792                           sizeof(UINT));
793     if (NdisStatus != NDIS_STATUS_SUCCESS) {
794         ExFreePool(IF);
795         return NdisStatus;
796     }
797
798     /* Get maximum packet size */
799     NdisStatus = NDISCall(IF,
800                           NdisRequestQueryInformation,
801                           OID_GEN_MAXIMUM_TOTAL_SIZE,
802                           &IF->MaxPacketSize,
803                           sizeof(UINT));
804     if (NdisStatus != NDIS_STATUS_SUCCESS) {
805         TI_DbgPrint(MIN_TRACE, ("Query for maximum packet size failed.\n"));
806         ExFreePool(IF);
807         return NdisStatus;
808     }
809
810     /* Get maximum number of packets we can pass to NdisSend(Packets) at one time */
811     NdisStatus = NDISCall(IF,
812                           NdisRequestQueryInformation,
813                           OID_GEN_MAXIMUM_SEND_PACKETS,
814                           &IF->MaxSendPackets,
815                           sizeof(UINT));
816     if (NdisStatus != NDIS_STATUS_SUCCESS)
817         /* Legacy NIC drivers may not support this query, if it fails we
818            assume it can send at least one packet per call to NdisSend(Packets) */
819         IF->MaxSendPackets = 1;
820
821     /* Get current hardware address */
822     NdisStatus = NDISCall(IF,
823                           NdisRequestQueryInformation,
824                           AddressOID,
825                           &IF->HWAddress,
826                           IF->HWAddressLength);
827     if (NdisStatus != NDIS_STATUS_SUCCESS) {
828         TI_DbgPrint(MIN_TRACE, ("Query for current hardware address failed.\n"));
829         ExFreePool(IF);
830         return NdisStatus;
831     }
832
833     /* Get maximum link speed */
834     NdisStatus = NDISCall(IF,
835                           NdisRequestQueryInformation,
836                           OID_GEN_LINK_SPEED,
837                           &Speed,
838                           sizeof(UINT));
839     if (NdisStatus != NDIS_STATUS_SUCCESS) {
840         TI_DbgPrint(MIN_TRACE, ("Query for maximum link speed failed.\n"));
841         ExFreePool(IF);
842         return NdisStatus;
843     }
844
845     /* Convert returned link speed to bps (it is in 100bps increments) */
846     IF->Speed = Speed * 100L;
847
848     *Adapter = IF;
849
850     /* Add adapter to the adapter list */
851     ExInterlockedInsertTailList(&AdapterListHead,
852                                 &IF->ListEntry,
853                                 &AdapterListLock);
854
855     /* Bind adapter to IP layer */
856     BindAdapter(IF);
857
858     TI_DbgPrint(DEBUG_DATALINK, ("Leaving.\n"));
859
860     return NDIS_STATUS_SUCCESS;
861 }
862
863
864 NDIS_STATUS LANUnregisterAdapter(
865     PLAN_ADAPTER Adapter)
866 /*
867  * FUNCTION: Unregisters protocol with NDIS adapter
868  * ARGUMENTS:
869  *     Adapter = Pointer to a LAN_ADAPTER structure
870  * RETURNS:
871  *     Status of operation
872  */
873 {
874     KIRQL OldIrql;
875     NDIS_HANDLE NdisHandle;
876     NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS;
877
878     TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
879
880     /* Unlink the adapter from the list */
881     RemoveEntryList(&Adapter->ListEntry);
882
883     /* Unbind adapter from IP layer */
884     UnbindAdapter(Adapter);
885
886     KeAcquireSpinLock(&Adapter->Lock, &OldIrql);
887     NdisHandle = Adapter->NdisHandle;
888     if (NdisHandle) {
889         Adapter->NdisHandle = NULL;
890         KeReleaseSpinLock(&Adapter->Lock, OldIrql);
891
892         NdisCloseAdapter(&NdisStatus, NdisHandle);
893         if (NdisStatus == NDIS_STATUS_PENDING) {
894             KeWaitForSingleObject(&Adapter->Event,
895                                   UserRequest,
896                                   KernelMode,
897                                   FALSE,
898                                   NULL);
899             NdisStatus = Adapter->NdisStatus;
900         }
901     } else
902         KeReleaseSpinLock(&Adapter->Lock, OldIrql);
903
904     FreeAdapter(Adapter);
905
906     return NDIS_STATUS_SUCCESS;
907 }
908
909
910 NTSTATUS LANRegisterProtocol(
911     PSTRING Name)
912 /*
913  * FUNCTION: Registers this protocol driver with NDIS
914  * ARGUMENTS:
915  *     Name = Name of this protocol driver
916  * RETURNS:
917  *     Status of operation
918  */
919 {
920     NDIS_STATUS NdisStatus;
921     NDIS_PROTOCOL_CHARACTERISTICS ProtChars;
922
923     TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
924
925     InitializeListHead(&AdapterListHead);
926     KeInitializeSpinLock(&AdapterListLock);
927
928     /* Set up protocol characteristics */
929     RtlZeroMemory(&ProtChars, sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
930     ProtChars.MajorNdisVersion               = NDIS_VERSION_MAJOR;
931     ProtChars.MinorNdisVersion               = NDIS_VERSION_MINOR;
932     ProtChars.Name.Length                    = Name->Length;
933     ProtChars.Name.Buffer                    = (PVOID)Name->Buffer;
934     ProtChars.OpenAdapterCompleteHandler     = ProtocolOpenAdapterComplete;
935     ProtChars.CloseAdapterCompleteHandler    = ProtocolCloseAdapterComplete;
936     ProtChars.ResetCompleteHandler           = ProtocolResetComplete;
937     ProtChars.RequestCompleteHandler         = ProtocolRequestComplete;
938     ProtChars.u2.SendCompleteHandler         = ProtocolSendComplete;
939     ProtChars.u3.TransferDataCompleteHandler = ProtocolTransferDataComplete;
940     ProtChars.u4.ReceiveHandler              = ProtocolReceive;
941     ProtChars.ReceiveCompleteHandler         = ProtocolReceiveComplete;
942     ProtChars.StatusHandler                  = ProtocolStatus;
943     ProtChars.StatusCompleteHandler          = ProtocolStatusComplete;
944
945         /* Try to register protocol */
946     NdisRegisterProtocol(&NdisStatus,
947                          &NdisProtocolHandle,
948                          &ProtChars,
949                          sizeof(NDIS_PROTOCOL_CHARACTERISTICS) + Name->Length);
950     if (NdisStatus != NDIS_STATUS_SUCCESS)
951         return (NTSTATUS)NdisStatus;
952
953     ProtocolRegistered = TRUE;
954
955     return STATUS_SUCCESS;
956 }
957
958
959 VOID LANUnregisterProtocol(
960     VOID)
961 /*
962  * FUNCTION: Unregisters this protocol driver with NDIS
963  * NOTES: Does not care wether we are already registered
964  */
965 {
966     TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
967
968     if (ProtocolRegistered) {
969         NDIS_STATUS NdisStatus;
970         PLIST_ENTRY CurrentEntry;
971         PLIST_ENTRY NextEntry;
972         PLAN_ADAPTER Current;
973         KIRQL OldIrql;
974
975         KeAcquireSpinLock(&AdapterListLock, &OldIrql);
976
977         /* Search the list and remove every adapter we find */
978         CurrentEntry = AdapterListHead.Flink;
979         while (CurrentEntry != &AdapterListHead) {
980             NextEntry = CurrentEntry->Flink;
981                 Current = CONTAINING_RECORD(CurrentEntry, LAN_ADAPTER, ListEntry);
982             /* Unregister it */
983             LANUnregisterAdapter(Current);
984             CurrentEntry = NextEntry;
985         }
986
987         KeReleaseSpinLock(&AdapterListLock, OldIrql);
988
989         NdisDeregisterProtocol(&NdisStatus, NdisProtocolHandle);
990         ProtocolRegistered = FALSE;
991     }
992 }
993
994 /* EOF */