diff --git a/src/config.c b/src/config.c
index a416c987e7c6e679638951362fdb434dc7c8d249..48c7ca563f92f092e7d9717379f82a1579b81a22 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 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 */