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