]> git.ipfire.org Git - thirdparty/hostap.git/blame - tests/hwsim/test_ap_hs20.py
tests: Use shorter Interworking element for larger coverage
[thirdparty/hostap.git] / tests / hwsim / test_ap_hs20.py
CommitLineData
93a06242
JM
1#!/usr/bin/python
2#
3# Hotspot 2.0 tests
4# Copyright (c) 2013, Jouni Malinen <j@w1.fi>
5#
6# This software may be distributed under the terms of the BSD license.
7# See README for more details.
8
9import time
10import subprocess
11import logging
c9aa4308 12logger = logging.getLogger()
efd43d85
JM
13import os.path
14import subprocess
93a06242
JM
15
16import hostapd
715bf904 17from wlantest import Wlantest
93a06242
JM
18
19def hs20_ap_params():
20 params = hostapd.wpa2_params(ssid="test-hs20")
21 params['wpa_key_mgmt'] = "WPA-EAP"
22 params['ieee80211w'] = "1"
23 params['ieee8021x'] = "1"
24 params['auth_server_addr'] = "127.0.0.1"
25 params['auth_server_port'] = "1812"
26 params['auth_server_shared_secret'] = "radius"
27 params['interworking'] = "1"
28 params['access_network_type'] = "14"
29 params['internet'] = "1"
30 params['asra'] = "0"
31 params['esr'] = "0"
32 params['uesa'] = "0"
33 params['venue_group'] = "7"
34 params['venue_type'] = "1"
35 params['venue_name'] = [ "eng:Example venue", "fin:Esimerkkipaikka" ]
36 params['roaming_consortium'] = [ "112233", "1020304050", "010203040506",
37 "fedcba" ]
38 params['domain_name'] = "example.com,another.example.com"
39 params['nai_realm'] = [ "0,example.com,13[5:6],21[2:4][5:7]",
40 "0,another.example.com" ]
41 params['hs20'] = "1"
42 params['hs20_wan_metrics'] = "01:8000:1000:80:240:3000"
43 params['hs20_conn_capab'] = [ "1:0:2", "6:22:1", "17:5060:0" ]
44 params['hs20_operating_class'] = "5173"
45 params['anqp_3gpp_cell_net'] = "244,91"
46 return params
47
bbe86767
JM
48def interworking_select(dev, bssid, type=None, no_match=False):
49 dev.dump_monitor()
50 dev.request("INTERWORKING_SELECT")
51 ev = dev.wait_event(["INTERWORKING-AP", "INTERWORKING-NO-MATCH"],
52 timeout=15)
93a06242
JM
53 if ev is None:
54 raise Exception("Network selection timed out");
bbe86767
JM
55 if no_match:
56 if "INTERWORKING-NO-MATCH" not in ev:
57 raise Exception("Unexpected network match")
58 return
93a06242
JM
59 if "INTERWORKING-NO-MATCH" in ev:
60 raise Exception("Matching network not found")
61 if bssid not in ev:
62 raise Exception("Unexpected BSSID in match")
bbe86767
JM
63 if type and "type=" + type not in ev:
64 raise Exception("Network type not recognized correctly")
93a06242 65
bbe86767
JM
66def check_sp_type(dev, sp_type):
67 type = dev.get_status_field("sp_type")
68 if type is None:
69 raise Exception("sp_type not available")
70 if type != sp_type:
71 raise Exception("sp_type did not indicate home network")
efd43d85 72
bbe86767 73def hlr_auc_gw_available():
efd43d85
JM
74 if not os.path.exists("/tmp/hlr_auc_gw.sock"):
75 logger.info("No hlr_auc_gw available");
bbe86767 76 return False
efd43d85
JM
77 if not os.path.exists("../../hostapd/hlr_auc_gw"):
78 logger.info("No hlr_auc_gw available");
bbe86767
JM
79 return False
80 return True
efd43d85 81
bbe86767
JM
82def interworking_ext_sim_connect(dev, bssid, method):
83 dev.request("INTERWORKING_CONNECT " + bssid)
efd43d85 84
bbe86767 85 ev = dev.wait_event(["CTRL-EVENT-EAP-METHOD"], timeout=15)
efd43d85
JM
86 if ev is None:
87 raise Exception("Network connected timed out")
bbe86767 88 if "(" + method + ")" not in ev:
efd43d85
JM
89 raise Exception("Unexpected EAP method selection")
90
bbe86767 91 ev = dev.wait_event(["CTRL-REQ-SIM"], timeout=15)
efd43d85
JM
92 if ev is None:
93 raise Exception("Wait for external SIM processing request timed out")
94 p = ev.split(':', 2)
95 if p[1] != "GSM-AUTH":
96 raise Exception("Unexpected CTRL-REQ-SIM type")
97 id = p[0].split('-')[3]
98 rand = p[2].split(' ')[0]
99
100 res = subprocess.check_output(["../../hostapd/hlr_auc_gw",
101 "-m",
102 "auth_serv/hlr_auc_gw.milenage_db",
103 "GSM-AUTH-REQ 232010000000000 " + rand])
104 if "GSM-AUTH-RESP" not in res:
105 raise Exception("Unexpected hlr_auc_gw response")
106 resp = res.split(' ')[2].rstrip()
107
bbe86767
JM
108 dev.request("CTRL-RSP-SIM-" + id + ":GSM-AUTH:" + resp)
109 ev = dev.wait_event(["CTRL-EVENT-CONNECTED"], timeout=15)
efd43d85
JM
110 if ev is None:
111 raise Exception("Connection timed out")
f4defd91 112
8fba2e5d
JM
113def interworking_connect(dev, bssid, method):
114 dev.request("INTERWORKING_CONNECT " + bssid)
115
116 ev = dev.wait_event(["CTRL-EVENT-EAP-METHOD"], timeout=15)
117 if ev is None:
118 raise Exception("Network connected timed out")
119 if "(" + method + ")" not in ev:
120 raise Exception("Unexpected EAP method selection")
121
122 ev = dev.wait_event(["CTRL-EVENT-CONNECTED"], timeout=15)
123 if ev is None:
124 raise Exception("Connection timed out")
125
715bf904
JM
126def check_probe_resp(wt, bssid_unexpected, bssid_expected):
127 if bssid_unexpected:
128 count = wt.get_bss_counter("probe_response", bssid_unexpected)
129 if count > 0:
130 raise Exception("Unexpected Probe Response frame from AP")
131
132 if bssid_expected:
133 count = wt.get_bss_counter("probe_response", bssid_expected)
134 if count == 0:
135 raise Exception("No Probe Response frame from AP")
136
137def test_ap_interworking_scan_filtering(dev, apdev):
138 """Interworking scan filtering with HESSID and access network type"""
139 bssid = apdev[0]['bssid']
140 params = hs20_ap_params()
141 ssid = "test-hs20-ap1"
142 params['ssid'] = ssid
143 params['hessid'] = bssid
144 hostapd.add_ap(apdev[0]['ifname'], params)
145
146 bssid2 = apdev[1]['bssid']
147 params = hs20_ap_params()
148 ssid2 = "test-hs20-ap2"
149 params['ssid'] = ssid2
150 params['hessid'] = bssid2
151 params['access_network_type'] = "1"
8175854e
JM
152 del params['venue_group']
153 del params['venue_type']
715bf904
JM
154 hostapd.add_ap(apdev[1]['ifname'], params)
155
156 dev[0].request("SET ignore_old_scan_res 1")
157 dev[0].hs20_enable()
158
159 wt = Wlantest()
160 wt.flush()
161
162 logger.info("Check probe request filtering based on HESSID")
163
164 dev[0].request("SET hessid " + bssid2)
0589f401 165 dev[0].scan(freq="2412")
715bf904
JM
166 check_probe_resp(wt, bssid, bssid2)
167
168 logger.info("Check probe request filtering based on access network type")
169
170 wt.clear_bss_counters(bssid)
171 wt.clear_bss_counters(bssid2)
172 dev[0].request("SET hessid 00:00:00:00:00:00")
173 dev[0].request("SET access_network_type 14")
0589f401 174 dev[0].scan(freq="2412")
715bf904
JM
175 check_probe_resp(wt, bssid2, bssid)
176
177 wt.clear_bss_counters(bssid)
178 wt.clear_bss_counters(bssid2)
179 dev[0].request("SET hessid 00:00:00:00:00:00")
180 dev[0].request("SET access_network_type 1")
0589f401 181 dev[0].scan(freq="2412")
715bf904
JM
182 check_probe_resp(wt, bssid, bssid2)
183
184 logger.info("Check probe request filtering based on HESSID and ANT")
185
186 wt.clear_bss_counters(bssid)
187 wt.clear_bss_counters(bssid2)
188 dev[0].request("SET hessid " + bssid)
189 dev[0].request("SET access_network_type 14")
0589f401 190 dev[0].scan(freq="2412")
715bf904
JM
191 check_probe_resp(wt, bssid2, bssid)
192
193 wt.clear_bss_counters(bssid)
194 wt.clear_bss_counters(bssid2)
195 dev[0].request("SET hessid " + bssid2)
196 dev[0].request("SET access_network_type 14")
0589f401 197 dev[0].scan(freq="2412")
715bf904
JM
198 check_probe_resp(wt, bssid, None)
199 check_probe_resp(wt, bssid2, None)
200
201 wt.clear_bss_counters(bssid)
202 wt.clear_bss_counters(bssid2)
203 dev[0].request("SET hessid " + bssid)
204 dev[0].request("SET access_network_type 1")
0589f401 205 dev[0].scan(freq="2412")
715bf904
JM
206 check_probe_resp(wt, bssid, None)
207 check_probe_resp(wt, bssid2, None)
208
bbe86767
JM
209def test_ap_hs20_select(dev, apdev):
210 """Hotspot 2.0 network selection"""
211 bssid = apdev[0]['bssid']
212 params = hs20_ap_params()
213 params['hessid'] = bssid
214 hostapd.add_ap(apdev[0]['ifname'], params)
215
469f5f3c 216 dev[0].request("SET ignore_old_scan_res 1")
bbe86767 217 dev[0].hs20_enable()
2232edf8
JM
218 id = dev[0].add_cred_values({ 'realm': "example.com", 'username': "test",
219 'password': "secret",
220 'domain': "example.com" })
bbe86767
JM
221 interworking_select(dev[0], bssid, "home")
222
223 dev[0].remove_cred(id)
2232edf8
JM
224 id = dev[0].add_cred_values({ 'realm': "example.com", 'username': "test",
225 'password': "secret",
226 'domain': "no.match.example.com" })
bbe86767
JM
227 interworking_select(dev[0], bssid, "roaming")
228
229 dev[0].set_cred_quoted(id, "realm", "no.match.example.com");
230 interworking_select(dev[0], bssid, no_match=True)
231
232def test_ap_hs20_ext_sim(dev, apdev):
233 """Hotspot 2.0 with external SIM processing"""
234 if not hlr_auc_gw_available():
235 return "skip"
236 bssid = apdev[0]['bssid']
237 params = hs20_ap_params()
238 params['hessid'] = bssid
239 params['anqp_3gpp_cell_net'] = "232,01"
240 params['domain_name'] = "wlan.mnc001.mcc232.3gppnetwork.org"
241 hostapd.add_ap(apdev[0]['ifname'], params)
242
469f5f3c 243 dev[0].request("SET ignore_old_scan_res 1")
bbe86767
JM
244 dev[0].hs20_enable()
245 dev[0].request("SET external_sim 1")
2232edf8 246 dev[0].add_cred_values({ 'imsi': "23201-0000000000", 'eap': "SIM" })
bbe86767
JM
247 interworking_select(dev[0], "home")
248 interworking_ext_sim_connect(dev[0], bssid, "SIM")
249 check_sp_type(dev[0], "home")
59f8a3c6
JM
250
251def test_ap_hs20_ext_sim_roaming(dev, apdev):
252 """Hotspot 2.0 with external SIM processing in roaming network"""
253 if not hlr_auc_gw_available():
254 return "skip"
255 bssid = apdev[0]['bssid']
256 params = hs20_ap_params()
257 params['hessid'] = bssid
258 params['anqp_3gpp_cell_net'] = "244,91;310,026;232,01;234,56"
259 params['domain_name'] = "wlan.mnc091.mcc244.3gppnetwork.org"
260 hostapd.add_ap(apdev[0]['ifname'], params)
261
469f5f3c 262 dev[0].request("SET ignore_old_scan_res 1")
59f8a3c6
JM
263 dev[0].hs20_enable()
264 dev[0].request("SET external_sim 1")
2232edf8 265 dev[0].add_cred_values({ 'imsi': "23201-0000000000", 'eap': "SIM" })
59f8a3c6
JM
266 interworking_select(dev[0], "roaming")
267 interworking_ext_sim_connect(dev[0], bssid, "SIM")
268 check_sp_type(dev[0], "roaming")
8fba2e5d
JM
269
270def test_ap_hs20_username(dev, apdev):
271 """Hotspot 2.0 connection in username/password credential"""
8fba2e5d
JM
272 bssid = apdev[0]['bssid']
273 params = hs20_ap_params()
274 params['hessid'] = bssid
275 hostapd.add_ap(apdev[0]['ifname'], params)
276
469f5f3c 277 dev[0].request("SET ignore_old_scan_res 1")
8fba2e5d 278 dev[0].hs20_enable()
2232edf8
JM
279 id = dev[0].add_cred_values({ 'realm': "example.com",
280 'username': "hs20-test",
281 'password': "password",
282 'domain': "example.com" })
8fba2e5d
JM
283 interworking_select(dev[0], bssid, "home")
284 interworking_connect(dev[0], bssid, "TTLS")
285 check_sp_type(dev[0], "home")
286
287def test_ap_hs20_username_roaming(dev, apdev):
288 """Hotspot 2.0 connection in username/password credential (roaming)"""
8fba2e5d
JM
289 bssid = apdev[0]['bssid']
290 params = hs20_ap_params()
291 params['nai_realm'] = [ "0,example.com,13[5:6],21[2:4][5:7]",
292 "0,roaming.example.com,21[2:4][5:7]",
293 "0,another.example.com" ]
294 params['domain_name'] = "another.example.com"
295 params['hessid'] = bssid
296 hostapd.add_ap(apdev[0]['ifname'], params)
297
469f5f3c 298 dev[0].request("SET ignore_old_scan_res 1")
8fba2e5d 299 dev[0].hs20_enable()
2232edf8
JM
300 id = dev[0].add_cred_values({ 'realm': "roaming.example.com",
301 'username': "hs20-test",
302 'password': "password",
303 'domain': "example.com" })
8fba2e5d
JM
304 interworking_select(dev[0], bssid, "roaming")
305 interworking_connect(dev[0], bssid, "TTLS")
306 check_sp_type(dev[0], "roaming")
307
308def test_ap_hs20_username_unknown(dev, apdev):
309 """Hotspot 2.0 connection in username/password credential (no domain in cred)"""
8fba2e5d
JM
310 bssid = apdev[0]['bssid']
311 params = hs20_ap_params()
312 params['hessid'] = bssid
313 hostapd.add_ap(apdev[0]['ifname'], params)
314
469f5f3c 315 dev[0].request("SET ignore_old_scan_res 1")
8fba2e5d 316 dev[0].hs20_enable()
2232edf8
JM
317 id = dev[0].add_cred_values({ 'realm': "example.com",
318 'username': "hs20-test",
319 'password': "password" })
8fba2e5d
JM
320 interworking_select(dev[0], bssid, "unknown")
321 interworking_connect(dev[0], bssid, "TTLS")
322 check_sp_type(dev[0], "unknown")
323
324def test_ap_hs20_username_unknown2(dev, apdev):
325 """Hotspot 2.0 connection in username/password credential (no domain advertized)"""
8fba2e5d
JM
326 bssid = apdev[0]['bssid']
327 params = hs20_ap_params()
328 params['hessid'] = bssid
329 del params['domain_name']
330 hostapd.add_ap(apdev[0]['ifname'], params)
331
469f5f3c 332 dev[0].request("SET ignore_old_scan_res 1")
8fba2e5d 333 dev[0].hs20_enable()
2232edf8
JM
334 id = dev[0].add_cred_values({ 'realm': "example.com",
335 'username': "hs20-test",
336 'password': "password",
337 'domain': "example.com" })
8fba2e5d
JM
338 interworking_select(dev[0], bssid, "unknown")
339 interworking_connect(dev[0], bssid, "TTLS")
340 check_sp_type(dev[0], "unknown")
d1ba402f 341
483691bd
JM
342def test_ap_hs20_gas_while_associated(dev, apdev):
343 """Hotspot 2.0 connection with GAS query while associated"""
344 bssid = apdev[0]['bssid']
345 params = hs20_ap_params()
346 params['hessid'] = bssid
347 hostapd.add_ap(apdev[0]['ifname'], params)
348
349 dev[0].request("SET ignore_old_scan_res 1")
350 dev[0].hs20_enable()
351 id = dev[0].add_cred_values({ 'realm': "example.com",
352 'username': "hs20-test",
353 'password': "password",
354 'domain': "example.com" })
355 interworking_select(dev[0], bssid, "home")
356 interworking_connect(dev[0], bssid, "TTLS")
357
358 logger.info("Verifying GAS query while associated")
359 dev[0].request("FETCH_ANQP")
360 for i in range(0, 6):
361 ev = dev[0].wait_event(["RX-ANQP"], timeout=5)
362 if ev is None:
363 raise Exception("Operation timed out")
364
365def test_ap_hs20_gas_frag_while_associated(dev, apdev):
366 """Hotspot 2.0 connection with fragmented GAS query while associated"""
367 bssid = apdev[0]['bssid']
368 params = hs20_ap_params()
369 params['hessid'] = bssid
370 hostapd.add_ap(apdev[0]['ifname'], params)
371 hapd = hostapd.Hostapd(apdev[0]['ifname'])
372 hapd.set("gas_frag_limit", "50")
373
374 dev[0].request("SET ignore_old_scan_res 1")
375 dev[0].hs20_enable()
376 id = dev[0].add_cred_values({ 'realm': "example.com",
377 'username': "hs20-test",
378 'password': "password",
379 'domain': "example.com" })
380 interworking_select(dev[0], bssid, "home")
381 interworking_connect(dev[0], bssid, "TTLS")
382
383 logger.info("Verifying GAS query while associated")
384 dev[0].request("FETCH_ANQP")
385 for i in range(0, 6):
386 ev = dev[0].wait_event(["RX-ANQP"], timeout=5)
387 if ev is None:
388 raise Exception("Operation timed out")
389
6a0b4002
JM
390def test_ap_hs20_multiple_connects(dev, apdev):
391 """Hotspot 2.0 connection through multiple network selections"""
392 bssid = apdev[0]['bssid']
393 params = hs20_ap_params()
394 params['hessid'] = bssid
395 hostapd.add_ap(apdev[0]['ifname'], params)
396
469f5f3c 397 dev[0].request("SET ignore_old_scan_res 1")
6a0b4002
JM
398 dev[0].hs20_enable()
399 values = { 'realm': "example.com",
400 'username': "hs20-test",
401 'password': "password",
402 'domain': "example.com" }
403 id = dev[0].add_cred_values(values)
404
405 for i in range(0, 3):
406 logger.info("Starting Interworking network selection")
407 dev[0].request("INTERWORKING_SELECT auto")
408 while True:
409 ev = dev[0].wait_event(["INTERWORKING-NO-MATCH",
410 "INTERWORKING-ALREADY-CONNECTED",
411 "CTRL-EVENT-CONNECTED"], timeout=15)
412 if ev is None:
413 raise Exception("Connection timed out")
414 if "INTERWORKING-NO-MATCH" in ev:
415 raise Exception("Matching AP not found")
416 if "CTRL-EVENT-CONNECTED" in ev:
417 break
418 if i == 2 and "INTERWORKING-ALREADY-CONNECTED" in ev:
419 break
420 if i == 0:
421 dev[0].request("DISCONNECT")
422 dev[0].dump_monitor()
423
424 networks = dev[0].list_networks()
425 if len(networks) > 1:
426 raise Exception("Duplicated network block detected")
427
b4264f8f
JM
428def test_ap_hs20_disallow_aps(dev, apdev):
429 """Hotspot 2.0 connection and disallow_aps"""
430 bssid = apdev[0]['bssid']
431 params = hs20_ap_params()
432 params['hessid'] = bssid
433 hostapd.add_ap(apdev[0]['ifname'], params)
434
469f5f3c 435 dev[0].request("SET ignore_old_scan_res 1")
b4264f8f
JM
436 dev[0].hs20_enable()
437 values = { 'realm': "example.com",
438 'username': "hs20-test",
439 'password': "password",
440 'domain': "example.com" }
441 id = dev[0].add_cred_values(values)
442
443 logger.info("Verify disallow_aps bssid")
444 dev[0].request("SET disallow_aps bssid " + bssid.translate(None, ':'))
445 dev[0].request("INTERWORKING_SELECT auto")
446 ev = dev[0].wait_event(["INTERWORKING-NO-MATCH"], timeout=15)
447 if ev is None:
448 raise Exception("Network selection timed out")
449 dev[0].dump_monitor()
450
451 logger.info("Verify disallow_aps ssid")
452 dev[0].request("SET disallow_aps ssid 746573742d68733230")
453 dev[0].request("INTERWORKING_SELECT auto")
454 ev = dev[0].wait_event(["INTERWORKING-NO-MATCH"], timeout=15)
455 if ev is None:
456 raise Exception("Network selection timed out")
457 dev[0].dump_monitor()
458
459 logger.info("Verify disallow_aps clear")
460 dev[0].request("SET disallow_aps ")
461 interworking_select(dev[0], bssid, "home")
462
463 dev[0].request("SET disallow_aps bssid " + bssid.translate(None, ':'))
464 ret = dev[0].request("INTERWORKING_CONNECT " + bssid)
465 if "FAIL" not in ret:
466 raise Exception("INTERWORKING_CONNECT to disallowed BSS not rejected")
467
d1ba402f
JM
468def policy_test(dev, ap, values, only_one=True):
469 dev.dump_monitor()
470 logger.info("Verify network selection to AP " + ap['ifname'])
471 bssid = ap['bssid']
469f5f3c 472 dev.request("SET ignore_old_scan_res 1")
d1ba402f
JM
473 dev.hs20_enable()
474 id = dev.add_cred_values(values)
475 dev.request("INTERWORKING_SELECT auto")
476 while True:
477 ev = dev.wait_event(["INTERWORKING-AP", "INTERWORKING-NO-MATCH",
478 "CTRL-EVENT-CONNECTED"], timeout=15)
479 if ev is None:
480 raise Exception("Connection timed out")
481 if "INTERWORKING-NO-MATCH" in ev:
482 raise Exception("Matching AP not found")
483 if only_one and "INTERWORKING-AP" in ev and bssid not in ev:
484 raise Exception("Unexpected AP claimed acceptable")
485 if "CTRL-EVENT-CONNECTED" in ev:
486 if bssid not in ev:
487 raise Exception("Connected to incorrect BSS")
488 break
489
490 conn_bssid = dev.get_status_field("bssid")
491 if conn_bssid != bssid:
492 raise Exception("bssid information points to incorrect BSS")
493
494 dev.remove_cred(id)
495 dev.dump_monitor()
496
d355372c
JM
497def default_cred():
498 return { 'realm': "example.com",
499 'username': "hs20-test",
500 'password': "password" }
501
d1ba402f
JM
502def test_ap_hs20_req_roaming_consortium(dev, apdev):
503 """Hotspot 2.0 required roaming consortium"""
504 params = hs20_ap_params()
505 hostapd.add_ap(apdev[0]['ifname'], params)
506
507 params = hs20_ap_params()
508 params['ssid'] = "test-hs20-other"
509 params['roaming_consortium'] = [ "223344" ]
510 hostapd.add_ap(apdev[1]['ifname'], params)
511
d355372c
JM
512 values = default_cred()
513 values['required_roaming_consortium'] = "223344"
d1ba402f
JM
514 policy_test(dev[0], apdev[1], values)
515 values['required_roaming_consortium'] = "112233"
516 policy_test(dev[0], apdev[0], values)
d355372c
JM
517
518def test_ap_hs20_excluded_ssid(dev, apdev):
519 """Hotspot 2.0 exclusion based on SSID"""
520 params = hs20_ap_params()
521 hostapd.add_ap(apdev[0]['ifname'], params)
522
523 params = hs20_ap_params()
524 params['ssid'] = "test-hs20-other"
525 params['roaming_consortium'] = [ "223344" ]
526 hostapd.add_ap(apdev[1]['ifname'], params)
527
528 values = default_cred()
529 values['excluded_ssid'] = "test-hs20"
530 policy_test(dev[0], apdev[1], values)
531 values['excluded_ssid'] = "test-hs20-other"
532 policy_test(dev[0], apdev[0], values)