• 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(I32, min_connect_snr), \
166         _cfg(I32, min_snr), \
167         _cfg(U32, min_snr_kick_delay), \
168         _cfg(U32, steer_reject_timeout), \
169         _cfg(U32, roam_process_timeout), \
170         _cfg(I32, roam_scan_snr), \
171         _cfg(U32, roam_scan_tries), \
172         _cfg(U32, roam_scan_timeout), \
173         _cfg(U32, roam_scan_interval), \
174         _cfg(I32, roam_trigger_snr), \
175         _cfg(U32, roam_trigger_interval), \
176         _cfg(U32, roam_kick_delay), \
177         _cfg(U32, signal_diff_threshold), \
178         _cfg(U32, initial_connect_delay), \
179         _cfg(BOOL, load_kick_enabled), \
180         _cfg(U32, load_kick_threshold), \
181         _cfg(U32, load_kick_delay), \
182         _cfg(U32, load_kick_min_clients), \
183         _cfg(U32, load_kick_reason_code), \
184         _cfg(U32, band_steering_interval), \
185         _cfg(I32, band_steering_min_snr), \
186         _cfg(U32, link_measurement_interval), \
187         _cfg(ARRAY_CB, interfaces), \
188         _cfg(STRING_CB, node_up_script), \
189         _cfg(ARRAY_CB, event_log_types), \
190         _cfg(ARRAY_CB, ssid_list)
191 
192 enum cfg_items {
193 #define _cfg(_type, _name) CFG_##_name
194         __config_items,
195 #undef _cfg
196         __CFG_MAX,
197 };
198 
199 static const struct blobmsg_policy config_policy[__CFG_MAX] = {
200 #define _cfg_policy(_type, _name) [CFG_##_name] = { .name = #_name, .type = BLOBMSG_TYPE_ ## _type }
201 #define _cfg_policy_BOOL(_name) _cfg_policy(BOOL, _name)
202 #define _cfg_policy_U32(_name) _cfg_policy(INT32, _name)
203 #define _cfg_policy_I32(_name) _cfg_policy(INT32, _name)
204 #define _cfg_policy_ARRAY_CB(_name) _cfg_policy(ARRAY, _name)
205 #define _cfg_policy_STRING_CB(_name) _cfg_policy(STRING, _name)
206 #define _cfg(_type, _name) _cfg_policy_##_type(_name)
207         __config_items,
208 #undef _cfg
209 };
210 
211 static const struct cfg_item config_data[__CFG_MAX] = {
212 #define _cfg_data_BOOL(_name) .ptr.BOOL = &config._name
213 #define _cfg_data_U32(_name) .ptr.U32 = &config._name
214 #define _cfg_data_I32(_name) .ptr.I32 = &config._name
215 #define _cfg_data_ARRAY_CB(_name) .ptr.CB = { .set = config_set_##_name, .get = config_get_##_name }
216 #define _cfg_data_STRING_CB(_name) .ptr.CB = { .set = config_set_##_name, .get = config_get_##_name }
217 #define _cfg(_type, _name) [CFG_##_name] = { .type = CFG_##_type, _cfg_data_##_type(_name) }
218         __config_items,
219 #undef _cfg
220 };
221 
222 static int
223 usteer_ubus_get_config(struct ubus_context *ctx, struct ubus_object *obj,
224                       struct ubus_request_data *req, const char *method,
225                       struct blob_attr *msg)
226 {
227         int i;
228 
229         blob_buf_init(&b, 0);
230         for (i = 0; i < __CFG_MAX; i++) {
231                 switch(config_data[i].type) {
232                 case CFG_BOOL:
233                         blobmsg_add_u8(&b, config_policy[i].name,
234                                         *config_data[i].ptr.BOOL);
235                         break;
236                 case CFG_I32:
237                 case CFG_U32:
238                         blobmsg_add_u32(&b, config_policy[i].name,
239                                         *config_data[i].ptr.U32);
240                         break;
241                 case CFG_ARRAY_CB:
242                 case CFG_STRING_CB:
243                         config_data[i].ptr.CB.get(&b);
244                         break;
245                 }
246         }
247         ubus_send_reply(ctx, req, b.head);
248         return 0;
249 }
250 
251 static int
252 usteer_ubus_set_config(struct ubus_context *ctx, struct ubus_object *obj,
253                       struct ubus_request_data *req, const char *method,
254                       struct blob_attr *msg)
255 {
256         struct blob_attr *tb[__CFG_MAX];
257         int i;
258 
259         if (!strcmp(method, "set_config"))
260                 usteer_init_defaults();
261 
262         blobmsg_parse(config_policy, __CFG_MAX, tb, blob_data(msg), blob_len(msg));
263         for (i = 0; i < __CFG_MAX; i++) {
264                 switch(config_data[i].type) {
265                 case CFG_BOOL:
266                         if (!tb[i])
267                                 continue;
268 
269                         *config_data[i].ptr.BOOL = blobmsg_get_u8(tb[i]);
270                         break;
271                 case CFG_I32:
272                 case CFG_U32:
273                         if (!tb[i])
274                                 continue;
275 
276                         *config_data[i].ptr.U32 = blobmsg_get_u32(tb[i]);
277                         break;
278                 case CFG_ARRAY_CB:
279                 case CFG_STRING_CB:
280                         config_data[i].ptr.CB.set(tb[i]);
281                         break;
282                 }
283         }
284 
285         usteer_interface_init();
286 
287         return 0;
288 }
289 
290 void usteer_dump_node(struct blob_buf *buf, struct usteer_node *node)
291 {
292         void *c, *roam_events;
293 
294         c = blobmsg_open_table(buf, usteer_node_name(node));
295         blobmsg_printf(buf, "bssid", MAC_ADDR_FMT, MAC_ADDR_DATA(node->bssid));
296         blobmsg_add_u32(buf, "freq", node->freq);
297         blobmsg_add_u32(buf, "n_assoc", node->n_assoc);
298         blobmsg_add_u32(buf, "noise", node->noise);
299         blobmsg_add_u32(buf, "load", node->load);
300         blobmsg_add_u32(buf, "max_assoc", node->max_assoc);
301 
302         roam_events = blobmsg_open_table(buf, "roam_events");
303         blobmsg_add_u32(buf, "source", node->roam_events.source);
304         blobmsg_add_u32(buf, "target", node->roam_events.target);
305         blobmsg_close_table(buf, roam_events);
306 
307         if (node->rrm_nr)
308                 blobmsg_add_field(buf, BLOBMSG_TYPE_ARRAY, "rrm_nr",
309                                   blobmsg_data(node->rrm_nr),
310                                   blobmsg_data_len(node->rrm_nr));
311         if (node->node_info)
312                 blobmsg_add_field(buf, BLOBMSG_TYPE_TABLE, "node_info",
313                                   blob_data(node->node_info),
314                                   blob_len(node->node_info));
315 
316         blobmsg_close_table(buf, c);
317 }
318 
319 void usteer_dump_host(struct blob_buf *buf, struct usteer_remote_host *host)
320 {
321         void *c;
322 
323         c = blobmsg_open_table(buf, host->addr);
324         blobmsg_add_u32(buf, "id", (uint32_t)(uintptr_t)host->avl.key);
325         if (host->host_info)
326                 blobmsg_add_field(buf, BLOBMSG_TYPE_TABLE, "host_info",
327                                   blobmsg_data(host->host_info),
328                                   blobmsg_len(host->host_info));
329         blobmsg_close_table(buf, c);
330 }
331 
332 static int
333 usteer_ubus_local_info(struct ubus_context *ctx, struct ubus_object *obj,
334                       struct ubus_request_data *req, const char *method,
335                       struct blob_attr *msg)
336 {
337         struct usteer_node *node;
338 
339         blob_buf_init(&b, 0);
340 
341         for_each_local_node(node)
342                 usteer_dump_node(&b, node);
343 
344         ubus_send_reply(ctx, req, b.head);
345 
346         return 0;
347 }
348 
349 static int
350 usteer_ubus_remote_hosts(struct ubus_context *ctx, struct ubus_object *obj,
351                          struct ubus_request_data *req, const char *method,
352                          struct blob_attr *msg)
353 {
354         struct usteer_remote_host *host;
355 
356         blob_buf_init(&b, 0);
357 
358         avl_for_each_element(&remote_hosts, host, avl)
359                 usteer_dump_host(&b, host);
360 
361         ubus_send_reply(ctx, req, b.head);
362 
363         return 0;
364 }
365 
366 static int
367 usteer_ubus_remote_info(struct ubus_context *ctx, struct ubus_object *obj,
368                        struct ubus_request_data *req, const char *method,
369                        struct blob_attr *msg)
370 {
371         struct usteer_remote_node *rn;
372 
373         blob_buf_init(&b, 0);
374 
375         for_each_remote_node(rn)
376                 usteer_dump_node(&b, &rn->node);
377 
378         ubus_send_reply(ctx, req, b.head);
379 
380         return 0;
381 }
382 
383 static int
384 usteer_ubus_get_connected_clients(struct ubus_context *ctx, struct ubus_object *obj,
385                                   struct ubus_request_data *req, const char *method,
386                                   struct blob_attr *msg)
387 {
388         struct usteer_measurement_report *mr;
389         struct usteer_node *node;
390         struct sta_info *si;
391         void *n, *s, *t, *a;
392 
393         blob_buf_init(&b, 0);
394 
395         for_each_local_node(node) {
396                 n = blobmsg_open_table(&b, usteer_node_name(node));
397 
398                 list_for_each_entry(si, &node->sta_info, node_list) {
399                         if (si->connected != STA_CONNECTED)
400                                 continue;
401 
402                         s = blobmsg_open_table_mac(&b, si->sta->addr);
403                         blobmsg_add_u32(&b, "signal", si->signal);
404                         blobmsg_add_u64(&b, "created", si->created);
405                         blobmsg_add_u64(&b, "seen", si->seen);
406                         blobmsg_add_u64(&b, "last_connected", si->last_connected);
407 
408                         t = blobmsg_open_table(&b, "snr-kick");
409                         blobmsg_add_u32(&b, "seen-below", si->below_min_snr);
410                         blobmsg_close_table(&b, t);
411 
412                         t = blobmsg_open_table(&b, "load-kick");
413                         blobmsg_add_u32(&b, "count", si->kick_count);
414                         blobmsg_close_table(&b, t);
415 
416                         t = blobmsg_open_table(&b, "roam-state-machine");
417                         blobmsg_add_u32(&b, "tries", si->roam_tries);
418                         blobmsg_add_u64(&b, "event", si->roam_event);
419                         blobmsg_add_u64(&b, "kick", si->roam_kick);
420                         blobmsg_add_u64(&b, "scan_start", si->roam_scan_start);
421                         blobmsg_add_u64(&b, "scan_timeout_start", si->roam_scan_timeout_start);
422                         blobmsg_close_table(&b, t);
423 
424                         t = blobmsg_open_table(&b, "bss-transition-response");
425                         blobmsg_add_u32(&b, "status-code", si->bss_transition_response.status_code);
426                         blobmsg_add_u64(&b, "timestamp", si->bss_transition_response.timestamp);
427                         blobmsg_close_table(&b, t);
428 
429                         /* Beacon measurement modes */
430                         a = blobmsg_open_array(&b, "beacon-measurement-modes");
431                         if (usteer_sta_supports_beacon_measurement_mode(si, BEACON_MEASUREMENT_PASSIVE))
432                                 blobmsg_add_string(&b, "", "PASSIVE");
433                         if (usteer_sta_supports_beacon_measurement_mode(si, BEACON_MEASUREMENT_ACTIVE))
434                                 blobmsg_add_string(&b, "", "ACTIVE");
435                         if (usteer_sta_supports_beacon_measurement_mode(si, BEACON_MEASUREMENT_TABLE))
436                                 blobmsg_add_string(&b, "", "TABLE");
437                         blobmsg_close_array(&b, a);
438 
439                         /* Link-Measurement support */
440                         blobmsg_add_u8(&b, "link-measurement", usteer_sta_supports_link_measurement(si));
441 
442                         /* BSS-Transition support */
443                         blobmsg_add_u8(&b, "bss-transition-management", si->bss_transition);
444 
445                         /* Measurements */
446                         a = blobmsg_open_array(&b, "measurements");
447                         list_for_each_entry(mr, &si->sta->measurements, sta_list) {
448                                 t = blobmsg_open_table(&b, "");
449                                 blobmsg_add_string(&b, "node", usteer_node_name(mr->node));
450                                 blobmsg_add_u32(&b, "rcpi", mr->rcpi);
451                                 blobmsg_add_u32(&b, "rsni", mr->rsni);
452                                 blobmsg_add_u64(&b, "timestamp", mr->timestamp);
453                                 blobmsg_close_table(&b, t);
454                         }
455                         blobmsg_close_array(&b, a);
456 
457                         blobmsg_close_table(&b, s);
458                 }
459 
460                 blobmsg_close_table(&b, n);
461         }
462 
463         ubus_send_reply(ctx, req, b.head);
464 
465         return 0;
466 }
467 
468 enum {
469         NODE_DATA_NODE,
470         NODE_DATA_VALUES,
471         __NODE_DATA_MAX,
472 };
473 
474 static const struct blobmsg_policy set_node_data_policy[] = {
475         [NODE_DATA_NODE] = { "node", BLOBMSG_TYPE_STRING },
476         [NODE_DATA_VALUES] = { "data", BLOBMSG_TYPE_TABLE },
477 };
478 
479 static const struct blobmsg_policy del_node_data_policy[] = {
480         [NODE_DATA_NODE] = { "node", BLOBMSG_TYPE_STRING },
481         [NODE_DATA_VALUES] = { "names", BLOBMSG_TYPE_ARRAY },
482 };
483 
484 static void
485 usteer_update_kvlist_data(struct kvlist *kv, struct blob_attr *data,
486                           bool delete)
487 {
488         struct blob_attr *cur;
489         int rem;
490 
491         blobmsg_for_each_attr(cur, data, rem) {
492                 if (delete)
493                         kvlist_delete(kv, blobmsg_get_string(cur));
494                 else
495                         kvlist_set(kv, blobmsg_name(cur), cur);
496         }
497 }
498 
499 static void
500 usteer_update_kvlist_blob(struct blob_attr **dest, struct kvlist *kv)
501 {
502         struct blob_attr *val;
503         const char *name;
504 
505         blob_buf_init(&b, 0);
506         kvlist_for_each(kv, name, val)
507                 blobmsg_add_field(&b, blobmsg_type(val), name,
508                                   blobmsg_data(val), blobmsg_len(val));
509 
510         val = b.head;
511         if (!blobmsg_len(val))
512                 val = NULL;
513 
514         usteer_node_set_blob(dest, val);
515 }
516 
517 static int
518 usteer_ubus_update_node_data(struct ubus_context *ctx, struct ubus_object *obj,
519                              struct ubus_request_data *req, const char *method,
520                              struct blob_attr *msg)
521 {
522         const struct blobmsg_policy *policy;
523         struct blob_attr *tb[__NODE_DATA_MAX];
524         struct usteer_local_node *ln;
525         struct blob_attr *val;
526         const char *name;
527         bool delete;
528 
529         delete = !strncmp(method, "del", 3);
530         policy = delete ? del_node_data_policy : set_node_data_policy;
531 
532         blobmsg_parse(policy, __NODE_DATA_MAX, tb, blob_data(msg), blob_len(msg));
533         if (!tb[NODE_DATA_NODE] || !tb[NODE_DATA_VALUES])
534                 return UBUS_STATUS_INVALID_ARGUMENT;
535 
536         name = blobmsg_get_string(tb[NODE_DATA_NODE]);
537         val = tb[NODE_DATA_VALUES];
538         if (delete && blobmsg_check_array(val, BLOBMSG_TYPE_STRING) < 0)
539                 return UBUS_STATUS_INVALID_ARGUMENT;
540 
541         if (strcmp(name, "*") != 0) {
542                 ln = avl_find_element(&local_nodes, name, ln, node.avl);
543                 if (!ln)
544                         return UBUS_STATUS_NOT_FOUND;
545 
546                 usteer_update_kvlist_data(&ln->node_info, val, delete);
547                 usteer_update_kvlist_blob(&ln->node.node_info, &ln->node_info);
548 
549                 return 0;
550         }
551 
552         usteer_update_kvlist_data(&host_info, val, delete);
553         usteer_update_kvlist_blob(&host_info_blob, &host_info);
554 
555         return 0;
556 }
557 
558 static const struct ubus_method usteer_methods[] = {
559         UBUS_METHOD_NOARG("local_info", usteer_ubus_local_info),
560         UBUS_METHOD_NOARG("remote_hosts", usteer_ubus_remote_hosts),
561         UBUS_METHOD_NOARG("remote_info", usteer_ubus_remote_info),
562         UBUS_METHOD_NOARG("connected_clients", usteer_ubus_get_connected_clients),
563         UBUS_METHOD_NOARG("get_clients", usteer_ubus_get_clients),
564         UBUS_METHOD("get_client_info", usteer_ubus_get_client_info, client_arg),
565         UBUS_METHOD_NOARG("get_config", usteer_ubus_get_config),
566         UBUS_METHOD("set_config", usteer_ubus_set_config, config_policy),
567         UBUS_METHOD("update_config", usteer_ubus_set_config, config_policy),
568         UBUS_METHOD("set_node_data", usteer_ubus_update_node_data, set_node_data_policy),
569         UBUS_METHOD("delete_node_data", usteer_ubus_update_node_data, del_node_data_policy),
570 };
571 
572 static struct ubus_object_type usteer_obj_type =
573         UBUS_OBJECT_TYPE("usteer", usteer_methods);
574 
575 struct ubus_object usteer_obj = {
576         .name = "usteer",
577         .type = &usteer_obj_type,
578         .methods = usteer_methods,
579         .n_methods = ARRAY_SIZE(usteer_methods),
580 };
581 
582 static bool
583 usteer_add_nr_entry(struct usteer_node *ln, struct usteer_node *node)
584 {
585         struct blobmsg_policy policy[3] = {
586                 { .type = BLOBMSG_TYPE_STRING },
587                 { .type = BLOBMSG_TYPE_STRING },
588                 { .type = BLOBMSG_TYPE_STRING },
589         };
590         struct blob_attr *tb[3];
591 
592         if (!node->rrm_nr)
593                 return false;
594 
595         if (strcmp(ln->ssid, node->ssid) != 0)
596                 return false;
597 
598         if (!usteer_policy_node_below_max_assoc(node))
599                 return false;
600 
601         blobmsg_parse_array(policy, ARRAY_SIZE(tb), tb,
602                             blobmsg_data(node->rrm_nr),
603                             blobmsg_data_len(node->rrm_nr));
604         if (!tb[2])
605                 return false;
606 
607         blobmsg_add_field(&b, BLOBMSG_TYPE_STRING, "",
608                           blobmsg_data(tb[2]),
609                           blobmsg_data_len(tb[2]));
610         
611         return true;
612 }
613 
614 static void
615 usteer_ubus_disassoc_add_neighbor(struct sta_info *si, struct usteer_node *node)
616 {
617         void *c;
618 
619         c = blobmsg_open_array(&b, "neighbors");
620         usteer_add_nr_entry(si->node, node);
621         blobmsg_close_array(&b, c);
622 }
623 
624 static void
625 usteer_ubus_disassoc_add_neighbors(struct sta_info *si)
626 {
627         struct usteer_node *node, *last_remote_neighbor = NULL;
628         int i = 0;
629         void *c;
630 
631         c = blobmsg_open_array(&b, "neighbors");
632         for_each_local_node(node) {
633                 if (i >= config.max_neighbor_reports)
634                         break;
635                 if (si->node == node)
636                         continue;
637                 if (usteer_add_nr_entry(si->node, node))
638                         i++;
639         }
640 
641         while (i < config.max_neighbor_reports) {
642                 node = usteer_node_get_next_neighbor(si->node, last_remote_neighbor);
643                 if (!node) {
644                         /* No more nodes available */
645                         break;
646                 }
647 
648                 last_remote_neighbor = node;
649                 if (usteer_add_nr_entry(si->node, node))
650                         i++;
651         }
652         blobmsg_close_array(&b, c);
653 }
654 
655 int usteer_ubus_bss_transition_request(struct sta_info *si,
656                                        uint8_t dialog_token,
657                                        bool disassoc_imminent,
658                                        bool abridged,
659                                        uint8_t validity_period,
660                                        struct usteer_node *target_node)
661 {
662         struct usteer_local_node *ln = container_of(si->node, struct usteer_local_node, node);
663 
664         blob_buf_init(&b, 0);
665         blobmsg_printf(&b, "addr", MAC_ADDR_FMT, MAC_ADDR_DATA(si->sta->addr));
666         blobmsg_add_u32(&b, "dialog_token", dialog_token);
667         blobmsg_add_u8(&b, "disassociation_imminent", disassoc_imminent);
668         blobmsg_add_u8(&b, "abridged", abridged);
669         blobmsg_add_u32(&b, "validity_period", validity_period);
670         if (!target_node) {
671                 usteer_ubus_disassoc_add_neighbors(si);
672         } else {
673                 usteer_ubus_disassoc_add_neighbor(si, target_node);
674         }
675         return ubus_invoke(ubus_ctx, ln->obj_id, "bss_transition_request", b.head, NULL, 0, 100);
676 }
677 
678 int usteer_ubus_band_steering_request(struct sta_info *si)
679 {
680         struct usteer_local_node *ln = container_of(si->node, struct usteer_local_node, node);
681         struct usteer_node *node;
682         void *c;
683 
684         blob_buf_init(&b, 0);
685         blobmsg_printf(&b, "addr", MAC_ADDR_FMT, MAC_ADDR_DATA(si->sta->addr));
686         blobmsg_add_u32(&b, "dialog_token", 0);
687         blobmsg_add_u8(&b, "disassociation_imminent", false);
688         blobmsg_add_u8(&b, "abridged", false);
689         blobmsg_add_u32(&b, "validity_period", 100);
690 
691         c = blobmsg_open_array(&b, "neighbors");
692         for_each_local_node(node) {
693                 if (!usteer_band_steering_is_target(ln, node))
694                         continue;
695         
696                 usteer_add_nr_entry(si->node, node);
697         }
698         blobmsg_close_array(&b, c);
699 
700         return ubus_invoke(ubus_ctx, ln->obj_id, "bss_transition_request", b.head, NULL, 0, 100);
701 }
702 
703 int usteer_ubus_trigger_link_measurement(struct sta_info *si)
704 {
705         struct usteer_local_node *ln = container_of(si->node, struct usteer_local_node, node);
706 
707         if (!usteer_sta_supports_link_measurement(si))
708                 return 0;
709 
710         blob_buf_init(&b, 0);
711         blobmsg_printf(&b, "addr", MAC_ADDR_FMT, MAC_ADDR_DATA(si->sta->addr));
712         blobmsg_add_u32(&b, "tx-power-used", 5);
713         blobmsg_add_u32(&b, "tx-power-max", 10);
714         return ubus_invoke(ubus_ctx, ln->obj_id, "link_measurement_req", b.head, NULL, 0, 100);
715 }
716 
717 int usteer_ubus_trigger_client_scan(struct sta_info *si)
718 {
719         struct usteer_local_node *ln = container_of(si->node, struct usteer_local_node, node);
720 
721         if (!usteer_sta_supports_beacon_measurement_mode(si, BEACON_MEASUREMENT_ACTIVE)) {
722                 MSG(DEBUG, "STA does not support beacon measurement sta=" MAC_ADDR_FMT "\n", MAC_ADDR_DATA(si->sta->addr));
723                 return 0;
724         }
725 
726         si->scan_band = !si->scan_band;
727 
728         blob_buf_init(&b, 0);
729         blobmsg_printf(&b, "addr", MAC_ADDR_FMT, MAC_ADDR_DATA(si->sta->addr));
730         blobmsg_add_string(&b, "ssid", si->node->ssid);
731         blobmsg_add_u32(&b, "mode", BEACON_MEASUREMENT_ACTIVE);
732         blobmsg_add_u32(&b, "duration", config.roam_scan_interval / 100);
733         blobmsg_add_u32(&b, "channel", 0);
734         blobmsg_add_u32(&b, "op_class", si->scan_band ? 1 : 12);
735         return ubus_invoke(ubus_ctx, ln->obj_id, "rrm_beacon_req", b.head, NULL, 0, 100);
736 }
737 
738 void usteer_ubus_kick_client(struct sta_info *si)
739 {
740         struct usteer_local_node *ln = container_of(si->node, struct usteer_local_node, node);
741 
742         blob_buf_init(&b, 0);
743         blobmsg_printf(&b, "addr", MAC_ADDR_FMT, MAC_ADDR_DATA(si->sta->addr));
744         blobmsg_add_u32(&b, "reason", config.load_kick_reason_code);
745         blobmsg_add_u8(&b, "deauth", 1);
746         ubus_invoke(ubus_ctx, ln->obj_id, "del_client", b.head, NULL, 0, 100);
747         usteer_sta_disconnected(si);
748         si->roam_kick = current_time;
749 }
750 
751 void usteer_ubus_init(struct ubus_context *ctx)
752 {
753         ubus_add_object(ctx, &usteer_obj);
754 }
755 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt