struct wpa_driver_capa capa;
#ifdef CONFIG_IEEE80211BE
struct hostapd_data *h_hapd = NULL;
+ void *shared_hapd = NULL;
#endif /* CONFIG_IEEE80211BE */
if (hapd->driver == NULL || hapd->driver->hapd_init == NULL) {
params.own_addr = hapd->own_addr;
+#ifdef CONFIG_IEEE80211BE
+ if (hapd->driver->can_share_drv &&
+ hapd->driver->can_share_drv(hapd, ¶ms, &shared_hapd)) {
+ char force_ifname[IFNAMSIZ];
+ const u8 *addr = params.bssid;
+ u8 if_addr[ETH_ALEN];
+
+ if (!shared_hapd) {
+ wpa_printf(MSG_ERROR, "Failed to get the shared drv");
+ os_free(params.bridge);
+ return -1;
+ }
+
+ /* Share an already initialized driver interface instance
+ * using an AP mode BSS in it instead of adding a new driver
+ * interface instance for the same driver. */
+ if (hostapd_if_add(shared_hapd, WPA_IF_AP_BSS,
+ params.ifname, addr, hapd,
+ &hapd->drv_priv, force_ifname, if_addr,
+ params.num_bridge && params.bridge[0] ?
+ params.bridge[0] : NULL,
+ 0)) {
+ wpa_printf(MSG_ERROR, "Failed to add BSS (BSSID="
+ MACSTR ")", MAC2STR(hapd->own_addr));
+ os_free(params.bridge);
+ return -1;
+ }
+ os_free(params.bridge);
+
+ hapd->interface_added = 1;
+ os_memcpy(params.own_addr, addr ? addr : if_addr, ETH_ALEN);
+
+ goto pre_setup_mld;
+ }
+#endif /* CONFIG_IEEE80211BE */
+
hapd->drv_priv = hapd->driver->hapd_init(hapd, ¶ms);
os_free(params.bridge);
if (hapd->drv_priv == NULL) {
}
#ifdef CONFIG_IEEE80211BE
+pre_setup_mld:
/*
* This is the first interface added to the AP MLD, so have the
* interface hardware address be the MLD address, while the link address
authsrv_deinit(hapd);
- if (hapd->interface_added) {
+ /* For single drv, first bss would have interface_added flag set.
+ * Don't remove interface now. Driver deinit part will take care
+ */
+ if (hapd->interface_added && hapd->iface->bss[0] != hapd) {
hapd->interface_added = 0;
if (hostapd_if_remove(hapd, WPA_IF_AP_BSS, hapd->conf->iface)) {
wpa_printf(MSG_WARNING,
* still being used by some other BSS before de-initiallizing. */
if (!iface->bss[0]->conf->mld_ap) {
driver->hapd_deinit(drv_priv);
- } else if (hostapd_mld_is_first_bss(iface->bss[0]) &&
- driver->is_drv_shared &&
+ } else if (driver->is_drv_shared &&
!driver->is_drv_shared(drv_priv,
iface->bss[0]->mld_link_id)) {
driver->hapd_deinit(drv_priv);
*/
int (*nan_cancel_subscribe)(void *priv, int subscribe_id);
+ /**
+ * can_share_drv - Check whether driver interface can be shared
+ * @ctx: Pointer to hostapd context
+ * @params: Configuration for the driver wrapper
+ * @hapd: Pointer for overwriting the hapd context or %NULL
+ * if can't find a shared drv
+ *
+ * Checks whether the driver interface with same phy name is
+ * already present under the global driver which can be shared
+ * instead of creating a new driver interface instance. If present,
+ * @hapd will be overwritten with the hapd pointer which this shared
+ * drv's first BSS is using. This will help the caller to later call
+ * if_add().
+ *
+ * Returns: true if it can be shared or else false.
+ */
+ bool (*can_share_drv)(void *ctx, struct wpa_init_params *params,
+ void **hapd);
+
#ifdef CONFIG_TESTING_OPTIONS
int (*register_frame)(void *priv, u16 type,
const u8 *match, size_t match_len,
#ifdef CONFIG_IEEE80211BE
+
static int wpa_driver_nl80211_link_sta_remove(void *priv, u8 link_id,
const u8 *addr)
{
return ret;
}
+
+
+static int wpa_driver_get_wiphy_name_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct wpa_driver_nl80211_data *drv = arg;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (!tb[NL80211_ATTR_WIPHY_NAME])
+ return NL_SKIP;
+
+ os_strlcpy(drv->phyname, nla_get_string(tb[NL80211_ATTR_WIPHY_NAME]),
+ sizeof(drv->phyname));
+
+ return NL_SKIP;
+}
+
+
+static int wpa_driver_get_phyname(struct wpa_driver_nl80211_data *drv)
+{
+ struct nl_msg *msg;
+ u32 feat, nl_flags;
+
+ feat = get_nl80211_protocol_features(drv);
+ if (feat & NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP)
+ nl_flags = NLM_F_DUMP;
+
+ if (!(msg = nl80211_cmd_msg(drv->first_bss, nl_flags,
+ NL80211_CMD_GET_WIPHY)) ||
+ nla_put_flag(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP)) {
+ nlmsg_free(msg);
+ return -1;
+ }
+
+ if (send_and_recv_resp(drv, msg, wpa_driver_get_wiphy_name_handler,
+ drv))
+ return -1;
+
+ return 0;
+}
+
+
+static bool
+wpa_driver_nl80211_name_match(struct wpa_driver_nl80211_data *drv,
+ struct wpa_driver_nl80211_data **match_drv)
+{
+ struct wpa_driver_nl80211_data *drv2;
+
+ dl_list_for_each(drv2, &drv->global->interfaces,
+ struct wpa_driver_nl80211_data, list) {
+ if (os_strcmp(drv2->phyname, drv->phyname) == 0) {
+ if (match_drv)
+ *match_drv = drv2;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+static bool wpa_driver_nl80211_can_share_drv(void *ctx,
+ struct wpa_init_params *params,
+ void **hapd)
+{
+ struct wpa_driver_nl80211_data *drv, *match_drv = NULL;
+ struct i802_bss *bss;
+ bool ret = false;
+
+ if (!params->global_priv)
+ return false;
+
+ /* Create a temporary drv to read the phyname */
+ drv = os_zalloc(sizeof(*drv));
+ if (!drv)
+ return false;
+ drv->global = params->global_priv;
+ drv->ctx = ctx;
+
+ drv->first_bss = os_zalloc(sizeof(*drv->first_bss));
+ if (!drv->first_bss) {
+ os_free(drv);
+ return false;
+ }
+
+ bss = drv->first_bss;
+ bss->drv = drv;
+ bss->ctx = ctx;
+
+ os_strlcpy(bss->ifname, params->ifname, sizeof(bss->ifname));
+
+ if (nl80211_init_bss(bss))
+ goto free_all;
+
+ drv->ifindex = if_nametoindex(bss->ifname);
+ bss->ifindex = drv->ifindex;
+
+ if (wpa_driver_get_phyname(drv) ||
+ !wpa_driver_nl80211_name_match(drv, &match_drv) ||
+ !match_drv)
+ goto free_all;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Driver for phy %s already exist",
+ match_drv->phyname);
+
+ *hapd = match_drv->first_bss->ctx;
+ ret = true;
+
+free_all:
+ nl80211_destroy_bss(bss);
+ os_free(bss);
+ os_free(drv);
+ return ret;
+}
+
#endif /* CONFIG_IEEE80211BE */
.link_remove = driver_nl80211_link_remove,
.is_drv_shared = nl80211_is_drv_shared,
.link_sta_remove = wpa_driver_nl80211_link_sta_remove,
+ .can_share_drv = wpa_driver_nl80211_can_share_drv,
#endif /* CONFIG_IEEE80211BE */
#ifdef CONFIG_TESTING_OPTIONS
.register_frame = testing_nl80211_register_frame,
int nl80211_set_default_scan_ies(void *priv, const u8 *ies, size_t ies_len);
struct hostapd_multi_hw_info *
nl80211_get_multi_hw_info(struct i802_bss *bss, unsigned int *num_multi_hws);
+u32 get_nl80211_protocol_features(struct wpa_driver_nl80211_data *drv);
#endif /* DRIVER_NL80211_H */
}
-static u32 get_nl80211_protocol_features(struct wpa_driver_nl80211_data *drv)
+u32 get_nl80211_protocol_features(struct wpa_driver_nl80211_data *drv)
{
u32 feat = 0;
struct nl_msg *msg;