mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git/
synced 2026-04-01 22:37:41 -04:00
Merge tag 'for-net-2026-04-01' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth
Luiz Augusto von Dentz says: ==================== bluetooth pull request for net: - hci_sync: Fix UAF in le_read_features_complete - hci_sync: call destroy in hci_cmd_sync_run if immediate - hci_sync: hci_cmd_sync_queue_once() return -EEXIST if exists - hci_sync: fix leaks when hci_cmd_sync_queue_once fails - hci_sync: fix stack buffer overflow in hci_le_big_create_sync - hci_conn: fix potential UAF in set_cig_params_sync - hci_event: fix potential UAF in hci_le_remote_conn_param_req_evt - hci_event: move wake reason storage into validated event handlers - SMP: force responder MITM requirements before building the pairing response - SMP: derive legacy responder STK authentication from MITM state - MGMT: validate LTK enc_size on load - MGMT: validate mesh send advertising payload length - SCO: fix race conditions in sco_sock_connect() - hci_h4: Fix race during initialization * tag 'for-net-2026-04-01' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth: Bluetooth: hci_sync: fix stack buffer overflow in hci_le_big_create_sync Bluetooth: SMP: derive legacy responder STK authentication from MITM state Bluetooth: SMP: force responder MITM requirements before building the pairing response Bluetooth: MGMT: validate mesh send advertising payload length Bluetooth: hci_event: fix potential UAF in hci_le_remote_conn_param_req_evt Bluetooth: hci_conn: fix potential UAF in set_cig_params_sync Bluetooth: MGMT: validate LTK enc_size on load Bluetooth: hci_h4: Fix race during initialization Bluetooth: hci_sync: Fix UAF in le_read_features_complete Bluetooth: hci_sync: fix leaks when hci_cmd_sync_queue_once fails Bluetooth: hci_sync: hci_cmd_sync_queue_once() return -EEXIST if exists Bluetooth: hci_event: move wake reason storage into validated event handlers Bluetooth: SCO: fix race conditions in sco_sock_connect() Bluetooth: hci_sync: call destroy in hci_cmd_sync_run if immediate ==================== Link: https://patch.msgid.link/20260401205834.2189162-1-luiz.dentz@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
@@ -109,9 +109,6 @@ static int h4_recv(struct hci_uart *hu, const void *data, int count)
|
||||
{
|
||||
struct h4_struct *h4 = hu->priv;
|
||||
|
||||
if (!test_bit(HCI_UART_REGISTERED, &hu->flags))
|
||||
return -EUNATCH;
|
||||
|
||||
h4->rx_skb = h4_recv_buf(hu, h4->rx_skb, data, count,
|
||||
h4_recv_pkts, ARRAY_SIZE(h4_recv_pkts));
|
||||
if (IS_ERR(h4->rx_skb)) {
|
||||
|
||||
@@ -1843,9 +1843,13 @@ static int set_cig_params_sync(struct hci_dev *hdev, void *data)
|
||||
u8 aux_num_cis = 0;
|
||||
u8 cis_id;
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
conn = hci_conn_hash_lookup_cig(hdev, cig_id);
|
||||
if (!conn)
|
||||
if (!conn) {
|
||||
hci_dev_unlock(hdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
qos = &conn->iso_qos;
|
||||
pdu->cig_id = cig_id;
|
||||
@@ -1884,6 +1888,8 @@ static int set_cig_params_sync(struct hci_dev *hdev, void *data)
|
||||
}
|
||||
pdu->num_cis = aux_num_cis;
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
if (!pdu->num_cis)
|
||||
return 0;
|
||||
|
||||
|
||||
@@ -80,6 +80,10 @@ static void *hci_le_ev_skb_pull(struct hci_dev *hdev, struct sk_buff *skb,
|
||||
return data;
|
||||
}
|
||||
|
||||
static void hci_store_wake_reason(struct hci_dev *hdev,
|
||||
const bdaddr_t *bdaddr, u8 addr_type)
|
||||
__must_hold(&hdev->lock);
|
||||
|
||||
static u8 hci_cc_inquiry_cancel(struct hci_dev *hdev, void *data,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
@@ -3111,6 +3115,7 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, void *data,
|
||||
bt_dev_dbg(hdev, "status 0x%2.2x", status);
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
hci_store_wake_reason(hdev, &ev->bdaddr, BDADDR_BREDR);
|
||||
|
||||
/* Check for existing connection:
|
||||
*
|
||||
@@ -3274,6 +3279,10 @@ static void hci_conn_request_evt(struct hci_dev *hdev, void *data,
|
||||
|
||||
bt_dev_dbg(hdev, "bdaddr %pMR type 0x%x", &ev->bdaddr, ev->link_type);
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
hci_store_wake_reason(hdev, &ev->bdaddr, BDADDR_BREDR);
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
/* Reject incoming connection from device with same BD ADDR against
|
||||
* CVE-2020-26555
|
||||
*/
|
||||
@@ -5021,6 +5030,7 @@ static void hci_sync_conn_complete_evt(struct hci_dev *hdev, void *data,
|
||||
bt_dev_dbg(hdev, "status 0x%2.2x", status);
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
hci_store_wake_reason(hdev, &ev->bdaddr, BDADDR_BREDR);
|
||||
|
||||
conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr);
|
||||
if (!conn) {
|
||||
@@ -5713,6 +5723,7 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status,
|
||||
int err;
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
hci_store_wake_reason(hdev, bdaddr, bdaddr_type);
|
||||
|
||||
/* All controllers implicitly stop advertising in the event of a
|
||||
* connection, so ensure that the state bit is cleared.
|
||||
@@ -6005,6 +6016,7 @@ static void hci_le_past_received_evt(struct hci_dev *hdev, void *data,
|
||||
bt_dev_dbg(hdev, "status 0x%2.2x", ev->status);
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
hci_store_wake_reason(hdev, &ev->bdaddr, ev->bdaddr_type);
|
||||
|
||||
hci_dev_clear_flag(hdev, HCI_PA_SYNC);
|
||||
|
||||
@@ -6403,6 +6415,8 @@ static void hci_le_adv_report_evt(struct hci_dev *hdev, void *data,
|
||||
info->length + 1))
|
||||
break;
|
||||
|
||||
hci_store_wake_reason(hdev, &info->bdaddr, info->bdaddr_type);
|
||||
|
||||
if (info->length <= max_adv_len(hdev)) {
|
||||
rssi = info->data[info->length];
|
||||
process_adv_report(hdev, info->type, &info->bdaddr,
|
||||
@@ -6491,6 +6505,8 @@ static void hci_le_ext_adv_report_evt(struct hci_dev *hdev, void *data,
|
||||
info->length))
|
||||
break;
|
||||
|
||||
hci_store_wake_reason(hdev, &info->bdaddr, info->bdaddr_type);
|
||||
|
||||
evt_type = __le16_to_cpu(info->type) & LE_EXT_ADV_EVT_TYPE_MASK;
|
||||
legacy_evt_type = ext_evt_type_to_legacy(hdev, evt_type);
|
||||
|
||||
@@ -6536,6 +6552,7 @@ static void hci_le_pa_sync_established_evt(struct hci_dev *hdev, void *data,
|
||||
bt_dev_dbg(hdev, "status 0x%2.2x", ev->status);
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
hci_store_wake_reason(hdev, &ev->bdaddr, ev->bdaddr_type);
|
||||
|
||||
hci_dev_clear_flag(hdev, HCI_PA_SYNC);
|
||||
|
||||
@@ -6767,25 +6784,31 @@ static void hci_le_remote_conn_param_req_evt(struct hci_dev *hdev, void *data,
|
||||
latency = le16_to_cpu(ev->latency);
|
||||
timeout = le16_to_cpu(ev->timeout);
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
hcon = hci_conn_hash_lookup_handle(hdev, handle);
|
||||
if (!hcon || hcon->state != BT_CONNECTED)
|
||||
return send_conn_param_neg_reply(hdev, handle,
|
||||
HCI_ERROR_UNKNOWN_CONN_ID);
|
||||
if (!hcon || hcon->state != BT_CONNECTED) {
|
||||
send_conn_param_neg_reply(hdev, handle,
|
||||
HCI_ERROR_UNKNOWN_CONN_ID);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (max > hcon->le_conn_max_interval)
|
||||
return send_conn_param_neg_reply(hdev, handle,
|
||||
HCI_ERROR_INVALID_LL_PARAMS);
|
||||
if (max > hcon->le_conn_max_interval) {
|
||||
send_conn_param_neg_reply(hdev, handle,
|
||||
HCI_ERROR_INVALID_LL_PARAMS);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (hci_check_conn_params(min, max, latency, timeout))
|
||||
return send_conn_param_neg_reply(hdev, handle,
|
||||
HCI_ERROR_INVALID_LL_PARAMS);
|
||||
if (hci_check_conn_params(min, max, latency, timeout)) {
|
||||
send_conn_param_neg_reply(hdev, handle,
|
||||
HCI_ERROR_INVALID_LL_PARAMS);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (hcon->role == HCI_ROLE_MASTER) {
|
||||
struct hci_conn_params *params;
|
||||
u8 store_hint;
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
params = hci_conn_params_lookup(hdev, &hcon->dst,
|
||||
hcon->dst_type);
|
||||
if (params) {
|
||||
@@ -6798,8 +6821,6 @@ static void hci_le_remote_conn_param_req_evt(struct hci_dev *hdev, void *data,
|
||||
store_hint = 0x00;
|
||||
}
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
mgmt_new_conn_param(hdev, &hcon->dst, hcon->dst_type,
|
||||
store_hint, min, max, latency, timeout);
|
||||
}
|
||||
@@ -6813,6 +6834,9 @@ static void hci_le_remote_conn_param_req_evt(struct hci_dev *hdev, void *data,
|
||||
cp.max_ce_len = 0;
|
||||
|
||||
hci_send_cmd(hdev, HCI_OP_LE_CONN_PARAM_REQ_REPLY, sizeof(cp), &cp);
|
||||
|
||||
unlock:
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static void hci_le_direct_adv_report_evt(struct hci_dev *hdev, void *data,
|
||||
@@ -6834,6 +6858,8 @@ static void hci_le_direct_adv_report_evt(struct hci_dev *hdev, void *data,
|
||||
for (i = 0; i < ev->num; i++) {
|
||||
struct hci_ev_le_direct_adv_info *info = &ev->info[i];
|
||||
|
||||
hci_store_wake_reason(hdev, &info->bdaddr, info->bdaddr_type);
|
||||
|
||||
process_adv_report(hdev, info->type, &info->bdaddr,
|
||||
info->bdaddr_type, &info->direct_addr,
|
||||
info->direct_addr_type, HCI_ADV_PHY_1M, 0,
|
||||
@@ -7517,73 +7543,29 @@ static bool hci_get_cmd_complete(struct hci_dev *hdev, u16 opcode,
|
||||
return true;
|
||||
}
|
||||
|
||||
static void hci_store_wake_reason(struct hci_dev *hdev, u8 event,
|
||||
struct sk_buff *skb)
|
||||
static void hci_store_wake_reason(struct hci_dev *hdev,
|
||||
const bdaddr_t *bdaddr, u8 addr_type)
|
||||
__must_hold(&hdev->lock)
|
||||
{
|
||||
struct hci_ev_le_advertising_info *adv;
|
||||
struct hci_ev_le_direct_adv_info *direct_adv;
|
||||
struct hci_ev_le_ext_adv_info *ext_adv;
|
||||
const struct hci_ev_conn_complete *conn_complete = (void *)skb->data;
|
||||
const struct hci_ev_conn_request *conn_request = (void *)skb->data;
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
lockdep_assert_held(&hdev->lock);
|
||||
|
||||
/* If we are currently suspended and this is the first BT event seen,
|
||||
* save the wake reason associated with the event.
|
||||
*/
|
||||
if (!hdev->suspended || hdev->wake_reason)
|
||||
goto unlock;
|
||||
return;
|
||||
|
||||
if (!bdaddr) {
|
||||
hdev->wake_reason = MGMT_WAKE_REASON_UNEXPECTED;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Default to remote wake. Values for wake_reason are documented in the
|
||||
* Bluez mgmt api docs.
|
||||
*/
|
||||
hdev->wake_reason = MGMT_WAKE_REASON_REMOTE_WAKE;
|
||||
|
||||
/* Once configured for remote wakeup, we should only wake up for
|
||||
* reconnections. It's useful to see which device is waking us up so
|
||||
* keep track of the bdaddr of the connection event that woke us up.
|
||||
*/
|
||||
if (event == HCI_EV_CONN_REQUEST) {
|
||||
bacpy(&hdev->wake_addr, &conn_request->bdaddr);
|
||||
hdev->wake_addr_type = BDADDR_BREDR;
|
||||
} else if (event == HCI_EV_CONN_COMPLETE) {
|
||||
bacpy(&hdev->wake_addr, &conn_complete->bdaddr);
|
||||
hdev->wake_addr_type = BDADDR_BREDR;
|
||||
} else if (event == HCI_EV_LE_META) {
|
||||
struct hci_ev_le_meta *le_ev = (void *)skb->data;
|
||||
u8 subevent = le_ev->subevent;
|
||||
u8 *ptr = &skb->data[sizeof(*le_ev)];
|
||||
u8 num_reports = *ptr;
|
||||
|
||||
if ((subevent == HCI_EV_LE_ADVERTISING_REPORT ||
|
||||
subevent == HCI_EV_LE_DIRECT_ADV_REPORT ||
|
||||
subevent == HCI_EV_LE_EXT_ADV_REPORT) &&
|
||||
num_reports) {
|
||||
adv = (void *)(ptr + 1);
|
||||
direct_adv = (void *)(ptr + 1);
|
||||
ext_adv = (void *)(ptr + 1);
|
||||
|
||||
switch (subevent) {
|
||||
case HCI_EV_LE_ADVERTISING_REPORT:
|
||||
bacpy(&hdev->wake_addr, &adv->bdaddr);
|
||||
hdev->wake_addr_type = adv->bdaddr_type;
|
||||
break;
|
||||
case HCI_EV_LE_DIRECT_ADV_REPORT:
|
||||
bacpy(&hdev->wake_addr, &direct_adv->bdaddr);
|
||||
hdev->wake_addr_type = direct_adv->bdaddr_type;
|
||||
break;
|
||||
case HCI_EV_LE_EXT_ADV_REPORT:
|
||||
bacpy(&hdev->wake_addr, &ext_adv->bdaddr);
|
||||
hdev->wake_addr_type = ext_adv->bdaddr_type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
hdev->wake_reason = MGMT_WAKE_REASON_UNEXPECTED;
|
||||
}
|
||||
|
||||
unlock:
|
||||
hci_dev_unlock(hdev);
|
||||
bacpy(&hdev->wake_addr, bdaddr);
|
||||
hdev->wake_addr_type = addr_type;
|
||||
}
|
||||
|
||||
#define HCI_EV_VL(_op, _func, _min_len, _max_len) \
|
||||
@@ -7830,14 +7812,15 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
|
||||
skb_pull(skb, HCI_EVENT_HDR_SIZE);
|
||||
|
||||
/* Store wake reason if we're suspended */
|
||||
hci_store_wake_reason(hdev, event, skb);
|
||||
|
||||
bt_dev_dbg(hdev, "event 0x%2.2x", event);
|
||||
|
||||
hci_event_func(hdev, event, skb, &opcode, &status, &req_complete,
|
||||
&req_complete_skb);
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
hci_store_wake_reason(hdev, NULL, 0);
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
if (req_complete) {
|
||||
req_complete(hdev, status, opcode);
|
||||
} else if (req_complete_skb) {
|
||||
|
||||
@@ -780,7 +780,7 @@ int hci_cmd_sync_queue_once(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
|
||||
void *data, hci_cmd_sync_work_destroy_t destroy)
|
||||
{
|
||||
if (hci_cmd_sync_lookup_entry(hdev, func, data, destroy))
|
||||
return 0;
|
||||
return -EEXIST;
|
||||
|
||||
return hci_cmd_sync_queue(hdev, func, data, destroy);
|
||||
}
|
||||
@@ -801,8 +801,15 @@ int hci_cmd_sync_run(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
|
||||
return -ENETDOWN;
|
||||
|
||||
/* If on cmd_sync_work then run immediately otherwise queue */
|
||||
if (current_work() == &hdev->cmd_sync_work)
|
||||
return func(hdev, data);
|
||||
if (current_work() == &hdev->cmd_sync_work) {
|
||||
int err;
|
||||
|
||||
err = func(hdev, data);
|
||||
if (destroy)
|
||||
destroy(hdev, data, err);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return hci_cmd_sync_submit(hdev, func, data, destroy);
|
||||
}
|
||||
@@ -3255,6 +3262,8 @@ static int update_passive_scan_sync(struct hci_dev *hdev, void *data)
|
||||
|
||||
int hci_update_passive_scan(struct hci_dev *hdev)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* Only queue if it would have any effect */
|
||||
if (!test_bit(HCI_UP, &hdev->flags) ||
|
||||
test_bit(HCI_INIT, &hdev->flags) ||
|
||||
@@ -3264,8 +3273,9 @@ int hci_update_passive_scan(struct hci_dev *hdev)
|
||||
hci_dev_test_flag(hdev, HCI_UNREGISTER))
|
||||
return 0;
|
||||
|
||||
return hci_cmd_sync_queue_once(hdev, update_passive_scan_sync, NULL,
|
||||
NULL);
|
||||
err = hci_cmd_sync_queue_once(hdev, update_passive_scan_sync, NULL,
|
||||
NULL);
|
||||
return (err == -EEXIST) ? 0 : err;
|
||||
}
|
||||
|
||||
int hci_write_sc_support_sync(struct hci_dev *hdev, u8 val)
|
||||
@@ -6958,8 +6968,11 @@ static int hci_acl_create_conn_sync(struct hci_dev *hdev, void *data)
|
||||
|
||||
int hci_connect_acl_sync(struct hci_dev *hdev, struct hci_conn *conn)
|
||||
{
|
||||
return hci_cmd_sync_queue_once(hdev, hci_acl_create_conn_sync, conn,
|
||||
NULL);
|
||||
int err;
|
||||
|
||||
err = hci_cmd_sync_queue_once(hdev, hci_acl_create_conn_sync, conn,
|
||||
NULL);
|
||||
return (err == -EEXIST) ? 0 : err;
|
||||
}
|
||||
|
||||
static void create_le_conn_complete(struct hci_dev *hdev, void *data, int err)
|
||||
@@ -6995,8 +7008,11 @@ done:
|
||||
|
||||
int hci_connect_le_sync(struct hci_dev *hdev, struct hci_conn *conn)
|
||||
{
|
||||
return hci_cmd_sync_queue_once(hdev, hci_le_create_conn_sync, conn,
|
||||
create_le_conn_complete);
|
||||
int err;
|
||||
|
||||
err = hci_cmd_sync_queue_once(hdev, hci_le_create_conn_sync, conn,
|
||||
create_le_conn_complete);
|
||||
return (err == -EEXIST) ? 0 : err;
|
||||
}
|
||||
|
||||
int hci_cancel_connect_sync(struct hci_dev *hdev, struct hci_conn *conn)
|
||||
@@ -7203,8 +7219,11 @@ done:
|
||||
|
||||
int hci_connect_pa_sync(struct hci_dev *hdev, struct hci_conn *conn)
|
||||
{
|
||||
return hci_cmd_sync_queue_once(hdev, hci_le_pa_create_sync, conn,
|
||||
create_pa_complete);
|
||||
int err;
|
||||
|
||||
err = hci_cmd_sync_queue_once(hdev, hci_le_pa_create_sync, conn,
|
||||
create_pa_complete);
|
||||
return (err == -EEXIST) ? 0 : err;
|
||||
}
|
||||
|
||||
static void create_big_complete(struct hci_dev *hdev, void *data, int err)
|
||||
@@ -7222,7 +7241,8 @@ static void create_big_complete(struct hci_dev *hdev, void *data, int err)
|
||||
|
||||
static int hci_le_big_create_sync(struct hci_dev *hdev, void *data)
|
||||
{
|
||||
DEFINE_FLEX(struct hci_cp_le_big_create_sync, cp, bis, num_bis, 0x11);
|
||||
DEFINE_FLEX(struct hci_cp_le_big_create_sync, cp, bis, num_bis,
|
||||
HCI_MAX_ISO_BIS);
|
||||
struct hci_conn *conn = data;
|
||||
struct bt_iso_qos *qos = &conn->iso_qos;
|
||||
int err;
|
||||
@@ -7266,8 +7286,11 @@ static int hci_le_big_create_sync(struct hci_dev *hdev, void *data)
|
||||
|
||||
int hci_connect_big_sync(struct hci_dev *hdev, struct hci_conn *conn)
|
||||
{
|
||||
return hci_cmd_sync_queue_once(hdev, hci_le_big_create_sync, conn,
|
||||
create_big_complete);
|
||||
int err;
|
||||
|
||||
err = hci_cmd_sync_queue_once(hdev, hci_le_big_create_sync, conn,
|
||||
create_big_complete);
|
||||
return (err == -EEXIST) ? 0 : err;
|
||||
}
|
||||
|
||||
struct past_data {
|
||||
@@ -7359,7 +7382,7 @@ int hci_past_sync(struct hci_conn *conn, struct hci_conn *le)
|
||||
if (err)
|
||||
kfree(data);
|
||||
|
||||
return err;
|
||||
return (err == -EEXIST) ? 0 : err;
|
||||
}
|
||||
|
||||
static void le_read_features_complete(struct hci_dev *hdev, void *data, int err)
|
||||
@@ -7368,10 +7391,8 @@ static void le_read_features_complete(struct hci_dev *hdev, void *data, int err)
|
||||
|
||||
bt_dev_dbg(hdev, "err %d", err);
|
||||
|
||||
if (err == -ECANCELED)
|
||||
return;
|
||||
|
||||
hci_conn_drop(conn);
|
||||
hci_conn_put(conn);
|
||||
}
|
||||
|
||||
static int hci_le_read_all_remote_features_sync(struct hci_dev *hdev,
|
||||
@@ -7438,15 +7459,20 @@ int hci_le_read_remote_features(struct hci_conn *conn)
|
||||
* role is possible. Otherwise just transition into the
|
||||
* connected state without requesting the remote features.
|
||||
*/
|
||||
if (conn->out || (hdev->le_features[0] & HCI_LE_PERIPHERAL_FEATURES))
|
||||
if (conn->out || (hdev->le_features[0] & HCI_LE_PERIPHERAL_FEATURES)) {
|
||||
err = hci_cmd_sync_queue_once(hdev,
|
||||
hci_le_read_remote_features_sync,
|
||||
hci_conn_hold(conn),
|
||||
hci_conn_hold(hci_conn_get(conn)),
|
||||
le_read_features_complete);
|
||||
else
|
||||
if (err) {
|
||||
hci_conn_drop(conn);
|
||||
hci_conn_put(conn);
|
||||
}
|
||||
} else {
|
||||
err = -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
return err;
|
||||
return (err == -EEXIST) ? 0 : err;
|
||||
}
|
||||
|
||||
static void pkt_type_changed(struct hci_dev *hdev, void *data, int err)
|
||||
@@ -7472,6 +7498,7 @@ int hci_acl_change_pkt_type(struct hci_conn *conn, u16 pkt_type)
|
||||
{
|
||||
struct hci_dev *hdev = conn->hdev;
|
||||
struct hci_cp_change_conn_ptype *cp;
|
||||
int err;
|
||||
|
||||
cp = kmalloc_obj(*cp);
|
||||
if (!cp)
|
||||
@@ -7480,8 +7507,12 @@ int hci_acl_change_pkt_type(struct hci_conn *conn, u16 pkt_type)
|
||||
cp->handle = cpu_to_le16(conn->handle);
|
||||
cp->pkt_type = cpu_to_le16(pkt_type);
|
||||
|
||||
return hci_cmd_sync_queue_once(hdev, hci_change_conn_ptype_sync, cp,
|
||||
pkt_type_changed);
|
||||
err = hci_cmd_sync_queue_once(hdev, hci_change_conn_ptype_sync, cp,
|
||||
pkt_type_changed);
|
||||
if (err)
|
||||
kfree(cp);
|
||||
|
||||
return (err == -EEXIST) ? 0 : err;
|
||||
}
|
||||
|
||||
static void le_phy_update_complete(struct hci_dev *hdev, void *data, int err)
|
||||
@@ -7507,6 +7538,7 @@ int hci_le_set_phy(struct hci_conn *conn, u8 tx_phys, u8 rx_phys)
|
||||
{
|
||||
struct hci_dev *hdev = conn->hdev;
|
||||
struct hci_cp_le_set_phy *cp;
|
||||
int err;
|
||||
|
||||
cp = kmalloc_obj(*cp);
|
||||
if (!cp)
|
||||
@@ -7517,6 +7549,10 @@ int hci_le_set_phy(struct hci_conn *conn, u8 tx_phys, u8 rx_phys)
|
||||
cp->tx_phys = tx_phys;
|
||||
cp->rx_phys = rx_phys;
|
||||
|
||||
return hci_cmd_sync_queue_once(hdev, hci_le_set_phy_sync, cp,
|
||||
le_phy_update_complete);
|
||||
err = hci_cmd_sync_queue_once(hdev, hci_le_set_phy_sync, cp,
|
||||
le_phy_update_complete);
|
||||
if (err)
|
||||
kfree(cp);
|
||||
|
||||
return (err == -EEXIST) ? 0 : err;
|
||||
}
|
||||
|
||||
@@ -2478,6 +2478,7 @@ static int mesh_send(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
|
||||
struct mgmt_mesh_tx *mesh_tx;
|
||||
struct mgmt_cp_mesh_send *send = data;
|
||||
struct mgmt_rp_mesh_read_features rp;
|
||||
u16 expected_len;
|
||||
bool sending;
|
||||
int err = 0;
|
||||
|
||||
@@ -2485,12 +2486,19 @@ static int mesh_send(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
|
||||
!hci_dev_test_flag(hdev, HCI_MESH_EXPERIMENTAL))
|
||||
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_MESH_SEND,
|
||||
MGMT_STATUS_NOT_SUPPORTED);
|
||||
if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) ||
|
||||
len <= MGMT_MESH_SEND_SIZE ||
|
||||
len > (MGMT_MESH_SEND_SIZE + 31))
|
||||
if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
|
||||
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_MESH_SEND,
|
||||
MGMT_STATUS_REJECTED);
|
||||
|
||||
if (!send->adv_data_len || send->adv_data_len > 31)
|
||||
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_MESH_SEND,
|
||||
MGMT_STATUS_REJECTED);
|
||||
|
||||
expected_len = struct_size(send, adv_data, send->adv_data_len);
|
||||
if (expected_len != len)
|
||||
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_MESH_SEND,
|
||||
MGMT_STATUS_INVALID_PARAMS);
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
memset(&rp, 0, sizeof(rp));
|
||||
@@ -7248,6 +7256,9 @@ static bool ltk_is_valid(struct mgmt_ltk_info *key)
|
||||
if (key->initiator != 0x00 && key->initiator != 0x01)
|
||||
return false;
|
||||
|
||||
if (key->enc_size > sizeof(key->val))
|
||||
return false;
|
||||
|
||||
switch (key->addr.type) {
|
||||
case BDADDR_LE_PUBLIC:
|
||||
return true;
|
||||
|
||||
@@ -298,7 +298,7 @@ static int sco_chan_add(struct sco_conn *conn, struct sock *sk,
|
||||
int err = 0;
|
||||
|
||||
sco_conn_lock(conn);
|
||||
if (conn->sk)
|
||||
if (conn->sk || sco_pi(sk)->conn)
|
||||
err = -EBUSY;
|
||||
else
|
||||
__sco_chan_add(conn, sk, parent);
|
||||
@@ -353,9 +353,20 @@ static int sco_connect(struct sock *sk)
|
||||
|
||||
lock_sock(sk);
|
||||
|
||||
/* Recheck state after reacquiring the socket lock, as another
|
||||
* thread may have changed it (e.g., closed the socket).
|
||||
*/
|
||||
if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND) {
|
||||
release_sock(sk);
|
||||
hci_conn_drop(hcon);
|
||||
err = -EBADFD;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
err = sco_chan_add(conn, sk, NULL);
|
||||
if (err) {
|
||||
release_sock(sk);
|
||||
hci_conn_drop(hcon);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
@@ -656,13 +667,18 @@ static int sco_sock_connect(struct socket *sock, struct sockaddr_unsized *addr,
|
||||
addr->sa_family != AF_BLUETOOTH)
|
||||
return -EINVAL;
|
||||
|
||||
if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND)
|
||||
return -EBADFD;
|
||||
|
||||
if (sk->sk_type != SOCK_SEQPACKET)
|
||||
err = -EINVAL;
|
||||
|
||||
lock_sock(sk);
|
||||
|
||||
if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND) {
|
||||
release_sock(sk);
|
||||
return -EBADFD;
|
||||
}
|
||||
|
||||
if (sk->sk_type != SOCK_SEQPACKET) {
|
||||
release_sock(sk);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Set destination address and psm */
|
||||
bacpy(&sco_pi(sk)->dst, &sa->sco_bdaddr);
|
||||
release_sock(sk);
|
||||
|
||||
@@ -1018,10 +1018,7 @@ static u8 smp_random(struct smp_chan *smp)
|
||||
|
||||
smp_s1(smp->tk, smp->prnd, smp->rrnd, stk);
|
||||
|
||||
if (hcon->pending_sec_level == BT_SECURITY_HIGH)
|
||||
auth = 1;
|
||||
else
|
||||
auth = 0;
|
||||
auth = test_bit(SMP_FLAG_MITM_AUTH, &smp->flags) ? 1 : 0;
|
||||
|
||||
/* Even though there's no _RESPONDER suffix this is the
|
||||
* responder STK we're adding for later lookup (the initiator
|
||||
@@ -1826,7 +1823,7 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
if (sec_level > conn->hcon->pending_sec_level)
|
||||
conn->hcon->pending_sec_level = sec_level;
|
||||
|
||||
/* If we need MITM check that it can be achieved */
|
||||
/* If we need MITM check that it can be achieved. */
|
||||
if (conn->hcon->pending_sec_level >= BT_SECURITY_HIGH) {
|
||||
u8 method;
|
||||
|
||||
@@ -1834,6 +1831,10 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
req->io_capability);
|
||||
if (method == JUST_WORKS || method == JUST_CFM)
|
||||
return SMP_AUTH_REQUIREMENTS;
|
||||
|
||||
/* Force MITM bit if it isn't set by the initiator. */
|
||||
auth |= SMP_AUTH_MITM;
|
||||
rsp.auth_req |= SMP_AUTH_MITM;
|
||||
}
|
||||
|
||||
key_size = min(req->max_key_size, rsp.max_key_size);
|
||||
|
||||
Reference in New Issue
Block a user