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 9c2488c..97ba601 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 24e764d..811a42a 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 240b926..a784439 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;