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    hapd = 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    hapd.wait_sta()
705    sta = hapd.get_sta(dev[0].own_addr())
706    if sta['dot1xAuthSessionUserName'] != "anonymous@example.com":
707        raise Exception("Unexpected anonymous identity: " + sta['dot1xAuthSessionUserName'])
708
709    dev[1].connect("test-hs20", key_mgmt="WPA-EAP", eap="TTLS",
710                   identity="hs20-test", password="password",
711                   ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
712                   scan_freq="2412")
713
714def test_ap_hs20_username_with_realm(dev, apdev):
715    """Hotspot 2.0 connection in username-with-realm/password credential"""
716    check_eap_capa(dev[0], "MSCHAPV2")
717    bssid = apdev[0]['bssid']
718    params = hs20_ap_params()
719    params['hessid'] = bssid
720    params['disable_dgaf'] = '1'
721    hapd = hostapd.add_ap(apdev[0], params)
722
723    dev[0].hs20_enable()
724    id = dev[0].add_cred_values({'realm': "example.com",
725                                 'username': "hs20-test@inner.com",
726                                 'password': "password2",
727                                 'ca_cert': "auth_serv/ca.pem",
728                                 'domain': "example.com"})
729    interworking_select(dev[0], bssid, "home", freq="2412")
730    interworking_connect(dev[0], bssid, "TTLS")
731    check_sp_type(dev[0], "home")
732    hapd.wait_sta()
733    sta = hapd.get_sta(dev[0].own_addr())
734    if sta['dot1xAuthSessionUserName'] != "anonymous@example.com":
735        raise Exception("Unexpected anonymous identity: " + sta['dot1xAuthSessionUserName'])
736
737def test_ap_hs20_connect_api(dev, apdev):
738    """Hotspot 2.0 connection with connect API"""
739    check_eap_capa(dev[0], "MSCHAPV2")
740    bssid = apdev[0]['bssid']
741    params = hs20_ap_params()
742    params['hessid'] = bssid
743    params['disable_dgaf'] = '1'
744    hostapd.add_ap(apdev[0], params)
745
746    wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
747    wpas.interface_add("wlan5", drv_params="force_connect_cmd=1")
748    wpas.hs20_enable()
749    wpas.flush_scan_cache()
750    id = wpas.add_cred_values({'realm': "example.com",
751                               'username': "hs20-test",
752                               'password': "password",
753                               'ca_cert': "auth_serv/ca.pem",
754                               'domain': "example.com",
755                               'update_identifier': "1234"})
756    interworking_select(wpas, bssid, "home", freq="2412")
757    interworking_connect(wpas, bssid, "TTLS")
758    check_sp_type(wpas, "home")
759    status = wpas.get_status()
760    if status['pairwise_cipher'] != "CCMP":
761        raise Exception("Unexpected pairwise cipher")
762    if status['hs20'] != "3":
763        raise Exception("Unexpected HS 2.0 support indication")
764
765def test_ap_hs20_auto_interworking(dev, apdev):
766    """Hotspot 2.0 connection with auto_interworking=1"""
767    check_eap_capa(dev[0], "MSCHAPV2")
768    bssid = apdev[0]['bssid']
769    params = hs20_ap_params()
770    params['hessid'] = bssid
771    params['disable_dgaf'] = '1'
772    hostapd.add_ap(apdev[0], params)
773
774    dev[0].hs20_enable(auto_interworking=True)
775    id = dev[0].add_cred_values({'realm': "example.com",
776                                 'username': "hs20-test",
777                                 'password': "password",
778                                 'ca_cert': "auth_serv/ca.pem",
779                                 'domain': "example.com",
780                                 'update_identifier': "1234"})
781    dev[0].request("REASSOCIATE")
782    dev[0].wait_connected(timeout=15)
783    check_sp_type(dev[0], "home")
784    status = dev[0].get_status()
785    if status['pairwise_cipher'] != "CCMP":
786        raise Exception("Unexpected pairwise cipher")
787    if status['hs20'] != "3":
788        raise Exception("Unexpected HS 2.0 support indication")
789
790def test_ap_hs20_auto_interworking_global_pmf(dev, apdev):
791    """Hotspot 2.0 connection with auto_interworking=1 and pmf=2"""
792    check_eap_capa(dev[0], "MSCHAPV2")
793    bssid = apdev[0]['bssid']
794    params = hs20_ap_params()
795    params['hessid'] = bssid
796    hostapd.add_ap(apdev[0], params)
797
798    dev[0].hs20_enable(auto_interworking=True)
799    id = dev[0].add_cred_values({'realm': "example.com",
800                                 'username': "hs20-test",
801                                 'password': "password",
802                                 'ca_cert': "auth_serv/ca.pem",
803                                 'domain': "example.com",
804                                 'update_identifier': "1234"})
805    try:
806        dev[0].set("pmf", "2")
807        dev[0].request("REASSOCIATE")
808        dev[0].wait_connected(timeout=15)
809        pmf = dev[0].get_status_field("pmf")
810        if pmf != "1":
811            raise Exception("Unexpected PMF state: " + str(pmf))
812    finally:
813        dev[0].set("pmf", "0")
814
815def test_ap_hs20_auto_interworking_global_pmf_fail(dev, apdev):
816    """Hotspot 2.0 connection with auto_interworking=1 and pmf=2 failure"""
817    check_eap_capa(dev[0], "MSCHAPV2")
818    bssid = apdev[0]['bssid']
819    params = hs20_ap_params()
820    params['ieee80211w'] = "0"
821    params['hessid'] = bssid
822    hostapd.add_ap(apdev[0], params)
823
824    dev[0].hs20_enable(auto_interworking=True)
825    id = dev[0].add_cred_values({'realm': "example.com",
826                                 'username': "hs20-test",
827                                 'password': "password",
828                                 'ca_cert': "auth_serv/ca.pem",
829                                 'domain': "example.com",
830                                 'update_identifier': "1234"})
831    try:
832        dev[0].set("pmf", "2")
833        dev[0].request("REASSOCIATE")
834        for i in range(2):
835            ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED",
836                                    "INTERWORKING-SELECTED"], timeout=15)
837            if ev is None:
838                raise Exception("Connection result not reported")
839            if "CTRL-EVENT-CONNECTED" in ev:
840                raise Exception("Unexpected connection")
841        dev[0].request("DISCONNECT")
842    finally:
843        dev[0].set("pmf", "0")
844
845@remote_compatible
846def test_ap_hs20_auto_interworking_no_match(dev, apdev):
847    """Hotspot 2.0 connection with auto_interworking=1 and no matching network"""
848    hapd = hostapd.add_ap(apdev[0], {"ssid": "mismatch"})
849
850    dev[0].hs20_enable(auto_interworking=True)
851    id = dev[0].connect("mismatch", psk="12345678", scan_freq="2412",
852                        only_add_network=True)
853    dev[0].request("ENABLE_NETWORK " + str(id) + " no-connect")
854
855    id = dev[0].add_cred_values({'realm': "example.com",
856                                 'username': "hs20-test",
857                                 'password': "password",
858                                 'ca_cert': "auth_serv/ca.pem",
859                                 'domain': "example.com",
860                                 'update_identifier': "1234"})
861    dev[0].request("INTERWORKING_SELECT auto freq=2412")
862    time.sleep(0.1)
863    dev[0].dump_monitor()
864    for i in range(5):
865        logger.info("start ping")
866        if "PONG" not in dev[0].ctrl.request("PING", timeout=2):
867            raise Exception("PING failed")
868        logger.info("ping done")
869        fetch = 0
870        scan = 0
871        for j in range(15):
872            ev = dev[0].wait_event(["ANQP fetch completed",
873                                    "CTRL-EVENT-SCAN-RESULTS"], timeout=0.05)
874            if ev is None:
875                break
876            if "ANQP fetch completed" in ev:
877                fetch += 1
878            else:
879                scan += 1
880        if fetch > 2 * scan + 3:
881            raise Exception("Too many ANQP fetch iterations")
882        dev[0].dump_monitor()
883    dev[0].request("DISCONNECT")
884
885@remote_compatible
886def test_ap_hs20_auto_interworking_no_cred_match(dev, apdev):
887    """Hotspot 2.0 connection with auto_interworking=1 but no cred match"""
888    bssid = apdev[0]['bssid']
889    params = {"ssid": "test"}
890    hostapd.add_ap(apdev[0], params)
891
892    dev[0].hs20_enable(auto_interworking=True)
893    dev[0].add_cred_values({'realm': "example.com",
894                            'username': "hs20-test",
895                            'password': "password",
896                            'ca_cert': "auth_serv/ca.pem",
897                            'domain': "example.com"})
898
899    id = dev[0].connect("test", psk="12345678", only_add_network=True)
900    dev[0].request("ENABLE_NETWORK %s" % id)
901    logger.info("Verify that scanning continues when there is partial network block match")
902    for i in range(0, 2):
903        ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"], 10)
904        if ev is None:
905            raise Exception("Scan timed out")
906        logger.info("Scan completed")
907
908def eap_test(dev, ap, eap_params, method, user, release=0):
909    bssid = ap['bssid']
910    params = hs20_ap_params()
911    params['nai_realm'] = ["0,example.com," + eap_params]
912    if release > 0:
913        params['hs20_release'] = str(release)
914    hapd = hostapd.add_ap(ap, params)
915
916    dev.flush_scan_cache()
917    dev.hs20_enable()
918    dev.add_cred_values({'realm': "example.com",
919                         'ca_cert': "auth_serv/ca.pem",
920                         'username': user,
921                         'password': "password"})
922    interworking_select(dev, bssid, freq="2412")
923    interworking_connect(dev, bssid, method)
924    return hapd
925
926@remote_compatible
927def test_ap_hs20_eap_unknown(dev, apdev):
928    """Hotspot 2.0 connection with unknown EAP method"""
929    bssid = apdev[0]['bssid']
930    params = hs20_ap_params()
931    params['nai_realm'] = "0,example.com,99"
932    hostapd.add_ap(apdev[0], params)
933
934    dev[0].hs20_enable()
935    dev[0].add_cred_values(default_cred())
936    interworking_select(dev[0], None, no_match=True, freq="2412")
937
938def test_ap_hs20_eap_peap_mschapv2(dev, apdev):
939    """Hotspot 2.0 connection with PEAP/MSCHAPV2"""
940    check_eap_capa(dev[0], "MSCHAPV2")
941    eap_test(dev[0], apdev[0], "25[3:26]", "PEAP", "user")
942
943def test_ap_hs20_eap_peap_default(dev, apdev):
944    """Hotspot 2.0 connection with PEAP/MSCHAPV2 (as default)"""
945    check_eap_capa(dev[0], "MSCHAPV2")
946    eap_test(dev[0], apdev[0], "25", "PEAP", "user")
947
948def test_ap_hs20_eap_peap_gtc(dev, apdev):
949    """Hotspot 2.0 connection with PEAP/GTC"""
950    eap_test(dev[0], apdev[0], "25[3:6]", "PEAP", "user")
951
952@remote_compatible
953def test_ap_hs20_eap_peap_unknown(dev, apdev):
954    """Hotspot 2.0 connection with PEAP/unknown"""
955    bssid = apdev[0]['bssid']
956    params = hs20_ap_params()
957    params['nai_realm'] = "0,example.com,25[3:99]"
958    hostapd.add_ap(apdev[0], params)
959
960    dev[0].hs20_enable()
961    dev[0].add_cred_values(default_cred())
962    interworking_select(dev[0], None, no_match=True, freq="2412")
963
964def test_ap_hs20_eap_ttls_chap(dev, apdev):
965    """Hotspot 2.0 connection with TTLS/CHAP"""
966    skip_with_fips(dev[0])
967    eap_test(dev[0], apdev[0], "21[2:2]", "TTLS", "chap user")
968
969def test_ap_hs20_eap_ttls_mschap(dev, apdev):
970    """Hotspot 2.0 connection with TTLS/MSCHAP"""
971    skip_with_fips(dev[0])
972    eap_test(dev[0], apdev[0], "21[2:3]", "TTLS", "mschap user")
973
974def test_ap_hs20_eap_ttls_default(dev, apdev):
975    """Hotspot 2.0 connection with TTLS/default"""
976    skip_with_fips(dev[0])
977    eap_test(dev[0], apdev[0], "21", "TTLS", "hs20-test")
978
979def test_ap_hs20_eap_ttls_eap_mschapv2(dev, apdev):
980    """Hotspot 2.0 connection with TTLS/EAP-MSCHAPv2"""
981    check_eap_capa(dev[0], "MSCHAPV2")
982    eap_test(dev[0], apdev[0], "21[3:26][6:7][99:99]", "TTLS", "user")
983
984@remote_compatible
985def test_ap_hs20_eap_ttls_eap_unknown(dev, apdev):
986    """Hotspot 2.0 connection with TTLS/EAP-unknown"""
987    bssid = apdev[0]['bssid']
988    params = hs20_ap_params()
989    params['nai_realm'] = "0,example.com,21[3:99]"
990    hostapd.add_ap(apdev[0], params)
991
992    dev[0].hs20_enable()
993    dev[0].add_cred_values(default_cred())
994    interworking_select(dev[0], None, no_match=True, freq="2412")
995
996@remote_compatible
997def test_ap_hs20_eap_ttls_eap_unsupported(dev, apdev):
998    """Hotspot 2.0 connection with TTLS/EAP-OTP(unsupported)"""
999    bssid = apdev[0]['bssid']
1000    params = hs20_ap_params()
1001    params['nai_realm'] = "0,example.com,21[3:5]"
1002    hostapd.add_ap(apdev[0], params)
1003
1004    dev[0].hs20_enable()
1005    dev[0].add_cred_values(default_cred())
1006    interworking_select(dev[0], None, no_match=True, freq="2412")
1007
1008@remote_compatible
1009def test_ap_hs20_eap_ttls_unknown(dev, apdev):
1010    """Hotspot 2.0 connection with TTLS/unknown"""
1011    bssid = apdev[0]['bssid']
1012    params = hs20_ap_params()
1013    params['nai_realm'] = "0,example.com,21[2:5]"
1014    hostapd.add_ap(apdev[0], params)
1015
1016    dev[0].hs20_enable()
1017    dev[0].add_cred_values(default_cred())
1018    interworking_select(dev[0], None, no_match=True, freq="2412")
1019
1020def test_ap_hs20_eap_fast_mschapv2(dev, apdev):
1021    """Hotspot 2.0 connection with FAST/EAP-MSCHAPV2"""
1022    check_eap_capa(dev[0], "FAST")
1023    eap_test(dev[0], apdev[0], "43[3:26]", "FAST", "user")
1024
1025def test_ap_hs20_eap_fast_gtc(dev, apdev):
1026    """Hotspot 2.0 connection with FAST/EAP-GTC"""
1027    check_eap_capa(dev[0], "FAST")
1028    eap_test(dev[0], apdev[0], "43[3:6]", "FAST", "user")
1029
1030def test_ap_hs20_eap_tls(dev, apdev):
1031    """Hotspot 2.0 connection with EAP-TLS"""
1032    bssid = apdev[0]['bssid']
1033    params = hs20_ap_params()
1034    params['nai_realm'] = ["0,example.com,13[5:6]"]
1035    hostapd.add_ap(apdev[0], params)
1036
1037    dev[0].flush_scan_cache()
1038    dev[0].hs20_enable()
1039    dev[0].add_cred_values({'realm': "example.com",
1040                            'username': "certificate-user",
1041                            'ca_cert': "auth_serv/ca.pem",
1042                            'client_cert': "auth_serv/user.pem",
1043                            'private_key': "auth_serv/user.key"})
1044    interworking_select(dev[0], bssid, freq="2412")
1045    interworking_connect(dev[0], bssid, "TLS")
1046
1047@remote_compatible
1048def test_ap_hs20_eap_cert_unknown(dev, apdev):
1049    """Hotspot 2.0 connection with certificate, but unknown EAP method"""
1050    bssid = apdev[0]['bssid']
1051    params = hs20_ap_params()
1052    params['nai_realm'] = ["0,example.com,99[5:6]"]
1053    hostapd.add_ap(apdev[0], params)
1054
1055    dev[0].hs20_enable()
1056    dev[0].add_cred_values({'realm': "example.com",
1057                            'username': "certificate-user",
1058                            'ca_cert': "auth_serv/ca.pem",
1059                            'client_cert': "auth_serv/user.pem",
1060                            'private_key': "auth_serv/user.key"})
1061    interworking_select(dev[0], None, no_match=True, freq="2412")
1062
1063@remote_compatible
1064def test_ap_hs20_eap_cert_unsupported(dev, apdev):
1065    """Hotspot 2.0 connection with certificate, but unsupported TTLS"""
1066    bssid = apdev[0]['bssid']
1067    params = hs20_ap_params()
1068    params['nai_realm'] = ["0,example.com,21[5:6]"]
1069    hostapd.add_ap(apdev[0], params)
1070
1071    dev[0].hs20_enable()
1072    dev[0].add_cred_values({'realm': "example.com",
1073                            'username': "certificate-user",
1074                            'ca_cert': "auth_serv/ca.pem",
1075                            'client_cert': "auth_serv/user.pem",
1076                            'private_key': "auth_serv/user.key"})
1077    interworking_select(dev[0], None, no_match=True, freq="2412")
1078
1079@remote_compatible
1080def test_ap_hs20_eap_invalid_cred(dev, apdev):
1081    """Hotspot 2.0 connection with invalid cred configuration"""
1082    bssid = apdev[0]['bssid']
1083    params = hs20_ap_params()
1084    hostapd.add_ap(apdev[0], params)
1085
1086    dev[0].hs20_enable()
1087    dev[0].add_cred_values({'realm': "example.com",
1088                            'username': "certificate-user",
1089                            'client_cert': "auth_serv/user.pem"})
1090    interworking_select(dev[0], None, no_match=True, freq="2412")
1091
1092def test_ap_hs20_nai_realms(dev, apdev):
1093    """Hotspot 2.0 connection and multiple NAI realms and TTLS/PAP"""
1094    bssid = apdev[0]['bssid']
1095    params = hs20_ap_params()
1096    params['hessid'] = bssid
1097    params['nai_realm'] = ["0,no.match.here;example.com;no.match.here.either,21[2:1][5:7]"]
1098    hostapd.add_ap(apdev[0], params)
1099
1100    dev[0].flush_scan_cache()
1101    dev[0].hs20_enable()
1102    id = dev[0].add_cred_values({'realm': "example.com",
1103                                 'ca_cert': "auth_serv/ca.pem",
1104                                 'username': "pap user",
1105                                 'password': "password",
1106                                 'domain': "example.com"})
1107    interworking_select(dev[0], bssid, "home", freq="2412")
1108    interworking_connect(dev[0], bssid, "TTLS")
1109    check_sp_type(dev[0], "home")
1110
1111def test_ap_hs20_roaming_consortium(dev, apdev):
1112    """Hotspot 2.0 connection based on roaming consortium match"""
1113    bssid = apdev[0]['bssid']
1114    params = hs20_ap_params()
1115    params['hessid'] = bssid
1116    hostapd.add_ap(apdev[0], params)
1117
1118    dev[0].flush_scan_cache()
1119    dev[0].hs20_enable()
1120    for consortium in ["112233", "1020304050", "010203040506", "fedcba"]:
1121        id = dev[0].add_cred_values({'username': "user",
1122                                     'password': "password",
1123                                     'domain': "example.com",
1124                                     'ca_cert': "auth_serv/ca.pem",
1125                                     'roaming_consortium': consortium,
1126                                     'eap': "PEAP"})
1127        interworking_select(dev[0], bssid, "home", freq="2412")
1128        interworking_connect(dev[0], bssid, "PEAP")
1129        check_sp_type(dev[0], "home")
1130        dev[0].request("INTERWORKING_SELECT auto freq=2412")
1131        ev = dev[0].wait_event(["INTERWORKING-ALREADY-CONNECTED"], timeout=15)
1132        if ev is None:
1133            raise Exception("Timeout on already-connected event")
1134        dev[0].remove_cred(id)
1135
1136def test_ap_hs20_home_ois(dev, apdev):
1137    """Hotspot 2.0 connection based on roaming consortium match"""
1138    bssid = apdev[0]['bssid']
1139    params = hs20_ap_params()
1140    params['hessid'] = bssid
1141    hostapd.add_ap(apdev[0], params)
1142
1143    dev[0].flush_scan_cache()
1144    dev[0].hs20_enable()
1145    for consortium in [["112233"], ["1020304050"], ["010203040506"], ["fedcba"],
1146                       ["f12233", "f020304050", "f10203040506", "fedcba"]]:
1147        id = dev[0].add_cred_values({'username': "user",
1148                                     'password': "password",
1149                                     'domain': "example.com",
1150                                     'ca_cert': "auth_serv/ca.pem",
1151                                     'home_ois': consortium,
1152                                     'eap': "PEAP"})
1153        interworking_select(dev[0], bssid, "home", freq="2412")
1154        interworking_connect(dev[0], bssid, "PEAP")
1155        check_sp_type(dev[0], "home")
1156        dev[0].request("INTERWORKING_SELECT auto freq=2412")
1157        ev = dev[0].wait_event(["INTERWORKING-ALREADY-CONNECTED"], timeout=15)
1158        if ev is None:
1159            raise Exception("Timeout on already-connected event")
1160        dev[0].remove_cred(id)
1161
1162def test_ap_hs20_roaming_consortiums_match(dev, apdev):
1163    """Hotspot 2.0 connection based on roaming_consortiums match"""
1164    bssid = apdev[0]['bssid']
1165    params = hs20_ap_params()
1166    params['hessid'] = bssid
1167    hostapd.add_ap(apdev[0], params)
1168
1169    dev[0].flush_scan_cache()
1170    dev[0].hs20_enable()
1171    tests = [("112233", "112233"),
1172             ("ffffff,1020304050,eeeeee", "1020304050")]
1173    for consortium, selected in tests:
1174        id = dev[0].add_cred_values({'username': "user",
1175                                     'password': "password",
1176                                     'domain': "my.home.example.com",
1177                                     'ca_cert': "auth_serv/ca.pem",
1178                                     'roaming_consortiums': consortium,
1179                                     'eap': "PEAP"})
1180        interworking_select(dev[0], bssid, "roaming", freq="2412")
1181        interworking_connect(dev[0], bssid, "PEAP")
1182        check_sp_type(dev[0], "roaming")
1183        network_id = dev[0].get_status_field("id")
1184        sel = dev[0].get_network(network_id, "roaming_consortium_selection")
1185        if sel != selected:
1186            raise Exception("Unexpected roaming_consortium_selection value: " +
1187                            sel)
1188        dev[0].request("INTERWORKING_SELECT auto freq=2412")
1189        ev = dev[0].wait_event(["INTERWORKING-ALREADY-CONNECTED"], timeout=15)
1190        if ev is None:
1191            raise Exception("Timeout on already-connected event")
1192        dev[0].remove_cred(id)
1193
1194def test_ap_hs20_max_roaming_consortiums(dev, apdev):
1195    """Maximum number of cred roaming_consortiums"""
1196    id = dev[0].add_cred()
1197    consortium = (36*",ffffff")[1:]
1198    if "OK" not in dev[0].request('SET_CRED %d roaming_consortiums "%s"' % (id, consortium)):
1199        raise Exception("Maximum number of consortium OIs rejected")
1200    consortium = (37*",ffffff")[1:]
1201    if "FAIL" not in dev[0].request('SET_CRED %d roaming_consortiums "%s"' % (id, consortium)):
1202        raise Exception("Over maximum number of consortium OIs accepted")
1203    dev[0].remove_cred(id)
1204
1205def test_ap_hs20_roaming_consortium_invalid(dev, apdev):
1206    """Hotspot 2.0 connection and invalid roaming consortium ANQP-element"""
1207    bssid = apdev[0]['bssid']
1208    params = hs20_ap_params()
1209    params['hessid'] = bssid
1210    # Override Roaming Consortium ANQP-element with an incorrectly encoded
1211    # value.
1212    params['anqp_elem'] = "261:04fedcba"
1213    hostapd.add_ap(apdev[0], params)
1214
1215    dev[0].hs20_enable()
1216    id = dev[0].add_cred_values({'username': "user",
1217                                 'password': "password",
1218                                 'domain': "example.com",
1219                                 'ca_cert': "auth_serv/ca.pem",
1220                                 'home_ois': ["fedcba"],
1221                                 'eap': "PEAP"})
1222    interworking_select(dev[0], bssid, "home", freq="2412", no_match=True)
1223
1224def test_ap_hs20_roaming_consortium_element(dev, apdev):
1225    """Hotspot 2.0 connection and invalid roaming consortium element"""
1226    bssid = apdev[0]['bssid']
1227    params = hs20_ap_params()
1228    params['hessid'] = bssid
1229    del params['roaming_consortium']
1230    params['vendor_elements'] = '6f00'
1231    hapd = hostapd.add_ap(apdev[0], params)
1232
1233    dev[0].hs20_enable()
1234    dev[0].scan_for_bss(bssid, freq="2412")
1235    id = dev[0].add_cred_values({'username': "user",
1236                                 'password': "password",
1237                                 'domain': "example.com",
1238                                 'ca_cert': "auth_serv/ca.pem",
1239                                 'home_ois': ["112233"],
1240                                 'eap': "PEAP"})
1241    interworking_select(dev[0], bssid, freq="2412", no_match=True)
1242
1243    hapd.set('vendor_elements', '6f020001')
1244    if "OK" not in hapd.request("UPDATE_BEACON"):
1245        raise Exception("UPDATE_BEACON failed")
1246    dev[0].request("BSS_FLUSH 0")
1247    dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
1248    interworking_select(dev[0], bssid, freq="2412", no_match=True)
1249
1250def test_ap_hs20_roaming_consortium_constraints(dev, apdev):
1251    """Hotspot 2.0 connection and roaming consortium constraints"""
1252    bssid = apdev[0]['bssid']
1253    params = hs20_ap_params()
1254    params['hessid'] = bssid
1255    params['bss_load_test'] = "12:200:20000"
1256    hostapd.add_ap(apdev[0], params)
1257
1258    dev[0].hs20_enable()
1259
1260    vals = {'username': "user",
1261            'password': "password",
1262            'domain': "example.com",
1263            'ca_cert': "auth_serv/ca.pem",
1264            'home_ois': ["fedcba"],
1265            'eap': "TTLS"}
1266    vals2 = vals.copy()
1267    vals2['required_home_ois'] = ["223344"]
1268    id = dev[0].add_cred_values(vals2)
1269    interworking_select(dev[0], bssid, "home", freq="2412", no_match=True)
1270    dev[0].remove_cred(id)
1271
1272    vals2 = vals.copy()
1273    vals2['min_dl_bandwidth_home'] = "65500"
1274    id = dev[0].add_cred_values(vals2)
1275    dev[0].request("INTERWORKING_SELECT freq=2412")
1276    ev = dev[0].wait_event(["INTERWORKING-AP"], timeout=15)
1277    if ev is None:
1278        raise Exception("No AP found")
1279    if "below_min_backhaul=1" not in ev:
1280        raise Exception("below_min_backhaul not reported")
1281    dev[0].remove_cred(id)
1282
1283    vals2 = vals.copy()
1284    vals2['max_bss_load'] = "100"
1285    id = dev[0].add_cred_values(vals2)
1286    dev[0].request("INTERWORKING_SELECT freq=2412")
1287    ev = dev[0].wait_event(["INTERWORKING-AP"], timeout=15)
1288    if ev is None:
1289        raise Exception("No AP found")
1290    if "over_max_bss_load=1" not in ev:
1291        raise Exception("over_max_bss_load not reported")
1292    dev[0].remove_cred(id)
1293
1294    vals2 = vals.copy()
1295    vals2['req_conn_capab'] = "6:1234"
1296    vals2['domain'] = 'example.org'
1297    id = dev[0].add_cred_values(vals2)
1298
1299    dev[0].request("INTERWORKING_SELECT freq=2412")
1300    ev = dev[0].wait_event(["INTERWORKING-AP"], timeout=15)
1301    if ev is None:
1302        raise Exception("No AP found")
1303    if "conn_capab_missing=1" not in ev:
1304        raise Exception("conn_capab_missing not reported")
1305    dev[0].remove_cred(id)
1306
1307    values = default_cred()
1308    values['home_ois'] = ["fedcba"]
1309    id3 = dev[0].add_cred_values(values)
1310
1311    vals2 = vals.copy()
1312    vals2['home_ois'] = ["fedcba"]
1313    vals2['priority'] = "2"
1314    id = dev[0].add_cred_values(vals2)
1315
1316    values = default_cred()
1317    values['home_ois'] = ["fedcba"]
1318    id2 = dev[0].add_cred_values(values)
1319
1320    dev[0].request("INTERWORKING_SELECT freq=2412")
1321    ev = dev[0].wait_event(["INTERWORKING-AP"], timeout=15)
1322    if ev is None:
1323        raise Exception("No AP found")
1324    dev[0].remove_cred(id)
1325    dev[0].remove_cred(id2)
1326    dev[0].remove_cred(id3)
1327
1328def test_ap_hs20_3gpp_constraints(dev, apdev):
1329    """Hotspot 2.0 connection and 3GPP credential constraints"""
1330    bssid = apdev[0]['bssid']
1331    params = hs20_ap_params()
1332    params['hessid'] = bssid
1333    params['anqp_3gpp_cell_net'] = "555,444"
1334    params['domain_name'] = "wlan.mnc444.mcc555.3gppnetwork.org"
1335    params['bss_load_test'] = "12:200:20000"
1336    hapd = hostapd.add_ap(apdev[0], params)
1337
1338    dev[0].hs20_enable()
1339
1340    vals = {'imsi': "555444-333222111",
1341            'eap': "SIM",
1342            'milenage': "5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123"}
1343    vals2 = vals.copy()
1344    vals2['required_home_ois'] = ["223344"]
1345    id = dev[0].add_cred_values(vals2)
1346    interworking_select(dev[0], bssid, "home", freq="2412", no_match=True)
1347    dev[0].remove_cred(id)
1348
1349    vals2 = vals.copy()
1350    vals2['min_dl_bandwidth_home'] = "65500"
1351    id = dev[0].add_cred_values(vals2)
1352    dev[0].request("INTERWORKING_SELECT freq=2412")
1353    ev = dev[0].wait_event(["INTERWORKING-AP"], timeout=15)
1354    if ev is None:
1355        raise Exception("No AP found")
1356    if "below_min_backhaul=1" not in ev:
1357        raise Exception("below_min_backhaul not reported")
1358    dev[0].remove_cred(id)
1359
1360    vals2 = vals.copy()
1361    vals2['max_bss_load'] = "100"
1362    id = dev[0].add_cred_values(vals2)
1363    dev[0].request("INTERWORKING_SELECT freq=2412")
1364    ev = dev[0].wait_event(["INTERWORKING-AP"], timeout=15)
1365    if ev is None:
1366        raise Exception("No AP found")
1367    if "over_max_bss_load=1" not in ev:
1368        raise Exception("over_max_bss_load not reported")
1369    dev[0].remove_cred(id)
1370
1371    values = default_cred()
1372    values['home_ois'] = ["fedcba"]
1373    id3 = dev[0].add_cred_values(values)
1374
1375    vals2 = vals.copy()
1376    vals2['home_ois'] = ["fedcba"]
1377    vals2['priority'] = "2"
1378    id = dev[0].add_cred_values(vals2)
1379
1380    values = default_cred()
1381    values['home_ois'] = ["fedcba"]
1382    id2 = dev[0].add_cred_values(values)
1383
1384    dev[0].request("INTERWORKING_SELECT freq=2412")
1385    ev = dev[0].wait_event(["INTERWORKING-AP"], timeout=15)
1386    if ev is None:
1387        raise Exception("No AP found")
1388    dev[0].remove_cred(id)
1389    dev[0].remove_cred(id2)
1390    dev[0].remove_cred(id3)
1391
1392    hapd.disable()
1393    params = hs20_ap_params()
1394    params['hessid'] = bssid
1395    params['anqp_3gpp_cell_net'] = "555,444"
1396    params['bss_load_test'] = "12:200:20000"
1397    hapd = hostapd.add_ap(apdev[0], params)
1398    vals2 = vals.copy()
1399    vals2['req_conn_capab'] = "6:1234"
1400    id = dev[0].add_cred_values(vals2)
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 "conn_capab_missing=1" not in ev:
1406        raise Exception("conn_capab_missing not reported")
1407    dev[0].remove_cred(id)
1408
1409def test_ap_hs20_connect_no_full_match(dev, apdev):
1410    """Hotspot 2.0 connection and no full match"""
1411    bssid = apdev[0]['bssid']
1412    params = hs20_ap_params()
1413    params['hessid'] = bssid
1414    params['anqp_3gpp_cell_net'] = "555,444"
1415    hapd = hostapd.add_ap(apdev[0], params)
1416
1417    dev[0].flush_scan_cache()
1418    dev[0].hs20_enable()
1419
1420    vals = {'username': "user",
1421            'password': "password",
1422            'domain': "example.com",
1423            'ca_cert': "auth_serv/ca.pem",
1424            'home_ois': ["fedcba"],
1425            'eap': "TTLS",
1426            'min_dl_bandwidth_home': "65500"}
1427    id = dev[0].add_cred_values(vals)
1428    dev[0].request("INTERWORKING_SELECT freq=2412")
1429    ev = dev[0].wait_event(["INTERWORKING-AP"], timeout=15)
1430    if ev is None:
1431        raise Exception("No AP found")
1432    if "below_min_backhaul=1" not in ev:
1433        raise Exception("below_min_backhaul not reported")
1434    interworking_connect(dev[0], bssid, "TTLS")
1435    # wait for sta to connect so it can actually disconnect later
1436    hapd.wait_sta()
1437    dev[0].remove_cred(id)
1438    dev[0].wait_disconnected()
1439    # wait for sta to disconnect so it can send GAS query
1440    hapd.wait_event(["AP-STA-DISCONNECTED"], timeout=1)
1441
1442    vals = {'imsi': "555444-333222111", 'eap': "SIM",
1443            'milenage': "5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123",
1444            'min_dl_bandwidth_roaming': "65500"}
1445    id = dev[0].add_cred_values(vals)
1446    dev[0].request("INTERWORKING_SELECT freq=2412")
1447    ev = dev[0].wait_event(["INTERWORKING-AP"], timeout=15)
1448    if ev is None:
1449        raise Exception("No AP found")
1450    if "below_min_backhaul=1" not in ev:
1451        raise Exception("below_min_backhaul not reported")
1452    interworking_connect(dev[0], bssid, "SIM")
1453    dev[0].remove_cred(id)
1454    dev[0].wait_disconnected()
1455
1456def test_ap_hs20_username_roaming(dev, apdev):
1457    """Hotspot 2.0 connection in username/password credential (roaming)"""
1458    check_eap_capa(dev[0], "MSCHAPV2")
1459    bssid = apdev[0]['bssid']
1460    params = hs20_ap_params()
1461    params['nai_realm'] = ["0,example.com,13[5:6],21[2:4][5:7]",
1462                           "0,roaming.example.com,21[2:4][5:7]",
1463                           "0,another.example.com"]
1464    params['domain_name'] = "another.example.com"
1465    params['hessid'] = bssid
1466    hostapd.add_ap(apdev[0], params)
1467
1468    dev[0].hs20_enable()
1469    id = dev[0].add_cred_values({'realm': "roaming.example.com",
1470                                 'username': "hs20-test",
1471                                 'password': "password",
1472                                 'ca_cert': "auth_serv/ca.pem",
1473                                 'domain': "example.com"})
1474    interworking_select(dev[0], bssid, "roaming", freq="2412")
1475    interworking_connect(dev[0], bssid, "TTLS")
1476    check_sp_type(dev[0], "roaming")
1477
1478def test_ap_hs20_username_unknown(dev, apdev):
1479    """Hotspot 2.0 connection in username/password credential (no domain in cred)"""
1480    check_eap_capa(dev[0], "MSCHAPV2")
1481    bssid = apdev[0]['bssid']
1482    params = hs20_ap_params()
1483    params['hessid'] = bssid
1484    hostapd.add_ap(apdev[0], params)
1485
1486    dev[0].hs20_enable()
1487    id = dev[0].add_cred_values({'realm': "example.com",
1488                                 'ca_cert': "auth_serv/ca.pem",
1489                                 'username': "hs20-test",
1490                                 'password': "password"})
1491    interworking_select(dev[0], bssid, "unknown", freq="2412")
1492    interworking_connect(dev[0], bssid, "TTLS")
1493    check_sp_type(dev[0], "unknown")
1494
1495def test_ap_hs20_username_unknown2(dev, apdev):
1496    """Hotspot 2.0 connection in username/password credential (no domain advertized)"""
1497    check_eap_capa(dev[0], "MSCHAPV2")
1498    bssid = apdev[0]['bssid']
1499    params = hs20_ap_params()
1500    params['hessid'] = bssid
1501    del params['domain_name']
1502    hostapd.add_ap(apdev[0], params)
1503
1504    dev[0].hs20_enable()
1505    id = dev[0].add_cred_values({'realm': "example.com",
1506                                 'ca_cert': "auth_serv/ca.pem",
1507                                 'username': "hs20-test",
1508                                 'password': "password",
1509                                 'domain': "example.com"})
1510    interworking_select(dev[0], bssid, "unknown", freq="2412")
1511    interworking_connect(dev[0], bssid, "TTLS")
1512    check_sp_type(dev[0], "unknown")
1513
1514def test_ap_hs20_gas_while_associated(dev, apdev):
1515    """Hotspot 2.0 connection with GAS query while associated"""
1516    check_eap_capa(dev[0], "MSCHAPV2")
1517    bssid = apdev[0]['bssid']
1518    params = hs20_ap_params()
1519    params['hessid'] = bssid
1520    hapd = hostapd.add_ap(apdev[0], params)
1521
1522    dev[0].hs20_enable()
1523    id = dev[0].add_cred_values({'realm': "example.com",
1524                                 'ca_cert': "auth_serv/ca.pem",
1525                                 'username': "hs20-test",
1526                                 'password': "password",
1527                                 'domain': "example.com"})
1528    interworking_select(dev[0], bssid, "home", freq="2412")
1529    interworking_connect(dev[0], bssid, "TTLS")
1530    hapd.wait_sta()
1531
1532    logger.info("Verifying GAS query while associated")
1533    dev[0].request("FETCH_ANQP")
1534    for i in range(0, 6):
1535        ev = dev[0].wait_event(["RX-ANQP"], timeout=5)
1536        if ev is None:
1537            raise Exception("Operation timed out")
1538
1539def test_ap_hs20_gas_with_another_ap_while_associated(dev, apdev):
1540    """GAS query with another AP while associated"""
1541    check_eap_capa(dev[0], "MSCHAPV2")
1542    bssid = apdev[0]['bssid']
1543    params = hs20_ap_params()
1544    params['hessid'] = bssid
1545    hapd = hostapd.add_ap(apdev[0], params)
1546
1547    bssid2 = apdev[1]['bssid']
1548    params = hs20_ap_params()
1549    params['hessid'] = bssid2
1550    params['nai_realm'] = ["0,no-match.example.org,13[5:6],21[2:4][5:7]"]
1551    hostapd.add_ap(apdev[1], params)
1552
1553    dev[0].hs20_enable()
1554    id = dev[0].add_cred_values({'realm': "example.com",
1555                                 'ca_cert': "auth_serv/ca.pem",
1556                                 'username': "hs20-test",
1557                                 'password': "password",
1558                                 'domain': "example.com"})
1559    interworking_select(dev[0], bssid, "home", freq="2412")
1560    interworking_connect(dev[0], bssid, "TTLS")
1561    hapd.wait_sta()
1562    dev[0].dump_monitor()
1563
1564    logger.info("Verifying GAS query with same AP while associated")
1565    dev[0].request("ANQP_GET " + bssid + " 263")
1566    ev = dev[0].wait_event(["RX-ANQP"], timeout=5)
1567    if ev is None:
1568        raise Exception("ANQP operation timed out")
1569    dev[0].dump_monitor()
1570
1571    logger.info("Verifying GAS query with another AP while associated")
1572    dev[0].scan_for_bss(bssid2, 2412)
1573    dev[0].request("ANQP_GET " + bssid2 + " 263")
1574    ev = dev[0].wait_event(["RX-ANQP"], timeout=5)
1575    if ev is None:
1576        raise Exception("ANQP operation timed out")
1577
1578def test_ap_hs20_gas_while_associated_with_pmf(dev, apdev):
1579    """Hotspot 2.0 connection with GAS query while associated and using PMF"""
1580    check_eap_capa(dev[0], "MSCHAPV2")
1581    try:
1582        _test_ap_hs20_gas_while_associated_with_pmf(dev, apdev)
1583    finally:
1584        dev[0].request("SET pmf 0")
1585
1586def _test_ap_hs20_gas_while_associated_with_pmf(dev, apdev):
1587    bssid = apdev[0]['bssid']
1588    params = hs20_ap_params()
1589    params['hessid'] = bssid
1590    hapd = hostapd.add_ap(apdev[0], params)
1591
1592    bssid2 = apdev[1]['bssid']
1593    params = hs20_ap_params()
1594    params['hessid'] = bssid2
1595    params['nai_realm'] = ["0,no-match.example.org,13[5:6],21[2:4][5:7]"]
1596    hostapd.add_ap(apdev[1], params)
1597
1598    dev[0].flush_scan_cache()
1599    dev[0].hs20_enable()
1600    dev[0].request("SET pmf 2")
1601    id = dev[0].add_cred_values({'realm': "example.com",
1602                                 'ca_cert': "auth_serv/ca.pem",
1603                                 'username': "hs20-test",
1604                                 'password': "password",
1605                                 'domain': "example.com"})
1606    interworking_select(dev[0], bssid, "home", freq="2412")
1607    interworking_connect(dev[0], bssid, "TTLS")
1608    hapd.wait_sta()
1609
1610    logger.info("Verifying GAS query while associated")
1611    dev[0].request("FETCH_ANQP")
1612    for i in range(0, 2 * 6):
1613        ev = dev[0].wait_event(["RX-ANQP"], timeout=5)
1614        if ev is None:
1615            raise Exception("Operation timed out")
1616
1617def test_ap_hs20_gas_with_another_ap_while_using_pmf(dev, apdev):
1618    """GAS query with another AP while associated and using PMF"""
1619    check_eap_capa(dev[0], "MSCHAPV2")
1620    try:
1621        _test_ap_hs20_gas_with_another_ap_while_using_pmf(dev, apdev)
1622    finally:
1623        dev[0].request("SET pmf 0")
1624
1625def _test_ap_hs20_gas_with_another_ap_while_using_pmf(dev, apdev):
1626    bssid = apdev[0]['bssid']
1627    params = hs20_ap_params()
1628    params['hessid'] = bssid
1629    hapd = hostapd.add_ap(apdev[0], params)
1630
1631    bssid2 = apdev[1]['bssid']
1632    params = hs20_ap_params()
1633    params['hessid'] = bssid2
1634    params['nai_realm'] = ["0,no-match.example.org,13[5:6],21[2:4][5:7]"]
1635    hostapd.add_ap(apdev[1], params)
1636
1637    dev[0].hs20_enable()
1638    dev[0].request("SET pmf 2")
1639    id = dev[0].add_cred_values({'realm': "example.com",
1640                                 'ca_cert': "auth_serv/ca.pem",
1641                                 'username': "hs20-test",
1642                                 'password': "password",
1643                                 'domain': "example.com"})
1644    interworking_select(dev[0], bssid, "home", freq="2412")
1645    interworking_connect(dev[0], bssid, "TTLS")
1646    dev[0].dump_monitor()
1647    hapd.wait_sta()
1648
1649    logger.info("Verifying GAS query with same AP while associated")
1650    dev[0].request("ANQP_GET " + bssid + " 263")
1651    ev = dev[0].wait_event(["RX-ANQP"], timeout=5)
1652    if ev is None:
1653        raise Exception("ANQP operation timed out")
1654    dev[0].dump_monitor()
1655
1656    logger.info("Verifying GAS query with another AP while associated")
1657    dev[0].scan_for_bss(bssid2, 2412)
1658    dev[0].request("ANQP_GET " + bssid2 + " 263")
1659    ev = dev[0].wait_event(["RX-ANQP"], timeout=5)
1660    if ev is None:
1661        raise Exception("ANQP operation timed out")
1662
1663def test_ap_hs20_gas_frag_while_associated(dev, apdev):
1664    """Hotspot 2.0 connection with fragmented GAS query while associated"""
1665    check_eap_capa(dev[0], "MSCHAPV2")
1666    bssid = apdev[0]['bssid']
1667    params = hs20_ap_params()
1668    params['hessid'] = bssid
1669    hapd = hostapd.add_ap(apdev[0], params)
1670    hapd.set("gas_frag_limit", "50")
1671
1672    dev[0].hs20_enable()
1673    id = dev[0].add_cred_values({'realm': "example.com",
1674                                 'ca_cert': "auth_serv/ca.pem",
1675                                 'username': "hs20-test",
1676                                 'password': "password",
1677                                 'domain': "example.com"})
1678    interworking_select(dev[0], bssid, "home", freq="2412")
1679    interworking_connect(dev[0], bssid, "TTLS")
1680    hapd.wait_sta()
1681
1682    logger.info("Verifying GAS query while associated")
1683    dev[0].request("FETCH_ANQP")
1684    for i in range(0, 6):
1685        ev = dev[0].wait_event(["RX-ANQP"], timeout=5)
1686        if ev is None:
1687            raise Exception("Operation timed out")
1688
1689def test_ap_hs20_multiple_connects(dev, apdev):
1690    """Hotspot 2.0 connection through multiple network selections"""
1691    check_eap_capa(dev[0], "MSCHAPV2")
1692    bssid = apdev[0]['bssid']
1693    params = hs20_ap_params()
1694    params['hessid'] = bssid
1695    hostapd.add_ap(apdev[0], params)
1696
1697    dev[0].hs20_enable()
1698    values = {'realm': "example.com",
1699              'ca_cert': "auth_serv/ca.pem",
1700              'username': "hs20-test",
1701              'password': "password",
1702              'domain': "example.com"}
1703    id = dev[0].add_cred_values(values)
1704
1705    dev[0].scan_for_bss(bssid, freq="2412")
1706
1707    for i in range(0, 3):
1708        logger.info("Starting Interworking network selection")
1709        dev[0].request("INTERWORKING_SELECT auto freq=2412")
1710        while True:
1711            ev = dev[0].wait_event(["INTERWORKING-NO-MATCH",
1712                                    "INTERWORKING-ALREADY-CONNECTED",
1713                                    "CTRL-EVENT-CONNECTED"], timeout=15)
1714            if ev is None:
1715                raise Exception("Connection timed out")
1716            if "INTERWORKING-NO-MATCH" in ev:
1717                raise Exception("Matching AP not found")
1718            if "CTRL-EVENT-CONNECTED" in ev:
1719                break
1720            if i == 2 and "INTERWORKING-ALREADY-CONNECTED" in ev:
1721                break
1722        if i == 0:
1723            dev[0].request("DISCONNECT")
1724        dev[0].dump_monitor()
1725
1726    networks = dev[0].list_networks()
1727    if len(networks) > 1:
1728        raise Exception("Duplicated network block detected")
1729
1730def test_ap_hs20_disallow_aps(dev, apdev):
1731    """Hotspot 2.0 connection and disallow_aps"""
1732    bssid = apdev[0]['bssid']
1733    params = hs20_ap_params()
1734    params['hessid'] = bssid
1735    hostapd.add_ap(apdev[0], params)
1736
1737    dev[0].hs20_enable()
1738    values = {'realm': "example.com",
1739              'ca_cert': "auth_serv/ca.pem",
1740              'username': "hs20-test",
1741              'password': "password",
1742              'domain': "example.com"}
1743    id = dev[0].add_cred_values(values)
1744
1745    dev[0].scan_for_bss(bssid, freq="2412")
1746
1747    logger.info("Verify disallow_aps bssid")
1748    dev[0].request("SET disallow_aps bssid " + bssid.replace(':', ''))
1749    dev[0].request("INTERWORKING_SELECT auto")
1750    ev = dev[0].wait_event(["INTERWORKING-NO-MATCH"], timeout=15)
1751    if ev is None:
1752        raise Exception("Network selection timed out")
1753    dev[0].dump_monitor()
1754
1755    logger.info("Verify disallow_aps ssid")
1756    dev[0].request("SET disallow_aps ssid 746573742d68733230")
1757    dev[0].request("INTERWORKING_SELECT auto freq=2412")
1758    ev = dev[0].wait_event(["INTERWORKING-NO-MATCH"], timeout=15)
1759    if ev is None:
1760        raise Exception("Network selection timed out")
1761    dev[0].dump_monitor()
1762
1763    logger.info("Verify disallow_aps clear")
1764    dev[0].request("SET disallow_aps ")
1765    interworking_select(dev[0], bssid, "home", freq="2412")
1766
1767    dev[0].request("SET disallow_aps bssid " + bssid.replace(':', ''))
1768    ret = dev[0].request("INTERWORKING_CONNECT " + bssid)
1769    if "FAIL" not in ret:
1770        raise Exception("INTERWORKING_CONNECT to disallowed BSS not rejected")
1771
1772    if "FAIL" not in dev[0].request("INTERWORKING_CONNECT foo"):
1773        raise Exception("Invalid INTERWORKING_CONNECT not rejected")
1774    if "FAIL" not in dev[0].request("INTERWORKING_CONNECT 00:11:22:33:44:55"):
1775        raise Exception("Invalid INTERWORKING_CONNECT not rejected")
1776
1777def policy_test(dev, ap, hapd, values, only_one=True):
1778    dev.dump_monitor()
1779    if hapd is not None:
1780        hapd.dump_monitor()
1781    if ap:
1782        logger.info("Verify network selection to AP " + ap['ifname'])
1783        bssid = ap['bssid']
1784        dev.scan_for_bss(bssid, freq="2412")
1785    else:
1786        logger.info("Verify network selection")
1787        bssid = None
1788    dev.hs20_enable()
1789    id = dev.add_cred_values(values)
1790    dev.request("INTERWORKING_SELECT auto freq=2412")
1791    events = []
1792    while True:
1793        ev = dev.wait_event(["INTERWORKING-AP", "INTERWORKING-NO-MATCH",
1794                             "INTERWORKING-BLACKLISTED",
1795                             "INTERWORKING-SELECTED"], timeout=15)
1796        if ev is None:
1797            raise Exception("Network selection timed out")
1798        events.append(ev)
1799        if "INTERWORKING-NO-MATCH" in ev:
1800            raise Exception("Matching AP not found")
1801        if bssid and only_one and "INTERWORKING-AP" in ev and bssid not in ev:
1802            raise Exception("Unexpected AP claimed acceptable")
1803        if "INTERWORKING-SELECTED" in ev:
1804            if bssid and bssid not in ev:
1805                raise Exception("Selected incorrect BSS")
1806            break
1807
1808    ev = dev.wait_connected(timeout=15)
1809    if bssid and bssid not in ev:
1810        raise Exception("Connected to incorrect BSS")
1811
1812    conn_bssid = dev.get_status_field("bssid")
1813    if bssid and conn_bssid != bssid:
1814        raise Exception("bssid information points to incorrect BSS")
1815
1816    if hapd is not None:
1817        hapd.wait_sta()
1818
1819    dev.remove_cred(id)
1820    dev.dump_monitor()
1821    return events
1822
1823def default_cred(domain=None, user="hs20-test"):
1824    cred = {'realm': "example.com",
1825            'ca_cert': "auth_serv/ca.pem",
1826            'username': user,
1827            'password': "password"}
1828    if domain:
1829        cred['domain'] = domain
1830    return cred
1831
1832def test_ap_hs20_prefer_home(dev, apdev):
1833    """Hotspot 2.0 required roaming consortium"""
1834    check_eap_capa(dev[0], "MSCHAPV2")
1835    params = hs20_ap_params()
1836    params['domain_name'] = "example.org"
1837    hapd0 = hostapd.add_ap(apdev[0], params)
1838
1839    params = hs20_ap_params()
1840    params['ssid'] = "test-hs20-other"
1841    params['domain_name'] = "example.com"
1842    hapd1 = hostapd.add_ap(apdev[1], params)
1843
1844    values = default_cred()
1845    values['domain'] = "example.com"
1846    policy_test(dev[0], apdev[1], hapd1, values, only_one=False)
1847    values['domain'] = "example.org"
1848    policy_test(dev[0], apdev[0], hapd0, values, only_one=False)
1849
1850def test_ap_hs20_req_home_ois(dev, apdev):
1851    """Hotspot 2.0 required roaming consortium"""
1852    check_eap_capa(dev[0], "MSCHAPV2")
1853    params = hs20_ap_params()
1854    hapd0 = hostapd.add_ap(apdev[0], params)
1855
1856    params = hs20_ap_params()
1857    params['ssid'] = "test-hs20-other"
1858    params['roaming_consortium'] = ["223344"]
1859    hapd1 = hostapd.add_ap(apdev[1], params)
1860
1861    values = default_cred()
1862    values['required_home_ois'] = ["223344"]
1863    policy_test(dev[0], apdev[1], hapd1, values)
1864    values['required_home_ois'] = ["112233"]
1865    policy_test(dev[0], apdev[0], hapd0, values)
1866
1867    id = dev[0].add_cred()
1868    dev[0].set_cred_quoted(id, "required_home_ois", "112233")
1869    dev[0].set_cred_quoted(id, "required_home_ois",
1870                           "112233445566778899aabbccddeeff")
1871
1872    for val in ["", "1", "11", "1122", "1122334",
1873                "112233445566778899aabbccddeeff00", "1122334455,12345"]:
1874        if "FAIL" not in dev[0].request('SET_CRED {} required_home_ois "{}"'.format(id, val)):
1875            raise Exception("Invalid roaming consortium value accepted: " + val)
1876
1877def test_ap_hs20_req_roaming_consortium_no_match(dev, apdev):
1878    """Hotspot 2.0 required roaming consortium and no match"""
1879    check_eap_capa(dev[0], "MSCHAPV2")
1880    params = hs20_ap_params()
1881    del params['roaming_consortium']
1882    hostapd.add_ap(apdev[0], params)
1883
1884    params = hs20_ap_params()
1885    params['ssid'] = "test-hs20-other"
1886    params['roaming_consortium'] = ["223345"]
1887    hostapd.add_ap(apdev[1], params)
1888
1889    values = default_cred()
1890    values['required_home_ois'] = ["223344"]
1891    dev[0].hs20_enable()
1892    id = dev[0].add_cred_values(values)
1893    dev[0].request("INTERWORKING_SELECT auto freq=2412")
1894    ev = dev[0].wait_event(["INTERWORKING-NO-MATCH"], timeout=10)
1895    if ev is None:
1896        raise Exception("INTERWORKING-NO-MATCH not reported")
1897
1898def test_ap_hs20_excluded_ssid(dev, apdev):
1899    """Hotspot 2.0 exclusion based on SSID"""
1900    check_eap_capa(dev[0], "MSCHAPV2")
1901    params = hs20_ap_params()
1902    params['roaming_consortium'] = ["223344"]
1903    params['anqp_3gpp_cell_net'] = "555,444"
1904    hapd0 = hostapd.add_ap(apdev[0], params)
1905
1906    params = hs20_ap_params()
1907    params['ssid'] = "test-hs20-other"
1908    params['roaming_consortium'] = ["223344"]
1909    params['anqp_3gpp_cell_net'] = "555,444"
1910    hapd1 = hostapd.add_ap(apdev[1], params)
1911
1912    values = default_cred()
1913    values['excluded_ssid'] = "test-hs20"
1914    events = policy_test(dev[0], apdev[1], hapd1, values)
1915    ev = [e for e in events if "INTERWORKING-BLACKLISTED " + apdev[0]['bssid'] in e]
1916    if len(ev) != 1:
1917        raise Exception("Excluded network not reported")
1918    values['excluded_ssid'] = "test-hs20-other"
1919    events = policy_test(dev[0], apdev[0], hapd0, values)
1920    ev = [e for e in events if "INTERWORKING-BLACKLISTED " + apdev[1]['bssid'] in e]
1921    if len(ev) != 1:
1922        raise Exception("Excluded network not reported")
1923
1924    values = default_cred()
1925    values['home_ois'] = ["223344"]
1926    values['eap'] = "TTLS"
1927    values['phase2'] = "auth=MSCHAPV2"
1928    values['excluded_ssid'] = "test-hs20"
1929    events = policy_test(dev[0], apdev[1], hapd1, values)
1930    ev = [e for e in events if "INTERWORKING-BLACKLISTED " + apdev[0]['bssid'] in e]
1931    if len(ev) != 1:
1932        raise Exception("Excluded network not reported")
1933
1934    values = {'imsi': "555444-333222111", 'eap': "SIM",
1935              'milenage': "5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123",
1936              'excluded_ssid': "test-hs20"}
1937    events = policy_test(dev[0], apdev[1], hapd1, values)
1938    ev = [e for e in events if "INTERWORKING-BLACKLISTED " + apdev[0]['bssid'] in e]
1939    if len(ev) != 1:
1940        raise Exception("Excluded network not reported")
1941
1942def test_ap_hs20_roam_to_higher_prio(dev, apdev):
1943    """Hotspot 2.0 and roaming from current to higher priority network"""
1944    check_eap_capa(dev[0], "MSCHAPV2")
1945    bssid = apdev[0]['bssid']
1946    params = hs20_ap_params(ssid="test-hs20-visited")
1947    params['domain_name'] = "visited.example.org"
1948    hostapd.add_ap(apdev[0], params)
1949
1950    dev[0].hs20_enable()
1951    id = dev[0].add_cred_values({'realm': "example.com",
1952                                 'ca_cert': "auth_serv/ca.pem",
1953                                 'username': "hs20-test",
1954                                 'password': "password",
1955                                 'domain': "example.com"})
1956    logger.info("Connect to the only network option")
1957    interworking_select(dev[0], bssid, "roaming", freq="2412")
1958    dev[0].dump_monitor()
1959    interworking_connect(dev[0], bssid, "TTLS")
1960
1961    logger.info("Start another AP (home operator) and reconnect")
1962    bssid2 = apdev[1]['bssid']
1963    params = hs20_ap_params(ssid="test-hs20-home")
1964    params['domain_name'] = "example.com"
1965    hostapd.add_ap(apdev[1], params)
1966
1967    dev[0].scan_for_bss(bssid2, freq="2412", force_scan=True)
1968    dev[0].request("INTERWORKING_SELECT auto freq=2412")
1969    ev = dev[0].wait_event(["INTERWORKING-NO-MATCH",
1970                            "INTERWORKING-ALREADY-CONNECTED",
1971                            "CTRL-EVENT-CONNECTED"], timeout=15)
1972    if ev is None:
1973        raise Exception("Connection timed out")
1974    if "INTERWORKING-NO-MATCH" in ev:
1975        raise Exception("Matching AP not found")
1976    if "INTERWORKING-ALREADY-CONNECTED" in ev:
1977        raise Exception("Unexpected AP selected")
1978    if bssid2 not in ev:
1979        raise Exception("Unexpected BSSID after reconnection")
1980
1981def test_ap_hs20_domain_suffix_match_full(dev, apdev):
1982    """Hotspot 2.0 and domain_suffix_match"""
1983    check_domain_match_full(dev[0])
1984    check_eap_capa(dev[0], "MSCHAPV2")
1985    bssid = apdev[0]['bssid']
1986    params = hs20_ap_params()
1987    hostapd.add_ap(apdev[0], params)
1988
1989    dev[0].hs20_enable()
1990    id = dev[0].add_cred_values({'realm': "example.com",
1991                                 'username': "hs20-test",
1992                                 'password': "password",
1993                                 'ca_cert': "auth_serv/ca.pem",
1994                                 'domain': "example.com",
1995                                 'domain_suffix_match': "server.w1.fi"})
1996    interworking_select(dev[0], bssid, "home", freq="2412")
1997    dev[0].dump_monitor()
1998    interworking_connect(dev[0], bssid, "TTLS")
1999    dev[0].request("REMOVE_NETWORK all")
2000    dev[0].dump_monitor()
2001
2002    dev[0].set_cred_quoted(id, "domain_suffix_match", "no-match.example.com")
2003    interworking_select(dev[0], bssid, "home", freq="2412")
2004    dev[0].dump_monitor()
2005    dev[0].request("INTERWORKING_CONNECT " + bssid)
2006    ev = dev[0].wait_event(["CTRL-EVENT-EAP-TLS-CERT-ERROR"])
2007    if ev is None:
2008        raise Exception("TLS certificate error not reported")
2009    if "Domain suffix mismatch" not in ev:
2010        raise Exception("Domain suffix mismatch not reported")
2011
2012def test_ap_hs20_domain_suffix_match(dev, apdev):
2013    """Hotspot 2.0 and domain_suffix_match"""
2014    check_eap_capa(dev[0], "MSCHAPV2")
2015    check_domain_match_full(dev[0])
2016    bssid = apdev[0]['bssid']
2017    params = hs20_ap_params()
2018    hostapd.add_ap(apdev[0], params)
2019
2020    dev[0].hs20_enable()
2021    id = dev[0].add_cred_values({'realm': "example.com",
2022                                 'username': "hs20-test",
2023                                 'password': "password",
2024                                 'ca_cert': "auth_serv/ca.pem",
2025                                 'domain': "example.com",
2026                                 'domain_suffix_match': "w1.fi"})
2027    interworking_select(dev[0], bssid, "home", freq="2412")
2028    dev[0].dump_monitor()
2029    interworking_connect(dev[0], bssid, "TTLS")
2030
2031def test_ap_hs20_roaming_partner_preference(dev, apdev):
2032    """Hotspot 2.0 and roaming partner preference"""
2033    check_eap_capa(dev[0], "MSCHAPV2")
2034    params = hs20_ap_params()
2035    params['domain_name'] = "roaming.example.org"
2036    hapd0 = hostapd.add_ap(apdev[0], params)
2037
2038    params = hs20_ap_params()
2039    params['ssid'] = "test-hs20-other"
2040    params['domain_name'] = "roaming.example.net"
2041    hapd1 = hostapd.add_ap(apdev[1], params)
2042
2043    logger.info("Verify default vs. specified preference")
2044    values = default_cred()
2045    values['roaming_partner'] = "roaming.example.net,1,127,*"
2046    policy_test(dev[0], apdev[1], hapd1, values, only_one=False)
2047    values['roaming_partner'] = "roaming.example.net,1,129,*"
2048    policy_test(dev[0], apdev[0], hapd0, values, only_one=False)
2049
2050    logger.info("Verify partial FQDN match")
2051    values['roaming_partner'] = "example.net,0,0,*"
2052    policy_test(dev[0], apdev[1], hapd1, values, only_one=False)
2053    values['roaming_partner'] = "example.net,0,255,*"
2054    policy_test(dev[0], apdev[0], hapd0, values, only_one=False)
2055
2056def test_ap_hs20_max_bss_load(dev, apdev):
2057    """Hotspot 2.0 and maximum BSS load"""
2058    check_eap_capa(dev[0], "MSCHAPV2")
2059    params = hs20_ap_params()
2060    params['bss_load_test'] = "12:200:20000"
2061    hapd0 = hostapd.add_ap(apdev[0], params)
2062
2063    params = hs20_ap_params()
2064    params['ssid'] = "test-hs20-other"
2065    params['bss_load_test'] = "5:20:10000"
2066    hapd1 = hostapd.add_ap(apdev[1], params)
2067
2068    logger.info("Verify maximum BSS load constraint")
2069    values = default_cred()
2070    values['domain'] = "example.com"
2071    values['max_bss_load'] = "100"
2072    events = policy_test(dev[0], apdev[1], hapd1, values, only_one=False)
2073
2074    ev = [e for e in events if "INTERWORKING-AP " + apdev[0]['bssid'] in e]
2075    if len(ev) != 1 or "over_max_bss_load=1" not in ev[0]:
2076        raise Exception("Maximum BSS Load case not noticed")
2077    ev = [e for e in events if "INTERWORKING-AP " + apdev[1]['bssid'] in e]
2078    if len(ev) != 1 or "over_max_bss_load=1" in ev[0]:
2079        raise Exception("Maximum BSS Load case reported incorrectly")
2080
2081    logger.info("Verify maximum BSS load does not prevent connection")
2082    values['max_bss_load'] = "1"
2083    events = policy_test(dev[0], None, None, values)
2084
2085    ev = [e for e in events if "INTERWORKING-AP " + apdev[0]['bssid'] in e]
2086    if len(ev) != 1 or "over_max_bss_load=1" not in ev[0]:
2087        raise Exception("Maximum BSS Load case not noticed")
2088    ev = [e for e in events if "INTERWORKING-AP " + apdev[1]['bssid'] in e]
2089    if len(ev) != 1 or "over_max_bss_load=1" not in ev[0]:
2090        raise Exception("Maximum BSS Load case not noticed")
2091
2092def test_ap_hs20_max_bss_load2(dev, apdev):
2093    """Hotspot 2.0 and maximum BSS load with one AP not advertising"""
2094    check_eap_capa(dev[0], "MSCHAPV2")
2095    params = hs20_ap_params()
2096    params['bss_load_test'] = "12:200:20000"
2097    hostapd.add_ap(apdev[0], params)
2098
2099    params = hs20_ap_params()
2100    params['ssid'] = "test-hs20-other"
2101    hapd1 = hostapd.add_ap(apdev[1], params)
2102
2103    logger.info("Verify maximum BSS load constraint with AP advertisement")
2104    values = default_cred()
2105    values['domain'] = "example.com"
2106    values['max_bss_load'] = "100"
2107    events = policy_test(dev[0], apdev[1], hapd1, values, only_one=False)
2108
2109    ev = [e for e in events if "INTERWORKING-AP " + apdev[0]['bssid'] in e]
2110    if len(ev) != 1 or "over_max_bss_load=1" not in ev[0]:
2111        raise Exception("Maximum BSS Load case not noticed")
2112    ev = [e for e in events if "INTERWORKING-AP " + apdev[1]['bssid'] in e]
2113    if len(ev) != 1 or "over_max_bss_load=1" in ev[0]:
2114        raise Exception("Maximum BSS Load case reported incorrectly")
2115
2116def test_ap_hs20_max_bss_load_roaming(dev, apdev):
2117    """Hotspot 2.0 and maximum BSS load (roaming)"""
2118    check_eap_capa(dev[0], "MSCHAPV2")
2119    params = hs20_ap_params()
2120    params['bss_load_test'] = "12:200:20000"
2121    hapd0 = hostapd.add_ap(apdev[0], params)
2122
2123    values = default_cred()
2124    values['domain'] = "roaming.example.com"
2125    values['max_bss_load'] = "100"
2126    events = policy_test(dev[0], apdev[0], hapd0, values, only_one=True)
2127    ev = [e for e in events if "INTERWORKING-AP " + apdev[0]['bssid'] in e]
2128    if len(ev) != 1:
2129        raise Exception("No INTERWORKING-AP event")
2130    if "over_max_bss_load=1" in ev[0]:
2131        raise Exception("Maximum BSS Load reported for roaming")
2132
2133def test_ap_hs20_multi_cred_sp_prio(dev, apdev):
2134    """Hotspot 2.0 multi-cred sp_priority"""
2135    check_eap_capa(dev[0], "MSCHAPV2")
2136    try:
2137        _test_ap_hs20_multi_cred_sp_prio(dev, apdev)
2138    finally:
2139        dev[0].request("SET external_sim 0")
2140
2141def _test_ap_hs20_multi_cred_sp_prio(dev, apdev):
2142    hlr_auc_gw_available()
2143    bssid = apdev[0]['bssid']
2144    params = hs20_ap_params()
2145    params['hessid'] = bssid
2146    del params['domain_name']
2147    params['anqp_3gpp_cell_net'] = "232,01"
2148    hostapd.add_ap(apdev[0], params)
2149
2150    dev[0].hs20_enable()
2151    dev[0].scan_for_bss(bssid, freq="2412")
2152    dev[0].request("SET external_sim 1")
2153    id1 = dev[0].add_cred_values({'imsi': "23201-0000000000", 'eap': "SIM",
2154                                  'provisioning_sp': "example.com",
2155                                  'sp_priority' :"1"})
2156    id2 = dev[0].add_cred_values({'realm': "example.com",
2157                                  'ca_cert': "auth_serv/ca.pem",
2158                                  'username': "hs20-test",
2159                                  'password': "password",
2160                                  'domain': "example.com",
2161                                  'provisioning_sp': "example.com",
2162                                  'sp_priority': "2"})
2163    dev[0].dump_monitor()
2164    dev[0].scan_for_bss(bssid, freq="2412")
2165    dev[0].request("INTERWORKING_SELECT auto freq=2412")
2166    interworking_ext_sim_auth(dev[0], "SIM")
2167    check_sp_type(dev[0], "unknown")
2168    dev[0].request("REMOVE_NETWORK all")
2169
2170    dev[0].set_cred(id1, "sp_priority", "2")
2171    dev[0].set_cred(id2, "sp_priority", "1")
2172    dev[0].dump_monitor()
2173    dev[0].request("INTERWORKING_SELECT auto freq=2412")
2174    interworking_auth(dev[0], "TTLS")
2175    check_sp_type(dev[0], "unknown")
2176
2177def test_ap_hs20_multi_cred_sp_prio2(dev, apdev):
2178    """Hotspot 2.0 multi-cred sp_priority with two BSSes"""
2179    check_eap_capa(dev[0], "MSCHAPV2")
2180    try:
2181        _test_ap_hs20_multi_cred_sp_prio2(dev, apdev)
2182    finally:
2183        dev[0].request("SET external_sim 0")
2184
2185def _test_ap_hs20_multi_cred_sp_prio2(dev, apdev):
2186    hlr_auc_gw_available()
2187    bssid = apdev[0]['bssid']
2188    params = hs20_ap_params()
2189    params['hessid'] = bssid
2190    del params['nai_realm']
2191    del params['domain_name']
2192    params['anqp_3gpp_cell_net'] = "232,01"
2193    hostapd.add_ap(apdev[0], params)
2194
2195    bssid2 = apdev[1]['bssid']
2196    params = hs20_ap_params()
2197    params['ssid'] = "test-hs20-other"
2198    params['hessid'] = bssid2
2199    del params['domain_name']
2200    del params['anqp_3gpp_cell_net']
2201    hostapd.add_ap(apdev[1], params)
2202
2203    dev[0].hs20_enable()
2204    dev[0].request("SET external_sim 1")
2205    id1 = dev[0].add_cred_values({'imsi': "23201-0000000000", 'eap': "SIM",
2206                                  'provisioning_sp': "example.com",
2207                                  'sp_priority': "1"})
2208    id2 = dev[0].add_cred_values({'realm': "example.com",
2209                                  'ca_cert': "auth_serv/ca.pem",
2210                                  'username': "hs20-test",
2211                                  'password': "password",
2212                                  'domain': "example.com",
2213                                  'provisioning_sp': "example.com",
2214                                  'sp_priority': "2"})
2215    dev[0].dump_monitor()
2216    dev[0].scan_for_bss(bssid, freq="2412")
2217    dev[0].scan_for_bss(bssid2, freq="2412")
2218    dev[0].request("INTERWORKING_SELECT auto freq=2412")
2219    interworking_ext_sim_auth(dev[0], "SIM")
2220    check_sp_type(dev[0], "unknown")
2221    conn_bssid = dev[0].get_status_field("bssid")
2222    if conn_bssid != bssid:
2223        raise Exception("Connected to incorrect BSS")
2224    dev[0].request("REMOVE_NETWORK all")
2225
2226    dev[0].set_cred(id1, "sp_priority", "2")
2227    dev[0].set_cred(id2, "sp_priority", "1")
2228    dev[0].dump_monitor()
2229    dev[0].request("INTERWORKING_SELECT auto freq=2412")
2230    interworking_auth(dev[0], "TTLS")
2231    check_sp_type(dev[0], "unknown")
2232    conn_bssid = dev[0].get_status_field("bssid")
2233    if conn_bssid != bssid2:
2234        raise Exception("Connected to incorrect BSS")
2235
2236def test_ap_hs20_multi_cred_sp_prio_same(dev, apdev):
2237    """Hotspot 2.0 multi-cred and same sp_priority"""
2238    check_eap_capa(dev[0], "MSCHAPV2")
2239    hlr_auc_gw_available()
2240    bssid = apdev[0]['bssid']
2241    params = hs20_ap_params()
2242    params['hessid'] = bssid
2243    del params['domain_name']
2244    params['anqp_3gpp_cell_net'] = "232,01"
2245    hostapd.add_ap(apdev[0], params)
2246
2247    dev[0].hs20_enable()
2248    dev[0].scan_for_bss(bssid, freq="2412")
2249    id1 = dev[0].add_cred_values({'realm': "example.com",
2250                                  'ca_cert': "auth_serv/ca.pem",
2251                                  'username': "hs20-test",
2252                                  'password': "password",
2253                                  'domain': "domain1.example.com",
2254                                  'provisioning_sp': "example.com",
2255                                  'sp_priority': "1"})
2256    id2 = dev[0].add_cred_values({'realm': "example.com",
2257                                  'ca_cert': "auth_serv/ca.pem",
2258                                  'username': "hs20-test",
2259                                  'password': "password",
2260                                  'domain': "domain2.example.com",
2261                                  'provisioning_sp': "example.com",
2262                                  'sp_priority': "1"})
2263    dev[0].dump_monitor()
2264    dev[0].scan_for_bss(bssid, freq="2412")
2265    check_auto_select(dev[0], bssid)
2266
2267def check_conn_capab_selection(dev, type, missing):
2268    dev.request("INTERWORKING_SELECT freq=2412")
2269    ev = dev.wait_event(["INTERWORKING-AP"])
2270    if ev is None:
2271        raise Exception("Network selection timed out")
2272    if "type=" + type not in ev:
2273        raise Exception("Unexpected network type")
2274    if missing and "conn_capab_missing=1" not in ev:
2275        raise Exception("conn_capab_missing not reported")
2276    if not missing and "conn_capab_missing=1" in ev:
2277        raise Exception("conn_capab_missing reported unexpectedly")
2278
2279def conn_capab_cred(domain=None, req_conn_capab=None):
2280    cred = default_cred(domain=domain)
2281    if req_conn_capab:
2282        cred['req_conn_capab'] = req_conn_capab
2283    return cred
2284
2285def test_ap_hs20_req_conn_capab(dev, apdev):
2286    """Hotspot 2.0 network selection with req_conn_capab"""
2287    check_eap_capa(dev[0], "MSCHAPV2")
2288    bssid = apdev[0]['bssid']
2289    params = hs20_ap_params()
2290    hapd = hostapd.add_ap(apdev[0], params)
2291
2292    dev[0].hs20_enable()
2293    dev[0].scan_for_bss(bssid, freq="2412")
2294    logger.info("Not used in home network")
2295    values = conn_capab_cred(domain="example.com", req_conn_capab="6:1234")
2296    id = dev[0].add_cred_values(values)
2297    check_conn_capab_selection(dev[0], "home", False)
2298
2299    logger.info("Used in roaming network")
2300    dev[0].remove_cred(id)
2301    values = conn_capab_cred(domain="example.org", req_conn_capab="6:1234")
2302    id = dev[0].add_cred_values(values)
2303    check_conn_capab_selection(dev[0], "roaming", True)
2304
2305    logger.info("Verify that req_conn_capab does not prevent connection if no other network is available")
2306    check_auto_select(dev[0], bssid, hapd=hapd)
2307
2308    logger.info("Additional req_conn_capab checks")
2309
2310    dev[0].remove_cred(id)
2311    values = conn_capab_cred(domain="example.org", req_conn_capab="1:0")
2312    id = dev[0].add_cred_values(values)
2313    check_conn_capab_selection(dev[0], "roaming", True)
2314
2315    dev[0].remove_cred(id)
2316    values = conn_capab_cred(domain="example.org", req_conn_capab="17:5060")
2317    id = dev[0].add_cred_values(values)
2318    check_conn_capab_selection(dev[0], "roaming", True)
2319
2320    bssid2 = apdev[1]['bssid']
2321    params = hs20_ap_params(ssid="test-hs20b")
2322    params['hs20_conn_capab'] = ["1:0:2", "6:22:1", "17:5060:0", "50:0:1"]
2323    hostapd.add_ap(apdev[1], params)
2324
2325    dev[0].remove_cred(id)
2326    values = conn_capab_cred(domain="example.org", req_conn_capab="50")
2327    id = dev[0].add_cred_values(values)
2328    dev[0].set_cred(id, "req_conn_capab", "6:22")
2329    dev[0].scan_for_bss(bssid2, freq="2412")
2330    dev[0].request("INTERWORKING_SELECT freq=2412")
2331    for i in range(0, 2):
2332        ev = dev[0].wait_event(["INTERWORKING-AP"])
2333        if ev is None:
2334            raise Exception("Network selection timed out")
2335        if bssid in ev and "conn_capab_missing=1" not in ev:
2336            raise Exception("Missing protocol connection capability not reported")
2337        if bssid2 in ev and "conn_capab_missing=1" in ev:
2338            raise Exception("Protocol connection capability not reported correctly")
2339
2340def test_ap_hs20_req_conn_capab2(dev, apdev):
2341    """Hotspot 2.0 network selection with req_conn_capab (not present)"""
2342    check_eap_capa(dev[0], "MSCHAPV2")
2343    bssid = apdev[0]['bssid']
2344    params = hs20_ap_params()
2345    del params['hs20_conn_capab']
2346    hostapd.add_ap(apdev[0], params)
2347
2348    dev[0].hs20_enable()
2349    dev[0].scan_for_bss(bssid, freq="2412")
2350    values = conn_capab_cred(domain="example.org", req_conn_capab="6:1234")
2351    id = dev[0].add_cred_values(values)
2352    check_conn_capab_selection(dev[0], "roaming", False)
2353
2354def test_ap_hs20_req_conn_capab_and_roaming_partner_preference(dev, apdev):
2355    """Hotspot 2.0 and req_conn_capab with roaming partner preference"""
2356    check_eap_capa(dev[0], "MSCHAPV2")
2357    bssid = apdev[0]['bssid']
2358    params = hs20_ap_params()
2359    params['domain_name'] = "roaming.example.org"
2360    params['hs20_conn_capab'] = ["1:0:2", "6:22:1", "17:5060:0", "50:0:1"]
2361    hapd = hostapd.add_ap(apdev[0], params)
2362
2363    bssid2 = apdev[1]['bssid']
2364    params = hs20_ap_params(ssid="test-hs20-b")
2365    params['domain_name'] = "roaming.example.net"
2366    hapd2 = hostapd.add_ap(apdev[1], params)
2367
2368    values = default_cred()
2369    values['roaming_partner'] = "roaming.example.net,1,127,*"
2370    id = dev[0].add_cred_values(values)
2371    check_auto_select(dev[0], bssid2, hapd=hapd2)
2372
2373    dev[0].set_cred(id, "req_conn_capab", "50")
2374    check_auto_select(dev[0], bssid, hapd=hapd)
2375
2376    dev[0].remove_cred(id)
2377    id = dev[0].add_cred_values(values)
2378    dev[0].set_cred(id, "req_conn_capab", "51")
2379    check_auto_select(dev[0], bssid2, hapd=hapd2)
2380
2381def check_bandwidth_selection(dev, type, below):
2382    dev.request("INTERWORKING_SELECT freq=2412")
2383    ev = dev.wait_event(["INTERWORKING-AP"])
2384    if ev is None:
2385        raise Exception("Network selection timed out")
2386    logger.debug("BSS entries:\n" + dev.request("BSS RANGE=ALL"))
2387    if "type=" + type not in ev:
2388        raise Exception("Unexpected network type")
2389    if below and "below_min_backhaul=1" not in ev:
2390        raise Exception("below_min_backhaul not reported")
2391    if not below and "below_min_backhaul=1" in ev:
2392        raise Exception("below_min_backhaul reported unexpectedly")
2393
2394def bw_cred(domain=None, dl_home=None, ul_home=None, dl_roaming=None, ul_roaming=None):
2395    cred = default_cred(domain=domain)
2396    if dl_home:
2397        cred['min_dl_bandwidth_home'] = str(dl_home)
2398    if ul_home:
2399        cred['min_ul_bandwidth_home'] = str(ul_home)
2400    if dl_roaming:
2401        cred['min_dl_bandwidth_roaming'] = str(dl_roaming)
2402    if ul_roaming:
2403        cred['min_ul_bandwidth_roaming'] = str(ul_roaming)
2404    return cred
2405
2406def test_ap_hs20_min_bandwidth_home(dev, apdev):
2407    """Hotspot 2.0 network selection with min bandwidth (home)"""
2408    check_eap_capa(dev[0], "MSCHAPV2")
2409    bssid = apdev[0]['bssid']
2410    params = hs20_ap_params()
2411    hapd = hostapd.add_ap(apdev[0], params)
2412
2413    dev[0].hs20_enable()
2414    dev[0].scan_for_bss(bssid, freq="2412")
2415    values = bw_cred(domain="example.com", dl_home=5490, ul_home=58)
2416    id = dev[0].add_cred_values(values)
2417    check_bandwidth_selection(dev[0], "home", False)
2418    dev[0].remove_cred(id)
2419
2420    values = bw_cred(domain="example.com", dl_home=5491, ul_home=58)
2421    id = dev[0].add_cred_values(values)
2422    check_bandwidth_selection(dev[0], "home", True)
2423    dev[0].remove_cred(id)
2424
2425    values = bw_cred(domain="example.com", dl_home=5490, ul_home=59)
2426    id = dev[0].add_cred_values(values)
2427    check_bandwidth_selection(dev[0], "home", True)
2428    dev[0].remove_cred(id)
2429
2430    values = bw_cred(domain="example.com", dl_home=5491, ul_home=59)
2431    id = dev[0].add_cred_values(values)
2432    check_bandwidth_selection(dev[0], "home", True)
2433    check_auto_select(dev[0], bssid, hapd=hapd)
2434
2435    bssid2 = apdev[1]['bssid']
2436    params = hs20_ap_params(ssid="test-hs20-b")
2437    params['hs20_wan_metrics'] = "01:8000:1000:1:1:3000"
2438    hapd2 = hostapd.add_ap(apdev[1], params)
2439
2440    check_auto_select(dev[0], bssid2, hapd=hapd2)
2441
2442def test_ap_hs20_min_bandwidth_home2(dev, apdev):
2443    """Hotspot 2.0 network selection with min bandwidth - special cases"""
2444    check_eap_capa(dev[0], "MSCHAPV2")
2445    bssid = apdev[0]['bssid']
2446    params = hs20_ap_params()
2447    hapd = hostapd.add_ap(apdev[0], params)
2448
2449    dev[0].hs20_enable()
2450    dev[0].scan_for_bss(bssid, freq="2412")
2451    values = bw_cred(domain="example.com", dl_home=5490, ul_home=58)
2452    id = dev[0].add_cred_values(values)
2453    check_bandwidth_selection(dev[0], "home", False)
2454
2455    logger.info("WAN link at capacity")
2456    hapd.set('hs20_wan_metrics', "09:8000:1000:80:240:3000")
2457    check_bandwidth_selection(dev[0], "home", True)
2458
2459    logger.info("Downlink/Uplink Load was not measured")
2460    hapd.set('hs20_wan_metrics', "01:8000:1000:80:240:0")
2461    check_bandwidth_selection(dev[0], "home", False)
2462
2463    logger.info("Uplink and Downlink max values")
2464    hapd.set('hs20_wan_metrics', "01:4294967295:4294967295:80:240:3000")
2465    check_bandwidth_selection(dev[0], "home", False)
2466
2467    dev[0].remove_cred(id)
2468
2469def test_ap_hs20_min_bandwidth_home_hidden_ssid_in_scan_res(dev, apdev):
2470    """Hotspot 2.0 network selection with min bandwidth (home) while hidden SSID is included in scan results"""
2471    check_eap_capa(dev[0], "MSCHAPV2")
2472    bssid = apdev[0]['bssid']
2473
2474    hapd = hostapd.add_ap(apdev[0], {"ssid": 'secret',
2475                                     "ignore_broadcast_ssid": "1"})
2476    dev[0].scan_for_bss(bssid, freq=2412)
2477    hapd.disable()
2478    hapd_global = hostapd.HostapdGlobal(apdev[0])
2479    hapd_global.flush()
2480    hapd_global.remove(apdev[0]['ifname'])
2481
2482    params = hs20_ap_params()
2483    hapd = hostapd.add_ap(apdev[0], params)
2484
2485    dev[0].hs20_enable()
2486    dev[0].scan_for_bss(bssid, freq="2412")
2487    values = bw_cred(domain="example.com", dl_home=5490, ul_home=58)
2488    id = dev[0].add_cred_values(values)
2489    check_bandwidth_selection(dev[0], "home", False)
2490    dev[0].remove_cred(id)
2491
2492    values = bw_cred(domain="example.com", dl_home=5491, ul_home=58)
2493    id = dev[0].add_cred_values(values)
2494    check_bandwidth_selection(dev[0], "home", True)
2495    dev[0].remove_cred(id)
2496
2497    values = bw_cred(domain="example.com", dl_home=5490, ul_home=59)
2498    id = dev[0].add_cred_values(values)
2499    check_bandwidth_selection(dev[0], "home", True)
2500    dev[0].remove_cred(id)
2501
2502    values = bw_cred(domain="example.com", dl_home=5491, ul_home=59)
2503    id = dev[0].add_cred_values(values)
2504    check_bandwidth_selection(dev[0], "home", True)
2505    check_auto_select(dev[0], bssid, hapd=hapd)
2506
2507    bssid2 = apdev[1]['bssid']
2508    params = hs20_ap_params(ssid="test-hs20-b")
2509    params['hs20_wan_metrics'] = "01:8000:1000:1:1:3000"
2510    hapd2 = hostapd.add_ap(apdev[1], params)
2511
2512    check_auto_select(dev[0], bssid2, hapd=hapd2)
2513
2514    dev[0].flush_scan_cache()
2515
2516def test_ap_hs20_min_bandwidth_roaming(dev, apdev):
2517    """Hotspot 2.0 network selection with min bandwidth (roaming)"""
2518    check_eap_capa(dev[0], "MSCHAPV2")
2519    bssid = apdev[0]['bssid']
2520    params = hs20_ap_params()
2521    hapd = hostapd.add_ap(apdev[0], params)
2522
2523    dev[0].hs20_enable()
2524    dev[0].scan_for_bss(bssid, freq="2412")
2525    values = bw_cred(domain="example.org", dl_roaming=5490, ul_roaming=58)
2526    id = dev[0].add_cred_values(values)
2527    check_bandwidth_selection(dev[0], "roaming", False)
2528    dev[0].remove_cred(id)
2529
2530    values = bw_cred(domain="example.org", dl_roaming=5491, ul_roaming=58)
2531    id = dev[0].add_cred_values(values)
2532    check_bandwidth_selection(dev[0], "roaming", True)
2533    dev[0].remove_cred(id)
2534
2535    values = bw_cred(domain="example.org", dl_roaming=5490, ul_roaming=59)
2536    id = dev[0].add_cred_values(values)
2537    check_bandwidth_selection(dev[0], "roaming", True)
2538    dev[0].remove_cred(id)
2539
2540    values = bw_cred(domain="example.org", dl_roaming=5491, ul_roaming=59)
2541    id = dev[0].add_cred_values(values)
2542    check_bandwidth_selection(dev[0], "roaming", True)
2543    check_auto_select(dev[0], bssid, hapd=hapd)
2544
2545    bssid2 = apdev[1]['bssid']
2546    params = hs20_ap_params(ssid="test-hs20-b")
2547    params['hs20_wan_metrics'] = "01:8000:1000:1:1:3000"
2548    hapd2 = hostapd.add_ap(apdev[1], params)
2549
2550    check_auto_select(dev[0], bssid2, hapd=hapd2)
2551
2552def test_ap_hs20_min_bandwidth_and_roaming_partner_preference(dev, apdev):
2553    """Hotspot 2.0 and minimum bandwidth with roaming partner preference"""
2554    check_eap_capa(dev[0], "MSCHAPV2")
2555    bssid = apdev[0]['bssid']
2556    params = hs20_ap_params()
2557    params['domain_name'] = "roaming.example.org"
2558    params['hs20_wan_metrics'] = "01:8000:1000:1:1:3000"
2559    hapd = hostapd.add_ap(apdev[0], params)
2560
2561    bssid2 = apdev[1]['bssid']
2562    params = hs20_ap_params(ssid="test-hs20-b")
2563    params['domain_name'] = "roaming.example.net"
2564    hapd2 = hostapd.add_ap(apdev[1], params)
2565
2566    values = default_cred()
2567    values['roaming_partner'] = "roaming.example.net,1,127,*"
2568    id = dev[0].add_cred_values(values)
2569    check_auto_select(dev[0], bssid2, hapd=hapd2)
2570
2571    dev[0].set_cred(id, "min_dl_bandwidth_roaming", "6000")
2572    check_auto_select(dev[0], bssid, hapd=hapd)
2573
2574    dev[0].set_cred(id, "min_dl_bandwidth_roaming", "10000")
2575    check_auto_select(dev[0], bssid2, hapd=hapd2)
2576
2577def test_ap_hs20_min_bandwidth_no_wan_metrics(dev, apdev):
2578    """Hotspot 2.0 network selection with min bandwidth but no WAN Metrics"""
2579    bssid = apdev[0]['bssid']
2580    params = hs20_ap_params()
2581    del params['hs20_wan_metrics']
2582    hostapd.add_ap(apdev[0], params)
2583
2584    dev[0].hs20_enable()
2585    dev[0].scan_for_bss(bssid, freq="2412")
2586    values = bw_cred(domain="example.com", dl_home=10000, ul_home=10000,
2587                     dl_roaming=10000, ul_roaming=10000)
2588    dev[0].add_cred_values(values)
2589    check_bandwidth_selection(dev[0], "home", False)
2590
2591def test_ap_hs20_deauth_req_ess(dev, apdev):
2592    """Hotspot 2.0 connection and deauthentication request for ESS"""
2593    check_eap_capa(dev[0], "MSCHAPV2")
2594    try:
2595        _test_ap_hs20_deauth_req_ess(dev, apdev)
2596    finally:
2597        dev[0].request("SET pmf 0")
2598
2599def _test_ap_hs20_deauth_req_ess(dev, apdev):
2600    dev[0].request("SET pmf 2")
2601    hapd = eap_test(dev[0], apdev[0], "21[3:26]", "TTLS", "user")
2602    dev[0].dump_monitor()
2603    addr = dev[0].p2p_interface_addr()
2604    hapd.wait_sta()
2605    hapd.request("HS20_DEAUTH_REQ " + addr + " 1 120 http://example.com/")
2606    ev = dev[0].wait_event(["HS20-DEAUTH-IMMINENT-NOTICE"])
2607    if ev is None:
2608        raise Exception("Timeout on deauth imminent notice")
2609    if "1 120 http://example.com/" not in ev:
2610        raise Exception("Unexpected deauth imminent notice: " + ev)
2611    hapd.request("DEAUTHENTICATE " + addr)
2612    dev[0].wait_disconnected(timeout=10)
2613    if "[TEMP-DISABLED]" not in dev[0].list_networks()[0]['flags']:
2614        raise Exception("Network not marked temporarily disabled")
2615    ev = dev[0].wait_event(["SME: Trying to authenticate",
2616                            "Trying to associate",
2617                            "CTRL-EVENT-CONNECTED"], timeout=5)
2618    if ev is not None:
2619        raise Exception("Unexpected connection attempt")
2620
2621def test_ap_hs20_deauth_req_bss(dev, apdev):
2622    """Hotspot 2.0 connection and deauthentication request for BSS"""
2623    check_eap_capa(dev[0], "MSCHAPV2")
2624    try:
2625        _test_ap_hs20_deauth_req_bss(dev, apdev)
2626    finally:
2627        dev[0].request("SET pmf 0")
2628
2629def _test_ap_hs20_deauth_req_bss(dev, apdev):
2630    dev[0].request("SET pmf 2")
2631    hapd = eap_test(dev[0], apdev[0], "21[3:26]", "TTLS", "user")
2632    dev[0].dump_monitor()
2633    addr = dev[0].p2p_interface_addr()
2634    hapd.wait_sta()
2635    hapd.request("HS20_DEAUTH_REQ " + addr + " 0 120 http://example.com/")
2636    ev = dev[0].wait_event(["HS20-DEAUTH-IMMINENT-NOTICE"])
2637    if ev is None:
2638        raise Exception("Timeout on deauth imminent notice")
2639    if "0 120 http://example.com/" not in ev:
2640        raise Exception("Unexpected deauth imminent notice: " + ev)
2641    hapd.request("DEAUTHENTICATE " + addr + " reason=4")
2642    ev = dev[0].wait_disconnected(timeout=10)
2643    if "reason=4" not in ev:
2644        raise Exception("Unexpected disconnection reason")
2645    if "[TEMP-DISABLED]" not in dev[0].list_networks()[0]['flags']:
2646        raise Exception("Network not marked temporarily disabled")
2647    ev = dev[0].wait_event(["SME: Trying to authenticate",
2648                            "Trying to associate",
2649                            "CTRL-EVENT-CONNECTED"], timeout=5)
2650    if ev is not None:
2651        raise Exception("Unexpected connection attempt")
2652
2653def test_ap_hs20_deauth_req_from_radius(dev, apdev):
2654    """Hotspot 2.0 connection and deauthentication request from RADIUS"""
2655    check_eap_capa(dev[0], "MSCHAPV2")
2656    try:
2657        _test_ap_hs20_deauth_req_from_radius(dev, apdev)
2658    finally:
2659        dev[0].request("SET pmf 0")
2660
2661def test_ap_hs20_deauth_req_from_radius_url(dev, apdev):
2662    """Hotspot 2.0 connection and deauthentication request from RADIUS with URL"""
2663    check_eap_capa(dev[0], "MSCHAPV2")
2664    try:
2665        _test_ap_hs20_deauth_req_from_radius(dev, apdev, url=True)
2666    finally:
2667        dev[0].set("pmf", "0")
2668
2669def _test_ap_hs20_deauth_req_from_radius(dev, apdev, url=False):
2670    bssid = apdev[0]['bssid']
2671    params = hs20_ap_params()
2672    params['nai_realm'] = ["0,example.com,21[2:4]"]
2673    params['hs20_deauth_req_timeout'] = "2"
2674    hostapd.add_ap(apdev[0], params)
2675
2676    dev[0].request("SET pmf 2")
2677    dev[0].hs20_enable()
2678    user = "hs20-deauth-test-url" if url else "hs20-deauth-test"
2679    dev[0].add_cred_values({'realm': "example.com",
2680                            'username': user,
2681                            'password': "password"})
2682    interworking_select(dev[0], bssid, freq="2412")
2683    interworking_connect(dev[0], bssid, "TTLS")
2684    ev = dev[0].wait_event(["HS20-DEAUTH-IMMINENT-NOTICE"], timeout=5)
2685    if ev is None:
2686        raise Exception("Timeout on deauth imminent notice")
2687    if not url and ev.split(' ', 1)[1] != "1 100 ":
2688        raise Exception("Unexpected deauth imminent contents: " + ev)
2689    if url and ev.split(' ', 1)[1] != "0 0 https://example.com/deauth/":
2690        raise Exception("Unexpected deauth imminent contents: " + ev)
2691    dev[0].wait_disconnected(timeout=3 if url else 1)
2692
2693def test_ap_hs20_deauth_req_without_pmf(dev, apdev):
2694    """Hotspot 2.0 connection and deauthentication request without PMF"""
2695    check_eap_capa(dev[0], "MSCHAPV2")
2696    dev[0].request("SET pmf 0")
2697    hapd = eap_test(dev[0], apdev[0], "21[3:26]", "TTLS", "user", release=1)
2698    dev[0].dump_monitor()
2699    id = int(dev[0].get_status_field("id"))
2700    dev[0].set_network(id, "ieee80211w", "0")
2701    dev[0].request("DISCONNECT")
2702    dev[0].wait_disconnected()
2703    dev[0].select_network(id, freq=2412)
2704    dev[0].wait_connected()
2705    addr = dev[0].own_addr()
2706    hapd.wait_sta()
2707    hapd.request("HS20_DEAUTH_REQ " + addr + " 1 120 http://example.com/")
2708    ev = dev[0].wait_event(["HS20-DEAUTH-IMMINENT-NOTICE"], timeout=0.2)
2709    if ev is not None:
2710        raise Exception("Deauth imminent notice without PMF accepted")
2711    with alloc_fail(hapd, 1, "wpabuf_alloc;hostapd_ctrl_iface_hs20_deauth_req"):
2712        if "FAIL" not in hapd.request("HS20_DEAUTH_REQ " + addr + " 1 120 http://example.com/"):
2713            raise Exception("HS20_DEAUTH_REQ accepted during OOM")
2714
2715def test_ap_hs20_deauth_req_pmf_htc(dev, apdev):
2716    """Hotspot 2.0 connection and deauthentication request PMF misbehavior (+HTC)"""
2717    try:
2718        run_ap_hs20_deauth_req_pmf_htc(dev, apdev)
2719    finally:
2720        stop_monitor(apdev[1]["ifname"])
2721
2722def run_ap_hs20_deauth_req_pmf_htc(dev, apdev):
2723    check_eap_capa(dev[0], "MSCHAPV2")
2724    dev[0].request("SET pmf 0")
2725    hapd = eap_test(dev[0], apdev[0], "21[3:26]", "TTLS", "user", release=1)
2726    dev[0].dump_monitor()
2727    addr = dev[0].own_addr()
2728    hapd.wait_sta()
2729
2730    sock = start_monitor(apdev[1]["ifname"])
2731    radiotap = radiotap_build()
2732    bssid = hapd.own_addr().replace(':', '')
2733    addr = dev[0].own_addr().replace(':', '')
2734    payload = "0a1a0101dd1b506f9a0101780013687474703a2f2f6578616d706c652e636f6d2f"
2735    # Claim there is a HT Control field, but then start the frame body from
2736    # there and do not encrypt the Robust Action frame.
2737    frame = binascii.unhexlify("d0803a01" + addr + 2 * bssid + "0000" + payload)
2738    # Claim there is a HT Control field and start the frame body in the correct
2739    # location, but do not encrypt the Robust Action frame. Make the first octet
2740    # of HT Control field use a non-robust Action Category value.
2741    frame2 = binascii.unhexlify("d0803a01" + addr + 2 * bssid + "0000" + "04000000" + payload)
2742
2743    sock.send(radiotap + frame)
2744    sock.send(radiotap + frame2)
2745
2746    ev = dev[0].wait_event(["HS20-DEAUTH-IMMINENT-NOTICE"], timeout=1)
2747    if ev is not None:
2748        raise Exception("Deauth imminent notice without PMF accepted")
2749
2750def test_ap_hs20_session_info(dev, apdev):
2751    """Hotspot 2.0 connection and session information from RADIUS"""
2752    check_eap_capa(dev[0], "MSCHAPV2")
2753    try:
2754        _test_ap_hs20_session_info(dev, apdev)
2755    finally:
2756        dev[0].request("SET pmf 0")
2757
2758def _test_ap_hs20_session_info(dev, apdev):
2759    bssid = apdev[0]['bssid']
2760    params = hs20_ap_params()
2761    params['nai_realm'] = ["0,example.com,21[2:4]"]
2762    hostapd.add_ap(apdev[0], params)
2763
2764    dev[0].request("SET pmf 1")
2765    dev[0].hs20_enable()
2766    dev[0].add_cred_values({'realm': "example.com",
2767                            'username': "hs20-session-info-test",
2768                            'password': "password"})
2769    interworking_select(dev[0], bssid, freq="2412")
2770    interworking_connect(dev[0], bssid, "TTLS")
2771    ev = dev[0].wait_event(["ESS-DISASSOC-IMMINENT"], timeout=10)
2772    if ev is None:
2773        raise Exception("Timeout on ESS disassociation imminent notice")
2774    if " 1 59904 https://example.com/" not in ev:
2775        raise Exception("Unexpected ESS disassociation imminent event contents")
2776    ev = dev[0].wait_event(["CTRL-EVENT-SCAN-STARTED"])
2777    if ev is None:
2778        raise Exception("Scan not started")
2779    ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"], timeout=30)
2780    if ev is None:
2781        raise Exception("Scan not completed")
2782
2783def test_ap_hs20_network_preference(dev, apdev):
2784    """Hotspot 2.0 network selection with preferred home network"""
2785    check_eap_capa(dev[0], "MSCHAPV2")
2786    dev[0].flush_scan_cache()
2787    bssid = apdev[0]['bssid']
2788    params = hs20_ap_params()
2789    hostapd.add_ap(apdev[0], params)
2790
2791    dev[0].hs20_enable()
2792    values = {'realm': "example.com",
2793              'username': "hs20-test",
2794              'password': "password",
2795              'domain': "example.com"}
2796    dev[0].add_cred_values(values)
2797
2798    id = dev[0].add_network()
2799    dev[0].set_network_quoted(id, "ssid", "home")
2800    dev[0].set_network_quoted(id, "psk", "12345678")
2801    dev[0].set_network(id, "priority", "1")
2802    dev[0].request("ENABLE_NETWORK %s no-connect" % id)
2803
2804    dev[0].scan_for_bss(bssid, freq="2412")
2805    dev[0].request("INTERWORKING_SELECT auto freq=2412")
2806    ev = dev[0].wait_connected(timeout=15)
2807    if bssid not in ev:
2808        raise Exception("Unexpected network selected")
2809
2810    bssid2 = apdev[1]['bssid']
2811    params = hostapd.wpa2_params(ssid="home", passphrase="12345678")
2812    hostapd.add_ap(apdev[1], params)
2813
2814    dev[0].scan_for_bss(bssid2, freq="2412")
2815    dev[0].request("INTERWORKING_SELECT auto freq=2412")
2816    ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED",
2817                            "INTERWORKING-ALREADY-CONNECTED"], timeout=15)
2818    if ev is None:
2819        raise Exception("Connection timed out")
2820    if "INTERWORKING-ALREADY-CONNECTED" in ev:
2821        raise Exception("No roam to higher priority network")
2822    if bssid2 not in ev:
2823        raise Exception("Unexpected network selected")
2824
2825def test_ap_hs20_network_preference2(dev, apdev):
2826    """Hotspot 2.0 network selection with preferred credential"""
2827    check_eap_capa(dev[0], "MSCHAPV2")
2828    dev[0].flush_scan_cache()
2829    bssid2 = apdev[1]['bssid']
2830    params = hostapd.wpa2_params(ssid="home", passphrase="12345678")
2831    hostapd.add_ap(apdev[1], params)
2832
2833    dev[0].hs20_enable()
2834    values = {'realm': "example.com",
2835              'username': "hs20-test",
2836              'password': "password",
2837              'domain': "example.com",
2838              'priority': "1"}
2839    dev[0].add_cred_values(values)
2840
2841    id = dev[0].add_network()
2842    dev[0].set_network_quoted(id, "ssid", "home")
2843    dev[0].set_network_quoted(id, "psk", "12345678")
2844    dev[0].request("ENABLE_NETWORK %s no-connect" % id)
2845
2846    dev[0].scan_for_bss(bssid2, freq="2412")
2847    dev[0].request("INTERWORKING_SELECT auto freq=2412")
2848    ev = dev[0].wait_connected(timeout=15)
2849    if bssid2 not in ev:
2850        raise Exception("Unexpected network selected")
2851
2852    bssid = apdev[0]['bssid']
2853    params = hs20_ap_params()
2854    hostapd.add_ap(apdev[0], params)
2855
2856    dev[0].scan_for_bss(bssid, freq="2412")
2857    dev[0].request("INTERWORKING_SELECT auto freq=2412")
2858    ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED",
2859                            "INTERWORKING-ALREADY-CONNECTED"], timeout=15)
2860    if ev is None:
2861        raise Exception("Connection timed out")
2862    if "INTERWORKING-ALREADY-CONNECTED" in ev:
2863        raise Exception("No roam to higher priority network")
2864    if bssid not in ev:
2865        raise Exception("Unexpected network selected")
2866
2867def test_ap_hs20_network_preference3(dev, apdev):
2868    """Hotspot 2.0 network selection with two credential (one preferred)"""
2869    check_eap_capa(dev[0], "MSCHAPV2")
2870    dev[0].flush_scan_cache()
2871    bssid = apdev[0]['bssid']
2872    params = hs20_ap_params()
2873    hostapd.add_ap(apdev[0], params)
2874
2875    bssid2 = apdev[1]['bssid']
2876    params = hs20_ap_params(ssid="test-hs20b")
2877    params['nai_realm'] = "0,example.org,13[5:6],21[2:4][5:7]"
2878    hostapd.add_ap(apdev[1], params)
2879
2880    dev[0].hs20_enable()
2881    values = {'realm': "example.com",
2882              'username': "hs20-test",
2883              'password': "password",
2884              'priority': "1"}
2885    dev[0].add_cred_values(values)
2886    values = {'realm': "example.org",
2887              'username': "hs20-test",
2888              'password': "password"}
2889    id = dev[0].add_cred_values(values)
2890
2891    dev[0].scan_for_bss(bssid, freq="2412")
2892    dev[0].scan_for_bss(bssid2, freq="2412")
2893    dev[0].request("INTERWORKING_SELECT auto freq=2412")
2894    ev = dev[0].wait_connected(timeout=15)
2895    if bssid not in ev:
2896        raise Exception("Unexpected network selected")
2897
2898    dev[0].set_cred(id, "priority", "2")
2899    dev[0].request("INTERWORKING_SELECT auto freq=2412")
2900    ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED",
2901                            "INTERWORKING-ALREADY-CONNECTED"], timeout=15)
2902    if ev is None:
2903        raise Exception("Connection timed out")
2904    if "INTERWORKING-ALREADY-CONNECTED" in ev:
2905        raise Exception("No roam to higher priority network")
2906    if bssid2 not in ev:
2907        raise Exception("Unexpected network selected")
2908
2909def test_ap_hs20_network_preference4(dev, apdev):
2910    """Hotspot 2.0 network selection with username vs. SIM credential"""
2911    check_eap_capa(dev[0], "MSCHAPV2")
2912    dev[0].flush_scan_cache()
2913    bssid = apdev[0]['bssid']
2914    params = hs20_ap_params()
2915    hostapd.add_ap(apdev[0], params)
2916
2917    bssid2 = apdev[1]['bssid']
2918    params = hs20_ap_params(ssid="test-hs20b")
2919    params['hessid'] = bssid2
2920    params['anqp_3gpp_cell_net'] = "555,444"
2921    params['domain_name'] = "wlan.mnc444.mcc555.3gppnetwork.org"
2922    hostapd.add_ap(apdev[1], params)
2923
2924    dev[0].hs20_enable()
2925    values = {'realm': "example.com",
2926              'username': "hs20-test",
2927              'password': "password",
2928              'priority': "1"}
2929    dev[0].add_cred_values(values)
2930    values = {'imsi': "555444-333222111",
2931              'eap': "SIM",
2932              'milenage': "5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123"}
2933    id = dev[0].add_cred_values(values)
2934
2935    dev[0].scan_for_bss(bssid, freq="2412")
2936    dev[0].scan_for_bss(bssid2, freq="2412")
2937    dev[0].request("INTERWORKING_SELECT auto freq=2412")
2938    ev = dev[0].wait_connected(timeout=15)
2939    if bssid not in ev:
2940        raise Exception("Unexpected network selected")
2941
2942    dev[0].set_cred(id, "priority", "2")
2943    dev[0].request("INTERWORKING_SELECT auto freq=2412")
2944    ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED",
2945                            "INTERWORKING-ALREADY-CONNECTED"], timeout=15)
2946    if ev is None:
2947        raise Exception("Connection timed out")
2948    if "INTERWORKING-ALREADY-CONNECTED" in ev:
2949        raise Exception("No roam to higher priority network")
2950    if bssid2 not in ev:
2951        raise Exception("Unexpected network selected")
2952
2953def test_ap_hs20_interworking_select_blocking_scan(dev, apdev):
2954    """Ongoing INTERWORKING_SELECT blocking SCAN"""
2955    check_eap_capa(dev[0], "MSCHAPV2")
2956    bssid = apdev[0]['bssid']
2957    params = hs20_ap_params()
2958    hostapd.add_ap(apdev[0], params)
2959
2960    dev[0].hs20_enable()
2961    values = {'realm': "example.com",
2962              'username': "hs20-test",
2963              'password': "password",
2964              'domain': "example.com"}
2965    dev[0].add_cred_values(values)
2966
2967    dev[0].scan_for_bss(bssid, freq="2412")
2968    dev[0].request("INTERWORKING_SELECT auto freq=2412")
2969    if "FAIL-BUSY" not in dev[0].request("SCAN"):
2970        raise Exception("Unexpected SCAN command result")
2971    dev[0].wait_connected(timeout=15)
2972
2973def test_ap_hs20_ft(dev, apdev):
2974    """Hotspot 2.0 connection with FT"""
2975    check_eap_capa(dev[0], "MSCHAPV2")
2976    bssid = apdev[0]['bssid']
2977    params = hs20_ap_params()
2978    params['wpa_key_mgmt'] = "FT-EAP"
2979    params['nas_identifier'] = "nas1.w1.fi"
2980    params['r1_key_holder'] = "000102030405"
2981    params["mobility_domain"] = "a1b2"
2982    params["reassociation_deadline"] = "1000"
2983    hapd = hostapd.add_ap(apdev[0], params)
2984
2985    dev[0].hs20_enable()
2986    id = dev[0].add_cred_values({'realm': "example.com",
2987                                 'username': "hs20-test",
2988                                 'password': "password",
2989                                 'ca_cert': "auth_serv/ca.pem",
2990                                 'domain': "example.com",
2991                                 'update_identifier': "1234"})
2992    interworking_select(dev[0], bssid, "home", freq="2412")
2993    interworking_connect(dev[0], bssid, "TTLS")
2994    dev[0].dump_monitor()
2995    key_mgmt = dev[0].get_status_field("key_mgmt")
2996    if key_mgmt != "FT-EAP":
2997        raise Exception("Unexpected key_mgmt: " + key_mgmt)
2998    # speed up testing by avoiding unnecessary scanning of other channels
2999    nid = dev[0].get_status_field("id")
3000    dev[0].set_network(nid, "scan_freq", "2412")
3001
3002    params = hs20_ap_params()
3003    hapd2 = hostapd.add_ap(apdev[1], params)
3004
3005    hapd.disable()
3006    ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=10)
3007    if ev is None:
3008        raise Exception("Disconnection not reported")
3009    ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED"], timeout=5)
3010    if ev is None:
3011        raise Exception("Connection to AP2 not reported")
3012    key_mgmt = dev[0].get_status_field("key_mgmt")
3013    if key_mgmt != "WPA2/IEEE 802.1X/EAP":
3014        raise Exception("Unexpected key_mgmt: " + key_mgmt)
3015
3016def test_ap_hs20_external_selection(dev, apdev):
3017    """Hotspot 2.0 connection using external network selection and creation"""
3018    check_eap_capa(dev[0], "MSCHAPV2")
3019    bssid = apdev[0]['bssid']
3020    params = hs20_ap_params()
3021    params['hessid'] = bssid
3022    params['disable_dgaf'] = '1'
3023    hostapd.add_ap(apdev[0], params)
3024
3025    dev[0].hs20_enable()
3026    dev[0].connect("test-hs20", proto="RSN", key_mgmt="WPA-EAP", eap="TTLS",
3027                   ieee80211w="1",
3028                   identity="hs20-test", password="password",
3029                   ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
3030                   scan_freq="2412", update_identifier="54321",
3031                   roaming_consortium_selection="1020304050")
3032    if dev[0].get_status_field("hs20") != "3":
3033        raise Exception("Unexpected hs20 indication")
3034    network_id = dev[0].get_status_field("id")
3035    sel = dev[0].get_network(network_id, "roaming_consortium_selection")
3036    if sel != "1020304050":
3037        raise Exception("Unexpected roaming_consortium_selection value: " + sel)
3038
3039def test_ap_hs20_random_mac_addr(dev, apdev):
3040    """Hotspot 2.0 connection with random MAC address"""
3041    check_eap_capa(dev[0], "MSCHAPV2")
3042    bssid = apdev[0]['bssid']
3043    params = hs20_ap_params()
3044    params['hessid'] = bssid
3045    params['disable_dgaf'] = '1'
3046    hapd = hostapd.add_ap(apdev[0], params)
3047
3048    wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
3049    wpas.interface_add("wlan5")
3050    addr = wpas.p2p_interface_addr()
3051    wpas.request("SET mac_addr 1")
3052    wpas.request("SET preassoc_mac_addr 1")
3053    wpas.request("SET rand_addr_lifetime 60")
3054    wpas.hs20_enable()
3055    wpas.flush_scan_cache()
3056    id = wpas.add_cred_values({'realm': "example.com",
3057                               'username': "hs20-test",
3058                               'password': "password",
3059                               'ca_cert': "auth_serv/ca.pem",
3060                               'domain': "example.com",
3061                               'update_identifier': "1234"})
3062    interworking_select(wpas, bssid, "home", freq="2412")
3063    interworking_connect(wpas, bssid, "TTLS")
3064    addr1 = wpas.get_driver_status_field("addr")
3065    if addr == addr1:
3066        raise Exception("Did not use random MAC address")
3067
3068    sta = hapd.get_sta(addr)
3069    if sta['addr'] != "FAIL":
3070        raise Exception("Unexpected STA association with permanent address")
3071    sta = hapd.get_sta(addr1)
3072    if sta['addr'] != addr1:
3073        raise Exception("STA association with random address not found")
3074
3075def test_ap_hs20_multi_network_and_cred_removal(dev, apdev):
3076    """Multiple networks and cred removal"""
3077    check_eap_capa(dev[0], "MSCHAPV2")
3078    bssid = apdev[0]['bssid']
3079    params = hs20_ap_params()
3080    params['nai_realm'] = ["0,example.com,25[3:26]"]
3081    hapd = hostapd.add_ap(apdev[0], params)
3082
3083    dev[0].add_network()
3084    dev[0].hs20_enable()
3085    id = dev[0].add_cred_values({'realm': "example.com",
3086                                 'username': "user",
3087                                 'password': "password"})
3088    interworking_select(dev[0], bssid, freq="2412")
3089    interworking_connect(dev[0], bssid, "PEAP")
3090    dev[0].add_network()
3091
3092    dev[0].request("DISCONNECT")
3093    dev[0].wait_disconnected(timeout=10)
3094
3095    hapd.disable()
3096    hapd.set("ssid", "another ssid")
3097    hapd.enable()
3098
3099    interworking_select(dev[0], bssid, freq="2412")
3100    interworking_connect(dev[0], bssid, "PEAP")
3101    dev[0].add_network()
3102    if len(dev[0].list_networks()) != 5:
3103        raise Exception("Unexpected number of networks prior to remove_cred")
3104
3105    dev[0].dump_monitor()
3106    dev[0].remove_cred(id)
3107    if len(dev[0].list_networks()) != 3:
3108        raise Exception("Unexpected number of networks after to remove_cred")
3109    dev[0].wait_disconnected(timeout=10)
3110
3111def test_ap_hs20_interworking_add_network(dev, apdev):
3112    """Hotspot 2.0 connection using INTERWORKING_ADD_NETWORK"""
3113    check_eap_capa(dev[0], "MSCHAPV2")
3114    bssid = apdev[0]['bssid']
3115    params = hs20_ap_params()
3116    params['nai_realm'] = ["0,example.com,21[3:26][6:7][99:99]"]
3117    hostapd.add_ap(apdev[0], params)
3118
3119    dev[0].hs20_enable()
3120    dev[0].add_cred_values(default_cred(user="user"))
3121    interworking_select(dev[0], bssid, freq=2412)
3122    id = dev[0].interworking_add_network(bssid)
3123    dev[0].select_network(id, freq=2412)
3124    dev[0].wait_connected()
3125
3126def _test_ap_hs20_proxyarp(dev, apdev):
3127    bssid = apdev[0]['bssid']
3128    params = hs20_ap_params()
3129    params['hessid'] = bssid
3130    params['disable_dgaf'] = '0'
3131    params['proxy_arp'] = '1'
3132    hapd = hostapd.add_ap(apdev[0], params, no_enable=True)
3133    if "OK" in hapd.request("ENABLE"):
3134        raise Exception("Incomplete hostapd configuration was accepted")
3135    hapd.set("ap_isolate", "1")
3136    if "OK" in hapd.request("ENABLE"):
3137        raise Exception("Incomplete hostapd configuration was accepted")
3138    hapd.set('bridge', 'ap-br0')
3139    hapd.dump_monitor()
3140    try:
3141        hapd.enable()
3142    except:
3143        # For now, do not report failures due to missing kernel support
3144        raise HwsimSkip("Could not start hostapd - assume proxyarp not supported in kernel version")
3145    ev = hapd.wait_event(["AP-ENABLED", "AP-DISABLED"], timeout=10)
3146    if ev is None:
3147        raise Exception("AP startup timed out")
3148    if "AP-ENABLED" not in ev:
3149        raise Exception("AP startup failed")
3150
3151    dev[0].hs20_enable()
3152    subprocess.call(['brctl', 'setfd', 'ap-br0', '0'])
3153    subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'up'])
3154
3155    id = dev[0].add_cred_values({'realm': "example.com",
3156                                 'username': "hs20-test",
3157                                 'password': "password",
3158                                 'ca_cert': "auth_serv/ca.pem",
3159                                 'domain': "example.com",
3160                                 'update_identifier': "1234"})
3161    interworking_select(dev[0], bssid, "home", freq="2412")
3162    interworking_connect(dev[0], bssid, "TTLS")
3163
3164    dev[1].connect("test-hs20", key_mgmt="WPA-EAP", eap="TTLS",
3165                   identity="hs20-test", password="password",
3166                   ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
3167                   scan_freq="2412")
3168    time.sleep(0.1)
3169
3170    addr0 = dev[0].p2p_interface_addr()
3171    addr1 = dev[1].p2p_interface_addr()
3172
3173    src_ll_opt0 = b"\x01\x01" + binascii.unhexlify(addr0.replace(':', ''))
3174    src_ll_opt1 = b"\x01\x01" + binascii.unhexlify(addr1.replace(':', ''))
3175
3176    pkt = build_ns(src_ll=addr0, ip_src="aaaa:bbbb:cccc::2",
3177                   ip_dst="ff02::1:ff00:2", target="aaaa:bbbb:cccc::2",
3178                   opt=src_ll_opt0)
3179    if "OK" not in dev[0].request("DATA_TEST_FRAME " + binascii.hexlify(pkt).decode()):
3180        raise Exception("DATA_TEST_FRAME failed")
3181
3182    pkt = build_ns(src_ll=addr1, ip_src="aaaa:bbbb:dddd::2",
3183                   ip_dst="ff02::1:ff00:2", target="aaaa:bbbb:dddd::2",
3184                   opt=src_ll_opt1)
3185    if "OK" not in dev[1].request("DATA_TEST_FRAME " + binascii.hexlify(pkt).decode()):
3186        raise Exception("DATA_TEST_FRAME failed")
3187
3188    pkt = build_ns(src_ll=addr1, ip_src="aaaa:bbbb:eeee::2",
3189                   ip_dst="ff02::1:ff00:2", target="aaaa:bbbb:eeee::2",
3190                   opt=src_ll_opt1)
3191    if "OK" not in dev[1].request("DATA_TEST_FRAME " + binascii.hexlify(pkt).decode()):
3192        raise Exception("DATA_TEST_FRAME failed")
3193
3194    # Wait for frames to be processed
3195    time.sleep(0.1)
3196
3197    matches = get_permanent_neighbors("ap-br0")
3198    logger.info("After connect: " + str(matches))
3199    if len(matches) != 3:
3200        raise Exception("Unexpected number of neighbor entries after connect")
3201    if 'aaaa:bbbb:cccc::2 dev ap-br0 lladdr 02:00:00:00:00:00 PERMANENT' not in matches:
3202        raise Exception("dev0 addr missing")
3203    if 'aaaa:bbbb:dddd::2 dev ap-br0 lladdr 02:00:00:00:01:00 PERMANENT' not in matches:
3204        raise Exception("dev1 addr(1) missing")
3205    if 'aaaa:bbbb:eeee::2 dev ap-br0 lladdr 02:00:00:00:01:00 PERMANENT' not in matches:
3206        raise Exception("dev1 addr(2) missing")
3207    dev[0].request("DISCONNECT")
3208    dev[1].request("DISCONNECT")
3209    time.sleep(0.5)
3210    matches = get_permanent_neighbors("ap-br0")
3211    logger.info("After disconnect: " + str(matches))
3212    if len(matches) > 0:
3213        raise Exception("Unexpected neighbor entries after disconnect")
3214
3215def test_ap_hs20_hidden_ssid_in_scan_res(dev, apdev):
3216    """Hotspot 2.0 connection with hidden SSId in scan results"""
3217    check_eap_capa(dev[0], "MSCHAPV2")
3218    bssid = apdev[0]['bssid']
3219
3220    hapd = hostapd.add_ap(apdev[0], {"ssid": 'secret',
3221                                     "ignore_broadcast_ssid": "1"})
3222    dev[0].scan_for_bss(bssid, freq=2412)
3223    hapd.disable()
3224    hapd_global = hostapd.HostapdGlobal(apdev[0])
3225    hapd_global.flush()
3226    hapd_global.remove(apdev[0]['ifname'])
3227
3228    params = hs20_ap_params()
3229    params['hessid'] = bssid
3230    hapd = hostapd.add_ap(apdev[0], params)
3231
3232    dev[0].hs20_enable()
3233    id = dev[0].add_cred_values({'realm': "example.com",
3234                                 'username': "hs20-test",
3235                                 'password': "password",
3236                                 'ca_cert': "auth_serv/ca.pem",
3237                                 'domain': "example.com"})
3238    interworking_select(dev[0], bssid, "home", freq="2412")
3239    interworking_connect(dev[0], bssid, "TTLS")
3240
3241    # clear BSS table to avoid issues in following test cases
3242    dev[0].request("DISCONNECT")
3243    dev[0].wait_disconnected()
3244    hapd.disable()
3245    dev[0].flush_scan_cache()
3246    dev[0].flush_scan_cache()
3247
3248def test_ap_hs20_proxyarp(dev, apdev):
3249    """Hotspot 2.0 and ProxyARP"""
3250    check_eap_capa(dev[0], "MSCHAPV2")
3251    try:
3252        _test_ap_hs20_proxyarp(dev, apdev)
3253    finally:
3254        subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'down'],
3255                        stderr=open('/dev/null', 'w'))
3256        subprocess.call(['brctl', 'delbr', 'ap-br0'],
3257                        stderr=open('/dev/null', 'w'))
3258
3259def _test_ap_hs20_proxyarp_dgaf(dev, apdev, disabled):
3260    bssid = apdev[0]['bssid']
3261    params = hs20_ap_params()
3262    params['hessid'] = bssid
3263    params['disable_dgaf'] = '1' if disabled else '0'
3264    params['proxy_arp'] = '1'
3265    params['na_mcast_to_ucast'] = '1'
3266    params['ap_isolate'] = '1'
3267    params['bridge'] = 'ap-br0'
3268    hapd = hostapd.add_ap(apdev[0], params, no_enable=True)
3269    try:
3270        hapd.enable()
3271    except:
3272        # For now, do not report failures due to missing kernel support
3273        raise HwsimSkip("Could not start hostapd - assume proxyarp not supported in kernel version")
3274    ev = hapd.wait_event(["AP-ENABLED"], timeout=10)
3275    if ev is None:
3276        raise Exception("AP startup timed out")
3277
3278    dev[0].hs20_enable()
3279    subprocess.call(['brctl', 'setfd', 'ap-br0', '0'])
3280    subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'up'])
3281
3282    id = dev[0].add_cred_values({'realm': "example.com",
3283                                 'username': "hs20-test",
3284                                 'password': "password",
3285                                 'ca_cert': "auth_serv/ca.pem",
3286                                 'domain': "example.com",
3287                                 'update_identifier': "1234"})
3288    interworking_select(dev[0], bssid, "home", freq="2412")
3289    interworking_connect(dev[0], bssid, "TTLS")
3290
3291    dev[1].connect("test-hs20", key_mgmt="WPA-EAP", eap="TTLS",
3292                   identity="hs20-test", password="password",
3293                   ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
3294                   scan_freq="2412")
3295    time.sleep(0.1)
3296
3297    addr0 = dev[0].p2p_interface_addr()
3298
3299    src_ll_opt0 = b"\x01\x01" + binascii.unhexlify(addr0.replace(':', ''))
3300
3301    pkt = build_ns(src_ll=addr0, ip_src="aaaa:bbbb:cccc::2",
3302                   ip_dst="ff02::1:ff00:2", target="aaaa:bbbb:cccc::2",
3303                   opt=src_ll_opt0)
3304    if "OK" not in dev[0].request("DATA_TEST_FRAME " + binascii.hexlify(pkt).decode()):
3305        raise Exception("DATA_TEST_FRAME failed")
3306
3307    pkt = build_ra(src_ll=apdev[0]['bssid'], ip_src="aaaa:bbbb:cccc::33",
3308                   ip_dst="ff01::1")
3309    if "OK" not in hapd.request("DATA_TEST_FRAME ifname=ap-br0 " + binascii.hexlify(pkt).decode()):
3310        raise Exception("DATA_TEST_FRAME failed")
3311
3312    pkt = build_na(src_ll=apdev[0]['bssid'], ip_src="aaaa:bbbb:cccc::44",
3313                   ip_dst="ff01::1", target="aaaa:bbbb:cccc::55")
3314    if "OK" not in hapd.request("DATA_TEST_FRAME ifname=ap-br0 " + binascii.hexlify(pkt).decode()):
3315        raise Exception("DATA_TEST_FRAME failed")
3316
3317    pkt = build_dhcp_ack(dst_ll="ff:ff:ff:ff:ff:ff", src_ll=bssid,
3318                         ip_src="192.168.1.1", ip_dst="255.255.255.255",
3319                         yiaddr="192.168.1.123", chaddr=addr0)
3320    if "OK" not in hapd.request("DATA_TEST_FRAME ifname=ap-br0 " + binascii.hexlify(pkt).decode()):
3321        raise Exception("DATA_TEST_FRAME failed")
3322    # another copy for additional code coverage
3323    pkt = build_dhcp_ack(dst_ll=addr0, src_ll=bssid,
3324                         ip_src="192.168.1.1", ip_dst="255.255.255.255",
3325                         yiaddr="192.168.1.123", chaddr=addr0)
3326    if "OK" not in hapd.request("DATA_TEST_FRAME ifname=ap-br0 " + binascii.hexlify(pkt).decode()):
3327        raise Exception("DATA_TEST_FRAME failed")
3328
3329    # Wait for frames to be processed
3330    time.sleep(0.1)
3331
3332    matches = get_permanent_neighbors("ap-br0")
3333    logger.info("After connect: " + str(matches))
3334    if len(matches) != 2:
3335        raise Exception("Unexpected number of neighbor entries after connect")
3336    if 'aaaa:bbbb:cccc::2 dev ap-br0 lladdr 02:00:00:00:00:00 PERMANENT' not in matches:
3337        raise Exception("dev0 addr missing")
3338    if '192.168.1.123 dev ap-br0 lladdr 02:00:00:00:00:00 PERMANENT' not in matches:
3339        raise Exception("dev0 IPv4 addr missing")
3340    dev[0].request("DISCONNECT")
3341    dev[1].request("DISCONNECT")
3342    time.sleep(0.5)
3343    matches = get_permanent_neighbors("ap-br0")
3344    logger.info("After disconnect: " + str(matches))
3345    if len(matches) > 0:
3346        raise Exception("Unexpected neighbor entries after disconnect")
3347
3348def test_ap_hs20_proxyarp_disable_dgaf(dev, apdev):
3349    """Hotspot 2.0 and ProxyARP with DGAF disabled"""
3350    check_eap_capa(dev[0], "MSCHAPV2")
3351    try:
3352        _test_ap_hs20_proxyarp_dgaf(dev, apdev, True)
3353    finally:
3354        subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'down'],
3355                        stderr=open('/dev/null', 'w'))
3356        subprocess.call(['brctl', 'delbr', 'ap-br0'],
3357                        stderr=open('/dev/null', 'w'))
3358
3359def test_ap_hs20_proxyarp_enable_dgaf(dev, apdev):
3360    """Hotspot 2.0 and ProxyARP with DGAF enabled"""
3361    check_eap_capa(dev[0], "MSCHAPV2")
3362    try:
3363        _test_ap_hs20_proxyarp_dgaf(dev, apdev, False)
3364    finally:
3365        subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'down'],
3366                        stderr=open('/dev/null', 'w'))
3367        subprocess.call(['brctl', 'delbr', 'ap-br0'],
3368                        stderr=open('/dev/null', 'w'))
3369
3370def ip_checksum(buf):
3371    sum = 0
3372    if len(buf) & 0x01:
3373        buf += b'\x00'
3374    for i in range(0, len(buf), 2):
3375        val, = struct.unpack('H', buf[i:i+2])
3376        sum += val
3377    while (sum >> 16):
3378        sum = (sum & 0xffff) + (sum >> 16)
3379    return struct.pack('H', ~sum & 0xffff)
3380
3381def ipv6_solicited_node_mcaddr(target):
3382    prefix = socket.inet_pton(socket.AF_INET6, "ff02::1:ff00:0")
3383    mask = socket.inet_pton(socket.AF_INET6, "::ff:ffff")
3384    _target = socket.inet_pton(socket.AF_INET6, target)
3385    p = struct.unpack('4I', prefix)
3386    m = struct.unpack('4I', mask)
3387    t = struct.unpack('4I', _target)
3388    res = (p[0] | (t[0] & m[0]),
3389           p[1] | (t[1] & m[1]),
3390           p[2] | (t[2] & m[2]),
3391           p[3] | (t[3] & m[3]))
3392    return socket.inet_ntop(socket.AF_INET6, struct.pack('4I', *res))
3393
3394def build_icmpv6(ipv6_addrs, type, code, payload):
3395    start = struct.pack("BB", type, code)
3396    end = payload
3397    icmp = start + b'\x00\x00' + end
3398    pseudo = ipv6_addrs + struct.pack(">LBBBB", len(icmp), 0, 0, 0, 58)
3399    csum = ip_checksum(pseudo + icmp)
3400    return start + csum + end
3401
3402def build_ra(src_ll, ip_src, ip_dst, cur_hop_limit=0, router_lifetime=0,
3403             reachable_time=0, retrans_timer=0, opt=None):
3404    link_mc = binascii.unhexlify("3333ff000002")
3405    _src_ll = binascii.unhexlify(src_ll.replace(':', ''))
3406    proto = b'\x86\xdd'
3407    ehdr = link_mc + _src_ll + proto
3408    _ip_src = socket.inet_pton(socket.AF_INET6, ip_src)
3409    _ip_dst = socket.inet_pton(socket.AF_INET6, ip_dst)
3410
3411    adv = struct.pack('>BBHLL', cur_hop_limit, 0, router_lifetime,
3412                      reachable_time, retrans_timer)
3413    if opt:
3414        payload = adv + opt
3415    else:
3416        payload = adv
3417    icmp = build_icmpv6(_ip_src + _ip_dst, 134, 0, payload)
3418
3419    ipv6 = struct.pack('>BBBBHBB', 0x60, 0, 0, 0, len(icmp), 58, 255)
3420    ipv6 += _ip_src + _ip_dst
3421
3422    return ehdr + ipv6 + icmp
3423
3424def build_ns(src_ll, ip_src, ip_dst, target, opt=None):
3425    link_mc = binascii.unhexlify("3333ff000002")
3426    _src_ll = binascii.unhexlify(src_ll.replace(':', ''))
3427    proto = b'\x86\xdd'
3428    ehdr = link_mc + _src_ll + proto
3429    _ip_src = socket.inet_pton(socket.AF_INET6, ip_src)
3430    if ip_dst is None:
3431        ip_dst = ipv6_solicited_node_mcaddr(target)
3432    _ip_dst = socket.inet_pton(socket.AF_INET6, ip_dst)
3433
3434    reserved = b'\x00\x00\x00\x00'
3435    _target = socket.inet_pton(socket.AF_INET6, target)
3436    if opt:
3437        payload = reserved + _target + opt
3438    else:
3439        payload = reserved + _target
3440    icmp = build_icmpv6(_ip_src + _ip_dst, 135, 0, payload)
3441
3442    ipv6 = struct.pack('>BBBBHBB', 0x60, 0, 0, 0, len(icmp), 58, 255)
3443    ipv6 += _ip_src + _ip_dst
3444
3445    return ehdr + ipv6 + icmp
3446
3447def send_ns(dev, src_ll=None, target=None, ip_src=None, ip_dst=None, opt=None,
3448            hapd_bssid=None):
3449    if hapd_bssid:
3450        if src_ll is None:
3451            src_ll = hapd_bssid
3452        cmd = "DATA_TEST_FRAME ifname=ap-br0 "
3453    else:
3454        if src_ll is None:
3455            src_ll = dev.p2p_interface_addr()
3456        cmd = "DATA_TEST_FRAME "
3457
3458    if opt is None:
3459        opt = b"\x01\x01" + binascii.unhexlify(src_ll.replace(':', ''))
3460
3461    pkt = build_ns(src_ll=src_ll, ip_src=ip_src, ip_dst=ip_dst, target=target,
3462                   opt=opt)
3463    if "OK" not in dev.request(cmd + binascii.hexlify(pkt).decode()):
3464        raise Exception("DATA_TEST_FRAME failed")
3465
3466def build_na(src_ll, ip_src, ip_dst, target, opt=None, flags=0):
3467    link_mc = binascii.unhexlify("3333ff000002")
3468    _src_ll = binascii.unhexlify(src_ll.replace(':', ''))
3469    proto = b'\x86\xdd'
3470    ehdr = link_mc + _src_ll + proto
3471    _ip_src = socket.inet_pton(socket.AF_INET6, ip_src)
3472    _ip_dst = socket.inet_pton(socket.AF_INET6, ip_dst)
3473
3474    _target = socket.inet_pton(socket.AF_INET6, target)
3475    if opt:
3476        payload = struct.pack('>Bxxx', flags) + _target + opt
3477    else:
3478        payload = struct.pack('>Bxxx', flags) + _target
3479    icmp = build_icmpv6(_ip_src + _ip_dst, 136, 0, payload)
3480
3481    ipv6 = struct.pack('>BBBBHBB', 0x60, 0, 0, 0, len(icmp), 58, 255)
3482    ipv6 += _ip_src + _ip_dst
3483
3484    return ehdr + ipv6 + icmp
3485
3486def send_na(dev, src_ll=None, target=None, ip_src=None, ip_dst=None, opt=None,
3487            hapd_bssid=None):
3488    if hapd_bssid:
3489        if src_ll is None:
3490            src_ll = hapd_bssid
3491        cmd = "DATA_TEST_FRAME ifname=ap-br0 "
3492    else:
3493        if src_ll is None:
3494            src_ll = dev.p2p_interface_addr()
3495        cmd = "DATA_TEST_FRAME "
3496
3497    pkt = build_na(src_ll=src_ll, ip_src=ip_src, ip_dst=ip_dst, target=target,
3498                   opt=opt)
3499    if "OK" not in dev.request(cmd + binascii.hexlify(pkt).decode()):
3500        raise Exception("DATA_TEST_FRAME failed")
3501
3502def build_dhcp_ack(dst_ll, src_ll, ip_src, ip_dst, yiaddr, chaddr,
3503                   subnet_mask="255.255.255.0", truncated_opt=False,
3504                   wrong_magic=False, force_tot_len=None, no_dhcp=False,
3505                   udp_checksum=True):
3506    _dst_ll = binascii.unhexlify(dst_ll.replace(':', ''))
3507    _src_ll = binascii.unhexlify(src_ll.replace(':', ''))
3508    proto = b'\x08\x00'
3509    ehdr = _dst_ll + _src_ll + proto
3510    _ip_src = socket.inet_pton(socket.AF_INET, ip_src)
3511    _ip_dst = socket.inet_pton(socket.AF_INET, ip_dst)
3512    _subnet_mask = socket.inet_pton(socket.AF_INET, subnet_mask)
3513
3514    _ciaddr = b'\x00\x00\x00\x00'
3515    _yiaddr = socket.inet_pton(socket.AF_INET, yiaddr)
3516    _siaddr = b'\x00\x00\x00\x00'
3517    _giaddr = b'\x00\x00\x00\x00'
3518    _chaddr = binascii.unhexlify(chaddr.replace(':', '') + "00000000000000000000")
3519    payload = struct.pack('>BBBBL3BB', 2, 1, 6, 0, 12345, 0, 0, 0, 0)
3520    payload += _ciaddr + _yiaddr + _siaddr + _giaddr + _chaddr + 192*b'\x00'
3521    # magic
3522    if wrong_magic:
3523        payload += b'\x63\x82\x53\x00'
3524    else:
3525        payload += b'\x63\x82\x53\x63'
3526    if truncated_opt:
3527        payload += b'\x22\xff\x00'
3528    # Option: DHCP Message Type = ACK
3529    payload += b'\x35\x01\x05'
3530    # Pad Option
3531    payload += b'\x00'
3532    # Option: Subnet Mask
3533    payload += b'\x01\x04' + _subnet_mask
3534    # Option: Time Offset
3535    payload += struct.pack('>BBL', 2, 4, 0)
3536    # End Option
3537    payload += b'\xff'
3538    # Pad Option
3539    payload += b'\x00\x00\x00\x00'
3540
3541    if no_dhcp:
3542        payload = struct.pack('>BBBBL3BB', 2, 1, 6, 0, 12345, 0, 0, 0, 0)
3543        payload += _ciaddr + _yiaddr + _siaddr + _giaddr + _chaddr + 192*b'\x00'
3544
3545    if udp_checksum:
3546        pseudohdr = _ip_src + _ip_dst + struct.pack('>BBH', 0, 17,
3547                                                    8 + len(payload))
3548        udphdr = struct.pack('>HHHH', 67, 68, 8 + len(payload), 0)
3549        checksum, = struct.unpack('>H', ip_checksum(pseudohdr + udphdr + payload))
3550    else:
3551        checksum = 0
3552    udp = struct.pack('>HHHH', 67, 68, 8 + len(payload), checksum) + payload
3553
3554    if force_tot_len:
3555        tot_len = force_tot_len
3556    else:
3557        tot_len = 20 + len(udp)
3558    start = struct.pack('>BBHHBBBB', 0x45, 0, tot_len, 0, 0, 0, 128, 17)
3559    ipv4 = start + b'\x00\x00' + _ip_src + _ip_dst
3560    csum = ip_checksum(ipv4)
3561    ipv4 = start + csum + _ip_src + _ip_dst
3562
3563    return ehdr + ipv4 + udp
3564
3565def build_arp(dst_ll, src_ll, opcode, sender_mac, sender_ip,
3566              target_mac, target_ip):
3567    _dst_ll = binascii.unhexlify(dst_ll.replace(':', ''))
3568    _src_ll = binascii.unhexlify(src_ll.replace(':', ''))
3569    proto = b'\x08\x06'
3570    ehdr = _dst_ll + _src_ll + proto
3571
3572    _sender_mac = binascii.unhexlify(sender_mac.replace(':', ''))
3573    _sender_ip = socket.inet_pton(socket.AF_INET, sender_ip)
3574    _target_mac = binascii.unhexlify(target_mac.replace(':', ''))
3575    _target_ip = socket.inet_pton(socket.AF_INET, target_ip)
3576
3577    arp = struct.pack('>HHBBH', 1, 0x0800, 6, 4, opcode)
3578    arp += _sender_mac + _sender_ip
3579    arp += _target_mac + _target_ip
3580
3581    return ehdr + arp
3582
3583def send_arp(dev, dst_ll="ff:ff:ff:ff:ff:ff", src_ll=None, opcode=1,
3584             sender_mac=None, sender_ip="0.0.0.0",
3585             target_mac="00:00:00:00:00:00", target_ip="0.0.0.0",
3586             hapd_bssid=None):
3587    if hapd_bssid:
3588        if src_ll is None:
3589            src_ll = hapd_bssid
3590        if sender_mac is None:
3591            sender_mac = hapd_bssid
3592        cmd = "DATA_TEST_FRAME ifname=ap-br0 "
3593    else:
3594        if src_ll is None:
3595            src_ll = dev.p2p_interface_addr()
3596        if sender_mac is None:
3597            sender_mac = dev.p2p_interface_addr()
3598        cmd = "DATA_TEST_FRAME "
3599
3600    pkt = build_arp(dst_ll=dst_ll, src_ll=src_ll, opcode=opcode,
3601                    sender_mac=sender_mac, sender_ip=sender_ip,
3602                    target_mac=target_mac, target_ip=target_ip)
3603    if "OK" not in dev.request(cmd + binascii.hexlify(pkt).decode()):
3604        raise Exception("DATA_TEST_FRAME failed")
3605
3606def get_permanent_neighbors(ifname):
3607    cmd = subprocess.Popen(['ip', 'nei'], stdout=subprocess.PIPE)
3608    out, err = cmd.communicate()
3609    res = out.decode()
3610    return [line.strip() for line in res.splitlines() if "PERMANENT" in line and ifname in line]
3611
3612def get_bridge_macs(ifname):
3613    cmd = subprocess.Popen(['brctl', 'showmacs', ifname],
3614                           stdout=subprocess.PIPE)
3615    out, err = cmd.communicate()
3616    return out.decode()
3617
3618def tshark_get_arp(cap, filter):
3619    res = run_tshark(cap, filter,
3620                     ["eth.dst", "eth.src",
3621                      "arp.src.hw_mac", "arp.src.proto_ipv4",
3622                      "arp.dst.hw_mac", "arp.dst.proto_ipv4"],
3623                     wait=False)
3624    frames = []
3625    for l in res.splitlines():
3626        frames.append(l.split('\t'))
3627    return frames
3628
3629def tshark_get_ns(cap):
3630    res = run_tshark(cap, "icmpv6.type == 135",
3631                     ["eth.dst", "eth.src",
3632                      "ipv6.src", "ipv6.dst",
3633                      "icmpv6.nd.ns.target_address",
3634                      "icmpv6.opt.linkaddr"],
3635                     wait=False)
3636    frames = []
3637    for l in res.splitlines():
3638        frames.append(l.split('\t'))
3639    return frames
3640
3641def tshark_get_na(cap):
3642    res = run_tshark(cap, "icmpv6.type == 136",
3643                     ["eth.dst", "eth.src",
3644                      "ipv6.src", "ipv6.dst",
3645                      "icmpv6.nd.na.target_address",
3646                      "icmpv6.opt.linkaddr"],
3647                     wait=False)
3648    frames = []
3649    for l in res.splitlines():
3650        frames.append(l.split('\t'))
3651    return frames
3652
3653def _test_proxyarp_open(dev, apdev, params, ebtables=False):
3654    cap_br = params['prefix'] + ".ap-br0.pcap"
3655    cap_dev0 = params['prefix'] + ".%s.pcap" % dev[0].ifname
3656    cap_dev1 = params['prefix'] + ".%s.pcap" % dev[1].ifname
3657    cap_dev2 = params['prefix'] + ".%s.pcap" % dev[2].ifname
3658
3659    bssid = apdev[0]['bssid']
3660    params = {'ssid': 'open'}
3661    params['proxy_arp'] = '1'
3662    hapd = hostapd.add_ap(apdev[0], params, no_enable=True)
3663    hapd.set("ap_isolate", "1")
3664    hapd.set('bridge', 'ap-br0')
3665    hapd.dump_monitor()
3666    try:
3667        hapd.enable()
3668    except:
3669        # For now, do not report failures due to missing kernel support
3670        raise HwsimSkip("Could not start hostapd - assume proxyarp not supported in kernel version")
3671    ev = hapd.wait_event(["AP-ENABLED", "AP-DISABLED"], timeout=10)
3672    if ev is None:
3673        raise Exception("AP startup timed out")
3674    if "AP-ENABLED" not in ev:
3675        raise Exception("AP startup failed")
3676
3677    params2 = {'ssid': 'another'}
3678    hapd2 = hostapd.add_ap(apdev[1], params2, no_enable=True)
3679    hapd2.set('bridge', 'ap-br0')
3680    hapd2.enable()
3681
3682    subprocess.call(['brctl', 'setfd', 'ap-br0', '0'])
3683    subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'up'])
3684
3685    if ebtables:
3686        for chain in ['FORWARD', 'OUTPUT']:
3687            try:
3688                err = subprocess.call(['ebtables', '-A', chain, '-p', 'ARP',
3689                                       '-d', 'Broadcast',
3690                                       '-o', apdev[0]['ifname'],
3691                                       '-j', 'DROP'])
3692                if err != 0:
3693                    raise
3694            except:
3695                raise HwsimSkip("No ebtables available")
3696
3697    time.sleep(0.5)
3698    cmd = {}
3699    cmd[0] = WlantestCapture('ap-br0', cap_br)
3700    cmd[1] = WlantestCapture(dev[0].ifname, cap_dev0)
3701    cmd[2] = WlantestCapture(dev[1].ifname, cap_dev1)
3702    cmd[3] = WlantestCapture(dev[2].ifname, cap_dev2)
3703
3704    dev[0].connect("open", key_mgmt="NONE", scan_freq="2412")
3705    dev[1].connect("open", key_mgmt="NONE", scan_freq="2412")
3706    dev[2].connect("another", key_mgmt="NONE", scan_freq="2412")
3707    time.sleep(1.1)
3708
3709    brcmd = subprocess.Popen(['brctl', 'show'], stdout=subprocess.PIPE)
3710    out, err = brcmd.communicate()
3711    logger.info("Bridge setup: " + out.decode())
3712
3713    brcmd = subprocess.Popen(['brctl', 'showstp', 'ap-br0'],
3714                             stdout=subprocess.PIPE)
3715    out, err = brcmd.communicate()
3716    logger.info("Bridge showstp: " + out.decode())
3717
3718    addr0 = dev[0].p2p_interface_addr()
3719    addr1 = dev[1].p2p_interface_addr()
3720    addr2 = dev[2].p2p_interface_addr()
3721
3722    pkt = build_dhcp_ack(dst_ll="ff:ff:ff:ff:ff:ff", src_ll=bssid,
3723                         ip_src="192.168.1.1", ip_dst="255.255.255.255",
3724                         yiaddr="192.168.1.124", chaddr=addr0)
3725    if "OK" not in hapd.request("DATA_TEST_FRAME ifname=ap-br0 " + binascii.hexlify(pkt).decode()):
3726        raise Exception("DATA_TEST_FRAME failed")
3727    # Change address and verify unicast
3728    pkt = build_dhcp_ack(dst_ll=addr0, src_ll=bssid,
3729                         ip_src="192.168.1.1", ip_dst="255.255.255.255",
3730                         yiaddr="192.168.1.123", chaddr=addr0,
3731                         udp_checksum=False)
3732    if "OK" not in hapd.request("DATA_TEST_FRAME ifname=ap-br0 " + binascii.hexlify(pkt).decode()):
3733        raise Exception("DATA_TEST_FRAME failed")
3734
3735    # Not-associated client MAC address
3736    pkt = build_dhcp_ack(dst_ll="ff:ff:ff:ff:ff:ff", src_ll=bssid,
3737                         ip_src="192.168.1.1", ip_dst="255.255.255.255",
3738                         yiaddr="192.168.1.125", chaddr="22:33:44:55:66:77")
3739    if "OK" not in hapd.request("DATA_TEST_FRAME ifname=ap-br0 " + binascii.hexlify(pkt).decode()):
3740        raise Exception("DATA_TEST_FRAME failed")
3741
3742    # No IP address
3743    pkt = build_dhcp_ack(dst_ll=addr1, src_ll=bssid,
3744                         ip_src="192.168.1.1", ip_dst="255.255.255.255",
3745                         yiaddr="0.0.0.0", chaddr=addr1)
3746    if "OK" not in hapd.request("DATA_TEST_FRAME ifname=ap-br0 " + binascii.hexlify(pkt).decode()):
3747        raise Exception("DATA_TEST_FRAME failed")
3748
3749    # Zero subnet mask
3750    pkt = build_dhcp_ack(dst_ll=addr1, src_ll=bssid,
3751                         ip_src="192.168.1.1", ip_dst="255.255.255.255",
3752                         yiaddr="192.168.1.126", chaddr=addr1,
3753                         subnet_mask="0.0.0.0")
3754    if "OK" not in hapd.request("DATA_TEST_FRAME ifname=ap-br0 " + binascii.hexlify(pkt).decode()):
3755        raise Exception("DATA_TEST_FRAME failed")
3756
3757    # Truncated option
3758    pkt = build_dhcp_ack(dst_ll=addr1, src_ll=bssid,
3759                         ip_src="192.168.1.1", ip_dst="255.255.255.255",
3760                         yiaddr="192.168.1.127", chaddr=addr1,
3761                         truncated_opt=True)
3762    if "OK" not in hapd.request("DATA_TEST_FRAME ifname=ap-br0 " + binascii.hexlify(pkt).decode()):
3763        raise Exception("DATA_TEST_FRAME failed")
3764
3765    # Wrong magic
3766    pkt = build_dhcp_ack(dst_ll=addr1, src_ll=bssid,
3767                         ip_src="192.168.1.1", ip_dst="255.255.255.255",
3768                         yiaddr="192.168.1.128", chaddr=addr1,
3769                         wrong_magic=True)
3770    if "OK" not in hapd.request("DATA_TEST_FRAME ifname=ap-br0 " + binascii.hexlify(pkt).decode()):
3771        raise Exception("DATA_TEST_FRAME failed")
3772
3773    # Wrong IPv4 total length
3774    pkt = build_dhcp_ack(dst_ll=addr1, src_ll=bssid,
3775                         ip_src="192.168.1.1", ip_dst="255.255.255.255",
3776                         yiaddr="192.168.1.129", chaddr=addr1,
3777                         force_tot_len=1000)
3778    if "OK" not in hapd.request("DATA_TEST_FRAME ifname=ap-br0 " + binascii.hexlify(pkt).decode()):
3779        raise Exception("DATA_TEST_FRAME failed")
3780
3781    # BOOTP
3782    pkt = build_dhcp_ack(dst_ll=addr1, src_ll=bssid,
3783                         ip_src="192.168.1.1", ip_dst="255.255.255.255",
3784                         yiaddr="192.168.1.129", chaddr=addr1,
3785                         no_dhcp=True)
3786    if "OK" not in hapd.request("DATA_TEST_FRAME ifname=ap-br0 " + binascii.hexlify(pkt).decode()):
3787        raise Exception("DATA_TEST_FRAME failed")
3788
3789    # Wait for frames to be processed
3790    time.sleep(0.1)
3791
3792    macs = get_bridge_macs("ap-br0")
3793    logger.info("After connect (showmacs): " + str(macs))
3794
3795    matches = get_permanent_neighbors("ap-br0")
3796    logger.info("After connect: " + str(matches))
3797    if len(matches) != 1:
3798        raise Exception("Unexpected number of neighbor entries after connect")
3799    if '192.168.1.123 dev ap-br0 lladdr 02:00:00:00:00:00 PERMANENT' not in matches:
3800        raise Exception("dev0 IPv4 addr missing")
3801
3802    targets = ["192.168.1.123", "192.168.1.124", "192.168.1.125",
3803               "192.168.1.126"]
3804    for target in targets:
3805        send_arp(dev[1], sender_ip="192.168.1.100", target_ip=target)
3806
3807    for target in targets:
3808        send_arp(hapd, hapd_bssid=bssid, sender_ip="192.168.1.101",
3809                 target_ip=target)
3810
3811    for target in targets:
3812        send_arp(dev[2], sender_ip="192.168.1.103", target_ip=target)
3813
3814    # ARP Probe from wireless STA
3815    send_arp(dev[1], target_ip="192.168.1.127")
3816    # ARP Announcement from wireless STA
3817    send_arp(dev[1], sender_ip="192.168.1.127", target_ip="192.168.1.127")
3818    send_arp(dev[1], sender_ip="192.168.1.127", target_ip="192.168.1.127",
3819             opcode=2)
3820
3821    macs = get_bridge_macs("ap-br0")
3822    logger.info("After ARP Probe + Announcement (showmacs): " + str(macs))
3823
3824    matches = get_permanent_neighbors("ap-br0")
3825    logger.info("After ARP Probe + Announcement: " + str(matches))
3826
3827    # ARP Request for the newly introduced IP address from wireless STA
3828    send_arp(dev[0], sender_ip="192.168.1.123", target_ip="192.168.1.127")
3829
3830    # ARP Request for the newly introduced IP address from bridge
3831    send_arp(hapd, hapd_bssid=bssid, sender_ip="192.168.1.102",
3832             target_ip="192.168.1.127")
3833    send_arp(dev[2], sender_ip="192.168.1.103", target_ip="192.168.1.127")
3834
3835    # ARP Probe from bridge
3836    send_arp(hapd, hapd_bssid=bssid, target_ip="192.168.1.130")
3837    send_arp(dev[2], target_ip="192.168.1.131")
3838    # ARP Announcement from bridge (not to be learned by AP for proxyarp)
3839    send_arp(hapd, hapd_bssid=bssid, sender_ip="192.168.1.130",
3840             target_ip="192.168.1.130")
3841    send_arp(hapd, hapd_bssid=bssid, sender_ip="192.168.1.130",
3842             target_ip="192.168.1.130", opcode=2)
3843    send_arp(dev[2], sender_ip="192.168.1.131", target_ip="192.168.1.131")
3844    send_arp(dev[2], sender_ip="192.168.1.131", target_ip="192.168.1.131",
3845             opcode=2)
3846
3847    macs = get_bridge_macs("ap-br0")
3848    logger.info("After ARP Probe + Announcement (showmacs): " + str(macs))
3849
3850    matches = get_permanent_neighbors("ap-br0")
3851    logger.info("After ARP Probe + Announcement: " + str(matches))
3852
3853    # ARP Request for the newly introduced IP address from wireless STA
3854    send_arp(dev[0], sender_ip="192.168.1.123", target_ip="192.168.1.130")
3855    # ARP Response from bridge (AP does not proxy for non-wireless devices)
3856    send_arp(hapd, hapd_bssid=bssid, dst_ll=addr0, sender_ip="192.168.1.130",
3857             target_ip="192.168.1.123", opcode=2)
3858
3859    # ARP Request for the newly introduced IP address from wireless STA
3860    send_arp(dev[0], sender_ip="192.168.1.123", target_ip="192.168.1.131")
3861    # ARP Response from bridge (AP does not proxy for non-wireless devices)
3862    send_arp(dev[2], dst_ll=addr0, sender_ip="192.168.1.131",
3863             target_ip="192.168.1.123", opcode=2)
3864
3865    # ARP Request for the newly introduced IP address from bridge
3866    send_arp(hapd, hapd_bssid=bssid, sender_ip="192.168.1.102",
3867             target_ip="192.168.1.130")
3868    send_arp(dev[2], sender_ip="192.168.1.104", target_ip="192.168.1.131")
3869
3870    # ARP Probe from wireless STA (duplicate address; learned through DHCP)
3871    send_arp(dev[1], target_ip="192.168.1.123")
3872    # ARP Probe from wireless STA (duplicate address; learned through ARP)
3873    send_arp(dev[0], target_ip="192.168.1.127")
3874
3875    # Gratuitous ARP Reply for another STA's IP address
3876    send_arp(dev[0], opcode=2, sender_mac=addr0, sender_ip="192.168.1.127",
3877             target_mac=addr1, target_ip="192.168.1.127")
3878    send_arp(dev[1], opcode=2, sender_mac=addr1, sender_ip="192.168.1.123",
3879             target_mac=addr0, target_ip="192.168.1.123")
3880    # ARP Request to verify previous mapping
3881    send_arp(dev[1], sender_ip="192.168.1.127", target_ip="192.168.1.123")
3882    send_arp(dev[0], sender_ip="192.168.1.123", target_ip="192.168.1.127")
3883
3884    try:
3885        hwsim_utils.test_connectivity_iface(dev[0], hapd, "ap-br0")
3886    except Exception as e:
3887        logger.info("test_connectibity_iface failed: " + str(e))
3888        raise HwsimSkip("Assume kernel did not have the required patches for proxyarp")
3889    hwsim_utils.test_connectivity_iface(dev[1], hapd, "ap-br0")
3890    hwsim_utils.test_connectivity(dev[0], dev[1])
3891
3892    dev[0].request("DISCONNECT")
3893    dev[1].request("DISCONNECT")
3894    time.sleep(1.5)
3895    for i in range(len(cmd)):
3896        cmd[i].close()
3897    time.sleep(0.1)
3898    macs = get_bridge_macs("ap-br0")
3899    logger.info("After disconnect (showmacs): " + str(macs))
3900    matches = get_permanent_neighbors("ap-br0")
3901    logger.info("After disconnect: " + str(matches))
3902    if len(matches) > 0:
3903        raise Exception("Unexpected neighbor entries after disconnect")
3904    if ebtables:
3905        cmd = subprocess.Popen(['ebtables', '-L', '--Lc'],
3906                               stdout=subprocess.PIPE)
3907        out, err = cmd.communicate()
3908        logger.info("ebtables results:\n" + out.decode())
3909
3910    # Verify that expected ARP messages were seen and no unexpected
3911    # ARP messages were seen.
3912
3913    arp_req = tshark_get_arp(cap_dev0, "arp.opcode == 1")
3914    arp_reply = tshark_get_arp(cap_dev0, "arp.opcode == 2")
3915    logger.info("dev0 seen ARP requests:\n" + str(arp_req))
3916    logger.info("dev0 seen ARP replies:\n" + str(arp_reply))
3917
3918    if ['ff:ff:ff:ff:ff:ff', addr1,
3919        addr1, '192.168.1.100',
3920        '00:00:00:00:00:00', '192.168.1.123'] in arp_req:
3921        raise Exception("dev0 saw ARP request from dev1")
3922    if ['ff:ff:ff:ff:ff:ff', addr2,
3923        addr2, '192.168.1.103',
3924        '00:00:00:00:00:00', '192.168.1.123'] in arp_req:
3925        raise Exception("dev0 saw ARP request from dev2")
3926    # TODO: Uncomment once fixed in kernel
3927    #if ['ff:ff:ff:ff:ff:ff', bssid,
3928    #    bssid, '192.168.1.101',
3929    #    '00:00:00:00:00:00', '192.168.1.123'] in arp_req:
3930    #    raise Exception("dev0 saw ARP request from br")
3931
3932    if ebtables:
3933        for req in arp_req:
3934            if req[1] != addr0:
3935                raise Exception("Unexpected foreign ARP request on dev0")
3936
3937    arp_req = tshark_get_arp(cap_dev1, "arp.opcode == 1")
3938    arp_reply = tshark_get_arp(cap_dev1, "arp.opcode == 2")
3939    logger.info("dev1 seen ARP requests:\n" + str(arp_req))
3940    logger.info("dev1 seen ARP replies:\n" + str(arp_reply))
3941
3942    if ['ff:ff:ff:ff:ff:ff', addr2,
3943        addr2, '192.168.1.103',
3944        '00:00:00:00:00:00', '192.168.1.123'] in arp_req:
3945        raise Exception("dev1 saw ARP request from dev2")
3946    if [addr1, addr0, addr0, '192.168.1.123', addr1, '192.168.1.100'] not in arp_reply:
3947        raise Exception("dev1 did not get ARP response for 192.168.1.123")
3948
3949    if ebtables:
3950        for req in arp_req:
3951            if req[1] != addr1:
3952                raise Exception("Unexpected foreign ARP request on dev1")
3953
3954    arp_req = tshark_get_arp(cap_dev2, "arp.opcode == 1")
3955    arp_reply = tshark_get_arp(cap_dev2, "arp.opcode == 2")
3956    logger.info("dev2 seen ARP requests:\n" + str(arp_req))
3957    logger.info("dev2 seen ARP replies:\n" + str(arp_reply))
3958
3959    if [addr2, addr0,
3960        addr0, '192.168.1.123',
3961        addr2, '192.168.1.103'] not in arp_reply:
3962        raise Exception("dev2 did not get ARP response for 192.168.1.123")
3963
3964    arp_req = tshark_get_arp(cap_br, "arp.opcode == 1")
3965    arp_reply = tshark_get_arp(cap_br, "arp.opcode == 2")
3966    logger.info("br seen ARP requests:\n" + str(arp_req))
3967    logger.info("br seen ARP replies:\n" + str(arp_reply))
3968
3969    # TODO: Uncomment once fixed in kernel
3970    #if [bssid, addr0,
3971    #    addr0, '192.168.1.123',
3972    #    bssid, '192.168.1.101'] not in arp_reply:
3973    #    raise Exception("br did not get ARP response for 192.168.1.123")
3974
3975def _test_proxyarp_open_ipv6(dev, apdev, params, ebtables=False):
3976    cap_br = params['prefix'] + ".ap-br0.pcap"
3977    cap_dev0 = params['prefix'] + ".%s.pcap" % dev[0].ifname
3978    cap_dev1 = params['prefix'] + ".%s.pcap" % dev[1].ifname
3979    cap_dev2 = params['prefix'] + ".%s.pcap" % dev[2].ifname
3980
3981    bssid = apdev[0]['bssid']
3982    params = {'ssid': 'open'}
3983    params['proxy_arp'] = '1'
3984    hapd = hostapd.add_ap(apdev[0], params, no_enable=True)
3985    hapd.set("ap_isolate", "1")
3986    hapd.set('bridge', 'ap-br0')
3987    hapd.dump_monitor()
3988    try:
3989        hapd.enable()
3990    except:
3991        # For now, do not report failures due to missing kernel support
3992        raise HwsimSkip("Could not start hostapd - assume proxyarp not supported in kernel version")
3993    ev = hapd.wait_event(["AP-ENABLED", "AP-DISABLED"], timeout=10)
3994    if ev is None:
3995        raise Exception("AP startup timed out")
3996    if "AP-ENABLED" not in ev:
3997        raise Exception("AP startup failed")
3998
3999    params2 = {'ssid': 'another'}
4000    hapd2 = hostapd.add_ap(apdev[1], params2, no_enable=True)
4001    hapd2.set('bridge', 'ap-br0')
4002    hapd2.enable()
4003
4004    subprocess.call(['brctl', 'setfd', 'ap-br0', '0'])
4005    subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'up'])
4006
4007    if ebtables:
4008        for chain in ['FORWARD', 'OUTPUT']:
4009            try:
4010                err = subprocess.call(['ebtables', '-A', chain,
4011                                       '-d', 'Multicast',
4012                                       '-p', 'IPv6',
4013                                       '--ip6-protocol', 'ipv6-icmp',
4014                                       '--ip6-icmp-type',
4015                                       'neighbor-solicitation',
4016                                       '-o', apdev[0]['ifname'], '-j', 'DROP'])
4017                if err != 0:
4018                    raise
4019                subprocess.call(['ebtables', '-A', chain, '-d', 'Multicast',
4020                                 '-p', 'IPv6', '--ip6-protocol', 'ipv6-icmp',
4021                                 '--ip6-icmp-type', 'neighbor-advertisement',
4022                                 '-o', apdev[0]['ifname'], '-j', 'DROP'])
4023                subprocess.call(['ebtables', '-A', chain,
4024                                 '-p', 'IPv6', '--ip6-protocol', 'ipv6-icmp',
4025                                 '--ip6-icmp-type', 'router-solicitation',
4026                                 '-o', apdev[0]['ifname'], '-j', 'DROP'])
4027                # Multicast Listener Report Message
4028                subprocess.call(['ebtables', '-A', chain, '-d', 'Multicast',
4029                                 '-p', 'IPv6', '--ip6-protocol', 'ipv6-icmp',
4030                                 '--ip6-icmp-type', '143',
4031                                 '-o', apdev[0]['ifname'], '-j', 'DROP'])
4032            except:
4033                raise HwsimSkip("No ebtables available")
4034
4035    time.sleep(0.5)
4036    cmd = {}
4037    cmd[0] = WlantestCapture('ap-br0', cap_br)
4038    cmd[1] = WlantestCapture(dev[0].ifname, cap_dev0)
4039    cmd[2] = WlantestCapture(dev[1].ifname, cap_dev1)
4040    cmd[3] = WlantestCapture(dev[2].ifname, cap_dev2)
4041
4042    dev[0].connect("open", key_mgmt="NONE", scan_freq="2412")
4043    dev[1].connect("open", key_mgmt="NONE", scan_freq="2412")
4044    dev[2].connect("another", key_mgmt="NONE", scan_freq="2412")
4045    time.sleep(0.1)
4046
4047    brcmd = subprocess.Popen(['brctl', 'show'], stdout=subprocess.PIPE)
4048    out, err = brcmd.communicate()
4049    logger.info("Bridge setup: " + out.decode())
4050
4051    brcmd = subprocess.Popen(['brctl', 'showstp', 'ap-br0'],
4052                             stdout=subprocess.PIPE)
4053    out, err = brcmd.communicate()
4054    logger.info("Bridge showstp: " + out.decode())
4055
4056    addr0 = dev[0].p2p_interface_addr()
4057    addr1 = dev[1].p2p_interface_addr()
4058    addr2 = dev[2].p2p_interface_addr()
4059
4060    src_ll_opt0 = b"\x01\x01" + binascii.unhexlify(addr0.replace(':', ''))
4061    src_ll_opt1 = b"\x01\x01" + binascii.unhexlify(addr1.replace(':', ''))
4062
4063    # DAD NS
4064    send_ns(dev[0], ip_src="::", target="aaaa:bbbb:cccc::2")
4065
4066    send_ns(dev[0], ip_src="aaaa:bbbb:cccc::2", target="aaaa:bbbb:cccc::2")
4067    # test frame without source link-layer address option
4068    send_ns(dev[0], ip_src="aaaa:bbbb:cccc::2", target="aaaa:bbbb:cccc::2",
4069            opt='')
4070    # test frame with bogus option
4071    send_ns(dev[0], ip_src="aaaa:bbbb:cccc::2", target="aaaa:bbbb:cccc::2",
4072            opt=b"\x70\x01\x01\x02\x03\x04\x05\x05")
4073    # test frame with truncated source link-layer address option
4074    send_ns(dev[0], ip_src="aaaa:bbbb:cccc::2", target="aaaa:bbbb:cccc::2",
4075            opt=b"\x01\x01\x01\x02\x03\x04")
4076    # test frame with foreign source link-layer address option
4077    send_ns(dev[0], ip_src="aaaa:bbbb:cccc::2", target="aaaa:bbbb:cccc::2",
4078            opt=b"\x01\x01\x01\x02\x03\x04\x05\x06")
4079
4080    send_ns(dev[1], ip_src="aaaa:bbbb:dddd::2", target="aaaa:bbbb:dddd::2")
4081
4082    send_ns(dev[1], ip_src="aaaa:bbbb:eeee::2", target="aaaa:bbbb:eeee::2")
4083    # another copy for additional code coverage
4084    send_ns(dev[1], ip_src="aaaa:bbbb:eeee::2", target="aaaa:bbbb:eeee::2")
4085
4086    macs = get_bridge_macs("ap-br0")
4087    logger.info("After connect (showmacs): " + str(macs))
4088
4089    matches = get_permanent_neighbors("ap-br0")
4090    logger.info("After connect: " + str(matches))
4091    if len(matches) != 3:
4092        raise Exception("Unexpected number of neighbor entries after connect")
4093    if 'aaaa:bbbb:cccc::2 dev ap-br0 lladdr 02:00:00:00:00:00 PERMANENT' not in matches:
4094        raise Exception("dev0 addr missing")
4095    if 'aaaa:bbbb:dddd::2 dev ap-br0 lladdr 02:00:00:00:01:00 PERMANENT' not in matches:
4096        raise Exception("dev1 addr(1) missing")
4097    if 'aaaa:bbbb:eeee::2 dev ap-br0 lladdr 02:00:00:00:01:00 PERMANENT' not in matches:
4098        raise Exception("dev1 addr(2) missing")
4099
4100    send_ns(dev[0], target="aaaa:bbbb:dddd::2", ip_src="aaaa:bbbb:cccc::2")
4101    time.sleep(0.1)
4102    send_ns(dev[1], target="aaaa:bbbb:cccc::2", ip_src="aaaa:bbbb:dddd::2")
4103    time.sleep(0.1)
4104    send_ns(hapd, hapd_bssid=bssid, target="aaaa:bbbb:dddd::2",
4105            ip_src="aaaa:bbbb:ffff::2")
4106    time.sleep(0.1)
4107    send_ns(dev[2], target="aaaa:bbbb:cccc::2", ip_src="aaaa:bbbb:ff00::2")
4108    time.sleep(0.1)
4109    send_ns(dev[2], target="aaaa:bbbb:dddd::2", ip_src="aaaa:bbbb:ff00::2")
4110    time.sleep(0.1)
4111    send_ns(dev[2], target="aaaa:bbbb:eeee::2", ip_src="aaaa:bbbb:ff00::2")
4112    time.sleep(0.1)
4113
4114    # Try to probe for an already assigned address
4115    send_ns(dev[1], target="aaaa:bbbb:cccc::2", ip_src="::")
4116    time.sleep(0.1)
4117    send_ns(hapd, hapd_bssid=bssid, target="aaaa:bbbb:cccc::2", ip_src="::")
4118    time.sleep(0.1)
4119    send_ns(dev[2], target="aaaa:bbbb:cccc::2", ip_src="::")
4120    time.sleep(0.1)
4121
4122    # Unsolicited NA
4123    send_na(dev[1], target="aaaa:bbbb:cccc:aeae::3",
4124            ip_src="aaaa:bbbb:cccc:aeae::3", ip_dst="ff02::1")
4125    send_na(hapd, hapd_bssid=bssid, target="aaaa:bbbb:cccc:aeae::4",
4126            ip_src="aaaa:bbbb:cccc:aeae::4", ip_dst="ff02::1")
4127    send_na(dev[2], target="aaaa:bbbb:cccc:aeae::5",
4128            ip_src="aaaa:bbbb:cccc:aeae::5", ip_dst="ff02::1")
4129
4130    try:
4131        hwsim_utils.test_connectivity_iface(dev[0], hapd, "ap-br0")
4132    except Exception as e:
4133        logger.info("test_connectibity_iface failed: " + str(e))
4134        raise HwsimSkip("Assume kernel did not have the required patches for proxyarp")
4135    hwsim_utils.test_connectivity_iface(dev[1], hapd, "ap-br0")
4136    hwsim_utils.test_connectivity(dev[0], dev[1])
4137
4138    dev[0].request("DISCONNECT")
4139    dev[1].request("DISCONNECT")
4140    time.sleep(0.5)
4141    for i in range(len(cmd)):
4142        cmd[i].close()
4143    macs = get_bridge_macs("ap-br0")
4144    logger.info("After disconnect (showmacs): " + str(macs))
4145    matches = get_permanent_neighbors("ap-br0")
4146    logger.info("After disconnect: " + str(matches))
4147    if len(matches) > 0:
4148        raise Exception("Unexpected neighbor entries after disconnect")
4149    if ebtables:
4150        cmd = subprocess.Popen(['ebtables', '-L', '--Lc'],
4151                               stdout=subprocess.PIPE)
4152        out, err = cmd.communicate()
4153        logger.info("ebtables results:\n" + out.decode())
4154
4155    ns = tshark_get_ns(cap_dev0)
4156    logger.info("dev0 seen NS: " + str(ns))
4157    na = tshark_get_na(cap_dev0)
4158    logger.info("dev0 seen NA: " + str(na))
4159
4160    if [addr0, addr1, 'aaaa:bbbb:dddd::2', 'aaaa:bbbb:cccc::2',
4161        'aaaa:bbbb:dddd::2', addr1] not in na:
4162        # For now, skip the test instead of reporting the error since the IPv6
4163        # proxyarp support is not yet in the upstream kernel tree.
4164        #raise Exception("dev0 did not get NA for aaaa:bbbb:dddd::2")
4165        raise HwsimSkip("Assume kernel did not have the required patches for proxyarp (IPv6)")
4166
4167    if ebtables:
4168        for req in ns:
4169            if req[1] == bssid and req[0] == "33:33:ff:" + bssid[9:] and \
4170               req[3] == 'ff02::1:ff00:300' and req[4] == 'fe80::ff:fe00:300':
4171                # At least for now, ignore this special case until the kernel
4172                # can be prevented from sending it out.
4173                logger.info("dev0: Ignore NS from AP to own local addr: " + str(req))
4174            elif req[1] != addr0:
4175                raise Exception("Unexpected foreign NS on dev0: " + str(req))
4176
4177    ns = tshark_get_ns(cap_dev1)
4178    logger.info("dev1 seen NS: " + str(ns))
4179    na = tshark_get_na(cap_dev1)
4180    logger.info("dev1 seen NA: " + str(na))
4181
4182    if [addr1, addr0, 'aaaa:bbbb:cccc::2', 'aaaa:bbbb:dddd::2',
4183        'aaaa:bbbb:cccc::2', addr0] not in na:
4184        raise Exception("dev1 did not get NA for aaaa:bbbb:cccc::2")
4185
4186    if ebtables:
4187        for req in ns:
4188            if req[1] == bssid and req[0] == "33:33:ff:" + bssid[9:] and \
4189               req[3] == 'ff02::1:ff00:300' and req[4] == 'fe80::ff:fe00:300':
4190                # At least for now, ignore this special case until the kernel
4191                # can be prevented from sending it out.
4192                logger.info("dev1: Ignore NS from AP to own local addr: " + str(req))
4193            elif req[1] != addr1:
4194                raise Exception("Unexpected foreign NS on dev1: " + str(req))
4195
4196    ns = tshark_get_ns(cap_dev2)
4197    logger.info("dev2 seen NS: " + str(ns))
4198    na = tshark_get_na(cap_dev2)
4199    logger.info("dev2 seen NA: " + str(na))
4200
4201    # FIX: enable once kernel implementation for proxyarp IPv6 is fixed
4202    #if [addr2, addr0, 'aaaa:bbbb:cccc::2', 'aaaa:bbbb:ff00::2',
4203    #    'aaaa:bbbb:cccc::2', addr0] not in na:
4204    #    raise Exception("dev2 did not get NA for aaaa:bbbb:cccc::2")
4205    #if [addr2, addr1, 'aaaa:bbbb:dddd::2', 'aaaa:bbbb:ff00::2',
4206    #    'aaaa:bbbb:dddd::2', addr1] not in na:
4207    #    raise Exception("dev2 did not get NA for aaaa:bbbb:dddd::2")
4208    #if [addr2, addr1, 'aaaa:bbbb:eeee::2', 'aaaa:bbbb:ff00::2',
4209    #    'aaaa:bbbb:eeee::2', addr1] not in na:
4210    #    raise Exception("dev2 did not get NA for aaaa:bbbb:eeee::2")
4211
4212def test_proxyarp_open(dev, apdev, params):
4213    """ProxyARP with open network"""
4214    try:
4215        _test_proxyarp_open(dev, apdev, params)
4216    finally:
4217        subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'down'],
4218                        stderr=open('/dev/null', 'w'))
4219        subprocess.call(['brctl', 'delbr', 'ap-br0'],
4220                        stderr=open('/dev/null', 'w'))
4221
4222def test_proxyarp_open_ipv6(dev, apdev, params):
4223    """ProxyARP with open network (IPv6)"""
4224    try:
4225        _test_proxyarp_open_ipv6(dev, apdev, params)
4226    finally:
4227        subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'down'],
4228                        stderr=open('/dev/null', 'w'))
4229        subprocess.call(['brctl', 'delbr', 'ap-br0'],
4230                        stderr=open('/dev/null', 'w'))
4231
4232def test_proxyarp_open_ebtables(dev, apdev, params):
4233    """ProxyARP with open network"""
4234    try:
4235        _test_proxyarp_open(dev, apdev, params, ebtables=True)
4236    finally:
4237        try:
4238            subprocess.call(['ebtables', '-F', 'FORWARD'])
4239            subprocess.call(['ebtables', '-F', 'OUTPUT'])
4240        except:
4241            pass
4242        subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'down'],
4243                        stderr=open('/dev/null', 'w'))
4244        subprocess.call(['brctl', 'delbr', 'ap-br0'],
4245                        stderr=open('/dev/null', 'w'))
4246
4247def test_proxyarp_open_ebtables_ipv6(dev, apdev, params):
4248    """ProxyARP with open network (IPv6)"""
4249    try:
4250        _test_proxyarp_open_ipv6(dev, apdev, params, ebtables=True)
4251    finally:
4252        try:
4253            subprocess.call(['ebtables', '-F', 'FORWARD'])
4254            subprocess.call(['ebtables', '-F', 'OUTPUT'])
4255        except:
4256            pass
4257        subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'down'],
4258                        stderr=open('/dev/null', 'w'))
4259        subprocess.call(['brctl', 'delbr', 'ap-br0'],
4260                        stderr=open('/dev/null', 'w'))
4261
4262def test_proxyarp_errors(dev, apdev, params):
4263    """ProxyARP error cases"""
4264    try:
4265        run_proxyarp_errors(dev, apdev, params)
4266    finally:
4267        subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'down'],
4268                        stderr=open('/dev/null', 'w'))
4269        subprocess.call(['brctl', 'delbr', 'ap-br0'],
4270                        stderr=open('/dev/null', 'w'))
4271
4272def run_proxyarp_errors(dev, apdev, params):
4273    params = {'ssid': 'open',
4274              'proxy_arp': '1',
4275              'ap_isolate': '1',
4276              'bridge': 'ap-br0',
4277              'disable_dgaf': '1'}
4278    hapd = hostapd.add_ap(apdev[0], params, no_enable=True)
4279    try:
4280        hapd.enable()
4281    except:
4282        # For now, do not report failures due to missing kernel support
4283        raise HwsimSkip("Could not start hostapd - assume proxyarp not supported in kernel version")
4284    ev = hapd.wait_event(["AP-ENABLED", "AP-DISABLED"], timeout=10)
4285    if ev is None:
4286        raise Exception("AP startup timed out")
4287    if "AP-ENABLED" not in ev:
4288        raise Exception("AP startup failed")
4289
4290    hapd.disable()
4291    with alloc_fail(hapd, 1, "l2_packet_init;x_snoop_get_l2_packet;dhcp_snoop_init"):
4292        if "FAIL" not in hapd.request("ENABLE"):
4293            raise Exception("ENABLE accepted unexpectedly")
4294    with alloc_fail(hapd, 1, "l2_packet_init;x_snoop_get_l2_packet;ndisc_snoop_init"):
4295        if "FAIL" not in hapd.request("ENABLE"):
4296            raise Exception("ENABLE accepted unexpectedly")
4297    with fail_test(hapd, 1, "l2_packet_set_packet_filter;x_snoop_get_l2_packet;ndisc_snoop_init"):
4298        if "FAIL" not in hapd.request("ENABLE"):
4299            raise Exception("ENABLE accepted unexpectedly")
4300    with fail_test(hapd, 1, "l2_packet_set_packet_filter;x_snoop_get_l2_packet;dhcp_snoop_init"):
4301        if "FAIL" not in hapd.request("ENABLE"):
4302            raise Exception("ENABLE accepted unexpectedly")
4303    hapd.enable()
4304
4305    subprocess.call(['brctl', 'setfd', 'ap-br0', '0'])
4306    subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'up'])
4307
4308    dev[0].connect("open", key_mgmt="NONE", scan_freq="2412")
4309    addr0 = dev[0].own_addr()
4310
4311    pkt = build_ra(src_ll=apdev[0]['bssid'], ip_src="aaaa:bbbb:cccc::33",
4312                   ip_dst="ff01::1")
4313    with fail_test(hapd, 1, "x_snoop_mcast_to_ucast_convert_send"):
4314        if "OK" not in hapd.request("DATA_TEST_FRAME ifname=ap-br0 " + binascii.hexlify(pkt).decode()):
4315            raise Exception("DATA_TEST_FRAME failed")
4316        wait_fail_trigger(hapd, "GET_FAIL")
4317
4318    with alloc_fail(hapd, 1, "sta_ip6addr_add"):
4319        src_ll_opt0 = b"\x01\x01" + binascii.unhexlify(addr0.replace(':', ''))
4320        pkt = build_ns(src_ll=addr0, ip_src="aaaa:bbbb:cccc::2",
4321                       ip_dst="ff02::1:ff00:2", target="aaaa:bbbb:cccc::2",
4322                       opt=src_ll_opt0)
4323        hwsim_utils.sync_carrier(dev[0])
4324        if "OK" not in dev[0].request("DATA_TEST_FRAME " + binascii.hexlify(pkt).decode()):
4325            raise Exception("DATA_TEST_FRAME failed")
4326        wait_fail_trigger(hapd, "GET_ALLOC_FAIL")
4327
4328def test_ap_hs20_connect_deinit(dev, apdev):
4329    """Hotspot 2.0 connection interrupted with deinit"""
4330    check_eap_capa(dev[0], "MSCHAPV2")
4331    bssid = apdev[0]['bssid']
4332    params = hs20_ap_params()
4333    params['hessid'] = bssid
4334    hapd = hostapd.add_ap(apdev[0], params)
4335
4336    wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
4337    wpas.interface_add("wlan5", drv_params="")
4338    wpas.hs20_enable()
4339    wpas.flush_scan_cache()
4340    wpas.add_cred_values({'realm': "example.com",
4341                          'username': "hs20-test",
4342                          'password': "password",
4343                          'ca_cert': "auth_serv/ca.pem",
4344                          'domain': "example.com"})
4345
4346    wpas.scan_for_bss(bssid, freq=2412)
4347    hapd.disable()
4348
4349    wpas.request("INTERWORKING_SELECT freq=2412")
4350
4351    id = wpas.request("RADIO_WORK add block-work")
4352    ev = wpas.wait_event(["GAS-QUERY-START", "EXT-RADIO-WORK-START"], timeout=5)
4353    if ev is None:
4354        raise Exception("Timeout while waiting radio work to start")
4355    ev = wpas.wait_event(["GAS-QUERY-START", "EXT-RADIO-WORK-START"], timeout=5)
4356    if ev is None:
4357        raise Exception("Timeout while waiting radio work to start (2)")
4358
4359    # Remove the interface while the gas-query radio work is still pending and
4360    # GAS query has not yet been started.
4361    wpas.interface_remove("wlan5")
4362
4363def test_ap_hs20_anqp_format_errors(dev, apdev):
4364    """Interworking network selection and ANQP format errors"""
4365    bssid = apdev[0]['bssid']
4366    params = hs20_ap_params()
4367    params['hessid'] = bssid
4368    hapd = hostapd.add_ap(apdev[0], params)
4369
4370    dev[0].hs20_enable()
4371    values = {'realm': "example.com",
4372              'ca_cert': "auth_serv/ca.pem",
4373              'username': "hs20-test",
4374              'password': "password",
4375              'domain': "example.com"}
4376    id = dev[0].add_cred_values(values)
4377
4378    dev[0].scan_for_bss(bssid, freq="2412")
4379
4380    tests = ["00", "ffff", "010011223344", "020008000005112233445500",
4381             "01000400000000", "01000000000000",
4382             "01000300000200", "0100040000ff0000", "01000300000100",
4383             "01000300000001",
4384             "01000600000056112233",
4385             "01000900000002050001000111",
4386             "01000600000001000000", "01000600000001ff0000",
4387             "01000600000001020001",
4388             "010008000000010400010001", "0100080000000104000100ff",
4389             "010011000000010d00050200020100030005000600",
4390             "0000"]
4391    for t in tests:
4392        hapd.set("anqp_elem", "263:" + t)
4393        dev[0].request("INTERWORKING_SELECT freq=2412")
4394        ev = dev[0].wait_event(["INTERWORKING-NO-MATCH"], timeout=5)
4395        if ev is None:
4396            raise Exception("Network selection timed out")
4397        dev[0].dump_monitor()
4398
4399    dev[0].remove_cred(id)
4400    id = dev[0].add_cred_values({'imsi': "555444-333222111", 'eap': "AKA",
4401                                 'milenage': "5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123"})
4402
4403    tests = ["00", "0100", "0001", "00ff", "000200ff", "0003000101",
4404             "00020100"]
4405    for t in tests:
4406        hapd.set("anqp_elem", "264:" + t)
4407        dev[0].request("INTERWORKING_SELECT freq=2412")
4408        ev = dev[0].wait_event(["INTERWORKING-NO-MATCH"], timeout=5)
4409        if ev is None:
4410            raise Exception("Network selection timed out")
4411        dev[0].dump_monitor()
4412
4413def test_ap_hs20_cred_with_nai_realm(dev, apdev):
4414    """Hotspot 2.0 network selection and cred_with_nai_realm cred->realm"""
4415    bssid = apdev[0]['bssid']
4416    params = hs20_ap_params()
4417    params['hessid'] = bssid
4418    hostapd.add_ap(apdev[0], params)
4419
4420    dev[0].hs20_enable()
4421
4422    id = dev[0].add_cred_values({'realm': "example.com",
4423                                 'username': "test",
4424                                 'password': "secret",
4425                                 'domain': "example.com",
4426                                 'eap': 'TTLS'})
4427    interworking_select(dev[0], bssid, "home", freq=2412)
4428    dev[0].remove_cred(id)
4429
4430    id = dev[0].add_cred_values({'realm': "foo.com",
4431                                 'username': "test",
4432                                 'password': "secret",
4433                                 'domain': "example.com",
4434                                 'home_ois': ["112234"],
4435                                 'eap': 'TTLS'})
4436    interworking_select(dev[0], bssid, "home", freq=2412, no_match=True)
4437    dev[0].remove_cred(id)
4438
4439def test_ap_hs20_cred_and_no_roaming_consortium(dev, apdev):
4440    """Hotspot 2.0 network selection and no roaming consortium"""
4441    bssid = apdev[0]['bssid']
4442    params = hs20_ap_params()
4443    params['hessid'] = bssid
4444    del params['roaming_consortium']
4445    hostapd.add_ap(apdev[0], params)
4446
4447    dev[0].hs20_enable()
4448
4449    id = dev[0].add_cred_values({'realm': "example.com",
4450                                 'username': "test",
4451                                 'password': "secret",
4452                                 'domain': "example.com",
4453                                 'home_ois': ["112234"],
4454                                 'eap': 'TTLS'})
4455    interworking_select(dev[0], bssid, "home", freq=2412)
4456
4457def test_ap_hs20_interworking_oom(dev, apdev):
4458    """Hotspot 2.0 network selection and OOM"""
4459    bssid = apdev[0]['bssid']
4460    params = hs20_ap_params()
4461    params['hessid'] = bssid
4462    params['nai_realm'] = ["0,no.match.here;example.com;no.match.here.either,21[2:1][5:7]",
4463                           "0,example.com,13[5:6],21[2:4][5:7]",
4464                           "0,another.example.com"]
4465    hostapd.add_ap(apdev[0], params)
4466
4467    dev[0].hs20_enable()
4468
4469    id = dev[0].add_cred_values({'realm': "example.com",
4470                                 'username': "test",
4471                                 'password': "secret",
4472                                 'domain': "example.com",
4473                                 'eap': 'TTLS'})
4474
4475    dev[0].scan_for_bss(bssid, freq="2412")
4476
4477    funcs = ["wpabuf_alloc;interworking_anqp_send_req",
4478             "anqp_build_req;interworking_anqp_send_req",
4479             "gas_query_req;interworking_anqp_send_req",
4480             "dup_binstr;nai_realm_parse_realm",
4481             "=nai_realm_parse_realm",
4482             "=nai_realm_parse",
4483             "=nai_realm_match"]
4484    for func in funcs:
4485        with alloc_fail(dev[0], 1, func):
4486            dev[0].request("INTERWORKING_SELECT auto freq=2412")
4487            ev = dev[0].wait_event(["Starting ANQP"], timeout=5)
4488            if ev is None:
4489                raise Exception("ANQP did not start")
4490            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4491            dev[0].dump_monitor()
4492
4493def test_ap_hs20_no_cred_connect(dev, apdev):
4494    """Hotspot 2.0 and connect attempt without credential"""
4495    bssid = apdev[0]['bssid']
4496    params = hs20_ap_params()
4497    params['hessid'] = bssid
4498    hapd = hostapd.add_ap(apdev[0], params)
4499
4500    dev[0].hs20_enable()
4501    dev[0].scan_for_bss(bssid, freq="2412")
4502    if "FAIL" not in dev[0].request("INTERWORKING_CONNECT " + bssid):
4503        raise Exception("Unexpected INTERWORKING_CONNECT success")
4504
4505def test_ap_hs20_no_rsn_connect(dev, apdev):
4506    """Hotspot 2.0 and connect attempt without RSN"""
4507    bssid = apdev[0]['bssid']
4508    params = hostapd.wpa_params(ssid="test-hs20")
4509    params['wpa_key_mgmt'] = "WPA-EAP"
4510    params['ieee80211w'] = "1"
4511    params['ieee8021x'] = "1"
4512    params['auth_server_addr'] = "127.0.0.1"
4513    params['auth_server_port'] = "1812"
4514    params['auth_server_shared_secret'] = "radius"
4515    params['interworking'] = "1"
4516    params['roaming_consortium'] = ["112233", "1020304050", "010203040506",
4517                                    "fedcba"]
4518    params['nai_realm'] = ["0,example.com,13[5:6],21[2:4][5:7]",
4519                           "0,another.example.com"]
4520    hapd = hostapd.add_ap(apdev[0], params)
4521
4522    dev[0].hs20_enable()
4523    dev[0].scan_for_bss(bssid, freq="2412")
4524
4525    id = dev[0].add_cred_values({'realm': "example.com",
4526                                 'username': "test",
4527                                 'password': "secret",
4528                                 'domain': "example.com",
4529                                 'home_ois': ["112233"],
4530                                 'eap': 'TTLS'})
4531
4532    interworking_select(dev[0], bssid, freq=2412, no_match=True)
4533    if "FAIL" not in dev[0].request("INTERWORKING_CONNECT " + bssid):
4534        raise Exception("Unexpected INTERWORKING_CONNECT success")
4535
4536def test_ap_hs20_no_match_connect(dev, apdev):
4537    """Hotspot 2.0 and connect attempt without matching cred"""
4538    bssid = apdev[0]['bssid']
4539    params = hs20_ap_params()
4540    hapd = hostapd.add_ap(apdev[0], params)
4541
4542    dev[0].hs20_enable()
4543    dev[0].scan_for_bss(bssid, freq="2412")
4544
4545    id = dev[0].add_cred_values({'realm': "example.org",
4546                                 'username': "test",
4547                                 'password': "secret",
4548                                 'domain': "example.org",
4549                                 'home_ois': ["112234"],
4550                                 'eap': 'TTLS'})
4551
4552    interworking_select(dev[0], bssid, freq=2412, no_match=True)
4553    if "FAIL" not in dev[0].request("INTERWORKING_CONNECT " + bssid):
4554        raise Exception("Unexpected INTERWORKING_CONNECT success")
4555
4556def test_ap_hs20_multiple_home_cred(dev, apdev):
4557    """Hotspot 2.0 and select with multiple matching home credentials"""
4558    bssid = apdev[0]['bssid']
4559    params = hs20_ap_params()
4560    params['hessid'] = bssid
4561    params['nai_realm'] = ["0,example.com,13[5:6],21[2:4][5:7]"]
4562    params['domain_name'] = "example.com"
4563    hapd = hostapd.add_ap(apdev[0], params)
4564
4565    bssid2 = apdev[1]['bssid']
4566    params = hs20_ap_params(ssid="test-hs20-other")
4567    params['hessid'] = bssid2
4568    params['nai_realm'] = ["0,example.org,13[5:6],21[2:4][5:7]"]
4569    params['domain_name'] = "example.org"
4570    hapd2 = hostapd.add_ap(apdev[1], params)
4571
4572    dev[0].hs20_enable()
4573    dev[0].scan_for_bss(bssid2, freq="2412")
4574    dev[0].scan_for_bss(bssid, freq="2412")
4575    id = dev[0].add_cred_values({'realm': "example.com",
4576                                 'priority': '2',
4577                                 'username': "hs20-test",
4578                                 'password': "password",
4579                                 'domain': "example.com"})
4580    id2 = dev[0].add_cred_values({'realm': "example.org",
4581                                  'priority': '3',
4582                                  'username': "hs20-test",
4583                                  'password': "password",
4584                                  'domain': "example.org"})
4585    dev[0].request("INTERWORKING_SELECT auto freq=2412")
4586    ev = dev[0].wait_connected(timeout=15)
4587    if bssid2 not in ev:
4588        raise Exception("Connected to incorrect network")
4589
4590def test_ap_hs20_anqp_invalid_gas_response(dev, apdev):
4591    """Hotspot 2.0 network selection and invalid GAS response"""
4592    bssid = apdev[0]['bssid']
4593    params = hs20_ap_params()
4594    params['hessid'] = bssid
4595    hapd = hostapd.add_ap(apdev[0], params)
4596
4597    dev[0].flush_scan_cache()
4598    dev[0].scan_for_bss(bssid, freq="2412")
4599    hapd.set("ext_mgmt_frame_handling", "1")
4600
4601    dev[0].hs20_enable()
4602
4603    id = dev[0].add_cred_values({'realm': "example.com",
4604                                 'username': "test",
4605                                 'password': "secret",
4606                                 'domain': "example.com",
4607                                 'home_ois': ["112234"],
4608                                 'eap': 'TTLS'})
4609    dev[0].request("INTERWORKING_SELECT freq=2412")
4610
4611    query = gas_rx(hapd)
4612    gas = parse_gas(query['payload'])
4613
4614    logger.info("ANQP: Unexpected Advertisement Protocol in response")
4615    resp = action_response(query)
4616    adv_proto = struct.pack('8B', 108, 6, 127, 0xdd, 0x00, 0x11, 0x22, 0x33)
4617    data = struct.pack('<H', 0)
4618    resp['payload'] = struct.pack('<BBBHH', ACTION_CATEG_PUBLIC,
4619                                  GAS_INITIAL_RESPONSE,
4620                                  gas['dialog_token'], 0, 0) + adv_proto + data
4621    send_gas_resp(hapd, resp)
4622
4623    ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=5)
4624    if ev is None:
4625        raise Exception("No ANQP-QUERY-DONE seen")
4626    if "result=INVALID_FRAME" not in ev:
4627        raise Exception("Unexpected result: " + ev)
4628
4629    dev[0].request("INTERWORKING_SELECT freq=2412")
4630
4631    query = gas_rx(hapd)
4632    gas = parse_gas(query['payload'])
4633
4634    logger.info("ANQP: Invalid element length for Info ID 1234")
4635    resp = action_response(query)
4636    adv_proto = struct.pack('BBBB', 108, 2, 127, 0)
4637    elements = struct.pack('<HH', 1234, 1)
4638    data = struct.pack('<H', len(elements)) + elements
4639    resp['payload'] = struct.pack('<BBBHH', ACTION_CATEG_PUBLIC,
4640                                  GAS_INITIAL_RESPONSE,
4641                                  gas['dialog_token'], 0, 0) + adv_proto + data
4642    send_gas_resp(hapd, resp)
4643
4644    ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=5)
4645    if ev is None:
4646        raise Exception("No ANQP-QUERY-DONE seen")
4647    if "result=INVALID_FRAME" not in ev:
4648        raise Exception("Unexpected result: " + ev)
4649
4650    with alloc_fail(dev[0], 1, "=anqp_add_extra"):
4651        dev[0].request("INTERWORKING_SELECT freq=2412")
4652
4653        query = gas_rx(hapd)
4654        gas = parse_gas(query['payload'])
4655
4656        resp = action_response(query)
4657        elements = struct.pack('<HHHH', 1, 0, 1, 0)
4658        data = struct.pack('<H', len(elements)) + elements
4659        resp['payload'] = struct.pack('<BBBHH', ACTION_CATEG_PUBLIC,
4660                                      GAS_INITIAL_RESPONSE,
4661                                      gas['dialog_token'], 0, 0) + adv_proto + data
4662        send_gas_resp(hapd, resp)
4663
4664        ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=5)
4665        if ev is None:
4666            raise Exception("No ANQP-QUERY-DONE seen")
4667        if "result=SUCCESS" not in ev:
4668            raise Exception("Unexpected result: " + ev)
4669
4670    with alloc_fail(dev[0], 1, "wpabuf_alloc_copy;anqp_add_extra"):
4671        dev[0].request("INTERWORKING_SELECT freq=2412")
4672
4673        query = gas_rx(hapd)
4674        gas = parse_gas(query['payload'])
4675
4676        resp = action_response(query)
4677        elements = struct.pack('<HHHH', 1, 0, 1, 0)
4678        data = struct.pack('<H', len(elements)) + elements
4679        resp['payload'] = struct.pack('<BBBHH', ACTION_CATEG_PUBLIC,
4680                                      GAS_INITIAL_RESPONSE,
4681                                      gas['dialog_token'], 0, 0) + adv_proto + data
4682        send_gas_resp(hapd, resp)
4683
4684        ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=5)
4685        if ev is None:
4686            raise Exception("No ANQP-QUERY-DONE seen")
4687        if "result=SUCCESS" not in ev:
4688            raise Exception("Unexpected result: " + ev)
4689
4690    tests = [struct.pack('<HH', 0xdddd, 0),
4691             struct.pack('<HH3B', 0xdddd, 3, 0x50, 0x6f, 0x9a),
4692             struct.pack('<HH4B', 0xdddd, 4, 0x50, 0x6f, 0x9a, 0),
4693             struct.pack('<HH4B', 0xdddd, 4, 0x11, 0x22, 0x33, 0),
4694             struct.pack('<HHHH', 1, 0, 1, 0)]
4695    for elements in tests:
4696        dev[0].request("INTERWORKING_SELECT freq=2412")
4697
4698        query = gas_rx(hapd)
4699        gas = parse_gas(query['payload'])
4700
4701        resp = action_response(query)
4702        data = struct.pack('<H', len(elements)) + elements
4703        resp['payload'] = struct.pack('<BBBHH', ACTION_CATEG_PUBLIC,
4704                                      GAS_INITIAL_RESPONSE,
4705                                      gas['dialog_token'], 0, 0) + adv_proto + data
4706        send_gas_resp(hapd, resp)
4707
4708        ev = dev[0].wait_event(["ANQP-QUERY-DONE"], timeout=5)
4709        if ev is None:
4710            raise Exception("No ANQP-QUERY-DONE seen")
4711        if "result=SUCCESS" not in ev:
4712            raise Exception("Unexpected result: " + ev)
4713
4714def test_ap_hs20_set_profile_failures(dev, apdev):
4715    """Hotspot 2.0 and failures during profile configuration"""
4716    bssid = apdev[0]['bssid']
4717    params = hs20_ap_params()
4718    params['hessid'] = bssid
4719    params['anqp_3gpp_cell_net'] = "555,444"
4720    hapd = hostapd.add_ap(apdev[0], params)
4721
4722    dev[0].hs20_enable()
4723    dev[0].scan_for_bss(bssid, freq="2412")
4724
4725    id = dev[0].add_cred_values({'realm': "example.com",
4726                                 'domain': "example.com",
4727                                 'username': "test",
4728                                 'password': "secret",
4729                                 'eap': 'TTLS'})
4730    interworking_select(dev[0], bssid, "home", freq=2412)
4731    dev[0].dump_monitor()
4732    dev[0].request("NOTE ssid->eap.eap_methods = os_malloc()")
4733    with alloc_fail(dev[0], 1, "interworking_set_eap_params"):
4734        dev[0].request("INTERWORKING_CONNECT " + bssid)
4735        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4736    dev[0].remove_cred(id)
4737
4738    id = dev[0].add_cred_values({'realm': "example.com",
4739                                 'domain': "example.com",
4740                                 'username': "hs20-test-with-domain@example.com",
4741                                 'password': "password"})
4742    interworking_select(dev[0], bssid, "home", freq=2412)
4743    dev[0].dump_monitor()
4744    dev[0].request("NOTE anon = os_malloc()")
4745    with alloc_fail(dev[0], 1, "interworking_set_eap_params"):
4746        dev[0].request("INTERWORKING_CONNECT " + bssid)
4747        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4748    dev[0].request("NOTE Successful connection with cred->username including realm")
4749    dev[0].request("INTERWORKING_CONNECT " + bssid)
4750    dev[0].wait_connected()
4751    hapd.wait_sta()
4752    dev[0].remove_cred(id)
4753    dev[0].wait_disconnected()
4754    hapd.wait_sta_disconnect()
4755
4756    id = dev[0].add_cred_values({'realm': "example.com",
4757                                 'domain': "example.com",
4758                                 'username': "hs20-test",
4759                                 'password': "password"})
4760    interworking_select(dev[0], bssid, "home", freq=2412)
4761    dev[0].dump_monitor()
4762    dev[0].request("NOTE anon = os_malloc() (second)")
4763    with alloc_fail(dev[0], 1, "interworking_set_eap_params"):
4764        dev[0].request("INTERWORKING_CONNECT " + bssid)
4765        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4766    with alloc_fail(dev[0], 1, "wpa_config_add_network;interworking_connect"):
4767        dev[0].request("INTERWORKING_CONNECT " + bssid)
4768        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4769    with alloc_fail(dev[0], 1, "=interworking_connect"):
4770        dev[0].request("INTERWORKING_CONNECT " + bssid)
4771        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4772    dev[0].request("NOTE wpa_config_set(eap)")
4773    with alloc_fail(dev[0], 1, "wpa_config_parse_eap;wpa_config_set;interworking_connect"):
4774        dev[0].request("INTERWORKING_CONNECT " + bssid)
4775        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4776    dev[0].request("NOTE wpa_config_set(TTLS-NON_EAP_MSCHAPV2-phase2)")
4777    with alloc_fail(dev[0], 1, "wpa_config_parse_str;wpa_config_set;interworking_connect"):
4778        dev[0].request("INTERWORKING_CONNECT " + bssid)
4779        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4780    dev[0].remove_cred(id)
4781
4782    id = dev[0].add_cred_values({'home_ois': ["112233"],
4783                                 'domain': "example.com",
4784                                 'username': "hs20-test",
4785                                 'password': "password",
4786                                 'eap': 'TTLS',
4787                                 'phase2': "auth=MSCHAPV2"})
4788    interworking_select(dev[0], bssid, "home", freq=2412)
4789    dev[0].dump_monitor()
4790    dev[0].request("NOTE anon = os_strdup()")
4791    with alloc_fail(dev[0], 2, "interworking_set_eap_params"):
4792        dev[0].request("INTERWORKING_CONNECT " + bssid)
4793        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4794    dev[0].request("NOTE wpa_config_set_quoted(anonymous_identity)")
4795    with alloc_fail(dev[0], 1, "=wpa_config_set_quoted;interworking_set_eap_params"):
4796        dev[0].request("INTERWORKING_CONNECT " + bssid)
4797        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4798    dev[0].request("NOTE Successful connection with cred->realm not included")
4799    dev[0].request("INTERWORKING_CONNECT " + bssid)
4800    dev[0].wait_connected()
4801    hapd.wait_sta()
4802    dev[0].remove_cred(id)
4803    dev[0].wait_disconnected()
4804    hapd.wait_sta_disconnect()
4805
4806    id = dev[0].add_cred_values({'home_ois': ["112233"],
4807                                 'domain': "example.com",
4808                                 'realm': "example.com",
4809                                 'username': "user",
4810                                 'password': "password",
4811                                 'eap': 'PEAP'})
4812    interworking_select(dev[0], bssid, "home", freq=2412)
4813    dev[0].dump_monitor()
4814    dev[0].request("NOTE id = os_strdup()")
4815    with alloc_fail(dev[0], 2, "interworking_set_eap_params"):
4816        dev[0].request("INTERWORKING_CONNECT " + bssid)
4817        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4818    dev[0].request("NOTE wpa_config_set_quoted(identity)")
4819    with alloc_fail(dev[0], 1, "=wpa_config_set_quoted;interworking_set_eap_params"):
4820        dev[0].request("INTERWORKING_CONNECT " + bssid)
4821        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4822    dev[0].remove_cred(id)
4823
4824    id = dev[0].add_cred_values({'home_ois': ["112233"],
4825                                 'domain': "example.com",
4826                                 'realm': "example.com",
4827                                 'username': "user",
4828                                 'password': "password",
4829                                 'eap': "TTLS"})
4830    interworking_select(dev[0], bssid, "home", freq=2412)
4831    dev[0].dump_monitor()
4832    dev[0].request("NOTE wpa_config_set_quoted(identity) (second)")
4833    with alloc_fail(dev[0], 2, "=wpa_config_set_quoted;interworking_set_eap_params"):
4834        dev[0].request("INTERWORKING_CONNECT " + bssid)
4835        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4836    dev[0].request("NOTE wpa_config_set_quoted(password)")
4837    with alloc_fail(dev[0], 3, "=wpa_config_set_quoted;interworking_set_eap_params"):
4838        dev[0].request("INTERWORKING_CONNECT " + bssid)
4839        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4840    with alloc_fail(dev[0], 1, "wpa_config_add_network;interworking_connect_roaming_consortium"):
4841        dev[0].request("INTERWORKING_CONNECT " + bssid)
4842        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4843    with alloc_fail(dev[0], 1, "=interworking_connect_roaming_consortium"):
4844        dev[0].request("INTERWORKING_CONNECT " + bssid)
4845        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4846    dev[0].remove_cred(id)
4847
4848    id = dev[0].add_cred_values({'home_ois': ["112233"],
4849                                 'domain': "example.com",
4850                                 'realm': "example.com",
4851                                 'username': "user",
4852                                 'eap': "PEAP"})
4853    dev[0].set_cred(id, "password", "ext:password")
4854    interworking_select(dev[0], bssid, "home", freq=2412)
4855    dev[0].dump_monitor()
4856    dev[0].request("NOTE wpa_config_set(password)")
4857    with alloc_fail(dev[0], 1, "wpa_config_parse_password;interworking_set_eap_params"):
4858        dev[0].request("INTERWORKING_CONNECT " + bssid)
4859        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4860    with alloc_fail(dev[0], 1, "interworking_set_hs20_params"):
4861        dev[0].request("INTERWORKING_CONNECT " + bssid)
4862        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4863    dev[0].remove_cred(id)
4864
4865    id = dev[0].add_cred_values({'realm': "example.com",
4866                                 'domain': "example.com",
4867                                 'username': "certificate-user",
4868                                 'phase1': "include_tls_length=0",
4869                                 'domain_suffix_match': "example.com",
4870                                 'ca_cert': "auth_serv/ca.pem",
4871                                 'client_cert': "auth_serv/user.pem",
4872                                 'private_key': "auth_serv/user.key",
4873                                 'private_key_passwd': "secret"})
4874    interworking_select(dev[0], bssid, "home", freq=2412)
4875    dev[0].dump_monitor()
4876    dev[0].request("NOTE wpa_config_set_quoted(client_cert)")
4877    with alloc_fail(dev[0], 2, "=wpa_config_set_quoted;interworking_set_eap_params"):
4878        dev[0].request("INTERWORKING_CONNECT " + bssid)
4879        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4880    dev[0].request("NOTE wpa_config_set_quoted(private_key)")
4881    with alloc_fail(dev[0], 3, "=wpa_config_set_quoted;interworking_set_eap_params"):
4882        dev[0].request("INTERWORKING_CONNECT " + bssid)
4883        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4884    dev[0].request("NOTE wpa_config_set_quoted(private_key_passwd)")
4885    with alloc_fail(dev[0], 4, "=wpa_config_set_quoted;interworking_set_eap_params"):
4886        dev[0].request("INTERWORKING_CONNECT " + bssid)
4887        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4888    dev[0].request("NOTE wpa_config_set_quoted(ca_cert)")
4889    with alloc_fail(dev[0], 5, "=wpa_config_set_quoted;interworking_set_eap_params"):
4890        dev[0].request("INTERWORKING_CONNECT " + bssid)
4891        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4892    dev[0].request("NOTE wpa_config_set_quoted(domain_suffix_match)")
4893    with alloc_fail(dev[0], 6, "=wpa_config_set_quoted;interworking_set_eap_params"):
4894        dev[0].request("INTERWORKING_CONNECT " + bssid)
4895        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4896    with alloc_fail(dev[0], 1, "interworking_set_hs20_params"):
4897        dev[0].request("INTERWORKING_CONNECT " + bssid)
4898        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4899    dev[0].remove_cred(id)
4900
4901    id = dev[0].add_cred_values({'imsi': "555444-333222111", 'eap': "SIM",
4902                                 'milenage': "5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123"})
4903    interworking_select(dev[0], bssid, freq=2412)
4904    dev[0].dump_monitor()
4905    with alloc_fail(dev[0], 1, "interworking_set_hs20_params"):
4906        dev[0].request("INTERWORKING_CONNECT " + bssid)
4907        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4908    dev[0].request("NOTE wpa_config_set_quoted(password;milenage)")
4909    with alloc_fail(dev[0], 2, "=wpa_config_set_quoted;interworking_connect_3gpp"):
4910        dev[0].request("INTERWORKING_CONNECT " + bssid)
4911        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4912    dev[0].request("NOTE wpa_config_set(eap)")
4913    with alloc_fail(dev[0], 1, "wpa_config_parse_eap;wpa_config_set;interworking_connect_3gpp"):
4914        dev[0].request("INTERWORKING_CONNECT " + bssid)
4915        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4916    dev[0].request("NOTE set_root_nai:wpa_config_set(identity)")
4917    with alloc_fail(dev[0], 1, "wpa_config_parse_str;interworking_connect_3gpp"):
4918            dev[0].request("INTERWORKING_CONNECT " + bssid)
4919            wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4920    dev[0].remove_cred(id)
4921
4922    id = dev[0].add_cred_values({'home_ois': ["112233"],
4923                                 'eap': 'TTLS',
4924                                 'username': "user@example.com",
4925                                 'password': "password"})
4926    interworking_select(dev[0], bssid, freq=2412)
4927    dev[0].dump_monitor()
4928    dev[0].request("NOTE Interworking: No EAP method set for credential using roaming consortium")
4929    dev[0].request("INTERWORKING_CONNECT " + bssid)
4930    dev[0].remove_cred(id)
4931
4932    hapd.disable()
4933    params = hs20_ap_params()
4934    params['nai_realm'] = "0,example.com,25[3:26]"
4935    hapd = hostapd.add_ap(apdev[0], params)
4936    id = dev[0].add_cred_values({'realm': "example.com",
4937                                 'domain': "example.com",
4938                                 'username': "hs20-test",
4939                                 'password': "password"})
4940    interworking_select(dev[0], bssid, freq=2412)
4941    dev[0].dump_monitor()
4942    dev[0].request("NOTE wpa_config_set(PEAP/FAST-phase1)")
4943    with alloc_fail(dev[0], 1, "wpa_config_parse_str;wpa_config_set;interworking_connect"):
4944        dev[0].request("INTERWORKING_CONNECT " + bssid)
4945        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4946    dev[0].request("NOTE wpa_config_set(PEAP/FAST-pac_interworking)")
4947    with alloc_fail(dev[0], 2, "wpa_config_parse_str;wpa_config_set;interworking_connect"):
4948        dev[0].request("INTERWORKING_CONNECT " + bssid)
4949        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4950    dev[0].request("NOTE wpa_config_set(PEAP/FAST-phase2)")
4951    with alloc_fail(dev[0], 3, "wpa_config_parse_str;wpa_config_set;interworking_connect"):
4952        dev[0].request("INTERWORKING_CONNECT " + bssid)
4953        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4954
4955    hapd.disable()
4956    params = hs20_ap_params()
4957    params['nai_realm'] = "0,example.com,21"
4958    hapd = hostapd.add_ap(apdev[0], params)
4959    interworking_select(dev[0], bssid, freq=2412)
4960    dev[0].request("NOTE wpa_config_set(TTLS-defaults-phase2)")
4961    with alloc_fail(dev[0], 1, "wpa_config_parse_str;wpa_config_set;interworking_connect"):
4962        dev[0].request("INTERWORKING_CONNECT " + bssid)
4963        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4964
4965    hapd.disable()
4966    params = hs20_ap_params()
4967    params['nai_realm'] = "0,example.com,21[2:3]"
4968    hapd = hostapd.add_ap(apdev[0], params)
4969    interworking_select(dev[0], bssid, freq=2412)
4970    dev[0].request("NOTE wpa_config_set(TTLS-NON_EAP_MSCHAP-phase2)")
4971    with alloc_fail(dev[0], 1, "wpa_config_parse_str;wpa_config_set;interworking_connect"):
4972        dev[0].request("INTERWORKING_CONNECT " + bssid)
4973        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4974
4975    hapd.disable()
4976    params = hs20_ap_params()
4977    params['nai_realm'] = "0,example.com,21[2:2]"
4978    hapd = hostapd.add_ap(apdev[0], params)
4979    interworking_select(dev[0], bssid, freq=2412)
4980    dev[0].request("NOTE wpa_config_set(TTLS-NON_EAP_CHAP-phase2)")
4981    with alloc_fail(dev[0], 1, "wpa_config_parse_str;wpa_config_set;interworking_connect"):
4982        dev[0].request("INTERWORKING_CONNECT " + bssid)
4983        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4984
4985    hapd.disable()
4986    params = hs20_ap_params()
4987    params['nai_realm'] = "0,example.com,21[2:1]"
4988    hapd = hostapd.add_ap(apdev[0], params)
4989    interworking_select(dev[0], bssid, freq=2412)
4990    dev[0].request("NOTE wpa_config_set(TTLS-NON_EAP_PAP-phase2)")
4991    with alloc_fail(dev[0], 1, "wpa_config_parse_str;wpa_config_set;interworking_connect"):
4992        dev[0].request("INTERWORKING_CONNECT " + bssid)
4993        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
4994
4995    hapd.disable()
4996    params = hs20_ap_params()
4997    params['nai_realm'] = "0,example.com,21[3:26]"
4998    hapd = hostapd.add_ap(apdev[0], params)
4999    interworking_select(dev[0], bssid, freq=2412)
5000    dev[0].request("NOTE wpa_config_set(TTLS-EAP-MSCHAPV2-phase2)")
5001    with alloc_fail(dev[0], 1, "wpa_config_parse_str;wpa_config_set;interworking_connect"):
5002        dev[0].request("INTERWORKING_CONNECT " + bssid)
5003        wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
5004
5005    dev[0].remove_cred(id)
5006
5007def test_ap_hs20_unexpected(dev, apdev):
5008    """Unexpected Hotspot 2.0 AP configuration"""
5009    skip_without_tkip(dev[0])
5010    skip_without_tkip(dev[1])
5011    skip_without_tkip(dev[2])
5012    check_eap_capa(dev[0], "MSCHAPV2")
5013    bssid = apdev[0]['bssid']
5014    params = hostapd.wpa_eap_params(ssid="test-hs20-fake")
5015    params['wpa'] = "3"
5016    params['wpa_pairwise'] = "TKIP CCMP"
5017    params['rsn_pairwise'] = "CCMP"
5018    params['ieee80211w'] = "1"
5019    #params['vendor_elements'] = 'dd07506f9a10140000'
5020    params['vendor_elements'] = 'dd04506f9a10'
5021    hostapd.add_ap(apdev[0], params)
5022
5023    dev[0].hs20_enable()
5024    dev[0].scan_for_bss(bssid, freq="2412")
5025    dev[0].connect("test-hs20-fake", key_mgmt="WPA-EAP", eap="TTLS",
5026                   pairwise="TKIP",
5027                   identity="hs20-test", password="password",
5028                   ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
5029                   scan_freq="2412")
5030
5031    dev[1].hs20_enable()
5032    dev[1].scan_for_bss(bssid, freq="2412")
5033    dev[1].connect("test-hs20-fake", key_mgmt="WPA-EAP", eap="TTLS",
5034                   proto="WPA",
5035                   identity="hs20-test", password="password",
5036                   ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
5037                   scan_freq="2412")
5038
5039    dev[2].hs20_enable()
5040    dev[2].scan_for_bss(bssid, freq="2412")
5041    dev[2].connect("test-hs20-fake", key_mgmt="WPA-EAP", eap="TTLS",
5042                   ieee80211w="1",
5043                   proto="RSN", pairwise="CCMP",
5044                   identity="hs20-test", password="password",
5045                   ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
5046                   scan_freq="2412")
5047
5048def test_ap_interworking_element_update(dev, apdev):
5049    """Dynamic Interworking element update"""
5050    bssid = apdev[0]['bssid']
5051    params = hs20_ap_params()
5052    params['hessid'] = bssid
5053    hapd = hostapd.add_ap(apdev[0], params)
5054
5055    dev[0].hs20_enable()
5056    dev[0].scan_for_bss(bssid, freq="2412")
5057    bss = dev[0].get_bss(bssid)
5058    logger.info("Before update: " + str(bss))
5059    if '6b091e0701020000000300' not in bss['ie']:
5060        raise Exception("Expected Interworking element not seen before update")
5061
5062    # Update configuration parameters related to Interworking element
5063    hapd.set('access_network_type', '2')
5064    hapd.set('asra', '1')
5065    hapd.set('esr', '1')
5066    hapd.set('uesa', '1')
5067    hapd.set('venue_group', '2')
5068    hapd.set('venue_type', '8')
5069    if "OK" not in hapd.request("UPDATE_BEACON"):
5070        raise Exception("UPDATE_BEACON failed")
5071    dev[0].request("BSS_FLUSH 0")
5072    dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
5073    bss = dev[0].get_bss(bssid)
5074    logger.info("After update: " + str(bss))
5075    if '6b09f20208020000000300' not in bss['ie']:
5076        raise Exception("Expected Interworking element not seen after update")
5077
5078def test_ap_hs20_terms_and_conditions(dev, apdev):
5079    """Hotspot 2.0 Terms and Conditions signaling"""
5080    check_eap_capa(dev[0], "MSCHAPV2")
5081    bssid = apdev[0]['bssid']
5082    params = hs20_ap_params()
5083    params['hessid'] = bssid
5084    params['hs20_t_c_filename'] = 'terms-and-conditions'
5085    params['hs20_t_c_timestamp'] = '123456789'
5086
5087    hostapd.add_ap(apdev[0], params)
5088
5089    dev[0].hs20_enable()
5090    dev[0].connect("test-hs20", proto="RSN", key_mgmt="WPA-EAP", eap="TTLS",
5091                   identity="hs20-t-c-test", password="password",
5092                   ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
5093                   ieee80211w='2', scan_freq="2412")
5094    ev = dev[0].wait_event(["HS20-T-C-ACCEPTANCE"], timeout=5)
5095    if ev is None:
5096        raise Exception("Terms and Conditions Acceptance notification not received")
5097    url = "https://example.com/t_and_c?addr=%s&ap=123" % dev[0].own_addr()
5098    if url not in ev:
5099        raise Exception("Unexpected URL: " + ev)
5100
5101def test_ap_hs20_terms_and_conditions_coa(dev, apdev):
5102    """Hotspot 2.0 Terms and Conditions signaling - CoA"""
5103    try:
5104        import pyrad.client
5105        import pyrad.packet
5106        import pyrad.dictionary
5107        import radius_das
5108    except ImportError:
5109        raise HwsimSkip("No pyrad modules available")
5110
5111    check_eap_capa(dev[0], "MSCHAPV2")
5112    bssid = apdev[0]['bssid']
5113    params = hs20_ap_params()
5114    params['hessid'] = bssid
5115    params['hs20_t_c_filename'] = 'terms-and-conditions'
5116    params['hs20_t_c_timestamp'] = '123456789'
5117    params['own_ip_addr'] = "127.0.0.1"
5118    params['radius_das_port'] = "3799"
5119    params['radius_das_client'] = "127.0.0.1 secret"
5120    params['radius_das_require_event_timestamp'] = "1"
5121    hapd = hostapd.add_ap(apdev[0], params)
5122
5123    dev[0].hs20_enable()
5124    dev[0].connect("test-hs20", proto="RSN", key_mgmt="WPA-EAP", eap="TTLS",
5125                   identity="hs20-t-c-test", password="password",
5126                   ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
5127                   ieee80211w='2', scan_freq="2412")
5128
5129    ev = hapd.wait_event(["HS20-T-C-FILTERING-ADD"], timeout=5)
5130    if ev is None:
5131        raise Exception("Terms and Conditions filtering not enabled")
5132    if ev.split(' ')[1] != dev[0].own_addr():
5133        raise Exception("Unexpected STA address for filtering: " + ev)
5134
5135    ev = dev[0].wait_event(["HS20-T-C-ACCEPTANCE"], timeout=5)
5136    if ev is None:
5137        raise Exception("Terms and Conditions Acceptance notification not received")
5138    url = "https://example.com/t_and_c?addr=%s&ap=123" % dev[0].own_addr()
5139    if url not in ev:
5140        raise Exception("Unexpected URL: " + ev)
5141
5142    dict = pyrad.dictionary.Dictionary("dictionary.radius")
5143
5144    srv = pyrad.client.Client(server="127.0.0.1", acctport=3799,
5145                              secret=b"secret", dict=dict)
5146    srv.retries = 1
5147    srv.timeout = 1
5148
5149    sta = hapd.get_sta(dev[0].own_addr())
5150    multi_sess_id = sta['authMultiSessionId']
5151
5152    logger.info("CoA-Request with matching Acct-Session-Id")
5153    vsa = binascii.unhexlify('00009f68090600000000')
5154    req = radius_das.CoAPacket(dict=dict, secret=b"secret",
5155                               NAS_IP_Address="127.0.0.1",
5156                               Acct_Multi_Session_Id=multi_sess_id,
5157                               Chargeable_User_Identity="hs20-cui",
5158                               Event_Timestamp=int(time.time()),
5159                               Vendor_Specific=vsa)
5160    reply = srv.SendPacket(req)
5161    logger.debug("RADIUS response from hostapd")
5162    for i in list(reply.keys()):
5163        logger.debug("%s: %s" % (i, reply[i]))
5164    if reply.code != pyrad.packet.CoAACK:
5165        raise Exception("CoA-Request failed")
5166
5167    ev = hapd.wait_event(["HS20-T-C-FILTERING-REMOVE"], timeout=5)
5168    if ev is None:
5169        raise Exception("Terms and Conditions filtering not disabled")
5170    if ev.split(' ')[1] != dev[0].own_addr():
5171        raise Exception("Unexpected STA address for filtering: " + ev)
5172
5173def test_ap_hs20_terms_and_conditions_sql(dev, apdev, params):
5174    """Hotspot 2.0 Terms and Conditions using SQLite for user DB"""
5175    addr = dev[0].own_addr()
5176    run_ap_hs20_terms_and_conditions_sql(dev, apdev, params,
5177                                         "https://example.com/t_and_c?addr=@1@&ap=123",
5178                                         "https://example.com/t_and_c?addr=" + addr + "&ap=123")
5179
5180def test_ap_hs20_terms_and_conditions_sql2(dev, apdev, params):
5181    """Hotspot 2.0 Terms and Conditions using SQLite for user DB"""
5182    addr = dev[0].own_addr()
5183    run_ap_hs20_terms_and_conditions_sql(dev, apdev, params,
5184                                         "https://example.com/t_and_c?addr=@1@",
5185                                         "https://example.com/t_and_c?addr=" + addr)
5186
5187def run_ap_hs20_terms_and_conditions_sql(dev, apdev, params, url_template,
5188                                         url_expected):
5189    check_eap_capa(dev[0], "MSCHAPV2")
5190    try:
5191        import sqlite3
5192    except ImportError:
5193        raise HwsimSkip("No sqlite3 module available")
5194    dbfile = params['prefix'] + ".eap-user.db"
5195    try:
5196        os.remove(dbfile)
5197    except:
5198        pass
5199    con = sqlite3.connect(dbfile)
5200    with con:
5201        cur = con.cursor()
5202        cur.execute("CREATE TABLE users(identity TEXT PRIMARY KEY, methods TEXT, password TEXT, phase2 INTEGER, t_c_timestamp INTEGER)")
5203        cur.execute("CREATE TABLE wildcards(identity TEXT PRIMARY KEY, methods TEXT)")
5204        cur.execute("INSERT INTO users(identity,methods,password,phase2) VALUES ('user-mschapv2','TTLS-MSCHAPV2','password',1)")
5205        cur.execute("INSERT INTO wildcards(identity,methods) VALUES ('','TTLS,TLS')")
5206        cur.execute("CREATE TABLE authlog(timestamp TEXT, session TEXT, nas_ip TEXT, username TEXT, note TEXT)")
5207        cur.execute("CREATE TABLE pending_tc(mac_addr TEXT PRIMARY KEY, identity TEXT)")
5208        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)")
5209
5210
5211    try:
5212        params = {"ssid": "as", "beacon_int": "2000",
5213                  "radius_server_clients": "auth_serv/radius_clients.conf",
5214                  "radius_server_auth_port": '18128',
5215                  "eap_server": "1",
5216                  "eap_user_file": "sqlite:" + dbfile,
5217                  "ca_cert": "auth_serv/ca.pem",
5218                  "server_cert": "auth_serv/server.pem",
5219                  "private_key": "auth_serv/server.key"}
5220        params['hs20_t_c_server_url'] = url_template
5221        authsrv = hostapd.add_ap(apdev[1], params)
5222
5223        bssid = apdev[0]['bssid']
5224        params = hs20_ap_params()
5225        params['auth_server_port'] = "18128"
5226        params['hs20_t_c_filename'] = 'terms-and-conditions'
5227        params['hs20_t_c_timestamp'] = '123456789'
5228        params['own_ip_addr'] = "127.0.0.1"
5229        params['radius_das_port'] = "3799"
5230        params['radius_das_client'] = "127.0.0.1 radius"
5231        params['radius_das_require_event_timestamp'] = "1"
5232        params['disable_pmksa_caching'] = '1'
5233        hapd = hostapd.add_ap(apdev[0], params)
5234
5235        dev[0].request("SET pmf 1")
5236        dev[0].hs20_enable()
5237        id = dev[0].add_cred_values({'realm': "example.com",
5238                                     'username': "user-mschapv2",
5239                                     'password': "password",
5240                                     'ca_cert': "auth_serv/ca.pem"})
5241        interworking_select(dev[0], bssid, freq="2412")
5242        interworking_connect(dev[0], bssid, "TTLS")
5243
5244        ev = hapd.wait_event(["HS20-T-C-FILTERING-ADD"], timeout=5)
5245        if ev is None:
5246            raise Exception("Terms and Conditions filtering not enabled")
5247        hapd.dump_monitor()
5248
5249        ev = dev[0].wait_event(["HS20-T-C-ACCEPTANCE"], timeout=5)
5250        if ev is None:
5251            raise Exception("Terms and Conditions Acceptance notification not received")
5252        url = ev.split(' ')[1]
5253        if url != url_expected:
5254            raise Exception("Unexpected URL delivered to the client: %s (expected %s)" % (url, url_expected))
5255        dev[0].dump_monitor()
5256
5257        with con:
5258            cur = con.cursor()
5259            cur.execute("SELECT * from current_sessions")
5260            rows = cur.fetchall()
5261            if len(rows) != 1:
5262                raise Exeception("Unexpected number of rows in current_sessions (%d; expected %d)" % (len(rows), 1))
5263            logger.info("current_sessions: " + str(rows))
5264
5265        tests = ["foo", "disconnect q", "coa %s" % dev[0].own_addr()]
5266        for t in tests:
5267            if "FAIL" not in authsrv.request("DAC_REQUEST " + t):
5268                raise Exception("Invalid DAC_REQUEST accepted: " + t)
5269        if "OK" not in authsrv.request("DAC_REQUEST coa %s t_c_clear" % dev[0].own_addr()):
5270            raise Exception("DAC_REQUEST failed")
5271
5272        ev = hapd.wait_event(["HS20-T-C-FILTERING-REMOVE"], timeout=5)
5273        if ev is None:
5274            raise Exception("Terms and Conditions filtering not disabled")
5275        if ev.split(' ')[1] != dev[0].own_addr():
5276            raise Exception("Unexpected STA address for filtering: " + ev)
5277
5278        time.sleep(0.2)
5279        with con:
5280            cur = con.cursor()
5281            cur.execute("SELECT * from current_sessions")
5282            rows = cur.fetchall()
5283            if len(rows) != 1:
5284                raise Exeception("Unexpected number of rows in current_sessions (%d; expected %d)" % (len(rows), 1))
5285            logger.info("current_sessions: " + str(rows))
5286            if rows[0][4] != 0 or rows[0][5] != 0 or rows[0][6] != 1:
5287                raise Exception("Unexpected current_sessions information after CoA-ACK")
5288
5289        dev[0].request("DISCONNECT")
5290        dev[0].wait_disconnected()
5291        dev[0].dump_monitor()
5292
5293        # Simulate T&C server operation on user reading the updated version
5294        with con:
5295            cur = con.cursor()
5296            cur.execute("SELECT identity FROM pending_tc WHERE mac_addr='" +
5297                        dev[0].own_addr() + "'")
5298            rows = cur.fetchall()
5299            if len(rows) != 1:
5300                raise Exception("No pending_tc entry found")
5301            if rows[0][0] != 'user-mschapv2':
5302                raise Exception("Unexpected pending_tc identity value")
5303
5304            cur.execute("UPDATE users SET t_c_timestamp=123456789 WHERE identity='user-mschapv2'")
5305
5306        dev[0].request("RECONNECT")
5307        dev[0].wait_connected()
5308
5309        ev = hapd.wait_event(["HS20-T-C-FILTERING-ADD"], timeout=0.1)
5310        if ev is not None:
5311            raise Exception("Terms and Conditions filtering enabled unexpectedly")
5312        hapd.dump_monitor()
5313
5314        ev = dev[0].wait_event(["HS20-T-C-ACCEPTANCE"], timeout=0.1)
5315        if ev is not None:
5316            raise Exception("Unexpected Terms and Conditions Acceptance notification")
5317        dev[0].dump_monitor()
5318
5319        dev[0].request("DISCONNECT")
5320        dev[0].wait_disconnected()
5321        dev[0].dump_monitor()
5322
5323        # New T&C available
5324        hapd.set('hs20_t_c_timestamp', '123456790')
5325
5326        dev[0].request("RECONNECT")
5327        dev[0].wait_connected()
5328
5329        ev = hapd.wait_event(["HS20-T-C-FILTERING-ADD"], timeout=5)
5330        if ev is None:
5331            raise Exception("Terms and Conditions filtering not enabled")
5332        hapd.dump_monitor()
5333
5334        ev = dev[0].wait_event(["HS20-T-C-ACCEPTANCE"], timeout=5)
5335        if ev is None:
5336            raise Exception("Terms and Conditions Acceptance notification not received (2)")
5337        dev[0].dump_monitor()
5338
5339        dev[0].request("DISCONNECT")
5340        dev[0].wait_disconnected()
5341        dev[0].dump_monitor()
5342
5343        # Simulate T&C server operation on user reading the updated version
5344        with con:
5345            cur = con.cursor()
5346            cur.execute("UPDATE users SET t_c_timestamp=123456790 WHERE identity='user-mschapv2'")
5347
5348        dev[0].request("RECONNECT")
5349        dev[0].wait_connected()
5350
5351        ev = hapd.wait_event(["HS20-T-C-FILTERING-ADD"], timeout=0.1)
5352        if ev is not None:
5353            raise Exception("Terms and Conditions filtering enabled unexpectedly")
5354        hapd.dump_monitor()
5355
5356        ev = dev[0].wait_event(["HS20-T-C-ACCEPTANCE"], timeout=0.1)
5357        if ev is not None:
5358            raise Exception("Unexpected Terms and Conditions Acceptance notification (2)")
5359        dev[0].dump_monitor()
5360    finally:
5361        os.remove(dbfile)
5362        dev[0].request("SET pmf 0")
5363
5364def test_ap_hs20_release_number_1(dev, apdev):
5365    """Hotspot 2.0 with AP claiming support for Release 1"""
5366    run_ap_hs20_release_number(dev, apdev, 1)
5367
5368def test_ap_hs20_release_number_2(dev, apdev):
5369    """Hotspot 2.0 with AP claiming support for Release 2"""
5370    run_ap_hs20_release_number(dev, apdev, 2)
5371
5372def test_ap_hs20_release_number_3(dev, apdev):
5373    """Hotspot 2.0 with AP claiming support for Release 3"""
5374    run_ap_hs20_release_number(dev, apdev, 3)
5375
5376def run_ap_hs20_release_number(dev, apdev, release):
5377    check_eap_capa(dev[0], "MSCHAPV2")
5378    eap_test(dev[0], apdev[0], "21[3:26][6:7][99:99]", "TTLS", "user",
5379             release=release)
5380    rel = dev[0].get_status_field('hs20')
5381    if rel != str(release):
5382        raise Exception("Unexpected release number indicated: " + rel)
5383
5384def test_ap_hs20_missing_pmf(dev, apdev):
5385    """Hotspot 2.0 connection attempt without PMF"""
5386    check_eap_capa(dev[0], "MSCHAPV2")
5387    bssid = apdev[0]['bssid']
5388    params = hs20_ap_params()
5389    params['hessid'] = bssid
5390    params['disable_dgaf'] = '1'
5391    hostapd.add_ap(apdev[0], params)
5392
5393    dev[0].hs20_enable()
5394    dev[0].connect("test-hs20", proto="RSN", key_mgmt="WPA-EAP", eap="TTLS",
5395                   ieee80211w="0",
5396                   identity="hs20-test", password="password",
5397                   ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
5398                   scan_freq="2412", update_identifier="54321",
5399                   roaming_consortium_selection="1020304050",
5400                   wait_connect=False)
5401    ev = dev[0].wait_event(["CTRL-EVENT-ASSOC-REJECT"], timeout=10)
5402    dev[0].request("DISCONNECT")
5403    if ev is None:
5404        raise Exception("Association rejection not reported")
5405    if "status_code=31" not in ev:
5406        raise Exception("Unexpected rejection reason: " + ev)
5407
5408def test_ap_hs20_open_osu_association(dev, apdev):
5409    """Hotspot 2.0 open OSU association"""
5410    try:
5411        run_ap_hs20_open_osu_association(dev, apdev)
5412    finally:
5413        dev[0].request("VENDOR_ELEM_REMOVE 13 *")
5414
5415def run_ap_hs20_open_osu_association(dev, apdev):
5416    params = {"ssid": "HS 2.0 OSU open"}
5417    hostapd.add_ap(apdev[0], params)
5418    dev[0].connect("HS 2.0 OSU open", key_mgmt="NONE", scan_freq="2412")
5419    dev[0].request("REMOVE_NETWORK all")
5420    dev[0].wait_disconnected()
5421    dev[0].dump_monitor()
5422    # Test with unexpected Hotspot 2.0 Indication element in Assoc Req
5423    dev[0].request("VENDOR_ELEM_ADD 13 dd07506f9a10220000")
5424    dev[0].connect("HS 2.0 OSU open", key_mgmt="NONE", scan_freq="2412")
5425