aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJouni Malinen <j@w1.fi>2012-05-28 00:35:00 (GMT)
committerJouni Malinen <j@w1.fi>2012-05-28 00:35:00 (GMT)
commitb6668734ab8ac235f129d1cd0aff4c4e1c922b41 (patch)
tree7a5932a36263cda9417dd9efc86bacbbade1c822
parentb80eb89d8e21eb699d847bec226d897d9e92e0b8 (diff)
downloadhostap-b6668734ab8ac235f129d1cd0aff4c4e1c922b41.zip
hostap-b6668734ab8ac235f129d1cd0aff4c4e1c922b41.tar.gz
hostap-b6668734ab8ac235f129d1cd0aff4c4e1c922b41.tar.bz2
WNM: Add advertisement of BSS max idle period
If WNM is enabled for the build (CONFIG_WNM=y), add BSS max idle period information to the (Re)Association Response frame from the AP and parse this information on the station. For SME-in-wpa_supplicant case, add a timer to handle periodic transmission of the keep-alive frame. The actual request for the driver to transmit a frame is not yet implemented. Signed-hostap: Jouni Malinen <j@w1.fi>
-rw-r--r--hostapd/Makefile4
-rw-r--r--hostapd/defconfig4
-rw-r--r--src/ap/ieee802_11.c1
-rw-r--r--src/ap/ieee802_11.h1
-rw-r--r--src/ap/ieee802_11_shared.c30
-rw-r--r--src/common/ieee802_11_common.c11
-rw-r--r--src/common/ieee802_11_common.h3
-rw-r--r--src/common/ieee802_11_defs.h1
-rw-r--r--wpa_supplicant/Makefile4
-rw-r--r--wpa_supplicant/defconfig4
-rw-r--r--wpa_supplicant/events.c78
-rw-r--r--wpa_supplicant/wpa_supplicant.c2
-rw-r--r--wpa_supplicant/wpa_supplicant_i.h2
13 files changed, 143 insertions, 2 deletions
diff --git a/hostapd/Makefile b/hostapd/Makefile
index 9e42d03..2a82920 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -169,6 +169,10 @@ ifdef CONFIG_IEEE80211N
CFLAGS += -DCONFIG_IEEE80211N
endif
+ifdef CONFIG_WNM
+CFLAGS += -DCONFIG_WNM
+endif
+
include ../src/drivers/drivers.mak
OBJS += $(DRV_AP_OBJS)
CFLAGS += $(DRV_AP_CFLAGS)
diff --git a/hostapd/defconfig b/hostapd/defconfig
index 3cf0d13..dea296c 100644
--- a/hostapd/defconfig
+++ b/hostapd/defconfig
@@ -136,6 +136,10 @@ CONFIG_IPV6=y
# IEEE 802.11n (High Throughput) support
#CONFIG_IEEE80211N=y
+# Wireless Network Management (IEEE Std 802.11v-2011)
+# Note: This is experimental and not complete implementation.
+#CONFIG_WNM=y
+
# Remove debugging code that is printing out debug messages to stdout.
# This can be used to reduce the size of the hostapd considerably if debugging
# code is not needed.
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index f305b07..3996c90 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -876,6 +876,7 @@ static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
#endif /* CONFIG_IEEE80211N */
p = hostapd_eid_ext_capab(hapd, p);
+ p = hostapd_eid_bss_max_idle_period(hapd, p);
if (sta->flags & WLAN_STA_WMM)
p = hostapd_eid_wmm(hapd, p);
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index d30e90f..b60350f 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -72,5 +72,6 @@ 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);
void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr);
+u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid);
#endif /* IEEE802_11_H */
diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c
index 0935cd5..b3fdf3d 100644
--- a/src/ap/ieee802_11_shared.c
+++ b/src/ap/ieee802_11_shared.c
@@ -1,6 +1,6 @@
/*
* hostapd / IEEE 802.11 Management
- * Copyright (c) 2002-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -397,3 +397,31 @@ int hostapd_update_time_adv(struct hostapd_data *hapd)
return 0;
}
+
+
+u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid)
+{
+ u8 *pos = eid;
+
+#ifdef CONFIG_WNM
+ if (hapd->conf->ap_max_inactivity > 0) {
+ unsigned int val;
+ *pos++ = WLAN_EID_BSS_MAX_IDLE_PERIOD;
+ *pos++ = 3;
+ val = hapd->conf->ap_max_inactivity;
+ if (val > 68000)
+ val = 68000;
+ val *= 1000;
+ val /= 1024;
+ if (val == 0)
+ val = 1;
+ if (val > 65535)
+ val = 65535;
+ WPA_PUT_LE16(pos, val);
+ pos += 2;
+ *pos++ = 0x00; /* TODO: Protected Keep-Alive Required */
+ }
+#endif /* CONFIG_WNM */
+
+ return pos;
+}
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index 5b2f2d5..d65675c 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -1,6 +1,6 @@
/*
* IEEE 802.11 Common routines
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -262,6 +262,15 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
elems->interworking = pos;
elems->interworking_len = elen;
break;
+ case WLAN_EID_EXT_CAPAB:
+ elems->ext_capab = pos;
+ elems->ext_capab_len = elen;
+ break;
+ case WLAN_EID_BSS_MAX_IDLE_PERIOD:
+ if (elen < 3)
+ break;
+ elems->bss_max_idle_period = pos;
+ break;
default:
unknown++;
if (!show_errors)
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index 60f13a6..d9b2b6c 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -38,6 +38,8 @@ struct ieee802_11_elems {
const u8 *link_id;
const u8 *interworking;
const u8 *hs20;
+ const u8 *ext_capab;
+ const u8 *bss_max_idle_period;
u8 ssid_len;
u8 supp_rates_len;
@@ -65,6 +67,7 @@ struct ieee802_11_elems {
u8 p2p_len;
u8 interworking_len;
u8 hs20_len;
+ u8 ext_capab_len;
};
typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes;
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index 27b9e61..0206294 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -228,6 +228,7 @@
#define WLAN_EID_20_40_BSS_INTOLERANT 73
#define WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS 74
#define WLAN_EID_MMIE 76
+#define WLAN_EID_BSS_MAX_IDLE_PERIOD 90
#define WLAN_EID_TFS_REQ 91
#define WLAN_EID_TFS_RESP 92
#define WLAN_EID_WNMSLEEP 93
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 1d66aa7..ab2dc85 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -722,6 +722,10 @@ ifdef CONFIG_IEEE80211N
CFLAGS += -DCONFIG_IEEE80211N
endif
+ifdef CONFIG_WNM
+CFLAGS += -DCONFIG_WNM
+endif
+
ifdef NEED_AP_MLME
OBJS += ../src/ap/wmm.o
OBJS += ../src/ap/ap_list.o
diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig
index 2d6bc81..de5e741 100644
--- a/wpa_supplicant/defconfig
+++ b/wpa_supplicant/defconfig
@@ -476,6 +476,10 @@ CONFIG_PEERKEY=y
# IEEE 802.11n (High Throughput) support (mainly for AP mode)
#CONFIG_IEEE80211N=y
+# Wireless Network Management (IEEE Std 802.11v-2011)
+# Note: This is experimental and not complete implementation.
+#CONFIG_WNM=y
+
# Interworking (IEEE 802.11u)
# This can be used to enable functionality to improve interworking with
# external networks (GAS/ANQP to learn more about the networks and network
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 407407a..3e2fe18 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -103,6 +103,8 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s)
{
int bssid_changed;
+ wnm_bss_keep_alive_deinit(wpa_s);
+
#ifdef CONFIG_IBSS_RSN
ibss_rsn_deinit(wpa_s->ibss_rsn);
wpa_s->ibss_rsn = NULL;
@@ -1200,6 +1202,78 @@ static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_NO_SCAN_PROCESSING */
+#ifdef CONFIG_WNM
+
+static void wnm_bss_keep_alive(void *eloop_ctx, void *sock_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+
+ if (wpa_s->wpa_state < WPA_ASSOCIATED)
+ return;
+
+ wpa_printf(MSG_DEBUG, "WNM: Send keep-alive");
+ /* TODO: could skip this if normal data traffic has been sent */
+ /* TODO: send keep alive frame - better use some short unicast data
+ * frame that gets protected if PTK is set */
+
+ if (wpa_s->sme.bss_max_idle_period) {
+ unsigned int msec;
+ msec = wpa_s->sme.bss_max_idle_period * 1024; /* times 1000 */
+ if (msec > 100)
+ msec -= 100;
+ eloop_register_timeout(msec / 1000, msec % 1000 * 1000,
+ wnm_bss_keep_alive, wpa_s, NULL);
+ }
+}
+
+
+static void wnm_process_assoc_resp(struct wpa_supplicant *wpa_s,
+ const u8 *ies, size_t ies_len)
+{
+ struct ieee802_11_elems elems;
+
+ if (ies == NULL)
+ return;
+
+ if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed)
+ return;
+
+#ifdef CONFIG_SME
+ if (elems.bss_max_idle_period) {
+ unsigned int msec;
+ wpa_s->sme.bss_max_idle_period =
+ WPA_GET_LE16(elems.bss_max_idle_period);
+ wpa_printf(MSG_DEBUG, "WNM: BSS Max Idle Period: %u (* 1000 "
+ "TU)%s", wpa_s->sme.bss_max_idle_period,
+ (elems.bss_max_idle_period[2] & 0x01) ?
+ " (protected keep-live required)" : "");
+ if (wpa_s->sme.bss_max_idle_period == 0)
+ wpa_s->sme.bss_max_idle_period = 1;
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) {
+ eloop_cancel_timeout(wnm_bss_keep_alive, wpa_s, NULL);
+ /* msec times 1000 */
+ msec = wpa_s->sme.bss_max_idle_period * 1024;
+ if (msec > 100)
+ msec -= 100;
+ eloop_register_timeout(msec / 1000, msec % 1000 * 1000,
+ wnm_bss_keep_alive, wpa_s,
+ NULL);
+ }
+ }
+#endif /* CONFIG_SME */
+}
+
+#endif /* CONFIG_WNM */
+
+
+void wnm_bss_keep_alive_deinit(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_WNM
+ eloop_cancel_timeout(wnm_bss_keep_alive, wpa_s, NULL);
+#endif /* CONFIG_WNM */
+}
+
+
static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
union wpa_event_data *data)
{
@@ -1217,6 +1291,10 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
wpa_tdls_assoc_resp_ies(wpa_s->wpa, data->assoc_info.resp_ies,
data->assoc_info.resp_ies_len);
#endif /* CONFIG_TDLS */
+#ifdef CONFIG_WNM
+ wnm_process_assoc_resp(wpa_s, data->assoc_info.resp_ies,
+ data->assoc_info.resp_ies_len);
+#endif /* CONFIG_WNM */
}
if (data->assoc_info.beacon_ies)
wpa_hexdump(MSG_DEBUG, "beacon_ies",
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 09b1640..3cb954d 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -449,6 +449,8 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
os_free(wpa_s->bssid_filter);
wpa_s->bssid_filter = NULL;
+
+ wnm_bss_keep_alive_deinit(wpa_s);
}
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 23ffd7d..dadeafb 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -423,6 +423,7 @@ struct wpa_supplicant {
struct os_time sa_query_start;
u8 sched_obss_scan;
u16 obss_scan_int;
+ u16 bss_max_idle_period;
} sme;
#endif /* CONFIG_SME */
@@ -664,6 +665,7 @@ int wpa_supplicant_connect(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid);
void wpa_supplicant_stop_countermeasures(void *eloop_ctx, void *sock_ctx);
void wpa_supplicant_delayed_mic_error_report(void *eloop_ctx, void *sock_ctx);
+void wnm_bss_keep_alive_deinit(struct wpa_supplicant *wpa_s);
/* eap_register.c */
int eap_register_methods(void);