]> git.ipfire.org Git - thirdparty/hostap.git/blame - tests/hwsim/test_gas.py
tests: Convert binascii.hexlify() output to a string object for python3
[thirdparty/hostap.git] / tests / hwsim / test_gas.py
CommitLineData
ebc61dc2
JM
1# GAS tests
2# Copyright (c) 2013, Qualcomm Atheros, Inc.
6d01255e 3# Copyright (c) 2013-2015, Jouni Malinen <j@w1.fi>
ebc61dc2
JM
4#
5# This software may be distributed under the terms of the BSD license.
6# See README for more details.
7
9fd6804d 8from remotehost import remote_compatible
ebc61dc2 9import time
bfe375ec 10import binascii
ebc61dc2 11import logging
c9aa4308 12logger = logging.getLogger()
61854f16 13import os
ebc61dc2 14import re
d9474958 15import struct
ebc61dc2
JM
16
17import hostapd
1d1de230 18from wpasupplicant import WpaSupplicant
61854f16 19from tshark import run_tshark
16f91791 20from utils import alloc_fail, wait_fail_trigger, skip_with_fips, HwsimSkip
70f2a3f4 21from hwsim import HWSimRadio
ebc61dc2
JM
22
23def hs20_ap_params():
24 params = hostapd.wpa2_params(ssid="test-gas")
25 params['wpa_key_mgmt'] = "WPA-EAP"
26 params['ieee80211w'] = "1"
27 params['ieee8021x'] = "1"
28 params['auth_server_addr'] = "127.0.0.1"
29 params['auth_server_port'] = "1812"
30 params['auth_server_shared_secret'] = "radius"
31 params['interworking'] = "1"
32 params['access_network_type'] = "14"
33 params['internet'] = "1"
34 params['asra'] = "0"
35 params['esr'] = "0"
36 params['uesa'] = "0"
37 params['venue_group'] = "7"
38 params['venue_type'] = "1"
39 params['venue_name'] = [ "eng:Example venue", "fin:Esimerkkipaikka" ]
40 params['roaming_consortium'] = [ "112233", "1020304050", "010203040506",
41 "fedcba" ]
42 params['domain_name'] = "example.com,another.example.com"
43 params['nai_realm'] = [ "0,example.com,13[5:6],21[2:4][5:7]",
44 "0,another.example.com" ]
45 params['anqp_3gpp_cell_net'] = "244,91"
cef16c47
JM
46 params['network_auth_type'] = "02http://www.example.com/redirect/me/here/"
47 params['ipaddr_type_availability'] = "14"
48 params['hs20'] = "1"
49 params['hs20_oper_friendly_name'] = [ "eng:Example operator", "fin:Esimerkkioperaattori" ]
50 params['hs20_wan_metrics'] = "01:8000:1000:80:240:3000"
51 params['hs20_conn_capab'] = [ "1:0:2", "6:22:1", "17:5060:0" ]
52 params['hs20_operating_class'] = "5173"
ebc61dc2
JM
53 return params
54
18dd2af0
JM
55def start_ap(ap):
56 params = hs20_ap_params()
57 params['hessid'] = ap['bssid']
6f334bf7 58 return hostapd.add_ap(ap, params)
18dd2af0 59
5e80b502
JM
60def get_gas_response(dev, bssid, info, allow_fetch_failure=False,
61 extra_test=False):
ebc61dc2
JM
62 exp = r'<.>(GAS-RESPONSE-INFO) addr=([0-9a-f:]*) dialog_token=([0-9]*) status_code=([0-9]*) resp_len=([\-0-9]*)'
63 res = re.split(exp, info)
64 if len(res) < 6:
65 raise Exception("Could not parse GAS-RESPONSE-INFO")
66 if res[2] != bssid:
67 raise Exception("Unexpected BSSID in response")
68 token = res[3]
69 status = res[4]
70 if status != "0":
71 raise Exception("GAS query failed")
72 resp_len = res[5]
73 if resp_len == "-1":
74 raise Exception("GAS query reported invalid response length")
75 if int(resp_len) > 2000:
76 raise Exception("Unexpected long GAS response")
77
5e80b502
JM
78 if extra_test:
79 if "FAIL" not in dev.request("GAS_RESPONSE_GET " + bssid + " 123456"):
80 raise Exception("Invalid dialog token accepted")
81 if "FAIL-Invalid range" not in dev.request("GAS_RESPONSE_GET " + bssid + " " + token + " 10000,10001"):
82 raise Exception("Invalid range accepted")
83 if "FAIL-Invalid range" not in dev.request("GAS_RESPONSE_GET " + bssid + " " + token + " 0,10000"):
84 raise Exception("Invalid range accepted")
85 if "FAIL" not in dev.request("GAS_RESPONSE_GET " + bssid + " " + token + " 0"):
86 raise Exception("Invalid GAS_RESPONSE_GET accepted")
87
88 res1_2 = dev.request("GAS_RESPONSE_GET " + bssid + " " + token + " 1,2")
89 res5_3 = dev.request("GAS_RESPONSE_GET " + bssid + " " + token + " 5,3")
90
ebc61dc2
JM
91 resp = dev.request("GAS_RESPONSE_GET " + bssid + " " + token)
92 if "FAIL" in resp:
93 if allow_fetch_failure:
94 logger.debug("GAS response was not available anymore")
95 return
96 raise Exception("Could not fetch GAS response")
97 if len(resp) != int(resp_len) * 2:
98 raise Exception("Unexpected GAS response length")
99 logger.debug("GAS response: " + resp)
5e80b502
JM
100 if extra_test:
101 if resp[2:6] != res1_2:
102 raise Exception("Unexpected response substring res1_2: " + res1_2)
103 if resp[10:16] != res5_3:
104 raise Exception("Unexpected response substring res5_3: " + res5_3)
ebc61dc2
JM
105
106def test_gas_generic(dev, apdev):
107 """Generic GAS query"""
108 bssid = apdev[0]['bssid']
109 params = hs20_ap_params()
110 params['hessid'] = bssid
8b8a1864 111 hostapd.add_ap(apdev[0], params)
ebc61dc2 112
5e80b502
JM
113 cmds = [ "foo",
114 "00:11:22:33:44:55",
115 "00:11:22:33:44:55 ",
116 "00:11:22:33:44:55 ",
117 "00:11:22:33:44:55 1",
118 "00:11:22:33:44:55 1 1234",
119 "00:11:22:33:44:55 qq",
120 "00:11:22:33:44:55 qq 1234",
121 "00:11:22:33:44:55 00 1",
122 "00:11:22:33:44:55 00 123",
123 "00:11:22:33:44:55 00 ",
124 "00:11:22:33:44:55 00 qq" ]
125 for cmd in cmds:
126 if "FAIL" not in dev[0].request("GAS_REQUEST " + cmd):
127 raise Exception("Invalid GAS_REQUEST accepted: " + cmd)
128
4ef70531 129 dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
ebc61dc2
JM
130 req = dev[0].request("GAS_REQUEST " + bssid + " 00 000102000101")
131 if "FAIL" in req:
132 raise Exception("GAS query request rejected")
133 ev = dev[0].wait_event(["GAS-RESPONSE-INFO"], timeout=10)
134 if ev is None:
135 raise Exception("GAS query timed out")
5e80b502
JM
136 get_gas_response(dev[0], bssid, ev, extra_test=True)
137
138 if "FAIL" not in dev[0].request("GAS_RESPONSE_GET ff"):
139 raise Exception("Invalid GAS_RESPONSE_GET accepted")
ebc61dc2 140
16f91791
VK
141def test_gas_rand_ta(dev, apdev, params):
142 """Generic GAS query with random TA"""
143 flags = int(dev[0].get_driver_status_field('capa.flags'), 16)
144 if flags & 0x0000400000000000 == 0:
145 raise HwsimSkip("Driver does not support random GAS TA")
146
147 try:
148 _test_gas_rand_ta(dev, apdev, params['logdir'])
149 finally:
150 dev[0].request("SET gas_rand_mac_addr 0")
151
152def _test_gas_rand_ta(dev, apdev, logdir):
153 bssid = apdev[0]['bssid']
154 params = hs20_ap_params()
155 params['hessid'] = bssid
156 hostapd.add_ap(apdev[0], params)
157
158 dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
159 req = dev[0].request("SET gas_rand_mac_addr 1")
160 if "FAIL" in req:
161 raise Exception("Failed to set gas_rand_mac_addr")
162
163 dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
164 req = dev[0].request("GAS_REQUEST " + bssid + " 00 000102000101")
165 if "FAIL" in req:
166 raise Exception("GAS query request rejected")
167 ev = dev[0].wait_event(["GAS-RESPONSE-INFO"], timeout=10)
168 if ev is None:
169 raise Exception("GAS query timed out")
170 get_gas_response(dev[0], bssid, ev, extra_test=True)
171
172 out = run_tshark(os.path.join(logdir, "hwsim0.pcapng"),
173 "wlan_mgt.fixed.category_code == 4 && (wlan_mgt.fixed.publicact == 0x0a || wlan_mgt.fixed.publicact == 0x0b)",
174 display=["wlan.ta", "wlan.ra"])
175 res = out.splitlines()
176 if len(res) != 2:
177 raise Exception("Unexpected number of GAS frames")
178 req_ta = res[0].split('\t')[0]
179 resp_ra = res[1].split('\t')[1]
180 logger.info("Request TA: %s, Response RA: %s" % (req_ta, resp_ra))
181 if req_ta != resp_ra:
182 raise Exception("Request TA does not match response RA")
183 if req_ta == dev[0].own_addr():
184 raise Exception("Request TA was own permanent MAC address, not random")
185
ebc61dc2
JM
186def test_gas_concurrent_scan(dev, apdev):
187 """Generic GAS queries with concurrent scan operation"""
188 bssid = apdev[0]['bssid']
189 params = hs20_ap_params()
190 params['hessid'] = bssid
8b8a1864 191 hostapd.add_ap(apdev[0], params)
ebc61dc2 192
d7a99700 193 # get BSS entry available to allow GAS query
4ef70531 194 dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
ebc61dc2
JM
195
196 logger.info("Request concurrent operations")
197 req = dev[0].request("GAS_REQUEST " + bssid + " 00 000102000101")
198 if "FAIL" in req:
199 raise Exception("GAS query request rejected")
200 req = dev[0].request("GAS_REQUEST " + bssid + " 00 000102000801")
201 if "FAIL" in req:
202 raise Exception("GAS query request rejected")
d7a99700 203 dev[0].scan(no_wait=True)
ebc61dc2
JM
204 req = dev[0].request("GAS_REQUEST " + bssid + " 00 000102000201")
205 if "FAIL" in req:
206 raise Exception("GAS query request rejected")
207 req = dev[0].request("GAS_REQUEST " + bssid + " 00 000102000501")
208 if "FAIL" in req:
209 raise Exception("GAS query request rejected")
210
211 responses = 0
212 for i in range(0, 5):
213 ev = dev[0].wait_event(["GAS-RESPONSE-INFO", "CTRL-EVENT-SCAN-RESULTS"],
214 timeout=10)
215 if ev is None:
216 raise Exception("Operation timed out")
217 if "GAS-RESPONSE-INFO" in ev:
218 responses = responses + 1
219 get_gas_response(dev[0], bssid, ev, allow_fetch_failure=True)
220
221 if responses != 4:
222 raise Exception("Unexpected number of GAS responses")
223
224def test_gas_concurrent_connect(dev, apdev):
225 """Generic GAS queries with concurrent connection operation"""
ca158ea6 226 skip_with_fips(dev[0])
ebc61dc2
JM
227 bssid = apdev[0]['bssid']
228 params = hs20_ap_params()
229 params['hessid'] = bssid
8b8a1864 230 hostapd.add_ap(apdev[0], params)
ebc61dc2 231
4ef70531 232 dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
ebc61dc2
JM
233
234 logger.debug("Start concurrent connect and GAS request")
235 dev[0].connect("test-gas", key_mgmt="WPA-EAP", eap="TTLS",
236 identity="DOMAIN\mschapv2 user", anonymous_identity="ttls",
237 password="password", phase2="auth=MSCHAPV2",
d7a99700
JM
238 ca_cert="auth_serv/ca.pem", wait_connect=False,
239 scan_freq="2412")
ebc61dc2
JM
240 req = dev[0].request("GAS_REQUEST " + bssid + " 00 000102000101")
241 if "FAIL" in req:
242 raise Exception("GAS query request rejected")
243
244 ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED", "GAS-RESPONSE-INFO"],
245 timeout=20)
246 if ev is None:
247 raise Exception("Operation timed out")
248 if "CTRL-EVENT-CONNECTED" not in ev:
249 raise Exception("Unexpected operation order")
250
251 ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED", "GAS-RESPONSE-INFO"],
252 timeout=20)
253 if ev is None:
254 raise Exception("Operation timed out")
255 if "GAS-RESPONSE-INFO" not in ev:
256 raise Exception("Unexpected operation order")
257 get_gas_response(dev[0], bssid, ev)
258
259 dev[0].request("DISCONNECT")
5f35a5e2 260 dev[0].wait_disconnected(timeout=5)
ebc61dc2
JM
261
262 logger.debug("Wait six seconds for expiration of connect-without-scan")
263 time.sleep(6)
adf277a0 264 dev[0].dump_monitor()
ebc61dc2
JM
265
266 logger.debug("Start concurrent GAS request and connect")
267 req = dev[0].request("GAS_REQUEST " + bssid + " 00 000102000101")
268 if "FAIL" in req:
269 raise Exception("GAS query request rejected")
270 dev[0].request("RECONNECT")
271
272 ev = dev[0].wait_event(["GAS-RESPONSE-INFO"], timeout=10)
273 if ev is None:
274 raise Exception("Operation timed out")
275 get_gas_response(dev[0], bssid, ev)
276
277 ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"], timeout=20)
278 if ev is None:
279 raise Exception("No new scan results reported")
280
5f35a5e2 281 ev = dev[0].wait_connected(timeout=20, error="Operation tiemd out")
ebc61dc2
JM
282 if "CTRL-EVENT-CONNECTED" not in ev:
283 raise Exception("Unexpected operation order")
836a3745 284
f2dfb1da
JM
285def gas_fragment_and_comeback(dev, apdev, frag_limit=0, comeback_delay=0):
286 hapd = start_ap(apdev)
287 if frag_limit:
288 hapd.set("gas_frag_limit", str(frag_limit))
289 if comeback_delay:
290 hapd.set("gas_comeback_delay", str(comeback_delay))
291
292 dev.scan_for_bss(apdev['bssid'], freq="2412", force_scan=True)
293 dev.request("FETCH_ANQP")
294 ev = dev.wait_event(["GAS-QUERY-DONE"], timeout=5)
fee39910
JM
295 if ev is None:
296 raise Exception("No GAS-QUERY-DONE event")
297 if "result=SUCCESS" not in ev:
298 raise Exception("Unexpected GAS result: " + ev)
cef16c47 299 for i in range(0, 13):
f2dfb1da 300 ev = dev.wait_event(["RX-ANQP", "RX-HS20-ANQP"], timeout=5)
e4a44b3c
JM
301 if ev is None:
302 raise Exception("Operation timed out")
f2dfb1da 303 ev = dev.wait_event(["ANQP-QUERY-DONE"], timeout=1)
fee39910
JM
304 if ev is None:
305 raise Exception("No ANQP-QUERY-DONE event")
306 if "result=SUCCESS" not in ev:
307 raise Exception("Unexpected ANQP result: " + ev)
e4a44b3c 308
f2dfb1da
JM
309def test_gas_fragment(dev, apdev):
310 """GAS fragmentation"""
311 gas_fragment_and_comeback(dev[0], apdev[0], frag_limit=50)
312
70f2a3f4
JM
313def test_gas_fragment_mcc(dev, apdev):
314 """GAS fragmentation with mac80211_hwsim MCC enabled"""
315 with HWSimRadio(n_channels=2) as (radio, iface):
316 wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
317 wpas.interface_add(iface)
f2dfb1da
JM
318 gas_fragment_and_comeback(wpas, apdev[0], frag_limit=50)
319
320def test_gas_fragment_with_comeback_delay(dev, apdev):
321 """GAS fragmentation and comeback delay"""
322 gas_fragment_and_comeback(dev[0], apdev[0], frag_limit=50,
323 comeback_delay=500)
324
325def test_gas_fragment_with_comeback_delay_mcc(dev, apdev):
326 """GAS fragmentation and comeback delay with mac80211_hwsim MCC enabled"""
327 with HWSimRadio(n_channels=2) as (radio, iface):
328 wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
329 wpas.interface_add(iface)
330 gas_fragment_and_comeback(wpas, apdev[0], frag_limit=50,
331 comeback_delay=500)
70f2a3f4 332
e4a44b3c 333def test_gas_comeback_delay(dev, apdev):
5a145a55 334 """GAS comeback delay"""
1d2e6a45
JM
335 run_gas_comeback_delay(dev, apdev, 500)
336
337def test_gas_comeback_delay_long(dev, apdev):
338 """GAS long comeback delay"""
339 run_gas_comeback_delay(dev, apdev, 2500)
340
0d7b2e90
JM
341def test_gas_comeback_delay_long2(dev, apdev):
342 """GAS long comeback delay over default STA timeout"""
343 run_gas_comeback_delay(dev, apdev, 6000)
344
1d2e6a45 345def run_gas_comeback_delay(dev, apdev, delay):
18dd2af0 346 hapd = start_ap(apdev[0])
1d2e6a45 347 hapd.set("gas_comeback_delay", str(delay))
e4a44b3c 348
4ef70531 349 dev[0].scan_for_bss(apdev[0]['bssid'], freq="2412", force_scan=True)
836a3745 350 dev[0].request("FETCH_ANQP")
5a145a55
JM
351 if "FAIL-BUSY" not in dev[0].request("SCAN"):
352 raise Exception("SCAN accepted during FETCH_ANQP")
836a3745 353 for i in range(0, 6):
0d7b2e90 354 ev = dev[0].wait_event(["RX-ANQP"], timeout=10)
836a3745
JM
355 if ev is None:
356 raise Exception("Operation timed out")
2cace98e 357
9fd6804d 358@remote_compatible
ea27f662
JM
359def test_gas_stop_fetch_anqp(dev, apdev):
360 """Stop FETCH_ANQP operation"""
361 hapd = start_ap(apdev[0])
362
363 dev[0].scan_for_bss(apdev[0]['bssid'], freq="2412", force_scan=True)
364 hapd.set("ext_mgmt_frame_handling", "1")
365 dev[0].request("FETCH_ANQP")
366 dev[0].request("STOP_FETCH_ANQP")
367 hapd.set("ext_mgmt_frame_handling", "0")
368 ev = dev[0].wait_event(["RX-ANQP", "GAS-QUERY-DONE"], timeout=10)
369 if ev is None:
370 raise Exception("GAS-QUERY-DONE timed out")
371 if "RX-ANQP" in ev:
372 raise Exception("Unexpected ANQP response received")
373
e56e286d
JM
374def test_gas_anqp_get(dev, apdev):
375 """GAS/ANQP query for both IEEE 802.11 and Hotspot 2.0 elements"""
376 hapd = start_ap(apdev[0])
377 bssid = apdev[0]['bssid']
378
4ef70531
JM
379 dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
380 if "OK" not in dev[0].request("ANQP_GET " + bssid + " 258,268,hs20:3,hs20:4"):
381 raise Exception("ANQP_GET command failed")
e56e286d
JM
382
383 ev = dev[0].wait_event(["GAS-QUERY-START"], timeout=5)
384 if ev is None:
385 raise Exception("GAS query start timed out")
386
387 ev = dev[0].wait_event(["GAS-QUERY-DONE"], timeout=10)
388 if ev is None:
389 raise Exception("GAS query timed out")
390
391 ev = dev[0].wait_event(["RX-ANQP"], timeout=1)
392 if ev is None or "Venue Name" not in ev:
393 raise Exception("Did not receive Venue Name")
394
395 ev = dev[0].wait_event(["RX-ANQP"], timeout=1)
396 if ev is None or "Domain Name list" not in ev:
397 raise Exception("Did not receive Domain Name list")
398
399 ev = dev[0].wait_event(["RX-HS20-ANQP"], timeout=1)
400 if ev is None or "Operator Friendly Name" not in ev:
6d6f3c09
JM
401 raise Exception("Did not receive Operator Friendly Name")
402
403 ev = dev[0].wait_event(["RX-HS20-ANQP"], timeout=1)
404 if ev is None or "WAN Metrics" not in ev:
405 raise Exception("Did not receive WAN Metrics")
406
a60dbbce
JM
407 ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=10)
408 if ev is None:
409 raise Exception("ANQP-QUERY-DONE event not seen")
410 if "result=SUCCESS" not in ev:
411 raise Exception("Unexpected result: " + ev)
412
2453f251
JM
413 if "OK" not in dev[0].request("ANQP_GET " + bssid + " hs20:3"):
414 raise Exception("ANQP_GET command failed")
415
416 ev = dev[0].wait_event(["GAS-QUERY-START"], timeout=5)
417 if ev is None:
418 raise Exception("GAS query start timed out")
419
420 ev = dev[0].wait_event(["GAS-QUERY-DONE"], timeout=10)
421 if ev is None:
422 raise Exception("GAS query timed out")
423
424 ev = dev[0].wait_event(["RX-HS20-ANQP"], timeout=1)
425 if ev is None or "Operator Friendly Name" not in ev:
426 raise Exception("Did not receive Operator Friendly Name")
427
428 ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=10)
429 if ev is None:
430 raise Exception("ANQP-QUERY-DONE event not seen")
431 if "result=SUCCESS" not in ev:
432 raise Exception("Unexpected result: " + ev)
433
4ef70531
JM
434 if "OK" not in dev[0].request("HS20_ANQP_GET " + bssid + " 3,4"):
435 raise Exception("ANQP_GET command failed")
6d6f3c09
JM
436
437 ev = dev[0].wait_event(["RX-HS20-ANQP"], timeout=1)
438 if ev is None or "Operator Friendly Name" not in ev:
e56e286d
JM
439 raise Exception("Did not receive Operator Friendly Name")
440
441 ev = dev[0].wait_event(["RX-HS20-ANQP"], timeout=1)
442 if ev is None or "WAN Metrics" not in ev:
443 raise Exception("Did not receive WAN Metrics")
444
09b812c9 445 logger.info("Attempt an MBO request with an AP that does not support MBO")
a9be28bf 446 if "OK" not in dev[0].request("ANQP_GET " + bssid + " 272,mbo:2"):
09b812c9
JM
447 raise Exception("ANQP_GET command failed (2)")
448
449 ev = dev[0].wait_event(["GAS-QUERY-START"], timeout=5)
450 if ev is None:
451 raise Exception("GAS query start timed out (2)")
452
453 ev = dev[0].wait_event(["GAS-QUERY-DONE"], timeout=10)
454 if ev is None:
455 raise Exception("GAS query timed out (2)")
456
ea68ed56
JM
457 cmds = [ "",
458 "foo",
459 "00:11:22:33:44:55 258,hs20:-1",
460 "00:11:22:33:44:55 258,hs20:0",
461 "00:11:22:33:44:55 258,hs20:32",
462 "00:11:22:33:44:55 hs20:-1",
463 "00:11:22:33:44:55 hs20:0",
464 "00:11:22:33:44:55 hs20:32",
09b812c9
JM
465 "00:11:22:33:44:55 mbo:-1",
466 "00:11:22:33:44:55 mbo:0",
467 "00:11:22:33:44:55 mbo:999",
2453f251 468 "00:11:22:33:44:55 mbo:1,258,mbo:2,mbo:3,259",
ea68ed56
JM
469 "00:11:22:33:44:55",
470 "00:11:22:33:44:55 ",
60547477
JM
471 "00:11:22:33:44:55 0",
472 "00:11:22:33:44:55 1" ]
ea68ed56
JM
473 for cmd in cmds:
474 if "FAIL" not in dev[0].request("ANQP_GET " + cmd):
475 raise Exception("Invalid ANQP_GET accepted")
476
477 cmds = [ "",
478 "foo",
479 "00:11:22:33:44:55 -1",
480 "00:11:22:33:44:55 0",
481 "00:11:22:33:44:55 32",
482 "00:11:22:33:44:55",
483 "00:11:22:33:44:55 ",
3e5f7818
JM
484 "00:11:22:33:44:55 0",
485 "00:11:22:33:44:55 1" ]
ea68ed56
JM
486 for cmd in cmds:
487 if "FAIL" not in dev[0].request("HS20_ANQP_GET " + cmd):
488 raise Exception("Invalid HS20_ANQP_GET accepted")
489
3429e2ff
JM
490def test_gas_anqp_get_oom(dev, apdev):
491 """GAS/ANQP query OOM"""
492 hapd = start_ap(apdev[0])
493 bssid = apdev[0]['bssid']
494
495 dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
496 with alloc_fail(dev[0], 1, "wpabuf_alloc;anqp_send_req"):
497 if "FAIL" not in dev[0].request("ANQP_GET " + bssid + " 258,268,hs20:3,hs20:4"):
498 raise Exception("ANQP_GET command accepted during OOM")
3e5f7818
JM
499 with alloc_fail(dev[0], 1, "hs20_build_anqp_req;hs20_anqp_send_req"):
500 if "FAIL" not in dev[0].request("HS20_ANQP_GET " + bssid + " 1"):
501 raise Exception("HS20_ANQP_GET command accepted during OOM")
502 with alloc_fail(dev[0], 1, "gas_query_req;hs20_anqp_send_req"):
503 if "FAIL" not in dev[0].request("HS20_ANQP_GET " + bssid + " 1"):
504 raise Exception("HS20_ANQP_GET command accepted during OOM")
505 with alloc_fail(dev[0], 1, "=hs20_anqp_send_req"):
506 if "FAIL" not in dev[0].request("REQ_HS20_ICON " + bssid + " w1fi_logo"):
507 raise Exception("REQ_HS20_ICON command accepted during OOM")
508 with alloc_fail(dev[0], 2, "=hs20_anqp_send_req"):
509 if "FAIL" not in dev[0].request("REQ_HS20_ICON " + bssid + " w1fi_logo"):
510 raise Exception("REQ_HS20_ICON command accepted during OOM")
3429e2ff 511
5dec77ee
JM
512def test_gas_anqp_icon_binary_proto(dev, apdev):
513 """GAS/ANQP and icon binary protocol testing"""
514 hapd = start_ap(apdev[0])
515 bssid = apdev[0]['bssid']
516
517 dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
518 hapd.set("ext_mgmt_frame_handling", "1")
519
520 tests = [ '010000', '01000000', '00000000', '00030000', '00020000',
521 '00000100', '0001ff0100ee', '0001ff0200ee' ]
522 for test in tests:
523 dev[0].request("HS20_ICON_REQUEST " + bssid + " w1fi_logo")
524 query = gas_rx(hapd)
525 gas = parse_gas(query['payload'])
526 resp = action_response(query)
527 data = binascii.unhexlify(test)
528 data = binascii.unhexlify('506f9a110b00') + data
529 data = struct.pack('<HHH', len(data) + 4, 0xdddd, len(data)) + data
530 resp['payload'] = anqp_initial_resp(gas['dialog_token'], 0) + data
531 send_gas_resp(hapd, resp)
532 expect_gas_result(dev[0], "SUCCESS")
533
21d410ca
JM
534def test_gas_anqp_hs20_proto(dev, apdev):
535 """GAS/ANQP and Hotspot 2.0 element protocol testing"""
536 hapd = start_ap(apdev[0])
537 bssid = apdev[0]['bssid']
538
539 dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
540 hapd.set("ext_mgmt_frame_handling", "1")
541
542 tests = [ '00', '0100', '0201', '0300', '0400', '0500', '0600', '0700',
543 '0800', '0900', '0a00', '0b0000000000' ]
544 for test in tests:
545 dev[0].request("HS20_ANQP_GET " + bssid + " 3,4")
546 query = gas_rx(hapd)
547 gas = parse_gas(query['payload'])
548 resp = action_response(query)
549 data = binascii.unhexlify(test)
550 data = binascii.unhexlify('506f9a11') + data
551 data = struct.pack('<HHH', len(data) + 4, 0xdddd, len(data)) + data
552 resp['payload'] = anqp_initial_resp(gas['dialog_token'], 0) + data
553 send_gas_resp(hapd, resp)
554 expect_gas_result(dev[0], "SUCCESS")
555
75f6134d 556def expect_gas_result(dev, result, status=None):
bfe375ec
JM
557 ev = dev.wait_event(["GAS-QUERY-DONE"], timeout=10)
558 if ev is None:
559 raise Exception("GAS query timed out")
560 if "result=" + result not in ev:
561 raise Exception("Unexpected GAS query result")
75f6134d
JM
562 if status and "status_code=" + str(status) + ' ' not in ev:
563 raise Exception("Unexpected GAS status code")
bfe375ec 564
18dd2af0 565def anqp_get(dev, bssid, id):
4ef70531
JM
566 if "OK" not in dev.request("ANQP_GET " + bssid + " " + str(id)):
567 raise Exception("ANQP_GET command failed")
18dd2af0
JM
568 ev = dev.wait_event(["GAS-QUERY-START"], timeout=5)
569 if ev is None:
570 raise Exception("GAS query start timed out")
571
2cace98e
JM
572def test_gas_timeout(dev, apdev):
573 """GAS timeout"""
18dd2af0 574 hapd = start_ap(apdev[0])
2cace98e 575 bssid = apdev[0]['bssid']
2cace98e 576
4ef70531 577 dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
2cace98e
JM
578 hapd.set("ext_mgmt_frame_handling", "1")
579
18dd2af0 580 anqp_get(dev[0], bssid, 263)
2cace98e
JM
581
582 ev = hapd.wait_event(["MGMT-RX"], timeout=5)
583 if ev is None:
584 raise Exception("MGMT RX wait timed out")
585
bfe375ec
JM
586 expect_gas_result(dev[0], "TIMEOUT")
587
d9474958
JM
588MGMT_SUBTYPE_ACTION = 13
589ACTION_CATEG_PUBLIC = 4
590
591GAS_INITIAL_REQUEST = 10
592GAS_INITIAL_RESPONSE = 11
593GAS_COMEBACK_REQUEST = 12
594GAS_COMEBACK_RESPONSE = 13
595GAS_ACTIONS = [ GAS_INITIAL_REQUEST, GAS_INITIAL_RESPONSE,
596 GAS_COMEBACK_REQUEST, GAS_COMEBACK_RESPONSE ]
597
598def anqp_adv_proto():
599 return struct.pack('BBBB', 108, 2, 127, 0)
600
75f6134d 601def anqp_initial_resp(dialog_token, status_code, comeback_delay=0):
fe871e48 602 return struct.pack('<BBBHH', ACTION_CATEG_PUBLIC, GAS_INITIAL_RESPONSE,
75f6134d
JM
603 dialog_token, status_code, comeback_delay) + anqp_adv_proto()
604
605def anqp_comeback_resp(dialog_token, status_code=0, id=0, more=False, comeback_delay=0, bogus_adv_proto=False):
606 if more:
607 id |= 0x80
608 if bogus_adv_proto:
609 adv = struct.pack('BBBB', 108, 2, 127, 1)
610 else:
611 adv = anqp_adv_proto()
d9474958 612 return struct.pack('<BBBHBH', ACTION_CATEG_PUBLIC, GAS_COMEBACK_RESPONSE,
75f6134d 613 dialog_token, status_code, id, comeback_delay) + adv
d9474958
JM
614
615def gas_rx(hapd):
616 count = 0
617 while count < 30:
618 count = count + 1
619 query = hapd.mgmt_rx()
620 if query is None:
621 raise Exception("Action frame not received")
622 if query['subtype'] != MGMT_SUBTYPE_ACTION:
623 continue
624 payload = query['payload']
625 if len(payload) < 2:
626 continue
627 (category, action) = struct.unpack('BB', payload[0:2])
628 if category != ACTION_CATEG_PUBLIC or action not in GAS_ACTIONS:
629 continue
630 return query
631 raise Exception("No Action frame received")
632
633def parse_gas(payload):
634 pos = payload
635 (category, action, dialog_token) = struct.unpack('BBB', pos[0:3])
636 if category != ACTION_CATEG_PUBLIC:
637 return None
638 if action not in GAS_ACTIONS:
639 return None
640 gas = {}
641 gas['action'] = action
642 pos = pos[3:]
643
75f6134d 644 if len(pos) < 1 and action != GAS_COMEBACK_REQUEST:
d9474958
JM
645 return None
646
647 gas['dialog_token'] = dialog_token
1d1de230
JM
648
649 if action == GAS_INITIAL_RESPONSE:
650 if len(pos) < 4:
651 return None
652 (status_code, comeback_delay) = struct.unpack('<HH', pos[0:4])
653 gas['status_code'] = status_code
654 gas['comeback_delay'] = comeback_delay
de8c4144
JM
655
656 if action == GAS_COMEBACK_RESPONSE:
657 if len(pos) < 5:
658 return None
659 (status_code, frag, comeback_delay) = struct.unpack('<HBH', pos[0:5])
660 gas['status_code'] = status_code
661 gas['frag'] = frag
662 gas['comeback_delay'] = comeback_delay
663
d9474958
JM
664 return gas
665
666def action_response(req):
667 resp = {}
668 resp['fc'] = req['fc']
669 resp['da'] = req['sa']
670 resp['sa'] = req['da']
671 resp['bssid'] = req['bssid']
672 return resp
673
75f6134d
JM
674def send_gas_resp(hapd, resp):
675 hapd.mgmt_tx(resp)
676 ev = hapd.wait_event(["MGMT-TX-STATUS"], timeout=5)
677 if ev is None:
678 raise Exception("Missing TX status for GAS response")
679 if "ok=1" not in ev:
680 raise Exception("GAS response not acknowledged")
681
bfe375ec
JM
682def test_gas_invalid_response_type(dev, apdev):
683 """GAS invalid response type"""
18dd2af0 684 hapd = start_ap(apdev[0])
bfe375ec 685 bssid = apdev[0]['bssid']
bfe375ec 686
4ef70531 687 dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
bfe375ec
JM
688 hapd.set("ext_mgmt_frame_handling", "1")
689
18dd2af0 690 anqp_get(dev[0], bssid, 263)
bfe375ec 691
d9474958
JM
692 query = gas_rx(hapd)
693 gas = parse_gas(query['payload'])
694
695 resp = action_response(query)
bfe375ec 696 # GAS Comeback Response instead of GAS Initial Response
d9474958 697 resp['payload'] = anqp_comeback_resp(gas['dialog_token']) + struct.pack('<H', 0)
75f6134d 698 send_gas_resp(hapd, resp)
bfe375ec
JM
699
700 # station drops the invalid frame, so this needs to result in GAS timeout
701 expect_gas_result(dev[0], "TIMEOUT")
fe871e48
JM
702
703def test_gas_failure_status_code(dev, apdev):
704 """GAS failure status code"""
705 hapd = start_ap(apdev[0])
706 bssid = apdev[0]['bssid']
707
4ef70531 708 dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
fe871e48
JM
709 hapd.set("ext_mgmt_frame_handling", "1")
710
711 anqp_get(dev[0], bssid, 263)
712
713 query = gas_rx(hapd)
714 gas = parse_gas(query['payload'])
715
716 resp = action_response(query)
717 resp['payload'] = anqp_initial_resp(gas['dialog_token'], 61) + struct.pack('<H', 0)
75f6134d 718 send_gas_resp(hapd, resp)
fe871e48
JM
719
720 expect_gas_result(dev[0], "FAILURE")
84262fef
JM
721
722def test_gas_malformed(dev, apdev):
723 """GAS malformed response frames"""
724 hapd = start_ap(apdev[0])
725 bssid = apdev[0]['bssid']
726
4ef70531 727 dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
84262fef
JM
728 hapd.set("ext_mgmt_frame_handling", "1")
729
730 anqp_get(dev[0], bssid, 263)
731
732 query = gas_rx(hapd)
733 gas = parse_gas(query['payload'])
734
735 resp = action_response(query)
736
737 resp['payload'] = struct.pack('<BBBH', ACTION_CATEG_PUBLIC,
738 GAS_COMEBACK_RESPONSE,
739 gas['dialog_token'], 0)
740 hapd.mgmt_tx(resp)
741
742 resp['payload'] = struct.pack('<BBBHB', ACTION_CATEG_PUBLIC,
743 GAS_COMEBACK_RESPONSE,
744 gas['dialog_token'], 0, 0)
745 hapd.mgmt_tx(resp)
746
747 hdr = struct.pack('<BBBHH', ACTION_CATEG_PUBLIC, GAS_INITIAL_RESPONSE,
748 gas['dialog_token'], 0, 0)
749 resp['payload'] = hdr + struct.pack('B', 108)
750 hapd.mgmt_tx(resp)
751 resp['payload'] = hdr + struct.pack('BB', 108, 0)
752 hapd.mgmt_tx(resp)
753 resp['payload'] = hdr + struct.pack('BB', 108, 1)
754 hapd.mgmt_tx(resp)
755 resp['payload'] = hdr + struct.pack('BB', 108, 255)
756 hapd.mgmt_tx(resp)
757 resp['payload'] = hdr + struct.pack('BBB', 108, 1, 127)
758 hapd.mgmt_tx(resp)
759 resp['payload'] = hdr + struct.pack('BBB', 108, 2, 127)
760 hapd.mgmt_tx(resp)
761 resp['payload'] = hdr + struct.pack('BBBB', 0, 2, 127, 0)
762 hapd.mgmt_tx(resp)
763
764 resp['payload'] = anqp_initial_resp(gas['dialog_token'], 0) + struct.pack('<H', 1)
765 hapd.mgmt_tx(resp)
766
767 resp['payload'] = anqp_initial_resp(gas['dialog_token'], 0) + struct.pack('<HB', 2, 0)
768 hapd.mgmt_tx(resp)
769
770 resp['payload'] = anqp_initial_resp(gas['dialog_token'], 0) + struct.pack('<H', 65535)
771 hapd.mgmt_tx(resp)
772
773 resp['payload'] = anqp_initial_resp(gas['dialog_token'], 0) + struct.pack('<HBB', 1, 0, 0)
774 hapd.mgmt_tx(resp)
775
776 # Station drops invalid frames, but the last of the responses is valid from
777 # GAS view point even though it has an extra octet in the end and the ANQP
a60dbbce 778 # part of the response is not valid. This is reported as successfully
84262fef
JM
779 # completed GAS exchange.
780 expect_gas_result(dev[0], "SUCCESS")
75f6134d 781
a60dbbce
JM
782 ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=5)
783 if ev is None:
784 raise Exception("ANQP-QUERY-DONE not reported")
785 if "result=INVALID_FRAME" not in ev:
786 raise Exception("Unexpected result: " + ev)
787
75f6134d
JM
788def init_gas(hapd, bssid, dev):
789 anqp_get(dev, bssid, 263)
790 query = gas_rx(hapd)
791 gas = parse_gas(query['payload'])
792 dialog_token = gas['dialog_token']
793
794 resp = action_response(query)
795 resp['payload'] = anqp_initial_resp(dialog_token, 0, comeback_delay=1) + struct.pack('<H', 0)
796 send_gas_resp(hapd, resp)
797
798 query = gas_rx(hapd)
799 gas = parse_gas(query['payload'])
800 if gas['action'] != GAS_COMEBACK_REQUEST:
801 raise Exception("Unexpected request action")
802 if gas['dialog_token'] != dialog_token:
803 raise Exception("Unexpected dialog token change")
804 return query, dialog_token
805
f9a93044
JM
806def allow_gas_initial_req(hapd, dialog_token):
807 msg = hapd.mgmt_rx(timeout=1)
808 if msg is not None:
809 gas = parse_gas(msg['payload'])
810 if gas['action'] != GAS_INITIAL_REQUEST or dialog_token == gas['dialog_token']:
811 raise Exception("Unexpected management frame")
812
75f6134d
JM
813def test_gas_malformed_comeback_resp(dev, apdev):
814 """GAS malformed comeback response frames"""
815 hapd = start_ap(apdev[0])
816 bssid = apdev[0]['bssid']
817
4ef70531 818 dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
75f6134d
JM
819 hapd.set("ext_mgmt_frame_handling", "1")
820
821 logger.debug("Non-zero status code in comeback response")
822 query, dialog_token = init_gas(hapd, bssid, dev[0])
823 resp = action_response(query)
824 resp['payload'] = anqp_comeback_resp(dialog_token, status_code=2) + struct.pack('<H', 0)
825 send_gas_resp(hapd, resp)
826 expect_gas_result(dev[0], "FAILURE", status=2)
827
828 logger.debug("Different advertisement protocol in comeback response")
829 query, dialog_token = init_gas(hapd, bssid, dev[0])
830 resp = action_response(query)
831 resp['payload'] = anqp_comeback_resp(dialog_token, bogus_adv_proto=True) + struct.pack('<H', 0)
832 send_gas_resp(hapd, resp)
833 expect_gas_result(dev[0], "PEER_ERROR")
834
835 logger.debug("Non-zero frag id and comeback delay in comeback response")
836 query, dialog_token = init_gas(hapd, bssid, dev[0])
837 resp = action_response(query)
838 resp['payload'] = anqp_comeback_resp(dialog_token, id=1, comeback_delay=1) + struct.pack('<H', 0)
839 send_gas_resp(hapd, resp)
840 expect_gas_result(dev[0], "PEER_ERROR")
841
842 logger.debug("Unexpected frag id in comeback response")
843 query, dialog_token = init_gas(hapd, bssid, dev[0])
844 resp = action_response(query)
845 resp['payload'] = anqp_comeback_resp(dialog_token, id=1) + struct.pack('<H', 0)
846 send_gas_resp(hapd, resp)
847 expect_gas_result(dev[0], "PEER_ERROR")
848
849 logger.debug("Empty fragment and replay in comeback response")
850 query, dialog_token = init_gas(hapd, bssid, dev[0])
851 resp = action_response(query)
852 resp['payload'] = anqp_comeback_resp(dialog_token, more=True) + struct.pack('<H', 0)
853 send_gas_resp(hapd, resp)
854 query = gas_rx(hapd)
855 gas = parse_gas(query['payload'])
856 if gas['action'] != GAS_COMEBACK_REQUEST:
857 raise Exception("Unexpected request action")
858 if gas['dialog_token'] != dialog_token:
859 raise Exception("Unexpected dialog token change")
860 resp = action_response(query)
861 resp['payload'] = anqp_comeback_resp(dialog_token) + struct.pack('<H', 0)
862 send_gas_resp(hapd, resp)
863 resp['payload'] = anqp_comeback_resp(dialog_token, id=1) + struct.pack('<H', 0)
864 send_gas_resp(hapd, resp)
865 expect_gas_result(dev[0], "SUCCESS")
866
867 logger.debug("Unexpected initial response when waiting for comeback response")
868 query, dialog_token = init_gas(hapd, bssid, dev[0])
869 resp = action_response(query)
870 resp['payload'] = anqp_initial_resp(dialog_token, 0) + struct.pack('<H', 0)
871 send_gas_resp(hapd, resp)
f9a93044 872 allow_gas_initial_req(hapd, dialog_token)
75f6134d
JM
873 expect_gas_result(dev[0], "TIMEOUT")
874
875 logger.debug("Too short comeback response")
876 query, dialog_token = init_gas(hapd, bssid, dev[0])
877 resp = action_response(query)
878 resp['payload'] = struct.pack('<BBBH', ACTION_CATEG_PUBLIC,
879 GAS_COMEBACK_RESPONSE, dialog_token, 0)
880 send_gas_resp(hapd, resp)
f9a93044 881 allow_gas_initial_req(hapd, dialog_token)
75f6134d
JM
882 expect_gas_result(dev[0], "TIMEOUT")
883
884 logger.debug("Too short comeback response(2)")
885 query, dialog_token = init_gas(hapd, bssid, dev[0])
886 resp = action_response(query)
887 resp['payload'] = struct.pack('<BBBHBB', ACTION_CATEG_PUBLIC,
888 GAS_COMEBACK_RESPONSE, dialog_token, 0, 0x80,
889 0)
890 send_gas_resp(hapd, resp)
f9a93044 891 allow_gas_initial_req(hapd, dialog_token)
75f6134d
JM
892 expect_gas_result(dev[0], "TIMEOUT")
893
894 logger.debug("Maximum comeback response fragment claiming more fragments")
895 query, dialog_token = init_gas(hapd, bssid, dev[0])
896 resp = action_response(query)
897 resp['payload'] = anqp_comeback_resp(dialog_token, more=True) + struct.pack('<H', 0)
898 send_gas_resp(hapd, resp)
899 for i in range(1, 129):
900 query = gas_rx(hapd)
901 gas = parse_gas(query['payload'])
902 if gas['action'] != GAS_COMEBACK_REQUEST:
903 raise Exception("Unexpected request action")
904 if gas['dialog_token'] != dialog_token:
905 raise Exception("Unexpected dialog token change")
906 resp = action_response(query)
907 resp['payload'] = anqp_comeback_resp(dialog_token, id=i, more=True) + struct.pack('<H', 0)
908 send_gas_resp(hapd, resp)
909 expect_gas_result(dev[0], "PEER_ERROR")
910
911def test_gas_comeback_resp_additional_delay(dev, apdev):
912 """GAS comeback response requesting additional delay"""
913 hapd = start_ap(apdev[0])
914 bssid = apdev[0]['bssid']
915
4ef70531 916 dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
75f6134d
JM
917 hapd.set("ext_mgmt_frame_handling", "1")
918
919 query, dialog_token = init_gas(hapd, bssid, dev[0])
920 for i in range(0, 2):
921 resp = action_response(query)
922 resp['payload'] = anqp_comeback_resp(dialog_token, status_code=95, comeback_delay=50) + struct.pack('<H', 0)
923 send_gas_resp(hapd, resp)
924 query = gas_rx(hapd)
925 gas = parse_gas(query['payload'])
926 if gas['action'] != GAS_COMEBACK_REQUEST:
927 raise Exception("Unexpected request action")
928 if gas['dialog_token'] != dialog_token:
929 raise Exception("Unexpected dialog token change")
930 resp = action_response(query)
931 resp['payload'] = anqp_comeback_resp(dialog_token, status_code=0) + struct.pack('<H', 0)
932 send_gas_resp(hapd, resp)
933 expect_gas_result(dev[0], "SUCCESS")
d61ed3ac
JM
934
935def test_gas_unknown_adv_proto(dev, apdev):
936 """Unknown advertisement protocol id"""
937 bssid = apdev[0]['bssid']
938 params = hs20_ap_params()
939 params['hessid'] = bssid
8b8a1864 940 hostapd.add_ap(apdev[0], params)
d61ed3ac 941
4ef70531 942 dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
d61ed3ac
JM
943 req = dev[0].request("GAS_REQUEST " + bssid + " 42 000102000101")
944 if "FAIL" in req:
945 raise Exception("GAS query request rejected")
946 expect_gas_result(dev[0], "FAILURE", "59")
947 ev = dev[0].wait_event(["GAS-RESPONSE-INFO"], timeout=10)
948 if ev is None:
949 raise Exception("GAS query timed out")
950 exp = r'<.>(GAS-RESPONSE-INFO) addr=([0-9a-f:]*) dialog_token=([0-9]*) status_code=([0-9]*) resp_len=([\-0-9]*)'
951 res = re.split(exp, ev)
952 if len(res) < 6:
953 raise Exception("Could not parse GAS-RESPONSE-INFO")
954 if res[2] != bssid:
955 raise Exception("Unexpected BSSID in response")
956 status = res[4]
957 if status != "59":
958 raise Exception("Unexpected GAS-RESPONSE-INFO status")
1d1de230 959
69e85c7f
JM
960def test_gas_request_oom(dev, apdev):
961 """GAS_REQUEST OOM"""
962 bssid = apdev[0]['bssid']
963 params = hs20_ap_params()
964 params['hessid'] = bssid
965 hostapd.add_ap(apdev[0], params)
966
967 dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
968
969 with alloc_fail(dev[0], 1, "gas_build_req;gas_send_request"):
970 if "FAIL" not in dev[0].request("GAS_REQUEST " + bssid + " 42"):
971 raise Exception("GAS query request rejected")
972
973 with alloc_fail(dev[0], 1, "gas_query_req;gas_send_request"):
974 if "FAIL" not in dev[0].request("GAS_REQUEST " + bssid + " 42"):
975 raise Exception("GAS query request rejected")
976
977 with alloc_fail(dev[0], 1, "wpabuf_dup;gas_resp_cb"):
978 if "OK" not in dev[0].request("GAS_REQUEST " + bssid + " 00 000102000101"):
979 raise Exception("GAS query request rejected")
980 ev = dev[0].wait_event(["GAS-RESPONSE-INFO"], timeout=10)
981 if ev is None:
982 raise Exception("No GAS response")
983 if "status_code=0" not in ev:
984 raise Exception("GAS response indicated a failure")
985
1d1de230
JM
986def test_gas_max_pending(dev, apdev):
987 """GAS and maximum pending query limit"""
988 hapd = start_ap(apdev[0])
989 hapd.set("gas_frag_limit", "50")
990 bssid = apdev[0]['bssid']
991
992 wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
993 wpas.interface_add("wlan5")
994 if "OK" not in wpas.request("P2P_SET listen_channel 1"):
995 raise Exception("Failed to set listen channel")
996 if "OK" not in wpas.p2p_listen():
997 raise Exception("Failed to start listen state")
998 if "FAIL" in wpas.request("SET ext_mgmt_frame_handling 1"):
999 raise Exception("Failed to enable external management frame handling")
1000
1001 anqp_query = struct.pack('<HHHHHHHHHH', 256, 16, 257, 258, 260, 261, 262, 263, 264, 268)
1002 gas = struct.pack('<H', len(anqp_query)) + anqp_query
1003
1004 for dialog_token in range(1, 10):
1005 msg = struct.pack('<BBB', ACTION_CATEG_PUBLIC, GAS_INITIAL_REQUEST,
1006 dialog_token) + anqp_adv_proto() + gas
7ab74770 1007 req = "MGMT_TX {} {} freq=2412 wait_time=10 action={}".format(bssid, bssid, binascii.hexlify(msg).decode())
1d1de230
JM
1008 if "OK" not in wpas.request(req):
1009 raise Exception("Could not send management frame")
1010 resp = wpas.mgmt_rx()
1011 if resp is None:
1012 raise Exception("MGMT-RX timeout")
1013 if 'payload' not in resp:
1014 raise Exception("Missing payload")
1015 gresp = parse_gas(resp['payload'])
1016 if gresp['dialog_token'] != dialog_token:
1017 raise Exception("Dialog token mismatch")
1018 status_code = gresp['status_code']
1019 if dialog_token < 9 and status_code != 0:
1020 raise Exception("Unexpected failure status code {} for dialog token {}".format(status_code, dialog_token))
1021 if dialog_token > 8 and status_code == 0:
1022 raise Exception("Unexpected success status code {} for dialog token {}".format(status_code, dialog_token))
de8c4144
JM
1023
1024def test_gas_no_pending(dev, apdev):
1025 """GAS and no pending query for comeback request"""
1026 hapd = start_ap(apdev[0])
1027 bssid = apdev[0]['bssid']
1028
1029 wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
1030 wpas.interface_add("wlan5")
1031 if "OK" not in wpas.request("P2P_SET listen_channel 1"):
1032 raise Exception("Failed to set listen channel")
1033 if "OK" not in wpas.p2p_listen():
1034 raise Exception("Failed to start listen state")
1035 if "FAIL" in wpas.request("SET ext_mgmt_frame_handling 1"):
1036 raise Exception("Failed to enable external management frame handling")
1037
1038 msg = struct.pack('<BBB', ACTION_CATEG_PUBLIC, GAS_COMEBACK_REQUEST, 1)
7ab74770 1039 req = "MGMT_TX {} {} freq=2412 wait_time=10 action={}".format(bssid, bssid, binascii.hexlify(msg).decode())
de8c4144
JM
1040 if "OK" not in wpas.request(req):
1041 raise Exception("Could not send management frame")
1042 resp = wpas.mgmt_rx()
1043 if resp is None:
1044 raise Exception("MGMT-RX timeout")
1045 if 'payload' not in resp:
1046 raise Exception("Missing payload")
1047 gresp = parse_gas(resp['payload'])
1048 status_code = gresp['status_code']
1049 if status_code != 60:
1050 raise Exception("Unexpected status code {} (expected 60)".format(status_code))
6ec64f3e 1051
1ad6f0d5
JM
1052def test_gas_delete_at_deinit(dev, apdev):
1053 """GAS query deleted at deinit"""
1054 hapd = start_ap(apdev[0])
1055 hapd.set("gas_comeback_delay", "1000")
1056 bssid = apdev[0]['bssid']
1057
1058 wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
1059 wpas.interface_add("wlan5")
1060 wpas.scan_for_bss(apdev[0]['bssid'], freq="2412", force_scan=True)
1061 wpas.request("ANQP_GET " + bssid + " 258")
1062
1063 wpas.global_request("INTERFACE_REMOVE " + wpas.ifname)
1064 ev = wpas.wait_event(["GAS-QUERY-DONE"], timeout=2)
1065 del wpas
1066 if ev is None:
1067 raise Exception("GAS-QUERY-DONE not seen")
1068 if "result=DELETED_AT_DEINIT" not in ev:
1069 raise Exception("Unexpected result code: " + ev)
1070
6ec64f3e
JM
1071def test_gas_missing_payload(dev, apdev):
1072 """No action code in the query frame"""
1073 bssid = apdev[0]['bssid']
1074 params = hs20_ap_params()
1075 params['hessid'] = bssid
8b8a1864 1076 hostapd.add_ap(apdev[0], params)
6ec64f3e
JM
1077
1078 dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
1079
1080 cmd = "MGMT_TX {} {} freq=2412 action=040A".format(bssid, bssid)
1081 if "FAIL" in dev[0].request(cmd):
1082 raise Exception("Could not send test Action frame")
1083 ev = dev[0].wait_event(["MGMT-TX-STATUS"], timeout=10)
1084 if ev is None:
1085 raise Exception("Timeout on MGMT-TX-STATUS")
1086 if "result=SUCCESS" not in ev:
1087 raise Exception("AP did not ack Action frame")
1088
1089 cmd = "MGMT_TX {} {} freq=2412 action=04".format(bssid, bssid)
1090 if "FAIL" in dev[0].request(cmd):
1091 raise Exception("Could not send test Action frame")
1092 ev = dev[0].wait_event(["MGMT-TX-STATUS"], timeout=10)
1093 if ev is None:
1094 raise Exception("Timeout on MGMT-TX-STATUS")
1095 if "result=SUCCESS" not in ev:
1096 raise Exception("AP did not ack Action frame")
c518fecc
JM
1097
1098def test_gas_query_deinit(dev, apdev):
1099 """Pending GAS/ANQP query during deinit"""
1100 hapd = start_ap(apdev[0])
1101 bssid = apdev[0]['bssid']
1102
1103 wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
1104 wpas.interface_add("wlan5")
1105
1106 wpas.scan_for_bss(bssid, freq="2412", force_scan=True)
1107 id = wpas.request("RADIO_WORK add block-work")
1108 if "OK" not in wpas.request("ANQP_GET " + bssid + " 258"):
1109 raise Exception("ANQP_GET command failed")
1110
1111 ev = wpas.wait_event(["GAS-QUERY-START", "EXT-RADIO-WORK-START"], timeout=5)
1112 if ev is None:
1113 raise Exception("Timeout while waiting radio work to start")
1114 ev = wpas.wait_event(["GAS-QUERY-START", "EXT-RADIO-WORK-START"], timeout=5)
1115 if ev is None:
1116 raise Exception("Timeout while waiting radio work to start (2)")
1117
1118 # Remove the interface while the gas-query radio work is still pending and
1119 # GAS query has not yet been started.
1120 wpas.interface_remove("wlan5")
6d01255e 1121
9fd6804d 1122@remote_compatible
6d01255e
JM
1123def test_gas_anqp_oom_wpas(dev, apdev):
1124 """GAS/ANQP query and OOM in wpa_supplicant"""
1125 hapd = start_ap(apdev[0])
1126 bssid = apdev[0]['bssid']
1127
1128 dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
1129
20c7d26f
JM
1130 with alloc_fail(dev[0], 1, "wpa_bss_anqp_alloc"):
1131 if "OK" not in dev[0].request("ANQP_GET " + bssid + " 258"):
1132 raise Exception("ANQP_GET command failed")
1133 ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=5)
1134 if ev is None:
1135 raise Exception("ANQP query did not complete")
1136
6d01255e
JM
1137 with alloc_fail(dev[0], 1, "gas_build_req"):
1138 if "FAIL" not in dev[0].request("ANQP_GET " + bssid + " 258"):
1139 raise Exception("Unexpected ANQP_GET command success (OOM)")
1140
1141def test_gas_anqp_oom_hapd(dev, apdev):
1142 """GAS/ANQP query and OOM in hostapd"""
1143 hapd = start_ap(apdev[0])
1144 bssid = apdev[0]['bssid']
1145
1146 dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
1147
1148 with alloc_fail(hapd, 1, "gas_build_resp"):
1149 # This query will time out due to the AP not sending a response (OOM).
1150 if "OK" not in dev[0].request("ANQP_GET " + bssid + " 258"):
1151 raise Exception("ANQP_GET command failed")
1152
1153 ev = dev[0].wait_event(["GAS-QUERY-START"], timeout=5)
1154 if ev is None:
1155 raise Exception("GAS query start timed out")
1156
1157 ev = dev[0].wait_event(["GAS-QUERY-DONE"], timeout=10)
1158 if ev is None:
1159 raise Exception("GAS query timed out")
1160 if "result=TIMEOUT" not in ev:
1161 raise Exception("Unexpected result: " + ev)
1162
1163 ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=10)
1164 if ev is None:
1165 raise Exception("ANQP-QUERY-DONE event not seen")
1166 if "result=FAILURE" not in ev:
1167 raise Exception("Unexpected result: " + ev)
1168
1169 with alloc_fail(hapd, 1, "gas_anqp_build_comeback_resp"):
1170 hapd.set("gas_frag_limit", "50")
1171
35c146bc
JM
1172 # The first attempt of this query will time out due to the AP not
1173 # sending a response (OOM), but the retry succeeds.
2c68ae2b 1174 dev[0].request("FETCH_ANQP")
6d01255e
JM
1175 ev = dev[0].wait_event(["GAS-QUERY-START"], timeout=5)
1176 if ev is None:
1177 raise Exception("GAS query start timed out")
1178
1179 ev = dev[0].wait_event(["GAS-QUERY-DONE"], timeout=10)
1180 if ev is None:
1181 raise Exception("GAS query timed out")
35c146bc 1182 if "result=SUCCESS" not in ev:
6d01255e
JM
1183 raise Exception("Unexpected result: " + ev)
1184
1185 ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=10)
1186 if ev is None:
1187 raise Exception("ANQP-QUERY-DONE event not seen")
35c146bc 1188 if "result=SUCCESS" not in ev:
6d01255e 1189 raise Exception("Unexpected result: " + ev)
1c532fd5
JM
1190
1191def test_gas_anqp_extra_elements(dev, apdev):
1192 """GAS/ANQP and extra ANQP elements"""
1193 geo_loc = "001052834d12efd2b08b9b4bf1cc2c00004104050000000000060100"
1194 civic_loc = "0000f9555302f50102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5"
47eac38a
JM
1195 held_uri = "https://held.example.com/location"
1196 held = struct.pack('BBB', 0, 1 + len(held_uri), 1) + held_uri
1197 supl_fqdn = "supl.example.com"
1198 supl = struct.pack('BBB', 0, 1 + len(supl_fqdn), 1) + supl_fqdn
7ab74770 1199 public_id = binascii.hexlify(held + supl).decode()
1c532fd5
JM
1200 params = { "ssid": "gas/anqp",
1201 "interworking": "1",
1202 "anqp_elem": [ "265:" + geo_loc,
1203 "266:" + civic_loc,
1204 "262:1122334455",
47eac38a 1205 "267:" + public_id,
1a4b4c84 1206 "279:01020304",
1c532fd5
JM
1207 "60000:01",
1208 "299:0102" ] }
8b8a1864 1209 hapd = hostapd.add_ap(apdev[0], params)
1c532fd5
JM
1210 bssid = apdev[0]['bssid']
1211
1212 dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
1213 if "OK" not in dev[0].request("ANQP_GET " + bssid + " 265,266"):
1214 raise Exception("ANQP_GET command failed")
1215
1216 ev = dev[0].wait_event(["GAS-QUERY-DONE"], timeout=10)
1217 if ev is None:
1218 raise Exception("GAS query timed out")
1219
1220 bss = dev[0].get_bss(bssid)
1221
1222 if 'anqp[265]' not in bss:
1223 raise Exception("AP Geospatial Location ANQP-element not seen")
1224 if bss['anqp[265]'] != geo_loc:
1225 raise Exception("Unexpected AP Geospatial Location ANQP-element value: " + bss['anqp[265]'])
1226
1227 if 'anqp[266]' not in bss:
1228 raise Exception("AP Civic Location ANQP-element not seen")
1229 if bss['anqp[266]'] != civic_loc:
1230 raise Exception("Unexpected AP Civic Location ANQP-element value: " + bss['anqp[266]'])
1231
1232 dev[1].scan_for_bss(bssid, freq="2412", force_scan=True)
1233 if "OK" not in dev[1].request("ANQP_GET " + bssid + " 257,258,259,260,261,262,263,264,265,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299"):
1234 raise Exception("ANQP_GET command failed")
1235
1236 ev = dev[1].wait_event(["GAS-QUERY-DONE"], timeout=10)
1237 if ev is None:
1238 raise Exception("GAS query timed out")
1239
1240 bss = dev[1].get_bss(bssid)
1241
1242 if 'anqp[265]' not in bss:
1243 raise Exception("AP Geospatial Location ANQP-element not seen")
1244 if bss['anqp[265]'] != geo_loc:
1245 raise Exception("Unexpected AP Geospatial Location ANQP-element value: " + bss['anqp[265]'])
1246
1247 if 'anqp[266]' in bss:
1248 raise Exception("AP Civic Location ANQP-element unexpectedly seen")
1249
47eac38a
JM
1250 if 'anqp[267]' not in bss:
1251 raise Exception("AP Location Public Identifier ANQP-element not seen")
1252 if bss['anqp[267]'] != public_id:
1253 raise Exception("Unexpected AP Location Public Identifier ANQP-element value: " + bss['anqp[267]'])
1254
1a4b4c84
JM
1255 if 'anqp[279]' not in bss:
1256 raise Exception("ANQP-element Info ID 279 not seen")
1257 if bss['anqp[279]'] != "01020304":
1258 raise Exception("Unexpected AP ANQP-element Info ID 279 value: " + bss['anqp[279]'])
1c532fd5
JM
1259
1260 if 'anqp[299]' not in bss:
1261 raise Exception("ANQP-element Info ID 299 not seen")
1262 if bss['anqp[299]'] != "0102":
1263 raise Exception("Unexpected AP ANQP-element Info ID 299 value: " + bss['anqp[299]'])
1264
1265 if 'anqp_ip_addr_type_availability' not in bss:
1266 raise Exception("ANQP-element Info ID 292 not seen")
1267 if bss['anqp_ip_addr_type_availability'] != "1122334455":
1268 raise Exception("Unexpected AP ANQP-element Info ID 262 value: " + bss['anqp_ip_addr_type_availability'])
61854f16
JM
1269
1270def test_gas_anqp_address3_not_assoc(dev, apdev, params):
1271 """GAS/ANQP query using IEEE 802.11 compliant Address 3 value when not associated"""
1272 try:
1273 _test_gas_anqp_address3_not_assoc(dev, apdev, params)
1274 finally:
1275 dev[0].request("SET gas_address3 0")
1276
1277def _test_gas_anqp_address3_not_assoc(dev, apdev, params):
1278 hapd = start_ap(apdev[0])
1279 bssid = apdev[0]['bssid']
1280
1281 if "OK" not in dev[0].request("SET gas_address3 1"):
1282 raise Exception("Failed to set gas_address3")
1283
1284 dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
1285 if "OK" not in dev[0].request("ANQP_GET " + bssid + " 258"):
1286 raise Exception("ANQP_GET command failed")
1287
1288 ev = dev[0].wait_event(["GAS-QUERY-START"], timeout=5)
1289 if ev is None:
1290 raise Exception("GAS query start timed out")
1291
1292 ev = dev[0].wait_event(["GAS-QUERY-DONE"], timeout=10)
1293 if ev is None:
1294 raise Exception("GAS query timed out")
1295
1296 ev = dev[0].wait_event(["RX-ANQP"], timeout=1)
1297 if ev is None or "Venue Name" not in ev:
1298 raise Exception("Did not receive Venue Name")
1299
1300 ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=10)
1301 if ev is None:
1302 raise Exception("ANQP-QUERY-DONE event not seen")
1303 if "result=SUCCESS" not in ev:
1304 raise Exception("Unexpected result: " + ev)
1305
1306 out = run_tshark(os.path.join(params['logdir'], "hwsim0.pcapng"),
1307 "wlan_mgt.fixed.category_code == 4 && (wlan_mgt.fixed.publicact == 0x0a || wlan_mgt.fixed.publicact == 0x0b)",
1308 display=["wlan.bssid"])
1309 res = out.splitlines()
1310 if len(res) != 2:
1311 raise Exception("Unexpected number of GAS frames")
1312 if res[0] != 'ff:ff:ff:ff:ff:ff':
1313 raise Exception("GAS request used unexpected Address3 field value: " + res[0])
1314 if res[1] != 'ff:ff:ff:ff:ff:ff':
1315 raise Exception("GAS response used unexpected Address3 field value: " + res[1])
1316
1317def test_gas_anqp_address3_assoc(dev, apdev, params):
1318 """GAS/ANQP query using IEEE 802.11 compliant Address 3 value when associated"""
1319 try:
1320 _test_gas_anqp_address3_assoc(dev, apdev, params)
1321 finally:
1322 dev[0].request("SET gas_address3 0")
1323
1324def _test_gas_anqp_address3_assoc(dev, apdev, params):
1325 hapd = start_ap(apdev[0])
1326 bssid = apdev[0]['bssid']
1327
1328 if "OK" not in dev[0].request("SET gas_address3 1"):
1329 raise Exception("Failed to set gas_address3")
1330
1331 dev[0].scan_for_bss(bssid, freq="2412")
1332 dev[0].connect("test-gas", key_mgmt="WPA-EAP", eap="TTLS",
1333 identity="DOMAIN\mschapv2 user", anonymous_identity="ttls",
1334 password="password", phase2="auth=MSCHAPV2",
1335 ca_cert="auth_serv/ca.pem", scan_freq="2412")
1336
1337 if "OK" not in dev[0].request("ANQP_GET " + bssid + " 258"):
1338 raise Exception("ANQP_GET command failed")
1339
1340 ev = dev[0].wait_event(["GAS-QUERY-START"], timeout=5)
1341 if ev is None:
1342 raise Exception("GAS query start timed out")
1343
1344 ev = dev[0].wait_event(["GAS-QUERY-DONE"], timeout=10)
1345 if ev is None:
1346 raise Exception("GAS query timed out")
1347
1348 ev = dev[0].wait_event(["RX-ANQP"], timeout=1)
1349 if ev is None or "Venue Name" not in ev:
1350 raise Exception("Did not receive Venue Name")
1351
1352 ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=10)
1353 if ev is None:
1354 raise Exception("ANQP-QUERY-DONE event not seen")
1355 if "result=SUCCESS" not in ev:
1356 raise Exception("Unexpected result: " + ev)
1357
1358 out = run_tshark(os.path.join(params['logdir'], "hwsim0.pcapng"),
1359 "wlan_mgt.fixed.category_code == 4 && (wlan_mgt.fixed.publicact == 0x0a || wlan_mgt.fixed.publicact == 0x0b)",
1360 display=["wlan.bssid"])
1361 res = out.splitlines()
1362 if len(res) != 2:
1363 raise Exception("Unexpected number of GAS frames")
1364 if res[0] != bssid:
1365 raise Exception("GAS request used unexpected Address3 field value: " + res[0])
1366 if res[1] != bssid:
1367 raise Exception("GAS response used unexpected Address3 field value: " + res[1])
1368
1369def test_gas_anqp_address3_ap_forced(dev, apdev, params):
1370 """GAS/ANQP query using IEEE 802.11 compliant Address 3 value on AP"""
1371 hapd = start_ap(apdev[0])
1372 bssid = apdev[0]['bssid']
1373 hapd.set("gas_address3", "1")
1374
1375 dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
1376 if "OK" not in dev[0].request("ANQP_GET " + bssid + " 258"):
1377 raise Exception("ANQP_GET command failed")
1378
1379 ev = dev[0].wait_event(["GAS-QUERY-START"], timeout=5)
1380 if ev is None:
1381 raise Exception("GAS query start timed out")
1382
1383 ev = dev[0].wait_event(["GAS-QUERY-DONE"], timeout=10)
1384 if ev is None:
1385 raise Exception("GAS query timed out")
1386
1387 ev = dev[0].wait_event(["RX-ANQP"], timeout=1)
1388 if ev is None or "Venue Name" not in ev:
1389 raise Exception("Did not receive Venue Name")
1390
1391 ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=10)
1392 if ev is None:
1393 raise Exception("ANQP-QUERY-DONE event not seen")
1394 if "result=SUCCESS" not in ev:
1395 raise Exception("Unexpected result: " + ev)
1396
1397 out = run_tshark(os.path.join(params['logdir'], "hwsim0.pcapng"),
1398 "wlan_mgt.fixed.category_code == 4 && (wlan_mgt.fixed.publicact == 0x0a || wlan_mgt.fixed.publicact == 0x0b)",
1399 display=["wlan.bssid"])
1400 res = out.splitlines()
1401 if len(res) != 2:
1402 raise Exception("Unexpected number of GAS frames")
1403 if res[0] != bssid:
1404 raise Exception("GAS request used unexpected Address3 field value: " + res[0])
1405 if res[1] != 'ff:ff:ff:ff:ff:ff':
1406 raise Exception("GAS response used unexpected Address3 field value: " + res[1])
1407
1408def test_gas_anqp_address3_ap_non_compliant(dev, apdev, params):
1409 """GAS/ANQP query using IEEE 802.11 non-compliant Address 3 (AP)"""
1410 try:
1411 _test_gas_anqp_address3_ap_non_compliant(dev, apdev, params)
1412 finally:
1413 dev[0].request("SET gas_address3 0")
1414
1415def _test_gas_anqp_address3_ap_non_compliant(dev, apdev, params):
1416 hapd = start_ap(apdev[0])
1417 bssid = apdev[0]['bssid']
1418 hapd.set("gas_address3", "2")
1419
1420 if "OK" not in dev[0].request("SET gas_address3 1"):
1421 raise Exception("Failed to set gas_address3")
1422
1423 dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
1424 if "OK" not in dev[0].request("ANQP_GET " + bssid + " 258"):
1425 raise Exception("ANQP_GET command failed")
1426
1427 ev = dev[0].wait_event(["GAS-QUERY-START"], timeout=5)
1428 if ev is None:
1429 raise Exception("GAS query start timed out")
1430
1431 ev = dev[0].wait_event(["GAS-QUERY-DONE"], timeout=10)
1432 if ev is None:
1433 raise Exception("GAS query timed out")
1434
1435 ev = dev[0].wait_event(["RX-ANQP"], timeout=1)
1436 if ev is None or "Venue Name" not in ev:
1437 raise Exception("Did not receive Venue Name")
1438
1439 ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=10)
1440 if ev is None:
1441 raise Exception("ANQP-QUERY-DONE event not seen")
1442 if "result=SUCCESS" not in ev:
1443 raise Exception("Unexpected result: " + ev)
1444
1445 out = run_tshark(os.path.join(params['logdir'], "hwsim0.pcapng"),
1446 "wlan_mgt.fixed.category_code == 4 && (wlan_mgt.fixed.publicact == 0x0a || wlan_mgt.fixed.publicact == 0x0b)",
1447 display=["wlan.bssid"])
1448 res = out.splitlines()
1449 if len(res) != 2:
1450 raise Exception("Unexpected number of GAS frames")
1451 if res[0] != 'ff:ff:ff:ff:ff:ff':
1452 raise Exception("GAS request used unexpected Address3 field value: " + res[0])
1453 if res[1] != bssid:
1454 raise Exception("GAS response used unexpected Address3 field value: " + res[1])
37a67659 1455
008aa15a
JM
1456def test_gas_anqp_address3_pmf(dev, apdev):
1457 """GAS/ANQP query using IEEE 802.11 compliant Address 3 value with PMF"""
1458 try:
1459 _test_gas_anqp_address3_pmf(dev, apdev)
1460 finally:
1461 dev[0].request("SET gas_address3 0")
1462
1463def _test_gas_anqp_address3_pmf(dev, apdev):
1464 hapd = start_ap(apdev[0])
1465 bssid = apdev[0]['bssid']
1466 hapd.set("gas_comeback_delay", "2")
1467 hapd.set("gas_address3", "1")
1468
1469 if "OK" not in dev[0].request("SET gas_address3 1"):
1470 raise Exception("Failed to set gas_address3")
1471
1472 dev[0].scan_for_bss(bssid, freq="2412")
1473 dev[0].connect("test-gas", key_mgmt="WPA-EAP", eap="TTLS",
1474 identity="DOMAIN\mschapv2 user", anonymous_identity="ttls",
1475 password="password", phase2="auth=MSCHAPV2",
1476 ca_cert="auth_serv/ca.pem", scan_freq="2412",
1477 ieee80211w="2")
1478
1479 if "OK" not in dev[0].request("ANQP_GET " + bssid + " 258"):
1480 raise Exception("ANQP_GET command failed")
1481
1482 ev = dev[0].wait_event(["GAS-QUERY-START"], timeout=5)
1483 if ev is None:
1484 raise Exception("GAS query start timed out")
1485
1486 ev = dev[0].wait_event(["GAS-QUERY-DONE"], timeout=10)
1487 if ev is None:
1488 raise Exception("GAS query timed out")
1489
1490 ev = dev[0].wait_event(["RX-ANQP"], timeout=1)
1491 if ev is None or "Venue Name" not in ev:
1492 raise Exception("Did not receive Venue Name")
1493
1494 ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=10)
1495 if ev is None:
1496 raise Exception("ANQP-QUERY-DONE event not seen")
1497 if "result=SUCCESS" not in ev:
1498 raise Exception("Unexpected result: " + ev)
1499
1500 req = dev[0].request("GAS_REQUEST " + bssid + " 42 000102000101")
1501 if "FAIL" in req:
1502 raise Exception("GAS query request rejected")
1503 expect_gas_result(dev[0], "FAILURE", "59")
1504
37a67659
JM
1505def test_gas_prot_vs_not_prot(dev, apdev, params):
1506 """GAS/ANQP query protected vs. not protected"""
1507 hapd = start_ap(apdev[0])
1508 bssid = apdev[0]['bssid']
1509
1510 dev[0].scan_for_bss(bssid, freq="2412")
1511 dev[0].connect("test-gas", key_mgmt="WPA-EAP", eap="TTLS",
1512 identity="DOMAIN\mschapv2 user", anonymous_identity="ttls",
1513 password="password", phase2="auth=MSCHAPV2",
1514 ca_cert="auth_serv/ca.pem", scan_freq="2412",
1515 ieee80211w="2")
1516
1517 if "OK" not in dev[0].request("ANQP_GET " + bssid + " 258"):
1518 raise Exception("ANQP_GET command failed")
1519
1520 ev = dev[0].wait_event(["GAS-QUERY-DONE"], timeout=5)
1521 if ev is None:
1522 raise Exception("No GAS-QUERY-DONE event")
1523 if "result=SUCCESS" not in ev:
1524 raise Exception("Unexpected GAS result: " + ev)
1525
1526 # GAS: Drop unexpected unprotected GAS frame when PMF is enabled
1527 dev[0].request("SET ext_mgmt_frame_handling 1")
1528 res = dev[0].request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=d0003a010200000000000200000003000200000003001000040b00000005006c027f000000")
1529 dev[0].request("SET ext_mgmt_frame_handling 0")
1530 if "OK" not in res:
1531 raise Exception("MGMT_RX_PROCESS failed")
1532
1533 dev[0].request("DISCONNECT")
1534 dev[0].wait_disconnected()
1535
1536 # GAS: No pending query found for 02:00:00:00:03:00 dialog token 0
1537 dev[0].request("SET ext_mgmt_frame_handling 1")
1538 res = dev[0].request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=d0003a010200000000000200000003000200000003001000040b00000005006c027f000000")
1539 dev[0].request("SET ext_mgmt_frame_handling 0")
1540 if "OK" not in res:
1541 raise Exception("MGMT_RX_PROCESS failed")
1542
1543 # GAS: Drop unexpected protected GAS frame when PMF is disabled
1544 dev[0].request("SET ext_mgmt_frame_handling 1")
1545 res = dev[0].request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=d0003a010200000000000200000003000200000003001000090b00000005006c027f000000")
1546 dev[0].request("SET ext_mgmt_frame_handling 0")
1547 if "OK" not in res:
1548 raise Exception("MGMT_RX_PROCESS failed")
643be15d
JM
1549
1550def test_gas_failures(dev, apdev):
1551 """GAS failure cases"""
1552 hapd = start_ap(apdev[0])
1553 hapd.set("gas_comeback_delay", "5")
1554 bssid = apdev[0]['bssid']
1555
1556 hapd2 = start_ap(apdev[1])
1557 bssid2 = apdev[1]['bssid']
1558
1559 dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
1560 dev[0].scan_for_bss(bssid2, freq="2412")
1561
1562 tests = [ (bssid, "gas_build_req;gas_query_tx_comeback_req"),
1563 (bssid, "gas_query_tx;gas_query_tx_comeback_req"),
1564 (bssid, "gas_query_append;gas_query_rx_comeback"),
1565 (bssid2, "gas_query_append;gas_query_rx_initial"),
1566 (bssid2, "wpabuf_alloc_copy;gas_query_rx_initial"),
1567 (bssid, "gas_query_tx;gas_query_tx_initial_req") ]
1568 for addr,func in tests:
1569 with alloc_fail(dev[0], 1, func):
1570 dev[0].request("ANQP_GET " + addr + " 258")
1571 ev = dev[0].wait_event(["GAS-QUERY-DONE"], timeout=5)
1572 if ev is None:
1573 raise Exception("No GAS-QUERY-DONE seen")
1574 if "result=INTERNAL_ERROR" not in ev:
1575 raise Exception("Unexpected result code: " + ev)
1576 dev[0].dump_monitor()
1577
1578 tests = [ "=gas_query_req", "radio_add_work;gas_query_req" ]
1579 for func in tests:
1580 with alloc_fail(dev[0], 1, func):
1581 if "FAIL" not in dev[0].request("ANQP_GET " + bssid + " 258"):
1582 raise Exception("ANQP_GET succeeded unexpectedly during OOM")
1583 dev[0].dump_monitor()
1584
1585 wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
1586 wpas.interface_add("wlan5")
1587 wpas.scan_for_bss(bssid2, freq="2412")
1588 wpas.request("SET preassoc_mac_addr 1111")
1589 wpas.request("ANQP_GET " + bssid2 + " 258")
1590 ev = wpas.wait_event(["Failed to assign random MAC address for GAS"],
1591 timeout=5)
1592 wpas.request("SET preassoc_mac_addr 0")
1593 if ev is None:
1594 raise Exception("No random MAC address error seen")
8e5c2c20
JM
1595
1596def test_gas_anqp_venue_url(dev, apdev):
1597 """GAS/ANQP and Venue URL"""
1598 venue_group = 1
1599 venue_type = 13
1600 venue_info = struct.pack('BB', venue_group, venue_type)
1601 lang1 = "eng"
1602 name1= "Example venue"
1603 lang2 = "fin"
1604 name2 = "Esimerkkipaikka"
1605 venue1 = struct.pack('B', len(lang1 + name1)) + lang1 + name1
1606 venue2 = struct.pack('B', len(lang2 + name2)) + lang2 + name2
7ab74770 1607 venue_name = binascii.hexlify(venue_info + venue1 + venue2).decode()
8e5c2c20
JM
1608
1609 url1 = "http://example.com/venue"
1610 url2 = "https://example.org/venue-info/"
f68caa35
JM
1611 duple1 = struct.pack('BB', 1 + len(url1), 1) + url1
1612 duple2 = struct.pack('BB', 1 + len(url2), 2) + url2
7ab74770 1613 venue_url = binascii.hexlify(duple1 + duple2).decode()
8e5c2c20
JM
1614
1615 params = { "ssid": "gas/anqp",
1616 "interworking": "1",
1617 "venue_group": str(venue_group),
1618 "venue_type": str(venue_type),
1619 "venue_name": [ lang1 + ":" + name1, lang2 + ":" + name2 ],
1620 "anqp_elem": [ "277:" + venue_url ] }
1621 hapd = hostapd.add_ap(apdev[0], params)
1622 bssid = apdev[0]['bssid']
1623
1624 dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
1625 if "OK" not in dev[0].request("ANQP_GET " + bssid + " 257,258,277"):
1626 raise Exception("ANQP_GET command failed")
1627
1628 ev = dev[0].wait_event(["GAS-QUERY-DONE"], timeout=10)
1629 if ev is None:
1630 raise Exception("GAS query timed out")
1631
bb2c25d0
JM
1632 ev = dev[0].wait_event(["RX-VENUE-URL"], timeout=0.1)
1633 if ev is not None:
1634 raise Exception("Unexpected Venue URL indication without PMF")
1635
8e5c2c20
JM
1636 bss = dev[0].get_bss(bssid)
1637
1638 if 'anqp_venue_name' not in bss:
1639 raise Exception("Venue Name ANQP-element not seen")
1640 if bss['anqp_venue_name'] != venue_name:
1641 raise Exception("Unexpected Venue Name ANQP-element value: " + bss['anqp_venue_name'])
1642 if 'anqp[277]' not in bss:
1643 raise Exception("Venue URL ANQP-element not seen")
1644 if bss['anqp[277]'] != venue_url:
1645 raise Exception("Unexpected Venue URL ANQP-element value: " + bss['anqp[277]'])
1646
1647 if 'anqp_capability_list' not in bss:
1648 raise Exception("Capability List ANQP-element not seen")
1649 ids = struct.pack('<HHH', 257, 258, 277)
7ab74770 1650 if not bss['anqp_capability_list'].startswith(binascii.hexlify(ids).decode()):
8e5c2c20 1651 raise Exception("Unexpected Capability List ANQP-element value: " + bss['anqp_capability_list'])
f68caa35
JM
1652
1653def test_gas_anqp_venue_url2(dev, apdev):
1654 """GAS/ANQP and Venue URL (hostapd venue_url)"""
1655 venue_group = 1
1656 venue_type = 13
1657 venue_info = struct.pack('BB', venue_group, venue_type)
1658 lang1 = "eng"
1659 name1= "Example venue"
1660 lang2 = "fin"
1661 name2 = "Esimerkkipaikka"
1662 venue1 = struct.pack('B', len(lang1 + name1)) + lang1 + name1
1663 venue2 = struct.pack('B', len(lang2 + name2)) + lang2 + name2
7ab74770 1664 venue_name = binascii.hexlify(venue_info + venue1 + venue2).decode()
f68caa35
JM
1665
1666 url1 = "http://example.com/venue"
1667 url2 = "https://example.org/venue-info/"
1668 duple1 = struct.pack('BB', 1 + len(url1), 1) + url1
1669 duple2 = struct.pack('BB', 1 + len(url2), 2) + url2
7ab74770 1670 venue_url = binascii.hexlify(duple1 + duple2).decode()
f68caa35
JM
1671
1672 params = { "ssid": "gas/anqp",
1673 "interworking": "1",
1674 "venue_group": str(venue_group),
1675 "venue_type": str(venue_type),
1676 "venue_name": [ lang1 + ":" + name1, lang2 + ":" + name2 ],
1677 "venue_url": [ "1:" + url1, "2:" + url2 ] }
1678 hapd = hostapd.add_ap(apdev[0], params)
1679 bssid = apdev[0]['bssid']
1680
1681 dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
1682 if "OK" not in dev[0].request("ANQP_GET " + bssid + " 257,258,277"):
1683 raise Exception("ANQP_GET command failed")
1684
1685 ev = dev[0].wait_event(["GAS-QUERY-DONE"], timeout=10)
1686 if ev is None:
1687 raise Exception("GAS query timed out")
1688
1689 bss = dev[0].get_bss(bssid)
1690
1691 if 'anqp_venue_name' not in bss:
1692 raise Exception("Venue Name ANQP-element not seen")
1693 if bss['anqp_venue_name'] != venue_name:
1694 raise Exception("Unexpected Venue Name ANQP-element value: " + bss['anqp_venue_name'])
1695 if 'anqp[277]' not in bss:
1696 raise Exception("Venue URL ANQP-element not seen")
1697 if bss['anqp[277]'] != venue_url:
89896c00 1698 print(venue_url)
f68caa35
JM
1699 raise Exception("Unexpected Venue URL ANQP-element value: " + bss['anqp[277]'])
1700
1701 if 'anqp_capability_list' not in bss:
1702 raise Exception("Capability List ANQP-element not seen")
1703 ids = struct.pack('<HHH', 257, 258, 277)
7ab74770 1704 if not bss['anqp_capability_list'].startswith(binascii.hexlify(ids).decode()):
f68caa35 1705 raise Exception("Unexpected Capability List ANQP-element value: " + bss['anqp_capability_list'])
242fc738 1706
bb2c25d0
JM
1707def test_gas_anqp_venue_url_pmf(dev, apdev):
1708 """GAS/ANQP and Venue URL with PMF"""
1709 venue_group = 1
1710 venue_type = 13
1711 venue_info = struct.pack('BB', venue_group, venue_type)
1712 lang1 = "eng"
1713 name1= "Example venue"
1714 lang2 = "fin"
1715 name2 = "Esimerkkipaikka"
1716 venue1 = struct.pack('B', len(lang1 + name1)) + lang1 + name1
1717 venue2 = struct.pack('B', len(lang2 + name2)) + lang2 + name2
1718 venue_name = binascii.hexlify(venue_info + venue1 + venue2)
1719
1720 url1 = "http://example.com/venue"
1721 url2 = "https://example.org/venue-info/"
1722
1723 params = { "ssid": "gas/anqp/pmf",
1724 "wpa": "2",
1725 "wpa_key_mgmt": "WPA-PSK",
1726 "rsn_pairwise": "CCMP",
1727 "wpa_passphrase": "12345678",
1728 "ieee80211w": "2",
1729 "interworking": "1",
1730 "venue_group": str(venue_group),
1731 "venue_type": str(venue_type),
1732 "venue_name": [ lang1 + ":" + name1, lang2 + ":" + name2 ],
1733 "venue_url": [ "1:" + url1, "2:" + url2 ] }
1734 hapd = hostapd.add_ap(apdev[0], params)
1735 bssid = apdev[0]['bssid']
1736
1737 dev[0].connect("gas/anqp/pmf", psk="12345678", ieee80211w="2",
1738 scan_freq="2412")
1739 if "OK" not in dev[0].request("ANQP_GET " + bssid + " 277"):
1740 raise Exception("ANQP_GET command failed")
1741
1742 ev = dev[0].wait_event(["GAS-QUERY-DONE"], timeout=10)
1743 if ev is None:
1744 raise Exception("GAS query timed out")
1745
1746 ev = dev[0].wait_event(["RX-VENUE-URL"], timeout=5)
1747 if ev is None:
1748 raise Exception("No Venue URL indication seen")
1749 if "1 " + url1 not in ev:
1750 raise Exception("Unexpected Venue URL information: " + ev)
1751
1752 ev = dev[0].wait_event(["RX-VENUE-URL"], timeout=5)
1753 if ev is None:
1754 raise Exception("No Venue URL indication seen (2)")
1755 if "2 " + url2 not in ev:
1756 raise Exception("Unexpected Venue URL information (2): " + ev)
1757
242fc738
JM
1758def test_gas_anqp_capab_list(dev, apdev):
1759 """GAS/ANQP and Capability List ANQP-element"""
1760 params = { "ssid": "gas/anqp",
1761 "interworking": "1" }
1762 params["anqp_elem"] = []
1763 for i in range(0, 400):
1764 if i not in [ 257 ]:
1765 params["anqp_elem"] += [ "%d:010203" % i ]
1766 hapd = hostapd.add_ap(apdev[0], params)
1767 bssid = apdev[0]['bssid']
1768
1769 dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
1770 if "OK" not in dev[0].request("ANQP_GET " + bssid + " 257"):
1771 raise Exception("ANQP_GET command failed")
1772
1773 ev = dev[0].wait_event(["GAS-QUERY-DONE"], timeout=10)
1774 if ev is None:
1775 raise Exception("GAS query timed out")
1776
1777 bss = dev[0].get_bss(bssid)
1778
1779 if 'anqp_capability_list' not in bss:
1780 raise Exception("Capability List ANQP-element not seen")
1781 val = bss['anqp_capability_list']
1782 logger.info("anqp_capability_list: " + val)
1783 ids = []
1784 while len(val) >= 4:
1785 id_bin = binascii.unhexlify(val[0:4])
1786 id = struct.unpack('<H', id_bin)[0]
1787 if id == 0xdddd:
1788 break
1789 ids.append(id)
1790 val = val[4:]
1791 logger.info("InfoIDs: " + str(ids))
1792 for i in range(257, 300):
1a4b4c84
JM
1793 if i in [ 273, 274 ]:
1794 continue
242fc738
JM
1795 if i not in ids:
1796 raise Exception("Unexpected Capability List ANQP-element value (missing %d): %s" % (i, bss['anqp_capability_list']))
008aa15a
JM
1797
1798def test_gas_server_oom(dev, apdev):
1799 """GAS server OOM"""
1800 bssid = apdev[0]['bssid']
1801 params = hs20_ap_params()
1802 params['hessid'] = bssid
1803 params['gas_comeback_delay'] = "5"
1804 hapd = hostapd.add_ap(apdev[0], params)
1805
1806 dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
1807
1808 tests = [ "ap_sta_add;gas_dialog_create",
1809 "=gas_dialog_create",
1810 "wpabuf_alloc_copy;gas_serv_rx_gas_comeback_req" ]
1811 for t in tests:
1812 with alloc_fail(hapd, 1, t):
1813 if "OK" not in dev[0].request("ANQP_GET " + bssid + " 258"):
1814 raise Exception("ANQP_GET command failed")
1815 ev = dev[0].wait_event(["GAS-QUERY-DONE"], timeout=5)
1816 if ev is None:
1817 raise Exception("No GAS-QUERY-DONE seen")
1818 dev[0].dump_monitor()
1819
1820 hapd.set("gas_comeback_delay", "0")
1821
1822 tests = [ "gas_serv_build_gas_resp_payload" ]
1823 for t in tests:
1824 with alloc_fail(hapd, 1, t):
1825 if "OK" not in dev[0].request("ANQP_GET " + bssid + " 258"):
1826 raise Exception("ANQP_GET command failed")
1827 ev = dev[0].wait_event(["GAS-QUERY-DONE"], timeout=5)
1828 if ev is None:
1829 raise Exception("No GAS-QUERY-DONE seen")
1830 dev[0].dump_monitor()
1831
1832 with alloc_fail(hapd, 1,
1833 "gas_build_initial_resp;gas_serv_rx_gas_initial_req"):
1834 req = dev[0].request("GAS_REQUEST " + bssid + " 42 000102000101")
1835 if "FAIL" in req:
1836 raise Exception("GAS query request rejected")
1837 ev = dev[0].wait_event(["GAS-QUERY-DONE"], timeout=5)
1838 if ev is None:
1839 raise Exception("No GAS-QUERY-DONE seen")
1840 dev[0].dump_monitor()
1841
1842 wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
1843 wpas.interface_add("wlan5")
1844 if "OK" not in wpas.request("P2P_SET listen_channel 1"):
1845 raise Exception("Failed to set listen channel")
1846 if "OK" not in wpas.p2p_listen():
1847 raise Exception("Failed to start listen state")
1848 if "FAIL" in wpas.request("SET ext_mgmt_frame_handling 1"):
1849 raise Exception("Failed to enable external management frame handling")
1850
1851 msg = struct.pack('<BBB', ACTION_CATEG_PUBLIC, GAS_COMEBACK_REQUEST, 1)
7ab74770 1852 req = "MGMT_TX {} {} freq=2412 wait_time=10 action={}".format(bssid, bssid, binascii.hexlify(msg).decode())
008aa15a
JM
1853 with alloc_fail(hapd, 1,
1854 "gas_anqp_build_comeback_resp_buf;gas_serv_rx_gas_comeback_req"):
1855 if "OK" not in wpas.request(req):
1856 raise Exception("Could not send management frame")
1857 wait_fail_trigger(hapd, "GET_ALLOC_FAIL")
1858
1859def test_gas_anqp_overrides(dev, apdev):
1860 """GAS and ANQP overrides"""
1861 params = { "ssid": "gas/anqp",
1862 "interworking": "1",
1863 "anqp_elem": [ "257:111111",
1864 "258:222222",
1865 "260:333333",
1866 "261:444444",
1867 "262:555555",
1868 "263:666666",
1869 "264:777777",
1870 "268:888888",
1871 "275:999999" ] }
1872 hapd = hostapd.add_ap(apdev[0], params)
1873 bssid = apdev[0]['bssid']
1874
1875 dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
1876 if "OK" not in dev[0].request("ANQP_GET " + bssid + " 257,258,260,261,262,263,264,268,275"):
1877 raise Exception("ANQP_GET command failed")
1878
1879 ev = dev[0].wait_event(["GAS-QUERY-DONE"], timeout=10)
1880 if ev is None:
1881 raise Exception("GAS query timed out")
de5ca36e
JM
1882 elems = 9
1883 capa = dev[0].get_capability("fils")
1884 if capa is None or "FILS" not in capa:
1885 # FILS Realm Info not supported in the build
1886 elems -= 1
1887 for i in range(elems):
008aa15a
JM
1888 ev = dev[0].wait_event(["RX-ANQP"], timeout=5)
1889 if ev is None:
1890 raise Exception("ANQP response not seen")
1891
1892def test_gas_no_dialog_token_match(dev, apdev):
1893 """GAS and no dialog token match for comeback request"""
1894 hapd = start_ap(apdev[0])
1895 hapd.set("gas_frag_limit", "50")
1896 bssid = apdev[0]['bssid']
1897
1898 wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
1899 wpas.interface_add("wlan5")
1900 if "OK" not in wpas.request("P2P_SET listen_channel 1"):
1901 raise Exception("Failed to set listen channel")
1902 if "OK" not in wpas.p2p_listen():
1903 raise Exception("Failed to start listen state")
1904 if "FAIL" in wpas.request("SET ext_mgmt_frame_handling 1"):
1905 raise Exception("Failed to enable external management frame handling")
1906
1907 anqp_query = struct.pack('<HHHHHHHHHH', 256, 16, 257, 258, 260, 261, 262, 263, 264, 268)
1908 gas = struct.pack('<H', len(anqp_query)) + anqp_query
1909
1910 dialog_token = 100
1911 msg = struct.pack('<BBB', ACTION_CATEG_PUBLIC, GAS_INITIAL_REQUEST,
1912 dialog_token) + anqp_adv_proto() + gas
7ab74770 1913 req = "MGMT_TX {} {} freq=2412 wait_time=10 action={}".format(bssid, bssid, binascii.hexlify(msg).decode())
008aa15a
JM
1914 if "OK" not in wpas.request(req):
1915 raise Exception("Could not send management frame")
1916 resp = wpas.mgmt_rx()
1917 if resp is None:
1918 raise Exception("MGMT-RX timeout")
1919 if 'payload' not in resp:
1920 raise Exception("Missing payload")
1921 gresp = parse_gas(resp['payload'])
1922 if gresp['dialog_token'] != dialog_token:
1923 raise Exception("Dialog token mismatch")
1924 status_code = gresp['status_code']
1925 if status_code != 0:
1926 raise Exception("Unexpected status code {}".format(status_code))
1927
1928 msg = struct.pack('<BBB', ACTION_CATEG_PUBLIC, GAS_COMEBACK_REQUEST,
1929 dialog_token + 1)
7ab74770 1930 req = "MGMT_TX {} {} freq=2412 wait_time=10 action={}".format(bssid, bssid, binascii.hexlify(msg).decode())
008aa15a
JM
1931 if "OK" not in wpas.request(req):
1932 raise Exception("Could not send management frame")
1933 resp = wpas.mgmt_rx()
1934 if resp is None:
1935 raise Exception("MGMT-RX timeout")
1936 if 'payload' not in resp:
1937 raise Exception("Missing payload")
1938 gresp = parse_gas(resp['payload'])
1939 status_code = gresp['status_code']
1940 if status_code != 60:
1941 raise Exception("Unexpected failure status code {}".format(status_code))
1942
1943def test_gas_vendor_spec_errors(dev, apdev):
1944 """GAS and vendor specific request error cases"""
1945 bssid = apdev[0]['bssid']
1946 params = hs20_ap_params()
1947 params['hessid'] = bssid
1948 params['osu_server_uri'] = "uri"
1949 params['hs20_icon'] = "32:32:eng:image/png:icon32:/tmp/icon32.png"
1950 del params['nai_realm']
1951 hapd = hostapd.add_ap(apdev[0], params)
1952
1953 dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
1954 tests = [ "00 12340000",
1955 "00 dddd0300506fff",
1956 "00 dddd0400506fffff",
1957 "00 dddd0400506f9aff",
1958 "00 dddd0400506f9a11",
1959 "00 dddd0600506f9a11ff00",
1960 "00 dddd0600506f9a110600",
1961 "00 dddd0600506f9a110600",
1962 "00 dddd0700506f9a11060000",
1963 "00 dddd0700506f9a110600ff",
1964 "00 dddd0800506f9a110600ff00",
1965 "00 dddd0900506f9a110600ff0000",
1966 "00 dddd0900506f9a110600ff0001",
1967 "00 dddd0900506f9a110600ffff00",
1968 "00 dddd0a00506f9a110600ff00013b",
1969 "00 dddd0700506f9a110100ff",
1970 "00 dddd0700506f9a11010008",
1971 "00 dddd14",
1972 "00 dddd1400506f9a11" ]
1973 for t in tests:
1974 req = dev[0].request("GAS_REQUEST " + bssid + " " + t)
1975 if "FAIL" in req:
1976 raise Exception("GAS query request rejected")
1977 ev = dev[0].wait_event(["GAS-QUERY-START"], timeout=5)
1978 if ev is None:
1979 raise Exception("GAS query did not start")
1980 ev = dev[0].wait_event(["GAS-QUERY-DONE"], timeout=5)
1981 if ev is None:
1982 raise Exception("GAS query did not complete")
1983 if t == "00 dddd0600506f9a110600":
1984 hapd.set("nai_realm", "0,another.example.com")
1985
1986 wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
1987 wpas.interface_add("wlan5")
1988 if "OK" not in wpas.request("P2P_SET listen_channel 1"):
1989 raise Exception("Failed to set listen channel")
1990 if "OK" not in wpas.p2p_listen():
1991 raise Exception("Failed to start listen state")
1992 if "FAIL" in wpas.request("SET ext_mgmt_frame_handling 1"):
1993 raise Exception("Failed to enable external management frame handling")
1994
1995 anqp_query = struct.pack('<HHHHHHHHHH', 256, 16, 257, 258, 260, 261, 262, 263, 264, 268)
1996 gas = struct.pack('<H', len(anqp_query)) + anqp_query
1997
1998 dialog_token = 100
1999 adv = struct.pack('BBBB', 109, 2, 0, 0)
2000 adv2 = struct.pack('BBB', 108, 1, 0)
2001 adv3 = struct.pack('BBBB', 108, 3, 0, 0)
2002 msg = struct.pack('<BBB', ACTION_CATEG_PUBLIC, GAS_INITIAL_REQUEST,
2003 dialog_token) + adv + gas
2004 msg2 = struct.pack('<BBB', ACTION_CATEG_PUBLIC, GAS_INITIAL_REQUEST,
2005 dialog_token) + adv2 + gas
2006 msg3 = struct.pack('<BBB', ACTION_CATEG_PUBLIC, GAS_INITIAL_REQUEST,
2007 dialog_token) + adv3
2008 msg4 = struct.pack('<BBB', ACTION_CATEG_PUBLIC, GAS_INITIAL_REQUEST,
2009 dialog_token) + anqp_adv_proto()
2010 msg5 = struct.pack('<BBB', ACTION_CATEG_PUBLIC, GAS_INITIAL_REQUEST,
2011 dialog_token) + anqp_adv_proto() + struct.pack('<H', 1)
2012 msg6 = struct.pack('<BB', ACTION_CATEG_PUBLIC, GAS_COMEBACK_REQUEST)
2013 tests = [ msg, msg2, msg3, msg4, msg5, msg6 ]
2014 for t in tests:
7ab74770 2015 req = "MGMT_TX {} {} freq=2412 wait_time=10 action={}".format(bssid, bssid, binascii.hexlify(t).decode())
008aa15a
JM
2016 if "OK" not in wpas.request(req):
2017 raise Exception("Could not send management frame")
2018 ev = wpas.wait_event(["MGMT-TX-STATUS"], timeout=5)
2019 if ev is None:
2020 raise Exception("No ACK frame seen")