Newer
Older
if (tb[STEER_RPT_RCPI_TH_5G]) {
const char *val = tb[STEER_RPT_RCPI_TH_5G]->v.string;
int rcpi;
rcpi = atoi(val);
if (rcpi > 0 && rcpi <= 220)
sc->report_rcpi_threshold_5g = rcpi;
}
if (tb[STEER_RPT_RCPI_TH_6G]) {
const char *val = tb[STEER_RPT_RCPI_TH_6G]->v.string;
int rcpi;
rcpi = atoi(val);
if (rcpi > 0 && rcpi <= 220)
sc->report_rcpi_threshold_6g = rcpi;
}
return 0;
}
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,
CRED_VENDOR_IE,
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_TYPE] = { .name = "type", .type = UCI_TYPE_STRING },
[CRED_D_BSTA] = { .name = "disallow_bsta_profile", .type = UCI_TYPE_LIST },
[CRED_ENABLED] = { .name = "enabled", .type = UCI_TYPE_STRING },
[CRED_VENDOR_IE] = { .name = "vendor_ie", .type = UCI_TYPE_LIST }
};
struct uci_option *tb[NUM_CREDS];
struct iface_credential *cred;
bool use_default_security = false;
if (c->num_bss >= 32)
return -1;
cred = calloc(1, sizeof(*cred));
if (!cred)
return -1;
cred->enabled = true;
if (tb[CRED_ENABLED])
cred->enabled = atoi(tb[CRED_ENABLED]->v.string);
#ifndef EASYMESH_VENDOR_EXT
if (!(cred->enabled)) {
free(cred);
return -1;
}
#endif
if (tb[CRED_BAND]) {
if (atoi(tb[CRED_BAND]->v.string) == 5)
cred->band = BAND_5;
cred->band = BAND_2;
else if (atoi(tb[CRED_BAND]->v.string) == 6)
cred->band = BAND_6;
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 |= BIT(WIFI_SECURITY_WPA3PSK);
cred->sec |= BIT(WIFI_SECURITY_WPA3PSK_T);
} else if (!strncmp(sec, "sae", 3)
#if (EASYMESH_VERSION > 2)
|| !strncmp(sec, "dpp", 3) ||
!strncmp(sec, "dpp+sae", 3) ||
!strncmp(sec, "sae+dpp", 3)
#endif
) {
cred->sec |= BIT(WIFI_SECURITY_WPA3PSK); /* TODO: how do we properly transfer DPP encryption */
} else if (!strncmp(sec, "psk-mixed", 9)) {
cred->sec |= BIT(WIFI_SECURITY_WPAPSK);
cred->sec |= BIT(WIFI_SECURITY_WPA2PSK);
} else if (!strncmp(sec, "psk2", 4)) {
cred->sec |= BIT(WIFI_SECURITY_WPA2PSK);
} else if (!strncmp(sec, "psk", 3)) {
cred->sec |= BIT(WIFI_SECURITY_WPAPSK);
} else if (!strncmp(sec, "wpa-mixed", 9)) {
cred->sec |= BIT(WIFI_SECURITY_WPA);
cred->sec |= BIT(WIFI_SECURITY_WPA2);
} else if (!strncmp(sec, "wpa2", 4)) {
cred->sec |= BIT(WIFI_SECURITY_WPA2);
} else if (!strncmp(sec, "wpa", 3)) {
cred->sec |= BIT(WIFI_SECURITY_WPA);
} else if (!strncmp(sec, "none", 4)) {
cred->sec |= BIT(WIFI_SECURITY_NONE);
} else if (!strncmp(sec, "open", 4)) {
cred->sec |= BIT(WIFI_SECURITY_NONE);
} else {
free(cred);
return -1;
}
} else {
use_default_security = true;
strncpy((char *) cred->key, tb[CRED_KEY]->v.string, 64);
if (tb[CRED_VLAN]) {
cred->vlanid = (uint16_t) atoi(tb[CRED_VLAN]->v.string);
if (!is_vid_valid(cred->vlanid)) {
dbg("|%s:%d| cred:%s vid:%d is not valid\n", __func__,
__LINE__, cred->ssid, cred->vlanid);
free(cred);
return -1;
}
} else {
/* if missing option vid in ap section use 1 as default */
cred->vlanid = 1;
}
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 (use_default_security) {
cred->sec |= BIT(WIFI_SECURITY_WPA3PSK);
if (!!(cred->multi_ap & 2))
cred->sec |= BIT(WIFI_SECURITY_WPA3PSK_T);
if (tb[CRED_D_BSTA]) {
struct uci_element *x;
uci_foreach_element(&tb[CRED_D_BSTA]->v.list, x) {
uint8_t profile;
profile = atoi(x->name);
if (profile > 2)
continue;
cred->disallow_bsta |= profile;
#ifdef EASYMESH_VENDOR_EXT
do {
/* add iopsys vendor_ies for cred->enabled option */
struct wsc_vendor_ie *ext;
uint8_t offset = 0;
uint8_t attr = 0x4c;
uint8_t attr_len = 0x01;
const uint8_t vendor_oui[4] = {0};
uint32_t oui = 0;
BUF_PUT_BE24(vendor_oui, EASYMESH_VENDOR_EXT_OUI_DEFAULT);
#ifdef EASYMESH_VENDOR_EXT_OUI
oui = EASYMESH_VENDOR_EXT_OUI;
BUF_PUT_BE24(vendor_oui, oui);
#endif
ext = &cred->ven_ies[0];
memcpy(ext->oui, vendor_oui, 3);
ext->len = 3;
ext->payload = calloc(1, ext->len);
if (!ext->payload)
break;
/* uses same format as WFA WSC vendor extension:
* <attr:8><len:8><data>
*/
memcpy(ext->payload, &attr, 1); /* IOP enabled attr */
offset += 1;
memcpy(ext->payload + offset, &attr_len, 1); /* len */
offset += 1;
memcpy(ext->payload + offset, &cred->enabled, 1); /* val */
cred->num_ven_ies++;
} while (0);
#endif /*EASYMESH_VENDOR_EXT*/
if (tb[CRED_VENDOR_IE]) {
struct uci_element *x;
uci_foreach_element(&tb[CRED_VENDOR_IE]->v.list, x) {
char *vendor_ie = x->name;
struct wsc_vendor_ie *ext;
uint16_t len;
uint8_t offset = 0;
uint8_t *buf;
if (cred->num_ven_ies >= VEN_IES_MAX) {
dbg("at most %d vendor ies\n", VEN_IES_MAX);
break;
}
len = strlen(vendor_ie);
if (len % 2 != 0)
continue;
len = len / 2;
dbg("payload len too short %d\n", len);
continue;
}
buf = calloc(1, len);
if (!buf)
continue;
strtob(vendor_ie, len, buf);
ext = &cred->ven_ies[cred->num_ven_ies];
memcpy(ext->oui, (uint8_t *) buf, 3);
offset += 3;
if (len > offset) {
ext->len = len - offset;
ext->payload = calloc(1, ext->len);
if (!ext->payload) {
free(buf);
continue;
}
memcpy(ext->payload,
(uint8_t *) (buf + offset),
ext->len);
}
cred->num_ven_ies++;
free(buf);
}
}
cntlr_config_get_wsc_attributes(c, cred);
list_add_tail(&cred->list, &c->aplist);
struct node_policy *cntlr_config_get_node_by_mac(struct controller_config *cfg,
uint8_t *macaddr)
{
list_for_each_entry(node, &cfg->nodelist, list) {
if (!memcmp(node->agent_id, macaddr, 6))
return node;
}
return NULL;
}
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_LIST },
{ .name = "steer_exclude_btm", .type = UCI_TYPE_LIST },
{ .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);
} 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);
else
a->report_metric_periodic = 1;
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;
return 0;
}
static int cntlr_config_get_agent_radio(struct controller_config *cc,
struct uci_section *s)
{
enum {
RADIO_AGENT,
RADIO_MAC,
RADIO_BAND,
RADIO_STEER_POLICY,
RADIO_UTIL_TH,
RADIO_RCPI_TH,
RADIO_RPT_RCPI_TH,
RADIO_RPT_UTIL_TH,
RADIO_RPT_HYS_MARGIN,
RADIO_INC_STA_STATS,
RADIO_INC_STA_METRIC,
RADIO_INC_WIFI6_STA_STATUS,
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 = "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 },
{ .name = "include_wifi6_sta_status", .type = UCI_TYPE_STRING },
struct controller *c = container_of(cc, struct controller, cfg);
struct uci_option *tb[NUM_POLICIES];
struct steer_control_config *scc = NULL;
struct radio_policy *a;
uci_parse_section(s, opts, NUM_POLICIES, tb);
if (!tb[RADIO_AGENT] || !tb[RADIO_MAC] || !tb[RADIO_BAND]) {
warn("|%s:%d| invalid radio config! Must hold agent_id, macaddr and band", __func__, __LINE__);
return -1;
}
a = calloc(1, sizeof(*a));
if (!a)
return -1;
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
hwaddr_aton(tb[RADIO_AGENT]->v.string, a->agent_id);
hwaddr_aton(tb[RADIO_MAC]->v.string, a->macaddr);
band = atoi(tb[RADIO_BAND]->v.string);
scc = get_steer_control_config(c);
a->band = BAND_UNKNOWN;
switch (band) {
case 5:
a->band = BAND_5;
if (scc) {
a->rcpi_threshold = scc->rcpi_threshold_5g;
a->report_rcpi_threshold = scc->report_rcpi_threshold_5g;
} else
a->rcpi_threshold = CONFIG_DEFAULT_RCPI_TH_5G;
break;
case 6:
a->band = BAND_6;
if (scc) {
a->rcpi_threshold = scc->rcpi_threshold_6g;
a->report_rcpi_threshold = scc->report_rcpi_threshold_6g;
} else
a->rcpi_threshold = CONFIG_DEFAULT_RCPI_TH_6G;
break;
case 2:
a->band = BAND_2;
/* no break */
default:
if (scc) {
a->rcpi_threshold = scc->rcpi_threshold_2g;
a->report_rcpi_threshold = scc->report_rcpi_threshold_2g;
} else
a->rcpi_threshold = CONFIG_DEFAULT_RCPI_TH_2G;
break;
}
if (!scc)
a->report_rcpi_threshold = a->rcpi_threshold + 10;
a->include_sta_stats = true;
a->include_sta_metric = true;
list_add(&a->list, &cc->radiolist);
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]) {
/* override default value from steer section in config */
a->rcpi_threshold = atoi(tb[RADIO_RCPI_TH]->v.string);
a->report_rcpi_threshold = a->rcpi_threshold + 10;
}
if (tb[RADIO_RPT_RCPI_TH]) {
/* override default value from steer section in config */
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 =
atoi(tb[RADIO_RPT_HYS_MARGIN]->v.string);
}
if (tb[RADIO_INC_STA_STATS]) {
atoi(tb[RADIO_INC_STA_STATS]->v.string) == 1 ?
if (tb[RADIO_INC_STA_METRIC]) {
atoi(tb[RADIO_INC_STA_METRIC]->v.string) == 1 ?
if (tb[RADIO_INC_WIFI6_STA_STATUS]) {
a->include_wifi6_sta_status =
atoi(tb[RADIO_INC_WIFI6_STA_STATUS]->v.string) == 1 ?
true : false;
}
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
#if (EASYMESH_VERSION > 2)
static int cntlr_config_get_dpp_controller(struct controller_config *a,
struct uci_section *s)
{
enum {
DPP_IFNAME,
DPP_DEVICE,
DPP_BAND,
DPP_TCP_PORT,
NUM_POLICIES
};
const struct uci_parse_option opts[] = {
{ .name = "ifname", .type = UCI_TYPE_STRING },
{ .name = "device", .type = UCI_TYPE_STRING },
{ .name = "band", .type = UCI_TYPE_STRING },
{ .name = "tcp_port", .type = UCI_TYPE_STRING },
};
struct uci_option *tb[NUM_POLICIES];
struct dpp_controller_cfg *dpp_cntlr;
/*
config dpp_dpp_cntlr
option device 'wl1'
option band '2'
option ifname 'wl1'
option tcp_dpp_cntlr '8902'
*/
uci_parse_section(s, opts, NUM_POLICIES, tb);
if (tb[DPP_BAND]) {
int bandval = atoi(tb[DPP_BAND]->v.string);
enum wifi_band band = BAND_UNKNOWN;
if (bandval == 2)
band = BAND_2;
else if (bandval == 5)
band = BAND_5;
else if (bandval == 6)
band = BAND_6;
dpp_cntlr = get_dpp_controller_by_band(a, band);
if (!dpp_cntlr) {
dpp_cntlr = create_dpp_controller_config(a, band);
if (!dpp_cntlr) {
warn("%s: OOM!\n", __func__);
return -1;
}
} else {
warn("Duplicate 'dpp dpp_cntlr %d' config!! ignore\n",
bandval);
}
} else
return -1;
if (tb[DPP_IFNAME]) {
const char *ifname;
ifname = tb[DPP_IFNAME]->v.string;
strncpy(dpp_cntlr->ifname, ifname, sizeof(dpp_cntlr->ifname) - 1);
}
if (tb[DPP_DEVICE]) {
const char *device;
device = tb[DPP_DEVICE]->v.string;
strncpy(dpp_cntlr->device, device, sizeof(dpp_cntlr->device) - 1);
}
if (tb[DPP_TCP_PORT]) {
int port = atoi(tb[DPP_TCP_PORT]->v.string);
dpp_cntlr->port = (uint16_t) port;
}
return 0;
}
#endif
static void config_map_radios_to_node(struct controller_config *cfg)
{
list_for_each_entry_safe(r, tmp, &cfg->radiolist, list) {
struct node_policy *n;
n = cntlr_config_get_node_by_mac(cfg, r->agent_id);
if (!n) {
list_del(&r->list);
free(r);
continue;
}
list_del(&r->list);
list_add(&r->list, &n->radiolist);
}
}
uint8_t cntlr_policy_exlist_diff(struct list_head *prev_policylist,
struct list_head *curr_policylist)
{
uint8_t diff = 0;
struct node_policy *prev, *curr;
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
list_for_multiple_entry(prev, curr, prev_policylist, curr_policylist, list, list) {
if ((prev->num_steer_stas != curr->num_steer_stas) ||
(prev->num_btmsteer_stas != curr->num_btmsteer_stas)) {
trace("num of exclude stas differ\n");
curr->is_policy_diff = 1;
diff |= CONFIG_DIFF_AGENT_POLICY;
} else if (list_memcmp(&prev->steer_exlist, &curr->steer_exlist,
struct stax, sizeof(struct list_head))) {
trace("steer_exlist differ\n");
curr->is_policy_diff = 1;
diff |= CONFIG_DIFF_AGENT_POLICY;
} else if (list_memcmp(&prev->btmsteer_exlist, &curr->btmsteer_exlist,
struct stax, sizeof(struct list_head))) {
trace("btmsteer_exlist differ\n");
curr->is_policy_diff = 1;
diff |= CONFIG_DIFF_AGENT_POLICY;
}
}
return diff;
}
uint8_t cntlr_vendor_ies_diff(struct list_head *prev_credslist,
struct list_head *curr_credslist)
struct iface_credential *prev, *curr;
uint8_t diff = 0;
list_for_multiple_entry(prev, curr, prev_credslist, curr_credslist, list, list) {
if (prev->num_ven_ies != curr->num_ven_ies) {
dbg("num of vendor ies differ\n");
diff |= CONFIG_DIFF_CREDENTIALS;
break;
} else {
int i;
for (i = 0; i < curr->num_ven_ies; i++) {
struct wsc_vendor_ie *curr_ie, *prev_ie;
uint16_t len = 0;
curr_ie = &curr->ven_ies[i];
prev_ie = &prev->ven_ies[i];
len = (prev_ie->len > curr_ie->len ?
prev_ie->len : curr_ie->len);
if (memcmp(curr_ie->payload, prev_ie->payload, len)) {
diff |= CONFIG_DIFF_CREDENTIALS;
}
}
}
return diff;
}
uint8_t cntlr_creds_diff(struct controller_config *cfg,
struct controller_config *prev)
{
uint8_t diff = 0;
/* credentials diff */
if (prev->num_bss != cfg->num_bss) {
dbg("|%s:%d| number of credentials differed\n", __func__, __LINE__);
diff |= CONFIG_DIFF_CREDENTIALS;
} else if (list_memcmp(&prev->aplist, &cfg->aplist,
struct iface_credential,
(sizeof(struct iface_credential) -
offsetof(struct iface_credential, list))
dbg("|%s:%d| bss credentials have changed\n", __func__, __LINE__);
diff |= CONFIG_DIFF_CREDENTIALS;
} else {
/* compare vendor ie list */
diff |= cntlr_vendor_ies_diff(&prev->aplist, &cfg->aplist);
return diff;
}
uint8_t cntlr_config_diff(struct controller_config *cfg,
struct controller_config *prev)
{
uint8_t diff = 0;
/* traffic separation change */
if (prev->primary_vid != cfg->primary_vid ||
prev->default_pcp != cfg->default_pcp ||
prev->enable_ts != cfg->enable_ts) {
diff |= CONFIG_DIFF_VLAN;
}
/* credentials diff */
diff |= cntlr_creds_diff(cfg, prev);
/* agent policy diff */
if (prev->num_apolicy != cfg->num_apolicy) {
dbg("|%s:%d| number of agent policy differed\n", __func__, __LINE__);
diff |= CONFIG_DIFF_AGENT_POLICY_CNT;
if (list_policy_memcmp(&prev->nodelist, &cfg->nodelist,
struct node_policy,
(sizeof(struct node_policy) -
offsetof(struct node_policy, is_policy_diff))
)) {
trace("|%s:%d| agent_policy section have changed\n", __func__, __LINE__);
diff |= CONFIG_DIFF_AGENT_POLICY;
} else {
/* exclude stalist diff */
diff |= cntlr_policy_exlist_diff(&prev->nodelist, &cfg->nodelist);
}
return diff;
}
void config_copy_cntlr_config(struct controller_config *curr,
struct controller_config *old)
{
INIT_LIST_HEAD(&old->nodelist);
memcpy(old, curr, offsetof(struct controller_config, nodelist));
list_copy(&curr->radiolist, &old->radiolist, struct radio_policy);
list_copy(&curr->nodelist, &old->nodelist, struct node_policy);
list_copy(&curr->aplist, &old->aplist, struct iface_credential);
}
uint8_t cntlr_config_reload(struct controller_config *cfg)
struct uci_context *ctx;
struct uci_package *pkg;
struct uci_element *e;
struct controller_config old = {0};
uint8_t diff = 0;
ctx = uci_alloc_context();
if (uci_load(ctx, "mapcontroller", &pkg)) {
uci_free_context(ctx);
return -1;
}
config_copy_cntlr_config(cfg, &old);
/* reset counters */
cfg->num_bss = cfg->num_apolicy = 0;
uci_foreach_element(&pkg->sections, e) {
struct uci_section *s = uci_to_section(e);
if (!strcmp(s->type, "controller")) {
} else if (!strcmp(s->type, "sta_steering")) {
cntlr_config_get_steer_params(cfg, s);
} else if (!strcmp(s->type, "node")) {
cntlr_config_get_agent_node(cfg, s);
} else if (!strcmp(s->type, "radio")) {
cntlr_config_get_agent_radio(cfg, s);
#if (EASYMESH_VERSION > 2)
else if (!strcmp(s->type, "dpp_controller"))
cntlr_config_get_dpp_controller(cfg, s);
#endif
config_map_radios_to_node(cfg);
/* get bitmap of what sections changed */
diff = cntlr_config_diff(cfg, &old);
/* clean old lists */
clean_cred_list(&old);
clean_agent_policies(&old); /* cleans nodelist */
int cntlr_config_clean(struct controller_config *cfg)
{
clean_cred_list(cfg);
clean_agent_policies(cfg); /* cleans nodelist */