1 /* 2 * RFC3927 ZeroConf IPv4 Link-Local addressing 3 * (see <http://www.zeroconf.org/>) 4 * 5 * Copied from BusyBox - networking/zcip.c 6 * 7 * Copyright (C) 2003 by Arthur van Hoff (avh@strangeberry.com) 8 * Copyright (C) 2004 by David Brownell 9 * Copyright (C) 2010 by Joe Hershberger 10 * 11 * Licensed under the GPL v2 or later 12 */ 13 14 #include <common.h> 15 #include <net.h> 16 #include "arp.h" 17 #include "net_rand.h" 18 19 /* We don't need more than 32 bits of the counter */ 20 #define MONOTONIC_MS() ((unsigned)get_timer(0) * (1000 / CONFIG_SYS_HZ)) 21 22 enum { 23 /* 169.254.0.0 */ 24 LINKLOCAL_ADDR = 0xa9fe0000, 25 26 IN_CLASSB_NET = 0xffff0000, 27 IN_CLASSB_HOST = 0x0000ffff, 28 29 /* protocol timeout parameters, specified in seconds */ 30 PROBE_WAIT = 1, 31 PROBE_MIN = 1, 32 PROBE_MAX = 2, 33 PROBE_NUM = 3, 34 MAX_CONFLICTS = 10, 35 RATE_LIMIT_INTERVAL = 60, 36 ANNOUNCE_WAIT = 2, 37 ANNOUNCE_NUM = 2, 38 ANNOUNCE_INTERVAL = 2, 39 DEFEND_INTERVAL = 10 40 }; 41 42 /* States during the configuration process. */ 43 static enum ll_state_t { 44 PROBE = 0, 45 RATE_LIMIT_PROBE, 46 ANNOUNCE, 47 MONITOR, 48 DEFEND, 49 DISABLED 50 } state = DISABLED; 51 52 static struct in_addr ip; 53 static int timeout_ms = -1; 54 static unsigned deadline_ms; 55 static unsigned conflicts; 56 static unsigned nprobes; 57 static unsigned nclaims; 58 static int ready; 59 static unsigned int seed; 60 61 static void link_local_timeout(void); 62 63 /** 64 * Pick a random link local IP address on 169.254/16, except that 65 * the first and last 256 addresses are reserved. 66 */ 67 static struct in_addr pick(void) 68 { 69 unsigned tmp; 70 struct in_addr ip; 71 72 do { 73 tmp = rand_r(&seed) & IN_CLASSB_HOST; 74 } while (tmp > (IN_CLASSB_HOST - 0x0200)); 75 ip.s_addr = htonl((LINKLOCAL_ADDR + 0x0100) + tmp); 76 return ip; 77 } 78 79 /** 80 * Return milliseconds of random delay, up to "secs" seconds. 81 */ 82 static inline unsigned random_delay_ms(unsigned secs) 83 { 84 return rand_r(&seed) % (secs * 1000); 85 } 86 87 static void configure_wait(void) 88 { 89 if (timeout_ms == -1) 90 return; 91 92 /* poll, being ready to adjust current timeout */ 93 if (!timeout_ms) 94 timeout_ms = random_delay_ms(PROBE_WAIT); 95 96 /* set deadline_ms to the point in time when we timeout */ 97 deadline_ms = MONOTONIC_MS() + timeout_ms; 98 99 debug_cond(DEBUG_DEV_PKT, "...wait %d %s nprobes=%u, nclaims=%u\n", 100 timeout_ms, eth_get_name(), nprobes, nclaims); 101 102 net_set_timeout_handler(timeout_ms, link_local_timeout); 103 } 104 105 void link_local_start(void) 106 { 107 ip = getenv_ip("llipaddr"); 108 if (ip.s_addr != 0 && 109 (ntohl(ip.s_addr) & IN_CLASSB_NET) != LINKLOCAL_ADDR) { 110 puts("invalid link address"); 111 net_set_state(NETLOOP_FAIL); 112 return; 113 } 114 net_netmask.s_addr = htonl(IN_CLASSB_NET); 115 116 seed = seed_mac(); 117 if (ip.s_addr == 0) 118 ip = pick(); 119 120 state = PROBE; 121 timeout_ms = 0; 122 conflicts = 0; 123 nprobes = 0; 124 nclaims = 0; 125 ready = 0; 126 127 configure_wait(); 128 } 129 130 static void link_local_timeout(void) 131 { 132 switch (state) { 133 case PROBE: 134 /* timeouts in the PROBE state mean no conflicting ARP packets 135 have been received, so we can progress through the states */ 136 if (nprobes < PROBE_NUM) { 137 struct in_addr zero_ip = {.s_addr = 0}; 138 139 nprobes++; 140 debug_cond(DEBUG_LL_STATE, "probe/%u %s@%pI4\n", 141 nprobes, eth_get_name(), &ip); 142 arp_raw_request(zero_ip, net_null_ethaddr, ip); 143 timeout_ms = PROBE_MIN * 1000; 144 timeout_ms += random_delay_ms(PROBE_MAX - PROBE_MIN); 145 } else { 146 /* Switch to announce state */ 147 state = ANNOUNCE; 148 nclaims = 0; 149 debug_cond(DEBUG_LL_STATE, "announce/%u %s@%pI4\n", 150 nclaims, eth_get_name(), &ip); 151 arp_raw_request(ip, net_ethaddr, ip); 152 timeout_ms = ANNOUNCE_INTERVAL * 1000; 153 } 154 break; 155 case RATE_LIMIT_PROBE: 156 /* timeouts in the RATE_LIMIT_PROBE state mean no conflicting 157 ARP packets have been received, so we can move immediately 158 to the announce state */ 159 state = ANNOUNCE; 160 nclaims = 0; 161 debug_cond(DEBUG_LL_STATE, "announce/%u %s@%pI4\n", 162 nclaims, eth_get_name(), &ip); 163 arp_raw_request(ip, net_ethaddr, ip); 164 timeout_ms = ANNOUNCE_INTERVAL * 1000; 165 break; 166 case ANNOUNCE: 167 /* timeouts in the ANNOUNCE state mean no conflicting ARP 168 packets have been received, so we can progress through 169 the states */ 170 if (nclaims < ANNOUNCE_NUM) { 171 nclaims++; 172 debug_cond(DEBUG_LL_STATE, "announce/%u %s@%pI4\n", 173 nclaims, eth_get_name(), &ip); 174 arp_raw_request(ip, net_ethaddr, ip); 175 timeout_ms = ANNOUNCE_INTERVAL * 1000; 176 } else { 177 /* Switch to monitor state */ 178 state = MONITOR; 179 printf("Successfully assigned %pI4\n", &ip); 180 net_copy_ip(&net_ip, &ip); 181 ready = 1; 182 conflicts = 0; 183 timeout_ms = -1; 184 /* Never timeout in the monitor state */ 185 net_set_timeout_handler(0, NULL); 186 187 /* NOTE: all other exit paths should deconfig ... */ 188 net_set_state(NETLOOP_SUCCESS); 189 return; 190 } 191 break; 192 case DEFEND: 193 /* We won! No ARP replies, so just go back to monitor */ 194 state = MONITOR; 195 timeout_ms = -1; 196 conflicts = 0; 197 break; 198 default: 199 /* Invalid, should never happen. Restart the whole protocol */ 200 state = PROBE; 201 ip = pick(); 202 timeout_ms = 0; 203 nprobes = 0; 204 nclaims = 0; 205 break; 206 } 207 configure_wait(); 208 } 209 210 void link_local_receive_arp(struct arp_hdr *arp, int len) 211 { 212 int source_ip_conflict; 213 int target_ip_conflict; 214 struct in_addr null_ip = {.s_addr = 0}; 215 216 if (state == DISABLED) 217 return; 218 219 /* We need to adjust the timeout in case we didn't receive a 220 conflicting packet. */ 221 if (timeout_ms > 0) { 222 unsigned diff = deadline_ms - MONOTONIC_MS(); 223 if ((int)(diff) < 0) { 224 /* Current time is greater than the expected timeout 225 time. This should never happen */ 226 debug_cond(DEBUG_LL_STATE, 227 "missed an expected timeout\n"); 228 timeout_ms = 0; 229 } else { 230 debug_cond(DEBUG_INT_STATE, "adjusting timeout\n"); 231 timeout_ms = diff | 1; /* never 0 */ 232 } 233 } 234 #if 0 235 /* XXX Don't bother with ethernet link just yet */ 236 if ((fds[0].revents & POLLIN) == 0) { 237 if (fds[0].revents & POLLERR) { 238 /* 239 * FIXME: links routinely go down; 240 */ 241 bb_error_msg("iface %s is down", eth_get_name()); 242 if (ready) 243 run(argv, "deconfig", &ip); 244 return EXIT_FAILURE; 245 } 246 continue; 247 } 248 #endif 249 250 debug_cond(DEBUG_INT_STATE, "%s recv arp type=%d, op=%d,\n", 251 eth_get_name(), ntohs(arp->ar_pro), 252 ntohs(arp->ar_op)); 253 debug_cond(DEBUG_INT_STATE, "\tsource=%pM %pI4\n", 254 &arp->ar_sha, 255 &arp->ar_spa); 256 debug_cond(DEBUG_INT_STATE, "\ttarget=%pM %pI4\n", 257 &arp->ar_tha, 258 &arp->ar_tpa); 259 260 if (arp->ar_op != htons(ARPOP_REQUEST) && 261 arp->ar_op != htons(ARPOP_REPLY)) { 262 configure_wait(); 263 return; 264 } 265 266 source_ip_conflict = 0; 267 target_ip_conflict = 0; 268 269 if (memcmp(&arp->ar_spa, &ip, ARP_PLEN) == 0 && 270 memcmp(&arp->ar_sha, net_ethaddr, ARP_HLEN) != 0) 271 source_ip_conflict = 1; 272 273 /* 274 * According to RFC 3927, section 2.2.1: 275 * Check if packet is an ARP probe by checking for a null source IP 276 * then check that target IP is equal to ours and source hw addr 277 * is not equal to ours. This condition should cause a conflict only 278 * during probe. 279 */ 280 if (arp->ar_op == htons(ARPOP_REQUEST) && 281 memcmp(&arp->ar_spa, &null_ip, ARP_PLEN) == 0 && 282 memcmp(&arp->ar_tpa, &ip, ARP_PLEN) == 0 && 283 memcmp(&arp->ar_sha, net_ethaddr, ARP_HLEN) != 0) { 284 target_ip_conflict = 1; 285 } 286 287 debug_cond(DEBUG_NET_PKT, 288 "state = %d, source ip conflict = %d, target ip conflict = " 289 "%d\n", state, source_ip_conflict, target_ip_conflict); 290 switch (state) { 291 case PROBE: 292 case ANNOUNCE: 293 /* When probing or announcing, check for source IP conflicts 294 and other hosts doing ARP probes (target IP conflicts). */ 295 if (source_ip_conflict || target_ip_conflict) { 296 conflicts++; 297 state = PROBE; 298 if (conflicts >= MAX_CONFLICTS) { 299 debug("%s ratelimit\n", eth_get_name()); 300 timeout_ms = RATE_LIMIT_INTERVAL * 1000; 301 state = RATE_LIMIT_PROBE; 302 } 303 304 /* restart the whole protocol */ 305 ip = pick(); 306 timeout_ms = 0; 307 nprobes = 0; 308 nclaims = 0; 309 } 310 break; 311 case MONITOR: 312 /* If a conflict, we try to defend with a single ARP probe */ 313 if (source_ip_conflict) { 314 debug("monitor conflict -- defending\n"); 315 state = DEFEND; 316 timeout_ms = DEFEND_INTERVAL * 1000; 317 arp_raw_request(ip, net_ethaddr, ip); 318 } 319 break; 320 case DEFEND: 321 /* Well, we tried. Start over (on conflict) */ 322 if (source_ip_conflict) { 323 state = PROBE; 324 debug("defend conflict -- starting over\n"); 325 ready = 0; 326 net_ip.s_addr = 0; 327 328 /* restart the whole protocol */ 329 ip = pick(); 330 timeout_ms = 0; 331 nprobes = 0; 332 nclaims = 0; 333 } 334 break; 335 default: 336 /* Invalid, should never happen. Restart the whole protocol */ 337 debug("invalid state -- starting over\n"); 338 state = PROBE; 339 ip = pick(); 340 timeout_ms = 0; 341 nprobes = 0; 342 nclaims = 0; 343 break; 344 } 345 configure_wait(); 346 } 347