kernel-hacking-2024-linux-s.../net/wireless/wext-compat.c
Johannes Berg ba44cb7226 cfg80211: mark all WEXT handlers _GPL
The fact that these are exported is a technical detail
of the conversion period -- we don't want anybody to
start relying on these. Ultimately we want things to
use cfg80211 only, and once everything that is in wext
is converted to cfg80211 drivers will not need to touch
wext _at all_.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-04-22 16:57:18 -04:00

467 lines
11 KiB
C

/*
* cfg80211 - wext compat code
*
* This is temporary code until all wireless functionality is migrated
* into cfg80211, when that happens all the exports here go away and
* we directly assign the wireless handlers of wireless interfaces.
*
* Copyright 2008 Johannes Berg <johannes@sipsolutions.net>
*/
#include <linux/wireless.h>
#include <linux/nl80211.h>
#include <linux/if_arp.h>
#include <net/iw_handler.h>
#include <net/cfg80211.h>
#include "core.h"
int cfg80211_wext_giwname(struct net_device *dev,
struct iw_request_info *info,
char *name, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct ieee80211_supported_band *sband;
bool is_ht = false, is_a = false, is_b = false, is_g = false;
if (!wdev)
return -EOPNOTSUPP;
sband = wdev->wiphy->bands[IEEE80211_BAND_5GHZ];
if (sband) {
is_a = true;
is_ht |= sband->ht_cap.ht_supported;
}
sband = wdev->wiphy->bands[IEEE80211_BAND_2GHZ];
if (sband) {
int i;
/* Check for mandatory rates */
for (i = 0; i < sband->n_bitrates; i++) {
if (sband->bitrates[i].bitrate == 10)
is_b = true;
if (sband->bitrates[i].bitrate == 60)
is_g = true;
}
is_ht |= sband->ht_cap.ht_supported;
}
strcpy(name, "IEEE 802.11");
if (is_a)
strcat(name, "a");
if (is_b)
strcat(name, "b");
if (is_g)
strcat(name, "g");
if (is_ht)
strcat(name, "n");
return 0;
}
EXPORT_SYMBOL_GPL(cfg80211_wext_giwname);
int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info,
u32 *mode, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev;
struct vif_params vifparams;
enum nl80211_iftype type;
int ret;
if (!wdev)
return -EOPNOTSUPP;
rdev = wiphy_to_dev(wdev->wiphy);
if (!rdev->ops->change_virtual_intf)
return -EOPNOTSUPP;
/* don't support changing VLANs, you just re-create them */
if (wdev->iftype == NL80211_IFTYPE_AP_VLAN)
return -EOPNOTSUPP;
switch (*mode) {
case IW_MODE_INFRA:
type = NL80211_IFTYPE_STATION;
break;
case IW_MODE_ADHOC:
type = NL80211_IFTYPE_ADHOC;
break;
case IW_MODE_REPEAT:
type = NL80211_IFTYPE_WDS;
break;
case IW_MODE_MONITOR:
type = NL80211_IFTYPE_MONITOR;
break;
default:
return -EINVAL;
}
if (type == wdev->iftype)
return 0;
memset(&vifparams, 0, sizeof(vifparams));
ret = rdev->ops->change_virtual_intf(wdev->wiphy, dev->ifindex, type,
NULL, &vifparams);
WARN_ON(!ret && wdev->iftype != type);
return ret;
}
EXPORT_SYMBOL_GPL(cfg80211_wext_siwmode);
int cfg80211_wext_giwmode(struct net_device *dev, struct iw_request_info *info,
u32 *mode, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
if (!wdev)
return -EOPNOTSUPP;
switch (wdev->iftype) {
case NL80211_IFTYPE_AP:
*mode = IW_MODE_MASTER;
break;
case NL80211_IFTYPE_STATION:
*mode = IW_MODE_INFRA;
break;
case NL80211_IFTYPE_ADHOC:
*mode = IW_MODE_ADHOC;
break;
case NL80211_IFTYPE_MONITOR:
*mode = IW_MODE_MONITOR;
break;
case NL80211_IFTYPE_WDS:
*mode = IW_MODE_REPEAT;
break;
case NL80211_IFTYPE_AP_VLAN:
*mode = IW_MODE_SECOND; /* FIXME */
break;
default:
*mode = IW_MODE_AUTO;
break;
}
return 0;
}
EXPORT_SYMBOL_GPL(cfg80211_wext_giwmode);
int cfg80211_wext_giwrange(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *data, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct iw_range *range = (struct iw_range *) extra;
enum ieee80211_band band;
int c = 0;
if (!wdev)
return -EOPNOTSUPP;
data->length = sizeof(struct iw_range);
memset(range, 0, sizeof(struct iw_range));
range->we_version_compiled = WIRELESS_EXT;
range->we_version_source = 21;
range->retry_capa = IW_RETRY_LIMIT;
range->retry_flags = IW_RETRY_LIMIT;
range->min_retry = 0;
range->max_retry = 255;
range->min_rts = 0;
range->max_rts = 2347;
range->min_frag = 256;
range->max_frag = 2346;
range->encoding_size[0] = 5;
range->encoding_size[1] = 13;
range->num_encoding_sizes = 2;
range->max_encoding_tokens = 4;
range->max_qual.updated = IW_QUAL_NOISE_INVALID;
switch (wdev->wiphy->signal_type) {
case CFG80211_SIGNAL_TYPE_NONE:
break;
case CFG80211_SIGNAL_TYPE_MBM:
range->max_qual.level = -110;
range->max_qual.qual = 70;
range->avg_qual.qual = 35;
range->max_qual.updated |= IW_QUAL_DBM;
range->max_qual.updated |= IW_QUAL_QUAL_UPDATED;
range->max_qual.updated |= IW_QUAL_LEVEL_UPDATED;
break;
case CFG80211_SIGNAL_TYPE_UNSPEC:
range->max_qual.level = 100;
range->max_qual.qual = 100;
range->avg_qual.qual = 50;
range->max_qual.updated |= IW_QUAL_QUAL_UPDATED;
range->max_qual.updated |= IW_QUAL_LEVEL_UPDATED;
break;
}
range->avg_qual.level = range->max_qual.level / 2;
range->avg_qual.noise = range->max_qual.noise / 2;
range->avg_qual.updated = range->max_qual.updated;
range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
for (band = 0; band < IEEE80211_NUM_BANDS; band ++) {
int i;
struct ieee80211_supported_band *sband;
sband = wdev->wiphy->bands[band];
if (!sband)
continue;
for (i = 0; i < sband->n_channels && c < IW_MAX_FREQUENCIES; i++) {
struct ieee80211_channel *chan = &sband->channels[i];
if (!(chan->flags & IEEE80211_CHAN_DISABLED)) {
range->freq[c].i =
ieee80211_frequency_to_channel(
chan->center_freq);
range->freq[c].m = chan->center_freq;
range->freq[c].e = 6;
c++;
}
}
}
range->num_channels = c;
range->num_frequency = c;
IW_EVENT_CAPA_SET_KERNEL(range->event_capa);
IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP);
IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);
range->scan_capa |= IW_SCAN_CAPA_ESSID;
return 0;
}
EXPORT_SYMBOL_GPL(cfg80211_wext_giwrange);
int cfg80211_wext_siwmlme(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *data, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct iw_mlme *mlme = (struct iw_mlme *)extra;
struct cfg80211_registered_device *rdev;
union {
struct cfg80211_disassoc_request disassoc;
struct cfg80211_deauth_request deauth;
} cmd;
if (!wdev)
return -EOPNOTSUPP;
rdev = wiphy_to_dev(wdev->wiphy);
if (wdev->iftype != NL80211_IFTYPE_STATION)
return -EINVAL;
if (mlme->addr.sa_family != ARPHRD_ETHER)
return -EINVAL;
memset(&cmd, 0, sizeof(cmd));
switch (mlme->cmd) {
case IW_MLME_DEAUTH:
if (!rdev->ops->deauth)
return -EOPNOTSUPP;
cmd.deauth.peer_addr = mlme->addr.sa_data;
cmd.deauth.reason_code = mlme->reason_code;
return rdev->ops->deauth(wdev->wiphy, dev, &cmd.deauth);
case IW_MLME_DISASSOC:
if (!rdev->ops->disassoc)
return -EOPNOTSUPP;
cmd.disassoc.peer_addr = mlme->addr.sa_data;
cmd.disassoc.reason_code = mlme->reason_code;
return rdev->ops->disassoc(wdev->wiphy, dev, &cmd.disassoc);
default:
return -EOPNOTSUPP;
}
}
EXPORT_SYMBOL_GPL(cfg80211_wext_siwmlme);
/**
* cfg80211_wext_freq - get wext frequency for non-"auto"
* @wiphy: the wiphy
* @freq: the wext freq encoding
*
* Returns a channel, %NULL for auto, or an ERR_PTR for errors!
*/
struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy,
struct iw_freq *freq)
{
if (freq->e == 0) {
if (freq->m < 0)
return NULL;
else
return ieee80211_get_channel(wiphy,
ieee80211_channel_to_frequency(freq->m));
} else {
int i, div = 1000000;
for (i = 0; i < freq->e; i++)
div /= 10;
if (div > 0)
return ieee80211_get_channel(wiphy, freq->m / div);
else
return ERR_PTR(-EINVAL);
}
}
EXPORT_SYMBOL_GPL(cfg80211_wext_freq);
int cfg80211_wext_siwrts(struct net_device *dev,
struct iw_request_info *info,
struct iw_param *rts, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
u32 orts = wdev->wiphy->rts_threshold;
int err;
if (rts->disabled || !rts->fixed)
wdev->wiphy->rts_threshold = (u32) -1;
else if (rts->value < 0)
return -EINVAL;
else
wdev->wiphy->rts_threshold = rts->value;
err = rdev->ops->set_wiphy_params(wdev->wiphy,
WIPHY_PARAM_RTS_THRESHOLD);
if (err)
wdev->wiphy->rts_threshold = orts;
return err;
}
EXPORT_SYMBOL_GPL(cfg80211_wext_siwrts);
int cfg80211_wext_giwrts(struct net_device *dev,
struct iw_request_info *info,
struct iw_param *rts, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
rts->value = wdev->wiphy->rts_threshold;
rts->disabled = rts->value == (u32) -1;
rts->fixed = 1;
return 0;
}
EXPORT_SYMBOL_GPL(cfg80211_wext_giwrts);
int cfg80211_wext_siwfrag(struct net_device *dev,
struct iw_request_info *info,
struct iw_param *frag, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
u32 ofrag = wdev->wiphy->frag_threshold;
int err;
if (frag->disabled || !frag->fixed)
wdev->wiphy->frag_threshold = (u32) -1;
else if (frag->value < 256)
return -EINVAL;
else {
/* Fragment length must be even, so strip LSB. */
wdev->wiphy->frag_threshold = frag->value & ~0x1;
}
err = rdev->ops->set_wiphy_params(wdev->wiphy,
WIPHY_PARAM_FRAG_THRESHOLD);
if (err)
wdev->wiphy->frag_threshold = ofrag;
return err;
}
EXPORT_SYMBOL_GPL(cfg80211_wext_siwfrag);
int cfg80211_wext_giwfrag(struct net_device *dev,
struct iw_request_info *info,
struct iw_param *frag, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
frag->value = wdev->wiphy->frag_threshold;
frag->disabled = frag->value == (u32) -1;
frag->fixed = 1;
return 0;
}
EXPORT_SYMBOL_GPL(cfg80211_wext_giwfrag);
int cfg80211_wext_siwretry(struct net_device *dev,
struct iw_request_info *info,
struct iw_param *retry, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
u32 changed = 0;
u8 olong = wdev->wiphy->retry_long;
u8 oshort = wdev->wiphy->retry_short;
int err;
if (retry->disabled ||
(retry->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT)
return -EINVAL;
if (retry->flags & IW_RETRY_LONG) {
wdev->wiphy->retry_long = retry->value;
changed |= WIPHY_PARAM_RETRY_LONG;
} else if (retry->flags & IW_RETRY_SHORT) {
wdev->wiphy->retry_short = retry->value;
changed |= WIPHY_PARAM_RETRY_SHORT;
} else {
wdev->wiphy->retry_short = retry->value;
wdev->wiphy->retry_long = retry->value;
changed |= WIPHY_PARAM_RETRY_LONG;
changed |= WIPHY_PARAM_RETRY_SHORT;
}
if (!changed)
return 0;
err = rdev->ops->set_wiphy_params(wdev->wiphy, changed);
if (err) {
wdev->wiphy->retry_short = oshort;
wdev->wiphy->retry_long = olong;
}
return err;
}
EXPORT_SYMBOL_GPL(cfg80211_wext_siwretry);
int cfg80211_wext_giwretry(struct net_device *dev,
struct iw_request_info *info,
struct iw_param *retry, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
retry->disabled = 0;
if (retry->flags == 0 || (retry->flags & IW_RETRY_SHORT)) {
/*
* First return short value, iwconfig will ask long value
* later if needed
*/
retry->flags |= IW_RETRY_LIMIT;
retry->value = wdev->wiphy->retry_short;
if (wdev->wiphy->retry_long != wdev->wiphy->retry_short)
retry->flags |= IW_RETRY_LONG;
return 0;
}
if (retry->flags & IW_RETRY_LONG) {
retry->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
retry->value = wdev->wiphy->retry_long;
}
return 0;
}
EXPORT_SYMBOL_GPL(cfg80211_wext_giwretry);