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