Skip to content
Snippets Groups Projects
config.c 63.8 KiB
Newer Older
  • Learn to ignore specific revisions
  • 	uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE, "ifname",
    
    			interface_name, "ssid", (char *) ssid);
    
    	uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE, "ifname",
    
    			interface_name, "key", (char *) network_key);
    
    	uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE, "ifname",
    
    			interface_name, "encryption", auth_type_str);
    
    	uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE, "ifname",
    
    	uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE, "ifname",
    
    	uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE, "ifname",
    
    	uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE,	"ifname",
    			interface_name, "ieee80211k", "1");
    	uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE,	"ifname",
    			interface_name, "ieee80211v", "1");
    
    	if (mfp > 0) {
    		uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE,
    				"ifname", interface_name,
    				"ieee80211w", mfp == 1 ? "1" : "2");
    	}
    
    	uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE, "ifname",
    
    			interface_name, "start_disabled", (exts->enabled ? "0" : "1"));
    
    
    
    	dbg("|%s:%d| Enabled interface %s\n", __func__, __LINE__,
    			interface_name);
    
    
    	do {
    		char buf[512] = {0};
    		char basemacstr[18] = {0};
    		uint8_t basemac[6] = {0};
    		//uint8_t uuid[16] = {0};
    
    		chrCmd(buf, sizeof(buf), "db -q get hw.board.basemac");
    		if (buf[0] != '\0' && strlen(buf) == 17)
    			strncpy(basemacstr, buf, 17);
    
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    		dbg("basemac: %s\n", basemacstr);
    
    		hwaddr_aton(buf, basemac);
    
    		memset(buf, 0, sizeof(buf));
    		chrCmd(buf, sizeof(buf),
    		       "uuidgen -s --namespace @dns --name www.iopsys.eu");
    
    		if (buf[0] == '\0' || strlen(buf) != 36) {
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    			dbg("uuidgen error!\n");
    
    			//TODO
    		}
    
    		snprintf(buf + 24, 13, "%02x%02x%02x%02x%02x%02x", MAC2STR(basemac));
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    		dbg("UUID: %s\n", buf);
    
    		uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE,	"ifname",
    			interface_name, "uuid", buf);
    	} while(0);
    
    		uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE,
    
    			"ifname", interface_name, "hidden", "1");
    	} else {
    		uci_set_wireless_interface_option(UCI_WIRELESS,
    			UCI_WLAN_IFACE,	"ifname", interface_name, "wps", "1");
    		uci_set_wireless_interface_option(UCI_WIRELESS,
    			UCI_WLAN_IFACE,	"ifname", interface_name,
    			"wps_pushbutton", "1");
    
    
    	/* TODO: don't support guest network for the moment */
    	//uci_add_dhcp(bridge);
    	//uci_add_fw(cfg, bridge);
    
    
    	return M2_PROCESS_OK;
    }
    /* end of functions taken from ieee1905d */
    
    
    static struct netif_bkcfg *get_netif_bkcfg_by_name(struct agent_config *c,
    
    		const char *name)
    
    {
    	struct netif_bkcfg *p;
    
    	list_for_each_entry(p, &c->bklist, list) {
    		if (!strcmp(name, p->name))
    			return p;
    	}
    
    	return NULL;
    }
    
    
    Anjan Chanda's avatar
    Anjan Chanda committed
    static struct netif_fhcfg *get_netif_fhcfg_by_name(struct agent_config *c,
    							const char *name)
    {
    	struct netif_fhcfg *p;
    
    	list_for_each_entry(p, &c->fhlist, list) {
    		if (!strcmp(name, p->name))
    			return p;
    	}
    
    	return NULL;
    }
    
    static struct steer_policy *get_steer_policy_by_name(struct netif_fhcfg *c,
    							const char *name)
    {
    	struct steer_policy *p;
    
    	if (!c)
    		return NULL;
    
    	list_for_each_entry(p, &c->steer_policylist, list) {
    		if (!strcmp(name, p->name))
    			return p;
    	}
    
    	return NULL;
    }
    
    
    static struct agent_config_radio *get_agent_config_radio(struct agent_config *c,
    							const char *ifname)
    {
    	struct agent_config_radio *p;
    
    	list_for_each_entry(p, &c->radiolist, list) {
    		if (!strcmp(ifname, p->name))
    			return p;
    	}
    
    	return NULL;
    }
    
    
    Anjan Chanda's avatar
    Anjan Chanda committed
    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);
    	}
    }
    
    void stax_del_entry(struct list_head *h, char *sta_macstr)
    {
    	struct stax *s, *tmp;
    
    	list_for_each_entry_safe(s, tmp, h, list) {
    		if (!strncmp(s->macstring, sta_macstr, sizeof(s->macstring))) {
    			list_del(&s->list);
    			free(s);
    			return;
    		}
    	}
    }
    
    
    static int clean_steer_btm_excl(struct agent_config *p)
    
    {
    	struct stax *n, *tmp;
    
    	list_for_each_entry_safe(n, tmp, &p->steer_btm_excludelist, list) {
    		list_del(&n->list);
    		free(n);
    	}
    
    	return 0;
    }
    
    static int clean_steer_excl(struct agent_config *p)
    
    {
    	struct stax *n, *tmp;
    
    	list_for_each_entry_safe(n, tmp, &p->steer_excludelist, list) {
    		list_del(&n->list);
    		free(n);
    	}
    
    	return 0;
    }
    
    
    Anjan Chanda's avatar
    Anjan Chanda committed
    void agent_config_dump(struct agent_config *cfg)
    {
    	struct netif_fhcfg *n;
    	struct steer_policy *pol;
    	struct stax *x;
    
    	if (!cfg)
    		return;
    
    
    	dbg("  Steer Exclude Lists -------\n");
    	list_for_each_entry(x, &cfg->steer_excludelist, list) {
    		dbg("    mac: %s\n", x->macstring);
    	}
    
    	dbg("  Steer BTM Exclude Lists -------\n");
    	list_for_each_entry(x, &cfg->steer_btm_excludelist, list) {
    		dbg("    mac: %s\n", x->macstring);
    	}
    
    
    Anjan Chanda's avatar
    Anjan Chanda committed
    	list_for_each_entry(n, &cfg->fhlist, list) {
    		dbg("name: %s\n", n->name);
    		dbg("  enabled  : %s\n", n->enabled ? "true" : "false");
    		dbg("  assocctrl: %s\n", n->assoc_control ? "true" : "false");
    
    		dbg("  Policies -------\n");
    		list_for_each_entry(pol, &n->steer_policylist, list) {
    			dbg("    name: %s\n", pol->name);
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    			dbg("    enabled  : %s\n",
    					pol->enabled ? "true" : "false");
    
    Anjan Chanda's avatar
    Anjan Chanda committed
    			/* if (pol->dump_config)
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    			 *	pol->dump_config(pol, pol->policy);
    			 */
    
    Anjan Chanda's avatar
    Anjan Chanda committed
    		}
    
    		dbg("  Assoc Ctrl Lists -------\n");
    		list_for_each_entry(x, &n->assoc_ctrllist, list) {
    			dbg("    mac: %s\n", x->macstring);
    		}
    	}
    }
    
    /* create fh-iface config and initialize with default values */
    struct netif_fhcfg *create_fronthaul_iface_config(struct agent_config *cfg,
    							const char *ifname)
    {
    	struct netif_fhcfg *new;
    	struct steer_rule *r;
    
    	if (!cfg)
    		return NULL;
    
    	new = calloc(1, sizeof(struct netif_fhcfg));
    	if (!new) {
    		warn("OOM! config\n");
    		return NULL;
    	}
    
    	snprintf(new->name, 16, "%s", ifname);
    	new->enabled = true;
    	new->fallback_legacy = STEER_LEGACY_FALLBACK_INT;
    	new->steer_btm_retry_secs = STEER_BTM_RETRY_INT;
    	new->steer_legacy_reassoc_secs = STEER_LEGACY_REASSOC_INT;
    	new->steer_legacy_retry_secs = STEER_LEGACY_RETRY_INT;
    	new->assoc_control_time = ASSOC_CONTROL_INT;
    
    	new->band = BAND_UNKNOWN;
    
    Anjan Chanda's avatar
    Anjan Chanda committed
    	INIT_LIST_HEAD(&new->steer_policylist);
    	/* nrules = get_registered_steer_rules(&pollist); */ /* TODO */
    	list_for_each_entry(r, &regd_steer_rules, list) {
    		struct steer_policy *pol;
    
    		pol = calloc(1, sizeof(struct steer_policy));
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    		if (!pol)
    
    Anjan Chanda's avatar
    Anjan Chanda committed
    			goto err_oom;
    
    		snprintf(pol->name, 16, "%s", r->name);
    		pol->enabled = false;
    		if (r->init_config)
    			r->init_config(r, &pol->policy);
    		list_add(&pol->list, &new->steer_policylist);
    	}
    
    	INIT_LIST_HEAD(&new->assoc_ctrllist);
    
    	/* f->cfg = new; */
    	dbg("%s: %s netif_fh->cfg = %p\n", __func__, new->name, new);
    
    	list_add(&new->list, &cfg->fhlist);
    
    	return new;
    
    err_oom:
    	list_flush(&new->steer_policylist, struct steer_policy, list);
    	free(new);
    	return NULL;
    }
    
    
    /* create fh-iface config and initialize with default values */
    struct netif_bkcfg *create_backhaul_iface_config(struct agent_config *cfg,
    							const char *ifname)
    
    Anjan Chanda's avatar
    Anjan Chanda committed
    {
    
    	struct netif_bkcfg *new;
    
    Anjan Chanda's avatar
    Anjan Chanda committed
    
    
    Anjan Chanda's avatar
    Anjan Chanda committed
    
    
    	new = calloc(1, sizeof(struct netif_bkcfg));
    	if (!new) {
    		warn("OOM! config\n");
    		return NULL;
    	}
    
    Anjan Chanda's avatar
    Anjan Chanda committed
    
    
    	snprintf(new->name, 16, "%s", ifname);
    	new->enabled = true;
    	new->onboarded = false;
    
    	new->band = BAND_UNKNOWN;
    
    Anjan Chanda's avatar
    Anjan Chanda committed
    
    
    	/* f->cfg = new; */
    	dbg("%s: %s netif_fh->cfg = %p\n", __func__, new->name, new);
    
    Anjan Chanda's avatar
    Anjan Chanda committed
    
    
    	list_add(&new->list, &cfg->bklist);
    
    Anjan Chanda's avatar
    Anjan Chanda committed
    
    
    Anjan Chanda's avatar
    Anjan Chanda committed
    }
    
    static void config_update_entry(struct uci_context *ctx, struct uci_package *p,
    				struct uci_section *s, const char *optname,
    				int add, void *val, int len)
    {
    	struct uci_ptr ptr;
    
    	memset(&ptr, 0, sizeof(struct uci_ptr));
    	ptr.p = p;
    	ptr.s = s;
    	ptr.package = p->e.name;
    	ptr.section = s->e.name;
    	ptr.option = optname;
    	ptr.target = UCI_TYPE_OPTION;
    	ptr.flags |= UCI_LOOKUP_EXTENDED;
    	ptr.value = (char *)val;
    
    	if (add) {
    		dbg("config: add list option: %s\n", (char *)val);
    		uci_add_list(ctx, &ptr);
    	} else {
    		dbg("config: del list option: %s\n", (char *)val);
    		uci_del_list(ctx, &ptr);
    	}
    	uci_commit(ctx, &p, false);
    }
    
    int config_update(const char *confname, struct agent_config *cfg,
    			const char *section, const char *option,
    			int add,
    			void *value, int len)
    {
    	struct uci_context *ctx = NULL;
    	struct uci_package *pkg = NULL;
    	struct uci_element *e;
    
    	ctx = uci_alloc_context();
    	if (ctx && uci_load(ctx, confname, &pkg) != UCI_OK) {
    		dbg("config file '%s' not found!\n", confname);
    		free(ctx);
    		return -1;
    	}
    
    	uci_foreach_element(&pkg->sections, e) {
    		struct uci_section *s = uci_to_section(e);
    		struct uci_element *x, *tmp;
    		struct uci_option *op;
    
    		if (strcmp(s->type, section))
    			continue;
    
    		/* iter through matched 'section' for the 'option' */
    		uci_foreach_element_safe(&s->options, tmp, x) {
    			if (strcmp(x->name, option))
    				continue;
    
    			op = uci_to_option(x);
    			if (op->type == UCI_TYPE_LIST) {
    				uci_foreach_element(&op->v.list, x) {
    					if (!strncmp(x->name, value, len)) {
    						if (!add)
    							config_update_entry(ctx,
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    								pkg, s,
    								option, 0,
    								value, len);
    
    Anjan Chanda's avatar
    Anjan Chanda committed
    
    						goto out_exit;
    					}
    				}
    				/* add new exclude at end of list */
    				if (add)
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    					config_update_entry(ctx, pkg, s, option,
    							1, value, len);
    
    Anjan Chanda's avatar
    Anjan Chanda committed
    
    				goto out_exit;
    			}
    		}
    		/* 'option' name not present in 'section'
    		 * Create a new one at end of 'section'.
    		 */
    		if (add)
    			config_update_entry(ctx, pkg, s, option, 1, value, len);
    
    		goto out_exit;
    	}
    out_exit:
    	uci_free_context(ctx);
    	return 0;
    }
    
    int config_update2(const char *confname, struct agent_config *cfg,
    		const char *section_type,
    		const char *match_option,
    		const char *match_option_value,
    		const char *option,
    		int add,
    		void *value, int len)
    {
    	struct uci_context *ctx = NULL;
    	struct uci_package *pkg = NULL;
    	struct uci_element *e;
    
    	ctx = uci_alloc_context();
    	if (ctx && uci_load(ctx, confname, &pkg) != UCI_OK) {
    		dbg("config file '%s' not found!\n", confname);
    		free(ctx);
    		return -1;
    	}
    
    	uci_foreach_element(&pkg->sections, e) {
    		struct uci_section *s = uci_to_section(e);
    		struct uci_element *x, *tmp;
    		struct uci_option *op;
    		const char *optstring;
    
    		if (strcmp(s->type, section_type))
    			continue;
    
    		if (match_option && match_option_value) {
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    			optstring = uci_lookup_option_string(ctx, s,
    				match_option);
    
    Anjan Chanda's avatar
    Anjan Chanda committed
    			if (!optstring || strcmp(optstring, match_option_value))
    				continue;
    		}
    
    		/* iter through matched 'section' for the 'option' */
    		uci_foreach_element_safe(&s->options, tmp, x) {
    			if (strcmp(x->name, option))
    				continue;
    
    			op = uci_to_option(x);
    			if (op->type == UCI_TYPE_LIST) {
    				uci_foreach_element(&op->v.list, x) {
    					if (!strncmp(x->name, value, len)) {
    						if (!add) {
    							config_update_entry(ctx,
    								pkg, s, option,
    								0, value, len);
    						}
    
    						goto out_exit;
    					}
    				}
    				/* add new 'option' at end of list */
    				if (add) {
    					config_update_entry(ctx, pkg, s, option,
    								1, value, len);
    				}
    
    				goto out_exit;
    			}
    		}
    		/* 'option' name not present in 'section'
    		 * Create a new one at end of 'section'.
    		 */
    		if (add)
    			config_update_entry(ctx, pkg, s, option,
    							1, value, len);
    
    		goto out_exit;
    	}
    out_exit:
    	uci_free_context(ctx);
    	return 0;
    }
    
    
    #if 0
    struct config uci_config = {
    	.name = "uci",
    	.priv = uci_ctx;
    	.get = uci_get_config,
    	.set = uci_set_config,
    	.init = uci_setup,
    	.exit = uci_exit,
    };
    
    #define priv_get_config(priv)	container_of(priv, struct config, priv)
    
    void register_config(struct config *c)
    {
    	static struct uci_context *ctx;
    	static struct uci_package *pkg;
    	struct uci_element *e;
    	int ret = 0;
    
    	if (uci_ctx)
    		return priv_get_config(uci_ctx);
    
    	ctx = uci_alloc_context();
    	if (ctx) {
    		uci_ctx = ctx;
    		memcpy(c, &uci_config, sizeof(*cfg));
    	}
    	if (uci_load(ctx, "wifiagent", &pkg))
    		return -1;
    
    	uci_foreach_element(&pkg->sections, e) {
    		struct uci_section *s = uci_to_section(e);
    		const char *option_val;
    
    		if (strcmp(s->type, "wifiagent"))
    			continue;
    
    		option_val = uci_lookup_option_string(ctx, s, name);
    		if (option_val)
    			sprintf(val, "%s", option_val);
    		else
    			ret = -1;
    	}
    	uci_free_context(ctx);
    	return ret;
    
    }
    #endif
    
    static int agent_config_get_wifi_agent(struct agent_config *a,
    
    		A_PROFILE,
    
    		NUM_POLICIES
    	};
    	const struct uci_parse_option opts[] = {
    		{ .name = "enabled", .type = UCI_TYPE_STRING },
    
    		{ .name = "debug", .type = UCI_TYPE_STRING },
    
    		{ .name = "profile", .type = UCI_TYPE_STRING },
    
    		{ .name = "brcm_setup", .type = UCI_TYPE_STRING },
    		/*{ .name = "configured", .type = UCI_TYPE_STRING },*/
    		{ .name = "controller_macaddr", .type = UCI_TYPE_STRING },
    
    		{ .name = "exclude", .type = UCI_TYPE_LIST },
    		{ .name = "exclude_btm", .type = UCI_TYPE_LIST },
    
    		{ .name = "al_bridge", .type = UCI_TYPE_STRING },
    
    		{ .name = "netdev", .type = UCI_TYPE_STRING },
    
    	};
    	struct uci_option *tb[NUM_POLICIES];
    
    	uci_parse_section(s, opts, NUM_POLICIES, tb);
    
    	if (tb[A_ENABLED])
    		a->enabled = atoi(tb[A_ENABLED]->v.string) == 1 ? true : false;
    
    
    	if (tb[A_DEBUG]) {
    		a->debug_level = atoi(tb[A_DEBUG]->v.string);
    		if (verbose < a->debug_level)
    			verbose = a->debug_level;
    	}
    
    
    	if (tb[A_PROFILE])
    		a->profile = atoi(tb[A_PROFILE]->v.string);
    
    
    	if (tb[A_BRCM_SETUP])
    		a->brcm_setup = atoi(tb[A_BRCM_SETUP]->v.string);
    
    	/*if (tb[A_CONFIGURED])
    		a->configured = atoi(tb[A_CONFIGURED]->v.string);*/
    
    	if (tb[A_CNTLR_MAC])
    		hwaddr_aton(tb[A_CNTLR_MAC]->v.string, a->cntlr_almac);
    
    
    	if (tb[A_EXCLUDE]) {
    		struct uci_element *xi;
    
    		dbg("Steer: exclude: ");
    		uci_foreach_element(&tb[A_EXCLUDE]->v.list, xi) {
    			dbg("%s ", xi->name);
    			stax_add_entry(&a->steer_excludelist, xi->name);
    		}
    		dbg("\n");
    	}
    
    	if (tb[A_EXCLUDE_BTM]) {
    		struct uci_element *xi;
    
    		dbg("Steer: exclude_btm: ");
    		uci_foreach_element(&tb[A_EXCLUDE_BTM]->v.list, xi) {
    			dbg("%s ", xi->name);
    			stax_add_entry(&a->steer_btm_excludelist, xi->name);
    		}
    		dbg("\n");
    	}
    
    
    	if (tb[A_AL_BRIDGE]) {
    		const char *iface;
    
    		iface = tb[A_AL_BRIDGE]->v.string;
    		strncpy(a->al_bridge, iface, sizeof(a->al_bridge) - 1);
    	} else /* Default to br-lan if non-specfied */
    		strncpy(a->al_bridge, "br-lan", sizeof(a->al_bridge) - 1);
    
    
    	if (tb[A_NETDEV]) {
    		const char *ifname;
    		ifname = tb[A_NETDEV]->v.string;
    		strncpy(a->netdev, ifname, sizeof(a->netdev) - 1);
    	} else { /* Default to wl/wlan if not specfied */
    		strncpy(a->netdev, (a->brcm_setup)?"wl":"wlan", sizeof(a->netdev) - 1);
    	}
    
    
    static int agent_config_get_controller_select(struct agent_config *a,
    				       struct uci_section *s)
    {	enum {
    		CTRL_SELECT_LOCAL,
    		CTRL_SELECT_ID,
    		CTRL_SELECT_PROBE_INT,
    		CTRL_SELECT_RETRY_INT,
    		CTRL_SELECT_AUTOSTART,
    		NUM_CTRL_SELECT_POLICIES,
    	};
    
    	const struct uci_parse_option opts[] = {
    		{ .name = "local", .type = UCI_TYPE_STRING },
    		{ .name = "id", .type = UCI_TYPE_STRING },
    		{ .name = "probe_int", .type = UCI_TYPE_STRING },
    		{ .name = "retry_int", .type = UCI_TYPE_STRING },
    		{ .name = "autostart", .type = UCI_TYPE_STRING },
    	};
    
    	struct uci_option *tb[NUM_CTRL_SELECT_POLICIES];
    	struct ctrl_select_cfg *cscfg;
    
    	uci_parse_section(s, opts, NUM_CTRL_SELECT_POLICIES, tb);
    
    	cscfg = (struct ctrl_select_cfg *)calloc(1, sizeof(struct ctrl_select_cfg));
    	if (!cscfg)
    		return -1;
    
    
    	if (!tb[CTRL_SELECT_LOCAL]) {
    		warn("Required option 'local' not found!\n");
    
    		free(cscfg);
    
    		return -1;
    	}
    	cscfg->local = atoi(tb[CTRL_SELECT_LOCAL]->v.string);
    
    		cscfg->auto_detect = true;
    		if (strncmp(tb[CTRL_SELECT_ID]->v.string, "auto", 4)) {
    			cscfg->auto_detect = false;
    			hwaddr_aton(tb[CTRL_SELECT_ID]->v.string, cscfg->alid);
    		}
    	}
    	if (tb[CTRL_SELECT_PROBE_INT])
    		cscfg->probe_int = atoi(tb[CTRL_SELECT_PROBE_INT]->v.string);
    	if (tb[CTRL_SELECT_RETRY_INT])
    		cscfg->retry_int = atoi(tb[CTRL_SELECT_RETRY_INT]->v.string);
    	if (tb[CTRL_SELECT_AUTOSTART])
    		cscfg->autostart = atoi(tb[CTRL_SELECT_AUTOSTART]->v.string);
    
    	if (a->cscfg)
    		free(a->cscfg);
    	a->cscfg = cscfg;
    
    	return 0;
    }
    
    
    static int agent_config_get_wifi_radio(struct agent_config *a,
    				       struct uci_section *s)
    {
    	enum {
    		WIFI_RADIO_DEVICE,
    		WIFI_RADIO_BAND,
    		WIFI_RADIO_CONFIGURED,
    		WIFI_RADIO_ONBOARDED,
    
    		NUM_WIFI_RADIO_POLICIES,
    	};
    	const struct uci_parse_option opts[] = {
    		{ .name = "device", .type = UCI_TYPE_STRING },
    		{ .name = "band", .type = UCI_TYPE_STRING },
    		{ .name = "configured", .type = UCI_TYPE_STRING },
    		{ .name = "onboarded", .type = UCI_TYPE_STRING },
    
    		{ .name = "dedicated_backhaul", .type = UCI_TYPE_STRING },
    
    	};
    	struct uci_option *tb[NUM_WIFI_RADIO_POLICIES];
    	const char *ifname = NULL;
    	uint32_t band = 0;
    	struct agent_config_radio *n;
    
    	uci_parse_section(s, opts, NUM_WIFI_RADIO_POLICIES, tb);
    
    	if (!tb[WIFI_RADIO_DEVICE] || !tb[WIFI_RADIO_BAND]) {
    		warn("No radio name or band option found!\n");
    		return -1;
    	}
    
    	if (tb[WIFI_RADIO_DEVICE])
    		ifname = tb[WIFI_RADIO_DEVICE]->v.string;
    
    	if (tb[WIFI_RADIO_BAND]) {
    		band = atoi(tb[WIFI_RADIO_BAND]->v.string);
    		if (band != 2 && band != 5) {
    			warn("Incorrect band '%d' in config\n", band);
    			return -1;
    		}
    	}
    
    	if (ifname && band) {
    
    		n = get_agent_config_radio(a, ifname);
    
    			n = calloc(1, sizeof(*n));
    			if (!n) {
    				warn("-ENOMEM!\n");
    				return -1;
    			}
    
    			list_add_tail(&n->list, &a->radiolist);
    
    		strncpy(n->name, ifname, 16);
    		n->name[15] = '\0';
    		n->band = band;
    	}
    
    	if (tb[WIFI_RADIO_CONFIGURED]) {
    		n->configured = atoi(tb[WIFI_RADIO_CONFIGURED]->v.string) == 1 ?
    								true : false;
    	}
    
    
    	if (tb[WIFI_RADIO_DEDICATED]) {
    
    		n->dedicated_backhaul = atoi(tb[WIFI_RADIO_DEDICATED]->v.string) == 1 ?
    
    static int agent_config_get_bk_iface(struct agent_config *a,
    
    		BK_BAND,
    
    		BK_ENABLED,
    		BK_ONBOARDED,
    
    		BK_DISALLOWED_BSTA_P1,
    		BK_DISALLOWED_BSTA_P2,
    
    		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 = "enabled", .type = UCI_TYPE_STRING },
    
    		{ .name = "onboarded", .type = UCI_TYPE_STRING },
    		{ .name = "ssid", .type = UCI_TYPE_STRING },
    		{ .name = "key", .type = UCI_TYPE_STRING },
    
    		{ .name = "encryption", .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 netif_bkcfg *bk;
    	const char *ifname;
    
    	uci_parse_section(s, opts, NUM_POLICIES, tb);
    
    	if (tb[BK_IFNAME]) {
    		ifname = tb[BK_IFNAME]->v.string;
    		bk = get_netif_bkcfg_by_name(a, ifname);
    		if (!bk) {
    			bk = create_backhaul_iface_config(a, ifname);
    			if (!bk) {
    				warn("%s: OOM!\n", __func__);
    				return -1;
    			}
    		} else {
    			warn("Duplicate 'bk-iface %s' config!! ignore\n",
    					ifname);
    		}
    	} else {
    		warn("No ifname in bk-iface section!\n");
    		return -1;
    	}
    
    
    	if (tb[BK_DEVICE]) {
    		const char *device;
    
    		device = tb[BK_DEVICE]->v.string;
    		strncpy(bk->device, device, sizeof(bk->device) - 1);
    	}
    
    
    	if (tb[BK_ENABLED])
    		bk->enabled = atoi(tb[BK_ENABLED]->v.string);
    
    	if (tb[BK_ONBOARDED])
    		bk->onboarded = atoi(tb[BK_ONBOARDED]->v.string);
    
    
    	if (tb[BK_BAND]) {
    		int band = atoi(tb[BK_BAND]->v.string);
    
    		if (band == 2)
    			bk->band = BAND_2;
    		else if (band == 5)
    			bk->band = BAND_5;
    	}
    
    
    	if (tb[BK_SSID]) {
    		const char *ssid;
    
    		ssid = tb[BK_SSID]->v.string;
    		strncpy(bk->ssid, ssid, sizeof(bk->ssid) - 1);
    	}
    
    	if (tb[BK_KEY]) {
    		const char *key;
    
    		key = tb[BK_KEY]->v.string;
    		strncpy(bk->key, key, sizeof(bk->key) - 1);
    	}
    
    	if (tb[BK_ENCRYPTION]) {
    		const char *encryption;
    
    		encryption = tb[BK_ENCRYPTION]->v.string;
    		strncpy(bk->encryption, encryption, sizeof(bk->encryption) - 1);
    	}
    
    
    	if (tb[BK_DISALLOWED_BSTA_P1])
    		bk->disallowed_bsta_p1 =
    			atoi(tb[BK_DISALLOWED_BSTA_P1]->v.string);
    
    	if (tb[BK_DISALLOWED_BSTA_P2])
    		bk->disallowed_bsta_p2 =
    			atoi(tb[BK_DISALLOWED_BSTA_P2]->v.string);
    
    
    static int agent_config_get_fh_iface(struct agent_config *a,
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    		struct uci_section *s)
    
    		FH_BAND,
    
    		FH_ASSOC_CTRL,
    		FH_BTM_RETRY,
    		FH_BTM_RETRY_SECS,
    		FH_FLBK_LEGACY,
    		FH_STEER_LEGACY_RASSOC_SECS,
    		FH_STEER_LEGACY_RETRY_SECS,
    		FH_ASSOC_CTRL_SECS,
    
    		FH_POLICY,
    		FH_UTIL_THRESHOLD,
    		FH_RCPI_THRESHOLD,
    		FH_REPORT_RCPI_THRESHOLD,
    		FH_RCPI_HYSTERESIS_MARGIN,
    		FH_REPORT_UTIL_THRESHOLD,
    		FH_INCLUDE_STA_STATS,
    		FH_INCLUDE_STA_METRIC,
    
    		NUM_POLICIES,
    	};
    	const struct uci_parse_option opts[] = {
    		{ .name = "ifname", .type = UCI_TYPE_STRING },
    
    		{ .name = "band", .type = UCI_TYPE_STRING },
    
    		{ .name = "steer", .type = UCI_TYPE_LIST },
    
    		{ .name = "device", .type = UCI_TYPE_STRING },
    
    		{ .name = "assoc_ctrl", .type = UCI_TYPE_LIST },
    
    		{ .name = "btm_retry", .type = UCI_TYPE_STRING },
    		{ .name = "btm_retry_secs", .type = UCI_TYPE_STRING },
    		{ .name = "fallback_legacy", .type = UCI_TYPE_STRING },
    		{ .name = "steer_legacy_reassoc_secs", .type = UCI_TYPE_STRING },
    		{ .name = "steer_legacy_retry_secs", .type = UCI_TYPE_STRING },
    
    		{ .name = "assoc_ctrl_secs", .type = UCI_TYPE_STRING },
    		{ .name = "ssid", .type = UCI_TYPE_STRING },
    		{ .name = "key", .type = UCI_TYPE_STRING },
    
    		{ .name = "encryption", .type = UCI_TYPE_STRING },
    		{ .name = "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 = "rcpi_hysteresis_margin", .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 = "enabled", .type = UCI_TYPE_STRING }
    
    
    	};
    	struct uci_option *tb[NUM_POLICIES];
    	struct netif_fhcfg *fh;
    
    	uci_parse_section(s, opts, NUM_POLICIES, tb);
    
    	if (tb[FH_IFNAME]) {
    
    		const char *ifname;
    
    
    		ifname = tb[FH_IFNAME]->v.string;
    
    		fh = get_netif_fhcfg_by_name(a, ifname);
    		if (!fh) {
    			fh = create_fronthaul_iface_config(a, ifname);
    			if (!fh) {
    				warn("%s: OOM!\n", __func__);
    				return -1;
    			}
    		} else {
    			warn("Duplicate 'fh-iface %s' config!! ignore\n",
    					ifname);
    		}
    	} else {
    		warn("No ifname in fh-iface section!\n");
    		return -1;
    	}
    
    
    	if (tb[FH_BAND]) {
    		int band = atoi(tb[FH_BAND]->v.string);
    
    		if (band == 2)
    			fh->band = BAND_2;
    		else if (band == 5)
    			fh->band = BAND_5;
    	}
    
    
    	if (tb[FH_STEER]) {
    		struct uci_element *xi;
    
    		dbg("Steer: param: ");
    		uci_foreach_element(&tb[FH_STEER]->v.list, xi) {
    			struct steer_policy *p = NULL;
    			struct steer_rule *r;
    
    			dbg("%s ", xi->name);
    			p = get_steer_policy_by_name(fh, xi->name);
    			if (!p) {
    				/* TODO? */
    				dbg("TODO!! steer before ifname\n");
    				continue;
    			}
    			p->enabled = true;
    			r = get_steer_rule_by_name(xi->name);
    			if (r)
    				r->enabled = true;
    		}
    		dbg("\n");
    	}
    
    
    	if (tb[FH_DEVICE]) {
    		const char *device;
    
    		device = tb[FH_DEVICE]->v.string;
    
    		strncpy(fh->device, device, sizeof(fh->device) - 1);
    	}
    
    
    	if (tb[FH_BTM_RETRY])
    		fh->steer_btm_retry = atoi(tb[FH_BTM_RETRY]->v.string);
    
    	if (tb[FH_BTM_RETRY_SECS])
    		fh->steer_btm_retry_secs = atoi(tb[FH_BTM_RETRY_SECS]->v.string);
    
    	if (tb[FH_FLBK_LEGACY])
    		fh->fallback_legacy = atoi(tb[FH_FLBK_LEGACY]->v.string);
    
    	if (tb[FH_STEER_LEGACY_RASSOC_SECS])
    		fh->steer_legacy_reassoc_secs =
    				atoi(tb[FH_STEER_LEGACY_RASSOC_SECS]->v.string);
    
    	if (tb[FH_STEER_LEGACY_RETRY_SECS])
    		fh->steer_legacy_retry_secs =
    				atoi(tb[FH_STEER_LEGACY_RETRY_SECS]->v.string);
    
    	if (tb[FH_ASSOC_CTRL_SECS])
    		fh->assoc_control_time =
    				atoi(tb[FH_ASSOC_CTRL_SECS]->v.string);
    
    
    	if (tb[FH_SSID]) {
    		const char *ssid;
    
    		ssid = tb[FH_SSID]->v.string;
    		strncpy(fh->ssid, ssid, sizeof(fh->ssid) - 1);
    	}
    
    	if (tb[FH_KEY]) {
    		const char *key;
    
    		key = tb[FH_KEY]->v.string;
    		strncpy(fh->key, key, sizeof(fh->key) - 1);
    	}
    
    	if (tb[FH_ENCRYPTION]) {