Pass TDLS peer capability information in tdls_mgmt

While framing the TDLS Setup Confirmation frame, the driver needs to
know if the TDLS peer is VHT/HT/WMM capable and thus shall construct the
VHT/HT operation / WMM parameter elements accordingly. Supplicant
determines if the TDLS peer is VHT/HT/WMM capable based on the presence
of the respective IEs in the received TDLS Setup Response frame.

The host driver should not need to parse the received TDLS Response
frame and thus, should be able to rely on the supplicant to indicate
the capability of the peer through additional flags while transmitting
the TDLS Setup Confirmation frame through tdls_mgmt operations.

Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
Sunil Dutt 2014-03-26 21:34:50 +05:30 committed by Jouni Malinen
parent 78cd7e69de
commit 96ecea5eb1
7 changed files with 60 additions and 22 deletions

View file

@ -1269,6 +1269,13 @@ struct csa_settings {
u16 counter_offset_presp; u16 counter_offset_presp;
}; };
/* 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 * struct wpa_driver_ops - Driver interface API definition
* *
@ -2449,6 +2456,7 @@ struct wpa_driver_ops {
* @action_code: TDLS action code for the mssage * @action_code: TDLS action code for the mssage
* @dialog_token: Dialog Token to use in the message (if needed) * @dialog_token: Dialog Token to use in the message (if needed)
* @status_code: Status Code or Reason Code to use (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 * @buf: TDLS IEs to add to the message
* @len: Length of buf in octets * @len: Length of buf in octets
* Returns: 0 on success, negative (<0) on failure * Returns: 0 on success, negative (<0) on failure
@ -2457,7 +2465,7 @@ struct wpa_driver_ops {
* responsible for receiving and sending all TDLS packets. * responsible for receiving and sending all TDLS packets.
*/ */
int (*send_tdls_mgmt)(void *priv, const u8 *dst, u8 action_code, 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); const u8 *buf, size_t len);
/** /**

View file

@ -11222,7 +11222,7 @@ nla_put_failure:
static int nl80211_send_tdls_mgmt(void *priv, const u8 *dst, u8 action_code, static int nl80211_send_tdls_mgmt(void *priv, const u8 *dst, u8 action_code,
u8 dialog_token, u16 status_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 i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv; struct wpa_driver_nl80211_data *drv = bss->drv;
@ -11244,6 +11244,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_ACTION, action_code);
NLA_PUT_U8(msg, NL80211_ATTR_TDLS_DIALOG_TOKEN, dialog_token); NLA_PUT_U8(msg, NL80211_ATTR_TDLS_DIALOG_TOKEN, dialog_token);
NLA_PUT_U16(msg, NL80211_ATTR_STATUS_CODE, status_code); 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); NLA_PUT(msg, NL80211_ATTR_IE, len, buf);
return send_and_recv_msgs(drv, msg, NULL, NULL); return send_and_recv_msgs(drv, msg, NULL, NULL);

View file

@ -118,6 +118,7 @@ struct wpa_tdls_peer {
u8 action_code; /* TDLS frame type */ u8 action_code; /* TDLS frame type */
u8 dialog_token; u8 dialog_token;
u16 status_code; u16 status_code;
u32 peer_capab;
int buf_len; /* length of TPK message for retransmission */ int buf_len; /* length of TPK message for retransmission */
u8 *buf; /* buffer for TPK message */ u8 *buf; /* buffer for TPK message */
} sm_tmr; } sm_tmr;
@ -142,6 +143,8 @@ struct wpa_tdls_peer {
u8 *supp_oper_classes; u8 *supp_oper_classes;
size_t supp_oper_classes_len; 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, static int wpa_tdls_send_tpk_msg(struct wpa_sm *sm, const u8 *dst,
u8 action_code, u8 dialog_token, 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, 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, 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) const u8 *msg, size_t msg_len)
{ {
struct wpa_tdls_peer *peer; 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); (unsigned int) msg_len);
if (wpa_tdls_send_tpk_msg(sm, dest, action_code, dialog_token, 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 " wpa_printf(MSG_INFO, "TDLS: Failed to send message "
"(action_code=%u)", action_code); "(action_code=%u)", action_code);
return -1; 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.action_code = action_code;
peer->sm_tmr.dialog_token = dialog_token; peer->sm_tmr.dialog_token = dialog_token;
peer->sm_tmr.status_code = status_code; peer->sm_tmr.status_code = status_code;
peer->sm_tmr.peer_capab = peer_capab;
peer->sm_tmr.buf_len = msg_len; peer->sm_tmr.buf_len = msg_len;
os_free(peer->sm_tmr.buf); os_free(peer->sm_tmr.buf);
peer->sm_tmr.buf = os_malloc(msg_len); 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.action_code,
peer->sm_tmr.dialog_token, peer->sm_tmr.dialog_token,
peer->sm_tmr.status_code, peer->sm_tmr.status_code,
peer->sm_tmr.peer_capab,
peer->sm_tmr.buf, peer->sm_tmr.buf,
peer->sm_tmr.buf_len)) { peer->sm_tmr.buf_len)) {
wpa_printf(MSG_INFO, "TDLS: Failed to retry " 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->supp_oper_classes = NULL;
peer->rsnie_i_len = peer->rsnie_p_len = 0; peer->rsnie_i_len = peer->rsnie_p_len = 0;
peer->cipher = 0; peer->cipher = 0;
peer->qos_info = 0;
peer->wmm_capable = 0;
peer->tpk_set = peer->tpk_success = 0; peer->tpk_set = peer->tpk_success = 0;
os_memset(&peer->tpk, 0, sizeof(peer->tpk)); os_memset(&peer->tpk, 0, sizeof(peer->tpk));
os_memset(peer->inonce, 0, WPA_NONCE_LEN); os_memset(peer->inonce, 0, WPA_NONCE_LEN);
@ -747,7 +755,7 @@ skip_ies:
/* request driver to send Teardown using this FTIE */ /* request driver to send Teardown using this FTIE */
wpa_tdls_tpk_send(sm, addr, WLAN_TDLS_TEARDOWN, 0, wpa_tdls_tpk_send(sm, addr, WLAN_TDLS_TEARDOWN, 0,
reason_code, rbuf, pos - rbuf); reason_code, 0, rbuf, pos - rbuf);
os_free(rbuf); os_free(rbuf);
/* clear the Peerkey statemachine */ /* clear the Peerkey statemachine */
@ -918,7 +926,7 @@ static int wpa_tdls_send_error(struct wpa_sm *sm, const u8 *dst,
" (action=%u status=%u)", " (action=%u status=%u)",
MAC2STR(dst), tdls_action, status); MAC2STR(dst), tdls_action, status);
return wpa_tdls_tpk_send(sm, dst, tdls_action, dialog_token, status, return wpa_tdls_tpk_send(sm, dst, tdls_action, dialog_token, status,
NULL, 0); 0, NULL, 0);
} }
@ -1124,7 +1132,7 @@ skip_ies:
MAC2STR(peer->addr)); MAC2STR(peer->addr));
status = wpa_tdls_tpk_send(sm, peer->addr, WLAN_TDLS_SETUP_REQUEST, 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); os_free(rbuf);
return status; return status;
@ -1208,7 +1216,7 @@ static int wpa_tdls_send_tpk_m2(struct wpa_sm *sm,
skip_ies: skip_ies:
status = wpa_tdls_tpk_send(sm, src_addr, WLAN_TDLS_SETUP_RESPONSE, 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); os_free(rbuf);
return status; return status;
@ -1226,6 +1234,7 @@ static int wpa_tdls_send_tpk_m3(struct wpa_sm *sm,
struct wpa_tdls_timeoutie timeoutie; struct wpa_tdls_timeoutie timeoutie;
u32 lifetime; u32 lifetime;
int status; int status;
u32 peer_capab = 0;
buf_len = 0; buf_len = 0;
if (wpa_tdls_get_privacy(sm)) { if (wpa_tdls_get_privacy(sm)) {
@ -1288,9 +1297,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, wpa_tdls_ftie_mic(peer->tpk.kck, 3, (u8 *) lnkid, peer->rsnie_p,
(u8 *) &timeoutie, (u8 *) ftie, ftie->mic); (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: skip_ies:
status = wpa_tdls_tpk_send(sm, src_addr, WLAN_TDLS_SETUP_CONFIRM, 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); os_free(rbuf);
return status; return status;
@ -1305,7 +1321,7 @@ static int wpa_tdls_send_discovery_response(struct wpa_sm *sm,
"(peer " MACSTR ")", MAC2STR(peer->addr)); "(peer " MACSTR ")", MAC2STR(peer->addr));
return wpa_tdls_tpk_send(sm, peer->addr, WLAN_TDLS_DISCOVERY_RESPONSE, return wpa_tdls_tpk_send(sm, peer->addr, WLAN_TDLS_DISCOVERY_RESPONSE,
dialog_token, 0, NULL, 0); dialog_token, 0, 0, NULL, 0);
} }
@ -1366,7 +1382,7 @@ int wpa_tdls_send_discovery_request(struct wpa_sm *sm, const u8 *addr)
wpa_printf(MSG_DEBUG, "TDLS: Sending Discovery Request to peer " wpa_printf(MSG_DEBUG, "TDLS: Sending Discovery Request to peer "
MACSTR, MAC2STR(addr)); MACSTR, MAC2STR(addr));
return wpa_tdls_tpk_send(sm, addr, WLAN_TDLS_DISCOVERY_REQUEST, return wpa_tdls_tpk_send(sm, addr, WLAN_TDLS_DISCOVERY_REQUEST,
1, 0, NULL, 0); 1, 0, 0, NULL, 0);
} }
@ -1484,6 +1500,8 @@ static int copy_peer_wmm_capab(const struct wpa_eapol_ie_parse *kde,
wmm = (struct wmm_information_element *) kde->wmm; wmm = (struct wmm_information_element *) kde->wmm;
peer->qos_info = wmm->qos_info; peer->qos_info = wmm->qos_info;
peer->wmm_capable = 1;
wpa_printf(MSG_DEBUG, "TDLS: Peer WMM QOS Info 0x%x", peer->qos_info); wpa_printf(MSG_DEBUG, "TDLS: Peer WMM QOS Info 0x%x", peer->qos_info);
return 0; return 0;
} }

View file

@ -54,7 +54,8 @@ struct wpa_sm_ctx {
int *tdls_ext_setup); int *tdls_ext_setup);
int (*send_tdls_mgmt)(void *ctx, const u8 *dst, int (*send_tdls_mgmt)(void *ctx, const u8 *dst,
u8 action_code, u8 dialog_token, 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_oper)(void *ctx, int oper, const u8 *peer);
int (*tdls_peer_addset)(void *ctx, const u8 *addr, int add, u16 aid, int (*tdls_peer_addset)(void *ctx, const u8 *addr, int add, u16 aid,
u16 capability, const u8 *supp_rates, u16 capability, const u8 *supp_rates,

View file

@ -267,13 +267,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, static inline int wpa_sm_send_tdls_mgmt(struct wpa_sm *sm, const u8 *dst,
u8 action_code, u8 dialog_token, u8 action_code, u8 dialog_token,
u16 status_code, const u8 *buf, u16 status_code, u32 peer_capab,
size_t len) const u8 *buf, size_t len)
{ {
if (sm->ctx->send_tdls_mgmt) if (sm->ctx->send_tdls_mgmt)
return sm->ctx->send_tdls_mgmt(sm->ctx->ctx, dst, action_code, return sm->ctx->send_tdls_mgmt(sm->ctx->ctx, dst, action_code,
dialog_token, status_code, dialog_token, status_code,
buf, len); peer_capab, buf, len);
return -1; return -1;
} }

View file

@ -532,12 +532,14 @@ static inline int wpa_drv_ampdu(struct wpa_supplicant *wpa_s, int ampdu)
static inline int wpa_drv_send_tdls_mgmt(struct wpa_supplicant *wpa_s, static inline int wpa_drv_send_tdls_mgmt(struct wpa_supplicant *wpa_s,
const u8 *dst, u8 action_code, const u8 *dst, u8 action_code,
u8 dialog_token, u16 status_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) { if (wpa_s->driver->send_tdls_mgmt) {
return wpa_s->driver->send_tdls_mgmt(wpa_s->drv_priv, dst, return wpa_s->driver->send_tdls_mgmt(wpa_s->drv_priv, dst,
action_code, dialog_token, action_code, dialog_token,
status_code, buf, len); status_code, peer_capab,
buf, len);
} }
return -1; return -1;
} }

View file

@ -558,12 +558,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, static int wpa_supplicant_send_tdls_mgmt(void *ctx, const u8 *dst,
u8 action_code, u8 dialog_token, u8 action_code, u8 dialog_token,
u16 status_code, const u8 *buf, u16 status_code, u32 peer_capab,
size_t len) const u8 *buf, size_t len)
{ {
struct wpa_supplicant *wpa_s = ctx; struct wpa_supplicant *wpa_s = ctx;
return wpa_drv_send_tdls_mgmt(wpa_s, dst, action_code, dialog_token, return wpa_drv_send_tdls_mgmt(wpa_s, dst, action_code, dialog_token,
status_code, buf, len); status_code, peer_capab, buf, len);
} }