]>
git.ipfire.org Git - thirdparty/hostap.git/blob - tests/hwsim/test_mbo.py
2 # Copyright (c) 2016, Intel Deutschland GmbH
4 # This software may be distributed under the terms of the BSD license.
5 # See README for more details.
7 from remotehost
import remote_compatible
9 logger
= logging
.getLogger()
16 from tshark
import run_tshark
19 def set_reg(country_code
, apdev0
=None, apdev1
=None, dev0
=None):
21 hostapd
.cmd_execute(apdev0
, ['iw', 'reg', 'set', country_code
])
23 hostapd
.cmd_execute(apdev1
, ['iw', 'reg', 'set', country_code
])
25 dev0
.cmd_execute(['iw', 'reg', 'set', country_code
])
27 def run_mbo_supp_oper_classes(dev
, apdev
, hapd
, hapd2
, country
, freq_list
=None,
28 disable_ht
=False, disable_vht
=False):
29 """MBO and supported operating classes"""
30 addr
= dev
[0].own_addr()
35 dev
[0].flush_scan_cache()
38 logger
.info("Country: " + country
)
39 dev
[0].note("Setting country code " + country
)
40 set_reg(country
, apdev
[0], apdev
[1], dev
[0])
42 ev
= dev
[0].wait_event(["CTRL-EVENT-REGDOM-CHANGE"], timeout
=5)
44 raise Exception("No regdom change event")
45 if "alpha2=" + country
in ev
:
50 _disable_ht
= "1" if disable_ht
else "0"
51 _disable_vht
= "1" if disable_vht
else "0"
53 hapd
.set("country_code", country
)
55 dev
[0].scan_for_bss(hapd
.own_addr(), 5180, force_scan
=True)
56 dev
[0].connect("test-wnm-mbo", key_mgmt
="NONE", scan_freq
="5180",
57 freq_list
=freq_list
, disable_ht
=_disable_ht
,
58 disable_vht
=_disable_vht
)
59 sta
= hapd
.get_sta(addr
)
60 res5
= sta
['supp_op_classes'][2:]
61 dev
[0].wait_regdom(country_ie
=True)
65 dev
[0].request("REMOVE_NETWORK all")
66 dev
[0].request("ABORT_SCAN")
67 dev
[0].wait_disconnected()
70 hapd2
.set("country_code", country
)
72 dev
[0].scan_for_bss(hapd2
.own_addr(), 2412, force_scan
=True)
73 dev
[0].connect("test-wnm-mbo-2", key_mgmt
="NONE", scan_freq
="2412",
74 freq_list
=freq_list
, disable_ht
=_disable_ht
,
75 disable_vht
=_disable_vht
)
76 sta
= hapd2
.get_sta(addr
)
77 res2
= sta
['supp_op_classes'][2:]
78 dev
[0].wait_regdom(country_ie
=True)
82 dev
[0].request("REMOVE_NETWORK all")
83 dev
[0].request("ABORT_SCAN")
84 dev
[0].wait_disconnected()
89 def run_mbo_supp_oper_class(dev
, apdev
, country
, expected
, inc5
,
90 freq_list
=None, disable_ht
=False,
93 params
= {'ssid': "test-wnm-mbo",
100 hapd
= hostapd
.add_ap(apdev
[0], params
, no_enable
=True)
104 params
= {'ssid': "test-wnm-mbo-2",
106 "country_code": "US",
111 hapd2
= hostapd
.add_ap(apdev
[1], params
, no_enable
=True)
114 dev
[0].request("STA_AUTOCONNECT 0")
115 res2
, res5
= run_mbo_supp_oper_classes(dev
, apdev
, hapd
, hapd2
, country
,
117 disable_ht
=disable_ht
,
118 disable_vht
=disable_vht
)
120 dev
[0].dump_monitor()
121 dev
[0].request("STA_AUTOCONNECT 1")
122 wait_regdom_changes(dev
[0])
123 country1
= dev
[0].get_driver_status_field("country")
124 logger
.info("Country code at the end (1): " + country1
)
125 set_reg("00", apdev
[0], apdev
[1], dev
[0])
126 country2
= dev
[0].get_driver_status_field("country")
127 logger
.info("Country code at the end (2): " + country2
)
129 ev
= dev
[0].wait_event(["CTRL-EVENT-REGDOM-CHANGE"], timeout
=1)
130 if ev
is None or "init=USER type=WORLD" in ev
:
132 wait_regdom_changes(dev
[0])
133 country3
= dev
[0].get_driver_status_field("country")
134 logger
.info("Country code at the end (3): " + country3
)
138 # For now, allow operating class 129 to be missing since not all
139 # installed regdb files include the 160 MHz channels.
140 expected2
= expected
.replace('808182', '8082')
141 # For now, allow operating classes 121-123 to be missing since not all
142 # installed regdb files include the related US DFS channels.
143 expected2
= expected2
.replace('78797a7b7c', '787c')
145 # For now, allow operating classes 124-127 to be missing for Finland
146 # since they were added only recently in regdb.
148 expected3
= expected3
.replace("7b7c7d7e7f80", "7b80")
149 if res2
!= expected
and res2
!= expected2
and res2
!= expected3
:
150 raise Exception("Unexpected supp_op_class string (country=%s, 2.4 GHz): %s (expected: %s)" % (country
, res2
, expected
))
151 if inc5
and res5
!= expected
and res5
!= expected2
and res5
!= expected3
:
152 raise Exception("Unexpected supp_op_class string (country=%s, 5 GHz): %s (expected: %s)" % (country
, res5
, expected
))
154 def test_mbo_supp_oper_classes_za(dev
, apdev
):
155 """MBO and supported operating classes (ZA)"""
156 run_mbo_supp_oper_class(dev
, apdev
, "ZA",
157 "515354737475767778797a7b808182", True)
159 def test_mbo_supp_oper_classes_fi(dev
, apdev
):
160 """MBO and supported operating classes (FI)"""
161 run_mbo_supp_oper_class(dev
, apdev
, "FI",
162 "515354737475767778797a7b7c7d7e7f808182", True)
164 def test_mbo_supp_oper_classes_us(dev
, apdev
):
165 """MBO and supported operating classes (US)"""
166 run_mbo_supp_oper_class(dev
, apdev
, "US",
167 "515354737475767778797a7b7c7d7e7f808182", True)
169 def test_mbo_supp_oper_classes_jp(dev
, apdev
):
170 """MBO and supported operating classes (JP)"""
171 run_mbo_supp_oper_class(dev
, apdev
, "JP",
172 "51525354737475767778797a7b808182", True)
174 def test_mbo_supp_oper_classes_bd(dev
, apdev
):
175 """MBO and supported operating classes (BD)"""
176 run_mbo_supp_oper_class(dev
, apdev
, "BD",
177 "5153547c7d7e7f80", False)
179 def test_mbo_supp_oper_classes_sy(dev
, apdev
):
180 """MBO and supported operating classes (SY)"""
181 run_mbo_supp_oper_class(dev
, apdev
, "SY",
184 def test_mbo_supp_oper_classes_us_freq_list(dev
, apdev
):
185 """MBO and supported operating classes (US) - freq_list"""
186 run_mbo_supp_oper_class(dev
, apdev
, "US", "515354", False,
187 freq_list
="2412 2437 2462")
189 def test_mbo_supp_oper_classes_us_disable_ht(dev
, apdev
):
190 """MBO and supported operating classes (US) - disable_ht"""
191 run_mbo_supp_oper_class(dev
, apdev
, "US", "517376797c7d", False,
194 def test_mbo_supp_oper_classes_us_disable_vht(dev
, apdev
):
195 """MBO and supported operating classes (US) - disable_vht"""
196 run_mbo_supp_oper_class(dev
, apdev
, "US",
197 "515354737475767778797a7b7c7d7e7f", False,
200 def test_mbo_assoc_disallow(dev
, apdev
, params
):
201 """MBO and association disallowed"""
202 hapd1
= hostapd
.add_ap(apdev
[0], {"ssid": "MBO", "mbo": "1"})
203 hapd2
= hostapd
.add_ap(apdev
[1], {"ssid": "MBO", "mbo": "1"})
205 logger
.debug("Set mbo_assoc_disallow with invalid value")
206 if "FAIL" not in hapd1
.request("SET mbo_assoc_disallow 2"):
207 raise Exception("Set mbo_assoc_disallow for AP1 succeeded unexpectedly with value 2")
209 logger
.debug("Disallow associations to AP1 and allow association to AP2")
210 if "OK" not in hapd1
.request("SET mbo_assoc_disallow 1"):
211 raise Exception("Failed to set mbo_assoc_disallow for AP1")
212 if "OK" not in hapd2
.request("SET mbo_assoc_disallow 0"):
213 raise Exception("Failed to set mbo_assoc_disallow for AP2")
215 dev
[0].connect("MBO", key_mgmt
="NONE", scan_freq
="2412")
217 out
= run_tshark(os
.path
.join(params
['logdir'], "hwsim0.pcapng"),
218 "wlan.fc.type == 0 && wlan.fc.type_subtype == 0x00",
220 if "Destination address: " + hapd1
.own_addr() in out
:
221 raise Exception("Association request sent to disallowed AP")
223 timestamp
= run_tshark(os
.path
.join(params
['logdir'], "hwsim0.pcapng"),
224 "wlan.fc.type_subtype == 0x00",
225 display
=['frame.time'], wait
=False)
227 logger
.debug("Allow associations to AP1 and disallow associations to AP2")
228 if "OK" not in hapd1
.request("SET mbo_assoc_disallow 0"):
229 raise Exception("Failed to set mbo_assoc_disallow for AP1")
230 if "OK" not in hapd2
.request("SET mbo_assoc_disallow 1"):
231 raise Exception("Failed to set mbo_assoc_disallow for AP2")
233 dev
[0].request("DISCONNECT")
234 dev
[0].wait_disconnected()
236 # Force new scan, so the assoc_disallowed indication is updated */
237 dev
[0].request("FLUSH")
239 dev
[0].connect("MBO", key_mgmt
="NONE", scan_freq
="2412")
241 filter = 'wlan.fc.type == 0 && wlan.fc.type_subtype == 0x00 && frame.time > "' + timestamp
.rstrip() + '"'
242 out
= run_tshark(os
.path
.join(params
['logdir'], "hwsim0.pcapng"),
244 if "Destination address: " + hapd2
.own_addr() in out
:
245 raise Exception("Association request sent to disallowed AP 2")
247 def test_mbo_assoc_disallow_ignore(dev
, apdev
):
248 """MBO and ignoring disallowed association"""
250 _test_mbo_assoc_disallow_ignore(dev
, apdev
)
252 dev
[0].request("SCAN_INTERVAL 5")
254 def _test_mbo_assoc_disallow_ignore(dev
, apdev
):
255 hapd1
= hostapd
.add_ap(apdev
[0], {"ssid": "MBO", "mbo": "1"})
256 if "OK" not in hapd1
.request("SET mbo_assoc_disallow 1"):
257 raise Exception("Failed to set mbo_assoc_disallow for AP1")
259 if "OK" not in dev
[0].request("SCAN_INTERVAL 1"):
260 raise Exception("Failed to set scan interval")
261 dev
[0].connect("MBO", key_mgmt
="NONE", scan_freq
="2412", wait_connect
=False)
262 ev
= dev
[0].wait_event(["CTRL-EVENT-NETWORK-NOT-FOUND"], timeout
=10)
264 raise Exception("CTRL-EVENT-NETWORK-NOT-FOUND not seen")
266 if "OK" not in dev
[0].request("SET ignore_assoc_disallow 1"):
267 raise Exception("Failed to set ignore_assoc_disallow")
268 ev
= dev
[0].wait_event(["CTRL-EVENT-ASSOC-REJECT"], timeout
=10)
270 raise Exception("CTRL-EVENT-ASSOC-REJECT not seen")
271 if "status_code=17" not in ev
:
272 raise Exception("Unexpected association reject reason: " + ev
)
274 if "OK" not in hapd1
.request("SET mbo_assoc_disallow 0"):
275 raise Exception("Failed to set mbo_assoc_disallow for AP1")
276 dev
[0].wait_connected()
279 def test_mbo_cell_capa_update(dev
, apdev
):
280 """MBO cellular data capability update"""
281 ssid
= "test-wnm-mbo"
282 params
= {'ssid': ssid
, 'mbo': '1'}
283 hapd
= hostapd
.add_ap(apdev
[0], params
)
284 bssid
= apdev
[0]['bssid']
285 if "OK" not in dev
[0].request("SET mbo_cell_capa 1"):
286 raise Exception("Failed to set STA as cellular data capable")
288 dev
[0].connect(ssid
, key_mgmt
="NONE", scan_freq
="2412")
290 addr
= dev
[0].own_addr()
291 sta
= hapd
.get_sta(addr
)
292 if 'mbo_cell_capa' not in sta
or sta
['mbo_cell_capa'] != '1':
293 raise Exception("mbo_cell_capa missing after association")
295 if "OK" not in dev
[0].request("SET mbo_cell_capa 3"):
296 raise Exception("Failed to set STA as cellular data not-capable")
297 # Duplicate update for additional code coverage
298 if "OK" not in dev
[0].request("SET mbo_cell_capa 3"):
299 raise Exception("Failed to set STA as cellular data not-capable")
302 sta
= hapd
.get_sta(addr
)
303 if 'mbo_cell_capa' not in sta
:
304 raise Exception("mbo_cell_capa missing after update")
305 if sta
['mbo_cell_capa'] != '3':
306 raise Exception("mbo_cell_capa not updated properly")
309 def test_mbo_cell_capa_update_pmf(dev
, apdev
):
310 """MBO cellular data capability update with PMF required"""
311 ssid
= "test-wnm-mbo"
312 passphrase
= "12345678"
313 params
= hostapd
.wpa2_params(ssid
=ssid
, passphrase
=passphrase
)
314 params
["wpa_key_mgmt"] = "WPA-PSK-SHA256"
315 params
["ieee80211w"] = "2"
317 hapd
= hostapd
.add_ap(apdev
[0], params
)
318 bssid
= apdev
[0]['bssid']
319 if "OK" not in dev
[0].request("SET mbo_cell_capa 1"):
320 raise Exception("Failed to set STA as cellular data capable")
322 dev
[0].connect(ssid
, psk
=passphrase
, key_mgmt
="WPA-PSK-SHA256",
323 proto
="WPA2", ieee80211w
="2", scan_freq
="2412")
326 addr
= dev
[0].own_addr()
327 sta
= hapd
.get_sta(addr
)
328 if 'mbo_cell_capa' not in sta
or sta
['mbo_cell_capa'] != '1':
329 raise Exception("mbo_cell_capa missing after association")
331 if "OK" not in dev
[0].request("SET mbo_cell_capa 3"):
332 raise Exception("Failed to set STA as cellular data not-capable")
335 sta
= hapd
.get_sta(addr
)
336 if 'mbo_cell_capa' not in sta
:
337 raise Exception("mbo_cell_capa missing after update")
338 if sta
['mbo_cell_capa'] != '3':
339 raise Exception("mbo_cell_capa not updated properly")
341 def test_mbo_wnm_token_wrap(dev
, apdev
):
342 """MBO WNM token wrap around"""
343 ssid
= "test-wnm-mbo"
344 params
= {'ssid': ssid
, 'mbo': '1'}
345 hapd
= hostapd
.add_ap(apdev
[0], params
)
346 bssid
= apdev
[0]['bssid']
348 dev
[0].connect(ssid
, key_mgmt
="NONE", scan_freq
="2412")
350 # Trigger transmission of 256 WNM-Notification frames to wrap around the
351 # 8-bit mbo_wnm_token counter.
353 if "OK" not in dev
[0].request("SET mbo_cell_capa 1"):
354 raise Exception("Failed to set STA as cellular data capable")
355 if "OK" not in dev
[0].request("SET mbo_cell_capa 3"):
356 raise Exception("Failed to set STA as cellular data not-capable")
359 def test_mbo_non_pref_chan(dev
, apdev
):
360 """MBO non-preferred channel list"""
361 ssid
= "test-wnm-mbo"
362 params
= {'ssid': ssid
, 'mbo': '1'}
363 hapd
= hostapd
.add_ap(apdev
[0], params
)
364 bssid
= apdev
[0]['bssid']
365 if "FAIL" not in dev
[0].request("SET non_pref_chan 81:7:200:99"):
366 raise Exception("Invalid non_pref_chan value accepted")
367 if "FAIL" not in dev
[0].request("SET non_pref_chan 81:15:200:3"):
368 raise Exception("Invalid non_pref_chan value accepted")
369 if "FAIL" not in dev
[0].request("SET non_pref_chan 81:7:200:3 81:7:201:3"):
370 raise Exception("Invalid non_pref_chan value accepted")
371 if "OK" not in dev
[0].request("SET non_pref_chan 81:7:200:3"):
372 raise Exception("Failed to set non-preferred channel list")
373 if "OK" not in dev
[0].request("SET non_pref_chan 81:7:200:1 81:9:100:2"):
374 raise Exception("Failed to set non-preferred channel list")
376 dev
[0].connect(ssid
, key_mgmt
="NONE", scan_freq
="2412")
378 addr
= dev
[0].own_addr()
379 sta
= hapd
.get_sta(addr
)
380 logger
.debug("STA: " + str(sta
))
381 if 'non_pref_chan[0]' not in sta
:
382 raise Exception("Missing non_pref_chan[0] value (assoc)")
383 if sta
['non_pref_chan[0]'] != '81:200:1:7':
384 raise Exception("Unexpected non_pref_chan[0] value (assoc)")
385 if 'non_pref_chan[1]' not in sta
:
386 raise Exception("Missing non_pref_chan[1] value (assoc)")
387 if sta
['non_pref_chan[1]'] != '81:100:2:9':
388 raise Exception("Unexpected non_pref_chan[1] value (assoc)")
389 if 'non_pref_chan[2]' in sta
:
390 raise Exception("Unexpected non_pref_chan[2] value (assoc)")
392 if "OK" not in dev
[0].request("SET non_pref_chan 81:9:100:2"):
393 raise Exception("Failed to update non-preferred channel list")
395 sta
= hapd
.get_sta(addr
)
396 logger
.debug("STA: " + str(sta
))
397 if 'non_pref_chan[0]' not in sta
:
398 raise Exception("Missing non_pref_chan[0] value (update 1)")
399 if sta
['non_pref_chan[0]'] != '81:100:2:9':
400 raise Exception("Unexpected non_pref_chan[0] value (update 1)")
401 if 'non_pref_chan[1]' in sta
:
402 raise Exception("Unexpected non_pref_chan[1] value (update 1)")
404 if "OK" not in dev
[0].request("SET non_pref_chan 81:9:100:2 81:10:100:2 81:8:100:2 81:7:100:1 81:5:100:1"):
405 raise Exception("Failed to update non-preferred channel list")
407 sta
= hapd
.get_sta(addr
)
408 logger
.debug("STA: " + str(sta
))
409 if 'non_pref_chan[0]' not in sta
:
410 raise Exception("Missing non_pref_chan[0] value (update 2)")
411 if sta
['non_pref_chan[0]'] != '81:100:1:7,5':
412 raise Exception("Unexpected non_pref_chan[0] value (update 2)")
413 if 'non_pref_chan[1]' not in sta
:
414 raise Exception("Missing non_pref_chan[1] value (update 2)")
415 if sta
['non_pref_chan[1]'] != '81:100:2:9,10,8':
416 raise Exception("Unexpected non_pref_chan[1] value (update 2)")
417 if 'non_pref_chan[2]' in sta
:
418 raise Exception("Unexpected non_pref_chan[2] value (update 2)")
420 if "OK" not in dev
[0].request("SET non_pref_chan 81:5:90:2 82:14:91:2"):
421 raise Exception("Failed to update non-preferred channel list")
423 sta
= hapd
.get_sta(addr
)
424 logger
.debug("STA: " + str(sta
))
425 if 'non_pref_chan[0]' not in sta
:
426 raise Exception("Missing non_pref_chan[0] value (update 3)")
427 if sta
['non_pref_chan[0]'] != '81:90:2:5':
428 raise Exception("Unexpected non_pref_chan[0] value (update 3)")
429 if 'non_pref_chan[1]' not in sta
:
430 raise Exception("Missing non_pref_chan[1] value (update 3)")
431 if sta
['non_pref_chan[1]'] != '82:91:2:14':
432 raise Exception("Unexpected non_pref_chan[1] value (update 3)")
433 if 'non_pref_chan[2]' in sta
:
434 raise Exception("Unexpected non_pref_chan[2] value (update 3)")
436 if "OK" not in dev
[0].request("SET non_pref_chan "):
437 raise Exception("Failed to update non-preferred channel list")
439 sta
= hapd
.get_sta(addr
)
440 logger
.debug("STA: " + str(sta
))
441 if 'non_pref_chan[0]' in sta
:
442 raise Exception("Unexpected non_pref_chan[0] value (update 4)")
445 def test_mbo_sta_supp_op_classes(dev
, apdev
):
446 """MBO STA supported operating classes"""
447 ssid
= "test-wnm-mbo"
448 params
= {'ssid': ssid
, 'mbo': '1'}
449 hapd
= hostapd
.add_ap(apdev
[0], params
)
451 dev
[0].connect(ssid
, key_mgmt
="NONE", scan_freq
="2412")
453 addr
= dev
[0].own_addr()
454 sta
= hapd
.get_sta(addr
)
455 logger
.debug("STA: " + str(sta
))
456 if 'supp_op_classes' not in sta
:
457 raise Exception("No supp_op_classes")
458 supp
= bytearray(binascii
.unhexlify(sta
['supp_op_classes']))
460 raise Exception("Unexpected current operating class %d" % supp
[0])
462 raise Exception("Operating class 115 missing")
464 def test_mbo_failures(dev
, apdev
):
465 """MBO failure cases"""
466 ssid
= "test-wnm-mbo"
467 params
= {'ssid': ssid
, 'mbo': '1'}
468 hapd
= hostapd
.add_ap(apdev
[0], params
)
470 with
alloc_fail(dev
[0], 1, "wpas_mbo_ie"):
471 dev
[0].connect(ssid
, key_mgmt
="NONE", scan_freq
="2412")
473 with
alloc_fail(dev
[0], 1, "wpas_mbo_send_wnm_notification"):
474 if "OK" not in dev
[0].request("SET mbo_cell_capa 1"):
475 raise Exception("Failed to set STA as cellular data capable")
476 with
fail_test(dev
[0], 1, "wpas_mbo_send_wnm_notification"):
477 if "OK" not in dev
[0].request("SET mbo_cell_capa 3"):
478 raise Exception("Failed to set STA as cellular data not-capable")
479 with
alloc_fail(dev
[0], 1, "wpas_mbo_update_non_pref_chan"):
480 if "FAIL" not in dev
[0].request("SET non_pref_chan 81:7:200:3"):
481 raise Exception("non_pref_chan value accepted during OOM")
482 with
alloc_fail(dev
[0], 2, "wpas_mbo_update_non_pref_chan"):
483 if "FAIL" not in dev
[0].request("SET non_pref_chan 81:7:200:3"):
484 raise Exception("non_pref_chan value accepted during OOM")
486 def test_mbo_wnm_bss_tm_ie_parsing(dev
, apdev
):
487 """MBO BSS transition request MBO IE parsing"""
488 ssid
= "test-wnm-mbo"
489 params
= hostapd
.wpa2_params(ssid
=ssid
, passphrase
="12345678")
490 hapd
= hostapd
.add_ap(apdev
[0], params
)
491 bssid
= apdev
[0]['bssid']
492 addr
= dev
[0].own_addr()
493 dev
[0].connect(ssid
, psk
="12345678", key_mgmt
="WPA-PSK",
494 proto
="WPA2", ieee80211w
="0", scan_freq
="2412")
496 dev
[0].request("SET ext_mgmt_frame_handling 1")
497 hdr
= "d0003a01" + addr
.replace(':', '') + bssid
.replace(':', '') + bssid
.replace(':', '') + "3000"
498 btm_hdr
= "0a070100030001"
500 tests
= [("Truncated attribute in MBO IE", "dd06506f9a160101"),
501 ("Unexpected cell data capa attribute length in MBO IE",
502 "dd09506f9a160501030500"),
503 ("Unexpected transition reason attribute length in MBO IE",
505 ("Unexpected assoc retry delay attribute length in MBO IE",
506 "dd0c506f9a160100080200000800"),
507 ("Unknown attribute id 255 in MBO IE",
510 for test
, mbo_ie
in tests
:
512 dev
[0].request("NOTE " + test
)
513 frame
= hdr
+ btm_hdr
+ mbo_ie
514 if "OK" not in dev
[0].request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + frame
):
515 raise Exception("MGMT_RX_PROCESS failed")
517 logger
.info("Unexpected association retry delay")
518 dev
[0].request("NOTE Unexpected association retry delay")
519 btm_hdr
= "0a070108030001112233445566778899aabbcc"
520 mbo_ie
= "dd08506f9a1608020000"
521 frame
= hdr
+ btm_hdr
+ mbo_ie
522 if "OK" not in dev
[0].request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + frame
):
523 raise Exception("MGMT_RX_PROCESS failed")
525 dev
[0].request("SET ext_mgmt_frame_handling 0")
527 def test_mbo_without_pmf(dev
, apdev
):
528 """MBO and WPA2 without PMF"""
529 ssid
= "test-wnm-mbo"
530 params
= {'ssid': ssid
, 'mbo': '1', "wpa": '2',
531 "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP",
532 "wpa_passphrase": "12345678"}
534 # "MBO: PMF needs to be enabled whenever using WPA2 with MBO"
535 hostapd
.add_ap(apdev
[0], params
)
536 raise Exception("AP setup succeeded unexpectedly")
537 except Exception as e
:
538 if "Failed to enable hostapd" in str(e
):
543 def test_mbo_without_pmf_workaround(dev
, apdev
):
544 """MBO and WPA2 without PMF on misbehaving AP"""
545 ssid
= "test-wnm-mbo"
546 params
= {'ssid': ssid
, "wpa": '2',
547 "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP",
548 "wpa_passphrase": "12345678",
549 "vendor_elements": "dd07506f9a16010100"}
550 hapd
= hostapd
.add_ap(apdev
[0], params
)
551 dev
[0].connect(ssid
, psk
="12345678", key_mgmt
="WPA-PSK",
552 proto
="WPA2", ieee80211w
="1", scan_freq
="2412")
554 sta
= hapd
.get_sta(dev
[0].own_addr())
555 ext_capab
= bytearray(binascii
.unhexlify(sta
['ext_capab']))
556 if ext_capab
[2] & 0x08:
557 raise Exception("STA did not disable BSS Transition capability")
559 def check_mbo_anqp(dev
, bssid
, cell_data_conn_pref
):
560 if "OK" not in dev
.request("ANQP_GET " + bssid
+ " 272,mbo:2"):
561 raise Exception("ANQP_GET command failed")
563 ev
= dev
.wait_event(["GAS-QUERY-START"], timeout
=5)
565 raise Exception("GAS query start timed out")
567 ev
= dev
.wait_event(["GAS-QUERY-DONE"], timeout
=10)
569 raise Exception("GAS query timed out")
571 if cell_data_conn_pref
is not None:
572 ev
= dev
.wait_event(["RX-MBO-ANQP"], timeout
=1)
573 if ev
is None or "cell_conn_pref" not in ev
:
574 raise Exception("Did not receive MBO Cellular Data Connection Preference")
575 if cell_data_conn_pref
!= int(ev
.split('=')[1]):
576 raise Exception("Unexpected cell_conn_pref value: " + ev
)
580 def test_mbo_anqp(dev
, apdev
):
582 params
= {'ssid': "test-wnm-mbo",
585 'mbo_cell_data_conn_pref': '1'}
586 hapd
= hostapd
.add_ap(apdev
[0], params
)
587 bssid
= hapd
.own_addr()
589 dev
[0].scan_for_bss(bssid
, freq
="2412", force_scan
=True)
590 check_mbo_anqp(dev
[0], bssid
, 1)
592 hapd
.set('mbo_cell_data_conn_pref', '255')
593 check_mbo_anqp(dev
[0], bssid
, 255)
595 hapd
.set('mbo_cell_data_conn_pref', '-1')
596 check_mbo_anqp(dev
[0], bssid
, None)