Skip to content

Commit

Permalink
Bluetooth: Add LE signaling commands handling
Browse files Browse the repository at this point in the history
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: Claudio Takahasi <claudio.takahasi@openbossa.org>
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
  • Loading branch information
Claudio Takahasi authored and Gustavo F. Padovan committed Feb 16, 2011
1 parent 03c2d0e commit 3300d9a
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 52 deletions.
2 changes: 2 additions & 0 deletions include/net/bluetooth/l2cap.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ struct l2cap_conninfo {
#define L2CAP_ECHO_RSP 0x09
#define L2CAP_INFO_REQ 0x0a
#define L2CAP_INFO_RSP 0x0b
#define L2CAP_CONN_PARAM_UPDATE_REQ 0x12
#define L2CAP_CONN_PARAM_UPDATE_RSP 0x13

/* L2CAP feature mask */
#define L2CAP_FEAT_FLOWCTL 0x00000001
Expand Down
142 changes: 90 additions & 52 deletions net/bluetooth/l2cap_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1428,7 +1428,11 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,

lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
lh->len = cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen);
lh->cid = cpu_to_le16(L2CAP_CID_SIGNALING);

if (conn->hcon->type == LE_LINK)
lh->cid = cpu_to_le16(L2CAP_CID_LE_SIGNALING);
else
lh->cid = cpu_to_le16(L2CAP_CID_SIGNALING);

cmd = (struct l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE);
cmd->code = code;
Expand Down Expand Up @@ -2497,12 +2501,90 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm
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)
{
int err = 0;

switch (cmd->code) {
case L2CAP_COMMAND_REJ:
l2cap_command_rej(conn, cmd, data);
break;

case L2CAP_CONN_REQ:
err = l2cap_connect_req(conn, cmd, data);
break;

case L2CAP_CONN_RSP:
err = l2cap_connect_rsp(conn, cmd, data);
break;

case L2CAP_CONF_REQ:
err = l2cap_config_req(conn, cmd, cmd_len, data);
break;

case L2CAP_CONF_RSP:
err = l2cap_config_rsp(conn, cmd, data);
break;

case L2CAP_DISCONN_REQ:
err = l2cap_disconnect_req(conn, cmd, data);
break;

case L2CAP_DISCONN_RSP:
err = l2cap_disconnect_rsp(conn, cmd, data);
break;

case L2CAP_ECHO_REQ:
l2cap_send_cmd(conn, cmd->ident, L2CAP_ECHO_RSP, cmd_len, data);
break;

case L2CAP_ECHO_RSP:
break;

case L2CAP_INFO_REQ:
err = l2cap_information_req(conn, cmd, data);
break;

case L2CAP_INFO_RSP:
err = l2cap_information_rsp(conn, cmd, data);
break;

default:
BT_ERR("Unknown BR/EDR signaling command 0x%2.2x", cmd->code);
err = -EINVAL;
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 = 0;
int err;

l2cap_raw_recv(conn, skb);

Expand All @@ -2521,55 +2603,10 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *sk
break;
}

switch (cmd.code) {
case L2CAP_COMMAND_REJ:
l2cap_command_rej(conn, &cmd, data);
break;

case L2CAP_CONN_REQ:
err = l2cap_connect_req(conn, &cmd, data);
break;

case L2CAP_CONN_RSP:
err = l2cap_connect_rsp(conn, &cmd, data);
break;

case L2CAP_CONF_REQ:
err = l2cap_config_req(conn, &cmd, cmd_len, data);
break;

case L2CAP_CONF_RSP:
err = l2cap_config_rsp(conn, &cmd, data);
break;

case L2CAP_DISCONN_REQ:
err = l2cap_disconnect_req(conn, &cmd, data);
break;

case L2CAP_DISCONN_RSP:
err = l2cap_disconnect_rsp(conn, &cmd, data);
break;

case L2CAP_ECHO_REQ:
l2cap_send_cmd(conn, cmd.ident, L2CAP_ECHO_RSP, cmd_len, data);
break;

case L2CAP_ECHO_RSP:
break;

case L2CAP_INFO_REQ:
err = l2cap_information_req(conn, &cmd, data);
break;

case L2CAP_INFO_RSP:
err = l2cap_information_rsp(conn, &cmd, data);
break;

default:
BT_ERR("Unknown signaling command 0x%2.2x", cmd.code);
err = -EINVAL;
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) {
struct l2cap_cmd_rej rej;
Expand Down Expand Up @@ -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);

switch (cid) {
case L2CAP_CID_LE_SIGNALING:
case L2CAP_CID_SIGNALING:
l2cap_sig_channel(conn, skb);
break;
Expand Down

0 comments on commit 3300d9a

Please sign in to comment.