Skip to content

Implement dynamic MCS selection based on signal strength in vWIFI driver #80

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions scripts/hostapd.conf
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ interface=vw0
driver=nl80211
debug=1
ctrl_interface=/var/run/hostapd
ctrl_interface_group=0
ctrl_interface_group=root
channel=6
ssid=test
wpa=2
Expand All @@ -12,4 +12,4 @@ wpa_pairwise=CCMP

# Beacon interval (kibi-us : 1.024 ms)
beacon_int=100
dtim_period=1
dtim_period=1
169 changes: 157 additions & 12 deletions vwifi.c
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,8 @@ struct vwifi_vif {
struct wireless_dev wdev;
struct net_device *ndev;
struct net_device_stats stats;

int manual_mcs;
bool manual_mcs_set;
size_t ssid_len;
/* Currently connected BSS id */
u8 bssid[ETH_ALEN];
Expand Down Expand Up @@ -1345,7 +1346,6 @@ static int vwifi_get_station(struct wiphy *wiphy,
struct station_info *sinfo)
{
struct vwifi_vif *vif = ndev_get_vwifi_vif(dev);

bool found_sta = false;
switch (dev->ieee80211_ptr->iftype) {
case NL80211_IFTYPE_AP:;
Expand Down Expand Up @@ -1403,8 +1403,18 @@ static int vwifi_get_station(struct wiphy *wiphy,
sinfo->tx_failed = vif->stats.tx_dropped;
sinfo->tx_bytes = vif->stats.tx_bytes;
sinfo->rx_bytes = vif->stats.rx_bytes;


/* Log byte counters for debugging */
pr_info(
"vwifi: Station %pM tx_bytes %llu, rx_bytes %llu, tx_packets %u, "
"rx_packets %u, tx_failed %u\n",
mac, sinfo->tx_bytes, sinfo->rx_bytes, sinfo->tx_packets,
sinfo->rx_packets, sinfo->tx_failed);

/* For CFG80211_SIGNAL_TYPE_MBM, value is expressed in dBm */
sinfo->signal = rand_int_smooth(-100, -30, jiffies);
pr_info("vwifi: Station %pM signal %d dBm (raw)\n", mac, sinfo->signal);
sinfo->inactive_time = jiffies_to_msecs(jiffies - vif->active_time);
/*
* Using 802.11n (HT) as the PHY, configure as follows:
Expand All @@ -1425,18 +1435,72 @@ static int vwifi_get_station(struct wiphy *wiphy,
* https://semfionetworks.com/blog/mcs-table-updated-with-80211ax-data-rates/
* IEEE 802.11n : https://zh.wikipedia.org/zh-tw/IEEE_802.11n
*/
sinfo->rxrate.flags |= RATE_INFO_FLAGS_MCS;
sinfo->rxrate.mcs = 31;



/* Checks vif->manual_mcs_set to use vif->manual_mcs if set;
* Assigns modulation string for manual MCS ; else auto change based
* on signal strength
*/
int mcs_index;
const char *modulation;
if (vif->manual_mcs_set) {
mcs_index = vif->manual_mcs;
switch (mcs_index) {
case 7:
modulation = "BPSK";
break;
case 15:
modulation = "QPSK";
break;
case 23:
modulation = "16-QAM";
break;
case 31:
modulation = "64-QAM";
break;
default:
modulation = "Unknown";
break;
}
pr_info("vwifi: Station %pM using manual MCS %d (%s)\n", mac, mcs_index,
modulation);
} else {
if (sinfo->signal > -50) {
mcs_index = 31;
modulation = "64-QAM";
} else if (sinfo->signal > -70 && sinfo->signal <= -50) {
mcs_index = 23;
modulation = "16-QAM";
} else if (sinfo->signal > -90 && sinfo->signal <= -70) {
mcs_index = 15;
modulation = "QPSK";
} else {
mcs_index = 7;
modulation = "BPSK";
}
pr_info(
"vwifi: Station %pM signal %d dBm, using modulation %s (MCS %d)\n",
mac, sinfo->signal, modulation, mcs_index);
}

/* Configure RX and TX rates */
sinfo->rxrate.flags = RATE_INFO_FLAGS_MCS;
sinfo->rxrate.mcs = mcs_index;
sinfo->rxrate.bw = RATE_INFO_BW_20;
sinfo->rxrate.n_bonded_ch = 1;

sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
sinfo->txrate.mcs = 31;
sinfo->txrate.flags = RATE_INFO_FLAGS_MCS;
sinfo->txrate.mcs = mcs_index;
sinfo->txrate.bw = RATE_INFO_BW_20;
sinfo->txrate.n_bonded_ch = 1;

/* Log rate configuration for verification */
pr_info("vwifi: Station %pM txrate MCS %d, rxrate MCS %d\n", mac,
sinfo->txrate.mcs, sinfo->rxrate.mcs);

return 0;
}

/* dump station callback -- resume dump at index @idx */
static int vwifi_dump_station(struct wiphy *wiphy,
struct net_device *dev,
Expand Down Expand Up @@ -2150,6 +2214,66 @@ static int vwifi_leave_ibss(struct wiphy *wiphy, struct net_device *ndev)

return 0;
}
/* Callback to handle manual bitrate configuration via iw */
static int vwifi_set_bitrate_mask(struct wiphy *wiphy,
struct net_device *dev,
unsigned int link_id,
const u8 *peer,
const struct cfg80211_bitrate_mask *mask)
{
struct vwifi_vif *vif = netdev_priv(dev);
int mcs_index = -1;

if (!vif) {
pr_err("vwifi: Failed to get vwifi_vif for dev %s\n", dev->name);
return -EINVAL;
}

if (vif->sme_state != SME_CONNECTED) {
pr_err("vwifi: Dev %s not connected, cannot set bitrate\n", dev->name);
return -EINVAL;
}

pr_info("vwifi: set_bitrate_mask called for dev %s, link_id %u, peer %pM\n",
dev->name, link_id, peer ? peer : vif->bssid);
pr_info("vwifi: 2.4GHz MCS mask: %02x %02x %02x %02x\n",
mask->control[NL80211_BAND_2GHZ].ht_mcs[0],
mask->control[NL80211_BAND_2GHZ].ht_mcs[1],
mask->control[NL80211_BAND_2GHZ].ht_mcs[2],
mask->control[NL80211_BAND_2GHZ].ht_mcs[3]);

/* Find the requested MCS index */
for (int i = 0; i < 4; i++) {
if (mask->control[NL80211_BAND_2GHZ].ht_mcs[i]) {
for (int j = 0; j < 8; j++) {
if (mask->control[NL80211_BAND_2GHZ].ht_mcs[i] & (1 << j)) {
mcs_index = i * 8 + j;
pr_info("vwifi: Requested MCS index %d\n", mcs_index);
break;
}
}
if (mcs_index != -1)
break;
}
}

if (mcs_index == -1) {
pr_err("vwifi: No valid MCS index found\n");
return -EINVAL;
}

if (mcs_index != 7 && mcs_index != 15 && mcs_index != 23 &&
mcs_index != 31) {
pr_err("vwifi: Unsupported MCS index %d\n", mcs_index);
return -EINVAL;
}

vif->manual_mcs = mcs_index;
vif->manual_mcs_set = true;
pr_info("vwifi: Set manual MCS %d for dev %s\n", mcs_index, dev->name);

return 0;
}

/* Structure of functions for FullMAC 80211 drivers. Functions implemented
* along with fields/flags in the wiphy structure represent driver features.
Expand All @@ -2175,6 +2299,7 @@ static struct cfg80211_ops vwifi_cfg_ops = {
.get_tx_power = vwifi_get_tx_power,
.join_ibss = vwifi_join_ibss,
.leave_ibss = vwifi_leave_ibss,
.set_bitrate_mask = vwifi_set_bitrate_mask,
};

/* Macro for defining 2GHZ channel array */
Expand All @@ -2191,14 +2316,15 @@ static struct cfg80211_ops vwifi_cfg_ops = {
.center_freq = 5000 + (5 * (channel)), \
}


/* Macro for defining rate table */
#define RATE_ENT(_rate, _hw_value) \
{ \
.bitrate = (_rate), .hw_value = (_hw_value), \
}

/* Array of "supported" channels in 2GHz band. It is required for wiphy. */
static const struct ieee80211_channel vwifi_supported_channels_2ghz[] = {
static struct ieee80211_channel vwifi_supported_channels_2ghz[] = {
CHAN_2GHZ(1, 2412), CHAN_2GHZ(2, 2417), CHAN_2GHZ(3, 2422),
CHAN_2GHZ(4, 2427), CHAN_2GHZ(5, 2432), CHAN_2GHZ(6, 2437),
CHAN_2GHZ(7, 2442), CHAN_2GHZ(8, 2447), CHAN_2GHZ(9, 2452),
Expand All @@ -2221,16 +2347,35 @@ static const struct ieee80211_channel vwifi_supported_channels_5ghz[] = {
/* Array of supported rates, required to support those next rates
* for 2GHz and 5GHz band.
*/
static const struct ieee80211_rate vwifi_supported_rates[] = {
static struct ieee80211_rate vwifi_supported_rates[] = {
RATE_ENT(10, 0x1), RATE_ENT(20, 0x2), RATE_ENT(55, 0x4),
RATE_ENT(110, 0x8), RATE_ENT(60, 0x10), RATE_ENT(90, 0x20),
RATE_ENT(120, 0x40), RATE_ENT(180, 0x80), RATE_ENT(240, 0x100),
RATE_ENT(360, 0x200), RATE_ENT(480, 0x400), RATE_ENT(540, 0x800),
};

/* Describes supported band of 2GHz. */
static struct ieee80211_supported_band nf_band_2ghz;

static struct ieee80211_supported_band nf_band_2ghz = {
.band = NL80211_BAND_2GHZ,
.channels = vwifi_supported_channels_2ghz,
.n_channels = ARRAY_SIZE(vwifi_supported_channels_2ghz),
.bitrates = vwifi_supported_rates,
.n_bitrates = ARRAY_SIZE(vwifi_supported_rates),
.ht_cap =
{
.ht_supported = true,
.cap = IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_GRN_FLD |
IEEE80211_HT_CAP_MAX_AMSDU |
IEEE80211_HT_CAP_SUP_WIDTH_20_40,
.mcs =
{
.rx_mask = {0xff, 0xff, 0xff, 0xff}, /* MCS 0-31 */
.rx_highest = cpu_to_le16(300),
.tx_params = IEEE80211_HT_MCS_TX_DEFINED,
},
.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K,
.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
},
};
/* Describes supported band of 5GHz. */
static struct ieee80211_supported_band nf_band_5ghz;

Expand Down