aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth
diff options
context:
space:
mode:
authorMat Martineau <mathewm@codeaurora.org>2012-07-10 08:47:07 -0400
committerGustavo Padovan <gustavo.padovan@collabora.co.uk>2012-07-15 11:18:29 -0400
commitc20f8e35ca8b0583323d310ec63a0f0d17cfdcf5 (patch)
treece775fec3821cc1cf9548b51ef10c980fe33c7e5 /net/bluetooth
parenta0dfe0ab6bf194805ce9d6a2dc81efab7a4a7fda (diff)
Bluetooth: Use tx window from config response for ack timing
This change addresses an L2CAP ERTM throughput problem when a remote device does not fully utilize the available transmit window. The L2CAP ERTM transmit window size determines the maximum number of unacked frames that may be outstanding at any time. It is configured separately for each direction of an ERTM connection. Each side sends a configuration request with a tx_win field indicating how many unacked frames it is capable of receiving before sending an ack. The configuration response's tx_win field shows how many frames the transmitter will actually send before waiting for an ack. It's important to trace both the actual transmit window (to check for validity of incoming frames) and the number of frames that the transmitter will send before waiting (to send acks at the appropriate time). Now there are separate tx_win and ack_win values. ack_win is updated based on configuration responses, and is used to determine when acks are sent. Signed-off-by: Mat Martineau <mathewm@codeaurora.org> Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Diffstat (limited to 'net/bluetooth')
-rw-r--r--net/bluetooth/l2cap_core.c59
1 files changed, 34 insertions, 25 deletions
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 9fd05993f5b4..a8964db04bfb 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -431,6 +431,7 @@ void l2cap_chan_set_defaults(struct l2cap_chan *chan)
431 chan->max_tx = L2CAP_DEFAULT_MAX_TX; 431 chan->max_tx = L2CAP_DEFAULT_MAX_TX;
432 chan->tx_win = L2CAP_DEFAULT_TX_WINDOW; 432 chan->tx_win = L2CAP_DEFAULT_TX_WINDOW;
433 chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW; 433 chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW;
434 chan->ack_win = L2CAP_DEFAULT_TX_WINDOW;
434 chan->sec_level = BT_SECURITY_LOW; 435 chan->sec_level = BT_SECURITY_LOW;
435 436
436 set_bit(FLAG_FORCE_ACTIVE, &chan->flags); 437 set_bit(FLAG_FORCE_ACTIVE, &chan->flags);
@@ -1877,10 +1878,10 @@ static void l2cap_send_ack(struct l2cap_chan *chan)
1877 frames_to_ack = 0; 1878 frames_to_ack = 0;
1878 } 1879 }
1879 1880
1880 /* Ack now if the tx window is 3/4ths full. 1881 /* Ack now if the window is 3/4ths full.
1881 * Calculate without mul or div 1882 * Calculate without mul or div
1882 */ 1883 */
1883 threshold = chan->tx_win; 1884 threshold = chan->ack_win;
1884 threshold += threshold << 1; 1885 threshold += threshold << 1;
1885 threshold >>= 2; 1886 threshold >>= 2;
1886 1887
@@ -2786,6 +2787,7 @@ static inline void l2cap_txwin_setup(struct l2cap_chan *chan)
2786 L2CAP_DEFAULT_TX_WINDOW); 2787 L2CAP_DEFAULT_TX_WINDOW);
2787 chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW; 2788 chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW;
2788 } 2789 }
2790 chan->ack_win = chan->tx_win;
2789} 2791}
2790 2792
2791static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data) 2793static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
@@ -3175,10 +3177,9 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi
3175 break; 3177 break;
3176 3178
3177 case L2CAP_CONF_EWS: 3179 case L2CAP_CONF_EWS:
3178 chan->tx_win = min_t(u16, val, 3180 chan->ack_win = min_t(u16, val, chan->ack_win);
3179 L2CAP_DEFAULT_EXT_WINDOW);
3180 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2, 3181 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
3181 chan->tx_win); 3182 chan->tx_win);
3182 break; 3183 break;
3183 3184
3184 case L2CAP_CONF_EFS: 3185 case L2CAP_CONF_EFS:
@@ -3207,6 +3208,9 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi
3207 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout); 3208 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
3208 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout); 3209 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
3209 chan->mps = le16_to_cpu(rfc.max_pdu_size); 3210 chan->mps = le16_to_cpu(rfc.max_pdu_size);
3211 if (!test_bit(FLAG_EXT_CTRL, &chan->flags))
3212 chan->ack_win = min_t(u16, chan->ack_win,
3213 rfc.txwin_size);
3210 3214
3211 if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) { 3215 if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
3212 chan->local_msdu = le16_to_cpu(efs.msdu); 3216 chan->local_msdu = le16_to_cpu(efs.msdu);
@@ -3268,7 +3272,17 @@ static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len)
3268{ 3272{
3269 int type, olen; 3273 int type, olen;
3270 unsigned long val; 3274 unsigned long val;
3271 struct l2cap_conf_rfc rfc; 3275 /* Use sane default values in case a misbehaving remote device
3276 * did not send an RFC or extended window size option.
3277 */
3278 u16 txwin_ext = chan->ack_win;
3279 struct l2cap_conf_rfc rfc = {
3280 .mode = chan->mode,
3281 .retrans_timeout = __constant_cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO),
3282 .monitor_timeout = __constant_cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO),
3283 .max_pdu_size = cpu_to_le16(chan->imtu),
3284 .txwin_size = min_t(u16, chan->ack_win, L2CAP_DEFAULT_TX_WINDOW),
3285 };
3272 3286
3273 BT_DBG("chan %p, rsp %p, len %d", chan, rsp, len); 3287 BT_DBG("chan %p, rsp %p, len %d", chan, rsp, len);
3274 3288
@@ -3278,32 +3292,27 @@ static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len)
3278 while (len >= L2CAP_CONF_OPT_SIZE) { 3292 while (len >= L2CAP_CONF_OPT_SIZE) {
3279 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val); 3293 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
3280 3294
3281 if (type != L2CAP_CONF_RFC) 3295 switch (type) {
3282 continue; 3296 case L2CAP_CONF_RFC:
3283 3297 if (olen == sizeof(rfc))
3284 if (olen != sizeof(rfc)) 3298 memcpy(&rfc, (void *)val, olen);
3285 break; 3299 break;
3286 3300 case L2CAP_CONF_EWS:
3287 memcpy(&rfc, (void *)val, olen); 3301 txwin_ext = val;
3288 goto done; 3302 break;
3303 }
3289 } 3304 }
3290 3305
3291 /* Use sane default values in case a misbehaving remote device
3292 * did not send an RFC option.
3293 */
3294 rfc.mode = chan->mode;
3295 rfc.retrans_timeout = __constant_cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO);
3296 rfc.monitor_timeout = __constant_cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO);
3297 rfc.max_pdu_size = cpu_to_le16(chan->imtu);
3298
3299 BT_ERR("Expected RFC option was not found, using defaults");
3300
3301done:
3302 switch (rfc.mode) { 3306 switch (rfc.mode) {
3303 case L2CAP_MODE_ERTM: 3307 case L2CAP_MODE_ERTM:
3304 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout); 3308 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
3305 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout); 3309 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
3306 chan->mps = le16_to_cpu(rfc.max_pdu_size); 3310 chan->mps = le16_to_cpu(rfc.max_pdu_size);
3311 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
3312 chan->ack_win = min_t(u16, chan->ack_win, txwin_ext);
3313 else
3314 chan->ack_win = min_t(u16, chan->ack_win,
3315 rfc.txwin_size);
3307 break; 3316 break;
3308 case L2CAP_MODE_STREAMING: 3317 case L2CAP_MODE_STREAMING:
3309 chan->mps = le16_to_cpu(rfc.max_pdu_size); 3318 chan->mps = le16_to_cpu(rfc.max_pdu_size);