diff --git a/src/core/agent.c b/src/core/agent.c index 566373d35e0b94b08da72adf590126bef6a9bb35..102528b31cef307cb65161e5a8c5f926201777a8 100644 --- a/src/core/agent.c +++ b/src/core/agent.c @@ -1055,7 +1055,7 @@ static int maybe_steer_sta(struct sta *s, unsigned int *res, struct pref_neighbor **nbr) { struct netif_fh *vif = s->vif; - struct netif_fhcfg *cfg = vif->cfg; + struct agent *a = vif->agent; struct stax *x; /* dbg("%s: vif = %p cfg = %p ifname = %s\n", @@ -1065,7 +1065,7 @@ static int maybe_steer_sta(struct sta *s, unsigned int *res, /* TODO: don't check here .. * flag exclude whenever cfg is updated to exclude a STA. */ - list_for_each_entry(x, &cfg->steer_excludelist, list) { + list_for_each_entry(x, &a->cfg.steer_excludelist, list) { unsigned char xmac[6] = {0}; int m_len; @@ -1272,7 +1272,7 @@ static int wifi_add_sta(struct agent *a, const char *vif, } // TODO: test more thorouhgly and comment back in -// list_for_each_entry(x, &cfg->steer_excludelist, list) { +// list_for_each_entry(x, &a->cfg.steer_excludelist, list) { // unsigned char xmac[6] = {0}; // int m_len; // @@ -3912,33 +3912,25 @@ int wifiagent_process_cmd(struct ubus_context *ctx, { int num = len / 17; int i; - struct netif_fh *n; - - list_for_each_entry(n, &a->fhlist, list) { - struct netif_fhcfg *ncfg = n->cfg; + struct agent_config *cfg = &a->cfg; - if (!n->cfg || !n->cfg->enabled) - continue; + if (!cfg->enabled) + break; - dbg("Cmd '%d': num addresses = %d\n", cmd_id, - num); - for (i = 0; i < num; i++) { - char p[18] = {0}; - - snprintf(p, 18, "%s", &cmd_data[i * 17]); - ret = config_update2("wifiagent", - &a->cfg, - "fh-iface", "ifname", - n->name, - "exclude", add, p, 18); - if (add) - stax_add_entry(&ncfg->steer_excludelist, - p); - else - stax_del_entry(&ncfg->steer_excludelist, - p); - } + dbg("Cmd '%d': num addresses = %d\n", cmd_id, num); + for (i = 0; i < num; i++) { + char p[18] = {0}; + + snprintf(p, 18, "%s", &cmd_data[i * 17]); + ret = config_update("agent", &a->cfg, + "wifiagent", "exclude", + add, p, 18); + if (add) + stax_add_entry(&cfg->steer_excludelist, p); + else + stax_del_entry(&cfg->steer_excludelist, p); } + } break; case CMD_STEER: diff --git a/src/core/agent.h b/src/core/agent.h index 599608b9f5b8697085e409a39f540776ef62328b..92eb344bafa106f7dba18d9bbc64dfdbab7567a4 100644 --- a/src/core/agent.h +++ b/src/core/agent.h @@ -167,6 +167,13 @@ struct netif_fh { struct uloop_timeout rdr_timer; /** radar nop timer */ struct uloop_timeout nbr_timer; /** refresh neighbor list timer */ struct uloop_timeout bss_timer; /** refresh own bss timer */ + + /* Channel utilization threshold timer */ + struct uloop_timeout util_threshold_timer; + + /* STA Metrics Reporting RCPI Threshold timer */ + struct uloop_timeout rcpi_threshold_timer; + struct list_head restrict_stalist; /* list of restrict_sta_entry */ struct list_head nbrlist; int nbr_nr; @@ -181,6 +188,12 @@ struct netif_fh { uint8_t tx_spatial_streams; struct wifi_caps_element caps; + + /* previous rcpi threshold value */ + uint8_t prev_rcpi; + + /* previous channel utilization threshold value */ + uint8_t prev_util; }; /* backhaul wifi (sta) interface */ @@ -458,5 +471,7 @@ extern int plugins_load(int argc, char *argv[], struct list_head *plugins); extern int plugins_unload(struct list_head *plugins); struct netif_fh *wifi_radio_to_ap(struct agent *a, const char *radio); +struct wifi_radio_element *wifi_ifname_to_radio_element(struct agent *a, + char *ifname); #endif /* AGENT_H */ diff --git a/src/core/agent_cmdu_generator.c b/src/core/agent_cmdu_generator.c index 3b2d19d77aacfbb9fc4ffe2d291cd6451ce7ca01..7d5680a532a209b9db29dfca7ff8f77d8c6e1e03 100644 --- a/src/core/agent_cmdu_generator.c +++ b/src/core/agent_cmdu_generator.c @@ -205,22 +205,18 @@ struct cmdu_cstruct *agent_gen_ap_metrics_response(struct agent *a, case MAP_TLV_AP_METRIC_QUERY: { - int radio_index; - int bss_index; - struct wifi_radio_element *radio; - struct netif_fh *fh; struct tlv_ap_metric_query *p = (struct tlv_ap_metric_query *)tmp; for (j = 0; j < p->bssid_nr; j++) { int num_sta = 0; struct sta *s; + uint8_t bssid[6] = { 0 }; + struct netif_fh *fh; - bss_index = get_radio_and_bss_index(a, - p->ap_metric_query_bssid[j].bssid, - &radio_index); - - if (bss_index == -1) + memcpy(bssid, p->ap_metric_query_bssid[j].bssid, 6); + fh = wifi_get_netif_by_bssid(a, bssid); + if (!fh) continue; /* AP Metrics TLV */ @@ -230,20 +226,15 @@ struct cmdu_cstruct *agent_gen_ap_metrics_response(struct agent *a, cmdu->num_tlvs++; // #endif - radio = a->radios + radio_index; - fh = wifi_radio_to_ap(a, radio->name); - if (fh == NULL) - continue; - list_for_each_entry(s, &fh->stalist, list) num_sta++; - // if (fh->cfg->include_sta_stats) { + if (fh->cfg->include_sta_stats) { /* Associated STA Traffic Stats TLV */ cmdu->num_tlvs += num_sta; - // } + } - // if (fh->cfg->include_sta_metric) { + if (fh->cfg->include_sta_metric) { /* Associated STA Link Metrics TLV */ cmdu->num_tlvs += num_sta; @@ -251,7 +242,7 @@ struct cmdu_cstruct *agent_gen_ap_metrics_response(struct agent *a, /* Associated STA Extended Link Metrics TLV */ cmdu->num_tlvs += num_sta; // #endif - // } + } } break; @@ -299,18 +290,18 @@ struct cmdu_cstruct *agent_gen_ap_metrics_response(struct agent *a, case MAP_TLV_AP_METRIC_QUERY: { - int radio_index; - int bss_index; struct wifi_radio_element *radio; struct wifi_bss_element *bss; - struct netif_fh *fh; struct tlv_ap_metrics *p2; struct tlv_ap_ext_metrics *p3; struct tlv_ap_metric_query *p = (struct tlv_ap_metric_query *)tmp; for (j = 0; j < p->bssid_nr; j++) { + int radio_index; + int bss_index; struct sta *s; + struct netif_fh *fh; bss_index = get_radio_and_bss_index(a, p->ap_metric_query_bssid[j].bssid, @@ -338,13 +329,12 @@ struct cmdu_cstruct *agent_gen_ap_metrics_response(struct agent *a, cmdu->tlvs[tlv_index++] = (uint8_t *)p3; // #endif - fh = wifi_radio_to_ap(a, radio->name); + fh = wifi_get_netif_by_bssid(a, bss->bssid); if (fh == NULL) continue; - list_for_each_entry(s, &fh->stalist, list) { - // if (fh->cfg->include_sta_stats) { + if (fh->cfg->include_sta_stats) { /* Associated STA Traffic Stats TLV */ struct tlv_assoc_sta_traffic_stats *p4; @@ -353,9 +343,9 @@ struct cmdu_cstruct *agent_gen_ap_metrics_response(struct agent *a, goto error; cmdu->tlvs[tlv_index++] = (uint8_t *)p4; - // } + } - // if (fh->cfg->include_sta_metric) { + if (fh->cfg->include_sta_metric) { struct tlv_assoc_sta_link_metrics *p5; struct tlv_assoc_sta_ext_link_metric *p6; @@ -372,7 +362,7 @@ struct cmdu_cstruct *agent_gen_ap_metrics_response(struct agent *a, cmdu->tlvs[tlv_index++] = (uint8_t *)p6; // #endif - // } + } } } @@ -387,3 +377,94 @@ error: map_free_cmdu(cmdu); return NULL; } + +struct cmdu_cstruct *agent_gen_assoc_sta_metric_response( + struct agent *a, char *ifname) +{ + int i; + int tlv_index = 0; + struct cmdu_cstruct *cmdu; + struct wifi_radio_element *radio; + struct wifi_bss_element *bss; + + cmdu = calloc(1, sizeof(struct cmdu_cstruct)); + if (!cmdu) + return NULL; + + cmdu->message_type = CMDU_ASSOC_STA_LINK_METRICS_RESPONSE; + memcpy(cmdu->origin, a->cntlr_almac, 6); + /* TODO/FIXME: interface name + * hardcoded: br-lan + */ + strncpy(cmdu->intf_name, "br-lan", IFNAMESIZE - 1); + + radio = wifi_ifname_to_radio_element(a, ifname); + if (!radio) + goto error; + + /* Calculate number of TLVs required for the response + */ + for (i = 0; i < radio->num_bss; i++) { + struct netif_fh *fh; + int num_sta = 0; + struct sta *s; + + bss = radio->bsslist + i; + fh = wifi_get_netif_by_bssid(a, bss->bssid); + if (!fh) + continue; + + list_for_each_entry(s, &fh->stalist, list) + num_sta++; + + /* Associated STA Link Metrics TLV */ + cmdu->num_tlvs += num_sta; +// #ifdef PROFILE2 + /* Associated STA Extended Link Metrics TLV */ + cmdu->num_tlvs += num_sta; +// #endif + } + + cmdu->tlvs = (uint8_t **)calloc(cmdu->num_tlvs, sizeof(uint8_t *)); + if (!cmdu->tlvs) { + cmdu->num_tlvs = 0; + goto error; + } + + for (i = 0; i < radio->num_bss; i++) { + struct sta *s; + struct netif_fh *fh; + + bss = radio->bsslist + i; + fh = wifi_get_netif_by_bssid(a, bss->bssid); + if (!fh) + continue; + + list_for_each_entry(s, &fh->stalist, list) { + struct tlv_assoc_sta_link_metrics *p1; + struct tlv_assoc_sta_ext_link_metric *p2; + + p1 = agent_gen_assoc_sta_link_metrics(a, s, bss->bssid); + if (!p1) + goto error; + + cmdu->tlvs[tlv_index++] = (uint8_t *)p1; + +// #ifdef PROFILE2 + p2 = agent_gen_assoc_sta_ext_link_metric(a, s, bss->bssid); + if (!p2) + goto error; + + cmdu->tlvs[tlv_index++] = (uint8_t *)p2; +// #endif + } + + } + + return cmdu; + +error: + map_free_cmdu(cmdu); + + return NULL; +} diff --git a/src/core/agent_cmdu_generator.h b/src/core/agent_cmdu_generator.h index f126aacb0fc7801f001a95d73b113cb2bcb1bec9..d416d15d6f0a1f13baccbe32d79cd5807e93d2a8 100644 --- a/src/core/agent_cmdu_generator.h +++ b/src/core/agent_cmdu_generator.h @@ -15,8 +15,7 @@ struct cmdu_cstruct *agent_gen_ap_autoconfig_search(struct agent *a, uint8_t profile); struct cmdu_cstruct *agent_gen_ap_metrics_response(struct agent *a, struct cmdu_cstruct *rec_cmdu); +struct cmdu_cstruct *agent_gen_assoc_sta_metric_response( + struct agent *a, char *ifname); -int get_radio_index(struct agent *a, uint8_t *mac); -int get_bss_index(struct wifi_radio_element *radio, uint8_t *bssid); -int get_radio_and_bss_index(struct agent *a, uint8_t *bssid, int *radio_index); #endif diff --git a/src/core/agent_map.c b/src/core/agent_map.c index 0dbcc4d850b47315e46d499b69e509c3ee10ae31..de486af28c531e53470d64cb71b4ae309f753796 100644 --- a/src/core/agent_map.c +++ b/src/core/agent_map.c @@ -58,6 +58,10 @@ #define UBUS_TIMEOUT 1000 +/* TODO/FIXME: hardcoded 5 sec */ +#define UTIL_THRESHOLD_TIMER (5 * 1000) +#define RCPI_THRESHOLD_TIMER (5 * 1000) + #define MAX_RADIO 20 struct channel_response { @@ -596,6 +600,19 @@ static struct wifi_radio_element *wifi_get_radio_by_mac(struct agent *a, return NULL; } +/* get netif_fh based on bssid */ +struct netif_fh *wifi_get_netif_by_bssid(struct agent *a, uint8_t *bssid) +{ + struct netif_fh *fh; + + list_for_each_entry(fh, &a->fhlist, list) { + if (hwaddr_equal(fh->bssid, bssid)) + return fh; + } + + return NULL; +} + int wifi_teardown_iface(const char *ifname) { config_del_iface("wireless", "wifi-iface", ifname); @@ -917,12 +934,13 @@ int get_radio_and_bss_index(struct agent *a, uint8_t *bssid, return -1; } -/* ifname: some value, prepare the query for that specific interface, +/* ifname: interface name, prepare the query for that specific interface; * ifname: NULL, include all the interface. */ -static int prepare_ap_metrics_query(void *agent, - struct cmdu_cstruct *cmdu, char *ifname) +static struct cmdu_cstruct *prepare_ap_metrics_query( + void *agent, char *ifname) { + trace("%s --->\n", __func__); int total_bss = 0; int i, j, k; int tlv_index = 0; @@ -930,6 +948,15 @@ static int prepare_ap_metrics_query(void *agent, struct wifi_radio_element *radio; struct wifi_bss_element *bss; struct tlv_ap_metric_query *p1; + struct cmdu_cstruct *cmdu; + + cmdu = calloc(1, sizeof(struct cmdu_cstruct)); + if (!cmdu) + return NULL; + + cmdu->message_type = CMDU_AP_METRICS_QUERY; + memcpy(cmdu->origin, a->cntlr_almac, 6); + strncpy(cmdu->intf_name, "br-lan", IFNAMESIZE - 1); if (ifname == NULL) { /* AP Metrics Query TLV */ @@ -953,7 +980,7 @@ static int prepare_ap_metrics_query(void *agent, radio = wifi_ifname_to_radio_element(a, ifname); if (!radio) { cmdu->num_tlvs = 0; - return -1; + goto error; } total_bss = radio->num_bss; @@ -962,13 +989,13 @@ static int prepare_ap_metrics_query(void *agent, cmdu->tlvs = (uint8_t **)calloc(cmdu->num_tlvs, sizeof(uint8_t *)); if (!cmdu->tlvs) { cmdu->num_tlvs = 0; - return -1; + goto error; } p1 = calloc(1, sizeof(*p1)); if (!p1) - return -1; + goto error; p1->tlv_type = MAP_TLV_AP_METRIC_QUERY; p1->bssid_nr = total_bss; @@ -976,7 +1003,7 @@ static int prepare_ap_metrics_query(void *agent, sizeof(*p1->ap_metric_query_bssid)); if (!p1->ap_metric_query_bssid) { free(p1); - return -1; + goto error; } if (ifname == NULL) { @@ -986,12 +1013,9 @@ static int prepare_ap_metrics_query(void *agent, for (i = 0; i < a->num_radios; i++) { radio = a->radios + i; // #ifdef PROFILE2 - p2 = calloc(1, sizeof(*p2)); - if (p2) { - p2->tlv_type = MAP_TLV_AP_RADIO_IDENTIFIER; - memcpy(p2->radio_id, radio->macaddr, 6); + p2 = agent_gen_ap_radio_identifier(a, radio->macaddr); + if (p2) cmdu->tlvs[tlv_index++] = (uint8_t *)p2; - } // #endif for (j = 0; j < radio->num_bss; j++) { @@ -1009,16 +1033,13 @@ static int prepare_ap_metrics_query(void *agent, radio = wifi_ifname_to_radio_element(a, ifname); if (!radio) { map_free_tlv_cstruct((uint8_t *)p1); - return -1; + goto error; } // #ifdef PROFILE2 - p2 = calloc(1, sizeof(*p2)); - if (p2) { - p2->tlv_type = MAP_TLV_AP_RADIO_IDENTIFIER; - memcpy(p2->radio_id, radio->macaddr, 6); + p2 = agent_gen_ap_radio_identifier(a, radio->macaddr); + if (p2) cmdu->tlvs[tlv_index++] = (uint8_t *)p2; - } // #endif for (i = 0; i < radio->num_bss; i++) { @@ -1032,7 +1053,10 @@ static int prepare_ap_metrics_query(void *agent, cmdu->tlvs[tlv_index] = (uint8_t *)p1; - return 0; + return cmdu; +error: + map_free_cmdu(cmdu); + return NULL; } static int prepare_ap_metrics_response(void *agent, @@ -1052,6 +1076,23 @@ static int prepare_ap_metrics_response(void *agent, return 0; } +static int prepare_assoc_sta_metric_response(void *agent, char *ifname) +{ + trace("%s: --->\n", __func__); + struct cmdu_cstruct *cmdu; + struct agent *a = (struct agent *)agent; + + cmdu = agent_gen_assoc_sta_metric_response(a, ifname); + if (!cmdu) + return -1; + + agent_send_cmdu(a, cmdu); + map_free_cmdu(cmdu); + + return 0; + +} + int handle_1905_ack(void *agent, struct cmdu_cstruct *cmdu) { trace("agent: %s: --->\n", __func__); @@ -1178,63 +1219,276 @@ fail: return -1; } -int handle_map_policy_config(void *agent, struct cmdu_cstruct *cmdu) +static uint8_t rssi_to_rcpi(int rssi) +{ + if (!rssi) + return 255; + else if (rssi < -110) + return 0; + else if (rssi > 0) + return 220; + else + return (rssi + 110) * 2; +} + +static uint8_t calculate_radio_util(struct agent *a, char *ifname) +{ + struct wifi_radio_element *radio; + + radio = wifi_ifname_to_radio_element(a, ifname); + if (!radio) + return 0; + + return radio->total_utilization; +} + +static uint8_t calculate_radio_rcpi(struct agent *a, char *ifname) +{ + int j, k; + struct wifi_radio_element *radio; + struct wifi_bss_element *bss; + struct wifi_sta_element *sta; + int8_t rssi = 0; + uint8_t rcpi = 0; + + radio = wifi_ifname_to_radio_element(a, ifname); + if (!radio) + return 0; + + for (j = 0; j < radio->num_bss; j++) { + bss = radio->bsslist + j; + for (k = 0; k < bss->num_stations; k++) { + sta = bss->stalist + k; + rssi += sta->rssi; + } + } + + rcpi = rssi_to_rcpi(rssi); + + return rcpi; +} + +static void agent_metric_report_timer_cb(struct uloop_timeout *t) +{ + struct agent_config *cfg = + container_of(t, struct agent_config, metric_report_timer); + struct agent *a = container_of(cfg, struct agent, cfg); + struct cmdu_cstruct *cmdu; + char *ifname = NULL; + + cmdu = prepare_ap_metrics_query((void *)a, ifname); + if (!cmdu) + goto refresh_interval; + + prepare_ap_metrics_response(a, cmdu); + map_free_cmdu(cmdu); + +refresh_interval: + uloop_timeout_set(&cfg->metric_report_timer, + cfg->pcfg->report_interval * 1000); +} + +static void agent_util_threshold_timer_cb(struct uloop_timeout *t) +{ + struct netif_fh *p = container_of(t, struct netif_fh, + util_threshold_timer); + struct agent *a = p->agent; + struct cmdu_cstruct *cmdu; + uint8_t curr_util = 0; + uint8_t prev_util; + + curr_util = calculate_radio_util(a, p->name); + prev_util = p->prev_util; + if (((prev_util > p->cfg->util_threshold) && + (curr_util > p->cfg->util_threshold)) || + ((prev_util < p->cfg->util_threshold) && + (curr_util < p->cfg->util_threshold))) + goto refresh_interval; + + cmdu = prepare_ap_metrics_query((void *)a, p->name); + if (!cmdu) + goto refresh_interval; + + prepare_ap_metrics_response(a, cmdu); + map_free_cmdu(cmdu); + +refresh_interval: + p->prev_util = curr_util; + uloop_timeout_set(&p->util_threshold_timer, UTIL_THRESHOLD_TIMER); +} + +static void agent_rcpi_thresold_timer_cb(struct uloop_timeout *t) +{ + struct netif_fh *p = container_of(t, struct netif_fh, + rcpi_threshold_timer); + struct agent *a = p->agent; + uint8_t curr_rcpi = 0; + uint8_t prev_rcpi; + + curr_rcpi = calculate_radio_rcpi(a, p->name); + prev_rcpi = p->prev_rcpi; + if (((prev_rcpi > p->cfg->rcpi_threshold) && + (curr_rcpi > p->cfg->rcpi_threshold)) || + ((prev_rcpi < p->cfg->rcpi_threshold) && + (curr_rcpi < p->cfg->rcpi_threshold))) + goto refresh_interval; + + prepare_assoc_sta_metric_response(a, p->name); + +refresh_interval: + p->prev_rcpi = curr_rcpi; + uloop_timeout_set(&p->rcpi_threshold_timer, RCPI_THRESHOLD_TIMER); +} + +static int agent_process_policy_config(struct agent *a) { - //struct tlv *t; + trace("%s: --->\n", __func__); + int i; + struct agent_config *cfg = &a->cfg; + struct policy_cfg *c = cfg->pcfg; + + if (c && (c->report_interval > 0)) { + cfg->metric_report_timer.cb = agent_metric_report_timer_cb; + uloop_timeout_set(&cfg->metric_report_timer, + c->report_interval * 1000); + } + + for (i = 0; i < a->num_radios; i++) { + struct netif_fh *p; + + p = wifi_radio_to_ap(a, a->radios[i].name); + if (!p) + continue; + + if (p->cfg->util_threshold > 0) { + p->util_threshold_timer.cb = + agent_util_threshold_timer_cb; + uloop_timeout_set(&p->util_threshold_timer, + UTIL_THRESHOLD_TIMER); + } + + if (p->cfg->rcpi_threshold > 0) { + p->rcpi_threshold_timer.cb = + agent_rcpi_thresold_timer_cb; + uloop_timeout_set(&p->rcpi_threshold_timer, + RCPI_THRESHOLD_TIMER); + } + } + + /* TODO: + * 17.2.37: report independent channel scan, + * will be useful while extending channel scan response + * + * 17.2.66: Backhaul configuration + * 17.2.49, 17.2.50: Will be used in traffic seperation + * + * 17.2.58: report unsuccesful association, + * Sta events should be checked & reported accordingly + */ + return 0; +} + +int handle_map_policy_config(void *agent, struct cmdu_cstruct *cmdu) +{ trace("%s: --->\n", __func__); + int i; + uint8_t *tlv; + struct agent *a = (struct agent *)agent; + struct uci_context *ctx; + struct uci_package *pkg; -#if 0 - for_each_tlv(t, tlvs, len) { - fprintf(stderr, "type = 0x%02x\n", t->type); + /* send the 1905 ack message to controller */ + // handle_1905_ack(a, cmdu); - switch (t->type) { - case 0x89 /* MAP_TLV_STEERING_POLICY */: + ctx = uci_alloc_context(); + if (!ctx) + return -1; + + if (uci_load(ctx, "mapagent", &pkg)) { + uci_free_context(ctx); + return -1; + } + + for (i = 0; i < cmdu->num_tlvs; i++) { + tlv = (uint8_t *)cmdu->tlvs[i]; + fprintf(stderr, "TLV: %s\n", map_stringify_tlv_type(*tlv)); + + switch (*tlv) { + case MAP_TLV_STEERING_POLICY: { - //struct tlv_0x89 *a = tlv_get_struct(0x89, t); + struct tlv_steering_policy *p = + (struct tlv_steering_policy *)tlv; - //free(a); + agent_fill_steering_policy(a, p, ctx, pkg); + break; } - break; - case 0x8a /* MAP_TLV_METRIC_REPORTING_POLICY */: + case MAP_TLV_METRIC_REPORTING_POLICY: { + struct tlv_metric_report_policy *p = + (struct tlv_metric_report_policy *)tlv; + + agent_fill_metric_report_policy(a, p, ctx, pkg); + break; } - break; - case 0xb5 /* MAP_TLV_DEFAULT_8021Q_SETTINGS_TLV */: + case MAP_TLV_DEFAULT_8021Q_SETTINGS: { + struct tlv_default_8021q_settings *p = + (struct tlv_default_8021q_settings *)tlv; + + agent_fill_8021q_setting(a, p, ctx, pkg); + break; } - break; - case 0xb6 /* MAP_TLV_TRAFFIC_SEPARATION_POLICY_TLV */: + case MAP_TLV_TRAFFIC_SEPARATION_POLICY: { + struct tlv_traffic_sep_policy *p = + (struct tlv_traffic_sep_policy *)tlv; + + agent_fill_traffic_sep_policy(a, p, ctx, pkg); + break; } - break; - case 0xa4 /* MAP_TLV_CHANNEL_SCAN_REPORTING_POLICY_TLV */: + case MAP_TLV_CHANNEL_SCAN_REPORTING_POLICY: { + struct tlv_ch_scan_rep_policy *p = + (struct tlv_ch_scan_rep_policy *)tlv; + + agent_fill_ch_scan_rep_policy(a, p, ctx, pkg); + break; } - break; - case 0xc4 /* MAP_TLV_UNSUCCESS_ASSOCIATION_POLICY_TLV */: + case MAP_TLV_UNSUCCESS_ASSOCIATION_POLICY: { + struct tlv_unsuccess_assoc_policy *p = + (struct tlv_unsuccess_assoc_policy *)tlv; + + agent_fill_unsuccess_assoc_policy(a, p, ctx, pkg); + break; } - break; - case 0xd0 /* MAP_TLV_BACKHAUL_BSS_CONFIG_TLV */: + case MAP_TLV_BACKHAUL_BSS_CONFIG: { - } - break; + struct tlv_backhaul_bss_config *p = + (struct tlv_backhaul_bss_config *)tlv; - default: - break; + agent_fill_backhaul_bss_config(a, p, ctx, pkg); + break; + } } } -#endif - /* update core structs in agent */ - //TODO + /* update agent config file */ + uci_commit(ctx, &pkg, false); + uci_unload(ctx, pkg); + uci_free_context(ctx); + + /* Reload agent config */ + agent_config_reload(&a->cfg); + + agent_process_policy_config(a); return 0; } diff --git a/src/core/agent_tlv_generator.c b/src/core/agent_tlv_generator.c index 532a4a542d39188b58a1fa86f100cbe6fbb7bbff..7ca4c85944b130089316b813fa3dcde3471be03c 100644 --- a/src/core/agent_tlv_generator.c +++ b/src/core/agent_tlv_generator.c @@ -888,3 +888,606 @@ struct tlv_assoc_sta_ext_link_metric *agent_gen_assoc_sta_ext_link_metric( return p; } + +struct tlv_ap_radio_identifier *agent_gen_ap_radio_identifier( + struct agent *a, uint8_t *radio_id) +{ + struct tlv_ap_radio_identifier *p; + + p = calloc(1, sizeof(*p)); + if (!p) + return NULL; + + p->tlv_type = MAP_TLV_AP_RADIO_IDENTIFIER; + memcpy(p->radio_id, radio_id, 6); + + return p; +} + +int agent_fill_steering_policy(struct agent *a, + struct tlv_steering_policy *p, + struct uci_context *ctx, struct uci_package *pkg) +{ + int ret, i; + struct uci_element *e; + struct uci_ptr ptr; + char buf[64] = {0}; + char addr[18] = {0}; + + /* Add exclude list & btm exclude list in 'agent' section */ + uci_foreach_element(&pkg->sections, e) { + struct uci_section *s = uci_to_section(e); + + if (strcmp(s->type, "agent")) + continue; + + for (i = 0; i < p->local_disallowed_sta_nr; i++) { + memset(buf, 0, sizeof(buf)); + memset(addr, 0, sizeof(addr)); + hwaddr_ntoa(p->local_disallowed_sta_macs[i].addr, addr); + snprintf(buf, sizeof(buf) - 1, + "%s.%s.steer_exclude=%s", + pkg->e.name, s->e.name, addr); + ret = uci_lookup_ptr(ctx, &ptr, buf, true); + if (ret != UCI_OK) + return -1; + + uci_add_list(ctx, &ptr); + uci_save(ctx, ptr.p); + } + + for (i = 0; i < p->btm_disallowed_sta_nr; i++) { + memset(buf, 0, sizeof(buf)); + memset(addr, 0, sizeof(addr)); + hwaddr_ntoa(p->btm_disallowed_sta_macs[i].addr, addr); + snprintf(buf, sizeof(buf) - 1, + "%s.%s.steer_exclude_btm=%s", + pkg->e.name, s->e.name, addr); + ret = uci_lookup_ptr(ctx, &ptr, buf, true); + if (ret != UCI_OK) + return -1; + + uci_add_list(ctx, &ptr); + uci_save(ctx, ptr.p); + } + + break; + } + + for (i = 0; i < p->control_policy_radio_nr; i++) { + int j, k; + int radio_index; + struct wifi_radio_element *radio; + int ifs_index = -1; + + radio_index = get_radio_index(a, p->control_policy[i].radio_id); + if (radio_index == -1) + continue; + + radio = a->radios + radio_index; + for (j = 0; j < WIFI_DEVICE_MAX_NUM; j++) { + if (!strcmp(a->ifs[j].radio, radio->name)) { + ifs_index = j; + break; + } + } + + if (ifs_index == -1) + continue; + + /* add the configuration in each iface section for specific radio */ + for (k = 0; k < WIFI_DEVICE_MAX_NUM; k++) { + uci_foreach_element(&pkg->sections, e) { + char iface_name[16] = {0}; + struct uci_section *s = uci_to_section(e); + struct uci_element *e1; + + if (strcmp(s->type, "fh-iface")) + continue; + + memset(buf, 0, sizeof(buf)); + snprintf(buf, sizeof(buf) - 1, "%s.%s.ifname", + pkg->e.name, s->e.name); + ret = uci_lookup_ptr(ctx, &ptr, buf, true); + if (ptr.value && (ret != UCI_OK)) { + fprintf(stderr, "value not found\n"); + continue; + } + + e1 = ptr.last; + if (e1->type == UCI_TYPE_OPTION) + strncpy(iface_name, ptr.o->v.string, 15); + + if (strcmp(iface_name, a->ifs[ifs_index].iface[k].name)) + continue; + + /* Add the policy config params */ + memset(buf, 0, sizeof(buf)); + snprintf(buf, sizeof(buf) - 1, + "%s.%s.policy=%d", + pkg->e.name, s->e.name, + p->control_policy[i].steering_policy); + ret = uci_lookup_ptr(ctx, &ptr, buf, true); + if (ret != UCI_OK) + return -1; + + uci_set(ctx, &ptr); + uci_save(ctx, ptr.p); + + memset(buf, 0, sizeof(buf)); + snprintf(buf, sizeof(buf) - 1, + "%s.%s.util_threshold=%d", + pkg->e.name, s->e.name, + p->control_policy[i].channel_utilization_thres); + ret = uci_lookup_ptr(ctx, &ptr, buf, true); + if (ret != UCI_OK) + return -1; + + uci_set(ctx, &ptr); + uci_save(ctx, ptr.p); + + memset(buf, 0, sizeof(buf)); + snprintf(buf, sizeof(buf) - 1, + "%s.%s.rcpi_threshold=%d", + pkg->e.name, s->e.name, + p->control_policy[i].rcpi_steering_thres); + ret = uci_lookup_ptr(ctx, &ptr, buf, true); + if (ret != UCI_OK) + return -1; + + uci_set(ctx, &ptr); + uci_save(ctx, ptr.p); + + break; + } + } + } + + return 0; +} + +int agent_fill_metric_report_policy(struct agent *a, + struct tlv_metric_report_policy *p, struct uci_context *ctx, + struct uci_package *pkg) +{ + int ret, i; + struct uci_element *e; + struct uci_ptr ptr; + char buf[64] = {0}; + bool is_section_found = false; + struct uci_section *s; + + uci_foreach_element(&pkg->sections, e) { + s = uci_to_section(e); + + if (!strcmp(s->type, "policy")) { + is_section_found = true; + break; + } + } + + if (!is_section_found) { + /* add a new section 'policy' */ + ret = uci_add_section(ctx, pkg, "policy", &s); + if (ret != UCI_OK) + return -1; + + uci_save(ctx, pkg); + } + + memset(buf, 0, sizeof(buf)); + snprintf(buf, sizeof(buf) - 1, + "%s.%s.report_interval=%d", + pkg->e.name, s->e.name, p->interval); + ret = uci_lookup_ptr(ctx, &ptr, buf, true); + if (ret != UCI_OK) + return -1; + + uci_set(ctx, &ptr); + uci_save(ctx, ptr.p); + + /* Add radio specific params in fh-iface section */ + for (i = 0; i < p->metric_reporting_policy_radio_nr; i++) { + int j, k; + int ifs_index = -1; + int radio_index; + struct wifi_radio_element *radio; + + radio_index = get_radio_index(a, + p->metric_reporting_policy[i].radio_id); + if (radio_index == -1) + continue; + + radio = a->radios + radio_index; + for (j = 0; j < WIFI_DEVICE_MAX_NUM; j++) { + if (!strcmp(a->ifs[j].radio, radio->name)) { + ifs_index = j; + break; + } + } + + if (ifs_index == -1) + continue; + + /* add configuration in each iface section for specific radio */ + for (k = 0; k < WIFI_DEVICE_MAX_NUM; k++) { + uci_foreach_element(&pkg->sections, e) { + char iface_name[16] = {0}; + struct uci_section *s = uci_to_section(e); + struct uci_element *e1; + + if (strcmp(s->type, "fh-iface")) + continue; + + memset(buf, 0, sizeof(buf)); + snprintf(buf, sizeof(buf) - 1, "%s.%s.ifname", + pkg->e.name, s->e.name); + ret = uci_lookup_ptr(ctx, &ptr, buf, true); + if (ptr.value && (ret != UCI_OK)) { + fprintf(stderr, "value not found\n"); + continue; + } + + e1 = ptr.last; + if (e1->type == UCI_TYPE_OPTION) + strncpy(iface_name, ptr.o->v.string, 15); + + if (strcmp(iface_name, a->ifs[ifs_index].iface[k].name)) + continue; + + /* Add the policy config params */ + memset(buf, 0, sizeof(buf)); + snprintf(buf, sizeof(buf) - 1, + "%s.%s.report_rcpi_threshold=%d", + pkg->e.name, s->e.name, + p->metric_reporting_policy[i].rcpi_thres); + ret = uci_lookup_ptr(ctx, &ptr, buf, true); + if (ret != UCI_OK) + return -1; + + uci_set(ctx, &ptr); + uci_save(ctx, ptr.p); + + memset(buf, 0, sizeof(buf)); + snprintf(buf, sizeof(buf) - 1, + "%s.%s.rcpi_hysteresis_margin=%d", + pkg->e.name, s->e.name, + p->metric_reporting_policy[i].rcpi_hysteresis_margin); + ret = uci_lookup_ptr(ctx, &ptr, buf, true); + if (ret != UCI_OK) + return -1; + + uci_set(ctx, &ptr); + uci_save(ctx, ptr.p); + + memset(buf, 0, sizeof(buf)); + snprintf(buf, sizeof(buf) - 1, + "%s.%s.report_util_threshold=%d", + pkg->e.name, s->e.name, + p->metric_reporting_policy[i].channel_utilization_thres); + ret = uci_lookup_ptr(ctx, &ptr, buf, true); + if (ret != UCI_OK) + return -1; + + uci_set(ctx, &ptr); + uci_save(ctx, ptr.p); + + memset(buf, 0, sizeof(buf)); + snprintf(buf, sizeof(buf) - 1, + "%s.%s.include_sta_stats=%d", + pkg->e.name, s->e.name, + p->metric_reporting_policy[i].is_assoc_sta_traffic_stats); + ret = uci_lookup_ptr(ctx, &ptr, buf, true); + if (ret != UCI_OK) + return -1; + + uci_set(ctx, &ptr); + uci_save(ctx, ptr.p); + + memset(buf, 0, sizeof(buf)); + snprintf(buf, sizeof(buf) - 1, + "%s.%s.include_sta_metric=%d", + pkg->e.name, s->e.name, + p->metric_reporting_policy[i].is_assoc_sta_link_metrics); + ret = uci_lookup_ptr(ctx, &ptr, buf, true); + if (ret != UCI_OK) + return -1; + + uci_set(ctx, &ptr); + uci_save(ctx, ptr.p); + + break; + } + } + + } + + return 0; +} + +int agent_fill_8021q_setting(struct agent *a, + struct tlv_default_8021q_settings *p, struct uci_context *ctx, + struct uci_package *pkg) +{ + int ret; + struct uci_element *e; + struct uci_ptr ptr; + char buf[64] = {0}; + struct uci_section *s; + bool is_section_found = false; + + uci_foreach_element(&pkg->sections, e) { + s = uci_to_section(e); + + if (!strcmp(s->type, "policy")) { + is_section_found = true; + break; + } + } + + if (!is_section_found) { + /* add a new section 'policy' */ + ret = uci_add_section(ctx, pkg, "policy", &s); + if (ret != UCI_OK) + return -1; + + uci_save(ctx, pkg); + } + + memset(buf, 0, sizeof(buf)); + snprintf(buf, sizeof(buf) - 1, "%s.%s.pvid=%d", + pkg->e.name, s->e.name, + p->primary_vid); + ret = uci_lookup_ptr(ctx, &ptr, buf, true); + if (ret != UCI_OK) + return -1; + + uci_set(ctx, &ptr); + uci_save(ctx, ptr.p); + + memset(buf, 0, sizeof(buf)); + snprintf(buf, sizeof(buf) - 1, "%s.%s.pcp_default=%d", + pkg->e.name, s->e.name, p->pcp); + ret = uci_lookup_ptr(ctx, &ptr, buf, true); + if (ret != UCI_OK) + return -1; + + uci_set(ctx, &ptr); + uci_save(ctx, ptr.p); + + return 0; +} + +int agent_fill_traffic_sep_policy(struct agent *a, + struct tlv_traffic_sep_policy *p, struct uci_context *ctx, + struct uci_package *pkg) +{ + int ret, i; + struct uci_element *e; + struct uci_ptr ptr; + char buf[64]; + + for (i = 0; i < p->nbr_ssid; i++) { + uci_foreach_element(&pkg->sections, e) { + struct uci_element *e1; + struct uci_section *s = uci_to_section(e); + char section_ssid[32] = {0}; + + if (strcmp(s->type, "fh-iface") && + strcmp(s->type, "bk-iface")) + continue; + + memset(buf, 0, sizeof(buf)); + snprintf(buf, sizeof(buf) - 1, "%s.%s.ssid", + pkg->e.name, s->e.name); + ret = uci_lookup_ptr(ctx, &ptr, buf, true); + if (ret != UCI_OK) + return -1; + + + e1 = ptr.last; + if (e1->type == UCI_TYPE_OPTION) + strncpy(section_ssid, ptr.o->v.string, 31); + + if (strcmp(section_ssid, p->data[i].ssid)) + continue; + + memset(buf, 0, sizeof(buf)); + snprintf(buf, sizeof(buf) - 1, "%s.%s.vid=%d", + pkg->e.name, s->e.name, + p->data[i].vid); + ret = uci_lookup_ptr(ctx, &ptr, buf, true); + if (ret != UCI_OK) + return -1; + + uci_set(ctx, &ptr); + uci_save(ctx, ptr.p); + break; + } + } + + return 0; +} + +int agent_fill_ch_scan_rep_policy(struct agent *a, + struct tlv_ch_scan_rep_policy *p, struct uci_context *ctx, + struct uci_package *pkg) +{ + int ret; + struct uci_element *e; + struct uci_ptr ptr; + char buf[64] = {0}; + bool is_section_found = false; + struct uci_section *s; + + uci_foreach_element(&pkg->sections, e) { + s = uci_to_section(e); + + if (!strcmp(s->type, "policy")) { + is_section_found = true; + break; + } + } + + if (!is_section_found) { + /* add a new section 'policy' */ + ret = uci_add_section(ctx, pkg, "policy", &s); + if (ret != UCI_OK) + return -1; + + uci_save(ctx, pkg); + } + + memset(buf, 0, sizeof(buf)); + snprintf(buf, sizeof(buf) - 1, "%s.%s.report_scan=%d", + pkg->e.name, s->e.name, + p->ch_scans); + ret = uci_lookup_ptr(ctx, &ptr, buf, true); + if (ret != UCI_OK) + return -1; + + uci_set(ctx, &ptr); + uci_save(ctx, ptr.p); + + return 0; +} + +int agent_fill_unsuccess_assoc_policy(struct agent *a, + struct tlv_unsuccess_assoc_policy *p, struct uci_context *ctx, + struct uci_package *pkg) +{ + int ret; + struct uci_element *e; + struct uci_ptr ptr; + char buf[64] = {0}; + bool is_section_found = false; + struct uci_section *s; + + uci_foreach_element(&pkg->sections, e) { + s = uci_to_section(e); + + if (!strcmp(s->type, "policy")) { + is_section_found = true; + break; + } + } + + if (!is_section_found) { + /* add a new section 'policy' */ + ret = uci_add_section(ctx, pkg, "policy", &s); + if (ret != UCI_OK) + return -1; + + uci_save(ctx, pkg); + } + + memset(buf, 0, sizeof(buf)); + snprintf(buf, sizeof(buf) - 1, + "%s.%s.report_sta_assocfails=%d", + pkg->e.name, s->e.name, p->report); + ret = uci_lookup_ptr(ctx, &ptr, buf, true); + if (ret != UCI_OK) + return -1; + + uci_set(ctx, &ptr); + uci_save(ctx, ptr.p); + + memset(buf, 0, sizeof(buf)); + snprintf(buf, sizeof(buf) - 1, + "%s.%s.report_sta_assocfails_rate=%d", + pkg->e.name, s->e.name, + p->max_reporting_rate); + ret = uci_lookup_ptr(ctx, &ptr, buf, true); + if (ret != UCI_OK) + return -1; + + uci_set(ctx, &ptr); + uci_save(ctx, ptr.p); + + return 0; +} + +int agent_fill_backhaul_bss_config(struct agent *a, + struct tlv_backhaul_bss_config *p, struct uci_context *ctx, + struct uci_package *pkg) +{ + struct netif_fh *fh; + struct uci_element *e; + struct uci_ptr ptr; + int ret; + bool is_bksec_found = false; + struct uci_section *s; + char buf[64] = {0}; + + fh = wifi_get_netif_by_bssid(a, p->bssid); + if (fh == NULL) + return -1; + + uci_foreach_element(&pkg->sections, e) { + struct uci_element *e1; + char section_ifname[16] = {0}; + + s = uci_to_section(e); + if (strcmp(s->type, "bk-iface")) + continue; + + memset(buf, 0, sizeof(buf)); + snprintf(buf, sizeof(buf) - 1, "%s.%s.ifname", + pkg->e.name, s->e.name); + ret = uci_lookup_ptr(ctx, &ptr, buf, true); + if (ptr.value && (ret != UCI_OK)) + return -1; + + e1 = ptr.last; + if (e1->type == UCI_TYPE_OPTION) + strncpy(section_ifname, ptr.o->v.string, 15); + + if (!strcmp(section_ifname, fh->name)) { + is_bksec_found = true; + break; + } + } + + if (!is_bksec_found) { + /* Add a new 'bk-iface section' */ + ret = uci_add_section(ctx, pkg, "bk-iface", &s); + if (ret != UCI_OK) + return -1; + + uci_save(ctx, pkg); + } + + memset(buf, 0, sizeof(buf)); + snprintf(buf, sizeof(buf) - 1, "%s.%s.ifname=%s", + pkg->e.name, s->e.name, fh->name); + ret = uci_lookup_ptr(ctx, &ptr, buf, true); + if (ret != UCI_OK) + return -1; + + uci_set(ctx, &ptr); + uci_save(ctx, ptr.p); + + memset(buf, 0, sizeof(buf)); + snprintf(buf, sizeof(buf) - 1, + "%s.%s.disallow_bsta_p1=%d", + pkg->e.name, s->e.name, p->p1); + ret = uci_lookup_ptr(ctx, &ptr, buf, true); + if (ret != UCI_OK) + return -1; + + uci_set(ctx, &ptr); + uci_save(ctx, ptr.p); + + memset(buf, 0, sizeof(buf)); + snprintf(buf, sizeof(buf) - 1, + "%s.%s.disallow_bsta_p2=%d", + pkg->e.name, s->e.name, p->p2); + ret = uci_lookup_ptr(ctx, &ptr, buf, true); + if (ret != UCI_OK) + return -1; + + uci_set(ctx, &ptr); + uci_save(ctx, ptr.p); + + return 0; +} diff --git a/src/core/agent_tlv_generator.h b/src/core/agent_tlv_generator.h index d6e67cd3426d1194d09a68b397c1fda186c337d2..f3ff1d17b3b63bb98ee5359a94281aa80c80ca55 100644 --- a/src/core/agent_tlv_generator.h +++ b/src/core/agent_tlv_generator.h @@ -10,6 +10,11 @@ #ifndef CNTLR_TLV_GEN_H #define CNTLR_TLV_GEN_H +int get_radio_index(struct agent *a, uint8_t *mac); +int get_bss_index(struct wifi_radio_element *radio, uint8_t *bssid); +int get_radio_and_bss_index(struct agent *a, uint8_t *bssid, int *radio_index); +struct netif_fh *wifi_get_netif_by_bssid(struct agent *a, uint8_t *bssid); + struct tlv_ap_ht_cap *agent_gen_ap_ht_caps(struct agent *a, struct cmdu_cstruct *cmdu, uint32_t radio_index); struct tlv_ap_cap *agent_gen_ap_caps(struct agent *a, @@ -60,4 +65,30 @@ struct tlv_assoc_sta_link_metrics *agent_gen_assoc_sta_link_metrics( struct agent *a, struct sta *s, uint8_t *bssid); struct tlv_assoc_sta_ext_link_metric *agent_gen_assoc_sta_ext_link_metric( struct agent *a, struct sta *s, uint8_t *bssid); +struct tlv_ap_radio_identifier *agent_gen_ap_radio_identifier( + struct agent *a, uint8_t *radio_id); + +/* Policy config related functions */ +int agent_fill_steering_policy(struct agent *a, + struct tlv_steering_policy *p, + struct uci_context *ctx, struct uci_package *pkg); +int agent_fill_metric_report_policy(struct agent *a, + struct tlv_metric_report_policy *p, + struct uci_context *ctx, struct uci_package *pkg); +int agent_fill_8021q_setting(struct agent *a, + struct tlv_default_8021q_settings *p, + struct uci_context *ctx, struct uci_package *pkg); +int agent_fill_traffic_sep_policy(struct agent *a, + struct tlv_traffic_sep_policy *p, + struct uci_context *ctx, struct uci_package *pkg); +int agent_fill_ch_scan_rep_policy(struct agent *a, + struct tlv_ch_scan_rep_policy *p, + struct uci_context *ctx, struct uci_package *pkg); +int agent_fill_unsuccess_assoc_policy(struct agent *a, + struct tlv_unsuccess_assoc_policy *p, + struct uci_context *ctx, struct uci_package *pkg); +int agent_fill_backhaul_bss_config(struct agent *a, + struct tlv_backhaul_bss_config *p, + struct uci_context *ctx, struct uci_package *pkg); + #endif diff --git a/src/core/config.c b/src/core/config.c index de49dd297ab7c68516ebcc6f09c2917f5056faa1..46e5c1921a278b313981d7cbfe924910dbdc4ea1 100644 --- a/src/core/config.c +++ b/src/core/config.c @@ -859,7 +859,7 @@ void stax_del_entry(struct list_head *h, char *sta_macstr) } } -static int clean_steer_btm_excl(struct netif_fhcfg *p) +static int clean_steer_btm_excl(struct agent_config *p) { struct stax *n, *tmp; @@ -870,7 +870,7 @@ static int clean_steer_btm_excl(struct netif_fhcfg *p) return 0; } -static int clean_steer_excl(struct netif_fhcfg *p) +static int clean_steer_excl(struct agent_config *p) { struct stax *n, *tmp; @@ -891,6 +891,16 @@ void agent_config_dump(struct agent_config *cfg) if (!cfg) return; + dbg(" Steer Exclude Lists -------\n"); + list_for_each_entry(x, &cfg->steer_excludelist, list) { + dbg(" mac: %s\n", x->macstring); + } + + dbg(" Steer BTM Exclude Lists -------\n"); + list_for_each_entry(x, &cfg->steer_btm_excludelist, list) { + dbg(" mac: %s\n", x->macstring); + } + list_for_each_entry(n, &cfg->fhlist, list) { dbg("name: %s\n", n->name); dbg(" enabled : %s\n", n->enabled ? "true" : "false"); @@ -906,16 +916,6 @@ void agent_config_dump(struct agent_config *cfg) */ } - dbg(" Steer Exclude Lists -------\n"); - list_for_each_entry(x, &n->steer_excludelist, list) { - dbg(" mac: %s\n", x->macstring); - } - - dbg(" Steer BTM Exclude Lists -------\n"); - list_for_each_entry(x, &n->steer_btm_excludelist, list) { - dbg(" mac: %s\n", x->macstring); - } - dbg(" Assoc Ctrl Lists -------\n"); list_for_each_entry(x, &n->assoc_ctrllist, list) { dbg(" mac: %s\n", x->macstring); @@ -963,8 +963,6 @@ struct netif_fhcfg *create_fronthaul_iface_config(struct agent_config *cfg, list_add(&pol->list, &new->steer_policylist); } - INIT_LIST_HEAD(&new->steer_excludelist); - INIT_LIST_HEAD(&new->steer_btm_excludelist); INIT_LIST_HEAD(&new->assoc_ctrllist); /* f->cfg = new; */ @@ -1233,6 +1231,8 @@ static int agent_config_get_wifi_agent(struct agent_config *a, A_BRCM_SETUP, /*A_CONFIGURED,*/ A_CNTLR_MAC, + A_EXCLUDE, + A_EXCLUDE_BTM, NUM_POLICIES }; const struct uci_parse_option opts[] = { @@ -1242,6 +1242,8 @@ static int agent_config_get_wifi_agent(struct agent_config *a, { .name = "brcm_setup", .type = UCI_TYPE_STRING }, /*{ .name = "configured", .type = UCI_TYPE_STRING },*/ { .name = "controller_macaddr", .type = UCI_TYPE_STRING }, + { .name = "exclude", .type = UCI_TYPE_LIST }, + { .name = "exclude_btm", .type = UCI_TYPE_LIST }, }; struct uci_option *tb[NUM_POLICIES]; @@ -1268,6 +1270,28 @@ static int agent_config_get_wifi_agent(struct agent_config *a, if (tb[A_CNTLR_MAC]) hwaddr_aton(tb[A_CNTLR_MAC]->v.string, a->cntlr_almac); + if (tb[A_EXCLUDE]) { + struct uci_element *xi; + + dbg("Steer: exclude: "); + uci_foreach_element(&tb[A_EXCLUDE]->v.list, xi) { + dbg("%s ", xi->name); + stax_add_entry(&a->steer_excludelist, xi->name); + } + dbg("\n"); + } + + if (tb[A_EXCLUDE_BTM]) { + struct uci_element *xi; + + dbg("Steer: exclude_btm: "); + uci_foreach_element(&tb[A_EXCLUDE_BTM]->v.list, xi) { + dbg("%s ", xi->name); + stax_add_entry(&a->steer_btm_excludelist, xi->name); + } + dbg("\n"); + } + return 0; } @@ -1348,6 +1372,8 @@ static int agent_config_get_bk_iface(struct agent_config *a, BK_SSID, BK_KEY, BK_ENCRYPTION, + BK_DISALLOWED_BSTA_P1, + BK_DISALLOWED_BSTA_P2, NUM_POLICIES }; const struct uci_parse_option opts[] = { @@ -1358,7 +1384,9 @@ static int agent_config_get_bk_iface(struct agent_config *a, { .name = "onboarded", .type = UCI_TYPE_STRING }, { .name = "ssid", .type = UCI_TYPE_STRING }, { .name = "key", .type = UCI_TYPE_STRING }, - { .name = "encryption", .type = UCI_TYPE_STRING } + { .name = "encryption", .type = UCI_TYPE_STRING }, + { .name = "disallow_bsta_p1", .type = UCI_TYPE_STRING }, + { .name = "disallow_bsta_p2", .type = UCI_TYPE_STRING } }; struct uci_option *tb[NUM_POLICIES]; struct netif_bkcfg *bk; @@ -1427,6 +1455,14 @@ static int agent_config_get_bk_iface(struct agent_config *a, strncpy(bk->encryption, encryption, sizeof(bk->encryption) - 1); } + if (tb[BK_DISALLOWED_BSTA_P1]) + bk->disallowed_bsta_p1 = + atoi(tb[BK_DISALLOWED_BSTA_P1]->v.string); + + if (tb[BK_DISALLOWED_BSTA_P2]) + bk->disallowed_bsta_p2 = + atoi(tb[BK_DISALLOWED_BSTA_P2]->v.string); + return 0; } @@ -1438,8 +1474,6 @@ static int agent_config_get_fh_iface(struct agent_config *a, FH_BAND, FH_STEER, FH_DEVICE, - FH_EXCLUDE, - FH_EXCLUDE_BTM, FH_ASSOC_CTRL, FH_BTM_RETRY, FH_BTM_RETRY_SECS, @@ -1450,6 +1484,14 @@ static int agent_config_get_fh_iface(struct agent_config *a, FH_SSID, FH_KEY, FH_ENCRYPTION, + FH_POLICY, + FH_UTIL_THRESHOLD, + FH_RCPI_THRESHOLD, + FH_REPORT_RCPI_THRESHOLD, + FH_RCPI_HYSTERESIS_MARGIN, + FH_REPORT_UTIL_THRESHOLD, + FH_INCLUDE_STA_STATS, + FH_INCLUDE_STA_METRIC, NUM_POLICIES, }; const struct uci_parse_option opts[] = { @@ -1457,8 +1499,6 @@ static int agent_config_get_fh_iface(struct agent_config *a, { .name = "band", .type = UCI_TYPE_STRING }, { .name = "steer", .type = UCI_TYPE_LIST }, { .name = "device", .type = UCI_TYPE_STRING }, - { .name = "exclude", .type = UCI_TYPE_LIST }, - { .name = "exclude_btm", .type = UCI_TYPE_LIST }, { .name = "assoc_ctrl", .type = UCI_TYPE_LIST }, { .name = "btm_retry", .type = UCI_TYPE_STRING }, { .name = "btm_retry_secs", .type = UCI_TYPE_STRING }, @@ -1468,7 +1508,15 @@ static int agent_config_get_fh_iface(struct agent_config *a, { .name = "assoc_ctrl_secs", .type = UCI_TYPE_STRING }, { .name = "ssid", .type = UCI_TYPE_STRING }, { .name = "key", .type = UCI_TYPE_STRING }, - { .name = "encryption", .type = UCI_TYPE_STRING } + { .name = "encryption", .type = UCI_TYPE_STRING }, + { .name = "policy", .type = UCI_TYPE_STRING }, + { .name = "util_threshold", .type = UCI_TYPE_STRING }, + { .name = "rcpi_threshold", .type = UCI_TYPE_STRING }, + { .name = "report_rcpi_threshold", .type = UCI_TYPE_STRING }, + { .name = "rcpi_hysteresis_margin", .type = UCI_TYPE_STRING }, + { .name = "report_util_threshold", .type = UCI_TYPE_STRING }, + { .name = "include_sta_stats", .type = UCI_TYPE_STRING }, + { .name = "include_sta_metric", .type = UCI_TYPE_STRING } }; struct uci_option *tb[NUM_POLICIES]; struct netif_fhcfg *fh; @@ -1488,8 +1536,6 @@ static int agent_config_get_fh_iface(struct agent_config *a, return -1; } } else { - clean_steer_btm_excl(fh); - clean_steer_excl(fh); warn("Duplicate 'fh-iface %s' config!! ignore\n", ifname); } @@ -1538,28 +1584,6 @@ static int agent_config_get_fh_iface(struct agent_config *a, strncpy(fh->device, device, sizeof(fh->device) - 1); } - if (tb[FH_EXCLUDE]) { - struct uci_element *xi; - - dbg("Steer: exclude: "); - uci_foreach_element(&tb[FH_EXCLUDE]->v.list, xi) { - dbg("%s ", xi->name); - stax_add_entry(&fh->steer_excludelist, xi->name); - } - dbg("\n"); - } - - if (tb[FH_EXCLUDE_BTM]) { - struct uci_element *xi; - - dbg("Steer: exclude_btm: "); - uci_foreach_element(&tb[FH_EXCLUDE_BTM]->v.list, xi) { - dbg("%s ", xi->name); - stax_add_entry(&fh->steer_btm_excludelist, xi->name); - } - dbg("\n"); - } - if (tb[FH_BTM_RETRY]) fh->steer_btm_retry = atoi(tb[FH_BTM_RETRY]->v.string); @@ -1602,6 +1626,35 @@ static int agent_config_get_fh_iface(struct agent_config *a, strncpy(fh->encryption, encryption, sizeof(fh->encryption) - 1); } + if (tb[FH_POLICY]) + fh->policy = atoi(tb[FH_POLICY]->v.string); + + if (tb[FH_UTIL_THRESHOLD]) + fh->util_threshold = atoi(tb[FH_UTIL_THRESHOLD]->v.string); + + if (tb[FH_RCPI_THRESHOLD]) + fh->rcpi_threshold = atoi(tb[FH_RCPI_THRESHOLD]->v.string); + + if (tb[FH_REPORT_RCPI_THRESHOLD]) + fh->report_rcpi_threshold = + atoi(tb[FH_REPORT_RCPI_THRESHOLD]->v.string); + + if (tb[FH_RCPI_HYSTERESIS_MARGIN]) + fh->rcpi_hysteresis_margin = + atoi(tb[FH_RCPI_HYSTERESIS_MARGIN]->v.string); + + if (tb[FH_REPORT_UTIL_THRESHOLD]) + fh->report_util_threshold = + atoi(tb[FH_REPORT_UTIL_THRESHOLD]->v.string); + + if (tb[FH_INCLUDE_STA_STATS]) + fh->include_sta_stats = + atoi(tb[FH_INCLUDE_STA_STATS]->v.string); + + if (tb[FH_INCLUDE_STA_METRIC]) + fh->include_sta_metric = + atoi(tb[FH_INCLUDE_STA_METRIC]->v.string); + return 0; } @@ -1621,6 +1674,64 @@ static int agent_config_get_steer_param(struct agent_config *a, return 0; } +static int agent_config_get_policy_param(struct agent_config *a, + struct uci_section *s) +{ + enum { + POL_REPORT_INTERVAL, + POL_PVID, + POL_PCP_DEFAULT, + POL_REPORT_SCAN, + POL_REPORT_STA_ASSOCFAILS, + POL_REPORT_STA_ASSOCFAILS_RATE, + NUM_POLICIES + }; + const struct uci_parse_option opts[] = { + { .name = "report_interval", .type = UCI_TYPE_STRING }, + { .name = "pvid", .type = UCI_TYPE_STRING }, + { .name = "pcp_default", .type = UCI_TYPE_STRING }, + { .name = "repost_scan", .type = UCI_TYPE_STRING }, + { .name = "report_sta_assocfails", .type = UCI_TYPE_STRING }, + { .name = "report_sta_assocfails_rate", .type = UCI_TYPE_STRING }, + }; + + struct uci_option *tb[NUM_POLICIES]; + struct policy_cfg *cfg; + + uci_parse_section(s, opts, NUM_POLICIES, tb); + + cfg = (struct policy_cfg *)calloc(1, sizeof(struct policy_cfg)); + if (!cfg) + return -1; + + if (tb[POL_REPORT_INTERVAL]) + cfg->report_interval = atoi(tb[POL_REPORT_INTERVAL]->v.string); + + if (tb[POL_PVID]) + cfg->pvid = atoi(tb[POL_PVID]->v.string); + + if (tb[POL_PCP_DEFAULT]) + cfg->pcp_default = atoi(tb[POL_PCP_DEFAULT]->v.string); + + if (tb[POL_REPORT_SCAN]) + cfg->report_scan = atoi(tb[POL_REPORT_SCAN]->v.string); + + if (tb[POL_REPORT_STA_ASSOCFAILS]) + cfg->report_sta_assocfails = + atoi(tb[POL_REPORT_STA_ASSOCFAILS]->v.string); + + if (tb[POL_REPORT_STA_ASSOCFAILS_RATE]) + cfg->report_sta_assocfails_rate = + atoi(tb[POL_REPORT_STA_ASSOCFAILS_RATE]->v.string); + + if (a->pcfg) + free(a->pcfg); + + a->pcfg = cfg; + + return 0; +} + int agent_config_reload(struct agent_config *cfg) { struct uci_context *ctx; @@ -1652,6 +1763,8 @@ int agent_config_reload(struct agent_config *cfg) agent_config_get_bk_iface(cfg, s); else if (!strcmp(s->type, "steer")) agent_config_get_steer_param(cfg, s); + else if (!strcmp(s->type, "policy")) + agent_config_get_policy_param(cfg, s); } uci_free_context(ctx); @@ -1886,6 +1999,8 @@ int agent_config_init(struct agent_config *cfg) INIT_LIST_HEAD(&cfg->fhlist); INIT_LIST_HEAD(&cfg->bklist); INIT_LIST_HEAD(&cfg->radiolist); + INIT_LIST_HEAD(&cfg->steer_excludelist); + INIT_LIST_HEAD(&cfg->steer_btm_excludelist); agent_config_prepare(cfg); agent_config_reload(cfg); @@ -1910,8 +2025,6 @@ int clean_all_bk(struct agent_config *cfg) void clean_fh(struct netif_fhcfg *p) { - clean_steer_btm_excl(p); - clean_steer_excl(p); list_del(&p->list); free(p); } @@ -1930,6 +2043,11 @@ int agent_config_clean(struct agent_config *cfg) { clean_all_fh(cfg); clean_all_bk(cfg); + clean_steer_btm_excl(cfg); + clean_steer_excl(cfg); + + if (cfg->pcfg) + free(cfg->pcfg); return 0; } diff --git a/src/core/config.h b/src/core/config.h index c13ddbadba2e0dea47e0ec19806527412a0b55d3..1c8d3d64782b236dfa9f83e6368db69451c16e06 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -50,6 +50,12 @@ struct stax { void stax_add_entry(struct list_head *h, char *sta_macstr); void stax_del_entry(struct list_head *h, char *sta_macstr); +enum agent_steer_policy { + AGENT_STEER_DISALLOW, /* agent shall not steer based on rcpi */ + AGENT_STEER_RCPI_MANDATE, /* agent shall steer based on rcpi */ + AGENT_STEER_RCPI_ALLOW, /* agent may steer based on rcpi */ +}; + /* per-bss interface config is good for now. * per-sta config is overkill, or maybe not ;) */ @@ -81,15 +87,18 @@ struct netif_fhcfg { /** ordered list of policies effective on per-bss interface */ struct list_head steer_policylist; - /** STAs excluded from steering; list of stax structs */ - struct list_head steer_excludelist; - - /** STAs excluded from BTM req steering; list of stax structs */ - struct list_head steer_btm_excludelist; - /** STAs assoc controlled; list of stax structs */ struct list_head assoc_ctrllist; + enum agent_steer_policy policy; + uint8_t util_threshold; + uint8_t rcpi_threshold; + uint8_t report_rcpi_threshold; + uint8_t rcpi_hysteresis_margin; + uint8_t report_util_threshold; + bool include_sta_stats; + bool include_sta_metric; + struct list_head list; /* link to next netif_config */ }; @@ -102,10 +111,22 @@ struct netif_bkcfg { char encryption[32]; bool enabled; bool onboarded; + bool disallowed_bsta_p1; + bool disallowed_bsta_p2; /* TODO: others as needed */ struct list_head list; /* link to next netif_bkcfg */ }; + +struct policy_cfg { + uint8_t report_interval; + uint16_t pvid; + uint8_t pcp_default; + bool report_scan; + bool report_sta_assocfails; + uint32_t report_sta_assocfails_rate; +}; + enum runfreq { AGENT_RUN_OFF, AGENT_RUN_HIGH, @@ -136,6 +157,16 @@ struct agent_config { bool brcm_setup; bool configured; uint8_t cntlr_almac[6]; + + struct policy_cfg *pcfg; /* policy section */ + struct uloop_timeout metric_report_timer; + + /** STAs excluded from steering; list of stax structs */ + struct list_head steer_excludelist; + + /** STAs excluded from BTM req steering; list of stax structs */ + struct list_head steer_btm_excludelist; + }; #if 0