Bluetooth: host: Add calling of read_remote_version

Make remote features and remote version accesible to the application
through the bt_conn_get_remote_info object. The host will auto initiate
the procedures. If the procedures have not finished with the application
calls bt_conn_get_remote_info then EBUSY will be returned.
The procedures should finish during the first 10 connection intervals.

Signed-off-by: Sverre Storvold <Sverre.Storvold@nordicsemi.no>
Signed-off-by: Joakim Andersson <joakim.andersson@nordicsemi.no>
This commit is contained in:
Sverre Storvold 2019-09-27 14:53:40 +02:00 committed by Johan Hedberg
commit 649a813bf6
6 changed files with 238 additions and 1 deletions

View file

@ -1977,6 +1977,7 @@ PREDEFINED = "CONFIG_SYS_CLOCK_EXISTS=y" \
"CONFIG_SYS_POWER_MANAGEMENT=y" \ "CONFIG_SYS_POWER_MANAGEMENT=y" \
"CONFIG_DEVICE_POWER_MANAGEMENT=y" \ "CONFIG_DEVICE_POWER_MANAGEMENT=y" \
"CONFIG_BT_SMP=y" \ "CONFIG_BT_SMP=y" \
"CONFIG_BT_REMOTE_INFO=y" \
"CONFIG_USERSPACE=y" \ "CONFIG_USERSPACE=y" \
"CONFIG_BT_BREDR=y" \ "CONFIG_BT_BREDR=y" \
"CONFIG_FLASH_PAGE_LAYOUT=y" \ "CONFIG_FLASH_PAGE_LAYOUT=y" \

View file

@ -163,7 +163,6 @@ enum {
}; };
/** @brief Connection Info Structure /** @brief Connection Info Structure
*
* *
* @param type Connection Type * @param type Connection Type
* @param role Connection Role * @param role Connection Role
@ -185,6 +184,50 @@ struct bt_conn_info {
}; };
}; };
/** LE Connection Remote Info Structure */
struct bt_conn_le_remote_info {
/** Remote LE feature set (bitmask). */
const u8_t *features;
};
/** BR/EDR Connection Remote Info structure */
struct bt_conn_br_remote_info {
/** Remote feature set (pages of bitmasks). */
const u8_t *features;
/** Number of pages in the remote feature set. */
u8_t num_pages;
};
/** @brief Connection Remote Info Structure
*
* @note The version, manufacturer and subversion fields will only contain
* valid data if :option:`CONFIG_BT_REMOTE_VERSION` is enabled.
*/
struct bt_conn_remote_info {
/* Connection Type */
u8_t type;
/* Remote Link Layer version */
u8_t version;
/* Remote manufacturer identifier */
u16_t manufacturer;
/* Per-manufacturer unique revision */
u16_t subversion;
union {
/* LE connection remote info */
struct bt_conn_le_remote_info le;
/* BR/EDR connection remote info */
struct bt_conn_br_remote_info br;
};
};
/** @brief Get connection info /** @brief Get connection info
* *
* @param conn Connection object. * @param conn Connection object.
@ -194,6 +237,24 @@ struct bt_conn_info {
*/ */
int bt_conn_get_info(const struct bt_conn *conn, struct bt_conn_info *info); int bt_conn_get_info(const struct bt_conn *conn, struct bt_conn_info *info);
/** @brief Get connection info for the remote device.
*
* @param conn Connection object.
* @param remote_info Connection remote info object.
*
* @note In order to retrieve the remote version (version, manufacturer
* and subversion) :option:`CONFIG_BT_REMOTE_VERSION` must be enabled
*
* @note The remote information is exchanged directly after the connection has
* been established. The application can be notified about when the remote
* information is available through the remote_info_available callback.
*
* @return Zero on success or (negative) error code on failure.
* @return -EBUSY The remote information is not yet available.
*/
int bt_conn_get_remote_info(struct bt_conn *conn,
struct bt_conn_remote_info *remote_info);
/** @brief Update the connection parameters. /** @brief Update the connection parameters.
* *
* @param conn Connection object. * @param conn Connection object.
@ -494,6 +555,17 @@ struct bt_conn_cb {
void (*security_changed)(struct bt_conn *conn, bt_security_t level, void (*security_changed)(struct bt_conn *conn, bt_security_t level,
enum bt_security_err err); enum bt_security_err err);
#endif /* defined(CONFIG_BT_SMP) || defined(CONFIG_BT_BREDR) */ #endif /* defined(CONFIG_BT_SMP) || defined(CONFIG_BT_BREDR) */
#if defined(CONFIG_BT_REMOTE_INFO)
/** @brief Remote information procedures has completed.
*
* This callback notifies the application that the remote information
* has been retrieved from the remote peer.
*/
void (*remote_info_available)(struct bt_conn *conn,
struct bt_conn_remote_info *remote_info);
#endif /* defined(CONFIG_BT_REMOTE_INFO) */
struct bt_conn_cb *_next; struct bt_conn_cb *_next;
}; };

View file

@ -261,6 +261,22 @@ config BT_AUTO_PHY_UPDATE
want to rely on remote device to initiate the procedure at its want to rely on remote device to initiate the procedure at its
discretion. discretion.
config BT_REMOTE_INFO
bool "Enable application access to remote information"
help
Enable application access to the remote information available in the
stack. The remote information is retrieved once a connection has been
established and the application will be notified when this information
is available through the remote_version_available connection callback.
config BT_REMOTE_VERSION
bool "Enable remote version information"
depends on BT_REMOTE_INFO
help
Enable this to get access to the remote version through
the remote_version_available callback. The host will automatically ask
the remote device after the connection has been established.
config BT_SMP config BT_SMP
bool "Security Manager Protocol support" bool "Security Manager Protocol support"
select TINYCRYPT select TINYCRYPT

View file

@ -154,6 +154,27 @@ static void notify_disconnected(struct bt_conn *conn)
} }
} }
#if defined(CONFIG_BT_REMOTE_INFO)
void notify_remote_info(struct bt_conn *conn)
{
struct bt_conn_remote_info remote_info;
struct bt_conn_cb *cb;
int err;
err = bt_conn_get_remote_info(conn, &remote_info);
if (err) {
BT_DBG("Notify remote info failed %d", err);
return;
}
for (cb = callback_list; cb; cb = cb->_next) {
if (cb->remote_info_available) {
cb->remote_info_available(conn, &remote_info);
}
}
}
#endif /* defined(CONFIG_BT_REMOTE_INFO) */
void notify_le_param_updated(struct bt_conn *conn) void notify_le_param_updated(struct bt_conn *conn)
{ {
struct bt_conn_cb *cb; struct bt_conn_cb *cb;
@ -1638,6 +1659,7 @@ void bt_conn_set_state(struct bt_conn *conn, bt_conn_state_t state)
bt_conn_unref(conn); bt_conn_unref(conn);
break; break;
} }
/* Notify disconnection and queue a dummy buffer to wake /* Notify disconnection and queue a dummy buffer to wake
* up and stop the tx thread for states where it was * up and stop the tx thread for states where it was
* running. * running.
@ -1902,6 +1924,42 @@ int bt_conn_get_info(const struct bt_conn *conn, struct bt_conn_info *info)
return -EINVAL; return -EINVAL;
} }
int bt_conn_get_remote_info(struct bt_conn *conn,
struct bt_conn_remote_info *remote_info)
{
if (!atomic_test_bit(conn->flags, BT_CONN_AUTO_FEATURE_EXCH) ||
(IS_ENABLED(CONFIG_BT_REMOTE_VERSION) &&
!atomic_test_bit(conn->flags, BT_CONN_AUTO_VERSION_INFO))) {
return -EBUSY;
}
remote_info->type = conn->type;
#if defined(CONFIG_BT_REMOTE_VERSION)
/* The conn->rv values will be just zeroes if the operation failed */
remote_info->version = conn->rv.version;
remote_info->manufacturer = conn->rv.manufacturer;
remote_info->subversion = conn->rv.subversion;
#else
remote_info->version = 0;
remote_info->manufacturer = 0;
remote_info->subversion = 0;
#endif
switch (conn->type) {
case BT_CONN_TYPE_LE:
remote_info->le.features = conn->le.features;
return 0;
#if defined(CONFIG_BT_BREDR)
case BT_CONN_TYPE_BR:
/* TODO: Make sure the HCI commands to read br features and
* extended features has finished. */
return -ENOTSUP;
#endif
default:
return -EINVAL;
}
}
static int bt_hci_disconnect(struct bt_conn *conn, u8_t reason) static int bt_hci_disconnect(struct bt_conn *conn, u8_t reason)
{ {
struct net_buf *buf; struct net_buf *buf;

View file

@ -33,6 +33,7 @@ enum {
BT_CONN_AUTO_PHY_COMPLETE, /* Auto-initiated PHY procedure done */ BT_CONN_AUTO_PHY_COMPLETE, /* Auto-initiated PHY procedure done */
BT_CONN_AUTO_FEATURE_EXCH, /* Auto-initiated LE Feat done */ BT_CONN_AUTO_FEATURE_EXCH, /* Auto-initiated LE Feat done */
BT_CONN_AUTO_VERSION_INFO, /* Auto-initiated LE version done */
/* Total number of flags - must be at the end of the enum */ /* Total number of flags - must be at the end of the enum */
BT_CONN_NUM_FLAGS, BT_CONN_NUM_FLAGS,
@ -146,6 +147,14 @@ struct bt_conn {
struct bt_conn_sco sco; struct bt_conn_sco sco;
#endif #endif
}; };
#if defined(CONFIG_BT_REMOTE_VERSION)
struct bt_conn_rv {
u8_t version;
u16_t manufacturer;
u16_t subversion;
} rv;
#endif
}; };
/* Process incoming data for a connection */ /* Process incoming data for a connection */
@ -212,6 +221,8 @@ void bt_conn_set_state(struct bt_conn *conn, bt_conn_state_t state);
int bt_conn_le_conn_update(struct bt_conn *conn, int bt_conn_le_conn_update(struct bt_conn *conn,
const struct bt_le_conn_param *param); const struct bt_le_conn_param *param);
void notify_remote_info(struct bt_conn *conn);
void notify_le_param_updated(struct bt_conn *conn); void notify_le_param_updated(struct bt_conn *conn);
bool le_param_req(struct bt_conn *conn, struct bt_le_conn_param *param); bool le_param_req(struct bt_conn *conn, struct bt_le_conn_param *param);

View file

@ -967,6 +967,33 @@ static int hci_le_read_remote_features(struct bt_conn *conn)
return 0; return 0;
} }
static int hci_read_remote_version(struct bt_conn *conn)
{
struct bt_hci_cp_read_remote_version_info *cp;
struct net_buf *buf;
if (conn->state != BT_CONN_CONNECTED) {
return -ENOTCONN;
}
/* Remote version cannot change. */
if (atomic_test_bit(conn->flags, BT_CONN_AUTO_VERSION_INFO)) {
return 0;
}
buf = bt_hci_cmd_create(BT_HCI_OP_READ_REMOTE_VERSION_INFO,
sizeof(*cp));
if (!buf) {
return -ENOBUFS;
}
cp = net_buf_add(buf, sizeof(*cp));
cp->handle = sys_cpu_to_le16(conn->handle);
return bt_hci_cmd_send_sync(BT_HCI_OP_READ_REMOTE_VERSION_INFO, buf,
NULL);
}
/* LE Data Length Change Event is optional so this function just ignore /* LE Data Length Change Event is optional so this function just ignore
* error and stack will continue to use default values. * error and stack will continue to use default values.
*/ */
@ -1099,6 +1126,14 @@ static void conn_auto_initiate(struct bt_conn *conn)
} }
} }
if (IS_ENABLED(CONFIG_BT_REMOTE_VERSION) &&
!atomic_test_bit(conn->flags, BT_CONN_AUTO_VERSION_INFO)) {
err = hci_read_remote_version(conn);
if (!err) {
return;
}
}
if (IS_ENABLED(CONFIG_BT_AUTO_PHY_UPDATE) && if (IS_ENABLED(CONFIG_BT_AUTO_PHY_UPDATE) &&
!atomic_test_bit(conn->flags, BT_CONN_AUTO_PHY_COMPLETE) && !atomic_test_bit(conn->flags, BT_CONN_AUTO_PHY_COMPLETE) &&
BT_FEAT_LE_PHY_2M(bt_dev.le.features)) { BT_FEAT_LE_PHY_2M(bt_dev.le.features)) {
@ -1372,6 +1407,12 @@ static void le_remote_feat_complete(struct net_buf *buf)
} }
atomic_set_bit(conn->flags, BT_CONN_AUTO_FEATURE_EXCH); atomic_set_bit(conn->flags, BT_CONN_AUTO_FEATURE_EXCH);
if (IS_ENABLED(CONFIG_BT_REMOTE_INFO) &&
!IS_ENABLED(CONFIG_BT_REMOTE_VERSION)) {
notify_remote_info(conn);
}
/* Continue with auto-initiated procedures */ /* Continue with auto-initiated procedures */
conn_auto_initiate(conn); conn_auto_initiate(conn);
@ -3231,6 +3272,39 @@ static void hci_encrypt_key_refresh_complete(struct net_buf *buf)
} }
#endif /* CONFIG_BT_SMP || CONFIG_BT_BREDR */ #endif /* CONFIG_BT_SMP || CONFIG_BT_BREDR */
#if defined(CONFIG_BT_REMOTE_VERSION)
static void bt_hci_evt_read_remote_version_complete(struct net_buf *buf)
{
struct bt_hci_evt_remote_version_info *evt;
struct bt_conn *conn;
evt = net_buf_pull_mem(buf, sizeof(*evt));
conn = bt_conn_lookup_handle(evt->handle);
if (!conn) {
BT_ERR("No connection for handle %u", evt->handle);
return;
}
if (!evt->status) {
conn->rv.version = evt->version;
conn->rv.manufacturer = sys_le16_to_cpu(evt->manufacturer);
conn->rv.subversion = sys_le16_to_cpu(evt->subversion);
}
atomic_set_bit(conn->flags, BT_CONN_AUTO_VERSION_INFO);
if (IS_ENABLED(CONFIG_BT_REMOTE_INFO)) {
/* Remote features is already present */
notify_remote_info(conn);
}
/* Continue with auto-initiated procedures */
conn_auto_initiate(conn);
bt_conn_unref(conn);
}
#endif /* CONFIG_BT_REMOTE_VERSION */
#if defined(CONFIG_BT_SMP) #if defined(CONFIG_BT_SMP)
static void le_ltk_neg_reply(u16_t handle) static void le_ltk_neg_reply(u16_t handle)
{ {
@ -3795,6 +3869,11 @@ static const struct event_handler normal_events[] = {
hci_encrypt_key_refresh_complete, hci_encrypt_key_refresh_complete,
sizeof(struct bt_hci_evt_encrypt_key_refresh_complete)), sizeof(struct bt_hci_evt_encrypt_key_refresh_complete)),
#endif /* CONFIG_BT_SMP || CONFIG_BT_BREDR */ #endif /* CONFIG_BT_SMP || CONFIG_BT_BREDR */
#if defined(CONFIG_BT_REMOTE_VERSION)
EVENT_HANDLER(BT_HCI_EVT_REMOTE_VERSION_INFO,
bt_hci_evt_read_remote_version_complete,
sizeof(struct bt_hci_evt_remote_version_info)),
#endif /* CONFIG_BT_REMOTE_VERSION */
}; };
static void hci_event(struct net_buf *buf) static void hci_event(struct net_buf *buf)