summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--net/tipc/link.c16
-rw-r--r--net/tipc/link.h1
-rw-r--r--net/tipc/node.c7
-rw-r--r--net/tipc/node.h14
4 files changed, 32 insertions, 6 deletions
diff --git a/net/tipc/link.c b/net/tipc/link.c
index ec4d28328652..065e9e67da5d 100644
--- a/net/tipc/link.c
+++ b/net/tipc/link.c
@@ -130,6 +130,8 @@ struct tipc_link {
 	/* Management and link supervision data */
 	u32 peer_session;
 	u32 session;
+	u16 snd_nxt_state;
+	u16 rcv_nxt_state;
 	u32 peer_bearer_id;
 	u32 bearer_id;
 	u32 tolerance;
@@ -339,6 +341,11 @@ char tipc_link_plane(struct tipc_link *l)
 	return l->net_plane;
 }
 
+void tipc_link_update_caps(struct tipc_link *l, u16 capabilities)
+{
+	l->peer_caps = capabilities;
+}
+
 void tipc_link_add_bc_peer(struct tipc_link *snd_l,
 			   struct tipc_link *uc_l,
 			   struct sk_buff_head *xmitq)
@@ -859,6 +866,8 @@ void tipc_link_reset(struct tipc_link *l)
 	l->rcv_unacked = 0;
 	l->snd_nxt = 1;
 	l->rcv_nxt = 1;
+	l->snd_nxt_state = 1;
+	l->rcv_nxt_state = 1;
 	l->acked = 0;
 	l->silent_intv_cnt = 0;
 	l->rst_cnt = 0;
@@ -1353,6 +1362,8 @@ static void tipc_link_build_proto_msg(struct tipc_link *l, int mtyp, bool probe,
 	msg_set_seqno(hdr, l->snd_nxt + U16_MAX / 2);
 
 	if (mtyp == STATE_MSG) {
+		if (l->peer_caps & TIPC_LINK_PROTO_SEQNO)
+			msg_set_seqno(hdr, l->snd_nxt_state++);
 		msg_set_seq_gap(hdr, rcvgap);
 		msg_set_bc_gap(hdr, link_bc_rcv_gap(bcl));
 		msg_set_probe(hdr, probe);
@@ -1522,6 +1533,11 @@ static int tipc_link_proto_rcv(struct tipc_link *l, struct sk_buff *skb,
 
 	case STATE_MSG:
 
+		if (l->peer_caps & TIPC_LINK_PROTO_SEQNO &&
+		    less(msg_seqno(hdr), l->rcv_nxt_state))
+			break;
+		l->rcv_nxt_state = msg_seqno(hdr) + 1;
+
 		/* Update own tolerance if peer indicates a non-zero value */
 		if (in_range(peers_tol, TIPC_MIN_LINK_TOL, TIPC_MAX_LINK_TOL))
 			l->tolerance = peers_tol;
diff --git a/net/tipc/link.h b/net/tipc/link.h
index ec59348a81e8..d56f9c9e5000 100644
--- a/net/tipc/link.h
+++ b/net/tipc/link.h
@@ -110,6 +110,7 @@ char *tipc_link_name(struct tipc_link *l);
 char tipc_link_plane(struct tipc_link *l);
 int tipc_link_prio(struct tipc_link *l);
 int tipc_link_window(struct tipc_link *l);
+void tipc_link_update_caps(struct tipc_link *l, u16 capabilities);
 unsigned long tipc_link_tolerance(struct tipc_link *l);
 void tipc_link_set_tolerance(struct tipc_link *l, u32 tol,
 			     struct sk_buff_head *xmitq);
diff --git a/net/tipc/node.c b/net/tipc/node.c
index cfdbaf479fd1..1cdb176798f7 100644
--- a/net/tipc/node.c
+++ b/net/tipc/node.c
@@ -363,6 +363,8 @@ static struct tipc_node *tipc_node_create(struct net *net, u32 addr,
 {
 	struct tipc_net *tn = net_generic(net, tipc_net_id);
 	struct tipc_node *n, *temp_node;
+	struct tipc_link *l;
+	int bearer_id;
 	int i;
 
 	spin_lock_bh(&tn->node_list_lock);
@@ -370,6 +372,11 @@ static struct tipc_node *tipc_node_create(struct net *net, u32 addr,
 	if (n) {
 		/* Same node may come back with new capabilities */
 		n->capabilities = capabilities;
+		for (bearer_id = 0; bearer_id < MAX_BEARERS; bearer_id++) {
+			l = n->links[bearer_id].link;
+			if (l)
+				tipc_link_update_caps(l, capabilities);
+		}
 		goto exit;
 	}
 	n = kzalloc(sizeof(*n), GFP_ATOMIC);
diff --git a/net/tipc/node.h b/net/tipc/node.h
index 846c8f240872..48b3298a248d 100644
--- a/net/tipc/node.h
+++ b/net/tipc/node.h
@@ -49,14 +49,16 @@ enum {
 	TIPC_BCAST_STATE_NACK = (1 << 2),
 	TIPC_BLOCK_FLOWCTL    = (1 << 3),
 	TIPC_BCAST_RCAST      = (1 << 4),
-	TIPC_NODE_ID128       = (1 << 5)
+	TIPC_NODE_ID128       = (1 << 5),
+	TIPC_LINK_PROTO_SEQNO = (1 << 6)
 };
 
-#define TIPC_NODE_CAPABILITIES (TIPC_BCAST_SYNCH | \
-				TIPC_BCAST_STATE_NACK | \
-				TIPC_BCAST_RCAST | \
-				TIPC_BLOCK_FLOWCTL | \
-				TIPC_NODE_ID128)
+#define TIPC_NODE_CAPABILITIES (TIPC_BCAST_SYNCH       |  \
+				TIPC_BCAST_STATE_NACK  |  \
+				TIPC_BCAST_RCAST       |  \
+				TIPC_BLOCK_FLOWCTL     |  \
+				TIPC_NODE_ID128        |  \
+				TIPC_LINK_PROTO_SEQNO)
 #define INVALID_BEARER_ID -1
 
 void tipc_node_stop(struct net *net);