Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next
Johan Hedberg says: ==================== pull request: bluetooth-next 2018-09-30 Here's the first bluetooth-next pull request for the 4.20 kernel. - Fixes & cleanups to hci_qca driver - NULL dereference fix to debugfs - Improved L2CAP Connection-oriented Channel MTU & MPS handling - Added support for USB-based RTL8822C controller - Added device ID for BCM4335C0 UART-based controller - Various other smaller cleanups & fixes Please let me know if there are any issues pulling. Thanks. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Коммит
00538ba915
|
@ -203,10 +203,11 @@ static const struct usb_device_id ath3k_blist_tbl[] = {
|
|||
{ } /* Terminating entry */
|
||||
};
|
||||
|
||||
static inline void ath3k_log_failed_loading(int err, int len, int size)
|
||||
static inline void ath3k_log_failed_loading(int err, int len, int size,
|
||||
int count)
|
||||
{
|
||||
BT_ERR("Error in firmware loading err = %d, len = %d, size = %d",
|
||||
err, len, size);
|
||||
BT_ERR("Firmware loading err = %d, len = %d, size = %d, count = %d",
|
||||
err, len, size, count);
|
||||
}
|
||||
|
||||
#define USB_REQ_DFU_DNLOAD 1
|
||||
|
@ -257,7 +258,7 @@ static int ath3k_load_firmware(struct usb_device *udev,
|
|||
&len, 3000);
|
||||
|
||||
if (err || (len != size)) {
|
||||
ath3k_log_failed_loading(err, len, size);
|
||||
ath3k_log_failed_loading(err, len, size, count);
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
@ -356,7 +357,7 @@ static int ath3k_load_fwfile(struct usb_device *udev,
|
|||
err = usb_bulk_msg(udev, pipe, send_buf, size,
|
||||
&len, 3000);
|
||||
if (err || (len != size)) {
|
||||
ath3k_log_failed_loading(err, len, size);
|
||||
ath3k_log_failed_loading(err, len, size, count);
|
||||
kfree(send_buf);
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -448,7 +448,7 @@ static int bt3c_load_firmware(struct bt3c_info *info,
|
|||
{
|
||||
char *ptr = (char *) firmware;
|
||||
char b[9];
|
||||
unsigned int iobase, tmp;
|
||||
unsigned int iobase, tmp, tn;
|
||||
unsigned long size, addr, fcs;
|
||||
int i, err = 0;
|
||||
|
||||
|
@ -490,7 +490,9 @@ static int bt3c_load_firmware(struct bt3c_info *info,
|
|||
memset(b, 0, sizeof(b));
|
||||
for (tmp = 0, i = 0; i < size; i++) {
|
||||
memcpy(b, ptr + (i * 2) + 2, 2);
|
||||
tmp += simple_strtol(b, NULL, 16);
|
||||
if (kstrtouint(b, 16, &tn))
|
||||
return -EINVAL;
|
||||
tmp += tn;
|
||||
}
|
||||
|
||||
if (((tmp + fcs) & 0xff) != 0xff) {
|
||||
|
@ -505,7 +507,8 @@ static int bt3c_load_firmware(struct bt3c_info *info,
|
|||
memset(b, 0, sizeof(b));
|
||||
for (i = 0; i < (size - 4) / 2; i++) {
|
||||
memcpy(b, ptr + (i * 4) + 12, 4);
|
||||
tmp = simple_strtoul(b, NULL, 16);
|
||||
if (kstrtouint(b, 16, &tmp))
|
||||
return -EINVAL;
|
||||
bt3c_put(iobase, tmp);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -324,6 +324,7 @@ static const struct bcm_subver_table bcm_uart_subver_table[] = {
|
|||
{ 0x4103, "BCM4330B1" }, /* 002.001.003 */
|
||||
{ 0x410e, "BCM43341B0" }, /* 002.001.014 */
|
||||
{ 0x4406, "BCM4324B3" }, /* 002.004.006 */
|
||||
{ 0x6109, "BCM4335C0" }, /* 003.001.009 */
|
||||
{ 0x610c, "BCM4354" }, /* 003.001.012 */
|
||||
{ 0x2122, "BCM4343A0" }, /* 001.001.034 */
|
||||
{ 0x2209, "BCM43430A1" }, /* 001.002.009 */
|
||||
|
|
|
@ -21,8 +21,9 @@
|
|||
#include <net/rsi_91x.h>
|
||||
#include <net/genetlink.h>
|
||||
|
||||
#define RSI_HEADROOM_FOR_BT_HAL 16
|
||||
#define RSI_DMA_ALIGN 8
|
||||
#define RSI_FRAME_DESC_SIZE 16
|
||||
#define RSI_HEADROOM_FOR_BT_HAL (RSI_FRAME_DESC_SIZE + RSI_DMA_ALIGN)
|
||||
|
||||
struct rsi_hci_adapter {
|
||||
void *priv;
|
||||
|
@ -70,6 +71,16 @@ static int rsi_hci_send_pkt(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
bt_cb(new_skb)->pkt_type = hci_skb_pkt_type(skb);
|
||||
kfree_skb(skb);
|
||||
skb = new_skb;
|
||||
if (!IS_ALIGNED((unsigned long)skb->data, RSI_DMA_ALIGN)) {
|
||||
u8 *skb_data = skb->data;
|
||||
int skb_len = skb->len;
|
||||
|
||||
skb_push(skb, RSI_DMA_ALIGN);
|
||||
skb_pull(skb, PTR_ALIGN(skb->data,
|
||||
RSI_DMA_ALIGN) - skb->data);
|
||||
memmove(skb->data, skb_data, skb_len);
|
||||
skb_trim(skb, skb_len);
|
||||
}
|
||||
}
|
||||
|
||||
return h_adapter->proto_ops->coex_send_pkt(h_adapter->priv, skb,
|
||||
|
|
|
@ -138,6 +138,13 @@ static const struct id_table ic_id_table[] = {
|
|||
.fw_name = "rtl_bt/rtl8761a_fw.bin",
|
||||
.cfg_name = "rtl_bt/rtl8761a_config" },
|
||||
|
||||
/* 8822C with USB interface */
|
||||
{ IC_INFO(RTL_ROM_LMP_8822B, 0xc),
|
||||
.config_needed = false,
|
||||
.has_rom_version = true,
|
||||
.fw_name = "rtl_bt/rtl8822cu_fw.bin",
|
||||
.cfg_name = "rtl_bt/rtl8822cu_config" },
|
||||
|
||||
/* 8822B */
|
||||
{ IC_INFO(RTL_ROM_LMP_8822B, 0xb),
|
||||
.config_needed = true,
|
||||
|
@ -206,7 +213,7 @@ static int rtlbt_parse_firmware(struct hci_dev *hdev,
|
|||
struct btrtl_device_info *btrtl_dev,
|
||||
unsigned char **_buf)
|
||||
{
|
||||
const u8 extension_sig[] = { 0x51, 0x04, 0xfd, 0x77 };
|
||||
static const u8 extension_sig[] = { 0x51, 0x04, 0xfd, 0x77 };
|
||||
struct rtl_epatch_header *epatch_info;
|
||||
unsigned char *buf;
|
||||
int i, len;
|
||||
|
@ -228,6 +235,7 @@ static int rtlbt_parse_firmware(struct hci_dev *hdev,
|
|||
{ RTL_ROM_LMP_8822B, 8 },
|
||||
{ RTL_ROM_LMP_8723B, 9 }, /* 8723D */
|
||||
{ RTL_ROM_LMP_8821A, 10 }, /* 8821C */
|
||||
{ RTL_ROM_LMP_8822B, 13 }, /* 8822C */
|
||||
};
|
||||
|
||||
min_size = sizeof(struct rtl_epatch_header) + sizeof(extension_sig) + 3;
|
||||
|
|
|
@ -3096,6 +3096,7 @@ static int btusb_probe(struct usb_interface *intf,
|
|||
hdev->set_diag = btintel_set_diag;
|
||||
hdev->set_bdaddr = btintel_set_bdaddr;
|
||||
set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
|
||||
set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks);
|
||||
set_bit(HCI_QUIRK_NON_PERSISTENT_DIAG, &hdev->quirks);
|
||||
}
|
||||
|
||||
|
|
|
@ -167,7 +167,8 @@ struct qca_serdev {
|
|||
};
|
||||
|
||||
static int qca_power_setup(struct hci_uart *hu, bool on);
|
||||
static void qca_power_shutdown(struct hci_dev *hdev);
|
||||
static void qca_power_shutdown(struct hci_uart *hu);
|
||||
static int qca_power_off(struct hci_dev *hdev);
|
||||
|
||||
static void __serial_clock_on(struct tty_struct *tty)
|
||||
{
|
||||
|
@ -499,7 +500,6 @@ static int qca_open(struct hci_uart *hu)
|
|||
hu->priv = qca;
|
||||
|
||||
if (hu->serdev) {
|
||||
serdev_device_open(hu->serdev);
|
||||
|
||||
qcadev = serdev_device_get_drvdata(hu->serdev);
|
||||
if (qcadev->btsoc_type != QCA_WCN3990) {
|
||||
|
@ -609,11 +609,10 @@ static int qca_close(struct hci_uart *hu)
|
|||
if (hu->serdev) {
|
||||
qcadev = serdev_device_get_drvdata(hu->serdev);
|
||||
if (qcadev->btsoc_type == QCA_WCN3990)
|
||||
qca_power_shutdown(hu->hdev);
|
||||
qca_power_shutdown(hu);
|
||||
else
|
||||
gpiod_set_value_cansleep(qcadev->bt_en, 0);
|
||||
|
||||
serdev_device_close(hu->serdev);
|
||||
}
|
||||
|
||||
kfree_skb(qca->rx_skb);
|
||||
|
@ -1101,8 +1100,26 @@ static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type speed_type)
|
|||
static int qca_wcn3990_init(struct hci_uart *hu)
|
||||
{
|
||||
struct hci_dev *hdev = hu->hdev;
|
||||
struct qca_serdev *qcadev;
|
||||
int ret;
|
||||
|
||||
/* Check for vregs status, may be hci down has turned
|
||||
* off the voltage regulator.
|
||||
*/
|
||||
qcadev = serdev_device_get_drvdata(hu->serdev);
|
||||
if (!qcadev->bt_power->vregs_on) {
|
||||
serdev_device_close(hu->serdev);
|
||||
ret = qca_power_setup(hu, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = serdev_device_open(hu->serdev);
|
||||
if (ret) {
|
||||
bt_dev_err(hu->hdev, "failed to open port");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* Forcefully enable wcn3990 to enter in to boot mode. */
|
||||
host_set_baudrate(hu, 2400);
|
||||
ret = qca_send_power_pulse(hdev, QCA_WCN3990_POWEROFF_PULSE);
|
||||
|
@ -1154,6 +1171,12 @@ static int qca_setup(struct hci_uart *hu)
|
|||
|
||||
if (qcadev->btsoc_type == QCA_WCN3990) {
|
||||
bt_dev_info(hdev, "setting up wcn3990");
|
||||
|
||||
/* Enable NON_PERSISTENT_SETUP QUIRK to ensure to execute
|
||||
* setup for every hci up.
|
||||
*/
|
||||
set_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks);
|
||||
hu->hdev->shutdown = qca_power_off;
|
||||
ret = qca_wcn3990_init(hu);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -1232,13 +1255,24 @@ static const struct qca_vreg_data qca_soc_data = {
|
|||
.num_vregs = 4,
|
||||
};
|
||||
|
||||
static void qca_power_shutdown(struct hci_dev *hdev)
|
||||
static void qca_power_shutdown(struct hci_uart *hu)
|
||||
{
|
||||
struct serdev_device *serdev = hu->serdev;
|
||||
unsigned char cmd = QCA_WCN3990_POWEROFF_PULSE;
|
||||
|
||||
host_set_baudrate(hu, 2400);
|
||||
hci_uart_set_flow_control(hu, true);
|
||||
serdev_device_write_buf(serdev, &cmd, sizeof(cmd));
|
||||
hci_uart_set_flow_control(hu, false);
|
||||
qca_power_setup(hu, false);
|
||||
}
|
||||
|
||||
static int qca_power_off(struct hci_dev *hdev)
|
||||
{
|
||||
struct hci_uart *hu = hci_get_drvdata(hdev);
|
||||
|
||||
host_set_baudrate(hu, 2400);
|
||||
qca_send_power_pulse(hdev, QCA_WCN3990_POWEROFF_PULSE);
|
||||
qca_power_setup(hu, false);
|
||||
qca_power_shutdown(hu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qca_enable_regulator(struct qca_vreg vregs,
|
||||
|
@ -1413,7 +1447,7 @@ static void qca_serdev_remove(struct serdev_device *serdev)
|
|||
struct qca_serdev *qcadev = serdev_device_get_drvdata(serdev);
|
||||
|
||||
if (qcadev->btsoc_type == QCA_WCN3990)
|
||||
qca_power_shutdown(qcadev->serdev_hu.hdev);
|
||||
qca_power_shutdown(&qcadev->serdev_hu);
|
||||
else
|
||||
clk_disable_unprepare(qcadev->susclk);
|
||||
|
||||
|
|
|
@ -57,9 +57,10 @@ static inline struct sk_buff *hci_uart_dequeue(struct hci_uart *hu)
|
|||
{
|
||||
struct sk_buff *skb = hu->tx_skb;
|
||||
|
||||
if (!skb)
|
||||
skb = hu->proto->dequeue(hu);
|
||||
else
|
||||
if (!skb) {
|
||||
if (test_bit(HCI_UART_PROTO_READY, &hu->flags))
|
||||
skb = hu->proto->dequeue(hu);
|
||||
} else
|
||||
hu->tx_skb = NULL;
|
||||
|
||||
return skb;
|
||||
|
@ -94,7 +95,7 @@ static void hci_uart_write_work(struct work_struct *work)
|
|||
hci_uart_tx_complete(hu, hci_skb_pkt_type(skb));
|
||||
kfree_skb(skb);
|
||||
}
|
||||
} while(test_bit(HCI_UART_TX_WAKEUP, &hu->tx_state));
|
||||
} while (test_bit(HCI_UART_TX_WAKEUP, &hu->tx_state));
|
||||
|
||||
clear_bit(HCI_UART_SENDING, &hu->tx_state);
|
||||
}
|
||||
|
@ -368,6 +369,7 @@ void hci_uart_unregister_device(struct hci_uart *hu)
|
|||
{
|
||||
struct hci_dev *hdev = hu->hdev;
|
||||
|
||||
clear_bit(HCI_UART_PROTO_READY, &hu->flags);
|
||||
hci_unregister_dev(hdev);
|
||||
hci_free_dev(hdev);
|
||||
|
||||
|
|
|
@ -1517,6 +1517,20 @@ struct hci_cp_le_write_def_data_len {
|
|||
__le16 tx_time;
|
||||
} __packed;
|
||||
|
||||
#define HCI_OP_LE_ADD_TO_RESOLV_LIST 0x2027
|
||||
struct hci_cp_le_add_to_resolv_list {
|
||||
__u8 bdaddr_type;
|
||||
bdaddr_t bdaddr;
|
||||
__u8 peer_irk[16];
|
||||
__u8 local_irk[16];
|
||||
} __packed;
|
||||
|
||||
#define HCI_OP_LE_DEL_FROM_RESOLV_LIST 0x2028
|
||||
struct hci_cp_le_del_from_resolv_list {
|
||||
__u8 bdaddr_type;
|
||||
bdaddr_t bdaddr;
|
||||
} __packed;
|
||||
|
||||
#define HCI_OP_LE_CLEAR_RESOLV_LIST 0x2029
|
||||
|
||||
#define HCI_OP_LE_READ_RESOLV_LIST_SIZE 0x202a
|
||||
|
|
|
@ -103,6 +103,14 @@ struct bdaddr_list {
|
|||
u8 bdaddr_type;
|
||||
};
|
||||
|
||||
struct bdaddr_list_with_irk {
|
||||
struct list_head list;
|
||||
bdaddr_t bdaddr;
|
||||
u8 bdaddr_type;
|
||||
u8 peer_irk[16];
|
||||
u8 local_irk[16];
|
||||
};
|
||||
|
||||
struct bt_uuid {
|
||||
struct list_head list;
|
||||
u8 uuid[16];
|
||||
|
@ -259,6 +267,8 @@ struct hci_dev {
|
|||
__u16 le_max_tx_time;
|
||||
__u16 le_max_rx_len;
|
||||
__u16 le_max_rx_time;
|
||||
__u8 le_max_key_size;
|
||||
__u8 le_min_key_size;
|
||||
__u16 discov_interleaved_timeout;
|
||||
__u16 conn_info_min_age;
|
||||
__u16 conn_info_max_age;
|
||||
|
@ -1058,8 +1068,15 @@ int hci_inquiry(void __user *arg);
|
|||
|
||||
struct bdaddr_list *hci_bdaddr_list_lookup(struct list_head *list,
|
||||
bdaddr_t *bdaddr, u8 type);
|
||||
struct bdaddr_list_with_irk *hci_bdaddr_list_lookup_with_irk(
|
||||
struct list_head *list, bdaddr_t *bdaddr,
|
||||
u8 type);
|
||||
int hci_bdaddr_list_add(struct list_head *list, bdaddr_t *bdaddr, u8 type);
|
||||
int hci_bdaddr_list_add_with_irk(struct list_head *list, bdaddr_t *bdaddr,
|
||||
u8 type, u8 *peer_irk, u8 *local_irk);
|
||||
int hci_bdaddr_list_del(struct list_head *list, bdaddr_t *bdaddr, u8 type);
|
||||
int hci_bdaddr_list_del_with_irk(struct list_head *list, bdaddr_t *bdaddr,
|
||||
u8 type);
|
||||
void hci_bdaddr_list_clear(struct list_head *list);
|
||||
|
||||
struct hci_conn_params *hci_conn_params_lookup(struct hci_dev *hdev,
|
||||
|
|
|
@ -455,9 +455,6 @@ struct l2cap_conn_param_update_rsp {
|
|||
#define L2CAP_CONN_PARAM_ACCEPTED 0x0000
|
||||
#define L2CAP_CONN_PARAM_REJECTED 0x0001
|
||||
|
||||
#define L2CAP_LE_MAX_CREDITS 10
|
||||
#define L2CAP_LE_DEFAULT_MPS 230
|
||||
|
||||
struct l2cap_le_conn_req {
|
||||
__le16 psm;
|
||||
__le16 scid;
|
||||
|
|
|
@ -489,9 +489,6 @@ static int bnep_session(void *arg)
|
|||
|
||||
add_wait_queue(sk_sleep(sk), &wait);
|
||||
while (1) {
|
||||
/* Ensure session->terminate is updated */
|
||||
smp_mb__before_atomic();
|
||||
|
||||
if (atomic_read(&s->terminate))
|
||||
break;
|
||||
/* RX */
|
||||
|
@ -512,6 +509,10 @@ static int bnep_session(void *arg)
|
|||
break;
|
||||
netif_wake_queue(dev);
|
||||
|
||||
/*
|
||||
* wait_woken() performs the necessary memory barriers
|
||||
* for us; see the header comment for this primitive.
|
||||
*/
|
||||
wait_woken(&wait, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
|
||||
}
|
||||
remove_wait_queue(sk_sleep(sk), &wait);
|
||||
|
|
|
@ -288,9 +288,6 @@ static int cmtp_session(void *arg)
|
|||
|
||||
add_wait_queue(sk_sleep(sk), &wait);
|
||||
while (1) {
|
||||
/* Ensure session->terminate is updated */
|
||||
smp_mb__before_atomic();
|
||||
|
||||
if (atomic_read(&session->terminate))
|
||||
break;
|
||||
if (sk->sk_state != BT_CONNECTED)
|
||||
|
@ -306,6 +303,10 @@ static int cmtp_session(void *arg)
|
|||
|
||||
cmtp_process_transmit(session);
|
||||
|
||||
/*
|
||||
* wait_woken() performs the necessary memory barriers
|
||||
* for us; see the header comment for this primitive.
|
||||
*/
|
||||
wait_woken(&wait, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
|
||||
}
|
||||
remove_wait_queue(sk_sleep(sk), &wait);
|
||||
|
@ -431,9 +432,10 @@ int cmtp_del_connection(struct cmtp_conndel_req *req)
|
|||
/* Stop session thread */
|
||||
atomic_inc(&session->terminate);
|
||||
|
||||
/* Ensure session->terminate is updated */
|
||||
smp_mb__after_atomic();
|
||||
|
||||
/*
|
||||
* See the comment preceding the call to wait_woken()
|
||||
* in cmtp_session().
|
||||
*/
|
||||
wake_up_interruptible(sk_sleep(session->sock->sk));
|
||||
} else
|
||||
err = -ENOENT;
|
||||
|
|
|
@ -2839,6 +2839,20 @@ struct bdaddr_list *hci_bdaddr_list_lookup(struct list_head *bdaddr_list,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
struct bdaddr_list_with_irk *hci_bdaddr_list_lookup_with_irk(
|
||||
struct list_head *bdaddr_list, bdaddr_t *bdaddr,
|
||||
u8 type)
|
||||
{
|
||||
struct bdaddr_list_with_irk *b;
|
||||
|
||||
list_for_each_entry(b, bdaddr_list, list) {
|
||||
if (!bacmp(&b->bdaddr, bdaddr) && b->bdaddr_type == type)
|
||||
return b;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void hci_bdaddr_list_clear(struct list_head *bdaddr_list)
|
||||
{
|
||||
struct bdaddr_list *b, *n;
|
||||
|
@ -2871,6 +2885,35 @@ int hci_bdaddr_list_add(struct list_head *list, bdaddr_t *bdaddr, u8 type)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int hci_bdaddr_list_add_with_irk(struct list_head *list, bdaddr_t *bdaddr,
|
||||
u8 type, u8 *peer_irk, u8 *local_irk)
|
||||
{
|
||||
struct bdaddr_list_with_irk *entry;
|
||||
|
||||
if (!bacmp(bdaddr, BDADDR_ANY))
|
||||
return -EBADF;
|
||||
|
||||
if (hci_bdaddr_list_lookup(list, bdaddr, type))
|
||||
return -EEXIST;
|
||||
|
||||
entry = kzalloc(sizeof(*entry), GFP_KERNEL);
|
||||
if (!entry)
|
||||
return -ENOMEM;
|
||||
|
||||
bacpy(&entry->bdaddr, bdaddr);
|
||||
entry->bdaddr_type = type;
|
||||
|
||||
if (peer_irk)
|
||||
memcpy(entry->peer_irk, peer_irk, 16);
|
||||
|
||||
if (local_irk)
|
||||
memcpy(entry->local_irk, local_irk, 16);
|
||||
|
||||
list_add(&entry->list, list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hci_bdaddr_list_del(struct list_head *list, bdaddr_t *bdaddr, u8 type)
|
||||
{
|
||||
struct bdaddr_list *entry;
|
||||
|
@ -2890,6 +2933,26 @@ int hci_bdaddr_list_del(struct list_head *list, bdaddr_t *bdaddr, u8 type)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int hci_bdaddr_list_del_with_irk(struct list_head *list, bdaddr_t *bdaddr,
|
||||
u8 type)
|
||||
{
|
||||
struct bdaddr_list_with_irk *entry;
|
||||
|
||||
if (!bacmp(bdaddr, BDADDR_ANY)) {
|
||||
hci_bdaddr_list_clear(list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
entry = hci_bdaddr_list_lookup_with_irk(list, bdaddr, type);
|
||||
if (!entry)
|
||||
return -ENOENT;
|
||||
|
||||
list_del(&entry->list);
|
||||
kfree(entry);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This function requires the caller holds hdev->lock */
|
||||
struct hci_conn_params *hci_conn_params_lookup(struct hci_dev *hdev,
|
||||
bdaddr_t *addr, u8 addr_type)
|
||||
|
@ -3084,6 +3147,8 @@ struct hci_dev *hci_alloc_dev(void)
|
|||
hdev->le_max_tx_time = 0x0148;
|
||||
hdev->le_max_rx_len = 0x001b;
|
||||
hdev->le_max_rx_time = 0x0148;
|
||||
hdev->le_max_key_size = SMP_MAX_ENC_KEY_SIZE;
|
||||
hdev->le_min_key_size = SMP_MIN_ENC_KEY_SIZE;
|
||||
hdev->le_tx_def_phys = HCI_LE_SET_PHY_1M;
|
||||
hdev->le_rx_def_phys = HCI_LE_SET_PHY_1M;
|
||||
|
||||
|
|
|
@ -1454,6 +1454,45 @@ static void hci_cc_le_write_def_data_len(struct hci_dev *hdev,
|
|||
hdev->le_def_tx_time = le16_to_cpu(sent->tx_time);
|
||||
}
|
||||
|
||||
static void hci_cc_le_add_to_resolv_list(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct hci_cp_le_add_to_resolv_list *sent;
|
||||
__u8 status = *((__u8 *) skb->data);
|
||||
|
||||
BT_DBG("%s status 0x%2.2x", hdev->name, status);
|
||||
|
||||
if (status)
|
||||
return;
|
||||
|
||||
sent = hci_sent_cmd_data(hdev, HCI_OP_LE_ADD_TO_RESOLV_LIST);
|
||||
if (!sent)
|
||||
return;
|
||||
|
||||
hci_bdaddr_list_add_with_irk(&hdev->le_resolv_list, &sent->bdaddr,
|
||||
sent->bdaddr_type, sent->peer_irk,
|
||||
sent->local_irk);
|
||||
}
|
||||
|
||||
static void hci_cc_le_del_from_resolv_list(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct hci_cp_le_del_from_resolv_list *sent;
|
||||
__u8 status = *((__u8 *) skb->data);
|
||||
|
||||
BT_DBG("%s status 0x%2.2x", hdev->name, status);
|
||||
|
||||
if (status)
|
||||
return;
|
||||
|
||||
sent = hci_sent_cmd_data(hdev, HCI_OP_LE_DEL_FROM_RESOLV_LIST);
|
||||
if (!sent)
|
||||
return;
|
||||
|
||||
hci_bdaddr_list_del_with_irk(&hdev->le_resolv_list, &sent->bdaddr,
|
||||
sent->bdaddr_type);
|
||||
}
|
||||
|
||||
static void hci_cc_le_clear_resolv_list(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
|
@ -3279,6 +3318,14 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb,
|
|||
hci_cc_le_write_def_data_len(hdev, skb);
|
||||
break;
|
||||
|
||||
case HCI_OP_LE_ADD_TO_RESOLV_LIST:
|
||||
hci_cc_le_add_to_resolv_list(hdev, skb);
|
||||
break;
|
||||
|
||||
case HCI_OP_LE_DEL_FROM_RESOLV_LIST:
|
||||
hci_cc_le_del_from_resolv_list(hdev, skb);
|
||||
break;
|
||||
|
||||
case HCI_OP_LE_CLEAR_RESOLV_LIST:
|
||||
hci_cc_le_clear_resolv_list(hdev, skb);
|
||||
break;
|
||||
|
|
|
@ -1074,6 +1074,10 @@ static int hidp_session_start_sync(struct hidp_session *session)
|
|||
static void hidp_session_terminate(struct hidp_session *session)
|
||||
{
|
||||
atomic_inc(&session->terminate);
|
||||
/*
|
||||
* See the comment preceding the call to wait_woken()
|
||||
* in hidp_session_run().
|
||||
*/
|
||||
wake_up_interruptible(&hidp_session_wq);
|
||||
}
|
||||
|
||||
|
@ -1193,8 +1197,6 @@ static void hidp_session_run(struct hidp_session *session)
|
|||
* thread is woken up by ->sk_state_changed().
|
||||
*/
|
||||
|
||||
/* Ensure session->terminate is updated */
|
||||
smp_mb__before_atomic();
|
||||
if (atomic_read(&session->terminate))
|
||||
break;
|
||||
|
||||
|
@ -1228,14 +1230,15 @@ static void hidp_session_run(struct hidp_session *session)
|
|||
hidp_process_transmit(session, &session->ctrl_transmit,
|
||||
session->ctrl_sock);
|
||||
|
||||
/*
|
||||
* wait_woken() performs the necessary memory barriers
|
||||
* for us; see the header comment for this primitive.
|
||||
*/
|
||||
wait_woken(&wait, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
|
||||
}
|
||||
remove_wait_queue(&hidp_session_wq, &wait);
|
||||
|
||||
atomic_inc(&session->terminate);
|
||||
|
||||
/* Ensure session->terminate is updated */
|
||||
smp_mb__after_atomic();
|
||||
}
|
||||
|
||||
static int hidp_session_wake_function(wait_queue_entry_t *wait,
|
||||
|
|
|
@ -51,9 +51,6 @@ static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN | L2CAP_FEAT_UCD;
|
|||
static LIST_HEAD(chan_list);
|
||||
static DEFINE_RWLOCK(chan_list_lock);
|
||||
|
||||
static u16 le_max_credits = L2CAP_LE_MAX_CREDITS;
|
||||
static u16 le_default_mps = L2CAP_LE_DEFAULT_MPS;
|
||||
|
||||
static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
|
||||
u8 code, u8 ident, u16 dlen, void *data);
|
||||
static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
|
||||
|
@ -519,8 +516,10 @@ static void l2cap_le_flowctl_init(struct l2cap_chan *chan)
|
|||
chan->sdu_last_frag = NULL;
|
||||
chan->sdu_len = 0;
|
||||
chan->tx_credits = 0;
|
||||
chan->rx_credits = le_max_credits;
|
||||
chan->mps = min_t(u16, chan->imtu, le_default_mps);
|
||||
/* Derive MPS from connection MTU to stop HCI fragmentation */
|
||||
chan->mps = min_t(u16, chan->imtu, chan->conn->mtu - L2CAP_HDR_SIZE);
|
||||
/* Give enough credits for a full packet */
|
||||
chan->rx_credits = (chan->imtu / chan->mps) + 1;
|
||||
|
||||
skb_queue_head_init(&chan->tx_q);
|
||||
}
|
||||
|
@ -1282,6 +1281,8 @@ static void l2cap_le_connect(struct l2cap_chan *chan)
|
|||
if (test_and_set_bit(FLAG_LE_CONN_REQ_SENT, &chan->flags))
|
||||
return;
|
||||
|
||||
l2cap_le_flowctl_init(chan);
|
||||
|
||||
req.psm = chan->psm;
|
||||
req.scid = cpu_to_le16(chan->scid);
|
||||
req.mtu = cpu_to_le16(chan->imtu);
|
||||
|
@ -5493,8 +5494,6 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn,
|
|||
goto response_unlock;
|
||||
}
|
||||
|
||||
l2cap_le_flowctl_init(chan);
|
||||
|
||||
bacpy(&chan->src, &conn->hcon->src);
|
||||
bacpy(&chan->dst, &conn->hcon->dst);
|
||||
chan->src_type = bdaddr_src_type(conn->hcon);
|
||||
|
@ -5506,6 +5505,9 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn,
|
|||
chan->tx_credits = __le16_to_cpu(req->credits);
|
||||
|
||||
__l2cap_chan_add(conn, chan);
|
||||
|
||||
l2cap_le_flowctl_init(chan);
|
||||
|
||||
dcid = chan->scid;
|
||||
credits = chan->rx_credits;
|
||||
|
||||
|
@ -6699,13 +6701,10 @@ static void l2cap_chan_le_send_credits(struct l2cap_chan *chan)
|
|||
struct l2cap_le_credits pkt;
|
||||
u16 return_credits;
|
||||
|
||||
/* We return more credits to the sender only after the amount of
|
||||
* credits falls below half of the initial amount.
|
||||
*/
|
||||
if (chan->rx_credits >= (le_max_credits + 1) / 2)
|
||||
return;
|
||||
return_credits = ((chan->imtu / chan->mps) + 1) - chan->rx_credits;
|
||||
|
||||
return_credits = le_max_credits - chan->rx_credits;
|
||||
if (!return_credits)
|
||||
return;
|
||||
|
||||
BT_DBG("chan %p returning %u credits to sender", chan, return_credits);
|
||||
|
||||
|
@ -6719,6 +6718,21 @@ static void l2cap_chan_le_send_credits(struct l2cap_chan *chan)
|
|||
l2cap_send_cmd(conn, chan->ident, L2CAP_LE_CREDITS, sizeof(pkt), &pkt);
|
||||
}
|
||||
|
||||
static int l2cap_le_recv(struct l2cap_chan *chan, struct sk_buff *skb)
|
||||
{
|
||||
int err;
|
||||
|
||||
BT_DBG("SDU reassemble complete: chan %p skb->len %u", chan, skb->len);
|
||||
|
||||
/* Wait recv to confirm reception before updating the credits */
|
||||
err = chan->ops->recv(chan, skb);
|
||||
|
||||
/* Update credits whenever an SDU is received */
|
||||
l2cap_chan_le_send_credits(chan);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int l2cap_le_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
|
||||
{
|
||||
int err;
|
||||
|
@ -6737,7 +6751,11 @@ static int l2cap_le_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
|
|||
chan->rx_credits--;
|
||||
BT_DBG("rx_credits %u -> %u", chan->rx_credits + 1, chan->rx_credits);
|
||||
|
||||
l2cap_chan_le_send_credits(chan);
|
||||
/* Update if remote had run out of credits, this should only happens
|
||||
* if the remote is not using the entire MPS.
|
||||
*/
|
||||
if (!chan->rx_credits)
|
||||
l2cap_chan_le_send_credits(chan);
|
||||
|
||||
err = 0;
|
||||
|
||||
|
@ -6763,12 +6781,22 @@ static int l2cap_le_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
|
|||
}
|
||||
|
||||
if (skb->len == sdu_len)
|
||||
return chan->ops->recv(chan, skb);
|
||||
return l2cap_le_recv(chan, skb);
|
||||
|
||||
chan->sdu = skb;
|
||||
chan->sdu_len = sdu_len;
|
||||
chan->sdu_last_frag = skb;
|
||||
|
||||
/* Detect if remote is not able to use the selected MPS */
|
||||
if (skb->len + L2CAP_SDULEN_SIZE < chan->mps) {
|
||||
u16 mps_len = skb->len + L2CAP_SDULEN_SIZE;
|
||||
|
||||
/* Adjust the number of credits */
|
||||
BT_DBG("chan->mps %u -> %u", chan->mps, mps_len);
|
||||
chan->mps = mps_len;
|
||||
l2cap_chan_le_send_credits(chan);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -6785,7 +6813,7 @@ static int l2cap_le_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
|
|||
skb = NULL;
|
||||
|
||||
if (chan->sdu->len == chan->sdu_len) {
|
||||
err = chan->ops->recv(chan, chan->sdu);
|
||||
err = l2cap_le_recv(chan, chan->sdu);
|
||||
if (!err) {
|
||||
chan->sdu = NULL;
|
||||
chan->sdu_last_frag = NULL;
|
||||
|
@ -7102,7 +7130,6 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
|
|||
case L2CAP_MODE_BASIC:
|
||||
break;
|
||||
case L2CAP_MODE_LE_FLOWCTL:
|
||||
l2cap_le_flowctl_init(chan);
|
||||
break;
|
||||
case L2CAP_MODE_ERTM:
|
||||
case L2CAP_MODE_STREAMING:
|
||||
|
@ -7645,11 +7672,6 @@ int __init l2cap_init(void)
|
|||
l2cap_debugfs = debugfs_create_file("l2cap", 0444, bt_debugfs,
|
||||
NULL, &l2cap_debugfs_fops);
|
||||
|
||||
debugfs_create_u16("l2cap_le_max_credits", 0644, bt_debugfs,
|
||||
&le_max_credits);
|
||||
debugfs_create_u16("l2cap_le_default_mps", 0644, bt_debugfs,
|
||||
&le_default_mps);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -88,9 +88,6 @@ struct smp_dev {
|
|||
u8 local_rand[16];
|
||||
bool debug_key;
|
||||
|
||||
u8 min_key_size;
|
||||
u8 max_key_size;
|
||||
|
||||
struct crypto_cipher *tfm_aes;
|
||||
struct crypto_shash *tfm_cmac;
|
||||
struct crypto_kpp *tfm_ecdh;
|
||||
|
@ -720,7 +717,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
|
|||
if (rsp == NULL) {
|
||||
req->io_capability = conn->hcon->io_capability;
|
||||
req->oob_flag = oob_flag;
|
||||
req->max_key_size = SMP_DEV(hdev)->max_key_size;
|
||||
req->max_key_size = hdev->le_max_key_size;
|
||||
req->init_key_dist = local_dist;
|
||||
req->resp_key_dist = remote_dist;
|
||||
req->auth_req = (authreq & AUTH_REQ_MASK(hdev));
|
||||
|
@ -731,7 +728,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
|
|||
|
||||
rsp->io_capability = conn->hcon->io_capability;
|
||||
rsp->oob_flag = oob_flag;
|
||||
rsp->max_key_size = SMP_DEV(hdev)->max_key_size;
|
||||
rsp->max_key_size = hdev->le_max_key_size;
|
||||
rsp->init_key_dist = req->init_key_dist & remote_dist;
|
||||
rsp->resp_key_dist = req->resp_key_dist & local_dist;
|
||||
rsp->auth_req = (authreq & AUTH_REQ_MASK(hdev));
|
||||
|
@ -745,7 +742,7 @@ static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size)
|
|||
struct hci_dev *hdev = conn->hcon->hdev;
|
||||
struct smp_chan *smp = chan->data;
|
||||
|
||||
if (max_key_size > SMP_DEV(hdev)->max_key_size ||
|
||||
if (max_key_size > hdev->le_max_key_size ||
|
||||
max_key_size < SMP_MIN_ENC_KEY_SIZE)
|
||||
return SMP_ENC_KEY_SIZE;
|
||||
|
||||
|
@ -3243,8 +3240,6 @@ static struct l2cap_chan *smp_add_cid(struct hci_dev *hdev, u16 cid)
|
|||
smp->tfm_aes = tfm_aes;
|
||||
smp->tfm_cmac = tfm_cmac;
|
||||
smp->tfm_ecdh = tfm_ecdh;
|
||||
smp->min_key_size = SMP_MIN_ENC_KEY_SIZE;
|
||||
smp->max_key_size = SMP_MAX_ENC_KEY_SIZE;
|
||||
|
||||
create_chan:
|
||||
chan = l2cap_chan_create();
|
||||
|
@ -3370,7 +3365,7 @@ static ssize_t le_min_key_size_read(struct file *file,
|
|||
struct hci_dev *hdev = file->private_data;
|
||||
char buf[4];
|
||||
|
||||
snprintf(buf, sizeof(buf), "%2u\n", SMP_DEV(hdev)->min_key_size);
|
||||
snprintf(buf, sizeof(buf), "%2u\n", hdev->le_min_key_size);
|
||||
|
||||
return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
|
||||
}
|
||||
|
@ -3391,11 +3386,11 @@ static ssize_t le_min_key_size_write(struct file *file,
|
|||
|
||||
sscanf(buf, "%hhu", &key_size);
|
||||
|
||||
if (key_size > SMP_DEV(hdev)->max_key_size ||
|
||||
if (key_size > hdev->le_max_key_size ||
|
||||
key_size < SMP_MIN_ENC_KEY_SIZE)
|
||||
return -EINVAL;
|
||||
|
||||
SMP_DEV(hdev)->min_key_size = key_size;
|
||||
hdev->le_min_key_size = key_size;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
@ -3414,7 +3409,7 @@ static ssize_t le_max_key_size_read(struct file *file,
|
|||
struct hci_dev *hdev = file->private_data;
|
||||
char buf[4];
|
||||
|
||||
snprintf(buf, sizeof(buf), "%2u\n", SMP_DEV(hdev)->max_key_size);
|
||||
snprintf(buf, sizeof(buf), "%2u\n", hdev->le_max_key_size);
|
||||
|
||||
return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
|
||||
}
|
||||
|
@ -3436,10 +3431,10 @@ static ssize_t le_max_key_size_write(struct file *file,
|
|||
sscanf(buf, "%hhu", &key_size);
|
||||
|
||||
if (key_size > SMP_MAX_ENC_KEY_SIZE ||
|
||||
key_size < SMP_DEV(hdev)->min_key_size)
|
||||
key_size < hdev->le_min_key_size)
|
||||
return -EINVAL;
|
||||
|
||||
SMP_DEV(hdev)->max_key_size = key_size;
|
||||
hdev->le_max_key_size = key_size;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче