Skip to content

Commit

Permalink
Bluetooth: Use extended LE Connection if supported
Browse files Browse the repository at this point in the history
This implements extended LE craete connection and enhanced
LE conn complete event if the controller supports.

For now it is as good as legacy LE connection and event as
no new features in the extended connection is handled.

< HCI Command: LE Extended Create Connection (0x08|0x0043) plen 26
        Filter policy: White list is not used (0x00)
        Own address type: Public (0x00)
        Peer address type: Random (0x01)
        Peer address: DB:7E:2E:1D:85:E8 (Static)
        Initiating PHYs: 0x01
        Entry 0: LE 1M
          Scan interval: 60.000 msec (0x0060)
          Scan window: 60.000 msec (0x0060)
          Min connection interval: 50.00 msec (0x0028)
          Max connection interval: 70.00 msec (0x0038)
          Connection latency: 0 (0x0000)
          Supervision timeout: 420 msec (0x002a)
          Min connection length: 0.000 msec (0x0000)
          Max connection length: 0.000 msec (0x0000)
> HCI Event: Command Status (0x0f) plen 4
      LE Extended Create Connection (0x08|0x0043) ncmd 2
        Status: Success (0x00)
> HCI Event: LE Meta Event (0x3e) plen 31
      LE Enhanced Connection Complete (0x0a)
        Status: Success (0x00)
        Handle: 3585
        Role: Master (0x00)
        Peer address type: Random (0x01)
        Peer address: DB:7E:2E:1D:85:E8 (Static)
        Local resolvable private address: 00:00:00:00:00:00 (Non-Resolvable)
        Peer resolvable private address: 00:00:00:00:00:00 (Non-Resolvable)
        Connection interval: 67.50 msec (0x0036)
        Connection latency: 0 (0x0000)
        Supervision timeout: 420 msec (0x002a)
        Master clock accuracy: 0x00
@ MGMT Event: Device Connected (0x000b) plen 40
        LE Address: DB:7E:2E:1D:85:E8 (Static)
        Flags: 0x00000000
        Data length: 27
        Name (complete): Designer Mouse
        Appearance: Mouse (0x03c2)
        Flags: 0x05
          LE Limited Discoverable Mode
          BR/EDR Not Supported
        16-bit Service UUIDs (complete): 1 entry
          Human Interface Device (0x1812)

Signed-off-by: Jaganath Kanakkassery <jaganathx.kanakkassery@intel.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
  • Loading branch information
jaganathkr authored and holtmann committed Jul 6, 2018
1 parent d12fb05 commit 4d94f95
Show file tree
Hide file tree
Showing 5 changed files with 147 additions and 18 deletions.
36 changes: 36 additions & 0 deletions include/net/bluetooth/hci.h
Original file line number Diff line number Diff line change
Expand Up @@ -1538,6 +1538,27 @@ struct hci_cp_le_set_ext_scan_enable {
__le16 period;
} __packed;

#define HCI_OP_LE_EXT_CREATE_CONN 0x2043
struct hci_cp_le_ext_create_conn {
__u8 filter_policy;
__u8 own_addr_type;
__u8 peer_addr_type;
bdaddr_t peer_addr;
__u8 phys;
__u8 data[0];
} __packed;

struct hci_cp_le_ext_conn_param {
__le16 scan_interval;
__le16 scan_window;
__le16 conn_interval_min;
__le16 conn_interval_max;
__le16 conn_latency;
__le16 supervision_timeout;
__le16 min_ce_len;
__le16 max_ce_len;
} __packed;

/* ---- HCI Events ---- */
#define HCI_EV_INQUIRY_COMPLETE 0x01

Expand Down Expand Up @@ -2015,6 +2036,21 @@ struct hci_ev_le_ext_adv_report {
__u8 data[0];
} __packed;

#define HCI_EV_LE_ENHANCED_CONN_COMPLETE 0x0a
struct hci_ev_le_enh_conn_complete {
__u8 status;
__le16 handle;
__u8 role;
__u8 bdaddr_type;
bdaddr_t bdaddr;
bdaddr_t local_rpa;
bdaddr_t peer_rpa;
__le16 interval;
__le16 latency;
__le16 supervision_timeout;
__u8 clk_accurancy;
} __packed;

/* Internal events generated by Bluetooth stack */
#define HCI_EV_STACK_INTERNAL 0xfd
struct hci_ev_stack_internal {
Expand Down
2 changes: 2 additions & 0 deletions include/net/bluetooth/hci_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -1161,6 +1161,8 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
/* Use ext scanning if set ext scan param and ext scan enable is supported */
#define use_ext_scan(dev) (((dev)->commands[37] & 0x20) && \
((dev)->commands[37] & 0x40))
/* Use ext create connection if command is supported */
#define use_ext_conn(dev) ((dev)->commands[37] & 0x80)

/* ----- HCI protocols ----- */
#define HCI_PROTO_DEFER 0x01
Expand Down
72 changes: 54 additions & 18 deletions net/bluetooth/hci_conn.c
Original file line number Diff line number Diff line change
Expand Up @@ -752,7 +752,6 @@ static void hci_req_add_le_create_conn(struct hci_request *req,
struct hci_conn *conn,
bdaddr_t *direct_rpa)
{
struct hci_cp_le_create_conn cp;
struct hci_dev *hdev = conn->hdev;
u8 own_addr_type;

Expand All @@ -775,25 +774,62 @@ static void hci_req_add_le_create_conn(struct hci_request *req,
return;
}

memset(&cp, 0, sizeof(cp));
if (use_ext_conn(hdev)) {
struct hci_cp_le_ext_create_conn *cp;
struct hci_cp_le_ext_conn_param *p;
/* As of now only LE 1M is supported */
u8 data[sizeof(*cp) + sizeof(*p) * 1];

/* Set window to be the same value as the interval to enable
* continuous scanning.
*/
cp.scan_interval = cpu_to_le16(hdev->le_scan_interval);
cp.scan_window = cp.scan_interval;
cp = (void *) data;
p = (void *) cp->data;

bacpy(&cp.peer_addr, &conn->dst);
cp.peer_addr_type = conn->dst_type;
cp.own_address_type = own_addr_type;
cp.conn_interval_min = cpu_to_le16(conn->le_conn_min_interval);
cp.conn_interval_max = cpu_to_le16(conn->le_conn_max_interval);
cp.conn_latency = cpu_to_le16(conn->le_conn_latency);
cp.supervision_timeout = cpu_to_le16(conn->le_supv_timeout);
cp.min_ce_len = cpu_to_le16(0x0000);
cp.max_ce_len = cpu_to_le16(0x0000);

hci_req_add(req, HCI_OP_LE_CREATE_CONN, sizeof(cp), &cp);
memset(cp, 0, sizeof(*cp));

bacpy(&cp->peer_addr, &conn->dst);
cp->peer_addr_type = conn->dst_type;
cp->own_addr_type = own_addr_type;
cp->phys = LE_SCAN_PHY_1M;

memset(p, 0, sizeof(*p));

/* Set window to be the same value as the interval to enable
* continuous scanning.
*/

p->scan_interval = cpu_to_le16(hdev->le_scan_interval);
p->scan_window = p->scan_interval;
p->conn_interval_min = cpu_to_le16(conn->le_conn_min_interval);
p->conn_interval_max = cpu_to_le16(conn->le_conn_max_interval);
p->conn_latency = cpu_to_le16(conn->le_conn_latency);
p->supervision_timeout = cpu_to_le16(conn->le_supv_timeout);
p->min_ce_len = cpu_to_le16(0x0000);
p->max_ce_len = cpu_to_le16(0x0000);

hci_req_add(req, HCI_OP_LE_EXT_CREATE_CONN, sizeof(data), data);

} else {
struct hci_cp_le_create_conn cp;

memset(&cp, 0, sizeof(cp));

/* Set window to be the same value as the interval to enable
* continuous scanning.
*/
cp.scan_interval = cpu_to_le16(hdev->le_scan_interval);
cp.scan_window = cp.scan_interval;

bacpy(&cp.peer_addr, &conn->dst);
cp.peer_addr_type = conn->dst_type;
cp.own_address_type = own_addr_type;
cp.conn_interval_min = cpu_to_le16(conn->le_conn_min_interval);
cp.conn_interval_max = cpu_to_le16(conn->le_conn_max_interval);
cp.conn_latency = cpu_to_le16(conn->le_conn_latency);
cp.supervision_timeout = cpu_to_le16(conn->le_supv_timeout);
cp.min_ce_len = cpu_to_le16(0x0000);
cp.max_ce_len = cpu_to_le16(0x0000);

hci_req_add(req, HCI_OP_LE_CREATE_CONN, sizeof(cp), &cp);
}

conn->state = BT_CONNECT;
clear_bit(HCI_CONN_SCANNING, &conn->flags);
Expand Down
8 changes: 8 additions & 0 deletions net/bluetooth/hci_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -704,6 +704,14 @@ static int hci_init3_req(struct hci_request *req, unsigned long opt)
* Report
*/

/* If the controller supports the LE Extended Create Connection
* command, enable the corresponding event.
*/
if (use_ext_conn(hdev))
events[1] |= 0x02; /* LE Enhanced Connection
* Complete
*/

hci_req_add(req, HCI_OP_LE_SET_EVENT_MASK, sizeof(events),
events);

Expand Down
47 changes: 47 additions & 0 deletions net/bluetooth/hci_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -2031,6 +2031,31 @@ static void hci_cs_le_create_conn(struct hci_dev *hdev, u8 status)
hci_dev_unlock(hdev);
}

static void hci_cs_le_ext_create_conn(struct hci_dev *hdev, u8 status)
{
struct hci_cp_le_ext_create_conn *cp;

BT_DBG("%s status 0x%2.2x", hdev->name, status);

/* All connection failure handling is taken care of by the
* hci_le_conn_failed function which is triggered by the HCI
* request completion callbacks used for connecting.
*/
if (status)
return;

cp = hci_sent_cmd_data(hdev, HCI_OP_LE_EXT_CREATE_CONN);
if (!cp)
return;

hci_dev_lock(hdev);

cs_le_create_conn(hdev, &cp->peer_addr, cp->peer_addr_type,
cp->own_addr_type, cp->filter_policy);

hci_dev_unlock(hdev);
}

static void hci_cs_le_read_remote_features(struct hci_dev *hdev, u8 status)
{
struct hci_cp_le_read_remote_features *cp;
Expand Down Expand Up @@ -3233,6 +3258,10 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb,
hci_cs_le_start_enc(hdev, ev->status);
break;

case HCI_OP_LE_EXT_CREATE_CONN:
hci_cs_le_ext_create_conn(hdev, ev->status);
break;

default:
BT_DBG("%s opcode 0x%4.4x", hdev->name, *opcode);
break;
Expand Down Expand Up @@ -4733,6 +4762,20 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
le16_to_cpu(ev->supervision_timeout));
}

static void hci_le_enh_conn_complete_evt(struct hci_dev *hdev,
struct sk_buff *skb)
{
struct hci_ev_le_enh_conn_complete *ev = (void *) skb->data;

BT_DBG("%s status 0x%2.2x", hdev->name, ev->status);

le_conn_complete_evt(hdev, ev->status, &ev->bdaddr, ev->bdaddr_type,
ev->role, le16_to_cpu(ev->handle),
le16_to_cpu(ev->interval),
le16_to_cpu(ev->latency),
le16_to_cpu(ev->supervision_timeout));
}

static void hci_le_conn_update_complete_evt(struct hci_dev *hdev,
struct sk_buff *skb)
{
Expand Down Expand Up @@ -5352,6 +5395,10 @@ static void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_le_ext_adv_report_evt(hdev, skb);
break;

case HCI_EV_LE_ENHANCED_CONN_COMPLETE:
hci_le_enh_conn_complete_evt(hdev, skb);
break;

default:
break;
}
Expand Down

0 comments on commit 4d94f95

Please sign in to comment.