aboutsummaryrefslogtreecommitdiffstats
path: root/net
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 /net
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>
Diffstat (limited to 'net')
-rw-r--r--net/bluetooth/l2cap_core.c51
-rw-r--r--net/bluetooth/l2cap_sock.c8
2 files changed, 52 insertions, 7 deletions
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: