Refactor adapter initialization and power control
This (rather big) patch refactors the way that adapters are initialized
and powered on/off. The purpose is to align the adapter_ops <-> core
daemon interface with how the management interface will behave.
diff --git a/plugins/hciops.c b/plugins/hciops.c
index c364ef2..5ed871b 100644
--- a/plugins/hciops.c
+++ b/plugins/hciops.c
@@ -72,6 +72,8 @@
#define WANTED_COD(index) devs[(index)].wanted_cod
#define PENDING_COD(index) devs[(index)].pending_cod
#define CACHE_ENABLE(index) devs[(index)].cache_enable
+#define ALREADY_UP(index) devs[(index)].already_up
+#define REGISTERED(index) devs[(index)].registered
#define VER(index) devs[(index)].ver
#define DID_VENDOR(index) devs[(index)].did_vendor
#define DID_PRODUCT(index) devs[(index)].did_product
@@ -97,6 +99,8 @@
uint32_t wanted_cod;
uint32_t pending_cod;
gboolean cache_enable;
+ gboolean already_up;
+ gboolean registered;
struct hci_version ver;
@@ -117,12 +121,13 @@
return hci_test_bit(HCI_RAW, &di->flags) || di->type >> 4 != HCI_BREDR;
}
-static void init_dev_info(int index, int sk)
+static void init_dev_info(int index, int sk, gboolean registered)
{
memset(&devs[index], 0, sizeof(struct dev_info));
SK(index) = sk;
PIN_LENGTH(index) = -1;
CACHE_ENABLE(index) = TRUE;
+ REGISTERED(index) = registered;
}
/* Async HCI command handling with callback support */
@@ -293,6 +298,49 @@
return 0;
}
+static int hciops_set_discoverable(int index, gboolean discoverable)
+{
+ uint8_t mode;
+
+ if (discoverable)
+ mode = (SCAN_PAGE | SCAN_INQUIRY);
+ else
+ mode = SCAN_PAGE;
+
+ DBG("hci%d discoverable %d", index, discoverable);
+
+ if (hci_send_cmd(SK(index), OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE,
+ 1, &mode) < 0)
+ return -errno;
+
+ return 0;
+}
+
+static int hciops_stop(int index)
+{
+ int err = 0;
+
+ DBG("hci%d", index);
+
+ if (ioctl(SK(index), HCIDEVDOWN, index) == 0)
+ goto done; /* on success */
+
+ if (errno != EALREADY) {
+ err = -errno;
+ error("Can't stop device hci%d: %s (%d)",
+ index, strerror(-err), -err);
+ }
+
+done:
+ return err;
+}
+
+static int hciops_set_pairable(int index, gboolean pairable)
+{
+ DBG("hci%d pairable %d", index, pairable);
+ return -ENOSYS;
+}
+
static void start_adapter(int index)
{
uint8_t events[8] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00 };
@@ -346,7 +394,6 @@
hci_send_cmd(SK(index), OGF_HOST_CTL,
OCF_READ_INQ_RESPONSE_TX_POWER_LEVEL, 0, NULL);
-
/* Set default link policy */
link_policy = main_opts.link_policy;
@@ -365,8 +412,49 @@
CURRENT_COD(index) = 0;
memset(EIR(index), 0, sizeof(EIR(index)));
+}
- manager_start_adapter(index);
+static gboolean init_adapter(int index)
+{
+ struct btd_adapter *adapter = NULL;
+ gboolean existing_adapter = REGISTERED(index);
+ uint8_t mode, on_mode;
+ gboolean pairable, discoverable;
+
+ if (!REGISTERED(index)) {
+ adapter = btd_manager_register_adapter(index);
+ if (adapter)
+ REGISTERED(index) = TRUE;
+ } else {
+ adapter = manager_find_adapter(&BDADDR(index));
+ /* FIXME: manager_find_adapter should return a new ref */
+ btd_adapter_ref(adapter);
+ }
+
+ if (adapter == NULL)
+ return FALSE;
+
+ btd_adapter_get_state(adapter, &mode, &on_mode, &pairable);
+
+ if (existing_adapter)
+ mode = on_mode;
+
+ if (mode == MODE_OFF) {
+ hciops_stop(index);
+ goto done;
+ }
+
+ start_adapter(index);
+ btd_adapter_start(adapter);
+
+ discoverable = (mode == MODE_DISCOVERABLE);
+
+ hciops_set_discoverable(index, discoverable);
+ hciops_set_pairable(index, pairable);
+
+done:
+ btd_adapter_unref(adapter);
+ return TRUE;
}
static int hciops_encrypt_link(int index, bdaddr_t *dst, bt_hci_result_t cb,
@@ -908,7 +996,7 @@
DBG("Got version for hci%d", index);
if (!PENDING(index) && UP(index))
- start_adapter(index);
+ init_adapter(index);
}
static void read_local_features_complete(int index,
@@ -927,7 +1015,7 @@
DBG("Got features for hci%d", index);
if (!PENDING(index) && UP(index))
- start_adapter(index);
+ init_adapter(index);
}
#define SIZEOF_UUID128 16
@@ -1178,7 +1266,7 @@
OCF_READ_LOCAL_VERSION, 0, NULL);
if (!PENDING(index))
- start_adapter(index);
+ init_adapter(index);
}
static void read_tx_power_complete(int index, void *ptr)
@@ -1256,7 +1344,7 @@
DBG("Got bdaddr for hci%d", index);
if (!PENDING(index) && UP(index))
- start_adapter(index);
+ init_adapter(index);
}
static inline void cmd_status(int index, void *ptr)
@@ -1729,7 +1817,7 @@
g_source_remove(WATCH_ID(index));
g_io_channel_unref(CHANNEL(index));
hci_close_dev(SK(index));
- init_dev_info(index, -1);
+ init_dev_info(index, -1, REGISTERED(index));
}
static gboolean io_security_event(GIOChannel *chan, GIOCondition cond,
@@ -1995,7 +2083,7 @@
READ_STORED_LINK_KEY_CP_SIZE, (void *) &cp);
if (!PENDING(index))
- start_adapter(index);
+ init_adapter(index);
}
static void init_pending(int index)
@@ -2026,7 +2114,7 @@
devs = g_realloc(devs, sizeof(devs[0]) * (max_dev + 1));
}
- init_dev_info(index, dd);
+ init_dev_info(index, dd, FALSE);
init_pending(index);
start_hci_dev(index);
@@ -2071,7 +2159,6 @@
static void device_devreg_setup(int index)
{
struct hci_dev_info di;
- gboolean devup;
DBG("hci%d", index);
@@ -2082,10 +2169,10 @@
if (hci_devinfo(index, &di) < 0)
return;
- devup = hci_test_bit(HCI_UP, &di.flags);
+ if (ignore_device(&di))
+ return;
- if (!ignore_device(&di))
- manager_register_adapter(index, devup);
+ ALREADY_UP(index) = hci_test_bit(HCI_UP, &di.flags);
}
static void device_event(int event, int index)
@@ -2094,12 +2181,15 @@
case HCI_DEV_REG:
info("HCI dev %d registered", index);
device_devreg_setup(index);
+ if (ALREADY_UP(index))
+ device_event(HCI_DEV_UP, index);
break;
case HCI_DEV_UNREG:
info("HCI dev %d unregistered", index);
stop_hci_dev(index);
- manager_unregister_adapter(index);
+ if (REGISTERED(index))
+ btd_manager_unregister_adapter(index);
break;
case HCI_DEV_UP:
@@ -2121,6 +2211,28 @@
}
}
+static int hciops_stop_inquiry(int index)
+{
+ struct hci_dev_info di;
+ int err;
+
+ DBG("hci%d", index);
+
+ if (hci_devinfo(index, &di) < 0)
+ return -errno;
+
+ if (hci_test_bit(HCI_INQUIRY, &di.flags))
+ err = hci_send_cmd(SK(index), OGF_LINK_CTL,
+ OCF_INQUIRY_CANCEL, 0, 0);
+ else
+ err = hci_send_cmd(SK(index), OGF_LINK_CTL,
+ OCF_EXIT_PERIODIC_INQUIRY, 0, 0);
+ if (err < 0)
+ err = -errno;
+
+ return err;
+}
+
static gboolean init_known_adapters(gpointer user_data)
{
struct hci_dev_list_req *dl;
@@ -2151,9 +2263,13 @@
for (i = 0; i < dl->dev_num; i++, dr++) {
device_event(HCI_DEV_REG, dr->dev_id);
- if (!hci_test_bit(HCI_UP, &dr->dev_opt))
+ ALREADY_UP(dr->dev_id) = hci_test_bit(HCI_UP, &dr->dev_opt);
+
+ if (!ALREADY_UP(dr->dev_id))
continue;
+ hciops_stop_inquiry(dr->dev_id);
+
PENDING(dr->dev_id) = 0;
hci_set_bit(PENDING_VERSION, &PENDING(dr->dev_id));
hci_send_cmd(SK(dr->dev_id), OGF_INFO_PARAM,
@@ -2331,25 +2447,6 @@
return err;
}
-static int hciops_stop(int index)
-{
- int err = 0;
-
- DBG("hci%d", index);
-
- if (ioctl(SK(index), HCIDEVDOWN, index) == 0)
- goto done; /* on success */
-
- if (errno != EALREADY) {
- err = -errno;
- error("Can't stop device hci%d: %s (%d)",
- index, strerror(-err), -err);
- }
-
-done:
- return err;
-}
-
static int hciops_set_powered(int index, gboolean powered)
{
uint8_t mode = SCAN_DISABLED;
@@ -2366,11 +2463,16 @@
return hciops_stop(index);
}
-static int hciops_connectable(int index)
+static int hciops_set_connectable(int index, gboolean connectable)
{
- uint8_t mode = SCAN_PAGE;
+ uint8_t mode;
- DBG("hci%d", index);
+ if (connectable)
+ mode = SCAN_PAGE;
+ else
+ mode = 0x00;
+
+ DBG("hci%d connectable %d", index, connectable);
if (hci_send_cmd(SK(index), OGF_HOST_CTL,
OCF_WRITE_SCAN_ENABLE, 1, &mode) < 0)
@@ -2379,23 +2481,12 @@
return 0;
}
-static int hciops_discoverable(int index)
-{
- uint8_t mode = (SCAN_PAGE | SCAN_INQUIRY);
-
- DBG("hci%d", index);
-
- if (hci_send_cmd(SK(index), OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE,
- 1, &mode) < 0)
- return -errno;
-
- return 0;
-}
-
static int hciops_set_dev_class(int index, uint8_t major, uint8_t minor)
{
int err;
+ DBG("hci%d major %u minor %u", index, major, minor);
+
/* Update only the major and minor class bits keeping remaining bits
* intact*/
WANTED_COD(index) &= 0xffe000;
@@ -2453,28 +2544,6 @@
return err;
}
-static int hciops_stop_inquiry(int index)
-{
- struct hci_dev_info di;
- int err;
-
- DBG("hci%d", index);
-
- if (hci_devinfo(index, &di) < 0)
- return -errno;
-
- if (hci_test_bit(HCI_INQUIRY, &di.flags))
- err = hci_send_cmd(SK(index), OGF_LINK_CTL,
- OCF_INQUIRY_CANCEL, 0, 0);
- else
- err = hci_send_cmd(SK(index), OGF_LINK_CTL,
- OCF_EXIT_PERIODIC_INQUIRY, 0, 0);
- if (err < 0)
- err = -errno;
-
- return err;
-}
-
static int le_set_scan_enable(int index, uint8_t enable)
{
le_set_scan_enable_cp cp;
@@ -2900,15 +2969,17 @@
return 0;
}
-static int hciops_write_le_host(int index, uint8_t le, uint8_t simul)
+static int hciops_enable_le(int index)
{
write_le_host_supported_cp cp;
- DBG("hci%d le %u simul %u", index, le, simul);
+ DBG("hci%d", index);
- memset(&cp, 0, sizeof(cp));
- cp.le = le;
- cp.simul = simul;
+ if (!(FEATURES(index)[4] & LMP_LE))
+ return -ENOTSUP;
+
+ cp.le = 0x01;
+ cp.simul = (FEATURES(index)[6] & LMP_LE_BREDR) ? 0x01 : 0x00;
if (hci_send_cmd(SK(index), OGF_HOST_CTL,
OCF_WRITE_LE_HOST_SUPPORTED,
@@ -2966,6 +3037,8 @@
{
int err;
+ DBG("hci%d value %u", index, value);
+
/* Update only the service class, keep the limited bit,
* major/minor class bits intact */
WANTED_COD(index) &= 0x00ffff;
@@ -3005,7 +3078,7 @@
return -ENODEV;
for (list = adapter_get_services(adapter); list; list = list->next) {
- sdp_record_t *rec = list->data;
+ sdp_record_t *rec = list->data;
if (rec->svclass.type != SDP_UUID16)
continue;
@@ -3080,14 +3153,23 @@
return write_class(index, WANTED_COD(index));
}
+static int hciops_restore_powered(int index)
+{
+ if (!ALREADY_UP(index) && UP(index))
+ return hciops_stop(index);
+
+ return 0;
+}
+
static struct btd_adapter_ops hci_ops = {
.setup = hciops_setup,
.cleanup = hciops_cleanup,
.start = hciops_start,
.stop = hciops_stop,
.set_powered = hciops_set_powered,
- .set_connectable = hciops_connectable,
- .set_discoverable = hciops_discoverable,
+ .set_connectable = hciops_set_connectable,
+ .set_discoverable = hciops_set_discoverable,
+ .set_pairable = hciops_set_pairable,
.set_limited_discoverable = hciops_set_limited_discoverable,
.start_inquiry = hciops_start_inquiry,
.stop_inquiry = hciops_stop_inquiry,
@@ -3115,12 +3197,13 @@
.passkey_reply = hciops_passkey_reply,
.get_auth_info = hciops_get_auth_info,
.read_scan_enable = hciops_read_scan_enable,
- .write_le_host = hciops_write_le_host,
+ .enable_le = hciops_enable_le,
.get_remote_version = hciops_get_remote_version,
.encrypt_link = hciops_encrypt_link,
.set_did = hciops_set_did,
.services_updated = hciops_services_updated,
.disable_cod_cache = hciops_disable_cod_cache,
+ .restore_powered = hciops_restore_powered,
};
static int hciops_init(void)
diff --git a/plugins/mgmtops.c b/plugins/mgmtops.c
index a7117fa..8320981 100644
--- a/plugins/mgmtops.c
+++ b/plugins/mgmtops.c
@@ -149,7 +149,7 @@
if (!controllers[index].valid)
return;
- manager_unregister_adapter(index);
+ btd_manager_unregister_adapter(index);
memset(&controllers[index], 0, sizeof(struct controller_info));
@@ -221,10 +221,31 @@
}
}
+static int mgmt_stop(int index)
+{
+ DBG("index %d", index);
+ return -ENOSYS;
+}
+
+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 void read_info_complete(int sk, void *buf, size_t len)
{
struct mgmt_rp_read_info *rp = buf;
struct controller_info *info;
+ struct btd_adapter *adapter;
+ uint8_t mode;
+ gboolean pairable, discoverable;
uint16_t index;
char addr[18];
@@ -262,10 +283,30 @@
info->enabled, info->discoverable,
info->pairable, info->sec_mode);
- manager_register_adapter(index, info->enabled);
+ adapter = btd_manager_register_adapter(index);
+ if (adapter == NULL) {
+ error("mgmtops: unable to register adapter");
+ return;
+ }
+
+ btd_adapter_get_state(adapter, &mode, NULL, &pairable);
+ if (mode == MODE_OFF) {
+ mgmt_stop(index);
+ return;
+ }
+
+ discoverable = (mode == MODE_DISCOVERABLE);
+
+ if (info->discoverable != discoverable)
+ mgmt_set_discoverable(index, discoverable);
+
+ if (info->pairable != pairable)
+ mgmt_set_pairable(index, pairable);
if (info->enabled)
- manager_start_adapter(index);
+ btd_adapter_start(adapter);
+
+ btd_adapter_unref(adapter);
}
static void mgmt_cmd_complete(int sk, void *buf, size_t len)
@@ -465,27 +506,15 @@
return -ENOSYS;
}
-static int mgmt_stop(int index)
-{
- DBG("index %d", index);
- return -ENOSYS;
-}
-
static int mgmt_set_powered(int index, gboolean powered)
{
DBG("index %d powered %d", index, powered);
return -ENOSYS;
}
-static int mgmt_connectable(int index)
+static int mgmt_set_connectable(int index, gboolean connectable)
{
- DBG("index %d", index);
- return -ENOSYS;
-}
-
-static int mgmt_discoverable(int index)
-{
- DBG("index %d", index);
+ DBG("index %d connectable %d", index, connectable);
return -ENOSYS;
}
@@ -722,9 +751,9 @@
return -ENOSYS;
}
-static int mgmt_write_le_host(int index, uint8_t le, uint8_t simul)
+static int mgmt_enable_le(int index)
{
- DBG("index %d le %u simul %u", index, le, simul);
+ DBG("index %d", index);
return -ENOSYS;
}
@@ -752,8 +781,9 @@
.start = mgmt_start,
.stop = mgmt_stop,
.set_powered = mgmt_set_powered,
- .set_connectable = mgmt_connectable,
- .set_discoverable = mgmt_discoverable,
+ .set_connectable = mgmt_set_connectable,
+ .set_discoverable = mgmt_set_discoverable,
+ .set_pairable = mgmt_set_pairable,
.set_limited_discoverable = mgmt_set_limited_discoverable,
.start_inquiry = mgmt_start_inquiry,
.stop_inquiry = mgmt_stop_inquiry,
@@ -781,7 +811,7 @@
.passkey_reply = mgmt_passkey_reply,
.get_auth_info = mgmt_get_auth_info,
.read_scan_enable = mgmt_read_scan_enable,
- .write_le_host = mgmt_write_le_host,
+ .enable_le = mgmt_enable_le,
.get_remote_version = mgmt_get_remote_version,
.encrypt_link = mgmt_encrypt_link,
};
diff --git a/src/adapter.c b/src/adapter.c
index 5118306..8c48501 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -125,9 +125,6 @@
struct hci_dev dev; /* hci info */
gboolean pairable; /* pairable state */
- gboolean initialized;
- gboolean already_up; /* adapter was already up on init */
-
gboolean off_requested; /* DEVDOWN ioctl was called */
gint ref;
@@ -352,7 +349,7 @@
adapter->discov_timeout_id = 0;
- adapter_ops->set_connectable(adapter->dev_id);
+ adapter_ops->set_connectable(adapter->dev_id, TRUE);
return FALSE;
}
@@ -421,9 +418,9 @@
int err;
if (mode == MODE_CONNECTABLE)
- err = adapter_ops->set_connectable(adapter->dev_id);
+ err = adapter_ops->set_connectable(adapter->dev_id, TRUE);
else
- err = adapter_ops->set_discoverable(adapter->dev_id);
+ err = adapter_ops->set_discoverable(adapter->dev_id, TRUE);
if (err < 0)
return err;
@@ -555,9 +552,10 @@
return btd_error_failed(msg, strerror(-err));
store:
-
adapter->pairable = pairable;
+ adapter_ops->set_pairable(adapter->dev_id, pairable);
+
write_device_pairable(&adapter->bdaddr, pairable);
emit_property_changed(connection, adapter->path,
@@ -1832,47 +1830,6 @@
{ }
};
-static int adapter_setup(struct btd_adapter *adapter, const char *mode)
-{
- struct hci_dev *dev = &adapter->dev;
- int err;
- char name[MAX_NAME_LENGTH + 1];
- uint8_t cls[3];
-
- if ((dev->features[4] & LMP_LE) && main_opts.le) {
- uint8_t simul = (dev->features[6] & LMP_LE_BREDR) ? 0x01 : 0x00;
- err = adapter_ops->write_le_host(adapter->dev_id, 0x01, simul);
- if (err < 0) {
- error("Can't write LE host supported for %s: %s(%d)",
- adapter->path, strerror(-err), -err);
- return err;
- }
- }
-
- if (read_local_name(&adapter->bdaddr, name) < 0)
- expand_name(name, MAX_NAME_LENGTH, main_opts.name,
- adapter->dev_id);
-
- adapter_ops->set_name(adapter->dev_id, name);
- if (g_str_equal(mode, "off"))
- strncpy((char *) adapter->dev.name, name, MAX_NAME_LENGTH);
-
- if (adapter->initialized)
- return 0;
-
- if (read_local_class(&adapter->bdaddr, cls) < 0) {
- uint32_t class = htobl(main_opts.class);
- if (class)
- memcpy(cls, &class, 3);
- else
- return 0;
- }
-
- btd_adapter_set_class(adapter, cls[1], cls[0]);
-
- return 0;
-}
-
static void create_stored_device_from_profiles(char *key, char *value,
void *user_data)
{
@@ -2117,75 +2074,65 @@
return type;
}
-static int adapter_up(struct btd_adapter *adapter, const char *mode)
+void btd_adapter_get_state(struct btd_adapter *adapter, uint8_t *mode,
+ uint8_t *on_mode, gboolean *pairable)
{
- char srcaddr[18];
- gboolean powered, dev_down = FALSE;
- int err;
+ char str[14], address[18];
- ba2str(&adapter->bdaddr, srcaddr);
+ ba2str(&adapter->bdaddr, address);
- adapter->off_requested = FALSE;
- adapter->up = 1;
- adapter->discov_timeout = get_discoverable_timeout(srcaddr);
- adapter->pairable_timeout = get_pairable_timeout(srcaddr);
- adapter->state = STATE_IDLE;
- adapter->mode = MODE_CONNECTABLE;
- powered = TRUE;
-
- /* Set pairable mode */
- if (read_device_pairable(&adapter->bdaddr, &adapter->pairable) < 0)
- adapter->pairable = TRUE;
-
- if (g_str_equal(mode, "off")) {
- char onmode[14];
-
- powered = FALSE;
-
- if (!adapter->initialized) {
- dev_down = TRUE;
- goto proceed;
- }
-
- if (read_on_mode(srcaddr, onmode, sizeof(onmode)) < 0 ||
- g_str_equal(onmode, "off"))
- strcpy(onmode, "connectable");
-
- write_device_mode(&adapter->bdaddr, onmode);
-
- return adapter_up(adapter, onmode);
- } else if (!g_str_equal(mode, "connectable"))
- adapter->mode = MODE_DISCOVERABLE;
-
-proceed:
- err = adapter_set_mode(adapter, adapter->mode);
-
- if (err < 0)
- return err;
-
- if (adapter->initialized == FALSE) {
- sdp_init_services_list(&adapter->bdaddr);
- btd_adapter_services_updated(adapter);
- load_drivers(adapter);
- clear_blocked(adapter);
- load_devices(adapter);
-
- /* retrieve the active connections: address the scenario where
- * the are active connections before the daemon've started */
- load_connections(adapter);
-
- adapter->initialized = TRUE;
-
- manager_add_adapter(adapter->path);
-
+ if (mode) {
+ if (main_opts.remember_powered == FALSE)
+ *mode = main_opts.mode;
+ else if (read_device_mode(address, str, sizeof(str)) < 0)
+ *mode = main_opts.mode;
+ else
+ *mode = get_mode(&adapter->bdaddr, str);
}
- if (dev_down) {
- adapter_ops->stop(adapter->dev_id);
- adapter->off_requested = TRUE;
- return 1;
- } else
- emit_property_changed(connection, adapter->path,
+ if (on_mode) {
+ if (main_opts.remember_powered == FALSE)
+ *on_mode = main_opts.mode;
+ else if (read_on_mode(address, str, sizeof(str)) < 0)
+ *on_mode = main_opts.mode;
+ else
+ *on_mode = get_mode(&adapter->bdaddr, str);
+ }
+
+ if (pairable)
+ *pairable = adapter->pairable;
+}
+
+void btd_adapter_start(struct btd_adapter *adapter)
+{
+ char address[18];
+ uint8_t cls[3];
+ gboolean powered;
+
+ ba2str(&adapter->bdaddr, address);
+
+ adapter->dev_class = 0;
+ adapter->off_requested = FALSE;
+ adapter->up = TRUE;
+ adapter->discov_timeout = get_discoverable_timeout(address);
+ adapter->pairable_timeout = get_pairable_timeout(address);
+ adapter->state = STATE_IDLE;
+ adapter->mode = MODE_CONNECTABLE;
+
+ if (main_opts.le)
+ adapter_ops->enable_le(adapter->dev_id);
+
+ adapter_ops->set_name(adapter->dev_id, adapter->dev.name);
+
+ if (read_local_class(&adapter->bdaddr, cls) < 0) {
+ uint32_t class = htobl(main_opts.class);
+ memcpy(cls, &class, 3);
+ }
+
+ btd_adapter_set_class(adapter, cls[1], cls[0]);
+
+ powered = TRUE;
+ emit_property_changed(connection, adapter->path,
ADAPTER_INTERFACE, "Powered",
DBUS_TYPE_BOOLEAN, &powered);
@@ -2193,71 +2140,7 @@
adapter_ops->disable_cod_cache(adapter->dev_id);
- return 0;
-}
-
-int adapter_start(struct btd_adapter *adapter)
-{
- struct hci_dev *dev = &adapter->dev;
- struct hci_version ver;
- uint8_t features[8];
- int err;
- char mode[14], address[18];
-
- if (!bacmp(&adapter->bdaddr, BDADDR_ANY)) {
- int err;
-
- err = adapter_ops->read_bdaddr(adapter->dev_id, &adapter->bdaddr);
- if (err < 0)
- return err;
- }
-
- ba2str(&adapter->bdaddr, address);
-
- err = read_device_mode(address, mode, sizeof(mode));
-
- if ((!adapter->initialized && !main_opts.remember_powered) || err < 0) {
- if (!adapter->initialized && main_opts.mode == MODE_OFF)
- strcpy(mode, "off");
- else
- strcpy(mode, "connectable");
- }
-
- err = adapter_ops->read_local_version(adapter->dev_id, &ver);
- if (err < 0) {
- error("Can't read version info for %s: %s (%d)",
- adapter->path, strerror(-err), -err);
- return err;
- }
-
- dev->hci_rev = ver.hci_rev;
- dev->lmp_ver = ver.lmp_ver;
- dev->lmp_subver = ver.lmp_subver;
- dev->manufacturer = ver.manufacturer;
-
- err = adapter_ops->read_local_features(adapter->dev_id, features);
- if (err < 0) {
- error("Can't read features for %s: %s (%d)",
- adapter->path, strerror(-err), -err);
- return err;
- }
-
- memcpy(dev->features, features, 8);
-
- adapter->dev_class = 0;
-
- adapter_setup(adapter, mode);
-
- if (!adapter->initialized && adapter->already_up) {
- DBG("Stopping Inquiry at adapter startup");
- adapter_ops->stop_inquiry(adapter->dev_id);
- }
-
- err = adapter_up(adapter, mode);
-
info("Adapter %s has been enabled", adapter->path);
-
- return err;
}
static void reply_pending_requests(struct btd_adapter *adapter)
@@ -2330,7 +2213,7 @@
session_unref(pending);
}
-int adapter_stop(struct btd_adapter *adapter)
+int btd_adapter_stop(struct btd_adapter *adapter)
{
gboolean powered, discoverable, pairable;
@@ -2445,8 +2328,66 @@
g_free(path);
}
-struct btd_adapter *adapter_create(DBusConnection *conn, int id,
- gboolean devup)
+gboolean adapter_init(struct btd_adapter *adapter)
+{
+ struct hci_version ver;
+ struct hci_dev *dev;
+ int err;
+
+ /* adapter_ops makes sure that newly registered adapters always
+ * start off as powered */
+ adapter->up = TRUE;
+
+ adapter_ops->read_bdaddr(adapter->dev_id, &adapter->bdaddr);
+
+ if (bacmp(&adapter->bdaddr, BDADDR_ANY) == 0) {
+ error("No address available for hci%d", adapter->dev_id);
+ return FALSE;
+ }
+
+ err = adapter_ops->read_local_version(adapter->dev_id, &ver);
+ if (err < 0) {
+ error("Can't read version info for hci%d: %s (%d)",
+ adapter->dev_id, strerror(-err), -err);
+ return FALSE;
+ }
+
+ dev = &adapter->dev;
+
+ dev->hci_rev = ver.hci_rev;
+ dev->lmp_ver = ver.lmp_ver;
+ dev->lmp_subver = ver.lmp_subver;
+ dev->manufacturer = ver.manufacturer;
+
+ err = adapter_ops->read_local_features(adapter->dev_id, dev->features);
+ if (err < 0) {
+ error("Can't read features for hci%d: %s (%d)",
+ adapter->dev_id, strerror(-err), -err);
+ return FALSE;
+ }
+
+ if (read_local_name(&adapter->bdaddr, adapter->dev.name) < 0)
+ expand_name(adapter->dev.name, MAX_NAME_LENGTH, main_opts.name,
+ adapter->dev_id);
+
+ sdp_init_services_list(&adapter->bdaddr);
+ btd_adapter_services_updated(adapter);
+ load_drivers(adapter);
+ clear_blocked(adapter);
+ load_devices(adapter);
+
+ /* Set pairable mode */
+ if (read_device_pairable(&adapter->bdaddr, &adapter->pairable) < 0)
+ adapter->pairable = TRUE;
+
+ /* retrieve the active connections: address the scenario where
+ * the are active connections before the daemon've started */
+ load_connections(adapter);
+
+ return TRUE;
+}
+
+struct btd_adapter *adapter_create(DBusConnection *conn, int id)
{
char path[MAX_PATH_LENGTH];
struct btd_adapter *adapter;
@@ -2455,21 +2396,20 @@
if (!connection)
connection = conn;
- snprintf(path, sizeof(path), "%s/hci%d", base_path, id);
-
adapter = g_try_new0(struct btd_adapter, 1);
if (!adapter) {
- error("adapter_create: failed to alloc memory for %s", path);
+ error("adapter_create: failed to alloc memory for hci%d", id);
return NULL;
}
adapter->dev_id = id;
+
+ snprintf(path, sizeof(path), "%s/hci%d", base_path, id);
adapter->path = g_strdup(path);
- adapter->already_up = devup;
if (!g_dbus_register_interface(conn, path, ADAPTER_INTERFACE,
- adapter_methods, adapter_signals, NULL,
- adapter, adapter_free)) {
+ adapter_methods, adapter_signals, NULL,
+ adapter, adapter_free)) {
error("Adapter interface init failed on path %s", path);
adapter_free(adapter);
return NULL;
@@ -2488,12 +2428,10 @@
device_remove(l->data, FALSE);
g_slist_free(adapter->devices);
- if (adapter->initialized)
- unload_drivers(adapter);
+ unload_drivers(adapter);
/* Return adapter to down state if it was not up on init */
- if (adapter->up && !adapter->already_up)
- adapter_ops->stop(adapter->dev_id);
+ adapter_ops->restore_powered(adapter->dev_id);
btd_adapter_unref(adapter);
}
@@ -2594,11 +2532,6 @@
return adapter->state;
}
-gboolean adapter_is_ready(struct btd_adapter *adapter)
-{
- return adapter->initialized;
-}
-
struct remote_dev_info *adapter_search_found_devices(struct btd_adapter *adapter,
struct remote_dev_info *match)
{
diff --git a/src/adapter.h b/src/adapter.h
index a02f61c..a7d17ae 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -31,6 +31,11 @@
#define ADAPTER_INTERFACE "org.bluez.Adapter"
+#define MODE_OFF 0x00
+#define MODE_CONNECTABLE 0x01
+#define MODE_DISCOVERABLE 0x02
+#define MODE_UNKNOWN 0xff
+
/* Discover states */
#define STATE_IDLE 0x00
#define STATE_LE_SCAN 0x01
@@ -90,9 +95,12 @@
char name[MAX_NAME_LENGTH + 1];
};
-int adapter_start(struct btd_adapter *adapter);
+void btd_adapter_start(struct btd_adapter *adapter);
-int adapter_stop(struct btd_adapter *adapter);
+int btd_adapter_stop(struct btd_adapter *adapter);
+
+void btd_adapter_get_state(struct btd_adapter *adapter, uint8_t *mode,
+ uint8_t *on_mode, gboolean *pairable);
int adapter_set_service_classes(struct btd_adapter *adapter, uint8_t value);
@@ -111,9 +119,10 @@
int adapter_resolve_names(struct btd_adapter *adapter);
-struct btd_adapter *adapter_create(DBusConnection *conn, int id,
- gboolean devup);
+struct btd_adapter *adapter_create(DBusConnection *conn, int id);
+gboolean adapter_init(struct btd_adapter *adapter);
void adapter_remove(struct btd_adapter *adapter);
+uint8_t btd_adapter_get_init_mode(struct btd_adapter *adapter);
uint16_t adapter_get_dev_id(struct btd_adapter *adapter);
const gchar *adapter_get_path(struct btd_adapter *adapter);
void adapter_get_address(struct btd_adapter *adapter, bdaddr_t *bdaddr);
@@ -190,8 +199,9 @@
int (*start) (int index);
int (*stop) (int index);
int (*set_powered) (int index, gboolean powered);
- int (*set_connectable) (int index);
- int (*set_discoverable) (int index);
+ int (*set_connectable) (int index, gboolean connectable);
+ int (*set_discoverable) (int index, gboolean discoverable);
+ int (*set_pairable) (int index, gboolean pairable);
int (*set_limited_discoverable) (int index, gboolean limited);
int (*start_inquiry) (int index, uint8_t length, gboolean periodic);
int (*stop_inquiry) (int index);
@@ -221,7 +231,7 @@
int (*passkey_reply) (int index, bdaddr_t *bdaddr, uint32_t passkey);
int (*get_auth_info) (int index, bdaddr_t *bdaddr, uint8_t *auth);
int (*read_scan_enable) (int index);
- int (*write_le_host) (int index, uint8_t le, uint8_t simul);
+ int (*enable_le) (int index);
int (*get_remote_version) (int index, uint16_t handle,
gboolean delayed);
int (*encrypt_link) (int index, bdaddr_t *bdaddr, bt_hci_result_t cb,
@@ -230,6 +240,7 @@
uint16_t version);
int (*services_updated) (int index);
int (*disable_cod_cache) (int index);
+ int (*restore_powered) (int index);
};
int btd_register_adapter_ops(struct btd_adapter_ops *ops, gboolean priority);
diff --git a/src/hcid.h b/src/hcid.h
index 2e16328..856723b 100644
--- a/src/hcid.h
+++ b/src/hcid.h
@@ -23,21 +23,6 @@
*
*/
-/*
- * Scanning modes, used by DEV_SET_MODE
- * off: remote devices are not allowed to find or connect to this device
- * connectable: remote devices are allowed to connect, but they are not
- * allowed to find it.
- * discoverable: remote devices are allowed to connect and find this device
- * limited: limited discoverable - GIAC + IAC enabled and set limited
- * bit on device class.
- */
-
-#define MODE_OFF 0x00
-#define MODE_CONNECTABLE 0x01
-#define MODE_DISCOVERABLE 0x02
-#define MODE_UNKNOWN 0xff
-
struct main_opts {
char host_name[40];
unsigned long flags;
diff --git a/src/manager.c b/src/manager.c
index c8ec7e5..5421385 100644
--- a/src/manager.c
+++ b/src/manager.c
@@ -179,9 +179,6 @@
for (i = 0, list = adapters; list; list = list->next) {
struct btd_adapter *adapter = list->data;
- if (!adapter_is_ready(adapter))
- continue;
-
array[i] = (char *) adapter_get_path(adapter);
i++;
}
@@ -231,9 +228,6 @@
for (i = 0, list = adapters; list; list = list->next) {
struct btd_adapter *adapter = list->data;
- if (!adapter_is_ready(adapter))
- continue;
-
array[i] = (char *) adapter_get_path(adapter);
i++;
}
@@ -245,6 +239,26 @@
g_free(array);
}
+static void manager_set_default_adapter(int id)
+{
+ struct btd_adapter *adapter;
+ const gchar *path;
+
+ default_adapter_id = id;
+
+ adapter = manager_find_adapter_by_id(id);
+ if (!adapter)
+ return;
+
+ path = adapter_get_path(adapter);
+
+ g_dbus_emit_signal(connection, "/",
+ MANAGER_INTERFACE,
+ "DefaultAdapterChanged",
+ DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID);
+}
+
static void manager_remove_adapter(struct btd_adapter *adapter)
{
uint16_t dev_id = adapter_get_dev_id(adapter);
@@ -383,26 +397,48 @@
btd_stop_exit_timer();
}
-int manager_register_adapter(int id, gboolean devup)
+struct btd_adapter *btd_manager_register_adapter(int id)
{
struct btd_adapter *adapter;
+ const char *path;
adapter = manager_find_adapter_by_id(id);
if (adapter) {
error("Unable to register adapter: hci%d already exist", id);
- return -1;
+ return NULL;
}
- adapter = adapter_create(connection, id, devup);
+ adapter = adapter_create(connection, id);
if (!adapter)
- return -1;
+ return NULL;
adapters = g_slist_append(adapters, adapter);
- return 0;
+ if (!adapter_init(adapter)) {
+ btd_adapter_unref(adapter);
+ return NULL;
+ }
+
+
+ path = adapter_get_path(adapter);
+ g_dbus_emit_signal(connection, "/",
+ MANAGER_INTERFACE, "AdapterAdded",
+ DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID);
+
+ manager_update_adapters();
+
+ btd_stop_exit_timer();
+
+ if (default_adapter_id < 0)
+ manager_set_default_adapter(id);
+
+ DBG("Adapter %s registered", path);
+
+ return btd_adapter_ref(adapter);
}
-int manager_unregister_adapter(int id)
+int btd_manager_unregister_adapter(int id)
{
struct btd_adapter *adapter;
const gchar *path;
@@ -420,27 +456,6 @@
return 0;
}
-int manager_start_adapter(int id)
-{
- struct btd_adapter *adapter;
- int ret;
-
- adapter = manager_find_adapter_by_id(id);
- if (!adapter) {
- error("Getting device data failed: hci%d", id);
- return -EINVAL;
- }
-
- ret = adapter_start(adapter);
- if (ret < 0)
- return ret;
-
- if (default_adapter_id < 0)
- manager_set_default_adapter(id);
-
- return ret;
-}
-
int manager_stop_adapter(int id)
{
struct btd_adapter *adapter;
@@ -451,7 +466,7 @@
return -EINVAL;
}
- return adapter_stop(adapter);
+ return btd_adapter_stop(adapter);
}
int manager_get_default_adapter()
@@ -459,26 +474,6 @@
return default_adapter_id;
}
-void manager_set_default_adapter(int id)
-{
- struct btd_adapter *adapter;
- const gchar *path;
-
- default_adapter_id = id;
-
- adapter = manager_find_adapter_by_id(id);
- if (!adapter)
- return;
-
- path = adapter_get_path(adapter);
-
- g_dbus_emit_signal(connection, "/",
- MANAGER_INTERFACE,
- "DefaultAdapterChanged",
- DBUS_TYPE_OBJECT_PATH, &path,
- DBUS_TYPE_INVALID);
-}
-
void btd_manager_set_offline(gboolean offline)
{
GSList *l;
diff --git a/src/manager.h b/src/manager.h
index e6d5dd9..504df22 100644
--- a/src/manager.h
+++ b/src/manager.h
@@ -36,13 +36,11 @@
struct btd_adapter *manager_find_adapter_by_path(const char *path);
struct btd_adapter *manager_find_adapter_by_id(int id);
GSList *manager_get_adapters(void);
-int manager_register_adapter(int id, gboolean devup);
-int manager_unregister_adapter(int id);
-int manager_start_adapter(int id);
+struct btd_adapter *btd_manager_register_adapter(int id);
+int btd_manager_unregister_adapter(int id);
int manager_stop_adapter(int id);
void manager_add_adapter(const char *path);
int manager_get_default_adapter();
-void manager_set_default_adapter(int id);
void manager_update_svc(struct btd_adapter *adapter, uint8_t svc);
void btd_manager_set_offline(gboolean offline);
void btd_manager_set_did(uint16_t vendor, uint16_t product, uint16_t version);