aboutsummaryrefslogtreecommitdiffstats
path: root/net/tipc/link.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/tipc/link.c')
-rw-r--r--net/tipc/link.c52
1 files changed, 47 insertions, 5 deletions
diff --git a/net/tipc/link.c b/net/tipc/link.c
index 136316fb37ec..58bb44d95f95 100644
--- a/net/tipc/link.c
+++ b/net/tipc/link.c
@@ -181,7 +181,10 @@ struct tipc_link {
181 u16 acked; 181 u16 acked;
182 struct tipc_link *bc_rcvlink; 182 struct tipc_link *bc_rcvlink;
183 struct tipc_link *bc_sndlink; 183 struct tipc_link *bc_sndlink;
184 int nack_state; 184 unsigned long prev_retr;
185 u16 prev_from;
186 u16 prev_to;
187 u8 nack_state;
185 bool bc_peer_is_up; 188 bool bc_peer_is_up;
186 189
187 /* Statistics */ 190 /* Statistics */
@@ -202,6 +205,8 @@ enum {
202 BC_NACK_SND_SUPPRESS, 205 BC_NACK_SND_SUPPRESS,
203}; 206};
204 207
208#define TIPC_BC_RETR_LIMIT 10 /* [ms] */
209
205/* 210/*
206 * Interval between NACKs when packets arrive out of order 211 * Interval between NACKs when packets arrive out of order
207 */ 212 */
@@ -1590,11 +1595,48 @@ void tipc_link_bc_init_rcv(struct tipc_link *l, struct tipc_msg *hdr)
1590 l->rcv_nxt = peers_snd_nxt; 1595 l->rcv_nxt = peers_snd_nxt;
1591} 1596}
1592 1597
1598/* link_bc_retr eval()- check if the indicated range can be retransmitted now
1599 * - Adjust permitted range if there is overlap with previous retransmission
1600 */
1601static bool link_bc_retr_eval(struct tipc_link *l, u16 *from, u16 *to)
1602{
1603 unsigned long elapsed = jiffies_to_msecs(jiffies - l->prev_retr);
1604
1605 if (less(*to, *from))
1606 return false;
1607
1608 /* New retransmission request */
1609 if ((elapsed > TIPC_BC_RETR_LIMIT) ||
1610 less(*to, l->prev_from) || more(*from, l->prev_to)) {
1611 l->prev_from = *from;
1612 l->prev_to = *to;
1613 l->prev_retr = jiffies;
1614 return true;
1615 }
1616
1617 /* Inside range of previous retransmit */
1618 if (!less(*from, l->prev_from) && !more(*to, l->prev_to))
1619 return false;
1620
1621 /* Fully or partially outside previous range => exclude overlap */
1622 if (less(*from, l->prev_from)) {
1623 *to = l->prev_from - 1;
1624 l->prev_from = *from;
1625 }
1626 if (more(*to, l->prev_to)) {
1627 *from = l->prev_to + 1;
1628 l->prev_to = *to;
1629 }
1630 l->prev_retr = jiffies;
1631 return true;
1632}
1633
1593/* tipc_link_bc_sync_rcv - update rcv link according to peer's send state 1634/* tipc_link_bc_sync_rcv - update rcv link according to peer's send state
1594 */ 1635 */
1595int tipc_link_bc_sync_rcv(struct tipc_link *l, struct tipc_msg *hdr, 1636int tipc_link_bc_sync_rcv(struct tipc_link *l, struct tipc_msg *hdr,
1596 struct sk_buff_head *xmitq) 1637 struct sk_buff_head *xmitq)
1597{ 1638{
1639 struct tipc_link *snd_l = l->bc_sndlink;
1598 u16 peers_snd_nxt = msg_bc_snd_nxt(hdr); 1640 u16 peers_snd_nxt = msg_bc_snd_nxt(hdr);
1599 u16 from = msg_bcast_ack(hdr) + 1; 1641 u16 from = msg_bcast_ack(hdr) + 1;
1600 u16 to = from + msg_bc_gap(hdr) - 1; 1642 u16 to = from + msg_bc_gap(hdr) - 1;
@@ -1613,14 +1655,14 @@ int tipc_link_bc_sync_rcv(struct tipc_link *l, struct tipc_msg *hdr,
1613 if (!l->bc_peer_is_up) 1655 if (!l->bc_peer_is_up)
1614 return rc; 1656 return rc;
1615 1657
1658 l->stats.recv_nacks++;
1659
1616 /* Ignore if peers_snd_nxt goes beyond receive window */ 1660 /* Ignore if peers_snd_nxt goes beyond receive window */
1617 if (more(peers_snd_nxt, l->rcv_nxt + l->window)) 1661 if (more(peers_snd_nxt, l->rcv_nxt + l->window))
1618 return rc; 1662 return rc;
1619 1663
1620 if (!less(to, from)) { 1664 if (link_bc_retr_eval(snd_l, &from, &to))
1621 rc = tipc_link_retrans(l->bc_sndlink, from, to, xmitq); 1665 rc = tipc_link_retrans(snd_l, from, to, xmitq);
1622 l->stats.recv_nacks++;
1623 }
1624 1666
1625 l->snd_nxt = peers_snd_nxt; 1667 l->snd_nxt = peers_snd_nxt;
1626 if (link_bc_rcv_gap(l)) 1668 if (link_bc_rcv_gap(l))