diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h index 8bcd109fe..14a0ddc94 100644 --- a/src/common/ieee802_11_defs.h +++ b/src/common/ieee802_11_defs.h @@ -884,6 +884,8 @@ struct wmm_information_element { } STRUCT_PACKED; +#define WMM_QOSINFO_AP_UAPSD 0x80 + #define WMM_QOSINFO_STA_AC_MASK 0x0f #define WMM_QOSINFO_STA_SP_MASK 0x03 #define WMM_QOSINFO_STA_SP_SHIFT 5 @@ -951,11 +953,12 @@ struct wmm_tspec_element { /* Access Categories / ACI to AC coding */ -enum { +enum wmm_ac { WMM_AC_BE = 0 /* Best Effort */, WMM_AC_BK = 1 /* Background */, WMM_AC_VI = 2 /* Video */, - WMM_AC_VO = 3 /* Voice */ + WMM_AC_VO = 3 /* Voice */, + WMM_AC_NUM = 4 }; diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk index 5e6a88f69..5ab299625 100644 --- a/wpa_supplicant/Android.mk +++ b/wpa_supplicant/Android.mk @@ -83,6 +83,7 @@ OBJS += eap_register.c OBJS += src/utils/common.c OBJS += src/utils/wpa_debug.c OBJS += src/utils/wpabuf.c +OBJS += wmm_ac.c OBJS_p = wpa_passphrase.c OBJS_p += src/utils/common.c OBJS_p += src/utils/wpa_debug.c diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile index 16c2830c3..470a85d1c 100644 --- a/wpa_supplicant/Makefile +++ b/wpa_supplicant/Makefile @@ -80,6 +80,7 @@ OBJS_p += ../src/utils/wpabuf.o OBJS_c = wpa_cli.o ../src/common/wpa_ctrl.o OBJS_c += ../src/utils/wpa_debug.o OBJS_c += ../src/utils/common.o +OBJS += wmm_ac.o ifndef CONFIG_OS ifdef CONFIG_NATIVE_WINDOWS diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index c1684bf45..e078c70cd 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -44,6 +44,7 @@ #include "interworking.h" #include "mesh.h" #include "mesh_mpm.h" +#include "wmm_ac.h" #ifndef CONFIG_NO_SCAN_PROCESSING @@ -2037,6 +2038,12 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, #endif /* CONFIG_IBSS_RSN */ wpas_wps_notify_assoc(wpa_s, bssid); + + if (data) { + wmm_ac_notify_assoc(wpa_s, data->assoc_info.resp_ies, + data->assoc_info.resp_ies_len, + &data->assoc_info.wmm_params); + } } @@ -2124,6 +2131,8 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s, return; } + wmm_ac_notify_disassoc(wpa_s); + if (could_be_psk_mismatch(wpa_s, reason_code, locally_generated)) { wpa_msg(wpa_s, MSG_INFO, "WPA: 4-Way Handshake failed - " "pre-shared key may be incorrect"); diff --git a/wpa_supplicant/wmm_ac.c b/wpa_supplicant/wmm_ac.c new file mode 100644 index 000000000..13bf7a36c --- /dev/null +++ b/wpa_supplicant/wmm_ac.c @@ -0,0 +1,128 @@ +/* + * Wi-Fi Multimedia Admission Control (WMM-AC) + * Copyright(c) 2014, Intel Mobile Communication GmbH. + * Copyright(c) 2014, Intel Corporation. All rights reserved. + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "includes.h" + +#include "utils/common.h" +#include "common/ieee802_11_common.h" +#include "wpa_supplicant_i.h" +#include "driver_i.h" +#include "wmm_ac.h" + + +static struct wmm_ac_assoc_data * +wmm_ac_process_param_elem(struct wpa_supplicant *wpa_s, const u8 *ies, + size_t ies_len) +{ + struct ieee802_11_elems elems; + struct wmm_parameter_element *wmm_params; + struct wmm_ac_assoc_data *assoc_data; + int i; + + /* Parsing WMM Parameter Element */ + if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) != ParseOK) { + wpa_printf(MSG_DEBUG, "WMM AC: could not parse assoc ies"); + return NULL; + } + + if (!elems.wmm) { + wpa_printf(MSG_DEBUG, "WMM AC: No WMM IE"); + return NULL; + } + + if (elems.wmm_len != sizeof(*wmm_params)) { + wpa_printf(MSG_WARNING, "WMM AC: Invalid WMM ie length"); + return NULL; + } + + wmm_params = (struct wmm_parameter_element *)(elems.wmm); + + assoc_data = os_zalloc(sizeof(*assoc_data)); + if (!assoc_data) + return NULL; + + for (i = 0; i < WMM_AC_NUM; i++) + assoc_data->ac_params[i].acm = + !!(wmm_params->ac[i].aci_aifsn & WMM_AC_ACM); + + wpa_printf(MSG_DEBUG, + "WMM AC: AC mandatory: AC_BE=%u AC_BK=%u AC_VI=%u AC_VO=%u", + assoc_data->ac_params[WMM_AC_BE].acm, + assoc_data->ac_params[WMM_AC_BK].acm, + assoc_data->ac_params[WMM_AC_VI].acm, + assoc_data->ac_params[WMM_AC_VO].acm); + + return assoc_data; +} + + +static int wmm_ac_init(struct wpa_supplicant *wpa_s, const u8 *ies, + size_t ies_len, const struct wmm_params *wmm_params) +{ + struct wmm_ac_assoc_data *assoc_data; + u8 ac; + + if (wpa_s->wmm_ac_assoc_info) { + wpa_printf(MSG_ERROR, "WMM AC: Already initialized"); + return -1; + } + + if (!ies) { + wpa_printf(MSG_ERROR, "WMM AC: Missing IEs"); + return -1; + } + + if (!(wmm_params->info_bitmap & WMM_PARAMS_UAPSD_QUEUES_INFO)) { + wpa_printf(MSG_DEBUG, "WMM AC: Missing U-APSD configuration"); + return -1; + } + + assoc_data = wmm_ac_process_param_elem(wpa_s, ies, ies_len); + if (!assoc_data) + return -1; + + wpa_printf(MSG_DEBUG, "WMM AC: U-APSD queues=0x%x", + wmm_params->uapsd_queues); + + for (ac = 0; ac < WMM_AC_NUM; ac++) { + assoc_data->ac_params[ac].uapsd = + !!(wmm_params->uapsd_queues & BIT(ac)); + } + + wpa_s->wmm_ac_assoc_info = assoc_data; + return 0; +} + + +static void wmm_ac_deinit(struct wpa_supplicant *wpa_s) +{ + os_free(wpa_s->wmm_ac_assoc_info); + wpa_s->wmm_ac_assoc_info = NULL; +} + + +void wmm_ac_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *ies, + size_t ies_len, const struct wmm_params *wmm_params) +{ + if (wmm_ac_init(wpa_s, ies, ies_len, wmm_params)) + return; + + wpa_printf(MSG_DEBUG, + "WMM AC: Valid WMM association, WMM AC is enabled"); +} + + +void wmm_ac_notify_disassoc(struct wpa_supplicant *wpa_s) +{ + if (!wpa_s->wmm_ac_assoc_info) + return; + + wmm_ac_deinit(wpa_s); + wpa_printf(MSG_DEBUG, "WMM AC: WMM AC is disabled"); +} diff --git a/wpa_supplicant/wmm_ac.h b/wpa_supplicant/wmm_ac.h new file mode 100644 index 000000000..dd376170a --- /dev/null +++ b/wpa_supplicant/wmm_ac.h @@ -0,0 +1,51 @@ +/* + * Wi-Fi Multimedia Admission Control (WMM-AC) + * Copyright(c) 2014, Intel Mobile Communication GmbH. + * Copyright(c) 2014, Intel Corporation. All rights reserved. + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef WMM_AC_H +#define WMM_AC_H + +#include "common/ieee802_11_defs.h" +#include "drivers/driver.h" + +struct wpa_supplicant; + +/** + * struct wmm_ac_assoc_data - WMM Admission Control Association Data + * + * This struct will store any relevant WMM association data needed by WMM AC. + * In case there is a valid WMM association, an instance of this struct will be + * created. In case there is no instance of this struct, the station is not + * associated to a valid WMM BSS and hence, WMM AC will not be used. + */ +struct wmm_ac_assoc_data { + struct { + /* + * acm - Admission Control Mandatory + * In case an access category is ACM, the traffic will have + * to be admitted by WMM-AC's admission mechanism before use. + */ + unsigned int acm:1; + + /* + * uapsd_queues - Unscheduled Automatic Power Save Delivery + * queues. + * Indicates whether ACs are configured for U-APSD (or legacy + * PS). Storing this value is necessary in order to set the + * Power Save Bit (PSB) in ADDTS request Action frames (if not + * given). + */ + unsigned int uapsd:1; + } ac_params[WMM_AC_NUM]; +}; + +void wmm_ac_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *ies, + size_t ies_len, const struct wmm_params *wmm_params); +void wmm_ac_notify_disassoc(struct wpa_supplicant *wpa_s); + +#endif /* WMM_AC_H */ diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 73e26282f..334bf717f 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -15,6 +15,7 @@ #include "common/wpa_ctrl.h" #include "wps/wps_defs.h" #include "config_ssid.h" +#include "wmm_ac.h" extern const char *wpa_supplicant_version; extern const char *wpa_supplicant_license; @@ -888,6 +889,8 @@ struct wpa_supplicant { struct l2_packet_data *l2_test; unsigned int extra_roc_dur; #endif /* CONFIG_TESTING_OPTIONS */ + + struct wmm_ac_assoc_data *wmm_ac_assoc_info; };