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;