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 IPaddr_t NetArpWaitPacketIP; 31 static IPaddr_t NetArpWaitReplyIP; 32 /* MAC address of waiting packet's destination */ 33 uchar *NetArpWaitPacketMAC; 34 int NetArpWaitTxPacketSize; 35 ulong NetArpWaitTimerStart; 36 int NetArpWaitTry; 37 38 static uchar *NetArpTxPacket; /* THE ARP transmit packet */ 39 static uchar NetArpPacketBuf[PKTSIZE_ALIGN + PKTALIGN]; 40 41 void ArpInit(void) 42 { 43 /* XXX problem with bss workaround */ 44 NetArpWaitPacketMAC = NULL; 45 NetArpWaitPacketIP = 0; 46 NetArpWaitReplyIP = 0; 47 NetArpWaitTxPacketSize = 0; 48 NetArpTxPacket = &NetArpPacketBuf[0] + (PKTALIGN - 1); 49 NetArpTxPacket -= (ulong)NetArpTxPacket % PKTALIGN; 50 } 51 52 void arp_raw_request(IPaddr_t sourceIP, const uchar *targetEther, 53 IPaddr_t targetIP) 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", NetArpWaitTry); 60 61 pkt = NetArpTxPacket; 62 63 eth_hdr_size = NetSetEther(pkt, NetBcastAddr, 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, NetOurEther, ARP_HLEN); /* source ET addr */ 75 NetWriteIP(&arp->ar_spa, sourceIP); /* source IP addr */ 76 memcpy(&arp->ar_tha, targetEther, ARP_HLEN); /* target ET addr */ 77 NetWriteIP(&arp->ar_tpa, targetIP); /* target IP addr */ 78 79 NetSendPacket(NetArpTxPacket, eth_hdr_size + ARP_HDR_SIZE); 80 } 81 82 void ArpRequest(void) 83 { 84 if ((NetArpWaitPacketIP & NetOurSubnetMask) != 85 (NetOurIP & NetOurSubnetMask)) { 86 if (NetOurGatewayIP == 0) { 87 puts("## Warning: gatewayip needed but not set\n"); 88 NetArpWaitReplyIP = NetArpWaitPacketIP; 89 } else { 90 NetArpWaitReplyIP = NetOurGatewayIP; 91 } 92 } else { 93 NetArpWaitReplyIP = NetArpWaitPacketIP; 94 } 95 96 arp_raw_request(NetOurIP, NetEtherNullAddr, NetArpWaitReplyIP); 97 } 98 99 void ArpTimeoutCheck(void) 100 { 101 ulong t; 102 103 if (!NetArpWaitPacketIP) 104 return; 105 106 t = get_timer(0); 107 108 /* check for arp timeout */ 109 if ((t - NetArpWaitTimerStart) > ARP_TIMEOUT) { 110 NetArpWaitTry++; 111 112 if (NetArpWaitTry >= ARP_TIMEOUT_COUNT) { 113 puts("\nARP Retry count exceeded; starting again\n"); 114 NetArpWaitTry = 0; 115 NetStartAgain(); 116 } else { 117 NetArpWaitTimerStart = t; 118 ArpRequest(); 119 } 120 } 121 } 122 123 void ArpReceive(struct ethernet_hdr *et, struct ip_udp_hdr *ip, int len) 124 { 125 struct arp_hdr *arp; 126 IPaddr_t reply_ip_addr; 127 uchar *pkt; 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 (NetOurIP == 0) 156 return; 157 158 if (NetReadIP(&arp->ar_tpa) != NetOurIP) 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 pkt = (uchar *)et; 166 eth_hdr_size = net_update_ether(et, et->et_src, PROT_ARP); 167 pkt += eth_hdr_size; 168 arp->ar_op = htons(ARPOP_REPLY); 169 memcpy(&arp->ar_tha, &arp->ar_sha, ARP_HLEN); 170 NetCopyIP(&arp->ar_tpa, &arp->ar_spa); 171 memcpy(&arp->ar_sha, NetOurEther, ARP_HLEN); 172 NetCopyIP(&arp->ar_spa, &NetOurIP); 173 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 */ 183 if ((NetReadIP(&arp->ar_tpa) & NetOurSubnetMask) != 184 (NetReadIP(&arp->ar_spa) & NetOurSubnetMask)) 185 udelay(5000); 186 #endif 187 NetSendPacket((uchar *)et, eth_hdr_size + ARP_HDR_SIZE); 188 return; 189 190 case ARPOP_REPLY: /* arp reply */ 191 /* are we waiting for a reply */ 192 if (!NetArpWaitPacketIP) 193 break; 194 195 #ifdef CONFIG_KEEP_SERVERADDR 196 if (NetServerIP == NetArpWaitPacketIP) { 197 char buf[20]; 198 sprintf(buf, "%pM", &arp->ar_sha); 199 setenv("serveraddr", buf); 200 } 201 #endif 202 203 reply_ip_addr = NetReadIP(&arp->ar_spa); 204 205 /* matched waiting packet's address */ 206 if (reply_ip_addr == NetArpWaitReplyIP) { 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 (NetArpWaitPacketMAC != NULL) 213 memcpy(NetArpWaitPacketMAC, 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 *)NetTxPacket)->et_dest, 222 &arp->ar_sha, ARP_HLEN); 223 NetSendPacket(NetTxPacket, NetArpWaitTxPacketSize); 224 225 /* no arp request pending now */ 226 NetArpWaitPacketIP = 0; 227 NetArpWaitTxPacketSize = 0; 228 NetArpWaitPacketMAC = NULL; 229 230 } 231 return; 232 default: 233 debug("Unexpected ARP opcode 0x%x\n", 234 ntohs(arp->ar_op)); 235 return; 236 } 237 } 238