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 /* THE transmit packet */ 34 uchar *NetArpWaitTxPacket; 35 int NetArpWaitTxPacketSize; 36 uchar NetArpWaitPacketBuf[PKTSIZE_ALIGN + PKTALIGN]; 37 ulong NetArpWaitTimerStart; 38 int NetArpWaitTry; 39 40 void ArpInit(void) 41 { 42 /* XXX problem with bss workaround */ 43 NetArpWaitPacketMAC = NULL; 44 NetArpWaitPacketIP = 0; 45 NetArpWaitReplyIP = 0; 46 NetArpWaitTxPacket = &NetArpWaitPacketBuf[0] + (PKTALIGN - 1); 47 NetArpWaitTxPacket -= (ulong)NetArpWaitTxPacket % PKTALIGN; 48 NetArpWaitTxPacketSize = 0; 49 } 50 51 void ArpRequest(void) 52 { 53 uchar *pkt; 54 struct arp_hdr *arp; 55 int eth_hdr_size; 56 57 debug("ARP broadcast %d\n", NetArpWaitTry); 58 59 pkt = NetTxPacket; 60 61 eth_hdr_size = NetSetEther(pkt, NetBcastAddr, PROT_ARP); 62 pkt += eth_hdr_size; 63 64 arp = (struct arp_hdr *) pkt; 65 66 arp->ar_hrd = htons(ARP_ETHER); 67 arp->ar_pro = htons(PROT_IP); 68 arp->ar_hln = ARP_HLEN; 69 arp->ar_pln = ARP_PLEN; 70 arp->ar_op = htons(ARPOP_REQUEST); 71 72 /* source ET addr */ 73 memcpy(&arp->ar_sha, NetOurEther, ARP_HLEN); 74 /* source IP addr */ 75 NetWriteIP(&arp->ar_spa, NetOurIP); 76 /* dest ET addr = 0 */ 77 memset(&arp->ar_tha, 0, ARP_HLEN); 78 if ((NetArpWaitPacketIP & NetOurSubnetMask) != 79 (NetOurIP & NetOurSubnetMask)) { 80 if (NetOurGatewayIP == 0) { 81 puts("## Warning: gatewayip needed but not set\n"); 82 NetArpWaitReplyIP = NetArpWaitPacketIP; 83 } else { 84 NetArpWaitReplyIP = NetOurGatewayIP; 85 } 86 } else { 87 NetArpWaitReplyIP = NetArpWaitPacketIP; 88 } 89 90 NetWriteIP(&arp->ar_tpa, NetArpWaitReplyIP); 91 NetSendPacket(NetTxPacket, eth_hdr_size + ARP_HDR_SIZE); 92 } 93 94 void ArpTimeoutCheck(void) 95 { 96 ulong t; 97 98 if (!NetArpWaitPacketIP) 99 return; 100 101 t = get_timer(0); 102 103 /* check for arp timeout */ 104 if ((t - NetArpWaitTimerStart) > ARP_TIMEOUT) { 105 NetArpWaitTry++; 106 107 if (NetArpWaitTry >= ARP_TIMEOUT_COUNT) { 108 puts("\nARP Retry count exceeded; starting again\n"); 109 NetArpWaitTry = 0; 110 NetStartAgain(); 111 } else { 112 NetArpWaitTimerStart = t; 113 ArpRequest(); 114 } 115 } 116 } 117 118 void ArpReceive(struct ethernet_hdr *et, struct ip_udp_hdr *ip, int len) 119 { 120 struct arp_hdr *arp; 121 IPaddr_t reply_ip_addr; 122 uchar *pkt; 123 int eth_hdr_size; 124 125 /* 126 * We have to deal with two types of ARP packets: 127 * - REQUEST packets will be answered by sending our 128 * IP address - if we know it. 129 * - REPLY packates are expected only after we asked 130 * for the TFTP server's or the gateway's ethernet 131 * address; so if we receive such a packet, we set 132 * the server ethernet address 133 */ 134 debug("Got ARP\n"); 135 136 arp = (struct arp_hdr *)ip; 137 if (len < ARP_HDR_SIZE) { 138 printf("bad length %d < %d\n", len, ARP_HDR_SIZE); 139 return; 140 } 141 if (ntohs(arp->ar_hrd) != ARP_ETHER) 142 return; 143 if (ntohs(arp->ar_pro) != PROT_IP) 144 return; 145 if (arp->ar_hln != ARP_HLEN) 146 return; 147 if (arp->ar_pln != ARP_PLEN) 148 return; 149 150 if (NetOurIP == 0) 151 return; 152 153 if (NetReadIP(&arp->ar_tpa) != NetOurIP) 154 return; 155 156 switch (ntohs(arp->ar_op)) { 157 case ARPOP_REQUEST: 158 /* reply with our IP address */ 159 debug("Got ARP REQUEST, return our IP\n"); 160 pkt = (uchar *)et; 161 eth_hdr_size = NetSetEther(pkt, et->et_src, PROT_ARP); 162 pkt += eth_hdr_size; 163 arp->ar_op = htons(ARPOP_REPLY); 164 memcpy(&arp->ar_tha, &arp->ar_sha, ARP_HLEN); 165 NetCopyIP(&arp->ar_tpa, &arp->ar_spa); 166 memcpy(&arp->ar_sha, NetOurEther, ARP_HLEN); 167 NetCopyIP(&arp->ar_spa, &NetOurIP); 168 NetSendPacket((uchar *)et, eth_hdr_size + ARP_HDR_SIZE); 169 return; 170 171 case ARPOP_REPLY: /* arp reply */ 172 /* are we waiting for a reply */ 173 if (!NetArpWaitPacketIP || !NetArpWaitPacketMAC) 174 break; 175 176 #ifdef CONFIG_KEEP_SERVERADDR 177 if (NetServerIP == NetArpWaitPacketIP) { 178 char buf[20]; 179 sprintf(buf, "%pM", arp->ar_sha); 180 setenv("serveraddr", buf); 181 } 182 #endif 183 184 reply_ip_addr = NetReadIP(&arp->ar_spa); 185 186 /* matched waiting packet's address */ 187 if (reply_ip_addr == NetArpWaitReplyIP) { 188 debug("Got ARP REPLY, set eth addr (%pM)\n", 189 arp->ar_data); 190 191 /* save address for later use */ 192 memcpy(NetArpWaitPacketMAC, 193 &arp->ar_sha, ARP_HLEN); 194 195 #ifdef CONFIG_NETCONSOLE 196 NetGetHandler()(0, 0, 0, 0, 0); 197 #endif 198 /* modify header, and transmit it */ 199 memcpy(((struct ethernet_hdr *)NetArpWaitTxPacket)-> 200 et_dest, NetArpWaitPacketMAC, ARP_HLEN); 201 NetSendPacket(NetArpWaitTxPacket, 202 NetArpWaitTxPacketSize); 203 204 /* no arp request pending now */ 205 NetArpWaitPacketIP = 0; 206 NetArpWaitTxPacketSize = 0; 207 NetArpWaitPacketMAC = NULL; 208 209 } 210 return; 211 default: 212 debug("Unexpected ARP opcode 0x%x\n", 213 ntohs(arp->ar_op)); 214 return; 215 } 216 } 217