#define pr_fmt(fmt) …
#include <linux/kernel.h>
#include <linux/export.h>
#include <linux/slab.h>
#include <linux/list.h>
#include <linux/ctype.h>
#include <linux/nl80211.h>
#include <linux/platform_device.h>
#include <linux/verification.h>
#include <linux/moduleparam.h>
#include <linux/firmware.h>
#include <linux/units.h>
#include <net/cfg80211.h>
#include "core.h"
#include "reg.h"
#include "rdev-ops.h"
#include "nl80211.h"
#define REG_ENFORCE_GRACE_MS …
enum reg_request_treatment { … };
static struct regulatory_request core_request_world = …;
static struct regulatory_request __rcu *last_request = …;
static struct platform_device *reg_pdev;
const struct ieee80211_regdomain __rcu *cfg80211_regdomain;
static int reg_num_devs_support_basehint;
static bool reg_is_indoor;
static DEFINE_SPINLOCK(reg_indoor_lock);
static u32 reg_is_indoor_portid;
static void restore_regulatory_settings(bool reset_user, bool cached);
static void print_regdomain(const struct ieee80211_regdomain *rd);
static void reg_process_hint(struct regulatory_request *reg_request);
static const struct ieee80211_regdomain *get_cfg80211_regdom(void)
{ … }
const struct ieee80211_regdomain *get_wiphy_regdom(struct wiphy *wiphy)
{ … }
EXPORT_SYMBOL(…);
static const char *reg_dfs_region_str(enum nl80211_dfs_regions dfs_region)
{ … }
enum nl80211_dfs_regions reg_get_dfs_region(struct wiphy *wiphy)
{ … }
static void rcu_free_regdom(const struct ieee80211_regdomain *r)
{ … }
static struct regulatory_request *get_last_request(void)
{ … }
static LIST_HEAD(reg_requests_list);
static DEFINE_SPINLOCK(reg_requests_lock);
static LIST_HEAD(reg_pending_beacons);
static DEFINE_SPINLOCK(reg_pending_beacons_lock);
static LIST_HEAD(reg_beacon_list);
struct reg_beacon { … };
static void reg_check_chans_work(struct work_struct *work);
static DECLARE_DELAYED_WORK(reg_check_chans, reg_check_chans_work);
static void reg_todo(struct work_struct *work);
static DECLARE_WORK(reg_work, reg_todo);
static const struct ieee80211_regdomain world_regdom = …;
static const struct ieee80211_regdomain *cfg80211_world_regdom = …;
static char *ieee80211_regdom = …;
static char user_alpha2[2];
static const struct ieee80211_regdomain *cfg80211_user_regdom;
module_param(ieee80211_regdom, charp, 0444);
MODULE_PARM_DESC(…) …;
static void reg_free_request(struct regulatory_request *request)
{ … }
static void reg_free_last_request(void)
{ … }
static void reg_update_last_request(struct regulatory_request *request)
{ … }
static void reset_regdomains(bool full_reset,
const struct ieee80211_regdomain *new_regdom)
{ … }
static void update_world_regdomain(const struct ieee80211_regdomain *rd)
{ … }
bool is_world_regdom(const char *alpha2)
{ … }
static bool is_alpha2_set(const char *alpha2)
{ … }
static bool is_unknown_alpha2(const char *alpha2)
{ … }
static bool is_intersected_alpha2(const char *alpha2)
{ … }
static bool is_an_alpha2(const char *alpha2)
{ … }
static bool alpha2_equal(const char *alpha2_x, const char *alpha2_y)
{ … }
static bool regdom_changes(const char *alpha2)
{ … }
static bool is_user_regdom_saved(void)
{ … }
static const struct ieee80211_regdomain *
reg_copy_regd(const struct ieee80211_regdomain *src_regd)
{ … }
static void cfg80211_save_user_regdom(const struct ieee80211_regdomain *rd)
{ … }
struct reg_regdb_apply_request { … };
static LIST_HEAD(reg_regdb_apply_list);
static DEFINE_MUTEX(reg_regdb_apply_mutex);
static void reg_regdb_apply(struct work_struct *work)
{ … }
static DECLARE_WORK(reg_regdb_work, reg_regdb_apply);
static int reg_schedule_apply(const struct ieee80211_regdomain *regdom)
{ … }
#ifdef CONFIG_CFG80211_CRDA_SUPPORT
#define REG_MAX_CRDA_TIMEOUTS …
static u32 reg_crda_timeouts;
static void crda_timeout_work(struct work_struct *work);
static DECLARE_DELAYED_WORK(crda_timeout, crda_timeout_work);
static void crda_timeout_work(struct work_struct *work)
{ … }
static void cancel_crda_timeout(void)
{ … }
static void cancel_crda_timeout_sync(void)
{ … }
static void reset_crda_timeouts(void)
{ … }
static int call_crda(const char *alpha2)
{ … }
#else
static inline void cancel_crda_timeout(void) {}
static inline void cancel_crda_timeout_sync(void) {}
static inline void reset_crda_timeouts(void) {}
static inline int call_crda(const char *alpha2)
{
return -ENODATA;
}
#endif
static const struct fwdb_header *regdb;
struct fwdb_country { … } __packed __aligned(…);
struct fwdb_collection { … } __packed __aligned(…);
enum fwdb_flags { … };
struct fwdb_wmm_ac { … } __packed;
struct fwdb_wmm_rule { … } __packed;
struct fwdb_rule { … } __packed __aligned(…);
#define FWDB_MAGIC …
#define FWDB_VERSION …
struct fwdb_header { … } __packed __aligned(…);
static int ecw2cw(int ecw)
{ … }
static bool valid_wmm(struct fwdb_wmm_rule *rule)
{ … }
static bool valid_rule(const u8 *data, unsigned int size, u16 rule_ptr)
{ … }
static bool valid_country(const u8 *data, unsigned int size,
const struct fwdb_country *country)
{ … }
#ifdef CONFIG_CFG80211_REQUIRE_SIGNED_REGDB
#include <keys/asymmetric-type.h>
static struct key *builtin_regdb_keys;
static int __init load_builtin_regdb_keys(void)
{ … }
MODULE_FIRMWARE(…) …;
static bool regdb_has_valid_signature(const u8 *data, unsigned int size)
{ … }
static void free_regdb_keyring(void)
{ … }
#else
static int load_builtin_regdb_keys(void)
{
return 0;
}
static bool regdb_has_valid_signature(const u8 *data, unsigned int size)
{
return true;
}
static void free_regdb_keyring(void)
{
}
#endif
static bool valid_regdb(const u8 *data, unsigned int size)
{ … }
static void set_wmm_rule(const struct fwdb_header *db,
const struct fwdb_country *country,
const struct fwdb_rule *rule,
struct ieee80211_reg_rule *rrule)
{ … }
static int __regdb_query_wmm(const struct fwdb_header *db,
const struct fwdb_country *country, int freq,
struct ieee80211_reg_rule *rrule)
{ … }
int reg_query_regdb_wmm(char *alpha2, int freq, struct ieee80211_reg_rule *rule)
{ … }
EXPORT_SYMBOL(…);
static int regdb_query_country(const struct fwdb_header *db,
const struct fwdb_country *country)
{ … }
static int query_regdb(const char *alpha2)
{ … }
static void regdb_fw_cb(const struct firmware *fw, void *context)
{ … }
MODULE_FIRMWARE(…) …;
static int query_regdb_file(const char *alpha2)
{ … }
int reg_reload_regdb(void)
{ … }
static bool reg_query_database(struct regulatory_request *request)
{ … }
bool reg_is_valid_request(const char *alpha2)
{ … }
static const struct ieee80211_regdomain *reg_get_regdomain(struct wiphy *wiphy)
{ … }
static unsigned int
reg_get_max_bandwidth_from_range(const struct ieee80211_regdomain *rd,
const struct ieee80211_reg_rule *rule)
{ … }
unsigned int reg_get_max_bandwidth(const struct ieee80211_regdomain *rd,
const struct ieee80211_reg_rule *rule)
{ … }
static bool is_valid_reg_rule(const struct ieee80211_reg_rule *rule)
{ … }
static bool is_valid_rd(const struct ieee80211_regdomain *rd)
{ … }
static bool freq_in_rule_band(const struct ieee80211_freq_range *freq_range,
u32 freq_khz)
{ … }
static enum nl80211_dfs_regions
reg_intersect_dfs_region(const enum nl80211_dfs_regions dfs_region1,
const enum nl80211_dfs_regions dfs_region2)
{ … }
static void reg_wmm_rules_intersect(const struct ieee80211_wmm_ac *wmm_ac1,
const struct ieee80211_wmm_ac *wmm_ac2,
struct ieee80211_wmm_ac *intersect)
{ … }
static int reg_rules_intersect(const struct ieee80211_regdomain *rd1,
const struct ieee80211_regdomain *rd2,
const struct ieee80211_reg_rule *rule1,
const struct ieee80211_reg_rule *rule2,
struct ieee80211_reg_rule *intersected_rule)
{ … }
static bool rule_contains(struct ieee80211_reg_rule *r1,
struct ieee80211_reg_rule *r2)
{ … }
static void add_rule(struct ieee80211_reg_rule *rule,
struct ieee80211_reg_rule *reg_rules, u32 *n_rules)
{ … }
static struct ieee80211_regdomain *
regdom_intersect(const struct ieee80211_regdomain *rd1,
const struct ieee80211_regdomain *rd2)
{ … }
static u32 map_regdom_flags(u32 rd_flags)
{ … }
static const struct ieee80211_reg_rule *
freq_reg_info_regd(u32 center_freq,
const struct ieee80211_regdomain *regd, u32 bw)
{ … }
static const struct ieee80211_reg_rule *
__freq_reg_info(struct wiphy *wiphy, u32 center_freq, u32 min_bw)
{ … }
const struct ieee80211_reg_rule *freq_reg_info(struct wiphy *wiphy,
u32 center_freq)
{ … }
EXPORT_SYMBOL(…);
const char *reg_initiator_name(enum nl80211_reg_initiator initiator)
{ … }
EXPORT_SYMBOL(…);
static uint32_t reg_rule_to_chan_bw_flags(const struct ieee80211_regdomain *regd,
const struct ieee80211_reg_rule *reg_rule,
const struct ieee80211_channel *chan)
{ … }
static void handle_channel_single_rule(struct wiphy *wiphy,
enum nl80211_reg_initiator initiator,
struct ieee80211_channel *chan,
u32 flags,
struct regulatory_request *lr,
struct wiphy *request_wiphy,
const struct ieee80211_reg_rule *reg_rule)
{ … }
static void handle_channel_adjacent_rules(struct wiphy *wiphy,
enum nl80211_reg_initiator initiator,
struct ieee80211_channel *chan,
u32 flags,
struct regulatory_request *lr,
struct wiphy *request_wiphy,
const struct ieee80211_reg_rule *rrule1,
const struct ieee80211_reg_rule *rrule2,
struct ieee80211_freq_range *comb_range)
{ … }
static void handle_channel(struct wiphy *wiphy,
enum nl80211_reg_initiator initiator,
struct ieee80211_channel *chan)
{ … }
static void handle_band(struct wiphy *wiphy,
enum nl80211_reg_initiator initiator,
struct ieee80211_supported_band *sband)
{ … }
static bool reg_request_cell_base(struct regulatory_request *request)
{ … }
bool reg_last_request_cell_base(void)
{ … }
#ifdef CONFIG_CFG80211_REG_CELLULAR_HINTS
static enum reg_request_treatment
reg_ignore_cell_hint(struct regulatory_request *pending_request)
{ … }
static bool reg_dev_ignore_cell_hint(struct wiphy *wiphy)
{ … }
#else
static enum reg_request_treatment
reg_ignore_cell_hint(struct regulatory_request *pending_request)
{
return REG_REQ_IGNORE;
}
static bool reg_dev_ignore_cell_hint(struct wiphy *wiphy)
{
return true;
}
#endif
static bool wiphy_strict_alpha2_regd(struct wiphy *wiphy)
{ … }
static bool ignore_reg_update(struct wiphy *wiphy,
enum nl80211_reg_initiator initiator)
{ … }
static bool reg_is_world_roaming(struct wiphy *wiphy)
{ … }
static void reg_call_notifier(struct wiphy *wiphy,
struct regulatory_request *request)
{ … }
static void handle_reg_beacon(struct wiphy *wiphy, unsigned int chan_idx,
struct reg_beacon *reg_beacon)
{ … }
static void wiphy_update_new_beacon(struct wiphy *wiphy,
struct reg_beacon *reg_beacon)
{ … }
static void wiphy_update_beacon_reg(struct wiphy *wiphy)
{ … }
static void reg_process_beacons(struct wiphy *wiphy)
{ … }
static bool is_ht40_allowed(struct ieee80211_channel *chan)
{ … }
static void reg_process_ht_flags_channel(struct wiphy *wiphy,
struct ieee80211_channel *channel)
{ … }
static void reg_process_ht_flags_band(struct wiphy *wiphy,
struct ieee80211_supported_band *sband)
{ … }
static void reg_process_ht_flags(struct wiphy *wiphy)
{ … }
static bool reg_wdev_chan_valid(struct wiphy *wiphy, struct wireless_dev *wdev)
{ … }
static void reg_leave_invalid_chans(struct wiphy *wiphy)
{ … }
static void reg_check_chans_work(struct work_struct *work)
{ … }
void reg_check_channels(void)
{ … }
static void wiphy_update_regulatory(struct wiphy *wiphy,
enum nl80211_reg_initiator initiator)
{ … }
static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator)
{ … }
static void handle_channel_custom(struct wiphy *wiphy,
struct ieee80211_channel *chan,
const struct ieee80211_regdomain *regd,
u32 min_bw)
{ … }
static void handle_band_custom(struct wiphy *wiphy,
struct ieee80211_supported_band *sband,
const struct ieee80211_regdomain *regd)
{ … }
void wiphy_apply_custom_regulatory(struct wiphy *wiphy,
const struct ieee80211_regdomain *regd)
{ … }
EXPORT_SYMBOL(…);
static void reg_set_request_processed(void)
{ … }
static enum reg_request_treatment
reg_process_hint_core(struct regulatory_request *core_request)
{ … }
static enum reg_request_treatment
__reg_process_hint_user(struct regulatory_request *user_request)
{ … }
static enum reg_request_treatment
reg_process_hint_user(struct regulatory_request *user_request)
{ … }
static enum reg_request_treatment
__reg_process_hint_driver(struct regulatory_request *driver_request)
{ … }
static enum reg_request_treatment
reg_process_hint_driver(struct wiphy *wiphy,
struct regulatory_request *driver_request)
{ … }
static enum reg_request_treatment
__reg_process_hint_country_ie(struct wiphy *wiphy,
struct regulatory_request *country_ie_request)
{ … }
static enum reg_request_treatment
reg_process_hint_country_ie(struct wiphy *wiphy,
struct regulatory_request *country_ie_request)
{ … }
bool reg_dfs_domain_same(struct wiphy *wiphy1, struct wiphy *wiphy2)
{ … }
static void reg_copy_dfs_chan_state(struct ieee80211_channel *dst_chan,
struct ieee80211_channel *src_chan)
{ … }
static void wiphy_share_dfs_chan_state(struct wiphy *dst_wiphy,
struct wiphy *src_wiphy)
{ … }
static void wiphy_all_share_dfs_chan_state(struct wiphy *wiphy)
{ … }
static void reg_process_hint(struct regulatory_request *reg_request)
{ … }
static void notify_self_managed_wiphys(struct regulatory_request *request)
{ … }
static void reg_process_pending_hints(void)
{ … }
static void reg_process_pending_beacon_hints(void)
{ … }
static void reg_process_self_managed_hint(struct wiphy *wiphy)
{ … }
static void reg_process_self_managed_hints(void)
{ … }
static void reg_todo(struct work_struct *work)
{ … }
static void queue_regulatory_request(struct regulatory_request *request)
{ … }
static int regulatory_hint_core(const char *alpha2)
{ … }
int regulatory_hint_user(const char *alpha2,
enum nl80211_user_reg_hint_type user_reg_hint_type)
{ … }
void regulatory_hint_indoor(bool is_indoor, u32 portid)
{ … }
void regulatory_netlink_notify(u32 portid)
{ … }
int regulatory_hint(struct wiphy *wiphy, const char *alpha2)
{ … }
EXPORT_SYMBOL(…);
void regulatory_hint_country_ie(struct wiphy *wiphy, enum nl80211_band band,
const u8 *country_ie, u8 country_ie_len)
{ … }
static void restore_alpha2(char *alpha2, bool reset_user)
{ … }
static void restore_custom_reg_settings(struct wiphy *wiphy)
{ … }
static void restore_regulatory_settings(bool reset_user, bool cached)
{ … }
static bool is_wiphy_all_set_reg_flag(enum ieee80211_regulatory_flags flag)
{ … }
void regulatory_hint_disconnect(void)
{ … }
static bool freq_is_chan_12_13_14(u32 freq)
{ … }
static bool pending_reg_beacon(struct ieee80211_channel *beacon_chan)
{ … }
void regulatory_hint_found_beacon(struct wiphy *wiphy,
struct ieee80211_channel *beacon_chan,
gfp_t gfp)
{ … }
static void print_rd_rules(const struct ieee80211_regdomain *rd)
{ … }
bool reg_supported_dfs_region(enum nl80211_dfs_regions dfs_region)
{ … }
static void print_regdomain(const struct ieee80211_regdomain *rd)
{ … }
static void print_regdomain_info(const struct ieee80211_regdomain *rd)
{ … }
static int reg_set_rd_core(const struct ieee80211_regdomain *rd)
{ … }
static int reg_set_rd_user(const struct ieee80211_regdomain *rd,
struct regulatory_request *user_request)
{ … }
static int reg_set_rd_driver(const struct ieee80211_regdomain *rd,
struct regulatory_request *driver_request)
{ … }
static int reg_set_rd_country_ie(const struct ieee80211_regdomain *rd,
struct regulatory_request *country_ie_request)
{ … }
int set_regdom(const struct ieee80211_regdomain *rd,
enum ieee80211_regd_source regd_src)
{ … }
static int __regulatory_set_wiphy_regd(struct wiphy *wiphy,
struct ieee80211_regdomain *rd)
{ … }
int regulatory_set_wiphy_regd(struct wiphy *wiphy,
struct ieee80211_regdomain *rd)
{ … }
EXPORT_SYMBOL(…);
int regulatory_set_wiphy_regd_sync(struct wiphy *wiphy,
struct ieee80211_regdomain *rd)
{ … }
EXPORT_SYMBOL(…);
void wiphy_regulatory_register(struct wiphy *wiphy)
{ … }
void wiphy_regulatory_deregister(struct wiphy *wiphy)
{ … }
int cfg80211_get_unii(int freq)
{ … }
bool regulatory_indoor_allowed(void)
{ … }
bool regulatory_pre_cac_allowed(struct wiphy *wiphy)
{ … }
EXPORT_SYMBOL(…);
static void cfg80211_check_and_end_cac(struct cfg80211_registered_device *rdev)
{ … }
void regulatory_propagate_dfs_state(struct wiphy *wiphy,
struct cfg80211_chan_def *chandef,
enum nl80211_dfs_state dfs_state,
enum nl80211_radar_event event)
{ … }
static int __init regulatory_init_db(void)
{ … }
#ifndef MODULE
late_initcall(regulatory_init_db);
#endif
int __init regulatory_init(void)
{ … }
void regulatory_exit(void)
{ … }