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