[PATCH 11/16] hostapd: MLO: add support to remove the link before removing interface

Aditya Kumar Singh quic_adisi at quicinc.com
Wed Mar 6 09:39:42 PST 2024


Currently whenever if_remove() is called, whole interface is deleted.
In MLO, all partner BSS uses the same driver private hence removing the
interface when only one the link goes down should be avoided.

Add helper function to remove link first whenever if_remove() is called.
Later while handling it, if number of links active goes to 0, then the
if_remove() would be called in order to clean up the interface.

This helper would be used later when co-hosted MLD support is added as well
later during ML reconfiguration support.

Signed-off-by: Aditya Kumar Singh <quic_adisi at quicinc.com>
---
 src/ap/ap_drv_ops.c          | 18 +++++++++++++
 src/ap/ap_drv_ops.h          |  3 +++
 src/drivers/driver.h         | 14 ++++++++++
 src/drivers/driver_nl80211.c | 50 ++++++++++++++++++++++++++++++++++++
 src/drivers/driver_nl80211.h |  1 +
 5 files changed, 86 insertions(+)

diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index a6f53fd8cbb1..5dfcdac3a137 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -571,6 +571,18 @@ int hostapd_if_add(struct hostapd_data *hapd, enum wpa_driver_if_type type,
 				    bridge, use_existing, 1);
 }
 
+#ifdef CONFIG_IEEE80211BE
+int hostapd_if_link_remove(struct hostapd_data *hapd, enum wpa_driver_if_type type,
+			   const char *ifname, u8 link_id)
+{
+	if (hapd->driver == NULL || hapd->drv_priv == NULL ||
+	    hapd->driver->if_link_remove == NULL)
+		return -1;
+
+	return hapd->driver->if_link_remove(hapd->drv_priv, type, ifname,
+					    hapd->mld_link_id);
+}
+#endif /* CONFIG_IEEE80211BE */
 
 int hostapd_if_remove(struct hostapd_data *hapd, enum wpa_driver_if_type type,
 		      const char *ifname)
@@ -578,6 +590,12 @@ int hostapd_if_remove(struct hostapd_data *hapd, enum wpa_driver_if_type type,
 	if (hapd->driver == NULL || hapd->drv_priv == NULL ||
 	    hapd->driver->if_remove == NULL)
 		return -1;
+
+#ifdef CONFIG_IEEE80211BE
+	if (hapd->conf->mld_ap)
+		return hostapd_if_link_remove(hapd, type, ifname, hapd->mld_link_id);
+#endif /* CONFIG_IEEE80211BE */
+
 	return hapd->driver->if_remove(hapd->drv_priv, type, ifname);
 }
 
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index b3a96447947a..9c74ef579b2f 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -458,6 +458,9 @@ static inline int hostapd_drv_link_add(struct hostapd_data *hapd,
 	return hapd->driver->link_add(hapd->drv_priv, link_id, addr, hapd);
 
 }
+
+int hostapd_if_link_remove(struct hostapd_data *hapd, enum wpa_driver_if_type type,
+			   const char *ifname, u8 link_id);
 #endif /* CONFIG_IEEE80211BE */
 
 #endif /* AP_DRV_OPS */
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 8ffe487ae1c7..6616397fb5d9 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -5142,6 +5142,20 @@ struct wpa_driver_ops {
 	 */
 	int (*link_add)(void *priv, u8 link_id, const u8 *addr, void *bss_ctx);
 
+#ifdef CONFIG_IEEE80211BE
+	/**
+	 * if_link_remove - Remove a link alone from virtual interface
+	 * @priv: Private driver interface data
+	 * @type: Interface type
+	 * @ifname: Interface name of the virtual interface from where link is
+	 *	    to be removed
+	 * @link_id: Valid link ID to remove
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*if_link_remove)(void *priv, enum wpa_driver_if_type type,
+			      const char *ifname, s8 link_id);
+#endif /* CONFIG_IEEE80211BE */
+
 #ifdef CONFIG_TESTING_OPTIONS
 	int (*register_frame)(void *priv, u16 type,
 			      const u8 *match, size_t match_len,
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index ef9a513b663b..d5f7cc7d041c 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -196,6 +196,7 @@ static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv,
 static int i802_set_iface_flags(struct i802_bss *bss, int up);
 static int nl80211_set_param(void *priv, const char *param);
 static void nl80211_remove_links(struct i802_bss *bss);
+static int nl80211_remove_link(struct i802_bss *bss, int link_id);
 #ifdef CONFIG_MESH
 static int nl80211_put_mesh_config(struct nl_msg *msg,
 				   struct wpa_driver_mesh_bss_params *params);
@@ -10709,6 +10710,52 @@ static int driver_nl80211_if_remove(void *priv, enum wpa_driver_if_type type,
 	return wpa_driver_nl80211_if_remove(bss, type, ifname);
 }
 
+#ifdef CONFIG_IEEE80211BE
+static int wpa_driver_nl80211_if_link_remove(struct i802_bss *bss,
+					     enum wpa_driver_if_type type,
+					     const char *ifname,
+					     s8 link_id)
+{
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+
+	wpa_printf(MSG_DEBUG, "nl80211: %s(type=%d ifname=%s links=0x%x) link_id=%d",
+		   __func__, type, ifname, bss->valid_links, link_id);
+	wpa_printf(MSG_DEBUG, "nl80211: Teardown AP(%s) link %d", bss->ifname,
+		   link_id);
+
+	nl80211_remove_link(bss, link_id);
+
+	bss->ctx = bss->flink->ctx;
+
+	if (drv->first_bss == bss && !bss->valid_links)
+		drv->ctx = bss->ctx;
+
+	if (!bss->valid_links) {
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Only 1 link was there hence remove interface");
+		return wpa_driver_nl80211_if_remove(bss, type, ifname);
+	}
+
+	return 0;
+}
+
+static int driver_nl80211_if_link_remove(void *priv, enum wpa_driver_if_type type,
+					 const char *ifname, s8 link_id)
+{
+	struct i802_bss *bss = priv;
+
+	if (link_id < 0 || link_id >= MAX_NUM_MLD_LINKS)
+		return -1;
+
+	if (type != WPA_IF_AP_BSS)
+		return -1;
+
+	if (!(bss->valid_links & BIT(link_id)))
+		return -1;
+
+	return wpa_driver_nl80211_if_link_remove(bss, type, ifname, link_id);
+}
+#endif /* CONFIG_IEEE80211BE */
 
 static int driver_nl80211_send_mlme(void *priv, const u8 *data,
 				    size_t data_len, int noack,
@@ -14038,6 +14085,9 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
 #endif /* CONFIG_DPP */
 	.get_sta_mlo_info = nl80211_get_sta_mlo_info,
 	.link_add = nl80211_link_add,
+#ifdef CONFIG_IEEE80211BE
+	.if_link_remove = driver_nl80211_if_link_remove,
+#endif /* CONFIG_IEEE80211BE */
 #ifdef CONFIG_TESTING_OPTIONS
 	.register_frame = testing_nl80211_register_frame,
 	.radio_disable = testing_nl80211_radio_disable,
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index 03d3c333b3d1..3e5a53452f00 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -352,6 +352,7 @@ const char * nl80211_iftype_str(enum nl80211_iftype mode);
 
 void nl80211_restore_ap_mode(struct i802_bss *bss);
 struct i802_link * nl80211_get_link(struct i802_bss *bss, s8 link_id);
+int nl80211_is_valid_link(struct i802_bss *bss, s8 link_id);
 
 static inline bool nl80211_link_valid(u16 links, s8 link_id)
 {
-- 
2.25.1




More information about the Hostap mailing list