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