Rename "subsystems" directory to "base"
[oonf.git] / src / nhdp / auto_ll4 / auto_ll4.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon version 2 (olsrd2)
4  * Copyright (c) 2004-2015, the olsr.org team - see HISTORY file
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  *   notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above copyright
14  *   notice, this list of conditions and the following disclaimer in
15  *   the documentation and/or other materials provided with the
16  *   distribution.
17  * * Neither the name of olsr.org, olsrd nor the names of its
18  *   contributors may be used to endorse or promote products derived
19  *   from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * Visit http://www.olsr.org for more information.
35  *
36  * If you find this software useful feel free to make a donation
37  * to the project. For more information see the website or contact
38  * the copyright holders.
39  *
40  */
41
42 /**
43  * @file
44  */
45
46 #include <errno.h>
47 #include <stdio.h>
48
49 #include <oonf/libcommon/autobuf.h>
50 #include <oonf/libcommon/avl.h>
51 #include <oonf/oonf.h>
52 #include <oonf/libconfig/cfg_schema.h>
53 #include <oonf/libcore/oonf_cfg.h>
54 #include <oonf/libcore/oonf_logging.h>
55 #include <oonf/libcore/oonf_subsystem.h>
56 #include <oonf/libcore/os_core.h>
57 #include <oonf/base/oonf_class.h>
58 #include <oonf/base/oonf_timer.h>
59 #include <oonf/base/os_interface.h>
60
61 #include <oonf/nhdp/nhdp/nhdp.h>
62 #include <oonf/nhdp/nhdp/nhdp_domain.h>
63 #include <oonf/nhdp/nhdp/nhdp_interfaces.h>
64
65 #include <oonf/nhdp/auto_ll4/auto_ll4.h>
66
67 /* constants and definitions */
68 #define LOG_AUTO_LL4 _olsrv2_auto_ll4_subsystem.logging
69
70 /**
71  * NHDP interface class extension of autoll4 plugin
72  */
73 struct _nhdp_if_autoll4 {
74   /*! timer until next update of autogenerated ip */
75   struct oonf_timer_instance update_timer;
76
77   /*! back pointer to NHDP interface */
78   struct nhdp_interface *nhdp_if;
79
80   /*! we have registered a NHDP interface instance */
81   bool registered;
82
83   /*! true if autoll4 is active for this interface */
84   bool active;
85
86   /*! delay until plugin starts generating interface addresses */
87   uint64_t startup_delay;
88
89   /*! true if current LL4 was generated by the plugin */
90   bool plugin_generated;
91
92   /*! data structure for setting and resetting auto-configured address */
93   struct os_interface_ip_change os_addr;
94
95   /*! currently configured address */
96   struct netaddr auto_ll4_addr;
97 };
98
99 /* prototypes */
100 static int _init(void);
101 static void _initiate_shutdown(void);
102 static void _cleanup(void);
103
104 static void _cb_add_nhdp_interface(void *);
105 static void _cb_remove_nhdp_interface(void *);
106 static void _cb_address_finished(struct os_interface_ip_change *, int);
107 static void _cb_update_timer(struct oonf_timer_instance *);
108 static int _get_current_if_ipv4_addresscount(
109   struct os_interface *os_if, struct netaddr *ll4_addr, struct netaddr *current_ll4);
110 static void _generate_default_address(struct _nhdp_if_autoll4 *auto_ll4, const struct netaddr *ipv6_ll);
111
112 static void _commit_address(struct _nhdp_if_autoll4 *auto_ll4, struct netaddr *addr, bool set);
113 uint16_t _calculate_host_part(const struct netaddr *addr);
114 static bool _is_address_collision(struct netaddr *auto_ll4, struct netaddr *addr);
115 static bool _nhdp_if_has_collision(struct nhdp_interface *nhdp_if, struct netaddr *addr);
116 static void _cb_ifaddr_change(void *);
117 static void _cb_laddr_change(void *);
118 static void _cb_2hop_change(void *);
119 static void _cb_if_cfg_changed(void);
120
121 /* plugin declaration */
122 static struct cfg_schema_entry _interface_entries[] = {
123   CFG_MAP_BOOL(
124     _nhdp_if_autoll4, active, "auto_ll4", "true", "Controls autogeneration of IPv4 linklocal IPs on interface."),
125   CFG_MAP_CLOCK(_nhdp_if_autoll4, startup_delay, "autoll4_startup_delay", "10",
126     "Startup time until first auto-configured IPv4 linklocal should be selected."),
127 };
128
129 static struct cfg_schema_section _interface_section = {
130   CFG_OSIF_SCHEMA_INTERFACE_SECTION_INIT,
131
132   .cb_delta_handler = _cb_if_cfg_changed,
133   .entries = _interface_entries,
134   .entry_count = ARRAYSIZE(_interface_entries),
135 };
136
137 static const char *_dependencies[] = {
138   OONF_CLASS_SUBSYSTEM,
139   OONF_TIMER_SUBSYSTEM,
140   OONF_OS_INTERFACE_SUBSYSTEM,
141   OONF_NHDP_SUBSYSTEM,
142 };
143 static struct oonf_subsystem _olsrv2_auto_ll4_subsystem = {
144   .name = OONF_AUTO_LL4_SUBSYSTEM,
145   .dependencies = _dependencies,
146   .dependencies_count = ARRAYSIZE(_dependencies),
147   .descr = "OLSRv2 Automatic IPv4 Linklayer IP generation plugin",
148   .author = "Henning Rogge",
149
150   .cfg_section = &_interface_section,
151
152   .init = _init,
153   .cleanup = _cleanup,
154   .initiate_shutdown = _initiate_shutdown,
155 };
156 DECLARE_OONF_PLUGIN(_olsrv2_auto_ll4_subsystem);
157
158 /* timer for handling new NHDP neighbors */
159 static struct oonf_timer_class _startup_timer_info = {
160   .name = "Initial delay until first IPv4 linklocal IPs are generated",
161   .callback = _cb_update_timer,
162   .periodic = false,
163 };
164
165 /* NHDP interface extension/listener */
166 static struct oonf_class_extension _nhdp_if_extenstion = {
167   .ext_name = "auto ll4 generation",
168   .class_name = NHDP_CLASS_INTERFACE,
169   .size = sizeof(struct _nhdp_if_autoll4),
170
171   .cb_add = _cb_add_nhdp_interface,
172   .cb_remove = _cb_remove_nhdp_interface,
173 };
174
175 /* NHDP interface address listener */
176 static struct oonf_class_extension _nhdp_ifaddr_listener = {
177   .ext_name = "auto ll4 generation",
178   .class_name = NHDP_CLASS_INTERFACE_ADDRESS,
179
180   .cb_add = _cb_ifaddr_change,
181   .cb_remove = _cb_ifaddr_change,
182 };
183
184 /* NHDP link address listener */
185 static struct oonf_class_extension _nhdp_laddr_listener = {
186   .ext_name = "auto ll4 laddr listener",
187   .class_name = NHDP_CLASS_LINK_ADDRESS,
188
189   .cb_add = _cb_laddr_change,
190   .cb_remove = _cb_laddr_change,
191 };
192
193 /* NHDP twohop listener */
194 static struct oonf_class_extension _nhdp_2hop_listener = {
195   .ext_name = "auto ll4 twohop listener",
196   .class_name = NHDP_CLASS_LINK_2HOP,
197
198   .cb_add = _cb_2hop_change,
199   .cb_remove = _cb_2hop_change,
200 };
201
202 /**
203  * Initialize plugin
204  * @return -1 if an error happened, 0 otherwise
205  */
206 static int
207 _init(void) {
208   if (oonf_class_extension_add(&_nhdp_if_extenstion)) {
209     OONF_WARN(LOG_AUTO_LL4, "Cannot allocate extension for NHDP interface data");
210     return -1;
211   }
212
213   oonf_class_extension_add(&_nhdp_ifaddr_listener);
214   oonf_class_extension_add(&_nhdp_laddr_listener);
215   oonf_class_extension_add(&_nhdp_2hop_listener);
216   oonf_timer_add(&_startup_timer_info);
217   return 0;
218 }
219
220 /**
221  * Initiate cleanup of plugin.
222  */
223 static void
224 _initiate_shutdown(void) {
225   struct nhdp_interface *nhdp_if, *nhdp_if_it;
226
227   /* cleanup plugin specific data for interfaces that still exist */
228   avl_for_each_element_safe(nhdp_interface_get_tree(), nhdp_if, _node, nhdp_if_it) {
229     OONF_DEBUG(LOG_AUTO_LL4, "initiate cleanup if: %s", nhdp_interface_get_if_listener(nhdp_if)->data->name);
230     _cb_remove_nhdp_interface(nhdp_if);
231   }
232   oonf_class_extension_remove(&_nhdp_2hop_listener);
233   oonf_class_extension_remove(&_nhdp_laddr_listener);
234   oonf_class_extension_remove(&_nhdp_ifaddr_listener);
235 }
236
237 /**
238  * Cleanup plugin
239  */
240 static void
241 _cleanup(void) {
242   struct nhdp_interface *nhdp_if, *nhdp_if_it;
243   struct _nhdp_if_autoll4 *auto_ll4;
244
245   avl_for_each_element_safe(nhdp_interface_get_tree(), nhdp_if, _node, nhdp_if_it) {
246     _cb_remove_nhdp_interface(nhdp_if);
247
248     auto_ll4 = oonf_class_get_extension(&_nhdp_if_extenstion, nhdp_if);
249     if (auto_ll4->registered) {
250       nhdp_interface_remove(nhdp_if);
251     }
252   }
253
254   oonf_timer_remove(&_startup_timer_info);
255   oonf_class_extension_remove(&_nhdp_if_extenstion);
256 }
257
258 /**
259  * Callback triggered when a new NHDP interface is added to the database
260  * @param ptr pointer to NHDP interface
261  */
262 static void
263 _cb_add_nhdp_interface(void *ptr) {
264   struct nhdp_interface *nhdp_if = ptr;
265   struct _nhdp_if_autoll4 *auto_ll4;
266
267   /* get auto linklayer extension */
268   auto_ll4 = oonf_class_get_extension(&_nhdp_if_extenstion, nhdp_if);
269   auto_ll4->nhdp_if = nhdp_if;
270
271   /* initialize static part of routing data */
272   auto_ll4->os_addr.cb_finished = _cb_address_finished;
273   auto_ll4->os_addr.scope = OS_ADDR_SCOPE_LINK;
274
275   /* activate update_timer delay timer */
276   auto_ll4->update_timer.class = &_startup_timer_info;
277 }
278
279 /**
280  * Callback triggered when a NHDP interface is removed from the database
281  * @param ptr pointer to NHDP interface
282  */
283 static void
284 _cb_remove_nhdp_interface(void *ptr) {
285   struct nhdp_interface *nhdp_if = ptr;
286   struct _nhdp_if_autoll4 *auto_ll4;
287
288   /* get auto linklayer extension */
289   auto_ll4 = oonf_class_get_extension(&_nhdp_if_extenstion, nhdp_if);
290   if (!auto_ll4->nhdp_if) {
291     /* Interface already cleaned up */
292     return;
293   }
294
295   /* stop running address setting feedback */
296   auto_ll4->os_addr.cb_finished = NULL;
297   os_interface_address_interrupt(&auto_ll4->os_addr);
298
299   /* cleanup address if necessary */
300   if (auto_ll4->active && auto_ll4->plugin_generated) {
301     auto_ll4->os_addr.set = false;
302     os_interface_address_set(&auto_ll4->os_addr);
303   }
304   auto_ll4->active = false;
305
306   /* stop update timer */
307   oonf_timer_stop(&auto_ll4->update_timer);
308
309   /* cleanup pointer to nhdp interface */
310   auto_ll4->nhdp_if = NULL;
311 }
312
313 /**
314  * Callback triggered when the kernel acknowledged that an address has
315  * been set on an interface (or not, because an error happened)
316  * @param os_addr pointer to address parameters
317  * @param error 0 if address was set, otherwise an error happened
318  */
319 static void
320 _cb_address_finished(struct os_interface_ip_change *os_addr, int error) {
321   struct _nhdp_if_autoll4 *auto_ll4;
322 #ifdef OONF_LOG_DEBUG_INFO
323   struct netaddr_str nbuf;
324   char ibuf[IF_NAMESIZE];
325 #endif
326
327   /* get auto linklayer extension */
328   auto_ll4 = container_of(os_addr, typeof(*auto_ll4), os_addr);
329   if (!auto_ll4->nhdp_if) {
330     /* Interface already cleaned up */
331     return;
332   }
333
334   OONF_DEBUG(LOG_AUTO_LL4, "Got feedback from netlink for %s address %s on if %s: %s (%d)",
335     os_addr->set ? "setting" : "resetting", netaddr_to_string(&nbuf, &os_addr->address),
336     if_indextoname(os_addr->if_index, ibuf), strerror(error), error);
337
338   if (error) {
339     if ((os_addr->set && error != EEXIST) || (!os_addr->set && error != EADDRNOTAVAIL)) {
340       /* try again */
341       oonf_timer_set(&auto_ll4->update_timer, 1000);
342       return;
343     }
344   }
345 }
346
347 /**
348  * Callback triggered when an address changes on a NHDP interface
349  * @param ptr pointer to NHDP interface
350  */
351 static void
352 _cb_ifaddr_change(void *ptr) {
353   struct nhdp_interface_addr *ifaddr = ptr;
354   struct nhdp_interface *nhdp_if;
355   struct _nhdp_if_autoll4 *auto_ll4;
356 #ifdef OONF_LOG_DEBUG_INFO
357   struct netaddr_str nbuf;
358 #endif
359
360   nhdp_if = ifaddr->interf;
361
362   /* get auto linklayer extension */
363   auto_ll4 = oonf_class_get_extension(&_nhdp_if_extenstion, nhdp_if);
364   if (!auto_ll4->nhdp_if) {
365     /* Interface already cleaned up */
366     return;
367   }
368
369   if (!oonf_timer_is_active(&auto_ll4->update_timer)) {
370     /* request delayed address check */
371     oonf_timer_set(&auto_ll4->update_timer, 1);
372
373     OONF_DEBUG(LOG_AUTO_LL4, "Interface address changed: %s", netaddr_to_string(&nbuf, &ifaddr->if_addr));
374   }
375 }
376
377 /**
378  * Callback triggered when a link address of a NHDP neighbor changes
379  * @param ptr pointer to NHDP link address
380  */
381 static void
382 _cb_laddr_change(void *ptr) {
383   struct nhdp_laddr *laddr = ptr;
384   struct nhdp_interface *nhdp_if;
385   struct _nhdp_if_autoll4 *auto_ll4;
386 #ifdef OONF_LOG_DEBUG_INFO
387   struct netaddr_str nbuf;
388 #endif
389
390   nhdp_if = laddr->link->local_if;
391
392   /* get auto linklayer extension */
393   auto_ll4 = oonf_class_get_extension(&_nhdp_if_extenstion, nhdp_if);
394   if (!auto_ll4->nhdp_if) {
395     /* Interface already cleaned up */
396     return;
397   }
398
399   if (!oonf_timer_is_active(&auto_ll4->update_timer)) {
400     /* request delayed address check */
401     oonf_timer_set(&auto_ll4->update_timer, 1);
402
403     OONF_DEBUG(LOG_AUTO_LL4, "Link address changed: %s", netaddr_to_string(&nbuf, &laddr->link_addr));
404   }
405 }
406
407 /**
408  * Callback triggered when a two-hop address of a NHDP neighbor changes
409  * @param ptr pointer to NHDP two-hop address
410  */
411 static void
412 _cb_2hop_change(void *ptr) {
413   struct nhdp_l2hop *l2hop = ptr;
414   struct nhdp_interface *nhdp_if;
415   struct _nhdp_if_autoll4 *auto_ll4;
416 #ifdef OONF_LOG_DEBUG_INFO
417   struct netaddr_str nbuf;
418 #endif
419
420   nhdp_if = l2hop->link->local_if;
421
422   /* get auto linklayer extension */
423   auto_ll4 = oonf_class_get_extension(&_nhdp_if_extenstion, nhdp_if);
424   if (!auto_ll4->nhdp_if) {
425     /* Interface already cleaned up */
426     return;
427   }
428
429   if (!oonf_timer_is_active(&auto_ll4->update_timer)) {
430     /* request delayed address check */
431     oonf_timer_set(&auto_ll4->update_timer, 1);
432
433     OONF_DEBUG(LOG_AUTO_LL4, "2Hop address changed: %s", netaddr_to_string(&nbuf, &l2hop->twohop_addr));
434   }
435 }
436
437 /**
438  * Callback triggered when the plugin should check if the autoconfigured
439  * address is still okay.
440  * @param ptr timer instance that fired
441  */
442 static void
443 _cb_update_timer(struct oonf_timer_instance *ptr) {
444   struct nhdp_interface *nhdp_if;
445   struct os_interface *os_if;
446   struct _nhdp_if_autoll4 *auto_ll4;
447   struct netaddr current_ll4;
448   int count;
449   uint32_t rnd;
450   uint16_t hash;
451 #ifdef OONF_LOG_DEBUG_INFO
452   struct netaddr_str nbuf;
453 #endif
454
455   auto_ll4 = container_of(ptr, struct _nhdp_if_autoll4, update_timer);
456   nhdp_if = auto_ll4->nhdp_if;
457
458   if (!nhdp_if) {
459     return;
460   }
461
462   /* get pointer to interface data */
463   os_if = nhdp_interface_get_if_listener(nhdp_if)->data;
464   auto_ll4->os_addr.if_index = os_if->index;
465
466   /* ignore loopback */
467   if (os_if->flags.loopback || !os_if->flags.up) {
468     OONF_DEBUG(LOG_AUTO_LL4, "Ignore interface %s: its loopback or down", os_if->name);
469     return;
470   }
471
472   /* query current interface status */
473   count = _get_current_if_ipv4_addresscount(os_if, &current_ll4, &auto_ll4->auto_ll4_addr);
474
475   if (!auto_ll4->active) {
476     if (auto_ll4->plugin_generated && count == 1 && netaddr_cmp(&current_ll4, &auto_ll4->auto_ll4_addr) == 0) {
477       /* remove our configured address, the user set a different one */
478       _commit_address(auto_ll4, &current_ll4, false);
479       OONF_DEBUG(LOG_AUTO_LL4, "Remove LL4, user has selected his own address");
480     }
481     OONF_DEBUG(LOG_AUTO_LL4, "Done (interface %s is not active)", os_if->name);
482     return;
483   }
484
485   if (count > 1) {
486     if (auto_ll4->plugin_generated && netaddr_cmp(&current_ll4, &auto_ll4->auto_ll4_addr) == 0) {
487       /* remove our configured address, the user set a different one */
488       _commit_address(auto_ll4, &current_ll4, false);
489       OONF_DEBUG(LOG_AUTO_LL4, "Remove LL4, user has selected his own address");
490     }
491     OONF_DEBUG(LOG_AUTO_LL4, "Done (interface %s has additional addresses)", os_if->name);
492     return;
493   }
494
495   if (count == 1) {
496     if (netaddr_get_address_family(&current_ll4) == AF_UNSPEC) {
497       /* do nothing, user set a non-LL interface IP */
498       OONF_DEBUG(LOG_AUTO_LL4, "Done (interface %s has non-ll ipv4)", os_if->name);
499       return;
500     }
501
502     /* copy the current IP to the setting variable */
503     memcpy(&auto_ll4->auto_ll4_addr, &current_ll4, sizeof(current_ll4));
504   }
505
506   if (netaddr_get_address_family(&auto_ll4->auto_ll4_addr) == AF_UNSPEC) {
507     /* try our default IP first */
508     _generate_default_address(auto_ll4, os_if->if_linklocal_v6);
509   }
510
511   while (_nhdp_if_has_collision(nhdp_if, &auto_ll4->auto_ll4_addr)) {
512     /* roll up a random address */
513     if (os_core_get_random(&rnd, sizeof(rnd))) {
514       OONF_WARN(LOG_AUTO_LL4, "Could not get random data");
515       return;
516     }
517     hash = htons((rnd % (256 * 254)) + 256);
518     netaddr_create_host_bin(&auto_ll4->auto_ll4_addr, &NETADDR_IPV4_LINKLOCAL, &hash, sizeof(hash));
519   }
520
521   if (netaddr_cmp(&auto_ll4->auto_ll4_addr, &current_ll4) == 0) {
522     /* nothing to do */
523     OONF_DEBUG(
524       LOG_AUTO_LL4, "Done (interface %s already has ll %s)", os_if->name, netaddr_to_string(&nbuf, &current_ll4));
525     return;
526   }
527
528   if (netaddr_get_address_family(&current_ll4) != AF_UNSPEC) {
529     /* remove current ipv4 linklocal address */
530     OONF_DEBUG(LOG_AUTO_LL4, "Remove old LL4 %s", netaddr_to_string(&nbuf, &current_ll4));
531     _commit_address(auto_ll4, &current_ll4, false);
532   }
533   else {
534     /* set new ipv4 linklocal address */
535     OONF_DEBUG(LOG_AUTO_LL4, "Set new LL4 %s", netaddr_to_string(&nbuf, &auto_ll4->auto_ll4_addr));
536     _commit_address(auto_ll4, &auto_ll4->auto_ll4_addr, true);
537   }
538 }
539
540 /**
541  * Generate a new auto-configured address on an interface
542  * @param auto_ll4 private auto_ll4 data structure
543  * @param ipv6_ll linklocal IPv6 address
544  */
545 static void
546 _generate_default_address(struct _nhdp_if_autoll4 *auto_ll4, const struct netaddr *ipv6_ll) {
547   uint16_t host_part;
548 #ifdef OONF_LOG_DEBUG_INFO
549   struct netaddr_str nbuf1, nbuf2;
550 #endif
551
552   if (!ipv6_ll || netaddr_get_address_family(ipv6_ll) == AF_UNSPEC) {
553     /* no ipv6 linklocal address */
554     netaddr_invalidate(&auto_ll4->auto_ll4_addr);
555     return;
556   }
557
558   host_part = _calculate_host_part(ipv6_ll);
559
560   /*
561    * generate the address between
562    * 169.254.1.0 and 169.254.254.255
563    */
564   netaddr_create_host_bin(&auto_ll4->auto_ll4_addr, &NETADDR_IPV4_LINKLOCAL, &host_part, sizeof(host_part));
565
566   OONF_DEBUG(LOG_AUTO_LL4, "IPv6 ll %s => IPv4 ll %s", netaddr_to_string(&nbuf1, ipv6_ll),
567     netaddr_to_string(&nbuf2, &auto_ll4->auto_ll4_addr));
568 }
569
570 /**
571  * Get the current number of IPv4 addresses of an interface and
572  * copy an IPv4 link-local address if set.
573  * @param os_if interface data
574  * @param ll4_addr return buffer for link-local address
575  * @param current_ll4 current link-local address, this will be returned
576  *   if set, even if multiple ipv4 link-local addresses are present
577  * @return number of IPv4 addresses on interface
578  */
579 static int
580 _get_current_if_ipv4_addresscount(struct os_interface *os_if, struct netaddr *ll4_addr, struct netaddr *current_ll4) {
581   struct os_interface_ip *ip;
582   bool match;
583   int count;
584 #ifdef OONF_LOG_DEBUG_INFO
585   struct netaddr_str nbuf1, nbuf2;
586 #endif
587
588   /* reset counter */
589   count = 0;
590   netaddr_invalidate(ll4_addr);
591   match = false;
592
593   avl_for_each_element(&os_if->addresses, ip, _node) {
594     OONF_DEBUG(LOG_AUTO_LL4, "Interface %s (%u) has address %s %s", os_if->name, os_if->index,
595       netaddr_to_string(&nbuf1, &ip->address), netaddr_to_string(&nbuf2, os_if->if_linklocal_v6));
596
597     if (netaddr_get_address_family(&ip->address) == AF_INET) {
598       /* count IPv4 addresses */
599       count++;
600
601       /* copy one IPv4 link-local address, if possible the current one */
602       if (!match && netaddr_is_in_subnet(&NETADDR_IPV4_LINKLOCAL, &ip->address)) {
603         memcpy(ll4_addr, &ip->address, sizeof(*ll4_addr));
604
605         if (netaddr_cmp(&ip->address, current_ll4) == 0) {
606           match = true;
607         }
608       }
609     }
610   }
611
612   return count;
613 }
614
615 /**
616  * Set/reset an address on a NHDP interface
617  * @param auto_ll4 pointer to data structure for auto-configured
618  * addresses on a NHDP interface
619  */
620 static void
621 _commit_address(struct _nhdp_if_autoll4 *auto_ll4, struct netaddr *addr, bool set) {
622 #ifdef OONF_LOG_INFO
623   struct netaddr_str nbuf;
624   char ibuf[IF_NAMESIZE];
625 #endif
626
627   memcpy(&auto_ll4->os_addr.address, addr, sizeof(*addr));
628   auto_ll4->os_addr.set = set;
629
630   OONF_INFO(LOG_AUTO_LL4, "%s address %s on interface %s (%u)", auto_ll4->os_addr.set ? "Set" : "Remove",
631     netaddr_to_string(&nbuf, &auto_ll4->os_addr.address), if_indextoname(auto_ll4->os_addr.if_index, ibuf),
632     auto_ll4->os_addr.if_index);
633
634   /* remember if the plugin set/reset the address */
635   auto_ll4->plugin_generated = set;
636
637   /* set prefix length */
638   netaddr_set_prefix_length(&auto_ll4->os_addr.address, 16);
639
640   /* call operation system */
641   os_interface_address_set(&auto_ll4->os_addr);
642 }
643
644 /**
645  * Checks if an address would collide with any neighbor on a
646  * NHDP interface, both one- and two-hop.
647  * @param nhdp_if pointer to NHDP interface
648  * @param addr pointer to address that might collide
649  * @return true if address or hash collides with known neighbor,
650  *   false otherwise
651  */
652 static bool
653 _nhdp_if_has_collision(struct nhdp_interface *nhdp_if, struct netaddr *addr) {
654   struct nhdp_link *lnk;
655   struct nhdp_laddr *laddr;
656   struct nhdp_l2hop *l2hop;
657
658   if (netaddr_is_unspec(addr)) {
659     return true;
660   }
661
662   list_for_each_element(&nhdp_if->_links, lnk, _if_node) {
663     /* check for collision with one-hop neighbor */
664     avl_for_each_element(&lnk->_addresses, laddr, _link_node) {
665       if (_is_address_collision(addr, &laddr->link_addr)) {
666         return true;
667       }
668     }
669
670     avl_for_each_element(&lnk->_2hop, l2hop, _link_node) {
671       if (_is_address_collision(addr, &l2hop->twohop_addr)) {
672         return true;
673       }
674     }
675   }
676   return false;
677 }
678
679 /**
680  * Check if an auto-configured address has a collision
681  * @param auto_ll4 pointer to data structure for auto-configured
682  * @param addr address that could collide with auto-configured IP
683  * @return true if address collides, false otherwise
684  */
685 static bool
686 _is_address_collision(struct netaddr *auto_ll4, struct netaddr *addr) {
687 #ifdef OONF_LOG_DEBUG_INFO
688   struct netaddr_str nbuf1, nbuf2;
689 #endif
690   uint16_t hostpart;
691   const char *ptr;
692
693   OONF_DEBUG(LOG_AUTO_LL4, "Check %s for collision with address %s", netaddr_to_string(&nbuf1, auto_ll4),
694     netaddr_to_string(&nbuf2, addr));
695
696   if (netaddr_get_address_family(addr) == AF_INET) {
697     if (netaddr_cmp(auto_ll4, addr) == 0) {
698       OONF_DEBUG(LOG_AUTO_LL4, "Collision with address");
699       return true;
700     }
701   }
702   else {
703     hostpart = _calculate_host_part(addr);
704     ptr = netaddr_get_binptr(auto_ll4);
705     if (memcmp(ptr + 2, &hostpart, 2) == 0) {
706       OONF_DEBUG(LOG_AUTO_LL4, "Collision with hashed IPv6!");
707       return true;
708     }
709   }
710
711   return false;
712 }
713
714 /**
715  * Calculates host part of an auto-configured address
716  * based on a hash value
717  * @param addr address that should be hashed
718  * @return number between 256 (.1.0) and 65279 (.254.255)
719  */
720 uint16_t
721 _calculate_host_part(const struct netaddr *addr) {
722   uint32_t hash, i;
723   const char *key;
724   size_t len;
725
726   key = netaddr_get_binptr(addr);
727   len = netaddr_get_binlength(addr);
728
729   /*
730    * step 1: calculate Jenkins hash
731    *
732    * This is no cryptographic secure has, it doesn't need
733    * to be. Its just to make sure all 6 byte of the MAC
734    * address are the source of the two-byte host part
735    * of the auto-configuredIP.
736    */
737   for (hash = i = 0; i < len; ++i) {
738     hash += key[i];
739     hash += (hash << 10);
740     hash ^= (hash >> 6);
741   }
742   hash += (hash << 3);
743   hash ^= (hash >> 11);
744   hash += (hash << 15);
745
746   /* step 2: calculate host part of linklocal address */
747   return htons((hash % (254 * 256)) + 256);
748 }
749
750 /**
751  * Plugin triggered when interface auto-configuration parameter changes
752  */
753 static void
754 _cb_if_cfg_changed(void) {
755   struct _nhdp_if_autoll4 *auto_ll4 = NULL;
756   struct nhdp_interface *nhdp_if;
757   const char *ifname;
758   char ifbuf[IF_NAMESIZE];
759
760   ifname = cfg_get_phy_if(ifbuf, _interface_section.section_name);
761
762   if (_interface_section.pre == NULL) {
763     /* increase nhdp_interface refcount */
764     nhdp_if = nhdp_interface_add(ifname);
765   }
766   else {
767     /* get interface */
768     nhdp_if = nhdp_interface_get(ifname);
769   }
770
771   if (nhdp_if) {
772     /* get block domain extension */
773     auto_ll4 = oonf_class_get_extension(&_nhdp_if_extenstion, nhdp_if);
774     auto_ll4->registered = true;
775   }
776
777   if (_interface_section.post == NULL) {
778     /* section was removed */
779     if (nhdp_if != NULL) {
780       auto_ll4->registered = false;
781
782       /* decrease nhdp_interface refcount */
783       nhdp_interface_remove(nhdp_if);
784     }
785
786     nhdp_if = NULL;
787   }
788
789   if (!nhdp_if) {
790     return;
791   }
792
793   /* get configuration */
794   if (cfg_schema_tobin(auto_ll4, _interface_section.post, _interface_entries, ARRAYSIZE(_interface_entries))) {
795     return;
796   }
797
798   if (!auto_ll4->plugin_generated) {
799     oonf_timer_set(&auto_ll4->update_timer, auto_ll4->startup_delay);
800   }
801   else if (!oonf_timer_is_active(&auto_ll4->update_timer)) {
802     /* activate delayed update */
803     oonf_timer_set(&auto_ll4->update_timer, 1);
804   }
805 }