diff --git a/src/acs.c b/src/acs.c index ceeee8da63198c395bcd4487fed54f861de9d6d7..4a97a8ab8f5e5d18c62871286410547e01d54f43 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 5c03f80c09b669274aef63cfde1b664a73afe8e4..fc264c1bb66512e8709e783b02fd68104b958309 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 5a1c1eb91c33883786d9aedfa6c499139595b2ea..71139ad923eff2fd66c2679523beeea3136d5986 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 526f9006f877465f66ac98bfd983818451bd4964..1ca7bbc0cc23f98bc94f703846f2a12eb01f0c3a 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 9e6726547d4e053fbfa5b2e1c688e58601199c51..d07588d9f39185fea1d05e894f4beb1b3c82bbba 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 4c9bcb5705a837efd60168c46e1668d8b9875188..3ac47d72ad09f3e2b7e24b91815004736e898cb7 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 ff8216dbd4aeb1aa48bb31476f2d1f5ed8556b4c..ca2366f44191c5cef3839922ad433928fa95dff4 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_ */