aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/drivers/driver.h10
-rw-r--r--src/drivers/driver_nl80211.c11
-rw-r--r--src/rsn_supp/tdls.c40
-rw-r--r--src/rsn_supp/wpa.h3
-rw-r--r--src/rsn_supp/wpa_i.h6
-rw-r--r--wpa_supplicant/driver_i.h6
-rw-r--r--wpa_supplicant/wpas_glue.c6
7 files changed, 60 insertions, 22 deletions
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 89ad5db7..ccbcab6e 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -1162,6 +1162,13 @@ struct wpa_signal_info {
int center_frq2;
};
+/* TDLS peer capabilities for send_tdls_mgmt() */
+enum tdls_peer_capability {
+ TDLS_PEER_HT = BIT(0),
+ TDLS_PEER_VHT = BIT(1),
+ TDLS_PEER_WMM = BIT(2),
+};
+
/**
* struct wpa_driver_ops - Driver interface API definition
*
@@ -2555,6 +2562,7 @@ struct wpa_driver_ops {
* @action_code: TDLS action code for the mssage
* @dialog_token: Dialog Token to use in the message (if needed)
* @status_code: Status Code or Reason Code to use (if needed)
+ * @peer_capab: TDLS peer capability (TDLS_PEER_* bitfield)
* @buf: TDLS IEs to add to the message
* @len: Length of buf in octets
* Returns: 0 on success, negative (<0) on failure
@@ -2563,7 +2571,7 @@ struct wpa_driver_ops {
* responsible for receiving and sending all TDLS packets.
*/
int (*send_tdls_mgmt)(void *priv, const u8 *dst, u8 action_code,
- u8 dialog_token, u16 status_code,
+ u8 dialog_token, u16 status_code, u32 peer_capab,
const u8 *buf, size_t len);
/**
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 8e6510ee..a98a3cd4 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -10750,7 +10750,7 @@ nla_put_failure:
static int nl80211_send_tdls_mgmt(void *priv, const u8 *dst, u8 action_code,
u8 dialog_token, u16 status_code,
- const u8 *buf, size_t len)
+ u32 peer_capab, const u8 *buf, size_t len)
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
@@ -10772,6 +10772,15 @@ static int nl80211_send_tdls_mgmt(void *priv, const u8 *dst, u8 action_code,
NLA_PUT_U8(msg, NL80211_ATTR_TDLS_ACTION, action_code);
NLA_PUT_U8(msg, NL80211_ATTR_TDLS_DIALOG_TOKEN, dialog_token);
NLA_PUT_U16(msg, NL80211_ATTR_STATUS_CODE, status_code);
+ if (peer_capab) {
+ /*
+ * The internal enum tdls_peer_capability definition is
+ * currently identical with the nl80211 enum
+ * nl80211_tdls_peer_capability, so no conversion is needed
+ * here.
+ */
+ NLA_PUT_U32(msg, NL80211_ATTR_TDLS_PEER_CAPABILITY, peer_capab);
+ }
NLA_PUT(msg, NL80211_ATTR_IE, len, buf);
return send_and_recv_msgs(drv, msg, NULL, NULL);
diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c
index 8d287a5b..17e8225c 100644
--- a/src/rsn_supp/tdls.c
+++ b/src/rsn_supp/tdls.c
@@ -118,6 +118,7 @@ struct wpa_tdls_peer {
u8 action_code; /* TDLS frame type */
u8 dialog_token;
u16 status_code;
+ u32 peer_capab;
int buf_len; /* length of TPK message for retransmission */
u8 *buf; /* buffer for TPK message */
} sm_tmr;
@@ -142,6 +143,8 @@ struct wpa_tdls_peer {
u8 *supp_oper_classes;
size_t supp_oper_classes_len;
+
+ u8 wmm_capable;
};
@@ -211,15 +214,16 @@ static int wpa_tdls_set_key(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
static int wpa_tdls_send_tpk_msg(struct wpa_sm *sm, const u8 *dst,
u8 action_code, u8 dialog_token,
- u16 status_code, const u8 *buf, size_t len)
+ u16 status_code, u32 peer_capab,
+ const u8 *buf, size_t len)
{
return wpa_sm_send_tdls_mgmt(sm, dst, action_code, dialog_token,
- status_code, buf, len);
+ status_code, peer_capab, buf, len);
}
static int wpa_tdls_tpk_send(struct wpa_sm *sm, const u8 *dest, u8 action_code,
- u8 dialog_token, u16 status_code,
+ u8 dialog_token, u16 status_code, u32 peer_capab,
const u8 *msg, size_t msg_len)
{
struct wpa_tdls_peer *peer;
@@ -230,7 +234,7 @@ static int wpa_tdls_tpk_send(struct wpa_sm *sm, const u8 *dest, u8 action_code,
(unsigned int) msg_len);
if (wpa_tdls_send_tpk_msg(sm, dest, action_code, dialog_token,
- status_code, msg, msg_len)) {
+ status_code, peer_capab, msg, msg_len)) {
wpa_printf(MSG_INFO, "TDLS: Failed to send message "
"(action_code=%u)", action_code);
return -1;
@@ -268,6 +272,7 @@ static int wpa_tdls_tpk_send(struct wpa_sm *sm, const u8 *dest, u8 action_code,
peer->sm_tmr.action_code = action_code;
peer->sm_tmr.dialog_token = dialog_token;
peer->sm_tmr.status_code = status_code;
+ peer->sm_tmr.peer_capab = peer_capab;
peer->sm_tmr.buf_len = msg_len;
os_free(peer->sm_tmr.buf);
peer->sm_tmr.buf = os_malloc(msg_len);
@@ -324,6 +329,7 @@ static void wpa_tdls_tpk_retry_timeout(void *eloop_ctx, void *timeout_ctx)
peer->sm_tmr.action_code,
peer->sm_tmr.dialog_token,
peer->sm_tmr.status_code,
+ peer->sm_tmr.peer_capab,
peer->sm_tmr.buf,
peer->sm_tmr.buf_len)) {
wpa_printf(MSG_INFO, "TDLS: Failed to retry "
@@ -645,6 +651,8 @@ static void wpa_tdls_peer_free(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
peer->supp_oper_classes = NULL;
peer->rsnie_i_len = peer->rsnie_p_len = 0;
peer->cipher = 0;
+ peer->qos_info = 0;
+ peer->wmm_capable = 0;
peer->tpk_set = peer->tpk_success = 0;
os_memset(&peer->tpk, 0, sizeof(peer->tpk));
os_memset(peer->inonce, 0, WPA_NONCE_LEN);
@@ -747,7 +755,7 @@ skip_ies:
/* request driver to send Teardown using this FTIE */
wpa_tdls_tpk_send(sm, addr, WLAN_TDLS_TEARDOWN, 0,
- reason_code, rbuf, pos - rbuf);
+ reason_code, 0, rbuf, pos - rbuf);
os_free(rbuf);
/* clear the Peerkey statemachine */
@@ -896,7 +904,7 @@ static int wpa_tdls_send_error(struct wpa_sm *sm, const u8 *dst,
" (action=%u status=%u)",
MAC2STR(dst), tdls_action, status);
return wpa_tdls_tpk_send(sm, dst, tdls_action, dialog_token, status,
- NULL, 0);
+ 0, NULL, 0);
}
@@ -1102,7 +1110,7 @@ skip_ies:
MAC2STR(peer->addr));
status = wpa_tdls_tpk_send(sm, peer->addr, WLAN_TDLS_SETUP_REQUEST,
- 1, 0, rbuf, pos - rbuf);
+ 1, 0, 0, rbuf, pos - rbuf);
os_free(rbuf);
return status;
@@ -1186,7 +1194,7 @@ static int wpa_tdls_send_tpk_m2(struct wpa_sm *sm,
skip_ies:
status = wpa_tdls_tpk_send(sm, src_addr, WLAN_TDLS_SETUP_RESPONSE,
- dtoken, 0, rbuf, pos - rbuf);
+ dtoken, 0, 0, rbuf, pos - rbuf);
os_free(rbuf);
return status;
@@ -1204,6 +1212,7 @@ static int wpa_tdls_send_tpk_m3(struct wpa_sm *sm,
struct wpa_tdls_timeoutie timeoutie;
u32 lifetime;
int status;
+ u32 peer_capab = 0;
buf_len = 0;
if (wpa_tdls_get_privacy(sm)) {
@@ -1266,9 +1275,16 @@ static int wpa_tdls_send_tpk_m3(struct wpa_sm *sm,
wpa_tdls_ftie_mic(peer->tpk.kck, 3, (u8 *) lnkid, peer->rsnie_p,
(u8 *) &timeoutie, (u8 *) ftie, ftie->mic);
+ if (peer->vht_capabilities)
+ peer_capab |= TDLS_PEER_VHT;
+ else if (peer->ht_capabilities)
+ peer_capab |= TDLS_PEER_HT;
+ else if (peer->wmm_capable)
+ peer_capab |= TDLS_PEER_WMM;
+
skip_ies:
status = wpa_tdls_tpk_send(sm, src_addr, WLAN_TDLS_SETUP_CONFIRM,
- dtoken, 0, rbuf, pos - rbuf);
+ dtoken, 0, peer_capab, rbuf, pos - rbuf);
os_free(rbuf);
return status;
@@ -1283,7 +1299,7 @@ static int wpa_tdls_send_discovery_response(struct wpa_sm *sm,
"(peer " MACSTR ")", MAC2STR(peer->addr));
return wpa_tdls_tpk_send(sm, peer->addr, WLAN_TDLS_DISCOVERY_RESPONSE,
- dialog_token, 0, NULL, 0);
+ dialog_token, 0, 0, NULL, 0);
}
@@ -1344,7 +1360,7 @@ int wpa_tdls_send_discovery_request(struct wpa_sm *sm, const u8 *addr)
wpa_printf(MSG_DEBUG, "TDLS: Sending Discovery Request to peer "
MACSTR, MAC2STR(addr));
return wpa_tdls_tpk_send(sm, addr, WLAN_TDLS_DISCOVERY_REQUEST,
- 1, 0, NULL, 0);
+ 1, 0, 0, NULL, 0);
}
@@ -1462,6 +1478,8 @@ static int copy_peer_wmm_capab(const struct wpa_eapol_ie_parse *kde,
wmm = (struct wmm_information_element *) kde->wmm;
peer->qos_info = wmm->qos_info;
+ peer->wmm_capable = 1;
+
wpa_printf(MSG_DEBUG, "TDLS: Peer WMM QOS Info 0x%x", peer->qos_info);
return 0;
}
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index f5ee76c3..50762335 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -54,7 +54,8 @@ struct wpa_sm_ctx {
int *tdls_ext_setup);
int (*send_tdls_mgmt)(void *ctx, const u8 *dst,
u8 action_code, u8 dialog_token,
- u16 status_code, const u8 *buf, size_t len);
+ u16 status_code, u32 peer_capab,
+ const u8 *buf, size_t len);
int (*tdls_oper)(void *ctx, int oper, const u8 *peer);
int (*tdls_peer_addset)(void *ctx, const u8 *addr, int add, u16 aid,
u16 capability, const u8 *supp_rates,
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index cad6c8d9..2ee8bc75 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -262,13 +262,13 @@ static inline int wpa_sm_tdls_get_capa(struct wpa_sm *sm,
static inline int wpa_sm_send_tdls_mgmt(struct wpa_sm *sm, const u8 *dst,
u8 action_code, u8 dialog_token,
- u16 status_code, const u8 *buf,
- size_t len)
+ u16 status_code, u32 peer_capab,
+ const u8 *buf, size_t len)
{
if (sm->ctx->send_tdls_mgmt)
return sm->ctx->send_tdls_mgmt(sm->ctx->ctx, dst, action_code,
dialog_token, status_code,
- buf, len);
+ peer_capab, buf, len);
return -1;
}
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index 5e7dbf73..d7368e13 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -647,12 +647,14 @@ static inline int wpa_drv_p2p_invite(struct wpa_supplicant *wpa_s,
static inline int wpa_drv_send_tdls_mgmt(struct wpa_supplicant *wpa_s,
const u8 *dst, u8 action_code,
u8 dialog_token, u16 status_code,
- const u8 *buf, size_t len)
+ u32 peer_capab, const u8 *buf,
+ size_t len)
{
if (wpa_s->driver->send_tdls_mgmt) {
return wpa_s->driver->send_tdls_mgmt(wpa_s->drv_priv, dst,
action_code, dialog_token,
- status_code, buf, len);
+ status_code, peer_capab,
+ buf, len);
}
return -1;
}
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index 19616221..40c7655e 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -539,12 +539,12 @@ static int wpa_supplicant_tdls_get_capa(void *ctx, int *tdls_supported,
static int wpa_supplicant_send_tdls_mgmt(void *ctx, const u8 *dst,
u8 action_code, u8 dialog_token,
- u16 status_code, const u8 *buf,
- size_t len)
+ u16 status_code, u32 peer_capab,
+ const u8 *buf, size_t len)
{
struct wpa_supplicant *wpa_s = ctx;
return wpa_drv_send_tdls_mgmt(wpa_s, dst, action_code, dialog_token,
- status_code, buf, len);
+ status_code, peer_capab, buf, len);
}