From 56f5af489c3f69decd9cd9ab8459c6afb739d09e Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Wed, 24 Jul 2013 13:17:56 +0300 Subject: [PATCH] Interworking: Add support for QoS Mapping functionality for the STA Indicate support for QoS Mapping and configure driver to update the QoS Map if QoS Map Set elements is received from the AP either in (Re)Association Response or QoS Map Configure frame. This commit adds support for receiving the frames with nl80211 drivers, but the actual QoS Map configuration command is still missing. Signed-hostap: Jouni Malinen --- src/common/ieee802_11_common.c | 6 ++++ src/common/ieee802_11_common.h | 2 ++ src/drivers/driver_nl80211.c | 5 +++ wpa_supplicant/driver_i.h | 9 ++++++ wpa_supplicant/events.c | 54 +++++++++++++++++++++++++++++++++ wpa_supplicant/wpa_supplicant.c | 3 ++ 6 files changed, 79 insertions(+) diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c index aab8ac61c..304dfc691 100644 --- a/src/common/ieee802_11_common.c +++ b/src/common/ieee802_11_common.c @@ -276,6 +276,12 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len, elems->interworking = pos; elems->interworking_len = elen; break; + case WLAN_EID_QOS_MAP_SET: + if (elen < 16) + break; + elems->qos_map_set = pos; + elems->qos_map_set_len = elen; + break; case WLAN_EID_EXT_CAPAB: elems->ext_capab = pos; elems->ext_capab_len = elen; diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h index 68c6b96f1..c4618b2d6 100644 --- a/src/common/ieee802_11_common.h +++ b/src/common/ieee802_11_common.h @@ -40,6 +40,7 @@ struct ieee802_11_elems { const u8 *wfd; const u8 *link_id; const u8 *interworking; + const u8 *qos_map_set; const u8 *hs20; const u8 *ext_capab; const u8 *bss_max_idle_period; @@ -73,6 +74,7 @@ struct ieee802_11_elems { u8 p2p_len; u8 wfd_len; u8 interworking_len; + u8 qos_map_set_len; u8 hs20_len; u8 ext_capab_len; u8 ssid_list_len; diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 8688ea1fa..80673faf7 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -3805,6 +3805,11 @@ static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss) wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with non-AP " "handle %p", bss->nl_mgmt); +#ifdef CONFIG_INTERWORKING + /* QoS Map Configure */ + if (nl80211_register_action_frame(bss, (u8 *) "\x01\x04", 2) < 0) + return -1; +#endif /* CONFIG_INTERWORKING */ #if defined(CONFIG_P2P) || defined(CONFIG_INTERWORKING) /* GAS Initial Request */ if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0a", 2) < 0) diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h index 461b47288..c39168012 100644 --- a/wpa_supplicant/driver_i.h +++ b/wpa_supplicant/driver_i.h @@ -708,4 +708,13 @@ static inline int wpa_drv_status(struct wpa_supplicant *wpa_s, return wpa_s->driver->status(wpa_s->drv_priv, buf, buflen); } +static inline int wpa_drv_set_qos_map(struct wpa_supplicant *wpa_s, + const u8 *qos_map_set, u8 qos_map_set_len) +{ + if (!wpa_s->driver->set_qos_map) + return -1; + return wpa_s->driver->set_qos_map(wpa_s->drv_priv, qos_map_set, + qos_map_set_len); +} + #endif /* DRIVER_I_H */ diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 8284b4fea..9c77ade07 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -1503,6 +1503,43 @@ void wnm_bss_keep_alive_deinit(struct wpa_supplicant *wpa_s) } +#ifdef CONFIG_INTERWORKING + +static int wpas_qos_map_set(struct wpa_supplicant *wpa_s, const u8 *qos_map, + size_t len) +{ + int res; + + wpa_hexdump(MSG_DEBUG, "Interworking: QoS Map Set", qos_map, len); + res = wpa_drv_set_qos_map(wpa_s, qos_map, len); + if (res) { + wpa_printf(MSG_DEBUG, "Interworking: Failed to configure QoS Map Set to the driver"); + } + + return res; +} + + +static void interworking_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; + + if (elems.qos_map_set) { + wpas_qos_map_set(wpa_s, elems.qos_map_set, + elems.qos_map_set_len); + } +} + +#endif /* CONFIG_INTERWORKING */ + + static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s, union wpa_event_data *data) { @@ -1527,6 +1564,10 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s, wnm_process_assoc_resp(wpa_s, data->assoc_info.resp_ies, data->assoc_info.resp_ies_len); #endif /* CONFIG_WNM */ +#ifdef CONFIG_INTERWORKING + interworking_process_assoc_resp(wpa_s, data->assoc_info.resp_ies, + data->assoc_info.resp_ies_len); +#endif /* CONFIG_INTERWORKING */ } if (data->assoc_info.beacon_ies) wpa_hexdump(MSG_DEBUG, "beacon_ies", @@ -2906,6 +2947,19 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, break; } #endif /* CONFIG_TDLS */ +#ifdef CONFIG_INTERWORKING + if (data->rx_action.category == WLAN_ACTION_QOS && + data->rx_action.len >= 1 && + data->rx_action.data[0] == QOS_QOS_MAP_CONFIG) { + wpa_dbg(wpa_s, MSG_DEBUG, "Interworking: Received QoS Map Configure frame from " + MACSTR, MAC2STR(data->rx_action.sa)); + if (os_memcmp(data->rx_action.sa, wpa_s->bssid, ETH_ALEN) + == 0) + wpas_qos_map_set(wpa_s, data->rx_action.data + 1, + data->rx_action.len - 1); + break; + } +#endif /* CONFIG_INTERWORKING */ #ifdef CONFIG_P2P wpas_p2p_rx_action(wpa_s, data->rx_action.da, data->rx_action.sa, diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 99e48eb6b..06ba2c7a8 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -1219,6 +1219,9 @@ static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx) #endif /* CONFIG_INTERWORKING */ break; case 4: /* Bits 32-39 */ +#ifdef CONFIG_INTERWORKING + *pos |= 0x01; /* Bit 32 - QoS Map */ +#endif /* CONFIG_INTERWORKING */ break; case 5: /* Bits 40-47 */ break;