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