• 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_string(buf, "ssid", node->ssid);
297         blobmsg_add_u32(buf, "freq", node->freq);
298         blobmsg_add_u32(buf, "n_assoc", node->n_assoc);
299         blobmsg_add_u32(buf, "noise", node->noise);
300         blobmsg_add_u32(buf, "load", node->load);
301         blobmsg_add_u32(buf, "max_assoc", node->max_assoc);
302 
303         roam_events = blobmsg_open_table(buf, "roam_events");
304         blobmsg_add_u32(buf, "source", node->roam_events.source);
305         blobmsg_add_u32(buf, "target", node->roam_events.target);
306         blobmsg_close_table(buf, roam_events);
307 
308         if (node->rrm_nr)
309                 blobmsg_add_field(buf, BLOBMSG_TYPE_ARRAY, "rrm_nr",
310                                   blobmsg_data(node->rrm_nr),
311                                   blobmsg_data_len(node->rrm_nr));
312         if (node->node_info)
313                 blobmsg_add_field(buf, BLOBMSG_TYPE_TABLE, "node_info",
314                                   blob_data(node->node_info),
315                                   blob_len(node->node_info));
316 
317         blobmsg_close_table(buf, c);
318 }
319 
320 void usteer_dump_host(struct blob_buf *buf, struct usteer_remote_host *host)
321 {
322         void *c;
323 
324         c = blobmsg_open_table(buf, host->addr);
325         blobmsg_add_u32(buf, "id", (uint32_t)(uintptr_t)host->avl.key);
326         if (host->host_info)
327                 blobmsg_add_field(buf, BLOBMSG_TYPE_TABLE, "host_info",
328                                   blobmsg_data(host->host_info),
329                                   blobmsg_len(host->host_info));
330         blobmsg_close_table(buf, c);
331 }
332 
333 static int
334 usteer_ubus_local_info(struct ubus_context *ctx, struct ubus_object *obj,
335                       struct ubus_request_data *req, const char *method,
336                       struct blob_attr *msg)
337 {
338         struct usteer_node *node;
339 
340         blob_buf_init(&b, 0);
341 
342         for_each_local_node(node)
343                 usteer_dump_node(&b, node);
344 
345         ubus_send_reply(ctx, req, b.head);
346 
347         return 0;
348 }
349 
350 static int
351 usteer_ubus_remote_hosts(struct ubus_context *ctx, struct ubus_object *obj,
352                          struct ubus_request_data *req, const char *method,
353                          struct blob_attr *msg)
354 {
355         struct usteer_remote_host *host;
356 
357         blob_buf_init(&b, 0);
358 
359         avl_for_each_element(&remote_hosts, host, avl)
360                 usteer_dump_host(&b, host);
361 
362         ubus_send_reply(ctx, req, b.head);
363 
364         return 0;
365 }
366 
367 static int
368 usteer_ubus_remote_info(struct ubus_context *ctx, struct ubus_object *obj,
369                        struct ubus_request_data *req, const char *method,
370                        struct blob_attr *msg)
371 {
372         struct usteer_remote_node *rn;
373 
374         blob_buf_init(&b, 0);
375 
376         for_each_remote_node(rn)
377                 usteer_dump_node(&b, &rn->node);
378 
379         ubus_send_reply(ctx, req, b.head);
380 
381         return 0;
382 }
383 
384 static const char *usteer_get_roam_sm_name(enum roam_trigger_state state)
385 {
386         switch (state) {
387                 case ROAM_TRIGGER_IDLE:
388                         return "ROAM_TRIGGER_IDLE";
389                 case ROAM_TRIGGER_SCAN:
390                         return "ROAM_TRIGGER_SCAN";
391                 case ROAM_TRIGGER_SCAN_DONE:
392                         return "ROAM_TRIGGER_SCAN_DONE";
393         }
394         return "N/A";
395 }
396 
397 static int
398 usteer_ubus_get_connected_clients(struct ubus_context *ctx, struct ubus_object *obj,
399                                   struct ubus_request_data *req, const char *method,
400                                   struct blob_attr *msg)
401 {
402         struct usteer_measurement_report *mr;
403         struct usteer_node *node;
404         struct sta_info *si;
405         void *n, *s, *t, *a;
406 
407         blob_buf_init(&b, 0);
408 
409         for_each_local_node(node) {
410                 n = blobmsg_open_table(&b, usteer_node_name(node));
411 
412                 list_for_each_entry(si, &node->sta_info, node_list) {
413                         if (si->connected != STA_CONNECTED)
414                                 continue;
415 
416                         s = blobmsg_open_table_mac(&b, si->sta->addr);
417                         blobmsg_add_u32(&b, "signal", si->signal);
418                         blobmsg_add_u64(&b, "created", current_time - si->created);
419                         blobmsg_add_u64(&b, "connected", current_time - si->connected_since);
420 
421                         t = blobmsg_open_table(&b, "snr-kick");
422                         blobmsg_add_u32(&b, "seen-below", si->below_min_snr);
423                         blobmsg_close_table(&b, t);
424 
425                         t = blobmsg_open_table(&b, "roam-state-machine");
426                         blobmsg_add_string(&b, "state",usteer_get_roam_sm_name(si->roam_state));
427                         blobmsg_add_u32(&b, "tries", si->roam_tries);
428                         blobmsg_add_u64(&b, "event", si->roam_event ? current_time - si->roam_event : 0);
429                         blobmsg_add_u32(&b, "kick-count", si->kick_count);
430                         blobmsg_add_u64(&b, "last-kick", si->roam_kick ? current_time - si->roam_kick : 0);
431                         blobmsg_add_u64(&b, "scan_start", si->roam_scan_start ? current_time - si->roam_scan_start : 0);
432                         blobmsg_add_u64(&b, "scan_timeout_start", si->roam_scan_timeout_start ? current_time - si->roam_scan_timeout_start : 0);
433                         blobmsg_close_table(&b, t);
434 
435                         t = blobmsg_open_table(&b, "bss-transition-response");
436                         blobmsg_add_u32(&b, "status-code", si->bss_transition_response.status_code);
437                         blobmsg_add_u64(&b, "age", si->bss_transition_response.timestamp ? current_time - si->bss_transition_response.timestamp : 0);
438                         blobmsg_close_table(&b, t);
439 
440                         /* Beacon measurement modes */
441                         a = blobmsg_open_array(&b, "beacon-measurement-modes");
442                         if (usteer_sta_supports_beacon_measurement_mode(si, BEACON_MEASUREMENT_PASSIVE))
443                                 blobmsg_add_string(&b, "", "PASSIVE");
444                         if (usteer_sta_supports_beacon_measurement_mode(si, BEACON_MEASUREMENT_ACTIVE))
445                                 blobmsg_add_string(&b, "", "ACTIVE");
446                         if (usteer_sta_supports_beacon_measurement_mode(si, BEACON_MEASUREMENT_TABLE))
447                                 blobmsg_add_string(&b, "", "TABLE");
448                         blobmsg_close_array(&b, a);
449 
450                         /* Link-Measurement support */
451                         blobmsg_add_u8(&b, "link-measurement", usteer_sta_supports_link_measurement(si));
452 
453                         /* BSS-Transition support */
454                         blobmsg_add_u8(&b, "bss-transition-management", si->bss_transition);
455 
456                         /* MBO support */
457                         blobmsg_add_u8(&b, "multi-band-operation", si->mbo);
458 
459                         /* Measurements */
460                         a = blobmsg_open_array(&b, "measurements");
461                         list_for_each_entry(mr, &si->sta->measurements, sta_list) {
462                                 t = blobmsg_open_table(&b, "");
463                                 blobmsg_add_string(&b, "node", usteer_node_name(mr->node));
464                                 blobmsg_add_u32(&b, "rcpi", mr->rcpi);
465                                 blobmsg_add_u32(&b, "rsni", mr->rsni);
466                                 blobmsg_add_u32(&b, "rssi", usteer_measurement_get_rssi(mr));
467                                 blobmsg_add_u64(&b, "age", current_time - mr->timestamp);
468                                 blobmsg_close_table(&b, t);
469                         }
470                         blobmsg_close_array(&b, a);
471 
472                         blobmsg_close_table(&b, s);
473                 }
474 
475                 blobmsg_close_table(&b, n);
476         }
477 
478         ubus_send_reply(ctx, req, b.head);
479 
480         return 0;
481 }
482 
483 enum {
484         NODE_DATA_NODE,
485         NODE_DATA_VALUES,
486         __NODE_DATA_MAX,
487 };
488 
489 static const struct blobmsg_policy set_node_data_policy[] = {
490         [NODE_DATA_NODE] = { "node", BLOBMSG_TYPE_STRING },
491         [NODE_DATA_VALUES] = { "data", BLOBMSG_TYPE_TABLE },
492 };
493 
494 static const struct blobmsg_policy del_node_data_policy[] = {
495         [NODE_DATA_NODE] = { "node", BLOBMSG_TYPE_STRING },
496         [NODE_DATA_VALUES] = { "names", BLOBMSG_TYPE_ARRAY },
497 };
498 
499 static void
500 usteer_update_kvlist_data(struct kvlist *kv, struct blob_attr *data,
501                           bool delete)
502 {
503         struct blob_attr *cur;
504         int rem;
505 
506         blobmsg_for_each_attr(cur, data, rem) {
507                 if (delete)
508                         kvlist_delete(kv, blobmsg_get_string(cur));
509                 else
510                         kvlist_set(kv, blobmsg_name(cur), cur);
511         }
512 }
513 
514 static void
515 usteer_update_kvlist_blob(struct blob_attr **dest, struct kvlist *kv)
516 {
517         struct blob_attr *val;
518         const char *name;
519 
520         blob_buf_init(&b, 0);
521         kvlist_for_each(kv, name, val)
522                 blobmsg_add_field(&b, blobmsg_type(val), name,
523                                   blobmsg_data(val), blobmsg_len(val));
524 
525         val = b.head;
526         if (!blobmsg_len(val))
527                 val = NULL;
528 
529         usteer_node_set_blob(dest, val);
530 }
531 
532 static int
533 usteer_ubus_update_node_data(struct ubus_context *ctx, struct ubus_object *obj,
534                              struct ubus_request_data *req, const char *method,
535                              struct blob_attr *msg)
536 {
537         const struct blobmsg_policy *policy;
538         struct blob_attr *tb[__NODE_DATA_MAX];
539         struct usteer_local_node *ln;
540         struct blob_attr *val;
541         const char *name;
542         bool delete;
543 
544         delete = !strncmp(method, "del", 3);
545         policy = delete ? del_node_data_policy : set_node_data_policy;
546 
547         blobmsg_parse(policy, __NODE_DATA_MAX, tb, blob_data(msg), blob_len(msg));
548         if (!tb[NODE_DATA_NODE] || !tb[NODE_DATA_VALUES])
549                 return UBUS_STATUS_INVALID_ARGUMENT;
550 
551         name = blobmsg_get_string(tb[NODE_DATA_NODE]);
552         val = tb[NODE_DATA_VALUES];
553         if (delete && blobmsg_check_array(val, BLOBMSG_TYPE_STRING) < 0)
554                 return UBUS_STATUS_INVALID_ARGUMENT;
555 
556         if (strcmp(name, "*") != 0) {
557                 ln = avl_find_element(&local_nodes, name, ln, node.avl);
558                 if (!ln)
559                         return UBUS_STATUS_NOT_FOUND;
560 
561                 usteer_update_kvlist_data(&ln->node_info, val, delete);
562                 usteer_update_kvlist_blob(&ln->node.node_info, &ln->node_info);
563 
564                 return 0;
565         }
566 
567         usteer_update_kvlist_data(&host_info, val, delete);
568         usteer_update_kvlist_blob(&host_info_blob, &host_info);
569 
570         return 0;
571 }
572 
573 static const struct ubus_method usteer_methods[] = {
574         UBUS_METHOD_NOARG("local_info", usteer_ubus_local_info),
575         UBUS_METHOD_NOARG("remote_hosts", usteer_ubus_remote_hosts),
576         UBUS_METHOD_NOARG("remote_info", usteer_ubus_remote_info),
577         UBUS_METHOD_NOARG("connected_clients", usteer_ubus_get_connected_clients),
578         UBUS_METHOD_NOARG("get_clients", usteer_ubus_get_clients),
579         UBUS_METHOD("get_client_info", usteer_ubus_get_client_info, client_arg),
580         UBUS_METHOD_NOARG("get_config", usteer_ubus_get_config),
581         UBUS_METHOD("set_config", usteer_ubus_set_config, config_policy),
582         UBUS_METHOD("update_config", usteer_ubus_set_config, config_policy),
583         UBUS_METHOD("set_node_data", usteer_ubus_update_node_data, set_node_data_policy),
584         UBUS_METHOD("delete_node_data", usteer_ubus_update_node_data, del_node_data_policy),
585 };
586 
587 static struct ubus_object_type usteer_obj_type =
588         UBUS_OBJECT_TYPE("usteer", usteer_methods);
589 
590 struct ubus_object usteer_obj = {
591         .name = "usteer",
592         .type = &usteer_obj_type,
593         .methods = usteer_methods,
594         .n_methods = ARRAY_SIZE(usteer_methods),
595 };
596 
597 static bool
598 usteer_add_nr_entry(struct usteer_node *ln, struct usteer_node *node)
599 {
600         struct blobmsg_policy policy[3] = {
601                 { .type = BLOBMSG_TYPE_STRING },
602                 { .type = BLOBMSG_TYPE_STRING },
603                 { .type = BLOBMSG_TYPE_STRING },
604         };
605         struct blob_attr *tb[3];
606 
607         if (!node->rrm_nr)
608                 return false;
609 
610         if (strcmp(ln->ssid, node->ssid) != 0)
611                 return false;
612 
613         if (!usteer_policy_node_below_max_assoc(node))
614                 return false;
615 
616         blobmsg_parse_array(policy, ARRAY_SIZE(tb), tb,
617                             blobmsg_data(node->rrm_nr),
618                             blobmsg_data_len(node->rrm_nr));
619         if (!tb[2])
620                 return false;
621 
622         blobmsg_add_field(&b, BLOBMSG_TYPE_STRING, "",
623                           blobmsg_data(tb[2]),
624                           blobmsg_data_len(tb[2]));
625         
626         return true;
627 }
628 
629 static void
630 usteer_ubus_disassoc_add_neighbor(struct sta_info *si, struct usteer_node *node)
631 {
632         void *c;
633 
634         c = blobmsg_open_array(&b, "neighbors");
635         usteer_add_nr_entry(si->node, node);
636         blobmsg_close_array(&b, c);
637 }
638 
639 static void
640 usteer_ubus_disassoc_add_neighbors(struct sta_info *si)
641 {
642         struct usteer_node *node, *last_remote_neighbor = NULL;
643         int i = 0;
644         void *c;
645 
646         c = blobmsg_open_array(&b, "neighbors");
647         for_each_local_node(node) {
648                 if (i >= config.max_neighbor_reports)
649                         break;
650                 if (si->node == node)
651                         continue;
652                 if (usteer_add_nr_entry(si->node, node))
653                         i++;
654         }
655 
656         while (i < config.max_neighbor_reports) {
657                 node = usteer_node_get_next_neighbor(si->node, last_remote_neighbor);
658                 if (!node) {
659                         /* No more nodes available */
660                         break;
661                 }
662 
663                 last_remote_neighbor = node;
664                 if (usteer_add_nr_entry(si->node, node))
665                         i++;
666         }
667         blobmsg_close_array(&b, c);
668 }
669 
670 int usteer_ubus_bss_transition_request(struct sta_info *si,
671                                        uint8_t dialog_token,
672                                        bool disassoc_imminent,
673                                        bool abridged,
674                                        uint8_t validity_period,
675                                        struct usteer_node *target_node)
676 {
677         struct usteer_local_node *ln = container_of(si->node, struct usteer_local_node, node);
678 
679         blob_buf_init(&b, 0);
680         blobmsg_printf(&b, "addr", MAC_ADDR_FMT, MAC_ADDR_DATA(si->sta->addr));
681         blobmsg_add_u32(&b, "dialog_token", dialog_token);
682         blobmsg_add_u8(&b, "disassociation_imminent", disassoc_imminent);
683         blobmsg_add_u8(&b, "abridged", abridged);
684         blobmsg_add_u32(&b, "validity_period", validity_period);
685         if (!target_node) {
686                 usteer_ubus_disassoc_add_neighbors(si);
687         } else {
688                 usteer_ubus_disassoc_add_neighbor(si, target_node);
689         }
690         return ubus_invoke(ubus_ctx, ln->obj_id, "bss_transition_request", b.head, NULL, 0, 100);
691 }
692 
693 int usteer_ubus_band_steering_request(struct sta_info *si)
694 {
695         struct usteer_local_node *ln = container_of(si->node, struct usteer_local_node, node);
696         struct usteer_node *node;
697         void *c;
698 
699         blob_buf_init(&b, 0);
700         blobmsg_printf(&b, "addr", MAC_ADDR_FMT, MAC_ADDR_DATA(si->sta->addr));
701         blobmsg_add_u32(&b, "dialog_token", 0);
702         blobmsg_add_u8(&b, "disassociation_imminent", false);
703         blobmsg_add_u8(&b, "abridged", false);
704         blobmsg_add_u32(&b, "validity_period", 100);
705 
706         c = blobmsg_open_array(&b, "neighbors");
707         for_each_local_node(node) {
708                 if (!usteer_band_steering_is_target(ln, node))
709                         continue;
710         
711                 usteer_add_nr_entry(si->node, node);
712         }
713         blobmsg_close_array(&b, c);
714 
715         return ubus_invoke(ubus_ctx, ln->obj_id, "bss_transition_request", b.head, NULL, 0, 100);
716 }
717 
718 int usteer_ubus_trigger_link_measurement(struct sta_info *si)
719 {
720         struct usteer_local_node *ln = container_of(si->node, struct usteer_local_node, node);
721 
722         if (!usteer_sta_supports_link_measurement(si))
723                 return 0;
724 
725         blob_buf_init(&b, 0);
726         blobmsg_printf(&b, "addr", MAC_ADDR_FMT, MAC_ADDR_DATA(si->sta->addr));
727         blobmsg_add_u32(&b, "tx-power-used", 5);
728         blobmsg_add_u32(&b, "tx-power-max", 10);
729         return ubus_invoke(ubus_ctx, ln->obj_id, "link_measurement_req", b.head, NULL, 0, 100);
730 }
731 
732 int usteer_ubus_trigger_client_scan(struct sta_info *si)
733 {
734         struct usteer_local_node *ln = container_of(si->node, struct usteer_local_node, node);
735 
736         if (!usteer_sta_supports_beacon_measurement_mode(si, BEACON_MEASUREMENT_ACTIVE)) {
737                 MSG(DEBUG, "STA does not support beacon measurement sta=" MAC_ADDR_FMT "\n", MAC_ADDR_DATA(si->sta->addr));
738                 return 0;
739         }
740 
741         si->scan_band = !si->scan_band;
742 
743         blob_buf_init(&b, 0);
744         blobmsg_printf(&b, "addr", MAC_ADDR_FMT, MAC_ADDR_DATA(si->sta->addr));
745         blobmsg_add_string(&b, "ssid", si->node->ssid);
746         blobmsg_add_u32(&b, "mode", BEACON_MEASUREMENT_ACTIVE);
747         blobmsg_add_u32(&b, "duration", config.roam_scan_interval / 100);
748         blobmsg_add_u32(&b, "channel", 0);
749         blobmsg_add_u32(&b, "op_class", si->scan_band ? 1 : 12);
750         return ubus_invoke(ubus_ctx, ln->obj_id, "rrm_beacon_req", b.head, NULL, 0, 100);
751 }
752 
753 void usteer_ubus_kick_client(struct sta_info *si)
754 {
755         struct usteer_local_node *ln = container_of(si->node, struct usteer_local_node, node);
756 
757         blob_buf_init(&b, 0);
758         blobmsg_printf(&b, "addr", MAC_ADDR_FMT, MAC_ADDR_DATA(si->sta->addr));
759         blobmsg_add_u32(&b, "reason", config.load_kick_reason_code);
760         blobmsg_add_u8(&b, "deauth", 1);
761         ubus_invoke(ubus_ctx, ln->obj_id, "del_client", b.head, NULL, 0, 100);
762         usteer_sta_disconnected(si);
763         si->kick_count++;
764         si->roam_kick = current_time;
765 }
766 
767 void usteer_ubus_init(struct ubus_context *ctx)
768 {
769         ubus_add_object(ctx, &usteer_obj);
770 }
771 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt