aboutsummaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorLukasz Rymanowski <lukasz.rymanowski@tieto.com>2011-01-14 14:57:38 +0100
committerJonas ABERG <jonas.aberg@stericsson.com>2011-01-20 08:20:47 +0100
commit5df03c41fa498d433fa9aa6acc1a706c2d28484c (patch)
tree978e442acd2b935a6b54e36df436de6477e93fb8 /net
parent3531c7b2a4c1ed08814099133b40833ebb5bf71b (diff)
bluetooth: Fix for security block issue.
It can happen that controller will schedule, ACL data containing L2CAP connect request to host just before encryption change event, even though link is encrypted on LMP level before L2CAP conntect request come. With this fix, L2CAP layer will handle such scenario. ST-Ericsson Linux next: Not tested, ER320222 ST-Ericsson ID: ER319123 ST-Ericsson FOSS-OUT ID: Trivial Change-Id: If436237b65b135df3ec351f9b59f9a8678a4f0db Signed-off-by: Lukasz Rymanowski <lukasz.rymanowski@tieto.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/12526 Reviewed-by: Lukasz RYMANOWSKI <lukasz.rymanowski@stericsson.com> Tested-by: Lukasz RYMANOWSKI <lukasz.rymanowski@stericsson.com> Reviewed-by: QATOOLS Reviewed-by: Par-Gunnar HJALMDAHL <par-gunnar.p.hjalmdahl@stericsson.com>
Diffstat (limited to 'net')
-rw-r--r--net/bluetooth/l2cap.c46
1 files changed, 46 insertions, 0 deletions
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index c2f6bb2f78d..443460012d0 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -55,6 +55,7 @@
#define VERSION "2.14"
+#define ENCRYPT_TIMEOUT (20) /* 20 ms */
#ifdef CONFIG_BT_L2CAP_EXT_FEATURES
static int enable_ertm = 1;
#else
@@ -79,6 +80,7 @@ static void l2cap_busy_work(struct work_struct *work);
static void __l2cap_sock_close(struct sock *sk, int reason);
static void l2cap_sock_close(struct sock *sk);
static void l2cap_sock_kill(struct sock *sk);
+static void l2cap_encrypt_timeout(unsigned long arg);
static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
u8 code, u8 ident, u16 dlen, void *data);
@@ -603,6 +605,8 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
setup_timer(&conn->info_timer, l2cap_info_timeout,
(unsigned long) conn);
+ setup_timer(&conn->encrypt_timer, l2cap_encrypt_timeout,
+ (unsigned long) conn);
conn->disc_reason = 0x13;
return conn;
@@ -631,6 +635,11 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
del_timer_sync(&conn->info_timer);
+ if (conn->p_req)
+ del_timer_sync(&conn->encrypt_timer);
+
+ kfree(conn->p_req);
+
hcon->l2cap_data = NULL;
kfree(conn);
}
@@ -2816,6 +2825,28 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
/* Check if the ACL is secure enough (if not SDP) */
if (psm != cpu_to_le16(0x0001) &&
!hci_conn_check_link_mode(conn->hcon)) {
+ /* Let's give a chance to Encryption Change Evt.*/
+ if (!conn->p_req) {
+ conn->p_req = kzalloc(sizeof(*conn->p_req), GFP_KERNEL);
+ if (conn->p_req) {
+ BT_DBG("Create pending connection req %p.",
+ conn->p_req);
+
+ memcpy(&conn->p_req->cmd, cmd, sizeof(*cmd));
+ memcpy(&conn->p_req->conn_req, req,
+ sizeof(*req));
+
+ mod_timer(&conn->encrypt_timer, jiffies +
+ msecs_to_jiffies(ENCRYPT_TIMEOUT));
+
+ /*
+ * We will restart l2cap_conn_req in
+ * l2cap_encrypt_timeout.
+ */
+ bh_unlock_sock(parent);
+ return 0;
+ }
+ }
conn->disc_reason = 0x05;
result = L2CAP_CR_SEC_BLOCK;
goto response;
@@ -2960,6 +2991,21 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd
return 0;
}
+static void l2cap_encrypt_timeout(unsigned long arg)
+{
+ struct l2cap_conn *conn = (void *) arg;
+
+ BUG_ON(conn->p_req == NULL);
+
+ BT_DBG("conn %p, p_req %p", conn, conn->p_req);
+
+ (void)l2cap_connect_req(conn, &conn->p_req->cmd,
+ (u8 *)&conn->p_req->conn_req);
+
+ kfree(conn->p_req);
+ conn->p_req = NULL;
+}
+
static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data)
{
struct l2cap_conf_req *req = (struct l2cap_conf_req *) data;