Skip to main content
Sign in
Snippets Groups Projects
Commit a45b90cd authored by Janusz Dziedzic's avatar Janusz Dziedzic Committed by Anjan Chanda
Browse files

introduce ACS

parent ee4d6d31
No related branches found
No related tags found
1 merge request!67introduce ACS
Pipeline #37393 failed
......@@ -13,6 +13,7 @@ OBJS = \
cntlr_map.o \
cntlr_tlv.o \
cntlr_cmdu.o \
cntlr_acs.o \
cntlr_map_debug.o \
config.o \
main.o
......
......
/*
* cntlr_acs.c - Auto Channel Selection
*
* Copyright (C) 2021 IOPSYS Software Solutions AB. All rights reserved.
*
*/
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <libubox/blobmsg.h>
#include <libubox/blobmsg_json.h>
#include <libubox/uloop.h>
#include <libubox/ustream.h>
#include <libubox/utils.h>
#include <libubus.h>
#include <uci.h>
#include <easy/easy.h>
#include <timer_impl.h>
#include <cmdu.h>
#include <1905_tlvs.h>
#include <map2.h>
#include <map_module.h>
#include "utils.h"
#include "debug.h"
#include "config.h"
#include "cntlr.h"
#include "allsta.h"
#include "cntlr_map.h"
#include "cntlr_ubus.h"
#include "cntlr_tlv.h"
#include "cntlr_tlv.h"
#include "cntlr_cmdu.h"
#include "cntlr_acs.h"
int cntlr_acs_radio_channel_recalc(struct netif_radio *radio, struct acs_params *params)
{
struct opclass_entry *entry;
struct opclass *opclass;
int chan, pref, reas;
int pref_best = 0;
int i, j;
opclass = &radio->opclass;
dbg("acs radio channel recalc " MACFMT " opclass %d bw %d skip_dfs %d\n", MAC2STR(radio->macaddr),
params->opclass, params->bw, params->skip_dfs);
for (i = 0; i < opclass->opclass_entry_num; i++) {
entry = &opclass->opclass_entry[i];
/* First check if opclass set */
if (params->opclass && params->opclass != entry->opclass)
continue;
/* Next check if bandwidth set */
if (params->bw && params->bw != entry->bw)
continue;
for (j = 0; j < entry->channels_num; j++) {
chan = entry->channels[j].channel;
pref = (entry->channels[j].preference & CHANNEL_PREF_MASK) >> 4;
reas = entry->channels[j].preference & CHANNEL_PREF_REASON;
trace("\tacs check/cmp chan %d pref %d reas %d\n", chan, pref, reas);
/* Always skip disabled channels */
if (reas == CHANNEL_PREF_REASON_DFS_NOP)
continue;
if (reas == CHANNEL_PREF_REASON_REG_DISALLOWED)
continue;
/* Skip DFS channels if requested */
if (params->skip_dfs) {
if (reas == CHANNEL_PREF_REASON_DFS_AVAILABLE ||
reas == CHANNEL_PREF_REASON_DFS_USABLE)
continue;
}
/* Skip non available DFS channels if requested */
if (params->skip_dfs_not_available && reas != CHANNEL_PREF_REASON_DFS_AVAILABLE)
continue;
/* Finally we are here, choose best value */
if (pref > pref_best) {
pref_best = pref;
params->best_channel = chan;
params->best_opclass = entry->opclass;
params->best_bw = entry->bw;
}
}
}
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;
return 0;
}
static bool cntlr_acs_radio_is_bsta_connected(struct netif_radio *radio)
{
struct netif_iface *iface;
list_for_each_entry(iface, &radio->iflist, list) {
/* Check if sta iface connected */
if (iface->type != NETIF_BSTA)
continue;
if (hwaddr_is_zero(iface->upstream_bssid))
continue;
return true;
}
return false;
}
static int cntlr_get_current_acs_params(struct netif_radio *radio, struct acs_params *params)
{
memset(params, 0, sizeof(*params));
if (!radio->cur_opclass.opclass_entry_num)
return -1;
params->opclass = radio->cur_opclass.opclass_entry[0].opclass;
params->bw = radio->cur_opclass.opclass_entry[0].bw;
params->best_channel = radio->cur_opclass.opclass_entry[0].channels[0].channel;
params->best_bw = params->bw;
params->best_opclass = params->opclass;
return 0;
}
void cntlr_acs_node_channel_recalc(struct node *node, bool skip_dfs)
{
struct acs_params cur_acs_params = {};
struct acs_params acs_params = {};
struct netif_radio *radio;
int ret;
acs_params.skip_dfs = skip_dfs;
dbg("acs node channel recalc " MACFMT " skip_dfs %d\n",
MAC2STR(node->alid), acs_params.skip_dfs);
list_for_each_entry(radio, &node->radiolist, list) {
WARN_ON(cntlr_get_current_acs_params(radio, &cur_acs_params));
/* Use current opclass - TODO: if no opclass check 80/40/20 */
acs_params.opclass = cur_acs_params.opclass;
ret = cntlr_acs_radio_channel_recalc(radio, &acs_params);
if (WARN_ON(ret))
continue;
dbg("acs node " MACFMT " radio " MACFMT " new %d/%d opclass %d vs old %d/%d opclass %d\n",
MAC2STR(node->alid), MAC2STR(radio->macaddr), acs_params.best_channel,
acs_params.best_bw, acs_params.best_opclass, cur_acs_params.best_channel,
cur_acs_params.bw, cur_acs_params.opclass);
if (cntlr_acs_radio_is_bsta_connected(radio))
continue;
warn("acs switch to best channel %d/%d\n", acs_params.best_channel, acs_params.best_bw);
ret = cntrl_send_channel_selection(node->cntlr, node->alid,
radio->macaddr,
acs_params.best_channel,
acs_params.best_opclass,
15);
if (ret)
warn("acs switch failed\n");
}
}
/*
* cntlr_acs.c - Auto Channel Selection header
*
* Copyright (C) 2021 IOPSYS Software Solutions AB. All rights reserved.
*
*/
#ifndef CNTLR_ACS_
#define CNTLR_ACS_
struct acs_params {
int opclass;
int bw;
bool skip_dfs;
bool skip_dfs_not_available;
int best_channel;
int best_opclass;
int best_bw;
};
int cntlr_acs_radio_channel_recalc(struct netif_radio *radio, struct acs_params *params);
void cntlr_acs_node_channel_recalc(struct node *node, bool skip_dfs);
#endif
......@@ -720,6 +720,32 @@ int cntrl_send_channel_preference_query(struct controller *c, uint8_t *agent)
return 0;
}
int cntrl_send_channel_selection(struct controller *c, uint8_t *agent, uint8_t *radio,
uint8_t channel, uint8_t opclass, uint8_t pref)
{
uint16_t mid = 0;
struct cmdu_buff *cmdu;
uint8_t chanlist[1] = {};
chanlist[0] = channel;
cmdu = cmdu_alloc_simple(CMDU_CHANNEL_SELECTION_REQ, &mid);
if (!cmdu)
return -1;
memcpy(cmdu->origin, agent, 6);
if (cntlr_gen_channel_pref(c, cmdu, radio, opclass, ARRAY_SIZE(chanlist), chanlist, pref)) {
cmdu_free(cmdu);
return -1;
}
cmdu_put_eom(cmdu);
send_cmdu(c, cmdu);
cmdu_free(cmdu);
return 0;
}
struct cmdu_buff* cntlr_gen_cac_req(struct controller *c, uint8_t *agent,
int num_data, void *data)
{
......
......
......@@ -73,4 +73,6 @@ struct cmdu_buff *cntlr_gen_client_steer_request(struct controller *c,
struct cmdu_buff *cntlr_gen_comb_infra_metrics_query(struct controller *c,
uint8_t *origin, uint8_t *bssid_mac);
int cntrl_send_channel_preference_query(struct controller *c, uint8_t *agent);
int cntrl_send_channel_selection(struct controller *c, uint8_t *agent, uint8_t *radio,
uint8_t channel, uint8_t opclass, uint8_t pref);
#endif
......@@ -38,6 +38,8 @@
#include "cntlr_tlv.h"
#include "cntlr_cmdu.h"
#include "cntlr_acs.h"
#define MULTICAST_ADDR_STR "01:80:c2:00:00:13"
enum {
......@@ -76,6 +78,17 @@ static const struct blobmsg_policy channel_pref_policy_params[__CHANNEL_PREF_POL
[CHANNEL_PREF_POLICY_AGENT] = { .name = "agent", .type = BLOBMSG_TYPE_STRING }
};
enum {
CHANNEL_RECALC_POLICY_AGENT,
CHANNEL_RECALC_POLICY_SKIP_DFS,
__CHANNEL_RECALC_POLICY_MAX,
};
static const struct blobmsg_policy channel_recalc_policy_params[__CHANNEL_RECALC_POLICY_MAX] = {
[CHANNEL_RECALC_POLICY_AGENT] = { .name = "agent", .type = BLOBMSG_TYPE_STRING },
[CHANNEL_RECALC_POLICY_SKIP_DFS] = { .name = "skip_dfs", .type = BLOBMSG_TYPE_BOOL },
};
enum {
CHANNEL_SEL_POLICY_AGENT,
CHANNEL_SEL_POLICY_RADIO_ID,
......@@ -853,6 +866,38 @@ error:
return UBUS_STATUS_UNKNOWN_ERROR;
}
static int cntlr_channel_recalc(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
struct blob_attr *tb[__CHANNEL_RECALC_POLICY_MAX];
struct controller *c = container_of(obj, struct controller, obj);
char alidstr[18] = {};
char *agent = NULL;
bool skip_dfs = 0;
struct node *n;
blobmsg_parse(channel_recalc_policy_params, __CHANNEL_RECALC_POLICY_MAX, tb,
blob_data(msg), blob_len(msg));
if (tb[CHANNEL_RECALC_POLICY_AGENT])
agent = blobmsg_data(tb[CHANNEL_RECALC_POLICY_AGENT]);
if (tb[CHANNEL_RECALC_POLICY_SKIP_DFS])
skip_dfs = blobmsg_data(tb[CHANNEL_RECALC_POLICY_SKIP_DFS]);
list_for_each_entry(n, &c->nodelist, list) {
hwaddr_ntoa(n->alid, alidstr);
if (agent && strcmp(agent, alidstr))
continue;
cntlr_acs_node_channel_recalc(n, skip_dfs);
}
return UBUS_STATUS_OK;
}
static int cntlr_channel_select(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
......@@ -2712,6 +2757,8 @@ int cntlr_publish_object(struct controller *c, const char *objname)
sta_caps_policy_params),
UBUS_METHOD("channel_pref", cntlr_channel_pref,
channel_pref_policy_params),
UBUS_METHOD("channel_recalc", cntlr_channel_recalc,
channel_recalc_policy_params),
UBUS_METHOD("bk_steer", cntlr_bk_steer, bk_steer_policy_params),
UBUS_METHOD("agent_policy", cntlr_ap_policy_config,
ap_policy_config_params),
......
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment