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:
David S. Miller 2018-10-02 22:34:54 -07:00
Родитель 258b6d1418 30d65e0804
Коммит 00538ba915
18 изменённых файлов: 300 добавлений и 76 удалений

Просмотреть файл

@ -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;
}