test_ap_ht.py 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001
  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. import time
  7. import logging
  8. logger = logging.getLogger()
  9. import struct
  10. import subprocess
  11. import hostapd
  12. from utils import HwsimSkip, alloc_fail
  13. import hwsim_utils
  14. from test_ap_csa import csa_supported
  15. def clear_scan_cache(ifname):
  16. subprocess.call(['ifconfig', ifname, 'up'])
  17. subprocess.call(['iw', ifname, 'scan', 'freq', '2412', 'flush'])
  18. time.sleep(0.1)
  19. subprocess.call(['ifconfig', ifname, 'down'])
  20. def test_ap_ht40_scan(dev, apdev):
  21. """HT40 co-ex scan"""
  22. clear_scan_cache(apdev[0]['ifname'])
  23. params = { "ssid": "test-ht40",
  24. "channel": "5",
  25. "ht_capab": "[HT40-]"}
  26. hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
  27. state = hapd.get_status_field("state")
  28. if state != "HT_SCAN":
  29. time.sleep(0.1)
  30. state = hapd.get_status_field("state")
  31. if state != "HT_SCAN":
  32. raise Exception("Unexpected interface state - expected HT_SCAN")
  33. ev = hapd.wait_event(["AP-ENABLED"], timeout=10)
  34. if not ev:
  35. raise Exception("AP setup timed out")
  36. state = hapd.get_status_field("state")
  37. if state != "ENABLED":
  38. raise Exception("Unexpected interface state - expected ENABLED")
  39. freq = hapd.get_status_field("freq")
  40. if freq != "2432":
  41. raise Exception("Unexpected frequency")
  42. pri = hapd.get_status_field("channel")
  43. if pri != "5":
  44. raise Exception("Unexpected primary channel")
  45. sec = hapd.get_status_field("secondary_channel")
  46. if sec != "-1":
  47. raise Exception("Unexpected secondary channel")
  48. dev[0].connect("test-ht40", key_mgmt="NONE", scan_freq=freq)
  49. def test_ap_ht40_scan_conflict(dev, apdev):
  50. """HT40 co-ex scan conflict"""
  51. clear_scan_cache(apdev[0]['ifname'])
  52. params = { "ssid": "test-ht40",
  53. "channel": "6",
  54. "ht_capab": "[HT40+]"}
  55. hostapd.add_ap(apdev[1]['ifname'], params)
  56. params = { "ssid": "test-ht40",
  57. "channel": "5",
  58. "ht_capab": "[HT40-]"}
  59. hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
  60. state = hapd.get_status_field("state")
  61. if state != "HT_SCAN":
  62. time.sleep(0.1)
  63. state = hapd.get_status_field("state")
  64. if state != "HT_SCAN":
  65. raise Exception("Unexpected interface state - expected HT_SCAN")
  66. ev = hapd.wait_event(["AP-ENABLED"], timeout=10)
  67. if not ev:
  68. raise Exception("AP setup timed out")
  69. state = hapd.get_status_field("state")
  70. if state != "ENABLED":
  71. raise Exception("Unexpected interface state - expected ENABLED")
  72. freq = hapd.get_status_field("freq")
  73. if freq != "2432":
  74. raise Exception("Unexpected frequency")
  75. pri = hapd.get_status_field("channel")
  76. if pri != "5":
  77. raise Exception("Unexpected primary channel")
  78. sec = hapd.get_status_field("secondary_channel")
  79. if sec != "0":
  80. raise Exception("Unexpected secondary channel: " + sec)
  81. dev[0].connect("test-ht40", key_mgmt="NONE", scan_freq=freq)
  82. def test_ap_ht40_scan_legacy_conflict(dev, apdev):
  83. """HT40 co-ex scan conflict with legacy 20 MHz AP"""
  84. clear_scan_cache(apdev[0]['ifname'])
  85. params = { "ssid": "legacy-20",
  86. "channel": "7", "ieee80211n": "0" }
  87. hostapd.add_ap(apdev[1]['ifname'], params)
  88. params = { "ssid": "test-ht40",
  89. "channel": "5",
  90. "ht_capab": "[HT40-]"}
  91. hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
  92. state = hapd.get_status_field("state")
  93. if state != "HT_SCAN":
  94. time.sleep(0.1)
  95. state = hapd.get_status_field("state")
  96. if state != "HT_SCAN":
  97. raise Exception("Unexpected interface state - expected HT_SCAN")
  98. ev = hapd.wait_event(["AP-ENABLED"], timeout=10)
  99. if not ev:
  100. raise Exception("AP setup timed out")
  101. state = hapd.get_status_field("state")
  102. if state != "ENABLED":
  103. raise Exception("Unexpected interface state - expected ENABLED")
  104. freq = hapd.get_status_field("freq")
  105. if freq != "2432":
  106. raise Exception("Unexpected frequency: " + freq)
  107. pri = hapd.get_status_field("channel")
  108. if pri != "5":
  109. raise Exception("Unexpected primary channel: " + pri)
  110. sec = hapd.get_status_field("secondary_channel")
  111. if sec != "0":
  112. raise Exception("Unexpected secondary channel: " + sec)
  113. dev[0].connect("test-ht40", key_mgmt="NONE", scan_freq=freq)
  114. def test_ap_ht40_scan_ht20_conflict(dev, apdev):
  115. """HT40 co-ex scan conflict with HT 20 MHz AP"""
  116. clear_scan_cache(apdev[0]['ifname'])
  117. params = { "ssid": "ht-20",
  118. "channel": "7", "ieee80211n": "1" }
  119. hostapd.add_ap(apdev[1]['ifname'], params)
  120. params = { "ssid": "test-ht40",
  121. "channel": "5",
  122. "ht_capab": "[HT40-]"}
  123. hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
  124. state = hapd.get_status_field("state")
  125. if state != "HT_SCAN":
  126. time.sleep(0.1)
  127. state = hapd.get_status_field("state")
  128. if state != "HT_SCAN":
  129. raise Exception("Unexpected interface state - expected HT_SCAN")
  130. ev = hapd.wait_event(["AP-ENABLED"], timeout=10)
  131. if not ev:
  132. raise Exception("AP setup timed out")
  133. state = hapd.get_status_field("state")
  134. if state != "ENABLED":
  135. raise Exception("Unexpected interface state - expected ENABLED")
  136. freq = hapd.get_status_field("freq")
  137. if freq != "2432":
  138. raise Exception("Unexpected frequency: " + freq)
  139. pri = hapd.get_status_field("channel")
  140. if pri != "5":
  141. raise Exception("Unexpected primary channel: " + pri)
  142. sec = hapd.get_status_field("secondary_channel")
  143. if sec != "0":
  144. raise Exception("Unexpected secondary channel: " + sec)
  145. dev[0].connect("test-ht40", key_mgmt="NONE", scan_freq=freq)
  146. def test_ap_ht40_scan_match(dev, apdev):
  147. """HT40 co-ex scan matching configuration"""
  148. clear_scan_cache(apdev[0]['ifname'])
  149. params = { "ssid": "test-ht40",
  150. "channel": "5",
  151. "ht_capab": "[HT40-]"}
  152. hostapd.add_ap(apdev[1]['ifname'], params)
  153. params = { "ssid": "test-ht40",
  154. "channel": "5",
  155. "ht_capab": "[HT40-]"}
  156. hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
  157. state = hapd.get_status_field("state")
  158. if state != "HT_SCAN":
  159. time.sleep(0.1)
  160. state = hapd.get_status_field("state")
  161. if state != "HT_SCAN":
  162. raise Exception("Unexpected interface state - expected HT_SCAN")
  163. ev = hapd.wait_event(["AP-ENABLED"], timeout=10)
  164. if not ev:
  165. raise Exception("AP setup timed out")
  166. state = hapd.get_status_field("state")
  167. if state != "ENABLED":
  168. raise Exception("Unexpected interface state - expected ENABLED")
  169. freq = hapd.get_status_field("freq")
  170. if freq != "2432":
  171. raise Exception("Unexpected frequency")
  172. pri = hapd.get_status_field("channel")
  173. if pri != "5":
  174. raise Exception("Unexpected primary channel")
  175. sec = hapd.get_status_field("secondary_channel")
  176. if sec != "-1":
  177. raise Exception("Unexpected secondary channel: " + sec)
  178. dev[0].connect("test-ht40", key_mgmt="NONE", scan_freq=freq)
  179. def test_ap_ht40_5ghz_match(dev, apdev):
  180. """HT40 co-ex scan on 5 GHz with matching pri/sec channel"""
  181. clear_scan_cache(apdev[0]['ifname'])
  182. try:
  183. hapd = None
  184. hapd2 = None
  185. params = { "ssid": "test-ht40",
  186. "hw_mode": "a",
  187. "channel": "36",
  188. "country_code": "US",
  189. "ht_capab": "[HT40+]"}
  190. hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
  191. params = { "ssid": "test-ht40",
  192. "hw_mode": "a",
  193. "channel": "36",
  194. "ht_capab": "[HT40+]"}
  195. hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
  196. state = hapd.get_status_field("state")
  197. if state != "HT_SCAN":
  198. time.sleep(0.1)
  199. state = hapd.get_status_field("state")
  200. if state != "HT_SCAN":
  201. raise Exception("Unexpected interface state - expected HT_SCAN")
  202. ev = hapd.wait_event(["AP-ENABLED"], timeout=10)
  203. if not ev:
  204. raise Exception("AP setup timed out")
  205. state = hapd.get_status_field("state")
  206. if state != "ENABLED":
  207. raise Exception("Unexpected interface state - expected ENABLED")
  208. freq = hapd.get_status_field("freq")
  209. if freq != "5180":
  210. raise Exception("Unexpected frequency")
  211. pri = hapd.get_status_field("channel")
  212. if pri != "36":
  213. raise Exception("Unexpected primary channel")
  214. sec = hapd.get_status_field("secondary_channel")
  215. if sec != "1":
  216. raise Exception("Unexpected secondary channel: " + sec)
  217. dev[0].connect("test-ht40", key_mgmt="NONE", scan_freq=freq)
  218. finally:
  219. dev[0].request("DISCONNECT")
  220. if hapd:
  221. hapd.request("DISABLE")
  222. if hapd2:
  223. hapd2.request("DISABLE")
  224. subprocess.call(['iw', 'reg', 'set', '00'])
  225. dev[0].flush_scan_cache()
  226. def test_ap_ht40_5ghz_switch(dev, apdev):
  227. """HT40 co-ex scan on 5 GHz switching pri/sec channel"""
  228. clear_scan_cache(apdev[0]['ifname'])
  229. try:
  230. hapd = None
  231. hapd2 = None
  232. params = { "ssid": "test-ht40",
  233. "hw_mode": "a",
  234. "channel": "36",
  235. "country_code": "US",
  236. "ht_capab": "[HT40+]"}
  237. hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
  238. params = { "ssid": "test-ht40",
  239. "hw_mode": "a",
  240. "channel": "40",
  241. "ht_capab": "[HT40-]"}
  242. hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
  243. state = hapd.get_status_field("state")
  244. if state != "HT_SCAN":
  245. time.sleep(0.1)
  246. state = hapd.get_status_field("state")
  247. if state != "HT_SCAN":
  248. raise Exception("Unexpected interface state - expected HT_SCAN")
  249. ev = hapd.wait_event(["AP-ENABLED"], timeout=10)
  250. if not ev:
  251. raise Exception("AP setup timed out")
  252. state = hapd.get_status_field("state")
  253. if state != "ENABLED":
  254. raise Exception("Unexpected interface state - expected ENABLED")
  255. freq = hapd.get_status_field("freq")
  256. if freq != "5180":
  257. raise Exception("Unexpected frequency: " + freq)
  258. pri = hapd.get_status_field("channel")
  259. if pri != "36":
  260. raise Exception("Unexpected primary channel: " + pri)
  261. sec = hapd.get_status_field("secondary_channel")
  262. if sec != "1":
  263. raise Exception("Unexpected secondary channel: " + sec)
  264. dev[0].connect("test-ht40", key_mgmt="NONE", scan_freq=freq)
  265. finally:
  266. dev[0].request("DISCONNECT")
  267. if hapd:
  268. hapd.request("DISABLE")
  269. if hapd2:
  270. hapd2.request("DISABLE")
  271. subprocess.call(['iw', 'reg', 'set', '00'])
  272. def test_ap_ht40_5ghz_switch2(dev, apdev):
  273. """HT40 co-ex scan on 5 GHz switching pri/sec channel (2)"""
  274. clear_scan_cache(apdev[0]['ifname'])
  275. try:
  276. hapd = None
  277. hapd2 = None
  278. params = { "ssid": "test-ht40",
  279. "hw_mode": "a",
  280. "channel": "36",
  281. "country_code": "US",
  282. "ht_capab": "[HT40+]"}
  283. hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
  284. id = dev[0].add_network()
  285. dev[0].set_network(id, "mode", "2")
  286. dev[0].set_network_quoted(id, "ssid", "wpas-ap-open")
  287. dev[0].set_network(id, "key_mgmt", "NONE")
  288. dev[0].set_network(id, "frequency", "5200")
  289. dev[0].set_network(id, "scan_freq", "5200")
  290. dev[0].select_network(id)
  291. time.sleep(1)
  292. params = { "ssid": "test-ht40",
  293. "hw_mode": "a",
  294. "channel": "40",
  295. "ht_capab": "[HT40-]"}
  296. hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
  297. state = hapd.get_status_field("state")
  298. if state != "HT_SCAN":
  299. time.sleep(0.1)
  300. state = hapd.get_status_field("state")
  301. if state != "HT_SCAN":
  302. raise Exception("Unexpected interface state - expected HT_SCAN")
  303. ev = hapd.wait_event(["AP-ENABLED"], timeout=10)
  304. if not ev:
  305. raise Exception("AP setup timed out")
  306. state = hapd.get_status_field("state")
  307. if state != "ENABLED":
  308. raise Exception("Unexpected interface state - expected ENABLED")
  309. freq = hapd.get_status_field("freq")
  310. if freq != "5180":
  311. raise Exception("Unexpected frequency: " + freq)
  312. pri = hapd.get_status_field("channel")
  313. if pri != "36":
  314. raise Exception("Unexpected primary channel: " + pri)
  315. sec = hapd.get_status_field("secondary_channel")
  316. if sec != "1":
  317. raise Exception("Unexpected secondary channel: " + sec)
  318. dev[0].connect("test-ht40", key_mgmt="NONE", scan_freq=freq)
  319. finally:
  320. dev[0].request("DISCONNECT")
  321. if hapd:
  322. hapd.request("DISABLE")
  323. if hapd2:
  324. hapd2.request("DISABLE")
  325. subprocess.call(['iw', 'reg', 'set', '00'])
  326. dev[0].flush_scan_cache()
  327. def test_obss_scan(dev, apdev):
  328. """Overlapping BSS scan request"""
  329. params = { "ssid": "obss-scan",
  330. "channel": "6",
  331. "ht_capab": "[HT40-]",
  332. "obss_interval": "10" }
  333. hapd = hostapd.add_ap(apdev[0]['ifname'], params)
  334. params = { "ssid": "another-bss",
  335. "channel": "9",
  336. "ieee80211n": "0" }
  337. hostapd.add_ap(apdev[1]['ifname'], params)
  338. dev[0].connect("obss-scan", key_mgmt="NONE", scan_freq="2437")
  339. hapd.set("ext_mgmt_frame_handling", "1")
  340. logger.info("Waiting for OBSS scan to occur")
  341. ev = dev[0].wait_event(["CTRL-EVENT-SCAN-STARTED"], timeout=15)
  342. if ev is None:
  343. raise Exception("Timed out while waiting for OBSS scan to start")
  344. ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"], timeout=10)
  345. if ev is None:
  346. raise Exception("Timed out while waiting for OBSS scan results")
  347. received = False
  348. for i in range(0, 4):
  349. frame = hapd.mgmt_rx(timeout=5)
  350. if frame is None:
  351. raise Exception("MGMT RX wait timed out")
  352. if frame['subtype'] != 13:
  353. continue
  354. payload = frame['payload']
  355. if len(payload) < 3:
  356. continue
  357. (category, action, ie) = struct.unpack('BBB', payload[0:3])
  358. if category != 4:
  359. continue
  360. if action != 0:
  361. continue
  362. if ie == 72:
  363. logger.info("20/40 BSS Coexistence report received")
  364. received = True
  365. break
  366. if not received:
  367. raise Exception("20/40 BSS Coexistence report not seen")
  368. def test_obss_scan_40_intolerant(dev, apdev):
  369. """Overlapping BSS scan request with 40 MHz intolerant AP"""
  370. params = { "ssid": "obss-scan",
  371. "channel": "6",
  372. "ht_capab": "[HT40-]",
  373. "obss_interval": "10" }
  374. hapd = hostapd.add_ap(apdev[0]['ifname'], params)
  375. params = { "ssid": "another-bss",
  376. "channel": "7",
  377. "ht_capab": "[40-INTOLERANT]" }
  378. hostapd.add_ap(apdev[1]['ifname'], params)
  379. dev[0].connect("obss-scan", key_mgmt="NONE", scan_freq="2437")
  380. hapd.set("ext_mgmt_frame_handling", "1")
  381. logger.info("Waiting for OBSS scan to occur")
  382. ev = dev[0].wait_event(["CTRL-EVENT-SCAN-STARTED"], timeout=15)
  383. if ev is None:
  384. raise Exception("Timed out while waiting for OBSS scan to start")
  385. ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"], timeout=10)
  386. if ev is None:
  387. raise Exception("Timed out while waiting for OBSS scan results")
  388. received = False
  389. for i in range(0, 4):
  390. frame = hapd.mgmt_rx(timeout=5)
  391. if frame is None:
  392. raise Exception("MGMT RX wait timed out")
  393. if frame['subtype'] != 13:
  394. continue
  395. payload = frame['payload']
  396. if len(payload) < 3:
  397. continue
  398. (category, action, ie) = struct.unpack('BBB', payload[0:3])
  399. if category != 4:
  400. continue
  401. if action != 0:
  402. continue
  403. if ie == 72:
  404. logger.info("20/40 BSS Coexistence report received")
  405. received = True
  406. break
  407. if not received:
  408. raise Exception("20/40 BSS Coexistence report not seen")
  409. def test_obss_coex_report_handling(dev, apdev):
  410. """Overlapping BSS scan report handling with obss_interval=0"""
  411. clear_scan_cache(apdev[0]['ifname'])
  412. params = { "ssid": "obss-scan",
  413. "channel": "6",
  414. "ht_capab": "[HT40-]" }
  415. hapd = hostapd.add_ap(apdev[0]['ifname'], params)
  416. bssid = apdev[0]['bssid']
  417. dev[0].connect("obss-scan", key_mgmt="NONE", scan_freq="2437")
  418. sec = hapd.get_status_field("secondary_channel")
  419. if sec != "-1":
  420. raise Exception("AP is not using 40 MHz channel")
  421. # 20/40 MHz co-ex report tests: number of invalid reports and a valid report
  422. # that forces 20 MHz channel.
  423. tests = [ '0400', '040048', '04004801', '0400480000', '0400490100',
  424. '040048ff0000', '04004801ff49ff00', '04004801004900',
  425. '0400480100490101', '0400480100490201ff',
  426. '040048010449020005' ]
  427. for msg in tests:
  428. req = "MGMT_TX {} {} freq=2437 action={}".format(bssid, bssid, msg)
  429. if "OK" not in dev[0].request(req):
  430. raise Exception("Could not send management frame")
  431. time.sleep(0.5)
  432. sec = hapd.get_status_field("secondary_channel")
  433. if sec != "0":
  434. raise Exception("AP did not move to 20 MHz channel")
  435. def test_obss_coex_report_handling1(dev, apdev):
  436. """Overlapping BSS scan report handling with obss_interval=1"""
  437. clear_scan_cache(apdev[0]['ifname'])
  438. params = { "ssid": "obss-scan",
  439. "channel": "6",
  440. "ht_capab": "[HT40+]",
  441. "obss_interval": "1" }
  442. hapd = hostapd.add_ap(apdev[0]['ifname'], params)
  443. bssid = apdev[0]['bssid']
  444. dev[0].connect("obss-scan", key_mgmt="NONE", scan_freq="2437")
  445. sec = hapd.get_status_field("secondary_channel")
  446. if sec != "1":
  447. raise Exception("AP is not using 40 MHz channel")
  448. # 20/40 MHz co-ex report forcing 20 MHz channel
  449. msg = '040048010449020005'
  450. req = "MGMT_TX {} {} freq=2437 action={}".format(bssid, bssid, msg)
  451. if "OK" not in dev[0].request(req):
  452. raise Exception("Could not send management frame")
  453. time.sleep(0.5)
  454. sec = hapd.get_status_field("secondary_channel")
  455. if sec != "0":
  456. raise Exception("AP did not move to 20 MHz channel")
  457. # No 20/40 MHz co-ex reports forcing 20 MHz channel during next interval
  458. for i in range(20):
  459. sec = hapd.get_status_field("secondary_channel")
  460. if sec == "1":
  461. break
  462. time.sleep(0.5)
  463. if sec != "1":
  464. raise Exception("AP did not return to 40 MHz channel")
  465. def test_olbc(dev, apdev):
  466. """OLBC detection"""
  467. params = { "ssid": "test-olbc",
  468. "channel": "6",
  469. "ht_capab": "[HT40-]",
  470. "ap_table_expiration_time": "2" }
  471. hapd = hostapd.add_ap(apdev[0]['ifname'], params)
  472. status = hapd.get_status()
  473. if status['olbc'] != '0' or status['olbc_ht'] != '0':
  474. raise Exception("Unexpected OLBC information")
  475. params = { "ssid": "olbc-ap",
  476. "hw_mode": "b",
  477. "channel": "6",
  478. "wmm_enabled": "0" }
  479. hostapd.add_ap(apdev[1]['ifname'], params)
  480. time.sleep(0.5)
  481. status = hapd.get_status()
  482. if status['olbc'] != '1' or status['olbc_ht'] != '1':
  483. raise Exception("Missing OLBC information")
  484. hapd_global = hostapd.HostapdGlobal()
  485. hapd_global.remove(apdev[1]['ifname'])
  486. logger.info("Waiting for OLBC state to time out")
  487. cleared = False
  488. for i in range(0, 15):
  489. time.sleep(1)
  490. status = hapd.get_status()
  491. if status['olbc'] == '0' and status['olbc_ht'] == '0':
  492. cleared = True
  493. break
  494. if not cleared:
  495. raise Exception("OLBC state did nto time out")
  496. def test_olbc_table_limit(dev, apdev):
  497. """OLBC AP table size limit"""
  498. ifname1 = apdev[0]['ifname']
  499. ifname2 = apdev[0]['ifname'] + '-2'
  500. ifname3 = apdev[0]['ifname'] + '-3'
  501. hostapd.add_bss('phy3', ifname1, 'bss-1.conf')
  502. hostapd.add_bss('phy3', ifname2, 'bss-2.conf')
  503. hostapd.add_bss('phy3', ifname3, 'bss-3.conf')
  504. params = { "ssid": "test-olbc",
  505. "channel": "1",
  506. "ap_table_max_size": "2" }
  507. hapd = hostapd.add_ap(apdev[1]['ifname'], params)
  508. time.sleep(0.3)
  509. with alloc_fail(hapd, 1, "ap_list_process_beacon"):
  510. time.sleep(0.3)
  511. hapd.set("ap_table_max_size", "1")
  512. time.sleep(0.3)
  513. hapd.set("ap_table_max_size", "0")
  514. time.sleep(0.3)
  515. def test_olbc_5ghz(dev, apdev):
  516. """OLBC detection on 5 GHz"""
  517. try:
  518. hapd = None
  519. hapd2 = None
  520. params = { "ssid": "test-olbc",
  521. "country_code": "FI",
  522. "hw_mode": "a",
  523. "channel": "36",
  524. "ht_capab": "[HT40+]" }
  525. hapd = hostapd.add_ap(apdev[0]['ifname'], params)
  526. status = hapd.get_status()
  527. if status['olbc'] != '0' or status['olbc_ht'] != '0':
  528. raise Exception("Unexpected OLBC information")
  529. params = { "ssid": "olbc-ap",
  530. "country_code": "FI",
  531. "hw_mode": "a",
  532. "channel": "36",
  533. "ieee80211n": "0",
  534. "wmm_enabled": "0" }
  535. hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
  536. found = False
  537. for i in range(20):
  538. time.sleep(0.1)
  539. status = hapd.get_status()
  540. logger.debug('olbc_ht: ' + status['olbc_ht'])
  541. if status['olbc_ht'] == '1':
  542. found = True
  543. break
  544. if not found:
  545. raise Exception("Missing OLBC information")
  546. finally:
  547. if hapd:
  548. hapd.request("DISABLE")
  549. if hapd2:
  550. hapd2.request("DISABLE")
  551. subprocess.call(['iw', 'reg', 'set', '00'])
  552. def test_ap_require_ht(dev, apdev):
  553. """Require HT"""
  554. params = { "ssid": "require-ht",
  555. "require_ht": "1" }
  556. hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
  557. dev[1].connect("require-ht", key_mgmt="NONE", scan_freq="2412",
  558. disable_ht="1", wait_connect=False)
  559. dev[0].connect("require-ht", key_mgmt="NONE", scan_freq="2412")
  560. ev = dev[1].wait_event(["CTRL-EVENT-ASSOC-REJECT"])
  561. if ev is None:
  562. raise Exception("Association rejection timed out")
  563. if "status_code=27" not in ev:
  564. raise Exception("Unexpected rejection status code")
  565. dev[2].connect("require-ht", key_mgmt="NONE", scan_freq="2412",
  566. ht_mcs="0x01 00 00 00 00 00 00 00 00 00",
  567. disable_max_amsdu="1", ampdu_factor="2",
  568. ampdu_density="1", disable_ht40="1", disable_sgi="1",
  569. disable_ldpc="1")
  570. def test_ap_require_ht_limited_rates(dev, apdev):
  571. """Require HT with limited supported rates"""
  572. params = { "ssid": "require-ht",
  573. "supported_rates": "60 120 240 360 480 540",
  574. "require_ht": "1" }
  575. hapd = hostapd.add_ap(apdev[0]['ifname'], params, wait_enabled=False)
  576. dev[1].connect("require-ht", key_mgmt="NONE", scan_freq="2412",
  577. disable_ht="1", wait_connect=False)
  578. dev[0].connect("require-ht", key_mgmt="NONE", scan_freq="2412")
  579. ev = dev[1].wait_event(["CTRL-EVENT-ASSOC-REJECT"])
  580. if ev is None:
  581. raise Exception("Association rejection timed out")
  582. if "status_code=27" not in ev:
  583. raise Exception("Unexpected rejection status code")
  584. def test_ap_ht_capab_not_supported(dev, apdev):
  585. """HT configuration with driver not supporting all ht_capab entries"""
  586. params = { "ssid": "test-ht40",
  587. "channel": "5",
  588. "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]"}
  589. hapd = hostapd.add_ap(apdev[0]['ifname'], params, no_enable=True)
  590. if "FAIL" not in hapd.request("ENABLE"):
  591. raise Exception("Unexpected ENABLE success")
  592. def test_ap_ht_40mhz_intolerant_sta(dev, apdev):
  593. """Associated STA indicating 40 MHz intolerant"""
  594. clear_scan_cache(apdev[0]['ifname'])
  595. params = { "ssid": "intolerant",
  596. "channel": "6",
  597. "ht_capab": "[HT40-]" }
  598. hapd = hostapd.add_ap(apdev[0]['ifname'], params)
  599. if hapd.get_status_field("num_sta_ht40_intolerant") != "0":
  600. raise Exception("Unexpected num_sta_ht40_intolerant value")
  601. if hapd.get_status_field("secondary_channel") != "-1":
  602. raise Exception("Unexpected secondary_channel")
  603. dev[0].connect("intolerant", key_mgmt="NONE", scan_freq="2437")
  604. if hapd.get_status_field("num_sta_ht40_intolerant") != "0":
  605. raise Exception("Unexpected num_sta_ht40_intolerant value")
  606. if hapd.get_status_field("secondary_channel") != "-1":
  607. raise Exception("Unexpected secondary_channel")
  608. dev[2].connect("intolerant", key_mgmt="NONE", scan_freq="2437",
  609. ht40_intolerant="1")
  610. time.sleep(1)
  611. if hapd.get_status_field("num_sta_ht40_intolerant") != "1":
  612. raise Exception("Unexpected num_sta_ht40_intolerant value (expected 1)")
  613. if hapd.get_status_field("secondary_channel") != "0":
  614. raise Exception("Unexpected secondary_channel (did not disable 40 MHz)")
  615. dev[2].request("DISCONNECT")
  616. time.sleep(1)
  617. if hapd.get_status_field("num_sta_ht40_intolerant") != "0":
  618. raise Exception("Unexpected num_sta_ht40_intolerant value (expected 0)")
  619. if hapd.get_status_field("secondary_channel") != "-1":
  620. raise Exception("Unexpected secondary_channel (did not re-enable 40 MHz)")
  621. def test_ap_ht_40mhz_intolerant_ap(dev, apdev):
  622. """Associated STA reports 40 MHz intolerant AP after association"""
  623. clear_scan_cache(apdev[0]['ifname'])
  624. params = { "ssid": "ht",
  625. "channel": "6",
  626. "ht_capab": "[HT40-]",
  627. "obss_interval": "3" }
  628. hapd = hostapd.add_ap(apdev[0]['ifname'], params)
  629. dev[0].connect("ht", key_mgmt="NONE", scan_freq="2437")
  630. if hapd.get_status_field("secondary_channel") != "-1":
  631. raise Exception("Unexpected secondary channel information")
  632. logger.info("Start 40 MHz intolerant AP")
  633. params = { "ssid": "intolerant",
  634. "channel": "5",
  635. "ht_capab": "[40-INTOLERANT]" }
  636. hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
  637. logger.info("Waiting for co-ex report from STA")
  638. ok = False
  639. for i in range(0, 20):
  640. time.sleep(1)
  641. if hapd.get_status_field("secondary_channel") == "0":
  642. logger.info("AP moved to 20 MHz channel")
  643. ok = True
  644. break
  645. if not ok:
  646. raise Exception("AP did not move to 20 MHz channel")
  647. if "OK" not in hapd2.request("DISABLE"):
  648. raise Exception("Failed to disable 40 MHz intolerant AP")
  649. # make sure the intolerant AP disappears from scan results more quickly
  650. dev[0].scan(type="ONLY", freq="2432", only_new=True)
  651. dev[0].scan(type="ONLY", freq="2432", only_new=True)
  652. dev[0].dump_monitor()
  653. logger.info("Waiting for AP to move back to 40 MHz channel")
  654. ok = False
  655. for i in range(0, 30):
  656. time.sleep(1)
  657. if hapd.get_status_field("secondary_channel") == "-1":
  658. logger.info("AP moved to 40 MHz channel")
  659. ok = True
  660. break
  661. if not ok:
  662. raise Exception("AP did not move to 40 MHz channel")
  663. def test_ap_ht40_csa(dev, apdev):
  664. """HT with 40 MHz channel width and CSA"""
  665. csa_supported(dev[0])
  666. try:
  667. hapd = None
  668. params = { "ssid": "ht",
  669. "country_code": "US",
  670. "hw_mode": "a",
  671. "channel": "36",
  672. "ht_capab": "[HT40+]",
  673. "ieee80211n": "1" }
  674. hapd = hostapd.add_ap(apdev[0]['ifname'], params)
  675. dev[0].connect("ht", key_mgmt="NONE", scan_freq="5180")
  676. hwsim_utils.test_connectivity(dev[0], hapd)
  677. hapd.request("CHAN_SWITCH 5 5200 ht sec_channel_offset=-1 bandwidth=40")
  678. ev = hapd.wait_event(["AP-CSA-FINISHED"], timeout=10)
  679. if ev is None:
  680. raise Exception("CSA finished event timed out")
  681. if "freq=5200" not in ev:
  682. raise Exception("Unexpected channel in CSA finished event")
  683. ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=0.5)
  684. if ev is not None:
  685. raise Exception("Unexpected STA disconnection during CSA")
  686. hwsim_utils.test_connectivity(dev[0], hapd)
  687. hapd.request("CHAN_SWITCH 5 5180 ht sec_channel_offset=1 bandwidth=40")
  688. ev = hapd.wait_event(["AP-CSA-FINISHED"], timeout=10)
  689. if ev is None:
  690. raise Exception("CSA finished event timed out")
  691. if "freq=5180" not in ev:
  692. raise Exception("Unexpected channel in CSA finished event")
  693. ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=0.5)
  694. if ev is not None:
  695. raise Exception("Unexpected STA disconnection during CSA")
  696. hwsim_utils.test_connectivity(dev[0], hapd)
  697. finally:
  698. dev[0].request("DISCONNECT")
  699. if hapd:
  700. hapd.request("DISABLE")
  701. subprocess.call(['iw', 'reg', 'set', '00'])
  702. dev[0].flush_scan_cache()
  703. def test_ap_ht40_csa2(dev, apdev):
  704. """HT with 40 MHz channel width and CSA"""
  705. csa_supported(dev[0])
  706. try:
  707. hapd = None
  708. params = { "ssid": "ht",
  709. "country_code": "US",
  710. "hw_mode": "a",
  711. "channel": "36",
  712. "ht_capab": "[HT40+]",
  713. "ieee80211n": "1" }
  714. hapd = hostapd.add_ap(apdev[0]['ifname'], params)
  715. dev[0].connect("ht", key_mgmt="NONE", scan_freq="5180")
  716. hwsim_utils.test_connectivity(dev[0], hapd)
  717. hapd.request("CHAN_SWITCH 5 5220 ht sec_channel_offset=1 bandwidth=40")
  718. ev = hapd.wait_event(["AP-CSA-FINISHED"], timeout=10)
  719. if ev is None:
  720. raise Exception("CSA finished event timed out")
  721. if "freq=5220" not in ev:
  722. raise Exception("Unexpected channel in CSA finished event")
  723. ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=0.5)
  724. if ev is not None:
  725. raise Exception("Unexpected STA disconnection during CSA")
  726. hwsim_utils.test_connectivity(dev[0], hapd)
  727. hapd.request("CHAN_SWITCH 5 5180 ht sec_channel_offset=1 bandwidth=40")
  728. ev = hapd.wait_event(["AP-CSA-FINISHED"], timeout=10)
  729. if ev is None:
  730. raise Exception("CSA finished event timed out")
  731. if "freq=5180" not in ev:
  732. raise Exception("Unexpected channel in CSA finished event")
  733. ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=0.5)
  734. if ev is not None:
  735. raise Exception("Unexpected STA disconnection during CSA")
  736. hwsim_utils.test_connectivity(dev[0], hapd)
  737. finally:
  738. dev[0].request("DISCONNECT")
  739. if hapd:
  740. hapd.request("DISABLE")
  741. subprocess.call(['iw', 'reg', 'set', '00'])
  742. dev[0].flush_scan_cache()
  743. def test_ap_ht40_csa3(dev, apdev):
  744. """HT with 40 MHz channel width and CSA"""
  745. csa_supported(dev[0])
  746. try:
  747. hapd = None
  748. params = { "ssid": "ht",
  749. "country_code": "US",
  750. "hw_mode": "a",
  751. "channel": "36",
  752. "ht_capab": "[HT40+]",
  753. "ieee80211n": "1" }
  754. hapd = hostapd.add_ap(apdev[0]['ifname'], params)
  755. dev[0].connect("ht", key_mgmt="NONE", scan_freq="5180")
  756. hwsim_utils.test_connectivity(dev[0], hapd)
  757. hapd.request("CHAN_SWITCH 5 5240 ht sec_channel_offset=-1 bandwidth=40")
  758. ev = hapd.wait_event(["AP-CSA-FINISHED"], timeout=10)
  759. if ev is None:
  760. raise Exception("CSA finished event timed out")
  761. if "freq=5240" not in ev:
  762. raise Exception("Unexpected channel in CSA finished event")
  763. ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=0.5)
  764. if ev is not None:
  765. raise Exception("Unexpected STA disconnection during CSA")
  766. hwsim_utils.test_connectivity(dev[0], hapd)
  767. hapd.request("CHAN_SWITCH 5 5180 ht sec_channel_offset=1 bandwidth=40")
  768. ev = hapd.wait_event(["AP-CSA-FINISHED"], timeout=10)
  769. if ev is None:
  770. raise Exception("CSA finished event timed out")
  771. if "freq=5180" not in ev:
  772. raise Exception("Unexpected channel in CSA finished event")
  773. ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=0.5)
  774. if ev is not None:
  775. raise Exception("Unexpected STA disconnection during CSA")
  776. hwsim_utils.test_connectivity(dev[0], hapd)
  777. finally:
  778. dev[0].request("DISCONNECT")
  779. if hapd:
  780. hapd.request("DISABLE")
  781. subprocess.call(['iw', 'reg', 'set', '00'])
  782. dev[0].flush_scan_cache()
  783. def test_ap_ht_smps(dev, apdev):
  784. """SMPS AP configuration options"""
  785. params = { "ssid": "ht1", "ht_capab": "[SMPS-STATIC]" }
  786. try:
  787. hapd = hostapd.add_ap(apdev[0]['ifname'], params)
  788. except:
  789. raise HwsimSkip("Assume mac80211_hwsim was not recent enough to support SMPS")
  790. params = { "ssid": "ht2", "ht_capab": "[SMPS-DYNAMIC]" }
  791. hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
  792. dev[0].connect("ht1", key_mgmt="NONE", scan_freq="2412")
  793. dev[1].connect("ht2", key_mgmt="NONE", scan_freq="2412")
  794. hwsim_utils.test_connectivity(dev[0], hapd)
  795. hwsim_utils.test_connectivity(dev[1], hapd2)
  796. def test_prefer_ht20(dev, apdev):
  797. """Preference on HT20 over no-HT"""
  798. params = { "ssid": "test",
  799. "channel": "1",
  800. "ieee80211n": "0" }
  801. hapd = hostapd.add_ap(apdev[0]['ifname'], params)
  802. bssid = apdev[0]['bssid']
  803. params = { "ssid": "test",
  804. "channel": "1",
  805. "ieee80211n": "1" }
  806. hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
  807. bssid2 = apdev[1]['bssid']
  808. dev[0].scan_for_bss(bssid, freq=2412)
  809. dev[0].scan_for_bss(bssid2, freq=2412)
  810. dev[0].connect("test", key_mgmt="NONE", scan_freq="2412")
  811. if dev[0].get_status_field('bssid') != bssid2:
  812. raise Exception("Unexpected BSS selected")
  813. est = dev[0].get_bss(bssid)['est_throughput']
  814. if est != "54000":
  815. raise Exception("Unexpected BSS0 est_throughput: " + est)
  816. est = dev[0].get_bss(bssid2)['est_throughput']
  817. if est != "65000":
  818. raise Exception("Unexpected BSS1 est_throughput: " + est)
  819. def test_prefer_ht40(dev, apdev):
  820. """Preference on HT40 over HT20"""
  821. params = { "ssid": "test",
  822. "channel": "1",
  823. "ieee80211n": "1" }
  824. hapd = hostapd.add_ap(apdev[0]['ifname'], params)
  825. bssid = apdev[0]['bssid']
  826. params = { "ssid": "test",
  827. "channel": "1",
  828. "ieee80211n": "1",
  829. "ht_capab": "[HT40+]" }
  830. hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
  831. bssid2 = apdev[1]['bssid']
  832. dev[0].scan_for_bss(bssid, freq=2412)
  833. dev[0].scan_for_bss(bssid2, freq=2412)
  834. dev[0].connect("test", key_mgmt="NONE", scan_freq="2412")
  835. if dev[0].get_status_field('bssid') != bssid2:
  836. raise Exception("Unexpected BSS selected")
  837. est = dev[0].get_bss(bssid)['est_throughput']
  838. if est != "65000":
  839. raise Exception("Unexpected BSS0 est_throughput: " + est)
  840. est = dev[0].get_bss(bssid2)['est_throughput']
  841. if est != "135000":
  842. raise Exception("Unexpected BSS1 est_throughput: " + est)
  843. def test_prefer_ht20_during_roam(dev, apdev):
  844. """Preference on HT20 over no-HT in roaming consideration"""
  845. params = { "ssid": "test",
  846. "channel": "1",
  847. "ieee80211n": "0" }
  848. hapd = hostapd.add_ap(apdev[0]['ifname'], params)
  849. bssid = apdev[0]['bssid']
  850. dev[0].scan_for_bss(bssid, freq=2412)
  851. dev[0].connect("test", key_mgmt="NONE", scan_freq="2412")
  852. params = { "ssid": "test",
  853. "channel": "1",
  854. "ieee80211n": "1" }
  855. hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
  856. bssid2 = apdev[1]['bssid']
  857. dev[0].scan_for_bss(bssid2, freq=2412)
  858. dev[0].scan(freq=2412)
  859. dev[0].wait_connected()
  860. if dev[0].get_status_field('bssid') != bssid2:
  861. raise Exception("Unexpected BSS selected")
  862. def test_ap_ht40_5ghz_invalid_pair(dev, apdev):
  863. """HT40 on 5 GHz with invalid channel pair"""
  864. clear_scan_cache(apdev[0]['ifname'])
  865. try:
  866. params = { "ssid": "test-ht40",
  867. "hw_mode": "a",
  868. "channel": "40",
  869. "country_code": "US",
  870. "ht_capab": "[HT40+]"}
  871. hapd = hostapd.add_ap(apdev[1]['ifname'], params, wait_enabled=False)
  872. ev = hapd.wait_event(["AP-DISABLED"], timeout=10)
  873. if not ev:
  874. raise Exception("AP setup failure timed out")
  875. finally:
  876. subprocess.call(['iw', 'reg', 'set', '00'])