1# Test cases for HT operations with hostapd 2# Copyright (c) 2013-2014, Jouni Malinen <j@w1.fi> 3# 4# This software may be distributed under the terms of the BSD license. 5# See README for more details. 6 7from remotehost import remote_compatible 8import time 9import logging 10logger = logging.getLogger() 11import struct 12 13import hostapd 14from wpasupplicant import WpaSupplicant 15from utils import * 16import hwsim_utils 17 18def test_ap_ht40_scan(dev, apdev): 19 """HT40 co-ex scan""" 20 clear_scan_cache(apdev[0]) 21 params = {"ssid": "test-ht40", 22 "channel": "5", 23 "ht_capab": "[HT40-]"} 24 hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False) 25 26 state = hapd.get_status_field("state") 27 if state != "HT_SCAN": 28 time.sleep(0.1) 29 state = hapd.get_status_field("state") 30 if state != "HT_SCAN": 31 raise Exception("Unexpected interface state - expected HT_SCAN") 32 33 ev = hapd.wait_event(["AP-ENABLED"], timeout=10) 34 if not ev: 35 raise Exception("AP setup timed out") 36 37 state = hapd.get_status_field("state") 38 if state != "ENABLED": 39 raise Exception("Unexpected interface state - expected ENABLED") 40 41 freq = hapd.get_status_field("freq") 42 if freq != "2432": 43 raise Exception("Unexpected frequency") 44 pri = hapd.get_status_field("channel") 45 if pri != "5": 46 raise Exception("Unexpected primary channel") 47 sec = hapd.get_status_field("secondary_channel") 48 if sec != "-1": 49 raise Exception("Unexpected secondary channel") 50 51 status = hapd.get_status() 52 logger.info("hostapd STATUS: " + str(status)) 53 54 dev[0].connect("test-ht40", key_mgmt="NONE", scan_freq=freq) 55 sta = hapd.get_sta(dev[0].own_addr()) 56 logger.info("hostapd STA: " + str(sta)) 57 58 res = dev[0].request("SIGNAL_POLL") 59 logger.info("STA SIGNAL_POLL:\n" + res.strip()) 60 sig = res.splitlines() 61 if "WIDTH=40 MHz" not in sig: 62 raise Exception("Not a 40 MHz connection") 63 64 if 'supp_op_classes' not in sta or len(sta['supp_op_classes']) < 2: 65 raise Exception("No Supported Operating Classes information for STA") 66 opclass = int(sta['supp_op_classes'][0:2], 16) 67 if opclass != 84: 68 raise Exception("Unexpected Current Operating Class from STA: %d" % opclass) 69 70def test_ap_ht_wifi_generation(dev, apdev): 71 """HT and wifi_generation""" 72 clear_scan_cache(apdev[0]) 73 params = {"ssid": "test-ht", 74 "channel": "6"} 75 hapd = hostapd.add_ap(apdev[0], params) 76 77 dev[0].connect("test-ht", key_mgmt="NONE", scan_freq="2437") 78 status = dev[0].get_status() 79 if 'wifi_generation' not in status: 80 # For now, assume this is because of missing kernel support 81 raise HwsimSkip("Association Request IE reporting not supported") 82 #raise Exception("Missing wifi_generation information") 83 if status['wifi_generation'] != "4": 84 raise Exception("Unexpected wifi_generation value: " + status['wifi_generation']) 85 86 wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5') 87 wpas.interface_add("wlan5", drv_params="force_connect_cmd=1") 88 wpas.connect("test-ht", key_mgmt="NONE", scan_freq="2437") 89 status = wpas.get_status() 90 if 'wifi_generation' not in status: 91 # For now, assume this is because of missing kernel support 92 raise HwsimSkip("Association Request IE reporting not supported") 93 #raise Exception("Missing wifi_generation information (connect)") 94 if status['wifi_generation'] != "4": 95 raise Exception("Unexpected wifi_generation value (connect): " + status['wifi_generation']) 96 97@remote_compatible 98def test_ap_ht40_scan_conflict(dev, apdev): 99 """HT40 co-ex scan conflict""" 100 clear_scan_cache(apdev[0]) 101 params = {"ssid": "test-ht40", 102 "channel": "6", 103 "ht_capab": "[HT40+]"} 104 hostapd.add_ap(apdev[1], params) 105 106 params = {"ssid": "test-ht40", 107 "channel": "5", 108 "ht_capab": "[HT40-]"} 109 hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False) 110 111 state = hapd.get_status_field("state") 112 if state != "HT_SCAN": 113 time.sleep(0.1) 114 state = hapd.get_status_field("state") 115 if state != "HT_SCAN": 116 raise Exception("Unexpected interface state - expected HT_SCAN") 117 118 ev = hapd.wait_event(["AP-ENABLED"], timeout=10) 119 if not ev: 120 raise Exception("AP setup timed out") 121 122 state = hapd.get_status_field("state") 123 if state != "ENABLED": 124 raise Exception("Unexpected interface state - expected ENABLED") 125 126 freq = hapd.get_status_field("freq") 127 if freq != "2432": 128 raise Exception("Unexpected frequency") 129 pri = hapd.get_status_field("channel") 130 if pri != "5": 131 raise Exception("Unexpected primary channel") 132 sec = hapd.get_status_field("secondary_channel") 133 if sec != "0": 134 raise Exception("Unexpected secondary channel: " + sec) 135 136 dev[0].connect("test-ht40", key_mgmt="NONE", scan_freq=freq) 137 138@remote_compatible 139def test_ap_ht40_scan_conflict2(dev, apdev): 140 """HT40 co-ex scan conflict (HT40-)""" 141 clear_scan_cache(apdev[0]) 142 params = {"ssid": "test-ht40", 143 "channel": "11", 144 "ht_capab": "[HT40-]"} 145 hostapd.add_ap(apdev[1], params) 146 147 params = {"ssid": "test-ht40", 148 "channel": "1", 149 "ht_capab": "[HT40+]"} 150 hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False) 151 152 state = hapd.get_status_field("state") 153 if state != "HT_SCAN": 154 time.sleep(0.1) 155 state = hapd.get_status_field("state") 156 if state != "HT_SCAN": 157 raise Exception("Unexpected interface state - expected HT_SCAN") 158 159 ev = hapd.wait_event(["AP-ENABLED"], timeout=10) 160 if not ev: 161 raise Exception("AP setup timed out") 162 163 state = hapd.get_status_field("state") 164 if state != "ENABLED": 165 raise Exception("Unexpected interface state - expected ENABLED") 166 167 freq = hapd.get_status_field("freq") 168 if freq != "2412": 169 raise Exception("Unexpected frequency") 170 pri = hapd.get_status_field("channel") 171 if pri != "1": 172 raise Exception("Unexpected primary channel") 173 sec = hapd.get_status_field("secondary_channel") 174 if sec != "0": 175 raise Exception("Unexpected secondary channel: " + sec) 176 177 dev[0].connect("test-ht40", key_mgmt="NONE", scan_freq=freq) 178 179def test_ap_ht40_scan_not_affected(dev, apdev): 180 """HT40 co-ex scan and other BSS not affected""" 181 clear_scan_cache(apdev[0]) 182 params = {"ssid": "test-ht20", 183 "channel": "11"} 184 hostapd.add_ap(apdev[1], params) 185 186 hostapd.cmd_execute(apdev[0], ['ifconfig', apdev[0]['ifname'], 'up']) 187 hostapd.cmd_execute(apdev[0], ['iw', apdev[0]['ifname'], 'scan', 'trigger', 188 'freq', '2462']) 189 time.sleep(0.5) 190 hostapd.cmd_execute(apdev[0], ['iw', apdev[0]['ifname'], 'scan', 'dump']) 191 time.sleep(0.1) 192 hostapd.cmd_execute(apdev[0], ['ifconfig', apdev[0]['ifname'], 'down']) 193 194 params = {"ssid": "test-ht40", 195 "channel": "1", 196 "ht_capab": "[HT40+]"} 197 hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False) 198 199 state = hapd.get_status_field("state") 200 if state != "HT_SCAN": 201 time.sleep(0.1) 202 state = hapd.get_status_field("state") 203 if state != "HT_SCAN": 204 raise Exception("Unexpected interface state - expected HT_SCAN") 205 206 ev = hapd.wait_event(["AP-ENABLED"], timeout=10) 207 if not ev: 208 raise Exception("AP setup timed out") 209 210 state = hapd.get_status_field("state") 211 if state != "ENABLED": 212 raise Exception("Unexpected interface state - expected ENABLED") 213 214 freq = hapd.get_status_field("freq") 215 if freq != "2412": 216 raise Exception("Unexpected frequency") 217 pri = hapd.get_status_field("channel") 218 if pri != "1": 219 raise Exception("Unexpected primary channel") 220 sec = hapd.get_status_field("secondary_channel") 221 if sec != "1": 222 raise Exception("Unexpected secondary channel: " + sec) 223 224 dev[0].connect("test-ht40", key_mgmt="NONE", scan_freq=freq) 225 226@remote_compatible 227def test_ap_ht40_scan_legacy_conflict(dev, apdev): 228 """HT40 co-ex scan conflict with legacy 20 MHz AP""" 229 clear_scan_cache(apdev[0]) 230 params = {"ssid": "legacy-20", 231 "channel": "7", "ieee80211n": "0"} 232 hostapd.add_ap(apdev[1], params) 233 234 params = {"ssid": "test-ht40", 235 "channel": "5", 236 "ht_capab": "[HT40-]"} 237 hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False) 238 239 state = hapd.get_status_field("state") 240 if state != "HT_SCAN": 241 time.sleep(0.1) 242 state = hapd.get_status_field("state") 243 if state != "HT_SCAN": 244 raise Exception("Unexpected interface state - expected HT_SCAN") 245 246 ev = hapd.wait_event(["AP-ENABLED"], timeout=10) 247 if not ev: 248 raise Exception("AP setup timed out") 249 250 state = hapd.get_status_field("state") 251 if state != "ENABLED": 252 raise Exception("Unexpected interface state - expected ENABLED") 253 254 freq = hapd.get_status_field("freq") 255 if freq != "2432": 256 raise Exception("Unexpected frequency: " + freq) 257 pri = hapd.get_status_field("channel") 258 if pri != "5": 259 raise Exception("Unexpected primary channel: " + pri) 260 sec = hapd.get_status_field("secondary_channel") 261 if sec != "0": 262 raise Exception("Unexpected secondary channel: " + sec) 263 264 dev[0].connect("test-ht40", key_mgmt="NONE", scan_freq=freq) 265 266@remote_compatible 267def test_ap_ht40_scan_ht20_conflict(dev, apdev): 268 """HT40 co-ex scan conflict with HT 20 MHz AP""" 269 clear_scan_cache(apdev[0]) 270 params = {"ssid": "ht-20", 271 "channel": "7", "ieee80211n": "1"} 272 hostapd.add_ap(apdev[1], params) 273 274 params = {"ssid": "test-ht40", 275 "channel": "5", 276 "ht_capab": "[HT40-]"} 277 hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False) 278 279 state = hapd.get_status_field("state") 280 if state != "HT_SCAN": 281 time.sleep(0.1) 282 state = hapd.get_status_field("state") 283 if state != "HT_SCAN": 284 raise Exception("Unexpected interface state - expected HT_SCAN") 285 286 ev = hapd.wait_event(["AP-ENABLED"], timeout=10) 287 if not ev: 288 raise Exception("AP setup timed out") 289 290 state = hapd.get_status_field("state") 291 if state != "ENABLED": 292 raise Exception("Unexpected interface state - expected ENABLED") 293 294 freq = hapd.get_status_field("freq") 295 if freq != "2432": 296 raise Exception("Unexpected frequency: " + freq) 297 pri = hapd.get_status_field("channel") 298 if pri != "5": 299 raise Exception("Unexpected primary channel: " + pri) 300 sec = hapd.get_status_field("secondary_channel") 301 if sec != "0": 302 raise Exception("Unexpected secondary channel: " + sec) 303 304 dev[0].connect("test-ht40", key_mgmt="NONE", scan_freq=freq) 305 306def test_ap_ht40_scan_intolerant(dev, apdev): 307 """HT40 co-ex scan finding an AP advertising 40 MHz intolerant""" 308 clear_scan_cache(apdev[0]) 309 params = {"ssid": "another-bss", 310 "channel": "1", 311 "ht_capab": "[40-INTOLERANT]"} 312 hostapd.add_ap(apdev[1], params) 313 314 params = {"ssid": "test-ht40", 315 "channel": "1", 316 "ht_capab": "[HT40+]"} 317 hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False) 318 319 state = hapd.get_status_field("state") 320 if state != "HT_SCAN": 321 time.sleep(0.1) 322 state = hapd.get_status_field("state") 323 if state != "HT_SCAN": 324 raise Exception("Unexpected interface state - expected HT_SCAN") 325 326 ev = hapd.wait_event(["AP-ENABLED"], timeout=10) 327 if not ev: 328 raise Exception("AP setup timed out") 329 330 state = hapd.get_status_field("state") 331 if state != "ENABLED": 332 raise Exception("Unexpected interface state - expected ENABLED") 333 334 freq = hapd.get_status_field("freq") 335 if freq != "2412": 336 raise Exception("Unexpected frequency: " + freq) 337 pri = hapd.get_status_field("channel") 338 if pri != "1": 339 raise Exception("Unexpected primary channel: " + pri) 340 sec = hapd.get_status_field("secondary_channel") 341 if sec != "0": 342 raise Exception("Unexpected secondary channel: " + sec) 343 344 dev[0].connect("test-ht40", key_mgmt="NONE", scan_freq=freq) 345 346def test_ap_ht40_scan_match(dev, apdev): 347 """HT40 co-ex scan matching configuration""" 348 clear_scan_cache(apdev[0]) 349 params = {"ssid": "test-ht40", 350 "channel": "5", 351 "ht_capab": "[HT40-]"} 352 hostapd.add_ap(apdev[1], params) 353 354 params = {"ssid": "test-ht40", 355 "channel": "5", 356 "ht_capab": "[HT40-]"} 357 hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False) 358 359 state = hapd.get_status_field("state") 360 if state != "HT_SCAN": 361 time.sleep(0.1) 362 state = hapd.get_status_field("state") 363 if state != "HT_SCAN": 364 raise Exception("Unexpected interface state - expected HT_SCAN") 365 366 ev = hapd.wait_event(["AP-ENABLED"], timeout=10) 367 if not ev: 368 raise Exception("AP setup timed out") 369 370 state = hapd.get_status_field("state") 371 if state != "ENABLED": 372 raise Exception("Unexpected interface state - expected ENABLED") 373 374 freq = hapd.get_status_field("freq") 375 if freq != "2432": 376 raise Exception("Unexpected frequency") 377 pri = hapd.get_status_field("channel") 378 if pri != "5": 379 raise Exception("Unexpected primary channel") 380 sec = hapd.get_status_field("secondary_channel") 381 if sec != "-1": 382 raise Exception("Unexpected secondary channel: " + sec) 383 384 dev[0].connect("test-ht40", key_mgmt="NONE", scan_freq=freq) 385 386def test_ap_ht40_5ghz_match(dev, apdev): 387 """HT40 co-ex scan on 5 GHz with matching pri/sec channel""" 388 clear_scan_cache(apdev[0]) 389 try: 390 hapd = None 391 hapd2 = None 392 params = {"ssid": "test-ht40", 393 "hw_mode": "a", 394 "channel": "36", 395 "country_code": "US", 396 "ht_capab": "[HT40+]"} 397 hapd2 = hostapd.add_ap(apdev[1], params) 398 399 params = {"ssid": "test-ht40", 400 "hw_mode": "a", 401 "channel": "36", 402 "ht_capab": "[HT40+]"} 403 hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False) 404 405 state = hapd.get_status_field("state") 406 if state != "HT_SCAN": 407 time.sleep(0.1) 408 state = hapd.get_status_field("state") 409 if state != "HT_SCAN": 410 raise Exception("Unexpected interface state - expected HT_SCAN") 411 412 ev = hapd.wait_event(["AP-ENABLED"], timeout=10) 413 if not ev: 414 raise Exception("AP setup timed out") 415 416 state = hapd.get_status_field("state") 417 if state != "ENABLED": 418 raise Exception("Unexpected interface state - expected ENABLED") 419 420 freq = hapd.get_status_field("freq") 421 if freq != "5180": 422 raise Exception("Unexpected frequency") 423 pri = hapd.get_status_field("channel") 424 if pri != "36": 425 raise Exception("Unexpected primary channel") 426 sec = hapd.get_status_field("secondary_channel") 427 if sec != "1": 428 raise Exception("Unexpected secondary channel: " + sec) 429 430 dev[0].connect("test-ht40", key_mgmt="NONE", scan_freq=freq) 431 finally: 432 dev[0].request("DISCONNECT") 433 if hapd: 434 hapd.request("DISABLE") 435 if hapd2: 436 hapd2.request("DISABLE") 437 set_world_reg(apdev[0], apdev[1], dev[0]) 438 dev[0].flush_scan_cache() 439 440def test_ap_ht40_5ghz_switch(dev, apdev): 441 """HT40 co-ex scan on 5 GHz switching pri/sec channel""" 442 clear_scan_cache(apdev[0]) 443 try: 444 hapd = None 445 hapd2 = None 446 params = {"ssid": "test-ht40", 447 "hw_mode": "a", 448 "channel": "36", 449 "country_code": "US", 450 "ht_capab": "[HT40+]"} 451 hapd2 = hostapd.add_ap(apdev[1], params) 452 453 params = {"ssid": "test-ht40", 454 "hw_mode": "a", 455 "channel": "40", 456 "ht_capab": "[HT40-]"} 457 hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False) 458 459 state = hapd.get_status_field("state") 460 if state != "HT_SCAN": 461 time.sleep(0.1) 462 state = hapd.get_status_field("state") 463 if state != "HT_SCAN": 464 raise Exception("Unexpected interface state - expected HT_SCAN") 465 466 ev = hapd.wait_event(["AP-ENABLED"], timeout=10) 467 if not ev: 468 raise Exception("AP setup timed out") 469 470 state = hapd.get_status_field("state") 471 if state != "ENABLED": 472 raise Exception("Unexpected interface state - expected ENABLED") 473 474 freq = hapd.get_status_field("freq") 475 if freq != "5180": 476 raise Exception("Unexpected frequency: " + freq) 477 pri = hapd.get_status_field("channel") 478 if pri != "36": 479 raise Exception("Unexpected primary channel: " + pri) 480 sec = hapd.get_status_field("secondary_channel") 481 if sec != "1": 482 raise Exception("Unexpected secondary channel: " + sec) 483 484 dev[0].connect("test-ht40", key_mgmt="NONE", scan_freq=freq) 485 finally: 486 dev[0].request("DISCONNECT") 487 if hapd: 488 hapd.request("DISABLE") 489 if hapd2: 490 hapd2.request("DISABLE") 491 set_world_reg(apdev[0], apdev[1], dev[0]) 492 493def test_ap_ht40_5ghz_switch2(dev, apdev): 494 """HT40 co-ex scan on 5 GHz switching pri/sec channel (2)""" 495 clear_scan_cache(apdev[0]) 496 try: 497 hapd = None 498 hapd2 = None 499 params = {"ssid": "test-ht40", 500 "hw_mode": "a", 501 "channel": "36", 502 "country_code": "US", 503 "ht_capab": "[HT40+]"} 504 hapd2 = hostapd.add_ap(apdev[1], params) 505 506 id = dev[0].add_network() 507 dev[0].set_network(id, "mode", "2") 508 dev[0].set_network_quoted(id, "ssid", "wpas-ap-open") 509 dev[0].set_network(id, "key_mgmt", "NONE") 510 dev[0].set_network(id, "frequency", "5200") 511 dev[0].set_network(id, "scan_freq", "5200") 512 dev[0].select_network(id) 513 time.sleep(1) 514 515 params = {"ssid": "test-ht40", 516 "hw_mode": "a", 517 "channel": "40", 518 "ht_capab": "[HT40-]"} 519 hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False) 520 521 state = hapd.get_status_field("state") 522 if state != "HT_SCAN": 523 time.sleep(0.1) 524 state = hapd.get_status_field("state") 525 if state != "HT_SCAN": 526 raise Exception("Unexpected interface state - expected HT_SCAN") 527 528 ev = hapd.wait_event(["AP-ENABLED"], timeout=10) 529 if not ev: 530 raise Exception("AP setup timed out") 531 532 state = hapd.get_status_field("state") 533 if state != "ENABLED": 534 raise Exception("Unexpected interface state - expected ENABLED") 535 536 freq = hapd.get_status_field("freq") 537 if freq != "5180": 538 raise Exception("Unexpected frequency: " + freq) 539 pri = hapd.get_status_field("channel") 540 if pri != "36": 541 raise Exception("Unexpected primary channel: " + pri) 542 sec = hapd.get_status_field("secondary_channel") 543 if sec != "1": 544 raise Exception("Unexpected secondary channel: " + sec) 545 546 dev[0].connect("test-ht40", key_mgmt="NONE", scan_freq=freq) 547 finally: 548 dev[0].request("DISCONNECT") 549 if hapd: 550 hapd.request("DISABLE") 551 if hapd2: 552 hapd2.request("DISABLE") 553 set_world_reg(apdev[0], apdev[1], dev[0]) 554 dev[0].flush_scan_cache() 555 556def test_obss_scan(dev, apdev): 557 """Overlapping BSS scan request""" 558 clear_scan_cache(apdev[0]) 559 params = {"ssid": "obss-scan", 560 "channel": "6", 561 "ht_capab": "[HT40-]", 562 "obss_interval": "10"} 563 hapd = hostapd.add_ap(apdev[0], params) 564 565 params = {"ssid": "another-bss", 566 "channel": "9", 567 "ieee80211n": "0"} 568 hostapd.add_ap(apdev[1], params) 569 run_obss_scan(hapd, dev) 570 571def test_obss_scan_ht40_plus(dev, apdev): 572 """Overlapping BSS scan request (HT40+)""" 573 clear_scan_cache(apdev[0]) 574 params = {"ssid": "obss-scan", 575 "channel": "6", 576 "ht_capab": "[HT40+]", 577 "obss_interval": "10"} 578 hapd = hostapd.add_ap(apdev[0], params) 579 580 params = {"ssid": "another-bss", 581 "channel": "9", 582 "ieee80211n": "0"} 583 hostapd.add_ap(apdev[1], params) 584 run_obss_scan(hapd, dev, ht40plus=True) 585 586def run_obss_scan(hapd, dev, ht40plus=False): 587 dev[0].connect("obss-scan", key_mgmt="NONE", scan_freq="2437") 588 res = dev[0].request("SIGNAL_POLL") 589 logger.info("SIGNAL_POLL:\n" + res) 590 sig = res.splitlines() 591 if "FREQUENCY=2437" not in sig: 592 raise Exception("Unexpected frequency") 593 if "WIDTH=40 MHz" not in sig: 594 raise Exception("Not a 40 MHz connection") 595 if ht40plus and "CENTER_FRQ1=2447" not in sig: 596 raise Exception("Not HT40+") 597 if not ht40plus and "CENTER_FRQ1=2427" not in sig: 598 raise Exception("Not HT40-") 599 hapd.set("ext_mgmt_frame_handling", "1") 600 logger.info("Waiting for OBSS scan to occur") 601 ev = dev[0].wait_event(["CTRL-EVENT-SCAN-STARTED"], timeout=15) 602 if ev is None: 603 raise Exception("Timed out while waiting for OBSS scan to start") 604 ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"], timeout=10) 605 if ev is None: 606 raise Exception("Timed out while waiting for OBSS scan results") 607 received = False 608 for i in range(0, 4): 609 frame = hapd.mgmt_rx(timeout=5) 610 if frame is None: 611 raise Exception("MGMT RX wait timed out") 612 if frame['subtype'] != 13: 613 continue 614 payload = frame['payload'] 615 if len(payload) < 3: 616 continue 617 (category, action, ie) = struct.unpack('BBB', payload[0:3]) 618 if category != 4: 619 continue 620 if action != 0: 621 continue 622 if ie == 72: 623 logger.info("20/40 BSS Coexistence report received") 624 received = True 625 break 626 if not received: 627 raise Exception("20/40 BSS Coexistence report not seen") 628 629def test_obss_scan_40_intolerant(dev, apdev): 630 """Overlapping BSS scan request with 40 MHz intolerant AP""" 631 params = {"ssid": "obss-scan", 632 "channel": "6", 633 "ht_capab": "[HT40-]", 634 "obss_interval": "10"} 635 hapd = hostapd.add_ap(apdev[0], params) 636 637 params = {"ssid": "another-bss", 638 "channel": "7", 639 "ht_capab": "[40-INTOLERANT]"} 640 hostapd.add_ap(apdev[1], params) 641 642 dev[0].connect("obss-scan", key_mgmt="NONE", scan_freq="2437") 643 hapd.set("ext_mgmt_frame_handling", "1") 644 logger.info("Waiting for OBSS scan to occur") 645 ev = dev[0].wait_event(["CTRL-EVENT-SCAN-STARTED"], timeout=15) 646 if ev is None: 647 raise Exception("Timed out while waiting for OBSS scan to start") 648 ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"], timeout=10) 649 if ev is None: 650 raise Exception("Timed out while waiting for OBSS scan results") 651 received = False 652 for i in range(0, 4): 653 frame = hapd.mgmt_rx(timeout=5) 654 if frame is None: 655 raise Exception("MGMT RX wait timed out") 656 if frame['subtype'] != 13: 657 continue 658 payload = frame['payload'] 659 if len(payload) < 3: 660 continue 661 (category, action, ie) = struct.unpack('BBB', payload[0:3]) 662 if category != 4: 663 continue 664 if action != 0: 665 continue 666 if ie == 72: 667 logger.info("20/40 BSS Coexistence report received") 668 received = True 669 break 670 if not received: 671 raise Exception("20/40 BSS Coexistence report not seen") 672 673def test_obss_coex_report_handling(dev, apdev): 674 """Overlapping BSS scan report handling with obss_interval=0""" 675 clear_scan_cache(apdev[0]) 676 params = {"ssid": "obss-scan", 677 "channel": "6", 678 "ht_capab": "[HT40-]"} 679 hapd = hostapd.add_ap(apdev[0], params) 680 bssid = apdev[0]['bssid'] 681 dev[0].connect("obss-scan", key_mgmt="NONE", scan_freq="2437") 682 683 sec = hapd.get_status_field("secondary_channel") 684 if sec != "-1": 685 raise Exception("AP is not using 40 MHz channel") 686 687 # 20/40 MHz co-ex report tests: number of invalid reports and a valid report 688 # that forces 20 MHz channel. 689 tests = ['0400', '040048', '04004801', '0400480000', '0400490100', 690 '040048ff0000', '04004801ff49ff00', '04004801004900', 691 '0400480100490101', '0400480100490201ff', 692 '040048010449020005'] 693 for msg in tests: 694 req = "MGMT_TX {} {} freq=2437 action={}".format(bssid, bssid, msg) 695 if "OK" not in dev[0].request(req): 696 raise Exception("Could not send management frame") 697 time.sleep(0.5) 698 sec = hapd.get_status_field("secondary_channel") 699 if sec != "0": 700 raise Exception("AP did not move to 20 MHz channel") 701 702def test_obss_coex_report_handling1(dev, apdev): 703 """Overlapping BSS scan report handling with obss_interval=1""" 704 clear_scan_cache(apdev[0]) 705 params = {"ssid": "obss-scan", 706 "channel": "6", 707 "ht_capab": "[HT40+]", 708 "obss_interval": "1"} 709 hapd = hostapd.add_ap(apdev[0], params) 710 bssid = apdev[0]['bssid'] 711 dev[0].connect("obss-scan", key_mgmt="NONE", scan_freq="2437") 712 713 sec = hapd.get_status_field("secondary_channel") 714 if sec != "1": 715 raise Exception("AP is not using 40 MHz channel") 716 717 # 20/40 MHz co-ex report forcing 20 MHz channel 718 msg = '040048010449020005' 719 req = "MGMT_TX {} {} freq=2437 action={}".format(bssid, bssid, msg) 720 if "OK" not in dev[0].request(req): 721 raise Exception("Could not send management frame") 722 time.sleep(0.5) 723 sec = hapd.get_status_field("secondary_channel") 724 if sec != "0": 725 raise Exception("AP did not move to 20 MHz channel") 726 727 # No 20/40 MHz co-ex reports forcing 20 MHz channel during next interval 728 for i in range(20): 729 sec = hapd.get_status_field("secondary_channel") 730 if sec == "1": 731 break 732 time.sleep(0.5) 733 if sec != "1": 734 raise Exception("AP did not return to 40 MHz channel") 735 736def test_obss_coex_report_handling2(dev, apdev): 737 """Overlapping BSS scan report handling with obss_interval=1 and no overlap""" 738 clear_scan_cache(apdev[0]) 739 params = {"ssid": "obss-scan", 740 "channel": "6", 741 "ht_capab": "[HT40+]", 742 "obss_interval": "1"} 743 hapd = hostapd.add_ap(apdev[0], params) 744 bssid = apdev[0]['bssid'] 745 dev[0].connect("obss-scan", key_mgmt="NONE", scan_freq="2437") 746 747 sec = hapd.get_status_field("secondary_channel") 748 if sec != "1": 749 raise Exception("AP is not using 40 MHz channel") 750 751 # 20/40 MHz co-ex report that does not force a move to 20 MHz channel 752 # (out of affected range and matching primary channel cases) 753 msg = '0400' + '480100' + '49020001' + '49020006' 754 req = "MGMT_TX {} {} freq=2437 action={}".format(bssid, bssid, msg) 755 if "OK" not in dev[0].request(req): 756 raise Exception("Could not send management frame") 757 time.sleep(0.5) 758 sec = hapd.get_status_field("secondary_channel") 759 if sec != "1": 760 raise Exception("Unexpected move to 20 MHz channel") 761 762 # 20/40 MHz co-ex report forcing 20 MHz channel 763 # (out of affected range and in affected range but not matching primary) 764 msg = '0400' + '480100' + '4903000105' 765 req = "MGMT_TX {} {} freq=2437 action={}".format(bssid, bssid, msg) 766 if "OK" not in dev[0].request(req): 767 raise Exception("Could not send management frame") 768 time.sleep(0.5) 769 sec = hapd.get_status_field("secondary_channel") 770 if sec != "0": 771 raise Exception("AP did not move to 20 MHz channel") 772 773def test_olbc(dev, apdev): 774 """OLBC detection""" 775 params = {"ssid": "test-olbc", 776 "channel": "6", 777 "ht_capab": "[HT40-]", 778 "ap_table_expiration_time": "2"} 779 hapd = hostapd.add_ap(apdev[0], params) 780 status = hapd.get_status() 781 if status['olbc'] != '0' or status['olbc_ht'] != '0': 782 raise Exception("Unexpected OLBC information") 783 784 params = {"ssid": "olbc-ap", 785 "hw_mode": "b", 786 "channel": "6", 787 "wmm_enabled": "0"} 788 hostapd.add_ap(apdev[1], params) 789 time.sleep(0.5) 790 status = hapd.get_status() 791 if status['olbc'] != '1' or status['olbc_ht'] != '1': 792 raise Exception("Missing OLBC information") 793 794 hostapd.remove_bss(apdev[1]) 795 796 logger.info("Waiting for OLBC state to time out") 797 cleared = False 798 for i in range(0, 15): 799 time.sleep(1) 800 status = hapd.get_status() 801 if status['olbc'] == '0' and status['olbc_ht'] == '0': 802 cleared = True 803 break 804 if not cleared: 805 raise Exception("OLBC state did nto time out") 806 807def test_olbc_table_limit(dev, apdev): 808 """OLBC AP table size limit""" 809 ifname1 = apdev[0]['ifname'] 810 ifname2 = apdev[0]['ifname'] + '-2' 811 ifname3 = apdev[0]['ifname'] + '-3' 812 hostapd.add_bss(apdev[0], ifname1, 'bss-1.conf') 813 hostapd.add_bss(apdev[0], ifname2, 'bss-2.conf') 814 hostapd.add_bss(apdev[0], ifname3, 'bss-3.conf') 815 816 params = {"ssid": "test-olbc", 817 "channel": "1", 818 "ap_table_max_size": "2"} 819 hapd = hostapd.add_ap(apdev[1], params) 820 821 time.sleep(0.3) 822 with alloc_fail(hapd, 1, "ap_list_process_beacon"): 823 time.sleep(0.3) 824 hapd.set("ap_table_max_size", "1") 825 time.sleep(0.3) 826 hapd.set("ap_table_max_size", "0") 827 time.sleep(0.3) 828 829def test_olbc_5ghz(dev, apdev): 830 """OLBC detection on 5 GHz""" 831 try: 832 hapd = None 833 hapd2 = None 834 params = {"ssid": "test-olbc", 835 "country_code": "FI", 836 "hw_mode": "a", 837 "channel": "36", 838 "ht_capab": "[HT40+]"} 839 hapd = hostapd.add_ap(apdev[0], params) 840 status = hapd.get_status() 841 if status['olbc'] != '0' or status['olbc_ht'] != '0': 842 raise Exception("Unexpected OLBC information") 843 844 params = {"ssid": "olbc-ap", 845 "country_code": "FI", 846 "hw_mode": "a", 847 "channel": "36", 848 "ieee80211n": "0", 849 "wmm_enabled": "0"} 850 hapd2 = hostapd.add_ap(apdev[1], params) 851 found = False 852 for i in range(20): 853 time.sleep(0.1) 854 status = hapd.get_status() 855 logger.debug('olbc_ht: ' + status['olbc_ht']) 856 if status['olbc_ht'] == '1': 857 found = True 858 break 859 if not found: 860 raise Exception("Missing OLBC information") 861 finally: 862 if hapd: 863 hapd.request("DISABLE") 864 if hapd2: 865 hapd2.request("DISABLE") 866 set_world_reg(apdev[0], apdev[1], None) 867 868def test_ap_require_ht(dev, apdev): 869 """Require HT""" 870 params = {"ssid": "require-ht", 871 "require_ht": "1"} 872 hapd = hostapd.add_ap(apdev[0], params) 873 874 dev[1].connect("require-ht", key_mgmt="NONE", scan_freq="2412", 875 disable_ht="1", wait_connect=False) 876 dev[0].connect("require-ht", key_mgmt="NONE", scan_freq="2412") 877 ev = dev[1].wait_event(["CTRL-EVENT-ASSOC-REJECT"]) 878 dev[1].request("DISCONNECT") 879 if ev is None: 880 raise Exception("Association rejection timed out") 881 if "status_code=27" not in ev: 882 raise Exception("Unexpected rejection status code") 883 dev[2].connect("require-ht", key_mgmt="NONE", scan_freq="2412", 884 ht_mcs="0x01 00 00 00 00 00 00 00 00 00", 885 disable_max_amsdu="1", ampdu_factor="2", 886 ampdu_density="1", disable_ht40="1", disable_sgi="1", 887 disable_ldpc="1", rx_stbc="2", tx_stbc="1") 888 889 sta = hapd.get_sta(dev[0].own_addr()) 890 if 'supp_op_classes' not in sta or len(sta['supp_op_classes']) < 2: 891 raise Exception("No Supported Operating Classes information for STA") 892 opclass = int(sta['supp_op_classes'][0:2], 16) 893 if opclass != 81: 894 raise Exception("Unexpected Current Operating Class from STA: %d" % opclass) 895 896def test_ap_ht_stbc(dev, apdev): 897 """HT STBC overrides""" 898 params = {"ssid": "ht"} 899 hapd = hostapd.add_ap(apdev[0], params) 900 901 dev[0].connect("ht", key_mgmt="NONE", scan_freq="2412") 902 dev[1].connect("ht", key_mgmt="NONE", scan_freq="2412", 903 rx_stbc="0", tx_stbc="0") 904 dev[2].connect("ht", key_mgmt="NONE", scan_freq="2412", 905 rx_stbc="1", tx_stbc="1") 906 907@remote_compatible 908def test_ap_require_ht_limited_rates(dev, apdev): 909 """Require HT with limited supported rates""" 910 params = {"ssid": "require-ht", 911 "supported_rates": "60 120 240 360 480 540", 912 "require_ht": "1"} 913 hapd = hostapd.add_ap(apdev[0], params) 914 915 dev[1].connect("require-ht", key_mgmt="NONE", scan_freq="2412", 916 disable_ht="1", wait_connect=False) 917 dev[0].connect("require-ht", key_mgmt="NONE", scan_freq="2412") 918 ev = dev[1].wait_event(["CTRL-EVENT-ASSOC-REJECT"]) 919 dev[1].request("DISCONNECT") 920 if ev is None: 921 raise Exception("Association rejection timed out") 922 if "status_code=27" not in ev: 923 raise Exception("Unexpected rejection status code") 924 925@remote_compatible 926def test_ap_ht_capab_not_supported(dev, apdev): 927 """HT configuration with driver not supporting all ht_capab entries""" 928 params = {"ssid": "test-ht40", 929 "channel": "5", 930 "ht_capab": "[HT40-][LDPC][SMPS-STATIC][SMPS-DYNAMIC][GF][SHORT-GI-20][SHORT-GI-40][TX-STBC][RX-STBC1][RX-STBC12][RX-STBC123][DELAYED-BA][MAX-AMSDU-7935][DSSS_CCK-40][LSIG-TXOP-PROT]"} 931 hapd = hostapd.add_ap(apdev[0], params, no_enable=True) 932 if "FAIL" not in hapd.request("ENABLE"): 933 raise Exception("Unexpected ENABLE success") 934 935def test_ap_ht_40mhz_intolerant_sta(dev, apdev): 936 """Associated STA indicating 40 MHz intolerant""" 937 clear_scan_cache(apdev[0]) 938 params = {"ssid": "intolerant", 939 "channel": "6", 940 "ht_capab": "[HT40-]"} 941 hapd = hostapd.add_ap(apdev[0], params) 942 if hapd.get_status_field("num_sta_ht40_intolerant") != "0": 943 raise Exception("Unexpected num_sta_ht40_intolerant value") 944 if hapd.get_status_field("secondary_channel") != "-1": 945 raise Exception("Unexpected secondary_channel") 946 947 dev[0].connect("intolerant", key_mgmt="NONE", scan_freq="2437") 948 if hapd.get_status_field("num_sta_ht40_intolerant") != "0": 949 raise Exception("Unexpected num_sta_ht40_intolerant value") 950 if hapd.get_status_field("secondary_channel") != "-1": 951 raise Exception("Unexpected secondary_channel") 952 953 dev[2].connect("intolerant", key_mgmt="NONE", scan_freq="2437", 954 ht40_intolerant="1") 955 time.sleep(1) 956 if hapd.get_status_field("num_sta_ht40_intolerant") != "1": 957 raise Exception("Unexpected num_sta_ht40_intolerant value (expected 1)") 958 if hapd.get_status_field("secondary_channel") != "0": 959 raise Exception("Unexpected secondary_channel (did not disable 40 MHz)") 960 961 dev[2].request("DISCONNECT") 962 time.sleep(1) 963 if hapd.get_status_field("num_sta_ht40_intolerant") != "0": 964 raise Exception("Unexpected num_sta_ht40_intolerant value (expected 0)") 965 if hapd.get_status_field("secondary_channel") != "-1": 966 raise Exception("Unexpected secondary_channel (did not re-enable 40 MHz)") 967 968def test_ap_ht_40mhz_intolerant_sta_deinit(dev, apdev): 969 """Associated STA indicating 40 MHz intolerant and hostapd deinit""" 970 clear_scan_cache(apdev[0]) 971 params = {"ssid": "intolerant", 972 "channel": "6", 973 "ht_capab": "[HT40-]", 974 "obss_interval": "0"} 975 hapd = hostapd.add_ap(apdev[0], params) 976 977 dev[0].connect("intolerant", key_mgmt="NONE", scan_freq="2437", 978 ht40_intolerant="1") 979 time.sleep(1) 980 if hapd.get_status_field("num_sta_ht40_intolerant") != "1": 981 raise Exception("Unexpected num_sta_ht40_intolerant value (expected 1)") 982 hglobal = hostapd.HostapdGlobal() 983 hglobal.remove(apdev[0]['ifname']) 984 985 dev[0].request("DISCONNECT") 986 987def test_ap_ht_40mhz_intolerant_ap(dev, apdev): 988 """Associated STA reports 40 MHz intolerant AP after association""" 989 clear_scan_cache(apdev[0]) 990 params = {"ssid": "ht", 991 "channel": "6", 992 "ht_capab": "[HT40-]", 993 "obss_interval": "3"} 994 hapd = hostapd.add_ap(apdev[0], params) 995 996 dev[0].connect("ht", key_mgmt="NONE", scan_freq="2437") 997 998 if hapd.get_status_field("secondary_channel") != "-1": 999 raise Exception("Unexpected secondary channel information") 1000 1001 logger.info("Start 40 MHz intolerant AP") 1002 params = {"ssid": "intolerant", 1003 "channel": "5", 1004 "ht_capab": "[40-INTOLERANT]"} 1005 hapd2 = hostapd.add_ap(apdev[1], params) 1006 1007 logger.info("Waiting for co-ex report from STA") 1008 ok = False 1009 for i in range(4): 1010 ev = dev[0].wait_event(['CTRL-EVENT-SCAN-RESULTS'], timeout=20) 1011 if ev is None: 1012 raise Exception("No OBSS scan seen") 1013 time.sleep(1) 1014 if hapd.get_status_field("secondary_channel") == "0": 1015 logger.info("AP moved to 20 MHz channel") 1016 ok = True 1017 break 1018 if not ok: 1019 raise Exception("AP did not move to 20 MHz channel") 1020 1021 if "OK" not in hapd2.request("DISABLE"): 1022 raise Exception("Failed to disable 40 MHz intolerant AP") 1023 1024 # make sure the intolerant AP disappears from scan results more quickly 1025 dev[0].scan(type="ONLY", freq="2432", only_new=True) 1026 dev[0].scan(type="ONLY", freq="2432", only_new=True) 1027 dev[0].dump_monitor() 1028 1029 logger.info("Waiting for AP to move back to 40 MHz channel") 1030 ok = False 1031 for i in range(0, 30): 1032 time.sleep(1) 1033 if hapd.get_status_field("secondary_channel") == "-1": 1034 logger.info("AP moved to 40 MHz channel") 1035 ok = True 1036 break 1037 if not ok: 1038 raise Exception("AP did not move to 40 MHz channel") 1039 1040def test_ap_ht40_csa(dev, apdev): 1041 """HT with 40 MHz channel width and CSA""" 1042 csa_supported(dev[0]) 1043 try: 1044 hapd = None 1045 params = {"ssid": "ht", 1046 "country_code": "US", 1047 "hw_mode": "a", 1048 "channel": "36", 1049 "ht_capab": "[HT40+]", 1050 "ieee80211n": "1"} 1051 hapd = hostapd.add_ap(apdev[0], params) 1052 1053 dev[0].connect("ht", key_mgmt="NONE", scan_freq="5180") 1054 hwsim_utils.test_connectivity(dev[0], hapd) 1055 1056 hapd.request("CHAN_SWITCH 5 5200 ht sec_channel_offset=-1 bandwidth=40") 1057 ev = hapd.wait_event(["AP-CSA-FINISHED"], timeout=10) 1058 if ev is None: 1059 raise Exception("CSA finished event timed out") 1060 if "freq=5200" not in ev: 1061 raise Exception("Unexpected channel in CSA finished event") 1062 ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=0.5) 1063 if ev is not None: 1064 raise Exception("Unexpected STA disconnection during CSA") 1065 hwsim_utils.test_connectivity(dev[0], hapd) 1066 1067 hapd.request("CHAN_SWITCH 5 5180 ht sec_channel_offset=1 bandwidth=40") 1068 ev = hapd.wait_event(["AP-CSA-FINISHED"], timeout=10) 1069 if ev is None: 1070 raise Exception("CSA finished event timed out") 1071 if "freq=5180" not in ev: 1072 raise Exception("Unexpected channel in CSA finished event") 1073 ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=0.5) 1074 if ev is not None: 1075 raise Exception("Unexpected STA disconnection during CSA") 1076 hwsim_utils.test_connectivity(dev[0], hapd) 1077 finally: 1078 dev[0].request("DISCONNECT") 1079 if hapd: 1080 hapd.request("DISABLE") 1081 set_world_reg(apdev[0], None, dev[0]) 1082 dev[0].flush_scan_cache() 1083 1084def test_ap_ht40_csa2(dev, apdev): 1085 """HT with 40 MHz channel width and CSA""" 1086 csa_supported(dev[0]) 1087 try: 1088 hapd = None 1089 params = {"ssid": "ht", 1090 "country_code": "US", 1091 "hw_mode": "a", 1092 "channel": "36", 1093 "ht_capab": "[HT40+]", 1094 "ieee80211n": "1"} 1095 hapd = hostapd.add_ap(apdev[0], params) 1096 1097 dev[0].connect("ht", key_mgmt="NONE", scan_freq="5180") 1098 hwsim_utils.test_connectivity(dev[0], hapd) 1099 1100 hapd.request("CHAN_SWITCH 5 5220 ht sec_channel_offset=1 bandwidth=40") 1101 ev = hapd.wait_event(["AP-CSA-FINISHED"], timeout=10) 1102 if ev is None: 1103 raise Exception("CSA finished event timed out") 1104 if "freq=5220" not in ev: 1105 raise Exception("Unexpected channel in CSA finished event") 1106 ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=0.5) 1107 if ev is not None: 1108 raise Exception("Unexpected STA disconnection during CSA") 1109 hwsim_utils.test_connectivity(dev[0], hapd) 1110 1111 hapd.request("CHAN_SWITCH 5 5180 ht sec_channel_offset=1 bandwidth=40") 1112 ev = hapd.wait_event(["AP-CSA-FINISHED"], timeout=10) 1113 if ev is None: 1114 raise Exception("CSA finished event timed out") 1115 if "freq=5180" not in ev: 1116 raise Exception("Unexpected channel in CSA finished event") 1117 ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=0.5) 1118 if ev is not None: 1119 raise Exception("Unexpected STA disconnection during CSA") 1120 hwsim_utils.test_connectivity(dev[0], hapd) 1121 finally: 1122 dev[0].request("DISCONNECT") 1123 if hapd: 1124 hapd.request("DISABLE") 1125 set_world_reg(apdev[0], None, dev[0]) 1126 dev[0].flush_scan_cache() 1127 1128def test_ap_ht40_csa3(dev, apdev): 1129 """HT with 40 MHz channel width and CSA""" 1130 csa_supported(dev[0]) 1131 try: 1132 hapd = None 1133 params = {"ssid": "ht", 1134 "country_code": "US", 1135 "hw_mode": "a", 1136 "channel": "36", 1137 "ht_capab": "[HT40+]", 1138 "ieee80211n": "1"} 1139 hapd = hostapd.add_ap(apdev[0], params) 1140 1141 dev[0].connect("ht", key_mgmt="NONE", scan_freq="5180") 1142 hwsim_utils.test_connectivity(dev[0], hapd) 1143 1144 hapd.request("CHAN_SWITCH 5 5240 ht sec_channel_offset=-1 bandwidth=40") 1145 ev = hapd.wait_event(["AP-CSA-FINISHED"], timeout=10) 1146 if ev is None: 1147 raise Exception("CSA finished event timed out") 1148 if "freq=5240" not in ev: 1149 raise Exception("Unexpected channel in CSA finished event") 1150 ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=0.5) 1151 if ev is not None: 1152 raise Exception("Unexpected STA disconnection during CSA") 1153 hwsim_utils.test_connectivity(dev[0], hapd) 1154 1155 hapd.request("CHAN_SWITCH 5 5180 ht sec_channel_offset=1 bandwidth=40") 1156 ev = hapd.wait_event(["AP-CSA-FINISHED"], timeout=10) 1157 if ev is None: 1158 raise Exception("CSA finished event timed out") 1159 if "freq=5180" not in ev: 1160 raise Exception("Unexpected channel in CSA finished event") 1161 ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=0.5) 1162 if ev is not None: 1163 raise Exception("Unexpected STA disconnection during CSA") 1164 hwsim_utils.test_connectivity(dev[0], hapd) 1165 finally: 1166 dev[0].request("DISCONNECT") 1167 if hapd: 1168 hapd.request("DISABLE") 1169 set_world_reg(apdev[0], None, dev[0]) 1170 dev[0].flush_scan_cache() 1171 1172def test_ap_ht_20_to_40_csa(dev, apdev): 1173 """HT with 20 MHz channel width doing CSA to 40 MHz""" 1174 csa_supported(dev[0]) 1175 1176 params = {"ssid": "ht", 1177 "channel": "1", 1178 "ieee80211n": "1"} 1179 hapd = hostapd.add_ap(apdev[0], params) 1180 1181 dev[0].connect("ht", key_mgmt="NONE", scan_freq="2412") 1182 hapd.wait_sta() 1183 res = dev[0].request("SIGNAL_POLL") 1184 logger.info("SIGNAL_POLL:\n" + res) 1185 sig = res.splitlines() 1186 if 'WIDTH=20 MHz' not in sig: 1187 raise Exception("20 MHz channel bandwidth not used on the original channel") 1188 1189 hapd.request("CHAN_SWITCH 5 2462 ht sec_channel_offset=-1 bandwidth=40") 1190 ev = hapd.wait_event(["AP-CSA-FINISHED"], timeout=10) 1191 if ev is None: 1192 raise Exception("CSA finished event timed out") 1193 if "freq=2462" not in ev: 1194 raise Exception("Unexpected channel in CSA finished event") 1195 ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=0.5) 1196 if ev is not None: 1197 raise Exception("Unexpected STA disconnection during CSA") 1198 res = dev[0].request("SIGNAL_POLL") 1199 logger.info("SIGNAL_POLL:\n" + res) 1200 sig = res.splitlines() 1201 if 'WIDTH=40 MHz' not in sig: 1202 raise Exception("40 MHz channel bandwidth not used on the new channel") 1203 1204@remote_compatible 1205def test_prefer_ht20(dev, apdev): 1206 """Preference on HT20 over no-HT""" 1207 params = {"ssid": "test", 1208 "channel": "1", 1209 "ieee80211n": "0"} 1210 hapd = hostapd.add_ap(apdev[0], params) 1211 bssid = apdev[0]['bssid'] 1212 params = {"ssid": "test", 1213 "channel": "1", 1214 "ieee80211n": "1"} 1215 hapd2 = hostapd.add_ap(apdev[1], params) 1216 bssid2 = apdev[1]['bssid'] 1217 1218 dev[0].scan_for_bss(bssid, freq=2412) 1219 dev[0].scan_for_bss(bssid2, freq=2412) 1220 dev[0].connect("test", key_mgmt="NONE", scan_freq="2412") 1221 if dev[0].get_status_field('bssid') != bssid2: 1222 raise Exception("Unexpected BSS selected") 1223 1224 est = dev[0].get_bss(bssid)['est_throughput'] 1225 if est != "54000": 1226 raise Exception("Unexpected BSS0 est_throughput: " + est) 1227 1228 est = dev[0].get_bss(bssid2)['est_throughput'] 1229 if est != "65000": 1230 raise Exception("Unexpected BSS1 est_throughput: " + est) 1231 1232def test_prefer_ht40(dev, apdev): 1233 """Preference on HT40 over HT20""" 1234 params = {"ssid": "test", 1235 "channel": "1", 1236 "ieee80211n": "1"} 1237 hapd = hostapd.add_ap(apdev[0], params) 1238 bssid = apdev[0]['bssid'] 1239 params = {"ssid": "test", 1240 "channel": "1", 1241 "ieee80211n": "1", 1242 "ht_capab": "[HT40+]"} 1243 hapd2 = hostapd.add_ap(apdev[1], params) 1244 bssid2 = apdev[1]['bssid'] 1245 1246 dev[0].scan_for_bss(bssid, freq=2412) 1247 dev[0].scan_for_bss(bssid2, freq=2412) 1248 dev[0].connect("test", key_mgmt="NONE", scan_freq="2412") 1249 if dev[0].get_status_field('bssid') != bssid2: 1250 raise Exception("Unexpected BSS selected") 1251 1252 est = dev[0].get_bss(bssid)['est_throughput'] 1253 if est != "65000": 1254 raise Exception("Unexpected BSS0 est_throughput: " + est) 1255 1256 est = dev[0].get_bss(bssid2)['est_throughput'] 1257 if est != "135000": 1258 raise Exception("Unexpected BSS1 est_throughput: " + est) 1259 1260@remote_compatible 1261def test_prefer_ht20_during_roam(dev, apdev): 1262 """Preference on HT20 over no-HT in roaming consideration""" 1263 params = {"ssid": "test", 1264 "channel": "1", 1265 "ieee80211n": "0"} 1266 hapd = hostapd.add_ap(apdev[0], params) 1267 bssid = apdev[0]['bssid'] 1268 1269 dev[0].scan_for_bss(bssid, freq=2412) 1270 dev[0].connect("test", key_mgmt="NONE", scan_freq="2412") 1271 1272 params = {"ssid": "test", 1273 "channel": "1", 1274 "ieee80211n": "1"} 1275 hapd2 = hostapd.add_ap(apdev[1], params) 1276 bssid2 = apdev[1]['bssid'] 1277 dev[0].scan_for_bss(bssid2, freq=2412) 1278 dev[0].scan(freq=2412) 1279 dev[0].wait_connected() 1280 1281 if dev[0].get_status_field('bssid') != bssid2: 1282 raise Exception("Unexpected BSS selected") 1283 1284@remote_compatible 1285def test_ap_ht40_5ghz_invalid_pair(dev, apdev): 1286 """HT40 on 5 GHz with invalid channel pair""" 1287 clear_scan_cache(apdev[0]) 1288 try: 1289 params = {"ssid": "test-ht40", 1290 "hw_mode": "a", 1291 "channel": "40", 1292 "country_code": "US", 1293 "ht_capab": "[HT40+]"} 1294 hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False) 1295 ev = hapd.wait_event(["AP-DISABLED", "AP-ENABLED"], timeout=10) 1296 if not ev: 1297 raise Exception("AP setup failure timed out") 1298 if "AP-ENABLED" in ev: 1299 sec = hapd.get_status_field("secondary_channel") 1300 if sec != "0": 1301 raise Exception("Invalid 40 MHz channel accepted") 1302 finally: 1303 clear_regdom(hapd, dev) 1304 1305@remote_compatible 1306def test_ap_ht40_5ghz_disabled_sec(dev, apdev): 1307 """HT40 on 5 GHz with disabled secondary channel""" 1308 clear_scan_cache(apdev[0]) 1309 try: 1310 params = {"ssid": "test-ht40", 1311 "hw_mode": "a", 1312 "channel": "48", 1313 "country_code": "US", 1314 "ht_capab": "[HT40+]"} 1315 hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False) 1316 ev = hapd.wait_event(["AP-DISABLED", "AP-ENABLED"], timeout=10) 1317 if not ev: 1318 raise Exception("AP setup failure timed out") 1319 if "AP-ENABLED" in ev: 1320 sec = hapd.get_status_field("secondary_channel") 1321 if sec != "0": 1322 raise Exception("Invalid 40 MHz channel accepted") 1323 finally: 1324 clear_regdom(hapd, dev) 1325 1326def test_ap_ht40_scan_broken_ap(dev, apdev): 1327 """HT40 co-ex scan and broken legacy/HT AP""" 1328 clear_scan_cache(apdev[0]) 1329 1330 # Broken AP: Include HT Capabilities element but not HT Operation element 1331 params = {"ssid": "legacy-20", 1332 "channel": "7", "ieee80211n": "0", 1333 "wmm_enabled": "1", 1334 "vendor_elements": "2d1a0e001bffff000000000000000000000100000000000000000000"} 1335 hapd2 = hostapd.add_ap(apdev[1], params) 1336 1337 params = {"ssid": "test-ht40", 1338 "channel": "5", 1339 "ht_capab": "[HT40-]"} 1340 hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False) 1341 1342 state = hapd.get_status_field("state") 1343 if state != "HT_SCAN": 1344 time.sleep(0.1) 1345 state = hapd.get_status_field("state") 1346 if state != "HT_SCAN": 1347 raise Exception("Unexpected interface state - expected HT_SCAN") 1348 1349 ev = hapd.wait_event(["AP-ENABLED"], timeout=10) 1350 if not ev: 1351 raise Exception("AP setup timed out") 1352 1353 state = hapd.get_status_field("state") 1354 if state != "ENABLED": 1355 raise Exception("Unexpected interface state - expected ENABLED") 1356 1357 freq = hapd.get_status_field("freq") 1358 if freq != "2432": 1359 raise Exception("Unexpected frequency: " + freq) 1360 pri = hapd.get_status_field("channel") 1361 if pri != "5": 1362 raise Exception("Unexpected primary channel: " + pri) 1363 sec = hapd.get_status_field("secondary_channel") 1364 if sec != "-1": 1365 raise Exception("Unexpected secondary channel: " + sec) 1366 1367 dev[0].connect("test-ht40", key_mgmt="NONE", scan_freq=freq) 1368 dev[1].connect("legacy-20", key_mgmt="NONE", scan_freq="2442") 1369 hwsim_utils.test_connectivity(dev[0], hapd) 1370 hwsim_utils.test_connectivity(dev[1], hapd2) 1371 1372def run_op_class(dev, apdev, hw_mode, channel, country, ht_capab, sec_chan, 1373 freq, opclass, use_op_class=False): 1374 clear_scan_cache(apdev[0]) 1375 try: 1376 params = {"ssid": "test-ht40", 1377 "hw_mode": hw_mode, 1378 "channel": channel, 1379 "ht_capab": ht_capab} 1380 if use_op_class: 1381 params['op_class'] = str(opclass) 1382 if country: 1383 params['country_code'] = country 1384 hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False) 1385 ev = hapd.wait_event(["AP-DISABLED", "AP-ENABLED"], timeout=10) 1386 if not ev: 1387 raise Exception("AP setup failure timed out") 1388 if "AP-DISABLED" in ev: 1389 raise HwsimSkip("Channel not supported") 1390 sec = hapd.get_status_field("secondary_channel") 1391 if sec != sec_chan: 1392 raise Exception("Unexpected secondary_channel: " + sec) 1393 dev[0].connect("test-ht40", key_mgmt="NONE", scan_freq=freq) 1394 bss = dev[0].get_bss(hapd.own_addr()) 1395 ie = parse_ie(bss['ie']) 1396 if 59 not in ie: 1397 raise Exception("Missing Supported Operating Classes element") 1398 rx_opclass, = struct.unpack('B', ie[59][0:1]) 1399 if rx_opclass != opclass: 1400 raise Exception("Unexpected operating class: %d" % rx_opclass) 1401 hapd.disable() 1402 hapd.dump_monitor() 1403 dev[0].request("REMOVE_NETWORK all") 1404 dev[0].request("ABORT_SCAN") 1405 dev[0].wait_disconnected() 1406 dev[0].dump_monitor() 1407 finally: 1408 set_world_reg(apdev[0], None, dev[0]) 1409 time.sleep(0.1) 1410 1411def test_ap_ht_op_class_81(dev, apdev): 1412 """HT20 on operating class 81""" 1413 for o in [False, True]: 1414 run_op_class(dev, apdev, "g", "1", None, "", "0", "2412", 81, 1415 use_op_class=o) 1416 1417def test_ap_ht_op_class_83(dev, apdev): 1418 """HT40 on operating class 83""" 1419 for o in [False, True]: 1420 run_op_class(dev, apdev, "g", "1", None, "[HT40+]", "1", "2412", 83, 1421 use_op_class=o) 1422 1423def test_ap_ht_op_class_84(dev, apdev): 1424 """HT40 on operating class 84""" 1425 for o in [False, True]: 1426 run_op_class(dev, apdev, "g", "11", None, "[HT40-]", "-1", "2462", 84, 1427 use_op_class=o) 1428 1429def test_ap_ht_op_class_115(dev, apdev): 1430 """HT20 on operating class 115""" 1431 for o in [False, True]: 1432 run_op_class(dev, apdev, "a", "36", "FI", "", "0", "5180", 115, 1433 use_op_class=o) 1434 1435def test_ap_ht_op_class_116(dev, apdev): 1436 """HT40 on operating class 116""" 1437 for o in [False, True]: 1438 run_op_class(dev, apdev, "a", "36", "FI", "[HT40+]", "1", "5180", 116, 1439 use_op_class=o) 1440 1441def test_ap_ht_op_class_117(dev, apdev): 1442 """HT40 on operating class 117""" 1443 for o in [False, True]: 1444 run_op_class(dev, apdev, "a", "40", "FI", "[HT40-]", "-1", "5200", 117, 1445 use_op_class=o) 1446 1447def test_ap_ht_op_class_118(dev, apdev): 1448 """HT20 on operating class 118""" 1449 for o in [False, True]: 1450 run_op_class(dev, apdev, "a", "60", "PA", "", "0", "5300", 118, 1451 use_op_class=o) 1452 1453def test_ap_ht_op_class_119(dev, apdev): 1454 """HT40 on operating class 119""" 1455 for o in [False, True]: 1456 run_op_class(dev, apdev, "a", "60", "PA", "[HT40+]", "1", "5300", 119, 1457 use_op_class=o) 1458 1459def test_ap_ht_op_class_120(dev, apdev): 1460 """HT40 on operating class 120""" 1461 for o in [False, True]: 1462 run_op_class(dev, apdev, "a", "64", "PA", "[HT40-]", "-1", "5320", 120, 1463 use_op_class=o) 1464 1465def test_ap_ht_op_class_121(dev, apdev): 1466 """HT20 on operating class 121""" 1467 for o in [False, True]: 1468 run_op_class(dev, apdev, "a", "100", "ZA", "", "0", "5500", 121, 1469 use_op_class=o) 1470 1471def test_ap_ht_op_class_122(dev, apdev): 1472 """HT40 on operating class 122""" 1473 for o in [False, True]: 1474 run_op_class(dev, apdev, "a", "100", "ZA", "[HT40+]", "1", "5500", 122, 1475 use_op_class=o) 1476 1477def test_ap_ht_op_class_123(dev, apdev): 1478 """HT40 on operating class 123""" 1479 for o in [False, True]: 1480 run_op_class(dev, apdev, "a", "104", "ZA", "[HT40-]", "-1", "5520", 123, 1481 use_op_class=o) 1482 1483def test_ap_ht_op_class_125_chan149(dev, apdev): 1484 """HT20 on operating class 125 with channel 149""" 1485 for o in [False, True]: 1486 run_op_class(dev, apdev, "a", "149", "US", "", "0", "5745", 125, 1487 use_op_class=o) 1488 1489def test_ap_ht_op_class_125(dev, apdev): 1490 """HT20 on operating class 125""" 1491 for o in [False, True]: 1492 run_op_class(dev, apdev, "a", "169", "NL", "", "0", "5845", 125, 1493 use_op_class=o) 1494 1495def test_ap_ht_op_class_126(dev, apdev): 1496 """HT40 on operating class 126""" 1497 for o in [False, True]: 1498 run_op_class(dev, apdev, "a", "149", "US", "[HT40+]", "1", "5745", 126, 1499 use_op_class=o) 1500 1501def test_ap_ht_op_class_127(dev, apdev): 1502 """HT40 on operating class 127""" 1503 for o in [False, True]: 1504 run_op_class(dev, apdev, "a", "153", "US", "[HT40-]", "-1", "5765", 127, 1505 use_op_class=o) 1506 1507def test_ap_ht40_plus_minus1(dev, apdev): 1508 """HT40 with both plus and minus allowed (1)""" 1509 clear_scan_cache(apdev[0]) 1510 params = {"ssid": "test-ht40", 1511 "channel": "11", 1512 "ht_capab": "[HT40+][HT40-]"} 1513 hapd = hostapd.add_ap(apdev[0], params) 1514 1515 freq = hapd.get_status_field("freq") 1516 if freq != "2462": 1517 raise Exception("Unexpected frequency: " + freq) 1518 pri = hapd.get_status_field("channel") 1519 if pri != "11": 1520 raise Exception("Unexpected primary channel: " + pri) 1521 sec = hapd.get_status_field("secondary_channel") 1522 if sec != "-1": 1523 raise Exception("Unexpected secondary channel: " + sec) 1524 1525 dev[0].connect("test-ht40", key_mgmt="NONE", scan_freq=freq) 1526 1527def test_ap_ht40_plus_minus2(dev, apdev): 1528 """HT40 with both plus and minus allowed (2)""" 1529 clear_scan_cache(apdev[0]) 1530 params = {"ssid": "test-ht40", 1531 "channel": "1", 1532 "ht_capab": "[HT40+][HT40-]"} 1533 hapd = hostapd.add_ap(apdev[0], params) 1534 1535 freq = hapd.get_status_field("freq") 1536 if freq != "2412": 1537 raise Exception("Unexpected frequency: " + freq) 1538 pri = hapd.get_status_field("channel") 1539 if pri != "1": 1540 raise Exception("Unexpected primary channel: " + pri) 1541 sec = hapd.get_status_field("secondary_channel") 1542 if sec != "1": 1543 raise Exception("Unexpected secondary channel: " + sec) 1544 1545 dev[0].connect("test-ht40", key_mgmt="NONE", scan_freq=freq) 1546 1547def test_ap_ht40_disable(dev, apdev): 1548 """HT40 disabling""" 1549 clear_scan_cache(apdev[0]) 1550 params = {"ssid": "test-ht40", 1551 "channel": "6", 1552 "ht_capab": "[HT40-]"} 1553 hapd = hostapd.add_ap(apdev[0], params) 1554 1555 sec = hapd.get_status_field("secondary_channel") 1556 if sec != "-1": 1557 raise Exception("Unexpected secondary channel: " + sec) 1558 1559 id = dev[0].connect("test-ht40", key_mgmt="NONE", scan_freq="2437") 1560 sig = dev[0].request("SIGNAL_POLL").splitlines() 1561 logger.info("SIGNAL_POLL: " + str(sig)) 1562 if "WIDTH=40 MHz" not in sig: 1563 raise Exception("Station did not report 40 MHz bandwidth") 1564 dev[0].request("DISCONNECT") 1565 dev[0].wait_disconnected() 1566 1567 hapd.disable() 1568 hapd.set("ht_capab", "") 1569 hapd.enable() 1570 sec = hapd.get_status_field("secondary_channel") 1571 if sec != "0": 1572 raise Exception("Unexpected secondary channel(2): " + sec) 1573 1574 dev[0].flush_scan_cache() 1575 dev[0].select_network(id, freq=2437) 1576 dev[0].wait_connected() 1577 sig = dev[0].request("SIGNAL_POLL").splitlines() 1578 logger.info("SIGNAL_POLL: " + str(sig)) 1579 if "WIDTH=20 MHz" not in sig: 1580 raise Exception("Station did not report 20 MHz bandwidth") 1581 1582def test_ap_ht_wmm_etsi(dev, apdev): 1583 """HT and WMM contents in ETSI""" 1584 run_ap_ht_wmm(dev, apdev, "FI") 1585 1586def test_ap_ht_wmm_fcc(dev, apdev): 1587 """HT and WMM contents in FCC""" 1588 run_ap_ht_wmm(dev, apdev, "US") 1589 1590def run_ap_ht_wmm(dev, apdev, country): 1591 clear_scan_cache(apdev[0]) 1592 try: 1593 hapd = None 1594 params = {"ssid": "test", 1595 "hw_mode": "a", 1596 "channel": "36", 1597 "country_code": country} 1598 hapd = hostapd.add_ap(apdev[0], params) 1599 freq = hapd.get_status_field("freq") 1600 bssid = hapd.own_addr() 1601 dev[0].connect("test", key_mgmt="NONE", scan_freq=freq) 1602 bss = dev[0].get_bss(bssid) 1603 ie = parse_ie(bss['ie']) 1604 if 221 not in ie: 1605 raise Exception("Could not find WMM IE") 1606 wmm = ie[221] 1607 if len(wmm) != 24: 1608 raise Exception("Unexpected WMM IE length") 1609 id, subtype, version, info, reserved = struct.unpack('>LBBBB', wmm[0:8]) 1610 if id != 0x0050f202 or subtype != 1 or version != 1: 1611 raise Exception("Not a WMM IE") 1612 ac = [] 1613 for i in range(4): 1614 ac.append(struct.unpack('<BBH', wmm[8 + i * 4: 12 + i * 4])) 1615 logger.info("WMM AC info: " + str(ac)) 1616 1617 aifsn = (ac[0][0] & 0x0f, ac[1][0] & 0x0f, 1618 ac[2][0] & 0x0f, ac[3][0] & 0x0f) 1619 logger.info("AIFSN: " + str(aifsn)) 1620 if aifsn != (3, 7, 2, 2): 1621 raise Exception("Unexpected AIFSN value: " + str(aifsn)) 1622 1623 ecw_min = (ac[0][1] & 0x0f, ac[1][1] & 0x0f, 1624 ac[2][1] & 0x0f, ac[3][1] & 0x0f) 1625 logger.info("ECW min: " + str(ecw_min)) 1626 if ecw_min != (4, 4, 3, 2): 1627 raise Exception("Unexpected ECW min value: " + str(ecw_min)) 1628 1629 ecw_max = ((ac[0][1] & 0xf0) >> 4, (ac[1][1] & 0xf0) >> 4, 1630 (ac[2][1] & 0xf0) >> 4, (ac[3][1] & 0xf0) >> 4) 1631 logger.info("ECW max: " + str(ecw_max)) 1632 if ecw_max != (10, 10, 4, 3): 1633 raise Exception("Unexpected ECW max value: " + str(ecw_max)) 1634 1635 txop = (ac[0][2], ac[1][2], ac[2][2], ac[3][2]) 1636 logger.info("TXOP: " + str(txop)) 1637 if txop != (0, 0, 94, 47): 1638 raise Exception("Unexpected TXOP value: " + str(txop)) 1639 finally: 1640 dev[0].request("DISCONNECT") 1641 if hapd: 1642 hapd.request("DISABLE") 1643 set_world_reg(apdev[0], None, dev[0]) 1644 dev[0].flush_scan_cache() 1645