From e46d9e2598b9aaf2f6b254ddb50355f163ac3432 Mon Sep 17 00:00:00 2001 From: Janusz Dziedzic <janusz.dziedzic@iopsys.eu> Date: Mon, 12 May 2025 13:44:05 +0200 Subject: [PATCH] acs: allow to choose highest bandwidth --- src/acs.c | 27 +++++++++++++------- src/acs.h | 4 +-- src/cntlr.c | 3 ++- src/cntlr_commands_impl.c | 8 ++++-- src/wifi_dataelements.h | 1 + src/wifi_opclass.c | 52 +++++++++++++++++++++++++++++++++++++++ src/wifi_opclass.h | 1 + 7 files changed, 82 insertions(+), 14 deletions(-) diff --git a/src/acs.c b/src/acs.c index ceeee8da..4a97a8ab 100644 --- a/src/acs.c +++ b/src/acs.c @@ -456,18 +456,20 @@ static int cntlr_get_current_acs_params(struct wifi_radio_element *radio, struct } void cntlr_acs_node_channel_recalc(struct node *node, enum wifi_band band, uint8_t opclass, - uint32_t bandwidth, bool skip_dfs, bool prevent_cac) + uint32_t bandwidth, bool skip_dfs, bool prevent_cac, + bool highest_bandwidth) { struct wifi_acs_params cur_acs_params = {}; struct wifi_acs_params acs_params = {}; + uint32_t bw = bandwidth; struct netif_radio *r = NULL; int ret; acs_params.skip_dfs = skip_dfs; acs_params.skip_dfs_not_available = prevent_cac; - cntlr_dbg(LOG_CHANNEL, "acs node channel recalc " MACFMT " skip_dfs %d prevent_cac %d\n", - MAC2STR(node->almacaddr), acs_params.skip_dfs, acs_params.skip_dfs_not_available); + cntlr_dbg(LOG_CHANNEL, "acs node channel recalc " MACFMT " opclass %u bandwidth %u skip_dfs %d prevent_cac %d higest_bandwidth %d\n", + MAC2STR(node->almacaddr), opclass, bandwidth, acs_params.skip_dfs, acs_params.skip_dfs_not_available, highest_bandwidth); list_for_each_entry(r, &node->radiolist, list) { struct wifi_radio_opclass req_opclass = {}; @@ -476,6 +478,13 @@ void cntlr_acs_node_channel_recalc(struct node *node, enum wifi_band band, uint8 if (band && band != BAND_ANY && band != r->radio_el->band) continue; + /* Try best bandwidth */ + if (highest_bandwidth && !bandwidth && !opclass) { + bw = wifi_opclass_highest_bandwidth(&r->radio_el->pref_opclass, prevent_cac); + cntlr_dbg(LOG_CHANNEL, "acs node channel recalc " MACFMT " radio " MACFMT " highest bandwidth %d\n", + MAC2STR(node->almacaddr), MAC2STR(r->radio_el->macaddr), bw); + } + if (opclass) { cntlr_get_current_acs_params(r->radio_el, &cur_acs_params); acs_params.opclass = opclass; @@ -484,11 +493,11 @@ void cntlr_acs_node_channel_recalc(struct node *node, enum wifi_band band, uint8 acs_params.best_channel = cur_acs_params.best_channel; acs_params.best_bw = cur_acs_params.best_bw; } - } else if (bandwidth) { + } else if (bw) { cntlr_get_current_acs_params(r->radio_el, &cur_acs_params); - acs_params.bw = bandwidth; + acs_params.bw = bw; - if (cur_acs_params.bw == bandwidth) { + if (cur_acs_params.bw == bw) { acs_params.best_channel = cur_acs_params.best_channel; acs_params.best_bw = cur_acs_params.best_bw; } @@ -554,12 +563,12 @@ void cntlr_acs_node_channel_recalc(struct node *node, enum wifi_band band, uint8 } } -void cntlr_acs_recalc(struct controller *c, bool skip_dfs, bool skip_cac) +void cntlr_acs_recalc(struct controller *c, bool skip_dfs, bool prevent_cac, bool highest_bandwidth) { struct node *n = NULL; list_for_each_entry(n, &c->nodelist, list) { - cntlr_acs_node_channel_recalc(n, BAND_ANY, 0, 0, skip_dfs, skip_cac); + cntlr_acs_node_channel_recalc(n, BAND_ANY, 0, 0, skip_dfs, prevent_cac, highest_bandwidth); } } @@ -917,6 +926,6 @@ void cntlr_acs_channel_pref_report(struct node *n, struct netif_radio *r) MAC2STR(n->almacaddr), MAC2STR(r->radio_el->macaddr)); acs->recalc = false; - cntlr_acs_node_channel_recalc(n, BAND_ANY, 0, 0, skip_dfs, prevent_cac); + cntlr_acs_node_channel_recalc(n, BAND_ANY, 0, 0, skip_dfs, prevent_cac, false); } } diff --git a/src/acs.h b/src/acs.h index 5c03f80c..fc264c1b 100644 --- a/src/acs.h +++ b/src/acs.h @@ -20,10 +20,10 @@ enum wifi_radio_opclass_dfs; int cntlr_acs_radio_channel_recalc(struct node *node, struct netif_radio *rd, struct wifi_acs_params *params); void cntlr_acs_node_channel_recalc(struct node *node, enum wifi_band band, uint8_t opclass, - uint32_t bandwidth, bool skip_dfs, bool prevent_cac); + uint32_t bandwidth, bool skip_dfs, bool prevent_cac, bool highest_bandwidth); void cntlr_dfs_node_cleanup(struct node *node); void cntlr_dfs_radio_cleanup(struct node *node, struct netif_radio *radio); -void cntlr_acs_recalc(struct controller *c, bool skip_dfs, bool skip_cac); +void cntlr_acs_recalc(struct controller *c, bool skip_dfs, bool prevent_cac, bool highest_bandwidth); void cntlr_dfs_cleanup(struct controller *c); int cntlr_radio_pref_opclass_add(struct wifi_radio_element *radio, uint8_t classid, diff --git a/src/cntlr.c b/src/cntlr.c index 5a1c1eb9..71139ad9 100644 --- a/src/cntlr.c +++ b/src/cntlr.c @@ -1451,10 +1451,11 @@ static void cntlr_acs_run(atimer_t *t) struct controller *c = container_of(t, struct controller, acs); bool skip_dfs = false; bool prevent_cac = true; + bool highest_bandwidth = false; /* Run ACS recalc here */ dbg("acs timeout - run recalc\n"); - cntlr_acs_recalc(c, skip_dfs, prevent_cac); + cntlr_acs_recalc(c, skip_dfs, prevent_cac, highest_bandwidth); if (c->cfg.acs_timeout) timer_set(&c->acs, c->cfg.acs_timeout * 1000); diff --git a/src/cntlr_commands_impl.c b/src/cntlr_commands_impl.c index 526f9006..1ca7bbc0 100644 --- a/src/cntlr_commands_impl.c +++ b/src/cntlr_commands_impl.c @@ -1316,6 +1316,7 @@ int COMMAND(trigger_channel_acs)(void *priv, void *args, void *out) char agent[18] = { 0 }; bool skip_dfs = false; bool prevent_cac = true; + bool highest_bandwidth = false; uint32_t bandwidth = 0; uint8_t opclass = 0; int ret; @@ -1357,15 +1358,18 @@ int COMMAND(trigger_channel_acs)(void *priv, void *args, void *out) if (tb[CHANNEL_ACS_ATTR_OPCLASS]) opclass = blobmsg_get_u32(tb[CHANNEL_ACS_ATTR_OPCLASS]); - if (tb[CHANNEL_ACS_ATTR_BANDWIDTH]) + if (tb[CHANNEL_ACS_ATTR_BANDWIDTH]) { bandwidth = blobmsg_get_u32(tb[CHANNEL_ACS_ATTR_BANDWIDTH]); + if (!bandwidth) + highest_bandwidth = true; + } list_for_each_entry(node, &c->nodelist, list) { if (!hwaddr_is_zero(agent_mac) && memcmp(agent_mac, node->almacaddr, 6)) continue; /* Action here */ - cntlr_acs_node_channel_recalc(node, band, opclass, bandwidth, skip_dfs, prevent_cac); + cntlr_acs_node_channel_recalc(node, band, opclass, bandwidth, skip_dfs, prevent_cac, highest_bandwidth); /* Show information about recalc */ cntlr_acs_node_info(node, band, bb); diff --git a/src/wifi_dataelements.h b/src/wifi_dataelements.h index 9e672654..d07588d9 100644 --- a/src/wifi_dataelements.h +++ b/src/wifi_dataelements.h @@ -95,6 +95,7 @@ struct wifi_acs_params { bool skip_dfs; /* Skip all DFS channels */ bool skip_dfs_not_available; /* Prevent CAC */ + bool higest_bandwidth; /* Use highest possible bandwidth */ /* Output params */ int best_channel; diff --git a/src/wifi_opclass.c b/src/wifi_opclass.c index 4c9bcb57..3ac47d72 100644 --- a/src/wifi_opclass.c +++ b/src/wifi_opclass.c @@ -1492,3 +1492,55 @@ int wifi_opclass_get_max_bw(struct wifi_radio_opclass *opclass, return 0; } + +uint32_t wifi_opclass_highest_bandwidth(struct wifi_radio_opclass *opclass, bool available_only) +{ + struct wifi_radio_opclass_entry *entry; + struct wifi_radio_opclass_channel *chan; + uint32_t bandwidth = 0; + uint8_t pref = 0; + int i, j; + + for (i = 0; i < opclass->num_opclass; i++) { + entry = &opclass->opclass[i]; + + if (!entry->num_channel) + continue; + + for (j = 0; j < entry->num_channel; j++) { + chan = &entry->channel[j]; + + /* Not supported */ + pref = (chan->preference & CHANNEL_PREF_MASK) >> 4; + if (!pref) + continue; + + if (entry->band != 5) + break; + + if (chan->dfs == WIFI_RADIO_OPCLASS_CHANNEL_DFS_NONE) + break; + + /* Check if we pass CAC */ + if (available_only && + chan->dfs != WIFI_RADIO_OPCLASS_CHANNEL_DFS_AVAILABLE) + continue; + + /* Skip NOP */ + if (chan->dfs == WIFI_RADIO_OPCLASS_CHANNEL_DFS_NOP || + chan->dfs == WIFI_RADIO_OPCLASS_CHANNEL_DFS_CAC) + continue; + + break; + } + + /* Not found */ + if (j == entry->num_channel) + continue; + + if (entry->bandwidth > bandwidth) + bandwidth = entry->bandwidth; + } + + return bandwidth; +} diff --git a/src/wifi_opclass.h b/src/wifi_opclass.h index ff8216db..ca2366f4 100644 --- a/src/wifi_opclass.h +++ b/src/wifi_opclass.h @@ -76,4 +76,5 @@ int wifi_opclass_get_max_bw(struct wifi_radio_opclass *opclass, uint32_t *bw, uint8_t *id, uint8_t *channel); +uint32_t wifi_opclass_highest_bandwidth(struct wifi_radio_opclass *opclass, bool available_only); #endif /* _WIFI_RADIO_OPCLASS_H_ */ -- GitLab