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, &param, 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, &param, 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);