From 5ab73f042a4b964ecd8acb4371667b24e9026e68 Mon Sep 17 00:00:00 2001
From: Saurabh Verma <saurabh.verma@iopsys.eu>
Date: Thu, 4 Feb 2021 14:27:36 +0000
Subject: [PATCH] map-agent: Code added for AP-Metric Response.
---
src/core/agent_cmdu_generator.c | 227 ++++++++++++++++++++++++++++++++
src/core/agent_cmdu_generator.h | 6 +
src/core/agent_map.c | 177 +++++++++++++++++++++++++
src/core/agent_tlv_generator.c | 163 +++++++++++++++++++++++
src/core/agent_tlv_generator.h | 12 ++
5 files changed, 585 insertions(+)
diff --git a/src/core/agent_cmdu_generator.c b/src/core/agent_cmdu_generator.c
index faa258700..3b2d19d77 100644
--- a/src/core/agent_cmdu_generator.c
+++ b/src/core/agent_cmdu_generator.c
@@ -160,3 +160,230 @@ fail_cmdu:
free(cmdu);
return NULL;
}
+
+struct cmdu_cstruct *agent_gen_ap_metrics_response(struct agent *a,
+ struct cmdu_cstruct *rec_cmdu)
+{
+ int i, j;
+ int tlv_index = 0;
+ uint8_t *tmp;
+ struct cmdu_cstruct *cmdu;
+
+ cmdu = calloc(1, sizeof(struct cmdu_cstruct));
+ if (!cmdu) {
+ dbg("Out of memory.!\n");
+ return NULL;
+ }
+
+ cmdu->message_type = CMDU_AP_METRICS_RESPONSE;
+ memcpy(cmdu->origin, rec_cmdu->origin, 6);
+ strncpy(cmdu->intf_name, rec_cmdu->intf_name, IFNAMESIZE - 1);
+ cmdu->message_id = rec_cmdu->message_id;
+
+ /* Calculate number of TLVs required for the response
+ * based on the received CMDU
+ */
+ for (i = 0; i < rec_cmdu->num_tlvs; i++) {
+ tmp = (uint8_t *)rec_cmdu->tlvs[i];
+
+ switch (*tmp) {
+ case MAP_TLV_AP_RADIO_IDENTIFIER:
+ {
+ int radio_index;
+ struct tlv_ap_radio_identifier *p =
+ (struct tlv_ap_radio_identifier *)tmp;
+
+ radio_index = get_radio_index(a, p->radio_id);
+ if (radio_index != -1) {
+// #ifdef PROFILE2
+ /* Radio Metrics TLV */
+ cmdu->num_tlvs++;
+// #endif
+ }
+ break;
+ }
+
+ 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;
+
+ bss_index = get_radio_and_bss_index(a,
+ p->ap_metric_query_bssid[j].bssid,
+ &radio_index);
+
+ if (bss_index == -1)
+ continue;
+
+ /* AP Metrics TLV */
+ cmdu->num_tlvs++;
+// #ifdef PROFILE2
+ /* AP Extended Metrics TLV */
+ 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) {
+ /* Associated STA Traffic Stats TLV */
+ cmdu->num_tlvs += num_sta;
+ // }
+
+ // if (fh->cfg->include_sta_metric) {
+ /* Associated STA Link Metrics TLV */
+ cmdu->num_tlvs += num_sta;
+
+// #ifdef PROFILE2
+ /* Associated STA Extended Link Metrics TLV */
+ cmdu->num_tlvs += num_sta;
+// #endif
+ // }
+
+ }
+ break;
+ }
+
+ default:
+ dbg("Unsupported tlv in cmdu:%s\n",
+ map_stringify_cmdu_type(rec_cmdu->message_type));
+ break;
+ }
+ }
+
+ cmdu->tlvs = (uint8_t **)calloc(cmdu->num_tlvs, sizeof(uint8_t *));
+ if (!cmdu->tlvs) {
+ cmdu->num_tlvs = 0;
+ goto error;
+ }
+
+ /* Process response based on received CMDU */
+ for (i = 0; i < rec_cmdu->num_tlvs; i++) {
+ tmp = (uint8_t *)rec_cmdu->tlvs[i];
+
+ switch (*tmp) {
+ case MAP_TLV_AP_RADIO_IDENTIFIER:
+ {
+ int radio_index;
+ struct tlv_radio_metrics *p1;
+ struct tlv_ap_radio_identifier *p =
+ (struct tlv_ap_radio_identifier *)tmp;
+
+ radio_index = get_radio_index(a, p->radio_id);
+ if (radio_index != -1) {
+// #ifdef PROFILE2
+ /* Radio Metrics TLV */
+ p1 = agent_gen_radio_metrics(a,
+ radio_index);
+ if (!p1)
+ goto error;
+
+ cmdu->tlvs[tlv_index++] = (uint8_t *)p1;
+// #endif
+ }
+ break;
+ }
+
+ 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++) {
+ struct sta *s;
+
+ bss_index = get_radio_and_bss_index(a,
+ p->ap_metric_query_bssid[j].bssid,
+ &radio_index);
+
+ if (bss_index == -1)
+ continue;
+
+ radio = a->radios + radio_index;
+ bss = radio->bsslist + bss_index;
+ /* AP Metrics TLV */
+ p2 = agent_gen_ap_metrics(a,
+ radio_index, bss_index);
+ if (!p2)
+ goto error;
+
+ cmdu->tlvs[tlv_index++] = (uint8_t *)p2;
+// #ifdef PROFILE2
+ /* AP Extended Metrics TLV */
+ p3 = agent_gen_ap_ext_metrics(a,
+ radio_index, bss_index);
+ if (!p3)
+ goto error;
+
+ cmdu->tlvs[tlv_index++] = (uint8_t *)p3;
+// #endif
+
+ fh = wifi_radio_to_ap(a, radio->name);
+ if (fh == NULL)
+ continue;
+
+
+ list_for_each_entry(s, &fh->stalist, list) {
+ // if (fh->cfg->include_sta_stats) {
+ /* Associated STA Traffic Stats TLV */
+ struct tlv_assoc_sta_traffic_stats *p4;
+
+ p4 = agent_gen_assoc_sta_traffic_stats(a, s);
+ if (!p4)
+ goto error;
+
+ cmdu->tlvs[tlv_index++] = (uint8_t *)p4;
+ // }
+
+ // if (fh->cfg->include_sta_metric) {
+ struct tlv_assoc_sta_link_metrics *p5;
+ struct tlv_assoc_sta_ext_link_metric *p6;
+
+ p5 = agent_gen_assoc_sta_link_metrics(a, s, bss->bssid);
+ if (!p5)
+ goto error;
+
+ cmdu->tlvs[tlv_index++] = (uint8_t *)p5;
+
+// #ifdef PROFILE2
+ p6 = agent_gen_assoc_sta_ext_link_metric(a, s, bss->bssid);
+ if (!p6)
+ goto error;
+
+ cmdu->tlvs[tlv_index++] = (uint8_t *)p6;
+// #endif
+ // }
+
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ 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 acf40545f..f126aacb0 100644
--- a/src/core/agent_cmdu_generator.h
+++ b/src/core/agent_cmdu_generator.h
@@ -13,4 +13,10 @@
struct cmdu_cstruct *agent_gen_ap_autoconfig_search(struct agent *a,
struct wifi_radio_element *radio, char *intf_name,
uint8_t profile);
+struct cmdu_cstruct *agent_gen_ap_metrics_response(struct agent *a,
+ struct cmdu_cstruct *rec_cmdu);
+
+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 59b8ea7ce..e5b984b2e 100644
--- a/src/core/agent_map.c
+++ b/src/core/agent_map.c
@@ -54,6 +54,7 @@
#include <wsc.h>
#include "agent_tlv_generator.h"
+#include "agent_cmdu_generator.h"
#define UBUS_TIMEOUT 1000
@@ -860,6 +861,181 @@ int handle_ap_autoconfig_renew(void *agent, struct cmdu_cstruct *cmdu)
return 0;
}
+int get_radio_index(struct agent *a, uint8_t *mac)
+{
+ int i;
+
+ for (i = 0; i < a->num_radios; i++) {
+ if (hwaddr_equal(a->radios[i].macaddr, mac))
+ return i;
+ }
+
+ return -1;
+}
+
+int get_bss_index(struct wifi_radio_element *radio, uint8_t *bssid)
+{
+ int i;
+
+ for (i = 0; i < radio->num_bss; i++) {
+ if (hwaddr_equal(radio->bsslist[i].bssid, bssid))
+ return i;
+ }
+
+ return -1;
+}
+
+int get_radio_and_bss_index(struct agent *a, uint8_t *bssid,
+ int *radio_index)
+{
+ int i;
+ int bss_index;
+
+ for (i = 0; i < a->num_radios; i++) {
+ bss_index = get_bss_index(&a->radios[i], bssid);
+ if (bss_index != -1) {
+ *radio_index = i;
+ return bss_index;
+ }
+ }
+
+ return -1;
+}
+
+/* ifname: some value, 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)
+{
+ int total_bss = 0;
+ int i, j, k;
+ int tlv_index = 0;
+ struct agent *a = (struct agent *)agent;
+ struct wifi_radio_element *radio;
+ struct wifi_bss_element *bss;
+ struct tlv_ap_metric_query *p1;
+
+ if (ifname == NULL) {
+ /* AP Metrics Query TLV */
+ cmdu->num_tlvs++;
+// #ifdef PROFILE2
+ /* AP Radio Identifier TLV */
+ cmdu->num_tlvs += a->num_radios;
+// #endif
+
+ for (i = 0; i < a->num_radios; i++)
+ total_bss += a->radios[i].num_bss;
+
+ } else if (ifname && (ifname[0] != '\0')) {
+ /* AP Metrics Query TLV */
+ cmdu->num_tlvs++;
+// #ifdef PROFILE2
+ /* AP Radio Identifier TLV */
+ cmdu->num_tlvs++;
+// #endif
+
+ radio = wifi_ifname_to_radio_element(a, ifname);
+ if (!radio) {
+ cmdu->num_tlvs = 0;
+ return -1;
+ }
+
+ total_bss = radio->num_bss;
+ }
+
+ cmdu->tlvs = (uint8_t **)calloc(cmdu->num_tlvs, sizeof(uint8_t *));
+ if (!cmdu->tlvs) {
+ cmdu->num_tlvs = 0;
+ return -1;
+ }
+
+
+ p1 = calloc(1, sizeof(*p1));
+ if (!p1)
+ return -1;
+
+ p1->tlv_type = MAP_TLV_AP_METRIC_QUERY;
+ p1->bssid_nr = total_bss;
+ p1->ap_metric_query_bssid = calloc(p1->bssid_nr,
+ sizeof(*p1->ap_metric_query_bssid));
+ if (!p1->ap_metric_query_bssid) {
+ free(p1);
+ return -1;
+ }
+
+ if (ifname == NULL) {
+ struct tlv_ap_radio_identifier *p2;
+
+ k = 0;
+ 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);
+ cmdu->tlvs[tlv_index++] = (uint8_t *)p2;
+ }
+// #endif
+
+ for (j = 0; j < radio->num_bss; j++) {
+ bss = radio->bsslist + j;
+ memcpy(p1->ap_metric_query_bssid[k].bssid,
+ bss->bssid, 6);
+ k++;
+ }
+ }
+
+ } else if (ifname && (ifname[0] != '\0')) {
+ struct tlv_ap_radio_identifier *p2;
+
+ k = 0;
+ radio = wifi_ifname_to_radio_element(a, ifname);
+ if (!radio) {
+ map_free_tlv_cstruct((uint8_t *)p1);
+ return -1;
+ }
+
+// #ifdef PROFILE2
+ p2 = calloc(1, sizeof(*p2));
+ if (p2) {
+ p2->tlv_type = MAP_TLV_AP_RADIO_IDENTIFIER;
+ memcpy(p2->radio_id, radio->macaddr, 6);
+ cmdu->tlvs[tlv_index++] = (uint8_t *)p2;
+ }
+// #endif
+
+ for (i = 0; i < radio->num_bss; i++) {
+ bss = radio->bsslist + i;
+ memcpy(p1->ap_metric_query_bssid[k].bssid,
+ bss->bssid, 6);
+ k++;
+ }
+
+ }
+
+ cmdu->tlvs[tlv_index] = (uint8_t *)p1;
+
+ return 0;
+}
+
+static int prepare_ap_metrics_response(void *agent,
+ struct cmdu_cstruct *rec_cmdu)
+{
+ trace("%s: --->\n", __func__);
+ struct cmdu_cstruct *cmdu;
+ struct agent *a = (struct agent *)agent;
+
+ cmdu = agent_gen_ap_metrics_response(a, rec_cmdu);
+ 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)
{
@@ -1495,6 +1671,7 @@ fail_cmdu:
int handle_ap_metrics_query(void *agent, struct cmdu_cstruct *cmdu)
{
trace("%s: --->\n", __func__);
+ prepare_ap_metrics_response(agent, cmdu);
return 0;
}
diff --git a/src/core/agent_tlv_generator.c b/src/core/agent_tlv_generator.c
index 67d271fe6..532a4a542 100644
--- a/src/core/agent_tlv_generator.c
+++ b/src/core/agent_tlv_generator.c
@@ -725,3 +725,166 @@ struct tlv_searched_role *agent_gen_searched_role(struct agent *a,
return p;
}
+
+struct tlv_radio_metrics *agent_gen_radio_metrics(struct agent *a,
+ int radio_index)
+{
+ struct tlv_radio_metrics *p;
+ struct wifi_radio_element *radio = a->radios + radio_index;
+
+ p = (struct tlv_radio_metrics *)calloc(1, sizeof(*p));
+ if (!p)
+ return NULL;
+
+ p->tlv_type = MAP_TLV_RADIO_METRICS;
+ memcpy(p->radio_id, radio->macaddr, 6);
+ p->noise = radio->anpi;
+ /*
+ * TODO/FIXME:
+ * transmit, receive_self & receive_other;
+ * these params need to be exposed in wifi.radio.<intf>.
+ */
+ p->transmit = radio->tx_utilization;
+ p->receive_self = radio->rx_utilization;
+ p->receive_other = radio->other_utilization;
+
+ return p;
+}
+
+struct tlv_ap_metrics *agent_gen_ap_metrics(struct agent *a,
+ int radio_index, int bss_index)
+{
+ struct tlv_ap_metrics *p;
+ struct wifi_radio_element *radio = a->radios + radio_index;
+ struct wifi_bss_element *bss = radio->bsslist + bss_index;
+
+ p = (struct tlv_ap_metrics *)calloc(1, sizeof(*p));
+ if (!p)
+ return NULL;
+
+ p->tlv_type = MAP_TLV_AP_METRICS;
+ memcpy(p->bssid, bss->bssid, 6);
+ if (bss->is_ac_be) {
+ p->is_ac_be = bss->is_ac_be;
+ memcpy(p->service_param_info_be, bss->est_wmm_be, 3);
+ }
+ if (bss->is_ac_bk) {
+ p->is_ac_bk = bss->is_ac_bk;
+ memcpy(p->service_param_info_bk, bss->est_wmm_bk, 3);
+ }
+ if (bss->is_ac_vo) {
+ p->is_ac_vo = bss->is_ac_vo;
+ memcpy(p->service_param_info_vo, bss->est_wmm_vo, 3);
+ }
+ if (bss->is_ac_vi) {
+ p->is_ac_vi = bss->is_ac_vi;
+ memcpy(p->service_param_info_vi, bss->est_wmm_vi, 3);
+ }
+
+ return p;
+}
+
+struct tlv_ap_ext_metrics *agent_gen_ap_ext_metrics(struct agent *a,
+ int radio_index, int bss_index)
+{
+ struct tlv_ap_ext_metrics *p;
+ struct wifi_radio_element *radio = a->radios + radio_index;
+ struct wifi_bss_element *bss = radio->bsslist + bss_index;
+
+ p = (struct tlv_ap_ext_metrics *)calloc(1, sizeof(*p));
+ if (!p)
+ return NULL;
+
+ p->tlv_type = MAP_TLV_AP_EXTENDED_METRICS;
+ memcpy(p->bssid, bss->bssid, 6);
+ p->uni_bytes_sent = bss->tx_ucast_bytes;
+ p->uni_bytes_recv = bss->rx_ucast_bytes;
+ p->multi_bytes_sent = bss->tx_mcast_bytes;
+ p->multi_bytes_recv = bss->rx_mcast_bytes;
+ p->bro_bytes_sent = bss->tx_bcast_bytes;
+ p->bro_bytes_recv = bss->rx_bcast_bytes;
+
+ return p;
+}
+
+struct tlv_assoc_sta_traffic_stats *agent_gen_assoc_sta_traffic_stats(
+ struct agent *a, struct sta *s)
+{
+ struct tlv_assoc_sta_traffic_stats *p;
+
+ p = (struct tlv_assoc_sta_traffic_stats *)calloc(1, sizeof(*p));
+ if (!p)
+ return NULL;
+
+ p->tlv_type = MAP_TLV_ASSOCIATED_STA_TRAFFIC_STATS;
+ memcpy(p->addr, s->macaddr, 6);
+ p->bytes_sent = s->tx_bytes;
+ p->bytes_received = s->rx_bytes;
+ p->packets_sent = s->tx_pkts;
+ p->packets_received = s->rx_pkts;
+ p->tx_packets_err = s->tx_fail_pkts;
+ p->rx_packets_err = s->rx_fail_pkts;
+
+ return p;
+}
+
+struct tlv_assoc_sta_link_metrics *agent_gen_assoc_sta_link_metrics(
+ struct agent *a, struct sta *s, uint8_t *bssid)
+{
+ int i;
+ struct tlv_assoc_sta_link_metrics *p;
+
+ p = (struct tlv_assoc_sta_link_metrics *)calloc(1, sizeof(*p));
+ if (!p)
+ return NULL;
+
+ p->tlv_type = MAP_TLV_ASSOCIATED_STA_LINK_METRICS;
+ memcpy(p->addr, s->macaddr, 6);
+ /* Reported BSS for specific STA */
+ p->bssid_nr = 1;
+ p->sta_link_metrics_bssid = calloc(p->bssid_nr, sizeof(*p->sta_link_metrics_bssid));
+ if (p->sta_link_metrics_bssid) {
+ for (i = 0; i < p->bssid_nr; i++) {
+ memcpy(p->sta_link_metrics_bssid[i].bssid, bssid, 6);
+ p->sta_link_metrics_bssid[i].time_delta = s->connected_ms;
+ p->sta_link_metrics_bssid[i].dl_mac_data_rate = s->rx_thput;
+ p->sta_link_metrics_bssid[i].ul_mac_data_rate = s->tx_thput;
+ p->sta_link_metrics_bssid[i].ul_rcpi = s->rssi[0];
+ }
+ }
+
+ return p;
+}
+
+struct tlv_assoc_sta_ext_link_metric *agent_gen_assoc_sta_ext_link_metric(
+ struct agent *a, struct sta *s, uint8_t *bssid)
+{
+ int i;
+ struct tlv_assoc_sta_ext_link_metric *p;
+
+ p = (struct tlv_assoc_sta_ext_link_metric *)calloc(1, sizeof(*p));
+ if (!p)
+ return NULL;
+
+ p->tlv_type = MAP_TLV_ASSOCIATED_STA_EXT_LINK_METRICS;
+ memcpy(p->mac, s->macaddr, 6);
+ /* Reported BSS for specific STA */
+ p->nbr_bssid = 1;
+ p->data = calloc(p->nbr_bssid, sizeof(*p->data));
+ if (p->data) {
+ for (i = 0; i < p->nbr_bssid; i++) {
+ memcpy(p->data[i].bssid, bssid, 6);
+ p->data[i].last_data_dwn_rate = s->rx_rate;
+ p->data[i].last_data_up_rate = s->tx_rate;
+ /*
+ * TODO/FIXME:
+ * Need to add parameters for uti_recv, uti_transmit in
+ * wifi.ap.<intf> stations UBUS method.
+ */
+ p->data[i].uti_recv = 101;
+ p->data[i].uti_transmit = 101;
+ }
+ }
+
+ return p;
+}
diff --git a/src/core/agent_tlv_generator.h b/src/core/agent_tlv_generator.h
index 68112982f..d6e67cd34 100644
--- a/src/core/agent_tlv_generator.h
+++ b/src/core/agent_tlv_generator.h
@@ -48,4 +48,16 @@ struct tlv_autoconf_freq_band *agent_gen_autoconf_freq_band(struct agent *a,
uint8_t band);
struct tlv_searched_role *agent_gen_searched_role(struct agent *a,
uint8_t role);
+struct tlv_radio_metrics *agent_gen_radio_metrics(struct agent *a,
+ int radio_index);
+struct tlv_ap_metrics *agent_gen_ap_metrics(struct agent *a,
+ int radio_index, int bss_index);
+struct tlv_ap_ext_metrics *agent_gen_ap_ext_metrics(struct agent *a,
+ int radio_index, int bss_index);
+struct tlv_assoc_sta_traffic_stats *agent_gen_assoc_sta_traffic_stats(
+ struct agent *a, struct sta *s);
+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);
#endif
--
GitLab