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