diff options
author | Lukasz Rymanowski <lukasz.rymanowski@tieto.com> | 2011-01-14 14:57:38 +0100 |
---|---|---|
committer | Jonas ABERG <jonas.aberg@stericsson.com> | 2011-01-20 08:20:47 +0100 |
commit | 5df03c41fa498d433fa9aa6acc1a706c2d28484c (patch) | |
tree | 978e442acd2b935a6b54e36df436de6477e93fb8 /net | |
parent | 3531c7b2a4c1ed08814099133b40833ebb5bf71b (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.c | 46 |
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; |