From 2bcd4003b8fafe200eb31f43d50e305e5dc44058 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 9 Jul 2014 19:18:09 +0300 Subject: Bluetooth: Always confirm incoming SMP just-works requests For incoming requests we want to let the user know that pairing is happening since otherwise there could be access to MEDIUM security services without any user interaction at all. Therefore, set the selected method to JUST_CFM instead of JUST_WORKS and let it be converted back to JUST_WORKS later if we are the initators. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 55c41de2f5a0..a17761c83820 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -391,10 +391,12 @@ static const u8 gen_method[5][5] = { static u8 get_auth_method(struct smp_chan *smp, u8 local_io, u8 remote_io) { - /* If either side has unknown io_caps, use JUST WORKS */ + /* If either side has unknown io_caps, use JUST_CFM (which gets + * converted later to JUST_WORKS if we're initiators. + */ if (local_io > SMP_IO_KEYBOARD_DISPLAY || remote_io > SMP_IO_KEYBOARD_DISPLAY) - return JUST_WORKS; + return JUST_CFM; return gen_method[remote_io][local_io]; } @@ -414,10 +416,14 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth, BT_DBG("tk_request: auth:%d lcl:%d rem:%d", auth, local_io, remote_io); - /* If neither side wants MITM, use JUST WORKS */ - /* Otherwise, look up method from the table */ + /* If neither side wants MITM, either "just" confirm an incoming + * request or use just-works for outgoing ones. The JUST_CFM + * will be converted to JUST_WORKS if necessary later in this + * function. If either side has MITM look up the method from the + * table. + */ if (!(auth & SMP_AUTH_MITM)) - method = JUST_WORKS; + method = JUST_CFM; else method = get_auth_method(smp, local_io, remote_io); -- cgit v1.2.3 From e247605a6247aff887d435d2334ffe0e581dae24 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 9 Jul 2014 19:18:10 +0300 Subject: Bluetooth: Fix forcing SMP just-works with no-bonding Whether we bond or not should not have any impact on the user interaction model. This patch removes an incorrect fall-back from JUST_CFM to JUST_WORKS in case we're not bonding. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index a17761c83820..a5e51c686469 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -427,10 +427,6 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth, else method = get_auth_method(smp, local_io, remote_io); - /* If not bonding, don't ask user to confirm a Zero TK */ - if (!(auth & SMP_AUTH_BONDING) && method == JUST_CFM) - method = JUST_WORKS; - /* Don't confirm locally initiated pairing attempts */ if (method == JUST_CFM && test_bit(SMP_FLAG_INITIATOR, &smp->flags)) method = JUST_WORKS; -- cgit v1.2.3 From c072d546c20390fea0e5332d00fd1b67366ca013 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 9 Jul 2014 19:18:11 +0300 Subject: Bluetooth: Fix incorrect clearing of SMP_FLAG_INITIATOR When the SMP context is created all flags default to zero. To determine that we are the initiators it's therefore best to simply change the flag value when we know we're sending the first SMP PDU. Clearing the flag when receiving a Pairing Request is not correct since the request may be a response to a previous Security Request from us (for which we would already have correctly set the flag). Same goes for receiving a Security Request which may be coming after us already starting pairing by sending a Pairing Request. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index a5e51c686469..627d683203cf 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -735,8 +735,6 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) if (ret) return SMP_UNSPECIFIED; - clear_bit(SMP_FLAG_INITIATOR, &smp->flags); - return 0; } @@ -927,8 +925,6 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp); - clear_bit(SMP_FLAG_INITIATOR, &smp->flags); - return 0; } -- cgit v1.2.3 From e8b1202ce6ab67341660812e7d66db4c3e2a5649 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 10 Jul 2014 10:51:27 +0300 Subject: Bluetooth: Fix advertising parameter update when toggling connectable When we change the connectable state and have advertising enabled we should update the advertising parameters no matter what. The code was incorrectly only updating them if advertising was not already active. This patch fixes the issue. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 91b1f92c681e..38f05386bc0c 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1882,8 +1882,8 @@ static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data, if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) write_fast_connectable(&req, false); - if (test_bit(HCI_ADVERTISING, &hdev->dev_flags) && - !test_bit(HCI_LE_ADV, &hdev->dev_flags)) + /* Update the advertising parameters if necessary */ + if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) enable_advertising(&req); err = hci_req_run(&req, set_connectable_complete); -- cgit v1.2.3 From b3c6410b8c75cd48e4242af0173bb55701939b9b Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 10 Jul 2014 11:02:07 +0300 Subject: Bluteooth: Reject SMP bonding if HCI_PAIRABLE is not set If the remote device tries to initiate bonding with us and we don't have HCI_PAIRABLE set we should just flat out reject the request. This brings SMP in line with how the flag is used for BR/EDR SSP. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'net/bluetooth') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 627d683203cf..bf3568c46847 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -676,6 +676,7 @@ int smp_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, __le32 passkey) static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) { struct smp_cmd_pairing rsp, *req = (void *) skb->data; + struct hci_dev *hdev = conn->hcon->hdev; struct smp_chan *smp; u8 key_size, auth, sec_level; int ret; @@ -696,6 +697,10 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) if (!smp) return SMP_UNSPECIFIED; + if (!test_bit(HCI_PAIRABLE, &hdev->dev_flags) && + (req->auth_req & SMP_AUTH_BONDING)) + return SMP_PAIRING_NOTSUPP; + smp->preq[0] = SMP_CMD_PAIRING_REQ; memcpy(&smp->preq[1], req, sizeof(*req)); skb_pull(skb, sizeof(*req)); @@ -911,6 +916,10 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) return 0; + if (!test_bit(HCI_PAIRABLE, &hcon->hdev->dev_flags) && + (rp->auth_req & SMP_AUTH_BONDING)) + return SMP_PAIRING_NOTSUPP; + smp = smp_chan_create(conn); if (!smp) return SMP_UNSPECIFIED; -- cgit v1.2.3 From 7fabc0f4c7bd2206c368a79e3ed79b7d36625cfd Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 10 Jul 2014 11:50:27 +0300 Subject: Bluetooth: Fix using test_and_clear instead of test_and_set The code for updating the HCI_CONNECTABLE flag was incorrectly using test_and_set_bit instead of test_and_clear_bit when HCI_CONNECTABLE is to be cleared. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 84431b86af96..8f9df768f250 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2726,8 +2726,8 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg) changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags); else - changed = test_and_set_bit(HCI_CONNECTABLE, - &hdev->dev_flags); + changed = test_and_clear_bit(HCI_CONNECTABLE, + &hdev->dev_flags); if (changed) mgmt_new_settings(hdev); -- cgit v1.2.3 From 031547d8688a0fc5da875b504bf11e6c2e18390e Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 10 Jul 2014 12:09:06 +0300 Subject: Bluetooth: Remove unneeded mgmt_connectable function The mgmt_connectable function has been used to ensure that the right actions to HCI_CONNECTABLE are taken when the HCI_Write_Scan_Enable command is triggered by something else than mgmt. The only other user that we really care about is the HCISETSCAN ioctl code, so we can actually more simply perform the needed changes there instead. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 1 - net/bluetooth/hci_core.c | 6 +++--- net/bluetooth/hci_event.c | 6 +----- net/bluetooth/mgmt.c | 32 -------------------------------- 4 files changed, 4 insertions(+), 41 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index e69c2b08c0c6..76675c55be15 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1288,7 +1288,6 @@ void mgmt_set_powered_failed(struct hci_dev *hdev, int err); int mgmt_powered(struct hci_dev *hdev, u8 powered); void mgmt_discoverable_timeout(struct hci_dev *hdev); void mgmt_discoverable(struct hci_dev *hdev, u8 discoverable); -void mgmt_connectable(struct hci_dev *hdev, u8 connectable); void mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status); void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, bool persistent); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 8f9df768f250..3844eeb85453 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2717,9 +2717,9 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg) HCI_INIT_TIMEOUT); /* Ensure that the connectable state gets correctly - * notified if the whitelist is in use. + * modified as this was a non-mgmt change. */ - if (!err && !list_empty(&hdev->whitelist)) { + if (!err) { bool changed; if ((dr.dev_opt & SCAN_PAGE)) @@ -2729,7 +2729,7 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg) changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags); - if (changed) + if (changed && test_bit(HCI_MGMT, &hdev->dev_flags)) mgmt_new_settings(hdev); } break; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index c8ae9ee3cb12..38a0e457eaf9 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -330,12 +330,8 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb) } else if (old_iscan) mgmt_discoverable(hdev, 0); - if (param & SCAN_PAGE) { + if (param & SCAN_PAGE) set_bit(HCI_PSCAN, &hdev->flags); - if (!old_pscan) - mgmt_connectable(hdev, 1); - } else if (old_pscan) - mgmt_connectable(hdev, 0); done: hci_dev_unlock(hdev); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 38f05386bc0c..9f9f11c8488b 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -6068,38 +6068,6 @@ void mgmt_discoverable(struct hci_dev *hdev, u8 discoverable) } } -void mgmt_connectable(struct hci_dev *hdev, u8 connectable) -{ - bool changed; - - /* Nothing needed here if there's a pending command since that - * commands request completion callback takes care of everything - * necessary. - */ - if (mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) - return; - - /* Powering off may clear the scan mode - don't let that interfere */ - if (!connectable && mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) - return; - - /* If something else than mgmt changed the page scan state we - * can't differentiate this from a change triggered by adding - * the first element to the whitelist. Therefore, avoid - * incorrectly setting HCI_CONNECTABLE. - */ - if (connectable && !list_empty(&hdev->whitelist)) - return; - - if (connectable) - changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags); - else - changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags); - - if (changed) - new_settings(hdev, NULL); -} - void mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status) { u8 mgmt_err = mgmt_status(status); -- cgit v1.2.3 From 123abc0833181aec4796c628d9ffd608b2b41d5c Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 10 Jul 2014 12:09:07 +0300 Subject: Bluetooth: Refactor ioctl scan state update to its own function With subsequent patches we'll also need to update the discoverable state. As the code grows bigger it's better to move this out from the switch statement into its own function. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 3844eeb85453..27c40e4901a3 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2655,6 +2655,26 @@ done: return ret; } +static void hci_update_scan_state(struct hci_dev *hdev, u8 scan) +{ + bool conn_changed; + + BT_DBG("%s scan 0x%02x", hdev->name, scan); + + if ((scan & SCAN_PAGE)) + conn_changed = !test_and_set_bit(HCI_CONNECTABLE, + &hdev->dev_flags); + else + conn_changed = test_and_clear_bit(HCI_CONNECTABLE, + &hdev->dev_flags); + + if (!test_bit(HCI_MGMT, &hdev->dev_flags)) + return; + + if (conn_changed) + mgmt_new_settings(hdev); +} + int hci_dev_cmd(unsigned int cmd, void __user *arg) { struct hci_dev *hdev; @@ -2719,19 +2739,8 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg) /* Ensure that the connectable state gets correctly * modified as this was a non-mgmt change. */ - if (!err) { - bool changed; - - if ((dr.dev_opt & SCAN_PAGE)) - changed = !test_and_set_bit(HCI_CONNECTABLE, - &hdev->dev_flags); - else - changed = test_and_clear_bit(HCI_CONNECTABLE, - &hdev->dev_flags); - - if (changed && test_bit(HCI_MGMT, &hdev->dev_flags)) - mgmt_new_settings(hdev); - } + if (!err) + hci_update_scan_state(hdev, dr.dev_opt); break; case HCISETLINKPOL: -- cgit v1.2.3 From bc6d2d04182877b198c1a945b7c401decbbb8c02 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 10 Jul 2014 12:09:08 +0300 Subject: Bluetooth: Remove unneeded mgmt_discoverable function Since the HCISETSCAN ioctl is the only non-mgmt user we care about for setting the right discoverable state we can simply do the necessary updates in the ioctl handler function instead. This then allows the removal of the mgmt_discoverable function and should simplify that state handling considerably. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 2 +- net/bluetooth/hci_core.c | 24 +++++++++++--- net/bluetooth/hci_event.c | 19 +++--------- net/bluetooth/mgmt.c | 67 ++++++++++++++-------------------------- 4 files changed, 50 insertions(+), 62 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 76675c55be15..b65efb22be54 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1286,8 +1286,8 @@ void mgmt_index_added(struct hci_dev *hdev); void mgmt_index_removed(struct hci_dev *hdev); void mgmt_set_powered_failed(struct hci_dev *hdev, int err); int mgmt_powered(struct hci_dev *hdev, u8 powered); +int mgmt_update_adv_data(struct hci_dev *hdev); void mgmt_discoverable_timeout(struct hci_dev *hdev); -void mgmt_discoverable(struct hci_dev *hdev, u8 discoverable); void mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status); void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, bool persistent); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 27c40e4901a3..3321c65c73ac 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2657,7 +2657,7 @@ done: static void hci_update_scan_state(struct hci_dev *hdev, u8 scan) { - bool conn_changed; + bool conn_changed, discov_changed; BT_DBG("%s scan 0x%02x", hdev->name, scan); @@ -2668,11 +2668,27 @@ static void hci_update_scan_state(struct hci_dev *hdev, u8 scan) conn_changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags); + if ((scan & SCAN_INQUIRY)) { + discov_changed = !test_and_set_bit(HCI_DISCOVERABLE, + &hdev->dev_flags); + } else { + clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags); + discov_changed = test_and_clear_bit(HCI_DISCOVERABLE, + &hdev->dev_flags); + } + if (!test_bit(HCI_MGMT, &hdev->dev_flags)) return; - if (conn_changed) + if (conn_changed || discov_changed) { + /* In case this was disabled through mgmt */ + set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags); + + if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) + mgmt_update_adv_data(hdev); + mgmt_new_settings(hdev); + } } int hci_dev_cmd(unsigned int cmd, void __user *arg) @@ -2736,8 +2752,8 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg) err = hci_req_sync(hdev, hci_scan_req, dr.dev_opt, HCI_INIT_TIMEOUT); - /* Ensure that the connectable state gets correctly - * modified as this was a non-mgmt change. + /* Ensure that the connectable and discoverable states + * get correctly modified as this was a non-mgmt change. */ if (!err) hci_update_scan_state(hdev, dr.dev_opt); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 38a0e457eaf9..760bbd88f3c5 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -296,7 +296,6 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb) { __u8 status = *((__u8 *) skb->data); __u8 param; - int old_pscan, old_iscan; void *sent; BT_DBG("%s status 0x%2.2x", hdev->name, status); @@ -315,23 +314,15 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb) goto done; } - /* We need to ensure that we set this back on if someone changed - * the scan mode through a raw HCI socket. - */ - set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags); - - old_pscan = test_and_clear_bit(HCI_PSCAN, &hdev->flags); - old_iscan = test_and_clear_bit(HCI_ISCAN, &hdev->flags); - - if (param & SCAN_INQUIRY) { + if (param & SCAN_INQUIRY) set_bit(HCI_ISCAN, &hdev->flags); - if (!old_iscan) - mgmt_discoverable(hdev, 1); - } else if (old_iscan) - mgmt_discoverable(hdev, 0); + else + clear_bit(HCI_ISCAN, &hdev->flags); if (param & SCAN_PAGE) set_bit(HCI_PSCAN, &hdev->flags); + else + clear_bit(HCI_ISCAN, &hdev->flags); done: hci_dev_unlock(hdev); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 9f9f11c8488b..1dad7bffc6af 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -906,6 +906,16 @@ static void update_adv_data(struct hci_request *req) hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp); } +int mgmt_update_adv_data(struct hci_dev *hdev) +{ + struct hci_request req; + + hci_req_init(&req, hdev); + update_adv_data(&req); + + return hci_req_run(&req, NULL); +} + static void create_eir(struct hci_dev *hdev, u8 *data) { u8 *ptr = data; @@ -1743,7 +1753,7 @@ static void set_connectable_complete(struct hci_dev *hdev, u8 status) { struct pending_cmd *cmd; struct mgmt_mode *cp; - bool changed; + bool conn_changed, discov_changed; BT_DBG("status 0x%02x", status); @@ -1760,15 +1770,23 @@ static void set_connectable_complete(struct hci_dev *hdev, u8 status) } cp = cmd->param; - if (cp->val) - changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags); - else - changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags); + if (cp->val) { + conn_changed = !test_and_set_bit(HCI_CONNECTABLE, + &hdev->dev_flags); + discov_changed = false; + } else { + conn_changed = test_and_clear_bit(HCI_CONNECTABLE, + &hdev->dev_flags); + discov_changed = test_and_clear_bit(HCI_DISCOVERABLE, + &hdev->dev_flags); + } send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev); - if (changed) { + if (conn_changed || discov_changed) { new_settings(hdev, cmd->sk); + if (discov_changed) + mgmt_update_adv_data(hdev); hci_update_background_scan(hdev); } @@ -6031,43 +6049,6 @@ void mgmt_discoverable_timeout(struct hci_dev *hdev) hci_dev_unlock(hdev); } -void mgmt_discoverable(struct hci_dev *hdev, u8 discoverable) -{ - bool changed; - - /* Nothing needed here if there's a pending command since that - * commands request completion callback takes care of everything - * necessary. - */ - if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev)) - return; - - /* Powering off may clear the scan mode - don't let that interfere */ - if (!discoverable && mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) - return; - - if (discoverable) { - changed = !test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags); - } else { - clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags); - changed = test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags); - } - - if (changed) { - struct hci_request req; - - /* In case this change in discoverable was triggered by - * a disabling of connectable there could be a need to - * update the advertising flags. - */ - hci_req_init(&req, hdev); - update_adv_data(&req); - hci_req_run(&req, NULL); - - new_settings(hdev, NULL); - } -} - void mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status) { u8 mgmt_err = mgmt_status(status); -- cgit v1.2.3 From 13a779e42251184d0f53a8f8299ced614faa028f Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 10 Jul 2014 12:09:09 +0300 Subject: Bluetooth: Remove unneeded mgmt_write_scan_failed function The Set Connectable/Discoverable mgmt handlers use a hci_request with a proper callback to handle the HCI command sending. It makes therefore little sense to have this extra function to be called from hci_event.c for command failures. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 1 - net/bluetooth/hci_event.c | 1 - net/bluetooth/mgmt.c | 13 ------------- 3 files changed, 15 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index b65efb22be54..7e9e95633a85 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1288,7 +1288,6 @@ void mgmt_set_powered_failed(struct hci_dev *hdev, int err); int mgmt_powered(struct hci_dev *hdev, u8 powered); int mgmt_update_adv_data(struct hci_dev *hdev); void mgmt_discoverable_timeout(struct hci_dev *hdev); -void mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status); void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, bool persistent); void mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 760bbd88f3c5..a62e918d2641 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -309,7 +309,6 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb) hci_dev_lock(hdev); if (status) { - mgmt_write_scan_failed(hdev, param, status); hdev->discov_timeout = 0; goto done; } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 1dad7bffc6af..7703b72653ff 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -6049,19 +6049,6 @@ void mgmt_discoverable_timeout(struct hci_dev *hdev) hci_dev_unlock(hdev); } -void mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status) -{ - u8 mgmt_err = mgmt_status(status); - - if (scan & SCAN_PAGE) - mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, - cmd_status_rsp, &mgmt_err); - - if (scan & SCAN_INQUIRY) - mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, - cmd_status_rsp, &mgmt_err); -} - void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, bool persistent) { -- cgit v1.2.3 From 2e84d8db91e45964c2b54ccc7da1f9b4bfb1222b Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 10 Jul 2014 13:17:37 +0200 Subject: Bluetooth: Mark controller is down when HCI_AUTO_OFF is set During the initial setup phase, the controller is powered on and will be powered off again if it is not used within the auto-off timeout. Userspace using ioctl does not know about the difference between the initial setup phase and a controller being present. It is a bad idea to keep the controller powered by just looking at the device list or device information. Instead just tell userspace that the controller is still down. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 3321c65c73ac..96e0acc3fc92 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2817,14 +2817,20 @@ int hci_get_dev_list(void __user *arg) read_lock(&hci_dev_list_lock); list_for_each_entry(hdev, &hci_dev_list, list) { - if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) - cancel_delayed_work(&hdev->power_off); + unsigned long flags = hdev->flags; + + /* When the auto-off is configured it means the transport + * is running, but in that case still indicate that the + * device is actually down. + */ + if (test_bit(HCI_AUTO_OFF, &hdev->dev_flags)) + flags &= ~BIT(HCI_UP); if (!test_bit(HCI_MGMT, &hdev->dev_flags)) set_bit(HCI_PAIRABLE, &hdev->dev_flags); (dr + n)->dev_id = hdev->id; - (dr + n)->dev_opt = hdev->flags; + (dr + n)->dev_opt = flags; if (++n >= dev_num) break; @@ -2844,6 +2850,7 @@ int hci_get_dev_info(void __user *arg) { struct hci_dev *hdev; struct hci_dev_info di; + unsigned long flags; int err = 0; if (copy_from_user(&di, arg, sizeof(di))) @@ -2853,8 +2860,14 @@ int hci_get_dev_info(void __user *arg) if (!hdev) return -ENODEV; - if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) - cancel_delayed_work_sync(&hdev->power_off); + /* When the auto-off is configured it means the transport + * is running, but in that case still indicate that the + * device is actually down. + */ + if (test_bit(HCI_AUTO_OFF, &hdev->dev_flags)) + flags = hdev->flags & ~BIT(HCI_UP); + else + flags = hdev->flags; if (!test_bit(HCI_MGMT, &hdev->dev_flags)) set_bit(HCI_PAIRABLE, &hdev->dev_flags); @@ -2862,7 +2875,7 @@ int hci_get_dev_info(void __user *arg) strcpy(di.name, hdev->name); di.bdaddr = hdev->bdaddr; di.type = (hdev->bus & 0x0f) | ((hdev->dev_type & 0x03) << 4); - di.flags = hdev->flags; + di.flags = flags; di.pkt_type = hdev->pkt_type; if (lmp_bredr_capable(hdev)) { di.acl_mtu = hdev->acl_mtu; -- cgit v1.2.3 From 12aa4f0a3d0576c554efc770a6e16c8bb897b966 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 10 Jul 2014 15:25:22 +0200 Subject: Bluetooth: Set HCI_PAIRABLE during power on for legacy ioctl When the controller is brought up using legacy ioctl, the setting of the HCI_PAIRABLE flag should happen then. Previously it was set during enumeration and when retrieving device information. This change also will not set the HCI_PAIRABLE flag when the controller is used with the HCI User Channel operation. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 96e0acc3fc92..52e8c91ea3e9 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2435,6 +2435,16 @@ int hci_dev_open(__u16 dev) */ flush_workqueue(hdev->req_workqueue); + /* For controllers not using the management interface and that + * are brought up using legacy ioctl, set the HCI_PAIRABLE bit + * so that pairing works for them. Once the management interface + * is in use this bit will be cleared again and userspace has + * to explicitly enable it. + */ + if (!test_bit(HCI_USER_CHANNEL, &hdev->dev_flags) && + !test_bit(HCI_MGMT, &hdev->dev_flags)) + set_bit(HCI_PAIRABLE, &hdev->dev_flags); + err = hci_dev_do_open(hdev); done: @@ -2826,9 +2836,6 @@ int hci_get_dev_list(void __user *arg) if (test_bit(HCI_AUTO_OFF, &hdev->dev_flags)) flags &= ~BIT(HCI_UP); - if (!test_bit(HCI_MGMT, &hdev->dev_flags)) - set_bit(HCI_PAIRABLE, &hdev->dev_flags); - (dr + n)->dev_id = hdev->id; (dr + n)->dev_opt = flags; @@ -2869,9 +2876,6 @@ int hci_get_dev_info(void __user *arg) else flags = hdev->flags; - if (!test_bit(HCI_MGMT, &hdev->dev_flags)) - set_bit(HCI_PAIRABLE, &hdev->dev_flags); - strcpy(di.name, hdev->name); di.bdaddr = hdev->bdaddr; di.type = (hdev->bus & 0x0f) | ((hdev->dev_type & 0x03) << 4); -- cgit v1.2.3 From 3ad254f7f6fd3b66ce47a156cbb92cb02002103e Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 11 Jul 2014 05:36:39 +0200 Subject: Bluetooth: Move struct hci_sec_filter next to its user There is only single location using struct hci_sec_filter and with that there is no point in putting this declaration into a global header file. So move it right next to its user and make the code a lot more simpler. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 9 --------- net/bluetooth/hci_sock.c | 8 ++++++++ 2 files changed, 8 insertions(+), 9 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 5c52a17d6326..e1930749fac7 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1360,15 +1360,6 @@ struct hci_pinfo { unsigned short channel; }; -/* HCI security filter */ -#define HCI_SFLT_MAX_OGF 5 - -struct hci_sec_filter { - __u32 type_mask; - __u32 event_mask[2]; - __u32 ocf_mask[HCI_SFLT_MAX_OGF + 1][4]; -}; - /* ----- HCI requests ----- */ #define HCI_REQ_DONE 0 #define HCI_REQ_PEND 1 diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index c64728d571ae..7805fd1b4a78 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -41,6 +41,14 @@ static inline int hci_test_bit(int nr, void *addr) } /* Security filter */ +#define HCI_SFLT_MAX_OGF 5 + +struct hci_sec_filter { + __u32 type_mask; + __u32 event_mask[2]; + __u32 ocf_mask[HCI_SFLT_MAX_OGF + 1][4]; +}; + static struct hci_sec_filter hci_sec_filter = { /* Packet types */ 0x10, -- cgit v1.2.3 From 7e67c112a007fafef6dd36c33d1029a65250ca9b Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 11 Jul 2014 05:36:40 +0200 Subject: Bluetooth: Delcare the hci_sec_filter as const The hci_sec_filter socket filter details do not change. They are fixed and with that they can also be delcared as const. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_sock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 7805fd1b4a78..0753fa4970c0 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -49,7 +49,7 @@ struct hci_sec_filter { __u32 ocf_mask[HCI_SFLT_MAX_OGF + 1][4]; }; -static struct hci_sec_filter hci_sec_filter = { +static const struct hci_sec_filter hci_sec_filter = { /* Packet types */ 0x10, /* Events */ -- cgit v1.2.3 From 863def58fec2fa494c8e9ca45471819c6d731ec3 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 11 Jul 2014 05:41:00 +0200 Subject: Bluetooth: Move struct hci_pinfo into net/bluetooth/hci_sock.c There exists no external user of struct hci_pinfo and hci_pi and thus move it into the one place that is actually using it. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 11 ----------- net/bluetooth/hci_sock.c | 11 +++++++++++ 2 files changed, 11 insertions(+), 11 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index e1930749fac7..fffd0da2e0fc 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1349,17 +1349,6 @@ void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr, void mgmt_reenable_advertising(struct hci_dev *hdev); void mgmt_smp_complete(struct hci_conn *conn, bool complete); -/* HCI info for socket */ -#define hci_pi(sk) ((struct hci_pinfo *) sk) - -struct hci_pinfo { - struct bt_sock bt; - struct hci_dev *hdev; - struct hci_filter filter; - __u32 cmsg_mask; - unsigned short channel; -}; - /* ----- HCI requests ----- */ #define HCI_REQ_DONE 0 #define HCI_REQ_PEND 1 diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 0753fa4970c0..115f149362ba 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -35,6 +35,17 @@ static atomic_t monitor_promisc = ATOMIC_INIT(0); /* ----- HCI socket interface ----- */ +/* Socket info */ +#define hci_pi(sk) ((struct hci_pinfo *) sk) + +struct hci_pinfo { + struct bt_sock bt; + struct hci_dev *hdev; + struct hci_filter filter; + __u32 cmsg_mask; + unsigned short channel; +}; + static inline int hci_test_bit(int nr, void *addr) { return *((__u32 *) addr + (nr >> 5)) & ((__u32) 1 << (nr & 31)); -- cgit v1.2.3 From 899de765667b63bb51526f0a31693aed6ad5f828 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 11 Jul 2014 05:51:58 +0200 Subject: Bluetooth: Move HCI request internals to net/bluetooth/hci_core.c The internals of the HCI request framework should not be leaking to its users. Move them all into net/bluetooth/hci_core.c and provide a simple hci_req_pending helper function for the one user outside the framework. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 9 +-------- net/bluetooth/hci_core.c | 14 ++++++++++++++ net/bluetooth/hci_event.c | 2 +- 3 files changed, 16 insertions(+), 9 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index fffd0da2e0fc..b52c2ef3f56d 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1240,6 +1240,7 @@ void hci_req_add(struct hci_request *req, u16 opcode, u32 plen, void hci_req_add_ev(struct hci_request *req, u16 opcode, u32 plen, const void *param, u8 event); void hci_req_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status); +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); @@ -1349,14 +1350,6 @@ void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr, void mgmt_reenable_advertising(struct hci_dev *hdev); void mgmt_smp_complete(struct hci_conn *conn, bool complete); -/* ----- HCI requests ----- */ -#define HCI_REQ_DONE 0 -#define HCI_REQ_PEND 1 -#define HCI_REQ_CANCELED 2 - -#define hci_req_lock(d) mutex_lock(&d->req_lock) -#define hci_req_unlock(d) mutex_unlock(&d->req_lock) - u8 hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency, u16 to_multiplier); void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __le64 rand, diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 52e8c91ea3e9..347f84fb66f9 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -54,6 +54,15 @@ DEFINE_RWLOCK(hci_cb_list_lock); /* HCI ID Numbering */ static DEFINE_IDA(hci_index_ida); +/* ----- HCI requests ----- */ + +#define HCI_REQ_DONE 0 +#define HCI_REQ_PEND 1 +#define HCI_REQ_CANCELED 2 + +#define hci_req_lock(d) mutex_lock(&d->req_lock) +#define hci_req_unlock(d) mutex_unlock(&d->req_lock) + /* ---- HCI notifications ---- */ static void hci_notify(struct hci_dev *hdev, int event) @@ -4432,6 +4441,11 @@ int hci_req_run(struct hci_request *req, hci_req_complete_t complete) return 0; } +bool hci_req_pending(struct hci_dev *hdev) +{ + return (hdev->req_status == HCI_REQ_PEND); +} + static struct sk_buff *hci_prepare_cmd(struct hci_dev *hdev, u16 opcode, u32 plen, const void *param) { diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index a62e918d2641..f0f220057f21 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4624,7 +4624,7 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) /* Received events are (currently) only needed when a request is * ongoing so avoid unnecessary memory allocation. */ - if (hdev->req_status == HCI_REQ_PEND) { + if (hci_req_pending(hdev)) { kfree_skb(hdev->recv_evt); hdev->recv_evt = skb_clone(skb, GFP_KERNEL); } -- cgit v1.2.3 From a6801ca9856c24298cba2c1fafd3da818acdaab6 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 11 Jul 2014 06:03:08 +0200 Subject: Bluetooth: Update the list of L2CAP fixed channels The list of L2CAP fixed channels increased with newer versions of the specification. This just updates the constants for it. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/l2cap.h | 5 ++++- net/bluetooth/l2cap_core.c | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index e0c6a9abdb62..d8e7b9330ab8 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -134,9 +134,12 @@ struct l2cap_conninfo { #define L2CAP_FCS_CRC16 0x01 /* L2CAP fixed channels */ -#define L2CAP_FC_L2CAP 0x02 +#define L2CAP_FC_SIG_BREDR 0x02 #define L2CAP_FC_CONNLESS 0x04 #define L2CAP_FC_A2MP 0x08 +#define L2CAP_FC_ATT 0x10 +#define L2CAP_FC_SIG_LE 0x20 +#define L2CAP_FC_SMP_LE 0x40 /* L2CAP Control Field bit masks */ #define L2CAP_CTRL_SAR 0xC000 diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 8680aae678ce..0c3c4935f635 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -46,7 +46,7 @@ bool disable_ertm; static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN | L2CAP_FEAT_UCD; -static u8 l2cap_fixed_chan[8] = { L2CAP_FC_L2CAP | L2CAP_FC_CONNLESS, }; +static u8 l2cap_fixed_chan[8] = { L2CAP_FC_SIG_BREDR | L2CAP_FC_CONNLESS, }; static LIST_HEAD(chan_list); static DEFINE_RWLOCK(chan_list_lock); -- cgit v1.2.3 From 2a0dccb3df2c8775d1a6e962aa88c4c22693c887 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 11 Jul 2014 06:19:41 +0200 Subject: Bluetooth: Move struct sco_pinfo into net/bluetooth/sco.c There exists no external user of struct sco_pinfo and sco_pi and thus move it into the one place that is actually using it. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/sco.h | 12 ------------ net/bluetooth/sco.c | 12 ++++++++++++ 2 files changed, 12 insertions(+), 12 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/sco.h b/include/net/bluetooth/sco.h index 2019d1a0996a..7fec7cbd7396 100644 --- a/include/net/bluetooth/sco.h +++ b/include/net/bluetooth/sco.h @@ -64,16 +64,4 @@ struct sco_conn { #define sco_conn_lock(c) spin_lock(&c->lock); #define sco_conn_unlock(c) spin_unlock(&c->lock); -/* ----- SCO socket info ----- */ -#define sco_pi(sk) ((struct sco_pinfo *) sk) - -struct sco_pinfo { - struct bt_sock bt; - bdaddr_t src; - bdaddr_t dst; - __u32 flags; - __u16 setting; - struct sco_conn *conn; -}; - #endif /* __SCO_H */ diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index c06dbd3938e8..c71698642ec6 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -46,6 +46,18 @@ static void sco_chan_del(struct sock *sk, int err); static void sco_sock_close(struct sock *sk); static void sco_sock_kill(struct sock *sk); +/* ----- SCO socket info ----- */ +#define sco_pi(sk) ((struct sco_pinfo *) sk) + +struct sco_pinfo { + struct bt_sock bt; + bdaddr_t src; + bdaddr_t dst; + __u32 flags; + __u16 setting; + struct sco_conn *conn; +}; + /* ---- SCO timers ---- */ static void sco_sock_timeout(unsigned long arg) { -- cgit v1.2.3 From fc8f525a6f7c81743bec6b5d497988313b211383 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 11 Jul 2014 06:19:42 +0200 Subject: Bluetooth: Move struct sco_conn into net/bluetooth/sco.c There exists no external user of struct sco_conn and thus move it into the one place that is actually using it. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/sco.h | 13 ------------- net/bluetooth/sco.c | 13 +++++++++++++ 2 files changed, 13 insertions(+), 13 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/sco.h b/include/net/bluetooth/sco.h index 7fec7cbd7396..42a0d089d715 100644 --- a/include/net/bluetooth/sco.h +++ b/include/net/bluetooth/sco.h @@ -51,17 +51,4 @@ struct sco_conninfo { __u8 dev_class[3]; }; -/* ---- SCO connections ---- */ -struct sco_conn { - struct hci_conn *hcon; - - spinlock_t lock; - struct sock *sk; - - unsigned int mtu; -}; - -#define sco_conn_lock(c) spin_lock(&c->lock); -#define sco_conn_unlock(c) spin_unlock(&c->lock); - #endif /* __SCO_H */ diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index c71698642ec6..9868ec7c7dc4 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -40,6 +40,19 @@ static struct bt_sock_list sco_sk_list = { .lock = __RW_LOCK_UNLOCKED(sco_sk_list.lock) }; +/* ---- SCO connections ---- */ +struct sco_conn { + struct hci_conn *hcon; + + spinlock_t lock; + struct sock *sk; + + unsigned int mtu; +}; + +#define sco_conn_lock(c) spin_lock(&c->lock); +#define sco_conn_unlock(c) spin_unlock(&c->lock); + static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent); static void sco_chan_del(struct sock *sk, int err); -- cgit v1.2.3 From 068d69e5bbd85291aa8ad0d81062f047609a173c Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 11 Jul 2014 06:19:44 +0200 Subject: Bluetooth: Move SCO timeout constants into net/bluetooth/sco.c There is no external user of the SCO timeout constants and thus move them into net/bluetooth/sco.c where they are actuallu used. In addition just remove SCO_CONN_IDLE_TIMEOUT since it is unused. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/sco.h | 4 ---- net/bluetooth/sco.c | 3 +++ 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/sco.h b/include/net/bluetooth/sco.h index ab8b1ed550d2..f40ddb4264fc 100644 --- a/include/net/bluetooth/sco.h +++ b/include/net/bluetooth/sco.h @@ -28,10 +28,6 @@ /* SCO defaults */ #define SCO_DEFAULT_MTU 500 -#define SCO_CONN_TIMEOUT (HZ * 40) -#define SCO_DISCONN_TIMEOUT (HZ * 2) -#define SCO_CONN_IDLE_TIMEOUT (HZ * 60) - /* SCO socket address */ struct sockaddr_sco { sa_family_t sco_family; diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 9868ec7c7dc4..e6c7b636b901 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -72,6 +72,9 @@ struct sco_pinfo { }; /* ---- SCO timers ---- */ +#define SCO_CONN_TIMEOUT (HZ * 40) +#define SCO_DISCONN_TIMEOUT (HZ * 2) + static void sco_sock_timeout(unsigned long arg) { struct sock *sk = (struct sock *) arg; -- cgit v1.2.3 From 6c53823ae0e10e723131055e1e65dd6a328a228e Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 11 Jul 2014 15:32:23 +0300 Subject: Bluetooth: Fix tracking local SSP authentication requirement When we need to make the decision whether to perform just-works or real user confirmation we need to know the exact local authentication requirement that was passed to the controller. So far conn->auth_type (the local requirement) wasn't in one case updated appropriately in fear of the user confirmation being rejected later. The real problem however was not really that conn->auth_type couldn't represent the true value but that we were checking the local MITM requirement in an incorrect way. It's perfectly fine to let auth_type follow what we tell the controller since we're still tracking the target security level with conn->pending_sec_level. This patch updates the check for local MITM requirement in the hci_user_confirm_request_evt function to use the locally requested security level and ensures that auth_type always represents what we tell the controller. All other code in hci_user_confirm_request_evt still uses the auth_type instead of pending_sec_level for determining whether to do just-works or not, since that's the only value that's in sync with what the remote device knows. Signed-off-by: Johan Hedberg Tested-by: Szymon Janc Signed-off-by: Marcel Holtmann Cc: stable@vger.kernel.org # 3.16 --- net/bluetooth/hci_event.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index f0f220057f21..8980bd24b8c0 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3664,18 +3664,14 @@ static void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff *skb) /* If we are initiators, there is no remote information yet */ if (conn->remote_auth == 0xff) { - cp.authentication = conn->auth_type; - /* Request MITM protection if our IO caps allow it * except for the no-bonding case. - * conn->auth_type is not updated here since - * that might cause the user confirmation to be - * rejected in case the remote doesn't have the - * IO capabilities for MITM. */ if (conn->io_capability != HCI_IO_NO_INPUT_OUTPUT && cp.authentication != HCI_AT_NO_BONDING) - cp.authentication |= 0x01; + conn->auth_type |= 0x01; + + cp.authentication = conn->auth_type; } else { conn->auth_type = hci_get_auth_req(conn); cp.authentication = conn->auth_type; @@ -3747,9 +3743,12 @@ static void hci_user_confirm_request_evt(struct hci_dev *hdev, rem_mitm = (conn->remote_auth & 0x01); /* If we require MITM but the remote device can't provide that - * (it has NoInputNoOutput) then reject the confirmation request + * (it has NoInputNoOutput) then reject the confirmation + * request. We check the security level here since it doesn't + * necessarily match conn->auth_type. */ - if (loc_mitm && conn->remote_cap == HCI_IO_NO_INPUT_OUTPUT) { + if (conn->pending_sec_level > BT_SECURITY_MEDIUM && + conn->remote_cap == HCI_IO_NO_INPUT_OUTPUT) { BT_DBG("Rejecting request: remote device can't provide MITM"); hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_NEG_REPLY, sizeof(ev->bdaddr), &ev->bdaddr); -- cgit v1.2.3 From 2c6bed7cfcd3f594ed9e4d6919fa2ebea2243d19 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Fri, 11 Jul 2014 10:24:18 +0200 Subject: 6lowpan: introduce new net/6lowpan directory This patch moves generic code which is used by bluetooth and ieee802154 6lowpan to a new net/6lowpan directory. This directory contains generic 6LoWPAN code which is shared between bluetooth and ieee802154 MAC-Layer. This is the IPHC - "IPv6 Header Compression" format at the moment. Which is described by RFC 6282 [0]. The BLTE 6LoWPAN draft describes that the IPHC is the same format like IEEE 802.15.4, see [1]. Futuremore we can put more code into this directory which is shared between BLTE and IEEE 802.15.4 6LoWPAN like RFC 6775 or the routing protocol RPL RFC 6550. To avoid naming conflicts I renamed 6lowpan-y to ieee802154_6lowpan-y in net/ieee802154/Makefile. [0] http://tools.ietf.org/html/rfc6282 [1] http://tools.ietf.org/html/draft-ietf-6lowpan-btle-12#section-3.2 [2] http://tools.ietf.org/html/rfc6775 [3] http://tools.ietf.org/html/rfc6550 Signed-off-by: Alexander Aring Acked-by: Jukka Rissanen Signed-off-by: Marcel Holtmann --- net/6lowpan/Kconfig | 6 + net/6lowpan/Makefile | 3 + net/6lowpan/iphc.c | 801 ++++++++++++++++++++++++++++++++++++++++++ net/Kconfig | 1 + net/Makefile | 3 +- net/bluetooth/Kconfig | 3 +- net/ieee802154/6lowpan_iphc.c | 801 ------------------------------------------ net/ieee802154/Kconfig | 9 +- net/ieee802154/Makefile | 5 +- 9 files changed, 817 insertions(+), 815 deletions(-) create mode 100644 net/6lowpan/Kconfig create mode 100644 net/6lowpan/Makefile create mode 100644 net/6lowpan/iphc.c delete mode 100644 net/ieee802154/6lowpan_iphc.c (limited to 'net/bluetooth') diff --git a/net/6lowpan/Kconfig b/net/6lowpan/Kconfig new file mode 100644 index 000000000000..028a5c6d1f61 --- /dev/null +++ b/net/6lowpan/Kconfig @@ -0,0 +1,6 @@ +config 6LOWPAN + bool "6LoWPAN Support" + depends on IPV6 + ---help--- + This enables IPv6 over Low power Wireless Personal Area Network - + "6LoWPAN" which is supported by IEEE 802.15.4 or Bluetooth stacks. diff --git a/net/6lowpan/Makefile b/net/6lowpan/Makefile new file mode 100644 index 000000000000..415886bb456a --- /dev/null +++ b/net/6lowpan/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_6LOWPAN) := 6lowpan.o + +6lowpan-y := iphc.o diff --git a/net/6lowpan/iphc.c b/net/6lowpan/iphc.c new file mode 100644 index 000000000000..211b5686d719 --- /dev/null +++ b/net/6lowpan/iphc.c @@ -0,0 +1,801 @@ +/* + * Copyright 2011, Siemens AG + * written by Alexander Smirnov + */ + +/* + * Based on patches from Jon Smirl + * Copyright (c) 2011 Jon Smirl + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/* Jon's code is based on 6lowpan implementation for Contiki which is: + * Copyright (c) 2008, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* + * Uncompress address function for source and + * destination address(non-multicast). + * + * address_mode is sam value or dam value. + */ +static int uncompress_addr(struct sk_buff *skb, + struct in6_addr *ipaddr, const u8 address_mode, + const u8 *lladdr, const u8 addr_type, + const u8 addr_len) +{ + bool fail; + + switch (address_mode) { + case LOWPAN_IPHC_ADDR_00: + /* for global link addresses */ + fail = lowpan_fetch_skb(skb, ipaddr->s6_addr, 16); + break; + case LOWPAN_IPHC_ADDR_01: + /* fe:80::XXXX:XXXX:XXXX:XXXX */ + ipaddr->s6_addr[0] = 0xFE; + ipaddr->s6_addr[1] = 0x80; + fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[8], 8); + break; + case LOWPAN_IPHC_ADDR_02: + /* fe:80::ff:fe00:XXXX */ + ipaddr->s6_addr[0] = 0xFE; + ipaddr->s6_addr[1] = 0x80; + ipaddr->s6_addr[11] = 0xFF; + ipaddr->s6_addr[12] = 0xFE; + fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[14], 2); + break; + case LOWPAN_IPHC_ADDR_03: + fail = false; + switch (addr_type) { + case IEEE802154_ADDR_LONG: + /* fe:80::XXXX:XXXX:XXXX:XXXX + * \_________________/ + * hwaddr + */ + ipaddr->s6_addr[0] = 0xFE; + ipaddr->s6_addr[1] = 0x80; + memcpy(&ipaddr->s6_addr[8], lladdr, addr_len); + /* second bit-flip (Universe/Local) + * is done according RFC2464 + */ + ipaddr->s6_addr[8] ^= 0x02; + break; + case IEEE802154_ADDR_SHORT: + /* fe:80::ff:fe00:XXXX + * \__/ + * short_addr + * + * Universe/Local bit is zero. + */ + ipaddr->s6_addr[0] = 0xFE; + ipaddr->s6_addr[1] = 0x80; + ipaddr->s6_addr[11] = 0xFF; + ipaddr->s6_addr[12] = 0xFE; + ipaddr->s6_addr16[7] = htons(*((u16 *)lladdr)); + break; + default: + pr_debug("Invalid addr_type set\n"); + return -EINVAL; + } + break; + default: + pr_debug("Invalid address mode value: 0x%x\n", address_mode); + return -EINVAL; + } + + if (fail) { + pr_debug("Failed to fetch skb data\n"); + return -EIO; + } + + raw_dump_inline(NULL, "Reconstructed ipv6 addr is", + ipaddr->s6_addr, 16); + + return 0; +} + +/* + * Uncompress address function for source context + * based address(non-multicast). + */ +static int uncompress_context_based_src_addr(struct sk_buff *skb, + struct in6_addr *ipaddr, + const u8 sam) +{ + switch (sam) { + case LOWPAN_IPHC_ADDR_00: + /* unspec address :: + * Do nothing, address is already :: + */ + break; + case LOWPAN_IPHC_ADDR_01: + /* TODO */ + case LOWPAN_IPHC_ADDR_02: + /* TODO */ + case LOWPAN_IPHC_ADDR_03: + /* TODO */ + netdev_warn(skb->dev, "SAM value 0x%x not supported\n", sam); + return -EINVAL; + default: + pr_debug("Invalid sam value: 0x%x\n", sam); + return -EINVAL; + } + + raw_dump_inline(NULL, + "Reconstructed context based ipv6 src addr is", + ipaddr->s6_addr, 16); + + return 0; +} + +static int skb_deliver(struct sk_buff *skb, struct ipv6hdr *hdr, + struct net_device *dev, skb_delivery_cb deliver_skb) +{ + struct sk_buff *new; + int stat; + + new = skb_copy_expand(skb, sizeof(struct ipv6hdr), skb_tailroom(skb), + GFP_ATOMIC); + kfree_skb(skb); + + if (!new) + return -ENOMEM; + + skb_push(new, sizeof(struct ipv6hdr)); + skb_reset_network_header(new); + skb_copy_to_linear_data(new, hdr, sizeof(struct ipv6hdr)); + + new->protocol = htons(ETH_P_IPV6); + new->pkt_type = PACKET_HOST; + new->dev = dev; + + raw_dump_table(__func__, "raw skb data dump before receiving", + new->data, new->len); + + stat = deliver_skb(new, dev); + + kfree_skb(new); + + return stat; +} + +/* Uncompress function for multicast destination address, + * when M bit is set. + */ +static int +lowpan_uncompress_multicast_daddr(struct sk_buff *skb, + struct in6_addr *ipaddr, + const u8 dam) +{ + bool fail; + + switch (dam) { + case LOWPAN_IPHC_DAM_00: + /* 00: 128 bits. The full address + * is carried in-line. + */ + fail = lowpan_fetch_skb(skb, ipaddr->s6_addr, 16); + break; + case LOWPAN_IPHC_DAM_01: + /* 01: 48 bits. The address takes + * the form ffXX::00XX:XXXX:XXXX. + */ + ipaddr->s6_addr[0] = 0xFF; + fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[1], 1); + fail |= lowpan_fetch_skb(skb, &ipaddr->s6_addr[11], 5); + break; + case LOWPAN_IPHC_DAM_10: + /* 10: 32 bits. The address takes + * the form ffXX::00XX:XXXX. + */ + ipaddr->s6_addr[0] = 0xFF; + fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[1], 1); + fail |= lowpan_fetch_skb(skb, &ipaddr->s6_addr[13], 3); + break; + case LOWPAN_IPHC_DAM_11: + /* 11: 8 bits. The address takes + * the form ff02::00XX. + */ + ipaddr->s6_addr[0] = 0xFF; + ipaddr->s6_addr[1] = 0x02; + fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[15], 1); + break; + default: + pr_debug("DAM value has a wrong value: 0x%x\n", dam); + return -EINVAL; + } + + if (fail) { + pr_debug("Failed to fetch skb data\n"); + return -EIO; + } + + raw_dump_inline(NULL, "Reconstructed ipv6 multicast addr is", + ipaddr->s6_addr, 16); + + return 0; +} + +static int +uncompress_udp_header(struct sk_buff *skb, struct udphdr *uh) +{ + bool fail; + u8 tmp = 0, val = 0; + + if (!uh) + goto err; + + fail = lowpan_fetch_skb(skb, &tmp, 1); + + if ((tmp & LOWPAN_NHC_UDP_MASK) == LOWPAN_NHC_UDP_ID) { + pr_debug("UDP header uncompression\n"); + switch (tmp & LOWPAN_NHC_UDP_CS_P_11) { + case LOWPAN_NHC_UDP_CS_P_00: + fail |= lowpan_fetch_skb(skb, &uh->source, 2); + fail |= lowpan_fetch_skb(skb, &uh->dest, 2); + break; + case LOWPAN_NHC_UDP_CS_P_01: + fail |= lowpan_fetch_skb(skb, &uh->source, 2); + fail |= lowpan_fetch_skb(skb, &val, 1); + uh->dest = htons(val + LOWPAN_NHC_UDP_8BIT_PORT); + break; + case LOWPAN_NHC_UDP_CS_P_10: + fail |= lowpan_fetch_skb(skb, &val, 1); + uh->source = htons(val + LOWPAN_NHC_UDP_8BIT_PORT); + fail |= lowpan_fetch_skb(skb, &uh->dest, 2); + break; + case LOWPAN_NHC_UDP_CS_P_11: + fail |= lowpan_fetch_skb(skb, &val, 1); + uh->source = htons(LOWPAN_NHC_UDP_4BIT_PORT + + (val >> 4)); + uh->dest = htons(LOWPAN_NHC_UDP_4BIT_PORT + + (val & 0x0f)); + break; + default: + pr_debug("ERROR: unknown UDP format\n"); + goto err; + break; + } + + pr_debug("uncompressed UDP ports: src = %d, dst = %d\n", + ntohs(uh->source), ntohs(uh->dest)); + + /* checksum */ + if (tmp & LOWPAN_NHC_UDP_CS_C) { + pr_debug_ratelimited("checksum elided currently not supported\n"); + goto err; + } else { + fail |= lowpan_fetch_skb(skb, &uh->check, 2); + } + + /* + * UDP lenght needs to be infered from the lower layers + * here, we obtain the hint from the remaining size of the + * frame + */ + uh->len = htons(skb->len + sizeof(struct udphdr)); + pr_debug("uncompressed UDP length: src = %d", ntohs(uh->len)); + } else { + pr_debug("ERROR: unsupported NH format\n"); + goto err; + } + + if (fail) + goto err; + + return 0; +err: + return -EINVAL; +} + +/* TTL uncompression values */ +static const u8 lowpan_ttl_values[] = { 0, 1, 64, 255 }; + +int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, + const u8 *saddr, const u8 saddr_type, const u8 saddr_len, + const u8 *daddr, const u8 daddr_type, const u8 daddr_len, + u8 iphc0, u8 iphc1, skb_delivery_cb deliver_skb) +{ + struct ipv6hdr hdr = {}; + u8 tmp, num_context = 0; + int err; + + raw_dump_table(__func__, "raw skb data dump uncompressed", + skb->data, skb->len); + + /* another if the CID flag is set */ + if (iphc1 & LOWPAN_IPHC_CID) { + pr_debug("CID flag is set, increase header with one\n"); + if (lowpan_fetch_skb_u8(skb, &num_context)) + goto drop; + } + + hdr.version = 6; + + /* Traffic Class and Flow Label */ + switch ((iphc0 & LOWPAN_IPHC_TF) >> 3) { + /* + * Traffic Class and FLow Label carried in-line + * ECN + DSCP + 4-bit Pad + Flow Label (4 bytes) + */ + case 0: /* 00b */ + if (lowpan_fetch_skb_u8(skb, &tmp)) + goto drop; + + memcpy(&hdr.flow_lbl, &skb->data[0], 3); + skb_pull(skb, 3); + hdr.priority = ((tmp >> 2) & 0x0f); + hdr.flow_lbl[0] = ((tmp >> 2) & 0x30) | (tmp << 6) | + (hdr.flow_lbl[0] & 0x0f); + break; + /* + * Traffic class carried in-line + * ECN + DSCP (1 byte), Flow Label is elided + */ + case 2: /* 10b */ + if (lowpan_fetch_skb_u8(skb, &tmp)) + goto drop; + + hdr.priority = ((tmp >> 2) & 0x0f); + hdr.flow_lbl[0] = ((tmp << 6) & 0xC0) | ((tmp >> 2) & 0x30); + break; + /* + * Flow Label carried in-line + * ECN + 2-bit Pad + Flow Label (3 bytes), DSCP is elided + */ + case 1: /* 01b */ + if (lowpan_fetch_skb_u8(skb, &tmp)) + goto drop; + + hdr.flow_lbl[0] = (skb->data[0] & 0x0F) | ((tmp >> 2) & 0x30); + memcpy(&hdr.flow_lbl[1], &skb->data[0], 2); + skb_pull(skb, 2); + break; + /* Traffic Class and Flow Label are elided */ + case 3: /* 11b */ + break; + default: + break; + } + + /* Next Header */ + if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) { + /* Next header is carried inline */ + if (lowpan_fetch_skb_u8(skb, &(hdr.nexthdr))) + goto drop; + + pr_debug("NH flag is set, next header carried inline: %02x\n", + hdr.nexthdr); + } + + /* Hop Limit */ + if ((iphc0 & 0x03) != LOWPAN_IPHC_TTL_I) + hdr.hop_limit = lowpan_ttl_values[iphc0 & 0x03]; + else { + if (lowpan_fetch_skb_u8(skb, &(hdr.hop_limit))) + goto drop; + } + + /* Extract SAM to the tmp variable */ + tmp = ((iphc1 & LOWPAN_IPHC_SAM) >> LOWPAN_IPHC_SAM_BIT) & 0x03; + + if (iphc1 & LOWPAN_IPHC_SAC) { + /* Source address context based uncompression */ + pr_debug("SAC bit is set. Handle context based source address.\n"); + err = uncompress_context_based_src_addr( + skb, &hdr.saddr, tmp); + } else { + /* Source address uncompression */ + pr_debug("source address stateless compression\n"); + err = uncompress_addr(skb, &hdr.saddr, tmp, saddr, + saddr_type, saddr_len); + } + + /* Check on error of previous branch */ + if (err) + goto drop; + + /* Extract DAM to the tmp variable */ + tmp = ((iphc1 & LOWPAN_IPHC_DAM_11) >> LOWPAN_IPHC_DAM_BIT) & 0x03; + + /* check for Multicast Compression */ + if (iphc1 & LOWPAN_IPHC_M) { + if (iphc1 & LOWPAN_IPHC_DAC) { + pr_debug("dest: context-based mcast compression\n"); + /* TODO: implement this */ + } else { + err = lowpan_uncompress_multicast_daddr( + skb, &hdr.daddr, tmp); + if (err) + goto drop; + } + } else { + err = uncompress_addr(skb, &hdr.daddr, tmp, daddr, + daddr_type, daddr_len); + pr_debug("dest: stateless compression mode %d dest %pI6c\n", + tmp, &hdr.daddr); + if (err) + goto drop; + } + + /* UDP data uncompression */ + if (iphc0 & LOWPAN_IPHC_NH_C) { + struct udphdr uh; + struct sk_buff *new; + if (uncompress_udp_header(skb, &uh)) + goto drop; + + /* + * replace the compressed UDP head by the uncompressed UDP + * header + */ + new = skb_copy_expand(skb, sizeof(struct udphdr), + skb_tailroom(skb), GFP_ATOMIC); + kfree_skb(skb); + + if (!new) + return -ENOMEM; + + skb = new; + + skb_push(skb, sizeof(struct udphdr)); + skb_reset_transport_header(skb); + skb_copy_to_linear_data(skb, &uh, sizeof(struct udphdr)); + + raw_dump_table(__func__, "raw UDP header dump", + (u8 *)&uh, sizeof(uh)); + + hdr.nexthdr = UIP_PROTO_UDP; + } + + hdr.payload_len = htons(skb->len); + + pr_debug("skb headroom size = %d, data length = %d\n", + skb_headroom(skb), skb->len); + + pr_debug("IPv6 header dump:\n\tversion = %d\n\tlength = %d\n\t" + "nexthdr = 0x%02x\n\thop_lim = %d\n\tdest = %pI6c\n", + hdr.version, ntohs(hdr.payload_len), hdr.nexthdr, + hdr.hop_limit, &hdr.daddr); + + raw_dump_table(__func__, "raw header dump", (u8 *)&hdr, + sizeof(hdr)); + + return skb_deliver(skb, &hdr, dev, deliver_skb); + +drop: + kfree_skb(skb); + return -EINVAL; +} +EXPORT_SYMBOL_GPL(lowpan_process_data); + +static u8 lowpan_compress_addr_64(u8 **hc06_ptr, u8 shift, + const struct in6_addr *ipaddr, + const unsigned char *lladdr) +{ + u8 val = 0; + + if (is_addr_mac_addr_based(ipaddr, lladdr)) { + val = 3; /* 0-bits */ + pr_debug("address compression 0 bits\n"); + } else if (lowpan_is_iid_16_bit_compressable(ipaddr)) { + /* compress IID to 16 bits xxxx::XXXX */ + memcpy(*hc06_ptr, &ipaddr->s6_addr16[7], 2); + *hc06_ptr += 2; + val = 2; /* 16-bits */ + raw_dump_inline(NULL, "Compressed ipv6 addr is (16 bits)", + *hc06_ptr - 2, 2); + } else { + /* do not compress IID => xxxx::IID */ + memcpy(*hc06_ptr, &ipaddr->s6_addr16[4], 8); + *hc06_ptr += 8; + val = 1; /* 64-bits */ + raw_dump_inline(NULL, "Compressed ipv6 addr is (64 bits)", + *hc06_ptr - 8, 8); + } + + return rol8(val, shift); +} + +static void compress_udp_header(u8 **hc06_ptr, struct sk_buff *skb) +{ + struct udphdr *uh = udp_hdr(skb); + u8 tmp; + + if (((ntohs(uh->source) & LOWPAN_NHC_UDP_4BIT_MASK) == + LOWPAN_NHC_UDP_4BIT_PORT) && + ((ntohs(uh->dest) & LOWPAN_NHC_UDP_4BIT_MASK) == + LOWPAN_NHC_UDP_4BIT_PORT)) { + pr_debug("UDP header: both ports compression to 4 bits\n"); + /* compression value */ + tmp = LOWPAN_NHC_UDP_CS_P_11; + lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); + /* source and destination port */ + tmp = ntohs(uh->dest) - LOWPAN_NHC_UDP_4BIT_PORT + + ((ntohs(uh->source) - LOWPAN_NHC_UDP_4BIT_PORT) << 4); + lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); + } else if ((ntohs(uh->dest) & LOWPAN_NHC_UDP_8BIT_MASK) == + LOWPAN_NHC_UDP_8BIT_PORT) { + pr_debug("UDP header: remove 8 bits of dest\n"); + /* compression value */ + tmp = LOWPAN_NHC_UDP_CS_P_01; + lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); + /* source port */ + lowpan_push_hc_data(hc06_ptr, &uh->source, sizeof(uh->source)); + /* destination port */ + tmp = ntohs(uh->dest) - LOWPAN_NHC_UDP_8BIT_PORT; + lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); + } else if ((ntohs(uh->source) & LOWPAN_NHC_UDP_8BIT_MASK) == + LOWPAN_NHC_UDP_8BIT_PORT) { + pr_debug("UDP header: remove 8 bits of source\n"); + /* compression value */ + tmp = LOWPAN_NHC_UDP_CS_P_10; + lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); + /* source port */ + tmp = ntohs(uh->source) - LOWPAN_NHC_UDP_8BIT_PORT; + lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); + /* destination port */ + lowpan_push_hc_data(hc06_ptr, &uh->dest, sizeof(uh->dest)); + } else { + pr_debug("UDP header: can't compress\n"); + /* compression value */ + tmp = LOWPAN_NHC_UDP_CS_P_00; + lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); + /* source port */ + lowpan_push_hc_data(hc06_ptr, &uh->source, sizeof(uh->source)); + /* destination port */ + lowpan_push_hc_data(hc06_ptr, &uh->dest, sizeof(uh->dest)); + } + + /* checksum is always inline */ + lowpan_push_hc_data(hc06_ptr, &uh->check, sizeof(uh->check)); + + /* skip the UDP header */ + skb_pull(skb, sizeof(struct udphdr)); +} + +int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, + unsigned short type, const void *_daddr, + const void *_saddr, unsigned int len) +{ + u8 tmp, iphc0, iphc1, *hc06_ptr; + struct ipv6hdr *hdr; + u8 head[100] = {}; + + if (type != ETH_P_IPV6) + return -EINVAL; + + hdr = ipv6_hdr(skb); + hc06_ptr = head + 2; + + pr_debug("IPv6 header dump:\n\tversion = %d\n\tlength = %d\n" + "\tnexthdr = 0x%02x\n\thop_lim = %d\n\tdest = %pI6c\n", + hdr->version, ntohs(hdr->payload_len), hdr->nexthdr, + hdr->hop_limit, &hdr->daddr); + + raw_dump_table(__func__, "raw skb network header dump", + skb_network_header(skb), sizeof(struct ipv6hdr)); + + /* + * As we copy some bit-length fields, in the IPHC encoding bytes, + * we sometimes use |= + * If the field is 0, and the current bit value in memory is 1, + * this does not work. We therefore reset the IPHC encoding here + */ + iphc0 = LOWPAN_DISPATCH_IPHC; + iphc1 = 0; + + /* TODO: context lookup */ + + raw_dump_inline(__func__, "saddr", + (unsigned char *)_saddr, IEEE802154_ADDR_LEN); + raw_dump_inline(__func__, "daddr", + (unsigned char *)_daddr, IEEE802154_ADDR_LEN); + + raw_dump_table(__func__, + "sending raw skb network uncompressed packet", + skb->data, skb->len); + + /* + * Traffic class, flow label + * If flow label is 0, compress it. If traffic class is 0, compress it + * We have to process both in the same time as the offset of traffic + * class depends on the presence of version and flow label + */ + + /* hc06 format of TC is ECN | DSCP , original one is DSCP | ECN */ + tmp = (hdr->priority << 4) | (hdr->flow_lbl[0] >> 4); + tmp = ((tmp & 0x03) << 6) | (tmp >> 2); + + if (((hdr->flow_lbl[0] & 0x0F) == 0) && + (hdr->flow_lbl[1] == 0) && (hdr->flow_lbl[2] == 0)) { + /* flow label can be compressed */ + iphc0 |= LOWPAN_IPHC_FL_C; + if ((hdr->priority == 0) && + ((hdr->flow_lbl[0] & 0xF0) == 0)) { + /* compress (elide) all */ + iphc0 |= LOWPAN_IPHC_TC_C; + } else { + /* compress only the flow label */ + *hc06_ptr = tmp; + hc06_ptr += 1; + } + } else { + /* Flow label cannot be compressed */ + if ((hdr->priority == 0) && + ((hdr->flow_lbl[0] & 0xF0) == 0)) { + /* compress only traffic class */ + iphc0 |= LOWPAN_IPHC_TC_C; + *hc06_ptr = (tmp & 0xc0) | (hdr->flow_lbl[0] & 0x0F); + memcpy(hc06_ptr + 1, &hdr->flow_lbl[1], 2); + hc06_ptr += 3; + } else { + /* compress nothing */ + memcpy(hc06_ptr, hdr, 4); + /* replace the top byte with new ECN | DSCP format */ + *hc06_ptr = tmp; + hc06_ptr += 4; + } + } + + /* NOTE: payload length is always compressed */ + + /* Next Header is compress if UDP */ + if (hdr->nexthdr == UIP_PROTO_UDP) + iphc0 |= LOWPAN_IPHC_NH_C; + + if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) { + *hc06_ptr = hdr->nexthdr; + hc06_ptr += 1; + } + + /* + * Hop limit + * if 1: compress, encoding is 01 + * if 64: compress, encoding is 10 + * if 255: compress, encoding is 11 + * else do not compress + */ + switch (hdr->hop_limit) { + case 1: + iphc0 |= LOWPAN_IPHC_TTL_1; + break; + case 64: + iphc0 |= LOWPAN_IPHC_TTL_64; + break; + case 255: + iphc0 |= LOWPAN_IPHC_TTL_255; + break; + default: + *hc06_ptr = hdr->hop_limit; + hc06_ptr += 1; + break; + } + + /* source address compression */ + if (is_addr_unspecified(&hdr->saddr)) { + pr_debug("source address is unspecified, setting SAC\n"); + iphc1 |= LOWPAN_IPHC_SAC; + /* TODO: context lookup */ + } else if (is_addr_link_local(&hdr->saddr)) { + iphc1 |= lowpan_compress_addr_64(&hc06_ptr, + LOWPAN_IPHC_SAM_BIT, &hdr->saddr, _saddr); + pr_debug("source address unicast link-local %pI6c " + "iphc1 0x%02x\n", &hdr->saddr, iphc1); + } else { + pr_debug("send the full source address\n"); + memcpy(hc06_ptr, &hdr->saddr.s6_addr16[0], 16); + hc06_ptr += 16; + } + + /* destination address compression */ + if (is_addr_mcast(&hdr->daddr)) { + pr_debug("destination address is multicast: "); + iphc1 |= LOWPAN_IPHC_M; + if (lowpan_is_mcast_addr_compressable8(&hdr->daddr)) { + pr_debug("compressed to 1 octet\n"); + iphc1 |= LOWPAN_IPHC_DAM_11; + /* use last byte */ + *hc06_ptr = hdr->daddr.s6_addr[15]; + hc06_ptr += 1; + } else if (lowpan_is_mcast_addr_compressable32(&hdr->daddr)) { + pr_debug("compressed to 4 octets\n"); + iphc1 |= LOWPAN_IPHC_DAM_10; + /* second byte + the last three */ + *hc06_ptr = hdr->daddr.s6_addr[1]; + memcpy(hc06_ptr + 1, &hdr->daddr.s6_addr[13], 3); + hc06_ptr += 4; + } else if (lowpan_is_mcast_addr_compressable48(&hdr->daddr)) { + pr_debug("compressed to 6 octets\n"); + iphc1 |= LOWPAN_IPHC_DAM_01; + /* second byte + the last five */ + *hc06_ptr = hdr->daddr.s6_addr[1]; + memcpy(hc06_ptr + 1, &hdr->daddr.s6_addr[11], 5); + hc06_ptr += 6; + } else { + pr_debug("using full address\n"); + iphc1 |= LOWPAN_IPHC_DAM_00; + memcpy(hc06_ptr, &hdr->daddr.s6_addr[0], 16); + hc06_ptr += 16; + } + } else { + /* TODO: context lookup */ + if (is_addr_link_local(&hdr->daddr)) { + iphc1 |= lowpan_compress_addr_64(&hc06_ptr, + LOWPAN_IPHC_DAM_BIT, &hdr->daddr, _daddr); + pr_debug("dest address unicast link-local %pI6c " + "iphc1 0x%02x\n", &hdr->daddr, iphc1); + } else { + pr_debug("dest address unicast %pI6c\n", &hdr->daddr); + memcpy(hc06_ptr, &hdr->daddr.s6_addr16[0], 16); + hc06_ptr += 16; + } + } + + /* UDP header compression */ + if (hdr->nexthdr == UIP_PROTO_UDP) + compress_udp_header(&hc06_ptr, skb); + + head[0] = iphc0; + head[1] = iphc1; + + skb_pull(skb, sizeof(struct ipv6hdr)); + skb_reset_transport_header(skb); + memcpy(skb_push(skb, hc06_ptr - head), head, hc06_ptr - head); + skb_reset_network_header(skb); + + pr_debug("header len %d skb %u\n", (int)(hc06_ptr - head), skb->len); + + raw_dump_table(__func__, "raw skb data dump compressed", + skb->data, skb->len); + return 0; +} +EXPORT_SYMBOL_GPL(lowpan_header_compress); + +MODULE_LICENSE("GPL"); diff --git a/net/Kconfig b/net/Kconfig index d92afe4204d9..4051fdfa4367 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -214,6 +214,7 @@ source "drivers/net/appletalk/Kconfig" source "net/x25/Kconfig" source "net/lapb/Kconfig" source "net/phonet/Kconfig" +source "net/6lowpan/Kconfig" source "net/ieee802154/Kconfig" source "net/mac802154/Kconfig" source "net/sched/Kconfig" diff --git a/net/Makefile b/net/Makefile index cbbbe6d657ca..7ed1970074b0 100644 --- a/net/Makefile +++ b/net/Makefile @@ -57,7 +57,8 @@ obj-$(CONFIG_CAIF) += caif/ ifneq ($(CONFIG_DCB),) obj-y += dcb/ endif -obj-y += ieee802154/ +obj-$(CONFIG_6LOWPAN) += 6lowpan/ +obj-$(CONFIG_IEEE802154) += ieee802154/ obj-$(CONFIG_MAC802154) += mac802154/ ifeq ($(CONFIG_NET),y) diff --git a/net/bluetooth/Kconfig b/net/bluetooth/Kconfig index f5afaa22f6ec..600fb29288f4 100644 --- a/net/bluetooth/Kconfig +++ b/net/bluetooth/Kconfig @@ -41,8 +41,7 @@ menuconfig BT config BT_6LOWPAN tristate "Bluetooth 6LoWPAN support" - depends on BT && IPV6 - select 6LOWPAN_IPHC if BT_6LOWPAN + depends on BT && 6LOWPAN help IPv6 compression over Bluetooth Low Energy. diff --git a/net/ieee802154/6lowpan_iphc.c b/net/ieee802154/6lowpan_iphc.c deleted file mode 100644 index 211b5686d719..000000000000 --- a/net/ieee802154/6lowpan_iphc.c +++ /dev/null @@ -1,801 +0,0 @@ -/* - * Copyright 2011, Siemens AG - * written by Alexander Smirnov - */ - -/* - * Based on patches from Jon Smirl - * Copyright (c) 2011 Jon Smirl - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -/* Jon's code is based on 6lowpan implementation for Contiki which is: - * Copyright (c) 2008, Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -#include -#include - -/* - * Uncompress address function for source and - * destination address(non-multicast). - * - * address_mode is sam value or dam value. - */ -static int uncompress_addr(struct sk_buff *skb, - struct in6_addr *ipaddr, const u8 address_mode, - const u8 *lladdr, const u8 addr_type, - const u8 addr_len) -{ - bool fail; - - switch (address_mode) { - case LOWPAN_IPHC_ADDR_00: - /* for global link addresses */ - fail = lowpan_fetch_skb(skb, ipaddr->s6_addr, 16); - break; - case LOWPAN_IPHC_ADDR_01: - /* fe:80::XXXX:XXXX:XXXX:XXXX */ - ipaddr->s6_addr[0] = 0xFE; - ipaddr->s6_addr[1] = 0x80; - fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[8], 8); - break; - case LOWPAN_IPHC_ADDR_02: - /* fe:80::ff:fe00:XXXX */ - ipaddr->s6_addr[0] = 0xFE; - ipaddr->s6_addr[1] = 0x80; - ipaddr->s6_addr[11] = 0xFF; - ipaddr->s6_addr[12] = 0xFE; - fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[14], 2); - break; - case LOWPAN_IPHC_ADDR_03: - fail = false; - switch (addr_type) { - case IEEE802154_ADDR_LONG: - /* fe:80::XXXX:XXXX:XXXX:XXXX - * \_________________/ - * hwaddr - */ - ipaddr->s6_addr[0] = 0xFE; - ipaddr->s6_addr[1] = 0x80; - memcpy(&ipaddr->s6_addr[8], lladdr, addr_len); - /* second bit-flip (Universe/Local) - * is done according RFC2464 - */ - ipaddr->s6_addr[8] ^= 0x02; - break; - case IEEE802154_ADDR_SHORT: - /* fe:80::ff:fe00:XXXX - * \__/ - * short_addr - * - * Universe/Local bit is zero. - */ - ipaddr->s6_addr[0] = 0xFE; - ipaddr->s6_addr[1] = 0x80; - ipaddr->s6_addr[11] = 0xFF; - ipaddr->s6_addr[12] = 0xFE; - ipaddr->s6_addr16[7] = htons(*((u16 *)lladdr)); - break; - default: - pr_debug("Invalid addr_type set\n"); - return -EINVAL; - } - break; - default: - pr_debug("Invalid address mode value: 0x%x\n", address_mode); - return -EINVAL; - } - - if (fail) { - pr_debug("Failed to fetch skb data\n"); - return -EIO; - } - - raw_dump_inline(NULL, "Reconstructed ipv6 addr is", - ipaddr->s6_addr, 16); - - return 0; -} - -/* - * Uncompress address function for source context - * based address(non-multicast). - */ -static int uncompress_context_based_src_addr(struct sk_buff *skb, - struct in6_addr *ipaddr, - const u8 sam) -{ - switch (sam) { - case LOWPAN_IPHC_ADDR_00: - /* unspec address :: - * Do nothing, address is already :: - */ - break; - case LOWPAN_IPHC_ADDR_01: - /* TODO */ - case LOWPAN_IPHC_ADDR_02: - /* TODO */ - case LOWPAN_IPHC_ADDR_03: - /* TODO */ - netdev_warn(skb->dev, "SAM value 0x%x not supported\n", sam); - return -EINVAL; - default: - pr_debug("Invalid sam value: 0x%x\n", sam); - return -EINVAL; - } - - raw_dump_inline(NULL, - "Reconstructed context based ipv6 src addr is", - ipaddr->s6_addr, 16); - - return 0; -} - -static int skb_deliver(struct sk_buff *skb, struct ipv6hdr *hdr, - struct net_device *dev, skb_delivery_cb deliver_skb) -{ - struct sk_buff *new; - int stat; - - new = skb_copy_expand(skb, sizeof(struct ipv6hdr), skb_tailroom(skb), - GFP_ATOMIC); - kfree_skb(skb); - - if (!new) - return -ENOMEM; - - skb_push(new, sizeof(struct ipv6hdr)); - skb_reset_network_header(new); - skb_copy_to_linear_data(new, hdr, sizeof(struct ipv6hdr)); - - new->protocol = htons(ETH_P_IPV6); - new->pkt_type = PACKET_HOST; - new->dev = dev; - - raw_dump_table(__func__, "raw skb data dump before receiving", - new->data, new->len); - - stat = deliver_skb(new, dev); - - kfree_skb(new); - - return stat; -} - -/* Uncompress function for multicast destination address, - * when M bit is set. - */ -static int -lowpan_uncompress_multicast_daddr(struct sk_buff *skb, - struct in6_addr *ipaddr, - const u8 dam) -{ - bool fail; - - switch (dam) { - case LOWPAN_IPHC_DAM_00: - /* 00: 128 bits. The full address - * is carried in-line. - */ - fail = lowpan_fetch_skb(skb, ipaddr->s6_addr, 16); - break; - case LOWPAN_IPHC_DAM_01: - /* 01: 48 bits. The address takes - * the form ffXX::00XX:XXXX:XXXX. - */ - ipaddr->s6_addr[0] = 0xFF; - fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[1], 1); - fail |= lowpan_fetch_skb(skb, &ipaddr->s6_addr[11], 5); - break; - case LOWPAN_IPHC_DAM_10: - /* 10: 32 bits. The address takes - * the form ffXX::00XX:XXXX. - */ - ipaddr->s6_addr[0] = 0xFF; - fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[1], 1); - fail |= lowpan_fetch_skb(skb, &ipaddr->s6_addr[13], 3); - break; - case LOWPAN_IPHC_DAM_11: - /* 11: 8 bits. The address takes - * the form ff02::00XX. - */ - ipaddr->s6_addr[0] = 0xFF; - ipaddr->s6_addr[1] = 0x02; - fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[15], 1); - break; - default: - pr_debug("DAM value has a wrong value: 0x%x\n", dam); - return -EINVAL; - } - - if (fail) { - pr_debug("Failed to fetch skb data\n"); - return -EIO; - } - - raw_dump_inline(NULL, "Reconstructed ipv6 multicast addr is", - ipaddr->s6_addr, 16); - - return 0; -} - -static int -uncompress_udp_header(struct sk_buff *skb, struct udphdr *uh) -{ - bool fail; - u8 tmp = 0, val = 0; - - if (!uh) - goto err; - - fail = lowpan_fetch_skb(skb, &tmp, 1); - - if ((tmp & LOWPAN_NHC_UDP_MASK) == LOWPAN_NHC_UDP_ID) { - pr_debug("UDP header uncompression\n"); - switch (tmp & LOWPAN_NHC_UDP_CS_P_11) { - case LOWPAN_NHC_UDP_CS_P_00: - fail |= lowpan_fetch_skb(skb, &uh->source, 2); - fail |= lowpan_fetch_skb(skb, &uh->dest, 2); - break; - case LOWPAN_NHC_UDP_CS_P_01: - fail |= lowpan_fetch_skb(skb, &uh->source, 2); - fail |= lowpan_fetch_skb(skb, &val, 1); - uh->dest = htons(val + LOWPAN_NHC_UDP_8BIT_PORT); - break; - case LOWPAN_NHC_UDP_CS_P_10: - fail |= lowpan_fetch_skb(skb, &val, 1); - uh->source = htons(val + LOWPAN_NHC_UDP_8BIT_PORT); - fail |= lowpan_fetch_skb(skb, &uh->dest, 2); - break; - case LOWPAN_NHC_UDP_CS_P_11: - fail |= lowpan_fetch_skb(skb, &val, 1); - uh->source = htons(LOWPAN_NHC_UDP_4BIT_PORT + - (val >> 4)); - uh->dest = htons(LOWPAN_NHC_UDP_4BIT_PORT + - (val & 0x0f)); - break; - default: - pr_debug("ERROR: unknown UDP format\n"); - goto err; - break; - } - - pr_debug("uncompressed UDP ports: src = %d, dst = %d\n", - ntohs(uh->source), ntohs(uh->dest)); - - /* checksum */ - if (tmp & LOWPAN_NHC_UDP_CS_C) { - pr_debug_ratelimited("checksum elided currently not supported\n"); - goto err; - } else { - fail |= lowpan_fetch_skb(skb, &uh->check, 2); - } - - /* - * UDP lenght needs to be infered from the lower layers - * here, we obtain the hint from the remaining size of the - * frame - */ - uh->len = htons(skb->len + sizeof(struct udphdr)); - pr_debug("uncompressed UDP length: src = %d", ntohs(uh->len)); - } else { - pr_debug("ERROR: unsupported NH format\n"); - goto err; - } - - if (fail) - goto err; - - return 0; -err: - return -EINVAL; -} - -/* TTL uncompression values */ -static const u8 lowpan_ttl_values[] = { 0, 1, 64, 255 }; - -int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, - const u8 *saddr, const u8 saddr_type, const u8 saddr_len, - const u8 *daddr, const u8 daddr_type, const u8 daddr_len, - u8 iphc0, u8 iphc1, skb_delivery_cb deliver_skb) -{ - struct ipv6hdr hdr = {}; - u8 tmp, num_context = 0; - int err; - - raw_dump_table(__func__, "raw skb data dump uncompressed", - skb->data, skb->len); - - /* another if the CID flag is set */ - if (iphc1 & LOWPAN_IPHC_CID) { - pr_debug("CID flag is set, increase header with one\n"); - if (lowpan_fetch_skb_u8(skb, &num_context)) - goto drop; - } - - hdr.version = 6; - - /* Traffic Class and Flow Label */ - switch ((iphc0 & LOWPAN_IPHC_TF) >> 3) { - /* - * Traffic Class and FLow Label carried in-line - * ECN + DSCP + 4-bit Pad + Flow Label (4 bytes) - */ - case 0: /* 00b */ - if (lowpan_fetch_skb_u8(skb, &tmp)) - goto drop; - - memcpy(&hdr.flow_lbl, &skb->data[0], 3); - skb_pull(skb, 3); - hdr.priority = ((tmp >> 2) & 0x0f); - hdr.flow_lbl[0] = ((tmp >> 2) & 0x30) | (tmp << 6) | - (hdr.flow_lbl[0] & 0x0f); - break; - /* - * Traffic class carried in-line - * ECN + DSCP (1 byte), Flow Label is elided - */ - case 2: /* 10b */ - if (lowpan_fetch_skb_u8(skb, &tmp)) - goto drop; - - hdr.priority = ((tmp >> 2) & 0x0f); - hdr.flow_lbl[0] = ((tmp << 6) & 0xC0) | ((tmp >> 2) & 0x30); - break; - /* - * Flow Label carried in-line - * ECN + 2-bit Pad + Flow Label (3 bytes), DSCP is elided - */ - case 1: /* 01b */ - if (lowpan_fetch_skb_u8(skb, &tmp)) - goto drop; - - hdr.flow_lbl[0] = (skb->data[0] & 0x0F) | ((tmp >> 2) & 0x30); - memcpy(&hdr.flow_lbl[1], &skb->data[0], 2); - skb_pull(skb, 2); - break; - /* Traffic Class and Flow Label are elided */ - case 3: /* 11b */ - break; - default: - break; - } - - /* Next Header */ - if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) { - /* Next header is carried inline */ - if (lowpan_fetch_skb_u8(skb, &(hdr.nexthdr))) - goto drop; - - pr_debug("NH flag is set, next header carried inline: %02x\n", - hdr.nexthdr); - } - - /* Hop Limit */ - if ((iphc0 & 0x03) != LOWPAN_IPHC_TTL_I) - hdr.hop_limit = lowpan_ttl_values[iphc0 & 0x03]; - else { - if (lowpan_fetch_skb_u8(skb, &(hdr.hop_limit))) - goto drop; - } - - /* Extract SAM to the tmp variable */ - tmp = ((iphc1 & LOWPAN_IPHC_SAM) >> LOWPAN_IPHC_SAM_BIT) & 0x03; - - if (iphc1 & LOWPAN_IPHC_SAC) { - /* Source address context based uncompression */ - pr_debug("SAC bit is set. Handle context based source address.\n"); - err = uncompress_context_based_src_addr( - skb, &hdr.saddr, tmp); - } else { - /* Source address uncompression */ - pr_debug("source address stateless compression\n"); - err = uncompress_addr(skb, &hdr.saddr, tmp, saddr, - saddr_type, saddr_len); - } - - /* Check on error of previous branch */ - if (err) - goto drop; - - /* Extract DAM to the tmp variable */ - tmp = ((iphc1 & LOWPAN_IPHC_DAM_11) >> LOWPAN_IPHC_DAM_BIT) & 0x03; - - /* check for Multicast Compression */ - if (iphc1 & LOWPAN_IPHC_M) { - if (iphc1 & LOWPAN_IPHC_DAC) { - pr_debug("dest: context-based mcast compression\n"); - /* TODO: implement this */ - } else { - err = lowpan_uncompress_multicast_daddr( - skb, &hdr.daddr, tmp); - if (err) - goto drop; - } - } else { - err = uncompress_addr(skb, &hdr.daddr, tmp, daddr, - daddr_type, daddr_len); - pr_debug("dest: stateless compression mode %d dest %pI6c\n", - tmp, &hdr.daddr); - if (err) - goto drop; - } - - /* UDP data uncompression */ - if (iphc0 & LOWPAN_IPHC_NH_C) { - struct udphdr uh; - struct sk_buff *new; - if (uncompress_udp_header(skb, &uh)) - goto drop; - - /* - * replace the compressed UDP head by the uncompressed UDP - * header - */ - new = skb_copy_expand(skb, sizeof(struct udphdr), - skb_tailroom(skb), GFP_ATOMIC); - kfree_skb(skb); - - if (!new) - return -ENOMEM; - - skb = new; - - skb_push(skb, sizeof(struct udphdr)); - skb_reset_transport_header(skb); - skb_copy_to_linear_data(skb, &uh, sizeof(struct udphdr)); - - raw_dump_table(__func__, "raw UDP header dump", - (u8 *)&uh, sizeof(uh)); - - hdr.nexthdr = UIP_PROTO_UDP; - } - - hdr.payload_len = htons(skb->len); - - pr_debug("skb headroom size = %d, data length = %d\n", - skb_headroom(skb), skb->len); - - pr_debug("IPv6 header dump:\n\tversion = %d\n\tlength = %d\n\t" - "nexthdr = 0x%02x\n\thop_lim = %d\n\tdest = %pI6c\n", - hdr.version, ntohs(hdr.payload_len), hdr.nexthdr, - hdr.hop_limit, &hdr.daddr); - - raw_dump_table(__func__, "raw header dump", (u8 *)&hdr, - sizeof(hdr)); - - return skb_deliver(skb, &hdr, dev, deliver_skb); - -drop: - kfree_skb(skb); - return -EINVAL; -} -EXPORT_SYMBOL_GPL(lowpan_process_data); - -static u8 lowpan_compress_addr_64(u8 **hc06_ptr, u8 shift, - const struct in6_addr *ipaddr, - const unsigned char *lladdr) -{ - u8 val = 0; - - if (is_addr_mac_addr_based(ipaddr, lladdr)) { - val = 3; /* 0-bits */ - pr_debug("address compression 0 bits\n"); - } else if (lowpan_is_iid_16_bit_compressable(ipaddr)) { - /* compress IID to 16 bits xxxx::XXXX */ - memcpy(*hc06_ptr, &ipaddr->s6_addr16[7], 2); - *hc06_ptr += 2; - val = 2; /* 16-bits */ - raw_dump_inline(NULL, "Compressed ipv6 addr is (16 bits)", - *hc06_ptr - 2, 2); - } else { - /* do not compress IID => xxxx::IID */ - memcpy(*hc06_ptr, &ipaddr->s6_addr16[4], 8); - *hc06_ptr += 8; - val = 1; /* 64-bits */ - raw_dump_inline(NULL, "Compressed ipv6 addr is (64 bits)", - *hc06_ptr - 8, 8); - } - - return rol8(val, shift); -} - -static void compress_udp_header(u8 **hc06_ptr, struct sk_buff *skb) -{ - struct udphdr *uh = udp_hdr(skb); - u8 tmp; - - if (((ntohs(uh->source) & LOWPAN_NHC_UDP_4BIT_MASK) == - LOWPAN_NHC_UDP_4BIT_PORT) && - ((ntohs(uh->dest) & LOWPAN_NHC_UDP_4BIT_MASK) == - LOWPAN_NHC_UDP_4BIT_PORT)) { - pr_debug("UDP header: both ports compression to 4 bits\n"); - /* compression value */ - tmp = LOWPAN_NHC_UDP_CS_P_11; - lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); - /* source and destination port */ - tmp = ntohs(uh->dest) - LOWPAN_NHC_UDP_4BIT_PORT + - ((ntohs(uh->source) - LOWPAN_NHC_UDP_4BIT_PORT) << 4); - lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); - } else if ((ntohs(uh->dest) & LOWPAN_NHC_UDP_8BIT_MASK) == - LOWPAN_NHC_UDP_8BIT_PORT) { - pr_debug("UDP header: remove 8 bits of dest\n"); - /* compression value */ - tmp = LOWPAN_NHC_UDP_CS_P_01; - lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); - /* source port */ - lowpan_push_hc_data(hc06_ptr, &uh->source, sizeof(uh->source)); - /* destination port */ - tmp = ntohs(uh->dest) - LOWPAN_NHC_UDP_8BIT_PORT; - lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); - } else if ((ntohs(uh->source) & LOWPAN_NHC_UDP_8BIT_MASK) == - LOWPAN_NHC_UDP_8BIT_PORT) { - pr_debug("UDP header: remove 8 bits of source\n"); - /* compression value */ - tmp = LOWPAN_NHC_UDP_CS_P_10; - lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); - /* source port */ - tmp = ntohs(uh->source) - LOWPAN_NHC_UDP_8BIT_PORT; - lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); - /* destination port */ - lowpan_push_hc_data(hc06_ptr, &uh->dest, sizeof(uh->dest)); - } else { - pr_debug("UDP header: can't compress\n"); - /* compression value */ - tmp = LOWPAN_NHC_UDP_CS_P_00; - lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp)); - /* source port */ - lowpan_push_hc_data(hc06_ptr, &uh->source, sizeof(uh->source)); - /* destination port */ - lowpan_push_hc_data(hc06_ptr, &uh->dest, sizeof(uh->dest)); - } - - /* checksum is always inline */ - lowpan_push_hc_data(hc06_ptr, &uh->check, sizeof(uh->check)); - - /* skip the UDP header */ - skb_pull(skb, sizeof(struct udphdr)); -} - -int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, - unsigned short type, const void *_daddr, - const void *_saddr, unsigned int len) -{ - u8 tmp, iphc0, iphc1, *hc06_ptr; - struct ipv6hdr *hdr; - u8 head[100] = {}; - - if (type != ETH_P_IPV6) - return -EINVAL; - - hdr = ipv6_hdr(skb); - hc06_ptr = head + 2; - - pr_debug("IPv6 header dump:\n\tversion = %d\n\tlength = %d\n" - "\tnexthdr = 0x%02x\n\thop_lim = %d\n\tdest = %pI6c\n", - hdr->version, ntohs(hdr->payload_len), hdr->nexthdr, - hdr->hop_limit, &hdr->daddr); - - raw_dump_table(__func__, "raw skb network header dump", - skb_network_header(skb), sizeof(struct ipv6hdr)); - - /* - * As we copy some bit-length fields, in the IPHC encoding bytes, - * we sometimes use |= - * If the field is 0, and the current bit value in memory is 1, - * this does not work. We therefore reset the IPHC encoding here - */ - iphc0 = LOWPAN_DISPATCH_IPHC; - iphc1 = 0; - - /* TODO: context lookup */ - - raw_dump_inline(__func__, "saddr", - (unsigned char *)_saddr, IEEE802154_ADDR_LEN); - raw_dump_inline(__func__, "daddr", - (unsigned char *)_daddr, IEEE802154_ADDR_LEN); - - raw_dump_table(__func__, - "sending raw skb network uncompressed packet", - skb->data, skb->len); - - /* - * Traffic class, flow label - * If flow label is 0, compress it. If traffic class is 0, compress it - * We have to process both in the same time as the offset of traffic - * class depends on the presence of version and flow label - */ - - /* hc06 format of TC is ECN | DSCP , original one is DSCP | ECN */ - tmp = (hdr->priority << 4) | (hdr->flow_lbl[0] >> 4); - tmp = ((tmp & 0x03) << 6) | (tmp >> 2); - - if (((hdr->flow_lbl[0] & 0x0F) == 0) && - (hdr->flow_lbl[1] == 0) && (hdr->flow_lbl[2] == 0)) { - /* flow label can be compressed */ - iphc0 |= LOWPAN_IPHC_FL_C; - if ((hdr->priority == 0) && - ((hdr->flow_lbl[0] & 0xF0) == 0)) { - /* compress (elide) all */ - iphc0 |= LOWPAN_IPHC_TC_C; - } else { - /* compress only the flow label */ - *hc06_ptr = tmp; - hc06_ptr += 1; - } - } else { - /* Flow label cannot be compressed */ - if ((hdr->priority == 0) && - ((hdr->flow_lbl[0] & 0xF0) == 0)) { - /* compress only traffic class */ - iphc0 |= LOWPAN_IPHC_TC_C; - *hc06_ptr = (tmp & 0xc0) | (hdr->flow_lbl[0] & 0x0F); - memcpy(hc06_ptr + 1, &hdr->flow_lbl[1], 2); - hc06_ptr += 3; - } else { - /* compress nothing */ - memcpy(hc06_ptr, hdr, 4); - /* replace the top byte with new ECN | DSCP format */ - *hc06_ptr = tmp; - hc06_ptr += 4; - } - } - - /* NOTE: payload length is always compressed */ - - /* Next Header is compress if UDP */ - if (hdr->nexthdr == UIP_PROTO_UDP) - iphc0 |= LOWPAN_IPHC_NH_C; - - if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) { - *hc06_ptr = hdr->nexthdr; - hc06_ptr += 1; - } - - /* - * Hop limit - * if 1: compress, encoding is 01 - * if 64: compress, encoding is 10 - * if 255: compress, encoding is 11 - * else do not compress - */ - switch (hdr->hop_limit) { - case 1: - iphc0 |= LOWPAN_IPHC_TTL_1; - break; - case 64: - iphc0 |= LOWPAN_IPHC_TTL_64; - break; - case 255: - iphc0 |= LOWPAN_IPHC_TTL_255; - break; - default: - *hc06_ptr = hdr->hop_limit; - hc06_ptr += 1; - break; - } - - /* source address compression */ - if (is_addr_unspecified(&hdr->saddr)) { - pr_debug("source address is unspecified, setting SAC\n"); - iphc1 |= LOWPAN_IPHC_SAC; - /* TODO: context lookup */ - } else if (is_addr_link_local(&hdr->saddr)) { - iphc1 |= lowpan_compress_addr_64(&hc06_ptr, - LOWPAN_IPHC_SAM_BIT, &hdr->saddr, _saddr); - pr_debug("source address unicast link-local %pI6c " - "iphc1 0x%02x\n", &hdr->saddr, iphc1); - } else { - pr_debug("send the full source address\n"); - memcpy(hc06_ptr, &hdr->saddr.s6_addr16[0], 16); - hc06_ptr += 16; - } - - /* destination address compression */ - if (is_addr_mcast(&hdr->daddr)) { - pr_debug("destination address is multicast: "); - iphc1 |= LOWPAN_IPHC_M; - if (lowpan_is_mcast_addr_compressable8(&hdr->daddr)) { - pr_debug("compressed to 1 octet\n"); - iphc1 |= LOWPAN_IPHC_DAM_11; - /* use last byte */ - *hc06_ptr = hdr->daddr.s6_addr[15]; - hc06_ptr += 1; - } else if (lowpan_is_mcast_addr_compressable32(&hdr->daddr)) { - pr_debug("compressed to 4 octets\n"); - iphc1 |= LOWPAN_IPHC_DAM_10; - /* second byte + the last three */ - *hc06_ptr = hdr->daddr.s6_addr[1]; - memcpy(hc06_ptr + 1, &hdr->daddr.s6_addr[13], 3); - hc06_ptr += 4; - } else if (lowpan_is_mcast_addr_compressable48(&hdr->daddr)) { - pr_debug("compressed to 6 octets\n"); - iphc1 |= LOWPAN_IPHC_DAM_01; - /* second byte + the last five */ - *hc06_ptr = hdr->daddr.s6_addr[1]; - memcpy(hc06_ptr + 1, &hdr->daddr.s6_addr[11], 5); - hc06_ptr += 6; - } else { - pr_debug("using full address\n"); - iphc1 |= LOWPAN_IPHC_DAM_00; - memcpy(hc06_ptr, &hdr->daddr.s6_addr[0], 16); - hc06_ptr += 16; - } - } else { - /* TODO: context lookup */ - if (is_addr_link_local(&hdr->daddr)) { - iphc1 |= lowpan_compress_addr_64(&hc06_ptr, - LOWPAN_IPHC_DAM_BIT, &hdr->daddr, _daddr); - pr_debug("dest address unicast link-local %pI6c " - "iphc1 0x%02x\n", &hdr->daddr, iphc1); - } else { - pr_debug("dest address unicast %pI6c\n", &hdr->daddr); - memcpy(hc06_ptr, &hdr->daddr.s6_addr16[0], 16); - hc06_ptr += 16; - } - } - - /* UDP header compression */ - if (hdr->nexthdr == UIP_PROTO_UDP) - compress_udp_header(&hc06_ptr, skb); - - head[0] = iphc0; - head[1] = iphc1; - - skb_pull(skb, sizeof(struct ipv6hdr)); - skb_reset_transport_header(skb); - memcpy(skb_push(skb, hc06_ptr - head), head, hc06_ptr - head); - skb_reset_network_header(skb); - - pr_debug("header len %d skb %u\n", (int)(hc06_ptr - head), skb->len); - - raw_dump_table(__func__, "raw skb data dump compressed", - skb->data, skb->len); - return 0; -} -EXPORT_SYMBOL_GPL(lowpan_header_compress); - -MODULE_LICENSE("GPL"); diff --git a/net/ieee802154/Kconfig b/net/ieee802154/Kconfig index 8af1330b3137..c0d4154d144f 100644 --- a/net/ieee802154/Kconfig +++ b/net/ieee802154/Kconfig @@ -12,13 +12,6 @@ config IEEE802154 config IEEE802154_6LOWPAN tristate "6lowpan support over IEEE 802.15.4" - depends on IEEE802154 && IPV6 - select 6LOWPAN_IPHC + depends on IEEE802154 && 6LOWPAN ---help--- IPv6 compression over IEEE 802.15.4. - -config 6LOWPAN_IPHC - tristate - ---help--- - 6lowpan compression code which is shared between IEEE 802.15.4 and Bluetooth - stacks. diff --git a/net/ieee802154/Makefile b/net/ieee802154/Makefile index bf1b51497a41..3914b1ed4274 100644 --- a/net/ieee802154/Makefile +++ b/net/ieee802154/Makefile @@ -1,8 +1,7 @@ obj-$(CONFIG_IEEE802154) += ieee802154.o af_802154.o -obj-$(CONFIG_IEEE802154_6LOWPAN) += 6lowpan.o -obj-$(CONFIG_6LOWPAN_IPHC) += 6lowpan_iphc.o +obj-$(CONFIG_IEEE802154_6LOWPAN) += ieee802154_6lowpan.o -6lowpan-y := 6lowpan_rtnl.o reassembly.o +ieee802154_6lowpan-y := 6lowpan_rtnl.o reassembly.o ieee802154-y := netlink.o nl-mac.o nl-phy.o nl_policy.o wpan-class.o \ header_ops.o af_802154-y := af_ieee802154.o raw.o dgram.o -- cgit v1.2.3 From 15a49cca98c3380271ced8db2ea69ee95db5c709 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 12 Jul 2014 23:20:50 +0200 Subject: Bluetooth: Read LE Advertising Channel TX Power only when available The Read LE Advertising Channel TX Power command is not mandatory for a Bluetooth HCI controller only supporting receiption. Move the command to the third stage of the controller initialization and only execute it when support for it has been indicated. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 347f84fb66f9..b29a984f7dd4 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1348,9 +1348,6 @@ static void le_setup(struct hci_request *req) /* Read LE Supported States */ hci_req_add(req, HCI_OP_LE_READ_SUPPORTED_STATES, 0, NULL); - /* Read LE Advertising Channel TX Power */ - hci_req_add(req, HCI_OP_LE_READ_ADV_TX_POWER, 0, NULL); - /* Read LE White List Size */ hci_req_add(req, HCI_OP_LE_READ_WHITE_LIST_SIZE, 0, NULL); @@ -1657,6 +1654,11 @@ static void hci_init3_req(struct hci_request *req, unsigned long opt) hci_req_add(req, HCI_OP_LE_SET_EVENT_MASK, sizeof(events), events); + if (hdev->commands[25] & 0x40) { + /* Read LE Advertising Channel TX Power */ + hci_req_add(req, HCI_OP_LE_READ_ADV_TX_POWER, 0, NULL); + } + hci_set_le_support(req); } -- cgit v1.2.3 From 0da71f1bf90f259debf50aaaa547e2cc31b5cf67 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 12 Jul 2014 23:36:16 +0200 Subject: Bluetooth: Enable LE encryption events only when supported The support for LE encryption is optional. When encryption is not supported then also do not enable the encryption related events. This moves the event mask setting to the third initialization stage to ensure that the LE features are available. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 1 + net/bluetooth/hci_core.c | 11 +++++++---- 2 files changed, 8 insertions(+), 4 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 7f754a246ca5..2fee852816ee 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -329,6 +329,7 @@ enum { #define LMP_HOST_SC 0x08 /* LE features */ +#define HCI_LE_ENCRYPTION 0x01 #define HCI_LE_CONN_PARAM_REQ_PROC 0x02 #define HCI_LE_PING 0x10 diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index b29a984f7dd4..ff150e3c7ad1 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1422,14 +1422,17 @@ static void hci_setup_event_mask(struct hci_request *req) /* Use a different default for LE-only devices */ memset(events, 0, sizeof(events)); events[0] |= 0x10; /* Disconnection Complete */ - events[0] |= 0x80; /* Encryption Change */ events[1] |= 0x08; /* Read Remote Version Information Complete */ events[1] |= 0x20; /* Command Complete */ events[1] |= 0x40; /* Command Status */ events[1] |= 0x80; /* Hardware Error */ events[2] |= 0x04; /* Number of Completed Packets */ events[3] |= 0x02; /* Data Buffer Overflow */ - events[5] |= 0x80; /* Encryption Key Refresh Complete */ + + if (hdev->le_features[0] & HCI_LE_ENCRYPTION) { + events[0] |= 0x80; /* Encryption Change */ + events[5] |= 0x80; /* Encryption Key Refresh Complete */ + } } if (lmp_inq_rssi_capable(hdev)) @@ -1482,8 +1485,6 @@ static void hci_init2_req(struct hci_request *req, unsigned long opt) if (lmp_le_capable(hdev)) le_setup(req); - hci_setup_event_mask(req); - /* AVM Berlin (31), aka "BlueFRITZ!", doesn't support the read * local supported commands HCI command. */ @@ -1611,6 +1612,8 @@ static void hci_init3_req(struct hci_request *req, unsigned long opt) struct hci_dev *hdev = req->hdev; u8 p; + hci_setup_event_mask(req); + /* Some Broadcom based Bluetooth controllers do not support the * Delete Stored Link Key command. They are clearly indicating its * absence in the bit mask of supported commands. -- cgit v1.2.3 From 4d6c705bbd9e845bcfbe119bb017a5653c0d9efb Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 13 Jul 2014 00:29:22 +0200 Subject: Bluetooth: Enable LE Long Term Key Request event only when supported The support for LE encryption is optional and with that also the LE Long Term Key Request event. If encryption is not supported, then do not bother enabling this event. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index ff150e3c7ad1..188bfd3d7c43 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1644,7 +1644,10 @@ static void hci_init3_req(struct hci_request *req, unsigned long opt) u8 events[8]; memset(events, 0, sizeof(events)); - events[0] = 0x1f; + events[0] = 0x0f; + + if (hdev->le_features[0] & HCI_LE_ENCRYPTION) + events[0] |= 0x10; /* LE Long Term Key Request */ /* If controller supports the Connection Parameters Request * Link Layer Procedure, enable the corresponding event. -- cgit v1.2.3 From 395365eaf125e53b9d7e1c11c91ee01bf5a4b792 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 13 Jul 2014 17:22:25 +0200 Subject: Bluetooth: Allocate struct inquiry_entry with GFP_KERNEL The allocation of inquiry cache entries is triggered as a result of processing HCI events. Since the processing is done in the context of a workqueue, there is no needed to allocate with GFP_ATOMIC in that case. Switch it to GFP_KERNEL. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 188bfd3d7c43..172041e2b15a 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2088,7 +2088,7 @@ u32 hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, } /* Entry not in the cache. Add new one. */ - ie = kzalloc(sizeof(struct inquiry_entry), GFP_ATOMIC); + ie = kzalloc(sizeof(struct inquiry_entry), GFP_KERNEL); if (!ie) { flags |= MGMT_DEV_FOUND_CONFIRM_NAME; goto done; -- cgit v1.2.3 From 015b01cbca20276a6b09ad25ce4002e811a53130 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 13 Jul 2014 19:54:48 +0200 Subject: Bluetooth: Remove unneeded forward declaration of __sco_chan_add The forward declaration of __sco_chan_add is not needed and thus just remove it. Move __sco_chan_add into the proper location. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/sco.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index e6c7b636b901..75cffc14ab6e 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -53,7 +53,6 @@ struct sco_conn { #define sco_conn_lock(c) spin_lock(&c->lock); #define sco_conn_unlock(c) spin_unlock(&c->lock); -static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent); static void sco_chan_del(struct sock *sk, int err); static void sco_sock_close(struct sock *sk); @@ -164,6 +163,17 @@ static int sco_conn_del(struct hci_conn *hcon, int err) return 0; } +static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent) +{ + BT_DBG("conn %p", conn); + + sco_pi(sk)->conn = conn; + conn->sk = sk; + + if (parent) + bt_accept_enqueue(parent, sk); +} + static int sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent) { @@ -968,17 +978,6 @@ static int sco_sock_release(struct socket *sock) return err; } -static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent) -{ - BT_DBG("conn %p", conn); - - sco_pi(sk)->conn = conn; - conn->sk = sk; - - if (parent) - bt_accept_enqueue(parent, sk); -} - /* Delete channel. * Must be called on the locked socket. */ static void sco_chan_del(struct sock *sk, int err) -- cgit v1.2.3 From e03ab5199df597d3f1737ef638a7f692daaaef9f Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 13 Jul 2014 19:54:49 +0200 Subject: Bluetooth: Remove unneeded forward declaration of sco_chan_del The forward declaration of sco_chan_del is not needed and thus just remove it. Move sco_chan_del into the proper location. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/sco.c | 56 ++++++++++++++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 29 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 75cffc14ab6e..4d67b0354d23 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -53,8 +53,6 @@ struct sco_conn { #define sco_conn_lock(c) spin_lock(&c->lock); #define sco_conn_unlock(c) spin_unlock(&c->lock); -static void sco_chan_del(struct sock *sk, int err); - static void sco_sock_close(struct sock *sk); static void sco_sock_kill(struct sock *sk); @@ -138,6 +136,33 @@ static struct sock *sco_chan_get(struct sco_conn *conn) return sk; } +/* Delete channel. + * Must be called on the locked socket. */ +static void sco_chan_del(struct sock *sk, int err) +{ + struct sco_conn *conn; + + conn = sco_pi(sk)->conn; + + BT_DBG("sk %p, conn %p, err %d", sk, conn, err); + + if (conn) { + sco_conn_lock(conn); + conn->sk = NULL; + sco_pi(sk)->conn = NULL; + sco_conn_unlock(conn); + + if (conn->hcon) + hci_conn_drop(conn->hcon); + } + + sk->sk_state = BT_CLOSED; + sk->sk_err = err; + sk->sk_state_change(sk); + + sock_set_flag(sk, SOCK_ZAPPED); +} + static int sco_conn_del(struct hci_conn *hcon, int err) { struct sco_conn *conn = hcon->sco_data; @@ -978,33 +1003,6 @@ static int sco_sock_release(struct socket *sock) return err; } -/* Delete channel. - * Must be called on the locked socket. */ -static void sco_chan_del(struct sock *sk, int err) -{ - struct sco_conn *conn; - - conn = sco_pi(sk)->conn; - - BT_DBG("sk %p, conn %p, err %d", sk, conn, err); - - if (conn) { - sco_conn_lock(conn); - conn->sk = NULL; - sco_pi(sk)->conn = NULL; - sco_conn_unlock(conn); - - if (conn->hcon) - hci_conn_drop(conn->hcon); - } - - sk->sk_state = BT_CLOSED; - sk->sk_err = err; - sk->sk_state_change(sk); - - sock_set_flag(sk, SOCK_ZAPPED); -} - static void sco_conn_ready(struct sco_conn *conn) { struct sock *parent; -- cgit v1.2.3 From 5a54e7c85b8303b84a9b2fbf978a74d625f85a99 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 13 Jul 2014 20:50:15 +0200 Subject: Bluetooth: Convert L2CAP ident spinlock into a mutex The spinlock protecting the L2CAP ident number can be converted into a mutex since the whole processing is run in a workqueue. So instead of using a spinlock, just use a mutex here. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/l2cap.h | 3 +-- net/bluetooth/l2cap_core.c | 6 +++--- 2 files changed, 4 insertions(+), 5 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index d8e7b9330ab8..1fffd92808b0 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -625,11 +625,10 @@ struct l2cap_conn { struct delayed_work info_timer; - spinlock_t lock; - struct sk_buff *rx_skb; __u32 rx_len; __u8 tx_ident; + struct mutex ident_lock; struct sk_buff_head pending_rx; struct work_struct pending_rx_work; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 0c3c4935f635..8538cb07b0c0 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -798,14 +798,14 @@ static u8 l2cap_get_ident(struct l2cap_conn *conn) * 200 - 254 are used by utilities like l2ping, etc. */ - spin_lock(&conn->lock); + mutex_lock(&conn->ident_lock); if (++conn->tx_ident > 128) conn->tx_ident = 1; id = conn->tx_ident; - spin_unlock(&conn->lock); + mutex_unlock(&conn->ident_lock); return id; } @@ -7016,7 +7016,7 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon) conn->hs_enabled = test_bit(HCI_HS_ENABLED, &hcon->hdev->dev_flags); - spin_lock_init(&conn->lock); + mutex_init(&conn->ident_lock); mutex_init(&conn->chan_lock); INIT_LIST_HEAD(&conn->chan_l); -- cgit v1.2.3 From eb5a4de80f266d0bb7edd43c61894da74faaa91a Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 14 Jul 2014 01:30:15 +0200 Subject: Bluetooth: Remove sco_chan_get helper function The sco_chan_get helper function is only used in two places and really only protects conn->sk with a lock. So instead of hiding that fact, just put the actual code in place where it is used. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/sco.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 4d67b0354d23..ebf7ee6a446c 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -127,15 +127,6 @@ static struct sco_conn *sco_conn_add(struct hci_conn *hcon) return conn; } -static struct sock *sco_chan_get(struct sco_conn *conn) -{ - struct sock *sk = NULL; - sco_conn_lock(conn); - sk = conn->sk; - sco_conn_unlock(conn); - return sk; -} - /* Delete channel. * Must be called on the locked socket. */ static void sco_chan_del(struct sock *sk, int err) @@ -174,7 +165,10 @@ static int sco_conn_del(struct hci_conn *hcon, int err) BT_DBG("hcon %p conn %p, err %d", hcon, conn, err); /* Kill socket */ - sk = sco_chan_get(conn); + sco_conn_lock(conn); + sk = conn->sk; + sco_conn_unlock(conn); + if (sk) { bh_lock_sock(sk); sco_sock_clear_timer(sk); @@ -303,7 +297,11 @@ static int sco_send_frame(struct sock *sk, struct msghdr *msg, int len) static void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb) { - struct sock *sk = sco_chan_get(conn); + struct sock *sk; + + sco_conn_lock(conn); + sk = conn->sk; + sco_conn_unlock(conn); if (!sk) goto drop; -- cgit v1.2.3 From b2d5e254ebfe9e4a926265c23bc5943f212fd1ac Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 14 Jul 2014 14:34:55 +0300 Subject: Bluetooth: Fix trying LTK re-encryption when we don't have an LTK In the case that the key distribution bits cause us not to generate a local LTK we should not try to re-encrypt if we're currently encrypted with an STK. This patch fixes the check for this in the smp_sufficient_security function. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index bf3568c46847..8339d6b0f2b8 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -876,9 +876,12 @@ bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level) /* If we're encrypted with an STK always claim insufficient * security. This way we allow the connection to be re-encrypted * with an LTK, even if the LTK provides the same level of - * security. + * security. Only exception is if we don't have an LTK (e.g. + * because of key distribution bits). */ - if (test_bit(HCI_CONN_STK_ENCRYPT, &hcon->flags)) + if (test_bit(HCI_CONN_STK_ENCRYPT, &hcon->flags) && + hci_find_ltk_by_addr(hcon->hdev, &hcon->dst, hcon->dst_type, + hcon->out)) return false; if (hcon->sec_level >= sec_level) -- cgit v1.2.3 From 4d042654afb342386cb5c33e29843b76d598ab61 Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Tue, 15 Jul 2014 02:04:13 +0530 Subject: Bluetooth: cmtp: Remove unnecessary null test This patch removes the null test on ctrl. ctrl is initialized at the beginning of the function to &session->ctrl. Since session is dereferenced prior to the null test, session must be a valid pointer, and &session->ctrl cannot be null. The following Coccinelle script is used for detecting the change: @r@ expression e,f; identifier g,y; statement S1,S2; @@ *e = &f->g <+... f->y ...+> *if (e != NULL || ...) S1 else S2 Signed-off-by: Himangi Saraogi Acked-by: Julia Lawall Signed-off-by: Marcel Holtmann --- net/bluetooth/cmtp/capi.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/cmtp/capi.c b/net/bluetooth/cmtp/capi.c index cd75e4d64b90..1ca8a87a0787 100644 --- a/net/bluetooth/cmtp/capi.c +++ b/net/bluetooth/cmtp/capi.c @@ -362,12 +362,6 @@ void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb) CAPIMSG_SETCONTROL(skb->data, contr); } - if (!ctrl) { - BT_ERR("Can't find controller %d for message", session->num); - kfree_skb(skb); - return; - } - capi_ctr_handle_message(ctrl, appl, skb); } -- cgit v1.2.3 From 3a19b6feb26295fe03c9242a72084d2f32dcaac4 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 15 Jul 2014 08:07:59 +0300 Subject: Bluetooth: Remove unnecessary params variable from process_adv_report() The params variable was just used for storing the return value from the hci_pend_le_action_lookup() function and then checking whether it's NULL or not. We can simplify the code by checking the return value directly. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 8980bd24b8c0..bf2926b2e4a9 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4314,14 +4314,11 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr, * device found events. */ if (hdev->le_scan_type == LE_SCAN_PASSIVE) { - struct hci_conn_params *param; - if (type == LE_ADV_DIRECT_IND) return; - param = hci_pend_le_action_lookup(&hdev->pend_le_reports, - bdaddr, bdaddr_type); - if (!param) + if (!hci_pend_le_action_lookup(&hdev->pend_le_reports, + bdaddr, bdaddr_type)) return; if (type == LE_ADV_NONCONN_IND || type == LE_ADV_SCAN_IND) -- cgit v1.2.3 From 2d3c2260e7ef0b21f7f0db0fbfee0b092e1202f8 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 15 Jul 2014 11:51:28 +0300 Subject: Bluetooth: Don't try to reject failed LE connections The check for the blacklist in hci_le_conn_complete_evt() should be when we know that we have an actual successful connection (ev->status being non-zero). This patch fixes this ordering. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index bf2926b2e4a9..68d335e193bf 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4187,14 +4187,14 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) else addr_type = BDADDR_LE_RANDOM; - /* Drop the connection if he device is blocked */ - if (hci_bdaddr_list_lookup(&hdev->blacklist, &conn->dst, addr_type)) { - hci_conn_drop(conn); + if (ev->status) { + hci_le_conn_failed(conn, ev->status); goto unlock; } - if (ev->status) { - hci_le_conn_failed(conn, ev->status); + /* Drop the connection if the device is blocked */ + if (hci_bdaddr_list_lookup(&hdev->blacklist, &conn->dst, addr_type)) { + hci_conn_drop(conn); goto unlock; } -- cgit v1.2.3 From ba165a90b59812ab1d9cd2943fd104cfc25c601e Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 16 Jul 2014 11:42:26 +0300 Subject: Bluetooth: Add proper defines for HCI connection role All HCI commands and events, including LE ones, use 0x00 for master role and 0x01 for slave role. It makes therefore sense to add generic defines for these instead of the current LE_CONN_ROLE_MASTER. Having clean defines will also make it possible to provide simpler internal APIs. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci.h | 6 +++--- net/bluetooth/hci_event.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 2fee852816ee..f0a3d8890760 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -401,6 +401,9 @@ enum { /* The core spec defines 127 as the "not available" value */ #define HCI_TX_POWER_INVALID 127 +#define HCI_ROLE_MASTER 0x00 +#define HCI_ROLE_SLAVE 0x01 + /* Extended Inquiry Response field types */ #define EIR_FLAGS 0x01 /* flags */ #define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */ @@ -1713,9 +1716,6 @@ struct hci_ev_sync_train_complete { #define HCI_EV_SLAVE_PAGE_RESP_TIMEOUT 0x54 -/* Low energy meta events */ -#define LE_CONN_ROLE_MASTER 0x00 - #define HCI_EV_LE_CONN_COMPLETE 0x01 struct hci_ev_le_conn_complete { __u8 status; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 68d335e193bf..13f83c48face 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4116,7 +4116,7 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) conn->dst_type = ev->bdaddr_type; - if (ev->role == LE_CONN_ROLE_MASTER) { + if (ev->role == HCI_ROLE_MASTER) { conn->out = true; set_bit(HCI_CONN_MASTER, &conn->flags); } -- cgit v1.2.3 From 40bef302f6323d1ee6fb3dc0e62edb0f446d0339 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 16 Jul 2014 11:42:27 +0300 Subject: Bluetooth: Convert HCI_CONN_MASTER flag to a conn->role variable Having a dedicated u8 role variable in the hci_conn struct greatly simplifies tracking of the role, since this is the native way that it's represented on the HCI level. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 2 +- net/bluetooth/hci_conn.c | 13 ++++++------- net/bluetooth/hci_event.c | 27 +++++++++------------------ net/bluetooth/l2cap_core.c | 4 ++-- net/bluetooth/smp.c | 12 ++++++------ 5 files changed, 24 insertions(+), 34 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index b52c2ef3f56d..e335c5fd8824 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -371,6 +371,7 @@ struct hci_conn { __u16 state; __u8 mode; __u8 type; + __u8 role; bool out; __u8 attempt; __u8 dev_class[3]; @@ -540,7 +541,6 @@ enum { HCI_CONN_POWER_SAVE, HCI_CONN_REMOTE_OOB, HCI_CONN_FLUSH_KEY, - HCI_CONN_MASTER, HCI_CONN_ENCRYPT, HCI_CONN_AUTH, HCI_CONN_SECURE, diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 490ee8846d9e..6c1c5048984c 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -66,8 +66,7 @@ static void hci_acl_create_connection(struct hci_conn *conn) conn->state = BT_CONNECT; conn->out = true; - - set_bit(HCI_CONN_MASTER, &conn->flags); + conn->role = HCI_ROLE_MASTER; conn->attempt++; @@ -335,7 +334,7 @@ static void hci_conn_timeout(struct work_struct *work) * event handling and hci_clock_offset_evt function. */ if (conn->type == ACL_LINK && - test_bit(HCI_CONN_MASTER, &conn->flags)) { + conn->role == HCI_ROLE_MASTER) { struct hci_dev *hdev = conn->hdev; struct hci_cp_read_clock_offset cp; @@ -786,8 +785,8 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, goto create_conn; } - conn->out = true; - set_bit(HCI_CONN_MASTER, &conn->flags); + conn->out = true; + conn->role = HCI_ROLE_MASTER; params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type); if (params) { @@ -1076,7 +1075,7 @@ int hci_conn_switch_role(struct hci_conn *conn, __u8 role) { BT_DBG("hcon %p", conn); - if (!role && test_bit(HCI_CONN_MASTER, &conn->flags)) + if (role == conn->role) return 1; if (!test_and_set_bit(HCI_CONN_RSWITCH_PEND, &conn->flags)) { @@ -1151,7 +1150,7 @@ static u32 get_link_mode(struct hci_conn *conn) { u32 link_mode = 0; - if (test_bit(HCI_CONN_MASTER, &conn->flags)) + if (conn->role == HCI_ROLE_MASTER) link_mode |= HCI_LM_MASTER; if (test_bit(HCI_CONN_ENCRYPT, &conn->flags)) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 13f83c48face..3b1d2dadedc8 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -101,12 +101,8 @@ static void hci_cc_role_discovery(struct hci_dev *hdev, struct sk_buff *skb) hci_dev_lock(hdev); conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rp->handle)); - if (conn) { - if (rp->role) - clear_bit(HCI_CONN_MASTER, &conn->flags); - else - set_bit(HCI_CONN_MASTER, &conn->flags); - } + if (conn) + conn->role = rp->role; hci_dev_unlock(hdev); } @@ -1420,8 +1416,8 @@ static void hci_cs_create_conn(struct hci_dev *hdev, __u8 status) if (!conn) { conn = hci_conn_add(hdev, ACL_LINK, &cp->bdaddr); if (conn) { - conn->out = true; - set_bit(HCI_CONN_MASTER, &conn->flags); + conn->out = true; + conn->role = HCI_ROLE_MASTER; } else BT_ERR("No memory for new connection"); } @@ -2924,12 +2920,8 @@ static void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb) conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); if (conn) { - if (!ev->status) { - if (ev->role) - clear_bit(HCI_CONN_MASTER, &conn->flags); - else - set_bit(HCI_CONN_MASTER, &conn->flags); - } + if (!ev->status) + conn->role = ev->role; clear_bit(HCI_CONN_RSWITCH_PEND, &conn->flags); @@ -4116,10 +4108,9 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) conn->dst_type = ev->bdaddr_type; - if (ev->role == HCI_ROLE_MASTER) { + conn->role = ev->role; + if (conn->role == HCI_ROLE_MASTER) conn->out = true; - set_bit(HCI_CONN_MASTER, &conn->flags); - } /* If we didn't have a hci_conn object previously * but we're in master role this must be something @@ -4527,7 +4518,7 @@ static void hci_le_remote_conn_param_req_evt(struct hci_dev *hdev, return send_conn_param_neg_reply(hdev, handle, HCI_ERROR_INVALID_LL_PARAMS); - if (test_bit(HCI_CONN_MASTER, &hcon->flags)) { + if (hcon->role == HCI_ROLE_MASTER) { struct hci_conn_params *params; u8 store_hint; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 8538cb07b0c0..ea68d3219b7e 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1487,7 +1487,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) * been configured for this connection. If not, then trigger * the connection update procedure. */ - if (!test_bit(HCI_CONN_MASTER, &hcon->flags) && + if (hcon->role == HCI_ROLE_SLAVE && (hcon->le_conn_interval < hcon->le_conn_min_interval || hcon->le_conn_interval > hcon->le_conn_max_interval)) { struct l2cap_conn_param_update_req req; @@ -5227,7 +5227,7 @@ static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn, u16 min, max, latency, to_multiplier; int err; - if (!test_bit(HCI_CONN_MASTER, &hcon->flags)) + if (hcon->role != HCI_ROLE_MASTER) return -EINVAL; if (cmd_len != sizeof(struct l2cap_conn_param_update_req)) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 8339d6b0f2b8..78eeb8b5970a 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -445,7 +445,7 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth, * Confirms and the slave Enters the passkey. */ if (method == OVERLAP) { - if (test_bit(HCI_CONN_MASTER, &hcon->flags)) + if (hcon->role == HCI_ROLE_MASTER) method = CFM_PASSKEY; else method = REQ_PASSKEY; @@ -686,7 +686,7 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) if (skb->len < sizeof(*req)) return SMP_INVALID_PARAMS; - if (test_bit(HCI_CONN_MASTER, &conn->hcon->flags)) + if (conn->hcon->role != HCI_ROLE_SLAVE) return SMP_CMD_NOTSUPP; if (!test_and_set_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) @@ -755,7 +755,7 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb) if (skb->len < sizeof(*rsp)) return SMP_INVALID_PARAMS; - if (!test_bit(HCI_CONN_MASTER, &conn->hcon->flags)) + if (conn->hcon->role != HCI_ROLE_MASTER) return SMP_CMD_NOTSUPP; skb_pull(skb, sizeof(*rsp)); @@ -903,7 +903,7 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) if (skb->len < sizeof(*rp)) return SMP_INVALID_PARAMS; - if (!test_bit(HCI_CONN_MASTER, &conn->hcon->flags)) + if (hcon->role != HCI_ROLE_MASTER) return SMP_CMD_NOTSUPP; sec_level = authreq_to_seclevel(rp->auth_req); @@ -961,7 +961,7 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level) if (sec_level > hcon->pending_sec_level) hcon->pending_sec_level = sec_level; - if (test_bit(HCI_CONN_MASTER, &hcon->flags)) + if (hcon->role == HCI_ROLE_MASTER) if (smp_ltk_encrypt(conn, hcon->pending_sec_level)) return 0; @@ -981,7 +981,7 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level) hcon->pending_sec_level > BT_SECURITY_MEDIUM) authreq |= SMP_AUTH_MITM; - if (test_bit(HCI_CONN_MASTER, &hcon->flags)) { + if (hcon->role == HCI_ROLE_MASTER) { struct smp_cmd_pairing cp; build_pairing_cmd(conn, &cp, NULL, authreq); -- cgit v1.2.3 From e804d25d4a07c0ff9e5e1c58ea5ee67232aa9af8 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 16 Jul 2014 11:42:28 +0300 Subject: Bluetooth: Use explicit role instead of a bool in function parameters To make the code more understandable it makes sense to use the new HCI defines for connection role instead of a "bool master" parameter. This makes it immediately clear when looking at the function calls what the last parameter is describing. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 6 +++--- net/bluetooth/hci_conn.c | 7 ++++--- net/bluetooth/hci_core.c | 19 +++++++++++-------- net/bluetooth/hci_event.c | 5 ++--- net/bluetooth/l2cap_core.c | 9 ++++++--- net/bluetooth/mgmt.c | 4 ++-- net/bluetooth/smp.c | 4 ++-- 7 files changed, 30 insertions(+), 24 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index e335c5fd8824..abe5083becd3 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -707,7 +707,7 @@ struct hci_chan *hci_chan_lookup_handle(struct hci_dev *hdev, __u16 handle); struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, u8 dst_type, u8 sec_level, u16 conn_timeout, - bool master); + u8 role); struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst, u8 sec_level, u8 auth_type); struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst, @@ -881,12 +881,12 @@ struct link_key *hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len, bool *persistent); struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, __le64 rand, - bool master); + u8 role); struct smp_ltk *hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type, u8 authenticated, u8 tk[16], u8 enc_size, __le16 ediv, __le64 rand); struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 addr_type, bool master); + u8 addr_type, u8 role); int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 bdaddr_type); void hci_smp_ltks_clear(struct hci_dev *hdev); int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr); diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 6c1c5048984c..6edd55340157 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -697,7 +697,7 @@ static void hci_req_directed_advertising(struct hci_request *req, struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, u8 dst_type, u8 sec_level, u16 conn_timeout, - bool master) + u8 role) { struct hci_conn_params *params; struct hci_conn *conn; @@ -769,8 +769,10 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, &enable); } + conn->role = role; + /* If requested to connect as slave use directed advertising */ - if (!master) { + if (conn->role == HCI_ROLE_SLAVE) { /* If we're active scanning most controllers are unable * to initiate advertising. Simply reject the attempt. */ @@ -786,7 +788,6 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, } conn->out = true; - conn->role = HCI_ROLE_MASTER; params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type); if (params) { diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 172041e2b15a..f575abdf2b4e 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3121,13 +3121,16 @@ static bool hci_persistent_key(struct hci_dev *hdev, struct hci_conn *conn, return false; } -static bool ltk_type_master(u8 type) +static u8 ltk_role(u8 type) { - return (type == SMP_LTK); + if (type == SMP_LTK) + return HCI_ROLE_MASTER; + + return HCI_ROLE_SLAVE; } struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, __le64 rand, - bool master) + u8 role) { struct smp_ltk *k; @@ -3135,7 +3138,7 @@ struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, __le64 rand, if (k->ediv != ediv || k->rand != rand) continue; - if (ltk_type_master(k->type) != master) + if (ltk_role(k->type) != role) continue; return k; @@ -3145,14 +3148,14 @@ struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, __le64 rand, } struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 addr_type, bool master) + u8 addr_type, u8 role) { struct smp_ltk *k; list_for_each_entry(k, &hdev->long_term_keys, list) if (addr_type == k->bdaddr_type && bacmp(bdaddr, &k->bdaddr) == 0 && - ltk_type_master(k->type) == master) + ltk_role(k->type) == role) return k; return NULL; @@ -3247,9 +3250,9 @@ struct smp_ltk *hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 tk[16], u8 enc_size, __le16 ediv, __le64 rand) { struct smp_ltk *key, *old_key; - bool master = ltk_type_master(type); + u8 role = ltk_role(type); - old_key = hci_find_ltk_by_addr(hdev, bdaddr, addr_type, master); + old_key = hci_find_ltk_by_addr(hdev, bdaddr, addr_type, role); if (old_key) key = old_key; else { diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 3b1d2dadedc8..5f7fd410fb3b 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4263,9 +4263,8 @@ static void check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr, return; connect: - /* Request connection in master = true role */ conn = hci_connect_le(hdev, addr, addr_type, BT_SECURITY_LOW, - HCI_LE_AUTOCONN_TIMEOUT, true); + HCI_LE_AUTOCONN_TIMEOUT, HCI_ROLE_MASTER); if (!IS_ERR(conn)) return; @@ -4443,7 +4442,7 @@ static void hci_le_ltk_request_evt(struct hci_dev *hdev, struct sk_buff *skb) if (conn == NULL) goto not_found; - ltk = hci_find_ltk(hdev, ev->ediv, ev->rand, conn->out); + ltk = hci_find_ltk(hdev, ev->ediv, ev->rand, conn->role); if (ltk == NULL) goto not_found; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index ea68d3219b7e..d0f36336b6ce 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -7128,7 +7128,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, chan->dcid = cid; if (bdaddr_type_is_le(dst_type)) { - bool master; + u8 role; /* Convert from L2CAP channel address type to HCI address type */ @@ -7137,10 +7137,13 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, else dst_type = ADDR_LE_DEV_RANDOM; - master = !test_bit(HCI_ADVERTISING, &hdev->dev_flags); + if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) + role = HCI_ROLE_SLAVE; + else + role = HCI_ROLE_MASTER; hcon = hci_connect_le(hdev, dst, dst_type, chan->sec_level, - HCI_LE_CONN_TIMEOUT, master); + HCI_LE_CONN_TIMEOUT, role); } else { u8 auth_type = l2cap_get_auth_type(chan); hcon = hci_connect_acl(hdev, dst, chan->sec_level, auth_type); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 7703b72653ff..b981bfb87f86 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3154,9 +3154,9 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, */ hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type); - /* Request a connection with master = true role */ conn = hci_connect_le(hdev, &cp->addr.bdaddr, addr_type, - sec_level, HCI_LE_CONN_TIMEOUT, true); + sec_level, HCI_LE_CONN_TIMEOUT, + HCI_ROLE_MASTER); } if (IS_ERR(conn)) { diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 78eeb8b5970a..70b726518d7b 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -849,7 +849,7 @@ static bool smp_ltk_encrypt(struct l2cap_conn *conn, u8 sec_level) struct hci_conn *hcon = conn->hcon; key = hci_find_ltk_by_addr(hcon->hdev, &hcon->dst, hcon->dst_type, - hcon->out); + hcon->role); if (!key) return false; @@ -881,7 +881,7 @@ bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level) */ if (test_bit(HCI_CONN_STK_ENCRYPT, &hcon->flags) && hci_find_ltk_by_addr(hcon->hdev, &hcon->dst, hcon->dst_type, - hcon->out)) + hcon->role)) return false; if (hcon->sec_level >= sec_level) -- cgit v1.2.3 From a5c4e309b9f23b9de5475029b2cb1641ec293137 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 16 Jul 2014 11:56:07 +0300 Subject: Bluetooth: Add a role parameter to hci_conn_add() We need to be able to track slave vs master LE connections in hci_conn_hash, and to be able to do that we need to know the role of the connection by the time hci_conn_add_has() is called. This means in practice the hci_conn_add() call that creates the hci_conn_object. This patch adds a new role parameter to hci_conn_add() function to give the object its initial role value, and updates the callers to pass the appropriate role to it. Since the function now takes care of initializing both conn->role and conn->out values we can remove some other unnecessary assignments. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 3 ++- net/bluetooth/amp.c | 4 ++-- net/bluetooth/hci_conn.c | 17 +++++++++-------- net/bluetooth/hci_event.c | 17 ++++++----------- 4 files changed, 19 insertions(+), 22 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index abe5083becd3..3de000fbecdc 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -695,7 +695,8 @@ void hci_disconnect(struct hci_conn *conn, __u8 reason); bool hci_setup_sync(struct hci_conn *conn, __u16 handle); void hci_sco_setup(struct hci_conn *conn, __u8 status); -struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst); +struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst, + u8 role); int hci_conn_del(struct hci_conn *conn); void hci_conn_hash_flush(struct hci_dev *hdev); void hci_conn_check_pending(struct hci_dev *hdev); diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c index bb39509b3f06..e60603a8969f 100644 --- a/net/bluetooth/amp.c +++ b/net/bluetooth/amp.c @@ -113,8 +113,9 @@ struct hci_conn *phylink_add(struct hci_dev *hdev, struct amp_mgr *mgr, { bdaddr_t *dst = &mgr->l2cap_conn->hcon->dst; struct hci_conn *hcon; + u8 role = out ? HCI_ROLE_MASTER : HCI_ROLE_SLAVE; - hcon = hci_conn_add(hdev, AMP_LINK, dst); + hcon = hci_conn_add(hdev, AMP_LINK, dst, role); if (!hcon) return NULL; @@ -125,7 +126,6 @@ struct hci_conn *phylink_add(struct hci_dev *hdev, struct amp_mgr *mgr, hcon->handle = __next_handle(mgr); hcon->remote_id = remote_id; hcon->amp_mgr = amp_mgr_get(mgr); - hcon->out = out; return hcon; } diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 6edd55340157..ad5f0b819e90 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -421,7 +421,8 @@ static void le_conn_timeout(struct work_struct *work) hci_le_create_connection_cancel(conn); } -struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) +struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst, + u8 role) { struct hci_conn *conn; @@ -435,6 +436,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) bacpy(&conn->src, &hdev->bdaddr); conn->hdev = hdev; conn->type = type; + conn->role = role; conn->mode = HCI_CM_ACTIVE; conn->state = BT_OPEN; conn->auth_type = HCI_AT_GENERAL_BONDING; @@ -447,6 +449,9 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) set_bit(HCI_CONN_POWER_SAVE, &conn->flags); conn->disc_timeout = HCI_DISCONN_TIMEOUT; + if (conn->role == HCI_ROLE_MASTER) + conn->out = true; + switch (type) { case ACL_LINK: conn->pkt_type = hdev->pkt_type & ACL_PTYPE_MASK; @@ -746,7 +751,7 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, dst_type = ADDR_LE_DEV_RANDOM; } - conn = hci_conn_add(hdev, LE_LINK, dst); + conn = hci_conn_add(hdev, LE_LINK, dst, role); if (!conn) return ERR_PTR(-ENOMEM); @@ -769,8 +774,6 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, &enable); } - conn->role = role; - /* If requested to connect as slave use directed advertising */ if (conn->role == HCI_ROLE_SLAVE) { /* If we're active scanning most controllers are unable @@ -787,8 +790,6 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, goto create_conn; } - conn->out = true; - params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type); if (params) { conn->le_conn_min_interval = params->conn_min_interval; @@ -837,7 +838,7 @@ struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst, acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst); if (!acl) { - acl = hci_conn_add(hdev, ACL_LINK, dst); + acl = hci_conn_add(hdev, ACL_LINK, dst, HCI_ROLE_MASTER); if (!acl) return ERR_PTR(-ENOMEM); } @@ -866,7 +867,7 @@ struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst, sco = hci_conn_hash_lookup_ba(hdev, type, dst); if (!sco) { - sco = hci_conn_add(hdev, type, dst); + sco = hci_conn_add(hdev, type, dst, HCI_ROLE_MASTER); if (!sco) { hci_conn_drop(acl); return ERR_PTR(-ENOMEM); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 5f7fd410fb3b..c68b93e11686 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1414,11 +1414,9 @@ static void hci_cs_create_conn(struct hci_dev *hdev, __u8 status) } } else { if (!conn) { - conn = hci_conn_add(hdev, ACL_LINK, &cp->bdaddr); - if (conn) { - conn->out = true; - conn->role = HCI_ROLE_MASTER; - } else + conn = hci_conn_add(hdev, ACL_LINK, &cp->bdaddr, + HCI_ROLE_MASTER); + if (!conn) BT_ERR("No memory for new connection"); } } @@ -2156,7 +2154,8 @@ static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr); if (!conn) { - conn = hci_conn_add(hdev, ev->link_type, &ev->bdaddr); + conn = hci_conn_add(hdev, ev->link_type, &ev->bdaddr, + HCI_ROLE_SLAVE); if (!conn) { BT_ERR("No memory for new connection"); hci_dev_unlock(hdev); @@ -4100,7 +4099,7 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT); if (!conn) { - conn = hci_conn_add(hdev, LE_LINK, &ev->bdaddr); + conn = hci_conn_add(hdev, LE_LINK, &ev->bdaddr, ev->role); if (!conn) { BT_ERR("No memory for new connection"); goto unlock; @@ -4108,10 +4107,6 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) conn->dst_type = ev->bdaddr_type; - conn->role = ev->role; - if (conn->role == HCI_ROLE_MASTER) - conn->out = true; - /* If we didn't have a hci_conn object previously * but we're in master role this must be something * initiated using a white list. Since white list based -- cgit v1.2.3 From f99353cf9c061bc1700b6a49ee98cae93e28207b Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 16 Jul 2014 11:56:09 +0300 Subject: Bluetooth: Fix trying to initiate connections when acting as LE slave When we have at least one LE slave connection most (probably all) controllers will refuse to initiate any new connections. To avoid unnecessary failures simply check for this situation up-front and skip the connection attempt. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index c68b93e11686..e54db7f0590b 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4246,6 +4246,12 @@ static void check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr, if (hci_bdaddr_list_lookup(&hdev->blacklist, addr, addr_type)) return; + /* Most controller will fail if we try to create new connections + * while we have an existing one in slave role. + */ + if (hdev->conn_hash.le_num_slave > 0) + return; + /* If we're connectable, always connect any ADV_DIRECT_IND event */ if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags) && adv_type == LE_ADV_DIRECT_IND) -- cgit v1.2.3 From 46c4c941a417265e4b8afb3c52f31cabcbf4deb1 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 16 Jul 2014 16:19:21 +0300 Subject: Bluetooth: Fix always checking the blacklist for incoming connections We should check the blacklist no matter what, meaning also when we're not connectable. This patch fixes the respective logic in the function making the decision whether to accept a connection or not. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index e54db7f0590b..cae860b02d67 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2129,18 +2129,17 @@ static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) return; } - if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) { - if (hci_bdaddr_list_lookup(&hdev->blacklist, &ev->bdaddr, - BDADDR_BREDR)) { - hci_reject_conn(hdev, &ev->bdaddr); - return; - } - } else { - if (!hci_bdaddr_list_lookup(&hdev->whitelist, &ev->bdaddr, - BDADDR_BREDR)) { - hci_reject_conn(hdev, &ev->bdaddr); - return; - } + if (hci_bdaddr_list_lookup(&hdev->blacklist, &ev->bdaddr, + BDADDR_BREDR)) { + hci_reject_conn(hdev, &ev->bdaddr); + return; + } + + if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags) && + !hci_bdaddr_list_lookup(&hdev->whitelist, &ev->bdaddr, + BDADDR_BREDR)) { + hci_reject_conn(hdev, &ev->bdaddr); + return; } /* Connection accepted */ -- cgit v1.2.3 From 9f743d7499bc2c4dc8c35af33bdb2a29bea663b9 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 17 Jul 2014 11:56:33 +0300 Subject: Bluetooth: Fix using uninitialized variable when pairing Commit 6c53823ae0e10e723131055e1e65dd6a328a228e reshuffled the way the authentication requirement gets set in the hci_io_capa_request_evt() function, but at the same time it failed to update an if-statement where cp.authentication is used before it has been initialized. The correct value the code should be looking for in this if-statement is conn->auth_type. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann Cc: stable@vger.kernel.org # 3.16 --- net/bluetooth/hci_event.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index cae860b02d67..1ac526022ad9 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3658,7 +3658,7 @@ static void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff *skb) * except for the no-bonding case. */ if (conn->io_capability != HCI_IO_NO_INPUT_OUTPUT && - cp.authentication != HCI_AT_NO_BONDING) + conn->auth_type != HCI_AT_NO_BONDING) conn->auth_type |= 0x01; cp.authentication = conn->auth_type; -- cgit v1.2.3 From 02f3e25457915728624b976b0382601b5605ad64 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 16 Jul 2014 15:09:13 +0300 Subject: Bluetooth: Don't bother user space without IO capabilities If user space has a NoInputNoOutput IO capability it makes no sense to bother it with confirmation requests. This patch updates both SSP and SMP to check for the local IO capability before sending a user confirmation request to user space. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 4 +++- net/bluetooth/smp.c | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 1ac526022ad9..1bd4de7e74fc 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3752,9 +3752,11 @@ static void hci_user_confirm_request_evt(struct hci_dev *hdev, /* If we're not the initiators request authorization to * proceed from user space (mgmt_user_confirm with * confirm_hint set to 1). The exception is if neither - * side had MITM in which case we do auto-accept. + * side had MITM or if the local IO capability is + * NoInputNoOutput, in which case we do auto-accept */ if (!test_bit(HCI_CONN_AUTH_PEND, &conn->flags) && + conn->io_capability != HCI_IO_NO_INPUT_OUTPUT && (loc_mitm || rem_mitm)) { BT_DBG("Confirming auto-accept as acceptor"); confirm_hint = 1; diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 70b726518d7b..74a0308e39f3 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -431,6 +431,10 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth, if (method == JUST_CFM && test_bit(SMP_FLAG_INITIATOR, &smp->flags)) method = JUST_WORKS; + /* Don't bother user space with no IO capabilities */ + if (method == JUST_CFM && hcon->io_capability == HCI_IO_NO_INPUT_OUTPUT) + method = JUST_WORKS; + /* If Just Works, Continue with Zero TK */ if (method == JUST_WORKS) { set_bit(SMP_FLAG_TK_VALID, &smp->flags); -- cgit v1.2.3 From 093facf3634da1b0c2cc7ed106f1983da901bbab Mon Sep 17 00:00:00 2001 From: Vladimir Davydov Date: Tue, 15 Jul 2014 12:25:28 +0400 Subject: Bluetooth: never linger on process exit If the current process is exiting, lingering on socket close will make it unkillable, so we should avoid it. Reproducer: #include #include #define BTPROTO_L2CAP 0 #define BTPROTO_SCO 2 #define BTPROTO_RFCOMM 3 int main() { int fd; struct linger ling; fd = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); //or: fd = socket(PF_BLUETOOTH, SOCK_DGRAM, BTPROTO_L2CAP); //or: fd = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO); ling.l_onoff = 1; ling.l_linger = 1000000000; setsockopt(fd, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling)); return 0; } Signed-off-by: Vladimir Davydov Signed-off-by: Marcel Holtmann Cc: stable@vger.kernel.org --- net/bluetooth/l2cap_sock.c | 3 ++- net/bluetooth/rfcomm/sock.c | 3 ++- net/bluetooth/sco.c | 6 ++++-- 3 files changed, 8 insertions(+), 4 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 9bb4d1b3a483..0bc67dc5dcce 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -1112,7 +1112,8 @@ static int l2cap_sock_shutdown(struct socket *sock, int how) l2cap_chan_close(chan, 0); lock_sock(sk); - if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime) + if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime && + !(current->flags & PF_EXITING)) err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime); } diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index c603a5eb4720..8bbbb5ec468c 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -918,7 +918,8 @@ static int rfcomm_sock_shutdown(struct socket *sock, int how) sk->sk_shutdown = SHUTDOWN_MASK; __rfcomm_sock_close(sk); - if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime) + if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime && + !(current->flags & PF_EXITING)) err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime); } release_sock(sk); diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index ebf7ee6a446c..7ee9e4ab00f8 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -970,7 +970,8 @@ static int sco_sock_shutdown(struct socket *sock, int how) sco_sock_clear_timer(sk); __sco_sock_close(sk); - if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime) + if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime && + !(current->flags & PF_EXITING)) err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime); } @@ -990,7 +991,8 @@ static int sco_sock_release(struct socket *sock) sco_sock_close(sk); - if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime) { + if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime && + !(current->flags & PF_EXITING)) { lock_sock(sk); err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime); release_sock(sk); -- cgit v1.2.3 From c1d4fa7aa86e9194724dfff9cb9359edb98d75ac Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 17 Jul 2014 15:14:50 +0300 Subject: Bluetooth: Fix resetting remote authentication requirement after pairing When a new hci_conn object is created the remote SSP authentication requirement is set to the invalid value 0xff to indicate that it is unknown. Once pairing completes however the code was leaving it as-is. In case a new pairing happens over the same connection it is important that we reset the value back to unknown so that the pairing code doesn't make false assumptions about the requirements. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 1bd4de7e74fc..495d6d5c1146 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3870,6 +3870,9 @@ static void hci_simple_pair_complete_evt(struct hci_dev *hdev, if (!conn) goto unlock; + /* Reset the authentication requirement to unknown */ + conn->remote_auth = 0xff; + /* To avoid duplicate auth_failed events to user space we check * the HCI_CONN_AUTH_PEND flag which will be set if we * initiated the authentication. A traditional auth_complete -- cgit v1.2.3 From e7cafc45258c852c5176cd421615846e79a3d307 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 17 Jul 2014 15:35:38 +0300 Subject: Bluetooth: Pass initiator/acceptor information to hci_conn_security() We're interested in whether an authentication request is because of a remote or local action. So far hci_conn_security() has been used both for incoming and outgoing actions (e.g. RFCOMM or L2CAP connect requests) so without some modifications it cannot know which peer is responsible for requesting authentication. This patch adds a new "bool initiator" parameter to hci_conn_security() to indicate which side is responsible for the request and updates the current users to pass this information correspondingly. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 3 ++- include/net/bluetooth/l2cap.h | 2 +- net/bluetooth/hci_conn.c | 3 ++- net/bluetooth/l2cap_core.c | 15 ++++++++------- net/bluetooth/l2cap_sock.c | 2 +- net/bluetooth/mgmt.c | 2 +- net/bluetooth/rfcomm/core.c | 3 ++- 7 files changed, 17 insertions(+), 13 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 73e16ecfd6b9..eb2b9c9e3480 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -720,7 +720,8 @@ struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst, __u16 setting); int hci_conn_check_link_mode(struct hci_conn *conn); int hci_conn_check_secure(struct hci_conn *conn, __u8 sec_level); -int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type); +int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type, + bool initiator); int hci_conn_change_link_key(struct hci_conn *conn); int hci_conn_switch_role(struct hci_conn *conn, __u8 role); diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 1fffd92808b0..8df15ad0d43f 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -905,7 +905,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *dst, u8 dst_type); int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len); void l2cap_chan_busy(struct l2cap_chan *chan, int busy); -int l2cap_chan_check_security(struct l2cap_chan *chan); +int l2cap_chan_check_security(struct l2cap_chan *chan, bool initiator); void l2cap_chan_set_defaults(struct l2cap_chan *chan); int l2cap_ertm_init(struct l2cap_chan *chan); void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan); diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index ad5f0b819e90..76c5a38e5997 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -973,7 +973,8 @@ static void hci_conn_encrypt(struct hci_conn *conn) } /* Enable security */ -int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) +int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type, + bool initiator) { BT_DBG("hcon %p", conn); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index d0f36336b6ce..c8c259f21d80 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -775,7 +775,7 @@ static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan) } /* Service level security */ -int l2cap_chan_check_security(struct l2cap_chan *chan) +int l2cap_chan_check_security(struct l2cap_chan *chan, bool initiator) { struct l2cap_conn *conn = chan->conn; __u8 auth_type; @@ -785,7 +785,8 @@ int l2cap_chan_check_security(struct l2cap_chan *chan) auth_type = l2cap_get_auth_type(chan); - return hci_conn_security(conn->hcon, chan->sec_level, auth_type); + return hci_conn_security(conn->hcon, chan->sec_level, auth_type, + initiator); } static u8 l2cap_get_ident(struct l2cap_conn *conn) @@ -1278,7 +1279,7 @@ static void l2cap_do_start(struct l2cap_chan *chan) if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)) return; - if (l2cap_chan_check_security(chan) && + if (l2cap_chan_check_security(chan, true) && __l2cap_no_conn_pending(chan)) { l2cap_start_connection(chan); } @@ -1357,7 +1358,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) } if (chan->state == BT_CONNECT) { - if (!l2cap_chan_check_security(chan) || + if (!l2cap_chan_check_security(chan, true) || !__l2cap_no_conn_pending(chan)) { l2cap_chan_unlock(chan); continue; @@ -1379,7 +1380,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) rsp.scid = cpu_to_le16(chan->dcid); rsp.dcid = cpu_to_le16(chan->scid); - if (l2cap_chan_check_security(chan)) { + if (l2cap_chan_check_security(chan, false)) { if (test_bit(FLAG_DEFER_SETUP, &chan->flags)) { rsp.result = cpu_to_le16(L2CAP_CR_PEND); rsp.status = cpu_to_le16(L2CAP_CS_AUTHOR_PEND); @@ -3849,7 +3850,7 @@ static struct l2cap_chan *l2cap_connect(struct l2cap_conn *conn, chan->ident = cmd->ident; if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) { - if (l2cap_chan_check_security(chan)) { + if (l2cap_chan_check_security(chan, false)) { if (test_bit(FLAG_DEFER_SETUP, &chan->flags)) { l2cap_state_change(chan, BT_CONNECT2); result = L2CAP_CR_PEND; @@ -7191,7 +7192,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, if (hcon->state == BT_CONNECTED) { if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) { __clear_chan_timer(chan); - if (l2cap_chan_check_security(chan)) + if (l2cap_chan_check_security(chan, true)) l2cap_state_change(chan, BT_CONNECTED); } else l2cap_do_start(chan); diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 0bc67dc5dcce..3bb1cdf34f07 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -797,7 +797,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, } else if ((sk->sk_state == BT_CONNECT2 && test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) || sk->sk_state == BT_CONNECTED) { - if (!l2cap_chan_check_security(chan)) + if (!l2cap_chan_check_security(chan, true)) set_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags); else sk->sk_state_change(sk); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index b981bfb87f86..190668367e42 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3202,7 +3202,7 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, cmd->user_data = conn; if (conn->state == BT_CONNECTED && - hci_conn_security(conn, sec_level, auth_type)) + hci_conn_security(conn, sec_level, auth_type, true)) pairing_complete(cmd, 0); err = 0; diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index 754b6fe4f742..a0690a84f3e9 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -227,7 +227,8 @@ static int rfcomm_check_security(struct rfcomm_dlc *d) break; } - return hci_conn_security(conn->hcon, d->sec_level, auth_type); + return hci_conn_security(conn->hcon, d->sec_level, auth_type, + d->out); } static void rfcomm_session_timeout(unsigned long arg) -- cgit v1.2.3 From 977f8fce0279e5f96dc5c5068610d60b9ae94802 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 17 Jul 2014 15:35:39 +0300 Subject: Bluetooth: Introduce a flag to track who really initiates authentication Even though our side requests authentication, the original action that caused it may be remotely triggered, such as an incoming L2CAP or RFCOMM connect request. To track this information introduce a new hci_conn flag called HCI_CONN_AUTH_INITIATOR. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_conn.c | 3 +++ net/bluetooth/hci_event.c | 5 +++++ 3 files changed, 9 insertions(+) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index eb2b9c9e3480..996ed065b6c2 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -547,6 +547,7 @@ enum { HCI_CONN_SECURE, HCI_CONN_FIPS, HCI_CONN_STK_ENCRYPT, + HCI_CONN_AUTH_INITIATOR, }; static inline bool hci_conn_ssp_enabled(struct hci_conn *conn) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 76c5a38e5997..0d76054efd26 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -1027,6 +1027,9 @@ auth: if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags)) return 0; + if (initiator) + set_bit(HCI_CONN_AUTH_INITIATOR, &conn->flags); + if (!hci_conn_auth(conn, sec_level, auth_type)) return 0; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 495d6d5c1146..af2cdca03d73 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1645,6 +1645,8 @@ static void hci_cs_remote_name_req(struct hci_dev *hdev, __u8 status) if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) { struct hci_cp_auth_requested auth_cp; + set_bit(HCI_CONN_AUTH_INITIATOR, &conn->flags); + auth_cp.handle = __cpu_to_le16(conn->handle); hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, sizeof(auth_cp), &auth_cp); @@ -2387,6 +2389,9 @@ check_auth: if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) { struct hci_cp_auth_requested cp; + + set_bit(HCI_CONN_AUTH_INITIATOR, &conn->flags); + cp.handle = __cpu_to_le16(conn->handle); hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp); } -- cgit v1.2.3 From 2f407f0afb443207789df3fb46456551aea11cc3 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 17 Jul 2014 15:35:40 +0300 Subject: Bluetooth: Fix allowing initiating pairing when not pairable When we're not pairable we should still allow us to act as initiators for pairing, i.e. the HCI_PAIRABLE flag should only be affecting incoming pairing attempts. This patch fixes the relevant checks for the hci_io_capa_request_evt() and hci_pin_code_request_evt() functions. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index af2cdca03d73..4c41774aa556 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3118,10 +3118,11 @@ static void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff *skb) hci_conn_drop(conn); } - if (!test_bit(HCI_PAIRABLE, &hdev->dev_flags)) + if (!test_bit(HCI_PAIRABLE, &hdev->dev_flags) && + !test_bit(HCI_CONN_AUTH_INITIATOR, &conn->flags)) { hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(ev->bdaddr), &ev->bdaddr); - else if (test_bit(HCI_MGMT, &hdev->dev_flags)) { + } else if (test_bit(HCI_MGMT, &hdev->dev_flags)) { u8 secure; if (conn->pending_sec_level == BT_SECURITY_HIGH) @@ -3647,7 +3648,11 @@ static void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff *skb) if (!test_bit(HCI_MGMT, &hdev->dev_flags)) goto unlock; + /* Allow pairing if we're pairable, the initiators of the + * pairing or if the remote is not requesting bonding. + */ if (test_bit(HCI_PAIRABLE, &hdev->dev_flags) || + test_bit(HCI_CONN_AUTH_INITIATOR, &conn->flags) || (conn->remote_auth & ~0x01) == HCI_AT_NO_BONDING) { struct hci_cp_io_capability_reply cp; -- cgit v1.2.3 From beb19e4c079d626bf0502fbb65bd7c9891a10c2e Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 18 Jul 2014 11:15:26 +0300 Subject: Bluetooth: Use EOPNOTSUPP instead of ENOTSUPP The EOPNOTSUPP and ENOTSUPP errors are very similar in meaning, but ENOTSUPP is a fairly new addition to POSIX. Not all libc versions know about the value the kernel uses for ENOTSUPP so it's better to use EOPNOTSUPP to ensure understandable error messages. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_conn.c | 2 +- net/bluetooth/l2cap_core.c | 2 +- net/bluetooth/l2cap_sock.c | 2 +- net/bluetooth/smp.c | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 0d76054efd26..1ac9f7f52acd 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -834,7 +834,7 @@ struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst, struct hci_conn *acl; if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) - return ERR_PTR(-ENOTSUPP); + return ERR_PTR(-EOPNOTSUPP); acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst); if (!acl) { diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index c8c259f21d80..f3fb61c9f96f 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -7094,7 +7094,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, break; /* fall through */ default: - err = -ENOTSUPP; + err = -EOPNOTSUPP; goto done; } diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 3bb1cdf34f07..1884f72083c2 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -279,7 +279,7 @@ static int l2cap_sock_listen(struct socket *sock, int backlog) break; /* fall through */ default: - err = -ENOTSUPP; + err = -EOPNOTSUPP; goto done; } diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 74a0308e39f3..e49c83d8b957 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -1189,7 +1189,7 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb) } if (!test_bit(HCI_LE_ENABLED, &hcon->hdev->dev_flags)) { - err = -ENOTSUPP; + err = -EOPNOTSUPP; reason = SMP_PAIRING_NOTSUPP; goto done; } @@ -1207,7 +1207,7 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb) !conn->smp_chan) { BT_ERR("Unexpected SMP command 0x%02x. Disconnecting.", code); kfree_skb(skb); - return -ENOTSUPP; + return -EOPNOTSUPP; } switch (code) { -- cgit v1.2.3 From d1d588c181e35d98113f91c8004f77cdac2bf9d5 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 20 Jul 2014 17:10:45 +0300 Subject: Bluetooth: Disable HCI_CONNECTABLE based passive scanning for now When HCI_CONNECTABLE is set the code has been enabling passive scanning in order to be consistent with BR/EDR and accept connections from any device doing directed advertising to us. However, some hardware (particularly CSR) can get very noisy even when doing duplicates filtering, making this feature waste resources. Considering that the feature is for fairly corner-case use (devices who'd use directed advertising would likely be in the whitelist anyway) it's better to disable it for now. It may still be brought back later, possibly with a better implementation (e.g. through improved scan parameters). Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index f575abdf2b4e..f82a6cf1aaa8 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -5465,8 +5465,7 @@ void hci_update_background_scan(struct hci_dev *hdev) hci_req_init(&req, hdev); - if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags) && - list_empty(&hdev->pend_le_conns) && + if (list_empty(&hdev->pend_le_conns) && list_empty(&hdev->pend_le_reports)) { /* If there is no pending LE connections or devices * to be scanned for, we should stop the background -- cgit v1.2.3 From 0a961a440d693f0f74d3185728b13b8a11fc5860 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 20 Jul 2014 17:43:07 +0200 Subject: Bluetooth: Remove unneeded variable assignment in hmac_sha256 The variable ret does not need to be assigned when declaring it. So remove this initial assignment. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/amp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c index e60603a8969f..016cdb66df6c 100644 --- a/net/bluetooth/amp.c +++ b/net/bluetooth/amp.c @@ -133,8 +133,8 @@ struct hci_conn *phylink_add(struct hci_dev *hdev, struct amp_mgr *mgr, /* AMP crypto key generation interface */ static int hmac_sha256(u8 *key, u8 ksize, char *plaintext, u8 psize, u8 *output) { - int ret = 0; struct crypto_shash *tfm; + int ret; if (!ksize) return -EINVAL; -- cgit v1.2.3 From 27f70f3e628c82362def60eb0af79d2129a51da2 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 21 Jul 2014 10:50:06 +0300 Subject: Bluetooth: Prefer sizeof(*ptr) when allocating memory It's safer practice to use sizeof(*ptr) instead of sizeof(ptr_type) when allocating memory in case the type changes. This also fixes the following style of warnings from static analyzers: CHECK: Prefer kzalloc(sizeof(*ie)...) over kzalloc(sizeof(struct inquiry_entry)...) + ie = kzalloc(sizeof(struct inquiry_entry), GFP_KERNEL); Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_conn.c | 4 ++-- net/bluetooth/hci_core.c | 6 +++--- net/bluetooth/l2cap_core.c | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 1ac9f7f52acd..b50dabb3f86a 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -428,7 +428,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst, BT_DBG("%s dst %pMR", hdev->name, dst); - conn = kzalloc(sizeof(struct hci_conn), GFP_KERNEL); + conn = kzalloc(sizeof(*conn), GFP_KERNEL); if (!conn) return NULL; @@ -1282,7 +1282,7 @@ struct hci_chan *hci_chan_create(struct hci_conn *conn) BT_DBG("%s hcon %p", hdev->name, conn); - chan = kzalloc(sizeof(struct hci_chan), GFP_KERNEL); + chan = kzalloc(sizeof(*chan), GFP_KERNEL); if (!chan) return NULL; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index f82a6cf1aaa8..cfcb6055ced8 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2088,7 +2088,7 @@ u32 hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, } /* Entry not in the cache. Add new one. */ - ie = kzalloc(sizeof(struct inquiry_entry), GFP_KERNEL); + ie = kzalloc(sizeof(*ie), GFP_KERNEL); if (!ie) { flags |= MGMT_DEV_FOUND_CONFIRM_NAME; goto done; @@ -3492,7 +3492,7 @@ int hci_bdaddr_list_add(struct list_head *list, bdaddr_t *bdaddr, u8 type) if (hci_bdaddr_list_lookup(list, bdaddr, type)) return -EEXIST; - entry = kzalloc(sizeof(struct bdaddr_list), GFP_KERNEL); + entry = kzalloc(sizeof(*entry), GFP_KERNEL); if (!entry) return -ENOMEM; @@ -3897,7 +3897,7 @@ struct hci_dev *hci_alloc_dev(void) { struct hci_dev *hdev; - hdev = kzalloc(sizeof(struct hci_dev), GFP_KERNEL); + hdev = kzalloc(sizeof(*hdev), GFP_KERNEL); if (!hdev) return NULL; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index f3fb61c9f96f..46547b920f88 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -6985,7 +6985,7 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon) if (!hchan) return NULL; - conn = kzalloc(sizeof(struct l2cap_conn), GFP_KERNEL); + conn = kzalloc(sizeof(*conn), GFP_KERNEL); if (!conn) { hci_chan_del(hchan); return NULL; -- cgit v1.2.3