diff --git a/src/agent.c b/src/agent.c index 4acbafd1a0d9f582cda0bde99ce97e624df074fd..daeaa1b1d42e90cce38f26d402468557041a8c28 100644 --- a/src/agent.c +++ b/src/agent.c @@ -1796,6 +1796,40 @@ static void agent_sta_clean_rssi(struct sta *s) s->num_rssi = 0; } +static int agent_modify_assoc_status(struct netif_ap *ap, bool allowed) +{ + int ret = 0; + + ret = wifi_set_ap_mbo_association_mode(ap->ifname, !allowed); + if (!ret) { + ap->cfg->disallow_assoc = !allowed; + uci_apply_bss_association_mode(ap->ifname, !allowed); + } + + return ret; +} + +static int agent_notify_assoc_status(struct agent *a, uint8_t *bssid, bool allowed) +{ + trace("%s: --->\n", __func__); + + struct bss_data { + uint8_t bssid[6]; + uint8_t status; + } bss_data; + int ret = 0; + + memcpy(bss_data.bssid, bssid, ETH_ALEN); + if (allowed) + bss_data.status = STA_ASSOC_ALLOWED; + else + bss_data.status = STA_ASSOC_NOT_ALLOWED; + + ret = send_assoc_status_notification(a, 1, &bss_data); + + return ret; +} + static struct sta *wifi_add_sta(struct agent *a, const char *ifname, unsigned char *macaddr) { @@ -1827,8 +1861,15 @@ static struct sta *wifi_add_sta(struct agent *a, const char *ifname, oldap = agent_get_ap(a, sptr->bssid); if (oldap) { - if (oldap->num_sta > 0) + if (oldap->num_sta > 0) { oldap->num_sta--; + if (oldap->num_sta == oldap->max_sta - 1) { + /* Set association mode in driver and update config */ + agent_modify_assoc_status(ap, true); + /* Notify ctrl that adding STA is allowed again */ + agent_notify_assoc_status(a, oldap->bssid, true); + } + } } clear_sta(sptr); } @@ -1869,6 +1910,13 @@ static struct sta *wifi_add_sta(struct agent *a, const char *ifname, /* Remove from unassociated list */ agent_del_unassoc_sta(a, new->macaddr); + if (ap->max_sta && ap->num_sta >= ap->max_sta) { + /* Set association mode in driver and update config */ + agent_modify_assoc_status(ap, false); + /* Notify ctrl that adding more STA is disallowed */ + agent_notify_assoc_status(a, ap->bssid, false); + } + timer_set(&new->sta_timer, 1 * 1000); return new; } @@ -1986,8 +2034,15 @@ static int wifi_del_sta(struct agent *a, const char *ifname, if (!memcmp(s->macaddr, macaddr, 6)) { dbg("Delete STA " MACFMT "record\n", MAC2STR(macaddr)); - if (ap->num_sta > 0) - ap->num_sta--; + if (ap->num_sta > 0) { + ap->num_sta--; + if (ap->num_sta == ap->max_sta - 1) { + /* Set association mode in driver and update config */ + agent_modify_assoc_status(ap, true); + /* Notify ctrl that adding STA is allowed again */ + agent_notify_assoc_status(a, ap->bssid, true); + } + } clear_sta(s); return 0; } @@ -3288,7 +3343,7 @@ static void agent_init_ifaces_assoc_mode(struct agent *a) WIFI_REASON_SERVICE_NOT_AUTHORIZED_IN_THIS_LOCATION); } - wifi_set_backhaul_bss_association_mode(ap->ifname, + wifi_set_ap_mbo_association_mode(ap->ifname, ap->cfg->disallow_assoc); } } @@ -3299,7 +3354,7 @@ static void apply_iface_assocation_mode(struct agent *a, const char *ifname) struct netif_ap *ap = agent_get_ap_by_ifname(a, ifname); if (ap) { - wifi_set_backhaul_bss_association_mode(ifname, + wifi_set_ap_mbo_association_mode(ifname, ap->cfg->disallow_assoc); } } @@ -5082,10 +5137,10 @@ static void refresh_bssinfo(atimer_t *t) struct netif_ap *ap = container_of(t, struct netif_ap, bss_timer); struct agent *a = ap->agent; struct wifi_ap_status ap_status = {}; - int i; - dbg("%s: ap = %s\n", __func__, ap->ifname); + trace("%s: ap = %s\n", __func__, ap->ifname); + if (!wifi_ap_status(ap->ifname, &ap_status)) { #if (EASYMESH_VERSION >= 6) struct wifi_mlsta mlsta[128] = {0}; @@ -5100,11 +5155,12 @@ static void refresh_bssinfo(atimer_t *t) /* others.. */ if (ap_status.ap.bss.load.utilization != 0xff) ap->bssload = ap_status.ap.bss.load.utilization; + ap->max_sta = ap_status.ap.assoclist_max; - dbg("ap: %s bssid: " MACFMT - " channel: %d bssload: %d\n", - ap->ifname, MAC2STR(ap->bssid), - ap->channel, ap->bssload); + dbg("%s: ap: %s max_sta: %d bssid: " MACFMT + " channel: %d bssload: %d\n", + __func__, ap->ifname, ap->max_sta, + MAC2STR(ap->bssid), ap->channel, ap->bssload); #if (EASYMESH_VERSION >= 6) if (!wifi_get_mld_stations(ap, mlsta, &num_mlsta)) { for (i = 0; i < num_mlsta; i++) { @@ -5712,6 +5768,7 @@ struct netif_ap *netif_alloc_ap(const char *ifname) timer_init(&n->nbr_timer, refresh_neighbor_list); timer_init(&n->bss_timer, refresh_bssinfo); + timer_set(&n->bss_timer, BSS_REFRESH_INTERVAL); return n; } @@ -6061,6 +6118,7 @@ static void parse_apmld(struct ubus_request *req, int type, [3] = { .name = "mode", .type = BLOBMSG_TYPE_STRING }, [4] = { .name = "links", .type = BLOBMSG_TYPE_ARRAY }, [5] = { .name = "bssid", .type = BLOBMSG_TYPE_STRING }, + [6] = { .name = "max_stations", .type = BLOBMSG_TYPE_INT32 }, }; struct netif_ap *ap = (struct netif_ap *)req->priv; struct blob_attr *tb[ARRAY_SIZE(ap_attr)]; @@ -6072,7 +6130,7 @@ static void parse_apmld(struct ubus_request *req, int type, 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]) { + if (!tb[0] || !tb[1] || !tb[2] || !tb[3] || !tb[4] || !tb[5] || !tb[6]) { err("|%s:%d| missing some mandatory field!\n", __func__, __LINE__); return; } @@ -6166,6 +6224,9 @@ static void parse_apmld(struct ubus_request *req, int type, } } + + if (tb[6]) + ap->max_sta = blobmsg_get_u32(tb[6]); } static void parse_affiliated_bsta(struct agent *a, struct bsta_mld *mld, @@ -6334,6 +6395,7 @@ static void parse_ap(struct ubus_request *req, int type, [12] = { .name = "linkid", .type = BLOBMSG_TYPE_INT32 }, #endif [13] = { .name = "band", .type = BLOBMSG_TYPE_STRING }, + [14] = { .name = "max_stations", .type = BLOBMSG_TYPE_INT32 }, }; struct blob_attr *tb[ARRAY_SIZE(ap_attr)]; @@ -6395,6 +6457,9 @@ static void parse_ap(struct ubus_request *req, int type, ap->band = BAND_UNKNOWN; } + if (tb[14]) + ap->max_sta = blobmsg_get_u32(tb[14]); + } static int agent_radio_update_scanresults_element(struct wifi_radio_element *re, struct wifi_bss *bsss, @@ -6519,21 +6584,24 @@ void agent_init_interfaces_post_actions(struct agent *a) list_for_each_entry(re, &a->radiolist, list) { list_for_each_entry(ap, &re->aplist, list) { + int num_sta = ap->max_sta ? ap->max_sta : 128; + #if (EASYMESH_VERSION >= 6) if (ap->is_affiliated_ap) { struct wifi_mlsta mlsta[128] = {0}; - int num_mlsta = 128; - if (wifi_get_mld_stations(ap, mlsta, &num_mlsta)) + if (wifi_get_mld_stations(ap, mlsta, &num_sta)) continue; - for (i = 0; i < num_mlsta; i++) { + for (i = 0; i < num_sta; i++) { if (!memcmp(mlsta[i].sta->bssid, ap->bssid, 6)) wifi_add_sta(a, ap->ifname, mlsta[i].sta->macaddr); } } else { +#else + if (1) { +#endif uint8_t sta[128 * 6] = {}; - int num_sta = 128; if (wifi_get_assoclist(ap, sta, &num_sta)) continue; @@ -6541,18 +6609,15 @@ void agent_init_interfaces_post_actions(struct agent *a) for (i = 0; i < num_sta; i++) wifi_add_sta(a, ap->ifname, &sta[i * 6]); } -#else - uint8_t sta[128 * 6] = {}; - int num_sta = 128; - if (wifi_get_assoclist(ap, sta, &num_sta)) - continue; - - for (i = 0; i < num_sta; i++) - wifi_add_sta(a, ap->ifname, &sta[i * 6]); -#endif /* Block STas in WiFi if wifi is restarted at run-time */ assoc_ctrl_apply_restriction(a, ap); + + /* Notify ctrl once upon start if adding STA is allowed */ + if (ap->max_sta && !ap->sent_assocnotif) { + agent_notify_assoc_status(a, ap->bssid, num_sta >= ap->max_sta ? false : true); + ap->sent_assocnotif = true; + } } /* request scan results from the driver, etc */ @@ -6681,6 +6746,7 @@ int agent_init_interfaces(struct agent *a) fn->cfg = f; fn->agent = a; strncpy(fn->radio_name, re->name, IFNAMSIZ-1); + fn->sent_assocnotif = false; list_add(&fn->list, &re->aplist); } else @@ -6723,7 +6789,6 @@ int agent_init_interfaces(struct agent *a) strncpy(bss->ssid, fn->ssid, sizeof(bss->ssid) - 1); bss->enabled = fn->enabled; - for (k = 0; k < num_subfr; k++) wifi_subscribe_frame(f->name, subfr[k].type, subfr[k].stype); @@ -7347,6 +7412,7 @@ void clear_stalist(struct netif_ap *p) p->num_sta--; clear_sta(s); } + agent_modify_assoc_status(p, true); } void clear_nbrlist(struct netif_ap *p) diff --git a/src/agent.h b/src/agent.h index e44fc068ce318956bf78249c34885c5d6be6d617..138409f5057d2cefa9ec62aa6b867411f8e96c53 100644 --- a/src/agent.h +++ b/src/agent.h @@ -328,7 +328,9 @@ struct netif_ap { struct list_head restrict_stalist; /* list of restrict_sta_entry */ struct list_head nbrlist; int nbr_nr; + uint16_t max_sta; /* max number of stations: 0 - unlimited */ uint16_t num_sta; + bool sent_assocnotif; struct list_head stalist; struct agent *agent; diff --git a/src/agent_map.c b/src/agent_map.c index e379dc1e6b354d93b5ea84baad362f2df166128a..bb3d0944127e9c790388b7c07426d84ae2399d14 100644 --- a/src/agent_map.c +++ b/src/agent_map.c @@ -492,19 +492,22 @@ int send_sta_disassoc_stats(void *agent, struct cmdu_buff *cmdu) int send_assoc_status_notification(struct agent *a, int num_data, void *data) { - struct node *n; + struct node *n = NULL; struct cmdu_buff *cmdu; + /* TODO: ensure 1905 sends msg as reliable multicast */ + /* cntlr may not have its own node allocated */ cmdu = agent_gen_association_status_notify(a, num_data, data); if (cmdu) { - memcpy(cmdu->origin, a->cfg.cntlr_almac, 6); + memcpy(cmdu->origin, a->cfg.cntlr_almac, ETH_ALEN); agent_send_cmdu(a, cmdu); cmdu_free(cmdu); } list_for_each_entry(n, &a->nodelist, list) { - if (!memcpy(n->alid, a->cfg.cntlr_almac, 6)) + if (!memcmp(n->alid, a->cfg.cntlr_almac, ETH_ALEN)) + /* skip cntlr - already sent */ continue; cmdu = agent_gen_association_status_notify(a, num_data, data); @@ -519,7 +522,6 @@ int send_assoc_status_notification(struct agent *a, int num_data, void *data) return 0; } - int send_tunneled_message(void *agent, struct cmdu_buff *cmdu) { return 0; diff --git a/src/agent_ubus.c b/src/agent_ubus.c index ea47029bea5b4ce25d178567aedb7a86efc82fb6..7c38ae6d74bd34fc5a0128294ea998c046630f29 100644 --- a/src/agent_ubus.c +++ b/src/agent_ubus.c @@ -1299,7 +1299,7 @@ static int assoc_notify(struct ubus_context *ctx, struct ubus_object *obj, * '0x00' or '0x01' */ status = blobmsg_get_u32(tb1[1]); - if (!((status == 0x00) || (status == 0x01))) + if (!((status == STA_ASSOC_NOT_ALLOWED) || (status == STA_ASSOC_ALLOWED))) continue; tmp = realloc(bss_data, (num_data + 1) * sizeof(*bss_data)); diff --git a/src/assoc_ctrl.c b/src/assoc_ctrl.c index aaea264e866f486fab8ccfac7cba94a4e83de9cd..3fd867c201c75b05f56c00787bc55f3975431093 100644 --- a/src/assoc_ctrl.c +++ b/src/assoc_ctrl.c @@ -389,7 +389,7 @@ int assoc_ctrl_process_request(void *agent, uint8_t *p, __func__, disallow ? "Disallow" : "Allow", MAC2STR(data->bssid), ap->ifname); - if (!wifi_set_backhaul_bss_association_mode(ap->ifname, disallow)) { + if (!wifi_set_ap_mbo_association_mode(ap->ifname, disallow)) { ap->cfg->disallow_assoc = disallow; uci_apply_bss_association_mode(ap->ifname, disallow); } diff --git a/src/wifi.c b/src/wifi.c index ca2b12d37863ceb128869e4724d874b103576504..fe1ac3a55a9e53d92edd2152b7d3900b38a02c8e 100644 --- a/src/wifi.c +++ b/src/wifi.c @@ -428,7 +428,7 @@ int wifi_ap_stats(const char *ifname, struct wifi_ap_stats *stats) return ret; } -int wifi_set_backhaul_bss_association_mode(const char *ifname, bool disallow) +int wifi_set_ap_mbo_association_mode(const char *ifname, bool disallow) { struct ubus_context *ctx = ubus_connect(NULL); int ret; diff --git a/src/wifi.h b/src/wifi.h index c21c832b3fb523901390834615d507376e9b2e0a..b904afc21f559f6a1bac69c94c7cd327f5b61016 100644 --- a/src/wifi.h +++ b/src/wifi.h @@ -134,7 +134,7 @@ int wifi_send_qos_map_conf(const char *ifname, uint8_t *macaddr); int wifi_sta_info(const char *ifname, struct wifi_sta *sta); int wifi_bsta_disconnect(struct netif_bk *bk, uint32_t reason); -int wifi_set_backhaul_bss_association_mode(const char *ifname, bool disallow); +int wifi_set_ap_mbo_association_mode(const char *ifname, bool disallow); /* WiFi send managment action frame*/ int wifi_send_action(const char *ifname, uint8_t *dst_mac, diff --git a/src/wifi_ubus.c b/src/wifi_ubus.c index 5d8958367f03e32160f33ee5a58afd5e2baf2383..b7efc90a0ed280e924b6045d0e0a48a9e46e6a15 100644 --- a/src/wifi_ubus.c +++ b/src/wifi_ubus.c @@ -1219,19 +1219,20 @@ static void wifi_ubus_ap_status_cb(struct ubus_request *req, struct blob_attr *msg) { struct ap_status_ctx *ctx = req->priv; - static const struct blobmsg_policy ap_status_policy[] = { - [0] = { .name = "channel", .type = BLOBMSG_TYPE_INT32 }, - [1] = { .name = "bssid", .type = BLOBMSG_TYPE_STRING }, - [2] = { .name = "ssid", .type = BLOBMSG_TYPE_STRING }, - [3] = { .name = "utilization", .type = BLOBMSG_TYPE_INT32 }, - [4] = { .name = "capabilities", .type = BLOBMSG_TYPE_TABLE }, - [5] = { .name = "standard", .type = BLOBMSG_TYPE_STRING }, - [6] = { .name = "bandwidth", .type = BLOBMSG_TYPE_INT32 }, - [7] = { .name = "status", .type = BLOBMSG_TYPE_STRING }, - [8] = { .name = "num_stations", .type = BLOBMSG_TYPE_INT32 }, - [9] = { .name = "enabled", .type = BLOBMSG_TYPE_BOOL }, - [10] = { .name = "encryption", .type = BLOBMSG_TYPE_STRING }, - [11] = { .name = "hidden", .type = BLOBMSG_TYPE_INT32 }, + static const struct blobmsg_policy ap_status_policy[] = { + [0] = { .name = "channel", .type = BLOBMSG_TYPE_INT32 }, + [1] = { .name = "bssid", .type = BLOBMSG_TYPE_STRING }, + [2] = { .name = "ssid", .type = BLOBMSG_TYPE_STRING }, + [3] = { .name = "utilization", .type = BLOBMSG_TYPE_INT32 }, + [4] = { .name = "capabilities", .type = BLOBMSG_TYPE_TABLE }, + [5] = { .name = "standard", .type = BLOBMSG_TYPE_STRING }, + [6] = { .name = "bandwidth", .type = BLOBMSG_TYPE_INT32 }, + [7] = { .name = "status", .type = BLOBMSG_TYPE_STRING }, + [8] = { .name = "num_stations", .type = BLOBMSG_TYPE_INT32 }, + [9] = { .name = "enabled", .type = BLOBMSG_TYPE_BOOL }, + [10] = { .name = "encryption", .type = BLOBMSG_TYPE_STRING }, + [11] = { .name = "hidden", .type = BLOBMSG_TYPE_INT32 }, + [12] = { .name = "max_stations", .type = BLOBMSG_TYPE_INT32 }, }; struct blob_attr *tb[ARRAY_SIZE(ap_status_policy)]; struct wifi_ap *ap; @@ -1239,8 +1240,8 @@ static void wifi_ubus_ap_status_cb(struct ubus_request *req, blobmsg_parse(ap_status_policy, ARRAY_SIZE(ap_status_policy), tb, blob_data(msg), blob_len(msg)); - if (!tb[0] || !tb[1] || !tb[2] || !tb[3] || !tb[4] || !tb[5] || - !tb[6] || !tb[7] || !tb[8] || !tb[9] || !tb[10] || !tb[11]) { + if (!tb[0] || !tb[1] || !tb[2] || !tb[3] || + !tb[8] || !tb[9] || !tb[12]) { ctx->status = -1; return; } @@ -1253,12 +1254,13 @@ static void wifi_ubus_ap_status_cb(struct ubus_request *req, return; } strncpy((char *) &ap->bss.ssid[0], blobmsg_get_string(tb[2]), sizeof(ap->bss.ssid)); - ap->bss.load.utilization = blobmsg_get_u32(tb[3]); - ap->bss.load.sta_count = blobmsg_get_u32(tb[8]); + ap->bss.load.sta_count = blobmsg_get_u32(tb[8]); ap->enabled = blobmsg_get_u32(tb[9]); + ap->assoclist_max = blobmsg_get_u32(tb[12]); + ctx->status = 0; }