From f63872b273f223b963c807c5e39b5f3299a818f5 Mon Sep 17 00:00:00 2001 From: elian Date: Sun, 2 Jun 2024 17:27:40 +0800 Subject: [PATCH] Support transmit power This commit introduces 'tx_power' to the virtual interface to specify the device's transmit power level. It also adds vwifi_set_tx_power() and vwifi_get_tx_power() to align with 'set_tx_power' and 'get_tx_power' in cfg80211_ops, respectively. The vwifi_set_tx_power() enables the setting of the device's transmit power, whereas vwifi_get_tx_power() facilitates the retrieval of this information. Users can adjust the transmit power by employing the command: iw dev [interface] set txpower auto/limit/fixed [transmit power (mBm)] auto: Use default transmit power limit: Restrict power limits to a specific value fixed: Set power freely Since using the above command results in the 'wdev' parameter NULL, a new function 'wiphy_get_vwifi_vif' was added to obtain the virtual interface. Additionally, the 'type' parameter is used to distinguish between "auto/limit/fixed". This commit also modifies the comments regarding mBm. In Linux source files, the correct terminology is mBm rather than mdBm. In traditional measurements, 'm' usually represents 10 to the power of negative three. However, 1 dBm equals 100 mBm, so using mdBm could be misleading. --- scripts/verify.sh | 5 +++ vwifi.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 83 insertions(+), 1 deletion(-) diff --git a/scripts/verify.sh b/scripts/verify.sh index af8b481..6113f07 100755 --- a/scripts/verify.sh +++ b/scripts/verify.sh @@ -24,6 +24,11 @@ if [ $final_ret -eq 0 ]; then # to avoid device or resource busy error sleep 0.5 + # set transmit power (mBm) + sudo iw dev vw0 set txpower auto + sudo iw dev vw1 set txpower fixed 1200 + sudo iw dev vw2 set txpower fixed 1300 + # get phy number of each interface sudo iw dev > device.log vw0_phy=$(get_wiphy_name vw0) diff --git a/vwifi.c b/vwifi.c index afdfb2b..2e09827 100644 --- a/vwifi.c +++ b/vwifi.c @@ -155,6 +155,9 @@ struct vwifi_vif { /* Packet virtio header size */ u8 vnet_hdr_len; + + /* Transmit power */ + s32 tx_power; }; static int station = 2; @@ -387,6 +390,20 @@ static inline struct vwifi_vif *wdev_get_vwifi_vif(struct wireless_dev *wdev) return container_of(wdev, struct vwifi_vif, wdev); } +/* helper function to retrieve vif from wiphy */ +static struct vwifi_vif *wiphy_get_vwifi_vif(struct wiphy *wiphy) +{ + struct wireless_dev *wdev; + struct vwifi_vif *vif = NULL; + + list_for_each_entry (wdev, &wiphy->wdev_list, list) { + vif = container_of(wdev, struct vwifi_vif, wdev); + break; /* Assuming only one virtual interface is present */ + } + + return vif; +} + static inline u32 vwifi_mac_to_32(const u8 *mac) { u32 h = 3323198485U; @@ -1840,6 +1857,64 @@ static int vwifi_delete_interface(struct vwifi_vif *vif) return 0; } +/* Set transmit power for the virtual interface */ +static int vwifi_set_tx_power(struct wiphy *wiphy, + struct wireless_dev *wdev, + enum nl80211_tx_power_setting type, + int mbm) +{ + struct vwifi_vif *vif = wiphy_get_vwifi_vif(wiphy); + /* Validate vif pointer */ + if (!vif) + return -EINVAL; + + if (mutex_lock_interruptible(&vif->lock)) + return -ERESTARTSYS; + + int power = MBM_TO_DBM(mbm); + switch (type) { + case NL80211_TX_POWER_AUTOMATIC: + /* Use default transmit power (11 dBm) */ + vif->tx_power = 11; + break; + + case NL80211_TX_POWER_LIMITED: + /* Restrict power limits to a specific value (0 ~ 18 dBm) */ + if (power < 0) + vif->tx_power = 0; + else if (power > 18) + vif->tx_power = 18; + else + vif->tx_power = power; + break; + + case NL80211_TX_POWER_FIXED: + /* Set power freely */ + vif->tx_power = power; + break; + + default: + return -EINVAL; /* Invalid parameter */ + } + + mutex_unlock(&vif->lock); + + return 0; +} + +/* Get transmit power from the virtual interface */ +static int vwifi_get_tx_power(struct wiphy *wiphy, + struct wireless_dev *wdev, + int *dbm) +{ + struct vwifi_vif *vif = wdev_get_vwifi_vif(wdev); + /* Validate vif pointer */ + if (!vif) + return -EINVAL; + *dbm = vif->tx_power; + return 0; +} + /* Structure of functions for FullMAC 80211 drivers. Functions implemented * along with fields/flags in the wiphy structure represent driver features. * This module can only perform "scan" and "connect". Some functions cannot @@ -1860,6 +1935,8 @@ static struct cfg80211_ops vwifi_cfg_ops = { .del_key = vwifi_del_key, .set_default_key = vwifi_set_default_key, .change_station = vwifi_change_station, + .set_tx_power = vwifi_set_tx_power, + .get_tx_power = vwifi_get_tx_power, }; /* Macro for defining 2GHZ channel array */ @@ -2044,7 +2121,7 @@ static struct wiphy *vwifi_cfg80211_add(void) /* Signal type * CFG80211_SIGNAL_TYPE_UNSPEC allows us specify signal strength from 0 to * 100. The reasonable value for CFG80211_SIGNAL_TYPE_MBM is -3000 to -10000 - * (mdBm). + * (mBm). */ wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;