From e46668819c1bd5930720a7e020e2a45291f9de4f Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Fri, 9 Mar 2012 11:59:15 +0200 Subject: Bluetooth: trivial: Correct endian conversion Correct endian conversion reported by sparse Signed-off-by: Andrei Emeltchenko Signed-off-by: Gustavo F. Padovan --- net/bluetooth/hci_event.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 6c065254afc0..982ae3c52db4 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3336,7 +3336,7 @@ static inline void hci_le_ltk_request_evt(struct hci_dev *hdev, struct hci_conn *conn; struct smp_ltk *ltk; - BT_DBG("%s handle %d", hdev->name, cpu_to_le16(ev->handle)); + BT_DBG("%s handle %d", hdev->name, __le16_to_cpu(ev->handle)); hci_dev_lock(hdev); -- cgit v1.2.3 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 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 53e8eb2f0a2e..0eec5dbaee0f 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 edfd61addcec..af55ea1b6882 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 From 78e8098e7b8db6a7dc01406464329c37d3b4973d Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Fri, 9 Mar 2012 13:00:50 +0200 Subject: Bluetooth: Fix extra conversion to __le32 Value to be converted is already in __le32 format. Signed-off-by: Andrei Emeltchenko Signed-off-by: Gustavo F. Padovan --- net/bluetooth/mgmt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 4bb03b111122..4a2fb06226fc 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3112,7 +3112,7 @@ int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr, bacpy(&ev.addr.bdaddr, bdaddr); ev.addr.type = link_to_mgmt(link_type, addr_type); ev.confirm_hint = confirm_hint; - put_unaligned_le32(value, &ev.value); + ev.value = value; return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev), NULL); -- cgit v1.2.3 From 097db76cdccd8107784e2c845b838ab333be02dc Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Fri, 9 Mar 2012 14:16:17 +0200 Subject: Bluetooth: Correct chan->psm endian conversions chan->psm is kept in __le16 format which was not always taken into account. Fix several bugs related to extra conversion. Signed-off-by: Andrei Emeltchenko Signed-off-by: Gustavo F. Padovan --- net/bluetooth/l2cap_core.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 94552b33d528..7b8a88fd3b78 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -301,7 +301,7 @@ void l2cap_chan_destroy(struct l2cap_chan *chan) 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, - chan->psm, chan->dcid); + __le16_to_cpu(chan->psm), chan->dcid); conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM; @@ -1144,7 +1144,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *d int err; BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst), - chan->psm); + __le16_to_cpu(chan->psm)); hdev = hci_get_route(dst, src); if (!hdev) @@ -1612,7 +1612,7 @@ static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); lh->cid = cpu_to_le16(chan->dcid); lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE)); - put_unaligned_le16(chan->psm, skb_put(skb, 2)); + put_unaligned(chan->psm, skb_put(skb, 2)); err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb); if (unlikely(err < 0)) { @@ -2644,7 +2644,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd u16 dcid = 0, scid = __le16_to_cpu(req->scid); __le16 psm = req->psm; - BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid); + BT_DBG("psm 0x%2.2x scid 0x%4.4x", __le16_to_cpu(psm), scid); /* Check if we have socket listening on psm */ pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, conn->src); @@ -4445,7 +4445,7 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) break; case L2CAP_CID_CONN_LESS: - psm = get_unaligned_le16(skb->data); + psm = get_unaligned((__le16 *) skb->data); skb_pull(skb, 2); l2cap_conless_channel(conn, psm, skb); break; -- cgit v1.2.3 From bc3dd33cef001e61da0f71b5d8f918b3dbaa4a94 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Tue, 6 Mar 2012 19:37:06 -0300 Subject: Bluetooth: Check FINDING state in interleaved discovery In order to do interleaved discovery we should be in DISCOVERY_ FINDING state. Otherwise, discovery should be stopped. Signed-off-by: Andre Guedes Signed-off-by: Gustavo F. Padovan --- net/bluetooth/hci_event.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 982ae3c52db4..50ff9a989531 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1098,7 +1098,8 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, schedule_delayed_work(&hdev->adv_work, ADV_CLEAR_TIMEOUT); - if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED) { + if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED && + hdev->discovery.state == DISCOVERY_FINDING) { mgmt_interleaved_discovery(hdev); } else { hci_dev_lock(hdev); -- cgit v1.2.3 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 'net') diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 98a8c05d4f23..e564579a6115 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 0eec5dbaee0f..c80a9684a144 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 bc154298979a..60b93d8219ef 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 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 'net') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index d47e523c9d83..3edb3e759ffe 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 c80a9684a144..ce09bf1592e2 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 50ff9a989531..75f01d1b126f 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 4a2fb06226fc..02b89e299ff8 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 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 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index ce09bf1592e2..c8e24a9b176c 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 02b89e299ff8..1da458d9b5ca 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 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 'net') diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index ebfd91fc20f8..23fd0546fccb 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 1da458d9b5ca..5e88fda42f1f 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 From eb55ef07a211eea95088eb0e6cdbd53cd65d9755 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 14 Mar 2012 18:08:46 +0200 Subject: Bluetooth: Fix broken usage of put_unaligned_le16 In case the struct is already __packed, there is no need to use unaligned access to the data. So just use cpu_to_le16 or __constant_cpu_to_le16 in these cases. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 5e88fda42f1f..194a0426a3e5 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -225,7 +225,7 @@ static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status) ev = (void *) skb_put(skb, sizeof(*ev)); ev->status = status; - put_unaligned_le16(cmd, &ev->opcode); + ev->opcode = cpu_to_le16(cmd); err = sock_queue_rcv_skb(sk, skb); if (err < 0) @@ -255,7 +255,7 @@ static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status, hdr->len = cpu_to_le16(sizeof(*ev) + rp_len); ev = (void *) skb_put(skb, sizeof(*ev) + rp_len); - put_unaligned_le16(cmd, &ev->opcode); + ev->opcode = cpu_to_le16(cmd); ev->status = status; if (rp) @@ -276,7 +276,7 @@ static int read_version(struct sock *sk, struct hci_dev *hdev, void *data, BT_DBG("sock %p", sk); rp.version = MGMT_VERSION; - put_unaligned_le16(MGMT_REVISION, &rp.revision); + rp.revision = __constant_cpu_to_le16(MGMT_REVISION); return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp, sizeof(rp)); @@ -286,8 +286,8 @@ static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data, u16 data_len) { struct mgmt_rp_read_commands *rp; - u16 num_commands = ARRAY_SIZE(mgmt_commands); - u16 num_events = ARRAY_SIZE(mgmt_events); + const u16 num_commands = ARRAY_SIZE(mgmt_commands); + const u16 num_events = ARRAY_SIZE(mgmt_events); u16 *opcode; size_t rp_size; int i, err; @@ -300,8 +300,8 @@ static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data, if (!rp) return -ENOMEM; - put_unaligned_le16(num_commands, &rp->num_commands); - put_unaligned_le16(num_events, &rp->num_events); + rp->num_commands = __constant_cpu_to_le16(num_commands); + rp->num_events = __constant_cpu_to_le16(num_events); for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++) put_unaligned_le16(mgmt_commands[i], opcode); @@ -342,14 +342,14 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data, return -ENOMEM; } - put_unaligned_le16(count, &rp->num_controllers); + rp->num_controllers = cpu_to_le16(count); i = 0; list_for_each_entry(d, &hci_dev_list, list) { if (test_bit(HCI_SETUP, &d->dev_flags)) continue; - put_unaligned_le16(d->id, &rp->index[i++]); + rp->index[i++] = cpu_to_le16(d->id); BT_DBG("Added hci%u", d->id); } @@ -665,8 +665,7 @@ static int read_controller_info(struct sock *sk, struct hci_dev *hdev, bacpy(&rp.bdaddr, &hdev->bdaddr); rp.version = hdev->hci_ver; - - put_unaligned_le16(hdev->manufacturer, &rp.manufacturer); + rp.manufacturer = cpu_to_le16(hdev->manufacturer); rp.supported_settings = cpu_to_le32(get_supported_settings(hdev)); rp.current_settings = cpu_to_le32(get_current_settings(hdev)); @@ -1571,7 +1570,7 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data, goto unlock; } - put_unaligned_le16(conn->handle, &dc.handle); + dc.handle = cpu_to_le16(conn->handle); dc.reason = 0x13; /* Remote User Terminated Connection */ err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc); if (err < 0) @@ -1624,7 +1623,7 @@ static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data, goto failed; } - put_unaligned_le16(conn->handle, &dc.handle); + dc.handle = cpu_to_le16(conn->handle); dc.reason = 0x13; /* Remote User Terminated Connection */ err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc); @@ -1698,7 +1697,7 @@ static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data, i++; } - put_unaligned_le16(i, &rp->conn_count); + rp->conn_count = cpu_to_le16(i); /* Recalculate length in case of filtered SCO connections, etc */ rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info)); @@ -2992,7 +2991,7 @@ int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV, dev_class, 3); - put_unaligned_le16(eir_len, &ev->eir_len); + ev->eir_len = cpu_to_le16(eir_len); return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf, sizeof(*ev) + eir_len, NULL); @@ -3517,7 +3516,7 @@ int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV, dev_class, 3); - put_unaligned_le16(eir_len, &ev->eir_len); + ev->eir_len = cpu_to_le16(eir_len); ev_size = sizeof(*ev) + eir_len; @@ -3542,7 +3541,7 @@ int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name, name_len); - put_unaligned_le16(eir_len, &ev->eir_len); + ev->eir_len = cpu_to_le16(eir_len); return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL); -- cgit v1.2.3 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 'net') diff --git a/include/net/bluetooth/smp.h b/include/net/bluetooth/smp.h index 7b3acdd29134..ca356a734920 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 deb119875fd9..6fc7c4708f3e 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 From 61386cba0fae4744b8e2f52c4911fe3af9ff6c54 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Mon, 12 Mar 2012 12:13:07 +0200 Subject: Bluetooth: Correct length calc in L2CAP conf rsp cmd->len is in le format so convert it to host format before use. Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 7b8a88fd3b78..0914cca7b578 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -2957,14 +2957,14 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data; u16 scid, flags, result; struct l2cap_chan *chan; - int len = cmd->len - sizeof(*rsp); + int len = le16_to_cpu(cmd->len) - sizeof(*rsp); scid = __le16_to_cpu(rsp->scid); flags = __le16_to_cpu(rsp->flags); result = __le16_to_cpu(rsp->result); - BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x", - scid, flags, result); + BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x len %d", scid, flags, + result, len); chan = l2cap_get_chan_by_scid(conn, scid); if (!chan) -- cgit v1.2.3 From d9b887020eb54eeb78d222c862ef2dc65b8e0ebe Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Mon, 12 Mar 2012 12:13:08 +0200 Subject: Bluetooth: Correct CID endian notation L2CAP channel id is used in host format in internal L2CAP code. Fix sparse warnings about wrong endian conversion. Signed-off-by: Andrei Emeltchenko Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 0914cca7b578..1a2f54b8f30c 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -833,7 +833,8 @@ static void l2cap_conn_start(struct l2cap_conn *conn) /* Find socket with cid and source bdaddr. * Returns closest match, locked. */ -static struct l2cap_chan *l2cap_global_chan_by_scid(int state, __le16 cid, bdaddr_t *src) +static struct l2cap_chan *l2cap_global_chan_by_scid(int state, u16 cid, + bdaddr_t *src) { struct l2cap_chan *c, *c1 = NULL; @@ -4396,7 +4397,8 @@ drop: return 0; } -static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct sk_buff *skb) +static inline int l2cap_att_channel(struct l2cap_conn *conn, u16 cid, + struct sk_buff *skb) { struct l2cap_chan *chan; -- cgit v1.2.3 From 8ce0c498aa6f40db119d5eb60aa9e7de5e66880e Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Mon, 12 Mar 2012 12:13:09 +0200 Subject: Bluetooth: Convert error codes to le16 Create Chan Rsp shall put result and status in le format. Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 1a2f54b8f30c..aaab65515098 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -3266,8 +3266,8 @@ static inline int l2cap_create_channel_req(struct l2cap_conn *conn, /* Placeholder: Always reject */ rsp.dcid = 0; rsp.scid = cpu_to_le16(scid); - rsp.result = L2CAP_CR_NO_MEM; - rsp.status = L2CAP_CS_NO_INFO; + rsp.result = __constant_cpu_to_le16(L2CAP_CR_NO_MEM); + rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO); l2cap_send_cmd(conn, cmd->ident, L2CAP_CREATE_CHAN_RSP, sizeof(rsp), &rsp); -- cgit v1.2.3 From 4fd21a88e311c03241f323f64aef643fcd5f149d Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Mon, 12 Mar 2012 12:13:10 +0200 Subject: Bluetooth: trivial: Fix endian conversion mode In L2CAP we use le16 format so change direction of conversion from le16_to_cpu to cpu_to_le16. Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index aaab65515098..4b66cad3ee3d 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -2379,9 +2379,9 @@ done: chan->remote_mps = size; rfc.retrans_timeout = - le16_to_cpu(L2CAP_DEFAULT_RETRANS_TO); + __constant_cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO); rfc.monitor_timeout = - le16_to_cpu(L2CAP_DEFAULT_MONITOR_TO); + __constant_cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO); set_bit(CONF_MODE_DONE, &chan->conf_state); -- cgit v1.2.3 From 739f43e860748f0e86034512d65ca480581b1b35 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Mon, 12 Mar 2012 15:59:31 +0200 Subject: Bluetooth: trivial: Correct types Fix sparse warnigns below: ... net/bluetooth/hci_sysfs.c:458:33: warning: cast to restricted __be32 net/bluetooth/hci_sysfs.c:458:47: warning: cast to restricted __be16 ... Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_sysfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index 60b93d8219ef..937f3187eafa 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c @@ -444,8 +444,8 @@ static const struct file_operations blacklist_fops = { static void print_bt_uuid(struct seq_file *f, u8 *uuid) { - u32 data0, data4; - u16 data1, data2, data3, data5; + __be32 data0, data4; + __be16 data1, data2, data3, data5; memcpy(&data0, &uuid[0], 4); memcpy(&data1, &uuid[4], 2); -- cgit v1.2.3 From 035100c8a808e5484ca0848cebed91783e1868cf Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Mon, 12 Mar 2012 15:59:32 +0200 Subject: Bluetooth: Fix type in cpu_to_le conversion Use struct hci_cp_write_def_link_policy to overcome sparse warnigs below: ... net/bluetooth/hci_event.c:633:21: warning: incorrect type in assignment (different base types) net/bluetooth/hci_event.c:633:21: expected unsigned short [unsigned] [assigned] [usertype] link_policy net/bluetooth/hci_event.c:633:21: got restricted __le16 [usertype] ... Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_event.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 75f01d1b126f..ecf885b79af1 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -615,6 +615,7 @@ done: static void hci_setup_link_policy(struct hci_dev *hdev) { + struct hci_cp_write_def_link_policy cp; u16 link_policy = 0; if (hdev->features[0] & LMP_RSWITCH) @@ -626,9 +627,8 @@ static void hci_setup_link_policy(struct hci_dev *hdev) if (hdev->features[1] & LMP_PARK) link_policy |= HCI_LP_PARK; - link_policy = cpu_to_le16(link_policy); - hci_send_cmd(hdev, HCI_OP_WRITE_DEF_LINK_POLICY, sizeof(link_policy), - &link_policy); + cp.policy = cpu_to_le16(link_policy); + hci_send_cmd(hdev, HCI_OP_WRITE_DEF_LINK_POLICY, sizeof(cp), &cp); } static void hci_cc_read_local_commands(struct hci_dev *hdev, struct sk_buff *skb) -- cgit v1.2.3 From 1036b89042df96e71c0cb941be212f8053ecccc0 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Mon, 12 Mar 2012 15:59:33 +0200 Subject: Bluetooth: Fix opcode access in hci_complete opcode to be accessed is in le16 format so convert it first to cpu byte order. Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index af55ea1b6882..47a4e9b26b9a 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -83,6 +83,7 @@ void hci_req_complete(struct hci_dev *hdev, __u16 cmd, int result) */ if (test_bit(HCI_INIT, &hdev->flags) && hdev->init_last_cmd != cmd) { struct hci_command_hdr *sent = (void *) hdev->sent_cmd->data; + u16 opcode = __le16_to_cpu(sent->opcode); struct sk_buff *skb; /* Some CSR based controllers generate a spontaneous @@ -92,7 +93,7 @@ void hci_req_complete(struct hci_dev *hdev, __u16 cmd, int result) * command. */ - if (cmd != HCI_OP_RESET || sent->opcode == HCI_OP_RESET) + if (cmd != HCI_OP_RESET || opcode == HCI_OP_RESET) return; skb = skb_clone(hdev->sent_cmd, GFP_ATOMIC); -- cgit v1.2.3 From 1f350c8724881fe6b1be9aa68d1e49508a6f8ab9 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 12 Mar 2012 20:31:08 -0700 Subject: Bluetooth: Fix broken usage of get_unaligned_le16 In case the struct is already __packed, there is no need to use unaligned access to the data. So just use __le16_to_cpu in these cases. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 194a0426a3e5..287623c35d61 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -862,7 +862,7 @@ static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data, BT_DBG("request for %s", hdev->name); - timeout = get_unaligned_le16(&cp->timeout); + timeout = __le16_to_cpu(cp->timeout); if (!cp->val && timeout > 0) return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE, MGMT_STATUS_INVALID_PARAMS); @@ -1461,7 +1461,7 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data, u16 key_count, expected_len; int i; - key_count = get_unaligned_le16(&cp->key_count); + key_count = __le16_to_cpu(cp->key_count); expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_link_key_info); @@ -2611,7 +2611,7 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, u16 key_count, expected_len; int i; - key_count = get_unaligned_le16(&cp->key_count); + key_count = __le16_to_cpu(cp->key_count); expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_ltk_info); @@ -2722,9 +2722,9 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) } hdr = buf; - opcode = get_unaligned_le16(&hdr->opcode); - index = get_unaligned_le16(&hdr->index); - len = get_unaligned_le16(&hdr->len); + opcode = __le16_to_cpu(hdr->opcode); + index = __le16_to_cpu(hdr->index); + len = __le16_to_cpu(hdr->len); if (len != msglen - sizeof(*hdr)) { err = -EINVAL; -- cgit v1.2.3 From 2e3c35ead821498f5b0a5b6c62365fbb187420fc Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Wed, 14 Mar 2012 18:54:15 +0200 Subject: Bluetooth: trivial: Remove sparse warnings Fix sparse warnings related to incorrect type in assignment and static symbol. Also use const keyword. Warnings are shown below: ... net/bluetooth/mgmt.c:305:28: warning: incorrect type in assignment (different base types) net/bluetooth/mgmt.c:305:28: expected unsigned short [usertype] *opcode net/bluetooth/mgmt.c:305:28: got restricted __le16 * ... net/bluetooth/mgmt.c:2609:3: warning: symbol 'mgmt_handlers' was not declared. Should it be static? ... Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 287623c35d61..0ef4b6ca6e44 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -288,7 +288,7 @@ static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data, struct mgmt_rp_read_commands *rp; const u16 num_commands = ARRAY_SIZE(mgmt_commands); const u16 num_events = ARRAY_SIZE(mgmt_events); - u16 *opcode; + __le16 *opcode; size_t rp_size; int i, err; @@ -2647,7 +2647,7 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, return 0; } -struct mgmt_handler { +static const struct mgmt_handler { int (*func) (struct sock *sk, struct hci_dev *hdev, void *data, u16 data_len); bool var_len; @@ -2704,7 +2704,7 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) struct mgmt_hdr *hdr; u16 opcode, index, len; struct hci_dev *hdev = NULL; - struct mgmt_handler *handler; + const struct mgmt_handler *handler; int err; BT_DBG("got %zu bytes", msglen); -- cgit v1.2.3 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 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index c8e24a9b176c..f7cf928ab6ff 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 47a4e9b26b9a..e3920b693f04 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 From c9ecc48e2f3577a73dcd830d8b67ecc48e224465 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Thu, 15 Mar 2012 16:52:08 -0300 Subject: Bluetooth: LE support for MGMT stop discovery This patch adds LE support to MGMT stop discovery command. So, now we are able to cancel LE discovery procedures (LE-only and interleaved). Signed-off-by: Andre Guedes Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_event.c | 6 +++++- net/bluetooth/mgmt.c | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index ecf885b79af1..0a936291f0e7 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1094,8 +1094,12 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, break; case LE_SCANNING_DISABLED: - if (status) + if (status) { + hci_dev_lock(hdev); + mgmt_stop_discovery_failed(hdev, status); + hci_dev_unlock(hdev); return; + } clear_bit(HCI_LE_SCAN, &hdev->dev_flags); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 0ef4b6ca6e44..5fc741bab2bf 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2404,7 +2404,11 @@ static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data, } if (hdev->discovery.state == DISCOVERY_FINDING) { - err = hci_cancel_inquiry(hdev); + if (test_bit(HCI_INQUIRY, &hdev->flags)) + err = hci_cancel_inquiry(hdev); + else + err = hci_cancel_le_scan(hdev); + if (err < 0) mgmt_pending_remove(cmd); else -- cgit v1.2.3 From d97dcb66001222efa79e55f5260b9b660fd452a4 Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Fri, 16 Mar 2012 16:02:56 +0100 Subject: Bluetooth: mgmt: Fix some code style and indentation issues Signed-off-by: Szymon Janc Acked-by: Gustavo Padovan Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 5fc741bab2bf..402cb0026f5d 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1144,8 +1144,8 @@ static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) } if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) { - err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, - MGMT_STATUS_BUSY); + err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, + MGMT_STATUS_BUSY); goto failed; } @@ -3052,7 +3052,7 @@ int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, sk); if (sk) - sock_put(sk); + sock_put(sk); mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp, hdev); @@ -3464,10 +3464,10 @@ int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status) if (enable && test_and_clear_bit(HCI_LE_ENABLED, &hdev->dev_flags)) - err = new_settings(hdev, NULL); + err = new_settings(hdev, NULL); - mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, - cmd_status_rsp, &mgmt_err); + mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp, + &mgmt_err); return err; } -- cgit v1.2.3 From c72d4b8afa8002cd6f64225954bee78296321e7e Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Fri, 16 Mar 2012 16:02:57 +0100 Subject: Bluetooth: mgmt: Don't allow to set invalid value to DeviceID source Reply with MGMT_STATUS_INVALID_PARAMS when userspace is trying to set source with out-of-scope value. Signed-off-by: Szymon Janc Acked-by: Gustavo Padovan Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 402cb0026f5d..f590dfbe9e07 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2532,12 +2532,19 @@ static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data, { struct mgmt_cp_set_device_id *cp = data; int err; + __u16 source; BT_DBG("%s", hdev->name); + source = __le16_to_cpu(cp->source); + + if (source > 0x0002) + return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, + MGMT_STATUS_INVALID_PARAMS); + hci_dev_lock(hdev); - hdev->devid_source = __le16_to_cpu(cp->source); + hdev->devid_source = 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); -- cgit v1.2.3 From 3e9fb6d87ee543b10bcf245d4a5c6aa1ab0ac2ab Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Tue, 20 Mar 2012 10:32:25 +0200 Subject: Bluetooth: Silence sparse warning Silence sparse warning shown below: ... net/bluetooth/mgmt.c:448:15: warning: cast to restricted __le32 ... Signed-off-by: Andrei Emeltchenko Signed-off-by: Gustavo Padovan --- net/bluetooth/mgmt.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index f590dfbe9e07..1d3e3d00d25f 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -443,9 +443,7 @@ static u16 get_uuid16(u8 *uuid128) return 0; } - memcpy(&val, &uuid128[12], 4); - - val = le32_to_cpu(val); + val = get_unaligned_le32(&uuid128[12]); if (val > 0xffff) return 0; -- cgit v1.2.3 From 7537e5c3064c5a5751a7b26aba82ad83c5e89190 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Tue, 20 Mar 2012 00:13:38 -0300 Subject: Bluetooth: Replace EPERM by EALREADY in hci_cancel_inquiry We should return -EALREADY in hci_cancel_inquiry since it is more suitable than -EPERM error code. Signed-off-by: Andre Guedes Signed-off-by: Gustavo Padovan --- net/bluetooth/hci_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index e3920b693f04..cc3d164f56fb 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2956,7 +2956,7 @@ int hci_cancel_inquiry(struct hci_dev *hdev) BT_DBG("%s", hdev->name); if (!test_bit(HCI_INQUIRY, &hdev->flags)) - return -EPERM; + return -EALREADY; return hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL); } -- cgit v1.2.3 From e0d9727edb3b66865989a1f592c06606392146ca Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Tue, 20 Mar 2012 15:15:36 -0300 Subject: Bluetooth: Refactor stop_discovery This patch does a trivial code refactoring in stop_discovery function by using a switch statement instead of an if-return-else approach. Signed-off-by: Andre Guedes Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- net/bluetooth/mgmt.c | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 1d3e3d00d25f..2975a10fca07 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2401,31 +2401,39 @@ static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data, goto unlock; } - if (hdev->discovery.state == DISCOVERY_FINDING) { + switch (hdev->discovery.state) { + case DISCOVERY_FINDING: if (test_bit(HCI_INQUIRY, &hdev->flags)) err = hci_cancel_inquiry(hdev); else err = hci_cancel_le_scan(hdev); - if (err < 0) + break; + + case DISCOVERY_RESOLVING: + e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, + NAME_PENDING); + if (!e) { mgmt_pending_remove(cmd); - else - hci_discovery_set_state(hdev, DISCOVERY_STOPPING); - goto unlock; - } + err = cmd_complete(sk, hdev->id, + MGMT_OP_STOP_DISCOVERY, 0, + &mgmt_cp->type, + sizeof(mgmt_cp->type)); + hci_discovery_set_state(hdev, DISCOVERY_STOPPED); + goto unlock; + } - e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING); - if (!e) { - mgmt_pending_remove(cmd); - err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY, 0, - &mgmt_cp->type, sizeof(mgmt_cp->type)); - hci_discovery_set_state(hdev, DISCOVERY_STOPPED); - goto unlock; + bacpy(&cp.bdaddr, &e->data.bdaddr); + err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL, + sizeof(cp), &cp); + + break; + + default: + BT_DBG("unknown discovery state %u", hdev->discovery.state); + err = -EFAULT; } - bacpy(&cp.bdaddr, &e->data.bdaddr); - err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp), - &cp); if (err < 0) mgmt_pending_remove(cmd); else -- cgit v1.2.3 From 4d93483b1c593a5ee5b3f917c26dbaad59dadde2 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 --- net/bluetooth/hci_event.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'net') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 0a936291f0e7..a0fc1afb3ae4 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -69,6 +69,13 @@ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb) hci_conn_check_pending(hdev); } +static void hci_cc_periodic_inq(struct hci_dev *hdev, struct sk_buff *skb) +{ + __u8 status = *((__u8 *) skb->data); + + BT_DBG("%s status 0x%x", hdev->name, status); +} + static void hci_cc_exit_periodic_inq(struct hci_dev *hdev, struct sk_buff *skb) { __u8 status = *((__u8 *) skb->data); @@ -2155,6 +2162,10 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk hci_cc_inquiry_cancel(hdev, skb); break; + case HCI_OP_PERIODIC_INQ: + hci_cc_periodic_inq(hdev, skb); + break; + case HCI_OP_EXIT_PERIODIC_INQ: hci_cc_exit_periodic_inq(hdev, skb); break; -- cgit v1.2.3 From ae854a70df3e2183a8db7a98a0deceee111c4542 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 --- net/bluetooth/hci_event.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index a0fc1afb3ae4..a61838b74257 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -74,6 +74,11 @@ static void hci_cc_periodic_inq(struct hci_dev *hdev, struct sk_buff *skb) __u8 status = *((__u8 *) skb->data); BT_DBG("%s status 0x%x", hdev->name, status); + + if (status) + return; + + set_bit(HCI_PERIODIC_INQ, &hdev->dev_flags); } static void hci_cc_exit_periodic_inq(struct hci_dev *hdev, struct sk_buff *skb) @@ -85,6 +90,8 @@ static void hci_cc_exit_periodic_inq(struct hci_dev *hdev, struct sk_buff *skb) if (status) return; + clear_bit(HCI_PERIODIC_INQ, &hdev->dev_flags); + hci_conn_check_pending(hdev); } @@ -199,7 +206,8 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb) hci_req_complete(hdev, HCI_OP_RESET, status); /* Reset all non-persistent flags */ - hdev->dev_flags &= ~(BIT(HCI_LE_SCAN) | BIT(HCI_PENDING_CLASS)); + hdev->dev_flags &= ~(BIT(HCI_LE_SCAN) | BIT(HCI_PENDING_CLASS) | + BIT(HCI_PERIODIC_INQ)); hdev->discovery.state = DISCOVERY_STOPPED; } -- cgit v1.2.3 From 642be6c768bd686577ffe6ebcc5e6132a932537b Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Wed, 21 Mar 2012 00:03:37 -0300 Subject: Bluetooth: Check HCI_PERIODIC_INQ in start_discovery This patch adds a HCI_PERIODIC_INQ check to start_discovery. If periodic inquiry is enabled, we fail MGMT Start Discovery command with MGMT_STATUS_BUSY code. Signed-off-by: Andre Guedes Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- net/bluetooth/mgmt.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 2975a10fca07..4bb0a130e7d9 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2315,6 +2315,12 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev, goto failed; } + if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) { + err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY, + MGMT_STATUS_BUSY); + goto failed; + } + if (hdev->discovery.state != DISCOVERY_STOPPED) { err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY, MGMT_STATUS_BUSY); -- cgit v1.2.3 From 1519cc177a05b96d8715c3cda244c46d6457efbb Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Wed, 21 Mar 2012 00:03:38 -0300 Subject: Bluetooth: Ignore inquiry results from periodic inquiry This patch changes inquiry result function handlers so they ignore inquiry result events if periodic inquiry is enabled. Signed-off-by: Andre Guedes Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- net/bluetooth/hci_event.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'net') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index a61838b74257..1778b18ffd97 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1722,6 +1722,9 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff * if (!num_rsp) return; + if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) + return; + hci_dev_lock(hdev); for (; num_rsp; num_rsp--, info++) { @@ -2826,6 +2829,9 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct if (!num_rsp) return; + if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) + return; + hci_dev_lock(hdev); if ((skb->len - 1) / num_rsp != sizeof(struct inquiry_info_with_rssi)) { @@ -2997,6 +3003,9 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct if (!num_rsp) return; + if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) + return; + hci_dev_lock(hdev); for (; num_rsp; num_rsp--, info++) { -- cgit v1.2.3 From bcd11ff7c2f7bf3d18fc9053994466e09b2d42d3 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Wed, 21 Mar 2012 10:34:32 +0200 Subject: Bluetooth: Remove unneeded timer clear set_chan_timer clears timer itself Signed-off-by: Andrei Emeltchenko Signed-off-by: Gustavo Padovan --- net/bluetooth/l2cap_core.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 4b66cad3ee3d..b05311ef71d3 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -453,7 +453,6 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason) case BT_CONFIG: if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED && conn->hcon->type == ACL_LINK) { - __clear_chan_timer(chan); __set_chan_timer(chan, sk->sk_sndtimeo); l2cap_send_disconn_req(conn, chan, reason); } else @@ -4542,7 +4541,6 @@ static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt) if (encrypt == 0x00) { if (chan->sec_level == BT_SECURITY_MEDIUM) { - __clear_chan_timer(chan); __set_chan_timer(chan, L2CAP_ENC_TIMEOUT); } else if (chan->sec_level == BT_SECURITY_HIGH) l2cap_chan_close(chan, ECONNREFUSED); @@ -4600,7 +4598,6 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) if (!status) { l2cap_send_conn_req(chan); } else { - __clear_chan_timer(chan); __set_chan_timer(chan, L2CAP_DISC_TIMEOUT); } } else if (chan->state == BT_CONNECT2) { -- cgit v1.2.3 From 14a284918416e480bf49f8c05dfeefa02640d2d6 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Fri, 23 Mar 2012 16:31:49 +0200 Subject: Bluetooth: Make L2CAP chan_add functions static Remove sparse warnings below: ... net/bluetooth/l2cap_core.c:302:6: warning: symbol '__l2cap_chan_add' was not declared. Should it be static? net/bluetooth/l2cap_core.c:351:6: warning: symbol 'l2cap_chan_add' was not declared. Should it be static? ... Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- net/bluetooth/l2cap_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index b05311ef71d3..8a3de1149352 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -298,7 +298,7 @@ void l2cap_chan_destroy(struct l2cap_chan *chan) l2cap_chan_put(chan); } -void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) +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, __le16_to_cpu(chan->psm), chan->dcid); @@ -347,7 +347,7 @@ void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) list_add(&chan->list, &conn->chan_l); } -void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) +static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) { mutex_lock(&conn->chan_lock); __l2cap_chan_add(conn, chan); -- cgit v1.2.3 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 'net') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index c988df6f63bf..f6f0500bf370 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 8a3de1149352..a57d96afa245 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 29122ed28ea9..53e563f01723 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 From 053262dce5a0cc503456d15e204cde205dcf927e Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 27 Mar 2012 18:49:02 +0200 Subject: Bluetooth: Update management interface revision For each kernel release where commands or events are added to the management interface, the revision field should be increment by one. The increment should only happen once per kernel release and not for every command/event that gets added. The revision value is for informational purposes only, but this simple policy would make any future debugging a lot simple. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 4bb0a130e7d9..d08edadd8bca 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -38,7 +38,7 @@ bool enable_hs; bool enable_le; #define MGMT_VERSION 1 -#define MGMT_REVISION 0 +#define MGMT_REVISION 1 static const u16 mgmt_commands[] = { MGMT_OP_READ_INDEX_LIST, -- cgit v1.2.3 From 3a602a00a4a9d531b4a71ceed487d84103e4b141 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Wed, 28 Mar 2012 16:06:41 +0300 Subject: Bluetooth: Remove unneeded zero initialization Remove zero initialization since channel is allocated with kzalloc in l2cap_chan_create. Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- net/bluetooth/l2cap_sock.c | 1 - 1 file changed, 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 53e563f01723..1d3e9c328a36 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -1011,7 +1011,6 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent) chan->tx_win = L2CAP_DEFAULT_TX_WINDOW; chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW; chan->sec_level = BT_SECURITY_LOW; - chan->flags = 0; set_bit(FLAG_FORCE_ACTIVE, &chan->flags); } -- cgit v1.2.3 From eb19aaacb3f88dbd69e1cd9a2b1f054d4dade678 Mon Sep 17 00:00:00 2001 From: Hemant Gupta Date: Fri, 30 Mar 2012 17:23:35 +0530 Subject: Bluetooth: Send correct address type for LTK This patch updates the address type sent from kernel to management interface of BlueZ while sending the Long Term Key. Signed-off-by: Hemant Gupta Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index d08edadd8bca..1ec16721ed7a 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2978,7 +2978,7 @@ int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent) ev.store_hint = persistent; bacpy(&ev.key.addr.bdaddr, &key->bdaddr); - ev.key.addr.type = key->bdaddr_type; + ev.key.addr.type = link_to_mgmt(LE_LINK, key->bdaddr_type); ev.key.authenticated = key->authenticated; ev.key.enc_size = key->enc_size; ev.key.ediv = key->ediv; -- cgit v1.2.3 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 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index f7cf928ab6ff..afdea9530d7b 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 1ec16721ed7a..5e80c6db6ae7 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 From b24c62471c276b7ac6105e832eb6fe3c41a654ef Mon Sep 17 00:00:00 2001 From: Hemant Gupta Date: Thu, 5 Apr 2012 10:27:21 +0530 Subject: Bluetooth: Fix clearing discovery type when stopping discovery This patch prevents resetting of discovery type while stopping discovery, since otherwise the wrong type might be send in case of discovery failure. It also doesn't matter that we are "lazy" with updating the type since it is anyway reset when starting discovery again and it's not needed to know the current discovery state. Signed-off-by: Hemant Gupta Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 1 - 1 file changed, 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index cc3d164f56fb..a6108469e9eb 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -385,7 +385,6 @@ void hci_discovery_set_state(struct hci_dev *hdev, int state) case DISCOVERY_STOPPED: if (hdev->discovery.state != DISCOVERY_STARTING) mgmt_discovering(hdev, 0); - hdev->discovery.type = 0; break; case DISCOVERY_STARTING: break; -- cgit v1.2.3 From 328c9248bfa7f5e1490ee82e9027e14c3ecc0485 Mon Sep 17 00:00:00 2001 From: Hemant Gupta Date: Thu, 5 Apr 2012 16:51:04 +0530 Subject: Bluetooth: mgmt: Fix missing connect failed event for LE This patch adds management connect failed event when LE Create Connection Command fails to inform user space that LE Connection failed to get established. Signed-off-by: Hemant Gupta Signed-off-by: Johan Hedberg --- net/bluetooth/hci_event.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 1778b18ffd97..054b1ad74496 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1648,6 +1648,8 @@ static void hci_cs_le_create_conn(struct hci_dev *hdev, __u8 status) if (status) { if (conn && conn->state == BT_CONNECT) { conn->state = BT_CLOSED; + mgmt_connect_failed(hdev, &cp->peer_addr, conn->type, + conn->dst_type, status); hci_proto_connect_cfm(conn, status); hci_conn_del(conn); } -- cgit v1.2.3 From 6bcbc4893fe8a6be3c3c5a83449d79dc9e9a51ac Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Wed, 28 Mar 2012 16:31:24 +0300 Subject: Bluetooth: Add Read Local AMP Info to init AMP Info will be used in Discovery Response. Signed-off-by: Andrei Emeltchenko Signed-off-by: Gustavo Padovan --- net/bluetooth/hci_core.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'net') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index a6108469e9eb..3b3d9a882dbd 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -252,6 +252,9 @@ static void amp_init(struct hci_dev *hdev) /* Read Local Version */ hci_send_cmd(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL); + + /* Read Local AMP Info */ + hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_INFO, 0, NULL); } static void hci_init_req(struct hci_dev *hdev, unsigned long opt) -- cgit v1.2.3 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 'net') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index f6f0500bf370..c70e2cf107ff 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 a57d96afa245..2eac6184a231 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 1d3e9c328a36..ae1d78ee0410 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 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 'net') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index c70e2cf107ff..a756c2406306 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 2eac6184a231..03746f565fc4 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 ae1d78ee0410..46126cbc9de4 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 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 'net') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index a756c2406306..e33165476e83 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 03746f565fc4..041ebed9e647 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 From b76bbd6657a2dd7545686ba9ad59625f44192146 Mon Sep 17 00:00:00 2001 From: Mat Martineau Date: Wed, 11 Apr 2012 10:48:43 -0700 Subject: Bluetooth: Functions for handling ERTM control fields These functions encode or decode ERTM control fields (extended or enhanced) to or from the new l2cap_ctrl structure. Signed-off-by: Mat Martineau Acked-by: Andrei Emeltchenko Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 113 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 041ebed9e647..913cec3e52d7 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -786,6 +786,117 @@ static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u32 control) l2cap_send_sframe(chan, control); } +static u16 __pack_enhanced_control(struct l2cap_ctrl *control) +{ + u16 packed; + + packed = control->reqseq << L2CAP_CTRL_REQSEQ_SHIFT; + packed |= control->final << L2CAP_CTRL_FINAL_SHIFT; + + if (control->sframe) { + packed |= control->poll << L2CAP_CTRL_POLL_SHIFT; + packed |= control->super << L2CAP_CTRL_SUPER_SHIFT; + packed |= L2CAP_CTRL_FRAME_TYPE; + } else { + packed |= control->sar << L2CAP_CTRL_SAR_SHIFT; + packed |= control->txseq << L2CAP_CTRL_TXSEQ_SHIFT; + } + + return packed; +} + +static void __unpack_enhanced_control(u16 enh, struct l2cap_ctrl *control) +{ + control->reqseq = (enh & L2CAP_CTRL_REQSEQ) >> L2CAP_CTRL_REQSEQ_SHIFT; + control->final = (enh & L2CAP_CTRL_FINAL) >> L2CAP_CTRL_FINAL_SHIFT; + + if (enh & L2CAP_CTRL_FRAME_TYPE) { + /* S-Frame */ + control->sframe = 1; + control->poll = (enh & L2CAP_CTRL_POLL) >> L2CAP_CTRL_POLL_SHIFT; + control->super = (enh & L2CAP_CTRL_SUPERVISE) >> L2CAP_CTRL_SUPER_SHIFT; + + control->sar = 0; + control->txseq = 0; + } else { + /* I-Frame */ + control->sframe = 0; + control->sar = (enh & L2CAP_CTRL_SAR) >> L2CAP_CTRL_SAR_SHIFT; + control->txseq = (enh & L2CAP_CTRL_TXSEQ) >> L2CAP_CTRL_TXSEQ_SHIFT; + + control->poll = 0; + control->super = 0; + } +} + +static u32 __pack_extended_control(struct l2cap_ctrl *control) +{ + u32 packed; + + packed = control->reqseq << L2CAP_EXT_CTRL_REQSEQ_SHIFT; + packed |= control->final << L2CAP_EXT_CTRL_FINAL_SHIFT; + + if (control->sframe) { + packed |= control->poll << L2CAP_EXT_CTRL_POLL_SHIFT; + packed |= control->super << L2CAP_EXT_CTRL_SUPER_SHIFT; + packed |= L2CAP_EXT_CTRL_FRAME_TYPE; + } else { + packed |= control->sar << L2CAP_EXT_CTRL_SAR_SHIFT; + packed |= control->txseq << L2CAP_EXT_CTRL_TXSEQ_SHIFT; + } + + return packed; +} + +static void __unpack_extended_control(u32 ext, struct l2cap_ctrl *control) +{ + control->reqseq = (ext & L2CAP_EXT_CTRL_REQSEQ) >> L2CAP_EXT_CTRL_REQSEQ_SHIFT; + control->final = (ext & L2CAP_EXT_CTRL_FINAL) >> L2CAP_EXT_CTRL_FINAL_SHIFT; + + if (ext & L2CAP_EXT_CTRL_FRAME_TYPE) { + /* S-Frame */ + control->sframe = 1; + control->poll = (ext & L2CAP_EXT_CTRL_POLL) >> L2CAP_EXT_CTRL_POLL_SHIFT; + control->super = (ext & L2CAP_EXT_CTRL_SUPERVISE) >> L2CAP_EXT_CTRL_SUPER_SHIFT; + + control->sar = 0; + control->txseq = 0; + } else { + /* I-Frame */ + control->sframe = 0; + control->sar = (ext & L2CAP_EXT_CTRL_SAR) >> L2CAP_EXT_CTRL_SAR_SHIFT; + control->txseq = (ext & L2CAP_EXT_CTRL_TXSEQ) >> L2CAP_EXT_CTRL_TXSEQ_SHIFT; + + control->poll = 0; + control->super = 0; + } +} + +static inline void __unpack_control(struct l2cap_chan *chan, + struct sk_buff *skb) +{ + if (test_bit(FLAG_EXT_CTRL, &chan->flags)) { + __unpack_extended_control(get_unaligned_le32(skb->data), + &bt_cb(skb)->control); + } else { + __unpack_enhanced_control(get_unaligned_le16(skb->data), + &bt_cb(skb)->control); + } +} + +static inline void __pack_control(struct l2cap_chan *chan, + struct l2cap_ctrl *control, + struct sk_buff *skb) +{ + if (test_bit(FLAG_EXT_CTRL, &chan->flags)) { + put_unaligned_le32(__pack_extended_control(control), + skb->data + L2CAP_HDR_SIZE); + } else { + put_unaligned_le16(__pack_enhanced_control(control), + skb->data + L2CAP_HDR_SIZE); + } +} + static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan) { return !test_bit(CONF_CONNECT_PEND, &chan->conf_state); @@ -4359,6 +4470,8 @@ static int l2cap_ertm_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) u16 req_seq; int len, next_tx_seq_offset, req_seq_offset; + __unpack_control(chan, skb); + control = __get_control(chan, skb->data); skb_pull(skb, __ctrl_size(chan)); len = skb->len; -- cgit v1.2.3 From abc5de8f4e68ea785e32b91e456f467d2a2fb7db Mon Sep 17 00:00:00 2001 From: Mikel Astiz Date: Wed, 11 Apr 2012 08:48:47 +0200 Subject: Bluetooth: Use unsigned int instead of signed int The involved values are all unsigned and thus unsigned int should be used instead of signed int. Assigning ~0 to a signed int results in -1, which is confusing and error-prone, while the code is trying to set the maximum value possible. The code still works because the C standard defines that unsigned comparison will be performed in these cases, when comparing an unsigned int and a signed int. Signed-off-by: Mikel Astiz Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- net/bluetooth/hci_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 3b3d9a882dbd..f7911e9224c5 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2334,7 +2334,7 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int { struct hci_conn_hash *h = &hdev->conn_hash; struct hci_conn *conn = NULL, *c; - int num = 0, min = ~0; + unsigned int num = 0, min = ~0; /* We don't have to lock device here. Connections are always * added and removed with TX task disabled. */ @@ -2415,7 +2415,7 @@ static inline struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type, { struct hci_conn_hash *h = &hdev->conn_hash; struct hci_chan *chan = NULL; - int num = 0, min = ~0, cur_prio = 0; + unsigned int num = 0, min = ~0, cur_prio = 0; struct hci_conn *conn; int cnt, q, conn_num = 0; -- cgit v1.2.3 From 088ce088ec115ee4bc89549b07b182e65dce9235 Mon Sep 17 00:00:00 2001 From: Mikel Astiz Date: Wed, 11 Apr 2012 08:48:48 +0200 Subject: Bluetooth: Remove unnecessary check The function already fails if the given size is greater than the MTU, so there is no need to consider that case afterwards. Signed-off-by: Mikel Astiz Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- net/bluetooth/sco.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index f6ab12907963..728dedb1b01e 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -233,7 +233,7 @@ static inline int sco_send_frame(struct sock *sk, struct msghdr *msg, int len) { struct sco_conn *conn = sco_pi(sk)->conn; struct sk_buff *skb; - int err, count; + int err; /* Check outgoing MTU */ if (len > conn->mtu) @@ -241,20 +241,18 @@ static inline int sco_send_frame(struct sock *sk, struct msghdr *msg, int len) BT_DBG("sk %p len %d", sk, len); - count = min_t(unsigned int, conn->mtu, len); - skb = bt_skb_send_alloc(sk, count, - msg->msg_flags & MSG_DONTWAIT, &err); + skb = bt_skb_send_alloc(sk, len, msg->msg_flags & MSG_DONTWAIT, &err); if (!skb) return err; - if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) { + if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) { kfree_skb(skb); return -EFAULT; } hci_send_sco(conn->hcon, skb); - return count; + return len; } static inline void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb) -- cgit v1.2.3 From 5c94f379c11a7ecfdb7c0cadbb3bb5f749e20732 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Fri, 13 Apr 2012 19:52:27 -0300 Subject: Bluetooth: remove unneeded declaration of sco_conn_del() By some reason this is not needed anymore. Signed-off-by: Gustavo Padovan --- net/bluetooth/sco.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'net') diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 728dedb1b01e..7bd0947af2fa 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -61,8 +61,6 @@ static struct bt_sock_list sco_sk_list = { static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent); static void sco_chan_del(struct sock *sk, int err); -static int sco_conn_del(struct hci_conn *conn, int err); - static void sco_sock_close(struct sock *sk); static void sco_sock_kill(struct sock *sk); -- cgit v1.2.3 From 0c01bc486a6f5f397732f808ecbcd63665c605d8 Mon Sep 17 00:00:00 2001 From: Syam Sidhardhan Date: Thu, 12 Apr 2012 20:33:21 +0530 Subject: Bluetooth: mgmt: Remove unwanted goto statements Remove goto statements that do nothing else than jump to the next line of code. Signed-off-by: Syam Sidhardhan Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 5e80c6db6ae7..b50e2ee2595c 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1247,10 +1247,8 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp), &hci_cp); - if (err < 0) { + if (err < 0) mgmt_pending_remove(cmd); - goto unlock; - } unlock: hci_dev_unlock(hdev); @@ -1300,10 +1298,8 @@ static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) } cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len); - if (!cmd) { + if (!cmd) err = -ENOMEM; - goto failed; - } failed: hci_dev_unlock(hdev); @@ -1388,10 +1384,8 @@ update_class: } cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len); - if (!cmd) { + if (!cmd) err = -ENOMEM; - goto unlock; - } unlock: hci_dev_unlock(hdev); @@ -1442,10 +1436,8 @@ static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data, } cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len); - if (!cmd) { + if (!cmd) err = -ENOMEM; - goto unlock; - } unlock: hci_dev_unlock(hdev); -- cgit v1.2.3 From 4596fde5401679f062336c6dbad8d9e4043858c2 Mon Sep 17 00:00:00 2001 From: Hemant Gupta Date: Mon, 16 Apr 2012 14:57:40 +0530 Subject: Bluetooth: mgmt: Fix address type while loading Long Term Key This patch fixes the address type while loading long term keys when BT is switched on. Without this fix pairing is reinitated even though LTK exists for remote device because of mismatch of address type. Signed-off-by: Hemant Gupta Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index b50e2ee2595c..7d37c88e4bf5 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1644,6 +1644,18 @@ static u8 link_to_mgmt(u8 link_type, u8 addr_type) } } +static u8 mgmt_to_le(u8 mgmt_type) +{ + switch (mgmt_type) { + case MGMT_ADDR_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) { @@ -2652,7 +2664,8 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, else type = HCI_SMP_LTK_SLAVE; - hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type, + hci_add_ltk(hdev, &key->addr.bdaddr, + mgmt_to_le(key->addr.type), type, 0, key->authenticated, key->val, key->enc_size, key->ediv, key->rand); } -- cgit v1.2.3 From 2d8b3a11623cf5203bc063927b6fc742625f1ebf Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Mon, 16 Apr 2012 16:32:04 +0300 Subject: Bluetooth: Fix debug printing unallocated name It does make sense to print hdev name after allocation. Signed-off-by: Andrei Emeltchenko Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index f7911e9224c5..544c7e3a40d2 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1741,8 +1741,6 @@ int hci_register_dev(struct hci_dev *hdev) struct list_head *head = &hci_dev_list, *p; int i, id, error; - BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus); - if (!hdev->open || !hdev->close) return -EINVAL; @@ -1762,6 +1760,9 @@ int hci_register_dev(struct hci_dev *hdev) sprintf(hdev->name, "hci%d", id); hdev->id = id; + + BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus); + list_add_tail(&hdev->list, head); mutex_init(&hdev->lock); -- cgit v1.2.3 From 35d4adcca1707c551f4598f68fe83118dd82cd60 Mon Sep 17 00:00:00 2001 From: Hemant Gupta Date: Wed, 18 Apr 2012 14:46:26 +0530 Subject: Bluetooth: Don't distribute keys in case of Encryption Failure SMP Keys should only be distributeed when encryption is successful. Signed-off-by: Hemant Gupta Signed-off-by: Gustavo Padovan --- net/bluetooth/l2cap_core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 913cec3e52d7..ce93dcf0c2db 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -4813,7 +4813,8 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) BT_DBG("conn %p", conn); if (hcon->type == LE_LINK) { - smp_distribute_keys(conn, 0); + if (!status && encrypt) + smp_distribute_keys(conn, 0); cancel_delayed_work(&conn->security_timer); } -- cgit v1.2.3 From 6b3af7334bd3c403647606adfb04f6e6bcf1597e Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 19 Apr 2012 13:43:51 +0200 Subject: Bluetooth: Split error handling for L2CAP listen sockets Split the checks for sk->sk_state and sk->sk_type for L2CAP listen sockets. This makes the code more readable. Signed-off-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- net/bluetooth/l2cap_sock.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 46126cbc9de4..8d8b50a29906 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -148,12 +148,16 @@ static int l2cap_sock_listen(struct socket *sock, int backlog) lock_sock(sk); - if ((sock->type != SOCK_SEQPACKET && sock->type != SOCK_STREAM) - || sk->sk_state != BT_BOUND) { + if (sk->sk_state != BT_BOUND) { err = -EBADFD; goto done; } + if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM) { + err = -EINVAL; + goto done; + } + switch (chan->mode) { case L2CAP_MODE_BASIC: break; -- cgit v1.2.3 From 7d5d775a55554183448b591a86b1d172ae993b94 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 19 Apr 2012 13:43:52 +0200 Subject: Bluetooth: Split error handling for SCO listen sockets Split the checks for sk->sk_state and sk->sk_type for SCO listen sockets. This makes the code more readable. Signed-off-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- net/bluetooth/sco.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 7bd0947af2fa..a69aa345597e 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -539,11 +539,16 @@ static int sco_sock_listen(struct socket *sock, int backlog) lock_sock(sk); - if (sk->sk_state != BT_BOUND || sock->type != SOCK_SEQPACKET) { + if (sk->sk_state != BT_BOUND) { err = -EBADFD; goto done; } + if (sk->sk_type != SOCK_SEQPACKET) { + err = -EINVAL; + goto done; + } + sk->sk_max_ack_backlog = backlog; sk->sk_ack_backlog = 0; sk->sk_state = BT_LISTEN; -- cgit v1.2.3 From 519e42b38ee47005aaa2243789cda54161e62dc8 Mon Sep 17 00:00:00 2001 From: Lukasz Rymanowski Date: Thu, 19 Apr 2012 16:12:28 +0200 Subject: Bluetooth: Remove not needed status parameter Sco_conn_add is called from two places and always with status = 0. Signed-off-by: Lukasz Rymanowski Signed-off-by: Gustavo Padovan --- net/bluetooth/sco.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index a69aa345597e..84d7a8023f80 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -93,12 +93,12 @@ static void sco_sock_clear_timer(struct sock *sk) } /* ---- SCO connections ---- */ -static struct sco_conn *sco_conn_add(struct hci_conn *hcon, __u8 status) +static struct sco_conn *sco_conn_add(struct hci_conn *hcon) { struct hci_dev *hdev = hcon->hdev; struct sco_conn *conn = hcon->sco_data; - if (conn || status) + if (conn) return conn; conn = kzalloc(sizeof(struct sco_conn), GFP_ATOMIC); @@ -199,7 +199,7 @@ static int sco_connect(struct sock *sk) goto done; } - conn = sco_conn_add(hcon, 0); + conn = sco_conn_add(hcon); if (!conn) { hci_conn_put(hcon); err = -ENOMEM; @@ -924,7 +924,7 @@ int sco_connect_cfm(struct hci_conn *hcon, __u8 status) if (!status) { struct sco_conn *conn; - conn = sco_conn_add(hcon, status); + conn = sco_conn_add(hcon); if (conn) sco_conn_ready(conn); } else -- cgit v1.2.3 From fc50744c1e518adfb4ff2eda156f941e20aea36d Mon Sep 17 00:00:00 2001 From: Ulisses Furquim Date: Wed, 18 Apr 2012 12:13:04 -0300 Subject: Bluetooth: Fix registering hci with duplicate name When adding HCI devices hci_register_dev assigns the same name hci1 for subsequently added AMP devices. ... [ 6958.381886] sysfs: cannot create duplicate filename '/devices/virtual/bluetooth/hci1 ... We assume id starts with the number we'll try to add the new device and keep iterating until we find the proper place. The only difference is we start with 0 for BR/EDR device and 1 for AMP devices (thus AMP devices will never receive register as index 0). Then every hdev->id in the _ordered_ list <= to the id we want we increment id and move the variable head. In the end we'll have id as the first available one and head is where you need to add hdev after to keep the list ordered. Reported-by: Andrei Emeltchenko Signed-off-by: Ulisses Furquim Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 544c7e3a40d2..22581823e610 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1738,24 +1738,28 @@ int hci_le_scan(struct hci_dev *hdev, u8 type, u16 interval, u16 window, /* Register HCI device */ int hci_register_dev(struct hci_dev *hdev) { - struct list_head *head = &hci_dev_list, *p; + struct list_head *head, *p; int i, id, error; if (!hdev->open || !hdev->close) return -EINVAL; + write_lock(&hci_dev_list_lock); + /* Do not allow HCI_AMP devices to register at index 0, * so the index can be used as the AMP controller ID. */ id = (hdev->dev_type == HCI_BREDR) ? 0 : 1; - - write_lock(&hci_dev_list_lock); + head = &hci_dev_list; /* Find first available device id */ list_for_each(p, &hci_dev_list) { - if (list_entry(p, struct hci_dev, list)->id != id) + int nid = list_entry(p, struct hci_dev, list)->id; + if (nid > id) break; - head = p; id++; + if (nid == id) + id++; + head = p; } sprintf(hdev->name, "hci%d", id); @@ -1763,7 +1767,7 @@ int hci_register_dev(struct hci_dev *hdev) BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus); - list_add_tail(&hdev->list, head); + list_add(&hdev->list, head); mutex_init(&hdev->lock); -- cgit v1.2.3 From 8ed21f7eece54bb80eea5e31c3d9c6c7b6517e49 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 19 Apr 2012 13:43:53 +0200 Subject: Bluetooth: Don't check source address in SCO bind function Checking the source address in SCO bind function will prevent from having an incoming and outgoing SCO socket. However that might be needed in case of multiple SCO connections on a single device. Signed-off-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- net/bluetooth/sco.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'net') diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 84d7a8023f80..c75cd7b07d18 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -462,7 +462,6 @@ static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le { struct sockaddr_sco *sa = (struct sockaddr_sco *) addr; struct sock *sk = sock->sk; - bdaddr_t *src = &sa->sco_bdaddr; int err = 0; BT_DBG("sk %p %s", sk, batostr(&sa->sco_bdaddr)); @@ -477,17 +476,14 @@ static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le goto done; } - write_lock(&sco_sk_list.lock); - - if (bacmp(src, BDADDR_ANY) && __sco_get_sock_by_addr(src)) { - err = -EADDRINUSE; - } else { - /* Save source address */ - bacpy(&bt_sk(sk)->src, &sa->sco_bdaddr); - sk->sk_state = BT_BOUND; + if (sk->sk_type != SOCK_SEQPACKET) { + err = -EINVAL; + goto done; } - write_unlock(&sco_sk_list.lock); + bacpy(&bt_sk(sk)->src, &sa->sco_bdaddr); + + sk->sk_state = BT_BOUND; done: release_sock(sk); -- cgit v1.2.3 From fb3340594bd6630c27e31ddeff25b7002fb4558e Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 19 Apr 2012 14:37:58 +0200 Subject: Bluetooth: Restrict to one SCO listening socket The SCO sockets are only identified by its address. So only allow one SCO socket in listening state per address or BDADDR_ANY. Signed-off-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- net/bluetooth/sco.c | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) (limited to 'net') diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index c75cd7b07d18..bf1af0b1497e 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -273,17 +273,20 @@ drop: } /* -------- Socket interface ---------- */ -static struct sock *__sco_get_sock_by_addr(bdaddr_t *ba) +static struct sock *__sco_get_sock_listen_by_addr(bdaddr_t *ba) { - struct sock *sk; struct hlist_node *node; + struct sock *sk; + + sk_for_each(sk, node, &sco_sk_list.head) { + if (sk->sk_state != BT_LISTEN) + continue; - sk_for_each(sk, node, &sco_sk_list.head) if (!bacmp(&bt_sk(sk)->src, ba)) - goto found; - sk = NULL; -found: - return sk; + return sk; + } + + return NULL; } /* Find socket listening on source bdaddr. @@ -529,6 +532,7 @@ done: static int sco_sock_listen(struct socket *sock, int backlog) { struct sock *sk = sock->sk; + bdaddr_t *src = &bt_sk(sk)->src; int err = 0; BT_DBG("sk %p backlog %d", sk, backlog); @@ -545,10 +549,21 @@ static int sco_sock_listen(struct socket *sock, int backlog) goto done; } + write_lock(&sco_sk_list.lock); + + if (__sco_get_sock_listen_by_addr(src)) { + err = -EADDRINUSE; + goto unlock; + } + sk->sk_max_ack_backlog = backlog; sk->sk_ack_backlog = 0; + sk->sk_state = BT_LISTEN; +unlock: + write_unlock(&sco_sk_list.lock); + done: release_sock(sk); return err; -- cgit v1.2.3 From 9be0dab793f52615274c357fce542b3cbf78f6d7 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Sun, 22 Apr 2012 14:39:57 +0200 Subject: Bluetooth: Move hci_alloc/free_dev close to hci_register/unregister_dev alloc() and register() (and free() and unregister()) are closely related so move them more closely together. This will also allow to move functionality from register() to alloc() without needing forward-declarations. Signed-off-by: David Herrmann Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 52 ++++++++++++++++++++++++------------------------ 1 file changed, 26 insertions(+), 26 deletions(-) (limited to 'net') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 22581823e610..d3fb986d6b27 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1092,32 +1092,6 @@ static const struct rfkill_ops hci_rfkill_ops = { .set_block = hci_rfkill_set_block, }; -/* Alloc HCI device */ -struct hci_dev *hci_alloc_dev(void) -{ - struct hci_dev *hdev; - - hdev = kzalloc(sizeof(struct hci_dev), GFP_KERNEL); - if (!hdev) - return NULL; - - hci_init_sysfs(hdev); - skb_queue_head_init(&hdev->driver_init); - - return hdev; -} -EXPORT_SYMBOL(hci_alloc_dev); - -/* Free HCI device */ -void hci_free_dev(struct hci_dev *hdev) -{ - skb_queue_purge(&hdev->driver_init); - - /* will free via device release */ - put_device(&hdev->dev); -} -EXPORT_SYMBOL(hci_free_dev); - static void hci_power_on(struct work_struct *work) { struct hci_dev *hdev = container_of(work, struct hci_dev, power_on); @@ -1735,6 +1709,32 @@ int hci_le_scan(struct hci_dev *hdev, u8 type, u16 interval, u16 window, return 0; } +/* Alloc HCI device */ +struct hci_dev *hci_alloc_dev(void) +{ + struct hci_dev *hdev; + + hdev = kzalloc(sizeof(struct hci_dev), GFP_KERNEL); + if (!hdev) + return NULL; + + hci_init_sysfs(hdev); + skb_queue_head_init(&hdev->driver_init); + + return hdev; +} +EXPORT_SYMBOL(hci_alloc_dev); + +/* Free HCI device */ +void hci_free_dev(struct hci_dev *hdev) +{ + skb_queue_purge(&hdev->driver_init); + + /* will free via device release */ + put_device(&hdev->dev); +} +EXPORT_SYMBOL(hci_free_dev); + /* Register HCI device */ int hci_register_dev(struct hci_dev *hdev) { -- cgit v1.2.3 From b1b813d4777f4843af2acce9a1b62d486e1d3ffc Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Sun, 22 Apr 2012 14:39:58 +0200 Subject: Bluetooth: Move device initialization to hci_alloc_dev() We currently initialize locks, lists, works, etc. in hci_register_dev() (hci_alloc_dev() was added later) which is bogus because an hdev is in an invalid state if it is not registered. This patch moves all memory initialization to hci_alloc_dev(). Device registering and registration of sub-modules is still left in hci_register_dev() as it belongs there. The benefit is (despite cleaning up the code-base) we can now always be sure that an hdev is a valid object and can be locked and worked on even though it may not be registered. This patch also reorders the initialization to be easier to understand. First the memory is initialized, then all generic structures and as last step the sub-init functions are called. This guarantees that all dependencies are initialized in the right order and makes it also easier to find a specific line. We previously initialized it in the same order as the "struct hci_dev" is declared which seems pretty random. Signed-off-by: David Herrmann Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 115 +++++++++++++++++++++-------------------------- 1 file changed, 52 insertions(+), 63 deletions(-) (limited to 'net') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index d3fb986d6b27..a362f01bf081 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1713,13 +1713,63 @@ int hci_le_scan(struct hci_dev *hdev, u8 type, u16 interval, u16 window, struct hci_dev *hci_alloc_dev(void) { struct hci_dev *hdev; + int i; hdev = kzalloc(sizeof(struct hci_dev), GFP_KERNEL); if (!hdev) return NULL; - hci_init_sysfs(hdev); + hdev->flags = 0; + hdev->dev_flags = 0; + hdev->pkt_type = (HCI_DM1 | HCI_DH1 | HCI_HV1); + hdev->esco_type = (ESCO_HV1); + hdev->link_mode = (HCI_LM_ACCEPT); + hdev->io_capability = 0x03; /* No Input No Output */ + + hdev->idle_timeout = 0; + hdev->sniff_max_interval = 800; + hdev->sniff_min_interval = 80; + + mutex_init(&hdev->lock); + mutex_init(&hdev->req_lock); + + INIT_LIST_HEAD(&hdev->mgmt_pending); + INIT_LIST_HEAD(&hdev->blacklist); + INIT_LIST_HEAD(&hdev->uuids); + 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); + INIT_WORK(&hdev->tx_work, hci_tx_work); + 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); + skb_queue_head_init(&hdev->driver_init); + skb_queue_head_init(&hdev->rx_q); + skb_queue_head_init(&hdev->cmd_q); + skb_queue_head_init(&hdev->raw_q); + + init_waitqueue_head(&hdev->req_wait_q); + + setup_timer(&hdev->cmd_timer, hci_cmd_timer, (unsigned long) hdev); + + memset(&hdev->stat, 0, sizeof(struct hci_dev_stats)); + atomic_set(&hdev->promisc, 0); + + for (i = 0; i < NUM_REASSEMBLY; i++) + hdev->reassembly[i] = NULL; + + hci_init_sysfs(hdev); + discovery_init(hdev); + hci_conn_hash_init(hdev); return hdev; } @@ -1739,7 +1789,7 @@ EXPORT_SYMBOL(hci_free_dev); int hci_register_dev(struct hci_dev *hdev) { struct list_head *head, *p; - int i, id, error; + int id, error; if (!hdev->open || !hdev->close) return -EINVAL; @@ -1769,67 +1819,6 @@ int hci_register_dev(struct hci_dev *hdev) list_add(&hdev->list, head); - mutex_init(&hdev->lock); - - hdev->flags = 0; - hdev->dev_flags = 0; - hdev->pkt_type = (HCI_DM1 | HCI_DH1 | HCI_HV1); - hdev->esco_type = (ESCO_HV1); - hdev->link_mode = (HCI_LM_ACCEPT); - hdev->io_capability = 0x03; /* No Input No Output */ - - hdev->idle_timeout = 0; - hdev->sniff_max_interval = 800; - hdev->sniff_min_interval = 80; - - INIT_WORK(&hdev->rx_work, hci_rx_work); - INIT_WORK(&hdev->cmd_work, hci_cmd_work); - INIT_WORK(&hdev->tx_work, hci_tx_work); - - - skb_queue_head_init(&hdev->rx_q); - skb_queue_head_init(&hdev->cmd_q); - skb_queue_head_init(&hdev->raw_q); - - setup_timer(&hdev->cmd_timer, hci_cmd_timer, (unsigned long) hdev); - - for (i = 0; i < NUM_REASSEMBLY; i++) - hdev->reassembly[i] = NULL; - - init_waitqueue_head(&hdev->req_wait_q); - mutex_init(&hdev->req_lock); - - discovery_init(hdev); - - hci_conn_hash_init(hdev); - - INIT_LIST_HEAD(&hdev->mgmt_pending); - - INIT_LIST_HEAD(&hdev->blacklist); - - INIT_LIST_HEAD(&hdev->uuids); - - 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_DELAYED_WORK(&hdev->adv_work, hci_clear_adv_cache); - INIT_WORK(&hdev->power_on, hci_power_on); - INIT_DELAYED_WORK(&hdev->power_off, hci_power_off); - - INIT_DELAYED_WORK(&hdev->discov_off, hci_discov_off); - - memset(&hdev->stat, 0, sizeof(struct hci_dev_stats)); - - atomic_set(&hdev->promisc, 0); - - INIT_WORK(&hdev->le_scan, le_scan_work); - - INIT_DELAYED_WORK(&hdev->le_scan_disable, le_scan_disable_work); - write_unlock(&hci_dev_list_lock); hdev->workqueue = alloc_workqueue(hdev->name, WQ_HIGHPRI | WQ_UNBOUND | -- cgit v1.2.3 From d8ce9395252fa9a264c04e7ab9949f4f7ec96f5b Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Sun, 22 Apr 2012 14:39:59 +0200 Subject: Bluetooth: Remove unneeded initialization in hci_alloc_dev() We allocate memory with kzalloc() so there is no need to call memset(..., 0, ...) or similar. Signed-off-by: David Herrmann Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'net') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index a362f01bf081..aa45ea496f87 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1713,20 +1713,16 @@ int hci_le_scan(struct hci_dev *hdev, u8 type, u16 interval, u16 window, struct hci_dev *hci_alloc_dev(void) { struct hci_dev *hdev; - int i; hdev = kzalloc(sizeof(struct hci_dev), GFP_KERNEL); if (!hdev) return NULL; - hdev->flags = 0; - hdev->dev_flags = 0; hdev->pkt_type = (HCI_DM1 | HCI_DH1 | HCI_HV1); hdev->esco_type = (ESCO_HV1); hdev->link_mode = (HCI_LM_ACCEPT); hdev->io_capability = 0x03; /* No Input No Output */ - hdev->idle_timeout = 0; hdev->sniff_max_interval = 800; hdev->sniff_min_interval = 80; @@ -1761,12 +1757,6 @@ struct hci_dev *hci_alloc_dev(void) setup_timer(&hdev->cmd_timer, hci_cmd_timer, (unsigned long) hdev); - memset(&hdev->stat, 0, sizeof(struct hci_dev_stats)); - atomic_set(&hdev->promisc, 0); - - for (i = 0; i < NUM_REASSEMBLY; i++) - hdev->reassembly[i] = NULL; - hci_init_sysfs(hdev); discovery_init(hdev); hci_conn_hash_init(hdev); -- cgit v1.2.3 From c22876814ee9cc72f84996b78203b5530c61bee8 Mon Sep 17 00:00:00 2001 From: Ido Yariv Date: Fri, 20 Apr 2012 15:46:07 -0300 Subject: Bluetooth: Search global l2cap channels by src/dst addresses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The cid or psm and the source address might not be enough to uniquely identify a global channel, especially when the source address is our own. For instance, when trying to communicate with two LE devices in master mode, data received from the both devices is sent to the same socket. Fix this by taking the destination address into account when choosing the socket. Signed-off-by: Ido Yariv Signed-off-by: Arik Nemtsov Tested-by: João Paulo Rechi Vita Signed-off-by: Gustavo Padovan --- net/bluetooth/l2cap_core.c | 43 +++++++++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 12 deletions(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index ce93dcf0c2db..cc96e0db284d 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1066,11 +1066,12 @@ static void l2cap_conn_start(struct l2cap_conn *conn) mutex_unlock(&conn->chan_lock); } -/* Find socket with cid and source bdaddr. +/* Find socket with cid and source/destination bdaddr. * Returns closest match, locked. */ static struct l2cap_chan *l2cap_global_chan_by_scid(int state, u16 cid, - bdaddr_t *src) + bdaddr_t *src, + bdaddr_t *dst) { struct l2cap_chan *c, *c1 = NULL; @@ -1083,14 +1084,22 @@ static struct l2cap_chan *l2cap_global_chan_by_scid(int state, u16 cid, continue; if (c->scid == cid) { + int src_match, dst_match; + int src_any, dst_any; + /* Exact match. */ - if (!bacmp(&bt_sk(sk)->src, src)) { + src_match = !bacmp(&bt_sk(sk)->src, src); + dst_match = !bacmp(&bt_sk(sk)->dst, dst); + if (src_match && dst_match) { read_unlock(&chan_list_lock); return c; } /* Closest match */ - if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) + src_any = !bacmp(&bt_sk(sk)->src, BDADDR_ANY); + dst_any = !bacmp(&bt_sk(sk)->dst, BDADDR_ANY); + if ((src_match && dst_any) || (src_any && dst_match) || + (src_any && dst_any)) c1 = c; } } @@ -1109,7 +1118,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) /* Check if we have socket listening on cid */ pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_LE_DATA, - conn->src); + conn->src, conn->dst); if (!pchan) return; @@ -1337,10 +1346,12 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status) /* ---- Socket interface ---- */ -/* Find socket with psm and source bdaddr. +/* Find socket with psm and source / destination bdaddr. * Returns closest match. */ -static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr_t *src) +static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, + bdaddr_t *src, + bdaddr_t *dst) { struct l2cap_chan *c, *c1 = NULL; @@ -1353,14 +1364,22 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr continue; if (c->psm == psm) { + int src_match, dst_match; + int src_any, dst_any; + /* Exact match. */ - if (!bacmp(&bt_sk(sk)->src, src)) { + src_match = !bacmp(&bt_sk(sk)->src, src); + dst_match = !bacmp(&bt_sk(sk)->dst, dst); + if (src_match && dst_match) { read_unlock(&chan_list_lock); return c; } /* Closest match */ - if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) + src_any = !bacmp(&bt_sk(sk)->src, BDADDR_ANY); + dst_any = !bacmp(&bt_sk(sk)->dst, BDADDR_ANY); + if ((src_match && dst_any) || (src_any && dst_match) || + (src_any && dst_any)) c1 = c; } } @@ -2887,7 +2906,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd BT_DBG("psm 0x%2.2x scid 0x%4.4x", __le16_to_cpu(psm), scid); /* Check if we have socket listening on psm */ - pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, conn->src); + pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, conn->src, conn->dst); if (!pchan) { result = L2CAP_CR_BAD_PSM; goto sendresp; @@ -4627,7 +4646,7 @@ static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, str { struct l2cap_chan *chan; - chan = l2cap_global_chan_by_psm(0, psm, conn->src); + chan = l2cap_global_chan_by_psm(0, psm, conn->src, conn->dst); if (!chan) goto drop; @@ -4653,7 +4672,7 @@ static inline int l2cap_att_channel(struct l2cap_conn *conn, u16 cid, { struct l2cap_chan *chan; - chan = l2cap_global_chan_by_scid(0, cid, conn->src); + chan = l2cap_global_chan_by_scid(0, cid, conn->src, conn->dst); if (!chan) goto drop; -- cgit v1.2.3 From 9f0caeb1deafa9a894ee03134f6642c3a245b1af Mon Sep 17 00:00:00 2001 From: Vinicius Costa Gomes Date: Fri, 20 Apr 2012 15:46:08 -0300 Subject: Bluetooth: Add support for reusing the same hci_conn for LE links MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As most LE devices leave advertising mode when they enter the connected state, we may want to "pass" that connection to other users. The first user will be the pairing procedure, the connection is established without an associated socket, after the pairing is complete, userspace may want to discover via GATT what services the newly bonded device has. If userspace establishes the connection while the timeout still hasn't expired, the connection will be re-used. Signed-off-by: Vinicius Costa Gomes Tested-by: João Paulo Rechi Vita Signed-off-by: Gustavo Padovan --- net/bluetooth/hci_conn.c | 32 ++++++++++++----------- net/bluetooth/l2cap_core.c | 63 +++++++++++++++++++++++++++++----------------- 2 files changed, 58 insertions(+), 37 deletions(-) (limited to 'net') diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 5238b6b3ea6a..7db3edc28f77 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -522,23 +522,27 @@ 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; + struct adv_entry *entry = NULL; le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst); - if (le) - return ERR_PTR(-EBUSY); - - 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; + 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->pending_sec_level = sec_level; + le->sec_level = BT_SECURITY_LOW; + le->auth_type = auth_type; + hci_le_connect(le); + } - hci_le_connect(le); + le->pending_sec_level = sec_level; + le->auth_type = auth_type; hci_conn_hold(le); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index cc96e0db284d..97af2b4f6238 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -917,10 +917,38 @@ static void l2cap_send_conn_req(struct l2cap_chan *chan) l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ, sizeof(req), &req); } +static void l2cap_chan_ready(struct l2cap_chan *chan) +{ + struct sock *sk = chan->sk; + struct sock *parent; + + lock_sock(sk); + + parent = bt_sk(sk)->parent; + + BT_DBG("sk %p, parent %p", sk, parent); + + chan->conf_state = 0; + __clear_chan_timer(chan); + + __l2cap_state_change(chan, BT_CONNECTED); + sk->sk_state_change(sk); + + if (parent) + parent->sk_data_ready(parent, 0); + + release_sock(sk); +} + static void l2cap_do_start(struct l2cap_chan *chan) { struct l2cap_conn *conn = chan->conn; + if (conn->hcon->type == LE_LINK) { + l2cap_chan_ready(chan); + return; + } + if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) { if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)) return; @@ -1156,29 +1184,6 @@ clean: release_sock(parent); } -static void l2cap_chan_ready(struct l2cap_chan *chan) -{ - struct sock *sk = chan->sk; - struct sock *parent; - - lock_sock(sk); - - parent = bt_sk(sk)->parent; - - BT_DBG("sk %p, parent %p", sk, parent); - - chan->conf_state = 0; - __clear_chan_timer(chan); - - __l2cap_state_change(chan, BT_CONNECTED); - sk->sk_state_change(sk); - - if (parent) - parent->sk_data_ready(parent, 0); - - release_sock(sk); -} - static void l2cap_conn_ready(struct l2cap_conn *conn) { struct l2cap_chan *chan; @@ -1492,6 +1497,18 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *d goto done; } + if (hcon->type == LE_LINK) { + err = 0; + + if (!list_empty(&conn->chan_l)) { + err = -EBUSY; + hci_conn_put(hcon); + } + + if (err) + goto done; + } + /* Update source addr of the socket */ bacpy(src, conn->src); -- cgit v1.2.3 From b29050448a7efcedf5e8bec71c371169389a7a26 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Tue, 24 Apr 2012 16:11:11 -0300 Subject: Bluetooth: Remove useless code in hci_connect This patch removes unneeded variable assignments in hci_connect. 'sec_level' is already assigned to BT_SECURITY_LOW in hci_le_connect and 'pending_sec_level' and 'auth_type' are assigned right after if statement. Signed-off-by: Andre Guedes Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_conn.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'net') diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 7db3edc28f77..8f352cd1745a 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -535,9 +535,6 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 return ERR_PTR(-ENOMEM); le->dst_type = entry->bdaddr_type; - le->pending_sec_level = sec_level; - le->sec_level = BT_SECURITY_LOW; - le->auth_type = auth_type; hci_le_connect(le); } -- cgit v1.2.3 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 'net') diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index d0e44a4151e6..27a6a936487d 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 ef6e6541aa2a..6777432ca61e 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 7d37c88e4bf5..d064ca9fa006 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 From 57c1477c2c6b6c73ca40e4b23a80e3ecdfd9b684 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Tue, 24 Apr 2012 21:02:50 -0300 Subject: Bluetooth: Rename link_to_mgmt to link_to_bdaddr Since address type macros are not only related to Management Interface anymore, it makes sense to rename the helper function link_to_mgmt to link_to_bdaddr. Signed-off-by: Andre Guedes Acked-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index d064ca9fa006..632d43d0980b 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1625,7 +1625,7 @@ failed: return err; } -static u8 link_to_mgmt(u8 link_type, u8 addr_type) +static u8 link_to_bdaddr(u8 link_type, u8 addr_type) { switch (link_type) { case LE_LINK: @@ -1693,7 +1693,7 @@ static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data, if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags)) continue; bacpy(&rp->addr[i].bdaddr, &c->dst); - rp->addr[i].type = link_to_mgmt(c->type, c->dst_type); + rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type); if (c->type == SCO_LINK || c->type == ESCO_LINK) continue; i++; @@ -1860,7 +1860,7 @@ static void pairing_complete(struct pending_cmd *cmd, u8 status) struct hci_conn *conn = cmd->user_data; bacpy(&rp.addr.bdaddr, &conn->dst); - rp.addr.type = link_to_mgmt(conn->type, conn->dst_type); + rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type); cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status, &rp, sizeof(rp)); @@ -2983,7 +2983,7 @@ int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent) ev.store_hint = persistent; bacpy(&ev.key.addr.bdaddr, &key->bdaddr); - ev.key.addr.type = link_to_mgmt(LE_LINK, key->bdaddr_type); + ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type); ev.key.authenticated = key->authenticated; ev.key.enc_size = key->enc_size; ev.key.ediv = key->ediv; @@ -3007,7 +3007,7 @@ int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u16 eir_len = 0; bacpy(&ev->addr.bdaddr, bdaddr); - ev->addr.type = link_to_mgmt(link_type, addr_type); + ev->addr.type = link_to_bdaddr(link_type, addr_type); ev->flags = __cpu_to_le32(flags); @@ -3070,7 +3070,7 @@ int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk); bacpy(&ev.bdaddr, bdaddr); - ev.type = link_to_mgmt(link_type, addr_type); + ev.type = link_to_bdaddr(link_type, addr_type); err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk); @@ -3096,7 +3096,7 @@ int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, return -ENOENT; bacpy(&rp.addr.bdaddr, bdaddr); - rp.addr.type = link_to_mgmt(link_type, addr_type); + rp.addr.type = link_to_bdaddr(link_type, addr_type); err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, mgmt_status(status), &rp, sizeof(rp)); @@ -3114,7 +3114,7 @@ int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, struct mgmt_ev_connect_failed ev; bacpy(&ev.addr.bdaddr, bdaddr); - ev.addr.type = link_to_mgmt(link_type, addr_type); + ev.addr.type = link_to_bdaddr(link_type, addr_type); ev.status = mgmt_status(status); return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL); @@ -3185,7 +3185,7 @@ int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr, BT_DBG("%s", hdev->name); bacpy(&ev.addr.bdaddr, bdaddr); - ev.addr.type = link_to_mgmt(link_type, addr_type); + ev.addr.type = link_to_bdaddr(link_type, addr_type); ev.confirm_hint = confirm_hint; ev.value = value; @@ -3201,7 +3201,7 @@ int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr, BT_DBG("%s", hdev->name); bacpy(&ev.addr.bdaddr, bdaddr); - ev.addr.type = link_to_mgmt(link_type, addr_type); + ev.addr.type = link_to_bdaddr(link_type, addr_type); return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev), NULL); @@ -3220,7 +3220,7 @@ static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, return -ENOENT; bacpy(&rp.addr.bdaddr, bdaddr); - rp.addr.type = link_to_mgmt(link_type, addr_type); + rp.addr.type = link_to_bdaddr(link_type, addr_type); err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status), &rp, sizeof(rp)); @@ -3263,7 +3263,7 @@ int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, struct mgmt_ev_auth_failed ev; bacpy(&ev.addr.bdaddr, bdaddr); - ev.addr.type = link_to_mgmt(link_type, addr_type); + ev.addr.type = link_to_bdaddr(link_type, addr_type); ev.status = mgmt_status(status); return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL); @@ -3530,7 +3530,7 @@ int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, memset(buf, 0, sizeof(buf)); bacpy(&ev->addr.bdaddr, bdaddr); - ev->addr.type = link_to_mgmt(link_type, addr_type); + ev->addr.type = link_to_bdaddr(link_type, addr_type); ev->rssi = rssi; if (cfm_name) ev->flags[0] |= MGMT_DEV_FOUND_CONFIRM_NAME; @@ -3563,7 +3563,7 @@ int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, memset(buf, 0, sizeof(buf)); bacpy(&ev->addr.bdaddr, bdaddr); - ev->addr.type = link_to_mgmt(link_type, addr_type); + ev->addr.type = link_to_bdaddr(link_type, addr_type); ev->rssi = rssi; eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name, -- cgit v1.2.3 From 378b5b7e8426f65a0ecb81b83a050c6a0c119e1f Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Tue, 24 Apr 2012 21:02:51 -0300 Subject: Bluetooth: Rename mgmt_to_le to bdaddr_to_le Since address type macros are not only related to Management Interface anymore, it makes sense to rename the helper function mgmt_to_le to bdaddr_to_le. Signed-off-by: Andre Guedes Acked-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 632d43d0980b..605a35b284fe 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1644,9 +1644,9 @@ static u8 link_to_bdaddr(u8 link_type, u8 addr_type) } } -static u8 mgmt_to_le(u8 mgmt_type) +static u8 bdaddr_to_le(u8 bdaddr_type) { - switch (mgmt_type) { + switch (bdaddr_type) { case BDADDR_LE_PUBLIC: return ADDR_LE_DEV_PUBLIC; @@ -2665,7 +2665,7 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, type = HCI_SMP_LTK_SLAVE; hci_add_ltk(hdev, &key->addr.bdaddr, - mgmt_to_le(key->addr.type), + bdaddr_to_le(key->addr.type), type, 0, key->authenticated, key->val, key->enc_size, key->ediv, key->rand); } -- cgit v1.2.3 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 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 6777432ca61e..7e7fe3f221fb 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 aa45ea496f87..7bbd5c5767b9 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 605a35b284fe..4e26c2585817 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 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 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 7e7fe3f221fb..e69a9eed082c 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 8f352cd1745a..a3ee1a929a6c 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 97af2b4f6238..61af06d35335 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 4e26c2585817..9038118d37a3 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 bf1af0b1497e..cbdd313659a7 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 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 'net') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index bb4e3f66b43c..86bb83bc6a4f 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 61af06d35335..4b6d11c199b5 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 8d8b50a29906..2b5e7e81c3c0 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 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 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index e69a9eed082c..d1e744f3b9be 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 7bbd5c5767b9..83d3d3563bcc 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 054b1ad74496..ae0a57d21ec4 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 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 'net') diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 27a6a936487d..2fb268f2895b 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 4b6d11c199b5..62ef7c335163 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 From b5c6aaed183d6300b2cc5a107e5798aef427e5d9 Mon Sep 17 00:00:00 2001 From: Mat Martineau Date: Wed, 25 Apr 2012 16:36:15 -0700 Subject: Bluetooth: Move recently-added ERTM header packing functions Moving these functions simplifies future patches by eliminating forward declarations, makes future patches easier to review, and better preserves 'git blame' information. Signed-off-by: Mat Martineau Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- net/bluetooth/l2cap_core.c | 200 ++++++++++++++++++++++----------------------- 1 file changed, 100 insertions(+), 100 deletions(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 62ef7c335163..3b5238d1dfaa 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -724,87 +724,6 @@ static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb) hci_send_acl(chan->conn->hchan, skb, flags); } -static inline void l2cap_send_sframe(struct l2cap_chan *chan, u32 control) -{ - struct sk_buff *skb; - struct l2cap_hdr *lh; - struct l2cap_conn *conn = chan->conn; - int count, hlen; - - if (chan->state != BT_CONNECTED) - return; - - if (test_bit(FLAG_EXT_CTRL, &chan->flags)) - hlen = L2CAP_EXT_HDR_SIZE; - else - hlen = L2CAP_ENH_HDR_SIZE; - - if (chan->fcs == L2CAP_FCS_CRC16) - hlen += L2CAP_FCS_SIZE; - - BT_DBG("chan %p, control 0x%8.8x", chan, control); - - count = min_t(unsigned int, conn->mtu, hlen); - - control |= __set_sframe(chan); - - if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state)) - control |= __set_ctrl_final(chan); - - if (test_and_clear_bit(CONN_SEND_PBIT, &chan->conn_state)) - control |= __set_ctrl_poll(chan); - - skb = bt_skb_alloc(count, GFP_ATOMIC); - if (!skb) - return; - - lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); - lh->len = cpu_to_le16(hlen - L2CAP_HDR_SIZE); - lh->cid = cpu_to_le16(chan->dcid); - - __put_control(chan, control, skb_put(skb, __ctrl_size(chan))); - - if (chan->fcs == L2CAP_FCS_CRC16) { - u16 fcs = crc16(0, (u8 *)lh, count - L2CAP_FCS_SIZE); - put_unaligned_le16(fcs, skb_put(skb, L2CAP_FCS_SIZE)); - } - - skb->priority = HCI_PRIO_MAX; - l2cap_do_send(chan, skb); -} - -static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u32 control) -{ - if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) { - control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR); - set_bit(CONN_RNR_SENT, &chan->conn_state); - } else - control |= __set_ctrl_super(chan, L2CAP_SUPER_RR); - - control |= __set_reqseq(chan, chan->buffer_seq); - - l2cap_send_sframe(chan, control); -} - -static u16 __pack_enhanced_control(struct l2cap_ctrl *control) -{ - u16 packed; - - packed = control->reqseq << L2CAP_CTRL_REQSEQ_SHIFT; - packed |= control->final << L2CAP_CTRL_FINAL_SHIFT; - - if (control->sframe) { - packed |= control->poll << L2CAP_CTRL_POLL_SHIFT; - packed |= control->super << L2CAP_CTRL_SUPER_SHIFT; - packed |= L2CAP_CTRL_FRAME_TYPE; - } else { - packed |= control->sar << L2CAP_CTRL_SAR_SHIFT; - packed |= control->txseq << L2CAP_CTRL_TXSEQ_SHIFT; - } - - return packed; -} - static void __unpack_enhanced_control(u16 enh, struct l2cap_ctrl *control) { control->reqseq = (enh & L2CAP_CTRL_REQSEQ) >> L2CAP_CTRL_REQSEQ_SHIFT; @@ -829,25 +748,6 @@ static void __unpack_enhanced_control(u16 enh, struct l2cap_ctrl *control) } } -static u32 __pack_extended_control(struct l2cap_ctrl *control) -{ - u32 packed; - - packed = control->reqseq << L2CAP_EXT_CTRL_REQSEQ_SHIFT; - packed |= control->final << L2CAP_EXT_CTRL_FINAL_SHIFT; - - if (control->sframe) { - packed |= control->poll << L2CAP_EXT_CTRL_POLL_SHIFT; - packed |= control->super << L2CAP_EXT_CTRL_SUPER_SHIFT; - packed |= L2CAP_EXT_CTRL_FRAME_TYPE; - } else { - packed |= control->sar << L2CAP_EXT_CTRL_SAR_SHIFT; - packed |= control->txseq << L2CAP_EXT_CTRL_TXSEQ_SHIFT; - } - - return packed; -} - static void __unpack_extended_control(u32 ext, struct l2cap_ctrl *control) { control->reqseq = (ext & L2CAP_EXT_CTRL_REQSEQ) >> L2CAP_EXT_CTRL_REQSEQ_SHIFT; @@ -884,6 +784,44 @@ static inline void __unpack_control(struct l2cap_chan *chan, } } +static u32 __pack_extended_control(struct l2cap_ctrl *control) +{ + u32 packed; + + packed = control->reqseq << L2CAP_EXT_CTRL_REQSEQ_SHIFT; + packed |= control->final << L2CAP_EXT_CTRL_FINAL_SHIFT; + + if (control->sframe) { + packed |= control->poll << L2CAP_EXT_CTRL_POLL_SHIFT; + packed |= control->super << L2CAP_EXT_CTRL_SUPER_SHIFT; + packed |= L2CAP_EXT_CTRL_FRAME_TYPE; + } else { + packed |= control->sar << L2CAP_EXT_CTRL_SAR_SHIFT; + packed |= control->txseq << L2CAP_EXT_CTRL_TXSEQ_SHIFT; + } + + return packed; +} + +static u16 __pack_enhanced_control(struct l2cap_ctrl *control) +{ + u16 packed; + + packed = control->reqseq << L2CAP_CTRL_REQSEQ_SHIFT; + packed |= control->final << L2CAP_CTRL_FINAL_SHIFT; + + if (control->sframe) { + packed |= control->poll << L2CAP_CTRL_POLL_SHIFT; + packed |= control->super << L2CAP_CTRL_SUPER_SHIFT; + packed |= L2CAP_CTRL_FRAME_TYPE; + } else { + packed |= control->sar << L2CAP_CTRL_SAR_SHIFT; + packed |= control->txseq << L2CAP_CTRL_TXSEQ_SHIFT; + } + + return packed; +} + static inline void __pack_control(struct l2cap_chan *chan, struct l2cap_ctrl *control, struct sk_buff *skb) @@ -897,6 +835,68 @@ static inline void __pack_control(struct l2cap_chan *chan, } } +static inline void l2cap_send_sframe(struct l2cap_chan *chan, u32 control) +{ + struct sk_buff *skb; + struct l2cap_hdr *lh; + struct l2cap_conn *conn = chan->conn; + int count, hlen; + + if (chan->state != BT_CONNECTED) + return; + + if (test_bit(FLAG_EXT_CTRL, &chan->flags)) + hlen = L2CAP_EXT_HDR_SIZE; + else + hlen = L2CAP_ENH_HDR_SIZE; + + if (chan->fcs == L2CAP_FCS_CRC16) + hlen += L2CAP_FCS_SIZE; + + BT_DBG("chan %p, control 0x%8.8x", chan, control); + + count = min_t(unsigned int, conn->mtu, hlen); + + control |= __set_sframe(chan); + + if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state)) + control |= __set_ctrl_final(chan); + + if (test_and_clear_bit(CONN_SEND_PBIT, &chan->conn_state)) + control |= __set_ctrl_poll(chan); + + skb = bt_skb_alloc(count, GFP_ATOMIC); + if (!skb) + return; + + lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); + lh->len = cpu_to_le16(hlen - L2CAP_HDR_SIZE); + lh->cid = cpu_to_le16(chan->dcid); + + __put_control(chan, control, skb_put(skb, __ctrl_size(chan))); + + if (chan->fcs == L2CAP_FCS_CRC16) { + u16 fcs = crc16(0, (u8 *)lh, count - L2CAP_FCS_SIZE); + put_unaligned_le16(fcs, skb_put(skb, L2CAP_FCS_SIZE)); + } + + skb->priority = HCI_PRIO_MAX; + l2cap_do_send(chan, skb); +} + +static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u32 control) +{ + if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) { + control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR); + set_bit(CONN_RNR_SENT, &chan->conn_state); + } else + control |= __set_ctrl_super(chan, L2CAP_SUPER_RR); + + control |= __set_reqseq(chan, chan->buffer_seq); + + l2cap_send_sframe(chan, control); +} + static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan) { return !test_bit(CONF_CONNECT_PEND, &chan->conf_state); -- cgit v1.2.3 From 105bdf9ec19e729bacdb33861c74fcf3eb39eb37 Mon Sep 17 00:00:00 2001 From: Mat Martineau Date: Fri, 27 Apr 2012 16:50:48 -0700 Subject: Bluetooth: Initialize new l2cap_chan structure members Structure members used by ERTM or streaming mode need to be initialized when an ERTM or streaming mode link is configured. Some duplicate code is also eliminated by moving in to the ERTM init function. Signed-off-by: Mat Martineau Signed-off-by: Gustavo Padovan --- net/bluetooth/l2cap_core.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 3b5238d1dfaa..a397ed7c4707 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -2314,17 +2314,30 @@ static inline int l2cap_ertm_init(struct l2cap_chan *chan) { int err; + chan->next_tx_seq = 0; + chan->expected_tx_seq = 0; chan->expected_ack_seq = 0; chan->unacked_frames = 0; chan->buffer_seq = 0; chan->num_acked = 0; chan->frames_sent = 0; + chan->last_acked_seq = 0; + chan->sdu = NULL; + chan->sdu_last_frag = NULL; + chan->sdu_len = 0; + + if (chan->mode != L2CAP_MODE_ERTM) + return 0; + + chan->rx_state = L2CAP_RX_STATE_RECV; + chan->tx_state = L2CAP_TX_STATE_XMIT; INIT_DELAYED_WORK(&chan->retrans_timer, l2cap_retrans_timeout); INIT_DELAYED_WORK(&chan->monitor_timer, l2cap_monitor_timeout); INIT_DELAYED_WORK(&chan->ack_timer, l2cap_ack_timeout); skb_queue_head_init(&chan->srej_q); + skb_queue_head_init(&chan->tx_q); INIT_LIST_HEAD(&chan->srej_l); err = l2cap_seq_list_init(&chan->srej_list, chan->tx_win); @@ -3192,10 +3205,8 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr l2cap_state_change(chan, BT_CONNECTED); - chan->next_tx_seq = 0; - chan->expected_tx_seq = 0; - skb_queue_head_init(&chan->tx_q); - if (chan->mode == L2CAP_MODE_ERTM) + if (chan->mode == L2CAP_MODE_ERTM || + chan->mode == L2CAP_MODE_STREAMING) err = l2cap_ertm_init(chan); if (err < 0) @@ -3327,10 +3338,8 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr set_default_fcs(chan); l2cap_state_change(chan, BT_CONNECTED); - chan->next_tx_seq = 0; - chan->expected_tx_seq = 0; - skb_queue_head_init(&chan->tx_q); - if (chan->mode == L2CAP_MODE_ERTM) + if (chan->mode == L2CAP_MODE_ERTM || + chan->mode == L2CAP_MODE_STREAMING) err = l2cap_ertm_init(chan); if (err < 0) -- cgit v1.2.3 From dbd89fddc1f1fc96085deb164b7b9b2361241dd3 Mon Sep 17 00:00:00 2001 From: Mat Martineau Date: Fri, 27 Apr 2012 16:50:49 -0700 Subject: Bluetooth: Remove unused function l2cap_get_chan_by_ident was not used, but didn't generate a compiler warning because it was an inline function. Signed-off-by: Mat Martineau Signed-off-by: Gustavo Padovan --- net/bluetooth/l2cap_core.c | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index a397ed7c4707..1192c943bf8e 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -120,17 +120,6 @@ static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 return NULL; } -static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident) -{ - struct l2cap_chan *c; - - mutex_lock(&conn->chan_lock); - c = __l2cap_get_chan_by_ident(conn, ident); - mutex_unlock(&conn->chan_lock); - - return c; -} - static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src) { struct l2cap_chan *c; -- cgit v1.2.3 From 61d6ef3e3408cdf7e622646fb90a9f7f9560b943 Mon Sep 17 00:00:00 2001 From: Mat Martineau Date: Fri, 27 Apr 2012 16:50:50 -0700 Subject: Bluetooth: Make better use of l2cap_chan reference counting L2CAP sockets contain a pointer to l2cap_chan that needs to be reference counted in order to prevent a possible dangling pointer when the channel is freed. There were a few other cases where an l2cap_chan pointer on the stack was dereferenced after a call to l2cap_chan_del. Those pointers are also now reference counted. Signed-off-by: Mat Martineau Signed-off-by: Gustavo Padovan --- net/bluetooth/l2cap_core.c | 6 ++++++ net/bluetooth/l2cap_sock.c | 3 +++ 2 files changed, 9 insertions(+) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 1192c943bf8e..b854d284d42a 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1256,6 +1256,7 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) /* Kill channels */ list_for_each_entry_safe(chan, l, &conn->chan_l, list) { + l2cap_chan_hold(chan); l2cap_chan_lock(chan); l2cap_chan_del(chan, err); @@ -1263,6 +1264,7 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) l2cap_chan_unlock(chan); chan->ops->close(chan->data); + l2cap_chan_put(chan); } mutex_unlock(&conn->chan_lock); @@ -3375,11 +3377,13 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd sk->sk_shutdown = SHUTDOWN_MASK; release_sock(sk); + l2cap_chan_hold(chan); l2cap_chan_del(chan, ECONNRESET); l2cap_chan_unlock(chan); chan->ops->close(chan->data); + l2cap_chan_put(chan); mutex_unlock(&conn->chan_lock); @@ -3407,11 +3411,13 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd l2cap_chan_lock(chan); + l2cap_chan_hold(chan); l2cap_chan_del(chan, 0); l2cap_chan_unlock(chan); chan->ops->close(chan->data); + l2cap_chan_put(chan); mutex_unlock(&conn->chan_lock); diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 2b5e7e81c3c0..6bf8ff75d95f 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -956,6 +956,7 @@ static void l2cap_sock_destruct(struct sock *sk) { BT_DBG("sk %p", sk); + l2cap_chan_put(l2cap_pi(sk)->chan); if (l2cap_pi(sk)->rx_busy_skb) { kfree_skb(l2cap_pi(sk)->rx_busy_skb); l2cap_pi(sk)->rx_busy_skb = NULL; @@ -1057,6 +1058,8 @@ static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int p return NULL; } + l2cap_chan_hold(chan); + chan->sk = sk; l2cap_pi(sk)->chan = chan; -- cgit v1.2.3 From 422e925b5b4201dc35bd6a647729ccd9440abb59 Mon Sep 17 00:00:00 2001 From: Mat Martineau Date: Fri, 27 Apr 2012 16:50:55 -0700 Subject: Bluetooth: Add Code Aurora Forum copyright Adding Code Aurora Forum copyright information due to significant additions of code. Acked-by: Marcel Holtmann Signed-off-by: Mat Martineau Signed-off-by: Gustavo Padovan --- net/bluetooth/l2cap_core.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index b854d284d42a..744d036ca91c 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -4,6 +4,7 @@ Copyright (C) 2009-2010 Gustavo F. Padovan Copyright (C) 2010 Google Inc. Copyright (C) 2011 ProFUSION Embedded Systems + Copyright (c) 2012 Code Aurora Forum. All rights reserved. Written 2000,2001 by Maxim Krasnyansky -- cgit v1.2.3 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 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index d1e744f3b9be..e3547ea83619 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 a3ee1a929a6c..cae7ec2df7ad 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 From 6ff9b5ef5e4e3f474689737640d0c01a96d0696d Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Wed, 2 May 2012 11:56:17 -0300 Subject: Bluetooth: Remove unneeded elements from size calculation hlen - L2CAP_HDR_SIZE = 0, so we don't need to add them in the calculation. Signed-off-by: Gustavo Padovan Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 744d036ca91c..02ba11831793 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1909,7 +1909,7 @@ static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, /* Create L2CAP header */ lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); lh->cid = cpu_to_le16(chan->dcid); - lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE)); + lh->len = cpu_to_le16(len); err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb); if (unlikely(err < 0)) { -- cgit v1.2.3 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 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index e3547ea83619..b60d2c844eba 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 cae7ec2df7ad..3f18a6ed9731 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 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 'net') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 346f08779792..66a7b579e31c 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 ae0a57d21ec4..d81262aff263 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 9038118d37a3..966f6bcfbcb9 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 From f2ba7fae044b578b068b40723dc3303b590abb78 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Thu, 3 May 2012 04:54:21 -0300 Subject: Bluetooth: Remove hlen variable hlen has a fixed size of L2CAP_HDR_SIZE, use this instead. Signed-off-by: Gustavo Padovan Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 02ba11831793..7acd884f1c3e 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1892,14 +1892,14 @@ static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, { struct l2cap_conn *conn = chan->conn; struct sk_buff *skb; - int err, count, hlen = L2CAP_HDR_SIZE; + int err, count; struct l2cap_hdr *lh; BT_DBG("chan %p len %d", chan, (int)len); - count = min_t(unsigned int, (conn->mtu - hlen), len); + count = min_t(unsigned int, (conn->mtu - L2CAP_HDR_SIZE), len); - skb = chan->ops->alloc_skb(chan, count + hlen, + skb = chan->ops->alloc_skb(chan, count + L2CAP_HDR_SIZE, msg->msg_flags & MSG_DONTWAIT); if (IS_ERR(skb)) return skb; -- cgit v1.2.3 From daf6a78c161fccd058ca2f1b21e757ebaa2e9909 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Thu, 3 May 2012 10:55:52 +0300 Subject: Bluetooth: Remove unneeded calculation and magic number Remove magic number unneeded calculation since hlen = L2CAP_HDR_SIZE + L2CAP_PSMLEN_SIZE Signed-off-by: Andrei Emeltchenko Signed-off-by: Gustavo Padovan --- net/bluetooth/l2cap_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 7acd884f1c3e..fcd09fb4b94c 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1875,8 +1875,8 @@ static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, /* Create L2CAP header */ lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); lh->cid = cpu_to_le16(chan->dcid); - lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE)); - put_unaligned(chan->psm, skb_put(skb, 2)); + lh->len = cpu_to_le16(len + L2CAP_PSMLEN_SIZE); + put_unaligned(chan->psm, skb_put(skb, L2CAP_PSMLEN_SIZE)); err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb); if (unlikely(err < 0)) { -- cgit v1.2.3 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 'net') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 084dec001bf2..1c7d1cd5e679 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 fcd09fb4b94c..2b30bd767779 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 From 000092b0b4793caf831f6016fa69d25abba31e51 Mon Sep 17 00:00:00 2001 From: Eldad Zack Date: Tue, 8 May 2012 00:09:35 +0200 Subject: Bluetooth: bnep: use constant for ethertype The dot1q ethertype number (0x8100) is embedded in the code, although it is already defined in included headers. Signed-off-by: Eldad Zack Signed-off-by: Gustavo Padovan --- net/bluetooth/bnep/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c index a779ec703323..4fab4362b5aa 100644 --- a/net/bluetooth/bnep/core.c +++ b/net/bluetooth/bnep/core.c @@ -340,7 +340,7 @@ static inline int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb) } /* Strip 802.1p header */ - if (ntohs(s->eh.h_proto) == 0x8100) { + if (ntohs(s->eh.h_proto) == ETH_P_8021Q) { if (!skb_pull(skb, 4)) goto badframe; s->eh.h_proto = get_unaligned((__be16 *) (skb->data - 2)); -- cgit v1.2.3 From 53168e5b3b40efffff8b9f2e6e0eaf5607daa884 Mon Sep 17 00:00:00 2001 From: Cristian Chilipirea Date: Wed, 9 May 2012 08:44:52 +0300 Subject: Bluetooth: Fixed checkpatch warnings Fixed some checkpatch warnings in mgmt.c. Signed-off-by: Cristian Chilipirea Signed-off-by: Gustavo Padovan --- net/bluetooth/mgmt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 966f6bcfbcb9..25d220776079 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2944,7 +2944,8 @@ int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status) return 0; } -int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, bool persistent) +int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, + bool persistent) { struct mgmt_ev_new_link_key ev; -- cgit v1.2.3 From 577cfaeb864874011386a05ab4f5580a6a2aeb11 Mon Sep 17 00:00:00 2001 From: Mat Martineau Date: Mon, 14 May 2012 11:24:33 -0700 Subject: Bluetooth: Update tx_send_head when sending ERTM data Commit 94122bbe9c8c4ad7ba9f02f9a30bfc95672c404e introduced a problem where tx_send_head was not set to point to the first skb in the ERTM transmit queue, which stalled data transmission. This change sets that pointer when transmission is not already in progress. Reported-by: Andrei Emeltchenko Signed-off-by: Mat Martineau Signed-off-by: Gustavo Padovan --- net/bluetooth/l2cap_core.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 2b30bd767779..869beb30f480 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -2104,7 +2104,10 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len, if (err) break; + if (chan->mode == L2CAP_MODE_ERTM && chan->tx_send_head == NULL) + chan->tx_send_head = seg_queue.next; skb_queue_splice_tail_init(&seg_queue, &chan->tx_q); + if (chan->mode == L2CAP_MODE_ERTM) err = l2cap_ertm_send(chan); else -- cgit v1.2.3 From f3a138c10b9a5f716d2b773e0ae08401ebd19f80 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 3 May 2012 07:12:48 +0200 Subject: NFC: Select CRC_CCITT for SHDLC link layer of HCI based drivers The SHDLC link layer of HCI based drivers uses CRC-CCITT and thus needs to select that kernel option. Otherwise it ends up with this linking error: net/built-in.o: In function `nfc_shdlc_add_len_crc': net/nfc/hci/shdlc.c:113: undefined reference to `crc_ccitt' Signed-off-by: Marcel Holtmann Acked-by: Samuel Ortiz Signed-off-by: John W. Linville --- net/nfc/hci/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/nfc/hci/Kconfig b/net/nfc/hci/Kconfig index 17213a6362b4..fd67f51d18e9 100644 --- a/net/nfc/hci/Kconfig +++ b/net/nfc/hci/Kconfig @@ -9,6 +9,7 @@ config NFC_HCI config NFC_SHDLC depends on NFC_HCI + select CRC_CCITT bool "SHDLC link layer for HCI based NFC drivers" default n ---help--- -- cgit v1.2.3 From f5c5681424299add910aad86b01d6ffe7ca02c84 Mon Sep 17 00:00:00 2001 From: Thomas Pedersen Date: Thu, 3 May 2012 15:06:09 -0700 Subject: mac80211: send peer candidate event for new sta only Only send a cfg80211 new peer candidate notification if userspace has yet to allocate this station entry. Signed-off-by: Thomas Pedersen Signed-off-by: John W. Linville --- net/mac80211/mesh_plink.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'net') diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 8cc8461b48a0..ae026acec874 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -346,6 +346,15 @@ static struct sta_info *mesh_peer_init(struct ieee80211_sub_if_data *sdata, sta = sta_info_get(sdata, addr); if (!sta) { + /* Userspace handles peer allocation when security is enabled */ + if (sdata->u.mesh.security & IEEE80211_MESH_SEC_AUTHED) { + cfg80211_notify_new_peer_candidate(sdata->dev, addr, + elems->ie_start, + elems->total_len, + GFP_ATOMIC); + return NULL; + } + sta = mesh_plink_alloc(sdata, addr); if (!sta) return NULL; @@ -387,15 +396,6 @@ void mesh_neighbour_update(struct ieee80211_sub_if_data *sdata, { struct sta_info *sta; - /* Userspace handles peer allocation when security is enabled */ - if (sdata->u.mesh.security & IEEE80211_MESH_SEC_AUTHED) { - cfg80211_notify_new_peer_candidate(sdata->dev, hw_addr, - elems->ie_start, - elems->total_len, - GFP_KERNEL); - return; - } - rcu_read_lock(); sta = mesh_peer_init(sdata, hw_addr, elems); if (!sta) -- cgit v1.2.3 From 7d4e15b177835dfddcab9851a889c28a85dde92e Mon Sep 17 00:00:00 2001 From: Chun-Yeow Yeoh Date: Fri, 4 May 2012 14:57:50 +0800 Subject: mac80211: fix the increment of unicast/multicast counters for forwarded PREQ Forwarded PREQ is either unicast or multicast. The appropriate counters should be incremented accordingly. Signed-off-by: Chun-Yeow Yeoh Signed-off-by: John W. Linville --- net/mac80211/mesh_hwmp.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 503016f58631..70ac7d180077 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -603,7 +603,10 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, hopcount, ttl, cpu_to_le32(lifetime), cpu_to_le32(metric), cpu_to_le32(preq_id), sdata); - ifmsh->mshstats.fwded_mcast++; + if (!is_multicast_ether_addr(da)) + ifmsh->mshstats.fwded_unicast++; + else + ifmsh->mshstats.fwded_mcast++; ifmsh->mshstats.fwded_frames++; } } -- cgit v1.2.3 From 900994332675f84a9fbbb33ff089474614c7f2fe Mon Sep 17 00:00:00 2001 From: Eric Lapuyade Date: Mon, 7 May 2012 12:31:13 +0200 Subject: NFC: Cache the core NFC active target pointer instead of its index The NFC Core now caches the active nfc target pointer, thereby avoiding the need to lookup the target table for each invocation of a driver ops. Consequently, pn533, HCI and NCI now directly receive an nfc_target pointer instead of a target index. Cc: Ilan Elias Signed-off-by: Eric Lapuyade Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- drivers/nfc/pn533.c | 16 +++++----- include/net/nfc/nfc.h | 18 +++++++----- net/nfc/core.c | 81 ++++++++++++++++++++++++++++++++++++++------------- net/nfc/hci/core.c | 36 ++++------------------- net/nfc/nci/core.c | 27 ++++++++--------- 5 files changed, 99 insertions(+), 79 deletions(-) (limited to 'net') diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index e6ec16d92e65..766e0bb5ae53 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -1194,8 +1194,8 @@ static int pn533_activate_target_nfcdep(struct pn533 *dev) return rc; } -static int pn533_activate_target(struct nfc_dev *nfc_dev, u32 target_idx, - u32 protocol) +static int pn533_activate_target(struct nfc_dev *nfc_dev, + struct nfc_target *target, u32 protocol) { struct pn533 *dev = nfc_get_drvdata(nfc_dev); int rc; @@ -1243,7 +1243,8 @@ static int pn533_activate_target(struct nfc_dev *nfc_dev, u32 target_idx, return 0; } -static void pn533_deactivate_target(struct nfc_dev *nfc_dev, u32 target_idx) +static void pn533_deactivate_target(struct nfc_dev *nfc_dev, + struct nfc_target *target) { struct pn533 *dev = nfc_get_drvdata(nfc_dev); u8 tg; @@ -1351,7 +1352,7 @@ static int pn533_in_dep_link_up_complete(struct pn533 *dev, void *arg, return 0; } -static int pn533_dep_link_up(struct nfc_dev *nfc_dev, int target_idx, +static int pn533_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target, u8 comm_mode, u8* gb, size_t gb_len) { struct pn533 *dev = nfc_get_drvdata(nfc_dev); @@ -1552,10 +1553,9 @@ error: return 0; } -static int pn533_data_exchange(struct nfc_dev *nfc_dev, u32 target_idx, - struct sk_buff *skb, - data_exchange_cb_t cb, - void *cb_context) +static int pn533_data_exchange(struct nfc_dev *nfc_dev, + struct nfc_target *target, struct sk_buff *skb, + data_exchange_cb_t cb, void *cb_context) { struct pn533 *dev = nfc_get_drvdata(nfc_dev); struct pn533_frame *out_frame, *in_frame; diff --git a/include/net/nfc/nfc.h b/include/net/nfc/nfc.h index 9a2505a5b8de..0fcf4a54776b 100644 --- a/include/net/nfc/nfc.h +++ b/include/net/nfc/nfc.h @@ -48,26 +48,28 @@ struct nfc_dev; typedef void (*data_exchange_cb_t)(void *context, struct sk_buff *skb, int err); +struct nfc_target; + struct nfc_ops { int (*dev_up)(struct nfc_dev *dev); int (*dev_down)(struct nfc_dev *dev); int (*start_poll)(struct nfc_dev *dev, u32 protocols); void (*stop_poll)(struct nfc_dev *dev); - int (*dep_link_up)(struct nfc_dev *dev, int target_idx, u8 comm_mode, - u8 *gb, size_t gb_len); + int (*dep_link_up)(struct nfc_dev *dev, struct nfc_target *target, + u8 comm_mode, u8 *gb, size_t gb_len); int (*dep_link_down)(struct nfc_dev *dev); - int (*activate_target)(struct nfc_dev *dev, u32 target_idx, + int (*activate_target)(struct nfc_dev *dev, struct nfc_target *target, u32 protocol); - void (*deactivate_target)(struct nfc_dev *dev, u32 target_idx); - int (*data_exchange)(struct nfc_dev *dev, u32 target_idx, + void (*deactivate_target)(struct nfc_dev *dev, + struct nfc_target *target); + int (*data_exchange)(struct nfc_dev *dev, struct nfc_target *target, struct sk_buff *skb, data_exchange_cb_t cb, void *cb_context); - int (*check_presence)(struct nfc_dev *dev, u32 target_idx); + int (*check_presence)(struct nfc_dev *dev, struct nfc_target *target); }; #define NFC_TARGET_IDX_ANY -1 #define NFC_MAX_GT_LEN 48 -#define NFC_TARGET_IDX_NONE 0xffffffff struct nfc_target { u32 idx; @@ -99,7 +101,7 @@ struct nfc_dev { struct device dev; bool dev_up; bool polling; - u32 activated_target_idx; + struct nfc_target *active_target; bool dep_link_up; u32 dep_rf_mode; struct nfc_genl_data genl_data; diff --git a/net/nfc/core.c b/net/nfc/core.c index 3192c3f589ee..7df28ad4727f 100644 --- a/net/nfc/core.c +++ b/net/nfc/core.c @@ -97,7 +97,7 @@ int nfc_dev_down(struct nfc_dev *dev) goto error; } - if (dev->polling || dev->activated_target_idx != NFC_TARGET_IDX_NONE) { + if (dev->polling || dev->active_target) { rc = -EBUSY; goto error; } @@ -183,11 +183,27 @@ error: return rc; } +static struct nfc_target *nfc_find_target(struct nfc_dev *dev, u32 target_idx) +{ + int i; + + if (dev->n_targets == 0) + return NULL; + + for (i = 0; i < dev->n_targets ; i++) { + if (dev->targets[i].idx == target_idx) + return &dev->targets[i]; + } + + return NULL; +} + int nfc_dep_link_up(struct nfc_dev *dev, int target_index, u8 comm_mode) { int rc = 0; u8 *gb; size_t gb_len; + struct nfc_target *target; pr_debug("dev_name=%s comm %d\n", dev_name(&dev->dev), comm_mode); @@ -212,9 +228,15 @@ int nfc_dep_link_up(struct nfc_dev *dev, int target_index, u8 comm_mode) goto error; } - rc = dev->ops->dep_link_up(dev, target_index, comm_mode, gb, gb_len); + target = nfc_find_target(dev, target_index); + if (target == NULL) { + rc = -ENOTCONN; + goto error; + } + + rc = dev->ops->dep_link_up(dev, target, comm_mode, gb, gb_len); if (!rc) - dev->activated_target_idx = target_index; + dev->active_target = target; error: device_unlock(&dev->dev); @@ -250,7 +272,7 @@ int nfc_dep_link_down(struct nfc_dev *dev) rc = dev->ops->dep_link_down(dev); if (!rc) { dev->dep_link_up = false; - dev->activated_target_idx = NFC_TARGET_IDX_NONE; + dev->active_target = NULL; nfc_llcp_mac_is_down(dev); nfc_genl_dep_link_down_event(dev); } @@ -282,6 +304,7 @@ EXPORT_SYMBOL(nfc_dep_link_is_up); int nfc_activate_target(struct nfc_dev *dev, u32 target_idx, u32 protocol) { int rc; + struct nfc_target *target; pr_debug("dev_name=%s target_idx=%u protocol=%u\n", dev_name(&dev->dev), target_idx, protocol); @@ -293,9 +316,20 @@ int nfc_activate_target(struct nfc_dev *dev, u32 target_idx, u32 protocol) goto error; } - rc = dev->ops->activate_target(dev, target_idx, protocol); + if (dev->active_target) { + rc = -EBUSY; + goto error; + } + + target = nfc_find_target(dev, target_idx); + if (target == NULL) { + rc = -ENOTCONN; + goto error; + } + + rc = dev->ops->activate_target(dev, target, protocol); if (!rc) { - dev->activated_target_idx = target_idx; + dev->active_target = target; if (dev->ops->check_presence) mod_timer(&dev->check_pres_timer, jiffies + @@ -327,11 +361,21 @@ int nfc_deactivate_target(struct nfc_dev *dev, u32 target_idx) goto error; } + if (dev->active_target == NULL) { + rc = -ENOTCONN; + goto error; + } + + if (dev->active_target->idx != target_idx) { + rc = -ENOTCONN; + goto error; + } + if (dev->ops->check_presence) del_timer_sync(&dev->check_pres_timer); - dev->ops->deactivate_target(dev, target_idx); - dev->activated_target_idx = NFC_TARGET_IDX_NONE; + dev->ops->deactivate_target(dev, dev->active_target); + dev->active_target = NULL; error: device_unlock(&dev->dev); @@ -365,13 +409,13 @@ int nfc_data_exchange(struct nfc_dev *dev, u32 target_idx, struct sk_buff *skb, goto error; } - if (dev->activated_target_idx == NFC_TARGET_IDX_NONE) { + if (dev->active_target == NULL) { rc = -ENOTCONN; kfree_skb(skb); goto error; } - if (target_idx != dev->activated_target_idx) { + if (dev->active_target->idx != target_idx) { rc = -EADDRNOTAVAIL; kfree_skb(skb); goto error; @@ -380,7 +424,8 @@ int nfc_data_exchange(struct nfc_dev *dev, u32 target_idx, struct sk_buff *skb, if (dev->ops->check_presence) del_timer_sync(&dev->check_pres_timer); - rc = dev->ops->data_exchange(dev, target_idx, skb, cb, cb_context); + rc = dev->ops->data_exchange(dev, dev->active_target, skb, cb, + cb_context); if (!rc && dev->ops->check_presence) mod_timer(&dev->check_pres_timer, jiffies + @@ -514,7 +559,7 @@ int nfc_target_lost(struct nfc_dev *dev, u32 target_idx) dev->targets_generation++; dev->n_targets--; - dev->activated_target_idx = NFC_TARGET_IDX_NONE; + dev->active_target = NULL; if (dev->n_targets) { memcpy(&dev->targets[i], &dev->targets[i + 1], @@ -556,15 +601,14 @@ static void nfc_check_pres_work(struct work_struct *work) device_lock(&dev->dev); - if (dev->activated_target_idx != NFC_TARGET_IDX_NONE && - timer_pending(&dev->check_pres_timer) == 0) { - rc = dev->ops->check_presence(dev, dev->activated_target_idx); + if (dev->active_target && timer_pending(&dev->check_pres_timer) == 0) { + rc = dev->ops->check_presence(dev, dev->active_target); if (!rc) { mod_timer(&dev->check_pres_timer, jiffies + msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS)); } else { - nfc_target_lost(dev, dev->activated_target_idx); - dev->activated_target_idx = NFC_TARGET_IDX_NONE; + nfc_target_lost(dev, dev->active_target->idx); + dev->active_target = NULL; } } @@ -643,8 +687,6 @@ struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops, /* first generation must not be 0 */ dev->targets_generation = 1; - dev->activated_target_idx = NFC_TARGET_IDX_NONE; - if (ops->check_presence) { char name[32]; init_timer(&dev->check_pres_timer); @@ -662,7 +704,6 @@ struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops, } } - return dev; } EXPORT_SYMBOL(nfc_allocate_device); diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c index 86fd00d5a099..545c19f17536 100644 --- a/net/nfc/hci/core.c +++ b/net/nfc/hci/core.c @@ -520,50 +520,26 @@ static void hci_stop_poll(struct nfc_dev *nfc_dev) } } -static struct nfc_target *hci_find_target(struct nfc_hci_dev *hdev, - u32 target_idx) +static int hci_activate_target(struct nfc_dev *nfc_dev, + struct nfc_target *target, u32 protocol) { - int i; - if (hdev->poll_started == false || hdev->targets == NULL) - return NULL; - - for (i = 0; i < hdev->target_count; i++) { - if (hdev->targets[i].idx == target_idx) - return &hdev->targets[i]; - } - - return NULL; -} - -static int hci_activate_target(struct nfc_dev *nfc_dev, u32 target_idx, - u32 protocol) -{ - struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); - - if (hci_find_target(hdev, target_idx) == NULL) - return -ENOMEDIUM; - return 0; } -static void hci_deactivate_target(struct nfc_dev *nfc_dev, u32 target_idx) +static void hci_deactivate_target(struct nfc_dev *nfc_dev, + struct nfc_target *target) { } -static int hci_data_exchange(struct nfc_dev *nfc_dev, u32 target_idx, +static int hci_data_exchange(struct nfc_dev *nfc_dev, struct nfc_target *target, struct sk_buff *skb, data_exchange_cb_t cb, void *cb_context) { struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); int r; - struct nfc_target *target; struct sk_buff *res_skb = NULL; - pr_debug("target_idx=%d\n", target_idx); - - target = hci_find_target(hdev, target_idx); - if (target == NULL) - return -ENOMEDIUM; + pr_debug("target_idx=%d\n", target->idx); switch (target->hci_reader_gate) { case NFC_HCI_RF_READER_A_GATE: diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c index 8737c2089fdd..d560e6f13072 100644 --- a/net/nfc/nci/core.c +++ b/net/nfc/nci/core.c @@ -436,16 +436,16 @@ static void nci_stop_poll(struct nfc_dev *nfc_dev) msecs_to_jiffies(NCI_RF_DEACTIVATE_TIMEOUT)); } -static int nci_activate_target(struct nfc_dev *nfc_dev, __u32 target_idx, - __u32 protocol) +static int nci_activate_target(struct nfc_dev *nfc_dev, + struct nfc_target *target, __u32 protocol) { struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); struct nci_rf_discover_select_param param; - struct nfc_target *target = NULL; + struct nfc_target *nci_target = NULL; int i; int rc = 0; - pr_debug("target_idx %d, protocol 0x%x\n", target_idx, protocol); + pr_debug("target_idx %d, protocol 0x%x\n", target->idx, protocol); if ((atomic_read(&ndev->state) != NCI_W4_HOST_SELECT) && (atomic_read(&ndev->state) != NCI_POLL_ACTIVE)) { @@ -459,25 +459,25 @@ static int nci_activate_target(struct nfc_dev *nfc_dev, __u32 target_idx, } for (i = 0; i < ndev->n_targets; i++) { - if (ndev->targets[i].idx == target_idx) { - target = &ndev->targets[i]; + if (ndev->targets[i].idx == target->idx) { + nci_target = &ndev->targets[i]; break; } } - if (!target) { + if (!nci_target) { pr_err("unable to find the selected target\n"); return -EINVAL; } - if (!(target->supported_protocols & (1 << protocol))) { + if (!(nci_target->supported_protocols & (1 << protocol))) { pr_err("target does not support the requested protocol 0x%x\n", protocol); return -EINVAL; } if (atomic_read(&ndev->state) == NCI_W4_HOST_SELECT) { - param.rf_discovery_id = target->logical_idx; + param.rf_discovery_id = nci_target->logical_idx; if (protocol == NFC_PROTO_JEWEL) param.rf_protocol = NCI_RF_PROTOCOL_T1T; @@ -501,11 +501,12 @@ static int nci_activate_target(struct nfc_dev *nfc_dev, __u32 target_idx, return rc; } -static void nci_deactivate_target(struct nfc_dev *nfc_dev, __u32 target_idx) +static void nci_deactivate_target(struct nfc_dev *nfc_dev, + struct nfc_target *target) { struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); - pr_debug("target_idx %d\n", target_idx); + pr_debug("target_idx %d\n", target->idx); if (!ndev->target_active_prot) { pr_err("unable to deactivate target, no active target\n"); @@ -520,14 +521,14 @@ static void nci_deactivate_target(struct nfc_dev *nfc_dev, __u32 target_idx) } } -static int nci_data_exchange(struct nfc_dev *nfc_dev, __u32 target_idx, +static int nci_data_exchange(struct nfc_dev *nfc_dev, struct nfc_target *target, struct sk_buff *skb, data_exchange_cb_t cb, void *cb_context) { struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); int rc; - pr_debug("target_idx %d, len %d\n", target_idx, skb->len); + pr_debug("target_idx %d, len %d\n", target->idx, skb->len); if (!ndev->target_active_prot) { pr_err("unable to exchange data, no active target\n"); -- cgit v1.2.3 From addfabf98daad7b469ad788a622dbeab6aaaa330 Mon Sep 17 00:00:00 2001 From: Eric Lapuyade Date: Mon, 7 May 2012 12:31:14 +0200 Subject: NFC: Remove useless HCI private nfc target table Signed-off-by: Eric Lapuyade Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- include/net/nfc/hci.h | 2 -- net/nfc/hci/core.c | 7 ------- 2 files changed, 9 deletions(-) (limited to 'net') diff --git a/include/net/nfc/hci.h b/include/net/nfc/hci.h index aca65a5a9d0d..95fc0c27578e 100644 --- a/include/net/nfc/hci.h +++ b/include/net/nfc/hci.h @@ -83,8 +83,6 @@ struct nfc_hci_dev { u8 gate2pipe[NFC_HCI_MAX_GATES]; bool poll_started; - struct nfc_target *targets; - int target_count; u8 sw_romlib; u8 sw_patch; diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c index 545c19f17536..ef5cd5c9e3fb 100644 --- a/net/nfc/hci/core.c +++ b/net/nfc/hci/core.c @@ -235,13 +235,6 @@ static int nfc_hci_target_discovered(struct nfc_hci_dev *hdev, u8 gate) targets->hci_reader_gate = gate; r = nfc_targets_found(hdev->ndev, targets, 1); - if (r < 0) - goto exit; - - kfree(hdev->targets); - hdev->targets = targets; - targets = NULL; - hdev->target_count = 1; exit: kfree(targets); -- cgit v1.2.3 From d4ccb132801aeeb2cfd18c4b4b7fa0043ab37f80 Mon Sep 17 00:00:00 2001 From: Eric Lapuyade Date: Mon, 7 May 2012 12:31:15 +0200 Subject: NFC: Specify usage for targets found and target lost events It is now specified that nfc_target_found() and nfc_target_lost() core functions must not be called from an atomic context. This allow us to serialize calls and protect the targets table using the nfc device lock instead of a spinlock. Signed-off-by: Eric Lapuyade Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- include/net/nfc/nfc.h | 1 - net/nfc/core.c | 35 ++++++++++++++++++++++++++--------- net/nfc/netlink.c | 4 ++-- 3 files changed, 28 insertions(+), 12 deletions(-) (limited to 'net') diff --git a/include/net/nfc/nfc.h b/include/net/nfc/nfc.h index 0fcf4a54776b..b7ca4a2a1d72 100644 --- a/include/net/nfc/nfc.h +++ b/include/net/nfc/nfc.h @@ -97,7 +97,6 @@ struct nfc_dev { struct nfc_target *targets; int n_targets; int targets_generation; - spinlock_t targets_lock; struct device dev; bool dev_up; bool polling; diff --git a/net/nfc/core.c b/net/nfc/core.c index 7df28ad4727f..9f6ce011d35d 100644 --- a/net/nfc/core.c +++ b/net/nfc/core.c @@ -501,6 +501,9 @@ EXPORT_SYMBOL(nfc_alloc_recv_skb); * The device driver must call this function when one or many nfc targets * are found. After calling this function, the device driver must stop * polling for targets. + * IMPORTANT: this function must not be called from an atomic context. + * In addition, it must also not be called from a context that would prevent + * the NFC Core to call other nfc ops entry point concurrently. */ int nfc_targets_found(struct nfc_dev *dev, struct nfc_target *targets, int n_targets) @@ -514,7 +517,7 @@ int nfc_targets_found(struct nfc_dev *dev, for (i = 0; i < n_targets; i++) targets[i].idx = dev->target_next_idx++; - spin_lock_bh(&dev->targets_lock); + device_lock(&dev->dev); dev->targets_generation++; @@ -524,12 +527,12 @@ int nfc_targets_found(struct nfc_dev *dev, if (!dev->targets) { dev->n_targets = 0; - spin_unlock_bh(&dev->targets_lock); + device_unlock(&dev->dev); return -ENOMEM; } dev->n_targets = n_targets; - spin_unlock_bh(&dev->targets_lock); + device_unlock(&dev->dev); nfc_genl_targets_found(dev); @@ -537,6 +540,18 @@ int nfc_targets_found(struct nfc_dev *dev, } EXPORT_SYMBOL(nfc_targets_found); +/** + * nfc_target_lost - inform that an activated target went out of field + * + * @dev: The nfc device that had the activated target in field + * @target_idx: the nfc index of the target + * + * The device driver must call this function when the activated target + * goes out of the field. + * IMPORTANT: this function must not be called from an atomic context. + * In addition, it must also not be called from a context that would prevent + * the NFC Core to call other nfc ops entry point concurrently. + */ int nfc_target_lost(struct nfc_dev *dev, u32 target_idx) { struct nfc_target *tg; @@ -544,7 +559,7 @@ int nfc_target_lost(struct nfc_dev *dev, u32 target_idx) pr_debug("dev_name %s n_target %d\n", dev_name(&dev->dev), target_idx); - spin_lock_bh(&dev->targets_lock); + device_lock(&dev->dev); for (i = 0; i < dev->n_targets; i++) { tg = &dev->targets[i]; @@ -553,7 +568,7 @@ int nfc_target_lost(struct nfc_dev *dev, u32 target_idx) } if (i == dev->n_targets) { - spin_unlock_bh(&dev->targets_lock); + device_unlock(&dev->dev); return -EINVAL; } @@ -569,7 +584,7 @@ int nfc_target_lost(struct nfc_dev *dev, u32 target_idx) dev->targets = NULL; } - spin_unlock_bh(&dev->targets_lock); + device_unlock(&dev->dev); nfc_genl_target_lost(dev, target_idx); @@ -607,8 +622,10 @@ static void nfc_check_pres_work(struct work_struct *work) mod_timer(&dev->check_pres_timer, jiffies + msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS)); } else { - nfc_target_lost(dev, dev->active_target->idx); - dev->active_target = NULL; + u32 active_target_idx = dev->active_target->idx; + device_unlock(&dev->dev); + nfc_target_lost(dev, active_target_idx); + return; } } @@ -681,9 +698,9 @@ struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops, dev->tx_headroom = tx_headroom; dev->tx_tailroom = tx_tailroom; - spin_lock_init(&dev->targets_lock); nfc_genl_data_init(&dev->genl_data); + /* first generation must not be 0 */ dev->targets_generation = 1; diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c index f1829f6ae9c5..77dae74832d3 100644 --- a/net/nfc/netlink.c +++ b/net/nfc/netlink.c @@ -128,7 +128,7 @@ static int nfc_genl_dump_targets(struct sk_buff *skb, cb->args[1] = (long) dev; } - spin_lock_bh(&dev->targets_lock); + device_lock(&dev->dev); cb->seq = dev->targets_generation; @@ -141,7 +141,7 @@ static int nfc_genl_dump_targets(struct sk_buff *skb, i++; } - spin_unlock_bh(&dev->targets_lock); + device_unlock(&dev->dev); cb->args[0] = i; -- cgit v1.2.3 From 1676f75159c8091e865c33b61ad4934dfd3b7821 Mon Sep 17 00:00:00 2001 From: Eric Lapuyade Date: Mon, 7 May 2012 12:31:16 +0200 Subject: NFC: Add HCI/SHDLC support to let driver check for tag presence Signed-off-by: Eric Lapuyade Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- include/net/nfc/hci.h | 2 ++ include/net/nfc/shdlc.h | 2 ++ net/nfc/hci/core.c | 12 ++++++++++++ net/nfc/hci/shdlc.c | 12 ++++++++++++ 4 files changed, 28 insertions(+) (limited to 'net') diff --git a/include/net/nfc/hci.h b/include/net/nfc/hci.h index 95fc0c27578e..ae042008571e 100644 --- a/include/net/nfc/hci.h +++ b/include/net/nfc/hci.h @@ -39,6 +39,8 @@ struct nfc_hci_ops { int (*data_exchange) (struct nfc_hci_dev *hdev, struct nfc_target *target, struct sk_buff *skb, struct sk_buff **res_skb); + int (*check_presence)(struct nfc_hci_dev *hdev, + struct nfc_target *target); }; #define NFC_HCI_MAX_CUSTOM_GATES 15 diff --git a/include/net/nfc/shdlc.h b/include/net/nfc/shdlc.h index 1071987d0408..ab06afd462da 100644 --- a/include/net/nfc/shdlc.h +++ b/include/net/nfc/shdlc.h @@ -35,6 +35,8 @@ struct nfc_shdlc_ops { int (*data_exchange) (struct nfc_shdlc *shdlc, struct nfc_target *target, struct sk_buff *skb, struct sk_buff **res_skb); + int (*check_presence)(struct nfc_shdlc *shdlc, + struct nfc_target *target); }; enum shdlc_state { diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c index ef5cd5c9e3fb..f7e4f5ae4559 100644 --- a/net/nfc/hci/core.c +++ b/net/nfc/hci/core.c @@ -574,6 +574,17 @@ static int hci_data_exchange(struct nfc_dev *nfc_dev, struct nfc_target *target, return 0; } +static int hci_check_presence(struct nfc_dev *nfc_dev, + struct nfc_target *target) +{ + struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); + + if (hdev->ops->check_presence) + return hdev->ops->check_presence(hdev, target); + + return 0; +} + struct nfc_ops hci_nfc_ops = { .dev_up = hci_dev_up, .dev_down = hci_dev_down, @@ -582,6 +593,7 @@ struct nfc_ops hci_nfc_ops = { .activate_target = hci_activate_target, .deactivate_target = hci_deactivate_target, .data_exchange = hci_data_exchange, + .check_presence = hci_check_presence, }; struct nfc_hci_dev *nfc_hci_allocate_device(struct nfc_hci_ops *ops, diff --git a/net/nfc/hci/shdlc.c b/net/nfc/hci/shdlc.c index 923bdf7c26d6..5665dc6d893a 100644 --- a/net/nfc/hci/shdlc.c +++ b/net/nfc/hci/shdlc.c @@ -816,6 +816,17 @@ static int nfc_shdlc_data_exchange(struct nfc_hci_dev *hdev, return -EPERM; } +static int nfc_shdlc_check_presence(struct nfc_hci_dev *hdev, + struct nfc_target *target) +{ + struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev); + + if (shdlc->ops->check_presence) + return shdlc->ops->check_presence(shdlc, target); + + return 0; +} + static struct nfc_hci_ops shdlc_ops = { .open = nfc_shdlc_open, .close = nfc_shdlc_close, @@ -825,6 +836,7 @@ static struct nfc_hci_ops shdlc_ops = { .target_from_gate = nfc_shdlc_target_from_gate, .complete_target_discovered = nfc_shdlc_complete_target_discovered, .data_exchange = nfc_shdlc_data_exchange, + .check_presence = nfc_shdlc_check_presence, }; struct nfc_shdlc *nfc_shdlc_allocate(struct nfc_shdlc_ops *ops, -- cgit v1.2.3 From ff353d86a92ee709e18fa485423dbaa7a52af8f3 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Mon, 7 May 2012 12:31:19 +0200 Subject: NFC: LLCP connect must wait for a CC frame Blocking sockets should sleep on a CC (Connection Complete) reception from the connect() call. Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- net/nfc/llcp/llcp.c | 7 +++++++ net/nfc/llcp/sock.c | 42 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 48 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c index 92988aa620dc..42994fac26d6 100644 --- a/net/nfc/llcp/llcp.c +++ b/net/nfc/llcp/llcp.c @@ -448,6 +448,8 @@ static struct nfc_llcp_sock *nfc_llcp_sock_get(struct nfc_llcp_local *local, { struct nfc_llcp_sock *sock, *llcp_sock, *n; + pr_debug("ssap dsap %d %d\n", ssap, dsap); + if (ssap == 0 && dsap == 0) return NULL; @@ -783,6 +785,7 @@ static void nfc_llcp_recv_disc(struct nfc_llcp_local *local, static void nfc_llcp_recv_cc(struct nfc_llcp_local *local, struct sk_buff *skb) { struct nfc_llcp_sock *llcp_sock; + struct sock *sk; u8 dsap, ssap; dsap = nfc_llcp_dsap(skb); @@ -801,10 +804,14 @@ static void nfc_llcp_recv_cc(struct nfc_llcp_local *local, struct sk_buff *skb) } llcp_sock->dsap = ssap; + sk = &llcp_sock->sk; nfc_llcp_parse_tlv(local, &skb->data[LLCP_HEADER_SIZE], skb->len - LLCP_HEADER_SIZE); + sk->sk_state = LLCP_CONNECTED; + sk->sk_state_change(sk); + nfc_llcp_sock_put(llcp_sock); } diff --git a/net/nfc/llcp/sock.c b/net/nfc/llcp/sock.c index c13e02ebdef9..99196d3b84eb 100644 --- a/net/nfc/llcp/sock.c +++ b/net/nfc/llcp/sock.c @@ -27,6 +27,42 @@ #include "../nfc.h" #include "llcp.h" +static int sock_wait_state(struct sock *sk, int state, unsigned long timeo) +{ + DECLARE_WAITQUEUE(wait, current); + int err = 0; + + pr_debug("sk %p", sk); + + add_wait_queue(sk_sleep(sk), &wait); + set_current_state(TASK_INTERRUPTIBLE); + + while (sk->sk_state != state) { + if (!timeo) { + err = -EINPROGRESS; + break; + } + + if (signal_pending(current)) { + err = sock_intr_errno(timeo); + break; + } + + release_sock(sk); + timeo = schedule_timeout(timeo); + lock_sock(sk); + set_current_state(TASK_INTERRUPTIBLE); + + err = sock_error(sk); + if (err) + break; + } + + __set_current_state(TASK_RUNNING); + remove_wait_queue(sk_sleep(sk), &wait); + return err; +} + static struct proto llcp_sock_proto = { .name = "NFC_LLCP", .owner = THIS_MODULE, @@ -462,9 +498,13 @@ static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr, if (ret) goto put_dev; - sk->sk_state = LLCP_CONNECTED; + ret = sock_wait_state(sk, LLCP_CONNECTED, + sock_sndtimeo(sk, flags & O_NONBLOCK)); + if (ret) + goto put_dev; release_sock(sk); + return 0; put_dev: -- cgit v1.2.3 From 4260c13ba9102d466f017139de990dfffaf4d997 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Mon, 7 May 2012 12:31:20 +0200 Subject: NFC: Update the LLCP poll mask Fix the poll mask depending on the socket state. POLLOUT was missing for example. Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- net/nfc/llcp/sock.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/nfc/llcp/sock.c b/net/nfc/llcp/sock.c index 99196d3b84eb..3f339b19d140 100644 --- a/net/nfc/llcp/sock.c +++ b/net/nfc/llcp/sock.c @@ -340,11 +340,24 @@ static unsigned int llcp_sock_poll(struct file *file, struct socket *sock, mask |= POLLERR; if (!skb_queue_empty(&sk->sk_receive_queue)) - mask |= POLLIN; + mask |= POLLIN | POLLRDNORM; if (sk->sk_state == LLCP_CLOSED) mask |= POLLHUP; + if (sk->sk_shutdown & RCV_SHUTDOWN) + mask |= POLLRDHUP | POLLIN | POLLRDNORM; + + if (sk->sk_shutdown == SHUTDOWN_MASK) + mask |= POLLHUP; + + if (sock_writeable(sk)) + mask |= POLLOUT | POLLWRNORM | POLLWRBAND; + else + set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); + + pr_debug("mask 0x%x\n", mask); + return mask; } -- cgit v1.2.3 From 43472fffb4628773397297f7e365983accd4a0ef Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Mon, 7 May 2012 12:31:21 +0200 Subject: NFC: Return the amount of LLCP bytes queued to sock_sendmsg Otherwise an LLCP send() always returns 0. Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- net/nfc/llcp/commands.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/nfc/llcp/commands.c b/net/nfc/llcp/commands.c index 11a3b7d98dc5..c4c100dc52ee 100644 --- a/net/nfc/llcp/commands.c +++ b/net/nfc/llcp/commands.c @@ -502,7 +502,7 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock, kfree(msg_data); - return 0; + return len; } int nfc_llcp_send_rr(struct nfc_llcp_sock *sock) -- cgit v1.2.3 From 51c25be857156493247d17c371d01735dc9b8658 Mon Sep 17 00:00:00 2001 From: joseph daniel Date: Mon, 7 May 2012 12:31:23 +0200 Subject: NFC: Fix LLCP compilation warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit nfc_llcp_general_bytes is defined in nfc/core.c as: nfc_llcp_general_bytes(struct nfc_dev *dev, size_t *gb_len). as in nfc/nfc.h: nfc_llcp_general_bytes(struct nfc_dev *dev, u8 *gb_len), if CONFIG_NFC_LLCP is not defined. so we got some warnings, net/nfc/core.c:207:2: warning: passing argument 2 of ‘nfc_llcp_general_bytes’ from incompatible pointer type [enabled by default] net/nfc/nfc.h:87:19: note: expected ‘u8 *’ but argument is of type ‘size_t *’ Signed-off-by: joseph daniel Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- net/nfc/nfc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/nfc/nfc.h b/net/nfc/nfc.h index 7d589a81942e..3dd4232ae664 100644 --- a/net/nfc/nfc.h +++ b/net/nfc/nfc.h @@ -84,7 +84,7 @@ static inline int nfc_llcp_set_remote_gb(struct nfc_dev *dev, return 0; } -static inline u8 *nfc_llcp_general_bytes(struct nfc_dev *dev, u8 *gb_len) +static inline u8 *nfc_llcp_general_bytes(struct nfc_dev *dev, size_t *gb_len) { *gb_len = 0; return NULL; -- cgit v1.2.3 From 040487f364e03fc4d9fcab5549618642cc3f6fe7 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Mon, 7 May 2012 12:31:24 +0200 Subject: NFC: Quiet nci/data.c sparse noise about plain integer as NULL pointer Pointers should be cleared with NULL, not 0. Quiets a couple sparse warnings of the type: warning: Using plain integer as NULL pointer Signed-off-by: H Hartley Sweeten Cc: Lauro Ramos Venancio Cc: Aloisio Almeida Jr Cc: Samuel Ortiz Cc: "David S. Miller" Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- net/nfc/nci/data.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/nfc/nci/data.c b/net/nfc/nci/data.c index a0bc326308a5..76c48c5324f8 100644 --- a/net/nfc/nci/data.c +++ b/net/nfc/nci/data.c @@ -49,7 +49,7 @@ void nci_data_exchange_complete(struct nci_dev *ndev, struct sk_buff *skb, if (cb) { ndev->data_exchange_cb = NULL; - ndev->data_exchange_cb_context = 0; + ndev->data_exchange_cb_context = NULL; /* forward skb to nfc core */ cb(cb_context, skb, err); @@ -200,10 +200,10 @@ static void nci_add_rx_data_frag(struct nci_dev *ndev, pr_err("error adding room for accumulated rx data\n"); kfree_skb(skb); - skb = 0; + skb = NULL; kfree_skb(ndev->rx_data_reassembly); - ndev->rx_data_reassembly = 0; + ndev->rx_data_reassembly = NULL; err = -ENOMEM; goto exit; @@ -216,7 +216,7 @@ static void nci_add_rx_data_frag(struct nci_dev *ndev, /* third, free old reassembly */ kfree_skb(ndev->rx_data_reassembly); - ndev->rx_data_reassembly = 0; + ndev->rx_data_reassembly = NULL; } if (pbf == NCI_PBF_CONT) { -- cgit v1.2.3 From 502b42408276431605ceaea5dc026a256acc310e Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Mon, 7 May 2012 12:31:25 +0200 Subject: NFC: Include nci_core.h to nci/lib.c Include the header to pickup the exported symbol prototype. Quites the sparse warning: warning: symbol 'nci_to_errno' was not declared. Should it be static? Signed-off-by: H Hartley Sweeten Cc: Lauro Ramos Venancio Cc: Aloisio Almeida Jr CC: Samuel Ortiz CC: "David S. Miller" Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- net/nfc/nci/lib.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/nfc/nci/lib.c b/net/nfc/nci/lib.c index 6a63e5eb483d..6b7fd26c68d9 100644 --- a/net/nfc/nci/lib.c +++ b/net/nfc/nci/lib.c @@ -31,6 +31,7 @@ #include #include +#include /* NCI status codes to Unix errno mapping */ int nci_to_errno(__u8 code) -- cgit v1.2.3 From 799030b75a4398b4e75ca5cb5ec790dc75986111 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Mon, 7 May 2012 12:31:26 +0200 Subject: NFC: Quiet nci/ntf.c sparse noise about plain integer as NULL pointer Pointers should be cleared with NULL, not 0. Quiets a couple sparse warnings of the type: warning: Using plain integer as NULL pointer Signed-off-by: H Hartley Sweeten Cc: Lauro Ramos Venancio Cc: Aloisio Almeida Jr Cc: Samuel Ortiz Cc: "David S. Miller" Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- net/nfc/nci/ntf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/nfc/nci/ntf.c b/net/nfc/nci/ntf.c index 99e1632e6aac..cb2646179e5f 100644 --- a/net/nfc/nci/ntf.c +++ b/net/nfc/nci/ntf.c @@ -497,7 +497,7 @@ static void nci_rf_deactivate_ntf_packet(struct nci_dev *ndev, /* drop partial rx data packet */ if (ndev->rx_data_reassembly) { kfree_skb(ndev->rx_data_reassembly); - ndev->rx_data_reassembly = 0; + ndev->rx_data_reassembly = NULL; } /* complete the data exchange transaction, if exists */ -- cgit v1.2.3 From bd007bea21f3a51fc67cbcec412725b2d86f1b27 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Mon, 7 May 2012 12:31:27 +0200 Subject: NFC: HCI ops should not be exposed globally The variable 'hci_nfc_ops' is only referenced in this file and should be marked static to prevent it from being exposed globally. Quites the sparse warning: warning: symbol 'hci_nfc_ops' was not declared. Should it be static? Signed-off-by: H Hartley Sweeten Cc: Lauro Ramos Venancio Cc: Aloisio Almeida Jr Cc: Samuel Ortiz Cc: "David S. Miller" Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- net/nfc/hci/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c index f7e4f5ae4559..0fdb96f152b1 100644 --- a/net/nfc/hci/core.c +++ b/net/nfc/hci/core.c @@ -585,7 +585,7 @@ static int hci_check_presence(struct nfc_dev *nfc_dev, return 0; } -struct nfc_ops hci_nfc_ops = { +static struct nfc_ops hci_nfc_ops = { .dev_up = hci_dev_up, .dev_down = hci_dev_down, .start_poll = hci_start_poll, -- cgit v1.2.3 From e5fe4cf8ee2bf15c0f44f9eba06147cdddbddf6d Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Mon, 7 May 2012 12:31:28 +0200 Subject: NFC: The NFC genl family structure should not be exposed globally The variable 'nfc_genl_family' is only referenced in this file and should be marked static to prevent it from being exposed globally. Quites the sparse warning: warning: symbol 'nfc_genl_family' was not declared. Should it be static? Signed-off-by: H Hartley Sweeten Cc: Lauro Ramos Venancio Cc: Aloisio Almeida Jr Cc: Samuel Ortiz Cc: "David S. Miller" Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- net/nfc/netlink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c index 77dae74832d3..581d419083aa 100644 --- a/net/nfc/netlink.c +++ b/net/nfc/netlink.c @@ -33,7 +33,7 @@ static struct genl_multicast_group nfc_genl_event_mcgrp = { .name = NFC_GENL_MCAST_EVENT_NAME, }; -struct genl_family nfc_genl_family = { +static struct genl_family nfc_genl_family = { .id = GENL_ID_GENERATE, .hdrsize = 0, .name = NFC_GENL_NAME, -- cgit v1.2.3 From 03bed29e0501b5757ce62ebdb01829f7bd8d9819 Mon Sep 17 00:00:00 2001 From: Eric Lapuyade Date: Mon, 7 May 2012 12:31:31 +0200 Subject: NFC: HCI drivers don't have to keep track of polling state The NFC core code already does that for them. Signed-off-by: Eric Lapuyade Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- include/net/nfc/hci.h | 2 -- net/nfc/hci/core.c | 21 ++++----------------- 2 files changed, 4 insertions(+), 19 deletions(-) (limited to 'net') diff --git a/include/net/nfc/hci.h b/include/net/nfc/hci.h index ae042008571e..4467c9460857 100644 --- a/include/net/nfc/hci.h +++ b/include/net/nfc/hci.h @@ -84,8 +84,6 @@ struct nfc_hci_dev { u8 gate2pipe[NFC_HCI_MAX_GATES]; - bool poll_started; - u8 sw_romlib; u8 sw_patch; u8 sw_flashlib_major; diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c index 0fdb96f152b1..e1a640d2b588 100644 --- a/net/nfc/hci/core.c +++ b/net/nfc/hci/core.c @@ -251,11 +251,6 @@ void nfc_hci_event_received(struct nfc_hci_dev *hdev, u8 pipe, u8 event, switch (event) { case NFC_HCI_EVT_TARGET_DISCOVERED: - if (hdev->poll_started == false) { - r = -EPROTO; - goto exit; - } - if (skb->len < 1) { /* no status data? */ r = -EPROTO; goto exit; @@ -489,28 +484,20 @@ static int hci_dev_down(struct nfc_dev *nfc_dev) static int hci_start_poll(struct nfc_dev *nfc_dev, u32 protocols) { struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); - int r; if (hdev->ops->start_poll) - r = hdev->ops->start_poll(hdev, protocols); + return hdev->ops->start_poll(hdev, protocols); else - r = nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE, + return nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE, NFC_HCI_EVT_READER_REQUESTED, NULL, 0); - if (r == 0) - hdev->poll_started = true; - - return r; } static void hci_stop_poll(struct nfc_dev *nfc_dev) { struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); - if (hdev->poll_started) { - nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE, - NFC_HCI_EVT_END_OPERATION, NULL, 0); - hdev->poll_started = false; - } + nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE, + NFC_HCI_EVT_END_OPERATION, NULL, 0); } static int hci_activate_target(struct nfc_dev *nfc_dev, -- cgit v1.2.3 From d34c34fb2592bd5231a153ad1676c3ded175410a Mon Sep 17 00:00:00 2001 From: Mat Martineau Date: Mon, 14 May 2012 14:49:27 -0700 Subject: Bluetooth: Initialize the transmit queue for L2CAP streaming mode Commit 105bdf9ec19e729bacdb33861c74fcf3eb39eb37 introduced a regression in L2CAP streaming mode due to rearranged initialization code that is shared between ERTM and streaming mode. This change makes sure the transmit queue is initialized in both modes. Signed-off-by: Mat Martineau Acked-by: Andrei Emeltchenko Signed-off-by: Gustavo Padovan --- net/bluetooth/l2cap_core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 869beb30f480..7adfcecf7a5e 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -2349,6 +2349,8 @@ static inline int l2cap_ertm_init(struct l2cap_chan *chan) chan->sdu_last_frag = NULL; chan->sdu_len = 0; + skb_queue_head_init(&chan->tx_q); + if (chan->mode != L2CAP_MODE_ERTM) return 0; @@ -2360,7 +2362,6 @@ static inline int l2cap_ertm_init(struct l2cap_chan *chan) INIT_DELAYED_WORK(&chan->ack_timer, l2cap_ack_timeout); skb_queue_head_init(&chan->srej_q); - skb_queue_head_init(&chan->tx_q); INIT_LIST_HEAD(&chan->srej_l); err = l2cap_seq_list_init(&chan->srej_list, chan->tx_win); -- cgit v1.2.3 From a9d3c05cca51d80ef2b9eddabf794c9458e36c2c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 7 May 2012 17:45:29 +0200 Subject: mac80211: fix single queue drivers My queue management rework broke drivers that don't have multiple AC queues and register a single queue only, causing a warning: WARNING: at net/mac80211/iface.c:162 ieee80211_check_queues This was due to filling the queues wrongly and then noticing the error when checking later. Reported-and-Tested-by: Larry Finger Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/iface.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 3e05a8bfddf0..c550945dd703 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -206,8 +206,10 @@ static void ieee80211_set_default_queues(struct ieee80211_sub_if_data *sdata) for (i = 0; i < IEEE80211_NUM_ACS; i++) { if (local->hw.flags & IEEE80211_HW_QUEUE_CONTROL) sdata->vif.hw_queue[i] = IEEE80211_INVAL_HW_QUEUE; - else + else if (local->hw.queues >= IEEE80211_NUM_ACS) sdata->vif.hw_queue[i] = i; + else + sdata->vif.hw_queue[i] = 0; } sdata->vif.cab_queue = IEEE80211_INVAL_HW_QUEUE; } -- cgit v1.2.3 From 9e73dee7d38e9fa00f6dd1492cfbbc5719378e4a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 7 May 2012 17:57:36 +0200 Subject: mac80211: fix TX aggregation session timer In commit 12d3952fc4a1cd96234bc7023bf7eefeb0bb6355 ("mac80211: optimize aggregation session timeout handling") two bugs were introduced: 1) RCU usage was completely broken since no locks are held 2) the timer must not rearm when agg session is stopping Reported-and-tested-by: Larry Finger Cc: Felix Fietkau Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/agg-tx.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 5b7053c58732..7cf07158805c 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -421,16 +421,22 @@ static void sta_tx_agg_session_timer_expired(unsigned long data) struct tid_ampdu_tx *tid_tx; unsigned long timeout; - tid_tx = rcu_dereference_protected_tid_tx(sta, *ptid); - if (!tid_tx) + rcu_read_lock(); + tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[*ptid]); + if (!tid_tx || test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) { + rcu_read_unlock(); return; + } timeout = tid_tx->last_tx + TU_TO_JIFFIES(tid_tx->timeout); if (time_is_after_jiffies(timeout)) { mod_timer(&tid_tx->session_timer, timeout); + rcu_read_unlock(); return; } + rcu_read_unlock(); + #ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "tx session timer expired on tid %d\n", (u16)*ptid); #endif -- cgit v1.2.3 From c4f6084623726857ac7c55922aefe138bd77292e Mon Sep 17 00:00:00 2001 From: Cristian Chilipirea Date: Tue, 8 May 2012 12:38:53 +0300 Subject: Net: wireless: core.c: fixed checkpatch warnings Fixed some checkpatch warnings. Signed-off-by: Cristian Chilipirea Signed-off-by: John W. Linville --- net/wireless/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/wireless/core.c b/net/wireless/core.c index 39f2538a46fc..a87d43552974 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -664,7 +664,7 @@ void wiphy_unregister(struct wiphy *wiphy) mutex_lock(&rdev->devlist_mtx); __count = rdev->opencount; mutex_unlock(&rdev->devlist_mtx); - __count == 0;})); + __count == 0; })); mutex_lock(&rdev->devlist_mtx); BUG_ON(!list_empty(&rdev->netdev_list)); @@ -776,7 +776,7 @@ static struct device_type wiphy_type = { .name = "wlan", }; -static int cfg80211_netdev_notifier_call(struct notifier_block * nb, +static int cfg80211_netdev_notifier_call(struct notifier_block *nb, unsigned long state, void *ndev) { -- cgit v1.2.3 From 4472037be86a9d7d1cab37e0c4cb310997a140ae Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 8 May 2012 21:23:54 +0200 Subject: cfg80211: remove double prototype cfg80211_calculate_bitrate() is defined in the external header file cfg80211.h now, so no need to keep it in the internal one as well. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/core.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'net') diff --git a/net/wireless/core.h b/net/wireless/core.h index 3ac2dd00d714..8523f3878677 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -445,8 +445,6 @@ int cfg80211_set_freq(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev, int freq, enum nl80211_channel_type channel_type); -u16 cfg80211_calculate_bitrate(struct rate_info *rate); - int ieee80211_get_ratemask(struct ieee80211_supported_band *sband, const u8 *rates, unsigned int n_rates, u32 *mask); -- cgit v1.2.3 From 2615f3759b7b7d47a2fa894bc9f45286bdf122d7 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 8 May 2012 21:36:20 +0200 Subject: cfg80211: add warning when calculating MCS rates >= 32 cfg80211_calculate_bitrate() doesn't work for MCS rates 32 or higher, and it has always returned 0 in that case. Warn if it ever really happens. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/wireless/util.c b/net/wireless/util.c index 6cba00173a2f..177df03064cf 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -880,7 +880,7 @@ u16 cfg80211_calculate_bitrate(struct rate_info *rate) return rate->legacy; /* the formula below does only work for MCS values smaller than 32 */ - if (rate->mcs >= 32) + if (WARN_ON_ONCE(rate->mcs >= 32)) return 0; modulation = rate->mcs & 7; -- cgit v1.2.3 From ee70108fa2a7688dc67bfedaeb0c8c46a221effb Mon Sep 17 00:00:00 2001 From: "Janusz.Dziedzic@tieto.com" Date: Wed, 9 May 2012 08:11:20 +0300 Subject: mac80211: Add IV-room in the skb for TKIP and WEP Add IV-room in skb also for TKIP and WEP. Extend patch: "mac80211: support adding IV-room in the skb for CCMP keys" Signed-off-by: Janusz Dziedzic Acked-by: Johannes Berg Signed-off-by: John W. Linville --- include/net/mac80211.h | 2 +- net/mac80211/wep.c | 14 +++++++++++--- net/mac80211/wpa.c | 8 +++++++- 3 files changed, 19 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 4d6e6c6818d0..60e3766d3739 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -939,7 +939,7 @@ static inline bool ieee80211_vif_is_mesh(struct ieee80211_vif *vif) * CCMP key if it requires CCMP encryption of management frames (MFP) to * be done in software. * @IEEE80211_KEY_FLAG_PUT_IV_SPACE: This flag should be set by the driver - * for a CCMP key if space should be prepared for the IV, but the IV + * if space should be prepared for the IV, but the IV * itself should not be generated. Do not set together with * @IEEE80211_KEY_FLAG_GENERATE_IV on the same key. */ diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c index 7aa31bbfaa3b..e904401684da 100644 --- a/net/mac80211/wep.c +++ b/net/mac80211/wep.c @@ -92,6 +92,7 @@ static u8 *ieee80211_wep_add_iv(struct ieee80211_local *local, int keylen, int keyidx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); unsigned int hdrlen; u8 *newhdr; @@ -104,6 +105,12 @@ static u8 *ieee80211_wep_add_iv(struct ieee80211_local *local, hdrlen = ieee80211_hdrlen(hdr->frame_control); newhdr = skb_push(skb, WEP_IV_LEN); memmove(newhdr, newhdr + WEP_IV_LEN, hdrlen); + + /* the HW only needs room for the IV, but not the actual IV */ + if (info->control.hw_key && + (info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) + return newhdr + hdrlen; + ieee80211_wep_get_iv(local, keylen, keyidx, newhdr + hdrlen); return newhdr + hdrlen; } @@ -313,14 +320,15 @@ ieee80211_crypto_wep_decrypt(struct ieee80211_rx_data *rx) static int wep_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_key_conf *hw_key = info->control.hw_key; - if (!info->control.hw_key) { + if (!hw_key) { if (ieee80211_wep_encrypt(tx->local, skb, tx->key->conf.key, tx->key->conf.keylen, tx->key->conf.keyidx)) return -1; - } else if (info->control.hw_key->flags & - IEEE80211_KEY_FLAG_GENERATE_IV) { + } else if ((hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV) || + (hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) { if (!ieee80211_wep_add_iv(tx->local, skb, tx->key->conf.keylen, tx->key->conf.keyidx)) diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 0ae23c60968c..4d05ad9403ae 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -183,7 +183,8 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) u8 *pos; if (info->control.hw_key && - !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV)) { + !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV) && + !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) { /* hwaccel - with no need for software-generated IV */ return 0; } @@ -204,6 +205,11 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) memmove(pos, pos + TKIP_IV_LEN, hdrlen); pos += hdrlen; + /* the HW only needs room for the IV, but not the actual IV */ + if (info->control.hw_key && + (info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) + return 0; + /* Increase IV for the frame */ spin_lock_irqsave(&key->u.tkip.txlock, flags); key->u.tkip.tx.iv16++; -- cgit v1.2.3 From ac55d2fe0576d272c4a98ed9dfb87b1cca29486e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 10 May 2012 09:09:10 +0200 Subject: mac80211: (selectively) add HT details in radiotap Add a flag for the HT format (mixed vs. greenfield) to allow drivers to report that on receive. Not all drivers will do that though, so allow drivers to set which radiotap MCS details they report. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- include/net/mac80211.h | 10 ++++++++++ net/mac80211/main.c | 3 +++ net/mac80211/rx.c | 6 +++--- 3 files changed, 16 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 60e3766d3739..1937c7d98304 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -667,6 +667,9 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info) * @RX_FLAG_SHORT_GI: Short guard interval was used * @RX_FLAG_NO_SIGNAL_VAL: The signal strength value is not present. * Valid only for data frames (mainly A-MPDU) + * @RX_FLAG_HT_GF: This frame was received in a HT-greenfield transmission, if + * the driver fills this value it should add %IEEE80211_RADIOTAP_MCS_HAVE_FMT + * to hw.radiotap_mcs_details to advertise that fact */ enum mac80211_rx_flags { RX_FLAG_MMIC_ERROR = 1<<0, @@ -681,6 +684,7 @@ enum mac80211_rx_flags { RX_FLAG_40MHZ = 1<<10, RX_FLAG_SHORT_GI = 1<<11, RX_FLAG_NO_SIGNAL_VAL = 1<<12, + RX_FLAG_HT_GF = 1<<13, }; /** @@ -1288,6 +1292,11 @@ enum ieee80211_hw_flags { * * @offchannel_tx_hw_queue: HW queue ID to use for offchannel TX * (if %IEEE80211_HW_QUEUE_CONTROL is set) + * + * @radiotap_mcs_details: lists which MCS information can the HW + * reports, by default it is set to _MCS, _GI and _BW but doesn't + * include _FMT. Use %IEEE80211_RADIOTAP_MCS_HAVE_* values, only + * adding _BW is supported today. */ struct ieee80211_hw { struct ieee80211_conf conf; @@ -1309,6 +1318,7 @@ struct ieee80211_hw { u8 max_rx_aggregation_subframes; u8 max_tx_aggregation_subframes; u8 offchannel_tx_hw_queue; + u8 radiotap_mcs_details; }; /** diff --git a/net/mac80211/main.c b/net/mac80211/main.c index b70f7f09da61..f5548e953259 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -596,6 +596,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, local->hw.offchannel_tx_hw_queue = IEEE80211_INVAL_HW_QUEUE; local->hw.conf.long_frame_max_tx_count = wiphy->retry_long; local->hw.conf.short_frame_max_tx_count = wiphy->retry_short; + local->hw.radiotap_mcs_details = IEEE80211_RADIOTAP_MCS_HAVE_MCS | + IEEE80211_RADIOTAP_MCS_HAVE_GI | + IEEE80211_RADIOTAP_MCS_HAVE_BW; local->user_power_level = -1; wiphy->ht_capa_mod_mask = &mac80211_ht_capa_mod_mask; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index d5ac02fe37ff..489093b08a4a 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -204,14 +204,14 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, if (status->flag & RX_FLAG_HT) { rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_MCS); - *pos++ = IEEE80211_RADIOTAP_MCS_HAVE_MCS | - IEEE80211_RADIOTAP_MCS_HAVE_GI | - IEEE80211_RADIOTAP_MCS_HAVE_BW; + *pos++ = local->hw.radiotap_mcs_details; *pos = 0; if (status->flag & RX_FLAG_SHORT_GI) *pos |= IEEE80211_RADIOTAP_MCS_SGI; if (status->flag & RX_FLAG_40MHZ) *pos |= IEEE80211_RADIOTAP_MCS_BW_40; + if (status->flag & RX_FLAG_HT_GF) + *pos |= IEEE80211_RADIOTAP_MCS_FMT_GF; pos++; *pos++ = status->rate_idx; } -- cgit v1.2.3 From 7863157d83763a0f1b9ad96c94a1ed3d0372526a Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Thu, 10 May 2012 13:21:09 +0300 Subject: mac80211: fix network header location when adding encryption headers Update the location of the network header when adding encryption specific headers to a skb. This allows low-level drivers to use the (now correct) location of the network header. Signed-off-by: Arik Nemtsov Signed-off-by: John W. Linville --- net/mac80211/wep.c | 1 + net/mac80211/wpa.c | 2 ++ 2 files changed, 3 insertions(+) (limited to 'net') diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c index e904401684da..c04d401dae92 100644 --- a/net/mac80211/wep.c +++ b/net/mac80211/wep.c @@ -111,6 +111,7 @@ static u8 *ieee80211_wep_add_iv(struct ieee80211_local *local, (info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) return newhdr + hdrlen; + skb_set_network_header(skb, skb_network_offset(skb) + WEP_IV_LEN); ieee80211_wep_get_iv(local, keylen, keyidx, newhdr + hdrlen); return newhdr + hdrlen; } diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 4d05ad9403ae..bdb53aba888e 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -203,6 +203,7 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) pos = skb_push(skb, TKIP_IV_LEN); memmove(pos, pos + TKIP_IV_LEN, hdrlen); + skb_set_network_header(skb, skb_network_offset(skb) + TKIP_IV_LEN); pos += hdrlen; /* the HW only needs room for the IV, but not the actual IV */ @@ -428,6 +429,7 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) pos = skb_push(skb, CCMP_HDR_LEN); memmove(pos, pos + CCMP_HDR_LEN, hdrlen); + skb_set_network_header(skb, skb_network_offset(skb) + CCMP_HDR_LEN); /* the HW only needs room for the IV, but not the actual IV */ if (info->control.hw_key && -- cgit v1.2.3 From bdbc59b35f2a66cdd9465f573f865cc2109ab33d Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Thu, 10 May 2012 19:45:52 +0200 Subject: NFC: Queue I frame fragments to the LLCP sockets queue tail After testing our stack with large SNEP messages, we realized the fragments were arriving in reversed order. Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- net/nfc/llcp/commands.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/nfc/llcp/commands.c b/net/nfc/llcp/commands.c index c4c100dc52ee..bf8ae4f0b90c 100644 --- a/net/nfc/llcp/commands.c +++ b/net/nfc/llcp/commands.c @@ -488,7 +488,7 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock, memcpy(skb_put(pdu, frag_len), msg_ptr, frag_len); - skb_queue_head(&sock->tx_queue, pdu); + skb_queue_tail(&sock->tx_queue, pdu); lock_sock(sk); -- cgit v1.2.3 From 3383b5a69de59eeef2501834c6e0960b7e2bff28 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 10 May 2012 20:14:43 +0200 Subject: nl80211: prevent additions to old station flags API We don't really want/need to maintain the old station flags API any more, so refuse changes to new (not yet defined) flags from the old flags API. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- include/linux/nl80211.h | 2 ++ net/wireless/nl80211.c | 10 ++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index f296a64d103b..a6959f72745e 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -1594,6 +1594,8 @@ enum nl80211_sta_flags { NL80211_STA_FLAG_MAX = __NL80211_STA_FLAG_AFTER_LAST - 1 }; +#define NL80211_STA_FLAG_MAX_OLD_API NL80211_STA_FLAG_TDLS_PEER + /** * struct nl80211_sta_flag_update - station flags mask/set * @mask: mask of station flags to set diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index b67b1114e25a..f1b0774d098b 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -2410,10 +2410,16 @@ static int parse_station_flags(struct genl_info *info, return -EINVAL; } - for (flag = 1; flag <= NL80211_STA_FLAG_MAX; flag++) - if (flags[flag]) + for (flag = 1; flag <= NL80211_STA_FLAG_MAX; flag++) { + if (flags[flag]) { params->sta_flags_set |= (1< NL80211_STA_FLAG_MAX_OLD_API) + return -EINVAL; + } + } + return 0; } -- cgit v1.2.3 From 294a20e039a5125b0e88b96e0ee47065ff4e07a5 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 10 May 2012 21:25:23 +0200 Subject: cfg80211: fix cfg80211_can_beacon_sec_chan prototype It should return bool, not int. The function even does return true/false. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- include/net/cfg80211.h | 6 +++--- net/wireless/chan.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index adb2320bccdf..0289d4ce7070 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -3365,9 +3365,9 @@ void cfg80211_report_obss_beacon(struct wiphy *wiphy, * @chan: main channel * @channel_type: HT mode */ -int cfg80211_can_beacon_sec_chan(struct wiphy *wiphy, - struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type); +bool cfg80211_can_beacon_sec_chan(struct wiphy *wiphy, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type); /* * cfg80211_ch_switch_notify - update wdev channel and notify userspace diff --git a/net/wireless/chan.c b/net/wireless/chan.c index 2fcfe0993ca2..884801ac4dd0 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c @@ -45,7 +45,7 @@ rdev_freq_to_chan(struct cfg80211_registered_device *rdev, return chan; } -int cfg80211_can_beacon_sec_chan(struct wiphy *wiphy, +bool cfg80211_can_beacon_sec_chan(struct wiphy *wiphy, struct ieee80211_channel *chan, enum nl80211_channel_type channel_type) { -- cgit v1.2.3 From cd6c65981e72aef9f5cc42ffe64404542162790a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 10 May 2012 21:27:18 +0200 Subject: nl80211: refactor valid channel type check There are four instances in nl80211 of getting the channel type from the attribute and validating it, refactor those. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/nl80211.c | 59 +++++++++++++++++++++++++------------------------- 1 file changed, 29 insertions(+), 30 deletions(-) (limited to 'net') diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index f1b0774d098b..206465dc0cab 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -1179,6 +1179,27 @@ static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev) wdev->iftype == NL80211_IFTYPE_P2P_GO; } +static bool nl80211_valid_channel_type(struct genl_info *info, + enum nl80211_channel_type *channel_type) +{ + enum nl80211_channel_type tmp; + + if (!info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) + return false; + + tmp = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]); + if (tmp != NL80211_CHAN_NO_HT && + tmp != NL80211_CHAN_HT20 && + tmp != NL80211_CHAN_HT40PLUS && + tmp != NL80211_CHAN_HT40MINUS) + return false; + + if (channel_type) + *channel_type = tmp; + + return true; +} + static int __nl80211_set_channel(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev, struct genl_info *info) @@ -1193,15 +1214,9 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev, if (!nl80211_can_set_dev_channel(wdev)) return -EOPNOTSUPP; - if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { - channel_type = nla_get_u32(info->attrs[ - NL80211_ATTR_WIPHY_CHANNEL_TYPE]); - if (channel_type != NL80211_CHAN_NO_HT && - channel_type != NL80211_CHAN_HT20 && - channel_type != NL80211_CHAN_HT40PLUS && - channel_type != NL80211_CHAN_HT40MINUS) - return -EINVAL; - } + if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] && + !nl80211_valid_channel_type(info, &channel_type)) + return -EINVAL; freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); @@ -4918,12 +4933,7 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { enum nl80211_channel_type channel_type; - channel_type = nla_get_u32( - info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]); - if (channel_type != NL80211_CHAN_NO_HT && - channel_type != NL80211_CHAN_HT20 && - channel_type != NL80211_CHAN_HT40MINUS && - channel_type != NL80211_CHAN_HT40PLUS) + if (!nl80211_valid_channel_type(info, &channel_type)) return -EINVAL; if (channel_type != NL80211_CHAN_NO_HT && @@ -5491,15 +5501,9 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, !(rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL)) return -EOPNOTSUPP; - if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { - channel_type = nla_get_u32( - info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]); - if (channel_type != NL80211_CHAN_NO_HT && - channel_type != NL80211_CHAN_HT20 && - channel_type != NL80211_CHAN_HT40PLUS && - channel_type != NL80211_CHAN_HT40MINUS) - return -EINVAL; - } + if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] && + !nl80211_valid_channel_type(info, &channel_type)) + return -EINVAL; freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); chan = rdev_freq_to_chan(rdev, freq, channel_type); @@ -5770,12 +5774,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) } if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { - channel_type = nla_get_u32( - info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]); - if (channel_type != NL80211_CHAN_NO_HT && - channel_type != NL80211_CHAN_HT20 && - channel_type != NL80211_CHAN_HT40PLUS && - channel_type != NL80211_CHAN_HT40MINUS) + if (!nl80211_valid_channel_type(info, &channel_type)) return -EINVAL; channel_type_valid = true; } -- cgit v1.2.3 From 0d894ec5017f7f463254e24fd2206e41d13cadff Mon Sep 17 00:00:00 2001 From: Ashok Nagarajan Date: Mon, 7 May 2012 21:00:29 -0700 Subject: mac80211: Push the deleted comment to correct place This comment is deleted in the patch "mac80211: Advertise HT protection mode in IEs". Moving the comment to the now corrected place. Signed-off-by: Ashok Nagarajan Signed-off-by: John W. Linville --- net/mac80211/ibss.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'net') diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index bb1a3e62a66a..11ac1ffd9570 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -163,6 +163,11 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, sizeof(struct ieee80211_ht_operation)); pos = ieee80211_ie_build_ht_cap(pos, &sband->ht_cap, sband->ht_cap.cap); + /* + * Note: According to 802.11n-2009 9.13.3.1, HT Protection + * field and RIFS Mode are reserved in IBSS mode, therefore + * keep them at 0 + */ pos = ieee80211_ie_build_ht_oper(pos, &sband->ht_cap, chan, channel_type, 0); } -- cgit v1.2.3 From 0e482db8d3713ad3a64a56e0dfe4fdf698fe7c1d Mon Sep 17 00:00:00 2001 From: Ashok Nagarajan Date: Mon, 7 May 2012 21:00:30 -0700 Subject: mac80211: Fix don't use '>' operator for matching channel types Johannes pointed out that the use of > operators for checking channel type mismatch maynot be correct way as we may add other channel types in future. Signed-off-by: Ashok Nagarajan Signed-off-by: John W. Linville --- net/mac80211/mesh.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 0a21e4e55f43..d3a9a6c081e7 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -109,8 +109,10 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata, /* Disallow HT40+/- mismatch */ if (ie->ht_operation && - local->_oper_channel_type > NL80211_CHAN_HT20 && - sta_channel_type > NL80211_CHAN_HT20 && + (local->_oper_channel_type == NL80211_CHAN_HT40MINUS || + local->_oper_channel_type == NL80211_CHAN_HT40PLUS) && + (sta_channel_type == NL80211_CHAN_HT40MINUS || + sta_channel_type == NL80211_CHAN_HT40PLUS) && local->_oper_channel_type != sta_channel_type) goto mismatch; -- cgit v1.2.3 From cbf9322eb1bb493b63aafffd010ab1a44c4ced5c Mon Sep 17 00:00:00 2001 From: Ashok Nagarajan Date: Mon, 7 May 2012 21:00:31 -0700 Subject: mac80211: Modify mesh_set_ht_prot_mode() to have less identation Determining types of peers is modified to have less indentation. This change is suggested by Johannes. This patch also corrects the reference in comment to IEEE 802.11-2012 version. Signed-off-by: Ashok Nagarajan Signed-off-by: John W. Linville --- net/mac80211/mesh_plink.c | 47 ++++++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 23 deletions(-) (limited to 'net') diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index ae026acec874..60ef235c9d9b 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -105,15 +105,15 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata, return sta; } -/** mesh_set_ht_prot_mode - set correct HT protection mode +/* + * mesh_set_ht_prot_mode - set correct HT protection mode * - * Section 9.23.3.5 of IEEE 80211s standard describes the protection rules for - * HT mesh STA in a MBSS. Three HT protection modes are supported for now, - * non-HT mixed mode, 20MHz-protection and no-protection mode. non-HT mixed - * mode is selected if any non-HT peers are present in our MBSS. - * 20MHz-protection mode is selected if all peers in our 20/40MHz MBSS support - * HT and atleast one HT20 peer is present. Otherwise no-protection mode is - * selected. + * Section 9.23.3.5 of IEEE 80211-2012 describes the protection rules for HT + * mesh STA in a MBSS. Three HT protection modes are supported for now, non-HT + * mixed mode, 20MHz-protection and no-protection mode. non-HT mixed mode is + * selected if any non-HT peers are present in our MBSS. 20MHz-protection mode + * is selected if all peers in our 20/40MHz MBSS support HT and atleast one + * HT20 peer is present. Otherwise no-protection mode is selected. */ static u32 mesh_set_ht_prot_mode(struct ieee80211_sub_if_data *sdata) { @@ -128,21 +128,22 @@ static u32 mesh_set_ht_prot_mode(struct ieee80211_sub_if_data *sdata) rcu_read_lock(); list_for_each_entry_rcu(sta, &local->sta_list, list) { - if (sdata == sta->sdata && - sta->plink_state == NL80211_PLINK_ESTAB) { - switch (sta->ch_type) { - case NL80211_CHAN_NO_HT: - mpl_dbg("mesh_plink %pM: nonHT sta (%pM) is present", - sdata->vif.addr, sta->sta.addr); - non_ht_sta = true; - goto out; - case NL80211_CHAN_HT20: - mpl_dbg("mesh_plink %pM: HT20 sta (%pM) is present", - sdata->vif.addr, sta->sta.addr); - ht20_sta = true; - default: - break; - } + if (sdata != sta->sdata || + sta->plink_state != NL80211_PLINK_ESTAB) + continue; + + switch (sta->ch_type) { + case NL80211_CHAN_NO_HT: + mpl_dbg("mesh_plink %pM: nonHT sta (%pM) is present", + sdata->vif.addr, sta->sta.addr); + non_ht_sta = true; + goto out; + case NL80211_CHAN_HT20: + mpl_dbg("mesh_plink %pM: HT20 sta (%pM) is present", + sdata->vif.addr, sta->sta.addr); + ht20_sta = true; + default: + break; } } out: -- cgit v1.2.3 From 4416f5d2ac986923fcb6e42419c8a048dfda7584 Mon Sep 17 00:00:00 2001 From: Ashok Nagarajan Date: Mon, 7 May 2012 21:00:32 -0700 Subject: mac80211: Add debugfs entry for mesh ht_opmode Signed-off-by: Ashok Nagarajan Signed-off-by: John W. Linville --- net/mac80211/debugfs_netdev.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net') diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index ea0122dbd2b3..7ed433c66d68 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -509,6 +509,7 @@ IEEE80211_IF_FILE(dot11MeshHWMPRannInterval, u.mesh.mshcfg.dot11MeshHWMPRannInterval, DEC); IEEE80211_IF_FILE(dot11MeshForwarding, u.mesh.mshcfg.dot11MeshForwarding, DEC); IEEE80211_IF_FILE(rssi_threshold, u.mesh.mshcfg.rssi_threshold, DEC); +IEEE80211_IF_FILE(ht_opmode, u.mesh.mshcfg.ht_opmode, DEC); #endif #define DEBUGFS_ADD_MODE(name, mode) \ @@ -608,6 +609,7 @@ static void add_mesh_config(struct ieee80211_sub_if_data *sdata) MESHPARAMS_ADD(dot11MeshHWMPRannInterval); MESHPARAMS_ADD(dot11MeshGateAnnouncementProtocol); MESHPARAMS_ADD(rssi_threshold); + MESHPARAMS_ADD(ht_opmode); #undef MESHPARAMS_ADD } #endif -- cgit v1.2.3 From fbe0070092c3968927c63ab56c00b47c6aa3770f Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Tue, 15 May 2012 13:22:55 -0300 Subject: Bluetooth: Fix wrong set of skb fragments If alloc() fails we let the frags linked list with garbage value (the err ptr value) in its last element. Reported-by: Mat Martineau Signed-off-by: Gustavo Padovan Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 3714c9656459..339f8344ee59 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1836,13 +1836,17 @@ static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan, /* Continuation fragments (no L2CAP header) */ frag = &skb_shinfo(skb)->frag_list; while (len) { + struct sk_buff *tmp; + count = min_t(unsigned int, conn->mtu, len); - *frag = chan->ops->alloc_skb(chan, count, - msg->msg_flags & MSG_DONTWAIT); + tmp = chan->ops->alloc_skb(chan, count, + msg->msg_flags & MSG_DONTWAIT); + if (IS_ERR(tmp)) + return PTR_ERR(tmp); + + *frag = tmp; - if (IS_ERR(*frag)) - return PTR_ERR(*frag); if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count)) return -EFAULT; -- cgit v1.2.3 From 087bfd99f75c5f7d5430e7e122c2f288f03d6c23 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Fri, 11 May 2012 13:16:11 -0300 Subject: Bluetooth: Fix packet size provided to the controller When building fragmented skb's skb->len keeps track of the size of head plus all fragments combined, however when queueing the skb for sending we need to report the head size instead of the total size, so we just set skb->len to skb_headlen(). This bug appeared when implementing MSG_MORE support for L2CAP sockets, it never showed up before because l2cap_skbuff_fromiovec() never accounted skb size correctly. A following patch will fix this. Signed-off-by: Gustavo Padovan Reviewed-by: Mat Martineau Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index a8962382f9c5..411ace8e647b 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2162,6 +2162,12 @@ static void hci_queue_acl(struct hci_conn *conn, struct sk_buff_head *queue, struct hci_dev *hdev = conn->hdev; struct sk_buff *list; + skb->len = skb_headlen(skb); + skb->data_len = 0; + + bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT; + hci_add_acl_hdr(skb, conn->handle, flags); + list = skb_shinfo(skb)->frag_list; if (!list) { /* Non fragmented */ @@ -2205,8 +2211,6 @@ void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags) BT_DBG("%s chan %p flags 0x%x", hdev->name, chan, flags); skb->dev = (void *) hdev; - bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT; - hci_add_acl_hdr(skb, conn->handle, flags); hci_queue_acl(conn, &chan->data_q, skb, flags); -- cgit v1.2.3 From 2d0ed3d5879edae4bf1c98eb3163466c30d41789 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Fri, 11 May 2012 13:16:12 -0300 Subject: Bluetooth: Fix skb length calculation When we add a fragment to a skb, len and data_len fields need to be updated. Signed-off-by: Gustavo Padovan Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 339f8344ee59..b3907a3b5236 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1855,6 +1855,9 @@ static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan, sent += count; len -= count; + skb->len += (*frag)->len; + skb->data_len += (*frag)->len; + frag = &(*frag)->next; } -- cgit v1.2.3 From f522ae363d5f20de172ea6f9973ba4cc44801f2b Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Wed, 9 May 2012 18:28:00 -0300 Subject: Bluetooth: improve readability of l2cap_seq_list code Removes one indentation level. Signed-off-by: Gustavo Padovan Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_core.c | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index b3907a3b5236..1e12d6d58e84 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -310,14 +310,16 @@ static inline u16 l2cap_seq_list_pop(struct l2cap_seq_list *seq_list) 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; + u16 i; - seq_list->head = L2CAP_SEQ_LIST_CLEAR; - seq_list->tail = L2CAP_SEQ_LIST_CLEAR; - } + if (seq_list->head == L2CAP_SEQ_LIST_CLEAR) + return; + + 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) @@ -326,15 +328,16 @@ static void l2cap_seq_list_append(struct l2cap_seq_list *seq_list, u16 seq) /* 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; + if (seq_list->list[seq & mask] != L2CAP_SEQ_LIST_CLEAR) + return; - seq_list->tail = seq; - seq_list->list[seq & mask] = L2CAP_SEQ_LIST_TAIL; - } + 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) -- cgit v1.2.3 From a24299e6c82f624cd2c717c91f04f1d79113ada8 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 26 Apr 2012 09:47:46 +0300 Subject: Bluetooth: Fix Inquiry with RSSI event mask The right bit for "Inquiry with RSSI" is 0x02 and not 0x04 (which means "Read Remote Extended Features Complete"). Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 4edbfd929f6e..fac840afd131 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -520,7 +520,7 @@ static void hci_setup_event_mask(struct hci_dev *hdev) events[5] |= 0x10; /* Synchronous Connection Changed */ if (hdev->features[3] & LMP_RSSI_INQ) - events[4] |= 0x04; /* Inquiry Result with RSSI */ + events[4] |= 0x02; /* Inquiry Result with RSSI */ if (hdev->features[5] & LMP_SNIFF_SUBR) events[5] |= 0x20; /* Sniff Subrating */ -- cgit v1.2.3 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 'net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index b60d2c844eba..9fc7728f94e4 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 fac840afd131..9c60e0d8db5f 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 From 35c84d76ee52f49fe2635d8cd686b5b658e8d892 Mon Sep 17 00:00:00 2001 From: Mat Martineau Date: Wed, 2 May 2012 09:41:59 -0700 Subject: Bluetooth: Fix a redundant and problematic incoming MTU check The L2CAP MTU for incoming data is verified differently depending on the L2CAP mode, so the check is best performed in a mode-specific context. Checking the incoming MTU before HCI fragment reassembly is a layer violation and assumes all bytes after the standard L2CAP header are L2CAP data. This approach causes issues with unsegmented ERTM or streaming mode frames, where there are additional enhanced or extended headers before the data payload and possible FCS bytes after the data payload. A valid frame could be as many as 10 bytes larger than the MTU. Removing this code is the best fix, because the MTU is checked later on for all L2CAP data frames (connectionless, basic, ERTM, and streaming). This also gets rid of outdated locking (socket instead of l2cap_chan) and an extra lookup of the channel ID. Signed-off-by: Mat Martineau Reviewed-by: Ulisses Furquim Signed-off-by: Gustavo Padovan --- net/bluetooth/l2cap_core.c | 20 -------------------- 1 file changed, 20 deletions(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 1e12d6d58e84..aea54f55c41d 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -5000,8 +5000,6 @@ int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags) if (!(flags & ACL_CONT)) { struct l2cap_hdr *hdr; - struct l2cap_chan *chan; - u16 cid; int len; if (conn->rx_len) { @@ -5021,7 +5019,6 @@ int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags) hdr = (struct l2cap_hdr *) skb->data; len = __le16_to_cpu(hdr->len) + L2CAP_HDR_SIZE; - cid = __le16_to_cpu(hdr->cid); if (len == skb->len) { /* Complete frame received */ @@ -5038,23 +5035,6 @@ int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags) goto drop; } - chan = l2cap_get_chan_by_scid(conn, cid); - - if (chan && chan->sk) { - struct sock *sk = chan->sk; - lock_sock(sk); - - if (chan->imtu < len - L2CAP_HDR_SIZE) { - BT_ERR("Frame exceeding recv MTU (len %d, " - "MTU %d)", len, - chan->imtu); - release_sock(sk); - l2cap_conn_unreliable(conn, ECOMM); - goto drop; - } - release_sock(sk); - } - /* Allocate skb for the complete frame (with header) */ conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC); if (!conn->rx_skb) -- cgit v1.2.3 From ef191aded58c5e6860b01f463818584a420a4d6b Mon Sep 17 00:00:00 2001 From: Mat Martineau Date: Wed, 2 May 2012 09:42:00 -0700 Subject: Bluetooth: Restore locking semantics when looking up L2CAP channels As the comment for l2cap_get_chan_by_scid indicated, the function used to return a locked socket. The lock for the socket was acquired while the channel list was also locked. When locking was moved over to the l2cap_chan structure, the channel lock was no longer acquired with the channel list still locked. This made it possible for the l2cap_chan to be deleted after conn->chan_lock was released but before l2cap_chan_lock was called. Making the call to l2cap_chan_lock before releasing conn->chan_lock makes it impossible for the l2cap_chan to be deleted at the wrong time. Signed-off-by: Mat Martineau Reviewed-by: Ulisses Furquim Signed-off-by: Gustavo Padovan --- net/bluetooth/l2cap_core.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index aea54f55c41d..285c5e13c7d5 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -98,13 +98,15 @@ static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 } /* Find channel with given SCID. - * Returns locked socket */ + * Returns locked channel. */ static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid) { struct l2cap_chan *c; mutex_lock(&conn->chan_lock); c = __l2cap_get_chan_by_scid(conn, cid); + if (c) + l2cap_chan_lock(c); mutex_unlock(&conn->chan_lock); return c; @@ -3183,8 +3185,6 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr if (!chan) return -ENOENT; - l2cap_chan_lock(chan); - if (chan->state != BT_CONFIG && chan->state != BT_CONNECT2) { struct l2cap_cmd_rej_cid rej; @@ -3297,8 +3297,6 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr if (!chan) return 0; - l2cap_chan_lock(chan); - switch (result) { case L2CAP_CONF_SUCCESS: l2cap_conf_rfc_get(chan, rsp->data, len); @@ -4631,8 +4629,6 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk return 0; } - l2cap_chan_lock(chan); - BT_DBG("chan %p, len %d", chan, skb->len); if (chan->state != BT_CONNECTED) -- cgit v1.2.3 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 'net') diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index c34a9a6184a1..7981ca48b83a 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 b7bc7b981ee2..f6d8e13197d6 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 From c6585a4da0c709a7a9f59aab68869298b52ca1e1 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Mon, 7 May 2012 03:07:26 -0300 Subject: Bluetooth: report the right security level in getsockopt During a security level elevation we need to keep track of the current security level of a connection until the new one is not confirmed. Signed-off-by: Gustavo Padovan Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/l2cap_sock.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index f6d8e13197d6..f52d58e05d02 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -379,7 +379,10 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch } memset(&sec, 0, sizeof(sec)); - sec.level = chan->sec_level; + if (chan->conn) + sec.level = chan->conn->hcon->sec_level; + else + sec.level = chan->sec_level; if (sk->sk_state == BT_CONNECTED) sec.key_size = chan->conn->hcon->enc_key_size; -- cgit v1.2.3 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 'net') diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 7981ca48b83a..961669b648fd 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 6fb68a9743af..46e7f86acfc9 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 285c5e13c7d5..24f144b72a96 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 f52d58e05d02..3bb1611b9d48 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 a55a43e9f70e..e8707debb864 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 From d839c81372d1f0caee47f87b26a68e91d4ff3847 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Wed, 16 May 2012 12:17:12 -0300 Subject: Bluetooth: Report proper error number in disconnection If encryption change fails we should disconnect with auth failure error code. Signed-off-by: Gustavo Padovan Signed-off-by: Johan Hedberg --- net/bluetooth/hci_event.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 9c60e0d8db5f..4eefb7f65cf6 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2063,7 +2063,7 @@ 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_acl_disconn(conn, HCI_ERROR_AUTH_FAILURE); hci_conn_put(conn); goto unlock; } -- cgit v1.2.3