Newer
Older
/*
* config.c - controller configuration handling
*
* Copyright (C) 2020 IOPSYS Software Solutions AB. All rights reserved.
*
* Author: anjan.chanda@iopsys.eu
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <json-c/json.h>
#include <libubox/blobmsg.h>
#include <libubox/blobmsg_json.h>
#include <libubox/uloop.h>
#include <libubox/ustream.h>
#include <libubox/utils.h>
#include <libubus.h>
#include <uci.h>
#include "debug.h"
#include "utils.h"
#include "config.h"
#include "cntlr.h"
#define CONFIG_DEFAULT_RCPI_TH_5G 86
#define CONFIG_DEFAULT_RCPI_TH_2G 70
#define list_copy(a, b, type) \
({ \
typeof(type *) ____ptr, ____tmp; \
list_for_each_entry_safe(____ptr, ____tmp, a, list) { \
list_del(&____ptr->list); \
list_add_tail(&____ptr->list, b); \
} \
})
#define list_memcmp(a, b, type, offset) \
({ \
int z = 0; \
typeof(type *) ____ptr, ____p; \
____p = list_first_entry(a, type, list); \
list_for_each_entry(____ptr, b, list) { \
if (memcmp(____p, ____ptr, sizeof(type) - offset)) { \
z = 1; \
break; \
} \
____p = list_entry(____p->list.next, type, list); \
} \
z; \
})
#define list_policy_memcmp(c, d, t, o) \
({ \
int z = 0; \
typeof(t *) ____d, ____c; \
____c = list_first_entry(c, t, list); \
list_for_each_entry(____d, d, list) { \
if (memcmp(____c, ____d, sizeof(t) - o)) { \
z = 1; \
____d->is_policy_diff = 1; \
} else { \
if (list_memcmp(&____d->radiolist, \
&____c->radiolist, struct radio_policy, \
(sizeof(struct radio_policy) - \
offsetof(struct radio_policy, list)))) { \
z = 1; \
____d->is_policy_diff = 1; \
} \
____c = list_entry(____c->list.next, t, list); \
} \
z; \
})
#define list_for_multiple_entry(pos, pos1, head, head1, field, field1) \
for (pos = list_first_entry(head, __typeof__(*pos), field), \
pos1 = list_first_entry(head1, __typeof__(*pos1), field1); \
(&pos->field != (head)) && (&pos1->field1 != (head1)); \
pos = list_entry(pos->field.next, __typeof__(*pos), field), \
pos1 = list_entry(pos1->field1.next, __typeof__(*pos1), field1))
static int clean_agentlist(struct node_policy *p)
static int clean_steer_btm_excl(struct node_policy *p)
{
struct stax *n, *tmp;
list_for_each_entry_safe(n, tmp, &p->btmsteer_exlist, list) {
list_del(&n->list);
free(n);
}
return 0;
}
static int clean_steer_excl(struct node_policy *p)
{
struct stax *n, *tmp;
list_for_each_entry_safe(n, tmp, &p->steer_exlist, list) {
list_del(&n->list);
free(n);
}
return 0;
}
int clean_agent_policies(struct controller_config *cfg)
{
struct node_policy *p, *tmp;
list_for_each_entry_safe(p, tmp, &cfg->nodelist, list) {
clean_steer_btm_excl(p);
clean_steer_excl(p);
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
list_del(&p->list);
free(p);
}
return 0;
}
int clean_bridgelist(struct controller_config *cfg)
{
struct netif_vlan *p, *tmp;
list_for_each_entry_safe(p, tmp, &cfg->vlanlist, list) {
list_del(&p->list);
free(p);
}
return 0;
}
int clean_credslist(struct list_head *credslist)
{
struct iface_credential *p, *tmp;
list_for_each_entry_safe(p, tmp, credslist, list) {
list_del(&p->list);
free(p);
}
return 0;
}
int clean_vlanlist(struct list_head *vlanlist)
{
struct netif_vlan *p, *tmp;
list_for_each_entry_safe(p, tmp, vlanlist, list) {
list_del(&p->list);
free(p);
}
return 0;
}
static void stax_add_entry(struct list_head *h, char *sta_macstr)
{
struct stax *n;
n = calloc(1, sizeof(struct stax));
if (n) {
snprintf(n->macstring, 18, "%s", sta_macstr);
list_add(&n->list, h);
}
}
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
struct uci_package *uci_load_pkg(struct uci_context **ctx, const char *config)
{
struct uci_package *pkg;
if (!*ctx) {
*ctx = uci_alloc_context();
if (!*ctx)
return NULL;
}
if (uci_load(*ctx, config, &pkg) != UCI_OK) {
free(*ctx);
return NULL;
}
return pkg;
}
int set_value(struct uci_context *ctx, struct uci_package *pkg,
struct uci_section *section, const char *key,
const char *value, enum uci_option_type type)
{
struct uci_ptr ptr = {0};
ptr.p = pkg;
ptr.s = section;
ptr.option = key;
ptr.value = value;
if (type == UCI_TYPE_STRING)
return uci_set(ctx, &ptr);
if (type == UCI_TYPE_LIST)
return uci_add_list(ctx, &ptr);
return -1;
}
int set_value_by_string(const char *package, const char *section,
const char *key, const char *value, enum uci_option_type type)
{
struct uci_ptr ptr = {0};
struct uci_context *ctx;
ctx = uci_alloc_context();
if (!ctx)
return -1;
ptr.package = package;
ptr.section = section;
ptr.option = key;
ptr.value = value;
if (type == UCI_TYPE_STRING)
rv = uci_set(ctx, &ptr);
if (type == UCI_TYPE_LIST)
rv = uci_add_list(ctx, &ptr);
uci_commit(ctx, &ptr.p, false);
uci_free_context(ctx);
return rv;
}
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
bool uci_set_option(char *package_name, char *section_type,
char *search_key, char *search_val,
char *option, char *value)
{
struct uci_context *ctx;
struct uci_package *pkg;
struct uci_element *e;
if (!package_name || !search_val || !option || !value)
return false;
ctx = uci_alloc_context();
if (!ctx)
return false;
if (uci_load(ctx, package_name, &pkg)) {
uci_free_context(ctx);
return false;
}
uci_foreach_element(&pkg->sections, e) {
struct uci_section *s = uci_to_section(e);
if (!strcmp(s->type, section_type)) {
struct uci_option *opt = uci_lookup_option(ctx, s,
search_key);
if (!opt || opt->type != UCI_TYPE_STRING)
continue;
if (strcmp(opt->v.string, search_val) == 0) {
struct uci_ptr ptr = {0};
ptr.value = value;
ptr.package = package_name;
ptr.section = s->e.name;
ptr.option = option;
ptr.target = UCI_TYPE_OPTION;
if (uci_lookup_ptr(ctx, &ptr, NULL, false) ||
!UCI_LOOKUP_COMPLETE)
break;
if (uci_set(ctx, &ptr) == UCI_OK)
uci_save(ctx, ptr.p);
break;
}
}
}
uci_commit(ctx, &pkg, false);
uci_unload(ctx, pkg);
uci_free_context(ctx);
return false;
}
struct uci_section *config_get_section(struct uci_context *ctx,
struct uci_package *pkg, const char *type, const char *key,
const char *value)
{
struct uci_element *e;
struct uci_section *section;
/* get the wet iface section */
uci_foreach_element(&pkg->sections, e) {
const char *c_value;
section = uci_to_section(e);
if (strcmp(section->type, type))
continue;
c_value = uci_lookup_option_string(ctx, section, key);
if (c_value && !strcmp(c_value, value))
return section;
}
return NULL;
}
int cntlr_config_add_agent(struct controller_config *c, char *al_mac)
{
struct uci_context *ctx = NULL;
struct uci_package *pkg;
struct uci_section *section;
int ret = -1;
pkg = uci_load_pkg(&ctx, "mapcontroller");
if (!pkg)
return ret;
section = config_get_section(ctx, pkg, "node", "agent_id", al_mac);
if (section)
goto out_pkg;
ret = uci_add_section(ctx, pkg, "node", §ion);
if (ret)
goto out_pkg;
ret = uci_save(ctx, pkg);
if (ret)
goto out_pkg;
ret = set_value(ctx, pkg, section, "agent_id", al_mac, UCI_TYPE_STRING);
uci_commit(ctx, &pkg, false);
out_pkg:
uci_unload(ctx, pkg);
uci_free_context(ctx);
return ret;
}
int cntlr_config_add_agent_radio(struct controller_config *c, char *al_mac,
char *radio_mac, char *band)
{
struct uci_context *ctx = NULL;
struct uci_package *pkg;
struct uci_section *section;
int ret = -1;
pkg = uci_load_pkg(&ctx, "mapcontroller");
if (!pkg)
return ret;
section = config_get_section(ctx, pkg, "radio", "macaddr", radio_mac);
if (!section) {
ret = uci_add_section(ctx, pkg, "radio", §ion);
if (ret)
goto out_pkg;
}
ret = uci_save(ctx, pkg);
if (ret)
goto out_pkg;
ret = set_value(ctx, pkg, section, "agent_id", al_mac, UCI_TYPE_STRING);
ret = set_value(ctx, pkg, section, "macaddr", radio_mac, UCI_TYPE_STRING);
ret = set_value(ctx, pkg, section, "band", band, UCI_TYPE_STRING);
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
uci_commit(ctx, &pkg, false);
out_pkg:
uci_unload(ctx, pkg);
uci_free_context(ctx);
return ret;
}
#if 0
void cntlr_dump_node_policy(struct node_policy *np)
{
dbg("Dump node policy for agent "MACFMT"\n", MAC2STR(np->agent_id));
dbg("agent_id "MACFMT"\n", MAC2STR(np->agent_id));
dbg("bk_ul_mac "MACFMT"\n", MAC2STR(np->bk_ul_mac));
dbg("bk_dl_mac "MACFMT"\n", MAC2STR(np->bk_dl_mac));
dbg("type %d\n", np->type);
dbg("pvid %u\n", np->pvid);
dbg("pcp %u\n", np->pcp);
dbg("report_scan %d\n", np->report_scan);
dbg("report_sta_assocfails %d\n", np->report_sta_assocfails);
dbg("report_sta_assocfails_rate %d\n", np->report_sta_assocfails_rate);
dbg("report_metric_periodic %u\n", np->report_metric_periodic);
dbg("steer_disallow %d\n", np->steer_disallow);
dbg("coordinated_cac %d\n", np->coordinated_cac);
dbg("traffic_separation %d\n", np->traffic_separation);
dbg("sta_steer %d\n", np->sta_steer);
dbg("num_steer_stas %d\n", np->num_steer_stas);
dbg("num_btmsteer_stas %d\n", np->num_btmsteer_stas);
}
void cntlr_config_dump(struct controller_config *c)
struct iface_credential *cred;
dbg("Controller config ---------\n");
dbg("Enabled: %d\n", c->enabled);
dbg("Registrar @5Ghz: %d\n", c->has_registrar_5g);
dbg("Registrar @2Ghz: %d\n", c->has_registrar_2g);
dbg("Enable STA steer: %d\n", c->enable_sta_steer);
dbg("Enable BSTA steer: %d\n", c->enable_bsta_steer);
dbg("Use bcn metrics to steer: %d\n", c->use_bcn_metrics);
dbg("Use uSTA metrics to steer: %d\n", c->use_usta_metrics);
dbg("Credentials\n");
list_for_each_entry(cred, &c->aplist, list) {
dbg(" Band : %d\n", cred->band);
dbg(" Security: 0x%x\n", cred->sec);
dbg(" ssid : %s\n", cred->ssid);
dbg(" vlan : %d\n\n", cred->vlanid);
//dbg(" Id : " MACFMT "\n", MAC2STR(c->apolicy.agent_id));
dbg(" Steer-policy : %d\n", c->apolicy->policy);
dbg(" Util-threshold : %d\n", c->apolicy->util_threshold);
dbg(" RCPI-threshold : %d\n", c->apolicy->rcpi_threshold);
dbg(" Report scan : %d\n", c->apolicy->report_scan);
dbg(" Report assocfails : %d\n", c->apolicy->report_sta_assocfails);
dbg(" Report assocfails rate: %d\n", c->apolicy->report_sta_assocfails_rate);
dbg(" Report metric : %d\n", c->apolicy->report_metric_periodic);
dbg(" Report RCPI-thresh : %d\n", c->apolicy->report_rcpi_threshold);
dbg(" Report Util-thresh : %d\n", c->apolicy->report_util_threshold);
dbg(" RCPI hysteresis margin: %d\n", c->apolicy->rcpi_hysteresis_margin);
dbg(" Include STA stats : %d\n", c->apolicy->include_sta_stats);
dbg(" Include STA metric : %d\n", c->apolicy->include_sta_metric);
dbg(" Disallow bSTA P1 : %d\n", c->apolicy->disallow_bsta_p1);
dbg(" Disallow bSTA P2 : %d\n", c->apolicy->disallow_bsta_p2);
dbg(" Is policy diff : %d\n", c->apolicy->is_policy_diff);
#if 0
// INIT_LIST_HEAD(&c->apolicy.steer_exlist); // TODO: remove INIT_LIST_HEAD
// INIT_LIST_HEAD(&c->apolicy.btmsteer_exlist);
list_for_each_entry(x, &c->apolicy.steer_exlist, list) {
dbg(" Disallowed STA : %s\n", x->macstring);
}
list_for_each_entry(x, &c->apolicy.btmsteer_exlist, list) {
dbg(" Disallowed BTM STA : %s\n", x->macstring);
}
#endif
int cntlr_config_defaults(struct controller *cntlr, struct controller_config *cfg)
memset(cfg, 0, sizeof(*cfg));
//INIT_LIST_HEAD(&cfg->policylist);
INIT_LIST_HEAD(&cfg->radiolist);
INIT_LIST_HEAD(&cfg->nodelist);
INIT_LIST_HEAD(&cfg->vlanlist);
INIT_LIST_HEAD(&cfg->aplist);
static int cntlr_config_get_base(struct controller_config *c,
struct uci_section *s)
enum {
CNTLR_ENABLED,
CNTLR_REGISTRAR,
CNTLR_ENABLE_STA_STEER,
CNTLR_ENABLE_BSTA_STEER,
CNTLR_USE_BCN_METRICS,
CNTLR_USE_USTA_METRICS,
};
const struct uci_parse_option opts[] = {
{ .name = "enabled", .type = UCI_TYPE_STRING },
{ .name = "registrar", .type = UCI_TYPE_STRING },
{ .name = "debug", .type = UCI_TYPE_STRING },
{ .name = "resend_num", .type = UCI_TYPE_STRING },
{ .name = "enable_sta_steer", .type = UCI_TYPE_STRING },
{ .name = "enable_bsta_steer", .type = UCI_TYPE_STRING },
{ .name = "use_bcn_metrics", .type = UCI_TYPE_STRING },
{ .name = "use_usta_metrics", .type = UCI_TYPE_STRING },
};
struct uci_option *tb[NUM_CNTLR_ATTRS];
uci_parse_section(s, opts, NUM_CNTLR_ATTRS, tb);
if (tb[CNTLR_ENABLED]) {
const char *val = tb[CNTLR_ENABLED]->v.string;
if (tb[CNTLR_REGISTRAR]) {
const char *val = tb[CNTLR_REGISTRAR]->v.string;
c->has_registrar_5g = !strstr(val, "5") ? false : true;
c->has_registrar_2g = !strstr(val, "2") ? false : true;
const char *debug = tb[CNTLR_DEBUG]->v.string;
c->debug_level = atoi(debug);
if (c->debug_level > verbose)
verbose = c->debug_level;
if (tb[CNTLR_RESEND_NUM]) {
const char *val = tb[CNTLR_RESEND_NUM]->v.string;
c->resend_num = atoi(val);
}
if (tb[CNTLR_ENABLE_STA_STEER]) {
const char *val = tb[CNTLR_ENABLE_STA_STEER]->v.string;
c->enable_sta_steer = atoi(val) == 1 ? true : false;
}
if (tb[CNTLR_ENABLE_BSTA_STEER]) {
const char *val = tb[CNTLR_ENABLE_BSTA_STEER]->v.string;
c->enable_bsta_steer = atoi(val) == 1 ? true : false;
}
if (tb[CNTLR_USE_BCN_METRICS]) {
const char *val = tb[CNTLR_USE_BCN_METRICS]->v.string;
c->use_bcn_metrics = atoi(val) == 1 ? true : false;
}
if (tb[CNTLR_USE_USTA_METRICS]) {
const char *val = tb[CNTLR_USE_USTA_METRICS]->v.string;
c->use_usta_metrics = atoi(val) == 1 ? true : false;
}
static int cntlr_config_get_credentials(struct controller_config *c,
struct uci_section *s)
enum {
CRED_BAND,
CRED_SSID,
CRED_SEC,
CRED_KEY,
CRED_VLAN,
CRED_ENABLED,
NUM_CREDS,
};
const struct uci_parse_option opts[] = {
[CRED_BAND] = { .name = "band", .type = UCI_TYPE_STRING },
[CRED_SSID] = { .name = "ssid", .type = UCI_TYPE_STRING },
[CRED_SEC] = { .name = "encryption", .type = UCI_TYPE_STRING },
[CRED_KEY] = { .name = "key", .type = UCI_TYPE_STRING },
[CRED_VLAN] = { .name = "vid", .type = UCI_TYPE_STRING },
[CRED_NETWORK] = { .name = "network", .type = UCI_TYPE_STRING },
[CRED_TYPE] = { .name = "type", .type = UCI_TYPE_STRING },
[CRED_D_BSTA] = { .name = "disallow_bsta", .type = UCI_TYPE_LIST },
[CRED_ENABLED] = { .name = "enabled", .type = UCI_TYPE_STRING }
};
struct uci_option *tb[NUM_CREDS];
struct iface_credential *cred;
if (c->num_bss >= 32)
return -1;
cred = calloc(1, sizeof(*cred));
if (!cred)
return -1;
cred->enabled = true;
if (tb[CRED_BAND]) {
if (atoi(tb[CRED_BAND]->v.string) == 5)
cred->band = BAND_5;
cred->band = BAND_2;
else
cred->band = BAND_UNKNOWN;
} else
cred->band = BAND_UNKNOWN;
strncpy((char *) cred->ssid, tb[CRED_SSID]->v.string, 32);
if (tb[CRED_SEC]) {
const char *sec = tb[CRED_SEC]->v.string;
if (!strncmp(sec, "sae-mixed", 9)) {
cred->sec |= WIFI_SECURITY_WPA3PSK;
cred->sec |= WIFI_SECURITY_WPA3PSK_T;
} else if (!strncmp(sec, "sae", 3)) {
cred->sec |= WIFI_SECURITY_WPA3PSK;
} else if (!strncmp(sec, "psk-mixed", 9)) {
cred->sec |= WIFI_SECURITY_WPAPSK;
cred->sec |= WIFI_SECURITY_WPA2PSK;
} else if (!strncmp(sec, "psk2", 4)) {
cred->sec |= WIFI_SECURITY_WPA2PSK;
} else if (!strncmp(sec, "psk", 3)) {
cred->sec |= WIFI_SECURITY_WPAPSK;
} else if (!strncmp(sec, "wpa-mixed", 9)) {
cred->sec |= WIFI_SECURITY_WPA;
cred->sec |= WIFI_SECURITY_WPA2;
} else if (!strncmp(sec, "wpa2", 4)) {
cred->sec |= WIFI_SECURITY_WPA2;
} else if (!strncmp(sec, "wpa", 3)) {
cred->sec |= WIFI_SECURITY_WPA;
} else if (!strncmp(sec, "none", 4)) {
cred->sec |= WIFI_SECURITY_NONE;
} else if (!strncmp(sec, "open", 4)) {
cred->sec |= WIFI_SECURITY_NONE;
} else {
free(cred);
return -1;
}
strncpy((char *) cred->key, tb[CRED_KEY]->v.string, 64);
cred->vlanid = (uint16_t) atoi(tb[CRED_VLAN]->v.string);
if (tb[CRED_NETWORK])
strncpy((char *)cred->network, tb[CRED_NETWORK]->v.string,
sizeof(cred->network));
else
strncpy((char *) cred->network, "lan", sizeof(cred->network));
if (tb[CRED_TYPE]) {
const char *type = tb[CRED_TYPE]->v.string;
if (!strcmp(type, "backhaul")) {
cred->mode = AP_WIFI_BBSS;
} else if (!strcmp(type, "fronthaul")) {
cred->mode = AP_WIFI_FBSS;
} else if (!strcmp(type, "combined")) {
cred->multi_ap = 3;
cred->mode = AP_WIFI_COMBINED;
} else {
free(cred);
return -1;
}
} else {
cred->multi_ap = 2; /* default to fhbss */
if (tb[CRED_D_BSTA]) {
struct uci_element *x;
uci_foreach_element(&tb[CRED_D_BSTA]->v.list, x)
cred->disallow_bsta |= atoi(x->name);
if (tb[CRED_ENABLED])
cred->enabled = atoi(tb[CRED_ENABLED]->v.string);
list_add_tail(&cred->list, &c->aplist);
static struct netif_vlan *cntlr_config_get_vlan_by_name(struct controller_config *cfg,
{
struct netif_vlan *vlan;
list_for_each_entry(vlan, &cfg->vlanlist, list) {
if (!strncmp(vlan->network, name, sizeof(vlan->network)))
return vlan;
}
return NULL;
}
struct node_policy *cntlr_config_get_node_by_mac(struct controller_config *cfg,
uint8_t *macaddr)
{
struct node_policy *node;
list_for_each_entry(node, &cfg->nodelist, list) {
if (!memcmp(node->agent_id, macaddr, 6))
return node;
}
return NULL;
}
static int cntlr_config_get_network(struct controller_config *c,
struct uci_section *s)
{
enum {
VLAN_PROTO,
VLAN_IP_ADDR,
NUM_OPTS,
};
const struct uci_parse_option opts[] = {
[VLAN_PROTO] = { .name = "proto", .type = UCI_TYPE_STRING },
[VLAN_IP_ADDR] = { .name = "ipaddr", .type = UCI_TYPE_STRING },
};
struct uci_option *tb[NUM_OPTS];
struct netif_vlan *vlan;
uci_parse_section(s, opts, NUM_OPTS, tb);
vlan = cntlr_config_get_vlan_by_name(c, name);
if (!vlan) {
vlan = calloc(1, sizeof(*vlan));
if (!vlan)
return -1;
strncpy(vlan->network, name, sizeof(vlan->network) - 1);
c->num_vlans++;
list_add(&vlan->list, &c->vlanlist);
}
if (tb[VLAN_PROTO])
strncpy((char *) vlan->proto, tb[VLAN_PROTO]->v.string,
sizeof(vlan->proto) - 1);
if (tb[VLAN_IP_ADDR])
inet_pton(AF_INET, tb[VLAN_IP_ADDR]->v.string,
&(vlan->ipaddr.addr.ip4.s_addr));
return 0;
}
static int cntlr_config_get_agent_node(struct controller_config *c,
NODE_AGENT_ID,
NODE_BK_UL_MAC,
NODE_BK_DL_MAC,
NODE_BK_TYPE,
NODE_PVID,
NODE_PCP,
NODE_RPT_ASSOC_FAILS,
NODE_RPT_ASSOC_FAILS_RATE,
NODE_RPT_METRIC_PERIODIC,
NODE_RPT_SCAN,
NODE_STEER_EXCLUDE,
NODE_STEER_EXCLUDE_BTM,
NODE_STEER_DISALLOW,
NODE_C_CAC,
NODE_TRAFFIC_SEPARATION,
NODE_STA_STEER,
NUM_POLICIES,
};
const struct uci_parse_option opts[] = {
{ .name = "agent_id", .type = UCI_TYPE_STRING },
{ .name = "backhaul_ul_macaddr", .type = UCI_TYPE_STRING },
{ .name = "backhaul_dl_macaddr", .type = UCI_TYPE_STRING },
{ .name = "backhaul_type", .type = UCI_TYPE_STRING },
{ .name = "primary_vid", .type = UCI_TYPE_STRING },
{ .name = "primary_pcp", .type = UCI_TYPE_STRING },
{ .name = "report_sta_assocfails", .type = UCI_TYPE_STRING },
{ .name = "report_sta_assocfails_rate", .type = UCI_TYPE_STRING },
{ .name = "report_metric_periodic", .type = UCI_TYPE_STRING },
{ .name = "report_scan", .type = UCI_TYPE_STRING },
{ .name = "steer_exclude", .type = UCI_TYPE_STRING },
{ .name = "steer_exclude_btm", .type = UCI_TYPE_STRING },
{ .name = "steer_disallow", .type = UCI_TYPE_STRING },
{ .name = "coordinated_cac", .type = UCI_TYPE_STRING },
{ .name = "traffic_separation", .type = UCI_TYPE_STRING },
{ .name = "sta_steer", .type = UCI_TYPE_STRING },
struct node_policy *a;
struct uci_element *x;
uci_parse_section(s, opts, NUM_POLICIES, tb);
if (tb[NODE_AGENT_ID]) {
a = calloc(1, sizeof(*a));
if (!a)
return -1;
list_add(&a->list, &c->nodelist);
INIT_LIST_HEAD(&a->radiolist);
hwaddr_aton(tb[NODE_AGENT_ID]->v.string, a->agent_id);
INIT_LIST_HEAD(&a->steer_exlist);
INIT_LIST_HEAD(&a->btmsteer_exlist);
a->pvid = 1;
} else
return -1;
if (tb[NODE_BK_UL_MAC])
hwaddr_aton(tb[NODE_BK_UL_MAC]->v.string, a->bk_ul_mac);
if (tb[NODE_BK_DL_MAC])
hwaddr_aton(tb[NODE_BK_DL_MAC]->v.string, a->bk_dl_mac);
if (tb[NODE_BK_TYPE]) {
char *type = tb[NODE_BK_TYPE]->v.string;
if (strcmp(type, "none"))
a->type = BK_TYPE_NONE;
else
a->type = BK_TYPE_NONE;
}
if (tb[NODE_PVID])
a->pvid = atoi(tb[NODE_PVID]->v.string);
if (tb[NODE_PCP])
a->pcp = atoi(tb[NODE_PCP]->v.string);
if (tb[NODE_RPT_ASSOC_FAILS]) {
a->report_sta_assocfails =
atoi(tb[NODE_RPT_ASSOC_FAILS]->v.string) == 1 ?
true : false;
}
if (tb[NODE_RPT_ASSOC_FAILS_RATE]) {
a->report_sta_assocfails_rate =
atoi(tb[NODE_RPT_ASSOC_FAILS_RATE]->v.string);
}
if (tb[NODE_STEER_EXCLUDE]) {
uci_foreach_element(&tb[NODE_STEER_EXCLUDE]->v.list, x) {
stax_add_entry(&a->steer_exlist, x->name);
a->num_steer_stas++;
}
}
if (tb[NODE_STEER_EXCLUDE_BTM]) {
uci_foreach_element(&tb[NODE_STEER_EXCLUDE_BTM]->v.list, x) {
stax_add_entry(&a->btmsteer_exlist, x->name);
a->num_btmsteer_stas++;
}
}
if (tb[NODE_RPT_SCAN]) {
a->report_scan =
atoi(tb[NODE_RPT_SCAN]->v.string) == 1 ? true : false;
}
if (tb[NODE_RPT_METRIC_PERIODIC])
a->report_metric_periodic = atoi(tb[NODE_RPT_METRIC_PERIODIC]->v.string);
if (tb[NODE_STEER_DISALLOW])
a->steer_disallow = atoi(tb[NODE_STEER_DISALLOW]->v.string) == 1 ? true : false;
if (tb[NODE_C_CAC])
a->coordinated_cac = atoi(tb[NODE_C_CAC]->v.string) == 1 ? true : false;
if (tb[NODE_TRAFFIC_SEPARATION])
a->traffic_separation = atoi(tb[NODE_TRAFFIC_SEPARATION]->v.string) == 1 ? true : false;
if (tb[NODE_STA_STEER])
a->sta_steer = atoi(tb[NODE_STA_STEER]->v.string) == 1 ? true : false;
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
return 0;
}
static int cntlr_config_get_agent_radio(struct controller_config *c,
struct uci_section *s)
{
enum {
RADIO_AGENT,
RADIO_MAC,
RADIO_BAND,
RADIO_STEER_POLICY,
RADIO_UTIL_TH,
RADIO_RCPI_TH,
RADIO_RCPI_HYSTERESIS_TH,
RADIO_RPT_RCPI_TH,
RADIO_RPT_UTIL_TH,
RADIO_RPT_HYS_MARGIN,
RADIO_INC_STA_STATS,
RADIO_INC_STA_METRIC,
NUM_POLICIES,
};
const struct uci_parse_option opts[] = {
{ .name = "agent_id", .type = UCI_TYPE_STRING },
{ .name = "macaddr", .type = UCI_TYPE_STRING },
{ .name = "band", .type = UCI_TYPE_STRING },
{ .name = "steer_policy", .type = UCI_TYPE_STRING },
{ .name = "util_threshold", .type = UCI_TYPE_STRING },
{ .name = "rcpi_threshold", .type = UCI_TYPE_STRING },
{ .name = "rcpi_hysteresis_threshold", .type = UCI_TYPE_STRING },
{ .name = "report_rcpi_threshold", .type = UCI_TYPE_STRING },
{ .name = "report_util_threshold", .type = UCI_TYPE_STRING },
{ .name = "report_rcpi_hysteresis_margin", .type = UCI_TYPE_STRING },
{ .name = "include_sta_stats", .type = UCI_TYPE_STRING },
{ .name = "include_sta_metric", .type = UCI_TYPE_STRING },
};
struct uci_option *tb[NUM_POLICIES];
struct radio_policy *a;
uci_parse_section(s, opts, NUM_POLICIES, tb);
if (tb[RADIO_AGENT] && tb[RADIO_MAC] && tb[RADIO_BAND]) {
a = calloc(1, sizeof(*a));
if (!a)
return -1;
hwaddr_aton(tb[RADIO_AGENT]->v.string, a->agent_id);
hwaddr_aton(tb[RADIO_MAC]->v.string, a->macaddr);
if (atoi(tb[RADIO_BAND]->v.string) == 5) {
a->band = BAND_5;
a->rcpi_threshold = CONFIG_DEFAULT_RCPI_TH_5G;
} else if (atoi(tb[RADIO_BAND]->v.string) == 2) {
a->band = BAND_2;
a->rcpi_threshold = CONFIG_DEFAULT_RCPI_TH_2G;
} else
a->band = BAND_UNKNOWN;
a->report_rcpi_threshold = a->rcpi_threshold + 10;
a->include_sta_stats = true;
a->include_sta_metric = true;
list_add(&a->list, &c->radiolist);
} else {
warn("|%s:%d| invalid radio config! Must hold agent_id, macaddr and band", __func__, __LINE__);
return -1;
if (tb[RADIO_STEER_POLICY])
a->policy = atoi(tb[RADIO_STEER_POLICY]->v.string);
if (tb[RADIO_UTIL_TH])
a->util_threshold = atoi(tb[RADIO_UTIL_TH]->v.string);
if (tb[RADIO_RCPI_TH])
a->rcpi_threshold = atoi(tb[RADIO_RCPI_TH]->v.string);
if (tb[RADIO_RCPI_HYSTERESIS_TH])
a->rcpi_threshold = atoi(tb[RADIO_RCPI_HYSTERESIS_TH]->v.string);
if (tb[RADIO_RPT_RCPI_TH]) {
atoi(tb[RADIO_RPT_RCPI_TH]->v.string);
if (tb[RADIO_RPT_UTIL_TH]) {
atoi(tb[RADIO_RPT_UTIL_TH]->v.string);
if (tb[RADIO_RPT_HYS_MARGIN]) {
a->report_rcpi_hysteresis_margin =