diff --git a/lib/mgmt.h b/lib/mgmt.h
index 3960815..ca08214 100644
--- a/lib/mgmt.h
+++ b/lib/mgmt.h
/* Reserve one extra byte for names in management messages so that they
* are always guaranteed to be nul-terminated */
#define MGMT_MAX_NAME_LENGTH (HCI_MAX_NAME_LENGTH + 1)
+#define MGMT_MAX_SHORT_NAME_LENGTH (10 + 1)
+
+#define MGMT_SETTING_POWERED 0x00000001
+#define MGMT_SETTING_CONNECTABLE 0x00000002
+#define MGMT_SETTING_FAST_CONNECTABLE 0x00000004
+#define MGMT_SETTING_DISCOVERABLE 0x00000008
+#define MGMT_SETTING_PAIRABLE 0x00000010
+#define MGMT_SETTING_LINK_SECURITY 0x00000020
+#define MGMT_SETTING_SSP 0x00000040
+#define MGMT_SETTING_BREDR 0x00000080
+#define MGMT_SETTING_HS 0x00000100
+#define MGMT_SETTING_LE 0x00000200
#define MGMT_OP_READ_INFO 0x0004
struct mgmt_rp_read_info {
- uint8_t type;
- uint8_t powered;
- uint8_t connectable;
- uint8_t discoverable;
- uint8_t pairable;
- uint8_t sec_mode;
bdaddr_t bdaddr;
- uint8_t dev_class[3];
- uint8_t features[8];
+ uint8_t version;
uint16_t manufacturer;
- uint8_t hci_ver;
- uint16_t hci_rev;
+ uint32_t supported_settings;
+ uint32_t current_settings;
+ uint8_t dev_class[3];
uint8_t name[MGMT_MAX_NAME_LENGTH];
+ uint8_t short_name[MGMT_MAX_SHORT_NAME_LENGTH];
} __packed;
struct mgmt_mode {
#define MGMT_EV_INDEX_REMOVED 0x0005
-#define MGMT_EV_POWERED 0x0006
+#define MGMT_EV_NEW_SETTINGS 0x0006
#define MGMT_EV_DISCOVERABLE 0x0007
diff --git a/mgmt/main.c b/mgmt/main.c
index 91ce102..225ed74 100644
--- a/mgmt/main.c
+++ b/mgmt/main.c
return 0;
}
-static int mgmt_setting(int mgmt_sk, uint16_t index, uint16_t op,
+static const char *settings_str[] = {
+ "powered",
+ "connectable",
+ "fast-connectable",
+ "discoverable",
+ "pairable",
+ "link-security",
+ "ssp",
+ "br/edr",
+ "hs",
+ "le" ,
+};
+
+static void print_settings(uint32_t settings)
+{
+ unsigned i;
+
+ for (i = 0; i < NELEM(settings_str); i++) {
+ if ((settings & (1 << i)) != 0)
+ printf("%s ", settings_str[i]);
+ }
+}
+
+static int mgmt_new_settings(int mgmt_sk, uint16_t index,
+ uint32_t *ev, uint16_t len)
+{
+ if (len < sizeof(*ev)) {
+ fprintf(stderr, "Too short new_settings event (%u)\n", len);
+ return -EINVAL;
+ }
+
+ if (monitor) {
+ printf("hci%u new_settings: ", index);
+ print_settings(bt_get_le32(ev));
+ printf("\n");
+ }
+
+ return 0;
+}
+
+static int mgmt_discovering(int mgmt_sk, uint16_t index,
struct mgmt_mode *ev, uint16_t len)
{
if (len < sizeof(*ev)) {
- fprintf(stderr, "Too short (%u bytes) %s event\n",
- len, mgmt_evstr(op));
+ fprintf(stderr, "Too short (%u bytes) discovering event\n",
+ len);
return -EINVAL;
}
- if (op == MGMT_EV_DISCOVERING && ev->val == 0 && discovery)
+ if (ev->val == 0 && discovery)
exit(EXIT_SUCCESS);
if (monitor)
- printf("hci%u %s %s\n", index, mgmt_evstr(op),
+ printf("hci%u discovering %s\n", index,
ev->val ? "on" : "off");
return 0;
return mgmt_index_added(mgmt_sk, index);
case MGMT_EV_INDEX_REMOVED:
return mgmt_index_removed(mgmt_sk, index);
- case MGMT_EV_POWERED:
- case MGMT_EV_DISCOVERABLE:
- case MGMT_EV_CONNECTABLE:
- case MGMT_EV_PAIRABLE:
+ case MGMT_EV_NEW_SETTINGS:
+ return mgmt_new_settings(mgmt_sk, index, data, len);
case MGMT_EV_DISCOVERING:
- return mgmt_setting(mgmt_sk, index, ev, data, len);
+ return mgmt_discovering(mgmt_sk, index, data, len);
case MGMT_EV_NEW_LINK_KEY:
return mgmt_new_link_key(mgmt_sk, index, data, len);
case MGMT_EV_DEVICE_CONNECTED:
}
ba2str(&rp->bdaddr, addr);
- printf("hci%u:\ttype %u addr %s class 0x%02x%02x%02x\n",
- id, rp->type, addr,
- rp->dev_class[2], rp->dev_class[1], rp->dev_class[0]);
- printf("\tmanufacturer %d HCI ver %d:%d\n",
- bt_get_le16(&rp->manufacturer),
- rp->hci_ver, bt_get_le16(&rp->hci_rev));
- printf("\tpowered %u connectable %u discoverable %u\n",
- rp->powered, rp->connectable, rp->discoverable);
- printf("\tpairable %u sec_mode %u\n", rp->pairable, rp->sec_mode);
- printf("\tname %s\n\n", (char *) rp->name);
+ printf("hci%u:\taddr %s version %u manufacturer %u"
+ " class 0x%02x%02x%02x\n",
+ id, addr, rp->version, bt_get_le16(&rp->manufacturer),
+ rp->dev_class[2], rp->dev_class[1], rp->dev_class[0]);
+
+ printf("\tsupported settings: ");
+ print_settings(bt_get_le32(&rp->supported_settings));
+
+ printf("\n\tcurrent settings: ");
+ print_settings(bt_get_le32(&rp->current_settings));
+
+ printf("\n\tname %s\n", rp->name);
+ printf("\tshort name %s\n", rp->short_name);
if (pending == NULL)
exit(EXIT_SUCCESS);
static void setting_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
void *rsp, uint16_t len, void *user_data)
{
- struct mgmt_mode *rp = rsp;
+ uint32_t *rp = rsp;
if (status != 0) {
fprintf(stderr,
exit(EXIT_FAILURE);
}
- printf("hci%u %s %s\n", id, mgmt_opstr(op), rp->val ? "on" : "off");
+ printf("hci%u %s complete, settings: ", id, mgmt_opstr(op));
+ print_settings(bt_get_le32(rp));
+ printf("\n");
exit(EXIT_SUCCESS);
}
diff --git a/plugins/mgmtops.c b/plugins/mgmtops.c
index b9e9ad6..ff20822 100644
--- a/plugins/mgmtops.c
+++ b/plugins/mgmtops.c
static struct controller_info {
gboolean valid;
gboolean notified;
- uint8_t type;
bdaddr_t bdaddr;
- uint8_t features[8];
- uint8_t dev_class[3];
+ uint8_t version;
uint16_t manufacturer;
- uint8_t hci_ver;
- uint16_t hci_rev;
- gboolean enabled;
- gboolean connectable;
- gboolean discoverable;
- gboolean pairable;
- uint8_t sec_mode;
+ uint32_t supported_settings;
+ uint32_t current_settings;
+ uint8_t dev_class[3];
GSList *connections;
} *controllers = NULL;
return mgmt_set_mode(index, MGMT_OP_SET_PAIRABLE, pairable);
}
-static int mgmt_update_powered(int index, uint8_t powered)
+static inline int mgmt_powered(uint32_t settings)
{
- struct controller_info *info;
- struct btd_adapter *adapter;
- gboolean pairable;
- uint8_t on_mode;
-
- if (index > max_index) {
- error("Unexpected index %u", index);
- return -ENODEV;
- }
-
- info = &controllers[index];
-
- info->enabled = powered;
-
- adapter = manager_find_adapter(&info->bdaddr);
- if (adapter == NULL) {
- DBG("Adapter not found");
- return -ENODEV;
- }
-
- if (!powered) {
- info->connectable = FALSE;
- info->pairable = FALSE;
- info->discoverable = FALSE;
+ return (settings & MGMT_SETTING_POWERED) != 0;
+}
- btd_adapter_stop(adapter);
- return 0;
- }
+static inline int mgmt_connectable(uint32_t settings)
+{
+ return (settings & MGMT_SETTING_CONNECTABLE) != 0;
+}
- btd_adapter_start(adapter);
+static inline int mgmt_fast_connectable(uint32_t settings)
+{
+ return (settings & MGMT_SETTING_FAST_CONNECTABLE) != 0;
+}
- btd_adapter_get_mode(adapter, NULL, &on_mode, &pairable);
+static inline int mgmt_discoverable(uint32_t settings)
+{
+ return (settings & MGMT_SETTING_DISCOVERABLE) != 0;
+}
- if (on_mode == MODE_DISCOVERABLE && !info->discoverable)
- mgmt_set_discoverable(index, TRUE);
- else if (on_mode == MODE_CONNECTABLE && !info->connectable)
- mgmt_set_connectable(index, TRUE);
- else {
- uint8_t mode = 0;
+static inline int mgmt_pairable(uint32_t settings)
+{
+ return (settings & MGMT_SETTING_PAIRABLE) != 0;
+}
- if (info->connectable)
- mode |= SCAN_PAGE;
- if (info->discoverable)
- mode |= SCAN_INQUIRY;
+static inline int mgmt_ssp(uint32_t settings)
+{
+ return (settings & MGMT_SETTING_SSP) != 0;
+}
- adapter_mode_changed(adapter, mode);
- }
+static inline int mgmt_bredr(uint32_t settings)
+{
+ return (settings & MGMT_SETTING_BREDR) != 0;
+}
- if (info->pairable != pairable)
- mgmt_set_pairable(index, pairable);
+static inline int mgmt_high_speed(uint32_t settings)
+{
+ return (settings & MGMT_SETTING_HS) != 0;
+}
- return 0;
+static inline int mgmt_low_energy(uint32_t settings)
+{
+ return (settings & MGMT_SETTING_LE) != 0;
}
-static void mgmt_powered(int sk, uint16_t index, void *buf, size_t len)
+static uint8_t create_mode(uint32_t settings)
{
- struct mgmt_mode *ev = buf;
+ uint8_t mode = 0;
- if (len < sizeof(*ev)) {
- error("Too small powered event");
- return;
- }
+ if (mgmt_connectable(settings))
+ mode |= SCAN_PAGE;
- DBG("Controller %u powered %u", index, ev->val);
+ if (mgmt_discoverable(settings))
+ mode |= SCAN_INQUIRY;
- mgmt_update_powered(index, ev->val);
+ return mode;
}
-static void mgmt_discoverable(int sk, uint16_t index, void *buf, size_t len)
+static int mgmt_update_powered(struct btd_adapter *adapter, uint32_t settings)
{
- struct mgmt_mode *ev = buf;
- struct controller_info *info;
- struct btd_adapter *adapter;
- uint8_t mode;
-
- if (len < sizeof(*ev)) {
- error("Too small discoverable event");
- return;
- }
-
- DBG("Controller %u discoverable %u", index, ev->val);
+ gboolean pairable;
+ uint8_t on_mode;
+ uint16_t index;
- if (index > max_index) {
- error("Unexpected index %u in discoverable event", index);
- return;
+ if (!mgmt_powered(settings)) {
+ btd_adapter_stop(adapter);
+ return 0;
}
- info = &controllers[index];
+ btd_adapter_start(adapter);
- info->discoverable = ev->val ? TRUE : FALSE;
+ btd_adapter_get_mode(adapter, NULL, &on_mode, &pairable);
- adapter = manager_find_adapter(&info->bdaddr);
- if (!adapter)
- return;
+ index = adapter_get_dev_id(adapter);
- if (info->connectable)
- mode = SCAN_PAGE;
+ if (on_mode == MODE_DISCOVERABLE && !mgmt_discoverable(settings))
+ mgmt_set_discoverable(index, TRUE);
+ else if (on_mode == MODE_CONNECTABLE && !mgmt_connectable(settings))
+ mgmt_set_connectable(index, TRUE);
else
- mode = 0;
+ adapter_mode_changed(adapter, create_mode(settings));
- if (info->discoverable)
- mode |= SCAN_INQUIRY;
+ if (mgmt_pairable(settings) != pairable)
+ mgmt_set_pairable(index, pairable);
- adapter_mode_changed(adapter, mode);
+ return 0;
}
-static void mgmt_connectable(int sk, uint16_t index, void *buf, size_t len)
+static int mode_changed(uint32_t s1, uint32_t s2)
{
- struct mgmt_mode *ev = buf;
- struct controller_info *info;
- struct btd_adapter *adapter;
- uint8_t mode;
-
- if (len < sizeof(*ev)) {
- error("Too small connectable event");
- return;
- }
-
- DBG("Controller %u connectable %u", index, ev->val);
-
- if (index > max_index) {
- error("Unexpected index %u in connectable event", index);
- return;
- }
-
- info = &controllers[index];
-
- info->connectable = ev->val ? TRUE : FALSE;
-
- adapter = manager_find_adapter(&info->bdaddr);
- if (!adapter)
- return;
+ if (mgmt_connectable(s1) != mgmt_connectable(s2))
+ return 1;
- if (info->discoverable)
- mode = SCAN_INQUIRY;
- else
- mode = 0;
-
- if (info->connectable)
- mode |= SCAN_PAGE;
+ if (mgmt_discoverable(s1) != mgmt_discoverable(s2))
+ return 1;
- adapter_mode_changed(adapter, mode);
+ return 0;
}
-static void mgmt_pairable(int sk, uint16_t index, void *buf, size_t len)
+static void mgmt_new_settings(int sk, uint16_t index, void *buf, size_t len)
{
- struct mgmt_mode *ev = buf;
+ uint32_t settings, *ev = buf;
struct controller_info *info;
struct btd_adapter *adapter;
if (len < sizeof(*ev)) {
- error("Too small pairable event");
+ error("Too small new settings event");
return;
}
- DBG("Controller %u pairable %u", index, ev->val);
+ DBG("hci%u new settings", index);
if (index > max_index) {
- error("Unexpected index %u in pairable event", index);
+ error("Unexpected index %u in new_settings event", index);
return;
}
info = &controllers[index];
- info->pairable = ev->val ? TRUE : FALSE;
-
adapter = manager_find_adapter(&info->bdaddr);
- if (!adapter)
+ if (adapter == NULL) {
+ DBG("Adapter not found");
return;
+ }
+
+ settings = bt_get_le32(ev);
+
+ if (mgmt_powered(settings) != mgmt_powered(info->current_settings))
+ mgmt_update_powered(adapter, settings);
+ else if (mode_changed(settings, info->current_settings))
+ adapter_mode_changed(adapter, create_mode(settings));
+
+ if (mgmt_pairable(settings) != mgmt_pairable(info->current_settings))
+ btd_adapter_pairable_changed(adapter, mgmt_pairable(settings));
- btd_adapter_pairable_changed(adapter, info->pairable);
+ info->current_settings = settings;
}
static void mgmt_new_link_key(int sk, uint16_t index, void *buf, size_t len)
mgmt_set_mode(index, MGMT_OP_SET_SERVICE_CACHE, 1);
info = &controllers[index];
- info->type = rp->type;
- info->enabled = rp->powered;
- info->connectable = rp->connectable;
- info->discoverable = rp->discoverable;
- info->pairable = rp->pairable;
- info->sec_mode = rp->sec_mode;
+
bacpy(&info->bdaddr, &rp->bdaddr);
- memcpy(info->dev_class, rp->dev_class, 3);
- memcpy(info->features, rp->features, 8);
+ info->version = rp->version;
info->manufacturer = btohs(bt_get_unaligned(&rp->manufacturer));
- info->hci_ver = rp->hci_ver;
- info->hci_rev = btohs(bt_get_unaligned(&rp->hci_rev));
+
+ memcpy(&info->supported_settings, &rp->supported_settings,
+ sizeof(info->supported_settings));
+ memcpy(&info->current_settings, &rp->current_settings,
+ sizeof(info->current_settings));
+
+ memcpy(info->dev_class, rp->dev_class, sizeof(info->dev_class));
ba2str(&info->bdaddr, addr);
- DBG("hci%u type %u addr %s", index, info->type, addr);
- DBG("hci%u class 0x%02x%02x%02x", index,
+ DBG("hci%u addr %s version %u manufacturer %u class 0x%02x%02x%02x\n",
+ index, addr, info->version, info->manufacturer,
info->dev_class[2], info->dev_class[1], info->dev_class[0]);
- DBG("hci%u manufacturer %d HCI ver %d:%d", index, info->manufacturer,
- info->hci_ver, info->hci_rev);
- DBG("hci%u enabled %u discoverable %u pairable %u sec_mode %u", index,
- info->enabled, info->discoverable,
- info->pairable, info->sec_mode);
+ DBG("hci%u settings", index);
DBG("hci%u name %s", index, (char *) rp->name);
+ DBG("hci%u short name %s", index, (char *) rp->short_name);
adapter = btd_manager_register_adapter(index);
if (adapter == NULL) {
return;
}
- if (info->enabled)
- mgmt_update_powered(index, TRUE);
+ if (mgmt_powered(info->current_settings))
+ mgmt_update_powered(adapter, info->current_settings);
else
mgmt_set_powered(index, TRUE);
btd_adapter_unref(adapter);
}
-static void set_powered_complete(int sk, uint16_t index, void *buf, size_t len)
-{
- struct mgmt_mode *rp = buf;
-
- if (len < sizeof(*rp)) {
- error("Too small set powered complete event");
- return;
- }
-
- DBG("hci%d powered %u", index, rp->val);
-
- mgmt_update_powered(index, rp->val);
-}
-
-static void set_discoverable_complete(int sk, uint16_t index, void *buf,
- size_t len)
-{
- struct mgmt_mode *rp = buf;
- struct controller_info *info;
- struct btd_adapter *adapter;
- uint8_t mode;
-
- if (len < sizeof(*rp)) {
- error("Too small set discoverable complete event");
- return;
- }
-
- DBG("hci%d discoverable %u", index, rp->val);
-
- if (index > max_index) {
- error("Unexpected index %u in discoverable complete", index);
- return;
- }
-
- info = &controllers[index];
-
- info->discoverable = rp->val ? TRUE : FALSE;
-
- adapter = manager_find_adapter(&info->bdaddr);
- if (!adapter)
- return;
-
- /* set_discoverable will always also change page scanning */
- mode = SCAN_PAGE;
-
- if (info->discoverable)
- mode |= SCAN_INQUIRY;
-
- adapter_mode_changed(adapter, mode);
-}
-
-static void set_connectable_complete(int sk, uint16_t index, void *buf,
- size_t len)
-{
- struct mgmt_mode *rp = buf;
- struct controller_info *info;
- struct btd_adapter *adapter;
-
- if (len < sizeof(*rp)) {
- error("Too small set connectable complete event");
- return;
- }
-
- DBG("hci%d connectable %u", index, rp->val);
-
- if (index > max_index) {
- error("Unexpected index %u in connectable complete", index);
- return;
- }
-
- info = &controllers[index];
-
- info->connectable = rp->val ? TRUE : FALSE;
-
- adapter = manager_find_adapter(&info->bdaddr);
- if (adapter)
- adapter_mode_changed(adapter, rp->val ? SCAN_PAGE : 0);
-}
-
-static void set_pairable_complete(int sk, uint16_t index, void *buf,
- size_t len)
-{
- struct mgmt_mode *rp = buf;
- struct controller_info *info;
- struct btd_adapter *adapter;
-
- if (len < sizeof(*rp)) {
- error("Too small set pairable complete event");
- return;
- }
-
- DBG("hci%d pairable %u", index, rp->val);
-
- if (index > max_index) {
- error("Unexpected index %u in pairable complete", index);
- return;
- }
-
- info = &controllers[index];
-
- info->pairable = rp->val ? TRUE : FALSE;
-
- adapter = manager_find_adapter(&info->bdaddr);
- if (!adapter)
- return;
-
- btd_adapter_pairable_changed(adapter, info->pairable);
-}
-
static void disconnect_complete(int sk, uint16_t index, void *buf, size_t len)
{
struct mgmt_rp_disconnect *rp = buf;
read_info_complete(sk, index, ev->data, len);
break;
case MGMT_OP_SET_POWERED:
- set_powered_complete(sk, index, ev->data, len);
+ mgmt_new_settings(sk, index, ev->data, len);
break;
case MGMT_OP_SET_DISCOVERABLE:
- set_discoverable_complete(sk, index, ev->data, len);
+ mgmt_new_settings(sk, index, ev->data, len);
break;
case MGMT_OP_SET_CONNECTABLE:
- set_connectable_complete(sk, index, ev->data, len);
+ mgmt_new_settings(sk, index, ev->data, len);
break;
case MGMT_OP_SET_PAIRABLE:
- set_pairable_complete(sk, index, ev->data, len);
+ mgmt_new_settings(sk, index, ev->data, len);
break;
case MGMT_OP_ADD_UUID:
DBG("add_uuid complete");
case MGMT_EV_INDEX_REMOVED:
mgmt_index_removed(sk, index);
break;
- case MGMT_EV_POWERED:
- mgmt_powered(sk, index, buf + MGMT_HDR_SIZE, len);
- break;
- case MGMT_EV_DISCOVERABLE:
- mgmt_discoverable(sk, index, buf + MGMT_HDR_SIZE, len);
- break;
- case MGMT_EV_CONNECTABLE:
- mgmt_connectable(sk, index, buf + MGMT_HDR_SIZE, len);
- break;
- case MGMT_EV_PAIRABLE:
- mgmt_pairable(sk, index, buf + MGMT_HDR_SIZE, len);
+ case MGMT_EV_NEW_SETTINGS:
+ mgmt_new_settings(sk, index, buf + MGMT_HDR_SIZE, len);
break;
case MGMT_EV_NEW_LINK_KEY:
mgmt_new_link_key(sk, index, buf + MGMT_HDR_SIZE, len);