[Bluetooth] Fall back to L2CAP in basic mode
authorMarcel Holtmann <marcel@holtmann.org>
Sat, 20 Oct 2007 11:39:51 +0000 (13:39 +0200)
committerDavid S. Miller <davem@sunset.davemloft.net>
Mon, 22 Oct 2007 09:59:43 +0000 (02:59 -0700)
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>
include/net/bluetooth/l2cap.h
net/bluetooth/l2cap.c

index e1ea64085c4fd5111a7e460b0f914621aa8edf33..73e115bc12dda4f688555c087d0c98558373d576 100644 (file)
@@ -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;
index 733c95dbd07e930bb5956a3ad265f1b9f863695f..6fbbae78b30452c8ee6e20742d011ebaba4acc11 100644 (file)
@@ -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);