@@ -581,6 +581,53 @@ static int wpa_derive_ptk(struct wpa_sm *sm, const unsigned char *src_addr,
sm->pairwise_cipher, z, z_len);
}
+static int handle_extended_key_id(struct wpa_sm *sm,
+ struct wpa_eapol_ie_parse *kde,
+ const u8 *rsn_ie, size_t rsn_ie_len)
+{
+ struct wpa_ie_data rsn;
+
+ /* IEEE 802.11 - 2016 requires the Extended Key ID
+ * bit to be set in the RSN capabilities for both STAs
+ * to use it with CCMP/GCMP
+ */
+ if (sm->wpa_extended_key_id && rsn_ie &&
+ sm->pairwise_cipher != WPA_CIPHER_TKIP &&
+ wpa_parse_wpa_ie_rsn(rsn_ie, rsn_ie_len, &rsn) >= 0 &&
+ rsn.capabilities & WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST) {
+ if (!kde->key_id) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_ERROR,
+ "WPA: No KeyID in Extended Key ID handshake");
+ return -1;
+ } else if (kde->key_id[0] & 0xfe) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_ERROR,
+ "WPA: Invalid KeyID: %d", kde->key_id[0]);
+ return -1;
+ }
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "WPA: Using Extended Key ID");
+ sm->keyidx_active = kde->key_id[0];
+ sm->use_extended_key_id = 1;
+ } else {
+ if (kde->key_id && kde->key_id[0]) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_ERROR,
+ "WPA: Non-zero KeyID in legacy handshake");
+ return -1;
+ } else if (kde->key_id) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+ "WPA: KeyID in legacy handshake");
+ } else if (!rsn_ie || sm->pairwise_cipher == WPA_CIPHER_TKIP) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "WPA: Extended Key ID requires wpa2 and CCMP/GCMP");
+ }
+ if (sm->wpa_extended_key_id)
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "WPA: Not using Extended Key ID");
+ sm->keyidx_active = 0;
+ sm->use_extended_key_id = 0;
+ }
+ return 0;
+}
static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
const unsigned char *src_addr,
@@ -779,6 +826,14 @@ static void wpa_sm_rekey_ptk(void *eloop_ctx, void *timeout_ctx)
wpa_sm_key_request(sm, 0, 1);
}
+static void wpa_supplicant_ptk_installed(struct wpa_sm *sm)
+{
+ if (sm->wpa_ptk_rekey) {
+ eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL);
+ eloop_register_timeout(sm->wpa_ptk_rekey, 0, wpa_sm_rekey_ptk,
+ sm, NULL);
+ }
+}
static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
const struct wpa_eapol_key *key,
@@ -826,12 +881,14 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
wpa_hexdump(MSG_DEBUG, "WPA: RSC", key_rsc, rsclen);
}
- if (wpa_sm_set_key(sm, alg, sm->bssid, 0, key_rsc, rsclen,
- sm->ptk.tk, keylen, key_type) < 0) {
+ if (wpa_sm_set_key(sm, alg, sm->bssid, sm->keyidx_active, key_rsc,
+ rsclen, sm->ptk.tk, keylen, key_type) < 0) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
- "WPA: Failed to set PTK to the "
- "driver (alg=%d keylen=%d bssid=" MACSTR ")",
- alg, keylen, MAC2STR(sm->bssid));
+ "WPA: Failed to set PTK to the driver"
+ "(alg=%d keylen=%d bssid=" MACSTR
+ " idx=%d use_extended_key_id=%d key_type=%d)",
+ alg, keylen, MAC2STR(sm->bssid),
+ sm->keyidx_active, sm->use_extended_key_id, key_type);
return -1;
}
@@ -840,12 +897,27 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
sm->ptk.tk_len = 0;
sm->ptk.installed = 1;
- if (sm->wpa_ptk_rekey) {
- eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL);
- eloop_register_timeout(sm->wpa_ptk_rekey, 0, wpa_sm_rekey_ptk,
- sm, NULL);
+ if (key_type != KEY_TYPE_NO_AUTO_TX)
+ wpa_supplicant_ptk_installed(sm);
+
+ return 0;
+}
+
+static int wpa_supplicant_activate_ptk(struct wpa_sm *sm)
+{
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "WPA: Activate PTK (idx=%d bssid=" MACSTR ")",
+ sm->keyidx_active, MAC2STR(sm->bssid));
+
+ if (wpa_sm_set_key(sm, 0, sm->bssid, sm->keyidx_active,
+ 0, 0, NULL, 0, KEY_TYPE_SET_TX) < 0) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_ERROR,
+ "WPA: Failed to activate PTK for Tx (idx=%d bssid="
+ MACSTR ")", sm->keyidx_active, MAC2STR(sm->bssid));
+ return -1;
}
+ wpa_supplicant_ptk_installed(sm);
return 0;
}
@@ -1481,6 +1553,9 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
if (wpa_supplicant_validate_ie(sm, sm->bssid, &ie) < 0)
goto failed;
+ if (handle_extended_key_id(sm, &ie, ie.rsn_ie, ie.rsn_ie_len))
+ goto failed;
+
if (os_memcmp(sm->anonce, key->key_nonce, WPA_NONCE_LEN) != 0) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: ANonce from message 1 of 4-Way Handshake "
@@ -1525,6 +1600,10 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
}
}
#endif /* CONFIG_OCV */
+ if (sm->use_extended_key_id) {
+ if (wpa_supplicant_install_ptk(sm, key, KEY_TYPE_NO_AUTO_TX))
+ goto failed;
+ }
if (wpa_supplicant_send_4_of_4(sm, sm->bssid, key, ver, key_info,
&sm->ptk) < 0) {
@@ -1537,8 +1616,13 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
sm->renew_snonce = 1;
if (key_info & WPA_KEY_INFO_INSTALL) {
- if (wpa_supplicant_install_ptk(sm, key, KEY_TYPE_PAIRWISE))
+ if (sm->use_extended_key_id) {
+ if (wpa_supplicant_activate_ptk(sm))
+ goto failed;
+ } else if (wpa_supplicant_install_ptk(sm, key,
+ KEY_TYPE_PAIRWISE)) {
goto failed;
+ }
}
if (key_info & WPA_KEY_INFO_SECURE) {
@@ -2645,6 +2729,7 @@ struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx)
return NULL;
dl_list_init(&sm->pmksa_candidates);
sm->renew_snonce = 1;
+ sm->keyidx_active = 0;
sm->ctx = ctx;
sm->dot11RSNAConfigPMKLifetime = 43200;
@@ -3035,6 +3120,9 @@ int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param,
case WPA_PARAM_PAIRWISE:
sm->pairwise_cipher = value;
break;
+ case WPA_PARAM_EXTENDED_KEY_ID:
+ sm->wpa_extended_key_id = value;
+ break;
case WPA_PARAM_GROUP:
sm->group_cipher = value;
break;
@@ -3160,6 +3248,9 @@ int wpa_sm_set_assoc_wpa_ie_default(struct wpa_sm *sm, u8 *wpa_ie,
#ifdef CONFIG_TESTING_OPTIONS
if (sm->test_assoc_ie) {
+ struct wpa_eapol_ie_parse ie;
+ struct wpa_ie_data rsn;
+
wpa_printf(MSG_DEBUG,
"TESTING: Replace association WPA/RSN IE");
if (*wpa_ie_len < wpabuf_len(sm->test_assoc_ie))
@@ -3167,6 +3258,15 @@ int wpa_sm_set_assoc_wpa_ie_default(struct wpa_sm *sm, u8 *wpa_ie,
os_memcpy(wpa_ie, wpabuf_head(sm->test_assoc_ie),
wpabuf_len(sm->test_assoc_ie));
res = wpabuf_len(sm->test_assoc_ie);
+
+ if (wpa_supplicant_parse_ies(wpa_ie, res, &ie) ||
+ wpa_parse_wpa_ie_rsn(ie.rsn_ie, ie.rsn_ie_len, &rsn) ||
+ !(rsn.capabilities &
+ WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST)) {
+ wpa_printf(MSG_DEBUG,
+ "TESTING: Force disable Extended Key ID");
+ sm->wpa_extended_key_id = 0;
+ }
} else
#endif /* CONFIG_TESTING_OPTIONS */
res = wpa_gen_wpa_ie(sm, wpa_ie, *wpa_ie_len);
@@ -3504,6 +3604,10 @@ int wpa_sm_has_ptk(struct wpa_sm *sm)
return sm->ptk_set;
}
+int wpa_sm_extended_key_id(struct wpa_sm *sm)
+{
+ return sm->wpa_extended_key_id;
+}
void wpa_sm_update_replay_ctr(struct wpa_sm *sm, const u8 *replay_ctr)
{
@@ -4130,6 +4234,8 @@ static int fils_ft_build_assoc_req_rsne(struct wpa_sm *sm, struct wpabuf *buf)
capab |= WPA_CAPABILITY_MFPR;
if (sm->ocv)
capab |= WPA_CAPABILITY_OCVC;
+ if (sm->wpa_extended_key_id)
+ capab |= WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST;
wpabuf_put_le16(buf, capab);
/* PMKID Count */
@@ -100,6 +100,7 @@ enum wpa_sm_conf_params {
WPA_PARAM_MFP,
WPA_PARAM_OCV,
WPA_PARAM_SAE_PWE,
+ WPA_PARAM_EXTENDED_KEY_ID
};
struct rsn_supp_config {
@@ -110,6 +111,7 @@ struct rsn_supp_config {
void *eap_conf_ctx;
const u8 *ssid;
size_t ssid_len;
+ int wpa_extended_key_id;
int wpa_ptk_rekey;
int p2p;
int wpa_rsc_relaxation;
@@ -172,6 +174,7 @@ int wpa_sm_pmksa_exists(struct wpa_sm *sm, const u8 *bssid,
const void *network_ctx);
void wpa_sm_drop_sa(struct wpa_sm *sm);
int wpa_sm_has_ptk(struct wpa_sm *sm);
+int wpa_sm_extended_key_id(struct wpa_sm *sm);
void wpa_sm_update_replay_ctr(struct wpa_sm *sm, const u8 *replay_ctr);
@@ -256,6 +256,8 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
capab |= WPA_CAPABILITY_MFPR;
if (sm->ocv)
capab |= WPA_CAPABILITY_OCVC;
+ if (sm->wpa_extended_key_id)
+ capab |= WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST;
WPA_PUT_LE16(pos, capab);
pos += 2;
@@ -422,8 +424,9 @@ static int wpa_ft_install_ptk(struct wpa_sm *sm, const u8 *bssid)
alg = wpa_cipher_to_alg(sm->pairwise_cipher);
keylen = wpa_cipher_key_len(sm->pairwise_cipher);
- if (wpa_sm_set_key(sm, alg, bssid, 0, null_rsc, sizeof(null_rsc),
- (u8 *) sm->ptk.tk, keylen, KEY_TYPE_PAIRWISE) < 0) {
+ if (wpa_sm_set_key(sm, alg, bssid, sm->keyidx_active, null_rsc,
+ sizeof(null_rsc), (u8 *) sm->ptk.tk, keylen,
+ KEY_TYPE_PAIRWISE) < 0) {
wpa_printf(MSG_WARNING, "FT: Failed to set PTK to the driver");
return -1;
}
@@ -26,6 +26,7 @@ struct wpa_sm {
u8 snonce[WPA_NONCE_LEN];
u8 anonce[WPA_NONCE_LEN]; /* ANonce from the last 1/4 msg */
int renew_snonce;
+ int keyidx_active;
u8 rx_replay_counter[WPA_REPLAY_COUNTER_LEN];
int rx_replay_counter_set;
u8 request_counter[WPA_REPLAY_COUNTER_LEN];
@@ -63,6 +64,8 @@ struct wpa_sm {
int wpa_ptk_rekey;
int p2p;
int wpa_rsc_relaxation;
+ int wpa_extended_key_id;
+ int use_extended_key_id;
u8 own_addr[ETH_ALEN];
const char *ifname;
@@ -221,6 +221,9 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
capab |= WPA_CAPABILITY_MFPR;
if (sm->ocv)
capab |= WPA_CAPABILITY_OCVC;
+ if (sm->wpa_extended_key_id)
+ capab |= WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST;
+
WPA_PUT_LE16(pos, capab);
pos += 2;
@@ -2494,6 +2494,7 @@ static const struct parse_data ssid_fields[] = {
{ INT(dot11MeshConfirmTimeout) },
{ INT(dot11MeshHoldingTimeout) },
#endif /* CONFIG_MESH */
+ { INT(wpa_extended_key_id) },
{ INT(wpa_ptk_rekey) },
{ INT(group_rekey) },
{ STR(bgscan) },
@@ -3016,6 +3017,7 @@ void wpa_config_set_network_defaults(struct wpa_ssid *ssid)
{
ssid->proto = DEFAULT_PROTO;
ssid->pairwise_cipher = DEFAULT_PAIRWISE;
+ ssid->wpa_extended_key_id = DEFAULT_EXTENDED_KEY_ID;
ssid->group_cipher = DEFAULT_GROUP;
ssid->key_mgmt = DEFAULT_KEY_MGMT;
ssid->bg_scan_period = DEFAULT_BG_SCAN_PERIOD;
@@ -899,6 +899,7 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
INT_DEF(dot11MeshHoldingTimeout, DEFAULT_MESH_HOLDING_TIMEOUT);
INT_DEF(mesh_rssi_threshold, DEFAULT_MESH_RSSI_THRESHOLD);
#endif /* CONFIG_MESH */
+ INT(wpa_extended_key_id);
INT(wpa_ptk_rekey);
INT(group_rekey);
INT(ignore_broadcast_ssid);
@@ -22,6 +22,7 @@
#define DEFAULT_PAIRWISE (WPA_CIPHER_CCMP | WPA_CIPHER_TKIP)
#define DEFAULT_GROUP (WPA_CIPHER_CCMP | WPA_CIPHER_TKIP)
#define DEFAULT_FRAGMENT_SIZE 1398
+#define DEFAULT_EXTENDED_KEY_ID 1
#define DEFAULT_BG_SCAN_PERIOD -1
#define DEFAULT_MESH_MAX_RETRIES 2
@@ -545,6 +546,15 @@ struct wpa_ssid {
unsigned int vht_center_freq1;
unsigned int vht_center_freq2;
+ /** wpa_extended_key_id - Extended Key ID support
+ *
+ * IEEE 802.11-2016 optionally allows to use key id 0 and 1 for PTK keys
+ * default: auto (1)
+ * 0 = force off. Do not announce or use Extended Key ID.
+ * 1 = auto. Use Extended Key ID when possible.
+ */
+ int wpa_extended_key_id;
+
/**
* wpa_ptk_rekey - Maximum lifetime for PTK in seconds
*
@@ -5264,6 +5264,9 @@ static void wpa_supplicant_ctrl_iface_drop_sa(struct wpa_supplicant *wpa_s)
wpa_drv_set_key(wpa_s, WPA_ALG_NONE, wpa_s->bssid, 0, NULL, 0, NULL,
0, KEY_TYPE_PAIRWISE);
+ if (wpa_sm_extended_key_id(wpa_s->wpa))
+ wpa_drv_set_key(wpa_s, WPA_ALG_NONE, wpa_s->bssid, 1, NULL,
+ 0, NULL, 0, KEY_TYPE_PAIRWISE);
/* MLME-SETPROTECTION.request(None) */
wpa_drv_mlme_setprotection(wpa_s, wpa_s->bssid,
MLME_SETPROTECTION_PROTECT_TYPE_NONE,
@@ -155,10 +155,19 @@ static inline int wpa_drv_set_key(struct wpa_supplicant *wpa_s,
enum key_type key_type)
{
if (alg != WPA_ALG_NONE) {
- if (key_idx >= 0 && key_idx <= 6)
+ if (key_idx == 1 &&
+ (key_type == KEY_TYPE_PAIRWISE ||
+ key_type == KEY_TYPE_NO_AUTO_TX)) {
+ /* keyidx = 1 can be either a broadcast or - with
+ * Extended Key ID - an unicast key. Use bit 6 for
+ * the pairwise keyidx 1.
+ */
+ wpa_s->keys_cleared &= ~BIT(6);
+ } else if (key_idx >= 0 && key_idx <= 5) {
wpa_s->keys_cleared &= ~BIT(key_idx);
- else
+ } else {
wpa_s->keys_cleared = 0;
+ }
}
if (wpa_s->driver->set_key) {
return wpa_s->driver->set_key(wpa_s->ifname, wpa_s->drv_priv,
@@ -1437,8 +1437,8 @@ static const char *network_fields[] = {
"dot11MeshRetryTimeout", "dot11MeshConfirmTimeout",
"dot11MeshHoldingTimeout",
#endif /* CONFIG_MESH */
- "wpa_ptk_rekey", "bgscan", "ignore_broadcast_ssid",
- "enable_edmg", "edmg_channel",
+ "wpa_extended_key_id", "wpa_ptk_rekey", "bgscan",
+ "ignore_broadcast_ssid", "enable_edmg", "edmg_channel",
#ifdef CONFIG_P2P
"go_p2p_dev_addr", "p2p_client_list", "psk_list",
#endif /* CONFIG_P2P */
@@ -706,10 +706,15 @@ void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr)
wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, i, NULL, 0,
NULL, 0, KEY_TYPE_BROADCAST);
}
- if (!(wpa_s->keys_cleared & BIT(0)) && addr &&
+ /* Pairwise key idx 1 for Extended Key ID is tracked with bit 6 */
+ if (~wpa_s->keys_cleared & (BIT(0) | BIT(6)) && addr &&
!is_zero_ether_addr(addr)) {
- wpa_drv_set_key(wpa_s, WPA_ALG_NONE, addr, 0, NULL, 0, NULL,
- 0, KEY_TYPE_PAIRWISE);
+ if (!(wpa_s->keys_cleared & (BIT(0))))
+ wpa_drv_set_key(wpa_s, WPA_ALG_NONE, addr, 0, NULL,
+ 0, NULL, 0, KEY_TYPE_PAIRWISE);
+ if (!(wpa_s->keys_cleared & (BIT(6))))
+ wpa_drv_set_key(wpa_s, WPA_ALG_NONE, addr, 1, NULL,
+ 0, NULL, 0, KEY_TYPE_PAIRWISE);
/* MLME-SETPROTECTION.request(None) */
wpa_drv_mlme_setprotection(
wpa_s, addr,
@@ -1241,6 +1246,23 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
int sel, proto;
const u8 *bss_wpa, *bss_rsn, *bss_rsnx, *bss_osen;
+ if (ssid->mode == WPAS_MODE_INFRA && ssid->wpa_extended_key_id &&
+ ssid->proto & WPA_PROTO_RSN &&
+ ssid->pairwise_cipher & (WPA_CIPHER_CCMP | WPA_CIPHER_CCMP_256 |
+ WPA_CIPHER_GCMP | WPA_CIPHER_GCMP_256) &&
+ wpa_s->drv_flags & WPA_DRIVER_FLAGS_EXTENDED_KEY_ID) {
+ wpa_msg(wpa_s, MSG_INFO, "Enable Extended Key ID support");
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_EXTENDED_KEY_ID, 1);
+ } else {
+ if (ssid->wpa_extended_key_id)
+ wpa_msg(wpa_s, MSG_INFO,
+ "Extended Key ID not supported");
+ else
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Extended Key ID support disabled");
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_EXTENDED_KEY_ID, 0);
+ }
+
if (bss) {
bss_wpa = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
bss_rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
@@ -1098,6 +1098,11 @@ fast_reauth=1
# hex without quotation, e.g., 0102030405)
# wep_tx_keyidx: Default WEP key index (TX) (0..3)
#
+# wpa_extended_key_id:
+# Support the unicast rekey protocol "Extended Key ID" from IEEE 802.11 - 2016.
+# 0 = force off: Do not announce or use Extended Key ID
+# 1 = auto: Use Extended Key ID when possible (default)
+#
# wpa_ptk_rekey: Maximum lifetime for PTK in seconds. This can be used to
# enforce rekeying of PTK to mitigate some attacks against TKIP deficiencies.
#
@@ -510,7 +510,8 @@ static int wpa_supplicant_set_key(void *_wpa_s, enum wpa_alg alg,
}
#endif /* CONFIG_TESTING_GET_GTK */
#ifdef CONFIG_TESTING_OPTIONS
- if (addr && !is_broadcast_ether_addr(addr)) {
+ if (addr && !is_broadcast_ether_addr(addr) &&
+ key_type != KEY_TYPE_SET_TX) {
wpa_s->last_tk_alg = alg;
os_memcpy(wpa_s->last_tk_addr, addr, ETH_ALEN);
wpa_s->last_tk_key_idx = key_idx;
@@ -1277,6 +1278,7 @@ void wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s,
#endif /* IEEE8021X_EAPOL */
conf.ssid = ssid->ssid;
conf.ssid_len = ssid->ssid_len;
+ conf.wpa_extended_key_id = ssid->wpa_extended_key_id;
conf.wpa_ptk_rekey = ssid->wpa_ptk_rekey;
#ifdef CONFIG_P2P
if (ssid->p2p_group && wpa_s->current_bss &&
Support Extended Key ID in wpa_supplicant according to IEEE 802.11 - 2016 for infrastructure (AP) associations. Extended Key ID allows to rekey pairwise keys without the otherwise unavoidable MPDU losses on a busy link. The standard is fully backward compatible, allowing a STA to connect to AP's with and without Extended Key ID support. Signed-off-by: Alexander Wetzel <alexander@wetzel-home.de> --- This complements the AP Extended Key ID patch for wpa_supplicant. For now we only have "client" Extended Key ID support covered in wpa_supplicant. IBSS and potential TDLS/mesh extensions are missing for now. (A proposal for FILS support is in a separate patch.) src/rsn_supp/wpa.c | 126 ++++++++++++++++++++++++++--- src/rsn_supp/wpa.h | 3 + src/rsn_supp/wpa_ft.c | 7 +- src/rsn_supp/wpa_i.h | 3 + src/rsn_supp/wpa_ie.c | 3 + wpa_supplicant/config.c | 2 + wpa_supplicant/config_file.c | 1 + wpa_supplicant/config_ssid.h | 10 +++ wpa_supplicant/ctrl_iface.c | 3 + wpa_supplicant/driver_i.h | 13 ++- wpa_supplicant/wpa_cli.c | 4 +- wpa_supplicant/wpa_supplicant.c | 28 ++++++- wpa_supplicant/wpa_supplicant.conf | 5 ++ wpa_supplicant/wpas_glue.c | 4 +- 14 files changed, 192 insertions(+), 20 deletions(-)