Skip to content

Commit

Permalink
cfg80211: move txpower wext from mac80211
Browse files Browse the repository at this point in the history
This patch introduces new cfg80211 API to set the TX power
via cfg80211, puts the wext code into cfg80211 and updates
mac80211 to use all that. The -ENETDOWN bits are a hack but
will go away soon.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Johannes Berg authored and John W. Linville committed Jun 3, 2009
1 parent c64fb01 commit 7643a2c
Show file tree
Hide file tree
Showing 4 changed files with 166 additions and 78 deletions.
30 changes: 30 additions & 0 deletions include/net/cfg80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -751,6 +751,21 @@ enum wiphy_params_flags {
WIPHY_PARAM_RTS_THRESHOLD = 1 << 3,
};

/**
* enum tx_power_setting - TX power adjustment
*
* @TX_POWER_AUTOMATIC: the dbm parameter is ignored
* @TX_POWER_LIMITED: limit TX power by the dbm parameter
* @TX_POWER_FIXED: fix TX power to the dbm parameter
* @TX_POWER_OFF: turn off completely (will go away)
*/
enum tx_power_setting {
TX_POWER_AUTOMATIC,
TX_POWER_LIMITED,
TX_POWER_FIXED,
TX_POWER_OFF,
};

/**
* struct cfg80211_ops - backend description for wireless configuration
*
Expand Down Expand Up @@ -837,6 +852,11 @@ enum wiphy_params_flags {
* @changed bitfield (see &enum wiphy_params_flags) describes which values
* have changed. The actual parameter values are available in
* struct wiphy. If returning an error, no value should be changed.
*
* @set_tx_power: set the transmit power according to the parameters
* @get_tx_power: store the current TX power into the dbm variable;
* return 0 if successful; or -ENETDOWN if successful but power
* is disabled (this will go away)
*/
struct cfg80211_ops {
int (*suspend)(struct wiphy *wiphy);
Expand Down Expand Up @@ -928,6 +948,10 @@ struct cfg80211_ops {
int (*leave_ibss)(struct wiphy *wiphy, struct net_device *dev);

int (*set_wiphy_params)(struct wiphy *wiphy, u32 changed);

int (*set_tx_power)(struct wiphy *wiphy,
enum tx_power_setting type, int dbm);
int (*get_tx_power)(struct wiphy *wiphy, int *dbm);
};

/*
Expand Down Expand Up @@ -1451,6 +1475,12 @@ int cfg80211_wext_siwencode(struct net_device *dev,
int cfg80211_wext_giwencode(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *erq, char *keybuf);
int cfg80211_wext_siwtxpower(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *data, char *keybuf);
int cfg80211_wext_giwtxpower(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *data, char *keybuf);

/*
* callbacks for asynchronous cfg80211 methods, notification
Expand Down
54 changes: 54 additions & 0 deletions net/mac80211/cfg.c
Original file line number Diff line number Diff line change
Expand Up @@ -1334,6 +1334,58 @@ static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
return 0;
}

static int ieee80211_set_tx_power(struct wiphy *wiphy,
enum tx_power_setting type, int dbm)
{
struct ieee80211_local *local = wiphy_priv(wiphy);
struct ieee80211_channel *chan = local->hw.conf.channel;
u32 changes = 0;
bool radio_enabled = true;

switch (type) {
case TX_POWER_AUTOMATIC:
local->user_power_level = -1;
break;
case TX_POWER_LIMITED:
if (dbm < 0)
return -EINVAL;
local->user_power_level = dbm;
break;
case TX_POWER_FIXED:
if (dbm < 0)
return -EINVAL;
/* TODO: move to cfg80211 when it knows the channel */
if (dbm > chan->max_power)
return -EINVAL;
local->user_power_level = dbm;
break;
case TX_POWER_OFF:
radio_enabled = false;
break;
}

if (radio_enabled != local->hw.conf.radio_enabled) {
changes |= IEEE80211_CONF_CHANGE_RADIO_ENABLED;
local->hw.conf.radio_enabled = radio_enabled;
}

ieee80211_hw_config(local, changes);

return 0;
}

static int ieee80211_get_tx_power(struct wiphy *wiphy, int *dbm)
{
struct ieee80211_local *local = wiphy_priv(wiphy);

*dbm = local->hw.conf.power_level;

if (!local->hw.conf.radio_enabled)
return -ENETDOWN;

return 0;
}

struct cfg80211_ops mac80211_config_ops = {
.add_virtual_intf = ieee80211_add_iface,
.del_virtual_intf = ieee80211_del_iface,
Expand Down Expand Up @@ -1373,4 +1425,6 @@ struct cfg80211_ops mac80211_config_ops = {
.join_ibss = ieee80211_join_ibss,
.leave_ibss = ieee80211_leave_ibss,
.set_wiphy_params = ieee80211_set_wiphy_params,
.set_tx_power = ieee80211_set_tx_power,
.get_tx_power = ieee80211_get_tx_power,
};
80 changes: 2 additions & 78 deletions net/mac80211/wext.c
Original file line number Diff line number Diff line change
Expand Up @@ -306,82 +306,6 @@ static int ieee80211_ioctl_giwrate(struct net_device *dev,
return 0;
}

static int ieee80211_ioctl_siwtxpower(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *data, char *extra)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_channel* chan = local->hw.conf.channel;
bool reconf = false;
u32 reconf_flags = 0;
int new_power_level;

if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM)
return -EINVAL;
if (data->txpower.flags & IW_TXPOW_RANGE)
return -EINVAL;
if (!chan)
return -EINVAL;

/* only change when not disabling */
if (!data->txpower.disabled) {
if (data->txpower.fixed) {
if (data->txpower.value < 0)
return -EINVAL;
new_power_level = data->txpower.value;
/*
* Debatable, but we cannot do a fixed power
* level above the regulatory constraint.
* Use "iwconfig wlan0 txpower 15dBm" instead.
*/
if (new_power_level > chan->max_power)
return -EINVAL;
} else {
/*
* Automatic power level setting, max being the value
* passed in from userland.
*/
if (data->txpower.value < 0)
new_power_level = -1;
else
new_power_level = data->txpower.value;
}

reconf = true;

/*
* ieee80211_hw_config() will limit to the channel's
* max power and possibly power constraint from AP.
*/
local->user_power_level = new_power_level;
}

if (local->hw.conf.radio_enabled != !(data->txpower.disabled)) {
local->hw.conf.radio_enabled = !(data->txpower.disabled);
reconf_flags |= IEEE80211_CONF_CHANGE_RADIO_ENABLED;
ieee80211_led_radio(local, local->hw.conf.radio_enabled);
}

if (reconf || reconf_flags)
ieee80211_hw_config(local, reconf_flags);

return 0;
}

static int ieee80211_ioctl_giwtxpower(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *data, char *extra)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);

data->txpower.fixed = 1;
data->txpower.disabled = !(local->hw.conf.radio_enabled);
data->txpower.value = local->hw.conf.power_level;
data->txpower.flags = IW_TXPOW_DBM;

return 0;
}

static int ieee80211_ioctl_siwpower(struct net_device *dev,
struct iw_request_info *info,
struct iw_param *wrq,
Expand Down Expand Up @@ -658,8 +582,8 @@ static const iw_handler ieee80211_handler[] =
(iw_handler) cfg80211_wext_giwrts, /* SIOCGIWRTS */
(iw_handler) cfg80211_wext_siwfrag, /* SIOCSIWFRAG */
(iw_handler) cfg80211_wext_giwfrag, /* SIOCGIWFRAG */
(iw_handler) ieee80211_ioctl_siwtxpower, /* SIOCSIWTXPOW */
(iw_handler) ieee80211_ioctl_giwtxpower, /* SIOCGIWTXPOW */
(iw_handler) cfg80211_wext_siwtxpower, /* SIOCSIWTXPOW */
(iw_handler) cfg80211_wext_giwtxpower, /* SIOCGIWTXPOW */
(iw_handler) cfg80211_wext_siwretry, /* SIOCSIWRETRY */
(iw_handler) cfg80211_wext_giwretry, /* SIOCGIWRETRY */
(iw_handler) cfg80211_wext_siwencode, /* SIOCSIWENCODE */
Expand Down
80 changes: 80 additions & 0 deletions net/wireless/wext-compat.c
Original file line number Diff line number Diff line change
Expand Up @@ -744,3 +744,83 @@ int cfg80211_wext_giwencode(struct net_device *dev,
return err;
}
EXPORT_SYMBOL_GPL(cfg80211_wext_giwencode);

int cfg80211_wext_siwtxpower(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *data, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
enum tx_power_setting type;
int dbm = 0;

if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM)
return -EINVAL;
if (data->txpower.flags & IW_TXPOW_RANGE)
return -EINVAL;

if (!rdev->ops->set_tx_power)
return -EOPNOTSUPP;

/* only change when not disabling */
if (!data->txpower.disabled) {
if (data->txpower.fixed) {
/*
* wext doesn't support negative values, see
* below where it's for automatic
*/
if (data->txpower.value < 0)
return -EINVAL;
dbm = data->txpower.value;
type = TX_POWER_FIXED;
/* TODO: do regulatory check! */
} else {
/*
* Automatic power level setting, max being the value
* passed in from userland.
*/
if (data->txpower.value < 0) {
type = TX_POWER_AUTOMATIC;
} else {
dbm = data->txpower.value;
type = TX_POWER_LIMITED;
}
}
} else {
type = TX_POWER_OFF;
}

return rdev->ops->set_tx_power(wdev->wiphy, type, dbm);;
}
EXPORT_SYMBOL_GPL(cfg80211_wext_siwtxpower);

int cfg80211_wext_giwtxpower(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *data, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
int err, val;

if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM)
return -EINVAL;
if (data->txpower.flags & IW_TXPOW_RANGE)
return -EINVAL;

if (!rdev->ops->get_tx_power)
return -EOPNOTSUPP;

err = rdev->ops->get_tx_power(wdev->wiphy, &val);
/* HACK!!! */
if (err && err != -ENETDOWN)
return err;

/* well... oh well */
data->txpower.fixed = 1;
data->txpower.disabled = err == -ENETDOWN;
data->txpower.value = val;
data->txpower.flags = IW_TXPOW_DBM;

return 0;
}
EXPORT_SYMBOL_GPL(cfg80211_wext_giwtxpower);

0 comments on commit 7643a2c

Please sign in to comment.