Commit 0453567b authored by Marcel Holtmann's avatar Marcel Holtmann Committed by Marcel Holtmann

[Bluetooth] Respond to L2CAP info requests

This patch adds the correct behavior when a L2CAP info request is sent
by the peer. The answer should be a L2CAP info response with the result
code set to "not supported".
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
parent 1dd7f7ca
...@@ -176,6 +176,14 @@ struct l2cap_info_rsp { ...@@ -176,6 +176,14 @@ struct l2cap_info_rsp {
__u8 data[0]; __u8 data[0];
} __attribute__ ((packed)); } __attribute__ ((packed));
/* info type */
#define L2CAP_IT_CL_MTU 0x0001
#define L2CAP_IT_FEAT_MASK 0x0002
/* info result */
#define L2CAP_IR_SUCCESS 0x0000
#define L2CAP_IR_NOTSUPP 0x0001
/* ----- L2CAP connections ----- */ /* ----- L2CAP connections ----- */
struct l2cap_chan_list { struct l2cap_chan_list {
struct sock *head; struct sock *head;
......
...@@ -57,7 +57,7 @@ ...@@ -57,7 +57,7 @@
#define BT_DBG(D...) #define BT_DBG(D...)
#endif #endif
#define VERSION "2.2" #define VERSION "2.3"
static struct proto_ops l2cap_sock_ops; static struct proto_ops l2cap_sock_ops;
...@@ -718,8 +718,7 @@ static inline int l2cap_do_send(struct sock *sk, struct msghdr *msg, int len) ...@@ -718,8 +718,7 @@ static inline int l2cap_do_send(struct sock *sk, struct msghdr *msg, int len)
return err; return err;
} }
static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len)
struct msghdr *msg, size_t len)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
int err = 0; int err = 0;
...@@ -1444,7 +1443,7 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd ...@@ -1444,7 +1443,7 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd
struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data; struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data;
u16 scid, dcid, result, status; u16 scid, dcid, result, status;
struct sock *sk; struct sock *sk;
char req[128]; u8 req[128];
scid = __le16_to_cpu(rsp->scid); scid = __le16_to_cpu(rsp->scid);
dcid = __le16_to_cpu(rsp->dcid); dcid = __le16_to_cpu(rsp->dcid);
...@@ -1481,7 +1480,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr ...@@ -1481,7 +1480,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
{ {
struct l2cap_conf_req *req = (struct l2cap_conf_req *) data; struct l2cap_conf_req *req = (struct l2cap_conf_req *) data;
u16 dcid, flags; u16 dcid, flags;
u8 rsp[64]; u8 rsp[64];
struct sock *sk; struct sock *sk;
int result; int result;
...@@ -1633,6 +1632,35 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd ...@@ -1633,6 +1632,35 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd
return 0; return 0;
} }
static inline int l2cap_info_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
{
struct l2cap_info_req *req = (struct l2cap_info_req *) data;
struct l2cap_info_rsp rsp;
u16 type;
type = __le16_to_cpu(req->type);
BT_DBG("type 0x%4.4x", type);
rsp.type = __cpu_to_le16(type);
rsp.result = __cpu_to_le16(L2CAP_IR_NOTSUPP);
l2cap_send_rsp(conn, cmd->ident, L2CAP_INFO_RSP, sizeof(rsp), &rsp);
return 0;
}
static inline int l2cap_info_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
{
struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) data;
u16 type, result;
type = __le16_to_cpu(rsp->type);
result = __le16_to_cpu(rsp->result);
BT_DBG("type 0x%4.4x result 0x%2.2x", type, result);
return 0;
}
static inline void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb) static inline void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
{ {
u8 *data = skb->data; u8 *data = skb->data;
...@@ -1657,6 +1685,10 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *sk ...@@ -1657,6 +1685,10 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *sk
} }
switch (cmd.code) { switch (cmd.code) {
case L2CAP_COMMAND_REJ:
/* FIXME: We should process this */
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;
...@@ -1681,17 +1713,19 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *sk ...@@ -1681,17 +1713,19 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *sk
err = l2cap_disconnect_rsp(conn, &cmd, data); err = l2cap_disconnect_rsp(conn, &cmd, data);
break; break;
case L2CAP_COMMAND_REJ:
/* FIXME: We should process this */
break;
case L2CAP_ECHO_REQ: case L2CAP_ECHO_REQ:
l2cap_send_rsp(conn, cmd.ident, L2CAP_ECHO_RSP, cmd.len, data); l2cap_send_rsp(conn, cmd.ident, L2CAP_ECHO_RSP, cmd.len, data);
break; break;
case L2CAP_ECHO_RSP: case L2CAP_ECHO_RSP:
break;
case L2CAP_INFO_REQ: case L2CAP_INFO_REQ:
err = l2cap_info_req(conn, &cmd, data);
break;
case L2CAP_INFO_RSP: case L2CAP_INFO_RSP:
err = l2cap_info_rsp(conn, &cmd, data);
break; break;
default: default:
...@@ -1704,7 +1738,7 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *sk ...@@ -1704,7 +1738,7 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *sk
struct l2cap_cmd_rej rej; struct l2cap_cmd_rej rej;
BT_DBG("error %d", err); BT_DBG("error %d", err);
/* FIXME: Map err to a valid reason. */ /* FIXME: Map err to a valid reason */
rej.reason = __cpu_to_le16(0); rej.reason = __cpu_to_le16(0);
l2cap_send_rsp(conn, cmd.ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej); l2cap_send_rsp(conn, cmd.ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej);
} }
...@@ -1737,7 +1771,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk ...@@ -1737,7 +1771,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
/* If socket recv buffers overflows we drop data here /* If socket recv buffers overflows we drop data here
* which is *bad* because L2CAP has to be reliable. * which is *bad* because L2CAP has to be reliable.
* But we don't have any other choice. L2CAP doesn't * But we don't have any other choice. L2CAP doesn't
* provide flow control mechanism */ * provide flow control mechanism. */
if (!sock_queue_rcv_skb(sk, skb)) if (!sock_queue_rcv_skb(sk, skb))
goto done; goto done;
...@@ -2210,7 +2244,7 @@ EXPORT_SYMBOL(l2cap_load); ...@@ -2210,7 +2244,7 @@ EXPORT_SYMBOL(l2cap_load);
module_init(l2cap_init); module_init(l2cap_init);
module_exit(l2cap_exit); module_exit(l2cap_exit);
MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>"); MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>");
MODULE_DESCRIPTION("Bluetooth L2CAP ver " VERSION); MODULE_DESCRIPTION("Bluetooth L2CAP ver " VERSION);
MODULE_VERSION(VERSION); MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
......
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