From 903e45411099ae8292f5ce637ad0c72f6fef61db Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Thu, 27 Sep 2012 17:26:09 +0300 Subject: Bluetooth: AMP: Use HCI cmd to Read Loc AMP Assoc When receiving A2MP Get AMP Assoc Request execute Read Local AMP Assoc HCI command to AMP controller. If the AMP Assoc data is larger than it can fit to HCI event only fragment is read. When all fragments are read send A2MP Get AMP Assoc Response. Signed-off-by: Andrei Emeltchenko Signed-off-by: Gustavo Padovan --- net/bluetooth/amp.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 net/bluetooth/amp.c (limited to 'net/bluetooth/amp.c') diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c new file mode 100644 index 000000000000..2d4e79ee06a5 --- /dev/null +++ b/net/bluetooth/amp.c @@ -0,0 +1,45 @@ +/* + Copyright (c) 2011,2012 Intel Corp. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 and + only 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. +*/ + +#include +#include +#include +#include +#include + +void amp_read_loc_assoc_frag(struct hci_dev *hdev, u8 phy_handle) +{ + struct hci_cp_read_local_amp_assoc cp; + struct amp_assoc *loc_assoc = &hdev->loc_assoc; + + BT_DBG("%s handle %d", hdev->name, phy_handle); + + cp.phy_handle = phy_handle; + cp.max_len = cpu_to_le16(hdev->amp_assoc_size); + cp.len_so_far = cpu_to_le16(loc_assoc->offset); + + hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp); +} + +void amp_read_loc_assoc(struct hci_dev *hdev, struct amp_mgr *mgr) +{ + struct hci_cp_read_local_amp_assoc cp; + + memset(&hdev->loc_assoc, 0, sizeof(struct amp_assoc)); + memset(&cp, 0, sizeof(cp)); + + cp.max_len = cpu_to_le16(hdev->amp_assoc_size); + + mgr->state = READ_LOC_AMP_ASSOC; + hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp); +} -- cgit v1.2.3 From 3161ae1c72f03b021bc67504c13025626c26d30c Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Thu, 27 Sep 2012 17:26:11 +0300 Subject: Bluetooth: AMP: Physical link struct and helpers Define physical link structures. Physical links are represented by hci_conn structure. For BR/EDR we use type ACL_LINK and for AMP we use AMP_LINK. Signed-off-by: Andrei Emeltchenko Signed-off-by: Gustavo Padovan --- include/net/bluetooth/amp.h | 3 +++ include/net/bluetooth/hci.h | 1 + include/net/bluetooth/hci_core.h | 1 + net/bluetooth/amp.c | 29 +++++++++++++++++++++++++++++ 4 files changed, 34 insertions(+) (limited to 'net/bluetooth/amp.c') diff --git a/include/net/bluetooth/amp.h b/include/net/bluetooth/amp.h index e8616751bc81..3414dfdc404c 100644 --- a/include/net/bluetooth/amp.h +++ b/include/net/bluetooth/amp.h @@ -14,6 +14,9 @@ #ifndef __AMP_H #define __AMP_H +struct hci_conn *phylink_add(struct hci_dev *hdev, struct amp_mgr *mgr, + u8 remote_id); + void amp_read_loc_info(struct hci_dev *hdev, struct amp_mgr *mgr); void amp_read_loc_assoc_frag(struct hci_dev *hdev, u8 phy_handle); void amp_read_loc_assoc(struct hci_dev *hdev, struct amp_mgr *mgr); diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index ccc08e57c107..77b6a197a6f6 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -207,6 +207,7 @@ enum { #define ESCO_LINK 0x02 /* Low Energy links do not have defined link type. Use invented one */ #define LE_LINK 0x80 +#define AMP_LINK 0x81 /* LMP features */ #define LMP_3SLOT 0x01 diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index b1c7d0607244..464eae340419 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -318,6 +318,7 @@ struct hci_conn { __u8 remote_cap; __u8 remote_auth; + __u8 remote_id; bool flush_key; unsigned int sent; diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c index 2d4e79ee06a5..50a7b2fb8bf3 100644 --- a/net/bluetooth/amp.c +++ b/net/bluetooth/amp.c @@ -17,6 +17,35 @@ #include #include +/* Physical Link interface */ +static u8 __next_handle(struct amp_mgr *mgr) +{ + if (++mgr->handle == 0) + mgr->handle = 1; + + return mgr->handle; +} + +struct hci_conn *phylink_add(struct hci_dev *hdev, struct amp_mgr *mgr, + u8 remote_id) +{ + bdaddr_t *dst = mgr->l2cap_conn->dst; + struct hci_conn *hcon; + + hcon = hci_conn_add(hdev, AMP_LINK, dst); + if (!hcon) + return NULL; + + hcon->state = BT_CONNECT; + hcon->out = true; + hcon->attempt++; + hcon->handle = __next_handle(mgr); + hcon->remote_id = remote_id; + hcon->amp_mgr = mgr; + + return hcon; +} + void amp_read_loc_assoc_frag(struct hci_dev *hdev, u8 phy_handle) { struct hci_cp_read_local_amp_assoc cp; -- cgit v1.2.3 From 52c0d6e56b634b195e377192182391d526cdd5e4 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Thu, 27 Sep 2012 17:26:12 +0300 Subject: Bluetooth: AMP: Remote AMP ctrl definitions Create remote AMP controllers structure. It is used to keep information about discovered remote AMP controllers by A2MP protocol. Signed-off-by: Andrei Emeltchenko Signed-off-by: Gustavo Padovan --- include/net/bluetooth/a2mp.h | 3 ++ include/net/bluetooth/amp.h | 15 +++++++++ net/bluetooth/a2mp.c | 5 +++ net/bluetooth/amp.c | 79 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 102 insertions(+) (limited to 'net/bluetooth/amp.c') diff --git a/include/net/bluetooth/a2mp.h b/include/net/bluetooth/a2mp.h index d5476719fa4c..99c7389b9189 100644 --- a/include/net/bluetooth/a2mp.h +++ b/include/net/bluetooth/a2mp.h @@ -33,6 +33,9 @@ struct amp_mgr { __u8 handle; enum amp_mgr_state state; unsigned long flags; + + struct list_head amp_ctrls; + struct mutex amp_ctrls_lock; }; struct a2mp_cmd { diff --git a/include/net/bluetooth/amp.h b/include/net/bluetooth/amp.h index 3414dfdc404c..f57854f0786d 100644 --- a/include/net/bluetooth/amp.h +++ b/include/net/bluetooth/amp.h @@ -14,6 +14,21 @@ #ifndef __AMP_H #define __AMP_H +struct amp_ctrl { + struct list_head list; + struct kref kref; + __u8 id; + __u16 assoc_len_so_far; + __u16 assoc_rem_len; + __u16 assoc_len; + __u8 *assoc; +}; + +int amp_ctrl_put(struct amp_ctrl *ctrl); +struct amp_ctrl *amp_ctrl_add(struct amp_mgr *mgr); +struct amp_ctrl *amp_ctrl_lookup(struct amp_mgr *mgr, u8 id); +void amp_ctrl_list_flush(struct amp_mgr *mgr); + struct hci_conn *phylink_add(struct hci_dev *hdev, struct amp_mgr *mgr, u8 remote_id); diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c index f04c44146663..35e188c7a441 100644 --- a/net/bluetooth/a2mp.c +++ b/net/bluetooth/a2mp.c @@ -594,6 +594,7 @@ static void amp_mgr_destroy(struct kref *kref) list_del(&mgr->list); mutex_unlock(&_mgr_list_lock); + amp_ctrl_list_flush(mgr); kfree(mgr); } @@ -630,6 +631,10 @@ static struct amp_mgr *amp_mgr_create(struct l2cap_conn *conn) kref_init(&mgr->kref); + /* Remote AMP ctrl list initialization */ + INIT_LIST_HEAD(&mgr->amp_ctrls); + mutex_init(&mgr->amp_ctrls_lock); + mutex_lock(&_mgr_list_lock); list_add(&mgr->list, &_mgr_list); mutex_unlock(&_mgr_list_lock); diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c index 50a7b2fb8bf3..8ef912c36224 100644 --- a/net/bluetooth/amp.c +++ b/net/bluetooth/amp.c @@ -17,6 +17,85 @@ #include #include +/* Remote AMP Controllers interface */ +static void amp_ctrl_get(struct amp_ctrl *ctrl) +{ + BT_DBG("ctrl %p orig refcnt %d", ctrl, + atomic_read(&ctrl->kref.refcount)); + + kref_get(&ctrl->kref); +} + +static void amp_ctrl_destroy(struct kref *kref) +{ + struct amp_ctrl *ctrl = container_of(kref, struct amp_ctrl, kref); + + BT_DBG("ctrl %p", ctrl); + + kfree(ctrl->assoc); + kfree(ctrl); +} + +int amp_ctrl_put(struct amp_ctrl *ctrl) +{ + BT_DBG("ctrl %p orig refcnt %d", ctrl, + atomic_read(&ctrl->kref.refcount)); + + return kref_put(&ctrl->kref, &_ctrl_destroy); +} + +struct amp_ctrl *amp_ctrl_add(struct amp_mgr *mgr) +{ + struct amp_ctrl *ctrl; + + ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); + if (!ctrl) + return NULL; + + mutex_lock(&mgr->amp_ctrls_lock); + list_add(&ctrl->list, &mgr->amp_ctrls); + mutex_unlock(&mgr->amp_ctrls_lock); + + kref_init(&ctrl->kref); + + BT_DBG("mgr %p ctrl %p", mgr, ctrl); + + return ctrl; +} + +void amp_ctrl_list_flush(struct amp_mgr *mgr) +{ + struct amp_ctrl *ctrl, *n; + + BT_DBG("mgr %p", mgr); + + mutex_lock(&mgr->amp_ctrls_lock); + list_for_each_entry_safe(ctrl, n, &mgr->amp_ctrls, list) { + list_del(&ctrl->list); + amp_ctrl_put(ctrl); + } + mutex_unlock(&mgr->amp_ctrls_lock); +} + +struct amp_ctrl *amp_ctrl_lookup(struct amp_mgr *mgr, u8 id) +{ + struct amp_ctrl *ctrl; + + BT_DBG("mgr %p id %d", mgr, id); + + mutex_lock(&mgr->amp_ctrls_lock); + list_for_each_entry(ctrl, &mgr->amp_ctrls, list) { + if (ctrl->id == id) { + amp_ctrl_get(ctrl); + mutex_unlock(&mgr->amp_ctrls_lock); + return ctrl; + } + } + mutex_unlock(&mgr->amp_ctrls_lock); + + return NULL; +} + /* Physical Link interface */ static u8 __next_handle(struct amp_mgr *mgr) { -- cgit v1.2.3 From ba221bbabadd5fc2c80677b52178138fd694cc26 Mon Sep 17 00:00:00 2001 From: Dmitry Kasatkin Date: Thu, 27 Sep 2012 17:26:17 +0300 Subject: Bluetooth: Add function to derive AMP key using hmac hmac(sha256) will be used for AMP key generation. Signed-off-by: Dmitry Kasatkin Signed-off-by: Andrei Emeltchenko Signed-off-by: Gustavo Padovan --- net/bluetooth/amp.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'net/bluetooth/amp.c') diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c index 8ef912c36224..ea4d5ffc1151 100644 --- a/net/bluetooth/amp.c +++ b/net/bluetooth/amp.c @@ -16,6 +16,7 @@ #include #include #include +#include /* Remote AMP Controllers interface */ static void amp_ctrl_get(struct amp_ctrl *ctrl) @@ -125,6 +126,41 @@ struct hci_conn *phylink_add(struct hci_dev *hdev, struct amp_mgr *mgr, return hcon; } +/* 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; + + if (!ksize) + return -EINVAL; + + tfm = crypto_alloc_shash("hmac(sha256)", 0, 0); + if (IS_ERR(tfm)) { + BT_DBG("crypto_alloc_ahash failed: err %ld", PTR_ERR(tfm)); + return PTR_ERR(tfm); + } + + ret = crypto_shash_setkey(tfm, key, ksize); + if (ret) { + BT_DBG("crypto_ahash_setkey failed: err %d", ret); + } else { + struct { + struct shash_desc shash; + char ctx[crypto_shash_descsize(tfm)]; + } desc; + + desc.shash.tfm = tfm; + desc.shash.flags = CRYPTO_TFM_REQ_MAY_SLEEP; + + ret = crypto_shash_digest(&desc.shash, plaintext, psize, + output); + } + + crypto_free_shash(tfm); + return ret; +} + void amp_read_loc_assoc_frag(struct hci_dev *hdev, u8 phy_handle) { struct hci_cp_read_local_amp_assoc cp; -- cgit v1.2.3 From 5a349186692950b13896abc3fb2f491d023f95a1 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Thu, 27 Sep 2012 17:26:18 +0300 Subject: Bluetooth: AMP: Add AMP key calculation Function calculates AMP keys using hmac_sha256 helper. Calculated keys are Generic AMP Link Key (gamp) and Dedicated AMP Link Key with keyID "802b" for 802.11 PAL. Signed-off-by: Andrei Emeltchenko Signed-off-by: Gustavo Padovan --- include/net/bluetooth/amp.h | 2 ++ net/bluetooth/Kconfig | 1 + net/bluetooth/amp.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+) (limited to 'net/bluetooth/amp.c') diff --git a/include/net/bluetooth/amp.h b/include/net/bluetooth/amp.h index f57854f0786d..763b4635c304 100644 --- a/include/net/bluetooth/amp.h +++ b/include/net/bluetooth/amp.h @@ -32,6 +32,8 @@ void amp_ctrl_list_flush(struct amp_mgr *mgr); struct hci_conn *phylink_add(struct hci_dev *hdev, struct amp_mgr *mgr, u8 remote_id); +int phylink_gen_key(struct hci_conn *hcon, u8 *data, u8 *len, u8 *type); + void amp_read_loc_info(struct hci_dev *hdev, struct amp_mgr *mgr); void amp_read_loc_assoc_frag(struct hci_dev *hdev, u8 phy_handle); void amp_read_loc_assoc(struct hci_dev *hdev, struct amp_mgr *mgr); diff --git a/net/bluetooth/Kconfig b/net/bluetooth/Kconfig index 3537d385035e..1c11d0dcd863 100644 --- a/net/bluetooth/Kconfig +++ b/net/bluetooth/Kconfig @@ -11,6 +11,7 @@ menuconfig BT select CRYPTO_BLKCIPHER select CRYPTO_AES select CRYPTO_ECB + select CRYPTO_SHA256 help Bluetooth is low-cost, low-power, short-range wireless technology. It was designed as a replacement for cables and other short-range diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c index ea4d5ffc1151..67bc2c2f8783 100644 --- a/net/bluetooth/amp.c +++ b/net/bluetooth/amp.c @@ -161,6 +161,51 @@ static int hmac_sha256(u8 *key, u8 ksize, char *plaintext, u8 psize, u8 *output) return ret; } +int phylink_gen_key(struct hci_conn *conn, u8 *data, u8 *len, u8 *type) +{ + struct hci_dev *hdev = conn->hdev; + struct link_key *key; + u8 keybuf[HCI_AMP_LINK_KEY_SIZE]; + u8 gamp_key[HCI_AMP_LINK_KEY_SIZE]; + int err; + + if (!hci_conn_check_link_mode(conn)) + return -EACCES; + + BT_DBG("conn %p key_type %d", conn, conn->key_type); + + /* Legacy key */ + if (conn->key_type < 3) { + BT_ERR("Legacy key type %d", conn->key_type); + return -EACCES; + } + + *type = conn->key_type; + *len = HCI_AMP_LINK_KEY_SIZE; + + key = hci_find_link_key(hdev, &conn->dst); + + /* BR/EDR Link Key concatenated together with itself */ + memcpy(&keybuf[0], key->val, HCI_LINK_KEY_SIZE); + memcpy(&keybuf[HCI_LINK_KEY_SIZE], key->val, HCI_LINK_KEY_SIZE); + + /* Derive Generic AMP Link Key (gamp) */ + err = hmac_sha256(keybuf, HCI_AMP_LINK_KEY_SIZE, "gamp", 4, gamp_key); + if (err) { + BT_ERR("Could not derive Generic AMP Key: err %d", err); + return err; + } + + if (conn->key_type == HCI_LK_DEBUG_COMBINATION) { + BT_DBG("Use Generic AMP Key (gamp)"); + memcpy(data, gamp_key, HCI_AMP_LINK_KEY_SIZE); + return err; + } + + /* Derive Dedicated AMP Link Key: "802b" is 802.11 PAL keyID */ + return hmac_sha256(gamp_key, HCI_AMP_LINK_KEY_SIZE, "802b", 4, data); +} + void amp_read_loc_assoc_frag(struct hci_dev *hdev, u8 phy_handle) { struct hci_cp_read_local_amp_assoc cp; -- cgit v1.2.3 From a02226d6ff5098e6b97590cc55aabe7faf0860ed Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Thu, 27 Sep 2012 17:26:19 +0300 Subject: Bluetooth: AMP: Create Physical Link When receiving A2MP Get AMP Assoc Response execute HCI Create Physical Link to AMP controller. Define function which will run when receiving HCI Command Status. Signed-off-by: Andrei Emeltchenko Signed-off-by: Gustavo Padovan --- include/net/bluetooth/amp.h | 2 ++ net/bluetooth/a2mp.c | 2 ++ net/bluetooth/amp.c | 19 +++++++++++++++++++ net/bluetooth/hci_event.c | 9 +++++++++ 4 files changed, 32 insertions(+) (limited to 'net/bluetooth/amp.c') diff --git a/include/net/bluetooth/amp.h b/include/net/bluetooth/amp.h index 763b4635c304..cadb3d032856 100644 --- a/include/net/bluetooth/amp.h +++ b/include/net/bluetooth/amp.h @@ -37,5 +37,7 @@ int phylink_gen_key(struct hci_conn *hcon, u8 *data, u8 *len, u8 *type); void amp_read_loc_info(struct hci_dev *hdev, struct amp_mgr *mgr); void amp_read_loc_assoc_frag(struct hci_dev *hdev, u8 phy_handle); void amp_read_loc_assoc(struct hci_dev *hdev, struct amp_mgr *mgr); +void amp_create_phylink(struct hci_dev *hdev, struct amp_mgr *mgr, + struct hci_conn *hcon); #endif /* __AMP_H */ diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c index 93adaad782ed..773e8fc41670 100644 --- a/net/bluetooth/a2mp.c +++ b/net/bluetooth/a2mp.c @@ -392,6 +392,8 @@ static int a2mp_getampassoc_rsp(struct amp_mgr *mgr, struct sk_buff *skb, BT_DBG("Created hcon %p: loc:%d -> rem:%d", hcon, hdev->id, rsp->id); + amp_create_phylink(hdev, mgr, hcon); + done: hci_dev_put(hdev); skb_pull(skb, len); diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c index 67bc2c2f8783..657ec736bbc6 100644 --- a/net/bluetooth/amp.c +++ b/net/bluetooth/amp.c @@ -232,3 +232,22 @@ void amp_read_loc_assoc(struct hci_dev *hdev, struct amp_mgr *mgr) mgr->state = READ_LOC_AMP_ASSOC; hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp); } + +void amp_create_phylink(struct hci_dev *hdev, struct amp_mgr *mgr, + struct hci_conn *hcon) +{ + struct hci_cp_create_phy_link cp; + + cp.phy_handle = hcon->handle; + + BT_DBG("%s hcon %p phy handle 0x%2.2x", hdev->name, hcon, + hcon->handle); + + if (phylink_gen_key(mgr->l2cap_conn->hcon, cp.key, &cp.key_len, + &cp.key_type)) { + BT_DBG("Cannot create link key"); + return; + } + + hci_send_cmd(hdev, HCI_OP_CREATE_PHY_LINK, sizeof(cp), &cp); +} diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index a4240f7a142e..bd06ef95693d 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1698,6 +1698,11 @@ static void hci_cs_le_start_enc(struct hci_dev *hdev, u8 status) BT_DBG("%s status 0x%2.2x", hdev->name, status); } +static void hci_cs_create_phylink(struct hci_dev *hdev, u8 status) +{ + BT_DBG("%s status 0x%2.2x", hdev->name, status); +} + static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) { __u8 status = *((__u8 *) skb->data); @@ -2512,6 +2517,10 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb) hci_cs_le_start_enc(hdev, ev->status); break; + case HCI_OP_CREATE_PHY_LINK: + hci_cs_create_phylink(hdev, ev->status); + break; + default: BT_DBG("%s opcode 0x%4.4x", hdev->name, opcode); break; -- cgit v1.2.3 From 93c284ee901f7d7bdd09087e92abefb7496c3777 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Thu, 27 Sep 2012 17:26:20 +0300 Subject: Bluetooth: AMP: Write remote AMP Assoc When receiving HCI Command Status after HCI Create Physical Link execute HCI Write Remote AMP Assoc command to AMP controller. Signed-off-by: Andrei Emeltchenko Signed-off-by: Gustavo Padovan --- include/net/bluetooth/amp.h | 2 + include/net/bluetooth/hci_core.h | 2 + net/bluetooth/amp.c | 80 ++++++++++++++++++++++++++++++++++++++++ net/bluetooth/hci_event.c | 29 +++++++++++++++ 4 files changed, 113 insertions(+) (limited to 'net/bluetooth/amp.c') diff --git a/include/net/bluetooth/amp.h b/include/net/bluetooth/amp.h index cadb3d032856..8f8032965eaf 100644 --- a/include/net/bluetooth/amp.h +++ b/include/net/bluetooth/amp.h @@ -39,5 +39,7 @@ void amp_read_loc_assoc_frag(struct hci_dev *hdev, u8 phy_handle); void amp_read_loc_assoc(struct hci_dev *hdev, struct amp_mgr *mgr); void amp_create_phylink(struct hci_dev *hdev, struct amp_mgr *mgr, struct hci_conn *hcon); +void amp_write_remote_assoc(struct hci_dev *hdev, u8 handle); +void amp_write_rem_assoc_continue(struct hci_dev *hdev, u8 handle); #endif /* __AMP_H */ diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 464eae340419..ea1f9340324d 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -127,6 +127,8 @@ struct le_scan_params { struct amp_assoc { __u16 len; __u16 offset; + __u16 rem_len; + __u16 len_so_far; __u8 data[HCI_MAX_AMP_ASSOC_SIZE]; }; diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c index 657ec736bbc6..5895ad0d2ac9 100644 --- a/net/bluetooth/amp.c +++ b/net/bluetooth/amp.c @@ -233,6 +233,86 @@ void amp_read_loc_assoc(struct hci_dev *hdev, struct amp_mgr *mgr) hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp); } + +/* Write AMP Assoc data fragments, returns true with last fragment written*/ +static bool amp_write_rem_assoc_frag(struct hci_dev *hdev, + struct hci_conn *hcon) +{ + struct hci_cp_write_remote_amp_assoc *cp; + struct amp_mgr *mgr = hcon->amp_mgr; + struct amp_ctrl *ctrl; + u16 frag_len, len; + + ctrl = amp_ctrl_lookup(mgr, hcon->remote_id); + if (!ctrl) + return false; + + if (!ctrl->assoc_rem_len) { + BT_DBG("all fragments are written"); + ctrl->assoc_rem_len = ctrl->assoc_len; + ctrl->assoc_len_so_far = 0; + + amp_ctrl_put(ctrl); + return true; + } + + frag_len = min_t(u16, 248, ctrl->assoc_rem_len); + len = frag_len + sizeof(*cp); + + cp = kzalloc(len, GFP_KERNEL); + if (!cp) { + amp_ctrl_put(ctrl); + return false; + } + + BT_DBG("hcon %p ctrl %p frag_len %u assoc_len %u rem_len %u", + hcon, ctrl, frag_len, ctrl->assoc_len, ctrl->assoc_rem_len); + + cp->phy_handle = hcon->handle; + cp->len_so_far = cpu_to_le16(ctrl->assoc_len_so_far); + cp->rem_len = cpu_to_le16(ctrl->assoc_rem_len); + memcpy(cp->frag, ctrl->assoc, frag_len); + + ctrl->assoc_len_so_far += frag_len; + ctrl->assoc_rem_len -= frag_len; + + amp_ctrl_put(ctrl); + + hci_send_cmd(hdev, HCI_OP_WRITE_REMOTE_AMP_ASSOC, len, cp); + + kfree(cp); + + return false; +} + +void amp_write_rem_assoc_continue(struct hci_dev *hdev, u8 handle) +{ + struct hci_conn *hcon; + + BT_DBG("%s phy handle 0x%2.2x", hdev->name, handle); + + hcon = hci_conn_hash_lookup_handle(hdev, handle); + if (!hcon) + return; + + amp_write_rem_assoc_frag(hdev, hcon); +} + +void amp_write_remote_assoc(struct hci_dev *hdev, u8 handle) +{ + struct hci_conn *hcon; + + BT_DBG("%s phy handle 0x%2.2x", hdev->name, handle); + + hcon = hci_conn_hash_lookup_handle(hdev, handle); + if (!hcon) + return; + + BT_DBG("%s phy handle 0x%2.2x hcon %p", hdev->name, handle, hcon); + + amp_write_rem_assoc_frag(hdev, hcon); +} + void amp_create_phylink(struct hci_dev *hdev, struct amp_mgr *mgr, struct hci_conn *hcon) { diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index bd06ef95693d..0b7ba1e39d45 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1215,6 +1215,20 @@ static void hci_cc_write_le_host_supported(struct hci_dev *hdev, hci_req_complete(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, status); } +static void hci_cc_write_remote_amp_assoc(struct hci_dev *hdev, + struct sk_buff *skb) +{ + struct hci_rp_write_remote_amp_assoc *rp = (void *) skb->data; + + BT_DBG("%s status 0x%2.2x phy_handle 0x%2.2x", + hdev->name, rp->status, rp->phy_handle); + + if (rp->status) + return; + + amp_write_rem_assoc_continue(hdev, rp->phy_handle); +} + static void hci_cs_inquiry(struct hci_dev *hdev, __u8 status) { BT_DBG("%s status 0x%2.2x", hdev->name, status); @@ -1700,7 +1714,18 @@ static void hci_cs_le_start_enc(struct hci_dev *hdev, u8 status) static void hci_cs_create_phylink(struct hci_dev *hdev, u8 status) { + struct hci_cp_create_phy_link *cp; + BT_DBG("%s status 0x%2.2x", hdev->name, status); + + if (status) + return; + + cp = hci_sent_cmd_data(hdev, HCI_OP_CREATE_PHY_LINK); + if (!cp) + return; + + amp_write_remote_assoc(hdev, cp->phy_handle); } static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) @@ -2436,6 +2461,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) hci_cc_write_le_host_supported(hdev, skb); break; + case HCI_OP_WRITE_REMOTE_AMP_ASSOC: + hci_cc_write_remote_amp_assoc(hdev, skb); + break; + default: BT_DBG("%s opcode 0x%4.4x", hdev->name, opcode); break; -- cgit v1.2.3 From 9495b2ee757f7747d7c28f9ba8d7edc53005ec2d Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Thu, 27 Sep 2012 17:26:22 +0300 Subject: Bluetooth: AMP: Process Chan Selected event Channel Selected event indicates that link information data is available. Read it with Read Local AMP Assoc command. The data shall be sent in the A2MP Create Physical Link Request. Signed-off-by: Andrei Emeltchenko Signed-off-by: Gustavo Padovan --- include/net/bluetooth/a2mp.h | 3 +++ include/net/bluetooth/amp.h | 2 ++ include/net/bluetooth/l2cap.h | 2 ++ net/bluetooth/a2mp.c | 41 ++++++++++++++++++++++++++++++++++++++++- net/bluetooth/amp.c | 15 +++++++++++++++ net/bluetooth/hci_event.c | 21 +++++++++++++++++++++ 6 files changed, 83 insertions(+), 1 deletion(-) (limited to 'net/bluetooth/amp.c') diff --git a/include/net/bluetooth/a2mp.h b/include/net/bluetooth/a2mp.h index 9fda7c94913f..e776ab2dc572 100644 --- a/include/net/bluetooth/a2mp.h +++ b/include/net/bluetooth/a2mp.h @@ -22,6 +22,7 @@ enum amp_mgr_state { READ_LOC_AMP_INFO, READ_LOC_AMP_ASSOC, + READ_LOC_AMP_ASSOC_FINAL, }; struct amp_mgr { @@ -134,6 +135,7 @@ extern struct mutex amp_mgr_list_lock; void amp_mgr_get(struct amp_mgr *mgr); int amp_mgr_put(struct amp_mgr *mgr); +u8 __next_ident(struct amp_mgr *mgr); struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn, struct sk_buff *skb); struct amp_mgr *amp_mgr_lookup_by_state(u8 state); @@ -141,5 +143,6 @@ void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len, void *data); void a2mp_discover_amp(struct l2cap_chan *chan); void a2mp_send_getinfo_rsp(struct hci_dev *hdev); void a2mp_send_getampassoc_rsp(struct hci_dev *hdev, u8 status); +void a2mp_send_create_phy_link_req(struct hci_dev *hdev, u8 status); #endif /* __A2MP_H */ diff --git a/include/net/bluetooth/amp.h b/include/net/bluetooth/amp.h index 8f8032965eaf..70496c07afaa 100644 --- a/include/net/bluetooth/amp.h +++ b/include/net/bluetooth/amp.h @@ -37,6 +37,8 @@ int phylink_gen_key(struct hci_conn *hcon, u8 *data, u8 *len, u8 *type); void amp_read_loc_info(struct hci_dev *hdev, struct amp_mgr *mgr); void amp_read_loc_assoc_frag(struct hci_dev *hdev, u8 phy_handle); void amp_read_loc_assoc(struct hci_dev *hdev, struct amp_mgr *mgr); +void amp_read_loc_assoc_final_data(struct hci_dev *hdev, + struct hci_conn *hcon); void amp_create_phylink(struct hci_dev *hdev, struct amp_mgr *mgr, struct hci_conn *hcon); void amp_write_remote_assoc(struct hci_dev *hdev, u8 handle); diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 0967f9e33750..ab58b81fb7c5 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -508,6 +508,8 @@ struct l2cap_chan { __u32 remote_acc_lat; __u32 remote_flush_to; + __u8 ctrl_id; + struct delayed_work chan_timer; struct delayed_work retrans_timer; struct delayed_work monitor_timer; diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c index 28d1246958be..375a67f501d0 100644 --- a/net/bluetooth/a2mp.c +++ b/net/bluetooth/a2mp.c @@ -67,7 +67,7 @@ void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len, void *data) kfree(cmd); } -static u8 __next_ident(struct amp_mgr *mgr) +u8 __next_ident(struct amp_mgr *mgr) { if (++mgr->ident == 0) mgr->ident = 1; @@ -420,6 +420,8 @@ static int a2mp_getampassoc_rsp(struct amp_mgr *mgr, struct sk_buff *skb, BT_DBG("Created hcon %p: loc:%d -> rem:%d", hcon, hdev->id, rsp->id); + mgr->bredr_chan->ctrl_id = rsp->id; + amp_create_phylink(hdev, mgr, hcon); done: @@ -876,6 +878,43 @@ void a2mp_send_getampassoc_rsp(struct hci_dev *hdev, u8 status) kfree(rsp); } +void a2mp_send_create_phy_link_req(struct hci_dev *hdev, u8 status) +{ + struct amp_mgr *mgr; + struct amp_assoc *loc_assoc = &hdev->loc_assoc; + struct a2mp_physlink_req *req; + struct l2cap_chan *bredr_chan; + size_t len; + + mgr = amp_mgr_lookup_by_state(READ_LOC_AMP_ASSOC_FINAL); + if (!mgr) + return; + + len = sizeof(*req) + loc_assoc->len; + + BT_DBG("%s mgr %p assoc_len %zu", hdev->name, mgr, len); + + req = kzalloc(len, GFP_KERNEL); + if (!req) { + amp_mgr_put(mgr); + return; + } + + bredr_chan = mgr->bredr_chan; + if (!bredr_chan) + goto clean; + + req->local_id = hdev->id; + req->remote_id = bredr_chan->ctrl_id; + memcpy(req->amp_assoc, loc_assoc->data, loc_assoc->len); + + a2mp_send(mgr, A2MP_CREATEPHYSLINK_REQ, __next_ident(mgr), len, req); + +clean: + amp_mgr_put(mgr); + kfree(req); +} + void a2mp_discover_amp(struct l2cap_chan *chan) { struct l2cap_conn *conn = chan->conn; diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c index 5895ad0d2ac9..4f7b2647d5e9 100644 --- a/net/bluetooth/amp.c +++ b/net/bluetooth/amp.c @@ -233,6 +233,21 @@ void amp_read_loc_assoc(struct hci_dev *hdev, struct amp_mgr *mgr) hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp); } +void amp_read_loc_assoc_final_data(struct hci_dev *hdev, + struct hci_conn *hcon) +{ + struct hci_cp_read_local_amp_assoc cp; + struct amp_mgr *mgr = hcon->amp_mgr; + + cp.phy_handle = hcon->handle; + cp.len_so_far = cpu_to_le16(0); + cp.max_len = cpu_to_le16(hdev->amp_assoc_size); + + mgr->state = READ_LOC_AMP_ASSOC_FINAL; + + /* Read Local AMP Assoc final link information data */ + hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp); +} /* Write AMP Assoc data fragments, returns true with last fragment written*/ static bool amp_write_rem_assoc_frag(struct hci_dev *hdev, diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 0b7ba1e39d45..d702ba1c171c 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -901,6 +901,7 @@ static void hci_cc_read_local_amp_assoc(struct hci_dev *hdev, a2mp_rsp: /* Send A2MP Rsp when all fragments are received */ a2mp_send_getampassoc_rsp(hdev, rp->status); + a2mp_send_create_phy_link_req(hdev, rp->status); } static void hci_cc_delete_stored_link_key(struct hci_dev *hdev, @@ -3641,6 +3642,22 @@ static void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb) } } +static void hci_chan_selected_evt(struct hci_dev *hdev, struct sk_buff *skb) +{ + struct hci_ev_channel_selected *ev = (void *) skb->data; + struct hci_conn *hcon; + + BT_DBG("%s handle 0x%2.2x", hdev->name, ev->phy_handle); + + skb_pull(skb, sizeof(*ev)); + + hcon = hci_conn_hash_lookup_handle(hdev, ev->phy_handle); + if (!hcon) + return; + + amp_read_loc_assoc_final_data(hdev, hcon); +} + void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_event_hdr *hdr = (void *) skb->data; @@ -3805,6 +3822,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) hci_le_meta_evt(hdev, skb); break; + case HCI_EV_CHANNEL_SELECTED: + hci_chan_selected_evt(hdev, skb); + break; + case HCI_EV_REMOTE_OOB_DATA_REQUEST: hci_remote_oob_data_request_evt(hdev, skb); break; -- cgit v1.2.3 From dffa387110025801862d7ad09f4e850d06ff55a9 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Thu, 27 Sep 2012 17:26:23 +0300 Subject: Bluetooth: AMP: Accept Physical Link When receiving A2MP Create Physical Link message execute HCI Accept Physical Link command to AMP controller. Signed-off-by: Andrei Emeltchenko Signed-off-by: Gustavo Padovan --- include/net/bluetooth/amp.h | 2 ++ net/bluetooth/a2mp.c | 5 +---- net/bluetooth/amp.c | 19 +++++++++++++++++++ 3 files changed, 22 insertions(+), 4 deletions(-) (limited to 'net/bluetooth/amp.c') diff --git a/include/net/bluetooth/amp.h b/include/net/bluetooth/amp.h index 70496c07afaa..1b06d7b01359 100644 --- a/include/net/bluetooth/amp.h +++ b/include/net/bluetooth/amp.h @@ -41,6 +41,8 @@ void amp_read_loc_assoc_final_data(struct hci_dev *hdev, struct hci_conn *hcon); void amp_create_phylink(struct hci_dev *hdev, struct amp_mgr *mgr, struct hci_conn *hcon); +void amp_accept_phylink(struct hci_dev *hdev, struct amp_mgr *mgr, + struct hci_conn *hcon); void amp_write_remote_assoc(struct hci_dev *hdev, u8 handle); void amp_write_rem_assoc_continue(struct hci_dev *hdev, u8 handle); diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c index 375a67f501d0..dbfdbbb9707c 100644 --- a/net/bluetooth/a2mp.c +++ b/net/bluetooth/a2mp.c @@ -453,12 +453,9 @@ static int a2mp_createphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb, goto send_rsp; } - /* TODO process physlink create */ - hcon = phylink_add(hdev, mgr, req->local_id); if (hcon) { - BT_DBG("hcon %p", hcon); - + amp_accept_phylink(hdev, mgr, hcon); rsp.status = A2MP_STATUS_SUCCESS; } else { rsp.status = A2MP_STATUS_UNABLE_START_LINK_CREATION; diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c index 4f7b2647d5e9..845e43073c40 100644 --- a/net/bluetooth/amp.c +++ b/net/bluetooth/amp.c @@ -346,3 +346,22 @@ void amp_create_phylink(struct hci_dev *hdev, struct amp_mgr *mgr, hci_send_cmd(hdev, HCI_OP_CREATE_PHY_LINK, sizeof(cp), &cp); } + +void amp_accept_phylink(struct hci_dev *hdev, struct amp_mgr *mgr, + struct hci_conn *hcon) +{ + struct hci_cp_accept_phy_link cp; + + cp.phy_handle = hcon->handle; + + BT_DBG("%s hcon %p phy handle 0x%2.2x", hdev->name, hcon, + hcon->handle); + + if (phylink_gen_key(mgr->l2cap_conn->hcon, cp.key, &cp.key_len, + &cp.key_type)) { + BT_DBG("Cannot create link key"); + return; + } + + hci_send_cmd(hdev, HCI_OP_ACCEPT_PHY_LINK, sizeof(cp), &cp); +} -- cgit v1.2.3 From 0b26ab9dce74f8ac77d7eef0d683ab1d527e45b1 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Thu, 27 Sep 2012 17:26:24 +0300 Subject: Bluetooth: AMP: Handle Accept phylink command status evt When receiving HCI Command Status event for Accept Physical Link execute HCI Write Remote AMP Assoc with data saved from A2MP Create Physical Link Request. Signed-off-by: Andrei Emeltchenko Signed-off-by: Gustavo Padovan --- include/net/bluetooth/amp.h | 1 + net/bluetooth/a2mp.c | 32 ++++++++++++++++++++++++++++++++ net/bluetooth/amp.c | 2 +- net/bluetooth/hci_event.c | 20 ++++++++++++++++++++ 4 files changed, 54 insertions(+), 1 deletion(-) (limited to 'net/bluetooth/amp.c') diff --git a/include/net/bluetooth/amp.h b/include/net/bluetooth/amp.h index 1b06d7b01359..b1e54903dd42 100644 --- a/include/net/bluetooth/amp.h +++ b/include/net/bluetooth/amp.h @@ -25,6 +25,7 @@ struct amp_ctrl { }; int amp_ctrl_put(struct amp_ctrl *ctrl); +void amp_ctrl_get(struct amp_ctrl *ctrl); struct amp_ctrl *amp_ctrl_add(struct amp_mgr *mgr); struct amp_ctrl *amp_ctrl_lookup(struct amp_mgr *mgr, u8 id); void amp_ctrl_list_flush(struct amp_mgr *mgr); diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c index dbfdbbb9707c..47565d28b27f 100644 --- a/net/bluetooth/a2mp.c +++ b/net/bluetooth/a2mp.c @@ -438,6 +438,7 @@ static int a2mp_createphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb, struct a2mp_physlink_rsp rsp; struct hci_dev *hdev; struct hci_conn *hcon; + struct amp_ctrl *ctrl; if (le16_to_cpu(hdr->len) < sizeof(*req)) return -EINVAL; @@ -453,6 +454,37 @@ static int a2mp_createphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb, goto send_rsp; } + ctrl = amp_ctrl_lookup(mgr, rsp.remote_id); + if (!ctrl) { + ctrl = amp_ctrl_add(mgr); + if (ctrl) { + amp_ctrl_get(ctrl); + } else { + rsp.status = A2MP_STATUS_UNABLE_START_LINK_CREATION; + goto send_rsp; + } + } + + if (ctrl) { + u8 *assoc, assoc_len = le16_to_cpu(hdr->len) - sizeof(*req); + + ctrl->id = rsp.remote_id; + + assoc = kzalloc(assoc_len, GFP_KERNEL); + if (!assoc) { + amp_ctrl_put(ctrl); + return -ENOMEM; + } + + memcpy(assoc, req->amp_assoc, assoc_len); + ctrl->assoc = assoc; + ctrl->assoc_len = assoc_len; + ctrl->assoc_rem_len = assoc_len; + ctrl->assoc_len_so_far = 0; + + amp_ctrl_put(ctrl); + } + hcon = phylink_add(hdev, mgr, req->local_id); if (hcon) { amp_accept_phylink(hdev, mgr, hcon); diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c index 845e43073c40..5dab2d1c7c82 100644 --- a/net/bluetooth/amp.c +++ b/net/bluetooth/amp.c @@ -19,7 +19,7 @@ #include /* Remote AMP Controllers interface */ -static void amp_ctrl_get(struct amp_ctrl *ctrl) +void amp_ctrl_get(struct amp_ctrl *ctrl) { BT_DBG("ctrl %p orig refcnt %d", ctrl, atomic_read(&ctrl->kref.refcount)); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index d702ba1c171c..7e716698fe64 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1729,6 +1729,22 @@ static void hci_cs_create_phylink(struct hci_dev *hdev, u8 status) amp_write_remote_assoc(hdev, cp->phy_handle); } +static void hci_cs_accept_phylink(struct hci_dev *hdev, u8 status) +{ + struct hci_cp_accept_phy_link *cp; + + BT_DBG("%s status 0x%2.2x", hdev->name, status); + + if (status) + return; + + cp = hci_sent_cmd_data(hdev, HCI_OP_ACCEPT_PHY_LINK); + if (!cp) + return; + + amp_write_remote_assoc(hdev, cp->phy_handle); +} + static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) { __u8 status = *((__u8 *) skb->data); @@ -2551,6 +2567,10 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb) hci_cs_create_phylink(hdev, ev->status); break; + case HCI_OP_ACCEPT_PHY_LINK: + hci_cs_accept_phylink(hdev, ev->status); + break; + default: BT_DBG("%s opcode 0x%4.4x", hdev->name, opcode); break; -- cgit v1.2.3 From 079db0c6e3854b3af9808268f3b884fa48ed0034 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Fri, 5 Oct 2012 16:56:53 +0300 Subject: Bluetooth: AMP: Fix possible NULL dereference Check that link key exist before accessing. Signed-off-by: Andrei Emeltchenko Signed-off-by: Gustavo Padovan --- net/bluetooth/amp.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'net/bluetooth/amp.c') diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c index 5dab2d1c7c82..b6e1c3ac74f1 100644 --- a/net/bluetooth/amp.c +++ b/net/bluetooth/amp.c @@ -184,6 +184,10 @@ int phylink_gen_key(struct hci_conn *conn, u8 *data, u8 *len, u8 *type) *len = HCI_AMP_LINK_KEY_SIZE; key = hci_find_link_key(hdev, &conn->dst); + if (!key) { + BT_DBG("No Link key for conn %p dst %pMR", conn, &conn->dst); + return -EACCES; + } /* BR/EDR Link Key concatenated together with itself */ memcpy(&keybuf[0], key->val, HCI_LINK_KEY_SIZE); -- cgit v1.2.3 From fa4ebc66c432d0e0ec947cb754d4144c4a681f28 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Fri, 5 Oct 2012 16:56:55 +0300 Subject: Bluetooth: AMP: Factor out amp_ctrl_add Add ctrl_id parameter to amp_ctrl_add since we always set it after function ctrl is created. Signed-off-by: Andrei Emeltchenko Signed-off-by: Gustavo Padovan --- include/net/bluetooth/amp.h | 2 +- net/bluetooth/a2mp.c | 8 ++------ net/bluetooth/amp.c | 7 ++++--- 3 files changed, 7 insertions(+), 10 deletions(-) (limited to 'net/bluetooth/amp.c') diff --git a/include/net/bluetooth/amp.h b/include/net/bluetooth/amp.h index b1e54903dd42..ae2c3e536473 100644 --- a/include/net/bluetooth/amp.h +++ b/include/net/bluetooth/amp.h @@ -26,7 +26,7 @@ struct amp_ctrl { int amp_ctrl_put(struct amp_ctrl *ctrl); void amp_ctrl_get(struct amp_ctrl *ctrl); -struct amp_ctrl *amp_ctrl_add(struct amp_mgr *mgr); +struct amp_ctrl *amp_ctrl_add(struct amp_mgr *mgr, u8 id); struct amp_ctrl *amp_ctrl_lookup(struct amp_mgr *mgr, u8 id); void amp_ctrl_list_flush(struct amp_mgr *mgr); diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c index d4946b591b71..88a4b583d218 100644 --- a/net/bluetooth/a2mp.c +++ b/net/bluetooth/a2mp.c @@ -316,12 +316,10 @@ static int a2mp_getinfo_rsp(struct amp_mgr *mgr, struct sk_buff *skb, if (rsp->status) return -EINVAL; - ctrl = amp_ctrl_add(mgr); + ctrl = amp_ctrl_add(mgr, rsp->id); if (!ctrl) return -ENOMEM; - ctrl->id = rsp->id; - req.id = rsp->id; a2mp_send(mgr, A2MP_GETAMPASSOC_REQ, __next_ident(mgr), sizeof(req), &req); @@ -461,7 +459,7 @@ static int a2mp_createphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb, ctrl = amp_ctrl_lookup(mgr, rsp.remote_id); if (!ctrl) { - ctrl = amp_ctrl_add(mgr); + ctrl = amp_ctrl_add(mgr, rsp.remote_id); if (ctrl) { amp_ctrl_get(ctrl); } else { @@ -474,8 +472,6 @@ static int a2mp_createphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb, size_t assoc_len = le16_to_cpu(hdr->len) - sizeof(*req); u8 *assoc; - ctrl->id = rsp.remote_id; - assoc = kzalloc(assoc_len, GFP_KERNEL); if (!assoc) { amp_ctrl_put(ctrl); diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c index b6e1c3ac74f1..2fc5562a84b9 100644 --- a/net/bluetooth/amp.c +++ b/net/bluetooth/amp.c @@ -45,7 +45,7 @@ int amp_ctrl_put(struct amp_ctrl *ctrl) return kref_put(&ctrl->kref, &_ctrl_destroy); } -struct amp_ctrl *amp_ctrl_add(struct amp_mgr *mgr) +struct amp_ctrl *amp_ctrl_add(struct amp_mgr *mgr, u8 id) { struct amp_ctrl *ctrl; @@ -53,12 +53,13 @@ struct amp_ctrl *amp_ctrl_add(struct amp_mgr *mgr) if (!ctrl) return NULL; + kref_init(&ctrl->kref); + ctrl->id = id; + mutex_lock(&mgr->amp_ctrls_lock); list_add(&ctrl->list, &mgr->amp_ctrls); mutex_unlock(&mgr->amp_ctrls_lock); - kref_init(&ctrl->kref); - BT_DBG("mgr %p ctrl %p", mgr, ctrl); return ctrl; -- cgit v1.2.3 From a0c234fe8972aa6a5afe2db6c27a3f5d5fbd88e7 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Fri, 5 Oct 2012 16:56:56 +0300 Subject: Bluetooth: AMP: Factor out phylink_add Add direction parameter to phylink_add since it is anyway set later. Signed-off-by: Andrei Emeltchenko Signed-off-by: Gustavo Padovan --- include/net/bluetooth/amp.h | 2 +- net/bluetooth/a2mp.c | 4 ++-- net/bluetooth/amp.c | 6 ++++-- 3 files changed, 7 insertions(+), 5 deletions(-) (limited to 'net/bluetooth/amp.c') diff --git a/include/net/bluetooth/amp.h b/include/net/bluetooth/amp.h index ae2c3e536473..2e7c79ea0463 100644 --- a/include/net/bluetooth/amp.h +++ b/include/net/bluetooth/amp.h @@ -31,7 +31,7 @@ struct amp_ctrl *amp_ctrl_lookup(struct amp_mgr *mgr, u8 id); void amp_ctrl_list_flush(struct amp_mgr *mgr); struct hci_conn *phylink_add(struct hci_dev *hdev, struct amp_mgr *mgr, - u8 remote_id); + u8 remote_id, bool out); int phylink_gen_key(struct hci_conn *hcon, u8 *data, u8 *len, u8 *type); diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c index 88a4b583d218..3ff4dc928bf5 100644 --- a/net/bluetooth/a2mp.c +++ b/net/bluetooth/a2mp.c @@ -417,7 +417,7 @@ static int a2mp_getampassoc_rsp(struct amp_mgr *mgr, struct sk_buff *skb, if (!hdev) return -EINVAL; - hcon = phylink_add(hdev, mgr, rsp->id); + hcon = phylink_add(hdev, mgr, rsp->id, true); if (!hcon) goto done; @@ -487,7 +487,7 @@ static int a2mp_createphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb, amp_ctrl_put(ctrl); } - hcon = phylink_add(hdev, mgr, req->local_id); + hcon = phylink_add(hdev, mgr, req->local_id, false); if (hcon) { amp_accept_phylink(hdev, mgr, hcon); rsp.status = A2MP_STATUS_SUCCESS; diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c index 2fc5562a84b9..59da0f15818e 100644 --- a/net/bluetooth/amp.c +++ b/net/bluetooth/amp.c @@ -108,7 +108,7 @@ static u8 __next_handle(struct amp_mgr *mgr) } struct hci_conn *phylink_add(struct hci_dev *hdev, struct amp_mgr *mgr, - u8 remote_id) + u8 remote_id, bool out) { bdaddr_t *dst = mgr->l2cap_conn->dst; struct hci_conn *hcon; @@ -117,12 +117,14 @@ struct hci_conn *phylink_add(struct hci_dev *hdev, struct amp_mgr *mgr, if (!hcon) return NULL; + BT_DBG("hcon %p dst %pMR", hcon, dst); + hcon->state = BT_CONNECT; - hcon->out = true; hcon->attempt++; hcon->handle = __next_handle(mgr); hcon->remote_id = remote_id; hcon->amp_mgr = mgr; + hcon->out = out; return hcon; } -- cgit v1.2.3 From f706adfeade767d2194c9f39c0f75e944b0bdd23 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Thu, 18 Oct 2012 13:16:19 +0300 Subject: Bluetooth: AMP: Get amp_mgr reference in HS hci_conn When assigning amp_mgr in hci_conn (type AMP_LINK) get also reference. In hci_conn_del those references would be put for both conn types AMP_LINK and ACL_LINK associated with amp_mgr. Signed-off-by: Andrei Emeltchenko Signed-off-by: Gustavo Padovan --- include/net/bluetooth/a2mp.h | 2 +- net/bluetooth/a2mp.c | 4 +++- net/bluetooth/amp.c | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) (limited to 'net/bluetooth/amp.c') diff --git a/include/net/bluetooth/a2mp.h b/include/net/bluetooth/a2mp.h index e776ab2dc572..42f21766c538 100644 --- a/include/net/bluetooth/a2mp.h +++ b/include/net/bluetooth/a2mp.h @@ -133,7 +133,7 @@ struct a2mp_physlink_rsp { extern struct list_head amp_mgr_list; extern struct mutex amp_mgr_list_lock; -void amp_mgr_get(struct amp_mgr *mgr); +struct amp_mgr *amp_mgr_get(struct amp_mgr *mgr); int amp_mgr_put(struct amp_mgr *mgr); u8 __next_ident(struct amp_mgr *mgr); struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn, diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c index 7bf9a10d8e46..d5136cfb57e2 100644 --- a/net/bluetooth/a2mp.c +++ b/net/bluetooth/a2mp.c @@ -751,11 +751,13 @@ static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn, bool locked) } /* AMP Manager functions */ -void amp_mgr_get(struct amp_mgr *mgr) +struct amp_mgr *amp_mgr_get(struct amp_mgr *mgr) { BT_DBG("mgr %p orig refcnt %d", mgr, atomic_read(&mgr->kref.refcount)); kref_get(&mgr->kref); + + return mgr; } static void amp_mgr_destroy(struct kref *kref) diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c index 59da0f15818e..231d7ef53ecb 100644 --- a/net/bluetooth/amp.c +++ b/net/bluetooth/amp.c @@ -123,7 +123,7 @@ struct hci_conn *phylink_add(struct hci_dev *hdev, struct amp_mgr *mgr, hcon->attempt++; hcon->handle = __next_handle(mgr); hcon->remote_id = remote_id; - hcon->amp_mgr = mgr; + hcon->amp_mgr = amp_mgr_get(mgr); hcon->out = out; return hcon; -- cgit v1.2.3