Commit 00538ba9 authored by David S. Miller's avatar David S. Miller

Merge branch 'for-upstream' of...

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: default avatarDavid S. Miller <davem@davemloft.net>
parents 258b6d14 30d65e08
...@@ -203,10 +203,11 @@ static const struct usb_device_id ath3k_blist_tbl[] = { ...@@ -203,10 +203,11 @@ static const struct usb_device_id ath3k_blist_tbl[] = {
{ } /* Terminating entry */ { } /* 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", BT_ERR("Firmware loading err = %d, len = %d, size = %d, count = %d",
err, len, size); err, len, size, count);
} }
#define USB_REQ_DFU_DNLOAD 1 #define USB_REQ_DFU_DNLOAD 1
...@@ -257,7 +258,7 @@ static int ath3k_load_firmware(struct usb_device *udev, ...@@ -257,7 +258,7 @@ static int ath3k_load_firmware(struct usb_device *udev,
&len, 3000); &len, 3000);
if (err || (len != size)) { if (err || (len != size)) {
ath3k_log_failed_loading(err, len, size); ath3k_log_failed_loading(err, len, size, count);
goto error; goto error;
} }
...@@ -356,7 +357,7 @@ static int ath3k_load_fwfile(struct usb_device *udev, ...@@ -356,7 +357,7 @@ static int ath3k_load_fwfile(struct usb_device *udev,
err = usb_bulk_msg(udev, pipe, send_buf, size, err = usb_bulk_msg(udev, pipe, send_buf, size,
&len, 3000); &len, 3000);
if (err || (len != size)) { if (err || (len != size)) {
ath3k_log_failed_loading(err, len, size); ath3k_log_failed_loading(err, len, size, count);
kfree(send_buf); kfree(send_buf);
return err; return err;
} }
......
...@@ -448,7 +448,7 @@ static int bt3c_load_firmware(struct bt3c_info *info, ...@@ -448,7 +448,7 @@ static int bt3c_load_firmware(struct bt3c_info *info,
{ {
char *ptr = (char *) firmware; char *ptr = (char *) firmware;
char b[9]; char b[9];
unsigned int iobase, tmp; unsigned int iobase, tmp, tn;
unsigned long size, addr, fcs; unsigned long size, addr, fcs;
int i, err = 0; int i, err = 0;
...@@ -490,7 +490,9 @@ static int bt3c_load_firmware(struct bt3c_info *info, ...@@ -490,7 +490,9 @@ static int bt3c_load_firmware(struct bt3c_info *info,
memset(b, 0, sizeof(b)); memset(b, 0, sizeof(b));
for (tmp = 0, i = 0; i < size; i++) { for (tmp = 0, i = 0; i < size; i++) {
memcpy(b, ptr + (i * 2) + 2, 2); 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) { if (((tmp + fcs) & 0xff) != 0xff) {
...@@ -505,7 +507,8 @@ static int bt3c_load_firmware(struct bt3c_info *info, ...@@ -505,7 +507,8 @@ static int bt3c_load_firmware(struct bt3c_info *info,
memset(b, 0, sizeof(b)); memset(b, 0, sizeof(b));
for (i = 0; i < (size - 4) / 2; i++) { for (i = 0; i < (size - 4) / 2; i++) {
memcpy(b, ptr + (i * 4) + 12, 4); memcpy(b, ptr + (i * 4) + 12, 4);
tmp = simple_strtoul(b, NULL, 16); if (kstrtouint(b, 16, &tmp))
return -EINVAL;
bt3c_put(iobase, tmp); bt3c_put(iobase, tmp);
} }
} }
......
...@@ -324,6 +324,7 @@ static const struct bcm_subver_table bcm_uart_subver_table[] = { ...@@ -324,6 +324,7 @@ static const struct bcm_subver_table bcm_uart_subver_table[] = {
{ 0x4103, "BCM4330B1" }, /* 002.001.003 */ { 0x4103, "BCM4330B1" }, /* 002.001.003 */
{ 0x410e, "BCM43341B0" }, /* 002.001.014 */ { 0x410e, "BCM43341B0" }, /* 002.001.014 */
{ 0x4406, "BCM4324B3" }, /* 002.004.006 */ { 0x4406, "BCM4324B3" }, /* 002.004.006 */
{ 0x6109, "BCM4335C0" }, /* 003.001.009 */
{ 0x610c, "BCM4354" }, /* 003.001.012 */ { 0x610c, "BCM4354" }, /* 003.001.012 */
{ 0x2122, "BCM4343A0" }, /* 001.001.034 */ { 0x2122, "BCM4343A0" }, /* 001.001.034 */
{ 0x2209, "BCM43430A1" }, /* 001.002.009 */ { 0x2209, "BCM43430A1" }, /* 001.002.009 */
......
...@@ -21,8 +21,9 @@ ...@@ -21,8 +21,9 @@
#include <net/rsi_91x.h> #include <net/rsi_91x.h>
#include <net/genetlink.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_FRAME_DESC_SIZE 16
#define RSI_HEADROOM_FOR_BT_HAL (RSI_FRAME_DESC_SIZE + RSI_DMA_ALIGN)
struct rsi_hci_adapter { struct rsi_hci_adapter {
void *priv; void *priv;
...@@ -70,6 +71,16 @@ static int rsi_hci_send_pkt(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -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); bt_cb(new_skb)->pkt_type = hci_skb_pkt_type(skb);
kfree_skb(skb); kfree_skb(skb);
skb = new_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, return h_adapter->proto_ops->coex_send_pkt(h_adapter->priv, skb,
......
...@@ -138,6 +138,13 @@ static const struct id_table ic_id_table[] = { ...@@ -138,6 +138,13 @@ static const struct id_table ic_id_table[] = {
.fw_name = "rtl_bt/rtl8761a_fw.bin", .fw_name = "rtl_bt/rtl8761a_fw.bin",
.cfg_name = "rtl_bt/rtl8761a_config" }, .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 */ /* 8822B */
{ IC_INFO(RTL_ROM_LMP_8822B, 0xb), { IC_INFO(RTL_ROM_LMP_8822B, 0xb),
.config_needed = true, .config_needed = true,
...@@ -206,7 +213,7 @@ static int rtlbt_parse_firmware(struct hci_dev *hdev, ...@@ -206,7 +213,7 @@ static int rtlbt_parse_firmware(struct hci_dev *hdev,
struct btrtl_device_info *btrtl_dev, struct btrtl_device_info *btrtl_dev,
unsigned char **_buf) 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; struct rtl_epatch_header *epatch_info;
unsigned char *buf; unsigned char *buf;
int i, len; int i, len;
...@@ -228,6 +235,7 @@ static int rtlbt_parse_firmware(struct hci_dev *hdev, ...@@ -228,6 +235,7 @@ static int rtlbt_parse_firmware(struct hci_dev *hdev,
{ RTL_ROM_LMP_8822B, 8 }, { RTL_ROM_LMP_8822B, 8 },
{ RTL_ROM_LMP_8723B, 9 }, /* 8723D */ { RTL_ROM_LMP_8723B, 9 }, /* 8723D */
{ RTL_ROM_LMP_8821A, 10 }, /* 8821C */ { RTL_ROM_LMP_8821A, 10 }, /* 8821C */
{ RTL_ROM_LMP_8822B, 13 }, /* 8822C */
}; };
min_size = sizeof(struct rtl_epatch_header) + sizeof(extension_sig) + 3; min_size = sizeof(struct rtl_epatch_header) + sizeof(extension_sig) + 3;
......
...@@ -3096,6 +3096,7 @@ static int btusb_probe(struct usb_interface *intf, ...@@ -3096,6 +3096,7 @@ static int btusb_probe(struct usb_interface *intf,
hdev->set_diag = btintel_set_diag; hdev->set_diag = btintel_set_diag;
hdev->set_bdaddr = btintel_set_bdaddr; hdev->set_bdaddr = btintel_set_bdaddr;
set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks); 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); set_bit(HCI_QUIRK_NON_PERSISTENT_DIAG, &hdev->quirks);
} }
......
...@@ -167,7 +167,8 @@ struct qca_serdev { ...@@ -167,7 +167,8 @@ struct qca_serdev {
}; };
static int qca_power_setup(struct hci_uart *hu, bool on); 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) static void __serial_clock_on(struct tty_struct *tty)
{ {
...@@ -499,7 +500,6 @@ static int qca_open(struct hci_uart *hu) ...@@ -499,7 +500,6 @@ static int qca_open(struct hci_uart *hu)
hu->priv = qca; hu->priv = qca;
if (hu->serdev) { if (hu->serdev) {
serdev_device_open(hu->serdev);
qcadev = serdev_device_get_drvdata(hu->serdev); qcadev = serdev_device_get_drvdata(hu->serdev);
if (qcadev->btsoc_type != QCA_WCN3990) { if (qcadev->btsoc_type != QCA_WCN3990) {
...@@ -609,11 +609,10 @@ static int qca_close(struct hci_uart *hu) ...@@ -609,11 +609,10 @@ static int qca_close(struct hci_uart *hu)
if (hu->serdev) { if (hu->serdev) {
qcadev = serdev_device_get_drvdata(hu->serdev); qcadev = serdev_device_get_drvdata(hu->serdev);
if (qcadev->btsoc_type == QCA_WCN3990) if (qcadev->btsoc_type == QCA_WCN3990)
qca_power_shutdown(hu->hdev); qca_power_shutdown(hu);
else else
gpiod_set_value_cansleep(qcadev->bt_en, 0); gpiod_set_value_cansleep(qcadev->bt_en, 0);
serdev_device_close(hu->serdev);
} }
kfree_skb(qca->rx_skb); kfree_skb(qca->rx_skb);
...@@ -1101,8 +1100,26 @@ static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type speed_type) ...@@ -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) static int qca_wcn3990_init(struct hci_uart *hu)
{ {
struct hci_dev *hdev = hu->hdev; struct hci_dev *hdev = hu->hdev;
struct qca_serdev *qcadev;
int ret; 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. */ /* Forcefully enable wcn3990 to enter in to boot mode. */
host_set_baudrate(hu, 2400); host_set_baudrate(hu, 2400);
ret = qca_send_power_pulse(hdev, QCA_WCN3990_POWEROFF_PULSE); ret = qca_send_power_pulse(hdev, QCA_WCN3990_POWEROFF_PULSE);
...@@ -1154,6 +1171,12 @@ static int qca_setup(struct hci_uart *hu) ...@@ -1154,6 +1171,12 @@ static int qca_setup(struct hci_uart *hu)
if (qcadev->btsoc_type == QCA_WCN3990) { if (qcadev->btsoc_type == QCA_WCN3990) {
bt_dev_info(hdev, "setting up 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); ret = qca_wcn3990_init(hu);
if (ret) if (ret)
return ret; return ret;
...@@ -1232,15 +1255,26 @@ static const struct qca_vreg_data qca_soc_data = { ...@@ -1232,15 +1255,26 @@ static const struct qca_vreg_data qca_soc_data = {
.num_vregs = 4, .num_vregs = 4,
}; };
static void qca_power_shutdown(struct hci_dev *hdev) static void qca_power_shutdown(struct hci_uart *hu)
{ {
struct hci_uart *hu = hci_get_drvdata(hdev); struct serdev_device *serdev = hu->serdev;
unsigned char cmd = QCA_WCN3990_POWEROFF_PULSE;
host_set_baudrate(hu, 2400); host_set_baudrate(hu, 2400);
qca_send_power_pulse(hdev, QCA_WCN3990_POWEROFF_PULSE); 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); qca_power_setup(hu, false);
} }
static int qca_power_off(struct hci_dev *hdev)
{
struct hci_uart *hu = hci_get_drvdata(hdev);
qca_power_shutdown(hu);
return 0;
}
static int qca_enable_regulator(struct qca_vreg vregs, static int qca_enable_regulator(struct qca_vreg vregs,
struct regulator *regulator) struct regulator *regulator)
{ {
...@@ -1413,7 +1447,7 @@ static void qca_serdev_remove(struct serdev_device *serdev) ...@@ -1413,7 +1447,7 @@ static void qca_serdev_remove(struct serdev_device *serdev)
struct qca_serdev *qcadev = serdev_device_get_drvdata(serdev); struct qca_serdev *qcadev = serdev_device_get_drvdata(serdev);
if (qcadev->btsoc_type == QCA_WCN3990) if (qcadev->btsoc_type == QCA_WCN3990)
qca_power_shutdown(qcadev->serdev_hu.hdev); qca_power_shutdown(&qcadev->serdev_hu);
else else
clk_disable_unprepare(qcadev->susclk); clk_disable_unprepare(qcadev->susclk);
......
...@@ -57,9 +57,10 @@ static inline struct sk_buff *hci_uart_dequeue(struct hci_uart *hu) ...@@ -57,9 +57,10 @@ static inline struct sk_buff *hci_uart_dequeue(struct hci_uart *hu)
{ {
struct sk_buff *skb = hu->tx_skb; struct sk_buff *skb = hu->tx_skb;
if (!skb) if (!skb) {
skb = hu->proto->dequeue(hu); if (test_bit(HCI_UART_PROTO_READY, &hu->flags))
else skb = hu->proto->dequeue(hu);
} else
hu->tx_skb = NULL; hu->tx_skb = NULL;
return skb; return skb;
...@@ -94,7 +95,7 @@ static void hci_uart_write_work(struct work_struct *work) ...@@ -94,7 +95,7 @@ static void hci_uart_write_work(struct work_struct *work)
hci_uart_tx_complete(hu, hci_skb_pkt_type(skb)); hci_uart_tx_complete(hu, hci_skb_pkt_type(skb));
kfree_skb(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); clear_bit(HCI_UART_SENDING, &hu->tx_state);
} }
...@@ -368,6 +369,7 @@ void hci_uart_unregister_device(struct hci_uart *hu) ...@@ -368,6 +369,7 @@ void hci_uart_unregister_device(struct hci_uart *hu)
{ {
struct hci_dev *hdev = hu->hdev; struct hci_dev *hdev = hu->hdev;
clear_bit(HCI_UART_PROTO_READY, &hu->flags);
hci_unregister_dev(hdev); hci_unregister_dev(hdev);
hci_free_dev(hdev); hci_free_dev(hdev);
......
...@@ -1517,6 +1517,20 @@ struct hci_cp_le_write_def_data_len { ...@@ -1517,6 +1517,20 @@ struct hci_cp_le_write_def_data_len {
__le16 tx_time; __le16 tx_time;
} __packed; } __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_CLEAR_RESOLV_LIST 0x2029
#define HCI_OP_LE_READ_RESOLV_LIST_SIZE 0x202a #define HCI_OP_LE_READ_RESOLV_LIST_SIZE 0x202a
......
...@@ -103,6 +103,14 @@ struct bdaddr_list { ...@@ -103,6 +103,14 @@ struct bdaddr_list {
u8 bdaddr_type; 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 bt_uuid {
struct list_head list; struct list_head list;
u8 uuid[16]; u8 uuid[16];
...@@ -259,6 +267,8 @@ struct hci_dev { ...@@ -259,6 +267,8 @@ struct hci_dev {
__u16 le_max_tx_time; __u16 le_max_tx_time;
__u16 le_max_rx_len; __u16 le_max_rx_len;
__u16 le_max_rx_time; __u16 le_max_rx_time;
__u8 le_max_key_size;
__u8 le_min_key_size;
__u16 discov_interleaved_timeout; __u16 discov_interleaved_timeout;
__u16 conn_info_min_age; __u16 conn_info_min_age;
__u16 conn_info_max_age; __u16 conn_info_max_age;
...@@ -1058,8 +1068,15 @@ int hci_inquiry(void __user *arg); ...@@ -1058,8 +1068,15 @@ int hci_inquiry(void __user *arg);
struct bdaddr_list *hci_bdaddr_list_lookup(struct list_head *list, struct bdaddr_list *hci_bdaddr_list_lookup(struct list_head *list,
bdaddr_t *bdaddr, u8 type); 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(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(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); void hci_bdaddr_list_clear(struct list_head *list);
struct hci_conn_params *hci_conn_params_lookup(struct hci_dev *hdev, struct hci_conn_params *hci_conn_params_lookup(struct hci_dev *hdev,
......
...@@ -455,9 +455,6 @@ struct l2cap_conn_param_update_rsp { ...@@ -455,9 +455,6 @@ struct l2cap_conn_param_update_rsp {
#define L2CAP_CONN_PARAM_ACCEPTED 0x0000 #define L2CAP_CONN_PARAM_ACCEPTED 0x0000
#define L2CAP_CONN_PARAM_REJECTED 0x0001 #define L2CAP_CONN_PARAM_REJECTED 0x0001
#define L2CAP_LE_MAX_CREDITS 10
#define L2CAP_LE_DEFAULT_MPS 230
struct l2cap_le_conn_req { struct l2cap_le_conn_req {
__le16 psm; __le16 psm;
__le16 scid; __le16 scid;
......
...@@ -489,9 +489,6 @@ static int bnep_session(void *arg) ...@@ -489,9 +489,6 @@ static int bnep_session(void *arg)
add_wait_queue(sk_sleep(sk), &wait); add_wait_queue(sk_sleep(sk), &wait);
while (1) { while (1) {
/* Ensure session->terminate is updated */
smp_mb__before_atomic();
if (atomic_read(&s->terminate)) if (atomic_read(&s->terminate))
break; break;
/* RX */ /* RX */
...@@ -512,6 +509,10 @@ static int bnep_session(void *arg) ...@@ -512,6 +509,10 @@ static int bnep_session(void *arg)
break; break;
netif_wake_queue(dev); 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); wait_woken(&wait, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
} }
remove_wait_queue(sk_sleep(sk), &wait); remove_wait_queue(sk_sleep(sk), &wait);
......
...@@ -288,9 +288,6 @@ static int cmtp_session(void *arg) ...@@ -288,9 +288,6 @@ static int cmtp_session(void *arg)
add_wait_queue(sk_sleep(sk), &wait); add_wait_queue(sk_sleep(sk), &wait);
while (1) { while (1) {
/* Ensure session->terminate is updated */
smp_mb__before_atomic();
if (atomic_read(&session->terminate)) if (atomic_read(&session->terminate))
break; break;
if (sk->sk_state != BT_CONNECTED) if (sk->sk_state != BT_CONNECTED)
...@@ -306,6 +303,10 @@ static int cmtp_session(void *arg) ...@@ -306,6 +303,10 @@ static int cmtp_session(void *arg)
cmtp_process_transmit(session); 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); wait_woken(&wait, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
} }
remove_wait_queue(sk_sleep(sk), &wait); remove_wait_queue(sk_sleep(sk), &wait);
...@@ -431,9 +432,10 @@ int cmtp_del_connection(struct cmtp_conndel_req *req) ...@@ -431,9 +432,10 @@ int cmtp_del_connection(struct cmtp_conndel_req *req)
/* Stop session thread */ /* Stop session thread */
atomic_inc(&session->terminate); 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)); wake_up_interruptible(sk_sleep(session->sock->sk));
} else } else
err = -ENOENT; err = -ENOENT;
......
...@@ -2839,6 +2839,20 @@ struct bdaddr_list *hci_bdaddr_list_lookup(struct list_head *bdaddr_list, ...@@ -2839,6 +2839,20 @@ struct bdaddr_list *hci_bdaddr_list_lookup(struct list_head *bdaddr_list,
return NULL; 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) void hci_bdaddr_list_clear(struct list_head *bdaddr_list)
{ {
struct bdaddr_list *b, *n; struct bdaddr_list *b, *n;
...@@ -2871,6 +2885,35 @@ int hci_bdaddr_list_add(struct list_head *list, bdaddr_t *bdaddr, u8 type) ...@@ -2871,6 +2885,35 @@ int hci_bdaddr_list_add(struct list_head *list, bdaddr_t *bdaddr, u8 type)
return 0; 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) int hci_bdaddr_list_del(struct list_head *list, bdaddr_t *bdaddr, u8 type)
{ {
struct bdaddr_list *entry; struct bdaddr_list *entry;
...@@ -2890,6 +2933,26 @@ int hci_bdaddr_list_del(struct list_head *list, bdaddr_t *bdaddr, u8 type) ...@@ -2890,6 +2933,26 @@ int hci_bdaddr_list_del(struct list_head *list, bdaddr_t *bdaddr, u8 type)
return 0; 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 */ /* This function requires the caller holds hdev->lock */
struct hci_conn_params *hci_conn_params_lookup(struct hci_dev *hdev, struct hci_conn_params *hci_conn_params_lookup(struct hci_dev *hdev,
bdaddr_t *addr, u8 addr_type) bdaddr_t *addr, u8 addr_type)
...@@ -3084,6 +3147,8 @@ struct hci_dev *hci_alloc_dev(void) ...@@ -3084,6 +3147,8 @@ struct hci_dev *hci_alloc_dev(void)
hdev->le_max_tx_time = 0x0148; hdev->le_max_tx_time = 0x0148;
hdev->le_max_rx_len = 0x001b; hdev->le_max_rx_len = 0x001b;
hdev->le_max_rx_time = 0x0148; 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_tx_def_phys = HCI_LE_SET_PHY_1M;
hdev->le_rx_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, ...@@ -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); 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, static void hci_cc_le_clear_resolv_list(struct hci_dev *hdev,
struct sk_buff *skb) struct sk_buff *skb)
{ {
...@@ -3279,6 +3318,14 @@ static void hci_cmd_complete_evt(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); hci_cc_le_write_def_data_len(hdev, skb);
break; 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: case HCI_OP_LE_CLEAR_RESOLV_LIST:
hci_cc_le_clear_resolv_list(hdev, skb); hci_cc_le_clear_resolv_list(hdev, skb);
break; break;
......
...@@ -1074,6 +1074,10 @@ static int hidp_session_start_sync(struct hidp_session *session) ...@@ -1074,6 +1074,10 @@ static int hidp_session_start_sync(struct hidp_session *session)
static void hidp_session_terminate(struct hidp_session *session) static void hidp_session_terminate(struct hidp_session *session)
{ {
atomic_inc(&session->terminate); atomic_inc(&session->terminate);
/*
* See the comment preceding the call to wait_woken()
* in hidp_session_run().
*/
wake_up_interruptible(&hidp_session_wq); wake_up_interruptible(&hidp_session_wq);
} }
...@@ -1193,8 +1197,6 @@ static void hidp_session_run(struct hidp_session *session) ...@@ -1193,8 +1197,6 @@ static void hidp_session_run(struct hidp_session *session)
* thread is woken up by ->sk_state_changed(). * thread is woken up by ->sk_state_changed().
*/ */
/* Ensure session->terminate is updated */
smp_mb__before_atomic();
if (atomic_read(&session->terminate)) if (atomic_read(&session->terminate))
break; break;
...@@ -1228,14 +1230,15 @@ static void hidp_session_run(struct hidp_session *session) ...@@ -1228,14 +1230,15 @@ static void hidp_session_run(struct hidp_session *session)
hidp_process_transmit(session, &session->ctrl_transmit, hidp_process_transmit(session, &session->ctrl_transmit,
session->ctrl_sock); 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); wait_woken(&wait, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
} }
remove_wait_queue(&hidp_session_wq, &wait); remove_wait_queue(&hidp_session_wq, &wait);
atomic_inc(&session->terminate); atomic_inc(&session->terminate);
/* Ensure session->terminate is updated */
smp_mb__after_atomic();
} }
static int hidp_session_wake_function(wait_queue_entry_t *wait, 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; ...@@ -51,9 +51,6 @@ static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN | L2CAP_FEAT_UCD;
static LIST_HEAD(chan_list); static LIST_HEAD(chan_list);
static DEFINE_RWLOCK(chan_list_lock); 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, static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
u8 code, u8 ident, u16 dlen, void *data); u8 code, u8 ident, u16 dlen, void *data);
static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, 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) ...@@ -519,8 +516,10 @@ static void l2cap_le_flowctl_init(struct l2cap_chan *chan)
chan->sdu_last_frag = NULL; chan->sdu_last_frag = NULL;
chan->sdu_len = 0; chan->sdu_len = 0;
chan->tx_credits = 0; chan->tx_credits = 0;
chan->rx_credits = le_max_credits; /* Derive MPS from connection MTU to stop HCI fragmentation */
chan->mps = min_t(u16, chan->imtu, le_default_mps); 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); skb_queue_head_init(&chan->tx_q);
} }
...@@ -1282,6 +1281,8 @@ static void l2cap_le_connect(struct l2cap_chan *chan) ...@@ -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)) if (test_and_set_bit(FLAG_LE_CONN_REQ_SENT, &chan->flags))
return; return;
l2cap_le_flowctl_init(chan);
req.psm = chan->psm; req.psm = chan->psm;
req.scid = cpu_to_le16(chan->scid); req.scid = cpu_to_le16(chan->scid);
req.mtu = cpu_to_le16(chan->imtu); req.mtu = cpu_to_le16(chan->imtu);
...@@ -5493,8 +5494,6 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn, ...@@ -5493,8 +5494,6 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn,
goto response_unlock; goto response_unlock;
} }
l2cap_le_flowctl_init(chan);
bacpy(&chan->src, &conn->hcon->src); bacpy(&chan->src, &conn->hcon->src);
bacpy(&chan->dst, &conn->hcon->dst); bacpy(&chan->dst, &conn->hcon->dst);
chan->src_type = bdaddr_src_type(conn->hcon); chan->src_type = bdaddr_src_type(conn->hcon);
...@@ -5506,6 +5505,9 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn, ...@@ -5506,6 +5505,9 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn,
chan->tx_credits = __le16_to_cpu(req->credits); chan->tx_credits = __le16_to_cpu(req->credits);
__l2cap_chan_add(conn, chan); __l2cap_chan_add(conn, chan);
l2cap_le_flowctl_init(chan);
dcid = chan->scid; dcid = chan->scid;
credits = chan->rx_credits; credits = chan->rx_credits;
...@@ -6699,13 +6701,10 @@ static void l2cap_chan_le_send_credits(struct l2cap_chan *chan) ...@@ -6699,13 +6701,10 @@ static void l2cap_chan_le_send_credits(struct l2cap_chan *chan)
struct l2cap_le_credits pkt; struct l2cap_le_credits pkt;
u16 return_credits; u16 return_credits;
/* We return more credits to the sender only after the amount of return_credits = ((chan->imtu / chan->mps) + 1) - chan->rx_credits;
* credits falls below half of the initial amount.
*/
if (chan->rx_credits >= (le_max_credits + 1) / 2)
return;
return_credits = le_max_credits - chan->rx_credits; if (!return_credits)
return;
BT_DBG("chan %p returning %u credits to sender", chan, return_credits); 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) ...@@ -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); 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) static int l2cap_le_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
{ {
int err; int err;
...@@ -6737,7 +6751,11 @@ static int l2cap_le_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) ...@@ -6737,7 +6751,11 @@ static int l2cap_le_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
chan->rx_credits--; chan->rx_credits--;
BT_DBG("rx_credits %u -> %u", chan->rx_credits + 1, 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; err = 0;
...@@ -6763,12 +6781,22 @@ static int l2cap_le_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) ...@@ -6763,12 +6781,22 @@ static int l2cap_le_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
} }
if (skb->len == sdu_len) if (skb->len == sdu_len)
return chan->ops->recv(chan, skb); return l2cap_le_recv(chan, skb);
chan->sdu = skb; chan->sdu = skb;
chan->sdu_len = sdu_len; chan->sdu_len = sdu_len;
chan->sdu_last_frag = skb; 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; return 0;
} }
...@@ -6785,7 +6813,7 @@ static int l2cap_le_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) ...@@ -6785,7 +6813,7 @@ static int l2cap_le_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
skb = NULL; skb = NULL;
if (chan->sdu->len == chan->sdu_len) { if (chan->sdu->len == chan->sdu_len) {
err = chan->ops->recv(chan, chan->sdu); err = l2cap_le_recv(chan, chan->sdu);
if (!err) { if (!err) {
chan->sdu = NULL; chan->sdu = NULL;
chan->sdu_last_frag = NULL; chan->sdu_last_frag = NULL;
...@@ -7102,7 +7130,6 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, ...@@ -7102,7 +7130,6 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
case L2CAP_MODE_BASIC: case L2CAP_MODE_BASIC:
break; break;
case L2CAP_MODE_LE_FLOWCTL: case L2CAP_MODE_LE_FLOWCTL:
l2cap_le_flowctl_init(chan);
break; break;
case L2CAP_MODE_ERTM: case L2CAP_MODE_ERTM:
case L2CAP_MODE_STREAMING: case L2CAP_MODE_STREAMING:
...@@ -7645,11 +7672,6 @@ int __init l2cap_init(void) ...@@ -7645,11 +7672,6 @@ int __init l2cap_init(void)
l2cap_debugfs = debugfs_create_file("l2cap", 0444, bt_debugfs, l2cap_debugfs = debugfs_create_file("l2cap", 0444, bt_debugfs,
NULL, &l2cap_debugfs_fops); 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; return 0;
} }
......
...@@ -88,9 +88,6 @@ struct smp_dev { ...@@ -88,9 +88,6 @@ struct smp_dev {
u8 local_rand[16]; u8 local_rand[16];
bool debug_key; bool debug_key;
u8 min_key_size;
u8 max_key_size;
struct crypto_cipher *tfm_aes; struct crypto_cipher *tfm_aes;
struct crypto_shash *tfm_cmac; struct crypto_shash *tfm_cmac;
struct crypto_kpp *tfm_ecdh; struct crypto_kpp *tfm_ecdh;
...@@ -720,7 +717,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn, ...@@ -720,7 +717,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
if (rsp == NULL) { if (rsp == NULL) {
req->io_capability = conn->hcon->io_capability; req->io_capability = conn->hcon->io_capability;
req->oob_flag = oob_flag; 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->init_key_dist = local_dist;
req->resp_key_dist = remote_dist; req->resp_key_dist = remote_dist;
req->auth_req = (authreq & AUTH_REQ_MASK(hdev)); req->auth_req = (authreq & AUTH_REQ_MASK(hdev));
...@@ -731,7 +728,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn, ...@@ -731,7 +728,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
rsp->io_capability = conn->hcon->io_capability; rsp->io_capability = conn->hcon->io_capability;
rsp->oob_flag = oob_flag; 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->init_key_dist = req->init_key_dist & remote_dist;
rsp->resp_key_dist = req->resp_key_dist & local_dist; rsp->resp_key_dist = req->resp_key_dist & local_dist;
rsp->auth_req = (authreq & AUTH_REQ_MASK(hdev)); 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) ...@@ -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 hci_dev *hdev = conn->hcon->hdev;
struct smp_chan *smp = chan->data; 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) max_key_size < SMP_MIN_ENC_KEY_SIZE)
return SMP_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) ...@@ -3243,8 +3240,6 @@ static struct l2cap_chan *smp_add_cid(struct hci_dev *hdev, u16 cid)
smp->tfm_aes = tfm_aes; smp->tfm_aes = tfm_aes;
smp->tfm_cmac = tfm_cmac; smp->tfm_cmac = tfm_cmac;
smp->tfm_ecdh = tfm_ecdh; 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: create_chan:
chan = l2cap_chan_create(); chan = l2cap_chan_create();
...@@ -3370,7 +3365,7 @@ static ssize_t le_min_key_size_read(struct file *file, ...@@ -3370,7 +3365,7 @@ static ssize_t le_min_key_size_read(struct file *file,
struct hci_dev *hdev = file->private_data; struct hci_dev *hdev = file->private_data;
char buf[4]; 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)); 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, ...@@ -3391,11 +3386,11 @@ static ssize_t le_min_key_size_write(struct file *file,
sscanf(buf, "%hhu", &key_size); 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) key_size < SMP_MIN_ENC_KEY_SIZE)
return -EINVAL; return -EINVAL;
SMP_DEV(hdev)->min_key_size = key_size; hdev->le_min_key_size = key_size;
return count; return count;
} }
...@@ -3414,7 +3409,7 @@ static ssize_t le_max_key_size_read(struct file *file, ...@@ -3414,7 +3409,7 @@ static ssize_t le_max_key_size_read(struct file *file,
struct hci_dev *hdev = file->private_data; struct hci_dev *hdev = file->private_data;
char buf[4]; 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)); 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, ...@@ -3436,10 +3431,10 @@ static ssize_t le_max_key_size_write(struct file *file,
sscanf(buf, "%hhu", &key_size); sscanf(buf, "%hhu", &key_size);
if (key_size > SMP_MAX_ENC_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; return -EINVAL;
SMP_DEV(hdev)->max_key_size = key_size; hdev->le_max_key_size = key_size;
return count; return count;
} }
......
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