Skip to content

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

New issue

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

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

Already on GitHub? # to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
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
188 changes: 181 additions & 7 deletions vwifi.c
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +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 */
Expand Down Expand Up @@ -1403,8 +1405,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,15 +1437,92 @@ 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;
/* Check vif->manual_mcs_set to use vif->manual_mcs if set;
* Assign modulation string for manual MCS ; else auto change based
* on signal strength
*/
int mcs_index;
const char *modulation;
const char *coding_rate;
if (vif->manual_mcs_set) {
mcs_index = vif->manual_mcs;
switch (mcs_index) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to IEEE 802.11n, MCS indices 7, 15, 23, and 31 all use 64-QAM modulation.
You should revise the descriptions associated with each MCS index accordingly, or consider modifying your design if your intention was to differentiate based on modulation type.

ref:
mcsindex

case 24:
modulation = "BPSK";
coding_rate = "1/2";
break;
case 25:
modulation = "QPSK";
coding_rate = "1/2";
break;
case 26:
modulation = "QPSK";
coding_rate = "3/4";
break;
case 27:
modulation = "16-QAM";
coding_rate = "1/2";
break;
case 28:
modulation = "16-QAM";
coding_rate = "3/4";
break;
case 29:
modulation = "64-QAM";
coding_rate = "2/3";
break;
case 30:
modulation = "64-QAM";
coding_rate = "3/4";
break;
case 31:
modulation = "64-QAM";
coding_rate = "5/6";
break;
default:
pr_err("vwifi: Unsupported MCS index %d\n", mcs_index);
mcs_index = 24; /* Default to lowest 4-stream MCS */
modulation = "BPSK";
coding_rate = "1/2";
break;
}
pr_info("vwifi: Station %pM using manual MCS %d (%s, %s)\n", mac,
mcs_index, modulation, coding_rate);
} else {
if (sinfo->signal > -50) {
mcs_index = 31;
modulation = "64-QAM";
coding_rate = "5/6";
} else if (sinfo->signal > -70 && sinfo->signal <= -50) {
mcs_index = 28;
modulation = "16-QAM";
coding_rate = "3/4";
} else if (sinfo->signal > -90 && sinfo->signal <= -70) {
mcs_index = 25;
modulation = "QPSK";
coding_rate = "1/2";
} else {
mcs_index = 24;
modulation = "BPSK";
coding_rate = "1/2";
}
pr_info("vwifi: Station %pM signal %d dBm, using MCS %d (%s, %s)\n",
mac, sinfo->signal, mcs_index, modulation, coding_rate);
}
/* 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;
}

Expand Down Expand Up @@ -1677,8 +1766,13 @@ static int vwifi_start_ap(struct wiphy *wiphy,

/* Initialize hrtimer of beacon */
pr_info("vwifi: init beacon_timer.\n");
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 15, 0)
hrtimer_setup(&vif->beacon_timer, vwifi_beacon, CLOCK_MONOTONIC,
HRTIMER_MODE_ABS_SOFT);
#else
hrtimer_init(&vif->beacon_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_SOFT);
vif->beacon_timer.function = vwifi_beacon;
#endif

if (!hrtimer_is_queued(&vif->beacon_timer)) {
u64 tsf, until_tbtt;
Expand Down Expand Up @@ -2145,6 +2239,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;
}

/* Restrict to supported 4-stream MCS indices 24–31 */
if (mcs_index < 24 || 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 @@ -2170,6 +2324,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 Down Expand Up @@ -2223,9 +2378,28 @@ static const struct ieee80211_rate vwifi_supported_rates[] = {
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
Loading