Merge branch 'for-john' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next
This commit is contained in:
Коммит
66ba271ab9
|
@ -188,6 +188,8 @@ struct ieee80211_channel {
|
|||
* when used with 802.11g (on the 2.4 GHz band); filled by the
|
||||
* core code when registering the wiphy.
|
||||
* @IEEE80211_RATE_ERP_G: This is an ERP rate in 802.11g mode.
|
||||
* @IEEE80211_RATE_SUPPORTS_5MHZ: Rate can be used in 5 MHz mode
|
||||
* @IEEE80211_RATE_SUPPORTS_10MHZ: Rate can be used in 10 MHz mode
|
||||
*/
|
||||
enum ieee80211_rate_flags {
|
||||
IEEE80211_RATE_SHORT_PREAMBLE = 1<<0,
|
||||
|
@ -195,6 +197,8 @@ enum ieee80211_rate_flags {
|
|||
IEEE80211_RATE_MANDATORY_B = 1<<2,
|
||||
IEEE80211_RATE_MANDATORY_G = 1<<3,
|
||||
IEEE80211_RATE_ERP_G = 1<<4,
|
||||
IEEE80211_RATE_SUPPORTS_5MHZ = 1<<5,
|
||||
IEEE80211_RATE_SUPPORTS_10MHZ = 1<<6,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -432,6 +436,30 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy,
|
|||
const struct cfg80211_chan_def *chandef,
|
||||
u32 prohibited_flags);
|
||||
|
||||
/**
|
||||
* ieee80211_chandef_rate_flags - returns rate flags for a channel
|
||||
*
|
||||
* In some channel types, not all rates may be used - for example CCK
|
||||
* rates may not be used in 5/10 MHz channels.
|
||||
*
|
||||
* @chandef: channel definition for the channel
|
||||
*
|
||||
* Returns: rate flags which apply for this channel
|
||||
*/
|
||||
static inline enum ieee80211_rate_flags
|
||||
ieee80211_chandef_rate_flags(struct cfg80211_chan_def *chandef)
|
||||
{
|
||||
switch (chandef->width) {
|
||||
case NL80211_CHAN_WIDTH_5:
|
||||
return IEEE80211_RATE_SUPPORTS_5MHZ;
|
||||
case NL80211_CHAN_WIDTH_10:
|
||||
return IEEE80211_RATE_SUPPORTS_10MHZ;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* enum survey_info_flags - survey information flags
|
||||
*
|
||||
|
@ -1431,7 +1459,8 @@ const u8 *ieee80211_bss_get_ie(struct cfg80211_bss *bss, u8 ie);
|
|||
* This structure provides information needed to complete IEEE 802.11
|
||||
* authentication.
|
||||
*
|
||||
* @bss: The BSS to authenticate with.
|
||||
* @bss: The BSS to authenticate with, the callee must obtain a reference
|
||||
* to it if it needs to keep it.
|
||||
* @auth_type: Authentication type (algorithm)
|
||||
* @ie: Extra IEs to add to Authentication frame or %NULL
|
||||
* @ie_len: Length of ie buffer in octets
|
||||
|
@ -1469,11 +1498,10 @@ enum cfg80211_assoc_req_flags {
|
|||
*
|
||||
* This structure provides information needed to complete IEEE 802.11
|
||||
* (re)association.
|
||||
* @bss: The BSS to associate with. If the call is successful the driver
|
||||
* is given a reference that it must release, normally via a call to
|
||||
* cfg80211_send_rx_assoc(), or, if association timed out, with a
|
||||
* call to cfg80211_put_bss() (in addition to calling
|
||||
* cfg80211_send_assoc_timeout())
|
||||
* @bss: The BSS to associate with. If the call is successful the driver is
|
||||
* given a reference that it must give back to cfg80211_send_rx_assoc()
|
||||
* or to cfg80211_assoc_timeout(). To ensure proper refcounting, new
|
||||
* association requests while already associating must be rejected.
|
||||
* @ie: Extra IEs to add to (Re)Association Request frame or %NULL
|
||||
* @ie_len: Length of ie buffer in octets
|
||||
* @use_mfp: Use management frame protection (IEEE 802.11w) in this association
|
||||
|
@ -2342,6 +2370,7 @@ struct cfg80211_ops {
|
|||
* responds to probe-requests in hardware.
|
||||
* @WIPHY_FLAG_OFFCHAN_TX: Device supports direct off-channel TX.
|
||||
* @WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL: Device supports remain-on-channel call.
|
||||
* @WIPHY_FLAG_SUPPORTS_5_10_MHZ: Device supports 5 MHz and 10 MHz channels.
|
||||
*/
|
||||
enum wiphy_flags {
|
||||
WIPHY_FLAG_CUSTOM_REGULATORY = BIT(0),
|
||||
|
@ -2365,6 +2394,7 @@ enum wiphy_flags {
|
|||
WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD = BIT(19),
|
||||
WIPHY_FLAG_OFFCHAN_TX = BIT(20),
|
||||
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL = BIT(21),
|
||||
WIPHY_FLAG_SUPPORTS_5_10_MHZ = BIT(22),
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -3492,11 +3522,11 @@ void cfg80211_rx_assoc_resp(struct net_device *dev,
|
|||
/**
|
||||
* cfg80211_assoc_timeout - notification of timed out association
|
||||
* @dev: network device
|
||||
* @addr: The MAC address of the device with which the association timed out
|
||||
* @bss: The BSS entry with which association timed out.
|
||||
*
|
||||
* This function may sleep. The caller must hold the corresponding wdev's mutex.
|
||||
*/
|
||||
void cfg80211_assoc_timeout(struct net_device *dev, const u8 *addr);
|
||||
void cfg80211_assoc_timeout(struct net_device *dev, struct cfg80211_bss *bss);
|
||||
|
||||
/**
|
||||
* cfg80211_tx_mlme_mgmt - notification of transmitted deauth/disassoc frame
|
||||
|
|
|
@ -305,6 +305,7 @@ enum ieee80211_rssi_event {
|
|||
* @basic_rates: bitmap of basic rates, each bit stands for an
|
||||
* index into the rate table configured by the driver in
|
||||
* the current band.
|
||||
* @beacon_rate: associated AP's beacon TX rate
|
||||
* @mcast_rate: per-band multicast rate index + 1 (0: disabled)
|
||||
* @bssid: The BSSID for this BSS
|
||||
* @enable_beacon: whether beaconing should be enabled or not
|
||||
|
@ -352,6 +353,7 @@ struct ieee80211_bss_conf {
|
|||
u32 sync_device_ts;
|
||||
u8 sync_dtim_count;
|
||||
u32 basic_rates;
|
||||
struct ieee80211_rate *beacon_rate;
|
||||
int mcast_rate[IEEE80211_NUM_BANDS];
|
||||
u16 ht_operation_mode;
|
||||
s32 cqm_rssi_thold;
|
||||
|
|
|
@ -2758,6 +2758,8 @@ enum nl80211_channel_type {
|
|||
* and %NL80211_ATTR_CENTER_FREQ2 attributes must be provided as well
|
||||
* @NL80211_CHAN_WIDTH_160: 160 MHz channel, the %NL80211_ATTR_CENTER_FREQ1
|
||||
* attribute must be provided as well
|
||||
* @NL80211_CHAN_WIDTH_5: 5 MHz OFDM channel
|
||||
* @NL80211_CHAN_WIDTH_10: 10 MHz OFDM channel
|
||||
*/
|
||||
enum nl80211_chan_width {
|
||||
NL80211_CHAN_WIDTH_20_NOHT,
|
||||
|
@ -2766,6 +2768,8 @@ enum nl80211_chan_width {
|
|||
NL80211_CHAN_WIDTH_80,
|
||||
NL80211_CHAN_WIDTH_80P80,
|
||||
NL80211_CHAN_WIDTH_160,
|
||||
NL80211_CHAN_WIDTH_5,
|
||||
NL80211_CHAN_WIDTH_10,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -2827,7 +2827,8 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
|||
!rcu_access_pointer(sdata->bss->beacon))
|
||||
need_offchan = true;
|
||||
if (!ieee80211_is_action(mgmt->frame_control) ||
|
||||
mgmt->u.action.category == WLAN_CATEGORY_PUBLIC)
|
||||
mgmt->u.action.category == WLAN_CATEGORY_PUBLIC ||
|
||||
mgmt->u.action.category == WLAN_CATEGORY_SELF_PROTECTED)
|
||||
break;
|
||||
rcu_read_lock();
|
||||
sta = sta_info_get(sdata, mgmt->da);
|
||||
|
@ -2930,19 +2931,8 @@ static void ieee80211_mgmt_frame_register(struct wiphy *wiphy,
|
|||
u16 frame_type, bool reg)
|
||||
{
|
||||
struct ieee80211_local *local = wiphy_priv(wiphy);
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
|
||||
|
||||
switch (frame_type) {
|
||||
case IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH:
|
||||
if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
|
||||
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
|
||||
|
||||
if (reg)
|
||||
ifibss->auth_frame_registrations++;
|
||||
else
|
||||
ifibss->auth_frame_registrations--;
|
||||
}
|
||||
break;
|
||||
case IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ:
|
||||
if (reg)
|
||||
local->probe_req_reg++;
|
||||
|
|
|
@ -281,13 +281,14 @@ void ieee80211_ba_session_work(struct work_struct *work)
|
|||
sta, tid, WLAN_BACK_RECIPIENT,
|
||||
WLAN_REASON_UNSPECIFIED, true);
|
||||
|
||||
spin_lock_bh(&sta->lock);
|
||||
|
||||
tid_tx = sta->ampdu_mlme.tid_start_tx[tid];
|
||||
if (tid_tx) {
|
||||
/*
|
||||
* Assign it over to the normal tid_tx array
|
||||
* where it "goes live".
|
||||
*/
|
||||
spin_lock_bh(&sta->lock);
|
||||
|
||||
sta->ampdu_mlme.tid_start_tx[tid] = NULL;
|
||||
/* could there be a race? */
|
||||
|
@ -300,6 +301,7 @@ void ieee80211_ba_session_work(struct work_struct *work)
|
|||
ieee80211_tx_ba_session_handle_start(sta, tid);
|
||||
continue;
|
||||
}
|
||||
spin_unlock_bh(&sta->lock);
|
||||
|
||||
tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
|
||||
if (tid_tx && test_and_clear_bit(HT_AGG_STATE_WANT_STOP,
|
||||
|
|
|
@ -81,7 +81,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0;
|
||||
|
||||
cfg80211_chandef_create(&chandef, chan, ifibss->channel_type);
|
||||
chandef = ifibss->chandef;
|
||||
if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef)) {
|
||||
chandef.width = NL80211_CHAN_WIDTH_20;
|
||||
chandef.center_freq1 = chan->center_freq;
|
||||
|
@ -176,6 +176,8 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
/* add HT capability and information IEs */
|
||||
if (chandef.width != NL80211_CHAN_WIDTH_20_NOHT &&
|
||||
chandef.width != NL80211_CHAN_WIDTH_5 &&
|
||||
chandef.width != NL80211_CHAN_WIDTH_10 &&
|
||||
sband->ht_cap.ht_supported) {
|
||||
pos = ieee80211_ie_build_ht_cap(pos, &sband->ht_cap,
|
||||
sband->ht_cap.cap);
|
||||
|
@ -298,8 +300,7 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
|
|||
tsf, false);
|
||||
}
|
||||
|
||||
static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta,
|
||||
bool auth)
|
||||
static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta)
|
||||
__acquires(RCU)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = sta->sdata;
|
||||
|
@ -321,20 +322,12 @@ static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta,
|
|||
/* If it fails, maybe we raced another insertion? */
|
||||
if (sta_info_insert_rcu(sta))
|
||||
return sta_info_get(sdata, addr);
|
||||
if (auth && !sdata->u.ibss.auth_frame_registrations) {
|
||||
ibss_dbg(sdata,
|
||||
"TX Auth SA=%pM DA=%pM BSSID=%pM (auth_transaction=1)\n",
|
||||
sdata->vif.addr, addr, sdata->u.ibss.bssid);
|
||||
ieee80211_send_auth(sdata, 1, WLAN_AUTH_OPEN, 0, NULL, 0,
|
||||
addr, sdata->u.ibss.bssid, NULL, 0, 0, 0);
|
||||
}
|
||||
return sta;
|
||||
}
|
||||
|
||||
static struct sta_info *
|
||||
ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
|
||||
const u8 *bssid, const u8 *addr,
|
||||
u32 supp_rates, bool auth)
|
||||
ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, const u8 *bssid,
|
||||
const u8 *addr, u32 supp_rates)
|
||||
__acquires(RCU)
|
||||
{
|
||||
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
|
||||
|
@ -385,7 +378,7 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
|
|||
sta->sta.supp_rates[band] = supp_rates |
|
||||
ieee80211_mandatory_rates(sband);
|
||||
|
||||
return ieee80211_ibss_finish_sta(sta, auth);
|
||||
return ieee80211_ibss_finish_sta(sta);
|
||||
}
|
||||
|
||||
static void ieee80211_rx_mgmt_deauth_ibss(struct ieee80211_sub_if_data *sdata,
|
||||
|
@ -407,8 +400,6 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata,
|
|||
size_t len)
|
||||
{
|
||||
u16 auth_alg, auth_transaction;
|
||||
struct sta_info *sta;
|
||||
u8 deauth_frame_buf[IEEE80211_DEAUTH_FRAME_LEN];
|
||||
|
||||
sdata_assert_lock(sdata);
|
||||
|
||||
|
@ -425,22 +416,6 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata,
|
|||
if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1)
|
||||
return;
|
||||
|
||||
sta_info_destroy_addr(sdata, mgmt->sa);
|
||||
sta = ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, 0, false);
|
||||
rcu_read_unlock();
|
||||
|
||||
/*
|
||||
* if we have any problem in allocating the new station, we reply with a
|
||||
* DEAUTH frame to tell the other end that we had a problem
|
||||
*/
|
||||
if (!sta) {
|
||||
ieee80211_send_deauth_disassoc(sdata, sdata->u.ibss.bssid,
|
||||
IEEE80211_STYPE_DEAUTH,
|
||||
WLAN_REASON_UNSPECIFIED, true,
|
||||
deauth_frame_buf);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* IEEE 802.11 standard does not require authentication in IBSS
|
||||
* networks and most implementations do not seem to use it.
|
||||
|
@ -506,7 +481,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
|
|||
} else {
|
||||
rcu_read_unlock();
|
||||
sta = ieee80211_ibss_add_sta(sdata, mgmt->bssid,
|
||||
mgmt->sa, supp_rates, true);
|
||||
mgmt->sa, supp_rates);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -514,7 +489,9 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
|
|||
set_sta_flag(sta, WLAN_STA_WME);
|
||||
|
||||
if (sta && elems->ht_operation && elems->ht_cap_elem &&
|
||||
sdata->u.ibss.channel_type != NL80211_CHAN_NO_HT) {
|
||||
sdata->u.ibss.chandef.width != NL80211_CHAN_WIDTH_20_NOHT &&
|
||||
sdata->u.ibss.chandef.width != NL80211_CHAN_WIDTH_5 &&
|
||||
sdata->u.ibss.chandef.width != NL80211_CHAN_WIDTH_10) {
|
||||
/* we both use HT */
|
||||
struct ieee80211_ht_cap htcap_ie;
|
||||
struct cfg80211_chan_def chandef;
|
||||
|
@ -529,8 +506,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
|
|||
* fall back to HT20 if we don't use or use
|
||||
* the other extension channel
|
||||
*/
|
||||
if (cfg80211_get_chandef_type(&chandef) !=
|
||||
sdata->u.ibss.channel_type)
|
||||
if (chandef.center_freq1 !=
|
||||
sdata->u.ibss.chandef.center_freq1)
|
||||
htcap_ie.cap_info &=
|
||||
cpu_to_le16(~IEEE80211_HT_CAP_SUP_WIDTH_20_40);
|
||||
|
||||
|
@ -569,7 +546,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
/* different channel */
|
||||
if (sdata->u.ibss.fixed_channel &&
|
||||
sdata->u.ibss.channel != cbss->channel)
|
||||
sdata->u.ibss.chandef.chan != cbss->channel)
|
||||
goto put_bss;
|
||||
|
||||
/* different SSID */
|
||||
|
@ -610,7 +587,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
|
|||
ieee80211_sta_join_ibss(sdata, bss);
|
||||
supp_rates = ieee80211_sta_get_rates(local, elems, band, NULL);
|
||||
ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa,
|
||||
supp_rates, true);
|
||||
supp_rates);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
|
@ -759,7 +736,7 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)
|
|||
sdata->drop_unencrypted = 0;
|
||||
|
||||
__ieee80211_sta_join_ibss(sdata, bssid, sdata->vif.bss_conf.beacon_int,
|
||||
ifibss->channel, ifibss->basic_rates,
|
||||
ifibss->chandef.chan, ifibss->basic_rates,
|
||||
capability, 0, true);
|
||||
}
|
||||
|
||||
|
@ -791,7 +768,7 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
|
|||
if (ifibss->fixed_bssid)
|
||||
bssid = ifibss->bssid;
|
||||
if (ifibss->fixed_channel)
|
||||
chan = ifibss->channel;
|
||||
chan = ifibss->chandef.chan;
|
||||
if (!is_zero_ether_addr(ifibss->bssid))
|
||||
bssid = ifibss->bssid;
|
||||
cbss = cfg80211_get_bss(local->hw.wiphy, chan, bssid,
|
||||
|
@ -982,7 +959,7 @@ void ieee80211_ibss_work(struct ieee80211_sub_if_data *sdata)
|
|||
list_del(&sta->list);
|
||||
spin_unlock_bh(&ifibss->incomplete_lock);
|
||||
|
||||
ieee80211_ibss_finish_sta(sta, true);
|
||||
ieee80211_ibss_finish_sta(sta);
|
||||
rcu_read_unlock();
|
||||
spin_lock_bh(&ifibss->incomplete_lock);
|
||||
}
|
||||
|
@ -1058,9 +1035,7 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
sdata->vif.bss_conf.beacon_int = params->beacon_interval;
|
||||
|
||||
sdata->u.ibss.channel = params->chandef.chan;
|
||||
sdata->u.ibss.channel_type =
|
||||
cfg80211_get_chandef_type(¶ms->chandef);
|
||||
sdata->u.ibss.chandef = params->chandef;
|
||||
sdata->u.ibss.fixed_channel = params->channel_fixed;
|
||||
|
||||
if (params->ie) {
|
||||
|
@ -1119,7 +1094,7 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata)
|
|||
if (ifibss->privacy)
|
||||
capability |= WLAN_CAPABILITY_PRIVACY;
|
||||
|
||||
cbss = cfg80211_get_bss(local->hw.wiphy, ifibss->channel,
|
||||
cbss = cfg80211_get_bss(local->hw.wiphy, ifibss->chandef.chan,
|
||||
ifibss->bssid, ifibss->ssid,
|
||||
ifibss->ssid_len, WLAN_CAPABILITY_IBSS |
|
||||
WLAN_CAPABILITY_PRIVACY,
|
||||
|
|
|
@ -94,6 +94,7 @@ struct ieee80211_bss {
|
|||
#define IEEE80211_MAX_SUPP_RATES 32
|
||||
u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
|
||||
size_t supp_rates_len;
|
||||
struct ieee80211_rate *beacon_rate;
|
||||
|
||||
/*
|
||||
* During association, we save an ERP value from a probe response so
|
||||
|
@ -497,14 +498,12 @@ struct ieee80211_if_ibss {
|
|||
bool privacy;
|
||||
|
||||
bool control_port;
|
||||
unsigned int auth_frame_registrations;
|
||||
|
||||
u8 bssid[ETH_ALEN] __aligned(2);
|
||||
u8 ssid[IEEE80211_MAX_SSID_LEN];
|
||||
u8 ssid_len, ie_len;
|
||||
u8 *ie;
|
||||
struct ieee80211_channel *channel;
|
||||
enum nl80211_channel_type channel_type;
|
||||
struct cfg80211_chan_def chandef;
|
||||
|
||||
unsigned long ibss_join_req;
|
||||
/* probe response/beacon for IBSS */
|
||||
|
@ -543,6 +542,7 @@ struct ieee80211_if_mesh {
|
|||
struct timer_list mesh_path_root_timer;
|
||||
|
||||
unsigned long wrkq_flags;
|
||||
unsigned long mbss_changed;
|
||||
|
||||
u8 mesh_id[IEEE80211_MAX_MESH_ID_LEN];
|
||||
size_t mesh_id_len;
|
||||
|
|
|
@ -161,11 +161,8 @@ void mesh_sta_cleanup(struct sta_info *sta)
|
|||
del_timer_sync(&sta->plink_timer);
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
sdata_lock(sdata);
|
||||
if (changed)
|
||||
ieee80211_mbss_info_change_notify(sdata, changed);
|
||||
sdata_unlock(sdata);
|
||||
}
|
||||
}
|
||||
|
||||
int mesh_rmc_init(struct ieee80211_sub_if_data *sdata)
|
||||
|
@ -419,7 +416,9 @@ int mesh_add_ht_cap_ie(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
sband = local->hw.wiphy->bands[band];
|
||||
if (!sband->ht_cap.ht_supported ||
|
||||
sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT)
|
||||
sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT ||
|
||||
sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_5 ||
|
||||
sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_10)
|
||||
return 0;
|
||||
|
||||
if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_ht_cap))
|
||||
|
@ -719,14 +718,18 @@ ieee80211_mesh_rebuild_beacon(struct ieee80211_sub_if_data *sdata)
|
|||
void ieee80211_mbss_info_change_notify(struct ieee80211_sub_if_data *sdata,
|
||||
u32 changed)
|
||||
{
|
||||
if (sdata->vif.bss_conf.enable_beacon &&
|
||||
(changed & (BSS_CHANGED_BEACON |
|
||||
BSS_CHANGED_HT |
|
||||
BSS_CHANGED_BASIC_RATES |
|
||||
BSS_CHANGED_BEACON_INT)))
|
||||
if (ieee80211_mesh_rebuild_beacon(sdata))
|
||||
return;
|
||||
ieee80211_bss_info_change_notify(sdata, changed);
|
||||
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
|
||||
unsigned long bits = changed;
|
||||
u32 bit;
|
||||
|
||||
if (!bits)
|
||||
return;
|
||||
|
||||
/* if we race with running work, worst case this work becomes a noop */
|
||||
for_each_set_bit(bit, &bits, sizeof(changed) * BITS_PER_BYTE)
|
||||
set_bit(bit, &ifmsh->mbss_changed);
|
||||
set_bit(MESH_WORK_MBSS_CHANGED, &ifmsh->wrkq_flags);
|
||||
ieee80211_queue_work(&sdata->local->hw, &sdata->work);
|
||||
}
|
||||
|
||||
int ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
|
||||
|
@ -799,6 +802,10 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
|
|||
del_timer_sync(&sdata->u.mesh.mesh_path_root_timer);
|
||||
del_timer_sync(&sdata->u.mesh.mesh_path_timer);
|
||||
|
||||
/* clear any mesh work (for next join) we may have accrued */
|
||||
ifmsh->wrkq_flags = 0;
|
||||
ifmsh->mbss_changed = 0;
|
||||
|
||||
local->fif_other_bss--;
|
||||
atomic_dec(&local->iff_allmultis);
|
||||
ieee80211_configure_filter(local);
|
||||
|
@ -965,6 +972,28 @@ out:
|
|||
sdata_unlock(sdata);
|
||||
}
|
||||
|
||||
static void mesh_bss_info_changed(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
|
||||
u32 bit, changed = 0;
|
||||
|
||||
for_each_set_bit(bit, &ifmsh->mbss_changed,
|
||||
sizeof(changed) * BITS_PER_BYTE) {
|
||||
clear_bit(bit, &ifmsh->mbss_changed);
|
||||
changed |= BIT(bit);
|
||||
}
|
||||
|
||||
if (sdata->vif.bss_conf.enable_beacon &&
|
||||
(changed & (BSS_CHANGED_BEACON |
|
||||
BSS_CHANGED_HT |
|
||||
BSS_CHANGED_BASIC_RATES |
|
||||
BSS_CHANGED_BEACON_INT)))
|
||||
if (ieee80211_mesh_rebuild_beacon(sdata))
|
||||
return;
|
||||
|
||||
ieee80211_bss_info_change_notify(sdata, changed);
|
||||
}
|
||||
|
||||
void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
|
||||
|
@ -995,6 +1024,8 @@ void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata)
|
|||
if (test_and_clear_bit(MESH_WORK_DRIFT_ADJUST, &ifmsh->wrkq_flags))
|
||||
mesh_sync_adjust_tbtt(sdata);
|
||||
|
||||
if (test_and_clear_bit(MESH_WORK_MBSS_CHANGED, &ifmsh->wrkq_flags))
|
||||
mesh_bss_info_changed(sdata);
|
||||
out:
|
||||
sdata_unlock(sdata);
|
||||
}
|
||||
|
|
|
@ -58,6 +58,7 @@ enum mesh_path_flags {
|
|||
* @MESH_WORK_ROOT: the mesh root station needs to send a frame
|
||||
* @MESH_WORK_DRIFT_ADJUST: time to compensate for clock drift relative to other
|
||||
* mesh nodes
|
||||
* @MESH_WORK_MBSS_CHANGED: rebuild beacon and notify driver of BSS changes
|
||||
*/
|
||||
enum mesh_deferred_task_flags {
|
||||
MESH_WORK_HOUSEKEEPING,
|
||||
|
@ -65,6 +66,7 @@ enum mesh_deferred_task_flags {
|
|||
MESH_WORK_GROW_MPP_TABLE,
|
||||
MESH_WORK_ROOT,
|
||||
MESH_WORK_DRIFT_ADJUST,
|
||||
MESH_WORK_MBSS_CHANGED,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -154,8 +154,14 @@ static u32 mesh_set_ht_prot_mode(struct ieee80211_sub_if_data *sdata)
|
|||
u16 ht_opmode;
|
||||
bool non_ht_sta = false, ht20_sta = false;
|
||||
|
||||
if (sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT)
|
||||
switch (sdata->vif.bss_conf.chandef.width) {
|
||||
case NL80211_CHAN_WIDTH_20_NOHT:
|
||||
case NL80211_CHAN_WIDTH_5:
|
||||
case NL80211_CHAN_WIDTH_10:
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(sta, &local->sta_list, list) {
|
||||
|
|
|
@ -190,6 +190,12 @@ static u32 chandef_downgrade(struct cfg80211_chan_def *c)
|
|||
c->width = NL80211_CHAN_WIDTH_20_NOHT;
|
||||
ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT;
|
||||
break;
|
||||
case NL80211_CHAN_WIDTH_5:
|
||||
case NL80211_CHAN_WIDTH_10:
|
||||
WARN_ON_ONCE(1);
|
||||
/* keep c->width */
|
||||
ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT;
|
||||
break;
|
||||
}
|
||||
|
||||
WARN_ON_ONCE(!cfg80211_chandef_valid(c));
|
||||
|
@ -1779,8 +1785,10 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
|
|||
* probably just won't work at all.
|
||||
*/
|
||||
bss_conf->dtim_period = sdata->u.mgd.dtim_period ?: 1;
|
||||
bss_conf->beacon_rate = bss->beacon_rate;
|
||||
bss_info_changed |= BSS_CHANGED_BEACON_INFO;
|
||||
} else {
|
||||
bss_conf->beacon_rate = NULL;
|
||||
bss_conf->dtim_period = 0;
|
||||
}
|
||||
|
||||
|
@ -1903,6 +1911,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
|
|||
del_timer_sync(&sdata->u.mgd.chswitch_timer);
|
||||
|
||||
sdata->vif.bss_conf.dtim_period = 0;
|
||||
sdata->vif.bss_conf.beacon_rate = NULL;
|
||||
|
||||
ifmgd->have_beacon = false;
|
||||
|
||||
ifmgd->flags = 0;
|
||||
|
@ -2785,8 +2795,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
|
|||
if (!ieee80211_assoc_success(sdata, bss, mgmt, len)) {
|
||||
/* oops -- internal error -- send timeout for now */
|
||||
ieee80211_destroy_assoc_data(sdata, false);
|
||||
cfg80211_put_bss(sdata->local->hw.wiphy, bss);
|
||||
cfg80211_assoc_timeout(sdata->dev, mgmt->bssid);
|
||||
cfg80211_assoc_timeout(sdata->dev, bss);
|
||||
return;
|
||||
}
|
||||
sdata_info(sdata, "associated\n");
|
||||
|
@ -2827,8 +2836,10 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems,
|
||||
channel);
|
||||
if (bss)
|
||||
if (bss) {
|
||||
ieee80211_rx_bss_put(local, bss);
|
||||
sdata->vif.bss_conf.beacon_rate = bss->beacon_rate;
|
||||
}
|
||||
|
||||
if (!sdata->u.mgd.associated ||
|
||||
!ether_addr_equal(mgmt->bssid, sdata->u.mgd.associated->bssid))
|
||||
|
@ -3501,13 +3512,10 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
|
|||
time_after(jiffies, ifmgd->assoc_data->timeout)) {
|
||||
if ((ifmgd->assoc_data->need_beacon && !ifmgd->have_beacon) ||
|
||||
ieee80211_do_assoc(sdata)) {
|
||||
u8 bssid[ETH_ALEN];
|
||||
|
||||
memcpy(bssid, ifmgd->assoc_data->bss->bssid, ETH_ALEN);
|
||||
struct cfg80211_bss *bss = ifmgd->assoc_data->bss;
|
||||
|
||||
ieee80211_destroy_assoc_data(sdata, false);
|
||||
|
||||
cfg80211_assoc_timeout(sdata->dev, bssid);
|
||||
cfg80211_assoc_timeout(sdata->dev, bss);
|
||||
}
|
||||
} else if (ifmgd->assoc_data && ifmgd->assoc_data->timeout_started)
|
||||
run_again(sdata, ifmgd->assoc_data->timeout);
|
||||
|
@ -3838,6 +3846,12 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
|
|||
*/
|
||||
ret = ieee80211_vif_use_channel(sdata, &chandef,
|
||||
IEEE80211_CHANCTX_SHARED);
|
||||
|
||||
/* don't downgrade for 5 and 10 MHz channels, though. */
|
||||
if (chandef.width == NL80211_CHAN_WIDTH_5 ||
|
||||
chandef.width == NL80211_CHAN_WIDTH_10)
|
||||
return ret;
|
||||
|
||||
while (ret && chandef.width != NL80211_CHAN_WIDTH_20_NOHT) {
|
||||
ifmgd->flags |= chandef_downgrade(&chandef);
|
||||
ret = ieee80211_vif_use_channel(sdata, &chandef,
|
||||
|
@ -4427,8 +4441,11 @@ void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata)
|
|||
cancel_work_sync(&ifmgd->chswitch_work);
|
||||
|
||||
sdata_lock(sdata);
|
||||
if (ifmgd->assoc_data)
|
||||
if (ifmgd->assoc_data) {
|
||||
struct cfg80211_bss *bss = ifmgd->assoc_data->bss;
|
||||
ieee80211_destroy_assoc_data(sdata, false);
|
||||
cfg80211_assoc_timeout(sdata->dev, bss);
|
||||
}
|
||||
if (ifmgd->auth_data)
|
||||
ieee80211_destroy_auth_data(sdata, false);
|
||||
del_timer_sync(&ifmgd->timer);
|
||||
|
|
|
@ -397,8 +397,14 @@ static void rate_idx_match_mask(struct ieee80211_tx_rate *rate,
|
|||
return;
|
||||
|
||||
/* if HT BSS, and we handle a data frame, also try HT rates */
|
||||
if (chan_width == NL80211_CHAN_WIDTH_20_NOHT)
|
||||
switch (chan_width) {
|
||||
case NL80211_CHAN_WIDTH_20_NOHT:
|
||||
case NL80211_CHAN_WIDTH_5:
|
||||
case NL80211_CHAN_WIDTH_10:
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
alt_rate.idx = 0;
|
||||
/* keep protection flags */
|
||||
|
|
|
@ -140,6 +140,15 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
|
|||
bss->valid_data |= IEEE80211_BSS_VALID_WMM;
|
||||
}
|
||||
|
||||
if (beacon) {
|
||||
struct ieee80211_supported_band *sband =
|
||||
local->hw.wiphy->bands[rx_status->band];
|
||||
if (!(rx_status->flag & RX_FLAG_HT) &&
|
||||
!(rx_status->flag & RX_FLAG_VHT))
|
||||
bss->beacon_rate =
|
||||
&sband->bitrates[rx_status->rate_idx];
|
||||
}
|
||||
|
||||
return bss;
|
||||
}
|
||||
|
||||
|
|
|
@ -149,6 +149,7 @@ static void cleanup_single_sta(struct sta_info *sta)
|
|||
* directly by station destruction.
|
||||
*/
|
||||
for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
|
||||
kfree(sta->ampdu_mlme.tid_start_tx[i]);
|
||||
tid_tx = rcu_dereference_raw(sta->ampdu_mlme.tid_tx[i]);
|
||||
if (!tid_tx)
|
||||
continue;
|
||||
|
@ -346,6 +347,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
|
|||
if (ieee80211_vif_is_mesh(&sdata->vif) &&
|
||||
!sdata->u.mesh.user_mpm)
|
||||
init_timer(&sta->plink_timer);
|
||||
sta->nonpeer_pm = NL80211_MESH_POWER_ACTIVE;
|
||||
#endif
|
||||
|
||||
memcpy(sta->sta.addr, addr, ETH_ALEN);
|
||||
|
|
|
@ -203,6 +203,7 @@ struct tid_ampdu_rx {
|
|||
* driver requested to close until the work for it runs
|
||||
* @mtx: mutex to protect all TX data (except non-NULL assignments
|
||||
* to tid_tx[idx], which are protected by the sta spinlock)
|
||||
* tid_start_tx is also protected by sta->lock.
|
||||
*/
|
||||
struct sta_ampdu_mlme {
|
||||
struct mutex mtx;
|
||||
|
|
|
@ -396,7 +396,7 @@ void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
|
|||
new_bw = ieee80211_sta_cur_vht_bw(sta);
|
||||
if (new_bw != sta->sta.bandwidth) {
|
||||
sta->sta.bandwidth = new_bw;
|
||||
changed |= IEEE80211_RC_NSS_CHANGED;
|
||||
changed |= IEEE80211_RC_BW_CHANGED;
|
||||
}
|
||||
|
||||
change:
|
||||
|
|
|
@ -54,6 +54,8 @@ bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef)
|
|||
control_freq = chandef->chan->center_freq;
|
||||
|
||||
switch (chandef->width) {
|
||||
case NL80211_CHAN_WIDTH_5:
|
||||
case NL80211_CHAN_WIDTH_10:
|
||||
case NL80211_CHAN_WIDTH_20:
|
||||
case NL80211_CHAN_WIDTH_20_NOHT:
|
||||
if (chandef->center_freq1 != control_freq)
|
||||
|
@ -152,6 +154,12 @@ static int cfg80211_chandef_get_width(const struct cfg80211_chan_def *c)
|
|||
int width;
|
||||
|
||||
switch (c->width) {
|
||||
case NL80211_CHAN_WIDTH_5:
|
||||
width = 5;
|
||||
break;
|
||||
case NL80211_CHAN_WIDTH_10:
|
||||
width = 10;
|
||||
break;
|
||||
case NL80211_CHAN_WIDTH_20:
|
||||
case NL80211_CHAN_WIDTH_20_NOHT:
|
||||
width = 20;
|
||||
|
@ -194,6 +202,16 @@ cfg80211_chandef_compatible(const struct cfg80211_chan_def *c1,
|
|||
if (c1->width == c2->width)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* can't be compatible if one of them is 5 or 10 MHz,
|
||||
* but they don't have the same width.
|
||||
*/
|
||||
if (c1->width == NL80211_CHAN_WIDTH_5 ||
|
||||
c1->width == NL80211_CHAN_WIDTH_10 ||
|
||||
c2->width == NL80211_CHAN_WIDTH_5 ||
|
||||
c2->width == NL80211_CHAN_WIDTH_10)
|
||||
return NULL;
|
||||
|
||||
if (c1->width == NL80211_CHAN_WIDTH_20_NOHT ||
|
||||
c1->width == NL80211_CHAN_WIDTH_20)
|
||||
return c2;
|
||||
|
@ -264,11 +282,17 @@ static int cfg80211_get_chans_dfs_required(struct wiphy *wiphy,
|
|||
u32 bandwidth)
|
||||
{
|
||||
struct ieee80211_channel *c;
|
||||
u32 freq;
|
||||
u32 freq, start_freq, end_freq;
|
||||
|
||||
for (freq = center_freq - bandwidth/2 + 10;
|
||||
freq <= center_freq + bandwidth/2 - 10;
|
||||
freq += 20) {
|
||||
if (bandwidth <= 20) {
|
||||
start_freq = center_freq;
|
||||
end_freq = center_freq;
|
||||
} else {
|
||||
start_freq = center_freq - bandwidth/2 + 10;
|
||||
end_freq = center_freq + bandwidth/2 - 10;
|
||||
}
|
||||
|
||||
for (freq = start_freq; freq <= end_freq; freq += 20) {
|
||||
c = ieee80211_get_channel(wiphy, freq);
|
||||
if (!c)
|
||||
return -EINVAL;
|
||||
|
@ -310,11 +334,17 @@ static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
|
|||
u32 prohibited_flags)
|
||||
{
|
||||
struct ieee80211_channel *c;
|
||||
u32 freq;
|
||||
u32 freq, start_freq, end_freq;
|
||||
|
||||
for (freq = center_freq - bandwidth/2 + 10;
|
||||
freq <= center_freq + bandwidth/2 - 10;
|
||||
freq += 20) {
|
||||
if (bandwidth <= 20) {
|
||||
start_freq = center_freq;
|
||||
end_freq = center_freq;
|
||||
} else {
|
||||
start_freq = center_freq - bandwidth/2 + 10;
|
||||
end_freq = center_freq + bandwidth/2 - 10;
|
||||
}
|
||||
|
||||
for (freq = start_freq; freq <= end_freq; freq += 20) {
|
||||
c = ieee80211_get_channel(wiphy, freq);
|
||||
if (!c)
|
||||
return false;
|
||||
|
@ -349,6 +379,12 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy,
|
|||
control_freq = chandef->chan->center_freq;
|
||||
|
||||
switch (chandef->width) {
|
||||
case NL80211_CHAN_WIDTH_5:
|
||||
width = 5;
|
||||
break;
|
||||
case NL80211_CHAN_WIDTH_10:
|
||||
width = 10;
|
||||
break;
|
||||
case NL80211_CHAN_WIDTH_20:
|
||||
if (!ht_cap->ht_supported)
|
||||
return false;
|
||||
|
@ -405,6 +441,11 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy,
|
|||
if (width > 20)
|
||||
prohibited_flags |= IEEE80211_CHAN_NO_OFDM;
|
||||
|
||||
/* 5 and 10 MHz are only defined for the OFDM PHY */
|
||||
if (width < 20)
|
||||
prohibited_flags |= IEEE80211_CHAN_NO_OFDM;
|
||||
|
||||
|
||||
if (!cfg80211_secondary_chans_ok(wiphy, chandef->center_freq1,
|
||||
width, prohibited_flags))
|
||||
return false;
|
||||
|
|
|
@ -934,6 +934,12 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
|
|||
* freed.
|
||||
*/
|
||||
cfg80211_process_wdev_events(wdev);
|
||||
|
||||
if (WARN_ON(wdev->current_bss)) {
|
||||
cfg80211_unhold_bss(wdev->current_bss);
|
||||
cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub);
|
||||
wdev->current_bss = NULL;
|
||||
}
|
||||
break;
|
||||
case NETDEV_PRE_UP:
|
||||
if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype)))
|
||||
|
|
|
@ -38,6 +38,7 @@ void cfg80211_rx_assoc_resp(struct net_device *dev, struct cfg80211_bss *bss,
|
|||
* frame instead of reassoc.
|
||||
*/
|
||||
if (cfg80211_sme_rx_assoc_resp(wdev, status_code)) {
|
||||
cfg80211_unhold_bss(bss_from_pub(bss));
|
||||
cfg80211_put_bss(wiphy, bss);
|
||||
return;
|
||||
}
|
||||
|
@ -131,16 +132,19 @@ void cfg80211_auth_timeout(struct net_device *dev, const u8 *addr)
|
|||
}
|
||||
EXPORT_SYMBOL(cfg80211_auth_timeout);
|
||||
|
||||
void cfg80211_assoc_timeout(struct net_device *dev, const u8 *addr)
|
||||
void cfg80211_assoc_timeout(struct net_device *dev, struct cfg80211_bss *bss)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct wiphy *wiphy = wdev->wiphy;
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
|
||||
|
||||
trace_cfg80211_send_assoc_timeout(dev, addr);
|
||||
trace_cfg80211_send_assoc_timeout(dev, bss->bssid);
|
||||
|
||||
nl80211_send_assoc_timeout(rdev, dev, addr, GFP_KERNEL);
|
||||
nl80211_send_assoc_timeout(rdev, dev, bss->bssid, GFP_KERNEL);
|
||||
cfg80211_sme_assoc_timeout(wdev);
|
||||
|
||||
cfg80211_unhold_bss(bss_from_pub(bss));
|
||||
cfg80211_put_bss(wiphy, bss);
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_assoc_timeout);
|
||||
|
||||
|
@ -307,6 +311,8 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
|
|||
goto out;
|
||||
|
||||
err = rdev_assoc(rdev, dev, req);
|
||||
if (!err)
|
||||
cfg80211_hold_bss(bss_from_pub(req->bss));
|
||||
|
||||
out:
|
||||
if (err)
|
||||
|
|
|
@ -1111,10 +1111,16 @@ nl80211_send_mgmt_stypes(struct sk_buff *msg,
|
|||
return 0;
|
||||
}
|
||||
|
||||
struct nl80211_dump_wiphy_state {
|
||||
s64 filter_wiphy;
|
||||
long start;
|
||||
long split_start, band_start, chan_start;
|
||||
bool split;
|
||||
};
|
||||
|
||||
static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
|
||||
struct sk_buff *msg, u32 portid, u32 seq,
|
||||
int flags, bool split, long *split_start,
|
||||
long *band_start, long *chan_start)
|
||||
int flags, struct nl80211_dump_wiphy_state *state)
|
||||
{
|
||||
void *hdr;
|
||||
struct nlattr *nl_bands, *nl_band;
|
||||
|
@ -1125,19 +1131,14 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
|
|||
int i;
|
||||
const struct ieee80211_txrx_stypes *mgmt_stypes =
|
||||
dev->wiphy.mgmt_stypes;
|
||||
long start = 0, start_chan = 0, start_band = 0;
|
||||
u32 features;
|
||||
|
||||
hdr = nl80211hdr_put(msg, portid, seq, flags, NL80211_CMD_NEW_WIPHY);
|
||||
if (!hdr)
|
||||
return -ENOBUFS;
|
||||
|
||||
/* allow always using the variables */
|
||||
if (!split) {
|
||||
split_start = &start;
|
||||
band_start = &start_band;
|
||||
chan_start = &start_chan;
|
||||
}
|
||||
if (WARN_ON(!state))
|
||||
return -EINVAL;
|
||||
|
||||
if (nla_put_u32(msg, NL80211_ATTR_WIPHY, dev->wiphy_idx) ||
|
||||
nla_put_string(msg, NL80211_ATTR_WIPHY_NAME,
|
||||
|
@ -1146,7 +1147,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
|
|||
cfg80211_rdev_list_generation))
|
||||
goto nla_put_failure;
|
||||
|
||||
switch (*split_start) {
|
||||
switch (state->split_start) {
|
||||
case 0:
|
||||
if (nla_put_u8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT,
|
||||
dev->wiphy.retry_short) ||
|
||||
|
@ -1188,9 +1189,12 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
|
|||
if ((dev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP) &&
|
||||
nla_put_flag(msg, NL80211_ATTR_TDLS_EXTERNAL_SETUP))
|
||||
goto nla_put_failure;
|
||||
if ((dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_5_10_MHZ) &&
|
||||
nla_put_flag(msg, WIPHY_FLAG_SUPPORTS_5_10_MHZ))
|
||||
goto nla_put_failure;
|
||||
|
||||
(*split_start)++;
|
||||
if (split)
|
||||
state->split_start++;
|
||||
if (state->split)
|
||||
break;
|
||||
case 1:
|
||||
if (nla_put(msg, NL80211_ATTR_CIPHER_SUITES,
|
||||
|
@ -1234,22 +1238,23 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
|
|||
}
|
||||
}
|
||||
|
||||
(*split_start)++;
|
||||
if (split)
|
||||
state->split_start++;
|
||||
if (state->split)
|
||||
break;
|
||||
case 2:
|
||||
if (nl80211_put_iftypes(msg, NL80211_ATTR_SUPPORTED_IFTYPES,
|
||||
dev->wiphy.interface_modes))
|
||||
goto nla_put_failure;
|
||||
(*split_start)++;
|
||||
if (split)
|
||||
state->split_start++;
|
||||
if (state->split)
|
||||
break;
|
||||
case 3:
|
||||
nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS);
|
||||
if (!nl_bands)
|
||||
goto nla_put_failure;
|
||||
|
||||
for (band = *band_start; band < IEEE80211_NUM_BANDS; band++) {
|
||||
for (band = state->band_start;
|
||||
band < IEEE80211_NUM_BANDS; band++) {
|
||||
struct ieee80211_supported_band *sband;
|
||||
|
||||
sband = dev->wiphy.bands[band];
|
||||
|
@ -1261,12 +1266,12 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
|
|||
if (!nl_band)
|
||||
goto nla_put_failure;
|
||||
|
||||
switch (*chan_start) {
|
||||
switch (state->chan_start) {
|
||||
case 0:
|
||||
if (nl80211_send_band_rateinfo(msg, sband))
|
||||
goto nla_put_failure;
|
||||
(*chan_start)++;
|
||||
if (split)
|
||||
state->chan_start++;
|
||||
if (state->split)
|
||||
break;
|
||||
default:
|
||||
/* add frequencies */
|
||||
|
@ -1275,7 +1280,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
|
|||
if (!nl_freqs)
|
||||
goto nla_put_failure;
|
||||
|
||||
for (i = *chan_start - 1;
|
||||
for (i = state->chan_start - 1;
|
||||
i < sband->n_channels;
|
||||
i++) {
|
||||
nl_freq = nla_nest_start(msg, i);
|
||||
|
@ -1284,26 +1289,27 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
|
|||
|
||||
chan = &sband->channels[i];
|
||||
|
||||
if (nl80211_msg_put_channel(msg, chan,
|
||||
split))
|
||||
if (nl80211_msg_put_channel(
|
||||
msg, chan,
|
||||
state->split))
|
||||
goto nla_put_failure;
|
||||
|
||||
nla_nest_end(msg, nl_freq);
|
||||
if (split)
|
||||
if (state->split)
|
||||
break;
|
||||
}
|
||||
if (i < sband->n_channels)
|
||||
*chan_start = i + 2;
|
||||
state->chan_start = i + 2;
|
||||
else
|
||||
*chan_start = 0;
|
||||
state->chan_start = 0;
|
||||
nla_nest_end(msg, nl_freqs);
|
||||
}
|
||||
|
||||
nla_nest_end(msg, nl_band);
|
||||
|
||||
if (split) {
|
||||
if (state->split) {
|
||||
/* start again here */
|
||||
if (*chan_start)
|
||||
if (state->chan_start)
|
||||
band--;
|
||||
break;
|
||||
}
|
||||
|
@ -1311,14 +1317,14 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
|
|||
nla_nest_end(msg, nl_bands);
|
||||
|
||||
if (band < IEEE80211_NUM_BANDS)
|
||||
*band_start = band + 1;
|
||||
state->band_start = band + 1;
|
||||
else
|
||||
*band_start = 0;
|
||||
state->band_start = 0;
|
||||
|
||||
/* if bands & channels are done, continue outside */
|
||||
if (*band_start == 0 && *chan_start == 0)
|
||||
(*split_start)++;
|
||||
if (split)
|
||||
if (state->band_start == 0 && state->chan_start == 0)
|
||||
state->split_start++;
|
||||
if (state->split)
|
||||
break;
|
||||
case 4:
|
||||
nl_cmds = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_COMMANDS);
|
||||
|
@ -1384,7 +1390,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
|
|||
}
|
||||
CMD(start_p2p_device, START_P2P_DEVICE);
|
||||
CMD(set_mcast_rate, SET_MCAST_RATE);
|
||||
if (split) {
|
||||
if (state->split) {
|
||||
CMD(crit_proto_start, CRIT_PROTOCOL_START);
|
||||
CMD(crit_proto_stop, CRIT_PROTOCOL_STOP);
|
||||
}
|
||||
|
@ -1408,8 +1414,8 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
|
|||
}
|
||||
|
||||
nla_nest_end(msg, nl_cmds);
|
||||
(*split_start)++;
|
||||
if (split)
|
||||
state->split_start++;
|
||||
if (state->split)
|
||||
break;
|
||||
case 5:
|
||||
if (dev->ops->remain_on_channel &&
|
||||
|
@ -1425,29 +1431,30 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
|
|||
|
||||
if (nl80211_send_mgmt_stypes(msg, mgmt_stypes))
|
||||
goto nla_put_failure;
|
||||
(*split_start)++;
|
||||
if (split)
|
||||
state->split_start++;
|
||||
if (state->split)
|
||||
break;
|
||||
case 6:
|
||||
#ifdef CONFIG_PM
|
||||
if (nl80211_send_wowlan(msg, dev, split))
|
||||
if (nl80211_send_wowlan(msg, dev, state->split))
|
||||
goto nla_put_failure;
|
||||
(*split_start)++;
|
||||
if (split)
|
||||
state->split_start++;
|
||||
if (state->split)
|
||||
break;
|
||||
#else
|
||||
(*split_start)++;
|
||||
state->split_start++;
|
||||
#endif
|
||||
case 7:
|
||||
if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES,
|
||||
dev->wiphy.software_iftypes))
|
||||
goto nla_put_failure;
|
||||
|
||||
if (nl80211_put_iface_combinations(&dev->wiphy, msg, split))
|
||||
if (nl80211_put_iface_combinations(&dev->wiphy, msg,
|
||||
state->split))
|
||||
goto nla_put_failure;
|
||||
|
||||
(*split_start)++;
|
||||
if (split)
|
||||
state->split_start++;
|
||||
if (state->split)
|
||||
break;
|
||||
case 8:
|
||||
if ((dev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME) &&
|
||||
|
@ -1461,7 +1468,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
|
|||
* dump is split, otherwise it makes it too big. Therefore
|
||||
* only advertise it in that case.
|
||||
*/
|
||||
if (split)
|
||||
if (state->split)
|
||||
features |= NL80211_FEATURE_ADVERTISE_CHAN_LIMITS;
|
||||
if (nla_put_u32(msg, NL80211_ATTR_FEATURE_FLAGS, features))
|
||||
goto nla_put_failure;
|
||||
|
@ -1488,7 +1495,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
|
|||
* case we'll continue with more data in the next round,
|
||||
* but break unconditionally so unsplit data stops here.
|
||||
*/
|
||||
(*split_start)++;
|
||||
state->split_start++;
|
||||
break;
|
||||
case 9:
|
||||
if (dev->wiphy.extended_capabilities &&
|
||||
|
@ -1507,7 +1514,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
|
|||
goto nla_put_failure;
|
||||
|
||||
/* done */
|
||||
*split_start = 0;
|
||||
state->split_start = 0;
|
||||
break;
|
||||
}
|
||||
return genlmsg_end(msg, hdr);
|
||||
|
@ -1517,59 +1524,76 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
|
|||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
static int nl80211_dump_wiphy_parse(struct sk_buff *skb,
|
||||
struct netlink_callback *cb,
|
||||
struct nl80211_dump_wiphy_state *state)
|
||||
{
|
||||
struct nlattr **tb = nl80211_fam.attrbuf;
|
||||
int ret = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
|
||||
tb, nl80211_fam.maxattr, nl80211_policy);
|
||||
/* ignore parse errors for backward compatibility */
|
||||
if (ret)
|
||||
return 0;
|
||||
|
||||
state->split = tb[NL80211_ATTR_SPLIT_WIPHY_DUMP];
|
||||
if (tb[NL80211_ATTR_WIPHY])
|
||||
state->filter_wiphy = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
|
||||
if (tb[NL80211_ATTR_WDEV])
|
||||
state->filter_wiphy = nla_get_u64(tb[NL80211_ATTR_WDEV]) >> 32;
|
||||
if (tb[NL80211_ATTR_IFINDEX]) {
|
||||
struct net_device *netdev;
|
||||
struct cfg80211_registered_device *rdev;
|
||||
int ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
|
||||
|
||||
netdev = dev_get_by_index(sock_net(skb->sk), ifidx);
|
||||
if (!netdev)
|
||||
return -ENODEV;
|
||||
if (netdev->ieee80211_ptr) {
|
||||
rdev = wiphy_to_dev(
|
||||
netdev->ieee80211_ptr->wiphy);
|
||||
state->filter_wiphy = rdev->wiphy_idx;
|
||||
}
|
||||
dev_put(netdev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
{
|
||||
int idx = 0, ret;
|
||||
int start = cb->args[0];
|
||||
struct nl80211_dump_wiphy_state *state = (void *)cb->args[0];
|
||||
struct cfg80211_registered_device *dev;
|
||||
s64 filter_wiphy = -1;
|
||||
bool split = false;
|
||||
struct nlattr **tb = nl80211_fam.attrbuf;
|
||||
int res;
|
||||
|
||||
rtnl_lock();
|
||||
res = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
|
||||
tb, nl80211_fam.maxattr, nl80211_policy);
|
||||
if (res == 0) {
|
||||
split = tb[NL80211_ATTR_SPLIT_WIPHY_DUMP];
|
||||
if (tb[NL80211_ATTR_WIPHY])
|
||||
filter_wiphy = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
|
||||
if (tb[NL80211_ATTR_WDEV])
|
||||
filter_wiphy = nla_get_u64(tb[NL80211_ATTR_WDEV]) >> 32;
|
||||
if (tb[NL80211_ATTR_IFINDEX]) {
|
||||
struct net_device *netdev;
|
||||
int ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
|
||||
|
||||
netdev = dev_get_by_index(sock_net(skb->sk), ifidx);
|
||||
if (!netdev) {
|
||||
rtnl_unlock();
|
||||
return -ENODEV;
|
||||
}
|
||||
if (netdev->ieee80211_ptr) {
|
||||
dev = wiphy_to_dev(
|
||||
netdev->ieee80211_ptr->wiphy);
|
||||
filter_wiphy = dev->wiphy_idx;
|
||||
}
|
||||
dev_put(netdev);
|
||||
if (!state) {
|
||||
state = kzalloc(sizeof(*state), GFP_KERNEL);
|
||||
if (!state)
|
||||
return -ENOMEM;
|
||||
state->filter_wiphy = -1;
|
||||
ret = nl80211_dump_wiphy_parse(skb, cb, state);
|
||||
if (ret) {
|
||||
kfree(state);
|
||||
rtnl_unlock();
|
||||
return ret;
|
||||
}
|
||||
cb->args[0] = (long)state;
|
||||
}
|
||||
|
||||
list_for_each_entry(dev, &cfg80211_rdev_list, list) {
|
||||
if (!net_eq(wiphy_net(&dev->wiphy), sock_net(skb->sk)))
|
||||
continue;
|
||||
if (++idx <= start)
|
||||
if (++idx <= state->start)
|
||||
continue;
|
||||
if (filter_wiphy != -1 && dev->wiphy_idx != filter_wiphy)
|
||||
if (state->filter_wiphy != -1 &&
|
||||
state->filter_wiphy != dev->wiphy_idx)
|
||||
continue;
|
||||
/* attempt to fit multiple wiphy data chunks into the skb */
|
||||
do {
|
||||
ret = nl80211_send_wiphy(dev, skb,
|
||||
NETLINK_CB(cb->skb).portid,
|
||||
cb->nlh->nlmsg_seq,
|
||||
NLM_F_MULTI,
|
||||
split, &cb->args[1],
|
||||
&cb->args[2],
|
||||
&cb->args[3]);
|
||||
NLM_F_MULTI, state);
|
||||
if (ret < 0) {
|
||||
/*
|
||||
* If sending the wiphy data didn't fit (ENOBUFS
|
||||
|
@ -1594,27 +1618,34 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
|
|||
idx--;
|
||||
break;
|
||||
}
|
||||
} while (cb->args[1] > 0);
|
||||
} while (state->split_start > 0);
|
||||
break;
|
||||
}
|
||||
rtnl_unlock();
|
||||
|
||||
cb->args[0] = idx;
|
||||
state->start = idx;
|
||||
|
||||
return skb->len;
|
||||
}
|
||||
|
||||
static int nl80211_dump_wiphy_done(struct netlink_callback *cb)
|
||||
{
|
||||
kfree((void *)cb->args[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct sk_buff *msg;
|
||||
struct cfg80211_registered_device *dev = info->user_ptr[0];
|
||||
struct nl80211_dump_wiphy_state state = {};
|
||||
|
||||
msg = nlmsg_new(4096, GFP_KERNEL);
|
||||
if (!msg)
|
||||
return -ENOMEM;
|
||||
|
||||
if (nl80211_send_wiphy(dev, msg, info->snd_portid, info->snd_seq, 0,
|
||||
false, NULL, NULL, NULL) < 0) {
|
||||
&state) < 0) {
|
||||
nlmsg_free(msg);
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
@ -1731,6 +1762,11 @@ static int nl80211_parse_chandef(struct cfg80211_registered_device *rdev,
|
|||
IEEE80211_CHAN_DISABLED))
|
||||
return -EINVAL;
|
||||
|
||||
if ((chandef->width == NL80211_CHAN_WIDTH_5 ||
|
||||
chandef->width == NL80211_CHAN_WIDTH_10) &&
|
||||
!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_5_10_MHZ))
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2882,61 +2918,58 @@ static int nl80211_set_mac_acl(struct sk_buff *skb, struct genl_info *info)
|
|||
return err;
|
||||
}
|
||||
|
||||
static int nl80211_parse_beacon(struct genl_info *info,
|
||||
static int nl80211_parse_beacon(struct nlattr *attrs[],
|
||||
struct cfg80211_beacon_data *bcn)
|
||||
{
|
||||
bool haveinfo = false;
|
||||
|
||||
if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_BEACON_TAIL]) ||
|
||||
!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]) ||
|
||||
!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE_PROBE_RESP]) ||
|
||||
!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]))
|
||||
if (!is_valid_ie_attr(attrs[NL80211_ATTR_BEACON_TAIL]) ||
|
||||
!is_valid_ie_attr(attrs[NL80211_ATTR_IE]) ||
|
||||
!is_valid_ie_attr(attrs[NL80211_ATTR_IE_PROBE_RESP]) ||
|
||||
!is_valid_ie_attr(attrs[NL80211_ATTR_IE_ASSOC_RESP]))
|
||||
return -EINVAL;
|
||||
|
||||
memset(bcn, 0, sizeof(*bcn));
|
||||
|
||||
if (info->attrs[NL80211_ATTR_BEACON_HEAD]) {
|
||||
bcn->head = nla_data(info->attrs[NL80211_ATTR_BEACON_HEAD]);
|
||||
bcn->head_len = nla_len(info->attrs[NL80211_ATTR_BEACON_HEAD]);
|
||||
if (attrs[NL80211_ATTR_BEACON_HEAD]) {
|
||||
bcn->head = nla_data(attrs[NL80211_ATTR_BEACON_HEAD]);
|
||||
bcn->head_len = nla_len(attrs[NL80211_ATTR_BEACON_HEAD]);
|
||||
if (!bcn->head_len)
|
||||
return -EINVAL;
|
||||
haveinfo = true;
|
||||
}
|
||||
|
||||
if (info->attrs[NL80211_ATTR_BEACON_TAIL]) {
|
||||
bcn->tail = nla_data(info->attrs[NL80211_ATTR_BEACON_TAIL]);
|
||||
bcn->tail_len =
|
||||
nla_len(info->attrs[NL80211_ATTR_BEACON_TAIL]);
|
||||
if (attrs[NL80211_ATTR_BEACON_TAIL]) {
|
||||
bcn->tail = nla_data(attrs[NL80211_ATTR_BEACON_TAIL]);
|
||||
bcn->tail_len = nla_len(attrs[NL80211_ATTR_BEACON_TAIL]);
|
||||
haveinfo = true;
|
||||
}
|
||||
|
||||
if (!haveinfo)
|
||||
return -EINVAL;
|
||||
|
||||
if (info->attrs[NL80211_ATTR_IE]) {
|
||||
bcn->beacon_ies = nla_data(info->attrs[NL80211_ATTR_IE]);
|
||||
bcn->beacon_ies_len = nla_len(info->attrs[NL80211_ATTR_IE]);
|
||||
if (attrs[NL80211_ATTR_IE]) {
|
||||
bcn->beacon_ies = nla_data(attrs[NL80211_ATTR_IE]);
|
||||
bcn->beacon_ies_len = nla_len(attrs[NL80211_ATTR_IE]);
|
||||
}
|
||||
|
||||
if (info->attrs[NL80211_ATTR_IE_PROBE_RESP]) {
|
||||
if (attrs[NL80211_ATTR_IE_PROBE_RESP]) {
|
||||
bcn->proberesp_ies =
|
||||
nla_data(info->attrs[NL80211_ATTR_IE_PROBE_RESP]);
|
||||
nla_data(attrs[NL80211_ATTR_IE_PROBE_RESP]);
|
||||
bcn->proberesp_ies_len =
|
||||
nla_len(info->attrs[NL80211_ATTR_IE_PROBE_RESP]);
|
||||
nla_len(attrs[NL80211_ATTR_IE_PROBE_RESP]);
|
||||
}
|
||||
|
||||
if (info->attrs[NL80211_ATTR_IE_ASSOC_RESP]) {
|
||||
if (attrs[NL80211_ATTR_IE_ASSOC_RESP]) {
|
||||
bcn->assocresp_ies =
|
||||
nla_data(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]);
|
||||
nla_data(attrs[NL80211_ATTR_IE_ASSOC_RESP]);
|
||||
bcn->assocresp_ies_len =
|
||||
nla_len(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]);
|
||||
nla_len(attrs[NL80211_ATTR_IE_ASSOC_RESP]);
|
||||
}
|
||||
|
||||
if (info->attrs[NL80211_ATTR_PROBE_RESP]) {
|
||||
bcn->probe_resp =
|
||||
nla_data(info->attrs[NL80211_ATTR_PROBE_RESP]);
|
||||
bcn->probe_resp_len =
|
||||
nla_len(info->attrs[NL80211_ATTR_PROBE_RESP]);
|
||||
if (attrs[NL80211_ATTR_PROBE_RESP]) {
|
||||
bcn->probe_resp = nla_data(attrs[NL80211_ATTR_PROBE_RESP]);
|
||||
bcn->probe_resp_len = nla_len(attrs[NL80211_ATTR_PROBE_RESP]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -3015,7 +3048,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
|
|||
!info->attrs[NL80211_ATTR_BEACON_HEAD])
|
||||
return -EINVAL;
|
||||
|
||||
err = nl80211_parse_beacon(info, ¶ms.beacon);
|
||||
err = nl80211_parse_beacon(info->attrs, ¶ms.beacon);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
@ -3167,7 +3200,7 @@ static int nl80211_set_beacon(struct sk_buff *skb, struct genl_info *info)
|
|||
if (!wdev->beacon_interval)
|
||||
return -EINVAL;
|
||||
|
||||
err = nl80211_parse_beacon(info, ¶ms);
|
||||
err = nl80211_parse_beacon(info->attrs, ¶ms);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
@ -6283,11 +6316,16 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
|
|||
if (!cfg80211_reg_can_beacon(&rdev->wiphy, &ibss.chandef))
|
||||
return -EINVAL;
|
||||
|
||||
if (ibss.chandef.width > NL80211_CHAN_WIDTH_40)
|
||||
return -EINVAL;
|
||||
if (ibss.chandef.width != NL80211_CHAN_WIDTH_20_NOHT &&
|
||||
!(rdev->wiphy.features & NL80211_FEATURE_HT_IBSS))
|
||||
switch (ibss.chandef.width) {
|
||||
case NL80211_CHAN_WIDTH_20_NOHT:
|
||||
break;
|
||||
case NL80211_CHAN_WIDTH_20:
|
||||
case NL80211_CHAN_WIDTH_40:
|
||||
if (rdev->wiphy.features & NL80211_FEATURE_HT_IBSS)
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED];
|
||||
ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
|
||||
|
@ -8401,6 +8439,7 @@ static struct genl_ops nl80211_ops[] = {
|
|||
.cmd = NL80211_CMD_GET_WIPHY,
|
||||
.doit = nl80211_get_wiphy,
|
||||
.dumpit = nl80211_dump_wiphy,
|
||||
.done = nl80211_dump_wiphy_done,
|
||||
.policy = nl80211_policy,
|
||||
/* can be retrieved by unprivileged users */
|
||||
.internal_flags = NL80211_FLAG_NEED_WIPHY |
|
||||
|
@ -9021,13 +9060,13 @@ static struct genl_multicast_group nl80211_regulatory_mcgrp = {
|
|||
void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev)
|
||||
{
|
||||
struct sk_buff *msg;
|
||||
struct nl80211_dump_wiphy_state state = {};
|
||||
|
||||
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
||||
if (!msg)
|
||||
return;
|
||||
|
||||
if (nl80211_send_wiphy(rdev, msg, 0, 0, 0,
|
||||
false, NULL, NULL, NULL) < 0) {
|
||||
if (nl80211_send_wiphy(rdev, msg, 0, 0, 0, &state) < 0) {
|
||||
nlmsg_free(msg);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -523,6 +523,7 @@ static int cmp_bss(struct cfg80211_bss *a,
|
|||
}
|
||||
}
|
||||
|
||||
/* Returned bss is reference counted and must be cleaned up appropriately. */
|
||||
struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy,
|
||||
struct ieee80211_channel *channel,
|
||||
const u8 *bssid,
|
||||
|
@ -678,6 +679,7 @@ static bool cfg80211_combine_bsses(struct cfg80211_registered_device *dev,
|
|||
return true;
|
||||
}
|
||||
|
||||
/* Returned bss is reference counted and must be cleaned up appropriately. */
|
||||
static struct cfg80211_internal_bss *
|
||||
cfg80211_bss_update(struct cfg80211_registered_device *dev,
|
||||
struct cfg80211_internal_bss *tmp)
|
||||
|
@ -866,6 +868,7 @@ cfg80211_get_bss_channel(struct wiphy *wiphy, const u8 *ie, size_t ielen,
|
|||
return channel;
|
||||
}
|
||||
|
||||
/* Returned bss is reference counted and must be cleaned up appropriately. */
|
||||
struct cfg80211_bss*
|
||||
cfg80211_inform_bss(struct wiphy *wiphy,
|
||||
struct ieee80211_channel *channel,
|
||||
|
@ -923,6 +926,7 @@ cfg80211_inform_bss(struct wiphy *wiphy,
|
|||
}
|
||||
EXPORT_SYMBOL(cfg80211_inform_bss);
|
||||
|
||||
/* Returned bss is reference counted and must be cleaned up appropriately. */
|
||||
struct cfg80211_bss *
|
||||
cfg80211_inform_bss_frame(struct wiphy *wiphy,
|
||||
struct ieee80211_channel *channel,
|
||||
|
|
|
@ -239,6 +239,7 @@ void cfg80211_conn_work(struct work_struct *work)
|
|||
rtnl_unlock();
|
||||
}
|
||||
|
||||
/* Returned bss is reference counted and must be cleaned up appropriately. */
|
||||
static struct cfg80211_bss *cfg80211_get_conn_bss(struct wireless_dev *wdev)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
|
||||
|
@ -557,6 +558,7 @@ static DECLARE_WORK(cfg80211_disconnect_work, disconnect_work);
|
|||
* SME event handling
|
||||
*/
|
||||
|
||||
/* This method must consume bss one way or another */
|
||||
void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
|
||||
const u8 *req_ie, size_t req_ie_len,
|
||||
const u8 *resp_ie, size_t resp_ie_len,
|
||||
|
@ -572,8 +574,10 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
|
|||
ASSERT_WDEV_LOCK(wdev);
|
||||
|
||||
if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION &&
|
||||
wdev->iftype != NL80211_IFTYPE_P2P_CLIENT))
|
||||
wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)) {
|
||||
cfg80211_put_bss(wdev->wiphy, bss);
|
||||
return;
|
||||
}
|
||||
|
||||
nl80211_send_connect_result(wiphy_to_dev(wdev->wiphy), dev,
|
||||
bssid, req_ie, req_ie_len,
|
||||
|
@ -615,19 +619,24 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
|
|||
kfree(wdev->connect_keys);
|
||||
wdev->connect_keys = NULL;
|
||||
wdev->ssid_len = 0;
|
||||
cfg80211_put_bss(wdev->wiphy, bss);
|
||||
if (bss) {
|
||||
cfg80211_unhold_bss(bss_from_pub(bss));
|
||||
cfg80211_put_bss(wdev->wiphy, bss);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!bss)
|
||||
if (!bss) {
|
||||
WARN_ON_ONCE(!wiphy_to_dev(wdev->wiphy)->ops->connect);
|
||||
bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
|
||||
wdev->ssid, wdev->ssid_len,
|
||||
WLAN_CAPABILITY_ESS,
|
||||
WLAN_CAPABILITY_ESS);
|
||||
if (WARN_ON(!bss))
|
||||
return;
|
||||
if (WARN_ON(!bss))
|
||||
return;
|
||||
cfg80211_hold_bss(bss_from_pub(bss));
|
||||
}
|
||||
|
||||
cfg80211_hold_bss(bss_from_pub(bss));
|
||||
wdev->current_bss = bss_from_pub(bss);
|
||||
|
||||
cfg80211_upload_connect_keys(wdev);
|
||||
|
@ -691,6 +700,7 @@ void cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
|
|||
}
|
||||
EXPORT_SYMBOL(cfg80211_connect_result);
|
||||
|
||||
/* Consumes bss object one way or another */
|
||||
void __cfg80211_roamed(struct wireless_dev *wdev,
|
||||
struct cfg80211_bss *bss,
|
||||
const u8 *req_ie, size_t req_ie_len,
|
||||
|
@ -767,6 +777,7 @@ void cfg80211_roamed(struct net_device *dev,
|
|||
}
|
||||
EXPORT_SYMBOL(cfg80211_roamed);
|
||||
|
||||
/* Consumes bss object one way or another */
|
||||
void cfg80211_roamed_bss(struct net_device *dev,
|
||||
struct cfg80211_bss *bss, const u8 *req_ie,
|
||||
size_t req_ie_len, const u8 *resp_ie,
|
||||
|
|
|
@ -83,6 +83,7 @@ static int wiphy_uevent(struct device *dev, struct kobj_uevent_env *env)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static void cfg80211_leave_all(struct cfg80211_registered_device *rdev)
|
||||
{
|
||||
struct wireless_dev *wdev;
|
||||
|
@ -91,7 +92,6 @@ static void cfg80211_leave_all(struct cfg80211_registered_device *rdev)
|
|||
cfg80211_leave(rdev, wdev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int wiphy_suspend(struct device *dev, pm_message_t state)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev = dev_to_rdev(dev);
|
||||
|
|
Загрузка…
Ссылка в новой задаче