Free (GPLv2) TCP/IP stack developed by TASS Belgium

Dependents:   lpc1768-picotcp-demo ZeroMQ_PicoTCP_Publisher_demo TCPSocket_HelloWorld_PicoTCP Pico_TCP_UDP_Test ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers pico_slaacv4.c Source File

pico_slaacv4.c

00001 /*********************************************************************
00002    PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
00003    See LICENSE and COPYING for usage.
00004 
00005    Authors: Bogdan Lupu
00006  *********************************************************************/
00007 #include "pico_slaacv4.h"
00008 #include "pico_arp.h"
00009 #include "pico_constants.h"
00010 #include "pico_stack.h"
00011 
00012 #ifdef PICO_SUPPORT_SLAACV4
00013 
00014 #define SLAACV4_NETWORK  ((long_be(0xa9fe0000)))
00015 #define SLAACV4_NETMASK  ((long_be(0xFFFF0000)))
00016 #define SLAACV4_MINRANGE  (0x00000100) /* In host order */
00017 #define SLAACV4_MAXRANGE  (0x0000FDFF) /* In host order */
00018 
00019 #define SLAACV4_CREATE_IPV4(seed) ((long_be((seed % SLAACV4_MAXRANGE) + SLAACV4_MINRANGE) & ~SLAACV4_NETMASK) | SLAACV4_NETWORK)
00020 
00021 #define PROBE_WAIT           1 /* delay between two tries during claim */
00022 #define PROBE_NB             3 /* number of probe packets during claim */
00023 /* #define PROBE_MIN  1 */
00024 /* #define PROBE_MAX  2 */
00025 #define ANNOUNCE_WAIT        2 /* delay before start announcing */
00026 #define ANNOUNCE_NB          2 /* number of announcement packets */
00027 #define ANNOUNCE_INTERVAL    2 /* time between announcement packets */
00028 #define MAX_CONFLICTS       10 /* max conflicts before rate limiting */
00029 #define RATE_LIMIT_INTERVAL 60 /* time between successive attempts */
00030 #define DEFEND_INTERVAL     10 /* minimum interval between defensive ARP */
00031 
00032 enum slaacv4_state {
00033     SLAACV4_RESET = 0,
00034     SLAACV4_CLAIMING,
00035     SLAACV4_CLAIMED,
00036     SLAACV4_ANNOUNCING,
00037     SLAACV4_ERROR
00038 };
00039 
00040 struct slaacv4_cookie {
00041     enum slaacv4_state state;
00042     uint8_t probe_try_nb;
00043     uint8_t conflict_nb;
00044     uint8_t announce_nb;
00045     struct pico_ip4 ip;
00046     struct pico_device *device;
00047     struct pico_timer *timer;
00048     void (*cb)(struct pico_ip4 *ip, uint8_t code);
00049 };
00050 
00051 static struct slaacv4_cookie slaacv4_local;
00052 
00053 static uint32_t pico_slaacv4_getip(struct pico_device *dev, uint8_t rand)
00054 {
00055     uint32_t seed = 0;
00056     if (dev->eth != NULL)
00057     {
00058         seed = pico_hash((const uint8_t *)dev->eth->mac.addr, PICO_SIZE_ETH);
00059     }
00060 
00061     if (rand)
00062     {
00063         seed += pico_rand();
00064     }
00065 
00066     return SLAACV4_CREATE_IPV4(seed);
00067 }
00068 
00069 static void pico_slaacv4_init_cookie(struct pico_ip4 *ip, struct pico_device *dev, struct slaacv4_cookie *ck, void (*cb)(struct pico_ip4 *ip,  uint8_t code))
00070 {
00071     ck->state = SLAACV4_RESET;
00072     ck->probe_try_nb = 0;
00073     ck->conflict_nb = 0;
00074     ck->announce_nb = 0;
00075     ck->cb = cb;
00076     ck->device = dev;
00077     ck->ip.addr = ip->addr;
00078     ck->timer = NULL;
00079 }
00080 
00081 static void pico_slaacv4_cancel_timers(struct slaacv4_cookie *tmp)
00082 {
00083     pico_timer_cancel(tmp->timer);
00084 
00085     tmp->timer = NULL;
00086 }
00087 
00088 static void pico_slaacv4_send_announce_timer(pico_time now, void *arg)
00089 {
00090     struct slaacv4_cookie *tmp = (struct slaacv4_cookie *)arg;
00091     struct pico_ip4 netmask = { 0 };
00092     netmask.addr = long_be(0xFFFF0000);
00093 
00094     (void)now;
00095 
00096     if (tmp->announce_nb < ANNOUNCE_NB)
00097     {
00098         pico_arp_request(tmp->device, &tmp->ip, PICO_ARP_ANNOUNCE);
00099         tmp->announce_nb++;
00100         tmp->timer = pico_timer_add(ANNOUNCE_INTERVAL * 1000, pico_slaacv4_send_announce_timer, arg);
00101     }
00102     else
00103     {
00104         tmp->state = SLAACV4_CLAIMED;
00105         pico_ipv4_link_add(tmp->device, tmp->ip, netmask);
00106         if (tmp->cb != NULL)
00107             tmp->cb(&tmp->ip, PICO_SLAACV4_SUCCESS);
00108     }
00109 }
00110 
00111 static void pico_slaacv4_send_probe_timer(pico_time now, void *arg)
00112 {
00113     struct slaacv4_cookie *tmp = (struct slaacv4_cookie *)arg;
00114     (void)now;
00115 
00116     if (tmp->probe_try_nb < PROBE_NB)
00117     {
00118         pico_arp_request(tmp->device, &tmp->ip, PICO_ARP_PROBE);
00119         tmp->probe_try_nb++;
00120         tmp->timer = pico_timer_add(PROBE_WAIT * 1000, pico_slaacv4_send_probe_timer, tmp);
00121     }
00122     else
00123     {
00124         tmp->state = SLAACV4_ANNOUNCING;
00125         tmp->timer = pico_timer_add(ANNOUNCE_WAIT * 1000, pico_slaacv4_send_announce_timer, arg);
00126     }
00127 }
00128 
00129 
00130 
00131 static void pico_slaacv4_receive_ipconflict(void)
00132 {
00133     struct slaacv4_cookie *tmp = &slaacv4_local;
00134 
00135     tmp->conflict_nb++;
00136     pico_slaacv4_cancel_timers(tmp);
00137 
00138     if(tmp->state == SLAACV4_CLAIMED)
00139     {
00140         pico_ipv4_link_del(tmp->device, tmp->ip);
00141     }
00142 
00143     if (tmp->conflict_nb < MAX_CONFLICTS)
00144     {
00145         tmp->state = SLAACV4_CLAIMING;
00146         tmp->probe_try_nb = 0;
00147         tmp->announce_nb = 0;
00148         tmp->ip.addr = long_be(pico_slaacv4_getip(tmp->device, (uint8_t)1));
00149         pico_arp_register_ipconflict(&tmp->ip, &tmp->device->eth->mac, pico_slaacv4_receive_ipconflict);
00150         pico_arp_request(tmp->device, &tmp->ip, PICO_ARP_PROBE);
00151         tmp->probe_try_nb++;
00152         tmp->timer = pico_timer_add(PROBE_WAIT * 1000, pico_slaacv4_send_probe_timer, tmp);
00153     }
00154     else
00155     {
00156         if (tmp->cb != NULL)
00157         {
00158             tmp->cb(&tmp->ip, PICO_SLAACV4_ERROR);
00159         }
00160 
00161         tmp->state = SLAACV4_ERROR;
00162     }
00163 
00164 }
00165 
00166 int pico_slaacv4_claimip(struct pico_device *dev, void (*cb)(struct pico_ip4 *ip,  uint8_t code))
00167 {
00168     struct pico_ip4 ip;
00169 
00170     if (!dev->eth) {
00171         pico_err = PICO_ERR_EPROTONOSUPPORT;
00172         return -1;
00173     }
00174 
00175     ip.addr = pico_slaacv4_getip(dev, 0);
00176 
00177     pico_slaacv4_init_cookie(&ip, dev, &slaacv4_local, cb);
00178     pico_arp_register_ipconflict(&ip, &dev->eth->mac, pico_slaacv4_receive_ipconflict);
00179     pico_arp_request(dev, &ip, PICO_ARP_PROBE);
00180     slaacv4_local.state = SLAACV4_CLAIMING;
00181     slaacv4_local.probe_try_nb++;
00182     slaacv4_local.timer = pico_timer_add(PROBE_WAIT * 1000, pico_slaacv4_send_probe_timer, &slaacv4_local);
00183 
00184     return 0;
00185 }
00186 
00187 void pico_slaacv4_unregisterip(void)
00188 {
00189     struct slaacv4_cookie *tmp = &slaacv4_local;
00190     struct pico_ip4 empty = {
00191         .addr = 0x00000000
00192     };
00193 
00194     if (tmp->state == SLAACV4_CLAIMED)
00195     {
00196         pico_ipv4_link_del(tmp->device, tmp->ip);
00197     }
00198 
00199     pico_slaacv4_cancel_timers(tmp);
00200     pico_slaacv4_init_cookie(&empty, NULL, tmp, NULL);
00201     pico_arp_register_ipconflict(&tmp->ip, NULL, NULL);
00202 
00203 }
00204 
00205 #endif