|
@@ -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 = (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);
|
|
- 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 = (struct l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE);
|
|
cmd->code = code;
|
|
cmd->code = code;
|
|
@@ -2497,12 +2501,90 @@ 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)
|
|
|
|
+{
|
|
|
|
+ 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;
|
|
u8 *data = skb->data;
|
|
int len = skb->len;
|
|
int len = skb->len;
|
|
struct l2cap_cmd_hdr cmd;
|
|
struct l2cap_cmd_hdr cmd;
|
|
- int err = 0;
|
|
|
|
|
|
+ int err;
|
|
|
|
|
|
l2cap_raw_recv(conn, skb);
|
|
l2cap_raw_recv(conn, skb);
|
|
|
|
|
|
@@ -2521,55 +2603,10 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *sk
|
|
break;
|
|
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) {
|
|
if (err) {
|
|
struct l2cap_cmd_rej rej;
|
|
struct l2cap_cmd_rej rej;
|
|
@@ -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;
|