diff --git a/src/band.c b/src/band.c index b1932f0b..4d9624f1 100644 --- a/src/band.c +++ b/src/band.c @@ -923,3 +923,196 @@ int oci_from_chandef(const struct band_chandef *own, uint8_t oci[static 3]) return -ENOENT; } + +uint8_t band_freq_to_channel(uint32_t freq, enum band_freq *out_band) +{ + uint32_t channel = 0; + + if (freq >= 2412 && freq <= 2484) { + if (freq == 2484) + channel = 14; + else { + channel = freq - 2407; + + if (channel % 5) + return 0; + + channel /= 5; + } + + if (out_band) + *out_band = BAND_FREQ_2_4_GHZ; + + return channel; + } + + if (freq >= 5005 && freq < 5900) { + if (freq % 5) + return 0; + + channel = (freq - 5000) / 5; + + if (out_band) + *out_band = BAND_FREQ_5_GHZ; + + return channel; + } + + if (freq >= 4905 && freq < 5000) { + if (freq % 5) + return 0; + + channel = (freq - 4000) / 5; + + if (out_band) + *out_band = BAND_FREQ_5_GHZ; + + return channel; + } + + return 0; +} + +uint32_t band_channel_to_freq(uint8_t channel, enum band_freq band) +{ + if (band == BAND_FREQ_2_4_GHZ) { + if (channel >= 1 && channel <= 13) + return 2407 + 5 * channel; + + if (channel == 14) + return 2484; + } + + if (band == BAND_FREQ_5_GHZ) { + if (channel >= 1 && channel <= 179) + return 5000 + 5 * channel; + + if (channel >= 181 && channel <= 199) + return 4000 + 5 * channel; + } + + return 0; +} + +static const char *const oper_class_us_codes[] = { + "US", "CA" +}; + +static const char *const oper_class_eu_codes[] = { + "AL", "AM", "AT", "AZ", "BA", "BE", "BG", "BY", "CH", "CY", "CZ", "DE", + "DK", "EE", "EL", "ES", "FI", "FR", "GE", "HR", "HU", "IE", "IS", "IT", + "LI", "LT", "LU", "LV", "MD", "ME", "MK", "MT", "NL", "NO", "PL", "PT", + "RO", "RS", "RU", "SE", "SI", "SK", "TR", "UA", "UK" +}; + +/* Annex E, table E-1 */ +static const uint8_t oper_class_us_to_global[] = { + [1] = 115, [2] = 118, [3] = 124, [4] = 121, + [5] = 125, [6] = 103, [7] = 103, [8] = 102, + [9] = 102, [10] = 101, [11] = 101, [12] = 81, + [13] = 94, [14] = 95, [15] = 96, [22] = 116, + [23] = 119, [24] = 122, [25] = 126, [26] = 126, + [27] = 117, [28] = 120, [29] = 123, [30] = 127, + [31] = 127, [32] = 83, [33] = 84, [34] = 180, + /* 128 - 130 is a 1 to 1 mapping */ +}; + +/* Annex E, table E-2 */ +static const uint8_t oper_class_eu_to_global[] = { + [1] = 115, [2] = 118, [3] = 121, [4] = 81, + [5] = 116, [6] = 119, [7] = 122, [8] = 117, + [9] = 120, [10] = 123, [11] = 83, [12] = 84, + [17] = 125, [18] = 130, + /* 128 - 130 is a 1 to 1 mapping */ +}; + +/* Annex E, table E-3 */ +static const uint8_t oper_class_jp_to_global[] = { + [1] = 115, [2] = 112, [3] = 112, [4] = 112, + [5] = 112, [6] = 112, [7] = 109, [8] = 109, + [9] = 109, [10] = 109, [11] = 109, [12] = 113, + [13] = 113, [14] = 113, [15] = 113, [16] = 110, + [17] = 110, [18] = 110, [19] = 110, [20] = 110, + [21] = 114, [22] = 114, [23] = 114, [24] = 114, + [25] = 111, [26] = 111, [27] = 111, [28] = 111, + [29] = 111, [30] = 81, [31] = 82, [32] = 118, + [33] = 118, [34] = 121, [35] = 121, [36] = 116, + [37] = 119, [38] = 119, [39] = 122, [40] = 122, + [41] = 117, [42] = 120, [43] = 120, [44] = 123, + [45] = 123, [46] = 104, [47] = 104, [48] = 104, + [49] = 104, [50] = 104, [51] = 105, [52] = 105, + [53] = 105, [54] = 105, [55] = 105, [56] = 83, + [57] = 84, [58] = 121, [59] = 180, + /* 128 - 130 is a 1 to 1 mapping */ +}; + +/* Annex E, table E-4 (only 2.4GHz and 4.9 / 5GHz bands) */ +static const enum band_freq oper_class_to_band_global[] = { + [81 ... 84] = BAND_FREQ_2_4_GHZ, + [104 ... 130] = BAND_FREQ_5_GHZ, +}; + +/* Annex E, table E-5 */ +static const uint8_t oper_class_cn_to_global[] = { + [1] = 115, [2] = 118, [3] = 125, [4] = 116, + [5] = 119, [6] = 126, [7] = 81, [8] = 83, + [9] = 84, + /* 128 - 130 is a 1 to 1 mapping */ +}; + +enum band_freq band_oper_class_to_band(const uint8_t *country, + uint8_t oper_class) +{ + unsigned int i; + int table = 0; + + if (country && country[2] >= 1 && country[2] <= 5) + table = country[2]; + else if (country) { + for (i = 0; i < L_ARRAY_SIZE(oper_class_us_codes); i++) + if (!memcmp(oper_class_us_codes[i], country, 2)) { + /* Use table E-1 */ + table = 1; + break; + } + + for (i = 0; i < L_ARRAY_SIZE(oper_class_eu_codes); i++) + if (!memcmp(oper_class_eu_codes[i], country, 2)) { + /* Use table E-2 */ + table = 2; + break; + } + + if (!memcmp("JP", country, 2)) + /* Use table E-3 */ + table = 3; + + if (!memcmp("CN", country, 2)) + /* Use table E-5 */ + table = 5; + } + + switch (table) { + case 1: + if (oper_class < L_ARRAY_SIZE(oper_class_us_to_global)) + oper_class = oper_class_us_to_global[oper_class]; + break; + case 2: + if (oper_class < L_ARRAY_SIZE(oper_class_eu_to_global)) + oper_class = oper_class_eu_to_global[oper_class]; + break; + case 3: + if (oper_class < L_ARRAY_SIZE(oper_class_jp_to_global)) + oper_class = oper_class_jp_to_global[oper_class]; + break; + case 5: + if (oper_class < L_ARRAY_SIZE(oper_class_cn_to_global)) + oper_class = oper_class_cn_to_global[oper_class]; + break; + } + + if (oper_class < L_ARRAY_SIZE(oper_class_to_band_global)) + return oper_class_to_band_global[oper_class]; + else + return 0; +} diff --git a/src/band.h b/src/band.h index 1bb5af8e..2320bbcf 100644 --- a/src/band.h +++ b/src/band.h @@ -36,6 +36,11 @@ enum band_chandef_width { BAND_CHANDEF_WIDTH_160, }; +enum band_freq { + BAND_FREQ_2_4_GHZ = 0x1, + BAND_FREQ_5_GHZ = 0x2, +}; + struct band_chandef { uint32_t frequency; uint32_t channel_width; @@ -76,3 +81,8 @@ int oci_to_frequency(uint32_t operating_class, uint32_t channel); int oci_verify(const uint8_t oci[static 3], const struct band_chandef *own); int oci_from_chandef(const struct band_chandef *own, uint8_t oci[static 3]); + +uint8_t band_freq_to_channel(uint32_t freq, enum band_freq *out_band); +uint32_t band_channel_to_freq(uint8_t channel, enum band_freq band); +enum band_freq band_oper_class_to_band(const uint8_t *country, + uint8_t oper_class);