HS 2.0R2 AP: Add support for Session Info URL RADIUS AVP
authorJouni Malinen <jouni@qca.qualcomm.com>
Thu, 1 Aug 2013 21:39:30 +0000 (00:39 +0300)
committerJouni Malinen <j@w1.fi>
Tue, 25 Feb 2014 23:24:24 +0000 (01:24 +0200)
If the authentication server includes the WFA HS 2.0 Session Info URL
AVP in Access-Accept, schedule ESS Disassociation Imminent frame to be
transmitted specified warning time prior to session timeout.

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

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

index 3c7b1ed..1971908 100644 (file)
@@ -1286,12 +1286,55 @@ static void ieee802_1x_hs20_deauth_req(struct hostapd_data *hapd,
        ap_sta_session_timeout(hapd, sta, hapd->conf->hs20_deauth_req_timeout);
 }
 
+
+static void ieee802_1x_hs20_session_info(struct hostapd_data *hapd,
+                                        struct sta_info *sta, u8 *pos,
+                                        size_t len, int session_timeout)
+{
+       unsigned int swt;
+       int warning_time, beacon_int;
+
+       if (len < 1)
+               return; /* Malformed information */
+       os_free(sta->hs20_session_info_url);
+       sta->hs20_session_info_url = os_malloc(len);
+       if (sta->hs20_session_info_url == NULL)
+               return;
+       swt = pos[0];
+       os_memcpy(sta->hs20_session_info_url, pos + 1, len - 1);
+       sta->hs20_session_info_url[len - 1] = '\0';
+       wpa_printf(MSG_DEBUG, "HS 2.0: Session Information URL='%s' SWT=%u "
+                  "(session_timeout=%d)",
+                  sta->hs20_session_info_url, swt, session_timeout);
+       if (session_timeout < 0) {
+               wpa_printf(MSG_DEBUG, "HS 2.0: No Session-Timeout set - ignore session info URL");
+               return;
+       }
+       if (swt == 255)
+               swt = 1; /* Use one minute as the AP selected value */
+
+       if ((unsigned int) session_timeout < swt * 60)
+               warning_time = 0;
+       else
+               warning_time = session_timeout - swt * 60;
+
+       beacon_int = hapd->iconf->beacon_int;
+       if (beacon_int < 1)
+               beacon_int = 100; /* best guess */
+       sta->hs20_disassoc_timer = swt * 60 * 1000 / beacon_int * 125 / 128;
+       if (sta->hs20_disassoc_timer > 65535)
+               sta->hs20_disassoc_timer = 65535;
+
+       ap_sta_session_warning_timeout(hapd, sta, warning_time);
+}
+
 #endif /* CONFIG_HS20 */
 
 
 static void ieee802_1x_check_hs20(struct hostapd_data *hapd,
                                  struct sta_info *sta,
-                                 struct radius_msg *msg)
+                                 struct radius_msg *msg,
+                                 int session_timeout)
 {
 #ifdef CONFIG_HS20
        u8 *buf, *pos, *end, type, sublen;
@@ -1328,6 +1371,10 @@ static void ieee802_1x_check_hs20(struct hostapd_data *hapd,
                case RADIUS_VENDOR_ATTR_WFA_HS20_DEAUTH_REQ:
                        ieee802_1x_hs20_deauth_req(hapd, sta, pos, sublen);
                        break;
+               case RADIUS_VENDOR_ATTR_WFA_HS20_SESSION_INFO_URL:
+                       ieee802_1x_hs20_session_info(hapd, sta, pos, sublen,
+                                                    session_timeout);
+                       break;
                }
        }
 #endif /* CONFIG_HS20 */
@@ -1492,7 +1539,9 @@ 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);
-               ieee802_1x_check_hs20(hapd, sta, msg);
+               ieee802_1x_check_hs20(hapd, sta, msg,
+                                     session_timeout_set ?
+                                     (int) session_timeout : -1);
                if (sm->eap_if->eapKeyAvailable && !sta->remediation &&
                    !sta->hs20_deauth_requested &&
                    wpa_auth_pmksa_add(sta->wpa_sm, sm->eapol_key_crypt,
index ada1106..f7af088 100644 (file)
 #include "p2p_hostapd.h"
 #include "ap_drv_ops.h"
 #include "gas_serv.h"
+#include "wnm_ap.h"
 #include "sta_info.h"
 
 static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
                                       struct sta_info *sta);
 static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx);
+static void ap_handle_session_warning_timer(void *eloop_ctx, void *timeout_ctx);
 static void ap_sta_deauth_cb_timeout(void *eloop_ctx, void *timeout_ctx);
 static void ap_sta_disassoc_cb_timeout(void *eloop_ctx, void *timeout_ctx);
 #ifdef CONFIG_IEEE80211W
@@ -224,6 +226,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
                   __func__, MAC2STR(sta->addr));
        eloop_cancel_timeout(ap_handle_timer, hapd, sta);
        eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
+       eloop_cancel_timeout(ap_handle_session_warning_timer, hapd, sta);
        eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
        eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta);
 
@@ -267,6 +270,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
        os_free(sta->radius_cui);
        os_free(sta->remediation_url);
        wpabuf_free(sta->hs20_deauth_req);
+       os_free(sta->hs20_session_info_url);
 
 #ifdef CONFIG_SAE
        sae_clear_data(sta->sae);
@@ -522,6 +526,32 @@ void ap_sta_no_session_timeout(struct hostapd_data *hapd, struct sta_info *sta)
 }
 
 
+static void ap_handle_session_warning_timer(void *eloop_ctx, void *timeout_ctx)
+{
+#ifdef CONFIG_WNM
+       struct hostapd_data *hapd = eloop_ctx;
+       struct sta_info *sta = timeout_ctx;
+
+       wpa_printf(MSG_DEBUG, "WNM: Session warning time reached for " MACSTR,
+                  MAC2STR(sta->addr));
+       if (sta->hs20_session_info_url == NULL)
+               return;
+
+       wnm_send_ess_disassoc_imminent(hapd, sta, sta->hs20_session_info_url,
+                                      sta->hs20_disassoc_timer);
+#endif /* CONFIG_WNM */
+}
+
+
+void ap_sta_session_warning_timeout(struct hostapd_data *hapd,
+                                   struct sta_info *sta, int warning_time)
+{
+       eloop_cancel_timeout(ap_handle_session_warning_timer, hapd, sta);
+       eloop_register_timeout(warning_time, 0, ap_handle_session_warning_timer,
+                              hapd, sta);
+}
+
+
 struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr)
 {
        struct sta_info *sta;
index df86cc2..c0bab6f 100644 (file)
@@ -130,6 +130,8 @@ struct sta_info {
        u8 remediation_method;
        char *remediation_url; /* HS 2.0 Subscription Remediation Server URL */
        struct wpabuf *hs20_deauth_req;
+       char *hs20_session_info_url;
+       int hs20_disassoc_timer;
 
        struct os_reltime connected_time;
 
@@ -173,6 +175,8 @@ void ap_sta_session_timeout(struct hostapd_data *hapd, struct sta_info *sta,
                            u32 session_timeout);
 void ap_sta_no_session_timeout(struct hostapd_data *hapd,
                               struct sta_info *sta);
+void ap_sta_session_warning_timeout(struct hostapd_data *hapd,
+                                   struct sta_info *sta, int warning_time);
 struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr);
 void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
                         u16 reason);
index 8cb7a0f..d8bf21e 100644 (file)
@@ -172,6 +172,7 @@ enum {
        RADIUS_VENDOR_ATTR_WFA_HS20_AP_VERSION = 2,
        RADIUS_VENDOR_ATTR_WFA_HS20_STA_VERSION = 3,
        RADIUS_VENDOR_ATTR_WFA_HS20_DEAUTH_REQ = 4,
+       RADIUS_VENDOR_ATTR_WFA_HS20_SESSION_INFO_URL = 5,
 };
 
 #ifdef _MSC_VER