diff --git a/src/cntlr_acs.c b/src/cntlr_acs.c index be4d5d1c2d27345640f4090d78a81e372907047d..9fc916ae448c963e9ab27a33437343f36e06d31d 100644 --- a/src/cntlr_acs.c +++ b/src/cntlr_acs.c @@ -38,11 +38,15 @@ int cntlr_acs_radio_channel_recalc(struct netif_radio *radio, struct acs_params *params) { + struct acs_params acs_params[64] = {}; + int acs_params_num = 0; struct opclass_entry *entry; struct opclass *opclass; int chan, pref, reas; int pref_best = 0; - int i, j; + int pref_cur = 0; + int prefered[64] = {0}; + int i, j, r; opclass = &radio->opclass; @@ -84,23 +88,69 @@ int cntlr_acs_radio_channel_recalc(struct netif_radio *radio, struct acs_params if (params->skip_dfs_not_available && reas != CHANNEL_PREF_REASON_DFS_AVAILABLE) continue; - /* Finally we are here, choose best value */ - if (pref > pref_best) { + if (WARN_ON(acs_params_num >= ARRAY_SIZE(acs_params))) + break; + + /* Current channel preference */ + if (chan == params->best_channel) + pref_cur = pref; + + /* Kick best value */ + if (pref > pref_best) pref_best = pref; - params->best_channel = chan; - params->best_opclass = entry->opclass; - params->best_bw = entry->bw; - } + acs_params[acs_params_num].best_channel = chan; + acs_params[acs_params_num].best_opclass = entry->opclass; + acs_params[acs_params_num].best_bw = entry->bw; + acs_params[acs_params_num].best_pref = pref; + + acs_params_num++; } } - dbg("acs radio " MACFMT " best chan %d/%d opclass %d\n", MAC2STR(radio->macaddr), - params->best_channel, params->best_bw, params->best_opclass); - if (!pref_best) return -1; + dbg("acs radio " MACFMT " best pref %d vs current pref %d\n", MAC2STR(radio->macaddr), pref_best, pref_cur); + + /* If current channel equal to best don't switch */ + if (pref_cur == pref_best) { + dbg("acs skip - current channel %d is the best\n", params->best_channel); + return -1; + } + + /* Get random channel from best performance */ + for (i = 0, j = 0; i < acs_params_num; i++) { + if (acs_params[i].best_pref != pref_best) + continue; + + if (j >= ARRAY_SIZE(prefered) - 1) + break; + + /* Save index in table */ + prefered[j] = i; + j++; + } + + if (WARN_ON(!j)) + return -1; + + srand(time(NULL)); + r = rand() % j; + + dbg("acs radio " MACFMT " table size %d - rand %d, index %d\n", + MAC2STR(radio->macaddr), j, r, prefered[r]); + + if (prefered[r] >= acs_params_num) + return -1; + + params->best_channel = acs_params[prefered[r]].best_channel; + params->best_bw = acs_params[prefered[r]].best_bw; + params->best_opclass = acs_params[prefered[r]].best_opclass; + + dbg("acs radio " MACFMT " best chan %d/%d opclass %d\n", MAC2STR(radio->macaddr), + params->best_channel, params->best_bw, params->best_opclass); + return 0; } @@ -155,6 +205,7 @@ void cntlr_acs_node_channel_recalc(struct node *node, bool skip_dfs) /* Use current opclass - TODO: if no opclass check 80/40/20 */ acs_params.opclass = cur_acs_params.opclass; + acs_params.best_channel = cur_acs_params.best_channel; ret = cntlr_acs_radio_channel_recalc(radio, &acs_params); if (WARN_ON(ret)) diff --git a/src/cntlr_acs.h b/src/cntlr_acs.h index fb1aec3c318cb1d18752c584d4120461c780e88d..a478810041c7a00e1114c1e817c432a237293a20 100644 --- a/src/cntlr_acs.h +++ b/src/cntlr_acs.h @@ -17,6 +17,7 @@ struct acs_params { int best_channel; int best_opclass; int best_bw; + int best_pref; }; int cntlr_acs_radio_channel_recalc(struct netif_radio *radio, struct acs_params *params);