diff options
author | Johan Hedberg <johan.hedberg@intel.com> | 2013-04-29 12:35:33 -0400 |
---|---|---|
committer | Gustavo Padovan <gustavo.padovan@collabora.co.uk> | 2013-06-22 19:23:47 -0400 |
commit | c5623556fc61804713b1569b4f748e36956bc6e8 (patch) | |
tree | 9324958d959cdbbccf9b801523871725292095e7 /net | |
parent | b887664d882ee4f6a67e0bf05e5f141d32fcc067 (diff) |
Bluetooth: Handle LE L2CAP signalling in its own function
The LE L2CAP signalling channel follows its own rules and will continue
to evolve independently from the BR/EDR signalling channel. Therefore,
it makes sense to have a clear split from BR/EDR by having a dedicated
function for handling LE signalling commands.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
Acked-by: Marcel Holtmann <marcel@holtmann.org>
Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Diffstat (limited to 'net')
-rw-r--r-- | net/bluetooth/l2cap_core.c | 53 |
1 files changed, 48 insertions, 5 deletions
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 4be6a264b475..ab9961118181 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c | |||
@@ -5292,6 +5292,51 @@ static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn, | |||
5292 | } | 5292 | } |
5293 | } | 5293 | } |
5294 | 5294 | ||
5295 | static inline void l2cap_le_sig_channel(struct l2cap_conn *conn, | ||
5296 | struct sk_buff *skb) | ||
5297 | { | ||
5298 | u8 *data = skb->data; | ||
5299 | int len = skb->len; | ||
5300 | struct l2cap_cmd_hdr cmd; | ||
5301 | int err; | ||
5302 | |||
5303 | l2cap_raw_recv(conn, skb); | ||
5304 | |||
5305 | while (len >= L2CAP_CMD_HDR_SIZE) { | ||
5306 | u16 cmd_len; | ||
5307 | memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE); | ||
5308 | data += L2CAP_CMD_HDR_SIZE; | ||
5309 | len -= L2CAP_CMD_HDR_SIZE; | ||
5310 | |||
5311 | cmd_len = le16_to_cpu(cmd.len); | ||
5312 | |||
5313 | BT_DBG("code 0x%2.2x len %d id 0x%2.2x", cmd.code, cmd_len, | ||
5314 | cmd.ident); | ||
5315 | |||
5316 | if (cmd_len > len || !cmd.ident) { | ||
5317 | BT_DBG("corrupted command"); | ||
5318 | break; | ||
5319 | } | ||
5320 | |||
5321 | err = l2cap_le_sig_cmd(conn, &cmd, data); | ||
5322 | if (err) { | ||
5323 | struct l2cap_cmd_rej_unk rej; | ||
5324 | |||
5325 | BT_ERR("Wrong link type (%d)", err); | ||
5326 | |||
5327 | /* FIXME: Map err to a valid reason */ | ||
5328 | rej.reason = __constant_cpu_to_le16(L2CAP_REJ_NOT_UNDERSTOOD); | ||
5329 | l2cap_send_cmd(conn, cmd.ident, L2CAP_COMMAND_REJ, | ||
5330 | sizeof(rej), &rej); | ||
5331 | } | ||
5332 | |||
5333 | data += cmd_len; | ||
5334 | len -= cmd_len; | ||
5335 | } | ||
5336 | |||
5337 | kfree_skb(skb); | ||
5338 | } | ||
5339 | |||
5295 | static inline void l2cap_sig_channel(struct l2cap_conn *conn, | 5340 | static inline void l2cap_sig_channel(struct l2cap_conn *conn, |
5296 | struct sk_buff *skb) | 5341 | struct sk_buff *skb) |
5297 | { | 5342 | { |
@@ -5318,11 +5363,7 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn, | |||
5318 | break; | 5363 | break; |
5319 | } | 5364 | } |
5320 | 5365 | ||
5321 | if (conn->hcon->type == LE_LINK) | 5366 | err = l2cap_bredr_sig_cmd(conn, &cmd, cmd_len, data); |
5322 | err = l2cap_le_sig_cmd(conn, &cmd, data); | ||
5323 | else | ||
5324 | err = l2cap_bredr_sig_cmd(conn, &cmd, cmd_len, data); | ||
5325 | |||
5326 | if (err) { | 5367 | if (err) { |
5327 | struct l2cap_cmd_rej_unk rej; | 5368 | struct l2cap_cmd_rej_unk rej; |
5328 | 5369 | ||
@@ -6395,6 +6436,8 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) | |||
6395 | 6436 | ||
6396 | switch (cid) { | 6437 | switch (cid) { |
6397 | case L2CAP_CID_LE_SIGNALING: | 6438 | case L2CAP_CID_LE_SIGNALING: |
6439 | l2cap_le_sig_channel(conn, skb); | ||
6440 | break; | ||
6398 | case L2CAP_CID_SIGNALING: | 6441 | case L2CAP_CID_SIGNALING: |
6399 | l2cap_sig_channel(conn, skb); | 6442 | l2cap_sig_channel(conn, skb); |
6400 | break; | 6443 | break; |