Bluetooth: Add support for outgoing BR/EDR connections

This allows to create outgoing BR/EDR connection and cancel pending
connection before it succeed.

Change-Id: I5c08bb2e89f79c09fa7930f860d6080d902186a1
Signed-off-by: Szymon Janc <ext.szymon.janc@tieto.com>
This commit is contained in:
Szymon Janc 2016-03-14 10:20:04 +01:00 committed by Gerrit Code Review
commit 8d154104b6
2 changed files with 124 additions and 0 deletions

View file

@ -379,6 +379,41 @@ int bt_conn_auth_pincode_entry(struct bt_conn *conn, const char *pin);
#endif /* CONFIG_BLUETOOTH_BREDR */ #endif /* CONFIG_BLUETOOTH_BREDR */
#endif /* CONFIG_BLUETOOTH_SMP || CONFIG_BLUETOOTH_BREDR */ #endif /* CONFIG_BLUETOOTH_SMP || CONFIG_BLUETOOTH_BREDR */
#if defined(CONFIG_BLUETOOTH_BREDR)
/** Connection parameters for BR/EDR connections */
struct bt_br_conn_param {
bool allow_role_switch;
};
/** Helper to declare BR/EDR connection parameters inline
*
* @param role_switch True if role switch is allowed
*/
#define BT_BR_CONN_PARAM(role_switch) \
(&(struct bt_br_conn_param) { \
.allow_role_switch = (role_switch), \
})
/** Default BR/EDR connection parameters:
* Role switch allowed
*/
#define BT_BR_CONN_PARAM_DEFAULT BT_BR_CONN_PARAM(true)
/** @brief Initiate an BR/EDR connection to a remote device.
*
* Allows initiate new BR/EDR link to remote peer using its address.
* Returns a new reference that the the caller is responsible for managing.
*
* @param peer Remote address.
* @param param Initial connection parameters.
*
* @return Valid connection object on success or NULL otherwise.
*/
struct bt_conn *bt_conn_create_br(const bt_addr_t *peer,
const struct bt_br_conn_param *param);
#endif /* CONFIG_BLUETOOTH_BREDR */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View file

@ -578,6 +578,58 @@ struct bt_conn *bt_conn_add_le(const bt_addr_le_t *peer)
} }
#if defined(CONFIG_BLUETOOTH_BREDR) #if defined(CONFIG_BLUETOOTH_BREDR)
struct bt_conn *bt_conn_create_br(const bt_addr_t *peer,
const struct bt_br_conn_param *param)
{
struct bt_hci_cp_connect *cp;
struct bt_conn *conn;
struct net_buf *buf;
conn = bt_conn_lookup_addr_br(peer);
if (conn) {
switch (conn->state) {
return conn;
case BT_CONN_CONNECT:
case BT_CONN_CONNECTED:
return conn;
default:
bt_conn_unref(conn);
return NULL;
}
}
conn = bt_conn_add_br(peer);
if (!conn) {
return NULL;
}
buf = bt_hci_cmd_create(BT_HCI_OP_CONNECT, sizeof(*cp));
if (!buf) {
bt_conn_unref(conn);
return NULL;
}
cp = net_buf_add(buf, sizeof(*cp));
memset(cp, 0, sizeof(*cp));
memcpy(&cp->bdaddr, peer, sizeof(cp->bdaddr));
cp->packet_type = sys_cpu_to_le16(0xcc18); /* DM1 DH1 DM3 DH5 DM5 DH5 */
cp->pscan_rep_mode = 0x02; /* R2 */
cp->allow_role_switch = param->allow_role_switch ? 0x01 : 0x00;
cp->clock_offset = 0x0000; /* TODO used cached clock offset */
if (bt_hci_cmd_send_sync(BT_HCI_OP_CONNECT, buf, NULL) < 0) {
bt_conn_unref(conn);
return NULL;
}
bt_conn_set_state(conn, BT_CONN_CONNECT);
conn->role = BT_CONN_ROLE_MASTER;
return conn;
}
struct bt_conn *bt_conn_lookup_addr_br(const bt_addr_t *peer) struct bt_conn *bt_conn_lookup_addr_br(const bt_addr_t *peer)
{ {
int i; int i;
@ -978,6 +1030,37 @@ static int bt_hci_connect_le_cancel(struct bt_conn *conn)
return 0; return 0;
} }
#if defined(CONFIG_BLUETOOTH_BREDR)
static int bt_hci_connect_br_cancel(struct bt_conn *conn)
{
struct bt_hci_cp_connect_cancel *cp;
struct bt_hci_rp_connect_cancel *rp;
struct net_buf *buf, *rsp;
int err;
buf = bt_hci_cmd_create(BT_HCI_OP_CONNECT_CANCEL, sizeof(*cp));
if (!buf) {
return -ENOBUFS;
}
cp = net_buf_add(buf, sizeof(*cp));
memcpy(&cp->bdaddr, &conn->br.dst, sizeof(cp->bdaddr));
err = bt_hci_cmd_send_sync(BT_HCI_OP_CONNECT_CANCEL, buf, &rsp);
if (err) {
return err;
}
rp = (void *)rsp->data;
err = rp->status ? -EIO : 0;
net_buf_unref(rsp);
return err;
}
#endif
int bt_conn_le_param_update(struct bt_conn *conn, int bt_conn_le_param_update(struct bt_conn *conn,
const struct bt_le_conn_param *param) const struct bt_le_conn_param *param)
{ {
@ -1003,6 +1086,12 @@ int bt_conn_disconnect(struct bt_conn *conn, uint8_t reason)
bt_le_scan_update(false); bt_le_scan_update(false);
return 0; return 0;
case BT_CONN_CONNECT: case BT_CONN_CONNECT:
#if defined(CONFIG_BLUETOOTH_BREDR)
if (conn->type == BT_CONN_TYPE_BR) {
return bt_hci_connect_br_cancel(conn);
}
#endif /* CONFIG_BLUETOOTH_BREDR */
return bt_hci_connect_le_cancel(conn); return bt_hci_connect_le_cancel(conn);
case BT_CONN_CONNECTED: case BT_CONN_CONNECTED:
return bt_hci_disconnect(conn, reason); return bt_hci_disconnect(conn, reason);