diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 9a03a127ad0..893aeea0792 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -534,6 +534,7 @@ struct l2cap_pinfo { __u16 tx_win; __u16 tx_win_max; + __u16 ack_win; __u8 max_tx; __u8 amp_pref; __u16 remote_tx_win; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 980b8464c0e..e9e85214075 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1993,10 +1993,10 @@ static void l2cap_ertm_send_ack(struct sock *sk) frames_to_ack = 0; } - /* Ack now if the tx window is 3/4ths full. + /* Ack now if the window is 3/4ths full. * Calculate without mul or div */ - threshold = pi->tx_win; + threshold = pi->ack_win; threshold += threshold << 1; threshold >>= 2; @@ -3105,6 +3105,7 @@ static void l2cap_setup_txwin(struct l2cap_pinfo *pi) pi->tx_win_max = L2CAP_TX_WIN_MAX_ENHANCED; pi->extended_control = 0; } + pi->ack_win = pi->tx_win; } static void l2cap_aggregate_fs(struct hci_ext_fs *cur, @@ -3844,10 +3845,7 @@ static int l2cap_parse_conf_rsp(struct sock *sk, void *rsp, int len, void *data, break; case L2CAP_CONF_EXT_WINDOW: - pi->tx_win = val; - - if (pi->tx_win > L2CAP_TX_WIN_MAX_ENHANCED) - pi->tx_win = L2CAP_TX_WIN_MAX_ENHANCED; + pi->ack_win = min_t(u16, val, pi->ack_win); l2cap_add_conf_opt(&ptr, L2CAP_CONF_EXT_WINDOW, 2, pi->tx_win); @@ -3869,6 +3867,10 @@ static int l2cap_parse_conf_rsp(struct sock *sk, void *rsp, int len, void *data, pi->retrans_timeout = le16_to_cpu(rfc.retrans_timeout); pi->monitor_timeout = le16_to_cpu(rfc.monitor_timeout); pi->mps = le16_to_cpu(rfc.max_pdu_size); + if (!pi->extended_control) { + pi->ack_win = min_t(u16, pi->ack_win, + rfc.txwin_size); + } break; case L2CAP_MODE_STREAMING: pi->mps = le16_to_cpu(rfc.max_pdu_size); @@ -3901,6 +3903,7 @@ static void l2cap_conf_rfc_get(struct sock *sk, void *rsp, int len) int type, olen; unsigned long val; struct l2cap_conf_rfc rfc; + u16 txwin_ext = pi->ack_win; BT_DBG("sk %p, rsp %p, len %d", sk, rsp, len); @@ -3909,6 +3912,7 @@ static void l2cap_conf_rfc_get(struct sock *sk, void *rsp, int len) rfc.retrans_timeout = cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO); rfc.monitor_timeout = cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO); rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE); + rfc.txwin_size = min_t(u16, pi->ack_win, L2CAP_DEFAULT_TX_WINDOW); if ((pi->mode != L2CAP_MODE_ERTM) && (pi->mode != L2CAP_MODE_STREAMING)) return; @@ -3920,16 +3924,22 @@ static void l2cap_conf_rfc_get(struct sock *sk, void *rsp, int len) case L2CAP_CONF_RFC: if (olen == sizeof(rfc)) memcpy(&rfc, (void *)val, olen); - goto done; + break; + case L2CAP_CONF_EXT_WINDOW: + txwin_ext = val; + break; } } -done: switch (rfc.mode) { case L2CAP_MODE_ERTM: pi->retrans_timeout = le16_to_cpu(rfc.retrans_timeout); pi->monitor_timeout = le16_to_cpu(rfc.monitor_timeout); pi->mps = le16_to_cpu(rfc.max_pdu_size); + if (pi->extended_control) + pi->ack_win = min_t(u16, pi->ack_win, txwin_ext); + else + pi->ack_win = min_t(u16, pi->ack_win, rfc.txwin_size); break; case L2CAP_MODE_STREAMING: pi->mps = le16_to_cpu(rfc.max_pdu_size); diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 123b9badcb7..45d2888b77c 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -1270,6 +1270,7 @@ void l2cap_sock_init(struct sock *sk, struct sock *parent) pi->scid = 0; pi->dcid = 0; pi->tx_win_max = L2CAP_TX_WIN_MAX_ENHANCED; + pi->ack_win = pi->tx_win; pi->extended_control = 0; pi->local_conf.fcs = pi->fcs;