Bluetooth: HFP HF: SCO: Accept eSCO conn request

1. Accept the incoming Synchronous connection request and establish
a new sco connection object.
2. Enable sco conn complete in event_mask

> HCI Event: Connect Request (0x04) plen 10           [hci0] 126.198264
        Address: 48:9D:24:1F:4D:1D (BlackBerry RTS)
        Class: 0x7a020c
          Major class: Phone (cellular, cordless, payphone, modem)
          Minor class: Smart phone
          Networking (LAN, Ad hoc)
          Capturing (Scanner, Microphone)
          Object Transfer (v-Inbox, v-Folder)
          Audio (Speaker, Microphone, Headset)
          Telephony (Cordless telephony, Modem, Headset)
        Link type: eSCO (0x02)
< HCI Command: Accept Synchronous Co.. (0x01|0x0029) plen 21
        Address: 48:9D:24:1F:4D:1D (BlackBerry RTS)
        Transmit bandwidth: 8000
        Receive bandwidth: 8000
        Max latency: 7
        Setting: 0x0060
          Input Coding: Linear
          Input Data Format: 2's complement
          Input Sample Size: 16-bit
          # of bits padding at MSB: 0
          Air Coding Format: CVSD
        Retransmission effort: Optimize for power consumption (0x01)
        Packet type: 0x0006
          HV2 may be used
          HV3 may be used
> HCI Event: Command Status (0x0f) plen 4           [hci0] 126.205171
      Accept Synchronous Connection Request (0x01|0x0029) ncmd 1
        Status: Success (0x00)

Change-Id: I71597aef94e945a9c07be1960994ad20c1b44bb3
Signed-off-by: Sathish Narasimman <sathish.narasimman@intel.com>
This commit is contained in:
Sathish Narasimman 2017-02-15 14:29:11 +05:30 committed by Johan Hedberg
commit e51a19fdc2
7 changed files with 145 additions and 3 deletions

View file

@ -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 */

View file

@ -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;

View file

@ -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

View file

@ -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();

View file

@ -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);

View file

@ -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 */

View file

@ -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,