1*03f9172cSAndroid Build Coastguard Worker /*
2*03f9172cSAndroid Build Coastguard Worker * Generic advertisement service (GAS) (IEEE 802.11u)
3*03f9172cSAndroid Build Coastguard Worker * Copyright (c) 2009, Atheros Communications
4*03f9172cSAndroid Build Coastguard Worker * Copyright (c) 2011-2012, Qualcomm Atheros
5*03f9172cSAndroid Build Coastguard Worker *
6*03f9172cSAndroid Build Coastguard Worker * This software may be distributed under the terms of the BSD license.
7*03f9172cSAndroid Build Coastguard Worker * See README for more details.
8*03f9172cSAndroid Build Coastguard Worker */
9*03f9172cSAndroid Build Coastguard Worker
10*03f9172cSAndroid Build Coastguard Worker #include "includes.h"
11*03f9172cSAndroid Build Coastguard Worker
12*03f9172cSAndroid Build Coastguard Worker #include "common.h"
13*03f9172cSAndroid Build Coastguard Worker #include "ieee802_11_defs.h"
14*03f9172cSAndroid Build Coastguard Worker #include "gas.h"
15*03f9172cSAndroid Build Coastguard Worker
16*03f9172cSAndroid Build Coastguard Worker
17*03f9172cSAndroid Build Coastguard Worker static struct wpabuf *
gas_build_req(u8 action,u8 dialog_token,size_t size)18*03f9172cSAndroid Build Coastguard Worker gas_build_req(u8 action, u8 dialog_token, size_t size)
19*03f9172cSAndroid Build Coastguard Worker {
20*03f9172cSAndroid Build Coastguard Worker struct wpabuf *buf;
21*03f9172cSAndroid Build Coastguard Worker
22*03f9172cSAndroid Build Coastguard Worker buf = wpabuf_alloc(100 + size);
23*03f9172cSAndroid Build Coastguard Worker if (buf == NULL)
24*03f9172cSAndroid Build Coastguard Worker return NULL;
25*03f9172cSAndroid Build Coastguard Worker
26*03f9172cSAndroid Build Coastguard Worker wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
27*03f9172cSAndroid Build Coastguard Worker wpabuf_put_u8(buf, action);
28*03f9172cSAndroid Build Coastguard Worker wpabuf_put_u8(buf, dialog_token);
29*03f9172cSAndroid Build Coastguard Worker
30*03f9172cSAndroid Build Coastguard Worker return buf;
31*03f9172cSAndroid Build Coastguard Worker }
32*03f9172cSAndroid Build Coastguard Worker
33*03f9172cSAndroid Build Coastguard Worker
gas_build_initial_req(u8 dialog_token,size_t size)34*03f9172cSAndroid Build Coastguard Worker struct wpabuf * gas_build_initial_req(u8 dialog_token, size_t size)
35*03f9172cSAndroid Build Coastguard Worker {
36*03f9172cSAndroid Build Coastguard Worker return gas_build_req(WLAN_PA_GAS_INITIAL_REQ, dialog_token,
37*03f9172cSAndroid Build Coastguard Worker size);
38*03f9172cSAndroid Build Coastguard Worker }
39*03f9172cSAndroid Build Coastguard Worker
40*03f9172cSAndroid Build Coastguard Worker
gas_build_comeback_req(u8 dialog_token)41*03f9172cSAndroid Build Coastguard Worker struct wpabuf * gas_build_comeback_req(u8 dialog_token)
42*03f9172cSAndroid Build Coastguard Worker {
43*03f9172cSAndroid Build Coastguard Worker return gas_build_req(WLAN_PA_GAS_COMEBACK_REQ, dialog_token, 0);
44*03f9172cSAndroid Build Coastguard Worker }
45*03f9172cSAndroid Build Coastguard Worker
46*03f9172cSAndroid Build Coastguard Worker
47*03f9172cSAndroid Build Coastguard Worker static struct wpabuf *
gas_build_resp(u8 action,u8 dialog_token,u16 status_code,u8 frag_id,u8 more,u16 comeback_delay,size_t size)48*03f9172cSAndroid Build Coastguard Worker gas_build_resp(u8 action, u8 dialog_token, u16 status_code, u8 frag_id,
49*03f9172cSAndroid Build Coastguard Worker u8 more, u16 comeback_delay, size_t size)
50*03f9172cSAndroid Build Coastguard Worker {
51*03f9172cSAndroid Build Coastguard Worker struct wpabuf *buf;
52*03f9172cSAndroid Build Coastguard Worker
53*03f9172cSAndroid Build Coastguard Worker buf = wpabuf_alloc(100 + size);
54*03f9172cSAndroid Build Coastguard Worker if (buf == NULL)
55*03f9172cSAndroid Build Coastguard Worker return NULL;
56*03f9172cSAndroid Build Coastguard Worker
57*03f9172cSAndroid Build Coastguard Worker wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
58*03f9172cSAndroid Build Coastguard Worker wpabuf_put_u8(buf, action);
59*03f9172cSAndroid Build Coastguard Worker wpabuf_put_u8(buf, dialog_token);
60*03f9172cSAndroid Build Coastguard Worker wpabuf_put_le16(buf, status_code);
61*03f9172cSAndroid Build Coastguard Worker if (action == WLAN_PA_GAS_COMEBACK_RESP)
62*03f9172cSAndroid Build Coastguard Worker wpabuf_put_u8(buf, frag_id | (more ? 0x80 : 0));
63*03f9172cSAndroid Build Coastguard Worker wpabuf_put_le16(buf, comeback_delay);
64*03f9172cSAndroid Build Coastguard Worker
65*03f9172cSAndroid Build Coastguard Worker return buf;
66*03f9172cSAndroid Build Coastguard Worker }
67*03f9172cSAndroid Build Coastguard Worker
68*03f9172cSAndroid Build Coastguard Worker
69*03f9172cSAndroid Build Coastguard Worker struct wpabuf *
gas_build_initial_resp(u8 dialog_token,u16 status_code,u16 comeback_delay,size_t size)70*03f9172cSAndroid Build Coastguard Worker gas_build_initial_resp(u8 dialog_token, u16 status_code, u16 comeback_delay,
71*03f9172cSAndroid Build Coastguard Worker size_t size)
72*03f9172cSAndroid Build Coastguard Worker {
73*03f9172cSAndroid Build Coastguard Worker return gas_build_resp(WLAN_PA_GAS_INITIAL_RESP, dialog_token,
74*03f9172cSAndroid Build Coastguard Worker status_code, 0, 0, comeback_delay, size);
75*03f9172cSAndroid Build Coastguard Worker }
76*03f9172cSAndroid Build Coastguard Worker
77*03f9172cSAndroid Build Coastguard Worker
78*03f9172cSAndroid Build Coastguard Worker struct wpabuf *
gas_build_comeback_resp(u8 dialog_token,u16 status_code,u8 frag_id,u8 more,u16 comeback_delay,size_t size)79*03f9172cSAndroid Build Coastguard Worker gas_build_comeback_resp(u8 dialog_token, u16 status_code, u8 frag_id, u8 more,
80*03f9172cSAndroid Build Coastguard Worker u16 comeback_delay, size_t size)
81*03f9172cSAndroid Build Coastguard Worker {
82*03f9172cSAndroid Build Coastguard Worker return gas_build_resp(WLAN_PA_GAS_COMEBACK_RESP, dialog_token,
83*03f9172cSAndroid Build Coastguard Worker status_code, frag_id, more, comeback_delay,
84*03f9172cSAndroid Build Coastguard Worker size);
85*03f9172cSAndroid Build Coastguard Worker }
86*03f9172cSAndroid Build Coastguard Worker
87*03f9172cSAndroid Build Coastguard Worker
88*03f9172cSAndroid Build Coastguard Worker /**
89*03f9172cSAndroid Build Coastguard Worker * gas_add_adv_proto_anqp - Add an Advertisement Protocol element
90*03f9172cSAndroid Build Coastguard Worker * @buf: Buffer to which the element is added
91*03f9172cSAndroid Build Coastguard Worker * @query_resp_len_limit: Query Response Length Limit in units of 256 octets
92*03f9172cSAndroid Build Coastguard Worker * @pame_bi: Pre-Association Message Exchange BSSID Independent (0/1)
93*03f9172cSAndroid Build Coastguard Worker *
94*03f9172cSAndroid Build Coastguard Worker *
95*03f9172cSAndroid Build Coastguard Worker * @query_resp_len_limit is 0 for request and 1-0x7f for response. 0x7f means
96*03f9172cSAndroid Build Coastguard Worker * that the maximum limit is determined by the maximum allowable number of
97*03f9172cSAndroid Build Coastguard Worker * fragments in the GAS Query Response Fragment ID.
98*03f9172cSAndroid Build Coastguard Worker */
gas_add_adv_proto_anqp(struct wpabuf * buf,u8 query_resp_len_limit,u8 pame_bi)99*03f9172cSAndroid Build Coastguard Worker static void gas_add_adv_proto_anqp(struct wpabuf *buf, u8 query_resp_len_limit,
100*03f9172cSAndroid Build Coastguard Worker u8 pame_bi)
101*03f9172cSAndroid Build Coastguard Worker {
102*03f9172cSAndroid Build Coastguard Worker /* Advertisement Protocol IE */
103*03f9172cSAndroid Build Coastguard Worker wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
104*03f9172cSAndroid Build Coastguard Worker wpabuf_put_u8(buf, 2); /* Length */
105*03f9172cSAndroid Build Coastguard Worker wpabuf_put_u8(buf, (query_resp_len_limit & 0x7f) |
106*03f9172cSAndroid Build Coastguard Worker (pame_bi ? 0x80 : 0));
107*03f9172cSAndroid Build Coastguard Worker /* Advertisement Protocol */
108*03f9172cSAndroid Build Coastguard Worker wpabuf_put_u8(buf, ACCESS_NETWORK_QUERY_PROTOCOL);
109*03f9172cSAndroid Build Coastguard Worker }
110*03f9172cSAndroid Build Coastguard Worker
111*03f9172cSAndroid Build Coastguard Worker
gas_anqp_build_initial_req(u8 dialog_token,size_t size)112*03f9172cSAndroid Build Coastguard Worker struct wpabuf * gas_anqp_build_initial_req(u8 dialog_token, size_t size)
113*03f9172cSAndroid Build Coastguard Worker {
114*03f9172cSAndroid Build Coastguard Worker struct wpabuf *buf;
115*03f9172cSAndroid Build Coastguard Worker
116*03f9172cSAndroid Build Coastguard Worker buf = gas_build_initial_req(dialog_token, 4 + size);
117*03f9172cSAndroid Build Coastguard Worker if (buf == NULL)
118*03f9172cSAndroid Build Coastguard Worker return NULL;
119*03f9172cSAndroid Build Coastguard Worker
120*03f9172cSAndroid Build Coastguard Worker gas_add_adv_proto_anqp(buf, 0, 0);
121*03f9172cSAndroid Build Coastguard Worker
122*03f9172cSAndroid Build Coastguard Worker wpabuf_put(buf, 2); /* Query Request Length to be filled */
123*03f9172cSAndroid Build Coastguard Worker
124*03f9172cSAndroid Build Coastguard Worker return buf;
125*03f9172cSAndroid Build Coastguard Worker }
126*03f9172cSAndroid Build Coastguard Worker
127*03f9172cSAndroid Build Coastguard Worker
gas_anqp_build_initial_resp(u8 dialog_token,u16 status_code,u16 comeback_delay,size_t size)128*03f9172cSAndroid Build Coastguard Worker struct wpabuf * gas_anqp_build_initial_resp(u8 dialog_token, u16 status_code,
129*03f9172cSAndroid Build Coastguard Worker u16 comeback_delay, size_t size)
130*03f9172cSAndroid Build Coastguard Worker {
131*03f9172cSAndroid Build Coastguard Worker struct wpabuf *buf;
132*03f9172cSAndroid Build Coastguard Worker
133*03f9172cSAndroid Build Coastguard Worker buf = gas_build_initial_resp(dialog_token, status_code, comeback_delay,
134*03f9172cSAndroid Build Coastguard Worker 4 + size);
135*03f9172cSAndroid Build Coastguard Worker if (buf == NULL)
136*03f9172cSAndroid Build Coastguard Worker return NULL;
137*03f9172cSAndroid Build Coastguard Worker
138*03f9172cSAndroid Build Coastguard Worker gas_add_adv_proto_anqp(buf, 0x7f, 0);
139*03f9172cSAndroid Build Coastguard Worker
140*03f9172cSAndroid Build Coastguard Worker wpabuf_put(buf, 2); /* Query Response Length to be filled */
141*03f9172cSAndroid Build Coastguard Worker
142*03f9172cSAndroid Build Coastguard Worker return buf;
143*03f9172cSAndroid Build Coastguard Worker }
144*03f9172cSAndroid Build Coastguard Worker
145*03f9172cSAndroid Build Coastguard Worker
gas_anqp_build_initial_resp_buf(u8 dialog_token,u16 status_code,u16 comeback_delay,struct wpabuf * payload)146*03f9172cSAndroid Build Coastguard Worker struct wpabuf * gas_anqp_build_initial_resp_buf(u8 dialog_token,
147*03f9172cSAndroid Build Coastguard Worker u16 status_code,
148*03f9172cSAndroid Build Coastguard Worker u16 comeback_delay,
149*03f9172cSAndroid Build Coastguard Worker struct wpabuf *payload)
150*03f9172cSAndroid Build Coastguard Worker {
151*03f9172cSAndroid Build Coastguard Worker struct wpabuf *buf;
152*03f9172cSAndroid Build Coastguard Worker
153*03f9172cSAndroid Build Coastguard Worker buf = gas_anqp_build_initial_resp(dialog_token, status_code,
154*03f9172cSAndroid Build Coastguard Worker comeback_delay,
155*03f9172cSAndroid Build Coastguard Worker payload ? wpabuf_len(payload) : 0);
156*03f9172cSAndroid Build Coastguard Worker if (buf == NULL)
157*03f9172cSAndroid Build Coastguard Worker return NULL;
158*03f9172cSAndroid Build Coastguard Worker
159*03f9172cSAndroid Build Coastguard Worker if (payload)
160*03f9172cSAndroid Build Coastguard Worker wpabuf_put_buf(buf, payload);
161*03f9172cSAndroid Build Coastguard Worker
162*03f9172cSAndroid Build Coastguard Worker gas_anqp_set_len(buf);
163*03f9172cSAndroid Build Coastguard Worker
164*03f9172cSAndroid Build Coastguard Worker return buf;
165*03f9172cSAndroid Build Coastguard Worker }
166*03f9172cSAndroid Build Coastguard Worker
167*03f9172cSAndroid Build Coastguard Worker
gas_anqp_build_comeback_resp(u8 dialog_token,u16 status_code,u8 frag_id,u8 more,u16 comeback_delay,size_t size)168*03f9172cSAndroid Build Coastguard Worker struct wpabuf * gas_anqp_build_comeback_resp(u8 dialog_token, u16 status_code,
169*03f9172cSAndroid Build Coastguard Worker u8 frag_id, u8 more,
170*03f9172cSAndroid Build Coastguard Worker u16 comeback_delay, size_t size)
171*03f9172cSAndroid Build Coastguard Worker {
172*03f9172cSAndroid Build Coastguard Worker struct wpabuf *buf;
173*03f9172cSAndroid Build Coastguard Worker
174*03f9172cSAndroid Build Coastguard Worker buf = gas_build_comeback_resp(dialog_token, status_code,
175*03f9172cSAndroid Build Coastguard Worker frag_id, more, comeback_delay, 4 + size);
176*03f9172cSAndroid Build Coastguard Worker if (buf == NULL)
177*03f9172cSAndroid Build Coastguard Worker return NULL;
178*03f9172cSAndroid Build Coastguard Worker
179*03f9172cSAndroid Build Coastguard Worker gas_add_adv_proto_anqp(buf, 0x7f, 0);
180*03f9172cSAndroid Build Coastguard Worker
181*03f9172cSAndroid Build Coastguard Worker wpabuf_put(buf, 2); /* Query Response Length to be filled */
182*03f9172cSAndroid Build Coastguard Worker
183*03f9172cSAndroid Build Coastguard Worker return buf;
184*03f9172cSAndroid Build Coastguard Worker }
185*03f9172cSAndroid Build Coastguard Worker
186*03f9172cSAndroid Build Coastguard Worker
gas_anqp_build_comeback_resp_buf(u8 dialog_token,u16 status_code,u8 frag_id,u8 more,u16 comeback_delay,struct wpabuf * payload)187*03f9172cSAndroid Build Coastguard Worker struct wpabuf * gas_anqp_build_comeback_resp_buf(u8 dialog_token,
188*03f9172cSAndroid Build Coastguard Worker u16 status_code,
189*03f9172cSAndroid Build Coastguard Worker u8 frag_id, u8 more,
190*03f9172cSAndroid Build Coastguard Worker u16 comeback_delay,
191*03f9172cSAndroid Build Coastguard Worker struct wpabuf *payload)
192*03f9172cSAndroid Build Coastguard Worker {
193*03f9172cSAndroid Build Coastguard Worker struct wpabuf *buf;
194*03f9172cSAndroid Build Coastguard Worker
195*03f9172cSAndroid Build Coastguard Worker buf = gas_anqp_build_comeback_resp(dialog_token, status_code, frag_id,
196*03f9172cSAndroid Build Coastguard Worker more, comeback_delay,
197*03f9172cSAndroid Build Coastguard Worker payload ? wpabuf_len(payload) : 0);
198*03f9172cSAndroid Build Coastguard Worker if (buf == NULL)
199*03f9172cSAndroid Build Coastguard Worker return NULL;
200*03f9172cSAndroid Build Coastguard Worker
201*03f9172cSAndroid Build Coastguard Worker if (payload)
202*03f9172cSAndroid Build Coastguard Worker wpabuf_put_buf(buf, payload);
203*03f9172cSAndroid Build Coastguard Worker
204*03f9172cSAndroid Build Coastguard Worker gas_anqp_set_len(buf);
205*03f9172cSAndroid Build Coastguard Worker
206*03f9172cSAndroid Build Coastguard Worker return buf;
207*03f9172cSAndroid Build Coastguard Worker }
208*03f9172cSAndroid Build Coastguard Worker
209*03f9172cSAndroid Build Coastguard Worker
210*03f9172cSAndroid Build Coastguard Worker /**
211*03f9172cSAndroid Build Coastguard Worker * gas_anqp_set_len - Set Query Request/Response Length
212*03f9172cSAndroid Build Coastguard Worker * @buf: GAS message
213*03f9172cSAndroid Build Coastguard Worker *
214*03f9172cSAndroid Build Coastguard Worker * This function is used to update the Query Request/Response Length field once
215*03f9172cSAndroid Build Coastguard Worker * the payload has been filled.
216*03f9172cSAndroid Build Coastguard Worker */
gas_anqp_set_len(struct wpabuf * buf)217*03f9172cSAndroid Build Coastguard Worker void gas_anqp_set_len(struct wpabuf *buf)
218*03f9172cSAndroid Build Coastguard Worker {
219*03f9172cSAndroid Build Coastguard Worker u8 action;
220*03f9172cSAndroid Build Coastguard Worker size_t offset;
221*03f9172cSAndroid Build Coastguard Worker u8 *len;
222*03f9172cSAndroid Build Coastguard Worker
223*03f9172cSAndroid Build Coastguard Worker if (buf == NULL || wpabuf_len(buf) < 2)
224*03f9172cSAndroid Build Coastguard Worker return;
225*03f9172cSAndroid Build Coastguard Worker
226*03f9172cSAndroid Build Coastguard Worker action = *(wpabuf_head_u8(buf) + 1);
227*03f9172cSAndroid Build Coastguard Worker switch (action) {
228*03f9172cSAndroid Build Coastguard Worker case WLAN_PA_GAS_INITIAL_REQ:
229*03f9172cSAndroid Build Coastguard Worker offset = 3 + 4;
230*03f9172cSAndroid Build Coastguard Worker break;
231*03f9172cSAndroid Build Coastguard Worker case WLAN_PA_GAS_INITIAL_RESP:
232*03f9172cSAndroid Build Coastguard Worker offset = 7 + 4;
233*03f9172cSAndroid Build Coastguard Worker break;
234*03f9172cSAndroid Build Coastguard Worker case WLAN_PA_GAS_COMEBACK_RESP:
235*03f9172cSAndroid Build Coastguard Worker offset = 8 + 4;
236*03f9172cSAndroid Build Coastguard Worker break;
237*03f9172cSAndroid Build Coastguard Worker default:
238*03f9172cSAndroid Build Coastguard Worker return;
239*03f9172cSAndroid Build Coastguard Worker }
240*03f9172cSAndroid Build Coastguard Worker
241*03f9172cSAndroid Build Coastguard Worker if (wpabuf_len(buf) < offset + 2)
242*03f9172cSAndroid Build Coastguard Worker return;
243*03f9172cSAndroid Build Coastguard Worker
244*03f9172cSAndroid Build Coastguard Worker len = wpabuf_mhead_u8(buf) + offset;
245*03f9172cSAndroid Build Coastguard Worker WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2);
246*03f9172cSAndroid Build Coastguard Worker }
247*03f9172cSAndroid Build Coastguard Worker
248*03f9172cSAndroid Build Coastguard Worker
249*03f9172cSAndroid Build Coastguard Worker /**
250*03f9172cSAndroid Build Coastguard Worker * gas_anqp_add_element - Add ANQP element header
251*03f9172cSAndroid Build Coastguard Worker * @buf: GAS message
252*03f9172cSAndroid Build Coastguard Worker * @info_id: ANQP Info ID
253*03f9172cSAndroid Build Coastguard Worker * Returns: Pointer to the Length field for gas_anqp_set_element_len()
254*03f9172cSAndroid Build Coastguard Worker */
gas_anqp_add_element(struct wpabuf * buf,u16 info_id)255*03f9172cSAndroid Build Coastguard Worker u8 * gas_anqp_add_element(struct wpabuf *buf, u16 info_id)
256*03f9172cSAndroid Build Coastguard Worker {
257*03f9172cSAndroid Build Coastguard Worker wpabuf_put_le16(buf, info_id);
258*03f9172cSAndroid Build Coastguard Worker return wpabuf_put(buf, 2); /* Length to be filled */
259*03f9172cSAndroid Build Coastguard Worker }
260*03f9172cSAndroid Build Coastguard Worker
261*03f9172cSAndroid Build Coastguard Worker
262*03f9172cSAndroid Build Coastguard Worker /**
263*03f9172cSAndroid Build Coastguard Worker * gas_anqp_set_element_len - Update ANQP element Length field
264*03f9172cSAndroid Build Coastguard Worker * @buf: GAS message
265*03f9172cSAndroid Build Coastguard Worker * @len_pos: Length field position from gas_anqp_add_element()
266*03f9172cSAndroid Build Coastguard Worker *
267*03f9172cSAndroid Build Coastguard Worker * This function is called after the ANQP element payload has been added to the
268*03f9172cSAndroid Build Coastguard Worker * buffer.
269*03f9172cSAndroid Build Coastguard Worker */
gas_anqp_set_element_len(struct wpabuf * buf,u8 * len_pos)270*03f9172cSAndroid Build Coastguard Worker void gas_anqp_set_element_len(struct wpabuf *buf, u8 *len_pos)
271*03f9172cSAndroid Build Coastguard Worker {
272*03f9172cSAndroid Build Coastguard Worker WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(buf, 0) - len_pos - 2);
273*03f9172cSAndroid Build Coastguard Worker }
274