diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index e648486fd..b5bf368dd 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -4216,6 +4216,18 @@ static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss) /* GAS Comeback Response */ if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0d", 2) < 0) ret = -1; + /* Protected GAS Initial Request */ + if (nl80211_register_action_frame(bss, (u8 *) "\x09\x0a", 2) < 0) + ret = -1; + /* Protected GAS Initial Response */ + if (nl80211_register_action_frame(bss, (u8 *) "\x09\x0b", 2) < 0) + ret = -1; + /* Protected GAS Comeback Request */ + if (nl80211_register_action_frame(bss, (u8 *) "\x09\x0c", 2) < 0) + ret = -1; + /* Protected GAS Comeback Response */ + if (nl80211_register_action_frame(bss, (u8 *) "\x09\x0d", 2) < 0) + ret = -1; #endif /* CONFIG_P2P || CONFIG_INTERWORKING */ #ifdef CONFIG_P2P /* P2P Public Action */ diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 862ebb000..d9449fdb7 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -2735,8 +2735,10 @@ static void wpas_event_rx_mgmt_action(struct wpa_supplicant *wpa_s, #endif /* CONFIG_WNM */ #ifdef CONFIG_GAS - if (mgmt->u.action.category == WLAN_ACTION_PUBLIC && + if ((mgmt->u.action.category == WLAN_ACTION_PUBLIC || + mgmt->u.action.category == WLAN_ACTION_PROTECTED_DUAL) && gas_query_rx(wpa_s->gas, mgmt->da, mgmt->sa, mgmt->bssid, + mgmt->u.action.category, payload, plen, freq) == 0) return; #endif /* CONFIG_GAS */ diff --git a/wpa_supplicant/gas_query.c b/wpa_supplicant/gas_query.c index f002fd509..abcb391a1 100644 --- a/wpa_supplicant/gas_query.c +++ b/wpa_supplicant/gas_query.c @@ -1,7 +1,7 @@ /* * Generic advertisement service (GAS) query * Copyright (c) 2009, Atheros Communications - * Copyright (c) 2011-2013, Qualcomm Atheros, Inc. + * Copyright (c) 2011-2014, Qualcomm Atheros, Inc. * Copyright (c) 2011-2014, Jouni Malinen * * This software may be distributed under the terms of the BSD license. @@ -15,6 +15,7 @@ #include "common/ieee802_11_defs.h" #include "common/gas.h" #include "common/wpa_ctrl.h" +#include "rsn_supp/wpa.h" #include "wpa_supplicant_i.h" #include "driver_i.h" #include "offchannel.h" @@ -228,13 +229,28 @@ static void gas_query_tx_status(struct wpa_supplicant *wpa_s, } +static int pmf_in_use(struct wpa_supplicant *wpa_s, const u8 *addr) +{ + if (wpa_s->current_ssid == NULL || + wpa_s->wpa_state < WPA_4WAY_HANDSHAKE || + os_memcmp(addr, wpa_s->bssid, ETH_ALEN) != 0) + return 0; + return wpa_sm_pmf_enabled(wpa_s->wpa); +} + + static int gas_query_tx(struct gas_query *gas, struct gas_query_pending *query, struct wpabuf *req) { - int res; + int res, prot = pmf_in_use(gas->wpa_s, query->addr); + wpa_printf(MSG_DEBUG, "GAS: Send action frame to " MACSTR " len=%u " - "freq=%d", MAC2STR(query->addr), - (unsigned int) wpabuf_len(req), query->freq); + "freq=%d prot=%d", MAC2STR(query->addr), + (unsigned int) wpabuf_len(req), query->freq, prot); + if (prot) { + u8 *categ = wpabuf_mhead_u8(req); + *categ = WLAN_ACTION_PROTECTED_DUAL; + } res = offchannel_send_action(gas->wpa_s, query->freq, query->addr, gas->wpa_s->own_addr, query->addr, wpabuf_head(req), wpabuf_len(req), 1000, @@ -386,27 +402,41 @@ static void gas_query_rx_comeback(struct gas_query *gas, /** - * gas_query_rx - Indicate reception of a Public Action frame + * gas_query_rx - Indicate reception of a Public Action or Protected Dual frame * @gas: GAS query data from gas_query_init() * @da: Destination MAC address of the Action frame * @sa: Source MAC address of the Action frame * @bssid: BSSID of the Action frame + * @categ: Category of the Action frame * @data: Payload of the Action frame * @len: Length of @data * @freq: Frequency (in MHz) on which the frame was received * Returns: 0 if the Public Action frame was a GAS frame or -1 if not */ int gas_query_rx(struct gas_query *gas, const u8 *da, const u8 *sa, - const u8 *bssid, const u8 *data, size_t len, int freq) + const u8 *bssid, u8 categ, const u8 *data, size_t len, + int freq) { struct gas_query_pending *query; u8 action, dialog_token, frag_id = 0, more_frags = 0; u16 comeback_delay, resp_len; const u8 *pos, *adv_proto; + int prot, pmf; if (gas == NULL || len < 4) return -1; + prot = categ == WLAN_ACTION_PROTECTED_DUAL; + pmf = pmf_in_use(gas->wpa_s, bssid); + if (prot && !pmf) { + wpa_printf(MSG_DEBUG, "GAS: Drop unexpected protected GAS frame when PMF is disabled"); + return 0; + } + if (!prot && pmf) { + wpa_printf(MSG_DEBUG, "GAS: Drop unexpected unprotected GAS frame when PMF is enabled"); + return 0; + } + pos = data; action = *pos++; dialog_token = *pos++; diff --git a/wpa_supplicant/gas_query.h b/wpa_supplicant/gas_query.h index 5c3d161ad..ad1349088 100644 --- a/wpa_supplicant/gas_query.h +++ b/wpa_supplicant/gas_query.h @@ -17,7 +17,8 @@ struct gas_query; struct gas_query * gas_query_init(struct wpa_supplicant *wpa_s); void gas_query_deinit(struct gas_query *gas); int gas_query_rx(struct gas_query *gas, const u8 *da, const u8 *sa, - const u8 *bssid, const u8 *data, size_t len, int freq); + const u8 *bssid, u8 categ, const u8 *data, size_t len, + int freq); /** * enum gas_query_result - GAS query result