aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth
diff options
context:
space:
mode:
authorMarcel Holtmann <marcel@holtmann.org>2007-10-20 13:39:51 +0200
committerDavid S. Miller <davem@sunset.davemloft.net>2007-10-22 02:59:43 -0700
commit6464f35f3771f69cd8d107fff166dc29ab392f97 (patch)
treeb737bc19dfd6decc6769a425491e0e0b06687d1b /net/bluetooth
parent[Bluetooth] Advertise L2CAP features mask support (diff)
downloadlinux-dev-6464f35f3771f69cd8d107fff166dc29ab392f97.tar.xz
linux-dev-6464f35f3771f69cd8d107fff166dc29ab392f97.zip
[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>
Diffstat (limited to 'net/bluetooth')
-rw-r--r--net/bluetooth/l2cap.c32
1 files changed, 24 insertions, 8 deletions
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
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)
+ 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);
+ } else {
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);
+ 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);