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