Commit 3300d9a9 authored by Claudio Takahasi's avatar Claudio Takahasi Committed by Gustavo F. Padovan

Bluetooth: Add LE signaling commands handling

This patch splits the L2CAP command handling function in order to
have a clear separation between the commands related to BR/EDR and
LE. Commands and responses in the LE signaling channel are not being
handled yet, command reject is sent to all received requests. Bluetooth
Core Specification, Volume 3, Part A, section 4 defines the signaling
packets formats and allowed commands/responses over the LE signaling
channel.
Signed-off-by: default avatarClaudio Takahasi <claudio.takahasi@openbossa.org>
Signed-off-by: default avatarGustavo F. Padovan <padovan@profusion.mobi>
parent 03c2d0e8
...@@ -89,6 +89,8 @@ struct l2cap_conninfo { ...@@ -89,6 +89,8 @@ struct l2cap_conninfo {
#define L2CAP_ECHO_RSP 0x09 #define L2CAP_ECHO_RSP 0x09
#define L2CAP_INFO_REQ 0x0a #define L2CAP_INFO_REQ 0x0a
#define L2CAP_INFO_RSP 0x0b #define L2CAP_INFO_RSP 0x0b
#define L2CAP_CONN_PARAM_UPDATE_REQ 0x12
#define L2CAP_CONN_PARAM_UPDATE_RSP 0x13
/* L2CAP feature mask */ /* L2CAP feature mask */
#define L2CAP_FEAT_FLOWCTL 0x00000001 #define L2CAP_FEAT_FLOWCTL 0x00000001
......
...@@ -1428,6 +1428,10 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, ...@@ -1428,6 +1428,10 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
lh->len = cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen); lh->len = cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen);
if (conn->hcon->type == LE_LINK)
lh->cid = cpu_to_le16(L2CAP_CID_LE_SIGNALING);
else
lh->cid = cpu_to_le16(L2CAP_CID_SIGNALING); lh->cid = cpu_to_le16(L2CAP_CID_SIGNALING);
cmd = (struct l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE); cmd = (struct l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE);
...@@ -2497,80 +2501,113 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm ...@@ -2497,80 +2501,113 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm
return 0; return 0;
} }
static inline void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb) static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data)
{ {
u8 *data = skb->data;
int len = skb->len;
struct l2cap_cmd_hdr cmd;
int err = 0; int err = 0;
l2cap_raw_recv(conn, skb); switch (cmd->code) {
while (len >= L2CAP_CMD_HDR_SIZE) {
u16 cmd_len;
memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE);
data += L2CAP_CMD_HDR_SIZE;
len -= L2CAP_CMD_HDR_SIZE;
cmd_len = le16_to_cpu(cmd.len);
BT_DBG("code 0x%2.2x len %d id 0x%2.2x", cmd.code, cmd_len, cmd.ident);
if (cmd_len > len || !cmd.ident) {
BT_DBG("corrupted command");
break;
}
switch (cmd.code) {
case L2CAP_COMMAND_REJ: case L2CAP_COMMAND_REJ:
l2cap_command_rej(conn, &cmd, data); l2cap_command_rej(conn, cmd, data);
break; break;
case L2CAP_CONN_REQ: case L2CAP_CONN_REQ:
err = l2cap_connect_req(conn, &cmd, data); err = l2cap_connect_req(conn, cmd, data);
break; break;
case L2CAP_CONN_RSP: case L2CAP_CONN_RSP:
err = l2cap_connect_rsp(conn, &cmd, data); err = l2cap_connect_rsp(conn, cmd, data);
break; break;
case L2CAP_CONF_REQ: case L2CAP_CONF_REQ:
err = l2cap_config_req(conn, &cmd, cmd_len, data); err = l2cap_config_req(conn, cmd, cmd_len, data);
break; break;
case L2CAP_CONF_RSP: case L2CAP_CONF_RSP:
err = l2cap_config_rsp(conn, &cmd, data); err = l2cap_config_rsp(conn, cmd, data);
break; break;
case L2CAP_DISCONN_REQ: case L2CAP_DISCONN_REQ:
err = l2cap_disconnect_req(conn, &cmd, data); err = l2cap_disconnect_req(conn, cmd, data);
break; break;
case L2CAP_DISCONN_RSP: case L2CAP_DISCONN_RSP:
err = l2cap_disconnect_rsp(conn, &cmd, data); err = l2cap_disconnect_rsp(conn, cmd, data);
break; break;
case L2CAP_ECHO_REQ: case L2CAP_ECHO_REQ:
l2cap_send_cmd(conn, cmd.ident, L2CAP_ECHO_RSP, cmd_len, data); l2cap_send_cmd(conn, cmd->ident, L2CAP_ECHO_RSP, cmd_len, data);
break; break;
case L2CAP_ECHO_RSP: case L2CAP_ECHO_RSP:
break; break;
case L2CAP_INFO_REQ: case L2CAP_INFO_REQ:
err = l2cap_information_req(conn, &cmd, data); err = l2cap_information_req(conn, cmd, data);
break; break;
case L2CAP_INFO_RSP: case L2CAP_INFO_RSP:
err = l2cap_information_rsp(conn, &cmd, data); err = l2cap_information_rsp(conn, cmd, data);
break; break;
default: default:
BT_ERR("Unknown signaling command 0x%2.2x", cmd.code); BT_ERR("Unknown BR/EDR signaling command 0x%2.2x", cmd->code);
err = -EINVAL; err = -EINVAL;
break; break;
} }
return err;
}
static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn,
struct l2cap_cmd_hdr *cmd, u8 *data)
{
switch (cmd->code) {
case L2CAP_COMMAND_REJ:
return 0;
case L2CAP_CONN_PARAM_UPDATE_REQ:
return -EINVAL;
case L2CAP_CONN_PARAM_UPDATE_RSP:
return 0;
default:
BT_ERR("Unknown LE signaling command 0x%2.2x", cmd->code);
return -EINVAL;
}
}
static inline void l2cap_sig_channel(struct l2cap_conn *conn,
struct sk_buff *skb)
{
u8 *data = skb->data;
int len = skb->len;
struct l2cap_cmd_hdr cmd;
int err;
l2cap_raw_recv(conn, skb);
while (len >= L2CAP_CMD_HDR_SIZE) {
u16 cmd_len;
memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE);
data += L2CAP_CMD_HDR_SIZE;
len -= L2CAP_CMD_HDR_SIZE;
cmd_len = le16_to_cpu(cmd.len);
BT_DBG("code 0x%2.2x len %d id 0x%2.2x", cmd.code, cmd_len, cmd.ident);
if (cmd_len > len || !cmd.ident) {
BT_DBG("corrupted command");
break;
}
if (conn->hcon->type == LE_LINK)
err = l2cap_le_sig_cmd(conn, &cmd, data);
else
err = l2cap_bredr_sig_cmd(conn, &cmd, cmd_len, data);
if (err) { if (err) {
struct l2cap_cmd_rej rej; struct l2cap_cmd_rej rej;
BT_DBG("error %d", err); BT_DBG("error %d", err);
...@@ -3566,6 +3603,7 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) ...@@ -3566,6 +3603,7 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
BT_DBG("len %d, cid 0x%4.4x", len, cid); BT_DBG("len %d, cid 0x%4.4x", len, cid);
switch (cid) { switch (cid) {
case L2CAP_CID_LE_SIGNALING:
case L2CAP_CID_SIGNALING: case L2CAP_CID_SIGNALING:
l2cap_sig_channel(conn, skb); l2cap_sig_channel(conn, skb);
break; break;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment