diff --git a/src/Makefile b/src/Makefile index a027ddf1ed20c1fb9583d8a8d9a90e500a086207..a8910ba167c58f34bf3e038b98133c751f97554f 100644 --- a/src/Makefile +++ b/src/Makefile @@ -37,7 +37,8 @@ AGENT_OBJS = \ dppfrag.o \ dpphandler.o \ qos.o \ - unasta.o + unasta.o \ + mld.o ifneq (,$(findstring VENDOR_EXTENSION,$(CFLAGS))) AGENT_OBJS += extension.o diff --git a/src/agent.c b/src/agent.c index d518584a783218f25f400aea5627b05c23e5a69c..37eb8f29830a9ae629b23141970e96609167337e 100644 --- a/src/agent.c +++ b/src/agent.c @@ -59,6 +59,9 @@ #include "qos.h" #endif #include "extension.h" +#if (EASYMESH_VERSION >= 6) +#include "mld.h" +#endif #include "nl.h" #include "steer_rules.h" #include "timer_impl.h" @@ -74,7 +77,6 @@ struct json_object; #define map_plugin "ieee1905.map" -#define IFACE_TIMEOUT 1 #define BOOT_UP_SCAN_TIME (0 * 1000) #define BOOT_UP_SCAN_ITV (2 * 1000) #define BOOT_UP_SCAN_MAX_TRY 5 @@ -93,10 +95,6 @@ static int agent_req_btm_steer(struct agent *a, const char *ifname, uint32_t validity_int); static void netif_free(struct netif_ap *ap); static void netif_reset(struct netif_ap *ap); -#if (EASYMESH_VERSION >= 6) -static void clear_apmld(struct netif_mld *mld); -#endif -void agent_clear_bsta_mld(struct agent *a); static void bsta_steer_cb(atimer_t *t) { @@ -198,37 +196,7 @@ struct node *agent_add_node(struct agent *a, uint8_t *almac) return n; } -#if (EASYMESH_VERSION >= 6) -bool wifi_is_affiliated_ap(struct agent *a, uint8_t *bssid) -{ - struct netif_ap *ap; - - ap = agent_get_ap(a, bssid); - if (ap && ap->is_affiliated_ap) - return true; - - return false; -} - -bool agent_radio_support_ap_wifi7(struct wifi7_radio_capabilities *wifi7_caps) -{ - if (wifi7_caps->ap_str_support || wifi7_caps->ap_nstr_support || - wifi7_caps->ap_emlsr_support || wifi7_caps->ap_emlmr_support) - return true; - - return false; -} - -bool agent_radio_support_bsta_wifi7(struct wifi7_radio_capabilities *wifi7_caps) -{ - if (wifi7_caps->bsta_str_support || wifi7_caps->bsta_nstr_support || - wifi7_caps->bsta_emlsr_support || wifi7_caps->bsta_emlmr_support) - return true; - - return false; -} -#endif struct wifi_radio_element *agent_get_radio_by_band(struct agent *a, enum wifi_band band) { @@ -536,136 +504,8 @@ struct wifi_assoc_frame *wifi_get_frame(struct agent *a, uint8_t *macaddr) return NULL; } -#if (EASYMESH_VERSION >=6) -struct netif_mld *agent_get_mld_by_ifname(struct agent *a, const char *ifname) -{ - struct netif_mld *mld = NULL; - - list_for_each_entry(mld, &a->apmldlist, list) { - if (!strncmp(ifname, mld->ifname, sizeof(mld->ifname))) - return mld; - } - - return NULL; -} - -struct netif_mld *agent_alloc_mld(struct agent *a, const char *ifname) -{ - struct netif_mld *mld; - - if (strlen(ifname) == 0) { - err("|%s:%d| MLD can not have empty ifname\n", __func__, __LINE__); - return NULL; - } - - mld = calloc(1, sizeof(*mld)); - if (!mld) - return NULL; - - dbg("|%s:%d| allocated mld ifname:%s\n", __func__, __LINE__, ifname); - - INIT_LIST_HEAD(&mld->stamldlist); - - strncpy(mld->ifname, ifname, sizeof(mld->ifname)); - list_add_tail(&mld->list, &a->apmldlist); - a->num_ap_mld++; - - return mld; -} -bool agent_is_ap_in_mld(struct agent *a, struct netif_mld *mld, - uint8_t *macaddr) -{ - int i; - - for (i = 0; i < mld->num_affiliated_ap; i++) { - if (!memcmp(mld->affiliated_ap[i]->bssid, macaddr, 6)) - return true; - } - - return false; -} - -bool agent_is_sta_in_sta_mld(struct agent *a, struct sta_mld *mld, - uint8_t *macaddr) -{ - int i; - - for (i = 0; i < mld->num_affiliated_sta; i++) { - if (!memcmp(mld->affiliated_sta[i]->macaddr, macaddr, 6)) - return true; - } - - return false; -} - - -bool agent_is_sta_in_bsta_mld(struct agent *a, struct bsta_mld *mld, - uint8_t *macaddr) -{ - int i; - - for (i = 0; i < mld->num_affiliated_bsta; i++) { - if (!memcmp(mld->affiliated_bsta[i]->macaddr, macaddr, 6)) - return true; - } - - return false; -} - - -struct sta_mld *agent_get_stamld(struct agent *a, uint8_t *macaddr) -{ - struct netif_mld *mld; - - list_for_each_entry(mld, &a->apmldlist, list) { - struct sta_mld *s; - - list_for_each_entry(s, &mld->stamldlist, list) { - if (!memcmp(macaddr, s->macaddr, 6)) - return s; - } - } - - return NULL; -} - -struct sta_mld *agent_alloc_stamld(struct agent *a, struct netif_mld *mld, - uint8_t *macaddr) -{ - struct sta_mld *s; - - s = calloc(1, sizeof(*s)); - if (!s) - return NULL; - - trace("|%s:%d| allocate sta mac:"MACFMT"\n", __func__, __LINE__, MAC2STR(macaddr)); - memcpy(s->macaddr, macaddr, 6); - - list_add_tail(&s->list, &mld->stamldlist); - - return s; -} - -struct bsta_mld *agent_init_bstamld(struct agent *a, char *ifname, - struct wifi7_radio_capabilities *caps) -{ - struct bsta_mld *bsta = &a->bstamld; - - strncpy(bsta->ifname, ifname, sizeof(bsta->ifname)); - dbg("|%s:%d| allocated bsta mld:%s\n", __func__, __LINE__, bsta->ifname); - - bsta->str_enabled = caps->bsta_str_support; - bsta->nstr_enabled = caps->bsta_nstr_support; - bsta->emlsr_enabled = caps->bsta_emlsr_support; - bsta->emlmr_enabled = caps->bsta_emlmr_support; - a->has_bstamld = true; - - return bsta; -} -#endif - /* lookup netif_bk struct by device */ struct netif_bk *agent_bsta_in_radio(struct agent *a, const char *device) @@ -1614,55 +1454,17 @@ static int cond_refresh_sta_neighbor_list(struct agent *a, struct sta *s) return 0; } -#if (EASYMESH_VERSION >= 6) -static void mlsta_update_sta_mld(struct agent *a, struct netif_ap *ap, - struct wifi_mlsta *mlsta, struct sta *s) -{ - struct sta_mld *mld; - int num_sta = 0; - - if (!ap || !mlsta) - return; - - //err("|%s:%d| mldmac:"MACFMT" linkmac:"MACFMT"\n", - // __func__, __LINE__, - // MAC2STR(ap->mld->macaddr), MAC2STR(mlsta->macaddr)); - - mld = agent_get_stamld(a, mlsta->macaddr); - if (!mld) { - mld = agent_alloc_stamld(a, ap->mld, mlsta->macaddr); - if (!mld) - return; - } - - memcpy(mld->bssid, mlsta->bssid, 6); - num_sta = mld->num_affiliated_sta; - - s->mld = mld; - s->is_affiliated_sta = true; - s->mlo_link_id = mlsta->sta[0].mlo_link_id; - - if (!agent_is_sta_in_sta_mld(a, mld, mlsta->sta[0].macaddr) && - num_sta < MAX_AFFILIATED_STA_LINKS_NUM) { - mld->affiliated_sta[num_sta] = s; - mld->num_affiliated_sta++; - } - //err("|%s:%d| num affiliated_sta:%d\n", - // __func__, __LINE__, - // mld->num_affiliated_sta); -} -#endif #define STA_STALE_STATS_CNT_MAX 60 static void wifi_sta_periodic_run(atimer_t *t) { struct sta *s = container_of(t, struct sta, sta_timer); struct pref_neighbor *pref_nbr = NULL; - struct netif_ap *ap; + struct agent *a = s->agent; struct wifi_sta sta = {}; + struct netif_ap *ap; unsigned int reason; - struct agent *a = s->agent; int ret = 0; ap = agent_get_ap(a, s->bssid); @@ -1694,12 +1496,8 @@ static void wifi_sta_periodic_run(atimer_t *t) #if (EASYMESH_VERSION >= 6) } else { struct wifi_mlsta mlsta = {0}; - uint8_t *mld_macaddr = NULL; - - if (s->mld) - mld_macaddr = s->mld->macaddr; - ret = wifi_get_mld_station(ap, mld_macaddr, s->macaddr, &mlsta); + ret = wifi_get_mld_station(ap, s->mld_macaddr, s->macaddr, &mlsta); if (ret) goto rearm_periodic; @@ -1713,17 +1511,11 @@ static void wifi_sta_periodic_run(atimer_t *t) return; } + if (mlsta.mlo_capable == true && + !hwaddr_is_zero(mlsta.sta[0].bssid)) + stamld_update(a, ap, mlsta.macaddr, mlsta.bssid, + mlsta.sta[0].mlo_link_id, s); - //err("%s: mac:"MACFMT" linkbssid:"MACFMT" mlo_link_id:%d\n", - // __func__, MAC2STR(s->macaddr), - // MAC2STR(mlsta.sta[0].bssid), - // mlsta.sta[0].mlo_link_id); - - if (mlsta.mlo_capable == true - && !hwaddr_is_zero(mlsta.sta[0].bssid) - && ap->mld) { - mlsta_update_sta_mld(a, ap, &mlsta, s); - } update_sta_entry(a, ap, &(mlsta.sta[0])); } #endif @@ -1875,105 +1667,6 @@ static struct sta *wifi_add_sta(struct agent *a, const char *ifname, return new; } -#if (EASYMESH_VERSION >= 6) -/* remove passed affiliated STA from mld */ -int wifi_sta_mld_del_sta(struct agent *a, struct sta *s) -{ - struct sta_mld *mld; - int i; - - if (!s->mld) - return -1; - - mld = s->mld; - for (i = 0; i < mld->num_affiliated_sta; i++) { - int j; - - if (memcmp(mld->affiliated_sta[i]->macaddr, s->macaddr, 6)) - continue; - - for (j = (i + 1); j < mld->num_affiliated_sta; j++) - mld->affiliated_sta[j-1] = mld->affiliated_sta[j]; - - mld->affiliated_sta[j] = NULL; - mld->num_affiliated_sta--; - } - - if (mld->num_affiliated_sta == 0) { - list_del(&mld->list); - free(mld); - } - - return 0; -} - -/* remove passed affiliated backhaul STA from mld */ -int wifi_sta_mld_del_bsta(struct agent *a, struct netif_bk *bk) -{ - struct bsta_mld *mld; - int i, j; - - /* bk->mld may be NULL if bSTAMLD is not connected (Eth backhaul) */ - if (!bk || bk->cfg->is_mld_netdev || !bk->mld) - return -1; - - mld = bk->mld; - for (i = 0; i < mld->num_affiliated_bsta; i++) { - if (!memcmp(mld->affiliated_bsta[i]->macaddr, bk->macaddr, 6)) - break; - } - - if (i == mld->num_affiliated_bsta) - return -1; - - for (j = (i + 1); j < mld->num_affiliated_bsta; j++) - mld->affiliated_bsta[j-1] = mld->affiliated_bsta[j]; - - mld->affiliated_bsta[j] = NULL; - mld->num_affiliated_bsta--; - - bk->mld = NULL; - bk->is_affiliated_sta = false; - - return 0; -} - -/* remove passed affiliated AP from mld */ -static int wifi_mld_del_ap(struct netif_ap *ap) -{ - struct netif_mld *mld; - int i; - - if (!ap->is_affiliated_ap) - return -1; - - if (!ap->mld) { - warn("|%s:%d| MLD for given netif is not assigned!\n", - __func__, __LINE__); - return -1; - } - - mld = ap->mld; - - for (i = 0; i < mld->num_affiliated_ap; i++) { - int j; - - if (memcmp(mld->affiliated_ap[i]->bssid, ap->bssid, 6)) - continue; - - for (j = (i + 1); j < mld->num_affiliated_ap; j++) - mld->affiliated_ap[j-1] = mld->affiliated_ap[j]; - - mld->affiliated_ap[j] = NULL; - mld->num_affiliated_ap--; - } - ap->mld = NULL; - ap->is_affiliated_ap = false; - - return 0; -} -#endif - static int wifi_del_sta(struct agent *a, const char *ifname, uint8_t *macaddr) { @@ -2482,86 +2175,6 @@ static int wifi_process_rx_frame(struct agent *a, struct json_object *frameobj) return -1; } -#if (EASYMESH_VERSION >= 6) -/* frame starting from payload, skipping header */ -int wifi_process_ml_ie(struct agent *a, struct sta_mld *stamld, - uint8_t *assocframe, int framelen) -{ - uint8_t *ml; - uint8_t *ml_ctrl; - uint8_t type; - uint8_t presence_bmp[2]; - - bool linkid_info_present; - bool bss_param_chg_present; - bool medium_sync_present; - bool eml_caps_present; - - bool mld_caps_ops_present; - uint8_t *common_info; - size_t pos; - - ml = wifi_find_ie_ext(assocframe, framelen, IE_EXT_ML); - if (!ml) { - dbg("%s: frame did not include ML IE\n", __func__); - return -1; - } - - ml_ctrl = ml + 3; - type = ml_ctrl[0] & 0x7; - presence_bmp[0] = (ml_ctrl[0] & 0xf0) >> 4; - presence_bmp[1] = ml_ctrl[1]; - - if (type != 0) { - dbg("%s: ML IE type non-zero\n", __func__); - return -1; - } - - linkid_info_present = !!(presence_bmp[0] & 0x1); - bss_param_chg_present = !!(presence_bmp[0] & 0x2); - medium_sync_present = !!(presence_bmp[0] & 0x4); - eml_caps_present = !!(presence_bmp[0] & 0x8); - - mld_caps_ops_present = !!(presence_bmp[1] & 0x1); - common_info = &ml_ctrl[2]; - pos = 1; - - pos += 6; /* skip apmld macaddr */ - - if (linkid_info_present) - pos += 1; - - if (bss_param_chg_present) - pos += 1; - - if (medium_sync_present) - pos += 2; - - if (eml_caps_present) { - uint8_t *eml_caps = &common_info[pos]; - - stamld->emlsr_enabled = !!(eml_caps[0] & BIT(0)) ? true : false; - stamld->emlmr_enabled = !!(eml_caps[0] & BIT(7)) ? true : false; - pos += 2; - } - - if (mld_caps_ops_present) { - uint8_t *mld_caps = &common_info[pos]; - uint8_t max_simlinks = (mld_caps[0] & 0x0f); - - pos += 2; - if (max_simlinks >= 1) { - stamld->nstr_enabled = false; - stamld->str_enabled = true; - } else { - stamld->nstr_enabled = true; - stamld->str_enabled = false; - } - } - - return 0; -} -#endif /* generate a netif_ap with first available ifname on passed radio */ struct netif_ap *agent_gen_netif_ap(struct agent *a, struct wifi_radio_element *re) @@ -2657,6 +2270,7 @@ static uint16_t wifi_process_pvid_assoc_frame(struct agent *a, uint8_t *frame, } #define ASSOC_TIMEOUT 60 +/* TODO: add dedicated handler for each event type */ static void wifi_sta_event_handler(void *c, struct blob_attr *msg) { struct agent *a = (struct agent *)c; @@ -2717,10 +2331,8 @@ static void wifi_sta_event_handler(void *c, struct blob_attr *msg) return; ap = agent_get_ap(a, bssid); - if (!ap) { - /* could also do link-id check here? */ + if (!ap) return; - } strncpy(ifname, ap->ifname, sizeof(ifname) - 1); } #endif @@ -2730,57 +2342,36 @@ static void wifi_sta_event_handler(void *c, struct blob_attr *msg) s = wifi_add_sta(a, ifname, macaddr); else s = agent_get_sta(a, macaddr); +#else + s = agent_get_sta(a, macaddr); +#endif if (!s) { dbg("%s: Failed to add STA or STA has already disconnected\n", __func__); return; } -#endif - #if (EASYMESH_VERSION >= 6) /* Affiliated STA MAC in-case of MLO client*/ - if (add && data[2] && data[3] && data[4]) { - uint8_t linkid = 0; - - linkid = (uint8_t) blobmsg_get_u32(data[4]); - - if (ap && ap->mld) { - uint8_t mlo_bssid[6] = {0}; - struct sta_mld *mld; - int num_sta = 0; - - if (!hwaddr_aton(blobmsg_data(data[3]), mlo_macaddr)) - return; - if (!hwaddr_aton(blobmsg_data(data[2]), mlo_bssid)) - return; - mld = agent_get_stamld(a, mlo_macaddr); - if (!mld) { - mld = agent_alloc_stamld(a, ap->mld, mlo_macaddr); - if (!mld) { - err("%s: Failed to allocate MLD:"MACFMT"\n", __func__, MAC2STR(mlo_macaddr)); - return; - } - } + if (ap && add && data[2] && data[3] && data[4]) { + uint8_t mlo_bssid[6] = {0}; + uint8_t mlo_link_id = 0; + struct sta_mld *mld; - memcpy(mld->bssid, mlo_bssid, 6); + mlo_link_id = (uint8_t) blobmsg_get_u32(data[4]); - /* TODO: code is copy pasted from mlsta_update_sta_mld() */ - num_sta = mld->num_affiliated_sta; - - s->mld = mld; - s->is_affiliated_sta = true; - s->mlo_link_id = linkid; + if (!hwaddr_aton(blobmsg_data(data[3]), mlo_macaddr)) + return; + if (!hwaddr_aton(blobmsg_data(data[2]), mlo_bssid)) + return; - if (!agent_is_sta_in_sta_mld(a, mld, macaddr) && - num_sta < MAX_AFFILIATED_STA_LINKS_NUM) { - mld->affiliated_sta[num_sta] = s; - mld->num_affiliated_sta++; - } + mld = stamld_update(a, ap, mlo_macaddr, mlo_bssid, + mlo_link_id, s); + if (!mld) + return; - if (s->assoc_frame && s->assoc_frame->len > 4) { - wifi_process_ml_ie(a, mld, - s->assoc_frame->frame + 4, - s->assoc_frame->len - 4); - } + if (s->assoc_frame && s->assoc_frame->len > 4) { + wifi_process_ml_ie(a, mld, + s->assoc_frame->frame + 4, + s->assoc_frame->len - 4); } } #endif @@ -4754,42 +4345,7 @@ static void wifi_bsta_event_handler(void *agent, struct blob_attr *msg) } } -#if (EASYMESH_VERSION >= 6) -static void wifi_mld_event_handler(void *agent, struct blob_attr *msg) -{ - char ifname[16] = {0}, event[16] = {0}; - struct agent *a = (struct agent *) agent; - struct blob_attr *tb[3]; - static const struct blobmsg_policy ev_attr[3] = { - [0] = { .name = "ifname", .type = BLOBMSG_TYPE_STRING }, - [1] = { .name = "event", .type = BLOBMSG_TYPE_STRING }, - [2] = { .name = "data", .type = BLOBMSG_TYPE_TABLE }, - }; - bool add, del; - - blobmsg_parse(ev_attr, 3, tb, blob_data(msg), blob_len(msg)); - if (!tb[0] || !tb[1]) - return; - - strncpy(ifname, blobmsg_data(tb[0]), sizeof(ifname) - 1); - strncpy(event, blobmsg_data(tb[1]), sizeof(event) - 1); - - add = !strcmp(event, "mlo-link-added"); - del = !strcmp(event, "mlo-link-remove"); - - if (add) { - /* more actions */ - timer_set(&a->init_ifaces_scheduler, - IFACE_TIMEOUT * 1000); - } else if (del) { - /* more actions */ - timer_set(&a->init_ifaces_scheduler, - IFACE_TIMEOUT * 1000); - } -} - -#endif #define ONBOARDING_TIMER 15 static void wifi_wps_creds_event_handler(void *agent, struct blob_attr *msg) @@ -4901,7 +4457,7 @@ static void agent_event_handler(struct ubus_context *ctx, #endif #endif #if (EASYMESH_VERSION >= 6) - { "wifi.mld", wifi_mld_event_handler }, + { "wifi.mld", mld_event_handler }, #endif }; @@ -5679,7 +5235,7 @@ struct netif_ap *wifi_radio_to_ap(struct agent *a, struct wifi_radio_element *re return NULL; } -static void bk_toggle(struct agent *a, struct netif_bk *bk, +void bk_toggle(struct agent *a, struct netif_bk *bk, uint8_t *bssid, uint32_t freq) { /* connect */ @@ -5891,325 +5447,6 @@ static void parse_ap_stats(struct ubus_request *req, int type, bss->rx_bcast_bytes = blobmsg_get_u64(tb[5]); } -#if (EASYMESH_VERSION >= 6) -static int parse_affiliated_ap(struct ubus_request *req, int type, - struct blob_attr *msg) -{ - struct netif_ap *ap = (struct netif_ap *) req->priv; - static const struct blobmsg_policy ap_attr[] = { - [0] = { .name = "id", .type = BLOBMSG_TYPE_INT32 }, - [1] = { .name = "band", .type = BLOBMSG_TYPE_STRING }, - [2] = { .name = "channel", .type = BLOBMSG_TYPE_INT32 }, - [3] = { .name = "ccfs0", .type = BLOBMSG_TYPE_INT32 }, - [4] = { .name = "ccfs1", .type = BLOBMSG_TYPE_INT32 }, - [5] = { .name = "bandwidth", .type = BLOBMSG_TYPE_INT32 }, - [6] = { .name = "macaddr", .type = BLOBMSG_TYPE_STRING }, - [7] = { .name = "security", .type = BLOBMSG_TYPE_STRING }, - [8] = { .name = "encryption", .type = BLOBMSG_TYPE_STRING }, - [9] = { .name = "standard", .type = BLOBMSG_TYPE_STRING }, - [10] = { .name = "num_stations", .type = BLOBMSG_TYPE_INT32 }, - [11] = { .name = "max_stations", .type = BLOBMSG_TYPE_INT32 }, - [12] = { .name = "utilization", .type = BLOBMSG_TYPE_INT32 }, - [13] = { .name = "adm_capacity", .type = BLOBMSG_TYPE_INT32 }, - [14] = { .name = "hidden", .type = BLOBMSG_TYPE_BOOL }, - [15] = { .name = "supp_security", .type = BLOBMSG_TYPE_ARRAY }, - [16] = { .name = "capabilities", .type = BLOBMSG_TYPE_TABLE }, - }; - struct blob_attr *tb[ARRAY_SIZE(ap_attr)]; - enum wifi_band band; - - if (!ap) - return -1; - - blobmsg_parse(ap_attr, ARRAY_SIZE(ap_attr), tb, blobmsg_data(msg), blobmsg_data_len(msg)); - - if (!tb[0] || !tb[1] || !tb[6]) { - return -1; - } - - band = wifi_bandstr_to_band(blobmsg_get_string(tb[1])); - if (band != ap->band) - return -1; - - ap->linkid = blobmsg_get_u32(tb[0]); - - hwaddr_aton(blobmsg_data(tb[6]), ap->bssid); - if (tb[2]) - ap->channel = blobmsg_get_u32(tb[2]); - - if (tb[5]) - ap->bandwidth = blobmsg_get_u32(tb[5]); - - if (tb[9]) - strncpy(ap->standard, blobmsg_data(tb[9]), sizeof(ap->standard) - 1); - - if (tb[10]) - ap->num_sta = blobmsg_get_u32(tb[10]); - - return 0; -} - -static void parse_apmld(struct ubus_request *req, int type, - struct blob_attr *msg) -{ - static const struct blobmsg_policy ap_attr[] = { - [0] = { .name = "ifname", .type = BLOBMSG_TYPE_STRING }, - [1] = { .name = "macaddr", .type = BLOBMSG_TYPE_STRING }, - [2] = { .name = "ssid", .type = BLOBMSG_TYPE_STRING }, - [3] = { .name = "mode", .type = BLOBMSG_TYPE_STRING }, - [4] = { .name = "links", .type = BLOBMSG_TYPE_ARRAY }, - [5] = { .name = "bssid", .type = BLOBMSG_TYPE_STRING }, - }; - struct netif_ap *ap = (struct netif_ap *)req->priv; - struct blob_attr *tb[ARRAY_SIZE(ap_attr)]; - struct agent *a = ap->agent; - struct netif_mld *mld; - const char *ifname; - const char *ssid; - uint8_t bssid[6] = {0}; - - blobmsg_parse(ap_attr, ARRAY_SIZE(ap_attr), tb, blob_data(msg), blob_len(msg)); - - if (!tb[0] || !tb[1] || !tb[2] || !tb[3] || !tb[4] || !tb[5]) { - err("|%s:%d| missing some mandatory field!\n", __func__, __LINE__); - return; - } - - ifname = blobmsg_get_string(tb[0]); - if (strlen(ifname) == 0) - return; - - mld = agent_get_mld_by_ifname(a, ifname); - if (!mld) { - mld = agent_alloc_mld(a, ifname); - if (!mld) { - err("|%s:%d| failed to alloc MLD\n", __func__, __LINE__); - return; - } - } - - if (!hwaddr_aton(blobmsg_data(tb[1]), mld->macaddr)) { - err("|%s:%d| MLD mac not valid\n", __func__, __LINE__); - return; - } - - if (!hwaddr_aton(blobmsg_data(tb[5]), bssid)) { - err("|%s:%d| MLD BSSID not valid\n", __func__, __LINE__); - return; - } - - /* In case of absence mld interface in the system, macaddres will be zero, use bssid */ - if (hwaddr_is_zero(mld->macaddr) && !hwaddr_is_zero(bssid)) - memcpy(mld->macaddr, bssid, 6); - - ssid = blobmsg_get_string(tb[2]); - strncpy(mld->ssid, ssid, sizeof(mld->ssid)); - - if (tb[4]) { - struct blob_attr *link = NULL; - int rem_links = 0; - - blobmsg_for_each_attr(link, tb[4], rem_links) { - struct wifi_radio_element *re = NULL; - struct wifi7_radio_capabilities *caps; - int num_ap = 0; - int ret; - - if (blobmsg_type(link) != BLOBMSG_TYPE_TABLE) { - err("|%s:%d| link was not a table\n", __func__, __LINE__); - continue; - } - - ret = parse_affiliated_ap(req, type, link); - if (ret) - continue; - - strncpy(ap->mld_ifname, ifname, sizeof(ap->mld_ifname) - 1); - ap->is_affiliated_ap = true; - strncpy(ap->ssid, ssid, sizeof(ap->ssid)); - ap->enabled = true; - - num_ap = mld->num_affiliated_ap; - if (!agent_is_ap_in_mld(a, mld, ap->bssid) && - num_ap < MAX_AFFILIATED_AP_LINKS_NUM) { - mld->affiliated_ap[num_ap] = ap; - mld->num_affiliated_ap++; - } else { - err("|%s:%d| link with bssid:"MACFMT" was already in the MLD (or num_ap too high:%d)\n", __func__, __LINE__, MAC2STR(ap->bssid), mld->num_affiliated_ap); - } - - re = agent_get_radio_with_ifname(a, ap->ifname); - if (re) { - caps = &re->wifi7_caps; - if (caps) { - /* TODO: revisit: */ - /* Enable based on capabilities */ - if (caps->ap_str_support) - mld->ap_str_enabled = true; - if (caps->ap_nstr_support) - mld->ap_nstr_enabled = true; - if (caps->ap_emlsr_support) - mld->ap_emlsr_enabled = true; - if (caps->ap_emlmr_support) - mld->ap_emlmr_enabled = true; - } - } - ap->mld = mld; - break; - } - - if (mld->num_affiliated_ap == 0) { - err("|%s:%d| no affiliated APs found in MLD, schedule reload\n", __func__, __LINE__); - timer_set(&a->init_ifaces_scheduler, IFACE_TIMEOUT * 1000); - } - - } -} - -static void parse_affiliated_bsta(struct agent *a, struct bsta_mld *mld, - struct netif_bk *bk, int type, - struct blob_attr *msg) -{ - - struct blob_attr *link; - int rem_links; - - /* mlo_links; */ - blobmsg_for_each_attr(link, msg, rem_links) { - static const struct blobmsg_policy mlo_links[] = { - [0] = { .name = "mlo_link_id", .type = BLOBMSG_TYPE_INT32 }, - [1] = { .name = "macaddr", .type = BLOBMSG_TYPE_STRING }, - [2] = { .name = "bssid", .type = BLOBMSG_TYPE_STRING }, - [3] = { .name = "band", .type = BLOBMSG_TYPE_STRING }, - [4] = { .name = "frequency", .type = BLOBMSG_TYPE_INT32 }, - }; - struct blob_attr *data[ARRAY_SIZE(mlo_links)]; - uint8_t link_id; - int num_sta; - enum wifi_band band; - - blobmsg_parse(mlo_links, ARRAY_SIZE(mlo_links), data, - blobmsg_data(msg), blobmsg_data_len(msg)); - - if (!data[0] || !data[1] || !data[2] || !data[3]) { - err("|%s:%d| missing mlo_links data for ifname:%s\n", __func__, __LINE__, bk->ifname); - continue; - } - - link_id = (uint8_t) blobmsg_get_u32(data[0]); - - band = wifi_bandstr_to_band(blobmsg_get_string(data[3])); - if (band != bk->cfg->band) - continue; - - hwaddr_aton(blobmsg_data(data[1]), bk->macaddr); - hwaddr_aton(blobmsg_data(data[2]), bk->bssid); - - num_sta = mld->num_affiliated_bsta; - bk->mld = mld; - bk->is_affiliated_sta = true; - bk->linkid = link_id; - - if (!agent_is_sta_in_bsta_mld(a, mld, bk->macaddr) && - num_sta < MAX_AFFILIATED_STA_LINKS_NUM) { - mld->affiliated_bsta[num_sta] = bk; - mld->num_affiliated_bsta++; - } - - break; - } -} - -void parse_bstamld(struct ubus_request *req, int type, - struct blob_attr *msg) -{ - static const struct blobmsg_policy ap_attr[] = { - [0] = { .name = "ifname", .type = BLOBMSG_TYPE_STRING }, - [1] = { .name = "status", .type = BLOBMSG_TYPE_STRING }, - [2] = { .name = "macaddr", .type = BLOBMSG_TYPE_STRING }, - [3] = { .name = "bssid", .type = BLOBMSG_TYPE_STRING }, - [4] = { .name = "ssid", .type = BLOBMSG_TYPE_STRING }, - [5] = { .name = "4addr", .type = BLOBMSG_TYPE_BOOL }, - [6] = { .name = "mlo_links", .type = BLOBMSG_TYPE_ARRAY }, - }; - struct netif_bk *bk = (struct netif_bk *)req->priv; - struct blob_attr *tb[ARRAY_SIZE(ap_attr)]; - struct wifi_radio_element *re; - struct agent *a = bk->agent; - uint8_t macaddr[6] = {0}; - uint8_t bssid[6] = {0}; - struct bsta_mld *mld = &a->bstamld; - const char *ifname; - const char *ssid = NULL; - - blobmsg_parse(ap_attr, ARRAY_SIZE(ap_attr), tb, blob_data(msg), blob_len(msg)); - - if (!tb[0] || !tb[1] || !tb[2] || !tb[5]) { - err("|%s:%d| missing some mandatory field(s)!\n", __func__, __LINE__); - return; - } - - if (tb[4]) - ssid = blobmsg_get_string(tb[4]); - - if (!hwaddr_aton(blobmsg_data(tb[2]), macaddr)) { - err("|%s:%d| MAC not valid\n", __func__, __LINE__); - return; - } - - if (tb[3] && !hwaddr_aton(blobmsg_data(tb[3]), bssid)) { - err("|%s:%d| MAC not valid\n", __func__, __LINE__); - return; - } - - ifname = blobmsg_get_string(tb[0]); - re = agent_get_radio_with_ifname(a, bk->ifname); - if (!re) { - err("|%s:%d| could not find radio element\n", __func__, - __LINE__); - return; - } - - mld = agent_init_bstamld(a, (char *)ifname, &re->wifi7_caps); - if (!mld) { - err("|%s:%d| failed to alloc bSTA MLD ifname:%s\n", __func__, __LINE__, ifname); - return; - } - - memcpy(mld->macaddr, macaddr, 6); - memcpy(mld->bssid, bssid, 6); - - if (bk->cfg->is_mld_netdev && !hwaddr_is_zero(bssid)) { - bk->mld = mld; - memcpy(bk->macaddr, macaddr, 6); - memcpy(bk->bssid, bssid, 6); - } - - if (tb[6] && !bk->cfg->is_mld_netdev) { - struct blob_attr *link = NULL; - int rem_links = 0; - - blobmsg_for_each_attr(link, tb[6], rem_links) { - if (blobmsg_type(link) != BLOBMSG_TYPE_TABLE) { - err("|%s:%d| link was not a table\n", __func__, __LINE__); - continue; - } - - parse_affiliated_bsta(a, mld, bk, type, link); - strncpy(bk->mld_ifname, ifname, sizeof(bk->mld_ifname) - 1); - bk->is_affiliated_sta = true; - if (ssid) - strncpy(bk->ssid, ssid, sizeof(bk->ssid)); - bk->enabled = true; - bk->mld = mld; - } - } - - if (!bk->is_affiliated_sta || bk->cfg->is_mld_netdev) - bk_toggle(a, bk, bssid, 0); -} -#endif - static void parse_ap(struct ubus_request *req, int type, struct blob_attr *msg) { @@ -6276,7 +5513,7 @@ static void parse_ap(struct ubus_request *req, int type, } if (tb[12]) - ap->linkid = blobmsg_get_u32(tb[12]); + ap->mlo_link_id = blobmsg_get_u32(tb[12]); #endif if (tb[13]) { @@ -6518,7 +5755,7 @@ int agent_init_interfaces(struct agent *a) ap->enabled = false; #if (EASYMESH_VERSIN >= 6) if (ap->is_affiliated_ap) - wifi_mld_del_ap(ap); + mld_del_ap(a, ap); #endif } } @@ -6585,7 +5822,7 @@ int agent_init_interfaces(struct agent *a) f->mld_id); if (mldcred) { snprintf(objname, 31, "wifi.apmld.%s", mldcred->ifname); - fn_parser = parse_apmld; + fn_parser = apmld_parse; band = band_to_int(re->band); } } @@ -6616,7 +5853,7 @@ int agent_init_interfaces(struct agent *a) blob_buf_init(&bb, 0); #if (EASYMESH_VERSION >= 6) - if (band) + if (f->mld_id) blobmsg_add_u32(&bb, "band", band); #endif ubus_call_object_args(a, uobj_id, &bb, "stats", parse_ap_stats, bss); @@ -6625,7 +5862,7 @@ int agent_init_interfaces(struct agent *a) } /** if AP is gone from config free it altogether - * if AP is disabled, cancel all timers/data + * if AP is disabled, cancel all timers and clear data */ list_for_each_entry(re, &a->radiolist, list) { struct netif_ap *ap, *tmp; @@ -6677,7 +5914,7 @@ int agent_init_interfaces(struct agent *a) b->mld_id); if (mldcred) { snprintf(objname, 31, "wifi.bstamld.%s", mldcred->ifname); - bk_parser = parse_bstamld; + bk_parser = bstamld_parse; } } #endif @@ -6704,11 +5941,11 @@ int agent_init_interfaces(struct agent *a) /* if an MLD is gone from config free it */ list_for_each_entry_safe(mld, tmp, &a->apmldlist, list) { if (!agent_get_mld_credential_by_ifname(&a->cfg, mld->ifname)) - clear_apmld(mld); + apmld_clean(a, mld); } if (a->has_bstamld) { - /* if bsta config has gone away free bstamld */ + /* if bsta config has gone away clear bstamld */ if (!agent_get_bsta_mld_credential(&a->cfg)) agent_clear_bsta_mld(a); } @@ -7221,7 +6458,7 @@ void clear_sta(struct sta *s) } #if (EASYMESH_VERSION >= 6) if (s->is_affiliated_sta) - wifi_sta_mld_del_sta(s->agent, s); + mld_del_sta(s->agent, s); #endif free(s); } @@ -7277,7 +6514,7 @@ static void netif_reset(struct netif_ap *ap) #if (EASYMESH_VERSION >= 6) if (ap->is_affiliated_ap) - wifi_mld_del_ap(ap); + mld_del_ap(ap->agent, ap); #endif } @@ -7328,7 +6565,7 @@ void clear_bk(struct agent *a, struct netif_bk *bk) { #if (EASYMESH_VERSION >= 6) if (bk->is_affiliated_sta) - wifi_sta_mld_del_bsta(a, bk); + mld_del_bsta(a, bk); #endif memset(bk, 0, sizeof(*bk)); } @@ -7354,128 +6591,6 @@ void clear_wdslist(struct agent *a) } } -#if (EASYMESH_VERSION >= 6) - -void agent_clean_affiliated_sta_mld(struct sta_mld *mld) -{ - int i; - - for (i = (mld->num_affiliated_sta - 1); i >= 0; i--) { - struct sta *s = mld->affiliated_sta[i]; - - if (!s) - continue; - - s->mld = NULL; - s->is_affiliated_sta = false; - mld->affiliated_sta[i] = NULL; - } - - mld->num_affiliated_sta = 0; -} - - -void agent_free_sta_mld(struct sta_mld *mld) -{ - agent_clean_affiliated_sta_mld(mld); - - list_del(&mld->list); - free(mld); -} - -/* -void clear_stamldlist(struct agent *a) -{ - struct netif_mld *mld = NULL; - - list_for_each_entry_safe(mld, tmp, &a->apmldlist, list) { - struct sta_mld *smld = NULL, *tmp; - - list_for_each_entry_safe(smld, tmp, &mld->stamldlist, list) - agent_free_sta_mld(mld); - } -} -*/ - -void agent_clean_affiliated_bsta_mld(struct bsta_mld *mld) -{ - int i; - - for (i = 0; i < mld->num_affiliated_bsta; i++) { - struct netif_bk *bk = mld->affiliated_bsta[i]; - - if (!bk) - continue; - - bk->mld = NULL; - bk->is_affiliated_sta = false; - mld->affiliated_bsta[i] = NULL; - } - - mld->num_affiliated_bsta = 0; -} - - -void agent_clear_bsta_mld(struct agent *a) -{ - struct bsta_mld *mld = &a->bstamld; - - agent_clean_affiliated_bsta_mld(mld); - - a->has_bstamld = false; -} - -void agent_clean_affiliated_ap_mld(struct netif_mld *mld) -{ - int i; - - for (i = (mld->num_affiliated_ap - 1); i >= 0; i--) { - struct netif_ap *ap = mld->affiliated_ap[i]; - - if (!ap) - continue; - - ap->mld = NULL; - ap->is_affiliated_ap = false; - mld->affiliated_ap[i] = NULL; - } - - mld->num_affiliated_ap = 0; -} - - -void agent_free_ap_mld(struct netif_mld *mld) -{ - agent_clean_affiliated_ap_mld(mld); - - list_del(&mld->list); - free(mld); -} - -/* TODO: fix mld free funcs... too many and they are all different */ - -static void clear_apmld(struct netif_mld *mld) -{ - struct sta_mld *smld = NULL, *stmp; - - list_for_each_entry_safe(smld, stmp, &mld->stamldlist, list) - agent_free_sta_mld(smld); - - agent_free_ap_mld(mld); -} - -void clear_apmldlist(struct agent *a) -{ - struct netif_mld *mld = NULL, *tmp; - - list_for_each_entry_safe(mld, tmp, &a->apmldlist, list) { - clear_apmld(mld); - } - - a->num_ap_mld = 0; -} -#endif - int agent_map_sub_cb(void *bus, void *priv, void *data) { struct blob_attr *msg = (struct blob_attr *)data; @@ -7855,7 +6970,7 @@ void run_agent(void) #endif #if (EASYMESH_VERSION >= 6) agent_clear_bsta_mld(w); - clear_apmldlist(w); + apmld_free_all(w); #endif ubus_unregister_event_handler(ctx, &w->evh); #ifdef VENDOR_EXTENSION @@ -8046,7 +7161,6 @@ int wifiagent_get_status(struct ubus_context *ctx, { struct agent *agent = this_agent; struct wifi_radio_element *re; - struct netif_ap *p = NULL; struct neighbor *n; struct blob_buf bb; void *a, *b, *c, *d, *t; @@ -8056,6 +7170,8 @@ int wifiagent_get_status(struct ubus_context *ctx, a = blobmsg_open_array(&bb, "radios"); list_for_each_entry(re, &agent->radiolist, list) { + struct netif_ap *ap = NULL; + t = blobmsg_open_table(&bb, ""); blobmsg_add_string(&bb, "name", re->name); blobmsg_add_macaddr(&bb, "macaddr", re->macaddr); @@ -8072,40 +7188,45 @@ int wifiagent_get_status(struct ubus_context *ctx, blobmsg_close_table(&bb, b); d = blobmsg_open_array(&bb, "fronthaul"); - list_for_each_entry(p, &re->aplist, list) { + list_for_each_entry(ap, &re->aplist, list) { struct sta *s; void *tt; - if (!p->cfg) + if (!ap->cfg) continue; tt = blobmsg_open_table(&bb, ""); - blobmsg_add_string(&bb, "name", p->ifname); + blobmsg_add_string(&bb, "name", ap->ifname); #if (EASYMESH_VERSION >= 6) - blobmsg_add_u8(&bb, "is_affiliated_ap", p->is_affiliated_ap); - if (p->is_affiliated_ap && p->mld) { - blobmsg_add_string(&bb, "mld_ifname", p->mld->ifname); - blobmsg_add_u32(&bb, "mlo_linkid", p->linkid); + blobmsg_add_u8(&bb, "is_affiliated_ap", ap->is_affiliated_ap); + if (ap->is_affiliated_ap) { + struct netif_mld *apmld; + + apmld = agent_get_apmld(a, ap->mld_macaddr); + if (apmld) { + blobmsg_add_string(&bb, "mld_ifname", apmld->ifname); + blobmsg_add_u32(&bb, "mlo_link_id", ap->mlo_link_id); + } } #endif - if (p->band == BAND_2) + if (ap->band == BAND_2) blobmsg_add_string(&bb, "band", "2.4GHz"); - else if (p->band == BAND_5) + else if (ap->band == BAND_5) blobmsg_add_string(&bb, "band", "5GHz"); - else if (p->band == BAND_6) + else if (ap->band == BAND_6) blobmsg_add_string(&bb, "band", "6GHz"); else blobmsg_add_string(&bb, "band", "Unknown"); - blobmsg_add_u8(&bb, "enabled", p->enabled); - blobmsg_add_macaddr(&bb, "bssid", p->bssid); - blobmsg_add_string(&bb, "ssid", p->ssid); - blobmsg_add_u32(&bb, "channel", p->channel); - blobmsg_add_u32(&bb, "load", p->bssload); - blobmsg_add_u32(&bb, "num_sta", p->num_sta); + blobmsg_add_u8(&bb, "enabled", ap->enabled); + blobmsg_add_macaddr(&bb, "bssid", ap->bssid); + blobmsg_add_string(&bb, "ssid", ap->ssid); + blobmsg_add_u32(&bb, "channel", ap->channel); + blobmsg_add_u32(&bb, "load", ap->bssload); + blobmsg_add_u32(&bb, "num_sta", ap->num_sta); b = blobmsg_open_array(&bb, "neighbor"); - list_for_each_entry(n, &p->nbrlist, list) { + list_for_each_entry(n, &ap->nbrlist, list) { void *ttt; ttt = blobmsg_open_table(&bb, ""); @@ -8116,7 +7237,7 @@ int wifiagent_get_status(struct ubus_context *ctx, blobmsg_close_array(&bb, b); b = blobmsg_open_array(&bb, "stations"); - list_for_each_entry(s, &p->stalist, list) { + list_for_each_entry(s, &ap->stalist, list) { void *aa, *ttt, *tttt; struct pref_neighbor *pn; @@ -8124,10 +7245,15 @@ int wifiagent_get_status(struct ubus_context *ctx, blobmsg_add_macaddr(&bb, "macaddr", s->macaddr); #if (EASYMESH_VERSION >= 6) blobmsg_add_u8(&bb, "is_affiliated_sta", s->is_affiliated_sta); - if (s->is_affiliated_sta && s->mld) { - blobmsg_add_macaddr(&bb, "mld_macaddr", s->mld->macaddr); - blobmsg_add_macaddr(&bb, "mld_bssid", s->mld->bssid); - blobmsg_add_u32(&bb, "mlo_linkid", s->mlo_link_id); + if (s->is_affiliated_sta) { + struct sta_mld *smld; + + smld = agent_get_stamld(a, s->mld_macaddr); + if (smld) { + blobmsg_add_macaddr(&bb, "mld_macaddr", smld->macaddr); + blobmsg_add_macaddr(&bb, "mld_bssid", smld->bssid); + blobmsg_add_u32(&bb, "mlo_linkid", s->mlo_link_id); + } } #endif /* blobmsg_add_u32(&bb, "conn_time", s->connected_ms / 1000); */ @@ -8202,15 +7328,15 @@ int wifiagent_get_status(struct ubus_context *ctx, aa = blobmsg_open_array(&bb, "affiliated_ap"); for (i = 0; i < mld->num_affiliated_ap; i++) { + struct netif_ap *ap; void *tt; - p = mld->affiliated_ap[i]; - - if (!p) - break; + ap = agent_get_ap(a, mld->affiliated_ap[i]); + if (!ap) + continue; tt = blobmsg_open_table(&bb, ""); - blobmsg_add_string(&bb, "ifname", p->ifname); + blobmsg_add_string(&bb, "ifname", ap->ifname); blobmsg_close_table(&bb, tt); } blobmsg_close_array(&bb, aa); @@ -8229,8 +7355,12 @@ int wifiagent_get_status(struct ubus_context *ctx, for (i = 0; i < smld->num_affiliated_sta; i++) { void *ttttt; struct sta *s; + ttttt = blobmsg_open_table(&bb, ""); - s = smld->affiliated_sta[i]; + s = agent_get_sta(a, smld->affiliated_sta[i]); + if (!s) + continue; + blobmsg_add_macaddr(&bb, "macaddr", s->macaddr); blobmsg_add_macaddr(&bb, "bssid", s->bssid); blobmsg_add_u32(&bb, "linkid", s->mlo_link_id); @@ -8262,10 +7392,9 @@ int wifiagent_get_status(struct ubus_context *ctx, struct netif_bk *bk; void *tt; - bk = agent->bstamld.affiliated_bsta[i]; - + bk = agent_get_bsta(a, agent->bstamld.affiliated_bsta[i]); if (!bk) - break; + continue; tt = blobmsg_open_table(&bb, ""); blobmsg_add_string(&bb, "ifname", bk->ifname); diff --git a/src/agent.h b/src/agent.h index 7953de5dac4880e37823bb9c793d274b8dd1dc24..8f9b458f142eed2c0f3b97c7e9d1abcac9cecab7 100644 --- a/src/agent.h +++ b/src/agent.h @@ -27,12 +27,15 @@ #include "utils/allmac.h" #include "config.h" #include "nl.h" +#include "mld.h" + #include "wifi.h" #include "wifi_opclass.h" #include "wifi_scanresults.h" struct blob_attr; +#define IFACE_TIMEOUT 1 #ifndef EASYMESH_VENDOR_EXT_OUI_DEFAULT #define EASYMESH_VENDOR_EXT_OUI_DEFAULT 0xB456FA /* IOPSYS OUI */ @@ -272,35 +275,6 @@ typedef uint32_t wifi_object_t; #define WIFI_OBJECT_INVALID ((uint32_t)-1) -#if (EASYMESH_VERSION >= 6) -/* multi-link device */ -struct netif_mld { - uint8_t id; - char ifname[16]; - int channel; - int bandwidth; - uint8_t macaddr[6]; - char ssid[33]; - char standard[32]; - char radio_name[16]; - bool enabled; - bool torndown; - - bool ap_str_enabled; - bool ap_nstr_enabled; - bool ap_emlsr_enabled; - bool ap_emlmr_enabled; - - struct agent *agent; - struct list_head stamldlist; - - int num_affiliated_ap; -#define MAX_AFFILIATED_AP_LINKS_NUM 14 - struct netif_ap *affiliated_ap[MAX_AFFILIATED_AP_LINKS_NUM]; - - struct list_head list; -}; -#endif /* fronthaul wifi (ap) interface */ struct netif_ap { @@ -344,8 +318,8 @@ struct netif_ap { #if (EASYMESH_VERSION >= 6) bool is_affiliated_ap; char mld_ifname[16]; - uint32_t linkid; - struct netif_mld *mld; + uint32_t mlo_link_id; + uint8_t mld_macaddr[6]; #endif struct wifi_bss_element bss; @@ -377,9 +351,9 @@ struct netif_bk { #if (EASYMESH_VERSION >= 6) bool is_affiliated_sta; char mld_ifname[16]; - uint32_t linkid; - struct bsta_mld *mld; - bool is_mld_netdev; + uint32_t mlo_link_id; + //struct bsta_mld *mld; + uint8_t mld_macaddr[6]; #endif /* enum netif_type iftype; */ struct agent *agent; @@ -405,44 +379,6 @@ struct netif_bk { uint8_t blacklist_bssid[16][6]; }; -#if (EASYMESH_VERSION >= 6) - -// struct used for client MLO STAs and own MLO bSTAs -struct sta_mld { -#define MAX_AFFILIATED_STA_LINKS_NUM 14 - uint8_t macaddr[6]; - uint8_t bssid[6]; - - bool str_enabled; - bool nstr_enabled; - bool emlsr_enabled; - bool emlmr_enabled; - - int num_affiliated_sta; - struct sta *affiliated_sta[MAX_AFFILIATED_STA_LINKS_NUM]; - - struct list_head list; -}; - -struct bsta_mld { -#define MAX_AFFILIATED_BSTA_LINKS_NUM 14 - uint8_t macaddr[6]; - uint8_t bssid[6]; - char ifname[16]; - - struct netif_bk bk; - - bool str_enabled; - bool nstr_enabled; - bool emlsr_enabled; - bool emlmr_enabled; - - int num_affiliated_bsta; - struct netif_bk *affiliated_bsta[MAX_AFFILIATED_BSTA_LINKS_NUM]; - - struct list_head list; -}; -#endif struct sta { uint8_t macaddr[6]; @@ -450,7 +386,8 @@ struct sta { #if (EASYMESH_VERSION >= 6) bool is_affiliated_sta; uint8_t mlo_link_id; - struct sta_mld *mld; + //struct sta_mld *mld; + uint8_t mld_macaddr[6]; uint8_t ruid[6]; #endif uint32_t caps; /** capability bitmap */ @@ -824,6 +761,29 @@ struct wifi_sta_steer_list { uint8_t sta_mac[6]; uint8_t complete; }; +#if (EASYMESH_VERSION >= 6) +/* TODO: FIXME!! MUST BE MOVED TO MLD.H */ +struct bsta_mld { + uint8_t macaddr[6]; + uint8_t bssid[6]; + char ifname[16]; + + struct netif_bk bk; + + bool str_enabled; + bool nstr_enabled; + bool emlsr_enabled; + bool emlmr_enabled; + + int num_affiliated_bsta; + //struct netif_bk *affiliated_bsta[MAX_AFFILIATED_BSTA_LINKS_NUM]; +#define MAX_AFFILIATED_BSTA_LINKS_NUM 14 + uint8_t affiliated_bsta[MAX_AFFILIATED_BSTA_LINKS_NUM][6]; + + struct list_head list; +}; + +#endif /** struct agent - wifi agent */ struct agent { @@ -1097,20 +1057,6 @@ void parse_bk(struct ubus_request *req, int type, int agent_radio_scanresults(struct agent *a, struct wifi_radio_element *re); int agent_init_interfaces(struct agent *a); int agent_switch_according_to_pref(struct agent *a); -#if (EASYMESH_VERSION >= 6) -bool wifi_is_affiliated_ap(struct agent *a, uint8_t *bssid); -const char *wifi_ifname_to_mld(struct agent *a, char *ifname); -bool agent_radio_support_ap_wifi7(struct wifi7_radio_capabilities *wifi7_caps); -bool agent_radio_support_bsta_wifi7(struct wifi7_radio_capabilities *wifi7_caps); -int wifi_sta_mld_del_bsta(struct agent *a, struct netif_bk *bk); -void parse_bstamld(struct ubus_request *req, int type, - struct blob_attr *msg); -struct sta_mld *agent_get_stamld(struct agent *a, uint8_t *macaddr); -int wifi_sta_mld_del_sta(struct agent *a, struct sta *s); -void agent_clean_affiliated_bsta_mld(struct bsta_mld *mld); -void agent_free_bsta_mld(struct agent *a); -void clear_apmldlist(struct agent *a); -#endif struct sta *agent_get_sta(struct agent *a, uint8_t *mac); struct wifi_radio_element *agent_get_radio_by_band(struct agent *a, @@ -1141,4 +1087,6 @@ void agent_pref_neighbor_to_nbr(struct pref_neighbor *pref_nbr_src, struct netif_ap *agent_gen_netif_ap(struct agent *a, struct wifi_radio_element *re); +void bk_toggle(struct agent *a, struct netif_bk *bk, + uint8_t *bssid, uint32_t freq); #endif /* AGENT_H */ diff --git a/src/agent_cmdu.c b/src/agent_cmdu.c index de97f9ba2e68b37ff8e32b914ee7948fa88c4273..987a7166a65abf685902467fbb17bf034082f35f 100644 --- a/src/agent_cmdu.c +++ b/src/agent_cmdu.c @@ -30,6 +30,9 @@ #include "agent_map.h" #include "agent_tlv.h" #include "config.h" +#if (EASYMESH_VERSION >= 6) +#include "mld.h" +#endif #include "utils/1905_ubus.h" #include "utils/debug.h" #include "utils/utils.h" @@ -327,7 +330,9 @@ struct cmdu_buff *agent_gen_ap_metrics_response(struct agent *a, list_for_each_entry(smld, &mld->stamldlist, list) { for (i = 0; i < smld->num_affiliated_sta; i++) { - s = smld->affiliated_sta[i]; + s = agent_get_sta(a, smld->affiliated_sta[i]); + if (!s) + continue; if (memcmp(s->bssid, bssid, 6)) continue; @@ -351,14 +356,14 @@ struct cmdu_buff *agent_gen_ap_metrics_response(struct agent *a, } /* TODO: traffic stats are per-mld, today use first client statistics */ - ret = agent_gen_assoc_sta_traffic_stats(a, frm, smld->macaddr, smld->affiliated_sta[0]); + ret = agent_gen_assoc_sta_traffic_stats(a, frm, smld->macaddr, s); if (ret) goto out; if (rcfg->include_wifi6_sta_status && a->cfg.map_profile > 2) { /* TLV is sent only for SLO and MLD clients */ - ret = agent_gen_assoc_wifi6_sta_status_report(a, frm, smld->affiliated_sta[0]); + ret = agent_gen_assoc_wifi6_sta_status_report(a, frm, s); if (ret) goto out; } @@ -1262,8 +1267,8 @@ struct cmdu_buff *agent_gen_topology_notification(struct agent *agent, uint8_t origin[6] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x13}; #if (EASYMESH_VERSION >= 6) - if (s->is_affiliated_sta && s->mld) - macaddr = s->mld->macaddr; + if (s->is_affiliated_sta) + macaddr = s->mld_macaddr; #endif frm = cmdu_alloc_simple(CMDU_TYPE_TOPOLOGY_NOTIFICATION, &mid); @@ -1309,14 +1314,22 @@ struct cmdu_buff *agent_gen_client_disassoc(struct agent *a, memcpy(cmdu->origin, a->cntlr_almac, 6); #if (EASYMESH_VERSION >= 6) - if (s->is_affiliated_sta && s->mld) { - macaddr = s->mld->macaddr; + if (s->is_affiliated_sta) { + struct sta_mld *smld; + + macaddr = s->mld_macaddr; ret = agent_gen_affiliated_sta_metrics(a, cmdu, s); if (ret) goto error; /* TODO: overwrite s as STA traffic are currently only available on first link */ - s = s->mld->affiliated_sta[0]; + smld = agent_get_stamld(a, s->mld_macaddr); + if (!smld) + goto error; + + s = agent_get_sta(a, smld->affiliated_sta[0]); + if (!s) + goto error; } #endif @@ -1419,8 +1432,6 @@ struct cmdu_buff *agent_gen_topology_response(struct agent *a, uint8_t *origin, #if (EASYMESH_VERSION >= 6) /* Backhaul STA Radio Capabilities TLV */ list_for_each_entry(re, &a->radiolist, list) { - agent_radio_support_bsta_wifi7(&re->wifi7_caps); - ret = agent_gen_bk_sta_radio_cap_tlv(a, resp, re); if (ret) goto error; diff --git a/src/agent_map.c b/src/agent_map.c index 01cf9efa6e868f7b47e44105a3d9a65cfa93d441..48fdd48ce72c2ea2a659b91ec574abedc4899167 100644 --- a/src/agent_map.c +++ b/src/agent_map.c @@ -60,6 +60,9 @@ #include "qos.h" #endif #include "extension.h" +#if (EASYMESH_VERSION >= 6) +#include "mld.h" +#endif #include "timer_impl.h" #include "unasta.h" #include "utils/1905_ubus.h" @@ -1704,43 +1707,6 @@ int wifi_teardown_iface(const char *ifname) return 0; } -#if (EASYMESH_VERSION >= 6) -int wifi_teardown_map_bsta_mld(struct agent *a, uint32_t band) -{ - struct wifi_radio_element *re; - char fmt[128] = {0}; - const char *bandstr; - - bandstr = band_to_str(band); - snprintf(fmt, sizeof(fmt), "teardown_bsta_mld %s", bandstr); - agent_exec_platform_scripts(fmt); - - list_for_each_entry(re, &a->radiolist, list) { - if (!re->has_bsta || !re->bk.is_affiliated_sta) - continue; - - if (!(re->bk.cfg->band & band)) - continue; - - re->bk.cfg->band &= ~band; - - if (re->bk.cfg->band) { - break; - } - -#if 0 - /* TODO: FIXME: proper MLD BSTA cleanup needed */ - clean_bk(re->bk.cfg); - clear_bk(a, re->bk); - re->bk = NULL; -#endif - } - - agent_config_reload(a); - return 0; -} -#endif - int wifi_teardown_map_ifaces_by_radio(struct agent *a, char *device) { struct netif_apcfg *apcfg; @@ -2240,36 +2206,6 @@ error_cleanup: #define RELOAD_TIMEOUT 5 #if (EASYMESH_VERSION >= 6) -static void mlo_update_id_in_configs(char *ifname, uint8_t mld_id) -{ - char mldname[16] = {0}; - char idstr[4] = {0}; - - /* write empty string if mld id is not set */ - if (mld_id) { - snprintf(idstr, sizeof(idstr), "%d", mld_id); - snprintf(mldname, sizeof(mldname), "mld%d", mld_id); - } - - uci_set_wireless_interface_option("mapagent", "ap", - "ifname", ifname, - "mld_id", idstr); - - uci_set_wireless_interface_option("wireless", - "wifi-iface", - "ifname", ifname, - "mld", mldname); - - uci_set_wireless_interface_option("mapagent", "ap", - "ifname", ifname, - "enabled", mld_id ? "1" : "0"); - - uci_set_wireless_interface_option("wireless", - "wifi-iface", - "ifname", ifname, - "disabled", mld_id ? "0" : "1"); -} - static int mlo_process_ap_mld_config(struct agent *a, uint8_t *tlv_data) { trace("%s: --->\n", __func__); @@ -2288,7 +2224,7 @@ static int mlo_process_ap_mld_config(struct agent *a, uint8_t *tlv_data) if (apcfg->mld_id) { struct netif_ap *ap; - mlo_update_id_in_configs(apcfg->name, 0); + mld_set_config_id(apcfg->name, 0); apcfg->mld_id = 0; ap = agent_get_ap_by_ifname(a, apcfg->name); if (ap) @@ -2444,7 +2380,7 @@ static int mlo_process_ap_mld_config(struct agent *a, uint8_t *tlv_data) mld_complete = true; /* Set mld_id/mld in ap/wifi-iface sections of cfg files */ - mlo_update_id_in_configs(apcfg->name, id); + mld_set_config_id(apcfg->name, id); apcfg->mld_id = id; } } @@ -2498,7 +2434,7 @@ static int mlo_process_bsta_mld_config(struct agent *a, uint8_t *tlv_data) continue; if (!re->bk.cfg->is_mld_netdev && re->bk.is_affiliated_sta) - wifi_sta_mld_del_bsta(a, &re->bk); + mld_del_bsta(a, &re->bk); } num_affiliated_bstas = tlv_data[offset++]; @@ -2574,9 +2510,7 @@ static int mlo_process_bsta_mld_config(struct agent *a, uint8_t *tlv_data) } return 0; } -#endif -#if (EASYMESH_VERSION >= 6) static bool update_tlv_hash(struct agent *a, struct tlv *tv, uint8_t *sha256_out) { @@ -2607,6 +2541,7 @@ error_cleanup: return ret; } #endif + int handle_ap_autoconfig_wsc(void *agent, struct cmdu_buff *rx_cmdu, struct node *n) { @@ -2865,7 +2800,7 @@ int handle_ap_autoconfig_wsc(void *agent, struct cmdu_buff *rx_cmdu, ret = mlo_process_bsta_mld_config(a, tv[AP_AUTOCONFIGURATION_WSC_M2_BACKHAUL_STA_MLD_CONFIG_IDX][0]->data); if (ret) - wifi_teardown_map_bsta_mld(a, radio->band); + bstamld_teardown_band(a, radio->band); update_tlv_hash(a, tv[AP_AUTOCONFIGURATION_WSC_M2_BACKHAUL_STA_MLD_CONFIG_IDX][0], a->bsta_mld_cfg_sha256); a->reconfig_reason |= AGENT_RECONFIG_REASON_MLD_ID; @@ -2873,7 +2808,7 @@ int handle_ap_autoconfig_wsc(void *agent, struct cmdu_buff *rx_cmdu, } else { dbg("%s: Missing BSTA MLD config TLV, teardown\n", __func__); - wifi_teardown_map_bsta_mld(a, radio->band); + bstamld_teardown_band(a, radio->band); } #endif @@ -6762,7 +6697,7 @@ int handle_bsta_mld_config_request(void *agent, struct cmdu_buff *cmdu, struct n if (ret) { uint32_t band_all = BAND_2 | BAND_5 | BAND_6; - wifi_teardown_map_bsta_mld(a, band_all); + bstamld_teardown_band(a, band_all); } else { /* re-do all MLD configuration in case TLV has changed */ dbg("%s: MLD configuration changed, schedule reconfig\n", diff --git a/src/agent_tlv.c b/src/agent_tlv.c index 85b421774c0e0181bb40ff70e5dbe80d134ce1fb..5c26b35c6deb7a41ada987b5d65fd4fcbc4896d1 100644 --- a/src/agent_tlv.c +++ b/src/agent_tlv.c @@ -33,6 +33,9 @@ #include "agent_map.h" #include "config.h" #include "unasta.h" +#if (EASYMESH_VERSION >= 6) +#include "mld.h" +#endif #include "utils/1905_ubus.h" #include "utils/debug.h" #include "utils/utils.h" @@ -3667,12 +3670,16 @@ int agent_gen_assoc_client_tlv(struct agent *a, struct cmdu_buff *frm) offset += 6; if (smld->num_affiliated_sta > 0) { - /** conntime is not (yet) available for MLD dev - * use first affiliated STA conntime - */ - conntime = ((smld->affiliated_sta[0]->connected_ms / 1000) > 0xFFFF) - ? 0xFFFF - : (smld->affiliated_sta[0]->connected_ms / 1000) & 0xFFFF; + struct sta *s; + + s = agent_get_sta(a, smld->affiliated_sta[0]); + if (s) { + /** conntime is not (yet) available for MLD dev + * use first affiliated STA conntime + */ + conntime = ((s->connected_ms / 1000) > 0xFFFF) + ? 0xFFFF : (s->connected_ms / 1000) & 0xFFFF; + } } /* conntime */ @@ -4224,8 +4231,8 @@ int agent_gen_assoc_wifi6_sta_status_report(struct agent *a, data = (struct tlv_assoc_wifi6_sta_status_report *)t->data; memcpy(data->macaddr, s->macaddr, 6); #if (EASYMESH_VERSION >= 6) - if (s->is_affiliated_sta && s->mld) - memcpy(data->macaddr, s->mld->macaddr, 6); + if (s->is_affiliated_sta) + memcpy(data->macaddr, s->mld_macaddr, 6); #endif offset += sizeof(*data); /* TODO: @@ -4528,7 +4535,6 @@ int agent_gen_ap_mld_config(struct agent *a, struct cmdu_buff *frm) list_for_each_entry(mld, &a->apmldlist, list) { int ssid_len = strlen(mld->ssid); - struct netif_ap *ap = NULL; int i; /* AP MLD MAC Addr Valid */ @@ -4566,8 +4572,9 @@ int agent_gen_ap_mld_config(struct agent *a, struct cmdu_buff *frm) t->data[offset++] = mld->num_affiliated_ap; for (i = 0; i < mld->num_affiliated_ap; i++) { struct wifi_radio_element *re = NULL; - ap = mld->affiliated_ap[i]; + struct netif_ap *ap; + ap = agent_get_ap(a, mld->affiliated_ap[i]); if (!ap || !ap->is_affiliated_ap) continue; @@ -4588,7 +4595,7 @@ int agent_gen_ap_mld_config(struct agent *a, struct cmdu_buff *frm) offset += 6; /* LinkID */ - t->data[offset++] = ap->linkid; + t->data[offset++] = ap->mlo_link_id; offset += 18; /* reserved */ } @@ -4615,7 +4622,7 @@ int agent_gen_bsta_mld_config(struct agent *a, struct cmdu_buff *frm) //struct mld_credential *mld = NULL; int offset = 0; uint8_t *num_aff_bstas; - struct bsta_mld *bsta = &a->bstamld; + struct bsta_mld *bstamld = &a->bstamld; uint8_t valid_flag = BSTA_MLD_CONF_AFFILIATED_BSTA_MLD_ADDR_VALID; int ret; @@ -4638,28 +4645,28 @@ int agent_gen_bsta_mld_config(struct agent *a, struct cmdu_buff *frm) data->flag = 0; /* bSTA_MLD_MAC_Addr */ - if (!hwaddr_is_zero(bsta->macaddr)) { - memcpy(&t->data[offset], bsta->macaddr, 6); + if (!hwaddr_is_zero(bstamld->macaddr)) { + memcpy(&t->data[offset], bstamld->macaddr, 6); data->flag |= BSTA_MLD_CONF_BSTA_MLD_ADDR_VALID; } offset += 6; /* AP_MLD_MAC_Addr */ /* "addr of the AP MLD to which the bSTA MLD is associated" */ - if (!hwaddr_is_zero(bsta->bssid)) { - memcpy(&t->data[offset], bsta->bssid, 6); + if (!hwaddr_is_zero(bstamld->bssid)) { + memcpy(&t->data[offset], bstamld->bssid, 6); data->flag |= BSTA_MLD_CONF_AP_MLD_ADDR_VALID; } offset += 6; /* STR/NSTR/EMLSR/EMLMR */ - if (bsta->str_enabled) + if (bstamld->str_enabled) caps_flag |= BSTA_MLD_CONFIG_STR; - if (bsta->nstr_enabled) + if (bstamld->nstr_enabled) caps_flag |= BSTA_MLD_CONFIG_NSTR; - if (bsta->emlsr_enabled) + if (bstamld->emlsr_enabled) caps_flag |= BSTA_MLD_CONFIG_EMLSR; - if (bsta->emlmr_enabled) + if (bstamld->emlmr_enabled) caps_flag |= BSTA_MLD_CONFIG_EMLMR; data->flag2 = caps_flag; @@ -4670,20 +4677,21 @@ int agent_gen_bsta_mld_config(struct agent *a, struct cmdu_buff *frm) /* numAffiliatedbSTAs */ num_aff_bstas = &t->data[offset]; - *num_aff_bstas = bsta->num_affiliated_bsta; + *num_aff_bstas = bstamld->num_affiliated_bsta; offset++; if (*num_aff_bstas) { int i; for (i = 0; i < *num_aff_bstas; i++) { - struct netif_bk *affsta = bsta->affiliated_bsta[i]; + struct netif_bk *bsta; struct wifi_radio_element *re; - if (!affsta->cfg) + bsta = agent_get_bsta(a, bstamld->affiliated_bsta[i]); + if (!bsta || !bsta->cfg) continue; - re = agent_get_radio_by_band(a, affsta->cfg->band); + re = agent_get_radio_by_band(a, bsta->cfg->band); if (!re) continue; @@ -4696,7 +4704,7 @@ int agent_gen_bsta_mld_config(struct agent *a, struct cmdu_buff *frm) offset += 6; /* Affilated_bSTA_MAC_Addr */ - memcpy(&t->data[offset], affsta->macaddr, 6); + memcpy(&t->data[offset], bsta->macaddr, 6); offset += 6; /* reserved */ @@ -4795,7 +4803,7 @@ int agent_gen_affiliated_ap_metrics(struct agent *a, struct cmdu_buff *frm, struct tlv *t; int ret; - if (!wifi_is_affiliated_ap(a, bss->bssid)) + if (!is_affiliated_ap(a, bss->bssid)) return 0; t = cmdu_reserve_tlv(frm, sizeof(*data)); @@ -4899,7 +4907,11 @@ int agent_gen_associated_sta_mld_config(struct agent *a, struct cmdu_buff *frm, offset += 1; for (i = 0; i < mld->num_affiliated_sta; i++) { - struct sta *s = mld->affiliated_sta[i]; + struct sta *s; + + s = agent_get_sta(a, mld->affiliated_sta[i]); + if (!s) + continue; memcpy(&t->data[offset], s->bssid, 6); offset += 6; diff --git a/src/backhaul.c b/src/backhaul.c index f3d7a65f0d408e91bd583827f6594295b594ae4e..7683f1f7f504b0d367941e624aa9c996ff089b48 100644 --- a/src/backhaul.c +++ b/src/backhaul.c @@ -21,6 +21,9 @@ #include "agent.h" #include "agent_ubus.h" #include "config.h" +#if (EASYMESH_VERSION >= 6) +#include "mld.h" +#endif #include "timer.h" #include "utils/debug.h" #include "utils/utils.h" @@ -532,9 +535,12 @@ void agent_check_bsta_connections(struct agent *a) #if (EASYMESH_VERSION >= 6) - if (bk->is_affiliated_sta) { - snprintf(objname, 31, "wifi.bstamld.%s", bk->mld->ifname); - cb = parse_bstamld; + if (bk->is_affiliated_sta && a->has_bstamld) { + struct bsta_mld *bstamld; + + bstamld = &a->bstamld; + snprintf(objname, 31, "wifi.bstamld.%s", bstamld->ifname); + cb = bstamld_parse; } if (bk->cfg->is_mld_netdev) diff --git a/src/mld.c b/src/mld.c new file mode 100644 index 0000000000000000000000000000000000000000..864733c0bb753e63a35bef35837d4bd983a4c03c --- /dev/null +++ b/src/mld.c @@ -0,0 +1,958 @@ +#if (EASYMESH_VERSION >= 6) + + +#include "mld.h" + +#include "utils/debug.h" +#include "utils/utils.h" +#include "backhaul.h" +#include "agent.h" + +struct sta_mld *stamld_update(struct agent *a, struct netif_ap *ap, uint8_t *mld_macaddr, + uint8_t *mld_bssid, uint8_t mlo_link_id, struct sta *s) +{ + struct sta_mld *mld; + int ret; + + mld = agent_get_stamld(a, mld_macaddr); + if (!mld) { + struct netif_mld *apmld; + + apmld = agent_get_apmld(a, ap->mld_macaddr); + if (!apmld) + return NULL; + + mld = agent_alloc_stamld(a, apmld, mld_macaddr); + if (!mld) + return NULL; + } + + ret = mld_add_sta(a, mld, s->macaddr); + if (ret) { + dbg("%s: failed to add affiliated STA:"MACFMT" to STAMLD:"MACFMT"\n", __func__, MAC2STR(s->macaddr), MAC2STR(mld_macaddr)); + return NULL; + } + + memcpy(mld->bssid, mld_bssid, 6); + + memcpy(s->mld_macaddr, mld->macaddr, 6); + s->is_affiliated_sta = true; + s->mlo_link_id = mlo_link_id; + return mld; +} + +/* remove passed affiliated STA from mld */ +int mld_del_sta(struct agent *a, struct sta *s) +{ + struct sta_mld *mld; + int i; + + mld = agent_get_stamld(a, s->mld_macaddr); + if (!mld) + return -1; + + for (i = 0; i < mld->num_affiliated_sta; i++) { + if (memcmp(mld->affiliated_sta[i], s->macaddr, 6)) + continue; + + if (i < mld->num_affiliated_sta) + memcpy(mld->affiliated_sta[i], mld->affiliated_sta[i + 1], (mld->num_affiliated_sta - (i + 1)) * 6); + + memset(mld->affiliated_sta[mld->num_affiliated_sta - 1], 0, 6); + mld->num_affiliated_sta--; + break; + } + + if (mld->num_affiliated_sta == 0) { + list_del(&mld->list); + free(mld); + } + + return 0; +} + +/* remove passed affiliated backhaul STA from mld */ +int mld_del_bsta(struct agent *a, struct netif_bk *bk) +{ + struct bsta_mld *mld; + int i; + + if (!a->has_bstamld || bk->cfg->is_mld_netdev) + return -1; + + mld = &a->bstamld; + for (i = 0; i < mld->num_affiliated_bsta; i++) { + if (memcmp(mld->affiliated_bsta[i], bk->macaddr, 6)) + continue; + + if (i < mld->num_affiliated_bsta) + memcpy(mld->affiliated_bsta[i], mld->affiliated_bsta[i + 1], (mld->num_affiliated_bsta - (i + 1)) * 6); + + memset(mld->affiliated_bsta[mld->num_affiliated_bsta - 1], 0, 6); + mld->num_affiliated_bsta--; + } + + bk->is_affiliated_sta = false; + return 0; +} + +/* remove passed affiliated AP from mld */ +int mld_del_ap(struct agent *a, struct netif_ap *ap) +{ + struct netif_mld *mld; + int i; + + if (!ap->is_affiliated_ap) + return -1; + + mld = agent_get_apmld(a, ap->mld_macaddr); + if (!mld) + return -1; + + for (i = 0; i < mld->num_affiliated_ap; i++) { + if (memcmp(mld->affiliated_ap[i], ap->bssid, 6)) + continue; + + if (i < mld->num_affiliated_ap) + memcpy(mld->affiliated_ap[i], mld->affiliated_ap[i + 1], (mld->num_affiliated_ap - (i + 1)) * 6); + + memset(mld->affiliated_ap[mld->num_affiliated_ap - 1], 0, 6); + mld->num_affiliated_ap--; + } + + ap->is_affiliated_ap = false; + return 0; +} + +/* frame starting from payload, skipping header */ +int wifi_process_ml_ie(struct agent *a, struct sta_mld *stamld, + uint8_t *assocframe, int framelen) +{ + uint8_t *ml; + uint8_t *ml_ctrl; + uint8_t type; + uint8_t presence_bmp[2]; + + bool linkid_info_present; + bool bss_param_chg_present; + bool medium_sync_present; + bool eml_caps_present; + + bool mld_caps_ops_present; + uint8_t *common_info; + size_t pos; + + ml = wifi_find_ie_ext(assocframe, framelen, IE_EXT_ML); + if (!ml) { + dbg("%s: frame did not include ML IE\n", __func__); + return -1; + } + + ml_ctrl = ml + 3; + type = ml_ctrl[0] & 0x7; + presence_bmp[0] = (ml_ctrl[0] & 0xf0) >> 4; + presence_bmp[1] = ml_ctrl[1]; + + if (type != 0) { + dbg("%s: ML IE type non-zero\n", __func__); + return -1; + } + + linkid_info_present = !!(presence_bmp[0] & 0x1); + bss_param_chg_present = !!(presence_bmp[0] & 0x2); + medium_sync_present = !!(presence_bmp[0] & 0x4); + eml_caps_present = !!(presence_bmp[0] & 0x8); + + mld_caps_ops_present = !!(presence_bmp[1] & 0x1); + common_info = &ml_ctrl[2]; + pos = 1; + + pos += 6; /* skip apmld macaddr */ + + if (linkid_info_present) + pos += 1; + + if (bss_param_chg_present) + pos += 1; + + if (medium_sync_present) + pos += 2; + + if (eml_caps_present) { + uint8_t *eml_caps = &common_info[pos]; + + stamld->emlsr_enabled = !!(eml_caps[0] & BIT(0)) ? true : false; + stamld->emlmr_enabled = !!(eml_caps[0] & BIT(7)) ? true : false; + pos += 2; + } + + if (mld_caps_ops_present) { + uint8_t *mld_caps = &common_info[pos]; + uint8_t max_simlinks = (mld_caps[0] & 0x0f); + + pos += 2; + if (max_simlinks >= 1) { + stamld->nstr_enabled = false; + stamld->str_enabled = true; + } else { + stamld->nstr_enabled = true; + stamld->str_enabled = false; + } + } + + return 0; +} + +void mld_event_handler(void *agent, struct blob_attr *msg) +{ + char ifname[16] = {0}, event[16] = {0}; + struct agent *a = (struct agent *) agent; + struct blob_attr *tb[3]; + static const struct blobmsg_policy ev_attr[3] = { + [0] = { .name = "ifname", .type = BLOBMSG_TYPE_STRING }, + [1] = { .name = "event", .type = BLOBMSG_TYPE_STRING }, + [2] = { .name = "data", .type = BLOBMSG_TYPE_TABLE }, + }; + bool add, del; + + blobmsg_parse(ev_attr, 3, tb, blob_data(msg), blob_len(msg)); + + if (!tb[0] || !tb[1]) + return; + + strncpy(ifname, blobmsg_data(tb[0]), sizeof(ifname) - 1); + strncpy(event, blobmsg_data(tb[1]), sizeof(event) - 1); + + add = !strcmp(event, "mlo-link-added"); + del = !strcmp(event, "mlo-link-remove"); + + if (add) { + /* more actions */ + timer_set(&a->init_ifaces_scheduler, + IFACE_TIMEOUT * 1000); + } else if (del) { + /* more actions */ + timer_set(&a->init_ifaces_scheduler, + IFACE_TIMEOUT * 1000); + } +} + +int mld_parse_affiliated_ap(struct ubus_request *req, int type, + struct blob_attr *msg) +{ + struct netif_ap *ap = (struct netif_ap *) req->priv; + static const struct blobmsg_policy ap_attr[] = { + [0] = { .name = "id", .type = BLOBMSG_TYPE_INT32 }, + [1] = { .name = "band", .type = BLOBMSG_TYPE_STRING }, + [2] = { .name = "channel", .type = BLOBMSG_TYPE_INT32 }, + [3] = { .name = "ccfs0", .type = BLOBMSG_TYPE_INT32 }, + [4] = { .name = "ccfs1", .type = BLOBMSG_TYPE_INT32 }, + [5] = { .name = "bandwidth", .type = BLOBMSG_TYPE_INT32 }, + [6] = { .name = "macaddr", .type = BLOBMSG_TYPE_STRING }, + [7] = { .name = "security", .type = BLOBMSG_TYPE_STRING }, + [8] = { .name = "encryption", .type = BLOBMSG_TYPE_STRING }, + [9] = { .name = "standard", .type = BLOBMSG_TYPE_STRING }, + [10] = { .name = "num_stations", .type = BLOBMSG_TYPE_INT32 }, + [11] = { .name = "max_stations", .type = BLOBMSG_TYPE_INT32 }, + [12] = { .name = "utilization", .type = BLOBMSG_TYPE_INT32 }, + [13] = { .name = "adm_capacity", .type = BLOBMSG_TYPE_INT32 }, + [14] = { .name = "hidden", .type = BLOBMSG_TYPE_BOOL }, + [15] = { .name = "supp_security", .type = BLOBMSG_TYPE_ARRAY }, + [16] = { .name = "capabilities", .type = BLOBMSG_TYPE_TABLE }, + }; + struct blob_attr *tb[ARRAY_SIZE(ap_attr)]; + enum wifi_band band; + + if (!ap) + return -1; + + blobmsg_parse(ap_attr, ARRAY_SIZE(ap_attr), tb, blobmsg_data(msg), blobmsg_data_len(msg)); + + if (!tb[0] || !tb[1] || !tb[6]) { + return -1; + } + + band = wifi_bandstr_to_band(blobmsg_get_string(tb[1])); + if (band != ap->band) + return -1; + + ap->mlo_link_id = blobmsg_get_u32(tb[0]); + + hwaddr_aton(blobmsg_data(tb[6]), ap->bssid); + if (tb[2]) + ap->channel = blobmsg_get_u32(tb[2]); + + if (tb[5]) + ap->bandwidth = blobmsg_get_u32(tb[5]); + + if (tb[9]) + strncpy(ap->standard, blobmsg_data(tb[9]), sizeof(ap->standard) - 1); + + if (tb[10]) + ap->num_sta = blobmsg_get_u32(tb[10]); + + return 0; +} + +void apmld_parse(struct ubus_request *req, int type, + struct blob_attr *msg) +{ + static const struct blobmsg_policy ap_attr[] = { + [0] = { .name = "ifname", .type = BLOBMSG_TYPE_STRING }, + [1] = { .name = "macaddr", .type = BLOBMSG_TYPE_STRING }, + [2] = { .name = "ssid", .type = BLOBMSG_TYPE_STRING }, + [3] = { .name = "mode", .type = BLOBMSG_TYPE_STRING }, + [4] = { .name = "links", .type = BLOBMSG_TYPE_ARRAY }, + [5] = { .name = "bssid", .type = BLOBMSG_TYPE_STRING }, + }; + struct netif_ap *ap = (struct netif_ap *)req->priv; + struct blob_attr *tb[ARRAY_SIZE(ap_attr)]; + struct agent *a = ap->agent; + struct netif_mld *mld; + const char *ifname; + const char *ssid; + uint8_t bssid[6] = {0}; + + blobmsg_parse(ap_attr, ARRAY_SIZE(ap_attr), tb, blob_data(msg), blob_len(msg)); + + if (!tb[0] || !tb[1] || !tb[2] || !tb[3] || !tb[4] || !tb[5]) { + err("|%s:%d| missing some mandatory field!\n", __func__, __LINE__); + return; + } + + ifname = blobmsg_get_string(tb[0]); + if (strlen(ifname) == 0) + return; + + mld = agent_get_apmld_by_ifname(a, ifname); + if (!mld) { + mld = agent_alloc_apmld(a, ifname); + if (!mld) { + err("|%s:%d| failed to alloc MLD\n", __func__, __LINE__); + return; + } + } + + if (!hwaddr_aton(blobmsg_data(tb[1]), mld->macaddr)) { + err("|%s:%d| MLD mac not valid\n", __func__, __LINE__); + return; + } + + if (!hwaddr_aton(blobmsg_data(tb[5]), bssid)) { + err("|%s:%d| MLD BSSID not valid\n", __func__, __LINE__); + return; + } + + /* In case of absence mld interface in the system, macaddres will be zero, use bssid */ + if (hwaddr_is_zero(mld->macaddr) && !hwaddr_is_zero(bssid)) + memcpy(mld->macaddr, bssid, 6); + + ssid = blobmsg_get_string(tb[2]); + strncpy(mld->ssid, ssid, sizeof(mld->ssid)); + + if (tb[4]) { + struct blob_attr *link = NULL; + int rem_links = 0; + + blobmsg_for_each_attr(link, tb[4], rem_links) { + struct wifi_radio_element *re = NULL; + struct wifi7_radio_capabilities *caps; + int num_ap = 0; + int ret; + + if (blobmsg_type(link) != BLOBMSG_TYPE_TABLE) { + err("|%s:%d| link was not a table\n", __func__, __LINE__); + continue; + } + + ret = mld_parse_affiliated_ap(req, type, link); + if (ret) + continue; + + strncpy(ap->mld_ifname, ifname, sizeof(ap->mld_ifname) - 1); + memcpy(ap->mld_macaddr, mld->macaddr, 6); + ap->is_affiliated_ap = true; + strncpy(ap->ssid, ssid, sizeof(ap->ssid)); + ap->enabled = true; + + num_ap = mld->num_affiliated_ap; + if (!mld_contains_ap(a, mld, ap->bssid) && + num_ap < MAX_AFFILIATED_AP_LINKS_NUM) { + memcpy(mld->affiliated_ap[num_ap], ap->bssid, 6); + mld->num_affiliated_ap++; + } else { + err("|%s:%d| link with bssid:"MACFMT" was already in the MLD (or num_ap too high:%d)\n", __func__, __LINE__, MAC2STR(ap->bssid), mld->num_affiliated_ap); + } + + re = agent_get_radio_with_ifname(a, ap->ifname); + if (re) { + caps = &re->wifi7_caps; + if (caps) { + /* TODO: revisit: */ + /* Enable based on capabilities */ + if (caps->ap_str_support) + mld->ap_str_enabled = true; + if (caps->ap_nstr_support) + mld->ap_nstr_enabled = true; + if (caps->ap_emlsr_support) + mld->ap_emlsr_enabled = true; + if (caps->ap_emlmr_support) + mld->ap_emlmr_enabled = true; + } + } + break; + } + + if (mld->num_affiliated_ap == 0) { + err("|%s:%d| no affiliated APs found in MLD, schedule reload\n", __func__, __LINE__); + timer_set(&a->init_ifaces_scheduler, IFACE_TIMEOUT * 1000); + } + + } +} + +void mld_parse_affiliated_bsta(struct agent *a, struct bsta_mld *mld, + struct netif_bk *bk, int type, + struct blob_attr *msg) +{ + + struct blob_attr *link; + int rem_links; + + /* mlo_links; */ + blobmsg_for_each_attr(link, msg, rem_links) { + static const struct blobmsg_policy mlo_links[] = { + [0] = { .name = "mlo_link_id", .type = BLOBMSG_TYPE_INT32 }, + [1] = { .name = "macaddr", .type = BLOBMSG_TYPE_STRING }, + [2] = { .name = "bssid", .type = BLOBMSG_TYPE_STRING }, + [3] = { .name = "band", .type = BLOBMSG_TYPE_STRING }, + [4] = { .name = "frequency", .type = BLOBMSG_TYPE_INT32 }, + }; + struct blob_attr *data[ARRAY_SIZE(mlo_links)]; + uint8_t link_id; + int num_sta; + enum wifi_band band; + + blobmsg_parse(mlo_links, ARRAY_SIZE(mlo_links), data, + blobmsg_data(msg), blobmsg_data_len(msg)); + + if (!data[0] || !data[1] || !data[2] || !data[3]) { + err("|%s:%d| missing mlo_links data for ifname:%s\n", __func__, __LINE__, bk->ifname); + continue; + } + + link_id = (uint8_t) blobmsg_get_u32(data[0]); + + band = wifi_bandstr_to_band(blobmsg_get_string(data[3])); + if (band != bk->cfg->band) + continue; + + hwaddr_aton(blobmsg_data(data[1]), bk->macaddr); + hwaddr_aton(blobmsg_data(data[2]), bk->bssid); + + num_sta = mld->num_affiliated_bsta; + memcpy(bk->mld_macaddr, mld->macaddr, 6); + bk->is_affiliated_sta = true; + bk->mlo_link_id = link_id; + + if (!mld_contains_bsta(a, mld, bk->macaddr) && + num_sta < MAX_AFFILIATED_STA_LINKS_NUM) { + memcpy(mld->affiliated_bsta[num_sta], bk->macaddr, 6); + mld->num_affiliated_bsta++; + } + + break; + } +} + +void bstamld_parse(struct ubus_request *req, int type, + struct blob_attr *msg) +{ + static const struct blobmsg_policy ap_attr[] = { + [0] = { .name = "ifname", .type = BLOBMSG_TYPE_STRING }, + [1] = { .name = "status", .type = BLOBMSG_TYPE_STRING }, + [2] = { .name = "macaddr", .type = BLOBMSG_TYPE_STRING }, + [3] = { .name = "bssid", .type = BLOBMSG_TYPE_STRING }, + [4] = { .name = "ssid", .type = BLOBMSG_TYPE_STRING }, + [5] = { .name = "4addr", .type = BLOBMSG_TYPE_BOOL }, + [6] = { .name = "mlo_links", .type = BLOBMSG_TYPE_ARRAY }, + }; + struct netif_bk *bk = (struct netif_bk *)req->priv; + struct blob_attr *tb[ARRAY_SIZE(ap_attr)]; + struct wifi_radio_element *re; + struct agent *a = bk->agent; + uint8_t macaddr[6] = {0}; + uint8_t bssid[6] = {0}; + struct bsta_mld *mld = &a->bstamld; + const char *ifname; + const char *ssid = NULL; + + blobmsg_parse(ap_attr, ARRAY_SIZE(ap_attr), tb, blob_data(msg), blob_len(msg)); + + if (!tb[0] || !tb[1] || !tb[2] || !tb[5]) { + err("|%s:%d| missing some mandatory field(s)!\n", __func__, __LINE__); + return; + } + + if (tb[4]) + ssid = blobmsg_get_string(tb[4]); + + if (!hwaddr_aton(blobmsg_data(tb[2]), macaddr)) { + err("|%s:%d| MAC not valid\n", __func__, __LINE__); + return; + } + + if (tb[3] && !hwaddr_aton(blobmsg_data(tb[3]), bssid)) { + err("|%s:%d| MAC not valid\n", __func__, __LINE__); + return; + } + + ifname = blobmsg_get_string(tb[0]); + re = agent_get_radio_with_ifname(a, bk->ifname); + if (!re) { + err("|%s:%d| could not find radio element\n", __func__, + __LINE__); + return; + } + + mld = agent_init_bstamld(a, (char *)ifname, &re->wifi7_caps); + if (!mld) { + err("|%s:%d| failed to alloc bSTA MLD ifname:%s\n", __func__, __LINE__, ifname); + return; + } + + memcpy(mld->macaddr, macaddr, 6); + memcpy(mld->bssid, bssid, 6); + + if (bk->cfg->is_mld_netdev && !hwaddr_is_zero(bssid)) { + memcpy(bk->mld_macaddr, mld->macaddr, 6); + memcpy(bk->macaddr, macaddr, 6); + memcpy(bk->bssid, bssid, 6); + } + + if (tb[6] && !bk->cfg->is_mld_netdev) { + struct blob_attr *link = NULL; + int rem_links = 0; + + blobmsg_for_each_attr(link, tb[6], rem_links) { + if (blobmsg_type(link) != BLOBMSG_TYPE_TABLE) { + err("|%s:%d| link was not a table\n", __func__, __LINE__); + continue; + } + + mld_parse_affiliated_bsta(a, mld, bk, type, link); + strncpy(bk->mld_ifname, ifname, sizeof(bk->mld_ifname) - 1); + memcpy(bk->mld_macaddr, mld->macaddr, 6); + bk->is_affiliated_sta = true; + if (ssid) + strncpy(bk->ssid, ssid, sizeof(bk->ssid)); + bk->enabled = true; + } + } + + if (!bk->is_affiliated_sta || bk->cfg->is_mld_netdev) + bk_toggle(a, bk, bssid, 0); +} + +struct netif_mld *agent_get_apmld(struct agent *a, uint8_t *macaddr) +{ + struct netif_mld *mld = NULL; + + list_for_each_entry(mld, &a->apmldlist, list) { + if (!memcmp(macaddr, mld->macaddr, 6)) + return mld; + } + + return NULL; +} + +struct netif_mld *agent_get_apmld_by_ifname(struct agent *a, const char *ifname) +{ + struct netif_mld *mld = NULL; + + list_for_each_entry(mld, &a->apmldlist, list) { + if (!strncmp(ifname, mld->ifname, sizeof(mld->ifname))) + return mld; + } + + return NULL; +} + +struct netif_mld *agent_alloc_apmld(struct agent *a, const char *ifname) +{ + struct netif_mld *mld; + + if (strlen(ifname) == 0) { + err("|%s:%d| MLD can not have empty ifname\n", __func__, __LINE__); + return NULL; + } + + mld = calloc(1, sizeof(*mld)); + if (!mld) + return NULL; + + dbg("|%s:%d| allocated mld ifname:%s\n", __func__, __LINE__, ifname); + + INIT_LIST_HEAD(&mld->stamldlist); + + strncpy(mld->ifname, ifname, sizeof(mld->ifname)); + list_add_tail(&mld->list, &a->apmldlist); + a->num_ap_mld++; + + return mld; +} + +int mld_add_ap(struct agent *a, struct netif_mld *mld, + uint8_t *macaddr) +{ + int num_ap = mld->num_affiliated_ap; + + if (mld_contains_ap(a, mld, macaddr)) + return 0; + + if (num_ap >= MAX_AFFILIATED_AP_LINKS_NUM) + return -1; + + memcpy(mld->affiliated_ap[num_ap], macaddr, 6); + mld->num_affiliated_ap++; + return 0; +} + +int mld_add_sta(struct agent *a, struct sta_mld *mld, + uint8_t *macaddr) +{ + int num_sta = mld->num_affiliated_sta; + + if (mld_contains_sta(a, mld, macaddr)) + return 0; + + if (num_sta >= MAX_AFFILIATED_STA_LINKS_NUM) + return -1; + + memcpy(mld->affiliated_sta[num_sta], macaddr, 6); + mld->num_affiliated_sta++; + return 0; +} + + +int mld_add_bsta(struct agent *a, struct bsta_mld *mld, + uint8_t *macaddr) +{ + int num_bsta = mld->num_affiliated_bsta; + + if (mld_contains_bsta(a, mld, macaddr)) + return 0; + + if (num_bsta >= MAX_AFFILIATED_BSTA_LINKS_NUM) + return -1; + + memcpy(mld->affiliated_bsta[num_bsta], macaddr, 6); + mld->num_affiliated_bsta++; + return 0; +} + + + +bool mld_contains_ap(struct agent *a, struct netif_mld *mld, + uint8_t *macaddr) +{ + int i; + + for (i = 0; i < mld->num_affiliated_ap; i++) { + if (!memcmp(mld->affiliated_ap[i], macaddr, 6)) + return true; + } + + return false; +} + +bool mld_contains_sta(struct agent *a, struct sta_mld *mld, + uint8_t *macaddr) +{ + int i; + + for (i = 0; i < mld->num_affiliated_sta; i++) { + if (!memcmp(mld->affiliated_sta[i], macaddr, 6)) + return true; + } + + return false; +} + + +bool mld_contains_bsta(struct agent *a, struct bsta_mld *mld, + uint8_t *macaddr) +{ + int i; + + for (i = 0; i < mld->num_affiliated_bsta; i++) { + if (!memcmp(mld->affiliated_bsta[i], macaddr, 6)) + return true; + } + + return false; +} + + +struct sta_mld *agent_get_stamld(struct agent *a, uint8_t *macaddr) +{ + struct netif_mld *mld; + + list_for_each_entry(mld, &a->apmldlist, list) { + struct sta_mld *s; + + list_for_each_entry(s, &mld->stamldlist, list) { + if (!memcmp(macaddr, s->macaddr, 6)) + return s; + } + } + + return NULL; +} + +struct sta_mld *agent_alloc_stamld(struct agent *a, struct netif_mld *mld, + uint8_t *macaddr) +{ + struct sta_mld *s; + + s = calloc(1, sizeof(*s)); + if (!s) + return NULL; + + trace("|%s:%d| allocate sta mac:"MACFMT"\n", __func__, __LINE__, MAC2STR(macaddr)); + memcpy(s->macaddr, macaddr, 6); + + list_add_tail(&s->list, &mld->stamldlist); + + return s; +} + +struct bsta_mld *agent_init_bstamld(struct agent *a, char *ifname, + struct wifi7_radio_capabilities *caps) +{ + struct bsta_mld *bsta = &a->bstamld; + + strncpy(bsta->ifname, ifname, sizeof(bsta->ifname)); + dbg("|%s:%d| allocated bsta mld:%s\n", __func__, __LINE__, bsta->ifname); + + bsta->str_enabled = caps->bsta_str_support; + bsta->nstr_enabled = caps->bsta_nstr_support; + bsta->emlsr_enabled = caps->bsta_emlsr_support; + bsta->emlmr_enabled = caps->bsta_emlmr_support; + a->has_bstamld = true; + + return bsta; +} + +void stamld_clean(struct agent *a, struct sta_mld *mld) +{ + int i; + + for (i = (mld->num_affiliated_sta - 1); i >= 0; i--) { + struct sta *s; + + s = agent_get_sta(a, mld->affiliated_sta[i]); + if (!s) + continue; + + memset(s->mld_macaddr, 0, 6); + s->is_affiliated_sta = false; + memset(mld->affiliated_sta[i], 0, 6);; + } + + mld->num_affiliated_sta = 0; +} + + +void stamld_free(struct agent *a, struct sta_mld *mld) +{ + stamld_clean(a, mld); + + list_del(&mld->list); + free(mld); +} + +/* +void clear_stamldlist(struct agent *a) +{ + struct netif_mld *mld = NULL; + + list_for_each_entry_safe(mld, tmp, &a->apmldlist, list) { + struct sta_mld *smld = NULL, *tmp; + + list_for_each_entry_safe(smld, tmp, &mld->stamldlist, list) + stamld_free(mld); + } +} +*/ + +void bstamld_clean(struct agent *a, struct bsta_mld *mld) +{ + int i; + + for (i = 0; i < mld->num_affiliated_bsta; i++) { + struct netif_bk *bk; + + bk = agent_get_bsta(a, mld->affiliated_bsta[i]); + if (!bk) + continue; + + memset(bk->mld_macaddr, 0, 6); + bk->is_affiliated_sta = false; + memset(mld->affiliated_bsta[i], 0, 6); + } + + mld->num_affiliated_bsta = 0; +} + + +void agent_clear_bsta_mld(struct agent *a) +{ + struct bsta_mld *mld = &a->bstamld; + + bstamld_clean(a, mld); + + a->has_bstamld = false; +} + +void apmld_clean(struct agent *a, struct netif_mld *mld) +{ + int i; + + for (i = (mld->num_affiliated_ap - 1); i >= 0; i--) { + struct netif_ap *ap; + + ap = agent_get_ap(a, mld->affiliated_ap[i]); + if (!ap) + continue; + + memset(ap->mld_macaddr, 0, 6); + ap->is_affiliated_ap = false; + memset(mld->affiliated_ap[i], 0, 6); + } + + mld->num_affiliated_ap = 0; +} + +void apmld_free(struct agent *a, struct netif_mld *mld) +{ + struct sta_mld *smld = NULL, *stmp; + + list_for_each_entry_safe(smld, stmp, &mld->stamldlist, list) + stamld_free(a, smld); + + apmld_clean(a, mld); + + list_del(&mld->list); + free(mld); +} + +void apmld_free_all(struct agent *a) +{ + struct netif_mld *mld = NULL, *tmp; + + list_for_each_entry_safe(mld, tmp, &a->apmldlist, list) { + apmld_free(a, mld); + } + + a->num_ap_mld = 0; +} + +bool is_affiliated_ap(struct agent *a, uint8_t *bssid) +{ + struct netif_ap *ap; + + ap = agent_get_ap(a, bssid); + if (ap && ap->is_affiliated_ap) + return true; + + return false; +} + + +bool agent_radio_support_ap_mlo(struct wifi7_radio_capabilities *wifi7_caps) +{ + if (wifi7_caps->ap_str_support || wifi7_caps->ap_nstr_support || + wifi7_caps->ap_emlsr_support || wifi7_caps->ap_emlmr_support) + return true; + + return false; +} + +bool agent_radio_support_bsta_mlo(struct wifi7_radio_capabilities *wifi7_caps) +{ + if (wifi7_caps->bsta_str_support || wifi7_caps->bsta_nstr_support || + wifi7_caps->bsta_emlsr_support || wifi7_caps->bsta_emlmr_support) + return true; + + return false; +} + + +int bstamld_teardown_band(struct agent *a, uint32_t band) +{ + struct wifi_radio_element *re; + char fmt[128] = {0}; + const char *bandstr; + + bandstr = band_to_str(band); + snprintf(fmt, sizeof(fmt), "teardown_bsta_mld %s", bandstr); + agent_exec_platform_scripts(fmt); + + list_for_each_entry(re, &a->radiolist, list) { + if (!re->has_bsta || !re->bk.is_affiliated_sta) + continue; + + if (!(re->bk.cfg->band & band)) + continue; + + re->bk.cfg->band &= ~band; + + if (re->bk.cfg->band) { + break; + } + +#if 0 + /* TODO: FIXME: proper MLD BSTA cleanup needed */ + clean_bk(re->bk.cfg); + clear_bk(a, re->bk); + re->bk = NULL; +#endif + } + + agent_config_reload(a); + return 0; +} + +void mld_set_config_id(char *ifname, uint8_t mld_id) +{ + char mldname[16] = {0}; + char idstr[4] = {0}; + + /* write empty string if mld id is not set */ + if (mld_id) { + snprintf(idstr, sizeof(idstr), "%d", mld_id); + snprintf(mldname, sizeof(mldname), "mld%d", mld_id); + } + + uci_set_wireless_interface_option("mapagent", "ap", + "ifname", ifname, + "mld_id", idstr); + + uci_set_wireless_interface_option("wireless", + "wifi-iface", + "ifname", ifname, + "mld", mldname); + + uci_set_wireless_interface_option("mapagent", "ap", + "ifname", ifname, + "enabled", mld_id ? "1" : "0"); + + uci_set_wireless_interface_option("wireless", + "wifi-iface", + "ifname", ifname, + "disabled", mld_id ? "0" : "1"); +} + + +#endif \ No newline at end of file diff --git a/src/mld.h b/src/mld.h new file mode 100644 index 0000000000000000000000000000000000000000..da04fb78652b7dd8f3f8647cdcd068f363fd2780 --- /dev/null +++ b/src/mld.h @@ -0,0 +1,120 @@ +#ifndef MLD_H +#define MLD_H +#if (EASYMESH_VERSION >= 6) + +#include <stdint.h> +#include <stdbool.h> +#include <stddef.h> + +#include <libubox/blobmsg.h> +#include <libubox/list.h> +#include <libubus.h> +#include <easy/easy.h> +#include <wifiutils.h> + +struct wifi7_radio_capabilities; +struct netif_bk; +struct netif_ap; +struct bsta_mld; +struct sta; + +/* multi-link device */ +struct netif_mld { + uint8_t id; + char ifname[16]; + int channel; + int bandwidth; + uint8_t macaddr[6]; + char ssid[33]; + char standard[32]; + char radio_name[16]; + bool enabled; + bool torndown; + + bool ap_str_enabled; + bool ap_nstr_enabled; + bool ap_emlsr_enabled; + bool ap_emlmr_enabled; + + struct agent *agent; + struct list_head stamldlist; + + int num_affiliated_ap; +#define MAX_AFFILIATED_AP_LINKS_NUM 14 + uint8_t affiliated_ap[MAX_AFFILIATED_AP_LINKS_NUM][6]; + + struct list_head list; +}; + + +// struct used for client MLO STAs and own MLO bSTAs +struct sta_mld { + uint8_t macaddr[6]; + uint8_t bssid[6]; + + bool str_enabled; + bool nstr_enabled; + bool emlsr_enabled; + bool emlmr_enabled; + + int num_affiliated_sta; +#define MAX_AFFILIATED_STA_LINKS_NUM 14 + uint8_t affiliated_sta[MAX_AFFILIATED_STA_LINKS_NUM][6]; + + struct list_head list; +}; + + +struct sta_mld *stamld_update(struct agent *a, struct netif_ap *ap, + uint8_t *mld_macaddr, uint8_t *mld_bssid, + uint8_t mlo_link_id, struct sta *s); +int mld_add_ap(struct agent *a, struct netif_mld *mld, + uint8_t *macaddr); +int mld_add_sta(struct agent *a, struct sta_mld *mld, + uint8_t *macaddr); +int mld_add_bsta(struct agent *a, struct bsta_mld *mld, + uint8_t *macaddr); +int mld_del_sta(struct agent *a, struct sta *s); +int mld_del_bsta(struct agent *a, struct netif_bk *bk); +int mld_del_ap(struct agent *a, struct netif_ap *ap); +int wifi_process_ml_ie(struct agent *a, struct sta_mld *stamld, + uint8_t *assocframe, int framelen); +void mld_event_handler(void *agent, struct blob_attr *msg); +int mld_parse_affiliated_ap(struct ubus_request *req, int type, + struct blob_attr *msg); +void apmld_parse(struct ubus_request *req, int type, + struct blob_attr *msg); +void mld_parse_affiliated_bsta(struct agent *a, struct bsta_mld *mld, + struct netif_bk *bk, int type, + struct blob_attr *msg); +void bstamld_parse(struct ubus_request *req, int type, + struct blob_attr *msg); +struct netif_mld *agent_get_apmld(struct agent *a, uint8_t *macaddr); +struct netif_mld *agent_get_apmld_by_ifname(struct agent *a, const char *ifname); +struct netif_mld *agent_alloc_apmld(struct agent *a, const char *ifname); +bool mld_contains_ap(struct agent *a, struct netif_mld *mld, + uint8_t *macaddr); +bool mld_contains_sta(struct agent *a, struct sta_mld *mld, + uint8_t *macaddr); +bool mld_contains_bsta(struct agent *a, struct bsta_mld *mld, + uint8_t *macaddr); +struct sta_mld *agent_get_stamld(struct agent *a, uint8_t *macaddr); +struct sta_mld *agent_alloc_stamld(struct agent *a, struct netif_mld *mld, + uint8_t *macaddr); +struct bsta_mld *agent_init_bstamld(struct agent *a, char *ifname, + struct wifi7_radio_capabilities *caps); +void stamld_clean(struct agent *a, struct sta_mld *mld); +void stamld_free(struct agent *a, struct sta_mld *mld); +void bstamld_clean(struct agent *a, struct bsta_mld *mld); +void agent_clear_bsta_mld(struct agent *a); +void apmld_clean(struct agent *a, struct netif_mld *mld); +void apmld_free(struct agent *a, struct netif_mld *mld); +void apmld_free_all(struct agent *a); +void clear_apmldlist(struct agent *a); +bool is_affiliated_ap(struct agent *a, uint8_t *bssid); +bool agent_radio_support_ap_mlo(struct wifi7_radio_capabilities *wifi7_caps); +bool agent_radio_support_bsta_mlo(struct wifi7_radio_capabilities *wifi7_caps); +int bstamld_teardown_band(struct agent *a, uint32_t band); +void mld_set_config_id(char *ifname, uint8_t mld_id); +#endif +#endif diff --git a/src/wifi_ubus.c b/src/wifi_ubus.c index 7248f59974bad0c7124d87b211cedc5b412c475b..d8c9702f2ec0f45daef7d351fc3970ff08148457 100644 --- a/src/wifi_ubus.c +++ b/src/wifi_ubus.c @@ -2137,7 +2137,6 @@ static int wifi_ubus_get_mld_sta_links(struct ubus_context *ubus_ctx, struct net .status = -1, }; struct blob_buf bb = {}; - char mld_addr_str[18] = {}; char name[256] = {}; uint32_t id; int ret; @@ -2153,7 +2152,9 @@ static int wifi_ubus_get_mld_sta_links(struct ubus_context *ubus_ctx, struct net blob_buf_init(&bb, 0); - if (mld_addr) { + if (mld_addr && !hwaddr_is_zero(mld_addr)) { + char mld_addr_str[18] = {}; + hwaddr_ntoa(mld_addr, mld_addr_str); blobmsg_add_string(&bb, "sta", mld_addr_str); ctx.mld_macaddr = mld_addr;