tests: Make HS 2.0 test cases more robust
[mech_eap.git] / tests / hwsim / test_ap_hs20.py
1 # Hotspot 2.0 tests
2 # Copyright (c) 2013-2014, 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 import time
8 import subprocess
9 import logging
10 logger = logging.getLogger()
11 import os
12 import os.path
13 import subprocess
14
15 import hostapd
16 from wlantest import Wlantest
17 from wpasupplicant import WpaSupplicant
18
19 def hs20_ap_params(ssid="test-hs20"):
20     params = hostapd.wpa2_params(ssid=ssid)
21     params['wpa_key_mgmt'] = "WPA-EAP"
22     params['ieee80211w'] = "1"
23     params['ieee8021x'] = "1"
24     params['auth_server_addr'] = "127.0.0.1"
25     params['auth_server_port'] = "1812"
26     params['auth_server_shared_secret'] = "radius"
27     params['interworking'] = "1"
28     params['access_network_type'] = "14"
29     params['internet'] = "1"
30     params['asra'] = "0"
31     params['esr'] = "0"
32     params['uesa'] = "0"
33     params['venue_group'] = "7"
34     params['venue_type'] = "1"
35     params['venue_name'] = [ "eng:Example venue", "fin:Esimerkkipaikka" ]
36     params['roaming_consortium'] = [ "112233", "1020304050", "010203040506",
37                                      "fedcba" ]
38     params['domain_name'] = "example.com,another.example.com"
39     params['nai_realm'] = [ "0,example.com,13[5:6],21[2:4][5:7]",
40                             "0,another.example.com" ]
41     params['hs20'] = "1"
42     params['hs20_wan_metrics'] = "01:8000:1000:80:240:3000"
43     params['hs20_conn_capab'] = [ "1:0:2", "6:22:1", "17:5060:0" ]
44     params['hs20_operating_class'] = "5173"
45     params['anqp_3gpp_cell_net'] = "244,91"
46     return params
47
48 def check_auto_select(dev, bssid):
49     dev.scan_for_bss(bssid, freq="2412")
50     dev.request("INTERWORKING_SELECT auto freq=2412")
51     ev = dev.wait_event(["CTRL-EVENT-CONNECTED"], timeout=15)
52     if ev is None:
53         raise Exception("Connection timed out")
54     if bssid not in ev:
55         raise Exception("Connected to incorrect network")
56     dev.request("REMOVE_NETWORK all")
57
58 def interworking_select(dev, bssid, type=None, no_match=False, freq=None):
59     dev.dump_monitor()
60     if bssid and freq and not no_match:
61         dev.scan_for_bss(bssid, freq=freq)
62     freq_extra = " freq=" + freq if freq else ""
63     dev.request("INTERWORKING_SELECT" + freq_extra)
64     ev = dev.wait_event(["INTERWORKING-AP", "INTERWORKING-NO-MATCH"],
65                         timeout=15)
66     if ev is None:
67         raise Exception("Network selection timed out");
68     if no_match:
69         if "INTERWORKING-NO-MATCH" not in ev:
70             raise Exception("Unexpected network match")
71         return
72     if "INTERWORKING-NO-MATCH" in ev:
73         logger.info("Matching network not found - try again")
74         dev.dump_monitor()
75         dev.request("INTERWORKING_SELECT" + freq_extra)
76         ev = dev.wait_event(["INTERWORKING-AP", "INTERWORKING-NO-MATCH"],
77                             timeout=15)
78         if ev is None:
79             raise Exception("Network selection timed out");
80         if "INTERWORKING-NO-MATCH" in ev:
81             raise Exception("Matching network not found")
82     if bssid and bssid not in ev:
83         raise Exception("Unexpected BSSID in match")
84     if type and "type=" + type not in ev:
85         raise Exception("Network type not recognized correctly")
86
87 def check_sp_type(dev, sp_type):
88     type = dev.get_status_field("sp_type")
89     if type is None:
90         raise Exception("sp_type not available")
91     if type != sp_type:
92         raise Exception("sp_type did not indicate home network")
93
94 def hlr_auc_gw_available():
95     if not os.path.exists("/tmp/hlr_auc_gw.sock"):
96         logger.info("No hlr_auc_gw available");
97         return False
98     if not os.path.exists("../../hostapd/hlr_auc_gw"):
99         logger.info("No hlr_auc_gw available");
100         return False
101     return True
102
103 def interworking_ext_sim_connect(dev, bssid, method):
104     dev.request("INTERWORKING_CONNECT " + bssid)
105     interworking_ext_sim_auth(dev, method)
106
107 def interworking_ext_sim_auth(dev, method):
108     ev = dev.wait_event(["CTRL-EVENT-EAP-METHOD"], timeout=15)
109     if ev is None:
110         raise Exception("Network connected timed out")
111     if "(" + method + ")" not in ev:
112         raise Exception("Unexpected EAP method selection")
113
114     ev = dev.wait_event(["CTRL-REQ-SIM"], timeout=15)
115     if ev is None:
116         raise Exception("Wait for external SIM processing request timed out")
117     p = ev.split(':', 2)
118     if p[1] != "GSM-AUTH":
119         raise Exception("Unexpected CTRL-REQ-SIM type")
120     id = p[0].split('-')[3]
121     rand = p[2].split(' ')[0]
122
123     res = subprocess.check_output(["../../hostapd/hlr_auc_gw",
124                                    "-m",
125                                    "auth_serv/hlr_auc_gw.milenage_db",
126                                    "GSM-AUTH-REQ 232010000000000 " + rand])
127     if "GSM-AUTH-RESP" not in res:
128         raise Exception("Unexpected hlr_auc_gw response")
129     resp = res.split(' ')[2].rstrip()
130
131     dev.request("CTRL-RSP-SIM-" + id + ":GSM-AUTH:" + resp)
132     ev = dev.wait_event(["CTRL-EVENT-CONNECTED"], timeout=15)
133     if ev is None:
134         raise Exception("Connection timed out")
135
136 def interworking_connect(dev, bssid, method):
137     dev.request("INTERWORKING_CONNECT " + bssid)
138     interworking_auth(dev, method)
139
140 def interworking_auth(dev, method):
141     ev = dev.wait_event(["CTRL-EVENT-EAP-METHOD"], timeout=15)
142     if ev is None:
143         raise Exception("Network connected timed out")
144     if "(" + method + ")" not in ev:
145         raise Exception("Unexpected EAP method selection")
146
147     ev = dev.wait_event(["CTRL-EVENT-CONNECTED"], timeout=15)
148     if ev is None:
149         raise Exception("Connection timed out")
150
151 def check_probe_resp(wt, bssid_unexpected, bssid_expected):
152     if bssid_unexpected:
153         count = wt.get_bss_counter("probe_response", bssid_unexpected)
154         if count > 0:
155             raise Exception("Unexpected Probe Response frame from AP")
156
157     if bssid_expected:
158         count = wt.get_bss_counter("probe_response", bssid_expected)
159         if count == 0:
160             raise Exception("No Probe Response frame from AP")
161
162 def test_ap_anqp_sharing(dev, apdev):
163     """ANQP sharing within ESS and explicit unshare"""
164     bssid = apdev[0]['bssid']
165     params = hs20_ap_params()
166     params['hessid'] = bssid
167     hostapd.add_ap(apdev[0]['ifname'], params)
168
169     bssid2 = apdev[1]['bssid']
170     params = hs20_ap_params()
171     params['hessid'] = bssid
172     params['nai_realm'] = [ "0,example.com,13[5:6],21[2:4][5:7]" ]
173     hostapd.add_ap(apdev[1]['ifname'], params)
174
175     dev[0].hs20_enable()
176     id = dev[0].add_cred_values({ 'realm': "example.com", 'username': "test",
177                                   'password': "secret",
178                                   'domain': "example.com" })
179     logger.info("Normal network selection with shared ANQP results")
180     dev[0].scan_for_bss(bssid, freq="2412")
181     dev[0].scan_for_bss(bssid2, freq="2412")
182     interworking_select(dev[0], None, "home", freq="2412")
183     dev[0].dump_monitor()
184
185     res1 = dev[0].get_bss(bssid)
186     res2 = dev[0].get_bss(bssid2)
187     if res1['anqp_nai_realm'] != res2['anqp_nai_realm']:
188         raise Exception("ANQP results were not shared between BSSes")
189
190     logger.info("Explicit ANQP request to unshare ANQP results")
191     dev[0].request("ANQP_GET " + bssid + " 263")
192     ev = dev[0].wait_event(["RX-ANQP"], timeout=5)
193     if ev is None:
194         raise Exception("ANQP operation timed out")
195
196     dev[0].request("ANQP_GET " + bssid2 + " 263")
197     ev = dev[0].wait_event(["RX-ANQP"], timeout=5)
198     if ev is None:
199         raise Exception("ANQP operation timed out")
200
201     res1 = dev[0].get_bss(bssid)
202     res2 = dev[0].get_bss(bssid2)
203     if res1['anqp_nai_realm'] == res2['anqp_nai_realm']:
204         raise Exception("ANQP results were not unshared")
205
206 def test_ap_nai_home_realm_query(dev, apdev):
207     """NAI Home Realm Query"""
208     bssid = apdev[0]['bssid']
209     params = hs20_ap_params()
210     params['nai_realm'] = [ "0,example.com,13[5:6],21[2:4][5:7]",
211                             "0,another.example.org" ]
212     hostapd.add_ap(apdev[0]['ifname'], params)
213
214     dev[0].scan(freq="2412")
215     dev[0].request("HS20_GET_NAI_HOME_REALM_LIST " + bssid + " realm=example.com")
216     ev = dev[0].wait_event(["RX-ANQP"], timeout=5)
217     if ev is None:
218         raise Exception("ANQP operation timed out")
219     nai1 = dev[0].get_bss(bssid)['anqp_nai_realm']
220     dev[0].dump_monitor()
221
222     dev[0].request("ANQP_GET " + bssid + " 263")
223     ev = dev[0].wait_event(["RX-ANQP"], timeout=5)
224     if ev is None:
225         raise Exception("ANQP operation timed out")
226     nai2 = dev[0].get_bss(bssid)['anqp_nai_realm']
227
228     if len(nai1) >= len(nai2):
229         raise Exception("Unexpected NAI Realm list response lengths")
230     if "example.com".encode('hex') not in nai1:
231         raise Exception("Home realm not reported")
232     if "example.org".encode('hex') in nai1:
233         raise Exception("Non-home realm reported")
234     if "example.com".encode('hex') not in nai2:
235         raise Exception("Home realm not reported in wildcard query")
236     if "example.org".encode('hex') not in nai2:
237         raise Exception("Non-home realm not reported in wildcard query ")
238
239 def test_ap_interworking_scan_filtering(dev, apdev):
240     """Interworking scan filtering with HESSID and access network type"""
241     bssid = apdev[0]['bssid']
242     params = hs20_ap_params()
243     ssid = "test-hs20-ap1"
244     params['ssid'] = ssid
245     params['hessid'] = bssid
246     hostapd.add_ap(apdev[0]['ifname'], params)
247
248     bssid2 = apdev[1]['bssid']
249     params = hs20_ap_params()
250     ssid2 = "test-hs20-ap2"
251     params['ssid'] = ssid2
252     params['hessid'] = bssid2
253     params['access_network_type'] = "1"
254     del params['venue_group']
255     del params['venue_type']
256     hostapd.add_ap(apdev[1]['ifname'], params)
257
258     dev[0].hs20_enable()
259
260     wt = Wlantest()
261     wt.flush()
262
263     logger.info("Check probe request filtering based on HESSID")
264
265     dev[0].request("SET hessid " + bssid2)
266     dev[0].scan(freq="2412")
267     time.sleep(0.03)
268     check_probe_resp(wt, bssid, bssid2)
269
270     logger.info("Check probe request filtering based on access network type")
271
272     wt.clear_bss_counters(bssid)
273     wt.clear_bss_counters(bssid2)
274     dev[0].request("SET hessid 00:00:00:00:00:00")
275     dev[0].request("SET access_network_type 14")
276     dev[0].scan(freq="2412")
277     time.sleep(0.03)
278     check_probe_resp(wt, bssid2, bssid)
279
280     wt.clear_bss_counters(bssid)
281     wt.clear_bss_counters(bssid2)
282     dev[0].request("SET hessid 00:00:00:00:00:00")
283     dev[0].request("SET access_network_type 1")
284     dev[0].scan(freq="2412")
285     time.sleep(0.03)
286     check_probe_resp(wt, bssid, bssid2)
287
288     logger.info("Check probe request filtering based on HESSID and ANT")
289
290     wt.clear_bss_counters(bssid)
291     wt.clear_bss_counters(bssid2)
292     dev[0].request("SET hessid " + bssid)
293     dev[0].request("SET access_network_type 14")
294     dev[0].scan(freq="2412")
295     time.sleep(0.03)
296     check_probe_resp(wt, bssid2, bssid)
297
298     wt.clear_bss_counters(bssid)
299     wt.clear_bss_counters(bssid2)
300     dev[0].request("SET hessid " + bssid2)
301     dev[0].request("SET access_network_type 14")
302     dev[0].scan(freq="2412")
303     time.sleep(0.03)
304     check_probe_resp(wt, bssid, None)
305     check_probe_resp(wt, bssid2, None)
306
307     wt.clear_bss_counters(bssid)
308     wt.clear_bss_counters(bssid2)
309     dev[0].request("SET hessid " + bssid)
310     dev[0].request("SET access_network_type 1")
311     dev[0].scan(freq="2412")
312     time.sleep(0.03)
313     check_probe_resp(wt, bssid, None)
314     check_probe_resp(wt, bssid2, None)
315
316 def test_ap_hs20_select(dev, apdev):
317     """Hotspot 2.0 network selection"""
318     bssid = apdev[0]['bssid']
319     params = hs20_ap_params()
320     params['hessid'] = bssid
321     hostapd.add_ap(apdev[0]['ifname'], params)
322
323     dev[0].hs20_enable()
324     id = dev[0].add_cred_values({ 'realm': "example.com", 'username': "test",
325                                   'password': "secret",
326                                   'domain': "example.com" })
327     interworking_select(dev[0], bssid, "home")
328
329     dev[0].remove_cred(id)
330     id = dev[0].add_cred_values({ 'realm': "example.com", 'username': "test",
331                                   'password': "secret",
332                                   'domain': "no.match.example.com" })
333     interworking_select(dev[0], bssid, "roaming", freq="2412")
334
335     dev[0].set_cred_quoted(id, "realm", "no.match.example.com");
336     interworking_select(dev[0], bssid, no_match=True, freq="2412")
337
338     bssid2 = apdev[1]['bssid']
339     params = hs20_ap_params()
340     params['nai_realm'] = [ "0,example.org,21" ]
341     params['hessid'] = bssid2
342     params['domain_name'] = "example.org"
343     hostapd.add_ap(apdev[1]['ifname'], params)
344     dev[0].remove_cred(id)
345     id = dev[0].add_cred_values({ 'realm': "example.org", 'username': "test",
346                                   'password': "secret",
347                                   'domain': "example.org" })
348     interworking_select(dev[0], bssid2, "home", freq="2412")
349
350 def hs20_simulated_sim(dev, ap, method):
351     bssid = ap['bssid']
352     params = hs20_ap_params()
353     params['hessid'] = bssid
354     params['anqp_3gpp_cell_net'] = "555,444"
355     params['domain_name'] = "wlan.mnc444.mcc555.3gppnetwork.org"
356     hostapd.add_ap(ap['ifname'], params)
357
358     dev.hs20_enable()
359     dev.add_cred_values({ 'imsi': "555444-333222111", 'eap': method,
360                           'milenage': "5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123"})
361     interworking_select(dev, "home", freq="2412")
362     interworking_connect(dev, bssid, method)
363     check_sp_type(dev, "home")
364
365 def test_ap_hs20_sim(dev, apdev):
366     """Hotspot 2.0 with simulated SIM and EAP-SIM"""
367     if not hlr_auc_gw_available():
368         return "skip"
369     hs20_simulated_sim(dev[0], apdev[0], "SIM")
370     dev[0].request("INTERWORKING_SELECT auto freq=2412")
371     ev = dev[0].wait_event(["INTERWORKING-ALREADY-CONNECTED"], timeout=15)
372     if ev is None:
373         raise Exception("Timeout on already-connected event")
374
375 def test_ap_hs20_aka(dev, apdev):
376     """Hotspot 2.0 with simulated USIM and EAP-AKA"""
377     if not hlr_auc_gw_available():
378         return "skip"
379     hs20_simulated_sim(dev[0], apdev[0], "AKA")
380
381 def test_ap_hs20_aka_prime(dev, apdev):
382     """Hotspot 2.0 with simulated USIM and EAP-AKA'"""
383     if not hlr_auc_gw_available():
384         return "skip"
385     hs20_simulated_sim(dev[0], apdev[0], "AKA'")
386
387 def test_ap_hs20_ext_sim(dev, apdev):
388     """Hotspot 2.0 with external SIM processing"""
389     if not hlr_auc_gw_available():
390         return "skip"
391     bssid = apdev[0]['bssid']
392     params = hs20_ap_params()
393     params['hessid'] = bssid
394     params['anqp_3gpp_cell_net'] = "232,01"
395     params['domain_name'] = "wlan.mnc001.mcc232.3gppnetwork.org"
396     hostapd.add_ap(apdev[0]['ifname'], params)
397
398     dev[0].hs20_enable()
399     dev[0].request("SET external_sim 1")
400     dev[0].add_cred_values({ 'imsi': "23201-0000000000", 'eap': "SIM" })
401     interworking_select(dev[0], "home", freq="2412")
402     interworking_ext_sim_connect(dev[0], bssid, "SIM")
403     check_sp_type(dev[0], "home")
404
405 def test_ap_hs20_ext_sim_roaming(dev, apdev):
406     """Hotspot 2.0 with external SIM processing in roaming network"""
407     if not hlr_auc_gw_available():
408         return "skip"
409     bssid = apdev[0]['bssid']
410     params = hs20_ap_params()
411     params['hessid'] = bssid
412     params['anqp_3gpp_cell_net'] = "244,91;310,026;232,01;234,56"
413     params['domain_name'] = "wlan.mnc091.mcc244.3gppnetwork.org"
414     hostapd.add_ap(apdev[0]['ifname'], params)
415
416     dev[0].hs20_enable()
417     dev[0].request("SET external_sim 1")
418     dev[0].add_cred_values({ 'imsi': "23201-0000000000", 'eap': "SIM" })
419     interworking_select(dev[0], "roaming", freq="2412")
420     interworking_ext_sim_connect(dev[0], bssid, "SIM")
421     check_sp_type(dev[0], "roaming")
422
423 def test_ap_hs20_username(dev, apdev):
424     """Hotspot 2.0 connection in username/password credential"""
425     bssid = apdev[0]['bssid']
426     params = hs20_ap_params()
427     params['hessid'] = bssid
428     params['disable_dgaf'] = '1'
429     hostapd.add_ap(apdev[0]['ifname'], params)
430
431     dev[0].hs20_enable()
432     id = dev[0].add_cred_values({ 'realm': "example.com",
433                                   'username': "hs20-test",
434                                   'password': "password",
435                                   'ca_cert': "auth_serv/ca.pem",
436                                   'domain': "example.com",
437                                   'update_identifier': "1234" })
438     interworking_select(dev[0], bssid, "home", freq="2412")
439     interworking_connect(dev[0], bssid, "TTLS")
440     check_sp_type(dev[0], "home")
441     status = dev[0].get_status()
442     if status['pairwise_cipher'] != "CCMP":
443         raise Exception("Unexpected pairwise cipher")
444     if status['hs20'] != "2":
445         raise Exception("Unexpected HS 2.0 support indication")
446
447     dev[1].connect("test-hs20", key_mgmt="WPA-EAP", eap="TTLS",
448                    identity="hs20-test", password="password",
449                    ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
450                    scan_freq="2412")
451
452 def test_ap_hs20_connect_api(dev, apdev):
453     """Hotspot 2.0 connection with connect API"""
454     bssid = apdev[0]['bssid']
455     params = hs20_ap_params()
456     params['hessid'] = bssid
457     params['disable_dgaf'] = '1'
458     hostapd.add_ap(apdev[0]['ifname'], params)
459
460     wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
461     wpas.interface_add("wlan5", drv_params="force_connect_cmd=1")
462     wpas.hs20_enable()
463     id = wpas.add_cred_values({ 'realm': "example.com",
464                                   'username': "hs20-test",
465                                   'password': "password",
466                                   'ca_cert': "auth_serv/ca.pem",
467                                   'domain': "example.com",
468                                   'update_identifier': "1234" })
469     interworking_select(wpas, bssid, "home", freq="2412")
470     interworking_connect(wpas, bssid, "TTLS")
471     check_sp_type(wpas, "home")
472     status = wpas.get_status()
473     if status['pairwise_cipher'] != "CCMP":
474         raise Exception("Unexpected pairwise cipher")
475     if status['hs20'] != "2":
476         raise Exception("Unexpected HS 2.0 support indication")
477
478 def test_ap_hs20_auto_interworking(dev, apdev):
479     """Hotspot 2.0 connection with auto_interworking=1"""
480     bssid = apdev[0]['bssid']
481     params = hs20_ap_params()
482     params['hessid'] = bssid
483     params['disable_dgaf'] = '1'
484     hostapd.add_ap(apdev[0]['ifname'], params)
485
486     dev[0].hs20_enable(auto_interworking=True)
487     id = dev[0].add_cred_values({ 'realm': "example.com",
488                                   'username': "hs20-test",
489                                   'password': "password",
490                                   'ca_cert': "auth_serv/ca.pem",
491                                   'domain': "example.com",
492                                   'update_identifier': "1234" })
493     dev[0].request("REASSOCIATE")
494     ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED"], timeout=15)
495     if ev is None:
496         raise Exception("Connection timed out")
497     check_sp_type(dev[0], "home")
498     status = dev[0].get_status()
499     if status['pairwise_cipher'] != "CCMP":
500         raise Exception("Unexpected pairwise cipher")
501     if status['hs20'] != "2":
502         raise Exception("Unexpected HS 2.0 support indication")
503
504 def eap_test(dev, ap, eap_params, method, user):
505     bssid = ap['bssid']
506     params = hs20_ap_params()
507     params['nai_realm'] = [ "0,example.com," + eap_params ]
508     hostapd.add_ap(ap['ifname'], params)
509
510     dev.hs20_enable()
511     dev.add_cred_values({ 'realm': "example.com",
512                           'username': user,
513                           'password': "password" })
514     interworking_select(dev, bssid, freq="2412")
515     interworking_connect(dev, bssid, method)
516
517 def test_ap_hs20_eap_unknown(dev, apdev):
518     """Hotspot 2.0 connection with unknown EAP method"""
519     bssid = apdev[0]['bssid']
520     params = hs20_ap_params()
521     params['nai_realm'] = "0,example.com,99"
522     hostapd.add_ap(apdev[0]['ifname'], params)
523
524     dev[0].hs20_enable()
525     dev[0].add_cred_values(default_cred())
526     interworking_select(dev[0], None, no_match=True, freq="2412")
527
528 def test_ap_hs20_eap_peap_mschapv2(dev, apdev):
529     """Hotspot 2.0 connection with PEAP/MSCHAPV2"""
530     eap_test(dev[0], apdev[0], "25[3:26]", "PEAP", "user")
531
532 def test_ap_hs20_eap_peap_default(dev, apdev):
533     """Hotspot 2.0 connection with PEAP/MSCHAPV2 (as default)"""
534     eap_test(dev[0], apdev[0], "25", "PEAP", "user")
535
536 def test_ap_hs20_eap_peap_gtc(dev, apdev):
537     """Hotspot 2.0 connection with PEAP/GTC"""
538     eap_test(dev[0], apdev[0], "25[3:6]", "PEAP", "user")
539
540 def test_ap_hs20_eap_peap_unknown(dev, apdev):
541     """Hotspot 2.0 connection with PEAP/unknown"""
542     bssid = apdev[0]['bssid']
543     params = hs20_ap_params()
544     params['nai_realm'] = "0,example.com,25[3:99]"
545     hostapd.add_ap(apdev[0]['ifname'], params)
546
547     dev[0].hs20_enable()
548     dev[0].add_cred_values(default_cred())
549     interworking_select(dev[0], None, no_match=True, freq="2412")
550
551 def test_ap_hs20_eap_ttls_chap(dev, apdev):
552     """Hotspot 2.0 connection with TTLS/CHAP"""
553     eap_test(dev[0], apdev[0], "21[2:2]", "TTLS", "chap user")
554
555 def test_ap_hs20_eap_ttls_mschap(dev, apdev):
556     """Hotspot 2.0 connection with TTLS/MSCHAP"""
557     eap_test(dev[0], apdev[0], "21[2:3]", "TTLS", "mschap user")
558
559 def test_ap_hs20_eap_ttls_eap_mschapv2(dev, apdev):
560     """Hotspot 2.0 connection with TTLS/EAP-MSCHAPv2"""
561     eap_test(dev[0], apdev[0], "21[3:26][6:7][99:99]", "TTLS", "user")
562
563 def test_ap_hs20_eap_ttls_eap_unknown(dev, apdev):
564     """Hotspot 2.0 connection with TTLS/EAP-unknown"""
565     bssid = apdev[0]['bssid']
566     params = hs20_ap_params()
567     params['nai_realm'] = "0,example.com,21[3:99]"
568     hostapd.add_ap(apdev[0]['ifname'], params)
569
570     dev[0].hs20_enable()
571     dev[0].add_cred_values(default_cred())
572     interworking_select(dev[0], None, no_match=True, freq="2412")
573
574 def test_ap_hs20_eap_ttls_eap_unsupported(dev, apdev):
575     """Hotspot 2.0 connection with TTLS/EAP-OTP(unsupported)"""
576     bssid = apdev[0]['bssid']
577     params = hs20_ap_params()
578     params['nai_realm'] = "0,example.com,21[3:5]"
579     hostapd.add_ap(apdev[0]['ifname'], params)
580
581     dev[0].hs20_enable()
582     dev[0].add_cred_values(default_cred())
583     interworking_select(dev[0], None, no_match=True, freq="2412")
584
585 def test_ap_hs20_eap_ttls_unknown(dev, apdev):
586     """Hotspot 2.0 connection with TTLS/unknown"""
587     bssid = apdev[0]['bssid']
588     params = hs20_ap_params()
589     params['nai_realm'] = "0,example.com,21[2:5]"
590     hostapd.add_ap(apdev[0]['ifname'], params)
591
592     dev[0].hs20_enable()
593     dev[0].add_cred_values(default_cred())
594     interworking_select(dev[0], None, no_match=True, freq="2412")
595
596 def test_ap_hs20_eap_fast_mschapv2(dev, apdev):
597     """Hotspot 2.0 connection with FAST/EAP-MSCHAPV2"""
598     eap_test(dev[0], apdev[0], "43[3:26]", "FAST", "user")
599
600 def test_ap_hs20_eap_fast_gtc(dev, apdev):
601     """Hotspot 2.0 connection with FAST/EAP-GTC"""
602     eap_test(dev[0], apdev[0], "43[3:6]", "FAST", "user")
603
604 def test_ap_hs20_eap_tls(dev, apdev):
605     """Hotspot 2.0 connection with EAP-TLS"""
606     bssid = apdev[0]['bssid']
607     params = hs20_ap_params()
608     params['nai_realm'] = [ "0,example.com,13[5:6]" ]
609     hostapd.add_ap(apdev[0]['ifname'], params)
610
611     dev[0].hs20_enable()
612     dev[0].add_cred_values({ 'realm': "example.com",
613                              'username': "certificate-user",
614                              'ca_cert': "auth_serv/ca.pem",
615                              'client_cert': "auth_serv/user.pem",
616                              'private_key': "auth_serv/user.key"})
617     interworking_select(dev[0], bssid, freq="2412")
618     interworking_connect(dev[0], bssid, "TLS")
619
620 def test_ap_hs20_eap_cert_unknown(dev, apdev):
621     """Hotspot 2.0 connection with certificate, but unknown EAP method"""
622     bssid = apdev[0]['bssid']
623     params = hs20_ap_params()
624     params['nai_realm'] = [ "0,example.com,99[5:6]" ]
625     hostapd.add_ap(apdev[0]['ifname'], params)
626
627     dev[0].hs20_enable()
628     dev[0].add_cred_values({ 'realm': "example.com",
629                              'username': "certificate-user",
630                              'ca_cert': "auth_serv/ca.pem",
631                              'client_cert': "auth_serv/user.pem",
632                              'private_key': "auth_serv/user.key"})
633     interworking_select(dev[0], None, no_match=True, freq="2412")
634
635 def test_ap_hs20_eap_cert_unsupported(dev, apdev):
636     """Hotspot 2.0 connection with certificate, but unsupported TTLS"""
637     bssid = apdev[0]['bssid']
638     params = hs20_ap_params()
639     params['nai_realm'] = [ "0,example.com,21[5:6]" ]
640     hostapd.add_ap(apdev[0]['ifname'], params)
641
642     dev[0].hs20_enable()
643     dev[0].add_cred_values({ 'realm': "example.com",
644                              'username': "certificate-user",
645                              'ca_cert': "auth_serv/ca.pem",
646                              'client_cert': "auth_serv/user.pem",
647                              'private_key': "auth_serv/user.key"})
648     interworking_select(dev[0], None, no_match=True, freq="2412")
649
650 def test_ap_hs20_eap_invalid_cred(dev, apdev):
651     """Hotspot 2.0 connection with invalid cred configuration"""
652     bssid = apdev[0]['bssid']
653     params = hs20_ap_params()
654     hostapd.add_ap(apdev[0]['ifname'], params)
655
656     dev[0].hs20_enable()
657     dev[0].add_cred_values({ 'realm': "example.com",
658                              'username': "certificate-user",
659                              'client_cert': "auth_serv/user.pem" })
660     interworking_select(dev[0], None, no_match=True, freq="2412")
661
662 def test_ap_hs20_nai_realms(dev, apdev):
663     """Hotspot 2.0 connection and multiple NAI realms and TTLS/PAP"""
664     bssid = apdev[0]['bssid']
665     params = hs20_ap_params()
666     params['hessid'] = bssid
667     params['nai_realm'] = [ "0,no.match.here;example.com;no.match.here.either,21[2:1][5:7]" ]
668     hostapd.add_ap(apdev[0]['ifname'], params)
669
670     dev[0].hs20_enable()
671     id = dev[0].add_cred_values({ 'realm': "example.com",
672                                   'username': "pap user",
673                                   'password': "password",
674                                   'domain': "example.com" })
675     interworking_select(dev[0], bssid, "home", freq="2412")
676     interworking_connect(dev[0], bssid, "TTLS")
677     check_sp_type(dev[0], "home")
678
679 def test_ap_hs20_roaming_consortium(dev, apdev):
680     """Hotspot 2.0 connection based on roaming consortium match"""
681     bssid = apdev[0]['bssid']
682     params = hs20_ap_params()
683     params['hessid'] = bssid
684     hostapd.add_ap(apdev[0]['ifname'], params)
685
686     dev[0].hs20_enable()
687     for consortium in [ "112233", "1020304050", "010203040506", "fedcba" ]:
688         id = dev[0].add_cred_values({ 'username': "user",
689                                       'password': "password",
690                                       'domain': "example.com",
691                                       'roaming_consortium': consortium,
692                                       'eap': "PEAP" })
693         interworking_select(dev[0], bssid, "home", freq="2412")
694         interworking_connect(dev[0], bssid, "PEAP")
695         check_sp_type(dev[0], "home")
696         dev[0].request("INTERWORKING_SELECT auto freq=2412")
697         ev = dev[0].wait_event(["INTERWORKING-ALREADY-CONNECTED"], timeout=15)
698         if ev is None:
699             raise Exception("Timeout on already-connected event")
700         dev[0].remove_cred(id)
701
702 def test_ap_hs20_username_roaming(dev, apdev):
703     """Hotspot 2.0 connection in username/password credential (roaming)"""
704     bssid = apdev[0]['bssid']
705     params = hs20_ap_params()
706     params['nai_realm'] = [ "0,example.com,13[5:6],21[2:4][5:7]",
707                             "0,roaming.example.com,21[2:4][5:7]",
708                             "0,another.example.com" ]
709     params['domain_name'] = "another.example.com"
710     params['hessid'] = bssid
711     hostapd.add_ap(apdev[0]['ifname'], params)
712
713     dev[0].hs20_enable()
714     id = dev[0].add_cred_values({ 'realm': "roaming.example.com",
715                                   'username': "hs20-test",
716                                   'password': "password",
717                                   'domain': "example.com" })
718     interworking_select(dev[0], bssid, "roaming", freq="2412")
719     interworking_connect(dev[0], bssid, "TTLS")
720     check_sp_type(dev[0], "roaming")
721
722 def test_ap_hs20_username_unknown(dev, apdev):
723     """Hotspot 2.0 connection in username/password credential (no domain in cred)"""
724     bssid = apdev[0]['bssid']
725     params = hs20_ap_params()
726     params['hessid'] = bssid
727     hostapd.add_ap(apdev[0]['ifname'], params)
728
729     dev[0].hs20_enable()
730     id = dev[0].add_cred_values({ 'realm': "example.com",
731                                   'username': "hs20-test",
732                                   'password': "password" })
733     interworking_select(dev[0], bssid, "unknown", freq="2412")
734     interworking_connect(dev[0], bssid, "TTLS")
735     check_sp_type(dev[0], "unknown")
736
737 def test_ap_hs20_username_unknown2(dev, apdev):
738     """Hotspot 2.0 connection in username/password credential (no domain advertized)"""
739     bssid = apdev[0]['bssid']
740     params = hs20_ap_params()
741     params['hessid'] = bssid
742     del params['domain_name']
743     hostapd.add_ap(apdev[0]['ifname'], params)
744
745     dev[0].hs20_enable()
746     id = dev[0].add_cred_values({ 'realm': "example.com",
747                                   'username': "hs20-test",
748                                   'password': "password",
749                                   'domain': "example.com" })
750     interworking_select(dev[0], bssid, "unknown", freq="2412")
751     interworking_connect(dev[0], bssid, "TTLS")
752     check_sp_type(dev[0], "unknown")
753
754 def test_ap_hs20_gas_while_associated(dev, apdev):
755     """Hotspot 2.0 connection with GAS query while associated"""
756     bssid = apdev[0]['bssid']
757     params = hs20_ap_params()
758     params['hessid'] = bssid
759     hostapd.add_ap(apdev[0]['ifname'], params)
760
761     dev[0].hs20_enable()
762     id = dev[0].add_cred_values({ 'realm': "example.com",
763                                   'username': "hs20-test",
764                                   'password': "password",
765                                   'domain': "example.com" })
766     interworking_select(dev[0], bssid, "home", freq="2412")
767     interworking_connect(dev[0], bssid, "TTLS")
768
769     logger.info("Verifying GAS query while associated")
770     dev[0].request("FETCH_ANQP")
771     for i in range(0, 6):
772         ev = dev[0].wait_event(["RX-ANQP"], timeout=5)
773         if ev is None:
774             raise Exception("Operation timed out")
775
776 def test_ap_hs20_gas_while_associated_with_pmf(dev, apdev):
777     """Hotspot 2.0 connection with GAS query while associated and using PMF"""
778     bssid = apdev[0]['bssid']
779     params = hs20_ap_params()
780     params['hessid'] = bssid
781     hostapd.add_ap(apdev[0]['ifname'], params)
782
783     bssid2 = apdev[1]['bssid']
784     params = hs20_ap_params()
785     params['hessid'] = bssid2
786     params['nai_realm'] = [ "0,no-match.example.org,13[5:6],21[2:4][5:7]" ]
787     hostapd.add_ap(apdev[1]['ifname'], params)
788
789     dev[0].hs20_enable()
790     dev[0].request("SET pmf 2")
791     id = dev[0].add_cred_values({ 'realm': "example.com",
792                                   'username': "hs20-test",
793                                   'password': "password",
794                                   'domain': "example.com" })
795     interworking_select(dev[0], bssid, "home", freq="2412")
796     interworking_connect(dev[0], bssid, "TTLS")
797
798     logger.info("Verifying GAS query while associated")
799     dev[0].request("FETCH_ANQP")
800     for i in range(0, 2 * 6):
801         ev = dev[0].wait_event(["RX-ANQP"], timeout=5)
802         if ev is None:
803             raise Exception("Operation timed out")
804
805 def test_ap_hs20_gas_frag_while_associated(dev, apdev):
806     """Hotspot 2.0 connection with fragmented GAS query while associated"""
807     bssid = apdev[0]['bssid']
808     params = hs20_ap_params()
809     params['hessid'] = bssid
810     hostapd.add_ap(apdev[0]['ifname'], params)
811     hapd = hostapd.Hostapd(apdev[0]['ifname'])
812     hapd.set("gas_frag_limit", "50")
813
814     dev[0].hs20_enable()
815     id = dev[0].add_cred_values({ 'realm': "example.com",
816                                   'username': "hs20-test",
817                                   'password': "password",
818                                   'domain': "example.com" })
819     interworking_select(dev[0], bssid, "home", freq="2412")
820     interworking_connect(dev[0], bssid, "TTLS")
821
822     logger.info("Verifying GAS query while associated")
823     dev[0].request("FETCH_ANQP")
824     for i in range(0, 6):
825         ev = dev[0].wait_event(["RX-ANQP"], timeout=5)
826         if ev is None:
827             raise Exception("Operation timed out")
828
829 def test_ap_hs20_multiple_connects(dev, apdev):
830     """Hotspot 2.0 connection through multiple network selections"""
831     bssid = apdev[0]['bssid']
832     params = hs20_ap_params()
833     params['hessid'] = bssid
834     hostapd.add_ap(apdev[0]['ifname'], params)
835
836     dev[0].hs20_enable()
837     values = { 'realm': "example.com",
838                'username': "hs20-test",
839                'password': "password",
840                'domain': "example.com" }
841     id = dev[0].add_cred_values(values)
842
843     dev[0].scan_for_bss(bssid, freq="2412")
844
845     for i in range(0, 3):
846         logger.info("Starting Interworking network selection")
847         dev[0].request("INTERWORKING_SELECT auto freq=2412")
848         while True:
849             ev = dev[0].wait_event(["INTERWORKING-NO-MATCH",
850                                     "INTERWORKING-ALREADY-CONNECTED",
851                                     "CTRL-EVENT-CONNECTED"], timeout=15)
852             if ev is None:
853                 raise Exception("Connection timed out")
854             if "INTERWORKING-NO-MATCH" in ev:
855                 raise Exception("Matching AP not found")
856             if "CTRL-EVENT-CONNECTED" in ev:
857                 break
858             if i == 2 and "INTERWORKING-ALREADY-CONNECTED" in ev:
859                 break
860         if i == 0:
861             dev[0].request("DISCONNECT")
862         dev[0].dump_monitor()
863
864     networks = dev[0].list_networks()
865     if len(networks) > 1:
866         raise Exception("Duplicated network block detected")
867
868 def test_ap_hs20_disallow_aps(dev, apdev):
869     """Hotspot 2.0 connection and disallow_aps"""
870     bssid = apdev[0]['bssid']
871     params = hs20_ap_params()
872     params['hessid'] = bssid
873     hostapd.add_ap(apdev[0]['ifname'], params)
874
875     dev[0].hs20_enable()
876     values = { 'realm': "example.com",
877                'username': "hs20-test",
878                'password': "password",
879                'domain': "example.com" }
880     id = dev[0].add_cred_values(values)
881
882     dev[0].scan_for_bss(bssid, freq="2412")
883
884     logger.info("Verify disallow_aps bssid")
885     dev[0].request("SET disallow_aps bssid " + bssid.translate(None, ':'))
886     dev[0].request("INTERWORKING_SELECT auto")
887     ev = dev[0].wait_event(["INTERWORKING-NO-MATCH"], timeout=15)
888     if ev is None:
889         raise Exception("Network selection timed out")
890     dev[0].dump_monitor()
891
892     logger.info("Verify disallow_aps ssid")
893     dev[0].request("SET disallow_aps ssid 746573742d68733230")
894     dev[0].request("INTERWORKING_SELECT auto freq=2412")
895     ev = dev[0].wait_event(["INTERWORKING-NO-MATCH"], timeout=15)
896     if ev is None:
897         raise Exception("Network selection timed out")
898     dev[0].dump_monitor()
899
900     logger.info("Verify disallow_aps clear")
901     dev[0].request("SET disallow_aps ")
902     interworking_select(dev[0], bssid, "home", freq="2412")
903
904     dev[0].request("SET disallow_aps bssid " + bssid.translate(None, ':'))
905     ret = dev[0].request("INTERWORKING_CONNECT " + bssid)
906     if "FAIL" not in ret:
907         raise Exception("INTERWORKING_CONNECT to disallowed BSS not rejected")
908
909 def policy_test(dev, ap, values, only_one=True):
910     dev.dump_monitor()
911     if ap:
912         logger.info("Verify network selection to AP " + ap['ifname'])
913         bssid = ap['bssid']
914         dev.scan_for_bss(bssid, freq="2412")
915     else:
916         logger.info("Verify network selection")
917         bssid = None
918     dev.hs20_enable()
919     id = dev.add_cred_values(values)
920     dev.request("INTERWORKING_SELECT auto freq=2412")
921     events = []
922     while True:
923         ev = dev.wait_event(["INTERWORKING-AP", "INTERWORKING-NO-MATCH",
924                              "INTERWORKING-BLACKLISTED",
925                              "INTERWORKING-SELECTED"], timeout=15)
926         if ev is None:
927             raise Exception("Network selection timed out")
928         events.append(ev)
929         if "INTERWORKING-NO-MATCH" in ev:
930             raise Exception("Matching AP not found")
931         if bssid and only_one and "INTERWORKING-AP" in ev and bssid not in ev:
932             raise Exception("Unexpected AP claimed acceptable")
933         if "INTERWORKING-SELECTED" in ev:
934             if bssid and bssid not in ev:
935                 raise Exception("Selected incorrect BSS")
936             break
937
938     ev = dev.wait_event(["CTRL-EVENT-CONNECTED"], timeout=15)
939     if ev is None:
940         raise Exception("Connection timed out")
941     if bssid and bssid not in ev:
942         raise Exception("Connected to incorrect BSS")
943
944     conn_bssid = dev.get_status_field("bssid")
945     if bssid and conn_bssid != bssid:
946         raise Exception("bssid information points to incorrect BSS")
947
948     dev.remove_cred(id)
949     dev.dump_monitor()
950     return events
951
952 def default_cred(domain=None):
953     cred = { 'realm': "example.com",
954              'username': "hs20-test",
955              'password': "password" }
956     if domain:
957         cred['domain'] = domain
958     return cred
959
960 def test_ap_hs20_prefer_home(dev, apdev):
961     """Hotspot 2.0 required roaming consortium"""
962     params = hs20_ap_params()
963     params['domain_name'] = "example.org"
964     hostapd.add_ap(apdev[0]['ifname'], params)
965
966     params = hs20_ap_params()
967     params['ssid'] = "test-hs20-other"
968     params['domain_name'] = "example.com"
969     hostapd.add_ap(apdev[1]['ifname'], params)
970
971     values = default_cred()
972     values['domain'] = "example.com"
973     policy_test(dev[0], apdev[1], values, only_one=False)
974     values['domain'] = "example.org"
975     policy_test(dev[0], apdev[0], values, only_one=False)
976
977 def test_ap_hs20_req_roaming_consortium(dev, apdev):
978     """Hotspot 2.0 required roaming consortium"""
979     params = hs20_ap_params()
980     hostapd.add_ap(apdev[0]['ifname'], params)
981
982     params = hs20_ap_params()
983     params['ssid'] = "test-hs20-other"
984     params['roaming_consortium'] = [ "223344" ]
985     hostapd.add_ap(apdev[1]['ifname'], params)
986
987     values = default_cred()
988     values['required_roaming_consortium'] = "223344"
989     policy_test(dev[0], apdev[1], values)
990     values['required_roaming_consortium'] = "112233"
991     policy_test(dev[0], apdev[0], values)
992
993     id = dev[0].add_cred()
994     dev[0].set_cred(id, "required_roaming_consortium", "112233")
995     dev[0].set_cred(id, "required_roaming_consortium", "112233445566778899aabbccddeeff")
996
997     for val in [ "", "1", "11", "1122", "1122334", "112233445566778899aabbccddeeff00" ]:
998         if "FAIL" not in dev[0].request('SET_CRED {} required_roaming_consortium {}'.format(id, val)):
999             raise Exception("Invalid roaming consortium value accepted: " + val)
1000
1001 def test_ap_hs20_excluded_ssid(dev, apdev):
1002     """Hotspot 2.0 exclusion based on SSID"""
1003     params = hs20_ap_params()
1004     params['roaming_consortium'] = [ "223344" ]
1005     params['anqp_3gpp_cell_net'] = "555,444"
1006     hostapd.add_ap(apdev[0]['ifname'], params)
1007
1008     params = hs20_ap_params()
1009     params['ssid'] = "test-hs20-other"
1010     params['roaming_consortium'] = [ "223344" ]
1011     params['anqp_3gpp_cell_net'] = "555,444"
1012     hostapd.add_ap(apdev[1]['ifname'], params)
1013
1014     values = default_cred()
1015     values['excluded_ssid'] = "test-hs20"
1016     events = policy_test(dev[0], apdev[1], values)
1017     ev = [e for e in events if "INTERWORKING-BLACKLISTED " + apdev[0]['bssid'] in e]
1018     if len(ev) != 1:
1019         raise Exception("Excluded network not reported")
1020     values['excluded_ssid'] = "test-hs20-other"
1021     events = policy_test(dev[0], apdev[0], values)
1022     ev = [e for e in events if "INTERWORKING-BLACKLISTED " + apdev[1]['bssid'] in e]
1023     if len(ev) != 1:
1024         raise Exception("Excluded network not reported")
1025
1026     values = default_cred()
1027     values['roaming_consortium'] = "223344"
1028     values['eap'] = "TTLS"
1029     values['phase2'] = "auth=MSCHAPV2"
1030     values['excluded_ssid'] = "test-hs20"
1031     events = policy_test(dev[0], apdev[1], values)
1032     ev = [e for e in events if "INTERWORKING-BLACKLISTED " + apdev[0]['bssid'] in e]
1033     if len(ev) != 1:
1034         raise Exception("Excluded network not reported")
1035
1036     values = { 'imsi': "555444-333222111", 'eap': "SIM",
1037                'milenage': "5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123",
1038                'excluded_ssid': "test-hs20" }
1039     events = policy_test(dev[0], apdev[1], values)
1040     ev = [e for e in events if "INTERWORKING-BLACKLISTED " + apdev[0]['bssid'] in e]
1041     if len(ev) != 1:
1042         raise Exception("Excluded network not reported")
1043
1044 def test_ap_hs20_roam_to_higher_prio(dev, apdev):
1045     """Hotspot 2.0 and roaming from current to higher priority network"""
1046     bssid = apdev[0]['bssid']
1047     params = hs20_ap_params(ssid="test-hs20-visited")
1048     params['domain_name'] = "visited.example.org"
1049     hostapd.add_ap(apdev[0]['ifname'], params)
1050
1051     dev[0].hs20_enable()
1052     id = dev[0].add_cred_values({ 'realm': "example.com",
1053                                   'username': "hs20-test",
1054                                   'password': "password",
1055                                   'domain': "example.com" })
1056     logger.info("Connect to the only network option")
1057     interworking_select(dev[0], bssid, "roaming", freq="2412")
1058     dev[0].dump_monitor()
1059     interworking_connect(dev[0], bssid, "TTLS")
1060
1061     logger.info("Start another AP (home operator) and reconnect")
1062     bssid2 = apdev[1]['bssid']
1063     params = hs20_ap_params(ssid="test-hs20-home")
1064     params['domain_name'] = "example.com"
1065     hostapd.add_ap(apdev[1]['ifname'], params)
1066
1067     dev[0].scan_for_bss(bssid2, freq="2412", force_scan=True)
1068     dev[0].request("INTERWORKING_SELECT auto freq=2412")
1069     ev = dev[0].wait_event(["INTERWORKING-NO-MATCH",
1070                             "INTERWORKING-ALREADY-CONNECTED",
1071                             "CTRL-EVENT-CONNECTED"], timeout=15)
1072     if ev is None:
1073         raise Exception("Connection timed out")
1074     if "INTERWORKING-NO-MATCH" in ev:
1075         raise Exception("Matching AP not found")
1076     if "INTERWORKING-ALREADY-CONNECTED" in ev:
1077         raise Exception("Unexpected AP selected")
1078     if bssid2 not in ev:
1079         raise Exception("Unexpected BSSID after reconnection")
1080
1081 def test_ap_hs20_domain_suffix_match(dev, apdev):
1082     """Hotspot 2.0 and domain_suffix_match"""
1083     bssid = apdev[0]['bssid']
1084     params = hs20_ap_params()
1085     hostapd.add_ap(apdev[0]['ifname'], params)
1086
1087     dev[0].hs20_enable()
1088     id = dev[0].add_cred_values({ 'realm': "example.com",
1089                                   'username': "hs20-test",
1090                                   'password': "password",
1091                                   'domain': "example.com",
1092                                   'domain_suffix_match': "w1.fi" })
1093     interworking_select(dev[0], bssid, "home", freq="2412")
1094     dev[0].dump_monitor()
1095     interworking_connect(dev[0], bssid, "TTLS")
1096     dev[0].request("REMOVE_NETWORK all")
1097     dev[0].dump_monitor()
1098
1099     dev[0].set_cred_quoted(id, "domain_suffix_match", "no-match.example.com")
1100     interworking_select(dev[0], bssid, "home", freq="2412")
1101     dev[0].dump_monitor()
1102     dev[0].request("INTERWORKING_CONNECT " + bssid)
1103     ev = dev[0].wait_event(["CTRL-EVENT-EAP-TLS-CERT-ERROR"])
1104     if ev is None:
1105         raise Exception("TLS certificate error not reported")
1106     if "Domain suffix mismatch" not in ev:
1107         raise Exception("Domain suffix mismatch not reported")
1108
1109 def test_ap_hs20_roaming_partner_preference(dev, apdev):
1110     """Hotspot 2.0 and roaming partner preference"""
1111     params = hs20_ap_params()
1112     params['domain_name'] = "roaming.example.org"
1113     hostapd.add_ap(apdev[0]['ifname'], params)
1114
1115     params = hs20_ap_params()
1116     params['ssid'] = "test-hs20-other"
1117     params['domain_name'] = "roaming.example.net"
1118     hostapd.add_ap(apdev[1]['ifname'], params)
1119
1120     logger.info("Verify default vs. specified preference")
1121     values = default_cred()
1122     values['roaming_partner'] = "roaming.example.net,1,127,*"
1123     policy_test(dev[0], apdev[1], values, only_one=False)
1124     values['roaming_partner'] = "roaming.example.net,1,129,*"
1125     policy_test(dev[0], apdev[0], values, only_one=False)
1126
1127     logger.info("Verify partial FQDN match")
1128     values['roaming_partner'] = "example.net,0,0,*"
1129     policy_test(dev[0], apdev[1], values, only_one=False)
1130     values['roaming_partner'] = "example.net,0,255,*"
1131     policy_test(dev[0], apdev[0], values, only_one=False)
1132
1133 def test_ap_hs20_max_bss_load(dev, apdev):
1134     """Hotspot 2.0 and maximum BSS load"""
1135     params = hs20_ap_params()
1136     params['bss_load_test'] = "12:200:20000"
1137     hostapd.add_ap(apdev[0]['ifname'], params)
1138
1139     params = hs20_ap_params()
1140     params['ssid'] = "test-hs20-other"
1141     params['bss_load_test'] = "5:20:10000"
1142     hostapd.add_ap(apdev[1]['ifname'], params)
1143
1144     logger.info("Verify maximum BSS load constraint")
1145     values = default_cred()
1146     values['domain'] = "example.com"
1147     values['max_bss_load'] = "100"
1148     events = policy_test(dev[0], apdev[1], values, only_one=False)
1149
1150     ev = [e for e in events if "INTERWORKING-AP " + apdev[0]['bssid'] in e]
1151     if len(ev) != 1 or "over_max_bss_load=1" not in ev[0]:
1152         raise Exception("Maximum BSS Load case not noticed")
1153     ev = [e for e in events if "INTERWORKING-AP " + apdev[1]['bssid'] in e]
1154     if len(ev) != 1 or "over_max_bss_load=1" in ev[0]:
1155         raise Exception("Maximum BSS Load case reported incorrectly")
1156
1157     logger.info("Verify maximum BSS load does not prevent connection")
1158     values['max_bss_load'] = "1"
1159     events = policy_test(dev[0], None, values)
1160
1161     ev = [e for e in events if "INTERWORKING-AP " + apdev[0]['bssid'] in e]
1162     if len(ev) != 1 or "over_max_bss_load=1" not in ev[0]:
1163         raise Exception("Maximum BSS Load case not noticed")
1164     ev = [e for e in events if "INTERWORKING-AP " + apdev[1]['bssid'] in e]
1165     if len(ev) != 1 or "over_max_bss_load=1" not in ev[0]:
1166         raise Exception("Maximum BSS Load case not noticed")
1167
1168 def test_ap_hs20_max_bss_load2(dev, apdev):
1169     """Hotspot 2.0 and maximum BSS load with one AP not advertising"""
1170     params = hs20_ap_params()
1171     params['bss_load_test'] = "12:200:20000"
1172     hostapd.add_ap(apdev[0]['ifname'], params)
1173
1174     params = hs20_ap_params()
1175     params['ssid'] = "test-hs20-other"
1176     hostapd.add_ap(apdev[1]['ifname'], params)
1177
1178     logger.info("Verify maximum BSS load constraint with AP advertisement")
1179     values = default_cred()
1180     values['domain'] = "example.com"
1181     values['max_bss_load'] = "100"
1182     events = policy_test(dev[0], apdev[1], values, only_one=False)
1183
1184     ev = [e for e in events if "INTERWORKING-AP " + apdev[0]['bssid'] in e]
1185     if len(ev) != 1 or "over_max_bss_load=1" not in ev[0]:
1186         raise Exception("Maximum BSS Load case not noticed")
1187     ev = [e for e in events if "INTERWORKING-AP " + apdev[1]['bssid'] in e]
1188     if len(ev) != 1 or "over_max_bss_load=1" in ev[0]:
1189         raise Exception("Maximum BSS Load case reported incorrectly")
1190
1191 def test_ap_hs20_multi_cred_sp_prio(dev, apdev):
1192     """Hotspot 2.0 multi-cred sp_priority"""
1193     if not hlr_auc_gw_available():
1194         return "skip"
1195     bssid = apdev[0]['bssid']
1196     params = hs20_ap_params()
1197     params['hessid'] = bssid
1198     del params['domain_name']
1199     params['anqp_3gpp_cell_net'] = "232,01"
1200     hostapd.add_ap(apdev[0]['ifname'], params)
1201
1202     dev[0].hs20_enable()
1203     dev[0].request("SET external_sim 1")
1204     id1 = dev[0].add_cred_values({ 'imsi': "23201-0000000000", 'eap': "SIM",
1205                                    'provisioning_sp': "example.com",
1206                                    'sp_priority' :"1" })
1207     id2 = dev[0].add_cred_values({ 'realm': "example.com",
1208                                    'username': "hs20-test",
1209                                    'password': "password",
1210                                    'domain': "example.com",
1211                                    'provisioning_sp': "example.com",
1212                                    'sp_priority': "2" })
1213     dev[0].dump_monitor()
1214     dev[0].request("INTERWORKING_SELECT auto freq=2412")
1215     interworking_ext_sim_auth(dev[0], "SIM")
1216     check_sp_type(dev[0], "unknown")
1217     dev[0].request("REMOVE_NETWORK all")
1218
1219     dev[0].set_cred(id1, "sp_priority", "2")
1220     dev[0].set_cred(id2, "sp_priority", "1")
1221     dev[0].dump_monitor()
1222     dev[0].request("INTERWORKING_SELECT auto freq=2412")
1223     interworking_auth(dev[0], "TTLS")
1224     check_sp_type(dev[0], "unknown")
1225
1226 def test_ap_hs20_multi_cred_sp_prio2(dev, apdev):
1227     """Hotspot 2.0 multi-cred sp_priority with two BSSes"""
1228     if not hlr_auc_gw_available():
1229         return "skip"
1230     bssid = apdev[0]['bssid']
1231     params = hs20_ap_params()
1232     params['hessid'] = bssid
1233     del params['nai_realm']
1234     del params['domain_name']
1235     params['anqp_3gpp_cell_net'] = "232,01"
1236     hostapd.add_ap(apdev[0]['ifname'], params)
1237
1238     bssid2 = apdev[1]['bssid']
1239     params = hs20_ap_params()
1240     params['ssid'] = "test-hs20-other"
1241     params['hessid'] = bssid2
1242     del params['domain_name']
1243     del params['anqp_3gpp_cell_net']
1244     hostapd.add_ap(apdev[1]['ifname'], params)
1245
1246     dev[0].hs20_enable()
1247     dev[0].request("SET external_sim 1")
1248     id1 = dev[0].add_cred_values({ 'imsi': "23201-0000000000", 'eap': "SIM",
1249                                    'provisioning_sp': "example.com",
1250                                    'sp_priority': "1" })
1251     id2 = dev[0].add_cred_values({ 'realm': "example.com",
1252                                    'username': "hs20-test",
1253                                    'password': "password",
1254                                    'domain': "example.com",
1255                                    'provisioning_sp': "example.com",
1256                                    'sp_priority': "2" })
1257     dev[0].dump_monitor()
1258     dev[0].request("INTERWORKING_SELECT auto freq=2412")
1259     interworking_ext_sim_auth(dev[0], "SIM")
1260     check_sp_type(dev[0], "unknown")
1261     conn_bssid = dev[0].get_status_field("bssid")
1262     if conn_bssid != bssid:
1263         raise Exception("Connected to incorrect BSS")
1264     dev[0].request("REMOVE_NETWORK all")
1265
1266     dev[0].set_cred(id1, "sp_priority", "2")
1267     dev[0].set_cred(id2, "sp_priority", "1")
1268     dev[0].dump_monitor()
1269     dev[0].request("INTERWORKING_SELECT auto freq=2412")
1270     interworking_auth(dev[0], "TTLS")
1271     check_sp_type(dev[0], "unknown")
1272     conn_bssid = dev[0].get_status_field("bssid")
1273     if conn_bssid != bssid2:
1274         raise Exception("Connected to incorrect BSS")
1275
1276 def check_conn_capab_selection(dev, type, missing):
1277     dev.request("INTERWORKING_SELECT freq=2412")
1278     ev = dev.wait_event(["INTERWORKING-AP"])
1279     if ev is None:
1280         raise Exception("Network selection timed out");
1281     if "type=" + type not in ev:
1282         raise Exception("Unexpected network type")
1283     if missing and "conn_capab_missing=1" not in ev:
1284         raise Exception("conn_capab_missing not reported")
1285     if not missing and "conn_capab_missing=1" in ev:
1286         raise Exception("conn_capab_missing reported unexpectedly")
1287
1288 def conn_capab_cred(domain=None, req_conn_capab=None):
1289     cred = default_cred(domain=domain)
1290     if req_conn_capab:
1291         cred['req_conn_capab'] = req_conn_capab
1292     return cred
1293
1294 def test_ap_hs20_req_conn_capab(dev, apdev):
1295     """Hotspot 2.0 network selection with req_conn_capab"""
1296     bssid = apdev[0]['bssid']
1297     params = hs20_ap_params()
1298     hostapd.add_ap(apdev[0]['ifname'], params)
1299
1300     dev[0].hs20_enable()
1301     logger.info("Not used in home network")
1302     values = conn_capab_cred(domain="example.com", req_conn_capab="6:1234")
1303     id = dev[0].add_cred_values(values)
1304     check_conn_capab_selection(dev[0], "home", False)
1305
1306     logger.info("Used in roaming network")
1307     dev[0].remove_cred(id)
1308     values = conn_capab_cred(domain="example.org", req_conn_capab="6:1234")
1309     id = dev[0].add_cred_values(values)
1310     check_conn_capab_selection(dev[0], "roaming", True)
1311
1312     logger.info("Verify that req_conn_capab does not prevent connection if no other network is available")
1313     check_auto_select(dev[0], bssid)
1314
1315     logger.info("Additional req_conn_capab checks")
1316
1317     dev[0].remove_cred(id)
1318     values = conn_capab_cred(domain="example.org", req_conn_capab="1:0")
1319     id = dev[0].add_cred_values(values)
1320     check_conn_capab_selection(dev[0], "roaming", True)
1321
1322     dev[0].remove_cred(id)
1323     values = conn_capab_cred(domain="example.org", req_conn_capab="17:5060")
1324     id = dev[0].add_cred_values(values)
1325     check_conn_capab_selection(dev[0], "roaming", True)
1326
1327     bssid2 = apdev[1]['bssid']
1328     params = hs20_ap_params(ssid="test-hs20b")
1329     params['hs20_conn_capab'] = [ "1:0:2", "6:22:1", "17:5060:0", "50:0:1" ]
1330     hostapd.add_ap(apdev[1]['ifname'], params)
1331
1332     dev[0].remove_cred(id)
1333     values = conn_capab_cred(domain="example.org", req_conn_capab="50")
1334     id = dev[0].add_cred_values(values)
1335     dev[0].set_cred(id, "req_conn_capab", "6:22")
1336     dev[0].scan_for_bss(bssid2, freq="2412")
1337     dev[0].request("INTERWORKING_SELECT freq=2412")
1338     for i in range(0, 2):
1339         ev = dev[0].wait_event(["INTERWORKING-AP"])
1340         if ev is None:
1341             raise Exception("Network selection timed out");
1342         if bssid in ev and "conn_capab_missing=1" not in ev:
1343             raise Exception("Missing protocol connection capability not reported")
1344         if bssid2 in ev and "conn_capab_missing=1" in ev:
1345             raise Exception("Protocol connection capability not reported correctly")
1346
1347 def test_ap_hs20_req_conn_capab_and_roaming_partner_preference(dev, apdev):
1348     """Hotspot 2.0 and req_conn_capab with roaming partner preference"""
1349     bssid = apdev[0]['bssid']
1350     params = hs20_ap_params()
1351     params['domain_name'] = "roaming.example.org"
1352     params['hs20_conn_capab'] = [ "1:0:2", "6:22:1", "17:5060:0", "50:0:1" ]
1353     hostapd.add_ap(apdev[0]['ifname'], params)
1354
1355     bssid2 = apdev[1]['bssid']
1356     params = hs20_ap_params(ssid="test-hs20-b")
1357     params['domain_name'] = "roaming.example.net"
1358     hostapd.add_ap(apdev[1]['ifname'], params)
1359
1360     values = default_cred()
1361     values['roaming_partner'] = "roaming.example.net,1,127,*"
1362     id = dev[0].add_cred_values(values)
1363     check_auto_select(dev[0], bssid2)
1364
1365     dev[0].set_cred(id, "req_conn_capab", "50")
1366     check_auto_select(dev[0], bssid)
1367
1368     dev[0].remove_cred(id)
1369     id = dev[0].add_cred_values(values)
1370     dev[0].set_cred(id, "req_conn_capab", "51")
1371     check_auto_select(dev[0], bssid2)
1372
1373 def check_bandwidth_selection(dev, type, below):
1374     dev.request("INTERWORKING_SELECT freq=2412")
1375     ev = dev.wait_event(["INTERWORKING-AP"])
1376     if ev is None:
1377         raise Exception("Network selection timed out");
1378     if "type=" + type not in ev:
1379         raise Exception("Unexpected network type")
1380     if below and "below_min_backhaul=1" not in ev:
1381         raise Exception("below_min_backhaul not reported")
1382     if not below and "below_min_backhaul=1" in ev:
1383         raise Exception("below_min_backhaul reported unexpectedly")
1384
1385 def bw_cred(domain=None, dl_home=None, ul_home=None, dl_roaming=None, ul_roaming=None):
1386     cred = default_cred(domain=domain)
1387     if dl_home:
1388         cred['min_dl_bandwidth_home'] = str(dl_home)
1389     if ul_home:
1390         cred['min_ul_bandwidth_home'] = str(ul_home)
1391     if dl_roaming:
1392         cred['min_dl_bandwidth_roaming'] = str(dl_roaming)
1393     if ul_roaming:
1394         cred['min_ul_bandwidth_roaming'] = str(ul_roaming)
1395     return cred
1396
1397 def test_ap_hs20_min_bandwidth_home(dev, apdev):
1398     """Hotspot 2.0 network selection with min bandwidth (home)"""
1399     bssid = apdev[0]['bssid']
1400     params = hs20_ap_params()
1401     hostapd.add_ap(apdev[0]['ifname'], params)
1402
1403     dev[0].hs20_enable()
1404     values = bw_cred(domain="example.com", dl_home=5490, ul_home=58)
1405     id = dev[0].add_cred_values(values)
1406     check_bandwidth_selection(dev[0], "home", False)
1407     dev[0].remove_cred(id)
1408
1409     values = bw_cred(domain="example.com", dl_home=5491, ul_home=58)
1410     id = dev[0].add_cred_values(values)
1411     check_bandwidth_selection(dev[0], "home", True)
1412     dev[0].remove_cred(id)
1413
1414     values = bw_cred(domain="example.com", dl_home=5490, ul_home=59)
1415     id = dev[0].add_cred_values(values)
1416     check_bandwidth_selection(dev[0], "home", True)
1417     dev[0].remove_cred(id)
1418
1419     values = bw_cred(domain="example.com", dl_home=5491, ul_home=59)
1420     id = dev[0].add_cred_values(values)
1421     check_bandwidth_selection(dev[0], "home", True)
1422     check_auto_select(dev[0], bssid)
1423
1424     bssid2 = apdev[1]['bssid']
1425     params = hs20_ap_params(ssid="test-hs20-b")
1426     params['hs20_wan_metrics'] = "01:8000:1000:1:1:3000"
1427     hostapd.add_ap(apdev[1]['ifname'], params)
1428
1429     check_auto_select(dev[0], bssid2)
1430
1431 def test_ap_hs20_min_bandwidth_roaming(dev, apdev):
1432     """Hotspot 2.0 network selection with min bandwidth (roaming)"""
1433     bssid = apdev[0]['bssid']
1434     params = hs20_ap_params()
1435     hostapd.add_ap(apdev[0]['ifname'], params)
1436
1437     dev[0].hs20_enable()
1438     values = bw_cred(domain="example.org", dl_roaming=5490, ul_roaming=58)
1439     id = dev[0].add_cred_values(values)
1440     check_bandwidth_selection(dev[0], "roaming", False)
1441     dev[0].remove_cred(id)
1442
1443     values = bw_cred(domain="example.org", dl_roaming=5491, ul_roaming=58)
1444     id = dev[0].add_cred_values(values)
1445     check_bandwidth_selection(dev[0], "roaming", True)
1446     dev[0].remove_cred(id)
1447
1448     values = bw_cred(domain="example.org", dl_roaming=5490, ul_roaming=59)
1449     id = dev[0].add_cred_values(values)
1450     check_bandwidth_selection(dev[0], "roaming", True)
1451     dev[0].remove_cred(id)
1452
1453     values = bw_cred(domain="example.org", dl_roaming=5491, ul_roaming=59)
1454     id = dev[0].add_cred_values(values)
1455     check_bandwidth_selection(dev[0], "roaming", True)
1456     check_auto_select(dev[0], bssid)
1457
1458     bssid2 = apdev[1]['bssid']
1459     params = hs20_ap_params(ssid="test-hs20-b")
1460     params['hs20_wan_metrics'] = "01:8000:1000:1:1:3000"
1461     hostapd.add_ap(apdev[1]['ifname'], params)
1462
1463     check_auto_select(dev[0], bssid2)
1464
1465 def test_ap_hs20_min_bandwidth_and_roaming_partner_preference(dev, apdev):
1466     """Hotspot 2.0 and minimum bandwidth with roaming partner preference"""
1467     bssid = apdev[0]['bssid']
1468     params = hs20_ap_params()
1469     params['domain_name'] = "roaming.example.org"
1470     params['hs20_wan_metrics'] = "01:8000:1000:1:1:3000"
1471     hostapd.add_ap(apdev[0]['ifname'], params)
1472
1473     bssid2 = apdev[1]['bssid']
1474     params = hs20_ap_params(ssid="test-hs20-b")
1475     params['domain_name'] = "roaming.example.net"
1476     hostapd.add_ap(apdev[1]['ifname'], params)
1477
1478     values = default_cred()
1479     values['roaming_partner'] = "roaming.example.net,1,127,*"
1480     id = dev[0].add_cred_values(values)
1481     check_auto_select(dev[0], bssid2)
1482
1483     dev[0].set_cred(id, "min_dl_bandwidth_roaming", "6000")
1484     check_auto_select(dev[0], bssid)
1485
1486     dev[0].set_cred(id, "min_dl_bandwidth_roaming", "10000")
1487     check_auto_select(dev[0], bssid2)
1488
1489 def test_ap_hs20_min_bandwidth_no_wan_metrics(dev, apdev):
1490     """Hotspot 2.0 network selection with min bandwidth but no WAN Metrics"""
1491     bssid = apdev[0]['bssid']
1492     params = hs20_ap_params()
1493     del params['hs20_wan_metrics']
1494     hostapd.add_ap(apdev[0]['ifname'], params)
1495
1496     dev[0].hs20_enable()
1497     values = bw_cred(domain="example.com", dl_home=10000, ul_home=10000,
1498                      dl_roaming=10000, ul_roaming=10000)
1499     dev[0].add_cred_values(values)
1500     check_bandwidth_selection(dev[0], "home", False)
1501
1502 def test_ap_hs20_deauth_req_ess(dev, apdev):
1503     """Hotspot 2.0 connection and deauthentication request for ESS"""
1504     dev[0].request("SET pmf 2")
1505     eap_test(dev[0], apdev[0], "21[3:26]", "TTLS", "user")
1506     dev[0].dump_monitor()
1507     addr = dev[0].p2p_interface_addr()
1508     hapd = hostapd.Hostapd(apdev[0]['ifname'])
1509     hapd.request("HS20_DEAUTH_REQ " + addr + " 1 120 http://example.com/")
1510     ev = dev[0].wait_event(["HS20-DEAUTH-IMMINENT-NOTICE"])
1511     if ev is None:
1512         raise Exception("Timeout on deauth imminent notice")
1513     if "1 120 http://example.com/" not in ev:
1514         raise Exception("Unexpected deauth imminent notice: " + ev)
1515     hapd.request("DEAUTHENTICATE " + addr)
1516     ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"])
1517     if ev is None:
1518         raise Exception("Timeout on disconnection")
1519     if "[TEMP-DISABLED]" not in dev[0].list_networks()[0]['flags']:
1520         raise Exception("Network not marked temporarily disabled")
1521     ev = dev[0].wait_event(["SME: Trying to authenticate",
1522                             "Trying to associate",
1523                             "CTRL-EVENT-CONNECTED"], timeout=5)
1524     if ev is not None:
1525         raise Exception("Unexpected connection attempt")
1526
1527 def test_ap_hs20_deauth_req_bss(dev, apdev):
1528     """Hotspot 2.0 connection and deauthentication request for BSS"""
1529     dev[0].request("SET pmf 2")
1530     eap_test(dev[0], apdev[0], "21[3:26]", "TTLS", "user")
1531     dev[0].dump_monitor()
1532     addr = dev[0].p2p_interface_addr()
1533     hapd = hostapd.Hostapd(apdev[0]['ifname'])
1534     hapd.request("HS20_DEAUTH_REQ " + addr + " 0 120 http://example.com/")
1535     ev = dev[0].wait_event(["HS20-DEAUTH-IMMINENT-NOTICE"])
1536     if ev is None:
1537         raise Exception("Timeout on deauth imminent notice")
1538     if "0 120 http://example.com/" not in ev:
1539         raise Exception("Unexpected deauth imminent notice: " + ev)
1540     hapd.request("DEAUTHENTICATE " + addr + " reason=4")
1541     ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"])
1542     if ev is None:
1543         raise Exception("Timeout on disconnection")
1544     if "reason=4" not in ev:
1545         raise Exception("Unexpected disconnection reason")
1546     if "[TEMP-DISABLED]" not in dev[0].list_networks()[0]['flags']:
1547         raise Exception("Network not marked temporarily disabled")
1548     ev = dev[0].wait_event(["SME: Trying to authenticate",
1549                             "Trying to associate",
1550                             "CTRL-EVENT-CONNECTED"], timeout=5)
1551     if ev is not None:
1552         raise Exception("Unexpected connection attempt")
1553
1554 def test_ap_hs20_deauth_req_from_radius(dev, apdev):
1555     """Hotspot 2.0 connection and deauthentication request from RADIUS"""
1556     bssid = apdev[0]['bssid']
1557     params = hs20_ap_params()
1558     params['nai_realm'] = [ "0,example.com,21[2:4]" ]
1559     params['hs20_deauth_req_timeout'] = "2"
1560     hostapd.add_ap(apdev[0]['ifname'], params)
1561
1562     dev[0].request("SET pmf 2")
1563     dev[0].hs20_enable()
1564     dev[0].add_cred_values({ 'realm': "example.com",
1565                              'username': "hs20-deauth-test",
1566                              'password': "password" })
1567     interworking_select(dev[0], bssid, freq="2412")
1568     interworking_connect(dev[0], bssid, "TTLS")
1569     ev = dev[0].wait_event(["HS20-DEAUTH-IMMINENT-NOTICE"], timeout=5)
1570     if ev is None:
1571         raise Exception("Timeout on deauth imminent notice")
1572     if " 1 100" not in ev:
1573         raise Exception("Unexpected deauth imminent contents")
1574     ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=3)
1575     if ev is None:
1576         raise Exception("Timeout on disconnection")
1577
1578 def test_ap_hs20_remediation_required(dev, apdev):
1579     """Hotspot 2.0 connection and remediation required from RADIUS"""
1580     bssid = apdev[0]['bssid']
1581     params = hs20_ap_params()
1582     params['nai_realm'] = [ "0,example.com,21[2:4]" ]
1583     hostapd.add_ap(apdev[0]['ifname'], params)
1584
1585     dev[0].request("SET pmf 1")
1586     dev[0].hs20_enable()
1587     dev[0].add_cred_values({ 'realm': "example.com",
1588                              'username': "hs20-subrem-test",
1589                              'password': "password" })
1590     interworking_select(dev[0], bssid, freq="2412")
1591     interworking_connect(dev[0], bssid, "TTLS")
1592     ev = dev[0].wait_event(["HS20-SUBSCRIPTION-REMEDIATION"], timeout=5)
1593     if ev is None:
1594         raise Exception("Timeout on subscription remediation notice")
1595     if " 1 https://example.com/" not in ev:
1596         raise Exception("Unexpected subscription remediation event contents")
1597
1598 def test_ap_hs20_remediation_required_ctrl(dev, apdev):
1599     """Hotspot 2.0 connection and subrem from ctrl_iface"""
1600     bssid = apdev[0]['bssid']
1601     addr = dev[0].p2p_dev_addr()
1602     params = hs20_ap_params()
1603     params['nai_realm'] = [ "0,example.com,21[2:4]" ]
1604     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
1605
1606     dev[0].request("SET pmf 1")
1607     dev[0].hs20_enable()
1608     dev[0].add_cred_values(default_cred())
1609     interworking_select(dev[0], bssid, freq="2412")
1610     interworking_connect(dev[0], bssid, "TTLS")
1611
1612     hapd.request("HS20_WNM_NOTIF " + addr + " https://example.com/")
1613     ev = dev[0].wait_event(["HS20-SUBSCRIPTION-REMEDIATION"], timeout=5)
1614     if ev is None:
1615         raise Exception("Timeout on subscription remediation notice")
1616     if " 1 https://example.com/" not in ev:
1617         raise Exception("Unexpected subscription remediation event contents")
1618
1619     hapd.request("HS20_WNM_NOTIF " + addr)
1620     ev = dev[0].wait_event(["HS20-SUBSCRIPTION-REMEDIATION"], timeout=5)
1621     if ev is None:
1622         raise Exception("Timeout on subscription remediation notice")
1623     if not ev.endswith("HS20-SUBSCRIPTION-REMEDIATION "):
1624         raise Exception("Unexpected subscription remediation event contents: " + ev)
1625
1626     if "FAIL" not in hapd.request("HS20_WNM_NOTIF "):
1627         raise Exception("Unexpected HS20_WNM_NOTIF success")
1628     if "FAIL" not in hapd.request("HS20_WNM_NOTIF foo"):
1629         raise Exception("Unexpected HS20_WNM_NOTIF success")
1630     if "FAIL" not in hapd.request("HS20_WNM_NOTIF " + addr + " https://12345678923456789842345678456783456712345678923456789842345678456783456712345678923456789842345678456783456712345678923456789842345678456783456712345678923456789842345678456783456712345678923456789842345678456783456712345678923456789842345678456783456712345678927.very.long.example.com/"):
1631         raise Exception("Unexpected HS20_WNM_NOTIF success")
1632
1633 def test_ap_hs20_session_info(dev, apdev):
1634     """Hotspot 2.0 connection and session information from RADIUS"""
1635     bssid = apdev[0]['bssid']
1636     params = hs20_ap_params()
1637     params['nai_realm'] = [ "0,example.com,21[2:4]" ]
1638     hostapd.add_ap(apdev[0]['ifname'], params)
1639
1640     dev[0].request("SET pmf 1")
1641     dev[0].hs20_enable()
1642     dev[0].add_cred_values({ 'realm': "example.com",
1643                              'username': "hs20-session-info-test",
1644                              'password': "password" })
1645     interworking_select(dev[0], bssid, freq="2412")
1646     interworking_connect(dev[0], bssid, "TTLS")
1647     ev = dev[0].wait_event(["ESS-DISASSOC-IMMINENT"], timeout=10)
1648     if ev is None:
1649         raise Exception("Timeout on ESS disassociation imminent notice")
1650     if " 1 59904 https://example.com/" not in ev:
1651         raise Exception("Unexpected ESS disassociation imminent event contents")
1652     ev = dev[0].wait_event(["CTRL-EVENT-SCAN-STARTED"])
1653     if ev is None:
1654         raise Exception("Scan not started")
1655     ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"])
1656     if ev is None:
1657         raise Exception("Scan not completed")
1658
1659 def test_ap_hs20_osen(dev, apdev):
1660     """Hotspot 2.0 OSEN connection"""
1661     params = { 'ssid': "osen",
1662                'osen': "1",
1663                'auth_server_addr': "127.0.0.1",
1664                'auth_server_port': "1812",
1665                'auth_server_shared_secret': "radius" }
1666     hostapd.add_ap(apdev[0]['ifname'], params)
1667
1668     dev[1].connect("osen", key_mgmt="NONE", scan_freq="2412",
1669                    wait_connect=False)
1670     dev[2].connect("osen", key_mgmt="NONE", wep_key0='"hello"',
1671                    scan_freq="2412", wait_connect=False)
1672     dev[0].connect("osen", proto="OSEN", key_mgmt="OSEN", pairwise="CCMP",
1673                    group="GTK_NOT_USED",
1674                    eap="WFA-UNAUTH-TLS", identity="osen@example.com",
1675                    ca_cert="auth_serv/ca.pem",
1676                    scan_freq="2412")
1677
1678     wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
1679     wpas.interface_add("wlan5", drv_params="force_connect_cmd=1")
1680     wpas.connect("osen", proto="OSEN", key_mgmt="OSEN", pairwise="CCMP",
1681                  group="GTK_NOT_USED",
1682                  eap="WFA-UNAUTH-TLS", identity="osen@example.com",
1683                  ca_cert="auth_serv/ca.pem",
1684                  scan_freq="2412")
1685     wpas.request("DISCONNECT")
1686
1687 def test_ap_hs20_network_preference(dev, apdev):
1688     """Hotspot 2.0 network selection with preferred home network"""
1689     bssid = apdev[0]['bssid']
1690     params = hs20_ap_params()
1691     hostapd.add_ap(apdev[0]['ifname'], params)
1692
1693     dev[0].hs20_enable()
1694     values = { 'realm': "example.com",
1695                'username': "hs20-test",
1696                'password': "password",
1697                'domain': "example.com" }
1698     dev[0].add_cred_values(values)
1699
1700     id = dev[0].add_network()
1701     dev[0].set_network_quoted(id, "ssid", "home")
1702     dev[0].set_network_quoted(id, "psk", "12345678")
1703     dev[0].set_network(id, "priority", "1")
1704     dev[0].request("ENABLE_NETWORK %s no-connect" % id)
1705
1706     dev[0].request("INTERWORKING_SELECT auto freq=2412")
1707     ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED"], timeout=15)
1708     if ev is None:
1709         raise Exception("Connection timed out")
1710     if bssid not in ev:
1711         raise Exception("Unexpected network selected")
1712
1713     bssid2 = apdev[1]['bssid']
1714     params = hostapd.wpa2_params(ssid="home", passphrase="12345678")
1715     hostapd.add_ap(apdev[1]['ifname'], params)
1716
1717     dev[0].request("INTERWORKING_SELECT auto freq=2412")
1718     ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED",
1719                             "INTERWORKING-ALREADY-CONNECTED" ], timeout=15)
1720     if ev is None:
1721         raise Exception("Connection timed out")
1722     if "INTERWORKING-ALREADY-CONNECTED" in ev:
1723         raise Exception("No roam to higher priority network")
1724     if bssid2 not in ev:
1725         raise Exception("Unexpected network selected")
1726
1727 def test_ap_hs20_network_preference2(dev, apdev):
1728     """Hotspot 2.0 network selection with preferred credential"""
1729     bssid2 = apdev[1]['bssid']
1730     params = hostapd.wpa2_params(ssid="home", passphrase="12345678")
1731     hostapd.add_ap(apdev[1]['ifname'], params)
1732
1733     dev[0].hs20_enable()
1734     values = { 'realm': "example.com",
1735                'username': "hs20-test",
1736                'password': "password",
1737                'domain': "example.com",
1738                'priority': "1" }
1739     dev[0].add_cred_values(values)
1740
1741     id = dev[0].add_network()
1742     dev[0].set_network_quoted(id, "ssid", "home")
1743     dev[0].set_network_quoted(id, "psk", "12345678")
1744     dev[0].request("ENABLE_NETWORK %s no-connect" % id)
1745
1746     dev[0].request("INTERWORKING_SELECT auto freq=2412")
1747     ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED"], timeout=15)
1748     if ev is None:
1749         raise Exception("Connection timed out")
1750     if bssid2 not in ev:
1751         raise Exception("Unexpected network selected")
1752
1753     bssid = apdev[0]['bssid']
1754     params = hs20_ap_params()
1755     hostapd.add_ap(apdev[0]['ifname'], params)
1756
1757     dev[0].request("INTERWORKING_SELECT auto freq=2412")
1758     ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED",
1759                             "INTERWORKING-ALREADY-CONNECTED" ], timeout=15)
1760     if ev is None:
1761         raise Exception("Connection timed out")
1762     if "INTERWORKING-ALREADY-CONNECTED" in ev:
1763         raise Exception("No roam to higher priority network")
1764     if bssid not in ev:
1765         raise Exception("Unexpected network selected")
1766
1767 def test_ap_hs20_network_preference3(dev, apdev):
1768     """Hotspot 2.0 network selection with two credential (one preferred)"""
1769     bssid = apdev[0]['bssid']
1770     params = hs20_ap_params()
1771     hostapd.add_ap(apdev[0]['ifname'], params)
1772
1773     bssid2 = apdev[1]['bssid']
1774     params = hs20_ap_params(ssid="test-hs20b")
1775     params['nai_realm'] = "0,example.org,13[5:6],21[2:4][5:7]"
1776     hostapd.add_ap(apdev[1]['ifname'], params)
1777
1778     dev[0].hs20_enable()
1779     values = { 'realm': "example.com",
1780                'username': "hs20-test",
1781                'password': "password",
1782                'priority': "1" }
1783     dev[0].add_cred_values(values)
1784     values = { 'realm': "example.org",
1785                'username': "hs20-test",
1786                'password': "password" }
1787     id = dev[0].add_cred_values(values)
1788
1789     dev[0].request("INTERWORKING_SELECT auto freq=2412")
1790     ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED"], timeout=15)
1791     if ev is None:
1792         raise Exception("Connection timed out")
1793     if bssid not in ev:
1794         raise Exception("Unexpected network selected")
1795
1796     dev[0].set_cred(id, "priority", "2")
1797     dev[0].request("INTERWORKING_SELECT auto freq=2412")
1798     ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED",
1799                             "INTERWORKING-ALREADY-CONNECTED" ], timeout=15)
1800     if ev is None:
1801         raise Exception("Connection timed out")
1802     if "INTERWORKING-ALREADY-CONNECTED" in ev:
1803         raise Exception("No roam to higher priority network")
1804     if bssid2 not in ev:
1805         raise Exception("Unexpected network selected")
1806
1807 def test_ap_hs20_network_preference4(dev, apdev):
1808     """Hotspot 2.0 network selection with username vs. SIM credential"""
1809     bssid = apdev[0]['bssid']
1810     params = hs20_ap_params()
1811     hostapd.add_ap(apdev[0]['ifname'], params)
1812
1813     bssid2 = apdev[1]['bssid']
1814     params = hs20_ap_params(ssid="test-hs20b")
1815     params['hessid'] = bssid2
1816     params['anqp_3gpp_cell_net'] = "555,444"
1817     params['domain_name'] = "wlan.mnc444.mcc555.3gppnetwork.org"
1818     hostapd.add_ap(apdev[1]['ifname'], params)
1819
1820     dev[0].hs20_enable()
1821     values = { 'realm': "example.com",
1822                'username': "hs20-test",
1823                'password': "password",
1824                'priority': "1" }
1825     dev[0].add_cred_values(values)
1826     values = { 'imsi': "555444-333222111",
1827                'eap': "SIM",
1828                'milenage': "5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123" }
1829     id = dev[0].add_cred_values(values)
1830
1831     dev[0].request("INTERWORKING_SELECT auto freq=2412")
1832     ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED"], timeout=15)
1833     if ev is None:
1834         raise Exception("Connection timed out")
1835     if bssid not in ev:
1836         raise Exception("Unexpected network selected")
1837
1838     dev[0].set_cred(id, "priority", "2")
1839     dev[0].request("INTERWORKING_SELECT auto freq=2412")
1840     ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED",
1841                             "INTERWORKING-ALREADY-CONNECTED" ], timeout=15)
1842     if ev is None:
1843         raise Exception("Connection timed out")
1844     if "INTERWORKING-ALREADY-CONNECTED" in ev:
1845         raise Exception("No roam to higher priority network")
1846     if bssid2 not in ev:
1847         raise Exception("Unexpected network selected")
1848
1849 def test_ap_hs20_fetch_osu(dev, apdev):
1850     """Hotspot 2.0 OSU provider and icon fetch"""
1851     bssid = apdev[0]['bssid']
1852     params = hs20_ap_params()
1853     params['hs20_icon'] = "128:80:zxx:image/png:w1fi_logo:w1fi_logo.png"
1854     params['osu_ssid'] = '"HS 2.0 OSU open"'
1855     params['osu_method_list'] = "1"
1856     params['osu_friendly_name'] = [ "eng:Test OSU", "fin:Testi-OSU" ]
1857     params['osu_icon'] = "w1fi_logo"
1858     params['osu_service_desc'] = [ "eng:Example services", "fin:Esimerkkipalveluja" ]
1859     params['osu_server_uri'] = "https://example.com/osu/"
1860     hostapd.add_ap(apdev[0]['ifname'], params)
1861
1862     bssid2 = apdev[1]['bssid']
1863     params = hs20_ap_params(ssid="test-hs20b")
1864     params['hessid'] = bssid2
1865     params['hs20_icon'] = "128:80:zxx:image/png:w1fi_logo:w1fi_logo.png"
1866     params['osu_ssid'] = '"HS 2.0 OSU OSEN"'
1867     params['osu_method_list'] = "0"
1868     params['osu_nai'] = "osen@example.com"
1869     params['osu_friendly_name'] = [ "eng:Test2 OSU", "fin:Testi2-OSU" ]
1870     params['osu_icon'] = "w1fi_logo"
1871     params['osu_service_desc'] = [ "eng:Example services2", "fin:Esimerkkipalveluja2" ]
1872     params['osu_server_uri'] = "https://example.org/osu/"
1873     hostapd.add_ap(apdev[1]['ifname'], params)
1874
1875     with open("w1fi_logo.png", "r") as f:
1876         orig_logo = f.read()
1877     dev[0].hs20_enable()
1878     dir = "/tmp/osu-fetch"
1879     if os.path.isdir(dir):
1880        files = [ f for f in os.listdir(dir) if f.startswith("osu-") ]
1881        for f in files:
1882            os.remove(dir + "/" + f)
1883     else:
1884         try:
1885             os.makedirs(dir)
1886         except:
1887             pass
1888     try:
1889         dev[1].scan(freq="2412")
1890         dev[0].request("SET osu_dir " + dir)
1891         dev[0].request("FETCH_OSU")
1892         if "OK" not in dev[1].request("HS20_ICON_REQUEST " + bssid + " w1fi_logo"):
1893             raise Exception("HS20_ICON_REQUEST failed")
1894         icons = 0
1895         while True:
1896             ev = dev[0].wait_event(["OSU provider fetch completed",
1897                                     "RX-HS20-ANQP-ICON"], timeout=15)
1898             if ev is None:
1899                 raise Exception("Timeout on OSU fetch")
1900             if "OSU provider fetch completed" in ev:
1901                 break
1902             if "RX-HS20-ANQP-ICON" in ev:
1903                 with open(ev.split(' ')[1], "r") as f:
1904                     logo = f.read()
1905                     if logo == orig_logo:
1906                         icons += 1
1907
1908         with open(dir + "/osu-providers.txt", "r") as f:
1909             prov = f.read()
1910         if "OSU-PROVIDER " + bssid not in prov:
1911             raise Exception("Missing OSU_PROVIDER")
1912         if "OSU-PROVIDER " + bssid2 not in prov:
1913             raise Exception("Missing OSU_PROVIDER")
1914     finally:
1915         files = [ f for f in os.listdir(dir) if f.startswith("osu-") ]
1916         for f in files:
1917             os.remove(dir + "/" + f)
1918         os.rmdir(dir)
1919
1920     if icons != 2:
1921         raise Exception("Unexpected number of icons fetched")
1922
1923     ev = dev[1].wait_event(["GAS-QUERY-START"], timeout=5)
1924     if ev is None:
1925         raise Exception("Timeout on GAS-QUERY-DONE")
1926     ev = dev[1].wait_event(["GAS-QUERY-DONE"], timeout=5)
1927     if ev is None:
1928         raise Exception("Timeout on GAS-QUERY-DONE")
1929     if "freq=2412 status_code=0 result=SUCCESS" not in ev:
1930         raise Exception("Unexpected GAS-QUERY-DONE: " + ev)
1931     ev = dev[1].wait_event(["RX-HS20-ANQP"], timeout=15)
1932     if ev is None:
1933         raise Exception("Timeout on icon fetch")
1934     if "Icon Binary File" not in ev:
1935         raise Exception("Unexpected ANQP element")
1936
1937 def test_ap_hs20_ft(dev, apdev):
1938     """Hotspot 2.0 connection with FT"""
1939     bssid = apdev[0]['bssid']
1940     params = hs20_ap_params()
1941     params['wpa_key_mgmt'] = "FT-EAP"
1942     params['nas_identifier'] = "nas1.w1.fi"
1943     params['r1_key_holder'] = "000102030405"
1944     params["mobility_domain"] = "a1b2"
1945     params["reassociation_deadline"] = "1000"
1946     hostapd.add_ap(apdev[0]['ifname'], params)
1947
1948     dev[0].hs20_enable()
1949     id = dev[0].add_cred_values({ 'realm': "example.com",
1950                                   'username': "hs20-test",
1951                                   'password': "password",
1952                                   'ca_cert': "auth_serv/ca.pem",
1953                                   'domain': "example.com",
1954                                   'update_identifier': "1234" })
1955     interworking_select(dev[0], bssid, "home", freq="2412")
1956     interworking_connect(dev[0], bssid, "TTLS")