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;
 }