tests: Hotspot 2.0 required roaming consortium and no match
[mech_eap.git] / tests / hwsim / test_ap_hs20.py
1 # Hotspot 2.0 tests
2 # Copyright (c) 2013-2015, 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 HwsimSkip, skip_with_fips, alloc_fail, wait_fail_trigger
21 import hwsim_utils
22 from tshark import run_tshark
23 from wlantest import Wlantest
24 from wpasupplicant import WpaSupplicant
25 from test_ap_eap import check_eap_capa, check_domain_match_full
26
27 def hs20_ap_params(ssid="test-hs20"):
28     params = hostapd.wpa2_params(ssid=ssid)
29     params['wpa_key_mgmt'] = "WPA-EAP"
30     params['ieee80211w'] = "1"
31     params['ieee8021x'] = "1"
32     params['auth_server_addr'] = "127.0.0.1"
33     params['auth_server_port'] = "1812"
34     params['auth_server_shared_secret'] = "radius"
35     params['interworking'] = "1"
36     params['access_network_type'] = "14"
37     params['internet'] = "1"
38     params['asra'] = "0"
39     params['esr'] = "0"
40     params['uesa'] = "0"
41     params['venue_group'] = "7"
42     params['venue_type'] = "1"
43     params['venue_name'] = [ "eng:Example venue", "fin:Esimerkkipaikka" ]
44     params['roaming_consortium'] = [ "112233", "1020304050", "010203040506",
45                                      "fedcba" ]
46     params['domain_name'] = "example.com,another.example.com"
47     params['nai_realm'] = [ "0,example.com,13[5:6],21[2:4][5:7]",
48                             "0,another.example.com" ]
49     params['hs20'] = "1"
50     params['hs20_wan_metrics'] = "01:8000:1000:80:240:3000"
51     params['hs20_conn_capab'] = [ "1:0:2", "6:22:1", "17:5060:0" ]
52     params['hs20_operating_class'] = "5173"
53     params['anqp_3gpp_cell_net'] = "244,91"
54     return params
55
56 def check_auto_select(dev, bssid):
57     dev.scan_for_bss(bssid, freq="2412")
58     dev.request("INTERWORKING_SELECT auto freq=2412")
59     ev = dev.wait_connected(timeout=15)
60     if bssid not in ev:
61         raise Exception("Connected to incorrect network")
62     dev.request("REMOVE_NETWORK all")
63     dev.wait_disconnected()
64     dev.dump_monitor()
65
66 def interworking_select(dev, bssid, type=None, no_match=False, freq=None):
67     dev.dump_monitor()
68     if bssid and freq and not no_match:
69         dev.scan_for_bss(bssid, freq=freq)
70     freq_extra = " freq=" + str(freq) if freq else ""
71     dev.request("INTERWORKING_SELECT" + freq_extra)
72     ev = dev.wait_event(["INTERWORKING-AP", "INTERWORKING-NO-MATCH"],
73                         timeout=15)
74     if ev is None:
75         raise Exception("Network selection timed out")
76     if no_match:
77         if "INTERWORKING-NO-MATCH" not in ev:
78             raise Exception("Unexpected network match")
79         return
80     if "INTERWORKING-NO-MATCH" in ev:
81         logger.info("Matching network not found - try again")
82         dev.dump_monitor()
83         dev.request("INTERWORKING_SELECT" + freq_extra)
84         ev = dev.wait_event(["INTERWORKING-AP", "INTERWORKING-NO-MATCH"],
85                             timeout=15)
86         if ev is None:
87             raise Exception("Network selection timed out")
88         if "INTERWORKING-NO-MATCH" in ev:
89             raise Exception("Matching network not found")
90     if bssid and bssid not in ev:
91         raise Exception("Unexpected BSSID in match")
92     if type and "type=" + type not in ev:
93         raise Exception("Network type not recognized correctly")
94
95 def check_sp_type(dev, sp_type):
96     type = dev.get_status_field("sp_type")
97     if type is None:
98         raise Exception("sp_type not available")
99     if type != sp_type:
100         raise Exception("sp_type did not indicate home network")
101
102 def hlr_auc_gw_available():
103     if not os.path.exists("/tmp/hlr_auc_gw.sock"):
104         raise HwsimSkip("No hlr_auc_gw socket available")
105     if not os.path.exists("../../hostapd/hlr_auc_gw"):
106         raise HwsimSkip("No hlr_auc_gw available")
107
108 def interworking_ext_sim_connect(dev, bssid, method):
109     dev.request("INTERWORKING_CONNECT " + bssid)
110     interworking_ext_sim_auth(dev, method)
111
112 def interworking_ext_sim_auth(dev, method):
113     ev = dev.wait_event(["CTRL-EVENT-EAP-METHOD"], timeout=15)
114     if ev is None:
115         raise Exception("Network connected timed out")
116     if "(" + method + ")" not in ev:
117         raise Exception("Unexpected EAP method selection")
118
119     ev = dev.wait_event(["CTRL-REQ-SIM"], timeout=15)
120     if ev is None:
121         raise Exception("Wait for external SIM processing request timed out")
122     p = ev.split(':', 2)
123     if p[1] != "GSM-AUTH":
124         raise Exception("Unexpected CTRL-REQ-SIM type")
125     id = p[0].split('-')[3]
126     rand = p[2].split(' ')[0]
127
128     res = subprocess.check_output(["../../hostapd/hlr_auc_gw",
129                                    "-m",
130                                    "auth_serv/hlr_auc_gw.milenage_db",
131                                    "GSM-AUTH-REQ 232010000000000 " + rand])
132     if "GSM-AUTH-RESP" not in res:
133         raise Exception("Unexpected hlr_auc_gw response")
134     resp = res.split(' ')[2].rstrip()
135
136     dev.request("CTRL-RSP-SIM-" + id + ":GSM-AUTH:" + resp)
137     dev.wait_connected(timeout=15)
138
139 def interworking_connect(dev, bssid, method):
140     dev.request("INTERWORKING_CONNECT " + bssid)
141     interworking_auth(dev, method)
142
143 def interworking_auth(dev, method):
144     ev = dev.wait_event(["CTRL-EVENT-EAP-METHOD"], timeout=15)
145     if ev is None:
146         raise Exception("Network connected timed out")
147     if "(" + method + ")" not in ev:
148         raise Exception("Unexpected EAP method selection")
149
150     dev.wait_connected(timeout=15)
151
152 def check_probe_resp(wt, bssid_unexpected, bssid_expected):
153     if bssid_unexpected:
154         count = wt.get_bss_counter("probe_response", bssid_unexpected)
155         if count > 0:
156             raise Exception("Unexpected Probe Response frame from AP")
157
158     if bssid_expected:
159         count = wt.get_bss_counter("probe_response", bssid_expected)
160         if count == 0:
161             raise Exception("No Probe Response frame from AP")
162
163 def test_ap_anqp_sharing(dev, apdev):
164     """ANQP sharing within ESS and explicit unshare"""
165     check_eap_capa(dev[0], "MSCHAPV2")
166     dev[0].flush_scan_cache()
167
168     bssid = apdev[0]['bssid']
169     params = hs20_ap_params()
170     params['hessid'] = bssid
171     hostapd.add_ap(apdev[0], params)
172
173     bssid2 = apdev[1]['bssid']
174     params = hs20_ap_params()
175     params['hessid'] = bssid
176     params['nai_realm'] = [ "0,example.com,13[5:6],21[2:4][5:7]" ]
177     hostapd.add_ap(apdev[1], params)
178
179     dev[0].hs20_enable()
180     id = dev[0].add_cred_values({ 'realm': "example.com", 'username': "test",
181                                   'password': "secret",
182                                   'domain': "example.com" })
183     logger.info("Normal network selection with shared ANQP results")
184     dev[0].scan_for_bss(bssid, freq="2412")
185     dev[0].scan_for_bss(bssid2, freq="2412")
186     interworking_select(dev[0], None, "home", freq="2412")
187     dev[0].dump_monitor()
188
189     logger.debug("BSS entries:\n" + dev[0].request("BSS RANGE=ALL"))
190     res1 = dev[0].get_bss(bssid)
191     res2 = dev[0].get_bss(bssid2)
192     if 'anqp_nai_realm' not in res1:
193         raise Exception("anqp_nai_realm not found for AP1")
194     if 'anqp_nai_realm' not in res2:
195         raise Exception("anqp_nai_realm not found for AP2")
196     if res1['anqp_nai_realm'] != res2['anqp_nai_realm']:
197         raise Exception("ANQP results were not shared between BSSes")
198
199     logger.info("Explicit ANQP request to unshare ANQP results")
200     dev[0].request("ANQP_GET " + bssid + " 263")
201     ev = dev[0].wait_event(["RX-ANQP"], timeout=5)
202     if ev is None:
203         raise Exception("ANQP operation timed out")
204
205     dev[0].request("ANQP_GET " + bssid2 + " 263")
206     ev = dev[0].wait_event(["RX-ANQP"], timeout=5)
207     if ev is None:
208         raise Exception("ANQP operation timed out")
209
210     res1 = dev[0].get_bss(bssid)
211     res2 = dev[0].get_bss(bssid2)
212     if res1['anqp_nai_realm'] == res2['anqp_nai_realm']:
213         raise Exception("ANQP results were not unshared")
214
215 def test_ap_anqp_sharing_oom(dev, apdev):
216     """ANQP sharing within ESS and explicit unshare OOM"""
217     check_eap_capa(dev[0], "MSCHAPV2")
218     dev[0].flush_scan_cache()
219
220     bssid = apdev[0]['bssid']
221     params = hs20_ap_params()
222     params['hessid'] = bssid
223     hostapd.add_ap(apdev[0], params)
224
225     bssid2 = apdev[1]['bssid']
226     params = hs20_ap_params()
227     params['hessid'] = bssid
228     params['nai_realm'] = [ "0,example.com,13[5:6],21[2:4][5:7]" ]
229     hostapd.add_ap(apdev[1], params)
230
231     dev[0].hs20_enable()
232     id = dev[0].add_cred_values({ 'realm': "example.com", 'username': "test",
233                                   'password': "secret",
234                                   'domain': "example.com" })
235     dev[0].scan_for_bss(bssid, freq="2412")
236     dev[0].scan_for_bss(bssid2, freq="2412")
237     interworking_select(dev[0], None, "home", freq="2412")
238     dev[0].dump_monitor()
239
240     with alloc_fail(dev[0], 1, "wpa_bss_anqp_clone"):
241         dev[0].request("ANQP_GET " + bssid + " 263")
242         ev = dev[0].wait_event(["RX-ANQP"], timeout=5)
243         if ev is None:
244             raise Exception("ANQP operation timed out")
245
246 def test_ap_nai_home_realm_query(dev, apdev):
247     """NAI Home Realm Query"""
248     check_eap_capa(dev[0], "MSCHAPV2")
249     bssid = apdev[0]['bssid']
250     params = hs20_ap_params()
251     params['nai_realm'] = [ "0,example.com,13[5:6],21[2:4][5:7]",
252                             "0,another.example.org" ]
253     hostapd.add_ap(apdev[0], params)
254
255     dev[0].scan(freq="2412")
256     dev[0].request("HS20_GET_NAI_HOME_REALM_LIST " + bssid + " realm=example.com")
257     ev = dev[0].wait_event(["RX-ANQP"], timeout=5)
258     if ev is None:
259         raise Exception("ANQP operation timed out")
260     nai1 = dev[0].get_bss(bssid)['anqp_nai_realm']
261     dev[0].dump_monitor()
262
263     dev[0].request("ANQP_GET " + bssid + " 263")
264     ev = dev[0].wait_event(["RX-ANQP"], timeout=5)
265     if ev is None:
266         raise Exception("ANQP operation timed out")
267     nai2 = dev[0].get_bss(bssid)['anqp_nai_realm']
268
269     if len(nai1) >= len(nai2):
270         raise Exception("Unexpected NAI Realm list response lengths")
271     if "example.com".encode('hex') not in nai1:
272         raise Exception("Home realm not reported")
273     if "example.org".encode('hex') in nai1:
274         raise Exception("Non-home realm reported")
275     if "example.com".encode('hex') not in nai2:
276         raise Exception("Home realm not reported in wildcard query")
277     if "example.org".encode('hex') not in nai2:
278         raise Exception("Non-home realm not reported in wildcard query ")
279
280     cmds = [ "foo",
281              "00:11:22:33:44:55 123",
282              "00:11:22:33:44:55 qq" ]
283     for cmd in cmds:
284         if "FAIL" not in dev[0].request("HS20_GET_NAI_HOME_REALM_LIST " + cmd):
285             raise Exception("Invalid HS20_GET_NAI_HOME_REALM_LIST accepted: " + cmd)
286
287     dev[0].dump_monitor()
288     if "OK" not in dev[0].request("HS20_GET_NAI_HOME_REALM_LIST " + bssid):
289         raise Exception("HS20_GET_NAI_HOME_REALM_LIST failed")
290     ev = dev[0].wait_event(["GAS-QUERY-DONE"], timeout=10)
291     if ev is None:
292         raise Exception("ANQP operation timed out")
293     ev = dev[0].wait_event(["RX-ANQP"], timeout=0.1)
294     if ev is not None:
295         raise Exception("Unexpected ANQP response: " + ev)
296
297     dev[0].dump_monitor()
298     if "OK" not in dev[0].request("HS20_GET_NAI_HOME_REALM_LIST " + bssid + " 01000b6578616d706c652e636f6d"):
299         raise Exception("HS20_GET_NAI_HOME_REALM_LIST failed")
300     ev = dev[0].wait_event(["RX-ANQP"], timeout=10)
301     if ev is None:
302         raise Exception("No ANQP response")
303     if "NAI Realm list" not in ev:
304         raise Exception("Missing NAI Realm list: " + ev)
305
306     dev[0].add_cred_values({ 'realm': "example.com", 'username': "test",
307                              'password': "secret",
308                              'domain': "example.com" })
309     dev[0].dump_monitor()
310     if "OK" not in dev[0].request("HS20_GET_NAI_HOME_REALM_LIST " + bssid):
311         raise Exception("HS20_GET_NAI_HOME_REALM_LIST failed")
312     ev = dev[0].wait_event(["RX-ANQP"], timeout=10)
313     if ev is None:
314         raise Exception("No ANQP response")
315     if "NAI Realm list" not in ev:
316         raise Exception("Missing NAI Realm list: " + ev)
317
318 @remote_compatible
319 def test_ap_interworking_scan_filtering(dev, apdev):
320     """Interworking scan filtering with HESSID and access network type"""
321     try:
322         _test_ap_interworking_scan_filtering(dev, apdev)
323     finally:
324         dev[0].request("SET hessid 00:00:00:00:00:00")
325         dev[0].request("SET access_network_type 15")
326
327 def _test_ap_interworking_scan_filtering(dev, apdev):
328     bssid = apdev[0]['bssid']
329     params = hs20_ap_params()
330     ssid = "test-hs20-ap1"
331     params['ssid'] = ssid
332     params['hessid'] = bssid
333     hapd0 = hostapd.add_ap(apdev[0], params)
334
335     bssid2 = apdev[1]['bssid']
336     params = hs20_ap_params()
337     ssid2 = "test-hs20-ap2"
338     params['ssid'] = ssid2
339     params['hessid'] = bssid2
340     params['access_network_type'] = "1"
341     del params['venue_group']
342     del params['venue_type']
343     hostapd.add_ap(apdev[1], params)
344
345     dev[0].hs20_enable()
346
347     Wlantest.setup(hapd0)
348     wt = Wlantest()
349     wt.flush()
350
351     logger.info("Check probe request filtering based on HESSID")
352
353     dev[0].request("SET hessid " + bssid2)
354     dev[0].scan(freq="2412")
355     time.sleep(0.03)
356     check_probe_resp(wt, bssid, bssid2)
357
358     logger.info("Check probe request filtering based on access network type")
359
360     wt.clear_bss_counters(bssid)
361     wt.clear_bss_counters(bssid2)
362     dev[0].request("SET hessid 00:00:00:00:00:00")
363     dev[0].request("SET access_network_type 14")
364     dev[0].scan(freq="2412")
365     time.sleep(0.03)
366     check_probe_resp(wt, bssid2, bssid)
367
368     wt.clear_bss_counters(bssid)
369     wt.clear_bss_counters(bssid2)
370     dev[0].request("SET hessid 00:00:00:00:00:00")
371     dev[0].request("SET access_network_type 1")
372     dev[0].scan(freq="2412")
373     time.sleep(0.03)
374     check_probe_resp(wt, bssid, bssid2)
375
376     logger.info("Check probe request filtering based on HESSID and ANT")
377
378     wt.clear_bss_counters(bssid)
379     wt.clear_bss_counters(bssid2)
380     dev[0].request("SET hessid " + bssid)
381     dev[0].request("SET access_network_type 14")
382     dev[0].scan(freq="2412")
383     time.sleep(0.03)
384     check_probe_resp(wt, bssid2, bssid)
385
386     wt.clear_bss_counters(bssid)
387     wt.clear_bss_counters(bssid2)
388     dev[0].request("SET hessid " + bssid2)
389     dev[0].request("SET access_network_type 14")
390     dev[0].scan(freq="2412")
391     time.sleep(0.03)
392     check_probe_resp(wt, bssid, None)
393     check_probe_resp(wt, bssid2, None)
394
395     wt.clear_bss_counters(bssid)
396     wt.clear_bss_counters(bssid2)
397     dev[0].request("SET hessid " + bssid)
398     dev[0].request("SET access_network_type 1")
399     dev[0].scan(freq="2412")
400     time.sleep(0.03)
401     check_probe_resp(wt, bssid, None)
402     check_probe_resp(wt, bssid2, None)
403
404 def test_ap_hs20_select(dev, apdev):
405     """Hotspot 2.0 network selection"""
406     bssid = apdev[0]['bssid']
407     params = hs20_ap_params()
408     params['hessid'] = bssid
409     hostapd.add_ap(apdev[0], params)
410
411     dev[0].hs20_enable()
412     id = dev[0].add_cred_values({ 'realm': "example.com", 'username': "test",
413                                   'password': "secret",
414                                   'domain': "example.com" })
415     interworking_select(dev[0], bssid, "home")
416
417     dev[0].remove_cred(id)
418     id = dev[0].add_cred_values({ 'realm': "example.com", 'username': "test",
419                                   'password': "secret",
420                                   'domain': "no.match.example.com" })
421     interworking_select(dev[0], bssid, "roaming", freq="2412")
422
423     dev[0].set_cred_quoted(id, "realm", "no.match.example.com")
424     interworking_select(dev[0], bssid, no_match=True, freq="2412")
425
426     res = dev[0].request("SCAN_RESULTS")
427     if "[HS20]" not in res:
428         raise Exception("HS20 flag missing from scan results: " + res)
429
430     bssid2 = apdev[1]['bssid']
431     params = hs20_ap_params()
432     params['nai_realm'] = [ "0,example.org,21" ]
433     params['hessid'] = bssid2
434     params['domain_name'] = "example.org"
435     hostapd.add_ap(apdev[1], params)
436     dev[0].remove_cred(id)
437     id = dev[0].add_cred_values({ 'realm': "example.org", 'username': "test",
438                                   'password': "secret",
439                                   'domain': "example.org" })
440     interworking_select(dev[0], bssid2, "home", freq="2412")
441
442 def hs20_simulated_sim(dev, ap, method):
443     bssid = ap['bssid']
444     params = hs20_ap_params()
445     params['hessid'] = bssid
446     params['anqp_3gpp_cell_net'] = "555,444"
447     params['domain_name'] = "wlan.mnc444.mcc555.3gppnetwork.org"
448     hostapd.add_ap(ap, params)
449
450     dev.hs20_enable()
451     dev.add_cred_values({ 'imsi': "555444-333222111", 'eap': method,
452                           'milenage': "5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123"})
453     interworking_select(dev, bssid, "home", freq="2412")
454     interworking_connect(dev, bssid, method)
455     check_sp_type(dev, "home")
456
457 def test_ap_hs20_sim(dev, apdev):
458     """Hotspot 2.0 with simulated SIM and EAP-SIM"""
459     hlr_auc_gw_available()
460     hs20_simulated_sim(dev[0], apdev[0], "SIM")
461     dev[0].request("INTERWORKING_SELECT auto freq=2412")
462     ev = dev[0].wait_event(["INTERWORKING-ALREADY-CONNECTED"], timeout=15)
463     if ev is None:
464         raise Exception("Timeout on already-connected event")
465
466 def test_ap_hs20_sim_invalid(dev, apdev):
467     """Hotspot 2.0 with simulated SIM and EAP-SIM - invalid IMSI"""
468     hlr_auc_gw_available()
469     bssid = apdev[0]['bssid']
470     params = hs20_ap_params()
471     params['hessid'] = bssid
472     params['anqp_3gpp_cell_net'] = "555,444"
473     params['domain_name'] = "wlan.mnc444.mcc555.3gppnetwork.org"
474     hostapd.add_ap(apdev[0], params)
475
476     dev[0].hs20_enable()
477     dev[0].add_cred_values({ 'imsi': "555444-3332221110", 'eap': "SIM",
478                           'milenage': "5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123"})
479     # This hits "No valid IMSI available" in build_root_nai()
480     interworking_select(dev[0], bssid, freq="2412")
481
482 def test_ap_hs20_sim_oom(dev, apdev):
483     """Hotspot 2.0 with simulated SIM and EAP-SIM - OOM"""
484     hlr_auc_gw_available()
485     bssid = apdev[0]['bssid']
486     params = hs20_ap_params()
487     params['hessid'] = bssid
488     params['anqp_3gpp_cell_net'] = "555,444"
489     params['domain_name'] = "wlan.mnc444.mcc555.3gppnetwork.org"
490     hostapd.add_ap(apdev[0], params)
491
492     dev[0].hs20_enable()
493     dev[0].add_cred_values({ 'imsi': "555444-333222111", 'eap': "SIM",
494                           'milenage': "5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123"})
495     dev[0].scan_for_bss(bssid, freq=2412)
496     interworking_select(dev[0], bssid, freq="2412")
497
498     with alloc_fail(dev[0], 1, "wpa_config_add_network;interworking_connect_3gpp"):
499         dev[0].request("INTERWORKING_CONNECT " + bssid)
500         wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
501
502     with alloc_fail(dev[0], 1, "=interworking_connect_3gpp"):
503         dev[0].request("INTERWORKING_CONNECT " + bssid)
504         wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
505
506 def test_ap_hs20_aka(dev, apdev):
507     """Hotspot 2.0 with simulated USIM and EAP-AKA"""
508     hlr_auc_gw_available()
509     hs20_simulated_sim(dev[0], apdev[0], "AKA")
510
511 def test_ap_hs20_aka_prime(dev, apdev):
512     """Hotspot 2.0 with simulated USIM and EAP-AKA'"""
513     hlr_auc_gw_available()
514     hs20_simulated_sim(dev[0], apdev[0], "AKA'")
515
516 def test_ap_hs20_ext_sim(dev, apdev):
517     """Hotspot 2.0 with external SIM processing"""
518     hlr_auc_gw_available()
519     bssid = apdev[0]['bssid']
520     params = hs20_ap_params()
521     params['hessid'] = bssid
522     params['anqp_3gpp_cell_net'] = "232,01"
523     params['domain_name'] = "wlan.mnc001.mcc232.3gppnetwork.org"
524     hostapd.add_ap(apdev[0], params)
525
526     dev[0].hs20_enable()
527     try:
528         dev[0].request("SET external_sim 1")
529         dev[0].add_cred_values({ 'imsi': "23201-0000000000", 'eap': "SIM" })
530         interworking_select(dev[0], bssid, "home", freq="2412")
531         interworking_ext_sim_connect(dev[0], bssid, "SIM")
532         check_sp_type(dev[0], "home")
533     finally:
534         dev[0].request("SET external_sim 0")
535
536 def test_ap_hs20_ext_sim_roaming(dev, apdev):
537     """Hotspot 2.0 with external SIM processing in roaming network"""
538     hlr_auc_gw_available()
539     bssid = apdev[0]['bssid']
540     params = hs20_ap_params()
541     params['hessid'] = bssid
542     params['anqp_3gpp_cell_net'] = "244,91;310,026;232,01;234,56"
543     params['domain_name'] = "wlan.mnc091.mcc244.3gppnetwork.org"
544     hostapd.add_ap(apdev[0], params)
545
546     dev[0].hs20_enable()
547     try:
548         dev[0].request("SET external_sim 1")
549         dev[0].add_cred_values({ 'imsi': "23201-0000000000", 'eap': "SIM" })
550         interworking_select(dev[0], bssid, "roaming", freq="2412")
551         interworking_ext_sim_connect(dev[0], bssid, "SIM")
552         check_sp_type(dev[0], "roaming")
553     finally:
554         dev[0].request("SET external_sim 0")
555
556 def test_ap_hs20_username(dev, apdev):
557     """Hotspot 2.0 connection in username/password credential"""
558     check_eap_capa(dev[0], "MSCHAPV2")
559     bssid = apdev[0]['bssid']
560     params = hs20_ap_params()
561     params['hessid'] = bssid
562     params['disable_dgaf'] = '1'
563     hostapd.add_ap(apdev[0], params)
564
565     dev[0].hs20_enable()
566     id = dev[0].add_cred_values({ 'realm': "example.com",
567                                   'username': "hs20-test",
568                                   'password': "password",
569                                   'ca_cert': "auth_serv/ca.pem",
570                                   'domain': "example.com",
571                                   'update_identifier': "1234" })
572     interworking_select(dev[0], bssid, "home", freq="2412")
573     interworking_connect(dev[0], bssid, "TTLS")
574     check_sp_type(dev[0], "home")
575     status = dev[0].get_status()
576     if status['pairwise_cipher'] != "CCMP":
577         raise Exception("Unexpected pairwise cipher")
578     if status['hs20'] != "2":
579         raise Exception("Unexpected HS 2.0 support indication")
580
581     dev[1].connect("test-hs20", key_mgmt="WPA-EAP", eap="TTLS",
582                    identity="hs20-test", password="password",
583                    ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
584                    scan_freq="2412")
585
586 def test_ap_hs20_connect_api(dev, apdev):
587     """Hotspot 2.0 connection with connect API"""
588     check_eap_capa(dev[0], "MSCHAPV2")
589     bssid = apdev[0]['bssid']
590     params = hs20_ap_params()
591     params['hessid'] = bssid
592     params['disable_dgaf'] = '1'
593     hostapd.add_ap(apdev[0], params)
594
595     wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
596     wpas.interface_add("wlan5", drv_params="force_connect_cmd=1")
597     wpas.hs20_enable()
598     wpas.flush_scan_cache()
599     id = wpas.add_cred_values({ 'realm': "example.com",
600                                   'username': "hs20-test",
601                                   'password': "password",
602                                   'ca_cert': "auth_serv/ca.pem",
603                                   'domain': "example.com",
604                                   'update_identifier': "1234" })
605     interworking_select(wpas, bssid, "home", freq="2412")
606     interworking_connect(wpas, bssid, "TTLS")
607     check_sp_type(wpas, "home")
608     status = wpas.get_status()
609     if status['pairwise_cipher'] != "CCMP":
610         raise Exception("Unexpected pairwise cipher")
611     if status['hs20'] != "2":
612         raise Exception("Unexpected HS 2.0 support indication")
613
614 def test_ap_hs20_auto_interworking(dev, apdev):
615     """Hotspot 2.0 connection with auto_interworking=1"""
616     check_eap_capa(dev[0], "MSCHAPV2")
617     bssid = apdev[0]['bssid']
618     params = hs20_ap_params()
619     params['hessid'] = bssid
620     params['disable_dgaf'] = '1'
621     hostapd.add_ap(apdev[0], params)
622
623     dev[0].hs20_enable(auto_interworking=True)
624     id = dev[0].add_cred_values({ 'realm': "example.com",
625                                   'username': "hs20-test",
626                                   'password': "password",
627                                   'ca_cert': "auth_serv/ca.pem",
628                                   'domain': "example.com",
629                                   'update_identifier': "1234" })
630     dev[0].request("REASSOCIATE")
631     dev[0].wait_connected(timeout=15)
632     check_sp_type(dev[0], "home")
633     status = dev[0].get_status()
634     if status['pairwise_cipher'] != "CCMP":
635         raise Exception("Unexpected pairwise cipher")
636     if status['hs20'] != "2":
637         raise Exception("Unexpected HS 2.0 support indication")
638
639 @remote_compatible
640 def test_ap_hs20_auto_interworking_no_match(dev, apdev):
641     """Hotspot 2.0 connection with auto_interworking=1 and no matching network"""
642     hapd = hostapd.add_ap(apdev[0], { "ssid": "mismatch" })
643
644     dev[0].hs20_enable(auto_interworking=True)
645     id = dev[0].connect("mismatch", psk="12345678", scan_freq="2412",
646                         only_add_network=True)
647     dev[0].request("ENABLE_NETWORK " + str(id) + " no-connect")
648
649     id = dev[0].add_cred_values({ 'realm': "example.com",
650                                   'username': "hs20-test",
651                                   'password': "password",
652                                   'ca_cert': "auth_serv/ca.pem",
653                                   'domain': "example.com",
654                                   'update_identifier': "1234" })
655     dev[0].request("INTERWORKING_SELECT auto freq=2412")
656     time.sleep(0.1)
657     dev[0].dump_monitor()
658     for i in range(5):
659         logger.info("start ping")
660         if "PONG" not in dev[0].ctrl.request("PING", timeout=2):
661             raise Exception("PING failed")
662         logger.info("ping done")
663         fetch = 0
664         scan = 0
665         for j in range(15):
666             ev = dev[0].wait_event([ "ANQP fetch completed",
667                                      "CTRL-EVENT-SCAN-RESULTS" ], timeout=0.05)
668             if ev is None:
669                 break
670             if "ANQP fetch completed" in ev:
671                 fetch += 1
672             else:
673                 scan += 1
674         if fetch > 2 * scan + 3:
675             raise Exception("Too many ANQP fetch iterations")
676         dev[0].dump_monitor()
677     dev[0].request("DISCONNECT")
678
679 @remote_compatible
680 def test_ap_hs20_auto_interworking_no_cred_match(dev, apdev):
681     """Hotspot 2.0 connection with auto_interworking=1 but no cred match"""
682     bssid = apdev[0]['bssid']
683     params = { "ssid": "test" }
684     hostapd.add_ap(apdev[0], params)
685
686     dev[0].hs20_enable(auto_interworking=True)
687     dev[0].add_cred_values({ 'realm': "example.com",
688                              'username': "hs20-test",
689                              'password': "password",
690                              'ca_cert': "auth_serv/ca.pem",
691                              'domain': "example.com" })
692
693     id = dev[0].connect("test", psk="12345678", only_add_network=True)
694     dev[0].request("ENABLE_NETWORK %s" % id)
695     logger.info("Verify that scanning continues when there is partial network block match")
696     for i in range(0, 2):
697         ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"], 10)
698         if ev is None:
699             raise Exception("Scan timed out")
700         logger.info("Scan completed")
701
702 def eap_test(dev, ap, eap_params, method, user):
703     bssid = ap['bssid']
704     params = hs20_ap_params()
705     params['nai_realm'] = [ "0,example.com," + eap_params ]
706     hostapd.add_ap(ap, params)
707
708     dev.hs20_enable()
709     dev.add_cred_values({ 'realm': "example.com",
710                           'ca_cert': "auth_serv/ca.pem",
711                           'username': user,
712                           'password': "password" })
713     interworking_select(dev, bssid, freq="2412")
714     interworking_connect(dev, bssid, method)
715
716 @remote_compatible
717 def test_ap_hs20_eap_unknown(dev, apdev):
718     """Hotspot 2.0 connection with unknown EAP method"""
719     bssid = apdev[0]['bssid']
720     params = hs20_ap_params()
721     params['nai_realm'] = "0,example.com,99"
722     hostapd.add_ap(apdev[0], params)
723
724     dev[0].hs20_enable()
725     dev[0].add_cred_values(default_cred())
726     interworking_select(dev[0], None, no_match=True, freq="2412")
727
728 def test_ap_hs20_eap_peap_mschapv2(dev, apdev):
729     """Hotspot 2.0 connection with PEAP/MSCHAPV2"""
730     check_eap_capa(dev[0], "MSCHAPV2")
731     eap_test(dev[0], apdev[0], "25[3:26]", "PEAP", "user")
732
733 def test_ap_hs20_eap_peap_default(dev, apdev):
734     """Hotspot 2.0 connection with PEAP/MSCHAPV2 (as default)"""
735     check_eap_capa(dev[0], "MSCHAPV2")
736     eap_test(dev[0], apdev[0], "25", "PEAP", "user")
737
738 def test_ap_hs20_eap_peap_gtc(dev, apdev):
739     """Hotspot 2.0 connection with PEAP/GTC"""
740     eap_test(dev[0], apdev[0], "25[3:6]", "PEAP", "user")
741
742 @remote_compatible
743 def test_ap_hs20_eap_peap_unknown(dev, apdev):
744     """Hotspot 2.0 connection with PEAP/unknown"""
745     bssid = apdev[0]['bssid']
746     params = hs20_ap_params()
747     params['nai_realm'] = "0,example.com,25[3:99]"
748     hostapd.add_ap(apdev[0], params)
749
750     dev[0].hs20_enable()
751     dev[0].add_cred_values(default_cred())
752     interworking_select(dev[0], None, no_match=True, freq="2412")
753
754 def test_ap_hs20_eap_ttls_chap(dev, apdev):
755     """Hotspot 2.0 connection with TTLS/CHAP"""
756     skip_with_fips(dev[0])
757     eap_test(dev[0], apdev[0], "21[2:2]", "TTLS", "chap user")
758
759 def test_ap_hs20_eap_ttls_mschap(dev, apdev):
760     """Hotspot 2.0 connection with TTLS/MSCHAP"""
761     skip_with_fips(dev[0])
762     eap_test(dev[0], apdev[0], "21[2:3]", "TTLS", "mschap user")
763
764 def test_ap_hs20_eap_ttls_eap_mschapv2(dev, apdev):
765     """Hotspot 2.0 connection with TTLS/EAP-MSCHAPv2"""
766     check_eap_capa(dev[0], "MSCHAPV2")
767     eap_test(dev[0], apdev[0], "21[3:26][6:7][99:99]", "TTLS", "user")
768
769 @remote_compatible
770 def test_ap_hs20_eap_ttls_eap_unknown(dev, apdev):
771     """Hotspot 2.0 connection with TTLS/EAP-unknown"""
772     bssid = apdev[0]['bssid']
773     params = hs20_ap_params()
774     params['nai_realm'] = "0,example.com,21[3:99]"
775     hostapd.add_ap(apdev[0], params)
776
777     dev[0].hs20_enable()
778     dev[0].add_cred_values(default_cred())
779     interworking_select(dev[0], None, no_match=True, freq="2412")
780
781 @remote_compatible
782 def test_ap_hs20_eap_ttls_eap_unsupported(dev, apdev):
783     """Hotspot 2.0 connection with TTLS/EAP-OTP(unsupported)"""
784     bssid = apdev[0]['bssid']
785     params = hs20_ap_params()
786     params['nai_realm'] = "0,example.com,21[3:5]"
787     hostapd.add_ap(apdev[0], params)
788
789     dev[0].hs20_enable()
790     dev[0].add_cred_values(default_cred())
791     interworking_select(dev[0], None, no_match=True, freq="2412")
792
793 @remote_compatible
794 def test_ap_hs20_eap_ttls_unknown(dev, apdev):
795     """Hotspot 2.0 connection with TTLS/unknown"""
796     bssid = apdev[0]['bssid']
797     params = hs20_ap_params()
798     params['nai_realm'] = "0,example.com,21[2:5]"
799     hostapd.add_ap(apdev[0], params)
800
801     dev[0].hs20_enable()
802     dev[0].add_cred_values(default_cred())
803     interworking_select(dev[0], None, no_match=True, freq="2412")
804
805 def test_ap_hs20_eap_fast_mschapv2(dev, apdev):
806     """Hotspot 2.0 connection with FAST/EAP-MSCHAPV2"""
807     check_eap_capa(dev[0], "FAST")
808     eap_test(dev[0], apdev[0], "43[3:26]", "FAST", "user")
809
810 def test_ap_hs20_eap_fast_gtc(dev, apdev):
811     """Hotspot 2.0 connection with FAST/EAP-GTC"""
812     check_eap_capa(dev[0], "FAST")
813     eap_test(dev[0], apdev[0], "43[3:6]", "FAST", "user")
814
815 def test_ap_hs20_eap_tls(dev, apdev):
816     """Hotspot 2.0 connection with EAP-TLS"""
817     bssid = apdev[0]['bssid']
818     params = hs20_ap_params()
819     params['nai_realm'] = [ "0,example.com,13[5:6]" ]
820     hostapd.add_ap(apdev[0], params)
821
822     dev[0].hs20_enable()
823     dev[0].add_cred_values({ 'realm': "example.com",
824                              'username': "certificate-user",
825                              'ca_cert': "auth_serv/ca.pem",
826                              'client_cert': "auth_serv/user.pem",
827                              'private_key': "auth_serv/user.key"})
828     interworking_select(dev[0], bssid, freq="2412")
829     interworking_connect(dev[0], bssid, "TLS")
830
831 @remote_compatible
832 def test_ap_hs20_eap_cert_unknown(dev, apdev):
833     """Hotspot 2.0 connection with certificate, but unknown EAP method"""
834     bssid = apdev[0]['bssid']
835     params = hs20_ap_params()
836     params['nai_realm'] = [ "0,example.com,99[5:6]" ]
837     hostapd.add_ap(apdev[0], params)
838
839     dev[0].hs20_enable()
840     dev[0].add_cred_values({ 'realm': "example.com",
841                              'username': "certificate-user",
842                              'ca_cert': "auth_serv/ca.pem",
843                              'client_cert': "auth_serv/user.pem",
844                              'private_key': "auth_serv/user.key"})
845     interworking_select(dev[0], None, no_match=True, freq="2412")
846
847 @remote_compatible
848 def test_ap_hs20_eap_cert_unsupported(dev, apdev):
849     """Hotspot 2.0 connection with certificate, but unsupported TTLS"""
850     bssid = apdev[0]['bssid']
851     params = hs20_ap_params()
852     params['nai_realm'] = [ "0,example.com,21[5:6]" ]
853     hostapd.add_ap(apdev[0], params)
854
855     dev[0].hs20_enable()
856     dev[0].add_cred_values({ 'realm': "example.com",
857                              'username': "certificate-user",
858                              'ca_cert': "auth_serv/ca.pem",
859                              'client_cert': "auth_serv/user.pem",
860                              'private_key': "auth_serv/user.key"})
861     interworking_select(dev[0], None, no_match=True, freq="2412")
862
863 @remote_compatible
864 def test_ap_hs20_eap_invalid_cred(dev, apdev):
865     """Hotspot 2.0 connection with invalid cred configuration"""
866     bssid = apdev[0]['bssid']
867     params = hs20_ap_params()
868     hostapd.add_ap(apdev[0], params)
869
870     dev[0].hs20_enable()
871     dev[0].add_cred_values({ 'realm': "example.com",
872                              'username': "certificate-user",
873                              'client_cert': "auth_serv/user.pem" })
874     interworking_select(dev[0], None, no_match=True, freq="2412")
875
876 def test_ap_hs20_nai_realms(dev, apdev):
877     """Hotspot 2.0 connection and multiple NAI realms and TTLS/PAP"""
878     bssid = apdev[0]['bssid']
879     params = hs20_ap_params()
880     params['hessid'] = bssid
881     params['nai_realm'] = [ "0,no.match.here;example.com;no.match.here.either,21[2:1][5:7]" ]
882     hostapd.add_ap(apdev[0], params)
883
884     dev[0].hs20_enable()
885     id = dev[0].add_cred_values({ 'realm': "example.com",
886                                   'ca_cert': "auth_serv/ca.pem",
887                                   'username': "pap user",
888                                   'password': "password",
889                                   'domain': "example.com" })
890     interworking_select(dev[0], bssid, "home", freq="2412")
891     interworking_connect(dev[0], bssid, "TTLS")
892     check_sp_type(dev[0], "home")
893
894 def test_ap_hs20_roaming_consortium(dev, apdev):
895     """Hotspot 2.0 connection based on roaming consortium match"""
896     bssid = apdev[0]['bssid']
897     params = hs20_ap_params()
898     params['hessid'] = bssid
899     hostapd.add_ap(apdev[0], params)
900
901     dev[0].hs20_enable()
902     for consortium in [ "112233", "1020304050", "010203040506", "fedcba" ]:
903         id = dev[0].add_cred_values({ 'username': "user",
904                                       'password': "password",
905                                       'domain': "example.com",
906                                       'ca_cert': "auth_serv/ca.pem",
907                                       'roaming_consortium': consortium,
908                                       'eap': "PEAP" })
909         interworking_select(dev[0], bssid, "home", freq="2412")
910         interworking_connect(dev[0], bssid, "PEAP")
911         check_sp_type(dev[0], "home")
912         dev[0].request("INTERWORKING_SELECT auto freq=2412")
913         ev = dev[0].wait_event(["INTERWORKING-ALREADY-CONNECTED"], timeout=15)
914         if ev is None:
915             raise Exception("Timeout on already-connected event")
916         dev[0].remove_cred(id)
917
918 def test_ap_hs20_roaming_consortium_invalid(dev, apdev):
919     """Hotspot 2.0 connection and invalid roaming consortium ANQP-element"""
920     bssid = apdev[0]['bssid']
921     params = hs20_ap_params()
922     params['hessid'] = bssid
923     # Override Roaming Consortium ANQP-element with an incorrectly encoded
924     # value.
925     params['anqp_elem'] = "261:04fedcba"
926     hostapd.add_ap(apdev[0], params)
927
928     dev[0].hs20_enable()
929     id = dev[0].add_cred_values({ 'username': "user",
930                                   'password': "password",
931                                   'domain': "example.com",
932                                   'ca_cert': "auth_serv/ca.pem",
933                                   'roaming_consortium': "fedcba",
934                                   'eap': "PEAP" })
935     interworking_select(dev[0], bssid, "home", freq="2412", no_match=True)
936
937 def test_ap_hs20_username_roaming(dev, apdev):
938     """Hotspot 2.0 connection in username/password credential (roaming)"""
939     check_eap_capa(dev[0], "MSCHAPV2")
940     bssid = apdev[0]['bssid']
941     params = hs20_ap_params()
942     params['nai_realm'] = [ "0,example.com,13[5:6],21[2:4][5:7]",
943                             "0,roaming.example.com,21[2:4][5:7]",
944                             "0,another.example.com" ]
945     params['domain_name'] = "another.example.com"
946     params['hessid'] = bssid
947     hostapd.add_ap(apdev[0], params)
948
949     dev[0].hs20_enable()
950     id = dev[0].add_cred_values({ 'realm': "roaming.example.com",
951                                   'username': "hs20-test",
952                                   'password': "password",
953                                   'ca_cert': "auth_serv/ca.pem",
954                                   'domain': "example.com" })
955     interworking_select(dev[0], bssid, "roaming", freq="2412")
956     interworking_connect(dev[0], bssid, "TTLS")
957     check_sp_type(dev[0], "roaming")
958
959 def test_ap_hs20_username_unknown(dev, apdev):
960     """Hotspot 2.0 connection in username/password credential (no domain in cred)"""
961     check_eap_capa(dev[0], "MSCHAPV2")
962     bssid = apdev[0]['bssid']
963     params = hs20_ap_params()
964     params['hessid'] = bssid
965     hostapd.add_ap(apdev[0], params)
966
967     dev[0].hs20_enable()
968     id = dev[0].add_cred_values({ 'realm': "example.com",
969                                   'ca_cert': "auth_serv/ca.pem",
970                                   'username': "hs20-test",
971                                   'password': "password" })
972     interworking_select(dev[0], bssid, "unknown", freq="2412")
973     interworking_connect(dev[0], bssid, "TTLS")
974     check_sp_type(dev[0], "unknown")
975
976 def test_ap_hs20_username_unknown2(dev, apdev):
977     """Hotspot 2.0 connection in username/password credential (no domain advertized)"""
978     check_eap_capa(dev[0], "MSCHAPV2")
979     bssid = apdev[0]['bssid']
980     params = hs20_ap_params()
981     params['hessid'] = bssid
982     del params['domain_name']
983     hostapd.add_ap(apdev[0], params)
984
985     dev[0].hs20_enable()
986     id = dev[0].add_cred_values({ 'realm': "example.com",
987                                   'ca_cert': "auth_serv/ca.pem",
988                                   'username': "hs20-test",
989                                   'password': "password",
990                                   'domain': "example.com" })
991     interworking_select(dev[0], bssid, "unknown", freq="2412")
992     interworking_connect(dev[0], bssid, "TTLS")
993     check_sp_type(dev[0], "unknown")
994
995 def test_ap_hs20_gas_while_associated(dev, apdev):
996     """Hotspot 2.0 connection with GAS query while associated"""
997     check_eap_capa(dev[0], "MSCHAPV2")
998     bssid = apdev[0]['bssid']
999     params = hs20_ap_params()
1000     params['hessid'] = bssid
1001     hostapd.add_ap(apdev[0], params)
1002
1003     dev[0].hs20_enable()
1004     id = dev[0].add_cred_values({ 'realm': "example.com",
1005                                   'ca_cert': "auth_serv/ca.pem",
1006                                   'username': "hs20-test",
1007                                   'password': "password",
1008                                   'domain': "example.com" })
1009     interworking_select(dev[0], bssid, "home", freq="2412")
1010     interworking_connect(dev[0], bssid, "TTLS")
1011
1012     logger.info("Verifying GAS query while associated")
1013     dev[0].request("FETCH_ANQP")
1014     for i in range(0, 6):
1015         ev = dev[0].wait_event(["RX-ANQP"], timeout=5)
1016         if ev is None:
1017             raise Exception("Operation timed out")
1018
1019 def test_ap_hs20_gas_with_another_ap_while_associated(dev, apdev):
1020     """GAS query with another AP while associated"""
1021     check_eap_capa(dev[0], "MSCHAPV2")
1022     bssid = apdev[0]['bssid']
1023     params = hs20_ap_params()
1024     params['hessid'] = bssid
1025     hostapd.add_ap(apdev[0], params)
1026
1027     bssid2 = apdev[1]['bssid']
1028     params = hs20_ap_params()
1029     params['hessid'] = bssid2
1030     params['nai_realm'] = [ "0,no-match.example.org,13[5:6],21[2:4][5:7]" ]
1031     hostapd.add_ap(apdev[1], params)
1032
1033     dev[0].hs20_enable()
1034     id = dev[0].add_cred_values({ 'realm': "example.com",
1035                                   'ca_cert': "auth_serv/ca.pem",
1036                                   'username': "hs20-test",
1037                                   'password': "password",
1038                                   'domain': "example.com" })
1039     interworking_select(dev[0], bssid, "home", freq="2412")
1040     interworking_connect(dev[0], bssid, "TTLS")
1041     dev[0].dump_monitor()
1042
1043     logger.info("Verifying GAS query with same AP while associated")
1044     dev[0].request("ANQP_GET " + bssid + " 263")
1045     ev = dev[0].wait_event(["RX-ANQP"], timeout=5)
1046     if ev is None:
1047         raise Exception("ANQP operation timed out")
1048     dev[0].dump_monitor()
1049
1050     logger.info("Verifying GAS query with another AP while associated")
1051     dev[0].scan_for_bss(bssid2, 2412)
1052     dev[0].request("ANQP_GET " + bssid2 + " 263")
1053     ev = dev[0].wait_event(["RX-ANQP"], timeout=5)
1054     if ev is None:
1055         raise Exception("ANQP operation timed out")
1056
1057 def test_ap_hs20_gas_while_associated_with_pmf(dev, apdev):
1058     """Hotspot 2.0 connection with GAS query while associated and using PMF"""
1059     check_eap_capa(dev[0], "MSCHAPV2")
1060     try:
1061         _test_ap_hs20_gas_while_associated_with_pmf(dev, apdev)
1062     finally:
1063         dev[0].request("SET pmf 0")
1064
1065 def _test_ap_hs20_gas_while_associated_with_pmf(dev, apdev):
1066     bssid = apdev[0]['bssid']
1067     params = hs20_ap_params()
1068     params['hessid'] = bssid
1069     hostapd.add_ap(apdev[0], params)
1070
1071     bssid2 = apdev[1]['bssid']
1072     params = hs20_ap_params()
1073     params['hessid'] = bssid2
1074     params['nai_realm'] = [ "0,no-match.example.org,13[5:6],21[2:4][5:7]" ]
1075     hostapd.add_ap(apdev[1], params)
1076
1077     dev[0].hs20_enable()
1078     dev[0].request("SET pmf 2")
1079     id = dev[0].add_cred_values({ 'realm': "example.com",
1080                                   'ca_cert': "auth_serv/ca.pem",
1081                                   'username': "hs20-test",
1082                                   'password': "password",
1083                                   'domain': "example.com" })
1084     interworking_select(dev[0], bssid, "home", freq="2412")
1085     interworking_connect(dev[0], bssid, "TTLS")
1086
1087     logger.info("Verifying GAS query while associated")
1088     dev[0].request("FETCH_ANQP")
1089     for i in range(0, 2 * 6):
1090         ev = dev[0].wait_event(["RX-ANQP"], timeout=5)
1091         if ev is None:
1092             raise Exception("Operation timed out")
1093
1094 def test_ap_hs20_gas_with_another_ap_while_using_pmf(dev, apdev):
1095     """GAS query with another AP while associated and using PMF"""
1096     check_eap_capa(dev[0], "MSCHAPV2")
1097     try:
1098         _test_ap_hs20_gas_with_another_ap_while_using_pmf(dev, apdev)
1099     finally:
1100         dev[0].request("SET pmf 0")
1101
1102 def _test_ap_hs20_gas_with_another_ap_while_using_pmf(dev, apdev):
1103     bssid = apdev[0]['bssid']
1104     params = hs20_ap_params()
1105     params['hessid'] = bssid
1106     hostapd.add_ap(apdev[0], params)
1107
1108     bssid2 = apdev[1]['bssid']
1109     params = hs20_ap_params()
1110     params['hessid'] = bssid2
1111     params['nai_realm'] = [ "0,no-match.example.org,13[5:6],21[2:4][5:7]" ]
1112     hostapd.add_ap(apdev[1], params)
1113
1114     dev[0].hs20_enable()
1115     dev[0].request("SET pmf 2")
1116     id = dev[0].add_cred_values({ 'realm': "example.com",
1117                                   'ca_cert': "auth_serv/ca.pem",
1118                                   'username': "hs20-test",
1119                                   'password': "password",
1120                                   'domain': "example.com" })
1121     interworking_select(dev[0], bssid, "home", freq="2412")
1122     interworking_connect(dev[0], bssid, "TTLS")
1123     dev[0].dump_monitor()
1124
1125     logger.info("Verifying GAS query with same AP while associated")
1126     dev[0].request("ANQP_GET " + bssid + " 263")
1127     ev = dev[0].wait_event(["RX-ANQP"], timeout=5)
1128     if ev is None:
1129         raise Exception("ANQP operation timed out")
1130     dev[0].dump_monitor()
1131
1132     logger.info("Verifying GAS query with another AP while associated")
1133     dev[0].scan_for_bss(bssid2, 2412)
1134     dev[0].request("ANQP_GET " + bssid2 + " 263")
1135     ev = dev[0].wait_event(["RX-ANQP"], timeout=5)
1136     if ev is None:
1137         raise Exception("ANQP operation timed out")
1138
1139 def test_ap_hs20_gas_frag_while_associated(dev, apdev):
1140     """Hotspot 2.0 connection with fragmented GAS query while associated"""
1141     check_eap_capa(dev[0], "MSCHAPV2")
1142     bssid = apdev[0]['bssid']
1143     params = hs20_ap_params()
1144     params['hessid'] = bssid
1145     hapd = hostapd.add_ap(apdev[0], params)
1146     hapd.set("gas_frag_limit", "50")
1147
1148     dev[0].hs20_enable()
1149     id = dev[0].add_cred_values({ 'realm': "example.com",
1150                                   'ca_cert': "auth_serv/ca.pem",
1151                                   'username': "hs20-test",
1152                                   'password': "password",
1153                                   'domain': "example.com" })
1154     interworking_select(dev[0], bssid, "home", freq="2412")
1155     interworking_connect(dev[0], bssid, "TTLS")
1156
1157     logger.info("Verifying GAS query while associated")
1158     dev[0].request("FETCH_ANQP")
1159     for i in range(0, 6):
1160         ev = dev[0].wait_event(["RX-ANQP"], timeout=5)
1161         if ev is None:
1162             raise Exception("Operation timed out")
1163
1164 def test_ap_hs20_multiple_connects(dev, apdev):
1165     """Hotspot 2.0 connection through multiple network selections"""
1166     check_eap_capa(dev[0], "MSCHAPV2")
1167     bssid = apdev[0]['bssid']
1168     params = hs20_ap_params()
1169     params['hessid'] = bssid
1170     hostapd.add_ap(apdev[0], params)
1171
1172     dev[0].hs20_enable()
1173     values = { 'realm': "example.com",
1174                'ca_cert': "auth_serv/ca.pem",
1175                'username': "hs20-test",
1176                'password': "password",
1177                'domain': "example.com" }
1178     id = dev[0].add_cred_values(values)
1179
1180     dev[0].scan_for_bss(bssid, freq="2412")
1181
1182     for i in range(0, 3):
1183         logger.info("Starting Interworking network selection")
1184         dev[0].request("INTERWORKING_SELECT auto freq=2412")
1185         while True:
1186             ev = dev[0].wait_event(["INTERWORKING-NO-MATCH",
1187                                     "INTERWORKING-ALREADY-CONNECTED",
1188                                     "CTRL-EVENT-CONNECTED"], timeout=15)
1189             if ev is None:
1190                 raise Exception("Connection timed out")
1191             if "INTERWORKING-NO-MATCH" in ev:
1192                 raise Exception("Matching AP not found")
1193             if "CTRL-EVENT-CONNECTED" in ev:
1194                 break
1195             if i == 2 and "INTERWORKING-ALREADY-CONNECTED" in ev:
1196                 break
1197         if i == 0:
1198             dev[0].request("DISCONNECT")
1199         dev[0].dump_monitor()
1200
1201     networks = dev[0].list_networks()
1202     if len(networks) > 1:
1203         raise Exception("Duplicated network block detected")
1204
1205 def test_ap_hs20_disallow_aps(dev, apdev):
1206     """Hotspot 2.0 connection and disallow_aps"""
1207     bssid = apdev[0]['bssid']
1208     params = hs20_ap_params()
1209     params['hessid'] = bssid
1210     hostapd.add_ap(apdev[0], params)
1211
1212     dev[0].hs20_enable()
1213     values = { 'realm': "example.com",
1214                'ca_cert': "auth_serv/ca.pem",
1215                'username': "hs20-test",
1216                'password': "password",
1217                'domain': "example.com" }
1218     id = dev[0].add_cred_values(values)
1219
1220     dev[0].scan_for_bss(bssid, freq="2412")
1221
1222     logger.info("Verify disallow_aps bssid")
1223     dev[0].request("SET disallow_aps bssid " + bssid.translate(None, ':'))
1224     dev[0].request("INTERWORKING_SELECT auto")
1225     ev = dev[0].wait_event(["INTERWORKING-NO-MATCH"], timeout=15)
1226     if ev is None:
1227         raise Exception("Network selection timed out")
1228     dev[0].dump_monitor()
1229
1230     logger.info("Verify disallow_aps ssid")
1231     dev[0].request("SET disallow_aps ssid 746573742d68733230")
1232     dev[0].request("INTERWORKING_SELECT auto freq=2412")
1233     ev = dev[0].wait_event(["INTERWORKING-NO-MATCH"], timeout=15)
1234     if ev is None:
1235         raise Exception("Network selection timed out")
1236     dev[0].dump_monitor()
1237
1238     logger.info("Verify disallow_aps clear")
1239     dev[0].request("SET disallow_aps ")
1240     interworking_select(dev[0], bssid, "home", freq="2412")
1241
1242     dev[0].request("SET disallow_aps bssid " + bssid.translate(None, ':'))
1243     ret = dev[0].request("INTERWORKING_CONNECT " + bssid)
1244     if "FAIL" not in ret:
1245         raise Exception("INTERWORKING_CONNECT to disallowed BSS not rejected")
1246
1247     if "FAIL" not in dev[0].request("INTERWORKING_CONNECT foo"):
1248         raise Exception("Invalid INTERWORKING_CONNECT not rejected")
1249     if "FAIL" not in dev[0].request("INTERWORKING_CONNECT 00:11:22:33:44:55"):
1250         raise Exception("Invalid INTERWORKING_CONNECT not rejected")
1251
1252 def policy_test(dev, ap, values, only_one=True):
1253     dev.dump_monitor()
1254     if ap:
1255         logger.info("Verify network selection to AP " + ap['ifname'])
1256         bssid = ap['bssid']
1257         dev.scan_for_bss(bssid, freq="2412")
1258     else:
1259         logger.info("Verify network selection")
1260         bssid = None
1261     dev.hs20_enable()
1262     id = dev.add_cred_values(values)
1263     dev.request("INTERWORKING_SELECT auto freq=2412")
1264     events = []
1265     while True:
1266         ev = dev.wait_event(["INTERWORKING-AP", "INTERWORKING-NO-MATCH",
1267                              "INTERWORKING-BLACKLISTED",
1268                              "INTERWORKING-SELECTED"], timeout=15)
1269         if ev is None:
1270             raise Exception("Network selection timed out")
1271         events.append(ev)
1272         if "INTERWORKING-NO-MATCH" in ev:
1273             raise Exception("Matching AP not found")
1274         if bssid and only_one and "INTERWORKING-AP" in ev and bssid not in ev:
1275             raise Exception("Unexpected AP claimed acceptable")
1276         if "INTERWORKING-SELECTED" in ev:
1277             if bssid and bssid not in ev:
1278                 raise Exception("Selected incorrect BSS")
1279             break
1280
1281     ev = dev.wait_connected(timeout=15)
1282     if bssid and bssid not in ev:
1283         raise Exception("Connected to incorrect BSS")
1284
1285     conn_bssid = dev.get_status_field("bssid")
1286     if bssid and conn_bssid != bssid:
1287         raise Exception("bssid information points to incorrect BSS")
1288
1289     dev.remove_cred(id)
1290     dev.dump_monitor()
1291     return events
1292
1293 def default_cred(domain=None, user="hs20-test"):
1294     cred = { 'realm': "example.com",
1295              'ca_cert': "auth_serv/ca.pem",
1296              'username': user,
1297              'password': "password" }
1298     if domain:
1299         cred['domain'] = domain
1300     return cred
1301
1302 def test_ap_hs20_prefer_home(dev, apdev):
1303     """Hotspot 2.0 required roaming consortium"""
1304     check_eap_capa(dev[0], "MSCHAPV2")
1305     params = hs20_ap_params()
1306     params['domain_name'] = "example.org"
1307     hostapd.add_ap(apdev[0], params)
1308
1309     params = hs20_ap_params()
1310     params['ssid'] = "test-hs20-other"
1311     params['domain_name'] = "example.com"
1312     hostapd.add_ap(apdev[1], params)
1313
1314     values = default_cred()
1315     values['domain'] = "example.com"
1316     policy_test(dev[0], apdev[1], values, only_one=False)
1317     values['domain'] = "example.org"
1318     policy_test(dev[0], apdev[0], values, only_one=False)
1319
1320 def test_ap_hs20_req_roaming_consortium(dev, apdev):
1321     """Hotspot 2.0 required roaming consortium"""
1322     check_eap_capa(dev[0], "MSCHAPV2")
1323     params = hs20_ap_params()
1324     hostapd.add_ap(apdev[0], params)
1325
1326     params = hs20_ap_params()
1327     params['ssid'] = "test-hs20-other"
1328     params['roaming_consortium'] = [ "223344" ]
1329     hostapd.add_ap(apdev[1], params)
1330
1331     values = default_cred()
1332     values['required_roaming_consortium'] = "223344"
1333     policy_test(dev[0], apdev[1], values)
1334     values['required_roaming_consortium'] = "112233"
1335     policy_test(dev[0], apdev[0], values)
1336
1337     id = dev[0].add_cred()
1338     dev[0].set_cred(id, "required_roaming_consortium", "112233")
1339     dev[0].set_cred(id, "required_roaming_consortium", "112233445566778899aabbccddeeff")
1340
1341     for val in [ "", "1", "11", "1122", "1122334", "112233445566778899aabbccddeeff00" ]:
1342         if "FAIL" not in dev[0].request('SET_CRED {} required_roaming_consortium {}'.format(id, val)):
1343             raise Exception("Invalid roaming consortium value accepted: " + val)
1344
1345 def test_ap_hs20_req_roaming_consortium_no_match(dev, apdev):
1346     """Hotspot 2.0 required roaming consortium and no match"""
1347     check_eap_capa(dev[0], "MSCHAPV2")
1348     params = hs20_ap_params()
1349     del params['roaming_consortium']
1350     hostapd.add_ap(apdev[0], params)
1351
1352     params = hs20_ap_params()
1353     params['ssid'] = "test-hs20-other"
1354     params['roaming_consortium'] = [ "223345" ]
1355     hostapd.add_ap(apdev[1], params)
1356
1357     values = default_cred()
1358     values['required_roaming_consortium'] = "223344"
1359     dev[0].hs20_enable()
1360     id = dev[0].add_cred_values(values)
1361     dev[0].request("INTERWORKING_SELECT auto freq=2412")
1362     ev = dev[0].wait_event(["INTERWORKING-NO-MATCH"], timeout=10)
1363     if ev is None:
1364         raise Exception("INTERWORKING-NO-MATCH not reported")
1365
1366 def test_ap_hs20_excluded_ssid(dev, apdev):
1367     """Hotspot 2.0 exclusion based on SSID"""
1368     check_eap_capa(dev[0], "MSCHAPV2")
1369     params = hs20_ap_params()
1370     params['roaming_consortium'] = [ "223344" ]
1371     params['anqp_3gpp_cell_net'] = "555,444"
1372     hostapd.add_ap(apdev[0], params)
1373
1374     params = hs20_ap_params()
1375     params['ssid'] = "test-hs20-other"
1376     params['roaming_consortium'] = [ "223344" ]
1377     params['anqp_3gpp_cell_net'] = "555,444"
1378     hostapd.add_ap(apdev[1], params)
1379
1380     values = default_cred()
1381     values['excluded_ssid'] = "test-hs20"
1382     events = policy_test(dev[0], apdev[1], values)
1383     ev = [e for e in events if "INTERWORKING-BLACKLISTED " + apdev[0]['bssid'] in e]
1384     if len(ev) != 1:
1385         raise Exception("Excluded network not reported")
1386     values['excluded_ssid'] = "test-hs20-other"
1387     events = policy_test(dev[0], apdev[0], values)
1388     ev = [e for e in events if "INTERWORKING-BLACKLISTED " + apdev[1]['bssid'] in e]
1389     if len(ev) != 1:
1390         raise Exception("Excluded network not reported")
1391
1392     values = default_cred()
1393     values['roaming_consortium'] = "223344"
1394     values['eap'] = "TTLS"
1395     values['phase2'] = "auth=MSCHAPV2"
1396     values['excluded_ssid'] = "test-hs20"
1397     events = policy_test(dev[0], apdev[1], values)
1398     ev = [e for e in events if "INTERWORKING-BLACKLISTED " + apdev[0]['bssid'] in e]
1399     if len(ev) != 1:
1400         raise Exception("Excluded network not reported")
1401
1402     values = { 'imsi': "555444-333222111", 'eap': "SIM",
1403                'milenage': "5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123",
1404                'excluded_ssid': "test-hs20" }
1405     events = policy_test(dev[0], apdev[1], values)
1406     ev = [e for e in events if "INTERWORKING-BLACKLISTED " + apdev[0]['bssid'] in e]
1407     if len(ev) != 1:
1408         raise Exception("Excluded network not reported")
1409
1410 def test_ap_hs20_roam_to_higher_prio(dev, apdev):
1411     """Hotspot 2.0 and roaming from current to higher priority network"""
1412     check_eap_capa(dev[0], "MSCHAPV2")
1413     bssid = apdev[0]['bssid']
1414     params = hs20_ap_params(ssid="test-hs20-visited")
1415     params['domain_name'] = "visited.example.org"
1416     hostapd.add_ap(apdev[0], params)
1417
1418     dev[0].hs20_enable()
1419     id = dev[0].add_cred_values({ 'realm': "example.com",
1420                                   'ca_cert': "auth_serv/ca.pem",
1421                                   'username': "hs20-test",
1422                                   'password': "password",
1423                                   'domain': "example.com" })
1424     logger.info("Connect to the only network option")
1425     interworking_select(dev[0], bssid, "roaming", freq="2412")
1426     dev[0].dump_monitor()
1427     interworking_connect(dev[0], bssid, "TTLS")
1428
1429     logger.info("Start another AP (home operator) and reconnect")
1430     bssid2 = apdev[1]['bssid']
1431     params = hs20_ap_params(ssid="test-hs20-home")
1432     params['domain_name'] = "example.com"
1433     hostapd.add_ap(apdev[1], params)
1434
1435     dev[0].scan_for_bss(bssid2, freq="2412", force_scan=True)
1436     dev[0].request("INTERWORKING_SELECT auto freq=2412")
1437     ev = dev[0].wait_event(["INTERWORKING-NO-MATCH",
1438                             "INTERWORKING-ALREADY-CONNECTED",
1439                             "CTRL-EVENT-CONNECTED"], timeout=15)
1440     if ev is None:
1441         raise Exception("Connection timed out")
1442     if "INTERWORKING-NO-MATCH" in ev:
1443         raise Exception("Matching AP not found")
1444     if "INTERWORKING-ALREADY-CONNECTED" in ev:
1445         raise Exception("Unexpected AP selected")
1446     if bssid2 not in ev:
1447         raise Exception("Unexpected BSSID after reconnection")
1448
1449 def test_ap_hs20_domain_suffix_match_full(dev, apdev):
1450     """Hotspot 2.0 and domain_suffix_match"""
1451     check_domain_match_full(dev[0])
1452     check_eap_capa(dev[0], "MSCHAPV2")
1453     bssid = apdev[0]['bssid']
1454     params = hs20_ap_params()
1455     hostapd.add_ap(apdev[0], params)
1456
1457     dev[0].hs20_enable()
1458     id = dev[0].add_cred_values({ 'realm': "example.com",
1459                                   'username': "hs20-test",
1460                                   'password': "password",
1461                                   'ca_cert': "auth_serv/ca.pem",
1462                                   'domain': "example.com",
1463                                   'domain_suffix_match': "server.w1.fi" })
1464     interworking_select(dev[0], bssid, "home", freq="2412")
1465     dev[0].dump_monitor()
1466     interworking_connect(dev[0], bssid, "TTLS")
1467     dev[0].request("REMOVE_NETWORK all")
1468     dev[0].dump_monitor()
1469
1470     dev[0].set_cred_quoted(id, "domain_suffix_match", "no-match.example.com")
1471     interworking_select(dev[0], bssid, "home", freq="2412")
1472     dev[0].dump_monitor()
1473     dev[0].request("INTERWORKING_CONNECT " + bssid)
1474     ev = dev[0].wait_event(["CTRL-EVENT-EAP-TLS-CERT-ERROR"])
1475     if ev is None:
1476         raise Exception("TLS certificate error not reported")
1477     if "Domain suffix mismatch" not in ev:
1478         raise Exception("Domain suffix mismatch not reported")
1479
1480 def test_ap_hs20_domain_suffix_match(dev, apdev):
1481     """Hotspot 2.0 and domain_suffix_match"""
1482     check_eap_capa(dev[0], "MSCHAPV2")
1483     check_domain_match_full(dev[0])
1484     bssid = apdev[0]['bssid']
1485     params = hs20_ap_params()
1486     hostapd.add_ap(apdev[0], params)
1487
1488     dev[0].hs20_enable()
1489     id = dev[0].add_cred_values({ 'realm': "example.com",
1490                                   'username': "hs20-test",
1491                                   'password': "password",
1492                                   'ca_cert': "auth_serv/ca.pem",
1493                                   'domain': "example.com",
1494                                   'domain_suffix_match': "w1.fi" })
1495     interworking_select(dev[0], bssid, "home", freq="2412")
1496     dev[0].dump_monitor()
1497     interworking_connect(dev[0], bssid, "TTLS")
1498
1499 def test_ap_hs20_roaming_partner_preference(dev, apdev):
1500     """Hotspot 2.0 and roaming partner preference"""
1501     check_eap_capa(dev[0], "MSCHAPV2")
1502     params = hs20_ap_params()
1503     params['domain_name'] = "roaming.example.org"
1504     hostapd.add_ap(apdev[0], params)
1505
1506     params = hs20_ap_params()
1507     params['ssid'] = "test-hs20-other"
1508     params['domain_name'] = "roaming.example.net"
1509     hostapd.add_ap(apdev[1], params)
1510
1511     logger.info("Verify default vs. specified preference")
1512     values = default_cred()
1513     values['roaming_partner'] = "roaming.example.net,1,127,*"
1514     policy_test(dev[0], apdev[1], values, only_one=False)
1515     values['roaming_partner'] = "roaming.example.net,1,129,*"
1516     policy_test(dev[0], apdev[0], values, only_one=False)
1517
1518     logger.info("Verify partial FQDN match")
1519     values['roaming_partner'] = "example.net,0,0,*"
1520     policy_test(dev[0], apdev[1], values, only_one=False)
1521     values['roaming_partner'] = "example.net,0,255,*"
1522     policy_test(dev[0], apdev[0], values, only_one=False)
1523
1524 def test_ap_hs20_max_bss_load(dev, apdev):
1525     """Hotspot 2.0 and maximum BSS load"""
1526     check_eap_capa(dev[0], "MSCHAPV2")
1527     params = hs20_ap_params()
1528     params['bss_load_test'] = "12:200:20000"
1529     hostapd.add_ap(apdev[0], params)
1530
1531     params = hs20_ap_params()
1532     params['ssid'] = "test-hs20-other"
1533     params['bss_load_test'] = "5:20:10000"
1534     hostapd.add_ap(apdev[1], params)
1535
1536     logger.info("Verify maximum BSS load constraint")
1537     values = default_cred()
1538     values['domain'] = "example.com"
1539     values['max_bss_load'] = "100"
1540     events = policy_test(dev[0], apdev[1], values, only_one=False)
1541
1542     ev = [e for e in events if "INTERWORKING-AP " + apdev[0]['bssid'] in e]
1543     if len(ev) != 1 or "over_max_bss_load=1" not in ev[0]:
1544         raise Exception("Maximum BSS Load case not noticed")
1545     ev = [e for e in events if "INTERWORKING-AP " + apdev[1]['bssid'] in e]
1546     if len(ev) != 1 or "over_max_bss_load=1" in ev[0]:
1547         raise Exception("Maximum BSS Load case reported incorrectly")
1548
1549     logger.info("Verify maximum BSS load does not prevent connection")
1550     values['max_bss_load'] = "1"
1551     events = policy_test(dev[0], None, values)
1552
1553     ev = [e for e in events if "INTERWORKING-AP " + apdev[0]['bssid'] in e]
1554     if len(ev) != 1 or "over_max_bss_load=1" not in ev[0]:
1555         raise Exception("Maximum BSS Load case not noticed")
1556     ev = [e for e in events if "INTERWORKING-AP " + apdev[1]['bssid'] in e]
1557     if len(ev) != 1 or "over_max_bss_load=1" not in ev[0]:
1558         raise Exception("Maximum BSS Load case not noticed")
1559
1560 def test_ap_hs20_max_bss_load2(dev, apdev):
1561     """Hotspot 2.0 and maximum BSS load with one AP not advertising"""
1562     check_eap_capa(dev[0], "MSCHAPV2")
1563     params = hs20_ap_params()
1564     params['bss_load_test'] = "12:200:20000"
1565     hostapd.add_ap(apdev[0], params)
1566
1567     params = hs20_ap_params()
1568     params['ssid'] = "test-hs20-other"
1569     hostapd.add_ap(apdev[1], params)
1570
1571     logger.info("Verify maximum BSS load constraint with AP advertisement")
1572     values = default_cred()
1573     values['domain'] = "example.com"
1574     values['max_bss_load'] = "100"
1575     events = policy_test(dev[0], apdev[1], values, only_one=False)
1576
1577     ev = [e for e in events if "INTERWORKING-AP " + apdev[0]['bssid'] in e]
1578     if len(ev) != 1 or "over_max_bss_load=1" not in ev[0]:
1579         raise Exception("Maximum BSS Load case not noticed")
1580     ev = [e for e in events if "INTERWORKING-AP " + apdev[1]['bssid'] in e]
1581     if len(ev) != 1 or "over_max_bss_load=1" in ev[0]:
1582         raise Exception("Maximum BSS Load case reported incorrectly")
1583
1584 def test_ap_hs20_multi_cred_sp_prio(dev, apdev):
1585     """Hotspot 2.0 multi-cred sp_priority"""
1586     check_eap_capa(dev[0], "MSCHAPV2")
1587     try:
1588         _test_ap_hs20_multi_cred_sp_prio(dev, apdev)
1589     finally:
1590         dev[0].request("SET external_sim 0")
1591
1592 def _test_ap_hs20_multi_cred_sp_prio(dev, apdev):
1593     hlr_auc_gw_available()
1594     bssid = apdev[0]['bssid']
1595     params = hs20_ap_params()
1596     params['hessid'] = bssid
1597     del params['domain_name']
1598     params['anqp_3gpp_cell_net'] = "232,01"
1599     hostapd.add_ap(apdev[0], params)
1600
1601     dev[0].hs20_enable()
1602     dev[0].scan_for_bss(bssid, freq="2412")
1603     dev[0].request("SET external_sim 1")
1604     id1 = dev[0].add_cred_values({ 'imsi': "23201-0000000000", 'eap': "SIM",
1605                                    'provisioning_sp': "example.com",
1606                                    'sp_priority' :"1" })
1607     id2 = dev[0].add_cred_values({ 'realm': "example.com",
1608                                    'ca_cert': "auth_serv/ca.pem",
1609                                    'username': "hs20-test",
1610                                    'password': "password",
1611                                    'domain': "example.com",
1612                                    'provisioning_sp': "example.com",
1613                                    'sp_priority': "2" })
1614     dev[0].dump_monitor()
1615     dev[0].scan_for_bss(bssid, freq="2412")
1616     dev[0].request("INTERWORKING_SELECT auto freq=2412")
1617     interworking_ext_sim_auth(dev[0], "SIM")
1618     check_sp_type(dev[0], "unknown")
1619     dev[0].request("REMOVE_NETWORK all")
1620
1621     dev[0].set_cred(id1, "sp_priority", "2")
1622     dev[0].set_cred(id2, "sp_priority", "1")
1623     dev[0].dump_monitor()
1624     dev[0].request("INTERWORKING_SELECT auto freq=2412")
1625     interworking_auth(dev[0], "TTLS")
1626     check_sp_type(dev[0], "unknown")
1627
1628 def test_ap_hs20_multi_cred_sp_prio2(dev, apdev):
1629     """Hotspot 2.0 multi-cred sp_priority with two BSSes"""
1630     check_eap_capa(dev[0], "MSCHAPV2")
1631     try:
1632         _test_ap_hs20_multi_cred_sp_prio2(dev, apdev)
1633     finally:
1634         dev[0].request("SET external_sim 0")
1635
1636 def _test_ap_hs20_multi_cred_sp_prio2(dev, apdev):
1637     hlr_auc_gw_available()
1638     bssid = apdev[0]['bssid']
1639     params = hs20_ap_params()
1640     params['hessid'] = bssid
1641     del params['nai_realm']
1642     del params['domain_name']
1643     params['anqp_3gpp_cell_net'] = "232,01"
1644     hostapd.add_ap(apdev[0], params)
1645
1646     bssid2 = apdev[1]['bssid']
1647     params = hs20_ap_params()
1648     params['ssid'] = "test-hs20-other"
1649     params['hessid'] = bssid2
1650     del params['domain_name']
1651     del params['anqp_3gpp_cell_net']
1652     hostapd.add_ap(apdev[1], params)
1653
1654     dev[0].hs20_enable()
1655     dev[0].request("SET external_sim 1")
1656     id1 = dev[0].add_cred_values({ 'imsi': "23201-0000000000", 'eap': "SIM",
1657                                    'provisioning_sp': "example.com",
1658                                    'sp_priority': "1" })
1659     id2 = dev[0].add_cred_values({ 'realm': "example.com",
1660                                    'ca_cert': "auth_serv/ca.pem",
1661                                    'username': "hs20-test",
1662                                    'password': "password",
1663                                    'domain': "example.com",
1664                                    'provisioning_sp': "example.com",
1665                                    'sp_priority': "2" })
1666     dev[0].dump_monitor()
1667     dev[0].scan_for_bss(bssid, freq="2412")
1668     dev[0].scan_for_bss(bssid2, freq="2412")
1669     dev[0].request("INTERWORKING_SELECT auto freq=2412")
1670     interworking_ext_sim_auth(dev[0], "SIM")
1671     check_sp_type(dev[0], "unknown")
1672     conn_bssid = dev[0].get_status_field("bssid")
1673     if conn_bssid != bssid:
1674         raise Exception("Connected to incorrect BSS")
1675     dev[0].request("REMOVE_NETWORK all")
1676
1677     dev[0].set_cred(id1, "sp_priority", "2")
1678     dev[0].set_cred(id2, "sp_priority", "1")
1679     dev[0].dump_monitor()
1680     dev[0].request("INTERWORKING_SELECT auto freq=2412")
1681     interworking_auth(dev[0], "TTLS")
1682     check_sp_type(dev[0], "unknown")
1683     conn_bssid = dev[0].get_status_field("bssid")
1684     if conn_bssid != bssid2:
1685         raise Exception("Connected to incorrect BSS")
1686
1687 def test_ap_hs20_multi_cred_sp_prio_same(dev, apdev):
1688     """Hotspot 2.0 multi-cred and same sp_priority"""
1689     check_eap_capa(dev[0], "MSCHAPV2")
1690     hlr_auc_gw_available()
1691     bssid = apdev[0]['bssid']
1692     params = hs20_ap_params()
1693     params['hessid'] = bssid
1694     del params['domain_name']
1695     params['anqp_3gpp_cell_net'] = "232,01"
1696     hostapd.add_ap(apdev[0], params)
1697
1698     dev[0].hs20_enable()
1699     dev[0].scan_for_bss(bssid, freq="2412")
1700     id1 = dev[0].add_cred_values({ 'realm': "example.com",
1701                                    'ca_cert': "auth_serv/ca.pem",
1702                                    'username': "hs20-test",
1703                                    'password': "password",
1704                                    'domain': "domain1.example.com",
1705                                    'provisioning_sp': "example.com",
1706                                    'sp_priority': "1" })
1707     id2 = dev[0].add_cred_values({ 'realm': "example.com",
1708                                    'ca_cert': "auth_serv/ca.pem",
1709                                    'username': "hs20-test",
1710                                    'password': "password",
1711                                    'domain': "domain2.example.com",
1712                                    'provisioning_sp': "example.com",
1713                                    'sp_priority': "1" })
1714     dev[0].dump_monitor()
1715     dev[0].scan_for_bss(bssid, freq="2412")
1716     check_auto_select(dev[0], bssid)
1717
1718 def check_conn_capab_selection(dev, type, missing):
1719     dev.request("INTERWORKING_SELECT freq=2412")
1720     ev = dev.wait_event(["INTERWORKING-AP"])
1721     if ev is None:
1722         raise Exception("Network selection timed out")
1723     if "type=" + type not in ev:
1724         raise Exception("Unexpected network type")
1725     if missing and "conn_capab_missing=1" not in ev:
1726         raise Exception("conn_capab_missing not reported")
1727     if not missing and "conn_capab_missing=1" in ev:
1728         raise Exception("conn_capab_missing reported unexpectedly")
1729
1730 def conn_capab_cred(domain=None, req_conn_capab=None):
1731     cred = default_cred(domain=domain)
1732     if req_conn_capab:
1733         cred['req_conn_capab'] = req_conn_capab
1734     return cred
1735
1736 def test_ap_hs20_req_conn_capab(dev, apdev):
1737     """Hotspot 2.0 network selection with req_conn_capab"""
1738     check_eap_capa(dev[0], "MSCHAPV2")
1739     bssid = apdev[0]['bssid']
1740     params = hs20_ap_params()
1741     hostapd.add_ap(apdev[0], params)
1742
1743     dev[0].hs20_enable()
1744     dev[0].scan_for_bss(bssid, freq="2412")
1745     logger.info("Not used in home network")
1746     values = conn_capab_cred(domain="example.com", req_conn_capab="6:1234")
1747     id = dev[0].add_cred_values(values)
1748     check_conn_capab_selection(dev[0], "home", False)
1749
1750     logger.info("Used in roaming network")
1751     dev[0].remove_cred(id)
1752     values = conn_capab_cred(domain="example.org", req_conn_capab="6:1234")
1753     id = dev[0].add_cred_values(values)
1754     check_conn_capab_selection(dev[0], "roaming", True)
1755
1756     logger.info("Verify that req_conn_capab does not prevent connection if no other network is available")
1757     check_auto_select(dev[0], bssid)
1758
1759     logger.info("Additional req_conn_capab checks")
1760
1761     dev[0].remove_cred(id)
1762     values = conn_capab_cred(domain="example.org", req_conn_capab="1:0")
1763     id = dev[0].add_cred_values(values)
1764     check_conn_capab_selection(dev[0], "roaming", True)
1765
1766     dev[0].remove_cred(id)
1767     values = conn_capab_cred(domain="example.org", req_conn_capab="17:5060")
1768     id = dev[0].add_cred_values(values)
1769     check_conn_capab_selection(dev[0], "roaming", True)
1770
1771     bssid2 = apdev[1]['bssid']
1772     params = hs20_ap_params(ssid="test-hs20b")
1773     params['hs20_conn_capab'] = [ "1:0:2", "6:22:1", "17:5060:0", "50:0:1" ]
1774     hostapd.add_ap(apdev[1], params)
1775
1776     dev[0].remove_cred(id)
1777     values = conn_capab_cred(domain="example.org", req_conn_capab="50")
1778     id = dev[0].add_cred_values(values)
1779     dev[0].set_cred(id, "req_conn_capab", "6:22")
1780     dev[0].scan_for_bss(bssid2, freq="2412")
1781     dev[0].request("INTERWORKING_SELECT freq=2412")
1782     for i in range(0, 2):
1783         ev = dev[0].wait_event(["INTERWORKING-AP"])
1784         if ev is None:
1785             raise Exception("Network selection timed out")
1786         if bssid in ev and "conn_capab_missing=1" not in ev:
1787             raise Exception("Missing protocol connection capability not reported")
1788         if bssid2 in ev and "conn_capab_missing=1" in ev:
1789             raise Exception("Protocol connection capability not reported correctly")
1790
1791 def test_ap_hs20_req_conn_capab_and_roaming_partner_preference(dev, apdev):
1792     """Hotspot 2.0 and req_conn_capab with roaming partner preference"""
1793     check_eap_capa(dev[0], "MSCHAPV2")
1794     bssid = apdev[0]['bssid']
1795     params = hs20_ap_params()
1796     params['domain_name'] = "roaming.example.org"
1797     params['hs20_conn_capab'] = [ "1:0:2", "6:22:1", "17:5060:0", "50:0:1" ]
1798     hostapd.add_ap(apdev[0], params)
1799
1800     bssid2 = apdev[1]['bssid']
1801     params = hs20_ap_params(ssid="test-hs20-b")
1802     params['domain_name'] = "roaming.example.net"
1803     hostapd.add_ap(apdev[1], params)
1804
1805     values = default_cred()
1806     values['roaming_partner'] = "roaming.example.net,1,127,*"
1807     id = dev[0].add_cred_values(values)
1808     check_auto_select(dev[0], bssid2)
1809
1810     dev[0].set_cred(id, "req_conn_capab", "50")
1811     check_auto_select(dev[0], bssid)
1812
1813     dev[0].remove_cred(id)
1814     id = dev[0].add_cred_values(values)
1815     dev[0].set_cred(id, "req_conn_capab", "51")
1816     check_auto_select(dev[0], bssid2)
1817
1818 def check_bandwidth_selection(dev, type, below):
1819     dev.request("INTERWORKING_SELECT freq=2412")
1820     ev = dev.wait_event(["INTERWORKING-AP"])
1821     if ev is None:
1822         raise Exception("Network selection timed out")
1823     logger.debug("BSS entries:\n" + dev.request("BSS RANGE=ALL"))
1824     if "type=" + type not in ev:
1825         raise Exception("Unexpected network type")
1826     if below and "below_min_backhaul=1" not in ev:
1827         raise Exception("below_min_backhaul not reported")
1828     if not below and "below_min_backhaul=1" in ev:
1829         raise Exception("below_min_backhaul reported unexpectedly")
1830
1831 def bw_cred(domain=None, dl_home=None, ul_home=None, dl_roaming=None, ul_roaming=None):
1832     cred = default_cred(domain=domain)
1833     if dl_home:
1834         cred['min_dl_bandwidth_home'] = str(dl_home)
1835     if ul_home:
1836         cred['min_ul_bandwidth_home'] = str(ul_home)
1837     if dl_roaming:
1838         cred['min_dl_bandwidth_roaming'] = str(dl_roaming)
1839     if ul_roaming:
1840         cred['min_ul_bandwidth_roaming'] = str(ul_roaming)
1841     return cred
1842
1843 def test_ap_hs20_min_bandwidth_home(dev, apdev):
1844     """Hotspot 2.0 network selection with min bandwidth (home)"""
1845     check_eap_capa(dev[0], "MSCHAPV2")
1846     bssid = apdev[0]['bssid']
1847     params = hs20_ap_params()
1848     hostapd.add_ap(apdev[0], params)
1849
1850     dev[0].hs20_enable()
1851     dev[0].scan_for_bss(bssid, freq="2412")
1852     values = bw_cred(domain="example.com", dl_home=5490, ul_home=58)
1853     id = dev[0].add_cred_values(values)
1854     check_bandwidth_selection(dev[0], "home", False)
1855     dev[0].remove_cred(id)
1856
1857     values = bw_cred(domain="example.com", dl_home=5491, ul_home=58)
1858     id = dev[0].add_cred_values(values)
1859     check_bandwidth_selection(dev[0], "home", True)
1860     dev[0].remove_cred(id)
1861
1862     values = bw_cred(domain="example.com", dl_home=5490, ul_home=59)
1863     id = dev[0].add_cred_values(values)
1864     check_bandwidth_selection(dev[0], "home", True)
1865     dev[0].remove_cred(id)
1866
1867     values = bw_cred(domain="example.com", dl_home=5491, ul_home=59)
1868     id = dev[0].add_cred_values(values)
1869     check_bandwidth_selection(dev[0], "home", True)
1870     check_auto_select(dev[0], bssid)
1871
1872     bssid2 = apdev[1]['bssid']
1873     params = hs20_ap_params(ssid="test-hs20-b")
1874     params['hs20_wan_metrics'] = "01:8000:1000:1:1:3000"
1875     hostapd.add_ap(apdev[1], params)
1876
1877     check_auto_select(dev[0], bssid2)
1878
1879 def test_ap_hs20_min_bandwidth_home_hidden_ssid_in_scan_res(dev, apdev):
1880     """Hotspot 2.0 network selection with min bandwidth (home) while hidden SSID is included in scan results"""
1881     check_eap_capa(dev[0], "MSCHAPV2")
1882     bssid = apdev[0]['bssid']
1883
1884     hapd = hostapd.add_ap(apdev[0], { "ssid": 'secret',
1885                                       "ignore_broadcast_ssid": "1" })
1886     dev[0].scan_for_bss(bssid, freq=2412)
1887     hapd.disable()
1888     hapd_global = hostapd.HostapdGlobal(apdev[0])
1889     hapd_global.flush()
1890     hapd_global.remove(apdev[0]['ifname'])
1891
1892     params = hs20_ap_params()
1893     hostapd.add_ap(apdev[0], params)
1894
1895     dev[0].hs20_enable()
1896     dev[0].scan_for_bss(bssid, freq="2412")
1897     values = bw_cred(domain="example.com", dl_home=5490, ul_home=58)
1898     id = dev[0].add_cred_values(values)
1899     check_bandwidth_selection(dev[0], "home", False)
1900     dev[0].remove_cred(id)
1901
1902     values = bw_cred(domain="example.com", dl_home=5491, ul_home=58)
1903     id = dev[0].add_cred_values(values)
1904     check_bandwidth_selection(dev[0], "home", True)
1905     dev[0].remove_cred(id)
1906
1907     values = bw_cred(domain="example.com", dl_home=5490, ul_home=59)
1908     id = dev[0].add_cred_values(values)
1909     check_bandwidth_selection(dev[0], "home", True)
1910     dev[0].remove_cred(id)
1911
1912     values = bw_cred(domain="example.com", dl_home=5491, ul_home=59)
1913     id = dev[0].add_cred_values(values)
1914     check_bandwidth_selection(dev[0], "home", True)
1915     check_auto_select(dev[0], bssid)
1916
1917     bssid2 = apdev[1]['bssid']
1918     params = hs20_ap_params(ssid="test-hs20-b")
1919     params['hs20_wan_metrics'] = "01:8000:1000:1:1:3000"
1920     hostapd.add_ap(apdev[1], params)
1921
1922     check_auto_select(dev[0], bssid2)
1923
1924     dev[0].flush_scan_cache()
1925
1926 def test_ap_hs20_min_bandwidth_roaming(dev, apdev):
1927     """Hotspot 2.0 network selection with min bandwidth (roaming)"""
1928     check_eap_capa(dev[0], "MSCHAPV2")
1929     bssid = apdev[0]['bssid']
1930     params = hs20_ap_params()
1931     hostapd.add_ap(apdev[0], params)
1932
1933     dev[0].hs20_enable()
1934     dev[0].scan_for_bss(bssid, freq="2412")
1935     values = bw_cred(domain="example.org", dl_roaming=5490, ul_roaming=58)
1936     id = dev[0].add_cred_values(values)
1937     check_bandwidth_selection(dev[0], "roaming", False)
1938     dev[0].remove_cred(id)
1939
1940     values = bw_cred(domain="example.org", dl_roaming=5491, ul_roaming=58)
1941     id = dev[0].add_cred_values(values)
1942     check_bandwidth_selection(dev[0], "roaming", True)
1943     dev[0].remove_cred(id)
1944
1945     values = bw_cred(domain="example.org", dl_roaming=5490, ul_roaming=59)
1946     id = dev[0].add_cred_values(values)
1947     check_bandwidth_selection(dev[0], "roaming", True)
1948     dev[0].remove_cred(id)
1949
1950     values = bw_cred(domain="example.org", dl_roaming=5491, ul_roaming=59)
1951     id = dev[0].add_cred_values(values)
1952     check_bandwidth_selection(dev[0], "roaming", True)
1953     check_auto_select(dev[0], bssid)
1954
1955     bssid2 = apdev[1]['bssid']
1956     params = hs20_ap_params(ssid="test-hs20-b")
1957     params['hs20_wan_metrics'] = "01:8000:1000:1:1:3000"
1958     hostapd.add_ap(apdev[1], params)
1959
1960     check_auto_select(dev[0], bssid2)
1961
1962 def test_ap_hs20_min_bandwidth_and_roaming_partner_preference(dev, apdev):
1963     """Hotspot 2.0 and minimum bandwidth with roaming partner preference"""
1964     check_eap_capa(dev[0], "MSCHAPV2")
1965     bssid = apdev[0]['bssid']
1966     params = hs20_ap_params()
1967     params['domain_name'] = "roaming.example.org"
1968     params['hs20_wan_metrics'] = "01:8000:1000:1:1:3000"
1969     hostapd.add_ap(apdev[0], params)
1970
1971     bssid2 = apdev[1]['bssid']
1972     params = hs20_ap_params(ssid="test-hs20-b")
1973     params['domain_name'] = "roaming.example.net"
1974     hostapd.add_ap(apdev[1], params)
1975
1976     values = default_cred()
1977     values['roaming_partner'] = "roaming.example.net,1,127,*"
1978     id = dev[0].add_cred_values(values)
1979     check_auto_select(dev[0], bssid2)
1980
1981     dev[0].set_cred(id, "min_dl_bandwidth_roaming", "6000")
1982     check_auto_select(dev[0], bssid)
1983
1984     dev[0].set_cred(id, "min_dl_bandwidth_roaming", "10000")
1985     check_auto_select(dev[0], bssid2)
1986
1987 def test_ap_hs20_min_bandwidth_no_wan_metrics(dev, apdev):
1988     """Hotspot 2.0 network selection with min bandwidth but no WAN Metrics"""
1989     bssid = apdev[0]['bssid']
1990     params = hs20_ap_params()
1991     del params['hs20_wan_metrics']
1992     hostapd.add_ap(apdev[0], params)
1993
1994     dev[0].hs20_enable()
1995     dev[0].scan_for_bss(bssid, freq="2412")
1996     values = bw_cred(domain="example.com", dl_home=10000, ul_home=10000,
1997                      dl_roaming=10000, ul_roaming=10000)
1998     dev[0].add_cred_values(values)
1999     check_bandwidth_selection(dev[0], "home", False)
2000
2001 def test_ap_hs20_deauth_req_ess(dev, apdev):
2002     """Hotspot 2.0 connection and deauthentication request for ESS"""
2003     check_eap_capa(dev[0], "MSCHAPV2")
2004     try:
2005         _test_ap_hs20_deauth_req_ess(dev, apdev)
2006     finally:
2007         dev[0].request("SET pmf 0")
2008
2009 def _test_ap_hs20_deauth_req_ess(dev, apdev):
2010     dev[0].request("SET pmf 2")
2011     eap_test(dev[0], apdev[0], "21[3:26]", "TTLS", "user")
2012     dev[0].dump_monitor()
2013     addr = dev[0].p2p_interface_addr()
2014     hapd = hostapd.Hostapd(apdev[0]['ifname'])
2015     hapd.request("HS20_DEAUTH_REQ " + addr + " 1 120 http://example.com/")
2016     ev = dev[0].wait_event(["HS20-DEAUTH-IMMINENT-NOTICE"])
2017     if ev is None:
2018         raise Exception("Timeout on deauth imminent notice")
2019     if "1 120 http://example.com/" not in ev:
2020         raise Exception("Unexpected deauth imminent notice: " + ev)
2021     hapd.request("DEAUTHENTICATE " + addr)
2022     dev[0].wait_disconnected(timeout=10)
2023     if "[TEMP-DISABLED]" not in dev[0].list_networks()[0]['flags']:
2024         raise Exception("Network not marked temporarily disabled")
2025     ev = dev[0].wait_event(["SME: Trying to authenticate",
2026                             "Trying to associate",
2027                             "CTRL-EVENT-CONNECTED"], timeout=5)
2028     if ev is not None:
2029         raise Exception("Unexpected connection attempt")
2030
2031 def test_ap_hs20_deauth_req_bss(dev, apdev):
2032     """Hotspot 2.0 connection and deauthentication request for BSS"""
2033     check_eap_capa(dev[0], "MSCHAPV2")
2034     try:
2035         _test_ap_hs20_deauth_req_bss(dev, apdev)
2036     finally:
2037         dev[0].request("SET pmf 0")
2038
2039 def _test_ap_hs20_deauth_req_bss(dev, apdev):
2040     dev[0].request("SET pmf 2")
2041     eap_test(dev[0], apdev[0], "21[3:26]", "TTLS", "user")
2042     dev[0].dump_monitor()
2043     addr = dev[0].p2p_interface_addr()
2044     hapd = hostapd.Hostapd(apdev[0]['ifname'])
2045     hapd.request("HS20_DEAUTH_REQ " + addr + " 0 120 http://example.com/")
2046     ev = dev[0].wait_event(["HS20-DEAUTH-IMMINENT-NOTICE"])
2047     if ev is None:
2048         raise Exception("Timeout on deauth imminent notice")
2049     if "0 120 http://example.com/" not in ev:
2050         raise Exception("Unexpected deauth imminent notice: " + ev)
2051     hapd.request("DEAUTHENTICATE " + addr + " reason=4")
2052     ev = dev[0].wait_disconnected(timeout=10)
2053     if "reason=4" not in ev:
2054         raise Exception("Unexpected disconnection reason")
2055     if "[TEMP-DISABLED]" not in dev[0].list_networks()[0]['flags']:
2056         raise Exception("Network not marked temporarily disabled")
2057     ev = dev[0].wait_event(["SME: Trying to authenticate",
2058                             "Trying to associate",
2059                             "CTRL-EVENT-CONNECTED"], timeout=5)
2060     if ev is not None:
2061         raise Exception("Unexpected connection attempt")
2062
2063 def test_ap_hs20_deauth_req_from_radius(dev, apdev):
2064     """Hotspot 2.0 connection and deauthentication request from RADIUS"""
2065     check_eap_capa(dev[0], "MSCHAPV2")
2066     try:
2067         _test_ap_hs20_deauth_req_from_radius(dev, apdev)
2068     finally:
2069         dev[0].request("SET pmf 0")
2070
2071 def _test_ap_hs20_deauth_req_from_radius(dev, apdev):
2072     bssid = apdev[0]['bssid']
2073     params = hs20_ap_params()
2074     params['nai_realm'] = [ "0,example.com,21[2:4]" ]
2075     params['hs20_deauth_req_timeout'] = "2"
2076     hostapd.add_ap(apdev[0], params)
2077
2078     dev[0].request("SET pmf 2")
2079     dev[0].hs20_enable()
2080     dev[0].add_cred_values({ 'realm': "example.com",
2081                              'username': "hs20-deauth-test",
2082                              'password': "password" })
2083     interworking_select(dev[0], bssid, freq="2412")
2084     interworking_connect(dev[0], bssid, "TTLS")
2085     ev = dev[0].wait_event(["HS20-DEAUTH-IMMINENT-NOTICE"], timeout=5)
2086     if ev is None:
2087         raise Exception("Timeout on deauth imminent notice")
2088     if " 1 100" not in ev:
2089         raise Exception("Unexpected deauth imminent contents")
2090     dev[0].wait_disconnected(timeout=3)
2091
2092 def test_ap_hs20_remediation_required(dev, apdev):
2093     """Hotspot 2.0 connection and remediation required from RADIUS"""
2094     check_eap_capa(dev[0], "MSCHAPV2")
2095     try:
2096         _test_ap_hs20_remediation_required(dev, apdev)
2097     finally:
2098         dev[0].request("SET pmf 0")
2099
2100 def _test_ap_hs20_remediation_required(dev, apdev):
2101     bssid = apdev[0]['bssid']
2102     params = hs20_ap_params()
2103     params['nai_realm'] = [ "0,example.com,21[2:4]" ]
2104     hostapd.add_ap(apdev[0], params)
2105
2106     dev[0].request("SET pmf 1")
2107     dev[0].hs20_enable()
2108     dev[0].add_cred_values({ 'realm': "example.com",
2109                              'username': "hs20-subrem-test",
2110                              'password': "password" })
2111     interworking_select(dev[0], bssid, freq="2412")
2112     interworking_connect(dev[0], bssid, "TTLS")
2113     ev = dev[0].wait_event(["HS20-SUBSCRIPTION-REMEDIATION"], timeout=5)
2114     if ev is None:
2115         raise Exception("Timeout on subscription remediation notice")
2116     if " 1 https://example.com/" not in ev:
2117         raise Exception("Unexpected subscription remediation event contents")
2118
2119 def test_ap_hs20_remediation_required_ctrl(dev, apdev):
2120     """Hotspot 2.0 connection and subrem from ctrl_iface"""
2121     check_eap_capa(dev[0], "MSCHAPV2")
2122     try:
2123         _test_ap_hs20_remediation_required_ctrl(dev, apdev)
2124     finally:
2125         dev[0].request("SET pmf 0")
2126
2127 def _test_ap_hs20_remediation_required_ctrl(dev, apdev):
2128     bssid = apdev[0]['bssid']
2129     addr = dev[0].own_addr()
2130     params = hs20_ap_params()
2131     params['nai_realm'] = [ "0,example.com,21[2:4]" ]
2132     hapd = hostapd.add_ap(apdev[0], params)
2133
2134     dev[0].request("SET pmf 1")
2135     dev[0].hs20_enable()
2136     dev[0].add_cred_values(default_cred())
2137     interworking_select(dev[0], bssid, freq="2412")
2138     interworking_connect(dev[0], bssid, "TTLS")
2139
2140     hapd.request("HS20_WNM_NOTIF " + addr + " https://example.com/")
2141     ev = dev[0].wait_event(["HS20-SUBSCRIPTION-REMEDIATION"], timeout=5)
2142     if ev is None:
2143         raise Exception("Timeout on subscription remediation notice")
2144     if " 1 https://example.com/" not in ev:
2145         raise Exception("Unexpected subscription remediation event contents")
2146
2147     hapd.request("HS20_WNM_NOTIF " + addr)
2148     ev = dev[0].wait_event(["HS20-SUBSCRIPTION-REMEDIATION"], timeout=5)
2149     if ev is None:
2150         raise Exception("Timeout on subscription remediation notice")
2151     if not ev.endswith("HS20-SUBSCRIPTION-REMEDIATION "):
2152         raise Exception("Unexpected subscription remediation event contents: " + ev)
2153
2154     if "FAIL" not in hapd.request("HS20_WNM_NOTIF "):
2155         raise Exception("Unexpected HS20_WNM_NOTIF success")
2156     if "FAIL" not in hapd.request("HS20_WNM_NOTIF foo"):
2157         raise Exception("Unexpected HS20_WNM_NOTIF success")
2158     if "FAIL" not in hapd.request("HS20_WNM_NOTIF " + addr + " https://12345678923456789842345678456783456712345678923456789842345678456783456712345678923456789842345678456783456712345678923456789842345678456783456712345678923456789842345678456783456712345678923456789842345678456783456712345678923456789842345678456783456712345678927.very.long.example.com/"):
2159         raise Exception("Unexpected HS20_WNM_NOTIF success")
2160
2161 def test_ap_hs20_session_info(dev, apdev):
2162     """Hotspot 2.0 connection and session information from RADIUS"""
2163     check_eap_capa(dev[0], "MSCHAPV2")
2164     try:
2165         _test_ap_hs20_session_info(dev, apdev)
2166     finally:
2167         dev[0].request("SET pmf 0")
2168
2169 def _test_ap_hs20_session_info(dev, apdev):
2170     bssid = apdev[0]['bssid']
2171     params = hs20_ap_params()
2172     params['nai_realm'] = [ "0,example.com,21[2:4]" ]
2173     hostapd.add_ap(apdev[0], params)
2174
2175     dev[0].request("SET pmf 1")
2176     dev[0].hs20_enable()
2177     dev[0].add_cred_values({ 'realm': "example.com",
2178                              'username': "hs20-session-info-test",
2179                              'password': "password" })
2180     interworking_select(dev[0], bssid, freq="2412")
2181     interworking_connect(dev[0], bssid, "TTLS")
2182     ev = dev[0].wait_event(["ESS-DISASSOC-IMMINENT"], timeout=10)
2183     if ev is None:
2184         raise Exception("Timeout on ESS disassociation imminent notice")
2185     if " 1 59904 https://example.com/" not in ev:
2186         raise Exception("Unexpected ESS disassociation imminent event contents")
2187     ev = dev[0].wait_event(["CTRL-EVENT-SCAN-STARTED"])
2188     if ev is None:
2189         raise Exception("Scan not started")
2190     ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"], timeout=30)
2191     if ev is None:
2192         raise Exception("Scan not completed")
2193
2194 def test_ap_hs20_osen(dev, apdev):
2195     """Hotspot 2.0 OSEN connection"""
2196     params = { 'ssid': "osen",
2197                'osen': "1",
2198                'auth_server_addr': "127.0.0.1",
2199                'auth_server_port': "1812",
2200                'auth_server_shared_secret': "radius" }
2201     hostapd.add_ap(apdev[0], params)
2202
2203     dev[1].connect("osen", key_mgmt="NONE", scan_freq="2412",
2204                    wait_connect=False)
2205     dev[2].connect("osen", key_mgmt="NONE", wep_key0='"hello"',
2206                    scan_freq="2412", wait_connect=False)
2207     dev[0].flush_scan_cache()
2208     dev[0].connect("osen", proto="OSEN", key_mgmt="OSEN", pairwise="CCMP",
2209                    group="GTK_NOT_USED",
2210                    eap="WFA-UNAUTH-TLS", identity="osen@example.com",
2211                    ca_cert="auth_serv/ca.pem",
2212                    scan_freq="2412")
2213     res = dev[0].get_bss(apdev[0]['bssid'])['flags']
2214     if "[OSEN-OSEN-CCMP]" not in res:
2215         raise Exception("OSEN not reported in BSS")
2216     if "[WEP]" in res:
2217         raise Exception("WEP reported in BSS")
2218     res = dev[0].request("SCAN_RESULTS")
2219     if "[OSEN-OSEN-CCMP]" not in res:
2220         raise Exception("OSEN not reported in SCAN_RESULTS")
2221
2222     wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
2223     wpas.interface_add("wlan5", drv_params="force_connect_cmd=1")
2224     wpas.connect("osen", proto="OSEN", key_mgmt="OSEN", pairwise="CCMP",
2225                  group="GTK_NOT_USED",
2226                  eap="WFA-UNAUTH-TLS", identity="osen@example.com",
2227                  ca_cert="auth_serv/ca.pem",
2228                  scan_freq="2412")
2229     wpas.request("DISCONNECT")
2230
2231 def test_ap_hs20_network_preference(dev, apdev):
2232     """Hotspot 2.0 network selection with preferred home network"""
2233     check_eap_capa(dev[0], "MSCHAPV2")
2234     bssid = apdev[0]['bssid']
2235     params = hs20_ap_params()
2236     hostapd.add_ap(apdev[0], params)
2237
2238     dev[0].hs20_enable()
2239     values = { 'realm': "example.com",
2240                'username': "hs20-test",
2241                'password': "password",
2242                'domain': "example.com" }
2243     dev[0].add_cred_values(values)
2244
2245     id = dev[0].add_network()
2246     dev[0].set_network_quoted(id, "ssid", "home")
2247     dev[0].set_network_quoted(id, "psk", "12345678")
2248     dev[0].set_network(id, "priority", "1")
2249     dev[0].request("ENABLE_NETWORK %s no-connect" % id)
2250
2251     dev[0].scan_for_bss(bssid, freq="2412")
2252     dev[0].request("INTERWORKING_SELECT auto freq=2412")
2253     ev = dev[0].wait_connected(timeout=15)
2254     if bssid not in ev:
2255         raise Exception("Unexpected network selected")
2256
2257     bssid2 = apdev[1]['bssid']
2258     params = hostapd.wpa2_params(ssid="home", passphrase="12345678")
2259     hostapd.add_ap(apdev[1], params)
2260
2261     dev[0].scan_for_bss(bssid2, freq="2412")
2262     dev[0].request("INTERWORKING_SELECT auto freq=2412")
2263     ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED",
2264                             "INTERWORKING-ALREADY-CONNECTED" ], timeout=15)
2265     if ev is None:
2266         raise Exception("Connection timed out")
2267     if "INTERWORKING-ALREADY-CONNECTED" in ev:
2268         raise Exception("No roam to higher priority network")
2269     if bssid2 not in ev:
2270         raise Exception("Unexpected network selected")
2271
2272 def test_ap_hs20_network_preference2(dev, apdev):
2273     """Hotspot 2.0 network selection with preferred credential"""
2274     check_eap_capa(dev[0], "MSCHAPV2")
2275     bssid2 = apdev[1]['bssid']
2276     params = hostapd.wpa2_params(ssid="home", passphrase="12345678")
2277     hostapd.add_ap(apdev[1], params)
2278
2279     dev[0].hs20_enable()
2280     values = { 'realm': "example.com",
2281                'username': "hs20-test",
2282                'password': "password",
2283                'domain': "example.com",
2284                'priority': "1" }
2285     dev[0].add_cred_values(values)
2286
2287     id = dev[0].add_network()
2288     dev[0].set_network_quoted(id, "ssid", "home")
2289     dev[0].set_network_quoted(id, "psk", "12345678")
2290     dev[0].request("ENABLE_NETWORK %s no-connect" % id)
2291
2292     dev[0].scan_for_bss(bssid2, freq="2412")
2293     dev[0].request("INTERWORKING_SELECT auto freq=2412")
2294     ev = dev[0].wait_connected(timeout=15)
2295     if bssid2 not in ev:
2296         raise Exception("Unexpected network selected")
2297
2298     bssid = apdev[0]['bssid']
2299     params = hs20_ap_params()
2300     hostapd.add_ap(apdev[0], params)
2301
2302     dev[0].scan_for_bss(bssid, freq="2412")
2303     dev[0].request("INTERWORKING_SELECT auto freq=2412")
2304     ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED",
2305                             "INTERWORKING-ALREADY-CONNECTED" ], timeout=15)
2306     if ev is None:
2307         raise Exception("Connection timed out")
2308     if "INTERWORKING-ALREADY-CONNECTED" in ev:
2309         raise Exception("No roam to higher priority network")
2310     if bssid not in ev:
2311         raise Exception("Unexpected network selected")
2312
2313 def test_ap_hs20_network_preference3(dev, apdev):
2314     """Hotspot 2.0 network selection with two credential (one preferred)"""
2315     check_eap_capa(dev[0], "MSCHAPV2")
2316     bssid = apdev[0]['bssid']
2317     params = hs20_ap_params()
2318     hostapd.add_ap(apdev[0], params)
2319
2320     bssid2 = apdev[1]['bssid']
2321     params = hs20_ap_params(ssid="test-hs20b")
2322     params['nai_realm'] = "0,example.org,13[5:6],21[2:4][5:7]"
2323     hostapd.add_ap(apdev[1], params)
2324
2325     dev[0].hs20_enable()
2326     values = { 'realm': "example.com",
2327                'username': "hs20-test",
2328                'password': "password",
2329                'priority': "1" }
2330     dev[0].add_cred_values(values)
2331     values = { 'realm': "example.org",
2332                'username': "hs20-test",
2333                'password': "password" }
2334     id = dev[0].add_cred_values(values)
2335
2336     dev[0].scan_for_bss(bssid, freq="2412")
2337     dev[0].scan_for_bss(bssid2, freq="2412")
2338     dev[0].request("INTERWORKING_SELECT auto freq=2412")
2339     ev = dev[0].wait_connected(timeout=15)
2340     if bssid not in ev:
2341         raise Exception("Unexpected network selected")
2342
2343     dev[0].set_cred(id, "priority", "2")
2344     dev[0].request("INTERWORKING_SELECT auto freq=2412")
2345     ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED",
2346                             "INTERWORKING-ALREADY-CONNECTED" ], timeout=15)
2347     if ev is None:
2348         raise Exception("Connection timed out")
2349     if "INTERWORKING-ALREADY-CONNECTED" in ev:
2350         raise Exception("No roam to higher priority network")
2351     if bssid2 not in ev:
2352         raise Exception("Unexpected network selected")
2353
2354 def test_ap_hs20_network_preference4(dev, apdev):
2355     """Hotspot 2.0 network selection with username vs. SIM credential"""
2356     check_eap_capa(dev[0], "MSCHAPV2")
2357     bssid = apdev[0]['bssid']
2358     params = hs20_ap_params()
2359     hostapd.add_ap(apdev[0], params)
2360
2361     bssid2 = apdev[1]['bssid']
2362     params = hs20_ap_params(ssid="test-hs20b")
2363     params['hessid'] = bssid2
2364     params['anqp_3gpp_cell_net'] = "555,444"
2365     params['domain_name'] = "wlan.mnc444.mcc555.3gppnetwork.org"
2366     hostapd.add_ap(apdev[1], params)
2367
2368     dev[0].hs20_enable()
2369     values = { 'realm': "example.com",
2370                'username': "hs20-test",
2371                'password': "password",
2372                'priority': "1" }
2373     dev[0].add_cred_values(values)
2374     values = { 'imsi': "555444-333222111",
2375                'eap': "SIM",
2376                'milenage': "5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123" }
2377     id = dev[0].add_cred_values(values)
2378
2379     dev[0].scan_for_bss(bssid, freq="2412")
2380     dev[0].scan_for_bss(bssid2, freq="2412")
2381     dev[0].request("INTERWORKING_SELECT auto freq=2412")
2382     ev = dev[0].wait_connected(timeout=15)
2383     if bssid not in ev:
2384         raise Exception("Unexpected network selected")
2385
2386     dev[0].set_cred(id, "priority", "2")
2387     dev[0].request("INTERWORKING_SELECT auto freq=2412")
2388     ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED",
2389                             "INTERWORKING-ALREADY-CONNECTED" ], timeout=15)
2390     if ev is None:
2391         raise Exception("Connection timed out")
2392     if "INTERWORKING-ALREADY-CONNECTED" in ev:
2393         raise Exception("No roam to higher priority network")
2394     if bssid2 not in ev:
2395         raise Exception("Unexpected network selected")
2396
2397 def test_ap_hs20_interworking_select_blocking_scan(dev, apdev):
2398     """Ongoing INTERWORKING_SELECT blocking SCAN"""
2399     check_eap_capa(dev[0], "MSCHAPV2")
2400     bssid = apdev[0]['bssid']
2401     params = hs20_ap_params()
2402     hostapd.add_ap(apdev[0], params)
2403
2404     dev[0].hs20_enable()
2405     values = { 'realm': "example.com",
2406                'username': "hs20-test",
2407                'password': "password",
2408                'domain': "example.com" }
2409     dev[0].add_cred_values(values)
2410
2411     dev[0].scan_for_bss(bssid, freq="2412")
2412     dev[0].request("INTERWORKING_SELECT auto freq=2412")
2413     if "FAIL-BUSY" not in dev[0].request("SCAN"):
2414         raise Exception("Unexpected SCAN command result")
2415     dev[0].wait_connected(timeout=15)
2416
2417 def test_ap_hs20_fetch_osu(dev, apdev):
2418     """Hotspot 2.0 OSU provider and icon fetch"""
2419     bssid = apdev[0]['bssid']
2420     params = hs20_ap_params()
2421     params['hs20_icon'] = "128:80:zxx:image/png:w1fi_logo:w1fi_logo.png"
2422     params['osu_ssid'] = '"HS 2.0 OSU open"'
2423     params['osu_method_list'] = "1"
2424     params['osu_friendly_name'] = [ "eng:Test OSU", "fin:Testi-OSU" ]
2425     params['osu_icon'] = "w1fi_logo"
2426     params['osu_service_desc'] = [ "eng:Example services", "fin:Esimerkkipalveluja" ]
2427     params['osu_server_uri'] = "https://example.com/osu/"
2428     hostapd.add_ap(apdev[0], params)
2429
2430     bssid2 = apdev[1]['bssid']
2431     params = hs20_ap_params(ssid="test-hs20b")
2432     params['hessid'] = bssid2
2433     params['hs20_icon'] = "128:80:zxx:image/png:w1fi_logo:w1fi_logo.png"
2434     params['osu_ssid'] = '"HS 2.0 OSU OSEN"'
2435     params['osu_method_list'] = "0"
2436     params['osu_nai'] = "osen@example.com"
2437     params['osu_friendly_name'] = [ "eng:Test2 OSU", "fin:Testi2-OSU" ]
2438     params['osu_icon'] = "w1fi_logo"
2439     params['osu_service_desc'] = [ "eng:Example services2", "fin:Esimerkkipalveluja2" ]
2440     params['osu_server_uri'] = "https://example.org/osu/"
2441     hostapd.add_ap(apdev[1], params)
2442
2443     with open("w1fi_logo.png", "r") as f:
2444         orig_logo = f.read()
2445     dev[0].hs20_enable()
2446     dir = "/tmp/osu-fetch"
2447     if os.path.isdir(dir):
2448        files = [ f for f in os.listdir(dir) if f.startswith("osu-") ]
2449        for f in files:
2450            os.remove(dir + "/" + f)
2451     else:
2452         try:
2453             os.makedirs(dir)
2454         except:
2455             pass
2456     try:
2457         dev[1].scan_for_bss(bssid, freq="2412")
2458         dev[2].scan_for_bss(bssid, freq="2412")
2459         dev[0].request("SET osu_dir " + dir)
2460         dev[0].request("FETCH_OSU")
2461         if "FAIL" not in dev[1].request("HS20_ICON_REQUEST foo w1fi_logo"):
2462             raise Exception("Invalid HS20_ICON_REQUEST accepted")
2463         if "OK" not in dev[1].request("HS20_ICON_REQUEST " + bssid + " w1fi_logo"):
2464             raise Exception("HS20_ICON_REQUEST failed")
2465         if "OK" not in dev[2].request("REQ_HS20_ICON " + bssid + " w1fi_logo"):
2466             raise Exception("REQ_HS20_ICON failed")
2467         icons = 0
2468         while True:
2469             ev = dev[0].wait_event(["OSU provider fetch completed",
2470                                     "RX-HS20-ANQP-ICON"], timeout=15)
2471             if ev is None:
2472                 raise Exception("Timeout on OSU fetch")
2473             if "OSU provider fetch completed" in ev:
2474                 break
2475             if "RX-HS20-ANQP-ICON" in ev:
2476                 with open(ev.split(' ')[1], "r") as f:
2477                     logo = f.read()
2478                     if logo == orig_logo:
2479                         icons += 1
2480
2481         with open(dir + "/osu-providers.txt", "r") as f:
2482             prov = f.read()
2483             logger.debug("osu-providers.txt: " + prov)
2484         if "OSU-PROVIDER " + bssid not in prov:
2485             raise Exception("Missing OSU_PROVIDER(1)")
2486         if "OSU-PROVIDER " + bssid2 not in prov:
2487             raise Exception("Missing OSU_PROVIDER(2)")
2488     finally:
2489         files = [ f for f in os.listdir(dir) if f.startswith("osu-") ]
2490         for f in files:
2491             os.remove(dir + "/" + f)
2492         os.rmdir(dir)
2493
2494     if icons != 2:
2495         raise Exception("Unexpected number of icons fetched")
2496
2497     ev = dev[1].wait_event(["GAS-QUERY-START"], timeout=5)
2498     if ev is None:
2499         raise Exception("Timeout on GAS-QUERY-DONE")
2500     ev = dev[1].wait_event(["GAS-QUERY-DONE"], timeout=5)
2501     if ev is None:
2502         raise Exception("Timeout on GAS-QUERY-DONE")
2503     if "freq=2412 status_code=0 result=SUCCESS" not in ev:
2504         raise Exception("Unexpected GAS-QUERY-DONE: " + ev)
2505     ev = dev[1].wait_event(["RX-HS20-ANQP"], timeout=15)
2506     if ev is None:
2507         raise Exception("Timeout on icon fetch")
2508     if "Icon Binary File" not in ev:
2509         raise Exception("Unexpected ANQP element")
2510
2511     ev = dev[2].wait_event(["RX-HS20-ICON"], timeout=5)
2512     if ev is None:
2513         raise Exception("Timeout on RX-HS20-ICON")
2514     event_icon_len = ev.split(' ')[3]
2515     if " w1fi_logo " not in ev:
2516         raise Exception("RX-HS20-ICON did not have the expected file name")
2517     if bssid not in ev:
2518         raise Exception("RX-HS20-ICON did not have the expected BSSID")
2519     if "FAIL" in dev[2].request("GET_HS20_ICON " + bssid + " w1fi_logo 0 10"):
2520         raise Exception("GET_HS20_ICON 0..10 failed")
2521     if "FAIL" in dev[2].request("GET_HS20_ICON " + bssid + " w1fi_logo 5 10"):
2522         raise Exception("GET_HS20_ICON 5..15 failed")
2523     if "FAIL" not in  dev[2].request("GET_HS20_ICON " + bssid + " w1fi_logo 100000 10"):
2524         raise Exception("Unexpected success of GET_HS20_ICON with too large offset")
2525     icon = ""
2526     pos = 0
2527     while True:
2528         if pos > 100000:
2529             raise Exception("Unexpectedly long icon")
2530         res = dev[2].request("GET_HS20_ICON " + bssid + " w1fi_logo %d 1000" % pos)
2531         if res.startswith("FAIL"):
2532             break
2533         icon += base64.b64decode(res)
2534         pos += 1000
2535     hex = binascii.hexlify(icon)
2536     if not hex.startswith("0009696d6167652f706e677d1d"):
2537         raise Exception("Unexpected beacon binary header: " + hex)
2538     with open('w1fi_logo.png', 'r') as f:
2539         data = f.read()
2540         if icon[13:] != data:
2541             raise Exception("Unexpected icon data")
2542     if len(icon) != int(event_icon_len):
2543         raise Exception("Unexpected RX-HS20-ICON event length: " + event_icon_len)
2544
2545     for i in range(3):
2546         if "OK" not in dev[i].request("REQ_HS20_ICON " + bssid + " w1fi_logo"):
2547             raise Exception("REQ_HS20_ICON failed [2]")
2548     for i in range(3):
2549         ev = dev[i].wait_event(["RX-HS20-ICON"], timeout=5)
2550         if ev is None:
2551             raise Exception("Timeout on RX-HS20-ICON [2]")
2552
2553     if "FAIL" not in dev[2].request("DEL_HS20_ICON foo w1fi_logo"):
2554         raise Exception("Invalid DEL_HS20_ICON accepted")
2555     if "OK" not in dev[2].request("DEL_HS20_ICON " + bssid + " w1fi_logo"):
2556         raise Exception("DEL_HS20_ICON failed")
2557     if "OK" not in dev[1].request("DEL_HS20_ICON " + bssid):
2558         raise Exception("DEL_HS20_ICON failed")
2559     if "OK" not in dev[0].request("DEL_HS20_ICON "):
2560         raise Exception("DEL_HS20_ICON failed")
2561     for i in range(3):
2562         if "FAIL" not in dev[i].request("DEL_HS20_ICON "):
2563             raise Exception("DEL_HS20_ICON accepted when no icons left")
2564
2565 def get_icon(dev, bssid, iconname):
2566     icon = ""
2567     pos = 0
2568     while True:
2569         if pos > 100000:
2570             raise Exception("Unexpectedly long icon")
2571         res = dev.request("GET_HS20_ICON " + bssid + " " + iconname + " %d 3000" % pos)
2572         if res.startswith("FAIL"):
2573             break
2574         icon += base64.b64decode(res)
2575         pos += 3000
2576     if len(icon) < 13:
2577         raise Exception("Too short GET_HS20_ICON response")
2578     return icon[0:13], icon[13:]
2579
2580 def test_ap_hs20_req_hs20_icon(dev, apdev):
2581     """Hotspot 2.0 OSU provider and multi-icon fetch with REQ_HS20_ICON"""
2582     bssid = apdev[0]['bssid']
2583     params = hs20_ap_params()
2584     params['hs20_icon'] = [ "128:80:zxx:image/png:w1fi_logo:w1fi_logo.png",
2585                             "128:80:zxx:image/png:test_logo:auth_serv/sha512-server.pem" ]
2586     params['osu_ssid'] = '"HS 2.0 OSU open"'
2587     params['osu_method_list'] = "1"
2588     params['osu_friendly_name'] = [ "eng:Test OSU", "fin:Testi-OSU" ]
2589     params['osu_icon'] = [ "w1fi_logo", "w1fi_logo2" ]
2590     params['osu_service_desc'] = [ "eng:Example services", "fin:Esimerkkipalveluja" ]
2591     params['osu_server_uri'] = "https://example.com/osu/"
2592     hostapd.add_ap(apdev[0], params)
2593
2594     dev[0].scan_for_bss(bssid, freq="2412")
2595
2596     # First, fetch two icons from the AP to wpa_supplicant
2597
2598     if "OK" not in dev[0].request("REQ_HS20_ICON " + bssid + " w1fi_logo"):
2599         raise Exception("REQ_HS20_ICON failed")
2600     ev = dev[0].wait_event(["RX-HS20-ICON"], timeout=5)
2601     if ev is None:
2602         raise Exception("Timeout on RX-HS20-ICON (1)")
2603
2604     if "OK" not in dev[0].request("REQ_HS20_ICON " + bssid + " test_logo"):
2605         raise Exception("REQ_HS20_ICON failed")
2606     ev = dev[0].wait_event(["RX-HS20-ICON"], timeout=5)
2607     if ev is None:
2608         raise Exception("Timeout on RX-HS20-ICON (2)")
2609
2610     # Then, fetch the icons from wpa_supplicant for validation
2611
2612     hdr, data1 = get_icon(dev[0], bssid, "w1fi_logo")
2613     hdr, data2 = get_icon(dev[0], bssid, "test_logo")
2614
2615     with open('w1fi_logo.png', 'r') as f:
2616         data = f.read()
2617         if data1 != data:
2618             raise Exception("Unexpected icon data (1)")
2619
2620     with open('auth_serv/sha512-server.pem', 'r') as f:
2621         data = f.read()
2622         if data2 != data:
2623             raise Exception("Unexpected icon data (2)")
2624
2625     # Finally, delete the icons from wpa_supplicant
2626
2627     if "OK" not in dev[0].request("DEL_HS20_ICON " + bssid + " w1fi_logo"):
2628         raise Exception("DEL_HS20_ICON failed")
2629     if "OK" not in dev[0].request("DEL_HS20_ICON " + bssid + " test_logo"):
2630         raise Exception("DEL_HS20_ICON failed")
2631
2632 def test_ap_hs20_req_hs20_icon_parallel(dev, apdev):
2633     """Hotspot 2.0 OSU provider and multi-icon parallel fetch with REQ_HS20_ICON"""
2634     bssid = apdev[0]['bssid']
2635     params = hs20_ap_params()
2636     params['hs20_icon'] = [ "128:80:zxx:image/png:w1fi_logo:w1fi_logo.png",
2637                             "128:80:zxx:image/png:test_logo:auth_serv/sha512-server.pem" ]
2638     params['osu_ssid'] = '"HS 2.0 OSU open"'
2639     params['osu_method_list'] = "1"
2640     params['osu_friendly_name'] = [ "eng:Test OSU", "fin:Testi-OSU" ]
2641     params['osu_icon'] = [ "w1fi_logo", "w1fi_logo2" ]
2642     params['osu_service_desc'] = [ "eng:Example services", "fin:Esimerkkipalveluja" ]
2643     params['osu_server_uri'] = "https://example.com/osu/"
2644     hostapd.add_ap(apdev[0], params)
2645
2646     dev[0].scan_for_bss(bssid, freq="2412")
2647
2648     # First, fetch two icons from the AP to wpa_supplicant
2649
2650     if "OK" not in dev[0].request("REQ_HS20_ICON " + bssid + " w1fi_logo"):
2651         raise Exception("REQ_HS20_ICON failed")
2652
2653     if "OK" not in dev[0].request("REQ_HS20_ICON " + bssid + " test_logo"):
2654         raise Exception("REQ_HS20_ICON failed")
2655     ev = dev[0].wait_event(["RX-HS20-ICON"], timeout=5)
2656     if ev is None:
2657         raise Exception("Timeout on RX-HS20-ICON (1)")
2658     ev = dev[0].wait_event(["RX-HS20-ICON"], timeout=5)
2659     if ev is None:
2660         raise Exception("Timeout on RX-HS20-ICON (2)")
2661
2662     # Then, fetch the icons from wpa_supplicant for validation
2663
2664     hdr, data1 = get_icon(dev[0], bssid, "w1fi_logo")
2665     hdr, data2 = get_icon(dev[0], bssid, "test_logo")
2666
2667     with open('w1fi_logo.png', 'r') as f:
2668         data = f.read()
2669         if data1 != data:
2670             raise Exception("Unexpected icon data (1)")
2671
2672     with open('auth_serv/sha512-server.pem', 'r') as f:
2673         data = f.read()
2674         if data2 != data:
2675             raise Exception("Unexpected icon data (2)")
2676
2677     # Finally, delete the icons from wpa_supplicant
2678
2679     if "OK" not in dev[0].request("DEL_HS20_ICON " + bssid + " w1fi_logo"):
2680         raise Exception("DEL_HS20_ICON failed")
2681     if "OK" not in dev[0].request("DEL_HS20_ICON " + bssid + " test_logo"):
2682         raise Exception("DEL_HS20_ICON failed")
2683
2684 def test_ap_hs20_fetch_osu_stop(dev, apdev):
2685     """Hotspot 2.0 OSU provider fetch stopped"""
2686     bssid = apdev[0]['bssid']
2687     params = hs20_ap_params()
2688     params['hs20_icon'] = "128:80:zxx:image/png:w1fi_logo:w1fi_logo.png"
2689     params['osu_ssid'] = '"HS 2.0 OSU open"'
2690     params['osu_method_list'] = "1"
2691     params['osu_friendly_name'] = [ "eng:Test OSU", "fin:Testi-OSU" ]
2692     params['osu_icon'] = "w1fi_logo"
2693     params['osu_service_desc'] = [ "eng:Example services", "fin:Esimerkkipalveluja" ]
2694     params['osu_server_uri'] = "https://example.com/osu/"
2695     hapd = hostapd.add_ap(apdev[0], params)
2696
2697     dev[0].hs20_enable()
2698     dir = "/tmp/osu-fetch"
2699     if os.path.isdir(dir):
2700        files = [ f for f in os.listdir(dir) if f.startswith("osu-") ]
2701        for f in files:
2702            os.remove(dir + "/" + f)
2703     else:
2704         try:
2705             os.makedirs(dir)
2706         except:
2707             pass
2708     try:
2709         dev[0].request("SET osu_dir " + dir)
2710         dev[0].request("SCAN freq=2412-2462")
2711         ev = dev[0].wait_event(["CTRL-EVENT-SCAN-STARTED"], timeout=10)
2712         if ev is None:
2713             raise Exception("Scan did not start")
2714         if "FAIL" not in dev[0].request("FETCH_OSU"):
2715             raise Exception("FETCH_OSU accepted while scanning")
2716         ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"], 10)
2717         if ev is None:
2718             raise Exception("Scan timed out")
2719         hapd.set("ext_mgmt_frame_handling", "1")
2720         dev[0].request("FETCH_ANQP")
2721         if "FAIL" not in dev[0].request("FETCH_OSU"):
2722             raise Exception("FETCH_OSU accepted while in FETCH_ANQP")
2723         dev[0].request("STOP_FETCH_ANQP")
2724         dev[0].wait_event(["GAS-QUERY-DONE"], timeout=5)
2725         dev[0].dump_monitor()
2726         hapd.dump_monitor()
2727         dev[0].request("INTERWORKING_SELECT freq=2412")
2728         for i in range(5):
2729             msg = hapd.mgmt_rx()
2730             if msg['subtype'] == 13:
2731                 break
2732         if "FAIL" not in dev[0].request("FETCH_OSU"):
2733             raise Exception("FETCH_OSU accepted while in INTERWORKING_SELECT")
2734         ev = dev[0].wait_event(["INTERWORKING-AP", "INTERWORKING-NO-MATCH"],
2735                                timeout=15)
2736         if ev is None:
2737             raise Exception("Network selection timed out")
2738
2739         dev[0].dump_monitor()
2740         if "OK" not in dev[0].request("FETCH_OSU"):
2741             raise Exception("FETCH_OSU failed")
2742         dev[0].request("CANCEL_FETCH_OSU")
2743
2744         for i in range(15):
2745             time.sleep(0.5)
2746             if dev[0].get_driver_status_field("scan_state") == "SCAN_COMPLETED":
2747                 break
2748
2749         dev[0].dump_monitor()
2750         if "OK" not in dev[0].request("FETCH_OSU"):
2751             raise Exception("FETCH_OSU failed")
2752         if "FAIL" not in dev[0].request("FETCH_OSU"):
2753             raise Exception("FETCH_OSU accepted while in FETCH_OSU")
2754         ev = dev[0].wait_event(["GAS-QUERY-START"], 10)
2755         if ev is None:
2756             raise Exception("GAS timed out")
2757         if "FAIL" not in dev[0].request("FETCH_OSU"):
2758             raise Exception("FETCH_OSU accepted while in FETCH_OSU")
2759         dev[0].request("CANCEL_FETCH_OSU")
2760         ev = dev[0].wait_event(["GAS-QUERY-DONE"], 10)
2761         if ev is None:
2762             raise Exception("GAS event timed out after CANCEL_FETCH_OSU")
2763     finally:
2764         files = [ f for f in os.listdir(dir) if f.startswith("osu-") ]
2765         for f in files:
2766             os.remove(dir + "/" + f)
2767         os.rmdir(dir)
2768
2769 def test_ap_hs20_ft(dev, apdev):
2770     """Hotspot 2.0 connection with FT"""
2771     check_eap_capa(dev[0], "MSCHAPV2")
2772     bssid = apdev[0]['bssid']
2773     params = hs20_ap_params()
2774     params['wpa_key_mgmt'] = "FT-EAP"
2775     params['nas_identifier'] = "nas1.w1.fi"
2776     params['r1_key_holder'] = "000102030405"
2777     params["mobility_domain"] = "a1b2"
2778     params["reassociation_deadline"] = "1000"
2779     hostapd.add_ap(apdev[0], params)
2780
2781     dev[0].hs20_enable()
2782     id = dev[0].add_cred_values({ 'realm': "example.com",
2783                                   'username': "hs20-test",
2784                                   'password': "password",
2785                                   'ca_cert': "auth_serv/ca.pem",
2786                                   'domain': "example.com",
2787                                   'update_identifier': "1234" })
2788     interworking_select(dev[0], bssid, "home", freq="2412")
2789     interworking_connect(dev[0], bssid, "TTLS")
2790
2791 def test_ap_hs20_remediation_sql(dev, apdev, params):
2792     """Hotspot 2.0 connection and remediation required using SQLite for user DB"""
2793     check_eap_capa(dev[0], "MSCHAPV2")
2794     try:
2795         import sqlite3
2796     except ImportError:
2797         raise HwsimSkip("No sqlite3 module available")
2798     dbfile = os.path.join(params['logdir'], "eap-user.db")
2799     try:
2800         os.remove(dbfile)
2801     except:
2802         pass
2803     con = sqlite3.connect(dbfile)
2804     with con:
2805         cur = con.cursor()
2806         cur.execute("CREATE TABLE users(identity TEXT PRIMARY KEY, methods TEXT, password TEXT, remediation TEXT, phase2 INTEGER)")
2807         cur.execute("CREATE TABLE wildcards(identity TEXT PRIMARY KEY, methods TEXT)")
2808         cur.execute("INSERT INTO users(identity,methods,password,phase2,remediation) VALUES ('user-mschapv2','TTLS-MSCHAPV2','password',1,'user')")
2809         cur.execute("INSERT INTO wildcards(identity,methods) VALUES ('','TTLS,TLS')")
2810         cur.execute("CREATE TABLE authlog(timestamp TEXT, session TEXT, nas_ip TEXT, username TEXT, note TEXT)")
2811
2812     try:
2813         params = { "ssid": "as", "beacon_int": "2000",
2814                    "radius_server_clients": "auth_serv/radius_clients.conf",
2815                    "radius_server_auth_port": '18128',
2816                    "eap_server": "1",
2817                    "eap_user_file": "sqlite:" + dbfile,
2818                    "ca_cert": "auth_serv/ca.pem",
2819                    "server_cert": "auth_serv/server.pem",
2820                    "private_key": "auth_serv/server.key",
2821                    "subscr_remediation_url": "https://example.org/",
2822                    "subscr_remediation_method": "1" }
2823         hostapd.add_ap(apdev[1], params)
2824
2825         bssid = apdev[0]['bssid']
2826         params = hs20_ap_params()
2827         params['auth_server_port'] = "18128"
2828         hostapd.add_ap(apdev[0], params)
2829
2830         dev[0].request("SET pmf 1")
2831         dev[0].hs20_enable()
2832         id = dev[0].add_cred_values({ 'realm': "example.com",
2833                                       'username': "user-mschapv2",
2834                                       'password': "password",
2835                                       'ca_cert': "auth_serv/ca.pem" })
2836         interworking_select(dev[0], bssid, freq="2412")
2837         interworking_connect(dev[0], bssid, "TTLS")
2838         ev = dev[0].wait_event(["HS20-SUBSCRIPTION-REMEDIATION"], timeout=5)
2839         if ev is None:
2840             raise Exception("Timeout on subscription remediation notice")
2841         if " 1 https://example.org/" not in ev:
2842             raise Exception("Unexpected subscription remediation event contents")
2843
2844         with con:
2845             cur = con.cursor()
2846             cur.execute("SELECT * from authlog")
2847             rows = cur.fetchall()
2848             if len(rows) < 1:
2849                 raise Exception("No authlog entries")
2850
2851     finally:
2852         os.remove(dbfile)
2853         dev[0].request("SET pmf 0")
2854
2855 def test_ap_hs20_external_selection(dev, apdev):
2856     """Hotspot 2.0 connection using external network selection and creation"""
2857     check_eap_capa(dev[0], "MSCHAPV2")
2858     bssid = apdev[0]['bssid']
2859     params = hs20_ap_params()
2860     params['hessid'] = bssid
2861     params['disable_dgaf'] = '1'
2862     hostapd.add_ap(apdev[0], params)
2863
2864     dev[0].hs20_enable()
2865     dev[0].connect("test-hs20", proto="RSN", key_mgmt="WPA-EAP", eap="TTLS",
2866                    identity="hs20-test", password="password",
2867                    ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
2868                    scan_freq="2412", update_identifier="54321")
2869     if dev[0].get_status_field("hs20") != "2":
2870         raise Exception("Unexpected hs20 indication")
2871
2872 def test_ap_hs20_random_mac_addr(dev, apdev):
2873     """Hotspot 2.0 connection with random MAC address"""
2874     check_eap_capa(dev[0], "MSCHAPV2")
2875     bssid = apdev[0]['bssid']
2876     params = hs20_ap_params()
2877     params['hessid'] = bssid
2878     params['disable_dgaf'] = '1'
2879     hapd = hostapd.add_ap(apdev[0], params)
2880
2881     wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
2882     wpas.interface_add("wlan5")
2883     addr = wpas.p2p_interface_addr()
2884     wpas.request("SET mac_addr 1")
2885     wpas.request("SET preassoc_mac_addr 1")
2886     wpas.request("SET rand_addr_lifetime 60")
2887     wpas.hs20_enable()
2888     wpas.flush_scan_cache()
2889     id = wpas.add_cred_values({ 'realm': "example.com",
2890                                   'username': "hs20-test",
2891                                   'password': "password",
2892                                   'ca_cert': "auth_serv/ca.pem",
2893                                   'domain': "example.com",
2894                                   'update_identifier': "1234" })
2895     interworking_select(wpas, bssid, "home", freq="2412")
2896     interworking_connect(wpas, bssid, "TTLS")
2897     addr1 = wpas.get_driver_status_field("addr")
2898     if addr == addr1:
2899         raise Exception("Did not use random MAC address")
2900
2901     sta = hapd.get_sta(addr)
2902     if sta['addr'] != "FAIL":
2903         raise Exception("Unexpected STA association with permanent address")
2904     sta = hapd.get_sta(addr1)
2905     if sta['addr'] != addr1:
2906         raise Exception("STA association with random address not found")
2907
2908 def test_ap_hs20_multi_network_and_cred_removal(dev, apdev):
2909     """Multiple networks and cred removal"""
2910     check_eap_capa(dev[0], "MSCHAPV2")
2911     bssid = apdev[0]['bssid']
2912     params = hs20_ap_params()
2913     params['nai_realm'] = [ "0,example.com,25[3:26]"]
2914     hapd = hostapd.add_ap(apdev[0], params)
2915
2916     dev[0].add_network()
2917     dev[0].hs20_enable()
2918     id = dev[0].add_cred_values({ 'realm': "example.com",
2919                                   'username': "user",
2920                                   'password': "password" })
2921     interworking_select(dev[0], bssid, freq="2412")
2922     interworking_connect(dev[0], bssid, "PEAP")
2923     dev[0].add_network()
2924
2925     dev[0].request("DISCONNECT")
2926     dev[0].wait_disconnected(timeout=10)
2927
2928     hapd.disable()
2929     hapd.set("ssid", "another ssid")
2930     hapd.enable()
2931
2932     interworking_select(dev[0], bssid, freq="2412")
2933     interworking_connect(dev[0], bssid, "PEAP")
2934     dev[0].add_network()
2935     if len(dev[0].list_networks()) != 5:
2936         raise Exception("Unexpected number of networks prior to remove_crec")
2937
2938     dev[0].dump_monitor()
2939     dev[0].remove_cred(id)
2940     if len(dev[0].list_networks()) != 3:
2941         raise Exception("Unexpected number of networks after to remove_crec")
2942     dev[0].wait_disconnected(timeout=10)
2943
2944 def test_ap_hs20_interworking_add_network(dev, apdev):
2945     """Hotspot 2.0 connection using INTERWORKING_ADD_NETWORK"""
2946     check_eap_capa(dev[0], "MSCHAPV2")
2947     bssid = apdev[0]['bssid']
2948     params = hs20_ap_params()
2949     params['nai_realm'] = [ "0,example.com,21[3:26][6:7][99:99]" ]
2950     hostapd.add_ap(apdev[0], params)
2951
2952     dev[0].hs20_enable()
2953     dev[0].add_cred_values(default_cred(user="user"))
2954     interworking_select(dev[0], bssid, freq=2412)
2955     id = dev[0].interworking_add_network(bssid)
2956     dev[0].select_network(id, freq=2412)
2957     dev[0].wait_connected()
2958
2959 def _test_ap_hs20_proxyarp(dev, apdev):
2960     bssid = apdev[0]['bssid']
2961     params = hs20_ap_params()
2962     params['hessid'] = bssid
2963     params['disable_dgaf'] = '0'
2964     params['proxy_arp'] = '1'
2965     hapd = hostapd.add_ap(apdev[0], params, no_enable=True)
2966     if "OK" in hapd.request("ENABLE"):
2967         raise Exception("Incomplete hostapd configuration was accepted")
2968     hapd.set("ap_isolate", "1")
2969     if "OK" in hapd.request("ENABLE"):
2970         raise Exception("Incomplete hostapd configuration was accepted")
2971     hapd.set('bridge', 'ap-br0')
2972     hapd.dump_monitor()
2973     try:
2974         hapd.enable()
2975     except:
2976         # For now, do not report failures due to missing kernel support
2977         raise HwsimSkip("Could not start hostapd - assume proxyarp not supported in kernel version")
2978     ev = hapd.wait_event(["AP-ENABLED", "AP-DISABLED"], timeout=10)
2979     if ev is None:
2980         raise Exception("AP startup timed out")
2981     if "AP-ENABLED" not in ev:
2982         raise Exception("AP startup failed")
2983
2984     dev[0].hs20_enable()
2985     subprocess.call(['brctl', 'setfd', 'ap-br0', '0'])
2986     subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'up'])
2987
2988     id = dev[0].add_cred_values({ 'realm': "example.com",
2989                                   'username': "hs20-test",
2990                                   'password': "password",
2991                                   'ca_cert': "auth_serv/ca.pem",
2992                                   'domain': "example.com",
2993                                   'update_identifier': "1234" })
2994     interworking_select(dev[0], bssid, "home", freq="2412")
2995     interworking_connect(dev[0], bssid, "TTLS")
2996
2997     dev[1].connect("test-hs20", key_mgmt="WPA-EAP", eap="TTLS",
2998                    identity="hs20-test", password="password",
2999                    ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
3000                    scan_freq="2412")
3001     time.sleep(0.1)
3002
3003     addr0 = dev[0].p2p_interface_addr()
3004     addr1 = dev[1].p2p_interface_addr()
3005
3006     src_ll_opt0 = "\x01\x01" + binascii.unhexlify(addr0.replace(':',''))
3007     src_ll_opt1 = "\x01\x01" + binascii.unhexlify(addr1.replace(':',''))
3008
3009     pkt = build_ns(src_ll=addr0, ip_src="aaaa:bbbb:cccc::2",
3010                    ip_dst="ff02::1:ff00:2", target="aaaa:bbbb:cccc::2",
3011                    opt=src_ll_opt0)
3012     if "OK" not in dev[0].request("DATA_TEST_FRAME " + binascii.hexlify(pkt)):
3013         raise Exception("DATA_TEST_FRAME failed")
3014
3015     pkt = build_ns(src_ll=addr1, ip_src="aaaa:bbbb:dddd::2",
3016                    ip_dst="ff02::1:ff00:2", target="aaaa:bbbb:dddd::2",
3017                    opt=src_ll_opt1)
3018     if "OK" not in dev[1].request("DATA_TEST_FRAME " + binascii.hexlify(pkt)):
3019         raise Exception("DATA_TEST_FRAME failed")
3020
3021     pkt = build_ns(src_ll=addr1, ip_src="aaaa:bbbb:eeee::2",
3022                    ip_dst="ff02::1:ff00:2", target="aaaa:bbbb:eeee::2",
3023                    opt=src_ll_opt1)
3024     if "OK" not in dev[1].request("DATA_TEST_FRAME " + binascii.hexlify(pkt)):
3025         raise Exception("DATA_TEST_FRAME failed")
3026
3027     matches = get_permanent_neighbors("ap-br0")
3028     logger.info("After connect: " + str(matches))
3029     if len(matches) != 3:
3030         raise Exception("Unexpected number of neighbor entries after connect")
3031     if 'aaaa:bbbb:cccc::2 dev ap-br0 lladdr 02:00:00:00:00:00 PERMANENT' not in matches:
3032         raise Exception("dev0 addr missing")
3033     if 'aaaa:bbbb:dddd::2 dev ap-br0 lladdr 02:00:00:00:01:00 PERMANENT' not in matches:
3034         raise Exception("dev1 addr(1) missing")
3035     if 'aaaa:bbbb:eeee::2 dev ap-br0 lladdr 02:00:00:00:01:00 PERMANENT' not in matches:
3036         raise Exception("dev1 addr(2) missing")
3037     dev[0].request("DISCONNECT")
3038     dev[1].request("DISCONNECT")
3039     time.sleep(0.5)
3040     matches = get_permanent_neighbors("ap-br0")
3041     logger.info("After disconnect: " + str(matches))
3042     if len(matches) > 0:
3043         raise Exception("Unexpected neighbor entries after disconnect")
3044
3045 def test_ap_hs20_hidden_ssid_in_scan_res(dev, apdev):
3046     """Hotspot 2.0 connection with hidden SSId in scan results"""
3047     check_eap_capa(dev[0], "MSCHAPV2")
3048     bssid = apdev[0]['bssid']
3049
3050     hapd = hostapd.add_ap(apdev[0], { "ssid": 'secret',
3051                                       "ignore_broadcast_ssid": "1" })
3052     dev[0].scan_for_bss(bssid, freq=2412)
3053     hapd.disable()
3054     hapd_global = hostapd.HostapdGlobal(apdev[0])
3055     hapd_global.flush()
3056     hapd_global.remove(apdev[0]['ifname'])
3057
3058     params = hs20_ap_params()
3059     params['hessid'] = bssid
3060     hapd = hostapd.add_ap(apdev[0], params)
3061
3062     dev[0].hs20_enable()
3063     id = dev[0].add_cred_values({ 'realm': "example.com",
3064                                   'username': "hs20-test",
3065                                   'password': "password",
3066                                   'ca_cert': "auth_serv/ca.pem",
3067                                   'domain': "example.com" })
3068     interworking_select(dev[0], bssid, "home", freq="2412")
3069     interworking_connect(dev[0], bssid, "TTLS")
3070
3071     # clear BSS table to avoid issues in following test cases
3072     dev[0].request("DISCONNECT")
3073     dev[0].wait_disconnected()
3074     hapd.disable()
3075     dev[0].flush_scan_cache()
3076     dev[0].flush_scan_cache()
3077
3078 def test_ap_hs20_proxyarp(dev, apdev):
3079     """Hotspot 2.0 and ProxyARP"""
3080     check_eap_capa(dev[0], "MSCHAPV2")
3081     try:
3082         _test_ap_hs20_proxyarp(dev, apdev)
3083     finally:
3084         subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'down'],
3085                         stderr=open('/dev/null', 'w'))
3086         subprocess.call(['brctl', 'delbr', 'ap-br0'],
3087                         stderr=open('/dev/null', 'w'))
3088
3089 def _test_ap_hs20_proxyarp_dgaf(dev, apdev, disabled):
3090     bssid = apdev[0]['bssid']
3091     params = hs20_ap_params()
3092     params['hessid'] = bssid
3093     params['disable_dgaf'] = '1' if disabled else '0'
3094     params['proxy_arp'] = '1'
3095     params['na_mcast_to_ucast'] = '1'
3096     params['ap_isolate'] = '1'
3097     params['bridge'] = 'ap-br0'
3098     hapd = hostapd.add_ap(apdev[0], params, no_enable=True)
3099     try:
3100         hapd.enable()
3101     except:
3102         # For now, do not report failures due to missing kernel support
3103         raise HwsimSkip("Could not start hostapd - assume proxyarp not supported in kernel version")
3104     ev = hapd.wait_event(["AP-ENABLED"], timeout=10)
3105     if ev is None:
3106         raise Exception("AP startup timed out")
3107
3108     dev[0].hs20_enable()
3109     subprocess.call(['brctl', 'setfd', 'ap-br0', '0'])
3110     subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'up'])
3111
3112     id = dev[0].add_cred_values({ 'realm': "example.com",
3113                                   'username': "hs20-test",
3114                                   'password': "password",
3115                                   'ca_cert': "auth_serv/ca.pem",
3116                                   'domain': "example.com",
3117                                   'update_identifier': "1234" })
3118     interworking_select(dev[0], bssid, "home", freq="2412")
3119     interworking_connect(dev[0], bssid, "TTLS")
3120
3121     dev[1].connect("test-hs20", key_mgmt="WPA-EAP", eap="TTLS",
3122                    identity="hs20-test", password="password",
3123                    ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
3124                    scan_freq="2412")
3125     time.sleep(0.1)
3126
3127     addr0 = dev[0].p2p_interface_addr()
3128
3129     src_ll_opt0 = "\x01\x01" + binascii.unhexlify(addr0.replace(':',''))
3130
3131     pkt = build_ns(src_ll=addr0, ip_src="aaaa:bbbb:cccc::2",
3132                    ip_dst="ff02::1:ff00:2", target="aaaa:bbbb:cccc::2",
3133                    opt=src_ll_opt0)
3134     if "OK" not in dev[0].request("DATA_TEST_FRAME " + binascii.hexlify(pkt)):
3135         raise Exception("DATA_TEST_FRAME failed")
3136
3137     pkt = build_ra(src_ll=apdev[0]['bssid'], ip_src="aaaa:bbbb:cccc::33",
3138                    ip_dst="ff01::1")
3139     if "OK" not in hapd.request("DATA_TEST_FRAME ifname=ap-br0 " + binascii.hexlify(pkt)):
3140         raise Exception("DATA_TEST_FRAME failed")
3141
3142     pkt = build_na(src_ll=apdev[0]['bssid'], ip_src="aaaa:bbbb:cccc::44",
3143                    ip_dst="ff01::1", target="aaaa:bbbb:cccc::55")
3144     if "OK" not in hapd.request("DATA_TEST_FRAME ifname=ap-br0 " + binascii.hexlify(pkt)):
3145         raise Exception("DATA_TEST_FRAME failed")
3146
3147     pkt = build_dhcp_ack(dst_ll="ff:ff:ff:ff:ff:ff", src_ll=bssid,
3148                          ip_src="192.168.1.1", ip_dst="255.255.255.255",
3149                          yiaddr="192.168.1.123", chaddr=addr0)
3150     if "OK" not in hapd.request("DATA_TEST_FRAME ifname=ap-br0 " + binascii.hexlify(pkt)):
3151         raise Exception("DATA_TEST_FRAME failed")
3152     # another copy for additional code coverage
3153     pkt = build_dhcp_ack(dst_ll=addr0, src_ll=bssid,
3154                          ip_src="192.168.1.1", ip_dst="255.255.255.255",
3155                          yiaddr="192.168.1.123", chaddr=addr0)
3156     if "OK" not in hapd.request("DATA_TEST_FRAME ifname=ap-br0 " + binascii.hexlify(pkt)):
3157         raise Exception("DATA_TEST_FRAME failed")
3158
3159     matches = get_permanent_neighbors("ap-br0")
3160     logger.info("After connect: " + str(matches))
3161     if len(matches) != 2:
3162         raise Exception("Unexpected number of neighbor entries after connect")
3163     if 'aaaa:bbbb:cccc::2 dev ap-br0 lladdr 02:00:00:00:00:00 PERMANENT' not in matches:
3164         raise Exception("dev0 addr missing")
3165     if '192.168.1.123 dev ap-br0 lladdr 02:00:00:00:00:00 PERMANENT' not in matches:
3166         raise Exception("dev0 IPv4 addr missing")
3167     dev[0].request("DISCONNECT")
3168     dev[1].request("DISCONNECT")
3169     time.sleep(0.5)
3170     matches = get_permanent_neighbors("ap-br0")
3171     logger.info("After disconnect: " + str(matches))
3172     if len(matches) > 0:
3173         raise Exception("Unexpected neighbor entries after disconnect")
3174
3175 def test_ap_hs20_proxyarp_disable_dgaf(dev, apdev):
3176     """Hotspot 2.0 and ProxyARP with DGAF disabled"""
3177     check_eap_capa(dev[0], "MSCHAPV2")
3178     try:
3179         _test_ap_hs20_proxyarp_dgaf(dev, apdev, True)
3180     finally:
3181         subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'down'],
3182                         stderr=open('/dev/null', 'w'))
3183         subprocess.call(['brctl', 'delbr', 'ap-br0'],
3184                         stderr=open('/dev/null', 'w'))
3185
3186 def test_ap_hs20_proxyarp_enable_dgaf(dev, apdev):
3187     """Hotspot 2.0 and ProxyARP with DGAF enabled"""
3188     check_eap_capa(dev[0], "MSCHAPV2")
3189     try:
3190         _test_ap_hs20_proxyarp_dgaf(dev, apdev, False)
3191     finally:
3192         subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'down'],
3193                         stderr=open('/dev/null', 'w'))
3194         subprocess.call(['brctl', 'delbr', 'ap-br0'],
3195                         stderr=open('/dev/null', 'w'))
3196
3197 def ip_checksum(buf):
3198     sum = 0
3199     if len(buf) & 0x01:
3200         buf += '\0x00'
3201     for i in range(0, len(buf), 2):
3202         val, = struct.unpack('H', buf[i:i+2])
3203         sum += val
3204     while (sum >> 16):
3205         sum = (sum & 0xffff) + (sum >> 16)
3206     return struct.pack('H', ~sum & 0xffff)
3207
3208 def ipv6_solicited_node_mcaddr(target):
3209     prefix = socket.inet_pton(socket.AF_INET6, "ff02::1:ff00:0")
3210     mask = socket.inet_pton(socket.AF_INET6, "::ff:ffff")
3211     _target = socket.inet_pton(socket.AF_INET6, target)
3212     p = struct.unpack('4I', prefix)
3213     m = struct.unpack('4I', mask)
3214     t = struct.unpack('4I', _target)
3215     res = (p[0] | (t[0] & m[0]),
3216            p[1] | (t[1] & m[1]),
3217            p[2] | (t[2] & m[2]),
3218            p[3] | (t[3] & m[3]))
3219     return socket.inet_ntop(socket.AF_INET6, struct.pack('4I', *res))
3220
3221 def build_icmpv6(ipv6_addrs, type, code, payload):
3222     start = struct.pack("BB", type, code)
3223     end = payload
3224     icmp = start + '\x00\x00' + end
3225     pseudo = ipv6_addrs + struct.pack(">LBBBB", len(icmp), 0, 0, 0, 58)
3226     csum = ip_checksum(pseudo + icmp)
3227     return start + csum + end
3228
3229 def build_ra(src_ll, ip_src, ip_dst, cur_hop_limit=0, router_lifetime=0,
3230              reachable_time=0, retrans_timer=0, opt=None):
3231     link_mc = binascii.unhexlify("3333ff000002")
3232     _src_ll = binascii.unhexlify(src_ll.replace(':',''))
3233     proto = '\x86\xdd'
3234     ehdr = link_mc + _src_ll + proto
3235     _ip_src = socket.inet_pton(socket.AF_INET6, ip_src)
3236     _ip_dst = socket.inet_pton(socket.AF_INET6, ip_dst)
3237
3238     adv = struct.pack('>BBHLL', cur_hop_limit, 0, router_lifetime,
3239                       reachable_time, retrans_timer)
3240     if opt:
3241         payload = adv + opt
3242     else:
3243         payload = adv
3244     icmp = build_icmpv6(_ip_src + _ip_dst, 134, 0, payload)
3245
3246     ipv6 = struct.pack('>BBBBHBB', 0x60, 0, 0, 0, len(icmp), 58, 255)
3247     ipv6 += _ip_src + _ip_dst
3248
3249     return ehdr + ipv6 + icmp
3250
3251 def build_ns(src_ll, ip_src, ip_dst, target, opt=None):
3252     link_mc = binascii.unhexlify("3333ff000002")
3253     _src_ll = binascii.unhexlify(src_ll.replace(':',''))
3254     proto = '\x86\xdd'
3255     ehdr = link_mc + _src_ll + proto
3256     _ip_src = socket.inet_pton(socket.AF_INET6, ip_src)
3257     if ip_dst is None:
3258         ip_dst = ipv6_solicited_node_mcaddr(target)
3259     _ip_dst = socket.inet_pton(socket.AF_INET6, ip_dst)
3260
3261     reserved = '\x00\x00\x00\x00'
3262     _target = socket.inet_pton(socket.AF_INET6, target)
3263     if opt:
3264         payload = reserved + _target + opt
3265     else:
3266         payload = reserved + _target
3267     icmp = build_icmpv6(_ip_src + _ip_dst, 135, 0, payload)
3268
3269     ipv6 = struct.pack('>BBBBHBB', 0x60, 0, 0, 0, len(icmp), 58, 255)
3270     ipv6 += _ip_src + _ip_dst
3271
3272     return ehdr + ipv6 + icmp
3273
3274 def send_ns(dev, src_ll=None, target=None, ip_src=None, ip_dst=None, opt=None,
3275             hapd_bssid=None):
3276     if hapd_bssid:
3277         if src_ll is None:
3278             src_ll = hapd_bssid
3279         cmd = "DATA_TEST_FRAME ifname=ap-br0 "
3280     else:
3281         if src_ll is None:
3282             src_ll = dev.p2p_interface_addr()
3283         cmd = "DATA_TEST_FRAME "
3284
3285     if opt is None:
3286         opt = "\x01\x01" + binascii.unhexlify(src_ll.replace(':',''))
3287
3288     pkt = build_ns(src_ll=src_ll, ip_src=ip_src, ip_dst=ip_dst, target=target,
3289                    opt=opt)
3290     if "OK" not in dev.request(cmd + binascii.hexlify(pkt)):
3291         raise Exception("DATA_TEST_FRAME failed")
3292
3293 def build_na(src_ll, ip_src, ip_dst, target, opt=None, flags=0):
3294     link_mc = binascii.unhexlify("3333ff000002")
3295     _src_ll = binascii.unhexlify(src_ll.replace(':',''))
3296     proto = '\x86\xdd'
3297     ehdr = link_mc + _src_ll + proto
3298     _ip_src = socket.inet_pton(socket.AF_INET6, ip_src)
3299     _ip_dst = socket.inet_pton(socket.AF_INET6, ip_dst)
3300
3301     _target = socket.inet_pton(socket.AF_INET6, target)
3302     if opt:
3303         payload = struct.pack('>Bxxx', flags) + _target + opt
3304     else:
3305         payload = struct.pack('>Bxxx', flags) + _target
3306     icmp = build_icmpv6(_ip_src + _ip_dst, 136, 0, payload)
3307
3308     ipv6 = struct.pack('>BBBBHBB', 0x60, 0, 0, 0, len(icmp), 58, 255)
3309     ipv6 += _ip_src + _ip_dst
3310
3311     return ehdr + ipv6 + icmp
3312
3313 def send_na(dev, src_ll=None, target=None, ip_src=None, ip_dst=None, opt=None,
3314             hapd_bssid=None):
3315     if hapd_bssid:
3316         if src_ll is None:
3317             src_ll = hapd_bssid
3318         cmd = "DATA_TEST_FRAME ifname=ap-br0 "
3319     else:
3320         if src_ll is None:
3321             src_ll = dev.p2p_interface_addr()
3322         cmd = "DATA_TEST_FRAME "
3323
3324     pkt = build_na(src_ll=src_ll, ip_src=ip_src, ip_dst=ip_dst, target=target,
3325                    opt=opt)
3326     if "OK" not in dev.request(cmd + binascii.hexlify(pkt)):
3327         raise Exception("DATA_TEST_FRAME failed")
3328
3329 def build_dhcp_ack(dst_ll, src_ll, ip_src, ip_dst, yiaddr, chaddr,
3330                    subnet_mask="255.255.255.0", truncated_opt=False,
3331                    wrong_magic=False, force_tot_len=None, no_dhcp=False):
3332     _dst_ll = binascii.unhexlify(dst_ll.replace(':',''))
3333     _src_ll = binascii.unhexlify(src_ll.replace(':',''))
3334     proto = '\x08\x00'
3335     ehdr = _dst_ll + _src_ll + proto
3336     _ip_src = socket.inet_pton(socket.AF_INET, ip_src)
3337     _ip_dst = socket.inet_pton(socket.AF_INET, ip_dst)
3338     _subnet_mask = socket.inet_pton(socket.AF_INET, subnet_mask)
3339
3340     _ciaddr = '\x00\x00\x00\x00'
3341     _yiaddr = socket.inet_pton(socket.AF_INET, yiaddr)
3342     _siaddr = '\x00\x00\x00\x00'
3343     _giaddr = '\x00\x00\x00\x00'
3344     _chaddr = binascii.unhexlify(chaddr.replace(':','') + "00000000000000000000")
3345     payload = struct.pack('>BBBBL3BB', 2, 1, 6, 0, 12345, 0, 0, 0, 0)
3346     payload += _ciaddr + _yiaddr + _siaddr + _giaddr + _chaddr + 192*'\x00'
3347     # magic
3348     if wrong_magic:
3349         payload += '\x63\x82\x53\x00'
3350     else:
3351         payload += '\x63\x82\x53\x63'
3352     if truncated_opt:
3353         payload += '\x22\xff\x00'
3354     # Option: DHCP Message Type = ACK
3355     payload += '\x35\x01\x05'
3356     # Pad Option
3357     payload += '\x00'
3358     # Option: Subnet Mask
3359     payload += '\x01\x04' + _subnet_mask
3360     # Option: Time Offset
3361     payload += struct.pack('>BBL', 2, 4, 0)
3362     # End Option
3363     payload += '\xff'
3364     # Pad Option
3365     payload += '\x00\x00\x00\x00'
3366
3367     if no_dhcp:
3368         payload = struct.pack('>BBBBL3BB', 2, 1, 6, 0, 12345, 0, 0, 0, 0)
3369         payload += _ciaddr + _yiaddr + _siaddr + _giaddr + _chaddr + 192*'\x00'
3370
3371     udp = struct.pack('>HHHH', 67, 68, 8 + len(payload), 0) + payload
3372
3373     if force_tot_len:
3374         tot_len = force_tot_len
3375     else:
3376         tot_len = 20 + len(udp)
3377     start = struct.pack('>BBHHBBBB', 0x45, 0, tot_len, 0, 0, 0, 128, 17)
3378     ipv4 = start + '\x00\x00' + _ip_src + _ip_dst
3379     csum = ip_checksum(ipv4)
3380     ipv4 = start + csum + _ip_src + _ip_dst
3381
3382     return ehdr + ipv4 + udp
3383
3384 def build_arp(dst_ll, src_ll, opcode, sender_mac, sender_ip,
3385               target_mac, target_ip):
3386     _dst_ll = binascii.unhexlify(dst_ll.replace(':',''))
3387     _src_ll = binascii.unhexlify(src_ll.replace(':',''))
3388     proto = '\x08\x06'
3389     ehdr = _dst_ll + _src_ll + proto
3390
3391     _sender_mac = binascii.unhexlify(sender_mac.replace(':',''))
3392     _sender_ip = socket.inet_pton(socket.AF_INET, sender_ip)
3393     _target_mac = binascii.unhexlify(target_mac.replace(':',''))
3394     _target_ip = socket.inet_pton(socket.AF_INET, target_ip)
3395
3396     arp = struct.pack('>HHBBH', 1, 0x0800, 6, 4, opcode)
3397     arp += _sender_mac + _sender_ip
3398     arp += _target_mac + _target_ip
3399
3400     return ehdr + arp
3401
3402 def send_arp(dev, dst_ll="ff:ff:ff:ff:ff:ff", src_ll=None, opcode=1,
3403              sender_mac=None, sender_ip="0.0.0.0",
3404              target_mac="00:00:00:00:00:00", target_ip="0.0.0.0",
3405              hapd_bssid=None):
3406     if hapd_bssid:
3407         if src_ll is None:
3408             src_ll = hapd_bssid
3409         if sender_mac is None:
3410             sender_mac = hapd_bssid
3411         cmd = "DATA_TEST_FRAME ifname=ap-br0 "
3412     else:
3413         if src_ll is None:
3414             src_ll = dev.p2p_interface_addr()
3415         if sender_mac is None:
3416             sender_mac = dev.p2p_interface_addr()
3417         cmd = "DATA_TEST_FRAME "
3418
3419     pkt = build_arp(dst_ll=dst_ll, src_ll=src_ll, opcode=opcode,
3420                     sender_mac=sender_mac, sender_ip=sender_ip,
3421                     target_mac=target_mac, target_ip=target_ip)
3422     if "OK" not in dev.request(cmd + binascii.hexlify(pkt)):
3423         raise Exception("DATA_TEST_FRAME failed")
3424
3425 def get_permanent_neighbors(ifname):
3426     cmd = subprocess.Popen(['ip', 'nei'], stdout=subprocess.PIPE)
3427     res = cmd.stdout.read()
3428     cmd.stdout.close()
3429     return [ line for line in res.splitlines() if "PERMANENT" in line and ifname in line ]
3430
3431 def get_bridge_macs(ifname):
3432     cmd = subprocess.Popen(['brctl', 'showmacs', ifname],
3433                            stdout=subprocess.PIPE)
3434     res = cmd.stdout.read()
3435     cmd.stdout.close()
3436     return res
3437
3438 def tshark_get_arp(cap, filter):
3439     res = run_tshark(cap, filter,
3440                      [ "eth.dst", "eth.src",
3441                        "arp.src.hw_mac", "arp.src.proto_ipv4",
3442                        "arp.dst.hw_mac", "arp.dst.proto_ipv4" ],
3443                      wait=False)
3444     frames = []
3445     for l in res.splitlines():
3446         frames.append(l.split('\t'))
3447     return frames
3448
3449 def tshark_get_ns(cap):
3450     res = run_tshark(cap, "icmpv6.type == 135",
3451                      [ "eth.dst", "eth.src",
3452                        "ipv6.src", "ipv6.dst",
3453                        "icmpv6.nd.ns.target_address",
3454                        "icmpv6.opt.linkaddr" ],
3455                      wait=False)
3456     frames = []
3457     for l in res.splitlines():
3458         frames.append(l.split('\t'))
3459     return frames
3460
3461 def tshark_get_na(cap):
3462     res = run_tshark(cap, "icmpv6.type == 136",
3463                      [ "eth.dst", "eth.src",
3464                        "ipv6.src", "ipv6.dst",
3465                        "icmpv6.nd.na.target_address",
3466                        "icmpv6.opt.linkaddr" ],
3467                      wait=False)
3468     frames = []
3469     for l in res.splitlines():
3470         frames.append(l.split('\t'))
3471     return frames
3472
3473 def _test_proxyarp_open(dev, apdev, params, ebtables=False):
3474     prefix = "proxyarp_open"
3475     if ebtables:
3476         prefix += "_ebtables"
3477     cap_br = os.path.join(params['logdir'], prefix + ".ap-br0.pcap")
3478     cap_dev0 = os.path.join(params['logdir'],
3479                             prefix + ".%s.pcap" % dev[0].ifname)
3480     cap_dev1 = os.path.join(params['logdir'],
3481                             prefix + ".%s.pcap" % dev[1].ifname)
3482     cap_dev2 = os.path.join(params['logdir'],
3483                             prefix + ".%s.pcap" % dev[2].ifname)
3484
3485     bssid = apdev[0]['bssid']
3486     params = { 'ssid': 'open' }
3487     params['proxy_arp'] = '1'
3488     hapd = hostapd.add_ap(apdev[0], params, no_enable=True)
3489     hapd.set("ap_isolate", "1")
3490     hapd.set('bridge', 'ap-br0')
3491     hapd.dump_monitor()
3492     try:
3493         hapd.enable()
3494     except:
3495         # For now, do not report failures due to missing kernel support
3496         raise HwsimSkip("Could not start hostapd - assume proxyarp not supported in kernel version")
3497     ev = hapd.wait_event(["AP-ENABLED", "AP-DISABLED"], timeout=10)
3498     if ev is None:
3499         raise Exception("AP startup timed out")
3500     if "AP-ENABLED" not in ev:
3501         raise Exception("AP startup failed")
3502
3503     params2 = { 'ssid': 'another' }
3504     hapd2 = hostapd.add_ap(apdev[1], params2, no_enable=True)
3505     hapd2.set('bridge', 'ap-br0')
3506     hapd2.enable()
3507
3508     subprocess.call(['brctl', 'setfd', 'ap-br0', '0'])
3509     subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'up'])
3510
3511     if ebtables:
3512         for chain in [ 'FORWARD', 'OUTPUT' ]:
3513             subprocess.call(['ebtables', '-A', chain, '-p', 'ARP',
3514                              '-d', 'Broadcast', '-o', apdev[0]['ifname'],
3515                              '-j', 'DROP'])
3516             subprocess.call(['ebtables', '-A', chain, '-d', 'Multicast',
3517                              '-p', 'IPv6', '--ip6-protocol', 'ipv6-icmp',
3518                              '--ip6-icmp-type', 'neighbor-solicitation',
3519                              '-o', apdev[0]['ifname'], '-j', 'DROP'])
3520             subprocess.call(['ebtables', '-A', chain, '-d', 'Multicast',
3521                              '-p', 'IPv6', '--ip6-protocol', 'ipv6-icmp',
3522                              '--ip6-icmp-type', 'neighbor-advertisement',
3523                              '-o', apdev[0]['ifname'], '-j', 'DROP'])
3524             subprocess.call(['ebtables', '-A', chain,
3525                              '-p', 'IPv6', '--ip6-protocol', 'ipv6-icmp',
3526                              '--ip6-icmp-type', 'router-solicitation',
3527                              '-o', apdev[0]['ifname'], '-j', 'DROP'])
3528             # Multicast Listener Report Message
3529             subprocess.call(['ebtables', '-A', chain, '-d', 'Multicast',
3530                              '-p', 'IPv6', '--ip6-protocol', 'ipv6-icmp',
3531                              '--ip6-icmp-type', '143',
3532                              '-o', apdev[0]['ifname'], '-j', 'DROP'])
3533
3534     time.sleep(0.5)
3535     cmd = {}
3536     cmd[0] = subprocess.Popen(['tcpdump', '-p', '-U', '-i', 'ap-br0',
3537                                '-w', cap_br, '-s', '2000'],
3538                               stderr=open('/dev/null', 'w'))
3539     cmd[1] = subprocess.Popen(['tcpdump', '-p', '-U', '-i', dev[0].ifname,
3540                                '-w', cap_dev0, '-s', '2000'],
3541                               stderr=open('/dev/null', 'w'))
3542     cmd[2] = subprocess.Popen(['tcpdump', '-p', '-U', '-i', dev[1].ifname,
3543                                '-w', cap_dev1, '-s', '2000'],
3544                               stderr=open('/dev/null', 'w'))
3545     cmd[3] = subprocess.Popen(['tcpdump', '-p', '-U', '-i', dev[2].ifname,
3546                                '-w', cap_dev2, '-s', '2000'],
3547                               stderr=open('/dev/null', 'w'))
3548
3549     dev[0].connect("open", key_mgmt="NONE", scan_freq="2412")
3550     dev[1].connect("open", key_mgmt="NONE", scan_freq="2412")
3551     dev[2].connect("another", key_mgmt="NONE", scan_freq="2412")
3552     time.sleep(0.1)
3553
3554     brcmd = subprocess.Popen(['brctl', 'show'], stdout=subprocess.PIPE)
3555     res = brcmd.stdout.read()
3556     brcmd.stdout.close()
3557     logger.info("Bridge setup: " + res)
3558
3559     brcmd = subprocess.Popen(['brctl', 'showstp', 'ap-br0'],
3560                              stdout=subprocess.PIPE)
3561     res = brcmd.stdout.read()
3562     brcmd.stdout.close()
3563     logger.info("Bridge showstp: " + res)
3564
3565     addr0 = dev[0].p2p_interface_addr()
3566     addr1 = dev[1].p2p_interface_addr()
3567     addr2 = dev[2].p2p_interface_addr()
3568
3569     src_ll_opt0 = "\x01\x01" + binascii.unhexlify(addr0.replace(':',''))
3570     src_ll_opt1 = "\x01\x01" + binascii.unhexlify(addr1.replace(':',''))
3571
3572     # DAD NS
3573     send_ns(dev[0], ip_src="::", target="aaaa:bbbb:cccc::2")
3574
3575     send_ns(dev[0], ip_src="aaaa:bbbb:cccc::2", target="aaaa:bbbb:cccc::2")
3576     # test frame without source link-layer address option
3577     send_ns(dev[0], ip_src="aaaa:bbbb:cccc::2", target="aaaa:bbbb:cccc::2",
3578             opt='')
3579     # test frame with bogus option
3580     send_ns(dev[0], ip_src="aaaa:bbbb:cccc::2", target="aaaa:bbbb:cccc::2",
3581             opt="\x70\x01\x01\x02\x03\x04\x05\x05")
3582     # test frame with truncated source link-layer address option
3583     send_ns(dev[0], ip_src="aaaa:bbbb:cccc::2", target="aaaa:bbbb:cccc::2",
3584             opt="\x01\x01\x01\x02\x03\x04")
3585     # test frame with foreign source link-layer address option
3586     send_ns(dev[0], ip_src="aaaa:bbbb:cccc::2", target="aaaa:bbbb:cccc::2",
3587             opt="\x01\x01\x01\x02\x03\x04\x05\x06")
3588
3589     send_ns(dev[1], ip_src="aaaa:bbbb:dddd::2", target="aaaa:bbbb:dddd::2")
3590
3591     send_ns(dev[1], ip_src="aaaa:bbbb:eeee::2", target="aaaa:bbbb:eeee::2")
3592     # another copy for additional code coverage
3593     send_ns(dev[1], ip_src="aaaa:bbbb:eeee::2", target="aaaa:bbbb:eeee::2")
3594
3595     pkt = build_dhcp_ack(dst_ll="ff:ff:ff:ff:ff:ff", src_ll=bssid,
3596                          ip_src="192.168.1.1", ip_dst="255.255.255.255",
3597                          yiaddr="192.168.1.124", chaddr=addr0)
3598     if "OK" not in hapd.request("DATA_TEST_FRAME ifname=ap-br0 " + binascii.hexlify(pkt)):
3599         raise Exception("DATA_TEST_FRAME failed")
3600     # Change address and verify unicast
3601     pkt = build_dhcp_ack(dst_ll=addr0, src_ll=bssid,
3602                          ip_src="192.168.1.1", ip_dst="255.255.255.255",
3603                          yiaddr="192.168.1.123", chaddr=addr0)
3604     if "OK" not in hapd.request("DATA_TEST_FRAME ifname=ap-br0 " + binascii.hexlify(pkt)):
3605         raise Exception("DATA_TEST_FRAME failed")
3606
3607     # Not-associated client MAC address
3608     pkt = build_dhcp_ack(dst_ll="ff:ff:ff:ff:ff:ff", src_ll=bssid,
3609                          ip_src="192.168.1.1", ip_dst="255.255.255.255",
3610                          yiaddr="192.168.1.125", chaddr="22:33:44:55:66:77")
3611     if "OK" not in hapd.request("DATA_TEST_FRAME ifname=ap-br0 " + binascii.hexlify(pkt)):
3612         raise Exception("DATA_TEST_FRAME failed")
3613
3614     # No IP address
3615     pkt = build_dhcp_ack(dst_ll=addr1, src_ll=bssid,
3616                          ip_src="192.168.1.1", ip_dst="255.255.255.255",
3617                          yiaddr="0.0.0.0", chaddr=addr1)
3618     if "OK" not in hapd.request("DATA_TEST_FRAME ifname=ap-br0 " + binascii.hexlify(pkt)):
3619         raise Exception("DATA_TEST_FRAME failed")
3620
3621     # Zero subnet mask
3622     pkt = build_dhcp_ack(dst_ll=addr1, src_ll=bssid,
3623                          ip_src="192.168.1.1", ip_dst="255.255.255.255",
3624                          yiaddr="192.168.1.126", chaddr=addr1,
3625                          subnet_mask="0.0.0.0")
3626     if "OK" not in hapd.request("DATA_TEST_FRAME ifname=ap-br0 " + binascii.hexlify(pkt)):
3627         raise Exception("DATA_TEST_FRAME failed")
3628
3629     # Truncated option
3630     pkt = build_dhcp_ack(dst_ll=addr1, src_ll=bssid,
3631                          ip_src="192.168.1.1", ip_dst="255.255.255.255",
3632                          yiaddr="192.168.1.127", chaddr=addr1,
3633                          truncated_opt=True)
3634     if "OK" not in hapd.request("DATA_TEST_FRAME ifname=ap-br0 " + binascii.hexlify(pkt)):
3635         raise Exception("DATA_TEST_FRAME failed")
3636
3637     # Wrong magic
3638     pkt = build_dhcp_ack(dst_ll=addr1, src_ll=bssid,
3639                          ip_src="192.168.1.1", ip_dst="255.255.255.255",
3640                          yiaddr="192.168.1.128", chaddr=addr1,
3641                          wrong_magic=True)
3642     if "OK" not in hapd.request("DATA_TEST_FRAME ifname=ap-br0 " + binascii.hexlify(pkt)):
3643         raise Exception("DATA_TEST_FRAME failed")
3644
3645     # Wrong IPv4 total length
3646     pkt = build_dhcp_ack(dst_ll=addr1, src_ll=bssid,
3647                          ip_src="192.168.1.1", ip_dst="255.255.255.255",
3648                          yiaddr="192.168.1.129", chaddr=addr1,
3649                          force_tot_len=1000)
3650     if "OK" not in hapd.request("DATA_TEST_FRAME ifname=ap-br0 " + binascii.hexlify(pkt)):
3651         raise Exception("DATA_TEST_FRAME failed")
3652
3653     # BOOTP
3654     pkt = build_dhcp_ack(dst_ll=addr1, src_ll=bssid,
3655                          ip_src="192.168.1.1", ip_dst="255.255.255.255",
3656                          yiaddr="192.168.1.129", chaddr=addr1,
3657                          no_dhcp=True)
3658     if "OK" not in hapd.request("DATA_TEST_FRAME ifname=ap-br0 " + binascii.hexlify(pkt)):
3659         raise Exception("DATA_TEST_FRAME failed")
3660
3661     macs = get_bridge_macs("ap-br0")
3662     logger.info("After connect (showmacs): " + str(macs))
3663
3664     matches = get_permanent_neighbors("ap-br0")
3665     logger.info("After connect: " + str(matches))
3666     if len(matches) != 4:
3667         raise Exception("Unexpected number of neighbor entries after connect")
3668     if 'aaaa:bbbb:cccc::2 dev ap-br0 lladdr 02:00:00:00:00:00 PERMANENT' not in matches:
3669         raise Exception("dev0 addr missing")
3670     if 'aaaa:bbbb:dddd::2 dev ap-br0 lladdr 02:00:00:00:01:00 PERMANENT' not in matches:
3671         raise Exception("dev1 addr(1) missing")
3672     if 'aaaa:bbbb:eeee::2 dev ap-br0 lladdr 02:00:00:00:01:00 PERMANENT' not in matches:
3673         raise Exception("dev1 addr(2) missing")
3674     if '192.168.1.123 dev ap-br0 lladdr 02:00:00:00:00:00 PERMANENT' not in matches:
3675         raise Exception("dev0 IPv4 addr missing")
3676
3677     targets = [ "192.168.1.123", "192.168.1.124", "192.168.1.125",
3678                 "192.168.1.126" ]
3679     for target in targets:
3680         send_arp(dev[1], sender_ip="192.168.1.100", target_ip=target)
3681
3682     for target in targets:
3683         send_arp(hapd, hapd_bssid=bssid, sender_ip="192.168.1.101",
3684                  target_ip=target)
3685
3686     for target in targets:
3687         send_arp(dev[2], sender_ip="192.168.1.103", target_ip=target)
3688
3689     # ARP Probe from wireless STA
3690     send_arp(dev[1], target_ip="192.168.1.127")
3691     # ARP Announcement from wireless STA
3692     send_arp(dev[1], sender_ip="192.168.1.127", target_ip="192.168.1.127")
3693     send_arp(dev[1], sender_ip="192.168.1.127", target_ip="192.168.1.127",
3694              opcode=2)
3695
3696     macs = get_bridge_macs("ap-br0")
3697     logger.info("After ARP Probe + Announcement (showmacs): " + str(macs))
3698
3699     matches = get_permanent_neighbors("ap-br0")
3700     logger.info("After ARP Probe + Announcement: " + str(matches))
3701
3702     # ARP Request for the newly introduced IP address from wireless STA
3703     send_arp(dev[0], sender_ip="192.168.1.123", target_ip="192.168.1.127")
3704
3705     # ARP Request for the newly introduced IP address from bridge
3706     send_arp(hapd, hapd_bssid=bssid, sender_ip="192.168.1.102",
3707              target_ip="192.168.1.127")
3708     send_arp(dev[2], sender_ip="192.168.1.103", target_ip="192.168.1.127")
3709
3710     # ARP Probe from bridge
3711     send_arp(hapd, hapd_bssid=bssid, target_ip="192.168.1.130")
3712     send_arp(dev[2], target_ip="192.168.1.131")
3713     # ARP Announcement from bridge (not to be learned by AP for proxyarp)
3714     send_arp(hapd, hapd_bssid=bssid, sender_ip="192.168.1.130",
3715              target_ip="192.168.1.130")
3716     send_arp(hapd, hapd_bssid=bssid, sender_ip="192.168.1.130",
3717              target_ip="192.168.1.130", opcode=2)
3718     send_arp(dev[2], sender_ip="192.168.1.131", target_ip="192.168.1.131")
3719     send_arp(dev[2], sender_ip="192.168.1.131", target_ip="192.168.1.131",
3720              opcode=2)
3721
3722     macs = get_bridge_macs("ap-br0")
3723     logger.info("After ARP Probe + Announcement (showmacs): " + str(macs))
3724
3725     matches = get_permanent_neighbors("ap-br0")
3726     logger.info("After ARP Probe + Announcement: " + str(matches))
3727
3728     # ARP Request for the newly introduced IP address from wireless STA
3729     send_arp(dev[0], sender_ip="192.168.1.123", target_ip="192.168.1.130")
3730     # ARP Response from bridge (AP does not proxy for non-wireless devices)
3731     send_arp(hapd, hapd_bssid=bssid, dst_ll=addr0, sender_ip="192.168.1.130",
3732              target_ip="192.168.1.123", opcode=2)
3733
3734     # ARP Request for the newly introduced IP address from wireless STA
3735     send_arp(dev[0], sender_ip="192.168.1.123", target_ip="192.168.1.131")
3736     # ARP Response from bridge (AP does not proxy for non-wireless devices)
3737     send_arp(dev[2], dst_ll=addr0, sender_ip="192.168.1.131",
3738              target_ip="192.168.1.123", opcode=2)
3739
3740     # ARP Request for the newly introduced IP address from bridge
3741     send_arp(hapd, hapd_bssid=bssid, sender_ip="192.168.1.102",
3742              target_ip="192.168.1.130")
3743     send_arp(dev[2], sender_ip="192.168.1.104", target_ip="192.168.1.131")
3744
3745     # ARP Probe from wireless STA (duplicate address; learned through DHCP)
3746     send_arp(dev[1], target_ip="192.168.1.123")
3747     # ARP Probe from wireless STA (duplicate address; learned through ARP)
3748     send_arp(dev[0], target_ip="192.168.1.127")
3749
3750     # Gratuitous ARP Reply for another STA's IP address
3751     send_arp(dev[0], opcode=2, sender_mac=addr0, sender_ip="192.168.1.127",
3752              target_mac=addr1, target_ip="192.168.1.127")
3753     send_arp(dev[1], opcode=2, sender_mac=addr1, sender_ip="192.168.1.123",
3754              target_mac=addr0, target_ip="192.168.1.123")
3755     # ARP Request to verify previous mapping
3756     send_arp(dev[1], sender_ip="192.168.1.127", target_ip="192.168.1.123")
3757     send_arp(dev[0], sender_ip="192.168.1.123", target_ip="192.168.1.127")
3758
3759     time.sleep(0.1)
3760
3761     send_ns(dev[0], target="aaaa:bbbb:dddd::2", ip_src="aaaa:bbbb:cccc::2")
3762     time.sleep(0.1)
3763     send_ns(dev[1], target="aaaa:bbbb:cccc::2", ip_src="aaaa:bbbb:dddd::2")
3764     time.sleep(0.1)
3765     send_ns(hapd, hapd_bssid=bssid, target="aaaa:bbbb:dddd::2",
3766             ip_src="aaaa:bbbb:ffff::2")
3767     time.sleep(0.1)
3768     send_ns(dev[2], target="aaaa:bbbb:cccc::2", ip_src="aaaa:bbbb:ff00::2")
3769     time.sleep(0.1)
3770     send_ns(dev[2], target="aaaa:bbbb:dddd::2", ip_src="aaaa:bbbb:ff00::2")
3771     time.sleep(0.1)
3772     send_ns(dev[2], target="aaaa:bbbb:eeee::2", ip_src="aaaa:bbbb:ff00::2")
3773     time.sleep(0.1)
3774
3775     # Try to probe for an already assigned address
3776     send_ns(dev[1], target="aaaa:bbbb:cccc::2", ip_src="::")
3777     time.sleep(0.1)
3778     send_ns(hapd, hapd_bssid=bssid, target="aaaa:bbbb:cccc::2", ip_src="::")
3779     time.sleep(0.1)
3780     send_ns(dev[2], target="aaaa:bbbb:cccc::2", ip_src="::")
3781     time.sleep(0.1)
3782
3783     # Unsolicited NA
3784     send_na(dev[1], target="aaaa:bbbb:cccc:aeae::3",
3785             ip_src="aaaa:bbbb:cccc:aeae::3", ip_dst="ff02::1")
3786     send_na(hapd, hapd_bssid=bssid, target="aaaa:bbbb:cccc:aeae::4",
3787             ip_src="aaaa:bbbb:cccc:aeae::4", ip_dst="ff02::1")
3788     send_na(dev[2], target="aaaa:bbbb:cccc:aeae::5",
3789             ip_src="aaaa:bbbb:cccc:aeae::5", ip_dst="ff02::1")
3790
3791     try:
3792         hwsim_utils.test_connectivity_iface(dev[0], hapd, "ap-br0")
3793     except Exception, e:
3794         logger.info("test_connectibity_iface failed: " + str(e))
3795         raise HwsimSkip("Assume kernel did not have the required patches for proxyarp")
3796     hwsim_utils.test_connectivity_iface(dev[1], hapd, "ap-br0")
3797     hwsim_utils.test_connectivity(dev[0], dev[1])
3798
3799     dev[0].request("DISCONNECT")
3800     dev[1].request("DISCONNECT")
3801     time.sleep(0.5)
3802     for i in range(len(cmd)):
3803         cmd[i].terminate()
3804     macs = get_bridge_macs("ap-br0")
3805     logger.info("After disconnect (showmacs): " + str(macs))
3806     matches = get_permanent_neighbors("ap-br0")
3807     logger.info("After disconnect: " + str(matches))
3808     if len(matches) > 0:
3809         raise Exception("Unexpected neighbor entries after disconnect")
3810     if ebtables:
3811         cmd = subprocess.Popen(['ebtables', '-L', '--Lc'],
3812                                stdout=subprocess.PIPE)
3813         res = cmd.stdout.read()
3814         cmd.stdout.close()
3815         logger.info("ebtables results:\n" + res)
3816
3817     # Verify that expected ARP messages were seen and no unexpected
3818     # ARP messages were seen.
3819
3820     arp_req = tshark_get_arp(cap_dev0, "arp.opcode == 1")
3821     arp_reply = tshark_get_arp(cap_dev0, "arp.opcode == 2")
3822     logger.info("dev0 seen ARP requests:\n" + str(arp_req))
3823     logger.info("dev0 seen ARP replies:\n" + str(arp_reply))
3824
3825     if [ 'ff:ff:ff:ff:ff:ff', addr1,
3826          addr1, '192.168.1.100',
3827          '00:00:00:00:00:00', '192.168.1.123' ] in arp_req:
3828         raise Exception("dev0 saw ARP request from dev1")
3829     if [ 'ff:ff:ff:ff:ff:ff', addr2,
3830          addr2, '192.168.1.103',
3831          '00:00:00:00:00:00', '192.168.1.123' ] in arp_req:
3832         raise Exception("dev0 saw ARP request from dev2")
3833     # TODO: Uncomment once fixed in kernel
3834     #if [ 'ff:ff:ff:ff:ff:ff', bssid,
3835     #     bssid, '192.168.1.101',
3836     #     '00:00:00:00:00:00', '192.168.1.123' ] in arp_req:
3837     #    raise Exception("dev0 saw ARP request from br")
3838
3839     if ebtables:
3840         for req in arp_req:
3841             if req[1] != addr0:
3842                 raise Exception("Unexpected foreign ARP request on dev0")
3843
3844     arp_req = tshark_get_arp(cap_dev1, "arp.opcode == 1")
3845     arp_reply = tshark_get_arp(cap_dev1, "arp.opcode == 2")
3846     logger.info("dev1 seen ARP requests:\n" + str(arp_req))
3847     logger.info("dev1 seen ARP replies:\n" + str(arp_reply))
3848
3849     if [ 'ff:ff:ff:ff:ff:ff', addr2,
3850          addr2, '192.168.1.103',
3851          '00:00:00:00:00:00', '192.168.1.123' ] in arp_req:
3852         raise Exception("dev1 saw ARP request from dev2")
3853     if [addr1, addr0, addr0, '192.168.1.123', addr1, '192.168.1.100'] not in arp_reply:
3854         raise Exception("dev1 did not get ARP response for 192.168.1.123")
3855
3856     if ebtables:
3857         for req in arp_req:
3858             if req[1] != addr1:
3859                 raise Exception("Unexpected foreign ARP request on dev1")
3860
3861     arp_req = tshark_get_arp(cap_dev2, "arp.opcode == 1")
3862     arp_reply = tshark_get_arp(cap_dev2, "arp.opcode == 2")
3863     logger.info("dev2 seen ARP requests:\n" + str(arp_req))
3864     logger.info("dev2 seen ARP replies:\n" + str(arp_reply))
3865
3866     if [ addr2, addr0,
3867          addr0, '192.168.1.123',
3868          addr2, '192.168.1.103' ] not in arp_reply:
3869         raise Exception("dev2 did not get ARP response for 192.168.1.123")
3870
3871     arp_req = tshark_get_arp(cap_br, "arp.opcode == 1")
3872     arp_reply = tshark_get_arp(cap_br, "arp.opcode == 2")
3873     logger.info("br seen ARP requests:\n" + str(arp_req))
3874     logger.info("br seen ARP replies:\n" + str(arp_reply))
3875
3876     # TODO: Uncomment once fixed in kernel
3877     #if [ bssid, addr0,
3878     #     addr0, '192.168.1.123',
3879     #     bssid, '192.168.1.101' ] not in arp_reply:
3880     #    raise Exception("br did not get ARP response for 192.168.1.123")
3881
3882     ns = tshark_get_ns(cap_dev0)
3883     logger.info("dev0 seen NS: " + str(ns))
3884     na = tshark_get_na(cap_dev0)
3885     logger.info("dev0 seen NA: " + str(na))
3886
3887     if [ addr0, addr1, 'aaaa:bbbb:dddd::2', 'aaaa:bbbb:cccc::2',
3888          'aaaa:bbbb:dddd::2', addr1 ] not in na:
3889         raise Exception("dev0 did not get NA for aaaa:bbbb:dddd::2")
3890
3891     if ebtables:
3892         for req in ns:
3893             if req[1] != addr0:
3894                 raise Exception("Unexpected foreign NS on dev0: " + str(req))
3895
3896     ns = tshark_get_ns(cap_dev1)
3897     logger.info("dev1 seen NS: " + str(ns))
3898     na = tshark_get_na(cap_dev1)
3899     logger.info("dev1 seen NA: " + str(na))
3900
3901     if [ addr1, addr0, 'aaaa:bbbb:cccc::2', 'aaaa:bbbb:dddd::2',
3902          'aaaa:bbbb:cccc::2', addr0 ] not in na:
3903         raise Exception("dev1 did not get NA for aaaa:bbbb:cccc::2")
3904
3905     if ebtables:
3906         for req in ns:
3907             if req[1] != addr1:
3908                 raise Exception("Unexpected foreign NS on dev1: " + str(req))
3909
3910     ns = tshark_get_ns(cap_dev2)
3911     logger.info("dev2 seen NS: " + str(ns))
3912     na = tshark_get_na(cap_dev2)
3913     logger.info("dev2 seen NA: " + str(na))
3914
3915     # FIX: enable once kernel implementation for proxyarp IPv6 is fixed
3916     #if [ addr2, addr0, 'aaaa:bbbb:cccc::2', 'aaaa:bbbb:ff00::2',
3917     #     'aaaa:bbbb:cccc::2', addr0 ] not in na:
3918     #    raise Exception("dev2 did not get NA for aaaa:bbbb:cccc::2")
3919     #if [ addr2, addr1, 'aaaa:bbbb:dddd::2', 'aaaa:bbbb:ff00::2',
3920     #     'aaaa:bbbb:dddd::2', addr1 ] not in na:
3921     #    raise Exception("dev2 did not get NA for aaaa:bbbb:dddd::2")
3922     #if [ addr2, addr1, 'aaaa:bbbb:eeee::2', 'aaaa:bbbb:ff00::2',
3923     #     'aaaa:bbbb:eeee::2', addr1 ] not in na:
3924     #    raise Exception("dev2 did not get NA for aaaa:bbbb:eeee::2")
3925
3926 def test_proxyarp_open(dev, apdev, params):
3927     """ProxyARP with open network"""
3928     try:
3929         _test_proxyarp_open(dev, apdev, params)
3930     finally:
3931         subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'down'],
3932                         stderr=open('/dev/null', 'w'))
3933         subprocess.call(['brctl', 'delbr', 'ap-br0'],
3934                         stderr=open('/dev/null', 'w'))
3935
3936 def test_proxyarp_open_ebtables(dev, apdev, params):
3937     """ProxyARP with open network"""
3938     try:
3939         _test_proxyarp_open(dev, apdev, params, ebtables=True)
3940     finally:
3941         try:
3942             subprocess.call(['ebtables', '-F', 'FORWARD'])
3943             subprocess.call(['ebtables', '-F', 'OUTPUT'])
3944         except:
3945             pass
3946         subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'down'],
3947                         stderr=open('/dev/null', 'w'))
3948         subprocess.call(['brctl', 'delbr', 'ap-br0'],
3949                         stderr=open('/dev/null', 'w'))
3950
3951 def test_ap_hs20_connect_deinit(dev, apdev):
3952     """Hotspot 2.0 connection interrupted with deinit"""
3953     check_eap_capa(dev[0], "MSCHAPV2")
3954     bssid = apdev[0]['bssid']
3955     params = hs20_ap_params()
3956     params['hessid'] = bssid
3957     hapd = hostapd.add_ap(apdev[0], params)
3958
3959     wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
3960     wpas.interface_add("wlan5", drv_params="")
3961     wpas.hs20_enable()
3962     wpas.flush_scan_cache()
3963     wpas.add_cred_values({ 'realm': "example.com",
3964                            'username': "hs20-test",
3965                            'password': "password",
3966                            'ca_cert': "auth_serv/ca.pem",
3967                            'domain': "example.com" })
3968
3969     wpas.scan_for_bss(bssid, freq=2412)
3970     hapd.disable()
3971
3972     wpas.request("INTERWORKING_SELECT freq=2412")
3973
3974     id = wpas.request("RADIO_WORK add block-work")
3975     ev = wpas.wait_event(["GAS-QUERY-START", "EXT-RADIO-WORK-START"], timeout=5)
3976     if ev is None:
3977         raise Exception("Timeout while waiting radio work to start")
3978     ev = wpas.wait_event(["GAS-QUERY-START", "EXT-RADIO-WORK-START"], timeout=5)
3979     if ev is None:
3980         raise Exception("Timeout while waiting radio work to start (2)")
3981
3982     # Remove the interface while the gas-query radio work is still pending and
3983     # GAS query has not yet been started.
3984     wpas.interface_remove("wlan5")
3985
3986 def test_ap_hs20_anqp_format_errors(dev, apdev):
3987     """Interworking network selection and ANQP format errors"""
3988     bssid = apdev[0]['bssid']
3989     params = hs20_ap_params()
3990     params['hessid'] = bssid
3991     hapd = hostapd.add_ap(apdev[0], params)
3992
3993     dev[0].hs20_enable()
3994     values = { 'realm': "example.com",
3995                'ca_cert': "auth_serv/ca.pem",
3996                'username': "hs20-test",
3997                'password': "password",
3998                'domain': "example.com" }
3999     id = dev[0].add_cred_values(values)
4000
4001     dev[0].scan_for_bss(bssid, freq="2412")
4002
4003     tests = [ "00", "ffff", "010011223344", "020008000005112233445500",
4004               "01000400000000", "01000000000000",
4005               "01000300000200", "0100040000ff0000", "01000300000100",
4006               "01000300000001",
4007               "01000600000056112233",
4008               "01000900000002050001000111",
4009               "01000600000001000000", "01000600000001ff0000",
4010               "01000600000001020001",
4011               "010008000000010400010001", "0100080000000104000100ff",
4012               "010011000000010d00050200020100030005000600",
4013               "0000" ]
4014     for t in tests:
4015         hapd.set("anqp_elem", "263:" + t)
4016         dev[0].request("INTERWORKING_SELECT freq=2412")
4017         ev = dev[0].wait_event(["INTERWORKING-NO-MATCH"], timeout=5)
4018         if ev is None:
4019             raise Exception("Network selection timed out")
4020         dev[0].dump_monitor()
4021
4022     dev[0].remove_cred(id)
4023     id = dev[0].add_cred_values({ 'imsi': "555444-333222111", 'eap': "AKA",
4024                                   'milenage': "5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123"})
4025
4026     tests = [ "00", "0100", "0001", "00ff", "000200ff", "0003000101",
4027               "00020100" ]
4028     for t in tests:
4029         hapd.set("anqp_elem", "264:" + t)
4030         dev[0].request("INTERWORKING_SELECT freq=2412")
4031         ev = dev[0].wait_event(["INTERWORKING-NO-MATCH"], timeout=5)
4032         if ev is None:
4033             raise Exception("Network selection timed out")
4034         dev[0].dump_monitor()
4035
4036 def test_ap_hs20_cred_with_nai_realm(dev, apdev):
4037     """Hotspot 2.0 network selection and cred_with_nai_realm cred->realm"""
4038     bssid = apdev[0]['bssid']
4039     params = hs20_ap_params()
4040     params['hessid'] = bssid
4041     hostapd.add_ap(apdev[0], params)
4042
4043     dev[0].hs20_enable()
4044
4045     id = dev[0].add_cred_values({ 'realm': "example.com",
4046                                   'username': "test",
4047                                   'password': "secret",
4048                                   'domain': "example.com",
4049                                   'eap': 'TTLS' })
4050     interworking_select(dev[0], bssid, "home", freq=2412)
4051     dev[0].remove_cred(id)
4052
4053     id = dev[0].add_cred_values({ 'realm': "foo.com",
4054                                   'username': "test",
4055                                   'password': "secret",
4056                                   'domain': "example.com",
4057                                   'roaming_consortium': "112234",
4058                                   'eap': 'TTLS' })
4059     interworking_select(dev[0], bssid, "home", freq=2412, no_match=True)
4060     dev[0].remove_cred(id)
4061
4062 def test_ap_hs20_cred_and_no_roaming_consortium(dev, apdev):
4063     """Hotspot 2.0 network selection and no roaming consortium"""
4064     bssid = apdev[0]['bssid']
4065     params = hs20_ap_params()
4066     params['hessid'] = bssid
4067     del params['roaming_consortium']
4068     hostapd.add_ap(apdev[0], params)
4069
4070     dev[0].hs20_enable()
4071
4072     id = dev[0].add_cred_values({ 'realm': "example.com",
4073                                   'username': "test",
4074                                   'password': "secret",
4075                                   'domain': "example.com",
4076                                   'roaming_consortium': "112234",
4077                                   'eap': 'TTLS' })
4078     interworking_select(dev[0], bssid, "home", freq=2412, no_match=True)
4079
4080 def test_ap_hs20_interworking_oom(dev, apdev):
4081     """Hotspot 2.0 network selection and OOM"""
4082     bssid = apdev[0]['bssid']
4083     params = hs20_ap_params()
4084     params['hessid'] = bssid
4085     params['nai_realm'] = [ "0,no.match.here;example.com;no.match.here.either,21[2:1][5:7]",
4086                             "0,example.com,13[5:6],21[2:4][5:7]",
4087                             "0,another.example.com" ]
4088     hostapd.add_ap(apdev[0], params)
4089
4090     dev[0].hs20_enable()
4091
4092     id = dev[0].add_cred_values({ 'realm': "example.com",
4093                                   'username': "test",
4094                                   'password': "secret",
4095                                   'domain': "example.com",
4096                                   'eap': 'TTLS' })
4097
4098     dev[0].scan_for_bss(bssid, freq="2412")
4099
4100     funcs = [ "wpabuf_alloc;interworking_anqp_send_req",
4101               "anqp_build_req;interworking_anqp_send_req",
4102               "gas_query_req;interworking_anqp_send_req",
4103               "dup_binstr;nai_realm_parse_realm",
4104               "=nai_realm_parse_realm",
4105               "=nai_realm_parse",
4106               "=nai_realm_match" ]
4107     for func in funcs:
4108         with alloc_fail(dev[0], 1, func):
4109             dev[0].request("INTERWORKING_SELECT auto freq=2412")
4110             ev = dev[0].wait_event(["Starting ANQP"], timeout=5)
4111             if ev is None:
4112                 raise Exception("ANQP did not start")
4113             wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")