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