From 184e110caff3339643a303ab3a2f32642623a0c4 Mon Sep 17 00:00:00 2001
From: Jouni Malinen <jouni@qca.qualcomm.com>
Date: Thu, 20 Dec 2012 21:15:05 +0200
Subject: [PATCH] HS 2.0R2: Add Icon Request and Icon binary File ANQP elements

wpa_supplicant can request OSU icon data with "hs20_icon_request <BSSID>
<icon filename>". This transmits an Icon Request ANQP element and
processes the response in Icon Binary File ANQP elements.

Signed-hostap: Jouni Malinen <jouni@qca.qualcomm.com>
---
 src/common/ieee802_11_defs.h     |  2 ++
 wpa_supplicant/ctrl_iface.c      | 22 +++++++++++++++
 wpa_supplicant/hs20_supplicant.c | 46 ++++++++++++++++++++++++++++++++
 wpa_supplicant/wpa_cli.c         | 21 +++++++++++++++
 4 files changed, 91 insertions(+)

diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index 68804bb08..7f2d77407 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -908,6 +908,8 @@ enum {
 #define HS20_STYPE_CONNECTION_CAPABILITY 5
 #define HS20_STYPE_NAI_HOME_REALM_QUERY 6
 #define HS20_STYPE_OPERATING_CLASS 7
+#define HS20_STYPE_ICON_REQUEST 10
+#define HS20_STYPE_ICON_BINARY_FILE 11
 
 #define HS20_DGAF_DISABLED 0x01
 #define HS20_PPS_MO_ID_PRESENT 0x02
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 0df37108e..ffc76f67f 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -5178,6 +5178,25 @@ static int hs20_get_nai_home_realm_list(struct wpa_supplicant *wpa_s,
 	return ret;
 }
 
+
+static int hs20_icon_request(struct wpa_supplicant *wpa_s, char *cmd)
+{
+	u8 dst_addr[ETH_ALEN];
+	int used;
+	char *icon;
+
+	used = hwaddr_aton2(cmd, dst_addr);
+	if (used < 0)
+		return -1;
+
+	while (cmd[used] == ' ')
+		used++;
+	icon = &cmd[used];
+
+	return hs20_anqp_send_req(wpa_s, dst_addr, BIT(HS20_STYPE_ICON_REQUEST),
+				  (u8 *) icon, os_strlen(icon));
+}
+
 #endif /* CONFIG_HS20 */
 
 
@@ -6103,6 +6122,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
 	} else if (os_strncmp(buf, "HS20_GET_NAI_HOME_REALM_LIST ", 29) == 0) {
 		if (hs20_get_nai_home_realm_list(wpa_s, buf + 29) < 0)
 			reply_len = -1;
+	} else if (os_strncmp(buf, "HS20_ICON_REQUEST ", 18) == 0) {
+		if (hs20_icon_request(wpa_s, buf + 18) < 0)
+			reply_len = -1;
 #endif /* CONFIG_HS20 */
 	} else if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0)
 	{
diff --git a/wpa_supplicant/hs20_supplicant.c b/wpa_supplicant/hs20_supplicant.c
index 456ba61ff..ceafc731e 100644
--- a/wpa_supplicant/hs20_supplicant.c
+++ b/wpa_supplicant/hs20_supplicant.c
@@ -105,6 +105,11 @@ struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload,
 		wpabuf_put_u8(buf, 0); /* Reserved */
 		if (payload)
 			wpabuf_put_data(buf, payload, payload_len);
+	} else if (stypes == BIT(HS20_STYPE_ICON_REQUEST)) {
+		wpabuf_put_u8(buf, HS20_STYPE_ICON_REQUEST);
+		wpabuf_put_u8(buf, 0); /* Reserved */
+		if (payload)
+			wpabuf_put_data(buf, payload, payload_len);
 	} else {
 		u8 i;
 		wpabuf_put_u8(buf, HS20_STYPE_QUERY_LIST);
@@ -167,6 +172,7 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
 	u8 subtype;
 	struct wpa_bss *bss = wpa_bss_get_bssid(wpa_s, sa);
 	struct wpa_bss_anqp *anqp = NULL;
+	u16 data_len;
 
 	if (slen < 2)
 		return;
@@ -232,6 +238,46 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
 				wpabuf_alloc_copy(pos, slen);
 		}
 		break;
+	case HS20_STYPE_ICON_BINARY_FILE:
+		wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
+			" Icon Binary File", MAC2STR(sa));
+
+		if (slen < 4) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: Too short Icon "
+				"Binary File value from " MACSTR, MAC2STR(sa));
+			break;
+		}
+
+		wpa_printf(MSG_DEBUG, "HS 2.0: Download Status Code %u", *pos);
+		pos++;
+		slen--;
+
+		if ((size_t) 1 + pos[0] > slen) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: Too short Icon "
+				"Binary File value from " MACSTR, MAC2STR(sa));
+			break;
+		}
+		wpa_hexdump_ascii(MSG_DEBUG, "Icon Type", pos + 1, pos[0]);
+		slen -= 1 + pos[0];
+		pos += 1 + pos[0];
+
+		if (slen < 2) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: Too short Icon "
+				"Binary File value from " MACSTR, MAC2STR(sa));
+			break;
+		}
+		data_len = WPA_GET_BE16(pos);
+		pos += 2;
+		slen -= 2;
+
+		if (data_len > slen) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: Too short Icon "
+				"Binary File value from " MACSTR, MAC2STR(sa));
+			break;
+		}
+
+		wpa_printf(MSG_DEBUG, "Icon Binary Data: %u bytes", data_len);
+		break;
 	default:
 		wpa_printf(MSG_DEBUG, "HS20: Unsupported subtype %u", subtype);
 		break;
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 1871a2802..fd7f92fa3 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -2298,6 +2298,24 @@ static int wpa_cli_cmd_get_nai_home_realm_list(struct wpa_ctrl *ctrl, int argc,
 	return wpa_ctrl_command(ctrl, cmd);
 }
 
+
+static int wpa_cli_cmd_hs20_icon_request(struct wpa_ctrl *ctrl, int argc,
+					 char *argv[])
+{
+	char cmd[512];
+
+	if (argc < 2) {
+		printf("Command needs two arguments (dst mac addr and "
+		       "icon name)\n");
+		return -1;
+	}
+
+	if (write_cmd(cmd, sizeof(cmd), "HS20_ICON_REQUEST", argc, argv) < 0)
+		return -1;
+
+	return wpa_ctrl_command(ctrl, cmd);
+}
+
 #endif /* CONFIG_HS20 */
 
 
@@ -2831,6 +2849,9 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
 	{ "nai_home_realm_list", wpa_cli_cmd_get_nai_home_realm_list,
 	  wpa_cli_complete_bss, cli_cmd_flag_none,
 	  "<addr> <home realm> = get HS20 nai home realm list" },
+	{ "hs20_icon_request", wpa_cli_cmd_hs20_icon_request,
+	  wpa_cli_complete_bss, cli_cmd_flag_none,
+	  "<addr> <icon name> = get Hotspot 2.0 OSU icon" },
 #endif /* CONFIG_HS20 */
 	{ "sta_autoconnect", wpa_cli_cmd_sta_autoconnect, NULL,
 	  cli_cmd_flag_none,