Merge tag 'mac80211-next-for-davem-2015-03-30' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next
Johannes Berg says: ==================== Lots of updates for net-next; along with the usual flurry of small fixes, cleanups and internal features we have: * VHT support for TDLS and IBSS (conditional on drivers though) * first TX performance improvements (the biggest will come later) * many suspend/resume (race) fixes * name_assign_type support from Tom Gundersen ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
@@ -178,10 +178,18 @@ config CFG80211_WEXT
|
||||
bool "cfg80211 wireless extensions compatibility"
|
||||
depends on CFG80211
|
||||
select WEXT_CORE
|
||||
default y if CFG80211_WEXT_EXPORT
|
||||
help
|
||||
Enable this option if you need old userspace for wireless
|
||||
extensions with cfg80211-based drivers.
|
||||
|
||||
config CFG80211_WEXT_EXPORT
|
||||
bool
|
||||
depends on CFG80211
|
||||
help
|
||||
Drivers should select this option if they require cfg80211's
|
||||
wext compatibility symbols to be exported.
|
||||
|
||||
config LIB80211
|
||||
tristate
|
||||
default n
|
||||
|
@@ -30,7 +30,7 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid,
|
||||
return;
|
||||
|
||||
bss = cfg80211_get_bss(wdev->wiphy, channel, bssid, NULL, 0,
|
||||
WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS);
|
||||
IEEE80211_BSS_TYPE_IBSS, IEEE80211_PRIVACY_ANY);
|
||||
|
||||
if (WARN_ON(!bss))
|
||||
return;
|
||||
|
@@ -229,7 +229,8 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
|
||||
return -EALREADY;
|
||||
|
||||
req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
|
||||
WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
|
||||
IEEE80211_BSS_TYPE_ESS,
|
||||
IEEE80211_PRIVACY_ANY);
|
||||
if (!req.bss)
|
||||
return -ENOENT;
|
||||
|
||||
@@ -296,7 +297,8 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
|
||||
rdev->wiphy.vht_capa_mod_mask);
|
||||
|
||||
req->bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
|
||||
WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
|
||||
IEEE80211_BSS_TYPE_ESS,
|
||||
IEEE80211_PRIVACY_ANY);
|
||||
if (!req->bss)
|
||||
return -ENOENT;
|
||||
|
||||
|
@@ -399,6 +399,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
|
||||
[NL80211_ATTR_WIPHY_SELF_MANAGED_REG] = { .type = NLA_FLAG },
|
||||
[NL80211_ATTR_NETNS_FD] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_SCHED_SCAN_DELAY] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_REG_INDOOR] = { .type = NLA_FLAG },
|
||||
};
|
||||
|
||||
/* policy for the key attributes */
|
||||
@@ -1098,8 +1099,6 @@ static int nl80211_send_wowlan(struct sk_buff *msg,
|
||||
if (large && nl80211_send_wowlan_tcp_caps(rdev, msg))
|
||||
return -ENOBUFS;
|
||||
|
||||
/* TODO: send wowlan net detect */
|
||||
|
||||
nla_nest_end(msg, nl_wowlan);
|
||||
|
||||
return 0;
|
||||
@@ -2668,7 +2667,8 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
|
||||
|
||||
wdev = rdev_add_virtual_intf(rdev,
|
||||
nla_data(info->attrs[NL80211_ATTR_IFNAME]),
|
||||
type, err ? NULL : &flags, ¶ms);
|
||||
NET_NAME_USER, type, err ? NULL : &flags,
|
||||
¶ms);
|
||||
if (WARN_ON(!wdev)) {
|
||||
nlmsg_free(msg);
|
||||
return -EPROTO;
|
||||
@@ -4968,7 +4968,10 @@ static int parse_reg_rule(struct nlattr *tb[],
|
||||
static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
char *data = NULL;
|
||||
bool is_indoor;
|
||||
enum nl80211_user_reg_hint_type user_reg_hint_type;
|
||||
u32 owner_nlportid;
|
||||
|
||||
|
||||
/*
|
||||
* You should only get this when cfg80211 hasn't yet initialized
|
||||
@@ -4994,7 +4997,15 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
|
||||
data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
|
||||
return regulatory_hint_user(data, user_reg_hint_type);
|
||||
case NL80211_USER_REG_HINT_INDOOR:
|
||||
return regulatory_hint_indoor_user();
|
||||
if (info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
|
||||
owner_nlportid = info->snd_portid;
|
||||
is_indoor = !!info->attrs[NL80211_ATTR_REG_INDOOR];
|
||||
} else {
|
||||
owner_nlportid = 0;
|
||||
is_indoor = true;
|
||||
}
|
||||
|
||||
return regulatory_hint_indoor(is_indoor, owner_nlportid);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -5275,7 +5286,7 @@ do { \
|
||||
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshAwakeWindowDuration,
|
||||
0, 65535, mask,
|
||||
NL80211_MESHCONF_AWAKE_WINDOW, nla_get_u16);
|
||||
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, plink_timeout, 1, 0xffffffff,
|
||||
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, plink_timeout, 0, 0xffffffff,
|
||||
mask, NL80211_MESHCONF_PLINK_TIMEOUT,
|
||||
nla_get_u32);
|
||||
if (mask_out)
|
||||
@@ -7275,8 +7286,18 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
|
||||
break;
|
||||
case NL80211_CHAN_WIDTH_20:
|
||||
case NL80211_CHAN_WIDTH_40:
|
||||
if (rdev->wiphy.features & NL80211_FEATURE_HT_IBSS)
|
||||
break;
|
||||
if (!(rdev->wiphy.features & NL80211_FEATURE_HT_IBSS))
|
||||
return -EINVAL;
|
||||
break;
|
||||
case NL80211_CHAN_WIDTH_80:
|
||||
case NL80211_CHAN_WIDTH_80P80:
|
||||
case NL80211_CHAN_WIDTH_160:
|
||||
if (!(rdev->wiphy.features & NL80211_FEATURE_HT_IBSS))
|
||||
return -EINVAL;
|
||||
if (!wiphy_ext_feature_isset(&rdev->wiphy,
|
||||
NL80211_EXT_FEATURE_VHT_IBSS))
|
||||
return -EINVAL;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -7389,8 +7410,8 @@ static int nl80211_set_mcast_rate(struct sk_buff *skb, struct genl_info *info)
|
||||
|
||||
static struct sk_buff *
|
||||
__cfg80211_alloc_vendor_skb(struct cfg80211_registered_device *rdev,
|
||||
int approxlen, u32 portid, u32 seq,
|
||||
enum nl80211_commands cmd,
|
||||
struct wireless_dev *wdev, int approxlen,
|
||||
u32 portid, u32 seq, enum nl80211_commands cmd,
|
||||
enum nl80211_attrs attr,
|
||||
const struct nl80211_vendor_cmd_info *info,
|
||||
gfp_t gfp)
|
||||
@@ -7421,6 +7442,16 @@ __cfg80211_alloc_vendor_skb(struct cfg80211_registered_device *rdev,
|
||||
goto nla_put_failure;
|
||||
}
|
||||
|
||||
if (wdev) {
|
||||
if (nla_put_u64(skb, NL80211_ATTR_WDEV,
|
||||
wdev_id(wdev)))
|
||||
goto nla_put_failure;
|
||||
if (wdev->netdev &&
|
||||
nla_put_u32(skb, NL80211_ATTR_IFINDEX,
|
||||
wdev->netdev->ifindex))
|
||||
goto nla_put_failure;
|
||||
}
|
||||
|
||||
data = nla_nest_start(skb, attr);
|
||||
|
||||
((void **)skb->cb)[0] = rdev;
|
||||
@@ -7435,6 +7466,7 @@ __cfg80211_alloc_vendor_skb(struct cfg80211_registered_device *rdev,
|
||||
}
|
||||
|
||||
struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev,
|
||||
enum nl80211_commands cmd,
|
||||
enum nl80211_attrs attr,
|
||||
int vendor_event_idx,
|
||||
@@ -7460,7 +7492,7 @@ struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return __cfg80211_alloc_vendor_skb(rdev, approxlen, 0, 0,
|
||||
return __cfg80211_alloc_vendor_skb(rdev, wdev, approxlen, 0, 0,
|
||||
cmd, attr, info, gfp);
|
||||
}
|
||||
EXPORT_SYMBOL(__cfg80211_alloc_event_skb);
|
||||
@@ -8808,6 +8840,9 @@ static int nl80211_send_wowlan_nd(struct sk_buff *msg,
|
||||
if (nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL, req->interval))
|
||||
return -ENOBUFS;
|
||||
|
||||
if (nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_DELAY, req->delay))
|
||||
return -ENOBUFS;
|
||||
|
||||
freqs = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES);
|
||||
if (!freqs)
|
||||
return -ENOBUFS;
|
||||
@@ -9094,6 +9129,7 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
|
||||
const struct wiphy_wowlan_support *wowlan = rdev->wiphy.wowlan;
|
||||
int err, i;
|
||||
bool prev_enabled = rdev->wiphy.wowlan_config;
|
||||
bool regular = false;
|
||||
|
||||
if (!wowlan)
|
||||
return -EOPNOTSUPP;
|
||||
@@ -9121,12 +9157,14 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
|
||||
if (!(wowlan->flags & WIPHY_WOWLAN_DISCONNECT))
|
||||
return -EINVAL;
|
||||
new_triggers.disconnect = true;
|
||||
regular = true;
|
||||
}
|
||||
|
||||
if (tb[NL80211_WOWLAN_TRIG_MAGIC_PKT]) {
|
||||
if (!(wowlan->flags & WIPHY_WOWLAN_MAGIC_PKT))
|
||||
return -EINVAL;
|
||||
new_triggers.magic_pkt = true;
|
||||
regular = true;
|
||||
}
|
||||
|
||||
if (tb[NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED])
|
||||
@@ -9136,24 +9174,28 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
|
||||
if (!(wowlan->flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE))
|
||||
return -EINVAL;
|
||||
new_triggers.gtk_rekey_failure = true;
|
||||
regular = true;
|
||||
}
|
||||
|
||||
if (tb[NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST]) {
|
||||
if (!(wowlan->flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ))
|
||||
return -EINVAL;
|
||||
new_triggers.eap_identity_req = true;
|
||||
regular = true;
|
||||
}
|
||||
|
||||
if (tb[NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE]) {
|
||||
if (!(wowlan->flags & WIPHY_WOWLAN_4WAY_HANDSHAKE))
|
||||
return -EINVAL;
|
||||
new_triggers.four_way_handshake = true;
|
||||
regular = true;
|
||||
}
|
||||
|
||||
if (tb[NL80211_WOWLAN_TRIG_RFKILL_RELEASE]) {
|
||||
if (!(wowlan->flags & WIPHY_WOWLAN_RFKILL_RELEASE))
|
||||
return -EINVAL;
|
||||
new_triggers.rfkill_release = true;
|
||||
regular = true;
|
||||
}
|
||||
|
||||
if (tb[NL80211_WOWLAN_TRIG_PKT_PATTERN]) {
|
||||
@@ -9162,6 +9204,8 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
|
||||
int rem, pat_len, mask_len, pkt_offset;
|
||||
struct nlattr *pat_tb[NUM_NL80211_PKTPAT];
|
||||
|
||||
regular = true;
|
||||
|
||||
nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN],
|
||||
rem)
|
||||
n_patterns++;
|
||||
@@ -9223,6 +9267,7 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
|
||||
}
|
||||
|
||||
if (tb[NL80211_WOWLAN_TRIG_TCP_CONNECTION]) {
|
||||
regular = true;
|
||||
err = nl80211_parse_wowlan_tcp(
|
||||
rdev, tb[NL80211_WOWLAN_TRIG_TCP_CONNECTION],
|
||||
&new_triggers);
|
||||
@@ -9231,6 +9276,7 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
|
||||
}
|
||||
|
||||
if (tb[NL80211_WOWLAN_TRIG_NET_DETECT]) {
|
||||
regular = true;
|
||||
err = nl80211_parse_wowlan_nd(
|
||||
rdev, wowlan, tb[NL80211_WOWLAN_TRIG_NET_DETECT],
|
||||
&new_triggers);
|
||||
@@ -9238,6 +9284,17 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* The 'any' trigger means the device continues operating more or less
|
||||
* as in its normal operation mode and wakes up the host on most of the
|
||||
* normal interrupts (like packet RX, ...)
|
||||
* It therefore makes little sense to combine with the more constrained
|
||||
* wakeup trigger modes.
|
||||
*/
|
||||
if (new_triggers.any && regular) {
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
ntrig = kmemdup(&new_triggers, sizeof(new_triggers), GFP_KERNEL);
|
||||
if (!ntrig) {
|
||||
err = -ENOMEM;
|
||||
@@ -9906,7 +9963,7 @@ struct sk_buff *__cfg80211_alloc_reply_skb(struct wiphy *wiphy,
|
||||
if (WARN_ON(!rdev->cur_cmd_info))
|
||||
return NULL;
|
||||
|
||||
return __cfg80211_alloc_vendor_skb(rdev, approxlen,
|
||||
return __cfg80211_alloc_vendor_skb(rdev, NULL, approxlen,
|
||||
rdev->cur_cmd_info->snd_portid,
|
||||
rdev->cur_cmd_info->snd_seq,
|
||||
cmd, attr, NULL, GFP_KERNEL);
|
||||
@@ -12775,6 +12832,11 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
/*
|
||||
* It is possible that the user space process that is controlling the
|
||||
* indoor setting disappeared, so notify the regulatory core.
|
||||
*/
|
||||
regulatory_netlink_notify(notify->portid);
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
|
@@ -35,13 +35,14 @@ static inline void rdev_set_wakeup(struct cfg80211_registered_device *rdev,
|
||||
|
||||
static inline struct wireless_dev
|
||||
*rdev_add_virtual_intf(struct cfg80211_registered_device *rdev, char *name,
|
||||
unsigned char name_assign_type,
|
||||
enum nl80211_iftype type, u32 *flags,
|
||||
struct vif_params *params)
|
||||
{
|
||||
struct wireless_dev *ret;
|
||||
trace_rdev_add_virtual_intf(&rdev->wiphy, name, type);
|
||||
ret = rdev->ops->add_virtual_intf(&rdev->wiphy, name, type, flags,
|
||||
params);
|
||||
ret = rdev->ops->add_virtual_intf(&rdev->wiphy, name, name_assign_type,
|
||||
type, flags, params);
|
||||
trace_rdev_return_wdev(&rdev->wiphy, ret);
|
||||
return ret;
|
||||
}
|
||||
|
@@ -82,17 +82,12 @@
|
||||
* be intersected with the current one.
|
||||
* @REG_REQ_ALREADY_SET: the regulatory request will not change the current
|
||||
* regulatory settings, and no further processing is required.
|
||||
* @REG_REQ_USER_HINT_HANDLED: a non alpha2 user hint was handled and no
|
||||
* further processing is required, i.e., not need to update last_request
|
||||
* etc. This should be used for user hints that do not provide an alpha2
|
||||
* but some other type of regulatory hint, i.e., indoor operation.
|
||||
*/
|
||||
enum reg_request_treatment {
|
||||
REG_REQ_OK,
|
||||
REG_REQ_IGNORE,
|
||||
REG_REQ_INTERSECT,
|
||||
REG_REQ_ALREADY_SET,
|
||||
REG_REQ_USER_HINT_HANDLED,
|
||||
};
|
||||
|
||||
static struct regulatory_request core_request_world = {
|
||||
@@ -133,9 +128,12 @@ static int reg_num_devs_support_basehint;
|
||||
* State variable indicating if the platform on which the devices
|
||||
* are attached is operating in an indoor environment. The state variable
|
||||
* is relevant for all registered devices.
|
||||
* (protected by RTNL)
|
||||
*/
|
||||
static bool reg_is_indoor;
|
||||
static spinlock_t reg_indoor_lock;
|
||||
|
||||
/* Used to track the userspace process controlling the indoor setting */
|
||||
static u32 reg_is_indoor_portid;
|
||||
|
||||
static const struct ieee80211_regdomain *get_cfg80211_regdom(void)
|
||||
{
|
||||
@@ -554,6 +552,9 @@ reg_call_crda(struct regulatory_request *request)
|
||||
{
|
||||
if (call_crda(request->alpha2))
|
||||
return REG_REQ_IGNORE;
|
||||
|
||||
queue_delayed_work(system_power_efficient_wq,
|
||||
®_timeout, msecs_to_jiffies(3142));
|
||||
return REG_REQ_OK;
|
||||
}
|
||||
|
||||
@@ -1248,13 +1249,6 @@ static bool reg_request_cell_base(struct regulatory_request *request)
|
||||
return request->user_reg_hint_type == NL80211_USER_REG_HINT_CELL_BASE;
|
||||
}
|
||||
|
||||
static bool reg_request_indoor(struct regulatory_request *request)
|
||||
{
|
||||
if (request->initiator != NL80211_REGDOM_SET_BY_USER)
|
||||
return false;
|
||||
return request->user_reg_hint_type == NL80211_USER_REG_HINT_INDOOR;
|
||||
}
|
||||
|
||||
bool reg_last_request_cell_base(void)
|
||||
{
|
||||
return reg_request_cell_base(get_last_request());
|
||||
@@ -1800,8 +1794,7 @@ static void reg_set_request_processed(void)
|
||||
need_more_processing = true;
|
||||
spin_unlock(®_requests_lock);
|
||||
|
||||
if (lr->initiator == NL80211_REGDOM_SET_BY_USER)
|
||||
cancel_delayed_work(®_timeout);
|
||||
cancel_delayed_work(®_timeout);
|
||||
|
||||
if (need_more_processing)
|
||||
schedule_work(®_work);
|
||||
@@ -1833,11 +1826,6 @@ __reg_process_hint_user(struct regulatory_request *user_request)
|
||||
{
|
||||
struct regulatory_request *lr = get_last_request();
|
||||
|
||||
if (reg_request_indoor(user_request)) {
|
||||
reg_is_indoor = true;
|
||||
return REG_REQ_USER_HINT_HANDLED;
|
||||
}
|
||||
|
||||
if (reg_request_cell_base(user_request))
|
||||
return reg_ignore_cell_hint(user_request);
|
||||
|
||||
@@ -1885,8 +1873,7 @@ reg_process_hint_user(struct regulatory_request *user_request)
|
||||
|
||||
treatment = __reg_process_hint_user(user_request);
|
||||
if (treatment == REG_REQ_IGNORE ||
|
||||
treatment == REG_REQ_ALREADY_SET ||
|
||||
treatment == REG_REQ_USER_HINT_HANDLED) {
|
||||
treatment == REG_REQ_ALREADY_SET) {
|
||||
reg_free_request(user_request);
|
||||
return treatment;
|
||||
}
|
||||
@@ -1947,7 +1934,6 @@ reg_process_hint_driver(struct wiphy *wiphy,
|
||||
case REG_REQ_OK:
|
||||
break;
|
||||
case REG_REQ_IGNORE:
|
||||
case REG_REQ_USER_HINT_HANDLED:
|
||||
reg_free_request(driver_request);
|
||||
return treatment;
|
||||
case REG_REQ_INTERSECT:
|
||||
@@ -2047,7 +2033,6 @@ reg_process_hint_country_ie(struct wiphy *wiphy,
|
||||
case REG_REQ_OK:
|
||||
break;
|
||||
case REG_REQ_IGNORE:
|
||||
case REG_REQ_USER_HINT_HANDLED:
|
||||
/* fall through */
|
||||
case REG_REQ_ALREADY_SET:
|
||||
reg_free_request(country_ie_request);
|
||||
@@ -2086,11 +2071,8 @@ static void reg_process_hint(struct regulatory_request *reg_request)
|
||||
case NL80211_REGDOM_SET_BY_USER:
|
||||
treatment = reg_process_hint_user(reg_request);
|
||||
if (treatment == REG_REQ_IGNORE ||
|
||||
treatment == REG_REQ_ALREADY_SET ||
|
||||
treatment == REG_REQ_USER_HINT_HANDLED)
|
||||
treatment == REG_REQ_ALREADY_SET)
|
||||
return;
|
||||
queue_delayed_work(system_power_efficient_wq,
|
||||
®_timeout, msecs_to_jiffies(3142));
|
||||
return;
|
||||
case NL80211_REGDOM_SET_BY_DRIVER:
|
||||
if (!wiphy)
|
||||
@@ -2177,6 +2159,13 @@ static void reg_process_pending_hints(void)
|
||||
}
|
||||
|
||||
reg_process_hint(reg_request);
|
||||
|
||||
lr = get_last_request();
|
||||
|
||||
spin_lock(®_requests_lock);
|
||||
if (!list_empty(®_requests_list) && lr && lr->processed)
|
||||
schedule_work(®_work);
|
||||
spin_unlock(®_requests_lock);
|
||||
}
|
||||
|
||||
/* Processes beacon hints -- this has nothing to do with country IEs */
|
||||
@@ -2309,22 +2298,50 @@ int regulatory_hint_user(const char *alpha2,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int regulatory_hint_indoor_user(void)
|
||||
int regulatory_hint_indoor(bool is_indoor, u32 portid)
|
||||
{
|
||||
struct regulatory_request *request;
|
||||
spin_lock(®_indoor_lock);
|
||||
|
||||
request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL);
|
||||
if (!request)
|
||||
return -ENOMEM;
|
||||
/* It is possible that more than one user space process is trying to
|
||||
* configure the indoor setting. To handle such cases, clear the indoor
|
||||
* setting in case that some process does not think that the device
|
||||
* is operating in an indoor environment. In addition, if a user space
|
||||
* process indicates that it is controlling the indoor setting, save its
|
||||
* portid, i.e., make it the owner.
|
||||
*/
|
||||
reg_is_indoor = is_indoor;
|
||||
if (reg_is_indoor) {
|
||||
if (!reg_is_indoor_portid)
|
||||
reg_is_indoor_portid = portid;
|
||||
} else {
|
||||
reg_is_indoor_portid = 0;
|
||||
}
|
||||
|
||||
request->wiphy_idx = WIPHY_IDX_INVALID;
|
||||
request->initiator = NL80211_REGDOM_SET_BY_USER;
|
||||
request->user_reg_hint_type = NL80211_USER_REG_HINT_INDOOR;
|
||||
queue_regulatory_request(request);
|
||||
spin_unlock(®_indoor_lock);
|
||||
|
||||
if (!is_indoor)
|
||||
reg_check_channels();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void regulatory_netlink_notify(u32 portid)
|
||||
{
|
||||
spin_lock(®_indoor_lock);
|
||||
|
||||
if (reg_is_indoor_portid != portid) {
|
||||
spin_unlock(®_indoor_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
reg_is_indoor = false;
|
||||
reg_is_indoor_portid = 0;
|
||||
|
||||
spin_unlock(®_indoor_lock);
|
||||
|
||||
reg_check_channels();
|
||||
}
|
||||
|
||||
/* Driver hints */
|
||||
int regulatory_hint(struct wiphy *wiphy, const char *alpha2)
|
||||
{
|
||||
@@ -2486,13 +2503,22 @@ static void restore_regulatory_settings(bool reset_user)
|
||||
char alpha2[2];
|
||||
char world_alpha2[2];
|
||||
struct reg_beacon *reg_beacon, *btmp;
|
||||
struct regulatory_request *reg_request, *tmp;
|
||||
LIST_HEAD(tmp_reg_req_list);
|
||||
struct cfg80211_registered_device *rdev;
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
reg_is_indoor = false;
|
||||
/*
|
||||
* Clear the indoor setting in case that it is not controlled by user
|
||||
* space, as otherwise there is no guarantee that the device is still
|
||||
* operating in an indoor environment.
|
||||
*/
|
||||
spin_lock(®_indoor_lock);
|
||||
if (reg_is_indoor && !reg_is_indoor_portid) {
|
||||
reg_is_indoor = false;
|
||||
reg_check_channels();
|
||||
}
|
||||
spin_unlock(®_indoor_lock);
|
||||
|
||||
reset_regdomains(true, &world_regdom);
|
||||
restore_alpha2(alpha2, reset_user);
|
||||
@@ -2504,11 +2530,7 @@ static void restore_regulatory_settings(bool reset_user)
|
||||
* settings.
|
||||
*/
|
||||
spin_lock(®_requests_lock);
|
||||
list_for_each_entry_safe(reg_request, tmp, ®_requests_list, list) {
|
||||
if (reg_request->initiator != NL80211_REGDOM_SET_BY_USER)
|
||||
continue;
|
||||
list_move_tail(®_request->list, &tmp_reg_req_list);
|
||||
}
|
||||
list_splice_tail_init(®_requests_list, &tmp_reg_req_list);
|
||||
spin_unlock(®_requests_lock);
|
||||
|
||||
/* Clear beacon hints */
|
||||
@@ -3089,6 +3111,7 @@ int __init regulatory_init(void)
|
||||
|
||||
spin_lock_init(®_requests_lock);
|
||||
spin_lock_init(®_pending_beacons_lock);
|
||||
spin_lock_init(®_indoor_lock);
|
||||
|
||||
reg_regdb_size_check();
|
||||
|
||||
|
@@ -25,7 +25,20 @@ enum nl80211_dfs_regions reg_get_dfs_region(struct wiphy *wiphy);
|
||||
|
||||
int regulatory_hint_user(const char *alpha2,
|
||||
enum nl80211_user_reg_hint_type user_reg_hint_type);
|
||||
int regulatory_hint_indoor_user(void);
|
||||
|
||||
/**
|
||||
* regulatory_hint_indoor - hint operation in indoor env. or not
|
||||
* @is_indoor: if true indicates that user space thinks that the
|
||||
* device is operating in an indoor environment.
|
||||
* @portid: the netlink port ID on which the hint was given.
|
||||
*/
|
||||
int regulatory_hint_indoor(bool is_indoor, u32 portid);
|
||||
|
||||
/**
|
||||
* regulatory_netlink_notify - notify on released netlink socket
|
||||
* @portid: the netlink socket port ID
|
||||
*/
|
||||
void regulatory_netlink_notify(u32 portid);
|
||||
|
||||
void wiphy_regulatory_register(struct wiphy *wiphy);
|
||||
void wiphy_regulatory_deregister(struct wiphy *wiphy);
|
||||
|
@@ -531,24 +531,78 @@ static int cmp_bss(struct cfg80211_bss *a,
|
||||
}
|
||||
}
|
||||
|
||||
static bool cfg80211_bss_type_match(u16 capability,
|
||||
enum ieee80211_band band,
|
||||
enum ieee80211_bss_type bss_type)
|
||||
{
|
||||
bool ret = true;
|
||||
u16 mask, val;
|
||||
|
||||
if (bss_type == IEEE80211_BSS_TYPE_ANY)
|
||||
return ret;
|
||||
|
||||
if (band == IEEE80211_BAND_60GHZ) {
|
||||
mask = WLAN_CAPABILITY_DMG_TYPE_MASK;
|
||||
switch (bss_type) {
|
||||
case IEEE80211_BSS_TYPE_ESS:
|
||||
val = WLAN_CAPABILITY_DMG_TYPE_AP;
|
||||
break;
|
||||
case IEEE80211_BSS_TYPE_PBSS:
|
||||
val = WLAN_CAPABILITY_DMG_TYPE_PBSS;
|
||||
break;
|
||||
case IEEE80211_BSS_TYPE_IBSS:
|
||||
val = WLAN_CAPABILITY_DMG_TYPE_IBSS;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
mask = WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS;
|
||||
switch (bss_type) {
|
||||
case IEEE80211_BSS_TYPE_ESS:
|
||||
val = WLAN_CAPABILITY_ESS;
|
||||
break;
|
||||
case IEEE80211_BSS_TYPE_IBSS:
|
||||
val = WLAN_CAPABILITY_IBSS;
|
||||
break;
|
||||
case IEEE80211_BSS_TYPE_MBSS:
|
||||
val = 0;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ret = ((capability & mask) == val);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Returned bss is reference counted and must be cleaned up appropriately. */
|
||||
struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy,
|
||||
struct ieee80211_channel *channel,
|
||||
const u8 *bssid,
|
||||
const u8 *ssid, size_t ssid_len,
|
||||
u16 capa_mask, u16 capa_val)
|
||||
enum ieee80211_bss_type bss_type,
|
||||
enum ieee80211_privacy privacy)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
|
||||
struct cfg80211_internal_bss *bss, *res = NULL;
|
||||
unsigned long now = jiffies;
|
||||
int bss_privacy;
|
||||
|
||||
trace_cfg80211_get_bss(wiphy, channel, bssid, ssid, ssid_len, capa_mask,
|
||||
capa_val);
|
||||
trace_cfg80211_get_bss(wiphy, channel, bssid, ssid, ssid_len, bss_type,
|
||||
privacy);
|
||||
|
||||
spin_lock_bh(&rdev->bss_lock);
|
||||
|
||||
list_for_each_entry(bss, &rdev->bss_list, list) {
|
||||
if ((bss->pub.capability & capa_mask) != capa_val)
|
||||
if (!cfg80211_bss_type_match(bss->pub.capability,
|
||||
bss->pub.channel->band, bss_type))
|
||||
continue;
|
||||
|
||||
bss_privacy = (bss->pub.capability & WLAN_CAPABILITY_PRIVACY);
|
||||
if ((privacy == IEEE80211_PRIVACY_ON && !bss_privacy) ||
|
||||
(privacy == IEEE80211_PRIVACY_OFF && bss_privacy))
|
||||
continue;
|
||||
if (channel && bss->pub.channel != channel)
|
||||
continue;
|
||||
@@ -896,6 +950,7 @@ cfg80211_inform_bss_width(struct wiphy *wiphy,
|
||||
struct cfg80211_bss_ies *ies;
|
||||
struct ieee80211_channel *channel;
|
||||
struct cfg80211_internal_bss tmp = {}, *res;
|
||||
int bss_type;
|
||||
bool signal_valid;
|
||||
|
||||
if (WARN_ON(!wiphy))
|
||||
@@ -950,8 +1005,15 @@ cfg80211_inform_bss_width(struct wiphy *wiphy,
|
||||
if (!res)
|
||||
return NULL;
|
||||
|
||||
if (res->pub.capability & WLAN_CAPABILITY_ESS)
|
||||
regulatory_hint_found_beacon(wiphy, channel, gfp);
|
||||
if (channel->band == IEEE80211_BAND_60GHZ) {
|
||||
bss_type = res->pub.capability & WLAN_CAPABILITY_DMG_TYPE_MASK;
|
||||
if (bss_type == WLAN_CAPABILITY_DMG_TYPE_AP ||
|
||||
bss_type == WLAN_CAPABILITY_DMG_TYPE_PBSS)
|
||||
regulatory_hint_found_beacon(wiphy, channel, gfp);
|
||||
} else {
|
||||
if (res->pub.capability & WLAN_CAPABILITY_ESS)
|
||||
regulatory_hint_found_beacon(wiphy, channel, gfp);
|
||||
}
|
||||
|
||||
trace_cfg80211_return_bss(&res->pub);
|
||||
/* cfg80211_bss_update gives us a referenced result */
|
||||
@@ -973,6 +1035,7 @@ cfg80211_inform_bss_width_frame(struct wiphy *wiphy,
|
||||
bool signal_valid;
|
||||
size_t ielen = len - offsetof(struct ieee80211_mgmt,
|
||||
u.probe_resp.variable);
|
||||
int bss_type;
|
||||
|
||||
BUILD_BUG_ON(offsetof(struct ieee80211_mgmt, u.probe_resp.variable) !=
|
||||
offsetof(struct ieee80211_mgmt, u.beacon.variable));
|
||||
@@ -1025,8 +1088,15 @@ cfg80211_inform_bss_width_frame(struct wiphy *wiphy,
|
||||
if (!res)
|
||||
return NULL;
|
||||
|
||||
if (res->pub.capability & WLAN_CAPABILITY_ESS)
|
||||
regulatory_hint_found_beacon(wiphy, channel, gfp);
|
||||
if (channel->band == IEEE80211_BAND_60GHZ) {
|
||||
bss_type = res->pub.capability & WLAN_CAPABILITY_DMG_TYPE_MASK;
|
||||
if (bss_type == WLAN_CAPABILITY_DMG_TYPE_AP ||
|
||||
bss_type == WLAN_CAPABILITY_DMG_TYPE_PBSS)
|
||||
regulatory_hint_found_beacon(wiphy, channel, gfp);
|
||||
} else {
|
||||
if (res->pub.capability & WLAN_CAPABILITY_ESS)
|
||||
regulatory_hint_found_beacon(wiphy, channel, gfp);
|
||||
}
|
||||
|
||||
trace_cfg80211_return_bss(&res->pub);
|
||||
/* cfg80211_bss_update gives us a referenced result */
|
||||
@@ -1237,17 +1307,17 @@ int cfg80211_wext_siwscan(struct net_device *dev,
|
||||
kfree(creq);
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cfg80211_wext_siwscan);
|
||||
EXPORT_WEXT_HANDLER(cfg80211_wext_siwscan);
|
||||
|
||||
static void ieee80211_scan_add_ies(struct iw_request_info *info,
|
||||
const struct cfg80211_bss_ies *ies,
|
||||
char **current_ev, char *end_buf)
|
||||
static char *ieee80211_scan_add_ies(struct iw_request_info *info,
|
||||
const struct cfg80211_bss_ies *ies,
|
||||
char *current_ev, char *end_buf)
|
||||
{
|
||||
const u8 *pos, *end, *next;
|
||||
struct iw_event iwe;
|
||||
|
||||
if (!ies)
|
||||
return;
|
||||
return current_ev;
|
||||
|
||||
/*
|
||||
* If needed, fragment the IEs buffer (at IE boundaries) into short
|
||||
@@ -1264,10 +1334,11 @@ static void ieee80211_scan_add_ies(struct iw_request_info *info,
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
iwe.cmd = IWEVGENIE;
|
||||
iwe.u.data.length = next - pos;
|
||||
*current_ev = iwe_stream_add_point(info, *current_ev,
|
||||
end_buf, &iwe,
|
||||
(void *)pos);
|
||||
|
||||
current_ev = iwe_stream_add_point_check(info, current_ev,
|
||||
end_buf, &iwe,
|
||||
(void *)pos);
|
||||
if (IS_ERR(current_ev))
|
||||
return current_ev;
|
||||
pos = next;
|
||||
}
|
||||
|
||||
@@ -1275,10 +1346,14 @@ static void ieee80211_scan_add_ies(struct iw_request_info *info,
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
iwe.cmd = IWEVGENIE;
|
||||
iwe.u.data.length = end - pos;
|
||||
*current_ev = iwe_stream_add_point(info, *current_ev,
|
||||
end_buf, &iwe,
|
||||
(void *)pos);
|
||||
current_ev = iwe_stream_add_point_check(info, current_ev,
|
||||
end_buf, &iwe,
|
||||
(void *)pos);
|
||||
if (IS_ERR(current_ev))
|
||||
return current_ev;
|
||||
}
|
||||
|
||||
return current_ev;
|
||||
}
|
||||
|
||||
static char *
|
||||
@@ -1289,7 +1364,8 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
|
||||
const struct cfg80211_bss_ies *ies;
|
||||
struct iw_event iwe;
|
||||
const u8 *ie;
|
||||
u8 *buf, *cfg, *p;
|
||||
u8 buf[50];
|
||||
u8 *cfg, *p, *tmp;
|
||||
int rem, i, sig;
|
||||
bool ismesh = false;
|
||||
|
||||
@@ -1297,22 +1373,28 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
|
||||
iwe.cmd = SIOCGIWAP;
|
||||
iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
|
||||
memcpy(iwe.u.ap_addr.sa_data, bss->pub.bssid, ETH_ALEN);
|
||||
current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
|
||||
IW_EV_ADDR_LEN);
|
||||
current_ev = iwe_stream_add_event_check(info, current_ev, end_buf, &iwe,
|
||||
IW_EV_ADDR_LEN);
|
||||
if (IS_ERR(current_ev))
|
||||
return current_ev;
|
||||
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
iwe.cmd = SIOCGIWFREQ;
|
||||
iwe.u.freq.m = ieee80211_frequency_to_channel(bss->pub.channel->center_freq);
|
||||
iwe.u.freq.e = 0;
|
||||
current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
|
||||
IW_EV_FREQ_LEN);
|
||||
current_ev = iwe_stream_add_event_check(info, current_ev, end_buf, &iwe,
|
||||
IW_EV_FREQ_LEN);
|
||||
if (IS_ERR(current_ev))
|
||||
return current_ev;
|
||||
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
iwe.cmd = SIOCGIWFREQ;
|
||||
iwe.u.freq.m = bss->pub.channel->center_freq;
|
||||
iwe.u.freq.e = 6;
|
||||
current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
|
||||
IW_EV_FREQ_LEN);
|
||||
current_ev = iwe_stream_add_event_check(info, current_ev, end_buf, &iwe,
|
||||
IW_EV_FREQ_LEN);
|
||||
if (IS_ERR(current_ev))
|
||||
return current_ev;
|
||||
|
||||
if (wiphy->signal_type != CFG80211_SIGNAL_TYPE_NONE) {
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
@@ -1341,8 +1423,11 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
|
||||
/* not reached */
|
||||
break;
|
||||
}
|
||||
current_ev = iwe_stream_add_event(info, current_ev, end_buf,
|
||||
&iwe, IW_EV_QUAL_LEN);
|
||||
current_ev = iwe_stream_add_event_check(info, current_ev,
|
||||
end_buf, &iwe,
|
||||
IW_EV_QUAL_LEN);
|
||||
if (IS_ERR(current_ev))
|
||||
return current_ev;
|
||||
}
|
||||
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
@@ -1352,8 +1437,10 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
|
||||
else
|
||||
iwe.u.data.flags = IW_ENCODE_DISABLED;
|
||||
iwe.u.data.length = 0;
|
||||
current_ev = iwe_stream_add_point(info, current_ev, end_buf,
|
||||
&iwe, "");
|
||||
current_ev = iwe_stream_add_point_check(info, current_ev, end_buf,
|
||||
&iwe, "");
|
||||
if (IS_ERR(current_ev))
|
||||
return current_ev;
|
||||
|
||||
rcu_read_lock();
|
||||
ies = rcu_dereference(bss->pub.ies);
|
||||
@@ -1371,66 +1458,91 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
|
||||
iwe.cmd = SIOCGIWESSID;
|
||||
iwe.u.data.length = ie[1];
|
||||
iwe.u.data.flags = 1;
|
||||
current_ev = iwe_stream_add_point(info, current_ev, end_buf,
|
||||
&iwe, (u8 *)ie + 2);
|
||||
current_ev = iwe_stream_add_point_check(info,
|
||||
current_ev,
|
||||
end_buf, &iwe,
|
||||
(u8 *)ie + 2);
|
||||
if (IS_ERR(current_ev))
|
||||
goto unlock;
|
||||
break;
|
||||
case WLAN_EID_MESH_ID:
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
iwe.cmd = SIOCGIWESSID;
|
||||
iwe.u.data.length = ie[1];
|
||||
iwe.u.data.flags = 1;
|
||||
current_ev = iwe_stream_add_point(info, current_ev, end_buf,
|
||||
&iwe, (u8 *)ie + 2);
|
||||
current_ev = iwe_stream_add_point_check(info,
|
||||
current_ev,
|
||||
end_buf, &iwe,
|
||||
(u8 *)ie + 2);
|
||||
if (IS_ERR(current_ev))
|
||||
goto unlock;
|
||||
break;
|
||||
case WLAN_EID_MESH_CONFIG:
|
||||
ismesh = true;
|
||||
if (ie[1] != sizeof(struct ieee80211_meshconf_ie))
|
||||
break;
|
||||
buf = kmalloc(50, GFP_ATOMIC);
|
||||
if (!buf)
|
||||
break;
|
||||
cfg = (u8 *)ie + 2;
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
iwe.cmd = IWEVCUSTOM;
|
||||
sprintf(buf, "Mesh Network Path Selection Protocol ID: "
|
||||
"0x%02X", cfg[0]);
|
||||
iwe.u.data.length = strlen(buf);
|
||||
current_ev = iwe_stream_add_point(info, current_ev,
|
||||
end_buf,
|
||||
&iwe, buf);
|
||||
current_ev = iwe_stream_add_point_check(info,
|
||||
current_ev,
|
||||
end_buf,
|
||||
&iwe, buf);
|
||||
if (IS_ERR(current_ev))
|
||||
goto unlock;
|
||||
sprintf(buf, "Path Selection Metric ID: 0x%02X",
|
||||
cfg[1]);
|
||||
iwe.u.data.length = strlen(buf);
|
||||
current_ev = iwe_stream_add_point(info, current_ev,
|
||||
end_buf,
|
||||
&iwe, buf);
|
||||
current_ev = iwe_stream_add_point_check(info,
|
||||
current_ev,
|
||||
end_buf,
|
||||
&iwe, buf);
|
||||
if (IS_ERR(current_ev))
|
||||
goto unlock;
|
||||
sprintf(buf, "Congestion Control Mode ID: 0x%02X",
|
||||
cfg[2]);
|
||||
iwe.u.data.length = strlen(buf);
|
||||
current_ev = iwe_stream_add_point(info, current_ev,
|
||||
end_buf,
|
||||
&iwe, buf);
|
||||
current_ev = iwe_stream_add_point_check(info,
|
||||
current_ev,
|
||||
end_buf,
|
||||
&iwe, buf);
|
||||
if (IS_ERR(current_ev))
|
||||
goto unlock;
|
||||
sprintf(buf, "Synchronization ID: 0x%02X", cfg[3]);
|
||||
iwe.u.data.length = strlen(buf);
|
||||
current_ev = iwe_stream_add_point(info, current_ev,
|
||||
end_buf,
|
||||
&iwe, buf);
|
||||
current_ev = iwe_stream_add_point_check(info,
|
||||
current_ev,
|
||||
end_buf,
|
||||
&iwe, buf);
|
||||
if (IS_ERR(current_ev))
|
||||
goto unlock;
|
||||
sprintf(buf, "Authentication ID: 0x%02X", cfg[4]);
|
||||
iwe.u.data.length = strlen(buf);
|
||||
current_ev = iwe_stream_add_point(info, current_ev,
|
||||
end_buf,
|
||||
&iwe, buf);
|
||||
current_ev = iwe_stream_add_point_check(info,
|
||||
current_ev,
|
||||
end_buf,
|
||||
&iwe, buf);
|
||||
if (IS_ERR(current_ev))
|
||||
goto unlock;
|
||||
sprintf(buf, "Formation Info: 0x%02X", cfg[5]);
|
||||
iwe.u.data.length = strlen(buf);
|
||||
current_ev = iwe_stream_add_point(info, current_ev,
|
||||
end_buf,
|
||||
&iwe, buf);
|
||||
current_ev = iwe_stream_add_point_check(info,
|
||||
current_ev,
|
||||
end_buf,
|
||||
&iwe, buf);
|
||||
if (IS_ERR(current_ev))
|
||||
goto unlock;
|
||||
sprintf(buf, "Capabilities: 0x%02X", cfg[6]);
|
||||
iwe.u.data.length = strlen(buf);
|
||||
current_ev = iwe_stream_add_point(info, current_ev,
|
||||
end_buf,
|
||||
&iwe, buf);
|
||||
kfree(buf);
|
||||
current_ev = iwe_stream_add_point_check(info,
|
||||
current_ev,
|
||||
end_buf,
|
||||
&iwe, buf);
|
||||
if (IS_ERR(current_ev))
|
||||
goto unlock;
|
||||
break;
|
||||
case WLAN_EID_SUPP_RATES:
|
||||
case WLAN_EID_EXT_SUPP_RATES:
|
||||
@@ -1445,8 +1557,14 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
|
||||
for (i = 0; i < ie[1]; i++) {
|
||||
iwe.u.bitrate.value =
|
||||
((ie[i + 2] & 0x7f) * 500000);
|
||||
tmp = p;
|
||||
p = iwe_stream_add_value(info, current_ev, p,
|
||||
end_buf, &iwe, IW_EV_PARAM_LEN);
|
||||
end_buf, &iwe,
|
||||
IW_EV_PARAM_LEN);
|
||||
if (p == tmp) {
|
||||
current_ev = ERR_PTR(-E2BIG);
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
current_ev = p;
|
||||
break;
|
||||
@@ -1465,31 +1583,35 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
|
||||
iwe.u.mode = IW_MODE_MASTER;
|
||||
else
|
||||
iwe.u.mode = IW_MODE_ADHOC;
|
||||
current_ev = iwe_stream_add_event(info, current_ev, end_buf,
|
||||
&iwe, IW_EV_UINT_LEN);
|
||||
current_ev = iwe_stream_add_event_check(info, current_ev,
|
||||
end_buf, &iwe,
|
||||
IW_EV_UINT_LEN);
|
||||
if (IS_ERR(current_ev))
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
buf = kmalloc(31, GFP_ATOMIC);
|
||||
if (buf) {
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
iwe.cmd = IWEVCUSTOM;
|
||||
sprintf(buf, "tsf=%016llx", (unsigned long long)(ies->tsf));
|
||||
iwe.u.data.length = strlen(buf);
|
||||
current_ev = iwe_stream_add_point(info, current_ev, end_buf,
|
||||
&iwe, buf);
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
iwe.cmd = IWEVCUSTOM;
|
||||
sprintf(buf, " Last beacon: %ums ago",
|
||||
elapsed_jiffies_msecs(bss->ts));
|
||||
iwe.u.data.length = strlen(buf);
|
||||
current_ev = iwe_stream_add_point(info, current_ev,
|
||||
end_buf, &iwe, buf);
|
||||
kfree(buf);
|
||||
}
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
iwe.cmd = IWEVCUSTOM;
|
||||
sprintf(buf, "tsf=%016llx", (unsigned long long)(ies->tsf));
|
||||
iwe.u.data.length = strlen(buf);
|
||||
current_ev = iwe_stream_add_point_check(info, current_ev, end_buf,
|
||||
&iwe, buf);
|
||||
if (IS_ERR(current_ev))
|
||||
goto unlock;
|
||||
memset(&iwe, 0, sizeof(iwe));
|
||||
iwe.cmd = IWEVCUSTOM;
|
||||
sprintf(buf, " Last beacon: %ums ago",
|
||||
elapsed_jiffies_msecs(bss->ts));
|
||||
iwe.u.data.length = strlen(buf);
|
||||
current_ev = iwe_stream_add_point_check(info, current_ev,
|
||||
end_buf, &iwe, buf);
|
||||
if (IS_ERR(current_ev))
|
||||
goto unlock;
|
||||
|
||||
ieee80211_scan_add_ies(info, ies, ¤t_ev, end_buf);
|
||||
current_ev = ieee80211_scan_add_ies(info, ies, current_ev, end_buf);
|
||||
|
||||
unlock:
|
||||
rcu_read_unlock();
|
||||
|
||||
return current_ev;
|
||||
}
|
||||
|
||||
@@ -1501,19 +1623,27 @@ static int ieee80211_scan_results(struct cfg80211_registered_device *rdev,
|
||||
char *current_ev = buf;
|
||||
char *end_buf = buf + len;
|
||||
struct cfg80211_internal_bss *bss;
|
||||
int err = 0;
|
||||
|
||||
spin_lock_bh(&rdev->bss_lock);
|
||||
cfg80211_bss_expire(rdev);
|
||||
|
||||
list_for_each_entry(bss, &rdev->bss_list, list) {
|
||||
if (buf + len - current_ev <= IW_EV_ADDR_LEN) {
|
||||
spin_unlock_bh(&rdev->bss_lock);
|
||||
return -E2BIG;
|
||||
err = -E2BIG;
|
||||
break;
|
||||
}
|
||||
current_ev = ieee80211_bss(&rdev->wiphy, info, bss,
|
||||
current_ev, end_buf);
|
||||
if (IS_ERR(current_ev)) {
|
||||
err = PTR_ERR(current_ev);
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock_bh(&rdev->bss_lock);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
return current_ev - buf;
|
||||
}
|
||||
|
||||
@@ -1545,5 +1675,5 @@ int cfg80211_wext_giwscan(struct net_device *dev,
|
||||
|
||||
return res;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cfg80211_wext_giwscan);
|
||||
EXPORT_WEXT_HANDLER(cfg80211_wext_giwscan);
|
||||
#endif
|
||||
|
@@ -257,19 +257,15 @@ static struct cfg80211_bss *cfg80211_get_conn_bss(struct wireless_dev *wdev)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
|
||||
struct cfg80211_bss *bss;
|
||||
u16 capa = WLAN_CAPABILITY_ESS;
|
||||
|
||||
ASSERT_WDEV_LOCK(wdev);
|
||||
|
||||
if (wdev->conn->params.privacy)
|
||||
capa |= WLAN_CAPABILITY_PRIVACY;
|
||||
|
||||
bss = cfg80211_get_bss(wdev->wiphy, wdev->conn->params.channel,
|
||||
wdev->conn->params.bssid,
|
||||
wdev->conn->params.ssid,
|
||||
wdev->conn->params.ssid_len,
|
||||
WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_PRIVACY,
|
||||
capa);
|
||||
IEEE80211_BSS_TYPE_ESS,
|
||||
IEEE80211_PRIVACY(wdev->conn->params.privacy));
|
||||
if (!bss)
|
||||
return NULL;
|
||||
|
||||
@@ -637,8 +633,8 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
|
||||
WARN_ON_ONCE(!wiphy_to_rdev(wdev->wiphy)->ops->connect);
|
||||
bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
|
||||
wdev->ssid, wdev->ssid_len,
|
||||
WLAN_CAPABILITY_ESS,
|
||||
WLAN_CAPABILITY_ESS);
|
||||
IEEE80211_BSS_TYPE_ESS,
|
||||
IEEE80211_PRIVACY_ANY);
|
||||
if (bss)
|
||||
cfg80211_hold_bss(bss_from_pub(bss));
|
||||
}
|
||||
@@ -795,8 +791,8 @@ void cfg80211_roamed(struct net_device *dev,
|
||||
struct cfg80211_bss *bss;
|
||||
|
||||
bss = cfg80211_get_bss(wdev->wiphy, channel, bssid, wdev->ssid,
|
||||
wdev->ssid_len, WLAN_CAPABILITY_ESS,
|
||||
WLAN_CAPABILITY_ESS);
|
||||
wdev->ssid_len,
|
||||
IEEE80211_BSS_TYPE_ESS, IEEE80211_PRIVACY_ANY);
|
||||
if (WARN_ON(!bss))
|
||||
return;
|
||||
|
||||
|
@@ -628,6 +628,7 @@ DECLARE_EVENT_CLASS(station_add_change,
|
||||
__field(u8, plink_state)
|
||||
__field(u8, uapsd_queues)
|
||||
__array(u8, ht_capa, (int)sizeof(struct ieee80211_ht_cap))
|
||||
__array(char, vlan, IFNAMSIZ)
|
||||
),
|
||||
TP_fast_assign(
|
||||
WIPHY_ASSIGN;
|
||||
@@ -645,16 +646,19 @@ DECLARE_EVENT_CLASS(station_add_change,
|
||||
if (params->ht_capa)
|
||||
memcpy(__entry->ht_capa, params->ht_capa,
|
||||
sizeof(struct ieee80211_ht_cap));
|
||||
memset(__entry->vlan, 0, sizeof(__entry->vlan));
|
||||
if (params->vlan)
|
||||
memcpy(__entry->vlan, params->vlan->name, IFNAMSIZ);
|
||||
),
|
||||
TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", station mac: " MAC_PR_FMT
|
||||
", station flags mask: %u, station flags set: %u, "
|
||||
"station modify mask: %u, listen interval: %d, aid: %u, "
|
||||
"plink action: %u, plink state: %u, uapsd queues: %u",
|
||||
"plink action: %u, plink state: %u, uapsd queues: %u, vlan:%s",
|
||||
WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(sta_mac),
|
||||
__entry->sta_flags_mask, __entry->sta_flags_set,
|
||||
__entry->sta_modify_mask, __entry->listen_interval,
|
||||
__entry->aid, __entry->plink_action, __entry->plink_state,
|
||||
__entry->uapsd_queues)
|
||||
__entry->uapsd_queues, __entry->vlan)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(station_add_change, rdev_add_station,
|
||||
@@ -2637,28 +2641,30 @@ DEFINE_EVENT(wiphy_only_evt, cfg80211_sched_scan_stopped,
|
||||
TRACE_EVENT(cfg80211_get_bss,
|
||||
TP_PROTO(struct wiphy *wiphy, struct ieee80211_channel *channel,
|
||||
const u8 *bssid, const u8 *ssid, size_t ssid_len,
|
||||
u16 capa_mask, u16 capa_val),
|
||||
TP_ARGS(wiphy, channel, bssid, ssid, ssid_len, capa_mask, capa_val),
|
||||
enum ieee80211_bss_type bss_type,
|
||||
enum ieee80211_privacy privacy),
|
||||
TP_ARGS(wiphy, channel, bssid, ssid, ssid_len, bss_type, privacy),
|
||||
TP_STRUCT__entry(
|
||||
WIPHY_ENTRY
|
||||
CHAN_ENTRY
|
||||
MAC_ENTRY(bssid)
|
||||
__dynamic_array(u8, ssid, ssid_len)
|
||||
__field(u16, capa_mask)
|
||||
__field(u16, capa_val)
|
||||
__field(enum ieee80211_bss_type, bss_type)
|
||||
__field(enum ieee80211_privacy, privacy)
|
||||
),
|
||||
TP_fast_assign(
|
||||
WIPHY_ASSIGN;
|
||||
CHAN_ASSIGN(channel);
|
||||
MAC_ASSIGN(bssid, bssid);
|
||||
memcpy(__get_dynamic_array(ssid), ssid, ssid_len);
|
||||
__entry->capa_mask = capa_mask;
|
||||
__entry->capa_val = capa_val;
|
||||
__entry->bss_type = bss_type;
|
||||
__entry->privacy = privacy;
|
||||
),
|
||||
TP_printk(WIPHY_PR_FMT ", " CHAN_PR_FMT ", " MAC_PR_FMT ", buf: %#.2x, "
|
||||
"capa_mask: %d, capa_val: %u", WIPHY_PR_ARG, CHAN_PR_ARG,
|
||||
MAC_PR_ARG(bssid), ((u8 *)__get_dynamic_array(ssid))[0],
|
||||
__entry->capa_mask, __entry->capa_val)
|
||||
TP_printk(WIPHY_PR_FMT ", " CHAN_PR_FMT ", " MAC_PR_FMT
|
||||
", buf: %#.2x, bss_type: %d, privacy: %d",
|
||||
WIPHY_PR_ARG, CHAN_PR_ARG, MAC_PR_ARG(bssid),
|
||||
((u8 *)__get_dynamic_array(ssid))[0], __entry->bss_type,
|
||||
__entry->privacy)
|
||||
);
|
||||
|
||||
TRACE_EVENT(cfg80211_inform_bss_width_frame,
|
||||
|
@@ -1296,6 +1296,7 @@ bool ieee80211_operating_class_to_band(u8 operating_class,
|
||||
switch (operating_class) {
|
||||
case 112:
|
||||
case 115 ... 127:
|
||||
case 128 ... 130:
|
||||
*band = IEEE80211_BAND_5GHZ;
|
||||
return true;
|
||||
case 81:
|
||||
@@ -1313,6 +1314,135 @@ bool ieee80211_operating_class_to_band(u8 operating_class,
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_operating_class_to_band);
|
||||
|
||||
bool ieee80211_chandef_to_operating_class(struct cfg80211_chan_def *chandef,
|
||||
u8 *op_class)
|
||||
{
|
||||
u8 vht_opclass;
|
||||
u16 freq = chandef->center_freq1;
|
||||
|
||||
if (freq >= 2412 && freq <= 2472) {
|
||||
if (chandef->width > NL80211_CHAN_WIDTH_40)
|
||||
return false;
|
||||
|
||||
/* 2.407 GHz, channels 1..13 */
|
||||
if (chandef->width == NL80211_CHAN_WIDTH_40) {
|
||||
if (freq > chandef->chan->center_freq)
|
||||
*op_class = 83; /* HT40+ */
|
||||
else
|
||||
*op_class = 84; /* HT40- */
|
||||
} else {
|
||||
*op_class = 81;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (freq == 2484) {
|
||||
if (chandef->width > NL80211_CHAN_WIDTH_40)
|
||||
return false;
|
||||
|
||||
*op_class = 82; /* channel 14 */
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (chandef->width) {
|
||||
case NL80211_CHAN_WIDTH_80:
|
||||
vht_opclass = 128;
|
||||
break;
|
||||
case NL80211_CHAN_WIDTH_160:
|
||||
vht_opclass = 129;
|
||||
break;
|
||||
case NL80211_CHAN_WIDTH_80P80:
|
||||
vht_opclass = 130;
|
||||
break;
|
||||
case NL80211_CHAN_WIDTH_10:
|
||||
case NL80211_CHAN_WIDTH_5:
|
||||
return false; /* unsupported for now */
|
||||
default:
|
||||
vht_opclass = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* 5 GHz, channels 36..48 */
|
||||
if (freq >= 5180 && freq <= 5240) {
|
||||
if (vht_opclass) {
|
||||
*op_class = vht_opclass;
|
||||
} else if (chandef->width == NL80211_CHAN_WIDTH_40) {
|
||||
if (freq > chandef->chan->center_freq)
|
||||
*op_class = 116;
|
||||
else
|
||||
*op_class = 117;
|
||||
} else {
|
||||
*op_class = 115;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* 5 GHz, channels 52..64 */
|
||||
if (freq >= 5260 && freq <= 5320) {
|
||||
if (vht_opclass) {
|
||||
*op_class = vht_opclass;
|
||||
} else if (chandef->width == NL80211_CHAN_WIDTH_40) {
|
||||
if (freq > chandef->chan->center_freq)
|
||||
*op_class = 119;
|
||||
else
|
||||
*op_class = 120;
|
||||
} else {
|
||||
*op_class = 118;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* 5 GHz, channels 100..144 */
|
||||
if (freq >= 5500 && freq <= 5720) {
|
||||
if (vht_opclass) {
|
||||
*op_class = vht_opclass;
|
||||
} else if (chandef->width == NL80211_CHAN_WIDTH_40) {
|
||||
if (freq > chandef->chan->center_freq)
|
||||
*op_class = 122;
|
||||
else
|
||||
*op_class = 123;
|
||||
} else {
|
||||
*op_class = 121;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* 5 GHz, channels 149..169 */
|
||||
if (freq >= 5745 && freq <= 5845) {
|
||||
if (vht_opclass) {
|
||||
*op_class = vht_opclass;
|
||||
} else if (chandef->width == NL80211_CHAN_WIDTH_40) {
|
||||
if (freq > chandef->chan->center_freq)
|
||||
*op_class = 126;
|
||||
else
|
||||
*op_class = 127;
|
||||
} else if (freq <= 5805) {
|
||||
*op_class = 124;
|
||||
} else {
|
||||
*op_class = 125;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* 56.16 GHz, channel 1..4 */
|
||||
if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 4) {
|
||||
if (chandef->width >= NL80211_CHAN_WIDTH_40)
|
||||
return false;
|
||||
|
||||
*op_class = 180;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* not supported yet */
|
||||
return false;
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_chandef_to_operating_class);
|
||||
|
||||
int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
|
||||
u32 beacon_int)
|
||||
{
|
||||
|
@@ -63,7 +63,7 @@ int cfg80211_wext_giwname(struct net_device *dev,
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cfg80211_wext_giwname);
|
||||
EXPORT_WEXT_HANDLER(cfg80211_wext_giwname);
|
||||
|
||||
int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info,
|
||||
u32 *mode, char *extra)
|
||||
@@ -99,7 +99,7 @@ int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info,
|
||||
|
||||
return cfg80211_change_iface(rdev, dev, type, NULL, &vifparams);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cfg80211_wext_siwmode);
|
||||
EXPORT_WEXT_HANDLER(cfg80211_wext_siwmode);
|
||||
|
||||
int cfg80211_wext_giwmode(struct net_device *dev, struct iw_request_info *info,
|
||||
u32 *mode, char *extra)
|
||||
@@ -134,7 +134,7 @@ int cfg80211_wext_giwmode(struct net_device *dev, struct iw_request_info *info,
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cfg80211_wext_giwmode);
|
||||
EXPORT_WEXT_HANDLER(cfg80211_wext_giwmode);
|
||||
|
||||
|
||||
int cfg80211_wext_giwrange(struct net_device *dev,
|
||||
@@ -248,7 +248,7 @@ int cfg80211_wext_giwrange(struct net_device *dev,
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cfg80211_wext_giwrange);
|
||||
EXPORT_WEXT_HANDLER(cfg80211_wext_giwrange);
|
||||
|
||||
|
||||
/**
|
||||
@@ -303,7 +303,7 @@ int cfg80211_wext_siwrts(struct net_device *dev,
|
||||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cfg80211_wext_siwrts);
|
||||
EXPORT_WEXT_HANDLER(cfg80211_wext_siwrts);
|
||||
|
||||
int cfg80211_wext_giwrts(struct net_device *dev,
|
||||
struct iw_request_info *info,
|
||||
@@ -317,7 +317,7 @@ int cfg80211_wext_giwrts(struct net_device *dev,
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cfg80211_wext_giwrts);
|
||||
EXPORT_WEXT_HANDLER(cfg80211_wext_giwrts);
|
||||
|
||||
int cfg80211_wext_siwfrag(struct net_device *dev,
|
||||
struct iw_request_info *info,
|
||||
@@ -343,7 +343,7 @@ int cfg80211_wext_siwfrag(struct net_device *dev,
|
||||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cfg80211_wext_siwfrag);
|
||||
EXPORT_WEXT_HANDLER(cfg80211_wext_siwfrag);
|
||||
|
||||
int cfg80211_wext_giwfrag(struct net_device *dev,
|
||||
struct iw_request_info *info,
|
||||
@@ -357,7 +357,7 @@ int cfg80211_wext_giwfrag(struct net_device *dev,
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cfg80211_wext_giwfrag);
|
||||
EXPORT_WEXT_HANDLER(cfg80211_wext_giwfrag);
|
||||
|
||||
static int cfg80211_wext_siwretry(struct net_device *dev,
|
||||
struct iw_request_info *info,
|
||||
@@ -427,7 +427,7 @@ int cfg80211_wext_giwretry(struct net_device *dev,
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cfg80211_wext_giwretry);
|
||||
EXPORT_WEXT_HANDLER(cfg80211_wext_giwretry);
|
||||
|
||||
static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev, bool pairwise,
|
||||
|
@@ -4,6 +4,12 @@
|
||||
#include <net/iw_handler.h>
|
||||
#include <linux/wireless.h>
|
||||
|
||||
#ifdef CONFIG_CFG80211_WEXT_EXPORT
|
||||
#define EXPORT_WEXT_HANDLER(h) EXPORT_SYMBOL_GPL(h)
|
||||
#else
|
||||
#define EXPORT_WEXT_HANDLER(h)
|
||||
#endif /* CONFIG_CFG80211_WEXT_EXPORT */
|
||||
|
||||
int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
|
||||
struct iw_request_info *info,
|
||||
struct iw_freq *freq, char *extra);
|
||||
|
Reference in New Issue
Block a user