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