mgmt: Implement set_powered
diff --git a/lib/mgmt.h b/lib/mgmt.h
index aa8f1c8..085ce21 100644
--- a/lib/mgmt.h
+++ b/lib/mgmt.h
@@ -72,6 +72,10 @@
 	uint16_t index;
 	uint8_t powered;
 } __packed;
+struct mgmt_rp_set_powered {
+	uint16_t index;
+	uint8_t powered;
+} __packed;
 
 #define MGMT_EV_CMD_COMPLETE		0x0001
 struct mgmt_ev_cmd_complete {
diff --git a/plugins/mgmtops.c b/plugins/mgmtops.c
index d6252cd..89bdb06 100644
--- a/plugins/mgmtops.c
+++ b/plugins/mgmtops.c
@@ -171,9 +171,75 @@
 	remove_controller(index);
 }
 
-static void mgmt_powered(int sk, void *buf, size_t len)
+static int mgmt_set_discoverable(int index, gboolean discoverable)
 {
 	struct btd_adapter *adapter;
+
+	DBG("index %d discoverable %d", index, discoverable);
+
+	adapter = manager_find_adapter_by_id(index);
+	if (!adapter) {
+		error("Unable to find matching adapter");
+		return -ENODEV;
+	}
+
+	adapter_mode_changed(adapter, discoverable ? 0x03 : 0x02);
+
+	return -ENOSYS;
+}
+
+static int mgmt_set_pairable(int index, gboolean pairable)
+{
+	DBG("index %d pairable %d", index, pairable);
+	return -ENOSYS;
+}
+
+static int mgmt_update_mode(int index, uint8_t powered)
+{
+	struct controller_info *info;
+	struct btd_adapter *adapter;
+	gboolean pairable, discoverable;
+	uint8_t mode, on_mode;
+
+	if (index > max_index) {
+		error("Unexpected index %u", index);
+		return -ENODEV;
+	}
+
+	info = &controllers[index];
+
+	info->enabled = powered;
+	info->pairable = FALSE;
+	info->discoverable = FALSE;
+
+	adapter = manager_find_adapter(&info->bdaddr);
+	if (adapter == NULL) {
+		DBG("Adapter not found");
+		return -ENODEV;
+	}
+
+	if (!powered) {
+		btd_adapter_stop(adapter);
+		return 0;
+	}
+
+	btd_adapter_start(adapter);
+
+	btd_adapter_get_mode(adapter, &mode, &on_mode, &pairable);
+
+	if (mode == MODE_OFF)
+		mode = on_mode;
+
+	discoverable = (on_mode == MODE_DISCOVERABLE);
+
+	mgmt_set_discoverable(index, discoverable);
+	mgmt_set_pairable(index, pairable);
+
+	return 0;
+}
+
+static void mgmt_powered(int sk, void *buf, size_t len)
+{
 	struct mgmt_ev_powered *ev = buf;
 	uint16_t index;
 
@@ -184,25 +250,9 @@
 
 	index = btohs(bt_get_unaligned(&ev->index));
 
-	if (index > max_index) {
-		DBG("Ignoring powered event for unknown controller %u", index);
-		return;
-	}
-
-	controllers[index].enabled = ev->powered;
-
 	DBG("Controller %u powered %s", index, ev->powered ? "on" : "off");
 
-	adapter = manager_find_adapter(&controllers[index].bdaddr);
-	if (adapter == NULL) {
-		DBG("Adapter not found");
-		return;
-	}
-
-	if (ev->powered)
-		btd_adapter_start(adapter);
-	else
-		btd_adapter_stop(adapter);
+	mgmt_update_mode(index, ev->powered);
 }
 
 static void read_index_list_complete(int sk, void *buf, size_t len)
@@ -233,18 +283,6 @@
 	}
 }
 
-static int mgmt_set_discoverable(int index, gboolean discoverable)
-{
-	DBG("index %d discoverable %d", index, discoverable);
-	return -ENOSYS;
-}
-
-static int mgmt_set_pairable(int index, gboolean pairable)
-{
-	DBG("index %d pairable %d", index, pairable);
-	return -ENOSYS;
-}
-
 static int mgmt_set_powered(int index, gboolean powered)
 {
 	char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_set_powered)];
@@ -336,6 +374,23 @@
 	btd_adapter_unref(adapter);
 }
 
+static void set_powered_complete(int sk, void *buf, size_t len)
+{
+	struct mgmt_rp_set_powered *rp = buf;
+	uint16_t index;
+
+	if (len < sizeof(*rp)) {
+		error("Too small set powered complete event");
+		return;
+	}
+
+	index = btohs(bt_get_unaligned(&rp->index));
+
+	DBG("hci%d powered %u", index, rp->powered);
+
+	mgmt_update_mode(index, rp->powered);
+}
+
 static void mgmt_cmd_complete(int sk, void *buf, size_t len)
 {
 	struct mgmt_ev_cmd_complete *ev = buf;
@@ -360,6 +415,9 @@
 	case MGMT_OP_READ_INFO:
 		read_info_complete(sk, ev->data, len - sizeof(*ev));
 		break;
+	case MGMT_OP_SET_POWERED:
+		set_powered_complete(sk, ev->data, len - sizeof(*ev));
+		break;
 	default:
 		error("Unknown command complete for opcode %u", opcode);
 		break;