[PATCH v2 04/20] driver: add new NL80211 cmds to support mesh ifaces
Bob Copeland
me
Sun Aug 31 21:23:23 PDT 2014
- To support mesh mode, use u64 to fit all necessary driver flags.
- 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 <jlopex at gmail.com>
Signed-off-by: Javier Cardona <javier at cozybit.com>
Signed-off-by: Jason Mobarak <x at jason.mobarak.name>
Signed-off-by: Bob Copeland <me at bobcopeland.com>
---
src/common/defs.h | 25 ++++
src/drivers/driver.h | 90 +++++++++++-
src/drivers/driver_common.c | 1 +
src/drivers/driver_nl80211.c | 302 ++++++++++++++++++++++++++++++++++++--
src/drivers/driver_wext.c | 5 +-
wpa_supplicant/driver_i.h | 22 +++
wpa_supplicant/wpa_supplicant_i.h | 2 +-
7 files changed, 428 insertions(+), 19 deletions(-)
diff --git a/src/common/defs.h b/src/common/defs.h
index d4091e3..fb289b0 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 352c163..f48ff84 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
@@ -893,6 +894,31 @@ 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;
+ 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
*/
@@ -1003,7 +1029,9 @@ struct wpa_driver_capa {
#define WPA_DRIVER_FLAGS_QOS_MAPPING 0x40000000
/* Driver supports CSA in AP mode */
#define WPA_DRIVER_FLAGS_AP_CSA 0x80000000
- unsigned int flags;
+/* Driver supports mesh */
+#define WPA_DRIVER_FLAGS_MESH 0x0000000100000000ULL
+ u64 flags;
int max_scan_ssids;
int max_sched_scan_ssids;
@@ -1081,6 +1109,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;
@@ -1161,7 +1195,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 {
@@ -1199,6 +1237,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,
@@ -3000,6 +3039,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);
};
@@ -3475,7 +3537,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
+
};
@@ -4114,6 +4182,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 3058cd5..63138ab 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 8ebf7d9..c39f77c 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -568,7 +568,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;
}
@@ -578,6 +579,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)
{
@@ -2496,6 +2502,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)
{
@@ -3150,6 +3187,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);
@@ -3453,6 +3493,9 @@ static void wiphy_info_supported_iftypes(struct wiphy_info_data *info,
case NL80211_IFTYPE_AP:
info->capa->flags |= WPA_DRIVER_FLAGS_AP;
break;
+ case NL80211_IFTYPE_MESH_POINT:
+ info->capa->flags |= WPA_DRIVER_FLAGS_MESH;
+ break;
case NL80211_IFTYPE_ADHOC:
info->capa->flags |= WPA_DRIVER_FLAGS_IBSS;
break;
@@ -4558,6 +4601,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)
{
@@ -4910,7 +4984,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);
@@ -5789,7 +5865,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);
@@ -7546,10 +7633,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)
@@ -7575,11 +7689,13 @@ 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->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->aid) {
wpa_printf(MSG_DEBUG, " * aid=%u", params->aid);
NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, params->aid);
@@ -7624,8 +7740,12 @@ 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",
@@ -7651,12 +7771,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);
@@ -8948,6 +9074,140 @@ static int wpa_driver_nl80211_connect(
}
+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 "
+ "mode 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",
+ (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)
{
@@ -9153,7 +9413,12 @@ done:
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");
@@ -9685,6 +9950,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);
@@ -9709,6 +9977,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);
@@ -10035,6 +10306,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;
}
@@ -12014,7 +12287,7 @@ static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen)
"capa.key_mgmt=0x%x\n"
"capa.enc=0x%x\n"
"capa.auth=0x%x\n"
- "capa.flags=0x%x\n"
+ "capa.flags=0x%llx\n"
"capa.max_scan_ssids=%d\n"
"capa.max_sched_scan_ssids=%d\n"
"capa.sched_scan_supported=%d\n"
@@ -12027,7 +12300,7 @@ static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen)
drv->capa.key_mgmt,
drv->capa.enc,
drv->capa.auth,
- drv->capa.flags,
+ (unsigned long long) drv->capa.flags,
drv->capa.max_scan_ssids,
drv->capa.max_sched_scan_ssids,
drv->capa.sched_scan_supported,
@@ -12365,6 +12638,9 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.deauthenticate = driver_nl80211_deauthenticate,
.authenticate = driver_nl80211_authenticate,
.associate = wpa_driver_nl80211_associate,
+ .init_mesh = wpa_driver_nl80211_init_mesh,
+ .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 459ac48..8d35424 100644
--- a/src/drivers/driver_wext.c
+++ b/src/drivers/driver_wext.c
@@ -1568,8 +1568,9 @@ 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",
- drv->capa.key_mgmt, drv->capa.enc, drv->capa.flags);
+ "flags 0x%llx",
+ drv->capa.key_mgmt, drv->capa.enc,
+ (unsigned long long) drv->capa.flags);
} else {
wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: too old (short) data - "
"assuming WPA is not supported");
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index 00703d9..1bc4340 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)
{
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 0a907c0..94a969c 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -573,7 +573,7 @@ struct wpa_supplicant {
int scan_id[MAX_SCAN_ID];
unsigned int scan_id_count;
- unsigned int drv_flags;
+ u64 drv_flags;
unsigned int drv_enc;
/*
--
2.1.0.rc1
More information about the Hostap
mailing list