From 84c61d92bb6e9048eecc0738a83f1bf66f053026 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 1 Aug 2014 11:13:30 +0300 Subject: [PATCH 01/48] Bluetooth: Add convenience function to check for pending power off There are several situations where we're interested in knowing whether we're currently in the process of powering off an adapter. This patch adds a convenience function for the purpose and makes it public since we'll soon need to access it from hci_event.c as well. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/mgmt.c | 52 +++++++++++++++++--------------- 2 files changed, 29 insertions(+), 24 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index b5d5af3aa469..8394abc4fd87 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1351,6 +1351,7 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, s8 rssi, u8 *name, u8 name_len); void mgmt_discovering(struct hci_dev *hdev, u8 discovering); +bool mgmt_powering_down(struct hci_dev *hdev); void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent); void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk); void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk, diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index b8554d429d88..c9de0d9945f5 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -6281,25 +6281,35 @@ static void unpair_device_rsp(struct pending_cmd *cmd, void *data) mgmt_pending_remove(cmd); } +bool mgmt_powering_down(struct hci_dev *hdev) +{ + struct pending_cmd *cmd; + struct mgmt_mode *cp; + + cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev); + if (!cmd) + return false; + + cp = cmd->param; + if (!cp->val) + return true; + + return false; +} + void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, u8 reason, bool mgmt_connected) { struct mgmt_ev_device_disconnected ev; - struct pending_cmd *power_off; struct sock *sk = NULL; - power_off = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev); - if (power_off) { - struct mgmt_mode *cp = power_off->param; - - /* The connection is still in hci_conn_hash so test for 1 - * instead of 0 to know if this is the last one. - */ - if (!cp->val && hci_conn_count(hdev) == 1) { - cancel_delayed_work(&hdev->power_off); - queue_work(hdev->req_workqueue, &hdev->power_off.work); - } + /* The connection is still in hci_conn_hash so test for 1 + * instead of 0 to know if this is the last one. + */ + if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) { + cancel_delayed_work(&hdev->power_off); + queue_work(hdev->req_workqueue, &hdev->power_off.work); } if (!mgmt_connected) @@ -6359,19 +6369,13 @@ void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, u8 status) { struct mgmt_ev_connect_failed ev; - struct pending_cmd *power_off; - power_off = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev); - if (power_off) { - struct mgmt_mode *cp = power_off->param; - - /* The connection is still in hci_conn_hash so test for 1 - * instead of 0 to know if this is the last one. - */ - if (!cp->val && hci_conn_count(hdev) == 1) { - cancel_delayed_work(&hdev->power_off); - queue_work(hdev->req_workqueue, &hdev->power_off.work); - } + /* The connection is still in hci_conn_hash so test for 1 + * instead of 0 to know if this is the last one. + */ + if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) { + cancel_delayed_work(&hdev->power_off); + queue_work(hdev->req_workqueue, &hdev->power_off.work); } bacpy(&ev.addr.bdaddr, bdaddr); From 432df05eb1e57adfc46df08abbedca6c3b8862f7 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 1 Aug 2014 11:13:31 +0300 Subject: [PATCH 02/48] Bluetooth: Create unified helper function for updating page scan Similar to our hci_update_background_scan() function we can simplify a lot of code by creating a unified helper function for doing page scan updates. This patch adds such a function to hci_core.c and updates all the relevant places to use it. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 5 +++ net/bluetooth/hci_core.c | 31 ++++++++++++++ net/bluetooth/mgmt.c | 72 ++++++-------------------------- 3 files changed, 48 insertions(+), 60 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 8394abc4fd87..cc2eb7730fbc 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -968,6 +968,9 @@ void hci_conn_del_sysfs(struct hci_conn *conn); #define lmp_host_le_capable(dev) (!!((dev)->features[1][0] & LMP_HOST_LE)) #define lmp_host_le_br_capable(dev) (!!((dev)->features[1][0] & LMP_HOST_LE_BREDR)) +#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \ + !test_bit(HCI_AUTO_OFF, &hdev->dev_flags)) + /* ----- HCI protocols ----- */ #define HCI_PROTO_DEFER 0x01 @@ -1256,6 +1259,8 @@ bool hci_req_pending(struct hci_dev *hdev); void hci_req_add_le_scan_disable(struct hci_request *req); void hci_req_add_le_passive_scan(struct hci_request *req); +void hci_update_page_scan(struct hci_dev *hdev, struct hci_request *req); + struct sk_buff *__hci_cmd_sync(struct hci_dev *hdev, u16 opcode, u32 plen, const void *param, u32 timeout); struct sk_buff *__hci_cmd_sync_ev(struct hci_dev *hdev, u16 opcode, u32 plen, diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index c32d361c0cf7..a031589598b2 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -5680,3 +5680,34 @@ void hci_update_background_scan(struct hci_dev *hdev) if (err) BT_ERR("Failed to run HCI request: err %d", err); } + +void hci_update_page_scan(struct hci_dev *hdev, struct hci_request *req) +{ + u8 scan; + + if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) + return; + + if (!hdev_is_powered(hdev)) + return; + + if (mgmt_powering_down(hdev)) + return; + + if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags) || + !list_empty(&hdev->whitelist)) + scan = SCAN_PAGE; + else + scan = SCAN_DISABLED; + + if (test_bit(HCI_PSCAN, &hdev->flags) == !!(scan & SCAN_PAGE)) + return; + + if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) + scan |= SCAN_INQUIRY; + + if (req) + hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); + else + hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); +} diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index c9de0d9945f5..c2457435a670 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -129,9 +129,6 @@ static const u16 mgmt_events[] = { #define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000) -#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \ - !test_bit(HCI_AUTO_OFF, &hdev->dev_flags)) - struct pending_cmd { struct list_head list; u16 opcode; @@ -1536,9 +1533,11 @@ static void set_discoverable_complete(struct hci_dev *hdev, u8 status) /* When the discoverable mode gets changed, make sure * that class of device has the limited discoverable - * bit correctly set. + * bit correctly set. Also update page scan based on whitelist + * entries. */ hci_req_init(&req, hdev); + hci_update_page_scan(hdev, &req); update_class(&req); hci_req_run(&req, NULL); @@ -1785,6 +1784,7 @@ static void set_connectable_complete(struct hci_dev *hdev, u8 status) if (conn_changed || discov_changed) { new_settings(hdev, cmd->sk); + hci_update_page_scan(hdev, NULL); if (discov_changed) mgmt_update_adv_data(hdev); hci_update_background_scan(hdev); @@ -1818,6 +1818,7 @@ static int set_connectable_update_settings(struct hci_dev *hdev, return err; if (changed) { + hci_update_page_scan(hdev, NULL); hci_update_background_scan(hdev); return new_settings(hdev, sk); } @@ -4381,27 +4382,6 @@ unlock: return err; } -static void set_bredr_scan(struct hci_request *req) -{ - struct hci_dev *hdev = req->hdev; - u8 scan = 0; - - /* Ensure that fast connectable is disabled. This function will - * not do anything if the page scan parameters are already what - * they should be. - */ - write_fast_connectable(req, false); - - if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags) || - !list_empty(&hdev->whitelist)) - scan |= SCAN_PAGE; - if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) - scan |= SCAN_INQUIRY; - - if (scan) - hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); -} - static void set_bredr_complete(struct hci_dev *hdev, u8 status) { struct pending_cmd *cmd; @@ -4507,9 +4487,8 @@ static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) hci_req_init(&req, hdev); - if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags) || - !list_empty(&hdev->whitelist)) - set_bredr_scan(&req); + write_fast_connectable(&req, false); + hci_update_page_scan(hdev, &req); /* Since only the advertising data flags will change, there * is no need to update the scan response data. @@ -5235,27 +5214,6 @@ unlock: return err; } -/* Helper for Add/Remove Device commands */ -static void update_page_scan(struct hci_dev *hdev, u8 scan) -{ - if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) - return; - - if (!hdev_is_powered(hdev)) - return; - - /* If HCI_CONNECTABLE is set then Add/Remove Device should not - * make any changes to page scanning. - */ - if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) - return; - - if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) - scan |= SCAN_INQUIRY; - - hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); -} - static void device_added(struct sock *sk, struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type, u8 action) { @@ -5291,8 +5249,6 @@ static int add_device(struct sock *sk, struct hci_dev *hdev, hci_dev_lock(hdev); if (cp->addr.type == BDADDR_BREDR) { - bool update_scan; - /* Only incoming connections action is supported for now */ if (cp->action != 0x01) { err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE, @@ -5301,15 +5257,12 @@ static int add_device(struct sock *sk, struct hci_dev *hdev, goto unlock; } - update_scan = list_empty(&hdev->whitelist); - err = hci_bdaddr_list_add(&hdev->whitelist, &cp->addr.bdaddr, cp->addr.type); if (err) goto unlock; - if (update_scan) - update_page_scan(hdev, SCAN_PAGE); + hci_update_page_scan(hdev, NULL); goto added; } @@ -5392,8 +5345,7 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev, goto unlock; } - if (list_empty(&hdev->whitelist)) - update_page_scan(hdev, SCAN_DISABLED); + hci_update_page_scan(hdev, NULL); device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type); @@ -5444,7 +5396,7 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev, kfree(b); } - update_page_scan(hdev, SCAN_DISABLED); + hci_update_page_scan(hdev, NULL); list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) { if (p->auto_connect == HCI_AUTO_CONN_DISABLED) @@ -5969,8 +5921,8 @@ static int powered_update_hci(struct hci_dev *hdev) sizeof(link_sec), &link_sec); if (lmp_bredr_capable(hdev)) { - if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) - set_bredr_scan(&req); + write_fast_connectable(&req, false); + hci_update_page_scan(hdev, &req); update_class(&req); update_name(&req); update_eir(&req); From 22f433dcf7c71cf075e4c42b5f36ea4352978a6d Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 1 Aug 2014 11:13:32 +0300 Subject: [PATCH 03/48] Bluetooth: Disable page scan if all whitelisted devices are connected When we're not connectable and all whitelisted (BR/EDR) devices are connected it doesn't make sense to keep page scan enabled. This patch adds code to check for any disconnected whitelist devices and if there are none take the appropriate action in the hci_update_page_scan() function to disable page scan. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 20 +++++++++++++++++++- net/bluetooth/hci_event.c | 11 ++++++++--- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index a031589598b2..217ef83fb541 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -5681,6 +5681,24 @@ void hci_update_background_scan(struct hci_dev *hdev) BT_ERR("Failed to run HCI request: err %d", err); } +static bool disconnected_whitelist_entries(struct hci_dev *hdev) +{ + struct bdaddr_list *b; + + list_for_each_entry(b, &hdev->whitelist, list) { + struct hci_conn *conn; + + conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &b->bdaddr); + if (!conn) + return true; + + if (conn->state != BT_CONNECTED && conn->state != BT_CONFIG) + return true; + } + + return false; +} + void hci_update_page_scan(struct hci_dev *hdev, struct hci_request *req) { u8 scan; @@ -5695,7 +5713,7 @@ void hci_update_page_scan(struct hci_dev *hdev, struct hci_request *req) return; if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags) || - !list_empty(&hdev->whitelist)) + disconnected_whitelist_entries(hdev)) scan = SCAN_PAGE; else scan = SCAN_DISABLED; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index be35598984d9..da7ab6b9bb69 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2071,6 +2071,8 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) cp.handle = ev->handle; hci_send_cmd(hdev, HCI_OP_READ_REMOTE_FEATURES, sizeof(cp), &cp); + + hci_update_page_scan(hdev, NULL); } /* Set packet type for incoming connection */ @@ -2247,9 +2249,12 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) mgmt_device_disconnected(hdev, &conn->dst, conn->type, conn->dst_type, reason, mgmt_connected); - if (conn->type == ACL_LINK && - test_bit(HCI_CONN_FLUSH_KEY, &conn->flags)) - hci_remove_link_key(hdev, &conn->dst); + if (conn->type == ACL_LINK) { + if (test_bit(HCI_CONN_FLUSH_KEY, &conn->flags)) + hci_remove_link_key(hdev, &conn->dst); + + hci_update_page_scan(hdev, NULL); + } params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type); if (params) { From 5fcb93475697911eb239f68241903eb5540803ac Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 7 Aug 2014 10:03:31 +0300 Subject: [PATCH 04/48] Bluetooth: Remove redundant check for remote_key_dist In the smp_cmd_sign_info() function the SMP_DIST_SIGN bit is explicitly cleared early on in the function. This means that there's no need to check for it again before calling smp_distribute_keys(). Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index fd3294300803..40db728f044b 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -1168,8 +1168,7 @@ static int smp_cmd_sign_info(struct l2cap_conn *conn, struct sk_buff *skb) memcpy(csrk->val, rp->csrk, sizeof(csrk->val)); } smp->csrk = csrk; - if (!(smp->remote_key_dist & SMP_DIST_SIGN)) - smp_distribute_keys(conn); + smp_distribute_keys(conn); hci_dev_unlock(hdev); return 0; From 2b29349044cc2cf74d4c6e23e26cd27977d91353 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 7 Aug 2014 10:03:32 +0300 Subject: [PATCH 05/48] Bluetooth: Fix confusion between parent and child channel for 6lowpan The new_connection L2CAP channel callback creates a new channel based on the provided parent channel. The 6lowpan code was confusingly naming the child channel "pchan" and the parent channel "chan". This patch swaps the names. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/6lowpan.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c index 206b65ccd5b8..35ebe79c87b0 100644 --- a/net/bluetooth/6lowpan.c +++ b/net/bluetooth/6lowpan.c @@ -772,16 +772,16 @@ static inline void chan_ready_cb(struct l2cap_chan *chan) ifup(dev->netdev); } -static inline struct l2cap_chan *chan_new_conn_cb(struct l2cap_chan *chan) +static inline struct l2cap_chan *chan_new_conn_cb(struct l2cap_chan *pchan) { - struct l2cap_chan *pchan; + struct l2cap_chan *chan; - pchan = chan_open(chan); - pchan->ops = chan->ops; + chan = chan_open(pchan); + chan->ops = pchan->ops; BT_DBG("chan %p pchan %p", chan, pchan); - return pchan; + return chan; } static void delete_netdev(struct work_struct *work) From a24cce144b9814a17f46006dbad6056f1f5f481e Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 7 Aug 2014 22:56:42 +0300 Subject: [PATCH 06/48] Bluetooth: Fix reference counting of global L2CAP channels When looking up entries from the global L2CAP channel list there needs to be a guarantee that other code doesn't go and remove the entry after a channel has been returned by the lookup function. This patch makes sure that the channel reference is incremented before the read lock is released in the global channel lookup functions. The patch also adds the corresponding l2cap_chan_put() calls once the channels pointers are no-longer needed. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 46547b920f88..a47a14efd5aa 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1440,6 +1440,7 @@ static struct l2cap_chan *l2cap_global_chan_by_scid(int state, u16 cid, src_match = !bacmp(&c->src, src); dst_match = !bacmp(&c->dst, dst); if (src_match && dst_match) { + l2cap_chan_hold(c); read_unlock(&chan_list_lock); return c; } @@ -1453,6 +1454,9 @@ static struct l2cap_chan *l2cap_global_chan_by_scid(int state, u16 cid, } } + if (c1) + l2cap_chan_hold(c1); + read_unlock(&chan_list_lock); return c1; @@ -1475,13 +1479,13 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) /* Client ATT sockets should override the server one */ if (__l2cap_get_chan_by_dcid(conn, L2CAP_CID_ATT)) - return; + goto put; dst_type = bdaddr_type(hcon, hcon->dst_type); /* If device is blocked, do not create a channel for it */ if (hci_bdaddr_list_lookup(&hdev->blacklist, &hcon->dst, dst_type)) - return; + goto put; /* For LE slave connections, make sure the connection interval * is in the range of the minium and maximum interval that has @@ -1517,6 +1521,8 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) clean: l2cap_chan_unlock(pchan); +put: + l2cap_chan_put(pchan); } static void l2cap_conn_ready(struct l2cap_conn *conn) @@ -1794,6 +1800,7 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, src_match = !bacmp(&c->src, src); dst_match = !bacmp(&c->dst, dst); if (src_match && dst_match) { + l2cap_chan_hold(c); read_unlock(&chan_list_lock); return c; } @@ -1807,6 +1814,9 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, } } + if (c1) + l2cap_chan_hold(c1); + read_unlock(&chan_list_lock); return c1; @@ -3884,6 +3894,7 @@ static struct l2cap_chan *l2cap_connect(struct l2cap_conn *conn, response: l2cap_chan_unlock(pchan); mutex_unlock(&conn->chan_lock); + l2cap_chan_put(pchan); sendresp: rsp.scid = cpu_to_le16(scid); @@ -5497,6 +5508,7 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn, response_unlock: l2cap_chan_unlock(pchan); mutex_unlock(&conn->chan_lock); + l2cap_chan_put(pchan); if (result == L2CAP_CR_PEND) return 0; @@ -6845,12 +6857,12 @@ static void l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, struct l2cap_chan *chan; if (hcon->type != ACL_LINK) - goto drop; + goto free_skb; chan = l2cap_global_chan_by_psm(0, psm, &hcon->src, &hcon->dst, ACL_LINK); if (!chan) - goto drop; + goto free_skb; BT_DBG("chan %p, len %d", chan, skb->len); @@ -6864,10 +6876,14 @@ static void l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, bacpy(&bt_cb(skb)->bdaddr, &hcon->dst); bt_cb(skb)->psm = psm; - if (!chan->ops->recv(chan, skb)) + if (!chan->ops->recv(chan, skb)) { + l2cap_chan_put(chan); return; + } drop: + l2cap_chan_put(chan); +free_skb: kfree_skb(skb); } @@ -6878,22 +6894,26 @@ static void l2cap_att_channel(struct l2cap_conn *conn, struct l2cap_chan *chan; if (hcon->type != LE_LINK) - goto drop; + goto free_skb; chan = l2cap_global_chan_by_scid(BT_CONNECTED, L2CAP_CID_ATT, &hcon->src, &hcon->dst); if (!chan) - goto drop; + goto free_skb; BT_DBG("chan %p, len %d", chan, skb->len); if (chan->imtu < skb->len) goto drop; - if (!chan->ops->recv(chan, skb)) + if (!chan->ops->recv(chan, skb)) { + l2cap_chan_put(chan); return; + } drop: + l2cap_chan_put(chan); +free_skb: kfree_skb(skb); } From 5ff6f34d4260c542df3712e29ead87cf071ad472 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 7 Aug 2014 22:56:43 +0300 Subject: [PATCH 07/48] Bluetooth: Fix __l2cap_no_conn_pending() usage with all channels The __l2cap_no_conn_pending() function would previously only return a meaningful value for connection oriented channels and was therefore not useful for anything else. As preparation of making the L2CAP code more generic allow the function to be called for other channel types as well by returning a meaningful value for them. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index a47a14efd5aa..a0a910eb897b 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1082,6 +1082,9 @@ static void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, bool poll) static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan) { + if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) + return true; + return !test_bit(CONF_CONNECT_PEND, &chan->conf_state); } From d52deb17489b8155e031fb1a9f116c602d719e11 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 7 Aug 2014 22:56:44 +0300 Subject: [PATCH 08/48] Bluetooth: Resume BT_CONNECTED state after LE security elevation The LE ATT socket uses a special trick where it temporarily sets BT_CONFIG state for the duration of a security level elevation. In order to not require special hacks for going back to BT_CONNECTED state in the l2cap_core.c code the most reasonable place to resume the state is the resume callback. This patch adds a new flag to track the pending security level change and ensures that the state is set back to BT_CONNECTED in the resume callback in case the flag is set. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 1 + net/bluetooth/l2cap_sock.c | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 8df15ad0d43f..4a51e7596608 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -708,6 +708,7 @@ enum { FLAG_EFS_ENABLE, FLAG_DEFER_SETUP, FLAG_LE_CONN_REQ_SENT, + FLAG_PENDING_SECURITY, }; enum { diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 1884f72083c2..5a42f6a818c0 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -790,6 +790,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, if (chan->scid == L2CAP_CID_ATT) { if (smp_conn_security(conn->hcon, sec.level)) break; + set_bit(FLAG_PENDING_SECURITY, &chan->flags); sk->sk_state = BT_CONFIG; chan->state = BT_CONFIG; @@ -1359,6 +1360,11 @@ static void l2cap_sock_resume_cb(struct l2cap_chan *chan) { struct sock *sk = chan->data; + if (test_and_clear_bit(FLAG_PENDING_SECURITY, &chan->flags)) { + sk->sk_state = BT_CONNECTED; + chan->state = BT_CONNECTED; + } + clear_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags); sk->sk_state_change(sk); } From 191eb398c677444bc08cb4497467ca9e2b8696bc Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 7 Aug 2014 22:56:45 +0300 Subject: [PATCH 09/48] Bluetooth: Remove special handling of ATT in l2cap_security_cfm() With the update to sk->resume() and __l2cap_no_conn_pending() we no-longer need to have special handling of ATT channels in the l2cap_security_cfm() function. The chan->sec_level update when encryption has been enabled is safe to do for any kind of channel, and the loop takes later care of calling chan->ready() or chan->resume() if necessary. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index a0a910eb897b..54cbfcd4da44 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -7341,15 +7341,8 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) continue; } - if (chan->scid == L2CAP_CID_ATT) { - if (!status && encrypt) { - chan->sec_level = hcon->sec_level; - l2cap_chan_ready(chan); - } - - l2cap_chan_unlock(chan); - continue; - } + if (!status && encrypt) + chan->sec_level = hcon->sec_level; if (!__l2cap_no_conn_pending(chan)) { l2cap_chan_unlock(chan); From dc0f5088182b2e48ae47629a55bdf35ad5d6ed44 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 7 Aug 2014 22:56:46 +0300 Subject: [PATCH 10/48] Bluetooth: Refactor l2cap_connect_cfm This patch is a simple refactoring of l2cap_connect_cfm to allow easier extension of the function. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 54cbfcd4da44..7a5cff89b792 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -7268,13 +7268,16 @@ void l2cap_connect_cfm(struct hci_conn *hcon, u8 status) BT_DBG("hcon %p bdaddr %pMR status %d", hcon, &hcon->dst, status); - if (!status) { - conn = l2cap_conn_add(hcon); - if (conn) - l2cap_conn_ready(conn); - } else { + if (status) { l2cap_conn_del(hcon, bt_to_errno(status)); + return; } + + conn = l2cap_conn_add(hcon); + if (!conn) + return; + + l2cap_conn_ready(conn); } int l2cap_disconn_ind(struct hci_conn *hcon) From e760ec12134d5736065c4e88b0e783cc1fe0d20a Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 7 Aug 2014 22:56:47 +0300 Subject: [PATCH 11/48] Bluetooth: Move L2CAP fixed channel creation into l2cap_conn_cfm In order to remove special handling of fixed L2CAP channels we need to start creating them in a single place instead of having per-channel exceptions. The most natural place is the l2cap_conn_cfm() function which is called whenever there is a new baseband link. The only really special case so far has been the ATT socket, so in order not to break the code in between this patch removes the ATT special handling at the same time as it adds the generic fixed channel handling from l2cap_le_conn_ready() into the hci_conn_cfm() function. As a related change the channel locking in l2cap_conn_ready() becomes simpler and we can thereby move the smp_conn_security() call into the l2cap_le_conn_ready() function. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 124 ++++++++++++++++++++++++------------- 1 file changed, 80 insertions(+), 44 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 7a5cff89b792..8c4767f91a23 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1469,26 +1469,14 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) { struct hci_conn *hcon = conn->hcon; struct hci_dev *hdev = hcon->hdev; - struct l2cap_chan *chan, *pchan; - u8 dst_type; - BT_DBG(""); + BT_DBG("%s conn %p", hdev->name, conn); - /* Check if we have socket listening on cid */ - pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_ATT, - &hcon->src, &hcon->dst); - if (!pchan) - return; - - /* Client ATT sockets should override the server one */ - if (__l2cap_get_chan_by_dcid(conn, L2CAP_CID_ATT)) - goto put; - - dst_type = bdaddr_type(hcon, hcon->dst_type); - - /* If device is blocked, do not create a channel for it */ - if (hci_bdaddr_list_lookup(&hdev->blacklist, &hcon->dst, dst_type)) - goto put; + /* For outgoing pairing which doesn't necessarily have an + * associated socket (e.g. mgmt_pair_device). + */ + if (hcon->out) + smp_conn_security(hcon, hcon->pending_sec_level); /* For LE slave connections, make sure the connection interval * is in the range of the minium and maximum interval that has @@ -1508,24 +1496,6 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONN_PARAM_UPDATE_REQ, sizeof(req), &req); } - - l2cap_chan_lock(pchan); - - chan = pchan->ops->new_connection(pchan); - if (!chan) - goto clean; - - bacpy(&chan->src, &hcon->src); - bacpy(&chan->dst, &hcon->dst); - chan->src_type = bdaddr_type(hcon, hcon->src_type); - chan->dst_type = dst_type; - - __l2cap_chan_add(conn, chan); - -clean: - l2cap_chan_unlock(pchan); -put: - l2cap_chan_put(pchan); } static void l2cap_conn_ready(struct l2cap_conn *conn) @@ -1535,17 +1505,11 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) BT_DBG("conn %p", conn); - /* For outgoing pairing which doesn't necessarily have an - * associated socket (e.g. mgmt_pair_device). - */ - if (hcon->out && hcon->type == LE_LINK) - smp_conn_security(hcon, hcon->pending_sec_level); - - mutex_lock(&conn->chan_lock); - if (hcon->type == LE_LINK) l2cap_le_conn_ready(conn); + mutex_lock(&conn->chan_lock); + list_for_each_entry(chan, &conn->chan_l, list) { l2cap_chan_lock(chan); @@ -7262,9 +7226,44 @@ int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr) return exact ? lm1 : lm2; } +/* Find the next fixed channel in BT_LISTEN state, continue iteration + * from an existing channel in the list or from the beginning of the + * global list (by passing NULL as first parameter). + */ +static struct l2cap_chan *l2cap_global_fixed_chan(struct l2cap_chan *c, + bdaddr_t *src) +{ + read_lock(&chan_list_lock); + + if (c) + c = list_next_entry(c, global_l); + else + c = list_entry(chan_list.next, typeof(*c), global_l); + + list_for_each_entry_from(c, &chan_list, global_l) { + if (c->chan_type != L2CAP_CHAN_FIXED) + continue; + if (c->state != BT_LISTEN) + continue; + if (bacmp(&c->src, src) && bacmp(&c->src, BDADDR_ANY)) + continue; + + l2cap_chan_hold(c); + read_unlock(&chan_list_lock); + return c; + } + + read_unlock(&chan_list_lock); + + return NULL; +} + void l2cap_connect_cfm(struct hci_conn *hcon, u8 status) { + struct hci_dev *hdev = hcon->hdev; struct l2cap_conn *conn; + struct l2cap_chan *pchan; + u8 dst_type; BT_DBG("hcon %p bdaddr %pMR status %d", hcon, &hcon->dst, status); @@ -7277,6 +7276,43 @@ void l2cap_connect_cfm(struct hci_conn *hcon, u8 status) if (!conn) return; + dst_type = bdaddr_type(hcon, hcon->dst_type); + + /* If device is blocked, do not create channels for it */ + if (hci_bdaddr_list_lookup(&hdev->blacklist, &hcon->dst, dst_type)) + return; + + /* Find fixed channels and notify them of the new connection. We + * use multiple individual lookups, continuing each time where + * we left off, because the list lock would prevent calling the + * potentially sleeping l2cap_chan_lock() function. + */ + pchan = l2cap_global_fixed_chan(NULL, &hdev->bdaddr); + while (pchan) { + struct l2cap_chan *chan, *next; + + /* Client fixed channels should override server ones */ + if (__l2cap_get_chan_by_dcid(conn, pchan->scid)) + goto next; + + l2cap_chan_lock(pchan); + chan = pchan->ops->new_connection(pchan); + if (chan) { + bacpy(&chan->src, &hcon->src); + bacpy(&chan->dst, &hcon->dst); + chan->src_type = bdaddr_type(hcon, hcon->src_type); + chan->dst_type = dst_type; + + __l2cap_chan_add(conn, chan); + } + + l2cap_chan_unlock(pchan); +next: + next = l2cap_global_fixed_chan(pchan, &hdev->bdaddr); + l2cap_chan_put(pchan); + pchan = next; + } + l2cap_conn_ready(conn); } From 54a1b626c96039f172dd2ea15b2671053b3c5a68 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 7 Aug 2014 22:56:48 +0300 Subject: [PATCH 12/48] Bluetooth: Improve fixed channel lookup based on link type When notifying global fixed channels of new connections it doesn't make sense to consider channels meant for a different link type than the one available. This patch adds an extra parameter to the l2cap_global_fixed_chan() lookup function and ensures that only channels matching the current hci_conn type are looked up. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 8c4767f91a23..191b58f48245 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -7231,7 +7231,7 @@ int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr) * global list (by passing NULL as first parameter). */ static struct l2cap_chan *l2cap_global_fixed_chan(struct l2cap_chan *c, - bdaddr_t *src) + bdaddr_t *src, u8 link_type) { read_lock(&chan_list_lock); @@ -7247,6 +7247,10 @@ static struct l2cap_chan *l2cap_global_fixed_chan(struct l2cap_chan *c, continue; if (bacmp(&c->src, src) && bacmp(&c->src, BDADDR_ANY)) continue; + if (link_type == ACL_LINK && c->src_type != BDADDR_BREDR) + continue; + if (link_type == LE_LINK && c->src_type == BDADDR_BREDR) + continue; l2cap_chan_hold(c); read_unlock(&chan_list_lock); @@ -7287,7 +7291,7 @@ void l2cap_connect_cfm(struct hci_conn *hcon, u8 status) * we left off, because the list lock would prevent calling the * potentially sleeping l2cap_chan_lock() function. */ - pchan = l2cap_global_fixed_chan(NULL, &hdev->bdaddr); + pchan = l2cap_global_fixed_chan(NULL, &hdev->bdaddr, hcon->type); while (pchan) { struct l2cap_chan *chan, *next; @@ -7308,7 +7312,8 @@ void l2cap_connect_cfm(struct hci_conn *hcon, u8 status) l2cap_chan_unlock(pchan); next: - next = l2cap_global_fixed_chan(pchan, &hdev->bdaddr); + next = l2cap_global_fixed_chan(pchan, &hdev->bdaddr, + hcon->type); l2cap_chan_put(pchan); pchan = next; } From 06171e0546434b006a3857ea745b4258ad5d677c Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 7 Aug 2014 22:56:49 +0300 Subject: [PATCH 13/48] Bluetooth: Remove special ATT data channel handling Now that we've got the fixed channel infrastructure cleaned up in a generic way there's no longer a need to have a dedicated function for handling data on the ATT channel. Instead the generic l2cap_data_channel() handler will be able to do the exact same thing. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 79 -------------------------------------- 1 file changed, 79 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 191b58f48245..09eb4e3e8ab2 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1420,51 +1420,6 @@ static void l2cap_conn_start(struct l2cap_conn *conn) mutex_unlock(&conn->chan_lock); } -/* 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 *dst) -{ - struct l2cap_chan *c, *c1 = NULL; - - read_lock(&chan_list_lock); - - list_for_each_entry(c, &chan_list, global_l) { - if (state && c->state != state) - continue; - - if (c->scid == cid) { - int src_match, dst_match; - int src_any, dst_any; - - /* Exact match. */ - src_match = !bacmp(&c->src, src); - dst_match = !bacmp(&c->dst, dst); - if (src_match && dst_match) { - l2cap_chan_hold(c); - read_unlock(&chan_list_lock); - return c; - } - - /* Closest match */ - src_any = !bacmp(&c->src, BDADDR_ANY); - dst_any = !bacmp(&c->dst, BDADDR_ANY); - if ((src_match && dst_any) || (src_any && dst_match) || - (src_any && dst_any)) - c1 = c; - } - } - - if (c1) - l2cap_chan_hold(c1); - - read_unlock(&chan_list_lock); - - return c1; -} - static void l2cap_le_conn_ready(struct l2cap_conn *conn) { struct hci_conn *hcon = conn->hcon; @@ -6854,36 +6809,6 @@ free_skb: kfree_skb(skb); } -static void l2cap_att_channel(struct l2cap_conn *conn, - struct sk_buff *skb) -{ - struct hci_conn *hcon = conn->hcon; - struct l2cap_chan *chan; - - if (hcon->type != LE_LINK) - goto free_skb; - - chan = l2cap_global_chan_by_scid(BT_CONNECTED, L2CAP_CID_ATT, - &hcon->src, &hcon->dst); - if (!chan) - goto free_skb; - - BT_DBG("chan %p, len %d", chan, skb->len); - - if (chan->imtu < skb->len) - goto drop; - - if (!chan->ops->recv(chan, skb)) { - l2cap_chan_put(chan); - return; - } - -drop: - l2cap_chan_put(chan); -free_skb: - kfree_skb(skb); -} - static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) { struct l2cap_hdr *lh = (void *) skb->data; @@ -6929,10 +6854,6 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) l2cap_conless_channel(conn, psm, skb); break; - case L2CAP_CID_ATT: - l2cap_att_channel(conn, skb); - break; - case L2CAP_CID_LE_SIGNALING: l2cap_le_sig_channel(conn, skb); break; From 148243087b3a5d95a32825da26858dc9d893b141 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 7 Aug 2014 22:56:50 +0300 Subject: [PATCH 14/48] Bluetooth: Move parts of fixed channel initialization to l2cap_add_scid The l2cap_add_scid function is used for registering a fixed L2CAP channel. Instead of having separate initialization of the channel type and outgoing MTU in l2cap_sock.c it's more intuitive to do these things in the l2cap_add_scid function itself (and thereby make the functionality available to other users besides l2cap_sock.c). Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 4 ++++ net/bluetooth/l2cap_sock.c | 9 --------- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 09eb4e3e8ab2..344a29c53227 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -210,6 +210,10 @@ int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid) { write_lock(&chan_list_lock); + /* Override the defaults (which are for conn-oriented) */ + chan->omtu = L2CAP_DEFAULT_MTU; + chan->chan_type = L2CAP_CHAN_FIXED; + chan->scid = scid; write_unlock(&chan_list_lock); diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 5a42f6a818c0..ed06f88e6f10 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -99,15 +99,6 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) if (!bdaddr_type_is_valid(la.l2_bdaddr_type)) return -EINVAL; - if (la.l2_cid) { - /* When the socket gets created it defaults to - * CHAN_CONN_ORIENTED, so we need to overwrite the - * default here. - */ - chan->chan_type = L2CAP_CHAN_FIXED; - chan->omtu = L2CAP_DEFAULT_MTU; - } - if (bdaddr_type_is_le(la.l2_bdaddr_type)) { /* We only allow ATT user space socket */ if (la.l2_cid && From 72847ce02180e8a0be1b23ba53ffe437cdb25d6a Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 8 Aug 2014 09:28:03 +0300 Subject: [PATCH 15/48] Bluetooth: Call L2CAP teardown callback before clearing chan->conn L2CAP channel implementations may want to still access the chan->conn pointer. This will particularly be the case for SMP that will want to clear a reference to the SMP channel in the l2cap_conn structure. The only user of the teardown callback so far is l2cap_sock.c and for the code there it makes no difference whether the callback is called before or after clearing the chan->conn pointer. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 344a29c53227..c6419f40cfba 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -566,6 +566,8 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err) BT_DBG("chan %p, conn %p, err %d", chan, conn, err); + chan->ops->teardown(chan, err); + if (conn) { struct amp_mgr *mgr = conn->hcon->amp_mgr; /* Delete from channel list */ @@ -589,8 +591,6 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err) amp_disconnect_logical_link(hs_hchan); } - chan->ops->teardown(chan, err); - if (test_bit(CONF_NOT_COMPLETE, &chan->conf_state)) return; From 79a0572736ad4b9cac7be72d4402f9c79db8ebaf Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 8 Aug 2014 09:28:04 +0300 Subject: [PATCH 16/48] Bluetooth: Call l2cap_le_conn_ready after notifying channels For most cases it makes no difference whether l2cap_le_conn_ready() is called before or after calling the channel ready() callbacks, however for upcoming SMP code we need this as the ready() callback initializes certain structures that a call to smp_conn_security() from l2cap_le_conn_ready() depends on. Therefore, move the call to l2cap_le_conn_ready() after iterating through and notifying channels. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index c6419f40cfba..8acfe6f57b5e 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1464,9 +1464,6 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) BT_DBG("conn %p", conn); - if (hcon->type == LE_LINK) - l2cap_le_conn_ready(conn); - mutex_lock(&conn->chan_lock); list_for_each_entry(chan, &conn->chan_l, list) { @@ -1492,6 +1489,9 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) mutex_unlock(&conn->chan_lock); + if (hcon->type == LE_LINK) + l2cap_le_conn_ready(conn); + queue_work(hcon->hdev->workqueue, &conn->pending_rx_work); } From d3368605591b88cd8af522adadb1c460a8f8e7bb Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 8 Aug 2014 09:28:05 +0300 Subject: [PATCH 17/48] Bluetooth: Fix using HCI_CONN_LE_SMP_PEND to check for SMP context The code is consistently using the HCI_CONN_LE_SMP_PEND flag check for the existence of the SMP context, with the exception of this one place in smp_sig_channel(). This patch converts the place to use the flag just like all other instances. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 40db728f044b..33016ec9b247 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -1206,7 +1206,7 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb) * returns an error). */ if (code != SMP_CMD_PAIRING_REQ && code != SMP_CMD_SECURITY_REQ && - !conn->smp_chan) { + !test_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) { BT_ERR("Unexpected SMP command 0x%02x. Disconnecting.", code); kfree_skb(skb); return -EOPNOTSUPP; From fabed38fcf456cc5d3e6946fab78855aa65bd40b Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 8 Aug 2014 09:32:48 +0300 Subject: [PATCH 18/48] Bluetooth: Fix hci_update_random_address() error return for no crypto If the AES crypto context is not available we cannot generate new RPAs. We should therefore cleanly return an error from the function responsible for updating the random address. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 217ef83fb541..860477090d78 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3882,6 +3882,12 @@ int hci_update_random_address(struct hci_request *req, bool require_privacy, !bacmp(&hdev->random_addr, &hdev->rpa)) return 0; + if (!hdev->tfm_aes) { + BT_ERR("%s crypto not available to generate RPA", + hdev->name); + return -EOPNOTSUPP; + } + err = smp_generate_rpa(hdev->tfm_aes, hdev->irk, &hdev->rpa); if (err < 0) { BT_ERR("%s failed to generate new RPA", hdev->name); From 893ededeb189aa48c308116a7acd793efae5c830 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 8 Aug 2014 09:32:49 +0300 Subject: [PATCH 19/48] Bluetooth: Fix IRK lookup when tfm_aes is not available If the AES crypto has not been initialized properly we should cleanly return from the hci_find_irk_by_rpa() function. Right now this will not happen in practice, but once (in subsequent patches) SMP init is moved to after the HCI init procedure it is possible that the pointer is NULL. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 860477090d78..4a1ec259099e 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3232,6 +3232,9 @@ struct smp_irk *hci_find_irk_by_rpa(struct hci_dev *hdev, bdaddr_t *rpa) return irk; } + if (!hdev->tfm_aes) + return NULL; + list_for_each_entry(irk, &hdev->identity_resolving_keys, list) { if (smp_irk_matches(hdev->tfm_aes, irk->val, rpa)) { bacpy(&irk->rpa, rpa); From 222916e3e509f04678d0b6f13f7b17bbc8dd14b6 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 8 Aug 2014 09:32:50 +0300 Subject: [PATCH 20/48] Bluetooth: Refactor SMP (de)initialization into separate functions As preparation for converting SMP to use the l2cap_chan infrastructure refactor the (de)initialization into separate functions. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 46 +++++++++++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 4a1ec259099e..1f691c50abbc 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1764,6 +1764,34 @@ static void hci_init4_req(struct hci_request *req, unsigned long opt) } } +static int hci_register_smp(struct hci_dev *hdev) +{ + int err; + + BT_DBG("%s", hdev->name); + + hdev->tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0, + CRYPTO_ALG_ASYNC); + if (IS_ERR(hdev->tfm_aes)) { + BT_ERR("Unable to create crypto context"); + err = PTR_ERR(hdev->tfm_aes); + hdev->tfm_aes = NULL; + return err; + } + + return 0; +} + +static void hci_unregister_smp(struct hci_dev *hdev) +{ + BT_DBG("%s", hdev->name); + + if (hdev->tfm_aes) { + crypto_free_blkcipher(hdev->tfm_aes); + hdev->tfm_aes = NULL; + } +} + static int __hci_init(struct hci_dev *hdev) { int err; @@ -4099,18 +4127,13 @@ int hci_register_dev(struct hci_dev *hdev) dev_set_name(&hdev->dev, "%s", hdev->name); - hdev->tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0, - CRYPTO_ALG_ASYNC); - if (IS_ERR(hdev->tfm_aes)) { - BT_ERR("Unable to create crypto context"); - error = PTR_ERR(hdev->tfm_aes); - hdev->tfm_aes = NULL; + error = hci_register_smp(hdev); + if (error) goto err_wqueue; - } error = device_add(&hdev->dev); if (error < 0) - goto err_tfm; + goto err_smp; hdev->rfkill = rfkill_alloc(hdev->name, &hdev->dev, RFKILL_TYPE_BLUETOOTH, &hci_rfkill_ops, @@ -4152,8 +4175,8 @@ int hci_register_dev(struct hci_dev *hdev) return id; -err_tfm: - crypto_free_blkcipher(hdev->tfm_aes); +err_smp: + hci_unregister_smp(hdev); err_wqueue: destroy_workqueue(hdev->workqueue); destroy_workqueue(hdev->req_workqueue); @@ -4205,8 +4228,7 @@ void hci_unregister_dev(struct hci_dev *hdev) rfkill_destroy(hdev->rfkill); } - if (hdev->tfm_aes) - crypto_free_blkcipher(hdev->tfm_aes); + hci_unregister_smp(hdev); device_del(&hdev->dev); From 54506918059a5bdbf396f34f2e0a2735803024db Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 8 Aug 2014 09:32:51 +0300 Subject: [PATCH 21/48] Bluetooth: Move SMP initialization after HCI init First of all, it's wasteful to initialize SMP if it's never going to be used (e.g. on non-LE controllers). Second of all, when we move to use l2cap_chan we need to know the real local address, meaning we must have completed at least part of the HCI init. This patch moves the SMP initialization to after the HCI init procedure and makes it depend on whether the controller actually supports LE. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 1f691c50abbc..9eb2869b183b 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1926,6 +1926,8 @@ static int __hci_init(struct hci_dev *hdev) debugfs_create_u16("discov_interleaved_timeout", 0644, hdev->debugfs, &hdev->discov_interleaved_timeout); + + hci_register_smp(hdev); } return 0; @@ -4127,13 +4129,9 @@ int hci_register_dev(struct hci_dev *hdev) dev_set_name(&hdev->dev, "%s", hdev->name); - error = hci_register_smp(hdev); - if (error) - goto err_wqueue; - error = device_add(&hdev->dev); if (error < 0) - goto err_smp; + goto err_wqueue; hdev->rfkill = rfkill_alloc(hdev->name, &hdev->dev, RFKILL_TYPE_BLUETOOTH, &hci_rfkill_ops, @@ -4175,8 +4173,6 @@ int hci_register_dev(struct hci_dev *hdev) return id; -err_smp: - hci_unregister_smp(hdev); err_wqueue: destroy_workqueue(hdev->workqueue); destroy_workqueue(hdev->req_workqueue); From 711eafe345d993cf4831e890fa989d02c06cad62 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 8 Aug 2014 09:32:52 +0300 Subject: [PATCH 22/48] Bluetooth: Move SMP (de)initialization to smp.c As preparation for moving SMP to use l2cap_chan infrastructure we need to move the (de)initialization functions to smp.c (where they'll eventually need access to the local L2CAP channel callbacks). Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 32 ++------------------------------ net/bluetooth/smp.c | 26 ++++++++++++++++++++++++++ net/bluetooth/smp.h | 3 +++ 3 files changed, 31 insertions(+), 30 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 9eb2869b183b..88575a633601 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1764,34 +1764,6 @@ static void hci_init4_req(struct hci_request *req, unsigned long opt) } } -static int hci_register_smp(struct hci_dev *hdev) -{ - int err; - - BT_DBG("%s", hdev->name); - - hdev->tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0, - CRYPTO_ALG_ASYNC); - if (IS_ERR(hdev->tfm_aes)) { - BT_ERR("Unable to create crypto context"); - err = PTR_ERR(hdev->tfm_aes); - hdev->tfm_aes = NULL; - return err; - } - - return 0; -} - -static void hci_unregister_smp(struct hci_dev *hdev) -{ - BT_DBG("%s", hdev->name); - - if (hdev->tfm_aes) { - crypto_free_blkcipher(hdev->tfm_aes); - hdev->tfm_aes = NULL; - } -} - static int __hci_init(struct hci_dev *hdev) { int err; @@ -1927,7 +1899,7 @@ static int __hci_init(struct hci_dev *hdev) hdev->debugfs, &hdev->discov_interleaved_timeout); - hci_register_smp(hdev); + smp_register(hdev); } return 0; @@ -4224,7 +4196,7 @@ void hci_unregister_dev(struct hci_dev *hdev) rfkill_destroy(hdev->rfkill); } - hci_unregister_smp(hdev); + smp_unregister(hdev); device_del(&hdev->dev); diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 33016ec9b247..ab07649ecc77 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -1455,3 +1455,29 @@ int smp_distribute_keys(struct l2cap_conn *conn) return 0; } + +int smp_register(struct hci_dev *hdev) +{ + BT_DBG("%s", hdev->name); + + hdev->tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0, + CRYPTO_ALG_ASYNC); + if (IS_ERR(hdev->tfm_aes)) { + int err = PTR_ERR(hdev->tfm_aes); + BT_ERR("Unable to create crypto context"); + hdev->tfm_aes = NULL; + return err; + } + + return 0; +} + +void smp_unregister(struct hci_dev *hdev) +{ + BT_DBG("%s", hdev->name); + + if (hdev->tfm_aes) { + crypto_free_blkcipher(hdev->tfm_aes); + hdev->tfm_aes = NULL; + } +} diff --git a/net/bluetooth/smp.h b/net/bluetooth/smp.h index 796f4f45f92f..6e29359f60a3 100644 --- a/net/bluetooth/smp.h +++ b/net/bluetooth/smp.h @@ -136,4 +136,7 @@ bool smp_irk_matches(struct crypto_blkcipher *tfm, u8 irk[16], bdaddr_t *bdaddr); int smp_generate_rpa(struct crypto_blkcipher *tfm, u8 irk[16], bdaddr_t *rpa); +int smp_register(struct hci_dev *hdev); +void smp_unregister(struct hci_dev *hdev); + #endif /* __SMP_H */ From f193844c51e88ea3d2137bb0c1d38d27d37691a2 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 8 Aug 2014 09:37:15 +0300 Subject: [PATCH 23/48] Bluetooth: Add more L2CAP convenience callbacks In preparation for converting SMP to use l2cap_chan it's useful to add a few more callback helpers so that smp.c won't need to define all of its own. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 4a51e7596608..a72965f6bc2f 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -838,18 +838,43 @@ static inline struct l2cap_chan *l2cap_chan_no_new_connection(struct l2cap_chan return NULL; } +static inline int l2cap_chan_no_recv(struct l2cap_chan *chan, struct sk_buff *skb) +{ + return -ENOSYS; +} + +static inline struct sk_buff *l2cap_chan_no_alloc_skb(struct l2cap_chan *chan, + unsigned long hdr_len, + unsigned long len, int nb) +{ + return ERR_PTR(-ENOSYS); +} + static inline void l2cap_chan_no_teardown(struct l2cap_chan *chan, int err) { } +static inline void l2cap_chan_no_close(struct l2cap_chan *chan) +{ +} + static inline void l2cap_chan_no_ready(struct l2cap_chan *chan) { } +static inline void l2cap_chan_no_state_change(struct l2cap_chan *chan, + int state, int err) +{ +} + static inline void l2cap_chan_no_defer(struct l2cap_chan *chan) { } +static inline void l2cap_chan_no_suspend(struct l2cap_chan *chan) +{ +} + static inline void l2cap_chan_no_resume(struct l2cap_chan *chan) { } From 70db83c4bcdc1447bbcb318389561c90d7056b18 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 8 Aug 2014 09:37:16 +0300 Subject: [PATCH 24/48] Bluetooth: Add SMP L2CAP channel skeleton This patch creates the initial SMP L2CAP channels and a skeleton for their callbacks. There is one per-adapter channel created upon adapter registration, and then one channel per-connection created through the new_connection callback. The channels are registered with the reserved CID 0x1f for now in order to not conflict with existing SMP functionality. Once everything is in place the value can be changed to what it should be, i.e. L2CAP_CID_SMP. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 1 + include/net/bluetooth/l2cap.h | 1 + net/bluetooth/smp.c | 131 ++++++++++++++++++++++++++++++- 3 files changed, 132 insertions(+), 1 deletion(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index cc2eb7730fbc..2571fc1cb1c5 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -303,6 +303,7 @@ struct hci_dev { __u32 req_result; struct crypto_blkcipher *tfm_aes; + void *smp_data; struct discovery_state discovery; struct hci_conn_hash conn_hash; diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index a72965f6bc2f..1a037ba4b6f4 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -637,6 +637,7 @@ struct l2cap_conn { struct delayed_work security_timer; struct smp_chan *smp_chan; + struct l2cap_chan *smp; struct list_head chan_l; struct mutex chan_lock; diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index ab07649ecc77..2362ae35a4d5 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -1456,8 +1456,106 @@ int smp_distribute_keys(struct l2cap_conn *conn) return 0; } +static void smp_teardown_cb(struct l2cap_chan *chan, int err) +{ + struct l2cap_conn *conn = chan->conn; + + BT_DBG("chan %p", chan); + + conn->smp = NULL; + l2cap_chan_put(chan); +} + +static void smp_ready_cb(struct l2cap_chan *chan) +{ + struct l2cap_conn *conn = chan->conn; + + BT_DBG("chan %p", chan); + + conn->smp = chan; + l2cap_chan_hold(chan); +} + +static struct sk_buff *smp_alloc_skb_cb(struct l2cap_chan *chan, + unsigned long hdr_len, + unsigned long len, int nb) +{ + struct sk_buff *skb; + + skb = bt_skb_alloc(hdr_len + len, GFP_KERNEL); + if (!skb) + return ERR_PTR(-ENOMEM); + + skb->priority = HCI_PRIO_MAX; + bt_cb(skb)->chan = chan; + + return skb; +} + +static const struct l2cap_ops smp_chan_ops = { + .name = "Security Manager", + .ready = smp_ready_cb, + .alloc_skb = smp_alloc_skb_cb, + .teardown = smp_teardown_cb, + + .new_connection = l2cap_chan_no_new_connection, + .recv = l2cap_chan_no_recv, + .state_change = l2cap_chan_no_state_change, + .close = l2cap_chan_no_close, + .defer = l2cap_chan_no_defer, + .suspend = l2cap_chan_no_suspend, + .resume = l2cap_chan_no_resume, + .set_shutdown = l2cap_chan_no_set_shutdown, + .get_sndtimeo = l2cap_chan_no_get_sndtimeo, + .memcpy_fromiovec = l2cap_chan_no_memcpy_fromiovec, +}; + +static inline struct l2cap_chan *smp_new_conn_cb(struct l2cap_chan *pchan) +{ + struct l2cap_chan *chan; + + BT_DBG("pchan %p", pchan); + + chan = l2cap_chan_create(); + if (!chan) + return NULL; + + chan->chan_type = pchan->chan_type; + chan->ops = &smp_chan_ops; + chan->scid = pchan->scid; + chan->dcid = chan->scid; + chan->imtu = pchan->imtu; + chan->omtu = pchan->omtu; + chan->mode = pchan->mode; + + BT_DBG("created chan %p", chan); + + return chan; +} + +static const struct l2cap_ops smp_root_chan_ops = { + .name = "Security Manager Root", + .new_connection = smp_new_conn_cb, + + /* None of these are implemented for the root channel */ + .close = l2cap_chan_no_close, + .alloc_skb = l2cap_chan_no_alloc_skb, + .recv = l2cap_chan_no_recv, + .state_change = l2cap_chan_no_state_change, + .teardown = l2cap_chan_no_teardown, + .ready = l2cap_chan_no_ready, + .defer = l2cap_chan_no_defer, + .suspend = l2cap_chan_no_suspend, + .resume = l2cap_chan_no_resume, + .set_shutdown = l2cap_chan_no_set_shutdown, + .get_sndtimeo = l2cap_chan_no_get_sndtimeo, + .memcpy_fromiovec = l2cap_chan_no_memcpy_fromiovec, +}; + int smp_register(struct hci_dev *hdev) { + struct l2cap_chan *chan; + BT_DBG("%s", hdev->name); hdev->tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0, @@ -1469,15 +1567,46 @@ int smp_register(struct hci_dev *hdev) return err; } + chan = l2cap_chan_create(); + if (!chan) { + crypto_free_blkcipher(hdev->tfm_aes); + hdev->tfm_aes = NULL; + return -ENOMEM; + } + + /* FIXME: Using reserved 0x1f value for now - to be changed to + * L2CAP_CID_SMP once all functionality is in place. + */ + l2cap_add_scid(chan, 0x1f); + + l2cap_chan_set_defaults(chan); + + bacpy(&chan->src, &hdev->bdaddr); + chan->src_type = BDADDR_LE_PUBLIC; + chan->state = BT_LISTEN; + chan->mode = L2CAP_MODE_BASIC; + chan->imtu = L2CAP_DEFAULT_MTU; + chan->ops = &smp_root_chan_ops; + + hdev->smp_data = chan; + return 0; } void smp_unregister(struct hci_dev *hdev) { - BT_DBG("%s", hdev->name); + struct l2cap_chan *chan = hdev->smp_data; + + if (!chan) + return; + + BT_DBG("%s chan %p", hdev->name, chan); if (hdev->tfm_aes) { crypto_free_blkcipher(hdev->tfm_aes); hdev->tfm_aes = NULL; } + + hdev->smp_data = NULL; + l2cap_chan_put(chan); } From defce9e83666658d4420d65e45ab1ad190992f72 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 8 Aug 2014 09:37:17 +0300 Subject: [PATCH 25/48] Bluetooth: Make AES crypto context private to SMP Now that we have per-adapter SMP data thanks to the root SMP L2CAP channel we can take advantage of it and attach the AES crypto context (only used for SMP) to it. This means that the smp_irk_matches() and smp_generate_rpa() function can be converted to internally handle the AES context. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 1 - net/bluetooth/hci_core.c | 13 ++-------- net/bluetooth/smp.c | 41 ++++++++++++++++++++++---------- net/bluetooth/smp.h | 5 ++-- 4 files changed, 32 insertions(+), 28 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 2571fc1cb1c5..5f0b77b71b45 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -302,7 +302,6 @@ struct hci_dev { __u32 req_status; __u32 req_result; - struct crypto_blkcipher *tfm_aes; void *smp_data; struct discovery_state discovery; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 88575a633601..abeb5e47311e 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3234,11 +3234,8 @@ struct smp_irk *hci_find_irk_by_rpa(struct hci_dev *hdev, bdaddr_t *rpa) return irk; } - if (!hdev->tfm_aes) - return NULL; - list_for_each_entry(irk, &hdev->identity_resolving_keys, list) { - if (smp_irk_matches(hdev->tfm_aes, irk->val, rpa)) { + if (smp_irk_matches(hdev, irk->val, rpa)) { bacpy(&irk->rpa, rpa); return irk; } @@ -3887,13 +3884,7 @@ int hci_update_random_address(struct hci_request *req, bool require_privacy, !bacmp(&hdev->random_addr, &hdev->rpa)) return 0; - if (!hdev->tfm_aes) { - BT_ERR("%s crypto not available to generate RPA", - hdev->name); - return -EOPNOTSUPP; - } - - err = smp_generate_rpa(hdev->tfm_aes, hdev->irk, &hdev->rpa); + err = smp_generate_rpa(hdev, hdev->irk, &hdev->rpa); if (err < 0) { BT_ERR("%s failed to generate new RPA", hdev->name); return err; diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 2362ae35a4d5..6925fc4caaee 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -139,12 +139,18 @@ static int smp_ah(struct crypto_blkcipher *tfm, u8 irk[16], u8 r[3], u8 res[3]) return 0; } -bool smp_irk_matches(struct crypto_blkcipher *tfm, u8 irk[16], - bdaddr_t *bdaddr) +bool smp_irk_matches(struct hci_dev *hdev, u8 irk[16], bdaddr_t *bdaddr) { + struct l2cap_chan *chan = hdev->smp_data; + struct crypto_blkcipher *tfm; u8 hash[3]; int err; + if (!chan || !chan->data) + return false; + + tfm = chan->data; + BT_DBG("RPA %pMR IRK %*phN", bdaddr, 16, irk); err = smp_ah(tfm, irk, &bdaddr->b[3], hash); @@ -154,10 +160,17 @@ bool smp_irk_matches(struct crypto_blkcipher *tfm, u8 irk[16], return !memcmp(bdaddr->b, hash, 3); } -int smp_generate_rpa(struct crypto_blkcipher *tfm, u8 irk[16], bdaddr_t *rpa) +int smp_generate_rpa(struct hci_dev *hdev, u8 irk[16], bdaddr_t *rpa) { + struct l2cap_chan *chan = hdev->smp_data; + struct crypto_blkcipher *tfm; int err; + if (!chan || !chan->data) + return -EOPNOTSUPP; + + tfm = chan->data; + get_random_bytes(&rpa->b[3], 3); rpa->b[5] &= 0x3f; /* Clear two most significant bits */ @@ -1555,25 +1568,25 @@ static const struct l2cap_ops smp_root_chan_ops = { int smp_register(struct hci_dev *hdev) { struct l2cap_chan *chan; + struct crypto_blkcipher *tfm_aes; BT_DBG("%s", hdev->name); - hdev->tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0, - CRYPTO_ALG_ASYNC); - if (IS_ERR(hdev->tfm_aes)) { - int err = PTR_ERR(hdev->tfm_aes); + tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(tfm_aes)) { + int err = PTR_ERR(tfm_aes); BT_ERR("Unable to create crypto context"); - hdev->tfm_aes = NULL; return err; } chan = l2cap_chan_create(); if (!chan) { - crypto_free_blkcipher(hdev->tfm_aes); - hdev->tfm_aes = NULL; + crypto_free_blkcipher(tfm_aes); return -ENOMEM; } + chan->data = tfm_aes; + /* FIXME: Using reserved 0x1f value for now - to be changed to * L2CAP_CID_SMP once all functionality is in place. */ @@ -1596,15 +1609,17 @@ int smp_register(struct hci_dev *hdev) void smp_unregister(struct hci_dev *hdev) { struct l2cap_chan *chan = hdev->smp_data; + struct crypto_blkcipher *tfm_aes; if (!chan) return; BT_DBG("%s chan %p", hdev->name, chan); - if (hdev->tfm_aes) { - crypto_free_blkcipher(hdev->tfm_aes); - hdev->tfm_aes = NULL; + tfm_aes = chan->data; + if (tfm_aes) { + chan->data = NULL; + crypto_free_blkcipher(tfm_aes); } hdev->smp_data = NULL; diff --git a/net/bluetooth/smp.h b/net/bluetooth/smp.h index 6e29359f60a3..d3f6bd617940 100644 --- a/net/bluetooth/smp.h +++ b/net/bluetooth/smp.h @@ -132,9 +132,8 @@ int smp_user_confirm_reply(struct hci_conn *conn, u16 mgmt_op, __le32 passkey); void smp_chan_destroy(struct l2cap_conn *conn); -bool smp_irk_matches(struct crypto_blkcipher *tfm, u8 irk[16], - bdaddr_t *bdaddr); -int smp_generate_rpa(struct crypto_blkcipher *tfm, u8 irk[16], bdaddr_t *rpa); +bool smp_irk_matches(struct hci_dev *hdev, u8 irk[16], bdaddr_t *bdaddr); +int smp_generate_rpa(struct hci_dev *hdev, u8 irk[16], bdaddr_t *rpa); int smp_register(struct hci_dev *hdev); void smp_unregister(struct hci_dev *hdev); From 5d88cc73dded31a93fcc4821f33a8c3d755bf454 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 8 Aug 2014 09:37:18 +0300 Subject: [PATCH 26/48] Bluetooth: Convert SMP to use l2cap_chan infrastructure Now that we have all the necessary pieces in place we can fully convert SMP to use the L2CAP channel infrastructure. This patch adds the necessary callbacks and removes the now unneeded conn->smp_chan pointer. One notable behavioral change in this patch comes from the following code snippet: - case L2CAP_CID_SMP: - if (smp_sig_channel(conn, skb)) - l2cap_conn_del(conn->hcon, EACCES); This piece of code was essentially forcing a disconnection if garbage SMP data was received. The l2cap_conn_del() function is private to l2cap_conn.c so we don't have access to it anymore when using the L2CAP channel callbacks. Therefore, the behavior of the new code is simply to return errors in the recv() callback (which is simply the old smp_sig_channel()), but no disconnection will occur. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 1 - net/bluetooth/l2cap_core.c | 10 --- net/bluetooth/smp.c | 126 ++++++++++++++++++---------------- net/bluetooth/smp.h | 1 - 4 files changed, 68 insertions(+), 70 deletions(-) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 1a037ba4b6f4..bda6252e3722 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -636,7 +636,6 @@ struct l2cap_conn { __u8 disc_reason; struct delayed_work security_timer; - struct smp_chan *smp_chan; struct l2cap_chan *smp; struct list_head chan_l; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 8acfe6f57b5e..40b6c06ab2c0 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1651,11 +1651,6 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) cancel_delayed_work_sync(&conn->info_timer); - if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) { - cancel_delayed_work_sync(&conn->security_timer); - smp_chan_destroy(conn); - } - hcon->l2cap_data = NULL; conn->hchan = NULL; l2cap_conn_put(conn); @@ -6862,11 +6857,6 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) l2cap_le_sig_channel(conn, skb); break; - case L2CAP_CID_SMP: - if (smp_sig_channel(conn, skb)) - l2cap_conn_del(conn->hcon, EACCES); - break; - default: l2cap_data_channel(conn, cid, skb); break; diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 6925fc4caaee..744f678ac3e8 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -248,44 +248,29 @@ static int smp_s1(struct smp_chan *smp, u8 k[16], u8 r1[16], u8 r2[16], return err; } -static struct sk_buff *smp_build_cmd(struct l2cap_conn *conn, u8 code, - u16 dlen, void *data) -{ - struct sk_buff *skb; - struct l2cap_hdr *lh; - int len; - - len = L2CAP_HDR_SIZE + sizeof(code) + dlen; - - if (len > conn->mtu) - return NULL; - - skb = bt_skb_alloc(len, GFP_ATOMIC); - if (!skb) - return NULL; - - lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); - lh->len = cpu_to_le16(sizeof(code) + dlen); - lh->cid = cpu_to_le16(L2CAP_CID_SMP); - - memcpy(skb_put(skb, sizeof(code)), &code, sizeof(code)); - - memcpy(skb_put(skb, dlen), data, dlen); - - return skb; -} - static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data) { - struct sk_buff *skb = smp_build_cmd(conn, code, len, data); + struct l2cap_chan *chan = conn->smp; + struct kvec iv[2]; + struct msghdr msg; + + if (!chan) + return; BT_DBG("code 0x%2.2x", code); - if (!skb) - return; + iv[0].iov_base = &code; + iv[0].iov_len = 1; - skb->priority = HCI_PRIO_MAX; - hci_send_acl(conn->hchan, skb, 0); + iv[1].iov_base = data; + iv[1].iov_len = len; + + memset(&msg, 0, sizeof(msg)); + + msg.msg_iov = (struct iovec *) &iv; + msg.msg_iovlen = 2; + + l2cap_chan_send(chan, &msg, 1 + len); cancel_delayed_work_sync(&conn->security_timer); schedule_delayed_work(&conn->security_timer, SMP_TIMEOUT); @@ -315,7 +300,8 @@ static void build_pairing_cmd(struct l2cap_conn *conn, struct smp_cmd_pairing *req, struct smp_cmd_pairing *rsp, __u8 authreq) { - struct smp_chan *smp = conn->smp_chan; + struct l2cap_chan *chan = conn->smp; + struct smp_chan *smp = chan->data; struct hci_conn *hcon = conn->hcon; struct hci_dev *hdev = hcon->hdev; u8 local_dist = 0, remote_dist = 0; @@ -358,7 +344,8 @@ static void build_pairing_cmd(struct l2cap_conn *conn, static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size) { - struct smp_chan *smp = conn->smp_chan; + struct l2cap_chan *chan = conn->smp; + struct smp_chan *smp = chan->data; if ((max_key_size > SMP_MAX_ENC_KEY_SIZE) || (max_key_size < SMP_MIN_ENC_KEY_SIZE)) @@ -418,7 +405,8 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth, u8 local_io, u8 remote_io) { struct hci_conn *hcon = conn->hcon; - struct smp_chan *smp = conn->smp_chan; + struct l2cap_chan *chan = conn->smp; + struct smp_chan *smp = chan->data; u8 method; u32 passkey = 0; int ret = 0; @@ -589,6 +577,7 @@ static u8 smp_random(struct smp_chan *smp) static struct smp_chan *smp_chan_create(struct l2cap_conn *conn) { + struct l2cap_chan *chan = conn->smp; struct smp_chan *smp; smp = kzalloc(sizeof(*smp), GFP_ATOMIC); @@ -606,7 +595,7 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn) } smp->conn = conn; - conn->smp_chan = smp; + chan->data = smp; hci_conn_hold(conn->hcon); @@ -615,7 +604,8 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn) void smp_chan_destroy(struct l2cap_conn *conn) { - struct smp_chan *smp = conn->smp_chan; + struct l2cap_chan *chan = conn->smp; + struct smp_chan *smp = chan->data; bool complete; BUG_ON(!smp); @@ -646,14 +636,15 @@ void smp_chan_destroy(struct l2cap_conn *conn) } } + chan->data = NULL; kfree(smp); - conn->smp_chan = NULL; hci_conn_drop(conn->hcon); } int smp_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, __le32 passkey) { struct l2cap_conn *conn = hcon->l2cap_data; + struct l2cap_chan *chan; struct smp_chan *smp; u32 value; @@ -662,7 +653,11 @@ int smp_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, __le32 passkey) if (!conn || !test_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) return -ENOTCONN; - smp = conn->smp_chan; + chan = conn->smp; + if (!chan) + return -ENOTCONN; + + smp = chan->data; switch (mgmt_op) { case MGMT_OP_USER_PASSKEY_REPLY: @@ -709,10 +704,12 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) if (conn->hcon->role != HCI_ROLE_SLAVE) return SMP_CMD_NOTSUPP; - if (!test_and_set_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) + if (!test_and_set_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) { smp = smp_chan_create(conn); - else - smp = conn->smp_chan; + } else { + struct l2cap_chan *chan = conn->smp; + smp = chan->data; + } if (!smp) return SMP_UNSPECIFIED; @@ -766,7 +763,8 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb) { struct smp_cmd_pairing *req, *rsp = (void *) skb->data; - struct smp_chan *smp = conn->smp_chan; + struct l2cap_chan *chan = conn->smp; + struct smp_chan *smp = chan->data; u8 key_size, auth = SMP_AUTH_NONE; int ret; @@ -827,7 +825,8 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb) static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb) { - struct smp_chan *smp = conn->smp_chan; + struct l2cap_chan *chan = conn->smp; + struct smp_chan *smp = chan->data; BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave"); @@ -850,7 +849,8 @@ static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb) static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb) { - struct smp_chan *smp = conn->smp_chan; + struct l2cap_chan *chan = conn->smp; + struct smp_chan *smp = chan->data; BT_DBG("conn %p", conn); @@ -1023,7 +1023,8 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level) static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb) { struct smp_cmd_encrypt_info *rp = (void *) skb->data; - struct smp_chan *smp = conn->smp_chan; + struct l2cap_chan *chan = conn->smp; + struct smp_chan *smp = chan->data; BT_DBG("conn %p", conn); @@ -1044,7 +1045,8 @@ static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb) static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb) { struct smp_cmd_master_ident *rp = (void *) skb->data; - struct smp_chan *smp = conn->smp_chan; + struct l2cap_chan *chan = conn->smp; + struct smp_chan *smp = chan->data; struct hci_dev *hdev = conn->hcon->hdev; struct hci_conn *hcon = conn->hcon; struct smp_ltk *ltk; @@ -1080,7 +1082,8 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb) static int smp_cmd_ident_info(struct l2cap_conn *conn, struct sk_buff *skb) { struct smp_cmd_ident_info *info = (void *) skb->data; - struct smp_chan *smp = conn->smp_chan; + struct l2cap_chan *chan = conn->smp; + struct smp_chan *smp = chan->data; BT_DBG(""); @@ -1102,7 +1105,8 @@ static int smp_cmd_ident_addr_info(struct l2cap_conn *conn, struct sk_buff *skb) { struct smp_cmd_ident_addr_info *info = (void *) skb->data; - struct smp_chan *smp = conn->smp_chan; + struct l2cap_chan *chan = conn->smp; + struct smp_chan *smp = chan->data; struct hci_conn *hcon = conn->hcon; bdaddr_t rpa; @@ -1156,7 +1160,8 @@ distribute: static int smp_cmd_sign_info(struct l2cap_conn *conn, struct sk_buff *skb) { struct smp_cmd_sign_info *rp = (void *) skb->data; - struct smp_chan *smp = conn->smp_chan; + struct l2cap_chan *chan = conn->smp; + struct smp_chan *smp = chan->data; struct hci_dev *hdev = conn->hcon->hdev; struct smp_csrk *csrk; @@ -1187,8 +1192,9 @@ static int smp_cmd_sign_info(struct l2cap_conn *conn, struct sk_buff *skb) return 0; } -int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb) +static int smp_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb) { + struct l2cap_conn *conn = chan->conn; struct hci_conn *hcon = conn->hcon; __u8 code, reason; int err = 0; @@ -1290,7 +1296,8 @@ done: static void smp_notify_keys(struct l2cap_conn *conn) { - struct smp_chan *smp = conn->smp_chan; + struct l2cap_chan *chan = conn->smp; + struct smp_chan *smp = chan->data; struct hci_conn *hcon = conn->hcon; struct hci_dev *hdev = hcon->hdev; struct smp_cmd_pairing *req = (void *) &smp->preq[1]; @@ -1357,7 +1364,8 @@ static void smp_notify_keys(struct l2cap_conn *conn) int smp_distribute_keys(struct l2cap_conn *conn) { struct smp_cmd_pairing *req, *rsp; - struct smp_chan *smp = conn->smp_chan; + struct l2cap_chan *chan = conn->smp; + struct smp_chan *smp = chan->data; struct hci_conn *hcon = conn->hcon; struct hci_dev *hdev = hcon->hdev; __u8 *keydist; @@ -1475,6 +1483,11 @@ static void smp_teardown_cb(struct l2cap_chan *chan, int err) BT_DBG("chan %p", chan); + if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) { + cancel_delayed_work_sync(&conn->security_timer); + smp_chan_destroy(conn); + } + conn->smp = NULL; l2cap_chan_put(chan); } @@ -1508,11 +1521,11 @@ static struct sk_buff *smp_alloc_skb_cb(struct l2cap_chan *chan, static const struct l2cap_ops smp_chan_ops = { .name = "Security Manager", .ready = smp_ready_cb, + .recv = smp_recv_cb, .alloc_skb = smp_alloc_skb_cb, .teardown = smp_teardown_cb, .new_connection = l2cap_chan_no_new_connection, - .recv = l2cap_chan_no_recv, .state_change = l2cap_chan_no_state_change, .close = l2cap_chan_no_close, .defer = l2cap_chan_no_defer, @@ -1587,10 +1600,7 @@ int smp_register(struct hci_dev *hdev) chan->data = tfm_aes; - /* FIXME: Using reserved 0x1f value for now - to be changed to - * L2CAP_CID_SMP once all functionality is in place. - */ - l2cap_add_scid(chan, 0x1f); + l2cap_add_scid(chan, L2CAP_CID_SMP); l2cap_chan_set_defaults(chan); diff --git a/net/bluetooth/smp.h b/net/bluetooth/smp.h index d3f6bd617940..161ace3c3234 100644 --- a/net/bluetooth/smp.h +++ b/net/bluetooth/smp.h @@ -126,7 +126,6 @@ enum { /* SMP Commands */ bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level); int smp_conn_security(struct hci_conn *hcon, __u8 sec_level); -int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb); int smp_distribute_keys(struct l2cap_conn *conn); int smp_user_confirm_reply(struct hci_conn *conn, u16 mgmt_op, __le32 passkey); From 4807b51895dce8aa650ebebc51fa4a795ed6b8b8 Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Fri, 8 Aug 2014 19:07:16 +0200 Subject: [PATCH 27/48] Bluetooth: Fix HCI H5 corrupted ack value In this expression: seq = (seq - 1) % 8 seq (u8) is implicitly converted to an int in the arithmetic operation. So if seq value is 0, operation is ((0 - 1) % 8) => (-1 % 8) => -1. The new seq value is 0xff which is an invalid ACK value, we expect 0x07. It leads to frequent dropped ACK and retransmission. Fix this by using '&' binary operator instead of '%'. Signed-off-by: Loic Poulain Signed-off-by: Marcel Holtmann Cc: stable@vger.kernel.org --- drivers/bluetooth/hci_h5.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c index caacb422995d..a22838669b4e 100644 --- a/drivers/bluetooth/hci_h5.c +++ b/drivers/bluetooth/hci_h5.c @@ -237,7 +237,7 @@ static void h5_pkt_cull(struct h5 *h5) break; to_remove--; - seq = (seq - 1) % 8; + seq = (seq - 1) & 0x07; } if (seq != h5->rx_ack) From ebef9c1236170fb3ba4dc05ccb41f6d842eb1c12 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Fri, 8 Aug 2014 17:32:45 +0530 Subject: [PATCH 28/48] MAINTAINERS: update maintainers info adds the mailing list address for bluetooth 6loWPAN and IEEE-802.15.4 subsystems. Also adds web page info. Signed-off-by: Varka Bhadram Signed-off-by: Marcel Holtmann --- MAINTAINERS | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 2f85f55c8fb8..5cc0b81e4a33 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -152,8 +152,8 @@ F: drivers/scsi/53c700* 6LOWPAN GENERIC (BTLE/IEEE 802.15.4) M: Alexander Aring -L: linux-zigbee-devel@lists.sourceforge.net (moderated for non-subscribers) L: linux-bluetooth@vger.kernel.org +L: linux-wpan@vger.kernel.org S: Maintained F: net/6lowpan/ F: include/net/6lowpan.h @@ -4564,13 +4564,14 @@ F: drivers/idle/i7300_idle.c IEEE 802.15.4 SUBSYSTEM M: Alexander Aring -L: linux-zigbee-devel@lists.sourceforge.net (moderated for non-subscribers) -W: http://apps.sourceforge.net/trac/linux-zigbee -T: git git://git.kernel.org/pub/scm/linux/kernel/git/lowpan/lowpan.git +L: linux-wpan@vger.kernel.org +W: https://github.com/linux-wpan +T: git git://github.com/linux-wpan/linux-wpan-next.git S: Maintained F: net/ieee802154/ F: net/mac802154/ F: drivers/net/ieee802154/ +F: Documentation/networking/ieee802154.txt IGUANAWORKS USB IR TRANSCEIVER M: Sean Young From 89d2975fa06e66ea0d3665d91f799fb1ce4b8bad Mon Sep 17 00:00:00 2001 From: Vincent Zwanenburg Date: Fri, 8 Aug 2014 12:33:56 +0100 Subject: [PATCH 29/48] Add a new PID/VID 0227/0930 for AR3012. usb devices info: T: Bus=01 Lev=02 Prnt=05 Port=00 Cnt=01 Dev#= 20 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0930 ProdID=0227 Rev= 0.02 C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA A: FirstIf#= 0 IfCount= 2 Cls=e0(wlcon) Sub=01 Prot=01 I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms Signed-off-by: Vincent Zwanenburg Signed-off-by: Marcel Holtmann --- drivers/bluetooth/ath3k.c | 2 ++ drivers/bluetooth/btusb.c | 1 + 2 files changed, 3 insertions(+) diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index a0d7355ef127..d85ced27ebd5 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -88,6 +88,7 @@ static const struct usb_device_id ath3k_table[] = { { USB_DEVICE(0x04CA, 0x300b) }, { USB_DEVICE(0x0930, 0x0219) }, { USB_DEVICE(0x0930, 0x0220) }, + { USB_DEVICE(0x0930, 0x0227) }, { USB_DEVICE(0x0b05, 0x17d0) }, { USB_DEVICE(0x0CF3, 0x0036) }, { USB_DEVICE(0x0CF3, 0x3004) }, @@ -138,6 +139,7 @@ static const struct usb_device_id ath3k_blist_tbl[] = { { USB_DEVICE(0x04ca, 0x300b), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0930, 0x0227), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0b05, 0x17d0), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0CF3, 0x0036), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 }, diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 292c38e8aa17..0527b29c3954 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -165,6 +165,7 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x04ca, 0x300b), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0930, 0x0227), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0b05, 0x17d0), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x0036), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 }, From 44f1a7ab51ebe1ca189445837e0599a5edc6efb1 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 11 Aug 2014 22:06:36 +0300 Subject: [PATCH 30/48] Bluetooth: Use L2CAP resume callback to call smp_distribute_keys There's no need to export the smp_distribute_keys() function since the resume callback is called in the same scenario. This patch makes the smp_notify_keys function private (at the same time moving it higher up in smp.c to avoid forward declarations) and adds a resume callback for SMP to call it from there instead. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 6 - net/bluetooth/smp.c | 380 +++++++++++++++++++------------------ net/bluetooth/smp.h | 1 - 3 files changed, 196 insertions(+), 191 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 40b6c06ab2c0..4de1e1827055 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -7281,12 +7281,6 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) BT_DBG("conn %p status 0x%2.2x encrypt %u", conn, status, encrypt); - if (hcon->type == LE_LINK) { - if (!status && encrypt) - smp_distribute_keys(conn); - cancel_delayed_work(&conn->security_timer); - } - mutex_lock(&conn->chan_lock); list_for_each_entry(chan, &conn->chan_l, list) { diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 744f678ac3e8..28014ad3d2d3 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -575,6 +575,189 @@ static u8 smp_random(struct smp_chan *smp) return 0; } +static void smp_notify_keys(struct l2cap_conn *conn) +{ + struct l2cap_chan *chan = conn->smp; + struct smp_chan *smp = chan->data; + struct hci_conn *hcon = conn->hcon; + struct hci_dev *hdev = hcon->hdev; + struct smp_cmd_pairing *req = (void *) &smp->preq[1]; + struct smp_cmd_pairing *rsp = (void *) &smp->prsp[1]; + bool persistent; + + if (smp->remote_irk) { + mgmt_new_irk(hdev, smp->remote_irk); + /* Now that user space can be considered to know the + * identity address track the connection based on it + * from now on. + */ + bacpy(&hcon->dst, &smp->remote_irk->bdaddr); + hcon->dst_type = smp->remote_irk->addr_type; + l2cap_conn_update_id_addr(hcon); + + /* When receiving an indentity resolving key for + * a remote device that does not use a resolvable + * private address, just remove the key so that + * it is possible to use the controller white + * list for scanning. + * + * Userspace will have been told to not store + * this key at this point. So it is safe to + * just remove it. + */ + if (!bacmp(&smp->remote_irk->rpa, BDADDR_ANY)) { + list_del(&smp->remote_irk->list); + kfree(smp->remote_irk); + smp->remote_irk = NULL; + } + } + + /* The LTKs and CSRKs should be persistent only if both sides + * had the bonding bit set in their authentication requests. + */ + persistent = !!((req->auth_req & rsp->auth_req) & SMP_AUTH_BONDING); + + if (smp->csrk) { + smp->csrk->bdaddr_type = hcon->dst_type; + bacpy(&smp->csrk->bdaddr, &hcon->dst); + mgmt_new_csrk(hdev, smp->csrk, persistent); + } + + if (smp->slave_csrk) { + smp->slave_csrk->bdaddr_type = hcon->dst_type; + bacpy(&smp->slave_csrk->bdaddr, &hcon->dst); + mgmt_new_csrk(hdev, smp->slave_csrk, persistent); + } + + if (smp->ltk) { + smp->ltk->bdaddr_type = hcon->dst_type; + bacpy(&smp->ltk->bdaddr, &hcon->dst); + mgmt_new_ltk(hdev, smp->ltk, persistent); + } + + if (smp->slave_ltk) { + smp->slave_ltk->bdaddr_type = hcon->dst_type; + bacpy(&smp->slave_ltk->bdaddr, &hcon->dst); + mgmt_new_ltk(hdev, smp->slave_ltk, persistent); + } +} + +static int smp_distribute_keys(struct l2cap_conn *conn) +{ + struct smp_cmd_pairing *req, *rsp; + struct l2cap_chan *chan = conn->smp; + struct smp_chan *smp = chan->data; + struct hci_conn *hcon = conn->hcon; + struct hci_dev *hdev = hcon->hdev; + __u8 *keydist; + + BT_DBG("conn %p", conn); + + if (!test_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) + return 0; + + rsp = (void *) &smp->prsp[1]; + + /* The responder sends its keys first */ + if (hcon->out && (smp->remote_key_dist & 0x07)) + return 0; + + req = (void *) &smp->preq[1]; + + if (hcon->out) { + keydist = &rsp->init_key_dist; + *keydist &= req->init_key_dist; + } else { + keydist = &rsp->resp_key_dist; + *keydist &= req->resp_key_dist; + } + + BT_DBG("keydist 0x%x", *keydist); + + if (*keydist & SMP_DIST_ENC_KEY) { + struct smp_cmd_encrypt_info enc; + struct smp_cmd_master_ident ident; + struct smp_ltk *ltk; + u8 authenticated; + __le16 ediv; + __le64 rand; + + get_random_bytes(enc.ltk, sizeof(enc.ltk)); + get_random_bytes(&ediv, sizeof(ediv)); + get_random_bytes(&rand, sizeof(rand)); + + smp_send_cmd(conn, SMP_CMD_ENCRYPT_INFO, sizeof(enc), &enc); + + authenticated = hcon->sec_level == BT_SECURITY_HIGH; + ltk = hci_add_ltk(hdev, &hcon->dst, hcon->dst_type, + SMP_LTK_SLAVE, authenticated, enc.ltk, + smp->enc_key_size, ediv, rand); + smp->slave_ltk = ltk; + + ident.ediv = ediv; + ident.rand = rand; + + smp_send_cmd(conn, SMP_CMD_MASTER_IDENT, sizeof(ident), &ident); + + *keydist &= ~SMP_DIST_ENC_KEY; + } + + if (*keydist & SMP_DIST_ID_KEY) { + struct smp_cmd_ident_addr_info addrinfo; + struct smp_cmd_ident_info idinfo; + + memcpy(idinfo.irk, hdev->irk, sizeof(idinfo.irk)); + + smp_send_cmd(conn, SMP_CMD_IDENT_INFO, sizeof(idinfo), &idinfo); + + /* The hci_conn contains the local identity address + * after the connection has been established. + * + * This is true even when the connection has been + * established using a resolvable random address. + */ + bacpy(&addrinfo.bdaddr, &hcon->src); + addrinfo.addr_type = hcon->src_type; + + smp_send_cmd(conn, SMP_CMD_IDENT_ADDR_INFO, sizeof(addrinfo), + &addrinfo); + + *keydist &= ~SMP_DIST_ID_KEY; + } + + if (*keydist & SMP_DIST_SIGN) { + struct smp_cmd_sign_info sign; + struct smp_csrk *csrk; + + /* Generate a new random key */ + get_random_bytes(sign.csrk, sizeof(sign.csrk)); + + csrk = kzalloc(sizeof(*csrk), GFP_KERNEL); + if (csrk) { + csrk->master = 0x00; + memcpy(csrk->val, sign.csrk, sizeof(csrk->val)); + } + smp->slave_csrk = csrk; + + smp_send_cmd(conn, SMP_CMD_SIGN_INFO, sizeof(sign), &sign); + + *keydist &= ~SMP_DIST_SIGN; + } + + /* If there are still keys to be received wait for them */ + if ((smp->remote_key_dist & 0x07)) + return 0; + + clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags); + cancel_delayed_work_sync(&conn->security_timer); + set_bit(SMP_FLAG_COMPLETE, &smp->flags); + smp_notify_keys(conn); + + smp_chan_destroy(conn); + + return 0; +} + static struct smp_chan *smp_chan_create(struct l2cap_conn *conn) { struct l2cap_chan *chan = conn->smp; @@ -1294,189 +1477,6 @@ done: return err; } -static void smp_notify_keys(struct l2cap_conn *conn) -{ - struct l2cap_chan *chan = conn->smp; - struct smp_chan *smp = chan->data; - struct hci_conn *hcon = conn->hcon; - struct hci_dev *hdev = hcon->hdev; - struct smp_cmd_pairing *req = (void *) &smp->preq[1]; - struct smp_cmd_pairing *rsp = (void *) &smp->prsp[1]; - bool persistent; - - if (smp->remote_irk) { - mgmt_new_irk(hdev, smp->remote_irk); - /* Now that user space can be considered to know the - * identity address track the connection based on it - * from now on. - */ - bacpy(&hcon->dst, &smp->remote_irk->bdaddr); - hcon->dst_type = smp->remote_irk->addr_type; - l2cap_conn_update_id_addr(hcon); - - /* When receiving an indentity resolving key for - * a remote device that does not use a resolvable - * private address, just remove the key so that - * it is possible to use the controller white - * list for scanning. - * - * Userspace will have been told to not store - * this key at this point. So it is safe to - * just remove it. - */ - if (!bacmp(&smp->remote_irk->rpa, BDADDR_ANY)) { - list_del(&smp->remote_irk->list); - kfree(smp->remote_irk); - smp->remote_irk = NULL; - } - } - - /* The LTKs and CSRKs should be persistent only if both sides - * had the bonding bit set in their authentication requests. - */ - persistent = !!((req->auth_req & rsp->auth_req) & SMP_AUTH_BONDING); - - if (smp->csrk) { - smp->csrk->bdaddr_type = hcon->dst_type; - bacpy(&smp->csrk->bdaddr, &hcon->dst); - mgmt_new_csrk(hdev, smp->csrk, persistent); - } - - if (smp->slave_csrk) { - smp->slave_csrk->bdaddr_type = hcon->dst_type; - bacpy(&smp->slave_csrk->bdaddr, &hcon->dst); - mgmt_new_csrk(hdev, smp->slave_csrk, persistent); - } - - if (smp->ltk) { - smp->ltk->bdaddr_type = hcon->dst_type; - bacpy(&smp->ltk->bdaddr, &hcon->dst); - mgmt_new_ltk(hdev, smp->ltk, persistent); - } - - if (smp->slave_ltk) { - smp->slave_ltk->bdaddr_type = hcon->dst_type; - bacpy(&smp->slave_ltk->bdaddr, &hcon->dst); - mgmt_new_ltk(hdev, smp->slave_ltk, persistent); - } -} - -int smp_distribute_keys(struct l2cap_conn *conn) -{ - struct smp_cmd_pairing *req, *rsp; - struct l2cap_chan *chan = conn->smp; - struct smp_chan *smp = chan->data; - struct hci_conn *hcon = conn->hcon; - struct hci_dev *hdev = hcon->hdev; - __u8 *keydist; - - BT_DBG("conn %p", conn); - - if (!test_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) - return 0; - - rsp = (void *) &smp->prsp[1]; - - /* The responder sends its keys first */ - if (hcon->out && (smp->remote_key_dist & 0x07)) - return 0; - - req = (void *) &smp->preq[1]; - - if (hcon->out) { - keydist = &rsp->init_key_dist; - *keydist &= req->init_key_dist; - } else { - keydist = &rsp->resp_key_dist; - *keydist &= req->resp_key_dist; - } - - BT_DBG("keydist 0x%x", *keydist); - - if (*keydist & SMP_DIST_ENC_KEY) { - struct smp_cmd_encrypt_info enc; - struct smp_cmd_master_ident ident; - struct smp_ltk *ltk; - u8 authenticated; - __le16 ediv; - __le64 rand; - - get_random_bytes(enc.ltk, sizeof(enc.ltk)); - get_random_bytes(&ediv, sizeof(ediv)); - get_random_bytes(&rand, sizeof(rand)); - - smp_send_cmd(conn, SMP_CMD_ENCRYPT_INFO, sizeof(enc), &enc); - - authenticated = hcon->sec_level == BT_SECURITY_HIGH; - ltk = hci_add_ltk(hdev, &hcon->dst, hcon->dst_type, - SMP_LTK_SLAVE, authenticated, enc.ltk, - smp->enc_key_size, ediv, rand); - smp->slave_ltk = ltk; - - ident.ediv = ediv; - ident.rand = rand; - - smp_send_cmd(conn, SMP_CMD_MASTER_IDENT, sizeof(ident), &ident); - - *keydist &= ~SMP_DIST_ENC_KEY; - } - - if (*keydist & SMP_DIST_ID_KEY) { - struct smp_cmd_ident_addr_info addrinfo; - struct smp_cmd_ident_info idinfo; - - memcpy(idinfo.irk, hdev->irk, sizeof(idinfo.irk)); - - smp_send_cmd(conn, SMP_CMD_IDENT_INFO, sizeof(idinfo), &idinfo); - - /* The hci_conn contains the local identity address - * after the connection has been established. - * - * This is true even when the connection has been - * established using a resolvable random address. - */ - bacpy(&addrinfo.bdaddr, &hcon->src); - addrinfo.addr_type = hcon->src_type; - - smp_send_cmd(conn, SMP_CMD_IDENT_ADDR_INFO, sizeof(addrinfo), - &addrinfo); - - *keydist &= ~SMP_DIST_ID_KEY; - } - - if (*keydist & SMP_DIST_SIGN) { - struct smp_cmd_sign_info sign; - struct smp_csrk *csrk; - - /* Generate a new random key */ - get_random_bytes(sign.csrk, sizeof(sign.csrk)); - - csrk = kzalloc(sizeof(*csrk), GFP_KERNEL); - if (csrk) { - csrk->master = 0x00; - memcpy(csrk->val, sign.csrk, sizeof(csrk->val)); - } - smp->slave_csrk = csrk; - - smp_send_cmd(conn, SMP_CMD_SIGN_INFO, sizeof(sign), &sign); - - *keydist &= ~SMP_DIST_SIGN; - } - - /* If there are still keys to be received wait for them */ - if ((smp->remote_key_dist & 0x07)) - return 0; - - clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags); - cancel_delayed_work_sync(&conn->security_timer); - set_bit(SMP_FLAG_COMPLETE, &smp->flags); - smp_notify_keys(conn); - - smp_chan_destroy(conn); - - return 0; -} - static void smp_teardown_cb(struct l2cap_chan *chan, int err) { struct l2cap_conn *conn = chan->conn; @@ -1492,6 +1492,18 @@ static void smp_teardown_cb(struct l2cap_chan *chan, int err) l2cap_chan_put(chan); } +static void smp_resume_cb(struct l2cap_chan *chan) +{ + struct l2cap_conn *conn = chan->conn; + struct hci_conn *hcon = conn->hcon; + + BT_DBG("chan %p", chan); + + if (test_bit(HCI_CONN_ENCRYPT, &hcon->flags)) + smp_distribute_keys(conn); + cancel_delayed_work(&conn->security_timer); +} + static void smp_ready_cb(struct l2cap_chan *chan) { struct l2cap_conn *conn = chan->conn; @@ -1524,13 +1536,13 @@ static const struct l2cap_ops smp_chan_ops = { .recv = smp_recv_cb, .alloc_skb = smp_alloc_skb_cb, .teardown = smp_teardown_cb, + .resume = smp_resume_cb, .new_connection = l2cap_chan_no_new_connection, .state_change = l2cap_chan_no_state_change, .close = l2cap_chan_no_close, .defer = l2cap_chan_no_defer, .suspend = l2cap_chan_no_suspend, - .resume = l2cap_chan_no_resume, .set_shutdown = l2cap_chan_no_set_shutdown, .get_sndtimeo = l2cap_chan_no_get_sndtimeo, .memcpy_fromiovec = l2cap_chan_no_memcpy_fromiovec, diff --git a/net/bluetooth/smp.h b/net/bluetooth/smp.h index 161ace3c3234..59a594278a85 100644 --- a/net/bluetooth/smp.h +++ b/net/bluetooth/smp.h @@ -126,7 +126,6 @@ enum { /* SMP Commands */ bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level); int smp_conn_security(struct hci_conn *hcon, __u8 sec_level); -int smp_distribute_keys(struct l2cap_conn *conn); int smp_user_confirm_reply(struct hci_conn *conn, u16 mgmt_op, __le32 passkey); void smp_chan_destroy(struct l2cap_conn *conn); From dec5b49235e2526d7aacf5b93ea48f5e30c2f7c3 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 11 Aug 2014 22:06:37 +0300 Subject: [PATCH 31/48] Bluetooth: Add public l2cap_conn_shutdown() API to request disconnection Since we no-longer do special handling of SMP within l2cap_core.c we don't have any code for calling l2cap_conn_del() when smp.c doesn't like the data it gets. At the same time we cannot simply export l2cap_conn_del() since it will try to lock the channels it calls into whereas we already hold the lock in the smp.c l2cap_chan callbacks (i.e. it'd lead to a deadlock). This patch adds a new l2cap_conn_shutdown() API which is very similar to l2cap_conn_del() except that it defers the call to l2cap_conn_del() through a workqueue, thereby making it safe to use it from an L2CAP channel callback. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 4 ++++ net/bluetooth/l2cap_core.c | 25 +++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index bda6252e3722..40f34866b6da 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -625,6 +625,9 @@ struct l2cap_conn { struct delayed_work info_timer; + int disconn_err; + struct work_struct disconn_work; + struct sk_buff *rx_skb; __u32 rx_len; __u8 tx_ident; @@ -944,6 +947,7 @@ void l2cap_logical_cfm(struct l2cap_chan *chan, struct hci_chan *hchan, u8 status); void __l2cap_physical_cfm(struct l2cap_chan *chan, int result); +void l2cap_conn_shutdown(struct l2cap_conn *conn, int err); void l2cap_conn_get(struct l2cap_conn *conn); void l2cap_conn_put(struct l2cap_conn *conn); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 4de1e1827055..404998efa7e2 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1627,6 +1627,9 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) if (work_pending(&conn->pending_rx_work)) cancel_work_sync(&conn->pending_rx_work); + if (work_pending(&conn->disconn_work)) + cancel_work_sync(&conn->disconn_work); + l2cap_unregister_all_users(conn); mutex_lock(&conn->chan_lock); @@ -1669,6 +1672,26 @@ static void security_timeout(struct work_struct *work) } } +static void disconn_work(struct work_struct *work) +{ + struct l2cap_conn *conn = container_of(work, struct l2cap_conn, + disconn_work); + + BT_DBG("conn %p", conn); + + l2cap_conn_del(conn->hcon, conn->disconn_err); +} + +void l2cap_conn_shutdown(struct l2cap_conn *conn, int err) +{ + struct hci_dev *hdev = conn->hcon->hdev; + + BT_DBG("conn %p err %d", conn, err); + + conn->disconn_err = err; + queue_work(hdev->workqueue, &conn->disconn_work); +} + static void l2cap_conn_free(struct kref *ref) { struct l2cap_conn *conn = container_of(ref, struct l2cap_conn, ref); @@ -6930,6 +6953,8 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon) else INIT_DELAYED_WORK(&conn->info_timer, l2cap_info_timeout); + INIT_WORK(&conn->disconn_work, disconn_work); + skb_queue_head_init(&conn->pending_rx); INIT_WORK(&conn->pending_rx_work, process_pending_rx); From 4befb867b9de8adc56c683f4cf6c9e6c035e94e3 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 11 Aug 2014 22:06:38 +0300 Subject: [PATCH 32/48] Bluetooth: Call l2cap_conn_shutdown() when SMP recv callback fails To restore pre-l2cap_chan functionality we should be trying to disconnect the connection when receviving garbage SMP data (i.e. when the SMP command handler fails). This patch renames the command handler back to smp_sig_channel() and adds a smp_recv_cb() wrapper function for calling it. If smp_sig_channel() fails the code calls l2cap_conn_shutdown(). Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 28014ad3d2d3..7a295d7edc44 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -1375,7 +1375,7 @@ static int smp_cmd_sign_info(struct l2cap_conn *conn, struct sk_buff *skb) return 0; } -static int smp_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb) +static int smp_sig_channel(struct l2cap_chan *chan, struct sk_buff *skb) { struct l2cap_conn *conn = chan->conn; struct hci_conn *hcon = conn->hcon; @@ -1514,6 +1514,24 @@ static void smp_ready_cb(struct l2cap_chan *chan) l2cap_chan_hold(chan); } +static int smp_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb) +{ + int err; + + BT_DBG("chan %p", chan); + + err = smp_sig_channel(chan, skb); + if (err) { + struct l2cap_conn *conn = chan->conn; + + cancel_delayed_work_sync(&conn->security_timer); + + l2cap_conn_shutdown(chan->conn, -err); + } + + return err; +} + static struct sk_buff *smp_alloc_skb_cb(struct l2cap_chan *chan, unsigned long hdr_len, unsigned long len, int nb) From 8ae9b9845b3252216cf5d2e033e5cca41bae48ef Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 11 Aug 2014 22:06:39 +0300 Subject: [PATCH 33/48] Bluetooth: Fix double free of SMP data skb In the case that the SMP recv callback returns error the calling code in l2cap_core.c expects that it still owns the skb and will try to free it. The SMP code should therefore not try to free the skb if it return an error. This patch fixes such behavior in the SMP command handler function. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 7a295d7edc44..5103dc739a17 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -1387,10 +1387,8 @@ static int smp_sig_channel(struct l2cap_chan *chan, struct sk_buff *skb) return 0; } - if (skb->len < 1) { - kfree_skb(skb); + if (skb->len < 1) return -EILSEQ; - } if (!test_bit(HCI_LE_ENABLED, &hcon->hdev->dev_flags)) { err = -EOPNOTSUPP; @@ -1410,8 +1408,9 @@ static int smp_sig_channel(struct l2cap_chan *chan, struct sk_buff *skb) if (code != SMP_CMD_PAIRING_REQ && code != SMP_CMD_SECURITY_REQ && !test_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) { BT_ERR("Unexpected SMP command 0x%02x. Disconnecting.", code); - kfree_skb(skb); - return -EOPNOTSUPP; + reason = SMP_CMD_NOTSUPP; + err = -EOPNOTSUPP; + goto done; } switch (code) { @@ -1472,8 +1471,8 @@ static int smp_sig_channel(struct l2cap_chan *chan, struct sk_buff *skb) done: if (reason) smp_failure(conn, reason); - - kfree_skb(skb); + if (!err) + kfree_skb(skb); return err; } From b68fda6848ebef3499905500971d40b84faa8319 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 11 Aug 2014 22:06:40 +0300 Subject: [PATCH 34/48] Bluetooth: Add SMP-internal timeout callback This patch adds an SMP-internal timeout callback to remove the depenency on (the soon to be removed) l2cap_conn->security_timer. The behavior is the same as with l2cap_conn->security_timer except that the new l2cap_conn_shutdown() public function is used instead of the L2CAP core internal l2cap_conn_del(). Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 52 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 43 insertions(+), 9 deletions(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 5103dc739a17..7ab5f52955cb 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -44,7 +44,9 @@ enum { }; struct smp_chan { - struct l2cap_conn *conn; + struct l2cap_conn *conn; + struct delayed_work security_timer; + u8 preq[7]; /* SMP Pairing Request */ u8 prsp[7]; /* SMP Pairing Response */ u8 prnd[16]; /* SMP Pairing Random (local) */ @@ -251,6 +253,7 @@ static int smp_s1(struct smp_chan *smp, u8 k[16], u8 r1[16], u8 r2[16], static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data) { struct l2cap_chan *chan = conn->smp; + struct smp_chan *smp; struct kvec iv[2]; struct msghdr msg; @@ -272,8 +275,14 @@ static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data) l2cap_chan_send(chan, &msg, 1 + len); - cancel_delayed_work_sync(&conn->security_timer); - schedule_delayed_work(&conn->security_timer, SMP_TIMEOUT); + if (!chan->data) + return; + + smp = chan->data; + + cancel_delayed_work_sync(&smp->security_timer); + if (test_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) + schedule_delayed_work(&smp->security_timer, SMP_TIMEOUT); } static __u8 authreq_to_seclevel(__u8 authreq) @@ -359,6 +368,8 @@ static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size) static void smp_failure(struct l2cap_conn *conn, u8 reason) { struct hci_conn *hcon = conn->hcon; + struct l2cap_chan *chan = conn->smp; + struct smp_chan *smp; if (reason) smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason), @@ -368,7 +379,12 @@ static void smp_failure(struct l2cap_conn *conn, u8 reason) mgmt_auth_failed(hcon->hdev, &hcon->dst, hcon->type, hcon->dst_type, HCI_ERROR_AUTH_FAILURE); - cancel_delayed_work_sync(&conn->security_timer); + if (!chan->data) + return; + + smp = chan->data; + + cancel_delayed_work_sync(&smp->security_timer); if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) smp_chan_destroy(conn); @@ -749,7 +765,7 @@ static int smp_distribute_keys(struct l2cap_conn *conn) return 0; clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags); - cancel_delayed_work_sync(&conn->security_timer); + cancel_delayed_work_sync(&smp->security_timer); set_bit(SMP_FLAG_COMPLETE, &smp->flags); smp_notify_keys(conn); @@ -758,6 +774,17 @@ static int smp_distribute_keys(struct l2cap_conn *conn) return 0; } +static void smp_timeout(struct work_struct *work) +{ + struct smp_chan *smp = container_of(work, struct smp_chan, + security_timer.work); + struct l2cap_conn *conn = smp->conn; + + BT_DBG("conn %p", conn); + + l2cap_conn_shutdown(conn, ETIMEDOUT); +} + static struct smp_chan *smp_chan_create(struct l2cap_conn *conn) { struct l2cap_chan *chan = conn->smp; @@ -780,6 +807,8 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn) smp->conn = conn; chan->data = smp; + INIT_DELAYED_WORK(&smp->security_timer, smp_timeout); + hci_conn_hold(conn->hcon); return smp; @@ -1479,11 +1508,12 @@ done: static void smp_teardown_cb(struct l2cap_chan *chan, int err) { struct l2cap_conn *conn = chan->conn; + struct smp_chan *smp = chan->data; BT_DBG("chan %p", chan); if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) { - cancel_delayed_work_sync(&conn->security_timer); + cancel_delayed_work_sync(&smp->security_timer); smp_chan_destroy(conn); } @@ -1493,6 +1523,7 @@ static void smp_teardown_cb(struct l2cap_chan *chan, int err) static void smp_resume_cb(struct l2cap_chan *chan) { + struct smp_chan *smp = chan->data; struct l2cap_conn *conn = chan->conn; struct hci_conn *hcon = conn->hcon; @@ -1500,7 +1531,9 @@ static void smp_resume_cb(struct l2cap_chan *chan) if (test_bit(HCI_CONN_ENCRYPT, &hcon->flags)) smp_distribute_keys(conn); - cancel_delayed_work(&conn->security_timer); + + if (smp) + cancel_delayed_work(&smp->security_timer); } static void smp_ready_cb(struct l2cap_chan *chan) @@ -1521,9 +1554,10 @@ static int smp_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb) err = smp_sig_channel(chan, skb); if (err) { - struct l2cap_conn *conn = chan->conn; + struct smp_chan *smp = chan->data; - cancel_delayed_work_sync(&conn->security_timer); + if (smp) + cancel_delayed_work_sync(&smp->security_timer); l2cap_conn_shutdown(chan->conn, -err); } From 276d807317dead63ef2f13aa46e3c17d57ba0713 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 11 Aug 2014 22:06:41 +0300 Subject: [PATCH 35/48] Bluetooth: Remove unused l2cap_conn->security_timer Now that there are no-longer any users for l2cap_conn->security_timer we can go ahead and simply remove it. The patch makes initialization of the conn->info_timer unconditional since it's better not to leave any l2cap_conn data structures uninitialized no matter what the underlying transport. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 1 - net/bluetooth/l2cap_core.c | 18 +----------------- 2 files changed, 1 insertion(+), 18 deletions(-) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 40f34866b6da..cedda399f9c0 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -638,7 +638,6 @@ struct l2cap_conn { __u8 disc_reason; - struct delayed_work security_timer; struct l2cap_chan *smp; struct list_head chan_l; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 404998efa7e2..0cd7ed99558b 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1659,19 +1659,6 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) l2cap_conn_put(conn); } -static void security_timeout(struct work_struct *work) -{ - struct l2cap_conn *conn = container_of(work, struct l2cap_conn, - security_timer.work); - - BT_DBG("conn %p", conn); - - if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) { - smp_chan_destroy(conn); - l2cap_conn_del(conn->hcon, ETIMEDOUT); - } -} - static void disconn_work(struct work_struct *work) { struct l2cap_conn *conn = container_of(work, struct l2cap_conn, @@ -6948,10 +6935,7 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon) INIT_LIST_HEAD(&conn->chan_l); INIT_LIST_HEAD(&conn->users); - if (hcon->type == LE_LINK) - INIT_DELAYED_WORK(&conn->security_timer, security_timeout); - else - INIT_DELAYED_WORK(&conn->info_timer, l2cap_info_timeout); + INIT_DELAYED_WORK(&conn->info_timer, l2cap_info_timeout); INIT_WORK(&conn->disconn_work, disconn_work); From 109ec2309eb996fbe03302fbd40dec9014c6f849 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 11 Aug 2014 22:06:42 +0300 Subject: [PATCH 36/48] Bluetooth: Move canceling security_timer into smp_chan_destroy() All places needing to cancel the security timer also call smp_chan_destroy() in the same go. To eliminate the need to do these two calls in multiple places simply move the timer cancellation into smp_chan_destroy(). Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 7ab5f52955cb..cdae40869447 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -384,8 +384,6 @@ static void smp_failure(struct l2cap_conn *conn, u8 reason) smp = chan->data; - cancel_delayed_work_sync(&smp->security_timer); - if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) smp_chan_destroy(conn); } @@ -765,7 +763,6 @@ static int smp_distribute_keys(struct l2cap_conn *conn) return 0; clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags); - cancel_delayed_work_sync(&smp->security_timer); set_bit(SMP_FLAG_COMPLETE, &smp->flags); smp_notify_keys(conn); @@ -822,6 +819,11 @@ void smp_chan_destroy(struct l2cap_conn *conn) BUG_ON(!smp); + cancel_delayed_work_sync(&smp->security_timer); + /* In case the timeout freed the SMP context */ + if (!chan->data) + return; + complete = test_bit(SMP_FLAG_COMPLETE, &smp->flags); mgmt_smp_complete(conn->hcon, complete); @@ -1512,10 +1514,8 @@ static void smp_teardown_cb(struct l2cap_chan *chan, int err) BT_DBG("chan %p", chan); - if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) { - cancel_delayed_work_sync(&smp->security_timer); + if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) smp_chan_destroy(conn); - } conn->smp = NULL; l2cap_chan_put(chan); From 86d1407cb9cd3cb866eae24a2aedb8006160db69 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 11 Aug 2014 22:06:43 +0300 Subject: [PATCH 37/48] Bluetooth: Always call smp_distribute_keys() from a workqueue The smp_distribute_keys() function calls smp_notify_keys() which in turn calls l2cap_conn_update_id_addr(). The l2cap_conn_update_id_addr() function will iterate through all L2CAP channels for the respective connection: lock the channel, update the address information and unlock the channel. Since SMP is now using l2cap_chan callbacks each callback is called with the channel lock held. Therefore, calling l2cap_conn_update_id_addr() would cause a deadlock calling l2cap_chan_lock() on the SMP channel. This patch moves calling smp_distribute_keys() through a workqueue so that it is never called from an L2CAP channel callback. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 42 ++++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index cdae40869447..312ea5ec2d7d 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -46,6 +46,7 @@ enum { struct smp_chan { struct l2cap_conn *conn; struct delayed_work security_timer; + struct work_struct distribute_work; u8 preq[7]; /* SMP Pairing Request */ u8 prsp[7]; /* SMP Pairing Response */ @@ -656,11 +657,12 @@ static void smp_notify_keys(struct l2cap_conn *conn) } } -static int smp_distribute_keys(struct l2cap_conn *conn) +static void smp_distribute_keys(struct work_struct *work) { + struct smp_chan *smp = container_of(work, struct smp_chan, + distribute_work); struct smp_cmd_pairing *req, *rsp; - struct l2cap_chan *chan = conn->smp; - struct smp_chan *smp = chan->data; + struct l2cap_conn *conn = smp->conn; struct hci_conn *hcon = conn->hcon; struct hci_dev *hdev = hcon->hdev; __u8 *keydist; @@ -668,13 +670,13 @@ static int smp_distribute_keys(struct l2cap_conn *conn) BT_DBG("conn %p", conn); if (!test_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) - return 0; + return; rsp = (void *) &smp->prsp[1]; /* The responder sends its keys first */ if (hcon->out && (smp->remote_key_dist & 0x07)) - return 0; + return; req = (void *) &smp->preq[1]; @@ -760,15 +762,13 @@ static int smp_distribute_keys(struct l2cap_conn *conn) /* If there are still keys to be received wait for them */ if ((smp->remote_key_dist & 0x07)) - return 0; + return; clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags); set_bit(SMP_FLAG_COMPLETE, &smp->flags); smp_notify_keys(conn); smp_chan_destroy(conn); - - return 0; } static void smp_timeout(struct work_struct *work) @@ -804,6 +804,7 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn) smp->conn = conn; chan->data = smp; + INIT_WORK(&smp->distribute_work, smp_distribute_keys); INIT_DELAYED_WORK(&smp->security_timer, smp_timeout); hci_conn_hold(conn->hcon); @@ -824,6 +825,12 @@ void smp_chan_destroy(struct l2cap_conn *conn) if (!chan->data) return; + if (work_pending(&smp->distribute_work)) { + cancel_work_sync(&smp->distribute_work); + if (!chan->data) + return; + } + complete = test_bit(SMP_FLAG_COMPLETE, &smp->flags); mgmt_smp_complete(conn->hcon, complete); @@ -1287,7 +1294,7 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb) rp->ediv, rp->rand); smp->ltk = ltk; if (!(smp->remote_key_dist & SMP_DIST_ID_KEY)) - smp_distribute_keys(conn); + queue_work(hdev->workqueue, &smp->distribute_work); hci_dev_unlock(hdev); return 0; @@ -1322,6 +1329,7 @@ static int smp_cmd_ident_addr_info(struct l2cap_conn *conn, struct l2cap_chan *chan = conn->smp; struct smp_chan *smp = chan->data; struct hci_conn *hcon = conn->hcon; + struct hci_dev *hdev = hcon->hdev; bdaddr_t rpa; BT_DBG(""); @@ -1364,7 +1372,7 @@ static int smp_cmd_ident_addr_info(struct l2cap_conn *conn, smp->id_addr_type, smp->irk, &rpa); distribute: - smp_distribute_keys(conn); + queue_work(hdev->workqueue, &smp->distribute_work); hci_dev_unlock(hcon->hdev); @@ -1400,7 +1408,7 @@ static int smp_cmd_sign_info(struct l2cap_conn *conn, struct sk_buff *skb) memcpy(csrk->val, rp->csrk, sizeof(csrk->val)); } smp->csrk = csrk; - smp_distribute_keys(conn); + queue_work(hdev->workqueue, &smp->distribute_work); hci_dev_unlock(hdev); return 0; @@ -1510,7 +1518,6 @@ done: static void smp_teardown_cb(struct l2cap_chan *chan, int err) { struct l2cap_conn *conn = chan->conn; - struct smp_chan *smp = chan->data; BT_DBG("chan %p", chan); @@ -1526,14 +1533,17 @@ static void smp_resume_cb(struct l2cap_chan *chan) struct smp_chan *smp = chan->data; struct l2cap_conn *conn = chan->conn; struct hci_conn *hcon = conn->hcon; + struct hci_dev *hdev = hcon->hdev; BT_DBG("chan %p", chan); - if (test_bit(HCI_CONN_ENCRYPT, &hcon->flags)) - smp_distribute_keys(conn); + if (!smp) + return; - if (smp) - cancel_delayed_work(&smp->security_timer); + cancel_delayed_work(&smp->security_timer); + + if (test_bit(HCI_CONN_ENCRYPT, &hcon->flags)) + queue_work(hdev->workqueue, &smp->distribute_work); } static void smp_ready_cb(struct l2cap_chan *chan) From 6f48e260a95c1a0161e5be39adb0f20c737fe459 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 11 Aug 2014 22:06:44 +0300 Subject: [PATCH 38/48] Bluetooth: Make smp_chan_destroy() private to smp.c There are no external users of smp_chan_destroy() so make it private to smp.c. The patch also moves the function higher up in the c-file in order to avoid forward declarations. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 100 ++++++++++++++++++++++---------------------- net/bluetooth/smp.h | 2 - 2 files changed, 50 insertions(+), 52 deletions(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 312ea5ec2d7d..07ca4ce0943b 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -366,6 +366,56 @@ static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size) return 0; } +static void smp_chan_destroy(struct l2cap_conn *conn) +{ + struct l2cap_chan *chan = conn->smp; + struct smp_chan *smp = chan->data; + bool complete; + + BUG_ON(!smp); + + cancel_delayed_work_sync(&smp->security_timer); + /* In case the timeout freed the SMP context */ + if (!chan->data) + return; + + if (work_pending(&smp->distribute_work)) { + cancel_work_sync(&smp->distribute_work); + if (!chan->data) + return; + } + + complete = test_bit(SMP_FLAG_COMPLETE, &smp->flags); + mgmt_smp_complete(conn->hcon, complete); + + kfree(smp->csrk); + kfree(smp->slave_csrk); + + crypto_free_blkcipher(smp->tfm_aes); + + /* If pairing failed clean up any keys we might have */ + if (!complete) { + if (smp->ltk) { + list_del(&smp->ltk->list); + kfree(smp->ltk); + } + + if (smp->slave_ltk) { + list_del(&smp->slave_ltk->list); + kfree(smp->slave_ltk); + } + + if (smp->remote_irk) { + list_del(&smp->remote_irk->list); + kfree(smp->remote_irk); + } + } + + chan->data = NULL; + kfree(smp); + hci_conn_drop(conn->hcon); +} + static void smp_failure(struct l2cap_conn *conn, u8 reason) { struct hci_conn *hcon = conn->hcon; @@ -812,56 +862,6 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn) return smp; } -void smp_chan_destroy(struct l2cap_conn *conn) -{ - struct l2cap_chan *chan = conn->smp; - struct smp_chan *smp = chan->data; - bool complete; - - BUG_ON(!smp); - - cancel_delayed_work_sync(&smp->security_timer); - /* In case the timeout freed the SMP context */ - if (!chan->data) - return; - - if (work_pending(&smp->distribute_work)) { - cancel_work_sync(&smp->distribute_work); - if (!chan->data) - return; - } - - complete = test_bit(SMP_FLAG_COMPLETE, &smp->flags); - mgmt_smp_complete(conn->hcon, complete); - - kfree(smp->csrk); - kfree(smp->slave_csrk); - - crypto_free_blkcipher(smp->tfm_aes); - - /* If pairing failed clean up any keys we might have */ - if (!complete) { - if (smp->ltk) { - list_del(&smp->ltk->list); - kfree(smp->ltk); - } - - if (smp->slave_ltk) { - list_del(&smp->slave_ltk->list); - kfree(smp->slave_ltk); - } - - if (smp->remote_irk) { - list_del(&smp->remote_irk->list); - kfree(smp->remote_irk); - } - } - - chan->data = NULL; - kfree(smp); - hci_conn_drop(conn->hcon); -} - int smp_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, __le32 passkey) { struct l2cap_conn *conn = hcon->l2cap_data; diff --git a/net/bluetooth/smp.h b/net/bluetooth/smp.h index 59a594278a85..cf1094617c69 100644 --- a/net/bluetooth/smp.h +++ b/net/bluetooth/smp.h @@ -128,8 +128,6 @@ bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level); int smp_conn_security(struct hci_conn *hcon, __u8 sec_level); int smp_user_confirm_reply(struct hci_conn *conn, u16 mgmt_op, __le32 passkey); -void smp_chan_destroy(struct l2cap_conn *conn); - bool smp_irk_matches(struct hci_dev *hdev, u8 irk[16], bdaddr_t *bdaddr); int smp_generate_rpa(struct hci_dev *hdev, u8 irk[16], bdaddr_t *rpa); From 24bbd44a96c7a209fafbf1b28f0ac1a00cf4e551 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Mon, 11 Aug 2014 13:25:07 +0200 Subject: [PATCH 39/48] mac802154: cleanup in rx path This patch replace the sizeof(struct rx_work) with sizeof(*work) and directly passing the skb in mac802154_subif_rx() Signed-off-by: Varka Bhadram Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- net/mac802154/rx.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/net/mac802154/rx.c b/net/mac802154/rx.c index 7f820a108a9c..a14cf9ede171 100644 --- a/net/mac802154/rx.c +++ b/net/mac802154/rx.c @@ -86,9 +86,8 @@ fail: static void mac802154_rx_worker(struct work_struct *work) { struct rx_work *rw = container_of(work, struct rx_work, work); - struct sk_buff *skb = rw->skb; - mac802154_subif_rx(rw->dev, skb, rw->lqi); + mac802154_subif_rx(rw->dev, rw->skb, rw->lqi); kfree(rw); } @@ -101,7 +100,7 @@ ieee802154_rx_irqsafe(struct ieee802154_dev *dev, struct sk_buff *skb, u8 lqi) if (!skb) return; - work = kzalloc(sizeof(struct rx_work), GFP_ATOMIC); + work = kzalloc(sizeof(*work), GFP_ATOMIC); if (!work) return; From b288a4963f09459c29cca240d3352cc7915710fc Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Mon, 11 Aug 2014 13:25:08 +0200 Subject: [PATCH 40/48] mac802154: common error path By introducing label fail, making the common error path for mac802154_llsec_decrypt() and packet type default case. Signed-off-by: Varka Bhadram Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- net/mac802154/wpan.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/net/mac802154/wpan.c b/net/mac802154/wpan.c index 3c3069fd6971..ce1757001917 100644 --- a/net/mac802154/wpan.c +++ b/net/mac802154/wpan.c @@ -472,8 +472,7 @@ mac802154_subif_frame(struct mac802154_sub_if_data *sdata, struct sk_buff *skb, rc = mac802154_llsec_decrypt(&sdata->sec, skb); if (rc) { pr_debug("decryption failed: %i\n", rc); - kfree_skb(skb); - return NET_RX_DROP; + goto fail; } sdata->dev->stats.rx_packets++; @@ -485,9 +484,12 @@ mac802154_subif_frame(struct mac802154_sub_if_data *sdata, struct sk_buff *skb, default: pr_warn("ieee802154: bad frame received (type = %d)\n", mac_cb(skb)->type); - kfree_skb(skb); - return NET_RX_DROP; + goto fail; } + +fail: + kfree_skb(skb); + return NET_RX_DROP; } static void mac802154_print_addr(const char *name, From 0ba1f94e72b811215ce2f4610fe0f6cf88f4b28a Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Mon, 11 Aug 2014 13:25:09 +0200 Subject: [PATCH 41/48] ieee802154: 6lowpan: remove unused function Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- net/ieee802154/6lowpan_rtnl.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/net/ieee802154/6lowpan_rtnl.c b/net/ieee802154/6lowpan_rtnl.c index 016b77ee88f0..509d7a625a4b 100644 --- a/net/ieee802154/6lowpan_rtnl.c +++ b/net/ieee802154/6lowpan_rtnl.c @@ -77,14 +77,6 @@ lowpan_dev_info *lowpan_dev_info(const struct net_device *dev) return netdev_priv(dev); } -static inline void lowpan_address_flip(u8 *src, u8 *dest) -{ - int i; - - for (i = 0; i < IEEE802154_ADDR_LEN; i++) - (dest)[IEEE802154_ADDR_LEN - i - 1] = (src)[i]; -} - static int lowpan_header_create(struct sk_buff *skb, struct net_device *dev, unsigned short type, const void *_daddr, const void *_saddr, unsigned int len) From f55889128a776b51581394b20abd0b470304cf95 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Mon, 11 Aug 2014 13:25:10 +0200 Subject: [PATCH 42/48] mac802154: common tx error path This patch introduce the common error path on failure of Tx by inserting the label 'err_tx'. Signed-off-by: Varka Bhadram Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- net/mac802154/tx.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/net/mac802154/tx.c b/net/mac802154/tx.c index 8124353646ae..fdf4c0e67259 100644 --- a/net/mac802154/tx.c +++ b/net/mac802154/tx.c @@ -89,8 +89,7 @@ netdev_tx_t mac802154_tx(struct mac802154_priv *priv, struct sk_buff *skb, if (!(priv->phy->channels_supported[page] & (1 << chan))) { WARN_ON(1); - kfree_skb(skb); - return NETDEV_TX_OK; + goto err_tx; } mac802154_monitors_rx(mac802154_to_priv(&priv->hw), skb); @@ -103,12 +102,10 @@ netdev_tx_t mac802154_tx(struct mac802154_priv *priv, struct sk_buff *skb, data[1] = crc >> 8; } - if (skb_cow_head(skb, priv->hw.extra_tx_headroom)) { - kfree_skb(skb); - return NETDEV_TX_OK; - } + if (skb_cow_head(skb, priv->hw.extra_tx_headroom)) + goto err_tx; - work = kzalloc(sizeof(struct xmit_work), GFP_ATOMIC); + work = kzalloc(sizeof(*work), GFP_ATOMIC); if (!work) { kfree_skb(skb); return NETDEV_TX_BUSY; @@ -129,4 +126,8 @@ netdev_tx_t mac802154_tx(struct mac802154_priv *priv, struct sk_buff *skb, queue_work(priv->dev_workqueue, &work->work); return NETDEV_TX_OK; + +err_tx: + kfree_skb(skb); + return NETDEV_TX_OK; } From d664cd9895b498da4fea3b43c72b4aacfc4126a2 Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Wed, 13 Aug 2014 14:53:31 +0530 Subject: [PATCH 43/48] Bluetooth: Remove typedef bluecard_info_t The Linux kernel coding style guidelines suggest not using typedefs for structure types. This patch gets rid of the typedef for bluecard_info_t. Also, the name of the struct is changed to drop the _t, to make the name look less typedef-like. The following Coccinelle semantic patch detects the case: @tn@ identifier i; type td; @@ -typedef struct i { ... } -td ; @@ type tn.td; identifier tn.i; @@ -td + struct i Signed-off-by: Himangi Saraogi Acked-by: Julia Lawall Signed-off-by: Marcel Holtmann --- drivers/bluetooth/bluecard_cs.c | 35 +++++++++++++++++---------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c index dfa5043e68ba..35e63aaa6f80 100644 --- a/drivers/bluetooth/bluecard_cs.c +++ b/drivers/bluetooth/bluecard_cs.c @@ -61,7 +61,7 @@ MODULE_LICENSE("GPL"); /* ======================== Local structures ======================== */ -typedef struct bluecard_info_t { +struct bluecard_info { struct pcmcia_device *p_dev; struct hci_dev *hdev; @@ -78,7 +78,7 @@ typedef struct bluecard_info_t { unsigned char ctrl_reg; unsigned long hw_state; /* Status of the hardware and LED control */ -} bluecard_info_t; +}; static int bluecard_config(struct pcmcia_device *link); @@ -157,7 +157,7 @@ static void bluecard_detach(struct pcmcia_device *p_dev); static void bluecard_activity_led_timeout(u_long arg) { - bluecard_info_t *info = (bluecard_info_t *)arg; + struct bluecard_info *info = (struct bluecard_info *)arg; unsigned int iobase = info->p_dev->resource[0]->start; if (!test_bit(CARD_HAS_PCCARD_ID, &(info->hw_state))) @@ -173,7 +173,7 @@ static void bluecard_activity_led_timeout(u_long arg) } -static void bluecard_enable_activity_led(bluecard_info_t *info) +static void bluecard_enable_activity_led(struct bluecard_info *info) { unsigned int iobase = info->p_dev->resource[0]->start; @@ -215,7 +215,7 @@ static int bluecard_write(unsigned int iobase, unsigned int offset, __u8 *buf, i } -static void bluecard_write_wakeup(bluecard_info_t *info) +static void bluecard_write_wakeup(struct bluecard_info *info) { if (!info) { BT_ERR("Unknown device"); @@ -368,7 +368,8 @@ static int bluecard_read(unsigned int iobase, unsigned int offset, __u8 *buf, in } -static void bluecard_receive(bluecard_info_t *info, unsigned int offset) +static void bluecard_receive(struct bluecard_info *info, + unsigned int offset) { unsigned int iobase; unsigned char buf[31]; @@ -497,7 +498,7 @@ static void bluecard_receive(bluecard_info_t *info, unsigned int offset) static irqreturn_t bluecard_interrupt(int irq, void *dev_inst) { - bluecard_info_t *info = dev_inst; + struct bluecard_info *info = dev_inst; unsigned int iobase; unsigned char reg; @@ -562,7 +563,7 @@ static irqreturn_t bluecard_interrupt(int irq, void *dev_inst) static int bluecard_hci_set_baud_rate(struct hci_dev *hdev, int baud) { - bluecard_info_t *info = hci_get_drvdata(hdev); + struct bluecard_info *info = hci_get_drvdata(hdev); struct sk_buff *skb; /* Ericsson baud rate command */ @@ -611,7 +612,7 @@ static int bluecard_hci_set_baud_rate(struct hci_dev *hdev, int baud) static int bluecard_hci_flush(struct hci_dev *hdev) { - bluecard_info_t *info = hci_get_drvdata(hdev); + struct bluecard_info *info = hci_get_drvdata(hdev); /* Drop TX queue */ skb_queue_purge(&(info->txq)); @@ -622,7 +623,7 @@ static int bluecard_hci_flush(struct hci_dev *hdev) static int bluecard_hci_open(struct hci_dev *hdev) { - bluecard_info_t *info = hci_get_drvdata(hdev); + struct bluecard_info *info = hci_get_drvdata(hdev); if (test_bit(CARD_HAS_PCCARD_ID, &(info->hw_state))) bluecard_hci_set_baud_rate(hdev, DEFAULT_BAUD_RATE); @@ -643,7 +644,7 @@ static int bluecard_hci_open(struct hci_dev *hdev) static int bluecard_hci_close(struct hci_dev *hdev) { - bluecard_info_t *info = hci_get_drvdata(hdev); + struct bluecard_info *info = hci_get_drvdata(hdev); if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags))) return 0; @@ -663,7 +664,7 @@ static int bluecard_hci_close(struct hci_dev *hdev) static int bluecard_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb) { - bluecard_info_t *info = hci_get_drvdata(hdev); + struct bluecard_info *info = hci_get_drvdata(hdev); switch (bt_cb(skb)->pkt_type) { case HCI_COMMAND_PKT: @@ -691,7 +692,7 @@ static int bluecard_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb) /* ======================== Card services HCI interaction ======================== */ -static int bluecard_open(bluecard_info_t *info) +static int bluecard_open(struct bluecard_info *info) { unsigned int iobase = info->p_dev->resource[0]->start; struct hci_dev *hdev; @@ -806,7 +807,7 @@ static int bluecard_open(bluecard_info_t *info) } -static int bluecard_close(bluecard_info_t *info) +static int bluecard_close(struct bluecard_info *info) { unsigned int iobase = info->p_dev->resource[0]->start; struct hci_dev *hdev = info->hdev; @@ -833,7 +834,7 @@ static int bluecard_close(bluecard_info_t *info) static int bluecard_probe(struct pcmcia_device *link) { - bluecard_info_t *info; + struct bluecard_info *info; /* Create new info device */ info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL); @@ -857,7 +858,7 @@ static void bluecard_detach(struct pcmcia_device *link) static int bluecard_config(struct pcmcia_device *link) { - bluecard_info_t *info = link->priv; + struct bluecard_info *info = link->priv; int i, n; link->config_index = 0x20; @@ -897,7 +898,7 @@ failed: static void bluecard_release(struct pcmcia_device *link) { - bluecard_info_t *info = link->priv; + struct bluecard_info *info = link->priv; bluecard_close(info); From ad709d4867985de0b239d01702f9ac6bb578099e Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Wed, 13 Aug 2014 14:51:39 +0530 Subject: [PATCH 44/48] Bluetooth: Remove typedef btuart_info_t The Linux kernel coding style guidelines suggest not using typedefs for structure types. This patch gets rid of the typedef for btuart_info_t. Also, the name of the struct is changed to drop the _t, to make the name look less typedef-like. The following Coccinelle semantic patch detects the case: @tn@ identifier i; type td; @@ -typedef struct i { ... } -td ; @@ type tn.td; identifier tn.i; @@ -td + struct i Signed-off-by: Himangi Saraogi Acked-by: Julia Lawall Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btuart_cs.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c index fb948f02eda5..abb4d2106db4 100644 --- a/drivers/bluetooth/btuart_cs.c +++ b/drivers/bluetooth/btuart_cs.c @@ -62,7 +62,7 @@ MODULE_LICENSE("GPL"); /* ======================== Local structures ======================== */ -typedef struct btuart_info_t { +struct btuart_info { struct pcmcia_device *p_dev; struct hci_dev *hdev; @@ -75,7 +75,7 @@ typedef struct btuart_info_t { unsigned long rx_state; unsigned long rx_count; struct sk_buff *rx_skb; -} btuart_info_t; +}; static int btuart_config(struct pcmcia_device *link); @@ -127,7 +127,7 @@ static int btuart_write(unsigned int iobase, int fifo_size, __u8 *buf, int len) } -static void btuart_write_wakeup(btuart_info_t *info) +static void btuart_write_wakeup(struct btuart_info *info) { if (!info) { BT_ERR("Unknown device"); @@ -172,7 +172,7 @@ static void btuart_write_wakeup(btuart_info_t *info) } -static void btuart_receive(btuart_info_t *info) +static void btuart_receive(struct btuart_info *info) { unsigned int iobase; int boguscount = 0; @@ -286,7 +286,7 @@ static void btuart_receive(btuart_info_t *info) static irqreturn_t btuart_interrupt(int irq, void *dev_inst) { - btuart_info_t *info = dev_inst; + struct btuart_info *info = dev_inst; unsigned int iobase; int boguscount = 0; int iir, lsr; @@ -340,7 +340,8 @@ static irqreturn_t btuart_interrupt(int irq, void *dev_inst) } -static void btuart_change_speed(btuart_info_t *info, unsigned int speed) +static void btuart_change_speed(struct btuart_info *info, + unsigned int speed) { unsigned long flags; unsigned int iobase; @@ -397,7 +398,7 @@ static void btuart_change_speed(btuart_info_t *info, unsigned int speed) static int btuart_hci_flush(struct hci_dev *hdev) { - btuart_info_t *info = hci_get_drvdata(hdev); + struct btuart_info *info = hci_get_drvdata(hdev); /* Drop TX queue */ skb_queue_purge(&(info->txq)); @@ -427,7 +428,7 @@ static int btuart_hci_close(struct hci_dev *hdev) static int btuart_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb) { - btuart_info_t *info = hci_get_drvdata(hdev); + struct btuart_info *info = hci_get_drvdata(hdev); switch (bt_cb(skb)->pkt_type) { case HCI_COMMAND_PKT: @@ -455,7 +456,7 @@ static int btuart_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb) /* ======================== Card services HCI interaction ======================== */ -static int btuart_open(btuart_info_t *info) +static int btuart_open(struct btuart_info *info) { unsigned long flags; unsigned int iobase = info->p_dev->resource[0]->start; @@ -521,7 +522,7 @@ static int btuart_open(btuart_info_t *info) } -static int btuart_close(btuart_info_t *info) +static int btuart_close(struct btuart_info *info) { unsigned long flags; unsigned int iobase = info->p_dev->resource[0]->start; @@ -550,7 +551,7 @@ static int btuart_close(btuart_info_t *info) static int btuart_probe(struct pcmcia_device *link) { - btuart_info_t *info; + struct btuart_info *info; /* Create new info device */ info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL); @@ -613,7 +614,7 @@ static int btuart_check_config_notpicky(struct pcmcia_device *p_dev, static int btuart_config(struct pcmcia_device *link) { - btuart_info_t *info = link->priv; + struct btuart_info *info = link->priv; int i; int try; @@ -654,7 +655,7 @@ failed: static void btuart_release(struct pcmcia_device *link) { - btuart_info_t *info = link->priv; + struct btuart_info *info = link->priv; btuart_close(info); From 66f4e0e43a0389a7f2814f0cc6df39019aead54f Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Wed, 13 Aug 2014 14:52:27 +0530 Subject: [PATCH 45/48] Bluetooth: Remove typedefs nsh_t and dtl1_info_t The Linux kernel coding style guidelines suggest not using typedefs for structure types. This patch gets rid of the typedefs for nsh_t and dtl1_info_t. Also, the name of the struct is changed to drop the _t, to make the name look less typedef-like. The following Coccinelle semantic patch detects the case for dtl1_info_t and a similar patch finds the nsh_t case: @tn@ identifier i; type td; @@ -typedef struct i { ... } -td ; @@ type tn.td; identifier tn.i; @@ -td + struct i Signed-off-by: Himangi Saraogi Acked-by: Julia Lawall Signed-off-by: Marcel Holtmann --- drivers/bluetooth/dtl1_cs.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c index 2bd8fad17206..78e10f0c65b2 100644 --- a/drivers/bluetooth/dtl1_cs.c +++ b/drivers/bluetooth/dtl1_cs.c @@ -62,7 +62,7 @@ MODULE_LICENSE("GPL"); /* ======================== Local structures ======================== */ -typedef struct dtl1_info_t { +struct dtl1_info { struct pcmcia_device *p_dev; struct hci_dev *hdev; @@ -78,7 +78,7 @@ typedef struct dtl1_info_t { unsigned long rx_state; unsigned long rx_count; struct sk_buff *rx_skb; -} dtl1_info_t; +}; static int dtl1_config(struct pcmcia_device *link); @@ -94,11 +94,11 @@ static int dtl1_config(struct pcmcia_device *link); #define RECV_WAIT_DATA 1 -typedef struct { +struct nsh { u8 type; u8 zero; u16 len; -} __packed nsh_t; /* Nokia Specific Header */ +} __packed; /* Nokia Specific Header */ #define NSHL 4 /* Nokia Specific Header Length */ @@ -126,7 +126,7 @@ static int dtl1_write(unsigned int iobase, int fifo_size, __u8 *buf, int len) } -static void dtl1_write_wakeup(dtl1_info_t *info) +static void dtl1_write_wakeup(struct dtl1_info *info) { if (!info) { BT_ERR("Unknown device"); @@ -176,7 +176,7 @@ static void dtl1_write_wakeup(dtl1_info_t *info) } -static void dtl1_control(dtl1_info_t *info, struct sk_buff *skb) +static void dtl1_control(struct dtl1_info *info, struct sk_buff *skb) { u8 flowmask = *(u8 *)skb->data; int i; @@ -199,10 +199,10 @@ static void dtl1_control(dtl1_info_t *info, struct sk_buff *skb) } -static void dtl1_receive(dtl1_info_t *info) +static void dtl1_receive(struct dtl1_info *info) { unsigned int iobase; - nsh_t *nsh; + struct nsh *nsh; int boguscount = 0; if (!info) { @@ -227,7 +227,7 @@ static void dtl1_receive(dtl1_info_t *info) } *skb_put(info->rx_skb, 1) = inb(iobase + UART_RX); - nsh = (nsh_t *)info->rx_skb->data; + nsh = (struct nsh *)info->rx_skb->data; info->rx_count--; @@ -287,7 +287,7 @@ static void dtl1_receive(dtl1_info_t *info) static irqreturn_t dtl1_interrupt(int irq, void *dev_inst) { - dtl1_info_t *info = dev_inst; + struct dtl1_info *info = dev_inst; unsigned int iobase; unsigned char msr; int boguscount = 0; @@ -365,7 +365,7 @@ static int dtl1_hci_open(struct hci_dev *hdev) static int dtl1_hci_flush(struct hci_dev *hdev) { - dtl1_info_t *info = hci_get_drvdata(hdev); + struct dtl1_info *info = hci_get_drvdata(hdev); /* Drop TX queue */ skb_queue_purge(&(info->txq)); @@ -387,9 +387,9 @@ static int dtl1_hci_close(struct hci_dev *hdev) static int dtl1_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb) { - dtl1_info_t *info = hci_get_drvdata(hdev); + struct dtl1_info *info = hci_get_drvdata(hdev); struct sk_buff *s; - nsh_t nsh; + struct nsh nsh; switch (bt_cb(skb)->pkt_type) { case HCI_COMMAND_PKT: @@ -436,7 +436,7 @@ static int dtl1_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb) /* ======================== Card services HCI interaction ======================== */ -static int dtl1_open(dtl1_info_t *info) +static int dtl1_open(struct dtl1_info *info) { unsigned long flags; unsigned int iobase = info->p_dev->resource[0]->start; @@ -505,7 +505,7 @@ static int dtl1_open(dtl1_info_t *info) } -static int dtl1_close(dtl1_info_t *info) +static int dtl1_close(struct dtl1_info *info) { unsigned long flags; unsigned int iobase = info->p_dev->resource[0]->start; @@ -534,7 +534,7 @@ static int dtl1_close(dtl1_info_t *info) static int dtl1_probe(struct pcmcia_device *link) { - dtl1_info_t *info; + struct dtl1_info *info; /* Create new info device */ info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL); @@ -552,7 +552,7 @@ static int dtl1_probe(struct pcmcia_device *link) static void dtl1_detach(struct pcmcia_device *link) { - dtl1_info_t *info = link->priv; + struct dtl1_info *info = link->priv; dtl1_close(info); pcmcia_disable_device(link); @@ -571,7 +571,7 @@ static int dtl1_confcheck(struct pcmcia_device *p_dev, void *priv_data) static int dtl1_config(struct pcmcia_device *link) { - dtl1_info_t *info = link->priv; + struct dtl1_info *info = link->priv; int ret; /* Look for a generic full-sized window */ From 3bbaf812065e8b0feca02b6c7e5117b731709008 Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Wed, 13 Aug 2014 14:49:56 +0530 Subject: [PATCH 46/48] Bluetooth: Remove typedef bt3c_info_t The Linux kernel coding style guidelines suggest not using typedefs for structure types. This patch gets rid of the typedef for bt3c_info_t. Also, the name of the struct is changed to drop the _t, to make the name look less typedef-like. The following Coccinelle semantic patch detects the case: @tn@ identifier i; type td; @@ -typedef struct i { ... } -td ; @@ type tn.td; identifier tn.i; @@ -td + struct i Signed-off-by: Himangi Saraogi Acked-by: Julia Lawall Signed-off-by: Marcel Holtmann --- drivers/bluetooth/bt3c_cs.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c index 1d82721cf9c6..4f7e8d400bc0 100644 --- a/drivers/bluetooth/bt3c_cs.c +++ b/drivers/bluetooth/bt3c_cs.c @@ -67,7 +67,7 @@ MODULE_FIRMWARE("BT3CPCC.bin"); /* ======================== Local structures ======================== */ -typedef struct bt3c_info_t { +struct bt3c_info { struct pcmcia_device *p_dev; struct hci_dev *hdev; @@ -80,7 +80,7 @@ typedef struct bt3c_info_t { unsigned long rx_state; unsigned long rx_count; struct sk_buff *rx_skb; -} bt3c_info_t; +}; static int bt3c_config(struct pcmcia_device *link); @@ -175,7 +175,7 @@ static int bt3c_write(unsigned int iobase, int fifo_size, __u8 *buf, int len) } -static void bt3c_write_wakeup(bt3c_info_t *info) +static void bt3c_write_wakeup(struct bt3c_info *info) { if (!info) { BT_ERR("Unknown device"); @@ -214,7 +214,7 @@ static void bt3c_write_wakeup(bt3c_info_t *info) } -static void bt3c_receive(bt3c_info_t *info) +static void bt3c_receive(struct bt3c_info *info) { unsigned int iobase; int size = 0, avail; @@ -336,7 +336,7 @@ static void bt3c_receive(bt3c_info_t *info) static irqreturn_t bt3c_interrupt(int irq, void *dev_inst) { - bt3c_info_t *info = dev_inst; + struct bt3c_info *info = dev_inst; unsigned int iobase; int iir; irqreturn_t r = IRQ_NONE; @@ -388,7 +388,7 @@ static irqreturn_t bt3c_interrupt(int irq, void *dev_inst) static int bt3c_hci_flush(struct hci_dev *hdev) { - bt3c_info_t *info = hci_get_drvdata(hdev); + struct bt3c_info *info = hci_get_drvdata(hdev); /* Drop TX queue */ skb_queue_purge(&(info->txq)); @@ -418,7 +418,7 @@ static int bt3c_hci_close(struct hci_dev *hdev) static int bt3c_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb) { - bt3c_info_t *info = hci_get_drvdata(hdev); + struct bt3c_info *info = hci_get_drvdata(hdev); unsigned long flags; switch (bt_cb(skb)->pkt_type) { @@ -451,7 +451,8 @@ static int bt3c_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb) /* ======================== Card services HCI interaction ======================== */ -static int bt3c_load_firmware(bt3c_info_t *info, const unsigned char *firmware, +static int bt3c_load_firmware(struct bt3c_info *info, + const unsigned char *firmware, int count) { char *ptr = (char *) firmware; @@ -536,7 +537,7 @@ error: } -static int bt3c_open(bt3c_info_t *info) +static int bt3c_open(struct bt3c_info *info) { const struct firmware *firmware; struct hci_dev *hdev; @@ -603,7 +604,7 @@ error: } -static int bt3c_close(bt3c_info_t *info) +static int bt3c_close(struct bt3c_info *info) { struct hci_dev *hdev = info->hdev; @@ -620,7 +621,7 @@ static int bt3c_close(bt3c_info_t *info) static int bt3c_probe(struct pcmcia_device *link) { - bt3c_info_t *info; + struct bt3c_info *info; /* Create new info device */ info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL); @@ -683,7 +684,7 @@ static int bt3c_check_config_notpicky(struct pcmcia_device *p_dev, static int bt3c_config(struct pcmcia_device *link) { - bt3c_info_t *info = link->priv; + struct bt3c_info *info = link->priv; int i; unsigned long try; @@ -724,7 +725,7 @@ failed: static void bt3c_release(struct pcmcia_device *link) { - bt3c_info_t *info = link->priv; + struct bt3c_info *info = link->priv; bt3c_close(info); From 069cb27017de6476d47a70fbf144f69200d3e854 Mon Sep 17 00:00:00 2001 From: Lukasz Rymanowski Date: Wed, 13 Aug 2014 16:01:41 +0200 Subject: [PATCH 47/48] Bluetooth: Improve data packing in SAR mode There is no need to decrease pdu size with L2CAP SDU lenght in Start L2CAP SDU frame. Start packtet is just 2 bytes longer as specified and we can keep payload as long as possible. When testing SAR L2CAP against PTS, L2CAP channel is usually configured in that way, that SDU = MPS * 3. PTS expets then 3 I-Frames from IUT: Start, Continuation and End frame. Without this fix, we sent 4 I-Frames. We could pass a test by using -b option in l2test and send just two bytes less than SDU length. With this patch no need to use -b option. Signed-off-by: Lukasz Rymanowski Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 0cd7ed99558b..ebe7454362f0 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -2275,7 +2275,6 @@ static int l2cap_segment_sdu(struct l2cap_chan *chan, } else { sar = L2CAP_SAR_START; sdu_len = len; - pdu_len -= L2CAP_SDULEN_SIZE; } while (len > 0) { @@ -2290,10 +2289,8 @@ static int l2cap_segment_sdu(struct l2cap_chan *chan, __skb_queue_tail(seg_queue, skb); len -= pdu_len; - if (sdu_len) { + if (sdu_len) sdu_len = 0; - pdu_len += L2CAP_SDULEN_SIZE; - } if (len <= pdu_len) { sar = L2CAP_SAR_END; From 13cac15296afe7e42088ecfcd0f1d4b658248c46 Mon Sep 17 00:00:00 2001 From: Lukasz Rymanowski Date: Thu, 14 Aug 2014 09:35:34 +0200 Subject: [PATCH 48/48] Bluetooth: Fix ERTM L2CAP resend packet I-Frame which is going to be resend already has FCS field added and set (if it was required). Adding additional FCS field calculated from data + old FCS in resend function is incorrect. This patch fix that. Issue has been found during PTS testing. Signed-off-by: Lukasz Rymanowski Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_core.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index ebe7454362f0..4a90438d99df 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1968,10 +1968,12 @@ static void l2cap_ertm_resend(struct l2cap_chan *chan) tx_skb->data + L2CAP_HDR_SIZE); } + /* Update FCS */ if (chan->fcs == L2CAP_FCS_CRC16) { - u16 fcs = crc16(0, (u8 *) tx_skb->data, tx_skb->len); - put_unaligned_le16(fcs, skb_put(tx_skb, - L2CAP_FCS_SIZE)); + u16 fcs = crc16(0, (u8 *) tx_skb->data, + tx_skb->len - L2CAP_FCS_SIZE); + put_unaligned_le16(fcs, skb_tail_pointer(tx_skb) - + L2CAP_FCS_SIZE); } l2cap_do_send(chan, tx_skb);