Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

cfg80211: move txpower wext from mac80211

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>

authored by

Johannes Berg and committed by
John W. Linville
7643a2c3 c64fb016

+166 -78
+30
include/net/cfg80211.h
··· 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 770 * struct cfg80211_ops - backend description for wireless configuration 756 771 * 757 772 * This struct is registered by fullmac card drivers and/or wireless stacks ··· 852 837 * @changed bitfield (see &enum wiphy_params_flags) describes which values 853 838 * have changed. The actual parameter values are available in 854 839 * struct wiphy. If returning an error, no value should be changed. 840 + * 841 + * @set_tx_power: set the transmit power according to the parameters 842 + * @get_tx_power: store the current TX power into the dbm variable; 843 + * return 0 if successful; or -ENETDOWN if successful but power 844 + * is disabled (this will go away) 855 845 */ 856 846 struct cfg80211_ops { 857 847 int (*suspend)(struct wiphy *wiphy); ··· 948 928 int (*leave_ibss)(struct wiphy *wiphy, struct net_device *dev); 949 929 950 930 int (*set_wiphy_params)(struct wiphy *wiphy, u32 changed); 931 + 932 + int (*set_tx_power)(struct wiphy *wiphy, 933 + enum tx_power_setting type, int dbm); 934 + int (*get_tx_power)(struct wiphy *wiphy, int *dbm); 951 935 }; 952 936 953 937 /* ··· 1475 1451 int cfg80211_wext_giwencode(struct net_device *dev, 1476 1452 struct iw_request_info *info, 1477 1453 struct iw_point *erq, char *keybuf); 1454 + int cfg80211_wext_siwtxpower(struct net_device *dev, 1455 + struct iw_request_info *info, 1456 + union iwreq_data *data, char *keybuf); 1457 + int cfg80211_wext_giwtxpower(struct net_device *dev, 1458 + struct iw_request_info *info, 1459 + union iwreq_data *data, char *keybuf); 1478 1460 1479 1461 /* 1480 1462 * callbacks for asynchronous cfg80211 methods, notification
+54
net/mac80211/cfg.c
··· 1334 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 1389 struct cfg80211_ops mac80211_config_ops = { 1338 1390 .add_virtual_intf = ieee80211_add_iface, 1339 1391 .del_virtual_intf = ieee80211_del_iface, ··· 1425 1373 .join_ibss = ieee80211_join_ibss, 1426 1374 .leave_ibss = ieee80211_leave_ibss, 1427 1375 .set_wiphy_params = ieee80211_set_wiphy_params, 1376 + .set_tx_power = ieee80211_set_tx_power, 1377 + .get_tx_power = ieee80211_get_tx_power, 1428 1378 };
+2 -78
net/mac80211/wext.c
··· 306 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 309 static int ieee80211_ioctl_siwpower(struct net_device *dev, 386 310 struct iw_request_info *info, 387 311 struct iw_param *wrq, ··· 582 658 (iw_handler) cfg80211_wext_giwrts, /* SIOCGIWRTS */ 583 659 (iw_handler) cfg80211_wext_siwfrag, /* SIOCSIWFRAG */ 584 660 (iw_handler) cfg80211_wext_giwfrag, /* SIOCGIWFRAG */ 585 - (iw_handler) ieee80211_ioctl_siwtxpower, /* SIOCSIWTXPOW */ 586 - (iw_handler) ieee80211_ioctl_giwtxpower, /* SIOCGIWTXPOW */ 661 + (iw_handler) cfg80211_wext_siwtxpower, /* SIOCSIWTXPOW */ 662 + (iw_handler) cfg80211_wext_giwtxpower, /* SIOCGIWTXPOW */ 587 663 (iw_handler) cfg80211_wext_siwretry, /* SIOCSIWRETRY */ 588 664 (iw_handler) cfg80211_wext_giwretry, /* SIOCGIWRETRY */ 589 665 (iw_handler) cfg80211_wext_siwencode, /* SIOCSIWENCODE */
+80
net/wireless/wext-compat.c
··· 744 744 return err; 745 745 } 746 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);