mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-29 03:01:39 -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
45ea4ea2af
124 changed files with 13213 additions and 1745 deletions
|
|
@ -10,6 +10,14 @@ config CFG80211_REG_DEBUG
|
|||
|
||||
If unsure, say N.
|
||||
|
||||
config CFG80211_DEBUGFS
|
||||
bool "cfg80211 DebugFS entries"
|
||||
depends on CFG80211 && DEBUG_FS
|
||||
---help---
|
||||
You can enable this if you want to debugfs entries for cfg80211.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config WIRELESS_OLD_REGULATORY
|
||||
bool "Old wireless static regulatory definitions"
|
||||
default n
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ obj-$(CONFIG_LIB80211_CRYPT_CCMP) += lib80211_crypt_ccmp.o
|
|||
obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o
|
||||
|
||||
cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o mlme.o ibss.o
|
||||
cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o
|
||||
cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o
|
||||
|
||||
ccflags-y += -D__CHECK_ENDIAN__
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
#include "nl80211.h"
|
||||
#include "core.h"
|
||||
#include "sysfs.h"
|
||||
#include "debugfs.h"
|
||||
|
||||
/* name for sysfs, %d is appended */
|
||||
#define PHY_NAME "phy"
|
||||
|
|
@ -228,7 +229,7 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
|
|||
|
||||
/* exported functions */
|
||||
|
||||
struct wiphy *wiphy_new(struct cfg80211_ops *ops, int sizeof_priv)
|
||||
struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
|
||||
{
|
||||
static int wiphy_counter;
|
||||
|
||||
|
|
@ -375,6 +376,8 @@ int wiphy_register(struct wiphy *wiphy)
|
|||
nl80211_send_reg_change_event(&request);
|
||||
}
|
||||
|
||||
cfg80211_debugfs_drv_add(drv);
|
||||
|
||||
res = 0;
|
||||
out_unlock:
|
||||
mutex_unlock(&cfg80211_mutex);
|
||||
|
|
@ -405,6 +408,8 @@ void wiphy_unregister(struct wiphy *wiphy)
|
|||
/* unlock again before freeing */
|
||||
mutex_unlock(&drv->mtx);
|
||||
|
||||
cfg80211_debugfs_drv_del(drv);
|
||||
|
||||
/* If this device got a regulatory hint tell core its
|
||||
* free to listen now to a new shiny device regulatory hint */
|
||||
reg_device_remove(wiphy);
|
||||
|
|
|
|||
|
|
@ -10,12 +10,13 @@
|
|||
#include <linux/netdevice.h>
|
||||
#include <linux/kref.h>
|
||||
#include <linux/rbtree.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <net/genetlink.h>
|
||||
#include <net/cfg80211.h>
|
||||
#include "reg.h"
|
||||
|
||||
struct cfg80211_registered_device {
|
||||
struct cfg80211_ops *ops;
|
||||
const struct cfg80211_ops *ops;
|
||||
struct list_head list;
|
||||
/* we hold this mutex during any call so that
|
||||
* we cannot do multiple calls at once, and also
|
||||
|
|
@ -50,6 +51,17 @@ struct cfg80211_registered_device {
|
|||
struct cfg80211_scan_request *scan_req; /* protected by RTNL */
|
||||
unsigned long suspend_at;
|
||||
|
||||
#ifdef CONFIG_CFG80211_DEBUGFS
|
||||
/* Debugfs entries */
|
||||
struct wiphy_debugfsdentries {
|
||||
struct dentry *rts_threshold;
|
||||
struct dentry *fragmentation_threshold;
|
||||
struct dentry *short_retry_limit;
|
||||
struct dentry *long_retry_limit;
|
||||
struct dentry *ht40allow_map;
|
||||
} debugfs;
|
||||
#endif
|
||||
|
||||
/* must be last because of the way we do wiphy_priv(),
|
||||
* and it should at least be aligned to NETDEV_ALIGN */
|
||||
struct wiphy wiphy __attribute__((__aligned__(NETDEV_ALIGN)));
|
||||
|
|
|
|||
131
net/wireless/debugfs.c
Normal file
131
net/wireless/debugfs.c
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
* cfg80211 debugfs
|
||||
*
|
||||
* Copyright 2009 Luis R. Rodriguez <lrodriguez@atheros.com>
|
||||
* Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include "core.h"
|
||||
#include "debugfs.h"
|
||||
|
||||
static int cfg80211_open_file_generic(struct inode *inode, struct file *file)
|
||||
{
|
||||
file->private_data = inode->i_private;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define DEBUGFS_READONLY_FILE(name, buflen, fmt, value...) \
|
||||
static ssize_t name## _read(struct file *file, char __user *userbuf, \
|
||||
size_t count, loff_t *ppos) \
|
||||
{ \
|
||||
struct wiphy *wiphy= file->private_data; \
|
||||
char buf[buflen]; \
|
||||
int res; \
|
||||
\
|
||||
res = scnprintf(buf, buflen, fmt "\n", ##value); \
|
||||
return simple_read_from_buffer(userbuf, count, ppos, buf, res); \
|
||||
} \
|
||||
\
|
||||
static const struct file_operations name## _ops = { \
|
||||
.read = name## _read, \
|
||||
.open = cfg80211_open_file_generic, \
|
||||
};
|
||||
|
||||
DEBUGFS_READONLY_FILE(rts_threshold, 20, "%d",
|
||||
wiphy->rts_threshold)
|
||||
DEBUGFS_READONLY_FILE(fragmentation_threshold, 20, "%d",
|
||||
wiphy->frag_threshold);
|
||||
DEBUGFS_READONLY_FILE(short_retry_limit, 20, "%d",
|
||||
wiphy->retry_short)
|
||||
DEBUGFS_READONLY_FILE(long_retry_limit, 20, "%d",
|
||||
wiphy->retry_long);
|
||||
|
||||
static int ht_print_chan(struct ieee80211_channel *chan,
|
||||
char *buf, int buf_size, int offset)
|
||||
{
|
||||
if (WARN_ON(offset > buf_size))
|
||||
return 0;
|
||||
|
||||
if (chan->flags & IEEE80211_CHAN_DISABLED)
|
||||
return snprintf(buf + offset,
|
||||
buf_size - offset,
|
||||
"%d Disabled\n",
|
||||
chan->center_freq);
|
||||
|
||||
return snprintf(buf + offset,
|
||||
buf_size - offset,
|
||||
"%d HT40 %c%c\n",
|
||||
chan->center_freq,
|
||||
(chan->flags & IEEE80211_CHAN_NO_HT40MINUS) ? ' ' : '-',
|
||||
(chan->flags & IEEE80211_CHAN_NO_HT40PLUS) ? ' ' : '+');
|
||||
}
|
||||
|
||||
static ssize_t ht40allow_map_read(struct file *file,
|
||||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct wiphy *wiphy = file->private_data;
|
||||
char *buf;
|
||||
unsigned int offset = 0, buf_size = PAGE_SIZE, i, r;
|
||||
enum ieee80211_band band;
|
||||
struct ieee80211_supported_band *sband;
|
||||
|
||||
buf = kzalloc(buf_size, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_lock(&cfg80211_mutex);
|
||||
|
||||
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
|
||||
sband = wiphy->bands[band];
|
||||
if (!sband)
|
||||
continue;
|
||||
for (i = 0; i < sband->n_channels; i++)
|
||||
offset += ht_print_chan(&sband->channels[i],
|
||||
buf, buf_size, offset);
|
||||
}
|
||||
|
||||
mutex_unlock(&cfg80211_mutex);
|
||||
|
||||
r = simple_read_from_buffer(user_buf, count, ppos, buf, offset);
|
||||
|
||||
kfree(buf);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static const struct file_operations ht40allow_map_ops = {
|
||||
.read = ht40allow_map_read,
|
||||
.open = cfg80211_open_file_generic,
|
||||
};
|
||||
|
||||
#define DEBUGFS_ADD(name) \
|
||||
drv->debugfs.name = debugfs_create_file(#name, S_IRUGO, phyd, \
|
||||
&drv->wiphy, &name## _ops);
|
||||
#define DEBUGFS_DEL(name) \
|
||||
debugfs_remove(drv->debugfs.name); \
|
||||
drv->debugfs.name = NULL;
|
||||
|
||||
void cfg80211_debugfs_drv_add(struct cfg80211_registered_device *drv)
|
||||
{
|
||||
struct dentry *phyd = drv->wiphy.debugfsdir;
|
||||
|
||||
DEBUGFS_ADD(rts_threshold);
|
||||
DEBUGFS_ADD(fragmentation_threshold);
|
||||
DEBUGFS_ADD(short_retry_limit);
|
||||
DEBUGFS_ADD(long_retry_limit);
|
||||
DEBUGFS_ADD(ht40allow_map);
|
||||
}
|
||||
|
||||
void cfg80211_debugfs_drv_del(struct cfg80211_registered_device *drv)
|
||||
{
|
||||
DEBUGFS_DEL(rts_threshold);
|
||||
DEBUGFS_DEL(fragmentation_threshold);
|
||||
DEBUGFS_DEL(short_retry_limit);
|
||||
DEBUGFS_DEL(long_retry_limit);
|
||||
DEBUGFS_DEL(ht40allow_map);
|
||||
}
|
||||
14
net/wireless/debugfs.h
Normal file
14
net/wireless/debugfs.h
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
#ifndef __CFG80211_DEBUGFS_H
|
||||
#define __CFG80211_DEBUGFS_H
|
||||
|
||||
#ifdef CONFIG_CFG80211_DEBUGFS
|
||||
void cfg80211_debugfs_drv_add(struct cfg80211_registered_device *drv);
|
||||
void cfg80211_debugfs_drv_del(struct cfg80211_registered_device *drv);
|
||||
#else
|
||||
static inline
|
||||
void cfg80211_debugfs_drv_add(struct cfg80211_registered_device *drv) {}
|
||||
static inline
|
||||
void cfg80211_debugfs_drv_del(struct cfg80211_registered_device *drv) {}
|
||||
#endif
|
||||
|
||||
#endif /* __CFG80211_DEBUGFS_H */
|
||||
|
|
@ -77,6 +77,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
|
|||
[NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 },
|
||||
[NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG },
|
||||
[NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 },
|
||||
|
||||
[NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 },
|
||||
|
|
@ -492,7 +493,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
|
|||
enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
|
||||
struct ieee80211_channel *chan;
|
||||
struct ieee80211_sta_ht_cap *ht_cap;
|
||||
u32 freq, sec_freq;
|
||||
u32 freq;
|
||||
|
||||
if (!rdev->ops->set_channel) {
|
||||
result = -EOPNOTSUPP;
|
||||
|
|
@ -518,33 +519,28 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
|
|||
if (!chan || chan->flags & IEEE80211_CHAN_DISABLED)
|
||||
goto bad_res;
|
||||
|
||||
if (channel_type == NL80211_CHAN_HT40MINUS)
|
||||
sec_freq = freq - 20;
|
||||
else if (channel_type == NL80211_CHAN_HT40PLUS)
|
||||
sec_freq = freq + 20;
|
||||
else
|
||||
sec_freq = 0;
|
||||
if (channel_type == NL80211_CHAN_HT40MINUS &&
|
||||
(chan->flags & IEEE80211_CHAN_NO_HT40MINUS))
|
||||
goto bad_res;
|
||||
else if (channel_type == NL80211_CHAN_HT40PLUS &&
|
||||
(chan->flags & IEEE80211_CHAN_NO_HT40PLUS))
|
||||
goto bad_res;
|
||||
|
||||
/*
|
||||
* At this point we know if that if HT40 was requested
|
||||
* we are allowed to use it and the extension channel
|
||||
* exists.
|
||||
*/
|
||||
|
||||
ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap;
|
||||
|
||||
/* no HT capabilities */
|
||||
if (channel_type != NL80211_CHAN_NO_HT &&
|
||||
!ht_cap->ht_supported)
|
||||
goto bad_res;
|
||||
|
||||
if (sec_freq) {
|
||||
struct ieee80211_channel *schan;
|
||||
|
||||
/* no 40 MHz capabilities */
|
||||
/* no HT capabilities or intolerant */
|
||||
if (channel_type != NL80211_CHAN_NO_HT) {
|
||||
if (!ht_cap->ht_supported)
|
||||
goto bad_res;
|
||||
if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) ||
|
||||
(ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT))
|
||||
goto bad_res;
|
||||
|
||||
schan = ieee80211_get_channel(&rdev->wiphy, sec_freq);
|
||||
|
||||
/* Secondary channel not allowed */
|
||||
if (!schan || schan->flags & IEEE80211_CHAN_DISABLED)
|
||||
goto bad_res;
|
||||
}
|
||||
|
||||
result = rdev->ops->set_channel(&rdev->wiphy, chan,
|
||||
|
|
@ -2571,18 +2567,24 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
|
|||
rem_reg_rules) {
|
||||
num_rules++;
|
||||
if (num_rules > NL80211_MAX_SUPP_REG_RULES)
|
||||
goto bad_reg;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!reg_is_valid_request(alpha2))
|
||||
return -EINVAL;
|
||||
mutex_lock(&cfg80211_mutex);
|
||||
|
||||
if (!reg_is_valid_request(alpha2)) {
|
||||
r = -EINVAL;
|
||||
goto bad_reg;
|
||||
}
|
||||
|
||||
size_of_regd = sizeof(struct ieee80211_regdomain) +
|
||||
(num_rules * sizeof(struct ieee80211_reg_rule));
|
||||
|
||||
rd = kzalloc(size_of_regd, GFP_KERNEL);
|
||||
if (!rd)
|
||||
return -ENOMEM;
|
||||
if (!rd) {
|
||||
r = -ENOMEM;
|
||||
goto bad_reg;
|
||||
}
|
||||
|
||||
rd->n_reg_rules = num_rules;
|
||||
rd->alpha2[0] = alpha2[0];
|
||||
|
|
@ -2599,20 +2601,24 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
|
|||
|
||||
rule_idx++;
|
||||
|
||||
if (rule_idx > NL80211_MAX_SUPP_REG_RULES)
|
||||
if (rule_idx > NL80211_MAX_SUPP_REG_RULES) {
|
||||
r = -EINVAL;
|
||||
goto bad_reg;
|
||||
}
|
||||
}
|
||||
|
||||
BUG_ON(rule_idx != num_rules);
|
||||
|
||||
mutex_lock(&cfg80211_mutex);
|
||||
r = set_regdom(rd);
|
||||
|
||||
mutex_unlock(&cfg80211_mutex);
|
||||
|
||||
return r;
|
||||
|
||||
bad_reg:
|
||||
mutex_unlock(&cfg80211_mutex);
|
||||
kfree(rd);
|
||||
return -EINVAL;
|
||||
return r;
|
||||
}
|
||||
|
||||
static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
|
||||
|
|
|
|||
|
|
@ -48,12 +48,6 @@ static struct regulatory_request *last_request;
|
|||
/* To trigger userspace events */
|
||||
static struct platform_device *reg_pdev;
|
||||
|
||||
/* Keep the ordering from large to small */
|
||||
static u32 supported_bandwidths[] = {
|
||||
MHZ_TO_KHZ(40),
|
||||
MHZ_TO_KHZ(20),
|
||||
};
|
||||
|
||||
/*
|
||||
* Central wireless core regulatory domains, we only need two,
|
||||
* the current one and a world regulatory domain in case we have no
|
||||
|
|
@ -388,6 +382,8 @@ static int call_crda(const char *alpha2)
|
|||
/* Used by nl80211 before kmalloc'ing our regulatory domain */
|
||||
bool reg_is_valid_request(const char *alpha2)
|
||||
{
|
||||
assert_cfg80211_lock();
|
||||
|
||||
if (!last_request)
|
||||
return false;
|
||||
|
||||
|
|
@ -435,19 +431,20 @@ static bool is_valid_rd(const struct ieee80211_regdomain *rd)
|
|||
return true;
|
||||
}
|
||||
|
||||
/* Returns value in KHz */
|
||||
static u32 freq_max_bandwidth(const struct ieee80211_freq_range *freq_range,
|
||||
u32 freq)
|
||||
static bool reg_does_bw_fit(const struct ieee80211_freq_range *freq_range,
|
||||
u32 center_freq_khz,
|
||||
u32 bw_khz)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 0; i < ARRAY_SIZE(supported_bandwidths); i++) {
|
||||
u32 start_freq_khz = freq - supported_bandwidths[i]/2;
|
||||
u32 end_freq_khz = freq + supported_bandwidths[i]/2;
|
||||
if (start_freq_khz >= freq_range->start_freq_khz &&
|
||||
end_freq_khz <= freq_range->end_freq_khz)
|
||||
return supported_bandwidths[i];
|
||||
}
|
||||
return 0;
|
||||
u32 start_freq_khz, end_freq_khz;
|
||||
|
||||
start_freq_khz = center_freq_khz - (bw_khz/2);
|
||||
end_freq_khz = center_freq_khz + (bw_khz/2);
|
||||
|
||||
if (start_freq_khz >= freq_range->start_freq_khz &&
|
||||
end_freq_khz <= freq_range->end_freq_khz)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -847,14 +844,17 @@ static u32 map_regdom_flags(u32 rd_flags)
|
|||
|
||||
static int freq_reg_info_regd(struct wiphy *wiphy,
|
||||
u32 center_freq,
|
||||
u32 *bandwidth,
|
||||
u32 desired_bw_khz,
|
||||
const struct ieee80211_reg_rule **reg_rule,
|
||||
const struct ieee80211_regdomain *custom_regd)
|
||||
{
|
||||
int i;
|
||||
bool band_rule_found = false;
|
||||
const struct ieee80211_regdomain *regd;
|
||||
u32 max_bandwidth = 0;
|
||||
bool bw_fits = false;
|
||||
|
||||
if (!desired_bw_khz)
|
||||
desired_bw_khz = MHZ_TO_KHZ(20);
|
||||
|
||||
regd = custom_regd ? custom_regd : cfg80211_regdomain;
|
||||
|
||||
|
|
@ -887,38 +887,54 @@ static int freq_reg_info_regd(struct wiphy *wiphy,
|
|||
if (!band_rule_found)
|
||||
band_rule_found = freq_in_rule_band(fr, center_freq);
|
||||
|
||||
max_bandwidth = freq_max_bandwidth(fr, center_freq);
|
||||
bw_fits = reg_does_bw_fit(fr,
|
||||
center_freq,
|
||||
desired_bw_khz);
|
||||
|
||||
if (max_bandwidth && *bandwidth <= max_bandwidth) {
|
||||
if (band_rule_found && bw_fits) {
|
||||
*reg_rule = rr;
|
||||
*bandwidth = max_bandwidth;
|
||||
break;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!band_rule_found)
|
||||
return -ERANGE;
|
||||
|
||||
return !max_bandwidth;
|
||||
return -EINVAL;
|
||||
}
|
||||
EXPORT_SYMBOL(freq_reg_info);
|
||||
|
||||
int freq_reg_info(struct wiphy *wiphy, u32 center_freq, u32 *bandwidth,
|
||||
const struct ieee80211_reg_rule **reg_rule)
|
||||
int freq_reg_info(struct wiphy *wiphy,
|
||||
u32 center_freq,
|
||||
u32 desired_bw_khz,
|
||||
const struct ieee80211_reg_rule **reg_rule)
|
||||
{
|
||||
assert_cfg80211_lock();
|
||||
return freq_reg_info_regd(wiphy, center_freq,
|
||||
bandwidth, reg_rule, NULL);
|
||||
return freq_reg_info_regd(wiphy,
|
||||
center_freq,
|
||||
desired_bw_khz,
|
||||
reg_rule,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Note that right now we assume the desired channel bandwidth
|
||||
* is always 20 MHz for each individual channel (HT40 uses 20 MHz
|
||||
* per channel, the primary and the extension channel). To support
|
||||
* smaller custom bandwidths such as 5 MHz or 10 MHz we'll need a
|
||||
* new ieee80211_channel.target_bw and re run the regulatory check
|
||||
* on the wiphy with the target_bw specified. Then we can simply use
|
||||
* that below for the desired_bw_khz below.
|
||||
*/
|
||||
static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band,
|
||||
unsigned int chan_idx)
|
||||
{
|
||||
int r;
|
||||
u32 flags;
|
||||
u32 max_bandwidth = 0;
|
||||
u32 flags, bw_flags = 0;
|
||||
u32 desired_bw_khz = MHZ_TO_KHZ(20);
|
||||
const struct ieee80211_reg_rule *reg_rule = NULL;
|
||||
const struct ieee80211_power_rule *power_rule = NULL;
|
||||
const struct ieee80211_freq_range *freq_range = NULL;
|
||||
struct ieee80211_supported_band *sband;
|
||||
struct ieee80211_channel *chan;
|
||||
struct wiphy *request_wiphy = NULL;
|
||||
|
|
@ -933,8 +949,10 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band,
|
|||
|
||||
flags = chan->orig_flags;
|
||||
|
||||
r = freq_reg_info(wiphy, MHZ_TO_KHZ(chan->center_freq),
|
||||
&max_bandwidth, ®_rule);
|
||||
r = freq_reg_info(wiphy,
|
||||
MHZ_TO_KHZ(chan->center_freq),
|
||||
desired_bw_khz,
|
||||
®_rule);
|
||||
|
||||
if (r) {
|
||||
/*
|
||||
|
|
@ -977,6 +995,10 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band,
|
|||
}
|
||||
|
||||
power_rule = ®_rule->power_rule;
|
||||
freq_range = ®_rule->freq_range;
|
||||
|
||||
if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(40))
|
||||
bw_flags = IEEE80211_CHAN_NO_HT40;
|
||||
|
||||
if (last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
|
||||
request_wiphy && request_wiphy == wiphy &&
|
||||
|
|
@ -987,19 +1009,19 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band,
|
|||
* settings
|
||||
*/
|
||||
chan->flags = chan->orig_flags =
|
||||
map_regdom_flags(reg_rule->flags);
|
||||
map_regdom_flags(reg_rule->flags) | bw_flags;
|
||||
chan->max_antenna_gain = chan->orig_mag =
|
||||
(int) MBI_TO_DBI(power_rule->max_antenna_gain);
|
||||
chan->max_bandwidth = KHZ_TO_MHZ(max_bandwidth);
|
||||
chan->max_bandwidth = KHZ_TO_MHZ(desired_bw_khz);
|
||||
chan->max_power = chan->orig_mpwr =
|
||||
(int) MBM_TO_DBM(power_rule->max_eirp);
|
||||
return;
|
||||
}
|
||||
|
||||
chan->flags = flags | map_regdom_flags(reg_rule->flags);
|
||||
chan->flags = flags | bw_flags | map_regdom_flags(reg_rule->flags);
|
||||
chan->max_antenna_gain = min(chan->orig_mag,
|
||||
(int) MBI_TO_DBI(power_rule->max_antenna_gain));
|
||||
chan->max_bandwidth = KHZ_TO_MHZ(max_bandwidth);
|
||||
chan->max_bandwidth = KHZ_TO_MHZ(desired_bw_khz);
|
||||
if (chan->orig_mpwr)
|
||||
chan->max_power = min(chan->orig_mpwr,
|
||||
(int) MBM_TO_DBM(power_rule->max_eirp));
|
||||
|
|
@ -1156,6 +1178,93 @@ static void reg_process_beacons(struct wiphy *wiphy)
|
|||
wiphy_update_beacon_reg(wiphy);
|
||||
}
|
||||
|
||||
static bool is_ht40_not_allowed(struct ieee80211_channel *chan)
|
||||
{
|
||||
if (!chan)
|
||||
return true;
|
||||
if (chan->flags & IEEE80211_CHAN_DISABLED)
|
||||
return true;
|
||||
/* This would happen when regulatory rules disallow HT40 completely */
|
||||
if (IEEE80211_CHAN_NO_HT40 == (chan->flags & (IEEE80211_CHAN_NO_HT40)))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static void reg_process_ht_flags_channel(struct wiphy *wiphy,
|
||||
enum ieee80211_band band,
|
||||
unsigned int chan_idx)
|
||||
{
|
||||
struct ieee80211_supported_band *sband;
|
||||
struct ieee80211_channel *channel;
|
||||
struct ieee80211_channel *channel_before = NULL, *channel_after = NULL;
|
||||
unsigned int i;
|
||||
|
||||
assert_cfg80211_lock();
|
||||
|
||||
sband = wiphy->bands[band];
|
||||
BUG_ON(chan_idx >= sband->n_channels);
|
||||
channel = &sband->channels[chan_idx];
|
||||
|
||||
if (is_ht40_not_allowed(channel)) {
|
||||
channel->flags |= IEEE80211_CHAN_NO_HT40;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* We need to ensure the extension channels exist to
|
||||
* be able to use HT40- or HT40+, this finds them (or not)
|
||||
*/
|
||||
for (i = 0; i < sband->n_channels; i++) {
|
||||
struct ieee80211_channel *c = &sband->channels[i];
|
||||
if (c->center_freq == (channel->center_freq - 20))
|
||||
channel_before = c;
|
||||
if (c->center_freq == (channel->center_freq + 20))
|
||||
channel_after = c;
|
||||
}
|
||||
|
||||
/*
|
||||
* Please note that this assumes target bandwidth is 20 MHz,
|
||||
* if that ever changes we also need to change the below logic
|
||||
* to include that as well.
|
||||
*/
|
||||
if (is_ht40_not_allowed(channel_before))
|
||||
channel->flags |= IEEE80211_CHAN_NO_HT40MINUS;
|
||||
else
|
||||
channel->flags &= ~IEEE80211_CHAN_NO_HT40MINUS;
|
||||
|
||||
if (is_ht40_not_allowed(channel_after))
|
||||
channel->flags |= IEEE80211_CHAN_NO_HT40PLUS;
|
||||
else
|
||||
channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS;
|
||||
}
|
||||
|
||||
static void reg_process_ht_flags_band(struct wiphy *wiphy,
|
||||
enum ieee80211_band band)
|
||||
{
|
||||
unsigned int i;
|
||||
struct ieee80211_supported_band *sband;
|
||||
|
||||
BUG_ON(!wiphy->bands[band]);
|
||||
sband = wiphy->bands[band];
|
||||
|
||||
for (i = 0; i < sband->n_channels; i++)
|
||||
reg_process_ht_flags_channel(wiphy, band, i);
|
||||
}
|
||||
|
||||
static void reg_process_ht_flags(struct wiphy *wiphy)
|
||||
{
|
||||
enum ieee80211_band band;
|
||||
|
||||
if (!wiphy)
|
||||
return;
|
||||
|
||||
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
|
||||
if (wiphy->bands[band])
|
||||
reg_process_ht_flags_band(wiphy, band);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void wiphy_update_regulatory(struct wiphy *wiphy,
|
||||
enum nl80211_reg_initiator initiator)
|
||||
{
|
||||
|
|
@ -1169,6 +1278,7 @@ void wiphy_update_regulatory(struct wiphy *wiphy,
|
|||
}
|
||||
out:
|
||||
reg_process_beacons(wiphy);
|
||||
reg_process_ht_flags(wiphy);
|
||||
if (wiphy->reg_notifier)
|
||||
wiphy->reg_notifier(wiphy, last_request);
|
||||
}
|
||||
|
|
@ -1179,9 +1289,11 @@ static void handle_channel_custom(struct wiphy *wiphy,
|
|||
const struct ieee80211_regdomain *regd)
|
||||
{
|
||||
int r;
|
||||
u32 max_bandwidth = 0;
|
||||
u32 desired_bw_khz = MHZ_TO_KHZ(20);
|
||||
u32 bw_flags = 0;
|
||||
const struct ieee80211_reg_rule *reg_rule = NULL;
|
||||
const struct ieee80211_power_rule *power_rule = NULL;
|
||||
const struct ieee80211_freq_range *freq_range = NULL;
|
||||
struct ieee80211_supported_band *sband;
|
||||
struct ieee80211_channel *chan;
|
||||
|
||||
|
|
@ -1191,8 +1303,11 @@ static void handle_channel_custom(struct wiphy *wiphy,
|
|||
BUG_ON(chan_idx >= sband->n_channels);
|
||||
chan = &sband->channels[chan_idx];
|
||||
|
||||
r = freq_reg_info_regd(wiphy, MHZ_TO_KHZ(chan->center_freq),
|
||||
&max_bandwidth, ®_rule, regd);
|
||||
r = freq_reg_info_regd(wiphy,
|
||||
MHZ_TO_KHZ(chan->center_freq),
|
||||
desired_bw_khz,
|
||||
®_rule,
|
||||
regd);
|
||||
|
||||
if (r) {
|
||||
chan->flags = IEEE80211_CHAN_DISABLED;
|
||||
|
|
@ -1200,10 +1315,14 @@ static void handle_channel_custom(struct wiphy *wiphy,
|
|||
}
|
||||
|
||||
power_rule = ®_rule->power_rule;
|
||||
freq_range = ®_rule->freq_range;
|
||||
|
||||
chan->flags |= map_regdom_flags(reg_rule->flags);
|
||||
if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(40))
|
||||
bw_flags = IEEE80211_CHAN_NO_HT40;
|
||||
|
||||
chan->flags |= map_regdom_flags(reg_rule->flags) | bw_flags;
|
||||
chan->max_antenna_gain = (int) MBI_TO_DBI(power_rule->max_antenna_gain);
|
||||
chan->max_bandwidth = KHZ_TO_MHZ(max_bandwidth);
|
||||
chan->max_bandwidth = KHZ_TO_MHZ(desired_bw_khz);
|
||||
chan->max_power = (int) MBM_TO_DBM(power_rule->max_eirp);
|
||||
}
|
||||
|
||||
|
|
@ -1225,13 +1344,22 @@ void wiphy_apply_custom_regulatory(struct wiphy *wiphy,
|
|||
const struct ieee80211_regdomain *regd)
|
||||
{
|
||||
enum ieee80211_band band;
|
||||
unsigned int bands_set = 0;
|
||||
|
||||
mutex_lock(&cfg80211_mutex);
|
||||
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
|
||||
if (wiphy->bands[band])
|
||||
handle_band_custom(wiphy, band, regd);
|
||||
if (!wiphy->bands[band])
|
||||
continue;
|
||||
handle_band_custom(wiphy, band, regd);
|
||||
bands_set++;
|
||||
}
|
||||
mutex_unlock(&cfg80211_mutex);
|
||||
|
||||
/*
|
||||
* no point in calling this if it won't have any effect
|
||||
* on your device's supportd bands.
|
||||
*/
|
||||
WARN_ON(!bands_set);
|
||||
}
|
||||
EXPORT_SYMBOL(wiphy_apply_custom_regulatory);
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,9 @@
|
|||
* Copyright 2007-2009 Johannes Berg <johannes@sipsolutions.net>
|
||||
*/
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <net/cfg80211.h>
|
||||
#include <net/ip.h>
|
||||
#include "core.h"
|
||||
|
||||
struct ieee80211_rate *
|
||||
|
|
@ -181,5 +183,323 @@ int cfg80211_validate_key_settings(struct key_params *params, int key_idx,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (params->seq) {
|
||||
switch (params->cipher) {
|
||||
case WLAN_CIPHER_SUITE_WEP40:
|
||||
case WLAN_CIPHER_SUITE_WEP104:
|
||||
/* These ciphers do not use key sequence */
|
||||
return -EINVAL;
|
||||
case WLAN_CIPHER_SUITE_TKIP:
|
||||
case WLAN_CIPHER_SUITE_CCMP:
|
||||
case WLAN_CIPHER_SUITE_AES_CMAC:
|
||||
if (params->seq_len != 6)
|
||||
return -EINVAL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */
|
||||
/* Ethernet-II snap header (RFC1042 for most EtherTypes) */
|
||||
const unsigned char rfc1042_header[] __aligned(2) =
|
||||
{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
|
||||
EXPORT_SYMBOL(rfc1042_header);
|
||||
|
||||
/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */
|
||||
const unsigned char bridge_tunnel_header[] __aligned(2) =
|
||||
{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
|
||||
EXPORT_SYMBOL(bridge_tunnel_header);
|
||||
|
||||
unsigned int ieee80211_hdrlen(__le16 fc)
|
||||
{
|
||||
unsigned int hdrlen = 24;
|
||||
|
||||
if (ieee80211_is_data(fc)) {
|
||||
if (ieee80211_has_a4(fc))
|
||||
hdrlen = 30;
|
||||
if (ieee80211_is_data_qos(fc))
|
||||
hdrlen += IEEE80211_QOS_CTL_LEN;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ieee80211_is_ctl(fc)) {
|
||||
/*
|
||||
* ACK and CTS are 10 bytes, all others 16. To see how
|
||||
* to get this condition consider
|
||||
* subtype mask: 0b0000000011110000 (0x00F0)
|
||||
* ACK subtype: 0b0000000011010000 (0x00D0)
|
||||
* CTS subtype: 0b0000000011000000 (0x00C0)
|
||||
* bits that matter: ^^^ (0x00E0)
|
||||
* value of those: 0b0000000011000000 (0x00C0)
|
||||
*/
|
||||
if ((fc & cpu_to_le16(0x00E0)) == cpu_to_le16(0x00C0))
|
||||
hdrlen = 10;
|
||||
else
|
||||
hdrlen = 16;
|
||||
}
|
||||
out:
|
||||
return hdrlen;
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_hdrlen);
|
||||
|
||||
unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb)
|
||||
{
|
||||
const struct ieee80211_hdr *hdr =
|
||||
(const struct ieee80211_hdr *)skb->data;
|
||||
unsigned int hdrlen;
|
||||
|
||||
if (unlikely(skb->len < 10))
|
||||
return 0;
|
||||
hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
||||
if (unlikely(hdrlen > skb->len))
|
||||
return 0;
|
||||
return hdrlen;
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb);
|
||||
|
||||
int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr)
|
||||
{
|
||||
int ae = meshhdr->flags & MESH_FLAGS_AE;
|
||||
/* 7.1.3.5a.2 */
|
||||
switch (ae) {
|
||||
case 0:
|
||||
return 6;
|
||||
case 1:
|
||||
return 12;
|
||||
case 2:
|
||||
return 18;
|
||||
case 3:
|
||||
return 24;
|
||||
default:
|
||||
return 6;
|
||||
}
|
||||
}
|
||||
|
||||
int ieee80211_data_to_8023(struct sk_buff *skb, u8 *addr,
|
||||
enum nl80211_iftype iftype)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
||||
u16 hdrlen, ethertype;
|
||||
u8 *payload;
|
||||
u8 dst[ETH_ALEN];
|
||||
u8 src[ETH_ALEN] __aligned(2);
|
||||
|
||||
if (unlikely(!ieee80211_is_data_present(hdr->frame_control)))
|
||||
return -1;
|
||||
|
||||
hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
||||
|
||||
/* convert IEEE 802.11 header + possible LLC headers into Ethernet
|
||||
* header
|
||||
* IEEE 802.11 address fields:
|
||||
* ToDS FromDS Addr1 Addr2 Addr3 Addr4
|
||||
* 0 0 DA SA BSSID n/a
|
||||
* 0 1 DA BSSID SA n/a
|
||||
* 1 0 BSSID SA DA n/a
|
||||
* 1 1 RA TA DA SA
|
||||
*/
|
||||
memcpy(dst, ieee80211_get_DA(hdr), ETH_ALEN);
|
||||
memcpy(src, ieee80211_get_SA(hdr), ETH_ALEN);
|
||||
|
||||
switch (hdr->frame_control &
|
||||
cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) {
|
||||
case cpu_to_le16(IEEE80211_FCTL_TODS):
|
||||
if (unlikely(iftype != NL80211_IFTYPE_AP &&
|
||||
iftype != NL80211_IFTYPE_AP_VLAN))
|
||||
return -1;
|
||||
break;
|
||||
case cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS):
|
||||
if (unlikely(iftype != NL80211_IFTYPE_WDS &&
|
||||
iftype != NL80211_IFTYPE_MESH_POINT))
|
||||
return -1;
|
||||
if (iftype == NL80211_IFTYPE_MESH_POINT) {
|
||||
struct ieee80211s_hdr *meshdr =
|
||||
(struct ieee80211s_hdr *) (skb->data + hdrlen);
|
||||
hdrlen += ieee80211_get_mesh_hdrlen(meshdr);
|
||||
if (meshdr->flags & MESH_FLAGS_AE_A5_A6) {
|
||||
memcpy(dst, meshdr->eaddr1, ETH_ALEN);
|
||||
memcpy(src, meshdr->eaddr2, ETH_ALEN);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case cpu_to_le16(IEEE80211_FCTL_FROMDS):
|
||||
if (iftype != NL80211_IFTYPE_STATION ||
|
||||
(is_multicast_ether_addr(dst) &&
|
||||
!compare_ether_addr(src, addr)))
|
||||
return -1;
|
||||
break;
|
||||
case cpu_to_le16(0):
|
||||
if (iftype != NL80211_IFTYPE_ADHOC)
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (unlikely(skb->len - hdrlen < 8))
|
||||
return -1;
|
||||
|
||||
payload = skb->data + hdrlen;
|
||||
ethertype = (payload[6] << 8) | payload[7];
|
||||
|
||||
if (likely((compare_ether_addr(payload, rfc1042_header) == 0 &&
|
||||
ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
|
||||
compare_ether_addr(payload, bridge_tunnel_header) == 0)) {
|
||||
/* remove RFC1042 or Bridge-Tunnel encapsulation and
|
||||
* replace EtherType */
|
||||
skb_pull(skb, hdrlen + 6);
|
||||
memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN);
|
||||
memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN);
|
||||
} else {
|
||||
struct ethhdr *ehdr;
|
||||
__be16 len;
|
||||
|
||||
skb_pull(skb, hdrlen);
|
||||
len = htons(skb->len);
|
||||
ehdr = (struct ethhdr *) skb_push(skb, sizeof(struct ethhdr));
|
||||
memcpy(ehdr->h_dest, dst, ETH_ALEN);
|
||||
memcpy(ehdr->h_source, src, ETH_ALEN);
|
||||
ehdr->h_proto = len;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_data_to_8023);
|
||||
|
||||
int ieee80211_data_from_8023(struct sk_buff *skb, u8 *addr,
|
||||
enum nl80211_iftype iftype, u8 *bssid, bool qos)
|
||||
{
|
||||
struct ieee80211_hdr hdr;
|
||||
u16 hdrlen, ethertype;
|
||||
__le16 fc;
|
||||
const u8 *encaps_data;
|
||||
int encaps_len, skip_header_bytes;
|
||||
int nh_pos, h_pos;
|
||||
int head_need;
|
||||
|
||||
if (unlikely(skb->len < ETH_HLEN))
|
||||
return -EINVAL;
|
||||
|
||||
nh_pos = skb_network_header(skb) - skb->data;
|
||||
h_pos = skb_transport_header(skb) - skb->data;
|
||||
|
||||
/* convert Ethernet header to proper 802.11 header (based on
|
||||
* operation mode) */
|
||||
ethertype = (skb->data[12] << 8) | skb->data[13];
|
||||
fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA);
|
||||
|
||||
switch (iftype) {
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_AP_VLAN:
|
||||
fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
|
||||
/* DA BSSID SA */
|
||||
memcpy(hdr.addr1, skb->data, ETH_ALEN);
|
||||
memcpy(hdr.addr2, addr, ETH_ALEN);
|
||||
memcpy(hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN);
|
||||
hdrlen = 24;
|
||||
break;
|
||||
case NL80211_IFTYPE_STATION:
|
||||
fc |= cpu_to_le16(IEEE80211_FCTL_TODS);
|
||||
/* BSSID SA DA */
|
||||
memcpy(hdr.addr1, bssid, ETH_ALEN);
|
||||
memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
|
||||
memcpy(hdr.addr3, skb->data, ETH_ALEN);
|
||||
hdrlen = 24;
|
||||
break;
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
/* DA SA BSSID */
|
||||
memcpy(hdr.addr1, skb->data, ETH_ALEN);
|
||||
memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
|
||||
memcpy(hdr.addr3, bssid, ETH_ALEN);
|
||||
hdrlen = 24;
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (qos) {
|
||||
fc |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
|
||||
hdrlen += 2;
|
||||
}
|
||||
|
||||
hdr.frame_control = fc;
|
||||
hdr.duration_id = 0;
|
||||
hdr.seq_ctrl = 0;
|
||||
|
||||
skip_header_bytes = ETH_HLEN;
|
||||
if (ethertype == ETH_P_AARP || ethertype == ETH_P_IPX) {
|
||||
encaps_data = bridge_tunnel_header;
|
||||
encaps_len = sizeof(bridge_tunnel_header);
|
||||
skip_header_bytes -= 2;
|
||||
} else if (ethertype > 0x600) {
|
||||
encaps_data = rfc1042_header;
|
||||
encaps_len = sizeof(rfc1042_header);
|
||||
skip_header_bytes -= 2;
|
||||
} else {
|
||||
encaps_data = NULL;
|
||||
encaps_len = 0;
|
||||
}
|
||||
|
||||
skb_pull(skb, skip_header_bytes);
|
||||
nh_pos -= skip_header_bytes;
|
||||
h_pos -= skip_header_bytes;
|
||||
|
||||
head_need = hdrlen + encaps_len - skb_headroom(skb);
|
||||
|
||||
if (head_need > 0 || skb_cloned(skb)) {
|
||||
head_need = max(head_need, 0);
|
||||
if (head_need)
|
||||
skb_orphan(skb);
|
||||
|
||||
if (pskb_expand_head(skb, head_need, 0, GFP_ATOMIC)) {
|
||||
printk(KERN_ERR "failed to reallocate Tx buffer\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
skb->truesize += head_need;
|
||||
}
|
||||
|
||||
if (encaps_data) {
|
||||
memcpy(skb_push(skb, encaps_len), encaps_data, encaps_len);
|
||||
nh_pos += encaps_len;
|
||||
h_pos += encaps_len;
|
||||
}
|
||||
|
||||
memcpy(skb_push(skb, hdrlen), &hdr, hdrlen);
|
||||
|
||||
nh_pos += hdrlen;
|
||||
h_pos += hdrlen;
|
||||
|
||||
/* Update skb pointers to various headers since this modified frame
|
||||
* is going to go through Linux networking code that may potentially
|
||||
* need things like pointer to IP header. */
|
||||
skb_set_mac_header(skb, 0);
|
||||
skb_set_network_header(skb, nh_pos);
|
||||
skb_set_transport_header(skb, h_pos);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_data_from_8023);
|
||||
|
||||
/* Given a data frame determine the 802.1p/1d tag to use. */
|
||||
unsigned int cfg80211_classify8021d(struct sk_buff *skb)
|
||||
{
|
||||
unsigned int dscp;
|
||||
|
||||
/* skb->priority values from 256->263 are magic values to
|
||||
* directly indicate a specific 802.1d priority. This is used
|
||||
* to allow 802.1d priority to be passed directly in from VLAN
|
||||
* tags, etc.
|
||||
*/
|
||||
if (skb->priority >= 256 && skb->priority <= 263)
|
||||
return skb->priority - 256;
|
||||
|
||||
switch (skb->protocol) {
|
||||
case htons(ETH_P_IP):
|
||||
dscp = ip_hdr(skb)->tos & 0xfc;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return dscp >> 5;
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_classify8021d);
|
||||
|
|
|
|||
|
|
@ -504,6 +504,13 @@ static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
|
|||
else if (idx == wdev->wext.default_mgmt_key)
|
||||
wdev->wext.default_mgmt_key = -1;
|
||||
}
|
||||
/*
|
||||
* Applications using wireless extensions expect to be
|
||||
* able to delete keys that don't exist, so allow that.
|
||||
*/
|
||||
if (err == -ENOENT)
|
||||
return 0;
|
||||
|
||||
return err;
|
||||
} else {
|
||||
if (addr)
|
||||
|
|
|
|||
|
|
@ -636,8 +636,10 @@ static void wireless_seq_printf_stats(struct seq_file *seq,
|
|||
/*
|
||||
* Print info for /proc/net/wireless (print all entries)
|
||||
*/
|
||||
static int wireless_seq_show(struct seq_file *seq, void *v)
|
||||
static int wireless_dev_seq_show(struct seq_file *seq, void *v)
|
||||
{
|
||||
might_sleep();
|
||||
|
||||
if (v == SEQ_START_TOKEN)
|
||||
seq_printf(seq, "Inter-| sta-| Quality | Discarded "
|
||||
"packets | Missed | WE\n"
|
||||
|
|
@ -651,21 +653,41 @@ static int wireless_seq_show(struct seq_file *seq, void *v)
|
|||
|
||||
static void *wireless_dev_seq_start(struct seq_file *seq, loff_t *pos)
|
||||
{
|
||||
struct net *net = seq_file_net(seq);
|
||||
loff_t off;
|
||||
struct net_device *dev;
|
||||
|
||||
rtnl_lock();
|
||||
return dev_seq_start(seq, pos);
|
||||
if (!*pos)
|
||||
return SEQ_START_TOKEN;
|
||||
|
||||
off = 1;
|
||||
for_each_netdev(net, dev)
|
||||
if (off++ == *pos)
|
||||
return dev;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *wireless_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
|
||||
{
|
||||
struct net *net = seq_file_net(seq);
|
||||
|
||||
++*pos;
|
||||
|
||||
return v == SEQ_START_TOKEN ?
|
||||
first_net_device(net) : next_net_device(v);
|
||||
}
|
||||
|
||||
static void wireless_dev_seq_stop(struct seq_file *seq, void *v)
|
||||
{
|
||||
dev_seq_stop(seq, v);
|
||||
rtnl_unlock();
|
||||
}
|
||||
|
||||
static const struct seq_operations wireless_seq_ops = {
|
||||
.start = wireless_dev_seq_start,
|
||||
.next = dev_seq_next,
|
||||
.next = wireless_dev_seq_next,
|
||||
.stop = wireless_dev_seq_stop,
|
||||
.show = wireless_seq_show,
|
||||
.show = wireless_dev_seq_show,
|
||||
};
|
||||
|
||||
static int seq_open_wireless(struct inode *inode, struct file *file)
|
||||
|
|
|
|||
Loading…
Reference in a new issue