diff --git a/src/core/cntlr.c b/src/core/cntlr.c index 853cc3ad0971eaf1449a7690f1b04237ca9c716d..5ecdc0e8725dea09f7b0239d9f90bf86653366f7 100644 --- a/src/core/cntlr.c +++ b/src/core/cntlr.c @@ -1835,7 +1835,6 @@ static void cntlr_ieee1905_cmdu_event_handler(void *cntlr, strtob(tlvstr, len, tlv); free(tlvstr); } - cntlr_handle_map_event(c, type, mid, in_ifname, srcmac, origin, tlv, len); if (tlv) @@ -2199,6 +2198,8 @@ static void mapclient_subscribe_for_cmdus(struct controller *c) CMDU_BEACON_METRICS_RESPONSE, CMDU_AP_METRICS_RESPONSE, CMDU_ASSOC_STA_LINK_METRICS_RESPONSE, + CMDU_CHANNEL_SCAN_REQUEST, + CMDU_CHANNEL_SCAN_REPORT, -1); trace("<----------------------------------- %s\n", __func__); diff --git a/src/core/cntlr_cmdu_generator.c b/src/core/cntlr_cmdu_generator.c index 39f1f47b3988ca3c48999e87c5c1f8b60af270da..9254e6792be70f7e613d5940ef29b4911e5e3f15 100644 --- a/src/core/cntlr_cmdu_generator.c +++ b/src/core/cntlr_cmdu_generator.c @@ -624,7 +624,37 @@ struct cmdu_buff *cntlr_gen_cmdu_1905_ack(struct controller *c, continue; } + cmdu_put_eom(resp); + return resp; +} +struct cmdu_buff *cntlr_gen_channel_scan_request(struct controller *c, + char *agent, uint8_t num_radios, uint8_t *num_ch_to_scan, + uint8_t **channel, char (*radio)[18]) +{ + int ret, mid; + struct cmdu_buff *resp; + uint8_t origin[6]; + + /* Allocate the cmdu_data structure */ + resp = cmdu_alloc_frame(3000); + if (!resp) { + trace("%s: -ENOMEM\n", __func__); + return NULL; + } + cmdu_set_type(resp, CMDU_CHANNEL_SCAN_REQUEST); + cmdu_set_mid(resp, mid); + strncpy(resp->dev_ifname, c->cfg.al_bridge, 15); + ret = cntlr_gen_channel_scan_req(c, resp, num_radios, num_ch_to_scan, channel, radio); + if (ret) + return NULL; + + if (!hwaddr_aton(agent, origin)) { + dbg("failed to hwaddr cmdu origin\n"); + return UBUS_STATUS_UNKNOWN_ERROR; + } + + memcpy(resp->origin, origin, 6); cmdu_put_eom(resp); return resp; } diff --git a/src/core/cntlr_cmdu_generator.h b/src/core/cntlr_cmdu_generator.h index 74ddfb3bb5513bb29630aebe8f56a82dbdc1d4a5..0013b7a9cd09ceaf26013ec3f44d585bda3b217c 100644 --- a/src/core/cntlr_cmdu_generator.h +++ b/src/core/cntlr_cmdu_generator.h @@ -47,4 +47,8 @@ struct cmdu_buff *cntlr_gen_topology_query(struct controller *c, struct cmdu_buff *cntlr_gen_cmdu_1905_ack(struct controller *c, struct cmdu_buff *rx_cmdu, struct sta_error_response *sta_resp, uint32_t sta_count); +struct cmdu_buff *cntlr_gen_channel_scan_request(struct controller *c, + char *agent, + uint8_t num_radios, uint8_t *num_ch_to_scan, + uint8_t **channel, char (*radio)[18]); #endif diff --git a/src/core/cntlr_map.c b/src/core/cntlr_map.c index 61acebfde9e5d27b6515949e8a07cc5859ce30c7..6a576757c7d3f99a0c96ac1a99926c28939fbd73 100644 --- a/src/core/cntlr_map.c +++ b/src/core/cntlr_map.c @@ -591,8 +591,100 @@ int handle_backhaul_sta_steer_response(void *cntlr, struct cmdu_buff *cmdu) int handle_channel_scan_report(void *cntlr, struct cmdu_buff *cmdu) { trace("%s: --->\n", __func__); -// trace("parsing channel scan report of |%s:" MACFMT "|\n", -// cmdu->intf_name, MAC2STR(cmdu->origin)); + trace("parsing channel scan report of |" MACFMT "|\n", MAC2STR(cmdu->origin)); + + struct tlv *tv[2][16]; + struct tlv_policy d_policy[] = { + [0] = { .type = MAP_TLV_TIMESTAMP, .present = TLV_PRESENT_ONE }, + [1] = { .type = MAP_TLV_CHANNEL_SCAN_RES, .present = TLV_PRESENT_NUM } + }; + int num = 0; + int offset = 0; + uint8_t time_len; + uint16_t num_neightbor; + uint8_t ssid_len; + uint8_t bw_len; + uint8_t *tv_data; + + cmdu_parse_tlvs(cmdu, tv, d_policy, 2); + + if (!tv[0][0]) { + dbg("No TIMESTAMP_TLV received!\n"); + return -1; + } + + if (!tv[1][0]) { + dbg("No RESULT_TLV received!\n"); + return -1; + } + if (tv[0][0]->type != MAP_TLV_TIMESTAMP) { + dbg("Wrong received TLV type!\n"); + return -1; + } + + trace("\nTLV type: MAP_TLV_TIMESTAMP\n"); + tv_data = (uint8_t *)tv[0][0]->data; + struct tlv_timestamp *p = (struct tlv_timestamp *)tv_data; + + char timestamp[32] = {0}; + trace("\tlen: %d\n", p->len); + strncpy(timestamp, (char *)p->timestamp, p->len); + trace("\ttimestamp: %s\n", timestamp); + trace("\n"); + + while (tv[1][num]) { + if (tv[1][num]->type != MAP_TLV_CHANNEL_SCAN_RES) { + dbg("Wrong received TLV type!\n"); + return -1; + } + trace("\nTLV type: MAP_TLV_CHANNEL_SCAN_RES\n"); + tv_data = (uint8_t *)tv[1][num]->data; + struct tlv_channel_scan_result *p1 = (struct tlv_channel_scan_result *)tv_data; + + trace("\tradio: " MACFMT "\n", MAC2STR(p1->radio)); + trace("\topclass: %d\n", p1->opclass); + trace("\tchannel: %d\n", p1->channel); + trace("\tstatus: 0x%02x\n", p1->status); + + offset = sizeof(*p1); + if (p1->status == 0x00) { + time_len = tv_data[offset++]; + trace("\tlen: %d\n", time_len - 1); + trace("\ttimestamp: "); + for (int i = 0; i < time_len; i++) + trace("%c", tv_data[offset++]); + trace("\n"); + // offset += time_len; + + trace("\tutilization: %d\n", tv_data[offset++]); + trace("\tnoise: %d\n", tv_data[offset++]); + num_neightbor = BUF_GET_BE16(tv_data[offset]); + trace("\tnum_neighbor: %d\n", num_neightbor); + offset += 2; + for (int j = 0; j < num_neightbor; j++) { + trace("\n\t\tbssid: " MACFMT "\n", MAC2STR(&tv_data[offset])); + offset += 6; + ssid_len = tv_data[offset++]; + trace("\t\tlen: %d\n", ssid_len); + char ssidstr[33] = {0}; + strncpy(ssidstr, (char *)&tv_data[offset], ssid_len); + trace("\t\tssid: %s\n", ssidstr); + offset += ssid_len; + trace("\t\trcpi: %d\n", (int)tv_data[offset++]); + bw_len = tv_data[offset++]; + trace("\t\tlen: %d\n", bw_len); + trace("\t\tbwstr: %d\n", atoi(&tv_data[offset])); + offset += bw_len; + trace("\t\tinfo: %d\n", tv_data[offset++]); + trace("\t\tch_util: %d\n", tv_data[offset++]); + trace("\t\tsta_count: %d\n", tv_data[offset++]); + offset++; /* sta_count is 2 byte*/ + } + } + num++; + trace("\n"); + } + return 0; } diff --git a/src/core/cntlr_map_debug.c b/src/core/cntlr_map_debug.c index a6602b9bc62d934eb4df9f32ec8575970855ebec..6019ed52c835effda9b084a6db0a98865d89bb36 100644 --- a/src/core/cntlr_map_debug.c +++ b/src/core/cntlr_map_debug.c @@ -1095,10 +1095,7 @@ int debug_backhaul_sta_steer_response(void *cntlr, struct cmdu_buff *cmdu) int debug_channel_scan_report(void *cntlr, struct cmdu_buff *cmdu) { - trace("%s: --->\n", __func__); return 0; -// trace("parsing channel scan report of |%s:" MACFMT "|\n", cmdu->intf_name, -// MAC2STR(cmdu->origin)); // int i, j; // uint8_t *tlv = NULL; // diff --git a/src/core/cntlr_tlv_generator.c b/src/core/cntlr_tlv_generator.c index c946f8fb8ade4d7036b5dbb331f239d2bfffc551..24c1d5df81f9eaf08a4cf8d164926685ef41bb91 100644 --- a/src/core/cntlr_tlv_generator.c +++ b/src/core/cntlr_tlv_generator.c @@ -1113,3 +1113,59 @@ int cntlr_gen_tlv_error_code(struct controller *c, return 0; } + +int cntlr_gen_channel_scan_req(struct controller *c, struct cmdu_buff *frm, + uint8_t num_radios, uint8_t *num_ch_to_scan, uint8_t **channel, char (*radio)[18]) +{ + struct tlv *t; + struct tlv_channel_scan_request *data; + struct channel_scan_request_radio *radio_data; + struct channel_scan_request_opclass *opclass_data; + uint8_t *channel_data; + int ret, offset; + uint8_t radiomac[6]; + + /* Allocate the TLV of the cmdu_data */ + t = cmdu_reserve_tlv(frm, 512); + if (!t) + return -1; + + /* Define the TLV */ + t->type = MAP_TLV_CHANNEL_SCAN_REQ; + data = (struct tlv_channel_scan_request *) t->data; + data->mode = SCAN_REQUEST_FRESH_SCAN; + data->num_radio = num_radios; + offset = sizeof(*data); + + for (int i = 0; i < data->num_radio; i++) { + radio_data = (struct channel_scan_request_radio *)&t->data[offset]; + if (!hwaddr_aton(radio[i], radio_data->radio)) { + dbg("failed to hwaddr radio_id\n"); + return UBUS_STATUS_UNKNOWN_ERROR; + } + radio_data->num_opclass = 1; /* TODO */ + offset += sizeof(*radio_data); + + for (int j = 0; j < radio_data->num_opclass; j++) { + opclass_data = (struct channel_scan_request_opclass *) &t->data[offset]; + opclass_data->classid = 80; + opclass_data->num_channel = num_ch_to_scan[i]; + offset += sizeof(*opclass_data); + + channel_data = (uint8_t *) &t->data[offset]; + memcpy(channel_data, channel[i], opclass_data->num_channel); + + offset += opclass_data->num_channel; + } + } + /* Update the TLV length */ + t->len = offset; + + ret = cmdu_put_tlv(frm, t); + if (ret) { + dbg("%s: error: cmdu_put_tlv()\n", __func__); + return -1; + } + + return 0; +} diff --git a/src/core/cntlr_tlv_generator.h b/src/core/cntlr_tlv_generator.h index 182f9527efbd547a911c2ea8f0abffec86ef0a6c..a8b44b451b6ade984ca9f8f6f8455667b63001e5 100644 --- a/src/core/cntlr_tlv_generator.h +++ b/src/core/cntlr_tlv_generator.h @@ -51,6 +51,9 @@ struct tlv_client_info *cntlr_gen_client_info(struct controller *c, int cntlr_gen_backhaul_steer_req(struct controller *c, struct cmdu_buff *frm, uint8_t *macaddr, uint8_t *target_bssid, uint8_t op_class, uint8_t channel); +int cntlr_gen_channel_scan_req(struct controller *c, struct cmdu_buff *frm, + uint8_t num_radios, uint8_t *num_ch_to_scan, uint8_t **channel, + char (*radio)[18]); struct tlv_steer_request *cntlr_gen_client_steering_req( char *bss_id, uint32_t steer_timeout, uint32_t sta_nr, char sta_id[][18], uint32_t bssid_nr, diff --git a/src/core/cntlr_ubus.c b/src/core/cntlr_ubus.c index 00627eb874d639d04c630570cf45be3d3923e4bf..931dc37b64be85101740ad181d5dc4a6759c293d 100644 --- a/src/core/cntlr_ubus.c +++ b/src/core/cntlr_ubus.c @@ -1407,169 +1407,111 @@ static int cntlr_scan(struct ubus_context *ctx, struct ubus_object *obj, struct blob_attr *msg) { trace("|%s:%d| Parsing the message\n", __func__, __LINE__); + struct blob_attr *tb[__SCAN_POLICY_MAX]; + struct controller *c = container_of(obj, struct controller, obj); + char agent[18] = {0}; + uint8_t radiomac[6] = {0}; + uint8_t (*radio)[6] = {0}; + char (*radio_str)[18] = {0}; + uint8_t **channel; /* array of channels per radio */ + uint8_t *num_ch_to_scan; /* array of number of channels per radio */ + uint8_t num_radios; /* number of radios */ + uint8_t num_ch_arrays; + struct cmdu_buff *cmdu_data; + int rem, rem1, i, j, valid; + struct blob_attr *attr, *cur; + + blobmsg_parse(scan_policy_params, __SCAN_POLICY_MAX, tb, + blob_data(msg), blob_len(msg)); + + if (!tb[SCAN_POLICY_AGENT]) { + dbg("Must provide agent mac address\n"); + return UBUS_STATUS_INVALID_ARGUMENT; + } + + if (!tb[SCAN_POLICY_RADIO]) { + dbg("Must provide radio mac address\n"); + return UBUS_STATUS_INVALID_ARGUMENT; + } + + // if (!tb[SCAN_POLICY_OP_CLASS]){ //OP + // dbg("Must provide operating class\n"); + // return UBUS_STATUS_INVALID_ARGUMENT; + // } + + if (!tb[SCAN_POLICY_CHANNEL]) { + dbg("Must provide channel\n"); + return UBUS_STATUS_INVALID_ARGUMENT; + } + + strncpy(agent, blobmsg_data(tb[SCAN_POLICY_AGENT]), sizeof(agent) - 1); + num_ch_arrays = blobmsg_check_array(tb[SCAN_POLICY_CHANNEL], BLOBMSG_TYPE_ARRAY); + num_radios = blobmsg_check_array(tb[SCAN_POLICY_RADIO], BLOBMSG_TYPE_STRING); + if (num_radios != num_ch_arrays) { + dbg("Number of channel arrays has to be the same as number of radios\n"); + return -1; + } + /* Allocate the arrays for channel and radio */ + num_ch_to_scan = calloc(num_radios, sizeof(uint8_t)); + if (!num_ch_to_scan) { + dbg("Out of memory!\n"); + return -1; + } + channel = (uint8_t **)calloc(num_radios, sizeof(uint8_t *)); + if (!channel) { + dbg("Out of memory for channels!\n"); + return -1; + } + radio_str = calloc(num_radios, 18*sizeof(char)); + if (!radio_str) { + dbg("Out of memory for radios!\n"); + return -1; + } + i = 0; + rem = 0; + rem1 = 0; + /* Radio */ + blobmsg_for_each_attr(attr, tb[SCAN_POLICY_RADIO], rem) { + if (blobmsg_type(attr) != BLOBMSG_TYPE_STRING) { + dbg("|%s:%d| Radios have to be string.\n", __func__, __LINE__); + continue; + } + strncpy(radio_str[i], blobmsg_data(attr), 17); + i++; + } + i = 0; + /* Array of channels (attr - current array) */ + blobmsg_for_each_attr(attr, tb[SCAN_POLICY_CHANNEL], rem) { + if (blobmsg_type(attr) != BLOBMSG_TYPE_ARRAY) { + dbg("|%s:%d| Channels have to be grouped into arrays.\n", __func__, __LINE__); + continue; + } + num_ch_to_scan[i] = blobmsg_check_array(attr, BLOBMSG_TYPE_INT32); + channel[i] = calloc(num_ch_to_scan[i], sizeof(uint8_t)); + if (!channel[i]) { + dbg("Out of memory!\n"); + return -1; + } + trace("|%s:%d| Radio: %s | Scan request for channels:", __func__, __LINE__, radio_str[i]); + /* Channels (cur - current channel) */ + blobmsg_for_each_attr(cur, attr, rem1) { + channel[i][j] = (uint8_t)blobmsg_get_u32(cur); + if (channel[i][j] <= 0) { + trace("Send the valid channel data\n"); + return -1; + } + trace(" %d", channel[i][j]); + j++; + } + if (j == 0) /* all_ch_scan */ + trace(" all"); + trace("\n"); + i++; j = 0; + } + cmdu_data = cntlr_gen_channel_scan_request(c, agent, num_radios, num_ch_to_scan, channel, radio_str); + send_cmdu(c, cmdu_data); + cmdu_free(cmdu_data); return 0; -// struct blob_attr *tb[__SCAN_POLICY_MAX]; // array of blob_attr // blob_attr = id, value // tb[id] = value -// struct tlv_ch_scan_req *p; //struct def in map2.h -// struct controller *c = container_of(obj, struct controller, obj); -// char agent[18] = {0}; -// char (*radio)[18] = {0}; -// // uint32_t op_class; -// uint8_t **channel; // array of channels per radio -// int *num_ch_to_scan; // array of number of channels per radio -// int num_radios; // number of radios -// struct cmdu_cstruct *cmdu_data; -// -// // parce the msg from the ubus method "scan" given by the user -// // based on the policy parameters -// blobmsg_parse(scan_policy_params, __SCAN_POLICY_MAX, tb, -// blob_data(msg), blob_len(msg)); -// -// // are the ubus method parameter empty? -// if (!tb[SCAN_POLICY_AGENT]) { -// dbg("Must provide agent mac address\n"); -// return UBUS_STATUS_INVALID_ARGUMENT; -// } -// -// if (!tb[SCAN_POLICY_RADIO]) { -// dbg("Must provide radio mac address\n"); -// return UBUS_STATUS_INVALID_ARGUMENT; -// } -// -// // if (!tb[SCAN_POLICY_OP_CLASS]){ //OP -// // dbg("Must provide operating class\n"); -// // return UBUS_STATUS_INVALID_ARGUMENT; -// // } -// -// if (!tb[SCAN_POLICY_CHANNEL]) { -// dbg("Must provide channel\n"); -// return UBUS_STATUS_INVALID_ARGUMENT; -// } -// // If not, write them to the string "agent" -// strncpy(agent, blobmsg_data(tb[SCAN_POLICY_AGENT]), sizeof(agent) - 1); -// int rem = 0, rem1 = 0; -// int i = 0, j = 0; -// struct blob_attr *attr, *cur; -// -// int num_ch_arrays = blobmsg_check_array(tb[SCAN_POLICY_CHANNEL], BLOBMSG_TYPE_ARRAY); -// -// num_radios = blobmsg_check_array(tb[SCAN_POLICY_RADIO], BLOBMSG_TYPE_STRING); -// if (num_radios != num_ch_arrays) { -// dbg("Number of channel arrays has to be the same as number of radios\n"); -// return -1; -// } -// // Allocate the arrays for channel and radio -// num_ch_to_scan = calloc(num_radios, sizeof(uint8_t)); -// if (!num_ch_to_scan) { -// dbg("Out of memory!\n"); -// return -1; -// } -// channel = (uint8_t **)calloc(num_radios, sizeof(uint8_t *)); -// if (!channel) { -// dbg("Out of memory for channels!\n"); -// return -1; -// } -// radio = calloc(num_radios, 18*sizeof(char)); -// if (!radio) { -// dbg("Out of memory for radios!\n"); -// return -1; -// } -// // Radio -// blobmsg_for_each_attr(attr, tb[SCAN_POLICY_RADIO], rem) { -// if (blobmsg_type(attr) != BLOBMSG_TYPE_STRING) { -// dbg("|%s:%d| Radios have to be string.\n", __func__, __LINE__); -// continue; -// } -// strncpy(radio[i], blobmsg_data(attr), 17); -// i++; -// } -// i = 0; -// // Array of channels (attr - current array) -// blobmsg_for_each_attr(attr, tb[SCAN_POLICY_CHANNEL], rem) { -// if (blobmsg_type(attr) != BLOBMSG_TYPE_ARRAY) { -// dbg("|%s:%d| Channels have to be grouped into arrays.\n", __func__, __LINE__); -// continue; -// } -// num_ch_to_scan[i] = blobmsg_check_array(attr, BLOBMSG_TYPE_INT32); -// channel[i] = calloc(num_ch_to_scan[i], sizeof(uint8_t)); -// if (!channel[i]) { -// dbg("Out of memory!\n"); -// return -1; -// } -// trace("|%s:%d| Radio: %s | Scan request for channels:", __func__, __LINE__, radio[i]); -// // Channels (cur - current channel) -// blobmsg_for_each_attr(cur, attr, rem1) { -// channel[i][j] = (uint8_t)blobmsg_get_u32(cur); -// trace(" %d", channel[i][j]); -// j++; -// } -// if (j == 0) // all_ch_scan -// trace(" all"); -// trace("\n"); -// i++; j = 0; -// } -// // Allocate the cmdu_data structure -// cmdu_data = (struct cmdu_cstruct *)calloc(1, -// sizeof(struct cmdu_cstruct)); -// // is it successfully allocated? -// if (!cmdu_data) { -// dbg("failed to malloc cmdu\n"); -// return UBUS_STATUS_UNKNOWN_ERROR; -// } -// // this parameter is neccessary for send_cmdu as it gives the origin -// if (!hwaddr_aton(agent, cmdu_data->origin)) { -// dbg("failed to hwaddr cmdu origin\n"); -// return UBUS_STATUS_UNKNOWN_ERROR; -// } -// // If yes, start creating the cdmu_data -// // that will be used to call the method "send" of "map.1905" -// // cmdu_data = {type, egress, mid, macaddr, num_tlvs, tlvs[]} -// cmdu_data->message_type = CMDU_CHANNEL_SCAN_REQUEST; -// // cmdu_data->message_id = 1; -// // 17.1.33: One Channel Scan Request TLV (17.2.39) -// cmdu_data->num_tlvs = 1; -// // Allocate the TLV of the cmdu_data -// p = (struct tlv_ch_scan_req *)calloc(1, sizeof(struct tlv_ch_scan_req)); // from map2.h (963 line) -// if (!p) { -// dbg("failed to malloc tlv\n"); -// return UBUS_STATUS_UNKNOWN_ERROR; -// } -// // Define the TLV -// p->tlv_type = MAP_TLV_CHANNEL_SCAN_REQ; // from map2.h (134 line) -// p->fresh_scan = 1; // 0000 0000 Bit7=0 -// p->nbr_radios = num_radios; -// if (p->nbr_radios > 0) -// p->radio_data = calloc(p->nbr_radios, sizeof(*p->radio_data)); -// if (!p->radio_data) { -// free(p); -// dbg("failed to malloc radio data\n"); -// return UBUS_STATUS_UNKNOWN_ERROR; -// } -// for (int i = 0; i < p->nbr_radios; i++) { -// //(ubus call wifi.ap.wl0 status -> bssid) -// if (!hwaddr_aton(radio[i], p->radio_data[i].radio_id)) { -// dbg("failed to hwaddr radio_id\n"); -// return UBUS_STATUS_UNKNOWN_ERROR; -// } -// p->radio_data[i].nbr_op_class = 1; //num_ch_to_scan; // TODO -// if (p->radio_data[i].nbr_op_class > 0) { -// p->radio_data[i].op_class_data = calloc(p->radio_data[i].nbr_op_class, sizeof(*p->radio_data[i].op_class_data)); -// } -// if (p->radio_data[i].op_class_data) { -// for (int j = 0; j < p->radio_data[i].nbr_op_class; j++) { /* j is already defined */ -// p->radio_data[i].op_class_data[j].nbr_ch = num_ch_to_scan[i]; -// // if (p->radio_data[i].op_class_data[j].nbr_ch==0) {all ch} -// // channel list -// p->radio_data[i].op_class_data[j].ch = channel[i]; -// } -// } -// } -// cmdu_data->tlvs = (uint8_t **)calloc(cmdu_data->num_tlvs, sizeof(uint8_t *)); -// if (cmdu_data->tlvs) -// cmdu_data->tlvs[0] = (uint8_t *)p; -// strncpy(cmdu_data->intf_name, c->cfg.al_bridge, 15); -// send_cmdu(c, cmdu_data); -// map_free_cmdu(cmdu_data); -// return 0; } static int cntlr_sta_metric_query(struct ubus_context *ctx,