1195972f6Sopenharmony_ci/**
2195972f6Sopenharmony_ci * @file
3195972f6Sopenharmony_ci * AutoIP Automatic LinkLocal IP Configuration
4195972f6Sopenharmony_ci *
5195972f6Sopenharmony_ci * This is a AutoIP implementation for the lwIP TCP/IP stack. It aims to conform
6195972f6Sopenharmony_ci * with RFC 3927.
7195972f6Sopenharmony_ci *
8195972f6Sopenharmony_ci * @defgroup autoip AUTOIP
9195972f6Sopenharmony_ci * @ingroup ip4
10195972f6Sopenharmony_ci * AUTOIP related functions
11195972f6Sopenharmony_ci * USAGE:
12195972f6Sopenharmony_ci *
13195972f6Sopenharmony_ci * define @ref LWIP_AUTOIP 1 in your lwipopts.h
14195972f6Sopenharmony_ci * Options:
15195972f6Sopenharmony_ci * AUTOIP_TMR_INTERVAL msecs,
16195972f6Sopenharmony_ci *   I recommend a value of 100. The value must divide 1000 with a remainder almost 0.
17195972f6Sopenharmony_ci *   Possible values are 1000, 500, 333, 250, 200, 166, 142, 125, 111, 100 ....
18195972f6Sopenharmony_ci *
19195972f6Sopenharmony_ci * Without DHCP:
20195972f6Sopenharmony_ci * - Call autoip_start() after netif_add().
21195972f6Sopenharmony_ci *
22195972f6Sopenharmony_ci * With DHCP:
23195972f6Sopenharmony_ci * - define @ref LWIP_DHCP_AUTOIP_COOP 1 in your lwipopts.h.
24195972f6Sopenharmony_ci * - Configure your DHCP Client.
25195972f6Sopenharmony_ci *
26195972f6Sopenharmony_ci * @see netifapi_autoip
27195972f6Sopenharmony_ci */
28195972f6Sopenharmony_ci
29195972f6Sopenharmony_ci/*
30195972f6Sopenharmony_ci *
31195972f6Sopenharmony_ci * Copyright (c) 2007 Dominik Spies <kontakt@dspies.de>
32195972f6Sopenharmony_ci * All rights reserved.
33195972f6Sopenharmony_ci *
34195972f6Sopenharmony_ci * Redistribution and use in source and binary forms, with or without modification,
35195972f6Sopenharmony_ci * are permitted provided that the following conditions are met:
36195972f6Sopenharmony_ci *
37195972f6Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright notice,
38195972f6Sopenharmony_ci *    this list of conditions and the following disclaimer.
39195972f6Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright notice,
40195972f6Sopenharmony_ci *    this list of conditions and the following disclaimer in the documentation
41195972f6Sopenharmony_ci *    and/or other materials provided with the distribution.
42195972f6Sopenharmony_ci * 3. The name of the author may not be used to endorse or promote products
43195972f6Sopenharmony_ci *    derived from this software without specific prior written permission.
44195972f6Sopenharmony_ci *
45195972f6Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
46195972f6Sopenharmony_ci * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
47195972f6Sopenharmony_ci * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
48195972f6Sopenharmony_ci * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
49195972f6Sopenharmony_ci * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
50195972f6Sopenharmony_ci * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
51195972f6Sopenharmony_ci * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
52195972f6Sopenharmony_ci * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
53195972f6Sopenharmony_ci * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
54195972f6Sopenharmony_ci * OF SUCH DAMAGE.
55195972f6Sopenharmony_ci *
56195972f6Sopenharmony_ci * Author: Dominik Spies <kontakt@dspies.de>
57195972f6Sopenharmony_ci */
58195972f6Sopenharmony_ci
59195972f6Sopenharmony_ci#include "lwip/opt.h"
60195972f6Sopenharmony_ci
61195972f6Sopenharmony_ci#if LWIP_IPV4 && LWIP_AUTOIP /* don't build if not configured for use in lwipopts.h */
62195972f6Sopenharmony_ci
63195972f6Sopenharmony_ci#include "lwip/mem.h"
64195972f6Sopenharmony_ci/* #include "lwip/udp.h" */
65195972f6Sopenharmony_ci#include "lwip/ip_addr.h"
66195972f6Sopenharmony_ci#include "lwip/netif.h"
67195972f6Sopenharmony_ci#include "lwip/autoip.h"
68195972f6Sopenharmony_ci#include "lwip/etharp.h"
69195972f6Sopenharmony_ci#include "lwip/prot/autoip.h"
70195972f6Sopenharmony_ci
71195972f6Sopenharmony_ci#include <string.h>
72195972f6Sopenharmony_ci
73195972f6Sopenharmony_ci/** Pseudo random macro based on netif informations.
74195972f6Sopenharmony_ci * You could use "rand()" from the C Library if you define LWIP_AUTOIP_RAND in lwipopts.h */
75195972f6Sopenharmony_ci#ifndef LWIP_AUTOIP_RAND
76195972f6Sopenharmony_ci#define LWIP_AUTOIP_RAND(netif) ( (((u32_t)((netif->hwaddr[5]) & 0xff) << 24) | \
77195972f6Sopenharmony_ci                                   ((u32_t)((netif->hwaddr[3]) & 0xff) << 16) | \
78195972f6Sopenharmony_ci                                   ((u32_t)((netif->hwaddr[2]) & 0xff) << 8) | \
79195972f6Sopenharmony_ci                                   ((u32_t)((netif->hwaddr[4]) & 0xff))) + \
80195972f6Sopenharmony_ci                                   (netif_autoip_data(netif)? netif_autoip_data(netif)->tried_llipaddr : 0))
81195972f6Sopenharmony_ci#endif /* LWIP_AUTOIP_RAND */
82195972f6Sopenharmony_ci
83195972f6Sopenharmony_ci/**
84195972f6Sopenharmony_ci * Macro that generates the initial IP address to be tried by AUTOIP.
85195972f6Sopenharmony_ci * If you want to override this, define it to something else in lwipopts.h.
86195972f6Sopenharmony_ci */
87195972f6Sopenharmony_ci#ifndef LWIP_AUTOIP_CREATE_SEED_ADDR
88195972f6Sopenharmony_ci#define LWIP_AUTOIP_CREATE_SEED_ADDR(netif) \
89195972f6Sopenharmony_ci  lwip_htonl(AUTOIP_RANGE_START + ((u32_t)(((u8_t)(netif->hwaddr[4])) | \
90195972f6Sopenharmony_ci                 ((u32_t)((u8_t)(netif->hwaddr[5]))) << 8)))
91195972f6Sopenharmony_ci#endif /* LWIP_AUTOIP_CREATE_SEED_ADDR */
92195972f6Sopenharmony_ci
93195972f6Sopenharmony_ci/* static functions */
94195972f6Sopenharmony_cistatic err_t autoip_arp_announce(struct netif *netif);
95195972f6Sopenharmony_cistatic void autoip_start_probing(struct netif *netif);
96195972f6Sopenharmony_ci
97195972f6Sopenharmony_ci/**
98195972f6Sopenharmony_ci * @ingroup autoip
99195972f6Sopenharmony_ci * Set a statically allocated struct autoip to work with.
100195972f6Sopenharmony_ci * Using this prevents autoip_start to allocate it using mem_malloc.
101195972f6Sopenharmony_ci *
102195972f6Sopenharmony_ci * @param netif the netif for which to set the struct autoip
103195972f6Sopenharmony_ci * @param autoip (uninitialised) autoip struct allocated by the application
104195972f6Sopenharmony_ci */
105195972f6Sopenharmony_civoid
106195972f6Sopenharmony_ciautoip_set_struct(struct netif *netif, struct autoip *autoip)
107195972f6Sopenharmony_ci{
108195972f6Sopenharmony_ci  LWIP_ASSERT_CORE_LOCKED();
109195972f6Sopenharmony_ci  LWIP_ASSERT("netif != NULL", netif != NULL);
110195972f6Sopenharmony_ci  LWIP_ASSERT("autoip != NULL", autoip != NULL);
111195972f6Sopenharmony_ci  LWIP_ASSERT("netif already has a struct autoip set",
112195972f6Sopenharmony_ci              netif_autoip_data(netif) == NULL);
113195972f6Sopenharmony_ci
114195972f6Sopenharmony_ci  /* clear data structure */
115195972f6Sopenharmony_ci  memset(autoip, 0, sizeof(struct autoip));
116195972f6Sopenharmony_ci  /* autoip->state = AUTOIP_STATE_OFF; */
117195972f6Sopenharmony_ci  netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_AUTOIP, autoip);
118195972f6Sopenharmony_ci}
119195972f6Sopenharmony_ci
120195972f6Sopenharmony_ci/** Restart AutoIP client and check the next address (conflict detected)
121195972f6Sopenharmony_ci *
122195972f6Sopenharmony_ci * @param netif The netif under AutoIP control
123195972f6Sopenharmony_ci */
124195972f6Sopenharmony_cistatic void
125195972f6Sopenharmony_ciautoip_restart(struct netif *netif)
126195972f6Sopenharmony_ci{
127195972f6Sopenharmony_ci  struct autoip *autoip = netif_autoip_data(netif);
128195972f6Sopenharmony_ci  autoip->tried_llipaddr++;
129195972f6Sopenharmony_ci  autoip_start(netif);
130195972f6Sopenharmony_ci}
131195972f6Sopenharmony_ci
132195972f6Sopenharmony_ci/**
133195972f6Sopenharmony_ci * Handle a IP address conflict after an ARP conflict detection
134195972f6Sopenharmony_ci */
135195972f6Sopenharmony_cistatic void
136195972f6Sopenharmony_ciautoip_handle_arp_conflict(struct netif *netif)
137195972f6Sopenharmony_ci{
138195972f6Sopenharmony_ci  struct autoip *autoip = netif_autoip_data(netif);
139195972f6Sopenharmony_ci
140195972f6Sopenharmony_ci  /* RFC3927, 2.5 "Conflict Detection and Defense" allows two options where
141195972f6Sopenharmony_ci     a) means retreat on the first conflict and
142195972f6Sopenharmony_ci     b) allows to keep an already configured address when having only one
143195972f6Sopenharmony_ci        conflict in 10 seconds
144195972f6Sopenharmony_ci     We use option b) since it helps to improve the chance that one of the two
145195972f6Sopenharmony_ci     conflicting hosts may be able to retain its address. */
146195972f6Sopenharmony_ci
147195972f6Sopenharmony_ci  if (autoip->lastconflict > 0) {
148195972f6Sopenharmony_ci    /* retreat, there was a conflicting ARP in the last DEFEND_INTERVAL seconds */
149195972f6Sopenharmony_ci    LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
150195972f6Sopenharmony_ci                ("autoip_handle_arp_conflict(): we are defending, but in DEFEND_INTERVAL, retreating\n"));
151195972f6Sopenharmony_ci
152195972f6Sopenharmony_ci    /* Active TCP sessions are aborted when removing the ip addresss */
153195972f6Sopenharmony_ci    autoip_restart(netif);
154195972f6Sopenharmony_ci  } else {
155195972f6Sopenharmony_ci    LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
156195972f6Sopenharmony_ci                ("autoip_handle_arp_conflict(): we are defend, send ARP Announce\n"));
157195972f6Sopenharmony_ci    autoip_arp_announce(netif);
158195972f6Sopenharmony_ci    autoip->lastconflict = DEFEND_INTERVAL * AUTOIP_TICKS_PER_SECOND;
159195972f6Sopenharmony_ci  }
160195972f6Sopenharmony_ci}
161195972f6Sopenharmony_ci
162195972f6Sopenharmony_ci/**
163195972f6Sopenharmony_ci * Create an IP-Address out of range 169.254.1.0 to 169.254.254.255
164195972f6Sopenharmony_ci *
165195972f6Sopenharmony_ci * @param netif network interface on which create the IP-Address
166195972f6Sopenharmony_ci * @param ipaddr ip address to initialize
167195972f6Sopenharmony_ci */
168195972f6Sopenharmony_cistatic void
169195972f6Sopenharmony_ciautoip_create_addr(struct netif *netif, ip4_addr_t *ipaddr)
170195972f6Sopenharmony_ci{
171195972f6Sopenharmony_ci  struct autoip *autoip = netif_autoip_data(netif);
172195972f6Sopenharmony_ci
173195972f6Sopenharmony_ci  /* Here we create an IP-Address out of range 169.254.1.0 to 169.254.254.255
174195972f6Sopenharmony_ci   * compliant to RFC 3927 Section 2.1
175195972f6Sopenharmony_ci   * We have 254 * 256 possibilities */
176195972f6Sopenharmony_ci
177195972f6Sopenharmony_ci  u32_t addr = lwip_ntohl(LWIP_AUTOIP_CREATE_SEED_ADDR(netif));
178195972f6Sopenharmony_ci  addr += autoip->tried_llipaddr;
179195972f6Sopenharmony_ci  addr = AUTOIP_NET | (addr & 0xffff);
180195972f6Sopenharmony_ci  /* Now, 169.254.0.0 <= addr <= 169.254.255.255 */
181195972f6Sopenharmony_ci
182195972f6Sopenharmony_ci  if (addr < AUTOIP_RANGE_START) {
183195972f6Sopenharmony_ci    addr += AUTOIP_RANGE_END - AUTOIP_RANGE_START + 1;
184195972f6Sopenharmony_ci  }
185195972f6Sopenharmony_ci  if (addr > AUTOIP_RANGE_END) {
186195972f6Sopenharmony_ci    addr -= AUTOIP_RANGE_END - AUTOIP_RANGE_START + 1;
187195972f6Sopenharmony_ci  }
188195972f6Sopenharmony_ci  LWIP_ASSERT("AUTOIP address not in range", (addr >= AUTOIP_RANGE_START) &&
189195972f6Sopenharmony_ci              (addr <= AUTOIP_RANGE_END));
190195972f6Sopenharmony_ci  ip4_addr_set_u32(ipaddr, lwip_htonl(addr));
191195972f6Sopenharmony_ci
192195972f6Sopenharmony_ci  LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
193195972f6Sopenharmony_ci              ("autoip_create_addr(): tried_llipaddr=%"U16_F", %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
194195972f6Sopenharmony_ci               (u16_t)(autoip->tried_llipaddr), ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr),
195195972f6Sopenharmony_ci               ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr)));
196195972f6Sopenharmony_ci}
197195972f6Sopenharmony_ci
198195972f6Sopenharmony_ci/**
199195972f6Sopenharmony_ci * Sends an ARP probe from a network interface
200195972f6Sopenharmony_ci *
201195972f6Sopenharmony_ci * @param netif network interface used to send the probe
202195972f6Sopenharmony_ci */
203195972f6Sopenharmony_cistatic err_t
204195972f6Sopenharmony_ciautoip_arp_probe(struct netif *netif)
205195972f6Sopenharmony_ci{
206195972f6Sopenharmony_ci  struct autoip *autoip = netif_autoip_data(netif);
207195972f6Sopenharmony_ci  /* this works because netif->ip_addr is ANY */
208195972f6Sopenharmony_ci  return etharp_request(netif, &autoip->llipaddr);
209195972f6Sopenharmony_ci}
210195972f6Sopenharmony_ci
211195972f6Sopenharmony_ci/**
212195972f6Sopenharmony_ci * Sends an ARP announce from a network interface
213195972f6Sopenharmony_ci *
214195972f6Sopenharmony_ci * @param netif network interface used to send the announce
215195972f6Sopenharmony_ci */
216195972f6Sopenharmony_cistatic err_t
217195972f6Sopenharmony_ciautoip_arp_announce(struct netif *netif)
218195972f6Sopenharmony_ci{
219195972f6Sopenharmony_ci  return etharp_gratuitous(netif);
220195972f6Sopenharmony_ci}
221195972f6Sopenharmony_ci
222195972f6Sopenharmony_ci/**
223195972f6Sopenharmony_ci * Configure interface for use with current LL IP-Address
224195972f6Sopenharmony_ci *
225195972f6Sopenharmony_ci * @param netif network interface to configure with current LL IP-Address
226195972f6Sopenharmony_ci */
227195972f6Sopenharmony_cistatic err_t
228195972f6Sopenharmony_ciautoip_bind(struct netif *netif)
229195972f6Sopenharmony_ci{
230195972f6Sopenharmony_ci  struct autoip *autoip = netif_autoip_data(netif);
231195972f6Sopenharmony_ci  ip4_addr_t sn_mask, gw_addr;
232195972f6Sopenharmony_ci
233195972f6Sopenharmony_ci  LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
234195972f6Sopenharmony_ci              ("autoip_bind(netif=%p) %c%c%"U16_F" %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
235195972f6Sopenharmony_ci               (void *)netif, netif->name[0], netif->name[1], (u16_t)netif->num,
236195972f6Sopenharmony_ci               ip4_addr1_16(&autoip->llipaddr), ip4_addr2_16(&autoip->llipaddr),
237195972f6Sopenharmony_ci               ip4_addr3_16(&autoip->llipaddr), ip4_addr4_16(&autoip->llipaddr)));
238195972f6Sopenharmony_ci
239195972f6Sopenharmony_ci  IP4_ADDR(&sn_mask, 255, 255, 0, 0);
240195972f6Sopenharmony_ci  IP4_ADDR(&gw_addr, 0, 0, 0, 0);
241195972f6Sopenharmony_ci
242195972f6Sopenharmony_ci  netif_set_addr(netif, &autoip->llipaddr, &sn_mask, &gw_addr);
243195972f6Sopenharmony_ci  /* interface is used by routing now that an address is set */
244195972f6Sopenharmony_ci
245195972f6Sopenharmony_ci  return ERR_OK;
246195972f6Sopenharmony_ci}
247195972f6Sopenharmony_ci
248195972f6Sopenharmony_ci/**
249195972f6Sopenharmony_ci * @ingroup autoip
250195972f6Sopenharmony_ci * Start AutoIP client
251195972f6Sopenharmony_ci *
252195972f6Sopenharmony_ci * @param netif network interface on which start the AutoIP client
253195972f6Sopenharmony_ci */
254195972f6Sopenharmony_cierr_t
255195972f6Sopenharmony_ciautoip_start(struct netif *netif)
256195972f6Sopenharmony_ci{
257195972f6Sopenharmony_ci  struct autoip *autoip = netif_autoip_data(netif);
258195972f6Sopenharmony_ci  err_t result = ERR_OK;
259195972f6Sopenharmony_ci
260195972f6Sopenharmony_ci  LWIP_ASSERT_CORE_LOCKED();
261195972f6Sopenharmony_ci  LWIP_ERROR("netif is not up, old style port?", netif_is_up(netif), return ERR_ARG;);
262195972f6Sopenharmony_ci
263195972f6Sopenharmony_ci  /* Set IP-Address, Netmask and Gateway to 0 to make sure that
264195972f6Sopenharmony_ci   * ARP Packets are formed correctly
265195972f6Sopenharmony_ci   */
266195972f6Sopenharmony_ci  netif_set_addr(netif, IP4_ADDR_ANY4, IP4_ADDR_ANY4, IP4_ADDR_ANY4);
267195972f6Sopenharmony_ci
268195972f6Sopenharmony_ci  LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
269195972f6Sopenharmony_ci              ("autoip_start(netif=%p) %c%c%"U16_F"\n", (void *)netif, netif->name[0],
270195972f6Sopenharmony_ci               netif->name[1], (u16_t)netif->num));
271195972f6Sopenharmony_ci  if (autoip == NULL) {
272195972f6Sopenharmony_ci    /* no AutoIP client attached yet? */
273195972f6Sopenharmony_ci    LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
274195972f6Sopenharmony_ci                ("autoip_start(): starting new AUTOIP client\n"));
275195972f6Sopenharmony_ci    autoip = (struct autoip *)mem_calloc(1, sizeof(struct autoip));
276195972f6Sopenharmony_ci    if (autoip == NULL) {
277195972f6Sopenharmony_ci      LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
278195972f6Sopenharmony_ci                  ("autoip_start(): could not allocate autoip\n"));
279195972f6Sopenharmony_ci      return ERR_MEM;
280195972f6Sopenharmony_ci    }
281195972f6Sopenharmony_ci    /* store this AutoIP client in the netif */
282195972f6Sopenharmony_ci    netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_AUTOIP, autoip);
283195972f6Sopenharmony_ci    LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_start(): allocated autoip"));
284195972f6Sopenharmony_ci  } else {
285195972f6Sopenharmony_ci    autoip->state = AUTOIP_STATE_OFF;
286195972f6Sopenharmony_ci    autoip->ttw = 0;
287195972f6Sopenharmony_ci    autoip->sent_num = 0;
288195972f6Sopenharmony_ci    ip4_addr_set_zero(&autoip->llipaddr);
289195972f6Sopenharmony_ci    autoip->lastconflict = 0;
290195972f6Sopenharmony_ci  }
291195972f6Sopenharmony_ci
292195972f6Sopenharmony_ci  autoip_create_addr(netif, &(autoip->llipaddr));
293195972f6Sopenharmony_ci  autoip_start_probing(netif);
294195972f6Sopenharmony_ci
295195972f6Sopenharmony_ci  return result;
296195972f6Sopenharmony_ci}
297195972f6Sopenharmony_ci
298195972f6Sopenharmony_cistatic void
299195972f6Sopenharmony_ciautoip_start_probing(struct netif *netif)
300195972f6Sopenharmony_ci{
301195972f6Sopenharmony_ci  struct autoip *autoip = netif_autoip_data(netif);
302195972f6Sopenharmony_ci
303195972f6Sopenharmony_ci  autoip->state = AUTOIP_STATE_PROBING;
304195972f6Sopenharmony_ci  autoip->sent_num = 0;
305195972f6Sopenharmony_ci  LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
306195972f6Sopenharmony_ci              ("autoip_start_probing(): changing state to PROBING: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
307195972f6Sopenharmony_ci               ip4_addr1_16(&autoip->llipaddr), ip4_addr2_16(&autoip->llipaddr),
308195972f6Sopenharmony_ci               ip4_addr3_16(&autoip->llipaddr), ip4_addr4_16(&autoip->llipaddr)));
309195972f6Sopenharmony_ci
310195972f6Sopenharmony_ci  /* time to wait to first probe, this is randomly
311195972f6Sopenharmony_ci   * chosen out of 0 to PROBE_WAIT seconds.
312195972f6Sopenharmony_ci   * compliant to RFC 3927 Section 2.2.1
313195972f6Sopenharmony_ci   */
314195972f6Sopenharmony_ci  autoip->ttw = (u16_t)(LWIP_AUTOIP_RAND(netif) % (PROBE_WAIT * AUTOIP_TICKS_PER_SECOND));
315195972f6Sopenharmony_ci
316195972f6Sopenharmony_ci  /*
317195972f6Sopenharmony_ci   * if we tried more then MAX_CONFLICTS we must limit our rate for
318195972f6Sopenharmony_ci   * acquiring and probing address
319195972f6Sopenharmony_ci   * compliant to RFC 3927 Section 2.2.1
320195972f6Sopenharmony_ci   */
321195972f6Sopenharmony_ci  if (autoip->tried_llipaddr > MAX_CONFLICTS) {
322195972f6Sopenharmony_ci    autoip->ttw = RATE_LIMIT_INTERVAL * AUTOIP_TICKS_PER_SECOND;
323195972f6Sopenharmony_ci  }
324195972f6Sopenharmony_ci}
325195972f6Sopenharmony_ci
326195972f6Sopenharmony_ci/**
327195972f6Sopenharmony_ci * Handle a possible change in the network configuration.
328195972f6Sopenharmony_ci *
329195972f6Sopenharmony_ci * If there is an AutoIP address configured, take the interface down
330195972f6Sopenharmony_ci * and begin probing with the same address.
331195972f6Sopenharmony_ci */
332195972f6Sopenharmony_civoid
333195972f6Sopenharmony_ciautoip_network_changed(struct netif *netif)
334195972f6Sopenharmony_ci{
335195972f6Sopenharmony_ci  struct autoip *autoip = netif_autoip_data(netif);
336195972f6Sopenharmony_ci
337195972f6Sopenharmony_ci  if (autoip && (autoip->state != AUTOIP_STATE_OFF)) {
338195972f6Sopenharmony_ci    autoip_start_probing(netif);
339195972f6Sopenharmony_ci  }
340195972f6Sopenharmony_ci}
341195972f6Sopenharmony_ci
342195972f6Sopenharmony_ci/**
343195972f6Sopenharmony_ci * @ingroup autoip
344195972f6Sopenharmony_ci * Stop AutoIP client
345195972f6Sopenharmony_ci *
346195972f6Sopenharmony_ci * @param netif network interface on which stop the AutoIP client
347195972f6Sopenharmony_ci */
348195972f6Sopenharmony_cierr_t
349195972f6Sopenharmony_ciautoip_stop(struct netif *netif)
350195972f6Sopenharmony_ci{
351195972f6Sopenharmony_ci  struct autoip *autoip = netif_autoip_data(netif);
352195972f6Sopenharmony_ci
353195972f6Sopenharmony_ci  LWIP_ASSERT_CORE_LOCKED();
354195972f6Sopenharmony_ci  if (autoip != NULL) {
355195972f6Sopenharmony_ci    autoip->state = AUTOIP_STATE_OFF;
356195972f6Sopenharmony_ci    if (ip4_addr_islinklocal(netif_ip4_addr(netif))) {
357195972f6Sopenharmony_ci      netif_set_addr(netif, IP4_ADDR_ANY4, IP4_ADDR_ANY4, IP4_ADDR_ANY4);
358195972f6Sopenharmony_ci    }
359195972f6Sopenharmony_ci  }
360195972f6Sopenharmony_ci  return ERR_OK;
361195972f6Sopenharmony_ci}
362195972f6Sopenharmony_ci
363195972f6Sopenharmony_ci#if LWIP_LOWPOWER
364195972f6Sopenharmony_ci#include "lwip/lowpower.h"
365195972f6Sopenharmony_ciu32_t
366195972f6Sopenharmony_ciautoip_tmr_tick(void)
367195972f6Sopenharmony_ci{
368195972f6Sopenharmony_ci  struct netif *netif = NULL;
369195972f6Sopenharmony_ci  u32_t tick = 0;
370195972f6Sopenharmony_ci  NETIF_FOREACH(netif) {
371195972f6Sopenharmony_ci    struct autoip *autoip = netif_autoip_data(netif);
372195972f6Sopenharmony_ci    if ((autoip != NULL) && (autoip->ttw > 0)) {
373195972f6Sopenharmony_ci      if ((autoip->state == AUTOIP_STATE_PROBING) ||
374195972f6Sopenharmony_ci          (autoip->state == AUTOIP_STATE_ANNOUNCING)) {
375195972f6Sopenharmony_ci        SET_TMR_TICK(tick, autoip->ttw);
376195972f6Sopenharmony_ci      }
377195972f6Sopenharmony_ci    }
378195972f6Sopenharmony_ci  }
379195972f6Sopenharmony_ci
380195972f6Sopenharmony_ci  LWIP_DEBUGF(LOWPOWER_DEBUG, ("%s tmr tick: %u\n", "autoip_tmr_tick", tick));
381195972f6Sopenharmony_ci  return tick;
382195972f6Sopenharmony_ci}
383195972f6Sopenharmony_ci
384195972f6Sopenharmony_ci#endif
385195972f6Sopenharmony_ci
386195972f6Sopenharmony_ci/**
387195972f6Sopenharmony_ci * Has to be called in loop every AUTOIP_TMR_INTERVAL milliseconds
388195972f6Sopenharmony_ci */
389195972f6Sopenharmony_civoid
390195972f6Sopenharmony_ciautoip_tmr(void)
391195972f6Sopenharmony_ci{
392195972f6Sopenharmony_ci  struct netif *netif;
393195972f6Sopenharmony_ci  /* loop through netif's */
394195972f6Sopenharmony_ci  NETIF_FOREACH(netif) {
395195972f6Sopenharmony_ci    struct autoip *autoip = netif_autoip_data(netif);
396195972f6Sopenharmony_ci    /* only act on AutoIP configured interfaces */
397195972f6Sopenharmony_ci    if (autoip != NULL) {
398195972f6Sopenharmony_ci      if (autoip->lastconflict > 0) {
399195972f6Sopenharmony_ci        autoip->lastconflict--;
400195972f6Sopenharmony_ci      }
401195972f6Sopenharmony_ci
402195972f6Sopenharmony_ci      LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
403195972f6Sopenharmony_ci                  ("autoip_tmr() AutoIP-State: %"U16_F", ttw=%"U16_F"\n",
404195972f6Sopenharmony_ci                   (u16_t)(autoip->state), autoip->ttw));
405195972f6Sopenharmony_ci
406195972f6Sopenharmony_ci      if (autoip->ttw > 0) {
407195972f6Sopenharmony_ci        autoip->ttw--;
408195972f6Sopenharmony_ci      }
409195972f6Sopenharmony_ci
410195972f6Sopenharmony_ci      switch (autoip->state) {
411195972f6Sopenharmony_ci        case AUTOIP_STATE_PROBING:
412195972f6Sopenharmony_ci          if (autoip->ttw == 0) {
413195972f6Sopenharmony_ci            if (autoip->sent_num >= PROBE_NUM) {
414195972f6Sopenharmony_ci              /* Switch to ANNOUNCING: now we can bind to an IP address and use it */
415195972f6Sopenharmony_ci              autoip->state = AUTOIP_STATE_ANNOUNCING;
416195972f6Sopenharmony_ci              autoip_bind(netif);
417195972f6Sopenharmony_ci              /* autoip_bind() calls netif_set_addr(): this triggers a gratuitous ARP
418195972f6Sopenharmony_ci                 which counts as an announcement */
419195972f6Sopenharmony_ci              autoip->sent_num = 1;
420195972f6Sopenharmony_ci              autoip->ttw = ANNOUNCE_WAIT * AUTOIP_TICKS_PER_SECOND;
421195972f6Sopenharmony_ci              LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
422195972f6Sopenharmony_ci                          ("autoip_tmr(): changing state to ANNOUNCING: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
423195972f6Sopenharmony_ci                           ip4_addr1_16(&autoip->llipaddr), ip4_addr2_16(&autoip->llipaddr),
424195972f6Sopenharmony_ci                           ip4_addr3_16(&autoip->llipaddr), ip4_addr4_16(&autoip->llipaddr)));
425195972f6Sopenharmony_ci            } else {
426195972f6Sopenharmony_ci              autoip_arp_probe(netif);
427195972f6Sopenharmony_ci              LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_tmr() PROBING Sent Probe\n"));
428195972f6Sopenharmony_ci              autoip->sent_num++;
429195972f6Sopenharmony_ci              if (autoip->sent_num == PROBE_NUM) {
430195972f6Sopenharmony_ci                /* calculate time to wait to for announce */
431195972f6Sopenharmony_ci                autoip->ttw = ANNOUNCE_WAIT * AUTOIP_TICKS_PER_SECOND;
432195972f6Sopenharmony_ci              } else {
433195972f6Sopenharmony_ci                /* calculate time to wait to next probe */
434195972f6Sopenharmony_ci                autoip->ttw = (u16_t)((LWIP_AUTOIP_RAND(netif) %
435195972f6Sopenharmony_ci                                       ((PROBE_MAX - PROBE_MIN) * AUTOIP_TICKS_PER_SECOND) ) +
436195972f6Sopenharmony_ci                                      PROBE_MIN * AUTOIP_TICKS_PER_SECOND);
437195972f6Sopenharmony_ci              }
438195972f6Sopenharmony_ci            }
439195972f6Sopenharmony_ci          }
440195972f6Sopenharmony_ci          break;
441195972f6Sopenharmony_ci
442195972f6Sopenharmony_ci        case AUTOIP_STATE_ANNOUNCING:
443195972f6Sopenharmony_ci          if (autoip->ttw == 0) {
444195972f6Sopenharmony_ci            autoip_arp_announce(netif);
445195972f6Sopenharmony_ci            LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_tmr() ANNOUNCING Sent Announce\n"));
446195972f6Sopenharmony_ci            autoip->ttw = ANNOUNCE_INTERVAL * AUTOIP_TICKS_PER_SECOND;
447195972f6Sopenharmony_ci            autoip->sent_num++;
448195972f6Sopenharmony_ci
449195972f6Sopenharmony_ci            if (autoip->sent_num >= ANNOUNCE_NUM) {
450195972f6Sopenharmony_ci              autoip->state = AUTOIP_STATE_BOUND;
451195972f6Sopenharmony_ci              autoip->sent_num = 0;
452195972f6Sopenharmony_ci              autoip->ttw = 0;
453195972f6Sopenharmony_ci              LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
454195972f6Sopenharmony_ci                          ("autoip_tmr(): changing state to BOUND: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
455195972f6Sopenharmony_ci                           ip4_addr1_16(&autoip->llipaddr), ip4_addr2_16(&autoip->llipaddr),
456195972f6Sopenharmony_ci                           ip4_addr3_16(&autoip->llipaddr), ip4_addr4_16(&autoip->llipaddr)));
457195972f6Sopenharmony_ci            }
458195972f6Sopenharmony_ci          }
459195972f6Sopenharmony_ci          break;
460195972f6Sopenharmony_ci
461195972f6Sopenharmony_ci        default:
462195972f6Sopenharmony_ci          /* nothing to do in other states */
463195972f6Sopenharmony_ci          break;
464195972f6Sopenharmony_ci      }
465195972f6Sopenharmony_ci    }
466195972f6Sopenharmony_ci  }
467195972f6Sopenharmony_ci}
468195972f6Sopenharmony_ci
469195972f6Sopenharmony_ci/**
470195972f6Sopenharmony_ci * Handles every incoming ARP Packet, called by etharp_input().
471195972f6Sopenharmony_ci *
472195972f6Sopenharmony_ci * @param netif network interface to use for autoip processing
473195972f6Sopenharmony_ci * @param hdr Incoming ARP packet
474195972f6Sopenharmony_ci */
475195972f6Sopenharmony_civoid
476195972f6Sopenharmony_ciautoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr)
477195972f6Sopenharmony_ci{
478195972f6Sopenharmony_ci  struct autoip *autoip = netif_autoip_data(netif);
479195972f6Sopenharmony_ci
480195972f6Sopenharmony_ci  LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_arp_reply()\n"));
481195972f6Sopenharmony_ci  if ((autoip != NULL) && (autoip->state != AUTOIP_STATE_OFF)) {
482195972f6Sopenharmony_ci    /* when ip.src == llipaddr && hw.src != netif->hwaddr
483195972f6Sopenharmony_ci     *
484195972f6Sopenharmony_ci     * when probing  ip.dst == llipaddr && hw.src != netif->hwaddr
485195972f6Sopenharmony_ci     * we have a conflict and must solve it
486195972f6Sopenharmony_ci     */
487195972f6Sopenharmony_ci    ip4_addr_t sipaddr, dipaddr;
488195972f6Sopenharmony_ci    struct eth_addr netifaddr;
489195972f6Sopenharmony_ci    SMEMCPY(netifaddr.addr, netif->hwaddr, ETH_HWADDR_LEN);
490195972f6Sopenharmony_ci
491195972f6Sopenharmony_ci    /* Copy struct ip4_addr_wordaligned to aligned ip4_addr, to support compilers without
492195972f6Sopenharmony_ci     * structure packing (not using structure copy which breaks strict-aliasing rules).
493195972f6Sopenharmony_ci     */
494195972f6Sopenharmony_ci    IPADDR_WORDALIGNED_COPY_TO_IP4_ADDR_T(&sipaddr, &hdr->sipaddr);
495195972f6Sopenharmony_ci    IPADDR_WORDALIGNED_COPY_TO_IP4_ADDR_T(&dipaddr, &hdr->dipaddr);
496195972f6Sopenharmony_ci
497195972f6Sopenharmony_ci    if (autoip->state == AUTOIP_STATE_PROBING) {
498195972f6Sopenharmony_ci      /* RFC 3927 Section 2.2.1:
499195972f6Sopenharmony_ci       * from beginning to after ANNOUNCE_WAIT
500195972f6Sopenharmony_ci       * seconds we have a conflict if
501195972f6Sopenharmony_ci       * ip.src == llipaddr OR
502195972f6Sopenharmony_ci       * ip.dst == llipaddr && hw.src != own hwaddr
503195972f6Sopenharmony_ci       */
504195972f6Sopenharmony_ci      if ((ip4_addr_cmp(&sipaddr, &autoip->llipaddr)) ||
505195972f6Sopenharmony_ci          (ip4_addr_isany_val(sipaddr) &&
506195972f6Sopenharmony_ci           ip4_addr_cmp(&dipaddr, &autoip->llipaddr) &&
507195972f6Sopenharmony_ci           !eth_addr_cmp(&netifaddr, &hdr->shwaddr))) {
508195972f6Sopenharmony_ci        LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING,
509195972f6Sopenharmony_ci                    ("autoip_arp_reply(): Probe Conflict detected\n"));
510195972f6Sopenharmony_ci        autoip_restart(netif);
511195972f6Sopenharmony_ci      }
512195972f6Sopenharmony_ci    } else {
513195972f6Sopenharmony_ci      /* RFC 3927 Section 2.5:
514195972f6Sopenharmony_ci       * in any state we have a conflict if
515195972f6Sopenharmony_ci       * ip.src == llipaddr && hw.src != own hwaddr
516195972f6Sopenharmony_ci       */
517195972f6Sopenharmony_ci      if (ip4_addr_cmp(&sipaddr, &autoip->llipaddr) &&
518195972f6Sopenharmony_ci          !eth_addr_cmp(&netifaddr, &hdr->shwaddr)) {
519195972f6Sopenharmony_ci        LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING,
520195972f6Sopenharmony_ci                    ("autoip_arp_reply(): Conflicting ARP-Packet detected\n"));
521195972f6Sopenharmony_ci        autoip_handle_arp_conflict(netif);
522195972f6Sopenharmony_ci      }
523195972f6Sopenharmony_ci    }
524195972f6Sopenharmony_ci  }
525195972f6Sopenharmony_ci}
526195972f6Sopenharmony_ci
527195972f6Sopenharmony_ci/** check if AutoIP supplied netif->ip_addr
528195972f6Sopenharmony_ci *
529195972f6Sopenharmony_ci * @param netif the netif to check
530195972f6Sopenharmony_ci * @return 1 if AutoIP supplied netif->ip_addr (state BOUND or ANNOUNCING),
531195972f6Sopenharmony_ci *         0 otherwise
532195972f6Sopenharmony_ci */
533195972f6Sopenharmony_ciu8_t
534195972f6Sopenharmony_ciautoip_supplied_address(const struct netif *netif)
535195972f6Sopenharmony_ci{
536195972f6Sopenharmony_ci  if ((netif != NULL) && (netif_autoip_data(netif) != NULL)) {
537195972f6Sopenharmony_ci    struct autoip *autoip = netif_autoip_data(netif);
538195972f6Sopenharmony_ci    return (autoip->state == AUTOIP_STATE_BOUND) || (autoip->state == AUTOIP_STATE_ANNOUNCING);
539195972f6Sopenharmony_ci  }
540195972f6Sopenharmony_ci  return 0;
541195972f6Sopenharmony_ci}
542195972f6Sopenharmony_ci
543195972f6Sopenharmony_ciu8_t
544195972f6Sopenharmony_ciautoip_accept_packet(struct netif *netif, const ip4_addr_t *addr)
545195972f6Sopenharmony_ci{
546195972f6Sopenharmony_ci  struct autoip *autoip = netif_autoip_data(netif);
547195972f6Sopenharmony_ci  return (autoip != NULL) && ip4_addr_cmp(addr, &(autoip->llipaddr));
548195972f6Sopenharmony_ci}
549195972f6Sopenharmony_ci
550195972f6Sopenharmony_ci#endif /* LWIP_IPV4 && LWIP_AUTOIP */
551