diff --git a/src/agent.c b/src/agent.c index 187711c537367b6904f1fcb62c5ee4f9dc2dea65..bb29a3f4df426e78c69406b37f8d7ce8b87f20e1 100644 --- a/src/agent.c +++ b/src/agent.c @@ -837,13 +837,11 @@ int wifi_radio_scan_req(struct agent *a, struct wifi_radio_element *re, } if (re) { - re->scan_state = SCAN_REQUESTED; return wifi_scan(re->name, ¶m, num_opclass, opclass, - num_channel, channel); + num_channel, channel); } list_for_each_entry(re, &a->radiolist, list) { - re->scan_state = SCAN_REQUESTED; res |= wifi_scan(re->name, ¶m, num_opclass, opclass, num_channel, channel); } @@ -879,19 +877,21 @@ int issue_channel_scan(struct agent *a, struct wifi_radio_element *re, if (ch_idx >= ARRAY_SIZE(channels)) break; - if (req->opclass[i].channel[j] > 0) + if (req->opclass[i].channel[j] > 0) { channels[ch_idx++] = req->opclass[i].channel[j]; + } } /* Channels listed explicitly */ if (req->opclass[i].num_channel) continue; - if (req->opclass[i].classid == 0) + if (req->opclass[i].classid == 0) { /* only channels provided, skip opclass */ // TODO: revisit continue; + } if (op_idx >= ARRAY_SIZE(opclasses)) break; @@ -901,22 +901,27 @@ int issue_channel_scan(struct agent *a, struct wifi_radio_element *re, /* num_channel == 0 indicates that the Multi-AP Agent is * requested to scan on all channels in the Operating Class. */ - if (req->opclass[i].num_channel == 0) { - ch_idx = ARRAY_SIZE(channels); + if (req->opclass[i].num_channel == 0 && ch_idx < ARRAY_SIZE(channels)) { + int idx = ARRAY_SIZE(channels) - ch_idx; + wifi_opclass_get_supported_ctrl_channels( - &re->opclass, - req->opclass[i].classid, - channels, - &ch_idx); + &re->opclass, + req->opclass[i].classid, + &channels[ch_idx], + &idx); + + ch_idx += idx; } } + ch_idx = remove_uint8_duplicates(channels, ch_idx); + /* Pass all the opclasses & channels from the request */ if (op_idx > 0 || ch_idx > 0) ret = wifi_radio_scan_req(a, re, NULL, op_idx, opclasses, ch_idx, channels); else - ret = wifi_radio_scan_req_all(a); + dbg("%s: no opclass/channel to scan\n", __func__); return ret; } @@ -6476,8 +6481,9 @@ static void parse_ap(struct ubus_request *req, int type, } -static int agent_radio_update_scanresults_element(struct wifi_radio_element *re, struct wifi_bss *bsss, - uint32_t classid) +static int agent_radio_update_scanresults_element(struct wifi_radio_element *re, + struct wifi_bss *bsss, + uint32_t classid) { struct wifi_scanres_channel_element *scanres_el; int idx; @@ -6527,13 +6533,32 @@ static int agent_radio_update_scanresults_element(struct wifi_radio_element *re, return 0; } +/* scan_duration expected as ms */ +static int agent_scanres_update_scan_duration(struct wifi_radio_element *re, + uint8_t classid, uint8_t channel, + uint64_t scan_duration) +{ + struct wifi_scanres_channel_element *scanres_el; + + scanres_el = wifi_get_scanres_ch_element(re, classid, channel); + if (!scanres_el) + return -1; + + scanres_el->scan_duration = scan_duration; + return 0; +} + static int agent_radio_update_scanlist(struct agent *a, - struct wifi_radio_element *re, struct wifi_bss *bsss, int bss_num) + struct wifi_radio_element *re, + struct wifi_bss *bsss, int bss_num, + struct chan_entry *ch_entry, + int ch_entry_num) { int i; trace("%s: update results for [%s]\n", __func__, re->name); + /* add neighbors */ for (i = 0; i < bss_num; i++) { uint8_t classid = wifi_opclass_find_id_from_channel( &re->opclass, @@ -6551,40 +6576,69 @@ static int agent_radio_update_scanlist(struct agent *a, } } + /* add scan duration */ + for (i = 0; i < ch_entry_num; i++) { + uint8_t classid = wifi_opclass_find_id_from_channel( + &re->opclass, + ch_entry[i].channel, + 20); /* caps */ + + /* TODO: current method is not an accurate measurement of + * scan duration for current channel */ + if (ch_entry[i].channel == re->current_channel) + continue; + + agent_scanres_update_scan_duration(re, classid, + ch_entry[i].channel, + ch_entry[i].survey.cca_time / 1000); + /* duplicate scan duration for opclass 125 channel overlap */ + if (classid == OPCLASS_124) { + agent_scanres_update_scan_duration(re, OPCLASS_125, + ch_entry[i].channel, + ch_entry[i].survey.cca_time / 1000); + } + } + return 0; } int agent_radio_scanresults(struct agent *a, struct wifi_radio_element *re) { struct wifi_bss bss[128]; + struct chan_entry ch_entry[128]; int bss_num = ARRAY_SIZE(bss); + int ch_entry_num = ARRAY_SIZE(ch_entry); int ret; if (!re || !strlen(re->name)) return -1; - trace("[%s] radio scanresults\n", re->name); + trace("%s: radio %s scanresults\n", __func__, re->name); /* Get scan results from the driver */ ret = wifi_get_scan_results(re->name, bss, &bss_num); if (ret) { - dbg("[%s] failed to get scanresults\n", re->name); + dbg("%s: failed to get radio %s scanresults\n", __func__, re->name); return -1; } /* Update scan cache */ ret = wifi_scanresults_add(&re->scanresults, &re->opclass, bss, bss_num); if (ret) { - dbg("[%s] failed to update scan cache\n", re->name); + dbg("%s: failed to update scan cache for radio %s\n", __func__, re->name); return -1; } + ret = wifi_get_channels_info(re->name, ch_entry, &ch_entry_num); + if (ret) { + ch_entry_num = 0; + dbg("%s: failed to fetch channels info for radio %s\n", __func__, re->name); + } /* TODO: update scanlist using fresh results from the cache */ - /* Empty scanlist & add most recent results for reporting */ free_scanlist_neighbors(re); - ret = agent_radio_update_scanlist(a, re, bss, bss_num); + ret = agent_radio_update_scanlist(a, re, bss, bss_num, ch_entry, ch_entry_num); return ret; } @@ -7015,13 +7069,19 @@ static void agent_boot_scan_cb(atimer_t *t) return; list_for_each_entry(re, &a->radiolist, list) { + int ret; + if (!re->enabled) { radio_missing = true; continue; } - if (re->scan_state != SCAN_DONE) - wifi_radio_scan_req_all(a); + if (re->scan_state == SCAN_DONE) + continue; + + ret = wifi_radio_scan_req_all(a); + if (!ret) + re->scan_state = SCAN_REQUESTED; } if (a->boot_scan_tries++ < BOOT_UP_SCAN_MAX_TRY @@ -8725,108 +8785,6 @@ struct cmdu_buff *agent_prepare_scan_cmdu(struct agent *a, struct tlv *tsp) return cmdu_data; } -/* Splits Channel Scan Report TLVs into fragment CMDUs. - * Sends fragmet CMDUs to controller. - */ -static int agent_send_ch_scan_rsp_frag(struct agent *a, struct cmdu_buff *cmdu) -{ - trace("agent: %s: --->\n", __func__); - - struct tlv_policy d_policy_scan[] = { - [0] = { - .type = MAP_TLV_CHANNEL_SCAN_RES, - .present = TLV_PRESENT_MORE, - .minlen = 9 - } - }; - /* Timestamp TLV */ - struct tlv *tv[CHAN_SCAN_REPORT_NUM_OF_TLV_TYPES][TLV_MAXNUM] = {0}; - struct tlv *tv_scan[256] = {0}; /* Channel Scan Results TLVs */ - int i; - int num_tlv = 256, num_tlv_copied = 0; - int ret = 0; - struct cmdu_buff *frag_cmdu = NULL; - - if (cmdu->datalen < CH_SCAN_RESP_CMDU_MAX_LEN) - /* No fragmentation required, just send the CMDU as is */ - return agent_send_cmdu(a, cmdu); - - /* If the number of neighbors detected during a channel scan would - * mean that the channel scan report message would not fit within - * one 1905 CMDU, the Multi-AP Agent shall split the channel scan - * report across multiple Channel Scan Result TLVs by splitting - * the information related to sets of neighbor BSSs into separate - * Channel Scan Result TLVs and setting the NumberofNeighbors field - * to the number of neighbors contained in the corresponding TLV. - */ - - /* Note: assuming neighbors are already evenly split between TLVs */ - - ret = map_cmdu_validate_parse(cmdu, tv, ARRAY_SIZE(tv), a->cfg.map_profile); - if (!ret) { - dbg("%s: map_cmdu_validate_parse failed, err = (%d) '%s'\n", __func__, - map_error, map_strerror(map_error)); - return -1; - } - - if (!tv[CHAN_SCAN_REPORT_TIMESTAMP_IDX][0]) { - dbg("%s: Missing TIMESTAMP_TLV!\n", __func__); - return -1; - } - - ret = cmdu_parse_tlv_single(cmdu, tv_scan, d_policy_scan, &num_tlv); - if (ret) { - dbg("%s: cmdu_parse_tlv_single failed, err = (%d) '%s'\n", - __func__, map_error, map_strerror(map_error)); - return -1; - } - - if (!tv_scan[0]) { - dbg("%s: Missing CHANNEL SCAN RESULT_TLV!\n", __func__); - return -1; - } - - tv[CHAN_SCAN_REPORT_TIMESTAMP_IDX][0]->len = - tlv_length(tv[CHAN_SCAN_REPORT_TIMESTAMP_IDX][0]); // FIXME - frag_cmdu = agent_prepare_scan_cmdu(a, tv[CHAN_SCAN_REPORT_TIMESTAMP_IDX][0]); - if (WARN_ON(!frag_cmdu)) - return -1; - - for (i = 0; i < num_tlv; i++) { - uint16_t tlv_len = tlv_length(tv_scan[i]); - - if (tlv_total_length(tv_scan[i]) > frag_cmdu->end - frag_cmdu->tail) { - /* No space left for current TLV in CMDU buffer */ - cmdu_put_eom(frag_cmdu); - agent_send_cmdu(a, frag_cmdu); - cmdu_free(frag_cmdu); - - num_tlv_copied = 0; - - /* Create next fragment and put next TLVs into it */ - frag_cmdu = agent_prepare_scan_cmdu(a, tv[CHAN_SCAN_REPORT_TIMESTAMP_IDX][0]); - } - - /* Add TLV to CMDU & continue */ - tv_scan[i]->len = tlv_len; // FIXME: assign len smwhr else - if (cmdu_copy_tlvs(frag_cmdu, &tv_scan[i], 1)) { - dbg("%s:%d copy TLVs failed, end = %p, tail = %p, len = %d\n", - __func__, __LINE__, - frag_cmdu->end, frag_cmdu->tail, tv_scan[i]->len); - return -1; - } - num_tlv_copied++; - } - - if (num_tlv_copied) { /* avoid sending timestamp alone */ - cmdu_put_eom(frag_cmdu); - agent_send_cmdu(a, frag_cmdu); - } - - cmdu_free(frag_cmdu); - - return 0; -} int agent_send_ch_scan_response(struct agent *a, struct wifi_radio_element *re, struct wifi_scan_request_radio *req) @@ -8850,19 +8808,9 @@ int agent_send_ch_scan_response(struct agent *a, struct wifi_radio_element *re, if (!cmdu_data) return -1; - /* Status will be SUCCESS once results available */ - if (req && req->status == CH_SCAN_STATUS_SCAN_NOT_COMPLETED) { - /* Replace old request data with the new one */ - re->scan_req = *req; - /* Reset the timer of available time (5min) */ - timer_set(&re->available_scan_timer, 300000); - } - /* Send the response cmdu */ - ret = agent_send_ch_scan_rsp_frag(a, cmdu_data); - + agent_send_cmdu(a, cmdu_data); cmdu_free(cmdu_data); - return ret; } diff --git a/src/agent.h b/src/agent.h index 1a9eac6b62ce6b8507a7e6c1a024fe4d0a6c5c77..863f5ad3cd78ddadaca2e6a31a41c632c80d3435 100644 --- a/src/agent.h +++ b/src/agent.h @@ -576,6 +576,7 @@ struct wifi_scanres_channel_element { uint8_t channel; uint8_t utilization; uint8_t anpi; + uint32_t scan_duration; uint32_t num_neighbors; struct wifi_scanres_neighbor_element *nbrlist; /* scanned AP list */ }; diff --git a/src/agent_cmdu.c b/src/agent_cmdu.c index de97f9ba2e68b37ff8e32b914ee7948fa88c4273..607bbc1fa487a059a1af06b610b6be92641b3235 100644 --- a/src/agent_cmdu.c +++ b/src/agent_cmdu.c @@ -806,13 +806,8 @@ static int agent_gen_ch_scan_response_all(struct agent *a, struct cmdu_buff *cmd { trace("%s --->\n", __func__); - int i, j, ret; struct wifi_scanres_element *sl; - struct wifi_scanres_opclass_element *op; - struct wifi_scanres_channel_element *ch; - int num_tlv = 0; - int num_bw_20 = 0; - bool results_missing = false; + int i, ret; if (!a || !cmdu || !re) return -1; @@ -828,45 +823,37 @@ static int agent_gen_ch_scan_response_all(struct agent *a, struct cmdu_buff *cmd if (WARN_ON(!sl)) return -1; - do { - /* do: second iteration to send empty TLVs for all supported opc/ch - * pairs in case there were no nbrs cached on any opc/ch pair. - */ - for (i = 0; i < sl->num_opclass; i++) { - op = sl->opclass_scanlist + i; + for (i = 0; i < sl->num_opclass; i++) { + struct wifi_scanres_opclass_element *op; + int j; - if (op->bandwidth != 20) /* caps */ - continue; - else - num_bw_20++; + op = sl->opclass_scanlist + i; - for (j = 0; j < op->num_channels; j++) { - ch = op->channel_scanlist + j; - - if (!ch->num_neighbors && !results_missing) - /* report only non-empty results */ - continue; + if (op->bandwidth != 20) /* caps */ + continue; - ret = agent_gen_ch_scan_response_tlv(a, cmdu, - re->macaddr, op->opclass, - ch, status); + for (j = 0; j < op->num_channels; j++) { + struct wifi_scanres_channel_element *ch; - if (ret) - return ret; + ch = op->channel_scanlist + j; - dbg("|%s:%d| Added Channel Scan Result TLV.\n", - __func__, __LINE__); - num_tlv++; + if (!wifi_opclass_id_channel_supported(&re->opclass, + op->opclass, + ch->channel)) { + /* skip channel(s) not supported */ + continue; } - } - if (!num_tlv) { - dbg("|%s:%d| No Scan Results found.\n", - __func__, __LINE__); - /* do send empty TLVs for all supported opc/ch pairs */ - results_missing = true; + ret = agent_gen_ch_scan_response_tlv(a, cmdu, + re->macaddr, op->opclass, + ch, status); + if (ret) + return ret; + + dbg("|%s:%d| Added Channel Scan Result TLV.\n", + __func__, __LINE__); } - } while (!num_tlv && num_bw_20); + } return 0; } @@ -893,7 +880,7 @@ static int agent_gen_ch_scan_response_opc(struct agent *a, if (req_opc->num_channel == 0) { /* Report all supported channels in Operating Class */ num_chan = ARRAY_SIZE(channels); - ret = wifi_opclass_get_supported_ctrl_channels(&re->opclass, + ret = wifi_opclass_get_supported_channels(&re->opclass, req_opc->classid, channels, &num_chan); @@ -942,29 +929,39 @@ static int agent_gen_ch_scan_response_opc(struct agent *a, for (j = 0; j < op->num_channels; j++) { int k; + ch = op->channel_scanlist + j; - trace("scan opclass %d channel %d num_neighbors %d\n", - op->opclass, ch->channel, ch->num_neighbors); + trace("%s: scan opclass %d channel %d num_neighbors %d\n", + __func__, op->opclass, ch->channel, ch->num_neighbors); for (k = 0; k < ch->num_neighbors; k++) { struct wifi_scanres_neighbor_element *nbr = ch->nbrlist + k; - trace("trace \tneigh " MACFMT " ssid %s\n", MAC2STR(nbr->bssid), nbr->ssid); + trace("\t %s: neigh " MACFMT " ssid %s\n", __func__, MAC2STR(nbr->bssid), nbr->ssid); } } if (req_opc->classid != op->opclass) { - trace("skip opclass %d\n", op->opclass); + trace("%s: skip opclass %d\n", __func__, op->opclass); continue; } for (j = 0; j < op->num_channels; j++) { + uint8_t st = status; + ch = op->channel_scanlist + j; if (ch->channel != channels[ci]) continue; + if (!wifi_opclass_id_channel_supported(&re->opclass, + op->opclass, + ch->channel)) { + /* override status for not supported channels */ + st = CH_SCAN_STATUS_SCAN_NOT_SUPPORTED; + } + ret = agent_gen_ch_scan_response_tlv(a, cmdu, re->macaddr, - op->opclass, ch, status); + op->opclass, ch, st); if (ret) return ret; @@ -1047,9 +1044,6 @@ struct cmdu_buff *agent_gen_ch_scan_response_radio(struct agent *a, /* Define the cmdu */ cmdu_set_type(cmdu_data, CMDU_CHANNEL_SCAN_REPORT); - - cmdu_set_mid(cmdu_data, req->mid); - memcpy(cmdu_data->origin, a->cntlr_almac, 6); /* Define the TLVs */ diff --git a/src/agent_map.c b/src/agent_map.c index 6465cefd8117b2a781d04263c5712058010a9f83..499e5f81a9c317c7fd1f143676b6bb07efe3a00e 100644 --- a/src/agent_map.c +++ b/src/agent_map.c @@ -5621,31 +5621,43 @@ int handle_channel_scan_request(void *agent, struct cmdu_buff *rx_cmdu, scan_req = &ch_scan_req.radio[i]; re = agent_get_radio(a, scan_req->radio); - if (!re) + if (!re) { + dbg("%s: radio not found:"MACFMT"\n", + __func__, MAC2STR(scan_req->radio)); + continue; + } + + if (!(ch_scan_req.mode & SCAN_REQUEST_FRESH_SCAN)) { + dbg("%s: return scan cache for radio:%s\n", __func__, re->name); + if (a->cfg.scan_on_boot_only && + re->scan_state != SCAN_DONE) { + /* Some boot scan results missing yet */ + scan_req->status = CH_SCAN_STATUS_SCAN_NOT_COMPLETED; + } else + scan_req->status = CH_SCAN_STATUS_SUCCESS; + ret = agent_send_ch_scan_response(a, re, scan_req); continue; + } + + if (scan_req->num_opclass <= 0) { + dbg("%s: no opclass provided, dropping scan req for radio:"MACFMT"\n", + __func__, MAC2STR(scan_req->radio)); + continue; + } /* 'Pefrorm Fresh Scan' while 'On boot only' set in Caps */ if (a->cfg.scan_on_boot_only && ch_scan_req.mode & SCAN_REQUEST_FRESH_SCAN) { - dbg("[Scan Status] radio %s: BOOT SCAN ONLY\n\n", + dbg("%s: [Scan Status] radio %s: BOOT SCAN ONLY\n\n", __func__, re->name); /* Special status in 'boot only' mode for 'fresh scan' */ scan_req->status = CH_SCAN_STATUS_BOOT_SCAN_ONLY; } - /* Do not 'Perform Fresh Scan' */ - else if (!(ch_scan_req.mode & SCAN_REQUEST_FRESH_SCAN)) { - if (a->cfg.scan_on_boot_only - && re->scan_state != SCAN_DONE) - /* Some boot scan results missing yet */ - scan_req->status = CH_SCAN_STATUS_SCAN_NOT_COMPLETED; - else - scan_req->status = CH_SCAN_STATUS_SUCCESS; - } /* Check all requested opc/chan pairs supported by radio */ else if (!scan_supported(a, scan_req, re)) { /* Scan not supported for some opc/channel pairs */ - dbg("[Status code] SCAN NOT SUPPORTED\n\n"); + dbg("%s: [Status code] SCAN NOT SUPPORTED\n\n", __func__); //TODO: separate status for individual opc/ch pairs @@ -5654,13 +5666,13 @@ int handle_channel_scan_request(void *agent, struct cmdu_buff *rx_cmdu, /* Scan too soon */ else if (!timestamp_expired(&re->last_scan_tsp, MIN_SCAN_ITV_SEC * 1000)) { - dbg("[Status code] SCAN TOO SOON\n\n"); + dbg("%s: [Status code] SCAN TOO SOON\n\n", __func__); scan_req->status = CH_SCAN_STATUS_TOO_SOON; } /* Ongoing scan in progress */ else if (re->scan_state == SCAN_SCANNING) { - dbg("[Status code] ONGOING SCAN NOT COMPLETED\n\n"); + dbg("%s: [Status code] ONGOING SCAN NOT COMPLETED\n\n", __func__); scan_req->status = CH_SCAN_STATUS_SCAN_NOT_COMPLETED; } else @@ -5683,13 +5695,13 @@ int handle_channel_scan_request(void *agent, struct cmdu_buff *rx_cmdu, /* Mark radio unscanned prior to a new scan (only) */ re->scan_state = SCAN_NONE; - trace("Trying to issue channel scan on the request of mid: %d\n", + trace("%s: Trying to issue channel scan on the request of mid: %d\n", __func__, scan_req->mid); /* Issue channel scan & check return code */ ret = issue_channel_scan(a, re, scan_req); if (ret) { - dbg("[Status code] RADIO BUSY\n\n"); + dbg("%s: [Status code] RADIO BUSY\n\n", __func__); /* Send the 'busy' response */ scan_req->status = CH_SCAN_STATUS_TOO_BUSY; @@ -5700,11 +5712,11 @@ int handle_channel_scan_request(void *agent, struct cmdu_buff *rx_cmdu, continue; } - trace("Scan started successfully.\n"); + trace("%s: Scan started successfully.\n", __func__); re->scan_state = SCAN_REQUESTED; /* Wait (up to 5min) for the results */ - timer_set(&re->available_scan_timer, 300000); + timer_set(&re->available_scan_timer, 300 * 1000); /* Store the request data */ re->scan_req = *scan_req; diff --git a/src/agent_tlv.c b/src/agent_tlv.c index a45236950d24a7c87b0125e0d9b9ac27f810bfaf..baab366094dd9b2999e275604213d34d296d80dc 100644 --- a/src/agent_tlv.c +++ b/src/agent_tlv.c @@ -3225,13 +3225,9 @@ int agent_gen_ch_scan_response_tlv(struct agent *a, struct cmdu_buff *cmdu, uint8_t bssload_elem_pres = CH_SCAN_RESULT_BSSLOAD_PRESENT; int i, ret, offset = 0; int reserve_len = CH_SCAN_RESP_TLV_MAX_LEN; - /* TODO/FIXME - * add the total scan duration for active scan - */ - uint32_t scan_duration = 0; uint32_t num_nbr = 0; - trace("\t INFO: radio " MACFMT ", opclass %d, channel %d\n", + trace("\t %s:INFO: radio " MACFMT ", opclass %d, channel %d\n", __func__, MAC2STR(radio_mac), opclass_id, ch->channel); get_timestamp(NULL, tsp); @@ -3254,7 +3250,7 @@ int agent_gen_ch_scan_response_tlv(struct agent *a, struct cmdu_buff *cmdu, /* Check if nbr data will fit within TLV limits */ if ((offset + 18 + strlen(nbr->ssid) + strlen(bw_str)) >= reserve_len) { /* Always add scan duration and scan type to TLV */ - BUF_PUT_BE32(t->data[offset], scan_duration); + BUF_PUT_BE32(t->data[offset], ch->scan_duration); offset += 4; t->data[offset++] = SCAN_RESULT_SCAN_TYPE; @@ -3290,7 +3286,7 @@ int agent_gen_ch_scan_response_tlv(struct agent *a, struct cmdu_buff *cmdu, /* ssid */ memcpy(&t->data[offset], nbr->ssid, strlen(nbr->ssid)); offset += strlen(nbr->ssid); - t->data[offset++] = rssi_to_rcpi(nbr->rssi); /* rcpi */ + t->data[offset++] = nbr->rssi; /* rssi */ t->data[offset++] = strlen(bw_str); //+ 1; /* BW length */ memcpy(&t->data[offset], bw_str, strlen(bw_str)); @@ -3307,7 +3303,7 @@ int agent_gen_ch_scan_response_tlv(struct agent *a, struct cmdu_buff *cmdu, num_nbr++; } - BUF_PUT_BE32(t->data[offset], scan_duration); /* scan duration */ + BUF_PUT_BE32(t->data[offset], ch->scan_duration); /* scan duration */ offset += 4; t->data[offset++] = SCAN_RESULT_SCAN_TYPE; /* scan type */ diff --git a/src/agent_ubus.c b/src/agent_ubus.c index 99fdade97709cc15f8593fef682c0dbd7d823a8e..14bcfca931e2e38012fb7bc822386b70c8573ca8 100644 --- a/src/agent_ubus.c +++ b/src/agent_ubus.c @@ -954,8 +954,10 @@ static int agent_timers(struct ubus_context *ctx, struct ubus_object *obj, { struct blob_buf bb; struct agent *a = container_of(obj, struct agent, obj); + struct wifi_radio_element *re = NULL; void *t; struct timespec now = {0}; + void *b; timestamp_update(&now); @@ -977,6 +979,20 @@ static int agent_timers(struct ubus_context *ctx, struct ubus_object *obj, #endif /* AGENT_ISLAND_PREVENTION */ blobmsg_add_u32(&bb, "disable_unconnected_bstas_scheduler", timer_remaining_ms(&a->disable_unconnected_bstas_scheduler)); blobmsg_add_u32(&bb, "onboarding_scheduler", timer_remaining_ms(&a->onboarding_scheduler)); + b = blobmsg_open_array(&bb, "scan"); + + list_for_each_entry(re, &a->radiolist, list) { + void *tt; + + tt = blobmsg_open_table(&bb, ""); + blobmsg_add_string(&bb, "name", re->name); + blobmsg_add_u32(&bb, "timeout", timer_remaining_ms(&re->available_scan_timer)); + blobmsg_add_u32(&bb, "state", re->scan_state); + blobmsg_close_table(&bb, tt); + } + + blobmsg_close_array(&bb, b); + blobmsg_close_table(&bb, t); ubus_send_reply(ctx, req, bb.head); blob_buf_free(&bb); diff --git a/src/utils/utils.c b/src/utils/utils.c index 1f611cd67297d9613694cea01f0a024da9dc2212..f6487c56e7e7b594d6669b0839865af580ef218c 100644 --- a/src/utils/utils.c +++ b/src/utils/utils.c @@ -732,3 +732,27 @@ out: blob_buf_free(&bb); return -1; } + + +/* remove duplicates from a uint8_t array and return the new length */ +int remove_uint8_duplicates(uint8_t *arr, int length) +{ + int i; + + for (i = 0; i < length; i++) { + int j; + + for (j = i + 1; j < length; ) { + if (arr[i] == arr[j]) { + int k; + + for (k = j; k < length - 1; k++) + arr[k] = arr[k + 1]; + length--; + } else + j++; + } + } + + return length; +} diff --git a/src/utils/utils.h b/src/utils/utils.h index e21deeac72216f644f53399770b88240ab0246d5..c81f77295910daad4c97aaed5a251d44bc8cb743 100644 --- a/src/utils/utils.h +++ b/src/utils/utils.h @@ -180,6 +180,8 @@ uint8_t *blobattrtob(struct blob_attr *attr, uint8_t *out, int size); int get_ethportslist(int *num, char ifs[][16]); +int remove_uint8_duplicates(uint8_t *arr, int length); + #define TS_VID_INVALID 0x0FFF bool is_vid_valid(unsigned int vid); diff --git a/src/wifi.c b/src/wifi.c index f1ca0764010e89cbfd373332618080e05565eb14..89da0315e6855479fabdc697f7bc729fd8261c22 100644 --- a/src/wifi.c +++ b/src/wifi.c @@ -111,6 +111,21 @@ int wifi_get_scan_results(const char *name, struct wifi_bss *bsss, int *num) return ret; } +int wifi_get_channels_info(const char *name, struct chan_entry *ch_entry, int *num) +{ + struct ubus_context *ctx = ubus_connect(NULL); + int ret; + + if (!ctx) + return -1; + + ret = wifi_ubus_channels_info(ctx, name, ch_entry, num); + + ubus_free(ctx); + return ret; +} + + int wifi_set_4addr(const char *ifname, bool enable) { struct ubus_context *ctx = ubus_connect(NULL); diff --git a/src/wifi.h b/src/wifi.h index bef96d28380dc2235901686339fa812b354ca83c..66575bf94236d8e3175f7ae4cae779f1a31f4691 100644 --- a/src/wifi.h +++ b/src/wifi.h @@ -83,6 +83,7 @@ int wifi_scan(const char *name, struct scan_param_ex *p, int num_opclass, uint8_t *opclass, int num_channel, uint8_t *channel); int wifi_get_scan_results(const char *name, struct wifi_bss *bsss, int *num); +int wifi_get_channels_info(const char *name, struct chan_entry *ch_entry, int *num); int wifi_start_cac(const char *name, int channel, enum wifi_bw bw, enum wifi_cac_method method); int wifi_stop_cac(const char *name, int channel, enum wifi_bw bw); diff --git a/src/wifi_opclass.c b/src/wifi_opclass.c index b8dba1e00d493e2c62e4ba2dc61500875fed8b7f..7f9d983b409a45fc32ec420b1e8aa169faa45a94 100644 --- a/src/wifi_opclass.c +++ b/src/wifi_opclass.c @@ -1181,6 +1181,34 @@ bool wifi_opclass_is_channel_supported(struct wifi_radio_opclass_channel *chan) return true; } +int wifi_opclass_get_supported_channels(struct wifi_radio_opclass *opclass, + uint8_t id, + uint8_t channels[], + int *num_channels) +{ + struct wifi_radio_opclass_entry *entry; + int i; + + if (WARN_ON(!opclass)) + return -1; + + entry = wifi_opclass_find_entry(opclass, id); + if (WARN_ON(!entry)) + return -1; + + if (WARN_ON(entry->channel_num > *num_channels)) + return -1; + + *num_channels = 0; + + for (i = 0; i < entry->channel_num; i++) { + channels[*num_channels] = entry->channel[i].channel; + (*num_channels)++; + } + + return 0; +} + int wifi_opclass_get_supported_ctrl_channels(struct wifi_radio_opclass *opclass, uint8_t id, uint8_t ctrl_channels[], diff --git a/src/wifi_opclass.h b/src/wifi_opclass.h index a5938ba49d57b4d0ba986618bce48dc6f0cf9e16..ad6576c3762a0d64123bc70e0b60a03c7ce10a5a 100644 --- a/src/wifi_opclass.h +++ b/src/wifi_opclass.h @@ -86,6 +86,10 @@ int wifi_opclass_id_num_channels_unsupported(struct wifi_radio_opclass *opclass, bool wifi_opclass_id_channel_supported(struct wifi_radio_opclass *opclass, uint8_t id, uint8_t channel); void wifi_opclass_id_set_preferences(struct wifi_radio_opclass *opclass, uint8_t id, uint8_t preference); bool wifi_opclass_is_channel_supported(struct wifi_radio_opclass_channel *chan); +int wifi_opclass_get_supported_channels(struct wifi_radio_opclass *opclass, + uint8_t id, + uint8_t channels[], + int *num_channels); int wifi_opclass_get_supported_ctrl_channels(struct wifi_radio_opclass *opclass, uint8_t id, uint8_t ctrl_channels[], diff --git a/src/wifi_ubus.c b/src/wifi_ubus.c index 100d0b4e44d18b2fe8cac02d9628eb79adf6bd9c..74130cbb9f3113cc20943ad0f5bc5680246fa288 100644 --- a/src/wifi_ubus.c +++ b/src/wifi_ubus.c @@ -1378,7 +1378,7 @@ static void wifi_ubus_radio_scanresults_cb(struct ubus_request *req, bss->curr_bw = BW20; break; } - bss->rssi = blobmsg_get_u32(bss_tb[4]); + bss->rssi = (int32_t)blobmsg_get_u32(bss_tb[4]); bss->load.sta_count = blobmsg_get_u32(bss_tb[5]); bss->load.utilization = blobmsg_get_u32(bss_tb[6]); @@ -1428,6 +1428,135 @@ out: return ret; } + +struct radio_chinfo_ctx { + const char *radio; + struct chan_entry *ch; + int num; + int max; + int status; +}; + +static void wifi_ubus_channels_info_cb(struct ubus_request *req, + int type, + struct blob_attr *msg) +{ + struct radio_chinfo_ctx *ctx = req->priv; + static const struct blobmsg_policy radio_chinfo_policy[] = { + [0] = { .name = "channels", .type = BLOBMSG_TYPE_ARRAY }, + }; + struct blob_attr *tb[ARRAY_SIZE(radio_chinfo_policy)]; + struct chan_entry *ch; + struct blob_attr *cur; + int rem, num; + + blobmsg_parse(radio_chinfo_policy, ARRAY_SIZE(radio_chinfo_policy), + tb, blob_data(msg), blob_len(msg)); + + num = 0; + ctx->num = 0; + + if (!tb[0]) { + ctx->status = -1; + return; + } + + blobmsg_for_each_attr(cur, tb[0], rem) { + static const struct blobmsg_policy ch_policy[] = { + [0] = { .name = "channel", .type = BLOBMSG_TYPE_INT32 }, + [1] = { .name = "freq", .type = BLOBMSG_TYPE_INT32 }, + [2] = { .name = "noise", .type = BLOBMSG_TYPE_INT32 }, + [3] = { .name = "diagnostics", .type = BLOBMSG_TYPE_TABLE } + }; + struct blob_attr *ch_tb[ARRAY_SIZE(ch_policy)]; + + if (WARN_ON(num >= ctx->max)) + break; + + blobmsg_parse(ch_policy, ARRAY_SIZE(ch_policy), ch_tb, + blobmsg_data(cur), blobmsg_data_len(cur)); + + if (!ch_tb[0] || !ch_tb[1] || !ch_tb[2] || !ch_tb[3]) + continue; + + ch = &ctx->ch[num]; + + ch->channel = blobmsg_get_u32(ch_tb[0]); + ch->freq = blobmsg_get_u32(ch_tb[1]); + ch->noise = (int32_t)blobmsg_get_u32(ch_tb[2]); + + { + static const struct blobmsg_policy diag_policy[] = { + [0] = { .name = "channel_busy", .type = BLOBMSG_TYPE_INT64 }, + [1] = { .name = "tx_airtime", .type = BLOBMSG_TYPE_INT64 }, + [2] = { .name = "rx_airtime", .type = BLOBMSG_TYPE_INT64 }, + [3] = { .name = "obss_airtime", .type = BLOBMSG_TYPE_INT64 }, + [4] = { .name = "cca_time", .type = BLOBMSG_TYPE_INT64 }, + [5] = { .name = "false_cca_count", .type = BLOBMSG_TYPE_INT64 } + }; + struct blob_attr *diag_tb[ARRAY_SIZE(diag_policy)]; + + blobmsg_parse(diag_policy, ARRAY_SIZE(diag_policy), diag_tb, + blobmsg_data(ch_tb[3]), blobmsg_data_len(ch_tb[3])); + + if (!diag_tb[0] || !diag_tb[1] || !diag_tb[2] || !diag_tb[3] || !diag_tb[4] || !diag_tb[5]) + continue; + + ch->survey.channel_busy = blobmsg_get_u64(diag_tb[0]); + ch->survey.tx_airtime = blobmsg_get_u64(diag_tb[1]); + ch->survey.rx_airtime = blobmsg_get_u64(diag_tb[2]); + ch->survey.obss_airtime = blobmsg_get_u64(diag_tb[3]); + ch->survey.cca_time = blobmsg_get_u64(diag_tb[4]); + ch->survey.false_cca_count = blobmsg_get_u64(diag_tb[5]); + } + num++; + } + + ctx->num = num; + ctx->status = 0; +} + + + +int wifi_ubus_channels_info(struct ubus_context *ubus_ctx, const char *radio, + struct chan_entry *ch, int *num) +{ + struct radio_chinfo_ctx ctx = { + .radio = radio, + .ch = ch, + .num = 0, + .max = *num, + .status = -1, + }; + struct blob_buf bb = {}; + char name[256] = {}; + uint32_t id; + int ret; + + trace("[%s] %s\n", radio, __func__); + + /* Get id from radio name */ + snprintf(name, sizeof(name), "wifi.radio.%s", radio); + ret = ubus_lookup_id(ubus_ctx, name, &id); + if (ret != UBUS_STATUS_OK) + goto out; + + blob_buf_init(&bb, 0); + ret = ubus_invoke(ubus_ctx, id, "channels_info", bb.head, + wifi_ubus_channels_info_cb, &ctx, + 2 * 1000); + blob_buf_free(&bb); + + if (ctx.status) + ret = ctx.status; + + *num = ctx.num; + +out: + trace("[%s] %s ret %d num %d max %d\n", radio, __func__, ret, *num, ctx.max); + return ret; +} + int wifi_ubus_chan_switch(struct ubus_context *ubus_ctx, const char *ifname, struct chan_switch_param *param) { diff --git a/src/wifi_ubus.h b/src/wifi_ubus.h index e7868d313d03505d9d594fb257e23366d978808b..dffd2c22c9c077110f94b84ffae16b9bcea69ef2 100644 --- a/src/wifi_ubus.h +++ b/src/wifi_ubus.h @@ -62,6 +62,9 @@ int wifi_ubus_ap_status(struct ubus_context *ubus_ctx, const char *ifname, struc int wifi_ubus_radio_scanresults(struct ubus_context *ubus_ctx, const char *radio, struct wifi_bss *bss, int *num); +int wifi_ubus_channels_info(struct ubus_context *ubus_ctx, const char *radio, + struct chan_entry *ch_entry, int *num); + int wifi_ubus_monitor_add_del(struct ubus_context *ubus_ctx, const char *ifname, uint8_t *macaddr, bool add); int wifi_ubus_monitor_add(struct ubus_context *ubus_ctx, const char *ifname, uint8_t *macaddr);