tests: GAS/ANQP query and Address 3 value selection
[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, 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_missing_payload(dev, apdev):
864     """No action code in the query frame"""
865     bssid = apdev[0]['bssid']
866     params = hs20_ap_params()
867     params['hessid'] = bssid
868     hostapd.add_ap(apdev[0], params)
869
870     dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
871
872     cmd = "MGMT_TX {} {} freq=2412 action=040A".format(bssid, bssid)
873     if "FAIL" in dev[0].request(cmd):
874         raise Exception("Could not send test Action frame")
875     ev = dev[0].wait_event(["MGMT-TX-STATUS"], timeout=10)
876     if ev is None:
877         raise Exception("Timeout on MGMT-TX-STATUS")
878     if "result=SUCCESS" not in ev:
879         raise Exception("AP did not ack Action frame")
880
881     cmd = "MGMT_TX {} {} freq=2412 action=04".format(bssid, bssid)
882     if "FAIL" in dev[0].request(cmd):
883         raise Exception("Could not send test Action frame")
884     ev = dev[0].wait_event(["MGMT-TX-STATUS"], timeout=10)
885     if ev is None:
886         raise Exception("Timeout on MGMT-TX-STATUS")
887     if "result=SUCCESS" not in ev:
888         raise Exception("AP did not ack Action frame")
889
890 def test_gas_query_deinit(dev, apdev):
891     """Pending GAS/ANQP query during deinit"""
892     hapd = start_ap(apdev[0])
893     bssid = apdev[0]['bssid']
894
895     wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
896     wpas.interface_add("wlan5")
897
898     wpas.scan_for_bss(bssid, freq="2412", force_scan=True)
899     id = wpas.request("RADIO_WORK add block-work")
900     if "OK" not in wpas.request("ANQP_GET " + bssid + " 258"):
901         raise Exception("ANQP_GET command failed")
902
903     ev = wpas.wait_event(["GAS-QUERY-START", "EXT-RADIO-WORK-START"], timeout=5)
904     if ev is None:
905         raise Exception("Timeout while waiting radio work to start")
906     ev = wpas.wait_event(["GAS-QUERY-START", "EXT-RADIO-WORK-START"], timeout=5)
907     if ev is None:
908         raise Exception("Timeout while waiting radio work to start (2)")
909
910     # Remove the interface while the gas-query radio work is still pending and
911     # GAS query has not yet been started.
912     wpas.interface_remove("wlan5")
913
914 def test_gas_anqp_oom_wpas(dev, apdev):
915     """GAS/ANQP query and OOM in wpa_supplicant"""
916     hapd = start_ap(apdev[0])
917     bssid = apdev[0]['bssid']
918
919     dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
920
921     with alloc_fail(dev[0], 1, "gas_build_req"):
922         if "FAIL" not in dev[0].request("ANQP_GET " + bssid + " 258"):
923             raise Exception("Unexpected ANQP_GET command success (OOM)")
924
925 def test_gas_anqp_oom_hapd(dev, apdev):
926     """GAS/ANQP query and OOM in hostapd"""
927     hapd = start_ap(apdev[0])
928     bssid = apdev[0]['bssid']
929
930     dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
931
932     with alloc_fail(hapd, 1, "gas_build_resp"):
933         # This query will time out due to the AP not sending a response (OOM).
934         if "OK" not in dev[0].request("ANQP_GET " + bssid + " 258"):
935             raise Exception("ANQP_GET command failed")
936
937         ev = dev[0].wait_event(["GAS-QUERY-START"], timeout=5)
938         if ev is None:
939             raise Exception("GAS query start timed out")
940
941         ev = dev[0].wait_event(["GAS-QUERY-DONE"], timeout=10)
942         if ev is None:
943             raise Exception("GAS query timed out")
944         if "result=TIMEOUT" not in ev:
945             raise Exception("Unexpected result: " + ev)
946
947         ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=10)
948         if ev is None:
949             raise Exception("ANQP-QUERY-DONE event not seen")
950         if "result=FAILURE" not in ev:
951             raise Exception("Unexpected result: " + ev)
952
953     with alloc_fail(hapd, 1, "gas_anqp_build_comeback_resp"):
954         hapd.set("gas_frag_limit", "50")
955
956         # The first attempt of this query will time out due to the AP not
957         # sending a response (OOM), but the retry succeeds.
958         dev[0].request("FETCH_ANQP")
959         ev = dev[0].wait_event(["GAS-QUERY-START"], timeout=5)
960         if ev is None:
961             raise Exception("GAS query start timed out")
962
963         ev = dev[0].wait_event(["GAS-QUERY-DONE"], timeout=10)
964         if ev is None:
965             raise Exception("GAS query timed out")
966         if "result=SUCCESS" not in ev:
967             raise Exception("Unexpected result: " + ev)
968
969         ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=10)
970         if ev is None:
971             raise Exception("ANQP-QUERY-DONE event not seen")
972         if "result=SUCCESS" not in ev:
973             raise Exception("Unexpected result: " + ev)
974
975 def test_gas_anqp_extra_elements(dev, apdev):
976     """GAS/ANQP and extra ANQP elements"""
977     geo_loc = "001052834d12efd2b08b9b4bf1cc2c00004104050000000000060100"
978     civic_loc = "0000f9555302f50102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5"
979     held_uri = "https://held.example.com/location"
980     held = struct.pack('BBB', 0, 1 + len(held_uri), 1) + held_uri
981     supl_fqdn = "supl.example.com"
982     supl = struct.pack('BBB', 0, 1 + len(supl_fqdn), 1) + supl_fqdn
983     public_id = binascii.hexlify(held + supl)
984     params = { "ssid": "gas/anqp",
985                "interworking": "1",
986                "anqp_elem": [ "265:" + geo_loc,
987                               "266:" + civic_loc,
988                               "262:1122334455",
989                               "267:" + public_id,
990                               "275:01020304",
991                               "60000:01",
992                               "299:0102" ] }
993     hapd = hostapd.add_ap(apdev[0], params)
994     bssid = apdev[0]['bssid']
995
996     dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
997     if "OK" not in dev[0].request("ANQP_GET " + bssid + " 265,266"):
998         raise Exception("ANQP_GET command failed")
999
1000     ev = dev[0].wait_event(["GAS-QUERY-DONE"], timeout=10)
1001     if ev is None:
1002         raise Exception("GAS query timed out")
1003
1004     bss = dev[0].get_bss(bssid)
1005
1006     if 'anqp[265]' not in bss:
1007         raise Exception("AP Geospatial Location ANQP-element not seen")
1008     if bss['anqp[265]'] != geo_loc:
1009         raise Exception("Unexpected AP Geospatial Location ANQP-element value: " + bss['anqp[265]'])
1010
1011     if 'anqp[266]' not in bss:
1012         raise Exception("AP Civic Location ANQP-element not seen")
1013     if bss['anqp[266]'] != civic_loc:
1014         raise Exception("Unexpected AP Civic Location ANQP-element value: " + bss['anqp[266]'])
1015
1016     dev[1].scan_for_bss(bssid, freq="2412", force_scan=True)
1017     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"):
1018         raise Exception("ANQP_GET command failed")
1019
1020     ev = dev[1].wait_event(["GAS-QUERY-DONE"], timeout=10)
1021     if ev is None:
1022         raise Exception("GAS query timed out")
1023
1024     bss = dev[1].get_bss(bssid)
1025
1026     if 'anqp[265]' not in bss:
1027         raise Exception("AP Geospatial Location ANQP-element not seen")
1028     if bss['anqp[265]'] != geo_loc:
1029         raise Exception("Unexpected AP Geospatial Location ANQP-element value: " + bss['anqp[265]'])
1030
1031     if 'anqp[266]' in bss:
1032         raise Exception("AP Civic Location ANQP-element unexpectedly seen")
1033
1034     if 'anqp[267]' not in bss:
1035         raise Exception("AP Location Public Identifier ANQP-element not seen")
1036     if bss['anqp[267]'] != public_id:
1037         raise Exception("Unexpected AP Location Public Identifier ANQP-element value: " + bss['anqp[267]'])
1038
1039     if 'anqp[275]' not in bss:
1040         raise Exception("ANQP-element Info ID 275 not seen")
1041     if bss['anqp[275]'] != "01020304":
1042         raise Exception("Unexpected AP ANQP-element Info ID 299 value: " + bss['anqp[299]'])
1043
1044     if 'anqp[299]' not in bss:
1045         raise Exception("ANQP-element Info ID 299 not seen")
1046     if bss['anqp[299]'] != "0102":
1047         raise Exception("Unexpected AP ANQP-element Info ID 299 value: " + bss['anqp[299]'])
1048
1049     if 'anqp_ip_addr_type_availability' not in bss:
1050         raise Exception("ANQP-element Info ID 292 not seen")
1051     if bss['anqp_ip_addr_type_availability'] != "1122334455":
1052         raise Exception("Unexpected AP ANQP-element Info ID 262 value: " + bss['anqp_ip_addr_type_availability'])
1053
1054 def test_gas_anqp_address3_not_assoc(dev, apdev, params):
1055     """GAS/ANQP query using IEEE 802.11 compliant Address 3 value when not associated"""
1056     try:
1057         _test_gas_anqp_address3_not_assoc(dev, apdev, params)
1058     finally:
1059         dev[0].request("SET gas_address3 0")
1060
1061 def _test_gas_anqp_address3_not_assoc(dev, apdev, params):
1062     hapd = start_ap(apdev[0])
1063     bssid = apdev[0]['bssid']
1064
1065     if "OK" not in dev[0].request("SET gas_address3 1"):
1066         raise Exception("Failed to set gas_address3")
1067
1068     dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
1069     if "OK" not in dev[0].request("ANQP_GET " + bssid + " 258"):
1070         raise Exception("ANQP_GET command failed")
1071
1072     ev = dev[0].wait_event(["GAS-QUERY-START"], timeout=5)
1073     if ev is None:
1074         raise Exception("GAS query start timed out")
1075
1076     ev = dev[0].wait_event(["GAS-QUERY-DONE"], timeout=10)
1077     if ev is None:
1078         raise Exception("GAS query timed out")
1079
1080     ev = dev[0].wait_event(["RX-ANQP"], timeout=1)
1081     if ev is None or "Venue Name" not in ev:
1082         raise Exception("Did not receive Venue Name")
1083
1084     ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=10)
1085     if ev is None:
1086         raise Exception("ANQP-QUERY-DONE event not seen")
1087     if "result=SUCCESS" not in ev:
1088         raise Exception("Unexpected result: " + ev)
1089
1090     out = run_tshark(os.path.join(params['logdir'], "hwsim0.pcapng"),
1091                      "wlan_mgt.fixed.category_code == 4 && (wlan_mgt.fixed.publicact == 0x0a || wlan_mgt.fixed.publicact == 0x0b)",
1092                      display=["wlan.bssid"])
1093     res = out.splitlines()
1094     if len(res) != 2:
1095         raise Exception("Unexpected number of GAS frames")
1096     if res[0] != 'ff:ff:ff:ff:ff:ff':
1097         raise Exception("GAS request used unexpected Address3 field value: " + res[0])
1098     if res[1] != 'ff:ff:ff:ff:ff:ff':
1099         raise Exception("GAS response used unexpected Address3 field value: " + res[1])
1100
1101 def test_gas_anqp_address3_assoc(dev, apdev, params):
1102     """GAS/ANQP query using IEEE 802.11 compliant Address 3 value when associated"""
1103     try:
1104         _test_gas_anqp_address3_assoc(dev, apdev, params)
1105     finally:
1106         dev[0].request("SET gas_address3 0")
1107
1108 def _test_gas_anqp_address3_assoc(dev, apdev, params):
1109     hapd = start_ap(apdev[0])
1110     bssid = apdev[0]['bssid']
1111
1112     if "OK" not in dev[0].request("SET gas_address3 1"):
1113         raise Exception("Failed to set gas_address3")
1114
1115     dev[0].scan_for_bss(bssid, freq="2412")
1116     dev[0].connect("test-gas", key_mgmt="WPA-EAP", eap="TTLS",
1117                    identity="DOMAIN\mschapv2 user", anonymous_identity="ttls",
1118                    password="password", phase2="auth=MSCHAPV2",
1119                    ca_cert="auth_serv/ca.pem", scan_freq="2412")
1120
1121     if "OK" not in dev[0].request("ANQP_GET " + bssid + " 258"):
1122         raise Exception("ANQP_GET command failed")
1123
1124     ev = dev[0].wait_event(["GAS-QUERY-START"], timeout=5)
1125     if ev is None:
1126         raise Exception("GAS query start timed out")
1127
1128     ev = dev[0].wait_event(["GAS-QUERY-DONE"], timeout=10)
1129     if ev is None:
1130         raise Exception("GAS query timed out")
1131
1132     ev = dev[0].wait_event(["RX-ANQP"], timeout=1)
1133     if ev is None or "Venue Name" not in ev:
1134         raise Exception("Did not receive Venue Name")
1135
1136     ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=10)
1137     if ev is None:
1138         raise Exception("ANQP-QUERY-DONE event not seen")
1139     if "result=SUCCESS" not in ev:
1140         raise Exception("Unexpected result: " + ev)
1141
1142     out = run_tshark(os.path.join(params['logdir'], "hwsim0.pcapng"),
1143                      "wlan_mgt.fixed.category_code == 4 && (wlan_mgt.fixed.publicact == 0x0a || wlan_mgt.fixed.publicact == 0x0b)",
1144                      display=["wlan.bssid"])
1145     res = out.splitlines()
1146     if len(res) != 2:
1147         raise Exception("Unexpected number of GAS frames")
1148     if res[0] != bssid:
1149         raise Exception("GAS request used unexpected Address3 field value: " + res[0])
1150     if res[1] != bssid:
1151         raise Exception("GAS response used unexpected Address3 field value: " + res[1])
1152
1153 def test_gas_anqp_address3_ap_forced(dev, apdev, params):
1154     """GAS/ANQP query using IEEE 802.11 compliant Address 3 value on AP"""
1155     hapd = start_ap(apdev[0])
1156     bssid = apdev[0]['bssid']
1157     hapd.set("gas_address3", "1")
1158
1159     dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
1160     if "OK" not in dev[0].request("ANQP_GET " + bssid + " 258"):
1161         raise Exception("ANQP_GET command failed")
1162
1163     ev = dev[0].wait_event(["GAS-QUERY-START"], timeout=5)
1164     if ev is None:
1165         raise Exception("GAS query start timed out")
1166
1167     ev = dev[0].wait_event(["GAS-QUERY-DONE"], timeout=10)
1168     if ev is None:
1169         raise Exception("GAS query timed out")
1170
1171     ev = dev[0].wait_event(["RX-ANQP"], timeout=1)
1172     if ev is None or "Venue Name" not in ev:
1173         raise Exception("Did not receive Venue Name")
1174
1175     ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=10)
1176     if ev is None:
1177         raise Exception("ANQP-QUERY-DONE event not seen")
1178     if "result=SUCCESS" not in ev:
1179         raise Exception("Unexpected result: " + ev)
1180
1181     out = run_tshark(os.path.join(params['logdir'], "hwsim0.pcapng"),
1182                      "wlan_mgt.fixed.category_code == 4 && (wlan_mgt.fixed.publicact == 0x0a || wlan_mgt.fixed.publicact == 0x0b)",
1183                      display=["wlan.bssid"])
1184     res = out.splitlines()
1185     if len(res) != 2:
1186         raise Exception("Unexpected number of GAS frames")
1187     if res[0] != bssid:
1188         raise Exception("GAS request used unexpected Address3 field value: " + res[0])
1189     if res[1] != 'ff:ff:ff:ff:ff:ff':
1190         raise Exception("GAS response used unexpected Address3 field value: " + res[1])
1191
1192 def test_gas_anqp_address3_ap_non_compliant(dev, apdev, params):
1193     """GAS/ANQP query using IEEE 802.11 non-compliant Address 3 (AP)"""
1194     try:
1195         _test_gas_anqp_address3_ap_non_compliant(dev, apdev, params)
1196     finally:
1197         dev[0].request("SET gas_address3 0")
1198
1199 def _test_gas_anqp_address3_ap_non_compliant(dev, apdev, params):
1200     hapd = start_ap(apdev[0])
1201     bssid = apdev[0]['bssid']
1202     hapd.set("gas_address3", "2")
1203
1204     if "OK" not in dev[0].request("SET gas_address3 1"):
1205         raise Exception("Failed to set gas_address3")
1206
1207     dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
1208     if "OK" not in dev[0].request("ANQP_GET " + bssid + " 258"):
1209         raise Exception("ANQP_GET command failed")
1210
1211     ev = dev[0].wait_event(["GAS-QUERY-START"], timeout=5)
1212     if ev is None:
1213         raise Exception("GAS query start timed out")
1214
1215     ev = dev[0].wait_event(["GAS-QUERY-DONE"], timeout=10)
1216     if ev is None:
1217         raise Exception("GAS query timed out")
1218
1219     ev = dev[0].wait_event(["RX-ANQP"], timeout=1)
1220     if ev is None or "Venue Name" not in ev:
1221         raise Exception("Did not receive Venue Name")
1222
1223     ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=10)
1224     if ev is None:
1225         raise Exception("ANQP-QUERY-DONE event not seen")
1226     if "result=SUCCESS" not in ev:
1227         raise Exception("Unexpected result: " + ev)
1228
1229     out = run_tshark(os.path.join(params['logdir'], "hwsim0.pcapng"),
1230                      "wlan_mgt.fixed.category_code == 4 && (wlan_mgt.fixed.publicact == 0x0a || wlan_mgt.fixed.publicact == 0x0b)",
1231                      display=["wlan.bssid"])
1232     res = out.splitlines()
1233     if len(res) != 2:
1234         raise Exception("Unexpected number of GAS frames")
1235     if res[0] != 'ff:ff:ff:ff:ff:ff':
1236         raise Exception("GAS request used unexpected Address3 field value: " + res[0])
1237     if res[1] != bssid:
1238         raise Exception("GAS response used unexpected Address3 field value: " + res[1])