diff --git a/src/config.c b/src/config.c index a416c987e7c6e679638951362fdb434dc7c8d249..a71fc329bfa602cd8f4e3eb4637cd48b0e3f1e36 100644 --- a/src/config.c +++ b/src/config.c @@ -241,6 +241,71 @@ int hostmngr_config_defaults(struct hostmngr_config *cfg) return 0; } +int ap_get_mld_ifname(char *ifname, char *mld_ifname) +{ + enum { + W_IFNAME, + W_MLD, + NUM_POLICIES + }; + const struct uci_parse_option opts[] = { + { .name = "ifname", .type = UCI_TYPE_STRING }, + { .name = "mld", .type = UCI_TYPE_STRING } + }; + struct uci_option *tb[NUM_POLICIES]; + struct uci_context *ctx; + struct uci_package *pkg; + struct uci_element *e; + int ret = -1; + + ctx = uci_alloc_context(); + if (!ctx) + return ret; + + if (uci_load(ctx, "wireless", &pkg)) { + uci_free_context(ctx); + return ret; + } + + uci_foreach_element(&pkg->sections, e) { + struct uci_section *s = uci_to_section(e); + struct uci_ptr ptr; + + if (strcmp(s->type, "wifi-iface")) + continue; + + uci_parse_section(s, opts, NUM_POLICIES, tb); + + if (!tb[W_IFNAME]) + continue; + + if (strncmp(ifname, tb[W_IFNAME]->v.string, 16)) + continue; + + if (!tb[W_MLD]) + break; + + /* lookup mld ifname in wifi-mld section directly */ + ptr.package = "wireless"; + ptr.section = tb[W_MLD]->v.string; + ptr.option = "ifname"; + ptr.target = UCI_TYPE_OPTION; + + ret = uci_lookup_ptr(ctx, &ptr, NULL, false); + if (ret != UCI_OK ||!(ptr.flags & UCI_LOOKUP_DONE)) + break; + + if (!(ptr.flags & UCI_LOOKUP_COMPLETE)) + break; + + strncpy(mld_ifname, ptr.o->v.string, 16); + } + + uci_unload(ctx, pkg); + uci_free_context(ctx); + return ret; +} + int hostmngr_dump_config(struct hostmngr_config *cfg) { char *s, *ifnames = NULL; diff --git a/src/hostmngr.c b/src/hostmngr.c index 76b1ac0a27df93a2b0da0a8ce098daf625fcbb19..c9f6cd306532f69aa465bc9cac33a9b3891caa43 100644 --- a/src/hostmngr.c +++ b/src/hostmngr.c @@ -95,8 +95,13 @@ struct local_interface *hostmngr_alloc_interface(const char *ifname) if (strncmp(iface->ifname, "lo", 2)) { if (is_wifi_interface(iface->ifname)) { iface->mediatype = IF_MEDIA_WIFI; - if (is_ap_interface(iface->ifname)) + if (is_ap_interface(iface->ifname)) { iface->is_ap = true; + iface->is_affiliated_ap = is_affiliated_ap(iface->ifname); + if (iface->is_affiliated_ap) + ap_get_mld_ifname(iface->ifname, iface->mld_ifname); + + } } else { iface->mediatype = IF_MEDIA_ETH; } @@ -166,8 +171,12 @@ void enum_interfaces_cb(struct nl_object *obj, void *arg) if (strncmp(iface->ifname, "lo", 2)) { if (is_wifi_interface(iface->ifname)) { iface->mediatype = IF_MEDIA_WIFI; - if (is_ap_interface(iface->ifname)) + if (is_ap_interface(iface->ifname)) { iface->is_ap = true; + iface->is_affiliated_ap = is_affiliated_ap(iface->ifname); + if (iface->is_affiliated_ap) + ap_get_mld_ifname(iface->ifname, iface->mld_ifname); + } } else { iface->mediatype = IF_MEDIA_ETH; } diff --git a/src/hostmngr.h b/src/hostmngr.h index 5968f49a1e48ab4be580c4526cd60e8b1c45c230..775295b1c97f9b925eee084b7e2c8783b097c884 100644 --- a/src/hostmngr.h +++ b/src/hostmngr.h @@ -192,11 +192,14 @@ int hostmngr_reconfig(struct hostmngr_config *cfg, const char *path, const char void hostmngr_config_free(struct hostmngr_config *cfg); int hostmngr_config_add_zone(struct hostmngr_config *cfg, const char *ifname); +int ap_get_mld_ifname(char *ifname, char *mld_ifname); struct local_interface { char ifname[16]; int ifindex; uint8_t macaddr[6]; + char mld_ifname[16]; + bool is_affiliated_ap; uint32_t ifflags; uint8_t operstate; bool is_bridge; diff --git a/src/neigh.c b/src/neigh.c index 9905f542e045aa83760a1f95fa81418e86ba05c5..8520386e83fa6ae3c417a7a8bec55ed2396241bf 100644 --- a/src/neigh.c +++ b/src/neigh.c @@ -1069,11 +1069,15 @@ int neigh_is_wifi_type(void *priv, uint8_t *macaddr) list_for_each_entry(iface, &p->iflist, list) { if (iface->is_ap) { + char *ifname = iface->ifname; uint8_t stas[6*128] = {0}; int num = 128; int ret; int i; + if (iface->is_affiliated_ap && strlen(iface->mld_ifname)) + ifname = iface->mld_ifname; + ret = ap_get_assoclist(iface->ifname, stas, &num); if (ret) continue; @@ -1092,12 +1096,16 @@ int neigh_is_wifi_type(void *priv, uint8_t *macaddr) void hostmngr_get_wifi_stations(struct hostmngr_private *priv, struct local_interface *iface) { + char *ifname = iface->ifname; uint8_t stas[6*128] = {0}; int num = 128; int ret; int i; - ret = ap_get_assoclist(iface->ifname, stas, &num); + if (iface->is_affiliated_ap && strlen(iface->mld_ifname)) + ifname = iface->mld_ifname; + + ret = ap_get_assoclist(ifname, stas, &num); if (ret) return; diff --git a/src/wifi_api.c b/src/wifi_api.c index 7a5f755712b667535e023b24394fe62ffcb9df63..c40999d14fa8369ebd2332027a311bd62668b0cb 100644 --- a/src/wifi_api.c +++ b/src/wifi_api.c @@ -58,6 +58,22 @@ int interface_get_4addr_parent(const char *ifname, char *parent) return wifi_get_4addr_parent(ifname, parent); } + +int is_affiliated_ap(const char *ifname) +{ + struct wifi_ap ap = {0}; + int ret; + + ret = wifi_ap_info(ifname, &ap); + if (ret) + return false; + + if (ap.bss.mlo_link_id == -1 || hwaddr_is_zero(ap.bss.mld_macaddr)) + return false; + + return true; +} + int is_wifi_interface(const char *ifname) { char parent[16] = {0}; diff --git a/src/wifi_api.h b/src/wifi_api.h index e01b177485293a9455c70d0c2158c951da8b1c3e..281955762a61f75dc4d75c9c7ef059ada39d5df3 100644 --- a/src/wifi_api.h +++ b/src/wifi_api.h @@ -15,7 +15,7 @@ int is_wifi_interface(const char *ifname); int is_ap_interface(const char *ifname); int ap_get_assoclist(const char *ifname, uint8_t *sta_macaddrs, int *num); int interface_get_4addr_parent(const char *ifname, char *parent); - +int is_affiliated_ap(const char *ifname); #else static inline int is_wifi_interface(const char *ifname) { @@ -36,6 +36,10 @@ static inline int interface_get_4addr_parent(const char *ifname, char *parent) { return -1; } +static inline int is_affiliated_ap(const char *ifname) +{ + return -1; +} #endif /* HAS_WIFI */