]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
HS 2.0R2 AP: Use Subscr Remediation request from RADIUS server
authorJouni Malinen <jouni@qca.qualcomm.com>
Wed, 21 Nov 2012 22:48:48 +0000 (00:48 +0200)
committerJouni Malinen <j@w1.fi>
Tue, 25 Feb 2014 23:24:24 +0000 (01:24 +0200)
If the RADIUS server includes the WFA RADIUS VSA in Access-Accept to
indicate need for subscription remediation, copy the server URL from
the message and send it to the station after successfully completed
4-way handshake (i.e., after PTK is set to allow PMF to work) in a
WNM-Notification.

AP must not allow PMKSA caching to be used after subscription
remediation association, so do not add the PMKSA cache entry whenever
the authentication server is indicating need for subscription
remediation. This allows station reassociation to use EAP authentication
to move to non-remediation connection.

Signed-hostap: Jouni Malinen <jouni@qca.qualcomm.com>

src/ap/ieee802_1x.c
src/ap/sta_info.c
src/ap/sta_info.h

index 9c2488cdd0261769884901834b759f4db6a8aaf7..97ba601b3932de55f37d409a8da72ed40f626b21 100644 (file)
@@ -30,6 +30,7 @@
 #include "ap_config.h"
 #include "ap_drv_ops.h"
 #include "wps_hostapd.h"
+#include "hs20.h"
 #include "ieee802_1x.h"
 
 
@@ -1238,6 +1239,74 @@ static void ieee802_1x_update_sta_cui(struct hostapd_data *hapd,
 }
 
 
+#ifdef CONFIG_HS20
+
+static void ieee802_1x_hs20_sub_rem(struct sta_info *sta, u8 *pos, size_t len)
+{
+       sta->remediation = 1;
+       os_free(sta->remediation_url);
+       if (len > 2) {
+               sta->remediation_url = os_malloc(len);
+               if (!sta->remediation_url)
+                       return;
+               sta->remediation_method = pos[0];
+               os_memcpy(sta->remediation_url, pos + 1, len - 1);
+               sta->remediation_url[len - 1] = '\0';
+               wpa_printf(MSG_DEBUG, "HS 2.0: Subscription remediation needed "
+                          "for " MACSTR " - server method %u URL %s",
+                          MAC2STR(sta->addr), sta->remediation_method,
+                          sta->remediation_url);
+       } else {
+               sta->remediation_url = NULL;
+               wpa_printf(MSG_DEBUG, "HS 2.0: Subscription remediation needed "
+                          "for " MACSTR, MAC2STR(sta->addr));
+       }
+       /* TODO: assign the STA into remediation VLAN or add filtering */
+}
+
+#endif /* CONFIG_HS20 */
+
+
+static void ieee802_1x_check_hs20(struct hostapd_data *hapd,
+                                 struct sta_info *sta,
+                                 struct radius_msg *msg)
+{
+#ifdef CONFIG_HS20
+       u8 *buf, *pos, *end, type, sublen;
+       size_t len;
+
+       buf = NULL;
+       sta->remediation = 0;
+       for (;;) {
+               if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_VENDOR_SPECIFIC,
+                                           &buf, &len, buf) < 0)
+                       break;
+               if (len < 6)
+                       continue;
+               pos = buf;
+               end = buf + len;
+               if (WPA_GET_BE32(pos) != RADIUS_VENDOR_ID_WFA)
+                       continue;
+               pos += 4;
+
+               type = *pos++;
+               sublen = *pos++;
+               if (sublen < 2)
+                       continue; /* invalid length */
+               sublen -= 2; /* skip header */
+               if (pos + sublen > end)
+                       continue; /* invalid WFA VSA */
+
+               switch (type) {
+               case RADIUS_VENDOR_ATTR_WFA_HS20_SUBSCR_REMEDIATION:
+                       ieee802_1x_hs20_sub_rem(sta, pos, sublen);
+                       break;
+               }
+       }
+#endif /* CONFIG_HS20 */
+}
+
+
 struct sta_id_search {
        u8 identifier;
        struct eapol_state_machine *sm;
@@ -1396,7 +1465,8 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
                ieee802_1x_store_radius_class(hapd, sta, msg);
                ieee802_1x_update_sta_identity(hapd, sta, msg);
                ieee802_1x_update_sta_cui(hapd, sta, msg);
-               if (sm->eap_if->eapKeyAvailable &&
+               ieee802_1x_check_hs20(hapd, sta, msg);
+               if (sm->eap_if->eapKeyAvailable && !sta->remediation &&
                    wpa_auth_pmksa_add(sta->wpa_sm, sm->eapol_key_crypt,
                                       session_timeout_set ?
                                       (int) session_timeout : -1, sm) == 0) {
@@ -2150,8 +2220,24 @@ static void ieee802_1x_finished(struct hostapd_data *hapd,
        /* TODO: get PMKLifetime from WPA parameters */
        static const int dot11RSNAConfigPMKLifetime = 43200;
 
+#ifdef CONFIG_HS20
+       if (success) {
+               if (sta->remediation) {
+                       wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification "
+                                  "to " MACSTR " to indicate Subscription "
+                                  "Remediation",
+                                  MAC2STR(sta->addr));
+                       hs20_send_wnm_notification(hapd, sta->addr,
+                                                  sta->remediation_method,
+                                                  sta->remediation_url);
+                       os_free(sta->remediation_url);
+                       sta->remediation_url = NULL;
+               }
+       }
+#endif /* CONFIG_HS20 */
+
        key = ieee802_1x_get_key(sta->eapol_sm, &len);
-       if (success && key && len >= PMK_LEN &&
+       if (success && key && len >= PMK_LEN && !sta->remediation &&
            wpa_auth_pmksa_add(sta->wpa_sm, key, dot11RSNAConfigPMKLifetime,
                               sta->eapol_sm) == 0) {
                hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
index 24e764d66bcdab91a77d4cdb927241f8b3c858e0..811a42a1723b00fb7c5b4c6e44da1b08a023af9e 100644 (file)
@@ -265,6 +265,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
        hostapd_free_psk_list(sta->psk);
        os_free(sta->identity);
        os_free(sta->radius_cui);
+       os_free(sta->remediation_url);
 
 #ifdef CONFIG_SAE
        sae_clear_data(sta->sae);
index 240b92634a39e036580b0a395ed6821d0c6472ca..a784439cf7106ba3bddb07e2b9e5c887b4f80f76 100644 (file)
@@ -57,6 +57,7 @@ struct sta_info {
        unsigned int ht_20mhz_set:1;
        unsigned int no_p2p_set:1;
        unsigned int qos_map_enabled:1;
+       unsigned int remediation:1;
 
        u16 auth_alg;
        u8 previous_ap[6];
@@ -125,6 +126,8 @@ struct sta_info {
        struct wpabuf *wps_ie; /* WPS IE from (Re)Association Request */
        struct wpabuf *p2p_ie; /* P2P IE from (Re)Association Request */
        struct wpabuf *hs20_ie; /* HS 2.0 IE from (Re)Association Request */
+       u8 remediation_method;
+       char *remediation_url; /* HS 2.0 Subscription Remediation Server URL */
 
        struct os_reltime connected_time;