diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 155207a4e..32941aedd 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -4849,9 +4849,8 @@ static int gas_response_get(struct wpa_supplicant *wpa_s, char *cmd, char *buf, int used; char *pos; size_t resp_len, start, requested_len; - - if (!wpa_s->last_gas_resp) - return -1; + struct wpabuf *resp; + int ret; used = hwaddr_aton2(cmd, addr); if (used < 0) @@ -4862,11 +4861,18 @@ static int gas_response_get(struct wpa_supplicant *wpa_s, char *cmd, char *buf, pos++; dialog_token = atoi(pos); - if (os_memcmp(addr, wpa_s->last_gas_addr, ETH_ALEN) != 0 || - dialog_token != wpa_s->last_gas_dialog_token) + if (wpa_s->last_gas_resp && + os_memcmp(addr, wpa_s->last_gas_addr, ETH_ALEN) == 0 && + dialog_token == wpa_s->last_gas_dialog_token) + resp = wpa_s->last_gas_resp; + else if (wpa_s->prev_gas_resp && + os_memcmp(addr, wpa_s->prev_gas_addr, ETH_ALEN) == 0 && + dialog_token == wpa_s->prev_gas_dialog_token) + resp = wpa_s->prev_gas_resp; + else return -1; - resp_len = wpabuf_len(wpa_s->last_gas_resp); + resp_len = wpabuf_len(resp); start = 0; requested_len = resp_len; @@ -4887,9 +4893,24 @@ static int gas_response_get(struct wpa_supplicant *wpa_s, char *cmd, char *buf, if (requested_len * 2 + 1 > buflen) return os_snprintf(buf, buflen, "FAIL-Too long response"); - return wpa_snprintf_hex(buf, buflen, - wpabuf_head_u8(wpa_s->last_gas_resp) + start, - requested_len); + ret = wpa_snprintf_hex(buf, buflen, wpabuf_head_u8(resp) + start, + requested_len); + + if (start + requested_len == resp_len) { + /* + * Free memory by dropping the response after it has been + * fetched. + */ + if (resp == wpa_s->prev_gas_resp) { + wpabuf_free(wpa_s->prev_gas_resp); + wpa_s->prev_gas_resp = NULL; + } else { + wpabuf_free(wpa_s->last_gas_resp); + wpa_s->last_gas_resp = NULL; + } + } + + return ret; } #endif /* CONFIG_INTERWORKING */ diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c index 5e7fe5b27..da8971d9b 100644 --- a/wpa_supplicant/interworking.c +++ b/wpa_supplicant/interworking.c @@ -1,6 +1,7 @@ /* * Interworking (IEEE 802.11u) * Copyright (c) 2011-2013, Qualcomm Atheros, Inc. + * Copyright (c) 2011-2014, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -2231,6 +2232,7 @@ static void gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token, const struct wpabuf *resp, u16 status_code) { struct wpa_supplicant *wpa_s = ctx; + struct wpabuf *n; wpa_msg(wpa_s, MSG_INFO, GAS_RESPONSE_INFO "addr=" MACSTR " dialog_token=%d status_code=%d resp_len=%d", @@ -2239,10 +2241,14 @@ static void gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token, if (!resp) return; - wpabuf_free(wpa_s->last_gas_resp); - wpa_s->last_gas_resp = wpabuf_dup(resp); - if (wpa_s->last_gas_resp == NULL) + n = wpabuf_dup(resp); + if (n == NULL) return; + wpabuf_free(wpa_s->prev_gas_resp); + wpa_s->prev_gas_resp = wpa_s->last_gas_resp; + os_memcpy(wpa_s->prev_gas_addr, wpa_s->last_gas_addr, ETH_ALEN); + wpa_s->prev_gas_dialog_token = wpa_s->last_gas_dialog_token; + wpa_s->last_gas_resp = n; os_memcpy(wpa_s->last_gas_addr, addr, ETH_ALEN); wpa_s->last_gas_dialog_token = dialog_token; } diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index b722b1319..187e5d9bc 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -477,6 +477,9 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s) wpa_s->ext_pw = NULL; wpabuf_free(wpa_s->last_gas_resp); + wpa_s->last_gas_resp = NULL; + wpabuf_free(wpa_s->prev_gas_resp); + wpa_s->prev_gas_resp = NULL; os_free(wpa_s->last_scan_res); wpa_s->last_scan_res = NULL; diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 61d155af1..17e1ca04c 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -770,9 +770,9 @@ struct wpa_supplicant { struct ext_password_data *ext_pw; - struct wpabuf *last_gas_resp; - u8 last_gas_addr[ETH_ALEN]; - u8 last_gas_dialog_token; + struct wpabuf *last_gas_resp, *prev_gas_resp; + u8 last_gas_addr[ETH_ALEN], prev_gas_addr[ETH_ALEN]; + u8 last_gas_dialog_token, prev_gas_dialog_token; unsigned int no_keep_alive:1;