From 89a6d3984741e5b7f857852bcfbaf993adfe95ab Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Mon, 10 Mar 2014 18:13:51 -0700 Subject: [PATCH] driver: add new NL80211 cmds to support mesh ifaces - Create mesh_join and mesh_leave actions to kernel. - Handle new_peer_candidate events from kernel. - Register to receive necessary frames. - Add plink_action_field and mesh_power_mode to hostapd_sta_add_params Signed-off-by: Javier Lopez Signed-off-by: Javier Cardona Signed-off-by: Jason Mobarak Signed-hostap: Bob Copeland --- v2: - Split out the widing of the drv_flags / flags into separate patch. - Squash with "Clarify comment on TODO" https://github.com/cozybit/wpa_s_mesh_android/commit/95430203e0462eb1c275380b6fed172f5ce9daf1 - Squash with "Add plink_action_field and mesh_power_mode to hostapd_sta_add_params" https://github.com/cozybit/wpa_s_mesh_android/commit/89d29f6a5c84a7b59ecfe1bb60c7271533bb6ea7 - Squash with "Clarify comment (issue #10)" https://github.com/cozybit/wpa_s_mesh_android/commit/21734bc9b50190f06040ca26f0819cbb75c9c522 - Squash with "closes #12" https://github.com/cozybit/wpa_s_mesh_android/commit/4d7209ed2d12a4eb1fbcafb26741f3b06f55149e - Squash with "Closes #16" https://github.com/cozybit/wpa_s_mesh_android/commit/fa05631616199fa48f61c7e58e44729e216d5d64 - Squash with "No default mesh frequency. Closes #18" https://github.com/cozybit/wpa_s_mesh_android/commit/03f80b9c4ae3b9580d3759c3f564b257aa62022e - Squash with "Closes #19" https://github.com/cozybit/wpa_s_mesh_android/commit/3cf9b4c238037e6bba73048d6f221f8ea9b1f445 - Squash with "Set mesh authentication protocol id in mesh config" https://github.com/cozybit/wpa_s_mesh_android/commit/caaf6ee68cc28cfde9400869440209b55c07a35f - Squash with "PLINK_CLOSE can have only MESHID and MPM IEs" https://github.com/cozybit/wpa_s_mesh_android/commit/6c4fd81f8cfa5f576fbaffae3654eb38bdf91016 v3: Remove workaround for NL80211_FEATURE_SK_TX_STATUS v4: No changes v5: Removed extraneous else for NL80211_FEATURE_SK_TX_STATUS change v6: Updated email addresses, added signed-hostap for Bob v7: remove blank lines --- src/common/defs.h | 25 ++++ src/drivers/driver.h | 78 +++++++++- src/drivers/driver_common.c | 1 + src/drivers/driver_nl80211.c | 270 +++++++++++++++++++++++++++++++++-- src/drivers/driver_wext.c | 2 +- wpa_supplicant/driver_i.h | 17 +++ 6 files changed, 378 insertions(+), 15 deletions(-) diff --git a/src/common/defs.h b/src/common/defs.h index d4091e310..1ee709049 100644 --- a/src/common/defs.h +++ b/src/common/defs.h @@ -300,4 +300,29 @@ enum wpa_ctrl_req_type { /* Maximum number of EAP methods to store for EAP server user information */ #define EAP_MAX_METHODS 8 +#ifdef CONFIG_MESH +enum mesh_plink_state { + PLINK_LISTEN = 1, + PLINK_OPEN_SENT, + PLINK_OPEN_RCVD, + PLINK_CNF_RCVD, + PLINK_ESTAB, + PLINK_HOLDING, + PLINK_BLOCKED, +}; + +enum mesh_power_mode { + MESH_POWER_ACTIVE = 1, + MESH_POWER_LIGHT_SLEEP, + MESH_POWER_DEEP_SLEEP, +}; + +enum plink_action_field { + PLINK_OPEN = 1, + PLINK_CONFIRM, + PLINK_CLOSE +}; + +#endif /* CONFIG_MESH */ + #endif /* DEFS_H */ diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 13bf7183d..c284df742 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -170,6 +170,7 @@ struct hostapd_hw_modes { #define IEEE80211_MODE_INFRA 0 #define IEEE80211_MODE_IBSS 1 #define IEEE80211_MODE_AP 2 +#define IEEE80211_MODE_MESH 5 #define IEEE80211_CAP_ESS 0x0001 #define IEEE80211_CAP_IBSS 0x0002 @@ -870,6 +871,29 @@ struct wpa_driver_ap_params { int osen; }; +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_* in nl80211.h for all the mesh config parameters. */ + unsigned int flags; +}; + +struct wpa_driver_mesh_join_params { + const u8 *meshid; + int meshid_len; + int *basic_rates; + int mcast_rate; + 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 */ @@ -1055,6 +1079,12 @@ struct hostapd_sta_add_params { int vht_opmode_enabled; u8 vht_opmode; u32 flags; /* bitmask of WPA_STA_* flags */ + u32 flags_mask; /* unset bits in flags */ +#ifdef CONFIG_MESH + enum mesh_plink_state plink_state; + enum plink_action_field plink_action; + enum mesh_power_mode power_mode; +#endif /* CONFIG_MESH */ int set; /* Set STA parameters instead of add */ u8 qosinfo; const u8 *ext_capab; @@ -1135,7 +1165,11 @@ enum wpa_driver_if_type { * WPA_IF_P2P_DEVICE - P2P Device interface is used to indentify the * abstracted P2P Device function in the driver */ - WPA_IF_P2P_DEVICE + WPA_IF_P2P_DEVICE, + /* + * WPA_IF_MESH - Mesh interface + */ + WPA_IF_MESH }; struct wpa_init_params { @@ -1173,6 +1207,7 @@ struct wpa_bss_params { #define WPA_STA_SHORT_PREAMBLE BIT(2) #define WPA_STA_MFP BIT(3) #define WPA_STA_TDLS_PEER BIT(4) +#define WPA_STA_AUTHENTICATED BIT(5) enum tdls_oper { TDLS_DISCOVERY_REQ, @@ -2164,7 +2199,7 @@ struct wpa_driver_ops { * @session_timeout: Session timeout for the station * Returns: 0 on success, -1 on failure */ - int (*set_radius_acl_auth)(void *priv, const u8 *mac, int accepted, + int (*set_radius_acl_auth)(void *priv, const u8 *mac, int accepted, u32 session_timeout); /** @@ -2761,6 +2796,21 @@ struct wpa_driver_ops { * Returns: Length of written status information or -1 on failure */ int (*status)(void *priv, char *buf, size_t buflen); + + /** + * 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); }; @@ -3235,7 +3285,13 @@ enum wpa_event_type { * to reduce issues due to interference or internal co-existence * information in the driver. */ - EVENT_AVOID_FREQUENCIES + EVENT_AVOID_FREQUENCIES, + + /** + * EVENT_NEW_PEER_CANDIDATE - new (unknown) mesh peer notification + */ + EVENT_NEW_PEER_CANDIDATE + }; @@ -3874,6 +3930,22 @@ union wpa_event_data { * This is used as the data with EVENT_AVOID_FREQUENCIES. */ struct wpa_freq_range_list freq_range; + + /** + * struct mesh_peer + * + * @peer: peer address + * @ies: beacon IEs + * @ie_len: length of @ies + * + * Notification of new candidate mesh peer. + */ + struct mesh_peer { + u8 peer[ETH_ALEN]; + u8 *ies; + int ie_len; + } mesh_peer; + }; /** diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c index 3058cd57d..63138ab4a 100644 --- a/src/drivers/driver_common.c +++ b/src/drivers/driver_common.c @@ -70,6 +70,7 @@ const char * event_to_string(enum wpa_event_type event) E2S(DRIVER_CLIENT_POLL_OK); E2S(EAPOL_TX_STATUS); E2S(CH_SWITCH); + E2S(NEW_PEER_CANDIDATE); E2S(WNM); E2S(CONNECT_FAILED_REASON); E2S(DFS_RADAR_DETECTED); diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 1300703e5..17b5bc5b5 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -544,7 +544,8 @@ static int is_ap_interface(enum nl80211_iftype nlmode) static int is_sta_interface(enum nl80211_iftype nlmode) { return (nlmode == NL80211_IFTYPE_STATION || - nlmode == NL80211_IFTYPE_P2P_CLIENT); + nlmode == NL80211_IFTYPE_P2P_CLIENT || + nlmode == NL80211_IFTYPE_MESH_POINT); } @@ -554,6 +555,11 @@ static int is_p2p_net_interface(enum nl80211_iftype nlmode) nlmode == NL80211_IFTYPE_P2P_GO); } +static int is_mesh_interface(enum nl80211_iftype nlmode) +{ + return nlmode == NL80211_IFTYPE_MESH_POINT; +} + static void nl80211_mark_disconnected(struct wpa_driver_nl80211_data *drv) { @@ -2459,6 +2465,37 @@ static void nl80211_cqm_event(struct wpa_driver_nl80211_data *drv, } +static void nl80211_new_peer_candidate(struct wpa_driver_nl80211_data *drv, + struct nlattr **tb) +{ + u8 *addr, *ie; + int ie_len; + union wpa_event_data data; + + if (drv->nlmode != NL80211_IFTYPE_MESH_POINT) + return; + + if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_IE]) + return; + + ie = nla_data(tb[NL80211_ATTR_IE]); + ie_len = nla_len(tb[NL80211_ATTR_IE]); + addr = nla_data(tb[NL80211_ATTR_MAC]); + wpa_printf(MSG_DEBUG, "nl80211: New peer candidate" MACSTR, MAC2STR(addr)); + + os_memset(&data, 0, sizeof(data)); + os_memcpy(data.mesh_peer.peer, addr, ETH_ALEN); + if ((data.mesh_peer.ies = os_zalloc(ie_len)) == NULL) { + wpa_printf(MSG_ERROR, "nl80211: couldn't alloc peer IEs!"); + return; + } + os_memcpy(data.mesh_peer.ies, ie, ie_len); + data.mesh_peer.ie_len = ie_len; + wpa_supplicant_event(drv->ctx, EVENT_NEW_PEER_CANDIDATE, &data); + os_free(data.mesh_peer.ies); +} + + static void nl80211_new_station_event(struct wpa_driver_nl80211_data *drv, struct nlattr **tb) { @@ -3113,6 +3150,9 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd, case NL80211_CMD_VENDOR: nl80211_vendor_event(drv, tb); break; + case NL80211_CMD_NEW_PEER_CANDIDATE: + nl80211_new_peer_candidate(drv, tb); + break; default: wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Ignored unknown event " "(cmd=%d)", cmd); @@ -4477,6 +4517,37 @@ static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss) return ret; } +static int nl80211_mgmt_subscribe_mesh(struct i802_bss *bss) +{ + int ret = 0; + + if (nl80211_alloc_mgmt_handle(bss)) + return -1; + + wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with mesh " + "handle %p", bss->nl_mgmt); + + /* Auth frames for mesh SAE */ + if (nl80211_register_frame(bss, bss->nl_mgmt, + (WLAN_FC_TYPE_MGMT << 2) | + (WLAN_FC_STYPE_AUTH << 4), + NULL, 0) < 0) + ret = -1; + + /* Mesh peering open */ + if (nl80211_register_action_frame(bss, (u8 *) "\x0f\x01", 2) < 0) + ret = -1; + /* Mesh peering confirm */ + if (nl80211_register_action_frame(bss, (u8 *) "\x0f\x02", 2) < 0) + ret = -1; + /* Mesh peering close */ + if (nl80211_register_action_frame(bss, (u8 *) "\x0f\x03", 2) < 0) + ret = -1; + + nl80211_mgmt_handle_register_eloop(bss); + + return ret; +} static int nl80211_register_spurious_class3(struct i802_bss *bss) { @@ -4825,7 +4896,9 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss) if (!drv->start_iface_up) (void) i802_set_iface_flags(bss, 0); - if (drv->nlmode != NL80211_IFTYPE_P2P_DEVICE) { + + if (drv->nlmode != NL80211_IFTYPE_P2P_DEVICE && + drv->nlmode != NL80211_IFTYPE_MESH_POINT) { if (!drv->hostapd || !drv->start_mode_ap) wpa_driver_nl80211_set_mode(bss, NL80211_IFTYPE_STATION); @@ -5688,7 +5761,18 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss, wpa_hexdump(MSG_DEBUG, "nl80211: KEY_SEQ", seq, seq_len); } - if (addr && !is_broadcast_ether_addr(addr)) { + if (!addr && key_len && set_tx) { + /* this is a group tx key */ + if (alg == WPA_ALG_IGTK || alg == WPA_ALG_CCMP) { + wpa_printf(MSG_DEBUG, " TX GTK"); + NLA_PUT_U32(msg, NL80211_ATTR_KEY_TYPE, + NL80211_KEYTYPE_GROUP); + if (alg == WPA_ALG_IGTK) + NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT_MGMT); + else + NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT); + } + } else if (addr && !is_broadcast_ether_addr(addr)) { wpa_printf(MSG_DEBUG, " addr=" MACSTR, MAC2STR(addr)); NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); @@ -7412,10 +7496,37 @@ static u32 sta_flags_nl80211(int flags) f |= BIT(NL80211_STA_FLAG_MFP); if (flags & WPA_STA_TDLS_PEER) f |= BIT(NL80211_STA_FLAG_TDLS_PEER); + if (flags & WPA_STA_AUTHENTICATED) + f |= BIT(NL80211_STA_FLAG_AUTHENTICATED); return f; } +#ifdef CONFIG_MESH +static u32 sta_plink_state_nl80211(enum mesh_plink_state state) +{ + switch (state) { + case PLINK_LISTEN: + return NL80211_PLINK_LISTEN; + case PLINK_OPEN_SENT: + return NL80211_PLINK_OPN_SNT; + case PLINK_OPEN_RCVD: + return NL80211_PLINK_OPN_RCVD; + case PLINK_CNF_RCVD: + return NL80211_PLINK_CNF_RCVD; + case PLINK_ESTAB: + return NL80211_PLINK_ESTAB; + case PLINK_HOLDING: + return NL80211_PLINK_HOLDING; + case PLINK_BLOCKED: + return NL80211_PLINK_BLOCKED; + default: + wpa_printf(MSG_ERROR, "nl80211: Invalid mesh plink state %d", + state); + } + return -1; +} +#endif /* CONFIG_MESH */ static int wpa_driver_nl80211_sta_add(void *priv, struct hostapd_sta_add_params *params) @@ -7441,10 +7552,12 @@ static int wpa_driver_nl80211_sta_add(void *priv, NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->addr); - NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_RATES, params->supp_rates_len, - params->supp_rates); - wpa_hexdump(MSG_DEBUG, " * supported rates", params->supp_rates, - params->supp_rates_len); + if (params->supp_rates || !params->set) { + NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_RATES, + params->supp_rates_len, params->supp_rates); + wpa_hexdump(MSG_DEBUG, " * supported rates", + params->supp_rates, params->supp_rates_len); + } if (!params->set) { if (params->aid) { wpa_printf(MSG_DEBUG, " * aid=%u", params->aid); @@ -7490,8 +7603,10 @@ static int wpa_driver_nl80211_sta_add(void *priv, params->vht_opmode); } - wpa_printf(MSG_DEBUG, " * capability=0x%x", params->capability); - NLA_PUT_U16(msg, NL80211_ATTR_STA_CAPABILITY, params->capability); + if (params->capability) { + wpa_printf(MSG_DEBUG, " * capability=0x%x", params->capability); + NLA_PUT_U16(msg, NL80211_ATTR_STA_CAPABILITY, params->capability); + } if (params->ext_capab) { wpa_hexdump(MSG_DEBUG, " * ext_capab", @@ -7517,12 +7632,18 @@ static int wpa_driver_nl80211_sta_add(void *priv, } os_memset(&upd, 0, sizeof(upd)); - upd.mask = sta_flags_nl80211(params->flags); - upd.set = upd.mask; + upd.set = sta_flags_nl80211(params->flags); + upd.mask = upd.set | sta_flags_nl80211(params->flags_mask); wpa_printf(MSG_DEBUG, " * flags set=0x%x mask=0x%x", upd.set, upd.mask); NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd); +#ifdef CONFIG_MESH + if (params->plink_state) + NLA_PUT_U8(msg, NL80211_ATTR_STA_PLINK_STATE, + sta_plink_state_nl80211(params->plink_state)); +#endif /* CONFIG_MESH */ + if (params->flags & WPA_STA_WMM) { struct nlattr *wme = nla_nest_start(msg, NL80211_ATTR_STA_WME); @@ -8789,6 +8910,118 @@ static int wpa_driver_nl80211_connect( } +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; + + if (wpa_driver_nl80211_set_mode(drv->first_bss, + NL80211_IFTYPE_MESH_POINT)) + 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->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", + (unsigned char *) 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; +} + static int wpa_driver_nl80211_associate( void *priv, struct wpa_driver_associate_params *params) { @@ -8969,7 +9202,12 @@ static int wpa_driver_nl80211_set_mode(struct i802_bss *bss, nl80211_mgmt_unsubscribe(bss, "mode change"); } + if (is_mesh_interface(nlmode)) + if (nl80211_mgmt_subscribe_mesh(bss)) + return -1; + if (!bss->in_deinit && !is_ap_interface(nlmode) && + !is_mesh_interface(nlmode) && nl80211_mgmt_subscribe_non_ap(bss) < 0) wpa_printf(MSG_DEBUG, "nl80211: Failed to register Action " "frame processing - ignore for now"); @@ -9484,6 +9722,9 @@ static int i802_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, struct wpa_driver_nl80211_data *drv = bss->drv; struct ieee80211_mgmt mgmt; + if (is_mesh_interface(drv->nlmode)) + return -1; + if (drv->device_ap_sme) return wpa_driver_nl80211_sta_remove(bss, addr); @@ -9508,6 +9749,9 @@ static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr, struct wpa_driver_nl80211_data *drv = bss->drv; struct ieee80211_mgmt mgmt; + if (is_mesh_interface(drv->nlmode)) + return -1; + if (drv->device_ap_sme) return wpa_driver_nl80211_sta_remove(bss, addr); @@ -9834,6 +10078,8 @@ static enum nl80211_iftype wpa_driver_nl80211_if_type( return NL80211_IFTYPE_P2P_GO; case WPA_IF_P2P_DEVICE: return NL80211_IFTYPE_P2P_DEVICE; + case WPA_IF_MESH: + return NL80211_IFTYPE_MESH_POINT; } return -1; } @@ -12096,6 +12342,8 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { .deauthenticate = driver_nl80211_deauthenticate, .authenticate = driver_nl80211_authenticate, .associate = wpa_driver_nl80211_associate, + .join_mesh = wpa_driver_nl80211_join_mesh, + .leave_mesh = wpa_driver_nl80211_leave_mesh, .global_init = nl80211_global_init, .global_deinit = nl80211_global_deinit, .init2 = wpa_driver_nl80211_init, diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c index e5734bddc..aeeb9b581 100644 --- a/src/drivers/driver_wext.c +++ b/src/drivers/driver_wext.c @@ -1568,7 +1568,7 @@ static int wpa_driver_wext_get_range(void *priv) drv->capa.max_scan_ssids = 1; wpa_printf(MSG_DEBUG, " capabilities: key_mgmt 0x%x enc 0x%x " - "flags 0x%x", + "flags 0x%lx", drv->capa.key_mgmt, drv->capa.enc, drv->capa.flags); } else { wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: too old (short) data - " diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h index 938ece699..c333913e2 100644 --- a/wpa_supplicant/driver_i.h +++ b/wpa_supplicant/driver_i.h @@ -65,6 +65,23 @@ static inline int wpa_drv_associate(struct wpa_supplicant *wpa_s, 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) {