Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os 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>

authored by

Marcel Holtmann and committed by
David S. Miller
6464f35f f0709e03

+38 -9
+13
include/net/bluetooth/l2cap.h
··· 149 149 150 150 #define L2CAP_CONF_MAX_SIZE 22 151 151 152 + struct l2cap_conf_rfc { 153 + __u8 mode; 154 + __u8 txwin_size; 155 + __u8 max_transmit; 156 + __le16 retrans_timeout; 157 + __le16 monitor_timeout; 158 + __le16 max_pdu_size; 159 + } __attribute__ ((packed)); 160 + 161 + #define L2CAP_MODE_BASIC 0x00 162 + #define L2CAP_MODE_RETRANS 0x01 163 + #define L2CAP_MODE_FLOWCTL 0x02 164 + 152 165 struct l2cap_disconn_req { 153 166 __le16 dcid; 154 167 __le16 scid;
+25 -9
net/bluetooth/l2cap.c
··· 1048 1048 opts.imtu = l2cap_pi(sk)->imtu; 1049 1049 opts.omtu = l2cap_pi(sk)->omtu; 1050 1050 opts.flush_to = l2cap_pi(sk)->flush_to; 1051 - opts.mode = 0x00; 1051 + opts.mode = L2CAP_MODE_BASIC; 1052 1052 1053 1053 len = min_t(unsigned int, sizeof(opts), optlen); 1054 1054 if (copy_from_user((char *) &opts, optval, len)) { ··· 1097 1097 opts.imtu = l2cap_pi(sk)->imtu; 1098 1098 opts.omtu = l2cap_pi(sk)->omtu; 1099 1099 opts.flush_to = l2cap_pi(sk)->flush_to; 1100 - opts.mode = 0x00; 1100 + opts.mode = L2CAP_MODE_BASIC; 1101 1101 1102 1102 len = min_t(unsigned int, len, sizeof(opts)); 1103 1103 if (copy_to_user(optval, (char *) &opts, len)) ··· 1376 1376 int len = pi->conf_len; 1377 1377 int type, hint, olen; 1378 1378 unsigned long val; 1379 + struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC }; 1379 1380 u16 mtu = L2CAP_DEFAULT_MTU; 1380 1381 u16 result = L2CAP_CONF_SUCCESS; 1381 1382 ··· 1400 1399 case L2CAP_CONF_QOS: 1401 1400 break; 1402 1401 1402 + case L2CAP_CONF_RFC: 1403 + if (olen == sizeof(rfc)) 1404 + memcpy(&rfc, (void *) val, olen); 1405 + break; 1406 + 1403 1407 default: 1404 1408 if (hint) 1405 1409 break; ··· 1419 1413 /* Configure output options and let the other side know 1420 1414 * which ones we don't like. */ 1421 1415 1422 - if (mtu < pi->omtu) 1423 - result = L2CAP_CONF_UNACCEPT; 1424 - else { 1425 - pi->omtu = mtu; 1426 - pi->conf_state |= L2CAP_CONF_OUTPUT_DONE; 1427 - } 1416 + if (rfc.mode == L2CAP_MODE_BASIC) { 1417 + if (mtu < pi->omtu) 1418 + result = L2CAP_CONF_UNACCEPT; 1419 + else { 1420 + pi->omtu = mtu; 1421 + pi->conf_state |= L2CAP_CONF_OUTPUT_DONE; 1422 + } 1428 1423 1429 - l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->omtu); 1424 + l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->omtu); 1425 + } else { 1426 + result = L2CAP_CONF_UNACCEPT; 1427 + 1428 + memset(&rfc, 0, sizeof(rfc)); 1429 + rfc.mode = L2CAP_MODE_BASIC; 1430 + 1431 + l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, 1432 + sizeof(rfc), (unsigned long) &rfc); 1433 + } 1430 1434 } 1431 1435 1432 1436 rsp->scid = cpu_to_le16(pi->dcid);