uboot/net/arp.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   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>
  13#include <env.h>
  14#include <log.h>
  15#include <net.h>
  16#include <linux/delay.h>
  17
  18#include "arp.h"
  19
  20struct in_addr net_arp_wait_packet_ip;
  21static struct in_addr net_arp_wait_reply_ip;
  22/* MAC address of waiting packet's destination */
  23uchar          *arp_wait_packet_ethaddr;
  24int             arp_wait_tx_packet_size;
  25ulong           arp_wait_timer_start;
  26int             arp_wait_try;
  27uchar          *arp_tx_packet; /* THE ARP transmit packet */
  28static uchar    arp_tx_packet_buf[PKTSIZE_ALIGN + PKTALIGN];
  29
  30void arp_init(void)
  31{
  32        /* XXX problem with bss workaround */
  33        arp_wait_packet_ethaddr = NULL;
  34        net_arp_wait_packet_ip.s_addr = 0;
  35        net_arp_wait_reply_ip.s_addr = 0;
  36        arp_wait_tx_packet_size = 0;
  37        arp_tx_packet = &arp_tx_packet_buf[0] + (PKTALIGN - 1);
  38        arp_tx_packet -= (ulong)arp_tx_packet % PKTALIGN;
  39}
  40
  41void arp_raw_request(struct in_addr source_ip, const uchar *target_ethaddr,
  42        struct in_addr target_ip)
  43{
  44        uchar *pkt;
  45        struct arp_hdr *arp;
  46        int eth_hdr_size;
  47
  48        debug_cond(DEBUG_DEV_PKT, "ARP broadcast %d\n", arp_wait_try);
  49
  50        pkt = arp_tx_packet;
  51
  52        eth_hdr_size = net_set_ether(pkt, net_bcast_ethaddr, PROT_ARP);
  53        pkt += eth_hdr_size;
  54
  55        arp = (struct arp_hdr *)pkt;
  56
  57        arp->ar_hrd = htons(ARP_ETHER);
  58        arp->ar_pro = htons(PROT_IP);
  59        arp->ar_hln = ARP_HLEN;
  60        arp->ar_pln = ARP_PLEN;
  61        arp->ar_op = htons(ARPOP_REQUEST);
  62
  63        memcpy(&arp->ar_sha, net_ethaddr, ARP_HLEN);    /* source ET addr */
  64        net_write_ip(&arp->ar_spa, source_ip);          /* source IP addr */
  65        memcpy(&arp->ar_tha, target_ethaddr, ARP_HLEN); /* target ET addr */
  66        net_write_ip(&arp->ar_tpa, target_ip);          /* target IP addr */
  67
  68        net_send_packet(arp_tx_packet, eth_hdr_size + ARP_HDR_SIZE);
  69}
  70
  71void arp_request(void)
  72{
  73        if ((net_arp_wait_packet_ip.s_addr & net_netmask.s_addr) !=
  74            (net_ip.s_addr & net_netmask.s_addr)) {
  75                if (net_gateway.s_addr == 0) {
  76                        puts("## Warning: gatewayip needed but not set\n");
  77                        net_arp_wait_reply_ip = net_arp_wait_packet_ip;
  78                } else {
  79                        net_arp_wait_reply_ip = net_gateway;
  80                }
  81        } else {
  82                net_arp_wait_reply_ip = net_arp_wait_packet_ip;
  83        }
  84
  85        arp_raw_request(net_ip, net_null_ethaddr, net_arp_wait_reply_ip);
  86}
  87
  88int arp_timeout_check(void)
  89{
  90        ulong t;
  91
  92        if (!arp_is_waiting())
  93                return 0;
  94
  95        t = get_timer(0);
  96
  97        /* check for arp timeout */
  98        if ((t - arp_wait_timer_start) > CONFIG_ARP_TIMEOUT) {
  99                arp_wait_try++;
 100
 101                if (arp_wait_try >= CONFIG_NET_RETRY_COUNT) {
 102                        puts("\nARP Retry count exceeded; starting again\n");
 103                        arp_wait_try = 0;
 104                        net_set_state(NETLOOP_FAIL);
 105                } else {
 106                        arp_wait_timer_start = t;
 107                        arp_request();
 108                }
 109        }
 110        return 1;
 111}
 112
 113void arp_receive(struct ethernet_hdr *et, struct ip_udp_hdr *ip, int len)
 114{
 115        struct arp_hdr *arp;
 116        struct in_addr reply_ip_addr;
 117        int eth_hdr_size;
 118        uchar *tx_packet;
 119
 120        /*
 121         * We have to deal with two types of ARP packets:
 122         * - REQUEST packets will be answered by sending  our
 123         *   IP address - if we know it.
 124         * - REPLY packates are expected only after we asked
 125         *   for the TFTP server's or the gateway's ethernet
 126         *   address; so if we receive such a packet, we set
 127         *   the server ethernet address
 128         */
 129        debug_cond(DEBUG_NET_PKT, "Got ARP\n");
 130
 131        arp = (struct arp_hdr *)ip;
 132        if (len < ARP_HDR_SIZE) {
 133                printf("bad length %d < %d\n", len, ARP_HDR_SIZE);
 134                return;
 135        }
 136        if (ntohs(arp->ar_hrd) != ARP_ETHER)
 137                return;
 138        if (ntohs(arp->ar_pro) != PROT_IP)
 139                return;
 140        if (arp->ar_hln != ARP_HLEN)
 141                return;
 142        if (arp->ar_pln != ARP_PLEN)
 143                return;
 144
 145        if (net_ip.s_addr == 0)
 146                return;
 147
 148        if (net_read_ip(&arp->ar_tpa).s_addr != net_ip.s_addr)
 149                return;
 150
 151        switch (ntohs(arp->ar_op)) {
 152        case ARPOP_REQUEST:
 153                /* reply with our IP address */
 154                debug_cond(DEBUG_DEV_PKT, "Got ARP REQUEST, return our IP\n");
 155                eth_hdr_size = net_update_ether(et, et->et_src, PROT_ARP);
 156                arp->ar_op = htons(ARPOP_REPLY);
 157                memcpy(&arp->ar_tha, &arp->ar_sha, ARP_HLEN);
 158                net_copy_ip(&arp->ar_tpa, &arp->ar_spa);
 159                memcpy(&arp->ar_sha, net_ethaddr, ARP_HLEN);
 160                net_copy_ip(&arp->ar_spa, &net_ip);
 161
 162#ifdef CONFIG_CMD_LINK_LOCAL
 163                /*
 164                 * Work-around for brain-damaged Cisco equipment with
 165                 *   arp-proxy enabled.
 166                 *
 167                 *   If the requesting IP is not on our subnet, wait 5ms to
 168                 *   reply to ARP request so that our reply will overwrite
 169                 *   the arp-proxy's instead of the other way around.
 170                 */
 171                if ((net_read_ip(&arp->ar_tpa).s_addr & net_netmask.s_addr) !=
 172                    (net_read_ip(&arp->ar_spa).s_addr & net_netmask.s_addr))
 173                        udelay(5000);
 174#endif
 175                tx_packet = net_get_async_tx_pkt_buf();
 176                memcpy(tx_packet, et, eth_hdr_size + ARP_HDR_SIZE);
 177                net_send_packet(tx_packet, eth_hdr_size + ARP_HDR_SIZE);
 178                return;
 179
 180        case ARPOP_REPLY:               /* arp reply */
 181                /* are we waiting for a reply? */
 182                if (!arp_is_waiting())
 183                        break;
 184
 185                if (IS_ENABLED(CONFIG_KEEP_SERVERADDR) &&
 186                    net_server_ip.s_addr == net_arp_wait_packet_ip.s_addr) {
 187                        char buf[20];
 188                        sprintf(buf, "%pM", &arp->ar_sha);
 189                        env_set("serveraddr", buf);
 190                }
 191
 192                reply_ip_addr = net_read_ip(&arp->ar_spa);
 193
 194                /* matched waiting packet's address */
 195                if (reply_ip_addr.s_addr == net_arp_wait_reply_ip.s_addr) {
 196                        debug_cond(DEBUG_DEV_PKT,
 197                                   "Got ARP REPLY, set eth addr (%pM)\n",
 198                                   arp->ar_data);
 199
 200                        /* save address for later use */
 201                        if (arp_wait_packet_ethaddr != NULL)
 202                                memcpy(arp_wait_packet_ethaddr,
 203                                       &arp->ar_sha, ARP_HLEN);
 204
 205                        net_get_arp_handler()((uchar *)arp, 0, reply_ip_addr,
 206                                              0, len);
 207
 208                        /* set the mac address in the waiting packet's header
 209                           and transmit it */
 210                        memcpy(((struct ethernet_hdr *)net_tx_packet)->et_dest,
 211                               &arp->ar_sha, ARP_HLEN);
 212                        net_send_packet(net_tx_packet, arp_wait_tx_packet_size);
 213
 214                        /* no arp request pending now */
 215                        net_arp_wait_packet_ip.s_addr = 0;
 216                        arp_wait_tx_packet_size = 0;
 217                        arp_wait_packet_ethaddr = NULL;
 218                }
 219                return;
 220        default:
 221                debug("Unexpected ARP opcode 0x%x\n",
 222                      ntohs(arp->ar_op));
 223                return;
 224        }
 225}
 226
 227bool arp_is_waiting(void)
 228{
 229        return !!net_arp_wait_packet_ip.s_addr;
 230}
 231