Reworking layer2 subsystem
[oonf.git] / src-plugins / nl80211_listener / nl80211_listener.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004-2013, 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 #define _GNU_SOURCE
43
44 /* must be first because of a problem with linux/netlink.h */
45 #include <sys/socket.h>
46
47 /* and now the rest of the includes */
48 #include <linux/types.h>
49 #include <linux/netlink.h>
50 #include <linux/genetlink.h>
51 #include "nl80211.h"
52 #include <netlink/attr.h>
53 #include <netlink/msg.h>
54
55 #include "common/autobuf.h"
56 #include "common/avl.h"
57 #include "common/avl_comp.h"
58 #include "common/common_types.h"
59 #include "common/netaddr.h"
60 #include "common/netaddr_acl.h"
61 #include "common/string.h"
62
63 #include "config/cfg.h"
64 #include "config/cfg_schema.h"
65 #include "core/oonf_logging.h"
66 #include "core/oonf_plugins.h"
67 #include "core/oonf_subsystem.h"
68 #include "subsystems/oonf_class.h"
69 #include "subsystems/oonf_clock.h"
70 #include "subsystems/oonf_interface.h"
71 #include "subsystems/oonf_layer2.h"
72 #include "subsystems/oonf_timer.h"
73 #include "subsystems/os_system.h"
74
75 #include "nl80211_listener/nl80211_listener.h"
76
77 /* definitions */
78 struct _nl80211_config {
79   uint64_t interval;
80 };
81
82 enum query_type {
83   QUERY_FIRST = 0,
84   QUERY_STATION_DUMP = 0,
85   QUERY_SCAN_DUMP,
86
87   /* must be last */
88   QUERY_COUNT,
89 };
90
91 /* prototypes */
92 static int _init(void);
93 static void _cleanup(void);
94
95 static void _cb_config_changed(void);
96 static void _send_genl_getfamily(void);
97
98 static void _cb_nl_message(struct nlmsghdr *hdr);
99 static void _cb_nl_error(uint32_t seq, int error);
100 static void _cb_nl_timeout(void);
101 static void _cb_nl_done(uint32_t seq);
102
103 static void _cb_transmission_event(void *);
104
105 /* configuration */
106 static struct cfg_schema_entry _nl80211_entries[] = {
107   CFG_MAP_CLOCK_MIN(_nl80211_config, interval, "interval", "1.0",
108       "Interval between two linklayer information updates", 100),
109 };
110
111 static struct cfg_schema_section _nl80211_section = {
112   .type = OONF_PLUGIN_GET_NAME(),
113   .cb_delta_handler = _cb_config_changed,
114   .entries = _nl80211_entries,
115   .entry_count = ARRAYSIZE(_nl80211_entries),
116 };
117
118 static struct _nl80211_config _config;
119
120 /* plugin declaration */
121 struct oonf_subsystem nl80211_listener_subsystem = {
122   .name = OONF_PLUGIN_GET_NAME(),
123   .descr = "OONF nl80211 listener plugin",
124   .author = "Henning Rogge",
125
126   .cfg_section = &_nl80211_section,
127
128   .init = _init,
129   .cleanup = _cleanup,
130 };
131 DECLARE_OONF_PLUGIN(nl80211_listener_subsystem);
132
133 /* netlink specific data */
134 static struct os_system_netlink _netlink_handler = {
135   .cb_message = _cb_nl_message,
136   .cb_error = _cb_nl_error,
137   .cb_done = _cb_nl_done,
138   .cb_timeout = _cb_nl_timeout,
139 };
140
141 static struct nlmsghdr *_msgbuf;
142
143 static int _nl80211_id = -1;
144 static bool _nl80211_mc_set = false;
145
146 static char _last_queried_if[IF_NAMESIZE];
147 static enum query_type _next_query_type;
148
149 static uint32_t _l2_origin;
150
151 /* timer for generatstatic ing netlink requests */
152 static struct oonf_timer_info _transmission_timer_info = {
153   .name = "nl80211 listener timer",
154   .callback = _cb_transmission_event,
155   .periodic = true,
156 };
157
158 struct oonf_timer_entry _transmission_timer = {
159   .info = &_transmission_timer_info
160 };
161
162 /**
163  * Constructor of plugin
164  * @return 0 if initialization was successful, -1 otherwise
165  */
166 static int
167 _init(void) {
168   _msgbuf = calloc(1, UIO_MAXIOV);
169   if (_msgbuf == NULL) {
170     OONF_WARN(LOG_NL80211, "Not enough memory for nl80211 memory buffer");
171     return -1;
172   }
173
174   if (os_system_netlink_add(&_netlink_handler, NETLINK_GENERIC)) {
175     free(_msgbuf);
176     return -1;
177   }
178
179   _l2_origin = oonf_layer2_register_origin();
180
181   oonf_timer_add(&_transmission_timer_info);
182
183   memset(_last_queried_if, 0, sizeof(_last_queried_if));
184   _next_query_type = QUERY_STATION_DUMP;
185
186   _send_genl_getfamily();
187   return 0;
188 }
189
190 /**
191  * Destructor of plugin
192  */
193 static void
194 _cleanup(void) {
195   oonf_layer2_unregister_origin(_l2_origin);
196
197   oonf_timer_stop(&_transmission_timer);
198   oonf_timer_remove(&_transmission_timer_info);
199   os_system_netlink_remove(&_netlink_handler);
200
201   free (_msgbuf);
202 }
203
204 static struct oonf_layer2_net *
205 _create_l2net(struct netaddr *mac, int if_index, const char *if_name) {
206   struct oonf_layer2_net *net;
207   net = oonf_layer2_net_add(mac);
208   if (net == NULL) {
209     return NULL;
210   }
211
212   if (net->if_type ==  OONF_LAYER2_TYPE_UNDEFINED) {
213     net->if_type = OONF_LAYER2_TYPE_WIRELESS;
214     net->if_index = if_index;
215     strscpy(net->if_name, if_name, IF_NAMESIZE);
216   }
217   if (net->if_type !=  OONF_LAYER2_TYPE_WIRELESS) {
218     OONF_WARN(LOG_NL80211, "Wireless interface %s is already type %d",
219         if_name, net->if_type);
220     return NULL;
221   }
222   return net;
223 }
224
225 /**
226  * Parse the netlink message result that contains the list of available
227  * generic netlink families of the kernel.
228  * @param hdr pointer to netlink message
229  */
230 static void
231 _parse_cmd_newfamily(struct nlmsghdr *hdr) {
232   static struct nla_policy ctrl_policy[CTRL_ATTR_MAX+1] = {
233     [CTRL_ATTR_FAMILY_ID]    = { .type = NLA_U16 },
234     [CTRL_ATTR_FAMILY_NAME]  = { .type = NLA_STRING, .maxlen = GENL_NAMSIZ },
235     [CTRL_ATTR_VERSION]      = { .type = NLA_U32 },
236     [CTRL_ATTR_HDRSIZE]      = { .type = NLA_U32 },
237     [CTRL_ATTR_MAXATTR]      = { .type = NLA_U32 },
238     [CTRL_ATTR_OPS]          = { .type = NLA_NESTED },
239     [CTRL_ATTR_MCAST_GROUPS] = { .type = NLA_NESTED },
240   };
241   struct nlattr *attrs[CTRL_ATTR_MAX+1];
242   struct nlattr *mcgrp;
243   int iterator;
244
245   if (nlmsg_parse(hdr, sizeof(struct genlmsghdr),
246       attrs, CTRL_ATTR_MAX, ctrl_policy) < 0) {
247     OONF_WARN(LOG_NL80211, "Cannot parse netlink CTRL_CMD_NEWFAMILY message");
248     return;
249   }
250
251   if (attrs[CTRL_ATTR_FAMILY_ID] == NULL) {
252     OONF_WARN(LOG_NL80211, "Missing Family ID in CTRL_CMD_NEWFAMILY");
253     return;
254   }
255   if (attrs[CTRL_ATTR_FAMILY_NAME] == NULL) {
256     OONF_WARN(LOG_NL80211, "Missing Family Name in CTRL_CMD_NEWFAMILY");
257     return;
258   }
259   if (strcmp(nla_get_string(attrs[CTRL_ATTR_FAMILY_NAME]), "nl80211") != 0) {
260     /* not interested in this one */
261     return;
262   }
263   _nl80211_id = nla_get_u32(attrs[CTRL_ATTR_FAMILY_ID]);
264
265   if (_nl80211_mc_set || !attrs[CTRL_ATTR_MCAST_GROUPS]) {
266     /* no multicast groups */
267     return;
268   }
269
270   nla_for_each_nested(mcgrp, attrs[CTRL_ATTR_MCAST_GROUPS], iterator) {
271     struct nlattr *tb_mcgrp[CTRL_ATTR_MCAST_GRP_MAX + 1];
272     uint32_t group;
273
274     nla_parse(tb_mcgrp, CTRL_ATTR_MCAST_GRP_MAX,
275         nla_data(mcgrp), nla_len(mcgrp), NULL);
276
277     if (!tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME] ||
278         !tb_mcgrp[CTRL_ATTR_MCAST_GRP_ID])
279       continue;
280
281     if (strcmp(nla_data(tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME]), "mlme"))
282       continue;
283
284     group = nla_get_u32(tb_mcgrp[CTRL_ATTR_MCAST_GRP_ID]);
285     OONF_DEBUG(LOG_NL80211, "Found multicast group %s: %d",
286         (char *)nla_data(tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME]),
287         group);
288
289     if (os_system_netlink_add_mc(&_netlink_handler, &group, 1)) {
290       OONF_WARN(LOG_NL80211,
291           "Could not activate multicast group %d for nl80211", group);
292     }
293     else {
294       _nl80211_mc_set = true;
295     }
296     break;
297   }
298 }
299
300 /**
301  * Parse result of station dump nl80211 command
302  * @param hdr pointer to netlink message
303  */
304 static void
305 _parse_cmd_new_station(struct nlmsghdr *hdr) {
306   static struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = {
307     [NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32 },
308     [NL80211_STA_INFO_RX_BYTES]      = { .type = NLA_U32 },
309     [NL80211_STA_INFO_TX_BYTES]      = { .type = NLA_U32 },
310     [NL80211_STA_INFO_RX_PACKETS]    = { .type = NLA_U32 },
311     [NL80211_STA_INFO_TX_PACKETS]    = { .type = NLA_U32 },
312     [NL80211_STA_INFO_SIGNAL]        = { .type = NLA_U8 },
313     [NL80211_STA_INFO_RX_BITRATE]    = { .type = NLA_NESTED },
314     [NL80211_STA_INFO_TX_BITRATE]    = { .type = NLA_NESTED },
315     [NL80211_STA_INFO_LLID]          = { .type = NLA_U16 },
316     [NL80211_STA_INFO_PLID]          = { .type = NLA_U16 },
317     [NL80211_STA_INFO_PLINK_STATE]   = { .type = NLA_U8 },
318     [NL80211_STA_INFO_TX_RETRIES]    = { .type = NLA_U32 },
319     [NL80211_STA_INFO_TX_FAILED]     = { .type = NLA_U32 },
320   };
321   static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
322     [NL80211_RATE_INFO_BITRATE]      = { .type = NLA_U16 },
323     [NL80211_RATE_INFO_MCS]          = { .type = NLA_U8 },
324     [NL80211_RATE_INFO_40_MHZ_WIDTH] = { .type = NLA_FLAG },
325     [NL80211_RATE_INFO_SHORT_GI]     = { .type = NLA_FLAG },
326   };
327
328   struct nlattr *tb[NL80211_ATTR_MAX + 1];
329   struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1];
330   struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1];
331
332   struct oonf_interface_data *if_data;
333   struct oonf_layer2_net *net;
334   struct oonf_layer2_neigh *neigh;
335   struct netaddr mac;
336   unsigned if_index;
337   char if_name[IF_NAMESIZE];
338   int i;
339
340 #ifdef OONF_LOG_DEBUG_INFO
341   struct netaddr_str buf1, buf2;
342 #endif
343
344   if (nlmsg_parse(hdr, sizeof(struct genlmsghdr),
345       tb, NL80211_ATTR_MAX, NULL) < 0) {
346     OONF_WARN(LOG_NL80211, "Cannot parse netlink NL80211_CMD_NEW_STATION message");
347     return;
348   }
349
350   if (!tb[NL80211_ATTR_STA_INFO]) {
351     OONF_WARN(LOG_NL80211, "Cannot find station info attribute");
352     return;
353   }
354   if (nla_parse_nested(sinfo, NL80211_STA_INFO_MAX,
355            tb[NL80211_ATTR_STA_INFO], stats_policy)) {
356     OONF_WARN(LOG_NL80211, "Cannot parse station info attribute");
357     return;
358   }
359
360   netaddr_from_binary(&mac, nla_data(tb[NL80211_ATTR_MAC]), 6, AF_MAC48);
361   if_index = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
362
363   if (if_indextoname(if_index, if_name) == NULL) {
364     return;
365   }
366
367   if_data = oonf_interface_get_data(if_name, NULL);
368   if (if_data == NULL || netaddr_get_address_family(&if_data->mac) == AF_UNSPEC) {
369     return;
370   }
371
372   OONF_DEBUG(LOG_NL80211, "Add neighbor %s for network %s",
373       netaddr_to_string(&buf1, &mac), netaddr_to_string(&buf2, &if_data->mac));
374
375   net = _create_l2net(&mac, if_data->index, if_name);
376   if (net == NULL) {
377     return;
378   }
379
380   neigh = oonf_layer2_neigh_add(net, &mac);
381   if (neigh == NULL) {
382     return;
383   }
384
385   /* remove old data */
386   for (i=0; i<OONF_LAYER2_NEIGH_COUNT; i++) {
387     oonf_layer2_reset_value(&neigh->data[i]);
388   }
389   neigh->last_seen = 0;
390
391   /* insert new data */
392   if (sinfo[NL80211_STA_INFO_INACTIVE_TIME]) {
393     neigh->last_seen = oonf_clock_get_absolute(nla_get_u32(sinfo[NL80211_STA_INFO_INACTIVE_TIME]));
394   }
395   if (sinfo[NL80211_STA_INFO_RX_BYTES]) {
396     oonf_layer2_set_value(&neigh->data[OONF_LAYER2_NEIGH_RX_BYTES], _l2_origin,
397         nla_get_u32(sinfo[NL80211_STA_INFO_RX_BYTES]));
398   }
399   if (sinfo[NL80211_STA_INFO_RX_PACKETS]) {
400     oonf_layer2_set_value(&neigh->data[OONF_LAYER2_NEIGH_RX_FRAMES], _l2_origin,
401         nla_get_u32(sinfo[NL80211_STA_INFO_RX_PACKETS]));
402   }
403   if (sinfo[NL80211_STA_INFO_TX_BYTES]) {
404     oonf_layer2_set_value(&neigh->data[OONF_LAYER2_NEIGH_TX_BYTES], _l2_origin,
405         nla_get_u32(sinfo[NL80211_STA_INFO_TX_BYTES]));
406   }
407   if (sinfo[NL80211_STA_INFO_TX_PACKETS]) {
408     oonf_layer2_set_value(&neigh->data[OONF_LAYER2_NEIGH_TX_FRAMES], _l2_origin,
409         nla_get_u32(sinfo[NL80211_STA_INFO_TX_PACKETS]));
410   }
411   if (sinfo[NL80211_STA_INFO_TX_RETRIES])  {
412     oonf_layer2_set_value(&neigh->data[OONF_LAYER2_NEIGH_TX_RETRIES], _l2_origin,
413         nla_get_u32(sinfo[NL80211_STA_INFO_TX_RETRIES]));
414   }
415   if (sinfo[NL80211_STA_INFO_TX_FAILED]) {
416     oonf_layer2_set_value(&neigh->data[OONF_LAYER2_NEIGH_TX_FAILED], _l2_origin,
417         nla_get_u32(sinfo[NL80211_STA_INFO_TX_FAILED]));
418   }
419   if (sinfo[NL80211_STA_INFO_SIGNAL])  {
420     oonf_layer2_set_value(&neigh->data[OONF_LAYER2_NEIGH_SIGNAL], _l2_origin,
421         1000 * (int8_t)nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL]));
422   }
423   if (sinfo[NL80211_STA_INFO_TX_BITRATE]) {
424     if (nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX,
425              sinfo[NL80211_STA_INFO_TX_BITRATE], rate_policy) == 0) {
426       if (rinfo[NL80211_RATE_INFO_BITRATE]) {
427         int64_t rate = nla_get_u16(rinfo[NL80211_RATE_INFO_BITRATE]);
428         oonf_layer2_set_value(&neigh->data[OONF_LAYER2_NEIGH_TX_BITRATE], _l2_origin,
429             (rate * 1024 * 1024) / 10);
430       }
431       /* TODO: do we need the rest of the data ? */
432 #if 0
433       if (rinfo[NL80211_RATE_INFO_MCS])
434         printf(" MCS %d", nla_get_u8(rinfo[NL80211_RATE_INFO_MCS]));
435       if (rinfo[NL80211_RATE_INFO_40_MHZ_WIDTH])
436         printf(" 40Mhz");
437       if (rinfo[NL80211_RATE_INFO_SHORT_GI])
438         printf(" short GI");
439 #endif
440     }
441   }
442   if (sinfo[NL80211_STA_INFO_RX_BITRATE]) {
443     if (nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX,
444              sinfo[NL80211_STA_INFO_RX_BITRATE], rate_policy) == 0) {
445       if (rinfo[NL80211_RATE_INFO_BITRATE]) {
446         int64_t rate = nla_get_u16(rinfo[NL80211_RATE_INFO_BITRATE]);
447         oonf_layer2_set_value(&neigh->data[OONF_LAYER2_NEIGH_RX_BITRATE], _l2_origin,
448             (rate * 1024 * 1024) / 10);
449       }
450       /* TODO: do we need the rest of the data ? */
451 #if 0
452       if (rinfo[NL80211_RATE_INFO_MCS])
453         printf(" MCS %d", nla_get_u8(rinfo[NL80211_RATE_INFO_MCS]));
454       if (rinfo[NL80211_RATE_INFO_40_MHZ_WIDTH])
455         printf(" 40Mhz");
456       if (rinfo[NL80211_RATE_INFO_SHORT_GI])
457         printf(" short GI");
458 #endif
459     }
460   }
461
462   oonf_layer2_neigh_commit(neigh);
463   return;
464 }
465
466 /**
467  * Parse result of station dump nl80211 command
468  * @param hdr pointer to netlink message
469  */
470 static void
471 _parse_cmd_del_station(struct nlmsghdr *hdr) {
472   struct nlattr *tb[NL80211_ATTR_MAX + 1];
473
474   struct oonf_interface_data *if_data;
475   struct oonf_layer2_neigh *neigh;
476   struct oonf_layer2_net *net;
477   struct netaddr mac;
478   unsigned if_index;
479   char if_name[IF_NAMESIZE];
480 #ifdef OONF_LOG_DEBUG_INFO
481   struct netaddr_str buf1, buf2;
482 #endif
483
484   if (nlmsg_parse(hdr, sizeof(struct genlmsghdr),
485       tb, NL80211_ATTR_MAX, NULL) < 0) {
486     OONF_WARN(LOG_NL80211, "Cannot parse netlink NL80211_CMD_NEW_STATION message");
487     return;
488   }
489
490   netaddr_from_binary(&mac, nla_data(tb[NL80211_ATTR_MAC]), 6, AF_MAC48);
491   if_index = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
492
493   if (if_indextoname(if_index, if_name) == NULL) {
494     return;
495   }
496   if_data = oonf_interface_get_data(if_name, NULL);
497   if (if_data == NULL || netaddr_get_address_family(&if_data->mac) == AF_UNSPEC) {
498     return;
499   }
500
501   OONF_DEBUG(LOG_NL80211, "Remove neighbor %s for network %s",
502       netaddr_to_string(&buf1, &mac), netaddr_to_string(&buf2, &if_data->mac));
503
504   net = oonf_layer2_net_get(&if_data->mac);
505   if (net == NULL) {
506     return;
507   }
508
509   neigh = oonf_layer2_neigh_get(net, &mac);
510   if (neigh != NULL) {
511     oonf_layer2_neigh_remove(neigh, _l2_origin);
512   }
513 }
514
515 #define WLAN_CAPABILITY_ESS   (1<<0)
516 #define WLAN_CAPABILITY_IBSS    (1<<1)
517 #define WLAN_CAPABILITY_CF_POLLABLE (1<<2)
518 #define WLAN_CAPABILITY_CF_POLL_REQUEST (1<<3)
519 #define WLAN_CAPABILITY_PRIVACY   (1<<4)
520 #define WLAN_CAPABILITY_SHORT_PREAMBLE  (1<<5)
521 #define WLAN_CAPABILITY_PBCC    (1<<6)
522 #define WLAN_CAPABILITY_CHANNEL_AGILITY (1<<7)
523 #define WLAN_CAPABILITY_SPECTRUM_MGMT (1<<8)
524 #define WLAN_CAPABILITY_QOS   (1<<9)
525 #define WLAN_CAPABILITY_SHORT_SLOT_TIME (1<<10)
526 #define WLAN_CAPABILITY_APSD    (1<<11)
527 #define WLAN_CAPABILITY_DSSS_OFDM (1<<13)
528
529 /**
530  * Parse the result of the passive scan of nl80211
531  * @param msg pointer to netlink message
532  */
533 static void
534 _parse_cmd_new_scan_result(struct nlmsghdr *msg) {
535   static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
536     [NL80211_BSS_TSF]             = { .type = NLA_U64 },
537     [NL80211_BSS_FREQUENCY]       = { .type = NLA_U32 },
538 //    [NL80211_BSS_BSSID] = { },
539     [NL80211_BSS_BEACON_INTERVAL] = { .type = NLA_U16 },
540     [NL80211_BSS_CAPABILITY]      = { .type = NLA_U16 },
541 //    [NL80211_BSS_INFORMATION_ELEMENTS] = { },
542     [NL80211_BSS_SIGNAL_MBM]      = { .type = NLA_U32 },
543     [NL80211_BSS_SIGNAL_UNSPEC]   = { .type = NLA_U8 },
544     [NL80211_BSS_STATUS]          = { .type = NLA_U32 },
545     [NL80211_BSS_SEEN_MS_AGO]     = { .type = NLA_U32 },
546 //    [NL80211_BSS_BEACON_IES] = { },
547   };
548
549   struct nlattr *tb[NL80211_ATTR_MAX + 1];
550   struct nlattr *bss[NL80211_BSS_MAX + 1];
551
552   struct oonf_interface_data *if_data;
553   struct oonf_layer2_net *net;
554   struct netaddr mac;
555   unsigned if_index;
556   char if_name[IF_NAMESIZE];
557   int i;
558 #ifdef OONF_LOG_DEBUG_INFO
559   struct netaddr_str buf;
560 #endif
561
562   if (nlmsg_parse(msg, sizeof(struct genlmsghdr),
563       tb, NL80211_ATTR_MAX, NULL) < 0) {
564     OONF_WARN(LOG_NL80211, "Cannot parse netlink NL80211_CMD_NEW_SCAN_RESULT message");
565     return;
566   }
567
568   if (!tb[NL80211_ATTR_BSS]) {
569     OONF_WARN(LOG_NL80211, "bss info missing!\n");
570     return;
571   }
572   if (nla_parse_nested(bss, NL80211_BSS_MAX,
573            tb[NL80211_ATTR_BSS],
574            bss_policy)) {
575     OONF_WARN(LOG_NL80211, "failed to parse nested attributes!\n");
576     return;
577   }
578
579   if (!bss[NL80211_BSS_BSSID]) {
580     OONF_WARN(LOG_NL80211, "No BSSID found");
581     return;
582   }
583
584   if (!bss[NL80211_BSS_STATUS]) {
585     /* ignore different networks for the moment */
586     return;
587   }
588   netaddr_from_binary(&mac, nla_data(bss[NL80211_BSS_BSSID]), 6, AF_MAC48);
589   if_index = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
590
591   if (if_indextoname(if_index, if_name) == NULL) {
592     return;
593   }
594
595   if_data = oonf_interface_get_data(if_name, NULL);
596   if (if_data == NULL || netaddr_get_address_family(&if_data->mac) == AF_UNSPEC) {
597     return;
598   }
599
600   net = _create_l2net(&mac, if_data->index, if_name);
601   if (net == NULL) {
602     return;
603   }
604
605   /* remove old data */
606   for (i=0; i<OONF_LAYER2_NET_COUNT; i++) {
607     oonf_layer2_reset_value(&net->data[i]);
608   }
609   net->last_seen = 0;
610
611   OONF_DEBUG(LOG_NL80211, "Add network %s", netaddr_to_string(&buf, &if_data->mac));
612 #if 0
613   if (bss[NL80211_BSS_STATUS]) {
614     switch (nla_get_u32(bss[NL80211_BSS_STATUS])) {
615     case NL80211_BSS_STATUS_AUTHENTICATED:
616       printf(" -- authenticated");
617       break;
618     case NL80211_BSS_STATUS_ASSOCIATED:
619       printf(" -- associated");
620       break;
621     case NL80211_BSS_STATUS_IBSS_JOINED:
622       printf(" -- joined");
623       break;
624     default:
625       printf(" -- unknown status: %d",
626         nla_get_u32(bss[NL80211_BSS_STATUS]));
627       break;
628     }
629   }
630   printf("\n");
631
632   if (bss[NL80211_BSS_TSF]) {
633     unsigned long long tsf;
634     tsf = (unsigned long long)nla_get_u64(bss[NL80211_BSS_TSF]);
635     printf("\tTSF: %llu usec (%llud, %.2lld:%.2llu:%.2llu)\n",
636       tsf, tsf/1000/1000/60/60/24, (tsf/1000/1000/60/60) % 24,
637       (tsf/1000/1000/60) % 60, (tsf/1000/1000) % 60);
638   }
639 #endif
640
641   if (bss[NL80211_BSS_FREQUENCY]) {
642     oonf_layer2_set_value(&net->data[OONF_LAYER2_NET_FREQUENCY], _l2_origin,
643         nla_get_u32(bss[NL80211_BSS_FREQUENCY]) * 1000000ll);
644   }
645 #if 0
646   if (bss[NL80211_BSS_BEACON_INTERVAL])
647     printf("\tbeacon interval: %d\n",
648       nla_get_u16(bss[NL80211_BSS_BEACON_INTERVAL]));
649   if (bss[NL80211_BSS_CAPABILITY]) {
650     __u16 capa = nla_get_u16(bss[NL80211_BSS_CAPABILITY]);
651     printf("\tcapability:");
652     if (capa & WLAN_CAPABILITY_ESS)
653       printf(" ESS");
654     if (capa & WLAN_CAPABILITY_IBSS)
655       printf(" IBSS");
656     if (capa & WLAN_CAPABILITY_PRIVACY)
657       printf(" Privacy");
658     if (capa & WLAN_CAPABILITY_SHORT_PREAMBLE)
659       printf(" ShortPreamble");
660     if (capa & WLAN_CAPABILITY_PBCC)
661       printf(" PBCC");
662     if (capa & WLAN_CAPABILITY_CHANNEL_AGILITY)
663       printf(" ChannelAgility");
664     if (capa & WLAN_CAPABILITY_SPECTRUM_MGMT)
665       printf(" SpectrumMgmt");
666     if (capa & WLAN_CAPABILITY_QOS)
667       printf(" QoS");
668     if (capa & WLAN_CAPABILITY_SHORT_SLOT_TIME)
669       printf(" ShortSlotTime");
670     if (capa & WLAN_CAPABILITY_APSD)
671       printf(" APSD");
672     if (capa & WLAN_CAPABILITY_DSSS_OFDM)
673       printf(" DSSS-OFDM");
674     printf(" (0x%.4x)\n", capa);
675   }
676   if (bss[NL80211_BSS_SIGNAL_MBM]) {
677     int s = nla_get_u32(bss[NL80211_BSS_SIGNAL_MBM]);
678     printf("\tsignal: %d.%.2d dBm\n", s/100, s%100);
679   }
680   if (bss[NL80211_BSS_SIGNAL_UNSPEC]) {
681     unsigned char s = nla_get_u8(bss[NL80211_BSS_SIGNAL_UNSPEC]);
682     printf("\tsignal: %d/100\n", s);
683   }
684 #endif
685   if (bss[NL80211_BSS_SEEN_MS_AGO]) {
686     net->last_seen = oonf_clock_get_absolute(nla_get_u32(bss[NL80211_BSS_SEEN_MS_AGO]));
687   }
688   if (bss[NL80211_BSS_INFORMATION_ELEMENTS] != NULL ||
689       bss[NL80211_BSS_BEACON_IES] != NULL) {
690     int len;
691     uint8_t *data;
692     int64_t rate, max_rate;
693
694     max_rate = 0;
695
696     if (bss[NL80211_BSS_INFORMATION_ELEMENTS]) {
697       len = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
698       data = nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
699     }
700     else {
701       len = nla_len(bss[NL80211_BSS_BEACON_IES]);
702       data = nla_data(bss[NL80211_BSS_BEACON_IES]);
703     }
704
705     /* collect pointers to data-rates */
706     while (len > 0) {
707       if (data[0] == 0) {
708         /* SSID */
709         strscpy(net->if_ident, (const char *)(&data[2]), data[1]);
710       }
711       if (data[0] == 1) {
712         /* supported rates */
713         for (i=0; i<data[1]; i++) {
714           rate = (data[2+i] & 0x7f) << 19;
715           if (rate > max_rate) {
716             max_rate = rate;
717           }
718         }
719       }
720       else if (data[0] == 50) {
721         /* extended supported rates */
722         for (i=0; i<data[1]; i++) {
723           rate = (data[2+i] & 0x7f) << 19;
724           if (rate > max_rate) {
725             max_rate = rate;
726           }
727         }
728       }
729       len -= data[1] + 2;
730       data += data[1] + 2;
731     }
732
733     if (max_rate) {
734       oonf_layer2_set_value(&net->data[OONF_LAYER2_NET_MAX_BITRATE], _l2_origin, max_rate);
735     }
736   }
737
738   oonf_layer2_net_commit(net);
739   return;
740 }
741
742 /**
743  * Parse an incoming netlink message from the kernel
744  * @param hdr pointer to netlink message
745  */
746 static void
747 _cb_nl_message(struct nlmsghdr *hdr) {
748   struct genlmsghdr *gen_hdr;
749
750   gen_hdr = NLMSG_DATA(hdr);
751   if (hdr->nlmsg_type == GENL_ID_CTRL && gen_hdr->cmd == CTRL_CMD_NEWFAMILY) {
752     _parse_cmd_newfamily(hdr);
753     return;
754   }
755
756   if (hdr->nlmsg_type == _nl80211_id) {
757     if (gen_hdr->cmd == NL80211_CMD_NEW_STATION) {
758       _parse_cmd_new_station(hdr);
759       return;
760     }
761     if (gen_hdr->cmd == NL80211_CMD_DEL_STATION) {
762       _parse_cmd_del_station(hdr);
763       return;
764     }
765     if (gen_hdr->cmd == NL80211_CMD_NEW_SCAN_RESULTS) {
766       _parse_cmd_new_scan_result(hdr);
767       return;
768     }
769   }
770
771   OONF_INFO(LOG_NL80211, "Unhandled incoming netlink message type %u cmd %u\n",
772       hdr->nlmsg_type, gen_hdr->cmd);
773 }
774
775 /**
776  * Request the list of generic netlink families from the kernel
777  */
778 static void
779 _send_genl_getfamily(void) {
780   struct genlmsghdr *hdr;
781
782   memset(_msgbuf, 0, UIO_MAXIOV);
783
784   /* generic netlink initialization */
785   hdr = NLMSG_DATA(_msgbuf);
786   _msgbuf->nlmsg_len = NLMSG_LENGTH(sizeof(*hdr));
787   _msgbuf->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
788
789   /* request nl80211 identifier */
790   _msgbuf->nlmsg_type = GENL_ID_CTRL;
791
792   hdr->cmd = CTRL_CMD_GETFAMILY;
793   hdr->version = 1;
794
795   os_system_netlink_send(&_netlink_handler, _msgbuf);
796 }
797
798 /**
799  * Request a station dump from nl80211
800  * @param if_idx interface index to be dumped
801  */
802 static void
803 _send_nl80211_get_station_dump(int if_idx) {
804   struct genlmsghdr *hdr;
805
806   memset(_msgbuf, 0, UIO_MAXIOV);
807
808   /* generic netlink initialization */
809   hdr = NLMSG_DATA(_msgbuf);
810   _msgbuf->nlmsg_len = NLMSG_LENGTH(sizeof(*hdr));
811   _msgbuf->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
812
813   /* get nl80211 station dump */
814   _msgbuf->nlmsg_type = _nl80211_id;
815   hdr->cmd = NL80211_CMD_GET_STATION;
816
817   /* add interface index to the request */
818   os_system_netlink_addreq(_msgbuf, NL80211_ATTR_IFINDEX, &if_idx, sizeof(if_idx));
819
820   os_system_netlink_send(&_netlink_handler, _msgbuf);
821 }
822
823 /**
824  * Request a passive scan dump from nl80211
825  * @param if_idx interface index to be dumped
826  */
827 static void
828 _send_nl80211_get_scan_dump(int if_idx) {
829   struct genlmsghdr *hdr;
830
831   memset(_msgbuf, 0, UIO_MAXIOV);
832
833   /* generic netlink initialization */
834   hdr = NLMSG_DATA(_msgbuf);
835   _msgbuf->nlmsg_len = NLMSG_LENGTH(sizeof(*hdr));
836   _msgbuf->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
837
838   /* get nl80211 station dump */
839   _msgbuf->nlmsg_type = _nl80211_id;
840   hdr->cmd = NL80211_CMD_GET_SCAN;
841
842   /* add interface index to the request */
843   os_system_netlink_addreq(_msgbuf, NL80211_ATTR_IFINDEX, &if_idx, sizeof(if_idx));
844
845   os_system_netlink_send(&_netlink_handler, _msgbuf);
846 }
847
848 /**
849  * Transmit the next netlink command to nl80211
850  * @param ptr unused
851  */
852 static void
853 _cb_transmission_event(void *ptr __attribute__((unused))) {
854   struct oonf_interface *interf;
855
856   if (_last_queried_if[0] == 0) {
857     /* get first interface */
858     interf = avl_first_element(&oonf_interface_tree, interf, _node);
859   }
860   else {
861     /* get next interface */
862     interf = avl_find_ge_element(&oonf_interface_tree, _last_queried_if, interf, _node);
863
864     if (interf != NULL && strcmp(_last_queried_if, interf->data.name) == 0) {
865       interf = avl_next_element_safe(&oonf_interface_tree, interf, _node);
866     }
867   }
868
869   if (!interf && _next_query_type < QUERY_COUNT-1) {
870     /* begin next query type */
871     _next_query_type++;
872     interf = avl_first_element(&oonf_interface_tree, interf, _node);
873   }
874
875   if (!interf) {
876     /* nothing to do anymore */
877     memset(_last_queried_if, 0, sizeof(_last_queried_if));
878     _next_query_type = QUERY_FIRST;
879     return;
880   }
881   else {
882     strscpy(_last_queried_if, interf->data.name, sizeof(_last_queried_if));
883   }
884
885   OONF_DEBUG(LOG_NL80211, "Send Query %d to NL80211 interface %s",
886       _next_query_type, interf->data.name);
887   if (_next_query_type == QUERY_STATION_DUMP) {
888     _send_nl80211_get_station_dump(interf->data.index);
889   }
890   else if (_next_query_type == QUERY_SCAN_DUMP){
891     _send_nl80211_get_scan_dump(interf->data.index);
892   }
893 }
894
895 static void
896 _cb_nl_error(uint32_t seq, int error) {
897   OONF_DEBUG(LOG_NL80211, "%u: Received error %d", seq, error);
898   _cb_transmission_event(NULL);
899 }
900
901 static void
902 _cb_nl_timeout(void) {
903   OONF_DEBUG(LOG_NL80211, "Received timeout");
904   _cb_transmission_event(NULL);
905 }
906
907 static void
908 _cb_nl_done(uint32_t seq) {
909   OONF_DEBUG(LOG_NL80211, "%u: Received done", seq);
910   _cb_transmission_event(NULL);
911 }
912
913 /**
914  * Update configuration of nl80211-listener plugin
915  */
916 static void
917 _cb_config_changed(void) {
918   if (cfg_schema_tobin(&_config, _nl80211_section.post,
919       _nl80211_entries, ARRAYSIZE(_nl80211_entries))) {
920     OONF_WARN(LOG_NL80211, "Could not convert %s config to bin",
921         OONF_PLUGIN_GET_NAME());
922     return;
923   }
924
925   oonf_timer_set_ext(&_transmission_timer, 1, _config.interval);
926 }