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