git.openpandora.org
/
pandora-kernel.git
/ blobdiff
commit
grep
author
committer
pickaxe
?
search:
re
summary
|
shortlog
|
log
|
commit
|
commitdiff
|
tree
raw
|
inline
| side by side
pandora: defconfig: update
[pandora-kernel.git]
/
net
/
bluetooth
/
l2cap_core.c
diff --git
a/net/bluetooth/l2cap_core.c
b/net/bluetooth/l2cap_core.c
index
17b5b1c
..
74f57d8
100644
(file)
--- a/
net/bluetooth/l2cap_core.c
+++ b/
net/bluetooth/l2cap_core.c
@@
-68,7
+68,7
@@
static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
u8 code, u8 ident, u16 dlen, void *data);
static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
void *data);
u8 code, u8 ident, u16 dlen, void *data);
static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
void *data);
-static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data);
+static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data
, size_t data_size
);
static void l2cap_send_disconn_req(struct l2cap_conn *conn,
struct l2cap_chan *chan, int err);
static void l2cap_send_disconn_req(struct l2cap_conn *conn,
struct l2cap_chan *chan, int err);
@@
-787,7
+787,7
@@
static void l2cap_conn_start(struct l2cap_conn *conn)
set_bit(CONF_REQ_SENT, &chan->conf_state);
l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
set_bit(CONF_REQ_SENT, &chan->conf_state);
l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
-
l2cap_build_conf_req(chan, buf
), buf);
+
l2cap_build_conf_req(chan, buf, sizeof(buf)
), buf);
chan->num_conf_req++;
}
chan->num_conf_req++;
}
@@
-862,6
+862,7
@@
static void l2cap_le_conn_ready(struct l2cap_conn *conn)
write_lock_bh(&conn->chan_lock);
hci_conn_hold(conn->hcon);
write_lock_bh(&conn->chan_lock);
hci_conn_hold(conn->hcon);
+ conn->hcon->disc_timeout = HCI_DISCONN_TIMEOUT;
bacpy(&bt_sk(sk)->src, conn->src);
bacpy(&bt_sk(sk)->dst, conn->dst);
bacpy(&bt_sk(sk)->src, conn->src);
bacpy(&bt_sk(sk)->dst, conn->dst);
@@
-901,14
+902,15
@@
static void l2cap_chan_ready(struct sock *sk)
static void l2cap_conn_ready(struct l2cap_conn *conn)
{
struct l2cap_chan *chan;
static void l2cap_conn_ready(struct l2cap_conn *conn)
{
struct l2cap_chan *chan;
+ struct hci_conn *hcon = conn->hcon;
BT_DBG("conn %p", conn);
BT_DBG("conn %p", conn);
- if (!
conn->hcon->out && conn->
hcon->type == LE_LINK)
+ if (!
hcon->out &&
hcon->type == LE_LINK)
l2cap_le_conn_ready(conn);
l2cap_le_conn_ready(conn);
- if (
conn->hcon->out && conn->
hcon->type == LE_LINK)
- smp_conn_security(
conn, conn->
hcon->pending_sec_level);
+ if (
hcon->out &&
hcon->type == LE_LINK)
+ smp_conn_security(
hcon,
hcon->pending_sec_level);
read_lock(&conn->chan_lock);
read_lock(&conn->chan_lock);
@@
-917,8
+919,8
@@
static void l2cap_conn_ready(struct l2cap_conn *conn)
bh_lock_sock(sk);
bh_lock_sock(sk);
- if (
conn->
hcon->type == LE_LINK) {
- if (smp_conn_security(
con
n, chan->sec_level))
+ if (hcon->type == LE_LINK) {
+ if (smp_conn_security(
hco
n, chan->sec_level))
l2cap_chan_ready(sk);
} else if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
l2cap_chan_ready(sk);
} else if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
@@
-1735,6
+1737,9
@@
static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %d",
conn, code, ident, dlen);
BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %d",
conn, code, ident, dlen);
+ if (conn->mtu < L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE)
+ return NULL;
+
len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen;
count = min_t(unsigned int, conn->mtu, len);
len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen;
count = min_t(unsigned int, conn->mtu, len);
@@
-1820,12
+1825,15
@@
static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, unsigned
return len;
}
return len;
}
-static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val)
+static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val
, size_t size
)
{
struct l2cap_conf_opt *opt = *ptr;
BT_DBG("type 0x%2.2x len %d val 0x%lx", type, len, val);
{
struct l2cap_conf_opt *opt = *ptr;
BT_DBG("type 0x%2.2x len %d val 0x%lx", type, len, val);
+ if (size < L2CAP_CONF_OPT_SIZE + len)
+ return;
+
opt->type = type;
opt->len = len;
opt->type = type;
opt->len = len;
@@
-1896,11
+1904,12
@@
static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
}
}
}
}
-static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
+static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data
, size_t data_size
)
{
struct l2cap_conf_req *req = data;
struct l2cap_conf_rfc rfc = { .mode = chan->mode };
void *ptr = req->data;
{
struct l2cap_conf_req *req = data;
struct l2cap_conf_rfc rfc = { .mode = chan->mode };
void *ptr = req->data;
+ void *endptr = data + data_size;
BT_DBG("chan %p", chan);
BT_DBG("chan %p", chan);
@@
-1921,7
+1930,7
@@
static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
done:
if (chan->imtu != L2CAP_DEFAULT_MTU)
done:
if (chan->imtu != L2CAP_DEFAULT_MTU)
- l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
+ l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu
, endptr - ptr
);
switch (chan->mode) {
case L2CAP_MODE_BASIC:
switch (chan->mode) {
case L2CAP_MODE_BASIC:
@@
-1937,7
+1946,7
@@
done:
rfc.max_pdu_size = 0;
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
rfc.max_pdu_size = 0;
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
-
(unsigned long) &rfc
);
+
(unsigned long) &rfc, endptr - ptr
);
break;
case L2CAP_MODE_ERTM:
break;
case L2CAP_MODE_ERTM:
@@
-1951,7
+1960,7
@@
done:
rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
-
(unsigned long) &rfc
);
+
(unsigned long) &rfc, endptr - ptr
);
if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
break;
if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
break;
@@
-1959,7
+1968,8
@@
done:
if (chan->fcs == L2CAP_FCS_NONE ||
test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
chan->fcs = L2CAP_FCS_NONE;
if (chan->fcs == L2CAP_FCS_NONE ||
test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
chan->fcs = L2CAP_FCS_NONE;
- l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
+ l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs,
+ endptr - ptr);
}
break;
}
break;
@@
-1974,7
+1984,7
@@
done:
rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
-
(unsigned long) &rfc
);
+
(unsigned long) &rfc, endptr - ptr
);
if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
break;
if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
break;
@@
-1982,7
+1992,8
@@
done:
if (chan->fcs == L2CAP_FCS_NONE ||
test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
chan->fcs = L2CAP_FCS_NONE;
if (chan->fcs == L2CAP_FCS_NONE ||
test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
chan->fcs = L2CAP_FCS_NONE;
- l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
+ l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs,
+ endptr - ptr);
}
break;
}
}
break;
}
@@
-1993,10
+2004,11
@@
done:
return ptr - data;
}
return ptr - data;
}
-static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
+static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data
, size_t data_size
)
{
struct l2cap_conf_rsp *rsp = data;
void *ptr = rsp->data;
{
struct l2cap_conf_rsp *rsp = data;
void *ptr = rsp->data;
+ void *endptr = data + data_size;
void *req = chan->conf_req;
int len = chan->conf_len;
int type, hint, olen;
void *req = chan->conf_req;
int len = chan->conf_len;
int type, hint, olen;
@@
-2009,6
+2021,8
@@
static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
while (len >= L2CAP_CONF_OPT_SIZE) {
len -= l2cap_get_conf_opt(&req, &type, &olen, &val);
while (len >= L2CAP_CONF_OPT_SIZE) {
len -= l2cap_get_conf_opt(&req, &type, &olen, &val);
+ if (len < 0)
+ break;
hint = type & L2CAP_CONF_HINT;
type &= L2CAP_CONF_MASK;
hint = type & L2CAP_CONF_HINT;
type &= L2CAP_CONF_MASK;
@@
-2072,8
+2086,8
@@
done:
if (chan->num_conf_rsp == 1)
return -ECONNREFUSED;
if (chan->num_conf_rsp == 1)
return -ECONNREFUSED;
- l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
-
sizeof(rfc), (unsigned long) &rfc
);
+ l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
sizeof(rfc),
+
(unsigned long) &rfc, endptr - ptr
);
}
}
@@
-2087,7
+2101,7
@@
done:
chan->omtu = mtu;
set_bit(CONF_MTU_DONE, &chan->conf_state);
}
chan->omtu = mtu;
set_bit(CONF_MTU_DONE, &chan->conf_state);
}
- l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->omtu);
+ l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->omtu
, endptr - ptr
);
switch (rfc.mode) {
case L2CAP_MODE_BASIC:
switch (rfc.mode) {
case L2CAP_MODE_BASIC:
@@
-2112,7
+2126,7
@@
done:
set_bit(CONF_MODE_DONE, &chan->conf_state);
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
set_bit(CONF_MODE_DONE, &chan->conf_state);
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
-
sizeof(rfc), (unsigned long) &rfc
);
+
sizeof(rfc), (unsigned long) &rfc, endptr - ptr
);
break;
break;
@@
-2124,8
+2138,8
@@
done:
set_bit(CONF_MODE_DONE, &chan->conf_state);
set_bit(CONF_MODE_DONE, &chan->conf_state);
- l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
-
sizeof(rfc), (unsigned long) &rfc
);
+ l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
sizeof(rfc),
+
(unsigned long) &rfc, endptr - ptr
);
break;
break;
@@
-2146,10
+2160,12
@@
done:
return ptr - data;
}
return ptr - data;
}
-static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, void *data, u16 *result)
+static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len,
+ void *data, size_t size, u16 *result)
{
struct l2cap_conf_req *req = data;
void *ptr = req->data;
{
struct l2cap_conf_req *req = data;
void *ptr = req->data;
+ void *endptr = data + size;
int type, olen;
unsigned long val;
struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
int type, olen;
unsigned long val;
struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
@@
-2158,6
+2174,8
@@
static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi
while (len >= L2CAP_CONF_OPT_SIZE) {
len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
while (len >= L2CAP_CONF_OPT_SIZE) {
len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
+ if (len < 0)
+ break;
switch (type) {
case L2CAP_CONF_MTU:
switch (type) {
case L2CAP_CONF_MTU:
@@
-2166,13
+2184,13
@@
static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi
chan->imtu = L2CAP_DEFAULT_MIN_MTU;
} else
chan->imtu = val;
chan->imtu = L2CAP_DEFAULT_MIN_MTU;
} else
chan->imtu = val;
- l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
+ l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu
, endptr - ptr
);
break;
case L2CAP_CONF_FLUSH_TO:
chan->flush_to = val;
l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO,
break;
case L2CAP_CONF_FLUSH_TO:
chan->flush_to = val;
l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO,
-
2, chan->flush_to
);
+
2, chan->flush_to, endptr - ptr
);
break;
case L2CAP_CONF_RFC:
break;
case L2CAP_CONF_RFC:
@@
-2186,7
+2204,7
@@
static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi
chan->fcs = 0;
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
chan->fcs = 0;
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
-
sizeof(rfc), (unsigned long) &rfc
);
+
sizeof(rfc), (unsigned long) &rfc, endptr - ptr
);
break;
}
}
break;
}
}
@@
-2245,7
+2263,7
@@
void __l2cap_connect_rsp_defer(struct l2cap_chan *chan)
return;
l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
return;
l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
-
l2cap_build_conf_req(chan, buf
), buf);
+
l2cap_build_conf_req(chan, buf, sizeof(buf)
), buf);
chan->num_conf_req++;
}
chan->num_conf_req++;
}
@@
-2262,13
+2280,17
@@
static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len)
while (len >= L2CAP_CONF_OPT_SIZE) {
len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
while (len >= L2CAP_CONF_OPT_SIZE) {
len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
+ if (len < 0)
+ break;
- switch (type) {
- case L2CAP_CONF_RFC:
- if (olen == sizeof(rfc))
- memcpy(&rfc, (void *)val, olen);
- goto done;
- }
+ if (type != L2CAP_CONF_RFC)
+ continue;
+
+ if (olen != sizeof(rfc))
+ break;
+
+ memcpy(&rfc, (void *)val, olen);
+ goto done;
}
/* Use sane default values in case a misbehaving remote device
}
/* Use sane default values in case a misbehaving remote device
@@
-2293,10
+2315,15
@@
done:
}
}
}
}
-static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
+static inline int l2cap_command_rej(struct l2cap_conn *conn,
+ struct l2cap_cmd_hdr *cmd, u16 cmd_len,
+ u8 *data)
{
struct l2cap_cmd_rej_unk *rej = (struct l2cap_cmd_rej_unk *) data;
{
struct l2cap_cmd_rej_unk *rej = (struct l2cap_cmd_rej_unk *) data;
+ if (cmd_len < sizeof(*rej))
+ return -EPROTO;
+
if (rej->reason != L2CAP_REJ_NOT_UNDERSTOOD)
return 0;
if (rej->reason != L2CAP_REJ_NOT_UNDERSTOOD)
return 0;
@@
-2313,7
+2340,8
@@
static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hd
return 0;
}
return 0;
}
-static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
+static int l2cap_connect_req(struct l2cap_conn *conn,
+ struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data)
{
struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
struct l2cap_conn_rsp rsp;
{
struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
struct l2cap_conn_rsp rsp;
@@
-2321,8
+2349,14
@@
static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
struct sock *parent, *sk = NULL;
int result, status = L2CAP_CS_NO_INFO;
struct sock *parent, *sk = NULL;
int result, status = L2CAP_CS_NO_INFO;
- u16 dcid = 0, scid = __le16_to_cpu(req->scid);
- __le16 psm = req->psm;
+ u16 dcid = 0, scid;
+ __le16 psm;
+
+ if (cmd_len < sizeof(struct l2cap_conn_req))
+ return -EPROTO;
+
+ scid = __le16_to_cpu(req->scid);
+ psm = req->psm;
BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid);
BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid);
@@
-2440,14
+2474,16
@@
sendresp:
u8 buf[128];
set_bit(CONF_REQ_SENT, &chan->conf_state);
l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
u8 buf[128];
set_bit(CONF_REQ_SENT, &chan->conf_state);
l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
-
l2cap_build_conf_req(chan, buf
), buf);
+
l2cap_build_conf_req(chan, buf, sizeof(buf)
), buf);
chan->num_conf_req++;
}
return 0;
}
chan->num_conf_req++;
}
return 0;
}
-static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
+static int l2cap_connect_rsp(struct l2cap_conn *conn,
+ struct l2cap_cmd_hdr *cmd, u16 cmd_len,
+ u8 *data)
{
struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data;
u16 scid, dcid, result, status;
{
struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data;
u16 scid, dcid, result, status;
@@
-2455,6
+2491,9
@@
static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd
struct sock *sk;
u8 req[128];
struct sock *sk;
u8 req[128];
+ if (cmd_len < sizeof(*rsp))
+ return -EPROTO;
+
scid = __le16_to_cpu(rsp->scid);
dcid = __le16_to_cpu(rsp->dcid);
result = __le16_to_cpu(rsp->result);
scid = __le16_to_cpu(rsp->scid);
dcid = __le16_to_cpu(rsp->dcid);
result = __le16_to_cpu(rsp->result);
@@
-2485,7
+2524,7
@@
static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd
break;
l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
break;
l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
-
l2cap_build_conf_req(chan, req
), req);
+
l2cap_build_conf_req(chan, req, sizeof(req)
), req);
chan->num_conf_req++;
break;
chan->num_conf_req++;
break;
@@
-2530,6
+2569,9
@@
static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
struct sock *sk;
int len;
struct sock *sk;
int len;
+ if (cmd_len < sizeof(*req))
+ return -EPROTO;
+
dcid = __le16_to_cpu(req->dcid);
flags = __le16_to_cpu(req->flags);
dcid = __le16_to_cpu(req->dcid);
flags = __le16_to_cpu(req->flags);
@@
-2555,7
+2597,7
@@
static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
/* Reject if config buffer is too small. */
len = cmd_len - sizeof(*req);
/* Reject if config buffer is too small. */
len = cmd_len - sizeof(*req);
- if (
len < 0 ||
chan->conf_len + len > sizeof(chan->conf_req)) {
+ if (chan->conf_len + len > sizeof(chan->conf_req)) {
l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
l2cap_build_conf_rsp(chan, rsp,
L2CAP_CONF_REJECT, flags), rsp);
l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
l2cap_build_conf_rsp(chan, rsp,
L2CAP_CONF_REJECT, flags), rsp);
@@
-2575,7
+2617,7
@@
static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
}
/* Complete config. */
}
/* Complete config. */
- len = l2cap_parse_conf_req(chan, rsp);
+ len = l2cap_parse_conf_req(chan, rsp
, sizeof(rsp)
);
if (len < 0) {
l2cap_send_disconn_req(conn, chan, ECONNRESET);
goto unlock;
if (len < 0) {
l2cap_send_disconn_req(conn, chan, ECONNRESET);
goto unlock;
@@
-2608,7
+2650,7
@@
static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
if (!test_and_set_bit(CONF_REQ_SENT, &chan->conf_state)) {
u8 buf[64];
l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
if (!test_and_set_bit(CONF_REQ_SENT, &chan->conf_state)) {
u8 buf[64];
l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
-
l2cap_build_conf_req(chan, buf
), buf);
+
l2cap_build_conf_req(chan, buf, sizeof(buf)
), buf);
chan->num_conf_req++;
}
chan->num_conf_req++;
}
@@
-2617,13
+2659,18
@@
unlock:
return 0;
}
return 0;
}
-static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
+static inline int l2cap_config_rsp(struct l2cap_conn *conn,
+ struct l2cap_cmd_hdr *cmd, u16 cmd_len,
+ u8 *data)
{
struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data;
u16 scid, flags, result;
struct l2cap_chan *chan;
struct sock *sk;
{
struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data;
u16 scid, flags, result;
struct l2cap_chan *chan;
struct sock *sk;
- int len = cmd->len - sizeof(*rsp);
+ int len = cmd_len - sizeof(*rsp);
+
+ if (cmd_len < sizeof(*rsp))
+ return -EPROTO;
scid = __le16_to_cpu(rsp->scid);
flags = __le16_to_cpu(rsp->flags);
scid = __le16_to_cpu(rsp->scid);
flags = __le16_to_cpu(rsp->flags);
@@
-2655,7
+2702,7
@@
static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
/* throw out any old stored conf requests */
result = L2CAP_CONF_SUCCESS;
len = l2cap_parse_conf_rsp(chan, rsp->data, len,
/* throw out any old stored conf requests */
result = L2CAP_CONF_SUCCESS;
len = l2cap_parse_conf_rsp(chan, rsp->data, len,
-
req
, &result);
+
req, sizeof(req)
, &result);
if (len < 0) {
l2cap_send_disconn_req(conn, chan, ECONNRESET);
goto done;
if (len < 0) {
l2cap_send_disconn_req(conn, chan, ECONNRESET);
goto done;
@@
-2699,7
+2746,9
@@
done:
return 0;
}
return 0;
}
-static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
+static inline int l2cap_disconnect_req(struct l2cap_conn *conn,
+ struct l2cap_cmd_hdr *cmd, u16 cmd_len,
+ u8 *data)
{
struct l2cap_disconn_req *req = (struct l2cap_disconn_req *) data;
struct l2cap_disconn_rsp rsp;
{
struct l2cap_disconn_req *req = (struct l2cap_disconn_req *) data;
struct l2cap_disconn_rsp rsp;
@@
-2707,6
+2756,9
@@
static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd
struct l2cap_chan *chan;
struct sock *sk;
struct l2cap_chan *chan;
struct sock *sk;
+ if (cmd_len != sizeof(*req))
+ return -EPROTO;
+
scid = __le16_to_cpu(req->scid);
dcid = __le16_to_cpu(req->dcid);
scid = __le16_to_cpu(req->scid);
dcid = __le16_to_cpu(req->dcid);
@@
-2740,13
+2792,18
@@
static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd
return 0;
}
return 0;
}
-static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
+static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn,
+ struct l2cap_cmd_hdr *cmd, u16 cmd_len,
+ u8 *data)
{
struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data;
u16 dcid, scid;
struct l2cap_chan *chan;
struct sock *sk;
{
struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data;
u16 dcid, scid;
struct l2cap_chan *chan;
struct sock *sk;
+ if (cmd_len != sizeof(*rsp))
+ return -EPROTO;
+
scid = __le16_to_cpu(rsp->scid);
dcid = __le16_to_cpu(rsp->dcid);
scid = __le16_to_cpu(rsp->scid);
dcid = __le16_to_cpu(rsp->dcid);
@@
-2774,11
+2831,16
@@
static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd
return 0;
}
return 0;
}
-static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
+static inline int l2cap_information_req(struct l2cap_conn *conn,
+ struct l2cap_cmd_hdr *cmd, u16 cmd_len,
+ u8 *data)
{
struct l2cap_info_req *req = (struct l2cap_info_req *) data;
u16 type;
{
struct l2cap_info_req *req = (struct l2cap_info_req *) data;
u16 type;
+ if (cmd_len != sizeof(*req))
+ return -EPROTO;
+
type = __le16_to_cpu(req->type);
BT_DBG("type 0x%4.4x", type);
type = __le16_to_cpu(req->type);
BT_DBG("type 0x%4.4x", type);
@@
-2814,11
+2876,16
@@
static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cm
return 0;
}
return 0;
}
-static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
+static inline int l2cap_information_rsp(struct l2cap_conn *conn,
+ struct l2cap_cmd_hdr *cmd, u16 cmd_len,
+ u8 *data)
{
struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) data;
u16 type, result;
{
struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) data;
u16 type, result;
+ if (cmd_len < sizeof(*rsp))
+ return -EPROTO;
+
type = __le16_to_cpu(rsp->type);
result = __le16_to_cpu(rsp->result);
type = __le16_to_cpu(rsp->type);
result = __le16_to_cpu(rsp->result);
@@
-2937,15
+3004,15
@@
static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
switch (cmd->code) {
case L2CAP_COMMAND_REJ:
switch (cmd->code) {
case L2CAP_COMMAND_REJ:
- l2cap_command_rej(conn, cmd, data);
+ l2cap_command_rej(conn, cmd,
cmd_len,
data);
break;
case L2CAP_CONN_REQ:
break;
case L2CAP_CONN_REQ:
- err = l2cap_connect_req(conn, cmd, data);
+ err = l2cap_connect_req(conn, cmd,
cmd_len,
data);
break;
case L2CAP_CONN_RSP:
break;
case L2CAP_CONN_RSP:
- err = l2cap_connect_rsp(conn, cmd, data);
+ err = l2cap_connect_rsp(conn, cmd,
cmd_len,
data);
break;
case L2CAP_CONF_REQ:
break;
case L2CAP_CONF_REQ:
@@
-2953,15
+3020,15
@@
static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
break;
case L2CAP_CONF_RSP:
break;
case L2CAP_CONF_RSP:
- err = l2cap_config_rsp(conn, cmd, data);
+ err = l2cap_config_rsp(conn, cmd,
cmd_len,
data);
break;
case L2CAP_DISCONN_REQ:
break;
case L2CAP_DISCONN_REQ:
- err = l2cap_disconnect_req(conn, cmd, data);
+ err = l2cap_disconnect_req(conn, cmd,
cmd_len,
data);
break;
case L2CAP_DISCONN_RSP:
break;
case L2CAP_DISCONN_RSP:
- err = l2cap_disconnect_rsp(conn, cmd, data);
+ err = l2cap_disconnect_rsp(conn, cmd,
cmd_len,
data);
break;
case L2CAP_ECHO_REQ:
break;
case L2CAP_ECHO_REQ:
@@
-2972,11
+3039,11
@@
static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
break;
case L2CAP_INFO_REQ:
break;
case L2CAP_INFO_REQ:
- err = l2cap_information_req(conn, cmd, data);
+ err = l2cap_information_req(conn, cmd,
cmd_len,
data);
break;
case L2CAP_INFO_RSP:
break;
case L2CAP_INFO_RSP:
- err = l2cap_information_rsp(conn, cmd, data);
+ err = l2cap_information_rsp(conn, cmd,
cmd_len,
data);
break;
default:
break;
default: