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 * SPDX-License-Identifier: GPL-2.0 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 30 struct in_addr net_arp_wait_packet_ip; 31 static struct in_addr net_arp_wait_reply_ip; 32 /* MAC address of waiting packet's destination */ 33 uchar *arp_wait_packet_ethaddr; 34 int arp_wait_tx_packet_size; 35 ulong arp_wait_timer_start; 36 int arp_wait_try; 37 38 static uchar *arp_tx_packet; /* THE ARP transmit packet */ 39 static uchar arp_tx_packet_buf[PKTSIZE_ALIGN + PKTALIGN]; 40 41 void arp_init(void) 42 { 43 /* XXX problem with bss workaround */ 44 arp_wait_packet_ethaddr = NULL; 45 net_arp_wait_packet_ip.s_addr = 0; 46 net_arp_wait_reply_ip.s_addr = 0; 47 arp_wait_tx_packet_size = 0; 48 arp_tx_packet = &arp_tx_packet_buf[0] + (PKTALIGN - 1); 49 arp_tx_packet -= (ulong)arp_tx_packet % PKTALIGN; 50 } 51 52 void arp_raw_request(struct in_addr source_ip, const uchar *target_ethaddr, 53 struct in_addr target_ip) 54 { 55 uchar *pkt; 56 struct arp_hdr *arp; 57 int eth_hdr_size; 58 59 debug_cond(DEBUG_DEV_PKT, "ARP broadcast %d\n", arp_wait_try); 60 61 pkt = arp_tx_packet; 62 63 eth_hdr_size = net_set_ether(pkt, net_bcast_ethaddr, PROT_ARP); 64 pkt += eth_hdr_size; 65 66 arp = (struct arp_hdr *)pkt; 67 68 arp->ar_hrd = htons(ARP_ETHER); 69 arp->ar_pro = htons(PROT_IP); 70 arp->ar_hln = ARP_HLEN; 71 arp->ar_pln = ARP_PLEN; 72 arp->ar_op = htons(ARPOP_REQUEST); 73 74 memcpy(&arp->ar_sha, net_ethaddr, ARP_HLEN); /* source ET addr */ 75 net_write_ip(&arp->ar_spa, source_ip); /* source IP addr */ 76 memcpy(&arp->ar_tha, target_ethaddr, ARP_HLEN); /* target ET addr */ 77 net_write_ip(&arp->ar_tpa, target_ip); /* target IP addr */ 78 79 net_send_packet(arp_tx_packet, eth_hdr_size + ARP_HDR_SIZE); 80 } 81 82 void arp_request(void) 83 { 84 if ((net_arp_wait_packet_ip.s_addr & net_netmask.s_addr) != 85 (net_ip.s_addr & net_netmask.s_addr)) { 86 if (net_gateway.s_addr == 0) { 87 puts("## Warning: gatewayip needed but not set\n"); 88 net_arp_wait_reply_ip = net_arp_wait_packet_ip; 89 } else { 90 net_arp_wait_reply_ip = net_gateway; 91 } 92 } else { 93 net_arp_wait_reply_ip = net_arp_wait_packet_ip; 94 } 95 96 arp_raw_request(net_ip, net_null_ethaddr, net_arp_wait_reply_ip); 97 } 98 99 int arp_timeout_check(void) 100 { 101 ulong t; 102 103 if (!net_arp_wait_packet_ip.s_addr) 104 return 0; 105 106 t = get_timer(0); 107 108 /* check for arp timeout */ 109 if ((t - arp_wait_timer_start) > ARP_TIMEOUT) { 110 arp_wait_try++; 111 112 if (arp_wait_try >= ARP_TIMEOUT_COUNT) { 113 puts("\nARP Retry count exceeded; starting again\n"); 114 arp_wait_try = 0; 115 net_set_state(NETLOOP_FAIL); 116 } else { 117 arp_wait_timer_start = t; 118 arp_request(); 119 } 120 } 121 return 1; 122 } 123 124 void arp_receive(struct ethernet_hdr *et, struct ip_udp_hdr *ip, int len) 125 { 126 struct arp_hdr *arp; 127 struct in_addr reply_ip_addr; 128 int eth_hdr_size; 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 net_send_packet((uchar *)et, eth_hdr_size + ARP_HDR_SIZE); 186 return; 187 188 case ARPOP_REPLY: /* arp reply */ 189 /* are we waiting for a reply */ 190 if (!net_arp_wait_packet_ip.s_addr) 191 break; 192 193 #ifdef CONFIG_KEEP_SERVERADDR 194 if (net_server_ip.s_addr == net_arp_wait_packet_ip.s_addr) { 195 char buf[20]; 196 sprintf(buf, "%pM", &arp->ar_sha); 197 env_set("serveraddr", buf); 198 } 199 #endif 200 201 reply_ip_addr = net_read_ip(&arp->ar_spa); 202 203 /* matched waiting packet's address */ 204 if (reply_ip_addr.s_addr == net_arp_wait_reply_ip.s_addr) { 205 debug_cond(DEBUG_DEV_PKT, 206 "Got ARP REPLY, set eth addr (%pM)\n", 207 arp->ar_data); 208 209 /* save address for later use */ 210 if (arp_wait_packet_ethaddr != NULL) 211 memcpy(arp_wait_packet_ethaddr, 212 &arp->ar_sha, ARP_HLEN); 213 214 net_get_arp_handler()((uchar *)arp, 0, reply_ip_addr, 215 0, len); 216 217 /* set the mac address in the waiting packet's header 218 and transmit it */ 219 memcpy(((struct ethernet_hdr *)net_tx_packet)->et_dest, 220 &arp->ar_sha, ARP_HLEN); 221 net_send_packet(net_tx_packet, arp_wait_tx_packet_size); 222 223 /* no arp request pending now */ 224 net_arp_wait_packet_ip.s_addr = 0; 225 arp_wait_tx_packet_size = 0; 226 arp_wait_packet_ethaddr = NULL; 227 } 228 return; 229 default: 230 debug("Unexpected ARP opcode 0x%x\n", 231 ntohs(arp->ar_op)); 232 return; 233 } 234 } 235