]>
Commit | Line | Data |
---|---|---|
8454e1fd JM |
1 | # Test cases for DFS |
2 | # Copyright (c) 2013, 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 | ||
9fd6804d | 7 | from remotehost import remote_compatible |
8454e1fd JM |
8 | import os |
9 | import subprocess | |
10 | import time | |
11 | import logging | |
12 | logger = logging.getLogger() | |
13 | ||
14 | import hwsim_utils | |
15 | import hostapd | |
81e787b7 | 16 | from utils import HwsimSkip |
8454e1fd JM |
17 | |
18 | def wait_dfs_event(hapd, event, timeout): | |
19 | dfs_events = [ "DFS-RADAR-DETECTED", "DFS-NEW-CHANNEL", | |
20 | "DFS-CAC-START", "DFS-CAC-COMPLETED", | |
bd5a7691 | 21 | "DFS-NOP-FINISHED", "AP-ENABLED", "AP-CSA-FINISHED" ] |
8454e1fd JM |
22 | ev = hapd.wait_event(dfs_events, timeout=timeout) |
23 | if not ev: | |
24 | raise Exception("DFS event timed out") | |
bc86d8c1 | 25 | if event and event not in ev: |
8454e1fd JM |
26 | raise Exception("Unexpected DFS event") |
27 | return ev | |
28 | ||
d92da8a2 | 29 | def start_dfs_ap(ap, allow_failure=False, ssid="dfs", ht=True, ht40=False, |
803d0190 JM |
30 | ht40minus=False, vht80=False, vht20=False, chanlist=None, |
31 | channel=None): | |
8454e1fd | 32 | ifname = ap['ifname'] |
8454e1fd | 33 | logger.info("Starting AP " + ifname + " on DFS channel") |
b29c46be | 34 | hapd = hostapd.add_ap(ap, {}, no_enable=True) |
bd5a7691 | 35 | hapd.set("ssid", ssid) |
8454e1fd JM |
36 | hapd.set("country_code", "FI") |
37 | hapd.set("ieee80211d", "1") | |
38 | hapd.set("ieee80211h", "1") | |
39 | hapd.set("hw_mode", "a") | |
40 | hapd.set("channel", "52") | |
d92da8a2 JM |
41 | if not ht: |
42 | hapd.set("ieee80211n", "0") | |
bd5a7691 JM |
43 | if ht40: |
44 | hapd.set("ht_capab", "[HT40+]") | |
d92da8a2 JM |
45 | elif ht40minus: |
46 | hapd.set("ht_capab", "[HT40-]") | |
47 | hapd.set("channel", "56") | |
2a6cce38 JM |
48 | if vht80: |
49 | hapd.set("ieee80211ac", "1") | |
50 | hapd.set("vht_oper_chwidth", "1") | |
51 | hapd.set("vht_oper_centr_freq_seg0_idx", "58") | |
52 | if vht20: | |
53 | hapd.set("ieee80211ac", "1") | |
54 | hapd.set("vht_oper_chwidth", "0") | |
55 | hapd.set("vht_oper_centr_freq_seg0_idx", "0") | |
56 | if chanlist: | |
57 | hapd.set("chanlist", chanlist) | |
803d0190 JM |
58 | if channel: |
59 | hapd.set("channel", str(channel)) | |
8454e1fd JM |
60 | hapd.enable() |
61 | ||
62 | ev = wait_dfs_event(hapd, "DFS-CAC-START", 5) | |
63 | if "DFS-CAC-START" not in ev: | |
64 | raise Exception("Unexpected DFS event") | |
65 | ||
66 | state = hapd.get_status_field("state") | |
67 | if state != "DFS": | |
4f62bfef JM |
68 | if allow_failure: |
69 | logger.info("Interface state not DFS: " + state) | |
81e787b7 JM |
70 | if not os.path.exists("dfs"): |
71 | raise HwsimSkip("Assume DFS testing not supported") | |
72 | raise Exception("Failed to start DFS AP") | |
4f62bfef | 73 | raise Exception("Unexpected interface state: " + state) |
8454e1fd JM |
74 | |
75 | return hapd | |
76 | ||
bd5a7691 JM |
77 | def dfs_simulate_radar(hapd): |
78 | logger.info("Trigger a simulated radar event") | |
79 | phyname = hapd.get_driver_status_field("phyname") | |
80 | radar_file = '/sys/kernel/debug/ieee80211/' + phyname + '/hwsim/dfs_simulate_radar' | |
81 | with open(radar_file, 'w') as f: | |
82 | f.write('1') | |
83 | ||
8454e1fd JM |
84 | def test_dfs(dev, apdev): |
85 | """DFS CAC functionality on clear channel""" | |
4f62bfef | 86 | try: |
e246d7d5 | 87 | hapd = None |
4f62bfef | 88 | hapd = start_dfs_ap(apdev[0], allow_failure=True) |
4f62bfef JM |
89 | |
90 | ev = wait_dfs_event(hapd, "DFS-CAC-COMPLETED", 70) | |
91 | if "success=1" not in ev: | |
92 | raise Exception("CAC failed") | |
93 | if "freq=5260" not in ev: | |
94 | raise Exception("Unexpected DFS freq result") | |
95 | ||
96 | ev = hapd.wait_event(["AP-ENABLED"], timeout=5) | |
97 | if not ev: | |
98 | raise Exception("AP setup timed out") | |
99 | ||
100 | state = hapd.get_status_field("state") | |
101 | if state != "ENABLED": | |
102 | raise Exception("Unexpected interface state") | |
103 | ||
104 | freq = hapd.get_status_field("freq") | |
105 | if freq != "5260": | |
106 | raise Exception("Unexpected frequency") | |
107 | ||
c634d320 | 108 | dev[0].connect("dfs", key_mgmt="NONE") |
a8375c94 | 109 | hwsim_utils.test_connectivity(dev[0], hapd) |
831cb7af JM |
110 | |
111 | hapd.request("RADAR DETECTED freq=5260 ht_enabled=1 chan_width=1") | |
112 | ev = hapd.wait_event(["DFS-RADAR-DETECTED"], timeout=10) | |
113 | if ev is None: | |
114 | raise Exception("DFS-RADAR-DETECTED event not reported") | |
115 | if "freq=5260" not in ev: | |
bc6e3288 | 116 | raise Exception("Incorrect frequency in radar detected event: " + ev) |
831cb7af JM |
117 | ev = hapd.wait_event(["DFS-NEW-CHANNEL"], timeout=70) |
118 | if ev is None: | |
119 | raise Exception("DFS-NEW-CHANNEL event not reported") | |
120 | if "freq=5260" in ev: | |
bc6e3288 | 121 | raise Exception("Channel did not change after radar was detected") |
831cb7af JM |
122 | |
123 | ev = hapd.wait_event(["AP-CSA-FINISHED"], timeout=70) | |
124 | if ev is None: | |
125 | raise Exception("AP-CSA-FINISHED event not reported") | |
126 | if "freq=5260" in ev: | |
bc6e3288 | 127 | raise Exception("Channel did not change after radar was detected(2)") |
831cb7af | 128 | time.sleep(1) |
a8375c94 | 129 | hwsim_utils.test_connectivity(dev[0], hapd) |
4f62bfef | 130 | finally: |
9d7fdac5 JM |
131 | dev[0].request("DISCONNECT") |
132 | if hapd: | |
133 | hapd.request("DISABLE") | |
c4668009 | 134 | subprocess.call(['iw', 'reg', 'set', '00']) |
9d7fdac5 | 135 | dev[0].flush_scan_cache() |
8454e1fd JM |
136 | |
137 | def test_dfs_radar(dev, apdev): | |
138 | """DFS CAC functionality with radar detected""" | |
4f62bfef | 139 | try: |
e246d7d5 | 140 | hapd = None |
9d7fdac5 | 141 | hapd2 = None |
8c6f6ac1 | 142 | hapd = start_dfs_ap(apdev[0], allow_failure=True) |
bc86d8c1 | 143 | time.sleep(1) |
8454e1fd | 144 | |
bd5a7691 JM |
145 | dfs_simulate_radar(hapd) |
146 | ||
147 | hapd2 = start_dfs_ap(apdev[1], ssid="dfs2", ht40=True) | |
bc86d8c1 JM |
148 | |
149 | ev = wait_dfs_event(hapd, "DFS-CAC-COMPLETED", 5) | |
150 | if ev is None: | |
151 | raise Exception("Timeout on DFS aborted event") | |
152 | if "success=0 freq=5260" not in ev: | |
153 | raise Exception("Unexpected DFS aborted event contents: " + ev) | |
154 | ||
155 | ev = wait_dfs_event(hapd, "DFS-RADAR-DETECTED", 5) | |
4f62bfef JM |
156 | if "freq=5260" not in ev: |
157 | raise Exception("Unexpected DFS radar detection freq") | |
8454e1fd | 158 | |
4f62bfef JM |
159 | ev = wait_dfs_event(hapd, "DFS-NEW-CHANNEL", 5) |
160 | if "freq=5260" in ev: | |
161 | raise Exception("Unexpected DFS new freq") | |
8454e1fd | 162 | |
bc86d8c1 JM |
163 | ev = wait_dfs_event(hapd, None, 5) |
164 | if "AP-ENABLED" in ev: | |
165 | logger.info("Started AP on non-DFS channel") | |
166 | else: | |
167 | logger.info("Trying to start AP on another DFS channel") | |
168 | if "DFS-CAC-START" not in ev: | |
169 | raise Exception("Unexpected DFS event") | |
170 | if "freq=5260" in ev: | |
171 | raise Exception("Unexpected DFS CAC freq") | |
172 | ||
173 | ev = wait_dfs_event(hapd, "DFS-CAC-COMPLETED", 70) | |
174 | if "success=1" not in ev: | |
175 | raise Exception("CAC failed") | |
176 | if "freq=5260" in ev: | |
177 | raise Exception("Unexpected DFS freq result - radar channel") | |
178 | ||
179 | ev = hapd.wait_event(["AP-ENABLED"], timeout=5) | |
180 | if not ev: | |
181 | raise Exception("AP setup timed out") | |
182 | ||
183 | state = hapd.get_status_field("state") | |
184 | if state != "ENABLED": | |
185 | raise Exception("Unexpected interface state") | |
186 | ||
187 | freq = hapd.get_status_field("freq") | |
188 | if freq == "5260": | |
189 | raise Exception("Unexpected frequency: " + freq) | |
8454e1fd | 190 | |
c634d320 | 191 | dev[0].connect("dfs", key_mgmt="NONE") |
bd5a7691 JM |
192 | |
193 | ev = hapd2.wait_event(["AP-ENABLED"], timeout=70) | |
194 | if not ev: | |
195 | raise Exception("AP2 setup timed out") | |
196 | ||
197 | dfs_simulate_radar(hapd2) | |
198 | ||
199 | ev = wait_dfs_event(hapd2, "DFS-RADAR-DETECTED", 5) | |
200 | if "freq=5260 ht_enabled=1 chan_offset=1 chan_width=2" not in ev: | |
201 | raise Exception("Unexpected DFS radar detection freq from AP2") | |
202 | ||
203 | ev = wait_dfs_event(hapd2, "DFS-NEW-CHANNEL", 5) | |
204 | if "freq=5260" in ev: | |
205 | raise Exception("Unexpected DFS new freq for AP2") | |
206 | ||
207 | wait_dfs_event(hapd2, None, 5) | |
4f62bfef | 208 | finally: |
9d7fdac5 JM |
209 | dev[0].request("DISCONNECT") |
210 | if hapd: | |
211 | hapd.request("DISABLE") | |
212 | if hapd2: | |
213 | hapd2.request("DISABLE") | |
c4668009 | 214 | subprocess.call(['iw', 'reg', 'set', '00']) |
9d7fdac5 | 215 | dev[0].flush_scan_cache() |
8454e1fd | 216 | |
9fd6804d | 217 | @remote_compatible |
4f62bfef JM |
218 | def test_dfs_radar_on_non_dfs_channel(dev, apdev): |
219 | """DFS radar detection test code on non-DFS channel""" | |
220 | params = { "ssid": "radar" } | |
8b8a1864 | 221 | hapd = hostapd.add_ap(apdev[0], params) |
4f62bfef JM |
222 | |
223 | hapd.request("RADAR DETECTED freq=5260 ht_enabled=1 chan_width=1") | |
224 | hapd.request("RADAR DETECTED freq=2412 ht_enabled=1 chan_width=1") | |
2a6cce38 JM |
225 | |
226 | def test_dfs_radar_chanlist(dev, apdev): | |
227 | """DFS chanlist when radar is detected""" | |
228 | try: | |
e246d7d5 | 229 | hapd = None |
8c6f6ac1 | 230 | hapd = start_dfs_ap(apdev[0], chanlist="40 44", allow_failure=True) |
2a6cce38 JM |
231 | time.sleep(1) |
232 | ||
233 | dfs_simulate_radar(hapd) | |
234 | ||
235 | ev = wait_dfs_event(hapd, "DFS-CAC-COMPLETED", 5) | |
236 | if ev is None: | |
237 | raise Exception("Timeout on DFS aborted event") | |
238 | if "success=0 freq=5260" not in ev: | |
239 | raise Exception("Unexpected DFS aborted event contents: " + ev) | |
240 | ||
241 | ev = wait_dfs_event(hapd, "DFS-RADAR-DETECTED", 5) | |
242 | if "freq=5260" not in ev: | |
243 | raise Exception("Unexpected DFS radar detection freq") | |
244 | ||
245 | ev = wait_dfs_event(hapd, "DFS-NEW-CHANNEL", 5) | |
246 | if "freq=5200 chan=40" not in ev and "freq=5220 chan=44" not in ev: | |
247 | raise Exception("Unexpected DFS new freq: " + ev) | |
248 | ||
249 | ev = wait_dfs_event(hapd, None, 5) | |
250 | if "AP-ENABLED" not in ev: | |
251 | raise Exception("Unexpected DFS event") | |
252 | dev[0].connect("dfs", key_mgmt="NONE") | |
253 | finally: | |
9d7fdac5 JM |
254 | dev[0].request("DISCONNECT") |
255 | if hapd: | |
256 | hapd.request("DISABLE") | |
c4668009 | 257 | subprocess.call(['iw', 'reg', 'set', '00']) |
9d7fdac5 | 258 | dev[0].flush_scan_cache() |
2a6cce38 JM |
259 | |
260 | def test_dfs_radar_chanlist_vht80(dev, apdev): | |
261 | """DFS chanlist when radar is detected and VHT80 configured""" | |
262 | try: | |
e246d7d5 | 263 | hapd = None |
8c6f6ac1 JM |
264 | hapd = start_dfs_ap(apdev[0], chanlist="36", ht40=True, vht80=True, |
265 | allow_failure=True) | |
2a6cce38 JM |
266 | time.sleep(1) |
267 | ||
268 | dfs_simulate_radar(hapd) | |
269 | ||
270 | ev = wait_dfs_event(hapd, "DFS-CAC-COMPLETED", 5) | |
271 | if ev is None: | |
272 | raise Exception("Timeout on DFS aborted event") | |
273 | if "success=0 freq=5260" not in ev: | |
274 | raise Exception("Unexpected DFS aborted event contents: " + ev) | |
275 | ||
276 | ev = wait_dfs_event(hapd, "DFS-RADAR-DETECTED", 5) | |
277 | if "freq=5260" not in ev: | |
278 | raise Exception("Unexpected DFS radar detection freq") | |
279 | ||
280 | ev = wait_dfs_event(hapd, "DFS-NEW-CHANNEL", 5) | |
281 | if "freq=5180 chan=36 sec_chan=1" not in ev: | |
282 | raise Exception("Unexpected DFS new freq: " + ev) | |
283 | ||
284 | ev = wait_dfs_event(hapd, None, 5) | |
285 | if "AP-ENABLED" not in ev: | |
286 | raise Exception("Unexpected DFS event") | |
287 | dev[0].connect("dfs", key_mgmt="NONE") | |
288 | ||
289 | if hapd.get_status_field('vht_oper_centr_freq_seg0_idx') != "42": | |
290 | raise Exception("Unexpected seg0 idx") | |
291 | finally: | |
9d7fdac5 JM |
292 | dev[0].request("DISCONNECT") |
293 | if hapd: | |
294 | hapd.request("DISABLE") | |
c4668009 | 295 | subprocess.call(['iw', 'reg', 'set', '00']) |
9d7fdac5 | 296 | dev[0].flush_scan_cache() |
2a6cce38 JM |
297 | |
298 | def test_dfs_radar_chanlist_vht20(dev, apdev): | |
299 | """DFS chanlist when radar is detected and VHT40 configured""" | |
300 | try: | |
e246d7d5 | 301 | hapd = None |
8c6f6ac1 JM |
302 | hapd = start_dfs_ap(apdev[0], chanlist="36", vht20=True, |
303 | allow_failure=True) | |
2a6cce38 JM |
304 | time.sleep(1) |
305 | ||
306 | dfs_simulate_radar(hapd) | |
307 | ||
308 | ev = wait_dfs_event(hapd, "DFS-CAC-COMPLETED", 5) | |
309 | if ev is None: | |
310 | raise Exception("Timeout on DFS aborted event") | |
311 | if "success=0 freq=5260" not in ev: | |
312 | raise Exception("Unexpected DFS aborted event contents: " + ev) | |
313 | ||
314 | ev = wait_dfs_event(hapd, "DFS-RADAR-DETECTED", 5) | |
315 | if "freq=5260" not in ev: | |
316 | raise Exception("Unexpected DFS radar detection freq") | |
317 | ||
318 | ev = wait_dfs_event(hapd, "DFS-NEW-CHANNEL", 5) | |
319 | if "freq=5180 chan=36 sec_chan=0" not in ev: | |
320 | raise Exception("Unexpected DFS new freq: " + ev) | |
321 | ||
322 | ev = wait_dfs_event(hapd, None, 5) | |
323 | if "AP-ENABLED" not in ev: | |
324 | raise Exception("Unexpected DFS event") | |
325 | dev[0].connect("dfs", key_mgmt="NONE") | |
326 | finally: | |
9d7fdac5 JM |
327 | dev[0].request("DISCONNECT") |
328 | if hapd: | |
329 | hapd.request("DISABLE") | |
c4668009 | 330 | subprocess.call(['iw', 'reg', 'set', '00']) |
9d7fdac5 | 331 | dev[0].flush_scan_cache() |
d92da8a2 JM |
332 | |
333 | def test_dfs_radar_no_ht(dev, apdev): | |
334 | """DFS chanlist when radar is detected and no HT configured""" | |
335 | try: | |
e246d7d5 | 336 | hapd = None |
8c6f6ac1 JM |
337 | hapd = start_dfs_ap(apdev[0], chanlist="36", ht=False, |
338 | allow_failure=True) | |
d92da8a2 JM |
339 | time.sleep(1) |
340 | ||
341 | dfs_simulate_radar(hapd) | |
342 | ||
343 | ev = wait_dfs_event(hapd, "DFS-CAC-COMPLETED", 5) | |
344 | if ev is None: | |
345 | raise Exception("Timeout on DFS aborted event") | |
346 | if "success=0 freq=5260" not in ev: | |
347 | raise Exception("Unexpected DFS aborted event contents: " + ev) | |
348 | ||
349 | ev = wait_dfs_event(hapd, "DFS-RADAR-DETECTED", 5) | |
350 | if "freq=5260 ht_enabled=0" not in ev: | |
351 | raise Exception("Unexpected DFS radar detection freq: " + ev) | |
352 | ||
353 | ev = wait_dfs_event(hapd, "DFS-NEW-CHANNEL", 5) | |
354 | if "freq=5180 chan=36 sec_chan=0" not in ev: | |
355 | raise Exception("Unexpected DFS new freq: " + ev) | |
356 | ||
357 | ev = wait_dfs_event(hapd, None, 5) | |
358 | if "AP-ENABLED" not in ev: | |
359 | raise Exception("Unexpected DFS event") | |
360 | dev[0].connect("dfs", key_mgmt="NONE") | |
361 | finally: | |
362 | dev[0].request("DISCONNECT") | |
363 | if hapd: | |
364 | hapd.request("DISABLE") | |
365 | subprocess.call(['iw', 'reg', 'set', '00']) | |
366 | dev[0].flush_scan_cache() | |
367 | ||
368 | def test_dfs_radar_ht40minus(dev, apdev): | |
369 | """DFS chanlist when radar is detected and HT40- configured""" | |
370 | try: | |
e246d7d5 | 371 | hapd = None |
8c6f6ac1 JM |
372 | hapd = start_dfs_ap(apdev[0], chanlist="36", ht40minus=True, |
373 | allow_failure=True) | |
d92da8a2 JM |
374 | time.sleep(1) |
375 | ||
376 | dfs_simulate_radar(hapd) | |
377 | ||
378 | ev = wait_dfs_event(hapd, "DFS-CAC-COMPLETED", 5) | |
379 | if ev is None: | |
380 | raise Exception("Timeout on DFS aborted event") | |
381 | if "success=0 freq=5280 ht_enabled=1 chan_offset=-1" not in ev: | |
382 | raise Exception("Unexpected DFS aborted event contents: " + ev) | |
383 | ||
384 | ev = wait_dfs_event(hapd, "DFS-RADAR-DETECTED", 5) | |
385 | if "freq=5280 ht_enabled=1 chan_offset=-1" not in ev: | |
386 | raise Exception("Unexpected DFS radar detection freq: " + ev) | |
387 | ||
388 | ev = wait_dfs_event(hapd, "DFS-NEW-CHANNEL", 5) | |
389 | if "freq=5180 chan=36 sec_chan=1" not in ev: | |
390 | raise Exception("Unexpected DFS new freq: " + ev) | |
391 | ||
392 | ev = wait_dfs_event(hapd, None, 5) | |
393 | if "AP-ENABLED" not in ev: | |
394 | raise Exception("Unexpected DFS event") | |
395 | dev[0].connect("dfs", key_mgmt="NONE") | |
396 | finally: | |
397 | dev[0].request("DISCONNECT") | |
398 | if hapd: | |
399 | hapd.request("DISABLE") | |
400 | subprocess.call(['iw', 'reg', 'set', '00']) | |
401 | dev[0].flush_scan_cache() | |
803d0190 JM |
402 | |
403 | def test_dfs_ht40_minus(dev, apdev, params): | |
404 | """DFS CAC functionality on channel 104 HT40- [long]""" | |
405 | if not params['long']: | |
406 | raise HwsimSkip("Skip test case with long duration due to --long not specified") | |
407 | try: | |
408 | hapd = None | |
409 | hapd = start_dfs_ap(apdev[0], allow_failure=True, ht40minus=True, | |
410 | channel=104) | |
411 | ||
412 | ev = wait_dfs_event(hapd, "DFS-CAC-COMPLETED", 70) | |
413 | if "success=1" not in ev: | |
414 | raise Exception("CAC failed") | |
415 | if "freq=5520" not in ev: | |
416 | raise Exception("Unexpected DFS freq result") | |
417 | ||
418 | ev = hapd.wait_event(["AP-ENABLED"], timeout=5) | |
419 | if not ev: | |
420 | raise Exception("AP setup timed out") | |
421 | ||
422 | state = hapd.get_status_field("state") | |
423 | if state != "ENABLED": | |
424 | raise Exception("Unexpected interface state") | |
425 | ||
426 | freq = hapd.get_status_field("freq") | |
427 | if freq != "5520": | |
428 | raise Exception("Unexpected frequency") | |
429 | ||
430 | dev[0].connect("dfs", key_mgmt="NONE", scan_freq="5520") | |
431 | hwsim_utils.test_connectivity(dev[0], hapd) | |
432 | finally: | |
433 | dev[0].request("DISCONNECT") | |
434 | if hapd: | |
435 | hapd.request("DISABLE") | |
436 | subprocess.call(['iw', 'reg', 'set', '00']) | |
437 | dev[0].flush_scan_cache() |