[RFC 08/34] nl80211: Support NAN Device interface

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Ilan Peer <ilan.peer@xxxxxxxxx>

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@xxxxxxxxx>
Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski@xxxxxxxxx>
---
 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


_______________________________________________
Hostap mailing list
Hostap@xxxxxxxxxxxxxxxxxxx
http://lists.infradead.org/mailman/listinfo/hostap



[Index of Archives]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]

  Powered by Linux