Merge branch 'for-john' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next
This commit is contained in:
commit
20fb9e5033
@ -542,9 +542,8 @@ brcms_ops_bss_info_changed(struct ieee80211_hw *hw,
|
||||
|
||||
if (changed & BSS_CHANGED_ARP_FILTER) {
|
||||
/* Hardware ARP filter address list or state changed */
|
||||
brcms_err(core, "%s: arp filtering: enabled %s, count %d"
|
||||
" (implement)\n", __func__, info->arp_filter_enabled ?
|
||||
"true" : "false", info->arp_addr_cnt);
|
||||
brcms_err(core, "%s: arp filtering: %d addresses"
|
||||
" (implement)\n", __func__, info->arp_addr_cnt);
|
||||
}
|
||||
|
||||
if (changed & BSS_CHANGED_QOS) {
|
||||
|
@ -1154,6 +1154,7 @@ static int iwlagn_mac_cancel_remain_on_channel(struct ieee80211_hw *hw)
|
||||
}
|
||||
|
||||
static void iwlagn_mac_rssi_callback(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_rssi_event rssi_event)
|
||||
{
|
||||
struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
|
||||
|
@ -4239,8 +4239,7 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
|
||||
wlvif->sta.qos = bss_conf->qos;
|
||||
WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS);
|
||||
|
||||
if (bss_conf->arp_addr_cnt == 1 &&
|
||||
bss_conf->arp_filter_enabled) {
|
||||
if (bss_conf->arp_addr_cnt == 1 && bss_conf->assoc) {
|
||||
wlvif->ip_addr = addr;
|
||||
/*
|
||||
* The template should have been configured only upon
|
||||
|
@ -1898,7 +1898,10 @@ enum ieee80211_sa_query_action {
|
||||
/* AKM suite selectors */
|
||||
#define WLAN_AKM_SUITE_8021X 0x000FAC01
|
||||
#define WLAN_AKM_SUITE_PSK 0x000FAC02
|
||||
#define WLAN_AKM_SUITE_SAE 0x000FAC08
|
||||
#define WLAN_AKM_SUITE_8021X_SHA256 0x000FAC05
|
||||
#define WLAN_AKM_SUITE_PSK_SHA256 0x000FAC06
|
||||
#define WLAN_AKM_SUITE_TDLS 0x000FAC07
|
||||
#define WLAN_AKM_SUITE_SAE 0x000FAC08
|
||||
#define WLAN_AKM_SUITE_FT_OVER_SAE 0x000FAC09
|
||||
|
||||
#define WLAN_MAX_KEY_LEN 32
|
||||
|
@ -527,6 +527,26 @@ struct cfg80211_beacon_data {
|
||||
size_t probe_resp_len;
|
||||
};
|
||||
|
||||
struct mac_address {
|
||||
u8 addr[ETH_ALEN];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct cfg80211_acl_data - Access control list data
|
||||
*
|
||||
* @acl_policy: ACL policy to be applied on the station's
|
||||
entry specified by mac_addr
|
||||
* @n_acl_entries: Number of MAC address entries passed
|
||||
* @mac_addrs: List of MAC addresses of stations to be used for ACL
|
||||
*/
|
||||
struct cfg80211_acl_data {
|
||||
enum nl80211_acl_policy acl_policy;
|
||||
int n_acl_entries;
|
||||
|
||||
/* Keep it last */
|
||||
struct mac_address mac_addrs[];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct cfg80211_ap_settings - AP configuration
|
||||
*
|
||||
@ -546,6 +566,8 @@ struct cfg80211_beacon_data {
|
||||
* @inactivity_timeout: time in seconds to determine station's inactivity.
|
||||
* @p2p_ctwindow: P2P CT Window
|
||||
* @p2p_opp_ps: P2P opportunistic PS
|
||||
* @acl: ACL configuration used by the drivers which has support for
|
||||
* MAC address based access control
|
||||
*/
|
||||
struct cfg80211_ap_settings {
|
||||
struct cfg80211_chan_def chandef;
|
||||
@ -562,6 +584,7 @@ struct cfg80211_ap_settings {
|
||||
int inactivity_timeout;
|
||||
u8 p2p_ctwindow;
|
||||
bool p2p_opp_ps;
|
||||
const struct cfg80211_acl_data *acl;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1796,6 +1819,13 @@ struct cfg80211_gtk_rekey_data {
|
||||
*
|
||||
* @start_p2p_device: Start the given P2P device.
|
||||
* @stop_p2p_device: Stop the given P2P device.
|
||||
*
|
||||
* @set_mac_acl: Sets MAC address control list in AP and P2P GO mode.
|
||||
* Parameters include ACL policy, an array of MAC address of stations
|
||||
* and the number of MAC addresses. If there is already a list in driver
|
||||
* this new list replaces the existing one. Driver has to clear its ACL
|
||||
* when number of MAC addresses entries is passed as 0. Drivers which
|
||||
* advertise the support for MAC based ACL have to implement this callback.
|
||||
*/
|
||||
struct cfg80211_ops {
|
||||
int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
|
||||
@ -2016,6 +2046,9 @@ struct cfg80211_ops {
|
||||
struct wireless_dev *wdev);
|
||||
void (*stop_p2p_device)(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev);
|
||||
|
||||
int (*set_mac_acl)(struct wiphy *wiphy, struct net_device *dev,
|
||||
const struct cfg80211_acl_data *params);
|
||||
};
|
||||
|
||||
/*
|
||||
@ -2181,10 +2214,6 @@ struct ieee80211_iface_combination {
|
||||
u8 radar_detect_widths;
|
||||
};
|
||||
|
||||
struct mac_address {
|
||||
u8 addr[ETH_ALEN];
|
||||
};
|
||||
|
||||
struct ieee80211_txrx_stypes {
|
||||
u16 tx, rx;
|
||||
};
|
||||
@ -2325,6 +2354,9 @@ struct wiphy_wowlan_support {
|
||||
* @ap_sme_capa: AP SME capabilities, flags from &enum nl80211_ap_sme_features.
|
||||
* @ht_capa_mod_mask: Specify what ht_cap values can be over-ridden.
|
||||
* If null, then none can be over-ridden.
|
||||
*
|
||||
* @max_acl_mac_addrs: Maximum number of MAC addresses that the device
|
||||
* supports for ACL.
|
||||
*/
|
||||
struct wiphy {
|
||||
/* assign these fields before you register the wiphy */
|
||||
@ -2346,6 +2378,8 @@ struct wiphy {
|
||||
/* Supported interface modes, OR together BIT(NL80211_IFTYPE_...) */
|
||||
u16 interface_modes;
|
||||
|
||||
u16 max_acl_mac_addrs;
|
||||
|
||||
u32 flags, features;
|
||||
|
||||
u32 ap_sme_capa;
|
||||
|
@ -297,11 +297,9 @@ enum ieee80211_rssi_event {
|
||||
* may filter ARP queries targeted for other addresses than listed here.
|
||||
* The driver must allow ARP queries targeted for all address listed here
|
||||
* to pass through. An empty list implies no ARP queries need to pass.
|
||||
* @arp_addr_cnt: Number of addresses currently on the list.
|
||||
* @arp_filter_enabled: Enable ARP filtering - if enabled, the hardware may
|
||||
* filter ARP queries based on the @arp_addr_list, if disabled, the
|
||||
* hardware must not perform any ARP filtering. Note, that the filter will
|
||||
* be enabled also in promiscuous mode.
|
||||
* @arp_addr_cnt: Number of addresses currently on the list. Note that this
|
||||
* may be larger than %IEEE80211_BSS_ARP_ADDR_LIST_LEN (the arp_addr_list
|
||||
* array size), it's up to the driver what to do in that case.
|
||||
* @qos: This is a QoS-enabled BSS.
|
||||
* @idle: This interface is idle. There's also a global idle flag in the
|
||||
* hardware config which may be more appropriate depending on what
|
||||
@ -338,8 +336,7 @@ struct ieee80211_bss_conf {
|
||||
u32 cqm_rssi_hyst;
|
||||
struct cfg80211_chan_def chandef;
|
||||
__be32 arp_addr_list[IEEE80211_BSS_ARP_ADDR_LIST_LEN];
|
||||
u8 arp_addr_cnt;
|
||||
bool arp_filter_enabled;
|
||||
int arp_addr_cnt;
|
||||
bool qos;
|
||||
bool idle;
|
||||
bool ps;
|
||||
@ -1630,6 +1627,10 @@ void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb);
|
||||
* rekeying), it will not include a valid phase 1 key. The valid phase 1 key is
|
||||
* provided by update_tkip_key only. The trigger that makes mac80211 call this
|
||||
* handler is software decryption with wrap around of iv16.
|
||||
*
|
||||
* The set_default_unicast_key() call updates the default WEP key index
|
||||
* configured to the hardware for WEP encryption type. This is required
|
||||
* for devices that support offload of data packets (e.g. ARP responses).
|
||||
*/
|
||||
|
||||
/**
|
||||
@ -2208,6 +2209,10 @@ enum ieee80211_rate_control_changed {
|
||||
* After rekeying was done it should (for example during resume) notify
|
||||
* userspace of the new replay counter using ieee80211_gtk_rekey_notify().
|
||||
*
|
||||
* @set_default_unicast_key: Set the default (unicast) key index, useful for
|
||||
* WEP when the device sends data packets autonomously, e.g. for ARP
|
||||
* offloading. The index can be 0-3, or -1 for unsetting it.
|
||||
*
|
||||
* @hw_scan: Ask the hardware to service the scan request, no need to start
|
||||
* the scan state machine in stack. The scan must honour the channel
|
||||
* configuration done by the regulatory agent in the wiphy's
|
||||
@ -2492,6 +2497,9 @@ enum ieee80211_rate_control_changed {
|
||||
* driver's resume function returned 1, as this is just like an "inline"
|
||||
* hardware restart. This callback may sleep.
|
||||
*
|
||||
* @ipv6_addr_change: IPv6 address assignment on the given interface changed.
|
||||
* Currently, this is only called for managed or P2P client interfaces.
|
||||
* This callback is optional; it must not sleep.
|
||||
*/
|
||||
struct ieee80211_ops {
|
||||
void (*tx)(struct ieee80211_hw *hw,
|
||||
@ -2539,6 +2547,8 @@ struct ieee80211_ops {
|
||||
void (*set_rekey_data)(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct cfg80211_gtk_rekey_data *data);
|
||||
void (*set_default_unicast_key)(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif, int idx);
|
||||
int (*hw_scan)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
struct cfg80211_scan_request *req);
|
||||
void (*cancel_hw_scan)(struct ieee80211_hw *hw,
|
||||
@ -2623,6 +2633,7 @@ struct ieee80211_ops {
|
||||
int (*set_bitrate_mask)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
const struct cfg80211_bitrate_mask *mask);
|
||||
void (*rssi_callback)(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_rssi_event rssi_event);
|
||||
|
||||
void (*allow_buffered_frames)(struct ieee80211_hw *hw,
|
||||
@ -2665,6 +2676,12 @@ struct ieee80211_ops {
|
||||
struct ieee80211_chanctx_conf *ctx);
|
||||
|
||||
void (*restart_complete)(struct ieee80211_hw *hw);
|
||||
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
void (*ipv6_addr_change)(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct inet6_dev *idev);
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -170,7 +170,8 @@
|
||||
* %NL80211_ATTR_HIDDEN_SSID, %NL80211_ATTR_CIPHERS_PAIRWISE,
|
||||
* %NL80211_ATTR_CIPHER_GROUP, %NL80211_ATTR_WPA_VERSIONS,
|
||||
* %NL80211_ATTR_AKM_SUITES, %NL80211_ATTR_PRIVACY,
|
||||
* %NL80211_ATTR_AUTH_TYPE and %NL80211_ATTR_INACTIVITY_TIMEOUT.
|
||||
* %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_INACTIVITY_TIMEOUT,
|
||||
* %NL80211_ATTR_ACL_POLICY and %NL80211_ATTR_MAC_ADDRS.
|
||||
* The channel to use can be set on the interface or be given using the
|
||||
* %NL80211_ATTR_WIPHY_FREQ and the attributes determining channel width.
|
||||
* @NL80211_CMD_NEW_BEACON: old alias for %NL80211_CMD_START_AP
|
||||
@ -586,6 +587,16 @@
|
||||
* @NL80211_CMD_SET_MCAST_RATE: Change the rate used to send multicast frames
|
||||
* for IBSS or MESH vif.
|
||||
*
|
||||
* @NL80211_CMD_SET_MAC_ACL: sets ACL for MAC address based access control.
|
||||
* This is to be used with the drivers advertising the support of MAC
|
||||
* address based access control. List of MAC addresses is passed in
|
||||
* %NL80211_ATTR_MAC_ADDRS and ACL policy is passed in
|
||||
* %NL80211_ATTR_ACL_POLICY. Driver will enable ACL with this list, if it
|
||||
* is not already done. The new list will replace any existing list. Driver
|
||||
* will clear its ACL when the list of MAC addresses passed is empty. This
|
||||
* command is used in AP/P2P GO mode. Driver has to make sure to clear its
|
||||
* ACL list during %NL80211_CMD_STOP_AP.
|
||||
*
|
||||
* @NL80211_CMD_MAX: highest used command number
|
||||
* @__NL80211_CMD_AFTER_LAST: internal use
|
||||
*/
|
||||
@ -736,6 +747,8 @@ enum nl80211_commands {
|
||||
|
||||
NL80211_CMD_SET_MCAST_RATE,
|
||||
|
||||
NL80211_CMD_SET_MAC_ACL,
|
||||
|
||||
/* add new commands above here */
|
||||
|
||||
/* used to define NL80211_CMD_MAX below */
|
||||
@ -1313,6 +1326,16 @@ enum nl80211_commands {
|
||||
* @NL80211_ATTR_LOCAL_MESH_POWER_MODE: local mesh STA link-specific power mode
|
||||
* defined in &enum nl80211_mesh_power_mode.
|
||||
*
|
||||
* @NL80211_ATTR_ACL_POLICY: ACL policy, see &enum nl80211_acl_policy,
|
||||
* carried in a u32 attribute
|
||||
*
|
||||
* @NL80211_ATTR_MAC_ADDRS: Array of nested MAC addresses, used for
|
||||
* MAC ACL.
|
||||
*
|
||||
* @NL80211_ATTR_MAC_ACL_MAX: u32 attribute to advertise the maximum
|
||||
* number of MAC addresses that a device can support for MAC
|
||||
* ACL.
|
||||
*
|
||||
* @NL80211_ATTR_MAX: highest attribute number currently defined
|
||||
* @__NL80211_ATTR_AFTER_LAST: internal use
|
||||
*/
|
||||
@ -1585,6 +1608,12 @@ enum nl80211_attrs {
|
||||
|
||||
NL80211_ATTR_LOCAL_MESH_POWER_MODE,
|
||||
|
||||
NL80211_ATTR_ACL_POLICY,
|
||||
|
||||
NL80211_ATTR_MAC_ADDRS,
|
||||
|
||||
NL80211_ATTR_MAC_ACL_MAX,
|
||||
|
||||
/* add attributes here, update the policy in nl80211.c */
|
||||
|
||||
__NL80211_ATTR_AFTER_LAST,
|
||||
@ -3248,7 +3277,7 @@ enum nl80211_probe_resp_offload_support_attr {
|
||||
* enum nl80211_connect_failed_reason - connection request failed reasons
|
||||
* @NL80211_CONN_FAIL_MAX_CLIENTS: Maximum number of clients that can be
|
||||
* handled by the AP is reached.
|
||||
* @NL80211_CONN_FAIL_BLOCKED_CLIENT: Client's MAC is in the AP's blocklist.
|
||||
* @NL80211_CONN_FAIL_BLOCKED_CLIENT: Connection request is rejected due to ACL.
|
||||
*/
|
||||
enum nl80211_connect_failed_reason {
|
||||
NL80211_CONN_FAIL_MAX_CLIENTS,
|
||||
@ -3276,4 +3305,22 @@ enum nl80211_scan_flags {
|
||||
NL80211_SCAN_FLAG_AP = 1<<2,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum nl80211_acl_policy - access control policy
|
||||
*
|
||||
* Access control policy is applied on a MAC list set by
|
||||
* %NL80211_CMD_START_AP and %NL80211_CMD_SET_MAC_ACL, to
|
||||
* be used with %NL80211_ATTR_ACL_POLICY.
|
||||
*
|
||||
* @NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED: Deny stations which are
|
||||
* listed in ACL, i.e. allow all the stations which are not listed
|
||||
* in ACL to authenticate.
|
||||
* @NL80211_ACL_POLICY_DENY_UNLESS_LISTED: Allow the stations which are listed
|
||||
* in ACL, i.e. deny all the stations which are not listed in ACL.
|
||||
*/
|
||||
enum nl80211_acl_policy {
|
||||
NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED,
|
||||
NL80211_ACL_POLICY_DENY_UNLESS_LISTED,
|
||||
};
|
||||
|
||||
#endif /* __LINUX_NL80211_H */
|
||||
|
@ -83,8 +83,8 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
|
||||
if (drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_STOP,
|
||||
&sta->sta, tid, NULL, 0))
|
||||
sdata_info(sta->sdata,
|
||||
"HW problem - can not stop rx aggregation for tid %d\n",
|
||||
tid);
|
||||
"HW problem - can not stop rx aggregation for %pM tid %d\n",
|
||||
sta->sta.addr, tid);
|
||||
|
||||
/* check if this is a self generated aggregation halt */
|
||||
if (initiator == WLAN_BACK_RECIPIENT && tx)
|
||||
@ -159,7 +159,8 @@ static void sta_rx_agg_session_timer_expired(unsigned long data)
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
ht_dbg(sta->sdata, "rx session timer expired on tid %d\n", (u16)*ptid);
|
||||
ht_dbg(sta->sdata, "RX session timer expired on %pM tid %d\n",
|
||||
sta->sta.addr, (u16)*ptid);
|
||||
|
||||
set_bit(*ptid, sta->ampdu_mlme.tid_rx_timer_expired);
|
||||
ieee80211_queue_work(&sta->local->hw, &sta->ampdu_mlme.work);
|
||||
@ -247,7 +248,9 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
|
||||
status = WLAN_STATUS_REQUEST_DECLINED;
|
||||
|
||||
if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) {
|
||||
ht_dbg(sta->sdata, "Suspend in progress - Denying ADDBA request\n");
|
||||
ht_dbg(sta->sdata,
|
||||
"Suspend in progress - Denying ADDBA request (%pM tid %d)\n",
|
||||
sta->sta.addr, tid);
|
||||
goto end_no_lock;
|
||||
}
|
||||
|
||||
@ -317,7 +320,8 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
|
||||
|
||||
ret = drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_START,
|
||||
&sta->sta, tid, &start_seq_num, 0);
|
||||
ht_dbg(sta->sdata, "Rx A-MPDU request on tid %d result %d\n", tid, ret);
|
||||
ht_dbg(sta->sdata, "Rx A-MPDU request on %pM tid %d result %d\n",
|
||||
sta->sta.addr, tid, ret);
|
||||
if (ret) {
|
||||
kfree(tid_agg_rx->reorder_buf);
|
||||
kfree(tid_agg_rx->reorder_time);
|
||||
|
@ -296,7 +296,7 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
|
||||
IEEE80211_AMPDU_TX_STOP_FLUSH_CONT,
|
||||
&sta->sta, tid, NULL, 0);
|
||||
WARN_ON_ONCE(ret);
|
||||
goto remove_tid_tx;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) {
|
||||
@ -354,12 +354,15 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
|
||||
*/
|
||||
}
|
||||
|
||||
if (reason == AGG_STOP_DESTROY_STA) {
|
||||
remove_tid_tx:
|
||||
spin_lock_bh(&sta->lock);
|
||||
ieee80211_remove_tid_tx(sta, tid);
|
||||
spin_unlock_bh(&sta->lock);
|
||||
}
|
||||
/*
|
||||
* In the case of AGG_STOP_DESTROY_STA, the driver won't
|
||||
* necessarily call ieee80211_stop_tx_ba_cb(), so this may
|
||||
* seem like we can leave the tid_tx data pending forever.
|
||||
* This is true, in a way, but "forever" is only until the
|
||||
* station struct is actually destroyed. In the meantime,
|
||||
* leaving it around ensures that we don't transmit packets
|
||||
* to the driver on this TID which might confuse it.
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -387,12 +390,13 @@ static void sta_addba_resp_timer_expired(unsigned long data)
|
||||
test_bit(HT_AGG_STATE_RESPONSE_RECEIVED, &tid_tx->state)) {
|
||||
rcu_read_unlock();
|
||||
ht_dbg(sta->sdata,
|
||||
"timer expired on tid %d but we are not (or no longer) expecting addBA response there\n",
|
||||
tid);
|
||||
"timer expired on %pM tid %d but we are not (or no longer) expecting addBA response there\n",
|
||||
sta->sta.addr, tid);
|
||||
return;
|
||||
}
|
||||
|
||||
ht_dbg(sta->sdata, "addBA response timer expired on tid %d\n", tid);
|
||||
ht_dbg(sta->sdata, "addBA response timer expired on %pM tid %d\n",
|
||||
sta->sta.addr, tid);
|
||||
|
||||
ieee80211_stop_tx_ba_session(&sta->sta, tid);
|
||||
rcu_read_unlock();
|
||||
@ -429,7 +433,8 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
|
||||
&sta->sta, tid, &start_seq_num, 0);
|
||||
if (ret) {
|
||||
ht_dbg(sdata,
|
||||
"BA request denied - HW unavailable for tid %d\n", tid);
|
||||
"BA request denied - HW unavailable for %pM tid %d\n",
|
||||
sta->sta.addr, tid);
|
||||
spin_lock_bh(&sta->lock);
|
||||
ieee80211_agg_splice_packets(sdata, tid_tx, tid);
|
||||
ieee80211_assign_tid_tx(sta, tid, NULL);
|
||||
@ -442,7 +447,8 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
|
||||
|
||||
/* activate the timer for the recipient's addBA response */
|
||||
mod_timer(&tid_tx->addba_resp_timer, jiffies + ADDBA_RESP_INTERVAL);
|
||||
ht_dbg(sdata, "activated addBA response timer on tid %d\n", tid);
|
||||
ht_dbg(sdata, "activated addBA response timer on %pM tid %d\n",
|
||||
sta->sta.addr, tid);
|
||||
|
||||
spin_lock_bh(&sta->lock);
|
||||
sta->ampdu_mlme.last_addba_req_time[tid] = jiffies;
|
||||
@ -489,7 +495,8 @@ static void sta_tx_agg_session_timer_expired(unsigned long data)
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
ht_dbg(sta->sdata, "tx session timer expired on tid %d\n", (u16)*ptid);
|
||||
ht_dbg(sta->sdata, "tx session timer expired on %pM tid %d\n",
|
||||
sta->sta.addr, (u16)*ptid);
|
||||
|
||||
ieee80211_stop_tx_ba_session(&sta->sta, *ptid);
|
||||
}
|
||||
@ -525,7 +532,8 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
|
||||
|
||||
if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) {
|
||||
ht_dbg(sdata,
|
||||
"BA sessions blocked - Denying BA session request\n");
|
||||
"BA sessions blocked - Denying BA session request %pM tid %d\n",
|
||||
sta->sta.addr, tid);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -566,8 +574,8 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
|
||||
time_before(jiffies, sta->ampdu_mlme.last_addba_req_time[tid] +
|
||||
HT_AGG_RETRIES_PERIOD)) {
|
||||
ht_dbg(sdata,
|
||||
"BA request denied - waiting a grace period after %d failed requests on tid %u\n",
|
||||
sta->ampdu_mlme.addba_req_num[tid], tid);
|
||||
"BA request denied - waiting a grace period after %d failed requests on %pM tid %u\n",
|
||||
sta->ampdu_mlme.addba_req_num[tid], sta->sta.addr, tid);
|
||||
ret = -EBUSY;
|
||||
goto err_unlock_sta;
|
||||
}
|
||||
@ -576,8 +584,8 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
|
||||
/* check if the TID is not in aggregation flow already */
|
||||
if (tid_tx || sta->ampdu_mlme.tid_start_tx[tid]) {
|
||||
ht_dbg(sdata,
|
||||
"BA request denied - session is not idle on tid %u\n",
|
||||
tid);
|
||||
"BA request denied - session is not idle on %pM tid %u\n",
|
||||
sta->sta.addr, tid);
|
||||
ret = -EAGAIN;
|
||||
goto err_unlock_sta;
|
||||
}
|
||||
@ -632,7 +640,8 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local,
|
||||
|
||||
tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
|
||||
|
||||
ht_dbg(sta->sdata, "Aggregation is on for tid %d\n", tid);
|
||||
ht_dbg(sta->sdata, "Aggregation is on for %pM tid %d\n",
|
||||
sta->sta.addr, tid);
|
||||
|
||||
drv_ampdu_action(local, sta->sdata,
|
||||
IEEE80211_AMPDU_TX_OPERATIONAL,
|
||||
@ -802,7 +811,9 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid)
|
||||
tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
|
||||
|
||||
if (!tid_tx || !test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) {
|
||||
ht_dbg(sdata, "unexpected callback to A-MPDU stop\n");
|
||||
ht_dbg(sdata,
|
||||
"unexpected callback to A-MPDU stop for %pM tid %d\n",
|
||||
sta->sta.addr, tid);
|
||||
goto unlock_sta;
|
||||
}
|
||||
|
||||
@ -861,13 +872,15 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
|
||||
goto out;
|
||||
|
||||
if (mgmt->u.action.u.addba_resp.dialog_token != tid_tx->dialog_token) {
|
||||
ht_dbg(sta->sdata, "wrong addBA response token, tid %d\n", tid);
|
||||
ht_dbg(sta->sdata, "wrong addBA response token, %pM tid %d\n",
|
||||
sta->sta.addr, tid);
|
||||
goto out;
|
||||
}
|
||||
|
||||
del_timer_sync(&tid_tx->addba_resp_timer);
|
||||
|
||||
ht_dbg(sta->sdata, "switched off addBA timer for tid %d\n", tid);
|
||||
ht_dbg(sta->sdata, "switched off addBA timer for %pM tid %d\n",
|
||||
sta->sta.addr, tid);
|
||||
|
||||
/*
|
||||
* addba_resp_timer may have fired before we got here, and
|
||||
@ -877,8 +890,8 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
|
||||
if (test_bit(HT_AGG_STATE_WANT_STOP, &tid_tx->state) ||
|
||||
test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) {
|
||||
ht_dbg(sta->sdata,
|
||||
"got addBA resp for tid %d but we already gave up\n",
|
||||
tid);
|
||||
"got addBA resp for %pM tid %d but we already gave up\n",
|
||||
sta->sta.addr, tid);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -569,7 +569,8 @@ static inline void drv_sta_rc_update(struct ieee80211_local *local,
|
||||
check_sdata_in_driver(sdata);
|
||||
|
||||
WARN_ON(changed & IEEE80211_RC_SUPP_RATES_CHANGED &&
|
||||
sdata->vif.type != NL80211_IFTYPE_ADHOC);
|
||||
(sdata->vif.type != NL80211_IFTYPE_ADHOC &&
|
||||
sdata->vif.type != NL80211_IFTYPE_MESH_POINT));
|
||||
|
||||
trace_drv_sta_rc_update(local, sdata, sta, changed);
|
||||
if (local->ops->sta_rc_update)
|
||||
@ -845,11 +846,12 @@ static inline void drv_set_rekey_data(struct ieee80211_local *local,
|
||||
}
|
||||
|
||||
static inline void drv_rssi_callback(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
const enum ieee80211_rssi_event event)
|
||||
{
|
||||
trace_drv_rssi_callback(local, event);
|
||||
trace_drv_rssi_callback(local, sdata, event);
|
||||
if (local->ops->rssi_callback)
|
||||
local->ops->rssi_callback(&local->hw, event);
|
||||
local->ops->rssi_callback(&local->hw, &sdata->vif, event);
|
||||
trace_drv_return_void(local);
|
||||
}
|
||||
|
||||
@ -1020,4 +1022,32 @@ static inline void drv_restart_complete(struct ieee80211_local *local)
|
||||
trace_drv_return_void(local);
|
||||
}
|
||||
|
||||
static inline void
|
||||
drv_set_default_unicast_key(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
int key_idx)
|
||||
{
|
||||
check_sdata_in_driver(sdata);
|
||||
|
||||
WARN_ON_ONCE(key_idx < -1 || key_idx > 3);
|
||||
|
||||
trace_drv_set_default_unicast_key(local, sdata, key_idx);
|
||||
if (local->ops->set_default_unicast_key)
|
||||
local->ops->set_default_unicast_key(&local->hw, &sdata->vif,
|
||||
key_idx);
|
||||
trace_drv_return_void(local);
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
static inline void drv_ipv6_addr_change(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
struct inet6_dev *idev)
|
||||
{
|
||||
trace_drv_ipv6_addr_change(local, sdata);
|
||||
if (local->ops->ipv6_addr_change)
|
||||
local->ops->ipv6_addr_change(&local->hw, &sdata->vif, idev);
|
||||
trace_drv_return_void(local);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __MAC80211_DRIVER_OPS */
|
||||
|
@ -747,8 +747,6 @@ struct ieee80211_sub_if_data {
|
||||
struct work_struct work;
|
||||
struct sk_buff_head skb_queue;
|
||||
|
||||
bool arp_filter_state;
|
||||
|
||||
u8 needed_rx_chains;
|
||||
enum ieee80211_smps_mode smps_mode;
|
||||
|
||||
@ -1129,6 +1127,7 @@ struct ieee80211_local {
|
||||
struct timer_list dynamic_ps_timer;
|
||||
struct notifier_block network_latency_notifier;
|
||||
struct notifier_block ifa_notifier;
|
||||
struct notifier_block ifa6_notifier;
|
||||
|
||||
/*
|
||||
* The dynamic ps timeout configured from user space via WEXT -
|
||||
|
@ -1574,9 +1574,6 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
|
||||
/* initialise type-independent data */
|
||||
sdata->wdev.wiphy = local->hw.wiphy;
|
||||
sdata->local = local;
|
||||
#ifdef CONFIG_INET
|
||||
sdata->arp_filter_state = true;
|
||||
#endif
|
||||
|
||||
for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++)
|
||||
skb_queue_head_init(&sdata->fragments[i].skb_list);
|
||||
|
@ -204,8 +204,11 @@ static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata,
|
||||
if (idx >= 0 && idx < NUM_DEFAULT_KEYS)
|
||||
key = key_mtx_dereference(sdata->local, sdata->keys[idx]);
|
||||
|
||||
if (uni)
|
||||
if (uni) {
|
||||
rcu_assign_pointer(sdata->default_unicast_key, key);
|
||||
drv_set_default_unicast_key(sdata->local, sdata, idx);
|
||||
}
|
||||
|
||||
if (multi)
|
||||
rcu_assign_pointer(sdata->default_multicast_key, key);
|
||||
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <linux/inetdevice.h>
|
||||
#include <net/net_namespace.h>
|
||||
#include <net/cfg80211.h>
|
||||
#include <net/addrconf.h>
|
||||
|
||||
#include "ieee80211_i.h"
|
||||
#include "driver-ops.h"
|
||||
@ -349,27 +350,19 @@ static int ieee80211_ifa_changed(struct notifier_block *nb,
|
||||
|
||||
/* Copy the addresses to the bss_conf list */
|
||||
ifa = idev->ifa_list;
|
||||
while (c < IEEE80211_BSS_ARP_ADDR_LIST_LEN && ifa) {
|
||||
bss_conf->arp_addr_list[c] = ifa->ifa_address;
|
||||
while (ifa) {
|
||||
if (c < IEEE80211_BSS_ARP_ADDR_LIST_LEN)
|
||||
bss_conf->arp_addr_list[c] = ifa->ifa_address;
|
||||
ifa = ifa->ifa_next;
|
||||
c++;
|
||||
}
|
||||
|
||||
/* If not all addresses fit the list, disable filtering */
|
||||
if (ifa) {
|
||||
sdata->arp_filter_state = false;
|
||||
c = 0;
|
||||
} else {
|
||||
sdata->arp_filter_state = true;
|
||||
}
|
||||
bss_conf->arp_addr_cnt = c;
|
||||
|
||||
/* Configure driver only if associated (which also implies it is up) */
|
||||
if (ifmgd->associated) {
|
||||
bss_conf->arp_filter_enabled = sdata->arp_filter_state;
|
||||
if (ifmgd->associated)
|
||||
ieee80211_bss_info_change_notify(sdata,
|
||||
BSS_CHANGED_ARP_FILTER);
|
||||
}
|
||||
|
||||
mutex_unlock(&ifmgd->mtx);
|
||||
|
||||
@ -377,6 +370,37 @@ static int ieee80211_ifa_changed(struct notifier_block *nb,
|
||||
}
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
static int ieee80211_ifa6_changed(struct notifier_block *nb,
|
||||
unsigned long data, void *arg)
|
||||
{
|
||||
struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)arg;
|
||||
struct inet6_dev *idev = ifa->idev;
|
||||
struct net_device *ndev = ifa->idev->dev;
|
||||
struct ieee80211_local *local =
|
||||
container_of(nb, struct ieee80211_local, ifa6_notifier);
|
||||
struct wireless_dev *wdev = ndev->ieee80211_ptr;
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
|
||||
/* Make sure it's our interface that got changed */
|
||||
if (!wdev || wdev->wiphy != local->hw.wiphy)
|
||||
return NOTIFY_DONE;
|
||||
|
||||
sdata = IEEE80211_DEV_TO_SUB_IF(ndev);
|
||||
|
||||
/*
|
||||
* For now only support station mode. This is mostly because
|
||||
* doing AP would have to handle AP_VLAN in some way ...
|
||||
*/
|
||||
if (sdata->vif.type != NL80211_IFTYPE_STATION)
|
||||
return NOTIFY_DONE;
|
||||
|
||||
drv_ipv6_addr_change(local, sdata, idev);
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int ieee80211_napi_poll(struct napi_struct *napi, int budget)
|
||||
{
|
||||
struct ieee80211_local *local =
|
||||
@ -985,12 +1009,25 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
||||
goto fail_ifa;
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
local->ifa6_notifier.notifier_call = ieee80211_ifa6_changed;
|
||||
result = register_inet6addr_notifier(&local->ifa6_notifier);
|
||||
if (result)
|
||||
goto fail_ifa6;
|
||||
#endif
|
||||
|
||||
netif_napi_add(&local->napi_dev, &local->napi, ieee80211_napi_poll,
|
||||
local->hw.napi_weight);
|
||||
|
||||
return 0;
|
||||
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
fail_ifa6:
|
||||
#ifdef CONFIG_INET
|
||||
unregister_inetaddr_notifier(&local->ifa_notifier);
|
||||
#endif
|
||||
#endif
|
||||
#if defined(CONFIG_INET) || defined(CONFIG_IPV6)
|
||||
fail_ifa:
|
||||
pm_qos_remove_notifier(PM_QOS_NETWORK_LATENCY,
|
||||
&local->network_latency_notifier);
|
||||
@ -1026,6 +1063,9 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
|
||||
#ifdef CONFIG_INET
|
||||
unregister_inetaddr_notifier(&local->ifa_notifier);
|
||||
#endif
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
unregister_inet6addr_notifier(&local->ifa6_notifier);
|
||||
#endif
|
||||
|
||||
rtnl_lock();
|
||||
|
||||
|
@ -55,30 +55,6 @@ static inline void mesh_plink_fsm_restart(struct sta_info *sta)
|
||||
sta->plink_retries = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate mesh sta entry and insert into station table
|
||||
*/
|
||||
static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata,
|
||||
u8 *hw_addr)
|
||||
{
|
||||
struct sta_info *sta;
|
||||
|
||||
if (sdata->local->num_sta >= MESH_MAX_PLINKS)
|
||||
return NULL;
|
||||
|
||||
sta = sta_info_alloc(sdata, hw_addr, GFP_KERNEL);
|
||||
if (!sta)
|
||||
return NULL;
|
||||
|
||||
sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);
|
||||
sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC);
|
||||
sta_info_pre_move_state(sta, IEEE80211_STA_AUTHORIZED);
|
||||
|
||||
set_sta_flag(sta, WLAN_STA_WME);
|
||||
|
||||
return sta;
|
||||
}
|
||||
|
||||
/**
|
||||
* mesh_set_ht_prot_mode - set correct HT protection mode
|
||||
*
|
||||
@ -309,53 +285,27 @@ free:
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* mesh_peer_init - initialize new mesh peer and return resulting sta_info
|
||||
*
|
||||
* @sdata: local meshif
|
||||
* @addr: peer's address
|
||||
* @elems: IEs from beacon or mesh peering frame
|
||||
*
|
||||
* call under RCU
|
||||
*/
|
||||
static struct sta_info *mesh_peer_init(struct ieee80211_sub_if_data *sdata,
|
||||
u8 *addr,
|
||||
struct ieee802_11_elems *elems)
|
||||
static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata,
|
||||
struct sta_info *sta,
|
||||
struct ieee802_11_elems *elems, bool insert)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
|
||||
struct ieee80211_supported_band *sband;
|
||||
u32 rates, basic_rates = 0;
|
||||
struct sta_info *sta;
|
||||
bool insert = false;
|
||||
u32 rates, basic_rates = 0, changed = 0;
|
||||
|
||||
sband = local->hw.wiphy->bands[band];
|
||||
rates = ieee80211_sta_get_rates(local, elems, band, &basic_rates);
|
||||
|
||||
sta = sta_info_get(sdata, addr);
|
||||
if (!sta) {
|
||||
/* Userspace handles peer allocation when security is enabled */
|
||||
if (sdata->u.mesh.security & IEEE80211_MESH_SEC_AUTHED) {
|
||||
cfg80211_notify_new_peer_candidate(sdata->dev, addr,
|
||||
elems->ie_start,
|
||||
elems->total_len,
|
||||
GFP_ATOMIC);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sta = mesh_plink_alloc(sdata, addr);
|
||||
if (!sta)
|
||||
return NULL;
|
||||
insert = true;
|
||||
}
|
||||
|
||||
spin_lock_bh(&sta->lock);
|
||||
sta->last_rx = jiffies;
|
||||
if (sta->plink_state == NL80211_PLINK_ESTAB) {
|
||||
spin_unlock_bh(&sta->lock);
|
||||
return sta;
|
||||
}
|
||||
|
||||
/* rates and capabilities don't change during peering */
|
||||
if (sta->plink_state == NL80211_PLINK_ESTAB)
|
||||
goto out;
|
||||
|
||||
if (sta->sta.supp_rates[band] != rates)
|
||||
changed |= IEEE80211_RC_SUPP_RATES_CHANGED;
|
||||
sta->sta.supp_rates[band] = rates;
|
||||
if (elems->ht_cap_elem &&
|
||||
sdata->vif.bss_conf.chandef.width != NL80211_CHAN_WIDTH_20_NOHT)
|
||||
@ -374,27 +324,115 @@ static struct sta_info *mesh_peer_init(struct ieee80211_sub_if_data *sdata,
|
||||
~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
|
||||
ieee80211_ht_oper_to_chandef(sdata->vif.bss_conf.chandef.chan,
|
||||
elems->ht_operation, &chandef);
|
||||
if (sta->ch_width != chandef.width)
|
||||
changed |= IEEE80211_RC_BW_CHANGED;
|
||||
sta->ch_width = chandef.width;
|
||||
}
|
||||
|
||||
if (insert)
|
||||
rate_control_rate_init(sta);
|
||||
else
|
||||
rate_control_rate_update(local, sband, sta, changed);
|
||||
out:
|
||||
spin_unlock_bh(&sta->lock);
|
||||
}
|
||||
|
||||
if (insert && sta_info_insert(sta))
|
||||
static struct sta_info *
|
||||
__mesh_sta_info_alloc(struct ieee80211_sub_if_data *sdata, u8 *hw_addr)
|
||||
{
|
||||
struct sta_info *sta;
|
||||
|
||||
if (sdata->local->num_sta >= MESH_MAX_PLINKS)
|
||||
return NULL;
|
||||
|
||||
sta = sta_info_alloc(sdata, hw_addr, GFP_KERNEL);
|
||||
if (!sta)
|
||||
return NULL;
|
||||
|
||||
sta->plink_state = NL80211_PLINK_LISTEN;
|
||||
init_timer(&sta->plink_timer);
|
||||
|
||||
sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);
|
||||
sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC);
|
||||
sta_info_pre_move_state(sta, IEEE80211_STA_AUTHORIZED);
|
||||
|
||||
set_sta_flag(sta, WLAN_STA_WME);
|
||||
|
||||
return sta;
|
||||
}
|
||||
|
||||
static struct sta_info *
|
||||
mesh_sta_info_alloc(struct ieee80211_sub_if_data *sdata, u8 *addr,
|
||||
struct ieee802_11_elems *elems)
|
||||
{
|
||||
struct sta_info *sta = NULL;
|
||||
|
||||
/* Userspace handles peer allocation when security is enabled */
|
||||
if (sdata->u.mesh.security & IEEE80211_MESH_SEC_AUTHED)
|
||||
cfg80211_notify_new_peer_candidate(sdata->dev, addr,
|
||||
elems->ie_start,
|
||||
elems->total_len,
|
||||
GFP_KERNEL);
|
||||
else
|
||||
sta = __mesh_sta_info_alloc(sdata, addr);
|
||||
|
||||
return sta;
|
||||
}
|
||||
|
||||
/*
|
||||
* mesh_sta_info_get - return mesh sta info entry for @addr.
|
||||
*
|
||||
* @sdata: local meshif
|
||||
* @addr: peer's address
|
||||
* @elems: IEs from beacon or mesh peering frame.
|
||||
*
|
||||
* Return existing or newly allocated sta_info under RCU read lock.
|
||||
* (re)initialize with given IEs.
|
||||
*/
|
||||
static struct sta_info *
|
||||
mesh_sta_info_get(struct ieee80211_sub_if_data *sdata,
|
||||
u8 *addr, struct ieee802_11_elems *elems) __acquires(RCU)
|
||||
{
|
||||
struct sta_info *sta = NULL;
|
||||
|
||||
rcu_read_lock();
|
||||
sta = sta_info_get(sdata, addr);
|
||||
if (sta) {
|
||||
mesh_sta_info_init(sdata, sta, elems, false);
|
||||
} else {
|
||||
rcu_read_unlock();
|
||||
/* can't run atomic */
|
||||
sta = mesh_sta_info_alloc(sdata, addr, elems);
|
||||
if (!sta) {
|
||||
rcu_read_lock();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mesh_sta_info_init(sdata, sta, elems, true);
|
||||
|
||||
if (sta_info_insert_rcu(sta))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return sta;
|
||||
}
|
||||
|
||||
/*
|
||||
* mesh_neighbour_update - update or initialize new mesh neighbor.
|
||||
*
|
||||
* @sdata: local meshif
|
||||
* @addr: peer's address
|
||||
* @elems: IEs from beacon or mesh peering frame
|
||||
*
|
||||
* Initiates peering if appropriate.
|
||||
*/
|
||||
void mesh_neighbour_update(struct ieee80211_sub_if_data *sdata,
|
||||
u8 *hw_addr,
|
||||
struct ieee802_11_elems *elems)
|
||||
{
|
||||
struct sta_info *sta;
|
||||
|
||||
rcu_read_lock();
|
||||
sta = mesh_peer_init(sdata, hw_addr, elems);
|
||||
sta = mesh_sta_info_get(sdata, hw_addr, elems);
|
||||
if (!sta)
|
||||
goto out;
|
||||
|
||||
@ -632,6 +670,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
|
||||
(ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len == 8))
|
||||
memcpy(&llid, PLINK_GET_PLID(elems.peering), 2);
|
||||
|
||||
/* WARNING: Only for sta pointer, is dropped & re-acquired */
|
||||
rcu_read_lock();
|
||||
|
||||
sta = sta_info_get(sdata, mgmt->sa);
|
||||
@ -735,8 +774,9 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
|
||||
}
|
||||
|
||||
if (event == OPN_ACPT) {
|
||||
rcu_read_unlock();
|
||||
/* allocate sta entry if necessary and update info */
|
||||
sta = mesh_peer_init(sdata, mgmt->sa, &elems);
|
||||
sta = mesh_sta_info_get(sdata, mgmt->sa, &elems);
|
||||
if (!sta) {
|
||||
mpl_dbg(sdata, "Mesh plink: failed to init peer!\n");
|
||||
rcu_read_unlock();
|
||||
|
@ -1465,10 +1465,8 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
|
||||
bss_info_changed |= BSS_CHANGED_CQM;
|
||||
|
||||
/* Enable ARP filtering */
|
||||
if (bss_conf->arp_filter_enabled != sdata->arp_filter_state) {
|
||||
bss_conf->arp_filter_enabled = sdata->arp_filter_state;
|
||||
if (bss_conf->arp_addr_cnt)
|
||||
bss_info_changed |= BSS_CHANGED_ARP_FILTER;
|
||||
}
|
||||
|
||||
ieee80211_bss_info_change_notify(sdata, bss_info_changed);
|
||||
|
||||
@ -1489,7 +1487,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
|
||||
{
|
||||
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct sta_info *sta;
|
||||
u32 changed = 0;
|
||||
|
||||
ASSERT_MGD_MTX(ifmgd);
|
||||
@ -1521,14 +1518,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
|
||||
netif_tx_stop_all_queues(sdata->dev);
|
||||
netif_carrier_off(sdata->dev);
|
||||
|
||||
mutex_lock(&local->sta_mtx);
|
||||
sta = sta_info_get(sdata, ifmgd->bssid);
|
||||
if (sta) {
|
||||
set_sta_flag(sta, WLAN_STA_BLOCK_BA);
|
||||
ieee80211_sta_tear_down_BA_sessions(sta, AGG_STOP_DESTROY_STA);
|
||||
}
|
||||
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
|
||||
@ -1582,10 +1571,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
|
||||
cancel_work_sync(&local->dynamic_ps_enable_work);
|
||||
|
||||
/* Disable ARP filtering */
|
||||
if (sdata->vif.bss_conf.arp_filter_enabled) {
|
||||
sdata->vif.bss_conf.arp_filter_enabled = false;
|
||||
if (sdata->vif.bss_conf.arp_addr_cnt)
|
||||
changed |= BSS_CHANGED_ARP_FILTER;
|
||||
}
|
||||
|
||||
sdata->vif.bss_conf.qos = false;
|
||||
changed |= BSS_CHANGED_QOS;
|
||||
@ -2608,12 +2595,12 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
||||
if (sig > ifmgd->rssi_max_thold &&
|
||||
(last_sig <= ifmgd->rssi_min_thold || last_sig == 0)) {
|
||||
ifmgd->last_ave_beacon_signal = sig;
|
||||
drv_rssi_callback(local, RSSI_EVENT_HIGH);
|
||||
drv_rssi_callback(local, sdata, RSSI_EVENT_HIGH);
|
||||
} else if (sig < ifmgd->rssi_min_thold &&
|
||||
(last_sig >= ifmgd->rssi_max_thold ||
|
||||
last_sig == 0)) {
|
||||
ifmgd->last_ave_beacon_signal = sig;
|
||||
drv_rssi_callback(local, RSSI_EVENT_LOW);
|
||||
drv_rssi_callback(local, sdata, RSSI_EVENT_LOW);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3169,23 +3156,22 @@ void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
|
||||
|
||||
if (!ifmgd->associated)
|
||||
mutex_lock(&ifmgd->mtx);
|
||||
if (!ifmgd->associated) {
|
||||
mutex_unlock(&ifmgd->mtx);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sdata->flags & IEEE80211_SDATA_DISCONNECT_RESUME) {
|
||||
sdata->flags &= ~IEEE80211_SDATA_DISCONNECT_RESUME;
|
||||
mutex_lock(&ifmgd->mtx);
|
||||
if (ifmgd->associated) {
|
||||
mlme_dbg(sdata,
|
||||
"driver requested disconnect after resume\n");
|
||||
ieee80211_sta_connection_lost(sdata,
|
||||
ifmgd->associated->bssid,
|
||||
WLAN_REASON_UNSPECIFIED);
|
||||
mutex_unlock(&ifmgd->mtx);
|
||||
return;
|
||||
}
|
||||
mlme_dbg(sdata, "driver requested disconnect after resume\n");
|
||||
ieee80211_sta_connection_lost(sdata,
|
||||
ifmgd->associated->bssid,
|
||||
WLAN_REASON_UNSPECIFIED);
|
||||
mutex_unlock(&ifmgd->mtx);
|
||||
return;
|
||||
}
|
||||
mutex_unlock(&ifmgd->mtx);
|
||||
|
||||
if (test_and_clear_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running))
|
||||
add_timer(&ifmgd->timer);
|
||||
|
@ -380,11 +380,6 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
sta_dbg(sdata, "Allocated STA %pM\n", sta->sta.addr);
|
||||
|
||||
#ifdef CONFIG_MAC80211_MESH
|
||||
sta->plink_state = NL80211_PLINK_LISTEN;
|
||||
init_timer(&sta->plink_timer);
|
||||
#endif
|
||||
|
||||
return sta;
|
||||
}
|
||||
|
||||
|
@ -347,8 +347,11 @@ TRACE_EVENT(drv_bss_info_changed,
|
||||
__field(s32, cqm_rssi_hyst);
|
||||
__field(u32, channel_width);
|
||||
__field(u32, channel_cfreq1);
|
||||
__dynamic_array(u32, arp_addr_list, info->arp_addr_cnt);
|
||||
__field(bool, arp_filter_enabled);
|
||||
__dynamic_array(u32, arp_addr_list,
|
||||
info->arp_addr_cnt > IEEE80211_BSS_ARP_ADDR_LIST_LEN ?
|
||||
IEEE80211_BSS_ARP_ADDR_LIST_LEN :
|
||||
info->arp_addr_cnt);
|
||||
__field(int, arp_addr_cnt);
|
||||
__field(bool, qos);
|
||||
__field(bool, idle);
|
||||
__field(bool, ps);
|
||||
@ -384,9 +387,11 @@ TRACE_EVENT(drv_bss_info_changed,
|
||||
__entry->cqm_rssi_hyst = info->cqm_rssi_hyst;
|
||||
__entry->channel_width = info->chandef.width;
|
||||
__entry->channel_cfreq1 = info->chandef.center_freq1;
|
||||
__entry->arp_addr_cnt = info->arp_addr_cnt;
|
||||
memcpy(__get_dynamic_array(arp_addr_list), info->arp_addr_list,
|
||||
sizeof(u32) * info->arp_addr_cnt);
|
||||
__entry->arp_filter_enabled = info->arp_filter_enabled;
|
||||
sizeof(u32) * (info->arp_addr_cnt > IEEE80211_BSS_ARP_ADDR_LIST_LEN ?
|
||||
IEEE80211_BSS_ARP_ADDR_LIST_LEN :
|
||||
info->arp_addr_cnt));
|
||||
__entry->qos = info->qos;
|
||||
__entry->idle = info->idle;
|
||||
__entry->ps = info->ps;
|
||||
@ -1184,23 +1189,26 @@ TRACE_EVENT(drv_set_rekey_data,
|
||||
|
||||
TRACE_EVENT(drv_rssi_callback,
|
||||
TP_PROTO(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
enum ieee80211_rssi_event rssi_event),
|
||||
|
||||
TP_ARGS(local, rssi_event),
|
||||
TP_ARGS(local, sdata, rssi_event),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
LOCAL_ENTRY
|
||||
VIF_ENTRY
|
||||
__field(u32, rssi_event)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
LOCAL_ASSIGN;
|
||||
VIF_ASSIGN;
|
||||
__entry->rssi_event = rssi_event;
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
LOCAL_PR_FMT " rssi_event:%d",
|
||||
LOCAL_PR_ARG, __entry->rssi_event
|
||||
LOCAL_PR_FMT VIF_PR_FMT " rssi_event:%d",
|
||||
LOCAL_PR_ARG, VIF_PR_ARG, __entry->rssi_event
|
||||
)
|
||||
);
|
||||
|
||||
@ -1432,6 +1440,14 @@ DEFINE_EVENT(local_only_evt, drv_restart_complete,
|
||||
TP_ARGS(local)
|
||||
);
|
||||
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
DEFINE_EVENT(local_sdata_evt, drv_ipv6_addr_change,
|
||||
TP_PROTO(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata),
|
||||
TP_ARGS(local, sdata)
|
||||
);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Tracing for API calls that drivers call.
|
||||
*/
|
||||
@ -1821,6 +1837,29 @@ TRACE_EVENT(stop_queue,
|
||||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(drv_set_default_unicast_key,
|
||||
TP_PROTO(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
int key_idx),
|
||||
|
||||
TP_ARGS(local, sdata, key_idx),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
LOCAL_ENTRY
|
||||
VIF_ENTRY
|
||||
__field(int, key_idx)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
LOCAL_ASSIGN;
|
||||
VIF_ASSIGN;
|
||||
__entry->key_idx = key_idx;
|
||||
),
|
||||
|
||||
TP_printk(LOCAL_PR_FMT VIF_PR_FMT " key_idx:%d",
|
||||
LOCAL_PR_ARG, VIF_PR_ARG, __entry->key_idx)
|
||||
);
|
||||
|
||||
#ifdef CONFIG_MAC80211_MESSAGE_TRACING
|
||||
#undef TRACE_SYSTEM
|
||||
#define TRACE_SYSTEM mac80211_msg
|
||||
|
@ -1787,16 +1787,16 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
|
||||
break;
|
||||
/* fall through */
|
||||
case NL80211_IFTYPE_AP:
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP)
|
||||
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
|
||||
if (!chanctx_conf)
|
||||
goto fail_rcu;
|
||||
fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
|
||||
/* DA BSSID SA */
|
||||
memcpy(hdr.addr1, skb->data, ETH_ALEN);
|
||||
memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN);
|
||||
memcpy(hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN);
|
||||
hdrlen = 24;
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP)
|
||||
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
|
||||
if (!chanctx_conf)
|
||||
goto fail_rcu;
|
||||
band = chanctx_conf->def.chan->band;
|
||||
break;
|
||||
case NL80211_IFTYPE_WDS:
|
||||
|
@ -478,6 +478,11 @@ int wiphy_register(struct wiphy *wiphy)
|
||||
ETH_ALEN)))
|
||||
return -EINVAL;
|
||||
|
||||
if (WARN_ON(wiphy->max_acl_mac_addrs &&
|
||||
(!(wiphy->flags & WIPHY_FLAG_HAVE_AP_SME) ||
|
||||
!rdev->ops->set_mac_acl)))
|
||||
return -EINVAL;
|
||||
|
||||
if (wiphy->addresses)
|
||||
memcpy(wiphy->perm_addr, wiphy->addresses[0].addr, ETH_ALEN);
|
||||
|
||||
|
@ -365,6 +365,8 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
|
||||
[NL80211_ATTR_SCAN_FLAGS] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_P2P_CTWINDOW] = { .type = NLA_U8 },
|
||||
[NL80211_ATTR_P2P_OPPPS] = { .type = NLA_U8 },
|
||||
[NL80211_ATTR_ACL_POLICY] = {. type = NLA_U32 },
|
||||
[NL80211_ATTR_MAC_ADDRS] = { .type = NLA_NESTED },
|
||||
};
|
||||
|
||||
/* policy for the key attributes */
|
||||
@ -1268,6 +1270,12 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 portid, u32 seq, int flag
|
||||
dev->wiphy.ht_capa_mod_mask))
|
||||
goto nla_put_failure;
|
||||
|
||||
if (dev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME &&
|
||||
dev->wiphy.max_acl_mac_addrs &&
|
||||
nla_put_u32(msg, NL80211_ATTR_MAC_ACL_MAX,
|
||||
dev->wiphy.max_acl_mac_addrs))
|
||||
goto nla_put_failure;
|
||||
|
||||
return genlmsg_end(msg, hdr);
|
||||
|
||||
nla_put_failure:
|
||||
@ -2491,6 +2499,97 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* This function returns an error or the number of nested attributes */
|
||||
static int validate_acl_mac_addrs(struct nlattr *nl_attr)
|
||||
{
|
||||
struct nlattr *attr;
|
||||
int n_entries = 0, tmp;
|
||||
|
||||
nla_for_each_nested(attr, nl_attr, tmp) {
|
||||
if (nla_len(attr) != ETH_ALEN)
|
||||
return -EINVAL;
|
||||
|
||||
n_entries++;
|
||||
}
|
||||
|
||||
return n_entries;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function parses ACL information and allocates memory for ACL data.
|
||||
* On successful return, the calling function is responsible to free the
|
||||
* ACL buffer returned by this function.
|
||||
*/
|
||||
static struct cfg80211_acl_data *parse_acl_data(struct wiphy *wiphy,
|
||||
struct genl_info *info)
|
||||
{
|
||||
enum nl80211_acl_policy acl_policy;
|
||||
struct nlattr *attr;
|
||||
struct cfg80211_acl_data *acl;
|
||||
int i = 0, n_entries, tmp;
|
||||
|
||||
if (!wiphy->max_acl_mac_addrs)
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
|
||||
if (!info->attrs[NL80211_ATTR_ACL_POLICY])
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
acl_policy = nla_get_u32(info->attrs[NL80211_ATTR_ACL_POLICY]);
|
||||
if (acl_policy != NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED &&
|
||||
acl_policy != NL80211_ACL_POLICY_DENY_UNLESS_LISTED)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
if (!info->attrs[NL80211_ATTR_MAC_ADDRS])
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
n_entries = validate_acl_mac_addrs(info->attrs[NL80211_ATTR_MAC_ADDRS]);
|
||||
if (n_entries < 0)
|
||||
return ERR_PTR(n_entries);
|
||||
|
||||
if (n_entries > wiphy->max_acl_mac_addrs)
|
||||
return ERR_PTR(-ENOTSUPP);
|
||||
|
||||
acl = kzalloc(sizeof(*acl) + (sizeof(struct mac_address) * n_entries),
|
||||
GFP_KERNEL);
|
||||
if (!acl)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
nla_for_each_nested(attr, info->attrs[NL80211_ATTR_MAC_ADDRS], tmp) {
|
||||
memcpy(acl->mac_addrs[i].addr, nla_data(attr), ETH_ALEN);
|
||||
i++;
|
||||
}
|
||||
|
||||
acl->n_acl_entries = n_entries;
|
||||
acl->acl_policy = acl_policy;
|
||||
|
||||
return acl;
|
||||
}
|
||||
|
||||
static int nl80211_set_mac_acl(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev = info->user_ptr[0];
|
||||
struct net_device *dev = info->user_ptr[1];
|
||||
struct cfg80211_acl_data *acl;
|
||||
int err;
|
||||
|
||||
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
|
||||
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!dev->ieee80211_ptr->beacon_interval)
|
||||
return -EINVAL;
|
||||
|
||||
acl = parse_acl_data(&rdev->wiphy, info);
|
||||
if (IS_ERR(acl))
|
||||
return PTR_ERR(acl);
|
||||
|
||||
err = rdev_set_mac_acl(rdev, dev, acl);
|
||||
|
||||
kfree(acl);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int nl80211_parse_beacon(struct genl_info *info,
|
||||
struct cfg80211_beacon_data *bcn)
|
||||
{
|
||||
@ -2734,6 +2833,12 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (info->attrs[NL80211_ATTR_ACL_POLICY]) {
|
||||
params.acl = parse_acl_data(&rdev->wiphy, info);
|
||||
if (IS_ERR(params.acl))
|
||||
return PTR_ERR(params.acl);
|
||||
}
|
||||
|
||||
err = rdev_start_ap(rdev, dev, ¶ms);
|
||||
if (!err) {
|
||||
wdev->preset_chandef = params.chandef;
|
||||
@ -2742,6 +2847,9 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
|
||||
wdev->ssid_len = params.ssid_len;
|
||||
memcpy(wdev->ssid, params.ssid, wdev->ssid_len);
|
||||
}
|
||||
|
||||
kfree(params.acl);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -7876,6 +7984,14 @@ static struct genl_ops nl80211_ops[] = {
|
||||
.internal_flags = NL80211_FLAG_NEED_NETDEV |
|
||||
NL80211_FLAG_NEED_RTNL,
|
||||
},
|
||||
{
|
||||
.cmd = NL80211_CMD_SET_MAC_ACL,
|
||||
.doit = nl80211_set_mac_acl,
|
||||
.policy = nl80211_policy,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
.internal_flags = NL80211_FLAG_NEED_NETDEV |
|
||||
NL80211_FLAG_NEED_RTNL,
|
||||
},
|
||||
};
|
||||
|
||||
static struct genl_multicast_group nl80211_mlme_mcgrp = {
|
||||
|
@ -875,4 +875,16 @@ static inline void rdev_stop_p2p_device(struct cfg80211_registered_device *rdev,
|
||||
rdev->ops->stop_p2p_device(&rdev->wiphy, wdev);
|
||||
trace_rdev_return_void(&rdev->wiphy);
|
||||
}
|
||||
|
||||
static inline int rdev_set_mac_acl(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev,
|
||||
struct cfg80211_acl_data *params)
|
||||
{
|
||||
int ret;
|
||||
|
||||
trace_rdev_set_mac_acl(&rdev->wiphy, dev, params);
|
||||
ret = rdev->ops->set_mac_acl(&rdev->wiphy, dev, params);
|
||||
trace_rdev_return_int(&rdev->wiphy, ret);
|
||||
return ret;
|
||||
}
|
||||
#endif /* __CFG80211_RDEV_OPS */
|
||||
|
@ -1767,6 +1767,24 @@ DEFINE_EVENT(wiphy_wdev_evt, rdev_stop_p2p_device,
|
||||
TP_ARGS(wiphy, wdev)
|
||||
);
|
||||
|
||||
TRACE_EVENT(rdev_set_mac_acl,
|
||||
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
|
||||
struct cfg80211_acl_data *params),
|
||||
TP_ARGS(wiphy, netdev, params),
|
||||
TP_STRUCT__entry(
|
||||
WIPHY_ENTRY
|
||||
NETDEV_ENTRY
|
||||
__field(u32, acl_policy)
|
||||
),
|
||||
TP_fast_assign(
|
||||
WIPHY_ASSIGN;
|
||||
WIPHY_ASSIGN;
|
||||
__entry->acl_policy = params->acl_policy;
|
||||
),
|
||||
TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", acl policy: %d",
|
||||
WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->acl_policy)
|
||||
);
|
||||
|
||||
/*************************************************************
|
||||
* cfg80211 exported functions traces *
|
||||
*************************************************************/
|
||||
|
@ -1212,7 +1212,8 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
case NL80211_IFTYPE_P2P_GO:
|
||||
case NL80211_IFTYPE_WDS:
|
||||
radar_required = !!(chan->flags & IEEE80211_CHAN_RADAR);
|
||||
radar_required = !!(chan &&
|
||||
(chan->flags & IEEE80211_CHAN_RADAR));
|
||||
break;
|
||||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
case NL80211_IFTYPE_STATION:
|
||||
|
Loading…
Reference in New Issue
Block a user