Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
autoip.c
00001 /** 00002 * @file 00003 * AutoIP Automatic LinkLocal IP Configuration 00004 * 00005 */ 00006 00007 /* 00008 * 00009 * Copyright (c) 2007 Dominik Spies <kontakt@dspies.de> 00010 * All rights reserved. 00011 * 00012 * Redistribution and use in source and binary forms, with or without modification, 00013 * are permitted provided that the following conditions are met: 00014 * 00015 * 1. Redistributions of source code must retain the above copyright notice, 00016 * this list of conditions and the following disclaimer. 00017 * 2. Redistributions in binary form must reproduce the above copyright notice, 00018 * this list of conditions and the following disclaimer in the documentation 00019 * and/or other materials provided with the distribution. 00020 * 3. The name of the author may not be used to endorse or promote products 00021 * derived from this software without specific prior written permission. 00022 * 00023 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 00024 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 00025 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 00026 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 00027 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 00028 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00029 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00030 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 00031 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 00032 * OF SUCH DAMAGE. 00033 * 00034 * Author: Dominik Spies <kontakt@dspies.de> 00035 * 00036 * This is a AutoIP implementation for the lwIP TCP/IP stack. It aims to conform 00037 * with RFC 3927. 00038 * 00039 * 00040 * Please coordinate changes and requests with Dominik Spies 00041 * <kontakt@dspies.de> 00042 */ 00043 00044 /******************************************************************************* 00045 * USAGE: 00046 * 00047 * define LWIP_AUTOIP 1 in your lwipopts.h 00048 * 00049 * If you don't use tcpip.c (so, don't call, you don't call tcpip_init): 00050 * - First, call autoip_init(). 00051 * - call autoip_tmr() all AUTOIP_TMR_INTERVAL msces, 00052 * that should be defined in autoip.h. 00053 * I recommend a value of 100. The value must divide 1000 with a remainder almost 0. 00054 * Possible values are 1000, 500, 333, 250, 200, 166, 142, 125, 111, 100 .... 00055 * 00056 * Without DHCP: 00057 * - Call autoip_start() after netif_add(). 00058 * 00059 * With DHCP: 00060 * - define LWIP_DHCP_AUTOIP_COOP 1 in your lwipopts.h. 00061 * - Configure your DHCP Client. 00062 * 00063 */ 00064 00065 #include "lwip/opt.h" 00066 00067 #if LWIP_AUTOIP /* don't build if not configured for use in lwipopts.h */ 00068 00069 #include "lwip/mem.h" 00070 #include "lwip/udp.h" 00071 #include "lwip/ip_addr.h" 00072 #include "lwip/netif.h" 00073 #include "lwip/autoip.h" 00074 #include "netif/etharp.h" 00075 00076 #include <stdlib.h> 00077 #include <string.h> 00078 00079 /* 169.254.0.0 */ 00080 #define AUTOIP_NET 0xA9FE0000 00081 /* 169.254.1.0 */ 00082 #define AUTOIP_RANGE_START (AUTOIP_NET | 0x0100) 00083 /* 169.254.254.255 */ 00084 #define AUTOIP_RANGE_END (AUTOIP_NET | 0xFEFF) 00085 00086 00087 /** Pseudo random macro based on netif informations. 00088 * You could use "rand()" from the C Library if you define LWIP_AUTOIP_RAND in lwipopts.h */ 00089 #ifndef LWIP_AUTOIP_RAND 00090 #define LWIP_AUTOIP_RAND(netif) ( (((u32_t)((netif->hwaddr[5]) & 0xff) << 24) | \ 00091 ((u32_t)((netif->hwaddr[3]) & 0xff) << 16) | \ 00092 ((u32_t)((netif->hwaddr[2]) & 0xff) << 8) | \ 00093 ((u32_t)((netif->hwaddr[4]) & 0xff))) + \ 00094 (netif->autoip?netif->autoip->tried_llipaddr:0)) 00095 #endif /* LWIP_AUTOIP_RAND */ 00096 00097 /** 00098 * Macro that generates the initial IP address to be tried by AUTOIP. 00099 * If you want to override this, define it to something else in lwipopts.h. 00100 */ 00101 #ifndef LWIP_AUTOIP_CREATE_SEED_ADDR 00102 #define LWIP_AUTOIP_CREATE_SEED_ADDR(netif) \ 00103 htonl(AUTOIP_RANGE_START + ((u32_t)(((u8_t)(netif->hwaddr[4])) | \ 00104 ((u32_t)((u8_t)(netif->hwaddr[5]))) << 8))) 00105 #endif /* LWIP_AUTOIP_CREATE_SEED_ADDR */ 00106 00107 /* static functions */ 00108 static void autoip_handle_arp_conflict(struct netif *netif); 00109 00110 /* creates a pseudo random LL IP-Address for a network interface */ 00111 static void autoip_create_addr(struct netif *netif, struct ip_addr *ipaddr); 00112 00113 /* sends an ARP probe */ 00114 static err_t autoip_arp_probe(struct netif *netif); 00115 00116 /* sends an ARP announce */ 00117 static err_t autoip_arp_announce(struct netif *netif); 00118 00119 /* configure interface for use with current LL IP-Address */ 00120 static err_t autoip_bind(struct netif *netif); 00121 00122 /* start sending probes for llipaddr */ 00123 static void autoip_start_probing(struct netif *netif); 00124 00125 /** 00126 * Initialize this module 00127 */ 00128 void 00129 autoip_init(void) 00130 { 00131 LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | 3, ("autoip_init()\n")); 00132 } 00133 00134 /** 00135 * Handle a IP address conflict after an ARP conflict detection 00136 */ 00137 static void 00138 autoip_handle_arp_conflict(struct netif *netif) 00139 { 00140 /* Somehow detect if we are defending or retreating */ 00141 unsigned char defend = 1; /* tbd */ 00142 00143 if(defend) { 00144 if(netif->autoip->lastconflict > 0) { 00145 /* retreat, there was a conflicting ARP in the last 00146 * DEFEND_INTERVAL seconds 00147 */ 00148 LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1, 00149 ("autoip_handle_arp_conflict(): we are defending, but in DEFEND_INTERVAL, retreating\n")); 00150 00151 /* TODO: close all TCP sessions */ 00152 autoip_start(netif); 00153 } else { 00154 LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1, 00155 ("autoip_handle_arp_conflict(): we are defend, send ARP Announce\n")); 00156 autoip_arp_announce(netif); 00157 netif->autoip->lastconflict = DEFEND_INTERVAL * AUTOIP_TICKS_PER_SECOND; 00158 } 00159 } else { 00160 LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1, 00161 ("autoip_handle_arp_conflict(): we do not defend, retreating\n")); 00162 /* TODO: close all TCP sessions */ 00163 autoip_start(netif); 00164 } 00165 } 00166 00167 /** 00168 * Create an IP-Address out of range 169.254.1.0 to 169.254.254.255 00169 * 00170 * @param netif network interface on which create the IP-Address 00171 * @param ipaddr ip address to initialize 00172 */ 00173 static void 00174 autoip_create_addr(struct netif *netif, struct ip_addr *ipaddr) 00175 { 00176 /* Here we create an IP-Address out of range 169.254.1.0 to 169.254.254.255 00177 * compliant to RFC 3927 Section 2.1 00178 * We have 254 * 256 possibilities */ 00179 00180 u32_t addr = ntohl(LWIP_AUTOIP_CREATE_SEED_ADDR(netif)); 00181 addr += netif->autoip->tried_llipaddr; 00182 addr = AUTOIP_NET | (addr & 0xffff); 00183 /* Now, 169.254.0.0 <= addr <= 169.254.255.255 */ 00184 00185 if (addr < AUTOIP_RANGE_START) { 00186 addr += AUTOIP_RANGE_END - AUTOIP_RANGE_START + 1; 00187 } 00188 if (addr > AUTOIP_RANGE_END) { 00189 addr -= AUTOIP_RANGE_END - AUTOIP_RANGE_START + 1; 00190 } 00191 LWIP_ASSERT("AUTOIP address not in range", (addr >= AUTOIP_RANGE_START) && 00192 (addr <= AUTOIP_RANGE_END)); 00193 ipaddr->addr = htonl(addr); 00194 00195 LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1, 00196 ("autoip_create_addr(): tried_llipaddr=%"U16_F", 0x%08"X32_F"\n", 00197 (u16_t)(netif->autoip->tried_llipaddr), (u32_t)(ipaddr->addr))); 00198 } 00199 00200 /** 00201 * Sends an ARP probe from a network interface 00202 * 00203 * @param netif network interface used to send the probe 00204 */ 00205 static err_t 00206 autoip_arp_probe(struct netif *netif) 00207 { 00208 return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, ðbroadcast, 00209 (struct eth_addr *)netif->hwaddr, IP_ADDR_ANY, ðzero, 00210 &netif->autoip->llipaddr, ARP_REQUEST); 00211 } 00212 00213 /** 00214 * Sends an ARP announce from a network interface 00215 * 00216 * @param netif network interface used to send the announce 00217 */ 00218 static err_t 00219 autoip_arp_announce(struct netif *netif) 00220 { 00221 return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, ðbroadcast, 00222 (struct eth_addr *)netif->hwaddr, &netif->autoip->llipaddr, ðzero, 00223 &netif->autoip->llipaddr, ARP_REQUEST); 00224 } 00225 00226 /** 00227 * Configure interface for use with current LL IP-Address 00228 * 00229 * @param netif network interface to configure with current LL IP-Address 00230 */ 00231 static err_t 00232 autoip_bind(struct netif *netif) 00233 { 00234 struct autoip *autoip = netif->autoip; 00235 struct ip_addr sn_mask, gw_addr; 00236 00237 LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | 3, 00238 ("autoip_bind(netif=%p) %c%c%"U16_F" 0x%08"X32_F"\n", 00239 (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num, autoip->llipaddr.addr)); 00240 00241 IP4_ADDR(&sn_mask, 255, 255, 0, 0); 00242 IP4_ADDR(&gw_addr, 0, 0, 0, 0); 00243 00244 netif_set_ipaddr(netif, &autoip->llipaddr); 00245 netif_set_netmask(netif, &sn_mask); 00246 netif_set_gw(netif, &gw_addr); 00247 00248 /* bring the interface up */ 00249 netif_set_up(netif); 00250 00251 return ERR_OK; 00252 } 00253 00254 /** 00255 * Start AutoIP client 00256 * 00257 * @param netif network interface on which start the AutoIP client 00258 */ 00259 err_t 00260 autoip_start(struct netif *netif) 00261 { 00262 struct autoip *autoip = netif->autoip; 00263 err_t result = ERR_OK; 00264 00265 if(netif_is_up(netif)) { 00266 netif_set_down(netif); 00267 } 00268 00269 /* Set IP-Address, Netmask and Gateway to 0 to make sure that 00270 * ARP Packets are formed correctly 00271 */ 00272 netif->ip_addr.addr = 0; 00273 netif->netmask.addr = 0; 00274 netif->gw.addr = 0; 00275 00276 LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, 00277 ("autoip_start(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], 00278 netif->name[1], (u16_t)netif->num)); 00279 if(autoip == NULL) { 00280 /* no AutoIP client attached yet? */ 00281 LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, 00282 ("autoip_start(): starting new AUTOIP client\n")); 00283 autoip = mem_malloc(sizeof(struct autoip)); 00284 if(autoip == NULL) { 00285 LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, 00286 ("autoip_start(): could not allocate autoip\n")); 00287 return ERR_MEM; 00288 } 00289 memset( autoip, 0, sizeof(struct autoip)); 00290 /* store this AutoIP client in the netif */ 00291 netif->autoip = autoip; 00292 LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_start(): allocated autoip")); 00293 } else { 00294 autoip->state = AUTOIP_STATE_OFF; 00295 autoip->ttw = 0; 00296 autoip->sent_num = 0; 00297 memset(&autoip->llipaddr, 0, sizeof(struct ip_addr)); 00298 autoip->lastconflict = 0; 00299 } 00300 00301 autoip_create_addr(netif, &(autoip->llipaddr)); 00302 autoip->tried_llipaddr++; 00303 autoip_start_probing(netif); 00304 00305 return result; 00306 } 00307 00308 static void 00309 autoip_start_probing(struct netif *netif) 00310 { 00311 struct autoip *autoip = netif->autoip; 00312 00313 autoip->state = AUTOIP_STATE_PROBING; 00314 autoip->sent_num = 0; 00315 00316 /* time to wait to first probe, this is randomly 00317 * choosen out of 0 to PROBE_WAIT seconds. 00318 * compliant to RFC 3927 Section 2.2.1 00319 */ 00320 autoip->ttw = (u16_t)(LWIP_AUTOIP_RAND(netif) % (PROBE_WAIT * AUTOIP_TICKS_PER_SECOND)); 00321 00322 /* 00323 * if we tried more then MAX_CONFLICTS we must limit our rate for 00324 * accquiring and probing address 00325 * compliant to RFC 3927 Section 2.2.1 00326 */ 00327 if(autoip->tried_llipaddr > MAX_CONFLICTS) { 00328 autoip->ttw = RATE_LIMIT_INTERVAL * AUTOIP_TICKS_PER_SECOND; 00329 } 00330 } 00331 00332 /** 00333 * Handle a possible change in the network configuration. 00334 * 00335 * If there is an AutoIP address configured, take the interface down 00336 * and begin probing with the same address. 00337 */ 00338 void 00339 autoip_network_changed(struct netif *netif) 00340 { 00341 if (netif->autoip && netif->autoip->state != AUTOIP_STATE_OFF) { 00342 netif_set_down(netif); 00343 autoip_start_probing(netif); 00344 } 00345 } 00346 00347 /** 00348 * Stop AutoIP client 00349 * 00350 * @param netif network interface on which stop the AutoIP client 00351 */ 00352 err_t 00353 autoip_stop(struct netif *netif) 00354 { 00355 netif->autoip->state = AUTOIP_STATE_OFF; 00356 netif_set_down(netif); 00357 return ERR_OK; 00358 } 00359 00360 /** 00361 * Has to be called in loop every AUTOIP_TMR_INTERVAL milliseconds 00362 */ 00363 void 00364 autoip_tmr() 00365 { 00366 struct netif *netif = netif_list; 00367 /* loop through netif's */ 00368 while (netif != NULL) { 00369 /* only act on AutoIP configured interfaces */ 00370 if (netif->autoip != NULL) { 00371 if(netif->autoip->lastconflict > 0) { 00372 netif->autoip->lastconflict--; 00373 } 00374 00375 LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, 00376 ("autoip_tmr() AutoIP-State: %"U16_F", ttw=%"U16_F"\n", 00377 (u16_t)(netif->autoip->state), netif->autoip->ttw)); 00378 00379 switch(netif->autoip->state) { 00380 case AUTOIP_STATE_PROBING: 00381 if(netif->autoip->ttw > 0) { 00382 netif->autoip->ttw--; 00383 } else { 00384 if(netif->autoip->sent_num >= PROBE_NUM) { 00385 netif->autoip->state = AUTOIP_STATE_ANNOUNCING; 00386 netif->autoip->sent_num = 0; 00387 netif->autoip->ttw = ANNOUNCE_WAIT * AUTOIP_TICKS_PER_SECOND; 00388 } else { 00389 autoip_arp_probe(netif); 00390 LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | 3, 00391 ("autoip_tmr() PROBING Sent Probe\n")); 00392 netif->autoip->sent_num++; 00393 /* calculate time to wait to next probe */ 00394 netif->autoip->ttw = (u16_t)((LWIP_AUTOIP_RAND(netif) % 00395 ((PROBE_MAX - PROBE_MIN) * AUTOIP_TICKS_PER_SECOND) ) + 00396 PROBE_MIN * AUTOIP_TICKS_PER_SECOND); 00397 } 00398 } 00399 break; 00400 00401 case AUTOIP_STATE_ANNOUNCING: 00402 if(netif->autoip->ttw > 0) { 00403 netif->autoip->ttw--; 00404 } else { 00405 if(netif->autoip->sent_num == 0) { 00406 /* We are here the first time, so we waited ANNOUNCE_WAIT seconds 00407 * Now we can bind to an IP address and use it. 00408 * 00409 * autoip_bind calls netif_set_up. This triggers a gratuitous ARP 00410 * which counts as an announcement. 00411 */ 00412 autoip_bind(netif); 00413 } else { 00414 autoip_arp_announce(netif); 00415 LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | 3, 00416 ("autoip_tmr() ANNOUNCING Sent Announce\n")); 00417 } 00418 netif->autoip->ttw = ANNOUNCE_INTERVAL * AUTOIP_TICKS_PER_SECOND; 00419 netif->autoip->sent_num++; 00420 00421 if(netif->autoip->sent_num >= ANNOUNCE_NUM) { 00422 netif->autoip->state = AUTOIP_STATE_BOUND; 00423 netif->autoip->sent_num = 0; 00424 netif->autoip->ttw = 0; 00425 } 00426 } 00427 break; 00428 } 00429 } 00430 /* proceed to next network interface */ 00431 netif = netif->next; 00432 } 00433 } 00434 00435 /** 00436 * Handles every incoming ARP Packet, called by etharp_arp_input. 00437 * 00438 * @param netif network interface to use for autoip processing 00439 * @param hdr Incoming ARP packet 00440 */ 00441 void 00442 autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr) 00443 { 00444 LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | 3, ("autoip_arp_reply()\n")); 00445 if ((netif->autoip != NULL) && (netif->autoip->state != AUTOIP_STATE_OFF)) { 00446 /* when ip.src == llipaddr && hw.src != netif->hwaddr 00447 * 00448 * when probing ip.dst == llipaddr && hw.src != netif->hwaddr 00449 * we have a conflict and must solve it 00450 */ 00451 struct ip_addr sipaddr, dipaddr; 00452 struct eth_addr netifaddr; 00453 netifaddr.addr[0] = netif->hwaddr[0]; 00454 netifaddr.addr[1] = netif->hwaddr[1]; 00455 netifaddr.addr[2] = netif->hwaddr[2]; 00456 netifaddr.addr[3] = netif->hwaddr[3]; 00457 netifaddr.addr[4] = netif->hwaddr[4]; 00458 netifaddr.addr[5] = netif->hwaddr[5]; 00459 00460 /* Copy struct ip_addr2 to aligned ip_addr, to support compilers without 00461 * structure packing (not using structure copy which breaks strict-aliasing rules). 00462 */ 00463 SMEMCPY(&sipaddr, &hdr->sipaddr, sizeof(sipaddr)); 00464 SMEMCPY(&dipaddr, &hdr->dipaddr, sizeof(dipaddr)); 00465 00466 if ((netif->autoip->state == AUTOIP_STATE_PROBING) || 00467 ((netif->autoip->state == AUTOIP_STATE_ANNOUNCING) && 00468 (netif->autoip->sent_num == 0))) { 00469 /* RFC 3927 Section 2.2.1: 00470 * from beginning to after ANNOUNCE_WAIT 00471 * seconds we have a conflict if 00472 * ip.src == llipaddr OR 00473 * ip.dst == llipaddr && hw.src != own hwaddr 00474 */ 00475 if ((ip_addr_cmp(&sipaddr, &netif->autoip->llipaddr)) || 00476 (ip_addr_cmp(&dipaddr, &netif->autoip->llipaddr) && 00477 !eth_addr_cmp(&netifaddr, &hdr->shwaddr))) { 00478 LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1, 00479 ("autoip_arp_reply(): Probe Conflict detected\n")); 00480 autoip_start(netif); 00481 } 00482 } else { 00483 /* RFC 3927 Section 2.5: 00484 * in any state we have a conflict if 00485 * ip.src == llipaddr && hw.src != own hwaddr 00486 */ 00487 if (ip_addr_cmp(&sipaddr, &netif->autoip->llipaddr) && 00488 !eth_addr_cmp(&netifaddr, &hdr->shwaddr)) { 00489 LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1, 00490 ("autoip_arp_reply(): Conflicting ARP-Packet detected\n")); 00491 autoip_handle_arp_conflict(netif); 00492 } 00493 } 00494 } 00495 } 00496 00497 #endif /* LWIP_AUTOIP */
Generated on Tue Jul 12 2022 20:39:37 by
1.7.2