@@ -2418,7 +2418,8 @@ static void pasn_fils_auth_resp(struct hostapd_data *hapd,
wpabuf_head(pasn->secret),
wpabuf_len(pasn->secret),
pasn_get_ptk(sta->pasn), pasn_get_akmp(sta->pasn),
- pasn_get_cipher(sta->pasn), sta->pasn->kdk_len);
+ pasn_get_cipher(sta->pasn), sta->pasn->kdk_len,
+ sta->pasn->kek_len);
if (ret) {
wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to derive PTK");
goto fail;
@@ -651,7 +651,7 @@ static int pasn_test_pasn_auth(void)
spa_addr, bssid,
dhss, sizeof(dhss),
&ptk, WPA_KEY_MGMT_PASN, WPA_CIPHER_CCMP,
- WPA_KDK_MAX_LEN);
+ WPA_KDK_MAX_LEN, 0);
if (ret)
return ret;
@@ -396,6 +396,10 @@ static int ieee802_11_parse_extension(const u8 *pos, size_t elen,
elems->mbssid_known_bss = pos;
elems->mbssid_known_bss_len = elen;
break;
+ case WLAN_EID_EXT_PASN_ENCRYPTED_ELEMENT:
+ elems->pasn_encrypted_ie = pos;
+ elems->pasn_encrypted_ie_len = elen;
+ break;
default:
if (show_errors) {
wpa_printf(MSG_MSGDUMP,
@@ -66,6 +66,7 @@ struct ieee802_11_elems {
const u8 *vendor_vht;
const u8 *p2p;
const u8 *p2p2_ie;
+ const u8 *pasn_encrypted_ie;
const u8 *wfd;
const u8 *link_id;
const u8 *interworking;
@@ -138,6 +139,7 @@ struct ieee802_11_elems {
u8 vendor_vht_len;
u8 p2p_len;
u8 p2p2_ie_len;
+ u8 pasn_encrypted_ie_len;
u8 wfd_len;
u8 interworking_len;
u8 qos_map_set_len;
@@ -524,6 +524,7 @@
#define WLAN_EID_EXT_MULTI_LINK_TRAFFIC_INDICATION 110
#define WLAN_EID_EXT_QOS_CHARACTERISTICS 113
#define WLAN_EID_EXT_AKM_SUITE_SELECTOR 114
+#define WLAN_EID_EXT_PASN_ENCRYPTED_ELEMENT 140
/* Extended Capabilities field */
#define WLAN_EXT_CAPAB_20_40_COEX 0
@@ -616,6 +617,7 @@
#define WLAN_RSNX_CAPAB_SECURE_RTT 9
#define WLAN_RSNX_CAPAB_URNM_MFPR_X20 10
#define WLAN_RSNX_CAPAB_URNM_MFPR 15
+#define WLAN_RSNX_CAPAB_KEK 18
#define WLAN_RSNX_CAPAB_SSID_PROTECTION 21
/* Multiple BSSID element subelements */
@@ -1460,9 +1460,9 @@ int pasn_pmk_to_ptk(const u8 *pmk, size_t pmk_len,
const u8 *spa, const u8 *bssid,
const u8 *dhss, size_t dhss_len,
struct wpa_ptk *ptk, int akmp, int cipher,
- size_t kdk_len)
+ size_t kdk_len, size_t kek_len)
{
- u8 tmp[WPA_KCK_MAX_LEN + WPA_TK_MAX_LEN + WPA_KDK_MAX_LEN];
+ u8 tmp[WPA_KCK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN + WPA_KDK_MAX_LEN];
u8 *data;
size_t data_len, ptk_len;
int ret = -1;
@@ -1497,7 +1497,7 @@ int pasn_pmk_to_ptk(const u8 *pmk, size_t pmk_len,
ptk->kck_len = WPA_PASN_KCK_LEN;
ptk->tk_len = wpa_cipher_key_len(cipher);
ptk->kdk_len = kdk_len;
- ptk->kek_len = 0;
+ ptk->kek_len = kek_len;
ptk->kek2_len = 0;
ptk->kck2_len = 0;
@@ -1508,7 +1508,7 @@ int pasn_pmk_to_ptk(const u8 *pmk, size_t pmk_len,
goto err;
}
- ptk_len = ptk->kck_len + ptk->tk_len + ptk->kdk_len;
+ ptk_len = ptk->kck_len + ptk->tk_len + ptk->kdk_len + ptk->kek_len;
if (ptk_len > sizeof(tmp))
goto err;
@@ -1537,12 +1537,18 @@ int pasn_pmk_to_ptk(const u8 *pmk, size_t pmk_len,
os_memcpy(ptk->kck, tmp, WPA_PASN_KCK_LEN);
wpa_hexdump_key(MSG_DEBUG, "PASN: KCK:", ptk->kck, WPA_PASN_KCK_LEN);
- os_memcpy(ptk->tk, tmp + WPA_PASN_KCK_LEN, ptk->tk_len);
+ if (kek_len) {
+ os_memcpy(ptk->kek, tmp + WPA_PASN_KCK_LEN, ptk->kek_len);
+ wpa_hexdump_key(MSG_DEBUG, "PASN: KEK:",
+ ptk->kek, ptk->kek_len);
+ }
+
+ os_memcpy(ptk->tk, tmp + WPA_PASN_KCK_LEN + ptk->kek_len, ptk->tk_len);
wpa_hexdump_key(MSG_DEBUG, "PASN: TK:", ptk->tk, ptk->tk_len);
if (kdk_len) {
- os_memcpy(ptk->kdk, tmp + WPA_PASN_KCK_LEN + ptk->tk_len,
- ptk->kdk_len);
+ os_memcpy(ptk->kdk, tmp + WPA_PASN_KCK_LEN + ptk->kek_len +
+ ptk->tk_len, ptk->kdk_len);
wpa_hexdump_key(MSG_DEBUG, "PASN: KDK:",
ptk->kdk, ptk->kdk_len);
}
@@ -248,6 +248,7 @@ struct wpa_eapol_key {
#define WPA_PASN_KCK_LEN 32
#define WPA_PASN_MIC_MAX_LEN 24
#define WPA_LTF_KEYSEED_MAX_LEN 48
+#define WPA_KEK_128 16
/**
* struct wpa_ptk - WPA Pairwise Transient Key
@@ -751,7 +752,7 @@ int pasn_pmk_to_ptk(const u8 *pmk, size_t pmk_len,
const u8 *spa, const u8 *bssid,
const u8 *dhss, size_t dhss_len,
struct wpa_ptk *ptk, int akmp, int cipher,
- size_t kdk_len);
+ size_t kdk_len, size_t kek_len);
u8 pasn_mic_len(int akmp, int cipher);
@@ -15,12 +15,15 @@
#include "common/ieee802_11_common.h"
#include "common/wpa_ctrl.h"
#include "crypto/sha256.h"
+#include "crypto/sha384.h"
#include "crypto/crypto.h"
#include "crypto/random.h"
#include "wps/wps_i.h"
#include "p2p_i.h"
#include "p2p.h"
-
+#include "common/sae.h"
+#include "pasn/pasn_common.h"
+#include "crypto/aes_wrap.h"
static void p2p_state_timeout(void *eloop_ctx, void *timeout_ctx);
static void p2p_device_free(struct p2p_data *p2p, struct p2p_device *dev);
@@ -243,6 +246,9 @@ void p2p_go_neg_failed(struct p2p_data *p2p, int status)
peer->go_neg_conf = NULL;
p2p->go_neg_peer = NULL;
+ if (peer->p2p2 && peer->pasn)
+ wpa_pasn_reset(peer->pasn);
+
os_memset(&res, 0, sizeof(res));
res.status = status;
os_memcpy(res.peer_device_addr, peer->info.p2p_device_addr, ETH_ALEN);
@@ -960,6 +966,12 @@ static void p2p_device_free(struct p2p_data *p2p, struct p2p_device *dev)
dev->bootstrap_params = NULL;
}
+ if (dev->pasn) {
+ wpa_pasn_reset(dev->pasn);
+ pasn_data_deinit(dev->pasn);
+ dev->pasn = NULL;
+ }
+
wpabuf_free(dev->info.wfd_subelems);
wpabuf_free(dev->info.vendor_elems);
wpabuf_free(dev->go_neg_conf);
@@ -1912,6 +1924,9 @@ void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer)
wpabuf_free(peer->go_neg_conf);
peer->go_neg_conf = NULL;
+ if (peer->p2p2 && peer->pasn)
+ wpa_pasn_reset(peer->pasn);
+
p2p_set_state(p2p, P2P_PROVISIONING);
p2p->cfg->go_neg_completed(p2p->cfg->cb_ctx, &res);
}
@@ -1928,17 +1943,16 @@ static void p2p_rx_p2p_action(struct p2p_data *p2p, const u8 *sa,
switch (data[0]) {
case P2P_GO_NEG_REQ:
- p2p_process_go_neg_req(p2p, sa, data + 1, len - 1, rx_freq);
+ p2p_handle_go_neg_req(p2p, sa, data + 1, len - 1, rx_freq);
break;
case P2P_GO_NEG_RESP:
- p2p_process_go_neg_resp(p2p, sa, data + 1, len - 1, rx_freq);
+ p2p_handle_go_neg_resp(p2p, sa, data + 1, len - 1, rx_freq);
break;
case P2P_GO_NEG_CONF:
- p2p_process_go_neg_conf(p2p, sa, data + 1, len - 1);
+ p2p_handle_go_neg_conf(p2p, sa, data + 1, len - 1, false);
break;
case P2P_INVITATION_REQ:
- p2p_process_invitation_req(p2p, sa, data + 1, len - 1,
- rx_freq);
+ p2p_handle_invitation_req(p2p, sa, data + 1, len - 1, rx_freq);
break;
case P2P_INVITATION_RESP:
p2p_process_invitation_resp(p2p, sa, data + 1, len - 1);
@@ -3016,6 +3030,9 @@ int p2p_pairing_info_init(struct p2p_data *p2p)
pairing_info->dev_ik.dik_len);
p2p->pairing_info = pairing_info;
+ p2p->initiator_pmksa = pasn_initiator_pmksa_cache_init();
+ p2p->responder_pmksa = pasn_responder_pmksa_cache_init();
+
return 0;
}
@@ -3085,6 +3102,8 @@ struct p2p_data * p2p_init(const struct p2p_config *cfg)
void p2p_pairing_info_deinit(struct p2p_data *p2p)
{
+ pasn_initiator_pmksa_cache_deinit(p2p->initiator_pmksa);
+ pasn_responder_pmksa_cache_deinit(p2p->responder_pmksa);
os_free(p2p->pairing_info);
}
@@ -5860,3 +5879,745 @@ void p2p_process_usd_elems(struct p2p_data *p2p, const u8 *ies, u16 ies_len,
p2p_parse_free(&msg);
}
+
+
+int p2p_prepare_pasn_extra_ie(struct p2p_data *p2p, struct wpabuf *extra_ies,
+ struct wpabuf *frame, bool dira)
+{
+ struct wpabuf *buf, *buf2;
+
+ buf = wpabuf_alloc(1500);
+ if (!buf) {
+ p2p_dbg(p2p, "Mem alloc failed for buf");
+ return -1;
+ }
+
+ /* P2P Capability Extension attribute */
+ p2p_buf_add_pcea(buf, p2p);
+
+ /* P2P Device Identity Resolution attribute */
+ if (dira)
+ p2p_buf_add_dira(buf, p2p);
+
+ if (frame) {
+ p2p_dbg(p2p, "P2P: Added Action frame wrapper");
+ wpabuf_put_u8(buf, P2P_ATTR_ACTION_FRAME_WRAPPER);
+ wpabuf_put_le16(buf, wpabuf_len(frame));
+ wpabuf_put_buf(buf, frame);
+ }
+
+ buf2 = p2p_encaps_p2p_vendor_ie(p2p, buf, P2P2_IE_VENDOR_TYPE);
+ wpabuf_free(buf);
+
+ wpabuf_put_buf(extra_ies, buf2);
+ wpabuf_free(buf2);
+
+ return 0;
+}
+
+struct wpabuf *p2p_pairing_generate_rsnxe(int akmp)
+{
+ u32 capab;
+ size_t flen = 0;
+ struct wpabuf *buf;
+
+ capab = BIT(WLAN_RSNX_CAPAB_KEK);
+
+ if (akmp == WPA_KEY_MGMT_SAE)
+ capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E);
+
+ while (capab >> flen * 8)
+ flen++;
+
+ buf = wpabuf_alloc(2 + flen);
+ if (!buf) {
+ wpa_printf(MSG_ERROR, "Memory allocation failed");
+ return NULL;
+ }
+
+ if (wpabuf_tailroom(buf) < 2 + flen) {
+ wpa_printf(MSG_ERROR, "wpabuf tail room small");
+ wpabuf_free(buf);
+ return NULL;
+ }
+ capab |= flen - 1; /* bit 0-3 = Field length (n - 1) */
+
+ wpa_printf(MSG_DEBUG, "RSNXE capabilities: %04x", capab);
+ wpabuf_put_u8(buf, WLAN_EID_RSNX);
+ wpabuf_put_u8(buf, flen);
+ while (flen--) {
+ wpabuf_put_u8(buf, (capab & 0xff));
+ capab = capab >> 8;
+ }
+ return buf;
+}
+
+/* sae password id to derive pt */
+#define P2P_PAIRING_SSID "516F9A020000"
+
+void p2p_pairing_set_password(struct pasn_data *pasn, const char *passphrase,
+ u32 len)
+{
+ const u8 *pairing_ssid;
+ size_t pairing_ssid_len;
+
+ if (!passphrase) {
+ wpa_printf(MSG_ERROR, "p2p pairing password NULL");
+ return;
+ }
+
+ pairing_ssid = (const u8 *)(P2P_PAIRING_SSID);
+ pairing_ssid_len = strlen(P2P_PAIRING_SSID);
+ pasn->pt = sae_derive_pt(NULL, pairing_ssid, pairing_ssid_len,
+ (const u8 *)passphrase, len, NULL);
+ /* Set passpharse for Pairing Responder to validate PASN auth1 frame*/
+ pasn->password = passphrase;
+}
+
+void p2p_pasn_initialize(struct p2p_data *p2p, struct p2p_device *dev,
+ const u8 *addr, int freq)
+{
+ struct pasn_data *pasn;
+ struct wpabuf *rsnxe;
+
+ if (!p2p || !dev)
+ return;
+
+ if (dev->pasn)
+ wpa_pasn_reset(dev->pasn);
+ else
+ dev->pasn = pasn_data_init();
+
+ pasn = dev->pasn;
+
+ os_memcpy(pasn->own_addr, p2p->cfg->dev_addr, ETH_ALEN);
+ os_memcpy(pasn->peer_addr, addr, ETH_ALEN);
+
+ if (dev->role == P2P_ROLE_PAIRING_INITIATOR)
+ memcpy(pasn->bssid, pasn->peer_addr, ETH_ALEN);
+ else
+ memcpy(pasn->bssid, pasn->own_addr, ETH_ALEN);
+
+ pasn->noauth = 1;
+ pasn->group = 19;
+ pasn->cipher = WPA_CIPHER_CCMP;
+ pasn->kek_len = WPA_KEK_128;
+
+ if (dev->password_len) {
+ pasn->akmp = WPA_KEY_MGMT_SAE;
+ p2p_pairing_set_password(pasn, dev->password,
+ dev->password_len);
+ pasn->rsnxe_capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E);
+ } else {
+ pasn->akmp = WPA_KEY_MGMT_PASN;
+ }
+
+ pasn->rsn_pairwise = pasn->cipher;
+ pasn->wpa_key_mgmt = pasn->akmp;
+
+ rsnxe = p2p_pairing_generate_rsnxe(pasn->akmp);
+ if (rsnxe) {
+ pasn->rsnxe_ie = os_zalloc(wpabuf_len(rsnxe));
+ if (!pasn->rsnxe_ie) {
+ p2p_dbg(p2p, "Mem alloc failed for pasn rsnxe ie");
+ wpabuf_free(rsnxe);
+ return;
+ }
+ os_memcpy((u8 *)pasn->rsnxe_ie, wpabuf_head_u8(rsnxe),
+ wpabuf_len(rsnxe));
+ pasn->rsnxe_ie_len = wpabuf_len(rsnxe);
+ wpabuf_free(rsnxe);
+ }
+
+ if (dev->role == P2P_ROLE_PAIRING_INITIATOR)
+ pasn->pmksa = p2p->initiator_pmksa;
+ else
+ pasn->pmksa = p2p->responder_pmksa;
+
+ pasn->cb_ctx = p2p->cfg->cb_ctx;
+ pasn->send_mgmt = p2p->cfg->pasn_send_mgmt;
+ pasn->update_extra_ies = p2p->cfg->pasn_update_extra_ies;
+ pasn->parse_encrypted_data = p2p->cfg->pasn_parse_encrypted_data;
+
+ pasn->freq = freq;
+}
+
+
+
+
+int p2p_initiate_pasn_auth(struct p2p_data *p2p, const u8 *addr, int freq)
+{
+ struct pasn_data *pasn;
+ struct p2p_device *dev;
+ struct wpabuf *extra_ies, *req;
+ int ret = 0;
+
+ if (!addr) {
+ p2p_dbg(p2p, "peer address NULL");
+ return -1;
+ }
+
+ dev = p2p_get_device(p2p, addr);
+ if (!dev) {
+ p2p_dbg(p2p, "Peer not known");
+ return -1;
+ }
+
+ dev->role = P2P_ROLE_PAIRING_INITIATOR;
+ p2p_pasn_initialize(p2p, dev, addr, freq);
+ pasn = dev->pasn;
+
+ /* FIXME: Added to resolve listen freq issue resulting in GO Neg no
+ * common channel failure
+ */
+ p2p->cfg->reg_class = p2p->op_reg_class;
+ p2p->cfg->channel = p2p->op_channel;
+
+ req = p2p_build_go_neg_req(p2p, dev);
+ if (!req)
+ return -1;
+
+ p2p->go_neg_peer = dev;
+ dev->flags |= P2P_DEV_WAIT_GO_NEG_RESPONSE;
+
+ extra_ies = wpabuf_alloc(1500);
+ if (!extra_ies) {
+ wpabuf_free(req);
+ p2p_dbg(p2p, "Mem alloc failed for extra ies");
+ return -1;
+ }
+
+ if (p2p_prepare_pasn_extra_ie(p2p, extra_ies, req, false)) {
+ p2p_dbg(p2p, "prepare pasn extra ies failed");
+ ret = -1;
+ goto out;
+ }
+
+ pasn->extra_ies = os_zalloc(wpabuf_len(extra_ies));
+ if (!pasn->extra_ies) {
+ p2p_dbg(p2p, "Mem alloc failed for pasn extra ies");
+ ret = -1;
+ goto out;
+ }
+
+ os_memcpy((u8 *)pasn->extra_ies, wpabuf_head_u8(extra_ies),
+ wpabuf_len(extra_ies));
+ pasn->extra_ies_len = wpabuf_len(extra_ies);
+
+ /* Start PASN Auth */
+ if (wpas_pasn_start(pasn, pasn->own_addr, pasn->peer_addr, pasn->bssid,
+ pasn->akmp, pasn->cipher, pasn->group, pasn->freq,
+ NULL, 0, NULL, 0, NULL)) {
+ p2p_dbg(p2p, "p2p pasn start failed");
+ ret = -1;
+ }
+out:
+ if (pasn->extra_ies) {
+ os_free((u8 *)pasn->extra_ies);
+ pasn->extra_ies = NULL;
+ pasn->extra_ies_len = 0;
+ }
+ wpabuf_free(req);
+ wpabuf_free(extra_ies);
+ return ret;
+}
+
+
+int p2p_pasn_handle_action_wrapper(struct p2p_data *p2p,
+ struct p2p_device *dev,
+ const struct ieee80211_mgmt *mgmt,
+ size_t len, int freq, int trans_seq)
+{
+ const u8 *ies;
+ size_t ies_len;
+ size_t data_len = 0;
+ const u8 *data = NULL;
+ struct p2p_message msg;
+
+ ies = mgmt->u.auth.variable;
+ ies_len = len - offsetof(struct ieee80211_mgmt, u.auth.variable);
+
+ os_memset(&msg, 0, sizeof(msg));
+ if (p2p_parse_ies(ies, ies_len, &msg)) {
+ p2p_dbg(p2p, "Failed to parse P2P IE from auth frame");
+ p2p_parse_free(&msg);
+ return -1;
+ }
+
+ if (msg.dira && msg.dira_len) {
+ }
+
+ if (msg.action_frame_wrapper && msg.action_frame_wrapper_len) {
+ data = msg.action_frame_wrapper;
+ data_len = msg.action_frame_wrapper_len;
+ if (data[0] == WLAN_ACTION_PUBLIC &&
+ data[1] == WLAN_PA_VENDOR_SPECIFIC) {
+ data += 2;
+ data_len -= 2;
+ if (data_len < 4 ||
+ WPA_GET_BE32(data) != P2P_IE_VENDOR_TYPE) {
+ p2p_parse_free(&msg);
+ return -1;
+ }
+ data += 4;
+ data_len -= 4;
+ } else {
+ p2p_dbg(p2p, "Invalid category in action frame wrapper in Auth %d",
+ trans_seq);
+ p2p_parse_free(&msg);
+ return -1;
+ }
+ }
+
+ if (trans_seq == 1) {
+ if (msg.dira && data && data[0] == P2P_INVITATION_REQ) {
+ p2p_process_invitation_req(p2p, mgmt->sa, data + 1,
+ data_len - 1, freq);
+ if (!p2p->invitation_resp)
+ p2p_dbg(p2p, "No Invitation Response found");
+ dev->pasn->action_frame_wrapper = p2p->invitation_resp;
+ } else if (data && data[0] == P2P_GO_NEG_REQ) {
+ p2p_process_go_neg_req(p2p, mgmt->sa, data + 1,
+ data_len - 1, freq, true);
+ if (!p2p->go_neg_resp)
+ p2p_dbg(p2p, "No GO Neg Response found");
+ dev->pasn->action_frame_wrapper = p2p->go_neg_resp;
+ } else {
+ p2p_dbg(p2p, "Invalid action frame wrapper in Auth1");
+ }
+ } else if (trans_seq == 2) {
+ if (msg.dira && data && data[0] == P2P_INVITATION_RESP) {
+ p2p_process_invitation_resp(p2p, mgmt->sa, data + 1,
+ data_len - 1);
+ dev->pasn->action_frame_wrapper = NULL;
+ } else if (data && data[0] == P2P_GO_NEG_RESP) {
+ p2p_process_go_neg_resp(p2p, mgmt->sa, data + 1,
+ data_len - 1, freq, true);
+ if (!p2p->go_neg_conf)
+ p2p_dbg(p2p, "No GO Neg confirm found");
+ dev->pasn->action_frame_wrapper = p2p->go_neg_conf;
+ } else {
+ p2p_dbg(p2p, "Invalid action frame wrapper in Auth2");
+ }
+ } else if (trans_seq == 3) {
+ if (data && data[0] == P2P_GO_NEG_CONF) {
+ p2p_handle_go_neg_conf(p2p, mgmt->sa, data + 1,
+ data_len - 1, true);
+ } else {
+ p2p_invitation_resp_cb(p2p, P2P_SEND_ACTION_SUCCESS);
+ }
+ }
+ p2p_parse_free(&msg);
+ return 0;
+}
+
+
+static void p2p_pasn_add_encrypted_element(struct p2p_data *p2p,
+ struct p2p_device *dev,
+ struct wpabuf *buf)
+{
+ int ret;
+ struct pasn_data *pasn;
+ struct wpabuf *p2p2_ie;
+ u8 *len, *dika_len, *p2p2_ie_len;
+ u8 *pos, *key_data, *encrypted_data;
+ u16 key_data_len, pad_len = 0;
+
+ if (!p2p || !dev || !dev->pasn)
+ return;
+
+ pasn = dev->pasn;
+
+ if (dev->req_bootstrap_method != P2P_PBMA_OPPORTUNISTIC &&
+ !p2p->pairing_info->enable_pairing_cache)
+ return;
+
+ p2p2_ie = wpabuf_alloc(100);
+ if (!p2p2_ie) {
+ p2p_dbg(p2p, "Mem alloc failed for p2p2 IE");
+ return;
+ }
+
+ p2p2_ie_len = p2p_buf_add_p2p2_ie_hdr(p2p2_ie);
+
+ if (p2p->pairing_info->enable_pairing_cache) {
+ wpabuf_put_u8(p2p2_ie, P2P_ATTR_DEVICE_IDENTITY_KEY);
+ dika_len = wpabuf_put(p2p2_ie, 2);
+
+ wpabuf_put_u8(p2p2_ie, DIRA_CIPHER_VERSION_128);
+ wpabuf_put_data(p2p2_ie, p2p->pairing_info->dev_ik.dik_data,
+ p2p->pairing_info->dev_ik.dik_len);
+ wpabuf_put_be32(p2p2_ie, p2p->pairing_info->dev_ik.expiration);
+
+ WPA_PUT_LE16(dika_len,
+ (u8 *)wpabuf_put(p2p2_ie, 0) - dika_len - 2);
+ }
+
+ if (dev->req_bootstrap_method != P2P_PBMA_OPPORTUNISTIC &&
+ dev->dev_password_len) {
+ wpabuf_put_u8(p2p2_ie, P2P_ATTR_PASSWORD);
+ wpabuf_put_le16(p2p2_ie, dev->dev_password_len);
+ wpabuf_put_data(p2p2_ie, dev->dev_password,
+ dev->dev_password_len);
+ }
+
+ p2p_buf_update_p2p2_ie_hdr(p2p2_ie, p2p2_ie_len);
+
+ key_data = (u8 *)wpabuf_head(p2p2_ie);
+ key_data_len = wpabuf_len(p2p2_ie);
+
+ pad_len = key_data_len % 8;
+
+ if (pad_len) {
+ pad_len = 8 - pad_len;
+ pos = key_data + key_data_len;
+ *pos++ = 0xdd;
+ }
+ key_data_len += pad_len + 8;
+
+ encrypted_data = os_malloc(key_data_len);
+ if (!encrypted_data) {
+ p2p_dbg(p2p, "P2P PASN: Mem alloc failed for encrypted data");
+ wpabuf_free(p2p2_ie);
+ return;
+ }
+ ret = aes_wrap(pasn->ptk.kek, pasn->ptk.kek_len,
+ (key_data_len - 8) / 8, key_data, encrypted_data);
+ if (ret) {
+ p2p_dbg(p2p, "P2P PASN: AES upwrap failed, ret=%d", ret);
+ goto out;
+ }
+
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+ len = wpabuf_put(buf, 1);
+
+ wpabuf_put_u8(buf, WLAN_EID_EXT_PASN_ENCRYPTED_ELEMENT);
+
+ wpabuf_put_data(buf, encrypted_data, key_data_len);
+ *len = (u8 *)wpabuf_put(buf, 0) - len - 1;
+
+out:
+ os_free(encrypted_data);
+ wpabuf_free(p2p2_ie);
+}
+
+
+int p2p_pasn_update_extra_ies(struct p2p_data *p2p, const u8 *peer_addr,
+ bool dira)
+{
+ int ret = -1;
+ struct p2p_device *dev;
+ struct pasn_data *pasn;
+ struct wpabuf *extra_ies;
+
+ if (!p2p)
+ return -1;
+
+ dev = p2p_get_device(p2p, (u8 *)peer_addr);
+ if (!dev || !dev->pasn) {
+ p2p_dbg(p2p, "P2P PASN: Peer not found" MACSTR,
+ MAC2STR(peer_addr));
+ return -1;
+ }
+ pasn = dev->pasn;
+
+ extra_ies = wpabuf_alloc(1500);
+ if (!extra_ies) {
+ p2p_dbg(p2p, "Mem alloc failed for extra ies");
+ goto out;
+ }
+
+ if (p2p_prepare_pasn_extra_ie(p2p, extra_ies,
+ pasn->action_frame_wrapper, dira)) {
+ p2p_dbg(p2p, "prepare pasn extra ies failed");
+ goto out;
+ }
+
+ p2p_pasn_add_encrypted_element(p2p, dev, extra_ies);
+
+ pasn->extra_ies = os_zalloc(wpabuf_len(extra_ies));
+ if (!pasn->extra_ies) {
+ p2p_dbg(p2p, "Mem alloc failed for pasn extra ies");
+ goto out;
+ }
+
+ os_memcpy((u8 *)pasn->extra_ies, wpabuf_head_u8(extra_ies),
+ wpabuf_len(extra_ies));
+ pasn->extra_ies_len = wpabuf_len(extra_ies);
+ ret = 0;
+
+out:
+ wpabuf_free(extra_ies);
+ wpabuf_free(pasn->action_frame_wrapper);
+ pasn->action_frame_wrapper = NULL;
+
+ return ret;
+}
+
+
+int p2p_pasn_parse_encrypted_data(struct p2p_data *p2p, const u8 *data,
+ size_t len)
+{
+ int ret = -1;
+ u8 attr_id;
+ u8 *buf, *pos;
+ u16 rem_len, attr_len;
+ struct p2p_device *dev;
+ struct pasn_data *pasn;
+ struct ieee802_11_elems elems;
+ const struct ieee80211_mgmt *mgmt =
+ (const struct ieee80211_mgmt *) data;
+
+ if (!p2p)
+ return -1;
+
+ dev = p2p_get_device(p2p, (u8 *)mgmt->sa);
+ if (!dev || !dev->pasn) {
+ p2p_dbg(p2p, "P2P PASN: Peer not found" MACSTR,
+ MAC2STR(mgmt->sa));
+ return -1;
+ }
+
+ if (ieee802_11_parse_elems(mgmt->u.auth.variable,
+ len - offsetof(struct ieee80211_mgmt,
+ u.auth.variable),
+ &elems, 0) == ParseFailed) {
+ p2p_dbg(p2p, "P2P PASN: Failed parsing Authentication frame");
+ return -1;
+ }
+
+ if (!elems.pasn_encrypted_ie || !elems.pasn_encrypted_ie_len) {
+ p2p_dbg(p2p, "P2P PASN: No encrypted IEs");
+ return 0;
+ }
+
+ pasn = dev->pasn;
+ rem_len = elems.pasn_encrypted_ie_len;
+
+ buf = os_zalloc(rem_len);
+ if (!buf) {
+ p2p_dbg(p2p, "Mem alloc failed for buf");
+ return -1;
+ }
+
+ ret = aes_unwrap(pasn->ptk.kek, pasn->ptk.kek_len, (rem_len - 8) / 8,
+ elems.pasn_encrypted_ie, buf);
+ if (ret) {
+ p2p_dbg(p2p, "P2P PASN: AES unwrap failed, ret=%d", ret);
+ goto done;
+ }
+
+ pos = buf;
+ if (pos[0] != WLAN_EID_VENDOR_SPECIFIC ||
+ WPA_GET_BE32(&pos[2]) != P2P2_IE_VENDOR_TYPE) {
+ p2p_dbg(p2p, "P2P PASN: P2P2 IE not present");
+ goto done;
+ }
+
+ pos += 6;
+ rem_len -= 6;
+
+ while (rem_len > 2) {
+ attr_id = *pos++;
+ attr_len = WPA_GET_LE16(pos);
+
+ pos += 2;
+ rem_len -= 3;
+ switch (attr_id) {
+ case P2P_ATTR_DEVICE_IDENTITY_KEY:
+ if (rem_len < 13) {
+ p2p_dbg(p2p, "P2P PASN: Invalid rem len %d", rem_len);
+ goto done;
+ }
+ dev->info.dik_cipher_version = *pos++;
+ rem_len--;
+ if (dev->info.dik_cipher_version == 0) {
+ memcpy(dev->info.device_identity_key, pos, 16);
+ pos += 16;
+ rem_len -= 16;
+ } else {
+ p2p_dbg(p2p, "P2P PASN: Invalid cipher");
+ goto done;
+ }
+ dev->info.dik_lifetime = WPA_GET_BE32(pos);
+ pos += 4;
+ rem_len -= 4;
+ break;
+ case P2P_ATTR_PASSWORD:
+ if (rem_len < 1) {
+ p2p_dbg(p2p, "P2P PASN: Invalid rem len %d", rem_len);
+ goto done;
+ }
+ dev->info.password_len = attr_len;
+ memset(dev->info.password, 0,
+ sizeof(dev->info.password));
+ memcpy(dev->info.password, pos, attr_len);
+ break;
+ default:
+ p2p_dbg(p2p, "Invalid Attr ID: %d", attr_id);
+ break;
+ }
+ }
+ ret = 0;
+done:
+ os_free(buf);
+ return ret;
+}
+
+int p2p_pasn_auth_tx_status(struct p2p_data *p2p, const u8 *data,
+ size_t data_len, u8 acked)
+{
+ int ret = 0;
+ struct p2p_device *dev;
+ struct pasn_data *pasn;
+ const struct ieee80211_mgmt *mgmt =
+ (const struct ieee80211_mgmt *) data;
+
+ if (!p2p)
+ return -1;
+
+ dev = p2p_get_device(p2p, (u8 *)mgmt->da);
+ if (!dev || !dev->pasn) {
+ p2p_dbg(p2p, "P2P PASN: Peer not found" MACSTR,
+ MAC2STR(mgmt->da));
+ return -1;
+ }
+
+ pasn = dev->pasn;
+
+ ret = wpa_pasn_auth_tx_status(pasn, data, data_len, acked);
+ if (ret != 1 && acked == 0 && pasn->frame) {
+ return pasn->send_mgmt(pasn->cb_ctx, wpabuf_head(pasn->frame),
+ wpabuf_len(pasn->frame), 0, pasn->freq,
+ 1000);
+ } else if (pasn->frame) {
+ wpabuf_free(pasn->frame);
+ pasn->frame = NULL;
+ }
+
+ if (ret != 1)
+ return ret;
+
+ if (dev == p2p->go_neg_peer)
+ p2p_go_complete(p2p, dev);
+
+ return 0;
+}
+
+int p2p_handle_pasn_auth(struct p2p_data *p2p, struct p2p_device *dev,
+ const struct ieee80211_mgmt *mgmt, size_t len,
+ int freq)
+{
+ struct pasn_data *pasn;
+ u16 auth_alg, auth_transaction, status_code;
+
+ if (!p2p || !dev || !dev->pasn)
+ return -1;
+
+ if (os_memcmp(mgmt->da, p2p->cfg->dev_addr, ETH_ALEN) != 0) {
+ p2p_dbg(p2p, "P2P PASN Responder: Not our frame");
+ return -1;
+ }
+
+ pasn = dev->pasn;
+ auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
+ status_code = le_to_host16(mgmt->u.auth.status_code);
+
+ auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
+
+ if (status_code != WLAN_STATUS_SUCCESS &&
+ status_code != WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY) {
+ p2p_dbg(p2p, "P2P PASN: Authentication rejected - status=%u",
+ status_code);
+ return -1;
+ }
+
+ if (auth_alg != WLAN_AUTH_PASN || auth_transaction == 2) {
+ p2p_dbg(p2p, "P2P PASN Responder: Not PASN frame "
+ " or Unexpected auth frame, auth_alg = %d",
+ auth_alg);
+ return -1;
+ }
+ if (auth_transaction == 1) {
+ if (p2p_pasn_handle_action_wrapper(p2p, dev, mgmt, len, freq,
+ auth_transaction)) {
+ p2p_dbg(p2p, "P2P PASN Responder: Handle Auth1 action wrapper failed");
+ return -1;
+ }
+ if (handle_auth_pasn_1(pasn, p2p->cfg->dev_addr, mgmt->sa, mgmt,
+ len) < 0) {
+ p2p_dbg(p2p, "P2P PASN Responder: Handle Auth1 failed");
+ return -1;
+ }
+ } else if (auth_transaction == 3) {
+ if (handle_auth_pasn_3(pasn, p2p->cfg->dev_addr, mgmt->sa, mgmt,
+ len) < 0) {
+ p2p_dbg(p2p, "P2P PASN Responder: Handle PASN Auth3 failed");
+ return -1;
+ }
+ if (p2p_pasn_handle_action_wrapper(p2p, dev, mgmt, len, freq,
+ auth_transaction)) {
+ p2p_dbg(p2p, "P2P PASN Responder: Handle Auth3 action wrapper failed");
+ memset(dev->info.device_identity_key, 0,
+ sizeof(dev->info.device_identity_key));
+ memset(dev->info.password, 0,
+ sizeof(dev->info.password));
+ dev->info.password_len = 0;
+ return -1;
+ }
+ }
+ return 0;
+}
+
+
+int p2p_pasn_auth_rx(struct p2p_data *p2p, const struct ieee80211_mgmt *mgmt,
+ size_t len, int freq)
+{
+ int ret = 0;
+ u8 auth_transaction;
+ struct p2p_device *dev;
+ struct pasn_data *pasn;
+ struct wpa_pasn_params_data pasn_data;
+
+ dev = p2p_get_device(p2p, (u8 *)mgmt->sa);
+ if (!dev) {
+ p2p_dbg(p2p, "P2P PASN: Peer not found" MACSTR,
+ MAC2STR(mgmt->sa));
+ return -1;
+ }
+
+ if (!dev->pasn) {
+ p2p_dbg(p2p, "P2P PASN: uninitialized");
+ return -1;
+ }
+
+ pasn = dev->pasn;
+
+ if (pasn->frame) {
+ wpabuf_free(pasn->frame);
+ pasn->frame = NULL;
+ }
+
+ pasn_register_callbacks(pasn, p2p->cfg->cb_ctx,
+ p2p->cfg->pasn_send_mgmt, NULL);
+ auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
+
+ if (dev->role == P2P_ROLE_PAIRING_INITIATOR && auth_transaction == 2) {
+ if (p2p_pasn_handle_action_wrapper(p2p, dev, mgmt, len, freq,
+ auth_transaction)) {
+ p2p_dbg(p2p, "P2P PASN Initiator: Handle Auth2 action wrapper failed");
+ return -1;
+ }
+ ret = wpa_pasn_auth_rx(pasn, (const u8 *)mgmt, len, &pasn_data);
+ forced_memzero(pasn_get_ptk(pasn), sizeof(pasn->ptk));
+
+ if (ret < 0) {
+ p2p_dbg(p2p, "P2P PASN: wpa_pasn_auth_rx failed");
+ dev->role = P2P_ROLE_IDLE;
+ }
+
+ } else {
+ ret = p2p_handle_pasn_auth(p2p, dev, mgmt, len, freq);
+ }
+ return ret;
+}
@@ -460,6 +460,31 @@ struct p2p_peer_info {
* p2p_pairing_config - P2P Pairing configuration
*/
struct p2p_pairing_config pairing_config;
+
+ /**
+ * cipher version for Device Identity key generation
+ */
+ u8 dik_cipher_version;
+
+ /**
+ * Device Identity key which is unique for a device
+ */
+ u8 device_identity_key[128];
+
+ /**
+ * Device Identity key lifetime
+ */
+ u32 dik_lifetime;
+
+ /**
+ * password used during group formation post opportunistic pasn auth
+ */
+ char password[100];
+
+ /**
+ * password length. Non zero if valid
+ */
+ u16 password_len;
};
enum p2p_prov_disc_status {
@@ -1255,6 +1280,23 @@ struct p2p_config {
*/
void (*bootstrap_completed)(void *ctx, const u8 *addr, int status,
int freq);
+
+ /**
+ * pasn_send_mgmt - Function handler to transmit a Management frame
+ * @ctx: Callback context from cb_ctx
+ * @data : Frame to transmit
+ * @data_len: Length of frame to transmit
+ * @noack : No ack flag
+ * @freq: Frequency in MHz for the channel on which to transmit
+ * @wait: How many milliseconds to wait for a response frame
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*pasn_send_mgmt)(void *ctx, const u8 *data, size_t data_len,
+ int noack, unsigned int freq, unsigned int wait);
+
+ int (*pasn_update_extra_ies)(void *ctx, const u8 *peer_addr, bool dira);
+
+ int (*pasn_parse_encrypted_data)(void *ctx, const u8 *data, size_t len);
};
@@ -2557,4 +2599,13 @@ int p2p_channel_to_freq(int op_class, int channel);
struct wpabuf * p2p_usd_elems(struct p2p_data *p2p);
void p2p_process_usd_elems(struct p2p_data *p2p, const u8 *ies, u16 ies_len,
const u8 *peer_addr, unsigned int freq);
+int p2p_initiate_pasn_auth(struct p2p_data *p2p, const u8 *addr, int freq);
+int p2p_pasn_auth_rx(struct p2p_data *p2p, const struct ieee80211_mgmt *mgmt,
+ size_t len, int freq);
+int p2p_pasn_update_extra_ies(struct p2p_data *p2p, const u8 *peer_addr,
+ bool dira);
+int p2p_pasn_parse_encrypted_data(struct p2p_data *p2p, const u8 *data,
+ size_t len);
+int p2p_pasn_auth_tx_status(struct p2p_data *p2p, const u8 *data,
+ size_t data_len, u8 acked);
#endif /* P2P_H */
@@ -1017,3 +1017,38 @@ int p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id,
return 0;
}
+
+
+struct wpabuf *p2p_encaps_p2p_vendor_ie(struct p2p_data *p2p,
+ struct wpabuf *subelems, u32 ie_type)
+{
+ struct wpabuf *ie;
+ const u8 *pos, *end;
+ size_t len;
+
+ if (!subelems)
+ return NULL;
+
+ len = wpabuf_len(subelems) + 1000;
+
+ ie = wpabuf_alloc(len);
+ if (!ie)
+ return NULL;
+
+ pos = wpabuf_head(subelems);
+ end = pos + wpabuf_len(subelems);
+
+ while (end > pos) {
+ size_t frag_len = end - pos;
+
+ if (frag_len > 251)
+ frag_len = 251;
+ wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC);
+ wpabuf_put_u8(ie, 4 + frag_len);
+ wpabuf_put_be32(ie, ie_type);
+ wpabuf_put_data(ie, pos, frag_len);
+ pos += frag_len;
+ }
+
+ return ie;
+}
@@ -135,15 +135,14 @@ static const char * p2p_wps_method_str(enum p2p_wps_method wps_method)
}
-static struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p,
- struct p2p_device *peer)
+struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p,
+ struct p2p_device *peer)
{
- struct wpabuf *buf;
- u8 *len;
u8 group_capab;
size_t extra = 0;
u16 pw_id;
bool is_6ghz_capab;
+ struct wpabuf *buf, *buf2, *p2p_ie;
#ifdef CONFIG_WIFI_DISPLAY
if (p2p->wfd_ie_go_neg)
@@ -153,13 +152,16 @@ static struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p,
if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_REQ])
extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_REQ]);
- buf = wpabuf_alloc(1000 + extra);
- if (buf == NULL)
+ buf2 = wpabuf_alloc(1000 + extra);
+ if (!buf2)
return NULL;
- p2p_buf_add_public_action_hdr(buf, P2P_GO_NEG_REQ, peer->dialog_token);
+ p2p_buf_add_public_action_hdr(buf2, P2P_GO_NEG_REQ, peer->dialog_token);
+
+ p2p_ie = wpabuf_alloc(500);
+ if (!p2p_ie)
+ return NULL;
- len = p2p_buf_add_ie_hdr(buf);
group_capab = 0;
if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) {
group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP;
@@ -170,17 +172,17 @@ static struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p,
group_capab |= P2P_GROUP_CAPAB_CROSS_CONN;
if (p2p->cfg->p2p_intra_bss)
group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST;
- p2p_buf_add_capability(buf, p2p->dev_capab &
+ p2p_buf_add_capability(p2p_ie, p2p->dev_capab &
~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY,
group_capab);
- p2p_buf_add_go_intent(buf, (p2p->go_intent << 1) | peer->tie_breaker);
- p2p_buf_add_config_timeout(buf, p2p->go_timeout, p2p->client_timeout);
- p2p_buf_add_listen_channel(buf, p2p->cfg->country, p2p->cfg->reg_class,
+ p2p_buf_add_go_intent(p2p_ie, (p2p->go_intent << 1) | peer->tie_breaker);
+ p2p_buf_add_config_timeout(p2p_ie, p2p->go_timeout, p2p->client_timeout);
+ p2p_buf_add_listen_channel(p2p_ie, p2p->cfg->country, p2p->cfg->reg_class,
p2p->cfg->channel);
if (p2p->ext_listen_interval)
- p2p_buf_add_ext_listen_timing(buf, p2p->ext_listen_period,
+ p2p_buf_add_ext_listen_timing(p2p_ie, p2p->ext_listen_period,
p2p->ext_listen_interval);
- p2p_buf_add_intended_addr(buf, p2p->intended_addr);
+ p2p_buf_add_intended_addr(p2p_ie, p2p->intended_addr);
is_6ghz_capab = is_p2p_6ghz_capable(p2p) &&
p2p_is_peer_6ghz_capab(p2p, peer->info.p2p_device_addr);
if (p2p->num_pref_freq) {
@@ -191,37 +193,41 @@ static struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p,
p2p->num_pref_freq, &pref_chanlist, go);
p2p_channels_dump(p2p, "channel list after filtering",
&pref_chanlist);
- p2p_buf_add_channel_list(buf, p2p->cfg->country,
+ p2p_buf_add_channel_list(p2p_ie, p2p->cfg->country,
&pref_chanlist, is_6ghz_capab);
} else {
- p2p_buf_add_channel_list(buf, p2p->cfg->country,
+ p2p_buf_add_channel_list(p2p_ie, p2p->cfg->country,
&p2p->channels, is_6ghz_capab);
}
- p2p_buf_add_device_info(buf, p2p, peer);
- p2p_buf_add_operating_channel(buf, p2p->cfg->country,
+ p2p_buf_add_device_info(p2p_ie, p2p, peer);
+ p2p_buf_add_operating_channel(p2p_ie, p2p->cfg->country,
p2p->op_reg_class, p2p->op_channel);
- p2p_buf_update_ie_hdr(buf, len);
- p2p_buf_add_pref_channel_list(buf, p2p->pref_freq_list,
+ buf = p2p_encaps_p2p_vendor_ie(p2p, p2p_ie, P2P_IE_VENDOR_TYPE);
+ wpabuf_free(p2p_ie);
+
+ p2p_buf_add_pref_channel_list(buf2, p2p->pref_freq_list,
p2p->num_pref_freq);
/* WPS IE with Device Password ID attribute */
pw_id = p2p_wps_method_pw_id(peer->wps_method);
if (peer->oob_pw_id)
pw_id = peer->oob_pw_id;
- if (p2p_build_wps_ie(p2p, buf, pw_id, 0) < 0) {
+ if (peer && !peer->p2p2 && p2p_build_wps_ie(p2p, buf2, pw_id, 0) < 0) {
p2p_dbg(p2p, "Failed to build WPS IE for GO Negotiation Request");
+ wpabuf_free(buf2);
wpabuf_free(buf);
return NULL;
}
#ifdef CONFIG_WIFI_DISPLAY
if (p2p->wfd_ie_go_neg)
- wpabuf_put_buf(buf, p2p->wfd_ie_go_neg);
+ wpabuf_put_buf(buf2, p2p->wfd_ie_go_neg);
#endif /* CONFIG_WIFI_DISPLAY */
if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_REQ])
- wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_REQ]);
+ wpabuf_put_buf(buf2, p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_REQ]);
+ buf = wpabuf_concat(buf2, buf);
return buf;
}
@@ -292,13 +298,12 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p,
u8 dialog_token, u8 status,
u8 tie_breaker)
{
- struct wpabuf *buf;
- u8 *len;
u8 group_capab;
size_t extra = 0;
u16 pw_id;
bool is_6ghz_capab;
struct p2p_channels pref_chanlist;
+ struct wpabuf *buf, *buf2, *p2p_ie;
p2p_dbg(p2p, "Building GO Negotiation Response");
@@ -310,14 +315,17 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p,
if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_RESP])
extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_RESP]);
- buf = wpabuf_alloc(1000 + extra);
- if (buf == NULL)
+ buf2 = wpabuf_alloc(1000 + extra);
+ if (!buf2)
return NULL;
- p2p_buf_add_public_action_hdr(buf, P2P_GO_NEG_RESP, dialog_token);
+ p2p_buf_add_public_action_hdr(buf2, P2P_GO_NEG_RESP, dialog_token);
- len = p2p_buf_add_ie_hdr(buf);
- p2p_buf_add_status(buf, status);
+ p2p_ie = wpabuf_alloc(500);
+ if (!p2p_ie)
+ return NULL;
+
+ p2p_buf_add_status(p2p_ie, status);
group_capab = 0;
if (peer && peer->go_state == LOCAL_GO) {
if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) {
@@ -331,24 +339,25 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p,
if (p2p->cfg->p2p_intra_bss)
group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST;
}
- p2p_buf_add_capability(buf, p2p->dev_capab &
+ p2p_buf_add_capability(p2p_ie, p2p->dev_capab &
~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY,
group_capab);
- p2p_buf_add_go_intent(buf, (p2p->go_intent << 1) | tie_breaker);
- p2p_buf_add_config_timeout(buf, p2p->go_timeout, p2p->client_timeout);
+ p2p_buf_add_go_intent(p2p_ie, (p2p->go_intent << 1) | tie_breaker);
+ p2p_buf_add_config_timeout(p2p_ie, p2p->go_timeout, p2p->client_timeout);
if (p2p->override_pref_op_class) {
p2p_dbg(p2p, "Override operating channel preference");
- p2p_buf_add_operating_channel(buf, p2p->cfg->country,
+ p2p_buf_add_operating_channel(p2p_ie, p2p->cfg->country,
p2p->override_pref_op_class,
p2p->override_pref_channel);
} else if (peer && peer->go_state == REMOTE_GO && !p2p->num_pref_freq) {
p2p_dbg(p2p, "Omit Operating Channel attribute");
} else {
- p2p_buf_add_operating_channel(buf, p2p->cfg->country,
+ p2p_buf_add_operating_channel(p2p_ie, p2p->cfg->country,
p2p->op_reg_class,
p2p->op_channel);
}
- p2p_buf_add_intended_addr(buf, p2p->intended_addr);
+ p2p_buf_add_intended_addr(p2p_ie, p2p->intended_addr);
+
if (p2p->num_pref_freq) {
bool go = (peer && peer->go_state == LOCAL_GO) ||
p2p->go_intent == 15;
@@ -362,12 +371,12 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p,
p2p->allow_6ghz);
}
if (status || peer == NULL) {
- p2p_buf_add_channel_list(buf, p2p->cfg->country,
+ p2p_buf_add_channel_list(p2p_ie, p2p->cfg->country,
&pref_chanlist, false);
} else if (peer->go_state == REMOTE_GO) {
is_6ghz_capab = is_p2p_6ghz_capable(p2p) &&
p2p_is_peer_6ghz_capab(p2p, peer->info.p2p_device_addr);
- p2p_buf_add_channel_list(buf, p2p->cfg->country,
+ p2p_buf_add_channel_list(p2p_ie, p2p->cfg->country,
&pref_chanlist, is_6ghz_capab);
} else {
struct p2p_channels res;
@@ -376,33 +385,37 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p,
p2p_is_peer_6ghz_capab(p2p, peer->info.p2p_device_addr);
p2p_channels_intersect(&pref_chanlist, &peer->channels,
&res);
- p2p_buf_add_channel_list(buf, p2p->cfg->country, &res,
- is_6ghz_capab);
+ p2p_buf_add_channel_list(p2p_ie, p2p->cfg->country, &res,
+ is_6ghz_capab);
}
- p2p_buf_add_device_info(buf, p2p, peer);
+ p2p_buf_add_device_info(p2p_ie, p2p, peer);
if (peer && peer->go_state == LOCAL_GO) {
- p2p_buf_add_group_id(buf, p2p->cfg->dev_addr, p2p->ssid,
+ p2p_buf_add_group_id(p2p_ie, p2p->cfg->dev_addr, p2p->ssid,
p2p->ssid_len);
}
- p2p_buf_update_ie_hdr(buf, len);
+
+ buf = p2p_encaps_p2p_vendor_ie(p2p, p2p_ie, P2P_IE_VENDOR_TYPE);
+ wpabuf_free(p2p_ie);
/* WPS IE with Device Password ID attribute */
pw_id = p2p_wps_method_pw_id(peer ? peer->wps_method : WPS_NOT_READY);
if (peer && peer->oob_pw_id)
pw_id = peer->oob_pw_id;
- if (p2p_build_wps_ie(p2p, buf, pw_id, 0) < 0) {
+ if (peer && !peer->p2p2 && p2p_build_wps_ie(p2p, buf2, pw_id, 0) < 0) {
p2p_dbg(p2p, "Failed to build WPS IE for GO Negotiation Response");
+ wpabuf_free(buf2);
wpabuf_free(buf);
return NULL;
}
#ifdef CONFIG_WIFI_DISPLAY
if (p2p->wfd_ie_go_neg)
- wpabuf_put_buf(buf, p2p->wfd_ie_go_neg);
+ wpabuf_put_buf(buf2, p2p->wfd_ie_go_neg);
#endif /* CONFIG_WIFI_DISPLAY */
if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_RESP])
- wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_RESP]);
+ wpabuf_put_buf(buf2, p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_RESP]);
+ buf = wpabuf_concat(buf2, buf);
return buf;
}
@@ -801,21 +814,19 @@ void p2p_check_pref_chan(struct p2p_data *p2p, int go,
}
-void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa,
- const u8 *data, size_t len, int rx_freq)
+int p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa,
+ const u8 *data, size_t len, int rx_freq, bool p2p2)
{
struct p2p_device *dev = NULL;
- struct wpabuf *resp;
struct p2p_message msg;
u8 status = P2P_SC_FAIL_INVALID_PARAMS;
int tie_breaker = 0;
- int freq;
p2p_dbg(p2p, "Received GO Negotiation Request from " MACSTR "(freq=%d)",
MAC2STR(sa), rx_freq);
if (p2p_parse(data, len, &msg))
- return;
+ return -1;
if (!msg.capability) {
p2p_dbg(p2p, "Mandatory Capability attribute missing from GO Negotiation Request");
@@ -890,7 +901,7 @@ void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa,
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
p2p_go_neg_failed(p2p, *msg.status);
p2p_parse_free(&msg);
- return;
+ return -1;
}
goto fail;
}
@@ -922,7 +933,7 @@ void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa,
p2p_dbg(p2p, "User has rejected this peer");
status = P2P_SC_FAIL_REJECTED_BY_USER;
} else if (dev == NULL ||
- (dev->wps_method == WPS_NOT_READY &&
+ (dev->wps_method == WPS_NOT_READY && !p2p2 &&
(p2p->authorized_oob_dev_pw_id == 0 ||
p2p->authorized_oob_dev_pw_id !=
msg.dev_password_id))) {
@@ -968,7 +979,7 @@ void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa,
os_memcmp(sa, p2p->cfg->dev_addr, ETH_ALEN) > 0) {
p2p_dbg(p2p, "Do not reply since peer has higher address and GO Neg Request already sent");
p2p_parse_free(&msg);
- return;
+ return -1;
}
if (dev->go_neg_req_sent &&
@@ -976,7 +987,7 @@ void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa,
p2p_dbg(p2p,
"Do not reply since peer is waiting for us to start a new GO Negotiation and GO Neg Request already sent");
p2p_parse_free(&msg);
- return;
+ return -1;
}
go = p2p_go_det(p2p->go_intent, *msg.go_intent);
@@ -993,6 +1004,9 @@ void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa,
goto fail;
}
+ if (p2p2)
+ goto skip;
+
switch (msg.dev_password_id) {
case DEV_PW_REGISTRAR_SPECIFIED:
p2p_dbg(p2p, "PIN from peer Display");
@@ -1059,7 +1073,7 @@ void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa,
status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
goto fail;
}
-
+skip:
if (go && p2p_go_select_channel(p2p, dev, &status) < 0)
goto fail;
@@ -1086,7 +1100,10 @@ void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa,
p2p_set_state(p2p, P2P_GO_NEG);
p2p_clear_timeout(p2p);
dev->dialog_token = msg.dialog_token;
- os_memcpy(dev->intended_addr, msg.intended_addr, ETH_ALEN);
+ if (!is_zero_ether_addr(msg.intended_addr)) {
+ p2p_dbg(p2p, "msg.intended_addr" MACSTR, MAC2STR(msg.intended_addr));
+ os_memcpy(dev->intended_addr, msg.intended_addr, ETH_ALEN);
+ }
p2p->go_neg_peer = dev;
eloop_cancel_timeout(p2p_go_neg_wait_timeout, p2p, NULL);
status = P2P_SC_SUCCESS;
@@ -1095,22 +1112,13 @@ void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa,
fail:
if (dev)
dev->status = status;
- resp = p2p_build_go_neg_resp(p2p, dev, msg.dialog_token, status,
- !tie_breaker);
+ p2p->go_neg_resp = p2p_build_go_neg_resp(p2p, dev, msg.dialog_token,
+ status, !tie_breaker);
+
p2p_parse_free(&msg);
- if (resp == NULL)
- return;
- p2p_dbg(p2p, "Sending GO Negotiation Response");
- if (rx_freq > 0)
- freq = rx_freq;
- else
- freq = p2p_channel_to_freq(p2p->cfg->reg_class,
- p2p->cfg->channel);
- if (freq < 0) {
- p2p_dbg(p2p, "Unknown regulatory class/channel");
- wpabuf_free(resp);
- return;
- }
+ if (!p2p->go_neg_resp)
+ return -1;
+
if (status == P2P_SC_SUCCESS) {
p2p->pending_action_state = P2P_PENDING_GO_NEG_RESPONSE;
dev->flags |= P2P_DEV_WAIT_GO_NEG_CONFIRM;
@@ -1128,13 +1136,38 @@ fail:
} else
p2p->pending_action_state =
P2P_PENDING_GO_NEG_RESPONSE_FAILURE;
- if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr,
- p2p->cfg->dev_addr,
- wpabuf_head(resp), wpabuf_len(resp), 100) < 0) {
- p2p_dbg(p2p, "Failed to send Action frame");
+ return 0;
+}
+
+void p2p_handle_go_neg_req(struct p2p_data *p2p, const u8 *sa, const u8 *data,
+ size_t len, int rx_freq)
+{
+ int freq;
+
+ if (p2p_process_go_neg_req(p2p, sa, data, len, rx_freq, false))
+ return;
+
+ p2p_dbg(p2p, "Sending GO Negotiation Response");
+
+ if (rx_freq > 0)
+ freq = rx_freq;
+ else
+ freq = p2p_channel_to_freq(p2p->cfg->reg_class,
+ p2p->cfg->channel);
+ if (freq < 0) {
+ p2p_dbg(p2p, "Unknown regulatory class/channel");
+ return;
}
- wpabuf_free(resp);
+ if (p2p->go_neg_resp &&
+ p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr,
+ p2p->cfg->dev_addr, wpabuf_head(p2p->go_neg_resp),
+ wpabuf_len(p2p->go_neg_resp), 100) < 0) {
+ p2p_dbg(p2p, "Failed to send Action frame");
+ }
+ wpabuf_free(p2p->go_neg_resp);
+ p2p->go_neg_resp = NULL;
+ return;
}
@@ -1143,12 +1176,11 @@ static struct wpabuf * p2p_build_go_neg_conf(struct p2p_data *p2p,
u8 dialog_token, u8 status,
const u8 *resp_chan, int go)
{
- struct wpabuf *buf;
- u8 *len;
struct p2p_channels res;
u8 group_capab;
size_t extra = 0;
bool is_6ghz_capab;
+ struct wpabuf *buf, *buf2, *p2p_ie;
p2p_dbg(p2p, "Building GO Negotiation Confirm");
@@ -1160,14 +1192,17 @@ static struct wpabuf * p2p_build_go_neg_conf(struct p2p_data *p2p,
if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_CONF])
extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_CONF]);
- buf = wpabuf_alloc(1000 + extra);
- if (buf == NULL)
+ buf2 = wpabuf_alloc(1000 + extra);
+ if (!buf2)
return NULL;
- p2p_buf_add_public_action_hdr(buf, P2P_GO_NEG_CONF, dialog_token);
+ p2p_buf_add_public_action_hdr(buf2, P2P_GO_NEG_CONF, dialog_token);
- len = p2p_buf_add_ie_hdr(buf);
- p2p_buf_add_status(buf, status);
+ p2p_ie = wpabuf_alloc(500);
+ if (!p2p_ie)
+ return NULL;
+
+ p2p_buf_add_status(p2p_ie, status);
group_capab = 0;
if (peer->go_state == LOCAL_GO) {
if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) {
@@ -1181,40 +1216,44 @@ static struct wpabuf * p2p_build_go_neg_conf(struct p2p_data *p2p,
if (p2p->cfg->p2p_intra_bss)
group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST;
}
- p2p_buf_add_capability(buf, p2p->dev_capab &
+ p2p_buf_add_capability(p2p_ie, p2p->dev_capab &
~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY,
group_capab);
if (go || resp_chan == NULL)
- p2p_buf_add_operating_channel(buf, p2p->cfg->country,
+ p2p_buf_add_operating_channel(p2p_ie, p2p->cfg->country,
p2p->op_reg_class,
p2p->op_channel);
else
- p2p_buf_add_operating_channel(buf, (const char *) resp_chan,
+ p2p_buf_add_operating_channel(p2p_ie, (const char *) resp_chan,
resp_chan[3], resp_chan[4]);
p2p_channels_intersect(&p2p->channels, &peer->channels, &res);
is_6ghz_capab = is_p2p_6ghz_capable(p2p) &&
p2p_is_peer_6ghz_capab(p2p, peer->info.p2p_device_addr);
- p2p_buf_add_channel_list(buf, p2p->cfg->country, &res, is_6ghz_capab);
+ p2p_buf_add_channel_list(p2p_ie, p2p->cfg->country, &res, is_6ghz_capab);
if (go) {
- p2p_buf_add_group_id(buf, p2p->cfg->dev_addr, p2p->ssid,
+ p2p_buf_add_group_id(p2p_ie, p2p->cfg->dev_addr, p2p->ssid,
p2p->ssid_len);
}
- p2p_buf_update_ie_hdr(buf, len);
+
+ buf = p2p_encaps_p2p_vendor_ie(p2p, p2p_ie, P2P_IE_VENDOR_TYPE);
+ wpabuf_free(p2p_ie);
#ifdef CONFIG_WIFI_DISPLAY
if (p2p->wfd_ie_go_neg)
- wpabuf_put_buf(buf, p2p->wfd_ie_go_neg);
+ wpabuf_put_buf(buf2, p2p->wfd_ie_go_neg);
#endif /* CONFIG_WIFI_DISPLAY */
if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_CONF])
- wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_CONF]);
+ wpabuf_put_buf(buf2, p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_CONF]);
+
+ buf = wpabuf_concat(buf2, buf);
return buf;
}
-void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
- const u8 *data, size_t len, int rx_freq)
+int p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa, const u8 *data,
+ size_t len, int rx_freq, bool p2p2)
{
struct p2p_device *dev;
int go = -1;
@@ -1225,20 +1264,20 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
p2p_dbg(p2p, "Received GO Negotiation Response from " MACSTR
" (freq=%d)", MAC2STR(sa), rx_freq);
dev = p2p_get_device(p2p, sa);
- if (dev == NULL || dev->wps_method == WPS_NOT_READY ||
+ if (dev == NULL || (!p2p2 && dev->wps_method == WPS_NOT_READY) ||
dev != p2p->go_neg_peer) {
p2p_dbg(p2p, "Not ready for GO negotiation with " MACSTR,
MAC2STR(sa));
- return;
+ return -1;
}
if (p2p_parse(data, len, &msg))
- return;
+ return -1;
if (!(dev->flags & P2P_DEV_WAIT_GO_NEG_RESPONSE)) {
p2p_dbg(p2p, "Was not expecting GO Negotiation Response - ignore");
p2p_parse_free(&msg);
- return;
+ return -1;
}
dev->flags &= ~P2P_DEV_WAIT_GO_NEG_RESPONSE;
p2p_update_peer_6ghz_capab(dev, &msg);
@@ -1247,7 +1286,7 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
p2p_dbg(p2p, "Unexpected Dialog Token %u (expected %u)",
msg.dialog_token, dev->dialog_token);
p2p_parse_free(&msg);
- return;
+ return -1;
}
if (!msg.status) {
@@ -1276,7 +1315,7 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
}
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
p2p_parse_free(&msg);
- return;
+ return -1;
}
if (!msg.capability) {
@@ -1377,6 +1416,9 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
} else
dev->oper_freq = 0;
+ if (p2p2)
+ goto skip;
+
switch (msg.dev_password_id) {
case DEV_PW_REGISTRAR_SPECIFIED:
p2p_dbg(p2p, "PIN from peer Display");
@@ -1432,6 +1474,7 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
goto fail;
}
+skip:
if (go && p2p_go_select_channel(p2p, dev, &status) < 0)
goto fail;
@@ -1446,7 +1489,10 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
p2p_clear_timeout(p2p);
p2p_dbg(p2p, "GO Negotiation with " MACSTR, MAC2STR(sa));
- os_memcpy(dev->intended_addr, msg.intended_addr, ETH_ALEN);
+ if (!is_zero_ether_addr(msg.intended_addr)) {
+ p2p_dbg(p2p, "msg.intended_addr" MACSTR, MAC2STR(msg.intended_addr));
+ os_memcpy(dev->intended_addr, msg.intended_addr, ETH_ALEN);
+ }
fail:
/* Store GO Negotiation Confirmation to allow retransmission */
@@ -1454,15 +1500,15 @@ fail:
dev->go_neg_conf = p2p_build_go_neg_conf(p2p, dev, msg.dialog_token,
status, msg.operating_channel,
go);
+ p2p->go_neg_conf = wpabuf_dup(dev->go_neg_conf);
p2p_parse_free(&msg);
- if (dev->go_neg_conf == NULL)
- return;
- p2p_dbg(p2p, "Sending GO Negotiation Confirm");
+
if (status == P2P_SC_SUCCESS) {
p2p->pending_action_state = P2P_PENDING_GO_NEG_CONFIRM;
dev->go_state = go ? LOCAL_GO : REMOTE_GO;
} else
p2p->pending_action_state = P2P_NO_PENDING_ACTION;
+
if (rx_freq > 0)
freq = rx_freq;
else
@@ -1471,6 +1517,36 @@ fail:
dev->go_neg_conf_freq = freq;
dev->go_neg_conf_sent = 0;
+ if (status != P2P_SC_SUCCESS) {
+ p2p_dbg(p2p, "GO Negotiation failed");
+ p2p_go_neg_failed(p2p, status);
+ }
+ return 0;
+}
+
+void p2p_handle_go_neg_resp(struct p2p_data *p2p, const u8 *sa, const u8 *data,
+ size_t len, int rx_freq)
+{
+ int freq;
+ struct p2p_device *dev;
+
+ dev = p2p_get_device(p2p, sa);
+ if (dev == NULL || dev->wps_method == WPS_NOT_READY ||
+ dev != p2p->go_neg_peer) {
+ p2p_dbg(p2p, "Not ready for GO negotiation with " MACSTR,
+ MAC2STR(sa));
+ return;
+ }
+
+ if (p2p_process_go_neg_resp(p2p, sa, data, len, rx_freq, false))
+ return;
+
+ p2p_dbg(p2p, "Sending GO Negotiation Confirm");
+ if (rx_freq > 0)
+ freq = rx_freq;
+ else
+ freq = dev->listen_freq;
+
if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr, sa,
wpabuf_head(dev->go_neg_conf),
wpabuf_len(dev->go_neg_conf), 50) < 0) {
@@ -1479,15 +1555,16 @@ fail:
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
} else
dev->go_neg_conf_sent++;
- if (status != P2P_SC_SUCCESS) {
- p2p_dbg(p2p, "GO Negotiation failed");
- p2p_go_neg_failed(p2p, status);
- }
+
+
+ wpabuf_free(p2p->go_neg_conf);
+ p2p->go_neg_conf = NULL;
+ return;
}
-void p2p_process_go_neg_conf(struct p2p_data *p2p, const u8 *sa,
- const u8 *data, size_t len)
+void p2p_handle_go_neg_conf(struct p2p_data *p2p, const u8 *sa,
+ const u8 *data, size_t len, bool p2p2)
{
struct p2p_device *dev;
struct p2p_message msg;
@@ -1495,7 +1572,7 @@ void p2p_process_go_neg_conf(struct p2p_data *p2p, const u8 *sa,
p2p_dbg(p2p, "Received GO Negotiation Confirm from " MACSTR,
MAC2STR(sa));
dev = p2p_get_device(p2p, sa);
- if (dev == NULL || dev->wps_method == WPS_NOT_READY ||
+ if (dev == NULL || (!p2p2 && dev->wps_method == WPS_NOT_READY) ||
dev != p2p->go_neg_peer) {
p2p_dbg(p2p, "Not ready for GO negotiation with " MACSTR,
MAC2STR(sa));
@@ -42,6 +42,13 @@ enum p2p_go_state {
};
+/* Enumeration for P2P device current role */
+enum p2p_role {
+ P2P_ROLE_IDLE = 0,
+ P2P_ROLE_PAIRING_INITIATOR,
+ P2P_ROLE_PAIRING_RESPONDER,
+};
+
/**
* struct bootstrap_params - P2P Device bootstrap request params
*/
@@ -193,6 +200,22 @@ struct p2p_device {
* password length. Non zero if valid
*/
u16 password_len;
+
+ /* pasn data structure */
+ struct pasn_data *pasn;
+
+ /* device role */
+ enum p2p_role role;
+
+ /**
+ * password used during group formation post opportunistic pasn auth
+ */
+ char dev_password[100];
+
+ /**
+ * password length. Non zero if valid
+ */
+ u16 dev_password_len;
};
struct p2p_sd_query {
@@ -637,6 +660,29 @@ struct p2p_data {
bool allow_6ghz;
struct p2p_pairing_info *pairing_info;
+ /*p2p pairing initiator pmksa cache list */
+ struct rsn_pmksa_cache *initiator_pmksa;
+ /* p2p pairing responder pmksa cache list */
+ struct rsn_pmksa_cache *responder_pmksa;
+ /**
+ * go_neg_resp - GO Negotiation Response frame
+ */
+ struct wpabuf *go_neg_resp;
+
+ /**
+ * go_neg_conf - GO Negotiation Confirmation frame
+ */
+ struct wpabuf *go_neg_conf;
+
+ /**
+ * invitation_req - Invitation request frame
+ */
+ struct wpabuf *invitation_req;
+
+ /**
+ * invitation_resp - Invitation Response frame
+ */
+ struct wpabuf *invitation_resp;
};
/**
@@ -749,6 +795,12 @@ struct p2p_message {
const u8 *pbma_info;
size_t pbma_info_len;
+
+ const u8 *action_frame_wrapper;
+ size_t action_frame_wrapper_len;
+
+ const u8 *dira;
+ size_t dira_len;
};
@@ -889,6 +941,8 @@ int p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id,
void p2p_buf_add_pref_channel_list(struct wpabuf *buf,
const struct weighted_pcl *pref_freq_list,
unsigned int size);
+struct wpabuf *p2p_encaps_p2p_vendor_ie(struct p2p_data *p2p,
+ struct wpabuf *subelems, u32 ie_type);
/* p2p_sd.c */
struct p2p_sd_query * p2p_pending_sd_req(struct p2p_data *p2p,
@@ -905,15 +959,21 @@ void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa,
int p2p_start_sd(struct p2p_data *p2p, struct p2p_device *dev);
/* p2p_go_neg.c */
+struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p,
+ struct p2p_device *peer);
int p2p_peer_channels_check(struct p2p_data *p2p, struct p2p_channels *own,
struct p2p_device *dev,
const u8 *channel_list, size_t channel_list_len);
-void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa,
- const u8 *data, size_t len, int rx_freq);
-void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
- const u8 *data, size_t len, int rx_freq);
-void p2p_process_go_neg_conf(struct p2p_data *p2p, const u8 *sa,
- const u8 *data, size_t len);
+void p2p_handle_go_neg_req(struct p2p_data *p2p, const u8 *sa, const u8 *data,
+ size_t len, int rx_freq);
+void p2p_handle_go_neg_resp(struct p2p_data *p2p, const u8 *sa, const u8 *data,
+ size_t len, int rx_freq);
+void p2p_handle_go_neg_conf(struct p2p_data *p2p, const u8 *sa, const u8 *data,
+ size_t len, bool p2p2);
+int p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa, const u8 *data,
+ size_t len, int rx_freq, bool p2p2);
+int p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa, const u8 *data,
+ size_t len, int rx_freq, bool p2p2);
int p2p_connect_send(struct p2p_data *p2p, struct p2p_device *dev);
u16 p2p_wps_method_pw_id(enum p2p_wps_method wps_method);
void p2p_reselect_channel(struct p2p_data *p2p,
@@ -934,10 +994,14 @@ void p2p_process_pcea(struct p2p_data *p2p, struct p2p_message *msg,
struct p2p_device *dev);
/* p2p_invitation.c */
-void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
- const u8 *data, size_t len, int rx_freq);
+void p2p_handle_invitation_req(struct p2p_data *p2p, const u8 *sa,
+ const u8 *data, size_t len, int rx_freq);
+void p2p_handle_invitation_resp(struct p2p_data *p2p, const u8 *sa,
+ const u8 *data, size_t len);
+int p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
+ const u8 *data, size_t len, int rx_freq);
void p2p_process_invitation_resp(struct p2p_data *p2p, const u8 *sa,
- const u8 *data, size_t len);
+ const u8 *data, size_t len);
int p2p_invite_send(struct p2p_data *p2p, struct p2p_device *dev,
const u8 *go_dev_addr, int dev_pw_id);
void p2p_invitation_req_cb(struct p2p_data *p2p, int success);
@@ -999,6 +1063,8 @@ void p2p_pref_channel_filter(const struct p2p_channels *a,
struct p2p_channels *res, bool go);
void p2p_sd_query_cb(struct p2p_data *p2p, int success);
+void p2p_pasn_initialize(struct p2p_data *p2p, struct p2p_device *dev,
+ const u8 *addr, int freq);
void p2p_dbg(struct p2p_data *p2p, const char *fmt, ...)
PRINTF_FORMAT(2, 3);
@@ -181,14 +181,12 @@ static struct wpabuf * p2p_build_invitation_resp(struct p2p_data *p2p,
}
-void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
- const u8 *data, size_t len, int rx_freq)
+int p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
+ const u8 *data, size_t len, int rx_freq)
{
struct p2p_device *dev;
struct p2p_message msg;
- struct wpabuf *resp = NULL;
u8 status = P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE;
- int freq;
int go = 0;
u8 group_bssid[ETH_ALEN], *bssid;
int op_freq = 0;
@@ -202,7 +200,7 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
MAC2STR(sa), rx_freq);
if (p2p_parse(data, len, &msg))
- return;
+ return -1;
dev = p2p_get_device(p2p, sa);
if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
@@ -385,21 +383,11 @@ fail:
bssid = group_bssid;
else
bssid = NULL;
- resp = p2p_build_invitation_resp(p2p, dev, msg.dialog_token, status,
- bssid, reg_class, channel, channels);
-
- if (resp == NULL)
- goto out;
-
- if (rx_freq > 0)
- freq = rx_freq;
- else
- freq = p2p_channel_to_freq(p2p->cfg->reg_class,
- p2p->cfg->channel);
- if (freq < 0) {
- p2p_dbg(p2p, "Unknown regulatory class/channel");
- goto out;
- }
+ p2p->invitation_resp = p2p_build_invitation_resp(p2p, dev,
+ msg.dialog_token,
+ status, bssid,
+ reg_class, channel,
+ channels);
/*
* Store copy of invitation data to be used when processing TX status
@@ -424,17 +412,38 @@ fail:
}
p2p->inv_status = status;
p2p->inv_op_freq = op_freq;
+ p2p_parse_free(&msg);
+ return 0;
+}
+
+
+void p2p_handle_invitation_req(struct p2p_data *p2p, const u8 *sa,
+ const u8 *data, size_t len, int rx_freq)
+{
+ int freq;
+
+ if (p2p_process_invitation_req(p2p, sa, data, len, rx_freq))
+ return;
+
+ if (rx_freq > 0)
+ freq = rx_freq;
+ else
+ freq = p2p_channel_to_freq(p2p->cfg->reg_class,
+ p2p->cfg->channel);
+ if (freq < 0)
+ p2p_dbg(p2p, "Unknown regulatory class/channel");
p2p->pending_action_state = P2P_PENDING_INVITATION_RESPONSE;
- if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr,
+ if (p2p->invitation_resp &&
+ p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr,
p2p->cfg->dev_addr,
- wpabuf_head(resp), wpabuf_len(resp), 50) < 0) {
+ wpabuf_head(p2p->invitation_resp),
+ wpabuf_len(p2p->invitation_resp), 50) < 0)
p2p_dbg(p2p, "Failed to send Action frame");
- }
-out:
- wpabuf_free(resp);
- p2p_parse_free(&msg);
+ wpabuf_free(p2p->invitation_resp);
+ p2p->invitation_resp = NULL;
+ return;
}
@@ -437,6 +437,26 @@ static int p2p_parse_attribute(u8 id, const u8 *data, u16 len,
msg->pbma_info_len = len;
wpa_printf(MSG_DEBUG, "P2P: * PBMA (length=%u)", len);
break;
+ case P2P_ATTR_ACTION_FRAME_WRAPPER:
+ if (len < 2) {
+ wpa_printf(MSG_DEBUG, "P2P: Too short Action frame (length %d)",
+ len);
+ return -1;
+ }
+ msg->action_frame_wrapper = data;
+ msg->action_frame_wrapper_len = len;
+ wpa_printf(MSG_DEBUG, "P2P: * Action frame wrapper (length=%u)", len);
+ break;
+ case P2P_ATTR_DEVICE_IDENTITY_RESOLUTION:
+ if (len < 2) {
+ wpa_printf(MSG_DEBUG, "P2P: Too short DIRA (length %d)",
+ len);
+ return -1;
+ }
+ msg->dira = data;
+ msg->dira_len = len;
+ wpa_printf(MSG_DEBUG, "P2P: * DIRA (length=%u)", len);
+ break;
default:
wpa_printf(MSG_DEBUG, "P2P: Skipped unknown attribute %d "
"(length %d)", id, len);
@@ -815,6 +815,10 @@ static void p2p_process_prov_disc_bootstrap_req(struct p2p_data *p2p,
wpa_printf(MSG_ERROR, "Bootstrap received %d", bootstrap);
+ if (status == P2P_SC_SUCCESS) {
+ dev->role = P2P_ROLE_PAIRING_RESPONDER;
+ p2p_pasn_initialize(p2p, dev, sa, rx_freq);
+ }
out:
/*
* Send PD Bootstrapping Response for the PD Request
@@ -55,6 +55,7 @@ struct pasn_data {
int rsn_pairwise;
u16 rsnxe_capab;
const u8 *rsnxe_ie;
+ size_t rsnxe_ie_len;
bool custom_pmkid_valid;
u8 custom_pmkid[PMKID_LEN];
@@ -66,6 +67,7 @@ struct pasn_data {
size_t extra_ies_len;
/* External modules do not access below variables */
+ size_t kek_len;
u16 group;
bool secure_ltf;
int freq;
@@ -129,6 +131,8 @@ struct pasn_data {
struct os_reltime last_comeback_key_update;
u16 comeback_idx;
u16 *comeback_pending_idx;
+ struct wpabuf *action_frame_wrapper;
+ struct wpabuf *frame;
/**
* send_mgmt - Function handler to transmit a Management frame
@@ -150,6 +154,10 @@ struct pasn_data {
*/
int (*validate_custom_pmkid)(void *ctx, const u8 *addr,
const u8 *pmkid);
+
+ int (*update_extra_ies)(void *ctx, const u8 *peer_addr, bool dira);
+
+ int (*parse_encrypted_data)(void *ctx, const u8 *data, size_t len);
};
/* Initiator */
@@ -202,9 +210,14 @@ void pasn_set_peer_addr(struct pasn_data *pasn, const u8 *addr);
void pasn_set_bssid(struct pasn_data *pasn, const u8 *addr);
void pasn_set_initiator_pmksa(struct pasn_data *pasn,
struct rsn_pmksa_cache *pmksa);
-void pasn_set_responder_pmksa(struct pasn_data *pasn,
- struct rsn_pmksa_cache *pmksa);
int pasn_set_pt(struct pasn_data *pasn, struct sae_pt *pt);
+struct rsn_pmksa_cache * pasn_initiator_pmksa_cache_init(void);
+void pasn_initiator_pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa);
+int pasn_initiator_pmksa_cache_add(struct rsn_pmksa_cache *pmksa, u8 *own_addr,
+ u8 *bssid, u8 *pmk, size_t pmk_len);
+int pasn_initiator_pmksa_cache_get(struct rsn_pmksa_cache *pmksa, u8 *bssid,
+ u8 *pmkid, u8 *pmk, size_t *pmk_len);
+void pasn_initiator_pmksa_cache_flush(struct rsn_pmksa_cache *pmksa);
/* Responder */
void pasn_set_password(struct pasn_data *pasn, const char *password);
@@ -215,6 +228,15 @@ void pasn_set_rsnxe_ie(struct pasn_data *pasn, const u8 *rsnxe_ie);
void pasn_set_custom_pmkid(struct pasn_data *pasn, const u8 *pmkid);
int pasn_set_extra_ies(struct pasn_data *pasn, const u8 *extra_ies,
size_t extra_ies_len);
+void pasn_set_responder_pmksa(struct pasn_data *pasn,
+ struct rsn_pmksa_cache *pmksa);
+struct rsn_pmksa_cache * pasn_responder_pmksa_cache_init(void);
+void pasn_responder_pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa);
+int pasn_responder_pmksa_cache_add(struct rsn_pmksa_cache *pmksa, u8 *own_addr,
+ u8 *bssid, u8 *pmk, size_t pmk_len);
+int pasn_responder_pmksa_cache_get(struct rsn_pmksa_cache *pmksa, u8 *bssid,
+ u8 *pmkid, u8 *pmk, size_t *pmk_len);
+void pasn_responder_pmksa_cache_flush(struct rsn_pmksa_cache *pmksa);
int pasn_get_akmp(struct pasn_data *pasn);
int pasn_get_cipher(struct pasn_data *pasn);
@@ -26,6 +26,50 @@
#include "pasn_common.h"
+struct rsn_pmksa_cache * pasn_initiator_pmksa_cache_init(void)
+{
+ return pmksa_cache_init(NULL, NULL, NULL, NULL, NULL);
+}
+
+
+void pasn_initiator_pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa)
+{
+ return pmksa_cache_deinit(pmksa);
+}
+
+
+int pasn_initiator_pmksa_cache_add(struct rsn_pmksa_cache *pmksa, u8 *own_addr,
+ u8 *bssid, u8 *pmk, size_t pmk_len)
+{
+ if (pmksa_cache_add(pmksa, pmk, pmk_len, NULL, NULL, 0, bssid, own_addr,
+ NULL, WPA_KEY_MGMT_SAE, 0))
+ return 0;
+ return -1;
+}
+
+
+int pasn_initiator_pmksa_cache_get(struct rsn_pmksa_cache *pmksa, u8 *bssid,
+ u8 *pmkid, u8 *pmk, size_t *pmk_len)
+{
+ struct rsn_pmksa_cache_entry *entry;
+
+ entry = pmksa_cache_get(pmksa, bssid, NULL, NULL, NULL, 0);
+ if (entry) {
+ os_memcpy(pmkid, entry->pmkid, PMKID_LEN);
+ os_memcpy(pmk, entry->pmk, entry->pmk_len);
+ *pmk_len = entry->pmk_len;
+ return 0;
+ }
+ return -1;
+}
+
+
+void pasn_initiator_pmksa_cache_flush(struct rsn_pmksa_cache *pmksa)
+{
+ return pmksa_cache_flush(pmksa, NULL, NULL, 0, false);
+}
+
+
void pasn_set_initiator_pmksa(struct pasn_data *pasn,
struct rsn_pmksa_cache *pmksa)
{
@@ -587,7 +631,10 @@ static struct wpabuf * wpas_pasn_build_auth_1(struct pasn_data *pasn,
if (wpa_pasn_add_wrapped_data(buf, wrapped_data_buf) < 0)
goto fail;
- wpa_pasn_add_rsnxe(buf, pasn->rsnxe_capab);
+ if (pasn->rsnxe_ie)
+ wpabuf_put_data(buf, pasn->rsnxe_ie, pasn->rsnxe_ie_len);
+ else
+ wpa_pasn_add_rsnxe(buf, pasn->rsnxe_capab);
wpa_pasn_add_extra_ies(buf, pasn->extra_ies, pasn->extra_ies_len);
@@ -616,11 +663,13 @@ fail:
}
-static struct wpabuf * wpas_pasn_build_auth_3(struct pasn_data *pasn)
+static struct wpabuf * wpas_pasn_build_auth_3(struct pasn_data *pasn,
+ const u8 *mgmt, size_t len)
{
struct wpabuf *buf, *wrapped_data_buf = NULL;
u8 mic[WPA_PASN_MAX_MIC_LEN];
- u8 mic_len, data_len;
+ u8 mic_len;
+ size_t data_len;
const u8 *data;
u8 *ptr;
u8 wrapped_data;
@@ -654,6 +703,11 @@ static struct wpabuf * wpas_pasn_build_auth_3(struct pasn_data *pasn)
wpabuf_free(wrapped_data_buf);
wrapped_data_buf = NULL;
+ if (pasn->update_extra_ies && pasn->cb_ctx)
+ pasn->update_extra_ies(pasn->cb_ctx, pasn->peer_addr, false);
+
+ wpa_pasn_add_extra_ies(buf, pasn->extra_ies, pasn->extra_ies_len);
+
/* Add the MIC */
mic_len = pasn_mic_len(pasn->akmp, pasn->cipher);
wpabuf_put_u8(buf, WLAN_EID_MIC);
@@ -747,13 +801,25 @@ void wpa_pasn_reset(struct pasn_data *pasn)
pasn->derive_kdk = false;
pasn->rsn_ie = NULL;
pasn->rsn_ie_len = 0;
- pasn->rsnxe_ie = NULL;
pasn->custom_pmkid_valid = false;
+ if (pasn->rsnxe_ie) {
+ os_free((u8 *)pasn->rsnxe_ie);
+ pasn->rsnxe_ie = NULL;
+ pasn->rsnxe_ie_len = 0;
+ }
if (pasn->extra_ies) {
os_free((u8 *) pasn->extra_ies);
pasn->extra_ies = NULL;
}
+ if (pasn->action_frame_wrapper) {
+ wpabuf_free(pasn->action_frame_wrapper);
+ pasn->action_frame_wrapper = NULL;
+ }
+ if (pasn->frame) {
+ wpabuf_free(pasn->frame);
+ pasn->frame = NULL;
+ }
}
@@ -928,12 +994,12 @@ static int wpas_pasn_send_auth_1(struct pasn_data *pasn, const u8 *own_addr,
wpabuf_head(frame), wpabuf_len(frame), 0,
pasn->freq, 1000);
- wpabuf_free(frame);
if (ret) {
wpa_printf(MSG_DEBUG, "PASN: Failed sending 1st auth frame");
+ wpabuf_free(frame);
goto fail;
}
-
+ pasn->frame = frame;
return 0;
fail:
@@ -1233,7 +1299,7 @@ int wpa_pasn_auth_rx(struct pasn_data *pasn, const u8 *data, size_t len,
pasn->own_addr, pasn->peer_addr,
wpabuf_head(secret), wpabuf_len(secret),
&pasn->ptk, pasn->akmp, pasn->cipher,
- pasn->kdk_len);
+ pasn->kdk_len, pasn->kek_len);
if (ret) {
wpa_printf(MSG_DEBUG, "PASN: Failed to derive PTK");
goto fail;
@@ -1323,7 +1389,10 @@ int wpa_pasn_auth_rx(struct pasn_data *pasn, const u8 *data, size_t len,
wpa_printf(MSG_DEBUG, "PASN: Success verifying Authentication frame");
- frame = wpas_pasn_build_auth_3(pasn);
+ if (pasn->parse_encrypted_data && pasn->cb_ctx)
+ pasn->parse_encrypted_data(pasn->cb_ctx, data, len);
+
+ frame = wpas_pasn_build_auth_3(pasn, data, len);
if (!frame) {
wpa_printf(MSG_DEBUG, "PASN: Failed building 3rd auth frame");
goto fail;
@@ -1332,12 +1401,13 @@ int wpa_pasn_auth_rx(struct pasn_data *pasn, const u8 *data, size_t len,
ret = pasn->send_mgmt(pasn->cb_ctx,
wpabuf_head(frame), wpabuf_len(frame), 0,
pasn->freq, 100);
- wpabuf_free(frame);
if (ret) {
wpa_printf(MSG_DEBUG, "PASN: Failed sending 3st auth frame");
+ wpabuf_free(frame);
goto fail;
}
+ pasn->frame = frame;
wpa_printf(MSG_DEBUG, "PASN: Success sending last frame. Store PTK");
pasn->status = WLAN_STATUS_SUCCESS;
@@ -26,6 +26,50 @@
#include "pasn_common.h"
+struct rsn_pmksa_cache * pasn_responder_pmksa_cache_init(void)
+{
+ return pmksa_cache_auth_init(NULL, NULL);
+}
+
+
+void pasn_responder_pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa)
+{
+ return pmksa_cache_auth_deinit(pmksa);
+}
+
+
+int pasn_responder_pmksa_cache_add(struct rsn_pmksa_cache *pmksa, u8 *own_addr,
+ u8 *bssid, u8 *pmk, size_t pmk_len)
+{
+ if (pmksa_cache_auth_add(pmksa, pmk, pmk_len, NULL, NULL, 0, own_addr,
+ bssid, 0, NULL, WPA_KEY_MGMT_SAE))
+ return 0;
+ return -1;
+}
+
+
+int pasn_responder_pmksa_cache_get(struct rsn_pmksa_cache *pmksa, u8 *bssid,
+ u8 *pmkid, u8 *pmk, size_t *pmk_len)
+{
+ struct rsn_pmksa_cache_entry *entry;
+
+ entry = pmksa_cache_auth_get(pmksa, bssid, NULL);
+ if (entry) {
+ os_memcpy(pmkid, entry->pmkid, PMKID_LEN);
+ os_memcpy(pmk, entry->pmk, entry->pmk_len);
+ *pmk_len = entry->pmk_len;
+ return 0;
+ }
+ return -1;
+}
+
+
+void pasn_responder_pmksa_cache_flush(struct rsn_pmksa_cache *pmksa)
+{
+ return pmksa_cache_auth_flush(pmksa);
+}
+
+
void pasn_set_responder_pmksa(struct pasn_data *pasn,
struct rsn_pmksa_cache *pmksa)
{
@@ -349,7 +393,7 @@ pasn_derive_keys(struct pasn_data *pasn,
ret = pasn_pmk_to_ptk(pmk, pmk_len, peer_addr, own_addr,
wpabuf_head(secret), wpabuf_len(secret),
&pasn->ptk, pasn->akmp,
- pasn->cipher, pasn->kdk_len);
+ pasn->cipher, pasn->kdk_len, pasn->kek_len);
if (ret) {
wpa_printf(MSG_DEBUG, "PASN: Failed to derive PTK");
return -1;
@@ -414,7 +458,7 @@ static void handle_auth_pasn_comeback(struct pasn_data *pasn,
"PASN: comeback: STA=" MACSTR, MAC2STR(peer_addr));
ret = pasn->send_mgmt(pasn->cb_ctx, wpabuf_head_u8(buf),
- wpabuf_len(buf), 0, 0, 0);
+ wpabuf_len(buf), 0, pasn->freq, 0);
if (ret)
wpa_printf(MSG_INFO, "PASN: Failed to send comeback frame 2");
@@ -502,6 +546,10 @@ int handle_auth_pasn_resp(struct pasn_data *pasn, const u8 *own_addr,
if (rsnxe_ie)
wpabuf_put_data(buf, rsnxe_ie, 2 + rsnxe_ie[1]);
+ if (pasn->update_extra_ies && pasn->cb_ctx)
+ pasn->update_extra_ies(pasn->cb_ctx, peer_addr,
+ pmkid ? true : false);
+
wpa_pasn_add_extra_ies(buf, pasn->extra_ies, pasn->extra_ies_len);
/* Add the mic */
@@ -579,12 +627,14 @@ done:
MAC2STR(peer_addr));
ret = pasn->send_mgmt(pasn->cb_ctx, wpabuf_head_u8(buf),
- wpabuf_len(buf), 0, 0, 0);
- if (ret)
+ wpabuf_len(buf), 0, pasn->freq, 0);
+ if (ret) {
wpa_printf(MSG_INFO, "send_auth_reply: Send failed");
+ goto fail;
+ }
wpabuf_free(rsn_buf);
- wpabuf_free(buf);
+ pasn->frame = buf;
return ret;
fail:
wpabuf_free(wrapped_data_buf);
@@ -1020,6 +1070,9 @@ int handle_auth_pasn_3(struct pasn_data *pasn, const u8 *own_addr,
wpabuf_free(wrapped_data);
}
+ if (pasn->parse_encrypted_data && pasn->cb_ctx)
+ pasn->parse_encrypted_data(pasn->cb_ctx, (const u8 *) mgmt, len);
+
wpa_printf(MSG_INFO,
"PASN: Success handling transaction == 3. Store PTK");
return 0;
@@ -5952,6 +5952,35 @@ static void wpas_link_reconfig(struct wpa_supplicant *wpa_s)
}
+int wpas_pasn_auth(struct wpa_supplicant *wpa_s,
+ const struct ieee80211_mgmt *mgmt, size_t len, int freq)
+{
+ int ret = 0;
+ struct ieee802_11_elems elems;
+
+ if (len < 24) {
+ wpa_printf(MSG_DEBUG, "nl80211: Too short management frame");
+ return -2;
+ }
+
+ if (ieee802_11_parse_elems(mgmt->u.auth.variable,
+ len - offsetof(struct ieee80211_mgmt,
+ u.auth.variable),
+ &elems, 1) == ParseFailed) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Failed parsing Authentication frame");
+ return -2;
+ }
+
+ if (!elems.p2p2_ie || !elems.p2p2_ie_len)
+ ret = wpas_pasn_auth_rx(wpa_s, mgmt, len);
+ else
+ ret = wpas_p2p_pasn_auth_rx(wpa_s, mgmt, len, freq);
+
+ return ret;
+}
+
+
void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
union wpa_event_data *data)
{
@@ -6182,11 +6211,22 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
#endif /* CONFIG_WNM */
#ifdef CONFIG_PASN
if (data->tx_status.type == WLAN_FC_TYPE_MGMT &&
- data->tx_status.stype == WLAN_FC_STYPE_AUTH &&
- wpas_pasn_auth_tx_status(wpa_s, data->tx_status.data,
- data->tx_status.data_len,
- data->tx_status.ack) == 0)
- break;
+ data->tx_status.stype == WLAN_FC_STYPE_AUTH) {
+ if (!wpa_s->pasn_auth_work &&
+ wpa_s->p2p_pasn_auth_work) {
+ if (wpas_p2p_pasn_auth_tx_status(wpa_s,
+ data->tx_status.data,
+ data->tx_status.data_len,
+ data->tx_status.ack) == 0)
+ break;
+ } else {
+ if (wpas_pasn_auth_tx_status(wpa_s,
+ data->tx_status.data,
+ data->tx_status.data_len,
+ data->tx_status.ack) == 0)
+ break;
+ }
+ }
#endif /* CONFIG_PASN */
#ifdef CONFIG_AP
if (wpa_s->ap_iface == NULL) {
@@ -6458,8 +6498,8 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
}
#ifdef CONFIG_PASN
if (stype == WLAN_FC_STYPE_AUTH &&
- wpas_pasn_auth_rx(wpa_s, mgmt,
- data->rx_mgmt.frame_len) != -2)
+ wpas_pasn_auth(wpa_s, mgmt, data->rx_mgmt.frame_len,
+ data->rx_mgmt.freq) != -2)
break;
#endif /* CONFIG_PASN */
@@ -38,7 +38,6 @@
#include "p2p_supplicant.h"
#include "wifi_display.h"
-
/*
* How many times to try to scan to find the GO before giving up on join
* request.
@@ -1716,6 +1715,28 @@ static void wpas_send_action_done(void *ctx)
offchannel_send_action_done(wpa_s);
}
+struct wpa_p2p_pasn_auth_work {
+ u8 peer_addr[ETH_ALEN];
+ bool verify;
+ int freq;
+};
+
+
+static void wpas_p2p_pasn_free_auth_work(struct wpa_p2p_pasn_auth_work *awork)
+{
+ os_free(awork);
+}
+
+
+static void wpas_p2p_pasn_cancel_auth_work(struct wpa_supplicant *wpa_s)
+{
+ wpa_printf(MSG_DEBUG, "P2P PASN: Cancel p2p-pasn-start-auth work");
+
+ /* Remove pending/started work */
+ radio_remove_works(wpa_s, "p2p-pasn-start-auth", 0);
+}
+
+
static int wpas_copy_go_neg_results(struct wpa_supplicant *wpa_s,
struct p2p_go_neg_results *params)
@@ -2391,6 +2412,12 @@ static void wpas_p2p_group_formation_timeout(void *eloop_ctx,
void *timeout_ctx)
{
struct wpa_supplicant *wpa_s = eloop_ctx;
+
+ if (wpa_s->p2p_pasn_auth_work) {
+ wpas_p2p_pasn_cancel_auth_work(wpa_s);
+ wpa_s->p2p_pasn_auth_work = NULL;
+ }
+
wpa_printf(MSG_DEBUG, "P2P: Group Formation timed out");
wpas_p2p_group_formation_failed(wpa_s, 0);
}
@@ -2456,6 +2483,11 @@ static void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
wpa_s->roc_waiting_drv_freq = 0;
}
+ if (wpa_s->p2p_pasn_auth_work) {
+ wpas_p2p_pasn_cancel_auth_work(wpa_s);
+ wpa_s->p2p_pasn_auth_work = NULL;
+ }
+
if (res->status) {
wpa_msg_global(wpa_s, MSG_INFO,
P2P_EVENT_GO_NEG_FAILURE "status=%d",
@@ -4822,6 +4854,68 @@ static int wpas_p2p_get_pref_freq_list(void *ctx, int go,
WPA_IF_P2P_CLIENT, len, freq_list);
}
+
+static void wpas_p2p_pasn_auth_start_cb(struct wpa_radio_work *work, int deinit)
+{
+ struct wpa_supplicant *wpa_s = work->wpa_s;
+ struct wpa_p2p_pasn_auth_work *awork = work->ctx;
+ struct p2p_data *p2p = wpa_s->global->p2p;
+ const u8 *peer_addr = NULL;
+
+ if (deinit) {
+ if (!work->started) {
+ eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
+ wpa_s->p2pdev, NULL);
+ }
+ os_free(awork);
+ return;
+ }
+
+ if (!is_zero_ether_addr(awork->peer_addr))
+ peer_addr = awork->peer_addr;
+ if (p2p_initiate_pasn_auth(p2p, peer_addr, awork->freq)) {
+ wpa_printf(MSG_DEBUG,
+ "P2P PASN: Failed to start PASN authentication");
+ goto fail;
+ }
+ eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
+ wpa_s->p2pdev, NULL);
+ eloop_register_timeout(P2P_MAX_INITIAL_CONN_WAIT, 0,
+ wpas_p2p_group_formation_timeout,
+ wpa_s->p2pdev, NULL);
+ wpa_s->p2p_pasn_auth_work = work;
+ return;
+fail:
+ wpas_p2p_pasn_free_auth_work(awork);
+ work->ctx = NULL;
+ radio_work_done(work);
+}
+
+static int wpas_p2p_initiate_pasn_auth(struct wpa_supplicant *wpa_s,
+ const u8 *peer_addr, int freq)
+{
+ struct wpa_p2p_pasn_auth_work *awork;
+
+ wpas_p2p_pasn_cancel_auth_work(wpa_s);
+ wpa_s->p2p_pasn_auth_work = NULL;
+
+ awork = os_zalloc(sizeof(*awork));
+ if (!awork)
+ return -1;
+
+ awork->freq = freq;
+ os_memcpy(awork->peer_addr, peer_addr, ETH_ALEN);
+
+ if (radio_add_work(wpa_s, freq, "p2p-pasn-start-auth", 1,
+ wpas_p2p_pasn_auth_start_cb, awork) < 0) {
+ wpas_p2p_pasn_free_auth_work(awork);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "P2P PASN: Auth work successfully added");
+ return 0;
+}
+
static void wpas_p2p_send_bootstrap_comeback(void *eloop_ctx, void *timeout_ctx)
{
struct wpa_supplicant *wpa_s = eloop_ctx;
@@ -4886,8 +4980,46 @@ static void wpas_bootstrap_completed(void *ctx, const u8 *addr, int status,
if (status)
return;
+
+ wpas_p2p_initiate_pasn_auth(wpa_s, addr, freq);
}
+static int wpas_p2p_pasn_send_mlme(void *ctx, const u8 *data, size_t data_len,
+ int noack, unsigned int freq,
+ unsigned int wait)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+
+ return wpa_drv_send_mlme(wpa_s, data, data_len, noack, freq, wait);
+}
+
+
+static int wpas_p2p_pasn_update_extra_ies(void *ctx, const u8 *peer_addr,
+ bool dira)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ struct p2p_data *p2p = wpa_s->global->p2p;
+
+ return p2p_pasn_update_extra_ies(p2p, peer_addr, dira);
+}
+
+
+static int wpas_p2p_pasn_parse_encrypted_data(void *ctx, const u8 *data,
+ size_t len)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ struct p2p_data *p2p = wpa_s->global->p2p;
+
+ return p2p_pasn_parse_encrypted_data(p2p, data, len);
+}
+
+int wpas_p2p_pasn_auth_tx_status(struct wpa_supplicant *wpa_s, const u8 *data,
+ size_t data_len, u8 acked)
+{
+ struct p2p_data *p2p = wpa_s->global->p2p;
+
+ return p2p_pasn_auth_tx_status(p2p, data, data_len, acked);
+}
int wpas_p2p_mac_setup(struct wpa_supplicant *wpa_s)
{
@@ -5011,6 +5143,9 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
p2p.register_bootstrap_comeback = wpas_p2p_register_bootstrap_comeback;
p2p.bootstrap_req_rx = wpas_bootstrap_req_rx;
p2p.bootstrap_completed = wpas_bootstrap_completed;
+ p2p.pasn_send_mgmt = wpas_p2p_pasn_send_mlme;
+ p2p.pasn_update_extra_ies = wpas_p2p_pasn_update_extra_ies;
+ p2p.pasn_parse_encrypted_data = wpas_p2p_pasn_parse_encrypted_data;
os_memcpy(wpa_s->global->p2p_dev_addr, wpa_s->own_addr, ETH_ALEN);
os_memcpy(p2p.dev_addr, wpa_s->global->p2p_dev_addr, ETH_ALEN);
@@ -10349,3 +10484,14 @@ void wpas_p2p_process_usd_elems(struct wpa_supplicant *wpa_s, const u8 *buf,
return;
p2p_process_usd_elems(p2p, buf, buf_len, peer_addr, freq);
}
+
+int wpas_p2p_pasn_auth_rx(struct wpa_supplicant *wpa_s,
+ const struct ieee80211_mgmt *mgmt, size_t len,
+ int freq)
+{
+ struct p2p_data *p2p = wpa_s->global->p2p;
+
+ if (wpa_s->global->p2p_disabled || !p2p)
+ return -2;
+ return p2p_pasn_auth_rx(p2p, mgmt, len, freq);
+}
@@ -227,7 +227,9 @@ int wpas_p2p_lo_start(struct wpa_supplicant *wpa_s, unsigned int freq,
int wpas_p2p_lo_stop(struct wpa_supplicant *wpa_s);
int wpas_p2p_mac_setup(struct wpa_supplicant *wpa_s);
struct wpabuf * wpas_p2p_usd_elems(struct wpa_supplicant *wpa_s);
-
+int wpas_p2p_pasn_auth_rx(struct wpa_supplicant *wpa_s,
+ const struct ieee80211_mgmt *mgmt, size_t len,
+ int freq);
#else /* CONFIG_P2P */
static inline int
@@ -357,6 +359,12 @@ static inline struct wpabuf * wpas_p2p_usd_elems(struct wpa_supplicant *wpa_s)
{
return NULL;
}
+static int wpas_p2p_pasn_auth_rx(struct wpa_supplicant *wpa_s,
+ const struct ieee80211_mgmt *mgmt, size_t len,
+ int freq)
+{
+ return 0;
+}
#endif /* CONFIG_P2P */
@@ -806,6 +806,11 @@ int wpas_pasn_auth_rx(struct wpa_supplicant *wpa_s,
if (!wpa_s->pasn_auth_work)
return -2;
+ if (pasn->frame) {
+ wpabuf_free(pasn->frame);
+ pasn->frame = NULL;
+ }
+
pasn_register_callbacks(pasn, wpa_s, wpas_pasn_send_mlme, NULL);
ret = wpa_pasn_auth_rx(pasn, (const u8 *) mgmt, len, &pasn_data);
if (ret == 0) {
@@ -1588,6 +1588,9 @@ struct wpa_supplicant {
struct wpa_radio_work *pasn_auth_work;
unsigned int pasn_count;
struct pasn_auth *pasn_params;
+#ifdef CONFIG_P2P
+ struct wpa_radio_work *p2p_pasn_auth_work;
+#endif /* CONFIG_P2P */
#endif /* CONFIG_PASN */
bool is_6ghz_enabled;
@@ -2010,5 +2013,7 @@ bool wpas_ap_link_address(struct wpa_supplicant *wpa_s, const u8 *addr);
void wpas_p2p_process_usd_elems(struct wpa_supplicant *wpa_s, const u8 *buf,
u16 buf_len, const u8 *peer_addr,
unsigned int freq);
+int wpas_p2p_pasn_auth_tx_status(struct wpa_supplicant *wpa_s, const u8 *data,
+ size_t data_len, u8 acked);
#endif /* WPA_SUPPLICANT_I_H */
Add P2P2 support for GO negotiation wrapped in PASN authentication frames as a action wrapper attribute. Signed-off-by: Shivani Baranwal <quic_shivbara@quicinc.com>