2 * Generic advertisement service (GAS) (IEEE 802.11u)
3 * Copyright (c) 2009, Atheros Communications
4 * Copyright (c) 2011-2012, Qualcomm Atheros
6 * This software may be distributed under the terms of the BSD license.
7 * See README for more details.
13 #include "ieee802_11_defs.h"
17 static struct wpabuf *
18 gas_build_req(u8 action, u8 dialog_token, size_t size)
22 buf = wpabuf_alloc(100 + size);
26 wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
27 wpabuf_put_u8(buf, action);
28 wpabuf_put_u8(buf, dialog_token);
34 struct wpabuf * gas_build_initial_req(u8 dialog_token, size_t size)
36 return gas_build_req(WLAN_PA_GAS_INITIAL_REQ, dialog_token,
41 struct wpabuf * gas_build_comeback_req(u8 dialog_token)
43 return gas_build_req(WLAN_PA_GAS_COMEBACK_REQ, dialog_token, 0);
47 static struct wpabuf *
48 gas_build_resp(u8 action, u8 dialog_token, u16 status_code, u8 frag_id,
49 u8 more, u16 comeback_delay, size_t size)
53 buf = wpabuf_alloc(100 + size);
57 wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
58 wpabuf_put_u8(buf, action);
59 wpabuf_put_u8(buf, dialog_token);
60 wpabuf_put_le16(buf, status_code);
61 if (action == WLAN_PA_GAS_COMEBACK_RESP)
62 wpabuf_put_u8(buf, frag_id | (more ? 0x80 : 0));
63 wpabuf_put_le16(buf, comeback_delay);
70 gas_build_initial_resp(u8 dialog_token, u16 status_code, u16 comeback_delay,
73 return gas_build_resp(WLAN_PA_GAS_INITIAL_RESP, dialog_token,
74 status_code, 0, 0, comeback_delay, size);
78 static struct wpabuf *
79 gas_build_comeback_resp(u8 dialog_token, u16 status_code, u8 frag_id, u8 more,
80 u16 comeback_delay, size_t size)
82 return gas_build_resp(WLAN_PA_GAS_COMEBACK_RESP, dialog_token,
83 status_code, frag_id, more, comeback_delay,
89 * gas_add_adv_proto_anqp - Add an Advertisement Protocol element
90 * @buf: Buffer to which the element is added
91 * @query_resp_len_limit: Query Response Length Limit in units of 256 octets
92 * @pame_bi: Pre-Association Message Exchange BSSID Independent (0/1)
95 * @query_resp_len_limit is 0 for request and 1-0x7f for response. 0x7f means
96 * that the maximum limit is determined by the maximum allowable number of
97 * fragments in the GAS Query Response Fragment ID.
99 static void gas_add_adv_proto_anqp(struct wpabuf *buf, u8 query_resp_len_limit,
102 /* Advertisement Protocol IE */
103 wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
104 wpabuf_put_u8(buf, 2); /* Length */
105 wpabuf_put_u8(buf, (query_resp_len_limit & 0x7f) |
106 (pame_bi ? 0x80 : 0));
107 /* Advertisement Protocol */
108 wpabuf_put_u8(buf, ACCESS_NETWORK_QUERY_PROTOCOL);
112 struct wpabuf * gas_anqp_build_initial_req(u8 dialog_token, size_t size)
116 buf = gas_build_initial_req(dialog_token, 4 + size);
120 gas_add_adv_proto_anqp(buf, 0, 0);
122 wpabuf_put(buf, 2); /* Query Request Length to be filled */
128 struct wpabuf * gas_anqp_build_initial_resp(u8 dialog_token, u16 status_code,
129 u16 comeback_delay, size_t size)
133 buf = gas_build_initial_resp(dialog_token, status_code, comeback_delay,
138 gas_add_adv_proto_anqp(buf, 0x7f, 0);
140 wpabuf_put(buf, 2); /* Query Response Length to be filled */
146 struct wpabuf * gas_anqp_build_initial_resp_buf(u8 dialog_token,
149 struct wpabuf *payload)
153 buf = gas_anqp_build_initial_resp(dialog_token, status_code,
155 payload ? wpabuf_len(payload) : 0);
160 wpabuf_put_buf(buf, payload);
162 gas_anqp_set_len(buf);
168 struct wpabuf * gas_anqp_build_comeback_resp(u8 dialog_token, u16 status_code,
170 u16 comeback_delay, size_t size)
174 buf = gas_build_comeback_resp(dialog_token, status_code,
175 frag_id, more, comeback_delay, 4 + size);
179 gas_add_adv_proto_anqp(buf, 0x7f, 0);
181 wpabuf_put(buf, 2); /* Query Response Length to be filled */
187 struct wpabuf * gas_anqp_build_comeback_resp_buf(u8 dialog_token,
191 struct wpabuf *payload)
195 buf = gas_anqp_build_comeback_resp(dialog_token, status_code, frag_id,
196 more, comeback_delay,
197 payload ? wpabuf_len(payload) : 0);
202 wpabuf_put_buf(buf, payload);
204 gas_anqp_set_len(buf);
211 * gas_anqp_set_len - Set Query Request/Response Length
214 * This function is used to update the Query Request/Response Length field once
215 * the payload has been filled.
217 void gas_anqp_set_len(struct wpabuf *buf)
223 if (buf == NULL || wpabuf_len(buf) < 2)
226 action = *(wpabuf_head_u8(buf) + 1);
228 case WLAN_PA_GAS_INITIAL_REQ:
231 case WLAN_PA_GAS_INITIAL_RESP:
234 case WLAN_PA_GAS_COMEBACK_RESP:
241 if (wpabuf_len(buf) < offset + 2)
244 len = wpabuf_mhead_u8(buf) + offset;
245 WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2);
250 * gas_anqp_add_element - Add ANQP element header
252 * @info_id: ANQP Info ID
253 * Returns: Pointer to the Length field for gas_anqp_set_element_len()
255 u8 * gas_anqp_add_element(struct wpabuf *buf, u16 info_id)
257 wpabuf_put_le16(buf, info_id);
258 return wpabuf_put(buf, 2); /* Length to be filled */
263 * gas_anqp_set_element_len - Update ANQP element Length field
265 * @len_pos: Length field position from gas_anqp_add_element()
267 * This function is called after the ANQP element payload has been added to the
270 void gas_anqp_set_element_len(struct wpabuf *buf, u8 *len_pos)
272 WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(buf, 0) - len_pos - 2);