From c7197ddbd8cb098eeb646516263fab70e8a5d67b Mon Sep 17 00:00:00 2001
From: Lejla Murselovic <lejla.murselovic@iopsys.eu>
Date: Fri, 19 Feb 2021 08:43:40 +0000
Subject: [PATCH] map-agent: Channel Scan (Section 10.2.2)
---
src/core/agent.c | 174 +++++++++++++++++++++++++++++++++++-----
src/core/agent.h | 1 +
src/core/agent_map.c | 184 +++++++++++++++++++++++++++++++++++++++++--
src/utils/debug.c | 2 +-
4 files changed, 335 insertions(+), 26 deletions(-)
diff --git a/src/core/agent.c b/src/core/agent.c
index 102528b31..defc7d25e 100644
--- a/src/core/agent.c
+++ b/src/core/agent.c
@@ -2600,6 +2600,8 @@ static void parse_radio(struct ubus_request *req, int type,
struct blob_attr *msg)
{
struct wifi_radio_element *re = (struct wifi_radio_element *)req->priv;
+ fprintf(stdout, "%s ---> %s\n", __func__, re->name);
+ int rem, remm, rem1, j = 0, i = 0;
struct blob_attr *tb[11];
static const struct blobmsg_policy radio_attr[11] = {
[0] = { .name = "isup", .type = BLOBMSG_TYPE_BOOL },
@@ -2642,46 +2644,78 @@ static void parse_radio(struct ubus_request *req, int type,
re->rx_streams = blobmsg_get_u8(tb[4]);
if (tb[5]) {
- int rem, rem1, i = 0;
- struct blob_attr *cur;
-
+ struct blob_attr *cur, *cur1;
re->num_supp_opclass = blobmsg_check_array(tb[5], BLOBMSG_TYPE_TABLE);
re->supp_opclass = calloc(re->num_supp_opclass, sizeof(*re->supp_opclass));
if (!re->supp_opclass) {
- fprintf(stderr, "|%s:%d| out of memory!\n", __func__, __LINE__);
+ dbg("|%s:%d| out of memory!\n", __func__, __LINE__);
return;
}
-
+ re->num_scanresult = 1;
+ re->scanlist = calloc(re->num_scanresult, sizeof(*re->scanlist));
+ if (!re->scanlist) {
+ dbg("|%s:%d| out of memory!\n", __func__, __LINE__);
+ return;
+ }
+ re->scanlist->num_opclass_scanned = re->num_supp_opclass;
+ re->scanlist->opclass_scanlist = calloc(re->scanlist->num_opclass_scanned, sizeof(struct wifi_scanres_opclass_element));
+ if (!re->scanlist->opclass_scanlist) {
+ dbg("|%s:%d| out of memory!\n", __func__, __LINE__);
+ return;
+ }
+ // Iterate through all supp_channels (opclasses) in radio
+ // fprintf(stderr, "|%s:%d| DEBUG!\n", __func__, __LINE__); // DEBUG
blobmsg_for_each_attr(cur, tb[5], rem) {
- struct blob_attr *data[3], *cur1;
- static const struct blobmsg_policy supp_attrs[3] = {
+ // fprintf(stderr, "|%s:%d| DEBUG!\n", __func__, __LINE__); // DEBUG
+ struct blob_attr *data[4];
+ static const struct blobmsg_policy supp_attrs[4] = {
[0] = { .name = "opclass", .type = BLOBMSG_TYPE_INT32 },
[1] = { .name = "txpower", .type = BLOBMSG_TYPE_INT32 },
- [2] = { .name = "channels", .type = BLOBMSG_TYPE_ARRAY }
+ [2] = { .name = "channels", .type = BLOBMSG_TYPE_ARRAY },
+ [3] = { .name = "bandwidth", .type = BLOBMSG_TYPE_INT32}
};
int k = 0;
if (blobmsg_type(cur) != BLOBMSG_TYPE_TABLE)
continue;
- blobmsg_parse(supp_attrs, 3, data, blobmsg_data(cur),
+ blobmsg_parse(supp_attrs, 4, data, blobmsg_data(cur),
blobmsg_data_len(cur));
-
- if (!data[0] || !data[1] || i >= re->num_supp_opclass)
+ // for whatever reason it may continue parsing next object
+ if (!data[0] || !data[1] || !data[2] || !data[3] || i >= re->num_supp_opclass)
continue;
-
re->supp_opclass[i].id = (uint8_t) blobmsg_get_u32(data[0]);
re->supp_opclass[i].max_txpower = (int8_t) blobmsg_get_u32(data[1]);
- if (data[2])
- re->supp_opclass[i].num_supported_channels = blobmsg_check_array(data[2], BLOBMSG_TYPE_INT32);
+ if (data[2]) {
+ struct blob_attr *attr;
+ j = 0; // reset iterator through channels for current opclass
+ re->supp_opclass[i].num_supported_channels = blobmsg_check_array(data[2], BLOBMSG_TYPE_INT32);
+ re->scanlist->opclass_scanlist[i].num_channels_scanned = blobmsg_check_array(data[2], BLOBMSG_TYPE_INT32); //lejla
+ //fprintf(stdout,"\t debug num_of_ch: %d\n", re->scanlist->opclass_scanlist[i].num_channels_scanned);
+ re->scanlist->opclass_scanlist[i].channel_scanlist = calloc(re->scanlist->opclass_scanlist[i].num_channels_scanned,
+ sizeof(struct wifi_scanres_channel_element));
+ if (!re->scanlist->opclass_scanlist[i].channel_scanlist) {
+ dbg("|%s:%d| out of memory!\n", __func__, __LINE__);
+ return;
+ }
+ //fprintf(stdout, "\t debug %s %d\n", __func__, __LINE__);
+ re->scanlist->opclass_scanlist[i].opclass = blobmsg_get_u32(data[0]);
+ // Iterate through all channels of the opclass
+ blobmsg_for_each_attr(attr, data[2], remm) {
+ if (blobmsg_type(attr) != BLOBMSG_TYPE_INT32)
+ continue;
+ re->scanlist->opclass_scanlist[i].channel_scanlist[j].channel = blobmsg_get_u32(attr);
+ j++;
+ }
+ //fprintf(stdout, "\t debug %s %d\n", __func__, __LINE__);
+ }
re->supp_opclass[i].supp_chanlist = calloc(re->supp_opclass[i].num_supported_channels, sizeof(struct supp_channel));
if (!re->supp_opclass[i].supp_chanlist) {
- fprintf(stderr, "|%s:%d| out of memory!\n", __func__, __LINE__);
+ dbg("|%s:%d| out of memory!\n", __func__, __LINE__);
return;
}
-
blobmsg_for_each_attr(cur1, data[2], rem1) {
re->supp_opclass[i].supp_chanlist[k].channel = blobmsg_get_u32(cur1);
re->supp_opclass[i].supp_chanlist[k].pref = 0xff;
@@ -2698,11 +2732,11 @@ static void parse_radio(struct ubus_request *req, int type,
re->supp_opclass[i].num_exclude_channels * sizeof(uint8_t));
}
}
-
+ if (data[3])
+ re->scanlist->opclass_scanlist[i].bandwidth = blobmsg_get_u32(data[3]);
i++;
}
}
-
if (tb[6])
re->current_opclass = (uint8_t) blobmsg_get_u32(tb[6]);
@@ -2724,6 +2758,98 @@ static void parse_radio(struct ubus_request *req, int type,
}
}
+static struct wifi_scanres_channel_element *wifi_get_scanres_ch_element(struct wifi_radio_element *re, uint8_t ch, uint8_t num_sr)
+{
+ uint32_t num_all_channels, opc;
+
+ for (int i = 0; i < num_sr; i++) {
+ num_all_channels = re->scanlist->opclass_scanlist[i].num_channels_scanned;
+ opc = re->scanlist->opclass_scanlist[i].opclass;
+ for (int j = 0; j < num_all_channels; j++) {
+ if (re->scanlist->opclass_scanlist[i].channel_scanlist[j].channel == ch && re->scanlist->opclass_scanlist[i].bandwidth == 20)
+ return &re->scanlist->opclass_scanlist[i].channel_scanlist[j];
+ }
+ }
+ fprintf(stderr, "No operating class with channel %d\n", ch);
+ return 0;
+}
+
+static void parse_scanresults(struct ubus_request *req, int type, struct blob_attr *msg)
+{
+ fprintf(stdout, "%s --->\n", __func__);
+ int rem, i = 0; // i iterator through scanresults
+ int f = 0; // index for filling neighbors
+ struct wifi_radio_element *re = (struct wifi_radio_element *)req->priv;
+ struct blob_attr *tb[1], *cur;
+
+ static const struct blobmsg_policy scan_attr[1] = {
+ [0] = { .name = "accesspoints", .type = BLOBMSG_TYPE_ARRAY }
+ };
+
+ blobmsg_parse(scan_attr, 1, tb, blob_data(msg), blob_len(msg));
+
+ if (!tb[0])
+ fprintf(stderr, "%s | Scanresults not parsed.", __func__);
+ int num_sr = blobmsg_check_array(tb[0], BLOBMSG_TYPE_TABLE);
+
+ // Iterate through all access points (neighbors) from *scanresult*
+ blobmsg_for_each_attr(cur, tb[0], rem) {
+ struct blob_attr *data[7];
+ static const struct blobmsg_policy ap_attrs[7] = {
+ [0] = { .name = "ssid", .type = BLOBMSG_TYPE_STRING },
+ [1] = { .name = "bssid", .type = BLOBMSG_TYPE_STRING },
+ [2] = { .name = "channel", .type = BLOBMSG_TYPE_INT32 },
+ [3] = { .name = "bandwidth", .type = BLOBMSG_TYPE_INT32 },
+ [4] = { .name = "rssi", .type = BLOBMSG_TYPE_INT32 },
+ [5] = { .name = "load_stas", .type = BLOBMSG_TYPE_INT32 },
+ [6] = { .name = "load_utilization", .type = BLOBMSG_TYPE_INT32 }
+ };
+
+ // Conditions for parsing the object
+ if (blobmsg_type(cur) != BLOBMSG_TYPE_TABLE) {
+ fprintf(stderr, "|%s:%d|\n", __func__, __LINE__);
+ continue;
+ }
+
+ //if (missing data){
+ if (!data[0] || !data[1] || !data[2] || !data[3] || !data[4] || !data[5] || !data[6] || i >= num_sr) {
+ fprintf(stderr, "|%s:%d|\n", __func__, __LINE__);
+ continue;
+ }
+
+ // Now if the conditions are passed we can parse the object
+ blobmsg_parse(ap_attrs, 7, data, blobmsg_data(cur), blobmsg_data_len(cur));
+ int current_channel_of_scanres_el = blobmsg_get_u32(data[2]);
+ struct wifi_scanres_channel_element *scanres_el;
+ scanres_el = wifi_get_scanres_ch_element(re, current_channel_of_scanres_el, num_sr);
+ if (!scanres_el)
+ continue;
+ // if no neighbors, allocated
+ if (scanres_el->num_neighbors == 0) {
+ scanres_el->num_neighbors++;
+ scanres_el->nbrlist = malloc(1 * sizeof(*(scanres_el->nbrlist)));
+ }
+ // If has neighbors, allocate one addiotnal neighbor
+ else {
+ scanres_el->num_neighbors++;
+ scanres_el->nbrlist = realloc(scanres_el->nbrlist, scanres_el->num_neighbors * sizeof(*(scanres_el->nbrlist)));
+ }
+ f = scanres_el->num_neighbors - 1; // fill index
+ // Fill in the neoghbour data
+ char bssid_string[18] = {0};
+ char ssid_string[33] = {0};
+
+ strncpy(scanres_el->nbrlist[f].ssid, blobmsg_data(data[0]), sizeof(scanres_el->nbrlist->ssid) - 1);
+ strncpy(bssid_string, blobmsg_data(data[1]), sizeof(bssid_string) - 1);
+ hwaddr_aton(bssid_string, scanres_el->nbrlist[f].bssid);
+ scanres_el->nbrlist[f].rssi = blobmsg_get_u32(data[4]);
+ scanres_el->nbrlist[f].bw = blobmsg_get_u32(data[3]);
+ scanres_el->nbrlist[f].utilization = blobmsg_get_u32(data[6]);
+ scanres_el->nbrlist[f].num_stations = blobmsg_get_u32(data[5]);
+ i++;
+ };
+}
+
static void _enumerate_wifi_objects(struct ubus_request *req, int type,
struct blob_attr *msg)
{
@@ -2816,9 +2942,17 @@ static void _enumerate_wifi_objects(struct ubus_request *req, int type,
// r_objname, f->name);
continue;
}
+ // ubus call wifi.radio.wl0 status
+ ubus_call_object(a, r_wobj, "status", parse_radio, &a->radios[i]);
+
+ // ubus call wifi.radio.wl0 scan
+ ubus_call_object(a, r_wobj, "scan", NULL, &a->radios[i]);
+ fprintf(stderr, "Scaning neighbors.....");
+ sleep(5); // TODO : week 8
+ fprintf(stderr, "DONE\n");
- ubus_call_object(a, r_wobj, "status", parse_radio,
- &a->radios[i]);
+ // ubus call wifi.radio.wl0 scanresults
+ ubus_call_object(a, r_wobj, "scanresults", parse_scanresults, &a->radios[i]);
}
out_json:
diff --git a/src/core/agent.h b/src/core/agent.h
index 92eb344ba..f6e5eb6d7 100644
--- a/src/core/agent.h
+++ b/src/core/agent.h
@@ -321,6 +321,7 @@ struct wifi_scanres_channel_element {
struct wifi_scanres_opclass_element {
uint8_t opclass;
+ uint32_t bandwidth;
uint32_t num_channels_scanned;
struct wifi_scanres_channel_element *channel_scanlist;
};
diff --git a/src/core/agent_map.c b/src/core/agent_map.c
index de486af28..eefabba14 100644
--- a/src/core/agent_map.c
+++ b/src/core/agent_map.c
@@ -7,7 +7,7 @@
*
*/
-
+#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
@@ -609,6 +609,22 @@ struct netif_fh *wifi_get_netif_by_bssid(struct agent *a, uint8_t *bssid)
if (hwaddr_equal(fh->bssid, bssid))
return fh;
}
+}
+
+static struct wifi_radio_element *wifi_get_radio_index_by_mac(struct agent *a,
+ uint8_t *hwaddr)
+{
+ struct wifi_radio_element *radio;
+ int i;
+
+ for (i = 0; i < a->num_radios; i++) {
+ radio = a->radios + i;
+
+ if (memcmp(radio->macaddr, hwaddr, 6))
+ continue;
+
+ return i;
+ }
return NULL;
}
@@ -2778,10 +2794,168 @@ out_cmdu:
return -1;
}
+char *get_timestamp(time_t *t, char **tbuf)
+{
+ char tmpbuf[64] = {0};
+ struct tm res;
+ char sign;
+ long toff, toff_hour, toff_min;
+ const time_t now = time(t);
+
+ //if (!tbuf)
+ // return NULL;
+
+ /* E.g. "2019-02-11T06:42:31.23039-08:00" */
+
+ localtime_r(&now, &res);
+ tzset();
+ toff = timezone;
+ sign = toff > 0 ? '-' : '+';
+ toff *= -1L;
+
+ toff_hour = toff / 3600;
+ toff_min = (toff % 3600) / 60;
+
+ snprintf(tmpbuf, 63, "%04d-%02d-%02dT%02d:%02d:%02d%c%02ld:%02ld",
+ res.tm_year + 1900, res.tm_mon, res.tm_mday, res.tm_hour, res.tm_min, res.tm_sec, sign, toff_hour, toff_min);
+ if (!*tbuf) {
+ *tbuf = calloc(1, strlen(tmpbuf) + 1);
+ if (!*tbuf)
+ return NULL;
+ }
+
+ sprintf(*tbuf, "%s", tmpbuf);
+ return *tbuf;
+}
+
+static void scan_results(struct agent *a, struct tlv_ch_scan_res *p, uint32_t radio_index, uint32_t opclass_index, uint32_t channel_index)
+{
+
+ struct wifi_radio_element *radio = a->radios + radio_index;
+ struct wifi_scanres_opclass_element *op = radio->scanlist[0].opclass_scanlist + opclass_index;
+ struct wifi_scanres_channel_element *ch = op->channel_scanlist + channel_index;
+ int i;
+ char bw_str[16] = {0};
+
+ memcpy(p->radio_id, radio->macaddr, 6);
+ p->op_class = op->opclass;
+ p->ch = ch->channel;
+ p->scan_res = CH_SCAN_STATUS_SUCCESS;
+ if (p->scan_res == CH_SCAN_STATUS_SUCCESS) {
+ get_timestamp(NULL, &p->timestamp);
+ p->time_len = strlen(p->timestamp);
+ p->utilization = ch->utilization;
+ p->noise = ch->anpi;
+ p->nbr_neighbors = ch->num_neighbors;
+ p->neighbor_data = calloc(p->nbr_neighbors, sizeof(*(p->neighbor_data)));
+ if (p->neighbor_data) {
+ for (i = 0; i < p->nbr_neighbors; i++) {
+ struct wifi_scanres_neighbor_element *nbr = ch->nbrlist + i;
+
+ memcpy(p->neighbor_data[i].bssid, nbr->bssid, 6);
+ p->neighbor_data[i].ssid = strdup(nbr->ssid);
+ p->neighbor_data[i].ssid_len = strlen(p->neighbor_data[i].ssid);
+ p->neighbor_data[i].signal_strength = nbr->rssi;
+ p->neighbor_data[i].bss_load_elm_present = 1;
+
+ snprintf(bw_str, 15, "%d", nbr->bw);
+ p->neighbor_data[i].ch_bandwidth = strdup(bw_str);
+ p->neighbor_data[i].ch_band_len = strlen(p->neighbor_data[i].ch_bandwidth);
+
+ if (p->neighbor_data[i].bss_load_elm_present == 1) {
+ p->neighbor_data[i].ch_util = nbr->utilization;
+ p->neighbor_data[i].sta_count = nbr->num_stations;
+ }
+ }
+ }
+ }
+}
+
int handle_channel_scan_request(void *agent, struct cmdu_cstruct *cmdu)
{
trace("%s: --->\n", __func__);
- return 0;
+ struct agent *a = (struct agent *) agent;
+ uint16_t tlv_index = 0;
+ uint32_t i, j, k;
+
+ int radio_index;
+ int opclass_index;
+ int channel_index;
+
+ struct cmdu_cstruct *cmdu_data;
+ int ret;
+ // The received TLV
+ uint8_t *tmp = NULL;
+
+ tmp = cmdu->tlvs[0];
+ if (*tmp != MAP_TLV_CHANNEL_SCAN_REQ) {
+ dbg("Wrong received TLV type!\n");
+ return -1;
+ }
+ struct tlv_ch_scan_req *query = (struct tlv_ch_scan_req *)tmp;
+ // Allocate the cmdu
+ cmdu_data = (struct cmdu_cstruct *)calloc(1, sizeof(struct cmdu_cstruct));
+ if (!cmdu_data) {
+ dbg("Out of memory!\n");
+ return -1;
+ }
+ // Define the cmdu
+ cmdu_data->message_type = CMDU_CHANNEL_SCAN_REPORT;
+ cmdu_data->message_id = cmdu->message_id;
+ strcpy(cmdu_data->intf_name, cmdu->intf_name);
+ memcpy(cmdu_data->origin, cmdu->origin, 6);
+ cmdu_data->num_tlvs = 1 + query->radio_data->op_class_data->nbr_ch;
+
+ // Allocate the TLVs
+ cmdu_data->tlvs = (uint8_t **)calloc(cmdu_data->num_tlvs, sizeof(uint8_t *));
+ if (!cmdu_data->tlvs) {
+ map_free_cmdu(cmdu_data);
+ return -1;
+ }
+ // Define the TLVs
+ /* Timestamp */
+ struct tlv_timestamp *p = (struct tlv_timestamp *)calloc(1, sizeof(struct tlv_timestamp));
+
+ if (p) {
+ p->tlv_type = MAP_TLV_TIMESTAMP;
+ get_timestamp(NULL, &p->time);
+ p->time_len = strlen(p->time);
+ cmdu_data->tlvs[tlv_index++] = (uint8_t *)p;
+ trace("|%s:%d| Added %s\n", __func__, __LINE__, map_stringify_tlv_type(*cmdu_data->tlvs[tlv_index-1]));
+ }
+
+ /* Channel scan result */
+ struct wifi_radio_element *radio = a->radios;
+ /* Assuming one radio */
+ radio_index = wifi_get_radio_index_by_mac(a, query->radio_data->radio_id);
+ // Go through the channel list from the query
+ for (int k = 0; k < query->radio_data->op_class_data->nbr_ch; k++) {
+ uint8_t query_channel = query->radio_data->op_class_data->ch[k];
+
+ for (int i = 0; i < radio->scanlist->num_opclass_scanned; i++) {
+ for (int j = 0; j < radio->scanlist->opclass_scanlist[i].num_channels_scanned; j++) {
+ if (radio->scanlist->opclass_scanlist[i].channel_scanlist[j].channel == query_channel) {
+ opclass_index = i;
+ channel_index = j;
+ struct tlv_ch_scan_res *p1 = (struct tlv_ch_scan_res *)calloc(1, sizeof(struct tlv_ch_scan_res));
+
+ if (p1) {
+ p1->tlv_type = MAP_TLV_CHANNEL_SCAN_RES;
+ scan_results(a, p1, radio_index, opclass_index, channel_index);
+ cmdu_data->tlvs[tlv_index++] = (uint8_t *)p1;
+ trace("|%s:%d| Added %s for channel %d\n", __func__, __LINE__, map_stringify_tlv_type(*cmdu_data->tlvs[tlv_index-1]), query_channel);
+ goto found;
+ }
+ }
+ }
+ }
+found:
+ continue;
+ }
+ // Send cmdu
+ ret = agent_send_cmdu(a, cmdu_data);
+ map_free_cmdu(cmdu_data);
+ return ret;
}
int handle_cac_request(void *agent, struct cmdu_cstruct *cmdu)
@@ -3012,7 +3186,7 @@ static void send_cmdu_cb(struct ubus_request *req,
if (json_object_object_get_ex(jobj, "mid", &tmp)) {
*mid = json_object_get_int(tmp);
- fprintf(stdout, "%s:%d map-mid:%d\n", __func__, __LINE__, *mid);
+ fprintf(stdout, "%s:%d agent map-mid:%d\n", __func__, __LINE__, *mid);
}
json_object_put(jobj);
@@ -3095,7 +3269,7 @@ int agent_send_cmdu(struct agent *a, struct cmdu_cstruct *cmdu)
trace("[%s:%d] not present", __func__, __LINE__);
goto out;
}
- test_cmdu(cmdu);
+ fprintf(stderr, " %s -", __func__); test_cmdu(cmdu);
ret = ubus_invoke(a->ubus_ctx, id, "send",
b.head, send_cmdu_cb,
(void *)&msgid,
@@ -3146,7 +3320,7 @@ int agent_handle_map_event(struct agent *a, uint16_t cmdutype, uint16_t mid,
if (f[idx]) {
cmdu = map_build_cmdu(cmdutype, mid, rxif, src, tlvs);
if (cmdu) {
- test_cmdu(cmdu);
+ fprintf(stderr, " %s -", __func__); test_cmdu(cmdu);
ret = f[idx](a, cmdu);
map_free_cmdu(cmdu);
} else {
diff --git a/src/utils/debug.c b/src/utils/debug.c
index 411077e28..b2a320b93 100644
--- a/src/utils/debug.c
+++ b/src/utils/debug.c
@@ -196,7 +196,7 @@ void log_test(int level, void *var, int len)
btostr(var, len, bstr);
- printf("%s %d bstr = %s\n", __func__, __LINE__, bstr);
+ printf("%s %d agent bstr = %s\n", __func__, __LINE__, bstr);
fprintf(testfile, "%s\n", bstr);
fflush(testfile);
--
GitLab