00001 /*############################################################################## 00002 00003 nIP - nano IP stack 00004 00005 File : autoip.c 00006 00007 Description : Implementation of Dynamic Configuration of IPv4 Link-Local 00008 Addresses (according to RFC 3927) 00009 00010 Copyright notice: 00011 00012 Copyright (C) 2005 - 00013 Andreas Dittrich, dittrich@informatik.hu-berlin.de 00014 Jon Kowal, kowal@informatik.hu-berlin.de 00015 00016 This program is free software; you can redistribute it and/or 00017 modify it under the terms of the GNU General Public License 00018 as published by the Free Software Foundation; either version 2 00019 of the License, or (at your option) any later version. 00020 00021 This program is distributed in the hope that it will be useful, 00022 but WITHOUT ANY WARRANTY; without even the implied warranty of 00023 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00024 GNU General Public License for more details. 00025 00026 You should have received a copy of the GNU General Public License 00027 along with this program; if not, write to the Free Software 00028 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 00029 00030 ##############################################################################*/ 00031 00032 #include "dispatcher.h" 00033 #include "inet.h" 00034 #include "net/autoip.h" 00035 #include "net/arp.h" 00036 #include "net/net_if.h" 00037 #include "net/ip.h" 00038 #include "os_core.h" 00039 00040 #if ( NIP_AUTOIP_ENABLE == 1 ) 00041 00042 00043 #if NIP_NET_IF_COUNT > 1 00044 struct nip_autoip_conf nip_autoip_conf[ NIP_NET_IF_COUNT ] ; 00045 #define NIP_AUTOIP_CONF( if_id ) nip_autoip_conf[if_id] 00046 #else 00047 struct nip_autoip_conf nip_autoip_conf; 00048 #define NIP_AUTOIP_CONF( if_id ) nip_autoip_conf 00049 #endif 00050 00051 /** Enable Dynamic Configuration of IPv4 Link-Local Addresses for given 00052 * interface. 00053 */ 00054 void nip_autoip_start( nip_net_if_id_t net_if ) 00055 { 00056 NIP_AUTOIP_CONF(net_if).state = NIP_AUTOIP_STAT_INIT; 00057 NIP_AUTOIP_CONF(net_if).t = nip_tickcount() + NIP_AUTOIP_PROBE_WAIT; 00058 } 00059 00060 00061 /** Function to be called by dispatcher to check AutoIP state 00062 */ 00063 void nip_autoip_disp_check( void ) 00064 { 00065 // use different mechanisms to access autoip configuration for the single and 00066 // the multi interface cases to minimize use of program memory in either case 00067 #if NIP_NET_IF_COUNT > 1 00068 struct nip_autoip_conf *conf = & NIP_AUTOIP_CONF( NIP_CURR_IF ); 00069 #define CONF_ATTR(attr) conf-> attr 00070 #else 00071 #define CONF_ATTR(attr) nip_autoip_conf.attr 00072 #endif 00073 nip_time_t tc = nip_tickcount(); 00074 nip_net_if_t *net_if = & nip_net_if_list[ NIP_CURR_IF ]; 00075 uint8_t *addr_ptr = &net_if->phy_conf.hw_addr[ net_if->phy_conf.hw_addr_size-4]; 00076 00077 // Don't perform any checks, if AutoIP is disabled. Also double check, that 00078 // we're not interfering with any other IP-setting instance (e.g. DHCP). 00079 if ( CONF_ATTR(state) == NIP_AUTOIP_STAT_DISABLED 00080 || (net_if->ip_conf.state == NIP_IP_CONF_STAT_CONFIGURED 00081 && memcmp( net_if->ip_conf.addr, CONF_ATTR(addr), 4 ) != 0) 00082 ) 00083 { 00084 return; 00085 } 00086 00087 // Upon conflict choose new IP address 00088 if ( CONF_ATTR(state) == NIP_AUTOIP_STAT_CONFLICT ) 00089 { 00090 if ( CONF_ATTR(conflict_cnt) < 255 ) 00091 CONF_ATTR(conflict_cnt)++; 00092 else 00093 CONF_ATTR(addr)[2]++; 00094 00095 CONF_ATTR(addr)[3] += addr_ptr[0]+addr_ptr[3]; 00096 00097 // set new timeout for next probe 00098 if ( CONF_ATTR(conflict_cnt) > NIP_AUTOIP_MAX_CONFLICTS ) 00099 CONF_ATTR(t) += NIP_AUTOIP_RATE_LIMIT_INTERVAL; 00100 00101 // reset probe mechanism 00102 CONF_ATTR(cnt) = 0; 00103 CONF_ATTR(state) = NIP_AUTOIP_STAT_PROBE; 00104 net_if->ip_conf.state = NIP_IP_CONF_STAT_UNCONFIGURED; 00105 } 00106 00107 // all states except CONFLICT which is handled above are time triggered 00108 if ( tc >= CONF_ATTR(t) ) 00109 { 00110 switch ( CONF_ATTR( state ) ) 00111 { 00112 case NIP_AUTOIP_STAT_INIT: 00113 CONF_ATTR(conflict_cnt) = 0; 00114 // select IP address based on hardware address 00115 CONF_ATTR(addr)[0] = 169; 00116 CONF_ATTR(addr)[1] = 254; 00117 CONF_ATTR(addr)[2] = addr_ptr[0]+addr_ptr[1]; 00118 CONF_ATTR(addr)[3] = addr_ptr[2]+addr_ptr[3]; 00119 00120 // send probes 00121 CONF_ATTR(cnt) = 0; 00122 CONF_ATTR(state) = NIP_AUTOIP_STAT_PROBE; 00123 goto probe; 00124 00125 case NIP_AUTOIP_STAT_PROBE: 00126 goto probe; 00127 00128 case NIP_AUTOIP_STAT_ANNOUNCE: 00129 goto announce; 00130 00131 default: 00132 // don't do anything if autoip is UP or DISABLED 00133 // just wait for conflicts 00134 break; 00135 } 00136 } 00137 00138 return; 00139 00140 probe: 00141 00142 // check counter and switch to ANNOUNCE state if PROBE_NUM has been 00143 // reached. 00144 if ( ++CONF_ATTR(cnt) < NIP_AUTOIP_PROBE_NUM ) 00145 { 00146 // set timeout for next probe 00147 CONF_ATTR(t) = tc + NIP_AUTOIP_PROBE_MAX; 00148 } 00149 else 00150 { 00151 // announce new address 00152 CONF_ATTR(cnt) = 0; 00153 CONF_ATTR(t) = tc + NIP_AUTOIP_ANNOUNCE_WAIT; 00154 CONF_ATTR(state) = NIP_AUTOIP_STAT_ANNOUNCE; 00155 } 00156 00157 // clear IP address and send ARP Probe 00158 nip_memset( net_if->ip_conf.addr, 0, 4 ); 00159 NIP_CURR_CMD = &nip_arp_disp_probe_announcement; 00160 00161 return; 00162 00163 announce: 00164 00165 // check announcement counter 00166 if ( ++CONF_ATTR(cnt) < NIP_AUTOIP_ANNOUNCE_NUM ) 00167 { 00168 CONF_ATTR(t) = tc + NIP_AUTOIP_ANNOUNCE_INTERVAL; 00169 } 00170 else 00171 { 00172 CONF_ATTR(cnt) = 0; 00173 CONF_ATTR(state) = NIP_AUTOIP_STAT_UP; 00174 } 00175 00176 // set IP address and send ARP announcement 00177 nip_ip_addr_set( NIP_CURR_IF, CONF_ATTR(addr) ); 00178 NIP_CURR_CMD = &nip_arp_disp_probe_announcement; 00179 00180 return; 00181 } 00182 00183 /** Check incoming ARP packet for conflict with current link-local configuration 00184 */ 00185 void nip_autoip_arpcheck( nip_net_if_id_t if_id, struct ARP_PACKET *arp ) 00186 { 00187 // nip_net_if_t *net_if = &nip_net_if_list[ if_id ]; 00188 #if NIP_NET_IF_COUNT > 1 00189 struct nip_autoip_conf *conf = & NIP_AUTOIP_CONF( NIP_CURR_IF ); 00190 #define CONF_ATTR(attr) conf-> attr 00191 #else 00192 #define CONF_ATTR(attr) nip_autoip_conf.attr 00193 #endif 00194 00195 // if sender address matches own address -> conflict 00196 if ( nip_memcmp( arp->spa, CONF_ATTR(addr), 4 ) == 0 ) 00197 { 00198 NIP_AUTOIP_CONF(if_id).state = NIP_AUTOIP_STAT_CONFLICT; 00199 nip_disp_notify_if( if_id, NIP_DISP_IF_AUTOIP ); 00200 } 00201 00202 } 00203 00204 00205 #endif // NIP_AUTOIP_ENABLE