diff --git a/src/agent.c b/src/agent.c index 74adcb57ba038364b57ca6310432d633414908d5..bb29a3f4df426e78c69406b37f8d7ce8b87f20e1 100644 --- a/src/agent.c +++ b/src/agent.c @@ -6481,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; @@ -6532,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, @@ -6556,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; } 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_map.c b/src/agent_map.c index b3c5a2c16559c4c00925c821a9d85774c334d0db..499e5f81a9c317c7fd1f143676b6bb07efe3a00e 100644 --- a/src/agent_map.c +++ b/src/agent_map.c @@ -5653,10 +5653,6 @@ int handle_channel_scan_request(void *agent, struct cmdu_buff *rx_cmdu, /* 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)) { - } /* Check all requested opc/chan pairs supported by radio */ else if (!scan_supported(a, scan_req, re)) { diff --git a/src/agent_tlv.c b/src/agent_tlv.c index d816f4647de16c0f6e128de6072105cc9458bd28..baab366094dd9b2999e275604213d34d296d80dc 100644 --- a/src/agent_tlv.c +++ b/src/agent_tlv.c @@ -3225,10 +3225,6 @@ 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 %s:INFO: radio " MACFMT ", opclass %d, channel %d\n", __func__, @@ -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; @@ -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/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_ubus.c b/src/wifi_ubus.c index 751f2a6ff12a7515ae1a2ddff2ffb7c22d270a1f..74130cbb9f3113cc20943ad0f5bc5680246fa288 100644 --- a/src/wifi_ubus.c +++ b/src/wifi_ubus.c @@ -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);