From c5a64e2d51d978f8d53bebd8f9c6ee37fd649716 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Thu, 23 Jan 2014 11:18:20 +0200 Subject: [PATCH] GAS client: Use Protected Dual of Public Action frames with PMF When GAS is used with PMF negotiated, Protected Dual of Public Action frames are expected to be used instead of Public Action frames, i.e., the GAS/ANQP frames are expected to be encrypted. Conver Public Action GAS queries to use Dual of Public Action frame if PMF has been negotiated with the AP to which the frame is being sent. Signed-hostap: Jouni Malinen --- src/drivers/driver_nl80211.c | 12 +++++++++++ wpa_supplicant/events.c | 4 +++- wpa_supplicant/gas_query.c | 42 ++++++++++++++++++++++++++++++------ wpa_supplicant/gas_query.h | 3 ++- 4 files changed, 53 insertions(+), 8 deletions(-) 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