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:
parent
32bde4fe78
commit
649a813bf6
6 changed files with 238 additions and 1 deletions
|
@ -1977,6 +1977,7 @@ PREDEFINED = "CONFIG_SYS_CLOCK_EXISTS=y" \
|
|||
"CONFIG_SYS_POWER_MANAGEMENT=y" \
|
||||
"CONFIG_DEVICE_POWER_MANAGEMENT=y" \
|
||||
"CONFIG_BT_SMP=y" \
|
||||
"CONFIG_BT_REMOTE_INFO=y" \
|
||||
"CONFIG_USERSPACE=y" \
|
||||
"CONFIG_BT_BREDR=y" \
|
||||
"CONFIG_FLASH_PAGE_LAYOUT=y" \
|
||||
|
|
|
@ -163,7 +163,6 @@ enum {
|
|||
};
|
||||
|
||||
/** @brief Connection Info Structure
|
||||
*
|
||||
*
|
||||
* @param type Connection Type
|
||||
* @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
|
||||
*
|
||||
* @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);
|
||||
|
||||
/** @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.
|
||||
*
|
||||
* @param conn Connection object.
|
||||
|
@ -494,6 +555,17 @@ struct bt_conn_cb {
|
|||
void (*security_changed)(struct bt_conn *conn, bt_security_t level,
|
||||
enum bt_security_err err);
|
||||
#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;
|
||||
};
|
||||
|
||||
|
|
|
@ -261,6 +261,22 @@ config BT_AUTO_PHY_UPDATE
|
|||
want to rely on remote device to initiate the procedure at its
|
||||
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
|
||||
bool "Security Manager Protocol support"
|
||||
select TINYCRYPT
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
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);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Notify disconnection and queue a dummy buffer to wake
|
||||
* up and stop the tx thread for states where it was
|
||||
* running.
|
||||
|
@ -1902,6 +1924,42 @@ int bt_conn_get_info(const struct bt_conn *conn, struct bt_conn_info *info)
|
|||
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)
|
||||
{
|
||||
struct net_buf *buf;
|
||||
|
|
|
@ -33,6 +33,7 @@ enum {
|
|||
|
||||
BT_CONN_AUTO_PHY_COMPLETE, /* Auto-initiated PHY procedure 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 */
|
||||
BT_CONN_NUM_FLAGS,
|
||||
|
@ -146,6 +147,14 @@ struct bt_conn {
|
|||
struct bt_conn_sco sco;
|
||||
#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 */
|
||||
|
@ -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,
|
||||
const struct bt_le_conn_param *param);
|
||||
|
||||
void notify_remote_info(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);
|
||||
|
|
|
@ -967,6 +967,33 @@ static int hci_le_read_remote_features(struct bt_conn *conn)
|
|||
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
|
||||
* 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) &&
|
||||
!atomic_test_bit(conn->flags, BT_CONN_AUTO_PHY_COMPLETE) &&
|
||||
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);
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_REMOTE_INFO) &&
|
||||
!IS_ENABLED(CONFIG_BT_REMOTE_VERSION)) {
|
||||
notify_remote_info(conn);
|
||||
}
|
||||
|
||||
/* Continue with auto-initiated procedures */
|
||||
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 */
|
||||
|
||||
#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)
|
||||
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,
|
||||
sizeof(struct bt_hci_evt_encrypt_key_refresh_complete)),
|
||||
#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)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue