aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarcel Holtmann <marcel@holtmann.org>2007-10-20 07:39:51 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-10-22 05:59:43 -0400
commit6464f35f3771f69cd8d107fff166dc29ab392f97 (patch)
treeb737bc19dfd6decc6769a425491e0e0b06687d1b
parentf0709e03ac3552b1b048ee171cb96ecaacc6813c (diff)
[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>
-rw-r--r--include/net/bluetooth/l2cap.h13
-rw-r--r--net/bluetooth/l2cap.c32
2 files changed, 37 insertions, 8 deletions
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index e1ea64085c4f..73e115bc12dd 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -149,6 +149,19 @@ struct l2cap_conf_opt {
149 149
150#define L2CAP_CONF_MAX_SIZE 22 150#define L2CAP_CONF_MAX_SIZE 22
151 151
152struct 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
152struct l2cap_disconn_req { 165struct l2cap_disconn_req {
153 __le16 dcid; 166 __le16 dcid;
154 __le16 scid; 167 __le16 scid;
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index 733c95dbd07e..6fbbae78b304 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -1048,7 +1048,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
1048 opts.imtu = l2cap_pi(sk)->imtu; 1048 opts.imtu = l2cap_pi(sk)->imtu;
1049 opts.omtu = l2cap_pi(sk)->omtu; 1049 opts.omtu = l2cap_pi(sk)->omtu;
1050 opts.flush_to = l2cap_pi(sk)->flush_to; 1050 opts.flush_to = l2cap_pi(sk)->flush_to;
1051 opts.mode = 0x00; 1051 opts.mode = L2CAP_MODE_BASIC;
1052 1052
1053 len = min_t(unsigned int, sizeof(opts), optlen); 1053 len = min_t(unsigned int, sizeof(opts), optlen);
1054 if (copy_from_user((char *) &opts, optval, len)) { 1054 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
1097 opts.imtu = l2cap_pi(sk)->imtu; 1097 opts.imtu = l2cap_pi(sk)->imtu;
1098 opts.omtu = l2cap_pi(sk)->omtu; 1098 opts.omtu = l2cap_pi(sk)->omtu;
1099 opts.flush_to = l2cap_pi(sk)->flush_to; 1099 opts.flush_to = l2cap_pi(sk)->flush_to;
1100 opts.mode = 0x00; 1100 opts.mode = L2CAP_MODE_BASIC;
1101 1101
1102 len = min_t(unsigned int, len, sizeof(opts)); 1102 len = min_t(unsigned int, len, sizeof(opts));
1103 if (copy_to_user(optval, (char *) &opts, len)) 1103 if (copy_to_user(optval, (char *) &opts, len))
@@ -1376,6 +1376,7 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data)
1376 int len = pi->conf_len; 1376 int len = pi->conf_len;
1377 int type, hint, olen; 1377 int type, hint, olen;
1378 unsigned long val; 1378 unsigned long val;
1379 struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
1379 u16 mtu = L2CAP_DEFAULT_MTU; 1380 u16 mtu = L2CAP_DEFAULT_MTU;
1380 u16 result = L2CAP_CONF_SUCCESS; 1381 u16 result = L2CAP_CONF_SUCCESS;
1381 1382
@@ -1399,6 +1400,11 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data)
1399 case L2CAP_CONF_QOS: 1400 case L2CAP_CONF_QOS:
1400 break; 1401 break;
1401 1402
1403 case L2CAP_CONF_RFC:
1404 if (olen == sizeof(rfc))
1405 memcpy(&rfc, (void *) val, olen);
1406 break;
1407
1402 default: 1408 default:
1403 if (hint) 1409 if (hint)
1404 break; 1410 break;
@@ -1413,14 +1419,24 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data)
1413 /* Configure output options and let the other side know 1419 /* Configure output options and let the other side know
1414 * which ones we don't like. */ 1420 * which ones we don't like. */
1415 1421
1416 if (mtu < pi->omtu) 1422 if (rfc.mode == L2CAP_MODE_BASIC) {
1423 if (mtu < pi->omtu)
1424 result = L2CAP_CONF_UNACCEPT;
1425 else {
1426 pi->omtu = mtu;
1427 pi->conf_state |= L2CAP_CONF_OUTPUT_DONE;
1428 }
1429
1430 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->omtu);
1431 } else {
1417 result = L2CAP_CONF_UNACCEPT; 1432 result = L2CAP_CONF_UNACCEPT;
1418 else {
1419 pi->omtu = mtu;
1420 pi->conf_state |= L2CAP_CONF_OUTPUT_DONE;
1421 }
1422 1433
1423 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->omtu); 1434 memset(&rfc, 0, sizeof(rfc));
1435 rfc.mode = L2CAP_MODE_BASIC;
1436
1437 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
1438 sizeof(rfc), (unsigned long) &rfc);
1439 }
1424 } 1440 }
1425 1441
1426 rsp->scid = cpu_to_le16(pi->dcid); 1442 rsp->scid = cpu_to_le16(pi->dcid);