diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 2a4adf4f8..f382d231b 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -910,6 +910,30 @@ struct wpa_driver_ap_params { struct hostapd_freq_params *freq; }; +struct wpa_driver_mesh_bss_params { +#define WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS 0x00000001 + /* + * TODO: Other mesh configuration parameters would go here. + * See NL80211_MESHCONF_* for all the mesh config parameters. + */ + unsigned int flags; +}; + +struct wpa_driver_mesh_join_params { + const u8 *meshid; + int meshid_len; + const int *basic_rates; + const u8 *ies; + int ie_len; + int freq; + struct wpa_driver_mesh_bss_params conf; +#define WPA_DRIVER_MESH_FLAG_USER_MPM 0x00000001 +#define WPA_DRIVER_MESH_FLAG_DRIVER_MPM 0x00000002 +#define WPA_DRIVER_MESH_FLAG_SAE_AUTH 0x00000004 +#define WPA_DRIVER_MESH_FLAG_AMPE 0x00000008 + unsigned int flags; +}; + /** * struct wpa_driver_capa - Driver capability information */ @@ -3025,6 +3049,29 @@ struct wpa_driver_ops { */ int (*disable_transmit_sa)(void *priv, u32 channel, u8 an); #endif /* CONFIG_MACSEC */ + + /** + * init_mesh - Driver specific initialization for mesh + * @priv: Private driver interface data + * Returns: 0 on success, -1 on failure + */ + int (*init_mesh)(void *priv); + + /** + * join_mesh - Join a mesh network + * @priv: Private driver interface data + * @params: Mesh configuration parameters + * Returns: 0 on success, -1 on failure + */ + int (*join_mesh)(void *priv, + struct wpa_driver_mesh_join_params *params); + + /** + * leave_mesh - Leave a mesh network + * @priv: Private driver interface data + * Returns 0 on success, -1 on failure + */ + int (*leave_mesh)(void *priv); }; diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index e055bebe1..70d6c30ee 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -12588,6 +12588,145 @@ static int nl80211_set_mac_addr(void *priv, const u8 *addr) } +#ifdef CONFIG_MESH + +static int wpa_driver_nl80211_init_mesh(void *priv) +{ + if (wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_MESH_POINT)) { + wpa_printf(MSG_INFO, + "nl80211: Failed to set interface into mesh mode"); + return -1; + } + return 0; +} + + +static int +wpa_driver_nl80211_join_mesh(void *priv, + struct wpa_driver_mesh_join_params *params) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + struct nl_msg *msg; + struct nlattr *container; + int ret = 0; + + msg = nlmsg_alloc(); + if (!msg) + return -1; + + wpa_printf(MSG_DEBUG, "nl80211: mesh join (ifindex=%d)", drv->ifindex); + nl80211_cmd(drv, msg, 0, NL80211_CMD_JOIN_MESH); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + /* XXX: need chtype too in case we want HT */ + if (params->freq) { + wpa_printf(MSG_DEBUG, " * freq=%d", params->freq); + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq); + } + + if (params->basic_rates) { + u8 rates[NL80211_MAX_SUPP_RATES]; + u8 rates_len = 0; + int i; + + for (i = 0; i < NL80211_MAX_SUPP_RATES; i++) { + if (params->basic_rates[i] < 0) + break; + rates[rates_len++] = params->basic_rates[i] / 5; + } + + NLA_PUT(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len, rates); + } + + if (params->meshid) { + wpa_hexdump_ascii(MSG_DEBUG, " * SSID", + params->meshid, params->meshid_len); + NLA_PUT(msg, NL80211_ATTR_MESH_ID, params->meshid_len, + params->meshid); + } + + wpa_printf(MSG_DEBUG, " * flags=%08X", params->flags); + + container = nla_nest_start(msg, NL80211_ATTR_MESH_SETUP); + if (!container) + goto nla_put_failure; + + if (params->ies) { + wpa_hexdump(MSG_DEBUG, " * IEs", params->ies, params->ie_len); + NLA_PUT(msg, NL80211_MESH_SETUP_IE, params->ie_len, + params->ies); + } + /* WPA_DRIVER_MESH_FLAG_OPEN_AUTH is treated as default by nl80211 */ + if (params->flags & WPA_DRIVER_MESH_FLAG_SAE_AUTH) { + NLA_PUT_U8(msg, NL80211_MESH_SETUP_AUTH_PROTOCOL, 0x1); + NLA_PUT_FLAG(msg, NL80211_MESH_SETUP_USERSPACE_AUTH); + } + if (params->flags & WPA_DRIVER_MESH_FLAG_AMPE) + NLA_PUT_FLAG(msg, NL80211_MESH_SETUP_USERSPACE_AMPE); + if (params->flags & WPA_DRIVER_MESH_FLAG_USER_MPM) + NLA_PUT_FLAG(msg, NL80211_MESH_SETUP_USERSPACE_MPM); + nla_nest_end(msg, container); + + container = nla_nest_start(msg, NL80211_ATTR_MESH_CONFIG); + if (!container) + goto nla_put_failure; + + if (!(params->conf.flags & WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS)) + NLA_PUT_U32(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS, 0); + nla_nest_end(msg, container); + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + msg = NULL; + if (ret) { + wpa_printf(MSG_DEBUG, "nl80211: mesh join failed: ret=%d (%s)", + ret, strerror(-ret)); + goto nla_put_failure; + } + ret = 0; + bss->freq = params->freq; + wpa_printf(MSG_DEBUG, "nl80211: mesh join request send successfully"); + + +nla_put_failure: + nlmsg_free(msg); + return ret; +} + + +static int wpa_driver_nl80211_leave_mesh(void *priv) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + struct nl_msg *msg; + int ret = 0; + + msg = nlmsg_alloc(); + if (!msg) + return -1; + + wpa_printf(MSG_DEBUG, "nl80211: mesh leave (ifindex=%d)", drv->ifindex); + nl80211_cmd(drv, msg, 0, NL80211_CMD_LEAVE_MESH); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + msg = NULL; + if (ret) { + wpa_printf(MSG_DEBUG, "nl80211: mesh leave failed: ret=%d (%s)", + ret, strerror(-ret)); + goto nla_put_failure; + } + ret = 0; + wpa_printf(MSG_DEBUG, "nl80211: mesh leave request send successfully"); + +nla_put_failure: + nlmsg_free(msg); + return ret; +} + +#endif /* CONFIG_MESH */ + + const struct wpa_driver_ops wpa_driver_nl80211_ops = { .name = "nl80211", .desc = "Linux nl80211/cfg80211", @@ -12681,4 +12820,9 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { .set_wowlan = nl80211_set_wowlan, .roaming = nl80211_roaming, .set_mac_addr = nl80211_set_mac_addr, +#ifdef CONFIG_MESH + .init_mesh = wpa_driver_nl80211_init_mesh, + .join_mesh = wpa_driver_nl80211_join_mesh, + .leave_mesh = wpa_driver_nl80211_leave_mesh, +#endif /* CONFIG_MESH */ }; diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk index d78ba78eb..8b7df6c77 100644 --- a/wpa_supplicant/Android.mk +++ b/wpa_supplicant/Android.mk @@ -195,6 +195,11 @@ NEED_SHA256=y NEED_AES_OMAC1=y endif +ifdef CONFIG_MESH +NEED_80211_COMMON=y +L_CFLAGS += -DCONFIG_MESH +endif + ifdef CONFIG_SAE L_CFLAGS += -DCONFIG_SAE OBJS += src/common/sae.c diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile index 7a6824697..7eee73a9d 100644 --- a/wpa_supplicant/Makefile +++ b/wpa_supplicant/Makefile @@ -198,6 +198,11 @@ NEED_SHA256=y NEED_AES_OMAC1=y endif +ifdef CONFIG_MESH +NEED_80211_COMMON=y +CFLAGS += -DCONFIG_MESH +endif + ifdef CONFIG_SAE CFLAGS += -DCONFIG_SAE OBJS += ../src/common/sae.o diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h index 649de9bd4..18a545764 100644 --- a/wpa_supplicant/driver_i.h +++ b/wpa_supplicant/driver_i.h @@ -65,6 +65,28 @@ static inline int wpa_drv_associate(struct wpa_supplicant *wpa_s, return -1; } +static inline int wpa_drv_init_mesh(struct wpa_supplicant *wpa_s) +{ + if (wpa_s->driver->init_mesh) + return wpa_s->driver->init_mesh(wpa_s->drv_priv); + return -1; +} + +static inline int wpa_drv_join_mesh(struct wpa_supplicant *wpa_s, + struct wpa_driver_mesh_join_params *params) +{ + if (wpa_s->driver->join_mesh) + return wpa_s->driver->join_mesh(wpa_s->drv_priv, params); + return -1; +} + +static inline int wpa_drv_leave_mesh(struct wpa_supplicant *wpa_s) +{ + if (wpa_s->driver->leave_mesh) + return wpa_s->driver->leave_mesh(wpa_s->drv_priv); + return -1; +} + static inline int wpa_drv_scan(struct wpa_supplicant *wpa_s, struct wpa_driver_scan_params *params) {