diff --git a/include/bluetooth/conn.h b/include/bluetooth/conn.h index 44ed746cd74..2aa0623c8a8 100644 --- a/include/bluetooth/conn.h +++ b/include/bluetooth/conn.h @@ -105,6 +105,8 @@ enum { BT_CONN_TYPE_LE, /** BR/EDR Connection Type */ BT_CONN_TYPE_BR, + /** SCO Connection Type */ + BT_CONN_TYPE_SCO, }; /** LE Connection Info Structure */ diff --git a/include/bluetooth/hci.h b/include/bluetooth/hci.h index d80faccb8da..5f99f8561dd 100644 --- a/include/bluetooth/hci.h +++ b/include/bluetooth/hci.h @@ -251,6 +251,18 @@ struct bt_hci_cmd_hdr { #define HCI_PKT_TYPE_ESCO_2EV5 0x0100 #define HCI_PKT_TYPE_ESCO_3EV5 0x0200 + +#define ESCO_PKT_MASK (HCI_PKT_TYPE_ESCO_HV1 | \ + HCI_PKT_TYPE_ESCO_HV2 | \ + HCI_PKT_TYPE_ESCO_HV3) +#define SCO_PKT_MASK (HCI_PKT_TYPE_HV1 | \ + HCI_PKT_TYPE_HV2 | \ + HCI_PKT_TYPE_HV3) +#define EDR_ESCO_PKT_MASK (HCI_PKT_TYPE_ESCO_2EV3 | \ + HCI_PKT_TYPE_ESCO_3EV3 | \ + HCI_PKT_TYPE_ESCO_2EV5 | \ + HCI_PKT_TYPE_ESCO_3EV5) + /* HCI BR/EDR link types */ #define BT_HCI_SCO 0x00 #define BT_HCI_ACL 0x01 @@ -312,6 +324,17 @@ struct bt_hci_cp_accept_conn_req { uint8_t role; } __packed; +#define BT_HCI_OP_ACCEPT_SYNC_CONN_REQ BT_OP(BT_OGF_LINK_CTRL, 0x0029) +struct bt_hci_cp_accept_sync_conn_req { + bt_addr_t bdaddr; + uint32_t tx_bandwidth; + uint32_t rx_bandwidth; + uint16_t max_latency; + uint16_t content_format; + uint8_t retrans_effort; + uint16_t pkt_type; +} __packed; + #define BT_HCI_OP_REJECT_CONN_REQ BT_OP(BT_OGF_LINK_CTRL, 0x000a) struct bt_hci_cp_reject_conn_req { bt_addr_t bdaddr; diff --git a/subsys/bluetooth/host/Kconfig b/subsys/bluetooth/host/Kconfig index 6bcb59f7881..8cdb4e3eeb3 100644 --- a/subsys/bluetooth/host/Kconfig +++ b/subsys/bluetooth/host/Kconfig @@ -260,6 +260,15 @@ config BLUETOOTH_TINYCRYPT_ECC option injects support for the 2 HCI commands required for LE Secure Connections so that Hosts can make use of those. +config BLUETOOTH_MAX_SCO_CONN + int "Maximum number of simultaneous SCO connections" + depends on BLUETOOTH_CONN || BLUETOOTH_CONTROLLER + default 1 + range 1 3 + help + Maximum number of simultaneous Bluetooth synchronous connections + supported. The minimum (and default) number is 1. + config BLUETOOTH_MAX_CONN int "Maximum number of simultaneous connections" depends on BLUETOOTH_CONN || BLUETOOTH_CONTROLLER diff --git a/subsys/bluetooth/host/conn.c b/subsys/bluetooth/host/conn.c index ae7c993cdad..62c746068dd 100644 --- a/subsys/bluetooth/host/conn.c +++ b/subsys/bluetooth/host/conn.c @@ -44,8 +44,9 @@ const struct bt_conn_auth_cb *bt_auth; static struct bt_conn conns[CONFIG_BLUETOOTH_MAX_CONN]; static struct bt_conn_cb *callback_list; - #if defined(CONFIG_BLUETOOTH_BREDR) +static struct bt_conn sco_conns[CONFIG_BLUETOOTH_MAX_SCO_CONN]; + enum pairing_method { LEGACY, /* Legacy (pre-SSP) pairing */ JUST_WORKS, /* JustWorks pairing */ @@ -190,6 +191,29 @@ static struct bt_conn *conn_new(void) } #if defined(CONFIG_BLUETOOTH_BREDR) +static struct bt_conn *sco_conn_new(void) +{ + struct bt_conn *sco_conn = NULL; + int i; + + for (i = 0; i < ARRAY_SIZE(sco_conns); i++) { + if (!atomic_get(&sco_conns[i].ref)) { + sco_conn = &sco_conns[i]; + break; + } + } + + if (!sco_conn) { + return NULL; + } + + memset(sco_conn, 0, sizeof(*sco_conn)); + + atomic_set(&sco_conn->ref, 1); + + return sco_conn; +} + struct bt_conn *bt_conn_create_br(const bt_addr_t *peer, const struct bt_br_conn_param *param) { @@ -263,6 +287,33 @@ struct bt_conn *bt_conn_lookup_addr_br(const bt_addr_t *peer) return NULL; } +struct bt_conn *bt_conn_add_sco(const bt_addr_t *peer, int link_type) +{ + struct bt_conn *sco_conn = sco_conn_new(); + + if (!sco_conn) { + return NULL; + } + + sco_conn->sco.conn = bt_conn_lookup_addr_br(peer); + sco_conn->type = BT_CONN_TYPE_SCO; + + if (link_type == BT_HCI_SCO) { + if (BT_FEAT_LMP_ESCO_CAPABLE(bt_dev.features)) { + sco_conn->sco.pkt_type = (bt_dev.esco.pkt_type & + ESCO_PKT_MASK); + } else { + sco_conn->sco.pkt_type = (bt_dev.esco.pkt_type & + SCO_PKT_MASK); + } + } else if (link_type == BT_HCI_ESCO) { + sco_conn->sco.pkt_type = (bt_dev.esco.pkt_type & + ~EDR_ESCO_PKT_MASK); + } + + return sco_conn; +} + struct bt_conn *bt_conn_add_br(const bt_addr_t *peer) { struct bt_conn *conn = conn_new(); diff --git a/subsys/bluetooth/host/conn_internal.h b/subsys/bluetooth/host/conn_internal.h index aec5925e423..74fccddc736 100644 --- a/subsys/bluetooth/host/conn_internal.h +++ b/subsys/bluetooth/host/conn_internal.h @@ -64,6 +64,12 @@ struct bt_conn_br { struct bt_keys_link_key *link_key; }; + +struct bt_conn_sco { + /* Reference to ACL Connection */ + struct bt_conn *conn; + uint16_t pkt_type; +}; #endif struct bt_conn { @@ -101,6 +107,7 @@ struct bt_conn { struct bt_conn_le le; #if defined(CONFIG_BLUETOOTH_BREDR) struct bt_conn_br br; + struct bt_conn_sco sco; #endif }; }; @@ -117,6 +124,9 @@ struct bt_conn *bt_conn_add_le(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); + /* Look up an existing connection by BT address */ struct bt_conn *bt_conn_lookup_addr_br(const bt_addr_t *peer); diff --git a/subsys/bluetooth/host/hci_core.c b/subsys/bluetooth/host/hci_core.c index 2ed0c9cb562..c3c4ef669a0 100644 --- a/subsys/bluetooth/host/hci_core.c +++ b/subsys/bluetooth/host/hci_core.c @@ -992,6 +992,34 @@ static int reject_conn(const bt_addr_t *bdaddr, uint8_t reason) return 0; } +static int accept_sco_conn(const bt_addr_t *bdaddr, struct bt_conn *sco_conn) +{ + struct bt_hci_cp_accept_sync_conn_req *cp; + struct net_buf *buf; + int err; + + buf = bt_hci_cmd_create(BT_HCI_OP_ACCEPT_SYNC_CONN_REQ, sizeof(*cp)); + if (!buf) { + return -ENOBUFS; + } + + cp = net_buf_add(buf, sizeof(*cp)); + bt_addr_copy(&cp->bdaddr, bdaddr); + cp->pkt_type = sco_conn->sco.pkt_type; + cp->tx_bandwidth = 0x00001f40; + cp->rx_bandwidth = 0x00001f40; + cp->max_latency = 0x0007; + cp->retrans_effort = 0x01; + cp->content_format = BT_VOICE_CVSD_16BIT; + + err = bt_hci_cmd_send_sync(BT_HCI_OP_ACCEPT_SYNC_CONN_REQ, buf, NULL); + if (err) { + return err; + } + + return 0; +} + static int accept_conn(const bt_addr_t *bdaddr) { struct bt_hci_cp_accept_conn_req *cp; @@ -1015,6 +1043,22 @@ static int accept_conn(const bt_addr_t *bdaddr) return 0; } +static void bt_esco_conn_req(struct bt_hci_evt_conn_request *evt) +{ + struct bt_conn *sco_conn; + + sco_conn = bt_conn_add_sco(&evt->bdaddr, evt->link_type); + if (!sco_conn) { + reject_conn(&evt->bdaddr, BT_HCI_ERR_INSUFFICIENT_RESOURCES); + return; + } + + accept_sco_conn(&evt->bdaddr, sco_conn); + sco_conn->role = BT_HCI_ROLE_SLAVE; + bt_conn_set_state(sco_conn, BT_CONN_CONNECT); + bt_conn_unref(sco_conn); +} + static void conn_req(struct net_buf *buf) { struct bt_hci_evt_conn_request *evt = (void *)buf->data; @@ -1023,9 +1067,8 @@ static void conn_req(struct net_buf *buf) BT_DBG("conn req from %s, type 0x%02x", bt_addr_str(&evt->bdaddr), evt->link_type); - /* Reject SCO connections until we have support for them */ if (evt->link_type != BT_HCI_ACL) { - reject_conn(&evt->bdaddr, BT_HCI_ERR_INSUFFICIENT_RESOURCES); + bt_esco_conn_req(evt); return; } @@ -3307,6 +3350,7 @@ static int set_event_mask(void) ev->events[2] |= 0x80; /* Link Key Notif */ ev->events[4] |= 0x02; /* Inquiry Result With RSSI */ ev->events[4] |= 0x04; /* Remote Extended Features Complete */ + ev->events[5] |= 0x08; /* Synchronous Conn Complete Event */ ev->events[5] |= 0x40; /* Extended Inquiry Result */ ev->events[6] |= 0x01; /* IO Capability Request */ ev->events[6] |= 0x02; /* IO Capability Response */ diff --git a/subsys/bluetooth/host/hci_core.h b/subsys/bluetooth/host/hci_core.h index afe4e400fcf..1c329de9a0a 100644 --- a/subsys/bluetooth/host/hci_core.h +++ b/subsys/bluetooth/host/hci_core.h @@ -16,6 +16,9 @@ #define LMP_FEAT_PAGES_COUNT 1 #endif +/* SCO settings */ +#define BT_VOICE_CVSD_16BIT 0x0060 + /* k_poll event tags */ enum { BT_EVENT_CMD_TX,