Signed-off-by: Peddolla Harshavardhan Reddy <peddolla@xxxxxxxxxxxxxxxx> --- src/common/proximity_ranging.c | 125 +++++++++++++++++++++++++++ src/common/proximity_ranging.h | 38 +++++++++ wpa_supplicant/pr_supplicant.c | 135 ++++++++++++++++++++++++++++++ wpa_supplicant/pr_supplicant.h | 13 +++ wpa_supplicant/wpa_supplicant_i.h | 1 + 5 files changed, 312 insertions(+) diff --git a/src/common/proximity_ranging.c b/src/common/proximity_ranging.c index b2eb42d6b..2bd7ee9fe 100644 --- a/src/common/proximity_ranging.c +++ b/src/common/proximity_ranging.c @@ -13,14 +13,22 @@ #include "common/ieee802_11_common.h" #include "common/qca-vendor.h" #include "wps/wps_i.h" +#include "common/sae.h" #include "proximity_ranging.h" #include "crypto/sha256.h" #include "crypto/sha384.h" #include "crypto/crypto.h" +#include "pasn/pasn_common.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); } @@ -973,3 +981,120 @@ void pr_process_usd_elems(struct pr_data *pr, const u8 *ies, u16 ies_len, 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) +{ + struct pasn_data *pasn; + + if (!pr || !dev) + return -1; + + 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; + + if ((pr->cfg->pasn_type & 0xc) && + (dev->pr_caps.pasn_type & 0xc)) { + pasn->group = 20; + pasn->cipher = WPA_CIPHER_GCMP_256; + } else { + pasn->group = 19; + pasn->cipher = WPA_CIPHER_CCMP; + } + + if (pr->cfg->secure_he_ltf) + pasn_enable_kdk_derivation(pasn); + else + pasn_disable_kdk_derivation(pasn); + + wpa_printf(MSG_DEBUG, "PASN: kdk_len=%zu", pasn->kdk_len); + + if (pr->cfg->secure_he_ltf) + pasn->secure_ltf = true; + + 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, "Peer address NULL"); + return -1; + } + + dev = pr_get_device(pr, addr); + if (!dev) { + wpa_printf(MSG_DEBUG, "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)) { + wpa_printf(MSG_ERROR, "PR PASN: Initialize 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_ERROR, "PR: Failed to start PASN"); + + return ret; +} + +#endif /* CONFIG_PASN */ diff --git a/src/common/proximity_ranging.h b/src/common/proximity_ranging.h index 5d5ec0dc3..16ebaabd7 100644 --- a/src/common/proximity_ranging.h +++ b/src/common/proximity_ranging.h @@ -38,6 +38,12 @@ #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 */ @@ -171,6 +177,17 @@ enum pr_attr_id { #define PR_ISTA_SUPPORT BIT(0) #define PR_RSTA_SUPPORT BIT(1) +/* PASN capabilities*/ +#define PR_PASN_DH19_AUTH BIT(0) +#define PR_PASN_DH19_UNAUTH BIT(1) +#define PR_PASN_DH20_AUTH BIT(2) +#define PR_PASN_DH20_UNAUTH 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]; @@ -208,6 +225,10 @@ struct pr_device { */ u8 pmk[PMK_LEN_MAX]; bool pmk_valid; + + /* PASN data structure */ + struct pasn_data *pasn; + enum pr_pasn_role pasn_role; }; @@ -312,6 +333,20 @@ struct pr_config { * 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 { @@ -351,5 +386,8 @@ void pr_add_dev_ik(struct pr_data *pr, const u8 *dik, const char *password, struct wpabuf * pr_prepare_usd_elems(struct pr_data *pr, const char *country); 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 */ diff --git a/wpa_supplicant/pr_supplicant.c b/wpa_supplicant/pr_supplicant.c index 18eebea73..0ec4ca828 100644 --- a/wpa_supplicant/pr_supplicant.c +++ b/wpa_supplicant/pr_supplicant.c @@ -74,6 +74,17 @@ static int wpas_pr_setup_channels(struct wpa_supplicant *wpa_s, return 0; } + +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, wpa_s->conf->country); @@ -132,6 +143,8 @@ int wpas_pr_init(struct wpa_global *global, struct wpa_supplicant *wpa_s) pr.support_6ghz = false; + 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_channels(wpa_s, &pr.ntb_channels); @@ -213,3 +226,125 @@ void wpas_pr_set_dev_ik(struct wpa_supplicant *wpa_s, const u8 *dik, 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 */ diff --git a/wpa_supplicant/pr_supplicant.h b/wpa_supplicant/pr_supplicant.h index ff4478ef9..4f082fb5d 100644 --- a/wpa_supplicant/pr_supplicant.h +++ b/wpa_supplicant/pr_supplicant.h @@ -22,6 +22,10 @@ struct wpabuf * wpas_pr_usd_elems(struct wpa_supplicant *wpa_s); 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 */ static inline int wpas_pr_init(struct wpa_global *global, struct wpa_supplicant *wpa_s) @@ -49,6 +53,15 @@ static inline struct wpabuf * wpas_pr_usd_elems(struct wpa_supplicant *wpa_s) 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 */ diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 85515f6fb..d648e6ccc 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -1614,6 +1614,7 @@ struct wpa_supplicant { #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; -- 2.34.1 _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap