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