summaryrefslogtreecommitdiff
path: root/net/bluetooth
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@intel.com>2013-12-10 12:52:48 +0400
committerMarcel Holtmann <marcel@holtmann.org>2013-12-10 13:15:44 +0400
commit71fb419724fadab4efdf98210aa3fe053bd81d29 (patch)
treebea18a28f16b8e66904ab4a1b1108c00e7f2044c /net/bluetooth
parent53b834d2333aec1e60fcbfadfddd4ad472329570 (diff)
downloadlinux-71fb419724fadab4efdf98210aa3fe053bd81d29.tar.xz
Bluetooth: Fix handling of L2CAP Command Reject over LE
If we receive an L2CAP command reject message over LE we should take appropriate action on the corresponding channel. This is particularly important when trying to interact with a remote pre-4.1 system using LE CoC signaling messages. If we don't react to the command reject the corresponding socket would not be notified until a connection timeout occurs. Signed-off-by: Johan Hedberg <johan.hedberg@intel.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/bluetooth')
-rw-r--r--net/bluetooth/l2cap_core.c26
1 files changed, 26 insertions, 0 deletions
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index ae0054ccee5b..b6bca64b320d 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -5736,6 +5736,31 @@ static inline int l2cap_le_credits(struct l2cap_conn *conn,
return 0;
}
+static inline int l2cap_le_command_rej(struct l2cap_conn *conn,
+ struct l2cap_cmd_hdr *cmd, u16 cmd_len,
+ u8 *data)
+{
+ struct l2cap_cmd_rej_unk *rej = (struct l2cap_cmd_rej_unk *) data;
+ struct l2cap_chan *chan;
+
+ if (cmd_len < sizeof(*rej))
+ return -EPROTO;
+
+ mutex_lock(&conn->chan_lock);
+
+ chan = __l2cap_get_chan_by_ident(conn, cmd->ident);
+ if (!chan)
+ goto done;
+
+ l2cap_chan_lock(chan);
+ l2cap_chan_del(chan, ECONNREFUSED);
+ l2cap_chan_unlock(chan);
+
+done:
+ mutex_unlock(&conn->chan_lock);
+ return 0;
+}
+
static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn,
struct l2cap_cmd_hdr *cmd, u16 cmd_len,
u8 *data)
@@ -5755,6 +5780,7 @@ static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn,
switch (cmd->code) {
case L2CAP_COMMAND_REJ:
+ l2cap_le_command_rej(conn, cmd, cmd_len, data);
break;
case L2CAP_CONN_PARAM_UPDATE_REQ: