11f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt/*
21f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * Generic advertisement service (GAS) (IEEE 802.11u)
31f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * Copyright (c) 2009, Atheros Communications
461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * Copyright (c) 2011-2012, Qualcomm Atheros
51f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt *
6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * This software may be distributed under the terms of the BSD license.
7c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * See README for more details.
81f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt */
91f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#include "includes.h"
111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#include "common.h"
131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#include "ieee802_11_defs.h"
141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#include "gas.h"
151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic struct wpabuf *
181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtgas_build_req(u8 action, u8 dialog_token, size_t size)
191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpabuf *buf;
211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	buf = wpabuf_alloc(100 + size);
231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (buf == NULL)
241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return NULL;
251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpabuf_put_u8(buf, action);
281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpabuf_put_u8(buf, dialog_token);
291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return buf;
311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
3461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstruct wpabuf * gas_build_initial_req(u8 dialog_token, size_t size)
351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return gas_build_req(WLAN_PA_GAS_INITIAL_REQ, dialog_token,
371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			     size);
381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstruct wpabuf * gas_build_comeback_req(u8 dialog_token)
421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return gas_build_req(WLAN_PA_GAS_COMEBACK_REQ, dialog_token, 0);
441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic struct wpabuf *
481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtgas_build_resp(u8 action, u8 dialog_token, u16 status_code, u8 frag_id,
491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	       u8 more, u16 comeback_delay, size_t size)
501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpabuf *buf;
521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	buf = wpabuf_alloc(100 + size);
541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (buf == NULL)
551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return NULL;
561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpabuf_put_u8(buf, action);
591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpabuf_put_u8(buf, dialog_token);
601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpabuf_put_le16(buf, status_code);
611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (action == WLAN_PA_GAS_COMEBACK_RESP)
621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpabuf_put_u8(buf, frag_id | (more ? 0x80 : 0));
631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpabuf_put_le16(buf, comeback_delay);
641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return buf;
661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstruct wpabuf *
701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtgas_build_initial_resp(u8 dialog_token, u16 status_code, u16 comeback_delay,
711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		       size_t size)
721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return gas_build_resp(WLAN_PA_GAS_INITIAL_RESP, dialog_token,
741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			      status_code, 0, 0, comeback_delay, size);
751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic struct wpabuf *
791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtgas_build_comeback_resp(u8 dialog_token, u16 status_code, u8 frag_id, u8 more,
801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			u16 comeback_delay, size_t size)
811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return gas_build_resp(WLAN_PA_GAS_COMEBACK_RESP, dialog_token,
831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			      status_code, frag_id, more, comeback_delay,
841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			      size);
851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt/**
891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * gas_add_adv_proto_anqp - Add an Advertisement Protocol element
901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * @buf: Buffer to which the element is added
911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * @query_resp_len_limit: Query Response Length Limit in units of 256 octets
921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * @pame_bi: Pre-Association Message Exchange BSSID Independent (0/1)
931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt *
941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt *
951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * @query_resp_len_limit is 0 for request and 1-0x7f for response. 0x7f means
961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * that the maximum limit is determined by the maximum allowable number of
971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * fragments in the GAS Query Response Fragment ID.
981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt */
991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic void gas_add_adv_proto_anqp(struct wpabuf *buf, u8 query_resp_len_limit,
1001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				   u8 pame_bi)
1011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
1021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	/* Advertisement Protocol IE */
1031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
1041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpabuf_put_u8(buf, 2); /* Length */
1051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpabuf_put_u8(buf, (query_resp_len_limit & 0x7f) |
1061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		      (pame_bi ? 0x80 : 0));
1071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	/* Advertisement Protocol */
1081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpabuf_put_u8(buf, ACCESS_NETWORK_QUERY_PROTOCOL);
1091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
1101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstruct wpabuf * gas_anqp_build_initial_req(u8 dialog_token, size_t size)
1131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
1141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpabuf *buf;
1151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	buf = gas_build_initial_req(dialog_token, 4 + size);
1171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (buf == NULL)
1181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return NULL;
1191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	gas_add_adv_proto_anqp(buf, 0, 0);
1211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpabuf_put(buf, 2); /* Query Request Length to be filled */
1231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return buf;
1251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
1261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstruct wpabuf * gas_anqp_build_initial_resp(u8 dialog_token, u16 status_code,
1291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					    u16 comeback_delay, size_t size)
1301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
1311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpabuf *buf;
1321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	buf = gas_build_initial_resp(dialog_token, status_code, comeback_delay,
1341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				     4 + size);
1351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (buf == NULL)
1361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return NULL;
1371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	gas_add_adv_proto_anqp(buf, 0x7f, 0);
1391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpabuf_put(buf, 2); /* Query Response Length to be filled */
1411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return buf;
1431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
1441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstruct wpabuf * gas_anqp_build_initial_resp_buf(u8 dialog_token,
1471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt						u16 status_code,
1481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt						u16 comeback_delay,
1491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt						struct wpabuf *payload)
1501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
1511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpabuf *buf;
1521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	buf = gas_anqp_build_initial_resp(dialog_token, status_code,
1541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					  comeback_delay,
1551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					  payload ? wpabuf_len(payload) : 0);
1561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (buf == NULL)
1571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return NULL;
1581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (payload)
1601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpabuf_put_buf(buf, payload);
1611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	gas_anqp_set_len(buf);
1631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return buf;
1651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
1661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstruct wpabuf * gas_anqp_build_comeback_resp(u8 dialog_token, u16 status_code,
1691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					     u8 frag_id, u8 more,
1701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					     u16 comeback_delay, size_t size)
1711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
1721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpabuf *buf;
1731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	buf = gas_build_comeback_resp(dialog_token, status_code,
1751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				      frag_id, more, comeback_delay, 4 + size);
1761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (buf == NULL)
1771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return NULL;
1781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	gas_add_adv_proto_anqp(buf, 0x7f, 0);
1801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpabuf_put(buf, 2); /* Query Response Length to be filled */
1821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return buf;
1841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
1851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstruct wpabuf * gas_anqp_build_comeback_resp_buf(u8 dialog_token,
1881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt						 u16 status_code,
1891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt						 u8 frag_id, u8 more,
1901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt						 u16 comeback_delay,
1911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt						 struct wpabuf *payload)
1921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
1931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpabuf *buf;
1941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	buf = gas_anqp_build_comeback_resp(dialog_token, status_code, frag_id,
1961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					   more, comeback_delay,
1971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					   payload ? wpabuf_len(payload) : 0);
1981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (buf == NULL)
1991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return NULL;
2001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
2011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (payload)
2021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpabuf_put_buf(buf, payload);
2031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
2041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	gas_anqp_set_len(buf);
2051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
2061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return buf;
2071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
2081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
2091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
2101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt/**
2111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * gas_anqp_set_len - Set Query Request/Response Length
2121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * @buf: GAS message
2131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt *
2141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * This function is used to update the Query Request/Response Length field once
2151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * the payload has been filled.
2161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt */
2171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtvoid gas_anqp_set_len(struct wpabuf *buf)
2181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
2191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	u8 action;
2201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	size_t offset;
2211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	u8 *len;
2221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
2231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (buf == NULL || wpabuf_len(buf) < 2)
2241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return;
2251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
2261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	action = *(wpabuf_head_u8(buf) + 1);
2271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	switch (action) {
2281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	case WLAN_PA_GAS_INITIAL_REQ:
2291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		offset = 3 + 4;
2301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		break;
2311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	case WLAN_PA_GAS_INITIAL_RESP:
2321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		offset = 7 + 4;
2331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		break;
2341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	case WLAN_PA_GAS_COMEBACK_RESP:
2351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		offset = 8 + 4;
2361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		break;
2371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	default:
2381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return;
2391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
2401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
2411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (wpabuf_len(buf) < offset + 2)
2421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return;
2431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
2441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	len = wpabuf_mhead_u8(buf) + offset;
2451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2);
2461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
2471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
2481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
2491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt/**
2501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * gas_anqp_add_element - Add ANQP element header
2511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * @buf: GAS message
2521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * @info_id: ANQP Info ID
2531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * Returns: Pointer to the Length field for gas_anqp_set_element_len()
2541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt */
2551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtu8 * gas_anqp_add_element(struct wpabuf *buf, u16 info_id)
2561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
2571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpabuf_put_le16(buf, info_id);
2581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return wpabuf_put(buf, 2); /* Length to be filled */
2591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
2601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
2611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
2621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt/**
2631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * gas_anqp_set_element_len - Update ANQP element Length field
2641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * @buf: GAS message
2651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * @len_pos: Length field position from gas_anqp_add_element()
2661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt *
2671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * This function is called after the ANQP element payload has been added to the
2681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * buffer.
2691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt */
2701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtvoid gas_anqp_set_element_len(struct wpabuf *buf, u8 *len_pos)
2711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
2721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(buf, 0) - len_pos - 2);
2731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
274