Skip to content

Commit a106e50

Browse files
committed
Bluetooth: HCI: Add support for LL Extended Feature Set
This adds support for emulating LL Extended Feature Set introduced in 6.0 that adds the following: Commands: - HCI_LE_Read_All_Local_Supported_­Features(0x2087)(Feature:47,1) - HCI_LE_Read_All_Remote_Features(0x2088)(Feature:47,2) Events: - HCI_LE_Read_All_Remote_Features_Complete(0x2b)(Mask bit:42) Signed-off-by: Luiz Augusto von Dentz <[email protected]>
1 parent 6f7cf13 commit a106e50

File tree

5 files changed

+227
-30
lines changed

5 files changed

+227
-30
lines changed

include/net/bluetooth/hci.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,7 @@ enum {
653653
#define HCI_LE_CIS_PERIPHERAL 0x20
654654
#define HCI_LE_ISO_BROADCASTER 0x40
655655
#define HCI_LE_ISO_SYNC_RECEIVER 0x80
656+
#define HCI_LE_LL_EXT_FEATURE 0x80
656657

657658
/* Connection modes */
658659
#define HCI_CM_ACTIVE 0x0000
@@ -2255,6 +2256,19 @@ struct hci_cp_le_set_host_feature {
22552256
__u8 bit_value;
22562257
} __packed;
22572258

2259+
#define HCI_OP_LE_READ_ALL_LOCAL_FEATURES 0x2087
2260+
struct hci_rp_le_read_all_local_features {
2261+
__u8 status;
2262+
__u8 page;
2263+
__u8 features[248];
2264+
} __packed;
2265+
2266+
#define HCI_OP_LE_READ_ALL_REMOTE_FEATURES 0x2088
2267+
struct hci_cp_le_read_all_remote_features {
2268+
__le16 handle;
2269+
__u8 pages;
2270+
} __packed;
2271+
22582272
/* ---- HCI Events ---- */
22592273
struct hci_ev_status {
22602274
__u8 status;
@@ -2937,6 +2951,15 @@ struct hci_evt_le_big_info_adv_report {
29372951
__u8 encryption;
29382952
} __packed;
29392953

2954+
#define HCI_EVT_LE_ALL_REMOTE_FEATURES_COMPLETE 0x2b
2955+
struct hci_evt_le_read_all_remote_features_complete {
2956+
__u8 status;
2957+
__le16 handle;
2958+
__u8 max_pages;
2959+
__u8 valid_pages;
2960+
__u8 features[248];
2961+
} __packed;
2962+
29402963
#define HCI_EV_VENDOR 0xff
29412964

29422965
/* Internal events generated by Bluetooth stack */

include/net/bluetooth/hci_core.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,7 @@ struct hci_dev {
378378
__u8 minor_class;
379379
__u8 max_page;
380380
__u8 features[HCI_MAX_PAGES][8];
381-
__u8 le_features[8];
381+
__u8 le_features[248];
382382
__u8 le_accept_list_size;
383383
__u8 le_resolv_list_size;
384384
__u8 le_num_of_adv_sets;
@@ -702,6 +702,7 @@ struct hci_conn {
702702
__u8 attempt;
703703
__u8 dev_class[3];
704704
__u8 features[HCI_MAX_PAGES][8];
705+
__u8 le_features[248];
705706
__u16 pkt_type;
706707
__u16 link_policy;
707708
__u8 key_type;
@@ -2067,6 +2068,8 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
20672068
(le_enabled(dev) && past_receiver_capable(dev))
20682069
#define past_enabled(dev) \
20692070
(past_sender_enabled(dev) || past_receiver_enabled(dev))
2071+
#define ll_ext_feature_capable(dev) \
2072+
((dev)->le_features[7] & HCI_LE_LL_EXT_FEATURE)
20702073

20712074
#define mws_transport_config_capable(dev) (((dev)->commands[30] & 0x08) && \
20722075
(!hci_test_quirk((dev), HCI_QUIRK_BROKEN_MWS_TRANSPORT_CONFIG)))

include/net/bluetooth/hci_sync.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,3 +189,5 @@ int hci_le_conn_update_sync(struct hci_dev *hdev, struct hci_conn *conn,
189189
int hci_connect_pa_sync(struct hci_dev *hdev, struct hci_conn *conn);
190190
int hci_connect_big_sync(struct hci_dev *hdev, struct hci_conn *conn);
191191
int hci_past_sync(struct hci_conn *conn, struct hci_conn *le);
192+
193+
int hci_le_read_remote_features(struct hci_conn *conn);

net/bluetooth/hci_event.c

Lines changed: 98 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2886,12 +2886,8 @@ static void hci_cs_le_read_remote_features(struct hci_dev *hdev, u8 status)
28862886
hci_dev_lock(hdev);
28872887

28882888
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
2889-
if (conn) {
2890-
if (conn->state == BT_CONFIG) {
2891-
hci_connect_cfm(conn, status);
2892-
hci_conn_drop(conn);
2893-
}
2894-
}
2889+
if (conn && conn->state == BT_CONFIG)
2890+
hci_connect_cfm(conn, status);
28952891

28962892
hci_dev_unlock(hdev);
28972893
}
@@ -3915,11 +3911,49 @@ static u8 hci_cc_le_setup_iso_path(struct hci_dev *hdev, void *data,
39153911
return rp->status;
39163912
}
39173913

3914+
static u8 hci_cc_le_read_all_local_features(struct hci_dev *hdev, void *data,
3915+
struct sk_buff *skb)
3916+
{
3917+
struct hci_rp_le_read_all_local_features *rp = data;
3918+
3919+
bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
3920+
3921+
if (rp->status)
3922+
return rp->status;
3923+
3924+
memcpy(hdev->le_features, rp->features, 248);
3925+
3926+
return rp->status;
3927+
}
3928+
39183929
static void hci_cs_le_create_big(struct hci_dev *hdev, u8 status)
39193930
{
39203931
bt_dev_dbg(hdev, "status 0x%2.2x", status);
39213932
}
39223933

3934+
static void hci_cs_le_read_all_remote_features(struct hci_dev *hdev, u8 status)
3935+
{
3936+
struct hci_cp_le_read_remote_features *cp;
3937+
struct hci_conn *conn;
3938+
3939+
bt_dev_dbg(hdev, "status 0x%2.2x", status);
3940+
3941+
if (!status)
3942+
return;
3943+
3944+
cp = hci_sent_cmd_data(hdev, HCI_OP_LE_READ_ALL_REMOTE_FEATURES);
3945+
if (!cp)
3946+
return;
3947+
3948+
hci_dev_lock(hdev);
3949+
3950+
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
3951+
if (conn && conn->state == BT_CONFIG)
3952+
hci_connect_cfm(conn, status);
3953+
3954+
hci_dev_unlock(hdev);
3955+
}
3956+
39233957
static u8 hci_cc_set_per_adv_param(struct hci_dev *hdev, void *data,
39243958
struct sk_buff *skb)
39253959
{
@@ -4171,6 +4205,9 @@ static const struct hci_cc {
41714205
sizeof(struct hci_rp_le_set_cig_params), HCI_MAX_EVENT_SIZE),
41724206
HCI_CC(HCI_OP_LE_SETUP_ISO_PATH, hci_cc_le_setup_iso_path,
41734207
sizeof(struct hci_rp_le_setup_iso_path)),
4208+
HCI_CC(HCI_OP_LE_READ_ALL_LOCAL_FEATURES,
4209+
hci_cc_le_read_all_local_features,
4210+
sizeof(struct hci_rp_le_read_all_local_features)),
41744211
};
41754212

41764213
static u8 hci_cc_func(struct hci_dev *hdev, const struct hci_cc *cc,
@@ -4325,6 +4362,8 @@ static const struct hci_cs {
43254362
HCI_CS(HCI_OP_LE_EXT_CREATE_CONN, hci_cs_le_ext_create_conn),
43264363
HCI_CS(HCI_OP_LE_CREATE_CIS, hci_cs_le_create_cis),
43274364
HCI_CS(HCI_OP_LE_CREATE_BIG, hci_cs_le_create_big),
4365+
HCI_CS(HCI_OP_LE_READ_ALL_REMOTE_FEATURES,
4366+
hci_cs_le_read_all_remote_features),
43284367
};
43294368

43304369
static void hci_cmd_status_evt(struct hci_dev *hdev, void *data,
@@ -5645,6 +5684,7 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status,
56455684
struct hci_conn *conn;
56465685
struct smp_irk *irk;
56475686
u8 addr_type;
5687+
int err;
56485688

56495689
hci_dev_lock(hdev);
56505690

@@ -5775,26 +5815,8 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status,
57755815
hci_debugfs_create_conn(conn);
57765816
hci_conn_add_sysfs(conn);
57775817

5778-
/* The remote features procedure is defined for central
5779-
* role only. So only in case of an initiated connection
5780-
* request the remote features.
5781-
*
5782-
* If the local controller supports peripheral-initiated features
5783-
* exchange, then requesting the remote features in peripheral
5784-
* role is possible. Otherwise just transition into the
5785-
* connected state without requesting the remote features.
5786-
*/
5787-
if (conn->out ||
5788-
(hdev->le_features[0] & HCI_LE_PERIPHERAL_FEATURES)) {
5789-
struct hci_cp_le_read_remote_features cp;
5790-
5791-
cp.handle = __cpu_to_le16(conn->handle);
5792-
5793-
hci_send_cmd(hdev, HCI_OP_LE_READ_REMOTE_FEATURES,
5794-
sizeof(cp), &cp);
5795-
5796-
hci_conn_hold(conn);
5797-
} else {
5818+
err = hci_le_read_remote_features(conn);
5819+
if (err) {
57985820
conn->state = BT_CONNECTED;
57995821
hci_connect_cfm(conn, status);
58005822
}
@@ -6608,7 +6630,6 @@ static void hci_le_remote_feat_complete_evt(struct hci_dev *hdev, void *data,
66086630

66096631
conn->state = BT_CONNECTED;
66106632
hci_connect_cfm(conn, status);
6611-
hci_conn_drop(conn);
66126633
}
66136634
}
66146635

@@ -7186,6 +7207,50 @@ static void hci_le_big_info_adv_report_evt(struct hci_dev *hdev, void *data,
71867207
hci_dev_unlock(hdev);
71877208
}
71887209

7210+
static void hci_le_read_all_remote_features_evt(struct hci_dev *hdev,
7211+
void *data, struct sk_buff *skb)
7212+
{
7213+
struct hci_evt_le_read_all_remote_features_complete *ev = data;
7214+
struct hci_conn *conn;
7215+
7216+
bt_dev_dbg(hdev, "status 0x%2.2x", ev->status);
7217+
7218+
hci_dev_lock(hdev);
7219+
7220+
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
7221+
if (!conn)
7222+
goto unlock;
7223+
7224+
if (!ev->status)
7225+
memcpy(conn->le_features, ev->features, 248);
7226+
7227+
if (conn->state == BT_CONFIG) {
7228+
__u8 status;
7229+
7230+
/* If the local controller supports peripheral-initiated
7231+
* features exchange, but the remote controller does
7232+
* not, then it is possible that the error code 0x1a
7233+
* for unsupported remote feature gets returned.
7234+
*
7235+
* In this specific case, allow the connection to
7236+
* transition into connected state and mark it as
7237+
* successful.
7238+
*/
7239+
if (!conn->out &&
7240+
ev->status == HCI_ERROR_UNSUPPORTED_REMOTE_FEATURE &&
7241+
(hdev->le_features[0] & HCI_LE_PERIPHERAL_FEATURES))
7242+
status = 0x00;
7243+
else
7244+
status = ev->status;
7245+
7246+
conn->state = BT_CONNECTED;
7247+
hci_connect_cfm(conn, status);
7248+
}
7249+
7250+
unlock:
7251+
hci_dev_unlock(hdev);
7252+
}
7253+
71897254
#define HCI_LE_EV_VL(_op, _func, _min_len, _max_len) \
71907255
[_op] = { \
71917256
.func = _func, \
@@ -7291,6 +7356,12 @@ static const struct hci_le_ev {
72917356
hci_le_big_info_adv_report_evt,
72927357
sizeof(struct hci_evt_le_big_info_adv_report),
72937358
HCI_MAX_EVENT_SIZE),
7359+
/* [0x2b = HCI_EVT_LE_ALL_REMOTE_FEATURES_COMPLETE] */
7360+
HCI_LE_EV_VL(HCI_EVT_LE_ALL_REMOTE_FEATURES_COMPLETE,
7361+
hci_le_read_all_remote_features_evt,
7362+
sizeof(struct
7363+
hci_evt_le_read_all_remote_features_complete),
7364+
HCI_MAX_EVENT_SIZE),
72947365
};
72957366

72967367
static void hci_le_meta_evt(struct hci_dev *hdev, void *data,

net/bluetooth/hci_sync.c

Lines changed: 100 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4011,8 +4011,19 @@ static int hci_le_read_buffer_size_sync(struct hci_dev *hdev)
40114011
/* Read LE Local Supported Features */
40124012
static int hci_le_read_local_features_sync(struct hci_dev *hdev)
40134013
{
4014-
return __hci_cmd_sync_status(hdev, HCI_OP_LE_READ_LOCAL_FEATURES,
4015-
0, NULL, HCI_CMD_TIMEOUT);
4014+
int err;
4015+
4016+
err = __hci_cmd_sync_status(hdev, HCI_OP_LE_READ_LOCAL_FEATURES,
4017+
0, NULL, HCI_CMD_TIMEOUT);
4018+
if (err)
4019+
return err;
4020+
4021+
if (ll_ext_feature_capable(hdev) && hdev->commands[47] & BIT(2))
4022+
return __hci_cmd_sync_status(hdev,
4023+
HCI_OP_LE_READ_ALL_LOCAL_FEATURES,
4024+
0, NULL, HCI_CMD_TIMEOUT);
4025+
4026+
return err;
40164027
}
40174028

40184029
/* Read LE Supported States */
@@ -7320,3 +7331,90 @@ int hci_past_sync(struct hci_conn *conn, struct hci_conn *le)
73207331

73217332
return err;
73227333
}
7334+
7335+
static void le_read_features_complete(struct hci_dev *hdev, void *data, int err)
7336+
{
7337+
struct hci_conn *conn = data;
7338+
7339+
bt_dev_dbg(hdev, "err %d", err);
7340+
7341+
if (err == -ECANCELED)
7342+
return;
7343+
7344+
hci_conn_drop(conn);
7345+
}
7346+
7347+
static int hci_le_read_all_remote_features_sync(struct hci_dev *hdev,
7348+
void *data)
7349+
{
7350+
struct hci_conn *conn = data;
7351+
struct hci_cp_le_read_all_remote_features cp;
7352+
7353+
memset(&cp, 0, sizeof(cp));
7354+
cp.handle = cpu_to_le16(conn->handle);
7355+
cp.pages = 10; /* Attempt to read all pages */
7356+
7357+
/* Wait for HCI_EVT_LE_ALL_REMOTE_FEATURES_COMPLETE event otherwise
7358+
* hci_conn_drop may run prematurely causing a disconnection.
7359+
*/
7360+
return __hci_cmd_sync_status_sk(hdev,
7361+
HCI_OP_LE_READ_ALL_REMOTE_FEATURES,
7362+
sizeof(cp), &cp,
7363+
HCI_EVT_LE_ALL_REMOTE_FEATURES_COMPLETE,
7364+
HCI_CMD_TIMEOUT, NULL);
7365+
7366+
return __hci_cmd_sync_status(hdev, HCI_OP_LE_READ_ALL_REMOTE_FEATURES,
7367+
sizeof(cp), &cp, HCI_CMD_TIMEOUT);
7368+
}
7369+
7370+
static int hci_le_read_remote_features_sync(struct hci_dev *hdev, void *data)
7371+
{
7372+
struct hci_conn *conn = data;
7373+
struct hci_cp_le_read_remote_features cp;
7374+
7375+
if (!hci_conn_valid(hdev, conn))
7376+
return -ECANCELED;
7377+
7378+
/* Check if LL Extended Feature Set is supported and
7379+
* HCI_OP_LE_READ_ALL_REMOTE_FEATURES is supported then use that to read
7380+
* all features.
7381+
*/
7382+
if (ll_ext_feature_capable(hdev) && hdev->commands[47] & BIT(3))
7383+
return hci_le_read_all_remote_features_sync(hdev, data);
7384+
7385+
memset(&cp, 0, sizeof(cp));
7386+
cp.handle = cpu_to_le16(conn->handle);
7387+
7388+
/* Wait for HCI_EV_LE_REMOTE_FEAT_COMPLETE event otherwise
7389+
* hci_conn_drop may run prematurely causing a disconnection.
7390+
*/
7391+
return __hci_cmd_sync_status_sk(hdev, HCI_OP_LE_READ_REMOTE_FEATURES,
7392+
sizeof(cp), &cp,
7393+
HCI_EV_LE_REMOTE_FEAT_COMPLETE,
7394+
HCI_CMD_TIMEOUT, NULL);
7395+
}
7396+
7397+
int hci_le_read_remote_features(struct hci_conn *conn)
7398+
{
7399+
struct hci_dev *hdev = conn->hdev;
7400+
int err;
7401+
7402+
/* The remote features procedure is defined for central
7403+
* role only. So only in case of an initiated connection
7404+
* request the remote features.
7405+
*
7406+
* If the local controller supports peripheral-initiated features
7407+
* exchange, then requesting the remote features in peripheral
7408+
* role is possible. Otherwise just transition into the
7409+
* connected state without requesting the remote features.
7410+
*/
7411+
if (conn->out || (hdev->le_features[0] & HCI_LE_PERIPHERAL_FEATURES))
7412+
err = hci_cmd_sync_queue_once(hdev,
7413+
hci_le_read_remote_features_sync,
7414+
hci_conn_hold(conn),
7415+
le_read_features_complete);
7416+
else
7417+
err = -EOPNOTSUPP;
7418+
7419+
return err;
7420+
}

0 commit comments

Comments
 (0)