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 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(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; \
____ptr->is_policy_diff = 1; \
} \
____p = list_entry(____p->list.next, type, 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 agent_policy *p)
{
struct agent *a, *tmp;
list_for_each_entry_safe(a, tmp, &p->agentlist, list) {
list_del(&a->list);
free(a);
}
return 0;
}
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
static int clean_steer_btm_excl(struct agent_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 agent_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 agent_policy *p, *tmp;
list_for_each_entry_safe(p, tmp, &cfg->policylist, list) {
clean_steer_btm_excl(p);
clean_steer_excl(p);
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
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);
}
}
184
185
186
187
188
189
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
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;
}
struct uci_section *config_get_agent_section(struct uci_context *ctx,
struct uci_package *pkg, const char *type, const char *al_mac)
{
struct uci_element *e;
struct uci_section *section;
uci_foreach_element(&pkg->sections, e) {
const char *agent_id;
section = uci_to_section(e);
if (strcmp(section->type, type))
continue;
agent_id = uci_lookup_option_string(ctx, section, "agent_id");
if (agent_id && !strcmp(agent_id, al_mac))
return section;
}
return NULL;
}
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
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
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;
}
int cntlr_config_add_agent(struct controller_config *c, char *al_mac)
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
{
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_agent_section(ctx, pkg, "agent-policy", al_mac);
if (section)
goto out_pkg;
ret = uci_add_section(ctx, pkg, "agent-policy", §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;
}
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("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 *c)
memset(c, 0, sizeof(*c));
INIT_LIST_HEAD(&c->policylist);
INIT_LIST_HEAD(&c->vlanlist);
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_RCPI_STEER_THRESHOLD,
};
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 = "enable_sta_steer", .type = UCI_TYPE_STRING },
{ .name = "enable_bsta_steer", .type = UCI_TYPE_STRING },
{ .name = "rcpi_threshold", .type = UCI_TYPE_STRING },
{ .name = "primary_vid", .type = UCI_TYPE_STRING },
{ .name = "primary_pcp", .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_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_RCPI_STEER_THRESHOLD]) {
const char *val = tb[CNTLR_RCPI_STEER_THRESHOLD]->v.string;
c->rcpi_threshold = atoi(val);
} else
c->rcpi_threshold = 120;
if (tb[CNTLR_PVID])
c->pvid = atoi(tb[CNTLR_PVID]->v.string);
if (tb[CNTLR_PCP_DEFAULT])
c->pcp_default = atoi(tb[CNTLR_PCP_DEFAULT]->v.string);
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;
}
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_policy(struct controller_config *c,
struct uci_section *s)
POL_BAND,
POL_STEER_EXCLUDE,
POL_STEER_EXCLUDE_BTM,
POL_STEER,
POL_UTIL_TH,
POL_RCPI_TH,
POL_RPT_SCAN,
POL_RPT_ASSOC_FAILS,
POL_RPT_ASSOC_FAILS_RATE,
POL_RPT_METRIC_PERIODIC,
POL_RPT_RCPI_TH,
POL_RPT_UTIL_TH,
POL_RPT_HYS_MARGIN,
POL_INC_STA_STATS,
POL_INC_STA_METRIC,
POL_DISALLOW_BSTA_P1,
POL_DISALLOW_BSTA_P2,
NUM_POLICIES,
};
const struct uci_parse_option opts[] = {
{ .name = "agent_id", .type = UCI_TYPE_LIST },
{ .name = "band", .type = UCI_TYPE_STRING },
{ .name = "steer_exclude", .type = UCI_TYPE_LIST },
{ .name = "steer_exclude_btm", .type = UCI_TYPE_LIST },
{ .name = "steer_policy", .type = UCI_TYPE_STRING },
{ .name = "util_threshold", .type = UCI_TYPE_STRING },
{ .name = "rcpi_threshold", .type = UCI_TYPE_STRING },
{ .name = "report_scan", .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_rcpi_threshold", .type = UCI_TYPE_STRING },
{ .name = "report_util_threshold", .type = UCI_TYPE_STRING },
{ .name = "rcpi_hysteresis_margin", .type = UCI_TYPE_STRING },
{ .name = "include_sta_stats", .type = UCI_TYPE_STRING },
{ .name = "include_sta_metric", .type = UCI_TYPE_STRING },
{ .name = "disallow_bsta_p1", .type = UCI_TYPE_STRING },
{ .name = "disallow_bsta_p2", .type = UCI_TYPE_STRING },
};
struct uci_option *tb[NUM_POLICIES];
struct uci_element *x;
uci_parse_section(s, opts, NUM_POLICIES, tb);
a = calloc(1, sizeof(*a));
if (!a)
return -1;
list_add(&a->list, &c->policylist);
c->num_apolicy++;
INIT_LIST_HEAD(&a->agentlist);
uci_foreach_element(&tb[POL_AGENT_ID]->v.list, x) {
struct agent *ax;
ax = calloc(1, sizeof(struct agent));
if (!ax)
continue;
hwaddr_aton(x->name, ax->agent_id);
list_add(&ax->list, &a->agentlist);
}
} else {
struct agent *ax;
uint8_t mac[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
/* add as default? add ff:ff:ff:ff:ff:ff? */
a = c->apolicy;
INIT_LIST_HEAD(&a->agentlist);
ax = calloc(1, sizeof(struct agent));
if (!ax)
return -1;
memcpy(ax->agent_id, mac, 6);
list_add(&ax->list, &a->agentlist);
list_add(&a->list, &c->policylist);
INIT_LIST_HEAD(&a->steer_exlist);
INIT_LIST_HEAD(&a->btmsteer_exlist);
if (tb[POL_BAND]) {
if (atoi(tb[POL_BAND]->v.string) == 5)
a->band = BAND_5;
else if (atoi(tb[POL_BAND]->v.string) == 2)
a->band = BAND_2;
else
a->band = BAND_UNKNOWN;
} else
a->band = BAND_UNKNOWN;
if (tb[POL_STEER_EXCLUDE]) {
uci_foreach_element(&tb[POL_STEER_EXCLUDE]->v.list, x) {
stax_add_entry(&a->steer_exlist, x->name);
a->num_steer_stas++;
}
}
if (tb[POL_STEER_EXCLUDE_BTM]) {
uci_foreach_element(&tb[POL_STEER_EXCLUDE_BTM]->v.list, x) {
stax_add_entry(&a->btmsteer_exlist, x->name);
a->num_btmsteer_stas++;
}
}
a->util_threshold = atoi(tb[POL_UTIL_TH]->v.string);
a->rcpi_threshold = atoi(tb[POL_RCPI_TH]->v.string);
atoi(tb[POL_RPT_SCAN]->v.string) == 1 ? true : false;
atoi(tb[POL_RPT_ASSOC_FAILS]->v.string) == 1 ?
if (tb[POL_RPT_ASSOC_FAILS_RATE]) {
a->report_sta_assocfails_rate =
atoi(tb[POL_RPT_ASSOC_FAILS_RATE]->v.string);
}
if (tb[POL_RPT_HYS_MARGIN]) {
a->rcpi_hysteresis_margin =
atoi(tb[POL_RPT_HYS_MARGIN]->v.string);
}
atoi(tb[POL_DISALLOW_BSTA_P1]->v.string) == 1 ?
atoi(tb[POL_DISALLOW_BSTA_P2]->v.string) == 1 ?
static void config_map_creds_to_network(struct controller_config *cfg,
struct list_head *credslist)
{
struct iface_credential *cred;
list_for_each_entry(cred, credslist, list) {
struct netif_vlan *vlan;
vlan = cntlr_config_get_vlan_by_name(cfg, cred->network);
if (!vlan)
continue;
cred->br = vlan;
}
}
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
uint8_t cntlr_policy_exlist_diff(struct list_head *prev_policylist,
struct list_head *curr_policylist)
{
uint8_t diff = 0;
struct agent_policy *prev, *curr;
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_config_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 list_head) + sizeof(struct netif_vlan *))
)) {
trace("|%s:%d| bss credentials have changed\n", __func__, __LINE__);
diff |= CONFIG_DIFF_CREDENTIALS;
}
/* vlan diff */
if (prev->num_vlans != cfg->num_vlans) {
dbg("|%s:%d| number of vlan credentials differed\n", __func__, __LINE__);
diff |= CONFIG_DIFF_VLAN;
} else if (list_memcmp(&prev->vlanlist, &cfg->vlanlist,
struct netif_vlan,
(sizeof(struct list_head))
)) {
trace("|%s:%d| vlan credentials have changed\n", __func__, __LINE__);
diff |= CONFIG_DIFF_VLAN;
}
/* 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->policylist, &cfg->policylist,
struct agent_policy,
(sizeof(struct list_head) +
sizeof(struct list_head) +
sizeof(struct list_head) +
sizeof(struct list_head) + sizeof(bool)))) {
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->policylist, &cfg->policylist);
}
return diff;
}
void config_copy_cntlr_config(struct controller_config *curr,
struct controller_config *old)
{
INIT_LIST_HEAD(&old->vlanlist);
INIT_LIST_HEAD(&old->policylist);
old->num_bss = curr->num_bss;
old->num_vlans = curr->num_vlans;
old->num_apolicy = curr->num_apolicy;
list_copy(&curr->aplist, &old->aplist, struct iface_credential);
list_copy(&curr->vlanlist, &old->vlanlist, struct netif_vlan);
list_copy(&curr->policylist, &old->policylist, struct agent_policy);
}
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);