Newer
Older
l = cntlr_find_link(c, upstream, downstream);
if (l)
return l;
l = calloc(1, sizeof(struct netif_link));
if (!l)
return NULL;
l->metrics = calloc(1, sizeof(struct link_metrics));
if (!l->metrics)
l->upstream = cntlr_find_iface(c, upstream);
l->downstream = cntlr_find_iface(c, downstream);
trace("Adding link | " MACFMT " <---> " MACFMT " |\n",
MAC2STR(l->upstream->bss->bssid),
MAC2STR(l->downstream->bss->bssid));
list_add(&l->list, &c->linklist);
return l;
out_metrics:
free(l->metrics);
out:
free(l);
static void cntlr_radar_exit(atimer_t *t)
{
/*TODO: before change channel due to radar, save old chandef.
* Restore that chandef upon exit from radar nop.
*/
}
static void cntlr_ieee1905_cmdu_event_handler(void *cntlr,
struct blob_attr *msg)
static const struct blobmsg_policy cmdu_attrs[6] = {
[0] = { .name = "type", .type = BLOBMSG_TYPE_INT16 },
[1] = { .name = "mid", .type = BLOBMSG_TYPE_INT16 },
[2] = { .name = "ifname", .type = BLOBMSG_TYPE_STRING },
[3] = { .name = "source", .type = BLOBMSG_TYPE_STRING },
[4] = { .name = "origin", .type = BLOBMSG_TYPE_STRING },
[5] = { .name = "cmdu", .type = BLOBMSG_TYPE_STRING },
struct controller *c = (struct controller *)cntlr;
char in_ifname[16] = {0};
struct blob_attr *tb[6];
char src[18] = { 0 }, src_origin[18] = { 0 };
uint8_t *tlv = NULL;
char *tlvstr = NULL;
uint16_t type;
uint8_t srcmac[6], origin[6];
uint16_t mid = 0;
int len = 0;
sigset_t waiting_mask;
sigpending(&waiting_mask);
if (sigismember(&waiting_mask, SIGINT) ||
sigismember(&waiting_mask, SIGTERM))
return;
blobmsg_parse(cmdu_attrs, 6, tb, blob_data(msg), blob_len(msg));
if (!tb[0] || !tb[1])
return;
if (tb[0]) {
int t;
t = blobmsg_get_u16(tb[0]);
if (t < 0)
return;
type = (uint16_t)t;
if (!is_cmdu_for_us(c, type))
return;
}
if (tb[1])
mid = (uint16_t)blobmsg_get_u16(tb[1]);
strncpy(in_ifname, blobmsg_data(tb[2]), 15);
if (tb[3]) {
strncpy(src, blobmsg_data(tb[3]), 17);
hwaddr_aton(src, srcmac);
}
if (tb[4]) {
strncpy(src_origin, blobmsg_data(tb[4]), 17);
hwaddr_aton(src_origin, origin);
}
if (tb[5]) {
len = blobmsg_data_len(tb[5]) - 16;
tlvstr = calloc(1, len + 1);
if (!tlvstr)
return;
strncpy(tlvstr, (blobmsg_data(tb[5]) + 16), len);
len = (len - 1) / 2;
tlv = calloc(1, len);
if (!tlv) {
free(tlvstr);
return;
strtob(tlvstr, len, tlv);
free(tlvstr);
cntlr_handle_map_event(c, type, mid, in_ifname, srcmac, origin, tlv, len);
if (tlv)
free(tlv);
static void cntlr_query_nodes(atimer_t *t)
{
struct controller *c = container_of(t, struct controller, query_nodes);
struct node *n = NULL;
list_for_each_entry(n, &c->nodelist, list) {
struct cmdu_buff *cmdu;
cmdu = cntlr_gen_bk_caps_query(c, n->almacaddr);
if (cmdu) {
send_cmdu(c, cmdu);
cmdu_free(cmdu);
}
cmdu = cntlr_gen_ap_capability_query(c, n->almacaddr);
if (cmdu) {
send_cmdu(c, cmdu);
cmdu_free(cmdu);
}
cmdu = cntlr_gen_topology_query(c, n->almacaddr);
if (cmdu) {
send_cmdu(c, cmdu);
cmdu_free(cmdu);
}
}
timer_set(&c->query_nodes, 60 * 1000);
bool cntlr_check_config_diff(struct controller *c, uint32_t diff)
{
bool reloaded = false;
if (diff & CONFIG_DIFF_CREDENTIALS || diff & CONFIG_DIFF_VLAN) {
struct cmdu_buff *cmdu;
uint8_t origin[6] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x13};
trace("Config changed, triggering renew!\n");
cmdu = cntlr_gen_ap_autoconfig_renew(c, origin);
if (cmdu) {
send_cmdu(c, cmdu);
cmdu_free(cmdu);
reloaded = true;
}
} else if (diff & (CONFIG_DIFF_AGENT_POLICY | CONFIG_DIFF_AGENT_POLICY_CNT)) {
struct node_policy *p = NULL;
trace("agent policy config changed\n");
/* send the policy config cmdu to the marked agent */
list_for_each_entry(n, &c->nodelist, list) {
struct cmdu_buff *cmdu;
int num_bk = 0;
uint8_t bk_id[16 * 6] = {0};
int num_radio = 0;
if ((diff & CONFIG_DIFF_AGENT_POLICY) && !n->np->is_policy_diff)
continue;
list_for_each_entry(r, &n->radiolist, list) {
struct netif_iface *iface = NULL;
memcpy(&radio_id[num_radio * 6],
num_radio++;
list_for_each_entry(iface, &r->iflist, list) {
if (!iface->bss->is_bbss)
continue;
memcpy(&bk_id[num_bk * 6],
iface->bss->bssid, 6);
num_bk++;
}
}
cmdu = cntlr_gen_policy_config_req(c, n->almacaddr,
n->np, num_radio, radio_id, num_bk,
bk_id);
if (cmdu) {
send_cmdu(c, cmdu);
cmdu_free(cmdu);
reloaded = true;
}
}
/* reset is_policy_diff to false; */
p->is_policy_diff = false;
}
#if (EASYMESH_VERSION > 2)
if ((diff & CONFIG_DIFF_QOS) && c->cfg.qos.enabled) {
struct node *n = NULL;
/* send the policy config cmdu to the marked agent */
list_for_each_entry(n, &c->nodelist, list) {
cntlr_qos_sync_node(c, n->almacaddr);
#if (EASYMESH_VERSION >= 6)
if ((diff & CONFIG_DIFF_AP_MLD) || (diff & CONFIG_DIFF_PUNCT_BITMAP)) {
struct node *n = NULL;
trace("ap mld config changed\n");
/* send the ap mld config cmdu to the agent */
list_for_each_entry(n, &c->nodelist, list)
cntlr_send_ap_mld_configuration_request(c, n);
}
if (diff & CONFIG_DIFF_BSTA_MLD) {
struct node *n = NULL;
trace("bsta mld config changed\n");
/* send the ap mld config cmdu to the agent */
list_for_each_entry(n, &c->nodelist, list)
cntlr_send_bsta_mld_configuration_request(c, n);
}
return reloaded;
}
#ifdef CONTROLLER_SYNC_DYNAMIC_CNTLR_CONFIG
int cntlr_sync_dyn_controller_config(struct controller *c, uint8_t *agent)
{
struct node *n = NULL;
uint8_t proto = 0xab;
struct cmdu_buff *cmdu;
if (agent && !hwaddr_is_zero(agent)) {
cmdu = cntlr_gen_higher_layer_data(c, agent, proto, NULL, 0);
if (!cmdu)
return -1;
send_cmdu(c, cmdu);
cmdu_free(cmdu);
} else {
list_for_each_entry(n, &c->nodelist, list) {
if (hwaddr_equal(c->almacaddr, n->almacaddr))
continue; /* skip locally running agent */
cmdu = cntlr_gen_higher_layer_data(c, n->almacaddr, proto, NULL, 0);
if (!cmdu)
return -1;
send_cmdu(c, cmdu);
cmdu_free(cmdu);
}
}
return 0;
}
bool cntlr_resync_config(struct controller *c, bool reload)
diff = cntlr_config_reload(&c->cfg);
list_for_each_entry(np, &c->cfg.nodelist, list) {
struct node *n;
if (n)
n->np = np;
if (reload)
cntlr_check_config_diff(c, diff);
#ifdef CONTROLLER_SYNC_DYNAMIC_CNTLR_CONFIG
/* in dyn-controller mode, sync controller's config in network */
if (diff)
cntlr_sync_dyn_controller_config(c, NULL);
return !!diff;
static void cntlr_signal_periodic_run(atimer_t *t)
{
struct controller *c = container_of(t, struct controller, signal_handler);
sigset_t waiting_mask;
sigpending(&waiting_mask);
if (sigismember(&waiting_mask, SIGHUP)) {
cntlr_dbg(LOG_TIMER, "|%s:%d| Received SIGHUP, reload config\n", __func__, __LINE__);
signal(SIGHUP, SIG_IGN);
cntlr_resync_config(c, true);
cntlr_dbg(LOG_TIMER, "%s --->\n", __func__);
timer_set(&c->signal_handler, 1 * 1000);
static void cntlr_ageout_nodes(struct controller *c)
{
struct node *n = NULL, *tmp;
struct netif_radio *r = NULL, *temp;
trace("%s: --->\n", __func__);
/* Here we need to see that all nodes in nodelist */
/* and check there timestamp */
list_for_each_entry_safe(n, tmp, &c->nodelist, list) {
if (timestamp_expired(&n->last_tsp_seen, NODE_EXPIRE_TIME * 1000)) {
list_for_each_entry_safe(r, temp, &n->radiolist, list) {
cntlr_config_del_radio(n->almacaddr);
cntlr_config_del_node(n->almacaddr);
topology_remove_device(&c->topology, n->almacaddr);
cntlr_clean_radiolist(c, n);
mactable_del_entry(c->mac_table, n->almacaddr, MAC_ENTRY_ALID);
list_del(&n->list);
free(n);
if (c->num_nodes > 0)
c->num_nodes--;
}
}
}
static void cntlr_renew_nodes_configuration(struct controller *c)
{
trace("%s: --->\n", __func__);
struct node *node = NULL;
/* When at least one running node was configured with older config, */
/* send autoconfig renew */
list_for_each_entry(node, &c->nodelist, list) {
if (!timestamp_invalid(&node->last_config) &&
timestamp_less_than(&node->last_config, &c->cfg.last_change) &&
timestamp_greater_than(&node->last_cmdu, &c->cfg.last_change)) {
uint8_t multicast_addr[6] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x13};
struct cmdu_buff *cmdu =
cntlr_gen_ap_autoconfig_renew(c, multicast_addr);
dbg("Found possibly unconfigured node: "MACFMT"\n", MAC2STR(node->almacaddr));
if (cmdu) {
dbg("Sending AP_AUTOCONFIGURATION_RENEW\n");
send_cmdu(c, cmdu);
cmdu_free(cmdu);
}
break;
}
#if (EASYMESH_VERSION >= 6)
else if (timestamp_less_than(&node->last_apmld_ack, &c->cfg.last_apmld_change) &&
timestamp_greater_than(&node->last_cmdu, &c->cfg.last_apmld_change)) {
dbg("Found possibly unconfigured AP MLD node: "MACFMT"\n", MAC2STR(node->almacaddr));
cntlr_send_ap_mld_configuration_request(c, node);
} else if (timestamp_less_than(&node->last_bstamld_ack, &c->cfg.last_bstamld_change) &&
timestamp_greater_than(&node->last_cmdu, &c->cfg.last_bstamld_change)) {
dbg("Found possibly unconfigured BSTA MLD node: "MACFMT"\n", MAC2STR(node->almacaddr));
cntlr_send_bsta_mld_configuration_request(c, node);
}
#endif
static void combined_link_metric_periodic_collection(struct controller *c)
{
trace("%s: --->\n", __func__);
uint8_t *radiolist = NULL, *bsslist = NULL;
struct cmdu_buff *cmdu;
struct node *n = NULL;
/* AP metrics query for each agent */
/* For each agent */
list_for_each_entry(n, &c->nodelist, list) {
uint8_t *new_radiolist;
struct netif_radio *r = NULL;
int num_bss = 0, num_radio = 0;
uint8_t hwaddr[6];
num_radio = 0;
num_bss = 0;
memcpy(hwaddr, n->almacaddr, 6);
list_for_each_entry(r, &n->radiolist, list) {
struct netif_iface *bss = NULL;
int radio_index;
/* Building a radiolist of all radios */
new_radiolist = (uint8_t *)realloc(radiolist,
6 * (num_radio + 1) * sizeof(uint8_t));
if (!new_radiolist) {
trace("realloc of radiolist failed\n");
radiolist = new_radiolist;
num_radio++;
radio_index = (num_radio - 1) * 6;
memcpy(radiolist + radio_index, r->radio_el->macaddr, 6);
list_for_each_entry(bss, &r->iflist, list) {
int bss_index;
uint8_t *new_bsslist;
if (!bss->bss->is_fbss && !bss->bss->is_bbss)
/* if bss is a bsta */
/* Building a bsslist of all BSS */
new_bsslist = (uint8_t *)realloc(bsslist,
6 * (num_bss + 1) * sizeof(uint8_t));
if (!new_bsslist) {
trace("realloc of bsslist failed\n");
bsslist = new_bsslist;
num_bss++;
bss_index = (num_bss - 1) * 6;
memcpy(bsslist + bss_index, bss->bss->bssid, 6);
if (num_bss > 0) {
cmdu = cntlr_gen_ap_metrics_query(c, hwaddr, num_bss, bsslist, num_radio, radiolist);
if (!cmdu) {
trace("cmdu cntlr_gen_ap_metrics_query failed!\n");
goto error;
}
send_cmdu(c, cmdu);
cmdu_free(cmdu);
} else {
dbg("Skip sending AP metrics query, no BSS to query\n");
}
cmdu = cntlr_gen_1905_link_metric_query(c, n->almacaddr);
if (!cmdu) {
trace("cmdu cntlr_gen_1905_link_metric_query failed!\n");
goto error;
}
send_cmdu(c, cmdu);
cmdu_free(cmdu);
}
/* query i1905d base CMDU */
cmdu = ieee1905_ubus_buildcmdu(c->ubus_ctx, CMDU_TYPE_LINK_METRIC_RESPONSE);
if (!cmdu)
dbg("No response from stack when generating 0x%04x\n",
CMDU_TYPE_LINK_METRIC_RESPONSE);
n = cntlr_find_node(c, c->almacaddr);
handle_link_metrics_response(c, cmdu, n);
cmdu_free(cmdu);
error:
if (radiolist)
free(radiolist);
if (bsslist)
free(bsslist);
static void cntlr_metric_collection(struct controller *c)
//forall_node_get_fhinfo(c); /* replaced from per-node refresh bss */
cntlr_get_all_sta_metrics(c);
/* TODO: */
//forall_node_get_usta_metrics(c);
//forall_node_update_neighbors(c);
/* Call AP metrics query and 1905 link metrics query for data collection */
combined_link_metric_periodic_collection(c);
cntlr_renew_nodes_configuration(c);
static void cntlr_acs_run(atimer_t *t)
{
struct controller *c = container_of(t, struct controller, acs);
/* Run ACS recalc here */
dbg("acs timeout - run recalc\n");
timer_set(&c->acs, c->cfg.acs_timeout * 1000);
static void cntlr_steer_sched_run(atimer_t *t)
{
struct controller *c = container_of(t, struct controller, steer_sched_timer);
int i;
cntlr_dbg(LOG_STEER, "%s: --->\n", __func__);
for (i = 0; i < c->inform_sta_num; i++) {
struct sta *s = cntlr_find_sta(c->sta_table, &c->inform_stalist[i * 6]);
if (!s)
continue;
if (c->cfg.steer.enable_sta_steer && !s->is_bsta)
cntlr_inform_steer_modules(c, s, c->inform_cmdu_type);
else if (c->cfg.steer.enable_bsta_steer && s->is_bsta)
cntlr_inform_bsteer_modules(c, s, c->inform_cmdu_type);
}
}
static void cntlr_start(atimer_t *t)
{
struct controller *c = container_of(t, struct controller, start_timer);
if (c->state == CNTLR_INIT) {
c->state = CNTLR_START;
cntlr_publish_object(c, "map.controller");
//cntlr_publish_dbg_object(c, "map.controller.dbg"); //TODO: open
static void cntlr_discovery(atimer_t *t)
{
struct controller *c = container_of(t, struct controller, discovery_timer);
struct cmdu_buff *cmdu;
cmdu = cntlr_gen_ap_autoconfig_search(c, 0x02, 0x00);
if (!cmdu)
return;
c->mid_2g = send_cmdu(c, cmdu);
cmdu = cntlr_gen_ap_autoconfig_search(c, 0x02, 0x01);
if (!cmdu)
return;
c->mid_5g = send_cmdu(c, cmdu);
int cntlr_map_sub_cb(void *bus, void *priv, void *data)
struct blob_attr *msg = (struct blob_attr *)data;
char *str;
str = blobmsg_format_json(msg, true);
trace("Received notification '%s'\n", str);
cntlr_ieee1905_cmdu_event_handler(priv, msg);
return 0;
}
int cntlr_map_del_cb(void *bus, void *priv, void *data)
struct controller *c = (struct controller *)priv;
uint32_t *obj = (uint32_t *)data;
c->subscribed = false;
fprintf(stdout, "Object 0x%x no longer present\n", *obj);
static int cntlr_subscribe_for_cmdus(struct controller *c)
mapmodule_cmdu_mask_t cmdu_mask = {0};
map_prepare_cmdu_mask(cmdu_mask,
CMDU_TYPE_TOPOLOGY_DISCOVERY,
CMDU_TYPE_TOPOLOGY_NOTIFICATION,
CMDU_TYPE_TOPOLOGY_QUERY,
CMDU_TYPE_TOPOLOGY_RESPONSE,
CMDU_TYPE_VENDOR_SPECIFIC,
CMDU_TYPE_AP_AUTOCONFIGURATION_SEARCH,
CMDU_TYPE_AP_AUTOCONFIGURATION_RESPONSE,
CMDU_TYPE_AP_AUTOCONFIGURATION_WSC,
CMDU_1905_ACK,
CMDU_BEACON_METRICS_RESPONSE,
CMDU_AP_METRICS_RESPONSE,
CMDU_ASSOC_STA_LINK_METRICS_RESPONSE,
CMDU_UNASSOC_STA_LINK_METRIC_RESPONSE,
CMDU_CHANNEL_SCAN_REQUEST,
CMDU_CHANNEL_SCAN_REPORT,
CMDU_CLIENT_DISASSOCIATION_STATS,
CMDU_ASSOCIATION_STATUS_NOTIFICATION,
CMDU_BACKHAUL_STA_CAPABILITY_QUERY,
CMDU_BACKHAUL_STA_CAPABILITY_REPORT,
CMDU_CHANNEL_PREFERENCE_REPORT,
CMDU_CLIENT_STEERING_BTM_REPORT,
CMDU_STEERING_COMPLETED,
CMDU_CHANNEL_SELECTION_RESPONSE,
CMDU_OPERATING_CHANNEL_REPORT,
CMDU_AP_CAPABILITY_QUERY,
CMDU_AP_CAPABILITY_REPORT,
CMDU_CLIENT_CAPABILITY_REPORT,
CMDU_BACKHAUL_STEER_RESPONSE,
#if (EASYMESH_VERSION > 2)
CMDU_BSS_CONFIG_REQUEST,
CMDU_BSS_CONFIG_RESULT,
CMDU_CHIRP_NOTIFICATION,
#endif
#if (EASYMESH_VERSION > 5)
CMDU_EARLY_AP_CAPABILITY_REPORT,
memcpy(c->cmdu_mask, cmdu_mask, sizeof(c->cmdu_mask));
trace("%s: wait for map-plugin\n", __func__);
cntlr_wait_for_object_timeout(c, map_plugin, -1, &map_id);
c->map_oid = map_id;
/* register as client to the map module */
ret = map_subscribe(c->ubus_ctx,
&c->map_oid,
"mapcontroller", &cmdu_mask, c,
cntlr_map_sub_cb,
cntlr_map_del_cb,
&c->subscriber);
if (!ret) {
c->subscribed = true;
} else {
trace("Failed to 'register' with %s (err = %s)\n",
map_plugin, ubus_strerror(ret));
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
static int cntlr_ackq_timeout_cb(struct cmdu_ackq *q, struct cmdu_ackq_entry *e)
{
struct controller *a = container_of(q, struct controller, cmdu_ack_q);
struct cmdu_buff *cmdu = (struct cmdu_buff *) e->cookie;
int ret;
trace("%s: ---> cmdu = %04x to "MACFMT" \n", __func__,
cmdu_get_type(cmdu), MAC2STR(cmdu->origin));
if (e->resend_cnt-- > 0) {
ret = send_cmdu_ubus(a, cmdu);
if (ret < 0)
err("%s fail to send cmdu\n", __func__);
return CMDU_ACKQ_TMO_REARM;
}
return CMDU_ACKQ_TMO_DELETE;
}
static void cntlr_ackq_delete_cb(struct cmdu_ackq *q, struct cmdu_ackq_entry *e)
{
struct cmdu_buff *cmdu = (struct cmdu_buff *) e->cookie;
trace("%s: ---> cmdu = %04x to "MACFMT" \n", __func__,
cmdu_get_type(cmdu), MAC2STR(cmdu->origin));
cmdu_free(cmdu);
}
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
static void uobj_add_event_handler(void *cntlr, struct blob_attr *msg)
{
char path[32] = {0};
uint32_t id = 0;
struct controller *c = (struct controller *) cntlr;
struct blob_attr *tb[2];
static const struct blobmsg_policy ev_attr[2] = {
[0] = { .name = "id", .type = BLOBMSG_TYPE_INT32 },
[1] = { .name = "path", .type = BLOBMSG_TYPE_STRING }
};
blobmsg_parse(ev_attr, 2, tb, blob_data(msg), blob_len(msg));
if (!tb[0] || !tb[1])
return;
strncpy(path, blobmsg_data(tb[1]), sizeof(path) - 1);
id = (uint32_t) blobmsg_get_u32(tb[0]);
dbg("|%s:%d| path = [%s] id = [%d] [%u]\n", __func__, __LINE__, path,
id, id);
if (!strncmp(path, map_plugin, strlen(map_plugin))) {
/* TODO: how to handle failure? */
cntlr_subscribe_for_cmdus(c);
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
}
}
static void cntlr_event_handler(struct ubus_context *ctx,
struct ubus_event_handler *ev,
const char *type, struct blob_attr *msg)
{
int i;
char *str;
struct controller *c = container_of(ev, struct controller, evh);
struct wifi_ev_handler {
const char *ev_type;
void (*handler)(void *ctx, struct blob_attr *ev_data);
} evs[] = {
{ "ubus.object.add", uobj_add_event_handler }
};
str = blobmsg_format_json(msg, true);
if (!str)
return;
info("[ &controller = %p ] Received [event = %s] [val = %s]\n",
c, type, str);
for (i = 0; i < ARRAY_SIZE(evs); i++) {
if (!strcmp(type, evs[i].ev_type))
evs[i].handler(c, msg);
}
free(str);
}
static void cntlr_periodic_run(atimer_t *t)
{
struct controller *c = container_of(t, struct controller, heartbeat);
c->uptime += 1;
cntlr_dbg(LOG_TIMER, "|%s:%d| periodic time (elapsed:%"PRIu64")\n",
__func__, __LINE__, c->uptime);
if ((c->uptime % METRIC_REP_INTERVAL) == 0)
cntlr_metric_collection(c);
#if 1 //TODO: move from here
if (c->uptime % 7 == 0) {
struct node *n = NULL;
list_for_each_entry(n, &c->nodelist, list) {
uint32_t est_thput = cntlr_estimate_max_throughput_for_node(c, n->almacaddr);
cntlr_info(LOG_DEFAULT, "** Node = " MACFMT ": est-throughput = %d\n",
MAC2STR(n->almacaddr), est_thput);
n->est_thput_dl = est_thput;
}
}
#endif
cntlr_ageout_nodes(c);
timer_set(&c->heartbeat, 1 * 1000);
}
struct log_options *lopts = (struct log_options *)opts;
sigset_t base_mask;
sigemptyset(&base_mask);
sigaddset(&base_mask, SIGHUP);
sigprocmask(SIG_SETMASK, &base_mask, NULL);
set_sighandler(SIGPIPE, SIG_IGN);
c = calloc(1, sizeof(struct controller));
if (!c)
memcpy(&c->log, lopts, sizeof(*lopts));
restart_logging(&c->log);
cntlr_info(LOG_MISC,
"Starting Controller build %s %s, EasyMesh ver%d.\n",
__DATE__, __TIME__, EASYMESH_VERSION);
cntlr_dbg(LOG_MISC, "%s: cntlr = %p\n", __func__, c);
uloop_init();
ctx = ubus_connect(ubus_socket);
if (!ctx) {
err("Failed to connect to ubus\n");
free(c);
}
c->ubus_ctx = ctx;
INIT_LIST_HEAD(&c->nodelist);
INIT_LIST_HEAD(&c->bcnreqlist);
c->num_nodes = 0;
INIT_LIST_HEAD(&c->linklist);
INIT_LIST_HEAD(&c->sclist);
init_topology(&c->topology);
cmdu_ackq_init(&c->cmdu_ack_q);
c->cmdu_ack_q.timeout_cb = cntlr_ackq_timeout_cb;
c->cmdu_ack_q.delete_cb = cntlr_ackq_delete_cb;
ubus_add_uloop(ctx);
#if (EASYMESH_VERSION > 2)
{
char *argv[] = {"-I", "-C", "-V", "2"};
int argc = 4;
int ret;
ret = dpp_init(&c->dpp, argc, argv);
if (ret) {
cntlr_dbg(LOG_DPP, "Failed to init dpp context\n");
goto out_exit;
}
dpp_register_cb(c->dpp, dpp_frame_handler);
dpp_set_ctx_private_data(c->dpp, c);
cntlr_config_defaults(c, &c->cfg);
ret = cntlr_get_ieee1905_almac(c, c->almacaddr);
if (ret)
goto out_exit;
memcpy(c->cfg.id, c->almacaddr, 6);
cntlr_resync_config(c, false);
if (!c->cfg.enabled)
goto out_exit;
/* diff always 1 after first round, will cause failures on
* first reload if not un-set
*/
struct node_policy *np = NULL;
list_for_each_entry(np, &c->cfg.nodelist, list) {
struct node *n;
np->is_policy_diff = false;
n = cntlr_add_node(c, np->agent_id);
if (!n)
goto out_exit;
n->np = np;
c->state = CNTLR_INIT;
timer_init(&c->discovery_timer, cntlr_discovery);
timer_init(&c->start_timer, cntlr_start);
timer_init(&c->heartbeat, cntlr_periodic_run);
timer_init(&c->radar_timer, cntlr_radar_exit);
timer_init(&c->signal_handler, cntlr_signal_periodic_run);
timer_init(&c->query_nodes, cntlr_query_nodes);
timer_init(&c->acs, cntlr_acs_run);
timer_init(&c->steer_sched_timer, cntlr_steer_sched_run);
timer_set(&c->heartbeat, 1 * 1000);
timer_set(&c->start_timer, waitext ? 5 * 1000 : 0);
timer_set(&c->discovery_timer, 0);
timer_set(&c->signal_handler, 5 * 1000);
timer_set(&c->query_nodes, 60 * 1000);
timer_set(&c->acs, c->cfg.acs_timeout * 1000);
c->evh.cb = cntlr_event_handler;
ubus_register_event_handler(ctx, &c->evh, "ubus.object.*");
cntlr_subscribe_for_cmdus(c);
/* The counters in MultiAPSteeringSummaryStats are all reset on reboot. */
memset(&c->dlem.network.steer_summary, 0, sizeof(struct wifi_steer_summary));
cntlr_dbg(LOG_MISC, "current wifi_cntlr profile %d\n", c->cfg.map_profile);
#if (EASYMESH_VERSION > 2)
#ifdef USE_LIBDPP
err("free dpp!!\n");
dpp_free(c->dpp);
#endif
#endif
cntlr_unload_steer_modules(c);
cntlr_clean_mac_hashtable(c);
cntlr_clean_bcnreqlist(c);
cntlr_clean_linklist(c);
free_topology(&c->topology);
ubus_unregister_event_handler(ctx, &c->evh);
//cntlr_remove_dbg_object(c); //TODO
cmdu_ackq_free(&c->cmdu_ack_q);
cntlr_config_clean(&c->cfg);