mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 10:41:38 -04:00
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
This commit is contained in:
commit
10be7eb36b
125 changed files with 3770 additions and 2018 deletions
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* This is the linux wireless configuration interface.
|
||||
*
|
||||
* Copyright 2006-2009 Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
|
||||
*/
|
||||
|
||||
#include <linux/if.h>
|
||||
|
|
@ -31,15 +31,10 @@ MODULE_AUTHOR("Johannes Berg");
|
|||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("wireless configuration support");
|
||||
|
||||
/* RCU might be appropriate here since we usually
|
||||
* only read the list, and that can happen quite
|
||||
* often because we need to do it for each command */
|
||||
/* RCU-protected (and cfg80211_mutex for writers) */
|
||||
LIST_HEAD(cfg80211_rdev_list);
|
||||
int cfg80211_rdev_list_generation;
|
||||
|
||||
/*
|
||||
* This is used to protect the cfg80211_rdev_list
|
||||
*/
|
||||
DEFINE_MUTEX(cfg80211_mutex);
|
||||
|
||||
/* for debugfs */
|
||||
|
|
@ -418,6 +413,18 @@ int wiphy_register(struct wiphy *wiphy)
|
|||
int i;
|
||||
u16 ifmodes = wiphy->interface_modes;
|
||||
|
||||
if (WARN_ON(wiphy->addresses && !wiphy->n_addresses))
|
||||
return -EINVAL;
|
||||
|
||||
if (WARN_ON(wiphy->addresses &&
|
||||
!is_zero_ether_addr(wiphy->perm_addr) &&
|
||||
memcmp(wiphy->perm_addr, wiphy->addresses[0].addr,
|
||||
ETH_ALEN)))
|
||||
return -EINVAL;
|
||||
|
||||
if (wiphy->addresses)
|
||||
memcpy(wiphy->perm_addr, wiphy->addresses[0].addr, ETH_ALEN);
|
||||
|
||||
/* sanity check ifmodes */
|
||||
WARN_ON(!ifmodes);
|
||||
ifmodes &= ((1 << __NL80211_IFTYPE_AFTER_LAST) - 1) & ~1;
|
||||
|
|
@ -477,7 +484,7 @@ int wiphy_register(struct wiphy *wiphy)
|
|||
/* set up regulatory info */
|
||||
wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE);
|
||||
|
||||
list_add(&rdev->list, &cfg80211_rdev_list);
|
||||
list_add_rcu(&rdev->list, &cfg80211_rdev_list);
|
||||
cfg80211_rdev_list_generation++;
|
||||
|
||||
mutex_unlock(&cfg80211_mutex);
|
||||
|
|
@ -554,7 +561,8 @@ void wiphy_unregister(struct wiphy *wiphy)
|
|||
* it impossible to find from userspace.
|
||||
*/
|
||||
debugfs_remove_recursive(rdev->wiphy.debugfsdir);
|
||||
list_del(&rdev->list);
|
||||
list_del_rcu(&rdev->list);
|
||||
synchronize_rcu();
|
||||
|
||||
/*
|
||||
* Try to grab rdev->mtx. If a command is still in progress,
|
||||
|
|
@ -670,7 +678,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
|
|||
INIT_LIST_HEAD(&wdev->event_list);
|
||||
spin_lock_init(&wdev->event_lock);
|
||||
mutex_lock(&rdev->devlist_mtx);
|
||||
list_add(&wdev->list, &rdev->netdev_list);
|
||||
list_add_rcu(&wdev->list, &rdev->netdev_list);
|
||||
rdev->devlist_generation++;
|
||||
/* can only change netns with wiphy */
|
||||
dev->features |= NETIF_F_NETNS_LOCAL;
|
||||
|
|
@ -782,13 +790,21 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
|
|||
*/
|
||||
if (!list_empty(&wdev->list)) {
|
||||
sysfs_remove_link(&dev->dev.kobj, "phy80211");
|
||||
list_del_init(&wdev->list);
|
||||
list_del_rcu(&wdev->list);
|
||||
rdev->devlist_generation++;
|
||||
#ifdef CONFIG_CFG80211_WEXT
|
||||
kfree(wdev->wext.keys);
|
||||
#endif
|
||||
}
|
||||
mutex_unlock(&rdev->devlist_mtx);
|
||||
/*
|
||||
* synchronise (so that we won't find this netdev
|
||||
* from other code any more) and then clear the list
|
||||
* head so that the above code can safely check for
|
||||
* !list_empty() to avoid double-cleanup.
|
||||
*/
|
||||
synchronize_rcu();
|
||||
INIT_LIST_HEAD(&wdev->list);
|
||||
break;
|
||||
case NETDEV_PRE_UP:
|
||||
if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype)))
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Wireless configuration interface internals.
|
||||
*
|
||||
* Copyright 2006-2009 Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
|
||||
*/
|
||||
#ifndef __NET_WIRELESS_CORE_H
|
||||
#define __NET_WIRELESS_CORE_H
|
||||
|
|
@ -48,6 +48,7 @@ struct cfg80211_registered_device {
|
|||
|
||||
/* associate netdev list */
|
||||
struct mutex devlist_mtx;
|
||||
/* protected by devlist_mtx or RCU */
|
||||
struct list_head netdev_list;
|
||||
int devlist_generation;
|
||||
int opencount; /* also protected by devlist_mtx */
|
||||
|
|
|
|||
|
|
@ -237,7 +237,6 @@ static int lib80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
|
|||
return -1;
|
||||
|
||||
pos = skb->data + hdr_len + CCMP_HDR_LEN;
|
||||
mic = skb_put(skb, CCMP_MIC_LEN);
|
||||
hdr = (struct ieee80211_hdr *)skb->data;
|
||||
ccmp_init_blocks(key->tfm, hdr, key->tx_pn, data_len, b0, b, s0);
|
||||
|
||||
|
|
@ -257,6 +256,7 @@ static int lib80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
|
|||
pos += len;
|
||||
}
|
||||
|
||||
mic = skb_put(skb, CCMP_MIC_LEN);
|
||||
for (i = 0; i < CCMP_MIC_LEN; i++)
|
||||
mic[i] = b[i] ^ s0[i];
|
||||
|
||||
|
|
|
|||
|
|
@ -36,6 +36,8 @@ MODULE_AUTHOR("Jouni Malinen");
|
|||
MODULE_DESCRIPTION("lib80211 crypt: TKIP");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#define TKIP_HDR_LEN 8
|
||||
|
||||
struct lib80211_tkip_data {
|
||||
#define TKIP_KEY_LEN 32
|
||||
u8 key[TKIP_KEY_LEN];
|
||||
|
|
@ -314,13 +316,12 @@ static int lib80211_tkip_hdr(struct sk_buff *skb, int hdr_len,
|
|||
u8 * rc4key, int keylen, void *priv)
|
||||
{
|
||||
struct lib80211_tkip_data *tkey = priv;
|
||||
int len;
|
||||
u8 *pos;
|
||||
struct ieee80211_hdr *hdr;
|
||||
|
||||
hdr = (struct ieee80211_hdr *)skb->data;
|
||||
|
||||
if (skb_headroom(skb) < 8 || skb->len < hdr_len)
|
||||
if (skb_headroom(skb) < TKIP_HDR_LEN || skb->len < hdr_len)
|
||||
return -1;
|
||||
|
||||
if (rc4key == NULL || keylen < 16)
|
||||
|
|
@ -333,9 +334,8 @@ static int lib80211_tkip_hdr(struct sk_buff *skb, int hdr_len,
|
|||
}
|
||||
tkip_mixing_phase2(rc4key, tkey->key, tkey->tx_ttak, tkey->tx_iv16);
|
||||
|
||||
len = skb->len - hdr_len;
|
||||
pos = skb_push(skb, 8);
|
||||
memmove(pos, pos + 8, hdr_len);
|
||||
pos = skb_push(skb, TKIP_HDR_LEN);
|
||||
memmove(pos, pos + TKIP_HDR_LEN, hdr_len);
|
||||
pos += hdr_len;
|
||||
|
||||
*pos++ = *rc4key;
|
||||
|
|
@ -353,7 +353,7 @@ static int lib80211_tkip_hdr(struct sk_buff *skb, int hdr_len,
|
|||
tkey->tx_iv32++;
|
||||
}
|
||||
|
||||
return 8;
|
||||
return TKIP_HDR_LEN;
|
||||
}
|
||||
|
||||
static int lib80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
|
||||
|
|
@ -384,9 +384,8 @@ static int lib80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
|
|||
if ((lib80211_tkip_hdr(skb, hdr_len, rc4key, 16, priv)) < 0)
|
||||
return -1;
|
||||
|
||||
icv = skb_put(skb, 4);
|
||||
|
||||
crc = ~crc32_le(~0, pos, len);
|
||||
icv = skb_put(skb, 4);
|
||||
icv[0] = crc;
|
||||
icv[1] = crc >> 8;
|
||||
icv[2] = crc >> 16;
|
||||
|
|
@ -434,7 +433,7 @@ static int lib80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (skb->len < hdr_len + 8 + 4)
|
||||
if (skb->len < hdr_len + TKIP_HDR_LEN + 4)
|
||||
return -1;
|
||||
|
||||
pos = skb->data + hdr_len;
|
||||
|
|
@ -462,7 +461,7 @@ static int lib80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
|
|||
}
|
||||
iv16 = (pos[0] << 8) | pos[2];
|
||||
iv32 = pos[4] | (pos[5] << 8) | (pos[6] << 16) | (pos[7] << 24);
|
||||
pos += 8;
|
||||
pos += TKIP_HDR_LEN;
|
||||
|
||||
if (tkip_replay_check(iv32, iv16, tkey->rx_iv32, tkey->rx_iv16)) {
|
||||
#ifdef CONFIG_LIB80211_DEBUG
|
||||
|
|
@ -523,8 +522,8 @@ static int lib80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
|
|||
tkey->rx_iv16_new = iv16;
|
||||
|
||||
/* Remove IV and ICV */
|
||||
memmove(skb->data + 8, skb->data, hdr_len);
|
||||
skb_pull(skb, 8);
|
||||
memmove(skb->data + TKIP_HDR_LEN, skb->data, hdr_len);
|
||||
skb_pull(skb, TKIP_HDR_LEN);
|
||||
skb_trim(skb, skb->len - 4);
|
||||
|
||||
return keyidx;
|
||||
|
|
|
|||
|
|
@ -3571,6 +3571,7 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
|
|||
{
|
||||
struct cfg80211_registered_device *rdev;
|
||||
struct net_device *dev;
|
||||
struct wireless_dev *wdev;
|
||||
struct cfg80211_crypto_settings crypto;
|
||||
struct ieee80211_channel *chan, *fixedchan;
|
||||
const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL;
|
||||
|
|
@ -3616,7 +3617,8 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
|
|||
}
|
||||
|
||||
mutex_lock(&rdev->devlist_mtx);
|
||||
fixedchan = rdev_fixed_channel(rdev, NULL);
|
||||
wdev = dev->ieee80211_ptr;
|
||||
fixedchan = rdev_fixed_channel(rdev, wdev);
|
||||
if (fixedchan && chan != fixedchan) {
|
||||
err = -EBUSY;
|
||||
mutex_unlock(&rdev->devlist_mtx);
|
||||
|
|
|
|||
|
|
@ -134,6 +134,7 @@ static const struct ieee80211_regdomain *cfg80211_world_regdom =
|
|||
&world_regdom;
|
||||
|
||||
static char *ieee80211_regdom = "00";
|
||||
static char user_alpha2[2];
|
||||
|
||||
module_param(ieee80211_regdom, charp, 0444);
|
||||
MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code");
|
||||
|
|
@ -252,6 +253,27 @@ static bool regdom_changes(const char *alpha2)
|
|||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* The NL80211_REGDOM_SET_BY_USER regdom alpha2 is cached, this lets
|
||||
* you know if a valid regulatory hint with NL80211_REGDOM_SET_BY_USER
|
||||
* has ever been issued.
|
||||
*/
|
||||
static bool is_user_regdom_saved(void)
|
||||
{
|
||||
if (user_alpha2[0] == '9' && user_alpha2[1] == '7')
|
||||
return false;
|
||||
|
||||
/* This would indicate a mistake on the design */
|
||||
if (WARN((!is_world_regdom(user_alpha2) &&
|
||||
!is_an_alpha2(user_alpha2)),
|
||||
"Unexpected user alpha2: %c%c\n",
|
||||
user_alpha2[0],
|
||||
user_alpha2[1]))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* country_ie_integrity_changes - tells us if the country IE has changed
|
||||
* @checksum: checksum of country IE of fields we are interested in
|
||||
|
|
@ -1646,7 +1668,7 @@ static int ignore_request(struct wiphy *wiphy,
|
|||
|
||||
switch (pending_request->initiator) {
|
||||
case NL80211_REGDOM_SET_BY_CORE:
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
case NL80211_REGDOM_SET_BY_COUNTRY_IE:
|
||||
|
||||
last_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx);
|
||||
|
|
@ -1785,6 +1807,11 @@ new_request:
|
|||
|
||||
pending_request = NULL;
|
||||
|
||||
if (last_request->initiator == NL80211_REGDOM_SET_BY_USER) {
|
||||
user_alpha2[0] = last_request->alpha2[0];
|
||||
user_alpha2[1] = last_request->alpha2[1];
|
||||
}
|
||||
|
||||
/* When r == REG_INTERSECT we do need to call CRDA */
|
||||
if (r < 0) {
|
||||
/*
|
||||
|
|
@ -1904,12 +1931,16 @@ static void queue_regulatory_request(struct regulatory_request *request)
|
|||
schedule_work(®_work);
|
||||
}
|
||||
|
||||
/* Core regulatory hint -- happens once during cfg80211_init() */
|
||||
/*
|
||||
* Core regulatory hint -- happens during cfg80211_init()
|
||||
* and when we restore regulatory settings.
|
||||
*/
|
||||
static int regulatory_hint_core(const char *alpha2)
|
||||
{
|
||||
struct regulatory_request *request;
|
||||
|
||||
BUG_ON(last_request);
|
||||
kfree(last_request);
|
||||
last_request = NULL;
|
||||
|
||||
request = kzalloc(sizeof(struct regulatory_request),
|
||||
GFP_KERNEL);
|
||||
|
|
@ -1920,14 +1951,12 @@ static int regulatory_hint_core(const char *alpha2)
|
|||
request->alpha2[1] = alpha2[1];
|
||||
request->initiator = NL80211_REGDOM_SET_BY_CORE;
|
||||
|
||||
queue_regulatory_request(request);
|
||||
|
||||
/*
|
||||
* This ensures last_request is populated once modules
|
||||
* come swinging in and calling regulatory hints and
|
||||
* wiphy_apply_custom_regulatory().
|
||||
*/
|
||||
flush_scheduled_work();
|
||||
reg_process_hint(request);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -2109,6 +2138,123 @@ out:
|
|||
mutex_unlock(®_mutex);
|
||||
}
|
||||
|
||||
static void restore_alpha2(char *alpha2, bool reset_user)
|
||||
{
|
||||
/* indicates there is no alpha2 to consider for restoration */
|
||||
alpha2[0] = '9';
|
||||
alpha2[1] = '7';
|
||||
|
||||
/* The user setting has precedence over the module parameter */
|
||||
if (is_user_regdom_saved()) {
|
||||
/* Unless we're asked to ignore it and reset it */
|
||||
if (reset_user) {
|
||||
REG_DBG_PRINT("cfg80211: Restoring regulatory settings "
|
||||
"including user preference\n");
|
||||
user_alpha2[0] = '9';
|
||||
user_alpha2[1] = '7';
|
||||
|
||||
/*
|
||||
* If we're ignoring user settings, we still need to
|
||||
* check the module parameter to ensure we put things
|
||||
* back as they were for a full restore.
|
||||
*/
|
||||
if (!is_world_regdom(ieee80211_regdom)) {
|
||||
REG_DBG_PRINT("cfg80211: Keeping preference on "
|
||||
"module parameter ieee80211_regdom: %c%c\n",
|
||||
ieee80211_regdom[0],
|
||||
ieee80211_regdom[1]);
|
||||
alpha2[0] = ieee80211_regdom[0];
|
||||
alpha2[1] = ieee80211_regdom[1];
|
||||
}
|
||||
} else {
|
||||
REG_DBG_PRINT("cfg80211: Restoring regulatory settings "
|
||||
"while preserving user preference for: %c%c\n",
|
||||
user_alpha2[0],
|
||||
user_alpha2[1]);
|
||||
alpha2[0] = user_alpha2[0];
|
||||
alpha2[1] = user_alpha2[1];
|
||||
}
|
||||
} else if (!is_world_regdom(ieee80211_regdom)) {
|
||||
REG_DBG_PRINT("cfg80211: Keeping preference on "
|
||||
"module parameter ieee80211_regdom: %c%c\n",
|
||||
ieee80211_regdom[0],
|
||||
ieee80211_regdom[1]);
|
||||
alpha2[0] = ieee80211_regdom[0];
|
||||
alpha2[1] = ieee80211_regdom[1];
|
||||
} else
|
||||
REG_DBG_PRINT("cfg80211: Restoring regulatory settings\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Restoring regulatory settings involves ingoring any
|
||||
* possibly stale country IE information and user regulatory
|
||||
* settings if so desired, this includes any beacon hints
|
||||
* learned as we could have traveled outside to another country
|
||||
* after disconnection. To restore regulatory settings we do
|
||||
* exactly what we did at bootup:
|
||||
*
|
||||
* - send a core regulatory hint
|
||||
* - send a user regulatory hint if applicable
|
||||
*
|
||||
* Device drivers that send a regulatory hint for a specific country
|
||||
* keep their own regulatory domain on wiphy->regd so that does does
|
||||
* not need to be remembered.
|
||||
*/
|
||||
static void restore_regulatory_settings(bool reset_user)
|
||||
{
|
||||
char alpha2[2];
|
||||
struct reg_beacon *reg_beacon, *btmp;
|
||||
|
||||
mutex_lock(&cfg80211_mutex);
|
||||
mutex_lock(®_mutex);
|
||||
|
||||
reset_regdomains();
|
||||
restore_alpha2(alpha2, reset_user);
|
||||
|
||||
/* Clear beacon hints */
|
||||
spin_lock_bh(®_pending_beacons_lock);
|
||||
if (!list_empty(®_pending_beacons)) {
|
||||
list_for_each_entry_safe(reg_beacon, btmp,
|
||||
®_pending_beacons, list) {
|
||||
list_del(®_beacon->list);
|
||||
kfree(reg_beacon);
|
||||
}
|
||||
}
|
||||
spin_unlock_bh(®_pending_beacons_lock);
|
||||
|
||||
if (!list_empty(®_beacon_list)) {
|
||||
list_for_each_entry_safe(reg_beacon, btmp,
|
||||
®_beacon_list, list) {
|
||||
list_del(®_beacon->list);
|
||||
kfree(reg_beacon);
|
||||
}
|
||||
}
|
||||
|
||||
/* First restore to the basic regulatory settings */
|
||||
cfg80211_regdomain = cfg80211_world_regdom;
|
||||
|
||||
mutex_unlock(®_mutex);
|
||||
mutex_unlock(&cfg80211_mutex);
|
||||
|
||||
regulatory_hint_core(cfg80211_regdomain->alpha2);
|
||||
|
||||
/*
|
||||
* This restores the ieee80211_regdom module parameter
|
||||
* preference or the last user requested regulatory
|
||||
* settings, user regulatory settings takes precedence.
|
||||
*/
|
||||
if (is_an_alpha2(alpha2))
|
||||
regulatory_hint_user(user_alpha2);
|
||||
}
|
||||
|
||||
|
||||
void regulatory_hint_disconnect(void)
|
||||
{
|
||||
REG_DBG_PRINT("cfg80211: All devices are disconnected, going to "
|
||||
"restore regulatory settings\n");
|
||||
restore_regulatory_settings(false);
|
||||
}
|
||||
|
||||
static bool freq_is_chan_12_13_14(u16 freq)
|
||||
{
|
||||
if (freq == ieee80211_channel_to_frequency(12) ||
|
||||
|
|
@ -2498,6 +2644,9 @@ int regulatory_init(void)
|
|||
|
||||
cfg80211_regdomain = cfg80211_world_regdom;
|
||||
|
||||
user_alpha2[0] = '9';
|
||||
user_alpha2[1] = '7';
|
||||
|
||||
/* We always try to get an update for the static regdomain */
|
||||
err = regulatory_hint_core(cfg80211_regdomain->alpha2);
|
||||
if (err) {
|
||||
|
|
|
|||
|
|
@ -63,4 +63,22 @@ void regulatory_hint_11d(struct wiphy *wiphy,
|
|||
u8 *country_ie,
|
||||
u8 country_ie_len);
|
||||
|
||||
/**
|
||||
* regulatory_hint_disconnect - informs all devices have been disconneted
|
||||
*
|
||||
* Regulotory rules can be enhanced further upon scanning and upon
|
||||
* connection to an AP. These rules become stale if we disconnect
|
||||
* and go to another country, whether or not we suspend and resume.
|
||||
* If we suspend, go to another country and resume we'll automatically
|
||||
* get disconnected shortly after resuming and things will be reset as well.
|
||||
* This routine is a helper to restore regulatory settings to how they were
|
||||
* prior to our first connect attempt. This includes ignoring country IE and
|
||||
* beacon regulatory hints. The ieee80211_regdom module parameter will always
|
||||
* be respected but if a user had set the regulatory domain that will take
|
||||
* precedence.
|
||||
*
|
||||
* Must be called from process context.
|
||||
*/
|
||||
void regulatory_hint_disconnect(void);
|
||||
|
||||
#endif /* __NET_WIRELESS_REG_H */
|
||||
|
|
|
|||
|
|
@ -143,9 +143,9 @@ void cfg80211_bss_expire(struct cfg80211_registered_device *dev)
|
|||
dev->bss_generation++;
|
||||
}
|
||||
|
||||
static u8 *find_ie(u8 num, u8 *ies, int len)
|
||||
const u8 *cfg80211_find_ie(u8 eid, const u8 *ies, int len)
|
||||
{
|
||||
while (len > 2 && ies[0] != num) {
|
||||
while (len > 2 && ies[0] != eid) {
|
||||
len -= ies[1] + 2;
|
||||
ies += ies[1] + 2;
|
||||
}
|
||||
|
|
@ -155,11 +155,12 @@ static u8 *find_ie(u8 num, u8 *ies, int len)
|
|||
return NULL;
|
||||
return ies;
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_find_ie);
|
||||
|
||||
static int cmp_ies(u8 num, u8 *ies1, size_t len1, u8 *ies2, size_t len2)
|
||||
{
|
||||
const u8 *ie1 = find_ie(num, ies1, len1);
|
||||
const u8 *ie2 = find_ie(num, ies2, len2);
|
||||
const u8 *ie1 = cfg80211_find_ie(num, ies1, len1);
|
||||
const u8 *ie2 = cfg80211_find_ie(num, ies2, len2);
|
||||
int r;
|
||||
|
||||
if (!ie1 && !ie2)
|
||||
|
|
@ -185,9 +186,9 @@ static bool is_bss(struct cfg80211_bss *a,
|
|||
if (!ssid)
|
||||
return true;
|
||||
|
||||
ssidie = find_ie(WLAN_EID_SSID,
|
||||
a->information_elements,
|
||||
a->len_information_elements);
|
||||
ssidie = cfg80211_find_ie(WLAN_EID_SSID,
|
||||
a->information_elements,
|
||||
a->len_information_elements);
|
||||
if (!ssidie)
|
||||
return false;
|
||||
if (ssidie[1] != ssid_len)
|
||||
|
|
@ -204,9 +205,9 @@ static bool is_mesh(struct cfg80211_bss *a,
|
|||
if (!is_zero_ether_addr(a->bssid))
|
||||
return false;
|
||||
|
||||
ie = find_ie(WLAN_EID_MESH_ID,
|
||||
a->information_elements,
|
||||
a->len_information_elements);
|
||||
ie = cfg80211_find_ie(WLAN_EID_MESH_ID,
|
||||
a->information_elements,
|
||||
a->len_information_elements);
|
||||
if (!ie)
|
||||
return false;
|
||||
if (ie[1] != meshidlen)
|
||||
|
|
@ -214,9 +215,9 @@ static bool is_mesh(struct cfg80211_bss *a,
|
|||
if (memcmp(ie + 2, meshid, meshidlen))
|
||||
return false;
|
||||
|
||||
ie = find_ie(WLAN_EID_MESH_CONFIG,
|
||||
a->information_elements,
|
||||
a->len_information_elements);
|
||||
ie = cfg80211_find_ie(WLAN_EID_MESH_CONFIG,
|
||||
a->information_elements,
|
||||
a->len_information_elements);
|
||||
if (!ie)
|
||||
return false;
|
||||
if (ie[1] != sizeof(struct ieee80211_meshconf_ie))
|
||||
|
|
@ -395,11 +396,12 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
|
|||
|
||||
if (is_zero_ether_addr(res->pub.bssid)) {
|
||||
/* must be mesh, verify */
|
||||
meshid = find_ie(WLAN_EID_MESH_ID, res->pub.information_elements,
|
||||
res->pub.len_information_elements);
|
||||
meshcfg = find_ie(WLAN_EID_MESH_CONFIG,
|
||||
res->pub.information_elements,
|
||||
res->pub.len_information_elements);
|
||||
meshid = cfg80211_find_ie(WLAN_EID_MESH_ID,
|
||||
res->pub.information_elements,
|
||||
res->pub.len_information_elements);
|
||||
meshcfg = cfg80211_find_ie(WLAN_EID_MESH_CONFIG,
|
||||
res->pub.information_elements,
|
||||
res->pub.len_information_elements);
|
||||
if (!meshid || !meshcfg ||
|
||||
meshcfg[1] != sizeof(struct ieee80211_meshconf_ie)) {
|
||||
/* bogus mesh */
|
||||
|
|
|
|||
|
|
@ -34,6 +34,44 @@ struct cfg80211_conn {
|
|||
bool auto_auth, prev_bssid_valid;
|
||||
};
|
||||
|
||||
bool cfg80211_is_all_idle(void)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev;
|
||||
struct wireless_dev *wdev;
|
||||
bool is_all_idle = true;
|
||||
|
||||
mutex_lock(&cfg80211_mutex);
|
||||
|
||||
/*
|
||||
* All devices must be idle as otherwise if you are actively
|
||||
* scanning some new beacon hints could be learned and would
|
||||
* count as new regulatory hints.
|
||||
*/
|
||||
list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
|
||||
cfg80211_lock_rdev(rdev);
|
||||
list_for_each_entry(wdev, &rdev->netdev_list, list) {
|
||||
wdev_lock(wdev);
|
||||
if (wdev->sme_state != CFG80211_SME_IDLE)
|
||||
is_all_idle = false;
|
||||
wdev_unlock(wdev);
|
||||
}
|
||||
cfg80211_unlock_rdev(rdev);
|
||||
}
|
||||
|
||||
mutex_unlock(&cfg80211_mutex);
|
||||
|
||||
return is_all_idle;
|
||||
}
|
||||
|
||||
static void disconnect_work(struct work_struct *work)
|
||||
{
|
||||
if (!cfg80211_is_all_idle())
|
||||
return;
|
||||
|
||||
regulatory_hint_disconnect();
|
||||
}
|
||||
|
||||
static DECLARE_WORK(cfg80211_disconnect_work, disconnect_work);
|
||||
|
||||
static int cfg80211_conn_scan(struct wireless_dev *wdev)
|
||||
{
|
||||
|
|
@ -658,6 +696,8 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
|
|||
wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
|
||||
wdev->wext.connect.ssid_len = 0;
|
||||
#endif
|
||||
|
||||
schedule_work(&cfg80211_disconnect_work);
|
||||
}
|
||||
|
||||
void cfg80211_disconnected(struct net_device *dev, u16 reason,
|
||||
|
|
|
|||
|
|
@ -33,10 +33,30 @@ static ssize_t name ## _show(struct device *dev, \
|
|||
|
||||
SHOW_FMT(index, "%d", wiphy_idx);
|
||||
SHOW_FMT(macaddress, "%pM", wiphy.perm_addr);
|
||||
SHOW_FMT(address_mask, "%pM", wiphy.addr_mask);
|
||||
|
||||
static ssize_t addresses_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct wiphy *wiphy = &dev_to_rdev(dev)->wiphy;
|
||||
char *start = buf;
|
||||
int i;
|
||||
|
||||
if (!wiphy->addresses)
|
||||
return sprintf(buf, "%pM\n", wiphy->perm_addr);
|
||||
|
||||
for (i = 0; i < wiphy->n_addresses; i++)
|
||||
buf += sprintf(buf, "%pM\n", &wiphy->addresses[i].addr);
|
||||
|
||||
return buf - start;
|
||||
}
|
||||
|
||||
static struct device_attribute ieee80211_dev_attrs[] = {
|
||||
__ATTR_RO(index),
|
||||
__ATTR_RO(macaddress),
|
||||
__ATTR_RO(address_mask),
|
||||
__ATTR_RO(addresses),
|
||||
{}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -227,8 +227,11 @@ unsigned int ieee80211_hdrlen(__le16 fc)
|
|||
if (ieee80211_is_data(fc)) {
|
||||
if (ieee80211_has_a4(fc))
|
||||
hdrlen = 30;
|
||||
if (ieee80211_is_data_qos(fc))
|
||||
if (ieee80211_is_data_qos(fc)) {
|
||||
hdrlen += IEEE80211_QOS_CTL_LEN;
|
||||
if (ieee80211_has_order(fc))
|
||||
hdrlen += IEEE80211_HT_CTL_LEN;
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1214,7 +1214,7 @@ int cfg80211_wext_siwrate(struct net_device *dev,
|
|||
|
||||
memset(&mask, 0, sizeof(mask));
|
||||
fixed = 0;
|
||||
maxrate = 0;
|
||||
maxrate = (u32)-1;
|
||||
|
||||
if (rate->value < 0) {
|
||||
/* nothing */
|
||||
|
|
|
|||
Loading…
Reference in a new issue