tests: GAS/ANQP query protected vs. not protected
[mech_eap.git] / tests / hwsim / test_gas.py
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
8 import time
9 import binascii
10 import logging
11 logger = logging.getLogger()
12 import os
13 import re
14 import struct
15
16 import hostapd
17 from wpasupplicant import WpaSupplicant
18 from tshark import run_tshark
19 from utils import alloc_fail, wait_fail_trigger, skip_with_fips
20 from hwsim import HWSimRadio
21
22 def hs20_ap_params():
23     params = hostapd.wpa2_params(ssid="test-gas")
24     params['wpa_key_mgmt'] = "WPA-EAP"
25     params['ieee80211w'] = "1"
26     params['ieee8021x'] = "1"
27     params['auth_server_addr'] = "127.0.0.1"
28     params['auth_server_port'] = "1812"
29     params['auth_server_shared_secret'] = "radius"
30     params['interworking'] = "1"
31     params['access_network_type'] = "14"
32     params['internet'] = "1"
33     params['asra'] = "0"
34     params['esr'] = "0"
35     params['uesa'] = "0"
36     params['venue_group'] = "7"
37     params['venue_type'] = "1"
38     params['venue_name'] = [ "eng:Example venue", "fin:Esimerkkipaikka" ]
39     params['roaming_consortium'] = [ "112233", "1020304050", "010203040506",
40                                      "fedcba" ]
41     params['domain_name'] = "example.com,another.example.com"
42     params['nai_realm'] = [ "0,example.com,13[5:6],21[2:4][5:7]",
43                             "0,another.example.com" ]
44     params['anqp_3gpp_cell_net'] = "244,91"
45     params['network_auth_type'] = "02http://www.example.com/redirect/me/here/"
46     params['ipaddr_type_availability'] = "14"
47     params['hs20'] = "1"
48     params['hs20_oper_friendly_name'] = [ "eng:Example operator", "fin:Esimerkkioperaattori" ]
49     params['hs20_wan_metrics'] = "01:8000:1000:80:240:3000"
50     params['hs20_conn_capab'] = [ "1:0:2", "6:22:1", "17:5060:0" ]
51     params['hs20_operating_class'] = "5173"
52     return params
53
54 def start_ap(ap):
55     params = hs20_ap_params()
56     params['hessid'] = ap['bssid']
57     return hostapd.add_ap(ap, params)
58
59 def get_gas_response(dev, bssid, info, allow_fetch_failure=False,
60                      extra_test=False):
61     exp = r'<.>(GAS-RESPONSE-INFO) addr=([0-9a-f:]*) dialog_token=([0-9]*) status_code=([0-9]*) resp_len=([\-0-9]*)'
62     res = re.split(exp, info)
63     if len(res) < 6:
64         raise Exception("Could not parse GAS-RESPONSE-INFO")
65     if res[2] != bssid:
66         raise Exception("Unexpected BSSID in response")
67     token = res[3]
68     status = res[4]
69     if status != "0":
70         raise Exception("GAS query failed")
71     resp_len = res[5]
72     if resp_len == "-1":
73         raise Exception("GAS query reported invalid response length")
74     if int(resp_len) > 2000:
75         raise Exception("Unexpected long GAS response")
76
77     if extra_test:
78         if "FAIL" not in dev.request("GAS_RESPONSE_GET " + bssid + " 123456"):
79             raise Exception("Invalid dialog token accepted")
80         if "FAIL-Invalid range" not in dev.request("GAS_RESPONSE_GET " + bssid + " " + token + " 10000,10001"):
81             raise Exception("Invalid range accepted")
82         if "FAIL-Invalid range" not in dev.request("GAS_RESPONSE_GET " + bssid + " " + token + " 0,10000"):
83             raise Exception("Invalid range accepted")
84         if "FAIL" not in dev.request("GAS_RESPONSE_GET " + bssid + " " + token + " 0"):
85             raise Exception("Invalid GAS_RESPONSE_GET accepted")
86
87         res1_2 = dev.request("GAS_RESPONSE_GET " + bssid + " " + token + " 1,2")
88         res5_3 = dev.request("GAS_RESPONSE_GET " + bssid + " " + token + " 5,3")
89
90     resp = dev.request("GAS_RESPONSE_GET " + bssid + " " + token)
91     if "FAIL" in resp:
92         if allow_fetch_failure:
93             logger.debug("GAS response was not available anymore")
94             return
95         raise Exception("Could not fetch GAS response")
96     if len(resp) != int(resp_len) * 2:
97         raise Exception("Unexpected GAS response length")
98     logger.debug("GAS response: " + resp)
99     if extra_test:
100         if resp[2:6] != res1_2:
101             raise Exception("Unexpected response substring res1_2: " + res1_2)
102         if resp[10:16] != res5_3:
103             raise Exception("Unexpected response substring res5_3: " + res5_3)
104
105 def test_gas_generic(dev, apdev):
106     """Generic GAS query"""
107     bssid = apdev[0]['bssid']
108     params = hs20_ap_params()
109     params['hessid'] = bssid
110     hostapd.add_ap(apdev[0], params)
111
112     cmds = [ "foo",
113              "00:11:22:33:44:55",
114              "00:11:22:33:44:55 ",
115              "00:11:22:33:44:55  ",
116              "00:11:22:33:44:55 1",
117              "00:11:22:33:44:55 1 1234",
118              "00:11:22:33:44:55 qq",
119              "00:11:22:33:44:55 qq 1234",
120              "00:11:22:33:44:55 00      1",
121              "00:11:22:33:44:55 00 123",
122              "00:11:22:33:44:55 00 ",
123              "00:11:22:33:44:55 00 qq" ]
124     for cmd in cmds:
125         if "FAIL" not in dev[0].request("GAS_REQUEST " + cmd):
126             raise Exception("Invalid GAS_REQUEST accepted: " + cmd)
127
128     dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
129     req = dev[0].request("GAS_REQUEST " + bssid + " 00 000102000101")
130     if "FAIL" in req:
131         raise Exception("GAS query request rejected")
132     ev = dev[0].wait_event(["GAS-RESPONSE-INFO"], timeout=10)
133     if ev is None:
134         raise Exception("GAS query timed out")
135     get_gas_response(dev[0], bssid, ev, extra_test=True)
136
137     if "FAIL" not in dev[0].request("GAS_RESPONSE_GET ff"):
138         raise Exception("Invalid GAS_RESPONSE_GET accepted")
139
140 def test_gas_concurrent_scan(dev, apdev):
141     """Generic GAS queries with concurrent scan operation"""
142     bssid = apdev[0]['bssid']
143     params = hs20_ap_params()
144     params['hessid'] = bssid
145     hostapd.add_ap(apdev[0], params)
146
147     # get BSS entry available to allow GAS query
148     dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
149
150     logger.info("Request concurrent operations")
151     req = dev[0].request("GAS_REQUEST " + bssid + " 00 000102000101")
152     if "FAIL" in req:
153         raise Exception("GAS query request rejected")
154     req = dev[0].request("GAS_REQUEST " + bssid + " 00 000102000801")
155     if "FAIL" in req:
156         raise Exception("GAS query request rejected")
157     dev[0].scan(no_wait=True)
158     req = dev[0].request("GAS_REQUEST " + bssid + " 00 000102000201")
159     if "FAIL" in req:
160         raise Exception("GAS query request rejected")
161     req = dev[0].request("GAS_REQUEST " + bssid + " 00 000102000501")
162     if "FAIL" in req:
163         raise Exception("GAS query request rejected")
164
165     responses = 0
166     for i in range(0, 5):
167         ev = dev[0].wait_event(["GAS-RESPONSE-INFO", "CTRL-EVENT-SCAN-RESULTS"],
168                                timeout=10)
169         if ev is None:
170             raise Exception("Operation timed out")
171         if "GAS-RESPONSE-INFO" in ev:
172             responses = responses + 1
173             get_gas_response(dev[0], bssid, ev, allow_fetch_failure=True)
174
175     if responses != 4:
176         raise Exception("Unexpected number of GAS responses")
177
178 def test_gas_concurrent_connect(dev, apdev):
179     """Generic GAS queries with concurrent connection operation"""
180     skip_with_fips(dev[0])
181     bssid = apdev[0]['bssid']
182     params = hs20_ap_params()
183     params['hessid'] = bssid
184     hostapd.add_ap(apdev[0], params)
185
186     dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
187
188     logger.debug("Start concurrent connect and GAS request")
189     dev[0].connect("test-gas", key_mgmt="WPA-EAP", eap="TTLS",
190                    identity="DOMAIN\mschapv2 user", anonymous_identity="ttls",
191                    password="password", phase2="auth=MSCHAPV2",
192                    ca_cert="auth_serv/ca.pem", wait_connect=False,
193                    scan_freq="2412")
194     req = dev[0].request("GAS_REQUEST " + bssid + " 00 000102000101")
195     if "FAIL" in req:
196         raise Exception("GAS query request rejected")
197
198     ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED", "GAS-RESPONSE-INFO"],
199                            timeout=20)
200     if ev is None:
201         raise Exception("Operation timed out")
202     if "CTRL-EVENT-CONNECTED" not in ev:
203         raise Exception("Unexpected operation order")
204
205     ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED", "GAS-RESPONSE-INFO"],
206                            timeout=20)
207     if ev is None:
208         raise Exception("Operation timed out")
209     if "GAS-RESPONSE-INFO" not in ev:
210         raise Exception("Unexpected operation order")
211     get_gas_response(dev[0], bssid, ev)
212
213     dev[0].request("DISCONNECT")
214     dev[0].wait_disconnected(timeout=5)
215
216     logger.debug("Wait six seconds for expiration of connect-without-scan")
217     time.sleep(6)
218     dev[0].dump_monitor()
219
220     logger.debug("Start concurrent GAS request and connect")
221     req = dev[0].request("GAS_REQUEST " + bssid + " 00 000102000101")
222     if "FAIL" in req:
223         raise Exception("GAS query request rejected")
224     dev[0].request("RECONNECT")
225
226     ev = dev[0].wait_event(["GAS-RESPONSE-INFO"], timeout=10)
227     if ev is None:
228         raise Exception("Operation timed out")
229     get_gas_response(dev[0], bssid, ev)
230
231     ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"], timeout=20)
232     if ev is None:
233         raise Exception("No new scan results reported")
234
235     ev = dev[0].wait_connected(timeout=20, error="Operation tiemd out")
236     if "CTRL-EVENT-CONNECTED" not in ev:
237         raise Exception("Unexpected operation order")
238
239 def gas_fragment_and_comeback(dev, apdev, frag_limit=0, comeback_delay=0):
240     hapd = start_ap(apdev)
241     if frag_limit:
242         hapd.set("gas_frag_limit", str(frag_limit))
243     if comeback_delay:
244         hapd.set("gas_comeback_delay", str(comeback_delay))
245
246     dev.scan_for_bss(apdev['bssid'], freq="2412", force_scan=True)
247     dev.request("FETCH_ANQP")
248     ev = dev.wait_event(["GAS-QUERY-DONE"], timeout=5)
249     if ev is None:
250         raise Exception("No GAS-QUERY-DONE event")
251     if "result=SUCCESS" not in ev:
252         raise Exception("Unexpected GAS result: " + ev)
253     for i in range(0, 13):
254         ev = dev.wait_event(["RX-ANQP", "RX-HS20-ANQP"], timeout=5)
255         if ev is None:
256             raise Exception("Operation timed out")
257     ev = dev.wait_event(["ANQP-QUERY-DONE"], timeout=1)
258     if ev is None:
259         raise Exception("No ANQP-QUERY-DONE event")
260     if "result=SUCCESS" not in ev:
261         raise Exception("Unexpected ANQP result: " + ev)
262
263 def test_gas_fragment(dev, apdev):
264     """GAS fragmentation"""
265     gas_fragment_and_comeback(dev[0], apdev[0], frag_limit=50)
266
267 def test_gas_fragment_mcc(dev, apdev):
268     """GAS fragmentation with mac80211_hwsim MCC enabled"""
269     with HWSimRadio(n_channels=2) as (radio, iface):
270         wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
271         wpas.interface_add(iface)
272         gas_fragment_and_comeback(wpas, apdev[0], frag_limit=50)
273
274 def test_gas_fragment_with_comeback_delay(dev, apdev):
275     """GAS fragmentation and comeback delay"""
276     gas_fragment_and_comeback(dev[0], apdev[0], frag_limit=50,
277                               comeback_delay=500)
278
279 def test_gas_fragment_with_comeback_delay_mcc(dev, apdev):
280     """GAS fragmentation and comeback delay with mac80211_hwsim MCC enabled"""
281     with HWSimRadio(n_channels=2) as (radio, iface):
282         wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
283         wpas.interface_add(iface)
284         gas_fragment_and_comeback(wpas, apdev[0], frag_limit=50,
285                                   comeback_delay=500)
286
287 def test_gas_comeback_delay(dev, apdev):
288     """GAS comeback delay"""
289     hapd = start_ap(apdev[0])
290     hapd.set("gas_comeback_delay", "500")
291
292     dev[0].scan_for_bss(apdev[0]['bssid'], freq="2412", force_scan=True)
293     dev[0].request("FETCH_ANQP")
294     if "FAIL-BUSY" not in dev[0].request("SCAN"):
295         raise Exception("SCAN accepted during FETCH_ANQP")
296     for i in range(0, 6):
297         ev = dev[0].wait_event(["RX-ANQP"], timeout=5)
298         if ev is None:
299             raise Exception("Operation timed out")
300
301 def test_gas_stop_fetch_anqp(dev, apdev):
302     """Stop FETCH_ANQP operation"""
303     hapd = start_ap(apdev[0])
304
305     dev[0].scan_for_bss(apdev[0]['bssid'], freq="2412", force_scan=True)
306     hapd.set("ext_mgmt_frame_handling", "1")
307     dev[0].request("FETCH_ANQP")
308     dev[0].request("STOP_FETCH_ANQP")
309     hapd.set("ext_mgmt_frame_handling", "0")
310     ev = dev[0].wait_event(["RX-ANQP", "GAS-QUERY-DONE"], timeout=10)
311     if ev is None:
312         raise Exception("GAS-QUERY-DONE timed out")
313     if "RX-ANQP" in ev:
314         raise Exception("Unexpected ANQP response received")
315
316 def test_gas_anqp_get(dev, apdev):
317     """GAS/ANQP query for both IEEE 802.11 and Hotspot 2.0 elements"""
318     hapd = start_ap(apdev[0])
319     bssid = apdev[0]['bssid']
320
321     dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
322     if "OK" not in dev[0].request("ANQP_GET " + bssid + " 258,268,hs20:3,hs20:4"):
323         raise Exception("ANQP_GET command failed")
324
325     ev = dev[0].wait_event(["GAS-QUERY-START"], timeout=5)
326     if ev is None:
327         raise Exception("GAS query start timed out")
328
329     ev = dev[0].wait_event(["GAS-QUERY-DONE"], timeout=10)
330     if ev is None:
331         raise Exception("GAS query timed out")
332
333     ev = dev[0].wait_event(["RX-ANQP"], timeout=1)
334     if ev is None or "Venue Name" not in ev:
335         raise Exception("Did not receive Venue Name")
336
337     ev = dev[0].wait_event(["RX-ANQP"], timeout=1)
338     if ev is None or "Domain Name list" not in ev:
339         raise Exception("Did not receive Domain Name list")
340
341     ev = dev[0].wait_event(["RX-HS20-ANQP"], timeout=1)
342     if ev is None or "Operator Friendly Name" not in ev:
343         raise Exception("Did not receive Operator Friendly Name")
344
345     ev = dev[0].wait_event(["RX-HS20-ANQP"], timeout=1)
346     if ev is None or "WAN Metrics" not in ev:
347         raise Exception("Did not receive WAN Metrics")
348
349     ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=10)
350     if ev is None:
351         raise Exception("ANQP-QUERY-DONE event not seen")
352     if "result=SUCCESS" not in ev:
353         raise Exception("Unexpected result: " + ev)
354
355     if "OK" not in dev[0].request("HS20_ANQP_GET " + bssid + " 3,4"):
356         raise Exception("ANQP_GET command failed")
357
358     ev = dev[0].wait_event(["RX-HS20-ANQP"], timeout=1)
359     if ev is None or "Operator Friendly Name" not in ev:
360         raise Exception("Did not receive Operator Friendly Name")
361
362     ev = dev[0].wait_event(["RX-HS20-ANQP"], timeout=1)
363     if ev is None or "WAN Metrics" not in ev:
364         raise Exception("Did not receive WAN Metrics")
365
366     cmds = [ "",
367              "foo",
368              "00:11:22:33:44:55 258,hs20:-1",
369              "00:11:22:33:44:55 258,hs20:0",
370              "00:11:22:33:44:55 258,hs20:32",
371              "00:11:22:33:44:55 hs20:-1",
372              "00:11:22:33:44:55 hs20:0",
373              "00:11:22:33:44:55 hs20:32",
374              "00:11:22:33:44:55",
375              "00:11:22:33:44:55 ",
376              "00:11:22:33:44:55 0" ]
377     for cmd in cmds:
378         if "FAIL" not in dev[0].request("ANQP_GET " + cmd):
379             raise Exception("Invalid ANQP_GET accepted")
380
381     cmds = [ "",
382              "foo",
383              "00:11:22:33:44:55 -1",
384              "00:11:22:33:44:55 0",
385              "00:11:22:33:44:55 32",
386              "00:11:22:33:44:55",
387              "00:11:22:33:44:55 ",
388              "00:11:22:33:44:55 0" ]
389     for cmd in cmds:
390         if "FAIL" not in dev[0].request("HS20_ANQP_GET " + cmd):
391             raise Exception("Invalid HS20_ANQP_GET accepted")
392
393 def expect_gas_result(dev, result, status=None):
394     ev = dev.wait_event(["GAS-QUERY-DONE"], timeout=10)
395     if ev is None:
396         raise Exception("GAS query timed out")
397     if "result=" + result not in ev:
398         raise Exception("Unexpected GAS query result")
399     if status and "status_code=" + str(status) + ' ' not in ev:
400         raise Exception("Unexpected GAS status code")
401
402 def anqp_get(dev, bssid, id):
403     if "OK" not in dev.request("ANQP_GET " + bssid + " " + str(id)):
404         raise Exception("ANQP_GET command failed")
405     ev = dev.wait_event(["GAS-QUERY-START"], timeout=5)
406     if ev is None:
407         raise Exception("GAS query start timed out")
408
409 def test_gas_timeout(dev, apdev):
410     """GAS timeout"""
411     hapd = start_ap(apdev[0])
412     bssid = apdev[0]['bssid']
413
414     dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
415     hapd.set("ext_mgmt_frame_handling", "1")
416
417     anqp_get(dev[0], bssid, 263)
418
419     ev = hapd.wait_event(["MGMT-RX"], timeout=5)
420     if ev is None:
421         raise Exception("MGMT RX wait timed out")
422
423     expect_gas_result(dev[0], "TIMEOUT")
424
425 MGMT_SUBTYPE_ACTION = 13
426 ACTION_CATEG_PUBLIC = 4
427
428 GAS_INITIAL_REQUEST = 10
429 GAS_INITIAL_RESPONSE = 11
430 GAS_COMEBACK_REQUEST = 12
431 GAS_COMEBACK_RESPONSE = 13
432 GAS_ACTIONS = [ GAS_INITIAL_REQUEST, GAS_INITIAL_RESPONSE,
433                 GAS_COMEBACK_REQUEST, GAS_COMEBACK_RESPONSE ]
434
435 def anqp_adv_proto():
436     return struct.pack('BBBB', 108, 2, 127, 0)
437
438 def anqp_initial_resp(dialog_token, status_code, comeback_delay=0):
439     return struct.pack('<BBBHH', ACTION_CATEG_PUBLIC, GAS_INITIAL_RESPONSE,
440                        dialog_token, status_code, comeback_delay) + anqp_adv_proto()
441
442 def anqp_comeback_resp(dialog_token, status_code=0, id=0, more=False, comeback_delay=0, bogus_adv_proto=False):
443     if more:
444         id |= 0x80
445     if bogus_adv_proto:
446         adv = struct.pack('BBBB', 108, 2, 127, 1)
447     else:
448         adv = anqp_adv_proto()
449     return struct.pack('<BBBHBH', ACTION_CATEG_PUBLIC, GAS_COMEBACK_RESPONSE,
450                        dialog_token, status_code, id, comeback_delay) + adv
451
452 def gas_rx(hapd):
453     count = 0
454     while count < 30:
455         count = count + 1
456         query = hapd.mgmt_rx()
457         if query is None:
458             raise Exception("Action frame not received")
459         if query['subtype'] != MGMT_SUBTYPE_ACTION:
460             continue
461         payload = query['payload']
462         if len(payload) < 2:
463             continue
464         (category, action) = struct.unpack('BB', payload[0:2])
465         if category != ACTION_CATEG_PUBLIC or action not in GAS_ACTIONS:
466             continue
467         return query
468     raise Exception("No Action frame received")
469
470 def parse_gas(payload):
471     pos = payload
472     (category, action, dialog_token) = struct.unpack('BBB', pos[0:3])
473     if category != ACTION_CATEG_PUBLIC:
474         return None
475     if action not in GAS_ACTIONS:
476         return None
477     gas = {}
478     gas['action'] = action
479     pos = pos[3:]
480
481     if len(pos) < 1 and action != GAS_COMEBACK_REQUEST:
482         return None
483
484     gas['dialog_token'] = dialog_token
485
486     if action == GAS_INITIAL_RESPONSE:
487         if len(pos) < 4:
488             return None
489         (status_code, comeback_delay) = struct.unpack('<HH', pos[0:4])
490         gas['status_code'] = status_code
491         gas['comeback_delay'] = comeback_delay
492
493     if action == GAS_COMEBACK_RESPONSE:
494         if len(pos) < 5:
495             return None
496         (status_code, frag, comeback_delay) = struct.unpack('<HBH', pos[0:5])
497         gas['status_code'] = status_code
498         gas['frag'] = frag
499         gas['comeback_delay'] = comeback_delay
500
501     return gas
502
503 def action_response(req):
504     resp = {}
505     resp['fc'] = req['fc']
506     resp['da'] = req['sa']
507     resp['sa'] = req['da']
508     resp['bssid'] = req['bssid']
509     return resp
510
511 def send_gas_resp(hapd, resp):
512     hapd.mgmt_tx(resp)
513     ev = hapd.wait_event(["MGMT-TX-STATUS"], timeout=5)
514     if ev is None:
515         raise Exception("Missing TX status for GAS response")
516     if "ok=1" not in ev:
517         raise Exception("GAS response not acknowledged")
518
519 def test_gas_invalid_response_type(dev, apdev):
520     """GAS invalid response type"""
521     hapd = start_ap(apdev[0])
522     bssid = apdev[0]['bssid']
523
524     dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
525     hapd.set("ext_mgmt_frame_handling", "1")
526
527     anqp_get(dev[0], bssid, 263)
528
529     query = gas_rx(hapd)
530     gas = parse_gas(query['payload'])
531
532     resp = action_response(query)
533     # GAS Comeback Response instead of GAS Initial Response
534     resp['payload'] = anqp_comeback_resp(gas['dialog_token']) + struct.pack('<H', 0)
535     send_gas_resp(hapd, resp)
536
537     # station drops the invalid frame, so this needs to result in GAS timeout
538     expect_gas_result(dev[0], "TIMEOUT")
539
540 def test_gas_failure_status_code(dev, apdev):
541     """GAS failure status code"""
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     anqp_get(dev[0], bssid, 263)
549
550     query = gas_rx(hapd)
551     gas = parse_gas(query['payload'])
552
553     resp = action_response(query)
554     resp['payload'] = anqp_initial_resp(gas['dialog_token'], 61) + struct.pack('<H', 0)
555     send_gas_resp(hapd, resp)
556
557     expect_gas_result(dev[0], "FAILURE")
558
559 def test_gas_malformed(dev, apdev):
560     """GAS malformed response frames"""
561     hapd = start_ap(apdev[0])
562     bssid = apdev[0]['bssid']
563
564     dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
565     hapd.set("ext_mgmt_frame_handling", "1")
566
567     anqp_get(dev[0], bssid, 263)
568
569     query = gas_rx(hapd)
570     gas = parse_gas(query['payload'])
571
572     resp = action_response(query)
573
574     resp['payload'] = struct.pack('<BBBH', ACTION_CATEG_PUBLIC,
575                                   GAS_COMEBACK_RESPONSE,
576                                   gas['dialog_token'], 0)
577     hapd.mgmt_tx(resp)
578
579     resp['payload'] = struct.pack('<BBBHB', ACTION_CATEG_PUBLIC,
580                                   GAS_COMEBACK_RESPONSE,
581                                   gas['dialog_token'], 0, 0)
582     hapd.mgmt_tx(resp)
583
584     hdr = struct.pack('<BBBHH', ACTION_CATEG_PUBLIC, GAS_INITIAL_RESPONSE,
585                       gas['dialog_token'], 0, 0)
586     resp['payload'] = hdr + struct.pack('B', 108)
587     hapd.mgmt_tx(resp)
588     resp['payload'] = hdr + struct.pack('BB', 108, 0)
589     hapd.mgmt_tx(resp)
590     resp['payload'] = hdr + struct.pack('BB', 108, 1)
591     hapd.mgmt_tx(resp)
592     resp['payload'] = hdr + struct.pack('BB', 108, 255)
593     hapd.mgmt_tx(resp)
594     resp['payload'] = hdr + struct.pack('BBB', 108, 1, 127)
595     hapd.mgmt_tx(resp)
596     resp['payload'] = hdr + struct.pack('BBB', 108, 2, 127)
597     hapd.mgmt_tx(resp)
598     resp['payload'] = hdr + struct.pack('BBBB', 0, 2, 127, 0)
599     hapd.mgmt_tx(resp)
600
601     resp['payload'] = anqp_initial_resp(gas['dialog_token'], 0) + struct.pack('<H', 1)
602     hapd.mgmt_tx(resp)
603
604     resp['payload'] = anqp_initial_resp(gas['dialog_token'], 0) + struct.pack('<HB', 2, 0)
605     hapd.mgmt_tx(resp)
606
607     resp['payload'] = anqp_initial_resp(gas['dialog_token'], 0) + struct.pack('<H', 65535)
608     hapd.mgmt_tx(resp)
609
610     resp['payload'] = anqp_initial_resp(gas['dialog_token'], 0) + struct.pack('<HBB', 1, 0, 0)
611     hapd.mgmt_tx(resp)
612
613     # Station drops invalid frames, but the last of the responses is valid from
614     # GAS view point even though it has an extra octet in the end and the ANQP
615     # part of the response is not valid. This is reported as successfully
616     # completed GAS exchange.
617     expect_gas_result(dev[0], "SUCCESS")
618
619     ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=5)
620     if ev is None:
621         raise Exception("ANQP-QUERY-DONE not reported")
622     if "result=INVALID_FRAME" not in ev:
623         raise Exception("Unexpected result: " + ev)
624
625 def init_gas(hapd, bssid, dev):
626     anqp_get(dev, bssid, 263)
627     query = gas_rx(hapd)
628     gas = parse_gas(query['payload'])
629     dialog_token = gas['dialog_token']
630
631     resp = action_response(query)
632     resp['payload'] = anqp_initial_resp(dialog_token, 0, comeback_delay=1) + struct.pack('<H', 0)
633     send_gas_resp(hapd, resp)
634
635     query = gas_rx(hapd)
636     gas = parse_gas(query['payload'])
637     if gas['action'] != GAS_COMEBACK_REQUEST:
638         raise Exception("Unexpected request action")
639     if gas['dialog_token'] != dialog_token:
640         raise Exception("Unexpected dialog token change")
641     return query, dialog_token
642
643 def allow_gas_initial_req(hapd, dialog_token):
644     msg = hapd.mgmt_rx(timeout=1)
645     if msg is not None:
646         gas = parse_gas(msg['payload'])
647         if gas['action'] != GAS_INITIAL_REQUEST or dialog_token == gas['dialog_token']:
648             raise Exception("Unexpected management frame")
649
650 def test_gas_malformed_comeback_resp(dev, apdev):
651     """GAS malformed comeback response frames"""
652     hapd = start_ap(apdev[0])
653     bssid = apdev[0]['bssid']
654
655     dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
656     hapd.set("ext_mgmt_frame_handling", "1")
657
658     logger.debug("Non-zero status code in comeback response")
659     query, dialog_token = init_gas(hapd, bssid, dev[0])
660     resp = action_response(query)
661     resp['payload'] = anqp_comeback_resp(dialog_token, status_code=2) + struct.pack('<H', 0)
662     send_gas_resp(hapd, resp)
663     expect_gas_result(dev[0], "FAILURE", status=2)
664
665     logger.debug("Different advertisement protocol in comeback response")
666     query, dialog_token = init_gas(hapd, bssid, dev[0])
667     resp = action_response(query)
668     resp['payload'] = anqp_comeback_resp(dialog_token, bogus_adv_proto=True) + struct.pack('<H', 0)
669     send_gas_resp(hapd, resp)
670     expect_gas_result(dev[0], "PEER_ERROR")
671
672     logger.debug("Non-zero frag id and comeback delay in comeback response")
673     query, dialog_token = init_gas(hapd, bssid, dev[0])
674     resp = action_response(query)
675     resp['payload'] = anqp_comeback_resp(dialog_token, id=1, comeback_delay=1) + struct.pack('<H', 0)
676     send_gas_resp(hapd, resp)
677     expect_gas_result(dev[0], "PEER_ERROR")
678
679     logger.debug("Unexpected frag id in comeback response")
680     query, dialog_token = init_gas(hapd, bssid, dev[0])
681     resp = action_response(query)
682     resp['payload'] = anqp_comeback_resp(dialog_token, id=1) + struct.pack('<H', 0)
683     send_gas_resp(hapd, resp)
684     expect_gas_result(dev[0], "PEER_ERROR")
685
686     logger.debug("Empty fragment and replay in comeback response")
687     query, dialog_token = init_gas(hapd, bssid, dev[0])
688     resp = action_response(query)
689     resp['payload'] = anqp_comeback_resp(dialog_token, more=True) + struct.pack('<H', 0)
690     send_gas_resp(hapd, resp)
691     query = gas_rx(hapd)
692     gas = parse_gas(query['payload'])
693     if gas['action'] != GAS_COMEBACK_REQUEST:
694         raise Exception("Unexpected request action")
695     if gas['dialog_token'] != dialog_token:
696         raise Exception("Unexpected dialog token change")
697     resp = action_response(query)
698     resp['payload'] = anqp_comeback_resp(dialog_token) + struct.pack('<H', 0)
699     send_gas_resp(hapd, resp)
700     resp['payload'] = anqp_comeback_resp(dialog_token, id=1) + struct.pack('<H', 0)
701     send_gas_resp(hapd, resp)
702     expect_gas_result(dev[0], "SUCCESS")
703
704     logger.debug("Unexpected initial response when waiting for comeback response")
705     query, dialog_token = init_gas(hapd, bssid, dev[0])
706     resp = action_response(query)
707     resp['payload'] = anqp_initial_resp(dialog_token, 0) + struct.pack('<H', 0)
708     send_gas_resp(hapd, resp)
709     allow_gas_initial_req(hapd, dialog_token)
710     expect_gas_result(dev[0], "TIMEOUT")
711
712     logger.debug("Too short comeback response")
713     query, dialog_token = init_gas(hapd, bssid, dev[0])
714     resp = action_response(query)
715     resp['payload'] = struct.pack('<BBBH', ACTION_CATEG_PUBLIC,
716                                   GAS_COMEBACK_RESPONSE, dialog_token, 0)
717     send_gas_resp(hapd, resp)
718     allow_gas_initial_req(hapd, dialog_token)
719     expect_gas_result(dev[0], "TIMEOUT")
720
721     logger.debug("Too short comeback response(2)")
722     query, dialog_token = init_gas(hapd, bssid, dev[0])
723     resp = action_response(query)
724     resp['payload'] = struct.pack('<BBBHBB', ACTION_CATEG_PUBLIC,
725                                   GAS_COMEBACK_RESPONSE, dialog_token, 0, 0x80,
726                                   0)
727     send_gas_resp(hapd, resp)
728     allow_gas_initial_req(hapd, dialog_token)
729     expect_gas_result(dev[0], "TIMEOUT")
730
731     logger.debug("Maximum comeback response fragment claiming more fragments")
732     query, dialog_token = init_gas(hapd, bssid, dev[0])
733     resp = action_response(query)
734     resp['payload'] = anqp_comeback_resp(dialog_token, more=True) + struct.pack('<H', 0)
735     send_gas_resp(hapd, resp)
736     for i in range(1, 129):
737         query = gas_rx(hapd)
738         gas = parse_gas(query['payload'])
739         if gas['action'] != GAS_COMEBACK_REQUEST:
740             raise Exception("Unexpected request action")
741         if gas['dialog_token'] != dialog_token:
742             raise Exception("Unexpected dialog token change")
743         resp = action_response(query)
744         resp['payload'] = anqp_comeback_resp(dialog_token, id=i, more=True) + struct.pack('<H', 0)
745         send_gas_resp(hapd, resp)
746     expect_gas_result(dev[0], "PEER_ERROR")
747
748 def test_gas_comeback_resp_additional_delay(dev, apdev):
749     """GAS comeback response requesting additional delay"""
750     hapd = start_ap(apdev[0])
751     bssid = apdev[0]['bssid']
752
753     dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
754     hapd.set("ext_mgmt_frame_handling", "1")
755
756     query, dialog_token = init_gas(hapd, bssid, dev[0])
757     for i in range(0, 2):
758         resp = action_response(query)
759         resp['payload'] = anqp_comeback_resp(dialog_token, status_code=95, comeback_delay=50) + struct.pack('<H', 0)
760         send_gas_resp(hapd, resp)
761         query = gas_rx(hapd)
762         gas = parse_gas(query['payload'])
763         if gas['action'] != GAS_COMEBACK_REQUEST:
764             raise Exception("Unexpected request action")
765         if gas['dialog_token'] != dialog_token:
766             raise Exception("Unexpected dialog token change")
767     resp = action_response(query)
768     resp['payload'] = anqp_comeback_resp(dialog_token, status_code=0) + struct.pack('<H', 0)
769     send_gas_resp(hapd, resp)
770     expect_gas_result(dev[0], "SUCCESS")
771
772 def test_gas_unknown_adv_proto(dev, apdev):
773     """Unknown advertisement protocol id"""
774     bssid = apdev[0]['bssid']
775     params = hs20_ap_params()
776     params['hessid'] = bssid
777     hostapd.add_ap(apdev[0], params)
778
779     dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
780     req = dev[0].request("GAS_REQUEST " + bssid + " 42 000102000101")
781     if "FAIL" in req:
782         raise Exception("GAS query request rejected")
783     expect_gas_result(dev[0], "FAILURE", "59")
784     ev = dev[0].wait_event(["GAS-RESPONSE-INFO"], timeout=10)
785     if ev is None:
786         raise Exception("GAS query timed out")
787     exp = r'<.>(GAS-RESPONSE-INFO) addr=([0-9a-f:]*) dialog_token=([0-9]*) status_code=([0-9]*) resp_len=([\-0-9]*)'
788     res = re.split(exp, ev)
789     if len(res) < 6:
790         raise Exception("Could not parse GAS-RESPONSE-INFO")
791     if res[2] != bssid:
792         raise Exception("Unexpected BSSID in response")
793     status = res[4]
794     if status != "59":
795         raise Exception("Unexpected GAS-RESPONSE-INFO status")
796
797 def test_gas_max_pending(dev, apdev):
798     """GAS and maximum pending query limit"""
799     hapd = start_ap(apdev[0])
800     hapd.set("gas_frag_limit", "50")
801     bssid = apdev[0]['bssid']
802
803     wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
804     wpas.interface_add("wlan5")
805     if "OK" not in wpas.request("P2P_SET listen_channel 1"):
806         raise Exception("Failed to set listen channel")
807     if "OK" not in wpas.p2p_listen():
808         raise Exception("Failed to start listen state")
809     if "FAIL" in wpas.request("SET ext_mgmt_frame_handling 1"):
810         raise Exception("Failed to enable external management frame handling")
811
812     anqp_query = struct.pack('<HHHHHHHHHH', 256, 16, 257, 258, 260, 261, 262, 263, 264, 268)
813     gas = struct.pack('<H', len(anqp_query)) + anqp_query
814
815     for dialog_token in range(1, 10):
816         msg = struct.pack('<BBB', ACTION_CATEG_PUBLIC, GAS_INITIAL_REQUEST,
817                           dialog_token) + anqp_adv_proto() + gas
818         req = "MGMT_TX {} {} freq=2412 wait_time=10 action={}".format(bssid, bssid, binascii.hexlify(msg))
819         if "OK" not in wpas.request(req):
820             raise Exception("Could not send management frame")
821         resp = wpas.mgmt_rx()
822         if resp is None:
823             raise Exception("MGMT-RX timeout")
824         if 'payload' not in resp:
825             raise Exception("Missing payload")
826         gresp = parse_gas(resp['payload'])
827         if gresp['dialog_token'] != dialog_token:
828             raise Exception("Dialog token mismatch")
829         status_code = gresp['status_code']
830         if dialog_token < 9 and status_code != 0:
831             raise Exception("Unexpected failure status code {} for dialog token {}".format(status_code, dialog_token))
832         if dialog_token > 8 and status_code == 0:
833             raise Exception("Unexpected success status code {} for dialog token {}".format(status_code, dialog_token))
834
835 def test_gas_no_pending(dev, apdev):
836     """GAS and no pending query for comeback request"""
837     hapd = start_ap(apdev[0])
838     bssid = apdev[0]['bssid']
839
840     wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
841     wpas.interface_add("wlan5")
842     if "OK" not in wpas.request("P2P_SET listen_channel 1"):
843         raise Exception("Failed to set listen channel")
844     if "OK" not in wpas.p2p_listen():
845         raise Exception("Failed to start listen state")
846     if "FAIL" in wpas.request("SET ext_mgmt_frame_handling 1"):
847         raise Exception("Failed to enable external management frame handling")
848
849     msg = struct.pack('<BBB', ACTION_CATEG_PUBLIC, GAS_COMEBACK_REQUEST, 1)
850     req = "MGMT_TX {} {} freq=2412 wait_time=10 action={}".format(bssid, bssid, binascii.hexlify(msg))
851     if "OK" not in wpas.request(req):
852         raise Exception("Could not send management frame")
853     resp = wpas.mgmt_rx()
854     if resp is None:
855         raise Exception("MGMT-RX timeout")
856     if 'payload' not in resp:
857         raise Exception("Missing payload")
858     gresp = parse_gas(resp['payload'])
859     status_code = gresp['status_code']
860     if status_code != 60:
861         raise Exception("Unexpected status code {} (expected 60)".format(status_code))
862
863 def test_gas_delete_at_deinit(dev, apdev):
864     """GAS query deleted at deinit"""
865     hapd = start_ap(apdev[0])
866     hapd.set("gas_comeback_delay", "1000")
867     bssid = apdev[0]['bssid']
868
869     wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
870     wpas.interface_add("wlan5")
871     wpas.scan_for_bss(apdev[0]['bssid'], freq="2412", force_scan=True)
872     wpas.request("ANQP_GET " + bssid + " 258")
873
874     wpas.global_request("INTERFACE_REMOVE " + wpas.ifname)
875     ev = wpas.wait_event(["GAS-QUERY-DONE"], timeout=2)
876     del wpas
877     if ev is None:
878         raise Exception("GAS-QUERY-DONE not seen")
879     if "result=DELETED_AT_DEINIT" not in ev:
880         raise Exception("Unexpected result code: " + ev)
881
882 def test_gas_missing_payload(dev, apdev):
883     """No action code in the query frame"""
884     bssid = apdev[0]['bssid']
885     params = hs20_ap_params()
886     params['hessid'] = bssid
887     hostapd.add_ap(apdev[0], params)
888
889     dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
890
891     cmd = "MGMT_TX {} {} freq=2412 action=040A".format(bssid, bssid)
892     if "FAIL" in dev[0].request(cmd):
893         raise Exception("Could not send test Action frame")
894     ev = dev[0].wait_event(["MGMT-TX-STATUS"], timeout=10)
895     if ev is None:
896         raise Exception("Timeout on MGMT-TX-STATUS")
897     if "result=SUCCESS" not in ev:
898         raise Exception("AP did not ack Action frame")
899
900     cmd = "MGMT_TX {} {} freq=2412 action=04".format(bssid, bssid)
901     if "FAIL" in dev[0].request(cmd):
902         raise Exception("Could not send test Action frame")
903     ev = dev[0].wait_event(["MGMT-TX-STATUS"], timeout=10)
904     if ev is None:
905         raise Exception("Timeout on MGMT-TX-STATUS")
906     if "result=SUCCESS" not in ev:
907         raise Exception("AP did not ack Action frame")
908
909 def test_gas_query_deinit(dev, apdev):
910     """Pending GAS/ANQP query during deinit"""
911     hapd = start_ap(apdev[0])
912     bssid = apdev[0]['bssid']
913
914     wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
915     wpas.interface_add("wlan5")
916
917     wpas.scan_for_bss(bssid, freq="2412", force_scan=True)
918     id = wpas.request("RADIO_WORK add block-work")
919     if "OK" not in wpas.request("ANQP_GET " + bssid + " 258"):
920         raise Exception("ANQP_GET command failed")
921
922     ev = wpas.wait_event(["GAS-QUERY-START", "EXT-RADIO-WORK-START"], timeout=5)
923     if ev is None:
924         raise Exception("Timeout while waiting radio work to start")
925     ev = wpas.wait_event(["GAS-QUERY-START", "EXT-RADIO-WORK-START"], timeout=5)
926     if ev is None:
927         raise Exception("Timeout while waiting radio work to start (2)")
928
929     # Remove the interface while the gas-query radio work is still pending and
930     # GAS query has not yet been started.
931     wpas.interface_remove("wlan5")
932
933 def test_gas_anqp_oom_wpas(dev, apdev):
934     """GAS/ANQP query and OOM in wpa_supplicant"""
935     hapd = start_ap(apdev[0])
936     bssid = apdev[0]['bssid']
937
938     dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
939
940     with alloc_fail(dev[0], 1, "wpa_bss_anqp_alloc"):
941         if "OK" not in dev[0].request("ANQP_GET " + bssid + " 258"):
942             raise Exception("ANQP_GET command failed")
943         ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=5)
944         if ev is None:
945             raise Exception("ANQP query did not complete")
946
947     with alloc_fail(dev[0], 1, "gas_build_req"):
948         if "FAIL" not in dev[0].request("ANQP_GET " + bssid + " 258"):
949             raise Exception("Unexpected ANQP_GET command success (OOM)")
950
951 def test_gas_anqp_oom_hapd(dev, apdev):
952     """GAS/ANQP query and OOM in hostapd"""
953     hapd = start_ap(apdev[0])
954     bssid = apdev[0]['bssid']
955
956     dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
957
958     with alloc_fail(hapd, 1, "gas_build_resp"):
959         # This query will time out due to the AP not sending a response (OOM).
960         if "OK" not in dev[0].request("ANQP_GET " + bssid + " 258"):
961             raise Exception("ANQP_GET command failed")
962
963         ev = dev[0].wait_event(["GAS-QUERY-START"], timeout=5)
964         if ev is None:
965             raise Exception("GAS query start timed out")
966
967         ev = dev[0].wait_event(["GAS-QUERY-DONE"], timeout=10)
968         if ev is None:
969             raise Exception("GAS query timed out")
970         if "result=TIMEOUT" not in ev:
971             raise Exception("Unexpected result: " + ev)
972
973         ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=10)
974         if ev is None:
975             raise Exception("ANQP-QUERY-DONE event not seen")
976         if "result=FAILURE" not in ev:
977             raise Exception("Unexpected result: " + ev)
978
979     with alloc_fail(hapd, 1, "gas_anqp_build_comeback_resp"):
980         hapd.set("gas_frag_limit", "50")
981
982         # The first attempt of this query will time out due to the AP not
983         # sending a response (OOM), but the retry succeeds.
984         dev[0].request("FETCH_ANQP")
985         ev = dev[0].wait_event(["GAS-QUERY-START"], timeout=5)
986         if ev is None:
987             raise Exception("GAS query start timed out")
988
989         ev = dev[0].wait_event(["GAS-QUERY-DONE"], timeout=10)
990         if ev is None:
991             raise Exception("GAS query timed out")
992         if "result=SUCCESS" not in ev:
993             raise Exception("Unexpected result: " + ev)
994
995         ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=10)
996         if ev is None:
997             raise Exception("ANQP-QUERY-DONE event not seen")
998         if "result=SUCCESS" not in ev:
999             raise Exception("Unexpected result: " + ev)
1000
1001 def test_gas_anqp_extra_elements(dev, apdev):
1002     """GAS/ANQP and extra ANQP elements"""
1003     geo_loc = "001052834d12efd2b08b9b4bf1cc2c00004104050000000000060100"
1004     civic_loc = "0000f9555302f50102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5"
1005     held_uri = "https://held.example.com/location"
1006     held = struct.pack('BBB', 0, 1 + len(held_uri), 1) + held_uri
1007     supl_fqdn = "supl.example.com"
1008     supl = struct.pack('BBB', 0, 1 + len(supl_fqdn), 1) + supl_fqdn
1009     public_id = binascii.hexlify(held + supl)
1010     params = { "ssid": "gas/anqp",
1011                "interworking": "1",
1012                "anqp_elem": [ "265:" + geo_loc,
1013                               "266:" + civic_loc,
1014                               "262:1122334455",
1015                               "267:" + public_id,
1016                               "275:01020304",
1017                               "60000:01",
1018                               "299:0102" ] }
1019     hapd = hostapd.add_ap(apdev[0], params)
1020     bssid = apdev[0]['bssid']
1021
1022     dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
1023     if "OK" not in dev[0].request("ANQP_GET " + bssid + " 265,266"):
1024         raise Exception("ANQP_GET command failed")
1025
1026     ev = dev[0].wait_event(["GAS-QUERY-DONE"], timeout=10)
1027     if ev is None:
1028         raise Exception("GAS query timed out")
1029
1030     bss = dev[0].get_bss(bssid)
1031
1032     if 'anqp[265]' not in bss:
1033         raise Exception("AP Geospatial Location ANQP-element not seen")
1034     if bss['anqp[265]'] != geo_loc:
1035         raise Exception("Unexpected AP Geospatial Location ANQP-element value: " + bss['anqp[265]'])
1036
1037     if 'anqp[266]' not in bss:
1038         raise Exception("AP Civic Location ANQP-element not seen")
1039     if bss['anqp[266]'] != civic_loc:
1040         raise Exception("Unexpected AP Civic Location ANQP-element value: " + bss['anqp[266]'])
1041
1042     dev[1].scan_for_bss(bssid, freq="2412", force_scan=True)
1043     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"):
1044         raise Exception("ANQP_GET command failed")
1045
1046     ev = dev[1].wait_event(["GAS-QUERY-DONE"], timeout=10)
1047     if ev is None:
1048         raise Exception("GAS query timed out")
1049
1050     bss = dev[1].get_bss(bssid)
1051
1052     if 'anqp[265]' not in bss:
1053         raise Exception("AP Geospatial Location ANQP-element not seen")
1054     if bss['anqp[265]'] != geo_loc:
1055         raise Exception("Unexpected AP Geospatial Location ANQP-element value: " + bss['anqp[265]'])
1056
1057     if 'anqp[266]' in bss:
1058         raise Exception("AP Civic Location ANQP-element unexpectedly seen")
1059
1060     if 'anqp[267]' not in bss:
1061         raise Exception("AP Location Public Identifier ANQP-element not seen")
1062     if bss['anqp[267]'] != public_id:
1063         raise Exception("Unexpected AP Location Public Identifier ANQP-element value: " + bss['anqp[267]'])
1064
1065     if 'anqp[275]' not in bss:
1066         raise Exception("ANQP-element Info ID 275 not seen")
1067     if bss['anqp[275]'] != "01020304":
1068         raise Exception("Unexpected AP ANQP-element Info ID 299 value: " + bss['anqp[299]'])
1069
1070     if 'anqp[299]' not in bss:
1071         raise Exception("ANQP-element Info ID 299 not seen")
1072     if bss['anqp[299]'] != "0102":
1073         raise Exception("Unexpected AP ANQP-element Info ID 299 value: " + bss['anqp[299]'])
1074
1075     if 'anqp_ip_addr_type_availability' not in bss:
1076         raise Exception("ANQP-element Info ID 292 not seen")
1077     if bss['anqp_ip_addr_type_availability'] != "1122334455":
1078         raise Exception("Unexpected AP ANQP-element Info ID 262 value: " + bss['anqp_ip_addr_type_availability'])
1079
1080 def test_gas_anqp_address3_not_assoc(dev, apdev, params):
1081     """GAS/ANQP query using IEEE 802.11 compliant Address 3 value when not associated"""
1082     try:
1083         _test_gas_anqp_address3_not_assoc(dev, apdev, params)
1084     finally:
1085         dev[0].request("SET gas_address3 0")
1086
1087 def _test_gas_anqp_address3_not_assoc(dev, apdev, params):
1088     hapd = start_ap(apdev[0])
1089     bssid = apdev[0]['bssid']
1090
1091     if "OK" not in dev[0].request("SET gas_address3 1"):
1092         raise Exception("Failed to set gas_address3")
1093
1094     dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
1095     if "OK" not in dev[0].request("ANQP_GET " + bssid + " 258"):
1096         raise Exception("ANQP_GET command failed")
1097
1098     ev = dev[0].wait_event(["GAS-QUERY-START"], timeout=5)
1099     if ev is None:
1100         raise Exception("GAS query start timed out")
1101
1102     ev = dev[0].wait_event(["GAS-QUERY-DONE"], timeout=10)
1103     if ev is None:
1104         raise Exception("GAS query timed out")
1105
1106     ev = dev[0].wait_event(["RX-ANQP"], timeout=1)
1107     if ev is None or "Venue Name" not in ev:
1108         raise Exception("Did not receive Venue Name")
1109
1110     ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=10)
1111     if ev is None:
1112         raise Exception("ANQP-QUERY-DONE event not seen")
1113     if "result=SUCCESS" not in ev:
1114         raise Exception("Unexpected result: " + ev)
1115
1116     out = run_tshark(os.path.join(params['logdir'], "hwsim0.pcapng"),
1117                      "wlan_mgt.fixed.category_code == 4 && (wlan_mgt.fixed.publicact == 0x0a || wlan_mgt.fixed.publicact == 0x0b)",
1118                      display=["wlan.bssid"])
1119     res = out.splitlines()
1120     if len(res) != 2:
1121         raise Exception("Unexpected number of GAS frames")
1122     if res[0] != 'ff:ff:ff:ff:ff:ff':
1123         raise Exception("GAS request used unexpected Address3 field value: " + res[0])
1124     if res[1] != 'ff:ff:ff:ff:ff:ff':
1125         raise Exception("GAS response used unexpected Address3 field value: " + res[1])
1126
1127 def test_gas_anqp_address3_assoc(dev, apdev, params):
1128     """GAS/ANQP query using IEEE 802.11 compliant Address 3 value when associated"""
1129     try:
1130         _test_gas_anqp_address3_assoc(dev, apdev, params)
1131     finally:
1132         dev[0].request("SET gas_address3 0")
1133
1134 def _test_gas_anqp_address3_assoc(dev, apdev, params):
1135     hapd = start_ap(apdev[0])
1136     bssid = apdev[0]['bssid']
1137
1138     if "OK" not in dev[0].request("SET gas_address3 1"):
1139         raise Exception("Failed to set gas_address3")
1140
1141     dev[0].scan_for_bss(bssid, freq="2412")
1142     dev[0].connect("test-gas", key_mgmt="WPA-EAP", eap="TTLS",
1143                    identity="DOMAIN\mschapv2 user", anonymous_identity="ttls",
1144                    password="password", phase2="auth=MSCHAPV2",
1145                    ca_cert="auth_serv/ca.pem", scan_freq="2412")
1146
1147     if "OK" not in dev[0].request("ANQP_GET " + bssid + " 258"):
1148         raise Exception("ANQP_GET command failed")
1149
1150     ev = dev[0].wait_event(["GAS-QUERY-START"], timeout=5)
1151     if ev is None:
1152         raise Exception("GAS query start timed out")
1153
1154     ev = dev[0].wait_event(["GAS-QUERY-DONE"], timeout=10)
1155     if ev is None:
1156         raise Exception("GAS query timed out")
1157
1158     ev = dev[0].wait_event(["RX-ANQP"], timeout=1)
1159     if ev is None or "Venue Name" not in ev:
1160         raise Exception("Did not receive Venue Name")
1161
1162     ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=10)
1163     if ev is None:
1164         raise Exception("ANQP-QUERY-DONE event not seen")
1165     if "result=SUCCESS" not in ev:
1166         raise Exception("Unexpected result: " + ev)
1167
1168     out = run_tshark(os.path.join(params['logdir'], "hwsim0.pcapng"),
1169                      "wlan_mgt.fixed.category_code == 4 && (wlan_mgt.fixed.publicact == 0x0a || wlan_mgt.fixed.publicact == 0x0b)",
1170                      display=["wlan.bssid"])
1171     res = out.splitlines()
1172     if len(res) != 2:
1173         raise Exception("Unexpected number of GAS frames")
1174     if res[0] != bssid:
1175         raise Exception("GAS request used unexpected Address3 field value: " + res[0])
1176     if res[1] != bssid:
1177         raise Exception("GAS response used unexpected Address3 field value: " + res[1])
1178
1179 def test_gas_anqp_address3_ap_forced(dev, apdev, params):
1180     """GAS/ANQP query using IEEE 802.11 compliant Address 3 value on AP"""
1181     hapd = start_ap(apdev[0])
1182     bssid = apdev[0]['bssid']
1183     hapd.set("gas_address3", "1")
1184
1185     dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
1186     if "OK" not in dev[0].request("ANQP_GET " + bssid + " 258"):
1187         raise Exception("ANQP_GET command failed")
1188
1189     ev = dev[0].wait_event(["GAS-QUERY-START"], timeout=5)
1190     if ev is None:
1191         raise Exception("GAS query start timed out")
1192
1193     ev = dev[0].wait_event(["GAS-QUERY-DONE"], timeout=10)
1194     if ev is None:
1195         raise Exception("GAS query timed out")
1196
1197     ev = dev[0].wait_event(["RX-ANQP"], timeout=1)
1198     if ev is None or "Venue Name" not in ev:
1199         raise Exception("Did not receive Venue Name")
1200
1201     ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=10)
1202     if ev is None:
1203         raise Exception("ANQP-QUERY-DONE event not seen")
1204     if "result=SUCCESS" not in ev:
1205         raise Exception("Unexpected result: " + ev)
1206
1207     out = run_tshark(os.path.join(params['logdir'], "hwsim0.pcapng"),
1208                      "wlan_mgt.fixed.category_code == 4 && (wlan_mgt.fixed.publicact == 0x0a || wlan_mgt.fixed.publicact == 0x0b)",
1209                      display=["wlan.bssid"])
1210     res = out.splitlines()
1211     if len(res) != 2:
1212         raise Exception("Unexpected number of GAS frames")
1213     if res[0] != bssid:
1214         raise Exception("GAS request used unexpected Address3 field value: " + res[0])
1215     if res[1] != 'ff:ff:ff:ff:ff:ff':
1216         raise Exception("GAS response used unexpected Address3 field value: " + res[1])
1217
1218 def test_gas_anqp_address3_ap_non_compliant(dev, apdev, params):
1219     """GAS/ANQP query using IEEE 802.11 non-compliant Address 3 (AP)"""
1220     try:
1221         _test_gas_anqp_address3_ap_non_compliant(dev, apdev, params)
1222     finally:
1223         dev[0].request("SET gas_address3 0")
1224
1225 def _test_gas_anqp_address3_ap_non_compliant(dev, apdev, params):
1226     hapd = start_ap(apdev[0])
1227     bssid = apdev[0]['bssid']
1228     hapd.set("gas_address3", "2")
1229
1230     if "OK" not in dev[0].request("SET gas_address3 1"):
1231         raise Exception("Failed to set gas_address3")
1232
1233     dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
1234     if "OK" not in dev[0].request("ANQP_GET " + bssid + " 258"):
1235         raise Exception("ANQP_GET command failed")
1236
1237     ev = dev[0].wait_event(["GAS-QUERY-START"], timeout=5)
1238     if ev is None:
1239         raise Exception("GAS query start timed out")
1240
1241     ev = dev[0].wait_event(["GAS-QUERY-DONE"], timeout=10)
1242     if ev is None:
1243         raise Exception("GAS query timed out")
1244
1245     ev = dev[0].wait_event(["RX-ANQP"], timeout=1)
1246     if ev is None or "Venue Name" not in ev:
1247         raise Exception("Did not receive Venue Name")
1248
1249     ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=10)
1250     if ev is None:
1251         raise Exception("ANQP-QUERY-DONE event not seen")
1252     if "result=SUCCESS" not in ev:
1253         raise Exception("Unexpected result: " + ev)
1254
1255     out = run_tshark(os.path.join(params['logdir'], "hwsim0.pcapng"),
1256                      "wlan_mgt.fixed.category_code == 4 && (wlan_mgt.fixed.publicact == 0x0a || wlan_mgt.fixed.publicact == 0x0b)",
1257                      display=["wlan.bssid"])
1258     res = out.splitlines()
1259     if len(res) != 2:
1260         raise Exception("Unexpected number of GAS frames")
1261     if res[0] != 'ff:ff:ff:ff:ff:ff':
1262         raise Exception("GAS request used unexpected Address3 field value: " + res[0])
1263     if res[1] != bssid:
1264         raise Exception("GAS response used unexpected Address3 field value: " + res[1])
1265
1266 def test_gas_prot_vs_not_prot(dev, apdev, params):
1267     """GAS/ANQP query protected vs. not protected"""
1268     hapd = start_ap(apdev[0])
1269     bssid = apdev[0]['bssid']
1270
1271     dev[0].scan_for_bss(bssid, freq="2412")
1272     dev[0].connect("test-gas", key_mgmt="WPA-EAP", eap="TTLS",
1273                    identity="DOMAIN\mschapv2 user", anonymous_identity="ttls",
1274                    password="password", phase2="auth=MSCHAPV2",
1275                    ca_cert="auth_serv/ca.pem", scan_freq="2412",
1276                    ieee80211w="2")
1277
1278     if "OK" not in dev[0].request("ANQP_GET " + bssid + " 258"):
1279         raise Exception("ANQP_GET command failed")
1280
1281     ev = dev[0].wait_event(["GAS-QUERY-DONE"], timeout=5)
1282     if ev is None:
1283         raise Exception("No GAS-QUERY-DONE event")
1284     if "result=SUCCESS" not in ev:
1285         raise Exception("Unexpected GAS result: " + ev)
1286
1287     # GAS: Drop unexpected unprotected GAS frame when PMF is enabled
1288     dev[0].request("SET ext_mgmt_frame_handling 1")
1289     res = dev[0].request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=d0003a010200000000000200000003000200000003001000040b00000005006c027f000000")
1290     dev[0].request("SET ext_mgmt_frame_handling 0")
1291     if "OK" not in res:
1292         raise Exception("MGMT_RX_PROCESS failed")
1293
1294     dev[0].request("DISCONNECT")
1295     dev[0].wait_disconnected()
1296
1297     # GAS: No pending query found for 02:00:00:00:03:00 dialog token 0
1298     dev[0].request("SET ext_mgmt_frame_handling 1")
1299     res = dev[0].request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=d0003a010200000000000200000003000200000003001000040b00000005006c027f000000")
1300     dev[0].request("SET ext_mgmt_frame_handling 0")
1301     if "OK" not in res:
1302         raise Exception("MGMT_RX_PROCESS failed")
1303
1304     # GAS: Drop unexpected protected GAS frame when PMF is disabled
1305     dev[0].request("SET ext_mgmt_frame_handling 1")
1306     res = dev[0].request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=d0003a010200000000000200000003000200000003001000090b00000005006c027f000000")
1307     dev[0].request("SET ext_mgmt_frame_handling 0")
1308     if "OK" not in res:
1309         raise Exception("MGMT_RX_PROCESS failed")