Skip to content
Snippets Groups Projects
config.c 9.7 KiB
Newer Older
  • Learn to ignore specific revisions
  • /*
     * 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 <string.h>
    
    #include <unistd.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"
    
    #include "config.h"
    
    int verbose;
    
    
    void cntlr_config_dump(struct controller_config *c)
    
    	int i;
    
    	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: Fronthaul\n");
    	for (i = 0; i < c->num_fh; i++) {
    		dbg("  Band    : %d\n", c->fh[i].band);
    		dbg("  Security: 0x%x\n", c->fh[i].sec);
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    		dbg("  Key     :\n");
    
    		dbg("  ssid    : %s\n", c->fh[i].ssid);
    		dbg("  vlan    : %d\n\n", c->fh[i].vlanid);
    
    	dbg("Credentials: Backhaul\n");
    	for (i = 0; i < c->num_bk; i++) {
    		dbg("  Band    : %d\n", c->bk[i].band);
    		dbg("  Security: 0x%x\n", c->bk[i].sec);
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    		dbg("  Key     :\n");
    
    		dbg("  ssid    : %s\n", c->bk[i].ssid);
    		dbg("  vlan    : %d\n\n", c->bk[i].vlanid);
    
    	dbg("Agents policy: Default\n");
    
    	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 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("  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);
    
    	dbg("---------------------------\n");
    
    int cntlr_config_defaults(struct controller *cntlr, struct controller_config *c)
    
    	memset(c, 0, sizeof(*c));
    	INIT_LIST_HEAD(&c->policylist);
    
    	return 0;
    
    static int cntlr_config_get_base(struct controller_config *c,
    						struct uci_section *s)
    
    	enum {
    		CNTLR_ENABLED,
    		CNTLR_REGISTRAR,
    
    		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 = "debug", .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;
    
    		c->enabled = atoi(val) == 1 ? true : false;
    
    	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;
    
    	if (tb[CNTLR_DEBUG]) {
    
    		const char *debug = tb[CNTLR_DEBUG]->v.string;
    
    		c->debug_level = atoi(debug);
    
    		if (c->debug_level > verbose)
    			verbose = c->debug_level;
    
    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_MAP,
    		CRED_D_BSTA,
    
    		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 },
    
    	};
    	struct uci_option *tb[NUM_CREDS];
    	struct iface_credential *cred;
    
    	if (!strcmp(s->type, "fh-credentials")) {
    		if (c->num_fh >= 2)
    			return -1;
    
    		cred = &c->fh[c->num_fh++];
    
    		cred->mode = WIFI_MODE_AP;
    
    	} else {
    		if (c->num_bk >= 2)
    			return -1;
    
    		cred = &c->bk[c->num_bk++];
    
    		cred->mode = WIFI_MODE_STA;
    
    	uci_parse_section(s, opts, NUM_CREDS, tb);
    
    	if (tb[CRED_BAND]) {
    		if (atoi(tb[CRED_BAND]->v.string) == 5)
    
    		else if (atoi(tb[CRED_BAND]->v.string) == 2)
    
    	if (tb[CRED_SSID])
    
    		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, "psk3", 4))
    			cred->sec = WIFI_SECURITY_WPA3PSK;
    		else if (!strncmp(sec, "psk2", 4))
    			cred->sec = WIFI_SECURITY_WPA2PSK;
    		else if (!strncmp(sec, "psk", 3))
    			cred->sec = WIFI_SECURITY_WPAPSK;
    
    		//TODO: ciphers (if any)
    	}
    
    	if (tb[CRED_KEY])
    
    		strncpy((char *) cred->key, tb[CRED_KEY]->v.string, 63);
    
    	if (tb[CRED_VLAN])
    		cred->vlanid = atoi(tb[CRED_VLAN]->v.string);
    
    	if (tb[CRED_MAP])
    		cred->multi_ap = atoi(tb[CRED_MAP]->v.string);
    
    	if (tb[CRED_D_BSTA])
    		cred->disallow_bsta = atoi(tb[CRED_D_BSTA]->v.string);
    
    
    	return 0;
    
    static int cntlr_config_get_agent_policy(struct controller_config *c,
    						struct uci_section *s)
    
    	enum {
    
    		POL_AGENT_ID,
    
    		POL_STEER,
    		POL_UTIL_TH,
    		POL_RCPI_TH,
    		POL_RPT_SCAN,
    		POL_RPT_ASSOC_FAILS,
    		POL_RPT_METRIC_PERIODIC,
    		POL_RPT_RCPI_TH,
    		POL_RPT_UTIL_TH,
    		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 = "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_metric_periodic", .type = UCI_TYPE_STRING },
    		{ .name = "report_rcpi_threshold", .type = UCI_TYPE_STRING },
    		{ .name = "report_util_threshold", .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 agent_policy *a;
    
    	a = calloc(1, sizeof(*a));
    	if (!a)
    		return -1;
    
    
    	uci_parse_section(s, opts, NUM_POLICIES, tb);
    
    
    	if (tb[POL_AGENT_ID]) {
    		const char *val = tb[POL_AGENT_ID]->v.string;
    
    		hwaddr_aton(val, a->agent_id);
    
    	if (tb[POL_STEER])
    
    		a->policy = atoi(tb[POL_STEER]->v.string);
    
    	if (tb[POL_UTIL_TH])
    
    		a->util_threshold = atoi(tb[POL_UTIL_TH]->v.string);
    
    	if (tb[POL_RCPI_TH])
    
    		a->rcpi_threshold = atoi(tb[POL_RCPI_TH]->v.string);
    
    	if (tb[POL_RPT_SCAN]) {
    
    		a->report_scan =
    
    			atoi(tb[POL_RPT_SCAN]->v.string) == 1 ? true : false;
    
    	if (tb[POL_RPT_ASSOC_FAILS]) {
    
    		a->report_sta_assocfails =
    
    			atoi(tb[POL_RPT_ASSOC_FAILS]->v.string) == 1 ?
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    					true : false;
    
    	if (tb[POL_RPT_METRIC_PERIODIC]) {
    
    		a->report_metric_periodic =
    
    				atoi(tb[POL_RPT_METRIC_PERIODIC]->v.string);
    
    	if (tb[POL_RPT_RCPI_TH]) {
    
    		a->report_rcpi_threshold =
    
    				atoi(tb[POL_RPT_RCPI_TH]->v.string);
    	}
    
    	if (tb[POL_RPT_UTIL_TH]) {
    
    		a->report_util_threshold =
    
    				atoi(tb[POL_RPT_UTIL_TH]->v.string);
    
    	if (tb[POL_INC_STA_STATS]) {
    
    		a->include_sta_stats =
    
    			atoi(tb[POL_INC_STA_STATS]->v.string) == 1 ?
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    					true : false;
    
    	if (tb[POL_INC_STA_METRIC]) {
    
    		a->include_sta_metric =
    
    			atoi(tb[POL_INC_STA_METRIC]->v.string) == 1 ?
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    					true : false;
    
    	if (tb[POL_PVID])
    
    		a->pvid = atoi(tb[POL_PVID]->v.string);
    
    	if (tb[POL_PCP_DEFAULT])
    
    		a->pcp_default = atoi(tb[POL_PCP_DEFAULT]->v.string);
    
    	if (tb[POL_DISALLOW_BSTA_P1]) {
    
    		a->disallow_bsta_p1 =
    
    			atoi(tb[POL_DISALLOW_BSTA_P1]->v.string) == 1 ?
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    					true : false;
    
    	if (tb[POL_DISALLOW_BSTA_P2]) {
    
    		a->disallow_bsta_p2 =
    
    			atoi(tb[POL_DISALLOW_BSTA_P2]->v.string) == 1 ?
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    					true : false;
    
    	list_add(&a->list, &c->policylist);
    
    	return 0;
    }
    
    int cntlr_config_reload(struct controller_config *cfg)
    
    	struct uci_context *ctx;
    	struct uci_package *pkg;
    
    	struct uci_element *e;
    
    	ctx = uci_alloc_context();
    
    	if (!ctx)
    
    	if (uci_load(ctx, "controller", &pkg)) {
    		uci_free_context(ctx);
    		return -1;
    	}
    
    
    	uci_foreach_element(&pkg->sections, e) {
    		struct uci_section *s = uci_to_section(e);
    
    
    		if (!strcmp(s->type, "wificntlr")) {
    			cntlr_config_get_base(cfg, s);
    		} else if (!strcmp(s->type, "fh-credentials") ||
    				!strcmp(s->type, "bk-credentials")) {
    			cntlr_config_get_credentials(cfg, s);
    		} else if (!strcmp(s->type, "agent-policy")) {
    			cntlr_config_get_agent_policy(cfg, s);
    		}
    
    	uci_free_context(ctx);
    	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) {
    		list_del(&p->list);
    		free(p);
    	}
    
    	return 0;
    }
    
    int cntlr_config_clean(struct controller_config *cfg)
    {
    	clean_agent_policies(cfg);
    
    	return 0;
    }