diff options
Diffstat (limited to 'net/tipc/link.c')
-rw-r--r-- | net/tipc/link.c | 64 |
1 files changed, 51 insertions, 13 deletions
diff --git a/net/tipc/link.c b/net/tipc/link.c index 2c6e1b9e024b..136316fb37ec 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c | |||
@@ -367,6 +367,18 @@ int tipc_link_bc_peers(struct tipc_link *l) | |||
367 | return l->ackers; | 367 | return l->ackers; |
368 | } | 368 | } |
369 | 369 | ||
370 | u16 link_bc_rcv_gap(struct tipc_link *l) | ||
371 | { | ||
372 | struct sk_buff *skb = skb_peek(&l->deferdq); | ||
373 | u16 gap = 0; | ||
374 | |||
375 | if (more(l->snd_nxt, l->rcv_nxt)) | ||
376 | gap = l->snd_nxt - l->rcv_nxt; | ||
377 | if (skb) | ||
378 | gap = buf_seqno(skb) - l->rcv_nxt; | ||
379 | return gap; | ||
380 | } | ||
381 | |||
370 | void tipc_link_set_mtu(struct tipc_link *l, int mtu) | 382 | void tipc_link_set_mtu(struct tipc_link *l, int mtu) |
371 | { | 383 | { |
372 | l->mtu = mtu; | 384 | l->mtu = mtu; |
@@ -1135,7 +1147,10 @@ int tipc_link_build_state_msg(struct tipc_link *l, struct sk_buff_head *xmitq) | |||
1135 | if (((l->rcv_nxt ^ tipc_own_addr(l->net)) & 0xf) != 0xf) | 1147 | if (((l->rcv_nxt ^ tipc_own_addr(l->net)) & 0xf) != 0xf) |
1136 | return 0; | 1148 | return 0; |
1137 | l->rcv_unacked = 0; | 1149 | l->rcv_unacked = 0; |
1138 | return TIPC_LINK_SND_BC_ACK; | 1150 | |
1151 | /* Use snd_nxt to store peer's snd_nxt in broadcast rcv link */ | ||
1152 | l->snd_nxt = l->rcv_nxt; | ||
1153 | return TIPC_LINK_SND_STATE; | ||
1139 | } | 1154 | } |
1140 | 1155 | ||
1141 | /* Unicast ACK */ | 1156 | /* Unicast ACK */ |
@@ -1236,7 +1251,7 @@ int tipc_link_rcv(struct tipc_link *l, struct sk_buff *skb, | |||
1236 | rc |= tipc_link_input(l, skb, l->inputq); | 1251 | rc |= tipc_link_input(l, skb, l->inputq); |
1237 | if (unlikely(++l->rcv_unacked >= TIPC_MIN_LINK_WIN)) | 1252 | if (unlikely(++l->rcv_unacked >= TIPC_MIN_LINK_WIN)) |
1238 | rc |= tipc_link_build_state_msg(l, xmitq); | 1253 | rc |= tipc_link_build_state_msg(l, xmitq); |
1239 | if (unlikely(rc & ~TIPC_LINK_SND_BC_ACK)) | 1254 | if (unlikely(rc & ~TIPC_LINK_SND_STATE)) |
1240 | break; | 1255 | break; |
1241 | } while ((skb = __skb_dequeue(defq))); | 1256 | } while ((skb = __skb_dequeue(defq))); |
1242 | 1257 | ||
@@ -1250,10 +1265,11 @@ static void tipc_link_build_proto_msg(struct tipc_link *l, int mtyp, bool probe, | |||
1250 | u16 rcvgap, int tolerance, int priority, | 1265 | u16 rcvgap, int tolerance, int priority, |
1251 | struct sk_buff_head *xmitq) | 1266 | struct sk_buff_head *xmitq) |
1252 | { | 1267 | { |
1268 | struct tipc_link *bcl = l->bc_rcvlink; | ||
1253 | struct sk_buff *skb; | 1269 | struct sk_buff *skb; |
1254 | struct tipc_msg *hdr; | 1270 | struct tipc_msg *hdr; |
1255 | struct sk_buff_head *dfq = &l->deferdq; | 1271 | struct sk_buff_head *dfq = &l->deferdq; |
1256 | bool node_up = link_is_up(l->bc_rcvlink); | 1272 | bool node_up = link_is_up(bcl); |
1257 | struct tipc_mon_state *mstate = &l->mon_state; | 1273 | struct tipc_mon_state *mstate = &l->mon_state; |
1258 | int dlen = 0; | 1274 | int dlen = 0; |
1259 | void *data; | 1275 | void *data; |
@@ -1281,7 +1297,7 @@ static void tipc_link_build_proto_msg(struct tipc_link *l, int mtyp, bool probe, | |||
1281 | msg_set_net_plane(hdr, l->net_plane); | 1297 | msg_set_net_plane(hdr, l->net_plane); |
1282 | msg_set_next_sent(hdr, l->snd_nxt); | 1298 | msg_set_next_sent(hdr, l->snd_nxt); |
1283 | msg_set_ack(hdr, l->rcv_nxt - 1); | 1299 | msg_set_ack(hdr, l->rcv_nxt - 1); |
1284 | msg_set_bcast_ack(hdr, l->bc_rcvlink->rcv_nxt - 1); | 1300 | msg_set_bcast_ack(hdr, bcl->rcv_nxt - 1); |
1285 | msg_set_last_bcast(hdr, l->bc_sndlink->snd_nxt - 1); | 1301 | msg_set_last_bcast(hdr, l->bc_sndlink->snd_nxt - 1); |
1286 | msg_set_link_tolerance(hdr, tolerance); | 1302 | msg_set_link_tolerance(hdr, tolerance); |
1287 | msg_set_linkprio(hdr, priority); | 1303 | msg_set_linkprio(hdr, priority); |
@@ -1291,6 +1307,7 @@ static void tipc_link_build_proto_msg(struct tipc_link *l, int mtyp, bool probe, | |||
1291 | 1307 | ||
1292 | if (mtyp == STATE_MSG) { | 1308 | if (mtyp == STATE_MSG) { |
1293 | msg_set_seq_gap(hdr, rcvgap); | 1309 | msg_set_seq_gap(hdr, rcvgap); |
1310 | msg_set_bc_gap(hdr, link_bc_rcv_gap(bcl)); | ||
1294 | msg_set_probe(hdr, probe); | 1311 | msg_set_probe(hdr, probe); |
1295 | tipc_mon_prep(l->net, data, &dlen, mstate, l->bearer_id); | 1312 | tipc_mon_prep(l->net, data, &dlen, mstate, l->bearer_id); |
1296 | msg_set_size(hdr, INT_H_SIZE + dlen); | 1313 | msg_set_size(hdr, INT_H_SIZE + dlen); |
@@ -1575,49 +1592,68 @@ void tipc_link_bc_init_rcv(struct tipc_link *l, struct tipc_msg *hdr) | |||
1575 | 1592 | ||
1576 | /* tipc_link_bc_sync_rcv - update rcv link according to peer's send state | 1593 | /* tipc_link_bc_sync_rcv - update rcv link according to peer's send state |
1577 | */ | 1594 | */ |
1578 | void tipc_link_bc_sync_rcv(struct tipc_link *l, struct tipc_msg *hdr, | 1595 | int tipc_link_bc_sync_rcv(struct tipc_link *l, struct tipc_msg *hdr, |
1579 | struct sk_buff_head *xmitq) | 1596 | struct sk_buff_head *xmitq) |
1580 | { | 1597 | { |
1581 | u16 peers_snd_nxt = msg_bc_snd_nxt(hdr); | 1598 | u16 peers_snd_nxt = msg_bc_snd_nxt(hdr); |
1599 | u16 from = msg_bcast_ack(hdr) + 1; | ||
1600 | u16 to = from + msg_bc_gap(hdr) - 1; | ||
1601 | int rc = 0; | ||
1582 | 1602 | ||
1583 | if (!link_is_up(l)) | 1603 | if (!link_is_up(l)) |
1584 | return; | 1604 | return rc; |
1585 | 1605 | ||
1586 | if (!msg_peer_node_is_up(hdr)) | 1606 | if (!msg_peer_node_is_up(hdr)) |
1587 | return; | 1607 | return rc; |
1588 | 1608 | ||
1589 | /* Open when peer ackowledges our bcast init msg (pkt #1) */ | 1609 | /* Open when peer ackowledges our bcast init msg (pkt #1) */ |
1590 | if (msg_ack(hdr)) | 1610 | if (msg_ack(hdr)) |
1591 | l->bc_peer_is_up = true; | 1611 | l->bc_peer_is_up = true; |
1592 | 1612 | ||
1593 | if (!l->bc_peer_is_up) | 1613 | if (!l->bc_peer_is_up) |
1594 | return; | 1614 | return rc; |
1595 | 1615 | ||
1596 | /* Ignore if peers_snd_nxt goes beyond receive window */ | 1616 | /* Ignore if peers_snd_nxt goes beyond receive window */ |
1597 | if (more(peers_snd_nxt, l->rcv_nxt + l->window)) | 1617 | if (more(peers_snd_nxt, l->rcv_nxt + l->window)) |
1598 | return; | 1618 | return rc; |
1619 | |||
1620 | if (!less(to, from)) { | ||
1621 | rc = tipc_link_retrans(l->bc_sndlink, from, to, xmitq); | ||
1622 | l->stats.recv_nacks++; | ||
1623 | } | ||
1624 | |||
1625 | l->snd_nxt = peers_snd_nxt; | ||
1626 | if (link_bc_rcv_gap(l)) | ||
1627 | rc |= TIPC_LINK_SND_STATE; | ||
1628 | |||
1629 | /* Return now if sender supports nack via STATE messages */ | ||
1630 | if (l->peer_caps & TIPC_BCAST_STATE_NACK) | ||
1631 | return rc; | ||
1632 | |||
1633 | /* Otherwise, be backwards compatible */ | ||
1599 | 1634 | ||
1600 | if (!more(peers_snd_nxt, l->rcv_nxt)) { | 1635 | if (!more(peers_snd_nxt, l->rcv_nxt)) { |
1601 | l->nack_state = BC_NACK_SND_CONDITIONAL; | 1636 | l->nack_state = BC_NACK_SND_CONDITIONAL; |
1602 | return; | 1637 | return 0; |
1603 | } | 1638 | } |
1604 | 1639 | ||
1605 | /* Don't NACK if one was recently sent or peeked */ | 1640 | /* Don't NACK if one was recently sent or peeked */ |
1606 | if (l->nack_state == BC_NACK_SND_SUPPRESS) { | 1641 | if (l->nack_state == BC_NACK_SND_SUPPRESS) { |
1607 | l->nack_state = BC_NACK_SND_UNCONDITIONAL; | 1642 | l->nack_state = BC_NACK_SND_UNCONDITIONAL; |
1608 | return; | 1643 | return 0; |
1609 | } | 1644 | } |
1610 | 1645 | ||
1611 | /* Conditionally delay NACK sending until next synch rcv */ | 1646 | /* Conditionally delay NACK sending until next synch rcv */ |
1612 | if (l->nack_state == BC_NACK_SND_CONDITIONAL) { | 1647 | if (l->nack_state == BC_NACK_SND_CONDITIONAL) { |
1613 | l->nack_state = BC_NACK_SND_UNCONDITIONAL; | 1648 | l->nack_state = BC_NACK_SND_UNCONDITIONAL; |
1614 | if ((peers_snd_nxt - l->rcv_nxt) < TIPC_MIN_LINK_WIN) | 1649 | if ((peers_snd_nxt - l->rcv_nxt) < TIPC_MIN_LINK_WIN) |
1615 | return; | 1650 | return 0; |
1616 | } | 1651 | } |
1617 | 1652 | ||
1618 | /* Send NACK now but suppress next one */ | 1653 | /* Send NACK now but suppress next one */ |
1619 | tipc_link_build_bc_proto_msg(l, true, peers_snd_nxt, xmitq); | 1654 | tipc_link_build_bc_proto_msg(l, true, peers_snd_nxt, xmitq); |
1620 | l->nack_state = BC_NACK_SND_SUPPRESS; | 1655 | l->nack_state = BC_NACK_SND_SUPPRESS; |
1656 | return 0; | ||
1621 | } | 1657 | } |
1622 | 1658 | ||
1623 | void tipc_link_bc_ack_rcv(struct tipc_link *l, u16 acked, | 1659 | void tipc_link_bc_ack_rcv(struct tipc_link *l, u16 acked, |
@@ -1654,6 +1690,8 @@ void tipc_link_bc_ack_rcv(struct tipc_link *l, u16 acked, | |||
1654 | } | 1690 | } |
1655 | 1691 | ||
1656 | /* tipc_link_bc_nack_rcv(): receive broadcast nack message | 1692 | /* tipc_link_bc_nack_rcv(): receive broadcast nack message |
1693 | * This function is here for backwards compatibility, since | ||
1694 | * no BCAST_PROTOCOL/STATE messages occur from TIPC v2.5. | ||
1657 | */ | 1695 | */ |
1658 | int tipc_link_bc_nack_rcv(struct tipc_link *l, struct sk_buff *skb, | 1696 | int tipc_link_bc_nack_rcv(struct tipc_link *l, struct sk_buff *skb, |
1659 | struct sk_buff_head *xmitq) | 1697 | struct sk_buff_head *xmitq) |