forked from Minki/linux
[Bluetooth] Fall back to L2CAP in basic mode
In case the remote entity tries to negogiate retransmission or flow control mode, reject it and fall back to basic mode. Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
This commit is contained in:
parent
f0709e03ac
commit
6464f35f37
@ -149,6 +149,19 @@ struct l2cap_conf_opt {
|
||||
|
||||
#define L2CAP_CONF_MAX_SIZE 22
|
||||
|
||||
struct l2cap_conf_rfc {
|
||||
__u8 mode;
|
||||
__u8 txwin_size;
|
||||
__u8 max_transmit;
|
||||
__le16 retrans_timeout;
|
||||
__le16 monitor_timeout;
|
||||
__le16 max_pdu_size;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define L2CAP_MODE_BASIC 0x00
|
||||
#define L2CAP_MODE_RETRANS 0x01
|
||||
#define L2CAP_MODE_FLOWCTL 0x02
|
||||
|
||||
struct l2cap_disconn_req {
|
||||
__le16 dcid;
|
||||
__le16 scid;
|
||||
|
@ -1048,7 +1048,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
|
||||
opts.imtu = l2cap_pi(sk)->imtu;
|
||||
opts.omtu = l2cap_pi(sk)->omtu;
|
||||
opts.flush_to = l2cap_pi(sk)->flush_to;
|
||||
opts.mode = 0x00;
|
||||
opts.mode = L2CAP_MODE_BASIC;
|
||||
|
||||
len = min_t(unsigned int, sizeof(opts), optlen);
|
||||
if (copy_from_user((char *) &opts, optval, len)) {
|
||||
@ -1097,7 +1097,7 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
|
||||
opts.imtu = l2cap_pi(sk)->imtu;
|
||||
opts.omtu = l2cap_pi(sk)->omtu;
|
||||
opts.flush_to = l2cap_pi(sk)->flush_to;
|
||||
opts.mode = 0x00;
|
||||
opts.mode = L2CAP_MODE_BASIC;
|
||||
|
||||
len = min_t(unsigned int, len, sizeof(opts));
|
||||
if (copy_to_user(optval, (char *) &opts, len))
|
||||
@ -1376,6 +1376,7 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data)
|
||||
int len = pi->conf_len;
|
||||
int type, hint, olen;
|
||||
unsigned long val;
|
||||
struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
|
||||
u16 mtu = L2CAP_DEFAULT_MTU;
|
||||
u16 result = L2CAP_CONF_SUCCESS;
|
||||
|
||||
@ -1399,6 +1400,11 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data)
|
||||
case L2CAP_CONF_QOS:
|
||||
break;
|
||||
|
||||
case L2CAP_CONF_RFC:
|
||||
if (olen == sizeof(rfc))
|
||||
memcpy(&rfc, (void *) val, olen);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (hint)
|
||||
break;
|
||||
@ -1413,14 +1419,24 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data)
|
||||
/* Configure output options and let the other side know
|
||||
* which ones we don't like. */
|
||||
|
||||
if (mtu < pi->omtu)
|
||||
result = L2CAP_CONF_UNACCEPT;
|
||||
else {
|
||||
pi->omtu = mtu;
|
||||
pi->conf_state |= L2CAP_CONF_OUTPUT_DONE;
|
||||
}
|
||||
if (rfc.mode == L2CAP_MODE_BASIC) {
|
||||
if (mtu < pi->omtu)
|
||||
result = L2CAP_CONF_UNACCEPT;
|
||||
else {
|
||||
pi->omtu = mtu;
|
||||
pi->conf_state |= L2CAP_CONF_OUTPUT_DONE;
|
||||
}
|
||||
|
||||
l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->omtu);
|
||||
l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->omtu);
|
||||
} else {
|
||||
result = L2CAP_CONF_UNACCEPT;
|
||||
|
||||
memset(&rfc, 0, sizeof(rfc));
|
||||
rfc.mode = L2CAP_MODE_BASIC;
|
||||
|
||||
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
|
||||
sizeof(rfc), (unsigned long) &rfc);
|
||||
}
|
||||
}
|
||||
|
||||
rsp->scid = cpu_to_le16(pi->dcid);
|
||||
|
Loading…
Reference in New Issue
Block a user