diff --git a/src/core/cntlr_map_debug.c b/src/core/cntlr_map_debug.c
index 919586fe9d1c2d034f7f035cd3e52ba3aed1f074..d0fe81513a4dae296d23ee0811f248207c5f61a3 100644
--- a/src/core/cntlr_map_debug.c
+++ b/src/core/cntlr_map_debug.c
@@ -437,7 +437,47 @@ int debug_sta_steer_complete(void *cntlr, struct cmdu_cstruct *cmdu)
 
 int debug_backhaul_sta_steer_response(void *cntlr, struct cmdu_cstruct *cmdu)
 {
+	int i;
+	uint8_t *tlv = NULL;
+
 	trace("%s: --->\n", __func__);
+	trace("parsing backhaul sta steer response of |%s:" MACFMT "|\n",
+			cmdu->intf_name, MAC2STR(cmdu->origin));
+
+	for (i = 0; i < cmdu->num_tlvs; i++) {
+		tlv = cmdu->tlvs[i];
+		trace("CMDU type: %s\n", map_stringify_tlv_type(*tlv));
+		switch (*tlv) {
+		case MAP_TLV_BACKHAUL_STEERING_RESPONSE:
+			{
+				struct tlv_backhaul_steer_resp *p =
+						(struct tlv_backhaul_steer_resp *)tlv;
+
+				trace("\tbssid: " MACFMT "\n",
+						MAC2STR(p->bssid));
+				trace("\taddr: " MACFMT "\n",
+						MAC2STR(p->addr));
+
+				trace("\tres_code: 0x%02x\n", p->res_code);
+
+				break;
+			}
+		case MAP_TLV_ERROR_CODE:
+			{
+				struct tlv_error_code *p =
+						(struct tlv_error_code *)tlv;
+
+				trace("\treason_code: 0x%02x\n", p->reason_code);
+				break;
+			}
+		default:
+			fprintf(stdout, "unknown TLV in CMDU:|%s|",
+					map_stringify_cmdu_type(cmdu->message_type));
+			break;
+		}
+		trace("\n");
+	}
+
 	return 0;
 }
 
diff --git a/src/core/cntlr_ubus.c b/src/core/cntlr_ubus.c
index 1bcffc90823922a3cd49ba8dd1e3707bc8c5dc85..cd4110b5ab334243a8551089c5bbec661c5b9e47 100644
--- a/src/core/cntlr_ubus.c
+++ b/src/core/cntlr_ubus.c
@@ -92,6 +92,22 @@ static const struct blobmsg_policy reconfig_policy_params[__RECFG_POLICY_MAX] =
 	[RECFG_POLICY_AGENT] = { .name = "agent", .type = BLOBMSG_TYPE_STRING },
 };
 
+enum {
+	BK_STEER_POLICY_AGENT,
+	BK_STEER_POLICY_BSSID,
+	BK_STEER_POLICY_CHANNEL,
+	BK_STEER_POLICY_OP_CLASS,
+	BK_STEER_POLICY_STA_MAC,
+	__BK_STEER_POLICY_MAX,
+};
+
+static const struct blobmsg_policy bk_steer_policy_params[__BK_STEER_POLICY_MAX] = {
+	[BK_STEER_POLICY_AGENT] = { .name = "agent", .type = BLOBMSG_TYPE_STRING },
+	[BK_STEER_POLICY_BSSID] = { .name = "bssid", .type = BLOBMSG_TYPE_STRING },
+	[BK_STEER_POLICY_CHANNEL] = { .name = "channel", .type = BLOBMSG_TYPE_INT32 },
+	[BK_STEER_POLICY_OP_CLASS] = { .name = "op_class", .type = BLOBMSG_TYPE_INT32 },
+	[BK_STEER_POLICY_STA_MAC] = { .name = "bksta", .type = BLOBMSG_TYPE_STRING },
+};
 
 void send_cmdu_cb(struct ubus_request *req,
 				int type, struct blob_attr *msg)
@@ -668,16 +684,98 @@ fail_cmdu:
 	return UBUS_STATUS_UNKNOWN_ERROR;
 }
 
+static int cntlr_bk_steer(struct ubus_context *ctx, struct ubus_object *obj,
+			struct ubus_request_data *req, const char *method,
+			struct blob_attr *msg)
+{
+	struct blob_attr *tb[__BK_STEER_POLICY_MAX];
+	struct tlv_backhaul_steer_req *p;
+	struct controller *c = container_of(obj, struct controller, obj);
+	char agent[18] = {0}, bssid[18] = {0}, bkhaul[18] = {0};
+	struct cmdu_cstruct *cmdu;
+
+	blobmsg_parse(bk_steer_policy_params, __BK_STEER_POLICY_MAX, tb,
+			blob_data(msg), blob_len(msg));
+
+	if (!tb[BK_STEER_POLICY_BSSID] || !tb[BK_STEER_POLICY_CHANNEL] ||
+			!tb[BK_STEER_POLICY_OP_CLASS] ||
+			!tb[BK_STEER_POLICY_STA_MAC]) {
+		fprintf(stderr, "BSSID, channel and op class required!\n");
+		return UBUS_STATUS_INVALID_ARGUMENT;
+	}
+
+	strncpy(bssid, blobmsg_data(tb[BK_STEER_POLICY_BSSID]),
+			sizeof(bssid) - 1);
+	strncpy(bkhaul, blobmsg_data(tb[BK_STEER_POLICY_STA_MAC]),
+			sizeof(bkhaul) - 1);
+
+	cmdu = (struct cmdu_cstruct *)calloc(1,
+			sizeof(struct cmdu_cstruct));
+	if (!cmdu) {
+		fprintf(stderr, "failed to malloc cmdu\n");
+		return UBUS_STATUS_UNKNOWN_ERROR;
+	}
+
+	if (tb[AP_POLICY_AGENT]) {
+		strncpy(agent, blobmsg_data(tb[AP_POLICY_AGENT]),
+				sizeof(agent) - 1);
+		if (!hwaddr_aton(agent, cmdu->origin))
+			goto fail_cmdu;
+	}
+
+	cmdu->message_type = CMDU_BACKHAUL_STEER_REQUEST;
+
+	p = calloc(1, sizeof(struct tlv_client_info));
+	if (!p) {
+		fprintf(stderr, "failed to malloc cmdu\n");
+		goto fail_cmdu;
+	}
+
+	cmdu->num_tlvs++;
+
+	if (!hwaddr_aton(bssid, p->bssid)) {
+		fprintf(stderr, "BSSID must be in format 11:22:33...\n");
+		goto fail_p;
+	}
+
+	if (!hwaddr_aton(bkhaul, p->addr)) {
+		fprintf(stderr, "Backhaul must be in format 11:22:33...\n");
+		goto fail_p;
+	}
+
+	p->channel = blobmsg_get_u8(tb[BK_STEER_POLICY_CHANNEL]);
+	p->op_class = blobmsg_get_u8(tb[BK_STEER_POLICY_OP_CLASS]);
+	p->tlv_type = MAP_TLV_BACKHAUL_STEERING_REQUEST;
+
+	cmdu->tlvs = (uint8_t **)calloc(cmdu->num_tlvs,
+			sizeof(uint8_t *));
+
+	if (cmdu->tlvs)
+		cmdu->tlvs[0] = (uint8_t *)p;
+
+	send_cmdu(c, cmdu);
+	map_free_cmdu(cmdu);
+
+	return 0;
+fail_p:
+	map_free_tlv_cstruct((uint8_t *) p);
+fail_cmdu:
+	free(cmdu);
+	return UBUS_STATUS_UNKNOWN_ERROR;
+}
+
 int cntlr_publish_object(struct controller *c, const char *objname)
 {
 	struct ubus_object *obj;
 	struct ubus_object_type *obj_type;
 	struct ubus_method *obj_methods;
-	struct ubus_method m[4] = {
+	struct ubus_method m[5] = {
 		UBUS_METHOD_NOARG("status", cntlr_status),
 		UBUS_METHOD("ap_caps", cntlr_ap_caps, ap_caps_policy_params),
 		UBUS_METHOD("sta_caps", cntlr_sta_caps, sta_caps_policy_params),
-		UBUS_METHOD("channels", cntlr_channel_pref, channel_pref_policy_params)
+		UBUS_METHOD("channels", cntlr_channel_pref,
+				channel_pref_policy_params),
+		UBUS_METHOD("bk_steer", cntlr_bk_steer, bk_steer_policy_params)
 		/*
 		UBUS_METHOD("teardown_ap", cntlr_teardown_ap,
 				config_policy_params),