diff options
-rw-r--r-- | include/net/cfg80211.h | 30 | ||||
-rw-r--r-- | net/mac80211/cfg.c | 54 | ||||
-rw-r--r-- | net/mac80211/wext.c | 80 | ||||
-rw-r--r-- | net/wireless/wext-compat.c | 80 |
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 | */ | ||
762 | enum 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 | */ |
841 | struct cfg80211_ops { | 861 | struct 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, | |||
1451 | int cfg80211_wext_giwencode(struct net_device *dev, | 1475 | int 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); |
1478 | int cfg80211_wext_siwtxpower(struct net_device *dev, | ||
1479 | struct iw_request_info *info, | ||
1480 | union iwreq_data *data, char *keybuf); | ||
1481 | int 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 | ||
1337 | static 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 | |||
1377 | static 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 | |||
1337 | struct cfg80211_ops mac80211_config_ops = { | 1389 | struct 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 | ||
309 | static 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 | |||
371 | static 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 | |||
385 | static int ieee80211_ioctl_siwpower(struct net_device *dev, | 309 | static 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 | } |
746 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwencode); | 746 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwencode); |
747 | |||
748 | int 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 | } | ||
795 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwtxpower); | ||
796 | |||
797 | int 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 | } | ||
826 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwtxpower); | ||