dfs.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870
  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, "DFS chan_idx seems wrong: -1");
  246. return res;
  247. }
  248. /* At least one channel have radar flag */
  249. static int dfs_check_chans_radar(struct hostapd_iface *iface,
  250. int start_chan_idx, int n_chans)
  251. {
  252. struct hostapd_channel_data *channel;
  253. struct hostapd_hw_modes *mode;
  254. int i, res = 0;
  255. mode = iface->current_mode;
  256. for (i = 0; i < n_chans; i++) {
  257. channel = &mode->channels[start_chan_idx + i];
  258. if (channel->flag & HOSTAPD_CHAN_RADAR)
  259. res++;
  260. }
  261. return res;
  262. }
  263. /* All channels available */
  264. static int dfs_check_chans_available(struct hostapd_iface *iface,
  265. int start_chan_idx, int n_chans)
  266. {
  267. struct hostapd_channel_data *channel;
  268. struct hostapd_hw_modes *mode;
  269. int i;
  270. mode = iface->current_mode;
  271. for (i = 0; i < n_chans; i++) {
  272. channel = &mode->channels[start_chan_idx + i];
  273. if (channel->flag & HOSTAPD_CHAN_DISABLED)
  274. break;
  275. if (!(channel->flag & HOSTAPD_CHAN_RADAR))
  276. continue;
  277. if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) !=
  278. HOSTAPD_CHAN_DFS_AVAILABLE)
  279. break;
  280. }
  281. return i == n_chans;
  282. }
  283. /* At least one channel unavailable */
  284. static int dfs_check_chans_unavailable(struct hostapd_iface *iface,
  285. int start_chan_idx,
  286. int n_chans)
  287. {
  288. struct hostapd_channel_data *channel;
  289. struct hostapd_hw_modes *mode;
  290. int i, res = 0;
  291. mode = iface->current_mode;
  292. for (i = 0; i < n_chans; i++) {
  293. channel = &mode->channels[start_chan_idx + i];
  294. if (channel->flag & HOSTAPD_CHAN_DISABLED)
  295. res++;
  296. if ((channel->flag & HOSTAPD_CHAN_DFS_MASK) ==
  297. HOSTAPD_CHAN_DFS_UNAVAILABLE)
  298. res++;
  299. }
  300. return res;
  301. }
  302. static struct hostapd_channel_data *
  303. dfs_get_valid_channel(struct hostapd_iface *iface,
  304. int *secondary_channel,
  305. u8 *vht_oper_centr_freq_seg0_idx,
  306. u8 *vht_oper_centr_freq_seg1_idx,
  307. int skip_radar)
  308. {
  309. struct hostapd_hw_modes *mode;
  310. struct hostapd_channel_data *chan = NULL;
  311. int num_available_chandefs;
  312. int chan_idx;
  313. u32 _rand;
  314. wpa_printf(MSG_DEBUG, "DFS: Selecting random channel");
  315. *secondary_channel = 0;
  316. *vht_oper_centr_freq_seg0_idx = 0;
  317. *vht_oper_centr_freq_seg1_idx = 0;
  318. if (iface->current_mode == NULL)
  319. return NULL;
  320. mode = iface->current_mode;
  321. if (mode->mode != HOSTAPD_MODE_IEEE80211A)
  322. return NULL;
  323. /* Get the count first */
  324. num_available_chandefs = dfs_find_channel(iface, NULL, 0, skip_radar);
  325. if (num_available_chandefs == 0)
  326. return NULL;
  327. os_get_random((u8 *) &_rand, sizeof(_rand));
  328. chan_idx = _rand % num_available_chandefs;
  329. dfs_find_channel(iface, &chan, chan_idx, skip_radar);
  330. /* dfs_find_channel() calculations assume HT40+ */
  331. if (iface->conf->secondary_channel)
  332. *secondary_channel = 1;
  333. else
  334. *secondary_channel = 0;
  335. dfs_adjust_vht_center_freq(iface, chan,
  336. *secondary_channel,
  337. vht_oper_centr_freq_seg0_idx,
  338. vht_oper_centr_freq_seg1_idx);
  339. return chan;
  340. }
  341. static int set_dfs_state_freq(struct hostapd_iface *iface, int freq, u32 state)
  342. {
  343. struct hostapd_hw_modes *mode;
  344. struct hostapd_channel_data *chan = NULL;
  345. int i;
  346. mode = iface->current_mode;
  347. if (mode == NULL)
  348. return 0;
  349. wpa_printf(MSG_DEBUG, "set_dfs_state 0x%X for %d MHz", state, freq);
  350. for (i = 0; i < iface->current_mode->num_channels; i++) {
  351. chan = &iface->current_mode->channels[i];
  352. if (chan->freq == freq) {
  353. if (chan->flag & HOSTAPD_CHAN_RADAR) {
  354. chan->flag &= ~HOSTAPD_CHAN_DFS_MASK;
  355. chan->flag |= state;
  356. return 1; /* Channel found */
  357. }
  358. }
  359. }
  360. wpa_printf(MSG_WARNING, "Can't set DFS state for freq %d MHz", freq);
  361. return 0;
  362. }
  363. static int set_dfs_state(struct hostapd_iface *iface, int freq, int ht_enabled,
  364. int chan_offset, int chan_width, int cf1,
  365. int cf2, u32 state)
  366. {
  367. int n_chans = 1, i;
  368. struct hostapd_hw_modes *mode;
  369. int frequency = freq;
  370. int ret = 0;
  371. mode = iface->current_mode;
  372. if (mode == NULL)
  373. return 0;
  374. if (mode->mode != HOSTAPD_MODE_IEEE80211A) {
  375. wpa_printf(MSG_WARNING, "current_mode != IEEE80211A");
  376. return 0;
  377. }
  378. /* Seems cf1 and chan_width is enough here */
  379. switch (chan_width) {
  380. case CHAN_WIDTH_20_NOHT:
  381. case CHAN_WIDTH_20:
  382. n_chans = 1;
  383. if (frequency == 0)
  384. frequency = cf1;
  385. break;
  386. case CHAN_WIDTH_40:
  387. n_chans = 2;
  388. frequency = cf1 - 10;
  389. break;
  390. case CHAN_WIDTH_80:
  391. n_chans = 4;
  392. frequency = cf1 - 30;
  393. break;
  394. case CHAN_WIDTH_160:
  395. n_chans = 8;
  396. frequency = cf1 - 70;
  397. break;
  398. default:
  399. wpa_printf(MSG_INFO, "DFS chan_width %d not supported",
  400. chan_width);
  401. break;
  402. }
  403. wpa_printf(MSG_DEBUG, "DFS freq: %dMHz, n_chans: %d", frequency,
  404. n_chans);
  405. for (i = 0; i < n_chans; i++) {
  406. ret += set_dfs_state_freq(iface, frequency, state);
  407. frequency = frequency + 20;
  408. }
  409. return ret;
  410. }
  411. static int dfs_are_channels_overlapped(struct hostapd_iface *iface, int freq,
  412. int chan_width, int cf1, int cf2)
  413. {
  414. int start_chan_idx;
  415. struct hostapd_hw_modes *mode;
  416. struct hostapd_channel_data *chan;
  417. int n_chans, i, j, frequency = freq, radar_n_chans = 1;
  418. u8 radar_chan;
  419. int res = 0;
  420. /* Our configuration */
  421. mode = iface->current_mode;
  422. start_chan_idx = dfs_get_start_chan_idx(iface);
  423. n_chans = dfs_get_used_n_chans(iface);
  424. /* Check we are on DFS channel(s) */
  425. if (!dfs_check_chans_radar(iface, start_chan_idx, n_chans))
  426. return 0;
  427. /* Reported via radar event */
  428. switch (chan_width) {
  429. case CHAN_WIDTH_20_NOHT:
  430. case CHAN_WIDTH_20:
  431. radar_n_chans = 1;
  432. if (frequency == 0)
  433. frequency = cf1;
  434. break;
  435. case CHAN_WIDTH_40:
  436. radar_n_chans = 2;
  437. frequency = cf1 - 10;
  438. break;
  439. case CHAN_WIDTH_80:
  440. radar_n_chans = 4;
  441. frequency = cf1 - 30;
  442. break;
  443. case CHAN_WIDTH_160:
  444. radar_n_chans = 8;
  445. frequency = cf1 - 70;
  446. break;
  447. default:
  448. wpa_printf(MSG_INFO, "DFS chan_width %d not supported",
  449. chan_width);
  450. break;
  451. }
  452. ieee80211_freq_to_chan(frequency, &radar_chan);
  453. for (i = 0; i < n_chans; i++) {
  454. chan = &mode->channels[start_chan_idx + i];
  455. if (!(chan->flag & HOSTAPD_CHAN_RADAR))
  456. continue;
  457. for (j = 0; j < radar_n_chans; j++) {
  458. wpa_printf(MSG_DEBUG, "checking our: %d, radar: %d",
  459. chan->chan, radar_chan + j * 4);
  460. if (chan->chan == radar_chan + j * 4)
  461. res++;
  462. }
  463. }
  464. wpa_printf(MSG_DEBUG, "overlapped: %d", res);
  465. return res;
  466. }
  467. /*
  468. * Main DFS handler
  469. * 1 - continue channel/ap setup
  470. * 0 - channel/ap setup will be continued after CAC
  471. * -1 - hit critical error
  472. */
  473. int hostapd_handle_dfs(struct hostapd_iface *iface)
  474. {
  475. struct hostapd_channel_data *channel;
  476. int res, n_chans, start_chan_idx;
  477. int skip_radar = 0;
  478. iface->cac_started = 0;
  479. do {
  480. /* Get start (first) channel for current configuration */
  481. start_chan_idx = dfs_get_start_chan_idx(iface);
  482. if (start_chan_idx == -1)
  483. return -1;
  484. /* Get number of used channels, depend on width */
  485. n_chans = dfs_get_used_n_chans(iface);
  486. /* Check if any of configured channels require DFS */
  487. res = dfs_check_chans_radar(iface, start_chan_idx, n_chans);
  488. wpa_printf(MSG_DEBUG,
  489. "DFS %d channels required radar detection",
  490. res);
  491. if (!res)
  492. return 1;
  493. /* Check if all channels are DFS available */
  494. res = dfs_check_chans_available(iface, start_chan_idx, n_chans);
  495. wpa_printf(MSG_DEBUG,
  496. "DFS all channels available, (SKIP CAC): %s",
  497. res ? "yes" : "no");
  498. if (res)
  499. return 1;
  500. /* Check if any of configured channels is unavailable */
  501. res = dfs_check_chans_unavailable(iface, start_chan_idx,
  502. n_chans);
  503. wpa_printf(MSG_DEBUG, "DFS %d chans unavailable - choose other channel: %s",
  504. res, res ? "yes": "no");
  505. if (res) {
  506. int sec = 0;
  507. u8 cf1 = 0, cf2 = 0;
  508. channel = dfs_get_valid_channel(iface, &sec, &cf1, &cf2,
  509. skip_radar);
  510. if (!channel) {
  511. wpa_printf(MSG_ERROR, "could not get valid channel");
  512. return -1;
  513. }
  514. iface->freq = channel->freq;
  515. iface->conf->channel = channel->chan;
  516. iface->conf->secondary_channel = sec;
  517. iface->conf->vht_oper_centr_freq_seg0_idx = cf1;
  518. iface->conf->vht_oper_centr_freq_seg1_idx = cf2;
  519. }
  520. } while (res);
  521. /* Finally start CAC */
  522. hostapd_set_state(iface, HAPD_IFACE_DFS);
  523. wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz", iface->freq);
  524. wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START
  525. "freq=%d chan=%d sec_chan=%d, width=%d, seg0=%d, seg1=%d",
  526. iface->freq,
  527. iface->conf->channel, iface->conf->secondary_channel,
  528. iface->conf->vht_oper_chwidth,
  529. iface->conf->vht_oper_centr_freq_seg0_idx,
  530. iface->conf->vht_oper_centr_freq_seg1_idx);
  531. res = hostapd_start_dfs_cac(iface, iface->conf->hw_mode,
  532. iface->freq,
  533. iface->conf->channel,
  534. iface->conf->ieee80211n,
  535. iface->conf->ieee80211ac,
  536. iface->conf->secondary_channel,
  537. iface->conf->vht_oper_chwidth,
  538. iface->conf->vht_oper_centr_freq_seg0_idx,
  539. iface->conf->vht_oper_centr_freq_seg1_idx);
  540. if (res) {
  541. wpa_printf(MSG_ERROR, "DFS start_dfs_cac() failed, %d", res);
  542. return -1;
  543. }
  544. return 0;
  545. }
  546. int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
  547. int ht_enabled, int chan_offset, int chan_width,
  548. int cf1, int cf2)
  549. {
  550. wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_COMPLETED
  551. "success=%d freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
  552. success, freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
  553. if (success) {
  554. /* Complete iface/ap configuration */
  555. set_dfs_state(iface, freq, ht_enabled, chan_offset,
  556. chan_width, cf1, cf2,
  557. HOSTAPD_CHAN_DFS_AVAILABLE);
  558. iface->cac_started = 0;
  559. hostapd_setup_interface_complete(iface, 0);
  560. }
  561. return 0;
  562. }
  563. static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
  564. {
  565. struct hostapd_channel_data *channel;
  566. int secondary_channel;
  567. u8 vht_oper_centr_freq_seg0_idx = 0;
  568. u8 vht_oper_centr_freq_seg1_idx = 0;
  569. int skip_radar = 0;
  570. int err = 1;
  571. /* Radar detected during active CAC */
  572. iface->cac_started = 0;
  573. channel = dfs_get_valid_channel(iface, &secondary_channel,
  574. &vht_oper_centr_freq_seg0_idx,
  575. &vht_oper_centr_freq_seg1_idx,
  576. skip_radar);
  577. if (!channel) {
  578. wpa_printf(MSG_ERROR, "No valid channel available");
  579. hostapd_setup_interface_complete(iface, err);
  580. return err;
  581. }
  582. wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
  583. channel->chan);
  584. wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
  585. "freq=%d chan=%d sec_chan=%d", channel->freq,
  586. channel->chan, secondary_channel);
  587. iface->freq = channel->freq;
  588. iface->conf->channel = channel->chan;
  589. iface->conf->secondary_channel = secondary_channel;
  590. iface->conf->vht_oper_centr_freq_seg0_idx =
  591. vht_oper_centr_freq_seg0_idx;
  592. iface->conf->vht_oper_centr_freq_seg1_idx =
  593. vht_oper_centr_freq_seg1_idx;
  594. err = 0;
  595. hostapd_setup_interface_complete(iface, err);
  596. return err;
  597. }
  598. static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
  599. {
  600. struct hostapd_channel_data *channel;
  601. int secondary_channel;
  602. u8 vht_oper_centr_freq_seg0_idx;
  603. u8 vht_oper_centr_freq_seg1_idx;
  604. int skip_radar = 1;
  605. struct csa_settings csa_settings;
  606. struct hostapd_data *hapd = iface->bss[0];
  607. int err = 1;
  608. wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)",
  609. __func__, iface->cac_started ? "yes" : "no",
  610. iface->csa_in_progress ? "yes" : "no");
  611. /* Check if CSA in progress */
  612. if (iface->csa_in_progress)
  613. return 0;
  614. /* Check if active CAC */
  615. if (iface->cac_started)
  616. return hostapd_dfs_start_channel_switch_cac(iface);
  617. /* Perform channel switch/CSA */
  618. channel = dfs_get_valid_channel(iface, &secondary_channel,
  619. &vht_oper_centr_freq_seg0_idx,
  620. &vht_oper_centr_freq_seg1_idx,
  621. skip_radar);
  622. if (!channel) {
  623. /* FIXME: Wait for channel(s) to become available */
  624. hostapd_disable_iface(iface);
  625. return err;
  626. }
  627. wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
  628. channel->chan);
  629. wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
  630. "freq=%d chan=%d sec_chan=%d", channel->freq,
  631. channel->chan, secondary_channel);
  632. /* Setup CSA request */
  633. os_memset(&csa_settings, 0, sizeof(csa_settings));
  634. csa_settings.cs_count = 5;
  635. csa_settings.block_tx = 1;
  636. err = hostapd_set_freq_params(&csa_settings.freq_params,
  637. iface->conf->hw_mode,
  638. channel->freq,
  639. channel->chan,
  640. iface->conf->ieee80211n,
  641. iface->conf->ieee80211ac,
  642. secondary_channel,
  643. iface->conf->vht_oper_chwidth,
  644. vht_oper_centr_freq_seg0_idx,
  645. vht_oper_centr_freq_seg1_idx,
  646. iface->current_mode->vht_capab);
  647. if (err) {
  648. wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params");
  649. hostapd_disable_iface(iface);
  650. return err;
  651. }
  652. err = hostapd_switch_channel(hapd, &csa_settings);
  653. if (err) {
  654. wpa_printf(MSG_WARNING, "DFS failed to schedule CSA (%d) - trying fallback",
  655. err);
  656. iface->freq = channel->freq;
  657. iface->conf->channel = channel->chan;
  658. iface->conf->secondary_channel = secondary_channel;
  659. iface->conf->vht_oper_centr_freq_seg0_idx =
  660. vht_oper_centr_freq_seg0_idx;
  661. iface->conf->vht_oper_centr_freq_seg1_idx =
  662. vht_oper_centr_freq_seg1_idx;
  663. hostapd_disable_iface(iface);
  664. hostapd_enable_iface(iface);
  665. return 0;
  666. }
  667. /* Channel configuration will be updated once CSA completes and
  668. * ch_switch_notify event is received */
  669. wpa_printf(MSG_DEBUG, "DFS waiting channel switch event");
  670. return 0;
  671. }
  672. int hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq,
  673. int ht_enabled, int chan_offset, int chan_width,
  674. int cf1, int cf2)
  675. {
  676. int res;
  677. if (!iface->conf->ieee80211h)
  678. return 0;
  679. wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_RADAR_DETECTED
  680. "freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
  681. freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
  682. /* mark radar frequency as invalid */
  683. res = set_dfs_state(iface, freq, ht_enabled, chan_offset,
  684. chan_width, cf1, cf2,
  685. HOSTAPD_CHAN_DFS_UNAVAILABLE);
  686. /* Skip if reported radar event not overlapped our channels */
  687. res = dfs_are_channels_overlapped(iface, freq, chan_width, cf1, cf2);
  688. if (!res)
  689. return 0;
  690. /* radar detected while operating, switch the channel. */
  691. res = hostapd_dfs_start_channel_switch(iface);
  692. return res;
  693. }
  694. int hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq,
  695. int ht_enabled, int chan_offset, int chan_width,
  696. int cf1, int cf2)
  697. {
  698. wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NOP_FINISHED
  699. "freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
  700. freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
  701. /* TODO add correct implementation here */
  702. set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
  703. cf1, cf2, HOSTAPD_CHAN_DFS_USABLE);
  704. return 0;
  705. }
  706. int hostapd_is_dfs_required(struct hostapd_iface *iface)
  707. {
  708. int n_chans, start_chan_idx;
  709. if (!iface->current_mode)
  710. return -1;
  711. /* Get start (first) channel for current configuration */
  712. start_chan_idx = dfs_get_start_chan_idx(iface);
  713. if (start_chan_idx == -1)
  714. return -1;
  715. /* Get number of used channels, depend on width */
  716. n_chans = dfs_get_used_n_chans(iface);
  717. /* Check if any of configured channels require DFS */
  718. return dfs_check_chans_radar(iface, start_chan_idx, n_chans);
  719. }