static void l2cap_sig(struct bthost *bthost, struct btconn *conn, const void *data, uint16_t len) { const struct bt_l2cap_hdr_sig *hdr = data; struct bt_l2cap_pdu_cmd_reject rej; uint16_t hdr_len; bool ret; if (len < sizeof(*hdr)) goto reject; hdr_len = le16_to_cpu(hdr->len); if (sizeof(*hdr) + hdr_len != len) goto reject; switch (hdr->code) { case BT_L2CAP_PDU_CMD_REJECT: ret = l2cap_cmd_rej(bthost, conn, hdr->ident, data + sizeof(*hdr), hdr_len); break; case BT_L2CAP_PDU_CONN_REQ: ret = l2cap_conn_req(bthost, conn, hdr->ident, data + sizeof(*hdr), hdr_len); break; case BT_L2CAP_PDU_CONN_RSP: ret = l2cap_conn_rsp(bthost, conn, hdr->ident, data + sizeof(*hdr), hdr_len); break; case BT_L2CAP_PDU_CONFIG_REQ: ret = l2cap_config_req(bthost, conn, hdr->ident, data + sizeof(*hdr), hdr_len); break; case BT_L2CAP_PDU_CONFIG_RSP: ret = l2cap_config_rsp(bthost, conn, hdr->ident, data + sizeof(*hdr), hdr_len); break; case BT_L2CAP_PDU_DISCONN_REQ: ret = l2cap_disconn_req(bthost, conn, hdr->ident, data + sizeof(*hdr), hdr_len); break; case BT_L2CAP_PDU_INFO_REQ: ret = l2cap_info_req(bthost, conn, hdr->ident, data + sizeof(*hdr), hdr_len); break; default: printf("Unknown L2CAP code 0x%02x\n", hdr->code); ret = false; } handle_pending_l2reqs(bthost, conn, hdr->ident, hdr->code, data + sizeof(*hdr), hdr_len); if (ret) return; reject: memset(&rej, 0, sizeof(rej)); l2cap_sig_send(bthost, conn, BT_L2CAP_PDU_CMD_REJECT, 0, &rej, sizeof(rej)); }
static inline void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb) { __u8 *data = skb->data; int len = skb->len; l2cap_cmd_hdr cmd; int err = 0; l2cap_raw_recv(conn, skb); while (len >= L2CAP_CMD_HDR_SIZE) { 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_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, 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_COMMAND_REJ: /* FIXME: We should process this */ break; case L2CAP_ECHO_REQ: l2cap_send_rsp(conn, cmd.ident, L2CAP_ECHO_RSP, cmd.len, data); break; case L2CAP_ECHO_RSP: case L2CAP_INFO_REQ: case L2CAP_INFO_RSP: break; default: BT_ERR("Unknown signaling command 0x%2.2x", cmd.code); err = -EINVAL; break; }; if (err) { l2cap_cmd_rej rej; BT_DBG("error %d", err); /* FIXME: Map err to a valid reason. */ rej.reason = __cpu_to_le16(0); l2cap_send_rsp(conn, cmd.ident, L2CAP_COMMAND_REJ, L2CAP_CMD_REJ_SIZE, &rej); } data += cmd.len; len -= cmd.len; } kfree_skb(skb); }