From b41f26845aaa7cf8aed6e4889e7041debc476ef9 Mon Sep 17 00:00:00 2001 From: Chet Lanctot Date: Thu, 23 Oct 2014 18:21:49 +0300 Subject: [PATCH] Add support for offloading key management operations to the driver This commit introduces a QCA vendor command and event to provide an option to use extended versions of the nl80211 connect/roam operations in a way that allows drivers to offload key management operations to the driver/firmware. Signed-off-by: Jouni Malinen --- src/common/qca-vendor.h | 25 ++++++ src/drivers/driver.h | 56 ++++++++++++++ src/drivers/driver_nl80211.c | 131 +++++++++++++++++++++++++++++++- src/rsn_supp/wpa.c | 46 +++++++++++ src/rsn_supp/wpa.h | 15 ++++ src/rsn_supp/wpa_i.h | 10 +++ wpa_supplicant/config.c | 2 + wpa_supplicant/config.h | 12 +++ wpa_supplicant/config_file.c | 3 + wpa_supplicant/events.c | 20 +++++ wpa_supplicant/wpa_supplicant.c | 16 ++++ wpa_supplicant/wpas_glue.c | 14 ++++ 12 files changed, 348 insertions(+), 2 deletions(-) diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h index ad3bdfd68..7e3057e14 100644 --- a/src/common/qca-vendor.h +++ b/src/common/qca-vendor.h @@ -50,6 +50,14 @@ enum qca_radiotap_vendor_ids { * @QCA_NL80211_VENDOR_SUBCMD_NAN: NAN command/event which is used to pass * NAN Request/Response and NAN Indication messages. These messages are * interpreted between the framework and the firmware component. + * + * @QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_SET_KEY: Set key operation that can be + * used to configure PMK to the driver even when not connected. This can + * be used to request offloading of key management operations. + * @QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH: An extended version of + * NL80211_CMD_ROAM event with optional attributes including information + * from offloaded key management operation. Uses + * enum qca_wlan_vendor_attr_roam_auth attributes. */ enum qca_nl80211_vendor_subcmds { QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0, @@ -61,6 +69,8 @@ enum qca_nl80211_vendor_subcmds { QCA_NL80211_VENDOR_SUBCMD_NAN = 12, QCA_NL80211_VENDOR_SUBMCD_STATS_EXT = 13, /* 14..49 - reserved for QCA */ + QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_SET_KEY = 50, + QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH = 51, }; @@ -89,4 +99,19 @@ enum qca_roaming_policy { QCA_ROAMING_ALLOWED_WITHIN_ESS, }; +enum qca_wlan_vendor_attr_roam_auth { + QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID, + QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_REQ_IE, + QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_RESP_IE, + QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AUTHORIZED, + QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_KEY_REPLAY_CTR, + QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KCK, + QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KEK, + /* keep last */ + QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_MAX = + QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AFTER_LAST - 1 +}; + #endif /* QCA_VENDOR_H */ diff --git a/src/drivers/driver.h b/src/drivers/driver.h index ad9d08014..7f1ee82e8 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -699,6 +699,14 @@ struct wpa_driver_associate_params { const struct ieee80211_vht_capabilities *vhtcaps; const struct ieee80211_vht_capabilities *vhtcaps_mask; #endif /* CONFIG_VHT_OVERRIDES */ + + /** + * req_key_mgmt_offload - Request key management offload for connection + * + * Request key management offload for this connection if the device + * supports it. + */ + int req_key_mgmt_offload; }; enum hide_ssid { @@ -3677,6 +3685,54 @@ union wpa_event_data { * addr - Station address (for AP mode) */ const u8 *addr; + + /** + * The following is the key management offload information + * @authorized + * @key_replay_ctr + * @key_replay_ctr_len + * @ptk_kck + * @ptk_kek_len + * @ptk_kek + * @ptk_kek_len + */ + + /** + * authorized - Status of key management offload, + * 1 = successful + */ + int authorized; + + /** + * key_replay_ctr - Key replay counter value last used + * in a valid EAPOL-Key frame + */ + const u8 *key_replay_ctr; + + /** + * key_replay_ctr_len - The length of key_replay_ctr + */ + size_t key_replay_ctr_len; + + /** + * ptk_kck - The derived PTK KCK + */ + const u8 *ptk_kck; + + /** + * ptk_kek_len - The length of ptk_kck + */ + size_t ptk_kck_len; + + /** + * ptk_kek - The derived PTK KEK + */ + const u8 *ptk_kek; + + /** + * ptk_kek_len - The length of ptk_kek + */ + size_t ptk_kek_len; } assoc_info; /** diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 158f1715c..b8df564c3 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -315,6 +315,8 @@ struct wpa_driver_nl80211_data { unsigned int have_low_prio_scan:1; unsigned int force_connect_cmd:1; unsigned int addr_changed:1; + unsigned int key_mgmt_set_key_vendor_cmd_avail:1; + unsigned int roam_auth_vendor_event_avail:1; u64 remain_on_chan_cookie; u64 send_action_cookie; @@ -1587,7 +1589,11 @@ static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv, static void mlme_event_connect(struct wpa_driver_nl80211_data *drv, enum nl80211_commands cmd, struct nlattr *status, struct nlattr *addr, struct nlattr *req_ie, - struct nlattr *resp_ie) + struct nlattr *resp_ie, + struct nlattr *authorized, + struct nlattr *key_replay_ctr, + struct nlattr *ptk_kck, + struct nlattr *ptk_kek) { union wpa_event_data event; @@ -1637,6 +1643,23 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv, event.assoc_info.freq = nl80211_get_assoc_freq(drv); + if (authorized && nla_get_u8(authorized)) { + event.assoc_info.authorized = 1; + wpa_printf(MSG_DEBUG, "nl80211: connection authorized"); + } + if (key_replay_ctr) { + event.assoc_info.key_replay_ctr = nla_data(key_replay_ctr); + event.assoc_info.key_replay_ctr_len = nla_len(key_replay_ctr); + } + if (ptk_kck) { + event.assoc_info.ptk_kck = nla_data(ptk_kck); + event.assoc_info.ptk_kck_len = nla_len(ptk_kek); + } + if (ptk_kek) { + event.assoc_info.ptk_kek = nla_data(ptk_kek); + event.assoc_info.ptk_kek_len = nla_len(ptk_kek); + } + wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event); } @@ -2976,6 +2999,39 @@ static void qca_nl80211_avoid_freq(struct wpa_driver_nl80211_data *drv, } +static void qca_nl80211_key_mgmt_auth(struct wpa_driver_nl80211_data *drv, + const u8 *data, size_t len) +{ + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_MAX + 1]; + u8 *bssid; + + wpa_printf(MSG_DEBUG, + "nl80211: Key management roam+auth vendor event received"); + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_MAX, + (struct nlattr *) data, len, NULL)) + return; + if (!tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID] || + nla_len(tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID]) != ETH_ALEN || + !tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_REQ_IE] || + !tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_RESP_IE] || + !tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AUTHORIZED]) + return; + + bssid = nla_data(tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID]); + wpa_printf(MSG_DEBUG, " * roam BSSID " MACSTR, MAC2STR(bssid)); + + mlme_event_connect(drv, NL80211_CMD_ROAM, NULL, + tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID], + tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_REQ_IE], + tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_RESP_IE], + tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AUTHORIZED], + tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_KEY_REPLAY_CTR], + tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KCK], + tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KEK]); +} + + static void nl80211_vendor_event_qca(struct wpa_driver_nl80211_data *drv, u32 subcmd, u8 *data, size_t len) { @@ -2983,6 +3039,9 @@ static void nl80211_vendor_event_qca(struct wpa_driver_nl80211_data *drv, case QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY: qca_nl80211_avoid_freq(drv, data, len); break; + case QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH: + qca_nl80211_key_mgmt_auth(drv, data, len); + break; default: wpa_printf(MSG_DEBUG, "nl80211: Ignore unsupported QCA vendor event %u", @@ -3109,6 +3168,17 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd, wpa_printf(MSG_DEBUG, "nl80211: Drv Event %d (%s) received for %s", cmd, nl80211_command_to_string(cmd), bss->ifname); + if (cmd == NL80211_CMD_ROAM && drv->roam_auth_vendor_event_avail) { + /* + * Device will use roam+auth vendor event to indicate + * roaming, so ignore the regular roam event. + */ + wpa_printf(MSG_DEBUG, + "nl80211: Ignore roam event (cmd=%d), device will use vendor event roam+auth", + cmd); + return; + } + if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED && (cmd == NL80211_CMD_NEW_SCAN_RESULTS || cmd == NL80211_CMD_SCAN_ABORTED)) { @@ -3187,7 +3257,8 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd, tb[NL80211_ATTR_STATUS_CODE], tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_REQ_IE], - tb[NL80211_ATTR_RESP_IE]); + tb[NL80211_ATTR_RESP_IE], + NULL, NULL, NULL, NULL); break; case NL80211_CMD_CH_SWITCH_NOTIFY: mlme_event_ch_switch(drv, @@ -3970,6 +4041,9 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg) case QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY: drv->dfs_vendor_cmd_avail = 1; break; + case QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_SET_KEY: + drv->key_mgmt_set_key_vendor_cmd_avail = 1; + break; } wpa_printf(MSG_DEBUG, "nl80211: Supported vendor command: vendor_id=0x%x subcmd=%u", @@ -3988,6 +4062,9 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg) continue; } vinfo = nla_data(nl); + if (vinfo->subcmd == + QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH) + drv->roam_auth_vendor_event_avail = 1; wpa_printf(MSG_DEBUG, "nl80211: Supported vendor event: vendor_id=0x%x subcmd=%u", vinfo->vendor_id, vinfo->subcmd); } @@ -5883,6 +5960,39 @@ static int wpa_cipher_to_cipher_suites(unsigned int ciphers, u32 suites[], } +static int issue_key_mgmt_set_key(struct wpa_driver_nl80211_data *drv, + const u8 *key, size_t key_len) +{ + struct nl_msg *msg; + int ret = 0; + + if (!drv->key_mgmt_set_key_vendor_cmd_avail) + return 0; + + msg = nlmsg_alloc(); + if (!msg) + return -1; + + nl80211_cmd(drv, msg, 0, NL80211_CMD_VENDOR); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + NLA_PUT_U32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA); + NLA_PUT_U32(msg, NL80211_ATTR_VENDOR_SUBCMD, + QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_SET_KEY); + NLA_PUT(msg, NL80211_ATTR_VENDOR_DATA, key_len, key); + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + msg = NULL; + if (ret) { + wpa_printf(MSG_DEBUG, + "nl80211: Key management set key failed: ret=%d (%s)", + ret, strerror(-ret)); + } + +nla_put_failure: + nlmsg_free(msg); + return ret; +} + + static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss, enum wpa_alg alg, const u8 *addr, int key_idx, int set_tx, @@ -5911,6 +6021,13 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss, } #endif /* CONFIG_TDLS */ + if (alg == WPA_ALG_PMK && drv->key_mgmt_set_key_vendor_cmd_avail) { + wpa_printf(MSG_DEBUG, "%s: calling issue_key_mgmt_set_key", + __func__); + ret = issue_key_mgmt_set_key(drv, key, key_len); + return ret; + } + msg = nlmsg_alloc(); if (!msg) return -ENOMEM; @@ -9066,6 +9183,16 @@ static int wpa_driver_nl80211_try_connect( int ret; int algs; + if (params->req_key_mgmt_offload && params->psk && + (params->key_mgmt_suite == WPA_KEY_MGMT_PSK || + params->key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256 || + params->key_mgmt_suite == WPA_KEY_MGMT_FT_PSK)) { + wpa_printf(MSG_DEBUG, "nl80211: Key management set PSK"); + ret = issue_key_mgmt_set_key(drv, params->psk, 32); + if (ret) + return ret; + } + msg = nlmsg_alloc(); if (!msg) return -1; diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c index 4df9e253c..d95c1bd54 100644 --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c @@ -138,6 +138,24 @@ void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise) } +static void wpa_supplicant_key_mgmt_set_pmk(struct wpa_sm *sm) +{ +#ifdef CONFIG_IEEE80211R + if (sm->key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) { + if (wpa_sm_key_mgmt_set_pmk(sm, sm->xxkey, sm->xxkey_len)) + wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, + "RSN: Cannot set low order 256 bits of MSK for key management offload"); + } else { +#endif /* CONFIG_IEEE80211R */ + if (wpa_sm_key_mgmt_set_pmk(sm, sm->pmk, sm->pmk_len)) + wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, + "RSN: Cannot set PMK for key management offload"); +#ifdef CONFIG_IEEE80211R + } +#endif /* CONFIG_IEEE80211R */ +} + + static int wpa_supplicant_get_pmk(struct wpa_sm *sm, const unsigned char *src_addr, const u8 *pmkid) @@ -198,6 +216,7 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm, wpa_hexdump_key(MSG_DEBUG, "WPA: PMK from EAPOL state " "machines", sm->pmk, pmk_len); sm->pmk_len = pmk_len; + wpa_supplicant_key_mgmt_set_pmk(sm); if (sm->proto == WPA_PROTO_RSN && !wpa_key_mgmt_ft(sm->key_mgmt)) { sa = pmksa_cache_add(sm->pmksa, @@ -2787,3 +2806,30 @@ int wpa_sm_get_p2p_ip_addr(struct wpa_sm *sm, u8 *buf) } #endif /* CONFIG_P2P */ + + +void wpa_sm_set_rx_replay_ctr(struct wpa_sm *sm, const u8 *rx_replay_counter) +{ + if (rx_replay_counter == NULL) + return; + + os_memcpy(sm->rx_replay_counter, rx_replay_counter, + WPA_REPLAY_COUNTER_LEN); + sm->rx_replay_counter_set = 1; + wpa_printf(MSG_DEBUG, "Updated key replay counter"); +} + + +void wpa_sm_set_ptk_kck_kek(struct wpa_sm *sm, const u8 *ptk_kck, + const u8 *ptk_kek) +{ + if (ptk_kck) { + os_memcpy(sm->ptk.kck, ptk_kck, 16); + wpa_printf(MSG_DEBUG, "Updated PTK KCK"); + } + if (ptk_kek) { + os_memcpy(sm->ptk.kek, ptk_kek, 16); + wpa_printf(MSG_DEBUG, "Updated PTK KEK"); + } + sm->ptk_set = 1; +} diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h index 595fdf209..355ed13a1 100644 --- a/src/rsn_supp/wpa.h +++ b/src/rsn_supp/wpa.h @@ -70,6 +70,7 @@ struct wpa_sm_ctx { #endif /* CONFIG_TDLS */ void (*set_rekey_offload)(void *ctx, const u8 *kek, const u8 *kck, const u8 *replay_ctr); + int (*key_mgmt_set_pmk)(void *ctx, const u8 *pmk, size_t pmk_len); }; @@ -148,6 +149,10 @@ void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm, void *network_ctx); int wpa_sm_get_p2p_ip_addr(struct wpa_sm *sm, u8 *buf); +void wpa_sm_set_rx_replay_ctr(struct wpa_sm *sm, const u8 *rx_replay_counter); +void wpa_sm_set_ptk_kck_kek(struct wpa_sm *sm, const u8 *ptk_kck, + const u8 *ptk_kek); + #else /* CONFIG_NO_WPA */ static inline struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx) @@ -302,6 +307,16 @@ static inline void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm, { } +static inline void wpa_sm_set_rx_replay_ctr(struct wpa_sm *sm, + const u8 *rx_replay_counter) +{ +} + +static inline void wpa_sm_set_ptk_kck_kek(struct wpa_sm *sm, const u8 *ptk_kck, + const u8 *ptk_kek) +{ +} + #endif /* CONFIG_NO_WPA */ #ifdef CONFIG_PEERKEY diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h index 839b545b9..dd5ddfbd1 100644 --- a/src/rsn_supp/wpa_i.h +++ b/src/rsn_supp/wpa_i.h @@ -312,6 +312,16 @@ wpa_sm_tdls_peer_addset(struct wpa_sm *sm, const u8 *addr, int add, } #endif /* CONFIG_TDLS */ +static inline int wpa_sm_key_mgmt_set_pmk(struct wpa_sm *sm, + const u8 *pmk, size_t pmk_len) +{ + if (!sm->proactive_key_caching) + return 0; + if (!sm->ctx->key_mgmt_set_pmk) + return -1; + return sm->ctx->key_mgmt_set_pmk(sm->ctx->ctx, pmk, pmk_len); +} + void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck, int ver, const u8 *dest, u16 proto, u8 *msg, size_t msg_len, u8 *key_mic); diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index a610b2416..45a346a96 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -3327,6 +3327,7 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface, config->wmm_ac_params[3] = ac_vo; config->p2p_search_delay = DEFAULT_P2P_SEARCH_DELAY; config->rand_addr_lifetime = DEFAULT_RAND_ADDR_LIFETIME; + config->key_mgmt_offload = DEFAULT_KEY_MGMT_OFFLOAD; if (ctrl_interface) config->ctrl_interface = os_strdup(ctrl_interface); @@ -3953,6 +3954,7 @@ static const struct global_parse_data global_fields[] = { { INT(mac_addr), 0 }, { INT(rand_addr_lifetime), 0 }, { INT(preassoc_mac_addr), 0 }, + { INT(key_mgmt_offload), 0}, }; #undef FUNC diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h index f4c2f8883..ba6e2d926 100644 --- a/wpa_supplicant/config.h +++ b/wpa_supplicant/config.h @@ -28,6 +28,7 @@ #define DEFAULT_SCAN_CUR_FREQ 0 #define DEFAULT_P2P_SEARCH_DELAY 500 #define DEFAULT_RAND_ADDR_LIFETIME 60 +#define DEFAULT_KEY_MGMT_OFFLOAD 1 #include "config_ssid.h" #include "wps/wps.h" @@ -1088,6 +1089,17 @@ struct wpa_config { * 2 = like 1, but maintain OUI (with local admin bit set) */ int preassoc_mac_addr; + + /** + * key_mgmt_offload - Use key management offload + * + * Key management offload should be used if the device supports it. + * Key management offload is the capability of a device operating as + * a station to do the exchange necessary to establish temporal keys + * during initial RSN connection, after roaming, or during a PTK + * rekeying operation. + */ + int key_mgmt_offload; }; diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c index 17dbab6f3..1661f88c0 100644 --- a/wpa_supplicant/config_file.c +++ b/wpa_supplicant/config_file.c @@ -1192,6 +1192,9 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config) if (config->preassoc_mac_addr) fprintf(f, "preassoc_mac_addr=%d\n", config->preassoc_mac_addr); + + if (config->key_mgmt_offload != DEFAULT_KEY_MGMT_OFFLOAD) + fprintf(f, "key_mgmt_offload=%u\n", config->key_mgmt_offload); } #endif /* CONFIG_NO_CONFIG_WRITE */ diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index f9e82ddfb..54c6ea16b 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -2894,6 +2894,24 @@ static void wpa_supplicant_notify_avoid_freq(struct wpa_supplicant *wpa_s, } +static void wpa_supplicant_event_assoc_auth(struct wpa_supplicant *wpa_s, + union wpa_event_data *data) +{ + wpa_dbg(wpa_s, MSG_DEBUG, + "Connection authorized by device, previous state %d", + wpa_s->wpa_state); + if (wpa_s->wpa_state == WPA_ASSOCIATED) { + wpa_supplicant_cancel_auth_timeout(wpa_s); + wpa_supplicant_set_state(wpa_s, WPA_COMPLETED); + eapol_sm_notify_portValid(wpa_s->eapol, TRUE); + eapol_sm_notify_eap_success(wpa_s->eapol, TRUE); + } + wpa_sm_set_rx_replay_ctr(wpa_s->wpa, data->assoc_info.key_replay_ctr); + wpa_sm_set_ptk_kck_kek(wpa_s->wpa, data->assoc_info.ptk_kck, + data->assoc_info.ptk_kek); +} + + void wpa_supplicant_event(void *ctx, enum wpa_event_type event, union wpa_event_data *data) { @@ -2934,6 +2952,8 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, break; case EVENT_ASSOC: wpa_supplicant_event_assoc(wpa_s, data); + if (data && data->assoc_info.authorized) + wpa_supplicant_event_assoc_auth(wpa_s, data); break; case EVENT_DISASSOC: wpas_event_disassoc(wpa_s, diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 27afa8320..044a96432 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -1921,6 +1921,22 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) params.psk = ssid->psk; } + if (wpa_s->conf->key_mgmt_offload) { + if (params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X || + params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256) + params.req_key_mgmt_offload = + ssid->proactive_key_caching < 0 ? + wpa_s->conf->okc : ssid->proactive_key_caching; + else + params.req_key_mgmt_offload = 1; + + if ((params.key_mgmt_suite == WPA_KEY_MGMT_PSK || + params.key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256 || + params.key_mgmt_suite == WPA_KEY_MGMT_FT_PSK) && + ssid->psk_set) + params.psk = ssid->psk; + } + params.drop_unencrypted = use_crypt; #ifdef CONFIG_IEEE80211W diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c index ea95a4ce0..48b854bd3 100644 --- a/wpa_supplicant/wpas_glue.c +++ b/wpa_supplicant/wpas_glue.c @@ -915,6 +915,19 @@ static void wpa_supplicant_set_rekey_offload(void *ctx, const u8 *kek, #endif /* CONFIG_NO_WPA */ +static int wpa_supplicant_key_mgmt_set_pmk(void *ctx, const u8 *pmk, + size_t pmk_len) +{ + struct wpa_supplicant *wpa_s = ctx; + + if (wpa_s->conf->key_mgmt_offload) + return wpa_drv_set_key(wpa_s, WPA_ALG_PMK, NULL, 0, 0, + NULL, 0, pmk, pmk_len); + else + return 0; +} + + int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s) { #ifndef CONFIG_NO_WPA @@ -956,6 +969,7 @@ int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s) ctx->tdls_peer_addset = wpa_supplicant_tdls_peer_addset; #endif /* CONFIG_TDLS */ ctx->set_rekey_offload = wpa_supplicant_set_rekey_offload; + ctx->key_mgmt_set_pmk = wpa_supplicant_key_mgmt_set_pmk; wpa_s->wpa = wpa_sm_init(ctx); if (wpa_s->wpa == NULL) {