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

Sources/usteer/ubus.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 #include <sys/types.h>
 21 #include <sys/socket.h>
 22 #include <net/ethernet.h>
 23 #ifdef linux
 24 #include <netinet/ether.h>
 25 #endif
 26 
 27 #include "usteer.h"
 28 #include "node.h"
 29 #include "event.h"
 30 
 31 static struct blob_buf b;
 32 static KVLIST(host_info, kvlist_blob_len);
 33 
 34 static void *
 35 blobmsg_open_table_mac(struct blob_buf *buf, uint8_t *addr)
 36 {
 37         char str[20];
 38         sprintf(str, MAC_ADDR_FMT, MAC_ADDR_DATA(addr));
 39         return blobmsg_open_table(buf, str);
 40 }
 41 
 42 static int
 43 usteer_ubus_get_clients(struct ubus_context *ctx, struct ubus_object *obj,
 44                        struct ubus_request_data *req, const char *method,
 45                        struct blob_attr *msg)
 46 {
 47         struct sta_info *si;
 48         struct sta *sta;
 49         void *_s, *_cur_n;
 50 
 51         blob_buf_init(&b, 0);
 52         avl_for_each_element(&stations, sta, avl) {
 53                 _s = blobmsg_open_table_mac(&b, sta->addr);
 54                 list_for_each_entry(si, &sta->nodes, list) {
 55                         _cur_n = blobmsg_open_table(&b, usteer_node_name(si->node));
 56                         blobmsg_add_u8(&b, "connected", si->connected);
 57                         blobmsg_add_u32(&b, "signal", si->signal);
 58                         blobmsg_close_table(&b, _cur_n);
 59                 }
 60                 blobmsg_close_table(&b, _s);
 61         }
 62         ubus_send_reply(ctx, req, b.head);
 63         return 0;
 64 }
 65 
 66 static struct blobmsg_policy client_arg[] = {
 67         { .name = "address", .type = BLOBMSG_TYPE_STRING, },
 68 };
 69 
 70 static void
 71 usteer_ubus_add_stats(struct sta_info_stats *stats, const char *name)
 72 {
 73         void *s;
 74 
 75         s = blobmsg_open_table(&b, name);
 76         blobmsg_add_u32(&b, "requests", stats->requests);
 77         blobmsg_add_u32(&b, "blocked_cur", stats->blocked_cur);
 78         blobmsg_add_u32(&b, "blocked_total", stats->blocked_total);
 79         blobmsg_close_table(&b, s);
 80 }
 81 
 82 static int
 83 usteer_ubus_get_client_info(struct ubus_context *ctx, struct ubus_object *obj,
 84                            struct ubus_request_data *req, const char *method,
 85                            struct blob_attr *msg)
 86 {
 87         struct sta_info *si;
 88         struct sta *sta;
 89         struct blob_attr *mac_str;
 90         uint8_t *mac;
 91         void *_n, *_cur_n, *_s;
 92         int i;
 93 
 94         blobmsg_parse(client_arg, 1, &mac_str, blob_data(msg), blob_len(msg));
 95         if (!mac_str)
 96                 return UBUS_STATUS_INVALID_ARGUMENT;
 97 
 98         mac = (uint8_t *) ether_aton(blobmsg_data(mac_str));
 99         if (!mac)
100                 return UBUS_STATUS_INVALID_ARGUMENT;
101 
102         sta = usteer_sta_get(mac, false);
103         if (!sta)
104                 return UBUS_STATUS_NOT_FOUND;
105 
106         blob_buf_init(&b, 0);
107         blobmsg_add_u8(&b, "2ghz", sta->seen_2ghz);
108         blobmsg_add_u8(&b, "5ghz", sta->seen_5ghz);
109         _n = blobmsg_open_table(&b, "nodes");
110         list_for_each_entry(si, &sta->nodes, list) {
111                 _cur_n = blobmsg_open_table(&b, usteer_node_name(si->node));
112                 blobmsg_add_u8(&b, "connected", si->connected);
113                 blobmsg_add_u32(&b, "signal", si->signal);
114                 _s = blobmsg_open_table(&b, "stats");
115                 for (i = 0; i < __EVENT_TYPE_MAX; i++)
116                         usteer_ubus_add_stats(&si->stats[EVENT_TYPE_PROBE], event_types[i]);
117                 blobmsg_close_table(&b, _s);
118                 blobmsg_close_table(&b, _cur_n);
119         }
120         blobmsg_close_table(&b, _n);
121 
122         ubus_send_reply(ctx, req, b.head);
123 
124         return 0;
125 }
126 
127 enum cfg_type {
128         CFG_BOOL,
129         CFG_I32,
130         CFG_U32,
131         CFG_ARRAY_CB,
132         CFG_STRING_CB,
133 };
134 
135 struct cfg_item {
136         enum cfg_type type;
137         union {
138                 bool *BOOL;
139                 uint32_t *U32;
140                 int32_t *I32;
141                 struct {
142                         void (*set)(struct blob_attr *data);
143                         void (*get)(struct blob_buf *buf);
144                 } CB;
145         } ptr;
146 };
147 
148 #define __config_items \
149         _cfg(BOOL, syslog), \
150         _cfg(U32, debug_level), \
151         _cfg(BOOL, ipv6), \
152         _cfg(BOOL, local_mode), \
153         _cfg(U32, sta_block_timeout), \
154         _cfg(U32, local_sta_timeout), \
155         _cfg(U32, local_sta_update), \
156         _cfg(U32, max_neighbor_reports), \
157         _cfg(U32, max_retry_band), \
158         _cfg(U32, seen_policy_timeout), \
159         _cfg(U32, measurement_report_timeout), \
160         _cfg(U32, load_balancing_threshold), \
161         _cfg(U32, band_steering_threshold), \
162         _cfg(U32, remote_update_interval), \
163         _cfg(U32, remote_node_timeout), \
164         _cfg(BOOL, assoc_steering), \
165         _cfg(U32, aggressiveness), \
166         _cfg(ARRAY_CB, aggressiveness_mac_list), \
167         _cfg(U32, aggressive_disassoc_timer), \
168         _cfg(I32, min_connect_snr), \
169         _cfg(I32, min_snr), \
170         _cfg(U32, min_snr_kick_delay), \
171         _cfg(U32, steer_reject_timeout), \
172         _cfg(U32, roam_process_timeout), \
173         _cfg(I32, roam_scan_snr), \
174         _cfg(U32, roam_scan_tries), \
175         _cfg(U32, roam_scan_timeout), \
176         _cfg(U32, roam_scan_interval), \
177         _cfg(I32, roam_trigger_snr), \
178         _cfg(U32, roam_trigger_interval), \
179         _cfg(U32, roam_kick_delay), \
180         _cfg(U32, signal_diff_threshold), \
181         _cfg(U32, initial_connect_delay), \
182         _cfg(BOOL, load_kick_enabled), \
183         _cfg(U32, load_kick_threshold), \
184         _cfg(U32, load_kick_delay), \
185         _cfg(U32, load_kick_min_clients), \
186         _cfg(U32, load_kick_reason_code), \
187         _cfg(U32, band_steering_interval), \
188         _cfg(I32, band_steering_min_snr), \
189         _cfg(U32, link_measurement_interval), \
190         _cfg(ARRAY_CB, interfaces), \
191         _cfg(STRING_CB, node_up_script), \
192         _cfg(ARRAY_CB, event_log_types), \
193         _cfg(ARRAY_CB, ssid_list)
194 
195 enum cfg_items {
196 #define _cfg(_type, _name) CFG_##_name
197         __config_items,
198 #undef _cfg
199         __CFG_MAX,
200 };
201 
202 static const struct blobmsg_policy config_policy[__CFG_MAX] = {
203 #define _cfg_policy(_type, _name) [CFG_##_name] = { .name = #_name, .type = BLOBMSG_TYPE_ ## _type }
204 #define _cfg_policy_BOOL(_name) _cfg_policy(BOOL, _name)
205 #define _cfg_policy_U32(_name) _cfg_policy(INT32, _name)
206 #define _cfg_policy_I32(_name) _cfg_policy(INT32, _name)
207 #define _cfg_policy_ARRAY_CB(_name) _cfg_policy(ARRAY, _name)
208 #define _cfg_policy_STRING_CB(_name) _cfg_policy(STRING, _name)
209 #define _cfg(_type, _name) _cfg_policy_##_type(_name)
210         __config_items,
211 #undef _cfg
212 };
213 
214 static const struct cfg_item config_data[__CFG_MAX] = {
215 #define _cfg_data_BOOL(_name) .ptr.BOOL = &config._name
216 #define _cfg_data_U32(_name) .ptr.U32 = &config._name
217 #define _cfg_data_I32(_name) .ptr.I32 = &config._name
218 #define _cfg_data_ARRAY_CB(_name) .ptr.CB = { .set = config_set_##_name, .get = config_get_##_name }
219 #define _cfg_data_STRING_CB(_name) .ptr.CB = { .set = config_set_##_name, .get = config_get_##_name }
220 #define _cfg(_type, _name) [CFG_##_name] = { .type = CFG_##_type, _cfg_data_##_type(_name) }
221         __config_items,
222 #undef _cfg
223 };
224 
225 static int
226 usteer_ubus_get_config(struct ubus_context *ctx, struct ubus_object *obj,
227                       struct ubus_request_data *req, const char *method,
228                       struct blob_attr *msg)
229 {
230         int i;
231 
232         blob_buf_init(&b, 0);
233         for (i = 0; i < __CFG_MAX; i++) {
234                 switch(config_data[i].type) {
235                 case CFG_BOOL:
236                         blobmsg_add_u8(&b, config_policy[i].name,
237                                         *config_data[i].ptr.BOOL);
238                         break;
239                 case CFG_I32:
240                 case CFG_U32:
241                         blobmsg_add_u32(&b, config_policy[i].name,
242                                         *config_data[i].ptr.U32);
243                         break;
244                 case CFG_ARRAY_CB:
245                 case CFG_STRING_CB:
246                         config_data[i].ptr.CB.get(&b);
247                         break;
248                 }
249         }
250         ubus_send_reply(ctx, req, b.head);
251         return 0;
252 }
253 
254 static int
255 usteer_ubus_set_config(struct ubus_context *ctx, struct ubus_object *obj,
256                       struct ubus_request_data *req, const char *method,
257                       struct blob_attr *msg)
258 {
259         struct blob_attr *tb[__CFG_MAX];
260         int i;
261 
262         if (!strcmp(method, "set_config"))
263                 usteer_init_defaults();
264 
265         blobmsg_parse(config_policy, __CFG_MAX, tb, blob_data(msg), blob_len(msg));
266         for (i = 0; i < __CFG_MAX; i++) {
267                 switch(config_data[i].type) {
268                 case CFG_BOOL:
269                         if (!tb[i])
270                                 continue;
271 
272                         *config_data[i].ptr.BOOL = blobmsg_get_u8(tb[i]);
273                         break;
274                 case CFG_I32:
275                 case CFG_U32:
276                         if (!tb[i])
277                                 continue;
278 
279                         *config_data[i].ptr.U32 = blobmsg_get_u32(tb[i]);
280                         break;
281                 case CFG_ARRAY_CB:
282                 case CFG_STRING_CB:
283                         config_data[i].ptr.CB.set(tb[i]);
284                         break;
285                 }
286         }
287 
288         usteer_interface_init();
289 
290         return 0;
291 }
292 
293 void usteer_dump_node(struct blob_buf *buf, struct usteer_node *node)
294 {
295         void *c, *roam_events;
296 
297         c = blobmsg_open_table(buf, usteer_node_name(node));
298         blobmsg_printf(buf, "bssid", MAC_ADDR_FMT, MAC_ADDR_DATA(node->bssid));
299         blobmsg_add_string(buf, "ssid", node->ssid);
300         blobmsg_add_u32(buf, "freq", node->freq);
301         blobmsg_add_u32(buf, "n_assoc", node->n_assoc);
302         blobmsg_add_u32(buf, "noise", node->noise);
303         blobmsg_add_u32(buf, "load", node->load);
304         blobmsg_add_u32(buf, "max_assoc", node->max_assoc);
305 
306         roam_events = blobmsg_open_table(buf, "roam_events");
307         blobmsg_add_u32(buf, "source", node->roam_events.source);
308         blobmsg_add_u32(buf, "target", node->roam_events.target);
309         blobmsg_close_table(buf, roam_events);
310 
311         if (node->rrm_nr)
312                 blobmsg_add_field(buf, BLOBMSG_TYPE_ARRAY, "rrm_nr",
313                                   blobmsg_data(node->rrm_nr),
314                                   blobmsg_data_len(node->rrm_nr));
315         if (node->node_info)
316                 blobmsg_add_field(buf, BLOBMSG_TYPE_TABLE, "node_info",
317                                   blob_data(node->node_info),
318                                   blob_len(node->node_info));
319 
320         blobmsg_close_table(buf, c);
321 }
322 
323 void usteer_dump_host(struct blob_buf *buf, struct usteer_remote_host *host)
324 {
325         void *c;
326 
327         c = blobmsg_open_table(buf, host->addr);
328         blobmsg_add_u32(buf, "id", (uint32_t)(uintptr_t)host->avl.key);
329         if (host->host_info)
330                 blobmsg_add_field(buf, BLOBMSG_TYPE_TABLE, "host_info",
331                                   blobmsg_data(host->host_info),
332                                   blobmsg_len(host->host_info));
333         blobmsg_close_table(buf, c);
334 }
335 
336 static int
337 usteer_ubus_local_info(struct ubus_context *ctx, struct ubus_object *obj,
338                       struct ubus_request_data *req, const char *method,
339                       struct blob_attr *msg)
340 {
341         struct usteer_node *node;
342 
343         blob_buf_init(&b, 0);
344 
345         for_each_local_node(node)
346                 usteer_dump_node(&b, node);
347 
348         ubus_send_reply(ctx, req, b.head);
349 
350         return 0;
351 }
352 
353 static int
354 usteer_ubus_remote_hosts(struct ubus_context *ctx, struct ubus_object *obj,
355                          struct ubus_request_data *req, const char *method,
356                          struct blob_attr *msg)
357 {
358         struct usteer_remote_host *host;
359 
360         blob_buf_init(&b, 0);
361 
362         avl_for_each_element(&remote_hosts, host, avl)
363                 usteer_dump_host(&b, host);
364 
365         ubus_send_reply(ctx, req, b.head);
366 
367         return 0;
368 }
369 
370 static int
371 usteer_ubus_remote_info(struct ubus_context *ctx, struct ubus_object *obj,
372                        struct ubus_request_data *req, const char *method,
373                        struct blob_attr *msg)
374 {
375         struct usteer_remote_node *rn;
376 
377         blob_buf_init(&b, 0);
378 
379         for_each_remote_node(rn)
380                 usteer_dump_node(&b, &rn->node);
381 
382         ubus_send_reply(ctx, req, b.head);
383 
384         return 0;
385 }
386 
387 static const char *usteer_get_roam_sm_name(enum roam_trigger_state state)
388 {
389         switch (state) {
390                 case ROAM_TRIGGER_IDLE:
391                         return "ROAM_TRIGGER_IDLE";
392                 case ROAM_TRIGGER_SCAN:
393                         return "ROAM_TRIGGER_SCAN";
394                 case ROAM_TRIGGER_SCAN_DONE:
395                         return "ROAM_TRIGGER_SCAN_DONE";
396         }
397         return "N/A";
398 }
399 
400 static int
401 usteer_ubus_get_connected_clients(struct ubus_context *ctx, struct ubus_object *obj,
402                                   struct ubus_request_data *req, const char *method,
403                                   struct blob_attr *msg)
404 {
405         struct usteer_measurement_report *mr;
406         struct usteer_node *node;
407         struct sta_info *si;
408         void *n, *s, *t, *a;
409 
410         blob_buf_init(&b, 0);
411 
412         for_each_local_node(node) {
413                 n = blobmsg_open_table(&b, usteer_node_name(node));
414 
415                 list_for_each_entry(si, &node->sta_info, node_list) {
416                         if (si->connected != STA_CONNECTED)
417                                 continue;
418 
419                         s = blobmsg_open_table_mac(&b, si->sta->addr);
420                         blobmsg_add_u32(&b, "signal", si->signal);
421                         blobmsg_add_u64(&b, "created", current_time - si->created);
422                         blobmsg_add_u64(&b, "connected", current_time - si->connected_since);
423 
424                         t = blobmsg_open_table(&b, "snr-kick");
425                         blobmsg_add_u32(&b, "seen-below", si->below_min_snr);
426                         blobmsg_close_table(&b, t);
427 
428                         t = blobmsg_open_table(&b, "roam-state-machine");
429                         blobmsg_add_string(&b, "state",usteer_get_roam_sm_name(si->roam_state));
430                         blobmsg_add_u32(&b, "tries", si->roam_tries);
431                         blobmsg_add_u64(&b, "event", si->roam_event ? current_time - si->roam_event : 0);
432                         blobmsg_add_u32(&b, "kick-count", si->kick_count);
433                         blobmsg_add_u64(&b, "last-kick", si->roam_kick ? current_time - si->roam_kick : 0);
434                         blobmsg_add_u64(&b, "scan_start", si->roam_scan_start ? current_time - si->roam_scan_start : 0);
435                         blobmsg_add_u64(&b, "scan_timeout_start", si->roam_scan_timeout_start ? current_time - si->roam_scan_timeout_start : 0);
436                         blobmsg_close_table(&b, t);
437 
438                         t = blobmsg_open_table(&b, "bss-transition-response");
439                         blobmsg_add_u32(&b, "status-code", si->bss_transition_response.status_code);
440                         blobmsg_add_u64(&b, "age", si->bss_transition_response.timestamp ? current_time - si->bss_transition_response.timestamp : 0);
441                         blobmsg_close_table(&b, t);
442 
443                         /* Beacon measurement modes */
444                         a = blobmsg_open_array(&b, "beacon-measurement-modes");
445                         if (usteer_sta_supports_beacon_measurement_mode(si, BEACON_MEASUREMENT_PASSIVE))
446                                 blobmsg_add_string(&b, "", "PASSIVE");
447                         if (usteer_sta_supports_beacon_measurement_mode(si, BEACON_MEASUREMENT_ACTIVE))
448                                 blobmsg_add_string(&b, "", "ACTIVE");
449                         if (usteer_sta_supports_beacon_measurement_mode(si, BEACON_MEASUREMENT_TABLE))
450                                 blobmsg_add_string(&b, "", "TABLE");
451                         blobmsg_close_array(&b, a);
452 
453                         /* Link-Measurement support */
454                         blobmsg_add_u8(&b, "link-measurement", usteer_sta_supports_link_measurement(si));
455 
456                         /* BSS-Transition support */
457                         blobmsg_add_u8(&b, "bss-transition-management", si->bss_transition);
458 
459                         /* MBO support */
460                         blobmsg_add_u8(&b, "multi-band-operation", si->mbo);
461 
462                         /* Measurements */
463                         a = blobmsg_open_array(&b, "measurements");
464                         list_for_each_entry(mr, &si->sta->measurements, sta_list) {
465                                 t = blobmsg_open_table(&b, "");
466                                 blobmsg_add_string(&b, "node", usteer_node_name(mr->node));
467                                 blobmsg_add_u32(&b, "rcpi", mr->rcpi);
468                                 blobmsg_add_u32(&b, "rsni", mr->rsni);
469                                 blobmsg_add_u32(&b, "rssi", usteer_measurement_get_rssi(mr));
470                                 blobmsg_add_u64(&b, "age", current_time - mr->timestamp);
471                                 blobmsg_close_table(&b, t);
472                         }
473                         blobmsg_close_array(&b, a);
474 
475                         blobmsg_close_table(&b, s);
476                 }
477 
478                 blobmsg_close_table(&b, n);
479         }
480 
481         ubus_send_reply(ctx, req, b.head);
482 
483         return 0;
484 }
485 
486 enum {
487         NODE_DATA_NODE,
488         NODE_DATA_VALUES,
489         __NODE_DATA_MAX,
490 };
491 
492 static const struct blobmsg_policy set_node_data_policy[] = {
493         [NODE_DATA_NODE] = { "node", BLOBMSG_TYPE_STRING },
494         [NODE_DATA_VALUES] = { "data", BLOBMSG_TYPE_TABLE },
495 };
496 
497 static const struct blobmsg_policy del_node_data_policy[] = {
498         [NODE_DATA_NODE] = { "node", BLOBMSG_TYPE_STRING },
499         [NODE_DATA_VALUES] = { "names", BLOBMSG_TYPE_ARRAY },
500 };
501 
502 static void
503 usteer_update_kvlist_data(struct kvlist *kv, struct blob_attr *data,
504                           bool delete)
505 {
506         struct blob_attr *cur;
507         int rem;
508 
509         blobmsg_for_each_attr(cur, data, rem) {
510                 if (delete)
511                         kvlist_delete(kv, blobmsg_get_string(cur));
512                 else
513                         kvlist_set(kv, blobmsg_name(cur), cur);
514         }
515 }
516 
517 static void
518 usteer_update_kvlist_blob(struct blob_attr **dest, struct kvlist *kv)
519 {
520         struct blob_attr *val;
521         const char *name;
522 
523         blob_buf_init(&b, 0);
524         kvlist_for_each(kv, name, val)
525                 blobmsg_add_field(&b, blobmsg_type(val), name,
526                                   blobmsg_data(val), blobmsg_len(val));
527 
528         val = b.head;
529         if (!blobmsg_len(val))
530                 val = NULL;
531 
532         usteer_node_set_blob(dest, val);
533 }
534 
535 static int
536 usteer_ubus_update_node_data(struct ubus_context *ctx, struct ubus_object *obj,
537                              struct ubus_request_data *req, const char *method,
538                              struct blob_attr *msg)
539 {
540         const struct blobmsg_policy *policy;
541         struct blob_attr *tb[__NODE_DATA_MAX];
542         struct usteer_local_node *ln;
543         struct blob_attr *val;
544         const char *name;
545         bool delete;
546 
547         delete = !strncmp(method, "del", 3);
548         policy = delete ? del_node_data_policy : set_node_data_policy;
549 
550         blobmsg_parse(policy, __NODE_DATA_MAX, tb, blob_data(msg), blob_len(msg));
551         if (!tb[NODE_DATA_NODE] || !tb[NODE_DATA_VALUES])
552                 return UBUS_STATUS_INVALID_ARGUMENT;
553 
554         name = blobmsg_get_string(tb[NODE_DATA_NODE]);
555         val = tb[NODE_DATA_VALUES];
556         if (delete && blobmsg_check_array(val, BLOBMSG_TYPE_STRING) < 0)
557                 return UBUS_STATUS_INVALID_ARGUMENT;
558 
559         if (strcmp(name, "*") != 0) {
560                 ln = avl_find_element(&local_nodes, name, ln, node.avl);
561                 if (!ln)
562                         return UBUS_STATUS_NOT_FOUND;
563 
564                 usteer_update_kvlist_data(&ln->node_info, val, delete);
565                 usteer_update_kvlist_blob(&ln->node.node_info, &ln->node_info);
566 
567                 return 0;
568         }
569 
570         usteer_update_kvlist_data(&host_info, val, delete);
571         usteer_update_kvlist_blob(&host_info_blob, &host_info);
572 
573         return 0;
574 }
575 
576 static const struct ubus_method usteer_methods[] = {
577         UBUS_METHOD_NOARG("local_info", usteer_ubus_local_info),
578         UBUS_METHOD_NOARG("remote_hosts", usteer_ubus_remote_hosts),
579         UBUS_METHOD_NOARG("remote_info", usteer_ubus_remote_info),
580         UBUS_METHOD_NOARG("connected_clients", usteer_ubus_get_connected_clients),
581         UBUS_METHOD_NOARG("get_clients", usteer_ubus_get_clients),
582         UBUS_METHOD("get_client_info", usteer_ubus_get_client_info, client_arg),
583         UBUS_METHOD_NOARG("get_config", usteer_ubus_get_config),
584         UBUS_METHOD("set_config", usteer_ubus_set_config, config_policy),
585         UBUS_METHOD("update_config", usteer_ubus_set_config, config_policy),
586         UBUS_METHOD("set_node_data", usteer_ubus_update_node_data, set_node_data_policy),
587         UBUS_METHOD("delete_node_data", usteer_ubus_update_node_data, del_node_data_policy),
588 };
589 
590 static struct ubus_object_type usteer_obj_type =
591         UBUS_OBJECT_TYPE("usteer", usteer_methods);
592 
593 struct ubus_object usteer_obj = {
594         .name = "usteer",
595         .type = &usteer_obj_type,
596         .methods = usteer_methods,
597         .n_methods = ARRAY_SIZE(usteer_methods),
598 };
599 
600 static bool
601 usteer_add_nr_entry(struct usteer_node *ln, struct usteer_node *node)
602 {
603         struct blobmsg_policy policy[3] = {
604                 { .type = BLOBMSG_TYPE_STRING },
605                 { .type = BLOBMSG_TYPE_STRING },
606                 { .type = BLOBMSG_TYPE_STRING },
607         };
608         struct blob_attr *tb[3];
609 
610         if (!node->rrm_nr)
611                 return false;
612 
613         if (strcmp(ln->ssid, node->ssid) != 0)
614                 return false;
615 
616         if (!usteer_policy_node_below_max_assoc(node))
617                 return false;
618 
619         blobmsg_parse_array(policy, ARRAY_SIZE(tb), tb,
620                             blobmsg_data(node->rrm_nr),
621                             blobmsg_data_len(node->rrm_nr));
622         if (!tb[2])
623                 return false;
624 
625         blobmsg_add_field(&b, BLOBMSG_TYPE_STRING, "",
626                           blobmsg_data(tb[2]),
627                           blobmsg_data_len(tb[2]));
628         
629         return true;
630 }
631 
632 static void
633 usteer_ubus_disassoc_add_neighbor(struct sta_info *si, struct usteer_node *node)
634 {
635         void *c;
636 
637         c = blobmsg_open_array(&b, "neighbors");
638         usteer_add_nr_entry(si->node, node);
639         blobmsg_close_array(&b, c);
640 }
641 
642 static void
643 usteer_ubus_disassoc_add_neighbors(struct sta_info *si)
644 {
645         struct usteer_node *node, *last_remote_neighbor = NULL;
646         int i = 0;
647         void *c;
648 
649         c = blobmsg_open_array(&b, "neighbors");
650         for_each_local_node(node) {
651                 if (i >= config.max_neighbor_reports)
652                         break;
653                 if (si->node == node)
654                         continue;
655                 if (usteer_add_nr_entry(si->node, node))
656                         i++;
657         }
658 
659         while (i < config.max_neighbor_reports) {
660                 node = usteer_node_get_next_neighbor(si->node, last_remote_neighbor);
661                 if (!node) {
662                         /* No more nodes available */
663                         break;
664                 }
665 
666                 last_remote_neighbor = node;
667                 if (usteer_add_nr_entry(si->node, node))
668                         i++;
669         }
670         blobmsg_close_array(&b, c);
671 }
672 
673 int usteer_ubus_bss_transition_request(struct sta_info *si,
674                                        uint8_t dialog_token,
675                                        bool disassoc_imminent,
676                                        uint32_t disassoc_timer,
677                                        bool abridged,
678                                        uint8_t validity_period,
679                                        struct usteer_node *target_node)
680 {
681         struct usteer_local_node *ln = container_of(si->node, struct usteer_local_node, node);
682 
683         blob_buf_init(&b, 0);
684         blobmsg_printf(&b, "addr", MAC_ADDR_FMT, MAC_ADDR_DATA(si->sta->addr));
685         blobmsg_add_u32(&b, "dialog_token", dialog_token);
686         blobmsg_add_u8(&b, "disassociation_imminent", disassoc_imminent);
687         if (disassoc_imminent) {
688                 blobmsg_add_u32(&b, "disassociation_timer", disassoc_timer);
689                 blobmsg_add_u32(&b, "reassoc_delay", config.reassociation_delay);
690         }
691         blobmsg_add_u8(&b, "abridged", abridged);
692         blobmsg_add_u32(&b, "validity_period", validity_period);
693         blobmsg_add_u32(&b, "mbo_reason", 5);
694 
695         if (!target_node) {
696                 /* Add all known neighbors if no specific target set */
697                 MSG(VERBOSE, "roaming station " MAC_ADDR_FMT " without target\n", MAC_ADDR_DATA(si->sta->addr));
698                 usteer_ubus_disassoc_add_neighbors(si);
699         } else {
700                 MSG(VERBOSE, "roaming station " MAC_ADDR_FMT " to " MAC_ADDR_FMT " (%s) disassociation timer %u, signal %d\n", MAC_ADDR_DATA(si->sta->addr), MAC_ADDR_DATA(target_node->bssid), usteer_node_name(target_node), disassoc_timer, si->signal);
701                 usteer_ubus_disassoc_add_neighbor(si, target_node);
702         }
703         return ubus_invoke(ubus_ctx, ln->obj_id, "bss_transition_request", b.head, NULL, 0, 100);
704 }
705 
706 int usteer_ubus_band_steering_request(struct sta_info *si,
707                                       uint8_t dialog_token,
708                                       bool disassoc_imminent,
709                                       uint32_t disassoc_timer,
710                                       bool abridged,
711                                       uint8_t validity_period)
712 {
713         struct usteer_local_node *ln = container_of(si->node, struct usteer_local_node, node);
714         struct usteer_node *node;
715         void *c;
716 
717         blob_buf_init(&b, 0);
718         blobmsg_printf(&b, "addr", MAC_ADDR_FMT, MAC_ADDR_DATA(si->sta->addr));
719         blobmsg_add_u32(&b, "dialog_token", dialog_token);
720         blobmsg_add_u8(&b, "disassociation_imminent", disassoc_imminent);
721         if (disassoc_imminent) {
722                 blobmsg_add_u32(&b, "disassociation_timer", disassoc_timer);
723                 blobmsg_add_u32(&b, "reassoc_delay", config.reassociation_delay);
724         }
725         blobmsg_add_u8(&b, "abridged", abridged);
726         blobmsg_add_u32(&b, "validity_period", validity_period);
727         blobmsg_add_u32(&b, "mbo_reason", 5);
728 
729         c = blobmsg_open_array(&b, "neighbors");
730         for_each_local_node(node) {
731                 if (!usteer_band_steering_is_target(ln, node))
732                         continue;
733         
734                 usteer_add_nr_entry(si->node, node);
735                 MSG(DEBUG, "band steering station " MAC_ADDR_FMT " adding neighbor " MAC_ADDR_FMT " (%s)\n", MAC_ADDR_DATA(si->sta->addr), MAC_ADDR_DATA(node->bssid), usteer_node_name(node));
736         }
737         blobmsg_close_array(&b, c);
738         if (sizeof(si->node) > 0) {
739                 MSG(VERBOSE, "band steering station " MAC_ADDR_FMT " disassociation timer %u, signal %d\n", MAC_ADDR_DATA(si->sta->addr), disassoc_timer, si->signal);
740                 return ubus_invoke(ubus_ctx, ln->obj_id, "bss_transition_request", b.head, NULL, 0, 100);
741         } else
742                 MSG(VERBOSE, "band steering no targets found for station " MAC_ADDR_FMT "\n", MAC_ADDR_DATA(si->sta->addr));
743 }
744 
745 int usteer_ubus_trigger_link_measurement(struct sta_info *si)
746 {
747         struct usteer_local_node *ln = container_of(si->node, struct usteer_local_node, node);
748 
749         if (!usteer_sta_supports_link_measurement(si))
750                 return 0;
751 
752         blob_buf_init(&b, 0);
753         blobmsg_printf(&b, "addr", MAC_ADDR_FMT, MAC_ADDR_DATA(si->sta->addr));
754         blobmsg_add_u32(&b, "tx-power-used", 5);
755         blobmsg_add_u32(&b, "tx-power-max", 10);
756         return ubus_invoke(ubus_ctx, ln->obj_id, "link_measurement_req", b.head, NULL, 0, 100);
757 }
758 
759 int usteer_ubus_trigger_client_scan(struct sta_info *si)
760 {
761         struct usteer_local_node *ln = container_of(si->node, struct usteer_local_node, node);
762 
763         if (!usteer_sta_supports_beacon_measurement_mode(si, BEACON_MEASUREMENT_ACTIVE)) {
764                 MSG(DEBUG, "STA does not support beacon measurement sta=" MAC_ADDR_FMT "\n", MAC_ADDR_DATA(si->sta->addr));
765                 return 0;
766         }
767 
768         si->scan_band = !si->scan_band;
769 
770         blob_buf_init(&b, 0);
771         blobmsg_printf(&b, "addr", MAC_ADDR_FMT, MAC_ADDR_DATA(si->sta->addr));
772         blobmsg_add_string(&b, "ssid", si->node->ssid);
773         blobmsg_add_u32(&b, "mode", BEACON_MEASUREMENT_ACTIVE);
774         blobmsg_add_u32(&b, "duration", config.roam_scan_interval / 100);
775         blobmsg_add_u32(&b, "channel", 0);
776         blobmsg_add_u32(&b, "op_class", si->scan_band ? 1 : 12);
777         return ubus_invoke(ubus_ctx, ln->obj_id, "rrm_beacon_req", b.head, NULL, 0, 100);
778 }
779 
780 void usteer_ubus_kick_client(struct sta_info *si, uint32_t kick_reason_code)
781 {
782         struct usteer_local_node *ln = container_of(si->node, struct usteer_local_node, node);
783 
784         blob_buf_init(&b, 0);
785         blobmsg_printf(&b, "addr", MAC_ADDR_FMT, MAC_ADDR_DATA(si->sta->addr));
786         blobmsg_add_u32(&b, "reason", kick_reason_code);
787         blobmsg_add_u8(&b, "deauth", 1);
788         ubus_invoke(ubus_ctx, ln->obj_id, "del_client", b.head, NULL, 0, 100);
789         usteer_sta_disconnected(si);
790         si->kick_count++;
791         si->roam_kick = current_time;
792 }
793 
794 void usteer_ubus_init(struct ubus_context *ctx)
795 {
796         ubus_add_object(ctx, &usteer_obj);
797 }
798 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt