Skip to content
Snippets Groups Projects
config.c 47.4 KiB
Newer Older
  • Learn to ignore specific revisions
  • 	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;
    	}
    
    
    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_TYPE,
    
    		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 = "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;
    
    	uci_parse_section(s, opts, NUM_CREDS, tb);
    
    	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)
    
    		else if (atoi(tb[CRED_BAND]->v.string) == 2)
    
    Janusz Dziedzic's avatar
    Janusz Dziedzic committed
    		else if (atoi(tb[CRED_BAND]->v.string) == 6)
    			cred->band = BAND_6;
    
    		else
    			cred->band = BAND_UNKNOWN;
    	} else
    		cred->band = BAND_UNKNOWN;
    
    	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, "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);
    
    
    		//TODO: ciphers (if any)
    
    	} else {
    		use_default_security = true;
    
    	if (tb[CRED_KEY])
    
    		strncpy((char *) cred->key, tb[CRED_KEY]->v.string, 64);
    
    		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->multi_ap = 1;
    
    			cred->mode = AP_WIFI_BBSS;
    
    		} else if (!strcmp(type, "fronthaul")) {
    
    			cred->multi_ap = 2;
    
    			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 */
    
    		cred->mode = AP_WIFI_FBSS;
    
    	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;
    
    
    Saurabh Verma's avatar
    Saurabh Verma committed
    		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;
    
    	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
    
    		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;
    			}
    
    
    				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);
    			}
    
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    
    	cntlr_config_get_wsc_attributes(c, cred);
    
    
    	list_add_tail(&cred->list, &c->aplist);
    
    	return 0;
    
    struct node_policy *cntlr_config_get_node_by_mac(struct controller_config *cfg,
    							uint8_t *macaddr)
    {
    
    Saurabh Verma's avatar
    Saurabh Verma committed
    	struct node_policy *node = NULL;
    
    
    	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,
    
    						struct uci_section *s)
    
    	enum {
    
    		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 uci_option *tb[NUM_POLICIES];
    
    	uci_parse_section(s, opts, NUM_POLICIES, tb);
    
    
    		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 = 0;
    
    	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);
    
    	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);
    
    	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;
    
    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,
    
    #if (EASYMESH_VERSION > 2)
    
    		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 },
    
    #if (EASYMESH_VERSION > 2)
    
    		{ .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;
    
    
    	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;
    
    	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);
    
    
    		/* 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;
    	}
    
    		/* override default value from steer section in config */
    
    		a->report_rcpi_threshold =
    
    				atoi(tb[RADIO_RPT_RCPI_TH]->v.string);
    
    	if (tb[RADIO_RPT_UTIL_TH]) {
    
    		a->report_util_threshold =
    
    				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]) {
    
    		a->include_sta_stats =
    
    			atoi(tb[RADIO_INC_STA_STATS]->v.string) == 1 ?
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    					true : false;
    
    	if (tb[RADIO_INC_STA_METRIC]) {
    
    		a->include_sta_metric =
    
    			atoi(tb[RADIO_INC_STA_METRIC]->v.string) == 1 ?
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    					true : false;
    
    #if (EASYMESH_VERSION > 2)
    
    	if (tb[RADIO_INC_WIFI6_STA_STATUS]) {
    		a->include_wifi6_sta_status =
    			atoi(tb[RADIO_INC_WIFI6_STA_STATUS]->v.string) == 1 ?
    					true : false;
    	}
    
    	return 0;
    }
    
    #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)
    {
    
    Saurabh Verma's avatar
    Saurabh Verma committed
    	struct radio_policy *r = NULL, *tmp;
    
    
    	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;
    
    
    	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;
    
    	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;
    
    
    	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,
    
    				(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 ||
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    	    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->radiolist);
    
    	INIT_LIST_HEAD(&old->nodelist);
    
    	INIT_LIST_HEAD(&old->aplist);
    
    	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 (!ctx)
    
    	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")) {
    
    			cntlr_config_get_base(cfg, s);
    
    		} else if (!strcmp(s->type, "sta_steering")) {
    			cntlr_config_get_steer_params(cfg, s);
    
    		} else if (!strcmp(s->type, "ap")) {
    
    			cntlr_config_get_credentials(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
    
    	/* get bitmap of what sections changed */
    	diff = cntlr_config_diff(cfg, &old);
    
    	clean_cred_list(&old);
    	clean_agent_policies(&old); /* cleans nodelist */
    
    	clean_radio_list(&old.radiolist);
    
    	uci_free_context(ctx);
    
    int cntlr_config_clean(struct controller_config *cfg)
    {
    
    Filip Matusiak's avatar
    Filip Matusiak committed
    	clean_scclist_list(cfg);
    
    	clean_cred_list(cfg);
    	clean_agent_policies(cfg); /* cleans nodelist */
    
    	clean_radio_list(&cfg->radiolist);