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 (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 announce */ 00114 static err_t autoip_arp_announce(struct netif *netif); 00115 00116 /* configure interface for use with current LL IP-Address */ 00117 static err_t autoip_bind(struct netif *netif); 00118 00119 /** 00120 * Initialize this module 00121 */ 00122 void 00123 autoip_init(void) 00124 { 00125 LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | 3, ("autoip_init()\n")); 00126 } 00127 00128 /** 00129 * Handle a IP address conflict after an ARP conflict detection 00130 */ 00131 static void 00132 autoip_handle_arp_conflict(struct netif *netif) 00133 { 00134 /* Somehow detect if we are defending or retreating */ 00135 unsigned char defend = 1; /* tbd */ 00136 00137 if(defend) { 00138 if(netif->autoip->lastconflict > 0) { 00139 /* retreat, there was a conflicting ARP in the last 00140 * DEFEND_INTERVAL seconds 00141 */ 00142 LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1, 00143 ("autoip_handle_arp_conflict(): we are defending, but in DEFEND_INTERVAL, retreating\n")); 00144 00145 /* TODO: close all TCP sessions */ 00146 autoip_start(netif); 00147 } else { 00148 LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1, 00149 ("autoip_handle_arp_conflict(): we are defend, send ARP Announce\n")); 00150 autoip_arp_announce(netif); 00151 netif->autoip->lastconflict = DEFEND_INTERVAL * AUTOIP_TICKS_PER_SECOND; 00152 } 00153 } else { 00154 LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1, 00155 ("autoip_handle_arp_conflict(): we do not defend, retreating\n")); 00156 /* TODO: close all TCP sessions */ 00157 autoip_start(netif); 00158 } 00159 } 00160 00161 /** 00162 * Create an IP-Address out of range 169.254.1.0 to 169.254.254.255 00163 * 00164 * @param netif network interface on which create the IP-Address 00165 * @param IPAddr ip address to initialize 00166 */ 00167 static void 00168 autoip_create_addr(struct netif *netif, struct ip_addr *IPAddr) 00169 { 00170 /* Here we create an IP-Address out of range 169.254.1.0 to 169.254.254.255 00171 * compliant to RFC 3927 Section 2.1 00172 * We have 254 * 256 possibilities */ 00173 00174 u32_t addr = ntohl(LWIP_AUTOIP_CREATE_SEED_ADDR(netif)); 00175 addr += netif->autoip->tried_llipaddr; 00176 addr = AUTOIP_NET | (addr & 0xffff); 00177 /* Now, 169.254.0.0 <= addr <= 169.254.255.255 */ 00178 00179 if (addr < AUTOIP_RANGE_START) { 00180 addr += AUTOIP_RANGE_END - AUTOIP_RANGE_START + 1; 00181 } 00182 if (addr > AUTOIP_RANGE_END) { 00183 addr -= AUTOIP_RANGE_END - AUTOIP_RANGE_START + 1; 00184 } 00185 LWIP_ASSERT("AUTOIP address not in range", (addr >= AUTOIP_RANGE_START) && 00186 (addr <= AUTOIP_RANGE_END)); 00187 IPAddr->addr = htonl(addr); 00188 00189 LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1, 00190 ("autoip_create_addr(): tried_llipaddr=%"U16_F", 0x%08"X32_F"\n", 00191 (u16_t)(netif->autoip->tried_llipaddr), (u32_t)(IPAddr->addr))); 00192 } 00193 00194 /** 00195 * Sends an ARP announce from a network interface 00196 * 00197 * @param netif network interface used to send the announce 00198 */ 00199 static err_t 00200 autoip_arp_announce(struct netif *netif) 00201 { 00202 return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, ðbroadcast, 00203 (struct eth_addr *)netif->hwaddr, &netif->autoip->llipaddr, ðzero, 00204 &netif->autoip->llipaddr, ARP_REQUEST); 00205 } 00206 00207 /** 00208 * Configure interface for use with current LL IP-Address 00209 * 00210 * @param netif network interface to configure with current LL IP-Address 00211 */ 00212 static err_t 00213 autoip_bind(struct netif *netif) 00214 { 00215 struct autoip *autoip = netif->autoip; 00216 struct ip_addr sn_mask, gw_addr; 00217 00218 LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | 3, 00219 ("autoip_bind(netif=%p) %c%c%"U16_F" 0x%08"X32_F"\n", 00220 (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num, autoip->llipaddr.addr)); 00221 00222 IP4_ADDR(&sn_mask, 255, 255, 0, 0); 00223 IP4_ADDR(&gw_addr, 0, 0, 0, 0); 00224 00225 netif_set_ipaddr(netif, &autoip->llipaddr); 00226 netif_set_netmask(netif, &sn_mask); 00227 netif_set_gw(netif, &gw_addr); 00228 00229 /* bring the interface up */ 00230 netif_set_up(netif); 00231 00232 return ERR_OK; 00233 } 00234 00235 /** 00236 * Start AutoIP client 00237 * 00238 * @param netif network interface on which start the AutoIP client 00239 */ 00240 err_t 00241 autoip_start(struct netif *netif) 00242 { 00243 struct autoip *autoip = netif->autoip; 00244 err_t result = ERR_OK; 00245 00246 if(netif_is_up(netif)) { 00247 netif_set_down(netif); 00248 } 00249 00250 /* Set IP-Address, Netmask and Gateway to 0 to make sure that 00251 * ARP Packets are formed correctly 00252 */ 00253 netif->ip_addr.addr = 0; 00254 netif->netmask.addr = 0; 00255 netif->gw.addr = 0; 00256 00257 LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, 00258 ("autoip_start(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], 00259 netif->name[1], (u16_t)netif->num)); 00260 if(autoip == NULL) { 00261 /* no AutoIP client attached yet? */ 00262 LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, 00263 ("autoip_start(): starting new AUTOIP client\n")); 00264 autoip = (struct autoip *)mem_malloc(sizeof(struct autoip)); // static_cast<struct autoip *>(x) 00265 if(autoip == NULL) { 00266 LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, 00267 ("autoip_start(): could not allocate autoip\n")); 00268 return ERR_MEM; 00269 } 00270 memset( autoip, 0, sizeof(struct autoip)); 00271 /* store this AutoIP client in the netif */ 00272 netif->autoip = autoip; 00273 LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_start(): allocated autoip")); 00274 } else { 00275 autoip->state = AUTOIP_STATE_OFF; 00276 autoip->ttw = 0; 00277 autoip->sent_num = 0; 00278 memset(&autoip->llipaddr, 0, sizeof(struct ip_addr)); 00279 autoip->lastconflict = 0; 00280 } 00281 00282 autoip_create_addr(netif, &(autoip->llipaddr)); 00283 autoip->tried_llipaddr++; 00284 autoip->state = AUTOIP_STATE_PROBING; 00285 autoip->sent_num = 0; 00286 00287 /* time to wait to first probe, this is randomly 00288 * choosen out of 0 to PROBE_WAIT seconds. 00289 * compliant to RFC 3927 Section 2.2.1 00290 */ 00291 autoip->ttw = (u16_t)(LWIP_AUTOIP_RAND(netif) % (PROBE_WAIT * AUTOIP_TICKS_PER_SECOND)); 00292 00293 /* 00294 * if we tried more then MAX_CONFLICTS we must limit our rate for 00295 * accquiring and probing address 00296 * compliant to RFC 3927 Section 2.2.1 00297 */ 00298 00299 if(autoip->tried_llipaddr > MAX_CONFLICTS) { 00300 autoip->ttw = RATE_LIMIT_INTERVAL * AUTOIP_TICKS_PER_SECOND; 00301 } 00302 00303 return result; 00304 } 00305 00306 /** 00307 * Stop AutoIP client 00308 * 00309 * @param netif network interface on which stop the AutoIP client 00310 */ 00311 err_t 00312 autoip_stop(struct netif *netif) 00313 { 00314 netif->autoip->state = AUTOIP_STATE_OFF; 00315 netif_set_down(netif); 00316 return ERR_OK; 00317 } 00318 00319 /** 00320 * Has to be called in loop every AUTOIP_TMR_INTERVAL milliseconds 00321 */ 00322 void 00323 autoip_tmr() 00324 { 00325 struct netif *netif = netif_list; 00326 /* loop through netif's */ 00327 while (netif != NULL) { 00328 /* only act on AutoIP configured interfaces */ 00329 if (netif->autoip != NULL) { 00330 if(netif->autoip->lastconflict > 0) { 00331 netif->autoip->lastconflict--; 00332 } 00333 00334 LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, 00335 ("autoip_tmr() AutoIP-State: %"U16_F", ttw=%"U16_F"\n", 00336 (u16_t)(netif->autoip->state), netif->autoip->ttw)); 00337 00338 switch(netif->autoip->state) { 00339 case AUTOIP_STATE_PROBING: 00340 if(netif->autoip->ttw > 0) { 00341 netif->autoip->ttw--; 00342 } else { 00343 if(netif->autoip->sent_num == PROBE_NUM) { 00344 netif->autoip->state = AUTOIP_STATE_ANNOUNCING; 00345 netif->autoip->sent_num = 0; 00346 netif->autoip->ttw = ANNOUNCE_WAIT * AUTOIP_TICKS_PER_SECOND; 00347 } else { 00348 etharp_request(netif, &(netif->autoip->llipaddr)); 00349 LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | 3, 00350 ("autoip_tmr() PROBING Sent Probe\n")); 00351 netif->autoip->sent_num++; 00352 /* calculate time to wait to next probe */ 00353 netif->autoip->ttw = (u16_t)((LWIP_AUTOIP_RAND(netif) % 00354 ((PROBE_MAX - PROBE_MIN) * AUTOIP_TICKS_PER_SECOND) ) + 00355 PROBE_MIN * AUTOIP_TICKS_PER_SECOND); 00356 } 00357 } 00358 break; 00359 00360 case AUTOIP_STATE_ANNOUNCING: 00361 if(netif->autoip->ttw > 0) { 00362 netif->autoip->ttw--; 00363 } else { 00364 if(netif->autoip->sent_num == 0) { 00365 /* We are here the first time, so we waited ANNOUNCE_WAIT seconds 00366 * Now we can bind to an IP address and use it 00367 */ 00368 autoip_bind(netif); 00369 } 00370 00371 if(netif->autoip->sent_num == ANNOUNCE_NUM) { 00372 netif->autoip->state = AUTOIP_STATE_BOUND; 00373 netif->autoip->sent_num = 0; 00374 netif->autoip->ttw = 0; 00375 } else { 00376 autoip_arp_announce(netif); 00377 LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | 3, 00378 ("autoip_tmr() ANNOUNCING Sent Announce\n")); 00379 netif->autoip->sent_num++; 00380 netif->autoip->ttw = ANNOUNCE_INTERVAL * AUTOIP_TICKS_PER_SECOND; 00381 } 00382 } 00383 break; 00384 } 00385 } 00386 /* proceed to next network interface */ 00387 netif = netif->next; 00388 } 00389 } 00390 00391 /** 00392 * Handles every incoming ARP Packet, called by etharp_arp_input. 00393 * 00394 * @param netif network interface to use for autoip processing 00395 * @param hdr Incoming ARP packet 00396 */ 00397 void 00398 autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr) 00399 { 00400 LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | 3, ("autoip_arp_reply()\n")); 00401 if ((netif->autoip != NULL) && (netif->autoip->state != AUTOIP_STATE_OFF)) { 00402 /* when ip.src == llipaddr && hw.src != netif->hwaddr 00403 * 00404 * when probing ip.dst == llipaddr && hw.src != netif->hwaddr 00405 * we have a conflict and must solve it 00406 */ 00407 struct ip_addr sipaddr, dipaddr; 00408 struct eth_addr netifaddr; 00409 netifaddr.addr[0] = netif->hwaddr[0]; 00410 netifaddr.addr[1] = netif->hwaddr[1]; 00411 netifaddr.addr[2] = netif->hwaddr[2]; 00412 netifaddr.addr[3] = netif->hwaddr[3]; 00413 netifaddr.addr[4] = netif->hwaddr[4]; 00414 netifaddr.addr[5] = netif->hwaddr[5]; 00415 00416 /* Copy struct ip_addr2 to aligned ip_addr, to support compilers without 00417 * structure packing (not using structure copy which breaks strict-aliasing rules). 00418 */ 00419 SMEMCPY(&sipaddr, &hdr->sipaddr, sizeof(sipaddr)); 00420 SMEMCPY(&dipaddr, &hdr->dipaddr, sizeof(dipaddr)); 00421 00422 if ((netif->autoip->state == AUTOIP_STATE_PROBING) || 00423 ((netif->autoip->state == AUTOIP_STATE_ANNOUNCING) && 00424 (netif->autoip->sent_num == 0))) { 00425 /* RFC 3927 Section 2.2.1: 00426 * from beginning to after ANNOUNCE_WAIT 00427 * seconds we have a conflict if 00428 * ip.src == llipaddr OR 00429 * ip.dst == llipaddr && hw.src != own hwaddr 00430 */ 00431 if ((ip_addr_cmp(&sipaddr, &netif->autoip->llipaddr)) || 00432 (ip_addr_cmp(&dipaddr, &netif->autoip->llipaddr) && 00433 !eth_addr_cmp(&netifaddr, &hdr->shwaddr))) { 00434 LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1, 00435 ("autoip_arp_reply(): Probe Conflict detected\n")); 00436 autoip_start(netif); 00437 } 00438 } else { 00439 /* RFC 3927 Section 2.5: 00440 * in any state we have a conflict if 00441 * ip.src == llipaddr && hw.src != own hwaddr 00442 */ 00443 if (ip_addr_cmp(&sipaddr, &netif->autoip->llipaddr) && 00444 !eth_addr_cmp(&netifaddr, &hdr->shwaddr)) { 00445 LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1, 00446 ("autoip_arp_reply(): Conflicting ARP-Packet detected\n")); 00447 autoip_handle_arp_conflict(netif); 00448 } 00449 } 00450 } 00451 } 00452 00453 #endif /* LWIP_AUTOIP */
Generated on Tue Jul 12 2022 19:24:05 by
1.7.2