First step: AutoIP compiled in and working

Dependencies:   mbed

Committer:
darran
Date:
Fri Jun 18 15:54:21 2010 +0000
Revision:
1:4218cacaf696
Parent:
0:55a05330f8cc

        

Who changed what in which revision?

UserRevisionLine numberNew contents of line
darran 0:55a05330f8cc 1 /**
darran 0:55a05330f8cc 2 * @file
darran 0:55a05330f8cc 3 * AutoIP Automatic LinkLocal IP Configuration
darran 0:55a05330f8cc 4 *
darran 0:55a05330f8cc 5 */
darran 0:55a05330f8cc 6
darran 0:55a05330f8cc 7 /*
darran 0:55a05330f8cc 8 *
darran 0:55a05330f8cc 9 * Copyright (c) 2007 Dominik Spies <kontakt@dspies.de>
darran 0:55a05330f8cc 10 * All rights reserved.
darran 0:55a05330f8cc 11 *
darran 0:55a05330f8cc 12 * Redistribution and use in source and binary forms, with or without modification,
darran 0:55a05330f8cc 13 * are permitted provided that the following conditions are met:
darran 0:55a05330f8cc 14 *
darran 0:55a05330f8cc 15 * 1. Redistributions of source code must retain the above copyright notice,
darran 0:55a05330f8cc 16 * this list of conditions and the following disclaimer.
darran 0:55a05330f8cc 17 * 2. Redistributions in binary form must reproduce the above copyright notice,
darran 0:55a05330f8cc 18 * this list of conditions and the following disclaimer in the documentation
darran 0:55a05330f8cc 19 * and/or other materials provided with the distribution.
darran 0:55a05330f8cc 20 * 3. The name of the author may not be used to endorse or promote products
darran 0:55a05330f8cc 21 * derived from this software without specific prior written permission.
darran 0:55a05330f8cc 22 *
darran 0:55a05330f8cc 23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
darran 0:55a05330f8cc 24 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
darran 0:55a05330f8cc 25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
darran 0:55a05330f8cc 26 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
darran 0:55a05330f8cc 27 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
darran 0:55a05330f8cc 28 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
darran 0:55a05330f8cc 29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
darran 0:55a05330f8cc 30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
darran 0:55a05330f8cc 31 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
darran 0:55a05330f8cc 32 * OF SUCH DAMAGE.
darran 0:55a05330f8cc 33 *
darran 0:55a05330f8cc 34 * Author: Dominik Spies <kontakt@dspies.de>
darran 0:55a05330f8cc 35 *
darran 0:55a05330f8cc 36 * This is a AutoIP implementation for the lwIP TCP/IP stack. It aims to conform
darran 0:55a05330f8cc 37 * with RFC 3927.
darran 0:55a05330f8cc 38 *
darran 0:55a05330f8cc 39 *
darran 0:55a05330f8cc 40 * Please coordinate changes and requests with Dominik Spies
darran 0:55a05330f8cc 41 * <kontakt@dspies.de>
darran 0:55a05330f8cc 42 */
darran 0:55a05330f8cc 43
darran 0:55a05330f8cc 44 /*******************************************************************************
darran 0:55a05330f8cc 45 * USAGE:
darran 0:55a05330f8cc 46 *
darran 0:55a05330f8cc 47 * define LWIP_AUTOIP 1 in your lwipopts.h
darran 0:55a05330f8cc 48 *
darran 0:55a05330f8cc 49 * If you don't use tcpip.c (so, don't call, you don't call tcpip_init):
darran 0:55a05330f8cc 50 * - First, call autoip_init().
darran 0:55a05330f8cc 51 * - call autoip_tmr() all AUTOIP_TMR_INTERVAL msces,
darran 0:55a05330f8cc 52 * that should be defined in autoip.h.
darran 0:55a05330f8cc 53 * I recommend a value of 100. The value must divide 1000 with a remainder almost 0.
darran 0:55a05330f8cc 54 * Possible values are 1000, 500, 333, 250, 200, 166, 142, 125, 111, 100 ....
darran 0:55a05330f8cc 55 *
darran 0:55a05330f8cc 56 * Without DHCP:
darran 0:55a05330f8cc 57 * - Call autoip_start() after netif_add().
darran 0:55a05330f8cc 58 *
darran 0:55a05330f8cc 59 * With DHCP:
darran 0:55a05330f8cc 60 * - define LWIP_DHCP_AUTOIP_COOP 1 in your lwipopts.h.
darran 0:55a05330f8cc 61 * - Configure your DHCP Client.
darran 0:55a05330f8cc 62 *
darran 0:55a05330f8cc 63 */
darran 0:55a05330f8cc 64
darran 0:55a05330f8cc 65 #include "lwip/opt.h"
darran 0:55a05330f8cc 66
darran 0:55a05330f8cc 67 #if LWIP_AUTOIP /* don't build if not configured for use in lwipopts.h */
darran 0:55a05330f8cc 68
darran 0:55a05330f8cc 69 #include "lwip/mem.h"
darran 0:55a05330f8cc 70 #include "lwip/udp.h"
darran 0:55a05330f8cc 71 #include "lwip/ip_addr.h"
darran 0:55a05330f8cc 72 #include "lwip/netif.h"
darran 0:55a05330f8cc 73 #include "lwip/autoip.h"
darran 0:55a05330f8cc 74 #include "netif/etharp.h"
darran 0:55a05330f8cc 75
darran 0:55a05330f8cc 76 #include <stdlib.h>
darran 0:55a05330f8cc 77 #include <string.h>
darran 0:55a05330f8cc 78
darran 0:55a05330f8cc 79 /* 169.254.0.0 */
darran 0:55a05330f8cc 80 #define AUTOIP_NET 0xA9FE0000
darran 0:55a05330f8cc 81 /* 169.254.1.0 */
darran 0:55a05330f8cc 82 #define AUTOIP_RANGE_START (AUTOIP_NET | 0x0100)
darran 0:55a05330f8cc 83 /* 169.254.254.255 */
darran 0:55a05330f8cc 84 #define AUTOIP_RANGE_END (AUTOIP_NET | 0xFEFF)
darran 0:55a05330f8cc 85
darran 0:55a05330f8cc 86
darran 0:55a05330f8cc 87 /** Pseudo random macro based on netif informations.
darran 0:55a05330f8cc 88 * You could use "rand()" from the C Library if you define LWIP_AUTOIP_RAND in lwipopts.h */
darran 0:55a05330f8cc 89 #ifndef LWIP_AUTOIP_RAND
darran 0:55a05330f8cc 90 #define LWIP_AUTOIP_RAND(netif) ( (((u32_t)((netif->hwaddr[5]) & 0xff) << 24) | \
darran 0:55a05330f8cc 91 ((u32_t)((netif->hwaddr[3]) & 0xff) << 16) | \
darran 0:55a05330f8cc 92 ((u32_t)((netif->hwaddr[2]) & 0xff) << 8) | \
darran 0:55a05330f8cc 93 ((u32_t)((netif->hwaddr[4]) & 0xff))) + \
darran 0:55a05330f8cc 94 (netif->autoip?netif->autoip->tried_llipaddr:0))
darran 0:55a05330f8cc 95 #endif /* LWIP_AUTOIP_RAND */
darran 0:55a05330f8cc 96
darran 0:55a05330f8cc 97 /**
darran 0:55a05330f8cc 98 * Macro that generates the initial IP address to be tried by AUTOIP.
darran 0:55a05330f8cc 99 * If you want to override this, define it to something else in lwipopts.h.
darran 0:55a05330f8cc 100 */
darran 0:55a05330f8cc 101 #ifndef LWIP_AUTOIP_CREATE_SEED_ADDR
darran 0:55a05330f8cc 102 #define LWIP_AUTOIP_CREATE_SEED_ADDR(netif) \
darran 0:55a05330f8cc 103 htonl(AUTOIP_RANGE_START + ((u32_t)(((u8_t)(netif->hwaddr[4])) | \
darran 0:55a05330f8cc 104 ((u32_t)((u8_t)(netif->hwaddr[5]))) << 8)))
darran 0:55a05330f8cc 105 #endif /* LWIP_AUTOIP_CREATE_SEED_ADDR */
darran 0:55a05330f8cc 106
darran 0:55a05330f8cc 107 /* static functions */
darran 0:55a05330f8cc 108 static void autoip_handle_arp_conflict(struct netif *netif);
darran 0:55a05330f8cc 109
darran 0:55a05330f8cc 110 /* creates a pseudo random LL IP-Address for a network interface */
darran 0:55a05330f8cc 111 static void autoip_create_addr(struct netif *netif, ip_addr_t *ipaddr);
darran 0:55a05330f8cc 112
darran 0:55a05330f8cc 113 /* sends an ARP probe */
darran 0:55a05330f8cc 114 static err_t autoip_arp_probe(struct netif *netif);
darran 0:55a05330f8cc 115
darran 0:55a05330f8cc 116 /* sends an ARP announce */
darran 0:55a05330f8cc 117 static err_t autoip_arp_announce(struct netif *netif);
darran 0:55a05330f8cc 118
darran 0:55a05330f8cc 119 /* configure interface for use with current LL IP-Address */
darran 0:55a05330f8cc 120 static err_t autoip_bind(struct netif *netif);
darran 0:55a05330f8cc 121
darran 0:55a05330f8cc 122 /* start sending probes for llipaddr */
darran 0:55a05330f8cc 123 static void autoip_start_probing(struct netif *netif);
darran 0:55a05330f8cc 124
darran 0:55a05330f8cc 125 /**
darran 0:55a05330f8cc 126 * Initialize this module
darran 0:55a05330f8cc 127 */
darran 0:55a05330f8cc 128 void
darran 0:55a05330f8cc 129 autoip_init(void)
darran 0:55a05330f8cc 130 {
darran 0:55a05330f8cc 131 LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_init()\n"));
darran 0:55a05330f8cc 132 }
darran 0:55a05330f8cc 133
darran 0:55a05330f8cc 134 /** Set a statically allocated struct autoip to work with.
darran 0:55a05330f8cc 135 * Using this prevents autoip_start to allocate it using mem_malloc.
darran 0:55a05330f8cc 136 *
darran 0:55a05330f8cc 137 * @param netif the netif for which to set the struct autoip
darran 0:55a05330f8cc 138 * @param dhcp (uninitialised) dhcp struct allocated by the application
darran 0:55a05330f8cc 139 */
darran 0:55a05330f8cc 140 void
darran 0:55a05330f8cc 141 autoip_set_struct(struct netif *netif, struct autoip *autoip)
darran 0:55a05330f8cc 142 {
darran 0:55a05330f8cc 143 LWIP_ASSERT("netif != NULL", netif != NULL);
darran 0:55a05330f8cc 144 LWIP_ASSERT("autoip != NULL", autoip != NULL);
darran 0:55a05330f8cc 145 LWIP_ASSERT("netif already has a struct autoip set", netif->autoip == NULL);
darran 0:55a05330f8cc 146
darran 0:55a05330f8cc 147 /* clear data structure */
darran 0:55a05330f8cc 148 memset(autoip, 0, sizeof(struct autoip));
darran 0:55a05330f8cc 149 /* autoip->state = AUTOIP_STATE_OFF; */
darran 0:55a05330f8cc 150 netif->autoip = autoip;
darran 0:55a05330f8cc 151 }
darran 0:55a05330f8cc 152
darran 0:55a05330f8cc 153 /**
darran 0:55a05330f8cc 154 * Handle a IP address conflict after an ARP conflict detection
darran 0:55a05330f8cc 155 */
darran 0:55a05330f8cc 156 static void
darran 0:55a05330f8cc 157 autoip_handle_arp_conflict(struct netif *netif)
darran 0:55a05330f8cc 158 {
darran 0:55a05330f8cc 159 /* Somehow detect if we are defending or retreating */
darran 0:55a05330f8cc 160 unsigned char defend = 1; /* tbd */
darran 0:55a05330f8cc 161
darran 0:55a05330f8cc 162 if(defend) {
darran 0:55a05330f8cc 163 if(netif->autoip->lastconflict > 0) {
darran 0:55a05330f8cc 164 /* retreat, there was a conflicting ARP in the last
darran 0:55a05330f8cc 165 * DEFEND_INTERVAL seconds
darran 0:55a05330f8cc 166 */
darran 0:55a05330f8cc 167 LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
darran 0:55a05330f8cc 168 ("autoip_handle_arp_conflict(): we are defending, but in DEFEND_INTERVAL, retreating\n"));
darran 0:55a05330f8cc 169
darran 0:55a05330f8cc 170 /* TODO: close all TCP sessions */
darran 0:55a05330f8cc 171 autoip_start(netif);
darran 0:55a05330f8cc 172 } else {
darran 0:55a05330f8cc 173 LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
darran 0:55a05330f8cc 174 ("autoip_handle_arp_conflict(): we are defend, send ARP Announce\n"));
darran 0:55a05330f8cc 175 autoip_arp_announce(netif);
darran 0:55a05330f8cc 176 netif->autoip->lastconflict = DEFEND_INTERVAL * AUTOIP_TICKS_PER_SECOND;
darran 0:55a05330f8cc 177 }
darran 0:55a05330f8cc 178 } else {
darran 0:55a05330f8cc 179 LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
darran 0:55a05330f8cc 180 ("autoip_handle_arp_conflict(): we do not defend, retreating\n"));
darran 0:55a05330f8cc 181 /* TODO: close all TCP sessions */
darran 0:55a05330f8cc 182 autoip_start(netif);
darran 0:55a05330f8cc 183 }
darran 0:55a05330f8cc 184 }
darran 0:55a05330f8cc 185
darran 0:55a05330f8cc 186 /**
darran 0:55a05330f8cc 187 * Create an IP-Address out of range 169.254.1.0 to 169.254.254.255
darran 0:55a05330f8cc 188 *
darran 0:55a05330f8cc 189 * @param netif network interface on which create the IP-Address
darran 0:55a05330f8cc 190 * @param ipaddr ip address to initialize
darran 0:55a05330f8cc 191 */
darran 0:55a05330f8cc 192 static void
darran 0:55a05330f8cc 193 autoip_create_addr(struct netif *netif, ip_addr_t *ipaddr)
darran 0:55a05330f8cc 194 {
darran 0:55a05330f8cc 195 /* Here we create an IP-Address out of range 169.254.1.0 to 169.254.254.255
darran 0:55a05330f8cc 196 * compliant to RFC 3927 Section 2.1
darran 0:55a05330f8cc 197 * We have 254 * 256 possibilities */
darran 0:55a05330f8cc 198
darran 0:55a05330f8cc 199 u32_t addr = ntohl(LWIP_AUTOIP_CREATE_SEED_ADDR(netif));
darran 0:55a05330f8cc 200 addr += netif->autoip->tried_llipaddr;
darran 0:55a05330f8cc 201 addr = AUTOIP_NET | (addr & 0xffff);
darran 0:55a05330f8cc 202 /* Now, 169.254.0.0 <= addr <= 169.254.255.255 */
darran 0:55a05330f8cc 203
darran 0:55a05330f8cc 204 if (addr < AUTOIP_RANGE_START) {
darran 0:55a05330f8cc 205 addr += AUTOIP_RANGE_END - AUTOIP_RANGE_START + 1;
darran 0:55a05330f8cc 206 }
darran 0:55a05330f8cc 207 if (addr > AUTOIP_RANGE_END) {
darran 0:55a05330f8cc 208 addr -= AUTOIP_RANGE_END - AUTOIP_RANGE_START + 1;
darran 0:55a05330f8cc 209 }
darran 0:55a05330f8cc 210 LWIP_ASSERT("AUTOIP address not in range", (addr >= AUTOIP_RANGE_START) &&
darran 0:55a05330f8cc 211 (addr <= AUTOIP_RANGE_END));
darran 0:55a05330f8cc 212 ip4_addr_set_u32(ipaddr, htonl(addr));
darran 0:55a05330f8cc 213
darran 0:55a05330f8cc 214 LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
darran 0:55a05330f8cc 215 ("autoip_create_addr(): tried_llipaddr=%"U16_F", %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
darran 0:55a05330f8cc 216 (u16_t)(netif->autoip->tried_llipaddr), ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr),
darran 0:55a05330f8cc 217 ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr)));
darran 0:55a05330f8cc 218 }
darran 0:55a05330f8cc 219
darran 0:55a05330f8cc 220 /**
darran 0:55a05330f8cc 221 * Sends an ARP probe from a network interface
darran 0:55a05330f8cc 222 *
darran 0:55a05330f8cc 223 * @param netif network interface used to send the probe
darran 0:55a05330f8cc 224 */
darran 0:55a05330f8cc 225 static err_t
darran 0:55a05330f8cc 226 autoip_arp_probe(struct netif *netif)
darran 0:55a05330f8cc 227 {
darran 0:55a05330f8cc 228 return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, &ethbroadcast,
darran 0:55a05330f8cc 229 (struct eth_addr *)netif->hwaddr, IP_ADDR_ANY, &ethzero,
darran 0:55a05330f8cc 230 &netif->autoip->llipaddr, ARP_REQUEST);
darran 0:55a05330f8cc 231 }
darran 0:55a05330f8cc 232
darran 0:55a05330f8cc 233 /**
darran 0:55a05330f8cc 234 * Sends an ARP announce from a network interface
darran 0:55a05330f8cc 235 *
darran 0:55a05330f8cc 236 * @param netif network interface used to send the announce
darran 0:55a05330f8cc 237 */
darran 0:55a05330f8cc 238 static err_t
darran 0:55a05330f8cc 239 autoip_arp_announce(struct netif *netif)
darran 0:55a05330f8cc 240 {
darran 0:55a05330f8cc 241 return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, &ethbroadcast,
darran 0:55a05330f8cc 242 (struct eth_addr *)netif->hwaddr, &netif->autoip->llipaddr, &ethzero,
darran 0:55a05330f8cc 243 &netif->autoip->llipaddr, ARP_REQUEST);
darran 0:55a05330f8cc 244 }
darran 0:55a05330f8cc 245
darran 0:55a05330f8cc 246 /**
darran 0:55a05330f8cc 247 * Configure interface for use with current LL IP-Address
darran 0:55a05330f8cc 248 *
darran 0:55a05330f8cc 249 * @param netif network interface to configure with current LL IP-Address
darran 0:55a05330f8cc 250 */
darran 0:55a05330f8cc 251 static err_t
darran 0:55a05330f8cc 252 autoip_bind(struct netif *netif)
darran 0:55a05330f8cc 253 {
darran 0:55a05330f8cc 254 struct autoip *autoip = netif->autoip;
darran 0:55a05330f8cc 255 ip_addr_t sn_mask, gw_addr;
darran 0:55a05330f8cc 256
darran 0:55a05330f8cc 257 LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
darran 0:55a05330f8cc 258 ("autoip_bind(netif=%p) %c%c%"U16_F" %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
darran 0:55a05330f8cc 259 (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num,
darran 0:55a05330f8cc 260 ip4_addr1_16(&autoip->llipaddr), ip4_addr2_16(&autoip->llipaddr),
darran 0:55a05330f8cc 261 ip4_addr3_16(&autoip->llipaddr), ip4_addr4_16(&autoip->llipaddr)));
darran 0:55a05330f8cc 262
darran 0:55a05330f8cc 263 IP4_ADDR(&sn_mask, 255, 255, 0, 0);
darran 0:55a05330f8cc 264 IP4_ADDR(&gw_addr, 0, 0, 0, 0);
darran 0:55a05330f8cc 265
darran 0:55a05330f8cc 266 netif_set_ipaddr(netif, &autoip->llipaddr);
darran 0:55a05330f8cc 267 netif_set_netmask(netif, &sn_mask);
darran 0:55a05330f8cc 268 netif_set_gw(netif, &gw_addr);
darran 0:55a05330f8cc 269
darran 0:55a05330f8cc 270 /* bring the interface up */
darran 0:55a05330f8cc 271 netif_set_up(netif);
darran 0:55a05330f8cc 272
darran 0:55a05330f8cc 273 return ERR_OK;
darran 0:55a05330f8cc 274 }
darran 0:55a05330f8cc 275
darran 0:55a05330f8cc 276 /**
darran 0:55a05330f8cc 277 * Start AutoIP client
darran 0:55a05330f8cc 278 *
darran 0:55a05330f8cc 279 * @param netif network interface on which start the AutoIP client
darran 0:55a05330f8cc 280 */
darran 0:55a05330f8cc 281 err_t
darran 0:55a05330f8cc 282 autoip_start(struct netif *netif)
darran 0:55a05330f8cc 283 {
darran 0:55a05330f8cc 284 struct autoip *autoip = netif->autoip;
darran 0:55a05330f8cc 285 err_t result = ERR_OK;
darran 0:55a05330f8cc 286
darran 0:55a05330f8cc 287 if(netif_is_up(netif)) {
darran 0:55a05330f8cc 288 netif_set_down(netif);
darran 0:55a05330f8cc 289 }
darran 0:55a05330f8cc 290
darran 0:55a05330f8cc 291 /* Set IP-Address, Netmask and Gateway to 0 to make sure that
darran 0:55a05330f8cc 292 * ARP Packets are formed correctly
darran 0:55a05330f8cc 293 */
darran 0:55a05330f8cc 294 ip_addr_set_zero(&netif->ip_addr);
darran 0:55a05330f8cc 295 ip_addr_set_zero(&netif->netmask);
darran 0:55a05330f8cc 296 ip_addr_set_zero(&netif->gw);
darran 0:55a05330f8cc 297
darran 0:55a05330f8cc 298 LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
darran 0:55a05330f8cc 299 ("autoip_start(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0],
darran 0:55a05330f8cc 300 netif->name[1], (u16_t)netif->num));
darran 0:55a05330f8cc 301 if(autoip == NULL) {
darran 0:55a05330f8cc 302 /* no AutoIP client attached yet? */
darran 0:55a05330f8cc 303 LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
darran 0:55a05330f8cc 304 ("autoip_start(): starting new AUTOIP client\n"));
darran 0:55a05330f8cc 305 autoip = (struct autoip *)mem_malloc(sizeof(struct autoip));
darran 0:55a05330f8cc 306 if(autoip == NULL) {
darran 0:55a05330f8cc 307 LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
darran 0:55a05330f8cc 308 ("autoip_start(): could not allocate autoip\n"));
darran 0:55a05330f8cc 309 return ERR_MEM;
darran 0:55a05330f8cc 310 }
darran 0:55a05330f8cc 311 memset( autoip, 0, sizeof(struct autoip));
darran 0:55a05330f8cc 312 /* store this AutoIP client in the netif */
darran 0:55a05330f8cc 313 netif->autoip = autoip;
darran 0:55a05330f8cc 314 LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_start(): allocated autoip"));
darran 0:55a05330f8cc 315 } else {
darran 0:55a05330f8cc 316 autoip->state = AUTOIP_STATE_OFF;
darran 0:55a05330f8cc 317 autoip->ttw = 0;
darran 0:55a05330f8cc 318 autoip->sent_num = 0;
darran 0:55a05330f8cc 319 memset(&autoip->llipaddr, 0, sizeof(ip_addr_t));
darran 0:55a05330f8cc 320 autoip->lastconflict = 0;
darran 0:55a05330f8cc 321 }
darran 0:55a05330f8cc 322
darran 0:55a05330f8cc 323 autoip_create_addr(netif, &(autoip->llipaddr));
darran 0:55a05330f8cc 324 autoip->tried_llipaddr++;
darran 0:55a05330f8cc 325 autoip_start_probing(netif);
darran 0:55a05330f8cc 326
darran 0:55a05330f8cc 327 return result;
darran 0:55a05330f8cc 328 }
darran 0:55a05330f8cc 329
darran 0:55a05330f8cc 330 static void
darran 0:55a05330f8cc 331 autoip_start_probing(struct netif *netif)
darran 0:55a05330f8cc 332 {
darran 0:55a05330f8cc 333 struct autoip *autoip = netif->autoip;
darran 0:55a05330f8cc 334
darran 0:55a05330f8cc 335 autoip->state = AUTOIP_STATE_PROBING;
darran 0:55a05330f8cc 336 autoip->sent_num = 0;
darran 0:55a05330f8cc 337 LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
darran 0:55a05330f8cc 338 ("autoip_start_probing(): changing state to PROBING: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
darran 0:55a05330f8cc 339 ip4_addr1_16(&netif->autoip->llipaddr), ip4_addr2_16(&netif->autoip->llipaddr),
darran 0:55a05330f8cc 340 ip4_addr3_16(&netif->autoip->llipaddr), ip4_addr4_16(&netif->autoip->llipaddr)));
darran 0:55a05330f8cc 341
darran 0:55a05330f8cc 342 /* time to wait to first probe, this is randomly
darran 0:55a05330f8cc 343 * choosen out of 0 to PROBE_WAIT seconds.
darran 0:55a05330f8cc 344 * compliant to RFC 3927 Section 2.2.1
darran 0:55a05330f8cc 345 */
darran 0:55a05330f8cc 346 autoip->ttw = (u16_t)(LWIP_AUTOIP_RAND(netif) % (PROBE_WAIT * AUTOIP_TICKS_PER_SECOND));
darran 0:55a05330f8cc 347
darran 0:55a05330f8cc 348 /*
darran 0:55a05330f8cc 349 * if we tried more then MAX_CONFLICTS we must limit our rate for
darran 0:55a05330f8cc 350 * accquiring and probing address
darran 0:55a05330f8cc 351 * compliant to RFC 3927 Section 2.2.1
darran 0:55a05330f8cc 352 */
darran 0:55a05330f8cc 353 if(autoip->tried_llipaddr > MAX_CONFLICTS) {
darran 0:55a05330f8cc 354 autoip->ttw = RATE_LIMIT_INTERVAL * AUTOIP_TICKS_PER_SECOND;
darran 0:55a05330f8cc 355 }
darran 0:55a05330f8cc 356 }
darran 0:55a05330f8cc 357
darran 0:55a05330f8cc 358 /**
darran 0:55a05330f8cc 359 * Handle a possible change in the network configuration.
darran 0:55a05330f8cc 360 *
darran 0:55a05330f8cc 361 * If there is an AutoIP address configured, take the interface down
darran 0:55a05330f8cc 362 * and begin probing with the same address.
darran 0:55a05330f8cc 363 */
darran 0:55a05330f8cc 364 void
darran 0:55a05330f8cc 365 autoip_network_changed(struct netif *netif)
darran 0:55a05330f8cc 366 {
darran 0:55a05330f8cc 367 if (netif->autoip && netif->autoip->state != AUTOIP_STATE_OFF) {
darran 0:55a05330f8cc 368 netif_set_down(netif);
darran 0:55a05330f8cc 369 autoip_start_probing(netif);
darran 0:55a05330f8cc 370 }
darran 0:55a05330f8cc 371 }
darran 0:55a05330f8cc 372
darran 0:55a05330f8cc 373 /**
darran 0:55a05330f8cc 374 * Stop AutoIP client
darran 0:55a05330f8cc 375 *
darran 0:55a05330f8cc 376 * @param netif network interface on which stop the AutoIP client
darran 0:55a05330f8cc 377 */
darran 0:55a05330f8cc 378 err_t
darran 0:55a05330f8cc 379 autoip_stop(struct netif *netif)
darran 0:55a05330f8cc 380 {
darran 0:55a05330f8cc 381 netif->autoip->state = AUTOIP_STATE_OFF;
darran 0:55a05330f8cc 382 netif_set_down(netif);
darran 0:55a05330f8cc 383 return ERR_OK;
darran 0:55a05330f8cc 384 }
darran 0:55a05330f8cc 385
darran 0:55a05330f8cc 386 /**
darran 0:55a05330f8cc 387 * Has to be called in loop every AUTOIP_TMR_INTERVAL milliseconds
darran 0:55a05330f8cc 388 */
darran 0:55a05330f8cc 389 void
darran 0:55a05330f8cc 390 autoip_tmr()
darran 0:55a05330f8cc 391 {
darran 0:55a05330f8cc 392 struct netif *netif = netif_list;
darran 0:55a05330f8cc 393 /* loop through netif's */
darran 0:55a05330f8cc 394 while (netif != NULL) {
darran 0:55a05330f8cc 395 /* only act on AutoIP configured interfaces */
darran 0:55a05330f8cc 396 if (netif->autoip != NULL) {
darran 0:55a05330f8cc 397 if(netif->autoip->lastconflict > 0) {
darran 0:55a05330f8cc 398 netif->autoip->lastconflict--;
darran 0:55a05330f8cc 399 }
darran 0:55a05330f8cc 400
darran 0:55a05330f8cc 401 LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
darran 0:55a05330f8cc 402 ("autoip_tmr() AutoIP-State: %"U16_F", ttw=%"U16_F"\n",
darran 0:55a05330f8cc 403 (u16_t)(netif->autoip->state), netif->autoip->ttw));
darran 0:55a05330f8cc 404
darran 0:55a05330f8cc 405 switch(netif->autoip->state) {
darran 0:55a05330f8cc 406 case AUTOIP_STATE_PROBING:
darran 0:55a05330f8cc 407 if(netif->autoip->ttw > 0) {
darran 0:55a05330f8cc 408 netif->autoip->ttw--;
darran 0:55a05330f8cc 409 } else {
darran 0:55a05330f8cc 410 if(netif->autoip->sent_num >= PROBE_NUM) {
darran 0:55a05330f8cc 411 netif->autoip->state = AUTOIP_STATE_ANNOUNCING;
darran 0:55a05330f8cc 412 netif->autoip->sent_num = 0;
darran 0:55a05330f8cc 413 netif->autoip->ttw = ANNOUNCE_WAIT * AUTOIP_TICKS_PER_SECOND;
darran 0:55a05330f8cc 414 LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
darran 0:55a05330f8cc 415 ("autoip_tmr(): changing state to ANNOUNCING: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
darran 0:55a05330f8cc 416 ip4_addr1_16(&netif->autoip->llipaddr), ip4_addr2_16(&netif->autoip->llipaddr),
darran 0:55a05330f8cc 417 ip4_addr3_16(&netif->autoip->llipaddr), ip4_addr4_16(&netif->autoip->llipaddr)));
darran 0:55a05330f8cc 418 } else {
darran 0:55a05330f8cc 419 autoip_arp_probe(netif);
darran 0:55a05330f8cc 420 LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
darran 0:55a05330f8cc 421 ("autoip_tmr() PROBING Sent Probe\n"));
darran 0:55a05330f8cc 422 netif->autoip->sent_num++;
darran 0:55a05330f8cc 423 /* calculate time to wait to next probe */
darran 0:55a05330f8cc 424 netif->autoip->ttw = (u16_t)((LWIP_AUTOIP_RAND(netif) %
darran 0:55a05330f8cc 425 ((PROBE_MAX - PROBE_MIN) * AUTOIP_TICKS_PER_SECOND) ) +
darran 0:55a05330f8cc 426 PROBE_MIN * AUTOIP_TICKS_PER_SECOND);
darran 0:55a05330f8cc 427 }
darran 0:55a05330f8cc 428 }
darran 0:55a05330f8cc 429 break;
darran 0:55a05330f8cc 430
darran 0:55a05330f8cc 431 case AUTOIP_STATE_ANNOUNCING:
darran 0:55a05330f8cc 432 if(netif->autoip->ttw > 0) {
darran 0:55a05330f8cc 433 netif->autoip->ttw--;
darran 0:55a05330f8cc 434 } else {
darran 0:55a05330f8cc 435 if(netif->autoip->sent_num == 0) {
darran 0:55a05330f8cc 436 /* We are here the first time, so we waited ANNOUNCE_WAIT seconds
darran 0:55a05330f8cc 437 * Now we can bind to an IP address and use it.
darran 0:55a05330f8cc 438 *
darran 0:55a05330f8cc 439 * autoip_bind calls netif_set_up. This triggers a gratuitous ARP
darran 0:55a05330f8cc 440 * which counts as an announcement.
darran 0:55a05330f8cc 441 */
darran 0:55a05330f8cc 442 autoip_bind(netif);
darran 0:55a05330f8cc 443 } else {
darran 0:55a05330f8cc 444 autoip_arp_announce(netif);
darran 0:55a05330f8cc 445 LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
darran 0:55a05330f8cc 446 ("autoip_tmr() ANNOUNCING Sent Announce\n"));
darran 0:55a05330f8cc 447 }
darran 0:55a05330f8cc 448 netif->autoip->ttw = ANNOUNCE_INTERVAL * AUTOIP_TICKS_PER_SECOND;
darran 0:55a05330f8cc 449 netif->autoip->sent_num++;
darran 0:55a05330f8cc 450
darran 0:55a05330f8cc 451 if(netif->autoip->sent_num >= ANNOUNCE_NUM) {
darran 0:55a05330f8cc 452 netif->autoip->state = AUTOIP_STATE_BOUND;
darran 0:55a05330f8cc 453 netif->autoip->sent_num = 0;
darran 0:55a05330f8cc 454 netif->autoip->ttw = 0;
darran 0:55a05330f8cc 455 LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
darran 0:55a05330f8cc 456 ("autoip_tmr(): changing state to BOUND: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
darran 0:55a05330f8cc 457 ip4_addr1_16(&netif->autoip->llipaddr), ip4_addr2_16(&netif->autoip->llipaddr),
darran 0:55a05330f8cc 458 ip4_addr3_16(&netif->autoip->llipaddr), ip4_addr4_16(&netif->autoip->llipaddr)));
darran 0:55a05330f8cc 459 }
darran 0:55a05330f8cc 460 }
darran 0:55a05330f8cc 461 break;
darran 0:55a05330f8cc 462 }
darran 0:55a05330f8cc 463 }
darran 0:55a05330f8cc 464 /* proceed to next network interface */
darran 0:55a05330f8cc 465 netif = netif->next;
darran 0:55a05330f8cc 466 }
darran 0:55a05330f8cc 467 }
darran 0:55a05330f8cc 468
darran 0:55a05330f8cc 469 /**
darran 0:55a05330f8cc 470 * Handles every incoming ARP Packet, called by etharp_arp_input.
darran 0:55a05330f8cc 471 *
darran 0:55a05330f8cc 472 * @param netif network interface to use for autoip processing
darran 0:55a05330f8cc 473 * @param hdr Incoming ARP packet
darran 0:55a05330f8cc 474 */
darran 0:55a05330f8cc 475 void
darran 0:55a05330f8cc 476 autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr)
darran 0:55a05330f8cc 477 {
darran 0:55a05330f8cc 478 LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_arp_reply()\n"));
darran 0:55a05330f8cc 479 if ((netif->autoip != NULL) && (netif->autoip->state != AUTOIP_STATE_OFF)) {
darran 0:55a05330f8cc 480 /* when ip.src == llipaddr && hw.src != netif->hwaddr
darran 0:55a05330f8cc 481 *
darran 0:55a05330f8cc 482 * when probing ip.dst == llipaddr && hw.src != netif->hwaddr
darran 0:55a05330f8cc 483 * we have a conflict and must solve it
darran 0:55a05330f8cc 484 */
darran 0:55a05330f8cc 485 ip_addr_t sipaddr, dipaddr;
darran 0:55a05330f8cc 486 struct eth_addr netifaddr;
darran 0:55a05330f8cc 487 netifaddr.addr[0] = netif->hwaddr[0];
darran 0:55a05330f8cc 488 netifaddr.addr[1] = netif->hwaddr[1];
darran 0:55a05330f8cc 489 netifaddr.addr[2] = netif->hwaddr[2];
darran 0:55a05330f8cc 490 netifaddr.addr[3] = netif->hwaddr[3];
darran 0:55a05330f8cc 491 netifaddr.addr[4] = netif->hwaddr[4];
darran 0:55a05330f8cc 492 netifaddr.addr[5] = netif->hwaddr[5];
darran 0:55a05330f8cc 493
darran 0:55a05330f8cc 494 /* Copy struct ip_addr2 to aligned ip_addr, to support compilers without
darran 0:55a05330f8cc 495 * structure packing (not using structure copy which breaks strict-aliasing rules).
darran 0:55a05330f8cc 496 */
darran 0:55a05330f8cc 497 SMEMCPY(&sipaddr, &hdr->sipaddr, sizeof(sipaddr));
darran 0:55a05330f8cc 498 SMEMCPY(&dipaddr, &hdr->dipaddr, sizeof(dipaddr));
darran 0:55a05330f8cc 499
darran 0:55a05330f8cc 500 if ((netif->autoip->state == AUTOIP_STATE_PROBING) ||
darran 0:55a05330f8cc 501 ((netif->autoip->state == AUTOIP_STATE_ANNOUNCING) &&
darran 0:55a05330f8cc 502 (netif->autoip->sent_num == 0))) {
darran 0:55a05330f8cc 503 /* RFC 3927 Section 2.2.1:
darran 0:55a05330f8cc 504 * from beginning to after ANNOUNCE_WAIT
darran 0:55a05330f8cc 505 * seconds we have a conflict if
darran 0:55a05330f8cc 506 * ip.src == llipaddr OR
darran 0:55a05330f8cc 507 * ip.dst == llipaddr && hw.src != own hwaddr
darran 0:55a05330f8cc 508 */
darran 0:55a05330f8cc 509 if ((ip_addr_cmp(&sipaddr, &netif->autoip->llipaddr)) ||
darran 0:55a05330f8cc 510 (ip_addr_cmp(&dipaddr, &netif->autoip->llipaddr) &&
darran 0:55a05330f8cc 511 !eth_addr_cmp(&netifaddr, &hdr->shwaddr))) {
darran 0:55a05330f8cc 512 LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING,
darran 0:55a05330f8cc 513 ("autoip_arp_reply(): Probe Conflict detected\n"));
darran 0:55a05330f8cc 514 autoip_start(netif);
darran 0:55a05330f8cc 515 }
darran 0:55a05330f8cc 516 } else {
darran 0:55a05330f8cc 517 /* RFC 3927 Section 2.5:
darran 0:55a05330f8cc 518 * in any state we have a conflict if
darran 0:55a05330f8cc 519 * ip.src == llipaddr && hw.src != own hwaddr
darran 0:55a05330f8cc 520 */
darran 0:55a05330f8cc 521 if (ip_addr_cmp(&sipaddr, &netif->autoip->llipaddr) &&
darran 0:55a05330f8cc 522 !eth_addr_cmp(&netifaddr, &hdr->shwaddr)) {
darran 0:55a05330f8cc 523 LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING,
darran 0:55a05330f8cc 524 ("autoip_arp_reply(): Conflicting ARP-Packet detected\n"));
darran 0:55a05330f8cc 525 autoip_handle_arp_conflict(netif);
darran 0:55a05330f8cc 526 }
darran 0:55a05330f8cc 527 }
darran 0:55a05330f8cc 528 }
darran 0:55a05330f8cc 529 }
darran 0:55a05330f8cc 530
darran 0:55a05330f8cc 531 #endif /* LWIP_AUTOIP */