aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--hostapd/config_file.c2
-rw-r--r--hostapd/hostapd.conf3
-rw-r--r--src/ap/ap_config.c5
-rw-r--r--src/ap/ap_config.h4
-rw-r--r--src/ap/ap_drv_ops.c11
-rw-r--r--src/ap/beacon.c6
-rw-r--r--src/ap/drv_callbacks.c29
-rw-r--r--src/ap/hostapd.c4
-rw-r--r--src/ap/hs20.c54
-rw-r--r--src/ap/hs20.h3
-rw-r--r--src/ap/ieee802_11.c30
-rw-r--r--src/ap/ieee802_1x.c11
-rw-r--r--src/ap/wpa_auth.c13
-rw-r--r--src/ap/wpa_auth.h3
-rw-r--r--src/ap/wpa_auth_glue.c13
-rw-r--r--src/ap/wpa_auth_ie.c88
-rw-r--r--src/ap/wpa_auth_ie.h3
-rw-r--r--src/drivers/driver.h5
-rw-r--r--src/rsn_supp/wpa.c32
19 files changed, 294 insertions, 25 deletions
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 26f52e9..d38c3f8 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -2810,6 +2810,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
bss->hs20 = atoi(pos);
} else if (os_strcmp(buf, "disable_dgaf") == 0) {
bss->disable_dgaf = atoi(pos);
+ } else if (os_strcmp(buf, "osen") == 0) {
+ bss->osen = atoi(pos);
} else if (os_strcmp(buf, "anqp_domain_id") == 0) {
bss->anqp_domain_id = atoi(pos);
} else if (os_strcmp(buf, "hs20_oper_friendly_name") == 0) {
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index 0630320..332cee0 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -1582,6 +1582,9 @@ own_ip_addr=127.0.0.1
# forging such frames to other stations in the BSS.
#disable_dgaf=1
+# OSU Server-Only Authenticated L2 Encryption Network
+#osen=1
+
# ANQP Domain ID (0..65535)
# An identifier for a set of APs in an ESS that share the same common ANQP
# information. 0 = Some of the ANQP information is unique to this AP (default).
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index f5014a5..cb5d3aa 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -890,6 +890,11 @@ void hostapd_set_security_params(struct hostapd_bss_config *bss)
bss->wpa_group = cipher;
bss->wpa_pairwise = cipher;
bss->rsn_pairwise = cipher;
+ } else if (bss->osen) {
+ bss->ssid.security_policy = SECURITY_OSEN;
+ bss->wpa_group = WPA_CIPHER_CCMP;
+ bss->wpa_pairwise = 0;
+ bss->rsn_pairwise = WPA_CIPHER_CCMP;
} else {
bss->ssid.security_policy = SECURITY_PLAINTEXT;
bss->wpa_group = WPA_CIPHER_NONE;
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index b6e8cbc..73645cd 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -45,7 +45,8 @@ typedef enum hostap_security_policy {
SECURITY_STATIC_WEP = 1,
SECURITY_IEEE_802_1X = 2,
SECURITY_WPA_PSK = 3,
- SECURITY_WPA = 4
+ SECURITY_WPA = 4,
+ SECURITY_OSEN = 5
} secpolicy;
struct hostapd_ssid {
@@ -452,6 +453,7 @@ struct hostapd_bss_config {
u8 qos_map_set[16 + 2 * 21];
unsigned int qos_map_set_len;
+ int osen;
#ifdef CONFIG_HS20
int hs20;
int disable_dgaf;
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index e998fc6..b8b260a 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -170,6 +170,17 @@ int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
goto fail;
wpabuf_put_data(proberesp, buf, pos - buf);
}
+
+ pos = hostapd_eid_osen(hapd, buf);
+ if (pos != buf) {
+ if (wpabuf_resize(&beacon, pos - buf) != 0)
+ goto fail;
+ wpabuf_put_data(beacon, buf, pos - buf);
+
+ if (wpabuf_resize(&proberesp, pos - buf) != 0)
+ goto fail;
+ wpabuf_put_data(proberesp, buf, pos - buf);
+ }
#endif /* CONFIG_HS20 */
if (hapd->conf->vendor_elements) {
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 33320bd..e06ce77 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -442,6 +442,7 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
#ifdef CONFIG_HS20
pos = hostapd_eid_hs20_indication(hapd, pos);
+ pos = hostapd_eid_osen(hapd, pos);
#endif /* CONFIG_HS20 */
if (hapd->conf->vendor_elements) {
@@ -854,6 +855,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
#ifdef CONFIG_HS20
tailpos = hostapd_eid_hs20_indication(hapd, tailpos);
+ tailpos = hostapd_eid_osen(hapd, tailpos);
#endif /* CONFIG_HS20 */
if (hapd->conf->vendor_elements) {
@@ -925,6 +927,10 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
params->ap_max_inactivity = hapd->conf->ap_max_inactivity;
#ifdef CONFIG_HS20
params->disable_dgaf = hapd->conf->disable_dgaf;
+ if (hapd->conf->osen) {
+ params->privacy = 1;
+ params->osen = 1;
+ }
#endif /* CONFIG_HS20 */
return 0;
}
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 9af9646..6fb1056 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -78,6 +78,12 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
ie = elems.wpa_ie - 2;
ielen = elems.wpa_ie_len + 2;
wpa_printf(MSG_DEBUG, "STA included WPA IE in (Re)AssocReq");
+#ifdef CONFIG_HS20
+ } else if (elems.osen) {
+ ie = elems.osen - 2;
+ ielen = elems.osen_len + 2;
+ wpa_printf(MSG_DEBUG, "STA included OSEN IE in (Re)AssocReq");
+#endif /* CONFIG_HS20 */
} else {
ie = NULL;
ielen = 0;
@@ -281,6 +287,29 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
sta->flags |= WLAN_STA_MAYBE_WPS;
wpabuf_free(wps);
#endif /* CONFIG_WPS */
+#ifdef CONFIG_HS20
+ } else if (hapd->conf->osen) {
+ if (elems.osen == NULL) {
+ hostapd_logger(
+ hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO,
+ "No HS 2.0 OSEN element in association request");
+ return WLAN_STATUS_INVALID_IE;
+ }
+
+ wpa_printf(MSG_DEBUG, "HS 2.0: OSEN association");
+ if (sta->wpa_sm == NULL)
+ sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
+ sta->addr, NULL);
+ if (sta->wpa_sm == NULL) {
+ wpa_printf(MSG_WARNING, "Failed to initialize WPA "
+ "state machine");
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+ if (wpa_validate_osen(hapd->wpa_auth, sta->wpa_sm,
+ elems.osen - 2, elems.osen_len + 2) < 0)
+ return WLAN_STATUS_INVALID_IE;
+#endif /* CONFIG_HS20 */
}
#ifdef CONFIG_WPS
skip_wpa_check:
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 98148da..75baec0 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -87,7 +87,7 @@ static void hostapd_reload_bss(struct hostapd_data *hapd)
else
hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 0);
- if (hapd->conf->wpa && hapd->wpa_auth == NULL) {
+ if ((hapd->conf->wpa || hapd->conf->osen) && hapd->wpa_auth == NULL) {
hostapd_setup_wpa(hapd);
if (hapd->wpa_auth)
wpa_init_keys(hapd->wpa_auth);
@@ -802,7 +802,7 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
return -1;
}
- if (hapd->conf->wpa && hostapd_setup_wpa(hapd))
+ if ((hapd->conf->wpa || hapd->conf->osen) && hostapd_setup_wpa(hapd))
return -1;
if (accounting_init(hapd)) {
diff --git a/src/ap/hs20.c b/src/ap/hs20.c
index 5875b40..d521d2c 100644
--- a/src/ap/hs20.c
+++ b/src/ap/hs20.c
@@ -1,7 +1,7 @@
/*
* Hotspot 2.0 AP ANQP processing
* Copyright (c) 2009, Atheros Communications, Inc.
- * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ * Copyright (c) 2011-2013, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -39,6 +39,58 @@ u8 * hostapd_eid_hs20_indication(struct hostapd_data *hapd, u8 *eid)
}
+u8 * hostapd_eid_osen(struct hostapd_data *hapd, u8 *eid)
+{
+ u8 *len;
+ u16 capab;
+
+ if (!hapd->conf->osen)
+ return eid;
+
+ *eid++ = WLAN_EID_VENDOR_SPECIFIC;
+ len = eid++; /* to be filled */
+ WPA_PUT_BE24(eid, OUI_WFA);
+ eid += 3;
+ *eid++ = HS20_OSEN_OUI_TYPE;
+
+ /* Group Data Cipher Suite */
+ RSN_SELECTOR_PUT(eid, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED);
+ eid += RSN_SELECTOR_LEN;
+
+ /* Pairwise Cipher Suite Count and List */
+ WPA_PUT_LE16(eid, 1);
+ eid += 2;
+ RSN_SELECTOR_PUT(eid, RSN_CIPHER_SUITE_CCMP);
+ eid += RSN_SELECTOR_LEN;
+
+ /* AKM Suite Count and List */
+ WPA_PUT_LE16(eid, 1);
+ eid += 2;
+ RSN_SELECTOR_PUT(eid, RSN_AUTH_KEY_MGMT_OSEN);
+ eid += RSN_SELECTOR_LEN;
+
+ /* RSN Capabilities */
+ capab = 0;
+ if (hapd->conf->wmm_enabled) {
+ /* 4 PTKSA replay counters when using WMM */
+ capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
+ }
+#ifdef CONFIG_IEEE80211W
+ if (hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+ capab |= WPA_CAPABILITY_MFPC;
+ if (hapd->conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)
+ capab |= WPA_CAPABILITY_MFPR;
+ }
+#endif /* CONFIG_IEEE80211W */
+ WPA_PUT_LE16(eid, capab);
+ eid += 2;
+
+ *len = eid - len - 1;
+
+ return eid;
+}
+
+
int hs20_send_wnm_notification(struct hostapd_data *hapd, const u8 *addr,
u8 osu_method, const char *url)
{
diff --git a/src/ap/hs20.h b/src/ap/hs20.h
index 059764e..c7ffa36 100644
--- a/src/ap/hs20.h
+++ b/src/ap/hs20.h
@@ -1,6 +1,6 @@
/*
* Hotspot 2.0 AP ANQP processing
- * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ * Copyright (c) 2011-2013, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -12,6 +12,7 @@
struct hostapd_data;
u8 * hostapd_eid_hs20_indication(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_osen(struct hostapd_data *hapd, u8 *eid);
int hs20_send_wnm_notification(struct hostapd_data *hapd, const u8 *addr,
u8 osu_method, const char *url);
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index f3e0df3..3e704e5 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -162,6 +162,11 @@ u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta,
if (hapd->conf->wpa)
privacy = 1;
+#ifdef CONFIG_HS20
+ if (hapd->conf->osen)
+ privacy = 1;
+#endif /* CONFIG_HS20 */
+
if (sta) {
int policy, def_klen;
if (probe && sta->ssid_probe) {
@@ -1089,6 +1094,29 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
}
#endif /* CONFIG_IEEE80211N */
+#ifdef CONFIG_HS20
+ } else if (hapd->conf->osen) {
+ if (elems.osen == NULL) {
+ hostapd_logger(
+ hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO,
+ "No HS 2.0 OSEN element in association request");
+ return WLAN_STATUS_INVALID_IE;
+ }
+
+ wpa_printf(MSG_DEBUG, "HS 2.0: OSEN association");
+ if (sta->wpa_sm == NULL)
+ sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
+ sta->addr, NULL);
+ if (sta->wpa_sm == NULL) {
+ wpa_printf(MSG_WARNING, "Failed to initialize WPA "
+ "state machine");
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+ if (wpa_validate_osen(hapd->wpa_auth, sta->wpa_sm,
+ elems.osen - 2, elems.osen_len + 2) < 0)
+ return WLAN_STATUS_INVALID_IE;
+#endif /* CONFIG_HS20 */
} else
wpa_auth_sta_no_wpa(sta->wpa_sm);
@@ -1924,7 +1952,7 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
new_assoc = 0;
sta->flags |= WLAN_STA_ASSOC;
sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE;
- if ((!hapd->conf->ieee802_1x && !hapd->conf->wpa) ||
+ if ((!hapd->conf->ieee802_1x && !hapd->conf->wpa && !hapd->conf->osen) ||
sta->auth_alg == WLAN_AUTH_FT) {
/*
* Open, static WEP, or FT protocol; no separate authorization
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index 97ba601..f07b6bf 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -686,7 +686,7 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
struct rsn_pmksa_cache_entry *pmksa;
int key_mgmt;
- if (!hapd->conf->ieee802_1x && !hapd->conf->wpa &&
+ if (!hapd->conf->ieee802_1x && !hapd->conf->wpa && !hapd->conf->osen &&
!hapd->conf->wps_state)
return;
@@ -737,7 +737,7 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
return;
}
- if (!hapd->conf->ieee802_1x &&
+ if (!hapd->conf->ieee802_1x && !hapd->conf->osen &&
!(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) {
wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore EAPOL message - "
"802.1X not enabled and WPS not used");
@@ -757,7 +757,7 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
return;
#ifdef CONFIG_WPS
- if (!hapd->conf->ieee802_1x) {
+ if (!hapd->conf->ieee802_1x && hapd->conf->wps_state) {
u32 wflags = sta->flags & (WLAN_STA_WPS |
WLAN_STA_WPS2 |
WLAN_STA_MAYBE_WPS);
@@ -875,7 +875,7 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
}
#endif /* CONFIG_WPS */
- if (!force_1x && !hapd->conf->ieee802_1x) {
+ if (!force_1x && !hapd->conf->ieee802_1x && !hapd->conf->osen) {
wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore STA - "
"802.1X not enabled or forced for WPS");
/*
@@ -913,7 +913,8 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
#ifdef CONFIG_WPS
sta->eapol_sm->flags &= ~EAPOL_SM_WAIT_START;
- if (!hapd->conf->ieee802_1x && !(sta->flags & WLAN_STA_WPS2)) {
+ if (!hapd->conf->ieee802_1x && hapd->conf->wps_state &&
+ !(sta->flags & WLAN_STA_WPS2)) {
/*
* Delay EAPOL frame transmission until a possible WPS STA
* initiates the handshake with EAPOL-Start. Only allow the
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 707a63f..cc64ff1 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -211,6 +211,8 @@ static int wpa_use_aes_cmac(struct wpa_state_machine *sm)
if (wpa_key_mgmt_sha256(sm->wpa_key_mgmt))
ret = 1;
#endif /* CONFIG_IEEE80211W */
+ if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN)
+ ret = 1;
return ret;
}
@@ -878,6 +880,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
if (sm->pairwise == WPA_CIPHER_CCMP ||
sm->pairwise == WPA_CIPHER_GCMP) {
if (wpa_use_aes_cmac(sm) &&
+ sm->wpa_key_mgmt != WPA_KEY_MGMT_OSEN &&
ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
wpa_auth_logger(wpa_auth, sm->addr,
LOGGER_WARNING,
@@ -1001,6 +1004,9 @@ continue_processing:
if (kde.rsn_ie) {
eapol_key_ie = kde.rsn_ie;
eapol_key_ie_len = kde.rsn_ie_len;
+ } else if (kde.osen) {
+ eapol_key_ie = kde.osen;
+ eapol_key_ie_len = kde.osen_len;
} else {
eapol_key_ie = kde.wpa_ie;
eapol_key_ie_len = kde.wpa_ie_len;
@@ -1286,6 +1292,8 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
if (force_version)
version = force_version;
+ else if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN)
+ version = WPA_KEY_INFO_TYPE_AKM_DEFINED;
else if (wpa_use_aes_cmac(sm))
version = WPA_KEY_INFO_TYPE_AES_128_CMAC;
else if (sm->pairwise != WPA_CIPHER_TKIP)
@@ -1308,6 +1316,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
key_data_len = kde_len;
if ((version == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES ||
+ sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN ||
version == WPA_KEY_INFO_TYPE_AES_128_CMAC) && encr) {
pad_len = key_data_len % 8;
if (pad_len)
@@ -1376,6 +1385,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
wpa_hexdump_key(MSG_DEBUG, "Plaintext EAPOL-Key Key Data",
buf, key_data_len);
if (version == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES ||
+ sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN ||
version == WPA_KEY_INFO_TYPE_AES_128_CMAC) {
if (aes_wrap(sm->PTK.kek, (key_data_len - 8) / 8, buf,
(u8 *) (key + 1))) {
@@ -1774,7 +1784,8 @@ SM_STATE(WPA_PTK, PTKSTART)
* one possible PSK for this STA.
*/
if (sm->wpa == WPA_VERSION_WPA2 &&
- wpa_key_mgmt_wpa_ieee8021x(sm->wpa_key_mgmt)) {
+ wpa_key_mgmt_wpa_ieee8021x(sm->wpa_key_mgmt) &&
+ sm->wpa_key_mgmt != WPA_KEY_MGMT_OSEN) {
pmkid = buf;
pmkid_len = 2 + RSN_SELECTOR_LEN + PMKID_LEN;
pmkid[0] = WLAN_EID_VENDOR_SPECIFIC;
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index bc3dec4..d99db69 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -232,6 +232,9 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm,
const u8 *wpa_ie, size_t wpa_ie_len,
const u8 *mdie, size_t mdie_len);
+int wpa_validate_osen(struct wpa_authenticator *wpa_auth,
+ struct wpa_state_machine *sm,
+ const u8 *osen_ie, size_t osen_ie_len);
int wpa_auth_uses_mfp(struct wpa_state_machine *sm);
struct wpa_state_machine *
wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr,
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index 5af1495..da5fea7 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -73,6 +73,19 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_HS20
wconf->disable_gtk = conf->disable_dgaf;
+ if (conf->osen) {
+ wconf->disable_gtk = 1;
+ wconf->wpa = WPA_PROTO_OSEN;
+ wconf->wpa_key_mgmt = WPA_KEY_MGMT_OSEN;
+ wconf->wpa_pairwise = 0;
+ wconf->wpa_group = WPA_CIPHER_CCMP;
+ wconf->rsn_pairwise = WPA_CIPHER_CCMP;
+ wconf->rsn_preauth = 0;
+ wconf->disable_pmksa_caching = 1;
+#ifdef CONFIG_IEEE80211W
+ wconf->ieee80211w = 1;
+#endif /* CONFIG_IEEE80211W */
+ }
#endif /* CONFIG_HS20 */
#ifdef CONFIG_TESTING_OPTIONS
wconf->corrupt_gtk_rekey_mic_probability =
diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
index 274f4d6..7a49751 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -295,6 +295,55 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
}
+static u8 * wpa_write_osen(struct wpa_auth_config *conf, u8 *eid)
+{
+ u8 *len;
+ u16 capab;
+
+ *eid++ = WLAN_EID_VENDOR_SPECIFIC;
+ len = eid++; /* to be filled */
+ WPA_PUT_BE24(eid, OUI_WFA);
+ eid += 3;
+ *eid++ = HS20_OSEN_OUI_TYPE;
+
+ /* Group Data Cipher Suite */
+ RSN_SELECTOR_PUT(eid, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED);
+ eid += RSN_SELECTOR_LEN;
+
+ /* Pairwise Cipher Suite Count and List */
+ WPA_PUT_LE16(eid, 1);
+ eid += 2;
+ RSN_SELECTOR_PUT(eid, RSN_CIPHER_SUITE_CCMP);
+ eid += RSN_SELECTOR_LEN;
+
+ /* AKM Suite Count and List */
+ WPA_PUT_LE16(eid, 1);
+ eid += 2;
+ RSN_SELECTOR_PUT(eid, RSN_AUTH_KEY_MGMT_OSEN);
+ eid += RSN_SELECTOR_LEN;
+
+ /* RSN Capabilities */
+ capab = 0;
+ if (conf->wmm_enabled) {
+ /* 4 PTKSA replay counters when using WMM */
+ capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
+ }
+#ifdef CONFIG_IEEE80211W
+ if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+ capab |= WPA_CAPABILITY_MFPC;
+ if (conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)
+ capab |= WPA_CAPABILITY_MFPR;
+ }
+#endif /* CONFIG_IEEE80211W */
+ WPA_PUT_LE16(eid, capab);
+ eid += 2;
+
+ *len = eid - len - 1;
+
+ return eid;
+}
+
+
int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth)
{
u8 *pos, buf[128];
@@ -302,6 +351,9 @@ int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth)
pos = buf;
+ if (wpa_auth->conf.wpa == WPA_PROTO_OSEN) {
+ pos = wpa_write_osen(&wpa_auth->conf, pos);
+ }
if (wpa_auth->conf.wpa & WPA_PROTO_RSN) {
res = wpa_write_rsn_ie(&wpa_auth->conf,
pos, buf + sizeof(buf) - pos, NULL);
@@ -626,6 +678,36 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
}
+#ifdef CONFIG_HS20
+int wpa_validate_osen(struct wpa_authenticator *wpa_auth,
+ struct wpa_state_machine *sm,
+ const u8 *osen_ie, size_t osen_ie_len)
+{
+ if (wpa_auth == NULL || sm == NULL)
+ return -1;
+
+ /* TODO: parse OSEN element */
+ sm->wpa_key_mgmt = WPA_KEY_MGMT_OSEN;
+ sm->mgmt_frame_prot = 1;
+ sm->pairwise = WPA_CIPHER_CCMP;
+ sm->wpa = WPA_VERSION_WPA2;
+
+ if (sm->wpa_ie == NULL || sm->wpa_ie_len < osen_ie_len) {
+ os_free(sm->wpa_ie);
+ sm->wpa_ie = os_malloc(osen_ie_len);
+ if (sm->wpa_ie == NULL)
+ return -1;
+ }
+
+ os_memcpy(sm->wpa_ie, osen_ie, osen_ie_len);
+ sm->wpa_ie_len = osen_ie_len;
+
+ return 0;
+}
+
+#endif /* CONFIG_HS20 */
+
+
/**
* wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs
* @pos: Pointer to the IE header
@@ -648,6 +730,12 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end,
return 0;
}
+ if (pos[1] >= 4 && WPA_GET_BE32(pos + 2) == OSEN_IE_VENDOR_TYPE) {
+ ie->osen = pos;
+ ie->osen_len = pos[1] + 2;
+ return 0;
+ }
+
if (pos + 1 + RSN_SELECTOR_LEN < end &&
pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) {
diff --git a/src/ap/wpa_auth_ie.h b/src/ap/wpa_auth_ie.h
index f945882..d2067ba 100644
--- a/src/ap/wpa_auth_ie.h
+++ b/src/ap/wpa_auth_ie.h
@@ -43,6 +43,9 @@ struct wpa_eapol_ie_parse {
const u8 *ip_addr_req;
const u8 *ip_addr_alloc;
#endif /* CONFIG_P2P */
+
+ const u8 *osen;
+ size_t osen_len;
};
int wpa_parse_kde_ies(const u8 *buf, size_t len,
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 69e837a..d2aad24 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -847,6 +847,11 @@ struct wpa_driver_ap_params {
* disable_dgaf - Whether group-addressed frames are disabled
*/
int disable_dgaf;
+
+ /**
+ * osen - Whether OSEN security is enabled
+ */
+ int osen;
};
/**
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index 0a6f0d8..ba50263 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -110,7 +110,8 @@ void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise)
if (rbuf == NULL)
return;
- reply->type = sm->proto == WPA_PROTO_RSN ?
+ reply->type = (sm->proto == WPA_PROTO_RSN ||
+ sm->proto == WPA_PROTO_OSEN) ?
EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
key_info = WPA_KEY_INFO_REQUEST | ver;
if (sm->ptk_set)
@@ -234,7 +235,8 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
}
if (abort_cached && wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt) &&
- !wpa_key_mgmt_ft(sm->key_mgmt)) {
+ !wpa_key_mgmt_ft(sm->key_mgmt) && sm->key_mgmt != WPA_KEY_MGMT_OSEN)
+ {
/* Send EAPOL-Start to trigger full EAP authentication. */
u8 *buf;
size_t buflen;
@@ -328,11 +330,12 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
return -1;
}
- reply->type = sm->proto == WPA_PROTO_RSN ?
+ reply->type = (sm->proto == WPA_PROTO_RSN ||
+ sm->proto == WPA_PROTO_OSEN) ?
EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
WPA_PUT_BE16(reply->key_info,
ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_MIC);
- if (sm->proto == WPA_PROTO_RSN)
+ if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN)
WPA_PUT_BE16(reply->key_length, 0);
else
os_memcpy(reply->key_length, key->key_length, 2);
@@ -397,7 +400,7 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
os_memset(&ie, 0, sizeof(ie));
- if (sm->proto == WPA_PROTO_RSN) {
+ if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) {
/* RSN: msg 1/4 should contain PMKID for the selected PMK */
const u8 *_buf = (const u8 *) (key + 1);
size_t len = WPA_GET_BE16(key->key_data_length);
@@ -564,7 +567,7 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
keylen = wpa_cipher_key_len(sm->pairwise_cipher);
rsclen = wpa_cipher_rsc_len(sm->pairwise_cipher);
- if (sm->proto == WPA_PROTO_RSN) {
+ if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) {
key_rsc = null_rsc;
} else {
key_rsc = key->key_rsc;
@@ -1036,12 +1039,13 @@ int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst,
if (rbuf == NULL)
return -1;
- reply->type = sm->proto == WPA_PROTO_RSN ?
+ reply->type = (sm->proto == WPA_PROTO_RSN ||
+ sm->proto == WPA_PROTO_OSEN) ?
EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
key_info &= WPA_KEY_INFO_SECURE;
key_info |= ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_MIC;
WPA_PUT_BE16(reply->key_info, key_info);
- if (sm->proto == WPA_PROTO_RSN)
+ if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN)
WPA_PUT_BE16(reply->key_length, 0);
else
os_memcpy(reply->key_length, key->key_length, 2);
@@ -1323,12 +1327,13 @@ static int wpa_supplicant_send_2_of_2(struct wpa_sm *sm,
if (rbuf == NULL)
return -1;
- reply->type = sm->proto == WPA_PROTO_RSN ?
+ reply->type = (sm->proto == WPA_PROTO_RSN ||
+ sm->proto == WPA_PROTO_OSEN) ?
EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
key_info &= WPA_KEY_INFO_KEY_INDEX_MASK;
key_info |= ver | WPA_KEY_INFO_MIC | WPA_KEY_INFO_SECURE;
WPA_PUT_BE16(reply->key_info, key_info);
- if (sm->proto == WPA_PROTO_RSN)
+ if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN)
WPA_PUT_BE16(reply->key_length, 0);
else
os_memcpy(reply->key_length, key->key_length, 2);
@@ -1363,7 +1368,7 @@ static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm,
key_info = WPA_GET_BE16(key->key_info);
keydatalen = WPA_GET_BE16(key->key_data_length);
- if (sm->proto == WPA_PROTO_RSN) {
+ if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) {
ret = wpa_supplicant_process_1_of_2_rsn(sm,
(const u8 *) (key + 1),
keydatalen, key_info,
@@ -1811,7 +1816,7 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
}
extra_len = WPA_GET_BE16(key->key_data_length);
- if (sm->proto == WPA_PROTO_RSN &&
+ if ((sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) &&
(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
if (wpa_supplicant_decrypt_key_data(sm, key, ver))
goto out;
@@ -1865,7 +1870,8 @@ static u32 wpa_key_mgmt_suite(struct wpa_sm *sm)
{
switch (sm->key_mgmt) {
case WPA_KEY_MGMT_IEEE8021X:
- return (sm->proto == WPA_PROTO_RSN ?
+ return ((sm->proto == WPA_PROTO_RSN ||
+ sm->proto == WPA_PROTO_OSEN) ?
RSN_AUTH_KEY_MGMT_UNSPEC_802_1X :
WPA_AUTH_KEY_MGMT_UNSPEC_802_1X);
case WPA_KEY_MGMT_PSK: