aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrei Emeltchenko <andrei.emeltchenko@intel.com>2011-10-11 06:37:42 -0400
committerGustavo F. Padovan <padovan@profusion.mobi>2011-10-13 15:44:26 -0400
commit6327eb980d2ff0c96363b81cb0ce580165cb81b8 (patch)
treea6351655b16aa61dfa26543fb3a47b54f0321827
parent669bb3962bd7f781879222eeb7263d527551dd5e (diff)
Bluetooth: EWS: extended window size option support
Adds support for extended window size (EWS) config option. We enable EWS feature in L2CAP Info RSP when hs enabled. EWS option is included in L2CAP Config Req if tx_win (which is set via socket) bigger then standard default value (63) && hs enabled && remote side supports EWS feature. Using EWS selects extended control field in L2CAP. Code partly based on Qualcomm and Atheros patches sent upstream a year ago. Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com> Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
-rw-r--r--include/net/bluetooth/l2cap.h8
-rw-r--r--net/bluetooth/l2cap_core.c51
-rw-r--r--net/bluetooth/l2cap_sock.c8
3 files changed, 58 insertions, 9 deletions
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 08ad40bb5a46..51998ff6b8ca 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -32,6 +32,7 @@
32#define L2CAP_DEFAULT_MIN_MTU 48 32#define L2CAP_DEFAULT_MIN_MTU 48
33#define L2CAP_DEFAULT_FLUSH_TO 0xffff 33#define L2CAP_DEFAULT_FLUSH_TO 0xffff
34#define L2CAP_DEFAULT_TX_WINDOW 63 34#define L2CAP_DEFAULT_TX_WINDOW 63
35#define L2CAP_DEFAULT_EXT_WINDOW 0x3FFF
35#define L2CAP_DEFAULT_MAX_TX 3 36#define L2CAP_DEFAULT_MAX_TX 3
36#define L2CAP_DEFAULT_RETRANS_TO 2000 /* 2 seconds */ 37#define L2CAP_DEFAULT_RETRANS_TO 2000 /* 2 seconds */
37#define L2CAP_DEFAULT_MONITOR_TO 12000 /* 12 seconds */ 38#define L2CAP_DEFAULT_MONITOR_TO 12000 /* 12 seconds */
@@ -233,6 +234,7 @@ struct l2cap_conf_opt {
233#define L2CAP_CONF_QOS 0x03 234#define L2CAP_CONF_QOS 0x03
234#define L2CAP_CONF_RFC 0x04 235#define L2CAP_CONF_RFC 0x04
235#define L2CAP_CONF_FCS 0x05 236#define L2CAP_CONF_FCS 0x05
237#define L2CAP_CONF_EWS 0x07
236 238
237#define L2CAP_CONF_MAX_SIZE 22 239#define L2CAP_CONF_MAX_SIZE 22
238 240
@@ -333,7 +335,7 @@ struct l2cap_chan {
333 335
334 __u8 fcs; 336 __u8 fcs;
335 337
336 __u8 tx_win; 338 __u16 tx_win;
337 __u8 max_tx; 339 __u8 max_tx;
338 __u16 retrans_timeout; 340 __u16 retrans_timeout;
339 __u16 monitor_timeout; 341 __u16 monitor_timeout;
@@ -357,7 +359,7 @@ struct l2cap_chan {
357 struct sk_buff *sdu; 359 struct sk_buff *sdu;
358 struct sk_buff *sdu_last_frag; 360 struct sk_buff *sdu_last_frag;
359 361
360 __u8 remote_tx_win; 362 __u16 remote_tx_win;
361 __u8 remote_max_tx; 363 __u8 remote_max_tx;
362 __u16 remote_mps; 364 __u16 remote_mps;
363 365
@@ -442,6 +444,7 @@ enum {
442 CONF_CONNECT_PEND, 444 CONF_CONNECT_PEND,
443 CONF_NO_FCS_RECV, 445 CONF_NO_FCS_RECV,
444 CONF_STATE2_DEVICE, 446 CONF_STATE2_DEVICE,
447 CONF_EWS_RECV,
445}; 448};
446 449
447#define L2CAP_CONF_MAX_CONF_REQ 2 450#define L2CAP_CONF_MAX_CONF_REQ 2
@@ -465,6 +468,7 @@ enum {
465 FLAG_FORCE_ACTIVE, 468 FLAG_FORCE_ACTIVE,
466 FLAG_FORCE_RELIABLE, 469 FLAG_FORCE_RELIABLE,
467 FLAG_FLUSHABLE, 470 FLAG_FLUSHABLE,
471 FLAG_EXT_CTRL,
468}; 472};
469 473
470#define __set_chan_timer(c, t) l2cap_set_timer(c, &c->chan_timer, (t)) 474#define __set_chan_timer(c, t) l2cap_set_timer(c, &c->chan_timer, (t))
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 18a08c59f083..6e343126f388 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -1898,6 +1898,22 @@ static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
1898 } 1898 }
1899} 1899}
1900 1900
1901static inline bool __l2cap_ews_supported(struct l2cap_chan *chan)
1902{
1903 return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_WINDOW;
1904}
1905
1906static inline void l2cap_txwin_setup(struct l2cap_chan *chan)
1907{
1908 if (chan->tx_win > L2CAP_DEFAULT_TX_WINDOW &&
1909 __l2cap_ews_supported(chan))
1910 /* use extended control field */
1911 set_bit(FLAG_EXT_CTRL, &chan->flags);
1912 else
1913 chan->tx_win = min_t(u16, chan->tx_win,
1914 L2CAP_DEFAULT_TX_WINDOW);
1915}
1916
1901static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data) 1917static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
1902{ 1918{
1903 struct l2cap_conf_req *req = data; 1919 struct l2cap_conf_req *req = data;
@@ -1944,7 +1960,6 @@ done:
1944 1960
1945 case L2CAP_MODE_ERTM: 1961 case L2CAP_MODE_ERTM:
1946 rfc.mode = L2CAP_MODE_ERTM; 1962 rfc.mode = L2CAP_MODE_ERTM;
1947 rfc.txwin_size = chan->tx_win;
1948 rfc.max_transmit = chan->max_tx; 1963 rfc.max_transmit = chan->max_tx;
1949 rfc.retrans_timeout = 0; 1964 rfc.retrans_timeout = 0;
1950 rfc.monitor_timeout = 0; 1965 rfc.monitor_timeout = 0;
@@ -1952,6 +1967,11 @@ done:
1952 if (L2CAP_DEFAULT_MAX_PDU_SIZE > chan->conn->mtu - 10) 1967 if (L2CAP_DEFAULT_MAX_PDU_SIZE > chan->conn->mtu - 10)
1953 rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10); 1968 rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
1954 1969
1970 l2cap_txwin_setup(chan);
1971
1972 rfc.txwin_size = min_t(u16, chan->tx_win,
1973 L2CAP_DEFAULT_TX_WINDOW);
1974
1955 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc), 1975 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
1956 (unsigned long) &rfc); 1976 (unsigned long) &rfc);
1957 1977
@@ -1963,6 +1983,10 @@ done:
1963 chan->fcs = L2CAP_FCS_NONE; 1983 chan->fcs = L2CAP_FCS_NONE;
1964 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs); 1984 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
1965 } 1985 }
1986
1987 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
1988 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
1989 chan->tx_win);
1966 break; 1990 break;
1967 1991
1968 case L2CAP_MODE_STREAMING: 1992 case L2CAP_MODE_STREAMING:
@@ -2038,6 +2062,15 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
2038 2062
2039 break; 2063 break;
2040 2064
2065 case L2CAP_CONF_EWS:
2066 if (!enable_hs)
2067 return -ECONNREFUSED;
2068
2069 set_bit(FLAG_EXT_CTRL, &chan->flags);
2070 set_bit(CONF_EWS_RECV, &chan->conf_state);
2071 chan->remote_tx_win = val;
2072 break;
2073
2041 default: 2074 default:
2042 if (hint) 2075 if (hint)
2043 break; 2076 break;
@@ -2098,7 +2131,11 @@ done:
2098 break; 2131 break;
2099 2132
2100 case L2CAP_MODE_ERTM: 2133 case L2CAP_MODE_ERTM:
2101 chan->remote_tx_win = rfc.txwin_size; 2134 if (!test_bit(CONF_EWS_RECV, &chan->conf_state))
2135 chan->remote_tx_win = rfc.txwin_size;
2136 else
2137 rfc.txwin_size = L2CAP_DEFAULT_TX_WINDOW;
2138
2102 chan->remote_max_tx = rfc.max_transmit; 2139 chan->remote_max_tx = rfc.max_transmit;
2103 2140
2104 if (le16_to_cpu(rfc.max_pdu_size) > chan->conn->mtu - 10) 2141 if (le16_to_cpu(rfc.max_pdu_size) > chan->conn->mtu - 10)
@@ -2190,6 +2227,13 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi
2190 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, 2227 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2191 sizeof(rfc), (unsigned long) &rfc); 2228 sizeof(rfc), (unsigned long) &rfc);
2192 break; 2229 break;
2230
2231 case L2CAP_CONF_EWS:
2232 chan->tx_win = min_t(u16, val,
2233 L2CAP_DEFAULT_EXT_WINDOW);
2234 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS,
2235 2, chan->tx_win);
2236 break;
2193 } 2237 }
2194 } 2238 }
2195 2239
@@ -2785,7 +2829,8 @@ static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cm
2785 feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING 2829 feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING
2786 | L2CAP_FEAT_FCS; 2830 | L2CAP_FEAT_FCS;
2787 if (enable_hs) 2831 if (enable_hs)
2788 feat_mask |= L2CAP_FEAT_EXT_FLOW; 2832 feat_mask |= L2CAP_FEAT_EXT_FLOW
2833 | L2CAP_FEAT_EXT_WINDOW;
2789 2834
2790 put_unaligned_le32(feat_mask, rsp->data); 2835 put_unaligned_le32(feat_mask, rsp->data);
2791 l2cap_send_cmd(conn, cmd->ident, 2836 l2cap_send_cmd(conn, cmd->ident,
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 48ad8ba492a5..836d12e66a38 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -331,7 +331,7 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us
331 opts.mode = chan->mode; 331 opts.mode = chan->mode;
332 opts.fcs = chan->fcs; 332 opts.fcs = chan->fcs;
333 opts.max_tx = chan->max_tx; 333 opts.max_tx = chan->max_tx;
334 opts.txwin_size = (__u16)chan->tx_win; 334 opts.txwin_size = chan->tx_win;
335 335
336 len = min_t(unsigned int, len, sizeof(opts)); 336 len = min_t(unsigned int, len, sizeof(opts));
337 if (copy_to_user(optval, (char *) &opts, len)) 337 if (copy_to_user(optval, (char *) &opts, len))
@@ -501,7 +501,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
501 opts.mode = chan->mode; 501 opts.mode = chan->mode;
502 opts.fcs = chan->fcs; 502 opts.fcs = chan->fcs;
503 opts.max_tx = chan->max_tx; 503 opts.max_tx = chan->max_tx;
504 opts.txwin_size = (__u16)chan->tx_win; 504 opts.txwin_size = chan->tx_win;
505 505
506 len = min_t(unsigned int, sizeof(opts), optlen); 506 len = min_t(unsigned int, sizeof(opts), optlen);
507 if (copy_from_user((char *) &opts, optval, len)) { 507 if (copy_from_user((char *) &opts, optval, len)) {
@@ -509,7 +509,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
509 break; 509 break;
510 } 510 }
511 511
512 if (opts.txwin_size > L2CAP_DEFAULT_TX_WINDOW) { 512 if (opts.txwin_size > L2CAP_DEFAULT_EXT_WINDOW) {
513 err = -EINVAL; 513 err = -EINVAL;
514 break; 514 break;
515 } 515 }
@@ -533,7 +533,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
533 chan->omtu = opts.omtu; 533 chan->omtu = opts.omtu;
534 chan->fcs = opts.fcs; 534 chan->fcs = opts.fcs;
535 chan->max_tx = opts.max_tx; 535 chan->max_tx = opts.max_tx;
536 chan->tx_win = (__u8)opts.txwin_size; 536 chan->tx_win = opts.txwin_size;
537 break; 537 break;
538 538
539 case L2CAP_LM: 539 case L2CAP_LM: