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