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("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("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("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 NetSendPacket((uchar *)et, eth_hdr_size + ARP_HDR_SIZE); 173 return; 174 175 case ARPOP_REPLY: /* arp reply */ 176 /* are we waiting for a reply */ 177 if (!NetArpWaitPacketIP) 178 break; 179 180 #ifdef CONFIG_KEEP_SERVERADDR 181 if (NetServerIP == NetArpWaitPacketIP) { 182 char buf[20]; 183 sprintf(buf, "%pM", arp->ar_sha); 184 setenv("serveraddr", buf); 185 } 186 #endif 187 188 reply_ip_addr = NetReadIP(&arp->ar_spa); 189 190 /* matched waiting packet's address */ 191 if (reply_ip_addr == NetArpWaitReplyIP) { 192 debug("Got ARP REPLY, set eth addr (%pM)\n", 193 arp->ar_data); 194 195 /* save address for later use */ 196 if (NetArpWaitPacketMAC != NULL) 197 memcpy(NetArpWaitPacketMAC, 198 &arp->ar_sha, ARP_HLEN); 199 200 net_get_arp_handler()((uchar *)arp, 0, reply_ip_addr, 201 0, len); 202 203 /* set the mac address in the waiting packet's header 204 and transmit it */ 205 memcpy(((struct ethernet_hdr *)NetTxPacket)->et_dest, 206 &arp->ar_sha, ARP_HLEN); 207 NetSendPacket(NetTxPacket, NetArpWaitTxPacketSize); 208 209 /* no arp request pending now */ 210 NetArpWaitPacketIP = 0; 211 NetArpWaitTxPacketSize = 0; 212 NetArpWaitPacketMAC = NULL; 213 214 } 215 return; 216 default: 217 debug("Unexpected ARP opcode 0x%x\n", 218 ntohs(arp->ar_op)); 219 return; 220 } 221 } 222