zephyr/subsys/bluetooth/host/conn_internal.h

321 lines
9.3 KiB
C
Raw Permalink Normal View History

/** @file
* @brief Internal APIs for Bluetooth connection handling.
*/
/*
* Copyright (c) 2015 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
typedef enum __packed {
BT_CONN_DISCONNECTED,
Bluetooth: Fix host RX thread deadlock Fix host RX thread being deadlocked. The deadlock occurs because the RX thread is stuck waiting in conn_tx_alloc with K_FOREVER but if the connection is disconnected only the RX thread can unblock it in the handling of the disconnect event. This commit fixes this deadlock by splitting the processing of the disconnected event into two parts. The part needed to unblock the RX is to release resources held by unack'ed TX packets and mark the connection state as not connected anymore. The RX thread waiting for free_tx fifo and the TX thread waiting for the bt_dev.le.pkts semaphore will both check the connected state after having acquired them and will abort if disconnected. The rest of the processing will be handled at normal RX thread priority like normal. Move the bt_recv_prio handling to the Bluetooth host when the host has defined its own RX thread (CONFIG_BT_RECV_IS_RX_THREAD=n). If the HCI driver has the RX thread (CONFIG_BT_RECV_IS_RX_THREAD=y), then the responsibility to call bt_recv and bt_recv_prio correctly falls to the HCI driver. The helper function bt_hci_evt_is_prio() is replaced with bt_hci_evt_get_flags() so that the HCI driver can do this correctly. This decision to replace was made so that existing HCI drivers maintained out-of-tree will fail at compile time with the new system. Signed-off-by: Joakim Andersson <joakim.andersson@nordicsemi.no> Signed-off-by: Carles Cufi <carles.cufi@nordicsemi.no> Bluetooth: host: Move bt_recv_prio to host when RX thread is defined Signed-off-by: Joakim Andersson <joakim.andersson@nordicsemi.no>
2020-06-03 14:48:04 +02:00
BT_CONN_DISCONNECT_COMPLETE,
BT_CONN_CONNECT_SCAN,
BT_CONN_CONNECT_AUTO,
BT_CONN_CONNECT_ADV,
BT_CONN_CONNECT_DIR_ADV,
BT_CONN_CONNECT,
BT_CONN_CONNECTED,
BT_CONN_DISCONNECT,
} bt_conn_state_t;
/* bt_conn flags: the flags defined here represent connection parameters */
enum {
BT_CONN_AUTO_CONNECT,
BT_CONN_BR_LEGACY_SECURE, /* 16 digits legacy PIN tracker */
BT_CONN_USER, /* user I/O when pairing */
Bluetooth: BR/EDR: Add pairing mode flag Since right now the stack supports as acceptor pre-2.1 devices pairing, start set the state pairing flag in legacy PIN request handler and resets it on Encryption Changed event. When connection is 'in-pairing' mode disallow of local user to trigger change security level on link. > HCI Event: Command Status (0x0f) plen 4 Accept Connection Request (0x01|0x0009) ncmd 1 Status: Success (0x00) > HCI Event: PIN Code Request (0x16) plen 6 Address: 00:1A:7D:DA:71:13 (cyber-blue(HK)Ltd) < HCI Command: PIN Code Request Reply (0x01|0x000d) plen 23 Address: 00:1A:7D:DA:71:13 (cyber-blue(HK)Ltd) PIN length: 4 PIN code: 1234 > HCI Event: Command Complete (0x0e) plen 10 PIN Code Request Reply (0x01|0x000d) ncmd 1 Status: Success (0x00) Address: 00:1A:7D:DA:71:13 (cyber-blue(HK)Ltd) > HCI Event: Link Key Notification (0x18) plen 23 Address: 00:1A:7D:DA:71:13 (cyber-blue(HK)Ltd) Link key: 2a4eae1018ed248064166e765d946313 Key type: Combination key (0x00) > HCI Event: Connect Complete (0x03) plen 11 Status: Success (0x00) Handle: 12 Address: 00:1A:7D:DA:71:13 (cyber-blue(HK)Ltd) Link type: ACL (0x01) Encryption: Disabled (0x00) > ACL Data RX: Handle 12 flags 0x02 dlen 10 L2CAP: Information Request (0x0a) ident 1 len 2 Type: Extended features supported (0x0002) < HCI Command: Host Number of Completed Packets (0x03|0x0035) plen 5 Num handles: 1 Handle: 12 Count: 1 > HCI Event: Encryption Change (0x08) plen 4 Status: Success (0x00) Handle: 12 Encryption: Enabled with E0 (0x01) Change-Id: I5cbdaab1d6d52197795bfffd465ba59216afee00 Signed-off-by: Arkadiusz Lichwa <arkadiusz.lichwa@tieto.com>
2016-02-19 12:16:38 +01:00
BT_CONN_BR_PAIRING, /* BR connection in pairing context */
BT_CONN_BR_NOBOND, /* SSP no bond pairing tracker */
Bluetooth: BR/EDR: Initiate authentication Enables initiate authentication using possibility to change security level on link by calling internal security API. In case of failure resets pairing state flag to re-enable change security on subsequent authentication attempts. To verify the process of authentication run BT shell app from tests/bluetooth/shell folder and use commands like below: >br-connect xx:xx:xx:xx:xx:xx [Connected: xx:xx:xx:xx:xx:xx] >security 1 HCI log: > HCI Event: Connect Complete (0x03) plen 11 Status: Success (0x00) Handle: 11 Address: 00:13:17:72:8D:87 (GN Netcom A/S) Link type: ACL (0x01) Encryption: Disabled (0x00) < HCI Command: Authentication Requested (0x01|0x0011) plen 2 Handle: 11 > HCI Event: Command Status (0x0f) plen 4 Authentication Requested (0x01|0x0011) ncmd 1 Status: Success (0x00) > HCI Event: Link Key Request (0x17) plen 6 Address: 00:13:17:72:8D:87 (GN Netcom A/S) < HCI Command: Link Key Request Negative Reply (0x01|0x000c) plen 6 Address: 00:13:17:72:8D:87 (GN Netcom A/S) > HCI Event: Command Complete (0x0e) plen 10 Link Key Request Negative Reply (0x01|0x000c) ncmd 1 Status: Success (0x00) Address: 00:13:17:72:8D:87 (GN Netcom A/S) > HCI Event: PIN Code Request (0x16) plen 6 Address: 00:13:17:72:8D:87 (GN Netcom A/S) < HCI Command: PIN Code Request Reply (0x01|0x000d) plen 23 Address: 00:13:17:72:8D:87 (GN Netcom A/S) PIN length: 4 PIN code: 0000 > HCI Event: Command Complete (0x0e) plen 10 PIN Code Request Reply (0x01|0x000d) ncmd 1 Status: Success (0x00) Address: 00:13:17:72:8D:87 (GN Netcom A/S) > HCI Event: Link Key Notification (0x18) plen 23 Address: 00:13:17:72:8D:87 (GN Netcom A/S) Link key: d9ff76c09284c1ed369851f87d7ac623 Key type: Combination key (0x00) > HCI Event: Auth Complete (0x06) plen 3 Status: Success (0x00) Handle: 11 Change-Id: I2d383d34e19c04ead3fa254e5514d5c7f352a21e Signed-off-by: Arkadiusz Lichwa <arkadiusz.lichwa@tieto.com>
2016-03-18 14:13:23 +01:00
BT_CONN_BR_PAIRING_INITIATOR, /* local host starts authentication */
BT_CONN_CLEANUP, /* Disconnected, pending cleanup */
BT_CONN_AUTO_PHY_UPDATE, /* Auto-update PHY */
BT_CONN_SLAVE_PARAM_UPDATE, /* If slave param update timer fired */
BT_CONN_SLAVE_PARAM_SET, /* If slave param were set from app */
BT_CONN_SLAVE_PARAM_L2CAP, /* If should force L2CAP for CPUP */
BT_CONN_FORCE_PAIR, /* Pairing even with existing keys. */
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 */
BT_CONN_AUTO_DATA_LEN_COMPLETE, /* Auto-initiated Data Length done */
/* Total number of flags - must be at the end of the enum */
BT_CONN_NUM_FLAGS,
};
struct bt_conn_le {
bt_addr_le_t dst;
bt_addr_le_t init_addr;
bt_addr_le_t resp_addr;
uint16_t interval;
uint16_t interval_min;
uint16_t interval_max;
uint16_t latency;
uint16_t timeout;
uint16_t pending_latency;
uint16_t pending_timeout;
uint8_t features[8];
struct bt_keys *keys;
#if defined(CONFIG_BT_USER_PHY_UPDATE)
struct bt_conn_le_phy_info phy;
#endif
#if defined(CONFIG_BT_USER_DATA_LEN_UPDATE)
struct bt_conn_le_data_len_info data_len;
#endif
};
#if defined(CONFIG_BT_BREDR)
/* For now reserve space for 2 pages of LMP remote features */
#define LMP_MAX_PAGES 2
struct bt_conn_br {
bt_addr_t dst;
uint8_t remote_io_capa;
uint8_t remote_auth;
uint8_t pairing_method;
/* remote LMP features pages per 8 bytes each */
uint8_t features[LMP_MAX_PAGES][8];
struct bt_keys_link_key *link_key;
};
struct bt_conn_sco {
/* Reference to ACL Connection */
struct bt_conn *acl;
uint16_t pkt_type;
};
#endif
typedef void (*bt_conn_tx_cb_t)(struct bt_conn *conn, void *user_data);
struct bt_conn_tx {
sys_snode_t node;
bt_conn_tx_cb_t cb;
void *user_data;
/* Number of pending packets without a callback after this one */
uint32_t pending_no_cb;
};
struct bt_conn {
uint16_t handle;
uint8_t type;
uint8_t role;
ATOMIC_DEFINE(flags, BT_CONN_NUM_FLAGS);
/* Which local identity address this connection uses */
uint8_t id;
#if defined(CONFIG_BT_SMP) || defined(CONFIG_BT_BREDR)
bt_security_t sec_level;
bt_security_t required_sec_level;
uint8_t encrypt;
#endif /* CONFIG_BT_SMP || CONFIG_BT_BREDR */
/* Connection error or reason for disconnect */
uint8_t err;
bt_conn_state_t state;
uint16_t rx_len;
struct net_buf *rx;
/* Sent but not acknowledged TX packets with a callback */
sys_slist_t tx_pending;
/* Sent but not acknowledged TX packets without a callback before
* the next packet (if any) in tx_pending.
*/
uint32_t pending_no_cb;
/* Completed TX for which we need to call the callback */
sys_slist_t tx_complete;
struct k_work tx_complete_work;
/* Queue for outgoing ACL data */
struct k_fifo tx_queue;
/* Active L2CAP channels */
sys_slist_t channels;
atomic_t ref;
/* Delayed work for connection update and other deferred tasks */
struct k_delayed_work update_work;
union {
struct bt_conn_le le;
#if defined(CONFIG_BT_BREDR)
struct bt_conn_br br;
struct bt_conn_sco sco;
#endif
};
#if defined(CONFIG_BT_REMOTE_VERSION)
struct bt_conn_rv {
uint8_t version;
uint16_t manufacturer;
uint16_t subversion;
} rv;
#endif
};
/* Process incoming data for a connection */
void bt_conn_recv(struct bt_conn *conn, struct net_buf *buf, uint8_t flags);
/* Send data over a connection */
int bt_conn_send_cb(struct bt_conn *conn, struct net_buf *buf,
bt_conn_tx_cb_t cb, void *user_data);
static inline int bt_conn_send(struct bt_conn *conn, struct net_buf *buf)
{
return bt_conn_send_cb(conn, buf, NULL, NULL);
}
/* Check if a connection object with the peer already exists */
bool bt_conn_exists_le(uint8_t id, const bt_addr_le_t *peer);
/* Add a new LE connection */
struct bt_conn *bt_conn_add_le(uint8_t id, const bt_addr_le_t *peer);
/* Add a new BR/EDR connection */
struct bt_conn *bt_conn_add_br(const bt_addr_t *peer);
/* Add a new SCO connection */
struct bt_conn *bt_conn_add_sco(const bt_addr_t *peer, int link_type);
/* Cleanup SCO references */
void bt_sco_cleanup(struct bt_conn *sco_conn);
/* Look up an existing sco connection by BT address */
struct bt_conn *bt_conn_lookup_addr_sco(const bt_addr_t *peer);
/* Look up an existing connection by BT address */
struct bt_conn *bt_conn_lookup_addr_br(const bt_addr_t *peer);
void bt_conn_pin_code_req(struct bt_conn *conn);
uint8_t bt_conn_get_io_capa(void);
uint8_t bt_conn_ssp_get_auth(const struct bt_conn *conn);
void bt_conn_ssp_auth(struct bt_conn *conn, uint32_t passkey);
void bt_conn_ssp_auth_complete(struct bt_conn *conn, uint8_t status);
void bt_conn_disconnect_all(uint8_t id);
/* Look up an existing connection */
struct bt_conn *bt_conn_lookup_handle(uint16_t handle);
Bluetooth: Fix host RX thread deadlock Fix host RX thread being deadlocked. The deadlock occurs because the RX thread is stuck waiting in conn_tx_alloc with K_FOREVER but if the connection is disconnected only the RX thread can unblock it in the handling of the disconnect event. This commit fixes this deadlock by splitting the processing of the disconnected event into two parts. The part needed to unblock the RX is to release resources held by unack'ed TX packets and mark the connection state as not connected anymore. The RX thread waiting for free_tx fifo and the TX thread waiting for the bt_dev.le.pkts semaphore will both check the connected state after having acquired them and will abort if disconnected. The rest of the processing will be handled at normal RX thread priority like normal. Move the bt_recv_prio handling to the Bluetooth host when the host has defined its own RX thread (CONFIG_BT_RECV_IS_RX_THREAD=n). If the HCI driver has the RX thread (CONFIG_BT_RECV_IS_RX_THREAD=y), then the responsibility to call bt_recv and bt_recv_prio correctly falls to the HCI driver. The helper function bt_hci_evt_is_prio() is replaced with bt_hci_evt_get_flags() so that the HCI driver can do this correctly. This decision to replace was made so that existing HCI drivers maintained out-of-tree will fail at compile time with the new system. Signed-off-by: Joakim Andersson <joakim.andersson@nordicsemi.no> Signed-off-by: Carles Cufi <carles.cufi@nordicsemi.no> Bluetooth: host: Move bt_recv_prio to host when RX thread is defined Signed-off-by: Joakim Andersson <joakim.andersson@nordicsemi.no>
2020-06-03 14:48:04 +02:00
static inline bool bt_conn_is_handle_valid(struct bt_conn *conn)
{
return conn->state == BT_CONN_CONNECTED ||
conn->state == BT_CONN_DISCONNECT ||
conn->state == BT_CONN_DISCONNECT_COMPLETE;
}
/* Check if the connection is with the given peer. */
bool bt_conn_is_peer_addr_le(const struct bt_conn *conn, uint8_t id,
const bt_addr_le_t *peer);
/* Helpers for identifying & looking up connections based on the the index to
* the connection list. This is useful for O(1) lookups, but can't be used
* e.g. as the handle since that's assigned to us by the controller.
*/
#define BT_CONN_INDEX_INVALID 0xff
struct bt_conn *bt_conn_lookup_index(uint8_t index);
/* Look up a connection state. For BT_ADDR_LE_ANY, returns the first connection
* with the specific state
*/
struct bt_conn *bt_conn_lookup_state_le(uint8_t id, const bt_addr_le_t *peer,
const bt_conn_state_t state);
/* Set connection object in certain state and perform action related to state */
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);
void notify_le_data_len_updated(struct bt_conn *conn);
void notify_le_phy_updated(struct bt_conn *conn);
bool le_param_req(struct bt_conn *conn, struct bt_le_conn_param *param);
#if defined(CONFIG_BT_SMP)
/* rand and ediv should be in BT order */
int bt_conn_le_start_encryption(struct bt_conn *conn, uint8_t rand[8],
uint8_t ediv[2], const uint8_t *ltk, size_t len);
/* Notify higher layers that RPA was resolved */
void bt_conn_identity_resolved(struct bt_conn *conn);
#endif /* CONFIG_BT_SMP */
#if defined(CONFIG_BT_SMP) || defined(CONFIG_BT_BREDR)
/* Notify higher layers that connection security changed */
void bt_conn_security_changed(struct bt_conn *conn, enum bt_security_err err);
#endif /* CONFIG_BT_SMP || CONFIG_BT_BREDR */
/* Prepare a PDU to be sent over a connection */
#if defined(CONFIG_NET_BUF_LOG)
struct net_buf *bt_conn_create_pdu_timeout_debug(struct net_buf_pool *pool,
size_t reserve,
k_timeout_t timeout,
const char *func, int line);
#define bt_conn_create_pdu_timeout(_pool, _reserve, _timeout) \
bt_conn_create_pdu_timeout_debug(_pool, _reserve, _timeout, \
__func__, __LINE__)
#define bt_conn_create_pdu(_pool, _reserve) \
bt_conn_create_pdu_timeout_debug(_pool, _reserve, K_FOREVER, \
__func__, __line__)
#else
struct net_buf *bt_conn_create_pdu_timeout(struct net_buf_pool *pool,
size_t reserve, k_timeout_t timeout);
#define bt_conn_create_pdu(_pool, _reserve) \
bt_conn_create_pdu_timeout(_pool, _reserve, K_FOREVER)
#endif
/* Prepare a PDU to be sent over a connection */
#if defined(CONFIG_NET_BUF_LOG)
struct net_buf *bt_conn_create_frag_timeout_debug(size_t reserve,
k_timeout_t timeout,
const char *func, int line);
#define bt_conn_create_frag_timeout(_reserve, _timeout) \
bt_conn_create_frag_timeout_debug(_reserve, _timeout, \
__func__, __LINE__)
#define bt_conn_create_frag(_reserve) \
bt_conn_create_frag_timeout_debug(_reserve, K_FOREVER, \
__func__, __LINE__)
#else
struct net_buf *bt_conn_create_frag_timeout(size_t reserve,
k_timeout_t timeout);
#define bt_conn_create_frag(_reserve) \
bt_conn_create_frag_timeout(_reserve, K_FOREVER)
#endif
/* Initialize connection management */
int bt_conn_init(void);
/* Selects based on connecton type right semaphore for ACL packets */
struct k_sem *bt_conn_get_pkts(struct bt_conn *conn);
/* k_poll related helpers for the TX thread */
int bt_conn_prepare_events(struct k_poll_event events[]);
void bt_conn_process_tx(struct bt_conn *conn);