auto_ip.c
Go to the documentation of this file.
1 /**
2  * @file auto_ip.c
3  * @brief Auto-IP (Dynamic Configuration of IPv4 Link-Local Addresses)
4  *
5  * @section License
6  *
7  * Copyright (C) 2010-2018 Oryx Embedded SARL. All rights reserved.
8  *
9  * This file is part of CycloneTCP Open.
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software Foundation,
23  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24  *
25  * @section Description
26  *
27  * Auto-IP describes a method by which a host may automatically configure an
28  * interface with an IPv4 address in the 169.254/16 prefix that is valid for
29  * Link-Local communication on that interface. This is especially valuable in
30  * environments where no other configuration mechanism is available. Refer to
31  * the following RFCs for complete details:
32  * - RFC 3927: Dynamic Configuration of IPv4 Link-Local Addresses
33  * - RFC 5227: IPv4 Address Conflict Detection
34  *
35  * @author Oryx Embedded SARL (www.oryx-embedded.com)
36  * @version 1.9.0
37  **/
38 
39 //Switch to the appropriate trace level
40 #define TRACE_LEVEL AUTO_IP_TRACE_LEVEL
41 
42 //Dependencies
43 #include "core/net.h"
44 #include "core/ethernet.h"
45 #include "ipv4/arp.h"
46 #include "ipv4/auto_ip.h"
47 #include "mdns/mdns_responder.h"
48 #include "debug.h"
49 
50 //Check TCP/IP stack configuration
51 #if (IPV4_SUPPORT == ENABLED && AUTO_IP_SUPPORT == ENABLED)
52 
53 //Tick counter to handle periodic operations
55 
56 
57 /**
58  * @brief Initialize settings with default values
59  * @param[out] settings Structure that contains Auto-IP settings
60  **/
61 
63 {
64  //Use default interface
65  settings->interface = netGetDefaultInterface();
66 
67  //Initial link-local address to be used
69  //Link state change event
70  settings->linkChangeEvent = NULL;
71  //FSM state change event
72  settings->stateChangeEvent = NULL;
73 }
74 
75 
76 /**
77  * @brief Auto-IP initialization
78  * @param[in] context Pointer to the Auto-IP context
79  * @param[in] settings Auto-IP specific settings
80  * @return Error code
81  **/
82 
83 error_t autoIpInit(AutoIpContext *context, const AutoIpSettings *settings)
84 {
85  NetInterface *interface;
86 
87  //Debug message
88  TRACE_INFO("Initializing Auto-IP...\r\n");
89 
90  //Ensure the parameters are valid
91  if(context == NULL || settings == NULL)
93 
94  //A valid pointer to the interface being configured is required
95  if(settings->interface == NULL)
97 
98  //Point to the underlying network interface
99  interface = settings->interface;
100 
101  //Clear the Auto-IP context
102  memset(context, 0, sizeof(AutoIpContext));
103  //Save user settings
104  context->settings = *settings;
105 
106  //Use default link-local address
107  context->linkLocalAddr = settings->linkLocalAddr;
108  //Reset conflict counter
109  context->conflictCount = 0;
110 
111  //Auto-IP operation is currently suspended
112  context->running = FALSE;
113  //Initialize state machine
114  context->state = AUTO_IP_STATE_INIT;
115 
116  //Attach the Auto-IP context to the network interface
117  interface->autoIpContext = context;
118 
119  //Successful initialization
120  return NO_ERROR;
121 }
122 
123 
124 /**
125  * @brief Start Auto-IP process
126  * @param[in] context Pointer to the Auto-IP context
127  * @return Error code
128  **/
129 
131 {
132  NetInterface *interface;
133 
134  //Check parameter
135  if(context == NULL)
137 
138  //Debug message
139  TRACE_INFO("Starting Auto-IP...\r\n");
140 
141  //Get exclusive access
143 
144  //Point to the underlying network interface
145  interface = context->settings.interface;
146 
147  //The host address is not longer valid
148  interface->ipv4Context.addr = IPV4_UNSPECIFIED_ADDR;
149  interface->ipv4Context.addrState = IPV4_ADDR_STATE_INVALID;
150 
151  //Clear subnet mask
152  interface->ipv4Context.subnetMask = IPV4_UNSPECIFIED_ADDR;
153 
154  //Start Auto-IP operation
155  context->running = TRUE;
156  //Initialize state machine
157  context->state = AUTO_IP_STATE_INIT;
158  //Reset conflict counter
159  context->conflictCount = 0;
160 
161  //Release exclusive access
163 
164  //Successful processing
165  return NO_ERROR;
166 }
167 
168 
169 /**
170  * @brief Stop Auto-IP process
171  * @param[in] context Pointer to the Auto-IP context
172  * @return Error code
173  **/
174 
176 {
177  //Check parameter
178  if(context == NULL)
180 
181  //Debug message
182  TRACE_INFO("Stopping Auto-IP...\r\n");
183 
184  //Get exclusive access
186 
187  //Suspend Auto-IP operation
188  context->running = FALSE;
189  //Reinitialize state machine
190  context->state = AUTO_IP_STATE_INIT;
191 
192  //Release exclusive access
194 
195  //Successful processing
196  return NO_ERROR;
197 }
198 
199 
200 /**
201  * @brief Retrieve current state
202  * @param[in] context Pointer to the Auto-IP context
203  * @return Current Auto-IP state
204  **/
205 
207 {
208  AutoIpState state;
209 
210  //Get exclusive access
212  //Get current state
213  state = context->state;
214  //Release exclusive access
216 
217  //Return current state
218  return state;
219 }
220 
221 
222 /**
223  * @brief Auto-IP timer handler
224  *
225  * This routine must be periodically called by the TCP/IP stack to
226  * manage Auto-IP operation
227  *
228  * @param[in] context Pointer to the Auto-IP context
229  **/
230 
231 void autoIpTick(AutoIpContext *context)
232 {
233  systime_t time;
234  systime_t delay;
235  NetInterface *interface;
236 
237  //Make sure Auto-IP has been properly instantiated
238  if(context == NULL)
239  return;
240 
241  //Point to the underlying network interface
242  interface = context->settings.interface;
243 
244  //Get current time
245  time = osGetSystemTime();
246 
247  //Check current state
248  if(context->state == AUTO_IP_STATE_INIT)
249  {
250  //Wait for the link to be up before starting Auto-IP
251  if(context->running && interface->linkState)
252  {
253  //Configure subnet mask
254  interface->ipv4Context.subnetMask = AUTO_IP_MASK;
255 
256  //The address must be in the range from 169.54.1.0 to 169.254.254.255
257  if(ntohl(context->linkLocalAddr) < ntohl(AUTO_IP_ADDR_MIN) ||
258  ntohl(context->linkLocalAddr) > ntohl(AUTO_IP_ADDR_MAX))
259  {
260  //Generate a random link-local address
261  autoIpGenerateAddr(&context->linkLocalAddr);
262  }
263 
264  //Use the link-local address as a tentative address
265  interface->ipv4Context.addr = context->linkLocalAddr;
266  interface->ipv4Context.addrState = IPV4_ADDR_STATE_TENTATIVE;
267 
268  //Clear conflict flag
269  interface->ipv4Context.addrConflict = FALSE;
270 
271  //Initial random delay
273 
274  //The number of conflicts exceeds the maximum acceptable value?
275  if(context->conflictCount >= AUTO_IP_MAX_CONFLICTS)
276  {
277  //The host must limit the rate at which it probes for new addresses
279  }
280 
281  //Verify the uniqueness of the link-local address
282  autoIpChangeState(context, AUTO_IP_STATE_PROBING, delay);
283  }
284  }
285  else if(context->state == AUTO_IP_STATE_PROBING)
286  {
287  //Any conflict detected?
288  if(interface->ipv4Context.addrConflict)
289  {
290  //The address is already in use by some other host and
291  //must not be assigned to the interface
292  interface->ipv4Context.addr = IPV4_UNSPECIFIED_ADDR;
293  interface->ipv4Context.addrState = IPV4_ADDR_STATE_INVALID;
294 
295  //The host should maintain a counter of the number of address
296  //conflicts it has experienced
297  context->conflictCount++;
298 
299  //The host must pick a new random address...
300  autoIpGenerateAddr(&context->linkLocalAddr);
301  //...and repeat the process
303  }
304  else
305  {
306  //Check current time
307  if(timeCompare(time, context->timestamp + context->timeout) >= 0)
308  {
309  //Address Conflict Detection is on-going?
310  if(context->retransmitCount < AUTO_IP_PROBE_NUM)
311  {
312  //Conflict detection is done using ARP probes
313  arpSendProbe(interface, context->linkLocalAddr);
314 
315  //Save the time at which the packet was sent
316  context->timestamp = time;
317  //Increment retransmission counter
318  context->retransmitCount++;
319 
320  //Last probe packet sent?
321  if(context->retransmitCount == AUTO_IP_PROBE_NUM)
322  {
323  //Delay before announcing
324  context->timeout = AUTO_IP_ANNOUNCE_WAIT;
325  }
326  else
327  {
328  //Maximum delay till repeated probe
329  context->timeout = netGetRandRange(AUTO_IP_PROBE_MIN,
331  }
332  }
333  else
334  {
335  //The use of the IPv4 address is now unrestricted
336  interface->ipv4Context.addrState = IPV4_ADDR_STATE_VALID;
337 
338 #if (MDNS_RESPONDER_SUPPORT == ENABLED)
339  //Restart mDNS probing process
340  mdnsResponderStartProbing(interface->mdnsResponderContext);
341 #endif
342  //The host must then announce its claimed address
344  }
345  }
346  }
347  }
348  else if(context->state == AUTO_IP_STATE_ANNOUNCING)
349  {
350  //Check current time
351  if(timeCompare(time, context->timestamp + context->timeout) >= 0)
352  {
353  //An ARP announcement is identical to an ARP probe, except that
354  //now the sender and target IP addresses are both set to the
355  //host's newly selected IPv4 address
356  arpSendRequest(interface, context->linkLocalAddr, &MAC_BROADCAST_ADDR);
357 
358  //Save the time at which the packet was sent
359  context->timestamp = time;
360  //Time interval between announcement packets
361  context->timeout = AUTO_IP_ANNOUNCE_INTERVAL;
362  //Increment retransmission counter
363  context->retransmitCount++;
364 
365  //Announcing is complete?
366  if(context->retransmitCount >= AUTO_IP_ANNOUNCE_NUM)
367  {
368  //Successful address autoconfiguration
370  //Reset conflict counter
371  context->conflictCount = 0;
372 
373  //Dump current IPv4 configuration for debugging purpose
374  autoIpDumpConfig(context);
375  }
376  }
377  }
378  else if(context->state == AUTO_IP_STATE_CONFIGURED)
379  {
380  //Address Conflict Detection is an on-going process that is in effect
381  //for as long as a host is using an IPv4 link-local address
382  if(interface->ipv4Context.addrConflict)
383  {
384  //The host may elect to attempt to defend its address by recording
385  //the time that the conflicting ARP packet was received, and then
386  //broadcasting one single ARP announcement, giving its own IP and
387  //hardware addresses as the sender addresses of the ARP
388 #if (AUTO_IP_BCT_SUPPORT == ENABLED)
389  arpSendProbe(interface, context->linkLocalAddr);
390 #else
391  arpSendRequest(interface, context->linkLocalAddr, &MAC_BROADCAST_ADDR);
392 #endif
393  //Clear conflict flag
394  interface->ipv4Context.addrConflict = FALSE;
395 
396  //The host can then continue to use the address normally without
397  //any further special action
399  }
400  }
401  else if(context->state == AUTO_IP_STATE_DEFENDING)
402  {
403  //if this is not the first conflicting ARP packet the host has seen, and
404  //the time recorded for the previous conflicting ARP packet is recent,
405  //within DEFEND_INTERVAL seconds, then the host must immediately cease
406  //using this address
407  if(interface->ipv4Context.addrConflict)
408  {
409  //The link-local address cannot be used anymore
410  interface->ipv4Context.addr = IPV4_UNSPECIFIED_ADDR;
411  interface->ipv4Context.addrState = IPV4_ADDR_STATE_INVALID;
412 
413 #if (MDNS_RESPONDER_SUPPORT == ENABLED)
414  //Restart mDNS probing process
415  mdnsResponderStartProbing(interface->mdnsResponderContext);
416 #endif
417  //The host must pick a new random address...
418  autoIpGenerateAddr(&context->linkLocalAddr);
419  //...and probes/announces again
421  }
422  else
423  {
424  //Check whether the DEFEND_INTERVAL has elapsed
425  if(timeCompare(time, context->timestamp + AUTO_IP_DEFEND_INTERVAL) >= 0)
426  {
427  //The host can continue to use its link-local address
429  }
430  }
431  }
432 }
433 
434 
435 /**
436  * @brief Callback function for link change event
437  * @param[in] context Pointer to the Auto-IP context
438  **/
439 
441 {
442  NetInterface *interface;
443 
444  //Make sure Auto-IP has been properly instantiated
445  if(context == NULL)
446  return;
447 
448  //Point to the underlying network interface
449  interface = context->settings.interface;
450 
451  //Check whether Auto-IP is enabled
452  if(context->running)
453  {
454  //The host address is not longer valid
455  interface->ipv4Context.addr = IPV4_UNSPECIFIED_ADDR;
456  interface->ipv4Context.addrState = IPV4_ADDR_STATE_INVALID;
457 
458  //Clear subnet mask
459  interface->ipv4Context.subnetMask = IPV4_UNSPECIFIED_ADDR;
460 
461 #if (MDNS_RESPONDER_SUPPORT == ENABLED)
462  //Restart mDNS probing process
463  mdnsResponderStartProbing(interface->mdnsResponderContext);
464 #endif
465  }
466 
467  //Reinitialize state machine
468  context->state = AUTO_IP_STATE_INIT;
469  //Reset conflict counter
470  context->conflictCount = 0;
471 
472  //Any registered callback?
473  if(context->settings.linkChangeEvent != NULL)
474  {
475  //Release exclusive access
477  //Invoke user callback function
478  context->settings.linkChangeEvent(context, interface, interface->linkState);
479  //Get exclusive access
481  }
482 }
483 
484 
485 /**
486  * @brief Update Auto-IP FSM state
487  * @param[in] context Pointer to the Auto-IP context
488  * @param[in] newState New Auto-IP state to switch to
489  * @param[in] delay Initial delay
490  **/
491 
493  AutoIpState newState, systime_t delay)
494 {
495  NetInterface *interface;
496 
497  //Point to the underlying network interface
498  interface = context->settings.interface;
499 
500  //Set time stamp
501  context->timestamp = osGetSystemTime();
502  //Set initial delay
503  context->timeout = delay;
504  //Reset retransmission counter
505  context->retransmitCount = 0;
506  //Switch to the new state
507  context->state = newState;
508 
509  //Any registered callback?
510  if(context->settings.stateChangeEvent != NULL)
511  {
512  //Release exclusive access
514  //Invoke user callback function
515  context->settings.stateChangeEvent(context, interface, newState);
516  //Get exclusive access
518  }
519 }
520 
521 
522 /**
523  * @brief Generate a random link-local address
524  * @param[out] ipAddr Random link-local address
525  **/
526 
528 {
529  uint32_t n;
530 
531  //Generate a random address in the range from 169.254.1.0 to 169.254.254.255
534 
535  //Convert the resulting address to network byte order
536  *ipAddr = htonl(n);
537 }
538 
539 
540 /**
541  * @brief Dump Auto-IP configuration for debugging purpose
542  * @param[in] context Pointer to the Auto-IP context
543  **/
544 
546 {
547 #if (AUTO_IP_TRACE_LEVEL >= TRACE_LEVEL_INFO)
548  NetInterface *interface;
549  Ipv4Context *ipv4Context;
550 
551  //Point to the underlying network interface
552  interface = context->settings.interface;
553  //Point to the IPv4 context
554  ipv4Context = &interface->ipv4Context;
555 
556  //Debug message
557  TRACE_INFO("\r\n");
558  TRACE_INFO("Auto-IP configuration:\r\n");
559 
560  //Link-local address
561  TRACE_INFO(" Link-local Address = %s\r\n",
562  ipv4AddrToString(ipv4Context->addr, NULL));
563 
564  //Subnet mask
565  TRACE_INFO(" Subnet Mask = %s\r\n",
566  ipv4AddrToString(ipv4Context->subnetMask, NULL));
567 
568  //Debug message
569  TRACE_INFO("\r\n");
570 #endif
571 }
572 
573 #endif
An address assigned to an interface whose use is unrestricted.
Definition: ipv4.h:184
ARP (Address Resolution Protocol)
uint32_t Ipv4Addr
IPv4 network address.
Definition: ipv4.h:232
uint32_t systime_t
Definition: compiler_port.h:44
mDNS responder (Multicast DNS)
#define timeCompare(t1, t2)
Definition: os_port.h:40
char_t * ipv4AddrToString(Ipv4Addr ipAddr, char_t *str)
Convert a binary IPv4 address to dot-decimal notation.
Definition: ipv4.c:1785
systime_t autoIpTickCounter
Definition: auto_ip.c:54
#define AUTO_IP_MASK
Definition: auto_ip.h:129
#define AUTO_IP_ADDR_MIN
Definition: auto_ip.h:132
systime_t osGetSystemTime(void)
Retrieve system time.
uint32_t time
Auto-IP settings.
Definition: auto_ip.h:179
TCP/IP stack core.
void autoIpLinkChangeEvent(AutoIpContext *context)
Callback function for link change event.
Definition: auto_ip.c:440
Debugging facilities.
#define AUTO_IP_ADDR_MAX
Definition: auto_ip.h:133
Invalid parameter.
Definition: error.h:45
#define AUTO_IP_RATE_LIMIT_INTERVAL
Definition: auto_ip.h:114
error_t autoIpStart(AutoIpContext *context)
Start Auto-IP process.
Definition: auto_ip.c:130
error_t autoIpInit(AutoIpContext *context, const AutoIpSettings *settings)
Auto-IP initialization.
Definition: auto_ip.c:83
#define AUTO_IP_PROBE_MIN
Definition: auto_ip.h:72
#define TRUE
Definition: os_port.h:48
error_t arpSendRequest(NetInterface *interface, Ipv4Addr targetIpAddr, const MacAddr *destMacAddr)
Send ARP request.
Definition: arp.c:812
uint8_t ipAddr[4]
Definition: mib_common.h:185
void autoIpTick(AutoIpContext *context)
Auto-IP timer handler.
Definition: auto_ip.c:231
#define ntohl(value)
Definition: cpu_endian.h:397
Ethernet.
error_t mdnsResponderStartProbing(MdnsResponderContext *context)
Restart probing process.
uint32_t netGetRand(void)
Get a random value.
Definition: net.c:1523
#define AUTO_IP_MAX_CONFLICTS
Definition: auto_ip.h:107
#define AUTO_IP_ANNOUNCE_NUM
Definition: auto_ip.h:93
#define htonl(value)
Definition: cpu_endian.h:391
An address that is not assigned to any interface.
Definition: ipv4.h:182
#define AUTO_IP_PROBE_NUM
Definition: auto_ip.h:65
An address whose uniqueness on a link is being verified.
Definition: ipv4.h:183
NetInterface * netGetDefaultInterface(void)
Get default network interface.
Definition: net.c:1495
AutoIpLinkChangeCallback linkChangeEvent
Link state change event.
Definition: auto_ip.h:183
Auto-IP (Dynamic Configuration of IPv4 Link-Local Addresses)
AutoIpState
Auto-IP FSM states.
Definition: auto_ip.h:149
void autoIpGetDefaultSettings(AutoIpSettings *settings)
Initialize settings with default values.
Definition: auto_ip.c:62
const MacAddr MAC_BROADCAST_ADDR
Definition: ethernet.c:55
#define TRACE_INFO(...)
Definition: debug.h:86
Success.
Definition: error.h:42
int32_t netGetRandRange(int32_t min, int32_t max)
Get a random value in the specified range.
Definition: net.c:1554
error_t
Error codes.
Definition: error.h:40
void osReleaseMutex(OsMutex *mutex)
Release ownership of the specified mutex object.
Ipv4Addr linkLocalAddr
Initial link-local address to be used.
Definition: auto_ip.h:182
void autoIpGenerateAddr(Ipv4Addr *ipAddr)
Generate a random link-local address.
Definition: auto_ip.c:527
#define AUTO_IP_PROBE_WAIT
Definition: auto_ip.h:58
#define NetInterface
Definition: net.h:34
NetInterface * interface
Network interface to configure.
Definition: auto_ip.h:181
AutoIpState autoIpGetState(AutoIpContext *context)
Retrieve current state.
Definition: auto_ip.c:206
AutoIpStateChangeCallback stateChangeEvent
FSM state change event.
Definition: auto_ip.h:184
#define AUTO_IP_ANNOUNCE_INTERVAL
Definition: auto_ip.h:100
#define IPV4_UNSPECIFIED_ADDR
Definition: ipv4.h:95
OsMutex netMutex
Definition: net.c:70
IPv4 context.
Definition: ipv4.h:317
void autoIpChangeState(AutoIpContext *context, AutoIpState newState, systime_t delay)
Update Auto-IP FSM state.
Definition: auto_ip.c:492
error_t autoIpStop(AutoIpContext *context)
Stop Auto-IP process.
Definition: auto_ip.c:175
uint8_t n
#define AUTO_IP_ANNOUNCE_WAIT
Definition: auto_ip.h:86
void autoIpDumpConfig(AutoIpContext *context)
Dump Auto-IP configuration for debugging purpose.
Definition: auto_ip.c:545
#define FALSE
Definition: os_port.h:44
#define AutoIpContext
Definition: auto_ip.h:137
void osAcquireMutex(OsMutex *mutex)
Acquire ownership of the specified mutex object.
error_t arpSendProbe(NetInterface *interface, Ipv4Addr targetIpAddr)
Send ARP probe.
Definition: arp.c:757
#define AUTO_IP_PROBE_MAX
Definition: auto_ip.h:79
#define AUTO_IP_DEFEND_INTERVAL
Definition: auto_ip.h:121