diff --git a/README.md b/README.md index f7b2ba7859a78bcb8204e4dc92b862b303307b2a..ccf8c9c9d594d69283ac55b7d577fc2bd3bf71c1 100644 --- a/README.md +++ b/README.md @@ -490,7 +490,7 @@ root@iopsys-021000000001:~# ubus -v list map.controller "steer":{"agent":"String","src_bssid":"String","sta":"Array","target_bssid":"Array","steer_timeout":"Integer","btm_timeout":"Integer","steer_req_mode":"Boolean"} "client_assoc_cntlr":{"agent":"String","bssid":"String","assoc_cntl_mode":"Integer","assoc_valid_timeout":"Integer","stalist":"Array"} "ap_metric_query":{"agent":"String","bsslist":"Array","radiolist":"Array"} - "scan":{"agent":"String","radio":"Array","channel":"Array"} + "scan":{"agent":"String","radio":"Array","opclass":"Array","channel":"Array","fresh_scan":"Boolean"} "sta_metric_query":{"agent":"String","sta":"String"} "unassoc_sta_lm_query":{"agent":"String","opclass":"Integer","metrics":"Array"} "bcn_metrics_query":{"agent":"String","sta":"String","opclass":"Integer","channel":"Integer","bssid":"String","reporting_detail":"Integer","ssid":"String","channel_report":"Array","request_element":"Array"} diff --git a/src/cntlr.c b/src/cntlr.c index 293154a651e86447f46ebdc750ab175cf88de3ce..b834878facc324c53fb33ff38e9605f4e41521c3 100644 --- a/src/cntlr.c +++ b/src/cntlr.c @@ -137,6 +137,21 @@ struct netif_radio *find_radio_by_node(struct controller *c, struct node *n, return NULL; } +/* find radio by macaddress, search all nodes */ +struct netif_radio *find_radio_by_mac(struct controller *c, uint8_t *mac) +{ + struct node *n = NULL; + struct netif_radio *r = NULL; + + list_for_each_entry(n, &c->nodelist, list) { + r = find_radio_by_node(c, n, mac); + if (r) + return r; + } + + return NULL; +} + /* finds radio struct from interface macaddr */ struct netif_radio *find_radio_by_bssid(struct controller *c, uint8_t *bssid) { @@ -674,6 +689,8 @@ struct netif_radio *cntlr_node_add_radio(struct controller *c, struct node *n, list_add(&r->list, &n->radiolist); r->agent = n; + /* TODO: schedule initial channel scan */ + return r; } @@ -739,6 +756,29 @@ static enum wifi_freqband get_op_class_band(int opclass) } } +uint8_t cntlr_get_classid_ht20(struct netif_radio *nr, uint8_t channel) +{ + int i, j; + struct opclass_entry *entry; + + if (nr == NULL) + return -1; + + for (i = 0; i < nr->opclass.opclass_entry_num; i++) { + entry = &nr->opclass.opclass_entry[i]; + + if (entry->bw != 20) + continue; + + for (j = 0; j < entry->channels_num; j++) { + if (entry->channels[j].channel == channel) + return entry->opclass; + } + } + + return 0; /* Not found */ +} + static struct opclass_entry *cntlr_radio_opclass_find_entry(struct opclass *opclass, uint8_t id) { struct opclass_entry *entry; diff --git a/src/cntlr.h b/src/cntlr.h index b6307bad39dbf5ab8a323ce4c017b0833c14692b..c45359456e8acc92f2bb300357a9e3bf679caa7f 100644 --- a/src/cntlr.h +++ b/src/cntlr.h @@ -38,6 +38,23 @@ struct cac_data { uint8_t cac_action; }; +#define SCAN_REQ_MAX_NUM_RADIO 4 +#define SCAN_REQ_MAX_NUM_OPCLASS 8 +#define SCAN_REQ_MAX_NUM_CHAN 16 +struct scan_req_data { + bool is_fresh_scan; + uint8_t num_radio; + struct scan_req_radio { + uint8_t radio_mac[6]; + uint8_t num_opclass; + struct scan_req_opclass { + uint8_t classid; + uint8_t num_channel; + uint8_t channels[SCAN_REQ_MAX_NUM_CHAN]; + } opclasses[SCAN_REQ_MAX_NUM_OPCLASS]; + } radios[SCAN_REQ_MAX_NUM_RADIO]; +}; + struct bcn_meas_element { uint8_t tag_number; uint8_t tag_length; @@ -335,6 +352,7 @@ struct netif_link *alloc_link_init(struct controller *c, uint8_t *upstream, uint8_t *downstream); struct netif_radio *find_radio_by_node(struct controller *c, struct node *n, uint8_t *radio); +struct netif_radio *find_radio_by_mac(struct controller *c, uint8_t *mac); struct netif_radio *find_radio_by_bssid(struct controller *c, uint8_t *bssid); struct node *find_node_by_mac(struct controller *c, uint8_t *mac); struct node *find_node_by_iface(struct controller *c, uint8_t *bssid); @@ -361,6 +379,7 @@ bool cntlr_resync_config(struct controller *c, bool reload); void free_bcn_metrics(struct controller *c, struct sta *s); void free_usta_metrics(struct controller *c, struct sta *s); +uint8_t cntlr_get_classid_ht20(struct netif_radio *nr, uint8_t channel); int cntlr_radio_opclass_add(struct netif_radio *radio, uint8_t opclass, uint8_t channel, uint8_t preference); void cntlr_radio_opclass_reset(struct netif_radio *radio); diff --git a/src/cntlr_cmdu.c b/src/cntlr_cmdu.c index 24ddea419e67ce870dd3dd391d82dafcf15ca193..61e1430fc0b6a2f91239bda894bef4d8435d9932 100644 --- a/src/cntlr_cmdu.c +++ b/src/cntlr_cmdu.c @@ -668,13 +668,11 @@ struct cmdu_buff *cntlr_gen_cmdu_1905_ack(struct controller *c, } 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]) + uint8_t *agent_mac, struct scan_req_data *req_data) { int ret; uint16_t mid = 0; struct cmdu_buff *resp; - uint8_t origin[6]; /* Allocate the cmdu_data structure */ resp = cmdu_alloc_frame(3000); @@ -684,16 +682,11 @@ struct cmdu_buff *cntlr_gen_channel_scan_request(struct controller *c, } cmdu_set_type(resp, CMDU_CHANNEL_SCAN_REQUEST); cmdu_set_mid(resp, mid); - ret = cntlr_gen_channel_scan_req(c, resp, num_radios, num_ch_to_scan, channel, radio); + ret = cntlr_gen_channel_scan_req(c, resp, req_data); if (ret) goto error; - if (!hwaddr_aton(agent, origin)) { - dbg("failed to hwaddr cmdu origin\n"); - goto error; - } - - memcpy(resp->origin, origin, 6); + memcpy(resp->origin, agent_mac, 6); cmdu_put_eom(resp); return resp; @@ -812,6 +805,22 @@ struct cmdu_buff* cntlr_gen_cac_term(struct controller *c, uint8_t *agent, } +int cntlr_send_channel_scan_request(struct controller *c, uint8_t *agent_mac, + struct scan_req_data *data) +{ + struct cmdu_buff *cmdu_data = NULL; + + cmdu_data = cntlr_gen_channel_scan_request(c, agent_mac, data); + + if (!cmdu_data) + return -1; + + send_cmdu(c, cmdu_data); + cmdu_free(cmdu_data); + + return 0; +} + int cntlr_send_cac_req(struct controller *c, uint8_t *agent, int num_data, struct cac_data *data) { diff --git a/src/cntlr_cmdu.h b/src/cntlr_cmdu.h index d9831d84b354196953670bb18162a495696ee575..ce74d06997f654003e496151a4dc42c1dcfb534e 100644 --- a/src/cntlr_cmdu.h +++ b/src/cntlr_cmdu.h @@ -53,9 +53,7 @@ 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]); + uint8_t *agent, struct scan_req_data *req_data); struct cmdu_buff *cntlr_gen_channel_preference_query(struct controller *c, uint8_t *agent); struct cmdu_buff* cntlr_gen_cac_req(struct controller *c, uint8_t *agent, @@ -75,6 +73,8 @@ struct cmdu_buff *cntlr_gen_comb_infra_metrics_query(struct controller *c, int cntrl_send_channel_preference_query(struct controller *c, uint8_t *agent); int cntrl_send_channel_selection(struct controller *c, uint8_t *agent, uint8_t *radio, uint8_t channel, uint8_t opclass, uint8_t pref); +int cntlr_send_channel_scan_request(struct controller *c, uint8_t *agent_mac, + struct scan_req_data *data); int cntlr_send_cac_req(struct controller *c, uint8_t *agent, int num_data, struct cac_data *data); int cntlr_send_cac_term(struct controller *c, uint8_t *agent, diff --git a/src/cntlr_map.c b/src/cntlr_map.c index b8a5f43c61d71398a6dadcc9f8ce005c69df2baf..56ac452a7dc8e299604861546da476284c93861e 100644 --- a/src/cntlr_map.c +++ b/src/cntlr_map.c @@ -1299,26 +1299,6 @@ static void cntlr_request_bcn_metrics_bsta(struct controller *c, struct sta *s) } } -static uint8_t cntlr_get_opclass_ht20(struct netif_radio *nr, uint8_t channel) -{ - int i, j; - struct opclass_entry *entry; - - for (i = 0; i < nr->opclass.opclass_entry_num; i++) { - entry = &nr->opclass.opclass_entry[i]; - - if (entry->bw != 20) - continue; - - for (j = 0; j < entry->channels_num; j++) { - if (entry->channels[j].channel == channel) - return entry->opclass; - } - } - - return 0; /* Not found */ -} - static int cntlr_request_bcn_metrics_sta(struct controller *c, struct sta *s) { struct cmdu_buff *bcn_cmdu; @@ -1351,7 +1331,7 @@ static int cntlr_request_bcn_metrics_sta(struct controller *c, struct sta *s) if (sp->channels_num == 1) { /* won't use channel report */ - opclass = cntlr_get_opclass_ht20(nr, sp->channels[0]); /* /20 */ + opclass = cntlr_get_classid_ht20(nr, sp->channels[0]); /* /20 */ if (!opclass) return -1; channel = sp->channels[0]; @@ -1360,7 +1340,7 @@ static int cntlr_request_bcn_metrics_sta(struct controller *c, struct sta *s) opclass = 0; channel = 255; /* use channel report */ for (i = 0; i < sp->channels_num; i++) { - opc = cntlr_get_opclass_ht20(nr, sp->channels[i]); + opc = cntlr_get_classid_ht20(nr, sp->channels[i]); if (!opc) continue; op_ch[num_report].opclass = opc; diff --git a/src/cntlr_tlv.c b/src/cntlr_tlv.c index c4ed15b92d447eb4c4fe0de499a00b64f9655e08..696c3b6bf278904eb9190df898c87ff8f367c52e 100644 --- a/src/cntlr_tlv.c +++ b/src/cntlr_tlv.c @@ -1330,12 +1330,13 @@ int cntlr_gen_tlv_error_code(struct controller *c, } int cntlr_gen_channel_scan_req(struct controller *c, struct cmdu_buff *frm, - uint8_t num_radios, const uint8_t *num_ch_to_scan, uint8_t **channel, char (*radio)[18]) + struct scan_req_data *req_data) { struct tlv *t; struct tlv_channel_scan_request *data; struct channel_scan_request_radio *radio_data; struct channel_scan_request_opclass *opclass_data; + int num_channel; uint8_t *channel_data; int ret, offset; @@ -1347,29 +1348,37 @@ int cntlr_gen_channel_scan_req(struct controller *c, struct cmdu_buff *frm, /* 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; + if (req_data->is_fresh_scan) + data->mode |= SCAN_REQUEST_FRESH_SCAN; + data->num_radio = req_data->num_radio; offset = sizeof(*data); + if (data->num_radio > SCAN_REQ_MAX_NUM_RADIO) + return -1; + 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 */ + memcpy(radio_data->radio, req_data->radios[i].radio_mac, 6); /* radio id */ + + radio_data->num_opclass = req_data->radios[i].num_opclass; + if (radio_data->num_opclass > SCAN_REQ_MAX_NUM_OPCLASS) + return -1; 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]; + opclass_data->classid = req_data->radios[i].opclasses[j].classid; + num_channel = req_data->radios[i].opclasses[j].num_channel; + if (num_channel > SCAN_REQ_MAX_NUM_CHAN) + return -1; + opclass_data->num_channel = num_channel; 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; + if (num_channel) { + channel_data = (uint8_t *) &t->data[offset]; + memcpy(channel_data, req_data->radios[i].opclasses[j].channels, num_channel); + offset += num_channel; + } } } /* Update the TLV length */ @@ -1384,7 +1393,6 @@ int cntlr_gen_channel_scan_req(struct controller *c, struct cmdu_buff *frm, return 0; } - int cntlr_gen_channel_pref(struct controller *c, struct cmdu_buff *frm, uint8_t *radio_id, uint8_t class_id, uint8_t channel_nr, const uint8_t *chanlist, uint8_t pref) diff --git a/src/cntlr_tlv.h b/src/cntlr_tlv.h index 3f93826cd3b0bacc6de9f5ba63e557e6889699ac..49b25f2de105ac8c9736c7d3d6e1926f6e44d7cf 100644 --- a/src/cntlr_tlv.h +++ b/src/cntlr_tlv.h @@ -62,8 +62,7 @@ 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, const uint8_t *num_ch_to_scan, uint8_t **channel, - char (*radio)[18]); + struct scan_req_data *req_data); int cntlr_gen_steer_request(struct controller *c, struct cmdu_buff *frm, uint8_t tlv_type, uint8_t *bss_id, uint32_t steer_timeout, diff --git a/src/cntlr_ubus.c b/src/cntlr_ubus.c index 2ce7adcb248ae135a102c9fd5a5d9b82b21855ae..0657d7c1194287900042fc6e353e26f27f97d253 100644 --- a/src/cntlr_ubus.c +++ b/src/cntlr_ubus.c @@ -240,16 +240,18 @@ static const struct blobmsg_policy ap_metric_query_params[__AP_METRIC_QUERY_MAX] enum { SCAN_POLICY_AGENT, SCAN_POLICY_RADIO, - //SCAN_POLICY_OP_CLASS, //OP + SCAN_POLICY_CLASSID, SCAN_POLICY_CHANNEL, + SCAN_POLICY_FRESH_SCAN, __SCAN_POLICY_MAX, }; static const struct blobmsg_policy scan_policy_params[__SCAN_POLICY_MAX] = { [SCAN_POLICY_AGENT] = { .name = "agent", .type = BLOBMSG_TYPE_STRING }, [SCAN_POLICY_RADIO] = { .name = "radio", .type = BLOBMSG_TYPE_ARRAY }, - //[SCAN_POLICY_OP_CLASS] = { .name = "opclass", .type = BLOBMSG_TYPE_INT32 }, // OP - [SCAN_POLICY_CHANNEL] = { .name = "channel", .type = BLOBMSG_TYPE_ARRAY } + [SCAN_POLICY_CLASSID] = { .name = "opclass", .type = BLOBMSG_TYPE_ARRAY }, + [SCAN_POLICY_CHANNEL] = { .name = "channel", .type = BLOBMSG_TYPE_ARRAY }, + [SCAN_POLICY_FRESH_SCAN] = { .name = "fresh_scan", .type = BLOBMSG_TYPE_BOOL } }; enum { @@ -2078,17 +2080,18 @@ 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}; - char (*radio_str)[18] = NULL; - uint8_t **channel = NULL; /* array of channels per radio */ - uint8_t *num_ch_to_scan = NULL; /* array of number of channels per radio */ + char mac_str[18] = {0}; + uint8_t agent_mac[6] = {0}; uint8_t num_radios; /* number of radios */ - uint8_t num_ch_arrays; - struct cmdu_buff *cmdu_data; + uint8_t num_ch_arrays = 0, num_opclass = 0; int rem, rem1, i, j, k; struct blob_attr *attr, *cur; + struct scan_req_data scan_req_data = {}; + uint8_t classid = 0; + int num_channel; int ret = UBUS_STATUS_OK; blobmsg_parse(scan_policy_params, __SCAN_POLICY_MAX, tb, @@ -2104,114 +2107,149 @@ static int cntlr_scan(struct ubus_context *ctx, struct ubus_object *obj, 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] && !tb[SCAN_POLICY_CLASSID]) { + dbg("Must provide channel list or opclass id for each radio\n"); + return UBUS_STATUS_INVALID_ARGUMENT; + } + + strncpy(mac_str, blobmsg_data(tb[SCAN_POLICY_AGENT]), sizeof(mac_str) - 1); + + if (!hwaddr_aton(mac_str, agent_mac)) { + dbg("failed to hwaddr cmdu origin\n"); + return UBUS_STATUS_UNKNOWN_ERROR; + } + + if (tb[SCAN_POLICY_FRESH_SCAN]) + scan_req_data.is_fresh_scan = blobmsg_get_bool(tb[SCAN_POLICY_FRESH_SCAN]); + else + /* always request for a fresh scan if not specified explicitly */ + scan_req_data.is_fresh_scan = true; + + dbg("|%s:%d| is_fresh_scan:%d\n", + __func__, __LINE__, scan_req_data.is_fresh_scan ? 1 : 0); + + if (tb[SCAN_POLICY_CHANNEL]) + num_ch_arrays = blobmsg_check_array(tb[SCAN_POLICY_CHANNEL], BLOBMSG_TYPE_ARRAY); - if (!tb[SCAN_POLICY_CHANNEL]) { - dbg("Must provide channel\n"); + if (tb[SCAN_POLICY_CLASSID]) + num_opclass = blobmsg_check_array(tb[SCAN_POLICY_CLASSID], BLOBMSG_TYPE_INT32); + + if (!num_ch_arrays && !num_opclass) { + dbg("Either channel list or opclass id must be provided for each radio\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"); + + if (num_radios > SCAN_REQ_MAX_NUM_RADIO) { + dbg("Number of radios exceeds maximum of %d\n", + SCAN_REQ_MAX_NUM_RADIO); return UBUS_STATUS_INVALID_ARGUMENT; } - /* 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 UBUS_STATUS_UNKNOWN_ERROR; + + if (num_ch_arrays && num_ch_arrays != num_radios) { + dbg("Number of channel arrays has to be the same as number of radios\n"); + return UBUS_STATUS_INVALID_ARGUMENT; } - channel = (uint8_t **)calloc(num_radios, sizeof(uint8_t *)); - if (!channel) { - dbg("Out of memory for channels!\n"); - ret = UBUS_STATUS_UNKNOWN_ERROR; - goto out; + + if (num_opclass && num_opclass != num_radios) { + dbg("Number of opclass ids has to be the same as number of radios\n"); + return UBUS_STATUS_INVALID_ARGUMENT; } - radio_str = calloc(num_radios, 18*sizeof(char)); - if (!radio_str) { - dbg("Out of memory for radios!\n"); - ret = UBUS_STATUS_UNKNOWN_ERROR; - goto out; + + scan_req_data.num_radio = num_radios; + for (i = 0; i < num_radios; i++) { + /* Bottom layer limitation - one opclass per radio */ + scan_req_data.radios[i].num_opclass = 1; } + i = 0; rem = 0; rem1 = 0; + + /* Current usage: + * ubus call map.controller scan '{"agent":"46:d4:37:6a:f4:c0", + * "radio":["44:d4:37:6a:f4:ce"], "channel":[[1]], "opclass":[81], "fresh_scan":TRUE}' + */ + /* 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); + + strncpy(mac_str, blobmsg_data(attr), 17); + if (!hwaddr_aton(mac_str, scan_req_data.radios[i].radio_mac)) { + return UBUS_STATUS_UNKNOWN_ERROR; + } + i++; } + /* Input is an array of channels (attr - current channel array) */ k = 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[k] = blobmsg_check_array(attr, BLOBMSG_TYPE_INT32); - channel[k] = calloc(num_ch_to_scan[k], sizeof(uint8_t)); - if (!channel[k]) { - dbg("Out of memory!\n"); - ret = UBUS_STATUS_UNKNOWN_ERROR; - goto out; + + num_channel = blobmsg_check_array(attr, BLOBMSG_TYPE_INT32); + if (num_channel < 0 || num_channel > SCAN_REQ_MAX_NUM_CHAN) { + dbg("|%s:%d| Channel list invalid.\n", __func__, __LINE__); + return UBUS_STATUS_INVALID_ARGUMENT; } - trace("|%s:%d| Radio: %s | Scan request for channels:", __func__, __LINE__, radio_str[k]); + + scan_req_data.radios[k].opclasses[0].num_channel = num_channel; + + dbg("|%s:%d| Radio: " MACFMT " | scan request, num_channel = %d\n", + __func__, __LINE__, + MAC2STR(scan_req_data.radios[k].radio_mac), num_channel); + /* Channels (cur - current channel) */ + j = 0; blobmsg_for_each_attr(cur, attr, rem1) { - int ch = 0; + uint8_t ch = (uint8_t) blobmsg_get_u32(cur); + + /* Get opclass id (once) if not provided explicitly */ + if (!classid && !num_opclass) { + struct netif_radio *r; + + r = find_radio_by_mac(c, scan_req_data.radios[k].radio_mac); + if (!r) { + dbg("|%s:%d| Could not find netif radio: " MACFMT "\n", + __func__, __LINE__, + MAC2STR(scan_req_data.radios[k].radio_mac)); + return UBUS_STATUS_UNKNOWN_ERROR; + } - ch = blobmsg_get_u32(cur); - if (ch <= 0) { - trace("Send the valid channel data\n"); - ret = UBUS_STATUS_INVALID_ARGUMENT; - goto out; + classid = cntlr_get_classid_ht20(r, ch); + /* one classid per radio */ + scan_req_data.radios[k].opclasses[0].classid = classid; } - channel[k][j] = (uint8_t)ch; - trace(" %d", channel[k][j]); + scan_req_data.radios[k].opclasses[0].channels[j] = ch; j++; } - if (j == 0) /* all_ch_scan */ - trace(" all"); - trace("\n"); k++; - j = 0; } - cmdu_data = cntlr_gen_channel_scan_request(c, agent, num_radios, num_ch_to_scan, channel, radio_str); - if (!cmdu_data) { - ret = UBUS_STATUS_UNKNOWN_ERROR; - goto out; - } + if (k != num_radios) + return UBUS_STATUS_UNKNOWN_ERROR; - send_cmdu(c, cmdu_data); - cmdu_free(cmdu_data); + /* Opclasses (cur - current opclass id) */ + k = 0; + blobmsg_for_each_attr(cur, tb[SCAN_POLICY_CLASSID], rem1) { -out: - if (radio_str) - free(radio_str); + classid = (uint8_t) blobmsg_get_u32(cur); + /* classid provided explicitly - override the HT20 one if set */ + scan_req_data.radios[k].opclasses[0].classid = classid; - if (channel) { - for (i = 0; i < num_radios; i++) { - if (channel[i]) - free(channel[i]); - } - free(channel); + dbg("|%s:%d| Radio: " MACFMT " | scan request's class id = %d\n", + __func__, __LINE__, + MAC2STR(scan_req_data.radios[k].radio_mac), classid); + + k++; } - if (num_ch_to_scan) - free(num_ch_to_scan); + ret = cntlr_send_channel_scan_request(c, agent_mac, &scan_req_data); return ret; }