diff --git a/src/agent.c b/src/agent.c index f959c4aa2a946924579c5db2b7b0ea65471cc5a5..bb468552c75b0583694ec4fd06b05a057065d8ab 100644 --- a/src/agent.c +++ b/src/agent.c @@ -127,16 +127,9 @@ out: bk->bsta_steer.cmdu = NULL; } -static pthread_t nl_thread; - static void agent_sighandler(int sig) { - pthread_t self = pthread_self(); - - if (nl_thread == self) - ts_need_reconfig = true; - else - uloop_end(); + uloop_end(); } int agent_exec_platform_scripts(char *arg) @@ -2955,14 +2948,14 @@ static void agent_detect_loop(struct agent *a, int secs) /* Check if Primary VLAN is set on bSTA in assoc IE */ static void agent_check_ts(struct agent *a, struct netif_bk *bk, char *ifname) { -#if 0 /* Not used at present */ char buf[64] = {0}; + if (Cmd(buf, sizeof(buf), "/lib/wifi/multiap ts primary get %s", ifname)) { err("|%s:%d| Unable to fetch Primary VID info from system", __func__, __LINE__); } - if (atoi(buf) && a) { + if (atoi(buf) && a && a->cfg.ts_enabled) { if (!(a->cfg.pcfg)) { a->cfg.pcfg = (struct policy_cfg *)calloc(1, sizeof(struct policy_cfg)); if (!(a->cfg.pcfg)) { @@ -2971,14 +2964,10 @@ static void agent_check_ts(struct agent *a, struct netif_bk *bk, char *ifname) return; } } - - pthread_mutex_lock(&a->nl_mutex); a->cfg.pcfg->pvid = atoi(buf); - pthread_mutex_unlock(&a->nl_mutex); - - /* TODO save pvid in the config file */ + a->ts.requested = 1; + agent_apply_traffic_separation(a); } -#endif } char *agent_get_backhaul_ifname(char *ifname) @@ -3622,6 +3611,37 @@ static void parse_i1905_info(struct ubus_request *req, int type, hwaddr_aton(mac, a->almac); dbg("almac = " MACFMT "\n", MAC2STR(a->almac)); } + + + if (tb[1] && a->cfg.ts_enabled) { + struct blob_attr *cur; + int rem; + + blobmsg_for_each_attr(cur, tb[1], rem) { + struct blob_attr *data[1]; + static const struct blobmsg_policy intf_attrs[1] = { + [0] = { .name = "ifname", .type = BLOBMSG_TYPE_STRING } + }; + char *ifname; + char fmt[64] = {0}; + + if (blobmsg_type(cur) != BLOBMSG_TYPE_TABLE) + continue; + + blobmsg_parse(intf_attrs, 1, data, blobmsg_data(cur), + blobmsg_data_len(cur)); + + if (!data[0]) + continue; + + ifname = blobmsg_get_string(data[0]); + if (!ifname) + continue; + + snprintf(fmt, sizeof(fmt), "ts multicast %s", ifname); + agent_exec_platform_scripts(fmt); + } + } } static void uobj_add_event_handler(void *agent, struct blob_attr *msg) @@ -3929,7 +3949,7 @@ static void wifi_wps_creds_event_handler(void *c, struct blob_attr *msg) { char encryption[32] = {0}, ifname[16] = {0}, ssid[33] = {0}, key[65] = {0}; - //uint16_t vlan = 0; + uint16_t vlan = 0; struct blob_attr *tb[5]; struct wifi_radio_element *radio; struct agent *a = (struct agent *) c; @@ -3952,6 +3972,9 @@ static void wifi_wps_creds_event_handler(void *c, struct blob_attr *msg) strncpy(encryption, blobmsg_data(tb[1]), sizeof(encryption) - 1); strncpy(ssid, blobmsg_data(tb[2]), sizeof(ssid) - 1); strncpy(key, blobmsg_data(tb[3]), sizeof(key) - 1); + if (tb[4]) + vlan = (uint16_t) blobmsg_get_u16(tb[4]); + bk = find_bkhaul_by_ifname(a, ifname); if (!bk) return; @@ -3986,12 +4009,7 @@ static void wifi_wps_creds_event_handler(void *c, struct blob_attr *msg) uloop_timeout_set(&a->onboarding_scheduler, timeout * 1000); -#if 0 /* Not used at present */ - vlan = 0; - if (tb[4]) - vlan = (uint16_t) blobmsg_get_u16(tb[4]); - - if (vlan && bk->agent) { + if (vlan && bk->agent && bk->agent->cfg.ts_enabled) { if (!(a->cfg.pcfg)) { a->cfg.pcfg = (struct policy_cfg *)calloc(1, sizeof(struct policy_cfg)); if (!(a->cfg.pcfg)) { @@ -4000,13 +4018,10 @@ static void wifi_wps_creds_event_handler(void *c, struct blob_attr *msg) return; } } - pthread_mutex_lock(&a->nl_mutex); bk->agent->cfg.pcfg->pvid = vlan; - pthread_mutex_unlock(&a->nl_mutex); - + bk->agent->ts.requested = 1; agent_apply_traffic_separation(bk->agent); } -#endif } static void agent_event_handler(struct ubus_context *ctx, @@ -4844,7 +4859,6 @@ static void _enumerate_wifi_objects(struct ubus_request *req, int type, /* clears radio apcfg states */ agent_free_radios(a); clear_fhlist(a); - clear_bklist(a); a->num_radios = len; } @@ -5614,10 +5628,8 @@ int agent_init_interfaces(struct agent *a) fn->cfg = f; fn->agent = a; strncpy(fn->radio_name, radio_name, IFNAMSIZ-1); - - pthread_mutex_lock(&a->nl_mutex); + fn->vid = TS_VID_INVALID; list_add(&fn->list, &a->fhlist); - pthread_mutex_unlock(&a->nl_mutex); } snprintf(r_objname, 31, "wifi.radio.%s", radio_name); @@ -5655,14 +5667,19 @@ int agent_init_interfaces(struct agent *a) char r_objname[32] = {0}; char objname[32] = {0}; - bn = find_bkhaul_by_ifname(a, b->name); if (!bn) { bn = netif_alloc_bk(b->name); if (bn) { - pthread_mutex_lock(&a->nl_mutex); + if (a->cfg.ts_enabled) { + char tsfmt[64] = {0}; + //FIXME: add primary VID + snprintf(tsfmt, sizeof(tsfmt), "ts create bh %s 1 2", + b->name); + dbg("%s %d ts-fmt = %s\n", __func__, __LINE__, tsfmt); + agent_exec_platform_scripts(tsfmt); + } list_add(&bn->list, &a->bklist); - pthread_mutex_unlock(&a->nl_mutex); } } @@ -5691,6 +5708,7 @@ int agent_init_interfaces(struct agent *a) bn->radio = r_wobj; bn->cfg = b; bn->agent = a; + bn->vid = TS_VID_INVALID; ubus_call_object(a, wobj, "status", parse_bk, bn); if (bn->connected) @@ -5718,7 +5736,7 @@ int agent_init_interfaces(struct agent *a) agent_config_reload(&a->cfg); agent_init_interfaces_post_actions(a); - agent_apply_traffic_separation(a); + return 0; } @@ -5733,12 +5751,17 @@ static void agent_enable_fhs_cb(struct uloop_timeout *t) static void agent_init_ifaces_cb(struct uloop_timeout *t) { + trace("%s: --->\n", __func__); + struct agent *a = container_of(t, struct agent, init_ifaces_scheduler); if (!a) return; agent_init_interfaces(a); + + if (a->cfg.ts_enabled && a->ts.requested) + agent_apply_traffic_separation(a); } @@ -5756,6 +5779,11 @@ static void agent_reload_wireless(struct uloop_timeout *t) agent_exec_platform_scripts("sync_credentials"); uci_reload_services("wireless"); + + if (a->cfg.ts_enabled && a->ts.requested) { + agent_apply_traffic_separation(a); + } else if (a->cfg.ts_enabled && a->ts.active) + agent_disable_traffic_separation(a); } /* send the steering compled message this function also resets the value of @@ -5974,7 +6002,7 @@ void clear_restrict_stalist(struct netif_fh *p) } } -static void netif_free(struct agent *a, struct netif_fh *n) +static void netif_free(struct netif_fh *n) { /* clear stalist */ clear_stalist(n); @@ -5992,10 +6020,7 @@ static void netif_free(struct agent *a, struct netif_fh *n) uloop_timeout_cancel(&n->util_threshold_timer); uloop_timeout_cancel(&n->una_sta_meas_timer); - pthread_mutex_lock(&a->nl_mutex); list_del(&n->list); - pthread_mutex_unlock(&a->nl_mutex); - free(n); } @@ -6004,23 +6029,10 @@ void clear_fhlist(struct agent *a) struct netif_fh *p, *tmp; list_for_each_entry_safe(p, tmp, &a->fhlist, list) { - netif_free(a, p); + netif_free(p); } } -void clear_bklist(struct agent *a) -{ - struct netif_bk *p, *tmp; - - list_for_each_entry_safe(p, tmp, &a->bklist, list) { - pthread_mutex_lock(&a->nl_mutex); - list_del(&p->list); - pthread_mutex_unlock(&a->nl_mutex); - free(p); - } -} - - int agent_map_sub_cb(void *bus, void *priv, void *data) { struct blob_attr *msg = (struct blob_attr *)data; @@ -6179,6 +6191,7 @@ void run_agent(void) { struct agent *w; struct ubus_context *ctx; + pthread_t tid[1]; set_sighandler(SIGHUP, agent_sighandler); set_sighandler(SIGPIPE, SIG_IGN); @@ -6190,7 +6203,6 @@ void run_agent(void) this_agent = w; dbg("Starting wifi_agent... (&agent = %p)\n", w); - pthread_mutex_init(&w->nl_mutex, NULL); agent_init_defaults(w); cmdu_ackq_init(&w->cmdu_ack_q); @@ -6217,26 +6229,23 @@ void run_agent(void) //agent_config_get_ethwan(w->ethwan); //memcpy(w->cntlr_almac, w->cfg.cntlr_almac, 6); - if (w->cfg.brcm_setup) { int ret; - ret = pthread_create(&w->nl_thread, NULL, (void *)&nl_loop, w); + /* TODO: memory management of thread on cleaup */ + ret = pthread_create(&(tid[0]), NULL, (void *)&nl_loop, w); if (ret) { fprintf(stderr, "Failed to create thread\n"); - free(w); return; } - nl_thread = w->nl_thread; + pthread_detach(tid[0]); } //agent_config_dump(&w->cfg); get_registered_steer_rules(); /* TODO: return rule list and improve */ - //agent_switch_according_to_pref(w); /*switch to the channel according to the prefrence*/ - ubus_register_event_handler(ctx, &w->evh, "ethport"); ubus_register_event_handler(ctx, &w->evh, "wifi.*"); ubus_register_event_handler(ctx, &w->evh, "wps_credentials"); @@ -6272,26 +6281,19 @@ void run_agent(void) agent_subscribe_for_cmdus(w); + /* TODO: can probably be removed */ + if (w->cfg.ts_enabled) + agent_exec_platform_scripts("ts multicast lei_lan"); + uloop_run(); /* out_and_exit: */ - if (w->cfg.brcm_setup) { - void *res; - - pthread_cancel(w->nl_thread); - pthread_join(w->nl_thread, &res); - if (res != PTHREAD_CANCELED) - warn("Fail to cancel nl thread\n"); - } - map_unsubscribe(w->ubus_ctx, w->subscriber); agent_free_radios(w); agent_remove_object(w); agent_config_clean(&w->cfg); cmdu_ackq_free(&w->cmdu_ack_q); clear_fhlist(w); - clear_bklist(w); - pthread_mutex_destroy(&w->nl_mutex); ubus_unregister_event_handler(ctx, &w->evh); plugins_unload(&w->pluginlist); uloop_done(); diff --git a/src/agent.h b/src/agent.h index fb7748da0e7a3a282cffd7f4a4d0697bf4862cbf..88bf348c1417b307516b08a48009a659af6b4c0d 100644 --- a/src/agent.h +++ b/src/agent.h @@ -16,7 +16,6 @@ #include <timer_impl.h> #include <cmdu_ackq.h> #include <map_module.h> -#include <linux/if_bridge.h> // TODO: TODO: fixme: remove this include //#include <ieee1905/1905_tlvs.h> @@ -269,6 +268,9 @@ struct netif_fh { /* previous channel utilization threshold value */ uint8_t prev_util; + + /* traffic separation */ + unsigned int vid; }; /* backhaul wifi (sta) interface */ @@ -293,6 +295,9 @@ struct netif_bk { struct cmdu_buff *cmdu; } bsta_steer; struct uloop_timeout connect_timer; + + /* traffic separation */ + unsigned int vid; }; #if 0 @@ -644,9 +649,13 @@ struct agent { struct uloop_timeout fh_disable_timer; #endif /* AGENT_ISLAND_PREVENTION */ - /* traffic separation and netlink events */ - pthread_t nl_thread; - pthread_mutex_t nl_mutex; + /* traffic separation */ + struct { +// bool enabled; // config option to enable/disable feature + bool requested; // triggered by condition according to spec +// bool setup; // TS subsystem separation prepared + bool active; // current status + } ts; /* dynamic backhaul */ struct uloop_timeout upgrade_backhaul_scheduler; @@ -726,7 +735,6 @@ void agent_disable_local_cntlr(struct agent *a); void wifiagent_log_cntlrinfo(struct agent *a); void agent_free_radios(struct agent *a); void clear_fhlist(struct agent *a); -void clear_bklist(struct agent *a); int agent_init_interfaces(struct agent *a); struct sta *find_sta_by_mac(struct agent *a, const unsigned char *mac); int agent_switch_according_to_pref(struct agent *a); diff --git a/src/agent_map.c b/src/agent_map.c index 56083dccc0c5cf25a8b4c6caa9d282fe3c05c745..43de2a00d23649e6adeaee87a94b0a3135419e45 100644 --- a/src/agent_map.c +++ b/src/agent_map.c @@ -903,6 +903,14 @@ int handle_ap_autoconfig_search(void *agent, struct cmdu_buff *rx_cmdu) return -1; } + if (memcmp(aladdr_origin, a->almac, 6) && a->cfg.ts_enabled) { + char cmd[64] = {0}; + + snprintf(cmd, sizeof(cmd), "ts unicast " MACFMT " %s", + MAC2STR(aladdr_origin), "lei_lan"); + agent_exec_platform_scripts(cmd); + } + /* Discard autoconfig search in case it's been sent by ourself */ for (i = 0; i < a->num_radios; i++) { if (a->radios[i].mid == cmdu_get_mid(rx_cmdu)) { @@ -1417,13 +1425,63 @@ static inline bool is_vid_valid(unsigned int vid) return (vid < TS_VID_INVALID) && (vid > 0); } +static void agent_ts_setup_eths(struct agent *a, struct agent_config *cfg, + struct policy_cfg *c) +{ + struct netif_fh *fh = NULL; + char cmd[128] = {0}; + char vids[64] = {0}; + char *vids_buf = vids; + int vids_len = sizeof(vids) - 1; + int len; + + bool have_vids = false; + /* secondary networks vlan id's*/ + list_for_each_entry(fh, &a->fhlist, list) { + char vid_str[8] = {0}; + + if (!is_vid_valid(fh->vid)) + continue; + if (fh->vid == c->pvid) + continue; + + /* TODO keep table of secondary vids from config */ + + snprintf(vid_str, sizeof(vid_str) - 1, " %u ", fh->vid); + if (strstr(vids, vid_str)) + continue; + + len = snprintf(vids_buf, vids_len, "%s", vid_str); + if (len < 0) { + err("Fail to add secondary vlan id"); + break; + } + + vids_buf += len; + vids_len -= len; + + have_vids = true; + } + + if (!have_vids) + return; + + snprintf(cmd, sizeof(cmd), "ts create eths %u %s %s", + c->pvid, cfg->al_bridge, vids); + agent_exec_platform_scripts(cmd); +} + /* Set up Traffic Separation rules */ int agent_apply_traffic_separation(struct agent *a) { + trace("%s: --->\n", __func__); struct agent_config *cfg; struct policy_cfg *c; - - trace("%s: --->\n", __func__); + struct netif_fh *fh; + struct netif_bk *bk; + bool diff = false; + char cmd[128] = {0}; + bool dhcp_reload = false; if (!a) return -1; @@ -1440,16 +1498,179 @@ int agent_apply_traffic_separation(struct agent *a) return -1; } - if (c->pvid == 0) + /* Fronthaul */ + list_for_each_entry(fh, &a->fhlist, list) { + if (fh->cfg->multi_ap == 2) { + /* FH BSS */ + unsigned int new_vid = + fh->cfg->vid ? fh->cfg->vid : c->pvid; + if (fh->vid == new_vid) /* no change */ + continue; + diff = true; + + if (is_vid_valid(fh->vid)) { + /* existing vlan has changed */ + /* TODO: less interruption if vlan filters are + * just modified instead of recreated */ + snprintf(cmd, sizeof(cmd), "ts delete %s", + fh->name); + agent_exec_platform_scripts(cmd); + trace("%s: VID changed for FH BSS: %s\n", + __func__, cmd); + } + + snprintf(cmd, sizeof(cmd), "ts create fh %s %u %s", + fh->name, new_vid, cfg->al_bridge); + agent_exec_platform_scripts(cmd); + + if (is_local_cntlr_running() && new_vid != c->pvid) { + snprintf(cmd, sizeof(cmd), "ts create dhcp %u", new_vid); + agent_exec_platform_scripts(cmd); + dhcp_reload = true; + } + + fh->vid = new_vid; + } else if (fh->cfg->multi_ap == 3) { + // TODO: Mixed FH/BH + } + } + + /* Backhaul */ + // TODO: Profile needs to be for BH, not Agent - for now always assume 2 + list_for_each_entry(bk, &a->bklist, list) { + /* BH STA */ + if (bk->vid == c->pvid) /* no change */ + continue; + diff = true; + + if (is_vid_valid(bk->vid)) { + /* existing vlan has changed */ + /* TODO: less interruption if vlan filters are + * just modified instead of recreated */ + snprintf(cmd, sizeof(cmd), "ts delete %s", + bk->name); + agent_exec_platform_scripts(cmd); + trace("%s: VID changed for BH STA: %s\n", __func__, cmd); + } + + snprintf(cmd, sizeof(cmd), "ts create bh %s %u %s %s", + bk->name, c->pvid, "2", cfg->al_bridge); +// cfg->profile == MULTIAP_PROFILE_2 ? "2" : "1"); + agent_exec_platform_scripts(cmd); + bk->vid = c->pvid; + trace("%s: applying TS for BH STA: %s\n", __func__, cmd); + } + + list_for_each_entry(fh, &a->fhlist, list) { + if (fh->cfg->multi_ap == 1) { + /* BH BSS */ + if (fh->vid == c->pvid) /* no change */ + continue; + diff = true; + + if (is_vid_valid(fh->vid)) { + /* existing vlan has changed */ + /* TODO: less interruption if vlan filters are + * just modified instead of recreated */ + snprintf(cmd, sizeof(cmd), "ts delete %s", + fh->name); + agent_exec_platform_scripts(cmd); + trace("%s: VID changed for BH BSS: %s\n", + __func__, cmd); + } + + snprintf(cmd, sizeof(cmd), "ts create bh %s %u %s", + fh->name, c->pvid, "2"); + agent_exec_platform_scripts(cmd); + fh->vid = c->pvid; + trace("%s: applying TS for BH BSS: %s\n", __func__, cmd); + } else if (fh->cfg->multi_ap == 3) { + // TODO: Mixed FH/BH + } + } + + if (!diff && a->ts.active) return 0; - if (!is_vid_valid(c->pvid)) { - warn("Invalid primary vlan id %u", c->pvid); - return -1; + /* Logical Ethernet Interface */ + /* Note: setup of LEI is already handled by init script */ + snprintf(cmd, sizeof(cmd), "ts create lei %u %u %s %s", + c->pvid, c->pcp_default, cfg->al_bridge, "br-lan"); + agent_exec_platform_scripts(cmd); + + agent_ts_setup_eths(a, cfg, c); + + a->ts.active = true; + + snprintf(cmd, sizeof(cmd), "ts reload %s" , dhcp_reload ? "1" : ""); + agent_exec_platform_scripts(cmd); + +#if 0 // Not needed for now, maybe never? + if (cfg->brcm_setup) { + /* special case to handle wds interface */ + int i, num, max = 32; + char if_list[max][16]; + + if (br_get_iflist(cfg->al_bridge, &num, if_list)) { + trace("Failed to check bridge affiliation\n"); + return -1; + } + max = (num < max) ? num : max; + for (i = 0; i < max; i++) { + if (strstr(if_list[i], "wds") && + !strstr(if_list[i], "vlan")) { + /* trigger nl hook */ + trace("%s: applying TS for %s\n", __func__, + if_list[i]); + br_delif(cfg->al_bridge, if_list[i]); + } + } + } +#endif + + return 0; +} + +int agent_disable_traffic_separation(struct agent *a) +{ + trace("%s: --->\n", __func__); + struct netif_fh *fh = NULL; + struct netif_bk *bk = NULL; + char cmd[64] = {0}; + + /* go through all (fh) SSIDs and remove any vid found */ + /* remove all existing vlans */ + + /* TODO: remove dual bridge */ + + /* Fronthaul */ + list_for_each_entry(fh, &a->fhlist, list) { + if (is_vid_valid(fh->vid)) { + snprintf(cmd, sizeof(cmd), "ts delete %s", fh->name); + agent_exec_platform_scripts(cmd); + fh->vid = TS_VID_INVALID; + } } - dbg("wakeup nl_thread\n"); - pthread_kill(a->nl_thread, SIGHUP); + /* Backhaul */ + list_for_each_entry(bk, &a->bklist, list) { + if (is_vid_valid(bk->vid)) { + snprintf(cmd, sizeof(cmd), "ts delete %s", bk->name); + agent_exec_platform_scripts(cmd); + bk->vid = TS_VID_INVALID; + } + } + + /* Ethernet */ + /* We might end without lei interface connected to br-map + * bridge. Enabling / disabling TS should be addressed + * properly , for now don't delete LEI */ +#if 0 + snprintf(cmd, sizeof(cmd), "ts delete %s", VLAN_IFACE); + agent_exec_platform_scripts(cmd); +#endif + + a->ts.active = false; return 0; } @@ -1597,9 +1818,19 @@ int handle_ap_autoconfig_wsc(void *agent, struct cmdu_buff *rx_cmdu) if (tv[1][0]) { struct tlv_traffic_sep_policy *tlv = (struct tlv_traffic_sep_policy *) tv[1][0]->data; + agent_fill_traffic_sep_policy(a, tlv); + dbg("|%s:%d| TS policy received\n", __func__, __LINE__); - agent_fill_traffic_sep_policy(a, tlv); + if (a->cfg.ts_enabled && tlv->num_ssid > 0) + a->ts.requested = true; + else + a->ts.requested = false; + + dbg("|%s:%d| TS status:\n", __func__, __LINE__); + dbg("\tenabled: %d\n", a->cfg.ts_enabled); + dbg("\trequested: %d\n", a->ts.requested); + dbg("\tactive: %d\n", a->ts.active); } dbg("|%s:%d| radio (%s) was configured! Apply heartbeat for this radio\n", @@ -2251,8 +2482,19 @@ int handle_map_policy_config(void *agent, struct cmdu_buff *cmdu) struct tlv_traffic_sep_policy *p = (struct tlv_traffic_sep_policy *)tv[3][0]->data; - dbg("|%s:%d| TS policy received\n", __func__, __LINE__); agent_fill_traffic_sep_policy(a, p); + + dbg("|%s:%d| TS policy received\n", __func__, __LINE__); + + if (a->cfg.ts_enabled && p->num_ssid > 0) + a->ts.requested = true; + else + a->ts.requested = false; + + dbg("|%s:%d| TS status:\n", __func__, __LINE__); + dbg("\tenabled: %d\n", a->cfg.ts_enabled); + dbg("\trequested: %d\n", a->ts.requested); + dbg("\tactive: %d\n", a->ts.active); } if (tv[4][0]) { @@ -2291,7 +2533,10 @@ int handle_map_policy_config(void *agent, struct cmdu_buff *cmdu) agent_process_policy_config(a); - agent_apply_traffic_separation(a); + if (a->cfg.ts_enabled && a->ts.requested) { + agent_apply_traffic_separation(a); + } else if (a->cfg.ts_enabled && a->ts.active) + agent_disable_traffic_separation(a); return 0; } diff --git a/src/agent_tlv.c b/src/agent_tlv.c index e0459a66cb7182eb887c29cf151b73328967910b..941f855421757ce7c8253d319d79e1a20bc960e7 100644 --- a/src/agent_tlv.c +++ b/src/agent_tlv.c @@ -2282,8 +2282,6 @@ int agent_fill_8021q_setting(struct agent *a, uci_save(ctx, pkg); } - dbg("Received Primary VID %u\n", BUF_GET_BE16(p->pvid)); - memset(buf, 0, sizeof(buf)); snprintf(buf, sizeof(buf) - 1, "%s.%s.pvid=%d", pkg->e.name, s->e.name, diff --git a/src/config.c b/src/config.c index 45c2e54b4b86c5e4947fe4320289c18746ff9b5a..76cb2b9f9c7156a89d2dc05644f272ac61698ab0 100644 --- a/src/config.c +++ b/src/config.c @@ -1812,6 +1812,7 @@ static int agent_config_get_wifi_agent(struct agent_config *a, A_AL_BRIDGE, A_NETDEV, A_IFPREFIX, + A_TS, A_RESEND_NUM, A_DYN_CNTLR_SYNC, A_ISL_PREV, @@ -1828,6 +1829,7 @@ static int agent_config_get_wifi_agent(struct agent_config *a, { .name = "al_bridge", .type = UCI_TYPE_STRING }, { .name = "netdev", .type = UCI_TYPE_STRING }, { .name = "ifprefix", .type = UCI_TYPE_STRING }, + { .name = "vlan_segregation", .type = UCI_TYPE_STRING }, { .name = "resend_num", .type = UCI_TYPE_STRING }, { .name = "dyn_cntlr_sync", .type = UCI_TYPE_STRING }, { .name = "island_prevention", .type = UCI_TYPE_STRING }, @@ -1882,6 +1884,9 @@ static int agent_config_get_wifi_agent(struct agent_config *a, sizeof(a->netdev) - 1); } + if (tb[A_TS]) + a->ts_enabled = atoi(tb[A_TS]->v.string); + if (tb[A_RESEND_NUM]) { const char *val = tb[A_RESEND_NUM]->v.string; @@ -2987,6 +2992,8 @@ int agent_config_init(struct agent *a, struct agent_config *cfg) INIT_LIST_HEAD(&cfg->bklist); INIT_LIST_HEAD(&cfg->radiolist); + cfg->ts_enabled = 0; + agent_config_prepare(cfg); agent_config_reload(cfg); diff --git a/src/config.h b/src/config.h index 2e1625c2f4e4e0ebe960480531aebac9143fc18a..c753722a252785141bf37ac78263b7d6ed41d7bf 100644 --- a/src/config.h +++ b/src/config.h @@ -190,6 +190,7 @@ struct agent_config { uint8_t profile; bool brcm_setup; bool configured; + bool ts_enabled; bool dyn_cntlr_sync; int resend_num; uint8_t cntlr_almac[6]; diff --git a/src/nl.c b/src/nl.c index 75d73781e82d990d7df0074298ed0d9ed84ad646..5916fa5ea664476fb622fde5555a6097a4cc37fe 100644 --- a/src/nl.c +++ b/src/nl.c @@ -4,18 +4,20 @@ #include <net/if.h> #include <uci.h> #include <string.h> -#include <pthread.h> #include <netlink/netlink.h> #include <netlink/route/rtnl.h> #include <netlink/socket.h> #include <netlink/msg.h> -#include <linux/if_bridge.h> - #include <sys/ioctl.h> #include <net/if.h> +#include <libubox/blobmsg.h> +#include <libubox/blobmsg_json.h> +#include <libubox/uloop.h> +#include <libubox/ustream.h> +#include <libubox/utils.h> #include <libubus.h> #include <easy/easy.h> @@ -25,397 +27,6 @@ #include "config.h" #include "agent.h" -#define dbg(...) fprintf(stderr, __VA_ARGS__) -#define warn(...) fprintf(stderr, __VA_ARGS__) - -#define TS_IFACE_MAX_NUM (2*WIFI_IFACE_MAX_NUM) -#define MAX_VIDS (WIFI_IFACE_MAX_NUM - 4) - -static struct nl_sock *nl_main_sk; -static struct nl_sock *nl_bridge_sk; -static struct nl_cb *nl_bridge_cb; - -static bool ts_bridge_dump_done; -static bool ts_check_vlan_settings; -bool ts_need_reconfig; - -struct ts_iface { - char name[IFNAMSIZ]; - uint16_t vid; - int ifi_index; - struct bridge_vlan_info cur_vinfo[MAX_VIDS]; - bool is_bsta; -}; - -static struct ts_iface ts_iface_array[TS_IFACE_MAX_NUM]; -static uint16_t ts_primary_vid; - -static uint16_t ts_all_vids[MAX_VIDS]; -static unsigned int ts_num_vids = 0; - -static bool ts_is_our_vid(uint16_t vid) -{ - int i; - - for (i = 0; i < ts_num_vids; i++) { - if (ts_all_vids[i] == vid) - return true; - } - - return false; -} - -static struct ts_iface *ts_find_iface(const char *ifname) -{ - int i; - - for (i = 0; i < TS_IFACE_MAX_NUM; i++) { - if (strncmp(ts_iface_array[i].name, ifname , 16) == 0) - return &ts_iface_array[i]; - } - - return NULL; -} - -static struct ts_iface *ts_configure_iface(const char *ifname, uint16_t vid) -{ - struct ts_iface *tsif; - int i; - - for (i = 0; i < TS_IFACE_MAX_NUM; i++) { - tsif = &ts_iface_array[i]; - if (tsif->name[0] == '\0') { - strncpy(tsif->name, ifname, IFNAMSIZ); - ts_check_vlan_settings = true; - break; - } - - if (strncmp(tsif->name, ifname, IFNAMSIZ) == 0) - break; - } - - if (i >= TS_IFACE_MAX_NUM) { - warn("Number of TS interfaces too small\n"); - return NULL; - } - - if (tsif->vid != vid) { - tsif->vid = vid; - ts_check_vlan_settings = true; - } - - if (vid != 0 && !ts_is_our_vid(tsif->vid)) { - if (ts_num_vids < MAX_VIDS) - ts_all_vids[ts_num_vids++] = tsif->vid; - else - warn("Too many vids\n"); - } - - return tsif; -} - -static void tsif_check_attr(struct ts_iface *tsif, struct rtattr *attr) -{ - struct bridge_vlan_info *vinfo; - struct rtattr *cur; - int rem = RTA_PAYLOAD(attr); - int i; - - for (cur = RTA_DATA(attr); RTA_OK(cur, rem); cur = RTA_NEXT(cur, rem)) { - if (cur->rta_type != IFLA_BRIDGE_VLAN_INFO) - continue; - - vinfo = RTA_DATA(cur); - - dbg("%s %s vid %d flags %0x\n", __func__, tsif->name, vinfo->vid, vinfo->flags); - - for (i = 0; i < MAX_VIDS; i++) { - if (tsif->cur_vinfo[i].vid == 0) { - tsif->cur_vinfo[i] = *vinfo; - break; - } - } - - if (i >= MAX_VIDS) - warn("%s cur_vinfo array too small\n", tsif->name); - } -} - -static int ts_nl_get_cb(struct nl_msg *msg, void *arg) -{ - struct nlmsghdr *nh = nlmsg_hdr(msg); - struct ifinfomsg *ifi = NLMSG_DATA(nh); - struct rtattr *attr; - struct ts_iface *tsif; - char name[16]; - char *ifname; - int rem; - - if (!nh || !ifi) - return NL_SKIP; - - dbg("%s family %u index %u\n", __func__, ifi->ifi_family, ifi->ifi_index); - - if (nh->nlmsg_type != RTM_NEWLINK) - return NL_SKIP; - - if (ifi->ifi_family != AF_BRIDGE) - return NL_SKIP; - - ifname = if_indextoname(ifi->ifi_index, name); - if (!ifname) { - ts_bridge_dump_done = true; - return NL_STOP; - } - - tsif = ts_find_iface(ifname); - if (!tsif) - return NL_SKIP; - - attr = IFLA_RTA(ifi); - rem = nh->nlmsg_len - NLMSG_LENGTH(sizeof(*ifi)); - while (RTA_OK(attr, rem)) { - if (attr->rta_type == IFLA_AF_SPEC) - tsif_check_attr(tsif, attr); - - attr = RTA_NEXT(attr, rem); - } - - tsif->ifi_index = ifi->ifi_index; - - return NL_SKIP; -} - -static int ts_nl_finish_cb(struct nl_msg *msg, void *arg) -{ - dbg("%s\n", __func__); - - ts_bridge_dump_done = true; - - return NL_STOP; -} - -static int ts_nl_error_cb(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg) -{ - /* TODO print error */ - dbg("%s\n", __func__); - - ts_bridge_dump_done = true; - - return NL_STOP; -} - -void ts_read_bridge_vlan(const char *br_name) -{ - static struct ifinfomsg ifi = { - .ifi_family = AF_BRIDGE - }; - static struct rtattr ext_req = { - .rta_type = IFLA_EXT_MASK, - .rta_len = RTA_LENGTH(sizeof(uint32_t)), - }; - uint32_t filter = RTEXT_FILTER_BRVLAN; - struct nl_msg *nlmsg; - int ret; - - /* TODO check if this works when there are more than one bridge */ - ifi.ifi_index = if_nametoindex(br_name); - if (ifi.ifi_index <= 0) - return; - - - nlmsg = nlmsg_alloc_simple(RTM_GETLINK, NLM_F_DUMP); - if (!nlmsg) - return; - - dbg("%s START\n", __func__); - - ret = nlmsg_append(nlmsg, &ifi, sizeof(ifi), 0); - ret |= nlmsg_append(nlmsg, &ext_req, sizeof(ext_req), NLMSG_ALIGNTO); - ret |= nlmsg_append(nlmsg, &filter, sizeof(filter), 0); - - if (ret) - goto free; - - ts_bridge_dump_done = false; - - if (nl_send_auto_complete(nl_bridge_sk, nlmsg) < 0) - ts_bridge_dump_done = true; - - while (!ts_bridge_dump_done) - nl_recvmsgs(nl_bridge_sk, nl_bridge_cb); -free: - nlmsg_free(nlmsg); - - dbg("%s END\n", __func__); -} - -static int send_bridge_vlan_info(int nlmsg_type, struct ifinfomsg *ifi, struct bridge_vlan_info *vinfo, int n) -{ - struct nl_msg *nlmsg; - struct nlattr *attr; - int ret = -1; - int i; - - nlmsg = nlmsg_alloc_simple(nlmsg_type, NLM_F_REQUEST); - if (!nlmsg) - return -1; - - nlmsg_append(nlmsg, ifi, sizeof(*ifi), 0); - - attr = nla_nest_start(nlmsg, IFLA_AF_SPEC); - if (!attr) - goto err; - - for (i = 0; i < n; i++) - nla_put(nlmsg, IFLA_BRIDGE_VLAN_INFO, sizeof(vinfo[i]), &vinfo[i]); - - nla_nest_end(nlmsg, attr); - - ret = nl_send_auto_complete(nl_main_sk, nlmsg); - -err: - nlmsg_free(nlmsg); - - return ret < 0 ? ret : 0; -} - -static void ts_set_iface_vlan(struct ts_iface *tsif) -{ - const uint16_t prim_flags = BRIDGE_VLAN_INFO_PVID | BRIDGE_VLAN_INFO_UNTAGGED; - struct ifinfomsg ifi = { .ifi_family = PF_BRIDGE }; - struct bridge_vlan_info add_vinfo[MAX_VIDS]; - struct bridge_vlan_info del_vinfo[MAX_VIDS]; - int n_del, n_add; - int i, ret; - bool has_vid; - - ifi.ifi_index = tsif->ifi_index; - if (ifi.ifi_index <= 0) { - warn("Wrong index %d for %s\n", tsif->ifi_index, tsif->name); - return; - } - - n_del = 0; - n_add = 0; - - if (tsif->vid) { - /* Fronthaul */ - has_vid = false; - for (i = 0; i < MAX_VIDS; i++) { - if (tsif->cur_vinfo[i].vid == 0) - break; - - if (tsif->cur_vinfo[i].vid != tsif->vid) - del_vinfo[n_del++] = tsif->cur_vinfo[i]; - else if (tsif->cur_vinfo[i].flags == prim_flags) - has_vid = true; - } - - if (!has_vid) { - add_vinfo[0].vid = tsif->vid; - add_vinfo[0].flags = prim_flags; - n_add = 1; - } - } else { - /* Backhaul */ - for (i = 0; i < MAX_VIDS; i++) { - if (tsif->cur_vinfo[i].vid == 0) - break; - - if (!ts_is_our_vid(tsif->cur_vinfo[i].vid)) - del_vinfo[n_del++] = tsif->cur_vinfo[i]; - } - - for (i = 0; i < ts_num_vids; i++) { - add_vinfo[i].vid = ts_all_vids[i]; -#if 0 - /* if we want primary vid to be send untagged - * similar like for eth interfaces, but this - * is not MultiAP spec compliant. - */ - if (add_vinfo[i].vid == ts_primary_vid) - add_vinfo[i].flags = prim_flags; - else -#endif - add_vinfo[i].flags = 0; - } - n_add = i; - } - - if (n_add == 0 && n_del == 0) - return; - - dbg("add %d del %d vids for %s iface %s %d\n", n_add, n_del, - tsif->vid ? "fronthaul" : "backhaul", tsif->name, tsif->ifi_index); - - if (n_add > 0) { - ret = send_bridge_vlan_info(RTM_SETLINK, &ifi, add_vinfo, n_add); - if (ret < 0) - warn("Failed to add vlan info for %s\n", tsif->name); - } - - if (n_del > 0) { - ret = send_bridge_vlan_info(RTM_DELLINK, &ifi, del_vinfo, n_del); - if (ret < 0) - warn("Failed to remove vlan info %s\n", tsif->name); - } -} - -static void ts_set_system(void) -{ - char buf[16] = {0}; - uint16_t vid; - int i; - - if (ts_primary_vid == 0) - return; - - for (i = 0; i < ts_num_vids; i++) { - vid = ts_all_vids[i]; - warn("/lib/wifi/multiap ts create %u\n",vid); - Cmd(buf, sizeof(buf), "/lib/wifi/multiap ts create %u", vid); - } - - warn("/lib/wifi/multiap ts reload\n"); - Cmd(buf, sizeof(buf), "/lib/wifi/multiap ts reload"); -} - -static void ts_check_ifi(struct ifinfomsg *ifi, const char *ifname) -{ - struct ts_iface *tsif; - - - if (ts_primary_vid == 0) - return; - -/* - if (ifi->ifi_family == AF_BRIDGE) - return; -*/ - - if (!(ifi->ifi_flags & IFF_UP)) - return; - - tsif = ts_find_iface(ifname); - if (tsif) { - ts_check_vlan_settings = true; - dbg("found %s tsif %p ifi_index %d\n", ifname, tsif, tsif->ifi_index); - return; - } - - if (!strstr(ifname, "wds")) - return; - - tsif = ts_configure_iface(ifname, 0); - if (tsif) { - tsif->ifi_index = ifi->ifi_index; - ts_check_vlan_settings = true; - dbg("added %s tsif %p ifi_index %d\n", ifname, tsif, tsif->ifi_index); - } else { - warn("Fail to add %s interface to ts array\n", ifname); - } -} int if_updown(const char *ifname, bool up) { @@ -452,11 +63,9 @@ int if_updown(const char *ifname, bool up) return 0; } -static int nl_main_cb(struct nl_msg *msg, void *arg) +static int func(struct nl_msg *msg, void *arg) { struct nlmsghdr *nlh = nlmsg_hdr(msg); - struct agent *a = (struct agent *) arg; - const char *bridge = a->cfg.al_bridge; switch (nlh->nlmsg_type) { case RTM_GETLINK: @@ -465,31 +74,42 @@ static int nl_main_cb(struct nl_msg *msg, void *arg) { struct ifinfomsg *ifi; char ifname[16] = {0}; + struct agent *a = (struct agent *) arg; + char *bridge = a->cfg.al_bridge; int ret; ifi = NLMSG_DATA(nlh); - if (if_indextoname(ifi->ifi_index, ifname) == NULL) - break; + if_indextoname(ifi->ifi_index, ifname); - fprintf(stderr, "ifname = %s ifindex = %d family = %u status = %s action = %s\n", - ifname, - ifi->ifi_index, - ifi->ifi_family, - !!(ifi->ifi_flags & IFF_UP) ? "up" : "down", - nlh->nlmsg_type == RTM_GETLINK ? "RTM_GETLINK" : - nlh->nlmsg_type == RTM_NEWLINK ? "RTM_NEWLINK" : - "RTM_DELLINK"); - -/* - if (!(ifi->ifi_flags & IFF_UP)) - break; -*/ - ts_check_ifi(ifi, ifname); + //printf("ifname = %s ifindex = %d status = %s action = %s\n", + // ifname, + // ifi->ifi_index, + // !!(ifi->ifi_flags & IFF_UP) ? "up" : "down", + // nlh->nlmsg_type == RTM_GETLINK ? "RTM_GETLINK" : + // nlh->nlmsg_type == RTM_NEWLINK ? "RTM_NEWLINK" : + // "RTM_DELLINK"); + + //if (!(ifi->ifi_flags & IFF_UP)) + // break; if (!strstr(ifname, "wds")) break; +#if 0 // Not needed for now, maybe never? + // TODO: find a better place to do this + if (a->ts.active && !strstr(ifname, "vlan")) { + char buf[32] = { 0 }; + snprintf(buf, 32, "%s_vlan", ifname); + if (if_isbridge_interface(buf) == -1){ + // create tagged wds + runCmd("/lib/wifi/multiap ts create bh %s %d 2", + ifname, a->cfg.pcfg->pvid ); + } + break; + } +#endif + if (if_isbridge_interface(ifname)) { int i, num, max = 32; char if_list[max][16]; @@ -512,7 +132,8 @@ static int nl_main_cb(struct nl_msg *msg, void *arg) break; } - printf("Adding interface %s to bridge %s!\n", ifname, bridge); + printf("Adding interface %s to bridge %s!\n", ifname, + bridge); /* add wds iface to bridge */ ret = br_addif(bridge, ifname); @@ -536,181 +157,24 @@ static int nl_main_cb(struct nl_msg *msg, void *arg) return 0; } -static inline bool is_vid_valid(unsigned int vid) -{ -#if 0 - dbg("%s: vid %u\n", __func__, vid); - - if (vid > TS_VID_INVALID) - abort(); -#endif - return (vid < TS_VID_INVALID) && (vid > 0); -} - -static void ts_configure(struct agent *a) -{ - struct netif_fh *fh; - struct netif_bk *bk; - struct ts_iface *tsif; - uint16_t vid; - char buf[16]; - - /* TODO remove interfaces */ - - pthread_mutex_lock(&a->nl_mutex); - - if (is_vid_valid(a->cfg.pcfg->pvid)) { - ts_primary_vid = a->cfg.pcfg->pvid; - snprintf(buf, sizeof(buf), "%u", ts_primary_vid); - setenv("PRIMARY_VID", buf, 1); - } - - if (ts_primary_vid == 0) - goto out; - - /* Fronthaul */ - list_for_each_entry(fh, &a->fhlist, list) { - dbg("FH name %s multi_ap %d\n", fh->name, fh->cfg->multi_ap); - // TODO? Mixed FH/BH - if (fh->cfg->multi_ap != 2) - continue; - - vid = fh->cfg->vid; - if (!is_vid_valid(vid)) - vid = a->cfg.pcfg->pvid; - - ts_configure_iface(fh->name, vid); - } - - /* Backhaul stations */ - list_for_each_entry(bk, &a->bklist, list) { - dbg("BK name %s\n", bk->name); - - tsif = ts_configure_iface(bk->name, 0); - if (tsif) - tsif->is_bsta = true; - } - -out: - pthread_mutex_unlock(&a->nl_mutex); -} - -int init_bridge_nl_sock(void) -{ - nl_bridge_sk = nl_socket_alloc(); - if (!nl_bridge_sk) - return -1; - - nl_bridge_cb = nl_cb_alloc(NL_CB_DEFAULT); - if (!nl_bridge_cb) { - nl_socket_free(nl_bridge_sk); - return -1; - } - - nl_connect(nl_bridge_sk, NETLINK_ROUTE); - nl_socket_add_memberships(nl_bridge_sk, RTNLGRP_LINK, 0); - - nl_cb_set(nl_bridge_cb, NL_CB_VALID, NL_CB_CUSTOM, ts_nl_get_cb, NULL); - nl_cb_set(nl_bridge_cb, NL_CB_FINISH, NL_CB_CUSTOM, ts_nl_finish_cb, NULL); - nl_cb_set(nl_bridge_cb, NL_CB_ACK, NL_CB_CUSTOM, ts_nl_finish_cb, NULL); - nl_cb_err(nl_bridge_cb, NL_CB_CUSTOM, ts_nl_error_cb, NULL); - - return 0; -} - -int init_main_nl_sock(struct agent *agent) -{ - nl_main_sk = nl_socket_alloc(); - if (!nl_main_sk) - return -1; - - nl_socket_disable_seq_check(nl_main_sk); - nl_socket_modify_cb(nl_main_sk, NL_CB_VALID, NL_CB_CUSTOM, nl_main_cb, agent); - - nl_connect(nl_main_sk, NETLINK_ROUTE); - nl_socket_add_memberships(nl_main_sk, RTNLGRP_LINK, 0); - nl_rtgen_request(nl_main_sk, RTM_GETLINK, AF_UNSPEC, NLM_F_DUMP); - - return 0; -} - int nl_loop(void *arg) { - struct agent *agent = arg; - char *bridge = agent->cfg.al_bridge; - struct pollfd fds[1]; - int ret, i; - - setenv("AL_BRIDGE", bridge, 1); - - ret = init_bridge_nl_sock(); - if (ret) - return -1; - - ret = init_main_nl_sock(agent); - if (ret) - return -1; - - fds[0].fd = nl_socket_get_fd(nl_main_sk); - fds[0].events = POLLIN; - - for (;;) { - ts_check_vlan_settings = false; - - dbg("Start polling ...\n"); - - ret = poll(fds, 1, -1); - - dbg("End polling with %d ret %08x revents\n", ret , fds[0].revents); - - if (fds[0].revents) { - ret = nl_recvmsgs_default(nl_main_sk); - fprintf(stderr, "nl_recvmsgs_default ret %d\n", ret); - } - - if (ts_need_reconfig) { - ts_configure(agent); - ts_need_reconfig = false; + struct nl_sock *sk; - ts_set_system(); - } + sk = nl_socket_alloc(); + if (!sk) + return 1; - if (ts_check_vlan_settings) { - dbg("Reading bridge %s vlan config\n", bridge); - for (i = 0; i < TS_IFACE_MAX_NUM; i++) { - ts_iface_array[i].cur_vinfo[0].vid = 0; - ts_iface_array[i].ifi_index = 0; - } - ts_read_bridge_vlan(bridge); - - for (i = 0; i < TS_IFACE_MAX_NUM; i++) { - struct ts_iface *tsif = &ts_iface_array[i]; - - if (tsif->name[0] == '\0') - break; + nl_socket_disable_seq_check(sk); - dbg("checking vlan settings for %s tsif %p index %d\n", - tsif->name, tsif, tsif->ifi_index); + nl_socket_modify_cb(sk, NL_CB_VALID, NL_CB_CUSTOM, func, arg); - /* Add to the bridge if not added already and if not backhaul sta, - * bsta bridging is done by dynamically by other entities. - */ - if (ts_iface_array[i].ifi_index <= 0 && !tsif->is_bsta) { - ret = br_addif(bridge, tsif->name); - dbg("(re)added %s interface to %s with status %d\n", - tsif->name, bridge, ret); + nl_connect(sk, NETLINK_ROUTE); + nl_socket_add_memberships(sk, RTNLGRP_LINK, 0); + nl_rtgen_request(sk, RTM_GETLINK, AF_UNSPEC, NLM_F_DUMP); - ts_iface_array[i].ifi_index = if_nametoindex(tsif->name); - dbg("get %s index %d\n", tsif->name, tsif->ifi_index); - - } - - if (ts_iface_array[i].ifi_index <= 0) - continue; - ts_set_iface_vlan(&ts_iface_array[i]); - } - } - } + for (;;) + nl_recvmsgs_default(sk); return 0; } diff --git a/src/nl.h b/src/nl.h index c9b981ff2111a7328baf6dd17d9089a263882ba4..5815516dca58433d50de7f1513202fafb49ef384 100644 --- a/src/nl.h +++ b/src/nl.h @@ -3,6 +3,4 @@ int nl_loop(void); -extern bool ts_need_reconfig; - #endif /* MAPAGENT_NL_H */