diff --git a/src/agent.c b/src/agent.c index 05826265f05c4328cdc9ffc181c275b190c4d5b0..182c91837a01bd44a573d93a0787afa88b15b2c3 100644 --- a/src/agent.c +++ b/src/agent.c @@ -127,9 +127,16 @@ out: bk->bsta_steer.cmdu = NULL; } +static pthread_t nl_thread; + static void agent_sighandler(int sig) { - uloop_end(); + pthread_t self = pthread_self(); + + if (nl_thread == self) + ts_need_reconfig = true; + else + uloop_end(); } int agent_exec_platform_scripts(char *arg) @@ -2948,14 +2955,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 && a->cfg.ts_enabled) { + if (atoi(buf) && a) { if (!(a->cfg.pcfg)) { a->cfg.pcfg = (struct policy_cfg *)calloc(1, sizeof(struct policy_cfg)); if (!(a->cfg.pcfg)) { @@ -2964,10 +2971,14 @@ 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); - a->ts.requested = 1; - agent_apply_traffic_separation(a); + pthread_mutex_unlock(&a->nl_mutex); + + /* TODO save pvid in the config file */ } +#endif } char *agent_get_backhaul_ifname(char *ifname) @@ -3611,37 +3622,6 @@ 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) @@ -3949,7 +3929,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; @@ -3972,9 +3952,6 @@ 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; @@ -4009,7 +3986,12 @@ static void wifi_wps_creds_event_handler(void *c, struct blob_attr *msg) uloop_timeout_set(&a->onboarding_scheduler, timeout * 1000); - if (vlan && bk->agent && bk->agent->cfg.ts_enabled) { +#if 0 /* Not used at present */ + vlan = 0; + if (tb[4]) + vlan = (uint16_t) blobmsg_get_u16(tb[4]); + + if (vlan && bk->agent) { if (!(a->cfg.pcfg)) { a->cfg.pcfg = (struct policy_cfg *)calloc(1, sizeof(struct policy_cfg)); if (!(a->cfg.pcfg)) { @@ -4018,10 +4000,13 @@ 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; - bk->agent->ts.requested = 1; + pthread_mutex_unlock(&a->nl_mutex); + agent_apply_traffic_separation(bk->agent); } +#endif } static void agent_event_handler(struct ubus_context *ctx, @@ -4859,6 +4844,7 @@ 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; } @@ -5496,8 +5482,10 @@ int agent_init_interfaces(struct agent *a) fn->cfg = f; fn->agent = a; strncpy(fn->radio_name, radio_name, IFNAMSIZ-1); - fn->vid = TS_VID_INVALID; + + pthread_mutex_lock(&a->nl_mutex); list_add(&fn->list, &a->fhlist); + pthread_mutex_unlock(&a->nl_mutex); } snprintf(r_objname, 31, "wifi.radio.%s", radio_name); @@ -5535,19 +5523,14 @@ 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) { - 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); - } + pthread_mutex_lock(&a->nl_mutex); list_add(&bn->list, &a->bklist); + pthread_mutex_unlock(&a->nl_mutex); } } @@ -5576,7 +5559,6 @@ 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) @@ -5604,7 +5586,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; } @@ -5619,17 +5601,12 @@ 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); } @@ -5647,11 +5624,6 @@ 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 @@ -5870,7 +5842,7 @@ void clear_restrict_stalist(struct netif_fh *p) } } -static void netif_free(struct netif_fh *n) +static void netif_free(struct agent *a, struct netif_fh *n) { /* clear stalist */ clear_stalist(n); @@ -5888,7 +5860,10 @@ static void netif_free(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); } @@ -5897,10 +5872,23 @@ void clear_fhlist(struct agent *a) struct netif_fh *p, *tmp; list_for_each_entry_safe(p, tmp, &a->fhlist, list) { - netif_free(p); + netif_free(a, 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; @@ -6059,7 +6047,6 @@ 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); @@ -6071,6 +6058,7 @@ 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); @@ -6097,23 +6085,26 @@ 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; - /* TODO: memory management of thread on cleaup */ - ret = pthread_create(&(tid[0]), NULL, (void *)&nl_loop, w); + ret = pthread_create(&w->nl_thread, NULL, (void *)&nl_loop, w); if (ret) { fprintf(stderr, "Failed to create thread\n"); + free(w); return; } - pthread_detach(tid[0]); + nl_thread = w->nl_thread; } //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"); @@ -6149,19 +6140,26 @@ 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 72306725f15a64c4cb147bfc9cb37a2e9c002c73..6a662b5cbd18fea4b9ef87f3ad79ff345a5dfec0 100644 --- a/src/agent.h +++ b/src/agent.h @@ -16,6 +16,7 @@ #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> @@ -268,9 +269,6 @@ struct netif_fh { /* previous channel utilization threshold value */ uint8_t prev_util; - - /* traffic separation */ - unsigned int vid; }; /* backhaul wifi (sta) interface */ @@ -295,9 +293,6 @@ struct netif_bk { struct cmdu_buff *cmdu; } bsta_steer; struct uloop_timeout connect_timer; - - /* traffic separation */ - unsigned int vid; }; #if 0 @@ -649,13 +644,9 @@ struct agent { struct uloop_timeout fh_disable_timer; #endif /* AGENT_ISLAND_PREVENTION */ - /* 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; + /* traffic separation and netlink events */ + pthread_t nl_thread; + pthread_mutex_t nl_mutex; /* dynamic backhaul */ struct uloop_timeout upgrade_backhaul_scheduler; @@ -735,6 +726,7 @@ 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 43de2a00d23649e6adeaee87a94b0a3135419e45..56083dccc0c5cf25a8b4c6caa9d282fe3c05c745 100644 --- a/src/agent_map.c +++ b/src/agent_map.c @@ -903,14 +903,6 @@ 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)) { @@ -1425,63 +1417,13 @@ 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; - struct netif_fh *fh; - struct netif_bk *bk; - bool diff = false; - char cmd[128] = {0}; - bool dhcp_reload = false; + + trace("%s: --->\n", __func__); if (!a) return -1; @@ -1498,179 +1440,16 @@ int agent_apply_traffic_separation(struct agent *a) return -1; } - /* 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) + if (c->pvid == 0) return 0; - /* 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; - } + if (!is_vid_valid(c->pvid)) { + warn("Invalid primary vlan id %u", c->pvid); + return -1; } - /* 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; + dbg("wakeup nl_thread\n"); + pthread_kill(a->nl_thread, SIGHUP); return 0; } @@ -1818,19 +1597,9 @@ 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__); - 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); + agent_fill_traffic_sep_policy(a, tlv); } dbg("|%s:%d| radio (%s) was configured! Apply heartbeat for this radio\n", @@ -2482,19 +2251,8 @@ 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; - 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); + agent_fill_traffic_sep_policy(a, p); } if (tv[4][0]) { @@ -2533,10 +2291,7 @@ int handle_map_policy_config(void *agent, struct cmdu_buff *cmdu) agent_process_policy_config(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); + agent_apply_traffic_separation(a); return 0; } diff --git a/src/agent_tlv.c b/src/agent_tlv.c index 941f855421757ce7c8253d319d79e1a20bc960e7..e0459a66cb7182eb887c29cf151b73328967910b 100644 --- a/src/agent_tlv.c +++ b/src/agent_tlv.c @@ -2282,6 +2282,8 @@ 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 76cb2b9f9c7156a89d2dc05644f272ac61698ab0..45c2e54b4b86c5e4947fe4320289c18746ff9b5a 100644 --- a/src/config.c +++ b/src/config.c @@ -1812,7 +1812,6 @@ 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, @@ -1829,7 +1828,6 @@ 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 }, @@ -1884,9 +1882,6 @@ 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; @@ -2992,8 +2987,6 @@ 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 c753722a252785141bf37ac78263b7d6ed41d7bf..2e1625c2f4e4e0ebe960480531aebac9143fc18a 100644 --- a/src/config.h +++ b/src/config.h @@ -190,7 +190,6 @@ 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 5916fa5ea664476fb622fde5555a6097a4cc37fe..75d73781e82d990d7df0074298ed0d9ed84ad646 100644 --- a/src/nl.c +++ b/src/nl.c @@ -4,20 +4,18 @@ #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> @@ -27,6 +25,397 @@ #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) { @@ -63,9 +452,11 @@ int if_updown(const char *ifname, bool up) return 0; } -static int func(struct nl_msg *msg, void *arg) +static int nl_main_cb(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: @@ -74,41 +465,30 @@ static int func(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_indextoname(ifi->ifi_index, 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 (if_indextoname(ifi->ifi_index, ifname) == NULL) + break; - if (!strstr(ifname, "wds")) + 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); -#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 ); - } + if (!strstr(ifname, "wds")) break; - } -#endif if (if_isbridge_interface(ifname)) { int i, num, max = 32; @@ -132,8 +512,7 @@ static int func(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); @@ -157,24 +536,181 @@ static int func(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 nl_sock *sk; + 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; - sk = nl_socket_alloc(); - if (!sk) - return 1; + ts_set_system(); + } - nl_socket_disable_seq_check(sk); + 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_modify_cb(sk, NL_CB_VALID, NL_CB_CUSTOM, func, arg); + dbg("checking vlan settings for %s tsif %p index %d\n", + tsif->name, tsif, tsif->ifi_index); - nl_connect(sk, NETLINK_ROUTE); - nl_socket_add_memberships(sk, RTNLGRP_LINK, 0); - nl_rtgen_request(sk, RTM_GETLINK, AF_UNSPEC, NLM_F_DUMP); + /* 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); - for (;;) - nl_recvmsgs_default(sk); + 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]); + } + } + } return 0; } diff --git a/src/nl.h b/src/nl.h index 5815516dca58433d50de7f1513202fafb49ef384..c9b981ff2111a7328baf6dd17d9089a263882ba4 100644 --- a/src/nl.h +++ b/src/nl.h @@ -3,4 +3,6 @@ int nl_loop(void); +extern bool ts_need_reconfig; + #endif /* MAPAGENT_NL_H */