mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-15 16:24:13 +08:00
Merge branch 'for-john' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next
This commit is contained in:
commit
707be0ae13
@ -1540,11 +1540,6 @@ static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2,
|
||||
/* now send back TX status */
|
||||
txi = IEEE80211_SKB_CB(skb);
|
||||
|
||||
if (txi->control.vif)
|
||||
hwsim_check_magic(txi->control.vif);
|
||||
if (txi->control.sta)
|
||||
hwsim_check_sta_magic(txi->control.sta);
|
||||
|
||||
ieee80211_tx_info_clear_status(txi);
|
||||
|
||||
for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
|
||||
|
@ -1245,6 +1245,12 @@ enum nl80211_commands {
|
||||
* @NL80211_ATTR_BG_SCAN_PERIOD: Background scan period in seconds
|
||||
* or 0 to disable background scan.
|
||||
*
|
||||
* @NL80211_ATTR_USER_REG_HINT_TYPE: type of regulatory hint passed from
|
||||
* userspace. If unset it is assumed the hint comes directly from
|
||||
* a user. If set code could specify exactly what type of source
|
||||
* was used to provide the hint. For the different types of
|
||||
* allowed user regulatory hints see nl80211_user_reg_hint_type.
|
||||
*
|
||||
* @NL80211_ATTR_MAX: highest attribute number currently defined
|
||||
* @__NL80211_ATTR_AFTER_LAST: internal use
|
||||
*/
|
||||
@ -1498,6 +1504,8 @@ enum nl80211_attrs {
|
||||
|
||||
NL80211_ATTR_WDEV,
|
||||
|
||||
NL80211_ATTR_USER_REG_HINT_TYPE,
|
||||
|
||||
/* add attributes here, update the policy in nl80211.c */
|
||||
|
||||
__NL80211_ATTR_AFTER_LAST,
|
||||
@ -1550,6 +1558,8 @@ enum nl80211_attrs {
|
||||
/* default RSSI threshold for scan results if none specified. */
|
||||
#define NL80211_SCAN_RSSI_THOLD_OFF -300
|
||||
|
||||
#define NL80211_CQM_TXE_MAX_INTVL 1800
|
||||
|
||||
/**
|
||||
* enum nl80211_iftype - (virtual) interface types
|
||||
*
|
||||
@ -2058,6 +2068,26 @@ enum nl80211_dfs_regions {
|
||||
NL80211_DFS_JP = 3,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum nl80211_user_reg_hint_type - type of user regulatory hint
|
||||
*
|
||||
* @NL80211_USER_REG_HINT_USER: a user sent the hint. This is always
|
||||
* assumed if the attribute is not set.
|
||||
* @NL80211_USER_REG_HINT_CELL_BASE: the hint comes from a cellular
|
||||
* base station. Device drivers that have been tested to work
|
||||
* properly to support this type of hint can enable these hints
|
||||
* by setting the NL80211_FEATURE_CELL_BASE_REG_HINTS feature
|
||||
* capability on the struct wiphy. The wireless core will
|
||||
* ignore all cell base station hints until at least one device
|
||||
* present has been registered with the wireless core that
|
||||
* has listed NL80211_FEATURE_CELL_BASE_REG_HINTS as a
|
||||
* supported feature.
|
||||
*/
|
||||
enum nl80211_user_reg_hint_type {
|
||||
NL80211_USER_REG_HINT_USER = 0,
|
||||
NL80211_USER_REG_HINT_CELL_BASE = 1,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum nl80211_survey_info - survey information
|
||||
*
|
||||
@ -2589,6 +2619,17 @@ enum nl80211_ps_state {
|
||||
* @NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT: RSSI threshold event
|
||||
* @NL80211_ATTR_CQM_PKT_LOSS_EVENT: a u32 value indicating that this many
|
||||
* consecutive packets were not acknowledged by the peer
|
||||
* @NL80211_ATTR_CQM_TXE_RATE: TX error rate in %. Minimum % of TX failures
|
||||
* during the given %NL80211_ATTR_CQM_TXE_INTVL before an
|
||||
* %NL80211_CMD_NOTIFY_CQM with reported %NL80211_ATTR_CQM_TXE_RATE and
|
||||
* %NL80211_ATTR_CQM_TXE_PKTS is generated.
|
||||
* @NL80211_ATTR_CQM_TXE_PKTS: number of attempted packets in a given
|
||||
* %NL80211_ATTR_CQM_TXE_INTVL before %NL80211_ATTR_CQM_TXE_RATE is
|
||||
* checked.
|
||||
* @NL80211_ATTR_CQM_TXE_INTVL: interval in seconds. Specifies the periodic
|
||||
* interval in which %NL80211_ATTR_CQM_TXE_PKTS and
|
||||
* %NL80211_ATTR_CQM_TXE_RATE must be satisfied before generating an
|
||||
* %NL80211_CMD_NOTIFY_CQM. Set to 0 to turn off TX error reporting.
|
||||
* @__NL80211_ATTR_CQM_AFTER_LAST: internal
|
||||
* @NL80211_ATTR_CQM_MAX: highest key attribute
|
||||
*/
|
||||
@ -2598,6 +2639,9 @@ enum nl80211_attr_cqm {
|
||||
NL80211_ATTR_CQM_RSSI_HYST,
|
||||
NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT,
|
||||
NL80211_ATTR_CQM_PKT_LOSS_EVENT,
|
||||
NL80211_ATTR_CQM_TXE_RATE,
|
||||
NL80211_ATTR_CQM_TXE_PKTS,
|
||||
NL80211_ATTR_CQM_TXE_INTVL,
|
||||
|
||||
/* keep last */
|
||||
__NL80211_ATTR_CQM_AFTER_LAST,
|
||||
@ -2947,11 +2991,15 @@ enum nl80211_ap_sme_features {
|
||||
* @NL80211_FEATURE_HT_IBSS: This driver supports IBSS with HT datarates.
|
||||
* @NL80211_FEATURE_INACTIVITY_TIMER: This driver takes care of freeing up
|
||||
* the connected inactive stations in AP mode.
|
||||
* @NL80211_FEATURE_CELL_BASE_REG_HINTS: This driver has been tested
|
||||
* to work properly to suppport receiving regulatory hints from
|
||||
* cellular base stations.
|
||||
*/
|
||||
enum nl80211_feature_flags {
|
||||
NL80211_FEATURE_SK_TX_STATUS = 1 << 0,
|
||||
NL80211_FEATURE_HT_IBSS = 1 << 1,
|
||||
NL80211_FEATURE_INACTIVITY_TIMER = 1 << 2,
|
||||
NL80211_FEATURE_CELL_BASE_REG_HINTS = 1 << 3,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1504,8 +1504,6 @@ struct cfg80211_gtk_rekey_data {
|
||||
* interfaces are active this callback should reject the configuration.
|
||||
* If no interfaces are active or the device is down, the channel should
|
||||
* be stored for when a monitor interface becomes active.
|
||||
* @set_monitor_enabled: Notify driver that there are only monitor
|
||||
* interfaces running.
|
||||
*
|
||||
* @scan: Request to do a scan. If returning zero, the scan request is given
|
||||
* the driver, and will be valid until passed to cfg80211_scan_done().
|
||||
@ -1575,6 +1573,8 @@ struct cfg80211_gtk_rekey_data {
|
||||
* @set_power_mgmt: Configure WLAN power management. A timeout value of -1
|
||||
* allows the driver to adjust the dynamic ps timeout value.
|
||||
* @set_cqm_rssi_config: Configure connection quality monitor RSSI threshold.
|
||||
* @set_cqm_txe_config: Configure connection quality monitor TX error
|
||||
* thresholds.
|
||||
* @sched_scan_start: Tell the driver to start a scheduled scan.
|
||||
* @sched_scan_stop: Tell the driver to stop an ongoing scheduled
|
||||
* scan. The driver_initiated flag specifies whether the driver
|
||||
@ -1612,6 +1612,10 @@ struct cfg80211_gtk_rekey_data {
|
||||
* @get_et_strings: Ethtool API to get a set of strings to describe stats
|
||||
* and perhaps other supported types of ethtool data-sets.
|
||||
* See @ethtool_ops.get_strings
|
||||
*
|
||||
* @get_channel: Get the current operating channel for the virtual interface.
|
||||
* For monitor interfaces, it should return %NULL unless there's a single
|
||||
* current monitoring channel.
|
||||
*/
|
||||
struct cfg80211_ops {
|
||||
int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
|
||||
@ -1781,6 +1785,10 @@ struct cfg80211_ops {
|
||||
struct net_device *dev,
|
||||
s32 rssi_thold, u32 rssi_hyst);
|
||||
|
||||
int (*set_cqm_txe_config)(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
u32 rate, u32 pkts, u32 intvl);
|
||||
|
||||
void (*mgmt_frame_register)(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev,
|
||||
u16 frame_type, bool reg);
|
||||
@ -1820,7 +1828,10 @@ struct cfg80211_ops {
|
||||
void (*get_et_strings)(struct wiphy *wiphy, struct net_device *dev,
|
||||
u32 sset, u8 *data);
|
||||
|
||||
void (*set_monitor_enabled)(struct wiphy *wiphy, bool enabled);
|
||||
struct ieee80211_channel *
|
||||
(*get_channel)(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev,
|
||||
enum nl80211_channel_type *type);
|
||||
};
|
||||
|
||||
/*
|
||||
@ -3390,6 +3401,21 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev,
|
||||
void cfg80211_cqm_pktloss_notify(struct net_device *dev,
|
||||
const u8 *peer, u32 num_packets, gfp_t gfp);
|
||||
|
||||
/**
|
||||
* cfg80211_cqm_txe_notify - TX error rate event
|
||||
* @dev: network device
|
||||
* @peer: peer's MAC address
|
||||
* @num_packets: how many packets were lost
|
||||
* @rate: % of packets which failed transmission
|
||||
* @intvl: interval (in s) over which the TX failure threshold was breached.
|
||||
* @gfp: context flags
|
||||
*
|
||||
* Notify userspace when configured % TX failures over number of packets in a
|
||||
* given interval is exceeded.
|
||||
*/
|
||||
void cfg80211_cqm_txe_notify(struct net_device *dev, const u8 *peer,
|
||||
u32 num_packets, u32 rate, u32 intvl, gfp_t gfp);
|
||||
|
||||
/**
|
||||
* cfg80211_gtk_rekey_notify - notify userspace about driver rekeying
|
||||
* @dev: network device
|
||||
|
@ -52,6 +52,10 @@ enum environment_cap {
|
||||
* DFS master operation on a known DFS region (NL80211_DFS_*),
|
||||
* dfs_region represents that region. Drivers can use this and the
|
||||
* @alpha2 to adjust their device's DFS parameters as required.
|
||||
* @user_reg_hint_type: if the @initiator was of type
|
||||
* %NL80211_REGDOM_SET_BY_USER, this classifies the type
|
||||
* of hint passed. This could be any of the %NL80211_USER_REG_HINT_*
|
||||
* types.
|
||||
* @intersect: indicates whether the wireless core should intersect
|
||||
* the requested regulatory domain with the presently set regulatory
|
||||
* domain.
|
||||
@ -70,6 +74,7 @@ enum environment_cap {
|
||||
struct regulatory_request {
|
||||
int wiphy_idx;
|
||||
enum nl80211_reg_initiator initiator;
|
||||
enum nl80211_user_reg_hint_type user_reg_hint_type;
|
||||
char alpha2[2];
|
||||
u8 dfs_region;
|
||||
bool intersect;
|
||||
|
@ -2493,6 +2493,7 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
skb->dev = sdata->dev;
|
||||
|
||||
if (!need_offchan) {
|
||||
*cookie = (unsigned long) skb;
|
||||
ieee80211_tx_skb(sdata, skb);
|
||||
ret = 0;
|
||||
goto out_unlock;
|
||||
@ -2982,14 +2983,14 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ieee80211_set_monitor_enabled(struct wiphy *wiphy, bool enabled)
|
||||
static struct ieee80211_channel *
|
||||
ieee80211_cfg_get_channel(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
enum nl80211_channel_type *type)
|
||||
{
|
||||
struct ieee80211_local *local = wiphy_priv(wiphy);
|
||||
|
||||
if (enabled)
|
||||
WARN_ON(ieee80211_add_virtual_monitor(local));
|
||||
else
|
||||
ieee80211_del_virtual_monitor(local);
|
||||
*type = local->_oper_channel_type;
|
||||
return local->oper_channel;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
@ -3066,11 +3067,11 @@ struct cfg80211_ops mac80211_config_ops = {
|
||||
.tdls_mgmt = ieee80211_tdls_mgmt,
|
||||
.probe_client = ieee80211_probe_client,
|
||||
.set_noack_map = ieee80211_set_noack_map,
|
||||
.set_monitor_enabled = ieee80211_set_monitor_enabled,
|
||||
#ifdef CONFIG_PM
|
||||
.set_wakeup = ieee80211_set_wakeup,
|
||||
#endif
|
||||
.get_et_sset_count = ieee80211_get_et_sset_count,
|
||||
.get_et_stats = ieee80211_get_et_stats,
|
||||
.get_et_strings = ieee80211_get_et_strings,
|
||||
.get_channel = ieee80211_cfg_get_channel,
|
||||
};
|
||||
|
@ -1491,10 +1491,6 @@ int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata,
|
||||
int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb, bool need_basic);
|
||||
|
||||
/* virtual monitor */
|
||||
int ieee80211_add_virtual_monitor(struct ieee80211_local *local);
|
||||
void ieee80211_del_virtual_monitor(struct ieee80211_local *local);
|
||||
|
||||
/* channel management */
|
||||
enum ieee80211_chan_mode {
|
||||
CHAN_MODE_UNDEFINED,
|
||||
|
@ -331,7 +331,7 @@ static void ieee80211_set_default_queues(struct ieee80211_sub_if_data *sdata)
|
||||
sdata->vif.cab_queue = IEEE80211_INVAL_HW_QUEUE;
|
||||
}
|
||||
|
||||
int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
|
||||
static int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
int ret = 0;
|
||||
@ -377,7 +377,7 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
|
||||
static void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
|
||||
@ -497,6 +497,12 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up)
|
||||
break;
|
||||
}
|
||||
|
||||
if (local->monitors == 0 && local->open_count == 0) {
|
||||
res = ieee80211_add_virtual_monitor(local);
|
||||
if (res)
|
||||
goto err_stop;
|
||||
}
|
||||
|
||||
/* must be before the call to ieee80211_configure_filter */
|
||||
local->monitors++;
|
||||
if (local->monitors == 1) {
|
||||
@ -511,6 +517,8 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up)
|
||||
break;
|
||||
default:
|
||||
if (coming_up) {
|
||||
ieee80211_del_virtual_monitor(local);
|
||||
|
||||
res = drv_add_interface(local, sdata);
|
||||
if (res)
|
||||
goto err_stop;
|
||||
@ -745,6 +753,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
|
||||
if (local->monitors == 0) {
|
||||
local->hw.conf.flags &= ~IEEE80211_CONF_MONITOR;
|
||||
hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR;
|
||||
ieee80211_del_virtual_monitor(local);
|
||||
}
|
||||
|
||||
ieee80211_adjust_monitor_flags(sdata, -1);
|
||||
@ -818,6 +827,9 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
|
||||
|
||||
if (local->monitors == local->open_count && local->monitors > 0)
|
||||
ieee80211_add_virtual_monitor(local);
|
||||
}
|
||||
|
||||
static int ieee80211_stop(struct net_device *dev)
|
||||
|
@ -1360,6 +1360,17 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
|
||||
}
|
||||
mutex_unlock(&local->sta_mtx);
|
||||
|
||||
/*
|
||||
* if we want to get out of ps before disassoc (why?) we have
|
||||
* to do it before sending disassoc, as otherwise the null-packet
|
||||
* won't be valid.
|
||||
*/
|
||||
if (local->hw.conf.flags & IEEE80211_CONF_PS) {
|
||||
local->hw.conf.flags &= ~IEEE80211_CONF_PS;
|
||||
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
|
||||
}
|
||||
local->ps_sdata = NULL;
|
||||
|
||||
/* flush out any pending frame (e.g. DELBA) before deauth/disassoc */
|
||||
if (tx)
|
||||
drv_flush(local, false);
|
||||
@ -1395,12 +1406,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
|
||||
del_timer_sync(&local->dynamic_ps_timer);
|
||||
cancel_work_sync(&local->dynamic_ps_enable_work);
|
||||
|
||||
if (local->hw.conf.flags & IEEE80211_CONF_PS) {
|
||||
local->hw.conf.flags &= ~IEEE80211_CONF_PS;
|
||||
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
|
||||
}
|
||||
local->ps_sdata = NULL;
|
||||
|
||||
/* Disable ARP filtering */
|
||||
if (sdata->vif.bss_conf.arp_filter_enabled) {
|
||||
sdata->vif.bss_conf.arp_filter_enabled = false;
|
||||
|
@ -324,6 +324,7 @@ void ieee80211_sw_roc_work(struct work_struct *work)
|
||||
container_of(work, struct ieee80211_roc_work, work.work);
|
||||
struct ieee80211_sub_if_data *sdata = roc->sdata;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
bool started;
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
|
||||
@ -366,9 +367,10 @@ void ieee80211_sw_roc_work(struct work_struct *work)
|
||||
/* finish this ROC */
|
||||
finish:
|
||||
list_del(&roc->list);
|
||||
started = roc->started;
|
||||
ieee80211_roc_notify_destroy(roc);
|
||||
|
||||
if (roc->started) {
|
||||
if (started) {
|
||||
drv_flush(local, false);
|
||||
|
||||
local->tmp_channel = NULL;
|
||||
@ -379,7 +381,7 @@ void ieee80211_sw_roc_work(struct work_struct *work)
|
||||
|
||||
ieee80211_recalc_idle(local);
|
||||
|
||||
if (roc->started)
|
||||
if (started)
|
||||
ieee80211_start_next_roc(local);
|
||||
}
|
||||
|
||||
|
@ -74,6 +74,27 @@ config CFG80211_REG_DEBUG
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config CFG80211_CERTIFICATION_ONUS
|
||||
bool "cfg80211 certification onus"
|
||||
depends on CFG80211 && EXPERT
|
||||
default n
|
||||
---help---
|
||||
You should disable this option unless you are both capable
|
||||
and willing to ensure your system will remain regulatory
|
||||
compliant with the features available under this option.
|
||||
Some options may still be under heavy development and
|
||||
for whatever reason regulatory compliance has not or
|
||||
cannot yet be verified. Regulatory verification may at
|
||||
times only be possible until you have the final system
|
||||
in place.
|
||||
|
||||
This option should only be enabled by system integrators
|
||||
or distributions that have done work necessary to ensure
|
||||
regulatory certification on the system with the enabled
|
||||
features. Alternatively you can enable this option if
|
||||
you are a wireless researcher and are working in a controlled
|
||||
and approved environment by your local regulatory agency.
|
||||
|
||||
config CFG80211_DEFAULT_PS
|
||||
bool "enable powersave by default"
|
||||
depends on CFG80211
|
||||
|
@ -82,7 +82,6 @@ int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
|
||||
int freq, enum nl80211_channel_type chantype)
|
||||
{
|
||||
struct ieee80211_channel *chan;
|
||||
int err;
|
||||
|
||||
if (!rdev->ops->set_monitor_channel)
|
||||
return -EOPNOTSUPP;
|
||||
@ -93,13 +92,7 @@ int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
|
||||
if (!chan)
|
||||
return -EINVAL;
|
||||
|
||||
err = rdev->ops->set_monitor_channel(&rdev->wiphy, chan, chantype);
|
||||
if (!err) {
|
||||
rdev->monitor_channel = chan;
|
||||
rdev->monitor_channel_type = chantype;
|
||||
}
|
||||
|
||||
return err;
|
||||
return rdev->ops->set_monitor_channel(&rdev->wiphy, chan, chantype);
|
||||
}
|
||||
|
||||
void
|
||||
@ -134,9 +127,16 @@ cfg80211_get_chan_state(struct wireless_dev *wdev,
|
||||
break;
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_P2P_GO:
|
||||
if (wdev->beacon_interval) {
|
||||
*chan = wdev->channel;
|
||||
*chanmode = CHAN_MODE_SHARED;
|
||||
}
|
||||
return;
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
*chan = wdev->channel;
|
||||
*chanmode = CHAN_MODE_SHARED;
|
||||
if (wdev->mesh_id_len) {
|
||||
*chan = wdev->channel;
|
||||
*chanmode = CHAN_MODE_SHARED;
|
||||
}
|
||||
return;
|
||||
case NL80211_IFTYPE_MONITOR:
|
||||
case NL80211_IFTYPE_AP_VLAN:
|
||||
|
@ -542,7 +542,7 @@ int wiphy_register(struct wiphy *wiphy)
|
||||
}
|
||||
|
||||
/* set up regulatory info */
|
||||
regulatory_update(wiphy, NL80211_REGDOM_SET_BY_CORE);
|
||||
wiphy_regulatory_register(wiphy);
|
||||
|
||||
list_add_rcu(&rdev->list, &cfg80211_rdev_list);
|
||||
cfg80211_rdev_list_generation++;
|
||||
@ -652,9 +652,11 @@ void wiphy_unregister(struct wiphy *wiphy)
|
||||
/* nothing */
|
||||
cfg80211_unlock_rdev(rdev);
|
||||
|
||||
/* If this device got a regulatory hint tell core its
|
||||
* free to listen now to a new shiny device regulatory hint */
|
||||
reg_device_remove(wiphy);
|
||||
/*
|
||||
* If this device got a regulatory hint tell core its
|
||||
* free to listen now to a new shiny device regulatory hint
|
||||
*/
|
||||
wiphy_regulatory_deregister(wiphy);
|
||||
|
||||
cfg80211_rdev_list_generation++;
|
||||
device_del(&rdev->wiphy.dev);
|
||||
@ -736,60 +738,14 @@ static struct device_type wiphy_type = {
|
||||
.name = "wlan",
|
||||
};
|
||||
|
||||
static struct ieee80211_channel *
|
||||
cfg80211_get_any_chan(struct cfg80211_registered_device *rdev)
|
||||
{
|
||||
struct ieee80211_supported_band *sband;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
|
||||
sband = rdev->wiphy.bands[i];
|
||||
if (sband && sband->n_channels > 0)
|
||||
return &sband->channels[0];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void cfg80211_init_mon_chan(struct cfg80211_registered_device *rdev)
|
||||
{
|
||||
struct ieee80211_channel *chan;
|
||||
|
||||
chan = cfg80211_get_any_chan(rdev);
|
||||
if (WARN_ON(!chan))
|
||||
return;
|
||||
|
||||
mutex_lock(&rdev->devlist_mtx);
|
||||
WARN_ON(cfg80211_set_monitor_channel(rdev, chan->center_freq,
|
||||
NL80211_CHAN_NO_HT));
|
||||
mutex_unlock(&rdev->devlist_mtx);
|
||||
}
|
||||
|
||||
void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev,
|
||||
enum nl80211_iftype iftype, int num)
|
||||
{
|
||||
bool has_monitors_only_old = cfg80211_has_monitors_only(rdev);
|
||||
bool has_monitors_only_new;
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
rdev->num_running_ifaces += num;
|
||||
if (iftype == NL80211_IFTYPE_MONITOR)
|
||||
rdev->num_running_monitor_ifaces += num;
|
||||
|
||||
has_monitors_only_new = cfg80211_has_monitors_only(rdev);
|
||||
if (has_monitors_only_new != has_monitors_only_old) {
|
||||
if (rdev->ops->set_monitor_enabled)
|
||||
rdev->ops->set_monitor_enabled(&rdev->wiphy,
|
||||
has_monitors_only_new);
|
||||
|
||||
if (!has_monitors_only_new) {
|
||||
rdev->monitor_channel = NULL;
|
||||
rdev->monitor_channel_type = NL80211_CHAN_NO_HT;
|
||||
} else {
|
||||
cfg80211_init_mon_chan(rdev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
|
||||
@ -912,6 +868,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
|
||||
mutex_unlock(&rdev->devlist_mtx);
|
||||
dev_put(dev);
|
||||
}
|
||||
cfg80211_update_iface_num(rdev, wdev->iftype, 1);
|
||||
cfg80211_lock_rdev(rdev);
|
||||
mutex_lock(&rdev->devlist_mtx);
|
||||
wdev_lock(wdev);
|
||||
@ -1006,7 +963,6 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
|
||||
mutex_unlock(&rdev->devlist_mtx);
|
||||
if (ret)
|
||||
return notifier_from_errno(ret);
|
||||
cfg80211_update_iface_num(rdev, wdev->iftype, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -61,9 +61,6 @@ struct cfg80211_registered_device {
|
||||
int num_running_ifaces;
|
||||
int num_running_monitor_ifaces;
|
||||
|
||||
struct ieee80211_channel *monitor_channel;
|
||||
enum nl80211_channel_type monitor_channel_type;
|
||||
|
||||
/* BSSes/scanning */
|
||||
spinlock_t bss_lock;
|
||||
struct list_head bss_list;
|
||||
|
@ -919,6 +919,19 @@ void cfg80211_cqm_pktloss_notify(struct net_device *dev,
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_cqm_pktloss_notify);
|
||||
|
||||
void cfg80211_cqm_txe_notify(struct net_device *dev,
|
||||
const u8 *peer, u32 num_packets,
|
||||
u32 rate, u32 intvl, gfp_t gfp)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct wiphy *wiphy = wdev->wiphy;
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
|
||||
|
||||
nl80211_send_cqm_txe_notify(rdev, dev, peer, num_packets,
|
||||
rate, intvl, gfp);
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_cqm_txe_notify);
|
||||
|
||||
void cfg80211_gtk_rekey_notify(struct net_device *dev, const u8 *bssid,
|
||||
const u8 *replay_ctr, gfp_t gfp)
|
||||
{
|
||||
|
@ -354,6 +354,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
|
||||
[NL80211_ATTR_INACTIVITY_TIMEOUT] = { .type = NLA_U16 },
|
||||
[NL80211_ATTR_BG_SCAN_PERIOD] = { .type = NLA_U16 },
|
||||
[NL80211_ATTR_WDEV] = { .type = NLA_U64 },
|
||||
[NL80211_ATTR_USER_REG_HINT_TYPE] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
/* policy for the key attributes */
|
||||
@ -1759,11 +1760,17 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags,
|
||||
(cfg80211_rdev_list_generation << 2)))
|
||||
goto nla_put_failure;
|
||||
|
||||
if (rdev->monitor_channel) {
|
||||
if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
|
||||
rdev->monitor_channel->center_freq) ||
|
||||
nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
|
||||
rdev->monitor_channel_type))
|
||||
if (rdev->ops->get_channel) {
|
||||
struct ieee80211_channel *chan;
|
||||
enum nl80211_channel_type channel_type;
|
||||
|
||||
chan = rdev->ops->get_channel(&rdev->wiphy, wdev,
|
||||
&channel_type);
|
||||
if (chan &&
|
||||
(nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
|
||||
chan->center_freq) ||
|
||||
nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
|
||||
channel_type)))
|
||||
goto nla_put_failure;
|
||||
}
|
||||
|
||||
@ -3576,6 +3583,7 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
int r;
|
||||
char *data = NULL;
|
||||
enum nl80211_user_reg_hint_type user_reg_hint_type;
|
||||
|
||||
/*
|
||||
* You should only get this when cfg80211 hasn't yet initialized
|
||||
@ -3595,7 +3603,21 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
|
||||
|
||||
data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
|
||||
|
||||
r = regulatory_hint_user(data);
|
||||
if (info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE])
|
||||
user_reg_hint_type =
|
||||
nla_get_u32(info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE]);
|
||||
else
|
||||
user_reg_hint_type = NL80211_USER_REG_HINT_USER;
|
||||
|
||||
switch (user_reg_hint_type) {
|
||||
case NL80211_USER_REG_HINT_USER:
|
||||
case NL80211_USER_REG_HINT_CELL_BASE:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
r = regulatory_hint_user(data, user_reg_hint_type);
|
||||
|
||||
return r;
|
||||
}
|
||||
@ -3965,6 +3987,11 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info)
|
||||
cfg80211_regdomain->dfs_region)))
|
||||
goto nla_put_failure;
|
||||
|
||||
if (reg_last_request_cell_base() &&
|
||||
nla_put_u32(msg, NL80211_ATTR_USER_REG_HINT_TYPE,
|
||||
NL80211_USER_REG_HINT_CELL_BASE))
|
||||
goto nla_put_failure;
|
||||
|
||||
nl_reg_rules = nla_nest_start(msg, NL80211_ATTR_REG_RULES);
|
||||
if (!nl_reg_rules)
|
||||
goto nla_put_failure;
|
||||
@ -6261,8 +6288,35 @@ nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] __read_mostly = {
|
||||
[NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_CQM_TXE_RATE] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_CQM_TXE_PKTS] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_CQM_TXE_INTVL] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
static int nl80211_set_cqm_txe(struct genl_info *info,
|
||||
u32 rate, u32 pkts, u32 intvl)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev = info->user_ptr[0];
|
||||
struct wireless_dev *wdev;
|
||||
struct net_device *dev = info->user_ptr[1];
|
||||
|
||||
if ((rate < 0 || rate > 100) ||
|
||||
(intvl < 0 || intvl > NL80211_CQM_TXE_MAX_INTVL))
|
||||
return -EINVAL;
|
||||
|
||||
wdev = dev->ieee80211_ptr;
|
||||
|
||||
if (!rdev->ops->set_cqm_txe_config)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (wdev->iftype != NL80211_IFTYPE_STATION &&
|
||||
wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return rdev->ops->set_cqm_txe_config(wdev->wiphy, dev,
|
||||
rate, pkts, intvl);
|
||||
}
|
||||
|
||||
static int nl80211_set_cqm_rssi(struct genl_info *info,
|
||||
s32 threshold, u32 hysteresis)
|
||||
{
|
||||
@ -6310,6 +6364,14 @@ static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info)
|
||||
threshold = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_THOLD]);
|
||||
hysteresis = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_HYST]);
|
||||
err = nl80211_set_cqm_rssi(info, threshold, hysteresis);
|
||||
} else if (attrs[NL80211_ATTR_CQM_TXE_RATE] &&
|
||||
attrs[NL80211_ATTR_CQM_TXE_PKTS] &&
|
||||
attrs[NL80211_ATTR_CQM_TXE_INTVL]) {
|
||||
u32 rate, pkts, intvl;
|
||||
rate = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_RATE]);
|
||||
pkts = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_PKTS]);
|
||||
intvl = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_INTVL]);
|
||||
err = nl80211_set_cqm_txe(info, rate, pkts, intvl);
|
||||
} else
|
||||
err = -EINVAL;
|
||||
|
||||
@ -6466,8 +6528,8 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev = info->user_ptr[0];
|
||||
struct nlattr *tb[NUM_NL80211_WOWLAN_TRIG];
|
||||
struct cfg80211_wowlan no_triggers = {};
|
||||
struct cfg80211_wowlan new_triggers = {};
|
||||
struct cfg80211_wowlan *ntrig;
|
||||
struct wiphy_wowlan_support *wowlan = &rdev->wiphy.wowlan;
|
||||
int err, i;
|
||||
bool prev_enabled = rdev->wowlan;
|
||||
@ -6475,8 +6537,11 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
|
||||
if (!rdev->wiphy.wowlan.flags && !rdev->wiphy.wowlan.n_patterns)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS])
|
||||
goto no_triggers;
|
||||
if (!info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]) {
|
||||
cfg80211_rdev_free_wowlan(rdev);
|
||||
rdev->wowlan = NULL;
|
||||
goto set_wakeup;
|
||||
}
|
||||
|
||||
err = nla_parse(tb, MAX_NL80211_WOWLAN_TRIG,
|
||||
nla_data(info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]),
|
||||
@ -6587,22 +6652,15 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
|
||||
}
|
||||
}
|
||||
|
||||
if (memcmp(&new_triggers, &no_triggers, sizeof(new_triggers))) {
|
||||
struct cfg80211_wowlan *ntrig;
|
||||
ntrig = kmemdup(&new_triggers, sizeof(new_triggers),
|
||||
GFP_KERNEL);
|
||||
if (!ntrig) {
|
||||
err = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
cfg80211_rdev_free_wowlan(rdev);
|
||||
rdev->wowlan = ntrig;
|
||||
} else {
|
||||
no_triggers:
|
||||
cfg80211_rdev_free_wowlan(rdev);
|
||||
rdev->wowlan = NULL;
|
||||
ntrig = kmemdup(&new_triggers, sizeof(new_triggers), GFP_KERNEL);
|
||||
if (!ntrig) {
|
||||
err = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
cfg80211_rdev_free_wowlan(rdev);
|
||||
rdev->wowlan = ntrig;
|
||||
|
||||
set_wakeup:
|
||||
if (rdev->ops->set_wakeup && prev_enabled != !!rdev->wowlan)
|
||||
rdev->ops->set_wakeup(&rdev->wiphy, rdev->wowlan);
|
||||
|
||||
@ -8099,7 +8157,7 @@ static void nl80211_send_remain_on_chan_event(
|
||||
if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
|
||||
(wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
|
||||
wdev->netdev->ifindex)) ||
|
||||
nla_put_u32(msg, NL80211_ATTR_WDEV, wdev_id(wdev)) ||
|
||||
nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev)) ||
|
||||
nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, chan->center_freq) ||
|
||||
nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, channel_type) ||
|
||||
nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie))
|
||||
@ -8493,6 +8551,56 @@ void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev,
|
||||
nlmsg_free(msg);
|
||||
}
|
||||
|
||||
void
|
||||
nl80211_send_cqm_txe_notify(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *netdev, const u8 *peer,
|
||||
u32 num_packets, u32 rate, u32 intvl, gfp_t gfp)
|
||||
{
|
||||
struct sk_buff *msg;
|
||||
struct nlattr *pinfoattr;
|
||||
void *hdr;
|
||||
|
||||
msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
|
||||
if (!msg)
|
||||
return;
|
||||
|
||||
hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NOTIFY_CQM);
|
||||
if (!hdr) {
|
||||
nlmsg_free(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
|
||||
nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
|
||||
nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer))
|
||||
goto nla_put_failure;
|
||||
|
||||
pinfoattr = nla_nest_start(msg, NL80211_ATTR_CQM);
|
||||
if (!pinfoattr)
|
||||
goto nla_put_failure;
|
||||
|
||||
if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_PKTS, num_packets))
|
||||
goto nla_put_failure;
|
||||
|
||||
if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_RATE, rate))
|
||||
goto nla_put_failure;
|
||||
|
||||
if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_INTVL, intvl))
|
||||
goto nla_put_failure;
|
||||
|
||||
nla_nest_end(msg, pinfoattr);
|
||||
|
||||
genlmsg_end(msg, hdr);
|
||||
|
||||
genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
|
||||
nl80211_mlme_mcgrp.id, gfp);
|
||||
return;
|
||||
|
||||
nla_put_failure:
|
||||
genlmsg_cancel(msg, hdr);
|
||||
nlmsg_free(msg);
|
||||
}
|
||||
|
||||
void
|
||||
nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *netdev, const u8 *peer,
|
||||
|
@ -110,6 +110,11 @@ nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *netdev, const u8 *peer,
|
||||
u32 num_packets, gfp_t gfp);
|
||||
|
||||
void
|
||||
nl80211_send_cqm_txe_notify(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *netdev, const u8 *peer,
|
||||
u32 num_packets, u32 rate, u32 intvl, gfp_t gfp);
|
||||
|
||||
void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *netdev, const u8 *bssid,
|
||||
const u8 *replay_ctr, gfp_t gfp);
|
||||
|
@ -97,9 +97,16 @@ const struct ieee80211_regdomain *cfg80211_regdomain;
|
||||
* - cfg80211_world_regdom
|
||||
* - cfg80211_regdom
|
||||
* - last_request
|
||||
* - reg_num_devs_support_basehint
|
||||
*/
|
||||
static DEFINE_MUTEX(reg_mutex);
|
||||
|
||||
/*
|
||||
* Number of devices that registered to the core
|
||||
* that support cellular base station regulatory hints
|
||||
*/
|
||||
static int reg_num_devs_support_basehint;
|
||||
|
||||
static inline void assert_reg_lock(void)
|
||||
{
|
||||
lockdep_assert_held(®_mutex);
|
||||
@ -911,6 +918,59 @@ static void handle_band(struct wiphy *wiphy,
|
||||
handle_channel(wiphy, initiator, band, i);
|
||||
}
|
||||
|
||||
static bool reg_request_cell_base(struct regulatory_request *request)
|
||||
{
|
||||
if (request->initiator != NL80211_REGDOM_SET_BY_USER)
|
||||
return false;
|
||||
if (request->user_reg_hint_type != NL80211_USER_REG_HINT_CELL_BASE)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool reg_last_request_cell_base(void)
|
||||
{
|
||||
assert_cfg80211_lock();
|
||||
|
||||
mutex_lock(®_mutex);
|
||||
return reg_request_cell_base(last_request);
|
||||
mutex_unlock(®_mutex);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CFG80211_CERTIFICATION_ONUS
|
||||
|
||||
/* Core specific check */
|
||||
static int reg_ignore_cell_hint(struct regulatory_request *pending_request)
|
||||
{
|
||||
if (!reg_num_devs_support_basehint)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (reg_request_cell_base(last_request)) {
|
||||
if (!regdom_changes(pending_request->alpha2))
|
||||
return -EALREADY;
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Device specific check */
|
||||
static bool reg_dev_ignore_cell_hint(struct wiphy *wiphy)
|
||||
{
|
||||
if (!(wiphy->features & NL80211_FEATURE_CELL_BASE_REG_HINTS))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
static int reg_ignore_cell_hint(struct regulatory_request *pending_request)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
static int reg_dev_ignore_cell_hint(struct wiphy *wiphy)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static bool ignore_reg_update(struct wiphy *wiphy,
|
||||
enum nl80211_reg_initiator initiator)
|
||||
{
|
||||
@ -944,6 +1004,9 @@ static bool ignore_reg_update(struct wiphy *wiphy,
|
||||
return true;
|
||||
}
|
||||
|
||||
if (reg_request_cell_base(last_request))
|
||||
return reg_dev_ignore_cell_hint(wiphy);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1169,14 +1232,6 @@ static void wiphy_update_regulatory(struct wiphy *wiphy,
|
||||
wiphy->reg_notifier(wiphy, last_request);
|
||||
}
|
||||
|
||||
void regulatory_update(struct wiphy *wiphy,
|
||||
enum nl80211_reg_initiator setby)
|
||||
{
|
||||
mutex_lock(®_mutex);
|
||||
wiphy_update_regulatory(wiphy, setby);
|
||||
mutex_unlock(®_mutex);
|
||||
}
|
||||
|
||||
static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev;
|
||||
@ -1307,6 +1362,13 @@ static int ignore_request(struct wiphy *wiphy,
|
||||
return 0;
|
||||
case NL80211_REGDOM_SET_BY_COUNTRY_IE:
|
||||
|
||||
if (reg_request_cell_base(last_request)) {
|
||||
/* Trust a Cell base station over the AP's country IE */
|
||||
if (regdom_changes(pending_request->alpha2))
|
||||
return -EOPNOTSUPP;
|
||||
return -EALREADY;
|
||||
}
|
||||
|
||||
last_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx);
|
||||
|
||||
if (unlikely(!is_an_alpha2(pending_request->alpha2)))
|
||||
@ -1351,6 +1413,12 @@ static int ignore_request(struct wiphy *wiphy,
|
||||
|
||||
return REG_INTERSECT;
|
||||
case NL80211_REGDOM_SET_BY_USER:
|
||||
if (reg_request_cell_base(pending_request))
|
||||
return reg_ignore_cell_hint(pending_request);
|
||||
|
||||
if (reg_request_cell_base(last_request))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (last_request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE)
|
||||
return REG_INTERSECT;
|
||||
/*
|
||||
@ -1640,7 +1708,8 @@ static int regulatory_hint_core(const char *alpha2)
|
||||
}
|
||||
|
||||
/* User hints */
|
||||
int regulatory_hint_user(const char *alpha2)
|
||||
int regulatory_hint_user(const char *alpha2,
|
||||
enum nl80211_user_reg_hint_type user_reg_hint_type)
|
||||
{
|
||||
struct regulatory_request *request;
|
||||
|
||||
@ -1654,6 +1723,7 @@ int regulatory_hint_user(const char *alpha2)
|
||||
request->alpha2[0] = alpha2[0];
|
||||
request->alpha2[1] = alpha2[1];
|
||||
request->initiator = NL80211_REGDOM_SET_BY_USER;
|
||||
request->user_reg_hint_type = user_reg_hint_type;
|
||||
|
||||
queue_regulatory_request(request);
|
||||
|
||||
@ -1906,7 +1976,7 @@ static void restore_regulatory_settings(bool reset_user)
|
||||
* settings, user regulatory settings takes precedence.
|
||||
*/
|
||||
if (is_an_alpha2(alpha2))
|
||||
regulatory_hint_user(user_alpha2);
|
||||
regulatory_hint_user(user_alpha2, NL80211_USER_REG_HINT_USER);
|
||||
|
||||
if (list_empty(&tmp_reg_req_list))
|
||||
return;
|
||||
@ -2081,9 +2151,16 @@ static void print_regdomain(const struct ieee80211_regdomain *rd)
|
||||
else {
|
||||
if (is_unknown_alpha2(rd->alpha2))
|
||||
pr_info("Regulatory domain changed to driver built-in settings (unknown country)\n");
|
||||
else
|
||||
pr_info("Regulatory domain changed to country: %c%c\n",
|
||||
rd->alpha2[0], rd->alpha2[1]);
|
||||
else {
|
||||
if (reg_request_cell_base(last_request))
|
||||
pr_info("Regulatory domain changed "
|
||||
"to country: %c%c by Cell Station\n",
|
||||
rd->alpha2[0], rd->alpha2[1]);
|
||||
else
|
||||
pr_info("Regulatory domain changed "
|
||||
"to country: %c%c\n",
|
||||
rd->alpha2[0], rd->alpha2[1]);
|
||||
}
|
||||
}
|
||||
print_dfs_region(rd->dfs_region);
|
||||
print_rd_rules(rd);
|
||||
@ -2128,7 +2205,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
|
||||
* checking if the alpha2 changes if CRDA was already called
|
||||
*/
|
||||
if (!regdom_changes(rd->alpha2))
|
||||
return -EINVAL;
|
||||
return -EALREADY;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2248,6 +2325,9 @@ int set_regdom(const struct ieee80211_regdomain *rd)
|
||||
/* Note that this doesn't update the wiphys, this is done below */
|
||||
r = __set_regdom(rd);
|
||||
if (r) {
|
||||
if (r == -EALREADY)
|
||||
reg_set_request_processed();
|
||||
|
||||
kfree(rd);
|
||||
mutex_unlock(®_mutex);
|
||||
return r;
|
||||
@ -2290,8 +2370,22 @@ int reg_device_uevent(struct device *dev, struct kobj_uevent_env *env)
|
||||
}
|
||||
#endif /* CONFIG_HOTPLUG */
|
||||
|
||||
void wiphy_regulatory_register(struct wiphy *wiphy)
|
||||
{
|
||||
assert_cfg80211_lock();
|
||||
|
||||
mutex_lock(®_mutex);
|
||||
|
||||
if (!reg_dev_ignore_cell_hint(wiphy))
|
||||
reg_num_devs_support_basehint++;
|
||||
|
||||
wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE);
|
||||
|
||||
mutex_unlock(®_mutex);
|
||||
}
|
||||
|
||||
/* Caller must hold cfg80211_mutex */
|
||||
void reg_device_remove(struct wiphy *wiphy)
|
||||
void wiphy_regulatory_deregister(struct wiphy *wiphy)
|
||||
{
|
||||
struct wiphy *request_wiphy = NULL;
|
||||
|
||||
@ -2299,6 +2393,9 @@ void reg_device_remove(struct wiphy *wiphy)
|
||||
|
||||
mutex_lock(®_mutex);
|
||||
|
||||
if (!reg_dev_ignore_cell_hint(wiphy))
|
||||
reg_num_devs_support_basehint--;
|
||||
|
||||
kfree(wiphy->regd);
|
||||
|
||||
if (last_request)
|
||||
@ -2364,7 +2461,8 @@ int __init regulatory_init(void)
|
||||
* as a user hint.
|
||||
*/
|
||||
if (!is_world_regdom(ieee80211_regdom))
|
||||
regulatory_hint_user(ieee80211_regdom);
|
||||
regulatory_hint_user(ieee80211_regdom,
|
||||
NL80211_USER_REG_HINT_USER);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -22,17 +22,19 @@ bool is_world_regdom(const char *alpha2);
|
||||
bool reg_is_valid_request(const char *alpha2);
|
||||
bool reg_supported_dfs_region(u8 dfs_region);
|
||||
|
||||
int regulatory_hint_user(const char *alpha2);
|
||||
int regulatory_hint_user(const char *alpha2,
|
||||
enum nl80211_user_reg_hint_type user_reg_hint_type);
|
||||
|
||||
int reg_device_uevent(struct device *dev, struct kobj_uevent_env *env);
|
||||
void reg_device_remove(struct wiphy *wiphy);
|
||||
void wiphy_regulatory_register(struct wiphy *wiphy);
|
||||
void wiphy_regulatory_deregister(struct wiphy *wiphy);
|
||||
|
||||
int __init regulatory_init(void);
|
||||
void regulatory_exit(void);
|
||||
|
||||
int set_regdom(const struct ieee80211_regdomain *rd);
|
||||
|
||||
void regulatory_update(struct wiphy *wiphy, enum nl80211_reg_initiator setby);
|
||||
bool reg_last_request_cell_base(void);
|
||||
|
||||
/**
|
||||
* regulatory_hint_found_beacon - hints a beacon was found on a channel
|
||||
|
@ -827,6 +827,8 @@ static int cfg80211_wext_giwfreq(struct net_device *dev,
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
|
||||
struct ieee80211_channel *chan;
|
||||
enum nl80211_channel_type channel_type;
|
||||
|
||||
switch (wdev->iftype) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
@ -834,10 +836,13 @@ static int cfg80211_wext_giwfreq(struct net_device *dev,
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra);
|
||||
case NL80211_IFTYPE_MONITOR:
|
||||
if (!rdev->monitor_channel)
|
||||
if (!rdev->ops->get_channel)
|
||||
return -EINVAL;
|
||||
|
||||
freq->m = rdev->monitor_channel->center_freq;
|
||||
chan = rdev->ops->get_channel(wdev->wiphy, wdev, &channel_type);
|
||||
if (!chan)
|
||||
return -EINVAL;
|
||||
freq->m = chan->center_freq;
|
||||
freq->e = 6;
|
||||
return 0;
|
||||
default:
|
||||
|
Loading…
Reference in New Issue
Block a user