提交 20fb9e50 编写于 作者: J John W. Linville
...@@ -542,9 +542,8 @@ brcms_ops_bss_info_changed(struct ieee80211_hw *hw, ...@@ -542,9 +542,8 @@ brcms_ops_bss_info_changed(struct ieee80211_hw *hw,
if (changed & BSS_CHANGED_ARP_FILTER) { if (changed & BSS_CHANGED_ARP_FILTER) {
/* Hardware ARP filter address list or state changed */ /* Hardware ARP filter address list or state changed */
brcms_err(core, "%s: arp filtering: enabled %s, count %d" brcms_err(core, "%s: arp filtering: %d addresses"
" (implement)\n", __func__, info->arp_filter_enabled ? " (implement)\n", __func__, info->arp_addr_cnt);
"true" : "false", info->arp_addr_cnt);
} }
if (changed & BSS_CHANGED_QOS) { if (changed & BSS_CHANGED_QOS) {
......
...@@ -1154,6 +1154,7 @@ static int iwlagn_mac_cancel_remain_on_channel(struct ieee80211_hw *hw) ...@@ -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, static void iwlagn_mac_rssi_callback(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
enum ieee80211_rssi_event rssi_event) enum ieee80211_rssi_event rssi_event)
{ {
struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
......
...@@ -4239,8 +4239,7 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, ...@@ -4239,8 +4239,7 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
wlvif->sta.qos = bss_conf->qos; wlvif->sta.qos = bss_conf->qos;
WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS); WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS);
if (bss_conf->arp_addr_cnt == 1 && if (bss_conf->arp_addr_cnt == 1 && bss_conf->assoc) {
bss_conf->arp_filter_enabled) {
wlvif->ip_addr = addr; wlvif->ip_addr = addr;
/* /*
* The template should have been configured only upon * The template should have been configured only upon
......
...@@ -1898,7 +1898,10 @@ enum ieee80211_sa_query_action { ...@@ -1898,7 +1898,10 @@ enum ieee80211_sa_query_action {
/* AKM suite selectors */ /* AKM suite selectors */
#define WLAN_AKM_SUITE_8021X 0x000FAC01 #define WLAN_AKM_SUITE_8021X 0x000FAC01
#define WLAN_AKM_SUITE_PSK 0x000FAC02 #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_AKM_SUITE_FT_OVER_SAE 0x000FAC09
#define WLAN_MAX_KEY_LEN 32 #define WLAN_MAX_KEY_LEN 32
......
...@@ -527,6 +527,26 @@ struct cfg80211_beacon_data { ...@@ -527,6 +527,26 @@ struct cfg80211_beacon_data {
size_t probe_resp_len; 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 * struct cfg80211_ap_settings - AP configuration
* *
...@@ -546,6 +566,8 @@ struct cfg80211_beacon_data { ...@@ -546,6 +566,8 @@ struct cfg80211_beacon_data {
* @inactivity_timeout: time in seconds to determine station's inactivity. * @inactivity_timeout: time in seconds to determine station's inactivity.
* @p2p_ctwindow: P2P CT Window * @p2p_ctwindow: P2P CT Window
* @p2p_opp_ps: P2P opportunistic PS * @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_ap_settings {
struct cfg80211_chan_def chandef; struct cfg80211_chan_def chandef;
...@@ -562,6 +584,7 @@ struct cfg80211_ap_settings { ...@@ -562,6 +584,7 @@ struct cfg80211_ap_settings {
int inactivity_timeout; int inactivity_timeout;
u8 p2p_ctwindow; u8 p2p_ctwindow;
bool p2p_opp_ps; bool p2p_opp_ps;
const struct cfg80211_acl_data *acl;
}; };
/** /**
...@@ -1796,6 +1819,13 @@ struct cfg80211_gtk_rekey_data { ...@@ -1796,6 +1819,13 @@ struct cfg80211_gtk_rekey_data {
* *
* @start_p2p_device: Start the given P2P device. * @start_p2p_device: Start the given P2P device.
* @stop_p2p_device: Stop 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 { struct cfg80211_ops {
int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
...@@ -2016,6 +2046,9 @@ struct cfg80211_ops { ...@@ -2016,6 +2046,9 @@ struct cfg80211_ops {
struct wireless_dev *wdev); struct wireless_dev *wdev);
void (*stop_p2p_device)(struct wiphy *wiphy, void (*stop_p2p_device)(struct wiphy *wiphy,
struct wireless_dev *wdev); 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 { ...@@ -2181,10 +2214,6 @@ struct ieee80211_iface_combination {
u8 radar_detect_widths; u8 radar_detect_widths;
}; };
struct mac_address {
u8 addr[ETH_ALEN];
};
struct ieee80211_txrx_stypes { struct ieee80211_txrx_stypes {
u16 tx, rx; u16 tx, rx;
}; };
...@@ -2325,6 +2354,9 @@ struct wiphy_wowlan_support { ...@@ -2325,6 +2354,9 @@ struct wiphy_wowlan_support {
* @ap_sme_capa: AP SME capabilities, flags from &enum nl80211_ap_sme_features. * @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. * @ht_capa_mod_mask: Specify what ht_cap values can be over-ridden.
* If null, then none 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 { struct wiphy {
/* assign these fields before you register the wiphy */ /* assign these fields before you register the wiphy */
...@@ -2346,6 +2378,8 @@ struct wiphy { ...@@ -2346,6 +2378,8 @@ struct wiphy {
/* Supported interface modes, OR together BIT(NL80211_IFTYPE_...) */ /* Supported interface modes, OR together BIT(NL80211_IFTYPE_...) */
u16 interface_modes; u16 interface_modes;
u16 max_acl_mac_addrs;
u32 flags, features; u32 flags, features;
u32 ap_sme_capa; u32 ap_sme_capa;
......
...@@ -297,11 +297,9 @@ enum ieee80211_rssi_event { ...@@ -297,11 +297,9 @@ enum ieee80211_rssi_event {
* may filter ARP queries targeted for other addresses than listed here. * may filter ARP queries targeted for other addresses than listed here.
* The driver must allow ARP queries targeted for all address 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. * to pass through. An empty list implies no ARP queries need to pass.
* @arp_addr_cnt: Number of addresses currently on the list. * @arp_addr_cnt: Number of addresses currently on the list. Note that this
* @arp_filter_enabled: Enable ARP filtering - if enabled, the hardware may * may be larger than %IEEE80211_BSS_ARP_ADDR_LIST_LEN (the arp_addr_list
* filter ARP queries based on the @arp_addr_list, if disabled, the * array size), it's up to the driver what to do in that case.
* hardware must not perform any ARP filtering. Note, that the filter will
* be enabled also in promiscuous mode.
* @qos: This is a QoS-enabled BSS. * @qos: This is a QoS-enabled BSS.
* @idle: This interface is idle. There's also a global idle flag in the * @idle: This interface is idle. There's also a global idle flag in the
* hardware config which may be more appropriate depending on what * hardware config which may be more appropriate depending on what
...@@ -338,8 +336,7 @@ struct ieee80211_bss_conf { ...@@ -338,8 +336,7 @@ struct ieee80211_bss_conf {
u32 cqm_rssi_hyst; u32 cqm_rssi_hyst;
struct cfg80211_chan_def chandef; struct cfg80211_chan_def chandef;
__be32 arp_addr_list[IEEE80211_BSS_ARP_ADDR_LIST_LEN]; __be32 arp_addr_list[IEEE80211_BSS_ARP_ADDR_LIST_LEN];
u8 arp_addr_cnt; int arp_addr_cnt;
bool arp_filter_enabled;
bool qos; bool qos;
bool idle; bool idle;
bool ps; bool ps;
...@@ -1630,6 +1627,10 @@ void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb); ...@@ -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 * 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 * provided by update_tkip_key only. The trigger that makes mac80211 call this
* handler is software decryption with wrap around of iv16. * 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 { ...@@ -2208,6 +2209,10 @@ enum ieee80211_rate_control_changed {
* After rekeying was done it should (for example during resume) notify * After rekeying was done it should (for example during resume) notify
* userspace of the new replay counter using ieee80211_gtk_rekey_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 * @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 * the scan state machine in stack. The scan must honour the channel
* configuration done by the regulatory agent in the wiphy's * configuration done by the regulatory agent in the wiphy's
...@@ -2492,6 +2497,9 @@ enum ieee80211_rate_control_changed { ...@@ -2492,6 +2497,9 @@ enum ieee80211_rate_control_changed {
* driver's resume function returned 1, as this is just like an "inline" * driver's resume function returned 1, as this is just like an "inline"
* hardware restart. This callback may sleep. * 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 { struct ieee80211_ops {
void (*tx)(struct ieee80211_hw *hw, void (*tx)(struct ieee80211_hw *hw,
...@@ -2539,6 +2547,8 @@ struct ieee80211_ops { ...@@ -2539,6 +2547,8 @@ struct ieee80211_ops {
void (*set_rekey_data)(struct ieee80211_hw *hw, void (*set_rekey_data)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
struct cfg80211_gtk_rekey_data *data); 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, int (*hw_scan)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct cfg80211_scan_request *req); struct cfg80211_scan_request *req);
void (*cancel_hw_scan)(struct ieee80211_hw *hw, void (*cancel_hw_scan)(struct ieee80211_hw *hw,
...@@ -2623,6 +2633,7 @@ struct ieee80211_ops { ...@@ -2623,6 +2633,7 @@ struct ieee80211_ops {
int (*set_bitrate_mask)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int (*set_bitrate_mask)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
const struct cfg80211_bitrate_mask *mask); const struct cfg80211_bitrate_mask *mask);
void (*rssi_callback)(struct ieee80211_hw *hw, void (*rssi_callback)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
enum ieee80211_rssi_event rssi_event); enum ieee80211_rssi_event rssi_event);
void (*allow_buffered_frames)(struct ieee80211_hw *hw, void (*allow_buffered_frames)(struct ieee80211_hw *hw,
...@@ -2665,6 +2676,12 @@ struct ieee80211_ops { ...@@ -2665,6 +2676,12 @@ struct ieee80211_ops {
struct ieee80211_chanctx_conf *ctx); struct ieee80211_chanctx_conf *ctx);
void (*restart_complete)(struct ieee80211_hw *hw); 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 @@ ...@@ -170,7 +170,8 @@
* %NL80211_ATTR_HIDDEN_SSID, %NL80211_ATTR_CIPHERS_PAIRWISE, * %NL80211_ATTR_HIDDEN_SSID, %NL80211_ATTR_CIPHERS_PAIRWISE,
* %NL80211_ATTR_CIPHER_GROUP, %NL80211_ATTR_WPA_VERSIONS, * %NL80211_ATTR_CIPHER_GROUP, %NL80211_ATTR_WPA_VERSIONS,
* %NL80211_ATTR_AKM_SUITES, %NL80211_ATTR_PRIVACY, * %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 * 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_ATTR_WIPHY_FREQ and the attributes determining channel width.
* @NL80211_CMD_NEW_BEACON: old alias for %NL80211_CMD_START_AP * @NL80211_CMD_NEW_BEACON: old alias for %NL80211_CMD_START_AP
...@@ -586,6 +587,16 @@ ...@@ -586,6 +587,16 @@
* @NL80211_CMD_SET_MCAST_RATE: Change the rate used to send multicast frames * @NL80211_CMD_SET_MCAST_RATE: Change the rate used to send multicast frames
* for IBSS or MESH vif. * 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_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use * @__NL80211_CMD_AFTER_LAST: internal use
*/ */
...@@ -736,6 +747,8 @@ enum nl80211_commands { ...@@ -736,6 +747,8 @@ enum nl80211_commands {
NL80211_CMD_SET_MCAST_RATE, NL80211_CMD_SET_MCAST_RATE,
NL80211_CMD_SET_MAC_ACL,
/* add new commands above here */ /* add new commands above here */
/* used to define NL80211_CMD_MAX below */ /* used to define NL80211_CMD_MAX below */
...@@ -1313,6 +1326,16 @@ enum nl80211_commands { ...@@ -1313,6 +1326,16 @@ enum nl80211_commands {
* @NL80211_ATTR_LOCAL_MESH_POWER_MODE: local mesh STA link-specific power mode * @NL80211_ATTR_LOCAL_MESH_POWER_MODE: local mesh STA link-specific power mode
* defined in &enum nl80211_mesh_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_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use * @__NL80211_ATTR_AFTER_LAST: internal use
*/ */
...@@ -1585,6 +1608,12 @@ enum nl80211_attrs { ...@@ -1585,6 +1608,12 @@ enum nl80211_attrs {
NL80211_ATTR_LOCAL_MESH_POWER_MODE, 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 */ /* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST, __NL80211_ATTR_AFTER_LAST,
...@@ -3248,7 +3277,7 @@ enum nl80211_probe_resp_offload_support_attr { ...@@ -3248,7 +3277,7 @@ enum nl80211_probe_resp_offload_support_attr {
* enum nl80211_connect_failed_reason - connection request failed reasons * enum nl80211_connect_failed_reason - connection request failed reasons
* @NL80211_CONN_FAIL_MAX_CLIENTS: Maximum number of clients that can be * @NL80211_CONN_FAIL_MAX_CLIENTS: Maximum number of clients that can be
* handled by the AP is reached. * 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 { enum nl80211_connect_failed_reason {
NL80211_CONN_FAIL_MAX_CLIENTS, NL80211_CONN_FAIL_MAX_CLIENTS,
...@@ -3276,4 +3305,22 @@ enum nl80211_scan_flags { ...@@ -3276,4 +3305,22 @@ enum nl80211_scan_flags {
NL80211_SCAN_FLAG_AP = 1<<2, 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 */ #endif /* __LINUX_NL80211_H */
...@@ -83,8 +83,8 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, ...@@ -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, if (drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_STOP,
&sta->sta, tid, NULL, 0)) &sta->sta, tid, NULL, 0))
sdata_info(sta->sdata, sdata_info(sta->sdata,
"HW problem - can not stop rx aggregation for tid %d\n", "HW problem - can not stop rx aggregation for %pM tid %d\n",
tid); sta->sta.addr, tid);
/* check if this is a self generated aggregation halt */ /* check if this is a self generated aggregation halt */
if (initiator == WLAN_BACK_RECIPIENT && tx) if (initiator == WLAN_BACK_RECIPIENT && tx)
...@@ -159,7 +159,8 @@ static void sta_rx_agg_session_timer_expired(unsigned long data) ...@@ -159,7 +159,8 @@ static void sta_rx_agg_session_timer_expired(unsigned long data)
} }
rcu_read_unlock(); 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); set_bit(*ptid, sta->ampdu_mlme.tid_rx_timer_expired);
ieee80211_queue_work(&sta->local->hw, &sta->ampdu_mlme.work); ieee80211_queue_work(&sta->local->hw, &sta->ampdu_mlme.work);
...@@ -247,7 +248,9 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, ...@@ -247,7 +248,9 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
status = WLAN_STATUS_REQUEST_DECLINED; status = WLAN_STATUS_REQUEST_DECLINED;
if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) { 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; goto end_no_lock;
} }
...@@ -317,7 +320,8 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, ...@@ -317,7 +320,8 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
ret = drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_START, ret = drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_START,
&sta->sta, tid, &start_seq_num, 0); &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) { if (ret) {
kfree(tid_agg_rx->reorder_buf); kfree(tid_agg_rx->reorder_buf);
kfree(tid_agg_rx->reorder_time); kfree(tid_agg_rx->reorder_time);
......
...@@ -296,7 +296,7 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, ...@@ -296,7 +296,7 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
IEEE80211_AMPDU_TX_STOP_FLUSH_CONT, IEEE80211_AMPDU_TX_STOP_FLUSH_CONT,
&sta->sta, tid, NULL, 0); &sta->sta, tid, NULL, 0);
WARN_ON_ONCE(ret); WARN_ON_ONCE(ret);
goto remove_tid_tx; return 0;
} }
if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) { 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, ...@@ -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: * In the case of AGG_STOP_DESTROY_STA, the driver won't
spin_lock_bh(&sta->lock); * necessarily call ieee80211_stop_tx_ba_cb(), so this may
ieee80211_remove_tid_tx(sta, tid); * seem like we can leave the tid_tx data pending forever.
spin_unlock_bh(&sta->lock); * 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; return 0;
} }
...@@ -387,12 +390,13 @@ static void sta_addba_resp_timer_expired(unsigned long data) ...@@ -387,12 +390,13 @@ static void sta_addba_resp_timer_expired(unsigned long data)
test_bit(HT_AGG_STATE_RESPONSE_RECEIVED, &tid_tx->state)) { test_bit(HT_AGG_STATE_RESPONSE_RECEIVED, &tid_tx->state)) {
rcu_read_unlock(); rcu_read_unlock();
ht_dbg(sta->sdata, ht_dbg(sta->sdata,
"timer expired on tid %d but we are not (or no longer) expecting addBA response there\n", "timer expired on %pM tid %d but we are not (or no longer) expecting addBA response there\n",
tid); sta->sta.addr, tid);
return; 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); ieee80211_stop_tx_ba_session(&sta->sta, tid);
rcu_read_unlock(); rcu_read_unlock();
...@@ -429,7 +433,8 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) ...@@ -429,7 +433,8 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
&sta->sta, tid, &start_seq_num, 0); &sta->sta, tid, &start_seq_num, 0);
if (ret) { if (ret) {
ht_dbg(sdata, 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); spin_lock_bh(&sta->lock);
ieee80211_agg_splice_packets(sdata, tid_tx, tid); ieee80211_agg_splice_packets(sdata, tid_tx, tid);
ieee80211_assign_tid_tx(sta, tid, NULL); ieee80211_assign_tid_tx(sta, tid, NULL);
...@@ -442,7 +447,8 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) ...@@ -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 */ /* activate the timer for the recipient's addBA response */
mod_timer(&tid_tx->addba_resp_timer, jiffies + ADDBA_RESP_INTERVAL); 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); spin_lock_bh(&sta->lock);
sta->ampdu_mlme.last_addba_req_time[tid] = jiffies; sta->ampdu_mlme.last_addba_req_time[tid] = jiffies;
...@@ -489,7 +495,8 @@ static void sta_tx_agg_session_timer_expired(unsigned long data) ...@@ -489,7 +495,8 @@ static void sta_tx_agg_session_timer_expired(unsigned long data)
rcu_read_unlock(); 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); ieee80211_stop_tx_ba_session(&sta->sta, *ptid);
} }
...@@ -525,7 +532,8 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, ...@@ -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)) { if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) {
ht_dbg(sdata, 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; return -EINVAL;
} }
...@@ -566,8 +574,8 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, ...@@ -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] + time_before(jiffies, sta->ampdu_mlme.last_addba_req_time[tid] +
HT_AGG_RETRIES_PERIOD)) { HT_AGG_RETRIES_PERIOD)) {
ht_dbg(sdata, ht_dbg(sdata,
"BA request denied - waiting a grace period after %d failed requests on tid %u\n", "BA request denied - waiting a grace period after %d failed requests on %pM tid %u\n",
sta->ampdu_mlme.addba_req_num[tid], tid); sta->ampdu_mlme.addba_req_num[tid], sta->sta.addr, tid);
ret = -EBUSY; ret = -EBUSY;
goto err_unlock_sta; goto err_unlock_sta;
} }
...@@ -576,8 +584,8 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, ...@@ -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 */ /* check if the TID is not in aggregation flow already */
if (tid_tx || sta->ampdu_mlme.tid_start_tx[tid]) { if (tid_tx || sta->ampdu_mlme.tid_start_tx[tid]) {
ht_dbg(sdata, ht_dbg(sdata,
"BA request denied - session is not idle on tid %u\n", "BA request denied - session is not idle on %pM tid %u\n",
tid); sta->sta.addr, tid);
ret = -EAGAIN; ret = -EAGAIN;
goto err_unlock_sta; goto err_unlock_sta;
} }
...@@ -632,7 +640,8 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local, ...@@ -632,7 +640,8 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local,
tid_tx = rcu_dereference_protected_tid_tx(sta, tid); 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, drv_ampdu_action(local, sta->sdata,
IEEE80211_AMPDU_TX_OPERATIONAL, IEEE80211_AMPDU_TX_OPERATIONAL,
...@@ -802,7 +811,9 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid) ...@@ -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); tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
if (!tid_tx || !test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) { 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; goto unlock_sta;
} }
...@@ -861,13 +872,15 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local, ...@@ -861,13 +872,15 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
goto out; goto out;
if (mgmt->u.action.u.addba_resp.dialog_token != tid_tx->dialog_token) { 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; goto out;
} }
del_timer_sync(&tid_tx->addba_resp_timer); 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 * addba_resp_timer may have fired before we got here, and
...@@ -877,8 +890,8 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local, ...@@ -877,8 +890,8 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
if (test_bit(HT_AGG_STATE_WANT_STOP, &tid_tx->state) || if (test_bit(HT_AGG_STATE_WANT_STOP, &tid_tx->state) ||
test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) { test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) {
ht_dbg(sta->sdata, ht_dbg(sta->sdata,
"got addBA resp for tid %d but we already gave up\n", "got addBA resp for %pM tid %d but we already gave up\n",
tid); sta->sta.addr, tid);
goto out; goto out;
} }
......
...@@ -569,7 +569,8 @@ static inline void drv_sta_rc_update(struct ieee80211_local *local, ...@@ -569,7 +569,8 @@ static inline void drv_sta_rc_update(struct ieee80211_local *local,
check_sdata_in_driver(sdata); check_sdata_in_driver(sdata);
WARN_ON(changed & IEEE80211_RC_SUPP_RATES_CHANGED && 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); trace_drv_sta_rc_update(local, sdata, sta, changed);
if (local->ops->sta_rc_update) if (local->ops->sta_rc_update)
...@@ -845,11 +846,12 @@ static inline void drv_set_rekey_data(struct ieee80211_local *local, ...@@ -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, static inline void drv_rssi_callback(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
const enum ieee80211_rssi_event event) const enum ieee80211_rssi_event event)
{ {
trace_drv_rssi_callback(local, event); trace_drv_rssi_callback(local, sdata, event);
if (local->ops->rssi_callback) 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); trace_drv_return_void(local);
} }
...@@ -1020,4 +1022,32 @@ static inline void drv_restart_complete(struct ieee80211_local *local) ...@@ -1020,4 +1022,32 @@ static inline void drv_restart_complete(struct ieee80211_local *local)
trace_drv_return_void(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 */ #endif /* __MAC80211_DRIVER_OPS */
...@@ -747,8 +747,6 @@ struct ieee80211_sub_if_data { ...@@ -747,8 +747,6 @@ struct ieee80211_sub_if_data {
struct work_struct work; struct work_struct work;
struct sk_buff_head skb_queue; struct sk_buff_head skb_queue;
bool arp_filter_state;
u8 needed_rx_chains; u8 needed_rx_chains;
enum ieee80211_smps_mode smps_mode; enum ieee80211_smps_mode smps_mode;
...@@ -1129,6 +1127,7 @@ struct ieee80211_local { ...@@ -1129,6 +1127,7 @@ struct ieee80211_local {
struct timer_list dynamic_ps_timer; struct timer_list dynamic_ps_timer;
struct notifier_block network_latency_notifier; struct notifier_block network_latency_notifier;
struct notifier_block ifa_notifier; struct notifier_block ifa_notifier;
struct notifier_block ifa6_notifier;
/* /*
* The dynamic ps timeout configured from user space via WEXT - * 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, ...@@ -1574,9 +1574,6 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
/* initialise type-independent data */ /* initialise type-independent data */
sdata->wdev.wiphy = local->hw.wiphy; sdata->wdev.wiphy = local->hw.wiphy;
sdata->local = local; sdata->local = local;
#ifdef CONFIG_INET
sdata->arp_filter_state = true;
#endif
for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++)
skb_queue_head_init(&sdata->fragments[i].skb_list); 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, ...@@ -204,8 +204,11 @@ static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata,
if (idx >= 0 && idx < NUM_DEFAULT_KEYS) if (idx >= 0 && idx < NUM_DEFAULT_KEYS)
key = key_mtx_dereference(sdata->local, sdata->keys[idx]); key = key_mtx_dereference(sdata->local, sdata->keys[idx]);
if (uni) if (uni) {
rcu_assign_pointer(sdata->default_unicast_key, key); rcu_assign_pointer(sdata->default_unicast_key, key);
drv_set_default_unicast_key(sdata->local, sdata, idx);
}
if (multi) if (multi)
rcu_assign_pointer(sdata->default_multicast_key, key); rcu_assign_pointer(sdata->default_multicast_key, key);
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <linux/inetdevice.h> #include <linux/inetdevice.h>
#include <net/net_namespace.h> #include <net/net_namespace.h>
#include <net/cfg80211.h> #include <net/cfg80211.h>
#include <net/addrconf.h>
#include "ieee80211_i.h" #include "ieee80211_i.h"
#include "driver-ops.h" #include "driver-ops.h"
...@@ -349,27 +350,19 @@ static int ieee80211_ifa_changed(struct notifier_block *nb, ...@@ -349,27 +350,19 @@ static int ieee80211_ifa_changed(struct notifier_block *nb,
/* Copy the addresses to the bss_conf list */ /* Copy the addresses to the bss_conf list */
ifa = idev->ifa_list; ifa = idev->ifa_list;
while (c < IEEE80211_BSS_ARP_ADDR_LIST_LEN && ifa) { while (ifa) {
bss_conf->arp_addr_list[c] = ifa->ifa_address; if (c < IEEE80211_BSS_ARP_ADDR_LIST_LEN)
bss_conf->arp_addr_list[c] = ifa->ifa_address;
ifa = ifa->ifa_next; ifa = ifa->ifa_next;
c++; 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; bss_conf->arp_addr_cnt = c;
/* Configure driver only if associated (which also implies it is up) */ /* Configure driver only if associated (which also implies it is up) */
if (ifmgd->associated) { if (ifmgd->associated)
bss_conf->arp_filter_enabled = sdata->arp_filter_state;
ieee80211_bss_info_change_notify(sdata, ieee80211_bss_info_change_notify(sdata,
BSS_CHANGED_ARP_FILTER); BSS_CHANGED_ARP_FILTER);
}
mutex_unlock(&ifmgd->mtx); mutex_unlock(&ifmgd->mtx);
...@@ -377,6 +370,37 @@ static int ieee80211_ifa_changed(struct notifier_block *nb, ...@@ -377,6 +370,37 @@ static int ieee80211_ifa_changed(struct notifier_block *nb,
} }
#endif #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) static int ieee80211_napi_poll(struct napi_struct *napi, int budget)
{ {
struct ieee80211_local *local = struct ieee80211_local *local =
...@@ -985,12 +1009,25 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) ...@@ -985,12 +1009,25 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
goto fail_ifa; goto fail_ifa;
#endif #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, netif_napi_add(&local->napi_dev, &local->napi, ieee80211_napi_poll,
local->hw.napi_weight); local->hw.napi_weight);
return 0; return 0;
#if IS_ENABLED(CONFIG_IPV6)
fail_ifa6:
#ifdef CONFIG_INET #ifdef CONFIG_INET
unregister_inetaddr_notifier(&local->ifa_notifier);
#endif
#endif
#if defined(CONFIG_INET) || defined(CONFIG_IPV6)
fail_ifa: fail_ifa:
pm_qos_remove_notifier(PM_QOS_NETWORK_LATENCY, pm_qos_remove_notifier(PM_QOS_NETWORK_LATENCY,
&local->network_latency_notifier); &local->network_latency_notifier);
...@@ -1026,6 +1063,9 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) ...@@ -1026,6 +1063,9 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
#ifdef CONFIG_INET #ifdef CONFIG_INET
unregister_inetaddr_notifier(&local->ifa_notifier); unregister_inetaddr_notifier(&local->ifa_notifier);
#endif #endif
#if IS_ENABLED(CONFIG_IPV6)
unregister_inet6addr_notifier(&local->ifa6_notifier);
#endif
rtnl_lock(); rtnl_lock();
......
...@@ -55,30 +55,6 @@ static inline void mesh_plink_fsm_restart(struct sta_info *sta) ...@@ -55,30 +55,6 @@ static inline void mesh_plink_fsm_restart(struct sta_info *sta)
sta->plink_retries = 0; 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 * mesh_set_ht_prot_mode - set correct HT protection mode
* *
...@@ -309,53 +285,27 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, ...@@ -309,53 +285,27 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
return err; return err;
} }
/** static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata,
* mesh_peer_init - initialize new mesh peer and return resulting sta_info struct sta_info *sta,
* struct ieee802_11_elems *elems, bool insert)
* @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)
{ {
struct ieee80211_local *local = sdata->local; struct ieee80211_local *local = sdata->local;
enum ieee80211_band band = ieee80211_get_sdata_band(sdata); enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
struct ieee80211_supported_band *sband; struct ieee80211_supported_band *sband;
u32 rates, basic_rates = 0; u32 rates, basic_rates = 0, changed = 0;
struct sta_info *sta;
bool insert = false;
sband = local->hw.wiphy->bands[band]; sband = local->hw.wiphy->bands[band];
rates = ieee80211_sta_get_rates(local, elems, band, &basic_rates); 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); spin_lock_bh(&sta->lock);
sta->last_rx = jiffies; 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; sta->sta.supp_rates[band] = rates;
if (elems->ht_cap_elem && if (elems->ht_cap_elem &&
sdata->vif.bss_conf.chandef.width != NL80211_CHAN_WIDTH_20_NOHT) 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, ...@@ -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_CAP_SUP_WIDTH_20_40;
ieee80211_ht_oper_to_chandef(sdata->vif.bss_conf.chandef.chan, ieee80211_ht_oper_to_chandef(sdata->vif.bss_conf.chandef.chan,
elems->ht_operation, &chandef); elems->ht_operation, &chandef);
if (sta->ch_width != chandef.width)
changed |= IEEE80211_RC_BW_CHANGED;
sta->ch_width = chandef.width; sta->ch_width = chandef.width;
} }
if (insert) if (insert)
rate_control_rate_init(sta); rate_control_rate_init(sta);
else
rate_control_rate_update(local, sband, sta, changed);
out:
spin_unlock_bh(&sta->lock); spin_unlock_bh(&sta->lock);
}
static struct sta_info *
__mesh_sta_info_alloc(struct ieee80211_sub_if_data *sdata, u8 *hw_addr)
{
struct sta_info *sta;
if (insert && sta_info_insert(sta)) if (sdata->local->num_sta >= MESH_MAX_PLINKS)
return NULL; 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; 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, void mesh_neighbour_update(struct ieee80211_sub_if_data *sdata,
u8 *hw_addr, u8 *hw_addr,
struct ieee802_11_elems *elems) struct ieee802_11_elems *elems)
{ {
struct sta_info *sta; struct sta_info *sta;
rcu_read_lock(); sta = mesh_sta_info_get(sdata, hw_addr, elems);
sta = mesh_peer_init(sdata, hw_addr, elems);
if (!sta) if (!sta)
goto out; goto out;
...@@ -632,6 +670,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m ...@@ -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)) (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len == 8))
memcpy(&llid, PLINK_GET_PLID(elems.peering), 2); memcpy(&llid, PLINK_GET_PLID(elems.peering), 2);
/* WARNING: Only for sta pointer, is dropped & re-acquired */
rcu_read_lock(); rcu_read_lock();
sta = sta_info_get(sdata, mgmt->sa); 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 ...@@ -735,8 +774,9 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
} }
if (event == OPN_ACPT) { if (event == OPN_ACPT) {
rcu_read_unlock();
/* allocate sta entry if necessary and update info */ /* 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) { if (!sta) {
mpl_dbg(sdata, "Mesh plink: failed to init peer!\n"); mpl_dbg(sdata, "Mesh plink: failed to init peer!\n");
rcu_read_unlock(); rcu_read_unlock();
......
...@@ -1465,10 +1465,8 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, ...@@ -1465,10 +1465,8 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
bss_info_changed |= BSS_CHANGED_CQM; bss_info_changed |= BSS_CHANGED_CQM;
/* Enable ARP filtering */ /* Enable ARP filtering */
if (bss_conf->arp_filter_enabled != sdata->arp_filter_state) { if (bss_conf->arp_addr_cnt)
bss_conf->arp_filter_enabled = sdata->arp_filter_state;
bss_info_changed |= BSS_CHANGED_ARP_FILTER; bss_info_changed |= BSS_CHANGED_ARP_FILTER;
}
ieee80211_bss_info_change_notify(sdata, bss_info_changed); ieee80211_bss_info_change_notify(sdata, bss_info_changed);
...@@ -1489,7 +1487,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, ...@@ -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_if_managed *ifmgd = &sdata->u.mgd;
struct ieee80211_local *local = sdata->local; struct ieee80211_local *local = sdata->local;
struct sta_info *sta;
u32 changed = 0; u32 changed = 0;
ASSERT_MGD_MTX(ifmgd); ASSERT_MGD_MTX(ifmgd);
...@@ -1521,14 +1518,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, ...@@ -1521,14 +1518,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
netif_tx_stop_all_queues(sdata->dev); netif_tx_stop_all_queues(sdata->dev);
netif_carrier_off(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 * if we want to get out of ps before disassoc (why?) we have
* to do it before sending disassoc, as otherwise the null-packet * 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, ...@@ -1582,10 +1571,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
cancel_work_sync(&local->dynamic_ps_enable_work); cancel_work_sync(&local->dynamic_ps_enable_work);
/* Disable ARP filtering */ /* Disable ARP filtering */
if (sdata->vif.bss_conf.arp_filter_enabled) { if (sdata->vif.bss_conf.arp_addr_cnt)
sdata->vif.bss_conf.arp_filter_enabled = false;
changed |= BSS_CHANGED_ARP_FILTER; changed |= BSS_CHANGED_ARP_FILTER;
}
sdata->vif.bss_conf.qos = false; sdata->vif.bss_conf.qos = false;
changed |= BSS_CHANGED_QOS; changed |= BSS_CHANGED_QOS;
...@@ -2608,12 +2595,12 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, ...@@ -2608,12 +2595,12 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
if (sig > ifmgd->rssi_max_thold && if (sig > ifmgd->rssi_max_thold &&
(last_sig <= ifmgd->rssi_min_thold || last_sig == 0)) { (last_sig <= ifmgd->rssi_min_thold || last_sig == 0)) {
ifmgd->last_ave_beacon_signal = sig; 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 && } else if (sig < ifmgd->rssi_min_thold &&
(last_sig >= ifmgd->rssi_max_thold || (last_sig >= ifmgd->rssi_max_thold ||
last_sig == 0)) { last_sig == 0)) {
ifmgd->last_ave_beacon_signal = sig; 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) ...@@ -3169,23 +3156,22 @@ void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata)
{ {
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
if (!ifmgd->associated) mutex_lock(&ifmgd->mtx);
if (!ifmgd->associated) {
mutex_unlock(&ifmgd->mtx);
return; return;
}
if (sdata->flags & IEEE80211_SDATA_DISCONNECT_RESUME) { if (sdata->flags & IEEE80211_SDATA_DISCONNECT_RESUME) {
sdata->flags &= ~IEEE80211_SDATA_DISCONNECT_RESUME; sdata->flags &= ~IEEE80211_SDATA_DISCONNECT_RESUME;
mutex_lock(&ifmgd->mtx); mlme_dbg(sdata, "driver requested disconnect after resume\n");
if (ifmgd->associated) { ieee80211_sta_connection_lost(sdata,
mlme_dbg(sdata, ifmgd->associated->bssid,
"driver requested disconnect after resume\n"); WLAN_REASON_UNSPECIFIED);
ieee80211_sta_connection_lost(sdata,
ifmgd->associated->bssid,
WLAN_REASON_UNSPECIFIED);
mutex_unlock(&ifmgd->mtx);
return;
}
mutex_unlock(&ifmgd->mtx); mutex_unlock(&ifmgd->mtx);
return;
} }
mutex_unlock(&ifmgd->mtx);
if (test_and_clear_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running)) if (test_and_clear_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running))
add_timer(&ifmgd->timer); add_timer(&ifmgd->timer);
......
...@@ -380,11 +380,6 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, ...@@ -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); 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; return sta;
} }
......
...@@ -347,8 +347,11 @@ TRACE_EVENT(drv_bss_info_changed, ...@@ -347,8 +347,11 @@ TRACE_EVENT(drv_bss_info_changed,
__field(s32, cqm_rssi_hyst); __field(s32, cqm_rssi_hyst);
__field(u32, channel_width); __field(u32, channel_width);
__field(u32, channel_cfreq1); __field(u32, channel_cfreq1);
__dynamic_array(u32, arp_addr_list, info->arp_addr_cnt); __dynamic_array(u32, arp_addr_list,
__field(bool, arp_filter_enabled); 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, qos);
__field(bool, idle); __field(bool, idle);
__field(bool, ps); __field(bool, ps);
...@@ -384,9 +387,11 @@ TRACE_EVENT(drv_bss_info_changed, ...@@ -384,9 +387,11 @@ TRACE_EVENT(drv_bss_info_changed,
__entry->cqm_rssi_hyst = info->cqm_rssi_hyst; __entry->cqm_rssi_hyst = info->cqm_rssi_hyst;
__entry->channel_width = info->chandef.width; __entry->channel_width = info->chandef.width;
__entry->channel_cfreq1 = info->chandef.center_freq1; __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, memcpy(__get_dynamic_array(arp_addr_list), info->arp_addr_list,
sizeof(u32) * info->arp_addr_cnt); sizeof(u32) * (info->arp_addr_cnt > IEEE80211_BSS_ARP_ADDR_LIST_LEN ?
__entry->arp_filter_enabled = info->arp_filter_enabled; IEEE80211_BSS_ARP_ADDR_LIST_LEN :
info->arp_addr_cnt));
__entry->qos = info->qos; __entry->qos = info->qos;
__entry->idle = info->idle; __entry->idle = info->idle;
__entry->ps = info->ps; __entry->ps = info->ps;
...@@ -1184,23 +1189,26 @@ TRACE_EVENT(drv_set_rekey_data, ...@@ -1184,23 +1189,26 @@ TRACE_EVENT(drv_set_rekey_data,
TRACE_EVENT(drv_rssi_callback, TRACE_EVENT(drv_rssi_callback,
TP_PROTO(struct ieee80211_local *local, TP_PROTO(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
enum ieee80211_rssi_event rssi_event), enum ieee80211_rssi_event rssi_event),
TP_ARGS(local, rssi_event), TP_ARGS(local, sdata, rssi_event),
TP_STRUCT__entry( TP_STRUCT__entry(
LOCAL_ENTRY LOCAL_ENTRY
VIF_ENTRY
__field(u32, rssi_event) __field(u32, rssi_event)
), ),
TP_fast_assign( TP_fast_assign(
LOCAL_ASSIGN; LOCAL_ASSIGN;
VIF_ASSIGN;
__entry->rssi_event = rssi_event; __entry->rssi_event = rssi_event;
), ),
TP_printk( TP_printk(
LOCAL_PR_FMT " rssi_event:%d", LOCAL_PR_FMT VIF_PR_FMT " rssi_event:%d",
LOCAL_PR_ARG, __entry->rssi_event LOCAL_PR_ARG, VIF_PR_ARG, __entry->rssi_event
) )
); );
...@@ -1432,6 +1440,14 @@ DEFINE_EVENT(local_only_evt, drv_restart_complete, ...@@ -1432,6 +1440,14 @@ DEFINE_EVENT(local_only_evt, drv_restart_complete,
TP_ARGS(local) 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. * Tracing for API calls that drivers call.
*/ */
...@@ -1821,6 +1837,29 @@ TRACE_EVENT(stop_queue, ...@@ -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 #ifdef CONFIG_MAC80211_MESSAGE_TRACING
#undef TRACE_SYSTEM #undef TRACE_SYSTEM
#define TRACE_SYSTEM mac80211_msg #define TRACE_SYSTEM mac80211_msg
......
...@@ -1787,16 +1787,16 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, ...@@ -1787,16 +1787,16 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
break; break;
/* fall through */ /* fall through */
case NL80211_IFTYPE_AP: 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); fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
/* DA BSSID SA */ /* DA BSSID SA */
memcpy(hdr.addr1, skb->data, ETH_ALEN); memcpy(hdr.addr1, skb->data, ETH_ALEN);
memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN); memcpy(hdr.addr2, sdata->vif.addr, ETH_ALEN);
memcpy(hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN); memcpy(hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN);
hdrlen = 24; 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; band = chanctx_conf->def.chan->band;
break; break;
case NL80211_IFTYPE_WDS: case NL80211_IFTYPE_WDS:
......
...@@ -478,6 +478,11 @@ int wiphy_register(struct wiphy *wiphy) ...@@ -478,6 +478,11 @@ int wiphy_register(struct wiphy *wiphy)
ETH_ALEN))) ETH_ALEN)))
return -EINVAL; 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) if (wiphy->addresses)
memcpy(wiphy->perm_addr, wiphy->addresses[0].addr, ETH_ALEN); 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] = { ...@@ -365,6 +365,8 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
[NL80211_ATTR_SCAN_FLAGS] = { .type = NLA_U32 }, [NL80211_ATTR_SCAN_FLAGS] = { .type = NLA_U32 },
[NL80211_ATTR_P2P_CTWINDOW] = { .type = NLA_U8 }, [NL80211_ATTR_P2P_CTWINDOW] = { .type = NLA_U8 },
[NL80211_ATTR_P2P_OPPPS] = { .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 */ /* policy for the key attributes */
...@@ -1268,6 +1270,12 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 portid, u32 seq, int flag ...@@ -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)) dev->wiphy.ht_capa_mod_mask))
goto nla_put_failure; 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); return genlmsg_end(msg, hdr);
nla_put_failure: nla_put_failure:
...@@ -2491,6 +2499,97 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) ...@@ -2491,6 +2499,97 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
return err; 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, static int nl80211_parse_beacon(struct genl_info *info,
struct cfg80211_beacon_data *bcn) struct cfg80211_beacon_data *bcn)
{ {
...@@ -2734,6 +2833,12 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) ...@@ -2734,6 +2833,12 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
if (err) if (err)
return 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, &params); err = rdev_start_ap(rdev, dev, &params);
if (!err) { if (!err) {
wdev->preset_chandef = params.chandef; wdev->preset_chandef = params.chandef;
...@@ -2742,6 +2847,9 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) ...@@ -2742,6 +2847,9 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
wdev->ssid_len = params.ssid_len; wdev->ssid_len = params.ssid_len;
memcpy(wdev->ssid, params.ssid, wdev->ssid_len); memcpy(wdev->ssid, params.ssid, wdev->ssid_len);
} }
kfree(params.acl);
return err; return err;
} }
...@@ -7876,6 +7984,14 @@ static struct genl_ops nl80211_ops[] = { ...@@ -7876,6 +7984,14 @@ static struct genl_ops nl80211_ops[] = {
.internal_flags = NL80211_FLAG_NEED_NETDEV | .internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL, 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 = { static struct genl_multicast_group nl80211_mlme_mcgrp = {
......
...@@ -875,4 +875,16 @@ static inline void rdev_stop_p2p_device(struct cfg80211_registered_device *rdev, ...@@ -875,4 +875,16 @@ static inline void rdev_stop_p2p_device(struct cfg80211_registered_device *rdev,
rdev->ops->stop_p2p_device(&rdev->wiphy, wdev); rdev->ops->stop_p2p_device(&rdev->wiphy, wdev);
trace_rdev_return_void(&rdev->wiphy); 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 */ #endif /* __CFG80211_RDEV_OPS */
...@@ -1767,6 +1767,24 @@ DEFINE_EVENT(wiphy_wdev_evt, rdev_stop_p2p_device, ...@@ -1767,6 +1767,24 @@ DEFINE_EVENT(wiphy_wdev_evt, rdev_stop_p2p_device,
TP_ARGS(wiphy, wdev) 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 * * cfg80211 exported functions traces *
*************************************************************/ *************************************************************/
......
...@@ -1212,7 +1212,8 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, ...@@ -1212,7 +1212,8 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_P2P_GO: case NL80211_IFTYPE_P2P_GO:
case NL80211_IFTYPE_WDS: case NL80211_IFTYPE_WDS:
radar_required = !!(chan->flags & IEEE80211_CHAN_RADAR); radar_required = !!(chan &&
(chan->flags & IEEE80211_CHAN_RADAR));
break; break;
case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_P2P_CLIENT:
case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_STATION:
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册