Commit 8a48a2dc authored by David S. Miller's avatar David S. Miller

Merge tag 'for-net-next-2023-12-22' of...

Merge tag 'for-net-next-2023-12-22' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next

Luiz Augusto von Dentz says:

====================
bluetooth-next pull request for net-next:

 - btnxpuart: Fix recv_buf return value
 - L2CAP: Fix responding with multiple rejects
 - Fix atomicity violation in {min,max}_key_size_set
 - ISO: Allow binding a PA sync socket
 - ISO: Reassociate a socket with an active BIS
 - ISO: Avoid creating child socket if PA sync is terminating
 - Add device 13d3:3572 IMC Networks Bluetooth Radio
 - Don't suspend when there are connections
 - Remove le_restart_scan work
 - Fix bogus check for re-auth not supported with non-ssp
 - lib: Add documentation to exported functions
 - Support HFP offload for QCA2066
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 7df54188 da9065ca
......@@ -535,6 +535,8 @@ static int btintel_version_info_tlv(struct hci_dev *hdev,
bt_dev_info(hdev, "%s timestamp %u.%u buildtype %u build %u", variant,
2000 + (version->timestamp >> 8), version->timestamp & 0xff,
version->build_type, version->build_num);
if (version->img_type == 0x03)
bt_dev_info(hdev, "Firmware SHA1: 0x%8.8x", version->git_sha1);
return 0;
}
......@@ -630,6 +632,9 @@ static int btintel_parse_version_tlv(struct hci_dev *hdev,
memcpy(&version->otp_bd_addr, tlv->val,
sizeof(bdaddr_t));
break;
case INTEL_TLV_GIT_SHA1:
version->git_sha1 = get_unaligned_le32(tlv->val);
break;
default:
/* Ignore rest of information */
break;
......
......@@ -41,7 +41,8 @@ enum {
INTEL_TLV_LIMITED_CCE,
INTEL_TLV_SBE_TYPE,
INTEL_TLV_OTP_BDADDR,
INTEL_TLV_UNLOCKED_STATE
INTEL_TLV_UNLOCKED_STATE,
INTEL_TLV_GIT_SHA1
};
struct intel_tlv {
......@@ -69,6 +70,7 @@ struct intel_version_tlv {
u8 min_fw_build_yy;
u8 limited_cce;
u8 sbe_type;
u32 git_sha1;
bdaddr_t otp_bd_addr;
};
......
......@@ -336,7 +336,7 @@ mtk_stp_split(struct btmtkuart_dev *bdev, const unsigned char *data, int count,
return data;
}
static int btmtkuart_recv(struct hci_dev *hdev, const u8 *data, size_t count)
static void btmtkuart_recv(struct hci_dev *hdev, const u8 *data, size_t count)
{
struct btmtkuart_dev *bdev = hci_get_drvdata(hdev);
const unsigned char *p_left = data, *p_h4;
......@@ -375,25 +375,20 @@ static int btmtkuart_recv(struct hci_dev *hdev, const u8 *data, size_t count)
bt_dev_err(bdev->hdev,
"Frame reassembly failed (%d)", err);
bdev->rx_skb = NULL;
return err;
return;
}
sz_left -= sz_h4;
p_left += sz_h4;
}
return 0;
}
static int btmtkuart_receive_buf(struct serdev_device *serdev, const u8 *data,
size_t count)
{
struct btmtkuart_dev *bdev = serdev_device_get_drvdata(serdev);
int err;
err = btmtkuart_recv(bdev->hdev, data, count);
if (err < 0)
return err;
btmtkuart_recv(bdev->hdev, data, count);
bdev->hdev->stat.byte_rx += count;
......
......@@ -1276,11 +1276,9 @@ static int btnxpuart_receive_buf(struct serdev_device *serdev, const u8 *data,
if (IS_ERR(nxpdev->rx_skb)) {
int err = PTR_ERR(nxpdev->rx_skb);
/* Safe to ignore out-of-sync bootloader signatures */
if (is_fw_downloading(nxpdev))
return count;
bt_dev_err(nxpdev->hdev, "Frame reassembly failed (%d)", err);
nxpdev->rx_skb = NULL;
return err;
if (!is_fw_downloading(nxpdev))
bt_dev_err(nxpdev->hdev, "Frame reassembly failed (%d)", err);
return count;
}
if (!is_fw_downloading(nxpdev))
nxpdev->hdev->stat.byte_rx += count;
......
......@@ -550,6 +550,8 @@ static const struct usb_device_id quirks_table[] = {
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x13d3, 0x3571), .driver_info = BTUSB_REALTEK |
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x13d3, 0x3572), .driver_info = BTUSB_REALTEK |
BTUSB_WIDEBAND_SPEECH },
/* Realtek Bluetooth devices */
{ USB_VENDOR_AND_INTERFACE_INFO(0x0bda, 0xe0, 0x01, 0x01),
......@@ -4629,6 +4631,10 @@ static int btusb_suspend(struct usb_interface *intf, pm_message_t message)
BT_DBG("intf %p", intf);
/* Don't suspend if there are connections */
if (hci_conn_count(data->hdev))
return -EBUSY;
if (data->suspend_count++)
return 0;
......
......@@ -1815,6 +1815,24 @@ static void hci_coredump_qca(struct hci_dev *hdev)
kfree_skb(skb);
}
static int qca_get_data_path_id(struct hci_dev *hdev, __u8 *data_path_id)
{
/* QCA uses 1 as non-HCI data path id for HFP */
*data_path_id = 1;
return 0;
}
static int qca_configure_hfp_offload(struct hci_dev *hdev)
{
bt_dev_info(hdev, "HFP non-HCI data transport is supported");
hdev->get_data_path_id = qca_get_data_path_id;
/* Do not need to send HCI_Configure_Data_Path to configure non-HCI
* data transport path for QCA controllers, so set below field as NULL.
*/
hdev->get_codec_config_data = NULL;
return 0;
}
static int qca_setup(struct hci_uart *hu)
{
struct hci_dev *hdev = hu->hdev;
......@@ -1969,6 +1987,10 @@ static int qca_setup(struct hci_uart *hu)
hu->hdev->set_bdaddr = qca_set_bdaddr_rome;
else
hu->hdev->set_bdaddr = qca_set_bdaddr;
if (soc_type == QCA_QCA2066)
qca_configure_hfp_offload(hdev);
qca->fw_version = le16_to_cpu(ver.patch_ver);
qca->controller_id = le16_to_cpu(ver.rom_ver);
hci_devcd_register(hdev, hci_coredump_qca, qca_dmp_hdr, NULL);
......@@ -2039,6 +2061,7 @@ static const struct qca_device_data qca_soc_data_wcn3998 __maybe_unused = {
static const struct qca_device_data qca_soc_data_qca2066 __maybe_unused = {
.soc_type = QCA_QCA2066,
.num_vregs = 0,
.capabilities = QCA_CAP_WIDEBAND_SPEECH | QCA_CAP_VALID_LE_STATES,
};
static const struct qca_device_data qca_soc_data_qca6390 __maybe_unused = {
......
......@@ -539,7 +539,6 @@ struct hci_dev {
struct work_struct tx_work;
struct delayed_work le_scan_disable;
struct delayed_work le_scan_restart;
struct sk_buff_head rx_q;
struct sk_buff_head raw_q;
......@@ -957,7 +956,6 @@ void hci_inquiry_cache_flush(struct hci_dev *hdev);
/* ----- HCI Connections ----- */
enum {
HCI_CONN_AUTH_PEND,
HCI_CONN_REAUTH_PEND,
HCI_CONN_ENCRYPT_PEND,
HCI_CONN_RSWITCH_PEND,
HCI_CONN_MODE_CHANGE_PEND,
......@@ -1297,6 +1295,30 @@ static inline struct hci_conn *hci_conn_hash_lookup_big(struct hci_dev *hdev,
return NULL;
}
static inline struct hci_conn *
hci_conn_hash_lookup_big_state(struct hci_dev *hdev, __u8 handle, __u16 state)
{
struct hci_conn_hash *h = &hdev->conn_hash;
struct hci_conn *c;
rcu_read_lock();
list_for_each_entry_rcu(c, &h->list, list) {
if (bacmp(&c->dst, BDADDR_ANY) || c->type != ISO_LINK ||
c->state != state)
continue;
if (handle == c->iso_qos.bcast.big) {
rcu_read_unlock();
return c;
}
}
rcu_read_unlock();
return NULL;
}
static inline struct hci_conn *
hci_conn_hash_lookup_pa_sync_big_handle(struct hci_dev *hdev, __u8 big)
{
......
......@@ -300,6 +300,13 @@ static int configure_datapath_sync(struct hci_dev *hdev, struct bt_codec *codec)
__u8 vnd_len, *vnd_data = NULL;
struct hci_op_configure_data_path *cmd = NULL;
if (!codec->data_path || !hdev->get_codec_config_data)
return 0;
/* Do not take me as error */
if (!hdev->get_codec_config_data)
return 0;
err = hdev->get_codec_config_data(hdev, ESCO_LINK, codec, &vnd_len,
&vnd_data);
if (err < 0)
......@@ -345,9 +352,7 @@ static int hci_enhanced_setup_sync(struct hci_dev *hdev, void *data)
bt_dev_dbg(hdev, "hcon %p", conn);
/* for offload use case, codec needs to configured before opening SCO */
if (conn->codec.data_path)
configure_datapath_sync(hdev, &conn->codec);
configure_datapath_sync(hdev, &conn->codec);
conn->state = BT_CONNECT;
conn->out = true;
......@@ -1086,8 +1091,9 @@ static void hci_conn_cleanup_child(struct hci_conn *conn, u8 reason)
hci_conn_failed(conn, reason);
break;
case ISO_LINK:
if (conn->state != BT_CONNECTED &&
!test_bit(HCI_CONN_CREATE_CIS, &conn->flags))
if ((conn->state != BT_CONNECTED &&
!test_bit(HCI_CONN_CREATE_CIS, &conn->flags)) ||
test_bit(HCI_CONN_BIG_CREATED, &conn->flags))
hci_conn_failed(conn, reason);
break;
}
......@@ -2228,7 +2234,17 @@ struct hci_conn *hci_bind_bis(struct hci_dev *hdev, bdaddr_t *dst,
__u8 base_len, __u8 *base)
{
struct hci_conn *conn;
struct hci_conn *parent;
__u8 eir[HCI_MAX_PER_AD_LENGTH];
struct hci_link *link;
/* Look for any BIS that is open for rebinding */
conn = hci_conn_hash_lookup_big_state(hdev, qos->bcast.big, BT_OPEN);
if (conn) {
memcpy(qos, &conn->iso_qos, sizeof(*qos));
conn->state = BT_CONNECTED;
return conn;
}
if (base_len && base)
base_len = eir_append_service_data(eir, 0, 0x1851,
......@@ -2256,6 +2272,20 @@ struct hci_conn *hci_bind_bis(struct hci_dev *hdev, bdaddr_t *dst,
conn->iso_qos = *qos;
conn->state = BT_BOUND;
/* Link BISes together */
parent = hci_conn_hash_lookup_big(hdev,
conn->iso_qos.bcast.big);
if (parent && parent != conn) {
link = hci_conn_link(parent, conn);
if (!link) {
hci_conn_drop(conn);
return ERR_PTR(-ENOLINK);
}
/* Link takes the refcount */
hci_conn_drop(conn);
}
return conn;
}
......@@ -2287,6 +2317,9 @@ struct hci_conn *hci_connect_bis(struct hci_dev *hdev, bdaddr_t *dst,
if (IS_ERR(conn))
return conn;
if (conn->state == BT_CONNECTED)
return conn;
data.big = qos->bcast.big;
data.bis = qos->bcast.bis;
......@@ -2421,12 +2454,10 @@ static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED,
sizeof(cp), &cp);
/* If we're already encrypted set the REAUTH_PEND flag,
* otherwise set the ENCRYPT_PEND.
/* Set the ENCRYPT_PEND to trigger encryption after
* authentication.
*/
if (test_bit(HCI_CONN_ENCRYPT, &conn->flags))
set_bit(HCI_CONN_REAUTH_PEND, &conn->flags);
else
if (!test_bit(HCI_CONN_ENCRYPT, &conn->flags))
set_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags);
}
......
......@@ -1046,10 +1046,12 @@ static int min_key_size_set(void *data, u64 val)
{
struct hci_dev *hdev = data;
if (val > hdev->le_max_key_size || val < SMP_MIN_ENC_KEY_SIZE)
hci_dev_lock(hdev);
if (val > hdev->le_max_key_size || val < SMP_MIN_ENC_KEY_SIZE) {
hci_dev_unlock(hdev);
return -EINVAL;
}
hci_dev_lock(hdev);
hdev->le_min_key_size = val;
hci_dev_unlock(hdev);
......@@ -1074,10 +1076,12 @@ static int max_key_size_set(void *data, u64 val)
{
struct hci_dev *hdev = data;
if (val > SMP_MAX_ENC_KEY_SIZE || val < hdev->le_min_key_size)
hci_dev_lock(hdev);
if (val > SMP_MAX_ENC_KEY_SIZE || val < hdev->le_min_key_size) {
hci_dev_unlock(hdev);
return -EINVAL;
}
hci_dev_lock(hdev);
hdev->le_max_key_size = val;
hci_dev_unlock(hdev);
......
......@@ -3500,14 +3500,8 @@ static void hci_auth_complete_evt(struct hci_dev *hdev, void *data,
if (!ev->status) {
clear_bit(HCI_CONN_AUTH_FAILURE, &conn->flags);
if (!hci_conn_ssp_enabled(conn) &&
test_bit(HCI_CONN_REAUTH_PEND, &conn->flags)) {
bt_dev_info(hdev, "re-auth of legacy device is not possible.");
} else {
set_bit(HCI_CONN_AUTH, &conn->flags);
conn->sec_level = conn->pending_sec_level;
}
set_bit(HCI_CONN_AUTH, &conn->flags);
conn->sec_level = conn->pending_sec_level;
} else {
if (ev->status == HCI_ERROR_PIN_OR_KEY_MISSING)
set_bit(HCI_CONN_AUTH_FAILURE, &conn->flags);
......@@ -3516,7 +3510,6 @@ static void hci_auth_complete_evt(struct hci_dev *hdev, void *data,
}
clear_bit(HCI_CONN_AUTH_PEND, &conn->flags);
clear_bit(HCI_CONN_REAUTH_PEND, &conn->flags);
if (conn->state == BT_CONFIG) {
if (!ev->status && hci_conn_ssp_enabled(conn)) {
......
......@@ -348,8 +348,6 @@ static void le_scan_disable(struct work_struct *work)
if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
goto _return;
cancel_delayed_work(&hdev->le_scan_restart);
status = hci_cmd_sync_queue(hdev, scan_disable_sync, NULL, NULL);
if (status) {
bt_dev_err(hdev, "failed to disable LE scan: %d", status);
......@@ -397,71 +395,6 @@ static void le_scan_disable(struct work_struct *work)
static int hci_le_set_scan_enable_sync(struct hci_dev *hdev, u8 val,
u8 filter_dup);
static int hci_le_scan_restart_sync(struct hci_dev *hdev)
{
/* If controller is not scanning we are done. */
if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
return 0;
if (hdev->scanning_paused) {
bt_dev_dbg(hdev, "Scanning is paused for suspend");
return 0;
}
hci_le_set_scan_enable_sync(hdev, LE_SCAN_DISABLE, 0x00);
return hci_le_set_scan_enable_sync(hdev, LE_SCAN_ENABLE,
LE_SCAN_FILTER_DUP_ENABLE);
}
static void le_scan_restart(struct work_struct *work)
{
struct hci_dev *hdev = container_of(work, struct hci_dev,
le_scan_restart.work);
unsigned long timeout, duration, scan_start, now;
int status;
bt_dev_dbg(hdev, "");
status = hci_le_scan_restart_sync(hdev);
if (status) {
bt_dev_err(hdev, "failed to restart LE scan: status %d",
status);
return;
}
hci_dev_lock(hdev);
if (!test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks) ||
!hdev->discovery.scan_start)
goto unlock;
/* When the scan was started, hdev->le_scan_disable has been queued
* after duration from scan_start. During scan restart this job
* has been canceled, and we need to queue it again after proper
* timeout, to make sure that scan does not run indefinitely.
*/
duration = hdev->discovery.scan_duration;
scan_start = hdev->discovery.scan_start;
now = jiffies;
if (now - scan_start <= duration) {
int elapsed;
if (now >= scan_start)
elapsed = now - scan_start;
else
elapsed = ULONG_MAX - scan_start + now;
timeout = duration - elapsed;
} else {
timeout = 0;
}
queue_delayed_work(hdev->req_workqueue,
&hdev->le_scan_disable, timeout);
unlock:
hci_dev_unlock(hdev);
}
static int reenable_adv_sync(struct hci_dev *hdev, void *data)
{
......@@ -630,7 +563,6 @@ void hci_cmd_sync_init(struct hci_dev *hdev)
INIT_WORK(&hdev->cmd_sync_cancel_work, hci_cmd_sync_cancel_work);
INIT_WORK(&hdev->reenable_adv_work, reenable_adv);
INIT_DELAYED_WORK(&hdev->le_scan_disable, le_scan_disable);
INIT_DELAYED_WORK(&hdev->le_scan_restart, le_scan_restart);
INIT_DELAYED_WORK(&hdev->adv_instance_expire, adv_timeout_expire);
}
......@@ -3800,12 +3732,14 @@ static int hci_set_event_mask_sync(struct hci_dev *hdev)
if (lmp_bredr_capable(hdev)) {
events[4] |= 0x01; /* Flow Specification Complete */
/* Don't set Disconnect Complete when suspended as that
* would wakeup the host when disconnecting due to
* suspend.
/* Don't set Disconnect Complete and mode change when
* suspended as that would wakeup the host when disconnecting
* due to suspend.
*/
if (hdev->suspended)
if (hdev->suspended) {
events[0] &= 0xef;
events[2] &= 0xf7;
}
} else {
/* Use a different default for LE-only devices */
memset(events, 0, sizeof(events));
......@@ -4960,7 +4894,6 @@ int hci_dev_close_sync(struct hci_dev *hdev)
cancel_delayed_work(&hdev->power_off);
cancel_delayed_work(&hdev->ncmd_timer);
cancel_delayed_work(&hdev->le_scan_disable);
cancel_delayed_work(&hdev->le_scan_restart);
hci_request_cancel_all(hdev);
......@@ -5178,7 +5111,6 @@ int hci_stop_discovery_sync(struct hci_dev *hdev)
if (hci_dev_test_flag(hdev, HCI_LE_SCAN)) {
cancel_delayed_work(&hdev->le_scan_disable);
cancel_delayed_work(&hdev->le_scan_restart);
err = hci_scan_disable_sync(hdev);
if (err)
......@@ -5686,19 +5618,18 @@ static int hci_active_scan_sync(struct hci_dev *hdev, uint16_t interval)
if (err < 0)
own_addr_type = ADDR_LE_DEV_PUBLIC;
if (hci_is_adv_monitoring(hdev)) {
if (hci_is_adv_monitoring(hdev) ||
(test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks) &&
hdev->discovery.result_filtering)) {
/* Duplicate filter should be disabled when some advertisement
* monitor is activated, otherwise AdvMon can only receive one
* advertisement for one peer(*) during active scanning, and
* might report loss to these peers.
*
* Note that different controllers have different meanings of
* |duplicate|. Some of them consider packets with the same
* address as duplicate, and others consider packets with the
* same address and the same RSSI as duplicate. Although in the
* latter case we don't need to disable duplicate filter, but
* it is common to have active scanning for a short period of
* time, the power impact should be neglectable.
* If controller does strict duplicate filtering and the
* discovery requires result filtering disables controller based
* filtering since that can cause reports that would match the
* host filter to not be reported.
*/
filter_dup = LE_SCAN_FILTER_DUP_DISABLE;
}
......@@ -5778,17 +5709,6 @@ int hci_start_discovery_sync(struct hci_dev *hdev)
bt_dev_dbg(hdev, "timeout %u ms", jiffies_to_msecs(timeout));
/* When service discovery is used and the controller has a
* strict duplicate filter, it is important to remember the
* start and duration of the scan. This is required for
* restarting scanning during the discovery phase.
*/
if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks) &&
hdev->discovery.result_filtering) {
hdev->discovery.scan_start = jiffies;
hdev->discovery.scan_duration = timeout;
}
queue_delayed_work(hdev->req_workqueue, &hdev->le_scan_disable,
timeout);
return 0;
......
......@@ -54,6 +54,7 @@ static void iso_sock_kill(struct sock *sk);
enum {
BT_SK_BIG_SYNC,
BT_SK_PA_SYNC,
BT_SK_PA_SYNC_TERM,
};
struct iso_pinfo {
......@@ -82,6 +83,11 @@ static bool iso_match_sid(struct sock *sk, void *data);
static bool iso_match_sync_handle(struct sock *sk, void *data);
static void iso_sock_disconn(struct sock *sk);
typedef bool (*iso_sock_match_t)(struct sock *sk, void *data);
static struct sock *iso_get_sock_listen(bdaddr_t *src, bdaddr_t *dst,
iso_sock_match_t match, void *data);
/* ---- ISO timers ---- */
#define ISO_CONN_TIMEOUT (HZ * 40)
#define ISO_DISCONN_TIMEOUT (HZ * 2)
......@@ -190,10 +196,21 @@ static void iso_chan_del(struct sock *sk, int err)
sock_set_flag(sk, SOCK_ZAPPED);
}
static bool iso_match_conn_sync_handle(struct sock *sk, void *data)
{
struct hci_conn *hcon = data;
if (test_bit(BT_SK_PA_SYNC, &iso_pi(sk)->flags))
return false;
return hcon->sync_handle == iso_pi(sk)->sync_handle;
}
static void iso_conn_del(struct hci_conn *hcon, int err)
{
struct iso_conn *conn = hcon->iso_data;
struct sock *sk;
struct sock *parent;
if (!conn)
return;
......@@ -209,6 +226,25 @@ static void iso_conn_del(struct hci_conn *hcon, int err)
if (sk) {
lock_sock(sk);
/* While a PA sync hcon is in the process of closing,
* mark parent socket with a flag, so that any residual
* BIGInfo adv reports that arrive before PA sync is
* terminated are not processed anymore.
*/
if (test_bit(BT_SK_PA_SYNC, &iso_pi(sk)->flags)) {
parent = iso_get_sock_listen(&hcon->src,
&hcon->dst,
iso_match_conn_sync_handle,
hcon);
if (parent) {
set_bit(BT_SK_PA_SYNC_TERM,
&iso_pi(parent)->flags);
sock_put(parent);
}
}
iso_sock_clear_timer(sk);
iso_chan_del(sk, err);
release_sock(sk);
......@@ -545,8 +581,6 @@ static struct sock *__iso_get_sock_listen_by_sid(bdaddr_t *ba, bdaddr_t *bc,
return NULL;
}
typedef bool (*iso_sock_match_t)(struct sock *sk, void *data);
/* Find socket listening:
* source bdaddr (Unicast)
* destination bdaddr (Broadcast only)
......@@ -574,19 +608,68 @@ static struct sock *iso_get_sock_listen(bdaddr_t *src, bdaddr_t *dst,
continue;
/* Exact match. */
if (!bacmp(&iso_pi(sk)->src, src))
if (!bacmp(&iso_pi(sk)->src, src)) {
sock_hold(sk);
break;
}
/* Closest match */
if (!bacmp(&iso_pi(sk)->src, BDADDR_ANY))
if (!bacmp(&iso_pi(sk)->src, BDADDR_ANY)) {
if (sk1)
sock_put(sk1);
sk1 = sk;
sock_hold(sk1);
}
}
if (sk && sk1)
sock_put(sk1);
read_unlock(&iso_sk_list.lock);
return sk ? sk : sk1;
}
static struct sock *iso_get_sock_big(struct sock *match_sk, bdaddr_t *src,
bdaddr_t *dst, uint8_t big)
{
struct sock *sk = NULL;
read_lock(&iso_sk_list.lock);
sk_for_each(sk, &iso_sk_list.head) {
if (match_sk == sk)
continue;
/* Look for sockets that have already been
* connected to the BIG
*/
if (sk->sk_state != BT_CONNECTED &&
sk->sk_state != BT_CONNECT)
continue;
/* Match Broadcast destination */
if (bacmp(&iso_pi(sk)->dst, dst))
continue;
/* Match BIG handle */
if (iso_pi(sk)->qos.bcast.big != big)
continue;
/* Match source address */
if (bacmp(&iso_pi(sk)->src, src))
continue;
sock_hold(sk);
break;
}
read_unlock(&iso_sk_list.lock);
return sk;
}
static void iso_sock_destruct(struct sock *sk)
{
BT_DBG("sk %p", sk);
......@@ -639,6 +722,28 @@ static void iso_sock_kill(struct sock *sk)
static void iso_sock_disconn(struct sock *sk)
{
struct sock *bis_sk;
struct hci_conn *hcon = iso_pi(sk)->conn->hcon;
if (test_bit(HCI_CONN_BIG_CREATED, &hcon->flags)) {
bis_sk = iso_get_sock_big(sk, &iso_pi(sk)->src,
&iso_pi(sk)->dst,
iso_pi(sk)->qos.bcast.big);
/* If there are any other connected sockets for the
* same BIG, just delete the sk and leave the bis
* hcon active, in case later rebinding is needed.
*/
if (bis_sk) {
hcon->state = BT_OPEN;
iso_pi(sk)->conn->hcon = NULL;
iso_sock_clear_timer(sk);
iso_chan_del(sk, bt_to_errno(hcon->abort_reason));
sock_put(bis_sk);
return;
}
}
sk->sk_state = BT_DISCONN;
iso_sock_set_timer(sk, ISO_DISCONN_TIMEOUT);
iso_conn_lock(iso_pi(sk)->conn);
......@@ -792,27 +897,75 @@ static int iso_sock_bind_bc(struct socket *sock, struct sockaddr *addr,
BT_DBG("sk %p bc_sid %u bc_num_bis %u", sk, sa->iso_bc->bc_sid,
sa->iso_bc->bc_num_bis);
if (addr_len > sizeof(*sa) + sizeof(*sa->iso_bc))
if (addr_len != sizeof(*sa) + sizeof(*sa->iso_bc))
return -EINVAL;
bacpy(&iso_pi(sk)->dst, &sa->iso_bc->bc_bdaddr);
/* Check if the address type is of LE type */
if (!bdaddr_type_is_le(sa->iso_bc->bc_bdaddr_type))
return -EINVAL;
iso_pi(sk)->dst_type = sa->iso_bc->bc_bdaddr_type;
iso_pi(sk)->sync_handle = -1;
if (sa->iso_bc->bc_sid > 0x0f)
return -EINVAL;
iso_pi(sk)->bc_sid = sa->iso_bc->bc_sid;
if (sa->iso_bc->bc_num_bis > ISO_MAX_NUM_BIS)
return -EINVAL;
iso_pi(sk)->bc_num_bis = sa->iso_bc->bc_num_bis;
for (i = 0; i < iso_pi(sk)->bc_num_bis; i++) {
for (i = 0; i < iso_pi(sk)->bc_num_bis; i++)
if (sa->iso_bc->bc_bis[i] < 0x01 ||
sa->iso_bc->bc_bis[i] > 0x1f)
return -EINVAL;
memcpy(iso_pi(sk)->bc_bis, sa->iso_bc->bc_bis,
iso_pi(sk)->bc_num_bis);
}
memcpy(iso_pi(sk)->bc_bis, sa->iso_bc->bc_bis,
iso_pi(sk)->bc_num_bis);
return 0;
}
static int iso_sock_bind_pa_sk(struct sock *sk, struct sockaddr_iso *sa,
int addr_len)
{
int err = 0;
if (sk->sk_type != SOCK_SEQPACKET) {
err = -EINVAL;
goto done;
}
if (addr_len != sizeof(*sa) + sizeof(*sa->iso_bc)) {
err = -EINVAL;
goto done;
}
if (sa->iso_bc->bc_num_bis > ISO_MAX_NUM_BIS) {
err = -EINVAL;
goto done;
}
iso_pi(sk)->bc_num_bis = sa->iso_bc->bc_num_bis;
for (int i = 0; i < iso_pi(sk)->bc_num_bis; i++)
if (sa->iso_bc->bc_bis[i] < 0x01 ||
sa->iso_bc->bc_bis[i] > 0x1f) {
err = -EINVAL;
goto done;
}
memcpy(iso_pi(sk)->bc_bis, sa->iso_bc->bc_bis,
iso_pi(sk)->bc_num_bis);
done:
return err;
}
static int iso_sock_bind(struct socket *sock, struct sockaddr *addr,
int addr_len)
{
......@@ -828,6 +981,15 @@ static int iso_sock_bind(struct socket *sock, struct sockaddr *addr,
lock_sock(sk);
/* Allow the user to bind a PA sync socket to a number
* of BISes to sync to.
*/
if (sk->sk_state == BT_CONNECT2 &&
test_bit(BT_SK_PA_SYNC, &iso_pi(sk)->flags)) {
err = iso_sock_bind_pa_sk(sk, sa, addr_len);
goto done;
}
if (sk->sk_state != BT_OPEN) {
err = -EBADFD;
goto done;
......@@ -1694,6 +1856,7 @@ static void iso_conn_ready(struct iso_conn *conn)
parent->sk_data_ready(parent);
release_sock(parent);
sock_put(parent);
}
}
......@@ -1759,9 +1922,20 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)
/* Try to get PA sync listening socket, if it exists */
sk = iso_get_sock_listen(&hdev->bdaddr, bdaddr,
iso_match_pa_sync_flag, NULL);
if (!sk)
if (!sk) {
sk = iso_get_sock_listen(&hdev->bdaddr, bdaddr,
iso_match_sync_handle, ev2);
/* If PA Sync is in process of terminating,
* do not handle any more BIGInfo adv reports.
*/
if (sk && test_bit(BT_SK_PA_SYNC_TERM,
&iso_pi(sk)->flags))
return lm;
}
if (sk) {
int err;
......@@ -1778,6 +1952,7 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)
if (err) {
bt_dev_err(hdev, "hci_le_big_create_sync: %d",
err);
sock_put(sk);
sk = NULL;
}
}
......@@ -1810,6 +1985,8 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)
if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags))
*flags |= HCI_PROTO_DEFER;
sock_put(sk);
return lm;
}
......
......@@ -6526,7 +6526,8 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn,
if (len > skb->len || !cmd->ident) {
BT_DBG("corrupted command");
l2cap_sig_send_rej(conn, cmd->ident);
break;
skb_pull(skb, len > skb->len ? skb->len : len);
continue;
}
err = l2cap_bredr_sig_cmd(conn, cmd, len, skb->data);
......
......@@ -30,6 +30,15 @@
#include <net/bluetooth/bluetooth.h>
/**
* baswap() - Swaps the order of a bd address
* @dst: Pointer to a bdaddr_t struct that will store the swapped
* bd address.
* @src: Pointer to the bdaddr_t struct to be swapped.
*
* This function reverses the byte order of a Bluetooth device
* address.
*/
void baswap(bdaddr_t *dst, const bdaddr_t *src)
{
const unsigned char *s = (const unsigned char *)src;
......@@ -41,7 +50,19 @@ void baswap(bdaddr_t *dst, const bdaddr_t *src)
}
EXPORT_SYMBOL(baswap);
/* Bluetooth error codes to Unix errno mapping */
/**
* bt_to_errno() - Bluetooth error codes to standard errno
* @code: Bluetooth error code to be converted
*
* This function takes a Bluetooth error code as input and convets
* it to an equivalent Unix/standard errno value.
*
* Return:
*
* If the bt error code is known, an equivalent Unix errno value
* is returned.
* If the given bt error code is not known, ENOSYS is returned.
*/
int bt_to_errno(__u16 code)
{
switch (code) {
......@@ -135,10 +156,22 @@ int bt_to_errno(__u16 code)
}
EXPORT_SYMBOL(bt_to_errno);
/* Unix errno to Bluetooth error codes mapping */
/**
* bt_status() - Standard errno value to Bluetooth error code
* @err: Unix/standard errno value to be converted
*
* This function converts a standard/Unix errno value to an
* equivalent Bluetooth error code.
*
* Return: Bluetooth error code.
*
* If the given errno is not found, 0x1f is returned by default
* which indicates an unspecified error.
* For err >= 0, no conversion is performed, and the same value
* is immediately returned.
*/
__u8 bt_status(int err)
{
/* Don't convert if already positive value */
if (err >= 0)
return err;
......@@ -206,6 +239,10 @@ __u8 bt_status(int err)
}
EXPORT_SYMBOL(bt_status);
/**
* bt_info() - Log Bluetooth information message
* @format: Message's format string
*/
void bt_info(const char *format, ...)
{
struct va_format vaf;
......@@ -222,6 +259,10 @@ void bt_info(const char *format, ...)
}
EXPORT_SYMBOL(bt_info);
/**
* bt_warn() - Log Bluetooth warning message
* @format: Message's format string
*/
void bt_warn(const char *format, ...)
{
struct va_format vaf;
......@@ -238,6 +279,10 @@ void bt_warn(const char *format, ...)
}
EXPORT_SYMBOL(bt_warn);
/**
* bt_err() - Log Bluetooth error message
* @format: Message's format string
*/
void bt_err(const char *format, ...)
{
struct va_format vaf;
......@@ -267,6 +312,10 @@ bool bt_dbg_get(void)
return debug_enable;
}
/**
* bt_dbg() - Log Bluetooth debugging message
* @format: Message's format string
*/
void bt_dbg(const char *format, ...)
{
struct va_format vaf;
......@@ -287,6 +336,13 @@ void bt_dbg(const char *format, ...)
EXPORT_SYMBOL(bt_dbg);
#endif
/**
* bt_warn_ratelimited() - Log rate-limited Bluetooth warning message
* @format: Message's format string
*
* This functions works like bt_warn, but it uses rate limiting
* to prevent the message from being logged too often.
*/
void bt_warn_ratelimited(const char *format, ...)
{
struct va_format vaf;
......@@ -303,6 +359,13 @@ void bt_warn_ratelimited(const char *format, ...)
}
EXPORT_SYMBOL(bt_warn_ratelimited);
/**
* bt_err_ratelimited() - Log rate-limited Bluetooth error message
* @format: Message's format string
*
* This functions works like bt_err, but it uses rate limiting
* to prevent the message from being logged too often.
*/
void bt_err_ratelimited(const char *format, ...)
{
struct va_format vaf;
......
......@@ -10145,21 +10145,6 @@ static bool eir_has_uuids(u8 *eir, u16 eir_len, u16 uuid_count, u8 (*uuids)[16])
return false;
}
static void restart_le_scan(struct hci_dev *hdev)
{
/* If controller is not scanning we are done. */
if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
return;
if (time_after(jiffies + DISCOV_LE_RESTART_DELAY,
hdev->discovery.scan_start +
hdev->discovery.scan_duration))
return;
queue_delayed_work(hdev->req_workqueue, &hdev->le_scan_restart,
DISCOV_LE_RESTART_DELAY);
}
static bool is_filter_match(struct hci_dev *hdev, s8 rssi, u8 *eir,
u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
{
......@@ -10194,8 +10179,6 @@ static bool is_filter_match(struct hci_dev *hdev, s8 rssi, u8 *eir,
* scanning to ensure updated result with updated RSSI values.
*/
if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks)) {
restart_le_scan(hdev);
/* Validate RSSI value against the RSSI threshold once more. */
if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
rssi < hdev->discovery.rssi)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment