diff --git a/src/core/agent.c b/src/core/agent.c index db8d462294d30d86912952098c45f05de55e183f..b5bf5841e71d14097ea985ba6d227684ebbfb4db 100644 --- a/src/core/agent.c +++ b/src/core/agent.c @@ -2001,7 +2001,7 @@ fail_cmdu: static void wifi_wps_creds_event_handler(void *c, struct blob_attr *msg) { char encryption[32] = {0}, ifname[16] = {0}, ssid[33] = {0}, - key[64] = {0}; + key[65] = {0}; struct blob_attr *tb[4]; struct wifi_radio_element *radio; struct agent *a = (struct agent *) c; diff --git a/src/core/agent_map.c b/src/core/agent_map.c index e5b984b2e1df9820dcfbbf7ffdf006387ecf702f..a3c90ac4f184375b17cb95b0085c24fda9ee1fbe 100644 --- a/src/core/agent_map.c +++ b/src/core/agent_map.c @@ -836,6 +836,7 @@ int handle_ap_autoconfig_wsc(void *agent, struct cmdu_cstruct *cmdu) } a->configured = true; + wifi_reorder_interfaces(&a->cfg); agent_config_reload(&a->cfg); uci_apply_wps_credentials(&a->cfg, radio->band); teardown: diff --git a/src/core/config.c b/src/core/config.c index 5db119a0dafd3f39902f58a1dd5d41000a57b48c..66916719c0909bbab3672031e5ab70ddf9f86997 100644 --- a/src/core/config.c +++ b/src/core/config.c @@ -47,6 +47,7 @@ #define UCI_BK_AGENT "bk-iface" #define UCI_FH_AGENT "fh-iface" #define UCI_WLAN_IFACE "wifi-iface" +#define UCI_WL_DEVICE "wifi-device" #define UCI_WIRELESS "wireless" #define UCI_IEEE1905 "ieee1905" #define UCI_AGENT "mapagent" @@ -101,22 +102,23 @@ int set_value_by_string(const char *package, const char *section, return -1; } -struct uci_section *config_get_iface_section(struct uci_context *ctx, - struct uci_package *pkg, const char *type, const char *ifname) +struct uci_section *config_get_section(struct uci_context *ctx, + struct uci_package *pkg, const char *type, const char *key, + const char *value) { struct uci_element *e; struct uci_section *section; /* get the wet iface section */ uci_foreach_element(&pkg->sections, e) { - const char *c_ifname; + const char *c_value; section = uci_to_section(e); if (strcmp(section->type, type)) continue; - c_ifname = uci_lookup_option_string(ctx, section, "ifname"); - if (c_ifname && !strcmp(c_ifname, ifname)) + c_value = uci_lookup_option_string(ctx, section, key); + if (c_value && !strcmp(c_value, value)) return section; } @@ -196,7 +198,7 @@ int wifi_set_iface_bssid(const char *ifname, uint8_t *bssid) if (!pkg) return ret; - section = config_get_iface_section(ctx, pkg, "wifi-iface", ifname); + section = config_get_section(ctx, pkg, "wifi-iface", "ifname", ifname); if (!section) goto out_pkg; @@ -231,7 +233,7 @@ int config_del_iface(const char *config, const char *type, const char *ifname) goto out_uci; } - section = config_get_iface_section(ctx, pkg, type, ifname); + section = config_get_section(ctx, pkg, type, "ifname", ifname); if (!section) goto out_pkg; @@ -265,7 +267,7 @@ int wifi_apply_iface_cfg(const char *ifname, const char *encryption, goto out_uci; } - section = config_get_iface_section(ctx, pkg, "wifi-iface", ifname); + section = config_get_section(ctx, pkg, "wifi-iface", "ifname", ifname); if (!section) goto out_pkg; @@ -283,51 +285,37 @@ out: return rv; } -int config_add_section(const char *config, const char *type, const char *ifname) +struct uci_section *config_add_section(struct uci_context *ctx, + struct uci_package *pkg, const char *config, const char *type, + const char *key, const char *value) { - struct uci_context *ctx; - struct uci_package *pkg; - struct uci_section *section; + struct uci_section *section = NULL; struct uci_ptr ptr = {0}; int rv = -1; - ctx = uci_alloc_context(); - if (!ctx) - goto out; + section = config_get_section(ctx, pkg, type, key, value); + if (!section) { + rv = uci_add_section(ctx, pkg, type, §ion); + if (rv) + goto out_pkg; - if (uci_load(ctx, config, &pkg) != UCI_OK) { - dbg("config file '%s' not found!\n", config); - goto out_uci; + rv = uci_save(ctx, pkg); + if (rv) + goto out_pkg; } - section = config_get_iface_section(ctx, pkg, type, ifname); - if (section) - goto out_pkg; - - rv = uci_add_section(ctx, pkg, type, §ion); - if (rv) - goto out_pkg; - - rv = uci_save(ctx, pkg); - if (rv) - goto out_pkg; - - ptr.value = ifname; + ptr.value = value; ptr.package = config; ptr.section = section->e.name; - ptr.option = "ifname"; + ptr.option = key; ptr.target = UCI_TYPE_OPTION; uci_lookup_ptr(ctx, &ptr, NULL, false); uci_set(ctx, &ptr); uci_save(ctx, ptr.p); - uci_commit(ctx, &pkg, false); + out_pkg: - uci_unload(ctx, pkg); -out_uci: - uci_free_context(ctx); -out: - return rv; + return section; } int config_add_default_wifi_iface(const char *config, const char *type, @@ -339,10 +327,6 @@ int config_add_default_wifi_iface(const char *config, const char *type, struct uci_section *section; int rv = -1; - rv = config_add_section(config, type, ifname); - if (rv) - return -1; - ctx = uci_alloc_context(); if (!ctx) goto out; @@ -352,9 +336,10 @@ int config_add_default_wifi_iface(const char *config, const char *type, goto out_uci; } - section = config_get_iface_section(ctx, pkg, type, ifname); + section = config_add_section(ctx, pkg, config, type, "ifname", ifname); if (!section) - goto out_pkg; + return -1; + set_value(ctx, pkg, section, "device", device, UCI_TYPE_STRING); set_value(ctx, pkg, section, "network", network, UCI_TYPE_STRING); @@ -367,7 +352,7 @@ out_pkg: out_uci: uci_free_context(ctx); out: - return rv; + return 0; } int config_add_default_agent_iface(const char *config, const char *type, @@ -378,10 +363,6 @@ int config_add_default_agent_iface(const char *config, const char *type, struct uci_section *section; int rv = -1; - rv = config_add_section(config, type, ifname); - if (rv) - return -1; - ctx = uci_alloc_context(); if (!ctx) goto out; @@ -391,9 +372,9 @@ int config_add_default_agent_iface(const char *config, const char *type, goto out_uci; } - section = config_get_iface_section(ctx, pkg, type, ifname); + section = config_add_section(ctx, pkg, config, type, "ifname", ifname); if (!section) - goto out_pkg; + return -1; trace("band = %d\n", band); @@ -409,7 +390,7 @@ out_pkg: out_uci: uci_free_context(ctx); out: - return rv; + return 0; } /* below functions are mostly taken from ieee1905d */ @@ -613,13 +594,17 @@ static int ubus_call(const char *object, const char *method, bool uci_reload_services(void) { struct blob_buf bb; - + int rv; memset(&bb, 0, sizeof(struct blob_buf)); blob_buf_init(&bb, 0); - info("## Reloading uci config\n"); - if (!ubus_call("uci", "reload_config", &bb, NULL, NULL)) - return true; + blobmsg_add_string(&bb, "config", "wireless"); + + rv = ubus_call("uci", "commit", &bb, NULL, NULL); + + info("## Reloading uci config %d\n", rv); + //if (!ubus_call("uci", "reload_config", &bb, NULL, NULL)) + // return true; blob_buf_free(&bb); @@ -1257,6 +1242,71 @@ static int agent_config_get_wifi_agent(struct agent_config *a, 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 }, + }; + 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 = calloc(1, sizeof(*n)); + if (!n) { + warn("-ENOMEM!\n"); + return -1; + } + 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_ONBOARDED]) { + n->onboarded = atoi(tb[WIFI_RADIO_ONBOARDED]->v.string) == 1 ? + true : false; + } + + list_add_tail(&n->list, &a->radiolist); + + return 0; +} + static int agent_config_get_bk_iface(struct agent_config *a, struct uci_section *s) { @@ -1565,6 +1615,8 @@ int agent_config_reload(struct agent_config *cfg) if (!strcmp(s->type, "agent")) agent_config_get_wifi_agent(cfg, s); + else if (!strcmp(s->type, "wifi-radio")) + agent_config_get_wifi_radio(cfg, s); else if (!strcmp(s->type, "fh-iface")) agent_config_get_fh_iface(cfg, s); else if (!strcmp(s->type, "bk-iface")) @@ -1577,11 +1629,236 @@ int agent_config_reload(struct agent_config *cfg) return 0; } +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, + char *device, 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; +} + +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, 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; + 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); + agent_config_prepare(cfg); agent_config_reload(cfg); return 0; } @@ -1627,3 +1904,83 @@ int agent_config_clean(struct agent_config *cfg) return 0; } + +int wifi_reorder_interfaces_by_device(struct agent_config *a, + struct uci_context *ctx, struct uci_package *pkg, char *device) +{ + int i, j = 0; + char ifname[16] = {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; + + trace("reordering interfaces for device %s\n", device); + + strncpy(ifname, device, sizeof(ifname)); + + for (i = 1; i < 16; i++) { + trace("iterating in search of %s\n", ifname); + 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; + trace("found interface %s, reordering to %d\n", ifname, j); + uci_reorder_section(ctx, s, j); + j++; + break; + } + + snprintf(ifname, sizeof(ifname), "%s%s%d", + device, + (a->brcm_setup ? "." : "_"), + i); + } + + return 0; +} + +int wifi_reorder_interfaces(struct agent_config *a) +{ + + 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(a, ctx, pkg, s->e.name); + } + + uci_commit(ctx, &pkg, false); + uci_free_context(ctx); + return 0; +} \ No newline at end of file diff --git a/src/core/config.h b/src/core/config.h index f10840a1e72155cfd0531af5b9f98492b0368b3d..283725d7a794369bf6647f62552907e922e8a00b 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -114,10 +114,19 @@ enum runfreq { AGENT_RUN_LOW = 10, }; +struct agent_config_radio { + char name[16]; + uint8_t band; + bool configured; + bool onboarded; + struct list_head list; +}; + struct agent_config { bool enabled; int debug_level; enum runfreq runfreq; + struct list_head radiolist; struct list_head fhlist; /* list of netif_fhcfg */ struct list_head bklist; /* list of netif_bkcfg */ unsigned char mobility_domain[2]; @@ -179,7 +188,9 @@ int config_update2(const char *confname, struct agent_config *cfg, int wifi_apply_iface_cfg(const char *ifname, const char *encryption, const char *ssid, const char *key); int config_del_iface(const char *config, const char *type, const char *ifname); -int config_add_section(const char *config, const char *type, const char *ifname); +struct uci_section *config_add_section(struct uci_context *ctx, + struct uci_package *pkg, const char *config, const char *type, + const char *key, const char *value); int config_add_default_wifi_iface(const char *config, const char *type, const char *ifname, const char *device, const char *network, const char *mode); @@ -200,4 +211,7 @@ int uci_apply_m2(char *interface_name, char *device, uint8_t *ssid, uint16_t auth_type, uint16_t encryption_type, uint8_t *network_key, uint8_t mapie, uint8_t band); int uci_apply_wps_credentials(struct agent_config *cfg, enum wifi_band band); +int wifi_reorder_interfaces_by_device(struct agent_config *a, + struct uci_context *ctx, struct uci_package *pkg, char *device); +int wifi_reorder_interfaces(struct agent_config *a); #endif