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