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