[PATCH 09/35] nl80211: Support NAN Device interface
Andrei Otcheretianski
andrei.otcheretianski at intel.com
Mon Oct 20 05:27:44 PDT 2025
From: Ilan Peer <ilan.peer at intel.com>
Add support for getting NAN Device interface capabilities from
the kernel and support adding a NAN Device interface.
As the NAN device interface is created with NL80211_ATTR_SOCKET_OWNER,
meaning that the NAN events would be sent on the socket that was
used for creating the interface, use a dedicated socket for the
NAN Device interface creation, to avoid races between kernel
asynchronous events, and kernel responses for commands sent from
wpa_supplicant.
Signed-off-by: Ilan Peer <ilan.peer at intel.com>
Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski at intel.com>
---
src/drivers/driver_nl80211.c | 152 +++++++++++++++++++++---------
src/drivers/driver_nl80211.h | 4 +
src/drivers/driver_nl80211_capa.c | 17 ++++
3 files changed, 129 insertions(+), 44 deletions(-)
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index e97eba7d1b..ef4248a197 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -246,6 +246,12 @@ static int is_p2p_net_interface(enum nl80211_iftype nlmode)
}
+static int nl80211_is_netdev_iftype(enum nl80211_iftype t)
+{
+ return t != NL80211_IFTYPE_P2P_DEVICE && t != NL80211_IFTYPE_NAN;
+}
+
+
struct i802_bss * get_bss_ifindex(struct wpa_driver_nl80211_data *drv,
int ifindex)
{
@@ -2303,7 +2309,7 @@ static void wpa_driver_nl80211_rfkill_blocked(void *ctx)
* rtnetlink ifdown handler will report interfaces other than the P2P
* Device interface as disabled.
*/
- if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE)
+ if (!nl80211_is_netdev_iftype(drv->nlmode))
wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED, NULL);
}
@@ -2325,7 +2331,7 @@ static void wpa_driver_nl80211_rfkill_unblocked(void *ctx)
* rtnetlink ifup handler will report interfaces other than the P2P
* Device interface as enabled.
*/
- if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE)
+ if (!nl80211_is_netdev_iftype(drv->nlmode))
wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED, NULL);
}
@@ -2459,25 +2465,27 @@ wpa_driver_nl80211_drv_init_rfkill(struct wpa_driver_nl80211_data *drv)
rcfg->ctx = drv;
- /* rfkill uses netdev sysfs for initialization. However, P2P Device is
- * not associated with a netdev, so use the name of some other interface
- * sharing the same wiphy as the P2P Device interface.
+ /* rfkill uses netdev sysfs for initialization. However, P2P/NAN Device
+ * is not associated with a netdev, so use the name of some other
+ * interface sharing the same wiphy as the P2P/NAN Device interface.
*
- * Note: This is valid, as a P2P Device interface is always dynamically
- * created and is created only once another wpa_s interface was added.
+ * Note: This is valid, as a P2P/NAN Device interface is always
+ * dynamically created and is created only once another wpa_s interface
+ * was added.
*/
- if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE) {
+ if (!nl80211_is_netdev_iftype(drv->nlmode)) {
struct nl80211_global *global = drv->global;
struct wpa_driver_nl80211_data *tmp1;
dl_list_for_each(tmp1, &global->interfaces,
struct wpa_driver_nl80211_data, list) {
if (drv == tmp1 || drv->wiphy_idx != tmp1->wiphy_idx ||
- !tmp1->rfkill)
+ !tmp1->rfkill ||
+ !nl80211_is_netdev_iftype(tmp1->nlmode))
continue;
wpa_printf(MSG_DEBUG,
- "nl80211: Use (%s) to initialize P2P Device rfkill",
+ "nl80211: Use (%s) to initialize P2P/NAN Device rfkill",
tmp1->first_bss->ifname);
os_strlcpy(rcfg->ifname, tmp1->first_bss->ifname,
sizeof(rcfg->ifname));
@@ -3097,7 +3105,7 @@ static void wpa_driver_nl80211_send_rfkill(void *eloop_ctx, void *timeout_ctx)
}
-static void nl80211_del_p2pdev(struct i802_bss *bss)
+static void nl80211_del_non_netdev(struct i802_bss *bss)
{
struct nl_msg *msg;
int ret;
@@ -3105,9 +3113,13 @@ static void nl80211_del_p2pdev(struct i802_bss *bss)
msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_DEL_INTERFACE);
ret = send_and_recv_cmd(bss->drv, msg);
- wpa_printf(MSG_DEBUG, "nl80211: Delete P2P Device %s (0x%llx): %s",
+ wpa_printf(MSG_DEBUG, "nl80211: Delete P2P/NAN Device %s (0x%llx): %s",
bss->ifname, (long long unsigned int) bss->wdev_id,
strerror(-ret));
+#ifdef CONFIG_NAN
+ if (bss->drv->nlmode == NL80211_IFTYPE_NAN && bss->drv->global->nl_nan)
+ nl80211_destroy_eloop_handle(&bss->drv->global->nl_nan, 0);
+#endif /* CONFIG_NAN */
}
@@ -3128,18 +3140,27 @@ static int nl80211_set_p2pdev(struct i802_bss *bss, int start)
}
+int nl80211_set_nandev(struct i802_bss *bss, int start)
+{
+ /* TODO: This will be implemented once NAN start/stop APIs are added */
+ return 0;
+}
+
+
static int i802_set_iface_flags(struct i802_bss *bss, int up)
{
enum nl80211_iftype nlmode;
nlmode = nl80211_get_ifmode(bss);
- if (nlmode != NL80211_IFTYPE_P2P_DEVICE) {
- return linux_set_iface_flags(bss->drv->global->ioctl_sock,
- bss->ifname, up);
+ if (nlmode == NL80211_IFTYPE_P2P_DEVICE) {
+ /* P2P Device has start/stop which is equivalent */
+ return nl80211_set_p2pdev(bss, up);
+ } else if (nlmode == NL80211_IFTYPE_NAN) {
+ return nl80211_set_nandev(bss, up);
}
- /* P2P Device has start/stop which is equivalent */
- return nl80211_set_p2pdev(bss, up);
+ return linux_set_iface_flags(bss->drv->global->ioctl_sock,
+ bss->ifname, up);
}
@@ -3276,8 +3297,7 @@ wpa_driver_nl80211_finish_drv_init(struct i802_bss *bss, const u8 *set_addr,
if (!bss->if_dynamic && nl80211_get_ifmode(bss) == NL80211_IFTYPE_AP)
bss->static_ap = 1;
- if (first &&
- nl80211_get_ifmode(bss) != NL80211_IFTYPE_P2P_DEVICE &&
+ if (first && nl80211_is_netdev_iftype(nl80211_get_ifmode(bss)) &&
linux_iface_up(drv->global->ioctl_sock, bss->ifname) > 0)
bss->start_iface_up = 1;
@@ -3312,7 +3332,7 @@ wpa_driver_nl80211_finish_drv_init(struct i802_bss *bss, const u8 *set_addr,
return -1;
}
- if (nlmode == NL80211_IFTYPE_P2P_DEVICE)
+ if (!nl80211_is_netdev_iftype(nl80211_get_ifmode(bss)))
nl80211_get_macaddr(bss);
wpa_driver_nl80211_drv_init_rfkill(drv);
@@ -3345,11 +3365,11 @@ wpa_driver_nl80211_finish_drv_init(struct i802_bss *bss, const u8 *set_addr,
send_rfkill_event = 1;
}
- if (!drv->hostapd && nlmode != NL80211_IFTYPE_P2P_DEVICE)
- netlink_send_oper_ifla(drv->global->netlink, bss->ifindex,
+ if (!drv->hostapd && nl80211_is_netdev_iftype(nlmode))
+ netlink_send_oper_ifla(drv->global->netlink, drv->ifindex,
1, IF_OPER_DORMANT);
- if (nlmode != NL80211_IFTYPE_P2P_DEVICE) {
+ if (nl80211_is_netdev_iftype(nlmode)) {
if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
bss->addr))
return -1;
@@ -3497,14 +3517,14 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
}
}
- if (drv->nlmode != NL80211_IFTYPE_P2P_DEVICE) {
+ if (nl80211_is_netdev_iftype(drv->nlmode)) {
if (drv->start_mode_sta)
wpa_driver_nl80211_set_mode(bss,
NL80211_IFTYPE_STATION);
nl80211_mgmt_unsubscribe(bss, "deinit");
} else {
nl80211_mgmt_unsubscribe(bss, "deinit");
- nl80211_del_p2pdev(bss);
+ nl80211_del_non_netdev(bss);
}
nl80211_destroy_bss(drv->first_bss);
@@ -6390,7 +6410,7 @@ const char * nl80211_iftype_str(enum nl80211_iftype mode)
case NL80211_IFTYPE_OCB:
return "OCB";
case NL80211_IFTYPE_NAN:
- return "NAN";
+ return "NAN DEVICE";
default:
return "unknown";
}
@@ -6431,7 +6451,43 @@ static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
goto fail;
- ret = send_and_recv_resp(drv, msg, handler, arg);
+ /* NAN interface is created on a dedicated socket */
+ if (iftype == NL80211_IFTYPE_NAN) {
+#ifdef CONFIG_NAN
+ if (drv->global->nl_nan) {
+ wpa_printf(MSG_ERROR,
+ "Failed to create interface %s: socket in use",
+ ifname);
+ goto fail;
+ }
+
+ drv->global->nl_nan = nl_create_handle(drv->global->nl_cb,
+ "nan");
+ if (!drv->global->nl_nan)
+ goto fail;
+
+ ret = send_and_recv(drv, drv->global->nl_nan, msg,
+ handler, arg, NULL, NULL, NULL);
+ if (ret) {
+ nl_destroy_handles(&drv->global->nl_nan);
+ goto fail;
+ }
+
+ /*
+ * NAN events are received on a socket which is used to create
+ * the interface. Note that after this call this socket can't be
+ * used for sending commands anymore.
+ */
+ nl80211_register_eloop_read(&drv->global->nl_nan,
+ wpa_driver_nl80211_event_receive,
+ drv->global->nl_cb, 0);
+#else
+ ret = -EOPNOTSUPP;
+#endif /* CONFIG_NAN */
+ } else {
+ ret = send_and_recv_resp(drv, msg, handler, arg);
+ }
+
msg = NULL;
if (ret) {
fail:
@@ -6441,7 +6497,7 @@ static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
return ret;
}
- if (iftype == NL80211_IFTYPE_P2P_DEVICE)
+ if (!nl80211_is_netdev_iftype(iftype))
return 0;
ifidx = if_nametoindex(ifname);
@@ -7890,6 +7946,10 @@ done:
nl80211_mgmt_subscribe_mesh(bss))
return -1;
+ /* TODO: Register to NAN management frames */
+ if (nlmode == NL80211_IFTYPE_NAN)
+ return 0;
+
if (!bss->in_deinit && !is_ap_interface(nlmode) &&
!is_mesh_interface(nlmode) &&
nl80211_mgmt_subscribe_non_ap(bss) < 0)
@@ -9123,6 +9183,8 @@ static enum nl80211_iftype wpa_driver_nl80211_if_type(
return NL80211_IFTYPE_P2P_DEVICE;
case WPA_IF_MESH:
return NL80211_IFTYPE_MESH_POINT;
+ case WPA_IF_NAN:
+ return NL80211_IFTYPE_NAN;
default:
return -1;
}
@@ -9208,26 +9270,28 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
if (addr)
os_memcpy(if_addr, addr, ETH_ALEN);
nlmode = wpa_driver_nl80211_if_type(type);
- if (nlmode == NL80211_IFTYPE_P2P_DEVICE) {
- struct wdev_info p2pdev_info;
+ if (!nl80211_is_netdev_iftype(nlmode)) {
+ struct wdev_info nonnetdev_info;
- os_memset(&p2pdev_info, 0, sizeof(p2pdev_info));
+ os_memset(&nonnetdev_info, 0, sizeof(nonnetdev_info));
ifidx = nl80211_create_iface(drv, ifname, nlmode, addr,
0, nl80211_wdev_handler,
- &p2pdev_info, use_existing);
- if (!p2pdev_info.wdev_id_set || ifidx != 0) {
- wpa_printf(MSG_ERROR, "nl80211: Failed to create a P2P Device interface %s",
+ &nonnetdev_info, use_existing);
+ if (!nonnetdev_info.wdev_id_set || ifidx != 0) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: Failed to create a P2P/NAN Device interface %s",
ifname);
return -1;
}
- drv->global->if_add_wdevid = p2pdev_info.wdev_id;
- drv->global->if_add_wdevid_set = p2pdev_info.wdev_id_set;
- if (!is_zero_ether_addr(p2pdev_info.macaddr))
- os_memcpy(if_addr, p2pdev_info.macaddr, ETH_ALEN);
- wpa_printf(MSG_DEBUG, "nl80211: New P2P Device interface %s (0x%llx) created",
+ drv->global->if_add_wdevid = nonnetdev_info.wdev_id;
+ drv->global->if_add_wdevid_set = nonnetdev_info.wdev_id_set;
+ if (!is_zero_ether_addr(nonnetdev_info.macaddr))
+ os_memcpy(if_addr, nonnetdev_info.macaddr, ETH_ALEN);
+ wpa_printf(MSG_DEBUG,
+ "nl80211: New P2P/NAN Device interface %s (0x%llx) created",
ifname,
- (long long unsigned int) p2pdev_info.wdev_id);
+ (long long unsigned int) nonnetdev_info.wdev_id);
} else {
ifidx = nl80211_create_iface(drv, ifname, nlmode, addr,
0, NULL, NULL, use_existing);
@@ -9240,7 +9304,7 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
}
if (!addr) {
- if (nlmode == NL80211_IFTYPE_P2P_DEVICE)
+ if (!nl80211_is_netdev_iftype(nlmode))
os_memcpy(if_addr, bss->addr, ETH_ALEN);
else if (linux_get_ifhwaddr(drv->global->ioctl_sock,
ifname, if_addr) < 0) {
@@ -11456,7 +11520,7 @@ static const u8 * wpa_driver_nl80211_get_macaddr(void *priv)
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
- if (drv->nlmode != NL80211_IFTYPE_P2P_DEVICE)
+ if (nl80211_is_netdev_iftype(drv->nlmode))
return NULL;
return bss->addr;
@@ -14458,8 +14522,8 @@ static int nl80211_configure_data_frame_filters(void *priv, u32 filter_flags)
char path[128];
int ret;
- /* P2P-Device has no netdev that can (or should) be configured here */
- if (nl80211_get_ifmode(bss) == NL80211_IFTYPE_P2P_DEVICE)
+ /* P2P/NAN-Device has no netdev that can (or should) be configured here */
+ if (!nl80211_is_netdev_iftype(nl80211_get_ifmode(bss)))
return 0;
wpa_printf(MSG_DEBUG, "nl80211: Data frame filter flags=0x%x",
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index 3d5eb493d6..b87bb7126c 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -48,6 +48,10 @@ struct nl80211_global {
/* pending events that happened while waiting for a sync reply */
struct dl_list pending_events;
+#ifdef CONFIG_NAN
+ /* dedicated socket for NAN interface creation and events */
+ struct nl_sock *nl_nan;
+#endif
};
struct nl80211_wiphy_data {
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index d11cd5ed63..c4f4c594b7 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -132,6 +132,9 @@ static void wiphy_info_supported_iftypes(struct wiphy_info_data *info,
case NL80211_IFTYPE_P2P_CLIENT:
info->p2p_client_supported = 1;
break;
+ case NL80211_IFTYPE_NAN:
+ info->capa->flags2 |= WPA_DRIVER_FLAGS2_SUPPORT_NAN;
+ break;
}
}
}
@@ -1191,6 +1194,20 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
if (tb[NL80211_ATTR_MLO_SUPPORT])
capa->flags2 |= WPA_DRIVER_FLAGS2_MLO;
+#ifdef CONFIG_NAN
+ if (tb[NL80211_ATTR_BANDS]) {
+ u32 bands;
+
+ bands = nla_get_u32(tb[NL80211_ATTR_BANDS]);
+ wpa_printf(MSG_DEBUG, "nl80211: NAN supported bands 0x%x",
+ bands);
+ if ((bands & BIT(NL80211_BAND_2GHZ)) &&
+ (bands & BIT(NL80211_BAND_5GHZ)))
+ capa->nan_flags |=
+ WPA_DRIVER_FLAGS_NAN_SUPPORT_DUAL_BAND;
+ }
+#endif /* CONFIG_NAN */
+
return NL_SKIP;
}
--
2.49.0
More information about the Hostap
mailing list