Skip to content
Snippets Groups Projects
config.c 63.8 KiB
Newer Older
  • Learn to ignore specific revisions
  • 		const char *encryption;
    
    		encryption = tb[FH_ENCRYPTION]->v.string;
    		strncpy(fh->encryption, encryption, sizeof(fh->encryption) - 1);
    	}
    
    
    	if (tb[FH_POLICY])
    		fh->policy = atoi(tb[FH_POLICY]->v.string);
    
    	if (tb[FH_UTIL_THRESHOLD])
    		fh->util_threshold = atoi(tb[FH_UTIL_THRESHOLD]->v.string);
    
    	if (tb[FH_RCPI_THRESHOLD])
    		fh->rcpi_threshold = atoi(tb[FH_RCPI_THRESHOLD]->v.string);
    
    	if (tb[FH_REPORT_RCPI_THRESHOLD])
    		fh->report_rcpi_threshold =
    			atoi(tb[FH_REPORT_RCPI_THRESHOLD]->v.string);
    
    	if (tb[FH_RCPI_HYSTERESIS_MARGIN])
    		fh->rcpi_hysteresis_margin =
    			atoi(tb[FH_RCPI_HYSTERESIS_MARGIN]->v.string);
    
    	if (tb[FH_REPORT_UTIL_THRESHOLD])
    		fh->report_util_threshold =
    			atoi(tb[FH_REPORT_UTIL_THRESHOLD]->v.string);
    
    	if (tb[FH_INCLUDE_STA_STATS])
    		fh->include_sta_stats =
    			atoi(tb[FH_INCLUDE_STA_STATS]->v.string);
    
    	if (tb[FH_INCLUDE_STA_METRIC])
    		fh->include_sta_metric =
    			atoi(tb[FH_INCLUDE_STA_METRIC]->v.string);
    
    
    	if (tb[FH_ENABLED])
    		fh->enabled = atoi(tb[FH_ENABLED]->v.string);
    
    
    static int agent_config_get_steer_param(struct agent_config *a,
    		struct uci_section *s)
    
    {
    	struct steer_rule *r;
    
    	dbg("Steer-param: %s\n", s->e.name);
    	r = get_steer_rule_by_name(s->e.name);
    	if (!r)
    		return -1;
    
    	dbg("Rule to handle steer-param '%s' available\n", s->e.name);
    	r->config(r, a, s);
    
    	return 0;
    }
    
    
    static int agent_config_get_policy_param(struct agent_config *a,
    		struct uci_section *s)
    {
    	enum {
    		POL_REPORT_INTERVAL,
    		POL_PVID,
    		POL_PCP_DEFAULT,
    		POL_REPORT_SCAN,
    		POL_REPORT_STA_ASSOCFAILS,
    		POL_REPORT_STA_ASSOCFAILS_RATE,
    		NUM_POLICIES
    	};
    	const struct uci_parse_option opts[] = {
    		{ .name = "report_interval", .type = UCI_TYPE_STRING },
    		{ .name = "pvid", .type = UCI_TYPE_STRING },
    		{ .name = "pcp_default", .type = UCI_TYPE_STRING },
    		{ .name = "repost_scan", .type = UCI_TYPE_STRING },
    		{ .name = "report_sta_assocfails", .type = UCI_TYPE_STRING },
    		{ .name = "report_sta_assocfails_rate", .type = UCI_TYPE_STRING },
    	};
    
    	struct uci_option *tb[NUM_POLICIES];
    	struct policy_cfg *cfg;
    
    	uci_parse_section(s, opts, NUM_POLICIES, tb);
    
    	cfg = (struct policy_cfg *)calloc(1, sizeof(struct policy_cfg));
    	if (!cfg)
    		return -1;
    
    	if (tb[POL_REPORT_INTERVAL])
    		cfg->report_interval = atoi(tb[POL_REPORT_INTERVAL]->v.string);
    
    	if (tb[POL_PVID])
    		cfg->pvid = atoi(tb[POL_PVID]->v.string);
    
    	if (tb[POL_PCP_DEFAULT])
    		cfg->pcp_default = atoi(tb[POL_PCP_DEFAULT]->v.string);
    
    	if (tb[POL_REPORT_SCAN])
    		cfg->report_scan = atoi(tb[POL_REPORT_SCAN]->v.string);
    
    	if (tb[POL_REPORT_STA_ASSOCFAILS])
    		cfg->report_sta_assocfails =
    			atoi(tb[POL_REPORT_STA_ASSOCFAILS]->v.string);
    
    	if (tb[POL_REPORT_STA_ASSOCFAILS_RATE])
    		cfg->report_sta_assocfails_rate =
    			atoi(tb[POL_REPORT_STA_ASSOCFAILS_RATE]->v.string);
    
    	if (a->pcfg)
    		free(a->pcfg);
    
    	a->pcfg = cfg;
    
    	return 0;
    }
    
    
    int agent_config_reload(struct agent_config *cfg)
    
    {
    	struct uci_context *ctx;
    	struct uci_package *pkg;
    	struct uci_element *e;
    
    
    	cfg->enabled = false;
    	cfg->runfreq = AGENT_RUN_AUTO;
    
    
    	ctx = uci_alloc_context();
    	if (!ctx)
    		return -1;
    
    
    		uci_free_context(ctx);
    		return -1;
    	}
    
    	uci_foreach_element(&pkg->sections, e) {
    		struct uci_section *s = uci_to_section(e);
    
    
    			agent_config_get_wifi_agent(cfg, s);
    
    		else if (!strcmp(s->type, "controller_select"))
    			agent_config_get_controller_select(cfg, s);
    
    		else if (!strcmp(s->type, "wifi-radio"))
    			agent_config_get_wifi_radio(cfg, s);
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    		else if (!strcmp(s->type, "fh-iface"))
    
    			agent_config_get_fh_iface(cfg, s);
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    		else if (!strcmp(s->type, "bk-iface"))
    
    			agent_config_get_bk_iface(cfg, s);
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    		else if (!strcmp(s->type, "steer"))
    
    			agent_config_get_steer_param(cfg, s);
    
    		else if (!strcmp(s->type, "policy"))
    			agent_config_get_policy_param(cfg, s);
    
    Jakob Olsson's avatar
    Jakob Olsson committed
    }
    
    int config_generate_radio(struct agent_config *cfg, struct uci_context *ctx,
    		char *device, uint8_t band)
    {
    	struct uci_package *pkg;
    	struct uci_section *s;
    	int rv;
    
    	rv = uci_load(ctx, UCI_AGENT, &pkg);
    	if (rv)
    		return -1;
    
    	s = config_add_section(ctx, pkg, UCI_AGENT, "wifi-radio", "device",
    			device);
    	if (!s)
    		return -1;
    
    	if (band == BAND_2)
    		set_value(ctx, pkg, s, "band", "2", UCI_TYPE_STRING);
    	else if (band == BAND_5)
    		set_value(ctx, pkg, s, "band", "5", UCI_TYPE_STRING);
    
    	uci_commit(ctx, &pkg, false);
    	uci_unload(ctx, pkg);
    	return 0;
    }
    
    int config_generate_bsta_agent(struct agent_config *cfg, struct uci_context *ctx,
    
    		const char *device, const char *ifname,
    
    		uint8_t band)
    {
    	struct uci_section *s;
    	struct uci_package *pkg;
    	int rv;
    
    	rv = uci_load(ctx, UCI_AGENT, &pkg);
    	if (rv)
    		return -1;
    
    	s = config_add_section(ctx, pkg, UCI_AGENT, UCI_BK_AGENT, "device",
    			device);
    	if (!s)
    		return -1;
    
    	if (band == BAND_2)
    		set_value(ctx, pkg, s, "band", "2", UCI_TYPE_STRING);
    	else if (band == BAND_5)
    		set_value(ctx, pkg, s, "band", "5", UCI_TYPE_STRING);
    
    	set_value(ctx, pkg, s, "ifname", ifname, UCI_TYPE_STRING);
    	uci_commit(ctx, &pkg, false);
    	uci_unload(ctx, pkg);
    	return 0;
    }
    
    int config_find_radio(struct agent_config *cfg, struct uci_context *ctx,
    		char *radio)
    {
    	struct uci_package *pkg;
    	struct uci_section *s;
    	struct uci_element *e;
    	bool found = false;
    	int rv;
    
    	rv = uci_load(ctx, UCI_AGENT, &pkg);
    	if (rv)
    		return found;
    
    	s = config_get_section(ctx, pkg, "wifi-radio", "device", radio);
    	if (s)
    		found = true;
    
    	uci_unload(ctx, pkg);
    	return found;
    }
    
    static void wifi_radio_status_cb(struct ubus_request *req, int type,
    		struct blob_attr *msg)
    {
    	struct blob_attr *tb[1];
    	static const struct blobmsg_policy ap_attr[1] = {
    		[0] = { .name = "band", .type = BLOBMSG_TYPE_STRING },
    	};
    	char band_str[8] = {0};
    	uint8_t *band = req->priv;
    
    	blobmsg_parse(ap_attr, 1, tb, blob_data(msg), blob_len(msg));
    
    	if (!tb[0])
    		return;
    
    	strncpy(band_str, blobmsg_data(tb[0]), sizeof(band_str));
    
    	if (!strncmp(band_str, "5GHz", sizeof(band_str)))
    		*band = BAND_5;
    	else if (!strncmp(band_str, "2.4GHz", sizeof(band_str)))
    		*band = BAND_2;
    	else
    		*band = BAND_UNKNOWN;
    }
    
    
    void config_disable_bstas(struct agent_config *cfg)
    {
    	struct uci_context *ctx = NULL;
    	struct uci_package *pkg;
    	struct uci_section *section;
    	struct netif_bkcfg *bk;
    	bool reload = false;
    
    
    	list_for_each_entry(bk, &cfg->bklist, list) {
    		/* only disable onboarded bsta */
    //		if (!bk->cfg->onboarded)
    //			continue;
    
    		/* disable from wireless config */
    		pkg = uci_load_pkg(&ctx, UCI_WIRELESS);
    		if (!pkg)
    			continue;
    
    		section = config_get_section(ctx, pkg, UCI_WLAN_IFACE, "ifname", bk->name);
    		if (!section) {
    			uci_unload(ctx, pkg);
    			continue;
    		}
    
    		set_value(ctx, pkg, section, "disabled", "1", UCI_TYPE_STRING);
    		uci_save(ctx, pkg);
    		reload = true;
    	}
    
    	if (reload) {
    		uci_commit(ctx, &pkg, false);
    		uci_unload(ctx, pkg);
    	}
    
    
    	list_for_each_entry(bk, &cfg->bklist, list) {
    		pkg = uci_load_pkg(&ctx, UCI_AGENT);
    		if (!pkg)
    			continue;
    
    		section = config_get_section(ctx, pkg, UCI_BK_AGENT, "ifname", bk->name);
    		if (!section) {
    			uci_unload(ctx, pkg);
    			continue;
    		}
    
    		set_value(ctx, pkg, section, "enabled", "0", UCI_TYPE_STRING);
    		uci_save(ctx, pkg);
    		bk->enabled = 0;
    	}
    
    	if (reload) {
    		uci_commit(ctx, &pkg, false);
    		uci_reload_services("wireless");
    	}
    
    	uci_free_context(ctx);
    }
    
    int config_disable_bsta(struct netif_bkcfg *bk)
    {
    	struct uci_context *ctx = NULL;
    	struct uci_package *pkg;
    	struct uci_section *section;
    	int ret = -1;
    
    	/* disable mapagent bk-iface section */
    	pkg = uci_load_pkg(&ctx, UCI_AGENT);
    	if (!pkg)
    		return -1;
    
    	section = config_get_section(ctx, pkg, UCI_BK_AGENT, "ifname", bk->name);
    	if (!section)
    		goto out_pkg;
    
    	set_value(ctx, pkg, section, "enabled", "0", UCI_TYPE_STRING);
    	uci_save(ctx, pkg);
    	bk->enabled = 0;
    	uci_commit(ctx, &pkg, false);
    	uci_unload(ctx, pkg);
    
    	/* disable wireless config bsta wifi-iface section */
    	pkg = uci_load_pkg(&ctx, UCI_WIRELESS);
    	if (!pkg)
    		goto out;
    
    	section = config_get_section(ctx, pkg, UCI_WLAN_IFACE, "ifname", bk->name);
    	if (!section)
    		goto out_pkg;
    
    	set_value(ctx, pkg, section, "disabled", "1", UCI_TYPE_STRING);
    	uci_save(ctx, pkg);
    	uci_commit(ctx, &pkg, false);
    	ret = 0;
    
    out_pkg:
    	uci_unload(ctx, pkg);
    out:
    	uci_free_context(ctx);
    	return ret;
    }
    
    
    bool config_find_bsta_agent(struct agent_config *cfg, struct uci_context *ctx,
    		char *device)
    {
    	struct uci_package *pkg;
    	struct uci_element *e;
    	struct uci_section *section = NULL;
    	int rv;
    	bool found = false;
    
    	rv = uci_load(ctx, UCI_AGENT, &pkg);
    	if (rv)
    		return found;
    
    	uci_foreach_element(&pkg->sections, e) {
    		struct uci_section *s = uci_to_section(e);
    		char *c_device;
    
    		if (strncmp(s->type, UCI_BK_AGENT, strlen(UCI_BK_AGENT)))
    			continue;
    
    		c_device = uci_lookup_option_string(ctx, s, "device");
    		if (!c_device)
    			continue;
    
    		if (strncmp(device, c_device, 16))
    			continue;
    
    		found = true;
    		break;
    	}
    
    	uci_unload(ctx, pkg);
    	return found;
    }
    
    struct uci_section *config_find_bsta_wireless(struct agent_config *cfg,
    
    		struct uci_context *ctx, struct uci_package *pkg, const char *device)
    
    {
    	struct uci_element *e;
    	int rv;
    
    	uci_foreach_element(&pkg->sections, e) {
    		struct uci_section *s = uci_to_section(e);
    		char *c_device, *mode;
    
    		if (strncmp(s->type, UCI_WLAN_IFACE, strlen(UCI_WLAN_IFACE)))
    			continue;
    
    		c_device = uci_lookup_option_string(ctx, s, "device");
    		if (!c_device || strncmp(device, c_device, 16))
    			continue;
    
    		mode = uci_lookup_option_string(ctx, s, "mode");
    		if (!mode || strcmp(mode, "sta"))
    			continue;
    
    		return s;
    	}
    
    
    	return NULL;
    }
    
    int agent_config_prepare(struct agent_config *cfg)
    {
    	// TODO: iterate through 'wifi-device' sections in wireless config.
    	// If corresponding 'wifi-radio <device-name>' section is not available
    	// in 'mapagent' config, create one. Check supported bands of the new
    	// wifi-device and add option 'band' to the wifi-radio section.
    	struct uci_context *ctx = NULL;
    	struct uci_package *pkg;
    	struct uci_element *e;
    	struct blob_buf bb = {0};
    
    	pkg = uci_load_pkg(&ctx, UCI_WIRELESS);
    	if (!pkg)
    		return -1;
    
    	blob_buf_init(&bb, 0);
    
    	uci_foreach_element(&pkg->sections, e) {
    		struct uci_section *s = uci_to_section(e);
    		struct uci_section *wl_s;
    
    		const char *device, *ifname;
    
    		uint8_t band = 0;
    		char obj_name[64] = {0};
    		int rv;
    
    		if (strncmp(s->type, UCI_WL_DEVICE, strlen(UCI_WL_DEVICE)))
    			continue;
    
    		device = s->e.name;
    
    		snprintf(obj_name, sizeof(obj_name), "wifi.radio.%s",
    				device);
    		rv = ubus_call(obj_name, "status", &bb,
    				wifi_radio_status_cb, &band);
    		if (rv)
    			continue;
    
    		if (!config_find_radio(cfg, ctx, device))
    			config_generate_radio(cfg, ctx, device, band);
    
    		if (config_find_bsta_agent(cfg, ctx, device))
    			continue;
    
    		wl_s = config_find_bsta_wireless(cfg, ctx, pkg, device);
    		if (!wl_s)
    			continue;
    
    		ifname = uci_lookup_option_string(ctx, wl_s, "ifname");
    		if (!ifname)
    			continue;
    
    		config_generate_bsta_agent(cfg, ctx, device, ifname, band);
    	}
    
    	blob_buf_free(&bb);
    	uci_unload(ctx, pkg);
    	uci_free_context(ctx);
    	return 0;
    }
    
    
    int agent_config_init(struct agent_config *cfg)
    {
    	INIT_LIST_HEAD(&cfg->fhlist);
    	INIT_LIST_HEAD(&cfg->bklist);
    
    	INIT_LIST_HEAD(&cfg->radiolist);
    
    	INIT_LIST_HEAD(&cfg->steer_excludelist);
    	INIT_LIST_HEAD(&cfg->steer_btm_excludelist);
    
    	agent_config_prepare(cfg);
    
    	agent_config_reload(cfg);
    	return 0;
    }
    
    void clean_bk(struct netif_bkcfg *p)
    {
    	list_del(&p->list);
    	free(p);
    }
    
    int clean_all_bk(struct agent_config *cfg)
    {
    	struct netif_bkcfg *p, *tmp;
    
    	list_for_each_entry_safe(p, tmp, &cfg->bklist, list)
    		clean_bk(p);
    
    	return 0;
    }
    
    void clean_fh(struct netif_fhcfg *p)
    {
    	list_del(&p->list);
    	free(p);
    }
    
    int clean_all_fh(struct agent_config *cfg)
    {
    	struct netif_fhcfg *p, *tmp;
    
    	list_for_each_entry_safe(p, tmp, &cfg->fhlist, list)
    		clean_fh(p);
    
    	return 0;
    }
    
    
    void clean_radio_cfg(struct agent_config_radio *p)
    {
    	list_del(&p->list);
    	free(p);
    }
    
    int clean_all_radios(struct agent_config *cfg)
    {
    	struct agent_config_radio *p, *tmp;
    
    	list_for_each_entry_safe(p, tmp, &cfg->radiolist, list)
    		clean_radio_cfg(p);
    
    	return 0;
    }
    
    
    int agent_config_clean(struct agent_config *cfg)
    {
    	clean_all_fh(cfg);
    	clean_all_bk(cfg);
    
    	clean_steer_btm_excl(cfg);
    	clean_steer_excl(cfg);
    
    	clean_all_radios(cfg);
    
    	if (cfg->pcfg)
    		free(cfg->pcfg);
    
    	if (cfg->cscfg)
    		free(cfg->cscfg);
    
    int wifi_reorder_interfaces_by_device(struct agent_config *ac,
    
    		struct uci_context *ctx, struct uci_package *pkg, char *device)
    {
    	int i, j = 0;
    
    	int devnum = 0;
    	char ifname[IFNAMSIZ] = {0};
    
    	enum {
    		W_IFNAME,
    		NUM_POLICIES
    	};
    	const struct uci_parse_option opts[] = {
    		{ .name = "ifname", .type = UCI_TYPE_STRING }
    	};
    	struct uci_option *tb[NUM_POLICIES];
    	struct uci_element *e;
    
    
    	dbg("|%s:%d| reordering interfaces for device %s\n", __func__,
    			__LINE__, device);
    
    	devnum = get_device_num_from_name(device);
    	snprintf(ifname, IFNAMSIZ, "%s%d",
    			ac->netdev,
    			devnum);
    
    
    	for (i = 1; i < 16; i++) {
    		uci_foreach_element(&pkg->sections, e) {
    			struct uci_section *s = uci_to_section(e);
    
    			if (strncmp(s->type, UCI_WLAN_IFACE,
    					strlen(UCI_WLAN_IFACE)))
    				continue;
    
    			uci_parse_section(s, opts, NUM_POLICIES, tb);
    
    			if (!tb[W_IFNAME])
    				continue;
    
    			if (strncmp(tb[W_IFNAME]->v.string, ifname, sizeof(ifname)))
    				continue;
    
    			dbg("|%s:%d| found interface %s, reordering to %d\n",
    					__func__, __LINE__, ifname, j);
    
    		snprintf(ifname, IFNAMSIZ, "%s%d%s%d",
    				ac->netdev,
    				devnum,
    				(ac->brcm_setup ? "." : "_"),
    
    int wifi_reorder_interfaces(struct agent_config *ac)
    
    {
    
    	struct uci_context *ctx;
    	struct uci_package *pkg;
    	struct uci_element *e;
    
    	ctx = uci_alloc_context();
    	if (!ctx)
    		return -1;
    
    	if (uci_load(ctx, UCI_WIRELESS, &pkg)) {
    		uci_free_context(ctx);
    		return -1;
    	}
    
    	uci_foreach_element(&pkg->sections, e) {
    		struct uci_section *s = uci_to_section(e);
    
    		if (strncmp(s->type, UCI_WL_DEVICE, strlen(UCI_WL_DEVICE)))
    			continue;
    
    
    		wifi_reorder_interfaces_by_device(ac, ctx, pkg, s->e.name);
    
    	}
    
    	uci_commit(ctx, &pkg, false);
    	uci_free_context(ctx);
    	return 0;
    
    }
    
    int uci_set_bridge(char *config, char *bridge, char *proto, char *ipaddress)
    {
    	struct uci_context *ctx = NULL;
    	struct uci_package *pkg;
    	struct uci_element *e;
    	struct uci_section *section = NULL;
    
    	/** if bridge starts with br prefix, step past */
    	if (!strncmp(bridge, "br-", 3))
    		bridge += 3;
    
    	pkg = uci_load_pkg(&ctx, "network");
    	if (!pkg)
    		return -1;
    
    	uci_foreach_element(&pkg->sections, e) {
    		struct uci_section *s = uci_to_section(e);
    
    		if (strncmp(s->e.name, bridge, 16))
    			continue;
    
    		section = s;
    		break;
    	}
    
    	if (!section) {
    		struct uci_ptr ptr = {0};
    
    		ptr.p = pkg;
    		ptr.section = bridge;
    		ptr.value = "interface";
    		ptr.option = NULL;
    		uci_set(ctx, &ptr);
    		section = ptr.s;
    	}
    
    	set_value(ctx, pkg, section, "type", "bridge", UCI_TYPE_STRING);
    	set_value(ctx, pkg, section, "is_lan", "1", UCI_TYPE_STRING);
    	if (strlen(proto))
    		set_value(ctx, pkg, section, "proto", proto, UCI_TYPE_STRING);
    	if (!strcmp(proto, "static")) {
    		set_value(ctx, pkg, section, "ipaddr", ipaddress,
    				UCI_TYPE_STRING);
    		set_value(ctx, pkg, section, "netmask", "255.255.255.0",
    				UCI_TYPE_STRING);
    	}
    
    	uci_commit(ctx, &pkg, false);
    	uci_unload(ctx, pkg);
    	uci_free_context(ctx);
    	return false;
    }
    
    
    int uci_add_dhcp(char *iface)
    {
    	struct uci_context *ctx = NULL;
    	struct uci_package *pkg;
    	struct uci_element *e;
    	struct uci_section *section = NULL;
    	struct uci_ptr ptr = {0};
    
    	/** if bridge starts with br prefix, step past */
    	if (!strncmp(iface, "br-", 3))
    		iface += 3;
    
    	pkg = uci_load_pkg(&ctx, "dhcp");
    	if (!pkg)
    		return -1;
    
    	uci_foreach_element(&pkg->sections, e) {
    		struct uci_section *s = uci_to_section(e);
    
    		if (strncmp(s->e.name, iface, 16))
    			continue;
    
    		trace("Existing section found for ifname %s\n", iface);
    		goto out;
    	}
    
    	trace("Adding DHCP section for ifname %s\n", iface);
    
    	ptr.p = pkg;
    	ptr.section = iface;
    	ptr.value = "dhcp";
    	ptr.option = NULL;
    	uci_set(ctx, &ptr);
    	section = ptr.s;
    
    	set_value(ctx, pkg, section, "interface", iface, UCI_TYPE_STRING);
    	set_value(ctx, pkg, section, "start", "100", UCI_TYPE_STRING);
    	set_value(ctx, pkg, section, "limit", "150", UCI_TYPE_STRING);
    	set_value(ctx, pkg, section, "leasetime", "1h", UCI_TYPE_STRING);
    	set_value(ctx, pkg, section, "dhcpv6", "server", UCI_TYPE_STRING);
    	set_value(ctx, pkg, section, "ra", "server", UCI_TYPE_STRING);
    
    	uci_commit(ctx, &pkg, false);
    out:
    	uci_unload(ctx, pkg);
    	uci_free_context(ctx);
    	return false;
    }
    
    int uci_add_fw(struct agent_config *cfg, char *iface)
    {
    	struct uci_context *ctx = NULL;
    	struct uci_package *pkg;
    	struct uci_element *e;
    	struct uci_section *section = NULL;
    	int rv;
    
    	/** if bridge starts with br prefix, step past */
    	if (!strncmp(iface, "br-", 3))
    		iface += 3;
    
    	pkg = uci_load_pkg(&ctx, "firewall");
    	if (!pkg)
    		return -1;
    
    	section = config_get_section(ctx, pkg, "zone", "name", iface);
    	if (!section) {
    		trace("No fw section found for %s\n", iface);
    		rv = uci_add_section(ctx, pkg, "zone", &section);
    		if (rv)
    			goto out_pkg;
    
    		set_value(ctx, pkg, section, "name", iface, UCI_TYPE_STRING);
    		set_value(ctx, pkg, section, "network", iface, UCI_TYPE_LIST);
    		set_value(ctx, pkg, section, "input", "ACCEPT", UCI_TYPE_STRING);
    		set_value(ctx, pkg, section, "output", "ACCEPT", UCI_TYPE_STRING);
    		set_value(ctx, pkg, section, "forward", "ACCEPT", UCI_TYPE_STRING);
    		rv = uci_save(ctx, pkg);
    		if (rv)
    			goto out_pkg;
    		uci_commit(ctx, &pkg, false);
    	}
    
    	section = config_get_section(ctx, pkg, "forwarding", "src", iface);
    	if (!section) {
    		//section = config_add_section(ctx, pkg, "firewall", "forwarding", "src", iface);
    		//if (!section)
    		//	goto out;
    		rv = uci_add_section(ctx, pkg, "forwarding", &section);
    		if (rv)
    			goto out_pkg;
    
    		set_value(ctx, pkg, section, "src", iface, UCI_TYPE_STRING);
    		set_value(ctx, pkg, section, "dest", cfg->al_bridge, UCI_TYPE_STRING);
    		uci_commit(ctx, &pkg, false);
    	}
    
    out_pkg:
    	uci_unload(ctx, pkg);
    	uci_free_context(ctx);
    	return false;
    }