bcmwifi_channels.c 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495
  1. /*
  2. * Misc utility routines used by kernel or app-level.
  3. * Contents are wifi-specific, used by any kernel or app-level
  4. * software that might want wifi things as it grows.
  5. *
  6. * Portions of this code are copyright (c) 2020 Cypress Semiconductor Corporation
  7. *
  8. * Copyright (C) 1999-2020, Broadcom Corporation
  9. *
  10. * Unless you and Broadcom execute a separate written software license
  11. * agreement governing use of this software, this software is licensed to you
  12. * under the terms of the GNU General Public License version 2 (the "GPL"),
  13. * available at http://www.broadcom.com/licenses/GPLv2.php, with the
  14. * following added to such license:
  15. *
  16. * As a special exception, the copyright holders of this software give you
  17. * permission to link this software with independent modules, and to copy and
  18. * distribute the resulting executable under terms of your choice, provided that
  19. * you also meet, for each linked independent module, the terms and conditions of
  20. * the license of that module. An independent module is a module which is not
  21. * derived from this software. The special exception does not apply to any
  22. * modifications of the software.
  23. *
  24. * Notwithstanding the above, under no circumstances may you combine this
  25. * software in any way with any other Broadcom software provided under a license
  26. * other than the GPL, without Broadcom's express prior written consent.
  27. *
  28. *
  29. * <<Broadcom-WL-IPTag/Open:>>
  30. *
  31. * $Id: bcmwifi_channels.c 695288 2017-04-19 17:20:39Z $
  32. */
  33. #include <bcm_cfg.h>
  34. #include <typedefs.h>
  35. #include <bcmutils.h>
  36. #ifdef BCMDRIVER
  37. #include <osl.h>
  38. #define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base))
  39. #define tolower(c) (bcm_isupper((c)) ? ((c) + 'a' - 'A') : (c))
  40. #else
  41. #include <stdio.h>
  42. #include <stdlib.h>
  43. #include <ctype.h>
  44. #ifndef ASSERT
  45. #define ASSERT(exp)
  46. #endif // endif
  47. #endif /* BCMDRIVER */
  48. #include <bcmwifi_channels.h>
  49. #if defined(WIN32) && (defined(BCMDLL) || defined(WLMDLL))
  50. #include <bcmstdlib.h> /* For wl/exe/GNUmakefile.brcm_wlu and GNUmakefile.wlm_dll */
  51. #endif // endif
  52. #include <802.11.h>
  53. /* Definitions for D11AC capable (80MHz+) Chanspec type */
  54. /* Chanspec ASCII representation:
  55. * [<band> 'g'] <channel> ['/'<bandwidth> [<primary-sideband>]['/'<1st80channel>'-'<2nd80channel>]]
  56. *
  57. * <band>:
  58. * (optional) 2, 3, 4, 5 for 2.4GHz, 3GHz, 4GHz, and 5GHz respectively.
  59. * Default value is 2g if channel <= 14, otherwise 5g.
  60. * <channel>:
  61. * channel number of the 5MHz, 10MHz, 20MHz channel,
  62. * or primary channel of 40MHz, 80MHz, 160MHz, or 80+80MHz channel.
  63. * <bandwidth>:
  64. * (optional) 5, 10, 20, 40, 80, 160, or 80+80. Default value is 20.
  65. * <primary-sideband>:
  66. * (only for 2.4GHz band 40MHz) U for upper sideband primary, L for lower.
  67. *
  68. * For 2.4GHz band 40MHz channels, the same primary channel may be the
  69. * upper sideband for one 40MHz channel, and the lower sideband for an
  70. * overlapping 40MHz channel. The U/L disambiguates which 40MHz channel
  71. * is being specified.
  72. *
  73. * For 40MHz in the 5GHz band and all channel bandwidths greater than
  74. * 40MHz, the U/L specificaion is not allowed since the channels are
  75. * non-overlapping and the primary sub-band is derived from its
  76. * position in the wide bandwidth channel.
  77. *
  78. * <1st80Channel>:
  79. * <2nd80Channel>:
  80. * Required for 80+80, otherwise not allowed.
  81. * Specifies the center channel of the primary and secondary 80MHz band.
  82. *
  83. * In its simplest form, it is a 20MHz channel number, with the implied band
  84. * of 2.4GHz if channel number <= 14, and 5GHz otherwise.
  85. *
  86. * To allow for backward compatibility with scripts, the old form for
  87. * 40MHz channels is also allowed: <channel><primary-sideband>
  88. *
  89. * <channel>:
  90. * primary channel of 40MHz, channel <= 14 is 2GHz, otherwise 5GHz
  91. * <primary-sideband>:
  92. * "U" for upper, "L" for lower (or lower case "u" "l")
  93. *
  94. * 5 GHz Examples:
  95. * Chanspec BW Center Ch Channel Range Primary Ch
  96. * 5g8 20MHz 8 - -
  97. * 52 20MHz 52 - -
  98. * 52/40 40MHz 54 52-56 52
  99. * 56/40 40MHz 54 52-56 56
  100. * 52/80 80MHz 58 52-64 52
  101. * 56/80 80MHz 58 52-64 56
  102. * 60/80 80MHz 58 52-64 60
  103. * 64/80 80MHz 58 52-64 64
  104. * 52/160 160MHz 50 36-64 52
  105. * 36/160 160MGz 50 36-64 36
  106. * 36/80+80/42-106 80+80MHz 42,106 36-48,100-112 36
  107. *
  108. * 2 GHz Examples:
  109. * Chanspec BW Center Ch Channel Range Primary Ch
  110. * 2g8 20MHz 8 - -
  111. * 8 20MHz 8 - -
  112. * 6 20MHz 6 - -
  113. * 6/40l 40MHz 8 6-10 6
  114. * 6l 40MHz 8 6-10 6
  115. * 6/40u 40MHz 4 2-6 6
  116. * 6u 40MHz 4 2-6 6
  117. */
  118. /* bandwidth ASCII string */
  119. static const char *wf_chspec_bw_str[] =
  120. {
  121. "5",
  122. "10",
  123. "20",
  124. "40",
  125. "80",
  126. "160",
  127. "80+80",
  128. "na"
  129. };
  130. static const uint8 wf_chspec_bw_mhz[] =
  131. {5, 10, 20, 40, 80, 160, 160};
  132. #define WF_NUM_BW \
  133. (sizeof(wf_chspec_bw_mhz)/sizeof(uint8))
  134. /* 40MHz channels in 5GHz band */
  135. static const uint8 wf_5g_40m_chans[] =
  136. {38, 46, 54, 62, 102, 110, 118, 126, 134, 142, 151, 159, 167, 175};
  137. #define WF_NUM_5G_40M_CHANS \
  138. (sizeof(wf_5g_40m_chans)/sizeof(uint8))
  139. /* 80MHz channels in 5GHz band */
  140. static const uint8 wf_5g_80m_chans[] =
  141. {42, 58, 106, 122, 138, 155, 171};
  142. #define WF_NUM_5G_80M_CHANS \
  143. (sizeof(wf_5g_80m_chans)/sizeof(uint8))
  144. /* 160MHz channels in 5GHz band */
  145. static const uint8 wf_5g_160m_chans[] =
  146. {50, 114};
  147. #define WF_NUM_5G_160M_CHANS \
  148. (sizeof(wf_5g_160m_chans)/sizeof(uint8))
  149. /* opclass and channel information for US. Table E-1 */
  150. static const uint16 opclass_data[] = {
  151. (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)),
  152. (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)),
  153. (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)),
  154. (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)),
  155. (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)),
  156. (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_5)&WL_CHANSPEC_BW_MASK)),
  157. (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_5)&WL_CHANSPEC_BW_MASK)),
  158. (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_10)&WL_CHANSPEC_BW_MASK)),
  159. (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_10)&WL_CHANSPEC_BW_MASK)),
  160. (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)),
  161. (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)),
  162. (WL_CHANSPEC_BAND_2G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)),
  163. (WL_CHANSPEC_BAND_3G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)),
  164. (WL_CHANSPEC_BAND_3G |((WL_CHANSPEC_BW_10)&WL_CHANSPEC_BW_MASK)),
  165. (WL_CHANSPEC_BAND_3G |((WL_CHANSPEC_BW_5)&WL_CHANSPEC_BW_MASK)),
  166. (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_5)&WL_CHANSPEC_BW_MASK)),
  167. (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_10)&WL_CHANSPEC_BW_MASK)),
  168. (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)),
  169. 0,
  170. 0,
  171. 0,
  172. (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_LOWER),
  173. (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_LOWER),
  174. (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_LOWER),
  175. (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_LOWER),
  176. (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_LOWER),
  177. (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_UPPER),
  178. (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_UPPER),
  179. (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_UPPER),
  180. (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_UPPER),
  181. (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_UPPER),
  182. (WL_CHANSPEC_BAND_2G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_LOWER),
  183. (WL_CHANSPEC_BAND_2G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_UPPER),
  184. };
  185. /**
  186. * Return the chanspec bandwidth in MHz
  187. * Bandwidth of 160 MHz will be returned for 80+80MHz chanspecs.
  188. *
  189. * @param chspec chanspec_t
  190. *
  191. * @return bandwidth of chspec in MHz units
  192. */
  193. uint
  194. wf_bw_chspec_to_mhz(chanspec_t chspec)
  195. {
  196. uint bw;
  197. bw = (chspec & WL_CHANSPEC_BW_MASK) >> WL_CHANSPEC_BW_SHIFT;
  198. return (bw >= WF_NUM_BW ? 0 : wf_chspec_bw_mhz[bw]);
  199. }
  200. /* bw in MHz, return the channel count from the center channel to the
  201. * the channel at the edge of the band
  202. */
  203. static uint8
  204. center_chan_to_edge(uint bw)
  205. {
  206. /* edge channels separated by BW - 10MHz on each side
  207. * delta from cf to edge is half of that,
  208. * MHz to channel num conversion is 5MHz/channel
  209. */
  210. return (uint8)(((bw - 20) / 2) / 5);
  211. }
  212. /* return channel number of the low edge of the band
  213. * given the center channel and BW
  214. */
  215. static uint8
  216. channel_low_edge(uint center_ch, uint bw)
  217. {
  218. return (uint8)(center_ch - center_chan_to_edge(bw));
  219. }
  220. /* return side band number given center channel and primary20 channel
  221. * return -1 on error
  222. */
  223. static int
  224. channel_to_sb(uint center_ch, uint primary_ch, uint bw)
  225. {
  226. uint lowest = channel_low_edge(center_ch, bw);
  227. uint sb;
  228. if ((primary_ch - lowest) % 4) {
  229. /* bad primary channel, not mult 4 */
  230. return -1;
  231. }
  232. sb = ((primary_ch - lowest) / 4);
  233. /* sb must be a index to a 20MHz channel in range */
  234. if (sb >= (bw / 20)) {
  235. /* primary_ch must have been too high for the center_ch */
  236. return -1;
  237. }
  238. return (int)sb;
  239. }
  240. /* return primary20 channel given center channel and side band */
  241. static uint8
  242. channel_to_primary20_chan(uint center_ch, uint bw, uint sb)
  243. {
  244. return (uint8)(channel_low_edge(center_ch, bw) + sb * 4);
  245. }
  246. /* return index of 80MHz channel from channel number
  247. * return -1 on error
  248. */
  249. static int
  250. channel_80mhz_to_id(uint ch)
  251. {
  252. uint i;
  253. for (i = 0; i < WF_NUM_5G_80M_CHANS; i ++) {
  254. if (ch == wf_5g_80m_chans[i])
  255. return (int)i;
  256. }
  257. return -1;
  258. }
  259. /* wrapper function for wf_chspec_ntoa. In case of an error it puts
  260. * the original chanspec in the output buffer, prepended with "invalid".
  261. * Can be directly used in print routines as it takes care of null
  262. */
  263. char *
  264. wf_chspec_ntoa_ex(chanspec_t chspec, char *buf)
  265. {
  266. if (wf_chspec_ntoa(chspec, buf) == NULL)
  267. snprintf(buf, CHANSPEC_STR_LEN, "invalid 0x%04x", chspec);
  268. return buf;
  269. }
  270. /* given a chanspec and a string buffer, format the chanspec as a
  271. * string, and return the original pointer a.
  272. * Min buffer length must be CHANSPEC_STR_LEN.
  273. * On error return NULL
  274. */
  275. char *
  276. wf_chspec_ntoa(chanspec_t chspec, char *buf)
  277. {
  278. const char *band;
  279. uint pri_chan;
  280. if (wf_chspec_malformed(chspec))
  281. return NULL;
  282. band = "";
  283. /* check for non-default band spec */
  284. if ((CHSPEC_IS2G(chspec) && CHSPEC_CHANNEL(chspec) > CH_MAX_2G_CHANNEL) ||
  285. (CHSPEC_IS5G(chspec) && CHSPEC_CHANNEL(chspec) <= CH_MAX_2G_CHANNEL))
  286. band = (CHSPEC_IS2G(chspec)) ? "2g" : "5g";
  287. /* primary20 channel */
  288. pri_chan = wf_chspec_primary20_chan(chspec);
  289. /* bandwidth and primary20 sideband */
  290. if (CHSPEC_IS20(chspec)) {
  291. snprintf(buf, CHANSPEC_STR_LEN, "%s%d", band, pri_chan);
  292. } else if (!CHSPEC_IS8080(chspec)) {
  293. const char *bw;
  294. const char *sb = "";
  295. bw = wf_chspec_to_bw_str(chspec);
  296. #ifdef CHANSPEC_NEW_40MHZ_FORMAT
  297. /* primary20 sideband string if needed for 2g 40MHz */
  298. if (CHSPEC_IS40(chspec) && CHSPEC_IS2G(chspec)) {
  299. sb = CHSPEC_SB_UPPER(chspec) ? "u" : "l";
  300. }
  301. snprintf(buf, CHANSPEC_STR_LEN, "%s%d/%s%s", band, pri_chan, bw, sb);
  302. #else
  303. /* primary20 sideband string instead of BW for 40MHz */
  304. if (CHSPEC_IS40(chspec)) {
  305. sb = CHSPEC_SB_UPPER(chspec) ? "u" : "l";
  306. snprintf(buf, CHANSPEC_STR_LEN, "%s%d%s", band, pri_chan, sb);
  307. } else {
  308. snprintf(buf, CHANSPEC_STR_LEN, "%s%d/%s", band, pri_chan, bw);
  309. }
  310. #endif /* CHANSPEC_NEW_40MHZ_FORMAT */
  311. } else {
  312. /* 80+80 */
  313. uint chan1 = (chspec & WL_CHANSPEC_CHAN1_MASK) >> WL_CHANSPEC_CHAN1_SHIFT;
  314. uint chan2 = (chspec & WL_CHANSPEC_CHAN2_MASK) >> WL_CHANSPEC_CHAN2_SHIFT;
  315. /* convert to channel number */
  316. chan1 = (chan1 < WF_NUM_5G_80M_CHANS) ? wf_5g_80m_chans[chan1] : 0;
  317. chan2 = (chan2 < WF_NUM_5G_80M_CHANS) ? wf_5g_80m_chans[chan2] : 0;
  318. /* Outputs a max of CHANSPEC_STR_LEN chars including '\0' */
  319. snprintf(buf, CHANSPEC_STR_LEN, "%d/80+80/%d-%d", pri_chan, chan1, chan2);
  320. }
  321. return (buf);
  322. }
  323. static int
  324. read_uint(const char **p, unsigned int *num)
  325. {
  326. unsigned long val;
  327. char *endp = NULL;
  328. val = strtoul(*p, &endp, 10);
  329. /* if endp is the initial pointer value, then a number was not read */
  330. if (endp == *p)
  331. return 0;
  332. /* advance the buffer pointer to the end of the integer string */
  333. *p = endp;
  334. /* return the parsed integer */
  335. *num = (unsigned int)val;
  336. return 1;
  337. }
  338. /* given a chanspec string, convert to a chanspec.
  339. * On error return 0
  340. */
  341. chanspec_t
  342. wf_chspec_aton(const char *a)
  343. {
  344. chanspec_t chspec;
  345. uint chspec_ch, chspec_band, bw, chspec_bw, chspec_sb;
  346. uint num, pri_ch;
  347. uint ch1, ch2;
  348. char c, sb_ul = '\0';
  349. int i;
  350. bw = 20;
  351. chspec_sb = 0;
  352. chspec_ch = ch1 = ch2 = 0;
  353. /* parse channel num or band */
  354. if (!read_uint(&a, &num))
  355. return 0;
  356. /* if we are looking at a 'g', then the first number was a band */
  357. c = tolower(a[0]);
  358. if (c == 'g') {
  359. a++; /* consume the char */
  360. /* band must be "2" or "5" */
  361. if (num == 2)
  362. chspec_band = WL_CHANSPEC_BAND_2G;
  363. else if (num == 5)
  364. chspec_band = WL_CHANSPEC_BAND_5G;
  365. else
  366. return 0;
  367. /* read the channel number */
  368. if (!read_uint(&a, &pri_ch))
  369. return 0;
  370. c = tolower(a[0]);
  371. }
  372. else {
  373. /* first number is channel, use default for band */
  374. pri_ch = num;
  375. chspec_band = ((pri_ch <= CH_MAX_2G_CHANNEL) ?
  376. WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G);
  377. }
  378. if (c == '\0') {
  379. /* default BW of 20MHz */
  380. chspec_bw = WL_CHANSPEC_BW_20;
  381. goto done_read;
  382. }
  383. a ++; /* consume the 'u','l', or '/' */
  384. /* check 'u'/'l' */
  385. if (c == 'u' || c == 'l') {
  386. sb_ul = c;
  387. chspec_bw = WL_CHANSPEC_BW_40;
  388. goto done_read;
  389. }
  390. /* next letter must be '/' */
  391. if (c != '/')
  392. return 0;
  393. /* read bandwidth */
  394. if (!read_uint(&a, &bw))
  395. return 0;
  396. /* convert to chspec value */
  397. if (bw == 5) {
  398. chspec_bw = WL_CHANSPEC_BW_5;
  399. } else if (bw == 10) {
  400. chspec_bw = WL_CHANSPEC_BW_10;
  401. } else if (bw == 20) {
  402. chspec_bw = WL_CHANSPEC_BW_20;
  403. } else if (bw == 40) {
  404. chspec_bw = WL_CHANSPEC_BW_40;
  405. } else if (bw == 80) {
  406. chspec_bw = WL_CHANSPEC_BW_80;
  407. } else if (bw == 160) {
  408. chspec_bw = WL_CHANSPEC_BW_160;
  409. } else {
  410. return 0;
  411. }
  412. /* So far we have <band>g<chan>/<bw>
  413. * Can now be followed by u/l if bw = 40,
  414. * or '+80' if bw = 80, to make '80+80' bw.
  415. */
  416. c = (char)tolower((int)a[0]);
  417. /* if we have a 2g/40 channel, we should have a l/u spec now */
  418. if (chspec_band == WL_CHANSPEC_BAND_2G && bw == 40) {
  419. if (c == 'u' || c == 'l') {
  420. a ++; /* consume the u/l char */
  421. sb_ul = c;
  422. goto done_read;
  423. }
  424. }
  425. /* check for 80+80 */
  426. if (c == '+') {
  427. /* 80+80 */
  428. const char plus80[] = "80/";
  429. /* must be looking at '+80/'
  430. * check and consume this string.
  431. */
  432. chspec_bw = WL_CHANSPEC_BW_8080;
  433. a ++; /* consume the char '+' */
  434. /* consume the '80/' string */
  435. for (i = 0; i < 3; i++) {
  436. if (*a++ != plus80[i]) {
  437. return 0;
  438. }
  439. }
  440. /* read primary 80MHz channel */
  441. if (!read_uint(&a, &ch1))
  442. return 0;
  443. /* must followed by '-' */
  444. if (a[0] != '-')
  445. return 0;
  446. a ++; /* consume the char */
  447. /* read secondary 80MHz channel */
  448. if (!read_uint(&a, &ch2))
  449. return 0;
  450. }
  451. done_read:
  452. /* skip trailing white space */
  453. while (a[0] == ' ') {
  454. a ++;
  455. }
  456. /* must be end of string */
  457. if (a[0] != '\0')
  458. return 0;
  459. /* Now have all the chanspec string parts read;
  460. * chspec_band, pri_ch, chspec_bw, sb_ul, ch1, ch2.
  461. * chspec_band and chspec_bw are chanspec values.
  462. * Need to convert pri_ch, sb_ul, and ch1,ch2 into
  463. * a center channel (or two) and sideband.
  464. */
  465. /* if a sb u/l string was given, just use that,
  466. * guaranteed to be bw = 40 by sting parse.
  467. */
  468. if (sb_ul != '\0') {
  469. if (sb_ul == 'l') {
  470. chspec_ch = UPPER_20_SB(pri_ch);
  471. chspec_sb = WL_CHANSPEC_CTL_SB_LLL;
  472. } else if (sb_ul == 'u') {
  473. chspec_ch = LOWER_20_SB(pri_ch);
  474. chspec_sb = WL_CHANSPEC_CTL_SB_LLU;
  475. }
  476. }
  477. /* if the bw is 20, center and sideband are trivial */
  478. else if (chspec_bw == WL_CHANSPEC_BW_20) {
  479. chspec_ch = pri_ch;
  480. chspec_sb = WL_CHANSPEC_CTL_SB_NONE;
  481. }
  482. /* if the bw is 40/80/160, not 80+80, a single method
  483. * can be used to to find the center and sideband
  484. */
  485. else if (chspec_bw != WL_CHANSPEC_BW_8080) {
  486. /* figure out primary20 sideband based on primary20 channel and bandwidth */
  487. const uint8 *center_ch = NULL;
  488. int num_ch = 0;
  489. int sb = -1;
  490. if (chspec_bw == WL_CHANSPEC_BW_40) {
  491. center_ch = wf_5g_40m_chans;
  492. num_ch = WF_NUM_5G_40M_CHANS;
  493. } else if (chspec_bw == WL_CHANSPEC_BW_80) {
  494. center_ch = wf_5g_80m_chans;
  495. num_ch = WF_NUM_5G_80M_CHANS;
  496. } else if (chspec_bw == WL_CHANSPEC_BW_160) {
  497. center_ch = wf_5g_160m_chans;
  498. num_ch = WF_NUM_5G_160M_CHANS;
  499. } else {
  500. return 0;
  501. }
  502. for (i = 0; i < num_ch; i ++) {
  503. sb = channel_to_sb(center_ch[i], pri_ch, bw);
  504. if (sb >= 0) {
  505. chspec_ch = center_ch[i];
  506. chspec_sb = (uint)(sb << WL_CHANSPEC_CTL_SB_SHIFT);
  507. break;
  508. }
  509. }
  510. /* check for no matching sb/center */
  511. if (sb < 0) {
  512. return 0;
  513. }
  514. }
  515. /* Otherwise, bw is 80+80. Figure out channel pair and sb */
  516. else {
  517. int ch1_id = 0, ch2_id = 0;
  518. int sb;
  519. /* look up the channel ID for the specified channel numbers */
  520. ch1_id = channel_80mhz_to_id(ch1);
  521. ch2_id = channel_80mhz_to_id(ch2);
  522. /* validate channels */
  523. if (ch1_id < 0 || ch2_id < 0)
  524. return 0;
  525. /* combine 2 channel IDs in channel field of chspec */
  526. chspec_ch = (((uint)ch1_id << WL_CHANSPEC_CHAN1_SHIFT) |
  527. ((uint)ch2_id << WL_CHANSPEC_CHAN2_SHIFT));
  528. /* figure out primary 20 MHz sideband */
  529. /* is the primary channel contained in the 1st 80MHz channel? */
  530. sb = channel_to_sb(ch1, pri_ch, bw);
  531. if (sb < 0) {
  532. /* no match for primary channel 'pri_ch' in segment0 80MHz channel */
  533. return 0;
  534. }
  535. chspec_sb = (uint)(sb << WL_CHANSPEC_CTL_SB_SHIFT);
  536. }
  537. chspec = (chanspec_t)(chspec_ch | chspec_band | chspec_bw | chspec_sb);
  538. if (wf_chspec_malformed(chspec))
  539. return 0;
  540. return chspec;
  541. }
  542. /*
  543. * Verify the chanspec is using a legal set of parameters, i.e. that the
  544. * chanspec specified a band, bw, pri_sb and channel and that the
  545. * combination could be legal given any set of circumstances.
  546. * RETURNS: TRUE is the chanspec is malformed, false if it looks good.
  547. */
  548. bool
  549. wf_chspec_malformed(chanspec_t chanspec)
  550. {
  551. uint chspec_bw = CHSPEC_BW(chanspec);
  552. uint chspec_ch = CHSPEC_CHANNEL(chanspec);
  553. /* must be 2G or 5G band */
  554. if (CHSPEC_IS2G(chanspec)) {
  555. /* must be valid bandwidth */
  556. if (!BW_LE40(chspec_bw)) {
  557. return TRUE;
  558. }
  559. } else if (CHSPEC_IS5G(chanspec)) {
  560. if (chspec_bw == WL_CHANSPEC_BW_8080) {
  561. uint ch1_id, ch2_id;
  562. /* channel IDs in 80+80 must be in range */
  563. ch1_id = CHSPEC_CHAN1(chanspec);
  564. ch2_id = CHSPEC_CHAN2(chanspec);
  565. if (ch1_id >= WF_NUM_5G_80M_CHANS || ch2_id >= WF_NUM_5G_80M_CHANS)
  566. return TRUE;
  567. } else if (chspec_bw == WL_CHANSPEC_BW_20 || chspec_bw == WL_CHANSPEC_BW_40 ||
  568. chspec_bw == WL_CHANSPEC_BW_80 || chspec_bw == WL_CHANSPEC_BW_160) {
  569. if (chspec_ch > MAXCHANNEL) {
  570. return TRUE;
  571. }
  572. } else {
  573. /* invalid bandwidth */
  574. return TRUE;
  575. }
  576. } else {
  577. /* must be 2G or 5G band */
  578. return TRUE;
  579. }
  580. /* side band needs to be consistent with bandwidth */
  581. if (chspec_bw == WL_CHANSPEC_BW_20) {
  582. if (CHSPEC_CTL_SB(chanspec) != WL_CHANSPEC_CTL_SB_LLL)
  583. return TRUE;
  584. } else if (chspec_bw == WL_CHANSPEC_BW_40) {
  585. if (CHSPEC_CTL_SB(chanspec) > WL_CHANSPEC_CTL_SB_LLU)
  586. return TRUE;
  587. } else if (chspec_bw == WL_CHANSPEC_BW_80 ||
  588. chspec_bw == WL_CHANSPEC_BW_8080) {
  589. /* both 80MHz and 80+80MHz use 80MHz side bands.
  590. * 80+80 SB info is relative to the primary 80MHz sub-band.
  591. */
  592. if (CHSPEC_CTL_SB(chanspec) > WL_CHANSPEC_CTL_SB_LUU)
  593. return TRUE;
  594. }
  595. else if (chspec_bw == WL_CHANSPEC_BW_160) {
  596. ASSERT(CHSPEC_CTL_SB(chanspec) <= WL_CHANSPEC_CTL_SB_UUU);
  597. }
  598. return FALSE;
  599. }
  600. /*
  601. * Verify the chanspec specifies a valid channel according to 802.11.
  602. * RETURNS: TRUE if the chanspec is a valid 802.11 channel
  603. */
  604. bool
  605. wf_chspec_valid(chanspec_t chanspec)
  606. {
  607. uint chspec_bw = CHSPEC_BW(chanspec);
  608. uint chspec_ch = CHSPEC_CHANNEL(chanspec);
  609. if (wf_chspec_malformed(chanspec))
  610. return FALSE;
  611. if (CHSPEC_IS2G(chanspec)) {
  612. /* must be valid bandwidth and channel range */
  613. if (chspec_bw == WL_CHANSPEC_BW_20) {
  614. if (chspec_ch >= 1 && chspec_ch <= 14)
  615. return TRUE;
  616. } else if (chspec_bw == WL_CHANSPEC_BW_40) {
  617. if (chspec_ch >= 3 && chspec_ch <= 11)
  618. return TRUE;
  619. }
  620. } else if (CHSPEC_IS5G(chanspec)) {
  621. if (chspec_bw == WL_CHANSPEC_BW_8080) {
  622. uint16 ch1, ch2;
  623. ch1 = wf_5g_80m_chans[CHSPEC_CHAN1(chanspec)];
  624. ch2 = wf_5g_80m_chans[CHSPEC_CHAN2(chanspec)];
  625. /* the two channels must be separated by more than 80MHz by VHT req */
  626. if ((ch2 > ch1 + CH_80MHZ_APART) ||
  627. (ch1 > ch2 + CH_80MHZ_APART))
  628. return TRUE;
  629. } else {
  630. const uint8 *center_ch;
  631. uint num_ch, i;
  632. if (chspec_bw == WL_CHANSPEC_BW_20 || chspec_bw == WL_CHANSPEC_BW_40) {
  633. center_ch = wf_5g_40m_chans;
  634. num_ch = WF_NUM_5G_40M_CHANS;
  635. } else if (chspec_bw == WL_CHANSPEC_BW_80) {
  636. center_ch = wf_5g_80m_chans;
  637. num_ch = WF_NUM_5G_80M_CHANS;
  638. } else if (chspec_bw == WL_CHANSPEC_BW_160) {
  639. center_ch = wf_5g_160m_chans;
  640. num_ch = WF_NUM_5G_160M_CHANS;
  641. } else {
  642. /* invalid bandwidth */
  643. return FALSE;
  644. }
  645. /* check for a valid center channel */
  646. if (chspec_bw == WL_CHANSPEC_BW_20) {
  647. /* We don't have an array of legal 20MHz 5G channels, but they are
  648. * each side of the legal 40MHz channels. Check the chanspec
  649. * channel against either side of the 40MHz channels.
  650. */
  651. for (i = 0; i < num_ch; i ++) {
  652. if (chspec_ch == (uint)LOWER_20_SB(center_ch[i]) ||
  653. chspec_ch == (uint)UPPER_20_SB(center_ch[i]))
  654. break; /* match found */
  655. }
  656. if (i == num_ch) {
  657. /* check for channel 165 which is not the side band
  658. * of 40MHz 5G channel
  659. */
  660. if (chspec_ch == 165)
  661. i = 0;
  662. /* check for legacy JP channels on failure */
  663. if (chspec_ch == 34 || chspec_ch == 38 ||
  664. chspec_ch == 42 || chspec_ch == 46)
  665. i = 0;
  666. }
  667. } else {
  668. /* check the chanspec channel to each legal channel */
  669. for (i = 0; i < num_ch; i ++) {
  670. if (chspec_ch == center_ch[i])
  671. break; /* match found */
  672. }
  673. }
  674. if (i < num_ch) {
  675. /* match found */
  676. return TRUE;
  677. }
  678. }
  679. }
  680. return FALSE;
  681. }
  682. /*
  683. * This function returns TRUE if both the chanspec can co-exist in PHY.
  684. * Addition to primary20 channel, the function checks for side band for 2g 40 channels
  685. */
  686. bool
  687. wf_chspec_coexist(chanspec_t chspec1, chanspec_t chspec2)
  688. {
  689. bool same_primary;
  690. same_primary = (wf_chspec_primary20_chan(chspec1) == wf_chspec_primary20_chan(chspec2));
  691. if (same_primary && CHSPEC_IS2G(chspec1)) {
  692. if (CHSPEC_IS40(chspec1) && CHSPEC_IS40(chspec2)) {
  693. return (CHSPEC_CTL_SB(chspec1) == CHSPEC_CTL_SB(chspec2));
  694. }
  695. }
  696. return same_primary;
  697. }
  698. /**
  699. * Create a 20MHz chanspec for the given band.
  700. *
  701. * This function returns a 20MHz chanspec in the given band.
  702. *
  703. * @param channel 20MHz channel number
  704. * @param band a chanspec band (e.g. WL_CHANSPEC_BAND_2G)
  705. *
  706. * @return Returns a 20MHz chanspec, or IVNCHANSPEC in case of error.
  707. */
  708. chanspec_t
  709. wf_create_20MHz_chspec(uint channel, chanspec_band_t band)
  710. {
  711. chanspec_t chspec;
  712. if (channel <= WL_CHANSPEC_CHAN_MASK &&
  713. (band == WL_CHANSPEC_BAND_2G ||
  714. band == WL_CHANSPEC_BAND_5G)) {
  715. chspec = band | WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE | channel;
  716. if (!wf_chspec_valid(chspec)) {
  717. chspec = INVCHANSPEC;
  718. }
  719. } else {
  720. chspec = INVCHANSPEC;
  721. }
  722. return chspec;
  723. }
  724. /**
  725. * Return the primary 20MHz channel.
  726. *
  727. * This function returns the channel number of the primary 20MHz channel. For
  728. * 20MHz channels this is just the channel number. For 40MHz or wider channels
  729. * it is the primary 20MHz channel specified by the chanspec.
  730. *
  731. * @param chspec input chanspec
  732. *
  733. * @return Returns the channel number of the primary 20MHz channel
  734. */
  735. uint8
  736. wf_chspec_primary20_chan(chanspec_t chspec)
  737. {
  738. uint center_chan;
  739. uint bw_mhz;
  740. uint sb;
  741. ASSERT(!wf_chspec_malformed(chspec));
  742. /* Is there a sideband ? */
  743. if (CHSPEC_IS20(chspec)) {
  744. return CHSPEC_CHANNEL(chspec);
  745. } else {
  746. sb = CHSPEC_CTL_SB(chspec) >> WL_CHANSPEC_CTL_SB_SHIFT;
  747. if (CHSPEC_IS8080(chspec)) {
  748. /* For an 80+80 MHz channel, the sideband 'sb' field is an 80 MHz sideband
  749. * (LL, LU, UL, LU) for the 80 MHz frequency segment 0.
  750. */
  751. uint chan_id = CHSPEC_CHAN1(chspec);
  752. bw_mhz = 80;
  753. /* convert from channel index to channel number */
  754. center_chan = wf_5g_80m_chans[chan_id];
  755. }
  756. else {
  757. bw_mhz = wf_bw_chspec_to_mhz(chspec);
  758. center_chan = CHSPEC_CHANNEL(chspec) >> WL_CHANSPEC_CHAN_SHIFT;
  759. }
  760. return (channel_to_primary20_chan(center_chan, bw_mhz, sb));
  761. }
  762. }
  763. /* given a chanspec, return the bandwidth string */
  764. const char *
  765. BCMRAMFN(wf_chspec_to_bw_str)(chanspec_t chspec)
  766. {
  767. return wf_chspec_bw_str[(CHSPEC_BW(chspec) >> WL_CHANSPEC_BW_SHIFT)];
  768. }
  769. /*
  770. * Return the primary 20MHz chanspec of the given chanspec
  771. */
  772. chanspec_t
  773. wf_chspec_primary20_chspec(chanspec_t chspec)
  774. {
  775. chanspec_t pri_chspec = chspec;
  776. uint8 pri_chan;
  777. ASSERT(!wf_chspec_malformed(chspec));
  778. /* Is there a sideband ? */
  779. if (!CHSPEC_IS20(chspec)) {
  780. pri_chan = wf_chspec_primary20_chan(chspec);
  781. pri_chspec = pri_chan | WL_CHANSPEC_BW_20;
  782. pri_chspec |= CHSPEC_BAND(chspec);
  783. }
  784. return pri_chspec;
  785. }
  786. /* return chanspec given primary 20MHz channel and bandwidth
  787. * return 0 on error
  788. */
  789. uint16
  790. wf_channel2chspec(uint pri_ch, uint bw)
  791. {
  792. uint16 chspec;
  793. const uint8 *center_ch = NULL;
  794. int num_ch = 0;
  795. int sb = -1;
  796. int i = 0;
  797. chspec = ((pri_ch <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G);
  798. chspec |= bw;
  799. if (bw == WL_CHANSPEC_BW_40) {
  800. center_ch = wf_5g_40m_chans;
  801. num_ch = WF_NUM_5G_40M_CHANS;
  802. bw = 40;
  803. } else if (bw == WL_CHANSPEC_BW_80) {
  804. center_ch = wf_5g_80m_chans;
  805. num_ch = WF_NUM_5G_80M_CHANS;
  806. bw = 80;
  807. } else if (bw == WL_CHANSPEC_BW_160) {
  808. center_ch = wf_5g_160m_chans;
  809. num_ch = WF_NUM_5G_160M_CHANS;
  810. bw = 160;
  811. } else if (bw == WL_CHANSPEC_BW_20) {
  812. chspec |= pri_ch;
  813. return chspec;
  814. } else {
  815. return 0;
  816. }
  817. for (i = 0; i < num_ch; i ++) {
  818. sb = channel_to_sb(center_ch[i], pri_ch, bw);
  819. if (sb >= 0) {
  820. chspec |= center_ch[i];
  821. chspec |= (sb << WL_CHANSPEC_CTL_SB_SHIFT);
  822. break;
  823. }
  824. }
  825. /* check for no matching sb/center */
  826. if (sb < 0) {
  827. return 0;
  828. }
  829. return chspec;
  830. }
  831. /*
  832. * This function returns the chanspec for the primary 40MHz of an 80MHz or wider channel.
  833. * The primary 20MHz channel of the returned 40MHz chanspec is the same as the primary 20MHz
  834. * channel of the input chanspec.
  835. */
  836. extern chanspec_t wf_chspec_primary40_chspec(chanspec_t chspec)
  837. {
  838. chanspec_t chspec40 = chspec;
  839. uint center_chan;
  840. uint sb;
  841. ASSERT(!wf_chspec_malformed(chspec));
  842. /* if the chanspec is > 80MHz, use the helper routine to find the primary 80 MHz channel */
  843. if (CHSPEC_IS8080(chspec) || CHSPEC_IS160(chspec)) {
  844. chspec = wf_chspec_primary80_chspec(chspec);
  845. }
  846. /* determine primary 40 MHz sub-channel of an 80 MHz chanspec */
  847. if (CHSPEC_IS80(chspec)) {
  848. center_chan = CHSPEC_CHANNEL(chspec);
  849. sb = CHSPEC_CTL_SB(chspec);
  850. if (sb < WL_CHANSPEC_CTL_SB_UL) {
  851. /* Primary 40MHz is on lower side */
  852. center_chan -= CH_20MHZ_APART;
  853. /* sideband bits are the same for LL/LU and L/U */
  854. } else {
  855. /* Primary 40MHz is on upper side */
  856. center_chan += CH_20MHZ_APART;
  857. /* sideband bits need to be adjusted by UL offset */
  858. sb -= WL_CHANSPEC_CTL_SB_UL;
  859. }
  860. /* Create primary 40MHz chanspec */
  861. chspec40 = (chanspec_t)(WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_40 |
  862. sb | center_chan);
  863. }
  864. return chspec40;
  865. }
  866. /*
  867. * Return the channel number for a given frequency and base frequency.
  868. * The returned channel number is relative to the given base frequency.
  869. * If the given base frequency is zero, a base frequency of 5 GHz is assumed for
  870. * frequencies from 5 - 6 GHz, and 2.407 GHz is assumed for 2.4 - 2.5 GHz.
  871. *
  872. * Frequency is specified in MHz.
  873. * The base frequency is specified as (start_factor * 500 kHz).
  874. * Constants WF_CHAN_FACTOR_2_4_G, WF_CHAN_FACTOR_5_G are defined for
  875. * 2.4 GHz and 5 GHz bands.
  876. *
  877. * The returned channel will be in the range [1, 14] in the 2.4 GHz band
  878. * and [0, 200] otherwise.
  879. * -1 is returned if the start_factor is WF_CHAN_FACTOR_2_4_G and the
  880. * frequency is not a 2.4 GHz channel, or if the frequency is not and even
  881. * multiple of 5 MHz from the base frequency to the base plus 1 GHz.
  882. *
  883. * Reference 802.11-2016, section 17.3.8.3 and section 16.3.6.3
  884. */
  885. int
  886. wf_mhz2channel(uint freq, uint start_factor)
  887. {
  888. int ch = -1;
  889. uint base;
  890. int offset;
  891. /* take the default channel start frequency */
  892. if (start_factor == 0) {
  893. if (freq >= 2400 && freq <= 2500)
  894. start_factor = WF_CHAN_FACTOR_2_4_G;
  895. else if (freq >= 5000 && freq <= 6000)
  896. start_factor = WF_CHAN_FACTOR_5_G;
  897. }
  898. if (freq == 2484 && start_factor == WF_CHAN_FACTOR_2_4_G)
  899. return 14;
  900. base = start_factor / 2;
  901. /* check that the frequency is in 1GHz range of the base */
  902. if ((freq < base) || (freq > base + 1000))
  903. return -1;
  904. offset = (int)(freq - base);
  905. ch = offset / 5;
  906. /* check that frequency is a 5MHz multiple from the base */
  907. if (offset != (ch * 5))
  908. return -1;
  909. /* restricted channel range check for 2.4G */
  910. if (start_factor == WF_CHAN_FACTOR_2_4_G && (ch < 1 || ch > 13))
  911. return -1;
  912. return ch;
  913. }
  914. /*
  915. * Return the center frequency in MHz of the given channel and base frequency.
  916. * The channel number is interpreted relative to the given base frequency.
  917. *
  918. * The valid channel range is [1, 14] in the 2.4 GHz band and [0, 200] otherwise.
  919. * The base frequency is specified as (start_factor * 500 kHz).
  920. * Constants WF_CHAN_FACTOR_2_4_G, WF_CHAN_FACTOR_4_G, and WF_CHAN_FACTOR_5_G
  921. * are defined for 2.4 GHz, 4 GHz, and 5 GHz bands.
  922. * The channel range of [1, 14] is only checked for a start_factor of
  923. * WF_CHAN_FACTOR_2_4_G (4814 = 2407 * 2).
  924. * Odd start_factors produce channels on .5 MHz boundaries, in which case
  925. * the answer is rounded down to an integral MHz.
  926. * -1 is returned for an out of range channel.
  927. *
  928. * Reference 802.11-2016, section 17.3.8.3 and section 16.3.6.3
  929. */
  930. int
  931. wf_channel2mhz(uint ch, uint start_factor)
  932. {
  933. int freq;
  934. if ((start_factor == WF_CHAN_FACTOR_2_4_G && (ch < 1 || ch > 14)) ||
  935. (ch > 200))
  936. freq = -1;
  937. else if ((start_factor == WF_CHAN_FACTOR_2_4_G) && (ch == 14))
  938. freq = 2484;
  939. else
  940. freq = (int)(ch * 5 + start_factor / 2);
  941. return freq;
  942. }
  943. static const uint16 sidebands[] = {
  944. WL_CHANSPEC_CTL_SB_LLL, WL_CHANSPEC_CTL_SB_LLU,
  945. WL_CHANSPEC_CTL_SB_LUL, WL_CHANSPEC_CTL_SB_LUU,
  946. WL_CHANSPEC_CTL_SB_ULL, WL_CHANSPEC_CTL_SB_ULU,
  947. WL_CHANSPEC_CTL_SB_UUL, WL_CHANSPEC_CTL_SB_UUU
  948. };
  949. /*
  950. * Returns the chanspec 80Mhz channel corresponding to the following input
  951. * parameters
  952. *
  953. * primary_channel - primary 20Mhz channel
  954. * center_channel - center frequecny of the 80Mhz channel
  955. *
  956. * The center_channel can be one of {42, 58, 106, 122, 138, 155}
  957. *
  958. * returns INVCHANSPEC in case of error
  959. */
  960. chanspec_t
  961. wf_chspec_80(uint8 center_channel, uint8 primary_channel)
  962. {
  963. chanspec_t chanspec = INVCHANSPEC;
  964. chanspec_t chanspec_cur;
  965. uint i;
  966. for (i = 0; i < WF_NUM_SIDEBANDS_80MHZ; i++) {
  967. chanspec_cur = CH80MHZ_CHSPEC(center_channel, sidebands[i]);
  968. if (primary_channel == wf_chspec_primary20_chan(chanspec_cur)) {
  969. chanspec = chanspec_cur;
  970. break;
  971. }
  972. }
  973. /* If the loop ended early, we are good, otherwise we did not
  974. * find a 80MHz chanspec with the given center_channel that had a primary channel
  975. *matching the given primary_channel.
  976. */
  977. return chanspec;
  978. }
  979. /*
  980. * Returns the 80+80 chanspec corresponding to the following input parameters
  981. *
  982. * primary_20mhz - Primary 20 MHz channel
  983. * chan0 - center channel number of one frequency segment
  984. * chan1 - center channel number of the other frequency segment
  985. *
  986. * Parameters chan0 and chan1 are channel numbers in {42, 58, 106, 122, 138, 155}.
  987. * The primary channel must be contained in one of the 80MHz channels. This routine
  988. * will determine which frequency segment is the primary 80 MHz segment.
  989. *
  990. * Returns INVCHANSPEC in case of error.
  991. *
  992. * Refer to 802.11-2016 section 22.3.14 "Channelization".
  993. */
  994. chanspec_t
  995. wf_chspec_get8080_chspec(uint8 primary_20mhz, uint8 chan0, uint8 chan1)
  996. {
  997. int sb = 0;
  998. uint16 chanspec = 0;
  999. int chan0_id = 0, chan1_id = 0;
  1000. int seg0, seg1;
  1001. chan0_id = channel_80mhz_to_id(chan0);
  1002. chan1_id = channel_80mhz_to_id(chan1);
  1003. /* make sure the channel numbers were valid */
  1004. if (chan0_id == -1 || chan1_id == -1)
  1005. return INVCHANSPEC;
  1006. /* does the primary channel fit with the 1st 80MHz channel ? */
  1007. sb = channel_to_sb(chan0, primary_20mhz, 80);
  1008. if (sb >= 0) {
  1009. /* yes, so chan0 is frequency segment 0, and chan1 is seg 1 */
  1010. seg0 = chan0_id;
  1011. seg1 = chan1_id;
  1012. } else {
  1013. /* no, so does the primary channel fit with the 2nd 80MHz channel ? */
  1014. sb = channel_to_sb(chan1, primary_20mhz, 80);
  1015. if (sb < 0) {
  1016. /* no match for pri_ch to either 80MHz center channel */
  1017. return INVCHANSPEC;
  1018. }
  1019. /* swapped, so chan1 is frequency segment 0, and chan0 is seg 1 */
  1020. seg0 = chan1_id;
  1021. seg1 = chan0_id;
  1022. }
  1023. chanspec = (uint16)((seg0 << WL_CHANSPEC_CHAN1_SHIFT) |
  1024. (seg1 << WL_CHANSPEC_CHAN2_SHIFT) |
  1025. (sb << WL_CHANSPEC_CTL_SB_SHIFT) |
  1026. WL_CHANSPEC_BW_8080 |
  1027. WL_CHANSPEC_BAND_5G);
  1028. return chanspec;
  1029. }
  1030. /*
  1031. * This function returns the 80Mhz channel for the given id.
  1032. */
  1033. static uint8
  1034. wf_chspec_get80Mhz_ch(uint8 chan_80Mhz_id)
  1035. {
  1036. if (chan_80Mhz_id < WF_NUM_5G_80M_CHANS)
  1037. return wf_5g_80m_chans[chan_80Mhz_id];
  1038. return 0;
  1039. }
  1040. /*
  1041. * Returns the center channel of the primary 80 MHz sub-band of the provided chanspec
  1042. */
  1043. uint8
  1044. wf_chspec_primary80_channel(chanspec_t chanspec)
  1045. {
  1046. chanspec_t primary80_chspec;
  1047. uint8 primary80_chan;
  1048. primary80_chspec = wf_chspec_primary80_chspec(chanspec);
  1049. if (primary80_chspec == INVCHANSPEC) {
  1050. primary80_chan = INVCHANNEL;
  1051. } else {
  1052. primary80_chan = CHSPEC_CHANNEL(primary80_chspec);
  1053. }
  1054. return primary80_chan;
  1055. }
  1056. /*
  1057. * Returns the center channel of the secondary 80 MHz sub-band of the provided chanspec
  1058. */
  1059. uint8
  1060. wf_chspec_secondary80_channel(chanspec_t chanspec)
  1061. {
  1062. chanspec_t secondary80_chspec;
  1063. uint8 secondary80_chan;
  1064. secondary80_chspec = wf_chspec_secondary80_chspec(chanspec);
  1065. if (secondary80_chspec == INVCHANSPEC) {
  1066. secondary80_chan = INVCHANNEL;
  1067. } else {
  1068. secondary80_chan = CHSPEC_CHANNEL(secondary80_chspec);
  1069. }
  1070. return secondary80_chan;
  1071. }
  1072. /*
  1073. * Returns the chanspec for the primary 80MHz sub-band of an 160MHz or 80+80 channel
  1074. */
  1075. chanspec_t
  1076. wf_chspec_primary80_chspec(chanspec_t chspec)
  1077. {
  1078. chanspec_t chspec80;
  1079. uint center_chan;
  1080. uint sb;
  1081. ASSERT(!wf_chspec_malformed(chspec));
  1082. if (CHSPEC_IS80(chspec)) {
  1083. chspec80 = chspec;
  1084. }
  1085. else if (CHSPEC_IS8080(chspec)) {
  1086. sb = CHSPEC_CTL_SB(chspec);
  1087. /* primary sub-band is stored in seg0 */
  1088. center_chan = wf_chspec_get80Mhz_ch(CHSPEC_CHAN1(chspec));
  1089. /* Create primary 80MHz chanspec */
  1090. chspec80 = (chanspec_t)(WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_80 | sb | center_chan);
  1091. }
  1092. else if (CHSPEC_IS160(chspec)) {
  1093. center_chan = CHSPEC_CHANNEL(chspec);
  1094. sb = CHSPEC_CTL_SB(chspec);
  1095. if (sb < WL_CHANSPEC_CTL_SB_ULL) {
  1096. /* Primary 80MHz is on lower side */
  1097. center_chan -= CH_40MHZ_APART;
  1098. }
  1099. else {
  1100. /* Primary 80MHz is on upper side */
  1101. center_chan += CH_40MHZ_APART;
  1102. sb -= WL_CHANSPEC_CTL_SB_ULL;
  1103. }
  1104. /* Create primary 80MHz chanspec */
  1105. chspec80 = (chanspec_t)(WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_80 | sb | center_chan);
  1106. }
  1107. else {
  1108. chspec80 = INVCHANSPEC;
  1109. }
  1110. return chspec80;
  1111. }
  1112. /*
  1113. * Returns the chanspec for the secondary 80MHz sub-band of an 160MHz or 80+80 channel
  1114. */
  1115. chanspec_t
  1116. wf_chspec_secondary80_chspec(chanspec_t chspec)
  1117. {
  1118. chanspec_t chspec80;
  1119. uint center_chan;
  1120. ASSERT(!wf_chspec_malformed(chspec));
  1121. if (CHSPEC_IS8080(chspec)) {
  1122. /* secondary sub-band is stored in seg1 */
  1123. center_chan = wf_chspec_get80Mhz_ch(CHSPEC_CHAN2(chspec));
  1124. /* Create secondary 80MHz chanspec */
  1125. chspec80 = (chanspec_t)(WL_CHANSPEC_BAND_5G |
  1126. WL_CHANSPEC_BW_80 |
  1127. WL_CHANSPEC_CTL_SB_LL |
  1128. center_chan);
  1129. }
  1130. else if (CHSPEC_IS160(chspec)) {
  1131. center_chan = CHSPEC_CHANNEL(chspec);
  1132. if (CHSPEC_CTL_SB(chspec) < WL_CHANSPEC_CTL_SB_ULL) {
  1133. /* Primary 80MHz is on lower side */
  1134. center_chan -= CH_40MHZ_APART;
  1135. }
  1136. else {
  1137. /* Primary 80MHz is on upper side */
  1138. center_chan += CH_40MHZ_APART;
  1139. }
  1140. /* Create secondary 80MHz chanspec */
  1141. chspec80 = (chanspec_t)(WL_CHANSPEC_BAND_5G |
  1142. WL_CHANSPEC_BW_80 |
  1143. WL_CHANSPEC_CTL_SB_LL |
  1144. center_chan);
  1145. }
  1146. else {
  1147. chspec80 = INVCHANSPEC;
  1148. }
  1149. return chspec80;
  1150. }
  1151. /*
  1152. * For 160MHz or 80P80 chanspec, set ch[0]/ch[1] to be the low/high 80 Mhz channels
  1153. *
  1154. * For 20/40/80MHz chanspec, set ch[0] to be the center freq, and chan[1]=-1
  1155. */
  1156. void
  1157. wf_chspec_get_80p80_channels(chanspec_t chspec, uint8 *ch)
  1158. {
  1159. if (CHSPEC_IS8080(chspec)) {
  1160. ch[0] = wf_chspec_get80Mhz_ch(CHSPEC_CHAN1(chspec));
  1161. ch[1] = wf_chspec_get80Mhz_ch(CHSPEC_CHAN2(chspec));
  1162. }
  1163. else if (CHSPEC_IS160(chspec)) {
  1164. uint8 center_chan = CHSPEC_CHANNEL(chspec);
  1165. ch[0] = center_chan - CH_40MHZ_APART;
  1166. ch[1] = center_chan + CH_40MHZ_APART;
  1167. }
  1168. else {
  1169. /* for 20, 40, and 80 Mhz */
  1170. ch[0] = CHSPEC_CHANNEL(chspec);
  1171. ch[1] = 0xFFu;
  1172. }
  1173. return;
  1174. }
  1175. #ifdef WL11AC_80P80
  1176. uint8
  1177. wf_chspec_channel(chanspec_t chspec)
  1178. {
  1179. if (CHSPEC_IS8080(chspec)) {
  1180. return wf_chspec_primary80_channel(chspec);
  1181. }
  1182. else {
  1183. return ((uint8)((chspec) & WL_CHANSPEC_CHAN_MASK));
  1184. }
  1185. }
  1186. #endif /* WL11AC_80P80 */
  1187. /* This routine returns the chanspec for a given operating class and
  1188. * channel number
  1189. */
  1190. chanspec_t
  1191. wf_channel_create_chspec_frm_opclass(uint8 opclass, uint8 channel)
  1192. {
  1193. chanspec_t chanspec = 0;
  1194. uint16 opclass_info = 0;
  1195. uint16 lookupindex = 0;
  1196. switch (opclass) {
  1197. case 115:
  1198. lookupindex = 1;
  1199. break;
  1200. case 124:
  1201. lookupindex = 3;
  1202. break;
  1203. case 125:
  1204. lookupindex = 5;
  1205. break;
  1206. case 81:
  1207. lookupindex = 12;
  1208. break;
  1209. case 116:
  1210. lookupindex = 22;
  1211. break;
  1212. case 119:
  1213. lookupindex = 23;
  1214. break;
  1215. case 126:
  1216. lookupindex = 25;
  1217. break;
  1218. case 83:
  1219. lookupindex = 32;
  1220. break;
  1221. case 84:
  1222. lookupindex = 33;
  1223. break;
  1224. default:
  1225. lookupindex = 12;
  1226. }
  1227. if (lookupindex < 33) {
  1228. opclass_info = opclass_data[lookupindex-1];
  1229. }
  1230. else {
  1231. opclass_info = opclass_data[11];
  1232. }
  1233. chanspec = opclass_info | (uint16)channel;
  1234. return chanspec;
  1235. }
  1236. /* This routine returns the opclass for a given chanspec */
  1237. int
  1238. wf_channel_create_opclass_frm_chspec(chanspec_t chspec)
  1239. {
  1240. BCM_REFERENCE(chspec);
  1241. /* TODO: Implement this function ! */
  1242. return 12; /* opclass 12 for basic 2G channels */
  1243. }
  1244. /* Populates array with all 20MHz side bands of a given chanspec_t in the following order:
  1245. * primary20, secondary20, two secondary40s, four secondary80s.
  1246. * 'chspec' is the chanspec of interest
  1247. * 'pext' must point to an uint8 array of long enough to hold all side bands of the given chspec
  1248. *
  1249. * Works with 20, 40, 80, 80p80 and 160MHz chspec
  1250. */
  1251. void
  1252. wf_get_all_ext(chanspec_t chspec, uint8 *pext)
  1253. {
  1254. #ifdef WL11N_20MHZONLY
  1255. GET_ALL_SB(chspec, pext);
  1256. #else /* !WL11N_20MHZONLY */
  1257. chanspec_t t = (CHSPEC_IS160(chspec) || CHSPEC_IS8080(chspec)) ? /* if bw > 80MHz */
  1258. wf_chspec_primary80_chspec(chspec) : (chspec); /* extract primary 80 */
  1259. /* primary20 channel as first element */
  1260. uint8 pri_ch = (pext)[0] = wf_chspec_primary20_chan(t);
  1261. if (CHSPEC_IS20(chspec)) return; /* nothing more to do since 20MHz chspec */
  1262. /* 20MHz EXT */
  1263. (pext)[1] = pri_ch + (uint8)(IS_CTL_IN_L20(t) ? CH_20MHZ_APART : -CH_20MHZ_APART);
  1264. if (CHSPEC_IS40(chspec)) return; /* nothing more to do since 40MHz chspec */
  1265. /* center 40MHz EXT */
  1266. t = wf_channel2chspec((uint)(pri_ch + (IS_CTL_IN_L40(chspec) ?
  1267. CH_40MHZ_APART : -CH_40MHZ_APART)), WL_CHANSPEC_BW_40);
  1268. GET_ALL_SB(t, &((pext)[2])); /* get the 20MHz side bands in 40MHz EXT */
  1269. if (CHSPEC_IS80(chspec)) return; /* nothing more to do since 80MHz chspec */
  1270. t = CH80MHZ_CHSPEC(wf_chspec_secondary80_channel(chspec), WL_CHANSPEC_CTL_SB_LLL);
  1271. /* get the 20MHz side bands in 80MHz EXT (secondary) */
  1272. GET_ALL_SB(t, &((pext)[4]));
  1273. #endif /* !WL11N_20MHZONLY */
  1274. }
  1275. /*
  1276. * Given two chanspecs, returns true if they overlap.
  1277. * (Overlap: At least one 20MHz subband is common between the two chanspecs provided)
  1278. */
  1279. bool wf_chspec_overlap(chanspec_t chspec0, chanspec_t chspec1)
  1280. {
  1281. uint8 ch0, ch1;
  1282. FOREACH_20_SB(chspec0, ch0) {
  1283. FOREACH_20_SB(chspec1, ch1) {
  1284. if (ABS(ch0 - ch1) < CH_20MHZ_APART) {
  1285. return TRUE;
  1286. }
  1287. }
  1288. }
  1289. return FALSE;
  1290. }
  1291. uint8
  1292. channel_bw_to_width(chanspec_t chspec)
  1293. {
  1294. uint8 channel_width;
  1295. if (CHSPEC_IS80(chspec))
  1296. channel_width = VHT_OP_CHAN_WIDTH_80;
  1297. else if (CHSPEC_IS160(chspec))
  1298. channel_width = VHT_OP_CHAN_WIDTH_160;
  1299. else if (CHSPEC_IS8080(chspec))
  1300. channel_width = VHT_OP_CHAN_WIDTH_80_80;
  1301. else
  1302. channel_width = VHT_OP_CHAN_WIDTH_20_40;
  1303. return channel_width;
  1304. }