• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/usteer/nl80211.c

  1 /*
  2  *   This program is free software; you can redistribute it and/or modify
  3  *   it under the terms of the GNU General Public License as published by
  4  *   the Free Software Foundation; either version 2 of the License.
  5  *
  6  *   This program is distributed in the hope that it will be useful,
  7  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  8  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  9  *   GNU General Public License for more details.
 10  *
 11  *   You should have received a copy of the GNU General Public License
 12  *   along with this program; if not, write to the Free Software
 13  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 14  *
 15  *   Copyright (C) 2020 embedd.ch 
 16  *   Copyright (C) 2020 Felix Fietkau <nbd@nbd.name> 
 17  *   Copyright (C) 2020 John Crispin <john@phrozen.org> 
 18  */
 19 
 20 #define _GNU_SOURCE
 21 #include <linux/if_ether.h>
 22 #include <net/if.h>
 23 
 24 
 25 #include <stdio.h>
 26 #include <unistd.h>
 27 #include <stdbool.h>
 28 #include <stdint.h>
 29 #include <string.h>
 30 #include <fcntl.h>
 31 #include <errno.h>
 32 
 33 #include <linux/nl80211.h>
 34 #include <unl.h>
 35 
 36 #include "usteer.h"
 37 #include "node.h"
 38 
 39 static struct unl unl;
 40 static struct nlattr *tb[NL80211_ATTR_MAX + 1];
 41 
 42 struct nl80211_survey_req {
 43         void (*cb)(void *priv, struct usteer_survey_data *d);
 44         void *priv;
 45 };
 46 
 47 struct nl80211_scan_req {
 48         void (*cb)(void *priv, struct usteer_scan_result *r);
 49         void *priv;
 50 };
 51 
 52 struct nl80211_freqlist_req {
 53         void (*cb)(void *priv, struct usteer_freq_data *f);
 54         void *priv;
 55 };
 56 
 57 static int nl80211_survey_result(struct nl_msg *msg, void *arg)
 58 {
 59         static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
 60                 [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
 61                 [NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
 62                 [NL80211_SURVEY_INFO_CHANNEL_TIME] = { .type = NLA_U64 },
 63                 [NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY] = { .type = NLA_U64 },
 64         };
 65         struct nlattr *tb[NL80211_ATTR_MAX + 1];
 66         struct nlattr *tb_s[NL80211_SURVEY_INFO_MAX + 1];
 67         struct nl80211_survey_req *req = arg;
 68         struct usteer_survey_data data = {};
 69         struct genlmsghdr *gnlh;
 70 
 71         gnlh = nlmsg_data(nlmsg_hdr(msg));
 72         nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
 73                   genlmsg_attrlen(gnlh, 0), NULL);
 74 
 75         if (!tb[NL80211_ATTR_SURVEY_INFO])
 76                 return NL_SKIP;
 77 
 78         if (nla_parse_nested(tb_s, NL80211_SURVEY_INFO_MAX,
 79                              tb[NL80211_ATTR_SURVEY_INFO], survey_policy))
 80                 return NL_SKIP;
 81 
 82         if (!tb_s[NL80211_SURVEY_INFO_FREQUENCY])
 83                 return NL_SKIP;
 84 
 85         data.freq = nla_get_u32(tb_s[NL80211_SURVEY_INFO_FREQUENCY]);
 86 
 87         if (tb_s[NL80211_SURVEY_INFO_NOISE])
 88                 data.noise = (int8_t) nla_get_u8(tb_s[NL80211_SURVEY_INFO_NOISE]);
 89 
 90         if (tb_s[NL80211_SURVEY_INFO_CHANNEL_TIME] &&
 91             tb_s[NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY]) {
 92                 data.time = nla_get_u64(tb_s[NL80211_SURVEY_INFO_CHANNEL_TIME]);
 93                 data.time_busy = nla_get_u64(tb_s[NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY]);
 94         }
 95 
 96         req->cb(req->priv, &data);
 97 
 98         return NL_SKIP;
 99 }
100 
101 static void nl80211_get_survey(struct usteer_node *node, void *priv,
102                                void (*cb)(void *priv, struct usteer_survey_data *d))
103 {
104         struct usteer_local_node *ln = container_of(node, struct usteer_local_node, node);
105         struct nl80211_survey_req req = {
106                 .priv = priv,
107                 .cb = cb,
108         };
109         struct nl_msg *msg;
110 
111         if (!ln->nl80211.present)
112                 return;
113 
114         msg = unl_genl_msg(&unl, NL80211_CMD_GET_SURVEY, true);
115         NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ln->ifindex);
116         unl_genl_request(&unl, msg, nl80211_survey_result, &req);
117 
118 nla_put_failure:
119         return;
120 }
121 
122 static void nl80211_update_node_result(void *priv, struct usteer_survey_data *d)
123 {
124         struct usteer_local_node *ln = priv;
125         uint32_t delta = 0, delta_busy = 0;
126 
127         if (d->freq != ln->node.freq)
128                 return;
129 
130         if (d->noise)
131                 ln->node.noise = d->noise;
132 
133         if (ln->time) {
134                 delta = d->time - ln->time;
135                 delta_busy = d->time_busy - ln->time_busy;
136         }
137 
138         ln->time = d->time;
139         ln->time_busy = d->time_busy;
140 
141         if (delta) {
142                 float cur = (100 * delta_busy) / delta;
143 
144                 if (ln->load_ewma < 0)
145                         ln->load_ewma = cur;
146                 else
147                         ln->load_ewma = 0.85 * ln->load_ewma + 0.15 * cur;
148 
149                 ln->node.load = ln->load_ewma;
150         }
151 }
152 
153 static void nl80211_update_node(struct uloop_timeout *t)
154 {
155         struct usteer_local_node *ln = container_of(t, struct usteer_local_node, nl80211.update);
156 
157         uloop_timeout_set(t, 1000);
158         ln->ifindex = if_nametoindex(ln->iface);
159         nl80211_get_survey(&ln->node, ln, nl80211_update_node_result);
160 }
161 
162 static void nl80211_init_node(struct usteer_node *node)
163 {
164         struct usteer_local_node *ln = container_of(node, struct usteer_local_node, node);
165         struct genlmsghdr *gnlh;
166         static bool _init = false;
167         struct nl_msg *msg;
168 
169         if (node->type != NODE_TYPE_LOCAL)
170                 return;
171 
172         ln->nl80211.present = false;
173         ln->wiphy = -1;
174 
175         if (!ln->ifindex) {
176                 MSG(INFO, "No ifindex found for node %s\n", usteer_node_name(node));
177                 return;
178         }
179 
180         if (!_init) {
181                 if (unl_genl_init(&unl, "nl80211") < 0) {
182                         unl_free(&unl);
183                         MSG(INFO, "nl80211 init failed\n");
184                         return;
185                 }
186 
187                 _init = true;
188         }
189 
190         msg = unl_genl_msg(&unl, NL80211_CMD_GET_INTERFACE, false);
191         NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ln->ifindex);
192         unl_genl_request_single(&unl, msg, &msg);
193         if (!msg)
194                 return;
195 
196         gnlh = nlmsg_data(nlmsg_hdr(msg));
197         nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
198                   genlmsg_attrlen(gnlh, 0), NULL);
199 
200         if (!tb[NL80211_ATTR_WIPHY])
201                 goto nla_put_failure;
202 
203         if (!tb[NL80211_ATTR_MAC])
204                 goto nla_put_failure;
205 
206         ln->wiphy = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
207 
208         memcpy(node->bssid, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
209 
210         if (tb[NL80211_ATTR_SSID]) {
211                 int len = nla_len(tb[NL80211_ATTR_SSID]);
212 
213                 if (len >= sizeof(node->ssid))
214                         len = sizeof(node->ssid) - 1;
215 
216                 memcpy(node->ssid, nla_data(tb[NL80211_ATTR_SSID]), len);
217                 node->ssid[len] = 0;
218         }
219 
220         MSG(INFO, "Found nl80211 phy on wdev %s, ssid=%s\n", usteer_node_name(node), node->ssid);
221         ln->load_ewma = -1;
222         ln->nl80211.present = true;
223         ln->nl80211.update.cb = nl80211_update_node;
224         nl80211_update_node(&ln->nl80211.update);
225 
226 nla_put_failure:
227         nlmsg_free(msg);
228         return;
229 }
230 
231 static void nl80211_free_node(struct usteer_node *node)
232 {
233         struct usteer_local_node *ln = container_of(node, struct usteer_local_node, node);
234 
235         if (!ln->nl80211.present)
236                 return;
237 
238         uloop_timeout_cancel(&ln->nl80211.update);
239 }
240 
241 static void nl80211_update_sta(struct usteer_node *node, struct sta_info *si)
242 {
243         struct nlattr *tb_sta[NL80211_STA_INFO_MAX + 1];
244         struct usteer_local_node *ln = container_of(node, struct usteer_local_node, node);
245         struct genlmsghdr *gnlh;
246         struct nl_msg *msg;
247         int signal = NO_SIGNAL;
248 
249         if (!ln->nl80211.present)
250                 return;
251 
252         msg = unl_genl_msg(&unl, NL80211_CMD_GET_STATION, false);
253         NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ln->ifindex);
254         NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, si->sta->addr);
255         unl_genl_request_single(&unl, msg, &msg);
256         if (!msg)
257                 return;
258 
259         gnlh = nlmsg_data(nlmsg_hdr(msg));
260         nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
261                   genlmsg_attrlen(gnlh, 0), NULL);
262 
263         if (!tb[NL80211_ATTR_STA_INFO])
264                 goto nla_put_failure;
265 
266         if (nla_parse_nested(tb_sta, NL80211_STA_INFO_MAX,
267                              tb[NL80211_ATTR_STA_INFO], NULL))
268                 goto nla_put_failure;
269 
270         if (tb_sta[NL80211_STA_INFO_SIGNAL_AVG])
271                 signal = (int8_t) nla_get_u8(tb_sta[NL80211_STA_INFO_SIGNAL_AVG]);
272         
273         if (tb_sta[NL80211_STA_INFO_CONNECTED_TIME])
274                 si->connected_since = current_time - (nla_get_u32(tb_sta[NL80211_STA_INFO_CONNECTED_TIME]) * 1000);
275 
276         usteer_sta_info_update(si, signal, true);
277 
278 nla_put_failure:
279         nlmsg_free(msg);
280         return;
281 }
282 
283 static int nl80211_scan_result(struct nl_msg *msg, void *arg)
284 {
285         static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
286                 [NL80211_BSS_FREQUENCY] = { .type = NLA_U32 },
287                 [NL80211_BSS_CAPABILITY] = { .type = NLA_U16 },
288                 [NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 },
289         };
290         struct nlattr *tb[NL80211_ATTR_MAX + 1];
291         struct nlattr *bss[NL80211_BSS_MAX + 1];
292         struct nl80211_scan_req *req = arg;
293         struct usteer_scan_result data = {
294                 .signal = -127,
295         };
296         struct genlmsghdr *gnlh;
297         struct nlattr *ie_attr;
298         int ielen = 0;
299         uint8_t *ie;
300 
301         gnlh = nlmsg_data(nlmsg_hdr(msg));
302         nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
303                   genlmsg_attrlen(gnlh, 0), NULL);
304 
305         if (!tb[NL80211_ATTR_BSS])
306                 return NL_SKIP;
307 
308         if (nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS],
309                              bss_policy))
310                 return NL_SKIP;
311 
312         if (!bss[NL80211_BSS_BSSID] ||
313             !bss[NL80211_BSS_FREQUENCY])
314                 return NL_SKIP;
315 
316         data.freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
317         memcpy(data.bssid, nla_data(bss[NL80211_BSS_BSSID]), sizeof(data.bssid));
318 
319         if (bss[NL80211_BSS_SIGNAL_MBM]) {
320                 int32_t signal = nla_get_u32(bss[NL80211_BSS_SIGNAL_MBM]);
321                 data.signal = signal / 100;
322         }
323 
324         ie_attr = bss[NL80211_BSS_INFORMATION_ELEMENTS];
325         if (!ie_attr)
326                 ie_attr = bss[NL80211_BSS_BEACON_IES];
327 
328         if (!ie_attr)
329                 goto skip_ie;
330 
331         ie = (uint8_t *) nla_data(ie_attr);
332         ielen = nla_len(ie_attr);
333         for (; ielen >= 2 && ielen >= ie[1];
334              ielen -= ie[1] + 2, ie += ie[1] + 2) {
335                 if (ie[0] == 0) { /* SSID */
336                         if (ie[1] > 32)
337                                 continue;
338 
339                         memcpy(data.ssid, ie + 2, ie[1]);
340                 }
341         }
342 
343 skip_ie:
344         req->cb(req->priv, &data);
345 
346         return NL_SKIP;
347 }
348 
349 static int nl80211_scan_event_cb(struct nl_msg *msg, void *data)
350 {
351         struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
352 
353         switch (gnlh->cmd) {
354         case NL80211_CMD_NEW_SCAN_RESULTS:
355         case NL80211_CMD_SCAN_ABORTED:
356                 unl_loop_done(&unl);
357                 break;
358         }
359 
360         return NL_SKIP;
361 }
362 
363 static int nl80211_scan(struct usteer_node *node, struct usteer_scan_request *req,
364                         void *priv, void (*cb)(void *priv, struct usteer_scan_result *r))
365 {
366         struct usteer_local_node *ln = container_of(node, struct usteer_local_node, node);
367         struct nl80211_scan_req reqdata = {
368                 .priv = priv,
369                 .cb = cb,
370         };
371         struct nl_msg *msg;
372         struct nlattr *cur;
373         int i, ret;
374 
375         if (!ln->nl80211.present)
376                 return -ENODEV;
377 
378         msg = unl_genl_msg(&unl, NL80211_CMD_TRIGGER_SCAN, false);
379         NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ln->ifindex);
380 
381         if (!req->passive) {
382                 cur = nla_nest_start(msg, NL80211_ATTR_SCAN_SSIDS);
383                 NLA_PUT(msg, 1, 0, "");
384                 nla_nest_end(msg, cur);
385         }
386 
387         NLA_PUT_U32(msg, NL80211_ATTR_SCAN_FLAGS, NL80211_SCAN_FLAG_AP);
388 
389         if (req->n_freq) {
390                 cur = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES);
391                 for (i = 0; i < req->n_freq; i++)
392                         NLA_PUT_U32(msg, i, req->freq[i]);
393                 nla_nest_end(msg, cur);
394         }
395 
396         unl_genl_subscribe(&unl, "scan");
397         ret = unl_genl_request(&unl, msg, NULL, NULL);
398         if (ret < 0)
399                 goto done;
400 
401         unl_genl_loop(&unl, nl80211_scan_event_cb, NULL);
402 
403 done:
404         unl_genl_unsubscribe(&unl, "scan");
405         if (ret < 0)
406                 return ret;
407 
408         if (!cb)
409                 return 0;
410 
411         msg = unl_genl_msg(&unl, NL80211_CMD_GET_SCAN, true);
412         NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ln->ifindex);
413         unl_genl_request(&unl, msg, nl80211_scan_result, &reqdata);
414 
415         return 0;
416 
417 nla_put_failure:
418         nlmsg_free(msg);
419         return -ENOMEM;
420 }
421 
422 static int nl80211_wiphy_result(struct nl_msg *msg, void *arg)
423 {
424         struct nl80211_freqlist_req *req = arg;
425         struct nlattr *tb[NL80211_ATTR_MAX + 1];
426         struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1];
427         struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1];
428         struct nlattr *nl_band;
429         struct nlattr *nl_freq;
430         struct nlattr *cur;
431         struct genlmsghdr *gnlh;
432         int rem_band;
433         int rem_freq;
434 
435         gnlh = nlmsg_data(nlmsg_hdr(msg));
436         nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
437                   genlmsg_attrlen(gnlh, 0), NULL);
438 
439         if (!tb[NL80211_ATTR_WIPHY_BANDS])
440                 return NL_SKIP;
441 
442         nla_for_each_nested(nl_band, tb[NL80211_ATTR_WIPHY_BANDS], rem_band) {
443                 nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band),
444                           nla_len(nl_band), NULL);
445 
446                 if (!tb_band[NL80211_BAND_ATTR_FREQS])
447                         continue;
448 
449                 nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS],
450                                     rem_freq) {
451                         struct usteer_freq_data f = {};
452 
453                         nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX,
454                                   nla_data(nl_freq), nla_len(nl_freq), NULL);
455 
456                         if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
457                                 continue;
458 
459                         if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IR])
460                                 continue;
461 
462                         cur = tb_freq[NL80211_FREQUENCY_ATTR_FREQ];
463                         if (!cur)
464                                 continue;
465 
466                         f.freq = nla_get_u32(cur);
467                         f.dfs = !!tb_freq[NL80211_FREQUENCY_ATTR_RADAR];
468 
469                         cur = tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER];
470                         if (cur)
471                                 f.txpower = nla_get_u32(cur) / 100;
472 
473                         req->cb(req->priv, &f);
474                 }
475         }
476 
477         return NL_SKIP;
478 }
479 
480 static void nl80211_get_freqlist(struct usteer_node *node, void *priv,
481                                  void (*cb)(void *priv, struct usteer_freq_data *f))
482 {
483         struct usteer_local_node *ln = container_of(node, struct usteer_local_node, node);
484         struct nl80211_freqlist_req req = {
485                 .priv = priv,
486                 .cb = cb
487         };
488         struct nl_msg *msg;
489 
490         if (!ln->nl80211.present)
491                 return;
492 
493         msg = unl_genl_msg(&unl, NL80211_CMD_GET_WIPHY, false);
494 
495         NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, ln->wiphy);
496         NLA_PUT_FLAG(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP);
497 
498         unl_genl_request(&unl, msg, nl80211_wiphy_result, &req);
499 
500         return;
501 
502 nla_put_failure:
503         nlmsg_free(msg);
504 }
505 
506 static struct usteer_node_handler nl80211_handler = {
507         .init_node = nl80211_init_node,
508         .free_node = nl80211_free_node,
509         .update_sta = nl80211_update_sta,
510         .get_survey = nl80211_get_survey,
511         .get_freqlist = nl80211_get_freqlist,
512         .scan = nl80211_scan,
513 };
514 
515 static void __usteer_init usteer_nl80211_init(void)
516 {
517         list_add(&nl80211_handler.list, &node_handlers);
518 }
519 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt