defb77cdfaa2198b0247f9e8fd4af598a78be73f
[oonf.git] / src-plugins / generic / nl80211_listener / nl80211_listener.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 #define _GNU_SOURCE
47
48 /* must be first because of a problem with linux/netlink.h */
49 #include <sys/socket.h>
50
51 /* and now the rest of the includes */
52 #include <linux/types.h>
53 #include <linux/netlink.h>
54 #include <linux/genetlink.h>
55 #include "nl80211.h"
56 #include <netlink/attr.h>
57 #include <netlink/msg.h>
58 #include <sys/uio.h>
59
60 #include "common/autobuf.h"
61 #include "common/avl.h"
62 #include "common/avl_comp.h"
63 #include "common/common_types.h"
64 #include "common/netaddr.h"
65 #include "common/netaddr_acl.h"
66 #include "common/string.h"
67
68 #include "config/cfg.h"
69 #include "config/cfg_schema.h"
70 #include "core/oonf_logging.h"
71 #include "core/oonf_subsystem.h"
72 #include "subsystems/oonf_class.h"
73 #include "subsystems/oonf_layer2.h"
74 #include "subsystems/oonf_timer.h"
75 #include "subsystems/os_interface.h"
76 #include "subsystems/os_system.h"
77
78 #include "nl80211_listener/genl_get_family.h"
79 #include "nl80211_listener/nl80211_get_interface.h"
80 #include "nl80211_listener/nl80211_get_mpp.h"
81 #include "nl80211_listener/nl80211_get_station_dump.h"
82 #include "nl80211_listener/nl80211_get_survey.h"
83 #include "nl80211_listener/nl80211_get_wiphy.h"
84 #include "nl80211_listener/nl80211_listener.h"
85
86 /* definitions */
87
88 /**
89  * nl80211 configuration
90  */
91 struct _nl80211_config {
92   /*! interval between two series of netlink probes */
93   uint64_t interval;
94
95   /*! true if plugin should set multicast rate in the l2 db */
96   bool report_multicast_rate;
97 };
98
99 /**
100  * definition of a query to the nl80211 subsystem
101  */
102 struct _nl80211_query {
103   /*! netlink command that should be queried later */
104   uint8_t cmd;
105
106   /**
107    * Callback to send query
108    * @param nl netlink handler
109    * @param nl_msg netlink message header
110    * @param hdr generic message header
111    * @param interf netlink interface
112    */
113   void (* send)(struct os_system_netlink *nl, struct nlmsghdr *nl_msg,
114       struct genlmsghdr *hdr, struct nl80211_if *interf);
115
116   /**
117    * Callback to process incoming netlink data
118    * @param interf netlink interface
119    * @param hdr netlink message header
120    */
121   void (* process)(struct nl80211_if *interf, struct nlmsghdr *hdr);
122
123   /**
124    * Finalize the processing of the netlink query
125    * @param interf netlink interface
126    */
127   void (* finalize)(struct nl80211_if *interf);
128 };
129
130 /**
131  * Index number for nl80211 configuration entries
132  */
133 enum _nl80211_cfg_idx {
134   IDX_INTERVAL,
135   IDX_INTERFACES,
136   IDX_MC_RATE,
137 };
138
139 /**
140  * index numbers for netlink queries done by listener
141  */
142 enum _if_query {
143   QUERY_START       = 0,//!< QUERY_START
144   QUERY_GET_IF      = 0,//!< QUERY_GET_IF
145   QUERY_GET_WIPHY   = 1,//!< QUERY_GET_WIPHY
146   QUERY_GET_SURVEY  = 2,//!< QUERY_GET_SURVEY
147   QUERY_GET_MPP     = 3,//!< QUERY_GET_MPP
148   QUERY_GET_STATION = 4,//!< QUERY_GET_STATION
149   QUERY_END         = 5,//!< QUERY_END
150
151   QUERY_GET_FAMILY  = 6,//!< QUERY_GET_FAMILY
152
153   QUERY_COUNT,          //!< QUERY_COUNT
154 };
155
156 static struct _nl80211_query _if_query_ops[QUERY_COUNT] =
157 {
158     [QUERY_GET_IF] = {
159         NL80211_CMD_NEW_INTERFACE,
160         nl80211_send_get_interface, nl80211_process_get_interface_result, NULL,
161     },
162     [QUERY_GET_WIPHY] = {
163         NL80211_CMD_NEW_WIPHY,
164         nl80211_send_get_wiphy, nl80211_process_get_wiphy_result, nl80211_finalize_get_wiphy,
165     },
166     [QUERY_GET_SURVEY] = {
167         NL80211_CMD_NEW_SURVEY_RESULTS,
168         nl80211_send_get_survey, nl80211_process_get_survey_result, NULL,
169     },
170     [QUERY_GET_MPP] = {
171         NL80211_CMD_NEW_MPATH,
172         nl80211_send_get_mpp, nl80211_process_get_mpp_result, NULL,
173     },
174     [QUERY_GET_STATION] = {
175         NL80211_CMD_NEW_STATION,
176         nl80211_send_get_station_dump, nl80211_process_get_station_dump_result, NULL,
177     },
178 };
179
180 /* prototypes */
181 static void _early_cfg_init(void);
182 static int _init(void);
183 static void _cleanup(void);
184
185 static struct nl80211_if *_nl80211_if_get(const char *name);
186 static struct nl80211_if *_nl80211_if_add(const char *name);
187 static void _nl80211_if_remove(struct nl80211_if *);
188
189 static void _cb_config_changed(void);
190 static void _cb_if_config_changed(void);
191
192 static void _cb_transmission_event(struct oonf_timer_instance *);
193 static void _trigger_next_netlink_query(void);
194
195 static void _cb_nl_message(struct nlmsghdr *hdr);
196 static void _cb_nl_error(uint32_t seq, int error);
197 static void _cb_nl_timeout(void);
198 static void _cb_nl_done(uint32_t seq);
199
200
201 /* configuration */
202 static struct cfg_schema_section _if_section = {
203   .type = CFG_INTERFACE_SECTION,
204   .mode = CFG_INTERFACE_SECTION_MODE,
205   .cb_delta_handler = _cb_if_config_changed,
206   .entries = NULL,
207   .entry_count = 0,
208 };
209
210 static struct cfg_schema_entry _nl80211_entries[] = {
211   [IDX_INTERVAL] = CFG_MAP_CLOCK_MIN(_nl80211_config, interval, "interval", "1.0",
212       "Interval between two linklayer information updates", 100),
213   [IDX_INTERFACES] = CFG_VALIDATE_PRINTABLE_LEN("if", "",
214       "List of additional interfaces to read nl80211 data from",
215       IF_NAMESIZE, .list=true),
216   [IDX_MC_RATE] = CFG_MAP_BOOL(_nl80211_config, report_multicast_rate, "report_mc_rate", "false",
217       "Activate to write the multicast/broadcast speed into the layer2 database"),
218 };
219
220 static struct cfg_schema_section _nl80211_section = {
221   .type = OONF_NL80211_LISTENER_SUBSYSTEM,
222   .cb_delta_handler = _cb_config_changed,
223   .entries = _nl80211_entries,
224   .entry_count = ARRAYSIZE(_nl80211_entries),
225   .next_section = &_if_section,
226 };
227
228 static struct _nl80211_config _config;
229
230 /* plugin declaration */
231 static const char *_dependencies[] = {
232   OONF_CLASS_SUBSYSTEM,
233   OONF_LAYER2_SUBSYSTEM,
234   OONF_TIMER_SUBSYSTEM,
235   OONF_OS_INTERFACE_SUBSYSTEM,
236   OONF_OS_SYSTEM_SUBSYSTEM,
237 };
238
239 static struct oonf_subsystem _nl80211_listener_subsystem = {
240   .name = OONF_NL80211_LISTENER_SUBSYSTEM,
241   .dependencies = _dependencies,
242   .dependencies_count = ARRAYSIZE(_dependencies),
243   .descr = "OONF nl80211 listener plugin",
244   .author = "Henning Rogge",
245
246   .cfg_section = &_nl80211_section,
247
248   .early_cfg_init = _early_cfg_init,
249   .init = _init,
250   .cleanup = _cleanup,
251 };
252 DECLARE_OONF_PLUGIN(_nl80211_listener_subsystem);
253
254 enum oonf_log_source LOG_NL80211;
255
256 /* netlink specific data */
257 static struct os_system_netlink _netlink_handler = {
258   .name = "nl80211 listener",
259   .used_by = &_nl80211_listener_subsystem,
260   .cb_message = _cb_nl_message,
261   .cb_error = _cb_nl_error,
262   .cb_done = _cb_nl_done,
263   .cb_timeout = _cb_nl_timeout,
264 };
265
266 /* buffer for outgoing netlink message */
267 static uint32_t _nl_msgbuffer[UIO_MAXIOV/4];
268 static struct nlmsghdr *_nl_msg = (void *)_nl_msgbuffer;
269
270 /* netlink nl80211 identification */
271 static uint32_t _nl80211_id = 0;
272 static uint32_t _nl80211_multicast_group = 0;
273
274 /* layer2 metadata */
275 static struct oonf_layer2_origin _layer2_updated_origin = {
276   .name = "nl80211 updated",
277   .proactive = true,
278   .priority = OONF_LAYER2_ORIGIN_RELIABLE,
279 };
280 static struct oonf_layer2_origin _layer2_data_origin = {
281   .name = "nl80211",
282   .proactive = true,
283   .priority = OONF_LAYER2_ORIGIN_RELIABLE,
284 };
285
286 /* current query data */
287 static struct nl80211_if *_current_query_if = NULL;
288 static enum _if_query _current_query_number = QUERY_START;
289 static bool _current_query_in_progress = false;
290
291 /* timer for generating netlink requests */
292 static struct oonf_timer_class _transmission_timer_info = {
293   .name = "nl80211 listener timer",
294   .callback = _cb_transmission_event,
295   .periodic = true,
296 };
297
298 static struct oonf_timer_instance _transmission_timer = {
299   .class = &_transmission_timer_info
300 };
301
302 /* nl80211_if handling */
303 static struct avl_tree _nl80211_if_tree;
304
305 static struct oonf_class _nl80211_if_class = {
306   .name = "nl80211 if",
307   .size = sizeof(struct nl80211_if),
308 };
309
310 static void
311 _early_cfg_init(void) {
312   LOG_NL80211 = _nl80211_listener_subsystem.logging;
313 }
314
315 /**
316  * Constructor of plugin
317  * @return 0 if initialization was successful, -1 otherwise
318  */
319 static int
320 _init(void) {
321   if (os_system_linux_netlink_add(&_netlink_handler, NETLINK_GENERIC)) {
322     return -1;
323   }
324
325   /* initialize nl80211 if storage system */
326   oonf_class_add(&_nl80211_if_class);
327   avl_init(&_nl80211_if_tree, avl_comp_strcasecmp, false);
328
329   /* get layer2 origin */
330   oonf_layer2_origin_add(&_layer2_updated_origin);
331   oonf_layer2_origin_add(&_layer2_data_origin);
332
333   oonf_timer_add(&_transmission_timer_info);
334   return 0;
335 }
336
337 /**
338  * Destructor of plugin
339  */
340 static void
341 _cleanup(void) {
342   struct nl80211_if *interf, *it_if;
343   avl_for_each_element_safe(&_nl80211_if_tree, interf, _node, it_if) {
344     _nl80211_if_remove(interf);
345   }
346   oonf_layer2_origin_remove(&_layer2_updated_origin);
347   oonf_layer2_origin_remove(&_layer2_data_origin);
348
349   oonf_timer_stop(&_transmission_timer);
350   oonf_timer_remove(&_transmission_timer_info);
351   os_system_linux_netlink_remove(&_netlink_handler);
352 }
353
354 /**
355  * Add a layer2 destination to the database
356  * @param l2neigh layer2 neighbor
357  * @param dstmac destination mac address
358  * @return layer2 destination
359  */
360 struct oonf_layer2_destination *
361 nl80211_add_dst(struct oonf_layer2_neigh *l2neigh, const struct netaddr *dstmac) {
362   struct oonf_layer2_destination *dst;
363
364   dst = oonf_layer2_destination_add(l2neigh, dstmac, &_layer2_updated_origin);
365   if (dst->origin == &_layer2_data_origin) {
366     dst->origin = &_layer2_updated_origin;
367   }
368   return dst;
369 }
370
371 /**
372  * Change a layer2 network setting
373  * @param l2net pointer to layer2 network
374  * @param idx index of setting
375  * @param value new value
376  * @return true if value changed, false otherwise
377  */
378 bool
379 nl80211_change_l2net_data(struct oonf_layer2_net *l2net,
380     enum oonf_layer2_network_index idx, uint64_t value) {
381   return oonf_layer2_data_set_int64(&l2net->data[idx], &_layer2_updated_origin, value);
382 }
383
384 /**
385  * Change a layer2 network neighbor default setting
386  * @param l2net pointer to layer2 network
387  * @param idx index of setting
388  * @param value new value
389  * @return true if value changed, false otherwise
390  */
391 bool
392 nl80211_change_l2net_neighbor_default(struct oonf_layer2_net *l2net,
393     enum oonf_layer2_neighbor_index idx, uint64_t value) {
394   return oonf_layer2_data_set_int64(&l2net->neighdata[idx], &_layer2_updated_origin, value);
395 }
396
397 /**
398  * Cleanup all data generated by this listener from a layer2 neighbor,
399  * but do not commit data
400  * @param l2neigh pointer to layer2 neighbor
401  */
402 void
403 nl80211_cleanup_l2neigh_data(struct oonf_layer2_neigh *l2neigh) {
404   oonf_layer2_neigh_cleanup(l2neigh, &_layer2_data_origin);
405 }
406
407 /**
408  * Change a layer2 neighbor setting
409  * @param l2neigh pointer to layer2 neighbor
410  * @param idx index of setting
411  * @param value new value
412  * @return true if value changed, false otherwise
413  */
414 bool
415 nl80211_change_l2neigh_data(struct oonf_layer2_neigh *l2neigh,
416     enum oonf_layer2_neighbor_index idx, uint64_t value) {
417   return oonf_layer2_data_set_int64(&l2neigh->data[idx], &_layer2_updated_origin, value);
418 }
419
420 /**
421  * @return true if plugin should create a broadcast entry neighbor
422  */
423 bool
424 nl80211_create_broadcast_neighbor(void) {
425   return _config.report_multicast_rate;
426 }
427
428 /**
429  * Get a nl80211 interface from tree
430  * @param name interface name
431  * @return nl80211 interface, NULL if not found
432  */
433 static struct nl80211_if *
434 _nl80211_if_get(const char *name) {
435   struct nl80211_if *interf;
436
437   return avl_find_element(&_nl80211_if_tree, name, interf, _node);
438 }
439
440 /**
441  * Add a nl80211 interface to the tree
442  * @param name interface name
443  * @return nl80211 interface, NULL if out of memory
444  */
445 static struct nl80211_if *
446 _nl80211_if_add(const char *name) {
447   struct nl80211_if *interf;
448
449   interf = _nl80211_if_get(name);
450   if (interf) {
451     return interf;
452   }
453
454   interf = oonf_class_malloc(&_nl80211_if_class);
455   if (!interf) {
456     return NULL;
457   }
458
459   /* initialize avl node */
460   strscpy(interf->name, name, IF_NAMESIZE);
461   interf->_node.key = interf->name;
462
463   /* initialize l2net */
464   interf->l2net = oonf_layer2_net_add(interf->name);
465   if (!interf->l2net) {
466     oonf_class_free(&_nl80211_if_class, interf);
467     return NULL;
468   }
469
470   if (interf->l2net->if_type == OONF_LAYER2_TYPE_UNDEFINED) {
471     interf->l2net->if_type = OONF_LAYER2_TYPE_WIRELESS;
472   }
473
474   /* initialize interface listener */
475   interf->if_listener.name = interf->name;
476   if (!os_interface_add(&interf->if_listener)) {
477     oonf_layer2_net_remove(interf->l2net, &_layer2_data_origin);
478     oonf_layer2_net_remove(interf->l2net, &_layer2_updated_origin);
479     oonf_class_free(&_nl80211_if_class, interf);
480     return NULL;
481   }
482
483   /* initialize interface */
484   interf->wifi_phy_if = -1;
485
486   OONF_DEBUG(LOG_NL80211, "Add if %s", name);
487   avl_insert(&_nl80211_if_tree, &interf->_node);
488   return interf;
489 }
490
491 /**
492  * Remove a nl80211 interface from tree
493  * @param interf nl80211 interface
494  */
495 static void
496 _nl80211_if_remove(struct nl80211_if *interf) {
497   avl_remove(&_nl80211_if_tree, &interf->_node);
498   os_interface_remove(&interf->if_listener);
499   oonf_class_free(&_nl80211_if_class, interf);
500 }
501
502 /**
503  * Update configuration of interface section
504  */
505 static void
506 _cb_if_config_changed(void) {
507   struct nl80211_if *interf;
508   const char *ifname;
509   char ifbuf[IF_NAMESIZE];
510
511   ifname = cfg_get_phy_if(ifbuf, _if_section.section_name);
512   if (_if_section.pre == NULL) {
513     interf = _nl80211_if_add(ifname);
514     if (interf) {
515       interf->_if_section = true;
516     }
517   }
518
519   if (_if_section.post == NULL) {
520     interf = _nl80211_if_get(ifname);
521     if (interf) {
522       interf->_if_section = false;
523       if (!interf->_nl80211_section) {
524         _nl80211_if_remove(interf);
525       }
526     }
527   }
528 }
529
530 /**
531  * Transmit the next netlink command to nl80211
532  * @param ptr timer instance that fired
533  */
534 static void
535 _cb_transmission_event(struct oonf_timer_instance *ptr __attribute__((unused))) {
536   if (!_current_query_in_progress) {
537     _trigger_next_netlink_query();
538   }
539 }
540
541 /**
542  * Send a netlink message to the nl80211 subsystem
543  * @param interf nl80211 interface for message
544  * @param query query id
545  */
546 static void
547 _send_netlink_message(struct nl80211_if *interf, enum _if_query query) {
548   struct genlmsghdr *hdr;
549
550   memset(&_nl_msgbuffer, 0, sizeof(_nl_msgbuffer));
551
552   /* generic netlink initialization */
553   _nl_msg->nlmsg_len = NLMSG_LENGTH(sizeof(struct genlmsghdr));
554   _nl_msg->nlmsg_flags = NLM_F_REQUEST;
555
556   /* request nl80211 identifier */
557   if (query == QUERY_GET_FAMILY) {
558     /* request nl80211 identifier */
559     _nl_msg->nlmsg_type = GENL_ID_CTRL;
560   }
561   else {
562     _nl_msg->nlmsg_type = _nl80211_id;
563   }
564
565   hdr = NLMSG_DATA(_nl_msg);
566
567   if (query < QUERY_END) {
568     OONF_DEBUG(LOG_NL80211, "Get query %d for interface %s", query, interf->name);
569   }
570
571   if (query == QUERY_GET_FAMILY) {
572     genl_send_get_family(_nl_msg, hdr);
573   }
574   else if (_if_query_ops[query].send) {
575     _if_query_ops[query].send(&_netlink_handler, _nl_msg, hdr, interf);
576   }
577
578   os_system_linux_netlink_send(&_netlink_handler, _nl_msg);
579 }
580
581 /**
582  * Proceed to next query
583  */
584 static void
585 _get_next_query(void) {
586   if (avl_is_empty(&_nl80211_if_tree)) {
587     OONF_DEBUG(LOG_NL80211, "No nl80211 interfaces");
588     _current_query_if = NULL;
589     return;
590   }
591
592   /* no query left to do? start again at the first */
593   if (!_current_query_if) {
594     /* start with first interface and query */
595     _current_query_if = avl_first_element(&_nl80211_if_tree, _current_query_if, _node);
596     _current_query_number = QUERY_START;
597     _current_query_in_progress = true;
598   }
599   else {
600     /* next query */
601     _current_query_number++;
602
603     if (_current_query_number == QUERY_END) {
604       /* commit interface data */
605       if (_current_query_if->ifdata_changed) {
606         oonf_layer2_net_cleanup(_current_query_if->l2net, &_layer2_data_origin, true);
607         oonf_layer2_net_relabel(_current_query_if->l2net,
608             &_layer2_data_origin, &_layer2_updated_origin);
609         oonf_layer2_net_commit(_current_query_if->l2net);
610         _current_query_if->ifdata_changed = false;
611       }
612
613       _current_query_if = avl_next_element_safe(
614           &_nl80211_if_tree, _current_query_if, _node);
615       _current_query_number = QUERY_START;
616     }
617   }
618 }
619
620 /**
621  * Trigger the next netlink query
622  */
623 static void
624 _trigger_next_netlink_query(void) {
625   if (!_nl80211_id || !_nl80211_multicast_group) {
626     if (_current_query_in_progress) {
627       /* wait for the next timer */
628       _current_query_in_progress = false;
629       return;
630     }
631
632     /* first we need to get the ID and multicast group */
633     OONF_DEBUG(LOG_NL80211, "Get nl80211 family and multicast id");
634     _current_query_in_progress = true;
635     _send_netlink_message(NULL, QUERY_GET_FAMILY);
636     return;
637   }
638
639   /* calculate next interface/query */
640   _get_next_query();
641
642   if (!_current_query_if) {
643     /* done with this series of queries, wait for next timer */
644     OONF_DEBUG(LOG_NL80211, "All queries done for all interfaces");
645     _current_query_in_progress = false;
646     return;
647   }
648
649   _send_netlink_message(_current_query_if,
650       _current_query_number);
651 }
652
653 /**
654  * Parse an incoming netlink message from the kernel
655  * @param hdr pointer to netlink message
656  */
657 static void
658 _cb_nl_message(struct nlmsghdr *hdr) {
659   struct genlmsghdr *gen_hdr;
660
661   gen_hdr = NLMSG_DATA(hdr);
662   if (hdr->nlmsg_type == GENL_ID_CTRL && gen_hdr->cmd == CTRL_CMD_NEWFAMILY) {
663     genl_process_get_family_result(hdr,
664         &_nl80211_id, &_nl80211_multicast_group);
665     return;
666   }
667
668   if (hdr->nlmsg_type != _nl80211_id) {
669     OONF_WARN(LOG_NL80211, "Unhandled netlink message type: %u", hdr->nlmsg_type);
670     return;
671   }
672
673   if (gen_hdr->cmd != _if_query_ops[_current_query_number].cmd) {
674     OONF_INFO(LOG_NL80211, "Received Nl80211 command %u for query %u (should be %u)",
675         gen_hdr->cmd, _current_query_number,
676         _if_query_ops[_current_query_number].cmd);
677   }
678   else if (_if_query_ops[_current_query_number].process) {
679     OONF_DEBUG(LOG_NL80211, "Received Nl80211 command %u for query %u",
680         gen_hdr->cmd, _current_query_number);
681     _if_query_ops[_current_query_number].process(_current_query_if, hdr);
682   }
683 }
684
685 /**
686  * Callback triggered when a netlink message failes
687  * @param seq sequence number
688  * @param error error code
689  */
690 static void
691 _cb_nl_error(uint32_t seq __attribute((unused)), int error __attribute((unused))) {
692   OONF_DEBUG(LOG_NL80211, "seq %u: Received error %d", seq, error);
693   if (_nl80211_id && _nl80211_multicast_group) {
694     _trigger_next_netlink_query();
695   }
696 }
697
698 /**
699  * Callback triggered when one or more netlink messages time out
700  */
701 static void
702 _cb_nl_timeout(void) {
703   OONF_DEBUG(LOG_NL80211, "Received timeout");
704   if (_nl80211_id && _nl80211_multicast_group) {
705     if (_if_query_ops[_current_query_number].finalize) {
706       _if_query_ops[_current_query_number].finalize(_current_query_if);
707     }
708     _trigger_next_netlink_query();
709   }
710 }
711
712 /**
713  * Callback triggered when a netlink message is done
714  * @param seq sequence number
715  */
716 static void
717 _cb_nl_done(uint32_t seq __attribute((unused))) {
718   OONF_DEBUG(LOG_NL80211, "%u: Received done", seq);
719   if (_nl80211_id && _nl80211_multicast_group) {
720     if (_if_query_ops[_current_query_number].finalize) {
721       _if_query_ops[_current_query_number].finalize(_current_query_if);
722     }
723     _trigger_next_netlink_query();
724   }
725 }
726
727 /**
728  * Update configuration of nl80211-listener plugin
729  */
730 static void
731 _cb_config_changed(void) {
732   const struct const_strarray *array;
733   struct nl80211_if *interf;
734   const char *str;
735
736   if (cfg_schema_tobin(&_config, _nl80211_section.post,
737       _nl80211_entries, ARRAYSIZE(_nl80211_entries))) {
738     OONF_WARN(LOG_NL80211, "Could not convert "
739         OONF_NL80211_LISTENER_SUBSYSTEM " config to bin");
740     return;
741   }
742
743   /* set transmission timer */
744   oonf_timer_set_ext(&_transmission_timer, 1, _config.interval);
745
746   /* mark old interfaces for removal */
747   array = cfg_db_get_schema_entry_value(
748       _nl80211_section.pre, &_nl80211_entries[IDX_INTERFACES]);
749   if (array && strarray_get_count_c(array) > 0) {
750     strarray_for_each_element(array, str) {
751       interf = _nl80211_if_get(str);
752       if (interf) {
753         interf->_remove = !interf->_if_section;
754         interf->_nl80211_section = false;
755       }
756     }
757   }
758
759   /* create new interfaces and remove mark */
760   array = cfg_db_get_schema_entry_value(
761       _nl80211_section.post, &_nl80211_entries[IDX_INTERFACES]);
762   if (array && strarray_get_count_c(array) > 0) {
763     strarray_for_each_element(array, str) {
764       interf = _nl80211_if_add(str);
765       if (interf) {
766         /* mark for removal */
767         interf->_remove = false;
768         interf->_nl80211_section = true;
769       }
770     }
771   }
772
773   array = cfg_db_get_schema_entry_value(
774       _nl80211_section.pre, &_nl80211_entries[IDX_INTERFACES]);
775   if (array && strarray_get_count_c(array) > 0) {
776     strarray_for_each_element(array, str) {
777       interf = _nl80211_if_get(str);
778       if (interf && interf->_remove) {
779         _nl80211_if_remove(interf);
780       }
781     }
782   }
783 }