mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-29 15:14:18 +08:00
Some more work for 4.7, notably:
* completion and fixups of nla_put_64_64bit() work * remove a/b/g/n from wext nickname to avoid confusion with 11ac (which wouldn't even fit fully there due to string length restrictions) along with some other minor changes/cleanups. -----BEGIN PGP SIGNATURE----- iQIcBAABCgAGBQJXNGMwAAoJEGt7eEactAAdrRMP/RGmFd1I8Z7gIsKc7pdknf20 4xLA3v8cqD7c9OtqlfVSfIyIosNl+pMatXK4eSaYzJICmdV9lU8VqgW6eH9lmDuM q8Eis2/i7ZozzYhANVFQxMRvmSED8MeRm49LOzRofuPg4FHzyTYd8+TRfQ+QGRm9 xlrKTJ4BwH5lZgmH20/cphbffo5j8IyjzjKw0MC/tjikIePww6Am/r1jpCnd0Mwz rWwRa4pQ9JBV7UzzzdcMpdn3KJkteFq/gJPCpZVDo3Zf+L21UavxP99NoUWiUvUU bEQ9FzcuB7Zyt/lCAyu3ECBGqLvskqseFg3zmDnUoL7GmCZ1PZlfsnfOhQP0HgpI t/dyw+TYIu6d4ZHbqGM6q6usjIJLltaxATwvREq3VdWFn5fYFu0Em3CyQ0on1XGn 4anNdkilGxaVEHCFBvfLvMTEfsTj7eycsNsDrZEGYV3NwX/wfz+6thqqu8gXFUsC 4MB1fS+YPg7u72ne+oJSPyJyFofYXDSjdNqnZ6HSQEZHinE+FnDCywZlJesxzDsH q1ABkKLnmMNIwHxbfRBE0eO8sKXo6kUTJeFmWHtxB8/LcsLsV0/8juUy9H5PPZPU 7TJhn4SZrlJb92xq1DQ0t1xsRxTLonbRuu9PtVVZMUhZP69PpzK9toC6eCo9bovn XFdSQ2c2xRwRAiSjUpQP =QNxF -----END PGP SIGNATURE----- Merge tag 'mac80211-next-for-davem-2016-05-12' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next Johannes Berg says: ==================== Some more work for 4.7, notably: * completion and fixups of nla_put_64_64bit() work * remove a/b/g/n from wext nickname to avoid confusion with 11ac (which wouldn't even fit fully there due to string length restrictions) along with some other minor changes/cleanups. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
7fd38193d0
@ -135,6 +135,7 @@
|
||||
!Finclude/net/cfg80211.h cfg80211_tx_mlme_mgmt
|
||||
!Finclude/net/cfg80211.h cfg80211_ibss_joined
|
||||
!Finclude/net/cfg80211.h cfg80211_connect_result
|
||||
!Finclude/net/cfg80211.h cfg80211_connect_bss
|
||||
!Finclude/net/cfg80211.h cfg80211_roamed
|
||||
!Finclude/net/cfg80211.h cfg80211_disconnected
|
||||
!Finclude/net/cfg80211.h cfg80211_ready_on_channel
|
||||
|
@ -1045,11 +1045,12 @@ struct cfg80211_tid_stats {
|
||||
* @rx_beacon: number of beacons received from this peer
|
||||
* @rx_beacon_signal_avg: signal strength average (in dBm) for beacons received
|
||||
* from this peer
|
||||
* @rx_duration: aggregate PPDU duration(usecs) for all the frames from a peer
|
||||
* @pertid: per-TID statistics, see &struct cfg80211_tid_stats, using the last
|
||||
* (IEEE80211_NUM_TIDS) index for MSDUs not encapsulated in QoS-MPDUs.
|
||||
*/
|
||||
struct station_info {
|
||||
u32 filled;
|
||||
u64 filled;
|
||||
u32 connected_time;
|
||||
u32 inactive_time;
|
||||
u64 rx_bytes;
|
||||
@ -1088,6 +1089,7 @@ struct station_info {
|
||||
u32 expected_throughput;
|
||||
|
||||
u64 rx_beacon;
|
||||
u64 rx_duration;
|
||||
u8 rx_beacon_signal_avg;
|
||||
struct cfg80211_tid_stats pertid[IEEE80211_NUM_TIDS + 1];
|
||||
};
|
||||
@ -3187,6 +3189,9 @@ struct wiphy_vendor_command {
|
||||
* @vht_capa_mod_mask: Specify what VHT capabilities can be over-ridden.
|
||||
* If null, then none can be over-ridden.
|
||||
*
|
||||
* @wdev_list: the list of associated (virtual) interfaces; this list must
|
||||
* not be modified by the driver, but can be read with RTNL/RCU protection.
|
||||
*
|
||||
* @max_acl_mac_addrs: Maximum number of MAC addresses that the device
|
||||
* supports for ACL.
|
||||
*
|
||||
@ -3326,6 +3331,8 @@ struct wiphy {
|
||||
const struct ieee80211_ht_cap *ht_capa_mod_mask;
|
||||
const struct ieee80211_vht_cap *vht_capa_mod_mask;
|
||||
|
||||
struct list_head wdev_list;
|
||||
|
||||
/* the network namespace this phy lives in currently */
|
||||
possible_net_t _net;
|
||||
|
||||
@ -3891,7 +3898,7 @@ const u8 *cfg80211_find_ie(u8 eid, const u8 *ies, int len);
|
||||
* cfg80211_find_vendor_ie - find vendor specific information element in data
|
||||
*
|
||||
* @oui: vendor OUI
|
||||
* @oui_type: vendor-specific OUI type
|
||||
* @oui_type: vendor-specific OUI type (must be < 0xff), negative means any
|
||||
* @ies: data consisting of IEs
|
||||
* @len: length of data
|
||||
*
|
||||
@ -3903,7 +3910,7 @@ const u8 *cfg80211_find_ie(u8 eid, const u8 *ies, int len);
|
||||
* Note: There are no checks on the element length other than having to fit into
|
||||
* the given data.
|
||||
*/
|
||||
const u8 *cfg80211_find_vendor_ie(unsigned int oui, u8 oui_type,
|
||||
const u8 *cfg80211_find_vendor_ie(unsigned int oui, int oui_type,
|
||||
const u8 *ies, int len);
|
||||
|
||||
/**
|
||||
@ -4649,6 +4656,32 @@ static inline void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp)
|
||||
#define CFG80211_TESTMODE_DUMP(cmd)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* cfg80211_connect_bss - notify cfg80211 of connection result
|
||||
*
|
||||
* @dev: network device
|
||||
* @bssid: the BSSID of the AP
|
||||
* @bss: entry of bss to which STA got connected to, can be obtained
|
||||
* through cfg80211_get_bss (may be %NULL)
|
||||
* @req_ie: association request IEs (maybe be %NULL)
|
||||
* @req_ie_len: association request IEs length
|
||||
* @resp_ie: association response IEs (may be %NULL)
|
||||
* @resp_ie_len: assoc response IEs length
|
||||
* @status: status code, 0 for successful connection, use
|
||||
* %WLAN_STATUS_UNSPECIFIED_FAILURE if your device cannot give you
|
||||
* the real status code for failures.
|
||||
* @gfp: allocation flags
|
||||
*
|
||||
* It should be called by the underlying driver whenever connect() has
|
||||
* succeeded. This is similar to cfg80211_connect_result(), but with the
|
||||
* option of identifying the exact bss entry for the connection. Only one of
|
||||
* these functions should be called.
|
||||
*/
|
||||
void cfg80211_connect_bss(struct net_device *dev, const u8 *bssid,
|
||||
struct cfg80211_bss *bss, const u8 *req_ie,
|
||||
size_t req_ie_len, const u8 *resp_ie,
|
||||
size_t resp_ie_len, u16 status, gfp_t gfp);
|
||||
|
||||
/**
|
||||
* cfg80211_connect_result - notify cfg80211 of connection result
|
||||
*
|
||||
@ -4666,10 +4699,15 @@ static inline void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp)
|
||||
* It should be called by the underlying driver whenever connect() has
|
||||
* succeeded.
|
||||
*/
|
||||
void cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
|
||||
const u8 *req_ie, size_t req_ie_len,
|
||||
const u8 *resp_ie, size_t resp_ie_len,
|
||||
u16 status, gfp_t gfp);
|
||||
static inline void
|
||||
cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
|
||||
const u8 *req_ie, size_t req_ie_len,
|
||||
const u8 *resp_ie, size_t resp_ie_len,
|
||||
u16 status, gfp_t gfp)
|
||||
{
|
||||
cfg80211_connect_bss(dev, bssid, NULL, req_ie, req_ie_len, resp_ie,
|
||||
resp_ie_len, status, gfp);
|
||||
}
|
||||
|
||||
/**
|
||||
* cfg80211_roamed - notify cfg80211 of roaming
|
||||
|
@ -1068,6 +1068,9 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info)
|
||||
* @RX_FLAG_RADIOTAP_VENDOR_DATA: This frame contains vendor-specific
|
||||
* radiotap data in the skb->data (before the frame) as described by
|
||||
* the &struct ieee80211_vendor_radiotap.
|
||||
* @RX_FLAG_ALLOW_SAME_PN: Allow the same PN as same packet before.
|
||||
* This is used for AMSDU subframes which can have the same PN as
|
||||
* the first subframe.
|
||||
*/
|
||||
enum mac80211_rx_flags {
|
||||
RX_FLAG_MMIC_ERROR = BIT(0),
|
||||
@ -1101,7 +1104,8 @@ enum mac80211_rx_flags {
|
||||
RX_FLAG_5MHZ = BIT(29),
|
||||
RX_FLAG_AMSDU_MORE = BIT(30),
|
||||
RX_FLAG_RADIOTAP_VENDOR_DATA = BIT(31),
|
||||
RX_FLAG_MIC_STRIPPED = BIT_ULL(32),
|
||||
RX_FLAG_MIC_STRIPPED = BIT_ULL(32),
|
||||
RX_FLAG_ALLOW_SAME_PN = BIT_ULL(33),
|
||||
};
|
||||
|
||||
#define RX_FLAG_STBC_SHIFT 26
|
||||
@ -3992,6 +3996,33 @@ static inline int ieee80211_sta_ps_transition_ni(struct ieee80211_sta *sta,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ieee80211_sta_pspoll - PS-Poll frame received
|
||||
* @sta: currently connected station
|
||||
*
|
||||
* When operating in AP mode with the %IEEE80211_HW_AP_LINK_PS flag set,
|
||||
* use this function to inform mac80211 that a PS-Poll frame from a
|
||||
* connected station was received.
|
||||
* This must be used in conjunction with ieee80211_sta_ps_transition()
|
||||
* and possibly ieee80211_sta_uapsd_trigger(); calls to all three must
|
||||
* be serialized.
|
||||
*/
|
||||
void ieee80211_sta_pspoll(struct ieee80211_sta *sta);
|
||||
|
||||
/**
|
||||
* ieee80211_sta_uapsd_trigger - (potential) U-APSD trigger frame received
|
||||
* @sta: currently connected station
|
||||
* @tid: TID of the received (potential) trigger frame
|
||||
*
|
||||
* When operating in AP mode with the %IEEE80211_HW_AP_LINK_PS flag set,
|
||||
* use this function to inform mac80211 that a (potential) trigger frame
|
||||
* from a connected station was received.
|
||||
* This must be used in conjunction with ieee80211_sta_ps_transition()
|
||||
* and possibly ieee80211_sta_pspoll(); calls to all three must be
|
||||
* serialized.
|
||||
*/
|
||||
void ieee80211_sta_uapsd_trigger(struct ieee80211_sta *sta, u8 tid);
|
||||
|
||||
/*
|
||||
* The TX headroom reserved by mac80211 for its own tx_status functions.
|
||||
* This is enough for the radiotap header.
|
||||
|
@ -1817,6 +1817,8 @@ enum nl80211_commands {
|
||||
* @NL80211_ATTR_STA_SUPPORT_P2P_PS: whether P2P PS mechanism supported
|
||||
* or not. u8, one of the values of &enum nl80211_sta_p2p_ps_status
|
||||
*
|
||||
* @NL80211_ATTR_PAD: attribute used for padding for 64-bit alignment
|
||||
*
|
||||
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
|
||||
* @NL80211_ATTR_MAX: highest attribute number currently defined
|
||||
* @__NL80211_ATTR_AFTER_LAST: internal use
|
||||
@ -2513,6 +2515,9 @@ enum nl80211_sta_bss_param {
|
||||
* TID+1 and the special TID 16 (i.e. value 17) is used for non-QoS frames;
|
||||
* each one of those is again nested with &enum nl80211_tid_stats
|
||||
* attributes carrying the actual values.
|
||||
* @NL80211_STA_INFO_RX_DURATION: aggregate PPDU duration for all frames
|
||||
* received from the station (u64, usec)
|
||||
* @NL80211_STA_INFO_PAD: attribute used for padding for 64-bit alignment
|
||||
* @__NL80211_STA_INFO_AFTER_LAST: internal
|
||||
* @NL80211_STA_INFO_MAX: highest possible station info attribute
|
||||
*/
|
||||
@ -2549,6 +2554,8 @@ enum nl80211_sta_info {
|
||||
NL80211_STA_INFO_BEACON_RX,
|
||||
NL80211_STA_INFO_BEACON_SIGNAL_AVG,
|
||||
NL80211_STA_INFO_TID_STATS,
|
||||
NL80211_STA_INFO_RX_DURATION,
|
||||
NL80211_STA_INFO_PAD,
|
||||
|
||||
/* keep last */
|
||||
__NL80211_STA_INFO_AFTER_LAST,
|
||||
@ -2565,6 +2572,7 @@ enum nl80211_sta_info {
|
||||
* transmitted MSDUs (not counting the first attempt; u64)
|
||||
* @NL80211_TID_STATS_TX_MSDU_FAILED: number of failed transmitted
|
||||
* MSDUs (u64)
|
||||
* @NL80211_TID_STATS_PAD: attribute used for padding for 64-bit alignment
|
||||
* @NUM_NL80211_TID_STATS: number of attributes here
|
||||
* @NL80211_TID_STATS_MAX: highest numbered attribute here
|
||||
*/
|
||||
@ -2574,6 +2582,7 @@ enum nl80211_tid_stats {
|
||||
NL80211_TID_STATS_TX_MSDU,
|
||||
NL80211_TID_STATS_TX_MSDU_RETRIES,
|
||||
NL80211_TID_STATS_TX_MSDU_FAILED,
|
||||
NL80211_TID_STATS_PAD,
|
||||
|
||||
/* keep last */
|
||||
NUM_NL80211_TID_STATS,
|
||||
@ -3010,6 +3019,7 @@ enum nl80211_user_reg_hint_type {
|
||||
* transmitting data (on channel or globally)
|
||||
* @NL80211_SURVEY_INFO_TIME_SCAN: time the radio spent for scan
|
||||
* (on this channel or globally)
|
||||
* @NL80211_SURVEY_INFO_PAD: attribute used for padding for 64-bit alignment
|
||||
* @NL80211_SURVEY_INFO_MAX: highest survey info attribute number
|
||||
* currently defined
|
||||
* @__NL80211_SURVEY_INFO_AFTER_LAST: internal use
|
||||
@ -3451,6 +3461,7 @@ enum nl80211_bss_scan_width {
|
||||
* @NL80211_BSS_LAST_SEEN_BOOTTIME: CLOCK_BOOTTIME timestamp when this entry
|
||||
* was last updated by a received frame. The value is expected to be
|
||||
* accurate to about 10ms. (u64, nanoseconds)
|
||||
* @NL80211_BSS_PAD: attribute used for padding for 64-bit alignment
|
||||
* @__NL80211_BSS_AFTER_LAST: internal
|
||||
* @NL80211_BSS_MAX: highest BSS attribute
|
||||
*/
|
||||
|
@ -2399,6 +2399,11 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata)
|
||||
return;
|
||||
}
|
||||
|
||||
/* AP is probably out of range (or not reachable for another reason) so
|
||||
* remove the bss struct for that AP.
|
||||
*/
|
||||
cfg80211_unlink_bss(local->hw.wiphy, ifmgd->associated);
|
||||
|
||||
ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
|
||||
WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,
|
||||
true, frame_buf);
|
||||
|
@ -1319,13 +1319,52 @@ int ieee80211_sta_ps_transition(struct ieee80211_sta *pubsta, bool start)
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_sta_ps_transition);
|
||||
|
||||
void ieee80211_sta_pspoll(struct ieee80211_sta *pubsta)
|
||||
{
|
||||
struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
|
||||
|
||||
if (test_sta_flag(sta, WLAN_STA_SP))
|
||||
return;
|
||||
|
||||
if (!test_sta_flag(sta, WLAN_STA_PS_DRIVER))
|
||||
ieee80211_sta_ps_deliver_poll_response(sta);
|
||||
else
|
||||
set_sta_flag(sta, WLAN_STA_PSPOLL);
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_sta_pspoll);
|
||||
|
||||
void ieee80211_sta_uapsd_trigger(struct ieee80211_sta *pubsta, u8 tid)
|
||||
{
|
||||
struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
|
||||
u8 ac = ieee802_1d_to_ac[tid & 7];
|
||||
|
||||
/*
|
||||
* If this AC is not trigger-enabled do nothing.
|
||||
*
|
||||
* NB: This could/should check a separate bitmap of trigger-
|
||||
* enabled queues, but for now we only implement uAPSD w/o
|
||||
* TSPEC changes to the ACs, so they're always the same.
|
||||
*/
|
||||
if (!(sta->sta.uapsd_queues & BIT(ac)))
|
||||
return;
|
||||
|
||||
/* if we are in a service period, do nothing */
|
||||
if (test_sta_flag(sta, WLAN_STA_SP))
|
||||
return;
|
||||
|
||||
if (!test_sta_flag(sta, WLAN_STA_PS_DRIVER))
|
||||
ieee80211_sta_ps_deliver_uapsd(sta);
|
||||
else
|
||||
set_sta_flag(sta, WLAN_STA_UAPSD);
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_sta_uapsd_trigger);
|
||||
|
||||
static ieee80211_rx_result debug_noinline
|
||||
ieee80211_rx_h_uapsd_and_pspoll(struct ieee80211_rx_data *rx)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = rx->sdata;
|
||||
struct ieee80211_hdr *hdr = (void *)rx->skb->data;
|
||||
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
|
||||
int tid, ac;
|
||||
|
||||
if (!rx->sta)
|
||||
return RX_CONTINUE;
|
||||
@ -1351,12 +1390,7 @@ ieee80211_rx_h_uapsd_and_pspoll(struct ieee80211_rx_data *rx)
|
||||
return RX_CONTINUE;
|
||||
|
||||
if (unlikely(ieee80211_is_pspoll(hdr->frame_control))) {
|
||||
if (!test_sta_flag(rx->sta, WLAN_STA_SP)) {
|
||||
if (!test_sta_flag(rx->sta, WLAN_STA_PS_DRIVER))
|
||||
ieee80211_sta_ps_deliver_poll_response(rx->sta);
|
||||
else
|
||||
set_sta_flag(rx->sta, WLAN_STA_PSPOLL);
|
||||
}
|
||||
ieee80211_sta_pspoll(&rx->sta->sta);
|
||||
|
||||
/* Free PS Poll skb here instead of returning RX_DROP that would
|
||||
* count as an dropped frame. */
|
||||
@ -1368,27 +1402,11 @@ ieee80211_rx_h_uapsd_and_pspoll(struct ieee80211_rx_data *rx)
|
||||
ieee80211_has_pm(hdr->frame_control) &&
|
||||
(ieee80211_is_data_qos(hdr->frame_control) ||
|
||||
ieee80211_is_qos_nullfunc(hdr->frame_control))) {
|
||||
u8 tid;
|
||||
|
||||
tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
|
||||
ac = ieee802_1d_to_ac[tid & 7];
|
||||
|
||||
/*
|
||||
* If this AC is not trigger-enabled do nothing.
|
||||
*
|
||||
* NB: This could/should check a separate bitmap of trigger-
|
||||
* enabled queues, but for now we only implement uAPSD w/o
|
||||
* TSPEC changes to the ACs, so they're always the same.
|
||||
*/
|
||||
if (!(rx->sta->sta.uapsd_queues & BIT(ac)))
|
||||
return RX_CONTINUE;
|
||||
|
||||
/* if we are in a service period, do nothing */
|
||||
if (test_sta_flag(rx->sta, WLAN_STA_SP))
|
||||
return RX_CONTINUE;
|
||||
|
||||
if (!test_sta_flag(rx->sta, WLAN_STA_PS_DRIVER))
|
||||
ieee80211_sta_ps_deliver_uapsd(rx->sta);
|
||||
else
|
||||
set_sta_flag(rx->sta, WLAN_STA_UAPSD);
|
||||
ieee80211_sta_uapsd_trigger(&rx->sta->sta, tid);
|
||||
}
|
||||
|
||||
return RX_CONTINUE;
|
||||
|
@ -519,12 +519,16 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx,
|
||||
return RX_DROP_UNUSABLE;
|
||||
|
||||
if (!(status->flag & RX_FLAG_PN_VALIDATED)) {
|
||||
int res;
|
||||
|
||||
ccmp_hdr2pn(pn, skb->data + hdrlen);
|
||||
|
||||
queue = rx->security_idx;
|
||||
|
||||
if (memcmp(pn, key->u.ccmp.rx_pn[queue],
|
||||
IEEE80211_CCMP_PN_LEN) <= 0) {
|
||||
res = memcmp(pn, key->u.ccmp.rx_pn[queue],
|
||||
IEEE80211_CCMP_PN_LEN);
|
||||
if (res < 0 ||
|
||||
(!res && !(status->flag & RX_FLAG_ALLOW_SAME_PN))) {
|
||||
key->u.ccmp.replays++;
|
||||
return RX_DROP_UNUSABLE;
|
||||
}
|
||||
@ -745,12 +749,16 @@ ieee80211_crypto_gcmp_decrypt(struct ieee80211_rx_data *rx)
|
||||
return RX_DROP_UNUSABLE;
|
||||
|
||||
if (!(status->flag & RX_FLAG_PN_VALIDATED)) {
|
||||
int res;
|
||||
|
||||
gcmp_hdr2pn(pn, skb->data + hdrlen);
|
||||
|
||||
queue = rx->security_idx;
|
||||
|
||||
if (memcmp(pn, key->u.gcmp.rx_pn[queue],
|
||||
IEEE80211_GCMP_PN_LEN) <= 0) {
|
||||
res = memcmp(pn, key->u.gcmp.rx_pn[queue],
|
||||
IEEE80211_GCMP_PN_LEN);
|
||||
if (res < 0 ||
|
||||
(!res && !(status->flag & RX_FLAG_ALLOW_SAME_PN))) {
|
||||
key->u.gcmp.replays++;
|
||||
return RX_DROP_UNUSABLE;
|
||||
}
|
||||
|
@ -739,7 +739,7 @@ static bool cfg80211_ir_permissive_chan(struct wiphy *wiphy,
|
||||
* and thus fail the GO instantiation, consider only the interfaces of
|
||||
* the current registered device.
|
||||
*/
|
||||
list_for_each_entry(wdev, &rdev->wdev_list, list) {
|
||||
list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
|
||||
struct ieee80211_channel *other_chan = NULL;
|
||||
int r1, r2;
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
*
|
||||
* Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
||||
* Copyright 2015 Intel Deutschland GmbH
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
@ -157,7 +158,7 @@ int cfg80211_switch_netns(struct cfg80211_registered_device *rdev,
|
||||
if (!(rdev->wiphy.flags & WIPHY_FLAG_NETNS_OK))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
list_for_each_entry(wdev, &rdev->wdev_list, list) {
|
||||
list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
|
||||
if (!wdev->netdev)
|
||||
continue;
|
||||
wdev->netdev->features &= ~NETIF_F_NETNS_LOCAL;
|
||||
@ -171,7 +172,8 @@ int cfg80211_switch_netns(struct cfg80211_registered_device *rdev,
|
||||
/* failed -- clean up to old netns */
|
||||
net = wiphy_net(&rdev->wiphy);
|
||||
|
||||
list_for_each_entry_continue_reverse(wdev, &rdev->wdev_list,
|
||||
list_for_each_entry_continue_reverse(wdev,
|
||||
&rdev->wiphy.wdev_list,
|
||||
list) {
|
||||
if (!wdev->netdev)
|
||||
continue;
|
||||
@ -230,7 +232,7 @@ void cfg80211_shutdown_all_interfaces(struct wiphy *wiphy)
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
list_for_each_entry(wdev, &rdev->wdev_list, list) {
|
||||
list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
|
||||
if (wdev->netdev) {
|
||||
dev_close(wdev->netdev);
|
||||
continue;
|
||||
@ -298,7 +300,8 @@ void cfg80211_destroy_ifaces(struct cfg80211_registered_device *rdev)
|
||||
kfree(item);
|
||||
spin_unlock_irq(&rdev->destroy_list_lock);
|
||||
|
||||
list_for_each_entry_safe(wdev, tmp, &rdev->wdev_list, list) {
|
||||
list_for_each_entry_safe(wdev, tmp,
|
||||
&rdev->wiphy.wdev_list, list) {
|
||||
if (nlportid == wdev->owner_nlportid)
|
||||
rdev_del_virtual_intf(rdev, wdev);
|
||||
}
|
||||
@ -410,7 +413,7 @@ use_default_name:
|
||||
dev_set_name(&rdev->wiphy.dev, PHY_NAME "%d", rdev->wiphy_idx);
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&rdev->wdev_list);
|
||||
INIT_LIST_HEAD(&rdev->wiphy.wdev_list);
|
||||
INIT_LIST_HEAD(&rdev->beacon_registrations);
|
||||
spin_lock_init(&rdev->beacon_registrations_lock);
|
||||
spin_lock_init(&rdev->bss_lock);
|
||||
@ -799,7 +802,7 @@ void wiphy_unregister(struct wiphy *wiphy)
|
||||
nl80211_notify_wiphy(rdev, NL80211_CMD_DEL_WIPHY);
|
||||
rdev->wiphy.registered = false;
|
||||
|
||||
WARN_ON(!list_empty(&rdev->wdev_list));
|
||||
WARN_ON(!list_empty(&rdev->wiphy.wdev_list));
|
||||
|
||||
/*
|
||||
* First remove the hardware from everywhere, this makes
|
||||
@ -1021,7 +1024,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
|
||||
spin_lock_init(&wdev->mgmt_registrations_lock);
|
||||
|
||||
wdev->identifier = ++rdev->wdev_id;
|
||||
list_add_rcu(&wdev->list, &rdev->wdev_list);
|
||||
list_add_rcu(&wdev->list, &rdev->wiphy.wdev_list);
|
||||
rdev->devlist_generation++;
|
||||
/* can only change netns with wiphy */
|
||||
dev->features |= NETIF_F_NETNS_LOCAL;
|
||||
|
@ -50,10 +50,9 @@ struct cfg80211_registered_device {
|
||||
/* wiphy index, internal only */
|
||||
int wiphy_idx;
|
||||
|
||||
/* associated wireless interfaces, protected by rtnl or RCU */
|
||||
struct list_head wdev_list;
|
||||
/* protected by RTNL */
|
||||
int devlist_generation, wdev_id;
|
||||
int opencount; /* also protected by devlist_mtx */
|
||||
int opencount;
|
||||
wait_queue_head_t dev_wait;
|
||||
|
||||
struct list_head beacon_registrations;
|
||||
@ -214,6 +213,7 @@ struct cfg80211_event {
|
||||
const u8 *resp_ie;
|
||||
size_t req_ie_len;
|
||||
size_t resp_ie_len;
|
||||
struct cfg80211_bss *bss;
|
||||
u16 status;
|
||||
} cr;
|
||||
struct {
|
||||
|
@ -103,7 +103,7 @@ __cfg80211_wdev_from_attrs(struct net *netns, struct nlattr **attrs)
|
||||
if (have_wdev_id && rdev->wiphy_idx != wiphy_idx)
|
||||
continue;
|
||||
|
||||
list_for_each_entry(wdev, &rdev->wdev_list, list) {
|
||||
list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
|
||||
if (have_ifidx && wdev->netdev &&
|
||||
wdev->netdev->ifindex == ifidx) {
|
||||
result = wdev;
|
||||
@ -149,7 +149,7 @@ __cfg80211_rdev_from_attrs(struct net *netns, struct nlattr **attrs)
|
||||
tmp = cfg80211_rdev_by_wiphy_idx(wdev_id >> 32);
|
||||
if (tmp) {
|
||||
/* make sure wdev exists */
|
||||
list_for_each_entry(wdev, &tmp->wdev_list, list) {
|
||||
list_for_each_entry(wdev, &tmp->wiphy.wdev_list, list) {
|
||||
if (wdev->identifier != (u32)wdev_id)
|
||||
continue;
|
||||
found = true;
|
||||
@ -535,7 +535,7 @@ static int nl80211_prepare_wdev_dump(struct sk_buff *skb,
|
||||
*rdev = wiphy_to_rdev(wiphy);
|
||||
*wdev = NULL;
|
||||
|
||||
list_for_each_entry(tmp, &(*rdev)->wdev_list, list) {
|
||||
list_for_each_entry(tmp, &(*rdev)->wiphy.wdev_list, list) {
|
||||
if (tmp->identifier == cb->args[1]) {
|
||||
*wdev = tmp;
|
||||
break;
|
||||
@ -2490,7 +2490,7 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *
|
||||
}
|
||||
if_idx = 0;
|
||||
|
||||
list_for_each_entry(wdev, &rdev->wdev_list, list) {
|
||||
list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
|
||||
if (if_idx < if_start) {
|
||||
if_idx++;
|
||||
continue;
|
||||
@ -2762,7 +2762,7 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
|
||||
spin_lock_init(&wdev->mgmt_registrations_lock);
|
||||
|
||||
wdev->identifier = ++rdev->wdev_id;
|
||||
list_add_rcu(&wdev->list, &rdev->wdev_list);
|
||||
list_add_rcu(&wdev->list, &rdev->wiphy.wdev_list);
|
||||
rdev->devlist_generation++;
|
||||
break;
|
||||
default:
|
||||
@ -3298,7 +3298,7 @@ static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev;
|
||||
bool ret = false;
|
||||
|
||||
list_for_each_entry(wdev, &rdev->wdev_list, list) {
|
||||
list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
|
||||
if (wdev->iftype != NL80211_IFTYPE_AP &&
|
||||
wdev->iftype != NL80211_IFTYPE_P2P_GO)
|
||||
continue;
|
||||
@ -3755,11 +3755,18 @@ static int nl80211_send_station(struct sk_buff *msg, u32 cmd, u32 portid,
|
||||
goto nla_put_failure;
|
||||
|
||||
#define PUT_SINFO(attr, memb, type) do { \
|
||||
if (sinfo->filled & BIT(NL80211_STA_INFO_ ## attr) && \
|
||||
BUILD_BUG_ON(sizeof(type) == sizeof(u64)); \
|
||||
if (sinfo->filled & (1ULL << NL80211_STA_INFO_ ## attr) && \
|
||||
nla_put_ ## type(msg, NL80211_STA_INFO_ ## attr, \
|
||||
sinfo->memb)) \
|
||||
goto nla_put_failure; \
|
||||
} while (0)
|
||||
#define PUT_SINFO_U64(attr, memb) do { \
|
||||
if (sinfo->filled & (1ULL << NL80211_STA_INFO_ ## attr) && \
|
||||
nla_put_u64_64bit(msg, NL80211_STA_INFO_ ## attr, \
|
||||
sinfo->memb, NL80211_STA_INFO_PAD)) \
|
||||
goto nla_put_failure; \
|
||||
} while (0)
|
||||
|
||||
PUT_SINFO(CONNECTED_TIME, connected_time, u32);
|
||||
PUT_SINFO(INACTIVE_TIME, inactive_time, u32);
|
||||
@ -3776,11 +3783,12 @@ static int nl80211_send_station(struct sk_buff *msg, u32 cmd, u32 portid,
|
||||
(u32)sinfo->tx_bytes))
|
||||
goto nla_put_failure;
|
||||
|
||||
PUT_SINFO(RX_BYTES64, rx_bytes, u64);
|
||||
PUT_SINFO(TX_BYTES64, tx_bytes, u64);
|
||||
PUT_SINFO_U64(RX_BYTES64, rx_bytes);
|
||||
PUT_SINFO_U64(TX_BYTES64, tx_bytes);
|
||||
PUT_SINFO(LLID, llid, u16);
|
||||
PUT_SINFO(PLID, plid, u16);
|
||||
PUT_SINFO(PLINK_STATE, plink_state, u8);
|
||||
PUT_SINFO_U64(RX_DURATION, rx_duration);
|
||||
|
||||
switch (rdev->wiphy.signal_type) {
|
||||
case CFG80211_SIGNAL_TYPE_MBM:
|
||||
@ -3848,12 +3856,13 @@ static int nl80211_send_station(struct sk_buff *msg, u32 cmd, u32 portid,
|
||||
&sinfo->sta_flags))
|
||||
goto nla_put_failure;
|
||||
|
||||
PUT_SINFO(T_OFFSET, t_offset, u64);
|
||||
PUT_SINFO(RX_DROP_MISC, rx_dropped_misc, u64);
|
||||
PUT_SINFO(BEACON_RX, rx_beacon, u64);
|
||||
PUT_SINFO_U64(T_OFFSET, t_offset);
|
||||
PUT_SINFO_U64(RX_DROP_MISC, rx_dropped_misc);
|
||||
PUT_SINFO_U64(BEACON_RX, rx_beacon);
|
||||
PUT_SINFO(BEACON_SIGNAL_AVG, rx_beacon_signal_avg, u8);
|
||||
|
||||
#undef PUT_SINFO
|
||||
#undef PUT_SINFO_U64
|
||||
|
||||
if (sinfo->filled & BIT(NL80211_STA_INFO_TID_STATS)) {
|
||||
struct nlattr *tidsattr;
|
||||
@ -3876,19 +3885,19 @@ static int nl80211_send_station(struct sk_buff *msg, u32 cmd, u32 portid,
|
||||
if (!tidattr)
|
||||
goto nla_put_failure;
|
||||
|
||||
#define PUT_TIDVAL(attr, memb, type) do { \
|
||||
#define PUT_TIDVAL_U64(attr, memb) do { \
|
||||
if (tidstats->filled & BIT(NL80211_TID_STATS_ ## attr) && \
|
||||
nla_put_ ## type(msg, NL80211_TID_STATS_ ## attr, \
|
||||
tidstats->memb)) \
|
||||
nla_put_u64_64bit(msg, NL80211_TID_STATS_ ## attr, \
|
||||
tidstats->memb, NL80211_TID_STATS_PAD)) \
|
||||
goto nla_put_failure; \
|
||||
} while (0)
|
||||
|
||||
PUT_TIDVAL(RX_MSDU, rx_msdu, u64);
|
||||
PUT_TIDVAL(TX_MSDU, tx_msdu, u64);
|
||||
PUT_TIDVAL(TX_MSDU_RETRIES, tx_msdu_retries, u64);
|
||||
PUT_TIDVAL(TX_MSDU_FAILED, tx_msdu_failed, u64);
|
||||
PUT_TIDVAL_U64(RX_MSDU, rx_msdu);
|
||||
PUT_TIDVAL_U64(TX_MSDU, tx_msdu);
|
||||
PUT_TIDVAL_U64(TX_MSDU_RETRIES, tx_msdu_retries);
|
||||
PUT_TIDVAL_U64(TX_MSDU_FAILED, tx_msdu_failed);
|
||||
|
||||
#undef PUT_TIDVAL
|
||||
#undef PUT_TIDVAL_U64
|
||||
nla_nest_end(msg, tidattr);
|
||||
}
|
||||
|
||||
@ -10383,7 +10392,7 @@ static int nl80211_prepare_vendor_dump(struct sk_buff *skb,
|
||||
*wdev = NULL;
|
||||
|
||||
if (cb->args[1]) {
|
||||
list_for_each_entry(tmp, &(*rdev)->wdev_list, list) {
|
||||
list_for_each_entry(tmp, &wiphy->wdev_list, list) {
|
||||
if (tmp->identifier == cb->args[1] - 1) {
|
||||
*wdev = tmp;
|
||||
break;
|
||||
@ -13404,7 +13413,7 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
|
||||
sched_scan_req->owner_nlportid == notify->portid)
|
||||
schedule_scan_stop = true;
|
||||
|
||||
list_for_each_entry_rcu(wdev, &rdev->wdev_list, list) {
|
||||
list_for_each_entry_rcu(wdev, &rdev->wiphy.wdev_list, list) {
|
||||
cfg80211_mlme_unregister_socket(wdev, notify->portid);
|
||||
|
||||
if (wdev->owner_nlportid == notify->portid)
|
||||
|
@ -1639,7 +1639,7 @@ static void reg_leave_invalid_chans(struct wiphy *wiphy)
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
list_for_each_entry(wdev, &rdev->wdev_list, list)
|
||||
list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list)
|
||||
if (!reg_wdev_chan_valid(wiphy, wdev))
|
||||
cfg80211_leave(rdev, wdev);
|
||||
}
|
||||
|
@ -364,13 +364,16 @@ const u8 *cfg80211_find_ie(u8 eid, const u8 *ies, int len)
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_find_ie);
|
||||
|
||||
const u8 *cfg80211_find_vendor_ie(unsigned int oui, u8 oui_type,
|
||||
const u8 *cfg80211_find_vendor_ie(unsigned int oui, int oui_type,
|
||||
const u8 *ies, int len)
|
||||
{
|
||||
struct ieee80211_vendor_ie *ie;
|
||||
const u8 *pos = ies, *end = ies + len;
|
||||
int ie_oui;
|
||||
|
||||
if (WARN_ON(oui_type > 0xff))
|
||||
return NULL;
|
||||
|
||||
while (pos < end) {
|
||||
pos = cfg80211_find_ie(WLAN_EID_VENDOR_SPECIFIC, pos,
|
||||
end - pos);
|
||||
@ -386,7 +389,8 @@ const u8 *cfg80211_find_vendor_ie(unsigned int oui, u8 oui_type,
|
||||
goto cont;
|
||||
|
||||
ie_oui = ie->oui[0] << 16 | ie->oui[1] << 8 | ie->oui[2];
|
||||
if (ie_oui == oui && ie->oui_type == oui_type)
|
||||
if (ie_oui == oui &&
|
||||
(oui_type < 0 || ie->oui_type == oui_type))
|
||||
return pos;
|
||||
cont:
|
||||
pos += 2 + ie->len;
|
||||
|
@ -223,7 +223,7 @@ void cfg80211_conn_work(struct work_struct *work)
|
||||
|
||||
rtnl_lock();
|
||||
|
||||
list_for_each_entry(wdev, &rdev->wdev_list, list) {
|
||||
list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
|
||||
if (!wdev->netdev)
|
||||
continue;
|
||||
|
||||
@ -617,7 +617,7 @@ static bool cfg80211_is_all_idle(void)
|
||||
* count as new regulatory hints.
|
||||
*/
|
||||
list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
|
||||
list_for_each_entry(wdev, &rdev->wdev_list, list) {
|
||||
list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
|
||||
wdev_lock(wdev);
|
||||
if (wdev->conn || wdev->current_bss)
|
||||
is_all_idle = false;
|
||||
@ -753,19 +753,32 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
|
||||
kfree(country_ie);
|
||||
}
|
||||
|
||||
void cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
|
||||
const u8 *req_ie, size_t req_ie_len,
|
||||
const u8 *resp_ie, size_t resp_ie_len,
|
||||
u16 status, gfp_t gfp)
|
||||
/* Consumes bss object one way or another */
|
||||
void cfg80211_connect_bss(struct net_device *dev, const u8 *bssid,
|
||||
struct cfg80211_bss *bss, const u8 *req_ie,
|
||||
size_t req_ie_len, const u8 *resp_ie,
|
||||
size_t resp_ie_len, u16 status, gfp_t gfp)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
|
||||
struct cfg80211_event *ev;
|
||||
unsigned long flags;
|
||||
|
||||
if (bss) {
|
||||
/* Make sure the bss entry provided by the driver is valid. */
|
||||
struct cfg80211_internal_bss *ibss = bss_from_pub(bss);
|
||||
|
||||
if (WARN_ON(list_empty(&ibss->list))) {
|
||||
cfg80211_put_bss(wdev->wiphy, bss);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ev = kzalloc(sizeof(*ev) + req_ie_len + resp_ie_len, gfp);
|
||||
if (!ev)
|
||||
if (!ev) {
|
||||
cfg80211_put_bss(wdev->wiphy, bss);
|
||||
return;
|
||||
}
|
||||
|
||||
ev->type = EVENT_CONNECT_RESULT;
|
||||
if (bssid)
|
||||
@ -780,6 +793,9 @@ void cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
|
||||
ev->cr.resp_ie_len = resp_ie_len;
|
||||
memcpy((void *)ev->cr.resp_ie, resp_ie, resp_ie_len);
|
||||
}
|
||||
if (bss)
|
||||
cfg80211_hold_bss(bss_from_pub(bss));
|
||||
ev->cr.bss = bss;
|
||||
ev->cr.status = status;
|
||||
|
||||
spin_lock_irqsave(&wdev->event_lock, flags);
|
||||
@ -787,7 +803,7 @@ void cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
|
||||
spin_unlock_irqrestore(&wdev->event_lock, flags);
|
||||
queue_work(cfg80211_wq, &rdev->event_work);
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_connect_result);
|
||||
EXPORT_SYMBOL(cfg80211_connect_bss);
|
||||
|
||||
/* Consumes bss object one way or another */
|
||||
void __cfg80211_roamed(struct wireless_dev *wdev,
|
||||
|
@ -91,7 +91,7 @@ static void cfg80211_leave_all(struct cfg80211_registered_device *rdev)
|
||||
{
|
||||
struct wireless_dev *wdev;
|
||||
|
||||
list_for_each_entry(wdev, &rdev->wdev_list, list)
|
||||
list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list)
|
||||
cfg80211_leave(rdev, wdev);
|
||||
}
|
||||
|
||||
|
@ -950,7 +950,7 @@ void cfg80211_process_wdev_events(struct wireless_dev *wdev)
|
||||
ev->cr.resp_ie, ev->cr.resp_ie_len,
|
||||
ev->cr.status,
|
||||
ev->cr.status == WLAN_STATUS_SUCCESS,
|
||||
NULL);
|
||||
ev->cr.bss);
|
||||
break;
|
||||
case EVENT_ROAMED:
|
||||
__cfg80211_roamed(wdev, ev->rm.bss, ev->rm.req_ie,
|
||||
@ -986,7 +986,7 @@ void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev)
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
list_for_each_entry(wdev, &rdev->wdev_list, list)
|
||||
list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list)
|
||||
cfg80211_process_wdev_events(wdev);
|
||||
}
|
||||
|
||||
@ -1560,7 +1560,7 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
|
||||
if (!beacon_int)
|
||||
return -EINVAL;
|
||||
|
||||
list_for_each_entry(wdev, &rdev->wdev_list, list) {
|
||||
list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
|
||||
if (!wdev->beacon_interval)
|
||||
continue;
|
||||
if (wdev->beacon_interval != beacon_int) {
|
||||
|
@ -25,42 +25,7 @@ int cfg80211_wext_giwname(struct net_device *dev,
|
||||
struct iw_request_info *info,
|
||||
char *name, char *extra)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct ieee80211_supported_band *sband;
|
||||
bool is_ht = false, is_a = false, is_b = false, is_g = false;
|
||||
|
||||
if (!wdev)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
sband = wdev->wiphy->bands[NL80211_BAND_5GHZ];
|
||||
if (sband) {
|
||||
is_a = true;
|
||||
is_ht |= sband->ht_cap.ht_supported;
|
||||
}
|
||||
|
||||
sband = wdev->wiphy->bands[NL80211_BAND_2GHZ];
|
||||
if (sband) {
|
||||
int i;
|
||||
/* Check for mandatory rates */
|
||||
for (i = 0; i < sband->n_bitrates; i++) {
|
||||
if (sband->bitrates[i].bitrate == 10)
|
||||
is_b = true;
|
||||
if (sband->bitrates[i].bitrate == 60)
|
||||
is_g = true;
|
||||
}
|
||||
is_ht |= sband->ht_cap.ht_supported;
|
||||
}
|
||||
|
||||
strcpy(name, "IEEE 802.11");
|
||||
if (is_a)
|
||||
strcat(name, "a");
|
||||
if (is_b)
|
||||
strcat(name, "b");
|
||||
if (is_g)
|
||||
strcat(name, "g");
|
||||
if (is_ht)
|
||||
strcat(name, "n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_WEXT_HANDLER(cfg80211_wext_giwname);
|
||||
|
Loading…
Reference in New Issue
Block a user