HS 2.0R2 AP: Add OSEN implementation
authorJouni Malinen <jouni@qca.qualcomm.com>
Tue, 23 Jul 2013 18:25:21 +0000 (21:25 +0300)
committerJouni Malinen <j@w1.fi>
Tue, 25 Feb 2014 23:24:24 +0000 (01:24 +0200)
Signed-hostap: Jouni Malinen <jouni@qca.qualcomm.com>

19 files changed:
hostapd/config_file.c
hostapd/hostapd.conf
src/ap/ap_config.c
src/ap/ap_config.h
src/ap/ap_drv_ops.c
src/ap/beacon.c
src/ap/drv_callbacks.c
src/ap/hostapd.c
src/ap/hs20.c
src/ap/hs20.h
src/ap/ieee802_11.c
src/ap/ieee802_1x.c
src/ap/wpa_auth.c
src/ap/wpa_auth.h
src/ap/wpa_auth_glue.c
src/ap/wpa_auth_ie.c
src/ap/wpa_auth_ie.h
src/drivers/driver.h
src/rsn_supp/wpa.c

index 26f52e9..d38c3f8 100644 (file)
@@ -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) {
index 0630320..332cee0 100644 (file)
@@ -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).
index f5014a5..cb5d3aa 100644 (file)
@@ -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;
index b6e8cbc..73645cd 100644 (file)
@@ -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;
index e998fc6..b8b260a 100644 (file)
@@ -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) {
index 33320bd..e06ce77 100644 (file)
@@ -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;
 }
index 9af9646..6fb1056 100644 (file)
@@ -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:
index 98148da..75baec0 100644 (file)
@@ -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)) {
index 5875b40..d521d2c 100644 (file)
@@ -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)
 {
index 059764e..c7ffa36 100644 (file)
@@ -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);
 
index f3e0df3..3e704e5 100644 (file)
@@ -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
index 97ba601..f07b6bf 100644 (file)
@@ -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
index 707a63f..cc64ff1 100644 (file)
@@ -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;
index bc3dec4..d99db69 100644 (file)
@@ -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,
index 5af1495..da5fea7 100644 (file)
@@ -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 =
index 274f4d6..7a49751 100644 (file)
@@ -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) {
index f945882..d2067ba 100644 (file)
@@ -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,
index 69e837a..d2aad24 100644 (file)
@@ -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;
 };
 
 /**
index 0a6f0d8..ba50263 100644 (file)
@@ -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: