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 <easy/easy.h> // TODO: remove wifi.h
#include <wifi.h> // TODO: remove wifi.h
#include "debug.h"
#include "utils.h"
#include "config.h"
#include "comm.h"
#include "msgqueue.h"
#include "worker.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))
90
91
92
93
94
95
96
97
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
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);
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);
}
}
175
176
177
178
179
180
181
182
183
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
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;
}
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
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;
int rv;
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;
}
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
308
309
310
311
312
313
314
315
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)
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
{
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 stax *x = NULL;
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("Credentials\n");
list_for_each_entry(cred, &c->bsslist, 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(" Primary VLAN ID : %d\n", c->apolicy.pvid);
dbg(" PCP Default : %d\n", c->apolicy.pcp_default);
dbg(" Disallow bSTA P1 : %d\n", c->apolicy.disallow_bsta_p1);
dbg(" Disallow bSTA P2 : %d\n", c->apolicy.disallow_bsta_p2);
#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);
INIT_LIST_HEAD(&c->bsslist);
static int cntlr_config_get_base(struct controller_config *c,
struct uci_section *s)
enum {
CNTLR_ENABLED,
CNTLR_REGISTRAR,
CNTLR_AL_BRIDGE,
NUM_CNTLR_ATTRS
};
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 = "al_bridge", .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_AL_BRIDGE]) {
const char *iface;
iface = tb[CNTLR_AL_BRIDGE]->v.string;
strncpy(c->al_bridge, iface, sizeof(c->al_bridge) - 1);
} else /* Default to br-lan if non-specfied */
strncpy(c->al_bridge, "br-lan", sizeof(c->al_bridge) - 1);
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 = "vlan", .type = UCI_TYPE_STRING },
[CRED_MAP] = { .name = "multi_ap", .type = UCI_TYPE_STRING },
[CRED_D_BSTA] = { .name = "disallow_bsta", .type = UCI_TYPE_STRING },
[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_MAP]) {
cred->multi_ap = atoi(tb[CRED_MAP]->v.string);
if (cred->multi_ap == 1)
cred->mode = AP_WIFI_BBSS;
else if (cred->multi_ap == 2)
cred->mode = AP_WIFI_FBSS;
else if (cred->multi_ap == 3)
cred->mode = AP_WIFI_COMBINED;
} else {
cred->multi_ap = 2; /* default to fhbss */
}
if (tb[CRED_D_BSTA])
cred->disallow_bsta = atoi(tb[CRED_D_BSTA]->v.string);
if (tb[CRED_ENABLED])
cred->enabled = atoi(tb[CRED_ENABLED]->v.string);
c->num_bss++;
list_add_tail(&cred->list, &c->bsslist);
static struct netif_vlan *cntlr_config_get_vlan_by_id(struct controller_config *cfg,
uint8_t id)
{
struct netif_vlan *vlan;
list_for_each_entry(vlan, &cfg->vlanlist, list) {
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
if (vlan->id == id)
return vlan;
}
return NULL;
}
static int cntlr_config_get_vlan(struct controller_config *c,
struct uci_section *s)
{
enum {
VLAN_NETWORK,
VLAN_PROTO,
VLAN_ID,
VLAN_IP_ADDR,
NUM_OPTS,
};
const struct uci_parse_option opts[] = {
[VLAN_NETWORK] = { .name = "network", .type = UCI_TYPE_STRING },
[VLAN_PROTO] = { .name = "proto", .type = UCI_TYPE_STRING },
[VLAN_ID] = { .name = "id", .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);
if (tb[VLAN_ID]) {
uint8_t id;
id = atoi(tb[VLAN_ID]->v.string);
vlan = cntlr_config_get_vlan_by_id(c, id);
if (!vlan) {
vlan = calloc(1, sizeof(*vlan));
if (!vlan)
return -1;
vlan->id = id;
c->num_vlans++;
list_add(&vlan->list, &c->vlanlist);
}
} else {
dbg("No vlan ID provided with vlan section!\n");
return -1;
}
if (tb[VLAN_NETWORK])
strncpy((char *) vlan->network, tb[VLAN_NETWORK]->v.string,
sizeof(vlan->network) - 1);
else
strncpy((char *) vlan->network, "br-lan", sizeof(vlan->network) - 1);
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_PVID,
POL_PCP_DEFAULT,
POL_DISALLOW_BSTA_P1,
POL_DISALLOW_BSTA_P2,
NUM_POLICIES,
};
const struct uci_parse_option opts[] = {
{ .name = "agent_id", .type = UCI_TYPE_STRING },
{ .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 = "pvid", .type = UCI_TYPE_STRING },
{ .name = "pcp_default", .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;
a = calloc(1, sizeof(*a));
if (!a)
return -1;
c->num_apolicy++;
INIT_LIST_HEAD(&a->steer_exlist);
INIT_LIST_HEAD(&a->btmsteer_exlist);
uci_parse_section(s, opts, NUM_POLICIES, tb);
if (tb[POL_AGENT_ID]) {
const char *val = tb[POL_AGENT_ID]->v.string;
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);
}
a->pcp_default = atoi(tb[POL_PCP_DEFAULT]->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_vlan(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_id(cfg, cred->vlanid);
if (!vlan)
continue;
cred->br = vlan;
}
}
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
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->bsslist, &cfg->bsslist,
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;
} else if (list_policy_memcmp(&prev->policylist, &cfg->policylist,
struct agent_policy, (sizeof(struct list_head) +
sizeof(struct list_head) + sizeof(struct list_head)))) {
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->bsslist);
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->bsslist, &old->bsslist, 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);
/* reset counters */
cfg->num_bss = cfg->num_vlans = 0;
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, "bss")) {
cntlr_config_get_credentials(cfg, s);
} else if (!strcmp(s->type, "agent-policy")) {
cntlr_config_get_agent_policy(cfg, s);
} else if (!strcmp(s->type, "vlan")) {
cntlr_config_get_vlan(cfg, s);
/* link credentials to their respective vlan sections */
config_map_creds_to_vlan(cfg, &cfg->bsslist);
/* get bitmap of what sections changed */
diff = cntlr_config_diff(cfg, &old);
/* clean old lists */
clean_credslist(&old.bsslist);
clean_vlanlist(&old.vlanlist);
clean_agent_policies(&old);
int cntlr_config_clean(struct controller_config *cfg)
{
clean_bridgelist(cfg);
clean_credslist(&cfg->bsslist);