aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/cfg80211.h30
-rw-r--r--net/mac80211/cfg.c54
-rw-r--r--net/mac80211/wext.c80
-rw-r--r--net/wireless/wext-compat.c80
4 files changed, 166 insertions, 78 deletions
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index f20da7d63b1e..8b8e4b893625 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -752,6 +752,21 @@ enum wiphy_params_flags {
752}; 752};
753 753
754/** 754/**
755 * enum tx_power_setting - TX power adjustment
756 *
757 * @TX_POWER_AUTOMATIC: the dbm parameter is ignored
758 * @TX_POWER_LIMITED: limit TX power by the dbm parameter
759 * @TX_POWER_FIXED: fix TX power to the dbm parameter
760 * @TX_POWER_OFF: turn off completely (will go away)
761 */
762enum tx_power_setting {
763 TX_POWER_AUTOMATIC,
764 TX_POWER_LIMITED,
765 TX_POWER_FIXED,
766 TX_POWER_OFF,
767};
768
769/**
755 * struct cfg80211_ops - backend description for wireless configuration 770 * struct cfg80211_ops - backend description for wireless configuration
756 * 771 *
757 * This struct is registered by fullmac card drivers and/or wireless stacks 772 * This struct is registered by fullmac card drivers and/or wireless stacks
@@ -837,6 +852,11 @@ enum wiphy_params_flags {
837 * @changed bitfield (see &enum wiphy_params_flags) describes which values 852 * @changed bitfield (see &enum wiphy_params_flags) describes which values
838 * have changed. The actual parameter values are available in 853 * have changed. The actual parameter values are available in
839 * struct wiphy. If returning an error, no value should be changed. 854 * struct wiphy. If returning an error, no value should be changed.
855 *
856 * @set_tx_power: set the transmit power according to the parameters
857 * @get_tx_power: store the current TX power into the dbm variable;
858 * return 0 if successful; or -ENETDOWN if successful but power
859 * is disabled (this will go away)
840 */ 860 */
841struct cfg80211_ops { 861struct cfg80211_ops {
842 int (*suspend)(struct wiphy *wiphy); 862 int (*suspend)(struct wiphy *wiphy);
@@ -928,6 +948,10 @@ struct cfg80211_ops {
928 int (*leave_ibss)(struct wiphy *wiphy, struct net_device *dev); 948 int (*leave_ibss)(struct wiphy *wiphy, struct net_device *dev);
929 949
930 int (*set_wiphy_params)(struct wiphy *wiphy, u32 changed); 950 int (*set_wiphy_params)(struct wiphy *wiphy, u32 changed);
951
952 int (*set_tx_power)(struct wiphy *wiphy,
953 enum tx_power_setting type, int dbm);
954 int (*get_tx_power)(struct wiphy *wiphy, int *dbm);
931}; 955};
932 956
933/* 957/*
@@ -1451,6 +1475,12 @@ int cfg80211_wext_siwencode(struct net_device *dev,
1451int cfg80211_wext_giwencode(struct net_device *dev, 1475int cfg80211_wext_giwencode(struct net_device *dev,
1452 struct iw_request_info *info, 1476 struct iw_request_info *info,
1453 struct iw_point *erq, char *keybuf); 1477 struct iw_point *erq, char *keybuf);
1478int cfg80211_wext_siwtxpower(struct net_device *dev,
1479 struct iw_request_info *info,
1480 union iwreq_data *data, char *keybuf);
1481int cfg80211_wext_giwtxpower(struct net_device *dev,
1482 struct iw_request_info *info,
1483 union iwreq_data *data, char *keybuf);
1454 1484
1455/* 1485/*
1456 * callbacks for asynchronous cfg80211 methods, notification 1486 * callbacks for asynchronous cfg80211 methods, notification
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index d2fc18c1ae0d..81258acf48bc 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1334,6 +1334,58 @@ static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
1334 return 0; 1334 return 0;
1335} 1335}
1336 1336
1337static int ieee80211_set_tx_power(struct wiphy *wiphy,
1338 enum tx_power_setting type, int dbm)
1339{
1340 struct ieee80211_local *local = wiphy_priv(wiphy);
1341 struct ieee80211_channel *chan = local->hw.conf.channel;
1342 u32 changes = 0;
1343 bool radio_enabled = true;
1344
1345 switch (type) {
1346 case TX_POWER_AUTOMATIC:
1347 local->user_power_level = -1;
1348 break;
1349 case TX_POWER_LIMITED:
1350 if (dbm < 0)
1351 return -EINVAL;
1352 local->user_power_level = dbm;
1353 break;
1354 case TX_POWER_FIXED:
1355 if (dbm < 0)
1356 return -EINVAL;
1357 /* TODO: move to cfg80211 when it knows the channel */
1358 if (dbm > chan->max_power)
1359 return -EINVAL;
1360 local->user_power_level = dbm;
1361 break;
1362 case TX_POWER_OFF:
1363 radio_enabled = false;
1364 break;
1365 }
1366
1367 if (radio_enabled != local->hw.conf.radio_enabled) {
1368 changes |= IEEE80211_CONF_CHANGE_RADIO_ENABLED;
1369 local->hw.conf.radio_enabled = radio_enabled;
1370 }
1371
1372 ieee80211_hw_config(local, changes);
1373
1374 return 0;
1375}
1376
1377static int ieee80211_get_tx_power(struct wiphy *wiphy, int *dbm)
1378{
1379 struct ieee80211_local *local = wiphy_priv(wiphy);
1380
1381 *dbm = local->hw.conf.power_level;
1382
1383 if (!local->hw.conf.radio_enabled)
1384 return -ENETDOWN;
1385
1386 return 0;
1387}
1388
1337struct cfg80211_ops mac80211_config_ops = { 1389struct cfg80211_ops mac80211_config_ops = {
1338 .add_virtual_intf = ieee80211_add_iface, 1390 .add_virtual_intf = ieee80211_add_iface,
1339 .del_virtual_intf = ieee80211_del_iface, 1391 .del_virtual_intf = ieee80211_del_iface,
@@ -1373,4 +1425,6 @@ struct cfg80211_ops mac80211_config_ops = {
1373 .join_ibss = ieee80211_join_ibss, 1425 .join_ibss = ieee80211_join_ibss,
1374 .leave_ibss = ieee80211_leave_ibss, 1426 .leave_ibss = ieee80211_leave_ibss,
1375 .set_wiphy_params = ieee80211_set_wiphy_params, 1427 .set_wiphy_params = ieee80211_set_wiphy_params,
1428 .set_tx_power = ieee80211_set_tx_power,
1429 .get_tx_power = ieee80211_get_tx_power,
1376}; 1430};
diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c
index a01154e127f0..d2d81b103341 100644
--- a/net/mac80211/wext.c
+++ b/net/mac80211/wext.c
@@ -306,82 +306,6 @@ static int ieee80211_ioctl_giwrate(struct net_device *dev,
306 return 0; 306 return 0;
307} 307}
308 308
309static int ieee80211_ioctl_siwtxpower(struct net_device *dev,
310 struct iw_request_info *info,
311 union iwreq_data *data, char *extra)
312{
313 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
314 struct ieee80211_channel* chan = local->hw.conf.channel;
315 bool reconf = false;
316 u32 reconf_flags = 0;
317 int new_power_level;
318
319 if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM)
320 return -EINVAL;
321 if (data->txpower.flags & IW_TXPOW_RANGE)
322 return -EINVAL;
323 if (!chan)
324 return -EINVAL;
325
326 /* only change when not disabling */
327 if (!data->txpower.disabled) {
328 if (data->txpower.fixed) {
329 if (data->txpower.value < 0)
330 return -EINVAL;
331 new_power_level = data->txpower.value;
332 /*
333 * Debatable, but we cannot do a fixed power
334 * level above the regulatory constraint.
335 * Use "iwconfig wlan0 txpower 15dBm" instead.
336 */
337 if (new_power_level > chan->max_power)
338 return -EINVAL;
339 } else {
340 /*
341 * Automatic power level setting, max being the value
342 * passed in from userland.
343 */
344 if (data->txpower.value < 0)
345 new_power_level = -1;
346 else
347 new_power_level = data->txpower.value;
348 }
349
350 reconf = true;
351
352 /*
353 * ieee80211_hw_config() will limit to the channel's
354 * max power and possibly power constraint from AP.
355 */
356 local->user_power_level = new_power_level;
357 }
358
359 if (local->hw.conf.radio_enabled != !(data->txpower.disabled)) {
360 local->hw.conf.radio_enabled = !(data->txpower.disabled);
361 reconf_flags |= IEEE80211_CONF_CHANGE_RADIO_ENABLED;
362 ieee80211_led_radio(local, local->hw.conf.radio_enabled);
363 }
364
365 if (reconf || reconf_flags)
366 ieee80211_hw_config(local, reconf_flags);
367
368 return 0;
369}
370
371static int ieee80211_ioctl_giwtxpower(struct net_device *dev,
372 struct iw_request_info *info,
373 union iwreq_data *data, char *extra)
374{
375 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
376
377 data->txpower.fixed = 1;
378 data->txpower.disabled = !(local->hw.conf.radio_enabled);
379 data->txpower.value = local->hw.conf.power_level;
380 data->txpower.flags = IW_TXPOW_DBM;
381
382 return 0;
383}
384
385static int ieee80211_ioctl_siwpower(struct net_device *dev, 309static int ieee80211_ioctl_siwpower(struct net_device *dev,
386 struct iw_request_info *info, 310 struct iw_request_info *info,
387 struct iw_param *wrq, 311 struct iw_param *wrq,
@@ -658,8 +582,8 @@ static const iw_handler ieee80211_handler[] =
658 (iw_handler) cfg80211_wext_giwrts, /* SIOCGIWRTS */ 582 (iw_handler) cfg80211_wext_giwrts, /* SIOCGIWRTS */
659 (iw_handler) cfg80211_wext_siwfrag, /* SIOCSIWFRAG */ 583 (iw_handler) cfg80211_wext_siwfrag, /* SIOCSIWFRAG */
660 (iw_handler) cfg80211_wext_giwfrag, /* SIOCGIWFRAG */ 584 (iw_handler) cfg80211_wext_giwfrag, /* SIOCGIWFRAG */
661 (iw_handler) ieee80211_ioctl_siwtxpower, /* SIOCSIWTXPOW */ 585 (iw_handler) cfg80211_wext_siwtxpower, /* SIOCSIWTXPOW */
662 (iw_handler) ieee80211_ioctl_giwtxpower, /* SIOCGIWTXPOW */ 586 (iw_handler) cfg80211_wext_giwtxpower, /* SIOCGIWTXPOW */
663 (iw_handler) cfg80211_wext_siwretry, /* SIOCSIWRETRY */ 587 (iw_handler) cfg80211_wext_siwretry, /* SIOCSIWRETRY */
664 (iw_handler) cfg80211_wext_giwretry, /* SIOCGIWRETRY */ 588 (iw_handler) cfg80211_wext_giwretry, /* SIOCGIWRETRY */
665 (iw_handler) cfg80211_wext_siwencode, /* SIOCSIWENCODE */ 589 (iw_handler) cfg80211_wext_siwencode, /* SIOCSIWENCODE */
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
index 711e00a0c9b5..9fbfb8536e75 100644
--- a/net/wireless/wext-compat.c
+++ b/net/wireless/wext-compat.c
@@ -744,3 +744,83 @@ int cfg80211_wext_giwencode(struct net_device *dev,
744 return err; 744 return err;
745} 745}
746EXPORT_SYMBOL_GPL(cfg80211_wext_giwencode); 746EXPORT_SYMBOL_GPL(cfg80211_wext_giwencode);
747
748int cfg80211_wext_siwtxpower(struct net_device *dev,
749 struct iw_request_info *info,
750 union iwreq_data *data, char *extra)
751{
752 struct wireless_dev *wdev = dev->ieee80211_ptr;
753 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
754 enum tx_power_setting type;
755 int dbm = 0;
756
757 if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM)
758 return -EINVAL;
759 if (data->txpower.flags & IW_TXPOW_RANGE)
760 return -EINVAL;
761
762 if (!rdev->ops->set_tx_power)
763 return -EOPNOTSUPP;
764
765 /* only change when not disabling */
766 if (!data->txpower.disabled) {
767 if (data->txpower.fixed) {
768 /*
769 * wext doesn't support negative values, see
770 * below where it's for automatic
771 */
772 if (data->txpower.value < 0)
773 return -EINVAL;
774 dbm = data->txpower.value;
775 type = TX_POWER_FIXED;
776 /* TODO: do regulatory check! */
777 } else {
778 /*
779 * Automatic power level setting, max being the value
780 * passed in from userland.
781 */
782 if (data->txpower.value < 0) {
783 type = TX_POWER_AUTOMATIC;
784 } else {
785 dbm = data->txpower.value;
786 type = TX_POWER_LIMITED;
787 }
788 }
789 } else {
790 type = TX_POWER_OFF;
791 }
792
793 return rdev->ops->set_tx_power(wdev->wiphy, type, dbm);;
794}
795EXPORT_SYMBOL_GPL(cfg80211_wext_siwtxpower);
796
797int cfg80211_wext_giwtxpower(struct net_device *dev,
798 struct iw_request_info *info,
799 union iwreq_data *data, char *extra)
800{
801 struct wireless_dev *wdev = dev->ieee80211_ptr;
802 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
803 int err, val;
804
805 if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM)
806 return -EINVAL;
807 if (data->txpower.flags & IW_TXPOW_RANGE)
808 return -EINVAL;
809
810 if (!rdev->ops->get_tx_power)
811 return -EOPNOTSUPP;
812
813 err = rdev->ops->get_tx_power(wdev->wiphy, &val);
814 /* HACK!!! */
815 if (err && err != -ENETDOWN)
816 return err;
817
818 /* well... oh well */
819 data->txpower.fixed = 1;
820 data->txpower.disabled = err == -ENETDOWN;
821 data->txpower.value = val;
822 data->txpower.flags = IW_TXPOW_DBM;
823
824 return 0;
825}
826EXPORT_SYMBOL_GPL(cfg80211_wext_giwtxpower);