1 # Hotspot 2.0 tests
2 # Copyright (c) 2013-2019, Jouni Malinen <j@w1.fi>
3 #
4 # This software may be distributed under the terms of the BSD license.
5 # See README for more details.
6 
7 from remotehost import remote_compatible
8 import base64
9 import binascii
10 import struct
11 import time
12 import logging
13 logger = logging.getLogger()
14 import os
15 import os.path
16 import socket
17 import subprocess
18 
19 import hostapd
20 from utils import *
21 import hwsim_utils
22 from tshark import run_tshark
23 from wlantest import Wlantest
24 from wpasupplicant import WpaSupplicant
25 from wlantest import WlantestCapture
26 from test_ap_eap import check_eap_capa, check_domain_match_full
27 from test_gas import gas_rx, parse_gas, action_response, anqp_initial_resp, send_gas_resp, ACTION_CATEG_PUBLIC, GAS_INITIAL_RESPONSE
28 
29 def hs20_ap_params(ssid="test-hs20"):
30     params = hostapd.wpa2_params(ssid=ssid)
31     params['wpa_key_mgmt'] = "WPA-EAP"
32     params['ieee80211w'] = "1"
33     params['ieee8021x'] = "1"
34     params['auth_server_addr'] = "127.0.0.1"
35     params['auth_server_port'] = "1812"
36     params['auth_server_shared_secret'] = "radius"
37     params['interworking'] = "1"
38     params['access_network_type'] = "14"
39     params['internet'] = "1"
40     params['asra'] = "0"
41     params['esr'] = "0"
42     params['uesa'] = "0"
43     params['venue_group'] = "7"
44     params['venue_type'] = "1"
45     params['venue_name'] = ["eng:Example venue", "fin:Esimerkkipaikka"]
46     params['roaming_consortium'] = ["112233", "1020304050", "010203040506",
47                                     "fedcba"]
48     params['domain_name'] = "example.com,another.example.com"
49     params['nai_realm'] = ["0,example.com,13[5:6],21[2:4][5:7]",
50                            "0,another.example.com"]
51     params['hs20'] = "1"
52     params['hs20_wan_metrics'] = "01:8000:1000:80:240:3000"
53     params['hs20_conn_capab'] = ["1:0:2", "6:22:1", "17:5060:0"]
54     params['hs20_operating_class'] = "5173"
55     params['anqp_3gpp_cell_net'] = "244,91"
56     return params
57 
58 def check_auto_select(dev, bssid, hapd=None):
59     dev.scan_for_bss(bssid, freq="2412")
60     dev.request("INTERWORKING_SELECT auto freq=2412")
61     ev = dev.wait_connected(timeout=15)
62     if bssid not in ev:
63         raise Exception("Connected to incorrect network")
64     if hapd:
65         hapd.wait_sta()
66     dev.request("REMOVE_NETWORK all")
67     dev.wait_disconnected()
68     dev.dump_monitor()
69     if hapd:
70         hapd.wait_sta_disconnect()
71 
72 def interworking_select(dev, bssid, type=None, no_match=False, freq=None):
73     dev.dump_monitor()
74     if bssid and freq and not no_match:
75         dev.scan_for_bss(bssid, freq=freq)
76     freq_extra = " freq=" + str(freq) if freq else ""
77     dev.request("INTERWORKING_SELECT" + freq_extra)
78     ev = dev.wait_event(["INTERWORKING-AP", "INTERWORKING-NO-MATCH"],
79                         timeout=15)
80     if ev is None:
81         raise Exception("Network selection timed out")
82     if no_match:
83         if "INTERWORKING-NO-MATCH" not in ev:
84             raise Exception("Unexpected network match")
85         return
86     if "INTERWORKING-NO-MATCH" in ev:
87         logger.info("Matching network not found - try again")
88         dev.dump_monitor()
89         dev.request("INTERWORKING_SELECT" + freq_extra)
90         ev = dev.wait_event(["INTERWORKING-AP", "INTERWORKING-NO-MATCH"],
91                             timeout=15)
92         if ev is None:
93             raise Exception("Network selection timed out")
94         if "INTERWORKING-NO-MATCH" in ev:
95             raise Exception("Matching network not found")
96     if bssid and bssid not in ev:
97         raise Exception("Unexpected BSSID in match")
98     if type and "type=" + type not in ev:
99         raise Exception("Network type not recognized correctly")
100 
101 def check_sp_type(dev, sp_type):
102     type = dev.get_status_field("sp_type")
103     if type is None:
104         raise Exception("sp_type not available")
105     if type != sp_type:
106         raise Exception("sp_type did not indicate %s network" % sp_type)
107 
108 def hlr_auc_gw_available():
109     if not os.path.exists("/tmp/hlr_auc_gw.sock"):
110         raise HwsimSkip("No hlr_auc_gw socket available")
111     if not os.path.exists("../../hostapd/hlr_auc_gw"):
112         raise HwsimSkip("No hlr_auc_gw available")
113 
114 def interworking_ext_sim_connect(dev, bssid, method):
115     dev.request("INTERWORKING_CONNECT " + bssid)
116     interworking_ext_sim_auth(dev, method)
117 
118 def interworking_ext_sim_auth(dev, method):
119     ev = dev.wait_event(["CTRL-EVENT-EAP-METHOD"], timeout=15)
120     if ev is None:
121         raise Exception("Network connected timed out")
122     if "(" + method + ")" not in ev:
123         raise Exception("Unexpected EAP method selection")
124 
125     ev = dev.wait_event(["CTRL-REQ-SIM"], timeout=15)
126     if ev is None:
127         raise Exception("Wait for external SIM processing request timed out")
128     p = ev.split(':', 2)
129     if p[1] != "GSM-AUTH":
130         raise Exception("Unexpected CTRL-REQ-SIM type")
131     id = p[0].split('-')[3]
132     rand = p[2].split(' ')[0]
133 
134     res = subprocess.check_output(["../../hostapd/hlr_auc_gw",
135                                    "-m",
136                                    "auth_serv/hlr_auc_gw.milenage_db",
137                                    "GSM-AUTH-REQ 232010000000000 " + rand]).decode()
138     if "GSM-AUTH-RESP" not in res:
139         raise Exception("Unexpected hlr_auc_gw response")
140     resp = res.split(' ')[2].rstrip()
141 
142     dev.request("CTRL-RSP-SIM-" + id + ":GSM-AUTH:" + resp)
143     dev.wait_connected(timeout=15)
144 
145 def interworking_connect(dev, bssid, method):
146     dev.request("INTERWORKING_CONNECT " + bssid)
147     interworking_auth(dev, method)
148 
149 def interworking_auth(dev, method):
150     ev = dev.wait_event(["CTRL-EVENT-EAP-METHOD"], timeout=15)
151     if ev is None:
152         raise Exception("Network connected timed out")
153     if "(" + method + ")" not in ev:
154         raise Exception("Unexpected EAP method selection")
155 
156     dev.wait_connected(timeout=15)
157 
158 def check_probe_resp(wt, bssid_unexpected, bssid_expected):
159     if bssid_unexpected:
160         count = wt.get_bss_counter("probe_response", bssid_unexpected)
161         if count > 0:
162             raise Exception("Unexpected Probe Response frame from AP")
163 
164     if bssid_expected:
165         count = wt.get_bss_counter("probe_response", bssid_expected)
166         if count == 0:
167             raise Exception("No Probe Response frame from AP")
168 
169 def test_ap_anqp_sharing(dev, apdev):
170     """ANQP sharing within ESS and explicit unshare"""
171     check_eap_capa(dev[0], "MSCHAPV2")
172     dev[0].flush_scan_cache()
173 
174     bssid = apdev[0]['bssid']
175     params = hs20_ap_params()
176     params['hessid'] = bssid
177     hostapd.add_ap(apdev[0], params)
178 
179     bssid2 = apdev[1]['bssid']
180     params = hs20_ap_params()
181     params['hessid'] = bssid
182     params['nai_realm'] = ["0,example.com,13[5:6],21[2:4][5:7]"]
183     hostapd.add_ap(apdev[1], params)
184 
185     dev[0].hs20_enable()
186     id = dev[0].add_cred_values({'realm': "example.com", 'username': "test",
187                                  'password': "secret",
188                                  'domain': "example.com"})
189     logger.info("Normal network selection with shared ANQP results")
190     dev[0].scan_for_bss(bssid, freq="2412")
191     dev[0].scan_for_bss(bssid2, freq="2412")
192     interworking_select(dev[0], None, "home", freq="2412")
193     dev[0].dump_monitor()
194     state = dev[0].get_status_field('wpa_state')
195     if state != "DISCONNECTED":
196         raise Exception("Unexpected wpa_state after INTERWORKING_SELECT: " + state)
197 
198     logger.debug("BSS entries:\n" + dev[0].request("BSS RANGE=ALL"))
199     res1 = dev[0].get_bss(bssid)
200     res2 = dev[0].get_bss(bssid2)
201     if 'anqp_nai_realm' not in res1:
202         raise Exception("anqp_nai_realm not found for AP1")
203     if 'anqp_nai_realm' not in res2:
204         raise Exception("anqp_nai_realm not found for AP2")
205     if res1['anqp_nai_realm'] != res2['anqp_nai_realm']:
206         raise Exception("ANQP results were not shared between BSSes")
207 
208     logger.info("Explicit ANQP request to unshare ANQP results")
209     dev[0].request("ANQP_GET " + bssid + " 263")
210     ev = dev[0].wait_event(["RX-ANQP"], timeout=5)
211     if ev is None:
212         raise Exception("ANQP operation timed out")
213 
214     dev[0].request("ANQP_GET " + bssid2 + " 263")
215     ev = dev[0].wait_event(["RX-ANQP"], timeout=5)
216     if ev is None:
217         raise Exception("ANQP operation timed out")
218 
219     res1 = dev[0].get_bss(bssid)
220     res2 = dev[0].get_bss(bssid2)
221     if res1['anqp_nai_realm'] == res2['anqp_nai_realm']:
222         raise Exception("ANQP results were not unshared")
223 
224 def test_ap_anqp_domain_id(dev, apdev):
225     """ANQP Domain ID"""
226     check_eap_capa(dev[0], "MSCHAPV2")
227     dev[0].flush_scan_cache()
228 
229     bssid = apdev[0]['bssid']
230     params = hs20_ap_params()
231     params['hessid'] = bssid
232     params['anqp_domain_id'] = '1234'
233     hostapd.add_ap(apdev[0], params)
234 
235     bssid2 = apdev[1]['bssid']
236     params = hs20_ap_params()
237     params['hessid'] = bssid
238     params['anqp_domain_id'] = '1234'
239     hostapd.add_ap(apdev[1], params)
240 
241     dev[0].hs20_enable()
242     id = dev[0].add_cred_values({'realm': "example.com", 'username': "test",
243                                  'password': "secret",
244                                  'domain': "example.com"})
245     dev[0].scan_for_bss(bssid, freq="2412")
246     dev[0].scan_for_bss(bssid2, freq="2412")
247     interworking_select(dev[0], None, "home", freq="2412")
248 
249 def test_ap_anqp_no_sharing_diff_ess(dev, apdev):
250     """ANQP no sharing between ESSs"""
251     check_eap_capa(dev[0], "MSCHAPV2")
252     dev[0].flush_scan_cache()
253 
254     bssid = apdev[0]['bssid']
255     params = hs20_ap_params()
256     params['hessid'] = bssid
257     hostapd.add_ap(apdev[0], params)
258 
259     bssid2 = apdev[1]['bssid']
260     params = hs20_ap_params(ssid="test-hs20-another")
261     params['hessid'] = bssid
262     params['nai_realm'] = ["0,example.com,13[5:6],21[2:4][5:7]"]
263     hostapd.add_ap(apdev[1], params)
264 
265     dev[0].hs20_enable()
266     id = dev[0].add_cred_values({'realm': "example.com", 'username': "test",
267                                  'password': "secret",
268                                  'domain': "example.com"})
269     logger.info("Normal network selection with shared ANQP results")
270     dev[0].scan_for_bss(bssid, freq="2412")
271     dev[0].scan_for_bss(bssid2, freq="2412")
272     interworking_select(dev[0], None, "home", freq="2412")
273 
274 def test_ap_anqp_no_sharing_missing_info(dev, apdev):
275     """ANQP no sharing due to missing information"""
276     check_eap_capa(dev[0], "MSCHAPV2")
277     dev[0].flush_scan_cache()
278 
279     bssid = apdev[0]['bssid']
280     params = hs20_ap_params()
281     params['hessid'] = bssid
282     del params['roaming_consortium']
283     del params['domain_name']
284     del params['anqp_3gpp_cell_net']
285     del params['nai_realm']
286     hostapd.add_ap(apdev[0], params)
287 
288     bssid2 = apdev[1]['bssid']
289     params = hs20_ap_params()
290     params['hessid'] = bssid
291     params['nai_realm'] = ["0,example.com,13[5:6],21[2:4][5:7]"]
292     hostapd.add_ap(apdev[1], params)
293 
294     dev[0].hs20_enable()
295     id = dev[0].add_cred_values({'realm': "example.com", 'username': "test",
296                                  'password': "secret",
297                                  'domain': "example.com"})
298     logger.info("Normal network selection with shared ANQP results")
299     dev[0].scan_for_bss(bssid, freq="2412")
300     dev[0].scan_for_bss(bssid2, freq="2412")
301     interworking_select(dev[0], None, "home", freq="2412")
302 
303 def test_ap_anqp_sharing_oom(dev, apdev):
304     """ANQP sharing within ESS and explicit unshare OOM"""
305     check_eap_capa(dev[0], "MSCHAPV2")
306     dev[0].flush_scan_cache()
307 
308     bssid = apdev[0]['bssid']
309     params = hs20_ap_params()
310     params['hessid'] = bssid
311     hostapd.add_ap(apdev[0], params)
312 
313     bssid2 = apdev[1]['bssid']
314     params = hs20_ap_params()
315     params['hessid'] = bssid
316     params['nai_realm'] = ["0,example.com,13[5:6],21[2:4][5:7]"]
317     hostapd.add_ap(apdev[1], params)
318 
319     dev[0].hs20_enable()
320     id = dev[0].add_cred_values({'realm': "example.com", 'username': "test",
321                                  'password': "secret",
322                                  'domain': "example.com"})
323     dev[0].scan_for_bss(bssid, freq="2412")
324     dev[0].scan_for_bss(bssid2, freq="2412")
325     interworking_select(dev[0], None, "home", freq="2412")
326     dev[0].dump_monitor()
327 
328     with alloc_fail(dev[0], 1, "wpa_bss_anqp_clone"):
329         dev[0].request("ANQP_GET " + bssid + " 263")
330         ev = dev[0].wait_event(["RX-ANQP"], timeout=5)
331         if ev is None:
332             raise Exception("ANQP operation timed out")
333 
334 def test_ap_nai_home_realm_query(dev, apdev):
335     """NAI Home Realm Query"""
336     check_eap_capa(dev[0], "MSCHAPV2")
337     bssid = apdev[0]['bssid']
338     params = hs20_ap_params()
339     params['nai_realm'] = ["0,example.com,13[5:6],21[2:4][5:7]",
340                            "0,another.example.org"]
341     hostapd.add_ap(apdev[0], params)
342 
343     dev[0].scan(freq="2412")
344     dev[0].request("HS20_GET_NAI_HOME_REALM_LIST " + bssid + " realm=example.com")
345     ev = dev[0].wait_event(["RX-ANQP"], timeout=5)
346     if ev is None:
347         raise Exception("ANQP operation timed out")
348     nai1 = dev[0].get_bss(bssid)['anqp_nai_realm']
349     dev[0].dump_monitor()
350 
351     dev[0].request("ANQP_GET " + bssid + " 263")
352     ev = dev[0].wait_event(["RX-ANQP"], timeout=5)
353     if ev is None:
354         raise Exception("ANQP operation timed out")
355     nai2 = dev[0].get_bss(bssid)['anqp_nai_realm']
356 
357     if len(nai1) >= len(nai2):
358         raise Exception("Unexpected NAI Realm list response lengths")
359     if binascii.hexlify(b"example.com").decode() not in nai1:
360         raise Exception("Home realm not reported")
361     if binascii.hexlify(b"example.org").decode() in nai1:
362         raise Exception("Non-home realm reported")
363     if binascii.hexlify(b"example.com").decode() not in nai2:
364         raise Exception("Home realm not reported in wildcard query")
365     if binascii.hexlify(b"example.org").decode() not in nai2:
366         raise Exception("Non-home realm not reported in wildcard query ")
367 
368     cmds = ["foo",
369             "00:11:22:33:44:55 123",
370             "00:11:22:33:44:55 qq"]
371     for cmd in cmds:
372         if "FAIL" not in dev[0].request("HS20_GET_NAI_HOME_REALM_LIST " + cmd):
373             raise Exception("Invalid HS20_GET_NAI_HOME_REALM_LIST accepted: " + cmd)
374 
375     dev[0].dump_monitor()
376     if "OK" not in dev[0].request("HS20_GET_NAI_HOME_REALM_LIST " + bssid):
377         raise Exception("HS20_GET_NAI_HOME_REALM_LIST failed")
378     ev = dev[0].wait_event(["GAS-QUERY-DONE"], timeout=10)
379     if ev is None:
380         raise Exception("ANQP operation timed out")
381     ev = dev[0].wait_event(["RX-ANQP"], timeout=0.1)
382     if ev is not None:
383         raise Exception("Unexpected ANQP response: " + ev)
384 
385     dev[0].dump_monitor()
386     if "OK" not in dev[0].request("HS20_GET_NAI_HOME_REALM_LIST " + bssid + " 01000b6578616d706c652e636f6d"):
387         raise Exception("HS20_GET_NAI_HOME_REALM_LIST failed")
388     ev = dev[0].wait_event(["RX-ANQP"], timeout=10)
389     if ev is None:
390         raise Exception("No ANQP response")
391     if "NAI Realm list" not in ev:
392         raise Exception("Missing NAI Realm list: " + ev)
393 
394     dev[0].add_cred_values({'realm': "example.com", 'username': "test",
395                             'password': "secret",
396                             'domain': "example.com"})
397     dev[0].dump_monitor()
398     if "OK" not in dev[0].request("HS20_GET_NAI_HOME_REALM_LIST " + bssid):
399         raise Exception("HS20_GET_NAI_HOME_REALM_LIST failed")
400     ev = dev[0].wait_event(["RX-ANQP"], timeout=10)
401     if ev is None:
402         raise Exception("No ANQP response")
403     if "NAI Realm list" not in ev:
404         raise Exception("Missing NAI Realm list: " + ev)
405 
406 @remote_compatible
407 def test_ap_interworking_scan_filtering(dev, apdev):
408     """Interworking scan filtering with HESSID and access network type"""
409     try:
410         _test_ap_interworking_scan_filtering(dev, apdev)
411     finally:
412         dev[0].request("SET hessid 00:00:00:00:00:00")
413         dev[0].request("SET access_network_type 15")
414 
415 def _test_ap_interworking_scan_filtering(dev, apdev):
416     bssid = apdev[0]['bssid']
417     params = hs20_ap_params()
418     ssid = "test-hs20-ap1"
419     params['ssid'] = ssid
420     params['hessid'] = bssid
421     hapd0 = hostapd.add_ap(apdev[0], params)
422 
423     bssid2 = apdev[1]['bssid']
424     params = hs20_ap_params()
425     ssid2 = "test-hs20-ap2"
426     params['ssid'] = ssid2
427     params['hessid'] = bssid2
428     params['access_network_type'] = "1"
429     del params['venue_group']
430     del params['venue_type']
431     hostapd.add_ap(apdev[1], params)
432 
433     dev[0].hs20_enable()
434 
435     Wlantest.setup(hapd0)
436     wt = Wlantest()
437     wt.flush()
438 
439     # Make sure wlantest has seen both BSSs to avoid issues in trying to clear
440     # counters for non-existing BSS.
441     dev[0].scan_for_bss(bssid, freq="2412")
442     dev[0].scan_for_bss(bssid2, freq="2412")
443     wt.clear_bss_counters(bssid)
444     wt.clear_bss_counters(bssid2)
445 
446     logger.info("Check probe request filtering based on HESSID")
447 
448     dev[0].request("SET hessid " + bssid2)
449     dev[0].scan(freq="2412")
450     time.sleep(0.03)
451     check_probe_resp(wt, bssid, bssid2)
452 
453     logger.info("Check probe request filtering based on access network type")
454 
455     wt.clear_bss_counters(bssid)
456     wt.clear_bss_counters(bssid2)
457     dev[0].request("SET hessid 00:00:00:00:00:00")
458     dev[0].request("SET access_network_type 14")
459     dev[0].scan(freq="2412")
460     time.sleep(0.03)
461     check_probe_resp(wt, bssid2, bssid)
462 
463     wt.clear_bss_counters(bssid)
464     wt.clear_bss_counters(bssid2)
465     dev[0].request("SET hessid 00:00:00:00:00:00")
466     dev[0].request("SET access_network_type 1")
467     dev[0].scan(freq="2412")
468     time.sleep(0.03)
469     check_probe_resp(wt, bssid, bssid2)
470 
471     logger.info("Check probe request filtering based on HESSID and ANT")
472 
473     wt.clear_bss_counters(bssid)
474     wt.clear_bss_counters(bssid2)
475     dev[0].request("SET hessid " + bssid)
476     dev[0].request("SET access_network_type 14")
477     dev[0].scan(freq="2412")
478     time.sleep(0.03)
479     check_probe_resp(wt, bssid2, bssid)
480 
481     wt.clear_bss_counters(bssid)
482     wt.clear_bss_counters(bssid2)
483     dev[0].request("SET hessid " + bssid2)
484     dev[0].request("SET access_network_type 14")
485     dev[0].scan(freq="2412")
486     time.sleep(0.03)
487     check_probe_resp(wt, bssid, None)
488     check_probe_resp(wt, bssid2, None)
489 
490     wt.clear_bss_counters(bssid)
491     wt.clear_bss_counters(bssid2)
492     dev[0].request("SET hessid " + bssid)
493     dev[0].request("SET access_network_type 1")
494     dev[0].scan(freq="2412")
495     time.sleep(0.03)
496     check_probe_resp(wt, bssid, None)
497     check_probe_resp(wt, bssid2, None)
498 
499 def test_ap_hs20_select(dev, apdev):
500     """Hotspot 2.0 network selection"""
501     bssid = apdev[0]['bssid']
502     params = hs20_ap_params()
503     params['hessid'] = bssid
504     hostapd.add_ap(apdev[0], params)
505     dev[0].flush_scan_cache()
506 
507     dev[0].hs20_enable()
508     id = dev[0].add_cred_values({'realm': "example.com", 'username': "test",
509                                  'password': "secret",
510                                  'domain': "example.com"})
511     interworking_select(dev[0], bssid, "home")
512 
513     dev[0].remove_cred(id)
514     id = dev[0].add_cred_values({'realm': "example.com", 'username': "test",
515                                  'password': "secret",
516                                  'domain': "no.match.example.com"})
517     interworking_select(dev[0], bssid, "roaming", freq="2412")
518 
519     dev[0].set_cred_quoted(id, "realm", "no.match.example.com")
520     interworking_select(dev[0], bssid, no_match=True, freq="2412")
521 
522     res = dev[0].request("SCAN_RESULTS")
523     if "[HS20]" not in res:
524         raise Exception("HS20 flag missing from scan results: " + res)
525 
526     bssid2 = apdev[1]['bssid']
527     params = hs20_ap_params()
528     params['nai_realm'] = ["0,example.org,21"]
529     params['hessid'] = bssid2
530     params['domain_name'] = "example.org"
531     hostapd.add_ap(apdev[1], params)
532     dev[0].remove_cred(id)
533     id = dev[0].add_cred_values({'realm': "example.org", 'username': "test",
534                                  'password': "secret",
535                                  'domain': "example.org"})
536     interworking_select(dev[0], bssid2, "home", freq="2412")
537 
538 def hs20_simulated_sim(dev, ap, method, imsi_privacy=False,
539                        imsi_privacy_attr=False):
540     bssid = ap['bssid']
541     params = hs20_ap_params()
542     params['hessid'] = bssid
543     params['anqp_3gpp_cell_net'] = "555,444"
544     params['domain_name'] = "wlan.mnc444.mcc555.3gppnetwork.org"
545     hostapd.add_ap(ap, params)
546 
547     dev.hs20_enable()
548     params = {'imsi': "555444-333222111", 'eap': method,
549               'milenage': "5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123"}
550     if imsi_privacy:
551         check_imsi_privacy_support(dev)
552         params['imsi_privacy_cert'] = "auth_serv/imsi-privacy-cert.pem"
553         if imsi_privacy_attr:
554             params['imsi_privacy_attr'] = "Identifier=1234567"
555     dev.add_cred_values(params)
556     interworking_select(dev, bssid, "home", freq="2412")
557     interworking_connect(dev, bssid, method)
558     check_sp_type(dev, "home")
559 
560 def test_ap_hs20_sim(dev, apdev):
561     """Hotspot 2.0 with simulated SIM and EAP-SIM"""
562     hlr_auc_gw_available()
563     hs20_simulated_sim(dev[0], apdev[0], "SIM")
564     dev[0].request("INTERWORKING_SELECT auto freq=2412")
565     ev = dev[0].wait_event(["INTERWORKING-ALREADY-CONNECTED"], timeout=15)
566     if ev is None:
567         raise Exception("Timeout on already-connected event")
568 
569 def test_ap_hs20_sim_imsi_privacy(dev, apdev):
570     """Hotspot 2.0 with simulated SIM and EAP-SIM with IMSI privacy"""
571     hlr_auc_gw_available()
572     hs20_simulated_sim(dev[0], apdev[0], "SIM", imsi_privacy=True)
573 
574 def test_ap_hs20_sim_invalid(dev, apdev):
575     """Hotspot 2.0 with simulated SIM and EAP-SIM - invalid IMSI"""
576     hlr_auc_gw_available()
577     bssid = apdev[0]['bssid']
578     params = hs20_ap_params()
579     params['hessid'] = bssid
580     params['anqp_3gpp_cell_net'] = "555,444"
581     params['domain_name'] = "wlan.mnc444.mcc555.3gppnetwork.org"
582     hostapd.add_ap(apdev[0], params)
583 
584     dev[0].hs20_enable()
585     dev[0].add_cred_values({'imsi': "555444-3332221110", 'eap': "SIM",
586                             'milenage': "5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123"})
587     # This hits "No valid IMSI available" in build_root_nai()
588     interworking_select(dev[0], bssid, freq="2412")
589 
590 def test_ap_hs20_sim_oom(dev, apdev):
591     """Hotspot 2.0 with simulated SIM and EAP-SIM - OOM"""
592     hlr_auc_gw_available()
593     bssid = apdev[0]['bssid']
594     params = hs20_ap_params()
595     params['hessid'] = bssid
596     params['anqp_3gpp_cell_net'] = "555,444"
597     params['domain_name'] = "wlan.mnc444.mcc555.3gppnetwork.org"
598     hostapd.add_ap(apdev[0], params)
599 
600     dev[0].hs20_enable()
601     dev[0].add_cred_values({'imsi': "555444-333222111", 'eap': "SIM",
602                             'milenage': "5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123"})
603     dev[0].scan_for_bss(bssid, freq=2412)
604     interworking_select(dev[0], bssid, freq="2412")
605 
606     with alloc_fail(dev[0], 1, "wpa_config_add_network;interworking_connect_3gpp"):
607         dev[0].request("INTERWORKING_CONNECT " + bssid)
608         wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
609 
610     with alloc_fail(dev[0], 1, "=interworking_connect_3gpp"):
611         dev[0].request("INTERWORKING_CONNECT " + bssid)
612         wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
613 
614 def test_ap_hs20_aka(dev, apdev):
615     """Hotspot 2.0 with simulated USIM and EAP-AKA"""
616     hlr_auc_gw_available()
617     hs20_simulated_sim(dev[0], apdev[0], "AKA")
618 
619 def test_ap_hs20_aka_imsi_privacy(dev, apdev):
620     """Hotspot 2.0 with simulated USIM and EAP-AKA with IMSI privacy"""
621     hlr_auc_gw_available()
622     hs20_simulated_sim(dev[0], apdev[0], "AKA", imsi_privacy=True)
623 
624 def test_ap_hs20_aka_imsi_privacy_attr(dev, apdev):
625     """Hotspot 2.0 with simulated USIM and EAP-AKA with IMSI privacy/attr"""
626     hlr_auc_gw_available()
627     hs20_simulated_sim(dev[0], apdev[0], "AKA", imsi_privacy=True,
628                        imsi_privacy_attr=True)
629 
630 def test_ap_hs20_aka_prime(dev, apdev):
631     """Hotspot 2.0 with simulated USIM and EAP-AKA'"""
632     hlr_auc_gw_available()
633     hs20_simulated_sim(dev[0], apdev[0], "AKA'")
634 
635 def test_ap_hs20_aka_prime_imsi_privacy(dev, apdev):
636     """Hotspot 2.0 with simulated USIM and EAP-AKA with IMSI privacy'"""
637     hlr_auc_gw_available()
638     hs20_simulated_sim(dev[0], apdev[0], "AKA'", imsi_privacy=True)
639 
640 def test_ap_hs20_ext_sim(dev, apdev):
641     """Hotspot 2.0 with external SIM processing"""
642     hlr_auc_gw_available()
643     bssid = apdev[0]['bssid']
644     params = hs20_ap_params()
645     params['hessid'] = bssid
646     params['anqp_3gpp_cell_net'] = "232,01"
647     params['domain_name'] = "wlan.mnc001.mcc232.3gppnetwork.org"
648     hostapd.add_ap(apdev[0], params)
649 
650     dev[0].hs20_enable()
651     try:
652         dev[0].request("SET external_sim 1")
653         dev[0].add_cred_values({'imsi': "23201-0000000000", 'eap': "SIM"})
654         interworking_select(dev[0], bssid, "home", freq="2412")
655         interworking_ext_sim_connect(dev[0], bssid, "SIM")
656         check_sp_type(dev[0], "home")
657     finally:
658         dev[0].request("SET external_sim 0")
659 
660 def test_ap_hs20_ext_sim_roaming(dev, apdev):
661     """Hotspot 2.0 with external SIM processing in roaming network"""
662     hlr_auc_gw_available()
663     bssid = apdev[0]['bssid']
664     params = hs20_ap_params()
665     params['hessid'] = bssid
666     params['anqp_3gpp_cell_net'] = "244,91;310,026;232,01;234,56"
667     params['domain_name'] = "wlan.mnc091.mcc244.3gppnetwork.org"
668     hostapd.add_ap(apdev[0], params)
669 
670     dev[0].hs20_enable()
671     try:
672         dev[0].request("SET external_sim 1")
673         dev[0].add_cred_values({'imsi': "23201-0000000000", 'eap': "SIM"})
674         interworking_select(dev[0], bssid, "roaming", freq="2412")
675         interworking_ext_sim_connect(dev[0], bssid, "SIM")
676         check_sp_type(dev[0], "roaming")
677     finally:
678         dev[0].request("SET external_sim 0")
679 
680 def test_ap_hs20_username(dev, apdev):
681     """Hotspot 2.0 connection in username/password credential"""
682     check_eap_capa(dev[0], "MSCHAPV2")
683     bssid = apdev[0]['bssid']
684     params = hs20_ap_params()
685     params['hessid'] = bssid
686     params['disable_dgaf'] = '1'
687     hapd = hostapd.add_ap(apdev[0], params)
688 
689     dev[0].hs20_enable()
690     id = dev[0].add_cred_values({'realm': "example.com",
691                                  'username': "hs20-test",
692                                  'password': "password",
693                                  'ca_cert': "auth_serv/ca.pem",
694                                  'domain': "example.com",
695                                  'update_identifier': "1234"})
696     interworking_select(dev[0], bssid, "home", freq="2412")
697     interworking_connect(dev[0], bssid, "TTLS")
698     check_sp_type(dev[0], "home")
699     status = dev[0].get_status()
700     if status['pairwise_cipher'] != "CCMP":
701         raise Exception("Unexpected pairwise cipher")
702     if status['hs20'] != "3":
703         raise Exception("Unexpected HS 2.0 support indication")
704     hapd.wait_sta()
705     sta = hapd.get_sta(dev[0].own_addr())
706     if sta['dot1xAuthSessionUserName'] != "anonymous@example.com":
707         raise Exception("Unexpected anonymous identity: " + sta['dot1xAuthSessionUserName'])
708 
709     dev[1].connect("test-hs20", key_mgmt="WPA-EAP", eap="TTLS",
710                    identity="hs20-test", password="password",
711                    ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
712                    scan_freq="2412")
713 
714 def test_ap_hs20_username_with_realm(dev, apdev):
715     """Hotspot 2.0 connection in username-with-realm/password credential"""
716     check_eap_capa(dev[0], "MSCHAPV2")
717     bssid = apdev[0]['bssid']
718     params = hs20_ap_params()
719     params['hessid'] = bssid
720     params['disable_dgaf'] = '1'
721     hapd = hostapd.add_ap(apdev[0], params)
722 
723     dev[0].hs20_enable()
724     id = dev[0].add_cred_values({'realm': "example.com",
725                                  'username': "hs20-test@inner.com",
726                                  'password': "password2",
727                                  'ca_cert': "auth_serv/ca.pem",
728                                  'domain': "example.com"})
729     interworking_select(dev[0], bssid, "home", freq="2412")
730     interworking_connect(dev[0], bssid, "TTLS")
731     check_sp_type(dev[0], "home")
732     hapd.wait_sta()
733     sta = hapd.get_sta(dev[0].own_addr())
734     if sta['dot1xAuthSessionUserName'] != "anonymous@example.com":
735         raise Exception("Unexpected anonymous identity: " + sta['dot1xAuthSessionUserName'])
736 
737 def test_ap_hs20_connect_api(dev, apdev):
738     """Hotspot 2.0 connection with connect API"""
739     check_eap_capa(dev[0], "MSCHAPV2")
740     bssid = apdev[0]['bssid']
741     params = hs20_ap_params()
742     params['hessid'] = bssid
743     params['disable_dgaf'] = '1'
744     hostapd.add_ap(apdev[0], params)
745 
746     wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
747     wpas.interface_add("wlan5", drv_params="force_connect_cmd=1")
748     wpas.hs20_enable()
749     wpas.flush_scan_cache()
750     id = wpas.add_cred_values({'realm': "example.com",
751                                'username': "hs20-test",
752                                'password': "password",
753                                'ca_cert': "auth_serv/ca.pem",
754                                'domain': "example.com",
755                                'update_identifier': "1234"})
756     interworking_select(wpas, bssid, "home", freq="2412")
757     interworking_connect(wpas, bssid, "TTLS")
758     check_sp_type(wpas, "home")
759     status = wpas.get_status()
760     if status['pairwise_cipher'] != "CCMP":
761         raise Exception("Unexpected pairwise cipher")
762     if status['hs20'] != "3":
763         raise Exception("Unexpected HS 2.0 support indication")
764 
765 def test_ap_hs20_auto_interworking(dev, apdev):
766     """Hotspot 2.0 connection with auto_interworking=1"""
767     check_eap_capa(dev[0], "MSCHAPV2")
768     bssid = apdev[0]['bssid']
769     params = hs20_ap_params()
770     params['hessid'] = bssid
771     params['disable_dgaf'] = '1'
772     hostapd.add_ap(apdev[0], params)
773 
774     dev[0].hs20_enable(auto_interworking=True)
775     id = dev[0].add_cred_values({'realm': "example.com",
776                                  'username': "hs20-test",
777                                  'password': "password",
778                                  'ca_cert': "auth_serv/ca.pem",
779                                  'domain': "example.com",
780                                  'update_identifier': "1234"})
781     dev[0].request("REASSOCIATE")
782     dev[0].wait_connected(timeout=15)
783     check_sp_type(dev[0], "home")
784     status = dev[0].get_status()
785     if status['pairwise_cipher'] != "CCMP":
786         raise Exception("Unexpected pairwise cipher")
787     if status['hs20'] != "3":
788         raise Exception("Unexpected HS 2.0 support indication")
789 
790 def test_ap_hs20_auto_interworking_global_pmf(dev, apdev):
791     """Hotspot 2.0 connection with auto_interworking=1 and pmf=2"""
792     check_eap_capa(dev[0], "MSCHAPV2")
793     bssid = apdev[0]['bssid']
794     params = hs20_ap_params()
795     params['hessid'] = bssid
796     hostapd.add_ap(apdev[0], params)
797 
798     dev[0].hs20_enable(auto_interworking=True)
799     id = dev[0].add_cred_values({'realm': "example.com",
800                                  'username': "hs20-test",
801                                  'password': "password",
802                                  'ca_cert': "auth_serv/ca.pem",
803                                  'domain': "example.com",
804                                  'update_identifier': "1234"})
805     try:
806         dev[0].set("pmf", "2")
807         dev[0].request("REASSOCIATE")
808         dev[0].wait_connected(timeout=15)
809         pmf = dev[0].get_status_field("pmf")
810         if pmf != "1":
811             raise Exception("Unexpected PMF state: " + str(pmf))
812     finally:
813         dev[0].set("pmf", "0")
814 
815 def test_ap_hs20_auto_interworking_global_pmf_fail(dev, apdev):
816     """Hotspot 2.0 connection with auto_interworking=1 and pmf=2 failure"""
817     check_eap_capa(dev[0], "MSCHAPV2")
818     bssid = apdev[0]['bssid']
819     params = hs20_ap_params()
820     params['ieee80211w'] = "0"
821     params['hessid'] = bssid
822     hostapd.add_ap(apdev[0], params)
823 
824     dev[0].hs20_enable(auto_interworking=True)
825     id = dev[0].add_cred_values({'realm': "example.com",
826                                  'username': "hs20-test",
827                                  'password': "password",
828                                  'ca_cert': "auth_serv/ca.pem",
829                                  'domain': "example.com",
830                                  'update_identifier': "1234"})
831     try:
832         dev[0].set("pmf", "2")
833         dev[0].request("REASSOCIATE")
834         for i in range(2):
835             ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED",
836                                     "INTERWORKING-SELECTED"], timeout=15)
837             if ev is None:
838                 raise Exception("Connection result not reported")
839             if "CTRL-EVENT-CONNECTED" in ev:
840                 raise Exception("Unexpected connection")
841         dev[0].request("DISCONNECT")
842     finally:
843         dev[0].set("pmf", "0")
844 
845 @remote_compatible
846 def test_ap_hs20_auto_interworking_no_match(dev, apdev):
847     """Hotspot 2.0 connection with auto_interworking=1 and no matching network"""
848     hapd = hostapd.add_ap(apdev[0], {"ssid": "mismatch"})
849 
850     dev[0].hs20_enable(auto_interworking=True)
851     id = dev[0].connect("mismatch", psk="12345678", scan_freq="2412",
852                         only_add_network=True)
853     dev[0].request("ENABLE_NETWORK " + str(id) + " no-connect")
854 
855     id = dev[0].add_cred_values({'realm': "example.com",
856                                  'username': "hs20-test",
857                                  'password': "password",
858                                  'ca_cert': "auth_serv/ca.pem",
859                                  'domain': "example.com",
860                                  'update_identifier': "1234"})
861     dev[0].request("INTERWORKING_SELECT auto freq=2412")
862     time.sleep(0.1)
863     dev[0].dump_monitor()
864     for i in range(5):
865         logger.info("start ping")
866         if "PONG" not in dev[0].ctrl.request("PING", timeout=2):
867             raise Exception("PING failed")
868         logger.info("ping done")
869         fetch = 0
870         scan = 0
871         for j in range(15):
872             ev = dev[0].wait_event(["ANQP fetch completed",
873                                     "CTRL-EVENT-SCAN-RESULTS"], timeout=0.05)
874             if ev is None:
875                 break
876             if "ANQP fetch completed" in ev:
877                 fetch += 1
878             else:
879                 scan += 1
880         if fetch > 2 * scan + 3:
881             raise Exception("Too many ANQP fetch iterations")
882         dev[0].dump_monitor()
883     dev[0].request("DISCONNECT")
884 
885 @remote_compatible
886 def test_ap_hs20_auto_interworking_no_cred_match(dev, apdev):
887     """Hotspot 2.0 connection with auto_interworking=1 but no cred match"""
888     bssid = apdev[0]['bssid']
889     params = {"ssid": "test"}
890     hostapd.add_ap(apdev[0], params)
891 
892     dev[0].hs20_enable(auto_interworking=True)
893     dev[0].add_cred_values({'realm': "example.com",
894                             'username': "hs20-test",
895                             'password': "password",
896                             'ca_cert': "auth_serv/ca.pem",
897                             'domain': "example.com"})
898 
899     id = dev[0].connect("test", psk="12345678", only_add_network=True)
900     dev[0].request("ENABLE_NETWORK %s" % id)
901     logger.info("Verify that scanning continues when there is partial network block match")
902     for i in range(0, 2):
903         ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"], 10)
904         if ev is None:
905             raise Exception("Scan timed out")
906         logger.info("Scan completed")
907 
908 def eap_test(dev, ap, eap_params, method, user, release=0):
909     bssid = ap['bssid']
910     params = hs20_ap_params()
911     params['nai_realm'] = ["0,example.com," + eap_params]
912     if release > 0:
913         params['hs20_release'] = str(release)
914     hapd = hostapd.add_ap(ap, params)
915 
916     dev.flush_scan_cache()
917     dev.hs20_enable()
918     dev.add_cred_values({'realm': "example.com",
919                          'ca_cert': "auth_serv/ca.pem",
920                          'username': user,
921                          'password': "password"})
922     interworking_select(dev, bssid, freq="2412")
923     interworking_connect(dev, bssid, method)
924     return hapd
925 
926 @remote_compatible
927 def test_ap_hs20_eap_unknown(dev, apdev):
928     """Hotspot 2.0 connection with unknown EAP method"""
929     bssid = apdev[0]['bssid']
930     params = hs20_ap_params()
931     params['nai_realm'] = "0,example.com,99"
932     hostapd.add_ap(apdev[0], params)
933 
934     dev[0].hs20_enable()
935     dev[0].add_cred_values(default_cred())
936     interworking_select(dev[0], None, no_match=True, freq="2412")
937 
938 def test_ap_hs20_eap_peap_mschapv2(dev, apdev):
939     """Hotspot 2.0 connection with PEAP/MSCHAPV2"""
940     check_eap_capa(dev[0], "MSCHAPV2")
941     eap_test(dev[0], apdev[0], "25[3:26]", "PEAP", "user")
942 
943 def test_ap_hs20_eap_peap_default(dev, apdev):
944     """Hotspot 2.0 connection with PEAP/MSCHAPV2 (as default)"""
945     check_eap_capa(dev[0], "MSCHAPV2")
946     eap_test(dev[0], apdev[0], "25", "PEAP", "user")
947 
948 def test_ap_hs20_eap_peap_gtc(dev, apdev):
949     """Hotspot 2.0 connection with PEAP/GTC"""
950     eap_test(dev[0], apdev[0], "25[3:6]", "PEAP", "user")
951 
952 @remote_compatible
953 def test_ap_hs20_eap_peap_unknown(dev, apdev):
954     """Hotspot 2.0 connection with PEAP/unknown"""
955     bssid = apdev[0]['bssid']
956     params = hs20_ap_params()
957     params['nai_realm'] = "0,example.com,25[3:99]"
958     hostapd.add_ap(apdev[0], params)
959 
960     dev[0].hs20_enable()
961     dev[0].add_cred_values(default_cred())
962     interworking_select(dev[0], None, no_match=True, freq="2412")
963 
964 def test_ap_hs20_eap_ttls_chap(dev, apdev):
965     """Hotspot 2.0 connection with TTLS/CHAP"""
966     skip_with_fips(dev[0])
967     eap_test(dev[0], apdev[0], "21[2:2]", "TTLS", "chap user")
968 
969 def test_ap_hs20_eap_ttls_mschap(dev, apdev):
970     """Hotspot 2.0 connection with TTLS/MSCHAP"""
971     skip_with_fips(dev[0])
972     eap_test(dev[0], apdev[0], "21[2:3]", "TTLS", "mschap user")
973 
974 def test_ap_hs20_eap_ttls_default(dev, apdev):
975     """Hotspot 2.0 connection with TTLS/default"""
976     skip_with_fips(dev[0])
977     eap_test(dev[0], apdev[0], "21", "TTLS", "hs20-test")
978 
979 def test_ap_hs20_eap_ttls_eap_mschapv2(dev, apdev):
980     """Hotspot 2.0 connection with TTLS/EAP-MSCHAPv2"""
981     check_eap_capa(dev[0], "MSCHAPV2")
982     eap_test(dev[0], apdev[0], "21[3:26][6:7][99:99]", "TTLS", "user")
983 
984 @remote_compatible
985 def test_ap_hs20_eap_ttls_eap_unknown(dev, apdev):
986     """Hotspot 2.0 connection with TTLS/EAP-unknown"""
987     bssid = apdev[0]['bssid']
988     params = hs20_ap_params()
989     params['nai_realm'] = "0,example.com,21[3:99]"
990     hostapd.add_ap(apdev[0], params)
991 
992     dev[0].hs20_enable()
993     dev[0].add_cred_values(default_cred())
994     interworking_select(dev[0], None, no_match=True, freq="2412")
995 
996 @remote_compatible
997 def test_ap_hs20_eap_ttls_eap_unsupported(dev, apdev):
998     """Hotspot 2.0 connection with TTLS/EAP-OTP(unsupported)"""
999     bssid = apdev[0]['bssid']
1000     params = hs20_ap_params()
1001     params['nai_realm'] = "0,example.com,21[3:5]"
1002     hostapd.add_ap(apdev[0], params)
1003 
1004     dev[0].hs20_enable()
1005     dev[0].add_cred_values(default_cred())
1006     interworking_select(dev[0], None, no_match=True, freq="2412")
1007 
1008 @remote_compatible
1009 def test_ap_hs20_eap_ttls_unknown(dev, apdev):
1010     """Hotspot 2.0 connection with TTLS/unknown"""
1011     bssid = apdev[0]['bssid']
1012     params = hs20_ap_params()
1013     params['nai_realm'] = "0,example.com,21[2:5]"
1014     hostapd.add_ap(apdev[0], params)
1015 
1016     dev[0].hs20_enable()
1017     dev[0].add_cred_values(default_cred())
1018     interworking_select(dev[0], None, no_match=True, freq="2412")
1019 
1020 def test_ap_hs20_eap_fast_mschapv2(dev, apdev):
1021     """Hotspot 2.0 connection with FAST/EAP-MSCHAPV2"""
1022     check_eap_capa(dev[0], "FAST")
1023     eap_test(dev[0], apdev[0], "43[3:26]", "FAST", "user")
1024 
1025 def test_ap_hs20_eap_fast_gtc(dev, apdev):
1026     """Hotspot 2.0 connection with FAST/EAP-GTC"""
1027     check_eap_capa(dev[0], "FAST")
1028     eap_test(dev[0], apdev[0], "43[3:6]", "FAST", "user")
1029 
1030 def test_ap_hs20_eap_tls(dev, apdev):
1031     """Hotspot 2.0 connection with EAP-TLS"""
1032     bssid = apdev[0]['bssid']
1033     params = hs20_ap_params()
1034     params['nai_realm'] = ["0,example.com,13[5:6]"]
1035     hostapd.add_ap(apdev[0], params)
1036 
1037     dev[0].flush_scan_cache()
1038     dev[0].hs20_enable()
1039     dev[0].add_cred_values({'realm': "example.com",
1040                             'username': "certificate-user",
1041                             'ca_cert': "auth_serv/ca.pem",
1042                             'client_cert': "auth_serv/user.pem",
1043                             'private_key': "auth_serv/user.key"})
1044     interworking_select(dev[0], bssid, freq="2412")
1045     interworking_connect(dev[0], bssid, "TLS")
1046 
1047 @remote_compatible
1048 def test_ap_hs20_eap_cert_unknown(dev, apdev):
1049     """Hotspot 2.0 connection with certificate, but unknown EAP method"""
1050     bssid = apdev[0]['bssid']
1051     params = hs20_ap_params()
1052     params['nai_realm'] = ["0,example.com,99[5:6]"]
1053     hostapd.add_ap(apdev[0], params)
1054 
1055     dev[0].hs20_enable()
1056     dev[0].add_cred_values({'realm': "example.com",
1057                             'username': "certificate-user",
1058                             'ca_cert': "auth_serv/ca.pem",
1059                             'client_cert': "auth_serv/user.pem",
1060                             'private_key': "auth_serv/user.key"})
1061     interworking_select(dev[0], None, no_match=True, freq="2412")
1062 
1063 @remote_compatible
1064 def test_ap_hs20_eap_cert_unsupported(dev, apdev):
1065     """Hotspot 2.0 connection with certificate, but unsupported TTLS"""
1066     bssid = apdev[0]['bssid']
1067     params = hs20_ap_params()
1068     params['nai_realm'] = ["0,example.com,21[5:6]"]
1069     hostapd.add_ap(apdev[0], params)
1070 
1071     dev[0].hs20_enable()
1072     dev[0].add_cred_values({'realm': "example.com",
1073                             'username': "certificate-user",
1074                             'ca_cert': "auth_serv/ca.pem",
1075                             'client_cert': "auth_serv/user.pem",
1076                             'private_key': "auth_serv/user.key"})
1077     interworking_select(dev[0], None, no_match=True, freq="2412")
1078 
1079 @remote_compatible
1080 def test_ap_hs20_eap_invalid_cred(dev, apdev):
1081     """Hotspot 2.0 connection with invalid cred configuration"""
1082     bssid = apdev[0]['bssid']
1083     params = hs20_ap_params()
1084     hostapd.add_ap(apdev[0], params)
1085 
1086     dev[0].hs20_enable()
1087     dev[0].add_cred_values({'realm': "example.com",
1088                             'username': "certificate-user",
1089                             'client_cert': "auth_serv/user.pem"})
1090     interworking_select(dev[0], None, no_match=True, freq="2412")
1091 
1092 def test_ap_hs20_nai_realms(dev, apdev):
1093     """Hotspot 2.0 connection and multiple NAI realms and TTLS/PAP"""
1094     bssid = apdev[0]['bssid']
1095     params = hs20_ap_params()
1096     params['hessid'] = bssid
1097     params['nai_realm'] = ["0,no.match.here;example.com;no.match.here.either,21[2:1][5:7]"]
1098     hostapd.add_ap(apdev[0], params)
1099 
1100     dev[0].flush_scan_cache()
1101     dev[0].hs20_enable()
1102     id = dev[0].add_cred_values({'realm': "example.com",
1103                                  'ca_cert': "auth_serv/ca.pem",
1104                                  'username': "pap user",
1105                                  'password': "password",
1106                                  'domain': "example.com"})
1107     interworking_select(dev[0], bssid, "home", freq="2412")
1108     interworking_connect(dev[0], bssid, "TTLS")
1109     check_sp_type(dev[0], "home")
1110 
1111 def test_ap_hs20_roaming_consortium(dev, apdev):
1112     """Hotspot 2.0 connection based on roaming consortium match"""
1113     bssid = apdev[0]['bssid']
1114     params = hs20_ap_params()
1115     params['hessid'] = bssid
1116     hostapd.add_ap(apdev[0], params)
1117 
1118     dev[0].flush_scan_cache()
1119     dev[0].hs20_enable()
1120     for consortium in ["112233", "1020304050", "010203040506", "fedcba"]:
1121         id = dev[0].add_cred_values({'username': "user",
1122                                      'password': "password",
1123                                      'domain': "example.com",
1124                                      'ca_cert': "auth_serv/ca.pem",
1125                                      'roaming_consortium': consortium,
1126                                      'eap': "PEAP"})
1127         interworking_select(dev[0], bssid, "home", freq="2412")
1128         interworking_connect(dev[0], bssid, "PEAP")
1129         check_sp_type(dev[0], "home")
1130         dev[0].request("INTERWORKING_SELECT auto freq=2412")
1131         ev = dev[0].wait_event(["INTERWORKING-ALREADY-CONNECTED"], timeout=15)
1132         if ev is None:
1133             raise Exception("Timeout on already-connected event")
1134         dev[0].remove_cred(id)
1135 
1136 def test_ap_hs20_home_ois(dev, apdev):
1137     """Hotspot 2.0 connection based on roaming consortium match"""
1138     bssid = apdev[0]['bssid']
1139     params = hs20_ap_params()
1140     params['hessid'] = bssid
1141     hostapd.add_ap(apdev[0], params)
1142 
1143     dev[0].flush_scan_cache()
1144     dev[0].hs20_enable()
1145     for consortium in [["112233"], ["1020304050"], ["010203040506"], ["fedcba"],
1146                        ["f12233", "f020304050", "f10203040506", "fedcba"]]:
1147         id = dev[0].add_cred_values({'username': "user",
1148                                      'password': "password",
1149                                      'domain': "example.com",
1150                                      'ca_cert': "auth_serv/ca.pem",
1151                                      'home_ois': consortium,
1152                                      'eap': "PEAP"})
1153         interworking_select(dev[0], bssid, "home", freq="2412")
1154         interworking_connect(dev[0], bssid, "PEAP")
1155         check_sp_type(dev[0], "home")
1156         dev[0].request("INTERWORKING_SELECT auto freq=2412")
1157         ev = dev[0].wait_event(["INTERWORKING-ALREADY-CONNECTED"], timeout=15)
1158         if ev is None:
1159             raise Exception("Timeout on already-connected event")
1160         dev[0].remove_cred(id)
1161 
1162 def test_ap_hs20_roaming_consortiums_match(dev, apdev):
1163     """Hotspot 2.0 connection based on roaming_consortiums match"""
1164     bssid = apdev[0]['bssid']
1165     params = hs20_ap_params()
1166     params['hessid'] = bssid
1167     hostapd.add_ap(apdev[0], params)
1168 
1169     dev[0].flush_scan_cache()
1170     dev[0].hs20_enable()
1171     tests = [("112233", "112233"),
1172              ("ffffff,1020304050,eeeeee", "1020304050")]
1173     for consortium, selected in tests:
1174         id = dev[0].add_cred_values({'username': "user",
1175                                      'password': "password",
1176                                      'domain': "my.home.example.com",
1177                                      'ca_cert': "auth_serv/ca.pem",
1178                                      'roaming_consortiums': consortium,
1179                                      'eap': "PEAP"})
1180         interworking_select(dev[0], bssid, "roaming", freq="2412")
1181         interworking_connect(dev[0], bssid, "PEAP")
1182         check_sp_type(dev[0], "roaming")
1183         network_id = dev[0].get_status_field("id")
1184         sel = dev[0].get_network(network_id, "roaming_consortium_selection")
1185         if sel != selected:
1186             raise Exception("Unexpected roaming_consortium_selection value: " +
1187                             sel)
1188         dev[0].request("INTERWORKING_SELECT auto freq=2412")
1189         ev = dev[0].wait_event(["INTERWORKING-ALREADY-CONNECTED"], timeout=15)
1190         if ev is None:
1191             raise Exception("Timeout on already-connected event")
1192         dev[0].remove_cred(id)
1193 
1194 def test_ap_hs20_max_roaming_consortiums(dev, apdev):
1195     """Maximum number of cred roaming_consortiums"""
1196     id = dev[0].add_cred()
1197     consortium = (36*",ffffff")[1:]
1198     if "OK" not in dev[0].request('SET_CRED %d roaming_consortiums "%s"' % (id, consortium)):
1199         raise Exception("Maximum number of consortium OIs rejected")
1200     consortium = (37*",ffffff")[1:]
1201     if "FAIL" not in dev[0].request('SET_CRED %d roaming_consortiums "%s"' % (id, consortium)):
1202         raise Exception("Over maximum number of consortium OIs accepted")
1203     dev[0].remove_cred(id)
1204 
1205 def test_ap_hs20_roaming_consortium_invalid(dev, apdev):
1206     """Hotspot 2.0 connection and invalid roaming consortium ANQP-element"""
1207     bssid = apdev[0]['bssid']
1208     params = hs20_ap_params()
1209     params['hessid'] = bssid
1210     # Override Roaming Consortium ANQP-element with an incorrectly encoded
1211     # value.
1212     params['anqp_elem'] = "261:04fedcba"
1213     hostapd.add_ap(apdev[0], params)
1214 
1215     dev[0].hs20_enable()
1216     id = dev[0].add_cred_values({'username': "user",
1217                                  'password': "password",
1218                                  'domain': "example.com",
1219                                  'ca_cert': "auth_serv/ca.pem",
1220                                  'home_ois': ["fedcba"],
1221                                  'eap': "PEAP"})
1222     interworking_select(dev[0], bssid, "home", freq="2412", no_match=True)
1223 
1224 def test_ap_hs20_roaming_consortium_element(dev, apdev):
1225     """Hotspot 2.0 connection and invalid roaming consortium element"""
1226     bssid = apdev[0]['bssid']
1227     params = hs20_ap_params()
1228     params['hessid'] = bssid
1229     del params['roaming_consortium']
1230     params['vendor_elements'] = '6f00'
1231     hapd = hostapd.add_ap(apdev[0], params)
1232 
1233     dev[0].hs20_enable()
1234     dev[0].scan_for_bss(bssid, freq="2412")
1235     id = dev[0].add_cred_values({'username': "user",
1236                                  'password': "password",
1237                                  'domain': "example.com",
1238                                  'ca_cert': "auth_serv/ca.pem",
1239                                  'home_ois': ["112233"],
1240                                  'eap': "PEAP"})
1241     interworking_select(dev[0], bssid, freq="2412", no_match=True)
1242 
1243     hapd.set('vendor_elements', '6f020001')
1244     if "OK" not in hapd.request("UPDATE_BEACON"):
1245         raise Exception("UPDATE_BEACON failed")
1246     dev[0].request("BSS_FLUSH 0")
1247     dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
1248     interworking_select(dev[0], bssid, freq="2412", no_match=True)
1249 
1250 def test_ap_hs20_roaming_consortium_constraints(dev, apdev):
1251     """Hotspot 2.0 connection and roaming consortium constraints"""
1252     bssid = apdev[0]['bssid']
1253     params = hs20_ap_params()
1254     params['hessid'] = bssid
1255     params['bss_load_test'] = "12:200:20000"
1256     hostapd.add_ap(apdev[0], params)
1257 
1258     dev[0].hs20_enable()
1259 
1260     vals = {'username': "user",
1261             'password': "password",
1262             'domain': "example.com",
1263             'ca_cert': "auth_serv/ca.pem",
1264             'home_ois': ["fedcba"],
1265             'eap': "TTLS"}
1266     vals2 = vals.copy()
1267     vals2['required_home_ois'] = ["223344"]
1268     id = dev[0].add_cred_values(vals2)
1269     interworking_select(dev[0], bssid, "home", freq="2412", no_match=True)
1270     dev[0].remove_cred(id)
1271 
1272     vals2 = vals.copy()
1273     vals2['min_dl_bandwidth_home'] = "65500"
1274     id = dev[0].add_cred_values(vals2)
1275     dev[0].request("INTERWORKING_SELECT freq=2412")
1276     ev = dev[0].wait_event(["INTERWORKING-AP"], timeout=15)
1277     if ev is None:
1278         raise Exception("No AP found")
1279     if "below_min_backhaul=1" not in ev:
1280         raise Exception("below_min_backhaul not reported")
1281     dev[0].remove_cred(id)
1282 
1283     vals2 = vals.copy()
1284     vals2['max_bss_load'] = "100"
1285     id = dev[0].add_cred_values(vals2)
1286     dev[0].request("INTERWORKING_SELECT freq=2412")
1287     ev = dev[0].wait_event(["INTERWORKING-AP"], timeout=15)
1288     if ev is None:
1289         raise Exception("No AP found")
1290     if "over_max_bss_load=1" not in ev:
1291         raise Exception("over_max_bss_load not reported")
1292     dev[0].remove_cred(id)
1293 
1294     vals2 = vals.copy()
1295     vals2['req_conn_capab'] = "6:1234"
1296     vals2['domain'] = 'example.org'
1297     id = dev[0].add_cred_values(vals2)
1298 
1299     dev[0].request("INTERWORKING_SELECT freq=2412")
1300     ev = dev[0].wait_event(["INTERWORKING-AP"], timeout=15)
1301     if ev is None:
1302         raise Exception("No AP found")
1303     if "conn_capab_missing=1" not in ev:
1304         raise Exception("conn_capab_missing not reported")
1305     dev[0].remove_cred(id)
1306 
1307     values = default_cred()
1308     values['home_ois'] = ["fedcba"]
1309     id3 = dev[0].add_cred_values(values)
1310 
1311     vals2 = vals.copy()
1312     vals2['home_ois'] = ["fedcba"]
1313     vals2['priority'] = "2"
1314     id = dev[0].add_cred_values(vals2)
1315 
1316     values = default_cred()
1317     values['home_ois'] = ["fedcba"]
1318     id2 = dev[0].add_cred_values(values)
1319 
1320     dev[0].request("INTERWORKING_SELECT freq=2412")
1321     ev = dev[0].wait_event(["INTERWORKING-AP"], timeout=15)
1322     if ev is None:
1323         raise Exception("No AP found")
1324     dev[0].remove_cred(id)
1325     dev[0].remove_cred(id2)
1326     dev[0].remove_cred(id3)
1327 
1328 def test_ap_hs20_3gpp_constraints(dev, apdev):
1329     """Hotspot 2.0 connection and 3GPP credential constraints"""
1330     bssid = apdev[0]['bssid']
1331     params = hs20_ap_params()
1332     params['hessid'] = bssid
1333     params['anqp_3gpp_cell_net'] = "555,444"
1334     params['domain_name'] = "wlan.mnc444.mcc555.3gppnetwork.org"
1335     params['bss_load_test'] = "12:200:20000"
1336     hapd = hostapd.add_ap(apdev[0], params)
1337 
1338     dev[0].hs20_enable()
1339 
1340     vals = {'imsi': "555444-333222111",
1341             'eap': "SIM",
1342             'milenage': "5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123"}
1343     vals2 = vals.copy()
1344     vals2['required_home_ois'] = ["223344"]
1345     id = dev[0].add_cred_values(vals2)
1346     interworking_select(dev[0], bssid, "home", freq="2412", no_match=True)
1347     dev[0].remove_cred(id)
1348 
1349     vals2 = vals.copy()
1350     vals2['min_dl_bandwidth_home'] = "65500"
1351     id = dev[0].add_cred_values(vals2)
1352     dev[0].request("INTERWORKING_SELECT freq=2412")
1353     ev = dev[0].wait_event(["INTERWORKING-AP"], timeout=15)
1354     if ev is None:
1355         raise Exception("No AP found")
1356     if "below_min_backhaul=1" not in ev:
1357         raise Exception("below_min_backhaul not reported")
1358     dev[0].remove_cred(id)
1359 
1360     vals2 = vals.copy()
1361     vals2['max_bss_load'] = "100"
1362     id = dev[0].add_cred_values(vals2)
1363     dev[0].request("INTERWORKING_SELECT freq=2412")
1364     ev = dev[0].wait_event(["INTERWORKING-AP"], timeout=15)
1365     if ev is None:
1366         raise Exception("No AP found")
1367     if "over_max_bss_load=1" not in ev:
1368         raise Exception("over_max_bss_load not reported")
1369     dev[0].remove_cred(id)
1370 
1371     values = default_cred()
1372     values['home_ois'] = ["fedcba"]
1373     id3 = dev[0].add_cred_values(values)
1374 
1375     vals2 = vals.copy()
1376     vals2['home_ois'] = ["fedcba"]
1377     vals2['priority'] = "2"
1378     id = dev[0].add_cred_values(vals2)
1379 
1380     values = default_cred()
1381     values['home_ois'] = ["fedcba"]
1382     id2 = dev[0].add_cred_values(values)
1383 
1384     dev[0].request("INTERWORKING_SELECT freq=2412")
1385     ev = dev[0].wait_event(["INTERWORKING-AP"], timeout=15)
1386     if ev is None:
1387         raise Exception("No AP found")
1388     dev[0].remove_cred(id)
1389     dev[0].remove_cred(id2)
1390     dev[0].remove_cred(id3)
1391 
1392     hapd.disable()
1393     params = hs20_ap_params()
1394     params['hessid'] = bssid
1395     params['anqp_3gpp_cell_net'] = "555,444"
1396     params['bss_load_test'] = "12:200:20000"
1397     hapd = hostapd.add_ap(apdev[0], params)
1398     vals2 = vals.copy()
1399     vals2['req_conn_capab'] = "6:1234"
1400     id = dev[0].add_cred_values(vals2)
1401     dev[0].request("INTERWORKING_SELECT freq=2412")
1402     ev = dev[0].wait_event(["INTERWORKING-AP"], timeout=15)
1403     if ev is None:
1404         raise Exception("No AP found")
1405     if "conn_capab_missing=1" not in ev:
1406         raise Exception("conn_capab_missing not reported")
1407     dev[0].remove_cred(id)
1408 
1409 def test_ap_hs20_connect_no_full_match(dev, apdev):
1410     """Hotspot 2.0 connection and no full match"""
1411     bssid = apdev[0]['bssid']
1412     params = hs20_ap_params()
1413     params['hessid'] = bssid
1414     params['anqp_3gpp_cell_net'] = "555,444"
1415     hapd = hostapd.add_ap(apdev[0], params)
1416 
1417     dev[0].flush_scan_cache()
1418     dev[0].hs20_enable()
1419 
1420     vals = {'username': "user",
1421             'password': "password",
1422             'domain': "example.com",
1423             'ca_cert': "auth_serv/ca.pem",
1424             'home_ois': ["fedcba"],
1425             'eap': "TTLS",
1426             'min_dl_bandwidth_home': "65500"}
1427     id = dev[0].add_cred_values(vals)
1428     dev[0].request("INTERWORKING_SELECT freq=2412")
1429     ev = dev[0].wait_event(["INTERWORKING-AP"], timeout=15)
1430     if ev is None:
1431         raise Exception("No AP found")
1432     if "below_min_backhaul=1" not in ev:
1433         raise Exception("below_min_backhaul not reported")
1434     interworking_connect(dev[0], bssid, "TTLS")
1435     # wait for sta to connect so it can actually disconnect later
1436     hapd.wait_sta()
1437     dev[0].remove_cred(id)
1438     dev[0].wait_disconnected()
1439     # wait for sta to disconnect so it can send GAS query
1440     hapd.wait_event(["AP-STA-DISCONNECTED"], timeout=1)
1441 
1442     vals = {'imsi': "555444-333222111", 'eap': "SIM",
1443             'milenage': "5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123",
1444             'min_dl_bandwidth_roaming': "65500"}
1445     id = dev[0].add_cred_values(vals)
1446     dev[0].request("INTERWORKING_SELECT freq=2412")
1447     ev = dev[0].wait_event(["INTERWORKING-AP"], timeout=15)
1448     if ev is None:
1449         raise Exception("No AP found")
1450     if "below_min_backhaul=1" not in ev:
1451         raise Exception("below_min_backhaul not reported")
1452     interworking_connect(dev[0], bssid, "SIM")
1453     dev[0].remove_cred(id)
1454     dev[0].wait_disconnected()
1455 
1456 def test_ap_hs20_username_roaming(dev, apdev):
1457     """Hotspot 2.0 connection in username/password credential (roaming)"""
1458     check_eap_capa(dev[0], "MSCHAPV2")
1459     bssid = apdev[0]['bssid']
1460     params = hs20_ap_params()
1461     params['nai_realm'] = ["0,example.com,13[5:6],21[2:4][5:7]",
1462                            "0,roaming.example.com,21[2:4][5:7]",
1463                            "0,another.example.com"]
1464     params['domain_name'] = "another.example.com"
1465     params['hessid'] = bssid
1466     hostapd.add_ap(apdev[0], params)
1467 
1468     dev[0].hs20_enable()
1469     id = dev[0].add_cred_values({'realm': "roaming.example.com",
1470                                  'username': "hs20-test",
1471                                  'password': "password",
1472                                  'ca_cert': "auth_serv/ca.pem",
1473                                  'domain': "example.com"})
1474     interworking_select(dev[0], bssid, "roaming", freq="2412")
1475     interworking_connect(dev[0], bssid, "TTLS")
1476     check_sp_type(dev[0], "roaming")
1477 
1478 def test_ap_hs20_username_unknown(dev, apdev):
1479     """Hotspot 2.0 connection in username/password credential (no domain in cred)"""
1480     check_eap_capa(dev[0], "MSCHAPV2")
1481     bssid = apdev[0]['bssid']
1482     params = hs20_ap_params()
1483     params['hessid'] = bssid
1484     hostapd.add_ap(apdev[0], params)
1485 
1486     dev[0].hs20_enable()
1487     id = dev[0].add_cred_values({'realm': "example.com",
1488                                  'ca_cert': "auth_serv/ca.pem",
1489                                  'username': "hs20-test",
1490                                  'password': "password"})
1491     interworking_select(dev[0], bssid, "unknown", freq="2412")
1492     interworking_connect(dev[0], bssid, "TTLS")
1493     check_sp_type(dev[0], "unknown")
1494 
1495 def test_ap_hs20_username_unknown2(dev, apdev):
1496     """Hotspot 2.0 connection in username/password credential (no domain advertized)"""
1497     check_eap_capa(dev[0], "MSCHAPV2")
1498     bssid = apdev[0]['bssid']
1499     params = hs20_ap_params()
1500     params['hessid'] = bssid
1501     del params['domain_name']
1502     hostapd.add_ap(apdev[0], params)
1503 
1504     dev[0].hs20_enable()
1505     id = dev[0].add_cred_values({'realm': "example.com",
1506                                  'ca_cert': "auth_serv/ca.pem",
1507                                  'username': "hs20-test",
1508                                  'password': "password",
1509                                  'domain': "example.com"})
1510     interworking_select(dev[0], bssid, "unknown", freq="2412")
1511     interworking_connect(dev[0], bssid, "TTLS")
1512     check_sp_type(dev[0], "unknown")
1513 
1514 def test_ap_hs20_gas_while_associated(dev, apdev):
1515     """Hotspot 2.0 connection with GAS query while associated"""
1516     check_eap_capa(dev[0], "MSCHAPV2")
1517     bssid = apdev[0]['bssid']
1518     params = hs20_ap_params()
1519     params['hessid'] = bssid
1520     hapd = hostapd.add_ap(apdev[0], params)
1521 
1522     dev[0].hs20_enable()
1523     id = dev[0].add_cred_values({'realm': "example.com",
1524                                  'ca_cert': "auth_serv/ca.pem",
1525                                  'username': "hs20-test",
1526                                  'password': "password",
1527                                  'domain': "example.com"})
1528     interworking_select(dev[0], bssid, "home", freq="2412")
1529     interworking_connect(dev[0], bssid, "TTLS")
1530     hapd.wait_sta()
1531 
1532     logger.info("Verifying GAS query while associated")
1533     dev[0].request("FETCH_ANQP")
1534     for i in range(0, 6):
1535         ev = dev[0].wait_event(["RX-ANQP"], timeout=5)
1536         if ev is None:
1537             raise Exception("Operation timed out")
1538 
1539 def test_ap_hs20_gas_with_another_ap_while_associated(dev, apdev):
1540     """GAS query with another AP while associated"""
1541     check_eap_capa(dev[0], "MSCHAPV2")
1542     bssid = apdev[0]['bssid']
1543     params = hs20_ap_params()
1544     params['hessid'] = bssid
1545     hapd = hostapd.add_ap(apdev[0], params)
1546 
1547     bssid2 = apdev[1]['bssid']
1548     params = hs20_ap_params()
1549     params['hessid'] = bssid2
1550     params['nai_realm'] = ["0,no-match.example.org,13[5:6],21[2:4][5:7]"]
1551     hostapd.add_ap(apdev[1], params)
1552 
1553     dev[0].hs20_enable()
1554     id = dev[0].add_cred_values({'realm': "example.com",
1555                                  'ca_cert': "auth_serv/ca.pem",
1556                                  'username': "hs20-test",
1557                                  'password': "password",
1558                                  'domain': "example.com"})
1559     interworking_select(dev[0], bssid, "home", freq="2412")
1560     interworking_connect(dev[0], bssid, "TTLS")
1561     hapd.wait_sta()
1562     dev[0].dump_monitor()
1563 
1564     logger.info("Verifying GAS query with same AP while associated")
1565     dev[0].request("ANQP_GET " + bssid + " 263")
1566     ev = dev[0].wait_event(["RX-ANQP"], timeout=5)
1567     if ev is None:
1568         raise Exception("ANQP operation timed out")
1569     dev[0].dump_monitor()
1570 
1571     logger.info("Verifying GAS query with another AP while associated")
1572     dev[0].scan_for_bss(bssid2, 2412)
1573     dev[0].request("ANQP_GET " + bssid2 + " 263")
1574     ev = dev[0].wait_event(["RX-ANQP"], timeout=5)
1575     if ev is None:
1576         raise Exception("ANQP operation timed out")
1577 
1578 def test_ap_hs20_gas_while_associated_with_pmf(dev, apdev):
1579     """Hotspot 2.0 connection with GAS query while associated and using PMF"""
1580     check_eap_capa(dev[0], "MSCHAPV2")
1581     try:
1582         _test_ap_hs20_gas_while_associated_with_pmf(dev, apdev)
1583     finally:
1584         dev[0].request("SET pmf 0")
1585 
1586 def _test_ap_hs20_gas_while_associated_with_pmf(dev, apdev):
1587     bssid = apdev[0]['bssid']
1588     params = hs20_ap_params()
1589     params['hessid'] = bssid
1590     hapd = hostapd.add_ap(apdev[0], params)
1591 
1592     bssid2 = apdev[1]['bssid']
1593     params = hs20_ap_params()
1594     params['hessid'] = bssid2
1595     params['nai_realm'] = ["0,no-match.example.org,13[5:6],21[2:4][5:7]"]
1596     hostapd.add_ap(apdev[1], params)
1597 
1598     dev[0].flush_scan_cache()
1599     dev[0].hs20_enable()
1600     dev[0].request("SET pmf 2")
1601     id = dev[0].add_cred_values({'realm': "example.com",
1602                                  'ca_cert': "auth_serv/ca.pem",
1603                                  'username': "hs20-test",
1604                                  'password': "password",
1605                                  'domain': "example.com"})
1606     interworking_select(dev[0], bssid, "home", freq="2412")
1607     interworking_connect(dev[0], bssid, "TTLS")
1608     hapd.wait_sta()
1609 
1610     logger.info("Verifying GAS query while associated")
1611     dev[0].request("FETCH_ANQP")
1612     for i in range(0, 2 * 6):
1613         ev = dev[0].wait_event(["RX-ANQP"], timeout=5)
1614         if ev is None:
1615             raise Exception("Operation timed out")
1616 
1617 def test_ap_hs20_gas_with_another_ap_while_using_pmf(dev, apdev):
1618     """GAS query with another AP while associated and using PMF"""
1619     check_eap_capa(dev[0], "MSCHAPV2")
1620     try:
1621         _test_ap_hs20_gas_with_another_ap_while_using_pmf(dev, apdev)
1622     finally:
1623         dev[0].request("SET pmf 0")
1624 
1625 def _test_ap_hs20_gas_with_another_ap_while_using_pmf(dev, apdev):
1626     bssid = apdev[0]['bssid']
1627     params = hs20_ap_params()
1628     params['hessid'] = bssid
1629     hapd = hostapd.add_ap(apdev[0], params)
1630 
1631     bssid2 = apdev[1]['bssid']
1632     params = hs20_ap_params()
1633     params['hessid'] = bssid2
1634     params['nai_realm'] = ["0,no-match.example.org,13[5:6],21[2:4][5:7]"]
1635     hostapd.add_ap(apdev[1], params)
1636 
1637     dev[0].hs20_enable()
1638     dev[0].request("SET pmf 2")
1639     id = dev[0].add_cred_values({'realm': "example.com",
1640                                  'ca_cert': "auth_serv/ca.pem",
1641                                  'username': "hs20-test",
1642                                  'password': "password",
1643                                  'domain': "example.com"})
1644     interworking_select(dev[0], bssid, "home", freq="2412")
1645     interworking_connect(dev[0], bssid, "TTLS")
1646     dev[0].dump_monitor()
1647     hapd.wait_sta()
1648 
1649     logger.info("Verifying GAS query with same AP while associated")
1650     dev[0].request("ANQP_GET " + bssid + " 263")
1651     ev = dev[0].wait_event(["RX-ANQP"], timeout=5)
1652     if ev is None:
1653         raise Exception("ANQP operation timed out")
1654     dev[0].dump_monitor()
1655 
1656     logger.info("Verifying GAS query with another AP while associated")
1657     dev[0].scan_for_bss(bssid2, 2412)
1658     dev[0].request("ANQP_GET " + bssid2 + " 263")
1659     ev = dev[0].wait_event(["RX-ANQP"], timeout=5)
1660     if ev is None:
1661         raise Exception("ANQP operation timed out")
1662 
1663 def test_ap_hs20_gas_frag_while_associated(dev, apdev):
1664     """Hotspot 2.0 connection with fragmented GAS query while associated"""
1665     check_eap_capa(dev[0], "MSCHAPV2")
1666     bssid = apdev[0]['bssid']
1667     params = hs20_ap_params()
1668     params['hessid'] = bssid
1669     hapd = hostapd.add_ap(apdev[0], params)
1670     hapd.set("gas_frag_limit", "50")
1671 
1672     dev[0].hs20_enable()
1673     id = dev[0].add_cred_values({'realm': "example.com",
1674                                  'ca_cert': "auth_serv/ca.pem",
1675                                  'username': "hs20-test",
1676                                  'password': "password",
1677                                  'domain': "example.com"})
1678     interworking_select(dev[0], bssid, "home", freq="2412")
1679     interworking_connect(dev[0], bssid, "TTLS")
1680     hapd.wait_sta()
1681 
1682     logger.info("Verifying GAS query while associated")
1683     dev[0].request("FETCH_ANQP")
1684     for i in range(0, 6):
1685         ev = dev[0].wait_event(["RX-ANQP"], timeout=5)
1686         if ev is None:
1687             raise Exception("Operation timed out")
1688 
1689 def test_ap_hs20_multiple_connects(dev, apdev):
1690     """Hotspot 2.0 connection through multiple network selections"""
1691     check_eap_capa(dev[0], "MSCHAPV2")
1692     bssid = apdev[0]['bssid']
1693     params = hs20_ap_params()
1694     params['hessid'] = bssid
1695     hostapd.add_ap(apdev[0], params)
1696 
1697     dev[0].hs20_enable()
1698     values = {'realm': "example.com",
1699               'ca_cert': "auth_serv/ca.pem",
1700               'username': "hs20-test",
1701               'password': "password",
1702               'domain': "example.com"}
1703     id = dev[0].add_cred_values(values)
1704 
1705     dev[0].scan_for_bss(bssid, freq="2412")
1706 
1707     for i in range(0, 3):
1708         logger.info("Starting Interworking network selection")
1709         dev[0].request("INTERWORKING_SELECT auto freq=2412")
1710         while True:
1711             ev = dev[0].wait_event(["INTERWORKING-NO-MATCH",
1712                                     "INTERWORKING-ALREADY-CONNECTED",
1713                                     "CTRL-EVENT-CONNECTED"], timeout=15)
1714             if ev is None:
1715                 raise Exception("Connection timed out")
1716             if "INTERWORKING-NO-MATCH" in ev:
1717                 raise Exception("Matching AP not found")
1718             if "CTRL-EVENT-CONNECTED" in ev:
1719                 break
1720             if i == 2 and "INTERWORKING-ALREADY-CONNECTED" in ev:
1721                 break
1722         if i == 0:
1723             dev[0].request("DISCONNECT")
1724         dev[0].dump_monitor()
1725 
1726     networks = dev[0].list_networks()
1727     if len(networks) > 1:
1728         raise Exception("Duplicated network block detected")
1729 
1730 def test_ap_hs20_disallow_aps(dev, apdev):
1731     """Hotspot 2.0 connection and disallow_aps"""
1732     bssid = apdev[0]['bssid']
1733     params = hs20_ap_params()
1734     params['hessid'] = bssid
1735     hostapd.add_ap(apdev[0], params)
1736 
1737     dev[0].hs20_enable()
1738     values = {'realm': "example.com",
1739               'ca_cert': "auth_serv/ca.pem",
1740               'username': "hs20-test",
1741               'password': "password",
1742               'domain': "example.com"}
1743     id = dev[0].add_cred_values(values)
1744 
1745     dev[0].scan_for_bss(bssid, freq="2412")
1746 
1747     logger.info("Verify disallow_aps bssid")
1748     dev[0].request("SET disallow_aps bssid " + bssid.replace(':', ''))
1749     dev[0].request("INTERWORKING_SELECT auto")
1750     ev = dev[0].wait_event(["INTERWORKING-NO-MATCH"], timeout=15)
1751     if ev is None:
1752         raise Exception("Network selection timed out")
1753     dev[0].dump_monitor()
1754 
1755     logger.info("Verify disallow_aps ssid")
1756     dev[0].request("SET disallow_aps ssid 746573742d68733230")
1757     dev[0].request("INTERWORKING_SELECT auto freq=2412")
1758     ev = dev[0].wait_event(["INTERWORKING-NO-MATCH"], timeout=15)
1759     if ev is None:
1760         raise Exception("Network selection timed out")
1761     dev[0].dump_monitor()
1762 
1763     logger.info("Verify disallow_aps clear")
1764     dev[0].request("SET disallow_aps ")
1765     interworking_select(dev[0], bssid, "home", freq="2412")
1766 
1767     dev[0].request("SET disallow_aps bssid " + bssid.replace(':', ''))
1768     ret = dev[0].request("INTERWORKING_CONNECT " + bssid)
1769     if "FAIL" not in ret:
1770         raise Exception("INTERWORKING_CONNECT to disallowed BSS not rejected")
1771 
1772     if "FAIL" not in dev[0].request("INTERWORKING_CONNECT foo"):
1773         raise Exception("Invalid INTERWORKING_CONNECT not rejected")
1774     if "FAIL" not in dev[0].request("INTERWORKING_CONNECT 00:11:22:33:44:55"):
1775         raise Exception("Invalid INTERWORKING_CONNECT not rejected")
1776 
1777 def policy_test(dev, ap, hapd, values, only_one=True):
1778     dev.dump_monitor()
1779     if hapd is not None:
1780         hapd.dump_monitor()
1781     if ap:
1782         logger.info("Verify network selection to AP " + ap['ifname'])
1783         bssid = ap['bssid']
1784         dev.scan_for_bss(bssid, freq="2412")
1785     else:
1786         logger.info("Verify network selection")
1787         bssid = None
1788     dev.hs20_enable()
1789     id = dev.add_cred_values(values)
1790     dev.request("INTERWORKING_SELECT auto freq=2412")
1791     events = []
1792     while True:
1793         ev = dev.wait_event(["INTERWORKING-AP", "INTERWORKING-NO-MATCH",
1794                              "INTERWORKING-BLACKLISTED",
1795                              "INTERWORKING-SELECTED"], timeout=15)
1796         if ev is None:
1797             raise Exception("Network selection timed out")
1798         events.append(ev)
1799         if "INTERWORKING-NO-MATCH" in ev:
1800             raise Exception("Matching AP not found")
1801         if bssid and only_one and "INTERWORKING-AP" in ev and bssid not in ev:
1802             raise Exception("Unexpected AP claimed acceptable")
1803         if "INTERWORKING-SELECTED" in ev:
1804             if bssid and bssid not in ev:
1805                 raise Exception("Selected incorrect BSS")
1806             break
1807 
1808     ev = dev.wait_connected(timeout=15)
1809     if bssid and bssid not in ev:
1810         raise Exception("Connected to incorrect BSS")
1811 
1812     conn_bssid = dev.get_status_field("bssid")
1813     if bssid and conn_bssid != bssid:
1814         raise Exception("bssid information points to incorrect BSS")
1815 
1816     if hapd is not None:
1817         hapd.wait_sta()
1818 
1819     dev.remove_cred(id)
1820     dev.dump_monitor()
1821     return events
1822 
1823 def default_cred(domain=None, user="hs20-test"):
1824     cred = {'realm': "example.com",
1825             'ca_cert': "auth_serv/ca.pem",
1826             'username': user,
1827             'password': "password"}
1828     if domain:
1829         cred['domain'] = domain
1830     return cred
1831 
1832 def test_ap_hs20_prefer_home(dev, apdev):
1833     """Hotspot 2.0 required roaming consortium"""
1834     check_eap_capa(dev[0], "MSCHAPV2")
1835     params = hs20_ap_params()
1836     params['domain_name'] = "example.org"
1837     hapd0 = hostapd.add_ap(apdev[0], params)
1838 
1839     params = hs20_ap_params()
1840     params['ssid'] = "test-hs20-other"
1841     params['domain_name'] = "example.com"
1842     hapd1 = hostapd.add_ap(apdev[1], params)
1843 
1844     values = default_cred()
1845     values['domain'] = "example.com"
1846     policy_test(dev[0], apdev[1], hapd1, values, only_one=False)
1847     values['domain'] = "example.org"
1848     policy_test(dev[0], apdev[0], hapd0, values, only_one=False)
1849 
1850 def test_ap_hs20_req_home_ois(dev, apdev):
1851     """Hotspot 2.0 required roaming consortium"""
1852     check_eap_capa(dev[0], "MSCHAPV2")
1853     params = hs20_ap_params()
1854     hapd0 = hostapd.add_ap(apdev[0], params)
1855 
1856     params = hs20_ap_params()
1857     params['ssid'] = "test-hs20-other"
1858     params['roaming_consortium'] = ["223344"]
1859     hapd1 = hostapd.add_ap(apdev[1], params)
1860 
1861     values = default_cred()
1862     values['required_home_ois'] = ["223344"]
1863     policy_test(dev[0], apdev[1], hapd1, values)
1864     values['required_home_ois'] = ["112233"]
1865     policy_test(dev[0], apdev[0], hapd0, values)
1866 
1867     id = dev[0].add_cred()
1868     dev[0].set_cred_quoted(id, "required_home_ois", "112233")
1869     dev[0].set_cred_quoted(id, "required_home_ois",
1870                            "112233445566778899aabbccddeeff")
1871 
1872     for val in ["", "1", "11", "1122", "1122334",
1873                 "112233445566778899aabbccddeeff00", "1122334455,12345"]:
1874         if "FAIL" not in dev[0].request('SET_CRED {} required_home_ois "{}"'.format(id, val)):
1875             raise Exception("Invalid roaming consortium value accepted: " + val)
1876 
1877 def test_ap_hs20_req_roaming_consortium_no_match(dev, apdev):
1878     """Hotspot 2.0 required roaming consortium and no match"""
1879     check_eap_capa(dev[0], "MSCHAPV2")
1880     params = hs20_ap_params()
1881     del params['roaming_consortium']
1882     hostapd.add_ap(apdev[0], params)
1883 
1884     params = hs20_ap_params()
1885     params['ssid'] = "test-hs20-other"
1886     params['roaming_consortium'] = ["223345"]
1887     hostapd.add_ap(apdev[1], params)
1888 
1889     values = default_cred()
1890     values['required_home_ois'] = ["223344"]
1891     dev[0].hs20_enable()
1892     id = dev[0].add_cred_values(values)
1893     dev[0].request("INTERWORKING_SELECT auto freq=2412")
1894     ev = dev[0].wait_event(["INTERWORKING-NO-MATCH"], timeout=10)
1895     if ev is None:
1896         raise Exception("INTERWORKING-NO-MATCH not reported")
1897 
1898 def test_ap_hs20_excluded_ssid(dev, apdev):
1899     """Hotspot 2.0 exclusion based on SSID"""
1900     check_eap_capa(dev[0], "MSCHAPV2")
1901     params = hs20_ap_params()
1902     params['roaming_consortium'] = ["223344"]
1903     params['anqp_3gpp_cell_net'] = "555,444"
1904     hapd0 = hostapd.add_ap(apdev[0], params)
1905 
1906     params = hs20_ap_params()
1907     params['ssid'] = "test-hs20-other"
1908     params['roaming_consortium'] = ["223344"]
1909     params['anqp_3gpp_cell_net'] = "555,444"
1910     hapd1 = hostapd.add_ap(apdev[1], params)
1911 
1912     values = default_cred()
1913     values['excluded_ssid'] = "test-hs20"
1914     events = policy_test(dev[0], apdev[1], hapd1, values)
1915     ev = [e for e in events if "INTERWORKING-BLACKLISTED " + apdev[0]['bssid'] in e]
1916     if len(ev) != 1:
1917         raise Exception("Excluded network not reported")
1918     values['excluded_ssid'] = "test-hs20-other"
1919     events = policy_test(dev[0], apdev[0], hapd0, values)
1920     ev = [e for e in events if "INTERWORKING-BLACKLISTED " + apdev[1]['bssid'] in e]
1921     if len(ev) != 1:
1922         raise Exception("Excluded network not reported")
1923 
1924     values = default_cred()
1925     values['home_ois'] = ["223344"]
1926     values['eap'] = "TTLS"
1927     values['phase2'] = "auth=MSCHAPV2"
1928     values['excluded_ssid'] = "test-hs20"
1929     events = policy_test(dev[0], apdev[1], hapd1, values)
1930     ev = [e for e in events if "INTERWORKING-BLACKLISTED " + apdev[0]['bssid'] in e]
1931     if len(ev) != 1:
1932         raise Exception("Excluded network not reported")
1933 
1934     values = {'imsi': "555444-333222111", 'eap': "SIM",
1935               'milenage': "5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123",
1936               'excluded_ssid': "test-hs20"}
1937     events = policy_test(dev[0], apdev[1], hapd1, values)
1938     ev = [e for e in events if "INTERWORKING-BLACKLISTED " + apdev[0]['bssid'] in e]
1939     if len(ev) != 1:
1940         raise Exception("Excluded network not reported")
1941 
1942 def test_ap_hs20_roam_to_higher_prio(dev, apdev):
1943     """Hotspot 2.0 and roaming from current to higher priority network"""
1944     check_eap_capa(dev[0], "MSCHAPV2")
1945     bssid = apdev[0]['bssid']
1946     params = hs20_ap_params(ssid="test-hs20-visited")
1947     params['domain_name'] = "visited.example.org"
1948     hostapd.add_ap(apdev[0], params)
1949 
1950     dev[0].hs20_enable()
1951     id = dev[0].add_cred_values({'realm': "example.com",
1952                                  'ca_cert': "auth_serv/ca.pem",
1953                                  'username': "hs20-test",
1954                                  'password': "password",
1955                                  'domain': "example.com"})
1956     logger.info("Connect to the only network option")
1957     interworking_select(dev[0], bssid, "roaming", freq="2412")
1958     dev[0].dump_monitor()
1959     interworking_connect(dev[0], bssid, "TTLS")
1960 
1961     logger.info("Start another AP (home operator) and reconnect")
1962     bssid2 = apdev[1]['bssid']
1963     params = hs20_ap_params(ssid="test-hs20-home")
1964     params['domain_name'] = "example.com"
1965     hostapd.add_ap(apdev[1], params)
1966 
1967     dev[0].scan_for_bss(bssid2, freq="2412", force_scan=True)
1968     dev[0].request("INTERWORKING_SELECT auto freq=2412")
1969     ev = dev[0].wait_event(["INTERWORKING-NO-MATCH",
1970                             "INTERWORKING-ALREADY-CONNECTED",
1971                             "CTRL-EVENT-CONNECTED"], timeout=15)
1972     if ev is None:
1973         raise Exception("Connection timed out")
1974     if "INTERWORKING-NO-MATCH" in ev:
1975         raise Exception("Matching AP not found")
1976     if "INTERWORKING-ALREADY-CONNECTED" in ev:
1977         raise Exception("Unexpected AP selected")
1978     if bssid2 not in ev:
1979         raise Exception("Unexpected BSSID after reconnection")
1980 
1981 def test_ap_hs20_domain_suffix_match_full(dev, apdev):
1982     """Hotspot 2.0 and domain_suffix_match"""
1983     check_domain_match_full(dev[0])
1984     check_eap_capa(dev[0], "MSCHAPV2")
1985     bssid = apdev[0]['bssid']
1986     params = hs20_ap_params()
1987     hostapd.add_ap(apdev[0], params)
1988 
1989     dev[0].hs20_enable()
1990     id = dev[0].add_cred_values({'realm': "example.com",
1991                                  'username': "hs20-test",
1992                                  'password': "password",
1993                                  'ca_cert': "auth_serv/ca.pem",
1994                                  'domain': "example.com",
1995                                  'domain_suffix_match': "server.w1.fi"})
1996     interworking_select(dev[0], bssid, "home", freq="2412")
1997     dev[0].dump_monitor()
1998     interworking_connect(dev[0], bssid, "TTLS")
1999     dev[0].request("REMOVE_NETWORK all")
2000     dev[0].dump_monitor()
2001 
2002     dev[0].set_cred_quoted(id, "domain_suffix_match", "no-match.example.com")
2003     interworking_select(dev[0], bssid, "home", freq="2412")
2004     dev[0].dump_monitor()
2005     dev[0].request("INTERWORKING_CONNECT " + bssid)
2006     ev = dev[0].wait_event(["CTRL-EVENT-EAP-TLS-CERT-ERROR"])
2007     if ev is None:
2008         raise Exception("TLS certificate error not reported")
2009     if "Domain suffix mismatch" not in ev:
2010         raise Exception("Domain suffix mismatch not reported")
2011 
2012 def test_ap_hs20_domain_suffix_match(dev, apdev):
2013     """Hotspot 2.0 and domain_suffix_match"""
2014     check_eap_capa(dev[0], "MSCHAPV2")
2015     check_domain_match_full(dev[0])
2016     bssid = apdev[0]['bssid']
2017     params = hs20_ap_params()
2018     hostapd.add_ap(apdev[0], params)
2019 
2020     dev[0].hs20_enable()
2021     id = dev[0].add_cred_values({'realm': "example.com",
2022                                  'username': "hs20-test",
2023                                  'password': "password",
2024                                  'ca_cert': "auth_serv/ca.pem",
2025                                  'domain': "example.com",
2026                                  'domain_suffix_match': "w1.fi"})
2027     interworking_select(dev[0], bssid, "home", freq="2412")
2028     dev[0].dump_monitor()
2029     interworking_connect(dev[0], bssid, "TTLS")
2030 
2031 def test_ap_hs20_roaming_partner_preference(dev, apdev):
2032     """Hotspot 2.0 and roaming partner preference"""
2033     check_eap_capa(dev[0], "MSCHAPV2")
2034     params = hs20_ap_params()
2035     params['domain_name'] = "roaming.example.org"
2036     hapd0 = hostapd.add_ap(apdev[0], params)
2037 
2038     params = hs20_ap_params()
2039     params['ssid'] = "test-hs20-other"
2040     params['domain_name'] = "roaming.example.net"
2041     hapd1 = hostapd.add_ap(apdev[1], params)
2042 
2043     logger.info("Verify default vs. specified preference")
2044     values = default_cred()
2045     values['roaming_partner'] = "roaming.example.net,1,127,*"
2046     policy_test(dev[0], apdev[1], hapd1, values, only_one=False)
2047     values['roaming_partner'] = "roaming.example.net,1,129,*"
2048     policy_test(dev[0], apdev[0], hapd0, values, only_one=False)
2049 
2050     logger.info("Verify partial FQDN match")
2051     values['roaming_partner'] = "example.net,0,0,*"
2052     policy_test(dev[0], apdev[1], hapd1, values, only_one=False)
2053     values['roaming_partner'] = "example.net,0,255,*"
2054     policy_test(dev[0], apdev[0], hapd0, values, only_one=False)
2055 
2056 def test_ap_hs20_max_bss_load(dev, apdev):
2057     """Hotspot 2.0 and maximum BSS load"""
2058     check_eap_capa(dev[0], "MSCHAPV2")
2059     params = hs20_ap_params()
2060     params['bss_load_test'] = "12:200:20000"
2061     hapd0 = hostapd.add_ap(apdev[0], params)
2062 
2063     params = hs20_ap_params()
2064     params['ssid'] = "test-hs20-other"
2065     params['bss_load_test'] = "5:20:10000"
2066     hapd1 = hostapd.add_ap(apdev[1], params)
2067 
2068     logger.info("Verify maximum BSS load constraint")
2069     values = default_cred()
2070     values['domain'] = "example.com"
2071     values['max_bss_load'] = "100"
2072     events = policy_test(dev[0], apdev[1], hapd1, values, only_one=False)
2073 
2074     ev = [e for e in events if "INTERWORKING-AP " + apdev[0]['bssid'] in e]
2075     if len(ev) != 1 or "over_max_bss_load=1" not in ev[0]:
2076         raise Exception("Maximum BSS Load case not noticed")
2077     ev = [e for e in events if "INTERWORKING-AP " + apdev[1]['bssid'] in e]
2078     if len(ev) != 1 or "over_max_bss_load=1" in ev[0]:
2079         raise Exception("Maximum BSS Load case reported incorrectly")
2080 
2081     logger.info("Verify maximum BSS load does not prevent connection")
2082     values['max_bss_load'] = "1"
2083     events = policy_test(dev[0], None, None, values)
2084 
2085     ev = [e for e in events if "INTERWORKING-AP " + apdev[0]['bssid'] in e]
2086     if len(ev) != 1 or "over_max_bss_load=1" not in ev[0]:
2087         raise Exception("Maximum BSS Load case not noticed")
2088     ev = [e for e in events if "INTERWORKING-AP " + apdev[1]['bssid'] in e]
2089     if len(ev) != 1 or "over_max_bss_load=1" not in ev[0]:
2090         raise Exception("Maximum BSS Load case not noticed")
2091 
2092 def test_ap_hs20_max_bss_load2(dev, apdev):
2093     """Hotspot 2.0 and maximum BSS load with one AP not advertising"""
2094     check_eap_capa(dev[0], "MSCHAPV2")
2095     params = hs20_ap_params()
2096     params['bss_load_test'] = "12:200:20000"
2097     hostapd.add_ap(apdev[0], params)
2098 
2099     params = hs20_ap_params()
2100     params['ssid'] = "test-hs20-other"
2101     hapd1 = hostapd.add_ap(apdev[1], params)
2102 
2103     logger.info("Verify maximum BSS load constraint with AP advertisement")
2104     values = default_cred()
2105     values['domain'] = "example.com"
2106     values['max_bss_load'] = "100"
2107     events = policy_test(dev[0], apdev[1], hapd1, values, only_one=False)
2108 
2109     ev = [e for e in events if "INTERWORKING-AP " + apdev[0]['bssid'] in e]
2110     if len(ev) != 1 or "over_max_bss_load=1" not in ev[0]:
2111         raise Exception("Maximum BSS Load case not noticed")
2112     ev = [e for e in events if "INTERWORKING-AP " + apdev[1]['bssid'] in e]
2113     if len(ev) != 1 or "over_max_bss_load=1" in ev[0]:
2114         raise Exception("Maximum BSS Load case reported incorrectly")
2115 
2116 def test_ap_hs20_max_bss_load_roaming(dev, apdev):
2117     """Hotspot 2.0 and maximum BSS load (roaming)"""
2118     check_eap_capa(dev[0], "MSCHAPV2")
2119     params = hs20_ap_params()
2120     params['bss_load_test'] = "12:200:20000"
2121     hapd0 = hostapd.add_ap(apdev[0], params)
2122 
2123     values = default_cred()
2124     values['domain'] = "roaming.example.com"
2125     values['max_bss_load'] = "100"
2126     events = policy_test(dev[0], apdev[0], hapd0, values, only_one=True)
2127     ev = [e for e in events if "INTERWORKING-AP " + apdev[0]['bssid'] in e]
2128     if len(ev) != 1:
2129         raise Exception("No INTERWORKING-AP event")
2130     if "over_max_bss_load=1" in ev[0]:
2131         raise Exception("Maximum BSS Load reported for roaming")
2132 
2133 def test_ap_hs20_multi_cred_sp_prio(dev, apdev):
2134     """Hotspot 2.0 multi-cred sp_priority"""
2135     check_eap_capa(dev[0], "MSCHAPV2")
2136     try:
2137         _test_ap_hs20_multi_cred_sp_prio(dev, apdev)
2138     finally:
2139         dev[0].request("SET external_sim 0")
2140 
2141 def _test_ap_hs20_multi_cred_sp_prio(dev, apdev):
2142     hlr_auc_gw_available()
2143     bssid = apdev[0]['bssid']
2144     params = hs20_ap_params()
2145     params['hessid'] = bssid
2146     del params['domain_name']
2147     params['anqp_3gpp_cell_net'] = "232,01"
2148     hostapd.add_ap(apdev[0], params)
2149 
2150     dev[0].hs20_enable()
2151     dev[0].scan_for_bss(bssid, freq="2412")
2152     dev[0].request("SET external_sim 1")
2153     id1 = dev[0].add_cred_values({'imsi': "23201-0000000000", 'eap': "SIM",
2154                                   'provisioning_sp': "example.com",
2155                                   'sp_priority' :"1"})
2156     id2 = dev[0].add_cred_values({'realm': "example.com",
2157                                   'ca_cert': "auth_serv/ca.pem",
2158                                   'username': "hs20-test",
2159                                   'password': "password",
2160                                   'domain': "example.com",
2161                                   'provisioning_sp': "example.com",
2162                                   'sp_priority': "2"})
2163     dev[0].dump_monitor()
2164     dev[0].scan_for_bss(bssid, freq="2412")
2165     dev[0].request("INTERWORKING_SELECT auto freq=2412")
2166     interworking_ext_sim_auth(dev[0], "SIM")
2167     check_sp_type(dev[0], "unknown")
2168     dev[0].request("REMOVE_NETWORK all")
2169 
2170     dev[0].set_cred(id1, "sp_priority", "2")
2171     dev[0].set_cred(id2, "sp_priority", "1")
2172     dev[0].dump_monitor()
2173     dev[0].request("INTERWORKING_SELECT auto freq=2412")
2174     interworking_auth(dev[0], "TTLS")
2175     check_sp_type(dev[0], "unknown")
2176 
2177 def test_ap_hs20_multi_cred_sp_prio2(dev, apdev):
2178     """Hotspot 2.0 multi-cred sp_priority with two BSSes"""
2179     check_eap_capa(dev[0], "MSCHAPV2")
2180     try:
2181         _test_ap_hs20_multi_cred_sp_prio2(dev, apdev)
2182     finally:
2183         dev[0].request("SET external_sim 0")
2184 
2185 def _test_ap_hs20_multi_cred_sp_prio2(dev, apdev):
2186     hlr_auc_gw_available()
2187     bssid = apdev[0]['bssid']
2188     params = hs20_ap_params()
2189     params['hessid'] = bssid
2190     del params['nai_realm']
2191     del params['domain_name']
2192     params['anqp_3gpp_cell_net'] = "232,01"
2193     hostapd.add_ap(apdev[0], params)
2194 
2195     bssid2 = apdev[1]['bssid']
2196     params = hs20_ap_params()
2197     params['ssid'] = "test-hs20-other"
2198     params['hessid'] = bssid2
2199     del params['domain_name']
2200     del params['anqp_3gpp_cell_net']
2201     hostapd.add_ap(apdev[1], params)
2202 
2203     dev[0].hs20_enable()
2204     dev[0].request("SET external_sim 1")
2205     id1 = dev[0].add_cred_values({'imsi': "23201-0000000000", 'eap': "SIM",
2206                                   'provisioning_sp': "example.com",
2207                                   'sp_priority': "1"})
2208     id2 = dev[0].add_cred_values({'realm': "example.com",
2209                                   'ca_cert': "auth_serv/ca.pem",
2210                                   'username': "hs20-test",
2211                                   'password': "password",
2212                                   'domain': "example.com",
2213                                   'provisioning_sp': "example.com",
2214                                   'sp_priority': "2"})
2215     dev[0].dump_monitor()
2216     dev[0].scan_for_bss(bssid, freq="2412")
2217     dev[0].scan_for_bss(bssid2, freq="2412")
2218     dev[0].request("INTERWORKING_SELECT auto freq=2412")
2219     interworking_ext_sim_auth(dev[0], "SIM")
2220     check_sp_type(dev[0], "unknown")
2221     conn_bssid = dev[0].get_status_field("bssid")
2222     if conn_bssid != bssid:
2223         raise Exception("Connected to incorrect BSS")
2224     dev[0].request("REMOVE_NETWORK all")
2225 
2226     dev[0].set_cred(id1, "sp_priority", "2")
2227     dev[0].set_cred(id2, "sp_priority", "1")
2228     dev[0].dump_monitor()
2229     dev[0].request("INTERWORKING_SELECT auto freq=2412")
2230     interworking_auth(dev[0], "TTLS")
2231     check_sp_type(dev[0], "unknown")
2232     conn_bssid = dev[0].get_status_field("bssid")
2233     if conn_bssid != bssid2:
2234         raise Exception("Connected to incorrect BSS")
2235 
2236 def test_ap_hs20_multi_cred_sp_prio_same(dev, apdev):
2237     """Hotspot 2.0 multi-cred and same sp_priority"""
2238     check_eap_capa(dev[0], "MSCHAPV2")
2239     hlr_auc_gw_available()
2240     bssid = apdev[0]['bssid']
2241     params = hs20_ap_params()
2242     params['hessid'] = bssid
2243     del params['domain_name']
2244     params['anqp_3gpp_cell_net'] = "232,01"
2245     hostapd.add_ap(apdev[0], params)
2246 
2247     dev[0].hs20_enable()
2248     dev[0].scan_for_bss(bssid, freq="2412")
2249     id1 = dev[0].add_cred_values({'realm': "example.com",
2250                                   'ca_cert': "auth_serv/ca.pem",
2251                                   'username': "hs20-test",
2252                                   'password': "password",
2253                                   'domain': "domain1.example.com",
2254                                   'provisioning_sp': "example.com",
2255                                   'sp_priority': "1"})
2256     id2 = dev[0].add_cred_values({'realm': "example.com",
2257                                   'ca_cert': "auth_serv/ca.pem",
2258                                   'username': "hs20-test",
2259                                   'password': "password",
2260                                   'domain': "domain2.example.com",
2261                                   'provisioning_sp': "example.com",
2262                                   'sp_priority': "1"})
2263     dev[0].dump_monitor()
2264     dev[0].scan_for_bss(bssid, freq="2412")
2265     check_auto_select(dev[0], bssid)
2266 
2267 def check_conn_capab_selection(dev, type, missing):
2268     dev.request("INTERWORKING_SELECT freq=2412")
2269     ev = dev.wait_event(["INTERWORKING-AP"])
2270     if ev is None:
2271         raise Exception("Network selection timed out")
2272     if "type=" + type not in ev:
2273         raise Exception("Unexpected network type")
2274     if missing and "conn_capab_missing=1" not in ev:
2275         raise Exception("conn_capab_missing not reported")
2276     if not missing and "conn_capab_missing=1" in ev:
2277         raise Exception("conn_capab_missing reported unexpectedly")
2278 
2279 def conn_capab_cred(domain=None, req_conn_capab=None):
2280     cred = default_cred(domain=domain)
2281     if req_conn_capab:
2282         cred['req_conn_capab'] = req_conn_capab
2283     return cred
2284 
2285 def test_ap_hs20_req_conn_capab(dev, apdev):
2286     """Hotspot 2.0 network selection with req_conn_capab"""
2287     check_eap_capa(dev[0], "MSCHAPV2")
2288     bssid = apdev[0]['bssid']
2289     params = hs20_ap_params()
2290     hapd = hostapd.add_ap(apdev[0], params)
2291 
2292     dev[0].hs20_enable()
2293     dev[0].scan_for_bss(bssid, freq="2412")
2294     logger.info("Not used in home network")
2295     values = conn_capab_cred(domain="example.com", req_conn_capab="6:1234")
2296     id = dev[0].add_cred_values(values)
2297     check_conn_capab_selection(dev[0], "home", False)
2298 
2299     logger.info("Used in roaming network")
2300     dev[0].remove_cred(id)
2301     values = conn_capab_cred(domain="example.org", req_conn_capab="6:1234")
2302     id = dev[0].add_cred_values(values)
2303     check_conn_capab_selection(dev[0], "roaming", True)
2304 
2305     logger.info("Verify that req_conn_capab does not prevent connection if no other network is available")
2306     check_auto_select(dev[0], bssid, hapd=hapd)
2307 
2308     logger.info("Additional req_conn_capab checks")
2309 
2310     dev[0].remove_cred(id)
2311     values = conn_capab_cred(domain="example.org", req_conn_capab="1:0")
2312     id = dev[0].add_cred_values(values)
2313     check_conn_capab_selection(dev[0], "roaming", True)
2314 
2315     dev[0].remove_cred(id)
2316     values = conn_capab_cred(domain="example.org", req_conn_capab="17:5060")
2317     id = dev[0].add_cred_values(values)
2318     check_conn_capab_selection(dev[0], "roaming", True)
2319 
2320     bssid2 = apdev[1]['bssid']
2321     params = hs20_ap_params(ssid="test-hs20b")
2322     params['hs20_conn_capab'] = ["1:0:2", "6:22:1", "17:5060:0", "50:0:1"]
2323     hostapd.add_ap(apdev[1], params)
2324 
2325     dev[0].remove_cred(id)
2326     values = conn_capab_cred(domain="example.org", req_conn_capab="50")
2327     id = dev[0].add_cred_values(values)
2328     dev[0].set_cred(id, "req_conn_capab", "6:22")
2329     dev[0].scan_for_bss(bssid2, freq="2412")
2330     dev[0].request("INTERWORKING_SELECT freq=2412")
2331     for i in range(0, 2):
2332         ev = dev[0].wait_event(["INTERWORKING-AP"])
2333         if ev is None:
2334             raise Exception("Network selection timed out")
2335         if bssid in ev and "conn_capab_missing=1" not in ev:
2336             raise Exception("Missing protocol connection capability not reported")
2337         if bssid2 in ev and "conn_capab_missing=1" in ev:
2338             raise Exception("Protocol connection capability not reported correctly")
2339 
2340 def test_ap_hs20_req_conn_capab2(dev, apdev):
2341     """Hotspot 2.0 network selection with req_conn_capab (not present)"""
2342     check_eap_capa(dev[0], "MSCHAPV2")
2343     bssid = apdev[0]['bssid']
2344     params = hs20_ap_params()
2345     del params['hs20_conn_capab']
2346     hostapd.add_ap(apdev[0], params)
2347 
2348     dev[0].hs20_enable()
2349     dev[0].scan_for_bss(bssid, freq="2412")
2350     values = conn_capab_cred(domain="example.org", req_conn_capab="6:1234")
2351     id = dev[0].add_cred_values(values)
2352     check_conn_capab_selection(dev[0], "roaming", False)
2353 
2354 def test_ap_hs20_req_conn_capab_and_roaming_partner_preference(dev, apdev):
2355     """Hotspot 2.0 and req_conn_capab with roaming partner preference"""
2356     check_eap_capa(dev[0], "MSCHAPV2")
2357     bssid = apdev[0]['bssid']
2358     params = hs20_ap_params()
2359     params['domain_name'] = "roaming.example.org"
2360     params['hs20_conn_capab'] = ["1:0:2", "6:22:1", "17:5060:0", "50:0:1"]
2361     hapd = hostapd.add_ap(apdev[0], params)
2362 
2363     bssid2 = apdev[1]['bssid']
2364     params = hs20_ap_params(ssid="test-hs20-b")
2365     params['domain_name'] = "roaming.example.net"
2366     hapd2 = hostapd.add_ap(apdev[1], params)
2367 
2368     values = default_cred()
2369     values['roaming_partner'] = "roaming.example.net,1,127,*"
2370     id = dev[0].add_cred_values(values)
2371     check_auto_select(dev[0], bssid2, hapd=hapd2)
2372 
2373     dev[0].set_cred(id, "req_conn_capab", "50")
2374     check_auto_select(dev[0], bssid, hapd=hapd)
2375 
2376     dev[0].remove_cred(id)
2377     id = dev[0].add_cred_values(values)
2378     dev[0].set_cred(id, "req_conn_capab", "51")
2379     check_auto_select(dev[0], bssid2, hapd=hapd2)
2380 
2381 def check_bandwidth_selection(dev, type, below):
2382     dev.request("INTERWORKING_SELECT freq=2412")
2383     ev = dev.wait_event(["INTERWORKING-AP"])
2384     if ev is None:
2385         raise Exception("Network selection timed out")
2386     logger.debug("BSS entries:\n" + dev.request("BSS RANGE=ALL"))
2387     if "type=" + type not in ev:
2388         raise Exception("Unexpected network type")
2389     if below and "below_min_backhaul=1" not in ev:
2390         raise Exception("below_min_backhaul not reported")
2391     if not below and "below_min_backhaul=1" in ev:
2392         raise Exception("below_min_backhaul reported unexpectedly")
2393 
2394 def bw_cred(domain=None, dl_home=None, ul_home=None, dl_roaming=None, ul_roaming=None):
2395     cred = default_cred(domain=domain)
2396     if dl_home:
2397         cred['min_dl_bandwidth_home'] = str(dl_home)
2398     if ul_home:
2399         cred['min_ul_bandwidth_home'] = str(ul_home)
2400     if dl_roaming:
2401         cred['min_dl_bandwidth_roaming'] = str(dl_roaming)
2402     if ul_roaming:
2403         cred['min_ul_bandwidth_roaming'] = str(ul_roaming)
2404     return cred
2405 
2406 def test_ap_hs20_min_bandwidth_home(dev, apdev):
2407     """Hotspot 2.0 network selection with min bandwidth (home)"""
2408     check_eap_capa(dev[0], "MSCHAPV2")
2409     bssid = apdev[0]['bssid']
2410     params = hs20_ap_params()
2411     hapd = hostapd.add_ap(apdev[0], params)
2412 
2413     dev[0].hs20_enable()
2414     dev[0].scan_for_bss(bssid, freq="2412")
2415     values = bw_cred(domain="example.com", dl_home=5490, ul_home=58)
2416     id = dev[0].add_cred_values(values)
2417     check_bandwidth_selection(dev[0], "home", False)
2418     dev[0].remove_cred(id)
2419 
2420     values = bw_cred(domain="example.com", dl_home=5491, ul_home=58)
2421     id = dev[0].add_cred_values(values)
2422     check_bandwidth_selection(dev[0], "home", True)
2423     dev[0].remove_cred(id)
2424 
2425     values = bw_cred(domain="example.com", dl_home=5490, ul_home=59)
2426     id = dev[0].add_cred_values(values)
2427     check_bandwidth_selection(dev[0], "home", True)
2428     dev[0].remove_cred(id)
2429 
2430     values = bw_cred(domain="example.com", dl_home=5491, ul_home=59)
2431     id = dev[0].add_cred_values(values)
2432     check_bandwidth_selection(dev[0], "home", True)
2433     check_auto_select(dev[0], bssid, hapd=hapd)
2434 
2435     bssid2 = apdev[1]['bssid']
2436     params = hs20_ap_params(ssid="test-hs20-b")
2437     params['hs20_wan_metrics'] = "01:8000:1000:1:1:3000"
2438     hapd2 = hostapd.add_ap(apdev[1], params)
2439 
2440     check_auto_select(dev[0], bssid2, hapd=hapd2)
2441 
2442 def test_ap_hs20_min_bandwidth_home2(dev, apdev):
2443     """Hotspot 2.0 network selection with min bandwidth - special cases"""
2444     check_eap_capa(dev[0], "MSCHAPV2")
2445     bssid = apdev[0]['bssid']
2446     params = hs20_ap_params()
2447     hapd = hostapd.add_ap(apdev[0], params)
2448 
2449     dev[0].hs20_enable()
2450     dev[0].scan_for_bss(bssid, freq="2412")
2451     values = bw_cred(domain="example.com", dl_home=5490, ul_home=58)
2452     id = dev[0].add_cred_values(values)
2453     check_bandwidth_selection(dev[0], "home", False)
2454 
2455     logger.info("WAN link at capacity")
2456     hapd.set('hs20_wan_metrics', "09:8000:1000:80:240:3000")
2457     check_bandwidth_selection(dev[0], "home", True)
2458 
2459     logger.info("Downlink/Uplink Load was not measured")
2460     hapd.set('hs20_wan_metrics', "01:8000:1000:80:240:0")
2461     check_bandwidth_selection(dev[0], "home", False)
2462 
2463     logger.info("Uplink and Downlink max values")
2464     hapd.set('hs20_wan_metrics', "01:4294967295:4294967295:80:240:3000")
2465     check_bandwidth_selection(dev[0], "home", False)
2466 
2467     dev[0].remove_cred(id)
2468 
2469 def test_ap_hs20_min_bandwidth_home_hidden_ssid_in_scan_res(dev, apdev):
2470     """Hotspot 2.0 network selection with min bandwidth (home) while hidden SSID is included in scan results"""
2471     check_eap_capa(dev[0], "MSCHAPV2")
2472     bssid = apdev[0]['bssid']
2473 
2474     hapd = hostapd.add_ap(apdev[0], {"ssid": 'secret',
2475                                      "ignore_broadcast_ssid": "1"})
2476     dev[0].scan_for_bss(bssid, freq=2412)
2477     hapd.disable()
2478     hapd_global = hostapd.HostapdGlobal(apdev[0])
2479     hapd_global.flush()
2480     hapd_global.remove(apdev[0]['ifname'])
2481 
2482     params = hs20_ap_params()
2483     hapd = hostapd.add_ap(apdev[0], params)
2484 
2485     dev[0].hs20_enable()
2486     dev[0].scan_for_bss(bssid, freq="2412")
2487     values = bw_cred(domain="example.com", dl_home=5490, ul_home=58)
2488     id = dev[0].add_cred_values(values)
2489     check_bandwidth_selection(dev[0], "home", False)
2490     dev[0].remove_cred(id)
2491 
2492     values = bw_cred(domain="example.com", dl_home=5491, ul_home=58)
2493     id = dev[0].add_cred_values(values)
2494     check_bandwidth_selection(dev[0], "home", True)
2495     dev[0].remove_cred(id)
2496 
2497     values = bw_cred(domain="example.com", dl_home=5490, ul_home=59)
2498     id = dev[0].add_cred_values(values)
2499     check_bandwidth_selection(dev[0], "home", True)
2500     dev[0].remove_cred(id)
2501 
2502     values = bw_cred(domain="example.com", dl_home=5491, ul_home=59)
2503     id = dev[0].add_cred_values(values)
2504     check_bandwidth_selection(dev[0], "home", True)
2505     check_auto_select(dev[0], bssid, hapd=hapd)
2506 
2507     bssid2 = apdev[1]['bssid']
2508     params = hs20_ap_params(ssid="test-hs20-b")
2509     params['hs20_wan_metrics'] = "01:8000:1000:1:1:3000"
2510     hapd2 = hostapd.add_ap(apdev[1], params)
2511 
2512     check_auto_select(dev[0], bssid2, hapd=hapd2)
2513 
2514     dev[0].flush_scan_cache()
2515 
2516 def test_ap_hs20_min_bandwidth_roaming(dev, apdev):
2517     """Hotspot 2.0 network selection with min bandwidth (roaming)"""
2518     check_eap_capa(dev[0], "MSCHAPV2")
2519     bssid = apdev[0]['bssid']
2520     params = hs20_ap_params()
2521     hapd = hostapd.add_ap(apdev[0], params)
2522 
2523     dev[0].hs20_enable()
2524     dev[0].scan_for_bss(bssid, freq="2412")
2525     values = bw_cred(domain="example.org", dl_roaming=5490, ul_roaming=58)
2526     id = dev[0].add_cred_values(values)
2527     check_bandwidth_selection(dev[0], "roaming", False)
2528     dev[0].remove_cred(id)
2529 
2530     values = bw_cred(domain="example.org", dl_roaming=5491, ul_roaming=58)
2531     id = dev[0].add_cred_values(values)
2532     check_bandwidth_selection(dev[0], "roaming", True)
2533     dev[0].remove_cred(id)
2534 
2535     values = bw_cred(domain="example.org", dl_roaming=5490, ul_roaming=59)
2536     id = dev[0].add_cred_values(values)
2537     check_bandwidth_selection(dev[0], "roaming", True)
2538     dev[0].remove_cred(id)
2539 
2540     values = bw_cred(domain="example.org", dl_roaming=5491, ul_roaming=59)
2541     id = dev[0].add_cred_values(values)
2542     check_bandwidth_selection(dev[0], "roaming", True)
2543     check_auto_select(dev[0], bssid, hapd=hapd)
2544 
2545     bssid2 = apdev[1]['bssid']
2546     params = hs20_ap_params(ssid="test-hs20-b")
2547     params['hs20_wan_metrics'] = "01:8000:1000:1:1:3000"
2548     hapd2 = hostapd.add_ap(apdev[1], params)
2549 
2550     check_auto_select(dev[0], bssid2, hapd=hapd2)
2551 
2552 def test_ap_hs20_min_bandwidth_and_roaming_partner_preference(dev, apdev):
2553     """Hotspot 2.0 and minimum bandwidth with roaming partner preference"""
2554     check_eap_capa(dev[0], "MSCHAPV2")
2555     bssid = apdev[0]['bssid']
2556     params = hs20_ap_params()
2557     params['domain_name'] = "roaming.example.org"
2558     params['hs20_wan_metrics'] = "01:8000:1000:1:1:3000"
2559     hapd = hostapd.add_ap(apdev[0], params)
2560 
2561     bssid2 = apdev[1]['bssid']
2562     params = hs20_ap_params(ssid="test-hs20-b")
2563     params['domain_name'] = "roaming.example.net"
2564     hapd2 = hostapd.add_ap(apdev[1], params)
2565 
2566     values = default_cred()
2567     values['roaming_partner'] = "roaming.example.net,1,127,*"
2568     id = dev[0].add_cred_values(values)
2569     check_auto_select(dev[0], bssid2, hapd=hapd2)
2570 
2571     dev[0].set_cred(id, "min_dl_bandwidth_roaming", "6000")
2572     check_auto_select(dev[0], bssid, hapd=hapd)
2573 
2574     dev[0].set_cred(id, "min_dl_bandwidth_roaming", "10000")
2575     check_auto_select(dev[0], bssid2, hapd=hapd2)
2576 
2577 def test_ap_hs20_min_bandwidth_no_wan_metrics(dev, apdev):
2578     """Hotspot 2.0 network selection with min bandwidth but no WAN Metrics"""
2579     bssid = apdev[0]['bssid']
2580     params = hs20_ap_params()
2581     del params['hs20_wan_metrics']
2582     hostapd.add_ap(apdev[0], params)
2583 
2584     dev[0].hs20_enable()
2585     dev[0].scan_for_bss(bssid, freq="2412")
2586     values = bw_cred(domain="example.com", dl_home=10000, ul_home=10000,
2587                      dl_roaming=10000, ul_roaming=10000)
2588     dev[0].add_cred_values(values)
2589     check_bandwidth_selection(dev[0], "home", False)
2590 
2591 def test_ap_hs20_deauth_req_ess(dev, apdev):
2592     """Hotspot 2.0 connection and deauthentication request for ESS"""
2593     check_eap_capa(dev[0], "MSCHAPV2")
2594     try:
2595         _test_ap_hs20_deauth_req_ess(dev, apdev)
2596     finally:
2597         dev[0].request("SET pmf 0")
2598 
2599 def _test_ap_hs20_deauth_req_ess(dev, apdev):
2600     dev[0].request("SET pmf 2")
2601     hapd = eap_test(dev[0], apdev[0], "21[3:26]", "TTLS", "user")
2602     dev[0].dump_monitor()
2603     addr = dev[0].p2p_interface_addr()
2604     hapd.wait_sta()
2605     hapd.request("HS20_DEAUTH_REQ " + addr + " 1 120 http://example.com/")
2606     ev = dev[0].wait_event(["HS20-DEAUTH-IMMINENT-NOTICE"])
2607     if ev is None:
2608         raise Exception("Timeout on deauth imminent notice")
2609     if "1 120 http://example.com/" not in ev:
2610         raise Exception("Unexpected deauth imminent notice: " + ev)
2611     hapd.request("DEAUTHENTICATE " + addr)
2612     dev[0].wait_disconnected(timeout=10)
2613     if "[TEMP-DISABLED]" not in dev[0].list_networks()[0]['flags']:
2614         raise Exception("Network not marked temporarily disabled")
2615     ev = dev[0].wait_event(["SME: Trying to authenticate",
2616                             "Trying to associate",
2617                             "CTRL-EVENT-CONNECTED"], timeout=5)
2618     if ev is not None:
2619         raise Exception("Unexpected connection attempt")
2620 
2621 def test_ap_hs20_deauth_req_bss(dev, apdev):
2622     """Hotspot 2.0 connection and deauthentication request for BSS"""
2623     check_eap_capa(dev[0], "MSCHAPV2")
2624     try:
2625         _test_ap_hs20_deauth_req_bss(dev, apdev)
2626     finally:
2627         dev[0].request("SET pmf 0")
2628 
2629 def _test_ap_hs20_deauth_req_bss(dev, apdev):
2630     dev[0].request("SET pmf 2")
2631     hapd = eap_test(dev[0], apdev[0], "21[3:26]", "TTLS", "user")
2632     dev[0].dump_monitor()
2633     addr = dev[0].p2p_interface_addr()
2634     hapd.wait_sta()
2635     hapd.request("HS20_DEAUTH_REQ " + addr + " 0 120 http://example.com/")
2636     ev = dev[0].wait_event(["HS20-DEAUTH-IMMINENT-NOTICE"])
2637     if ev is None:
2638         raise Exception("Timeout on deauth imminent notice")
2639     if "0 120 http://example.com/" not in ev:
2640         raise Exception("Unexpected deauth imminent notice: " + ev)
2641     hapd.request("DEAUTHENTICATE " + addr + " reason=4")
2642     ev = dev[0].wait_disconnected(timeout=10)
2643     if "reason=4" not in ev:
2644         raise Exception("Unexpected disconnection reason")
2645     if "[TEMP-DISABLED]" not in dev[0].list_networks()[0]['flags']:
2646         raise Exception("Network not marked temporarily disabled")
2647     ev = dev[0].wait_event(["SME: Trying to authenticate",
2648                             "Trying to associate",
2649                             "CTRL-EVENT-CONNECTED"], timeout=5)
2650     if ev is not None:
2651         raise Exception("Unexpected connection attempt")
2652 
2653 def test_ap_hs20_deauth_req_from_radius(dev, apdev):
2654     """Hotspot 2.0 connection and deauthentication request from RADIUS"""
2655     check_eap_capa(dev[0], "MSCHAPV2")
2656     try:
2657         _test_ap_hs20_deauth_req_from_radius(dev, apdev)
2658     finally:
2659         dev[0].request("SET pmf 0")
2660 
2661 def test_ap_hs20_deauth_req_from_radius_url(dev, apdev):
2662     """Hotspot 2.0 connection and deauthentication request from RADIUS with URL"""
2663     check_eap_capa(dev[0], "MSCHAPV2")
2664     try:
2665         _test_ap_hs20_deauth_req_from_radius(dev, apdev, url=True)
2666     finally:
2667         dev[0].set("pmf", "0")
2668 
2669 def _test_ap_hs20_deauth_req_from_radius(dev, apdev, url=False):
2670     bssid = apdev[0]['bssid']
2671     params = hs20_ap_params()
2672     params['nai_realm'] = ["0,example.com,21[2:4]"]
2673     params['hs20_deauth_req_timeout'] = "2"
2674     hostapd.add_ap(apdev[0], params)
2675 
2676     dev[0].request("SET pmf 2")
2677     dev[0].hs20_enable()
2678     user = "hs20-deauth-test-url" if url else "hs20-deauth-test"
2679     dev[0].add_cred_values({'realm': "example.com",
2680                             'username': user,
2681                             'password': "password"})
2682     interworking_select(dev[0], bssid, freq="2412")
2683     interworking_connect(dev[0], bssid, "TTLS")
2684     ev = dev[0].wait_event(["HS20-DEAUTH-IMMINENT-NOTICE"], timeout=5)
2685     if ev is None:
2686         raise Exception("Timeout on deauth imminent notice")
2687     if not url and ev.split(' ', 1)[1] != "1 100 ":
2688         raise Exception("Unexpected deauth imminent contents: " + ev)
2689     if url and ev.split(' ', 1)[1] != "0 0 https://example.com/deauth/":
2690         raise Exception("Unexpected deauth imminent contents: " + ev)
2691     dev[0].wait_disconnected(timeout=3 if url else 1)
2692 
2693 def test_ap_hs20_deauth_req_without_pmf(dev, apdev):
2694     """Hotspot 2.0 connection and deauthentication request without PMF"""
2695     check_eap_capa(dev[0], "MSCHAPV2")
2696     dev[0].request("SET pmf 0")
2697     hapd = eap_test(dev[0], apdev[0], "21[3:26]", "TTLS", "user", release=1)
2698     dev[0].dump_monitor()
2699     id = int(dev[0].get_status_field("id"))
2700     dev[0].set_network(id, "ieee80211w", "0")
2701     dev[0].request("DISCONNECT")
2702     dev[0].wait_disconnected()
2703     dev[0].select_network(id, freq=2412)
2704     dev[0].wait_connected()
2705     addr = dev[0].own_addr()
2706     hapd.wait_sta()
2707     hapd.request("HS20_DEAUTH_REQ " + addr + " 1 120 http://example.com/")
2708     ev = dev[0].wait_event(["HS20-DEAUTH-IMMINENT-NOTICE"], timeout=0.2)
2709     if ev is not None:
2710         raise Exception("Deauth imminent notice without PMF accepted")
2711     with alloc_fail(hapd, 1, "wpabuf_alloc;hostapd_ctrl_iface_hs20_deauth_req"):
2712         if "FAIL" not in hapd.request("HS20_DEAUTH_REQ " + addr + " 1 120 http://example.com/"):
2713             raise Exception("HS20_DEAUTH_REQ accepted during OOM")
2714 
2715 def test_ap_hs20_deauth_req_pmf_htc(dev, apdev):
2716     """Hotspot 2.0 connection and deauthentication request PMF misbehavior (+HTC)"""
2717     try:
2718         run_ap_hs20_deauth_req_pmf_htc(dev, apdev)
2719     finally:
2720         stop_monitor(apdev[1]["ifname"])
2721 
2722 def run_ap_hs20_deauth_req_pmf_htc(dev, apdev):
2723     check_eap_capa(dev[0], "MSCHAPV2")
2724     dev[0].request("SET pmf 0")
2725     hapd = eap_test(dev[0], apdev[0], "21[3:26]", "TTLS", "user", release=1)
2726     dev[0].dump_monitor()
2727     addr = dev[0].own_addr()
2728     hapd.wait_sta()
2729 
2730     sock = start_monitor(apdev[1]["ifname"])
2731     radiotap = radiotap_build()
2732     bssid = hapd.own_addr().replace(':', '')
2733     addr = dev[0].own_addr().replace(':', '')
2734     payload = "0a1a0101dd1b506f9a0101780013687474703a2f2f6578616d706c652e636f6d2f"
2735     # Claim there is a HT Control field, but then start the frame body from
2736     # there and do not encrypt the Robust Action frame.
2737     frame = binascii.unhexlify("d0803a01" + addr + 2 * bssid + "0000" + payload)
2738     # Claim there is a HT Control field and start the frame body in the correct
2739     # location, but do not encrypt the Robust Action frame. Make the first octet
2740     # of HT Control field use a non-robust Action Category value.
2741     frame2 = binascii.unhexlify("d0803a01" + addr + 2 * bssid + "0000" + "04000000" + payload)
2742 
2743     sock.send(radiotap + frame)
2744     sock.send(radiotap + frame2)
2745 
2746     ev = dev[0].wait_event(["HS20-DEAUTH-IMMINENT-NOTICE"], timeout=1)
2747     if ev is not None:
2748         raise Exception("Deauth imminent notice without PMF accepted")
2749 
2750 def test_ap_hs20_session_info(dev, apdev):
2751     """Hotspot 2.0 connection and session information from RADIUS"""
2752     check_eap_capa(dev[0], "MSCHAPV2")
2753     try:
2754         _test_ap_hs20_session_info(dev, apdev)
2755     finally:
2756         dev[0].request("SET pmf 0")
2757 
2758 def _test_ap_hs20_session_info(dev, apdev):
2759     bssid = apdev[0]['bssid']
2760     params = hs20_ap_params()
2761     params['nai_realm'] = ["0,example.com,21[2:4]"]
2762     hostapd.add_ap(apdev[0], params)
2763 
2764     dev[0].request("SET pmf 1")
2765     dev[0].hs20_enable()
2766     dev[0].add_cred_values({'realm': "example.com",
2767                             'username': "hs20-session-info-test",
2768                             'password': "password"})
2769     interworking_select(dev[0], bssid, freq="2412")
2770     interworking_connect(dev[0], bssid, "TTLS")
2771     ev = dev[0].wait_event(["ESS-DISASSOC-IMMINENT"], timeout=10)
2772     if ev is None:
2773         raise Exception("Timeout on ESS disassociation imminent notice")
2774     if " 1 59904 https://example.com/" not in ev:
2775         raise Exception("Unexpected ESS disassociation imminent event contents")
2776     ev = dev[0].wait_event(["CTRL-EVENT-SCAN-STARTED"])
2777     if ev is None:
2778         raise Exception("Scan not started")
2779     ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"], timeout=30)
2780     if ev is None:
2781         raise Exception("Scan not completed")
2782 
2783 def test_ap_hs20_network_preference(dev, apdev):
2784     """Hotspot 2.0 network selection with preferred home network"""
2785     check_eap_capa(dev[0], "MSCHAPV2")
2786     dev[0].flush_scan_cache()
2787     bssid = apdev[0]['bssid']
2788     params = hs20_ap_params()
2789     hostapd.add_ap(apdev[0], params)
2790 
2791     dev[0].hs20_enable()
2792     values = {'realm': "example.com",
2793               'username': "hs20-test",
2794               'password': "password",
2795               'domain': "example.com"}
2796     dev[0].add_cred_values(values)
2797 
2798     id = dev[0].add_network()
2799     dev[0].set_network_quoted(id, "ssid", "home")
2800     dev[0].set_network_quoted(id, "psk", "12345678")
2801     dev[0].set_network(id, "priority", "1")
2802     dev[0].request("ENABLE_NETWORK %s no-connect" % id)
2803 
2804     dev[0].scan_for_bss(bssid, freq="2412")
2805     dev[0].request("INTERWORKING_SELECT auto freq=2412")
2806     ev = dev[0].wait_connected(timeout=15)
2807     if bssid not in ev:
2808         raise Exception("Unexpected network selected")
2809 
2810     bssid2 = apdev[1]['bssid']
2811     params = hostapd.wpa2_params(ssid="home", passphrase="12345678")
2812     hostapd.add_ap(apdev[1], params)
2813 
2814     dev[0].scan_for_bss(bssid2, freq="2412")
2815     dev[0].request("INTERWORKING_SELECT auto freq=2412")
2816     ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED",
2817                             "INTERWORKING-ALREADY-CONNECTED"], timeout=15)
2818     if ev is None:
2819         raise Exception("Connection timed out")
2820     if "INTERWORKING-ALREADY-CONNECTED" in ev:
2821         raise Exception("No roam to higher priority network")
2822     if bssid2 not in ev:
2823         raise Exception("Unexpected network selected")
2824 
2825 def test_ap_hs20_network_preference2(dev, apdev):
2826     """Hotspot 2.0 network selection with preferred credential"""
2827     check_eap_capa(dev[0], "MSCHAPV2")
2828     dev[0].flush_scan_cache()
2829     bssid2 = apdev[1]['bssid']
2830     params = hostapd.wpa2_params(ssid="home", passphrase="12345678")
2831     hostapd.add_ap(apdev[1], params)
2832 
2833     dev[0].hs20_enable()
2834     values = {'realm': "example.com",
2835               'username': "hs20-test",
2836               'password': "password",
2837               'domain': "example.com",
2838               'priority': "1"}
2839     dev[0].add_cred_values(values)
2840 
2841     id = dev[0].add_network()
2842     dev[0].set_network_quoted(id, "ssid", "home")
2843     dev[0].set_network_quoted(id, "psk", "12345678")
2844     dev[0].request("ENABLE_NETWORK %s no-connect" % id)
2845 
2846     dev[0].scan_for_bss(bssid2, freq="2412")
2847     dev[0].request("INTERWORKING_SELECT auto freq=2412")
2848     ev = dev[0].wait_connected(timeout=15)
2849     if bssid2 not in ev:
2850         raise Exception("Unexpected network selected")
2851 
2852     bssid = apdev[0]['bssid']
2853     params = hs20_ap_params()
2854     hostapd.add_ap(apdev[0], params)
2855 
2856     dev[0].scan_for_bss(bssid, freq="2412")
2857     dev[0].request("INTERWORKING_SELECT auto freq=2412")
2858     ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED",
2859                             "INTERWORKING-ALREADY-CONNECTED"], timeout=15)
2860     if ev is None:
2861         raise Exception("Connection timed out")
2862     if "INTERWORKING-ALREADY-CONNECTED" in ev:
2863         raise Exception("No roam to higher priority network")
2864     if bssid not in ev:
2865         raise Exception("Unexpected network selected")
2866 
2867 def test_ap_hs20_network_preference3(dev, apdev):
2868     """Hotspot 2.0 network selection with two credential (one preferred)"""
2869     check_eap_capa(dev[0], "MSCHAPV2")
2870     dev[0].flush_scan_cache()
2871     bssid = apdev[0]['bssid']
2872     params = hs20_ap_params()
2873     hostapd.add_ap(apdev[0], params)
2874 
2875     bssid2 = apdev[1]['bssid']
2876     params = hs20_ap_params(ssid="test-hs20b")
2877     params['nai_realm'] = "0,example.org,13[5:6],21[2:4][5:7]"
2878     hostapd.add_ap(apdev[1], params)
2879 
2880     dev[0].hs20_enable()
2881     values = {'realm': "example.com",
2882               'username': "hs20-test",
2883               'password': "password",
2884               'priority': "1"}
2885     dev[0].add_cred_values(values)
2886     values = {'realm': "example.org",
2887               'username': "hs20-test",
2888               'password': "password"}
2889     id = dev[0].add_cred_values(values)
2890 
2891     dev[0].scan_for_bss(bssid, freq="2412")
2892     dev[0].scan_for_bss(bssid2, freq="2412")
2893     dev[0].request("INTERWORKING_SELECT auto freq=2412")
2894     ev = dev[0].wait_connected(timeout=15)
2895     if bssid not in ev:
2896         raise Exception("Unexpected network selected")
2897 
2898     dev[0].set_cred(id, "priority", "2")
2899     dev[0].request("INTERWORKING_SELECT auto freq=2412")
2900     ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED",
2901                             "INTERWORKING-ALREADY-CONNECTED"], timeout=15)
2902     if ev is None:
2903         raise Exception("Connection timed out")
2904     if "INTERWORKING-ALREADY-CONNECTED" in ev:
2905         raise Exception("No roam to higher priority network")
2906     if bssid2 not in ev:
2907         raise Exception("Unexpected network selected")
2908 
2909 def test_ap_hs20_network_preference4(dev, apdev):
2910     """Hotspot 2.0 network selection with username vs. SIM credential"""
2911     check_eap_capa(dev[0], "MSCHAPV2")
2912     dev[0].flush_scan_cache()
2913     bssid = apdev[0]['bssid']
2914     params = hs20_ap_params()
2915     hostapd.add_ap(apdev[0], params)
2916 
2917     bssid2 = apdev[1]['bssid']
2918     params = hs20_ap_params(ssid="test-hs20b")
2919     params['hessid'] = bssid2
2920     params['anqp_3gpp_cell_net'] = "555,444"
2921     params['domain_name'] = "wlan.mnc444.mcc555.3gppnetwork.org"
2922     hostapd.add_ap(apdev[1], params)
2923 
2924     dev[0].hs20_enable()
2925     values = {'realm': "example.com",
2926               'username': "hs20-test",
2927               'password': "password",
2928               'priority': "1"}
2929     dev[0].add_cred_values(values)
2930     values = {'imsi': "555444-333222111",
2931               'eap': "SIM",
2932               'milenage': "5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123"}
2933     id = dev[0].add_cred_values(values)
2934 
2935     dev[0].scan_for_bss(bssid, freq="2412")
2936     dev[0].scan_for_bss(bssid2, freq="2412")
2937     dev[0].request("INTERWORKING_SELECT auto freq=2412")
2938     ev = dev[0].wait_connected(timeout=15)
2939     if bssid not in ev:
2940         raise Exception("Unexpected network selected")
2941 
2942     dev[0].set_cred(id, "priority", "2")
2943     dev[0].request("INTERWORKING_SELECT auto freq=2412")
2944     ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED",
2945                             "INTERWORKING-ALREADY-CONNECTED"], timeout=15)
2946     if ev is None:
2947         raise Exception("Connection timed out")
2948     if "INTERWORKING-ALREADY-CONNECTED" in ev:
2949         raise Exception("No roam to higher priority network")
2950     if bssid2 not in ev:
2951         raise Exception("Unexpected network selected")
2952 
2953 def test_ap_hs20_interworking_select_blocking_scan(dev, apdev):
2954     """Ongoing INTERWORKING_SELECT blocking SCAN"""
2955     check_eap_capa(dev[0], "MSCHAPV2")
2956     bssid = apdev[0]['bssid']
2957     params = hs20_ap_params()
2958     hostapd.add_ap(apdev[0], params)
2959 
2960     dev[0].hs20_enable()
2961     values = {'realm': "example.com",
2962               'username': "hs20-test",
2963               'password': "password",
2964               'domain': "example.com"}
2965     dev[0].add_cred_values(values)
2966 
2967     dev[0].scan_for_bss(bssid, freq="2412")
2968     dev[0].request("INTERWORKING_SELECT auto freq=2412")
2969     if "FAIL-BUSY" not in dev[0].request("SCAN"):
2970         raise Exception("Unexpected SCAN command result")
2971     dev[0].wait_connected(timeout=15)
2972 
2973 def test_ap_hs20_ft(dev, apdev):
2974     """Hotspot 2.0 connection with FT"""
2975     check_eap_capa(dev[0], "MSCHAPV2")
2976     bssid = apdev[0]['bssid']
2977     params = hs20_ap_params()
2978     params['wpa_key_mgmt'] = "FT-EAP"
2979     params['nas_identifier'] = "nas1.w1.fi"
2980     params['r1_key_holder'] = "000102030405"
2981     params["mobility_domain"] = "a1b2"
2982     params["reassociation_deadline"] = "1000"
2983     hapd = hostapd.add_ap(apdev[0], params)
2984 
2985     dev[0].hs20_enable()
2986     id = dev[0].add_cred_values({'realm': "example.com",
2987                                  'username': "hs20-test",
2988                                  'password': "password",
2989                                  'ca_cert': "auth_serv/ca.pem",
2990                                  'domain': "example.com",
2991                                  'update_identifier': "1234"})
2992     interworking_select(dev[0], bssid, "home", freq="2412")
2993     interworking_connect(dev[0], bssid, "TTLS")
2994     dev[0].dump_monitor()
2995     key_mgmt = dev[0].get_status_field("key_mgmt")
2996     if key_mgmt != "FT-EAP":
2997         raise Exception("Unexpected key_mgmt: " + key_mgmt)
2998     # speed up testing by avoiding unnecessary scanning of other channels
2999     nid = dev[0].get_status_field("id")
3000     dev[0].set_network(nid, "scan_freq", "2412")
3001 
3002     params = hs20_ap_params()
3003     hapd2 = hostapd.add_ap(apdev[1], params)
3004 
3005     hapd.disable()
3006     ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=10)
3007     if ev is None:
3008         raise Exception("Disconnection not reported")
3009     ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED"], timeout=5)
3010     if ev is None:
3011         raise Exception("Connection to AP2 not reported")
3012     key_mgmt = dev[0].get_status_field("key_mgmt")
3013     if key_mgmt != "WPA2/IEEE 802.1X/EAP":
3014         raise Exception("Unexpected key_mgmt: " + key_mgmt)
3015 
3016 def test_ap_hs20_external_selection(dev, apdev):
3017     """Hotspot 2.0 connection using external network selection and creation"""
3018     check_eap_capa(dev[0], "MSCHAPV2")
3019     bssid = apdev[0]['bssid']
3020     params = hs20_ap_params()
3021     params['hessid'] = bssid
3022     params['disable_dgaf'] = '1'
3023     hostapd.add_ap(apdev[0], params)
3024 
3025     dev[0].hs20_enable()
3026     dev[0].connect("test-hs20", proto="RSN", key_mgmt="WPA-EAP", eap="TTLS",
3027                    ieee80211w="1",
3028                    identity="hs20-test", password="password",
3029                    ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
3030                    scan_freq="2412", update_identifier="54321",
3031                    roaming_consortium_selection="1020304050")
3032     if dev[0].get_status_field("hs20") != "3":
3033         raise Exception("Unexpected hs20 indication")
3034     network_id = dev[0].get_status_field("id")
3035     sel = dev[0].get_network(network_id, "roaming_consortium_selection")
3036     if sel != "1020304050":
3037         raise Exception("Unexpected roaming_consortium_selection value: " + sel)
3038 
3039 def test_ap_hs20_random_mac_addr(dev, apdev):
3040     """Hotspot 2.0 connection with random MAC address"""
3041     check_eap_capa(dev[0], "MSCHAPV2")
3042     bssid = apdev[0]['bssid']
3043     params = hs20_ap_params()
3044     params['hessid'] = bssid
3045     params['disable_dgaf'] = '1'
3046     hapd = hostapd.add_ap(apdev[0], params)
3047 
3048     wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
3049     wpas.interface_add("wlan5")
3050     addr = wpas.p2p_interface_addr()
3051     wpas.request("SET mac_addr 1")
3052     wpas.request("SET preassoc_mac_addr 1")
3053     wpas.request("SET rand_addr_lifetime 60")
3054     wpas.hs20_enable()
3055     wpas.flush_scan_cache()
3056     id = wpas.add_cred_values({'realm': "example.com",
3057                                'username': "hs20-test",
3058                                'password': "password",
3059                                'ca_cert': "auth_serv/ca.pem",
3060                                'domain': "example.com",
3061                                'update_identifier': "1234"})
3062     interworking_select(wpas, bssid, "home", freq="2412")
3063     interworking_connect(wpas, bssid, "TTLS")
3064     addr1 = wpas.get_driver_status_field("addr")
3065     if addr == addr1:
3066         raise Exception("Did not use random MAC address")
3067 
3068     sta = hapd.get_sta(addr)
3069     if sta['addr'] != "FAIL":
3070         raise Exception("Unexpected STA association with permanent address")
3071     sta = hapd.get_sta(addr1)
3072     if sta['addr'] != addr1:
3073         raise Exception("STA association with random address not found")
3074 
3075 def test_ap_hs20_multi_network_and_cred_removal(dev, apdev):
3076     """Multiple networks and cred removal"""
3077     check_eap_capa(dev[0], "MSCHAPV2")
3078     bssid = apdev[0]['bssid']
3079     params = hs20_ap_params()
3080     params['nai_realm'] = ["0,example.com,25[3:26]"]
3081     hapd = hostapd.add_ap(apdev[0], params)
3082 
3083     dev[0].add_network()
3084     dev[0].hs20_enable()
3085     id = dev[0].add_cred_values({'realm': "example.com",
3086                                  'username': "user",
3087                                  'password': "password"})
3088     interworking_select(dev[0], bssid, freq="2412")
3089     interworking_connect(dev[0], bssid, "PEAP")
3090     dev[0].add_network()
3091 
3092     dev[0].request("DISCONNECT")
3093     dev[0].wait_disconnected(timeout=10)
3094 
3095     hapd.disable()
3096     hapd.set("ssid", "another ssid")
3097     hapd.enable()
3098 
3099     interworking_select(dev[0], bssid, freq="2412")
3100     interworking_connect(dev[0], bssid, "PEAP")
3101     dev[0].add_network()
3102     if len(dev[0].list_networks()) != 5:
3103         raise Exception("Unexpected number of networks prior to remove_cred")
3104 
3105     dev[0].dump_monitor()
3106     dev[0].remove_cred(id)
3107     if len(dev[0].list_networks()) != 3:
3108         raise Exception("Unexpected number of networks after to remove_cred")
3109     dev[0].wait_disconnected(timeout=10)
3110 
3111 def test_ap_hs20_interworking_add_network(dev, apdev):
3112     """Hotspot 2.0 connection using INTERWORKING_ADD_NETWORK"""
3113     check_eap_capa(dev[0], "MSCHAPV2")
3114     bssid = apdev[0]['bssid']
3115     params = hs20_ap_params()
3116     params['nai_realm'] = ["0,example.com,21[3:26][6:7][99:99]"]
3117     hostapd.add_ap(apdev[0], params)
3118 
3119     dev[0].hs20_enable()
3120     dev[0].add_cred_values(default_cred(user="user"))
3121     interworking_select(dev[0], bssid, freq=2412)
3122     id = dev[0].interworking_add_network(bssid)
3123     dev[0].select_network(id, freq=2412)
3124     dev[0].wait_connected()
3125 
3126 def _test_ap_hs20_proxyarp(dev, apdev):
3127     bssid = apdev[0]['bssid']
3128     params = hs20_ap_params()
3129     params['hessid'] = bssid
3130     params['disable_dgaf'] = '0'
3131     params['proxy_arp'] = '1'
3132     hapd = hostapd.add_ap(apdev[0], params, no_enable=True)
3133     if "OK" in hapd.request("ENABLE"):
3134         raise Exception("Incomplete hostapd configuration was accepted")
3135     hapd.set("ap_isolate", "1")
3136     if "OK" in hapd.request("ENABLE"):
3137         raise Exception("Incomplete hostapd configuration was accepted")
3138     hapd.set('bridge', 'ap-br0')
3139     hapd.dump_monitor()
3140     try:
3141         hapd.enable()
3142     except:
3143         # For now, do not report failures due to missing kernel support
3144         raise HwsimSkip("Could not start hostapd - assume proxyarp not supported in kernel version")
3145     ev = hapd.wait_event(["AP-ENABLED", "AP-DISABLED"], timeout=10)
3146     if ev is None:
3147         raise Exception("AP startup timed out")
3148     if "AP-ENABLED" not in ev:
3149         raise Exception("AP startup failed")
3150 
3151     dev[0].hs20_enable()
3152     subprocess.call(['brctl', 'setfd', 'ap-br0', '0'])
3153     subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'up'])
3154 
3155     id = dev[0].add_cred_values({'realm': "example.com",
3156                                  'username': "hs20-test",
3157                                  'password': "password",
3158                                  'ca_cert': "auth_serv/ca.pem",
3159                                  'domain': "example.com",
3160                                  'update_identifier': "1234"})
3161     interworking_select(dev[0], bssid, "home", freq="2412")
3162     interworking_connect(dev[0], bssid, "TTLS")
3163 
3164     dev[1].connect("test-hs20", key_mgmt="WPA-EAP", eap="TTLS",
3165                    identity="hs20-test", password="password",
3166                    ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
3167                    scan_freq="2412")
3168     time.sleep(0.1)
3169 
3170     addr0 = dev[0].p2p_interface_addr()
3171     addr1 = dev[1].p2p_interface_addr()
3172 
3173     src_ll_opt0 = b"\x01\x01" + binascii.unhexlify(addr0.replace(':', ''))
3174     src_ll_opt1 = b"\x01\x01" + binascii.unhexlify(addr1.replace(':', ''))
3175 
3176     pkt = build_ns(src_ll=addr0, ip_src="aaaa:bbbb:cccc::2",
3177                    ip_dst="ff02::1:ff00:2", target="aaaa:bbbb:cccc::2",
3178                    opt=src_ll_opt0)
3179     if "OK" not in dev[0].request("DATA_TEST_FRAME " + binascii.hexlify(pkt).decode()):
3180         raise Exception("DATA_TEST_FRAME failed")
3181 
3182     pkt = build_ns(src_ll=addr1, ip_src="aaaa:bbbb:dddd::2",
3183                    ip_dst="ff02::1:ff00:2", target="aaaa:bbbb:dddd::2",
3184                    opt=src_ll_opt1)
3185     if "OK" not in dev[1].request("DATA_TEST_FRAME " + binascii.hexlify(pkt).decode()):
3186         raise Exception("DATA_TEST_FRAME failed")
3187 
3188     pkt = build_ns(src_ll=addr1, ip_src="aaaa:bbbb:eeee::2",
3189                    ip_dst="ff02::1:ff00:2", target="aaaa:bbbb:eeee::2",
3190                    opt=src_ll_opt1)
3191     if "OK" not in dev[1].request("DATA_TEST_FRAME " + binascii.hexlify(pkt).decode()):
3192         raise Exception("DATA_TEST_FRAME failed")
3193 
3194     # Wait for frames to be processed
3195     time.sleep(0.1)
3196 
3197     matches = get_permanent_neighbors("ap-br0")
3198     logger.info("After connect: " + str(matches))
3199     if len(matches) != 3:
3200         raise Exception("Unexpected number of neighbor entries after connect")
3201     if 'aaaa:bbbb:cccc::2 dev ap-br0 lladdr 02:00:00:00:00:00 PERMANENT' not in matches:
3202         raise Exception("dev0 addr missing")
3203     if 'aaaa:bbbb:dddd::2 dev ap-br0 lladdr 02:00:00:00:01:00 PERMANENT' not in matches:
3204         raise Exception("dev1 addr(1) missing")
3205     if 'aaaa:bbbb:eeee::2 dev ap-br0 lladdr 02:00:00:00:01:00 PERMANENT' not in matches:
3206         raise Exception("dev1 addr(2) missing")
3207     dev[0].request("DISCONNECT")
3208     dev[1].request("DISCONNECT")
3209     time.sleep(0.5)
3210     matches = get_permanent_neighbors("ap-br0")
3211     logger.info("After disconnect: " + str(matches))
3212     if len(matches) > 0:
3213         raise Exception("Unexpected neighbor entries after disconnect")
3214 
3215 def test_ap_hs20_hidden_ssid_in_scan_res(dev, apdev):
3216     """Hotspot 2.0 connection with hidden SSId in scan results"""
3217     check_eap_capa(dev[0], "MSCHAPV2")
3218     bssid = apdev[0]['bssid']
3219 
3220     hapd = hostapd.add_ap(apdev[0], {"ssid": 'secret',
3221                                      "ignore_broadcast_ssid": "1"})
3222     dev[0].scan_for_bss(bssid, freq=2412)
3223     hapd.disable()
3224     hapd_global = hostapd.HostapdGlobal(apdev[0])
3225     hapd_global.flush()
3226     hapd_global.remove(apdev[0]['ifname'])
3227 
3228     params = hs20_ap_params()
3229     params['hessid'] = bssid
3230     hapd = hostapd.add_ap(apdev[0], params)
3231 
3232     dev[0].hs20_enable()
3233     id = dev[0].add_cred_values({'realm': "example.com",
3234                                  'username': "hs20-test",
3235                                  'password': "password",
3236                                  'ca_cert': "auth_serv/ca.pem",
3237                                  'domain': "example.com"})
3238     interworking_select(dev[0], bssid, "home", freq="2412")
3239     interworking_connect(dev[0], bssid, "TTLS")
3240 
3241     # clear BSS table to avoid issues in following test cases
3242     dev[0].request("DISCONNECT")
3243     dev[0].wait_disconnected()
3244     hapd.disable()
3245     dev[0].flush_scan_cache()
3246     dev[0].flush_scan_cache()
3247 
3248 def test_ap_hs20_proxyarp(dev, apdev):
3249     """Hotspot 2.0 and ProxyARP"""
3250     check_eap_capa(dev[0], "MSCHAPV2")
3251     try:
3252         _test_ap_hs20_proxyarp(dev, apdev)
3253     finally:
3254         subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'down'],
3255                         stderr=open('/dev/null', 'w'))
3256         subprocess.call(['brctl', 'delbr', 'ap-br0'],
3257                         stderr=open('/dev/null', 'w'))
3258 
3259 def _test_ap_hs20_proxyarp_dgaf(dev, apdev, disabled):
3260     bssid = apdev[0]['bssid']
3261     params = hs20_ap_params()
3262     params['hessid'] = bssid
3263     params['disable_dgaf'] = '1' if disabled else '0'
3264     params['proxy_arp'] = '1'
3265     params['na_mcast_to_ucast'] = '1'
3266     params['ap_isolate'] = '1'
3267     params['bridge'] = 'ap-br0'
3268     hapd = hostapd.add_ap(apdev[0], params, no_enable=True)
3269     try:
3270         hapd.enable()
3271     except:
3272         # For now, do not report failures due to missing kernel support
3273         raise HwsimSkip("Could not start hostapd - assume proxyarp not supported in kernel version")
3274     ev = hapd.wait_event(["AP-ENABLED"], timeout=10)
3275     if ev is None:
3276         raise Exception("AP startup timed out")
3277 
3278     dev[0].hs20_enable()
3279     subprocess.call(['brctl', 'setfd', 'ap-br0', '0'])
3280     subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'up'])
3281 
3282     id = dev[0].add_cred_values({'realm': "example.com",
3283                                  'username': "hs20-test",
3284                                  'password': "password",
3285                                  'ca_cert': "auth_serv/ca.pem",
3286                                  'domain': "example.com",
3287                                  'update_identifier': "1234"})
3288     interworking_select(dev[0], bssid, "home", freq="2412")
3289     interworking_connect(dev[0], bssid, "TTLS")
3290 
3291     dev[1].connect("test-hs20", key_mgmt="WPA-EAP", eap="TTLS",
3292                    identity="hs20-test", password="password",
3293                    ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
3294                    scan_freq="2412")
3295     time.sleep(0.1)
3296 
3297     addr0 = dev[0].p2p_interface_addr()
3298 
3299     src_ll_opt0 = b"\x01\x01" + binascii.unhexlify(addr0.replace(':', ''))
3300 
3301     pkt = build_ns(src_ll=addr0, ip_src="aaaa:bbbb:cccc::2",
3302                    ip_dst="ff02::1:ff00:2", target="aaaa:bbbb:cccc::2",
3303                    opt=src_ll_opt0)
3304     if "OK" not in dev[0].request("DATA_TEST_FRAME " + binascii.hexlify(pkt).decode()):
3305         raise Exception("DATA_TEST_FRAME failed")
3306 
3307     pkt = build_ra(src_ll=apdev[0]['bssid'], ip_src="aaaa:bbbb:cccc::33",
3308                    ip_dst="ff01::1")
3309     if "OK" not in hapd.request("DATA_TEST_FRAME ifname=ap-br0 " + binascii.hexlify(pkt).decode()):
3310         raise Exception("DATA_TEST_FRAME failed")
3311 
3312     pkt = build_na(src_ll=apdev[0]['bssid'], ip_src="aaaa:bbbb:cccc::44",
3313                    ip_dst="ff01::1", target="aaaa:bbbb:cccc::55")
3314     if "OK" not in hapd.request("DATA_TEST_FRAME ifname=ap-br0 " + binascii.hexlify(pkt).decode()):
3315         raise Exception("DATA_TEST_FRAME failed")
3316 
3317     pkt = build_dhcp_ack(dst_ll="ff:ff:ff:ff:ff:ff", src_ll=bssid,
3318                          ip_src="192.168.1.1", ip_dst="255.255.255.255",
3319                          yiaddr="192.168.1.123", chaddr=addr0)
3320     if "OK" not in hapd.request("DATA_TEST_FRAME ifname=ap-br0 " + binascii.hexlify(pkt).decode()):
3321         raise Exception("DATA_TEST_FRAME failed")
3322     # another copy for additional code coverage
3323     pkt = build_dhcp_ack(dst_ll=addr0, src_ll=bssid,
3324                          ip_src="192.168.1.1", ip_dst="255.255.255.255",
3325                          yiaddr="192.168.1.123", chaddr=addr0)
3326     if "OK" not in hapd.request("DATA_TEST_FRAME ifname=ap-br0 " + binascii.hexlify(pkt).decode()):
3327         raise Exception("DATA_TEST_FRAME failed")
3328 
3329     # Wait for frames to be processed
3330     time.sleep(0.1)
3331 
3332     matches = get_permanent_neighbors("ap-br0")
3333     logger.info("After connect: " + str(matches))
3334     if len(matches) != 2:
3335         raise Exception("Unexpected number of neighbor entries after connect")
3336     if 'aaaa:bbbb:cccc::2 dev ap-br0 lladdr 02:00:00:00:00:00 PERMANENT' not in matches:
3337         raise Exception("dev0 addr missing")
3338     if '192.168.1.123 dev ap-br0 lladdr 02:00:00:00:00:00 PERMANENT' not in matches:
3339         raise Exception("dev0 IPv4 addr missing")
3340     dev[0].request("DISCONNECT")
3341     dev[1].request("DISCONNECT")
3342     time.sleep(0.5)
3343     matches = get_permanent_neighbors("ap-br0")
3344     logger.info("After disconnect: " + str(matches))
3345     if len(matches) > 0:
3346         raise Exception("Unexpected neighbor entries after disconnect")
3347 
3348 def test_ap_hs20_proxyarp_disable_dgaf(dev, apdev):
3349     """Hotspot 2.0 and ProxyARP with DGAF disabled"""
3350     check_eap_capa(dev[0], "MSCHAPV2")
3351     try:
3352         _test_ap_hs20_proxyarp_dgaf(dev, apdev, True)
3353     finally:
3354         subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'down'],
3355                         stderr=open('/dev/null', 'w'))
3356         subprocess.call(['brctl', 'delbr', 'ap-br0'],
3357                         stderr=open('/dev/null', 'w'))
3358 
3359 def test_ap_hs20_proxyarp_enable_dgaf(dev, apdev):
3360     """Hotspot 2.0 and ProxyARP with DGAF enabled"""
3361     check_eap_capa(dev[0], "MSCHAPV2")
3362     try:
3363         _test_ap_hs20_proxyarp_dgaf(dev, apdev, False)
3364     finally:
3365         subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'down'],
3366                         stderr=open('/dev/null', 'w'))
3367         subprocess.call(['brctl', 'delbr', 'ap-br0'],
3368                         stderr=open('/dev/null', 'w'))
3369 
3370 def ip_checksum(buf):
3371     sum = 0
3372     if len(buf) & 0x01:
3373         buf += b'\x00'
3374     for i in range(0, len(buf), 2):
3375         val, = struct.unpack('H', buf[i:i+2])
3376         sum += val
3377     while (sum >> 16):
3378         sum = (sum & 0xffff) + (sum >> 16)
3379     return struct.pack('H', ~sum & 0xffff)
3380 
3381 def ipv6_solicited_node_mcaddr(target):
3382     prefix = socket.inet_pton(socket.AF_INET6, "ff02::1:ff00:0")
3383     mask = socket.inet_pton(socket.AF_INET6, "::ff:ffff")
3384     _target = socket.inet_pton(socket.AF_INET6, target)
3385     p = struct.unpack('4I', prefix)
3386     m = struct.unpack('4I', mask)
3387     t = struct.unpack('4I', _target)
3388     res = (p[0] | (t[0] & m[0]),
3389            p[1] | (t[1] & m[1]),
3390            p[2] | (t[2] & m[2]),
3391            p[3] | (t[3] & m[3]))
3392     return socket.inet_ntop(socket.AF_INET6, struct.pack('4I', *res))
3393 
3394 def build_icmpv6(ipv6_addrs, type, code, payload):
3395     start = struct.pack("BB", type, code)
3396     end = payload
3397     icmp = start + b'\x00\x00' + end
3398     pseudo = ipv6_addrs + struct.pack(">LBBBB", len(icmp), 0, 0, 0, 58)
3399     csum = ip_checksum(pseudo + icmp)
3400     return start + csum + end
3401 
3402 def build_ra(src_ll, ip_src, ip_dst, cur_hop_limit=0, router_lifetime=0,
3403              reachable_time=0, retrans_timer=0, opt=None):
3404     link_mc = binascii.unhexlify("3333ff000002")
3405     _src_ll = binascii.unhexlify(src_ll.replace(':', ''))
3406     proto = b'\x86\xdd'
3407     ehdr = link_mc + _src_ll + proto
3408     _ip_src = socket.inet_pton(socket.AF_INET6, ip_src)
3409     _ip_dst = socket.inet_pton(socket.AF_INET6, ip_dst)
3410 
3411     adv = struct.pack('>BBHLL', cur_hop_limit, 0, router_lifetime,
3412                       reachable_time, retrans_timer)
3413     if opt:
3414         payload = adv + opt
3415     else:
3416         payload = adv
3417     icmp = build_icmpv6(_ip_src + _ip_dst, 134, 0, payload)
3418 
3419     ipv6 = struct.pack('>BBBBHBB', 0x60, 0, 0, 0, len(icmp), 58, 255)
3420     ipv6 += _ip_src + _ip_dst
3421 
3422     return ehdr + ipv6 + icmp
3423 
3424 def build_ns(src_ll, ip_src, ip_dst, target, opt=None):
3425     link_mc = binascii.unhexlify("3333ff000002")
3426     _src_ll = binascii.unhexlify(src_ll.replace(':', ''))
3427     proto = b'\x86\xdd'
3428     ehdr = link_mc + _src_ll + proto
3429     _ip_src = socket.inet_pton(socket.AF_INET6, ip_src)
3430     if ip_dst is None:
3431         ip_dst = ipv6_solicited_node_mcaddr(target)
3432     _ip_dst = socket.inet_pton(socket.AF_INET6, ip_dst)
3433 
3434     reserved = b'\x00\x00\x00\x00'
3435     _target = socket.inet_pton(socket.AF_INET6, target)
3436     if opt:
3437         payload = reserved + _target + opt
3438     else:
3439         payload = reserved + _target
3440     icmp = build_icmpv6(_ip_src + _ip_dst, 135, 0, payload)
3441 
3442     ipv6 = struct.pack('>BBBBHBB', 0x60, 0, 0, 0, len(icmp), 58, 255)
3443     ipv6 += _ip_src + _ip_dst
3444 
3445     return ehdr + ipv6 + icmp
3446 
3447 def send_ns(dev, src_ll=None, target=None, ip_src=None, ip_dst=None, opt=None,
3448             hapd_bssid=None):
3449     if hapd_bssid:
3450         if src_ll is None:
3451             src_ll = hapd_bssid
3452         cmd = "DATA_TEST_FRAME ifname=ap-br0 "
3453     else:
3454         if src_ll is None:
3455             src_ll = dev.p2p_interface_addr()
3456         cmd = "DATA_TEST_FRAME "
3457 
3458     if opt is None:
3459         opt = b"\x01\x01" + binascii.unhexlify(src_ll.replace(':', ''))
3460 
3461     pkt = build_ns(src_ll=src_ll, ip_src=ip_src, ip_dst=ip_dst, target=target,
3462                    opt=opt)
3463     if "OK" not in dev.request(cmd + binascii.hexlify(pkt).decode()):
3464         raise Exception("DATA_TEST_FRAME failed")
3465 
3466 def build_na(src_ll, ip_src, ip_dst, target, opt=None, flags=0):
3467     link_mc = binascii.unhexlify("3333ff000002")
3468     _src_ll = binascii.unhexlify(src_ll.replace(':', ''))
3469     proto = b'\x86\xdd'
3470     ehdr = link_mc + _src_ll + proto
3471     _ip_src = socket.inet_pton(socket.AF_INET6, ip_src)
3472     _ip_dst = socket.inet_pton(socket.AF_INET6, ip_dst)
3473 
3474     _target = socket.inet_pton(socket.AF_INET6, target)
3475     if opt:
3476         payload = struct.pack('>Bxxx', flags) + _target + opt
3477     else:
3478         payload = struct.pack('>Bxxx', flags) + _target
3479     icmp = build_icmpv6(_ip_src + _ip_dst, 136, 0, payload)
3480 
3481     ipv6 = struct.pack('>BBBBHBB', 0x60, 0, 0, 0, len(icmp), 58, 255)
3482     ipv6 += _ip_src + _ip_dst
3483 
3484     return ehdr + ipv6 + icmp
3485 
3486 def send_na(dev, src_ll=None, target=None, ip_src=None, ip_dst=None, opt=None,
3487             hapd_bssid=None):
3488     if hapd_bssid:
3489         if src_ll is None:
3490             src_ll = hapd_bssid
3491         cmd = "DATA_TEST_FRAME ifname=ap-br0 "
3492     else:
3493         if src_ll is None:
3494             src_ll = dev.p2p_interface_addr()
3495         cmd = "DATA_TEST_FRAME "
3496 
3497     pkt = build_na(src_ll=src_ll, ip_src=ip_src, ip_dst=ip_dst, target=target,
3498                    opt=opt)
3499     if "OK" not in dev.request(cmd + binascii.hexlify(pkt).decode()):
3500         raise Exception("DATA_TEST_FRAME failed")
3501 
3502 def build_dhcp_ack(dst_ll, src_ll, ip_src, ip_dst, yiaddr, chaddr,
3503                    subnet_mask="255.255.255.0", truncated_opt=False,
3504                    wrong_magic=False, force_tot_len=None, no_dhcp=False,
3505                    udp_checksum=True):
3506     _dst_ll = binascii.unhexlify(dst_ll.replace(':', ''))
3507     _src_ll = binascii.unhexlify(src_ll.replace(':', ''))
3508     proto = b'\x08\x00'
3509     ehdr = _dst_ll + _src_ll + proto
3510     _ip_src = socket.inet_pton(socket.AF_INET, ip_src)
3511     _ip_dst = socket.inet_pton(socket.AF_INET, ip_dst)
3512     _subnet_mask = socket.inet_pton(socket.AF_INET, subnet_mask)
3513 
3514     _ciaddr = b'\x00\x00\x00\x00'
3515     _yiaddr = socket.inet_pton(socket.AF_INET, yiaddr)
3516     _siaddr = b'\x00\x00\x00\x00'
3517     _giaddr = b'\x00\x00\x00\x00'
3518     _chaddr = binascii.unhexlify(chaddr.replace(':', '') + "00000000000000000000")
3519     payload = struct.pack('>BBBBL3BB', 2, 1, 6, 0, 12345, 0, 0, 0, 0)
3520     payload += _ciaddr + _yiaddr + _siaddr + _giaddr + _chaddr + 192*b'\x00'
3521     # magic
3522     if wrong_magic:
3523         payload += b'\x63\x82\x53\x00'
3524     else:
3525         payload += b'\x63\x82\x53\x63'
3526     if truncated_opt:
3527         payload += b'\x22\xff\x00'
3528     # Option: DHCP Message Type = ACK
3529     payload += b'\x35\x01\x05'
3530     # Pad Option
3531     payload += b'\x00'
3532     # Option: Subnet Mask
3533     payload += b'\x01\x04' + _subnet_mask
3534     # Option: Time Offset
3535     payload += struct.pack('>BBL', 2, 4, 0)
3536     # End Option
3537     payload += b'\xff'
3538     # Pad Option
3539     payload += b'\x00\x00\x00\x00'
3540 
3541     if no_dhcp:
3542         payload = struct.pack('>BBBBL3BB', 2, 1, 6, 0, 12345, 0, 0, 0, 0)
3543         payload += _ciaddr + _yiaddr + _siaddr + _giaddr + _chaddr + 192*b'\x00'
3544 
3545     if udp_checksum:
3546         pseudohdr = _ip_src + _ip_dst + struct.pack('>BBH', 0, 17,
3547                                                     8 + len(payload))
3548         udphdr = struct.pack('>HHHH', 67, 68, 8 + len(payload), 0)
3549         checksum, = struct.unpack('>H', ip_checksum(pseudohdr + udphdr + payload))
3550     else:
3551         checksum = 0
3552     udp = struct.pack('>HHHH', 67, 68, 8 + len(payload), checksum) + payload
3553 
3554     if force_tot_len:
3555         tot_len = force_tot_len
3556     else:
3557         tot_len = 20 + len(udp)
3558     start = struct.pack('>BBHHBBBB', 0x45, 0, tot_len, 0, 0, 0, 128, 17)
3559     ipv4 = start + b'\x00\x00' + _ip_src + _ip_dst
3560     csum = ip_checksum(ipv4)
3561     ipv4 = start + csum + _ip_src + _ip_dst
3562 
3563     return ehdr + ipv4 + udp
3564 
3565 def build_arp(dst_ll, src_ll, opcode, sender_mac, sender_ip,
3566               target_mac, target_ip):
3567     _dst_ll = binascii.unhexlify(dst_ll.replace(':', ''))
3568     _src_ll = binascii.unhexlify(src_ll.replace(':', ''))
3569     proto = b'\x08\x06'
3570     ehdr = _dst_ll + _src_ll + proto
3571 
3572     _sender_mac = binascii.unhexlify(sender_mac.replace(':', ''))
3573     _sender_ip = socket.inet_pton(socket.AF_INET, sender_ip)
3574     _target_mac = binascii.unhexlify(target_mac.replace(':', ''))
3575     _target_ip = socket.inet_pton(socket.AF_INET, target_ip)
3576 
3577     arp = struct.pack('>HHBBH', 1, 0x0800, 6, 4, opcode)
3578     arp += _sender_mac + _sender_ip
3579     arp += _target_mac + _target_ip
3580 
3581     return ehdr + arp
3582 
3583 def send_arp(dev, dst_ll="ff:ff:ff:ff:ff:ff", src_ll=None, opcode=1,
3584              sender_mac=None, sender_ip="0.0.0.0",
3585              target_mac="00:00:00:00:00:00", target_ip="0.0.0.0",
3586              hapd_bssid=None):
3587     if hapd_bssid:
3588         if src_ll is None:
3589             src_ll = hapd_bssid
3590         if sender_mac is None:
3591             sender_mac = hapd_bssid
3592         cmd = "DATA_TEST_FRAME ifname=ap-br0 "
3593     else:
3594         if src_ll is None:
3595             src_ll = dev.p2p_interface_addr()
3596         if sender_mac is None:
3597             sender_mac = dev.p2p_interface_addr()
3598         cmd = "DATA_TEST_FRAME "
3599 
3600     pkt = build_arp(dst_ll=dst_ll, src_ll=src_ll, opcode=opcode,
3601                     sender_mac=sender_mac, sender_ip=sender_ip,
3602                     target_mac=target_mac, target_ip=target_ip)
3603     if "OK" not in dev.request(cmd + binascii.hexlify(pkt).decode()):
3604         raise Exception("DATA_TEST_FRAME failed")
3605 
3606 def get_permanent_neighbors(ifname):
3607     cmd = subprocess.Popen(['ip', 'nei'], stdout=subprocess.PIPE)
3608     out, err = cmd.communicate()
3609     res = out.decode()
3610     return [line.strip() for line in res.splitlines() if "PERMANENT" in line and ifname in line]
3611 
3612 def get_bridge_macs(ifname):
3613     cmd = subprocess.Popen(['brctl', 'showmacs', ifname],
3614                            stdout=subprocess.PIPE)
3615     out, err = cmd.communicate()
3616     return out.decode()
3617 
3618 def tshark_get_arp(cap, filter):
3619     res = run_tshark(cap, filter,
3620                      ["eth.dst", "eth.src",
3621                       "arp.src.hw_mac", "arp.src.proto_ipv4",
3622                       "arp.dst.hw_mac", "arp.dst.proto_ipv4"],
3623                      wait=False)
3624     frames = []
3625     for l in res.splitlines():
3626         frames.append(l.split('\t'))
3627     return frames
3628 
3629 def tshark_get_ns(cap):
3630     res = run_tshark(cap, "icmpv6.type == 135",
3631                      ["eth.dst", "eth.src",
3632                       "ipv6.src", "ipv6.dst",
3633                       "icmpv6.nd.ns.target_address",
3634                       "icmpv6.opt.linkaddr"],
3635                      wait=False)
3636     frames = []
3637     for l in res.splitlines():
3638         frames.append(l.split('\t'))
3639     return frames
3640 
3641 def tshark_get_na(cap):
3642     res = run_tshark(cap, "icmpv6.type == 136",
3643                      ["eth.dst", "eth.src",
3644                       "ipv6.src", "ipv6.dst",
3645                       "icmpv6.nd.na.target_address",
3646                       "icmpv6.opt.linkaddr"],
3647                      wait=False)
3648     frames = []
3649     for l in res.splitlines():
3650         frames.append(l.split('\t'))
3651     return frames
3652 
3653 def _test_proxyarp_open(dev, apdev, params, ebtables=False):
3654     cap_br = params['prefix'] + ".ap-br0.pcap"
3655     cap_dev0 = params['prefix'] + ".%s.pcap" % dev[0].ifname
3656     cap_dev1 = params['prefix'] + ".%s.pcap" % dev[1].ifname
3657     cap_dev2 = params['prefix'] + ".%s.pcap" % dev[2].ifname
3658 
3659     bssid = apdev[0]['bssid']
3660     params = {'ssid': 'open'}
3661     params['proxy_arp'] = '1'
3662     hapd = hostapd.add_ap(apdev[0], params, no_enable=True)
3663     hapd.set("ap_isolate", "1")
3664     hapd.set('bridge', 'ap-br0')
3665     hapd.dump_monitor()
3666     try:
3667         hapd.enable()
3668     except:
3669         # For now, do not report failures due to missing kernel support
3670         raise HwsimSkip("Could not start hostapd - assume proxyarp not supported in kernel version")
3671     ev = hapd.wait_event(["AP-ENABLED", "AP-DISABLED"], timeout=10)
3672     if ev is None:
3673         raise Exception("AP startup timed out")
3674     if "AP-ENABLED" not in ev:
3675         raise Exception("AP startup failed")
3676 
3677     params2 = {'ssid': 'another'}
3678     hapd2 = hostapd.add_ap(apdev[1], params2, no_enable=True)
3679     hapd2.set('bridge', 'ap-br0')
3680     hapd2.enable()
3681 
3682     subprocess.call(['brctl', 'setfd', 'ap-br0', '0'])
3683     subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'up'])
3684 
3685     if ebtables:
3686         for chain in ['FORWARD', 'OUTPUT']:
3687             try:
3688                 err = subprocess.call(['ebtables', '-A', chain, '-p', 'ARP',
3689                                        '-d', 'Broadcast',
3690                                        '-o', apdev[0]['ifname'],
3691                                        '-j', 'DROP'])
3692                 if err != 0:
3693                     raise
3694             except:
3695                 raise HwsimSkip("No ebtables available")
3696 
3697     time.sleep(0.5)
3698     cmd = {}
3699     cmd[0] = WlantestCapture('ap-br0', cap_br)
3700     cmd[1] = WlantestCapture(dev[0].ifname, cap_dev0)
3701     cmd[2] = WlantestCapture(dev[1].ifname, cap_dev1)
3702     cmd[3] = WlantestCapture(dev[2].ifname, cap_dev2)
3703 
3704     dev[0].connect("open", key_mgmt="NONE", scan_freq="2412")
3705     dev[1].connect("open", key_mgmt="NONE", scan_freq="2412")
3706     dev[2].connect("another", key_mgmt="NONE", scan_freq="2412")
3707     time.sleep(1.1)
3708 
3709     brcmd = subprocess.Popen(['brctl', 'show'], stdout=subprocess.PIPE)
3710     out, err = brcmd.communicate()
3711     logger.info("Bridge setup: " + out.decode())
3712 
3713     brcmd = subprocess.Popen(['brctl', 'showstp', 'ap-br0'],
3714                              stdout=subprocess.PIPE)
3715     out, err = brcmd.communicate()
3716     logger.info("Bridge showstp: " + out.decode())
3717 
3718     addr0 = dev[0].p2p_interface_addr()
3719     addr1 = dev[1].p2p_interface_addr()
3720     addr2 = dev[2].p2p_interface_addr()
3721 
3722     pkt = build_dhcp_ack(dst_ll="ff:ff:ff:ff:ff:ff", src_ll=bssid,
3723                          ip_src="192.168.1.1", ip_dst="255.255.255.255",
3724                          yiaddr="192.168.1.124", chaddr=addr0)
3725     if "OK" not in hapd.request("DATA_TEST_FRAME ifname=ap-br0 " + binascii.hexlify(pkt).decode()):
3726         raise Exception("DATA_TEST_FRAME failed")
3727     # Change address and verify unicast
3728     pkt = build_dhcp_ack(dst_ll=addr0, src_ll=bssid,
3729                          ip_src="192.168.1.1", ip_dst="255.255.255.255",
3730                          yiaddr="192.168.1.123", chaddr=addr0,
3731                          udp_checksum=False)
3732     if "OK" not in hapd.request("DATA_TEST_FRAME ifname=ap-br0 " + binascii.hexlify(pkt).decode()):
3733         raise Exception("DATA_TEST_FRAME failed")
3734 
3735     # Not-associated client MAC address
3736     pkt = build_dhcp_ack(dst_ll="ff:ff:ff:ff:ff:ff", src_ll=bssid,
3737                          ip_src="192.168.1.1", ip_dst="255.255.255.255",
3738                          yiaddr="192.168.1.125", chaddr="22:33:44:55:66:77")
3739     if "OK" not in hapd.request("DATA_TEST_FRAME ifname=ap-br0 " + binascii.hexlify(pkt).decode()):
3740         raise Exception("DATA_TEST_FRAME failed")
3741 
3742     # No IP address
3743     pkt = build_dhcp_ack(dst_ll=addr1, src_ll=bssid,
3744                          ip_src="192.168.1.1", ip_dst="255.255.255.255",
3745                          yiaddr="0.0.0.0", chaddr=addr1)
3746     if "OK" not in hapd.request("DATA_TEST_FRAME ifname=ap-br0 " + binascii.hexlify(pkt).decode()):
3747         raise Exception("DATA_TEST_FRAME failed")
3748 
3749     # Zero subnet mask
3750     pkt = build_dhcp_ack(dst_ll=addr1, src_ll=bssid,
3751                          ip_src="192.168.1.1", ip_dst="255.255.255.255",
3752                          yiaddr="192.168.1.126", chaddr=addr1,
3753                          subnet_mask="0.0.0.0")
3754     if "OK" not in hapd.request("DATA_TEST_FRAME ifname=ap-br0 " + binascii.hexlify(pkt).decode()):
3755         raise Exception("DATA_TEST_FRAME failed")
3756 
3757     # Truncated option
3758     pkt = build_dhcp_ack(dst_ll=addr1, src_ll=bssid,
3759                          ip_src="192.168.1.1", ip_dst="255.255.255.255",
3760                          yiaddr="192.168.1.127", chaddr=addr1,
3761                          truncated_opt=True)
3762     if "OK" not in hapd.request("DATA_TEST_FRAME ifname=ap-br0 " + binascii.hexlify(pkt).decode()):
3763         raise Exception("DATA_TEST_FRAME failed")
3764 
3765     # Wrong magic
3766     pkt = build_dhcp_ack(dst_ll=addr1, src_ll=bssid,
3767                          ip_src="192.168.1.1", ip_dst="255.255.255.255",
3768                          yiaddr="192.168.1.128", chaddr=addr1,
3769                          wrong_magic=True)
3770     if "OK" not in hapd.request("DATA_TEST_FRAME ifname=ap-br0 " + binascii.hexlify(pkt).decode()):
3771         raise Exception("DATA_TEST_FRAME failed")
3772 
3773     # Wrong IPv4 total length
3774     pkt = build_dhcp_ack(dst_ll=addr1, src_ll=bssid,
3775                          ip_src="192.168.1.1", ip_dst="255.255.255.255",
3776                          yiaddr="192.168.1.129", chaddr=addr1,
3777                          force_tot_len=1000)
3778     if "OK" not in hapd.request("DATA_TEST_FRAME ifname=ap-br0 " + binascii.hexlify(pkt).decode()):
3779         raise Exception("DATA_TEST_FRAME failed")
3780 
3781     # BOOTP
3782     pkt = build_dhcp_ack(dst_ll=addr1, src_ll=bssid,
3783                          ip_src="192.168.1.1", ip_dst="255.255.255.255",
3784                          yiaddr="192.168.1.129", chaddr=addr1,
3785                          no_dhcp=True)
3786     if "OK" not in hapd.request("DATA_TEST_FRAME ifname=ap-br0 " + binascii.hexlify(pkt).decode()):
3787         raise Exception("DATA_TEST_FRAME failed")
3788 
3789     # Wait for frames to be processed
3790     time.sleep(0.1)
3791 
3792     macs = get_bridge_macs("ap-br0")
3793     logger.info("After connect (showmacs): " + str(macs))
3794 
3795     matches = get_permanent_neighbors("ap-br0")
3796     logger.info("After connect: " + str(matches))
3797     if len(matches) != 1:
3798         raise Exception("Unexpected number of neighbor entries after connect")
3799     if '192.168.1.123 dev ap-br0 lladdr 02:00:00:00:00:00 PERMANENT' not in matches:
3800         raise Exception("dev0 IPv4 addr missing")
3801 
3802     targets = ["192.168.1.123", "192.168.1.124", "192.168.1.125",
3803                "192.168.1.126"]
3804     for target in targets:
3805         send_arp(dev[1], sender_ip="192.168.1.100", target_ip=target)
3806 
3807     for target in targets:
3808         send_arp(hapd, hapd_bssid=bssid, sender_ip="192.168.1.101",
3809                  target_ip=target)
3810 
3811     for target in targets:
3812         send_arp(dev[2], sender_ip="192.168.1.103", target_ip=target)
3813 
3814     # ARP Probe from wireless STA
3815     send_arp(dev[1], target_ip="192.168.1.127")
3816     # ARP Announcement from wireless STA
3817     send_arp(dev[1], sender_ip="192.168.1.127", target_ip="192.168.1.127")
3818     send_arp(dev[1], sender_ip="192.168.1.127", target_ip="192.168.1.127",
3819              opcode=2)
3820 
3821     macs = get_bridge_macs("ap-br0")
3822     logger.info("After ARP Probe + Announcement (showmacs): " + str(macs))
3823 
3824     matches = get_permanent_neighbors("ap-br0")
3825     logger.info("After ARP Probe + Announcement: " + str(matches))
3826 
3827     # ARP Request for the newly introduced IP address from wireless STA
3828     send_arp(dev[0], sender_ip="192.168.1.123", target_ip="192.168.1.127")
3829 
3830     # ARP Request for the newly introduced IP address from bridge
3831     send_arp(hapd, hapd_bssid=bssid, sender_ip="192.168.1.102",
3832              target_ip="192.168.1.127")
3833     send_arp(dev[2], sender_ip="192.168.1.103", target_ip="192.168.1.127")
3834 
3835     # ARP Probe from bridge
3836     send_arp(hapd, hapd_bssid=bssid, target_ip="192.168.1.130")
3837     send_arp(dev[2], target_ip="192.168.1.131")
3838     # ARP Announcement from bridge (not to be learned by AP for proxyarp)
3839     send_arp(hapd, hapd_bssid=bssid, sender_ip="192.168.1.130",
3840              target_ip="192.168.1.130")
3841     send_arp(hapd, hapd_bssid=bssid, sender_ip="192.168.1.130",
3842              target_ip="192.168.1.130", opcode=2)
3843     send_arp(dev[2], sender_ip="192.168.1.131", target_ip="192.168.1.131")
3844     send_arp(dev[2], sender_ip="192.168.1.131", target_ip="192.168.1.131",
3845              opcode=2)
3846 
3847     macs = get_bridge_macs("ap-br0")
3848     logger.info("After ARP Probe + Announcement (showmacs): " + str(macs))
3849 
3850     matches = get_permanent_neighbors("ap-br0")
3851     logger.info("After ARP Probe + Announcement: " + str(matches))
3852 
3853     # ARP Request for the newly introduced IP address from wireless STA
3854     send_arp(dev[0], sender_ip="192.168.1.123", target_ip="192.168.1.130")
3855     # ARP Response from bridge (AP does not proxy for non-wireless devices)
3856     send_arp(hapd, hapd_bssid=bssid, dst_ll=addr0, sender_ip="192.168.1.130",
3857              target_ip="192.168.1.123", opcode=2)
3858 
3859     # ARP Request for the newly introduced IP address from wireless STA
3860     send_arp(dev[0], sender_ip="192.168.1.123", target_ip="192.168.1.131")
3861     # ARP Response from bridge (AP does not proxy for non-wireless devices)
3862     send_arp(dev[2], dst_ll=addr0, sender_ip="192.168.1.131",
3863              target_ip="192.168.1.123", opcode=2)
3864 
3865     # ARP Request for the newly introduced IP address from bridge
3866     send_arp(hapd, hapd_bssid=bssid, sender_ip="192.168.1.102",
3867              target_ip="192.168.1.130")
3868     send_arp(dev[2], sender_ip="192.168.1.104", target_ip="192.168.1.131")
3869 
3870     # ARP Probe from wireless STA (duplicate address; learned through DHCP)
3871     send_arp(dev[1], target_ip="192.168.1.123")
3872     # ARP Probe from wireless STA (duplicate address; learned through ARP)
3873     send_arp(dev[0], target_ip="192.168.1.127")
3874 
3875     # Gratuitous ARP Reply for another STA's IP address
3876     send_arp(dev[0], opcode=2, sender_mac=addr0, sender_ip="192.168.1.127",
3877              target_mac=addr1, target_ip="192.168.1.127")
3878     send_arp(dev[1], opcode=2, sender_mac=addr1, sender_ip="192.168.1.123",
3879              target_mac=addr0, target_ip="192.168.1.123")
3880     # ARP Request to verify previous mapping
3881     send_arp(dev[1], sender_ip="192.168.1.127", target_ip="192.168.1.123")
3882     send_arp(dev[0], sender_ip="192.168.1.123", target_ip="192.168.1.127")
3883 
3884     try:
3885         hwsim_utils.test_connectivity_iface(dev[0], hapd, "ap-br0")
3886     except Exception as e:
3887         logger.info("test_connectibity_iface failed: " + str(e))
3888         raise HwsimSkip("Assume kernel did not have the required patches for proxyarp")
3889     hwsim_utils.test_connectivity_iface(dev[1], hapd, "ap-br0")
3890     hwsim_utils.test_connectivity(dev[0], dev[1])
3891 
3892     dev[0].request("DISCONNECT")
3893     dev[1].request("DISCONNECT")
3894     time.sleep(1.5)
3895     for i in range(len(cmd)):
3896         cmd[i].close()
3897     time.sleep(0.1)
3898     macs = get_bridge_macs("ap-br0")
3899     logger.info("After disconnect (showmacs): " + str(macs))
3900     matches = get_permanent_neighbors("ap-br0")
3901     logger.info("After disconnect: " + str(matches))
3902     if len(matches) > 0:
3903         raise Exception("Unexpected neighbor entries after disconnect")
3904     if ebtables:
3905         cmd = subprocess.Popen(['ebtables', '-L', '--Lc'],
3906                                stdout=subprocess.PIPE)
3907         out, err = cmd.communicate()
3908         logger.info("ebtables results:\n" + out.decode())
3909 
3910     # Verify that expected ARP messages were seen and no unexpected
3911     # ARP messages were seen.
3912 
3913     arp_req = tshark_get_arp(cap_dev0, "arp.opcode == 1")
3914     arp_reply = tshark_get_arp(cap_dev0, "arp.opcode == 2")
3915     logger.info("dev0 seen ARP requests:\n" + str(arp_req))
3916     logger.info("dev0 seen ARP replies:\n" + str(arp_reply))
3917 
3918     if ['ff:ff:ff:ff:ff:ff', addr1,
3919         addr1, '192.168.1.100',
3920         '00:00:00:00:00:00', '192.168.1.123'] in arp_req:
3921         raise Exception("dev0 saw ARP request from dev1")
3922     if ['ff:ff:ff:ff:ff:ff', addr2,
3923         addr2, '192.168.1.103',
3924         '00:00:00:00:00:00', '192.168.1.123'] in arp_req:
3925         raise Exception("dev0 saw ARP request from dev2")
3926     # TODO: Uncomment once fixed in kernel
3927     #if ['ff:ff:ff:ff:ff:ff', bssid,
3928     #    bssid, '192.168.1.101',
3929     #    '00:00:00:00:00:00', '192.168.1.123'] in arp_req:
3930     #    raise Exception("dev0 saw ARP request from br")
3931 
3932     if ebtables:
3933         for req in arp_req:
3934             if req[1] != addr0:
3935                 raise Exception("Unexpected foreign ARP request on dev0")
3936 
3937     arp_req = tshark_get_arp(cap_dev1, "arp.opcode == 1")
3938     arp_reply = tshark_get_arp(cap_dev1, "arp.opcode == 2")
3939     logger.info("dev1 seen ARP requests:\n" + str(arp_req))
3940     logger.info("dev1 seen ARP replies:\n" + str(arp_reply))
3941 
3942     if ['ff:ff:ff:ff:ff:ff', addr2,
3943         addr2, '192.168.1.103',
3944         '00:00:00:00:00:00', '192.168.1.123'] in arp_req:
3945         raise Exception("dev1 saw ARP request from dev2")
3946     if [addr1, addr0, addr0, '192.168.1.123', addr1, '192.168.1.100'] not in arp_reply:
3947         raise Exception("dev1 did not get ARP response for 192.168.1.123")
3948 
3949     if ebtables:
3950         for req in arp_req:
3951             if req[1] != addr1:
3952                 raise Exception("Unexpected foreign ARP request on dev1")
3953 
3954     arp_req = tshark_get_arp(cap_dev2, "arp.opcode == 1")
3955     arp_reply = tshark_get_arp(cap_dev2, "arp.opcode == 2")
3956     logger.info("dev2 seen ARP requests:\n" + str(arp_req))
3957     logger.info("dev2 seen ARP replies:\n" + str(arp_reply))
3958 
3959     if [addr2, addr0,
3960         addr0, '192.168.1.123',
3961         addr2, '192.168.1.103'] not in arp_reply:
3962         raise Exception("dev2 did not get ARP response for 192.168.1.123")
3963 
3964     arp_req = tshark_get_arp(cap_br, "arp.opcode == 1")
3965     arp_reply = tshark_get_arp(cap_br, "arp.opcode == 2")
3966     logger.info("br seen ARP requests:\n" + str(arp_req))
3967     logger.info("br seen ARP replies:\n" + str(arp_reply))
3968 
3969     # TODO: Uncomment once fixed in kernel
3970     #if [bssid, addr0,
3971     #    addr0, '192.168.1.123',
3972     #    bssid, '192.168.1.101'] not in arp_reply:
3973     #    raise Exception("br did not get ARP response for 192.168.1.123")
3974 
3975 def _test_proxyarp_open_ipv6(dev, apdev, params, ebtables=False):
3976     cap_br = params['prefix'] + ".ap-br0.pcap"
3977     cap_dev0 = params['prefix'] + ".%s.pcap" % dev[0].ifname
3978     cap_dev1 = params['prefix'] + ".%s.pcap" % dev[1].ifname
3979     cap_dev2 = params['prefix'] + ".%s.pcap" % dev[2].ifname
3980 
3981     bssid = apdev[0]['bssid']
3982     params = {'ssid': 'open'}
3983     params['proxy_arp'] = '1'
3984     hapd = hostapd.add_ap(apdev[0], params, no_enable=True)
3985     hapd.set("ap_isolate", "1")
3986     hapd.set('bridge', 'ap-br0')
3987     hapd.dump_monitor()
3988     try:
3989         hapd.enable()
3990     except:
3991         # For now, do not report failures due to missing kernel support
3992         raise HwsimSkip("Could not start hostapd - assume proxyarp not supported in kernel version")
3993     ev = hapd.wait_event(["AP-ENABLED", "AP-DISABLED"], timeout=10)
3994     if ev is None:
3995         raise Exception("AP startup timed out")
3996     if "AP-ENABLED" not in ev:
3997         raise Exception("AP startup failed")
3998 
3999     params2 = {'ssid': 'another'}
4000     hapd2 = hostapd.add_ap(apdev[1], params2, no_enable=True)
4001     hapd2.set('bridge', 'ap-br0')
4002     hapd2.enable()
4003 
4004     subprocess.call(['brctl', 'setfd', 'ap-br0', '0'])
4005     subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'up'])
4006 
4007     if ebtables:
4008         for chain in ['FORWARD', 'OUTPUT']:
4009             try:
4010                 err = subprocess.call(['ebtables', '-A', chain,
4011                                        '-d', 'Multicast',
4012                                        '-p', 'IPv6',
4013                                        '--ip6-protocol', 'ipv6-icmp',
4014                                        '--ip6-icmp-type',
4015                                        'neighbor-solicitation',
4016                                        '-o', apdev[0]['ifname'], '-j', 'DROP'])
4017                 if err != 0:
4018                     raise
4019                 subprocess.call(['ebtables', '-A', chain, '-d', 'Multicast',
4020                                  '-p', 'IPv6', '--ip6-protocol', 'ipv6-icmp',
4021                                  '--ip6-icmp-type', 'neighbor-advertisement',
4022                                  '-o', apdev[0]['ifname'], '-j', 'DROP'])
4023                 subprocess.call(['ebtables', '-A', chain,
4024                                  '-p', 'IPv6', '--ip6-protocol', 'ipv6-icmp',
4025                                  '--ip6-icmp-type', 'router-solicitation',
4026                                  '-o', apdev[0]['ifname'], '-j', 'DROP'])
4027                 # Multicast Listener Report Message
4028                 subprocess.call(['ebtables', '-A', chain, '-d', 'Multicast',
4029                                  '-p', 'IPv6', '--ip6-protocol', 'ipv6-icmp',
4030                                  '--ip6-icmp-type', '143',
4031                                  '-o', apdev[0]['ifname'], '-j', 'DROP'])
4032             except:
4033                 raise HwsimSkip("No ebtables available")
4034 
4035     time.sleep(0.5)
4036     cmd = {}
4037     cmd[0] = WlantestCapture('ap-br0', cap_br)
4038     cmd[1] = WlantestCapture(dev[0].ifname, cap_dev0)
4039     cmd[2] = WlantestCapture(dev[1].ifname, cap_dev1)
4040     cmd[3] = WlantestCapture(dev[2].ifname, cap_dev2)
4041 
4042     dev[0].connect("open", key_mgmt="NONE", scan_freq="2412")
4043     dev[1].connect("open", key_mgmt="NONE", scan_freq="2412")
4044     dev[2].connect("another", key_mgmt="NONE", scan_freq="2412")
4045     time.sleep(0.1)
4046 
4047     brcmd = subprocess.Popen(['brctl', 'show'], stdout=subprocess.PIPE)
4048     out, err = brcmd.communicate()
4049     logger.info("Bridge setup: " + out.decode())
4050 
4051     brcmd = subprocess.Popen(['brctl', 'showstp', 'ap-br0'],
4052                              stdout=subprocess.PIPE)
4053     out, err = brcmd.communicate()
4054     logger.info("Bridge showstp: " + out.decode())
4055 
4056     addr0 = dev[0].p2p_interface_addr()
4057     addr1 = dev[1].p2p_interface_addr()
4058     addr2 = dev[2].p2p_interface_addr()
4059 
4060     src_ll_opt0 = b"\x01\x01" + binascii.unhexlify(addr0.replace(':', ''))
4061     src_ll_opt1 = b"\x01\x01" + binascii.unhexlify(addr1.replace(':', ''))
4062 
4063     # DAD NS
4064     send_ns(dev[0], ip_src="::", target="aaaa:bbbb:cccc::2")
4065 
4066     send_ns(dev[0], ip_src="aaaa:bbbb:cccc::2", target="aaaa:bbbb:cccc::2")
4067     # test frame without source link-layer address option
4068     send_ns(dev[0], ip_src="aaaa:bbbb:cccc::2", target="aaaa:bbbb:cccc::2",
4069             opt='')
4070     # test frame with bogus option
4071     send_ns(dev[0], ip_src="aaaa:bbbb:cccc::2", target="aaaa:bbbb:cccc::2",
4072             opt=b"\x70\x01\x01\x02\x03\x04\x05\x05")
4073     # test frame with truncated source link-layer address option
4074     send_ns(dev[0], ip_src="aaaa:bbbb:cccc::2", target="aaaa:bbbb:cccc::2",
4075             opt=b"\x01\x01\x01\x02\x03\x04")
4076     # test frame with foreign source link-layer address option
4077     send_ns(dev[0], ip_src="aaaa:bbbb:cccc::2", target="aaaa:bbbb:cccc::2",
4078             opt=b"\x01\x01\x01\x02\x03\x04\x05\x06")
4079 
4080     send_ns(dev[1], ip_src="aaaa:bbbb:dddd::2", target="aaaa:bbbb:dddd::2")
4081 
4082     send_ns(dev[1], ip_src="aaaa:bbbb:eeee::2", target="aaaa:bbbb:eeee::2")
4083     # another copy for additional code coverage
4084     send_ns(dev[1], ip_src="aaaa:bbbb:eeee::2", target="aaaa:bbbb:eeee::2")
4085 
4086     macs = get_bridge_macs("ap-br0")
4087     logger.info("After connect (showmacs): " + str(macs))
4088 
4089     matches = get_permanent_neighbors("ap-br0")
4090     logger.info("After connect: " + str(matches))
4091     if len(matches) != 3:
4092         raise Exception("Unexpected number of neighbor entries after connect")
4093     if 'aaaa:bbbb:cccc::2 dev ap-br0 lladdr 02:00:00:00:00:00 PERMANENT' not in matches:
4094         raise Exception("dev0 addr missing")
4095     if 'aaaa:bbbb:dddd::2 dev ap-br0 lladdr 02:00:00:00:01:00 PERMANENT' not in matches:
4096         raise Exception("dev1 addr(1) missing")
4097     if 'aaaa:bbbb:eeee::2 dev ap-br0 lladdr 02:00:00:00:01:00 PERMANENT' not in matches:
4098         raise Exception("dev1 addr(2) missing")
4099 
4100     send_ns(dev[0], target="aaaa:bbbb:dddd::2", ip_src="aaaa:bbbb:cccc::2")
4101     time.sleep(0.1)
4102     send_ns(dev[1], target="aaaa:bbbb:cccc::2", ip_src="aaaa:bbbb:dddd::2")
4103     time.sleep(0.1)
4104     send_ns(hapd, hapd_bssid=bssid, target="aaaa:bbbb:dddd::2",
4105             ip_src="aaaa:bbbb:ffff::2")
4106     time.sleep(0.1)
4107     send_ns(dev[2], target="aaaa:bbbb:cccc::2", ip_src="aaaa:bbbb:ff00::2")
4108     time.sleep(0.1)
4109     send_ns(dev[2], target="aaaa:bbbb:dddd::2", ip_src="aaaa:bbbb:ff00::2")
4110     time.sleep(0.1)
4111     send_ns(dev[2], target="aaaa:bbbb:eeee::2", ip_src="aaaa:bbbb:ff00::2")
4112     time.sleep(0.1)
4113 
4114     # Try to probe for an already assigned address
4115     send_ns(dev[1], target="aaaa:bbbb:cccc::2", ip_src="::")
4116     time.sleep(0.1)
4117     send_ns(hapd, hapd_bssid=bssid, target="aaaa:bbbb:cccc::2", ip_src="::")
4118     time.sleep(0.1)
4119     send_ns(dev[2], target="aaaa:bbbb:cccc::2", ip_src="::")
4120     time.sleep(0.1)
4121 
4122     # Unsolicited NA
4123     send_na(dev[1], target="aaaa:bbbb:cccc:aeae::3",
4124             ip_src="aaaa:bbbb:cccc:aeae::3", ip_dst="ff02::1")
4125     send_na(hapd, hapd_bssid=bssid, target="aaaa:bbbb:cccc:aeae::4",
4126             ip_src="aaaa:bbbb:cccc:aeae::4", ip_dst="ff02::1")
4127     send_na(dev[2], target="aaaa:bbbb:cccc:aeae::5",
4128             ip_src="aaaa:bbbb:cccc:aeae::5", ip_dst="ff02::1")
4129 
4130     try:
4131         hwsim_utils.test_connectivity_iface(dev[0], hapd, "ap-br0")
4132     except Exception as e:
4133         logger.info("test_connectibity_iface failed: " + str(e))
4134         raise HwsimSkip("Assume kernel did not have the required patches for proxyarp")
4135     hwsim_utils.test_connectivity_iface(dev[1], hapd, "ap-br0")
4136     hwsim_utils.test_connectivity(dev[0], dev[1])
4137 
4138     dev[0].request("DISCONNECT")
4139     dev[1].request("DISCONNECT")
4140     time.sleep(0.5)
4141     for i in range(len(cmd)):
4142         cmd[i].close()
4143     macs = get_bridge_macs("ap-br0")
4144     logger.info("After disconnect (showmacs): " + str(macs))
4145     matches = get_permanent_neighbors("ap-br0")
4146     logger.info("After disconnect: " + str(matches))
4147     if len(matches) > 0:
4148         raise Exception("Unexpected neighbor entries after disconnect")
4149     if ebtables:
4150         cmd = subprocess.Popen(['ebtables', '-L', '--Lc'],
4151                                stdout=subprocess.PIPE)
4152         out, err = cmd.communicate()
4153         logger.info("ebtables results:\n" + out.decode())
4154 
4155     ns = tshark_get_ns(cap_dev0)
4156     logger.info("dev0 seen NS: " + str(ns))
4157     na = tshark_get_na(cap_dev0)
4158     logger.info("dev0 seen NA: " + str(na))
4159 
4160     if [addr0, addr1, 'aaaa:bbbb:dddd::2', 'aaaa:bbbb:cccc::2',
4161         'aaaa:bbbb:dddd::2', addr1] not in na:
4162         # For now, skip the test instead of reporting the error since the IPv6
4163         # proxyarp support is not yet in the upstream kernel tree.
4164         #raise Exception("dev0 did not get NA for aaaa:bbbb:dddd::2")
4165         raise HwsimSkip("Assume kernel did not have the required patches for proxyarp (IPv6)")
4166 
4167     if ebtables:
4168         for req in ns:
4169             if req[1] == bssid and req[0] == "33:33:ff:" + bssid[9:] and \
4170                req[3] == 'ff02::1:ff00:300' and req[4] == 'fe80::ff:fe00:300':
4171                 # At least for now, ignore this special case until the kernel
4172                 # can be prevented from sending it out.
4173                 logger.info("dev0: Ignore NS from AP to own local addr: " + str(req))
4174             elif req[1] != addr0:
4175                 raise Exception("Unexpected foreign NS on dev0: " + str(req))
4176 
4177     ns = tshark_get_ns(cap_dev1)
4178     logger.info("dev1 seen NS: " + str(ns))
4179     na = tshark_get_na(cap_dev1)
4180     logger.info("dev1 seen NA: " + str(na))
4181 
4182     if [addr1, addr0, 'aaaa:bbbb:cccc::2', 'aaaa:bbbb:dddd::2',
4183         'aaaa:bbbb:cccc::2', addr0] not in na:
4184         raise Exception("dev1 did not get NA for aaaa:bbbb:cccc::2")
4185 
4186     if ebtables:
4187         for req in ns:
4188             if req[1] == bssid and req[0] == "33:33:ff:" + bssid[9:] and \
4189                req[3] == 'ff02::1:ff00:300' and req[4] == 'fe80::ff:fe00:300':
4190                 # At least for now, ignore this special case until the kernel
4191                 # can be prevented from sending it out.
4192                 logger.info("dev1: Ignore NS from AP to own local addr: " + str(req))
4193             elif req[1] != addr1:
4194                 raise Exception("Unexpected foreign NS on dev1: " + str(req))
4195 
4196     ns = tshark_get_ns(cap_dev2)
4197     logger.info("dev2 seen NS: " + str(ns))
4198     na = tshark_get_na(cap_dev2)
4199     logger.info("dev2 seen NA: " + str(na))
4200 
4201     # FIX: enable once kernel implementation for proxyarp IPv6 is fixed
4202     #if [addr2, addr0, 'aaaa:bbbb:cccc::2', 'aaaa:bbbb:ff00::2',
4203     #    'aaaa:bbbb:cccc::2', addr0] not in na:
4204     #    raise Exception("dev2 did not get NA for aaaa:bbbb:cccc::2")
4205     #if [addr2, addr1, 'aaaa:bbbb:dddd::2', 'aaaa:bbbb:ff00::2',
4206     #    'aaaa:bbbb:dddd::2', addr1] not in na:
4207     #    raise Exception("dev2 did not get NA for aaaa:bbbb:dddd::2")
4208     #if [addr2, addr1, 'aaaa:bbbb:eeee::2', 'aaaa:bbbb:ff00::2',
4209     #    'aaaa:bbbb:eeee::2', addr1] not in na:
4210     #    raise Exception("dev2 did not get NA for aaaa:bbbb:eeee::2")
4211 
4212 def test_proxyarp_open(dev, apdev, params):
4213     """ProxyARP with open network"""
4214     try:
4215         _test_proxyarp_open(dev, apdev, params)
4216     finally:
4217         subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'down'],
4218                         stderr=open('/dev/null', 'w'))
4219         subprocess.call(['brctl', 'delbr', 'ap-br0'],
4220                         stderr=open('/dev/null', 'w'))
4221 
4222 def test_proxyarp_open_ipv6(dev, apdev, params):
4223     """ProxyARP with open network (IPv6)"""
4224     try:
4225         _test_proxyarp_open_ipv6(dev, apdev, params)
4226     finally:
4227         subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'down'],
4228                         stderr=open('/dev/null', 'w'))
4229         subprocess.call(['brctl', 'delbr', 'ap-br0'],
4230                         stderr=open('/dev/null', 'w'))
4231 
4232 def test_proxyarp_open_ebtables(dev, apdev, params):
4233     """ProxyARP with open network"""
4234     try:
4235         _test_proxyarp_open(dev, apdev, params, ebtables=True)
4236     finally:
4237         try:
4238             subprocess.call(['ebtables', '-F', 'FORWARD'])
4239             subprocess.call(['ebtables', '-F', 'OUTPUT'])
4240         except:
4241             pass
4242         subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'down'],
4243                         stderr=open('/dev/null', 'w'))
4244         subprocess.call(['brctl', 'delbr', 'ap-br0'],
4245                         stderr=open('/dev/null', 'w'))
4246 
4247 def test_proxyarp_open_ebtables_ipv6(dev, apdev, params):
4248     """ProxyARP with open network (IPv6)"""
4249     try:
4250         _test_proxyarp_open_ipv6(dev, apdev, params, ebtables=True)
4251     finally:
4252         try:
4253             subprocess.call(['ebtables', '-F', 'FORWARD'])
4254             subprocess.call(['ebtables', '-F', 'OUTPUT'])
4255         except:
4256             pass
4257         subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'down'],
4258                         stderr=open('/dev/null', 'w'))
4259         subprocess.call(['brctl', 'delbr', 'ap-br0'],
4260                         stderr=open('/dev/null', 'w'))
4261 
4262 def test_proxyarp_errors(dev, apdev, params):
4263     """ProxyARP error cases"""
4264     try:
4265         run_proxyarp_errors(dev, apdev, params)
4266     finally:
4267         subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'down'],
4268                         stderr=open('/dev/null', 'w'))
4269         subprocess.call(['brctl', 'delbr', 'ap-br0'],
4270                         stderr=open('/dev/null', 'w'))
4271 
4272 def run_proxyarp_errors(dev, apdev, params):
4273     params = {'ssid': 'open',
4274               'proxy_arp': '1',
4275               'ap_isolate': '1',
4276               'bridge': 'ap-br0',
4277               'disable_dgaf': '1'}
4278     hapd = hostapd.add_ap(apdev[0], params, no_enable=True)
4279     try:
4280         hapd.enable()
4281     except:
4282         # For now, do not report failures due to missing kernel support
4283         raise HwsimSkip("Could not start hostapd - assume proxyarp not supported in kernel version")
4284     ev = hapd.wait_event(["AP-ENABLED", "AP-DISABLED"], timeout=10)
4285     if ev is None:
4286         raise Exception("AP startup timed out")
4287     if "AP-ENABLED" not in ev:
4288         raise Exception("AP startup failed")
4289 
4290     hapd.disable()
4291     with alloc_fail(hapd, 1, "l2_packet_init;x_snoop_get_l2_packet;dhcp_snoop_init"):
4292         if "FAIL" not in hapd.request("ENABLE"):
4293             raise Exception("ENABLE accepted unexpectedly")
4294     with alloc_fail(hapd, 1, "l2_packet_init;x_snoop_get_l2_packet;ndisc_snoop_init"):
4295         if "FAIL" not in hapd.request("ENABLE"):
4296             raise Exception("ENABLE accepted unexpectedly")
4297     with fail_test(hapd, 1, "l2_packet_set_packet_filter;x_snoop_get_l2_packet;ndisc_snoop_init"):
4298         if "FAIL" not in hapd.request("ENABLE"):
4299             raise Exception("ENABLE accepted unexpectedly")
4300     with fail_test(hapd, 1, "l2_packet_set_packet_filter;x_snoop_get_l2_packet;dhcp_snoop_init"):
4301         if "FAIL" not in hapd.request("ENABLE"):
4302             raise Exception("ENABLE accepted unexpectedly")
4303     hapd.enable()
4304 
4305     subprocess.call(['brctl', 'setfd', 'ap-br0', '0'])
4306     subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'up'])
4307 
4308     dev[0].connect("open", key_mgmt="NONE", scan_freq="2412")
4309     addr0 = dev[0].own_addr()
4310 
4311     pkt = build_ra(src_ll=apdev[0]['bssid'], ip_src="aaaa:bbbb:cccc::33",
4312                    ip_dst="ff01::1")
4313     with fail_test(hapd, 1, "x_snoop_mcast_to_ucast_convert_send"):
4314         if "OK" not in hapd.request("DATA_TEST_FRAME ifname=ap-br0 " + binascii.hexlify(pkt).decode()):
4315             raise Exception("DATA_TEST_FRAME failed")
4316         wait_fail_trigger(hapd, "GET_FAIL")
4317 
4318     with alloc_fail(hapd, 1, "sta_ip6addr_add"):
4319         src_ll_opt0 = b"\x01\x01" + binascii.unhexlify(addr0.replace(':', ''))
4320         pkt = build_ns(src_ll=addr0, ip_src="aaaa:bbbb:cccc::2",
4321                        ip_dst="ff02::1:ff00:2", target="aaaa:bbbb:cccc::2",
4322                        opt=src_ll_opt0)
4323         hwsim_utils.sync_carrier(dev[0])
4324         if "OK" not in dev[0].request("DATA_TEST_FRAME " + binascii.hexlify(pkt).decode()):
4325             raise Exception("DATA_TEST_FRAME failed")
4326         wait_fail_trigger(hapd, "GET_ALLOC_FAIL")
4327 
4328 def test_ap_hs20_connect_deinit(dev, apdev):
4329     """Hotspot 2.0 connection interrupted with deinit"""
4330     check_eap_capa(dev[0], "MSCHAPV2")
4331     bssid = apdev[0]['bssid']
4332     params = hs20_ap_params()
4333     params['hessid'] = bssid
4334     hapd = hostapd.add_ap(apdev[0], params)
4335 
4336     wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
4337     wpas.interface_add("wlan5", drv_params="")
4338     wpas.hs20_enable()
4339     wpas.flush_scan_cache()
4340     wpas.add_cred_values({'realm': "example.com",
4341                           'username': "hs20-test",
4342                           'password': "password",
4343                           'ca_cert': "auth_serv/ca.pem",
4344                           'domain': "example.com"})
4345 
4346     wpas.scan_for_bss(bssid, freq=2412)
4347     hapd.disable()
4348 
4349     wpas.request("INTERWORKING_SELECT freq=2412")
4350 
4351     id = wpas.request("RADIO_WORK add block-work")
4352     ev = wpas.wait_event(["GAS-QUERY-START", "EXT-RADIO-WORK-START"], timeout=5)
4353     if ev is None:
4354         raise Exception("Timeout while waiting radio work to start")
4355     ev = wpas.wait_event(["GAS-QUERY-START", "EXT-RADIO-WORK-START"], timeout=5)
4356     if ev is None:
4357         raise Exception("Timeout while waiting radio work to start (2)")
4358 
4359     # Remove the interface while the gas-query radio work is still pending and
4360     # GAS query has not yet been started.
4361     wpas.interface_remove("wlan5")
4362 
4363 def test_ap_hs20_anqp_format_errors(dev, apdev):
4364     """Interworking network selection and ANQP format errors"""
4365     bssid = apdev[0]['bssid']
4366     params = hs20_ap_params()
4367     params['hessid'] = bssid
4368     hapd = hostapd.add_ap(apdev[0], params)
4369 
4370     dev[0].hs20_enable()
4371     values = {'realm': "example.com",
4372               'ca_cert': "auth_serv/ca.pem",
4373               'username': "hs20-test",
4374               'password': "password",
4375               'domain': "example.com"}
4376     id = dev[0].add_cred_values(values)
4377 
4378     dev[0].scan_for_bss(bssid, freq="2412")
4379 
4380     tests = ["00", "ffff", "010011223344", "020008000005112233445500",
4381              "01000400000000", "01000000000000",
4382              "01000300000200", "0100040000ff0000", "01000300000100",
4383              "01000300000001",
4384              "01000600000056112233",
4385              "01000900000002050001000111",
4386              "01000600000001000000", "01000600000001ff0000",
4387              "01000600000001020001",
4388              "010008000000010400010001", "0100080000000104000100ff",
4389              "010011000000010d00050200020100030005000600",
4390              "0000"]
4391     for t in tests:
4392         hapd.set("anqp_elem", "263:" + t)
4393         dev[0].request("INTERWORKING_SELECT freq=2412")
4394         ev = dev[0].wait_event(["INTERWORKING-NO-MATCH"], timeout=5)
4395         if ev is None:
4396             raise Exception("Network selection timed out")
4397         dev[0].dump_monitor()
4398 
4399     dev[0].remove_cred(id)
4400     id = dev[0].add_cred_values({'imsi': "555444-333222111", 'eap': "AKA",
4401                                  'milenage': "5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123"})
4402 
4403     tests = ["00", "0100", "0001", "00ff", "000200ff", "0003000101",
4404              "00020100"]
4405     for t in tests:
4406         hapd.set("anqp_elem", "264:" + t)
4407         dev[0].request("INTERWORKING_SELECT freq=2412")
4408         ev = dev[0].wait_event(["INTERWORKING-NO-MATCH"], timeout=5)
4409         if ev is None:
4410             raise Exception("Network selection timed out")
4411         dev[0].dump_monitor()
4412 
4413 def test_ap_hs20_cred_with_nai_realm(dev, apdev):
4414     """Hotspot 2.0 network selection and cred_with_nai_realm cred->realm"""
4415     bssid = apdev[0]['bssid']
4416     params = hs20_ap_params()
4417     params['hessid'] = bssid
4418     hostapd.add_ap(apdev[0], params)
4419 
4420     dev[0].hs20_enable()
4421 
4422     id = dev[0].add_cred_values({'realm': "example.com",
4423                                  'username': "test",
4424                                  'password': "secret",
4425                                  'domain': "example.com",
4426                                  'eap': 'TTLS'})
4427     interworking_select(dev[0], bssid, "home", freq=2412)
4428     dev[0].remove_cred(id)
4429 
4430     id = dev[0].add_cred_values({'realm': "foo.com",
4431                                  'username': "test",
4432                                  'password': "secret",
4433                                  'domain': "example.com",
4434                                  'home_ois': ["112234"],
4435                                  'eap': 'TTLS'})
4436     interworking_select(dev[0], bssid, "home", freq=2412, no_match=True)
4437     dev[0].remove_cred(id)
4438 
4439 def test_ap_hs20_cred_and_no_roaming_consortium(dev, apdev):
4440     """Hotspot 2.0 network selection and no roaming consortium"""
4441     bssid = apdev[0]['bssid']
4442     params = hs20_ap_params()
4443     params['hessid'] = bssid
4444     del params['roaming_consortium']
4445     hostapd.add_ap(apdev[0], params)
4446 
4447     dev[0].hs20_enable()
4448 
4449     id = dev[0].add_cred_values({'realm': "example.com",
4450                                  'username': "test",
4451                                  'password': "secret",
4452                                  'domain': "example.com",
4453                                  'home_ois': ["112234"],
4454                                  'eap': 'TTLS'})
4455     interworking_select(dev[0], bssid, "home", freq=2412)
4456 
4457 def test_ap_hs20_interworking_oom(dev, apdev):
4458     """Hotspot 2.0 network selection and OOM"""
4459     bssid = apdev[0]['bssid']
4460     params = hs20_ap_params()
4461     params['hessid'] = bssid
4462     params['nai_realm'] = ["0,no.match.here;example.com;no.match.here.either,21[2:1][5:7]",
4463                            "0,example.com,13[5:6],21[2:4][5:7]",
4464                            "0,another.example.com"]
4465     hostapd.add_ap(apdev[0], params)
4466 
4467     dev[0].hs20_enable()
4468 
4469     id = dev[0].add_cred_values({'realm': "example.com",
4470                                  'username': "test",
4471                                  'password': "secret",
4472                                  'domain': "example.com",
4473                                  'eap': 'TTLS'})
4474 
4475     dev[0].scan_for_bss(bssid, freq="2412")
4476 
4477     funcs = ["wpabuf_alloc;interworking_anqp_send_req",
4478              "anqp_build_req;interworking_anqp_send_req",
4479              "gas_query_req;interworking_anqp_send_req",
4480              "dup_binstr;nai_realm_parse_realm",
4481              "=nai_realm_parse_realm",
4482              "=nai_realm_parse",
4483              "=nai_realm_match"]
4484     for func in funcs:
4485         with alloc_fail(dev[0], 1, func):
4486             dev[0].request("INTERWORKING_SELECT auto freq=2412")
4487             ev = dev[0].wait_event(["Starting ANQP"], timeout=5)
4488             if ev is None:
4489                 raise Exception("ANQP did not start")
4490             wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4491             dev[0].dump_monitor()
4492 
4493 def test_ap_hs20_no_cred_connect(dev, apdev):
4494     """Hotspot 2.0 and connect attempt without credential"""
4495     bssid = apdev[0]['bssid']
4496     params = hs20_ap_params()
4497     params['hessid'] = bssid
4498     hapd = hostapd.add_ap(apdev[0], params)
4499 
4500     dev[0].hs20_enable()
4501     dev[0].scan_for_bss(bssid, freq="2412")
4502     if "FAIL" not in dev[0].request("INTERWORKING_CONNECT " + bssid):
4503         raise Exception("Unexpected INTERWORKING_CONNECT success")
4504 
4505 def test_ap_hs20_no_rsn_connect(dev, apdev):
4506     """Hotspot 2.0 and connect attempt without RSN"""
4507     bssid = apdev[0]['bssid']
4508     params = hostapd.wpa_params(ssid="test-hs20")
4509     params['wpa_key_mgmt'] = "WPA-EAP"
4510     params['ieee80211w'] = "1"
4511     params['ieee8021x'] = "1"
4512     params['auth_server_addr'] = "127.0.0.1"
4513     params['auth_server_port'] = "1812"
4514     params['auth_server_shared_secret'] = "radius"
4515     params['interworking'] = "1"
4516     params['roaming_consortium'] = ["112233", "1020304050", "010203040506",
4517                                     "fedcba"]
4518     params['nai_realm'] = ["0,example.com,13[5:6],21[2:4][5:7]",
4519                            "0,another.example.com"]
4520     hapd = hostapd.add_ap(apdev[0], params)
4521 
4522     dev[0].hs20_enable()
4523     dev[0].scan_for_bss(bssid, freq="2412")
4524 
4525     id = dev[0].add_cred_values({'realm': "example.com",
4526                                  'username': "test",
4527                                  'password': "secret",
4528                                  'domain': "example.com",
4529                                  'home_ois': ["112233"],
4530                                  'eap': 'TTLS'})
4531 
4532     interworking_select(dev[0], bssid, freq=2412, no_match=True)
4533     if "FAIL" not in dev[0].request("INTERWORKING_CONNECT " + bssid):
4534         raise Exception("Unexpected INTERWORKING_CONNECT success")
4535 
4536 def test_ap_hs20_no_match_connect(dev, apdev):
4537     """Hotspot 2.0 and connect attempt without matching cred"""
4538     bssid = apdev[0]['bssid']
4539     params = hs20_ap_params()
4540     hapd = hostapd.add_ap(apdev[0], params)
4541 
4542     dev[0].hs20_enable()
4543     dev[0].scan_for_bss(bssid, freq="2412")
4544 
4545     id = dev[0].add_cred_values({'realm': "example.org",
4546                                  'username': "test",
4547                                  'password': "secret",
4548                                  'domain': "example.org",
4549                                  'home_ois': ["112234"],
4550                                  'eap': 'TTLS'})
4551 
4552     interworking_select(dev[0], bssid, freq=2412, no_match=True)
4553     if "FAIL" not in dev[0].request("INTERWORKING_CONNECT " + bssid):
4554         raise Exception("Unexpected INTERWORKING_CONNECT success")
4555 
4556 def test_ap_hs20_multiple_home_cred(dev, apdev):
4557     """Hotspot 2.0 and select with multiple matching home credentials"""
4558     bssid = apdev[0]['bssid']
4559     params = hs20_ap_params()
4560     params['hessid'] = bssid
4561     params['nai_realm'] = ["0,example.com,13[5:6],21[2:4][5:7]"]
4562     params['domain_name'] = "example.com"
4563     hapd = hostapd.add_ap(apdev[0], params)
4564 
4565     bssid2 = apdev[1]['bssid']
4566     params = hs20_ap_params(ssid="test-hs20-other")
4567     params['hessid'] = bssid2
4568     params['nai_realm'] = ["0,example.org,13[5:6],21[2:4][5:7]"]
4569     params['domain_name'] = "example.org"
4570     hapd2 = hostapd.add_ap(apdev[1], params)
4571 
4572     dev[0].hs20_enable()
4573     dev[0].scan_for_bss(bssid2, freq="2412")
4574     dev[0].scan_for_bss(bssid, freq="2412")
4575     id = dev[0].add_cred_values({'realm': "example.com",
4576                                  'priority': '2',
4577                                  'username': "hs20-test",
4578                                  'password': "password",
4579                                  'domain': "example.com"})
4580     id2 = dev[0].add_cred_values({'realm': "example.org",
4581                                   'priority': '3',
4582                                   'username': "hs20-test",
4583                                   'password': "password",
4584                                   'domain': "example.org"})
4585     dev[0].request("INTERWORKING_SELECT auto freq=2412")
4586     ev = dev[0].wait_connected(timeout=15)
4587     if bssid2 not in ev:
4588         raise Exception("Connected to incorrect network")
4589 
4590 def test_ap_hs20_anqp_invalid_gas_response(dev, apdev):
4591     """Hotspot 2.0 network selection and invalid GAS response"""
4592     bssid = apdev[0]['bssid']
4593     params = hs20_ap_params()
4594     params['hessid'] = bssid
4595     hapd = hostapd.add_ap(apdev[0], params)
4596 
4597     dev[0].flush_scan_cache()
4598     dev[0].scan_for_bss(bssid, freq="2412")
4599     hapd.set("ext_mgmt_frame_handling", "1")
4600 
4601     dev[0].hs20_enable()
4602 
4603     id = dev[0].add_cred_values({'realm': "example.com",
4604                                  'username': "test",
4605                                  'password': "secret",
4606                                  'domain': "example.com",
4607                                  'home_ois': ["112234"],
4608                                  'eap': 'TTLS'})
4609     dev[0].request("INTERWORKING_SELECT freq=2412")
4610 
4611     query = gas_rx(hapd)
4612     gas = parse_gas(query['payload'])
4613 
4614     logger.info("ANQP: Unexpected Advertisement Protocol in response")
4615     resp = action_response(query)
4616     adv_proto = struct.pack('8B', 108, 6, 127, 0xdd, 0x00, 0x11, 0x22, 0x33)
4617     data = struct.pack('<H', 0)
4618     resp['payload'] = struct.pack('<BBBHH', ACTION_CATEG_PUBLIC,
4619                                   GAS_INITIAL_RESPONSE,
4620                                   gas['dialog_token'], 0, 0) + adv_proto + data
4621     send_gas_resp(hapd, resp)
4622 
4623     ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=5)
4624     if ev is None:
4625         raise Exception("No ANQP-QUERY-DONE seen")
4626     if "result=INVALID_FRAME" not in ev:
4627         raise Exception("Unexpected result: " + ev)
4628 
4629     dev[0].request("INTERWORKING_SELECT freq=2412")
4630 
4631     query = gas_rx(hapd)
4632     gas = parse_gas(query['payload'])
4633 
4634     logger.info("ANQP: Invalid element length for Info ID 1234")
4635     resp = action_response(query)
4636     adv_proto = struct.pack('BBBB', 108, 2, 127, 0)
4637     elements = struct.pack('<HH', 1234, 1)
4638     data = struct.pack('<H', len(elements)) + elements
4639     resp['payload'] = struct.pack('<BBBHH', ACTION_CATEG_PUBLIC,
4640                                   GAS_INITIAL_RESPONSE,
4641                                   gas['dialog_token'], 0, 0) + adv_proto + data
4642     send_gas_resp(hapd, resp)
4643 
4644     ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=5)
4645     if ev is None:
4646         raise Exception("No ANQP-QUERY-DONE seen")
4647     if "result=INVALID_FRAME" not in ev:
4648         raise Exception("Unexpected result: " + ev)
4649 
4650     with alloc_fail(dev[0], 1, "=anqp_add_extra"):
4651         dev[0].request("INTERWORKING_SELECT freq=2412")
4652 
4653         query = gas_rx(hapd)
4654         gas = parse_gas(query['payload'])
4655 
4656         resp = action_response(query)
4657         elements = struct.pack('<HHHH', 1, 0, 1, 0)
4658         data = struct.pack('<H', len(elements)) + elements
4659         resp['payload'] = struct.pack('<BBBHH', ACTION_CATEG_PUBLIC,
4660                                       GAS_INITIAL_RESPONSE,
4661                                       gas['dialog_token'], 0, 0) + adv_proto + data
4662         send_gas_resp(hapd, resp)
4663 
4664         ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=5)
4665         if ev is None:
4666             raise Exception("No ANQP-QUERY-DONE seen")
4667         if "result=SUCCESS" not in ev:
4668             raise Exception("Unexpected result: " + ev)
4669 
4670     with alloc_fail(dev[0], 1, "wpabuf_alloc_copy;anqp_add_extra"):
4671         dev[0].request("INTERWORKING_SELECT freq=2412")
4672 
4673         query = gas_rx(hapd)
4674         gas = parse_gas(query['payload'])
4675 
4676         resp = action_response(query)
4677         elements = struct.pack('<HHHH', 1, 0, 1, 0)
4678         data = struct.pack('<H', len(elements)) + elements
4679         resp['payload'] = struct.pack('<BBBHH', ACTION_CATEG_PUBLIC,
4680                                       GAS_INITIAL_RESPONSE,
4681                                       gas['dialog_token'], 0, 0) + adv_proto + data
4682         send_gas_resp(hapd, resp)
4683 
4684         ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=5)
4685         if ev is None:
4686             raise Exception("No ANQP-QUERY-DONE seen")
4687         if "result=SUCCESS" not in ev:
4688             raise Exception("Unexpected result: " + ev)
4689 
4690     tests = [struct.pack('<HH', 0xdddd, 0),
4691              struct.pack('<HH3B', 0xdddd, 3, 0x50, 0x6f, 0x9a),
4692              struct.pack('<HH4B', 0xdddd, 4, 0x50, 0x6f, 0x9a, 0),
4693              struct.pack('<HH4B', 0xdddd, 4, 0x11, 0x22, 0x33, 0),
4694              struct.pack('<HHHH', 1, 0, 1, 0)]
4695     for elements in tests:
4696         dev[0].request("INTERWORKING_SELECT freq=2412")
4697 
4698         query = gas_rx(hapd)
4699         gas = parse_gas(query['payload'])
4700 
4701         resp = action_response(query)
4702         data = struct.pack('<H', len(elements)) + elements
4703         resp['payload'] = struct.pack('<BBBHH', ACTION_CATEG_PUBLIC,
4704                                       GAS_INITIAL_RESPONSE,
4705                                       gas['dialog_token'], 0, 0) + adv_proto + data
4706         send_gas_resp(hapd, resp)
4707 
4708         ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=5)
4709         if ev is None:
4710             raise Exception("No ANQP-QUERY-DONE seen")
4711         if "result=SUCCESS" not in ev:
4712             raise Exception("Unexpected result: " + ev)
4713 
4714 def test_ap_hs20_set_profile_failures(dev, apdev):
4715     """Hotspot 2.0 and failures during profile configuration"""
4716     bssid = apdev[0]['bssid']
4717     params = hs20_ap_params()
4718     params['hessid'] = bssid
4719     params['anqp_3gpp_cell_net'] = "555,444"
4720     hapd = hostapd.add_ap(apdev[0], params)
4721 
4722     dev[0].hs20_enable()
4723     dev[0].scan_for_bss(bssid, freq="2412")
4724 
4725     id = dev[0].add_cred_values({'realm': "example.com",
4726                                  'domain': "example.com",
4727                                  'username': "test",
4728                                  'password': "secret",
4729                                  'eap': 'TTLS'})
4730     interworking_select(dev[0], bssid, "home", freq=2412)
4731     dev[0].dump_monitor()
4732     dev[0].request("NOTE ssid->eap.eap_methods = os_malloc()")
4733     with alloc_fail(dev[0], 1, "interworking_set_eap_params"):
4734         dev[0].request("INTERWORKING_CONNECT " + bssid)
4735         wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4736     dev[0].remove_cred(id)
4737 
4738     id = dev[0].add_cred_values({'realm': "example.com",
4739                                  'domain': "example.com",
4740                                  'username': "hs20-test-with-domain@example.com",
4741                                  'password': "password"})
4742     interworking_select(dev[0], bssid, "home", freq=2412)
4743     dev[0].dump_monitor()
4744     dev[0].request("NOTE anon = os_malloc()")
4745     with alloc_fail(dev[0], 1, "interworking_set_eap_params"):
4746         dev[0].request("INTERWORKING_CONNECT " + bssid)
4747         wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4748     dev[0].request("NOTE Successful connection with cred->username including realm")
4749     dev[0].request("INTERWORKING_CONNECT " + bssid)
4750     dev[0].wait_connected()
4751     hapd.wait_sta()
4752     dev[0].remove_cred(id)
4753     dev[0].wait_disconnected()
4754     hapd.wait_sta_disconnect()
4755 
4756     id = dev[0].add_cred_values({'realm': "example.com",
4757                                  'domain': "example.com",
4758                                  'username': "hs20-test",
4759                                  'password': "password"})
4760     interworking_select(dev[0], bssid, "home", freq=2412)
4761     dev[0].dump_monitor()
4762     dev[0].request("NOTE anon = os_malloc() (second)")
4763     with alloc_fail(dev[0], 1, "interworking_set_eap_params"):
4764         dev[0].request("INTERWORKING_CONNECT " + bssid)
4765         wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4766     with alloc_fail(dev[0], 1, "wpa_config_add_network;interworking_connect"):
4767         dev[0].request("INTERWORKING_CONNECT " + bssid)
4768         wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4769     with alloc_fail(dev[0], 1, "=interworking_connect"):
4770         dev[0].request("INTERWORKING_CONNECT " + bssid)
4771         wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4772     dev[0].request("NOTE wpa_config_set(eap)")
4773     with alloc_fail(dev[0], 1, "wpa_config_parse_eap;wpa_config_set;interworking_connect"):
4774         dev[0].request("INTERWORKING_CONNECT " + bssid)
4775         wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4776     dev[0].request("NOTE wpa_config_set(TTLS-NON_EAP_MSCHAPV2-phase2)")
4777     with alloc_fail(dev[0], 1, "wpa_config_parse_str;wpa_config_set;interworking_connect"):
4778         dev[0].request("INTERWORKING_CONNECT " + bssid)
4779         wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4780     dev[0].remove_cred(id)
4781 
4782     id = dev[0].add_cred_values({'home_ois': ["112233"],
4783                                  'domain': "example.com",
4784                                  'username': "hs20-test",
4785                                  'password': "password",
4786                                  'eap': 'TTLS',
4787                                  'phase2': "auth=MSCHAPV2"})
4788     interworking_select(dev[0], bssid, "home", freq=2412)
4789     dev[0].dump_monitor()
4790     dev[0].request("NOTE anon = os_strdup()")
4791     with alloc_fail(dev[0], 2, "interworking_set_eap_params"):
4792         dev[0].request("INTERWORKING_CONNECT " + bssid)
4793         wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4794     dev[0].request("NOTE wpa_config_set_quoted(anonymous_identity)")
4795     with alloc_fail(dev[0], 1, "=wpa_config_set_quoted;interworking_set_eap_params"):
4796         dev[0].request("INTERWORKING_CONNECT " + bssid)
4797         wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4798     dev[0].request("NOTE Successful connection with cred->realm not included")
4799     dev[0].request("INTERWORKING_CONNECT " + bssid)
4800     dev[0].wait_connected()
4801     hapd.wait_sta()
4802     dev[0].remove_cred(id)
4803     dev[0].wait_disconnected()
4804     hapd.wait_sta_disconnect()
4805 
4806     id = dev[0].add_cred_values({'home_ois': ["112233"],
4807                                  'domain': "example.com",
4808                                  'realm': "example.com",
4809                                  'username': "user",
4810                                  'password': "password",
4811                                  'eap': 'PEAP'})
4812     interworking_select(dev[0], bssid, "home", freq=2412)
4813     dev[0].dump_monitor()
4814     dev[0].request("NOTE id = os_strdup()")
4815     with alloc_fail(dev[0], 2, "interworking_set_eap_params"):
4816         dev[0].request("INTERWORKING_CONNECT " + bssid)
4817         wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4818     dev[0].request("NOTE wpa_config_set_quoted(identity)")
4819     with alloc_fail(dev[0], 1, "=wpa_config_set_quoted;interworking_set_eap_params"):
4820         dev[0].request("INTERWORKING_CONNECT " + bssid)
4821         wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4822     dev[0].remove_cred(id)
4823 
4824     id = dev[0].add_cred_values({'home_ois': ["112233"],
4825                                  'domain': "example.com",
4826                                  'realm': "example.com",
4827                                  'username': "user",
4828                                  'password': "password",
4829                                  'eap': "TTLS"})
4830     interworking_select(dev[0], bssid, "home", freq=2412)
4831     dev[0].dump_monitor()
4832     dev[0].request("NOTE wpa_config_set_quoted(identity) (second)")
4833     with alloc_fail(dev[0], 2, "=wpa_config_set_quoted;interworking_set_eap_params"):
4834         dev[0].request("INTERWORKING_CONNECT " + bssid)
4835         wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4836     dev[0].request("NOTE wpa_config_set_quoted(password)")
4837     with alloc_fail(dev[0], 3, "=wpa_config_set_quoted;interworking_set_eap_params"):
4838         dev[0].request("INTERWORKING_CONNECT " + bssid)
4839         wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4840     with alloc_fail(dev[0], 1, "wpa_config_add_network;interworking_connect_roaming_consortium"):
4841         dev[0].request("INTERWORKING_CONNECT " + bssid)
4842         wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4843     with alloc_fail(dev[0], 1, "=interworking_connect_roaming_consortium"):
4844         dev[0].request("INTERWORKING_CONNECT " + bssid)
4845         wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4846     dev[0].remove_cred(id)
4847 
4848     id = dev[0].add_cred_values({'home_ois': ["112233"],
4849                                  'domain': "example.com",
4850                                  'realm': "example.com",
4851                                  'username': "user",
4852                                  'eap': "PEAP"})
4853     dev[0].set_cred(id, "password", "ext:password")
4854     interworking_select(dev[0], bssid, "home", freq=2412)
4855     dev[0].dump_monitor()
4856     dev[0].request("NOTE wpa_config_set(password)")
4857     with alloc_fail(dev[0], 1, "wpa_config_parse_password;interworking_set_eap_params"):
4858         dev[0].request("INTERWORKING_CONNECT " + bssid)
4859         wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4860     with alloc_fail(dev[0], 1, "interworking_set_hs20_params"):
4861         dev[0].request("INTERWORKING_CONNECT " + bssid)
4862         wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4863     dev[0].remove_cred(id)
4864 
4865     id = dev[0].add_cred_values({'realm': "example.com",
4866                                  'domain': "example.com",
4867                                  'username': "certificate-user",
4868                                  'phase1': "include_tls_length=0",
4869                                  'domain_suffix_match': "example.com",
4870                                  'ca_cert': "auth_serv/ca.pem",
4871                                  'client_cert': "auth_serv/user.pem",
4872                                  'private_key': "auth_serv/user.key",
4873                                  'private_key_passwd': "secret"})
4874     interworking_select(dev[0], bssid, "home", freq=2412)
4875     dev[0].dump_monitor()
4876     dev[0].request("NOTE wpa_config_set_quoted(client_cert)")
4877     with alloc_fail(dev[0], 2, "=wpa_config_set_quoted;interworking_set_eap_params"):
4878         dev[0].request("INTERWORKING_CONNECT " + bssid)
4879         wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4880     dev[0].request("NOTE wpa_config_set_quoted(private_key)")
4881     with alloc_fail(dev[0], 3, "=wpa_config_set_quoted;interworking_set_eap_params"):
4882         dev[0].request("INTERWORKING_CONNECT " + bssid)
4883         wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4884     dev[0].request("NOTE wpa_config_set_quoted(private_key_passwd)")
4885     with alloc_fail(dev[0], 4, "=wpa_config_set_quoted;interworking_set_eap_params"):
4886         dev[0].request("INTERWORKING_CONNECT " + bssid)
4887         wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4888     dev[0].request("NOTE wpa_config_set_quoted(ca_cert)")
4889     with alloc_fail(dev[0], 5, "=wpa_config_set_quoted;interworking_set_eap_params"):
4890         dev[0].request("INTERWORKING_CONNECT " + bssid)
4891         wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4892     dev[0].request("NOTE wpa_config_set_quoted(domain_suffix_match)")
4893     with alloc_fail(dev[0], 6, "=wpa_config_set_quoted;interworking_set_eap_params"):
4894         dev[0].request("INTERWORKING_CONNECT " + bssid)
4895         wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4896     with alloc_fail(dev[0], 1, "interworking_set_hs20_params"):
4897         dev[0].request("INTERWORKING_CONNECT " + bssid)
4898         wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4899     dev[0].remove_cred(id)
4900 
4901     id = dev[0].add_cred_values({'imsi': "555444-333222111", 'eap': "SIM",
4902                                  'milenage': "5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123"})
4903     interworking_select(dev[0], bssid, freq=2412)
4904     dev[0].dump_monitor()
4905     with alloc_fail(dev[0], 1, "interworking_set_hs20_params"):
4906         dev[0].request("INTERWORKING_CONNECT " + bssid)
4907         wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4908     dev[0].request("NOTE wpa_config_set_quoted(password;milenage)")
4909     with alloc_fail(dev[0], 2, "=wpa_config_set_quoted;interworking_connect_3gpp"):
4910         dev[0].request("INTERWORKING_CONNECT " + bssid)
4911         wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4912     dev[0].request("NOTE wpa_config_set(eap)")
4913     with alloc_fail(dev[0], 1, "wpa_config_parse_eap;wpa_config_set;interworking_connect_3gpp"):
4914         dev[0].request("INTERWORKING_CONNECT " + bssid)
4915         wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4916     dev[0].request("NOTE set_root_nai:wpa_config_set(identity)")
4917     with alloc_fail(dev[0], 1, "wpa_config_parse_str;interworking_connect_3gpp"):
4918             dev[0].request("INTERWORKING_CONNECT " + bssid)
4919             wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4920     dev[0].remove_cred(id)
4921 
4922     id = dev[0].add_cred_values({'home_ois': ["112233"],
4923                                  'eap': 'TTLS',
4924                                  'username': "user@example.com",
4925                                  'password': "password"})
4926     interworking_select(dev[0], bssid, freq=2412)
4927     dev[0].dump_monitor()
4928     dev[0].request("NOTE Interworking: No EAP method set for credential using roaming consortium")
4929     dev[0].request("INTERWORKING_CONNECT " + bssid)
4930     dev[0].remove_cred(id)
4931 
4932     hapd.disable()
4933     params = hs20_ap_params()
4934     params['nai_realm'] = "0,example.com,25[3:26]"
4935     hapd = hostapd.add_ap(apdev[0], params)
4936     id = dev[0].add_cred_values({'realm': "example.com",
4937                                  'domain': "example.com",
4938                                  'username': "hs20-test",
4939                                  'password': "password"})
4940     interworking_select(dev[0], bssid, freq=2412)
4941     dev[0].dump_monitor()
4942     dev[0].request("NOTE wpa_config_set(PEAP/FAST-phase1)")
4943     with alloc_fail(dev[0], 1, "wpa_config_parse_str;wpa_config_set;interworking_connect"):
4944         dev[0].request("INTERWORKING_CONNECT " + bssid)
4945         wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4946     dev[0].request("NOTE wpa_config_set(PEAP/FAST-pac_interworking)")
4947     with alloc_fail(dev[0], 2, "wpa_config_parse_str;wpa_config_set;interworking_connect"):
4948         dev[0].request("INTERWORKING_CONNECT " + bssid)
4949         wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4950     dev[0].request("NOTE wpa_config_set(PEAP/FAST-phase2)")
4951     with alloc_fail(dev[0], 3, "wpa_config_parse_str;wpa_config_set;interworking_connect"):
4952         dev[0].request("INTERWORKING_CONNECT " + bssid)
4953         wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4954 
4955     hapd.disable()
4956     params = hs20_ap_params()
4957     params['nai_realm'] = "0,example.com,21"
4958     hapd = hostapd.add_ap(apdev[0], params)
4959     interworking_select(dev[0], bssid, freq=2412)
4960     dev[0].request("NOTE wpa_config_set(TTLS-defaults-phase2)")
4961     with alloc_fail(dev[0], 1, "wpa_config_parse_str;wpa_config_set;interworking_connect"):
4962         dev[0].request("INTERWORKING_CONNECT " + bssid)
4963         wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4964 
4965     hapd.disable()
4966     params = hs20_ap_params()
4967     params['nai_realm'] = "0,example.com,21[2:3]"
4968     hapd = hostapd.add_ap(apdev[0], params)
4969     interworking_select(dev[0], bssid, freq=2412)
4970     dev[0].request("NOTE wpa_config_set(TTLS-NON_EAP_MSCHAP-phase2)")
4971     with alloc_fail(dev[0], 1, "wpa_config_parse_str;wpa_config_set;interworking_connect"):
4972         dev[0].request("INTERWORKING_CONNECT " + bssid)
4973         wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4974 
4975     hapd.disable()
4976     params = hs20_ap_params()
4977     params['nai_realm'] = "0,example.com,21[2:2]"
4978     hapd = hostapd.add_ap(apdev[0], params)
4979     interworking_select(dev[0], bssid, freq=2412)
4980     dev[0].request("NOTE wpa_config_set(TTLS-NON_EAP_CHAP-phase2)")
4981     with alloc_fail(dev[0], 1, "wpa_config_parse_str;wpa_config_set;interworking_connect"):
4982         dev[0].request("INTERWORKING_CONNECT " + bssid)
4983         wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4984 
4985     hapd.disable()
4986     params = hs20_ap_params()
4987     params['nai_realm'] = "0,example.com,21[2:1]"
4988     hapd = hostapd.add_ap(apdev[0], params)
4989     interworking_select(dev[0], bssid, freq=2412)
4990     dev[0].request("NOTE wpa_config_set(TTLS-NON_EAP_PAP-phase2)")
4991     with alloc_fail(dev[0], 1, "wpa_config_parse_str;wpa_config_set;interworking_connect"):
4992         dev[0].request("INTERWORKING_CONNECT " + bssid)
4993         wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4994 
4995     hapd.disable()
4996     params = hs20_ap_params()
4997     params['nai_realm'] = "0,example.com,21[3:26]"
4998     hapd = hostapd.add_ap(apdev[0], params)
4999     interworking_select(dev[0], bssid, freq=2412)
5000     dev[0].request("NOTE wpa_config_set(TTLS-EAP-MSCHAPV2-phase2)")
5001     with alloc_fail(dev[0], 1, "wpa_config_parse_str;wpa_config_set;interworking_connect"):
5002         dev[0].request("INTERWORKING_CONNECT " + bssid)
5003         wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
5004 
5005     dev[0].remove_cred(id)
5006 
5007 def test_ap_hs20_unexpected(dev, apdev):
5008     """Unexpected Hotspot 2.0 AP configuration"""
5009     skip_without_tkip(dev[0])
5010     skip_without_tkip(dev[1])
5011     skip_without_tkip(dev[2])
5012     check_eap_capa(dev[0], "MSCHAPV2")
5013     bssid = apdev[0]['bssid']
5014     params = hostapd.wpa_eap_params(ssid="test-hs20-fake")
5015     params['wpa'] = "3"
5016     params['wpa_pairwise'] = "TKIP CCMP"
5017     params['rsn_pairwise'] = "CCMP"
5018     params['ieee80211w'] = "1"
5019     #params['vendor_elements'] = 'dd07506f9a10140000'
5020     params['vendor_elements'] = 'dd04506f9a10'
5021     hostapd.add_ap(apdev[0], params)
5022 
5023     dev[0].hs20_enable()
5024     dev[0].scan_for_bss(bssid, freq="2412")
5025     dev[0].connect("test-hs20-fake", key_mgmt="WPA-EAP", eap="TTLS",
5026                    pairwise="TKIP",
5027                    identity="hs20-test", password="password",
5028                    ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
5029                    scan_freq="2412")
5030 
5031     dev[1].hs20_enable()
5032     dev[1].scan_for_bss(bssid, freq="2412")
5033     dev[1].connect("test-hs20-fake", key_mgmt="WPA-EAP", eap="TTLS",
5034                    proto="WPA",
5035                    identity="hs20-test", password="password",
5036                    ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
5037                    scan_freq="2412")
5038 
5039     dev[2].hs20_enable()
5040     dev[2].scan_for_bss(bssid, freq="2412")
5041     dev[2].connect("test-hs20-fake", key_mgmt="WPA-EAP", eap="TTLS",
5042                    ieee80211w="1",
5043                    proto="RSN", pairwise="CCMP",
5044                    identity="hs20-test", password="password",
5045                    ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
5046                    scan_freq="2412")
5047 
5048 def test_ap_interworking_element_update(dev, apdev):
5049     """Dynamic Interworking element update"""
5050     bssid = apdev[0]['bssid']
5051     params = hs20_ap_params()
5052     params['hessid'] = bssid
5053     hapd = hostapd.add_ap(apdev[0], params)
5054 
5055     dev[0].hs20_enable()
5056     dev[0].scan_for_bss(bssid, freq="2412")
5057     bss = dev[0].get_bss(bssid)
5058     logger.info("Before update: " + str(bss))
5059     if '6b091e0701020000000300' not in bss['ie']:
5060         raise Exception("Expected Interworking element not seen before update")
5061 
5062     # Update configuration parameters related to Interworking element
5063     hapd.set('access_network_type', '2')
5064     hapd.set('asra', '1')
5065     hapd.set('esr', '1')
5066     hapd.set('uesa', '1')
5067     hapd.set('venue_group', '2')
5068     hapd.set('venue_type', '8')
5069     if "OK" not in hapd.request("UPDATE_BEACON"):
5070         raise Exception("UPDATE_BEACON failed")
5071     dev[0].request("BSS_FLUSH 0")
5072     dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
5073     bss = dev[0].get_bss(bssid)
5074     logger.info("After update: " + str(bss))
5075     if '6b09f20208020000000300' not in bss['ie']:
5076         raise Exception("Expected Interworking element not seen after update")
5077 
5078 def test_ap_hs20_terms_and_conditions(dev, apdev):
5079     """Hotspot 2.0 Terms and Conditions signaling"""
5080     check_eap_capa(dev[0], "MSCHAPV2")
5081     bssid = apdev[0]['bssid']
5082     params = hs20_ap_params()
5083     params['hessid'] = bssid
5084     params['hs20_t_c_filename'] = 'terms-and-conditions'
5085     params['hs20_t_c_timestamp'] = '123456789'
5086 
5087     hostapd.add_ap(apdev[0], params)
5088 
5089     dev[0].hs20_enable()
5090     dev[0].connect("test-hs20", proto="RSN", key_mgmt="WPA-EAP", eap="TTLS",
5091                    identity="hs20-t-c-test", password="password",
5092                    ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
5093                    ieee80211w='2', scan_freq="2412")
5094     ev = dev[0].wait_event(["HS20-T-C-ACCEPTANCE"], timeout=5)
5095     if ev is None:
5096         raise Exception("Terms and Conditions Acceptance notification not received")
5097     url = "https://example.com/t_and_c?addr=%s&ap=123" % dev[0].own_addr()
5098     if url not in ev:
5099         raise Exception("Unexpected URL: " + ev)
5100 
5101 def test_ap_hs20_terms_and_conditions_coa(dev, apdev):
5102     """Hotspot 2.0 Terms and Conditions signaling - CoA"""
5103     try:
5104         import pyrad.client
5105         import pyrad.packet
5106         import pyrad.dictionary
5107         import radius_das
5108     except ImportError:
5109         raise HwsimSkip("No pyrad modules available")
5110 
5111     check_eap_capa(dev[0], "MSCHAPV2")
5112     bssid = apdev[0]['bssid']
5113     params = hs20_ap_params()
5114     params['hessid'] = bssid
5115     params['hs20_t_c_filename'] = 'terms-and-conditions'
5116     params['hs20_t_c_timestamp'] = '123456789'
5117     params['own_ip_addr'] = "127.0.0.1"
5118     params['radius_das_port'] = "3799"
5119     params['radius_das_client'] = "127.0.0.1 secret"
5120     params['radius_das_require_event_timestamp'] = "1"
5121     hapd = hostapd.add_ap(apdev[0], params)
5122 
5123     dev[0].hs20_enable()
5124     dev[0].connect("test-hs20", proto="RSN", key_mgmt="WPA-EAP", eap="TTLS",
5125                    identity="hs20-t-c-test", password="password",
5126                    ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
5127                    ieee80211w='2', scan_freq="2412")
5128 
5129     ev = hapd.wait_event(["HS20-T-C-FILTERING-ADD"], timeout=5)
5130     if ev is None:
5131         raise Exception("Terms and Conditions filtering not enabled")
5132     if ev.split(' ')[1] != dev[0].own_addr():
5133         raise Exception("Unexpected STA address for filtering: " + ev)
5134 
5135     ev = dev[0].wait_event(["HS20-T-C-ACCEPTANCE"], timeout=5)
5136     if ev is None:
5137         raise Exception("Terms and Conditions Acceptance notification not received")
5138     url = "https://example.com/t_and_c?addr=%s&ap=123" % dev[0].own_addr()
5139     if url not in ev:
5140         raise Exception("Unexpected URL: " + ev)
5141 
5142     dict = pyrad.dictionary.Dictionary("dictionary.radius")
5143 
5144     srv = pyrad.client.Client(server="127.0.0.1", acctport=3799,
5145                               secret=b"secret", dict=dict)
5146     srv.retries = 1
5147     srv.timeout = 1
5148 
5149     sta = hapd.get_sta(dev[0].own_addr())
5150     multi_sess_id = sta['authMultiSessionId']
5151 
5152     logger.info("CoA-Request with matching Acct-Session-Id")
5153     vsa = binascii.unhexlify('00009f68090600000000')
5154     req = radius_das.CoAPacket(dict=dict, secret=b"secret",
5155                                NAS_IP_Address="127.0.0.1",
5156                                Acct_Multi_Session_Id=multi_sess_id,
5157                                Chargeable_User_Identity="hs20-cui",
5158                                Event_Timestamp=int(time.time()),
5159                                Vendor_Specific=vsa)
5160     reply = srv.SendPacket(req)
5161     logger.debug("RADIUS response from hostapd")
5162     for i in list(reply.keys()):
5163         logger.debug("%s: %s" % (i, reply[i]))
5164     if reply.code != pyrad.packet.CoAACK:
5165         raise Exception("CoA-Request failed")
5166 
5167     ev = hapd.wait_event(["HS20-T-C-FILTERING-REMOVE"], timeout=5)
5168     if ev is None:
5169         raise Exception("Terms and Conditions filtering not disabled")
5170     if ev.split(' ')[1] != dev[0].own_addr():
5171         raise Exception("Unexpected STA address for filtering: " + ev)
5172 
5173 def test_ap_hs20_terms_and_conditions_sql(dev, apdev, params):
5174     """Hotspot 2.0 Terms and Conditions using SQLite for user DB"""
5175     addr = dev[0].own_addr()
5176     run_ap_hs20_terms_and_conditions_sql(dev, apdev, params,
5177                                          "https://example.com/t_and_c?addr=@1@&ap=123",
5178                                          "https://example.com/t_and_c?addr=" + addr + "&ap=123")
5179 
5180 def test_ap_hs20_terms_and_conditions_sql2(dev, apdev, params):
5181     """Hotspot 2.0 Terms and Conditions using SQLite for user DB"""
5182     addr = dev[0].own_addr()
5183     run_ap_hs20_terms_and_conditions_sql(dev, apdev, params,
5184                                          "https://example.com/t_and_c?addr=@1@",
5185                                          "https://example.com/t_and_c?addr=" + addr)
5186 
5187 def run_ap_hs20_terms_and_conditions_sql(dev, apdev, params, url_template,
5188                                          url_expected):
5189     check_eap_capa(dev[0], "MSCHAPV2")
5190     try:
5191         import sqlite3
5192     except ImportError:
5193         raise HwsimSkip("No sqlite3 module available")
5194     dbfile = params['prefix'] + ".eap-user.db"
5195     try:
5196         os.remove(dbfile)
5197     except:
5198         pass
5199     con = sqlite3.connect(dbfile)
5200     with con:
5201         cur = con.cursor()
5202         cur.execute("CREATE TABLE users(identity TEXT PRIMARY KEY, methods TEXT, password TEXT, phase2 INTEGER, t_c_timestamp INTEGER)")
5203         cur.execute("CREATE TABLE wildcards(identity TEXT PRIMARY KEY, methods TEXT)")
5204         cur.execute("INSERT INTO users(identity,methods,password,phase2) VALUES ('user-mschapv2','TTLS-MSCHAPV2','password',1)")
5205         cur.execute("INSERT INTO wildcards(identity,methods) VALUES ('','TTLS,TLS')")
5206         cur.execute("CREATE TABLE authlog(timestamp TEXT, session TEXT, nas_ip TEXT, username TEXT, note TEXT)")
5207         cur.execute("CREATE TABLE pending_tc(mac_addr TEXT PRIMARY KEY, identity TEXT)")
5208         cur.execute("CREATE TABLE current_sessions(mac_addr TEXT PRIMARY KEY, identity TEXT, start_time TEXT, nas TEXT, hs20_t_c_filtering BOOLEAN, waiting_coa_ack BOOLEAN, coa_ack_received BOOLEAN)")
5209 
5210 
5211     try:
5212         params = {"ssid": "as", "beacon_int": "2000",
5213                   "radius_server_clients": "auth_serv/radius_clients.conf",
5214                   "radius_server_auth_port": '18128',
5215                   "eap_server": "1",
5216                   "eap_user_file": "sqlite:" + dbfile,
5217                   "ca_cert": "auth_serv/ca.pem",
5218                   "server_cert": "auth_serv/server.pem",
5219                   "private_key": "auth_serv/server.key"}
5220         params['hs20_t_c_server_url'] = url_template
5221         authsrv = hostapd.add_ap(apdev[1], params)
5222 
5223         bssid = apdev[0]['bssid']
5224         params = hs20_ap_params()
5225         params['auth_server_port'] = "18128"
5226         params['hs20_t_c_filename'] = 'terms-and-conditions'
5227         params['hs20_t_c_timestamp'] = '123456789'
5228         params['own_ip_addr'] = "127.0.0.1"
5229         params['radius_das_port'] = "3799"
5230         params['radius_das_client'] = "127.0.0.1 radius"
5231         params['radius_das_require_event_timestamp'] = "1"
5232         params['disable_pmksa_caching'] = '1'
5233         hapd = hostapd.add_ap(apdev[0], params)
5234 
5235         dev[0].request("SET pmf 1")
5236         dev[0].hs20_enable()
5237         id = dev[0].add_cred_values({'realm': "example.com",
5238                                      'username': "user-mschapv2",
5239                                      'password': "password",
5240                                      'ca_cert': "auth_serv/ca.pem"})
5241         interworking_select(dev[0], bssid, freq="2412")
5242         interworking_connect(dev[0], bssid, "TTLS")
5243 
5244         ev = hapd.wait_event(["HS20-T-C-FILTERING-ADD"], timeout=5)
5245         if ev is None:
5246             raise Exception("Terms and Conditions filtering not enabled")
5247         hapd.dump_monitor()
5248 
5249         ev = dev[0].wait_event(["HS20-T-C-ACCEPTANCE"], timeout=5)
5250         if ev is None:
5251             raise Exception("Terms and Conditions Acceptance notification not received")
5252         url = ev.split(' ')[1]
5253         if url != url_expected:
5254             raise Exception("Unexpected URL delivered to the client: %s (expected %s)" % (url, url_expected))
5255         dev[0].dump_monitor()
5256 
5257         with con:
5258             cur = con.cursor()
5259             cur.execute("SELECT * from current_sessions")
5260             rows = cur.fetchall()
5261             if len(rows) != 1:
5262                 raise Exeception("Unexpected number of rows in current_sessions (%d; expected %d)" % (len(rows), 1))
5263             logger.info("current_sessions: " + str(rows))
5264 
5265         tests = ["foo", "disconnect q", "coa %s" % dev[0].own_addr()]
5266         for t in tests:
5267             if "FAIL" not in authsrv.request("DAC_REQUEST " + t):
5268                 raise Exception("Invalid DAC_REQUEST accepted: " + t)
5269         if "OK" not in authsrv.request("DAC_REQUEST coa %s t_c_clear" % dev[0].own_addr()):
5270             raise Exception("DAC_REQUEST failed")
5271 
5272         ev = hapd.wait_event(["HS20-T-C-FILTERING-REMOVE"], timeout=5)
5273         if ev is None:
5274             raise Exception("Terms and Conditions filtering not disabled")
5275         if ev.split(' ')[1] != dev[0].own_addr():
5276             raise Exception("Unexpected STA address for filtering: " + ev)
5277 
5278         time.sleep(0.2)
5279         with con:
5280             cur = con.cursor()
5281             cur.execute("SELECT * from current_sessions")
5282             rows = cur.fetchall()
5283             if len(rows) != 1:
5284                 raise Exeception("Unexpected number of rows in current_sessions (%d; expected %d)" % (len(rows), 1))
5285             logger.info("current_sessions: " + str(rows))
5286             if rows[0][4] != 0 or rows[0][5] != 0 or rows[0][6] != 1:
5287                 raise Exception("Unexpected current_sessions information after CoA-ACK")
5288 
5289         dev[0].request("DISCONNECT")
5290         dev[0].wait_disconnected()
5291         dev[0].dump_monitor()
5292 
5293         # Simulate T&C server operation on user reading the updated version
5294         with con:
5295             cur = con.cursor()
5296             cur.execute("SELECT identity FROM pending_tc WHERE mac_addr='" +
5297                         dev[0].own_addr() + "'")
5298             rows = cur.fetchall()
5299             if len(rows) != 1:
5300                 raise Exception("No pending_tc entry found")
5301             if rows[0][0] != 'user-mschapv2':
5302                 raise Exception("Unexpected pending_tc identity value")
5303 
5304             cur.execute("UPDATE users SET t_c_timestamp=123456789 WHERE identity='user-mschapv2'")
5305 
5306         dev[0].request("RECONNECT")
5307         dev[0].wait_connected()
5308 
5309         ev = hapd.wait_event(["HS20-T-C-FILTERING-ADD"], timeout=0.1)
5310         if ev is not None:
5311             raise Exception("Terms and Conditions filtering enabled unexpectedly")
5312         hapd.dump_monitor()
5313 
5314         ev = dev[0].wait_event(["HS20-T-C-ACCEPTANCE"], timeout=0.1)
5315         if ev is not None:
5316             raise Exception("Unexpected Terms and Conditions Acceptance notification")
5317         dev[0].dump_monitor()
5318 
5319         dev[0].request("DISCONNECT")
5320         dev[0].wait_disconnected()
5321         dev[0].dump_monitor()
5322 
5323         # New T&C available
5324         hapd.set('hs20_t_c_timestamp', '123456790')
5325 
5326         dev[0].request("RECONNECT")
5327         dev[0].wait_connected()
5328 
5329         ev = hapd.wait_event(["HS20-T-C-FILTERING-ADD"], timeout=5)
5330         if ev is None:
5331             raise Exception("Terms and Conditions filtering not enabled")
5332         hapd.dump_monitor()
5333 
5334         ev = dev[0].wait_event(["HS20-T-C-ACCEPTANCE"], timeout=5)
5335         if ev is None:
5336             raise Exception("Terms and Conditions Acceptance notification not received (2)")
5337         dev[0].dump_monitor()
5338 
5339         dev[0].request("DISCONNECT")
5340         dev[0].wait_disconnected()
5341         dev[0].dump_monitor()
5342 
5343         # Simulate T&C server operation on user reading the updated version
5344         with con:
5345             cur = con.cursor()
5346             cur.execute("UPDATE users SET t_c_timestamp=123456790 WHERE identity='user-mschapv2'")
5347 
5348         dev[0].request("RECONNECT")
5349         dev[0].wait_connected()
5350 
5351         ev = hapd.wait_event(["HS20-T-C-FILTERING-ADD"], timeout=0.1)
5352         if ev is not None:
5353             raise Exception("Terms and Conditions filtering enabled unexpectedly")
5354         hapd.dump_monitor()
5355 
5356         ev = dev[0].wait_event(["HS20-T-C-ACCEPTANCE"], timeout=0.1)
5357         if ev is not None:
5358             raise Exception("Unexpected Terms and Conditions Acceptance notification (2)")
5359         dev[0].dump_monitor()
5360     finally:
5361         os.remove(dbfile)
5362         dev[0].request("SET pmf 0")
5363 
5364 def test_ap_hs20_release_number_1(dev, apdev):
5365     """Hotspot 2.0 with AP claiming support for Release 1"""
5366     run_ap_hs20_release_number(dev, apdev, 1)
5367 
5368 def test_ap_hs20_release_number_2(dev, apdev):
5369     """Hotspot 2.0 with AP claiming support for Release 2"""
5370     run_ap_hs20_release_number(dev, apdev, 2)
5371 
5372 def test_ap_hs20_release_number_3(dev, apdev):
5373     """Hotspot 2.0 with AP claiming support for Release 3"""
5374     run_ap_hs20_release_number(dev, apdev, 3)
5375 
5376 def run_ap_hs20_release_number(dev, apdev, release):
5377     check_eap_capa(dev[0], "MSCHAPV2")
5378     eap_test(dev[0], apdev[0], "21[3:26][6:7][99:99]", "TTLS", "user",
5379              release=release)
5380     rel = dev[0].get_status_field('hs20')
5381     if rel != str(release):
5382         raise Exception("Unexpected release number indicated: " + rel)
5383 
5384 def test_ap_hs20_missing_pmf(dev, apdev):
5385     """Hotspot 2.0 connection attempt without PMF"""
5386     check_eap_capa(dev[0], "MSCHAPV2")
5387     bssid = apdev[0]['bssid']
5388     params = hs20_ap_params()
5389     params['hessid'] = bssid
5390     params['disable_dgaf'] = '1'
5391     hostapd.add_ap(apdev[0], params)
5392 
5393     dev[0].hs20_enable()
5394     dev[0].connect("test-hs20", proto="RSN", key_mgmt="WPA-EAP", eap="TTLS",
5395                    ieee80211w="0",
5396                    identity="hs20-test", password="password",
5397                    ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
5398                    scan_freq="2412", update_identifier="54321",
5399                    roaming_consortium_selection="1020304050",
5400                    wait_connect=False)
5401     ev = dev[0].wait_event(["CTRL-EVENT-ASSOC-REJECT"], timeout=10)
5402     dev[0].request("DISCONNECT")
5403     if ev is None:
5404         raise Exception("Association rejection not reported")
5405     if "status_code=31" not in ev:
5406         raise Exception("Unexpected rejection reason: " + ev)
5407 
5408 def test_ap_hs20_open_osu_association(dev, apdev):
5409     """Hotspot 2.0 open OSU association"""
5410     try:
5411         run_ap_hs20_open_osu_association(dev, apdev)
5412     finally:
5413         dev[0].request("VENDOR_ELEM_REMOVE 13 *")
5414 
5415 def run_ap_hs20_open_osu_association(dev, apdev):
5416     params = {"ssid": "HS 2.0 OSU open"}
5417     hostapd.add_ap(apdev[0], params)
5418     dev[0].connect("HS 2.0 OSU open", key_mgmt="NONE", scan_freq="2412")
5419     dev[0].request("REMOVE_NETWORK all")
5420     dev[0].wait_disconnected()
5421     dev[0].dump_monitor()
5422     # Test with unexpected Hotspot 2.0 Indication element in Assoc Req
5423     dev[0].request("VENDOR_ELEM_ADD 13 dd07506f9a10220000")
5424     dev[0].connect("HS 2.0 OSU open", key_mgmt="NONE", scan_freq="2412")
5425