TDLS: Allow unencrypted network negotiation through wpa_supplicant
This allows the same code path to be used for both protected and unprotected configurations to limit need for duplicated code in both the driver and wpa_supplicant.
This commit is contained in:
parent
9fe6e4b4db
commit
2e1d335e44
1 changed files with 292 additions and 236 deletions
|
@ -77,8 +77,6 @@ struct wpa_tdls_frame {
|
||||||
u8 action; /* Action (enum tdls_frame_type) */
|
u8 action; /* Action (enum tdls_frame_type) */
|
||||||
} STRUCT_PACKED;
|
} STRUCT_PACKED;
|
||||||
|
|
||||||
#define TDLS_FRAME_TYPE(tf) (((struct wpa_tdls_frame *) tf)->action)
|
|
||||||
|
|
||||||
static u8 * wpa_add_tdls_timeoutie(u8 *pos, u8 *ie, size_t ie_len, u32 tsecs);
|
static u8 * wpa_add_tdls_timeoutie(u8 *pos, u8 *ie, size_t ie_len, u32 tsecs);
|
||||||
static void wpa_tdls_smkretry_timeout(void *eloop_ctx, void *timeout_ctx);
|
static void wpa_tdls_smkretry_timeout(void *eloop_ctx, void *timeout_ctx);
|
||||||
static void wpa_tdls_peer_free(struct wpa_sm *sm, struct wpa_tdls_peer *peer);
|
static void wpa_tdls_peer_free(struct wpa_sm *sm, struct wpa_tdls_peer *peer);
|
||||||
|
@ -107,6 +105,7 @@ struct wpa_tdls_peer {
|
||||||
u8 tk[16]; /* TPK-TK; assuming only CCMP will be used */
|
u8 tk[16]; /* TPK-TK; assuming only CCMP will be used */
|
||||||
} tpk;
|
} tpk;
|
||||||
int tpk_set;
|
int tpk_set;
|
||||||
|
int tpk_success;
|
||||||
|
|
||||||
struct smk_timer {
|
struct smk_timer {
|
||||||
u8 dest[ETH_ALEN];
|
u8 dest[ETH_ALEN];
|
||||||
|
@ -122,6 +121,17 @@ struct wpa_tdls_peer {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static int wpa_tdls_get_privacy(struct wpa_sm *sm)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Get info needed from supplicant to check if the current BSS supports
|
||||||
|
* security. Other than OPEN mode, rest are considered secured
|
||||||
|
* WEP/WPA/WPA2 hence TDLS frames are processed for TPK handshake.
|
||||||
|
*/
|
||||||
|
return sm->pairwise_cipher != WPA_CIPHER_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static u8 * wpa_add_ie(u8 *pos, const u8 *ie, size_t ie_len)
|
static u8 * wpa_add_ie(u8 *pos, const u8 *ie, size_t ie_len)
|
||||||
{
|
{
|
||||||
os_memcpy(pos, ie, ie_len);
|
os_memcpy(pos, ie, ie_len);
|
||||||
|
@ -609,6 +619,7 @@ int wpa_tdls_recv_teardown_notify(struct wpa_sm *sm, const u8 *addr,
|
||||||
u8 dialogue_token = 0;
|
u8 dialogue_token = 0;
|
||||||
u8 *rbuf;
|
u8 *rbuf;
|
||||||
int ielen;
|
int ielen;
|
||||||
|
u8 *pos;
|
||||||
|
|
||||||
/* Find the node and free from the list */
|
/* Find the node and free from the list */
|
||||||
for (peer = sm->tdls; peer; peer = peer->next) {
|
for (peer = sm->tdls; peer; peer = peer->next) {
|
||||||
|
@ -629,26 +640,33 @@ int wpa_tdls_recv_teardown_notify(struct wpa_sm *sm, const u8 *addr,
|
||||||
wpa_printf(MSG_DEBUG, "RSN: TDLS Teardown for " MACSTR,
|
wpa_printf(MSG_DEBUG, "RSN: TDLS Teardown for " MACSTR,
|
||||||
MAC2STR(addr));
|
MAC2STR(addr));
|
||||||
|
|
||||||
/* To add FTIE for Teardown request and compute MIC */
|
ielen = 0;
|
||||||
ielen = sizeof(*ftie);
|
if (wpa_tdls_get_privacy(sm) && peer->tpk_set && peer->tpk_success) {
|
||||||
|
/* To add FTIE for Teardown request and compute MIC */
|
||||||
|
ielen += sizeof(*ftie);
|
||||||
#ifdef CONFIG_TDLS_TESTING
|
#ifdef CONFIG_TDLS_TESTING
|
||||||
if (tdls_testing & TDLS_TESTING_LONG_FRAME)
|
if (tdls_testing & TDLS_TESTING_LONG_FRAME)
|
||||||
ielen += 170;
|
ielen += 170;
|
||||||
#endif /* CONFIG_TDLS_TESTING */
|
#endif /* CONFIG_TDLS_TESTING */
|
||||||
|
}
|
||||||
|
|
||||||
rbuf = os_zalloc(ielen);
|
rbuf = os_zalloc(ielen + 1);
|
||||||
if (rbuf == NULL)
|
if (rbuf == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
pos = rbuf;
|
||||||
|
|
||||||
ftie = (struct wpa_tdls_ftie *) rbuf;
|
if (!wpa_tdls_get_privacy(sm) || !peer->tpk_set || !peer->tpk_success)
|
||||||
|
goto skip_ies;
|
||||||
|
|
||||||
|
ftie = (struct wpa_tdls_ftie *) pos;
|
||||||
ftie->ie_type = WLAN_EID_FAST_BSS_TRANSITION;
|
ftie->ie_type = WLAN_EID_FAST_BSS_TRANSITION;
|
||||||
/* Using the recent nonce which should be for CONFIRM frame */
|
/* Using the recent nonce which should be for CONFIRM frame */
|
||||||
os_memcpy(ftie->Anonce, peer->pnonce, WPA_NONCE_LEN);
|
os_memcpy(ftie->Anonce, peer->pnonce, WPA_NONCE_LEN);
|
||||||
os_memcpy(ftie->Snonce, peer->inonce, WPA_NONCE_LEN);
|
os_memcpy(ftie->Snonce, peer->inonce, WPA_NONCE_LEN);
|
||||||
ftie->ie_len = sizeof(struct wpa_tdls_ftie) - 2;
|
ftie->ie_len = sizeof(struct wpa_tdls_ftie) - 2;
|
||||||
|
pos = (u8 *) (ftie + 1);
|
||||||
#ifdef CONFIG_TDLS_TESTING
|
#ifdef CONFIG_TDLS_TESTING
|
||||||
if (tdls_testing & TDLS_TESTING_LONG_FRAME) {
|
if (tdls_testing & TDLS_TESTING_LONG_FRAME) {
|
||||||
u8 *pos = (u8 *) (ftie + 1);
|
|
||||||
wpa_printf(MSG_DEBUG, "TDLS: Testing - add extra subelem to "
|
wpa_printf(MSG_DEBUG, "TDLS: Testing - add extra subelem to "
|
||||||
"FTIE");
|
"FTIE");
|
||||||
ftie->ie_len += 170;
|
ftie->ie_len += 170;
|
||||||
|
@ -664,12 +682,14 @@ int wpa_tdls_recv_teardown_notify(struct wpa_sm *sm, const u8 *addr,
|
||||||
dialogue_token, (u8 *) lnkid, (u8 *) ftie,
|
dialogue_token, (u8 *) lnkid, (u8 *) ftie,
|
||||||
ftie->mic);
|
ftie->mic);
|
||||||
|
|
||||||
|
skip_ies:
|
||||||
/* TODO: register for a Timeout handler, if Teardown is not received at
|
/* TODO: register for a Timeout handler, if Teardown is not received at
|
||||||
* the other end, then try again another time */
|
* the other end, then try again another time */
|
||||||
|
|
||||||
/* request driver to send Teardown using this FTIE */
|
/* request driver to send Teardown using this FTIE */
|
||||||
wpa_tdls_smk_send(sm, addr, WLAN_TDLS_TEARDOWN, 0,
|
wpa_tdls_smk_send(sm, addr, WLAN_TDLS_TEARDOWN, 0,
|
||||||
WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED, rbuf, ielen);
|
WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED, rbuf,
|
||||||
|
pos - rbuf);
|
||||||
os_free(rbuf);
|
os_free(rbuf);
|
||||||
|
|
||||||
/* clear the Peerkey statemachine */
|
/* clear the Peerkey statemachine */
|
||||||
|
@ -680,14 +700,13 @@ int wpa_tdls_recv_teardown_notify(struct wpa_sm *sm, const u8 *addr,
|
||||||
|
|
||||||
|
|
||||||
static int wpa_tdls_recv_teardown(struct wpa_sm *sm, const u8 *src_addr,
|
static int wpa_tdls_recv_teardown(struct wpa_sm *sm, const u8 *src_addr,
|
||||||
const u8 *buf, u16 len)
|
const u8 *buf, size_t len)
|
||||||
{
|
{
|
||||||
struct wpa_tdls_peer *peer = NULL;
|
struct wpa_tdls_peer *peer = NULL;
|
||||||
struct wpa_tdls_ftie *ftie;
|
struct wpa_tdls_ftie *ftie;
|
||||||
struct wpa_tdls_lnkid *lnkid;
|
struct wpa_tdls_lnkid *lnkid;
|
||||||
struct wpa_eapol_ie_parse kde;
|
struct wpa_eapol_ie_parse kde;
|
||||||
u16 reason_code = 0;
|
u16 reason_code;
|
||||||
u8 dialogue_token = 0;
|
|
||||||
const u8 *pos;
|
const u8 *pos;
|
||||||
int ielen;
|
int ielen;
|
||||||
|
|
||||||
|
@ -703,20 +722,14 @@ static int wpa_tdls_recv_teardown(struct wpa_sm *sm, const u8 *src_addr,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buf == NULL) {
|
|
||||||
wpa_printf(MSG_INFO, "TDLS: No message delivered for "
|
|
||||||
"wpa_tdls_recv_teardown?!");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
pos = buf;
|
pos = buf;
|
||||||
pos += 1 /* pkt_type */ + 1 /* Category */ + 1 /* Action */;
|
pos += 1 /* pkt_type */ + 1 /* Category */ + 1 /* Action */;
|
||||||
|
|
||||||
reason_code = WPA_GET_LE16(pos);
|
reason_code = WPA_GET_LE16(pos);
|
||||||
pos += 2;
|
pos += 2;
|
||||||
|
|
||||||
wpa_printf(MSG_INFO, "TDLS: Reason code in Teardown rcode %d",
|
wpa_printf(MSG_DEBUG, "TDLS: TDLS Teardown Request from " MACSTR
|
||||||
reason_code);
|
" (reason code %u)", MAC2STR(src_addr), reason_code);
|
||||||
|
|
||||||
ielen = len - (pos - buf); /* start of IE in buf */
|
ielen = len - (pos - buf); /* start of IE in buf */
|
||||||
if (wpa_supplicant_parse_ies((const u8 *) pos, ielen, &kde) < 0) {
|
if (wpa_supplicant_parse_ies((const u8 *) pos, ielen, &kde) < 0) {
|
||||||
|
@ -724,33 +737,40 @@ static int wpa_tdls_recv_teardown(struct wpa_sm *sm, const u8 *src_addr,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kde.ftie == NULL) {
|
|
||||||
wpa_printf(MSG_INFO, "TDLS: No FTIE in TDLS Teardown");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (kde.lnkid == NULL || kde.lnkid_len < 3 * ETH_ALEN) {
|
if (kde.lnkid == NULL || kde.lnkid_len < 3 * ETH_ALEN) {
|
||||||
wpa_printf(MSG_INFO, "TDLS: No Link Identifier IE in TDLS "
|
wpa_printf(MSG_INFO, "TDLS: No Link Identifier IE in TDLS "
|
||||||
"Teardown");
|
"Teardown");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
lnkid = (struct wpa_tdls_lnkid *) kde.lnkid;
|
||||||
|
|
||||||
|
if (!wpa_tdls_get_privacy(sm) || !peer->tpk_set || !peer->tpk_success)
|
||||||
|
goto skip_ftie;
|
||||||
|
|
||||||
|
if (kde.ftie == NULL) {
|
||||||
|
wpa_printf(MSG_INFO, "TDLS: No FTIE in TDLS Teardown");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
ftie = (struct wpa_tdls_ftie *) kde.ftie;
|
ftie = (struct wpa_tdls_ftie *) kde.ftie;
|
||||||
lnkid = (struct wpa_tdls_lnkid *) kde.lnkid;
|
|
||||||
dialogue_token = peer->dtoken; /* used for TDLS handshake */
|
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "RSN: TDLS Teardown Request from " MACSTR,
|
|
||||||
MAC2STR(src_addr));
|
|
||||||
|
|
||||||
/* Process MIC check to see if TDLS Teardown is right */
|
/* Process MIC check to see if TDLS Teardown is right */
|
||||||
if (wpa_supplicant_verify_tdls_mic_teardown(4, reason_code,
|
if (wpa_supplicant_verify_tdls_mic_teardown(4, reason_code,
|
||||||
dialogue_token, peer,
|
peer->dtoken, peer,
|
||||||
(u8 *) lnkid, ftie) < 0) {
|
(u8 *) lnkid, ftie) < 0) {
|
||||||
wpa_printf(MSG_DEBUG, "RSN: MIC failure for TDLS "
|
wpa_printf(MSG_DEBUG, "TDLS: MIC failure for TDLS "
|
||||||
"Teardown Request from " MACSTR,
|
"Teardown Request from " MACSTR, MAC2STR(src_addr));
|
||||||
MAC2STR(src_addr));
|
#if 0
|
||||||
//return -1;
|
return -1;
|
||||||
|
#else
|
||||||
|
/* TODO: figure out whether this workaround could be disabled
|
||||||
|
*/
|
||||||
|
wpa_printf(MSG_DEBUG, "TDLS: Workaround - ignore Teardown MIC "
|
||||||
|
"failure");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
skip_ftie:
|
||||||
/*
|
/*
|
||||||
* Request the driver to disable the direct link and clear associated
|
* Request the driver to disable the direct link and clear associated
|
||||||
* keys.
|
* keys.
|
||||||
|
@ -786,24 +806,30 @@ static int wpa_tdls_send_tpk_m2(struct wpa_sm *sm,
|
||||||
const struct wpa_tdls_peer *peer)
|
const struct wpa_tdls_peer *peer)
|
||||||
{
|
{
|
||||||
u8 *rbuf, *pos;
|
u8 *rbuf, *pos;
|
||||||
u16 kde_len;
|
size_t buf_len;
|
||||||
u32 lifetime = 0;
|
u32 lifetime;
|
||||||
struct wpa_tdls_timeoutie timeoutie;
|
struct wpa_tdls_timeoutie timeoutie;
|
||||||
struct wpa_tdls_ftie *ftie;
|
struct wpa_tdls_ftie *ftie;
|
||||||
|
|
||||||
/* Peer RSN IE, FTIE(Initiator Nonce, Peer nonce), Lifetime */
|
buf_len = 0;
|
||||||
kde_len = peer->rsnie_i_len + sizeof(struct wpa_tdls_ftie) +
|
if (wpa_tdls_get_privacy(sm)) {
|
||||||
sizeof(struct wpa_tdls_timeoutie);
|
/* Peer RSN IE, FTIE(Initiator Nonce, Peer nonce), Lifetime */
|
||||||
|
buf_len += peer->rsnie_i_len + sizeof(struct wpa_tdls_ftie) +
|
||||||
|
sizeof(struct wpa_tdls_timeoutie);
|
||||||
#ifdef CONFIG_TDLS_TESTING
|
#ifdef CONFIG_TDLS_TESTING
|
||||||
if (tdls_testing & TDLS_TESTING_LONG_FRAME)
|
if (tdls_testing & TDLS_TESTING_LONG_FRAME)
|
||||||
kde_len += 170;
|
buf_len += 170;
|
||||||
#endif /* CONFIG_TDLS_TESTING */
|
#endif /* CONFIG_TDLS_TESTING */
|
||||||
|
}
|
||||||
|
|
||||||
rbuf = os_zalloc(kde_len);
|
rbuf = os_zalloc(buf_len + 1);
|
||||||
if (rbuf == NULL)
|
if (rbuf == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
pos = rbuf;
|
pos = rbuf;
|
||||||
|
|
||||||
|
if (!wpa_tdls_get_privacy(sm))
|
||||||
|
goto skip_ies;
|
||||||
|
|
||||||
/* Peer RSN IE */
|
/* Peer RSN IE */
|
||||||
pos = wpa_add_ie(pos, peer->rsnie_p, peer->rsnie_p_len);
|
pos = wpa_add_ie(pos, peer->rsnie_p, peer->rsnie_p_len);
|
||||||
|
|
||||||
|
@ -847,8 +873,9 @@ static int wpa_tdls_send_tpk_m2(struct wpa_sm *sm,
|
||||||
wpa_tdls_ftie_mic(peer->tpk.kck, 2, (u8 *) lnkid, peer->rsnie_p,
|
wpa_tdls_ftie_mic(peer->tpk.kck, 2, (u8 *) lnkid, peer->rsnie_p,
|
||||||
(u8 *) &timeoutie, (u8 *) ftie, ftie->mic);
|
(u8 *) &timeoutie, (u8 *) ftie, ftie->mic);
|
||||||
|
|
||||||
|
skip_ies:
|
||||||
wpa_tdls_smk_send(sm, src_addr, WLAN_TDLS_SETUP_RESPONSE, dtoken, 0,
|
wpa_tdls_smk_send(sm, src_addr, WLAN_TDLS_SETUP_RESPONSE, dtoken, 0,
|
||||||
rbuf, kde_len);
|
rbuf, pos - rbuf);
|
||||||
os_free(rbuf);
|
os_free(rbuf);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -861,24 +888,30 @@ static int wpa_tdls_send_tpk_m3(struct wpa_sm *sm,
|
||||||
const struct wpa_tdls_peer *peer)
|
const struct wpa_tdls_peer *peer)
|
||||||
{
|
{
|
||||||
u8 *rbuf, *pos;
|
u8 *rbuf, *pos;
|
||||||
u16 kde_len;
|
size_t buf_len;
|
||||||
struct wpa_tdls_ftie *ftie;
|
struct wpa_tdls_ftie *ftie;
|
||||||
struct wpa_tdls_timeoutie timeoutie;
|
struct wpa_tdls_timeoutie timeoutie;
|
||||||
u32 lifetime;
|
u32 lifetime;
|
||||||
|
|
||||||
/* Peer RSN IE, FTIE(Initiator Nonce, Peer nonce), Lifetime */
|
buf_len = 0;
|
||||||
kde_len = peer->rsnie_i_len + sizeof(struct wpa_tdls_ftie) +
|
if (wpa_tdls_get_privacy(sm)) {
|
||||||
sizeof(struct wpa_tdls_timeoutie);
|
/* Peer RSN IE, FTIE(Initiator Nonce, Peer nonce), Lifetime */
|
||||||
|
buf_len += peer->rsnie_i_len + sizeof(struct wpa_tdls_ftie) +
|
||||||
|
sizeof(struct wpa_tdls_timeoutie);
|
||||||
#ifdef CONFIG_TDLS_TESTING
|
#ifdef CONFIG_TDLS_TESTING
|
||||||
if (tdls_testing & TDLS_TESTING_LONG_FRAME)
|
if (tdls_testing & TDLS_TESTING_LONG_FRAME)
|
||||||
kde_len += 170;
|
buf_len += 170;
|
||||||
#endif /* CONFIG_TDLS_TESTING */
|
#endif /* CONFIG_TDLS_TESTING */
|
||||||
|
}
|
||||||
|
|
||||||
rbuf = os_zalloc(kde_len);
|
rbuf = os_zalloc(buf_len + 1);
|
||||||
if (rbuf == NULL)
|
if (rbuf == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
pos = rbuf;
|
pos = rbuf;
|
||||||
|
|
||||||
|
if (!wpa_tdls_get_privacy(sm))
|
||||||
|
goto skip_ies;
|
||||||
|
|
||||||
/* Peer RSN IE */
|
/* Peer RSN IE */
|
||||||
pos = wpa_add_ie(pos, peer->rsnie_p, peer->rsnie_p_len);
|
pos = wpa_add_ie(pos, peer->rsnie_p, peer->rsnie_p_len);
|
||||||
|
|
||||||
|
@ -920,8 +953,9 @@ 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);
|
||||||
|
|
||||||
|
skip_ies:
|
||||||
wpa_tdls_smk_send(sm, src_addr, WLAN_TDLS_SETUP_CONFIRM, dtoken, 0,
|
wpa_tdls_smk_send(sm, src_addr, WLAN_TDLS_SETUP_CONFIRM, dtoken, 0,
|
||||||
rbuf, kde_len);
|
rbuf, pos - rbuf);
|
||||||
os_free(rbuf);
|
os_free(rbuf);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -929,14 +963,14 @@ static int wpa_tdls_send_tpk_m3(struct wpa_sm *sm,
|
||||||
|
|
||||||
|
|
||||||
static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
|
static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
|
||||||
const u8 *buf, u16 len)
|
const u8 *buf, size_t len)
|
||||||
{
|
{
|
||||||
struct wpa_tdls_peer *peer;
|
struct wpa_tdls_peer *peer;
|
||||||
struct wpa_eapol_ie_parse kde;
|
struct wpa_eapol_ie_parse kde;
|
||||||
struct wpa_ie_data ie;
|
struct wpa_ie_data ie;
|
||||||
int cipher;
|
int cipher;
|
||||||
const u8 *cpos;
|
const u8 *cpos;
|
||||||
struct wpa_tdls_ftie *ftie;
|
struct wpa_tdls_ftie *ftie = NULL;
|
||||||
struct wpa_tdls_timeoutie *timeoutie;
|
struct wpa_tdls_timeoutie *timeoutie;
|
||||||
struct wpa_tdls_lnkid *lnkid;
|
struct wpa_tdls_lnkid *lnkid;
|
||||||
u32 lifetime = 0;
|
u32 lifetime = 0;
|
||||||
|
@ -949,12 +983,6 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
|
||||||
u8 dtoken;
|
u8 dtoken;
|
||||||
u16 ielen;
|
u16 ielen;
|
||||||
|
|
||||||
if (buf == NULL) {
|
|
||||||
wpa_printf(MSG_INFO, "TDLS: No message delivered for "
|
|
||||||
"wpa_tdls_process_tpk_m1?!");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
cpos = buf;
|
cpos = buf;
|
||||||
cpos += 1 /* pkt_type */ + 1 /* Category */ + 1 /* Action */;
|
cpos += 1 /* pkt_type */ + 1 /* Category */ + 1 /* Action */;
|
||||||
|
|
||||||
|
@ -968,57 +996,62 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
|
||||||
|
|
||||||
ielen = len - (cpos - buf); /* start of IE in buf */
|
ielen = len - (cpos - buf); /* start of IE in buf */
|
||||||
if (wpa_supplicant_parse_ies(cpos, ielen, &kde) < 0) {
|
if (wpa_supplicant_parse_ies(cpos, ielen, &kde) < 0) {
|
||||||
wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in TDLS_M1");
|
wpa_printf(MSG_INFO, "TDLS: Failed to parse KDEs in TPK M1");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kde.ftie == NULL) {
|
|
||||||
wpa_printf(MSG_INFO, "RSN: No FTIE in TDLS_M1");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (kde.rsn_ie == NULL) {
|
|
||||||
wpa_printf(MSG_INFO, "RSN: No RSN IE in TDLS_M1");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (kde.lnkid == NULL || kde.lnkid_len < 3 * ETH_ALEN) {
|
if (kde.lnkid == NULL || kde.lnkid_len < 3 * ETH_ALEN) {
|
||||||
wpa_printf(MSG_INFO, "RSN: No Link Identifier IE in TDLS_M1");
|
wpa_printf(MSG_INFO, "TDLS: No Link Identifier IE in TPK M1");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ftie = (struct wpa_tdls_ftie *) kde.ftie;
|
|
||||||
lnkid = (struct wpa_tdls_lnkid *) kde.lnkid;
|
lnkid = (struct wpa_tdls_lnkid *) kde.lnkid;
|
||||||
|
|
||||||
if (os_memcmp(sm->bssid, lnkid->bssid, ETH_ALEN) != 0) {
|
if (os_memcmp(sm->bssid, lnkid->bssid, ETH_ALEN) != 0) {
|
||||||
wpa_printf(MSG_INFO, "TDLS: TPK M1 from diff BSS");
|
wpa_printf(MSG_INFO, "TDLS: TPK M1 from diff BSS");
|
||||||
|
wpa_tdls_send_smk_error(sm, src_addr, WLAN_TDLS_SETUP_RESPONSE,
|
||||||
|
dtoken, WLAN_STATUS_NOT_IN_SAME_BSS);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "RSN: TDLS_M1 - SMK initiator " MACSTR,
|
wpa_printf(MSG_DEBUG, "TDLS: TPK M1 - TPK initiator " MACSTR,
|
||||||
MAC2STR(src_addr));
|
MAC2STR(src_addr));
|
||||||
|
|
||||||
|
if (!wpa_tdls_get_privacy(sm))
|
||||||
|
goto skip_rsn;
|
||||||
|
|
||||||
|
if (kde.ftie == NULL) {
|
||||||
|
wpa_printf(MSG_INFO, "TDLS: No FTIE in TPK M1");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
ftie = (struct wpa_tdls_ftie *) kde.ftie;
|
||||||
|
if (kde.rsn_ie == NULL) {
|
||||||
|
wpa_printf(MSG_INFO, "TDLS: No RSN IE in TPK M1");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (kde.rsn_ie_len > TDLS_MAX_IE_LEN) {
|
if (kde.rsn_ie_len > TDLS_MAX_IE_LEN) {
|
||||||
wpa_printf(MSG_INFO, "RSN: Too long Initiator RSN IE in "
|
wpa_printf(MSG_INFO, "TDLS: Too long Initiator RSN IE in "
|
||||||
"TDLS_M1");
|
"TPK M1");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wpa_parse_wpa_ie_rsn(kde.rsn_ie, kde.rsn_ie_len, &ie) < 0) {
|
if (wpa_parse_wpa_ie_rsn(kde.rsn_ie, kde.rsn_ie_len, &ie) < 0) {
|
||||||
wpa_printf(MSG_INFO, "RSN: Failed to parse RSN IE in TDLS_M1");
|
wpa_printf(MSG_INFO, "TDLS: Failed to parse RSN IE in TPK M1");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
cipher = ie.pairwise_cipher;
|
cipher = ie.pairwise_cipher;
|
||||||
if (cipher & WPA_CIPHER_CCMP) {
|
if (cipher & WPA_CIPHER_CCMP) {
|
||||||
wpa_printf(MSG_DEBUG, "RSN: Using CCMP for direct link");
|
wpa_printf(MSG_DEBUG, "TDLS: Using CCMP for direct link");
|
||||||
cipher = WPA_CIPHER_CCMP;
|
cipher = WPA_CIPHER_CCMP;
|
||||||
} else {
|
} else {
|
||||||
wpa_printf(MSG_INFO, "RSN: No acceptable cipher in TDLS_M1");
|
wpa_printf(MSG_INFO, "TDLS: No acceptable cipher in TPK M1");
|
||||||
wpa_tdls_send_smk_error(sm, src_addr, WLAN_TDLS_SETUP_RESPONSE,
|
wpa_tdls_send_smk_error(sm, src_addr, WLAN_TDLS_SETUP_RESPONSE,
|
||||||
dtoken,
|
dtoken,
|
||||||
WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID);
|
WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
skip_rsn:
|
||||||
/* Find existing entry and if found, use that instead of adding
|
/* Find existing entry and if found, use that instead of adding
|
||||||
* a new one; how to handle the case where both ends initiate at the
|
* a new one; how to handle the case where both ends initiate at the
|
||||||
* same time? */
|
* same time? */
|
||||||
|
@ -1028,8 +1061,8 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (peer == NULL) {
|
if (peer == NULL) {
|
||||||
wpa_printf(MSG_INFO, "RSN: No matching entry found for "
|
wpa_printf(MSG_INFO, "TDLS: No matching entry found for "
|
||||||
"Initiator, creating one. " MACSTR,
|
"peer, creating one for " MACSTR,
|
||||||
MAC2STR(src_addr));
|
MAC2STR(src_addr));
|
||||||
peer = os_malloc(sizeof(*peer));
|
peer = os_malloc(sizeof(*peer));
|
||||||
if (peer == NULL)
|
if (peer == NULL)
|
||||||
|
@ -1070,6 +1103,14 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
|
||||||
peer->initiator = 0; /* Need to check */
|
peer->initiator = 0; /* Need to check */
|
||||||
peer->dtoken = dtoken;
|
peer->dtoken = dtoken;
|
||||||
os_memcpy(peer->lnkid, (u8 *) lnkid, sizeof(struct wpa_tdls_lnkid));
|
os_memcpy(peer->lnkid, (u8 *) lnkid, sizeof(struct wpa_tdls_lnkid));
|
||||||
|
|
||||||
|
if (!wpa_tdls_get_privacy(sm)) {
|
||||||
|
peer->rsnie_i_len = 0;
|
||||||
|
peer->rsnie_p_len = 0;
|
||||||
|
peer->cipher = WPA_CIPHER_NONE;
|
||||||
|
goto skip_rsn_check;
|
||||||
|
}
|
||||||
|
|
||||||
os_memcpy(peer->inonce, ftie->Snonce, WPA_NONCE_LEN);
|
os_memcpy(peer->inonce, ftie->Snonce, WPA_NONCE_LEN);
|
||||||
os_memcpy(peer->rsnie_i, kde.rsn_ie, kde.rsn_ie_len);
|
os_memcpy(peer->rsnie_i, kde.rsn_ie, kde.rsn_ie_len);
|
||||||
peer->rsnie_i_len = kde.rsn_ie_len;
|
peer->rsnie_i_len = kde.rsn_ie_len;
|
||||||
|
@ -1077,7 +1118,7 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
|
||||||
|
|
||||||
if (os_get_random(peer->pnonce, WPA_NONCE_LEN)) {
|
if (os_get_random(peer->pnonce, WPA_NONCE_LEN)) {
|
||||||
wpa_msg(sm->ctx->ctx, MSG_WARNING,
|
wpa_msg(sm->ctx->ctx, MSG_WARNING,
|
||||||
"WPA: Failed to get random data for PNonce");
|
"TDLS: Failed to get random data for PNonce");
|
||||||
wpa_tdls_peer_free(sm, peer);
|
wpa_tdls_peer_free(sm, peer);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -1142,7 +1183,8 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
|
||||||
/* generate SMK using Nonce */
|
/* generate SMK using Nonce */
|
||||||
wpa_tdls_generate_tpk(peer, sm->own_addr, sm->bssid);
|
wpa_tdls_generate_tpk(peer, sm->own_addr, sm->bssid);
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "TDLS: Sending TPK Handshake Message 2");
|
skip_rsn_check:
|
||||||
|
wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Response / TPK M2");
|
||||||
wpa_tdls_send_tpk_m2(sm, src_addr, dtoken, lnkid, peer);
|
wpa_tdls_send_tpk_m2(sm, src_addr, dtoken, lnkid, peer);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1151,15 +1193,18 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
|
||||||
|
|
||||||
static void wpa_tdls_enable_link(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
|
static void wpa_tdls_enable_link(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
|
||||||
{
|
{
|
||||||
|
peer->tpk_success = 1;
|
||||||
eloop_cancel_timeout(wpa_tdls_tpk_timeout, sm, peer);
|
eloop_cancel_timeout(wpa_tdls_tpk_timeout, sm, peer);
|
||||||
eloop_register_timeout(peer->lifetime, 0, wpa_tdls_tpk_timeout,
|
if (wpa_tdls_get_privacy(sm)) {
|
||||||
sm, peer);
|
eloop_register_timeout(peer->lifetime, 0, wpa_tdls_tpk_timeout,
|
||||||
|
sm, peer);
|
||||||
|
}
|
||||||
wpa_sm_tdls_oper(sm, TDLS_ENABLE_LINK, peer->addr);
|
wpa_sm_tdls_oper(sm, TDLS_ENABLE_LINK, peer->addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr,
|
static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr,
|
||||||
const u8 *buf, u16 len)
|
const u8 *buf, size_t len)
|
||||||
{
|
{
|
||||||
struct wpa_tdls_peer *peer;
|
struct wpa_tdls_peer *peer;
|
||||||
struct wpa_eapol_ie_parse kde;
|
struct wpa_eapol_ie_parse kde;
|
||||||
|
@ -1174,8 +1219,8 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr,
|
||||||
u16 status;
|
u16 status;
|
||||||
const u8 *pos;
|
const u8 *pos;
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "TDLS: Received TPK M2 (Peer " MACSTR ")",
|
wpa_printf(MSG_DEBUG, "TDLS: Received TDLS Setup Response / TPK M2 "
|
||||||
MAC2STR(src_addr));
|
"(Peer " MACSTR ")", MAC2STR(src_addr));
|
||||||
for (peer = sm->tdls; peer; peer = peer->next) {
|
for (peer = sm->tdls; peer; peer = peer->next) {
|
||||||
if (os_memcmp(peer->addr, src_addr, ETH_ALEN) == 0)
|
if (os_memcmp(peer->addr, src_addr, ETH_ALEN) == 0)
|
||||||
break;
|
break;
|
||||||
|
@ -1187,12 +1232,8 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr,
|
||||||
}
|
}
|
||||||
wpa_tdls_smkretry_timeout_cancel(sm, peer, WLAN_TDLS_SETUP_REQUEST);
|
wpa_tdls_smkretry_timeout_cancel(sm, peer, WLAN_TDLS_SETUP_REQUEST);
|
||||||
|
|
||||||
if (buf == NULL) {
|
if (len < 3 + 2 + 1)
|
||||||
wpa_printf(MSG_INFO, "TDLS: No message delivered for "
|
|
||||||
"wpa_tdls_process_tpk_m2?!");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
|
||||||
|
|
||||||
pos = buf;
|
pos = buf;
|
||||||
pos += 1 /* pkt_type */ + 1 /* Category */ + 1 /* Action */;
|
pos += 1 /* pkt_type */ + 1 /* Category */ + 1 /* Action */;
|
||||||
status = WPA_GET_LE16(pos);
|
status = WPA_GET_LE16(pos);
|
||||||
|
@ -1204,76 +1245,57 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* driver had already verified the frame format */
|
/* TODO: need to verify dialog token matches here or in kernel */
|
||||||
dtoken = *pos++; /* dialogue token */
|
dtoken = *pos++; /* dialogue token */
|
||||||
|
|
||||||
wpa_printf(MSG_INFO, "TDLS: Dialogue Token in TPK M2 %d",
|
wpa_printf(MSG_DEBUG, "TDLS: Dialogue Token in TPK M2 %d", dtoken);
|
||||||
dtoken);
|
|
||||||
|
|
||||||
|
if (len < 3 + 2 + 1 + 2)
|
||||||
|
return -1;
|
||||||
pos += 2; /* capability information */
|
pos += 2; /* capability information */
|
||||||
|
|
||||||
ielen = len - (pos - buf); /* start of IE in buf */
|
ielen = len - (pos - buf); /* start of IE in buf */
|
||||||
if (wpa_supplicant_parse_ies(pos, ielen, &kde) < 0) {
|
if (wpa_supplicant_parse_ies(pos, ielen, &kde) < 0) {
|
||||||
wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in TDLS_M2");
|
wpa_printf(MSG_INFO, "TDLS: Failed to parse IEs in TPK M2");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kde.ftie == NULL) {
|
|
||||||
wpa_printf(MSG_INFO, "RSN: No FTIE in TDLS_M2");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (kde.rsn_ie == NULL) {
|
|
||||||
wpa_printf(MSG_INFO, "RSN: No RSN IE KDE in TDLS_M2");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (kde.lnkid == NULL || kde.lnkid_len < 3 * ETH_ALEN) {
|
if (kde.lnkid == NULL || kde.lnkid_len < 3 * ETH_ALEN) {
|
||||||
wpa_printf(MSG_INFO, "RSN: No Link Identifier IE in TDLS_M2");
|
wpa_printf(MSG_INFO, "TDLS: No valid Link Identifier IE in "
|
||||||
|
"TPK M2");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
wpa_hexdump(MSG_DEBUG, "TDLS: Link ID Received from TPK M2",
|
||||||
ftie = (struct wpa_tdls_ftie *) kde.ftie;
|
kde.lnkid, kde.lnkid_len);
|
||||||
lnkid = (struct wpa_tdls_lnkid *) kde.lnkid;
|
lnkid = (struct wpa_tdls_lnkid *) kde.lnkid;
|
||||||
|
|
||||||
if (os_memcmp(sm->bssid, lnkid->bssid, ETH_ALEN) != 0) {
|
if (os_memcmp(sm->bssid, lnkid->bssid, ETH_ALEN) != 0) {
|
||||||
wpa_printf(MSG_INFO, "TDLS: TPK M2 from diff BSS");
|
wpa_printf(MSG_INFO, "TDLS: TPK M2 from different BSS");
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (kde.rsn_ie_len > TDLS_MAX_IE_LEN) {
|
|
||||||
wpa_printf(MSG_INFO, "RSN: Too long Initiator RSN IE in TDLS_"
|
|
||||||
"M2");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wpa_parse_wpa_ie_rsn(kde.rsn_ie, kde.rsn_ie_len, &ie) < 0) {
|
|
||||||
wpa_printf(MSG_INFO, "RSN: Failed to parse RSN IE in SMK M2");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
cipher = ie.pairwise_cipher;
|
|
||||||
if (cipher & WPA_CIPHER_CCMP) {
|
|
||||||
wpa_printf(MSG_DEBUG, "RSN: Using CCMP for direct link");
|
|
||||||
cipher = WPA_CIPHER_CCMP;
|
|
||||||
} else {
|
|
||||||
wpa_printf(MSG_INFO, "RSN: No acceptable cipher in TDLS_M2");
|
|
||||||
wpa_tdls_send_smk_error(sm, src_addr, WLAN_TDLS_SETUP_CONFIRM,
|
wpa_tdls_send_smk_error(sm, src_addr, WLAN_TDLS_SETUP_CONFIRM,
|
||||||
dtoken,
|
dtoken, WLAN_STATUS_NOT_IN_SAME_BSS);
|
||||||
WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!os_memcmp(peer->inonce, ftie->Snonce, WPA_NONCE_LEN) == 0) {
|
if (!wpa_tdls_get_privacy(sm)) {
|
||||||
wpa_printf(MSG_INFO, "RSN: Key Nonce in TDLS_M2 does "
|
peer->rsnie_p_len = 0;
|
||||||
"not match with INonce used in TDLS_M1");
|
peer->cipher = WPA_CIPHER_NONE;
|
||||||
return -1;
|
goto skip_rsn;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!os_memcmp(peer->rsnie_i, kde.rsn_ie, peer->rsnie_i_len) == 0) {
|
if (kde.rsn_ie == NULL) {
|
||||||
wpa_printf(MSG_INFO, "TDLS: RSNIE in TPK M2 does "
|
wpa_printf(MSG_INFO, "TDLS: No RSN IE in TPK M2");
|
||||||
"not match with RSNIE used in TPK M1");
|
return -1;
|
||||||
wpa_hexdump(MSG_DEBUG, "TDLS: RSNIE Sent in TPK M1",
|
}
|
||||||
|
wpa_hexdump(MSG_DEBUG, "TDLS: RSNIE Received from TPK M2",
|
||||||
|
kde.rsn_ie, kde.rsn_ie_len);
|
||||||
|
|
||||||
|
if (kde.rsn_ie_len != peer->rsnie_i_len ||
|
||||||
|
os_memcmp(peer->rsnie_i, kde.rsn_ie, peer->rsnie_i_len) != 0) {
|
||||||
|
wpa_printf(MSG_INFO, "TDLS: RSN IE in TPK M2 does "
|
||||||
|
"not match with RSN IE used in TPK M1");
|
||||||
|
wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE Sent in TPK M1",
|
||||||
peer->rsnie_i, peer->rsnie_i_len);
|
peer->rsnie_i, peer->rsnie_i_len);
|
||||||
wpa_hexdump(MSG_DEBUG, "TDLS: RSNIE Received from TPK M2",
|
wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE Received from TPK M2",
|
||||||
kde.rsn_ie, kde.rsn_ie_len);
|
kde.rsn_ie, kde.rsn_ie_len);
|
||||||
wpa_tdls_send_smk_error(
|
wpa_tdls_send_smk_error(
|
||||||
sm, src_addr,
|
sm, src_addr,
|
||||||
|
@ -1283,15 +1305,38 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
wpa_hexdump(MSG_DEBUG, "RSN: FTIE Received from SMK M2",
|
if (wpa_parse_wpa_ie_rsn(kde.rsn_ie, kde.rsn_ie_len, &ie) < 0) {
|
||||||
(u8 *) ftie, sizeof(*ftie));
|
wpa_printf(MSG_INFO, "TDLS: Failed to parse RSN IE in TPK M2");
|
||||||
wpa_hexdump(MSG_DEBUG, "RSN: RSNIE Received from SMK M2",
|
return -1;
|
||||||
kde.rsn_ie, kde.rsn_ie_len);
|
}
|
||||||
wpa_hexdump(MSG_DEBUG, "RSN: Link ID Received from SMK M2",
|
|
||||||
(u8 *) lnkid, kde.lnkid_len);
|
cipher = ie.pairwise_cipher;
|
||||||
|
if (cipher & WPA_CIPHER_CCMP) {
|
||||||
|
wpa_printf(MSG_DEBUG, "TDLS: Using CCMP for direct link");
|
||||||
|
cipher = WPA_CIPHER_CCMP;
|
||||||
|
} else {
|
||||||
|
wpa_printf(MSG_INFO, "TDLS: No acceptable cipher in TPK M2");
|
||||||
|
wpa_tdls_send_smk_error(sm, src_addr, WLAN_TDLS_SETUP_CONFIRM,
|
||||||
|
dtoken,
|
||||||
|
WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kde.ftie == NULL) {
|
||||||
|
wpa_printf(MSG_INFO, "TDLS: No FTIE in TPK M2");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
wpa_hexdump(MSG_DEBUG, "TDLS: FTIE Received from TPK M2",
|
||||||
|
kde.ftie, sizeof(*ftie));
|
||||||
|
ftie = (struct wpa_tdls_ftie *) kde.ftie;
|
||||||
|
|
||||||
|
if (!os_memcmp(peer->inonce, ftie->Snonce, WPA_NONCE_LEN) == 0) {
|
||||||
|
wpa_printf(MSG_INFO, "TDLS: Key Nonce in TPK M2 does "
|
||||||
|
"not match with INonce used in TPK M1");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/* P-Nonce and RSN_IE */
|
/* P-Nonce and RSN_IE */
|
||||||
peer->dtoken = dtoken;
|
|
||||||
os_memcpy(peer->lnkid, (u8 *) lnkid, sizeof(struct wpa_tdls_lnkid));
|
os_memcpy(peer->lnkid, (u8 *) lnkid, sizeof(struct wpa_tdls_lnkid));
|
||||||
os_memcpy(peer->pnonce, ftie->Anonce, WPA_NONCE_LEN);
|
os_memcpy(peer->pnonce, ftie->Anonce, WPA_NONCE_LEN);
|
||||||
os_memcpy(peer->rsnie_p, kde.rsn_ie, kde.rsn_ie_len);
|
os_memcpy(peer->rsnie_p, kde.rsn_ie, kde.rsn_ie_len);
|
||||||
|
@ -1319,7 +1364,7 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr,
|
||||||
/* generate SMK using Nonce */
|
/* generate SMK using Nonce */
|
||||||
wpa_tdls_generate_tpk(peer, sm->own_addr, sm->bssid);
|
wpa_tdls_generate_tpk(peer, sm->own_addr, sm->bssid);
|
||||||
|
|
||||||
/* Process MIC check to see if TDLS_M2 is right */
|
/* Process MIC check to see if TPK M2 is right */
|
||||||
if (wpa_supplicant_verify_tdls_mic(2, peer, (u8 *) lnkid,
|
if (wpa_supplicant_verify_tdls_mic(2, peer, (u8 *) lnkid,
|
||||||
(u8 *) timeoutie, ftie) < 0) {
|
(u8 *) timeoutie, ftie) < 0) {
|
||||||
wpa_tdls_del_key(sm, peer);
|
wpa_tdls_del_key(sm, peer);
|
||||||
|
@ -1329,7 +1374,11 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr,
|
||||||
|
|
||||||
wpa_tdls_set_key(sm, peer);
|
wpa_tdls_set_key(sm, peer);
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "TDLS: Sending TPK Handshake Message 3");
|
skip_rsn:
|
||||||
|
peer->dtoken = dtoken;
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Confirm / "
|
||||||
|
"TPK Handshake Message 3");
|
||||||
wpa_tdls_send_tpk_m3(sm, src_addr, dtoken, lnkid, peer);
|
wpa_tdls_send_tpk_m3(sm, src_addr, dtoken, lnkid, peer);
|
||||||
|
|
||||||
wpa_tdls_enable_link(sm, peer);
|
wpa_tdls_enable_link(sm, peer);
|
||||||
|
@ -1339,7 +1388,7 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr,
|
||||||
|
|
||||||
|
|
||||||
static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr,
|
static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr,
|
||||||
const u8 *buf, u16 len)
|
const u8 *buf, size_t len)
|
||||||
{
|
{
|
||||||
struct wpa_tdls_peer *peer;
|
struct wpa_tdls_peer *peer;
|
||||||
struct wpa_eapol_ie_parse kde;
|
struct wpa_eapol_ie_parse kde;
|
||||||
|
@ -1351,7 +1400,7 @@ static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr,
|
||||||
const u8 *pos;
|
const u8 *pos;
|
||||||
u32 lifetime;
|
u32 lifetime;
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "RSN: Received TDLS_M3 (Peer " MACSTR ")",
|
wpa_printf(MSG_DEBUG, "RSN: Received TPK M3 (Peer " MACSTR ")",
|
||||||
MAC2STR(src_addr));
|
MAC2STR(src_addr));
|
||||||
for (peer = sm->tdls; peer; peer = peer->next) {
|
for (peer = sm->tdls; peer; peer = peer->next) {
|
||||||
if (os_memcmp(peer->addr, src_addr, ETH_ALEN) == 0)
|
if (os_memcmp(peer->addr, src_addr, ETH_ALEN) == 0)
|
||||||
|
@ -1364,12 +1413,6 @@ static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr,
|
||||||
}
|
}
|
||||||
wpa_tdls_smkretry_timeout_cancel(sm, peer, WLAN_TDLS_SETUP_RESPONSE);
|
wpa_tdls_smkretry_timeout_cancel(sm, peer, WLAN_TDLS_SETUP_RESPONSE);
|
||||||
|
|
||||||
if (buf == NULL) {
|
|
||||||
wpa_printf(MSG_INFO, "TDLS: No message delivered for "
|
|
||||||
"wpa_tdls_process_tpk_m3?!");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
pos = buf;
|
pos = buf;
|
||||||
pos += 1 /* pkt_type */ + 1 /* Category */ + 1 /* Action */;
|
pos += 1 /* pkt_type */ + 1 /* Category */ + 1 /* Action */;
|
||||||
|
|
||||||
|
@ -1384,25 +1427,16 @@ static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr,
|
||||||
|
|
||||||
ielen = len - (pos - buf); /* start of IE in buf */
|
ielen = len - (pos - buf); /* start of IE in buf */
|
||||||
if (wpa_supplicant_parse_ies((const u8 *) pos, ielen, &kde) < 0) {
|
if (wpa_supplicant_parse_ies((const u8 *) pos, ielen, &kde) < 0) {
|
||||||
wpa_printf(MSG_INFO, "TDLS: Failed to parse KDEs in TPK "
|
wpa_printf(MSG_INFO, "TDLS: Failed to parse KDEs in TPK M3");
|
||||||
"Handshake Message 3");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kde.ftie == NULL) {
|
|
||||||
wpa_printf(MSG_INFO, "RSN: No FTIE in TDLS_M3");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (kde.rsn_ie == NULL) {
|
|
||||||
wpa_printf(MSG_INFO, "RSN: No RSN IE KDE in TDLS_M3");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (kde.lnkid == NULL || kde.lnkid_len < 3 * ETH_ALEN) {
|
if (kde.lnkid == NULL || kde.lnkid_len < 3 * ETH_ALEN) {
|
||||||
wpa_printf(MSG_INFO, "RSN: No Link Identifier IE in TDLS_M3");
|
wpa_printf(MSG_INFO, "TDLS: No Link Identifier IE in TPK M3");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
wpa_hexdump(MSG_DEBUG, "TDLS: Link ID Received from TPK M3",
|
||||||
ftie = (struct wpa_tdls_ftie *) kde.ftie;
|
(u8 *) kde.lnkid, kde.lnkid_len);
|
||||||
lnkid = (struct wpa_tdls_lnkid *) kde.lnkid;
|
lnkid = (struct wpa_tdls_lnkid *) kde.lnkid;
|
||||||
|
|
||||||
if (os_memcmp(sm->bssid, lnkid->bssid, ETH_ALEN) != 0) {
|
if (os_memcmp(sm->bssid, lnkid->bssid, ETH_ALEN) != 0) {
|
||||||
|
@ -1410,22 +1444,33 @@ static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!wpa_tdls_get_privacy(sm))
|
||||||
|
goto skip_rsn;
|
||||||
|
|
||||||
|
if (kde.ftie == NULL) {
|
||||||
|
wpa_printf(MSG_INFO, "TDLS: No FTIE in TPK M3");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
wpa_hexdump(MSG_DEBUG, "TDLS: FTIE Received from TPK M3",
|
wpa_hexdump(MSG_DEBUG, "TDLS: FTIE Received from TPK M3",
|
||||||
(u8 *) ftie, sizeof(*ftie));
|
(u8 *) ftie, sizeof(*ftie));
|
||||||
|
ftie = (struct wpa_tdls_ftie *) kde.ftie;
|
||||||
|
|
||||||
|
if (kde.rsn_ie == NULL) {
|
||||||
|
wpa_printf(MSG_INFO, "TDLS: No RSN IE KDE in TPK M3");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
wpa_hexdump(MSG_DEBUG, "TDLS: RSNIE Received from TPK M3",
|
wpa_hexdump(MSG_DEBUG, "TDLS: RSNIE Received from TPK M3",
|
||||||
kde.rsn_ie, kde.rsn_ie_len);
|
kde.rsn_ie, kde.rsn_ie_len);
|
||||||
wpa_hexdump(MSG_DEBUG, "TDLS: Link ID Received from TPK M3",
|
|
||||||
(u8 *) lnkid, sizeof(*lnkid));
|
|
||||||
|
|
||||||
if (!os_memcmp(peer->pnonce, ftie->Anonce, WPA_NONCE_LEN) == 0) {
|
if (!os_memcmp(peer->pnonce, ftie->Anonce, WPA_NONCE_LEN) == 0) {
|
||||||
wpa_printf(MSG_INFO, "RSN: PNonce in TDLS_M3 does "
|
wpa_printf(MSG_INFO, "TDLS: PNonce in TPK M3 does "
|
||||||
"not match with PNonce used in TDLS_M2");
|
"not match with PNonce used in TPK M2");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!os_memcmp(peer->inonce, ftie->Snonce, WPA_NONCE_LEN) == 0) {
|
if (!os_memcmp(peer->inonce, ftie->Snonce, WPA_NONCE_LEN) == 0) {
|
||||||
wpa_printf(MSG_INFO, "RSN: INonce in TDLS_M3 did not "
|
wpa_printf(MSG_INFO, "TDLS: INonce in TPK M3 did not "
|
||||||
"match with the one received in TDLS_M1");
|
"match with the one received in TPK M1");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1455,6 +1500,7 @@ static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr,
|
||||||
if (wpa_tdls_set_key(sm, peer) < 0)
|
if (wpa_tdls_set_key(sm, peer) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
skip_rsn:
|
||||||
wpa_tdls_enable_link(sm, peer);
|
wpa_tdls_enable_link(sm, peer);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1486,7 +1532,7 @@ static u8 * wpa_add_tdls_timeoutie(u8 *pos, u8 *ie, size_t ie_len, u32 tsecs)
|
||||||
*/
|
*/
|
||||||
int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr)
|
int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr)
|
||||||
{
|
{
|
||||||
u16 kde_len; /* TDLS TPK Messages are around 400 bytes */
|
u16 buf_len;
|
||||||
struct wpa_tdls_ftie *ftie;
|
struct wpa_tdls_ftie *ftie;
|
||||||
u8 *rbuf, *pos, *count_pos;
|
u8 *rbuf, *pos, *count_pos;
|
||||||
u16 count;
|
u16 count;
|
||||||
|
@ -1503,8 +1549,8 @@ int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (peer == NULL) {
|
if (peer == NULL) {
|
||||||
wpa_printf(MSG_INFO, "RSN: No matching entry found for "
|
wpa_printf(MSG_INFO, "TDLS: No matching entry found for "
|
||||||
"peer, creating one. " MACSTR, MAC2STR(addr));
|
"peer, creating one for " MACSTR, MAC2STR(addr));
|
||||||
peer = os_malloc(sizeof(*peer));
|
peer = os_malloc(sizeof(*peer));
|
||||||
if (peer == NULL)
|
if (peer == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -1516,6 +1562,12 @@ int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr)
|
||||||
|
|
||||||
peer->initiator = 1;
|
peer->initiator = 1;
|
||||||
|
|
||||||
|
if (!wpa_tdls_get_privacy(sm)) {
|
||||||
|
wpa_printf(MSG_DEBUG, "TDLS: No security used on the link");
|
||||||
|
peer->rsnie_i_len = 0;
|
||||||
|
goto skip_rsnie;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TPK Handshake Message 1:
|
* TPK Handshake Message 1:
|
||||||
* FTIE: ANonce=0, SNonce=nonce MIC=0, DataKDs=(RSNIE_I,
|
* FTIE: ANonce=0, SNonce=nonce MIC=0, DataKDs=(RSNIE_I,
|
||||||
|
@ -1578,21 +1630,28 @@ int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr)
|
||||||
wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE for TPK handshake",
|
wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE for TPK handshake",
|
||||||
peer->rsnie_i, peer->rsnie_i_len);
|
peer->rsnie_i, peer->rsnie_i_len);
|
||||||
|
|
||||||
kde_len = peer->rsnie_i_len + sizeof(struct wpa_tdls_ftie) +
|
skip_rsnie:
|
||||||
sizeof(struct wpa_tdls_timeoutie);
|
buf_len = 0;
|
||||||
|
if (wpa_tdls_get_privacy(sm))
|
||||||
|
buf_len += peer->rsnie_i_len + sizeof(struct wpa_tdls_ftie) +
|
||||||
|
sizeof(struct wpa_tdls_timeoutie);
|
||||||
#ifdef CONFIG_TDLS_TESTING
|
#ifdef CONFIG_TDLS_TESTING
|
||||||
if (tdls_testing & TDLS_TESTING_LONG_FRAME)
|
if (wpa_tdls_get_privacy(sm) &&
|
||||||
kde_len += 170;
|
(tdls_testing & TDLS_TESTING_LONG_FRAME))
|
||||||
|
buf_len += 170;
|
||||||
if (tdls_testing & TDLS_TESTING_DIFF_BSSID)
|
if (tdls_testing & TDLS_TESTING_DIFF_BSSID)
|
||||||
kde_len += sizeof(struct wpa_tdls_lnkid);
|
buf_len += sizeof(struct wpa_tdls_lnkid);
|
||||||
#endif /* CONFIG_TDLS_TESTING */
|
#endif /* CONFIG_TDLS_TESTING */
|
||||||
rbuf = os_zalloc(kde_len);
|
rbuf = os_zalloc(buf_len + 1);
|
||||||
if (rbuf == NULL) {
|
if (rbuf == NULL) {
|
||||||
wpa_tdls_peer_free(sm, peer);
|
wpa_tdls_peer_free(sm, peer);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
pos = rbuf;
|
pos = rbuf;
|
||||||
|
|
||||||
|
if (!wpa_tdls_get_privacy(sm))
|
||||||
|
goto skip_ies;
|
||||||
|
|
||||||
/* Initiator RSN IE */
|
/* Initiator RSN IE */
|
||||||
pos = wpa_add_ie(pos, peer->rsnie_i, peer->rsnie_i_len);
|
pos = wpa_add_ie(pos, peer->rsnie_i, peer->rsnie_i_len);
|
||||||
|
|
||||||
|
@ -1625,19 +1684,6 @@ int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr)
|
||||||
*pos++ = 168; /* FTIE subelem length */
|
*pos++ = 168; /* FTIE subelem length */
|
||||||
pos += 168;
|
pos += 168;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tdls_testing & TDLS_TESTING_DIFF_BSSID) {
|
|
||||||
wpa_printf(MSG_DEBUG, "TDLS: Testing - use incorrect BSSID in "
|
|
||||||
"Link Identifier");
|
|
||||||
struct wpa_tdls_lnkid *l = (struct wpa_tdls_lnkid *) pos;
|
|
||||||
l->ie_type = WLAN_EID_LINK_ID;
|
|
||||||
l->ie_len = 3 * ETH_ALEN;
|
|
||||||
os_memcpy(l->bssid, sm->bssid, ETH_ALEN);
|
|
||||||
l->bssid[5] ^= 0x01;
|
|
||||||
os_memcpy(l->init_sta, sm->own_addr, ETH_ALEN);
|
|
||||||
os_memcpy(l->resp_sta, addr, ETH_ALEN);
|
|
||||||
pos += sizeof(*l);
|
|
||||||
}
|
|
||||||
#endif /* CONFIG_TDLS_TESTING */
|
#endif /* CONFIG_TDLS_TESTING */
|
||||||
|
|
||||||
/* Lifetime */
|
/* Lifetime */
|
||||||
|
@ -1653,28 +1699,34 @@ int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr)
|
||||||
sizeof(timeoutie), peer->lifetime);
|
sizeof(timeoutie), peer->lifetime);
|
||||||
wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds", peer->lifetime);
|
wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds", peer->lifetime);
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "TDLS: Sending TPK Handshake Message 1 (peer "
|
skip_ies:
|
||||||
MACSTR ")", MAC2STR(addr));
|
|
||||||
|
#ifdef CONFIG_TDLS_TESTING
|
||||||
|
if (tdls_testing & TDLS_TESTING_DIFF_BSSID) {
|
||||||
|
wpa_printf(MSG_DEBUG, "TDLS: Testing - use incorrect BSSID in "
|
||||||
|
"Link Identifier");
|
||||||
|
struct wpa_tdls_lnkid *l = (struct wpa_tdls_lnkid *) pos;
|
||||||
|
l->ie_type = WLAN_EID_LINK_ID;
|
||||||
|
l->ie_len = 3 * ETH_ALEN;
|
||||||
|
os_memcpy(l->bssid, sm->bssid, ETH_ALEN);
|
||||||
|
l->bssid[5] ^= 0x01;
|
||||||
|
os_memcpy(l->init_sta, sm->own_addr, ETH_ALEN);
|
||||||
|
os_memcpy(l->resp_sta, addr, ETH_ALEN);
|
||||||
|
pos += sizeof(*l);
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_TDLS_TESTING */
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Request / TPK "
|
||||||
|
"Handshake Message 1 (peer " MACSTR ")", MAC2STR(addr));
|
||||||
|
|
||||||
wpa_tdls_smk_send(sm, addr, WLAN_TDLS_SETUP_REQUEST, 0, 0,
|
wpa_tdls_smk_send(sm, addr, WLAN_TDLS_SETUP_REQUEST, 0, 0,
|
||||||
rbuf, kde_len);
|
rbuf, pos - rbuf);
|
||||||
os_free(rbuf);
|
os_free(rbuf);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int wpa_tdls_get_privacy(struct wpa_sm *sm)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Get info needed from supplicant to check if the current BSS supports
|
|
||||||
* security. Other than OPEN mode, rest are considered secured
|
|
||||||
* WEP/WPA/WPA2 hence TDLS frames are processed for TPK handshake.
|
|
||||||
*/
|
|
||||||
return sm->pairwise_cipher != WPA_CIPHER_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* wpa_supplicant_rx_tdls - Receive TDLS data frame
|
* wpa_supplicant_rx_tdls - Receive TDLS data frame
|
||||||
*
|
*
|
||||||
|
@ -1686,44 +1738,48 @@ static void wpa_supplicant_rx_tdls(void *ctx, const u8 *src_addr,
|
||||||
struct wpa_sm *sm = ctx;
|
struct wpa_sm *sm = ctx;
|
||||||
struct wpa_tdls_frame *tf;
|
struct wpa_tdls_frame *tf;
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "Received TDLS Packet");
|
wpa_hexdump(MSG_DEBUG, "TDLS: Received Data frame encapsulation",
|
||||||
|
buf, len);
|
||||||
if (!wpa_tdls_get_privacy(sm)) {
|
|
||||||
wpa_printf(MSG_INFO, "TDLS: %s: In open mode, so discard",
|
|
||||||
__func__);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (os_memcmp(src_addr, sm->own_addr, ETH_ALEN) == 0) {
|
if (os_memcmp(src_addr, sm->own_addr, ETH_ALEN) == 0) {
|
||||||
wpa_printf(MSG_DEBUG, "TDLS: Discard copy of own message");
|
wpa_printf(MSG_DEBUG, "TDLS: Discard copy of own message");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (len < sizeof(*tf)) {
|
||||||
|
wpa_printf(MSG_INFO, "TDLS: Drop too short frame");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check to make sure its a valid encapsulated TDLS frame */
|
||||||
tf = (struct wpa_tdls_frame *) buf;
|
tf = (struct wpa_tdls_frame *) buf;
|
||||||
|
if (tf->payloadtype != 2 /* TDLS_RFTYPE */ ||
|
||||||
/* Check to make sure its a valid setup request */
|
tf->category != WLAN_ACTION_TDLS) {
|
||||||
if (tf->payloadtype != 2 /* TDLS_RFTYPE */) {
|
wpa_printf(MSG_INFO, "TDLS: Invalid frame - payloadtype=%u "
|
||||||
wpa_printf(MSG_INFO, "TDLS: Invalid payloadtype: %x, "
|
"category=%u action=%u",
|
||||||
"action:%x", tf->payloadtype, TDLS_FRAME_TYPE(tf));
|
tf->payloadtype, tf->category, tf->action);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!len) {
|
switch (tf->action) {
|
||||||
wpa_printf(MSG_INFO, "%s cannot process a frame of 0 len",
|
case WLAN_TDLS_SETUP_REQUEST:
|
||||||
__func__);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
wpa_hexdump(MSG_DEBUG, "TDLS: l2_packet Received frame", buf, len);
|
|
||||||
|
|
||||||
if (TDLS_FRAME_TYPE(tf) == WLAN_TDLS_SETUP_REQUEST)
|
|
||||||
wpa_tdls_process_tpk_m1(sm, src_addr, buf, len);
|
wpa_tdls_process_tpk_m1(sm, src_addr, buf, len);
|
||||||
else if (TDLS_FRAME_TYPE(tf) == WLAN_TDLS_SETUP_RESPONSE)
|
break;
|
||||||
|
case WLAN_TDLS_SETUP_RESPONSE:
|
||||||
wpa_tdls_process_tpk_m2(sm, src_addr, buf, len);
|
wpa_tdls_process_tpk_m2(sm, src_addr, buf, len);
|
||||||
else if (TDLS_FRAME_TYPE(tf) == WLAN_TDLS_SETUP_CONFIRM)
|
break;
|
||||||
|
case WLAN_TDLS_SETUP_CONFIRM:
|
||||||
wpa_tdls_process_tpk_m3(sm, src_addr, buf, len);
|
wpa_tdls_process_tpk_m3(sm, src_addr, buf, len);
|
||||||
else if (TDLS_FRAME_TYPE(tf) == WLAN_TDLS_TEARDOWN)
|
break;
|
||||||
|
case WLAN_TDLS_TEARDOWN:
|
||||||
wpa_tdls_recv_teardown(sm, src_addr, buf, len);
|
wpa_tdls_recv_teardown(sm, src_addr, buf, len);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* Kernel code will process remaining frames */
|
||||||
|
wpa_printf(MSG_DEBUG, "TDLS: Ignore TDLS frame action code %u",
|
||||||
|
tf->action);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue