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 <jouni@qca.qualcomm.com>
This commit is contained in:
parent
fbb79f94eb
commit
b41f26845a
12 changed files with 348 additions and 2 deletions
|
@ -50,6 +50,14 @@ enum qca_radiotap_vendor_ids {
|
||||||
* @QCA_NL80211_VENDOR_SUBCMD_NAN: NAN command/event which is used to pass
|
* @QCA_NL80211_VENDOR_SUBCMD_NAN: NAN command/event which is used to pass
|
||||||
* NAN Request/Response and NAN Indication messages. These messages are
|
* NAN Request/Response and NAN Indication messages. These messages are
|
||||||
* interpreted between the framework and the firmware component.
|
* 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 {
|
enum qca_nl80211_vendor_subcmds {
|
||||||
QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0,
|
QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0,
|
||||||
|
@ -61,6 +69,8 @@ enum qca_nl80211_vendor_subcmds {
|
||||||
QCA_NL80211_VENDOR_SUBCMD_NAN = 12,
|
QCA_NL80211_VENDOR_SUBCMD_NAN = 12,
|
||||||
QCA_NL80211_VENDOR_SUBMCD_STATS_EXT = 13,
|
QCA_NL80211_VENDOR_SUBMCD_STATS_EXT = 13,
|
||||||
/* 14..49 - reserved for QCA */
|
/* 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,
|
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 */
|
#endif /* QCA_VENDOR_H */
|
||||||
|
|
|
@ -699,6 +699,14 @@ struct wpa_driver_associate_params {
|
||||||
const struct ieee80211_vht_capabilities *vhtcaps;
|
const struct ieee80211_vht_capabilities *vhtcaps;
|
||||||
const struct ieee80211_vht_capabilities *vhtcaps_mask;
|
const struct ieee80211_vht_capabilities *vhtcaps_mask;
|
||||||
#endif /* CONFIG_VHT_OVERRIDES */
|
#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 {
|
enum hide_ssid {
|
||||||
|
@ -3677,6 +3685,54 @@ union wpa_event_data {
|
||||||
* addr - Station address (for AP mode)
|
* addr - Station address (for AP mode)
|
||||||
*/
|
*/
|
||||||
const u8 *addr;
|
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;
|
} assoc_info;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -315,6 +315,8 @@ struct wpa_driver_nl80211_data {
|
||||||
unsigned int have_low_prio_scan:1;
|
unsigned int have_low_prio_scan:1;
|
||||||
unsigned int force_connect_cmd:1;
|
unsigned int force_connect_cmd:1;
|
||||||
unsigned int addr_changed: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 remain_on_chan_cookie;
|
||||||
u64 send_action_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,
|
static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
|
||||||
enum nl80211_commands cmd, struct nlattr *status,
|
enum nl80211_commands cmd, struct nlattr *status,
|
||||||
struct nlattr *addr, struct nlattr *req_ie,
|
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;
|
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);
|
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);
|
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,
|
static void nl80211_vendor_event_qca(struct wpa_driver_nl80211_data *drv,
|
||||||
u32 subcmd, u8 *data, size_t len)
|
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:
|
case QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY:
|
||||||
qca_nl80211_avoid_freq(drv, data, len);
|
qca_nl80211_avoid_freq(drv, data, len);
|
||||||
break;
|
break;
|
||||||
|
case QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH:
|
||||||
|
qca_nl80211_key_mgmt_auth(drv, data, len);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
wpa_printf(MSG_DEBUG,
|
wpa_printf(MSG_DEBUG,
|
||||||
"nl80211: Ignore unsupported QCA vendor event %u",
|
"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",
|
wpa_printf(MSG_DEBUG, "nl80211: Drv Event %d (%s) received for %s",
|
||||||
cmd, nl80211_command_to_string(cmd), bss->ifname);
|
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 &&
|
if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED &&
|
||||||
(cmd == NL80211_CMD_NEW_SCAN_RESULTS ||
|
(cmd == NL80211_CMD_NEW_SCAN_RESULTS ||
|
||||||
cmd == NL80211_CMD_SCAN_ABORTED)) {
|
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_STATUS_CODE],
|
||||||
tb[NL80211_ATTR_MAC],
|
tb[NL80211_ATTR_MAC],
|
||||||
tb[NL80211_ATTR_REQ_IE],
|
tb[NL80211_ATTR_REQ_IE],
|
||||||
tb[NL80211_ATTR_RESP_IE]);
|
tb[NL80211_ATTR_RESP_IE],
|
||||||
|
NULL, NULL, NULL, NULL);
|
||||||
break;
|
break;
|
||||||
case NL80211_CMD_CH_SWITCH_NOTIFY:
|
case NL80211_CMD_CH_SWITCH_NOTIFY:
|
||||||
mlme_event_ch_switch(drv,
|
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:
|
case QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY:
|
||||||
drv->dfs_vendor_cmd_avail = 1;
|
drv->dfs_vendor_cmd_avail = 1;
|
||||||
break;
|
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",
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
vinfo = nla_data(nl);
|
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",
|
wpa_printf(MSG_DEBUG, "nl80211: Supported vendor event: vendor_id=0x%x subcmd=%u",
|
||||||
vinfo->vendor_id, vinfo->subcmd);
|
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,
|
static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
|
||||||
enum wpa_alg alg, const u8 *addr,
|
enum wpa_alg alg, const u8 *addr,
|
||||||
int key_idx, int set_tx,
|
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 */
|
#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();
|
msg = nlmsg_alloc();
|
||||||
if (!msg)
|
if (!msg)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@ -9066,6 +9183,16 @@ static int wpa_driver_nl80211_try_connect(
|
||||||
int ret;
|
int ret;
|
||||||
int algs;
|
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();
|
msg = nlmsg_alloc();
|
||||||
if (!msg)
|
if (!msg)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
@ -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,
|
static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
|
||||||
const unsigned char *src_addr,
|
const unsigned char *src_addr,
|
||||||
const u8 *pmkid)
|
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 "
|
wpa_hexdump_key(MSG_DEBUG, "WPA: PMK from EAPOL state "
|
||||||
"machines", sm->pmk, pmk_len);
|
"machines", sm->pmk, pmk_len);
|
||||||
sm->pmk_len = pmk_len;
|
sm->pmk_len = pmk_len;
|
||||||
|
wpa_supplicant_key_mgmt_set_pmk(sm);
|
||||||
if (sm->proto == WPA_PROTO_RSN &&
|
if (sm->proto == WPA_PROTO_RSN &&
|
||||||
!wpa_key_mgmt_ft(sm->key_mgmt)) {
|
!wpa_key_mgmt_ft(sm->key_mgmt)) {
|
||||||
sa = pmksa_cache_add(sm->pmksa,
|
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 */
|
#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;
|
||||||
|
}
|
||||||
|
|
|
@ -70,6 +70,7 @@ struct wpa_sm_ctx {
|
||||||
#endif /* CONFIG_TDLS */
|
#endif /* CONFIG_TDLS */
|
||||||
void (*set_rekey_offload)(void *ctx, const u8 *kek, const u8 *kck,
|
void (*set_rekey_offload)(void *ctx, const u8 *kek, const u8 *kck,
|
||||||
const u8 *replay_ctr);
|
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);
|
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 */
|
#else /* CONFIG_NO_WPA */
|
||||||
|
|
||||||
static inline struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx)
|
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 */
|
#endif /* CONFIG_NO_WPA */
|
||||||
|
|
||||||
#ifdef CONFIG_PEERKEY
|
#ifdef CONFIG_PEERKEY
|
||||||
|
|
|
@ -312,6 +312,16 @@ wpa_sm_tdls_peer_addset(struct wpa_sm *sm, const u8 *addr, int add,
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_TDLS */
|
#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,
|
void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck,
|
||||||
int ver, const u8 *dest, u16 proto,
|
int ver, const u8 *dest, u16 proto,
|
||||||
u8 *msg, size_t msg_len, u8 *key_mic);
|
u8 *msg, size_t msg_len, u8 *key_mic);
|
||||||
|
|
|
@ -3327,6 +3327,7 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
|
||||||
config->wmm_ac_params[3] = ac_vo;
|
config->wmm_ac_params[3] = ac_vo;
|
||||||
config->p2p_search_delay = DEFAULT_P2P_SEARCH_DELAY;
|
config->p2p_search_delay = DEFAULT_P2P_SEARCH_DELAY;
|
||||||
config->rand_addr_lifetime = DEFAULT_RAND_ADDR_LIFETIME;
|
config->rand_addr_lifetime = DEFAULT_RAND_ADDR_LIFETIME;
|
||||||
|
config->key_mgmt_offload = DEFAULT_KEY_MGMT_OFFLOAD;
|
||||||
|
|
||||||
if (ctrl_interface)
|
if (ctrl_interface)
|
||||||
config->ctrl_interface = os_strdup(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(mac_addr), 0 },
|
||||||
{ INT(rand_addr_lifetime), 0 },
|
{ INT(rand_addr_lifetime), 0 },
|
||||||
{ INT(preassoc_mac_addr), 0 },
|
{ INT(preassoc_mac_addr), 0 },
|
||||||
|
{ INT(key_mgmt_offload), 0},
|
||||||
};
|
};
|
||||||
|
|
||||||
#undef FUNC
|
#undef FUNC
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#define DEFAULT_SCAN_CUR_FREQ 0
|
#define DEFAULT_SCAN_CUR_FREQ 0
|
||||||
#define DEFAULT_P2P_SEARCH_DELAY 500
|
#define DEFAULT_P2P_SEARCH_DELAY 500
|
||||||
#define DEFAULT_RAND_ADDR_LIFETIME 60
|
#define DEFAULT_RAND_ADDR_LIFETIME 60
|
||||||
|
#define DEFAULT_KEY_MGMT_OFFLOAD 1
|
||||||
|
|
||||||
#include "config_ssid.h"
|
#include "config_ssid.h"
|
||||||
#include "wps/wps.h"
|
#include "wps/wps.h"
|
||||||
|
@ -1088,6 +1089,17 @@ struct wpa_config {
|
||||||
* 2 = like 1, but maintain OUI (with local admin bit set)
|
* 2 = like 1, but maintain OUI (with local admin bit set)
|
||||||
*/
|
*/
|
||||||
int preassoc_mac_addr;
|
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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1192,6 +1192,9 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
|
||||||
|
|
||||||
if (config->preassoc_mac_addr)
|
if (config->preassoc_mac_addr)
|
||||||
fprintf(f, "preassoc_mac_addr=%d\n", 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 */
|
#endif /* CONFIG_NO_CONFIG_WRITE */
|
||||||
|
|
|
@ -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,
|
void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
|
||||||
union wpa_event_data *data)
|
union wpa_event_data *data)
|
||||||
{
|
{
|
||||||
|
@ -2934,6 +2952,8 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
|
||||||
break;
|
break;
|
||||||
case EVENT_ASSOC:
|
case EVENT_ASSOC:
|
||||||
wpa_supplicant_event_assoc(wpa_s, data);
|
wpa_supplicant_event_assoc(wpa_s, data);
|
||||||
|
if (data && data->assoc_info.authorized)
|
||||||
|
wpa_supplicant_event_assoc_auth(wpa_s, data);
|
||||||
break;
|
break;
|
||||||
case EVENT_DISASSOC:
|
case EVENT_DISASSOC:
|
||||||
wpas_event_disassoc(wpa_s,
|
wpas_event_disassoc(wpa_s,
|
||||||
|
|
|
@ -1921,6 +1921,22 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
|
||||||
params.psk = ssid->psk;
|
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;
|
params.drop_unencrypted = use_crypt;
|
||||||
|
|
||||||
#ifdef CONFIG_IEEE80211W
|
#ifdef CONFIG_IEEE80211W
|
||||||
|
|
|
@ -915,6 +915,19 @@ static void wpa_supplicant_set_rekey_offload(void *ctx, const u8 *kek,
|
||||||
#endif /* CONFIG_NO_WPA */
|
#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)
|
int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s)
|
||||||
{
|
{
|
||||||
#ifndef CONFIG_NO_WPA
|
#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;
|
ctx->tdls_peer_addset = wpa_supplicant_tdls_peer_addset;
|
||||||
#endif /* CONFIG_TDLS */
|
#endif /* CONFIG_TDLS */
|
||||||
ctx->set_rekey_offload = wpa_supplicant_set_rekey_offload;
|
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);
|
wpa_s->wpa = wpa_sm_init(ctx);
|
||||||
if (wpa_s->wpa == NULL) {
|
if (wpa_s->wpa == NULL) {
|
||||||
|
|
Loading…
Reference in a new issue