cfg80211: move txpower wext from mac80211
authorJohannes Berg <johannes@sipsolutions.net>
Tue, 2 Jun 2009 11:01:39 +0000 (13:01 +0200)
committerJohn W. Linville <linville@tuxdriver.com>
Wed, 3 Jun 2009 18:06:14 +0000 (14:06 -0400)
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>
include/net/cfg80211.h
net/mac80211/cfg.c
net/mac80211/wext.c
net/wireless/wext-compat.c

index f20da7d63b1e33919a40aef0e5a43827fdebedf2..8b8e4b8936259e4d62e731429e4011668435e7f6 100644 (file)
@@ -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
  *
@@ -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);
@@ -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);
 };
 
 /*
@@ -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
index d2fc18c1ae0d162384a3ed435172fcf73c3af571..81258acf48bc950221e52d0fad7e0bcf13cef81e 100644 (file)
@@ -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,
@@ -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,
 };
index a01154e127f07b0ae6d949177f4dd06c49806667..d2d81b103341472613d8dabe14c3fda20c21c01b 100644 (file)
@@ -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,
@@ -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 */
index 711e00a0c9b5c2f1fab1d464bfa7782a36aed510..9fbfb8536e754f81061aa9100dd6dd47e393bc2d 100644 (file)
@@ -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);