.. | .. |
---|
5 | 5 | * Copyright 2008-2011 Luis R. Rodriguez <mcgrof@qca.qualcomm.com> |
---|
6 | 6 | * Copyright 2013-2014 Intel Mobile Communications GmbH |
---|
7 | 7 | * Copyright 2017 Intel Deutschland GmbH |
---|
8 | | - * Copyright (C) 2018 Intel Corporation |
---|
| 8 | + * Copyright (C) 2018 - 2019 Intel Corporation |
---|
9 | 9 | * |
---|
10 | 10 | * Permission to use, copy, modify, and/or distribute this software for any |
---|
11 | 11 | * purpose with or without fee is hereby granted, provided that the above |
---|
.. | .. |
---|
131 | 131 | /* Used to track the userspace process controlling the indoor setting */ |
---|
132 | 132 | static u32 reg_is_indoor_portid; |
---|
133 | 133 | |
---|
134 | | -static void restore_regulatory_settings(bool reset_user); |
---|
| 134 | +static void restore_regulatory_settings(bool reset_user, bool cached); |
---|
| 135 | +static void print_regdomain(const struct ieee80211_regdomain *rd); |
---|
135 | 136 | |
---|
136 | 137 | static const struct ieee80211_regdomain *get_cfg80211_regdom(void) |
---|
137 | 138 | { |
---|
.. | .. |
---|
263 | 264 | |
---|
264 | 265 | static char *ieee80211_regdom = "00"; |
---|
265 | 266 | static char user_alpha2[2]; |
---|
| 267 | +static const struct ieee80211_regdomain *cfg80211_user_regdom; |
---|
266 | 268 | |
---|
267 | 269 | module_param(ieee80211_regdom, charp, 0444); |
---|
268 | 270 | MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code"); |
---|
.. | .. |
---|
425 | 427 | reg_copy_regd(const struct ieee80211_regdomain *src_regd) |
---|
426 | 428 | { |
---|
427 | 429 | struct ieee80211_regdomain *regd; |
---|
428 | | - int size_of_regd; |
---|
429 | 430 | unsigned int i; |
---|
430 | 431 | |
---|
431 | | - size_of_regd = |
---|
432 | | - sizeof(struct ieee80211_regdomain) + |
---|
433 | | - src_regd->n_reg_rules * sizeof(struct ieee80211_reg_rule); |
---|
434 | | - |
---|
435 | | - regd = kzalloc(size_of_regd, GFP_KERNEL); |
---|
| 432 | + regd = kzalloc(struct_size(regd, reg_rules, src_regd->n_reg_rules), |
---|
| 433 | + GFP_KERNEL); |
---|
436 | 434 | if (!regd) |
---|
437 | 435 | return ERR_PTR(-ENOMEM); |
---|
438 | 436 | |
---|
.. | .. |
---|
443 | 441 | sizeof(struct ieee80211_reg_rule)); |
---|
444 | 442 | |
---|
445 | 443 | return regd; |
---|
| 444 | +} |
---|
| 445 | + |
---|
| 446 | +static void cfg80211_save_user_regdom(const struct ieee80211_regdomain *rd) |
---|
| 447 | +{ |
---|
| 448 | + ASSERT_RTNL(); |
---|
| 449 | + |
---|
| 450 | + if (!IS_ERR(cfg80211_user_regdom)) |
---|
| 451 | + kfree(cfg80211_user_regdom); |
---|
| 452 | + cfg80211_user_regdom = reg_copy_regd(rd); |
---|
446 | 453 | } |
---|
447 | 454 | |
---|
448 | 455 | struct reg_regdb_apply_request { |
---|
.. | .. |
---|
510 | 517 | pr_debug("Timeout while waiting for CRDA to reply, restoring regulatory settings\n"); |
---|
511 | 518 | rtnl_lock(); |
---|
512 | 519 | reg_crda_timeouts++; |
---|
513 | | - restore_regulatory_settings(true); |
---|
| 520 | + restore_regulatory_settings(true, false); |
---|
514 | 521 | rtnl_unlock(); |
---|
515 | 522 | } |
---|
516 | 523 | |
---|
.. | .. |
---|
780 | 787 | return 0; |
---|
781 | 788 | } |
---|
782 | 789 | |
---|
| 790 | +MODULE_FIRMWARE("regulatory.db.p7s"); |
---|
| 791 | + |
---|
783 | 792 | static bool regdb_has_valid_signature(const u8 *data, unsigned int size) |
---|
784 | 793 | { |
---|
785 | 794 | const struct firmware *sig; |
---|
.. | .. |
---|
937 | 946 | unsigned int ptr = be16_to_cpu(country->coll_ptr) << 2; |
---|
938 | 947 | struct fwdb_collection *coll = (void *)((u8 *)db + ptr); |
---|
939 | 948 | struct ieee80211_regdomain *regdom; |
---|
940 | | - unsigned int size_of_regd, i; |
---|
| 949 | + unsigned int i; |
---|
941 | 950 | |
---|
942 | | - size_of_regd = sizeof(struct ieee80211_regdomain) + |
---|
943 | | - coll->n_rules * sizeof(struct ieee80211_reg_rule); |
---|
944 | | - |
---|
945 | | - regdom = kzalloc(size_of_regd, GFP_KERNEL); |
---|
| 951 | + regdom = kzalloc(struct_size(regdom, reg_rules, coll->n_rules), |
---|
| 952 | + GFP_KERNEL); |
---|
946 | 953 | if (!regdom) |
---|
947 | 954 | return -ENOMEM; |
---|
948 | 955 | |
---|
.. | .. |
---|
1024 | 1031 | } |
---|
1025 | 1032 | |
---|
1026 | 1033 | rtnl_lock(); |
---|
1027 | | - if (WARN_ON(regdb && !IS_ERR(regdb))) { |
---|
1028 | | - /* just restore and free new db */ |
---|
| 1034 | + if (regdb && !IS_ERR(regdb)) { |
---|
| 1035 | + /* negative case - a bug |
---|
| 1036 | + * positive case - can happen due to race in case of multiple cb's in |
---|
| 1037 | + * queue, due to usage of asynchronous callback |
---|
| 1038 | + * |
---|
| 1039 | + * Either case, just restore and free new db. |
---|
| 1040 | + */ |
---|
1029 | 1041 | } else if (set_error) { |
---|
1030 | 1042 | regdb = ERR_PTR(set_error); |
---|
1031 | 1043 | } else if (fw) { |
---|
.. | .. |
---|
1039 | 1051 | } |
---|
1040 | 1052 | |
---|
1041 | 1053 | if (restore) |
---|
1042 | | - restore_regulatory_settings(true); |
---|
| 1054 | + restore_regulatory_settings(true, false); |
---|
1043 | 1055 | |
---|
1044 | 1056 | rtnl_unlock(); |
---|
1045 | 1057 | |
---|
.. | .. |
---|
1048 | 1060 | release_firmware(fw); |
---|
1049 | 1061 | } |
---|
1050 | 1062 | |
---|
| 1063 | +MODULE_FIRMWARE("regulatory.db"); |
---|
| 1064 | + |
---|
1051 | 1065 | static int query_regdb_file(const char *alpha2) |
---|
1052 | 1066 | { |
---|
| 1067 | + int err; |
---|
| 1068 | + |
---|
1053 | 1069 | ASSERT_RTNL(); |
---|
1054 | 1070 | |
---|
1055 | 1071 | if (regdb) |
---|
.. | .. |
---|
1059 | 1075 | if (!alpha2) |
---|
1060 | 1076 | return -ENOMEM; |
---|
1061 | 1077 | |
---|
1062 | | - return request_firmware_nowait(THIS_MODULE, true, "regulatory.db", |
---|
1063 | | - ®_pdev->dev, GFP_KERNEL, |
---|
1064 | | - (void *)alpha2, regdb_fw_cb); |
---|
| 1078 | + err = request_firmware_nowait(THIS_MODULE, true, "regulatory.db", |
---|
| 1079 | + ®_pdev->dev, GFP_KERNEL, |
---|
| 1080 | + (void *)alpha2, regdb_fw_cb); |
---|
| 1081 | + if (err) |
---|
| 1082 | + kfree(alpha2); |
---|
| 1083 | + |
---|
| 1084 | + return err; |
---|
1065 | 1085 | } |
---|
1066 | 1086 | |
---|
1067 | 1087 | int reg_reload_regdb(void) |
---|
.. | .. |
---|
1473 | 1493 | regdom_intersect(const struct ieee80211_regdomain *rd1, |
---|
1474 | 1494 | const struct ieee80211_regdomain *rd2) |
---|
1475 | 1495 | { |
---|
1476 | | - int r, size_of_regd; |
---|
| 1496 | + int r; |
---|
1477 | 1497 | unsigned int x, y; |
---|
1478 | 1498 | unsigned int num_rules = 0; |
---|
1479 | 1499 | const struct ieee80211_reg_rule *rule1, *rule2; |
---|
.. | .. |
---|
1504 | 1524 | if (!num_rules) |
---|
1505 | 1525 | return NULL; |
---|
1506 | 1526 | |
---|
1507 | | - size_of_regd = sizeof(struct ieee80211_regdomain) + |
---|
1508 | | - num_rules * sizeof(struct ieee80211_reg_rule); |
---|
1509 | | - |
---|
1510 | | - rd = kzalloc(size_of_regd, GFP_KERNEL); |
---|
| 1527 | + rd = kzalloc(struct_size(rd, reg_rules, num_rules), GFP_KERNEL); |
---|
1511 | 1528 | if (!rd) |
---|
1512 | 1529 | return NULL; |
---|
1513 | 1530 | |
---|
.. | .. |
---|
1562 | 1579 | channel_flags |= IEEE80211_CHAN_NO_80MHZ; |
---|
1563 | 1580 | if (rd_flags & NL80211_RRF_NO_160MHZ) |
---|
1564 | 1581 | channel_flags |= IEEE80211_CHAN_NO_160MHZ; |
---|
| 1582 | + if (rd_flags & NL80211_RRF_NO_HE) |
---|
| 1583 | + channel_flags |= IEEE80211_CHAN_NO_HE; |
---|
1565 | 1584 | return channel_flags; |
---|
1566 | 1585 | } |
---|
1567 | 1586 | |
---|
.. | .. |
---|
1585 | 1604 | |
---|
1586 | 1605 | /* |
---|
1587 | 1606 | * We only need to know if one frequency rule was |
---|
1588 | | - * was in center_freq's band, that's enough, so lets |
---|
| 1607 | + * in center_freq's band, that's enough, so let's |
---|
1589 | 1608 | * not overwrite it once found |
---|
1590 | 1609 | */ |
---|
1591 | 1610 | if (!band_rule_found) |
---|
.. | .. |
---|
1607 | 1626 | __freq_reg_info(struct wiphy *wiphy, u32 center_freq, u32 min_bw) |
---|
1608 | 1627 | { |
---|
1609 | 1628 | const struct ieee80211_regdomain *regd = reg_get_regdomain(wiphy); |
---|
1610 | | - const struct ieee80211_reg_rule *reg_rule = NULL; |
---|
| 1629 | + const u32 bws[] = {0, 1, 2, 4, 5, 8, 10, 16, 20}; |
---|
| 1630 | + const struct ieee80211_reg_rule *reg_rule; |
---|
| 1631 | + int i = ARRAY_SIZE(bws) - 1; |
---|
1611 | 1632 | u32 bw; |
---|
1612 | 1633 | |
---|
1613 | | - for (bw = MHZ_TO_KHZ(20); bw >= min_bw; bw = bw / 2) { |
---|
| 1634 | + for (bw = MHZ_TO_KHZ(bws[i]); bw >= min_bw; bw = MHZ_TO_KHZ(bws[i--])) { |
---|
1614 | 1635 | reg_rule = freq_reg_info_regd(center_freq, regd, bw); |
---|
1615 | 1636 | if (!IS_ERR(reg_rule)) |
---|
1616 | 1637 | return reg_rule; |
---|
.. | .. |
---|
1622 | 1643 | const struct ieee80211_reg_rule *freq_reg_info(struct wiphy *wiphy, |
---|
1623 | 1644 | u32 center_freq) |
---|
1624 | 1645 | { |
---|
1625 | | - return __freq_reg_info(wiphy, center_freq, MHZ_TO_KHZ(20)); |
---|
| 1646 | + u32 min_bw = center_freq < MHZ_TO_KHZ(1000) ? 1 : 20; |
---|
| 1647 | + |
---|
| 1648 | + return __freq_reg_info(wiphy, center_freq, MHZ_TO_KHZ(min_bw)); |
---|
1626 | 1649 | } |
---|
1627 | 1650 | EXPORT_SYMBOL(freq_reg_info); |
---|
1628 | 1651 | |
---|
.. | .. |
---|
1649 | 1672 | const struct ieee80211_channel *chan) |
---|
1650 | 1673 | { |
---|
1651 | 1674 | const struct ieee80211_freq_range *freq_range = NULL; |
---|
1652 | | - u32 max_bandwidth_khz, bw_flags = 0; |
---|
| 1675 | + u32 max_bandwidth_khz, center_freq_khz, bw_flags = 0; |
---|
| 1676 | + bool is_s1g = chan->band == NL80211_BAND_S1GHZ; |
---|
1653 | 1677 | |
---|
1654 | 1678 | freq_range = ®_rule->freq_range; |
---|
1655 | 1679 | |
---|
1656 | 1680 | max_bandwidth_khz = freq_range->max_bandwidth_khz; |
---|
| 1681 | + center_freq_khz = ieee80211_channel_to_khz(chan); |
---|
1657 | 1682 | /* Check if auto calculation requested */ |
---|
1658 | 1683 | if (reg_rule->flags & NL80211_RRF_AUTO_BW) |
---|
1659 | 1684 | max_bandwidth_khz = reg_get_max_bandwidth(regd, reg_rule); |
---|
1660 | 1685 | |
---|
1661 | 1686 | /* If we get a reg_rule we can assume that at least 5Mhz fit */ |
---|
1662 | 1687 | if (!cfg80211_does_bw_fit_range(freq_range, |
---|
1663 | | - MHZ_TO_KHZ(chan->center_freq), |
---|
| 1688 | + center_freq_khz, |
---|
1664 | 1689 | MHZ_TO_KHZ(10))) |
---|
1665 | 1690 | bw_flags |= IEEE80211_CHAN_NO_10MHZ; |
---|
1666 | 1691 | if (!cfg80211_does_bw_fit_range(freq_range, |
---|
1667 | | - MHZ_TO_KHZ(chan->center_freq), |
---|
| 1692 | + center_freq_khz, |
---|
1668 | 1693 | MHZ_TO_KHZ(20))) |
---|
1669 | 1694 | bw_flags |= IEEE80211_CHAN_NO_20MHZ; |
---|
1670 | 1695 | |
---|
1671 | | - if (max_bandwidth_khz < MHZ_TO_KHZ(10)) |
---|
1672 | | - bw_flags |= IEEE80211_CHAN_NO_10MHZ; |
---|
1673 | | - if (max_bandwidth_khz < MHZ_TO_KHZ(20)) |
---|
1674 | | - bw_flags |= IEEE80211_CHAN_NO_20MHZ; |
---|
1675 | | - if (max_bandwidth_khz < MHZ_TO_KHZ(40)) |
---|
1676 | | - bw_flags |= IEEE80211_CHAN_NO_HT40; |
---|
1677 | | - if (max_bandwidth_khz < MHZ_TO_KHZ(80)) |
---|
1678 | | - bw_flags |= IEEE80211_CHAN_NO_80MHZ; |
---|
1679 | | - if (max_bandwidth_khz < MHZ_TO_KHZ(160)) |
---|
1680 | | - bw_flags |= IEEE80211_CHAN_NO_160MHZ; |
---|
| 1696 | + if (is_s1g) { |
---|
| 1697 | + /* S1G is strict about non overlapping channels. We can |
---|
| 1698 | + * calculate which bandwidth is allowed per channel by finding |
---|
| 1699 | + * the largest bandwidth which cleanly divides the freq_range. |
---|
| 1700 | + */ |
---|
| 1701 | + int edge_offset; |
---|
| 1702 | + int ch_bw = max_bandwidth_khz; |
---|
| 1703 | + |
---|
| 1704 | + while (ch_bw) { |
---|
| 1705 | + edge_offset = (center_freq_khz - ch_bw / 2) - |
---|
| 1706 | + freq_range->start_freq_khz; |
---|
| 1707 | + if (edge_offset % ch_bw == 0) { |
---|
| 1708 | + switch (KHZ_TO_MHZ(ch_bw)) { |
---|
| 1709 | + case 1: |
---|
| 1710 | + bw_flags |= IEEE80211_CHAN_1MHZ; |
---|
| 1711 | + break; |
---|
| 1712 | + case 2: |
---|
| 1713 | + bw_flags |= IEEE80211_CHAN_2MHZ; |
---|
| 1714 | + break; |
---|
| 1715 | + case 4: |
---|
| 1716 | + bw_flags |= IEEE80211_CHAN_4MHZ; |
---|
| 1717 | + break; |
---|
| 1718 | + case 8: |
---|
| 1719 | + bw_flags |= IEEE80211_CHAN_8MHZ; |
---|
| 1720 | + break; |
---|
| 1721 | + case 16: |
---|
| 1722 | + bw_flags |= IEEE80211_CHAN_16MHZ; |
---|
| 1723 | + break; |
---|
| 1724 | + default: |
---|
| 1725 | + /* If we got here, no bandwidths fit on |
---|
| 1726 | + * this frequency, ie. band edge. |
---|
| 1727 | + */ |
---|
| 1728 | + bw_flags |= IEEE80211_CHAN_DISABLED; |
---|
| 1729 | + break; |
---|
| 1730 | + } |
---|
| 1731 | + break; |
---|
| 1732 | + } |
---|
| 1733 | + ch_bw /= 2; |
---|
| 1734 | + } |
---|
| 1735 | + } else { |
---|
| 1736 | + if (max_bandwidth_khz < MHZ_TO_KHZ(10)) |
---|
| 1737 | + bw_flags |= IEEE80211_CHAN_NO_10MHZ; |
---|
| 1738 | + if (max_bandwidth_khz < MHZ_TO_KHZ(20)) |
---|
| 1739 | + bw_flags |= IEEE80211_CHAN_NO_20MHZ; |
---|
| 1740 | + if (max_bandwidth_khz < MHZ_TO_KHZ(40)) |
---|
| 1741 | + bw_flags |= IEEE80211_CHAN_NO_HT40; |
---|
| 1742 | + if (max_bandwidth_khz < MHZ_TO_KHZ(80)) |
---|
| 1743 | + bw_flags |= IEEE80211_CHAN_NO_80MHZ; |
---|
| 1744 | + if (max_bandwidth_khz < MHZ_TO_KHZ(160)) |
---|
| 1745 | + bw_flags |= IEEE80211_CHAN_NO_160MHZ; |
---|
| 1746 | + } |
---|
1681 | 1747 | return bw_flags; |
---|
1682 | 1748 | } |
---|
1683 | 1749 | |
---|
1684 | | -/* |
---|
1685 | | - * Note that right now we assume the desired channel bandwidth |
---|
1686 | | - * is always 20 MHz for each individual channel (HT40 uses 20 MHz |
---|
1687 | | - * per channel, the primary and the extension channel). |
---|
1688 | | - */ |
---|
1689 | | -static void handle_channel(struct wiphy *wiphy, |
---|
1690 | | - enum nl80211_reg_initiator initiator, |
---|
1691 | | - struct ieee80211_channel *chan) |
---|
| 1750 | +static void handle_channel_single_rule(struct wiphy *wiphy, |
---|
| 1751 | + enum nl80211_reg_initiator initiator, |
---|
| 1752 | + struct ieee80211_channel *chan, |
---|
| 1753 | + u32 flags, |
---|
| 1754 | + struct regulatory_request *lr, |
---|
| 1755 | + struct wiphy *request_wiphy, |
---|
| 1756 | + const struct ieee80211_reg_rule *reg_rule) |
---|
1692 | 1757 | { |
---|
1693 | | - u32 flags, bw_flags = 0; |
---|
1694 | | - const struct ieee80211_reg_rule *reg_rule = NULL; |
---|
| 1758 | + u32 bw_flags = 0; |
---|
1695 | 1759 | const struct ieee80211_power_rule *power_rule = NULL; |
---|
1696 | | - struct wiphy *request_wiphy = NULL; |
---|
1697 | | - struct regulatory_request *lr = get_last_request(); |
---|
1698 | 1760 | const struct ieee80211_regdomain *regd; |
---|
1699 | | - |
---|
1700 | | - request_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx); |
---|
1701 | | - |
---|
1702 | | - flags = chan->orig_flags; |
---|
1703 | | - |
---|
1704 | | - reg_rule = freq_reg_info(wiphy, MHZ_TO_KHZ(chan->center_freq)); |
---|
1705 | | - if (IS_ERR(reg_rule)) { |
---|
1706 | | - /* |
---|
1707 | | - * We will disable all channels that do not match our |
---|
1708 | | - * received regulatory rule unless the hint is coming |
---|
1709 | | - * from a Country IE and the Country IE had no information |
---|
1710 | | - * about a band. The IEEE 802.11 spec allows for an AP |
---|
1711 | | - * to send only a subset of the regulatory rules allowed, |
---|
1712 | | - * so an AP in the US that only supports 2.4 GHz may only send |
---|
1713 | | - * a country IE with information for the 2.4 GHz band |
---|
1714 | | - * while 5 GHz is still supported. |
---|
1715 | | - */ |
---|
1716 | | - if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE && |
---|
1717 | | - PTR_ERR(reg_rule) == -ERANGE) |
---|
1718 | | - return; |
---|
1719 | | - |
---|
1720 | | - if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER && |
---|
1721 | | - request_wiphy && request_wiphy == wiphy && |
---|
1722 | | - request_wiphy->regulatory_flags & REGULATORY_STRICT_REG) { |
---|
1723 | | - pr_debug("Disabling freq %d MHz for good\n", |
---|
1724 | | - chan->center_freq); |
---|
1725 | | - chan->orig_flags |= IEEE80211_CHAN_DISABLED; |
---|
1726 | | - chan->flags = chan->orig_flags; |
---|
1727 | | - } else { |
---|
1728 | | - pr_debug("Disabling freq %d MHz\n", |
---|
1729 | | - chan->center_freq); |
---|
1730 | | - chan->flags |= IEEE80211_CHAN_DISABLED; |
---|
1731 | | - } |
---|
1732 | | - return; |
---|
1733 | | - } |
---|
1734 | 1761 | |
---|
1735 | 1762 | regd = reg_get_regdomain(wiphy); |
---|
1736 | 1763 | |
---|
.. | .. |
---|
1791 | 1818 | chan->max_reg_power); |
---|
1792 | 1819 | } else |
---|
1793 | 1820 | chan->max_power = chan->max_reg_power; |
---|
| 1821 | +} |
---|
| 1822 | + |
---|
| 1823 | +static void handle_channel_adjacent_rules(struct wiphy *wiphy, |
---|
| 1824 | + enum nl80211_reg_initiator initiator, |
---|
| 1825 | + struct ieee80211_channel *chan, |
---|
| 1826 | + u32 flags, |
---|
| 1827 | + struct regulatory_request *lr, |
---|
| 1828 | + struct wiphy *request_wiphy, |
---|
| 1829 | + const struct ieee80211_reg_rule *rrule1, |
---|
| 1830 | + const struct ieee80211_reg_rule *rrule2, |
---|
| 1831 | + struct ieee80211_freq_range *comb_range) |
---|
| 1832 | +{ |
---|
| 1833 | + u32 bw_flags1 = 0; |
---|
| 1834 | + u32 bw_flags2 = 0; |
---|
| 1835 | + const struct ieee80211_power_rule *power_rule1 = NULL; |
---|
| 1836 | + const struct ieee80211_power_rule *power_rule2 = NULL; |
---|
| 1837 | + const struct ieee80211_regdomain *regd; |
---|
| 1838 | + |
---|
| 1839 | + regd = reg_get_regdomain(wiphy); |
---|
| 1840 | + |
---|
| 1841 | + power_rule1 = &rrule1->power_rule; |
---|
| 1842 | + power_rule2 = &rrule2->power_rule; |
---|
| 1843 | + bw_flags1 = reg_rule_to_chan_bw_flags(regd, rrule1, chan); |
---|
| 1844 | + bw_flags2 = reg_rule_to_chan_bw_flags(regd, rrule2, chan); |
---|
| 1845 | + |
---|
| 1846 | + if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER && |
---|
| 1847 | + request_wiphy && request_wiphy == wiphy && |
---|
| 1848 | + request_wiphy->regulatory_flags & REGULATORY_STRICT_REG) { |
---|
| 1849 | + /* This guarantees the driver's requested regulatory domain |
---|
| 1850 | + * will always be used as a base for further regulatory |
---|
| 1851 | + * settings |
---|
| 1852 | + */ |
---|
| 1853 | + chan->flags = |
---|
| 1854 | + map_regdom_flags(rrule1->flags) | |
---|
| 1855 | + map_regdom_flags(rrule2->flags) | |
---|
| 1856 | + bw_flags1 | |
---|
| 1857 | + bw_flags2; |
---|
| 1858 | + chan->orig_flags = chan->flags; |
---|
| 1859 | + chan->max_antenna_gain = |
---|
| 1860 | + min_t(int, MBI_TO_DBI(power_rule1->max_antenna_gain), |
---|
| 1861 | + MBI_TO_DBI(power_rule2->max_antenna_gain)); |
---|
| 1862 | + chan->orig_mag = chan->max_antenna_gain; |
---|
| 1863 | + chan->max_reg_power = |
---|
| 1864 | + min_t(int, MBM_TO_DBM(power_rule1->max_eirp), |
---|
| 1865 | + MBM_TO_DBM(power_rule2->max_eirp)); |
---|
| 1866 | + chan->max_power = chan->max_reg_power; |
---|
| 1867 | + chan->orig_mpwr = chan->max_reg_power; |
---|
| 1868 | + |
---|
| 1869 | + if (chan->flags & IEEE80211_CHAN_RADAR) { |
---|
| 1870 | + chan->dfs_cac_ms = IEEE80211_DFS_MIN_CAC_TIME_MS; |
---|
| 1871 | + if (rrule1->dfs_cac_ms || rrule2->dfs_cac_ms) |
---|
| 1872 | + chan->dfs_cac_ms = max_t(unsigned int, |
---|
| 1873 | + rrule1->dfs_cac_ms, |
---|
| 1874 | + rrule2->dfs_cac_ms); |
---|
| 1875 | + } |
---|
| 1876 | + |
---|
| 1877 | + return; |
---|
| 1878 | + } |
---|
| 1879 | + |
---|
| 1880 | + chan->dfs_state = NL80211_DFS_USABLE; |
---|
| 1881 | + chan->dfs_state_entered = jiffies; |
---|
| 1882 | + |
---|
| 1883 | + chan->beacon_found = false; |
---|
| 1884 | + chan->flags = flags | bw_flags1 | bw_flags2 | |
---|
| 1885 | + map_regdom_flags(rrule1->flags) | |
---|
| 1886 | + map_regdom_flags(rrule2->flags); |
---|
| 1887 | + |
---|
| 1888 | + /* reg_rule_to_chan_bw_flags may forbids 10 and forbids 20 MHz |
---|
| 1889 | + * (otherwise no adj. rule case), recheck therefore |
---|
| 1890 | + */ |
---|
| 1891 | + if (cfg80211_does_bw_fit_range(comb_range, |
---|
| 1892 | + ieee80211_channel_to_khz(chan), |
---|
| 1893 | + MHZ_TO_KHZ(10))) |
---|
| 1894 | + chan->flags &= ~IEEE80211_CHAN_NO_10MHZ; |
---|
| 1895 | + if (cfg80211_does_bw_fit_range(comb_range, |
---|
| 1896 | + ieee80211_channel_to_khz(chan), |
---|
| 1897 | + MHZ_TO_KHZ(20))) |
---|
| 1898 | + chan->flags &= ~IEEE80211_CHAN_NO_20MHZ; |
---|
| 1899 | + |
---|
| 1900 | + chan->max_antenna_gain = |
---|
| 1901 | + min_t(int, chan->orig_mag, |
---|
| 1902 | + min_t(int, |
---|
| 1903 | + MBI_TO_DBI(power_rule1->max_antenna_gain), |
---|
| 1904 | + MBI_TO_DBI(power_rule2->max_antenna_gain))); |
---|
| 1905 | + chan->max_reg_power = min_t(int, |
---|
| 1906 | + MBM_TO_DBM(power_rule1->max_eirp), |
---|
| 1907 | + MBM_TO_DBM(power_rule2->max_eirp)); |
---|
| 1908 | + |
---|
| 1909 | + if (chan->flags & IEEE80211_CHAN_RADAR) { |
---|
| 1910 | + if (rrule1->dfs_cac_ms || rrule2->dfs_cac_ms) |
---|
| 1911 | + chan->dfs_cac_ms = max_t(unsigned int, |
---|
| 1912 | + rrule1->dfs_cac_ms, |
---|
| 1913 | + rrule2->dfs_cac_ms); |
---|
| 1914 | + else |
---|
| 1915 | + chan->dfs_cac_ms = IEEE80211_DFS_MIN_CAC_TIME_MS; |
---|
| 1916 | + } |
---|
| 1917 | + |
---|
| 1918 | + if (chan->orig_mpwr) { |
---|
| 1919 | + /* Devices that use REGULATORY_COUNTRY_IE_FOLLOW_POWER |
---|
| 1920 | + * will always follow the passed country IE power settings. |
---|
| 1921 | + */ |
---|
| 1922 | + if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE && |
---|
| 1923 | + wiphy->regulatory_flags & REGULATORY_COUNTRY_IE_FOLLOW_POWER) |
---|
| 1924 | + chan->max_power = chan->max_reg_power; |
---|
| 1925 | + else |
---|
| 1926 | + chan->max_power = min(chan->orig_mpwr, |
---|
| 1927 | + chan->max_reg_power); |
---|
| 1928 | + } else { |
---|
| 1929 | + chan->max_power = chan->max_reg_power; |
---|
| 1930 | + } |
---|
| 1931 | +} |
---|
| 1932 | + |
---|
| 1933 | +/* Note that right now we assume the desired channel bandwidth |
---|
| 1934 | + * is always 20 MHz for each individual channel (HT40 uses 20 MHz |
---|
| 1935 | + * per channel, the primary and the extension channel). |
---|
| 1936 | + */ |
---|
| 1937 | +static void handle_channel(struct wiphy *wiphy, |
---|
| 1938 | + enum nl80211_reg_initiator initiator, |
---|
| 1939 | + struct ieee80211_channel *chan) |
---|
| 1940 | +{ |
---|
| 1941 | + const u32 orig_chan_freq = ieee80211_channel_to_khz(chan); |
---|
| 1942 | + struct regulatory_request *lr = get_last_request(); |
---|
| 1943 | + struct wiphy *request_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx); |
---|
| 1944 | + const struct ieee80211_reg_rule *rrule = NULL; |
---|
| 1945 | + const struct ieee80211_reg_rule *rrule1 = NULL; |
---|
| 1946 | + const struct ieee80211_reg_rule *rrule2 = NULL; |
---|
| 1947 | + |
---|
| 1948 | + u32 flags = chan->orig_flags; |
---|
| 1949 | + |
---|
| 1950 | + rrule = freq_reg_info(wiphy, orig_chan_freq); |
---|
| 1951 | + if (IS_ERR(rrule)) { |
---|
| 1952 | + /* check for adjacent match, therefore get rules for |
---|
| 1953 | + * chan - 20 MHz and chan + 20 MHz and test |
---|
| 1954 | + * if reg rules are adjacent |
---|
| 1955 | + */ |
---|
| 1956 | + rrule1 = freq_reg_info(wiphy, |
---|
| 1957 | + orig_chan_freq - MHZ_TO_KHZ(20)); |
---|
| 1958 | + rrule2 = freq_reg_info(wiphy, |
---|
| 1959 | + orig_chan_freq + MHZ_TO_KHZ(20)); |
---|
| 1960 | + if (!IS_ERR(rrule1) && !IS_ERR(rrule2)) { |
---|
| 1961 | + struct ieee80211_freq_range comb_range; |
---|
| 1962 | + |
---|
| 1963 | + if (rrule1->freq_range.end_freq_khz != |
---|
| 1964 | + rrule2->freq_range.start_freq_khz) |
---|
| 1965 | + goto disable_chan; |
---|
| 1966 | + |
---|
| 1967 | + comb_range.start_freq_khz = |
---|
| 1968 | + rrule1->freq_range.start_freq_khz; |
---|
| 1969 | + comb_range.end_freq_khz = |
---|
| 1970 | + rrule2->freq_range.end_freq_khz; |
---|
| 1971 | + comb_range.max_bandwidth_khz = |
---|
| 1972 | + min_t(u32, |
---|
| 1973 | + rrule1->freq_range.max_bandwidth_khz, |
---|
| 1974 | + rrule2->freq_range.max_bandwidth_khz); |
---|
| 1975 | + |
---|
| 1976 | + if (!cfg80211_does_bw_fit_range(&comb_range, |
---|
| 1977 | + orig_chan_freq, |
---|
| 1978 | + MHZ_TO_KHZ(20))) |
---|
| 1979 | + goto disable_chan; |
---|
| 1980 | + |
---|
| 1981 | + handle_channel_adjacent_rules(wiphy, initiator, chan, |
---|
| 1982 | + flags, lr, request_wiphy, |
---|
| 1983 | + rrule1, rrule2, |
---|
| 1984 | + &comb_range); |
---|
| 1985 | + return; |
---|
| 1986 | + } |
---|
| 1987 | + |
---|
| 1988 | +disable_chan: |
---|
| 1989 | + /* We will disable all channels that do not match our |
---|
| 1990 | + * received regulatory rule unless the hint is coming |
---|
| 1991 | + * from a Country IE and the Country IE had no information |
---|
| 1992 | + * about a band. The IEEE 802.11 spec allows for an AP |
---|
| 1993 | + * to send only a subset of the regulatory rules allowed, |
---|
| 1994 | + * so an AP in the US that only supports 2.4 GHz may only send |
---|
| 1995 | + * a country IE with information for the 2.4 GHz band |
---|
| 1996 | + * while 5 GHz is still supported. |
---|
| 1997 | + */ |
---|
| 1998 | + if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE && |
---|
| 1999 | + PTR_ERR(rrule) == -ERANGE) |
---|
| 2000 | + return; |
---|
| 2001 | + |
---|
| 2002 | + if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER && |
---|
| 2003 | + request_wiphy && request_wiphy == wiphy && |
---|
| 2004 | + request_wiphy->regulatory_flags & REGULATORY_STRICT_REG) { |
---|
| 2005 | + pr_debug("Disabling freq %d.%03d MHz for good\n", |
---|
| 2006 | + chan->center_freq, chan->freq_offset); |
---|
| 2007 | + chan->orig_flags |= IEEE80211_CHAN_DISABLED; |
---|
| 2008 | + chan->flags = chan->orig_flags; |
---|
| 2009 | + } else { |
---|
| 2010 | + pr_debug("Disabling freq %d.%03d MHz\n", |
---|
| 2011 | + chan->center_freq, chan->freq_offset); |
---|
| 2012 | + chan->flags |= IEEE80211_CHAN_DISABLED; |
---|
| 2013 | + } |
---|
| 2014 | + return; |
---|
| 2015 | + } |
---|
| 2016 | + |
---|
| 2017 | + handle_channel_single_rule(wiphy, initiator, chan, flags, lr, |
---|
| 2018 | + request_wiphy, rrule); |
---|
1794 | 2019 | } |
---|
1795 | 2020 | |
---|
1796 | 2021 | static void handle_band(struct wiphy *wiphy, |
---|
.. | .. |
---|
1927 | 2152 | sband = wiphy->bands[reg_beacon->chan.band]; |
---|
1928 | 2153 | chan = &sband->channels[chan_idx]; |
---|
1929 | 2154 | |
---|
1930 | | - if (likely(chan->center_freq != reg_beacon->chan.center_freq)) |
---|
| 2155 | + if (likely(!ieee80211_channel_equal(chan, ®_beacon->chan))) |
---|
1931 | 2156 | return; |
---|
1932 | 2157 | |
---|
1933 | 2158 | if (chan->beacon_found) |
---|
.. | .. |
---|
2260 | 2485 | u32 bw_flags = 0; |
---|
2261 | 2486 | const struct ieee80211_reg_rule *reg_rule = NULL; |
---|
2262 | 2487 | const struct ieee80211_power_rule *power_rule = NULL; |
---|
2263 | | - u32 bw; |
---|
| 2488 | + u32 bw, center_freq_khz; |
---|
2264 | 2489 | |
---|
| 2490 | + center_freq_khz = ieee80211_channel_to_khz(chan); |
---|
2265 | 2491 | for (bw = MHZ_TO_KHZ(20); bw >= min_bw; bw = bw / 2) { |
---|
2266 | | - reg_rule = freq_reg_info_regd(MHZ_TO_KHZ(chan->center_freq), |
---|
2267 | | - regd, bw); |
---|
| 2492 | + reg_rule = freq_reg_info_regd(center_freq_khz, regd, bw); |
---|
2268 | 2493 | if (!IS_ERR(reg_rule)) |
---|
2269 | 2494 | break; |
---|
2270 | 2495 | } |
---|
2271 | 2496 | |
---|
2272 | 2497 | if (IS_ERR_OR_NULL(reg_rule)) { |
---|
2273 | | - pr_debug("Disabling freq %d MHz as custom regd has no rule that fits it\n", |
---|
2274 | | - chan->center_freq); |
---|
| 2498 | + pr_debug("Disabling freq %d.%03d MHz as custom regd has no rule that fits it\n", |
---|
| 2499 | + chan->center_freq, chan->freq_offset); |
---|
2275 | 2500 | if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) { |
---|
2276 | 2501 | chan->flags |= IEEE80211_CHAN_DISABLED; |
---|
2277 | 2502 | } else { |
---|
.. | .. |
---|
2374 | 2599 | |
---|
2375 | 2600 | /** |
---|
2376 | 2601 | * reg_process_hint_core - process core regulatory requests |
---|
2377 | | - * @pending_request: a pending core regulatory request |
---|
| 2602 | + * @core_request: a pending core regulatory request |
---|
2378 | 2603 | * |
---|
2379 | 2604 | * The wireless subsystem can use this function to process |
---|
2380 | 2605 | * a regulatory request issued by the regulatory core. |
---|
.. | .. |
---|
2483 | 2708 | |
---|
2484 | 2709 | /** |
---|
2485 | 2710 | * reg_process_hint_driver - process driver regulatory requests |
---|
| 2711 | + * @wiphy: the wireless device for the regulatory request |
---|
2486 | 2712 | * @driver_request: a pending driver regulatory request |
---|
2487 | 2713 | * |
---|
2488 | 2714 | * The wireless subsystem can use this function to process |
---|
.. | .. |
---|
2583 | 2809 | |
---|
2584 | 2810 | /** |
---|
2585 | 2811 | * reg_process_hint_country_ie - process regulatory requests from country IEs |
---|
| 2812 | + * @wiphy: the wireless device for the regulatory request |
---|
2586 | 2813 | * @country_ie_request: a regulatory request from a country IE |
---|
2587 | 2814 | * |
---|
2588 | 2815 | * The wireless subsystem can use this function to process |
---|
.. | .. |
---|
2770 | 2997 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { |
---|
2771 | 2998 | wiphy = &rdev->wiphy; |
---|
2772 | 2999 | if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED && |
---|
2773 | | - request->initiator == NL80211_REGDOM_SET_BY_USER && |
---|
2774 | | - request->user_reg_hint_type == |
---|
2775 | | - NL80211_USER_REG_HINT_CELL_BASE) |
---|
| 3000 | + request->initiator == NL80211_REGDOM_SET_BY_USER) |
---|
2776 | 3001 | reg_call_notifier(wiphy, request); |
---|
2777 | 3002 | } |
---|
2778 | 3003 | } |
---|
.. | .. |
---|
3160 | 3385 | * - send a user regulatory hint if applicable |
---|
3161 | 3386 | * |
---|
3162 | 3387 | * Device drivers that send a regulatory hint for a specific country |
---|
3163 | | - * keep their own regulatory domain on wiphy->regd so that does does |
---|
| 3388 | + * keep their own regulatory domain on wiphy->regd so that does |
---|
3164 | 3389 | * not need to be remembered. |
---|
3165 | 3390 | */ |
---|
3166 | | -static void restore_regulatory_settings(bool reset_user) |
---|
| 3391 | +static void restore_regulatory_settings(bool reset_user, bool cached) |
---|
3167 | 3392 | { |
---|
3168 | 3393 | char alpha2[2]; |
---|
3169 | 3394 | char world_alpha2[2]; |
---|
.. | .. |
---|
3222 | 3447 | restore_custom_reg_settings(&rdev->wiphy); |
---|
3223 | 3448 | } |
---|
3224 | 3449 | |
---|
3225 | | - regulatory_hint_core(world_alpha2); |
---|
| 3450 | + if (cached && (!is_an_alpha2(alpha2) || |
---|
| 3451 | + !IS_ERR_OR_NULL(cfg80211_user_regdom))) { |
---|
| 3452 | + reset_regdomains(false, cfg80211_world_regdom); |
---|
| 3453 | + update_all_wiphy_regulatory(NL80211_REGDOM_SET_BY_CORE); |
---|
| 3454 | + print_regdomain(get_cfg80211_regdom()); |
---|
| 3455 | + nl80211_send_reg_change_event(&core_request_world); |
---|
| 3456 | + reg_set_request_processed(); |
---|
3226 | 3457 | |
---|
3227 | | - /* |
---|
3228 | | - * This restores the ieee80211_regdom module parameter |
---|
3229 | | - * preference or the last user requested regulatory |
---|
3230 | | - * settings, user regulatory settings takes precedence. |
---|
3231 | | - */ |
---|
3232 | | - if (is_an_alpha2(alpha2)) |
---|
3233 | | - regulatory_hint_user(alpha2, NL80211_USER_REG_HINT_USER); |
---|
| 3458 | + if (is_an_alpha2(alpha2) && |
---|
| 3459 | + !regulatory_hint_user(alpha2, NL80211_USER_REG_HINT_USER)) { |
---|
| 3460 | + struct regulatory_request *ureq; |
---|
| 3461 | + |
---|
| 3462 | + spin_lock(®_requests_lock); |
---|
| 3463 | + ureq = list_last_entry(®_requests_list, |
---|
| 3464 | + struct regulatory_request, |
---|
| 3465 | + list); |
---|
| 3466 | + list_del(&ureq->list); |
---|
| 3467 | + spin_unlock(®_requests_lock); |
---|
| 3468 | + |
---|
| 3469 | + notify_self_managed_wiphys(ureq); |
---|
| 3470 | + reg_update_last_request(ureq); |
---|
| 3471 | + set_regdom(reg_copy_regd(cfg80211_user_regdom), |
---|
| 3472 | + REGD_SOURCE_CACHED); |
---|
| 3473 | + } |
---|
| 3474 | + } else { |
---|
| 3475 | + regulatory_hint_core(world_alpha2); |
---|
| 3476 | + |
---|
| 3477 | + /* |
---|
| 3478 | + * This restores the ieee80211_regdom module parameter |
---|
| 3479 | + * preference or the last user requested regulatory |
---|
| 3480 | + * settings, user regulatory settings takes precedence. |
---|
| 3481 | + */ |
---|
| 3482 | + if (is_an_alpha2(alpha2)) |
---|
| 3483 | + regulatory_hint_user(alpha2, NL80211_USER_REG_HINT_USER); |
---|
| 3484 | + } |
---|
3234 | 3485 | |
---|
3235 | 3486 | spin_lock(®_requests_lock); |
---|
3236 | 3487 | list_splice_tail_init(&tmp_reg_req_list, ®_requests_list); |
---|
.. | .. |
---|
3290 | 3541 | } |
---|
3291 | 3542 | |
---|
3292 | 3543 | pr_debug("All devices are disconnected, going to restore regulatory settings\n"); |
---|
3293 | | - restore_regulatory_settings(false); |
---|
| 3544 | + restore_regulatory_settings(false, true); |
---|
3294 | 3545 | } |
---|
3295 | 3546 | |
---|
3296 | | -static bool freq_is_chan_12_13_14(u16 freq) |
---|
| 3547 | +static bool freq_is_chan_12_13_14(u32 freq) |
---|
3297 | 3548 | { |
---|
3298 | 3549 | if (freq == ieee80211_channel_to_frequency(12, NL80211_BAND_2GHZ) || |
---|
3299 | 3550 | freq == ieee80211_channel_to_frequency(13, NL80211_BAND_2GHZ) || |
---|
.. | .. |
---|
3307 | 3558 | struct reg_beacon *pending_beacon; |
---|
3308 | 3559 | |
---|
3309 | 3560 | list_for_each_entry(pending_beacon, ®_pending_beacons, list) |
---|
3310 | | - if (beacon_chan->center_freq == |
---|
3311 | | - pending_beacon->chan.center_freq) |
---|
| 3561 | + if (ieee80211_channel_equal(beacon_chan, |
---|
| 3562 | + &pending_beacon->chan)) |
---|
3312 | 3563 | return true; |
---|
3313 | 3564 | return false; |
---|
3314 | 3565 | } |
---|
.. | .. |
---|
3337 | 3588 | if (!reg_beacon) |
---|
3338 | 3589 | return -ENOMEM; |
---|
3339 | 3590 | |
---|
3340 | | - pr_debug("Found new beacon on frequency: %d MHz (Ch %d) on %s\n", |
---|
3341 | | - beacon_chan->center_freq, |
---|
3342 | | - ieee80211_frequency_to_channel(beacon_chan->center_freq), |
---|
| 3591 | + pr_debug("Found new beacon on frequency: %d.%03d MHz (Ch %d) on %s\n", |
---|
| 3592 | + beacon_chan->center_freq, beacon_chan->freq_offset, |
---|
| 3593 | + ieee80211_freq_khz_to_channel( |
---|
| 3594 | + ieee80211_channel_to_khz(beacon_chan)), |
---|
3343 | 3595 | wiphy_name(wiphy)); |
---|
3344 | 3596 | |
---|
3345 | 3597 | memcpy(®_beacon->chan, beacon_chan, |
---|
.. | .. |
---|
3607 | 3859 | bool user_reset = false; |
---|
3608 | 3860 | int r; |
---|
3609 | 3861 | |
---|
| 3862 | + if (IS_ERR_OR_NULL(rd)) |
---|
| 3863 | + return -ENODATA; |
---|
| 3864 | + |
---|
3610 | 3865 | if (!reg_is_valid_request(rd->alpha2)) { |
---|
3611 | 3866 | kfree(rd); |
---|
3612 | 3867 | return -EINVAL; |
---|
.. | .. |
---|
3623 | 3878 | r = reg_set_rd_core(rd); |
---|
3624 | 3879 | break; |
---|
3625 | 3880 | case NL80211_REGDOM_SET_BY_USER: |
---|
| 3881 | + cfg80211_save_user_regdom(rd); |
---|
3626 | 3882 | r = reg_set_rd_user(rd, lr); |
---|
3627 | 3883 | user_reset = true; |
---|
3628 | 3884 | break; |
---|
.. | .. |
---|
3645 | 3901 | break; |
---|
3646 | 3902 | default: |
---|
3647 | 3903 | /* Back to world regulatory in case of errors */ |
---|
3648 | | - restore_regulatory_settings(user_reset); |
---|
| 3904 | + restore_regulatory_settings(user_reset, false); |
---|
3649 | 3905 | } |
---|
3650 | 3906 | |
---|
3651 | 3907 | kfree(rd); |
---|
.. | .. |
---|
3744 | 4000 | /* |
---|
3745 | 4001 | * The last request may have been received before this |
---|
3746 | 4002 | * registration call. Call the driver notifier if |
---|
3747 | | - * initiator is USER and user type is CELL_BASE. |
---|
| 4003 | + * initiator is USER. |
---|
3748 | 4004 | */ |
---|
3749 | | - if (lr->initiator == NL80211_REGDOM_SET_BY_USER && |
---|
3750 | | - lr->user_reg_hint_type == NL80211_USER_REG_HINT_CELL_BASE) |
---|
| 4005 | + if (lr->initiator == NL80211_REGDOM_SET_BY_USER) |
---|
3751 | 4006 | reg_call_notifier(wiphy, lr); |
---|
3752 | 4007 | } |
---|
3753 | 4008 | |
---|
.. | .. |
---|
3756 | 4011 | |
---|
3757 | 4012 | wiphy_update_regulatory(wiphy, lr->initiator); |
---|
3758 | 4013 | wiphy_all_share_dfs_chan_state(wiphy); |
---|
| 4014 | + reg_process_self_managed_hints(); |
---|
3759 | 4015 | } |
---|
3760 | 4016 | |
---|
3761 | 4017 | void wiphy_regulatory_deregister(struct wiphy *wiphy) |
---|
.. | .. |
---|
3782 | 4038 | } |
---|
3783 | 4039 | |
---|
3784 | 4040 | /* |
---|
3785 | | - * See http://www.fcc.gov/document/5-ghz-unlicensed-spectrum-unii, for |
---|
3786 | | - * UNII band definitions |
---|
| 4041 | + * See FCC notices for UNII band definitions |
---|
| 4042 | + * 5GHz: https://www.fcc.gov/document/5-ghz-unlicensed-spectrum-unii |
---|
| 4043 | + * 6GHz: https://www.fcc.gov/document/fcc-proposes-more-spectrum-unlicensed-use-0 |
---|
3787 | 4044 | */ |
---|
3788 | 4045 | int cfg80211_get_unii(int freq) |
---|
3789 | 4046 | { |
---|
.. | .. |
---|
3806 | 4063 | /* UNII-3 */ |
---|
3807 | 4064 | if (freq > 5725 && freq <= 5825) |
---|
3808 | 4065 | return 4; |
---|
| 4066 | + |
---|
| 4067 | + /* UNII-5 */ |
---|
| 4068 | + if (freq > 5925 && freq <= 6425) |
---|
| 4069 | + return 5; |
---|
| 4070 | + |
---|
| 4071 | + /* UNII-6 */ |
---|
| 4072 | + if (freq > 6425 && freq <= 6525) |
---|
| 4073 | + return 6; |
---|
| 4074 | + |
---|
| 4075 | + /* UNII-7 */ |
---|
| 4076 | + if (freq > 6525 && freq <= 6875) |
---|
| 4077 | + return 7; |
---|
| 4078 | + |
---|
| 4079 | + /* UNII-8 */ |
---|
| 4080 | + if (freq > 6875 && freq <= 7125) |
---|
| 4081 | + return 8; |
---|
3809 | 4082 | |
---|
3810 | 4083 | return -EINVAL; |
---|
3811 | 4084 | } |
---|
.. | .. |
---|
3842 | 4115 | |
---|
3843 | 4116 | return pre_cac_allowed; |
---|
3844 | 4117 | } |
---|
| 4118 | +EXPORT_SYMBOL(regulatory_pre_cac_allowed); |
---|
3845 | 4119 | |
---|
3846 | 4120 | static void cfg80211_check_and_end_cac(struct cfg80211_registered_device *rdev) |
---|
3847 | 4121 | { |
---|
.. | .. |
---|
3911 | 4185 | return -EINVAL; |
---|
3912 | 4186 | |
---|
3913 | 4187 | err = load_builtin_regdb_keys(); |
---|
3914 | | - if (err) |
---|
| 4188 | + if (err) { |
---|
| 4189 | + platform_device_unregister(reg_pdev); |
---|
3915 | 4190 | return err; |
---|
| 4191 | + } |
---|
3916 | 4192 | |
---|
3917 | 4193 | /* We always try to get an update for the static regdomain */ |
---|
3918 | 4194 | err = regulatory_hint_core(cfg80211_world_regdom->alpha2); |
---|
.. | .. |
---|
4002 | 4278 | |
---|
4003 | 4279 | if (!IS_ERR_OR_NULL(regdb)) |
---|
4004 | 4280 | kfree(regdb); |
---|
| 4281 | + if (!IS_ERR_OR_NULL(cfg80211_user_regdom)) |
---|
| 4282 | + kfree(cfg80211_user_regdom); |
---|
4005 | 4283 | |
---|
4006 | 4284 | free_regdb_keyring(); |
---|
4007 | 4285 | } |
---|