net: Move ARP out of net.c
[kernel/u-boot.git] / net / arp.c
1 /*
2  *      Copied from Linux Monitor (LiMon) - Networking.
3  *
4  *      Copyright 1994 - 2000 Neil Russell.
5  *      (See License)
6  *      Copyright 2000 Roland Borde
7  *      Copyright 2000 Paolo Scaffardi
8  *      Copyright 2000-2002 Wolfgang Denk, wd@denx.de
9  */
10
11 #include <common.h>
12
13 #include "arp.h"
14
15 #ifndef CONFIG_ARP_TIMEOUT
16 /* Milliseconds before trying ARP again */
17 # define ARP_TIMEOUT            5000UL
18 #else
19 # define ARP_TIMEOUT            CONFIG_ARP_TIMEOUT
20 #endif
21
22
23 #ifndef CONFIG_NET_RETRY_COUNT
24 # define ARP_TIMEOUT_COUNT      5       /* # of timeouts before giving up  */
25 #else
26 # define ARP_TIMEOUT_COUNT      CONFIG_NET_RETRY_COUNT
27 #endif
28
29 IPaddr_t        NetArpWaitPacketIP;
30 IPaddr_t        NetArpWaitReplyIP;
31 /* MAC address of waiting packet's destination */
32 uchar          *NetArpWaitPacketMAC;
33 /* THE transmit packet */
34 uchar          *NetArpWaitTxPacket;
35 int             NetArpWaitTxPacketSize;
36 uchar           NetArpWaitPacketBuf[PKTSIZE_ALIGN + PKTALIGN];
37 ulong           NetArpWaitTimerStart;
38 int             NetArpWaitTry;
39
40 void ArpInit(void)
41 {
42         /* XXX problem with bss workaround */
43         NetArpWaitPacketMAC = NULL;
44         NetArpWaitPacketIP = 0;
45         NetArpWaitReplyIP = 0;
46         NetArpWaitTxPacket = &NetArpWaitPacketBuf[0] + (PKTALIGN - 1);
47         NetArpWaitTxPacket -= (ulong)NetArpWaitTxPacket % PKTALIGN;
48         NetArpWaitTxPacketSize = 0;
49 }
50
51 void ArpRequest(void)
52 {
53         uchar *pkt;
54         ARP_t *arp;
55
56         debug("ARP broadcast %d\n", NetArpWaitTry);
57
58         pkt = NetTxPacket;
59
60         pkt += NetSetEther(pkt, NetBcastAddr, PROT_ARP);
61
62         arp = (ARP_t *) pkt;
63
64         arp->ar_hrd = htons(ARP_ETHER);
65         arp->ar_pro = htons(PROT_IP);
66         arp->ar_hln = 6;
67         arp->ar_pln = 4;
68         arp->ar_op = htons(ARPOP_REQUEST);
69
70         /* source ET addr */
71         memcpy(&arp->ar_data[0], NetOurEther, 6);
72         /* source IP addr */
73         NetWriteIP((uchar *) &arp->ar_data[6], NetOurIP);
74         /* dest ET addr = 0 */
75         memset(&arp->ar_data[10], '\0', 6);
76         if ((NetArpWaitPacketIP & NetOurSubnetMask) !=
77             (NetOurIP & NetOurSubnetMask)) {
78                 if (NetOurGatewayIP == 0) {
79                         puts("## Warning: gatewayip needed but not set\n");
80                         NetArpWaitReplyIP = NetArpWaitPacketIP;
81                 } else {
82                         NetArpWaitReplyIP = NetOurGatewayIP;
83                 }
84         } else {
85                 NetArpWaitReplyIP = NetArpWaitPacketIP;
86         }
87
88         NetWriteIP((uchar *) &arp->ar_data[16], NetArpWaitReplyIP);
89         (void) eth_send(NetTxPacket, (pkt - NetTxPacket) + ARP_HDR_SIZE);
90 }
91
92 void ArpTimeoutCheck(void)
93 {
94         ulong t;
95
96         if (!NetArpWaitPacketIP)
97                 return;
98
99         t = get_timer(0);
100
101         /* check for arp timeout */
102         if ((t - NetArpWaitTimerStart) > ARP_TIMEOUT) {
103                 NetArpWaitTry++;
104
105                 if (NetArpWaitTry >= ARP_TIMEOUT_COUNT) {
106                         puts("\nARP Retry count exceeded; starting again\n");
107                         NetArpWaitTry = 0;
108                         NetStartAgain();
109                 } else {
110                         NetArpWaitTimerStart = t;
111                         ArpRequest();
112                 }
113         }
114 }
115
116 void ArpReceive(Ethernet_t *et, IP_t *ip, int len)
117 {
118         ARP_t *arp;
119         IPaddr_t tmp;
120         uchar *pkt;
121
122         /*
123          * We have to deal with two types of ARP packets:
124          * - REQUEST packets will be answered by sending  our
125          *   IP address - if we know it.
126          * - REPLY packates are expected only after we asked
127          *   for the TFTP server's or the gateway's ethernet
128          *   address; so if we receive such a packet, we set
129          *   the server ethernet address
130          */
131         debug("Got ARP\n");
132
133         arp = (ARP_t *)ip;
134         if (len < ARP_HDR_SIZE) {
135                 printf("bad length %d < %d\n", len, ARP_HDR_SIZE);
136                 return;
137         }
138         if (ntohs(arp->ar_hrd) != ARP_ETHER)
139                 return;
140         if (ntohs(arp->ar_pro) != PROT_IP)
141                 return;
142         if (arp->ar_hln != 6)
143                 return;
144         if (arp->ar_pln != 4)
145                 return;
146
147         if (NetOurIP == 0)
148                 return;
149
150         if (NetReadIP(&arp->ar_data[16]) != NetOurIP)
151                 return;
152
153         switch (ntohs(arp->ar_op)) {
154         case ARPOP_REQUEST:
155                 /* reply with our IP address */
156                 debug("Got ARP REQUEST, return our IP\n");
157                 pkt = (uchar *)et;
158                 pkt += NetSetEther(pkt, et->et_src, PROT_ARP);
159                 arp->ar_op = htons(ARPOP_REPLY);
160                 memcpy(&arp->ar_data[10], &arp->ar_data[0], 6);
161                 NetCopyIP(&arp->ar_data[16], &arp->ar_data[6]);
162                 memcpy(&arp->ar_data[0], NetOurEther, 6);
163                 NetCopyIP(&arp->ar_data[6], &NetOurIP);
164                 (void) eth_send((uchar *)et,
165                                 (pkt - (uchar *)et) + ARP_HDR_SIZE);
166                 return;
167
168         case ARPOP_REPLY:               /* arp reply */
169                 /* are we waiting for a reply */
170                 if (!NetArpWaitPacketIP || !NetArpWaitPacketMAC)
171                         break;
172
173 #ifdef CONFIG_KEEP_SERVERADDR
174                 if (NetServerIP == NetArpWaitPacketIP) {
175                         char buf[20];
176                         sprintf(buf, "%pM", arp->ar_data);
177                         setenv("serveraddr", buf);
178                 }
179 #endif
180
181                 tmp = NetReadIP(&arp->ar_data[6]);
182
183                 /* matched waiting packet's address */
184                 if (tmp == NetArpWaitReplyIP) {
185                         debug("Got ARP REPLY, set eth addr (%pM)\n",
186                                 arp->ar_data);
187
188                         /* save address for later use */
189                         memcpy(NetArpWaitPacketMAC,
190                                &arp->ar_data[0], 6);
191
192 #ifdef CONFIG_NETCONSOLE
193                         NetGetHandler()(0, 0, 0, 0, 0);
194 #endif
195                         /* modify header, and transmit it */
196                         memcpy(((Ethernet_t *)NetArpWaitTxPacket)->
197                                 et_dest, NetArpWaitPacketMAC, 6);
198                         (void) eth_send(NetArpWaitTxPacket,
199                                         NetArpWaitTxPacketSize);
200
201                         /* no arp request pending now */
202                         NetArpWaitPacketIP = 0;
203                         NetArpWaitTxPacketSize = 0;
204                         NetArpWaitPacketMAC = NULL;
205
206                 }
207                 return;
208         default:
209                 debug("Unexpected ARP opcode 0x%x\n",
210                       ntohs(arp->ar_op));
211                 return;
212         }
213 }