[RFC 08/34] nl80211: Support NAN Device interface
Andrei Otcheretianski
andrei.otcheretianski at intel.com
Wed Aug 13 10:38:52 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 | 150 +++++++++++++++++++++---------
src/drivers/driver_nl80211.h | 5 +
src/drivers/driver_nl80211_capa.c | 17 ++++
3 files changed, 129 insertions(+), 43 deletions(-)
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index ca9af775b0..ad98f3292d 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -247,6 +247,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)
{
@@ -2169,7 +2175,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);
}
@@ -2191,7 +2197,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);
}
@@ -2315,25 +2321,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));
@@ -2953,7 +2961,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;
@@ -2961,9 +2969,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 */
}
@@ -2984,18 +2996,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);
}
@@ -3131,8 +3152,7 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
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)
drv->start_iface_up = 1;
@@ -3167,7 +3187,7 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
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);
@@ -3200,11 +3220,11 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
send_rfkill_event = 1;
}
- if (!drv->hostapd && nlmode != NL80211_IFTYPE_P2P_DEVICE)
+ 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;
@@ -3352,14 +3372,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);
@@ -6224,7 +6244,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";
}
@@ -6265,7 +6285,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:
@@ -6275,7 +6331,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);
@@ -7735,6 +7791,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)
@@ -8969,6 +9029,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;
}
@@ -9054,26 +9116,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);
@@ -9086,7 +9150,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) {
@@ -11281,7 +11345,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;
@@ -14283,8 +14347,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 674c26a71a..d8b3157c6c 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -37,6 +37,11 @@ struct nl80211_global {
int ioctl_sock; /* socket for ioctl() use */
struct nl_sock *nl_event;
+
+#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 f77a4fb115..ede16cca0c 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;
}
}
}
@@ -1189,6 +1192,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