From 7d69230c4381a5abc7286a8dfc893268e14e6ead Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Fri, 9 Mar 2012 11:46:49 +0200 Subject: Bluetooth: Correct type for hdev lmp_subver Keep lmp_subver in host byte order. We have following conversion in hci_cc_read_local_version: hdev->lmp_subver = __le16_to_cpu(rp->lmp_subver); Signed-off-by: Andrei Emeltchenko Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/hci_core.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index db1c5df4522..53e8eb2f0a2 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -155,7 +155,7 @@ struct hci_dev { __u16 hci_rev; __u8 lmp_ver; __u16 manufacturer; - __le16 lmp_subver; + __u16 lmp_subver; __u16 voice_setting; __u8 io_capability; -- cgit v1.2.3-70-g09d2 From 9a0066579270584108f1f2f97d98fe989d8117df Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Fri, 9 Mar 2012 12:12:12 +0200 Subject: Bluetooth: Correct type for ediv to __le16 Correct type warnings reported by sparse to show that this functions takes ediv argument in __le16 format. Signed-off-by: Andrei Emeltchenko Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/hci_core.h | 4 ++-- net/bluetooth/hci_core.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 53e8eb2f0a2..0eec5dbaee0 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -673,8 +673,8 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len); struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8]); int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type, - int new_key, u8 authenticated, u8 tk[16], u8 enc_size, u16 ediv, - u8 rand[8]); + int new_key, u8 authenticated, u8 tk[16], u8 enc_size, + __le16 ediv, u8 rand[8]); struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type); int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index edfd61addce..af55ea1b688 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1336,7 +1336,7 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, } int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type, - int new_key, u8 authenticated, u8 tk[16], u8 enc_size, u16 + int new_key, u8 authenticated, u8 tk[16], u8 enc_size, __le16 ediv, u8 rand[8]) { struct smp_ltk *key, *old_key; -- cgit v1.2.3-70-g09d2 From 6935e0f5181644201894f0b7fbe3d8910c18af05 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Fri, 9 Mar 2012 15:53:42 +0100 Subject: Bluetooth: Remove redundant hdev->parent field We initialize the "struct device" in hci_alloc_dev() for a long time now so we can access hdev->dev.parent directly. Hence, we can drop the temporary field hdev->parent which is used in no other place than hci_add_sysfs(). SET_HCIDEV_DEV() is never called after registering a device by the drivers so we do not overwrite internal device-state. Furthermore, hdev->dev is initialized to 0 by kzalloc() inside hci_alloc_dev() so the default behavior with dev.parent = NULL is kept. Signed-off-by: David Herrmann Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/hci_ldisc.c | 2 +- include/net/bluetooth/hci_core.h | 3 +-- net/bluetooth/hci_sysfs.c | 1 - 3 files changed, 2 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 98a8c05d4f2..e564579a611 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -388,7 +388,7 @@ static int hci_uart_register_dev(struct hci_uart *hu) hdev->close = hci_uart_close; hdev->flush = hci_uart_flush; hdev->send = hci_uart_send_frame; - hdev->parent = hu->tty->dev; + SET_HCIDEV_DEV(hdev, hu->tty->dev); if (test_bit(HCI_UART_RAW_DEVICE, &hu->hdev_flags)) set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks); diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 0eec5dbaee0..c80a9684a14 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -263,7 +263,6 @@ struct hci_dev { struct dentry *debugfs; - struct device *parent; struct device dev; struct rfkill *rfkill; @@ -709,7 +708,7 @@ void hci_conn_init_sysfs(struct hci_conn *conn); void hci_conn_add_sysfs(struct hci_conn *conn); void hci_conn_del_sysfs(struct hci_conn *conn); -#define SET_HCIDEV_DEV(hdev, pdev) ((hdev)->parent = (pdev)) +#define SET_HCIDEV_DEV(hdev, pdev) ((hdev)->dev.parent = (pdev)) /* ----- LMP capabilities ----- */ #define lmp_rswitch_capable(dev) ((dev)->features[0] & LMP_RSWITCH) diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index bc154298979..60b93d8219e 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c @@ -533,7 +533,6 @@ int hci_add_sysfs(struct hci_dev *hdev) BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus); - dev->parent = hdev->parent; dev_set_name(dev, "%s", hdev->name); err = device_add(dev); -- cgit v1.2.3-70-g09d2 From 91c4e9b1ac595f83681c9a9de691e0f30eeafb44 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 11 Mar 2012 19:27:21 -0700 Subject: Bluetooth: Add TX power tag to EIR data The Inquiry Response TX power tag should be added to the Extended Inquiry Data (EIR) as well. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 4 ++++ include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_event.c | 9 ++++++--- net/bluetooth/mgmt.c | 9 +++++++++ 4 files changed, 20 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index d47e523c9d8..3edb3e759ff 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -717,6 +717,10 @@ struct hci_rp_read_local_oob_data { } __packed; #define HCI_OP_READ_INQ_RSP_TX_POWER 0x0c58 +struct hci_rp_read_inq_rsp_tx_power { + __u8 status; + __s8 tx_power; +} __packed; #define HCI_OP_READ_FLOW_CONTROL_MODE 0x0c66 struct hci_rp_read_flow_control_mode { diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index c80a9684a14..ce09bf1592e 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -158,6 +158,7 @@ struct hci_dev { __u16 lmp_subver; __u16 voice_setting; __u8 io_capability; + __s8 inq_tx_power; __u16 pkt_type; __u16 esco_type; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 50ff9a98953..75f01d1b126 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -887,11 +887,14 @@ static void hci_cc_write_inquiry_mode(struct hci_dev *hdev, static void hci_cc_read_inq_rsp_tx_power(struct hci_dev *hdev, struct sk_buff *skb) { - __u8 status = *((__u8 *) skb->data); + struct hci_rp_read_inq_rsp_tx_power *rp = (void *) skb->data; - BT_DBG("%s status 0x%x", hdev->name, status); + BT_DBG("%s status 0x%x", hdev->name, rp->status); + + if (!rp->status) + hdev->inq_tx_power = rp->tx_power; - hci_req_complete(hdev, HCI_OP_READ_INQ_RSP_TX_POWER, status); + hci_req_complete(hdev, HCI_OP_READ_INQ_RSP_TX_POWER, rp->status); } static void hci_cc_set_event_flt(struct hci_dev *hdev, struct sk_buff *skb) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 4a2fb06226f..02b89e299ff 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -479,6 +479,15 @@ static void create_eir(struct hci_dev *hdev, u8 *data) ptr += (name_len + 2); } + if (hdev->inq_tx_power) { + ptr[0] = 2; + ptr[1] = EIR_TX_POWER; + ptr[2] = (u8) hdev->inq_tx_power; + + eir_len += 3; + ptr += 3; + } + memset(uuid16_list, 0, sizeof(uuid16_list)); /* Group all UUID16 types */ -- cgit v1.2.3-70-g09d2 From 2b9be137b70bef9ec7835d83e225d8b35ba9c7ae Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 11 Mar 2012 19:32:12 -0700 Subject: Bluetooth: Handle EIR tags for Device ID The Device ID information can be provided via Extended Inquiry Data as well. If a valid source is present, then include it. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 4 ++++ net/bluetooth/mgmt.c | 13 +++++++++++++ 2 files changed, 17 insertions(+) (limited to 'include') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index ce09bf1592e..c8e24a9b176 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -159,6 +159,10 @@ struct hci_dev { __u16 voice_setting; __u8 io_capability; __s8 inq_tx_power; + __u16 devid_source; + __u16 devid_vendor; + __u16 devid_product; + __u16 devid_version; __u16 pkt_type; __u16 esco_type; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 02b89e299ff..1da458d9b5c 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -488,6 +488,19 @@ static void create_eir(struct hci_dev *hdev, u8 *data) ptr += 3; } + if (hdev->devid_source > 0) { + ptr[0] = 9; + ptr[1] = EIR_DEVICE_ID; + + put_unaligned_le16(hdev->devid_source, ptr + 2); + put_unaligned_le16(hdev->devid_vendor, ptr + 4); + put_unaligned_le16(hdev->devid_product, ptr + 6); + put_unaligned_le16(hdev->devid_version, ptr + 8); + + eir_len += 10; + ptr += 10; + } + memset(uuid16_list, 0, sizeof(uuid16_list)); /* Group all UUID16 types */ -- cgit v1.2.3-70-g09d2 From cdbaccca733c9dde3faf150150102dade311c91f Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 11 Mar 2012 20:00:29 -0700 Subject: Bluetooth: Add management command for setting Device ID The Device ID details need to be programmed into the kernel for every controller at least once. So provide management command for this. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/mgmt.h | 9 +++++++++ net/bluetooth/mgmt.c | 26 ++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) (limited to 'include') diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index ebfd91fc20f..23fd0546fcc 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -341,6 +341,15 @@ struct mgmt_cp_unblock_device { } __packed; #define MGMT_UNBLOCK_DEVICE_SIZE MGMT_ADDR_INFO_SIZE +#define MGMT_OP_SET_DEVICE_ID 0x0028 +struct mgmt_cp_set_device_id { + __le16 source; + __le16 vendor; + __le16 product; + __le16 version; +} __packed; +#define MGMT_SET_DEVICE_ID_SIZE 8 + #define MGMT_EV_CMD_COMPLETE 0x0001 struct mgmt_ev_cmd_complete { __le16 opcode; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 1da458d9b5c..5e88fda42f1 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -78,6 +78,7 @@ static const u16 mgmt_commands[] = { MGMT_OP_CONFIRM_NAME, MGMT_OP_BLOCK_DEVICE, MGMT_OP_UNBLOCK_DEVICE, + MGMT_OP_SET_DEVICE_ID, }; static const u16 mgmt_events[] = { @@ -2523,6 +2524,30 @@ static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data, return err; } +static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data, + u16 len) +{ + struct mgmt_cp_set_device_id *cp = data; + int err; + + BT_DBG("%s", hdev->name); + + hci_dev_lock(hdev); + + hdev->devid_source = __le16_to_cpu(cp->source); + hdev->devid_vendor = __le16_to_cpu(cp->vendor); + hdev->devid_product = __le16_to_cpu(cp->product); + hdev->devid_version = __le16_to_cpu(cp->version); + + err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0); + + update_eir(hdev); + + hci_dev_unlock(hdev); + + return err; +} + static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) { @@ -2669,6 +2694,7 @@ struct mgmt_handler { { confirm_name, false, MGMT_CONFIRM_NAME_SIZE }, { block_device, false, MGMT_BLOCK_DEVICE_SIZE }, { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE }, + { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE }, }; -- cgit v1.2.3-70-g09d2 From 58115373e74c7ee18d0f54f00831649a6471a899 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Mon, 12 Mar 2012 12:13:06 +0200 Subject: Bluetooth: Correct ediv in SMP ediv is already in little endian order. Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/smp.h | 2 +- net/bluetooth/smp.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/smp.h b/include/net/bluetooth/smp.h index 7b3acdd2913..ca356a73492 100644 --- a/include/net/bluetooth/smp.h +++ b/include/net/bluetooth/smp.h @@ -77,7 +77,7 @@ struct smp_cmd_encrypt_info { #define SMP_CMD_MASTER_IDENT 0x07 struct smp_cmd_master_ident { - __u16 ediv; + __le16 ediv; __u8 rand[8]; } __packed; diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index deb119875fd..6fc7c4708f3 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -956,7 +956,7 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) HCI_SMP_LTK_SLAVE, 1, authenticated, enc.ltk, smp->enc_key_size, ediv, ident.rand); - ident.ediv = cpu_to_le16(ediv); + ident.ediv = ediv; smp_send_cmd(conn, SMP_CMD_MASTER_IDENT, sizeof(ident), &ident); -- cgit v1.2.3-70-g09d2 From 7dbfac1d720d3ea68e00e187bbd2f1147257528b Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Thu, 15 Mar 2012 16:52:07 -0300 Subject: Bluetooth: Add hci_cancel_le_scan() to hci_core This patch adds to hci_core the hci_cancel_le_scan function which should be used to cancel an ongoing LE scan. Signed-off-by: Andre Guedes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_core.c | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) (limited to 'include') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index c8e24a9b176..f7cf928ab6f 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1078,5 +1078,6 @@ int hci_do_inquiry(struct hci_dev *hdev, u8 length); int hci_cancel_inquiry(struct hci_dev *hdev); int hci_le_scan(struct hci_dev *hdev, u8 type, u16 interval, u16 window, int timeout); +int hci_cancel_le_scan(struct hci_dev *hdev); #endif /* __HCI_CORE_H */ diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 47a4e9b26b9..e3920b693f0 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1671,6 +1671,24 @@ static int hci_do_le_scan(struct hci_dev *hdev, u8 type, u16 interval, return 0; } +int hci_cancel_le_scan(struct hci_dev *hdev) +{ + BT_DBG("%s", hdev->name); + + if (!test_bit(HCI_LE_SCAN, &hdev->dev_flags)) + return -EALREADY; + + if (cancel_delayed_work(&hdev->le_scan_disable)) { + struct hci_cp_le_set_scan_enable cp; + + /* Send HCI command to disable LE Scan */ + memset(&cp, 0, sizeof(cp)); + hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp); + } + + return 0; +} + static void le_scan_disable_work(struct work_struct *work) { struct hci_dev *hdev = container_of(work, struct hci_dev, -- cgit v1.2.3-70-g09d2 From 79d6e068bee82e9998b2be78bc0f08f2dec8777a Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Wed, 21 Mar 2012 00:03:35 -0300 Subject: Bluetooth: Add Periodic Inquiry command complete handler This patch adds a handler function to Periodic Inquiry command complete event. Signed-off-by: Andre Guedes Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- include/net/bluetooth/hci.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 3edb3e759ff..9cf088db486 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -324,6 +324,8 @@ struct hci_cp_inquiry { #define HCI_OP_INQUIRY_CANCEL 0x0402 +#define HCI_OP_PERIODIC_INQ 0x0403 + #define HCI_OP_EXIT_PERIODIC_INQ 0x0404 #define HCI_OP_CREATE_CONN 0x0405 -- cgit v1.2.3-70-g09d2 From 21693c15c0c3be1aac16eee19497a545f12b1a37 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Wed, 21 Mar 2012 00:03:36 -0300 Subject: Bluetooth: Add HCI_PERIODIC_INQ to dev_flags This patch adds the HCI_PERIODIC_INQ flag to dev_flags. This flag tracks if periodic inquiry is enabled or not. Signed-off-by: Andre Guedes Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- include/net/bluetooth/hci.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 9cf088db486..346f0877979 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -102,6 +102,7 @@ enum { HCI_DISCOVERABLE, HCI_LINK_SECURITY, HCI_PENDING_CLASS, + HCI_PERIODIC_INQ, }; /* HCI ioctl defines */ -- cgit v1.2.3-70-g09d2 From 6f74b6f36fc06fafb0c5868563385a59dc22b1b2 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Fri, 23 Mar 2012 16:31:50 +0200 Subject: Bluetooth: Comments and style fixes Add comments to timer implementation and style fixes. Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- include/net/bluetooth/l2cap.h | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 9b242c6bf55..35334a0de07 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -622,21 +622,26 @@ static inline void l2cap_chan_unlock(struct l2cap_chan *chan) } static inline void l2cap_set_timer(struct l2cap_chan *chan, - struct delayed_work *work, long timeout) + struct delayed_work *work, long timeout) { BT_DBG("chan %p state %s timeout %ld", chan, - state_to_string(chan->state), timeout); + state_to_string(chan->state), timeout); + /* If delayed work cancelled do not hold(chan) + since it is already done with previous set_timer */ if (!cancel_delayed_work(work)) l2cap_chan_hold(chan); + schedule_delayed_work(work, timeout); } static inline bool l2cap_clear_timer(struct l2cap_chan *chan, - struct delayed_work *work) + struct delayed_work *work) { bool ret; + /* put(chan) if delayed work cancelled otherwise it + is done in delayed work function */ ret = cancel_delayed_work(work); if (ret) l2cap_chan_put(chan); -- cgit v1.2.3-70-g09d2 From d5f7ac38102c12069de247890cfdd357bf845a77 Mon Sep 17 00:00:00 2001 From: Mat Martineau Date: Fri, 23 Mar 2012 16:56:55 -0700 Subject: Bluetooth: Add definitions and struct members for new ERTM state machine Adds some missing values for control field parsing, additional data for the new state machine, and enumerations for states, incoming packet classification, and state machine events. Signed-off-by: Mat Martineau Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- include/net/bluetooth/l2cap.h | 49 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) (limited to 'include') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 35334a0de07..c988df6f63b 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -139,6 +139,8 @@ struct l2cap_conninfo { #define L2CAP_CTRL_TXSEQ_SHIFT 1 #define L2CAP_CTRL_SUPER_SHIFT 2 +#define L2CAP_CTRL_POLL_SHIFT 4 +#define L2CAP_CTRL_FINAL_SHIFT 7 #define L2CAP_CTRL_REQSEQ_SHIFT 8 #define L2CAP_CTRL_SAR_SHIFT 14 @@ -152,9 +154,11 @@ struct l2cap_conninfo { #define L2CAP_EXT_CTRL_FINAL 0x00000002 #define L2CAP_EXT_CTRL_FRAME_TYPE 0x00000001 /* I- or S-Frame */ +#define L2CAP_EXT_CTRL_FINAL_SHIFT 1 #define L2CAP_EXT_CTRL_REQSEQ_SHIFT 2 #define L2CAP_EXT_CTRL_SAR_SHIFT 16 #define L2CAP_EXT_CTRL_SUPER_SHIFT 16 +#define L2CAP_EXT_CTRL_POLL_SHIFT 18 #define L2CAP_EXT_CTRL_TXSEQ_SHIFT 18 /* L2CAP Supervisory Function */ @@ -186,6 +190,8 @@ struct l2cap_hdr { #define L2CAP_FCS_SIZE 2 #define L2CAP_SDULEN_SIZE 2 #define L2CAP_PSMLEN_SIZE 2 +#define L2CAP_ENH_CTRL_SIZE 2 +#define L2CAP_EXT_CTRL_SIZE 4 struct l2cap_cmd_hdr { __u8 code; @@ -446,6 +452,9 @@ struct l2cap_chan { __u16 monitor_timeout; __u16 mps; + __u8 tx_state; + __u8 rx_state; + unsigned long conf_state; unsigned long conn_state; unsigned long flags; @@ -456,9 +465,11 @@ struct l2cap_chan { __u16 buffer_seq; __u16 buffer_seq_srej; __u16 srej_save_reqseq; + __u16 last_acked_seq; __u16 frames_sent; __u16 unacked_frames; __u8 retry_count; + __u16 srej_queue_next; __u8 num_acked; __u16 sdu_len; struct sk_buff *sdu; @@ -600,6 +611,44 @@ enum { FLAG_EFS_ENABLE, }; +enum { + L2CAP_TX_STATE_XMIT, + L2CAP_TX_STATE_WAIT_F, +}; + +enum { + L2CAP_RX_STATE_RECV, + L2CAP_RX_STATE_SREJ_SENT, +}; + +enum { + L2CAP_TXSEQ_EXPECTED, + L2CAP_TXSEQ_EXPECTED_SREJ, + L2CAP_TXSEQ_UNEXPECTED, + L2CAP_TXSEQ_UNEXPECTED_SREJ, + L2CAP_TXSEQ_DUPLICATE, + L2CAP_TXSEQ_DUPLICATE_SREJ, + L2CAP_TXSEQ_INVALID, + L2CAP_TXSEQ_INVALID_IGNORE, +}; + +enum { + L2CAP_EV_DATA_REQUEST, + L2CAP_EV_LOCAL_BUSY_DETECTED, + L2CAP_EV_LOCAL_BUSY_CLEAR, + L2CAP_EV_RECV_REQSEQ_AND_FBIT, + L2CAP_EV_RECV_FBIT, + L2CAP_EV_RETRANS_TO, + L2CAP_EV_MONITOR_TO, + L2CAP_EV_EXPLICIT_POLL, + L2CAP_EV_RECV_IFRAME, + L2CAP_EV_RECV_RR, + L2CAP_EV_RECV_REJ, + L2CAP_EV_RECV_RNR, + L2CAP_EV_RECV_SREJ, + L2CAP_EV_RECV_FRAME, +}; + static inline void l2cap_chan_hold(struct l2cap_chan *c) { atomic_inc(&c->refcnt); -- cgit v1.2.3-70-g09d2 From 00e3112c5a90963bb7b56e0648d22fc51ed17d23 Mon Sep 17 00:00:00 2001 From: Mat Martineau Date: Fri, 23 Mar 2012 16:56:56 -0700 Subject: Bluetooth: Add a structure to carry ERTM data in skb control blocks Every field from ERTM control headers is now carried in the control block so it only has to be parsed or generated once, and can be efficiently accessed throughout the ERTM code. Signed-off-by: Mat Martineau Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- include/net/bluetooth/bluetooth.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'include') diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 262ebd1747d..f2c8bdf0806 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -215,6 +215,18 @@ void bt_accept_unlink(struct sock *sk); struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock); /* Skb helpers */ +struct l2cap_ctrl { + unsigned int sframe : 1, + poll : 1, + final : 1, + fcs : 1, + sar : 2, + super : 2; + __u16 reqseq; + __u16 txseq; + __u8 retries; +}; + struct bt_skb_cb { __u8 pkt_type; __u8 incoming; @@ -223,6 +235,7 @@ struct bt_skb_cb { __u8 retries; __u8 sar; __u8 force_active; + struct l2cap_ctrl control; }; #define bt_cb(skb) ((struct bt_skb_cb *)((skb)->cb)) -- cgit v1.2.3-70-g09d2 From eef1d9b668c51dcae58d8bb41ce0c805f866dbbd Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Sun, 25 Mar 2012 13:59:16 -0300 Subject: Bluetooth: Remove sk parameter from l2cap_chan_create() Following the separation if core and sock code this change avoid manipulation of sk inside l2cap_chan_create(). Signed-off-by: Gustavo Padovan --- include/net/bluetooth/l2cap.h | 2 +- net/bluetooth/l2cap_core.c | 6 ++---- net/bluetooth/l2cap_sock.c | 4 +++- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index c988df6f63b..f6f0500bf37 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -906,7 +906,7 @@ int __l2cap_wait_ack(struct sock *sk); int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm); int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid); -struct l2cap_chan *l2cap_chan_create(struct sock *sk); +struct l2cap_chan *l2cap_chan_create(void); void l2cap_chan_close(struct l2cap_chan *chan, int reason); void l2cap_chan_destroy(struct l2cap_chan *chan); int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 8a3de114935..a57d96afa24 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -262,7 +262,7 @@ static void l2cap_chan_timeout(struct work_struct *work) l2cap_chan_put(chan); } -struct l2cap_chan *l2cap_chan_create(struct sock *sk) +struct l2cap_chan *l2cap_chan_create(void) { struct l2cap_chan *chan; @@ -272,8 +272,6 @@ struct l2cap_chan *l2cap_chan_create(struct sock *sk) mutex_init(&chan->lock); - chan->sk = sk; - write_lock(&chan_list_lock); list_add(&chan->global_l, &chan_list); write_unlock(&chan_list_lock); @@ -284,7 +282,7 @@ struct l2cap_chan *l2cap_chan_create(struct sock *sk) atomic_set(&chan->refcnt, 1); - BT_DBG("sk %p chan %p", sk, chan); + BT_DBG("chan %p", chan); return chan; } diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 29122ed28ea..53e563f0172 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -1048,12 +1048,14 @@ static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int p sk->sk_protocol = proto; sk->sk_state = BT_OPEN; - chan = l2cap_chan_create(sk); + chan = l2cap_chan_create(); if (!chan) { l2cap_sock_kill(sk); return NULL; } + chan->sk = sk; + l2cap_pi(sk)->chan = chan; return sk; -- cgit v1.2.3-70-g09d2 From 0ed09148fa61e01cd27c92933ba275ea8078b34d Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Tue, 3 Apr 2012 08:46:54 -0300 Subject: Bluetooth: Remove MGMT_ADDR_INVALID macro This patch removes the MGMT_ADDR_INVALID macro. If the address type isn't LE, we consider it is BR/EDR type. Signed-off-by: Andre Guedes Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 1 - net/bluetooth/mgmt.c | 14 +++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index f7cf928ab6f..afdea9530d7 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -968,7 +968,6 @@ void hci_sock_dev_event(struct hci_dev *hdev, int event); #define MGMT_ADDR_BREDR 0x00 #define MGMT_ADDR_LE_PUBLIC 0x01 #define MGMT_ADDR_LE_RANDOM 0x02 -#define MGMT_ADDR_INVALID 0xff #define DISCOV_TYPE_BREDR (BIT(MGMT_ADDR_BREDR)) #define DISCOV_TYPE_LE (BIT(MGMT_ADDR_LE_PUBLIC) | \ diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 1ec16721ed7..5e80c6db6ae 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1640,15 +1640,15 @@ static u8 link_to_mgmt(u8 link_type, u8 addr_type) switch (addr_type) { case ADDR_LE_DEV_PUBLIC: return MGMT_ADDR_LE_PUBLIC; - case ADDR_LE_DEV_RANDOM: - return MGMT_ADDR_LE_RANDOM; + default: - return MGMT_ADDR_INVALID; + /* Fallback to LE Random address type */ + return MGMT_ADDR_LE_RANDOM; } - case ACL_LINK: - return MGMT_ADDR_BREDR; + default: - return MGMT_ADDR_INVALID; + /* Fallback to BR/EDR type */ + return MGMT_ADDR_BREDR; } } @@ -1690,7 +1690,7 @@ static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data, continue; bacpy(&rp->addr[i].bdaddr, &c->dst); rp->addr[i].type = link_to_mgmt(c->type, c->dst_type); - if (rp->addr[i].type == MGMT_ADDR_INVALID) + if (c->type == SCO_LINK || c->type == ESCO_LINK) continue; i++; } -- cgit v1.2.3-70-g09d2 From bd4b165312bacbf1e732cbc22c141362cfb5fda3 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Wed, 28 Mar 2012 16:31:25 +0300 Subject: Bluetooth: Adds set_default function in L2CAP setup Some parameters in L2CAP chan are set to default similar way in socket based channels and A2MP channels. Adds common function which sets all defaults. Signed-off-by: Andrei Emeltchenko Signed-off-by: Gustavo Padovan --- include/net/bluetooth/l2cap.h | 1 + net/bluetooth/l2cap_core.c | 11 +++++++++++ net/bluetooth/l2cap_sock.c | 8 ++------ 3 files changed, 14 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index f6f0500bf37..c70e2cf107f 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -915,5 +915,6 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len, u32 priority); void l2cap_chan_busy(struct l2cap_chan *chan, int busy); int l2cap_chan_check_security(struct l2cap_chan *chan); +void l2cap_chan_set_defaults(struct l2cap_chan *chan); #endif /* __L2CAP_H */ diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index a57d96afa24..2eac6184a23 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -296,6 +296,17 @@ void l2cap_chan_destroy(struct l2cap_chan *chan) l2cap_chan_put(chan); } +void l2cap_chan_set_defaults(struct l2cap_chan *chan) +{ + chan->fcs = L2CAP_FCS_CRC16; + chan->max_tx = L2CAP_DEFAULT_MAX_TX; + chan->tx_win = L2CAP_DEFAULT_TX_WINDOW; + chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW; + chan->sec_level = BT_SECURITY_LOW; + + set_bit(FLAG_FORCE_ACTIVE, &chan->flags); +} + static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) { BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 1d3e9c328a3..ae1d78ee041 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -1006,12 +1006,8 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent) } else { chan->mode = L2CAP_MODE_BASIC; } - chan->max_tx = L2CAP_DEFAULT_MAX_TX; - chan->fcs = L2CAP_FCS_CRC16; - chan->tx_win = L2CAP_DEFAULT_TX_WINDOW; - chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW; - chan->sec_level = BT_SECURITY_LOW; - set_bit(FLAG_FORCE_ACTIVE, &chan->flags); + + l2cap_chan_set_defaults(chan); } /* Default config options */ -- cgit v1.2.3-70-g09d2 From 9033894722ec595053c92bfa4359b37e7bc91b78 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Fri, 6 Apr 2012 20:15:47 -0300 Subject: Bluetooth: Remove err parameter from alloc_skb() Use ERR_PTR maginc instead. Signed-off-by: Gustavo Padovan Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/l2cap.h | 2 +- net/bluetooth/l2cap_core.c | 30 +++++++++++++----------------- net/bluetooth/l2cap_sock.c | 12 ++++++++---- 3 files changed, 22 insertions(+), 22 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index c70e2cf107f..a756c240630 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -519,7 +519,7 @@ struct l2cap_ops { void (*close) (void *data); void (*state_change) (void *data, int state); struct sk_buff *(*alloc_skb) (struct l2cap_chan *chan, - unsigned long len, int nb, int *err); + unsigned long len, int nb); }; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 2eac6184a23..03746f565fc 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1563,7 +1563,7 @@ static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan, { struct l2cap_conn *conn = chan->conn; struct sk_buff **frag; - int err, sent = 0; + int sent = 0; if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) return -EFAULT; @@ -1577,11 +1577,10 @@ static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan, count = min_t(unsigned int, conn->mtu, len); *frag = chan->ops->alloc_skb(chan, count, - msg->msg_flags & MSG_DONTWAIT, - &err); + msg->msg_flags & MSG_DONTWAIT); - if (!*frag) - return err; + if (IS_ERR(*frag)) + return PTR_ERR(*frag); if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count)) return -EFAULT; @@ -1610,10 +1609,9 @@ static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, count = min_t(unsigned int, (conn->mtu - hlen), len); skb = chan->ops->alloc_skb(chan, count + hlen, - msg->msg_flags & MSG_DONTWAIT, &err); - - if (!skb) - return ERR_PTR(err); + msg->msg_flags & MSG_DONTWAIT); + if (IS_ERR(skb)) + return skb; skb->priority = priority; @@ -1645,10 +1643,9 @@ static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, count = min_t(unsigned int, (conn->mtu - hlen), len); skb = chan->ops->alloc_skb(chan, count + hlen, - msg->msg_flags & MSG_DONTWAIT, &err); - - if (!skb) - return ERR_PTR(err); + msg->msg_flags & MSG_DONTWAIT); + if (IS_ERR(skb)) + return skb; skb->priority = priority; @@ -1693,10 +1690,9 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, count = min_t(unsigned int, (conn->mtu - hlen), len); skb = chan->ops->alloc_skb(chan, count + hlen, - msg->msg_flags & MSG_DONTWAIT, &err); - - if (!skb) - return ERR_PTR(err); + msg->msg_flags & MSG_DONTWAIT); + if (IS_ERR(skb)) + return skb; /* Create L2CAP header */ lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index ae1d78ee041..46126cbc9de 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -927,12 +927,16 @@ static void l2cap_sock_state_change_cb(void *data, int state) } static struct sk_buff *l2cap_sock_alloc_skb_cb(struct l2cap_chan *chan, - unsigned long len, int nb, - int *err) + unsigned long len, int nb) { - struct sock *sk = chan->sk; + struct sk_buff *skb; + int err; + + skb = bt_skb_send_alloc(chan->sk, len, nb, &err); + if (!skb) + return ERR_PTR(err); - return bt_skb_send_alloc(sk, len, nb, err); + return skb; } static struct l2cap_ops l2cap_chan_ops = { -- cgit v1.2.3-70-g09d2 From 3c588192b5e5328cdfc8e299c55477004d397208 Mon Sep 17 00:00:00 2001 From: Mat Martineau Date: Wed, 11 Apr 2012 10:48:42 -0700 Subject: Bluetooth: Add the l2cap_seq_list structure for tracking frames A sequence list is a data structure used to track frames that need to be retransmitted, and frames that have been requested for retransmission by the remote device. It can compactly represent a list of sequence numbers within the ERTM transmit window. Memory for the list is allocated once at connection time, and common operations in ERTM are O(1). Signed-off-by: Mat Martineau Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 12 ++++ net/bluetooth/l2cap_core.c | 150 +++++++++++++++++++++++++++++++++++++++--- 2 files changed, 154 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index a756c240630..e33165476e8 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -407,6 +407,16 @@ struct l2cap_conn_param_update_rsp { #define L2CAP_CONN_PARAM_REJECTED 0x0001 /* ----- L2CAP channels and connections ----- */ +struct l2cap_seq_list { + __u16 head; + __u16 tail; + __u16 mask; + __u16 *list; +}; + +#define L2CAP_SEQ_LIST_CLEAR 0xFFFF +#define L2CAP_SEQ_LIST_TAIL 0x8000 + struct srej_list { __u16 tx_seq; struct list_head list; @@ -501,6 +511,8 @@ struct l2cap_chan { struct sk_buff *tx_send_head; struct sk_buff_head tx_q; struct sk_buff_head srej_q; + struct l2cap_seq_list srej_list; + struct l2cap_seq_list retrans_list; struct list_head srej_l; struct list_head list; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 03746f565fc..041ebed9e64 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -232,6 +232,121 @@ static inline void l2cap_chan_set_err(struct l2cap_chan *chan, int err) release_sock(sk); } +/* ---- L2CAP sequence number lists ---- */ + +/* For ERTM, ordered lists of sequence numbers must be tracked for + * SREJ requests that are received and for frames that are to be + * retransmitted. These seq_list functions implement a singly-linked + * list in an array, where membership in the list can also be checked + * in constant time. Items can also be added to the tail of the list + * and removed from the head in constant time, without further memory + * allocs or frees. + */ + +static int l2cap_seq_list_init(struct l2cap_seq_list *seq_list, u16 size) +{ + size_t alloc_size, i; + + /* Allocated size is a power of 2 to map sequence numbers + * (which may be up to 14 bits) in to a smaller array that is + * sized for the negotiated ERTM transmit windows. + */ + alloc_size = roundup_pow_of_two(size); + + seq_list->list = kmalloc(sizeof(u16) * alloc_size, GFP_KERNEL); + if (!seq_list->list) + return -ENOMEM; + + seq_list->mask = alloc_size - 1; + seq_list->head = L2CAP_SEQ_LIST_CLEAR; + seq_list->tail = L2CAP_SEQ_LIST_CLEAR; + for (i = 0; i < alloc_size; i++) + seq_list->list[i] = L2CAP_SEQ_LIST_CLEAR; + + return 0; +} + +static inline void l2cap_seq_list_free(struct l2cap_seq_list *seq_list) +{ + kfree(seq_list->list); +} + +static inline bool l2cap_seq_list_contains(struct l2cap_seq_list *seq_list, + u16 seq) +{ + /* Constant-time check for list membership */ + return seq_list->list[seq & seq_list->mask] != L2CAP_SEQ_LIST_CLEAR; +} + +static u16 l2cap_seq_list_remove(struct l2cap_seq_list *seq_list, u16 seq) +{ + u16 mask = seq_list->mask; + + if (seq_list->head == L2CAP_SEQ_LIST_CLEAR) { + /* In case someone tries to pop the head of an empty list */ + return L2CAP_SEQ_LIST_CLEAR; + } else if (seq_list->head == seq) { + /* Head can be removed in constant time */ + seq_list->head = seq_list->list[seq & mask]; + seq_list->list[seq & mask] = L2CAP_SEQ_LIST_CLEAR; + + if (seq_list->head == L2CAP_SEQ_LIST_TAIL) { + seq_list->head = L2CAP_SEQ_LIST_CLEAR; + seq_list->tail = L2CAP_SEQ_LIST_CLEAR; + } + } else { + /* Walk the list to find the sequence number */ + u16 prev = seq_list->head; + while (seq_list->list[prev & mask] != seq) { + prev = seq_list->list[prev & mask]; + if (prev == L2CAP_SEQ_LIST_TAIL) + return L2CAP_SEQ_LIST_CLEAR; + } + + /* Unlink the number from the list and clear it */ + seq_list->list[prev & mask] = seq_list->list[seq & mask]; + seq_list->list[seq & mask] = L2CAP_SEQ_LIST_CLEAR; + if (seq_list->tail == seq) + seq_list->tail = prev; + } + return seq; +} + +static inline u16 l2cap_seq_list_pop(struct l2cap_seq_list *seq_list) +{ + /* Remove the head in constant time */ + return l2cap_seq_list_remove(seq_list, seq_list->head); +} + +static void l2cap_seq_list_clear(struct l2cap_seq_list *seq_list) +{ + if (seq_list->head != L2CAP_SEQ_LIST_CLEAR) { + u16 i; + for (i = 0; i <= seq_list->mask; i++) + seq_list->list[i] = L2CAP_SEQ_LIST_CLEAR; + + seq_list->head = L2CAP_SEQ_LIST_CLEAR; + seq_list->tail = L2CAP_SEQ_LIST_CLEAR; + } +} + +static void l2cap_seq_list_append(struct l2cap_seq_list *seq_list, u16 seq) +{ + u16 mask = seq_list->mask; + + /* All appends happen in constant time */ + + if (seq_list->list[seq & mask] == L2CAP_SEQ_LIST_CLEAR) { + if (seq_list->tail == L2CAP_SEQ_LIST_CLEAR) + seq_list->head = seq; + else + seq_list->list[seq_list->tail & mask] = seq; + + seq_list->tail = seq; + seq_list->list[seq & mask] = L2CAP_SEQ_LIST_TAIL; + } +} + static void l2cap_chan_timeout(struct work_struct *work) { struct l2cap_chan *chan = container_of(work, struct l2cap_chan, @@ -414,6 +529,8 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err) skb_queue_purge(&chan->srej_q); + l2cap_seq_list_free(&chan->srej_list); + l2cap_seq_list_free(&chan->retrans_list); list_for_each_entry_safe(l, tmp, &chan->srej_l, list) { list_del(&l->list); kfree(l); @@ -2045,8 +2162,10 @@ static void l2cap_ack_timeout(struct work_struct *work) l2cap_chan_put(chan); } -static inline void l2cap_ertm_init(struct l2cap_chan *chan) +static inline int l2cap_ertm_init(struct l2cap_chan *chan) { + int err; + chan->expected_ack_seq = 0; chan->unacked_frames = 0; chan->buffer_seq = 0; @@ -2060,6 +2179,11 @@ static inline void l2cap_ertm_init(struct l2cap_chan *chan) skb_queue_head_init(&chan->srej_q); INIT_LIST_HEAD(&chan->srej_l); + err = l2cap_seq_list_init(&chan->srej_list, chan->tx_win); + if (err < 0) + return err; + + return l2cap_seq_list_init(&chan->retrans_list, chan->remote_tx_win); } static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask) @@ -2853,7 +2977,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr u16 dcid, flags; u8 rsp[64]; struct l2cap_chan *chan; - int len; + int len, err = 0; dcid = __le16_to_cpu(req->dcid); flags = __le16_to_cpu(req->flags); @@ -2924,9 +3048,13 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr chan->expected_tx_seq = 0; skb_queue_head_init(&chan->tx_q); if (chan->mode == L2CAP_MODE_ERTM) - l2cap_ertm_init(chan); + err = l2cap_ertm_init(chan); + + if (err < 0) + l2cap_send_disconn_req(chan->conn, chan, -err); + else + l2cap_chan_ready(chan); - l2cap_chan_ready(chan); goto unlock; } @@ -2954,7 +3082,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr unlock: l2cap_chan_unlock(chan); - return 0; + return err; } static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data) @@ -2963,6 +3091,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr u16 scid, flags, result; struct l2cap_chan *chan; int len = le16_to_cpu(cmd->len) - sizeof(*rsp); + int err = 0; scid = __le16_to_cpu(rsp->scid); flags = __le16_to_cpu(rsp->flags); @@ -3054,14 +3183,17 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr chan->expected_tx_seq = 0; skb_queue_head_init(&chan->tx_q); if (chan->mode == L2CAP_MODE_ERTM) - l2cap_ertm_init(chan); + err = l2cap_ertm_init(chan); - l2cap_chan_ready(chan); + if (err < 0) + l2cap_send_disconn_req(chan->conn, chan, -err); + else + l2cap_chan_ready(chan); } done: l2cap_chan_unlock(chan); - return 0; + return err; } static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data) @@ -3805,6 +3937,7 @@ static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan) BT_DBG("chan %p, Enter local busy", chan); set_bit(CONN_LOCAL_BUSY, &chan->conn_state); + l2cap_seq_list_clear(&chan->srej_list); __set_ack_timer(chan); } @@ -3897,6 +4030,7 @@ static int l2cap_send_srejframe(struct l2cap_chan *chan, u16 tx_seq) while (tx_seq != chan->expected_tx_seq) { control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ); control |= __set_reqseq(chan, chan->expected_tx_seq); + l2cap_seq_list_append(&chan->srej_list, chan->expected_tx_seq); l2cap_send_sframe(chan, control); new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC); -- cgit v1.2.3-70-g09d2 From 270ca16bc7ff575a5900aec2475fa7f8742f7337 Mon Sep 17 00:00:00 2001 From: Syam Sidhardhan Date: Thu, 12 Apr 2012 20:33:19 +0530 Subject: Bluetooth: remove header declared but not defined hci_del_off_timer() doesn't exist anymore. Signed-off-by: Syam Sidhardhan Signed-off-by: Gustavo Padovan --- include/net/bluetooth/hci_core.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index afdea9530d7..ef6e6541aa2 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -698,8 +698,6 @@ struct adv_entry *hci_find_adv_entry(struct hci_dev *hdev, bdaddr_t *bdaddr); int hci_add_adv_entry(struct hci_dev *hdev, struct hci_ev_le_advertising_info *ev); -void hci_del_off_timer(struct hci_dev *hdev); - void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb); int hci_recv_frame(struct sk_buff *skb); -- cgit v1.2.3-70-g09d2 From e47872209d67a3283f88c39729b5bf11860b7b19 Mon Sep 17 00:00:00 2001 From: Syam Sidhardhan Date: Thu, 12 Apr 2012 20:33:20 +0530 Subject: Bluetooth: Remove strtoba header declared but not defined No one is using strtoba() in the bluetooth subsystem. Signed-off-by: Syam Sidhardhan Signed-off-by: Gustavo Padovan --- include/net/bluetooth/bluetooth.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include') diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index f2c8bdf0806..d0e44a4151e 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -178,7 +178,6 @@ static inline void bacpy(bdaddr_t *dst, bdaddr_t *src) void baswap(bdaddr_t *dst, bdaddr_t *src); char *batostr(bdaddr_t *ba); -bdaddr_t *strtoba(char *str); /* Common socket structures and functions */ -- cgit v1.2.3-70-g09d2 From 2bbf2968e5cd72d2dd9e229d85c1617b8aa48f4e Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Mon, 16 Apr 2012 16:32:03 +0300 Subject: Bluetooth: trivial: Remove empty line Signed-off-by: Andrei Emeltchenko Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index e33165476e8..52f7e6a9a23 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -532,7 +532,6 @@ struct l2cap_ops { void (*state_change) (void *data, int state); struct sk_buff *(*alloc_skb) (struct l2cap_chan *chan, unsigned long len, int nb); - }; struct l2cap_conn { -- cgit v1.2.3-70-g09d2 From 591f47f31ba4e89fc0cce2ad90da80945ce8bf94 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Tue, 24 Apr 2012 21:02:49 -0300 Subject: Bluetooth: Move address type macros to bluetooth.h This patch moves address type macros to bluetooth.h since they will be used by management interface and Bluetooth socket interface. It also replaces the macro prefix MGMT_ADDR_ by BDADDR_. Signed-off-by: Andre Guedes Acked-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/bluetooth.h | 5 +++++ include/net/bluetooth/hci_core.h | 16 ++++++---------- net/bluetooth/mgmt.c | 30 +++++++++++++++--------------- 3 files changed, 26 insertions(+), 25 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index d0e44a4151e..27a6a936487 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -163,6 +163,11 @@ typedef struct { __u8 b[6]; } __packed bdaddr_t; +/* BD Address type */ +#define BDADDR_BREDR 0x00 +#define BDADDR_LE_PUBLIC 0x01 +#define BDADDR_LE_RANDOM 0x02 + #define BDADDR_ANY (&(bdaddr_t) {{0, 0, 0, 0, 0, 0}}) #define BDADDR_LOCAL (&(bdaddr_t) {{0, 0, 0, 0xff, 0xff, 0xff}}) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index ef6e6541aa2..6777432ca61 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -963,16 +963,12 @@ void hci_send_to_monitor(struct hci_dev *hdev, struct sk_buff *skb); void hci_sock_dev_event(struct hci_dev *hdev, int event); /* Management interface */ -#define MGMT_ADDR_BREDR 0x00 -#define MGMT_ADDR_LE_PUBLIC 0x01 -#define MGMT_ADDR_LE_RANDOM 0x02 - -#define DISCOV_TYPE_BREDR (BIT(MGMT_ADDR_BREDR)) -#define DISCOV_TYPE_LE (BIT(MGMT_ADDR_LE_PUBLIC) | \ - BIT(MGMT_ADDR_LE_RANDOM)) -#define DISCOV_TYPE_INTERLEAVED (BIT(MGMT_ADDR_BREDR) | \ - BIT(MGMT_ADDR_LE_PUBLIC) | \ - BIT(MGMT_ADDR_LE_RANDOM)) +#define DISCOV_TYPE_BREDR (BIT(BDADDR_BREDR)) +#define DISCOV_TYPE_LE (BIT(BDADDR_LE_PUBLIC) | \ + BIT(BDADDR_LE_RANDOM)) +#define DISCOV_TYPE_INTERLEAVED (BIT(BDADDR_BREDR) | \ + BIT(BDADDR_LE_PUBLIC) | \ + BIT(BDADDR_LE_RANDOM)) int mgmt_control(struct sock *sk, struct msghdr *msg, size_t len); int mgmt_index_added(struct hci_dev *hdev); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 7d37c88e4bf..d064ca9fa00 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1524,7 +1524,7 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data, goto unlock; } - if (cp->addr.type == MGMT_ADDR_BREDR) + if (cp->addr.type == BDADDR_BREDR) err = hci_remove_link_key(hdev, &cp->addr.bdaddr); else err = hci_remove_ltk(hdev, &cp->addr.bdaddr); @@ -1536,7 +1536,7 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data, } if (cp->disconnect) { - if (cp->addr.type == MGMT_ADDR_BREDR) + if (cp->addr.type == BDADDR_BREDR) conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr); else @@ -1596,7 +1596,7 @@ static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data, goto failed; } - if (cp->addr.type == MGMT_ADDR_BREDR) + if (cp->addr.type == BDADDR_BREDR) conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr); else conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr); @@ -1631,23 +1631,23 @@ static u8 link_to_mgmt(u8 link_type, u8 addr_type) case LE_LINK: switch (addr_type) { case ADDR_LE_DEV_PUBLIC: - return MGMT_ADDR_LE_PUBLIC; + return BDADDR_LE_PUBLIC; default: /* Fallback to LE Random address type */ - return MGMT_ADDR_LE_RANDOM; + return BDADDR_LE_RANDOM; } default: /* Fallback to BR/EDR type */ - return MGMT_ADDR_BREDR; + return BDADDR_BREDR; } } static u8 mgmt_to_le(u8 mgmt_type) { switch (mgmt_type) { - case MGMT_ADDR_LE_PUBLIC: + case BDADDR_LE_PUBLIC: return ADDR_LE_DEV_PUBLIC; default: @@ -1914,7 +1914,7 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, else auth_type = HCI_AT_DEDICATED_BONDING_MITM; - if (cp->addr.type == MGMT_ADDR_BREDR) + if (cp->addr.type == BDADDR_BREDR) conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level, auth_type); else @@ -1947,7 +1947,7 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, } /* For LE, just connecting isn't a proof that the pairing finished */ - if (cp->addr.type == MGMT_ADDR_BREDR) + if (cp->addr.type == BDADDR_BREDR) conn->connect_cfm_cb = pairing_complete_cb; conn->security_cfm_cb = pairing_complete_cb; @@ -2024,7 +2024,7 @@ static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev, goto done; } - if (type == MGMT_ADDR_BREDR) + if (type == BDADDR_BREDR) conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr); else conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr); @@ -2035,7 +2035,7 @@ static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev, goto done; } - if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) { + if (type == BDADDR_LE_PUBLIC || type == BDADDR_LE_RANDOM) { /* Continue with pairing via SMP */ err = smp_user_confirm_reply(conn, mgmt_op, passkey); @@ -2967,7 +2967,7 @@ int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, bool persisten ev.store_hint = persistent; bacpy(&ev.key.addr.bdaddr, &key->bdaddr); - ev.key.addr.type = MGMT_ADDR_BREDR; + ev.key.addr.type = BDADDR_BREDR; ev.key.type = key->type; memcpy(ev.key.val, key->val, 16); ev.key.pin_len = key->pin_len; @@ -3125,7 +3125,7 @@ int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure) struct mgmt_ev_pin_code_request ev; bacpy(&ev.addr.bdaddr, bdaddr); - ev.addr.type = MGMT_ADDR_BREDR; + ev.addr.type = BDADDR_BREDR; ev.secure = secure; return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), @@ -3144,7 +3144,7 @@ int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, return -ENOENT; bacpy(&rp.addr.bdaddr, bdaddr); - rp.addr.type = MGMT_ADDR_BREDR; + rp.addr.type = BDADDR_BREDR; err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, mgmt_status(status), &rp, sizeof(rp)); @@ -3166,7 +3166,7 @@ int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, return -ENOENT; bacpy(&rp.addr.bdaddr, bdaddr); - rp.addr.type = MGMT_ADDR_BREDR; + rp.addr.type = BDADDR_BREDR; err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, mgmt_status(status), &rp, sizeof(rp)); -- cgit v1.2.3-70-g09d2 From 43ef0b8b8d95c7aab7bb3778351e3591502bf355 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Tue, 24 Apr 2012 21:02:52 -0300 Subject: Bluetooth: Add address type to struct sockaddr_l2 This patch adds the address type info to struct sockaddr_l2 so user-space can inform the remote device address type required to establish LE connections. Soon, instead of looking the advertising cache up to discover the address type, we'll use this address type info to establish LE connections. Signed-off-by: Andre Guedes Acked-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 52f7e6a9a23..bb4e3f66b43 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -57,6 +57,7 @@ struct sockaddr_l2 { __le16 l2_psm; bdaddr_t l2_bdaddr; __le16 l2_cid; + __u8 l2_bdaddr_type; }; /* L2CAP socket options */ -- cgit v1.2.3-70-g09d2 From 31f7956c6648fbae9c9550e91d1c348d28276309 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Tue, 24 Apr 2012 21:02:53 -0300 Subject: Bluetooth: Move bdaddr_to_le to hci_core This patch moves the helper function bdaddr_to_le to hci_core, so it can be used in mgmt.c and hci_conn.c. Signed-off-by: Andre Guedes Acked-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 2 ++ net/bluetooth/hci_core.c | 12 ++++++++++++ net/bluetooth/mgmt.c | 12 ------------ 3 files changed, 14 insertions(+), 12 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 6777432ca61..7e7fe3f221f 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1073,4 +1073,6 @@ int hci_le_scan(struct hci_dev *hdev, u8 type, u16 interval, u16 window, int timeout); int hci_cancel_le_scan(struct hci_dev *hdev); +u8 bdaddr_to_le(u8 bdaddr_type); + #endif /* __HCI_CORE_H */ diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index aa45ea496f8..7bbd5c5767b 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2946,3 +2946,15 @@ int hci_cancel_inquiry(struct hci_dev *hdev) return hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL); } + +u8 bdaddr_to_le(u8 bdaddr_type) +{ + switch (bdaddr_type) { + case BDADDR_LE_PUBLIC: + return ADDR_LE_DEV_PUBLIC; + + default: + /* Fallback to LE Random address type */ + return ADDR_LE_DEV_RANDOM; + } +} diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 605a35b284f..4e26c258581 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1644,18 +1644,6 @@ static u8 link_to_bdaddr(u8 link_type, u8 addr_type) } } -static u8 bdaddr_to_le(u8 bdaddr_type) -{ - switch (bdaddr_type) { - case BDADDR_LE_PUBLIC: - return ADDR_LE_DEV_PUBLIC; - - default: - /* Fallback to LE Random address type */ - return ADDR_LE_DEV_RANDOM; - } -} - static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data, u16 data_len) { -- cgit v1.2.3-70-g09d2 From b12f62cfd9f46ac70013ce661640174b489efd39 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Tue, 24 Apr 2012 21:02:54 -0300 Subject: Bluetooth: Add dst_type parameter to hci_connect This patch adds the dst_type parameter to hci_connect function. Instead of searching the address type in advertising cache, we use the dst_type parameter to establish LE connections. The dst_type is ignored for BR/EDR connection establishment. Signed-off-by: Andre Guedes Acked-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 2 +- net/bluetooth/hci_conn.c | 11 +++-------- net/bluetooth/l2cap_core.c | 8 ++++---- net/bluetooth/mgmt.c | 8 ++++---- net/bluetooth/sco.c | 3 ++- 5 files changed, 14 insertions(+), 18 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 7e7fe3f221f..e69a9eed082 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -575,7 +575,7 @@ int hci_chan_del(struct hci_chan *chan); void hci_chan_list_flush(struct hci_conn *conn); struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, - __u8 sec_level, __u8 auth_type); + __u8 dst_type, __u8 sec_level, __u8 auth_type); int hci_conn_check_link_mode(struct hci_conn *conn); int hci_conn_check_secure(struct hci_conn *conn, __u8 sec_level); int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type); diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 8f352cd1745..a3ee1a929a6 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -513,7 +513,8 @@ EXPORT_SYMBOL(hci_get_route); /* Create SCO, ACL or LE connection. * Device _must_ be locked */ -struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 sec_level, __u8 auth_type) +struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, + __u8 dst_type, __u8 sec_level, __u8 auth_type) { struct hci_conn *acl; struct hci_conn *sco; @@ -522,19 +523,13 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 BT_DBG("%s dst %s", hdev->name, batostr(dst)); if (type == LE_LINK) { - struct adv_entry *entry = NULL; - le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst); if (!le) { - entry = hci_find_adv_entry(hdev, dst); - if (!entry) - return ERR_PTR(-EHOSTUNREACH); - le = hci_conn_add(hdev, LE_LINK, dst); if (!le) return ERR_PTR(-ENOMEM); - le->dst_type = entry->bdaddr_type; + le->dst_type = bdaddr_to_le(dst_type); hci_le_connect(le); } diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 97af2b4f623..61af06d3533 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1479,11 +1479,11 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *d auth_type = l2cap_get_auth_type(chan); if (chan->dcid == L2CAP_CID_LE_DATA) - hcon = hci_connect(hdev, LE_LINK, dst, - chan->sec_level, auth_type); + hcon = hci_connect(hdev, LE_LINK, dst, BDADDR_LE_RANDOM, + chan->sec_level, auth_type); else - hcon = hci_connect(hdev, ACL_LINK, dst, - chan->sec_level, auth_type); + hcon = hci_connect(hdev, ACL_LINK, dst, BDADDR_BREDR, + chan->sec_level, auth_type); if (IS_ERR(hcon)) { err = PTR_ERR(hcon); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 4e26c258581..9038118d37a 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1903,11 +1903,11 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, auth_type = HCI_AT_DEDICATED_BONDING_MITM; if (cp->addr.type == BDADDR_BREDR) - conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level, - auth_type); + conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, + cp->addr.type, sec_level, auth_type); else - conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level, - auth_type); + conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, + cp->addr.type, sec_level, auth_type); memset(&rp, 0, sizeof(rp)); bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr); diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index bf1af0b1497..cbdd313659a 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -193,7 +193,8 @@ static int sco_connect(struct sock *sk) else type = SCO_LINK; - hcon = hci_connect(hdev, type, dst, BT_SECURITY_LOW, HCI_AT_NO_BONDING); + hcon = hci_connect(hdev, type, dst, BDADDR_BREDR, BT_SECURITY_LOW, + HCI_AT_NO_BONDING); if (IS_ERR(hcon)) { err = PTR_ERR(hcon); goto done; -- cgit v1.2.3-70-g09d2 From 8e9f98921c0718cda76bc53c2b51954657b60fa6 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Tue, 24 Apr 2012 21:02:55 -0300 Subject: Bluetooth: Use address type info from user-space In order to establish a LE connection we need the address type information. User-space already pass this information to kernel through struct sockaddr_l2. This patch adds the dst_type parameter to l2cap_chan_connect so we are able to pass the address type info from user-space down to hci_conn layer. Signed-off-by: Andre Guedes Acked-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 2 +- net/bluetooth/l2cap_core.c | 11 ++++++----- net/bluetooth/l2cap_sock.c | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index bb4e3f66b43..86bb83bc6a4 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -922,7 +922,7 @@ struct l2cap_chan *l2cap_chan_create(void); void l2cap_chan_close(struct l2cap_chan *chan, int reason); void l2cap_chan_destroy(struct l2cap_chan *chan); int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, - bdaddr_t *dst); + bdaddr_t *dst, u8 dst_type); int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len, u32 priority); void l2cap_chan_busy(struct l2cap_chan *chan, int busy); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 61af06d3533..4b6d11c199b 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1394,7 +1394,8 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, return c1; } -int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *dst) +int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, + bdaddr_t *dst, u8 dst_type) { struct sock *sk = chan->sk; bdaddr_t *src = &bt_sk(sk)->src; @@ -1404,8 +1405,8 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *d __u8 auth_type; int err; - BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst), - __le16_to_cpu(chan->psm)); + BT_DBG("%s -> %s (type %u) psm 0x%2.2x", batostr(src), batostr(dst), + dst_type, __le16_to_cpu(chan->psm)); hdev = hci_get_route(dst, src); if (!hdev) @@ -1479,10 +1480,10 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *d auth_type = l2cap_get_auth_type(chan); if (chan->dcid == L2CAP_CID_LE_DATA) - hcon = hci_connect(hdev, LE_LINK, dst, BDADDR_LE_RANDOM, + hcon = hci_connect(hdev, LE_LINK, dst, dst_type, chan->sec_level, auth_type); else - hcon = hci_connect(hdev, ACL_LINK, dst, BDADDR_BREDR, + hcon = hci_connect(hdev, ACL_LINK, dst, dst_type, chan->sec_level, auth_type); if (IS_ERR(hcon)) { diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 8d8b50a2990..2b5e7e81c3c 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -124,7 +124,7 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al return -EINVAL; err = l2cap_chan_connect(chan, la.l2_psm, __le16_to_cpu(la.l2_cid), - &la.l2_bdaddr); + &la.l2_bdaddr, la.l2_bdaddr_type); if (err) return err; -- cgit v1.2.3-70-g09d2 From 479453d5fe3a5b911b7f56474764988100f9f650 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Tue, 24 Apr 2012 21:02:56 -0300 Subject: Bluetooth: Remove advertising cache User-space pass the remote device address type to kernel through struct sockaddr_l2 what makes the advertising useless. This patch removes all advertising cache code. Signed-off-by: Andre Guedes Acked-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 9 ----- net/bluetooth/hci_core.c | 74 ---------------------------------------- net/bluetooth/hci_event.c | 7 ---- 3 files changed, 90 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index e69a9eed082..d1e744f3b9b 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -255,9 +255,6 @@ struct hci_dev { struct list_head remote_oob_data; - struct list_head adv_entries; - struct delayed_work adv_work; - struct hci_dev_stats stat; struct sk_buff_head driver_init; @@ -692,12 +689,6 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash, u8 *randomizer); int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr); -#define ADV_CLEAR_TIMEOUT (3*60*HZ) /* Three minutes */ -int hci_adv_entries_clear(struct hci_dev *hdev); -struct adv_entry *hci_find_adv_entry(struct hci_dev *hdev, bdaddr_t *bdaddr); -int hci_add_adv_entry(struct hci_dev *hdev, - struct hci_ev_le_advertising_info *ev); - void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb); int hci_recv_frame(struct sk_buff *skb); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 7bbd5c5767b..83d3d3563bc 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1521,75 +1521,6 @@ int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) return mgmt_device_unblocked(hdev, bdaddr, type); } -static void hci_clear_adv_cache(struct work_struct *work) -{ - struct hci_dev *hdev = container_of(work, struct hci_dev, - adv_work.work); - - hci_dev_lock(hdev); - - hci_adv_entries_clear(hdev); - - hci_dev_unlock(hdev); -} - -int hci_adv_entries_clear(struct hci_dev *hdev) -{ - struct adv_entry *entry, *tmp; - - list_for_each_entry_safe(entry, tmp, &hdev->adv_entries, list) { - list_del(&entry->list); - kfree(entry); - } - - BT_DBG("%s adv cache cleared", hdev->name); - - return 0; -} - -struct adv_entry *hci_find_adv_entry(struct hci_dev *hdev, bdaddr_t *bdaddr) -{ - struct adv_entry *entry; - - list_for_each_entry(entry, &hdev->adv_entries, list) - if (bacmp(bdaddr, &entry->bdaddr) == 0) - return entry; - - return NULL; -} - -static inline int is_connectable_adv(u8 evt_type) -{ - if (evt_type == ADV_IND || evt_type == ADV_DIRECT_IND) - return 1; - - return 0; -} - -int hci_add_adv_entry(struct hci_dev *hdev, - struct hci_ev_le_advertising_info *ev) { struct adv_entry *entry; if (!is_connectable_adv(ev->evt_type)) - return -EINVAL; - - /* Only new entries should be added to adv_entries. So, if - * bdaddr was found, don't add it. */ - if (hci_find_adv_entry(hdev, &ev->bdaddr)) - return 0; - - entry = kzalloc(sizeof(*entry), GFP_KERNEL); - if (!entry) - return -ENOMEM; - - bacpy(&entry->bdaddr, &ev->bdaddr); - entry->bdaddr_type = ev->bdaddr_type; - - list_add(&entry->list, &hdev->adv_entries); - - BT_DBG("%s adv entry added: address %s type %u", hdev->name, - batostr(&entry->bdaddr), entry->bdaddr_type); - - return 0; -} - static void le_scan_param_req(struct hci_dev *hdev, unsigned long opt) { struct le_scan_params *param = (struct le_scan_params *) opt; @@ -1735,7 +1666,6 @@ struct hci_dev *hci_alloc_dev(void) INIT_LIST_HEAD(&hdev->link_keys); INIT_LIST_HEAD(&hdev->long_term_keys); INIT_LIST_HEAD(&hdev->remote_oob_data); - INIT_LIST_HEAD(&hdev->adv_entries); INIT_WORK(&hdev->rx_work, hci_rx_work); INIT_WORK(&hdev->cmd_work, hci_cmd_work); @@ -1743,7 +1673,6 @@ struct hci_dev *hci_alloc_dev(void) INIT_WORK(&hdev->power_on, hci_power_on); INIT_WORK(&hdev->le_scan, le_scan_work); - INIT_DELAYED_WORK(&hdev->adv_work, hci_clear_adv_cache); INIT_DELAYED_WORK(&hdev->power_off, hci_power_off); INIT_DELAYED_WORK(&hdev->discov_off, hci_discov_off); INIT_DELAYED_WORK(&hdev->le_scan_disable, le_scan_disable_work); @@ -1889,8 +1818,6 @@ void hci_unregister_dev(struct hci_dev *hdev) hci_del_sysfs(hdev); - cancel_delayed_work_sync(&hdev->adv_work); - destroy_workqueue(hdev->workqueue); hci_dev_lock(hdev); @@ -1899,7 +1826,6 @@ void hci_unregister_dev(struct hci_dev *hdev) hci_link_keys_clear(hdev); hci_smp_ltks_clear(hdev); hci_remote_oob_data_clear(hdev); - hci_adv_entries_clear(hdev); hci_dev_unlock(hdev); hci_dev_put(hdev); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 054b1ad7449..ae0a57d21ec 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1100,10 +1100,7 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, set_bit(HCI_LE_SCAN, &hdev->dev_flags); - cancel_delayed_work_sync(&hdev->adv_work); - hci_dev_lock(hdev); - hci_adv_entries_clear(hdev); hci_discovery_set_state(hdev, DISCOVERY_FINDING); hci_dev_unlock(hdev); break; @@ -1118,8 +1115,6 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, clear_bit(HCI_LE_SCAN, &hdev->dev_flags); - schedule_delayed_work(&hdev->adv_work, ADV_CLEAR_TIMEOUT); - if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED && hdev->discovery.state == DISCOVERY_FINDING) { mgmt_interleaved_discovery(hdev); @@ -3353,8 +3348,6 @@ static inline void hci_le_adv_report_evt(struct hci_dev *hdev, while (num_reports--) { struct hci_ev_le_advertising_info *ev = ptr; - hci_add_adv_entry(hdev, ev); - rssi = ev->data[ev->length]; mgmt_device_found(hdev, &ev->bdaddr, LE_LINK, ev->bdaddr_type, NULL, rssi, 0, 1, ev->data, ev->length); -- cgit v1.2.3-70-g09d2 From 5a364bd399d23fe6244de8f84c46f249b763c723 Mon Sep 17 00:00:00 2001 From: Mat Martineau Date: Wed, 25 Apr 2012 16:36:12 -0700 Subject: Bluetooth: Improve ERTM sequence number offset calculation Instead of using modular division, the offset can be calculated using only addition and subtraction. The previous calculation did not work as intended and was more difficult to understand, involving unsigned integer underflow and a check for a negative value where one was not possible. Signed-off-by: Mat Martineau Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- include/net/bluetooth/l2cap.h | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 86bb83bc6a4..084dec001bf 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -724,13 +724,10 @@ static inline bool l2cap_clear_timer(struct l2cap_chan *chan, static inline int __seq_offset(struct l2cap_chan *chan, __u16 seq1, __u16 seq2) { - int offset; - - offset = (seq1 - seq2) % (chan->tx_win_max + 1); - if (offset < 0) - offset += (chan->tx_win_max + 1); - - return offset; + if (seq1 >= seq2) + return seq1 - seq2; + else + return chan->tx_win_max + 1 - seq2 + seq1; } static inline __u16 __next_seq(struct l2cap_chan *chan, __u16 seq) -- cgit v1.2.3-70-g09d2 From 3ce3514f5d0f90c7d856e8b0f26c6da393bbeba0 Mon Sep 17 00:00:00 2001 From: Mat Martineau Date: Wed, 25 Apr 2012 16:36:14 -0700 Subject: Bluetooth: Remove duplicate structure members from bt_skb_cb These values are now in the nested l2cap_ctrl struct. Signed-off-by: Mat Martineau Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- include/net/bluetooth/bluetooth.h | 3 --- net/bluetooth/l2cap_core.c | 38 +++++++++++++++++++------------------- 2 files changed, 19 insertions(+), 22 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 27a6a936487..2fb268f2895 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -235,9 +235,6 @@ struct bt_skb_cb { __u8 pkt_type; __u8 incoming; __u16 expect; - __u16 tx_seq; - __u8 retries; - __u8 sar; __u8 force_active; struct l2cap_ctrl control; }; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 4b6d11c199b..62ef7c33516 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1620,7 +1620,7 @@ static void l2cap_drop_acked_frames(struct l2cap_chan *chan) while ((skb = skb_peek(&chan->tx_q)) && chan->unacked_frames) { - if (bt_cb(skb)->tx_seq == chan->expected_ack_seq) + if (bt_cb(skb)->control.txseq == chan->expected_ack_seq) break; skb = skb_dequeue(&chan->tx_q); @@ -1667,21 +1667,21 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u16 tx_seq) if (!skb) return; - while (bt_cb(skb)->tx_seq != tx_seq) { + while (bt_cb(skb)->control.txseq != tx_seq) { if (skb_queue_is_last(&chan->tx_q, skb)) return; skb = skb_queue_next(&chan->tx_q, skb); } - if (chan->remote_max_tx && - bt_cb(skb)->retries == chan->remote_max_tx) { + if (bt_cb(skb)->control.retries == chan->remote_max_tx && + chan->remote_max_tx) { l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED); return; } tx_skb = skb_clone(skb, GFP_ATOMIC); - bt_cb(skb)->retries++; + bt_cb(skb)->control.retries++; control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE); control &= __get_sar_mask(chan); @@ -1716,15 +1716,15 @@ static int l2cap_ertm_send(struct l2cap_chan *chan) while ((skb = chan->tx_send_head) && (!l2cap_tx_window_full(chan))) { - if (chan->remote_max_tx && - bt_cb(skb)->retries == chan->remote_max_tx) { + if (bt_cb(skb)->control.retries == chan->remote_max_tx && + chan->remote_max_tx) { l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED); break; } tx_skb = skb_clone(skb, GFP_ATOMIC); - bt_cb(skb)->retries++; + bt_cb(skb)->control.retries++; control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE); control &= __get_sar_mask(chan); @@ -1748,11 +1748,11 @@ static int l2cap_ertm_send(struct l2cap_chan *chan) __set_retrans_timer(chan); - bt_cb(skb)->tx_seq = chan->next_tx_seq; + bt_cb(skb)->control.txseq = chan->next_tx_seq; chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq); - if (bt_cb(skb)->retries == 1) { + if (bt_cb(skb)->control.retries == 1) { chan->unacked_frames++; if (!nsent++) @@ -1978,7 +1978,7 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, if (chan->fcs == L2CAP_FCS_CRC16) put_unaligned_le16(0, skb_put(skb, L2CAP_FCS_SIZE)); - bt_cb(skb)->retries = 0; + bt_cb(skb)->control.retries = 0; return skb; } @@ -3950,19 +3950,19 @@ static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb, struct sk_buff *next_skb; int tx_seq_offset, next_tx_seq_offset; - bt_cb(skb)->tx_seq = tx_seq; - bt_cb(skb)->sar = sar; + bt_cb(skb)->control.txseq = tx_seq; + bt_cb(skb)->control.sar = sar; next_skb = skb_peek(&chan->srej_q); tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq); while (next_skb) { - if (bt_cb(next_skb)->tx_seq == tx_seq) + if (bt_cb(next_skb)->control.txseq == tx_seq) return -EINVAL; next_tx_seq_offset = __seq_offset(chan, - bt_cb(next_skb)->tx_seq, chan->buffer_seq); + bt_cb(next_skb)->control.txseq, chan->buffer_seq); if (next_tx_seq_offset > tx_seq_offset) { __skb_queue_before(&chan->srej_q, next_skb, skb); @@ -4134,11 +4134,11 @@ static void l2cap_check_srej_gap(struct l2cap_chan *chan, u16 tx_seq) !test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) { int err; - if (bt_cb(skb)->tx_seq != tx_seq) + if (bt_cb(skb)->control.txseq != tx_seq) break; skb = skb_dequeue(&chan->srej_q); - control = __set_ctrl_sar(chan, bt_cb(skb)->sar); + control = __set_ctrl_sar(chan, bt_cb(skb)->control.sar); err = l2cap_reassemble_sdu(chan, skb, control); if (err < 0) { @@ -4309,8 +4309,8 @@ expected: chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq); if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) { - bt_cb(skb)->tx_seq = tx_seq; - bt_cb(skb)->sar = sar; + bt_cb(skb)->control.txseq = tx_seq; + bt_cb(skb)->control.sar = sar; __skb_queue_tail(&chan->srej_q, skb); return 0; } -- cgit v1.2.3-70-g09d2 From e10b9969f217c948c5523045f44eba4d3a758ff0 Mon Sep 17 00:00:00 2001 From: Syam Sidhardhan Date: Thu, 12 Apr 2012 20:33:17 +0530 Subject: Bluetooth: Remove unused hci_le_ltk_reply() In this API, we were using sizeof operator for an array given as function argument, which is invalid. However this API is not used anywhere. Signed-off-by: Syam Sidhardhan Signed-off-by: Gustavo Padovan --- include/net/bluetooth/hci_core.h | 1 - net/bluetooth/hci_conn.c | 16 ---------------- 2 files changed, 17 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index d1e744f3b9b..e3547ea8361 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1055,7 +1055,6 @@ void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency, u16 to_multiplier); void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8], __u8 ltk[16]); -void hci_le_ltk_reply(struct hci_conn *conn, u8 ltk[16]); void hci_le_ltk_neg_reply(struct hci_conn *conn); int hci_do_inquiry(struct hci_dev *hdev, u8 length); diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index a3ee1a929a6..cae7ec2df7a 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -223,22 +223,6 @@ void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8], } EXPORT_SYMBOL(hci_le_start_enc); -void hci_le_ltk_reply(struct hci_conn *conn, u8 ltk[16]) -{ - struct hci_dev *hdev = conn->hdev; - struct hci_cp_le_ltk_reply cp; - - BT_DBG("%p", conn); - - memset(&cp, 0, sizeof(cp)); - - cp.handle = cpu_to_le16(conn->handle); - memcpy(cp.ltk, ltk, sizeof(ltk)); - - hci_send_cmd(hdev, HCI_OP_LE_LTK_REPLY, sizeof(cp), &cp); -} -EXPORT_SYMBOL(hci_le_ltk_reply); - void hci_le_ltk_neg_reply(struct hci_conn *conn) { struct hci_dev *hdev = conn->hdev; -- cgit v1.2.3-70-g09d2 From 2ee8ce35b1e8ba2523fa4c45fa19f9dbe321f008 Mon Sep 17 00:00:00 2001 From: Syam Sidhardhan Date: Fri, 20 Apr 2012 22:12:31 +0530 Subject: Bluetooth: Remove unused hci_le_ltk_neg_reply() No one is using hci_le_ltk_neg_reply() in bluetooth subsystem. Signed-off-by: Syam Sidhardhan Signed-off-by: Gustavo Padovan --- include/net/bluetooth/hci_core.h | 2 -- net/bluetooth/hci_conn.c | 14 -------------- 2 files changed, 16 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index e3547ea8361..b60d2c844eb 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1055,8 +1055,6 @@ void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency, u16 to_multiplier); void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8], __u8 ltk[16]); -void hci_le_ltk_neg_reply(struct hci_conn *conn); - int hci_do_inquiry(struct hci_dev *hdev, u8 length); int hci_cancel_inquiry(struct hci_dev *hdev); int hci_le_scan(struct hci_dev *hdev, u8 type, u16 interval, u16 window, diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index cae7ec2df7a..3f18a6ed973 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -223,20 +223,6 @@ void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8], } EXPORT_SYMBOL(hci_le_start_enc); -void hci_le_ltk_neg_reply(struct hci_conn *conn) -{ - struct hci_dev *hdev = conn->hdev; - struct hci_cp_le_ltk_neg_reply cp; - - BT_DBG("%p", conn); - - memset(&cp, 0, sizeof(cp)); - - cp.handle = cpu_to_le16(conn->handle); - - hci_send_cmd(hdev, HCI_OP_LE_LTK_NEG_REPLY, sizeof(cp), &cp); -} - /* Device _must_ be locked */ void hci_sco_setup(struct hci_conn *conn, __u8 status) { -- cgit v1.2.3-70-g09d2 From 9d42820f378e6372f154a3f0c8def5d4bba29191 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 3 May 2012 07:12:31 +0200 Subject: Bluetooth: Enable Low Energy support by default The Bluetooth Low Energy support so far was disabled by default via a module parameter. With this change the module parameter will be removed and Low Energy is enabled by default. Signed-off-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- include/net/bluetooth/hci.h | 1 - net/bluetooth/hci_event.c | 2 +- net/bluetooth/mgmt.c | 12 +++--------- 3 files changed, 4 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 346f0877979..66a7b579e31 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -1438,6 +1438,5 @@ struct hci_inquiry_req { #define IREQ_CACHE_FLUSH 0x0001 extern bool enable_hs; -extern bool enable_le; #endif /* __HCI_H */ diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index ae0a57d21ec..d81262aff26 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -725,7 +725,7 @@ static void hci_set_le_support(struct hci_dev *hdev) memset(&cp, 0, sizeof(cp)); - if (enable_le && test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) { + if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) { cp.le = 1; cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR); } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 9038118d37a..966f6bcfbcb 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -35,7 +35,6 @@ #include bool enable_hs; -bool enable_le; #define MGMT_VERSION 1 #define MGMT_REVISION 1 @@ -384,10 +383,8 @@ static u32 get_supported_settings(struct hci_dev *hdev) if (enable_hs) settings |= MGMT_SETTING_HS; - if (enable_le) { - if (hdev->features[4] & LMP_LE) - settings |= MGMT_SETTING_LE; - } + if (hdev->features[4] & LMP_LE) + settings |= MGMT_SETTING_LE; return settings; } @@ -1199,7 +1196,7 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) hci_dev_lock(hdev); - if (!enable_le || !(hdev->features[4] & LMP_LE)) { + if (!(hdev->features[4] & LMP_LE)) { err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE, MGMT_STATUS_NOT_SUPPORTED); goto unlock; @@ -3657,6 +3654,3 @@ int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) module_param(enable_hs, bool, 0644); MODULE_PARM_DESC(enable_hs, "Enable High Speed support"); - -module_param(enable_le, bool, 0644); -MODULE_PARM_DESC(enable_le, "Enable Low Energy support"); -- cgit v1.2.3-70-g09d2 From 94122bbe9c8c4ad7ba9f02f9a30bfc95672c404e Mon Sep 17 00:00:00 2001 From: Mat Martineau Date: Wed, 2 May 2012 09:42:02 -0700 Subject: Bluetooth: Refactor L2CAP ERTM and streaming transmit segmentation Use more common code for ERTM and streaming mode segmentation and transmission, and begin using skb control block data for delaying extended or enhanced header generation until just before the packet is transmitted. This code is also better suited for resegmentation, which is needed when L2CAP links are reconfigured after an AMP channel move. Signed-off-by: Mat Martineau Reviewed-by: Ulisses Furquim Signed-off-by: Gustavo Padovan --- include/net/bluetooth/l2cap.h | 1 + net/bluetooth/l2cap_core.c | 144 +++++++++++++++++++++++++----------------- 2 files changed, 87 insertions(+), 58 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 084dec001bf..1c7d1cd5e67 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -44,6 +44,7 @@ #define L2CAP_DEFAULT_MAX_SDU_SIZE 0xFFFF #define L2CAP_DEFAULT_SDU_ITIME 0xFFFFFFFF #define L2CAP_DEFAULT_ACC_LAT 0xFFFFFFFF +#define L2CAP_BREDR_MAX_PAYLOAD 1019 /* 3-DH5 packet */ #define L2CAP_DISC_TIMEOUT msecs_to_jiffies(100) #define L2CAP_DISC_REJ_TIMEOUT msecs_to_jiffies(5000) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index fcd09fb4b94..2b30bd76777 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1634,6 +1634,7 @@ static void l2cap_streaming_send(struct l2cap_chan *chan) while ((skb = skb_dequeue(&chan->tx_q))) { control = __get_control(chan, skb->data + L2CAP_HDR_SIZE); control |= __set_txseq(chan, chan->next_tx_seq); + control |= __set_ctrl_sar(chan, bt_cb(skb)->control.sar); __put_control(chan, control, skb->data + L2CAP_HDR_SIZE); if (chan->fcs == L2CAP_FCS_CRC16) { @@ -1706,6 +1707,9 @@ static int l2cap_ertm_send(struct l2cap_chan *chan) if (chan->state != BT_CONNECTED) return -ENOTCONN; + if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state)) + return 0; + while ((skb = chan->tx_send_head) && (!l2cap_tx_window_full(chan))) { if (bt_cb(skb)->control.retries == chan->remote_max_tx && @@ -1726,6 +1730,7 @@ static int l2cap_ertm_send(struct l2cap_chan *chan) control |= __set_reqseq(chan, chan->buffer_seq); control |= __set_txseq(chan, chan->next_tx_seq); + control |= __set_ctrl_sar(chan, bt_cb(skb)->control.sar); __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE); @@ -1921,7 +1926,7 @@ static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len, - u32 control, u16 sdulen) + u16 sdulen) { struct l2cap_conn *conn = chan->conn; struct sk_buff *skb; @@ -1956,7 +1961,7 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, lh->cid = cpu_to_le16(chan->dcid); lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE)); - __put_control(chan, control, skb_put(skb, __ctrl_size(chan))); + __put_control(chan, 0, skb_put(skb, __ctrl_size(chan))); if (sdulen) put_unaligned_le16(sdulen, skb_put(skb, L2CAP_SDULEN_SIZE)); @@ -1974,57 +1979,78 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, return skb; } -static int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len) +static int l2cap_segment_sdu(struct l2cap_chan *chan, + struct sk_buff_head *seg_queue, + struct msghdr *msg, size_t len) { struct sk_buff *skb; - struct sk_buff_head sar_queue; - u32 control; - size_t size = 0; + u16 sdu_len; + size_t pdu_len; + int err = 0; + u8 sar; - skb_queue_head_init(&sar_queue); - control = __set_ctrl_sar(chan, L2CAP_SAR_START); - skb = l2cap_create_iframe_pdu(chan, msg, chan->remote_mps, control, len); - if (IS_ERR(skb)) - return PTR_ERR(skb); + BT_DBG("chan %p, msg %p, len %d", chan, msg, (int)len); - __skb_queue_tail(&sar_queue, skb); - len -= chan->remote_mps; - size += chan->remote_mps; + /* It is critical that ERTM PDUs fit in a single HCI fragment, + * so fragmented skbs are not used. The HCI layer's handling + * of fragmented skbs is not compatible with ERTM's queueing. + */ - while (len > 0) { - size_t buflen; + /* PDU size is derived from the HCI MTU */ + pdu_len = chan->conn->mtu; - if (len > chan->remote_mps) { - control = __set_ctrl_sar(chan, L2CAP_SAR_CONTINUE); - buflen = chan->remote_mps; - } else { - control = __set_ctrl_sar(chan, L2CAP_SAR_END); - buflen = len; - } + pdu_len = min_t(size_t, pdu_len, L2CAP_BREDR_MAX_PAYLOAD); + + /* Adjust for largest possible L2CAP overhead. */ + pdu_len -= L2CAP_EXT_HDR_SIZE + L2CAP_FCS_SIZE; + + /* Remote device may have requested smaller PDUs */ + pdu_len = min_t(size_t, pdu_len, chan->remote_mps); + + if (len <= pdu_len) { + sar = L2CAP_SAR_UNSEGMENTED; + sdu_len = 0; + pdu_len = len; + } else { + sar = L2CAP_SAR_START; + sdu_len = len; + pdu_len -= L2CAP_SDULEN_SIZE; + } + + while (len > 0) { + skb = l2cap_create_iframe_pdu(chan, msg, pdu_len, sdu_len); - skb = l2cap_create_iframe_pdu(chan, msg, buflen, control, 0); if (IS_ERR(skb)) { - skb_queue_purge(&sar_queue); + __skb_queue_purge(seg_queue); return PTR_ERR(skb); } - __skb_queue_tail(&sar_queue, skb); - len -= buflen; - size += buflen; + bt_cb(skb)->control.sar = sar; + __skb_queue_tail(seg_queue, skb); + + len -= pdu_len; + if (sdu_len) { + sdu_len = 0; + pdu_len += L2CAP_SDULEN_SIZE; + } + + if (len <= pdu_len) { + sar = L2CAP_SAR_END; + pdu_len = len; + } else { + sar = L2CAP_SAR_CONTINUE; + } } - skb_queue_splice_tail(&sar_queue, &chan->tx_q); - if (chan->tx_send_head == NULL) - chan->tx_send_head = sar_queue.next; - return size; + return err; } int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len, u32 priority) { struct sk_buff *skb; - u32 control; int err; + struct sk_buff_head seg_queue; /* Connectionless channel */ if (chan->chan_type == L2CAP_CHAN_CONN_LESS) { @@ -2053,42 +2079,44 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len, case L2CAP_MODE_ERTM: case L2CAP_MODE_STREAMING: - /* Entire SDU fits into one PDU */ - if (len <= chan->remote_mps) { - control = __set_ctrl_sar(chan, L2CAP_SAR_UNSEGMENTED); - skb = l2cap_create_iframe_pdu(chan, msg, len, control, - 0); - if (IS_ERR(skb)) - return PTR_ERR(skb); + /* Check outgoing MTU */ + if (len > chan->omtu) { + err = -EMSGSIZE; + break; + } - __skb_queue_tail(&chan->tx_q, skb); + __skb_queue_head_init(&seg_queue); - if (chan->tx_send_head == NULL) - chan->tx_send_head = skb; + /* Do segmentation before calling in to the state machine, + * since it's possible to block while waiting for memory + * allocation. + */ + err = l2cap_segment_sdu(chan, &seg_queue, msg, len); - } else { - /* Segment SDU into multiples PDUs */ - err = l2cap_sar_segment_sdu(chan, msg, len); - if (err < 0) - return err; + /* The channel could have been closed while segmenting, + * check that it is still connected. + */ + if (chan->state != BT_CONNECTED) { + __skb_queue_purge(&seg_queue); + err = -ENOTCONN; } - if (chan->mode == L2CAP_MODE_STREAMING) { - l2cap_streaming_send(chan); - err = len; + if (err) break; - } - if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) && - test_bit(CONN_WAIT_F, &chan->conn_state)) { - err = len; - break; - } + skb_queue_splice_tail_init(&seg_queue, &chan->tx_q); + if (chan->mode == L2CAP_MODE_ERTM) + err = l2cap_ertm_send(chan); + else + l2cap_streaming_send(chan); - err = l2cap_ertm_send(chan); if (err >= 0) err = len; + /* If the skbs were not queued for sending, they'll still be in + * seg_queue and need to be purged. + */ + __skb_queue_purge(&seg_queue); break; default: -- cgit v1.2.3-70-g09d2 From a7d7723ae7c0178d715c06c5621e8fd8014ba92f Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Sun, 13 May 2012 03:20:07 -0300 Subject: Bluetooth: notify userspace of security level change It fixes L2CAP socket based security level elevation during a connection. The HID profile needs this (for keyboards) and it is the only way to achieve the security level elevation when using the management interface to talk to the kernel (hence the management enabling patch being the one that exposes this issue). It enables the userspace a security level change when the socket is already connected and create a way to notify the socket the result of the request. At the moment of the request the socket is made non writable, if the request fails the connections closes, otherwise the socket is made writable again, POLL_OUT is emmited. Signed-off-by: Gustavo Padovan Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg Signed-off-by: John W. Linville --- include/net/bluetooth/bluetooth.h | 1 + net/bluetooth/af_bluetooth.c | 2 +- net/bluetooth/hci_event.c | 7 +++++++ net/bluetooth/l2cap_core.c | 5 +++++ net/bluetooth/l2cap_sock.c | 12 ++++++++---- 5 files changed, 22 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 262ebd1747d..a65910bda38 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -191,6 +191,7 @@ struct bt_sock { struct list_head accept_q; struct sock *parent; u32 defer_setup; + bool suspended; }; struct bt_sock_list { diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index 72eb187a5f6..6fb68a9743a 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c @@ -450,7 +450,7 @@ unsigned int bt_sock_poll(struct file *file, struct socket *sock, poll_table *wa sk->sk_state == BT_CONFIG) return mask; - if (sock_writeable(sk)) + if (!bt_sk(sk)->suspended && sock_writeable(sk)) mask |= POLLOUT | POLLWRNORM | POLLWRBAND; else set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 6c065254afc..53680fe8462 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2039,6 +2039,12 @@ static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff * clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags); + if (ev->status && conn->state == BT_CONNECTED) { + hci_acl_disconn(conn, 0x13); + hci_conn_put(conn); + goto unlock; + } + if (conn->state == BT_CONFIG) { if (!ev->status) conn->state = BT_CONNECTED; @@ -2049,6 +2055,7 @@ static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff * hci_encrypt_cfm(conn, ev->status, ev->encrypt); } +unlock: hci_dev_unlock(hdev); } diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 94552b33d52..6f9c25b633a 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -4589,6 +4589,11 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) if (!status && (chan->state == BT_CONNECTED || chan->state == BT_CONFIG)) { + struct sock *sk = chan->sk; + + bt_sk(sk)->suspended = false; + sk->sk_state_change(sk); + l2cap_check_encryption(chan, encrypt); l2cap_chan_unlock(chan); continue; diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 29122ed28ea..04e7c172d49 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -592,10 +592,14 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch sk->sk_state = BT_CONFIG; chan->state = BT_CONFIG; - /* or for ACL link, under defer_setup time */ - } else if (sk->sk_state == BT_CONNECT2 && - bt_sk(sk)->defer_setup) { - err = l2cap_chan_check_security(chan); + /* or for ACL link */ + } else if ((sk->sk_state == BT_CONNECT2 && + bt_sk(sk)->defer_setup) || + sk->sk_state == BT_CONNECTED) { + if (!l2cap_chan_check_security(chan)) + bt_sk(sk)->suspended = true; + else + sk->sk_state_change(sk); } else { err = -EINVAL; } -- cgit v1.2.3-70-g09d2 From 9d939d948469b49912a76e789f7d4059eb1f8bc7 Mon Sep 17 00:00:00 2001 From: Vishal Agarwal Date: Thu, 26 Apr 2012 19:19:56 +0530 Subject: Bluetooth: Fix EIR data generation for mgmt_device_found The mgmt_device_found function expects to receive only the significant part of the EIR data so it needs to be removed before calling the function. This patch adds a new eir_get_length() helper function to calculate the length of the significant part. Signed-off-by: Vishal Agarwal Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 17 +++++++++++++++++ net/bluetooth/hci_event.c | 4 +++- 2 files changed, 20 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index b60d2c844eb..9fc7728f94e 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -926,6 +926,23 @@ static inline bool eir_has_data_type(u8 *data, size_t data_len, u8 type) return false; } +static inline size_t eir_get_length(u8 *eir, size_t eir_len) +{ + size_t parsed = 0; + + while (parsed < eir_len) { + u8 field_len = eir[0]; + + if (field_len == 0) + return parsed; + + parsed += field_len + 1; + eir += field_len + 1; + } + + return eir_len; +} + static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data, u8 data_len) { diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index fac840afd13..9c60e0d8db5 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3001,6 +3001,7 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct struct inquiry_data data; struct extended_inquiry_info *info = (void *) (skb->data + 1); int num_rsp = *((__u8 *) skb->data); + size_t eir_len; BT_DBG("%s num_rsp %d", hdev->name, num_rsp); @@ -3033,9 +3034,10 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct name_known = hci_inquiry_cache_update(hdev, &data, name_known, &ssp); + eir_len = eir_get_length(info->data, sizeof(info->data)); mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, info->dev_class, info->rssi, !name_known, - ssp, info->data, sizeof(info->data)); + ssp, info->data, eir_len); } hci_dev_unlock(hdev); -- cgit v1.2.3-70-g09d2 From a6a5568c03c4805d4d250f6bd9d468eeeb4ea059 Mon Sep 17 00:00:00 2001 From: Mat Martineau Date: Fri, 4 May 2012 14:20:31 -0700 Subject: Bluetooth: Lock the L2CAP channel when sending The ERTM and streaming mode transmit queue must only be accessed while the L2CAP channel lock is held. Locking the channel before calling l2cap_chan_send ensures that multiple threads cannot simultaneously manipulate the queue when sending and receiving concurrently. L2CAP channel locking had previously moved to the l2cap_chan struct instead of the associated socket, so some of the old socket locking can also be removed in this patch. Signed-off-by: Mat Martineau Signed-off-by: Gustavo Padovan --- include/net/bluetooth/bluetooth.h | 2 -- net/bluetooth/l2cap_sock.c | 12 ++++++------ 2 files changed, 6 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index c34a9a6184a..7981ca48b83 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -257,12 +257,10 @@ static inline struct sk_buff *bt_skb_send_alloc(struct sock *sk, { struct sk_buff *skb; - release_sock(sk); if ((skb = sock_alloc_send_skb(sk, len + BT_SKB_RESERVE, nb, err))) { skb_reserve(skb, BT_SKB_RESERVE); bt_cb(skb)->incoming = 0; } - lock_sock(sk); if (!skb && *err) return NULL; diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index b7bc7b981ee..f6d8e13197d 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -720,16 +720,13 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms if (msg->msg_flags & MSG_OOB) return -EOPNOTSUPP; - lock_sock(sk); - - if (sk->sk_state != BT_CONNECTED) { - release_sock(sk); + if (sk->sk_state != BT_CONNECTED) return -ENOTCONN; - } + l2cap_chan_lock(chan); err = l2cap_chan_send(chan, msg, len, sk->sk_priority); + l2cap_chan_unlock(chan); - release_sock(sk); return err; } @@ -940,7 +937,10 @@ static struct sk_buff *l2cap_sock_alloc_skb_cb(struct l2cap_chan *chan, struct sk_buff *skb; int err; + l2cap_chan_unlock(chan); skb = bt_skb_send_alloc(chan->sk, len, nb, &err); + l2cap_chan_lock(chan); + if (!skb) return ERR_PTR(err); -- cgit v1.2.3-70-g09d2 From c5daa683f2d3315cd766f550ef7d88bfca1671f4 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Wed, 16 May 2012 12:17:10 -0300 Subject: Bluetooth: Create flags for bt_sk() defer_setup and suspended are now flags into bt_sk(). Signed-off-by: Gustavo Padovan Signed-off-by: Johan Hedberg --- include/net/bluetooth/bluetooth.h | 8 ++++++-- net/bluetooth/af_bluetooth.c | 8 ++++---- net/bluetooth/l2cap_core.c | 14 ++++++++------ net/bluetooth/l2cap_sock.c | 21 +++++++++++++-------- net/bluetooth/rfcomm/sock.c | 14 ++++++++++---- 5 files changed, 41 insertions(+), 24 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 7981ca48b83..961669b648f 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -194,8 +194,12 @@ struct bt_sock { bdaddr_t dst; struct list_head accept_q; struct sock *parent; - u32 defer_setup; - bool suspended; + unsigned long flags; +}; + +enum { + BT_SK_DEFER_SETUP, + BT_SK_SUSPEND, }; struct bt_sock_list { diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index 6fb68a9743a..46e7f86acfc 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c @@ -210,7 +210,7 @@ struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock) } if (sk->sk_state == BT_CONNECTED || !newsock || - bt_sk(parent)->defer_setup) { + test_bit(BT_DEFER_SETUP, &bt_sk(parent)->flags)) { bt_accept_unlink(sk); if (newsock) sock_graft(sk, newsock); @@ -410,8 +410,8 @@ static inline unsigned int bt_accept_poll(struct sock *parent) list_for_each_safe(p, n, &bt_sk(parent)->accept_q) { sk = (struct sock *) list_entry(p, struct bt_sock, accept_q); if (sk->sk_state == BT_CONNECTED || - (bt_sk(parent)->defer_setup && - sk->sk_state == BT_CONNECT2)) + (test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags) && + sk->sk_state == BT_CONNECT2)) return POLLIN | POLLRDNORM; } @@ -450,7 +450,7 @@ unsigned int bt_sock_poll(struct file *file, struct socket *sock, poll_table *wa sk->sk_state == BT_CONFIG) return mask; - if (!bt_sk(sk)->suspended && sock_writeable(sk)) + if (!test_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags) && sock_writeable(sk)) mask |= POLLOUT | POLLWRNORM | POLLWRBAND; else set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 285c5e13c7d..24f144b72a9 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -71,7 +71,7 @@ static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data); static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data); static void l2cap_send_disconn_req(struct l2cap_conn *conn, - struct l2cap_chan *chan, int err); + struct l2cap_chan *chan, int err); /* ---- L2CAP channels ---- */ @@ -586,7 +586,7 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason) struct l2cap_conn_rsp rsp; __u16 result; - if (bt_sk(sk)->defer_setup) + if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) result = L2CAP_CR_SEC_BLOCK; else result = L2CAP_CR_BAD_PSM; @@ -1050,7 +1050,8 @@ static void l2cap_conn_start(struct l2cap_conn *conn) if (l2cap_chan_check_security(chan)) { lock_sock(sk); - if (bt_sk(sk)->defer_setup) { + if (test_bit(BT_SK_DEFER_SETUP, + &bt_sk(sk)->flags)) { struct sock *parent = bt_sk(sk)->parent; rsp.result = cpu_to_le16(L2CAP_CR_PEND); rsp.status = cpu_to_le16(L2CAP_CS_AUTHOR_PEND); @@ -3032,7 +3033,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) { if (l2cap_chan_check_security(chan)) { - if (bt_sk(sk)->defer_setup) { + if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) { __l2cap_state_change(chan, BT_CONNECT2); result = L2CAP_CR_PEND; status = L2CAP_CS_AUTHOR_PEND; @@ -4924,7 +4925,7 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) chan->state == BT_CONFIG)) { struct sock *sk = chan->sk; - bt_sk(sk)->suspended = false; + clear_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags); sk->sk_state_change(sk); l2cap_check_encryption(chan, encrypt); @@ -4946,7 +4947,8 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) lock_sock(sk); if (!status) { - if (bt_sk(sk)->defer_setup) { + if (test_bit(BT_SK_DEFER_SETUP, + &bt_sk(sk)->flags)) { struct sock *parent = bt_sk(sk)->parent; res = L2CAP_CR_PEND; stat = L2CAP_CS_AUTHOR_PEND; diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index f52d58e05d0..3bb1611b9d4 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -324,8 +324,8 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us case L2CAP_CONNINFO: if (sk->sk_state != BT_CONNECTED && - !(sk->sk_state == BT_CONNECT2 && - bt_sk(sk)->defer_setup)) { + !(sk->sk_state == BT_CONNECT2 && + test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags))) { err = -ENOTCONN; break; } @@ -399,7 +399,8 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch break; } - if (put_user(bt_sk(sk)->defer_setup, (u32 __user *) optval)) + if (put_user(test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags), + (u32 __user *) optval)) err = -EFAULT; break; @@ -601,10 +602,10 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch /* or for ACL link */ } else if ((sk->sk_state == BT_CONNECT2 && - bt_sk(sk)->defer_setup) || + test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) || sk->sk_state == BT_CONNECTED) { if (!l2cap_chan_check_security(chan)) - bt_sk(sk)->suspended = true; + set_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags); else sk->sk_state_change(sk); } else { @@ -623,7 +624,10 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch break; } - bt_sk(sk)->defer_setup = opt; + if (opt) + set_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags); + else + clear_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags); break; case BT_FLUSHABLE: @@ -741,7 +745,8 @@ static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct ms lock_sock(sk); - if (sk->sk_state == BT_CONNECT2 && bt_sk(sk)->defer_setup) { + if (sk->sk_state == BT_CONNECT2 && test_bit(BT_SK_DEFER_SETUP, + &bt_sk(sk)->flags)) { sk->sk_state = BT_CONFIG; pi->chan->state = BT_CONFIG; @@ -984,7 +989,7 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent) struct l2cap_chan *pchan = l2cap_pi(parent)->chan; sk->sk_type = parent->sk_type; - bt_sk(sk)->defer_setup = bt_sk(parent)->defer_setup; + bt_sk(sk)->flags = bt_sk(parent)->flags; chan->chan_type = pchan->chan_type; chan->imtu = pchan->imtu; diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index a55a43e9f70..e8707debb86 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -260,7 +260,8 @@ static void rfcomm_sock_init(struct sock *sk, struct sock *parent) if (parent) { sk->sk_type = parent->sk_type; - pi->dlc->defer_setup = bt_sk(parent)->defer_setup; + pi->dlc->defer_setup = test_bit(BT_SK_DEFER_SETUP, + &bt_sk(parent)->flags); pi->sec_level = rfcomm_pi(parent)->sec_level; pi->role_switch = rfcomm_pi(parent)->role_switch; @@ -731,7 +732,11 @@ static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, c break; } - bt_sk(sk)->defer_setup = opt; + if (opt) + set_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags); + else + clear_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags); + break; default: @@ -849,7 +854,8 @@ static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, c break; } - if (put_user(bt_sk(sk)->defer_setup, (u32 __user *) optval)) + if (put_user(test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags), + (u32 __user *) optval)) err = -EFAULT; break; @@ -972,7 +978,7 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc * done: bh_unlock_sock(parent); - if (bt_sk(parent)->defer_setup) + if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags)) parent->sk_state_change(parent); return result; -- cgit v1.2.3-70-g09d2