dfs.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933
  1. /*
  2. * DFS - Dynamic Frequency Selection
  3. * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
  4. * Copyright (c) 2013, Qualcomm Atheros, Inc.
  5. *
  6. * This software may be distributed under the terms of the BSD license.
  7. * See README for more details.
  8. */
  9. #include "utils/includes.h"
  10. #include "utils/common.h"
  11. #include "common/ieee802_11_defs.h"
  12. #include "common/wpa_ctrl.h"
  13. #include "hostapd.h"
  14. #include "ap_drv_ops.h"
  15. #include "drivers/driver.h"
  16. #include "dfs.h"
  17. static int dfs_get_used_n_chans(struct hostapd_iface *iface)
  18. {
  19. int n_chans = 1;
  20. if (iface->conf->ieee80211n && iface->conf->secondary_channel)
  21. n_chans = 2;
  22. if (iface->conf->ieee80211ac) {
  23. switch (iface->conf->vht_oper_chwidth) {
  24. case VHT_CHANWIDTH_USE_HT:
  25. break;
  26. case VHT_CHANWIDTH_80MHZ:
  27. n_chans = 4;
  28. break;
  29. case VHT_CHANWIDTH_160MHZ:
  30. n_chans = 8;
  31. break;
  32. default:
  33. break;
  34. }
  35. }
  36. return n_chans;
  37. }
  38. static int dfs_channel_available(struct hostapd_channel_data *chan,
  39. int skip_radar)
  40. {
  41. /*
  42. * When radar detection happens, CSA is performed. However, there's no
  43. * time for CAC, so radar channels must be skipped when finding a new
  44. * channel for CSA, unless they are available for immediate use.
  45. */
  46. if (skip_radar && (chan->flag & HOSTAPD_CHAN_RADAR) &&
  47. ((chan->flag & HOSTAPD_CHAN_DFS_MASK) !=
  48. HOSTAPD_CHAN_DFS_AVAILABLE))
  49. return 0;
  50. if (chan->flag & HOSTAPD_CHAN_DISABLED)
  51. return 0;
  52. if ((chan->flag & HOSTAPD_CHAN_RADAR) &&
  53. ((chan->flag & HOSTAPD_CHAN_DFS_MASK) ==
  54. HOSTAPD_CHAN_DFS_UNAVAILABLE))
  55. return 0;
  56. return 1;
  57. }
  58. static int dfs_is_chan_allowed(struct hostapd_channel_data *chan, int n_chans)
  59. {
  60. /*
  61. * The tables contain first valid channel number based on channel width.
  62. * We will also choose this first channel as the control one.
  63. */
  64. int allowed_40[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
  65. 184, 192 };
  66. /*
  67. * VHT80, valid channels based on center frequency:
  68. * 42, 58, 106, 122, 138, 155
  69. */
  70. int allowed_80[] = { 36, 52, 100, 116, 132, 149 };
  71. /*
  72. * VHT160 valid channels based on center frequency:
  73. * 50, 114
  74. */
  75. int allowed_160[] = { 36, 100 };
  76. int *allowed = allowed_40;
  77. unsigned int i, allowed_no = 0;
  78. switch (n_chans) {
  79. case 2:
  80. allowed = allowed_40;
  81. allowed_no = ARRAY_SIZE(allowed_40);
  82. break;
  83. case 4:
  84. allowed = allowed_80;
  85. allowed_no = ARRAY_SIZE(allowed_80);
  86. break;
  87. case 8:
  88. allowed = allowed_160;
  89. allowed_no = ARRAY_SIZE(allowed_160);
  90. break;
  91. default:
  92. wpa_printf(MSG_DEBUG, "Unknown width for %d channels", n_chans);
  93. break;
  94. }
  95. for (i = 0; i < allowed_no; i++) {
  96. if (chan->chan == allowed[i])
  97. return 1;
  98. }
  99. return 0;
  100. }
  101. static int dfs_chan_range_available(struct hostapd_hw_modes *mode,
  102. int first_chan_idx, int num_chans,
  103. int skip_radar)
  104. {
  105. struct hostapd_channel_data *first_chan, *chan;
  106. int i;
  107. if (first_chan_idx + num_chans >= mode->num_channels)
  108. return 0;
  109. first_chan = &mode->channels[first_chan_idx];
  110. for (i = 0; i < num_chans; i++) {
  111. chan = &mode->channels[first_chan_idx + i];
  112. if (first_chan->freq + i * 20 != chan->freq)
  113. return 0;
  114. if (!dfs_channel_available(chan, skip_radar))
  115. return 0;
  116. }
  117. return 1;
  118. }
  119. static int is_in_chanlist(struct hostapd_iface *iface,
  120. struct hostapd_channel_data *chan)
  121. {
  122. int *entry;
  123. if (!iface->conf->chanlist)
  124. return 1;
  125. for (entry = iface->conf->chanlist; *entry != -1; entry++) {
  126. if (*entry == chan->chan)
  127. return 1;
  128. }
  129. return 0;
  130. }
  131. /*
  132. * The function assumes HT40+ operation.
  133. * Make sure to adjust the following variables after calling this:
  134. * - hapd->secondary_channel
  135. * - hapd->vht_oper_centr_freq_seg0_idx
  136. * - hapd->vht_oper_centr_freq_seg1_idx
  137. */
  138. static int dfs_find_channel(struct hostapd_iface *iface,
  139. struct hostapd_channel_data **ret_chan,
  140. int idx, int skip_radar)
  141. {
  142. struct hostapd_hw_modes *mode;
  143. struct hostapd_channel_data *chan;
  144. int i, channel_idx = 0, n_chans;
  145. mode = iface->current_mode;
  146. n_chans = dfs_get_used_n_chans(iface);
  147. wpa_printf(MSG_DEBUG, "DFS new chan checking %d channels", n_chans);
  148. for (i = 0; i < mode->num_channels; i++) {
  149. chan = &mode->channels[i];
  150. /* Skip HT40/VHT incompatible channels */
  151. if (iface->conf->ieee80211n &&
  152. iface->conf->secondary_channel &&
  153. !dfs_is_chan_allowed(chan, n_chans))
  154. continue;
  155. /* Skip incompatible chandefs */
  156. if (!dfs_chan_range_available(mode, i, n_chans, skip_radar))
  157. continue;
  158. if (!is_in_chanlist(iface, chan))
  159. continue;
  160. if (ret_chan && idx == channel_idx) {
  161. wpa_printf(MSG_DEBUG, "Selected ch. #%d", chan->chan);
  162. *ret_chan = chan;
  163. return idx;
  164. }
  165. wpa_printf(MSG_DEBUG, "Adding channel: %d", chan->chan);
  166. channel_idx++;
  167. }
  168. return channel_idx;
  169. }
  170. static void dfs_adjust_vht_center_freq(struct hostapd_iface *iface,
  171. struct hostapd_channel_data *chan,
  172. int secondary_channel,
  173. u8 *vht_oper_centr_freq_seg0_idx,
  174. u8 *vht_oper_centr_freq_seg1_idx)
  175. {
  176. if (!iface->conf->ieee80211ac)
  177. return;
  178. if (!chan)
  179. return;
  180. *vht_oper_centr_freq_seg1_idx = 0;
  181. switch (iface->conf->vht_oper_chwidth) {
  182. case VHT_CHANWIDTH_USE_HT:
  183. if (secondary_channel == 1)
  184. *vht_oper_centr_freq_seg0_idx = chan->chan + 2;
  185. else if (secondary_channel == -1)
  186. *vht_oper_centr_freq_seg0_idx = chan->chan - 2;
  187. else
  188. *vht_oper_centr_freq_seg0_idx = chan->chan;
  189. break;
  190. case VHT_CHANWIDTH_80MHZ:
  191. *vht_oper_centr_freq_seg0_idx = chan->chan + 6;
  192. break;
  193. case VHT_CHANWIDTH_160MHZ:
  194. *vht_oper_centr_freq_seg0_idx = chan->chan + 14;
  195. break;
  196. default:
  197. wpa_printf(MSG_INFO, "DFS only VHT20/40/80/160 is supported now");
  198. *vht_oper_centr_freq_seg0_idx = 0;
  199. break;
  200. }
  201. wpa_printf(MSG_DEBUG, "DFS adjusting VHT center frequency: %d, %d",
  202. *vht_oper_centr_freq_seg0_idx,
  203. *vht_oper_centr_freq_seg1_idx);
  204. }
  205. /* Return start channel idx we will use for mode->channels[idx] */
  206. static int dfs_get_start_chan_idx(struct hostapd_iface *iface)
  207. {
  208. struct hostapd_hw_modes *mode;
  209. struct hostapd_channel_data *chan;
  210. int channel_no = iface->conf->channel;
  211. int res = -1, i;
  212. /* HT40- */
  213. if (iface->conf->ieee80211n && iface->conf->secondary_channel == -1)
  214. channel_no -= 4;
  215. /* VHT */
  216. if (iface->conf->ieee80211ac) {
  217. switch (iface->conf->vht_oper_chwidth) {
  218. case VHT_CHANWIDTH_USE_HT:
  219. break;
  220. case VHT_CHANWIDTH_80MHZ:
  221. channel_no =
  222. iface->conf->vht_oper_centr_freq_seg0_idx - 6;
  223. break;
  224. case VHT_CHANWIDTH_160MHZ:
  225. channel_no =
  226. iface->conf->vht_oper_centr_freq_seg0_idx - 14;
  227. break;
  228. default:
  229. wpa_printf(MSG_INFO,
  230. "DFS only VHT20/40/80/160 is supported now");
  231. channel_no = -1;
  232. break;
  233. }
  234. }
  235. /* Get idx */
  236. mode = iface->current_mode;
  237. for (i = 0; i < mode->num_channels; i++) {
  238. chan = &mode->channels[i];
  239. if (chan->chan == channel_no) {
  240. res = i;
  241. break;
  242. }
  243. }
  244. if (res == -1) {
  245. wpa_printf(MSG_DEBUG,
  246. "DFS chan_idx seems wrong; num-ch: %d ch-no: %d conf-ch-no: %d 11n: %d sec-ch: %d vht-oper-width: %d",
  247. mode->num_channels, channel_no, iface->conf->channel,
  248. iface->conf->ieee80211n,
  249. iface->conf->secondary_channel,
  250. iface->conf->vht_oper_chwidth);
  251. for (i = 0; i < mode->num_channels; i++) {
  252. wpa_printf(MSG_DEBUG, "Available channel: %d",
  253. mode->channels[i].chan);
  254. }
  255. }
  256. return res;
  257. }
  258. /* At least one channel have radar flag */
  259. static int dfs_check_chans_radar(struct hostapd_iface *iface,
  260. int start_chan_idx, int n_chans)
  261. {
  262. struct hostapd_channel_data *channel;
  263. struct hostapd_hw_modes *mode;
  264. int i, res = 0;
  265. mode = iface->current_mode;
  266. for (i = 0; i < n_chans; i++) {
  267. channel = &mode->channels[start_chan_idx + i];
  268. if (channel->flag & HOSTAPD_CHAN_RADAR)
  269. res++;
  270. }
  271. return res;
  272. }
  273. /* All channels available */
  274. static int dfs_check_chans_available(struct hostapd_iface *iface,
  275. int start_chan_idx, int n_chans)
  276. {
  277. struct hostapd_channel_data *channel;
  278. struct hostapd_hw_modes *mode;
  279. int i;
  280. mode = iface->current_mode;
  281. for (i = 0; i < n_chans; i++) {
  282. channel = &mode->channels[start_chan_idx + i];
  283. if (channel->flag & HOSTAPD_CHAN_DISABLED)
  284. break;
  285. if (!(channel->flag & HOSTAPD_CHAN_RADAR))
  286. continue;
  287. if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) !=
  288. HOSTAPD_CHAN_DFS_AVAILABLE)
  289. break;
  290. }
  291. return i == n_chans;
  292. }
  293. /* At least one channel unavailable */
  294. static int dfs_check_chans_unavailable(struct hostapd_iface *iface,
  295. int start_chan_idx,
  296. int n_chans)
  297. {
  298. struct hostapd_channel_data *channel;
  299. struct hostapd_hw_modes *mode;
  300. int i, res = 0;
  301. mode = iface->current_mode;
  302. for (i = 0; i < n_chans; i++) {
  303. channel = &mode->channels[start_chan_idx + i];
  304. if (channel->flag & HOSTAPD_CHAN_DISABLED)
  305. res++;
  306. if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) ==
  307. HOSTAPD_CHAN_DFS_UNAVAILABLE)
  308. res++;
  309. }
  310. return res;
  311. }
  312. static struct hostapd_channel_data *
  313. dfs_get_valid_channel(struct hostapd_iface *iface,
  314. int *secondary_channel,
  315. u8 *vht_oper_centr_freq_seg0_idx,
  316. u8 *vht_oper_centr_freq_seg1_idx,
  317. int skip_radar)
  318. {
  319. struct hostapd_hw_modes *mode;
  320. struct hostapd_channel_data *chan = NULL;
  321. int num_available_chandefs;
  322. int chan_idx;
  323. u32 _rand;
  324. wpa_printf(MSG_DEBUG, "DFS: Selecting random channel");
  325. *secondary_channel = 0;
  326. *vht_oper_centr_freq_seg0_idx = 0;
  327. *vht_oper_centr_freq_seg1_idx = 0;
  328. if (iface->current_mode == NULL)
  329. return NULL;
  330. mode = iface->current_mode;
  331. if (mode->mode != HOSTAPD_MODE_IEEE80211A)
  332. return NULL;
  333. /* Get the count first */
  334. num_available_chandefs = dfs_find_channel(iface, NULL, 0, skip_radar);
  335. if (num_available_chandefs == 0)
  336. return NULL;
  337. os_get_random((u8 *) &_rand, sizeof(_rand));
  338. chan_idx = _rand % num_available_chandefs;
  339. dfs_find_channel(iface, &chan, chan_idx, skip_radar);
  340. /* dfs_find_channel() calculations assume HT40+ */
  341. if (iface->conf->secondary_channel)
  342. *secondary_channel = 1;
  343. else
  344. *secondary_channel = 0;
  345. dfs_adjust_vht_center_freq(iface, chan,
  346. *secondary_channel,
  347. vht_oper_centr_freq_seg0_idx,
  348. vht_oper_centr_freq_seg1_idx);
  349. return chan;
  350. }
  351. static int set_dfs_state_freq(struct hostapd_iface *iface, int freq, u32 state)
  352. {
  353. struct hostapd_hw_modes *mode;
  354. struct hostapd_channel_data *chan = NULL;
  355. int i;
  356. mode = iface->current_mode;
  357. if (mode == NULL)
  358. return 0;
  359. wpa_printf(MSG_DEBUG, "set_dfs_state 0x%X for %d MHz", state, freq);
  360. for (i = 0; i < iface->current_mode->num_channels; i++) {
  361. chan = &iface->current_mode->channels[i];
  362. if (chan->freq == freq) {
  363. if (chan->flag & HOSTAPD_CHAN_RADAR) {
  364. chan->flag &= ~HOSTAPD_CHAN_DFS_MASK;
  365. chan->flag |= state;
  366. return 1; /* Channel found */
  367. }
  368. }
  369. }
  370. wpa_printf(MSG_WARNING, "Can't set DFS state for freq %d MHz", freq);
  371. return 0;
  372. }
  373. static int set_dfs_state(struct hostapd_iface *iface, int freq, int ht_enabled,
  374. int chan_offset, int chan_width, int cf1,
  375. int cf2, u32 state)
  376. {
  377. int n_chans = 1, i;
  378. struct hostapd_hw_modes *mode;
  379. int frequency = freq;
  380. int ret = 0;
  381. mode = iface->current_mode;
  382. if (mode == NULL)
  383. return 0;
  384. if (mode->mode != HOSTAPD_MODE_IEEE80211A) {
  385. wpa_printf(MSG_WARNING, "current_mode != IEEE80211A");
  386. return 0;
  387. }
  388. /* Seems cf1 and chan_width is enough here */
  389. switch (chan_width) {
  390. case CHAN_WIDTH_20_NOHT:
  391. case CHAN_WIDTH_20:
  392. n_chans = 1;
  393. if (frequency == 0)
  394. frequency = cf1;
  395. break;
  396. case CHAN_WIDTH_40:
  397. n_chans = 2;
  398. frequency = cf1 - 10;
  399. break;
  400. case CHAN_WIDTH_80:
  401. n_chans = 4;
  402. frequency = cf1 - 30;
  403. break;
  404. case CHAN_WIDTH_160:
  405. n_chans = 8;
  406. frequency = cf1 - 70;
  407. break;
  408. default:
  409. wpa_printf(MSG_INFO, "DFS chan_width %d not supported",
  410. chan_width);
  411. break;
  412. }
  413. wpa_printf(MSG_DEBUG, "DFS freq: %dMHz, n_chans: %d", frequency,
  414. n_chans);
  415. for (i = 0; i < n_chans; i++) {
  416. ret += set_dfs_state_freq(iface, frequency, state);
  417. frequency = frequency + 20;
  418. }
  419. return ret;
  420. }
  421. static int dfs_are_channels_overlapped(struct hostapd_iface *iface, int freq,
  422. int chan_width, int cf1, int cf2)
  423. {
  424. int start_chan_idx;
  425. struct hostapd_hw_modes *mode;
  426. struct hostapd_channel_data *chan;
  427. int n_chans, i, j, frequency = freq, radar_n_chans = 1;
  428. u8 radar_chan;
  429. int res = 0;
  430. /* Our configuration */
  431. mode = iface->current_mode;
  432. start_chan_idx = dfs_get_start_chan_idx(iface);
  433. n_chans = dfs_get_used_n_chans(iface);
  434. /* Check we are on DFS channel(s) */
  435. if (!dfs_check_chans_radar(iface, start_chan_idx, n_chans))
  436. return 0;
  437. /* Reported via radar event */
  438. switch (chan_width) {
  439. case CHAN_WIDTH_20_NOHT:
  440. case CHAN_WIDTH_20:
  441. radar_n_chans = 1;
  442. if (frequency == 0)
  443. frequency = cf1;
  444. break;
  445. case CHAN_WIDTH_40:
  446. radar_n_chans = 2;
  447. frequency = cf1 - 10;
  448. break;
  449. case CHAN_WIDTH_80:
  450. radar_n_chans = 4;
  451. frequency = cf1 - 30;
  452. break;
  453. case CHAN_WIDTH_160:
  454. radar_n_chans = 8;
  455. frequency = cf1 - 70;
  456. break;
  457. default:
  458. wpa_printf(MSG_INFO, "DFS chan_width %d not supported",
  459. chan_width);
  460. break;
  461. }
  462. ieee80211_freq_to_chan(frequency, &radar_chan);
  463. for (i = 0; i < n_chans; i++) {
  464. chan = &mode->channels[start_chan_idx + i];
  465. if (!(chan->flag & HOSTAPD_CHAN_RADAR))
  466. continue;
  467. for (j = 0; j < radar_n_chans; j++) {
  468. wpa_printf(MSG_DEBUG, "checking our: %d, radar: %d",
  469. chan->chan, radar_chan + j * 4);
  470. if (chan->chan == radar_chan + j * 4)
  471. res++;
  472. }
  473. }
  474. wpa_printf(MSG_DEBUG, "overlapped: %d", res);
  475. return res;
  476. }
  477. static unsigned int dfs_get_cac_time(struct hostapd_iface *iface,
  478. int start_chan_idx, int n_chans)
  479. {
  480. struct hostapd_channel_data *channel;
  481. struct hostapd_hw_modes *mode;
  482. int i;
  483. unsigned int cac_time_ms = 0;
  484. mode = iface->current_mode;
  485. for (i = 0; i < n_chans; i++) {
  486. channel = &mode->channels[start_chan_idx + i];
  487. if (!(channel->flag & HOSTAPD_CHAN_RADAR))
  488. continue;
  489. if (channel->dfs_cac_ms > cac_time_ms)
  490. cac_time_ms = channel->dfs_cac_ms;
  491. }
  492. return cac_time_ms;
  493. }
  494. /*
  495. * Main DFS handler
  496. * 1 - continue channel/ap setup
  497. * 0 - channel/ap setup will be continued after CAC
  498. * -1 - hit critical error
  499. */
  500. int hostapd_handle_dfs(struct hostapd_iface *iface)
  501. {
  502. struct hostapd_channel_data *channel;
  503. int res, n_chans, start_chan_idx;
  504. int skip_radar = 0;
  505. iface->cac_started = 0;
  506. do {
  507. /* Get start (first) channel for current configuration */
  508. start_chan_idx = dfs_get_start_chan_idx(iface);
  509. if (start_chan_idx == -1)
  510. return -1;
  511. /* Get number of used channels, depend on width */
  512. n_chans = dfs_get_used_n_chans(iface);
  513. /* Setup CAC time */
  514. iface->dfs_cac_ms = dfs_get_cac_time(iface, start_chan_idx,
  515. n_chans);
  516. /* Check if any of configured channels require DFS */
  517. res = dfs_check_chans_radar(iface, start_chan_idx, n_chans);
  518. wpa_printf(MSG_DEBUG,
  519. "DFS %d channels required radar detection",
  520. res);
  521. if (!res)
  522. return 1;
  523. /* Check if all channels are DFS available */
  524. res = dfs_check_chans_available(iface, start_chan_idx, n_chans);
  525. wpa_printf(MSG_DEBUG,
  526. "DFS all channels available, (SKIP CAC): %s",
  527. res ? "yes" : "no");
  528. if (res)
  529. return 1;
  530. /* Check if any of configured channels is unavailable */
  531. res = dfs_check_chans_unavailable(iface, start_chan_idx,
  532. n_chans);
  533. wpa_printf(MSG_DEBUG, "DFS %d chans unavailable - choose other channel: %s",
  534. res, res ? "yes": "no");
  535. if (res) {
  536. int sec = 0;
  537. u8 cf1 = 0, cf2 = 0;
  538. channel = dfs_get_valid_channel(iface, &sec, &cf1, &cf2,
  539. skip_radar);
  540. if (!channel) {
  541. wpa_printf(MSG_ERROR, "could not get valid channel");
  542. return -1;
  543. }
  544. iface->freq = channel->freq;
  545. iface->conf->channel = channel->chan;
  546. iface->conf->secondary_channel = sec;
  547. iface->conf->vht_oper_centr_freq_seg0_idx = cf1;
  548. iface->conf->vht_oper_centr_freq_seg1_idx = cf2;
  549. }
  550. } while (res);
  551. /* Finally start CAC */
  552. hostapd_set_state(iface, HAPD_IFACE_DFS);
  553. wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz", iface->freq);
  554. wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START
  555. "freq=%d chan=%d sec_chan=%d, width=%d, seg0=%d, seg1=%d, cac_time=%ds",
  556. iface->freq,
  557. iface->conf->channel, iface->conf->secondary_channel,
  558. iface->conf->vht_oper_chwidth,
  559. iface->conf->vht_oper_centr_freq_seg0_idx,
  560. iface->conf->vht_oper_centr_freq_seg1_idx,
  561. iface->dfs_cac_ms / 1000);
  562. res = hostapd_start_dfs_cac(iface, iface->conf->hw_mode,
  563. iface->freq,
  564. iface->conf->channel,
  565. iface->conf->ieee80211n,
  566. iface->conf->ieee80211ac,
  567. iface->conf->secondary_channel,
  568. iface->conf->vht_oper_chwidth,
  569. iface->conf->vht_oper_centr_freq_seg0_idx,
  570. iface->conf->vht_oper_centr_freq_seg1_idx);
  571. if (res) {
  572. wpa_printf(MSG_ERROR, "DFS start_dfs_cac() failed, %d", res);
  573. return -1;
  574. }
  575. return 0;
  576. }
  577. int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
  578. int ht_enabled, int chan_offset, int chan_width,
  579. int cf1, int cf2)
  580. {
  581. wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_COMPLETED
  582. "success=%d freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
  583. success, freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
  584. if (success) {
  585. /* Complete iface/ap configuration */
  586. set_dfs_state(iface, freq, ht_enabled, chan_offset,
  587. chan_width, cf1, cf2,
  588. HOSTAPD_CHAN_DFS_AVAILABLE);
  589. iface->cac_started = 0;
  590. hostapd_setup_interface_complete(iface, 0);
  591. }
  592. return 0;
  593. }
  594. static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
  595. {
  596. struct hostapd_channel_data *channel;
  597. int secondary_channel;
  598. u8 vht_oper_centr_freq_seg0_idx = 0;
  599. u8 vht_oper_centr_freq_seg1_idx = 0;
  600. int skip_radar = 0;
  601. int err = 1;
  602. /* Radar detected during active CAC */
  603. iface->cac_started = 0;
  604. channel = dfs_get_valid_channel(iface, &secondary_channel,
  605. &vht_oper_centr_freq_seg0_idx,
  606. &vht_oper_centr_freq_seg1_idx,
  607. skip_radar);
  608. if (!channel) {
  609. wpa_printf(MSG_ERROR, "No valid channel available");
  610. hostapd_setup_interface_complete(iface, err);
  611. return err;
  612. }
  613. wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
  614. channel->chan);
  615. wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
  616. "freq=%d chan=%d sec_chan=%d", channel->freq,
  617. channel->chan, secondary_channel);
  618. iface->freq = channel->freq;
  619. iface->conf->channel = channel->chan;
  620. iface->conf->secondary_channel = secondary_channel;
  621. iface->conf->vht_oper_centr_freq_seg0_idx =
  622. vht_oper_centr_freq_seg0_idx;
  623. iface->conf->vht_oper_centr_freq_seg1_idx =
  624. vht_oper_centr_freq_seg1_idx;
  625. err = 0;
  626. hostapd_setup_interface_complete(iface, err);
  627. return err;
  628. }
  629. static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
  630. {
  631. struct hostapd_channel_data *channel;
  632. int secondary_channel;
  633. u8 vht_oper_centr_freq_seg0_idx;
  634. u8 vht_oper_centr_freq_seg1_idx;
  635. int skip_radar = 1;
  636. struct csa_settings csa_settings;
  637. struct hostapd_data *hapd = iface->bss[0];
  638. int err = 1;
  639. wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)",
  640. __func__, iface->cac_started ? "yes" : "no",
  641. iface->csa_in_progress ? "yes" : "no");
  642. /* Check if CSA in progress */
  643. if (iface->csa_in_progress)
  644. return 0;
  645. /* Check if active CAC */
  646. if (iface->cac_started)
  647. return hostapd_dfs_start_channel_switch_cac(iface);
  648. /* Perform channel switch/CSA */
  649. channel = dfs_get_valid_channel(iface, &secondary_channel,
  650. &vht_oper_centr_freq_seg0_idx,
  651. &vht_oper_centr_freq_seg1_idx,
  652. skip_radar);
  653. if (!channel) {
  654. /*
  655. * If there is no channel to switch immediately to, check if
  656. * there is another channel where we can switch even if it
  657. * requires to perform a CAC first.
  658. */
  659. skip_radar = 0;
  660. channel = dfs_get_valid_channel(iface, &secondary_channel,
  661. &vht_oper_centr_freq_seg0_idx,
  662. &vht_oper_centr_freq_seg1_idx,
  663. skip_radar);
  664. if (!channel) {
  665. /* FIXME: Wait for channel(s) to become available */
  666. hostapd_disable_iface(iface);
  667. return err;
  668. }
  669. iface->freq = channel->freq;
  670. iface->conf->channel = channel->chan;
  671. iface->conf->secondary_channel = secondary_channel;
  672. iface->conf->vht_oper_centr_freq_seg0_idx =
  673. vht_oper_centr_freq_seg0_idx;
  674. iface->conf->vht_oper_centr_freq_seg1_idx =
  675. vht_oper_centr_freq_seg1_idx;
  676. hostapd_disable_iface(iface);
  677. hostapd_enable_iface(iface);
  678. return 0;
  679. }
  680. wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
  681. channel->chan);
  682. wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
  683. "freq=%d chan=%d sec_chan=%d", channel->freq,
  684. channel->chan, secondary_channel);
  685. /* Setup CSA request */
  686. os_memset(&csa_settings, 0, sizeof(csa_settings));
  687. csa_settings.cs_count = 5;
  688. csa_settings.block_tx = 1;
  689. err = hostapd_set_freq_params(&csa_settings.freq_params,
  690. iface->conf->hw_mode,
  691. channel->freq,
  692. channel->chan,
  693. iface->conf->ieee80211n,
  694. iface->conf->ieee80211ac,
  695. secondary_channel,
  696. iface->conf->vht_oper_chwidth,
  697. vht_oper_centr_freq_seg0_idx,
  698. vht_oper_centr_freq_seg1_idx,
  699. iface->current_mode->vht_capab);
  700. if (err) {
  701. wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params");
  702. hostapd_disable_iface(iface);
  703. return err;
  704. }
  705. err = hostapd_switch_channel(hapd, &csa_settings);
  706. if (err) {
  707. wpa_printf(MSG_WARNING, "DFS failed to schedule CSA (%d) - trying fallback",
  708. err);
  709. iface->freq = channel->freq;
  710. iface->conf->channel = channel->chan;
  711. iface->conf->secondary_channel = secondary_channel;
  712. iface->conf->vht_oper_centr_freq_seg0_idx =
  713. vht_oper_centr_freq_seg0_idx;
  714. iface->conf->vht_oper_centr_freq_seg1_idx =
  715. vht_oper_centr_freq_seg1_idx;
  716. hostapd_disable_iface(iface);
  717. hostapd_enable_iface(iface);
  718. return 0;
  719. }
  720. /* Channel configuration will be updated once CSA completes and
  721. * ch_switch_notify event is received */
  722. wpa_printf(MSG_DEBUG, "DFS waiting channel switch event");
  723. return 0;
  724. }
  725. int hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq,
  726. int ht_enabled, int chan_offset, int chan_width,
  727. int cf1, int cf2)
  728. {
  729. int res;
  730. if (!iface->conf->ieee80211h)
  731. return 0;
  732. wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_RADAR_DETECTED
  733. "freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
  734. freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
  735. /* mark radar frequency as invalid */
  736. res = set_dfs_state(iface, freq, ht_enabled, chan_offset,
  737. chan_width, cf1, cf2,
  738. HOSTAPD_CHAN_DFS_UNAVAILABLE);
  739. /* Skip if reported radar event not overlapped our channels */
  740. res = dfs_are_channels_overlapped(iface, freq, chan_width, cf1, cf2);
  741. if (!res)
  742. return 0;
  743. /* radar detected while operating, switch the channel. */
  744. res = hostapd_dfs_start_channel_switch(iface);
  745. return res;
  746. }
  747. int hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq,
  748. int ht_enabled, int chan_offset, int chan_width,
  749. int cf1, int cf2)
  750. {
  751. wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NOP_FINISHED
  752. "freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
  753. freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
  754. /* TODO add correct implementation here */
  755. set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
  756. cf1, cf2, HOSTAPD_CHAN_DFS_USABLE);
  757. return 0;
  758. }
  759. int hostapd_is_dfs_required(struct hostapd_iface *iface)
  760. {
  761. int n_chans, start_chan_idx;
  762. if (!iface->conf->ieee80211h || !iface->current_mode ||
  763. iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A)
  764. return 0;
  765. /* Get start (first) channel for current configuration */
  766. start_chan_idx = dfs_get_start_chan_idx(iface);
  767. if (start_chan_idx == -1)
  768. return -1;
  769. /* Get number of used channels, depend on width */
  770. n_chans = dfs_get_used_n_chans(iface);
  771. /* Check if any of configured channels require DFS */
  772. return dfs_check_chans_radar(iface, start_chan_idx, n_chans);
  773. }