26a5cb23f25e4fbf13bddef361e9cde905df8334
[oonf.git] / src / generic / layer2_import / layer2_import.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 <oonf/oonf.h>
47 #include <oonf/libcommon/autobuf.h>
48 #include <oonf/libcommon/avl.h>
49 #include <oonf/libcommon/avl_comp.h>
50 #include <oonf/libcommon/list.h>
51 #include <oonf/libcommon/netaddr.h>
52 #include <oonf/libcommon/netaddr_acl.h>
53 #include <oonf/libconfig/cfg_schema.h>
54 #include <oonf/libcore/oonf_logging.h>
55 #include <oonf/libcore/oonf_subsystem.h>
56
57 #include <oonf/base/oonf_class.h>
58 #include <oonf/base/oonf_clock.h>
59 #include <oonf/base/oonf_layer2.h>
60 #include <oonf/base/oonf_timer.h>
61 #include <oonf/base/os_interface.h>
62 #include <oonf/base/os_routing.h>
63
64 #include <oonf/generic/layer2_import/layer2_import.h>
65
66 /* definitions */
67 #define LOG_L2_IMPORT _import_subsystem.logging
68
69 /**
70  * configuration of one LAN import instance
71  */
72 struct _import_entry {
73   /*! name of the lan import */
74   char name[20];
75
76   struct oonf_layer2_origin l2origin;
77
78   /*! domain of the lan import */
79   int32_t domain;
80
81   /*! address filter */
82   struct netaddr_acl filter;
83
84   /*! filter by prefix length, -1 to ignore */
85   int32_t prefix_length;
86
87   /*! filter by interface name, length null to ignore*/
88   char ifname[IF_NAMESIZE];
89
90   /*! filter by routing table id, 0 to ignore */
91   int32_t table;
92
93   /*! filter by routing protocol id, 0 to ignore */
94   int32_t protocol;
95
96   /*! filter by routing metric, 0 to ignore */
97   int32_t distance;
98
99   /*! set MAC address of imported entries to this interface */
100   char fixed_mac_if[IF_NAMESIZE];
101
102   /*! helper to keep track of MAC of 'fixed' interface */
103   struct os_interface_listener fixed_if_listener;
104
105   /*! layer2 interface name for all imported entries, might be empty string */
106   char fixed_l2if_name[IF_NAMESIZE];
107
108   /*! tree of all configured lan import */
109   struct avl_node _node;
110 };
111
112 /* prototypes */
113 static int _init(void);
114 static void _initiate_shutdown(void);
115 static void _cleanup(void);
116
117 static struct _import_entry *_get_import(const char *name);
118 static void _remove_import(struct _import_entry *);
119
120 static void _cb_query(struct os_route *filter, struct os_route *route);
121 static void _cb_query_finished(struct os_route *, int error);
122
123 static void _cb_rt_event(const struct os_route *, bool);
124 static void _cb_reload_routes(struct oonf_timer_instance *);
125
126 static void _cb_lan_cfg_changed(void);
127 static void _cb_l2_cfg_changed(void);
128 static void _cb_cfg_changed(struct cfg_schema_section *section, char *section_name);
129
130 /* plugin declaration */
131 static struct cfg_schema_entry _l2_entries[] = {
132   CFG_MAP_INT32_MINMAX(
133     _import_entry, domain, "domain", "-1", "Routing domain extension for filter, -1 for all domains", 0, -1, 255),
134   CFG_MAP_ACL(_import_entry, filter, "matches", ACL_DEFAULT_ACCEPT,
135     "Ip addresses the filter should be applied to"
136     " (the plugin will never import loopback, linklocal or multicast IPs)"),
137   CFG_MAP_INT32_MINMAX(_import_entry, prefix_length, "prefix_length", "-1",
138     "Prefix length the filter should be applied to, -1 for any prefix length", 0, -1, 128),
139   CFG_MAP_STRING_ARRAY(
140     _import_entry, ifname, "interface", "", "Interface name of matching routes, empty if all interfaces", IF_NAMESIZE),
141   CFG_MAP_INT32_MINMAX(
142     _import_entry, table, "table", "-1", "Routing table of matching routes, 0 for matching all tables", 0, -1, 255),
143   CFG_MAP_INT32_MINMAX(
144     _import_entry, protocol, "protocol", "-1", "Routing protocol of matching routes, 0 for all protocols", 0, -1, 255),
145   CFG_MAP_INT32_MINMAX(
146     _import_entry, distance, "metric", "-1", "Metric of matching routes, 0 for all metrics", 0, -1, INT32_MAX),
147   CFG_MAP_STRING_ARRAY(_import_entry, fixed_mac_if, "fixed_mac_if", "",
148     "Name of interface that will be used to fill in layer2 entry MAC addresses", IF_NAMESIZE),
149   CFG_MAP_STRING_ARRAY(_import_entry, fixed_l2if_name, "fixed_l2if_name", "",
150     "Name of interface that will be used to fill in layer2 interface name", IF_NAMESIZE),
151 };
152
153 static struct cfg_schema_entry _lan_entries[] = {
154   CFG_MAP_INT32_MINMAX(
155     _import_entry, domain, "domain", "-1", "Routing domain extension for filter, -1 for all domains", 0, -1, 255),
156   CFG_MAP_ACL(_import_entry, filter, "matches", ACL_DEFAULT_ACCEPT,
157     "Ip addresses the filter should be applied to"
158     " (the plugin will never import loopback, linklocal or multicast IPs)"),
159   CFG_MAP_INT32_MINMAX(_import_entry, prefix_length, "prefix_length", "-1",
160     "Prefix length the filter should be applied to, -1 for any prefix length", 0, -1, 128),
161   CFG_MAP_STRING_ARRAY(
162     _import_entry, ifname, "interface", "", "Interface name of matching routes, empty if all interfaces", IF_NAMESIZE),
163   CFG_MAP_INT32_MINMAX(
164     _import_entry, table, "table", "-1", "Routing table of matching routes, 0 for matching all tables", 0, -1, 255),
165   CFG_MAP_INT32_MINMAX(
166     _import_entry, protocol, "protocol", "-1", "Routing protocol of matching routes, 0 for all protocols", 0, -1, 255),
167   CFG_MAP_INT32_MINMAX(
168     _import_entry, distance, "metric", "-1", "Metric of matching routes, 0 for all metrics", 0, -1, INT32_MAX),
169 };
170
171 static struct cfg_schema_section _lan_import_section = {
172   .type = OONF_LAN_IMPORT_SECTION,
173
174   /*
175    * this MUST NOT be CFG_SSMODE_NAMED_WITH_DEFAULT, otherwise it will
176    * activate without user interaction
177    */
178   .mode = CFG_SSMODE_NAMED,
179
180   .cb_delta_handler = _cb_lan_cfg_changed,
181
182   .entries = _lan_entries,
183   .entry_count = ARRAYSIZE(_lan_entries),
184 };
185
186 static struct cfg_schema_section _l2_import_section = {
187   .type = OONF_LAYER2_IMPORT_SUBSYSTEM,
188
189   /*
190    * this MUST NOT be CFG_SSMODE_NAMED_WITH_DEFAULT, otherwise it will
191    * activate without user interaction
192    */
193   .mode = CFG_SSMODE_NAMED,
194
195   .cb_delta_handler = _cb_l2_cfg_changed,
196
197   .entries = _l2_entries,
198   .entry_count = ARRAYSIZE(_l2_entries),
199
200   .next_section = &_lan_import_section,
201 };
202
203 static const char *_dependencies[] = {
204   OONF_CLASS_SUBSYSTEM,
205   OONF_CLOCK_SUBSYSTEM,
206   OONF_TIMER_SUBSYSTEM,
207   OONF_OS_INTERFACE_SUBSYSTEM,
208   OONF_OS_ROUTING_SUBSYSTEM,
209 };
210 static struct oonf_subsystem _import_subsystem = {
211   .name = OONF_LAYER2_IMPORT_SUBSYSTEM,
212   .dependencies = _dependencies,
213   .dependencies_count = ARRAYSIZE(_dependencies),
214   .descr = "OLSRv2 lan-import plugin",
215   .author = "Henning Rogge",
216
217   .cfg_section = &_l2_import_section,
218
219   .init = _init,
220   .cleanup = _cleanup,
221   .initiate_shutdown = _initiate_shutdown,
222 };
223 DECLARE_OONF_PLUGIN(_import_subsystem);
224
225 /* class definition for filters */
226 static struct oonf_class _import_class = {
227   .name = "l2 import filter",
228   .size = sizeof(struct _import_entry),
229 };
230
231 /* timer for triggering 'lazy' reload of routes */
232 static struct oonf_timer_class _route_reload = {
233   .name = "l2 import route reload",
234   .callback = _cb_reload_routes,
235 };
236 static struct oonf_timer_instance _route_reload_instance = {
237   .class = &_route_reload,
238 };
239
240 /* callback filter for dijkstra */
241 static struct os_route_listener _routing_listener = {
242   .cb_get = _cb_rt_event,
243 };
244
245 /* tree of lan importers */
246 static struct avl_tree _import_tree;
247
248 /* wildcard route for first query */
249 static struct os_route _unicast_query;
250
251 /**
252  * Initialize plugin
253  * @return always returns 0 (cannot fail)
254  */
255 static int
256 _init(void) {
257   avl_init(&_import_tree, avl_comp_strcasecmp, false);
258
259   oonf_class_add(&_import_class);
260   oonf_timer_add(&_route_reload);
261   os_routing_listener_add(&_routing_listener);
262
263   /* initialize wildcard query */
264   os_routing_init_wildcard_route(&_unicast_query);
265   _unicast_query.cb_get = _cb_query;
266   _unicast_query.cb_finished = _cb_query_finished;
267   _unicast_query.p.type = OS_ROUTE_UNICAST;
268   return 0;
269 }
270
271 static void
272 _initiate_shutdown(void) {
273   /* we are not interested in listening to all the routing cleanup */
274   os_routing_listener_remove(&_routing_listener);
275 }
276
277 /**
278  * Cleanup plugin
279  */
280 static void
281 _cleanup(void) {
282   struct _import_entry *import, *import_it;
283
284   avl_for_each_element_safe(&_import_tree, import, _node, import_it) {
285     _remove_import(import);
286   }
287
288   oonf_timer_remove(&_route_reload);
289   oonf_class_remove(&_import_class);
290 }
291
292 /**
293  * Wrapper for cb_get for wildcard query
294  * @param filter unused filter
295  * @param route route found by wildcard query
296  */
297 static void
298 _cb_query(struct os_route *filter __attribute__((unused)), struct os_route *route) {
299   _cb_rt_event(route, true);
300 }
301
302 /**
303  * Dummy cb_finished callback for wildcard query
304  * @param route route that was finished
305  * @param error error code
306  */
307 static void
308 _cb_query_finished(struct os_route *route __attribute__((unused)), int error __attribute__((unused))) {}
309
310 /**
311 * Remove old IP entries going to the same destination but different gateway
312 * and remember (if available) the one with the same gateway
313 * @param l2net layer2 network to iterate over
314 * @param import import data
315 * @param route_gw gateway address
316 * @param route_dst destination prefix
317 * @return address to layer2 network address with same gateway and destination, NULL if not found
318 */
319 static struct oonf_layer2_neighbor_address *
320 _remove_old_entries(struct oonf_layer2_net *l2net, struct _import_entry *import,
321                     const struct netaddr *route_gw, const struct netaddr *route_dst) {
322   struct oonf_layer2_neighbor_address *match, *l2n_it1, *l2n_start, *l2n_it2;
323   const struct netaddr *gw;
324   struct netaddr_str nbuf;
325
326   match = NULL;
327   OONF_DEBUG(LOG_L2_IMPORT, "route-DST: %s", netaddr_to_string(&nbuf, route_dst));
328   avl_for_each_elements_with_key_safe(&l2net->remote_neighbor_ips, l2n_it1, _net_node, l2n_start, l2n_it2, route_dst) {
329     OONF_DEBUG(LOG_L2_IMPORT, "l2n-remote: %s", netaddr_to_string(&nbuf, &l2n_it1->ip));
330     if (l2n_it1->origin == &import->l2origin) {
331       gw = oonf_layer2_neigh_get_nexthop(l2n_it1->l2neigh, netaddr_get_address_family(route_dst));
332       if (netaddr_cmp(gw, route_gw) == 0) {
333         match = l2n_it1;
334       }
335       else {
336         oonf_layer2_neigh_remove_ip(l2n_it1, &import->l2origin);
337       }
338     }
339   }
340   return match;
341 }
342
343 /**
344  * Callback for route listener
345  * @param route routing data
346  * @param set true if route was set, false otherwise
347  */
348 static void
349 _cb_rt_event(const struct os_route *route, bool set) {
350   struct _import_entry *import;
351   char ifname[IF_NAMESIZE];
352   struct oonf_layer2_net *l2net;
353   struct oonf_layer2_neigh *l2neigh;
354   struct oonf_layer2_neighbor_address *l2neigh_ip;
355   struct oonf_layer2_neigh_key nb_key;
356   const struct netaddr *gw, *dst, *mac;
357   const char *l2ifname, *macifname;
358
359 #ifdef OONF_LOG_DEBUG_INFO
360   struct os_route_str rbuf;
361   struct netaddr_str nbuf;
362 #endif
363
364   if (netaddr_is_in_subnet(&NETADDR_IPV4_MULTICAST, &route->p.key.dst) ||
365       netaddr_is_in_subnet(&NETADDR_IPV4_LINKLOCAL, &route->p.key.dst) ||
366       netaddr_is_in_subnet(&NETADDR_IPV4_LOOPBACK_NET, &route->p.key.dst) ||
367       netaddr_is_in_subnet(&NETADDR_IPV6_MULTICAST, &route->p.key.dst) ||
368       netaddr_is_in_subnet(&NETADDR_IPV6_LINKLOCAL, &route->p.key.dst) ||
369       netaddr_is_in_subnet(&NETADDR_IPV6_LOOPBACK, &route->p.key.dst)) {
370     /* ignore multicast, linklocal and loopback */
371     return;
372   }
373   if (route->p.type != OS_ROUTE_UNICAST) {
374     /* return all non-unicast type routes */
375     return;
376   }
377
378   OONF_DEBUG(
379     LOG_L2_IMPORT, "Received route event (%s): %s", set ? "set" : "remove", os_routing_to_string(&rbuf, &route->p));
380
381   /* get interface name for route */
382   if (!route->p.if_index) {
383     /* should not happen for unicast routes */
384     return;
385   }
386
387   if_indextoname(route->p.if_index, ifname);
388
389   avl_for_each_element(&_import_tree, import, _node) {
390     OONF_DEBUG(LOG_L2_IMPORT, "Check for import: %s", import->name);
391
392     /* check prefix length */
393     if (import->prefix_length != -1 && import->prefix_length != netaddr_get_prefix_length(&route->p.key.dst)) {
394       OONF_DEBUG(LOG_L2_IMPORT, "Bad prefix length %u (filter was %d)",
395                  netaddr_get_prefix_length(&route->p.key.dst), import->prefix_length);
396       continue;
397     }
398
399     /* check if destination matches */
400     if (!netaddr_acl_check_accept(&import->filter, &route->p.key.dst)) {
401       OONF_DEBUG(LOG_L2_IMPORT, "Bad prefix %s", netaddr_to_string(&nbuf, &route->p.key.dst));
402       continue;
403     }
404
405     /* check routing table */
406     if (import->table != -1 && import->table != route->p.table) {
407       OONF_DEBUG(LOG_L2_IMPORT, "Bad routing table %u (filter was %d)", route->p.table, import->table);
408       continue;
409     }
410
411     /* check protocol only for setting routes, its not reported for removing ones */
412     if (set && import->protocol != -1 && import->protocol != route->p.protocol) {
413       OONF_DEBUG(LOG_L2_IMPORT, "Bad protocol %u (filter was %d)", route->p.protocol, import->protocol);
414       continue;
415     }
416
417     /* check metric */
418     if (import->distance != -1 && import->distance != route->p.metric) {
419       OONF_DEBUG(LOG_L2_IMPORT, "Bad distance %u (filter was %d)", route->p.metric, import->distance);
420       continue;
421     }
422
423     /* check interface name */
424     if (import->ifname[0]) {
425       if (route->p.if_index == 0) {
426         OONF_DEBUG(LOG_L2_IMPORT, "Route has no interface");
427         continue;
428       }
429       if (strcmp(import->ifname, ifname) != 0) {
430         OONF_DEBUG(LOG_L2_IMPORT, "Bad interface '%s' (filter was '%s')", ifname, import->ifname);
431         continue;
432       }
433     }
434
435     /* see if user wants to overwrite layer2 network name */
436     if (import->fixed_l2if_name[0]) {
437       l2ifname = import->fixed_l2if_name;
438     }
439     else {
440       l2ifname = ifname;
441     }
442
443     OONF_DEBUG(LOG_L2_IMPORT, "Write imported route to l2 interface %s (%s)", l2ifname, import->fixed_l2if_name);
444     /* get layer2 network */
445     if (set) {
446       l2net = oonf_layer2_net_add(l2ifname);
447     }
448     else {
449       l2net = oonf_layer2_net_get(l2ifname);
450     }
451     if (!l2net) {
452       OONF_DEBUG(LOG_L2_IMPORT, "No l2 network '%s' found", l2ifname);
453       return;
454     }
455
456     mac = NULL;
457     macifname = "";
458     if (import->fixed_mac_if[0]) {
459       if (import->fixed_if_listener.data) {
460         mac = &import->fixed_if_listener.data->mac;
461         macifname = import->fixed_if_listener.data->name;
462       }
463     }
464     else {
465       mac = &l2net->if_listener.data->mac;
466       macifname = l2net->if_listener.data->name;
467     }
468     if (netaddr_is_unspec(mac)) {
469       OONF_DEBUG(LOG_L2_IMPORT, "Wait for interface (%s) data to be initialized", macifname);
470       if (!oonf_timer_is_active(&_route_reload_instance)) {
471         oonf_timer_set(&_route_reload_instance, 1000);
472       }
473       return;
474     }
475
476     dst = &route->p.key.dst;
477     gw = &route->p.gw;
478
479     l2neigh_ip = _remove_old_entries(l2net, import, gw, dst);
480     l2neigh = NULL;
481     /* get layer2 neighbor */
482     if (set && !l2neigh_ip) {
483       /* generate l2 key including LID */
484       if (oonf_layer2_neigh_generate_lid(&nb_key, &import->l2origin, mac)) {
485         OONF_DEBUG(LOG_L2_IMPORT, "Could not generate LID for MAC %s",
486             netaddr_to_string(&nbuf, mac));
487         continue;
488       }
489
490       l2neigh = oonf_layer2_neigh_add_lid(l2net, &nb_key);
491       if (!l2neigh) {
492         OONF_DEBUG(LOG_L2_IMPORT, "No l2 neighbor found");
493         return;
494       }
495
496       OONF_DEBUG(LOG_L2_IMPORT, "Import layer2 neighbor...");
497
498       /* make sure next hop is initialized */
499       oonf_layer2_neigh_set_nexthop(l2neigh, gw);
500       if (!oonf_layer2_neigh_get_remote_ip(l2neigh, dst)) {
501         oonf_layer2_neigh_add_ip(l2neigh, &import->l2origin, dst);
502       }
503       oonf_layer2_neigh_commit(l2neigh);
504     }
505     else if (!set && l2neigh_ip) {
506       l2neigh = l2neigh_ip->l2neigh;
507       oonf_layer2_neigh_remove_ip(l2neigh_ip, &import->l2origin);
508       oonf_layer2_neigh_commit(l2neigh);
509     }
510   }
511 }
512
513 /**
514  * Lookups a lan importer or create a new one
515  * @param name name of lan importer
516  * @return pointer to lan importer or NULL if out of memory
517  */
518 static struct _import_entry *
519 _get_import(const char *name) {
520   struct _import_entry *import;
521
522   import = avl_find_element(&_import_tree, name, import, _node);
523   if (import) {
524     return import;
525   }
526
527   import = oonf_class_malloc(&_import_class);
528   if (import == NULL) {
529     return NULL;
530   }
531
532   /* copy key and add to tree */
533   strscpy(import->name, name, sizeof(import->name));
534   import->_node.key = import->name;
535   avl_insert(&_import_tree, &import->_node);
536
537   /* request layer2 origin */
538   import->l2origin.name = import->name;
539   import->l2origin.priority = OONF_LAYER2_ORIGIN_RELIABLE;
540   import->l2origin.proactive = true;
541   import->l2origin.lid = true;
542
543   oonf_layer2_origin_add(&import->l2origin);
544
545   /* initialize l2 fixed interface listener */
546   import->fixed_if_listener.name = import->fixed_mac_if;
547
548   return import;
549 }
550
551 /**
552  * Free all resources associated with a route modifier
553  * @param import import entry
554  */
555 static void
556 _remove_import(struct _import_entry *import) {
557   oonf_layer2_origin_remove(&import->l2origin);
558   avl_remove(&_import_tree, &import->_node);
559   netaddr_acl_remove(&import->filter);
560   oonf_class_free(&_import_class, import);
561 }
562
563 /**
564  * Timer for reloading routes when interface data is not finished
565  * @param timer timer instance
566  */
567 static void
568 _cb_reload_routes(struct oonf_timer_instance *timer __attribute__((unused))) {
569   /* trigger wildcard query */
570   if (!os_routing_is_in_progress(&_unicast_query)) {
571     os_routing_query(&_unicast_query);
572   }
573 }
574
575 /**
576  * lan Configuration changed
577  */
578 static void
579 _cb_lan_cfg_changed(void) {
580   char name[20];
581
582   snprintf(name, sizeof(name), LAN_ORIGIN_PREFIX "%s", _lan_import_section.section_name);
583   _cb_cfg_changed(&_lan_import_section, name);
584 }
585
586 /**
587  * l2import Configuration changed
588  */
589 static void
590 _cb_l2_cfg_changed(void) {
591   char name[20];
592
593   snprintf(name, sizeof(name), L2IMPORT_ORIGIN_PREFIX "%s", _l2_import_section.section_name);
594   _cb_cfg_changed(&_l2_import_section, name);
595 }
596
597 /**
598  * (one of two) Configuration changed
599  */
600 static void
601 _cb_cfg_changed(struct cfg_schema_section *section, char *section_name) {
602   struct _import_entry *import;
603
604   /* get existing modifier */
605   import = _get_import(section_name);
606   if (!import) {
607     /* out of memory */
608     return;
609   }
610
611   if (section->post == NULL) {
612     /* section was removed */
613     _remove_import(import);
614     return;
615   }
616
617   /* remove old interface listener */
618   os_interface_remove(&import->fixed_if_listener);
619
620   if (cfg_schema_tobin(import, section->post, section->entries, section->entry_count)) {
621     OONF_WARN(LOG_L2_IMPORT, "Could not convert configuration data of section '%s'", section->section_name);
622
623     if (section->pre == NULL) {
624       _remove_import(import);
625     }
626     return;
627   }
628
629   cfg_get_phy_if(import->ifname, import->ifname);
630   cfg_get_phy_if(import->fixed_mac_if, import->fixed_mac_if);
631   cfg_get_phy_if(import->fixed_l2if_name, import->fixed_l2if_name);
632
633   if (!import->fixed_mac_if[0]) {
634     strscpy(import->fixed_mac_if, import->ifname, IF_NAMESIZE);
635   }
636   if (import->fixed_mac_if[0]) {
637     os_interface_add(&import->fixed_if_listener);
638   }
639
640   if (!oonf_timer_is_active(&_route_reload_instance)) {
641     oonf_timer_set(&_route_reload_instance, 1000);
642   }
643 }