This is done so that the helpers can be used for extended conn
implementation which will be done in subsequent patch.
Signed-off-by: Jaganath Kanakkassery <[email protected]>
---
net/bluetooth/hci_event.c | 110 +++++++++++++++++++++++++++-------------------
1 file changed, 65 insertions(+), 45 deletions(-)
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 9e0cd51..de7b3c3 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1943,55 +1943,63 @@ static void hci_cs_disconnect(struct hci_dev *hdev, u8 status)
hci_dev_unlock(hdev);
}
-static void hci_cs_le_create_conn(struct hci_dev *hdev, u8 status)
+static void cs_le_create_conn(struct hci_dev *hdev, bdaddr_t *peer_addr,
+ u8 peer_addr_type, u8 own_address_type,
+ u8 filter_policy)
{
- struct hci_cp_le_create_conn *cp;
struct hci_conn *conn;
- 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_CREATE_CONN);
- if (!cp)
- return;
-
- hci_dev_lock(hdev);
-
- conn = hci_conn_hash_lookup_le(hdev, &cp->peer_addr,
- cp->peer_addr_type);
+ conn = hci_conn_hash_lookup_le(hdev, peer_addr,
+ peer_addr_type);
if (!conn)
- goto unlock;
+ return;
/* Store the initiator and responder address information which
* is needed for SMP. These values will not change during the
* lifetime of the connection.
*/
- conn->init_addr_type = cp->own_address_type;
- if (cp->own_address_type == ADDR_LE_DEV_RANDOM)
+ conn->init_addr_type = own_address_type;
+ if (own_address_type == ADDR_LE_DEV_RANDOM)
bacpy(&conn->init_addr, &hdev->random_addr);
else
bacpy(&conn->init_addr, &hdev->bdaddr);
- conn->resp_addr_type = cp->peer_addr_type;
- bacpy(&conn->resp_addr, &cp->peer_addr);
+ conn->resp_addr_type = peer_addr_type;
+ bacpy(&conn->resp_addr, peer_addr);
/* We don't want the connection attempt to stick around
* indefinitely since LE doesn't have a page timeout concept
* like BR/EDR. Set a timer for any connection that doesn't use
* the white list for connecting.
*/
- if (cp->filter_policy == HCI_LE_USE_PEER_ADDR)
+ if (filter_policy == HCI_LE_USE_PEER_ADDR)
queue_delayed_work(conn->hdev->workqueue,
&conn->le_conn_timeout,
conn->conn_timeout);
+}
+
+static void hci_cs_le_create_conn(struct hci_dev *hdev, u8 status)
+{
+ struct hci_cp_le_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_CREATE_CONN);
+ if (!cp)
+ return;
+
+ hci_dev_lock(hdev);
+
+ cs_le_create_conn(hdev, &cp->peer_addr, cp->peer_addr_type,
+ cp->own_address_type, cp->filter_policy);
-unlock:
hci_dev_unlock(hdev);
}
@@ -4514,16 +4522,15 @@ static void hci_disconn_phylink_complete_evt(struct hci_dev *hdev,
}
#endif
-static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void le_conn_complete_evt(struct hci_dev *hdev, u8 status,
+ bdaddr_t *bdaddr, u8 bdaddr_type, u8 role, u16 handle,
+ u16 interval, u16 latency, u16 supervision_timeout)
{
- struct hci_ev_le_conn_complete *ev = (void *) skb->data;
struct hci_conn_params *params;
struct hci_conn *conn;
struct smp_irk *irk;
u8 addr_type;
- BT_DBG("%s status 0x%2.2x", hdev->name, ev->status);
-
hci_dev_lock(hdev);
/* All controllers implicitly stop advertising in the event of a
@@ -4533,13 +4540,13 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
conn = hci_lookup_le_connect(hdev);
if (!conn) {
- conn = hci_conn_add(hdev, LE_LINK, &ev->bdaddr, ev->role);
+ conn = hci_conn_add(hdev, LE_LINK, bdaddr, role);
if (!conn) {
BT_ERR("No memory for new connection");
goto unlock;
}
- conn->dst_type = ev->bdaddr_type;
+ conn->dst_type = bdaddr_type;
/* If we didn't have a hci_conn object previously
* but we're in master role this must be something
@@ -4550,8 +4557,8 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
* initiator address based on the HCI_PRIVACY flag.
*/
if (conn->out) {
- conn->resp_addr_type = ev->bdaddr_type;
- bacpy(&conn->resp_addr, &ev->bdaddr);
+ conn->resp_addr_type = bdaddr_type;
+ bacpy(&conn->resp_addr, bdaddr);
if (hci_dev_test_flag(hdev, HCI_PRIVACY)) {
conn->init_addr_type = ADDR_LE_DEV_RANDOM;
bacpy(&conn->init_addr, &hdev->rpa);
@@ -4575,8 +4582,8 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
else
bacpy(&conn->resp_addr, &hdev->bdaddr);
- conn->init_addr_type = ev->bdaddr_type;
- bacpy(&conn->init_addr, &ev->bdaddr);
+ conn->init_addr_type = bdaddr_type;
+ bacpy(&conn->init_addr, bdaddr);
/* For incoming connections, set the default minimum
* and maximum connection interval. They will be used
@@ -4602,8 +4609,8 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
conn->dst_type = irk->addr_type;
}
- if (ev->status) {
- hci_le_conn_failed(conn, ev->status);
+ if (status) {
+ hci_le_conn_failed(conn, status);
goto unlock;
}
@@ -4622,17 +4629,17 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
mgmt_device_connected(hdev, conn, 0, NULL, 0);
conn->sec_level = BT_SECURITY_LOW;
- conn->handle = __le16_to_cpu(ev->handle);
+ conn->handle = handle;
conn->state = BT_CONFIG;
- conn->le_conn_interval = le16_to_cpu(ev->interval);
- conn->le_conn_latency = le16_to_cpu(ev->latency);
- conn->le_supv_timeout = le16_to_cpu(ev->supervision_timeout);
+ conn->le_conn_interval = interval;
+ conn->le_conn_latency = latency;
+ conn->le_supv_timeout = supervision_timeout;
hci_debugfs_create_conn(conn);
hci_conn_add_sysfs(conn);
- if (!ev->status) {
+ if (!status) {
/* The remote features procedure is defined for master
* role only. So only in case of an initiated connection
* request the remote features.
@@ -4654,10 +4661,10 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_conn_hold(conn);
} else {
conn->state = BT_CONNECTED;
- hci_connect_cfm(conn, ev->status);
+ hci_connect_cfm(conn, status);
}
} else {
- hci_connect_cfm(conn, ev->status);
+ hci_connect_cfm(conn, status);
}
params = hci_pend_le_action_lookup(&hdev->pend_le_conns, &conn->dst,
@@ -4676,6 +4683,19 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_dev_unlock(hdev);
}
+static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+ struct hci_ev_le_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)
{
--
2.7.4
Hi,
2017-10-23 15:00 GMT+02:00 Andrzej Kaczmarek <[email protected]>:
>> >>> Is there any point in using extended version if we can only do
>> >>> 1Mbit/s, is there any practical difference? Is there any reason we are
>> >>> not trying 2 Mbit/s phy as well?
>> >>>
>> >>
>> >> The idea is to first implement the extended version with no functionality
>> >> change (ie with PHY as 1M). We are planning to expose kernel
>> >> interface so that user can select the PHY for the connection. We can add
>> >> other PHYs accordingly during the implementation of the interfaces.
>> >
>> > There is nothing here suggesting what sort of interface we will use
>> > for switching between 1-2 MBit/s,
>>
>> I am planning to raise separate patch for the interfaces.
>>
>> > usually, for BR/EDR we choose the
>> > best possible (or let the controller do so) we will continue with the
>> > same logic the phy policy will reside in the kernel anyway. Are there
>> > any reasons why we cannot request 2MBit/s?
>>
>> My thinking was to select 1M, 2M or LR based on the user selection.
>> Whether we need 2M or LR would be based on the usecase i think.
>> But i understand your point that we can have 2M instead of 1M if both
>> controller supports. But i am not sure whether any power consumption
>> issues (i may be dumb here) will be there wherein some use cases 1M is
>> preferred over 2M (Usecases where data rate is not relevant). But otherwise
>> as you said we can add 2M also in the PHYs by default.
>
> We cannot just have 2M instead of 1M since scanning on primary
> advertising channels in only possible on 1M or LR - so 1M is perfectly
> fine here.
> The only reason to include 2M here is to specify default connection
> parameters in case connection is established on 2M (which is still
> possible) and we want them to be different than for 1M (which are used
> if 2M is not specified).
>
> IMO having 1M only is just fine until we have proper support for other
> PHYs in place.
>
2 MBit/s consumes around half the energy since it does everything in
half the time with the same radio power consumption. But I wouldn't be
surprised if the range is worse compared to 1 MBit/s.
/Emil
Hi,
(sending once more since previous one was blocked due to HTML...
thanks to gmail)
On Mon, Oct 23, 2017 at 2:35 PM, Jaganath K <[email protected]> wrote:
>
> Hi Luiz,
>
> On Mon, Oct 23, 2017 at 5:34 PM, Luiz Augusto von Dentz
> <[email protected]> wrote:
> > Hi Jaganath,
> >
> > On Mon, Oct 23, 2017 at 2:52 PM, Jaganath K <[email protected]> wrote:
> >> Hi Luiz,
> >>
> >> On Mon, Oct 23, 2017 at 5:08 PM, Luiz Augusto von Dentz
> >> <[email protected]> wrote:
> >>> Hi Jaganath,
> >>>
> >>> On Wed, Oct 18, 2017 at 2:05 PM, Jaganath Kanakkassery
> >>> <[email protected]> wrote:
> >>>> 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 <[email protected]>
> >>>> ---
> >>>> include/net/bluetooth/hci.h | 36 ++++++++++++++++++++++
> >>>> net/bluetooth/hci_conn.c | 73 ++++++++++++++++++++++++++++++++++-----------
> >>>> net/bluetooth/hci_core.c | 6 ++++
> >>>> net/bluetooth/hci_event.c | 47 +++++++++++++++++++++++++++++
> >>>> 4 files changed, 144 insertions(+), 18 deletions(-)
> >>>>
> >>>> diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
> >>>> index a4ab295..416b935 100644
> >>>> --- a/include/net/bluetooth/hci.h
> >>>> +++ b/include/net/bluetooth/hci.h
> >>>> @@ -1530,6 +1530,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
> >>>>
> >>>> @@ -2007,6 +2028,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 {
> >>>> diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
> >>>> index dc59eae..3538b69 100644
> >>>> --- a/net/bluetooth/hci_conn.c
> >>>> +++ b/net/bluetooth/hci_conn.c
> >>>> @@ -751,7 +751,6 @@ static bool conn_use_rpa(struct hci_conn *conn)
> >>>> static void hci_req_add_le_create_conn(struct hci_request *req,
> >>>> struct hci_conn *conn)
> >>>> {
> >>>> - struct hci_cp_le_create_conn cp;
> >>>> struct hci_dev *hdev = conn->hdev;
> >>>> u8 own_addr_type;
> >>>>
> >>>> @@ -762,25 +761,63 @@ static void hci_req_add_le_create_conn(struct hci_request *req,
> >>>> &own_addr_type))
> >>>> return;
> >>>>
> >>>> - memset(&cp, 0, sizeof(cp));
> >>>> + /* Use extended conn if supported */
> >>>> + if (hdev->commands[37] & 0x80) {
> >>>> + 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];
> >>>
> >>> Is there any point in using extended version if we can only do
> >>> 1Mbit/s, is there any practical difference? Is there any reason we are
> >>> not trying 2 Mbit/s phy as well?
> >>>
> >>
> >> The idea is to first implement the extended version with no functionality
> >> change (ie with PHY as 1M). We are planning to expose kernel
> >> interface so that user can select the PHY for the connection. We can add
> >> other PHYs accordingly during the implementation of the interfaces.
> >
> > There is nothing here suggesting what sort of interface we will use
> > for switching between 1-2 MBit/s,
>
> I am planning to raise separate patch for the interfaces.
>
> > usually, for BR/EDR we choose the
> > best possible (or let the controller do so) we will continue with the
> > same logic the phy policy will reside in the kernel anyway. Are there
> > any reasons why we cannot request 2MBit/s?
>
> My thinking was to select 1M, 2M or LR based on the user selection.
> Whether we need 2M or LR would be based on the usecase i think.
> But i understand your point that we can have 2M instead of 1M if both
> controller supports. But i am not sure whether any power consumption
> issues (i may be dumb here) will be there wherein some use cases 1M is
> preferred over 2M (Usecases where data rate is not relevant). But otherwise
> as you said we can add 2M also in the PHYs by default.
We cannot just have 2M instead of 1M since scanning on primary
advertising channels in only possible on 1M or LR - so 1M is perfectly
fine here.
The only reason to include 2M here is to specify default connection
parameters in case connection is established on 2M (which is still
possible) and we want them to be different than for 1M (which are used
if 2M is not specified).
IMO having 1M only is just fine until we have proper support for other
PHYs in place.
>
>
> Even in that case i think it makes more sense to add it as a separate patch.
> My idea with this patch is implementation of new command with no
> additional functionality change.
>
>
> >
> >>>> - /* 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_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);
> >>>> diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
> >>>> index eb5999a..a5a47ee 100644
> >>>> --- a/net/bluetooth/hci_core.c
> >>>> +++ b/net/bluetooth/hci_core.c
> >>>> @@ -711,6 +711,12 @@ static int hci_init3_req(struct hci_request *req, unsigned long opt)
> >>>> if (hdev->commands[37] & 0x20 && hdev->commands[37] & 0x40)
> >>>> events[1] |= 0x10; /* LE Extended adv report */
> >>>>
> >>>> + /* If the controller supports the LE Extended connection
> >>>> + * enable the corresponding event.
> >>>> + */
> >>>> + if (hdev->commands[37] & 0x80)
> >>>> + events[1] |= 0x02; /* LE Enhanced conn complete */
> >>>> +
> >>>> hci_req_add(req, HCI_OP_LE_SET_EVENT_MASK, sizeof(events),
> >>>> events);
> >>>>
> >>>> diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
> >>>> index de7b3c3..5d0517b 100644
> >>>> --- a/net/bluetooth/hci_event.c
> >>>> +++ b/net/bluetooth/hci_event.c
> >>>> @@ -2003,6 +2003,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;
> >>>> @@ -3198,6 +3223,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;
> >>>> @@ -4696,6 +4725,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)
> >>>> {
> >>>> @@ -5305,6 +5348,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;
> >>>> }
> >>>> --
> >>>> 2.7.4
> >>
> >> Thanks,
> >> Jaganath
BR,
Andrzej
Hi Luiz,
On Mon, Oct 23, 2017 at 5:34 PM, Luiz Augusto von Dentz
<[email protected]> wrote:
> Hi Jaganath,
>
> On Mon, Oct 23, 2017 at 2:52 PM, Jaganath K <[email protected]> wrote:
>> Hi Luiz,
>>
>> On Mon, Oct 23, 2017 at 5:08 PM, Luiz Augusto von Dentz
>> <[email protected]> wrote:
>>> Hi Jaganath,
>>>
>>> On Wed, Oct 18, 2017 at 2:05 PM, Jaganath Kanakkassery
>>> <[email protected]> wrote:
>>>> 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 <[email protected]>
>>>> ---
>>>> include/net/bluetooth/hci.h | 36 ++++++++++++++++++++++
>>>> net/bluetooth/hci_conn.c | 73 ++++++++++++++++++++++++++++++++++-----------
>>>> net/bluetooth/hci_core.c | 6 ++++
>>>> net/bluetooth/hci_event.c | 47 +++++++++++++++++++++++++++++
>>>> 4 files changed, 144 insertions(+), 18 deletions(-)
>>>>
>>>> diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
>>>> index a4ab295..416b935 100644
>>>> --- a/include/net/bluetooth/hci.h
>>>> +++ b/include/net/bluetooth/hci.h
>>>> @@ -1530,6 +1530,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
>>>>
>>>> @@ -2007,6 +2028,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 {
>>>> diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
>>>> index dc59eae..3538b69 100644
>>>> --- a/net/bluetooth/hci_conn.c
>>>> +++ b/net/bluetooth/hci_conn.c
>>>> @@ -751,7 +751,6 @@ static bool conn_use_rpa(struct hci_conn *conn)
>>>> static void hci_req_add_le_create_conn(struct hci_request *req,
>>>> struct hci_conn *conn)
>>>> {
>>>> - struct hci_cp_le_create_conn cp;
>>>> struct hci_dev *hdev = conn->hdev;
>>>> u8 own_addr_type;
>>>>
>>>> @@ -762,25 +761,63 @@ static void hci_req_add_le_create_conn(struct hci_request *req,
>>>> &own_addr_type))
>>>> return;
>>>>
>>>> - memset(&cp, 0, sizeof(cp));
>>>> + /* Use extended conn if supported */
>>>> + if (hdev->commands[37] & 0x80) {
>>>> + 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];
>>>
>>> Is there any point in using extended version if we can only do
>>> 1Mbit/s, is there any practical difference? Is there any reason we are
>>> not trying 2 Mbit/s phy as well?
>>>
>>
>> The idea is to first implement the extended version with no functionality
>> change (ie with PHY as 1M). We are planning to expose kernel
>> interface so that user can select the PHY for the connection. We can add
>> other PHYs accordingly during the implementation of the interfaces.
>
> There is nothing here suggesting what sort of interface we will use
> for switching between 1-2 MBit/s,
I am planning to raise separate patch for the interfaces.
> usually, for BR/EDR we choose the
> best possible (or let the controller do so) we will continue with the
> same logic the phy policy will reside in the kernel anyway. Are there
> any reasons why we cannot request 2MBit/s?
My thinking was to select 1M, 2M or LR based on the user selection.
Whether we need 2M or LR would be based on the usecase i think.
But i understand your point that we can have 2M instead of 1M if both
controller supports. But i am not sure whether any power consumption
issues (i may be dumb here) will be there wherein some use cases 1M is
preferred over 2M (Usecases where data rate is not relevant). But otherwise
as you said we can add 2M also in the PHYs by default.
Even in that case i think it makes more sense to add it as a separate patch.
My idea with this patch is implementation of new command with no
additional functionality change.
>
>>>> - /* 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_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);
>>>> diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
>>>> index eb5999a..a5a47ee 100644
>>>> --- a/net/bluetooth/hci_core.c
>>>> +++ b/net/bluetooth/hci_core.c
>>>> @@ -711,6 +711,12 @@ static int hci_init3_req(struct hci_request *req, unsigned long opt)
>>>> if (hdev->commands[37] & 0x20 && hdev->commands[37] & 0x40)
>>>> events[1] |= 0x10; /* LE Extended adv report */
>>>>
>>>> + /* If the controller supports the LE Extended connection
>>>> + * enable the corresponding event.
>>>> + */
>>>> + if (hdev->commands[37] & 0x80)
>>>> + events[1] |= 0x02; /* LE Enhanced conn complete */
>>>> +
>>>> hci_req_add(req, HCI_OP_LE_SET_EVENT_MASK, sizeof(events),
>>>> events);
>>>>
>>>> diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
>>>> index de7b3c3..5d0517b 100644
>>>> --- a/net/bluetooth/hci_event.c
>>>> +++ b/net/bluetooth/hci_event.c
>>>> @@ -2003,6 +2003,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;
>>>> @@ -3198,6 +3223,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;
>>>> @@ -4696,6 +4725,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)
>>>> {
>>>> @@ -5305,6 +5348,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;
>>>> }
>>>> --
>>>> 2.7.4
>>
>> Thanks,
>> Jaganath
>
>
>
> --
> Luiz Augusto von Dentz
Hi Jaganath,
On Mon, Oct 23, 2017 at 2:52 PM, Jaganath K <[email protected]> wrote:
> Hi Luiz,
>
> On Mon, Oct 23, 2017 at 5:08 PM, Luiz Augusto von Dentz
> <[email protected]> wrote:
>> Hi Jaganath,
>>
>> On Wed, Oct 18, 2017 at 2:05 PM, Jaganath Kanakkassery
>> <[email protected]> wrote:
>>> 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 <[email protected]>
>>> ---
>>> include/net/bluetooth/hci.h | 36 ++++++++++++++++++++++
>>> net/bluetooth/hci_conn.c | 73 ++++++++++++++++++++++++++++++++++-----------
>>> net/bluetooth/hci_core.c | 6 ++++
>>> net/bluetooth/hci_event.c | 47 +++++++++++++++++++++++++++++
>>> 4 files changed, 144 insertions(+), 18 deletions(-)
>>>
>>> diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
>>> index a4ab295..416b935 100644
>>> --- a/include/net/bluetooth/hci.h
>>> +++ b/include/net/bluetooth/hci.h
>>> @@ -1530,6 +1530,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
>>>
>>> @@ -2007,6 +2028,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 {
>>> diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
>>> index dc59eae..3538b69 100644
>>> --- a/net/bluetooth/hci_conn.c
>>> +++ b/net/bluetooth/hci_conn.c
>>> @@ -751,7 +751,6 @@ static bool conn_use_rpa(struct hci_conn *conn)
>>> static void hci_req_add_le_create_conn(struct hci_request *req,
>>> struct hci_conn *conn)
>>> {
>>> - struct hci_cp_le_create_conn cp;
>>> struct hci_dev *hdev = conn->hdev;
>>> u8 own_addr_type;
>>>
>>> @@ -762,25 +761,63 @@ static void hci_req_add_le_create_conn(struct hci_request *req,
>>> &own_addr_type))
>>> return;
>>>
>>> - memset(&cp, 0, sizeof(cp));
>>> + /* Use extended conn if supported */
>>> + if (hdev->commands[37] & 0x80) {
>>> + 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];
>>
>> Is there any point in using extended version if we can only do
>> 1Mbit/s, is there any practical difference? Is there any reason we are
>> not trying 2 Mbit/s phy as well?
>>
>
> The idea is to first implement the extended version with no functionality
> change (ie with PHY as 1M). We are planning to expose kernel
> interface so that user can select the PHY for the connection. We can add
> other PHYs accordingly during the implementation of the interfaces.
There is nothing here suggesting what sort of interface we will use
for switching between 1-2 MBit/s, usually, for BR/EDR we choose the
best possible (or let the controller do so) we will continue with the
same logic the phy policy will reside in the kernel anyway. Are there
any reasons why we cannot request 2MBit/s?
>>> - /* 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_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);
>>> diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
>>> index eb5999a..a5a47ee 100644
>>> --- a/net/bluetooth/hci_core.c
>>> +++ b/net/bluetooth/hci_core.c
>>> @@ -711,6 +711,12 @@ static int hci_init3_req(struct hci_request *req, unsigned long opt)
>>> if (hdev->commands[37] & 0x20 && hdev->commands[37] & 0x40)
>>> events[1] |= 0x10; /* LE Extended adv report */
>>>
>>> + /* If the controller supports the LE Extended connection
>>> + * enable the corresponding event.
>>> + */
>>> + if (hdev->commands[37] & 0x80)
>>> + events[1] |= 0x02; /* LE Enhanced conn complete */
>>> +
>>> hci_req_add(req, HCI_OP_LE_SET_EVENT_MASK, sizeof(events),
>>> events);
>>>
>>> diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
>>> index de7b3c3..5d0517b 100644
>>> --- a/net/bluetooth/hci_event.c
>>> +++ b/net/bluetooth/hci_event.c
>>> @@ -2003,6 +2003,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;
>>> @@ -3198,6 +3223,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;
>>> @@ -4696,6 +4725,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)
>>> {
>>> @@ -5305,6 +5348,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;
>>> }
>>> --
>>> 2.7.4
>
> Thanks,
> Jaganath
--
Luiz Augusto von Dentz
Hi Luiz,
On Mon, Oct 23, 2017 at 5:08 PM, Luiz Augusto von Dentz
<[email protected]> wrote:
> Hi Jaganath,
>
> On Wed, Oct 18, 2017 at 2:05 PM, Jaganath Kanakkassery
> <[email protected]> wrote:
>> 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 <[email protected]>
>> ---
>> include/net/bluetooth/hci.h | 36 ++++++++++++++++++++++
>> net/bluetooth/hci_conn.c | 73 ++++++++++++++++++++++++++++++++++-----------
>> net/bluetooth/hci_core.c | 6 ++++
>> net/bluetooth/hci_event.c | 47 +++++++++++++++++++++++++++++
>> 4 files changed, 144 insertions(+), 18 deletions(-)
>>
>> diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
>> index a4ab295..416b935 100644
>> --- a/include/net/bluetooth/hci.h
>> +++ b/include/net/bluetooth/hci.h
>> @@ -1530,6 +1530,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
>>
>> @@ -2007,6 +2028,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 {
>> diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
>> index dc59eae..3538b69 100644
>> --- a/net/bluetooth/hci_conn.c
>> +++ b/net/bluetooth/hci_conn.c
>> @@ -751,7 +751,6 @@ static bool conn_use_rpa(struct hci_conn *conn)
>> static void hci_req_add_le_create_conn(struct hci_request *req,
>> struct hci_conn *conn)
>> {
>> - struct hci_cp_le_create_conn cp;
>> struct hci_dev *hdev = conn->hdev;
>> u8 own_addr_type;
>>
>> @@ -762,25 +761,63 @@ static void hci_req_add_le_create_conn(struct hci_request *req,
>> &own_addr_type))
>> return;
>>
>> - memset(&cp, 0, sizeof(cp));
>> + /* Use extended conn if supported */
>> + if (hdev->commands[37] & 0x80) {
>> + 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];
>
> Is there any point in using extended version if we can only do
> 1Mbit/s, is there any practical difference? Is there any reason we are
> not trying 2 Mbit/s phy as well?
>
The idea is to first implement the extended version with no functionality
change (ie with PHY as 1M). We are planning to expose kernel
interface so that user can select the PHY for the connection. We can add
other PHYs accordingly during the implementation of the interfaces.
>> - /* 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_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);
>> diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
>> index eb5999a..a5a47ee 100644
>> --- a/net/bluetooth/hci_core.c
>> +++ b/net/bluetooth/hci_core.c
>> @@ -711,6 +711,12 @@ static int hci_init3_req(struct hci_request *req, unsigned long opt)
>> if (hdev->commands[37] & 0x20 && hdev->commands[37] & 0x40)
>> events[1] |= 0x10; /* LE Extended adv report */
>>
>> + /* If the controller supports the LE Extended connection
>> + * enable the corresponding event.
>> + */
>> + if (hdev->commands[37] & 0x80)
>> + events[1] |= 0x02; /* LE Enhanced conn complete */
>> +
>> hci_req_add(req, HCI_OP_LE_SET_EVENT_MASK, sizeof(events),
>> events);
>>
>> diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
>> index de7b3c3..5d0517b 100644
>> --- a/net/bluetooth/hci_event.c
>> +++ b/net/bluetooth/hci_event.c
>> @@ -2003,6 +2003,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;
>> @@ -3198,6 +3223,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;
>> @@ -4696,6 +4725,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)
>> {
>> @@ -5305,6 +5348,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;
>> }
>> --
>> 2.7.4
Thanks,
Jaganath
Hi Jaganath,
On Wed, Oct 18, 2017 at 2:05 PM, Jaganath Kanakkassery
<[email protected]> wrote:
> 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 <[email protected]>
> ---
> include/net/bluetooth/hci.h | 36 ++++++++++++++++++++++
> net/bluetooth/hci_conn.c | 73 ++++++++++++++++++++++++++++++++++-----------
> net/bluetooth/hci_core.c | 6 ++++
> net/bluetooth/hci_event.c | 47 +++++++++++++++++++++++++++++
> 4 files changed, 144 insertions(+), 18 deletions(-)
>
> diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
> index a4ab295..416b935 100644
> --- a/include/net/bluetooth/hci.h
> +++ b/include/net/bluetooth/hci.h
> @@ -1530,6 +1530,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
>
> @@ -2007,6 +2028,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 {
> diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
> index dc59eae..3538b69 100644
> --- a/net/bluetooth/hci_conn.c
> +++ b/net/bluetooth/hci_conn.c
> @@ -751,7 +751,6 @@ static bool conn_use_rpa(struct hci_conn *conn)
> static void hci_req_add_le_create_conn(struct hci_request *req,
> struct hci_conn *conn)
> {
> - struct hci_cp_le_create_conn cp;
> struct hci_dev *hdev = conn->hdev;
> u8 own_addr_type;
>
> @@ -762,25 +761,63 @@ static void hci_req_add_le_create_conn(struct hci_request *req,
> &own_addr_type))
> return;
>
> - memset(&cp, 0, sizeof(cp));
> + /* Use extended conn if supported */
> + if (hdev->commands[37] & 0x80) {
> + 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];
Is there any point in using extended version if we can only do
1Mbit/s, is there any practical difference? Is there any reason we are
not trying 2 Mbit/s phy as well?
> - /* 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_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);
> diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
> index eb5999a..a5a47ee 100644
> --- a/net/bluetooth/hci_core.c
> +++ b/net/bluetooth/hci_core.c
> @@ -711,6 +711,12 @@ static int hci_init3_req(struct hci_request *req, unsigned long opt)
> if (hdev->commands[37] & 0x20 && hdev->commands[37] & 0x40)
> events[1] |= 0x10; /* LE Extended adv report */
>
> + /* If the controller supports the LE Extended connection
> + * enable the corresponding event.
> + */
> + if (hdev->commands[37] & 0x80)
> + events[1] |= 0x02; /* LE Enhanced conn complete */
> +
> hci_req_add(req, HCI_OP_LE_SET_EVENT_MASK, sizeof(events),
> events);
>
> diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
> index de7b3c3..5d0517b 100644
> --- a/net/bluetooth/hci_event.c
> +++ b/net/bluetooth/hci_event.c
> @@ -2003,6 +2003,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;
> @@ -3198,6 +3223,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;
> @@ -4696,6 +4725,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)
> {
> @@ -5305,6 +5348,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;
> }
> --
> 2.7.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
Luiz Augusto von Dentz
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 <[email protected]>
---
include/net/bluetooth/hci.h | 36 ++++++++++++++++++++++
net/bluetooth/hci_conn.c | 73 ++++++++++++++++++++++++++++++++++-----------
net/bluetooth/hci_core.c | 6 ++++
net/bluetooth/hci_event.c | 47 +++++++++++++++++++++++++++++
4 files changed, 144 insertions(+), 18 deletions(-)
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index a4ab295..416b935 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -1530,6 +1530,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
@@ -2007,6 +2028,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 {
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index dc59eae..3538b69 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -751,7 +751,6 @@ static bool conn_use_rpa(struct hci_conn *conn)
static void hci_req_add_le_create_conn(struct hci_request *req,
struct hci_conn *conn)
{
- struct hci_cp_le_create_conn cp;
struct hci_dev *hdev = conn->hdev;
u8 own_addr_type;
@@ -762,25 +761,63 @@ static void hci_req_add_le_create_conn(struct hci_request *req,
&own_addr_type))
return;
- memset(&cp, 0, sizeof(cp));
+ /* Use extended conn if supported */
+ if (hdev->commands[37] & 0x80) {
+ 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_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);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index eb5999a..a5a47ee 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -711,6 +711,12 @@ static int hci_init3_req(struct hci_request *req, unsigned long opt)
if (hdev->commands[37] & 0x20 && hdev->commands[37] & 0x40)
events[1] |= 0x10; /* LE Extended adv report */
+ /* If the controller supports the LE Extended connection
+ * enable the corresponding event.
+ */
+ if (hdev->commands[37] & 0x80)
+ events[1] |= 0x02; /* LE Enhanced conn complete */
+
hci_req_add(req, HCI_OP_LE_SET_EVENT_MASK, sizeof(events),
events);
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index de7b3c3..5d0517b 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -2003,6 +2003,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;
@@ -3198,6 +3223,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;
@@ -4696,6 +4725,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)
{
@@ -5305,6 +5348,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;
}
--
2.7.4