#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "crypto/sha256.h"
+#include "pasn/pasn_common.h"
#include "proximity_ranging.h"
static void pr_device_free(struct pr_data *pr, struct pr_device *dev)
{
+#ifdef CONFIG_PASN
+ if (dev->pasn) {
+ wpa_pasn_reset(dev->pasn);
+ pasn_data_deinit(dev->pasn);
+ }
+#endif /* CONFIG_PASN */
os_free(dev);
}
pr_parse_free(&msg);
}
+
+
+#ifdef CONFIG_PASN
+
+static int pr_pasn_initialize(struct pr_data *pr, struct pr_device *dev,
+ const u8 *addr, u8 auth_mode, int freq,
+ u8 ranging_type)
+{
+ struct pasn_data *pasn;
+
+ if (dev->pasn) {
+ wpa_pasn_reset(dev->pasn);
+ } else {
+ dev->pasn = pasn_data_init();
+ if (!dev->pasn)
+ return -1;
+ }
+
+ pasn = dev->pasn;
+ os_memcpy(pasn->own_addr, pr->cfg->dev_addr, ETH_ALEN);
+ os_memcpy(pasn->peer_addr, addr, ETH_ALEN);
+
+ if (dev->pasn_role == PR_ROLE_PASN_INITIATOR)
+ os_memcpy(pasn->bssid, pasn->peer_addr, ETH_ALEN);
+ else
+ os_memcpy(pasn->bssid, pasn->own_addr, ETH_ALEN);
+
+ pasn->noauth = 1;
+
+ /* As specified in Proximity Ranging Implementation Considerations for
+ * P2P Operation D1.8, unauthenticated mode PASN with DH group 19
+ * should be supported by all P2P proximity ranging devices. */
+ if (!(pr->cfg->pasn_type & BIT(0)) ||
+ !(dev->pr_caps.pasn_type & BIT(0))) {
+ wpa_printf(MSG_DEBUG,
+ "PR PASN: Unauthenticated DH group 19 NOT supported, PASN type of self 0x%x, peer 0x%x",
+ pr->cfg->pasn_type, dev->pr_caps.pasn_type);
+ return -1;
+ }
+
+ /* As specified in Proximity Ranging Implementation Considerations for
+ * P2P Operation D1.8, EDCA based ranging is only supported with
+ * unauthenticated mode PASN with DH group 19. */
+ if (((pr->cfg->pasn_type & 0xc) && (dev->pr_caps.pasn_type & 0xc)) &&
+ ranging_type != PR_EDCA_BASED_RANGING) {
+ pasn->group = 20;
+ pasn->cipher = WPA_CIPHER_GCMP_256;
+ } else {
+ pasn->group = 19;
+ pasn->cipher = WPA_CIPHER_CCMP;
+ }
+
+ if (pr->cfg->secure_he_ltf &&
+ ranging_type == PR_NTB_SECURE_LTF_BASED_RANGING) {
+ pasn->secure_ltf = true;
+ pasn_enable_kdk_derivation(pasn);
+ } else {
+ pasn_disable_kdk_derivation(pasn);
+ }
+ wpa_printf(MSG_DEBUG, "PASN: kdk_len=%zu", pasn->kdk_len);
+
+ if (auth_mode == PR_PASN_AUTH_MODE_SAE)
+ pasn->akmp = WPA_KEY_MGMT_SAE;
+ else if (auth_mode == PR_PASN_AUTH_MODE_PMK)
+ pasn->akmp = WPA_KEY_MGMT_SAE;
+ else
+ pasn->akmp = WPA_KEY_MGMT_PASN;
+
+ pasn->rsn_pairwise = pasn->cipher;
+ pasn->wpa_key_mgmt = pasn->akmp;
+
+ pasn->cb_ctx = pr->cfg->cb_ctx;
+ pasn->send_mgmt = pr->cfg->pasn_send_mgmt;
+ pasn->freq = freq;
+ return 0;
+}
+
+
+int pr_initiate_pasn_auth(struct pr_data *pr, const u8 *addr, int freq,
+ u8 auth_mode, u8 ranging_role, u8 ranging_type,
+ int forced_pr_freq)
+{
+ int ret = 0;
+ struct pasn_data *pasn;
+ struct pr_device *dev;
+
+ if (!addr) {
+ wpa_printf(MSG_DEBUG, "PR PASN: Peer address NULL");
+ return -1;
+ }
+
+ dev = pr_get_device(pr, addr);
+ if (!dev) {
+ wpa_printf(MSG_DEBUG, "PR PASN: Peer not known");
+ return -1;
+ }
+
+ if (freq == 0)
+ freq = dev->listen_freq;
+
+ dev->pasn_role = PR_ROLE_PASN_INITIATOR;
+
+ if (pr_pasn_initialize(pr, dev, addr, auth_mode, freq, ranging_type)) {
+ wpa_printf(MSG_INFO, "PR PASN: Initialization failed");
+ return -1;
+ }
+ pasn = dev->pasn;
+
+ if (auth_mode == PR_PASN_AUTH_MODE_PMK) {
+ ret = wpa_pasn_verify(pasn, pasn->own_addr, pasn->peer_addr,
+ pasn->bssid, pasn->akmp, pasn->cipher,
+ pasn->group, pasn->freq, NULL, 0, NULL, 0,
+ NULL);
+ } else {
+ ret = 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);
+ }
+ if (ret)
+ wpa_printf(MSG_INFO, "PR PASN: Failed to start PASN");
+
+ return ret;
+}
+
+#endif /* CONFIG_PASN */
*/
#define PR_MAX_PEER 100
+enum pr_pasn_role {
+ PR_ROLE_IDLE = 0,
+ PR_ROLE_PASN_INITIATOR,
+ PR_ROLE_PASN_RESPONDER,
+};
+
/**
* struct pr_channels - List of supported channels
*/
#define PR_ISTA_SUPPORT BIT(0)
#define PR_RSTA_SUPPORT BIT(1)
+/*
+ * PASN capabilities in PASN Type field
+ * Proximity Ranging Implementation Considerations for P2P Operation D1.8,
+ * Table 7 (Proximity Ranging Capability Attribute).
+ */
+#define PR_PASN_DH19_UNAUTH BIT(0)
+#define PR_PASN_DH19_AUTH BIT(1)
+#define PR_PASN_DH20_UNAUTH BIT(2)
+#define PR_PASN_DH20_AUTH BIT(3)
+
+/* Authentication Mode */
+#define PR_PASN_AUTH_MODE_PASN 0
+#define PR_PASN_AUTH_MODE_SAE 1
+#define PR_PASN_AUTH_MODE_PMK 2
+
struct pr_dev_ik {
struct dl_list list;
u8 dik[DEVICE_IDENTITY_KEY_LEN];
*/
u8 pmk[PMK_LEN_MAX];
bool pmk_valid;
+
+#ifdef CONFIG_PASN
+ /* PASN data structure */
+ struct pasn_data *pasn;
+ enum pr_pasn_role pasn_role;
+#endif /* CONFIG_PASN */
};
* cb_ctx - Context to use with callback functions
*/
void *cb_ctx;
+
+ /**
+ * 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);
+
};
struct pr_data {
struct wpabuf * pr_prepare_usd_elems(struct pr_data *pr);
void pr_process_usd_elems(struct pr_data *pr, const u8 *ies, u16 ies_len,
const u8 *peer_addr, unsigned int freq);
+int pr_initiate_pasn_auth(struct pr_data *pr, const u8 *addr, int freq,
+ u8 auth_mode, u8 ranging_role, u8 ranging_type,
+ int forced_pr_freq);
#endif /* PROXIMITY_RANGING_H */
#ifndef PASN_COMMON_H
#define PASN_COMMON_H
+#include "common/wpa_common.h"
+#ifdef CONFIG_SAE
+#include "common/sae.h"
+#endif /* CONFIG_SAE */
+#include "crypto/sha384.h"
+
#ifdef __cplusplus
extern "C" {
#endif
#include "includes.h"
#include "utils/common.h"
+#include "utils/eloop.h"
#include "common/proximity_ranging.h"
#include "p2p/p2p.h"
#include "wpa_supplicant_i.h"
#include "config.h"
+#include "driver_i.h"
#include "pr_supplicant.h"
+#ifdef CONFIG_PASN
+static void wpas_pr_pasn_timeout(void *eloop_ctx, void *timeout_ctx);
+#endif /* CONFIG_PASN */
+
static int wpas_pr_edca_get_bw(enum edca_format_and_bw_value format_and_bw)
{
}
+static int wpas_pr_pasn_send_mgmt(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);
+}
+
+
struct wpabuf * wpas_pr_usd_elems(struct wpa_supplicant *wpa_s)
{
return pr_prepare_usd_elems(wpa_s->global->pr);
pr.support_6ghz = wpas_is_6ghz_supported(wpa_s, true);
+ pr.pasn_send_mgmt = wpas_pr_pasn_send_mgmt;
+
pr.secure_he_ltf = wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF_STA;
wpas_pr_setup_ntb_channels(wpa_s, &pr.ntb_channels,
wpa_s->global->pr = NULL;
wpa_s->global->pr_init_wpa_s = NULL;
}
+
+#ifdef CONFIG_PASN
+ eloop_cancel_timeout(wpas_pr_pasn_timeout, wpa_s, NULL);
+#endif /* CONFIG_PASN */
}
pr_add_dev_ik(pr, dik, password, pmk, own);
}
+
+
+#ifdef CONFIG_PASN
+
+struct wpa_pr_pasn_auth_work {
+ u8 peer_addr[ETH_ALEN];
+ u8 auth_mode;
+ int freq;
+ enum pr_pasn_role role;
+ u8 ranging_role;
+ u8 ranging_type;
+ u8 *ssid;
+ size_t ssid_len;
+ u8 bssid[ETH_ALEN];
+ int forced_pr_freq;
+};
+
+
+static void wpas_pr_pasn_free_auth_work(struct wpa_pr_pasn_auth_work *awork)
+{
+ if (!awork)
+ return;
+ os_free(awork->ssid);
+ os_free(awork);
+}
+
+
+static void wpas_pr_pasn_cancel_auth_work(struct wpa_supplicant *wpa_s)
+{
+ wpa_printf(MSG_DEBUG, "PR PASN: Cancel pr-pasn-start-auth work");
+
+ /* Remove pending/started work */
+ radio_remove_works(wpa_s, "pr-pasn-start-auth", 0);
+}
+
+
+static void wpas_pr_pasn_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+
+ if (wpa_s->pr_pasn_auth_work) {
+ wpas_pr_pasn_cancel_auth_work(wpa_s);
+ wpa_s->pr_pasn_auth_work = NULL;
+ }
+ wpa_printf(MSG_DEBUG, "PR: PASN timed out");
+}
+
+
+static void wpas_pr_pasn_auth_start_cb(struct wpa_radio_work *work, int deinit)
+{
+ int ret;
+ struct wpa_supplicant *wpa_s = work->wpa_s;
+ struct wpa_pr_pasn_auth_work *awork = work->ctx;
+ struct pr_data *pr = wpa_s->global->pr;
+ const u8 *peer_addr = NULL;
+
+ if (deinit) {
+ if (!work->started)
+ eloop_cancel_timeout(wpas_pr_pasn_timeout, wpa_s, NULL);
+
+ wpas_pr_pasn_free_auth_work(awork);
+ return;
+ }
+
+ if (!is_zero_ether_addr(awork->peer_addr))
+ peer_addr = awork->peer_addr;
+
+ ret = pr_initiate_pasn_auth(pr, peer_addr, awork->freq,
+ awork->auth_mode, awork->ranging_role,
+ awork->ranging_type, awork->forced_pr_freq);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "PR PASN: Failed to start PASN authentication");
+ goto fail;
+ }
+
+ eloop_cancel_timeout(wpas_pr_pasn_timeout, wpa_s, NULL);
+ eloop_register_timeout(2, 0, wpas_pr_pasn_timeout, wpa_s, NULL);
+ wpa_s->pr_pasn_auth_work = work;
+ return;
+
+fail:
+ wpas_pr_pasn_free_auth_work(awork);
+ work->ctx = NULL;
+ radio_work_done(work);
+}
+
+
+int wpas_pr_initiate_pasn_auth(struct wpa_supplicant *wpa_s,
+ const u8 *peer_addr, int freq, u8 auth_mode,
+ u8 ranging_role, u8 ranging_type,
+ int forced_pr_freq)
+{
+ struct wpa_pr_pasn_auth_work *awork;
+
+ wpas_pr_pasn_cancel_auth_work(wpa_s);
+ wpa_s->pr_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);
+ awork->ranging_role = ranging_role;
+ awork->ranging_type = ranging_type;
+ awork->auth_mode = auth_mode;
+ awork->forced_pr_freq = forced_pr_freq;
+
+ if (radio_add_work(wpa_s, freq, "pr-pasn-start-auth", 1,
+ wpas_pr_pasn_auth_start_cb, awork) < 0) {
+ wpas_pr_pasn_free_auth_work(awork);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "PR PASN: Authentication work successfully added");
+ return 0;
+}
+
+#endif /* CONFIG_PASN */
void wpas_pr_process_usd_elems(struct wpa_supplicant *wpa_s, const u8 *buf,
u16 buf_len, const u8 *peer_addr,
unsigned int freq);
+int wpas_pr_initiate_pasn_auth(struct wpa_supplicant *wpa_s,
+ const u8 *peer_addr, int freq, u8 auth_mode,
+ u8 ranging_role, u8 ranging_type,
+ int forced_pr_freq);
#else /* CONFIG_PR */
return NULL;
}
+static inline int wpas_pr_initiate_pasn_auth(struct wpa_supplicant *wpa_s,
+ const u8 *peer_addr, int freq,
+ u8 auth_mode, u8 ranging_role,
+ u8 ranging_type,
+ int forced_pr_freq)
+{
+ return 0;
+}
+
#endif /* CONFIG_PR */
#endif /* PR_SUPPLICANT_H */
#ifdef CONFIG_P2P
struct wpa_radio_work *p2p_pasn_auth_work;
#endif /* CONFIG_P2P */
+ struct wpa_radio_work *pr_pasn_auth_work;
#endif /* CONFIG_PASN */
bool is_6ghz_enabled;