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