Add support for Time Advertisement
authorJouni Malinen <jouni@qca.qualcomm.com>
Mon, 17 Oct 2011 21:24:16 +0000 (00:24 +0300)
committerJouni Malinen <j@w1.fi>
Mon, 17 Oct 2011 21:24:16 +0000 (00:24 +0300)
This adds preliminary support for IEEE 802.11v Time Advertisement
mechanism with UTC TSF offset.

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/hostapd.c
src/ap/hostapd.h
src/ap/ieee802_11.h
src/ap/ieee802_11_shared.c
src/common/ieee802_11_defs.h

index b84545d..1bfd456 100644 (file)
@@ -2092,6 +2092,20 @@ struct hostapd_config * hostapd_config_read(const char *fname)
                        extern int rsn_testing;
                        rsn_testing = atoi(pos);
 #endif /* CONFIG_RSN_TESTING */
+               } else if (os_strcmp(buf, "time_advertisement") == 0) {
+                       bss->time_advertisement = atoi(pos);
+               } else if (os_strcmp(buf, "time_zone") == 0) {
+                       size_t tz_len = os_strlen(pos);
+                       if (tz_len < 4 || tz_len > 255) {
+                               wpa_printf(MSG_DEBUG, "Line %d: invalid "
+                                          "time_zone", line);
+                               errors++;
+                               continue;
+                       }
+                       os_free(bss->time_zone);
+                       bss->time_zone = os_strdup(pos);
+                       if (bss->time_zone == NULL)
+                               errors++;
 #ifdef CONFIG_INTERWORKING
                } else if (os_strcmp(buf, "interworking") == 0) {
                        bss->interworking = atoi(pos);
index d5ab422..a2e50bf 100644 (file)
@@ -1023,6 +1023,17 @@ own_ip_addr=127.0.0.1
 # Prohibit use of TDLS Channel Switching in this BSS
 #tdls_prohibit_chan_switch=1
 
+##### IEEE 802.11v-2011 #######################################################
+
+# Time advertisement
+# 0 = disabled (default)
+# 2 = UTC time at which the TSF timer is 0
+#time_advertisement=2
+
+# Local time zone as specified in 8.3 of IEEE Std 1003.1-2004:
+# stdoffset[dst[offset][,start[/time],end[/time]]]
+#time_zone=EST5
+
 ##### IEEE 802.11u-2011 #######################################################
 
 # Enable Interworking service
index 0e6f476..cfb6b2d 100644 (file)
@@ -426,6 +426,8 @@ static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
                ssid->dyn_vlan_keys = NULL;
        }
 
+       os_free(conf->time_zone);
+
 #ifdef CONFIG_IEEE80211R
        {
                struct ft_remote_r0kh *r0kh, *r0kh_prev;
index ce63a10..7748fd7 100644 (file)
@@ -342,6 +342,10 @@ struct hostapd_bss_config {
        int tdls;
        int disable_11n;
 
+       /* IEEE 802.11v */
+       int time_advertisement;
+       char *time_zone;
+
        /* IEEE 802.11u - Interworking */
        int interworking;
        int access_network_type;
index b585650..31a8ee6 100644 (file)
@@ -52,6 +52,20 @@ int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
        *beacon_ret = *proberesp_ret = *assocresp_ret = NULL;
 
        pos = buf;
+       pos = hostapd_eid_time_adv(hapd, pos);
+       if (pos != buf) {
+               if (wpabuf_resize(&beacon, pos - buf) != 0)
+                       goto fail;
+               wpabuf_put_data(beacon, buf, pos - buf);
+       }
+       pos = hostapd_eid_time_zone(hapd, pos);
+       if (pos != buf) {
+               if (wpabuf_resize(&proberesp, pos - buf) != 0)
+                       goto fail;
+               wpabuf_put_data(proberesp, buf, pos - buf);
+       }
+
+       pos = buf;
        pos = hostapd_eid_ext_capab(hapd, pos);
        if (pos != buf) {
                if (wpabuf_resize(&assocresp, pos - buf) != 0)
index 696d5e4..831506c 100644 (file)
@@ -357,6 +357,9 @@ void handle_probe_req(struct hostapd_data *hapd,
 
        pos = hostapd_eid_ext_capab(hapd, pos);
 
+       pos = hostapd_eid_time_adv(hapd, pos);
+       pos = hostapd_eid_time_zone(hapd, pos);
+
        pos = hostapd_eid_interworking(hapd, pos);
        pos = hostapd_eid_adv_proto(hapd, pos);
        pos = hostapd_eid_roaming_consortium(hapd, pos);
@@ -494,6 +497,12 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd)
 
        tailpos = hostapd_eid_ext_capab(hapd, tailpos);
 
+       /*
+        * TODO: Time Advertisement element should only be included in some
+        * DTIM Beacon frames.
+        */
+       tailpos = hostapd_eid_time_adv(hapd, tailpos);
+
        tailpos = hostapd_eid_interworking(hapd, tailpos);
        tailpos = hostapd_eid_adv_proto(hapd, tailpos);
        tailpos = hostapd_eid_roaming_consortium(hapd, tailpos);
index 4dad78a..23c8b1a 100644 (file)
@@ -261,6 +261,8 @@ static void hostapd_cleanup(struct hostapd_data *hapd)
        wpabuf_free(hapd->p2p_probe_resp_ie);
        hapd->p2p_probe_resp_ie = NULL;
 #endif /* CONFIG_P2P */
+
+       wpabuf_free(hapd->time_adv);
 }
 
 
index 803776c..5401e80 100644 (file)
@@ -108,6 +108,10 @@ struct hostapd_data {
 
        int parameter_set_count;
 
+       /* Time Advertisement */
+       u8 time_update_counter;
+       struct wpabuf *time_adv;
+
 #ifdef CONFIG_FULL_DYNAMIC_VLAN
        struct full_dynamic_vlan *full_dynamic_vlan;
 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
index 1c2c367..6706400 100644 (file)
@@ -72,5 +72,8 @@ void ieee802_11_sa_query_action(struct hostapd_data *hapd,
 u8 * hostapd_eid_interworking(struct hostapd_data *hapd, u8 *eid);
 u8 * hostapd_eid_adv_proto(struct hostapd_data *hapd, u8 *eid);
 u8 * hostapd_eid_roaming_consortium(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_time_adv(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_time_zone(struct hostapd_data *hapd, u8 *eid);
+int hostapd_update_time_adv(struct hostapd_data *hapd);
 
 #endif /* IEEE802_11_H */
index 6b17bc6..12a2a70 100644 (file)
@@ -20,6 +20,7 @@
 #include "sta_info.h"
 #include "ap_config.h"
 #include "ap_drv_ops.h"
+#include "ieee802_11.h"
 
 
 #ifdef CONFIG_IEEE80211W
@@ -188,6 +189,8 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
        *pos++ = 0x00;
 
        *pos = 0x00;
+       if (hapd->conf->time_advertisement == 2)
+               *pos |= 0x08; /* Bit 27 - UTC TSF Offset */
        if (hapd->conf->interworking)
                *pos |= 0x80; /* Bit 31 - Interworking */
        pos++;
@@ -309,3 +312,91 @@ u8 * hostapd_eid_roaming_consortium(struct hostapd_data *hapd, u8 *eid)
 
        return pos;
 }
+
+
+u8 * hostapd_eid_time_adv(struct hostapd_data *hapd, u8 *eid)
+{
+       if (hapd->conf->time_advertisement != 2)
+               return eid;
+
+       if (hapd->time_adv == NULL &&
+           hostapd_update_time_adv(hapd) < 0)
+               return eid;
+
+       os_memcpy(eid, wpabuf_head(hapd->time_adv),
+                 wpabuf_len(hapd->time_adv));
+       eid += wpabuf_len(hapd->time_adv);
+
+       return eid;
+}
+
+
+u8 * hostapd_eid_time_zone(struct hostapd_data *hapd, u8 *eid)
+{
+       size_t len;
+
+       if (hapd->conf->time_advertisement != 2)
+               return eid;
+
+       len = os_strlen(hapd->conf->time_zone);
+
+       *eid++ = WLAN_EID_TIME_ZONE;
+       *eid++ = len;
+       os_memcpy(eid, hapd->conf->time_zone, len);
+       eid += len;
+
+       return eid;
+}
+
+
+int hostapd_update_time_adv(struct hostapd_data *hapd)
+{
+       const int elen = 2 + 1 + 10 + 5 + 1;
+       struct os_time t;
+       struct os_tm tm;
+       u8 *pos;
+
+       if (hapd->conf->time_advertisement != 2)
+               return 0;
+
+       if (os_get_time(&t) < 0 || os_gmtime(t.sec, &tm) < 0)
+               return -1;
+
+       if (!hapd->time_adv) {
+               hapd->time_adv = wpabuf_alloc(elen);
+               if (hapd->time_adv == NULL)
+                       return -1;
+               pos = wpabuf_put(hapd->time_adv, elen);
+       } else
+               pos = wpabuf_mhead_u8(hapd->time_adv);
+
+       *pos++ = WLAN_EID_TIME_ADVERTISEMENT;
+       *pos++ = 1 + 10 + 5 + 1;
+
+       *pos++ = 2; /* UTC time at which the TSF timer is 0 */
+
+       /* Time Value at TSF 0 */
+       /* FIX: need to calculate this based on the current TSF value */
+       WPA_PUT_LE16(pos, tm.year); /* Year */
+       pos += 2;
+       *pos++ = tm.month; /* Month */
+       *pos++ = tm.day; /* Day of month */
+       *pos++ = tm.hour; /* Hours */
+       *pos++ = tm.min; /* Minutes */
+       *pos++ = tm.sec; /* Seconds */
+       WPA_PUT_LE16(pos, 0); /* Milliseconds (not used) */
+       pos += 2;
+       *pos++ = 0; /* Reserved */
+
+       /* Time Error */
+       /* TODO: fill in an estimate on the error */
+       *pos++ = 0;
+       *pos++ = 0;
+       *pos++ = 0;
+       *pos++ = 0;
+       *pos++ = 0;
+
+       *pos++ = hapd->time_update_counter++;
+
+       return 0;
+}
index 5a8ee5f..1286167 100644 (file)
 #define WLAN_EID_RIC_DATA 57
 #define WLAN_EID_HT_OPERATION 61
 #define WLAN_EID_SECONDARY_CHANNEL_OFFSET 62
+#define WLAN_EID_TIME_ADVERTISEMENT 69
 #define WLAN_EID_20_40_BSS_COEXISTENCE 72
 #define WLAN_EID_20_40_BSS_INTOLERANT 73
 #define WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS 74
 #define WLAN_EID_MMIE 76
+#define WLAN_EID_TIME_ZONE 98
 #define WLAN_EID_LINK_ID 101
 #define WLAN_EID_INTERWORKING 107
 #define WLAN_EID_ADV_PROTO 108