@@ -2487,6 +2487,10 @@ static void pasn_fils_auth_resp(struct hostapd_data *hapd,
fils->erp_resp = erp_resp;
ret = handle_auth_pasn_resp(sta->pasn, hapd->own_addr, sta->addr, NULL,
WLAN_STATUS_SUCCESS);
+ if (sta->pasn->frame) {
+ wpabuf_free(sta->pasn->frame);
+ sta->pasn->frame = NULL;
+ }
fils->erp_resp = NULL;
if (ret) {
@@ -2800,6 +2804,8 @@ static void handle_auth_pasn(struct hostapd_data *hapd, struct sta_info *sta,
const struct ieee80211_mgmt *mgmt, size_t len,
u16 trans_seq, u16 status)
{
+ int ret;
+
if (hapd->conf->wpa != WPA_PROTO_RSN) {
wpa_printf(MSG_INFO, "PASN: RSN is not configured");
return;
@@ -2831,9 +2837,15 @@ static void handle_auth_pasn(struct hostapd_data *hapd, struct sta_info *sta,
hapd_initialize_pasn(hapd, sta);
hapd_pasn_update_params(hapd, sta, mgmt, len);
- if (handle_auth_pasn_1(sta->pasn, hapd->own_addr,
- sta->addr, mgmt, len) < 0)
+ ret = handle_auth_pasn_1(sta->pasn, hapd->own_addr, sta->addr,
+ mgmt, len);
+ if (sta->pasn->frame) {
+ wpabuf_free(sta->pasn->frame);
+ sta->pasn->frame = NULL;
+ }
+ if (ret < 0)
ap_free_sta(hapd, sta);
+
} else if (trans_seq == 3) {
if (!sta->pasn) {
wpa_printf(MSG_DEBUG,
@@ -413,6 +413,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;
@@ -141,6 +142,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 */
@@ -15,10 +15,14 @@
#include "common/ieee802_11_common.h"
#include "common/wpa_ctrl.h"
#include "crypto/sha256.h"
+#include "crypto/sha384.h"
#include "crypto/crypto.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);
@@ -242,6 +246,11 @@ void p2p_go_neg_failed(struct p2p_data *p2p, int status)
peer->go_neg_conf = NULL;
p2p->go_neg_peer = NULL;
+#ifdef CONFIG_PASN
+ if (peer->p2p2 && peer->pasn)
+ wpa_pasn_reset(peer->pasn);
+#endif /* CONFIG_PASN */
+
os_memset(&res, 0, sizeof(res));
res.status = status;
os_memcpy(res.peer_device_addr, peer->info.p2p_device_addr, ETH_ALEN);
@@ -959,6 +968,14 @@ static void p2p_device_free(struct p2p_data *p2p, struct p2p_device *dev)
dev->bootstrap_params = NULL;
}
+#ifdef CONFIG_PASN
+ if (dev->pasn) {
+ wpa_pasn_reset(dev->pasn);
+ pasn_data_deinit(dev->pasn);
+ dev->pasn = NULL;
+ }
+#endif /* CONFIG_PASN */
+
wpabuf_free(dev->info.wfd_subelems);
wpabuf_free(dev->info.vendor_elems);
wpabuf_free(dev->go_neg_conf);
@@ -1861,8 +1878,13 @@ void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer)
os_memset(&res, 0, sizeof(res));
res.role_go = go;
+
+ if (is_zero_ether_addr(peer->interface_addr))
+ os_memcpy(peer->interface_addr, peer->intended_addr, ETH_ALEN);
+
os_memcpy(res.peer_device_addr, peer->info.p2p_device_addr, ETH_ALEN);
- os_memcpy(res.peer_interface_addr, peer->intended_addr, ETH_ALEN);
+ os_memcpy(res.peer_interface_addr, peer->interface_addr, ETH_ALEN);
+
res.wps_method = peer->wps_method;
if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) {
if (peer->flags & P2P_DEV_PREFER_PERSISTENT_RECONN)
@@ -1911,6 +1933,11 @@ void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer)
wpabuf_free(peer->go_neg_conf);
peer->go_neg_conf = NULL;
+#ifdef CONFIG_PASN
+ if (peer->p2p2 && peer->pasn)
+ wpa_pasn_reset(peer->pasn);
+#endif /* CONFIG_PASN */
+
p2p_set_state(p2p, P2P_PROVISIONING);
p2p->cfg->go_neg_completed(p2p->cfg->cb_ctx, &res);
}
@@ -3012,7 +3039,18 @@ int p2p_pairing_info_init(struct p2p_data *p2p)
os_memcpy(pairing_info->dev_ik.dik_data,
p2p->cfg->pairing_config.dik_data,
p2p->cfg->pairing_config.dik_len);
+
+ if (!p2p->cfg->dev_password_len) {
+ p2p->cfg->dev_password_len = 10;
+ p2p_random(p2p->cfg->dev_password, p2p->cfg->dev_password_len);
+ p2p->cfg->dev_password[p2p->cfg->dev_password_len] = '\0';
+ }
+
p2p->pairing_info = pairing_info;
+#ifdef CONFIG_PASN
+ p2p->initiator_pmksa = pasn_initiator_pmksa_cache_init();
+ p2p->responder_pmksa = pasn_responder_pmksa_cache_init();
+#endif /* CONFIG_PASN */
return 0;
}
@@ -3086,6 +3124,10 @@ struct p2p_data * p2p_init(const struct p2p_config *cfg)
void p2p_pairing_info_deinit(struct p2p_data *p2p)
{
+#ifdef CONFIG_PASN
+ pasn_initiator_pmksa_cache_deinit(p2p->initiator_pmksa);
+ pasn_responder_pmksa_cache_deinit(p2p->responder_pmksa);
+#endif /* CONFIG_PASN */
os_free(p2p->pairing_info);
}
@@ -4975,8 +5017,11 @@ int p2p_get_interface_addr(struct p2p_data *p2p, const u8 *dev_addr,
u8 *iface_addr)
{
struct p2p_device *dev = p2p_get_device(p2p, dev_addr);
- if (dev == NULL || is_zero_ether_addr(dev->interface_addr))
+ if (dev == NULL || is_zero_ether_addr(dev->interface_addr)) {
+ wpa_printf(MSG_DEBUG, "P2P: Failed to get interface addr from dev addr "
+ MACSTR, MAC2STR(dev_addr));
return -1;
+ }
os_memcpy(iface_addr, dev->interface_addr, ETH_ALEN);
return 0;
}
@@ -4986,8 +5031,11 @@ int p2p_get_dev_addr(struct p2p_data *p2p, const u8 *iface_addr,
u8 *dev_addr)
{
struct p2p_device *dev = p2p_get_device_interface(p2p, iface_addr);
- if (dev == NULL)
+ if (!dev) {
+ wpa_printf(MSG_DEBUG, "P2P: Failed to get device addr from iface addr "
+ MACSTR, MAC2STR(iface_addr));
return -1;
+ }
os_memcpy(dev_addr, dev->info.p2p_device_addr, ETH_ALEN);
return 0;
}
@@ -5862,3 +5910,757 @@ void p2p_process_usd_elems(struct p2p_data *p2p, const u8 *ies, u16 ies_len,
p2p_parse_free(&msg);
}
+
+#ifdef CONFIG_PASN
+int p2p_prepare_pasn_extra_ie(struct p2p_data *p2p, struct wpabuf *extra_ies,
+ struct wpabuf *frame)
+{
+ 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);
+
+ 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(pasn->pasn_groups, 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, bool verify)
+{
+ 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;
+
+ if ((p2p->cfg->pairing_config.pasn_type & 0xc) &&
+ (dev->info.pairing_config.pasn_type & 0xc)) {
+ pasn->group = 20;
+ pasn->cipher = WPA_CIPHER_GCMP_256;
+ pasn->kek_len = WPA_KEK_256;
+ pasn->pasn_groups = p2p->cfg->pairing_config.pasn_groups;
+ } else {
+ 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 if (verify) {
+ pasn->akmp = WPA_KEY_MGMT_SAE;
+ } 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, false);
+ pasn = dev->pasn;
+
+ pasn_initiator_pmksa_cache_remove(pasn->pmksa, (u8 *)addr);
+
+ /* 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)) {
+ 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.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 (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->role = P2P_ROLE_PAIRING_RESPONDER;
+ p2p_pasn_initialize(p2p, dev, mgmt->sa, freq, true);
+ 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 (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;
+ /* FIXME: If go neg resp is with failure status,
+ how go_neg_failed is indicated to host */
+ } 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 &&
+ p2p->cfg->dev_password_len) {
+ wpabuf_put_u8(p2p2_ie, P2P_ATTR_PASSWORD);
+ wpabuf_put_le16(p2p2_ie, p2p->cfg->dev_password_len);
+ wpabuf_put_data(p2p2_ie, p2p->cfg->dev_password,
+ p2p->cfg->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)
+{
+ 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)) {
+ 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.dik_data, pos, 16);
+ dev->info.dik_len = 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.dik_data, 0,
+ sizeof(dev->info.dik_data));
+ memset(dev->info.password, 0,
+ sizeof(dev->info.password));
+ dev->info.password_len = 0;
+ return -1;
+ }
+ forced_memzero(pasn_get_ptk(pasn), sizeof(pasn->ptk));
+ }
+ 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;
+}
+#endif
@@ -372,6 +372,11 @@ struct p2p_pairing_config {
/* length of DevIK */
size_t dik_len;
+
+ /**
+ * The set of supported PASN groups
+ */
+ int pasn_groups[4];
};
@@ -479,6 +484,36 @@ 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 dik_data[DEVICE_IDENTITY_KEY_MAX_LEN];
+
+ /**
+ * Device Identity key length
+ */
+ u16 dik_len;
+
+ /**
+ * 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 {
@@ -658,6 +693,16 @@ struct p2p_config {
unsigned int passphrase_len;
/**
+ * password used during group formation post opportunistic pasn auth
+ */
+ char dev_password[100];
+
+ /**
+ * password length. Non zero if valid
+ */
+ u16 dev_password_len;
+
+ /**
* p2p_pairing_config - P2P Pairing configuration
*/
struct p2p_pairing_config pairing_config;
@@ -1269,6 +1314,38 @@ 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);
+
+ /**
+ * pasn_update_extra_ies - Function handler to update protocol specific
+ * IEs in pasn auth frames
+ * @ctx: Callback context from cb_ctx
+ * @peer_addr : peer mac address
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*pasn_update_extra_ies)(void *ctx, const u8 *peer_addr);
+
+ /**
+ * pasn_parse_encrypted_data - Function handler to parse encrypted data
+ * with KEK received in pasn auth frames
+ * @ctx: Callback context from cb_ctx
+ * @data : data to be decrypted
+ * @len: length of encrypted data
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*pasn_parse_encrypted_data)(void *ctx, const u8 *data, size_t len);
};
@@ -2571,4 +2648,12 @@ 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);
+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 */
@@ -135,8 +135,8 @@ 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)
{
u8 group_capab;
size_t extra = 0;
@@ -37,6 +37,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
*/
@@ -188,6 +195,12 @@ 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;
};
struct p2p_sd_query {
@@ -630,6 +643,10 @@ 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
*/
@@ -761,6 +778,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;
};
@@ -919,6 +942,8 @@ 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);
@@ -1021,6 +1046,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, bool verify);
void p2p_dbg(struct p2p_data *p2p, const char *fmt, ...)
PRINTF_FORMAT(2, 3);
@@ -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);
@@ -824,6 +824,12 @@ 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;
+#ifdef CONFIG_PASN
+ p2p_pasn_initialize(p2p, dev, sa, rx_freq, false);
+#endif /* CONFIG_PASN */
+ }
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];
@@ -130,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
@@ -151,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);
+
+ int (*parse_encrypted_data)(void *ctx, const u8 *data, size_t len);
};
/* Initiator */
@@ -646,7 +646,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);
@@ -675,11 +678,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;
@@ -713,6 +718,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);
+
+ 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);
@@ -806,13 +816,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;
+ }
}
@@ -982,17 +1004,21 @@ static int wpas_pasn_send_auth_1(struct pasn_data *pasn, const u8 *own_addr,
wpa_printf(MSG_DEBUG, "PASN: Failed building 1st auth frame");
goto fail;
}
+ if (pasn->frame) {
+ wpabuf_free(pasn->frame);
+ pasn->frame = NULL;
+ }
ret = pasn->send_mgmt(pasn->cb_ctx,
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:
@@ -1382,21 +1408,29 @@ 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;
}
+ if (pasn->frame) {
+ wpabuf_free(pasn->frame);
+ pasn->frame = NULL;
+ }
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;
@@ -473,7 +473,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");
@@ -561,6 +561,9 @@ 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);
+
wpa_pasn_add_extra_ies(buf, pasn->extra_ies, pasn->extra_ies_len);
/* Add the mic */
@@ -636,14 +639,20 @@ done:
wpa_printf(MSG_DEBUG,
"PASN: Building frame 2: success; resp STA=" MACSTR,
MAC2STR(peer_addr));
+ if (pasn->frame) {
+ wpabuf_free(pasn->frame);
+ pasn->frame = NULL;
+ }
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);
@@ -1079,6 +1088,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;
@@ -6093,6 +6093,37 @@ static void wpas_link_reconfig(struct wpa_supplicant *wpa_s)
}
+#ifdef CONFIG_PASN
+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;
+}
+#endif /* CONFIG_PASN */
+
+
void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
union wpa_event_data *data)
{
@@ -6323,11 +6354,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) {
@@ -6599,8 +6641,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 */
@@ -40,6 +40,7 @@
#include "crypto/random.h"
+
/*
* How many times to try to scan to find the GO before giving up on join
* request.
@@ -165,7 +166,10 @@ wpas_p2p_consider_moving_gos(struct wpa_supplicant *wpa_s,
static void wpas_p2p_reconsider_moving_go(void *eloop_ctx, void *timeout_ctx);
static int wpas_p2p_disallowed_freq(struct wpa_global *global,
unsigned int freq);
-
+#ifdef CONFIG_PASN
+static int wpas_p2p_initiate_pasn_auth(struct wpa_supplicant *wpa_s,
+ const u8 *peer_addr, int freq);
+#endif /* CONFIG_PASN */
static int wpas_get_6ghz_he_chwidth_capab(struct hostapd_hw_modes *mode)
{
@@ -1717,6 +1721,29 @@ static void wpas_send_action_done(void *ctx)
offchannel_send_action_done(wpa_s);
}
+#ifdef CONFIG_PASN
+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);
+}
+#endif /* CONFIG_PASN */
+
static int wpas_copy_go_neg_results(struct wpa_supplicant *wpa_s,
struct p2p_go_neg_results *params)
@@ -2392,6 +2419,12 @@ static void wpas_p2p_group_formation_timeout(void *eloop_ctx,
void *timeout_ctx)
{
struct wpa_supplicant *wpa_s = eloop_ctx;
+#ifdef CONFIG_PASN
+ if (wpa_s->p2p_pasn_auth_work) {
+ wpas_p2p_pasn_cancel_auth_work(wpa_s);
+ wpa_s->p2p_pasn_auth_work = NULL;
+ }
+#endif /* CONFIG_PASN */
wpa_printf(MSG_DEBUG, "P2P: Group Formation timed out");
wpas_p2p_group_formation_failed(wpa_s, 0);
}
@@ -2456,6 +2489,12 @@ static void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
wpa_s->off_channel_freq = 0;
wpa_s->roc_waiting_drv_freq = 0;
}
+#ifdef CONFIG_PASN
+ if (wpa_s->p2p_pasn_auth_work) {
+ wpas_p2p_pasn_cancel_auth_work(wpa_s);
+ wpa_s->p2p_pasn_auth_work = NULL;
+ }
+#endif /* CONFIG_PASN */
if (res->status) {
wpa_msg_global(wpa_s, MSG_INFO,
@@ -4888,8 +4927,109 @@ static void wpas_bootstrap_completed(void *ctx, const u8 *addr, int status,
if (status)
return;
+#ifdef CONFIG_PASN
+ wpas_p2p_initiate_pasn_auth(wpa_s, addr, freq);
+#endif /* CONFIG_PASN */
+}
+
+#ifdef CONFIG_PASN
+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 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)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ struct p2p_data *p2p = wpa_s->global->p2p;
+
+ return p2p_pasn_update_extra_ies(p2p, peer_addr);
+}
+
+
+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);
+}
+#endif
int wpas_p2p_mac_setup(struct wpa_supplicant *wpa_s)
{
@@ -5013,7 +5153,11 @@ 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;
-
+#ifdef CONFIG_PASN
+ 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;
+#endif /* CONFIG_PASN */
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);
p2p.dev_name = wpa_s->conf->device_name;
@@ -10383,3 +10527,16 @@ 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);
}
+
+#ifdef CONFIG_PASN
+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);
+}
+#endif /* CONFIG_PASN */
@@ -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
@@ -358,6 +360,13 @@ static inline struct wpabuf * wpas_p2p_usd_elems(struct wpa_supplicant *wpa_s)
return NULL;
}
+static inline 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 */
#endif /* P2P_SUPPLICANT_H */
@@ -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) {
@@ -1593,6 +1593,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;
@@ -2028,5 +2031,7 @@ int wpas_get_owe_trans_network(const u8 *owe_ie, const u8 **bssid,
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> --- src/ap/ieee802_11.c | 16 +- src/common/ieee802_11_common.c | 4 + src/common/ieee802_11_common.h | 2 + src/common/ieee802_11_defs.h | 2 + src/p2p/p2p.c | 808 +++++++++++++++++++++++++++++++++++++- src/p2p/p2p.h | 85 ++++ src/p2p/p2p_go_neg.c | 4 +- src/p2p/p2p_i.h | 27 ++ src/p2p/p2p_parse.c | 20 + src/p2p/p2p_pd.c | 6 + src/pasn/pasn_common.h | 7 + src/pasn/pasn_initiator.c | 50 ++- src/pasn/pasn_responder.c | 20 +- wpa_supplicant/events.c | 56 ++- wpa_supplicant/p2p_supplicant.c | 161 +++++++- wpa_supplicant/p2p_supplicant.h | 11 +- wpa_supplicant/pasn_supplicant.c | 5 + wpa_supplicant/wpa_supplicant_i.h | 5 + 18 files changed, 1260 insertions(+), 29 deletions(-)