AP MLD: Add links to bridge FDB for FT roaming

During FT, RRB messages are getting dropped at bridge on an AP MLD since
bridge doesn't know all the link address, so roaming gets failed.

Add AP MLD's each link address to the bridge FDB, so that RRB frames
get forwarded through bridge to hostapd.

Co-developed-by: Rameshkumar Sundaram <quic_ramess@quicinc.com>
Signed-off-by: Rameshkumar Sundaram <quic_ramess@quicinc.com>
Signed-off-by: Karthikeyan Kathirvel <quic_kathirve@quicinc.com>
This commit is contained in:
Karthikeyan Kathirvel 2024-04-09 22:53:46 +05:30 committed by Jouni Malinen
parent 1282787878
commit 7e7e43d6b3

View file

@ -3151,9 +3151,6 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
bss->ifname, bss->brname, strerror(errno)); bss->ifname, bss->brname, strerror(errno));
} }
if (drv->rtnl_sk)
nl_socket_free(drv->rtnl_sk);
if (bss->added_bridge) { if (bss->added_bridge) {
if (linux_set_iface_flags(drv->global->ioctl_sock, bss->brname, if (linux_set_iface_flags(drv->global->ioctl_sock, bss->brname,
0) < 0) 0) < 0)
@ -3173,6 +3170,9 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
nl80211_remove_links(bss); nl80211_remove_links(bss);
} }
if (drv->rtnl_sk)
nl_socket_free(drv->rtnl_sk);
if (drv->eapol_sock >= 0) { if (drv->eapol_sock >= 0) {
eloop_unregister_read_sock(drv->eapol_sock); eloop_unregister_read_sock(drv->eapol_sock);
close(drv->eapol_sock); close(drv->eapol_sock);
@ -5881,13 +5881,15 @@ fail:
} }
static void rtnl_neigh_delete_fdb_entry(struct i802_bss *bss, const u8 *addr) static void rtnl_neigh_delete_fdb_entry(struct i802_bss *bss, const u8 *addr,
bool is_bridge)
{ {
struct wpa_driver_nl80211_data *drv = bss->drv; struct wpa_driver_nl80211_data *drv = bss->drv;
struct ndmsg nhdr = { struct ndmsg nhdr = {
.ndm_state = NUD_PERMANENT, .ndm_state = NUD_PERMANENT,
.ndm_ifindex = bss->ifindex, .ndm_ifindex = is_bridge ? bss->br_ifindex : bss->ifindex,
.ndm_family = AF_BRIDGE, .ndm_family = AF_BRIDGE,
.ndm_type = is_bridge ? NTF_SELF : 0,
}; };
struct nl_msg *msg; struct nl_msg *msg;
int err; int err;
@ -5904,11 +5906,61 @@ static void rtnl_neigh_delete_fdb_entry(struct i802_bss *bss, const u8 *addr)
err = nl_wait_for_ack(drv->rtnl_sk); err = nl_wait_for_ack(drv->rtnl_sk);
if (err < 0) { if (err < 0) {
wpa_printf(MSG_DEBUG, "nl80211: bridge FDB entry delete for " wpa_printf(MSG_DEBUG, "nl80211: bridge FDB entry delete for "
MACSTR " ifindex=%d failed: %s", MAC2STR(addr), MACSTR " ifindex=%d ifname %s failed: %s",
bss->ifindex, nl_geterror(err)); MAC2STR(addr),
is_bridge ? bss->br_ifindex : bss->ifindex,
is_bridge ? bss->brname : bss->ifname,
nl_geterror(err));
} else { } else {
wpa_printf(MSG_DEBUG, "nl80211: deleted bridge FDB entry for " wpa_printf(MSG_DEBUG, "nl80211: deleted bridge FDB entry "
MACSTR, MAC2STR(addr)); MACSTR " from %s",
MAC2STR(addr),
is_bridge ? bss->brname : bss->ifname);
}
errout:
nlmsg_free(msg);
}
static void rtnl_neigh_add_fdb_entry(struct i802_bss *bss, const u8 *addr,
bool is_bridge)
{
struct wpa_driver_nl80211_data *drv = bss->drv;
struct ndmsg nhdr = {
.ndm_state = NUD_PERMANENT,
.ndm_ifindex = is_bridge ? bss->br_ifindex : bss->ifindex,
.ndm_family = AF_BRIDGE,
/* TODO: remove this check if this flag needs to be used,
* for other interfaces type.
*/
.ndm_flags = is_bridge ? NTF_SELF : 0,
};
struct nl_msg *msg;
int err;
msg = nlmsg_alloc_simple(RTM_NEWNEIGH, NLM_F_CREATE);
if (!msg)
return;
if (nlmsg_append(msg, &nhdr, sizeof(nhdr), NLMSG_ALIGNTO) < 0 ||
nla_put(msg, NDA_LLADDR, ETH_ALEN, (void *) addr) ||
nl_send_auto_complete(drv->rtnl_sk, msg) < 0)
goto errout;
err = nl_wait_for_ack(drv->rtnl_sk);
if (err < 0) {
wpa_printf(MSG_DEBUG, "nl80211: bridge FDB entry addition for "
MACSTR " ifindex=%d ifname %s failed: %s",
MAC2STR(addr),
is_bridge ? bss->br_ifindex : bss->ifindex,
is_bridge ? bss->brname : bss->ifname,
nl_geterror(err));
} else {
wpa_printf(MSG_DEBUG, "nl80211: added bridge FDB entry " MACSTR
" to %s",
MAC2STR(addr),
is_bridge ? bss->brname : bss->ifname);
} }
errout: errout:
@ -5943,7 +5995,7 @@ static int wpa_driver_nl80211_sta_remove(struct i802_bss *bss, const u8 *addr,
bss->ifname, MAC2STR(addr), ret, strerror(-ret)); bss->ifname, MAC2STR(addr), ret, strerror(-ret));
if (drv->rtnl_sk) if (drv->rtnl_sk)
rtnl_neigh_delete_fdb_entry(bss, addr); rtnl_neigh_delete_fdb_entry(bss, addr, false);
if (ret == -ENOENT) if (ret == -ENOENT)
return 0; return 0;
@ -9465,6 +9517,7 @@ int nl80211_remove_link(struct i802_bss *bss, int link_id)
struct nl_msg *msg; struct nl_msg *msg;
size_t i; size_t i;
int ret; int ret;
u8 link_addr[ETH_ALEN];
wpa_printf(MSG_DEBUG, "nl80211: Remove link (ifindex=%d link_id=%u)", wpa_printf(MSG_DEBUG, "nl80211: Remove link (ifindex=%d link_id=%u)",
bss->ifindex, link_id); bss->ifindex, link_id);
@ -9479,6 +9532,7 @@ int nl80211_remove_link(struct i802_bss *bss, int link_id)
wpa_driver_nl80211_del_beacon(bss, link_id); wpa_driver_nl80211_del_beacon(bss, link_id);
os_memcpy(link_addr, link->addr, ETH_ALEN);
/* First remove the link locally */ /* First remove the link locally */
bss->valid_links &= ~BIT(link_id); bss->valid_links &= ~BIT(link_id);
os_memset(link->addr, 0, ETH_ALEN); os_memset(link->addr, 0, ETH_ALEN);
@ -9516,6 +9570,9 @@ int nl80211_remove_link(struct i802_bss *bss, int link_id)
"nl80211: remove link (%d) failed. ret=%d (%s)", "nl80211: remove link (%d) failed. ret=%d (%s)",
link_id, ret, strerror(-ret)); link_id, ret, strerror(-ret));
if (drv->rtnl_sk)
rtnl_neigh_delete_fdb_entry(bss, link_addr, true);
return ret; return ret;
} }
@ -13957,6 +14014,10 @@ static int nl80211_link_add(void *priv, u8 link_id, const u8 *addr,
wpa_printf(MSG_DEBUG, "nl80211: MLD: valid_links=0x%04x on %s", wpa_printf(MSG_DEBUG, "nl80211: MLD: valid_links=0x%04x on %s",
bss->valid_links, bss->ifname); bss->valid_links, bss->ifname);
if (drv->rtnl_sk)
rtnl_neigh_add_fdb_entry(bss, addr, true);
return 0; return 0;
} }