blob: 8fc744d932c658cc7dec8eac86f5b9638cdc9fb2 [file] [log] [blame]
Tom Rini70df9d62018-05-07 17:02:21 -04001// SPDX-License-Identifier: GPL-2.0
Joe Hershbergeraae05082012-05-23 07:58:01 +00002/*
3 * Copied from Linux Monitor (LiMon) - Networking.
4 *
5 * Copyright 1994 - 2000 Neil Russell.
6 * (See License)
7 * Copyright 2000 Roland Borde
8 * Copyright 2000 Paolo Scaffardi
9 * Copyright 2000-2002 Wolfgang Denk, wd@denx.de
10 */
11
12#include <common.h>
Simon Glassed38aef2020-05-10 11:40:03 -060013#include <env.h>
Simon Glass274e0b02020-05-10 11:39:56 -060014#include <net.h>
Joe Hershbergeraae05082012-05-23 07:58:01 +000015
16#include "arp.h"
17
18#ifndef CONFIG_ARP_TIMEOUT
19/* Milliseconds before trying ARP again */
20# define ARP_TIMEOUT 5000UL
21#else
22# define ARP_TIMEOUT CONFIG_ARP_TIMEOUT
23#endif
24
25
26#ifndef CONFIG_NET_RETRY_COUNT
27# define ARP_TIMEOUT_COUNT 5 /* # of timeouts before giving up */
28#else
29# define ARP_TIMEOUT_COUNT CONFIG_NET_RETRY_COUNT
30#endif
31
Joe Hershberger5874dec2015-04-08 01:41:01 -050032struct in_addr net_arp_wait_packet_ip;
33static struct in_addr net_arp_wait_reply_ip;
Joe Hershbergeraae05082012-05-23 07:58:01 +000034/* MAC address of waiting packet's destination */
Joe Hershberger85ae7762015-04-08 01:41:08 -050035uchar *arp_wait_packet_ethaddr;
36int arp_wait_tx_packet_size;
37ulong arp_wait_timer_start;
38int arp_wait_try;
Joe Hershbergere79a5182018-09-26 16:49:02 -050039uchar *arp_tx_packet; /* THE ARP transmit packet */
Joe Hershberger85ae7762015-04-08 01:41:08 -050040static uchar arp_tx_packet_buf[PKTSIZE_ALIGN + PKTALIGN];
Joe Hershbergerde8205a2012-05-23 07:59:24 +000041
Joe Hershberger85ae7762015-04-08 01:41:08 -050042void arp_init(void)
Joe Hershbergeraae05082012-05-23 07:58:01 +000043{
44 /* XXX problem with bss workaround */
Joe Hershberger85ae7762015-04-08 01:41:08 -050045 arp_wait_packet_ethaddr = NULL;
Joe Hershberger5874dec2015-04-08 01:41:01 -050046 net_arp_wait_packet_ip.s_addr = 0;
47 net_arp_wait_reply_ip.s_addr = 0;
Joe Hershberger85ae7762015-04-08 01:41:08 -050048 arp_wait_tx_packet_size = 0;
49 arp_tx_packet = &arp_tx_packet_buf[0] + (PKTALIGN - 1);
50 arp_tx_packet -= (ulong)arp_tx_packet % PKTALIGN;
Joe Hershbergeraae05082012-05-23 07:58:01 +000051}
52
Joe Hershberger85ae7762015-04-08 01:41:08 -050053void arp_raw_request(struct in_addr source_ip, const uchar *target_ethaddr,
Joe Hershberger5874dec2015-04-08 01:41:01 -050054 struct in_addr target_ip)
Joe Hershbergeraae05082012-05-23 07:58:01 +000055{
56 uchar *pkt;
Joe Hershbergerde15d0932012-05-23 07:58:08 +000057 struct arp_hdr *arp;
Joe Hershbergerf7ea8052012-05-23 07:59:09 +000058 int eth_hdr_size;
Joe Hershbergeraae05082012-05-23 07:58:01 +000059
Joe Hershberger85ae7762015-04-08 01:41:08 -050060 debug_cond(DEBUG_DEV_PKT, "ARP broadcast %d\n", arp_wait_try);
Joe Hershbergeraae05082012-05-23 07:58:01 +000061
Joe Hershberger85ae7762015-04-08 01:41:08 -050062 pkt = arp_tx_packet;
Joe Hershbergeraae05082012-05-23 07:58:01 +000063
Joe Hershbergera8ca4f62015-04-08 01:41:05 -050064 eth_hdr_size = net_set_ether(pkt, net_bcast_ethaddr, PROT_ARP);
Joe Hershbergerf7ea8052012-05-23 07:59:09 +000065 pkt += eth_hdr_size;
Joe Hershbergeraae05082012-05-23 07:58:01 +000066
Joe Hershberger85ae7762015-04-08 01:41:08 -050067 arp = (struct arp_hdr *)pkt;
Joe Hershbergeraae05082012-05-23 07:58:01 +000068
69 arp->ar_hrd = htons(ARP_ETHER);
70 arp->ar_pro = htons(PROT_IP);
Joe Hershberger2f787492012-05-23 07:58:17 +000071 arp->ar_hln = ARP_HLEN;
72 arp->ar_pln = ARP_PLEN;
Joe Hershbergeraae05082012-05-23 07:58:01 +000073 arp->ar_op = htons(ARPOP_REQUEST);
74
Joe Hershberger8ecdbed2015-04-08 01:41:04 -050075 memcpy(&arp->ar_sha, net_ethaddr, ARP_HLEN); /* source ET addr */
Joe Hershberger5874dec2015-04-08 01:41:01 -050076 net_write_ip(&arp->ar_spa, source_ip); /* source IP addr */
Joe Hershberger85ae7762015-04-08 01:41:08 -050077 memcpy(&arp->ar_tha, target_ethaddr, ARP_HLEN); /* target ET addr */
Joe Hershberger5874dec2015-04-08 01:41:01 -050078 net_write_ip(&arp->ar_tpa, target_ip); /* target IP addr */
Joe Hershbergerc07e8102012-05-23 08:00:11 +000079
Joe Hershberger85ae7762015-04-08 01:41:08 -050080 net_send_packet(arp_tx_packet, eth_hdr_size + ARP_HDR_SIZE);
Joe Hershbergerc07e8102012-05-23 08:00:11 +000081}
82
Joe Hershberger85ae7762015-04-08 01:41:08 -050083void arp_request(void)
Joe Hershbergerc07e8102012-05-23 08:00:11 +000084{
Joe Hershberger5874dec2015-04-08 01:41:01 -050085 if ((net_arp_wait_packet_ip.s_addr & net_netmask.s_addr) !=
86 (net_ip.s_addr & net_netmask.s_addr)) {
87 if (net_gateway.s_addr == 0) {
Joe Hershbergeraae05082012-05-23 07:58:01 +000088 puts("## Warning: gatewayip needed but not set\n");
Joe Hershberger5874dec2015-04-08 01:41:01 -050089 net_arp_wait_reply_ip = net_arp_wait_packet_ip;
Joe Hershbergeraae05082012-05-23 07:58:01 +000090 } else {
Joe Hershberger5874dec2015-04-08 01:41:01 -050091 net_arp_wait_reply_ip = net_gateway;
Joe Hershbergeraae05082012-05-23 07:58:01 +000092 }
93 } else {
Joe Hershberger5874dec2015-04-08 01:41:01 -050094 net_arp_wait_reply_ip = net_arp_wait_packet_ip;
Joe Hershbergeraae05082012-05-23 07:58:01 +000095 }
96
Joe Hershberger8ecdbed2015-04-08 01:41:04 -050097 arp_raw_request(net_ip, net_null_ethaddr, net_arp_wait_reply_ip);
Joe Hershbergeraae05082012-05-23 07:58:01 +000098}
99
Stefan Brünscc97ead2015-08-30 17:46:54 +0200100int arp_timeout_check(void)
Joe Hershbergeraae05082012-05-23 07:58:01 +0000101{
102 ulong t;
103
Joe Hershberger5641f672018-09-26 16:48:58 -0500104 if (!arp_is_waiting())
Stefan Brünscc97ead2015-08-30 17:46:54 +0200105 return 0;
Joe Hershbergeraae05082012-05-23 07:58:01 +0000106
107 t = get_timer(0);
108
109 /* check for arp timeout */
Joe Hershberger85ae7762015-04-08 01:41:08 -0500110 if ((t - arp_wait_timer_start) > ARP_TIMEOUT) {
111 arp_wait_try++;
Joe Hershbergeraae05082012-05-23 07:58:01 +0000112
Joe Hershberger85ae7762015-04-08 01:41:08 -0500113 if (arp_wait_try >= ARP_TIMEOUT_COUNT) {
Joe Hershbergeraae05082012-05-23 07:58:01 +0000114 puts("\nARP Retry count exceeded; starting again\n");
Joe Hershberger85ae7762015-04-08 01:41:08 -0500115 arp_wait_try = 0;
Stefan Brüns86f1fe42015-08-30 17:46:43 +0200116 net_set_state(NETLOOP_FAIL);
Joe Hershbergeraae05082012-05-23 07:58:01 +0000117 } else {
Joe Hershberger85ae7762015-04-08 01:41:08 -0500118 arp_wait_timer_start = t;
119 arp_request();
Joe Hershbergeraae05082012-05-23 07:58:01 +0000120 }
121 }
Stefan Brünscc97ead2015-08-30 17:46:54 +0200122 return 1;
Joe Hershbergeraae05082012-05-23 07:58:01 +0000123}
124
Joe Hershberger85ae7762015-04-08 01:41:08 -0500125void arp_receive(struct ethernet_hdr *et, struct ip_udp_hdr *ip, int len)
Joe Hershbergeraae05082012-05-23 07:58:01 +0000126{
Joe Hershbergerde15d0932012-05-23 07:58:08 +0000127 struct arp_hdr *arp;
Joe Hershberger5874dec2015-04-08 01:41:01 -0500128 struct in_addr reply_ip_addr;
Joe Hershbergerf7ea8052012-05-23 07:59:09 +0000129 int eth_hdr_size;
Joe Hershbergere79a5182018-09-26 16:49:02 -0500130 uchar *tx_packet;
Joe Hershbergeraae05082012-05-23 07:58:01 +0000131
132 /*
133 * We have to deal with two types of ARP packets:
134 * - REQUEST packets will be answered by sending our
135 * IP address - if we know it.
136 * - REPLY packates are expected only after we asked
137 * for the TFTP server's or the gateway's ethernet
138 * address; so if we receive such a packet, we set
139 * the server ethernet address
140 */
Joe Hershberger05a377b2012-05-23 08:01:04 +0000141 debug_cond(DEBUG_NET_PKT, "Got ARP\n");
Joe Hershbergeraae05082012-05-23 07:58:01 +0000142
Joe Hershbergerde15d0932012-05-23 07:58:08 +0000143 arp = (struct arp_hdr *)ip;
Joe Hershbergeraae05082012-05-23 07:58:01 +0000144 if (len < ARP_HDR_SIZE) {
145 printf("bad length %d < %d\n", len, ARP_HDR_SIZE);
146 return;
147 }
148 if (ntohs(arp->ar_hrd) != ARP_ETHER)
149 return;
150 if (ntohs(arp->ar_pro) != PROT_IP)
151 return;
Joe Hershberger2f787492012-05-23 07:58:17 +0000152 if (arp->ar_hln != ARP_HLEN)
Joe Hershbergeraae05082012-05-23 07:58:01 +0000153 return;
Joe Hershberger2f787492012-05-23 07:58:17 +0000154 if (arp->ar_pln != ARP_PLEN)
Joe Hershbergeraae05082012-05-23 07:58:01 +0000155 return;
156
Joe Hershberger5874dec2015-04-08 01:41:01 -0500157 if (net_ip.s_addr == 0)
Joe Hershbergeraae05082012-05-23 07:58:01 +0000158 return;
159
Joe Hershberger5874dec2015-04-08 01:41:01 -0500160 if (net_read_ip(&arp->ar_tpa).s_addr != net_ip.s_addr)
Joe Hershbergeraae05082012-05-23 07:58:01 +0000161 return;
162
163 switch (ntohs(arp->ar_op)) {
164 case ARPOP_REQUEST:
165 /* reply with our IP address */
Joe Hershberger05a377b2012-05-23 08:01:04 +0000166 debug_cond(DEBUG_DEV_PKT, "Got ARP REQUEST, return our IP\n");
Joe Hershberger530cd6b2012-05-23 07:59:16 +0000167 eth_hdr_size = net_update_ether(et, et->et_src, PROT_ARP);
Joe Hershbergeraae05082012-05-23 07:58:01 +0000168 arp->ar_op = htons(ARPOP_REPLY);
Joe Hershberger2f787492012-05-23 07:58:17 +0000169 memcpy(&arp->ar_tha, &arp->ar_sha, ARP_HLEN);
Joe Hershberger5874dec2015-04-08 01:41:01 -0500170 net_copy_ip(&arp->ar_tpa, &arp->ar_spa);
Joe Hershberger8ecdbed2015-04-08 01:41:04 -0500171 memcpy(&arp->ar_sha, net_ethaddr, ARP_HLEN);
Joe Hershberger5874dec2015-04-08 01:41:01 -0500172 net_copy_ip(&arp->ar_spa, &net_ip);
Joe Hershberger39048f62012-05-23 08:00:13 +0000173
174#ifdef CONFIG_CMD_LINK_LOCAL
175 /*
176 * Work-around for brain-damaged Cisco equipment with
177 * arp-proxy enabled.
178 *
179 * If the requesting IP is not on our subnet, wait 5ms to
180 * reply to ARP request so that our reply will overwrite
181 * the arp-proxy's instead of the other way around.
182 */
Joe Hershberger5874dec2015-04-08 01:41:01 -0500183 if ((net_read_ip(&arp->ar_tpa).s_addr & net_netmask.s_addr) !=
184 (net_read_ip(&arp->ar_spa).s_addr & net_netmask.s_addr))
Joe Hershberger39048f62012-05-23 08:00:13 +0000185 udelay(5000);
186#endif
Joe Hershbergere79a5182018-09-26 16:49:02 -0500187 tx_packet = net_get_async_tx_pkt_buf();
188 memcpy(tx_packet, et, eth_hdr_size + ARP_HDR_SIZE);
189 net_send_packet(tx_packet, eth_hdr_size + ARP_HDR_SIZE);
Joe Hershbergeraae05082012-05-23 07:58:01 +0000190 return;
191
192 case ARPOP_REPLY: /* arp reply */
Joe Hershberger5641f672018-09-26 16:48:58 -0500193 /* are we waiting for a reply? */
194 if (!arp_is_waiting())
Joe Hershbergeraae05082012-05-23 07:58:01 +0000195 break;
196
197#ifdef CONFIG_KEEP_SERVERADDR
Joe Hershberger5874dec2015-04-08 01:41:01 -0500198 if (net_server_ip.s_addr == net_arp_wait_packet_ip.s_addr) {
Joe Hershbergeraae05082012-05-23 07:58:01 +0000199 char buf[20];
Mike Frysingerdc36a6a2012-07-10 00:41:50 +0000200 sprintf(buf, "%pM", &arp->ar_sha);
Simon Glass6a38e412017-08-03 12:22:09 -0600201 env_set("serveraddr", buf);
Joe Hershbergeraae05082012-05-23 07:58:01 +0000202 }
203#endif
204
Joe Hershberger5874dec2015-04-08 01:41:01 -0500205 reply_ip_addr = net_read_ip(&arp->ar_spa);
Joe Hershbergeraae05082012-05-23 07:58:01 +0000206
207 /* matched waiting packet's address */
Joe Hershberger5874dec2015-04-08 01:41:01 -0500208 if (reply_ip_addr.s_addr == net_arp_wait_reply_ip.s_addr) {
Joe Hershberger05a377b2012-05-23 08:01:04 +0000209 debug_cond(DEBUG_DEV_PKT,
Joe Hershberger85ae7762015-04-08 01:41:08 -0500210 "Got ARP REPLY, set eth addr (%pM)\n",
211 arp->ar_data);
Joe Hershbergeraae05082012-05-23 07:58:01 +0000212
213 /* save address for later use */
Joe Hershberger85ae7762015-04-08 01:41:08 -0500214 if (arp_wait_packet_ethaddr != NULL)
215 memcpy(arp_wait_packet_ethaddr,
Joe Hershbergere96624a2012-05-23 07:59:20 +0000216 &arp->ar_sha, ARP_HLEN);
Joe Hershbergeraae05082012-05-23 07:58:01 +0000217
Joe Hershbergerf50357b2012-05-23 07:59:15 +0000218 net_get_arp_handler()((uchar *)arp, 0, reply_ip_addr,
Joe Hershberger85ae7762015-04-08 01:41:08 -0500219 0, len);
Joe Hershbergerf50357b2012-05-23 07:59:15 +0000220
Joe Hershbergerde8205a2012-05-23 07:59:24 +0000221 /* set the mac address in the waiting packet's header
222 and transmit it */
Joe Hershbergera8ca4f62015-04-08 01:41:05 -0500223 memcpy(((struct ethernet_hdr *)net_tx_packet)->et_dest,
224 &arp->ar_sha, ARP_HLEN);
Joe Hershberger85ae7762015-04-08 01:41:08 -0500225 net_send_packet(net_tx_packet, arp_wait_tx_packet_size);
Joe Hershbergeraae05082012-05-23 07:58:01 +0000226
227 /* no arp request pending now */
Joe Hershberger5874dec2015-04-08 01:41:01 -0500228 net_arp_wait_packet_ip.s_addr = 0;
Joe Hershberger85ae7762015-04-08 01:41:08 -0500229 arp_wait_tx_packet_size = 0;
230 arp_wait_packet_ethaddr = NULL;
Joe Hershbergeraae05082012-05-23 07:58:01 +0000231 }
232 return;
233 default:
234 debug("Unexpected ARP opcode 0x%x\n",
235 ntohs(arp->ar_op));
236 return;
237 }
238}
Joe Hershberger5641f672018-09-26 16:48:58 -0500239
240bool arp_is_waiting(void)
241{
242 return !!net_arp_wait_packet_ip.s_addr;
243}