aboutsummaryrefslogtreecommitdiffstats
path: root/net/tipc
diff options
context:
space:
mode:
authorJon Maloy <jon.maloy@ericsson.com>2018-03-22 15:42:51 -0400
committerDavid S. Miller <davem@davemloft.net>2018-03-23 13:12:18 -0400
commit25b0b9c4e835ffaa65b61c3efe2e28acf84d0259 (patch)
tree39474fca13a7ecde0c1c30cf4530254062d0cbda /net/tipc
parentd50ccc2d3909fc1b4d40e4af16b026f05dc68707 (diff)
tipc: handle collisions of 32-bit node address hash values
When a 32-bit node address is generated from a 128-bit identifier, there is a risk of collisions which must be discovered and handled. We do this as follows: - We don't apply the generated address immediately to the node, but do instead initiate a 1 sec trial period to allow other cluster members to discover and handle such collisions. - During the trial period the node periodically sends out a new type of message, DSC_TRIAL_MSG, using broadcast or emulated broadcast, to all the other nodes in the cluster. - When a node is receiving such a message, it must check that the presented 32-bit identifier either is unused, or was used by the very same peer in a previous session. In both cases it accepts the request by not responding to it. - If it finds that the same node has been up before using a different address, it responds with a DSC_TRIAL_FAIL_MSG containing that address. - If it finds that the address has already been taken by some other node, it generates a new, unused address and returns it to the requester. - During the trial period the requesting node must always be prepared to accept a failure message, i.e., a message where a peer suggests a different (or equal) address to the one tried. In those cases it must apply the suggested value as trial address and restart the trial period. This algorithm ensures that in the vast majority of cases a node will have the same address before and after a reboot. If a legacy user configures the address explicitly, there will be no trial period and messages, so this protocol addition is completely backwards compatible. Acked-by: Ying Xue <ying.xue@windriver.com> Signed-off-by: Jon Maloy <jon.maloy@ericsson.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/tipc')
-rw-r--r--net/tipc/addr.c3
-rw-r--r--net/tipc/bearer.c3
-rw-r--r--net/tipc/core.c2
-rw-r--r--net/tipc/core.h2
-rw-r--r--net/tipc/discover.c126
-rw-r--r--net/tipc/link.c26
-rw-r--r--net/tipc/link.h4
-rw-r--r--net/tipc/msg.h23
-rw-r--r--net/tipc/net.c4
-rw-r--r--net/tipc/node.c85
-rw-r--r--net/tipc/node.h3
11 files changed, 236 insertions, 45 deletions
diff --git a/net/tipc/addr.c b/net/tipc/addr.c
index 4841e98591d0..b88d48d00913 100644
--- a/net/tipc/addr.c
+++ b/net/tipc/addr.c
@@ -59,7 +59,7 @@ void tipc_set_node_id(struct net *net, u8 *id)
59 59
60 memcpy(tn->node_id, id, NODE_ID_LEN); 60 memcpy(tn->node_id, id, NODE_ID_LEN);
61 tipc_nodeid2string(tn->node_id_string, id); 61 tipc_nodeid2string(tn->node_id_string, id);
62 tn->node_addr = tmp[0] ^ tmp[1] ^ tmp[2] ^ tmp[3]; 62 tn->trial_addr = tmp[0] ^ tmp[1] ^ tmp[2] ^ tmp[3];
63 pr_info("Own node identity %s, cluster identity %u\n", 63 pr_info("Own node identity %s, cluster identity %u\n",
64 tipc_own_id_string(net), tn->net_id); 64 tipc_own_id_string(net), tn->net_id);
65} 65}
@@ -74,6 +74,7 @@ void tipc_set_node_addr(struct net *net, u32 addr)
74 sprintf(node_id, "%x", addr); 74 sprintf(node_id, "%x", addr);
75 tipc_set_node_id(net, node_id); 75 tipc_set_node_id(net, node_id);
76 } 76 }
77 tn->trial_addr = addr;
77 pr_info("32-bit node address hash set to %x\n", addr); 78 pr_info("32-bit node address hash set to %x\n", addr);
78} 79}
79 80
diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c
index a71f31879cb3..ae5b44ca1c1e 100644
--- a/net/tipc/bearer.c
+++ b/net/tipc/bearer.c
@@ -235,7 +235,6 @@ static int tipc_enable_bearer(struct net *net, const char *name,
235{ 235{
236 struct tipc_net *tn = tipc_net(net); 236 struct tipc_net *tn = tipc_net(net);
237 struct tipc_bearer_names b_names; 237 struct tipc_bearer_names b_names;
238 u32 self = tipc_own_addr(net);
239 int with_this_prio = 1; 238 int with_this_prio = 1;
240 struct tipc_bearer *b; 239 struct tipc_bearer *b;
241 struct tipc_media *m; 240 struct tipc_media *m;
@@ -244,7 +243,7 @@ static int tipc_enable_bearer(struct net *net, const char *name,
244 int res = -EINVAL; 243 int res = -EINVAL;
245 char *errstr = ""; 244 char *errstr = "";
246 245
247 if (!self) { 246 if (!tipc_own_id(net)) {
248 errstr = "not supported in standalone mode"; 247 errstr = "not supported in standalone mode";
249 res = -ENOPROTOOPT; 248 res = -ENOPROTOOPT;
250 goto rejected; 249 goto rejected;
diff --git a/net/tipc/core.c b/net/tipc/core.c
index e92fed49e095..52dfc51ac4d5 100644
--- a/net/tipc/core.c
+++ b/net/tipc/core.c
@@ -57,6 +57,8 @@ static int __net_init tipc_init_net(struct net *net)
57 57
58 tn->net_id = 4711; 58 tn->net_id = 4711;
59 tn->node_addr = 0; 59 tn->node_addr = 0;
60 tn->trial_addr = 0;
61 tn->addr_trial_end = 0;
60 memset(tn->node_id, 0, sizeof(tn->node_id)); 62 memset(tn->node_id, 0, sizeof(tn->node_id));
61 memset(tn->node_id_string, 0, sizeof(tn->node_id_string)); 63 memset(tn->node_id_string, 0, sizeof(tn->node_id_string));
62 tn->mon_threshold = TIPC_DEF_MON_THRESHOLD; 64 tn->mon_threshold = TIPC_DEF_MON_THRESHOLD;
diff --git a/net/tipc/core.h b/net/tipc/core.h
index eabad41cc832..d0f64ca62d02 100644
--- a/net/tipc/core.h
+++ b/net/tipc/core.h
@@ -82,6 +82,8 @@ extern int sysctl_tipc_named_timeout __read_mostly;
82struct tipc_net { 82struct tipc_net {
83 u8 node_id[NODE_ID_LEN]; 83 u8 node_id[NODE_ID_LEN];
84 u32 node_addr; 84 u32 node_addr;
85 u32 trial_addr;
86 unsigned long addr_trial_end;
85 char node_id_string[NODE_ID_STR_LEN]; 87 char node_id_string[NODE_ID_STR_LEN];
86 int net_id; 88 int net_id;
87 int random; 89 int random;
diff --git a/net/tipc/discover.c b/net/tipc/discover.c
index b4c4cd176b9b..e7655736abed 100644
--- a/net/tipc/discover.c
+++ b/net/tipc/discover.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * net/tipc/discover.c 2 * net/tipc/discover.c
3 * 3 *
4 * Copyright (c) 2003-2006, 2014-2015, Ericsson AB 4 * Copyright (c) 2003-2006, 2014-2018, Ericsson AB
5 * Copyright (c) 2005-2006, 2010-2011, Wind River Systems 5 * Copyright (c) 2005-2006, 2010-2011, Wind River Systems
6 * All rights reserved. 6 * All rights reserved.
7 * 7 *
@@ -78,34 +78,40 @@ struct tipc_discoverer {
78 * @b: ptr to bearer issuing message 78 * @b: ptr to bearer issuing message
79 */ 79 */
80static void tipc_disc_init_msg(struct net *net, struct sk_buff *skb, 80static void tipc_disc_init_msg(struct net *net, struct sk_buff *skb,
81 u32 mtyp, struct tipc_bearer *b) 81 u32 mtyp, struct tipc_bearer *b)
82{ 82{
83 struct tipc_net *tn = tipc_net(net); 83 struct tipc_net *tn = tipc_net(net);
84 u32 self = tipc_own_addr(net);
85 u32 dest_domain = b->domain; 84 u32 dest_domain = b->domain;
86 struct tipc_msg *hdr; 85 struct tipc_msg *hdr;
87 86
88 hdr = buf_msg(skb); 87 hdr = buf_msg(skb);
89 tipc_msg_init(self, hdr, LINK_CONFIG, mtyp, 88 tipc_msg_init(tn->trial_addr, hdr, LINK_CONFIG, mtyp,
90 MAX_H_SIZE, dest_domain); 89 MAX_H_SIZE, dest_domain);
90 msg_set_size(hdr, MAX_H_SIZE + NODE_ID_LEN);
91 msg_set_non_seq(hdr, 1); 91 msg_set_non_seq(hdr, 1);
92 msg_set_node_sig(hdr, tn->random); 92 msg_set_node_sig(hdr, tn->random);
93 msg_set_node_capabilities(hdr, TIPC_NODE_CAPABILITIES); 93 msg_set_node_capabilities(hdr, TIPC_NODE_CAPABILITIES);
94 msg_set_dest_domain(hdr, dest_domain); 94 msg_set_dest_domain(hdr, dest_domain);
95 msg_set_bc_netid(hdr, tn->net_id); 95 msg_set_bc_netid(hdr, tn->net_id);
96 b->media->addr2msg(msg_media_addr(hdr), &b->addr); 96 b->media->addr2msg(msg_media_addr(hdr), &b->addr);
97 msg_set_node_id(hdr, tipc_own_id(net));
97} 98}
98 99
99static void tipc_disc_msg_xmit(struct net *net, u32 mtyp, u32 dst, u32 src, 100static void tipc_disc_msg_xmit(struct net *net, u32 mtyp, u32 dst,
101 u32 src, u32 sugg_addr,
100 struct tipc_media_addr *maddr, 102 struct tipc_media_addr *maddr,
101 struct tipc_bearer *b) 103 struct tipc_bearer *b)
102{ 104{
105 struct tipc_msg *hdr;
103 struct sk_buff *skb; 106 struct sk_buff *skb;
104 107
105 skb = tipc_buf_acquire(MAX_H_SIZE, GFP_ATOMIC); 108 skb = tipc_buf_acquire(MAX_H_SIZE + NODE_ID_LEN, GFP_ATOMIC);
106 if (!skb) 109 if (!skb)
107 return; 110 return;
111 hdr = buf_msg(skb);
108 tipc_disc_init_msg(net, skb, mtyp, b); 112 tipc_disc_init_msg(net, skb, mtyp, b);
113 msg_set_sugg_node_addr(hdr, sugg_addr);
114 msg_set_dest_domain(hdr, dst);
109 tipc_bearer_xmit_skb(net, b->identity, skb, maddr); 115 tipc_bearer_xmit_skb(net, b->identity, skb, maddr);
110} 116}
111 117
@@ -126,6 +132,52 @@ static void disc_dupl_alert(struct tipc_bearer *b, u32 node_addr,
126 media_addr_str, b->name); 132 media_addr_str, b->name);
127} 133}
128 134
135/* tipc_disc_addr_trial(): - handle an address uniqueness trial from peer
136 */
137bool tipc_disc_addr_trial_msg(struct tipc_discoverer *d,
138 struct tipc_media_addr *maddr,
139 struct tipc_bearer *b,
140 u32 dst, u32 src,
141 u32 sugg_addr,
142 u8 *peer_id,
143 int mtyp)
144{
145 struct net *net = d->net;
146 struct tipc_net *tn = tipc_net(net);
147 bool trial = time_before(jiffies, tn->addr_trial_end);
148 u32 self = tipc_own_addr(net);
149
150 if (mtyp == DSC_TRIAL_FAIL_MSG) {
151 if (!trial)
152 return true;
153
154 /* Ignore if somebody else already gave new suggestion */
155 if (dst != tn->trial_addr)
156 return true;
157
158 /* Otherwise update trial address and restart trial period */
159 tn->trial_addr = sugg_addr;
160 msg_set_prevnode(buf_msg(d->skb), sugg_addr);
161 tn->addr_trial_end = jiffies + msecs_to_jiffies(1000);
162 return true;
163 }
164
165 /* Apply trial address if we just left trial period */
166 if (!trial && !self) {
167 tipc_net_finalize(net, tn->trial_addr);
168 msg_set_type(buf_msg(d->skb), DSC_REQ_MSG);
169 }
170
171 if (mtyp != DSC_TRIAL_MSG)
172 return false;
173
174 sugg_addr = tipc_node_try_addr(net, peer_id, src);
175 if (sugg_addr)
176 tipc_disc_msg_xmit(net, DSC_TRIAL_FAIL_MSG, src,
177 self, sugg_addr, maddr, b);
178 return true;
179}
180
129/** 181/**
130 * tipc_disc_rcv - handle incoming discovery message (request or response) 182 * tipc_disc_rcv - handle incoming discovery message (request or response)
131 * @net: applicable net namespace 183 * @net: applicable net namespace
@@ -139,17 +191,27 @@ void tipc_disc_rcv(struct net *net, struct sk_buff *skb,
139 struct tipc_msg *hdr = buf_msg(skb); 191 struct tipc_msg *hdr = buf_msg(skb);
140 u16 caps = msg_node_capabilities(hdr); 192 u16 caps = msg_node_capabilities(hdr);
141 bool legacy = tn->legacy_addr_format; 193 bool legacy = tn->legacy_addr_format;
194 u32 sugg = msg_sugg_node_addr(hdr);
142 u32 signature = msg_node_sig(hdr); 195 u32 signature = msg_node_sig(hdr);
196 u8 peer_id[NODE_ID_LEN] = {0,};
143 u32 dst = msg_dest_domain(hdr); 197 u32 dst = msg_dest_domain(hdr);
144 u32 net_id = msg_bc_netid(hdr); 198 u32 net_id = msg_bc_netid(hdr);
145 u32 self = tipc_own_addr(net);
146 struct tipc_media_addr maddr; 199 struct tipc_media_addr maddr;
147 u32 src = msg_prevnode(hdr); 200 u32 src = msg_prevnode(hdr);
148 u32 mtyp = msg_type(hdr); 201 u32 mtyp = msg_type(hdr);
149 bool dupl_addr = false; 202 bool dupl_addr = false;
150 bool respond = false; 203 bool respond = false;
204 u32 self;
151 int err; 205 int err;
152 206
207 skb_linearize(skb);
208 hdr = buf_msg(skb);
209
210 if (caps & TIPC_NODE_ID128)
211 memcpy(peer_id, msg_node_id(hdr), NODE_ID_LEN);
212 else
213 sprintf(peer_id, "%x", src);
214
153 err = b->media->msg2addr(b, &maddr, msg_media_addr(hdr)); 215 err = b->media->msg2addr(b, &maddr, msg_media_addr(hdr));
154 kfree_skb(skb); 216 kfree_skb(skb);
155 if (err || maddr.broadcast) { 217 if (err || maddr.broadcast) {
@@ -161,6 +223,12 @@ void tipc_disc_rcv(struct net *net, struct sk_buff *skb,
161 return; 223 return;
162 if (net_id != tn->net_id) 224 if (net_id != tn->net_id)
163 return; 225 return;
226 if (tipc_disc_addr_trial_msg(b->disc, &maddr, b, dst,
227 src, sugg, peer_id, mtyp))
228 return;
229 self = tipc_own_addr(net);
230
231 /* Message from somebody using this node's address */
164 if (in_own_node(net, src)) { 232 if (in_own_node(net, src)) {
165 disc_dupl_alert(b, self, &maddr); 233 disc_dupl_alert(b, self, &maddr);
166 return; 234 return;
@@ -169,8 +237,7 @@ void tipc_disc_rcv(struct net *net, struct sk_buff *skb,
169 return; 237 return;
170 if (!tipc_in_scope(legacy, b->domain, src)) 238 if (!tipc_in_scope(legacy, b->domain, src))
171 return; 239 return;
172 240 tipc_node_check_dest(net, src, peer_id, b, caps, signature,
173 tipc_node_check_dest(net, src, b, caps, signature,
174 &maddr, &respond, &dupl_addr); 241 &maddr, &respond, &dupl_addr);
175 if (dupl_addr) 242 if (dupl_addr)
176 disc_dupl_alert(b, src, &maddr); 243 disc_dupl_alert(b, src, &maddr);
@@ -178,7 +245,7 @@ void tipc_disc_rcv(struct net *net, struct sk_buff *skb,
178 return; 245 return;
179 if (mtyp != DSC_REQ_MSG) 246 if (mtyp != DSC_REQ_MSG)
180 return; 247 return;
181 tipc_disc_msg_xmit(net, DSC_RESP_MSG, src, self, &maddr, b); 248 tipc_disc_msg_xmit(net, DSC_RESP_MSG, src, self, 0, &maddr, b);
182} 249}
183 250
184/* tipc_disc_add_dest - increment set of discovered nodes 251/* tipc_disc_add_dest - increment set of discovered nodes
@@ -216,9 +283,11 @@ void tipc_disc_remove_dest(struct tipc_discoverer *d)
216static void tipc_disc_timeout(struct timer_list *t) 283static void tipc_disc_timeout(struct timer_list *t)
217{ 284{
218 struct tipc_discoverer *d = from_timer(d, t, timer); 285 struct tipc_discoverer *d = from_timer(d, t, timer);
286 struct tipc_net *tn = tipc_net(d->net);
287 u32 self = tipc_own_addr(d->net);
219 struct tipc_media_addr maddr; 288 struct tipc_media_addr maddr;
220 struct sk_buff *skb = NULL; 289 struct sk_buff *skb = NULL;
221 struct net *net; 290 struct net *net = d->net;
222 u32 bearer_id; 291 u32 bearer_id;
223 292
224 spin_lock_bh(&d->lock); 293 spin_lock_bh(&d->lock);
@@ -228,16 +297,29 @@ static void tipc_disc_timeout(struct timer_list *t)
228 d->timer_intv = TIPC_DISC_INACTIVE; 297 d->timer_intv = TIPC_DISC_INACTIVE;
229 goto exit; 298 goto exit;
230 } 299 }
300
301 /* Did we just leave the address trial period ? */
302 if (!self && !time_before(jiffies, tn->addr_trial_end)) {
303 self = tn->trial_addr;
304 tipc_net_finalize(net, self);
305 msg_set_prevnode(buf_msg(d->skb), self);
306 msg_set_type(buf_msg(d->skb), DSC_REQ_MSG);
307 }
308
231 /* Adjust timeout interval according to discovery phase */ 309 /* Adjust timeout interval according to discovery phase */
232 d->timer_intv *= 2; 310 if (time_before(jiffies, tn->addr_trial_end)) {
233 if (d->num_nodes && d->timer_intv > TIPC_DISC_SLOW) 311 d->timer_intv = TIPC_DISC_INIT;
234 d->timer_intv = TIPC_DISC_SLOW; 312 } else {
235 else if (!d->num_nodes && d->timer_intv > TIPC_DISC_FAST) 313 d->timer_intv *= 2;
236 d->timer_intv = TIPC_DISC_FAST; 314 if (d->num_nodes && d->timer_intv > TIPC_DISC_SLOW)
315 d->timer_intv = TIPC_DISC_SLOW;
316 else if (!d->num_nodes && d->timer_intv > TIPC_DISC_FAST)
317 d->timer_intv = TIPC_DISC_FAST;
318 }
319
237 mod_timer(&d->timer, jiffies + d->timer_intv); 320 mod_timer(&d->timer, jiffies + d->timer_intv);
238 memcpy(&maddr, &d->dest, sizeof(maddr)); 321 memcpy(&maddr, &d->dest, sizeof(maddr));
239 skb = skb_clone(d->skb, GFP_ATOMIC); 322 skb = skb_clone(d->skb, GFP_ATOMIC);
240 net = d->net;
241 bearer_id = d->bearer_id; 323 bearer_id = d->bearer_id;
242exit: 324exit:
243 spin_unlock_bh(&d->lock); 325 spin_unlock_bh(&d->lock);
@@ -257,18 +339,24 @@ exit:
257int tipc_disc_create(struct net *net, struct tipc_bearer *b, 339int tipc_disc_create(struct net *net, struct tipc_bearer *b,
258 struct tipc_media_addr *dest, struct sk_buff **skb) 340 struct tipc_media_addr *dest, struct sk_buff **skb)
259{ 341{
342 struct tipc_net *tn = tipc_net(net);
260 struct tipc_discoverer *d; 343 struct tipc_discoverer *d;
261 344
262 d = kmalloc(sizeof(*d), GFP_ATOMIC); 345 d = kmalloc(sizeof(*d), GFP_ATOMIC);
263 if (!d) 346 if (!d)
264 return -ENOMEM; 347 return -ENOMEM;
265 d->skb = tipc_buf_acquire(MAX_H_SIZE, GFP_ATOMIC); 348 d->skb = tipc_buf_acquire(MAX_H_SIZE + NODE_ID_LEN, GFP_ATOMIC);
266 if (!d->skb) { 349 if (!d->skb) {
267 kfree(d); 350 kfree(d);
268 return -ENOMEM; 351 return -ENOMEM;
269 } 352 }
270
271 tipc_disc_init_msg(net, d->skb, DSC_REQ_MSG, b); 353 tipc_disc_init_msg(net, d->skb, DSC_REQ_MSG, b);
354
355 /* Do we need an address trial period first ? */
356 if (!tipc_own_addr(net)) {
357 tn->addr_trial_end = jiffies + msecs_to_jiffies(1000);
358 msg_set_type(buf_msg(d->skb), DSC_TRIAL_MSG);
359 }
272 memcpy(&d->dest, dest, sizeof(*dest)); 360 memcpy(&d->dest, dest, sizeof(*dest));
273 d->net = net; 361 d->net = net;
274 d->bearer_id = b->identity; 362 d->bearer_id = b->identity;
diff --git a/net/tipc/link.c b/net/tipc/link.c
index bcd76b1e440c..1289b4ba404f 100644
--- a/net/tipc/link.c
+++ b/net/tipc/link.c
@@ -434,15 +434,16 @@ char *tipc_link_name(struct tipc_link *l)
434 */ 434 */
435bool tipc_link_create(struct net *net, char *if_name, int bearer_id, 435bool tipc_link_create(struct net *net, char *if_name, int bearer_id,
436 int tolerance, char net_plane, u32 mtu, int priority, 436 int tolerance, char net_plane, u32 mtu, int priority,
437 int window, u32 session, u32 self, u32 peer, 437 int window, u32 session, u32 self,
438 u16 peer_caps, 438 u32 peer, u8 *peer_id, u16 peer_caps,
439 struct tipc_link *bc_sndlink, 439 struct tipc_link *bc_sndlink,
440 struct tipc_link *bc_rcvlink, 440 struct tipc_link *bc_rcvlink,
441 struct sk_buff_head *inputq, 441 struct sk_buff_head *inputq,
442 struct sk_buff_head *namedq, 442 struct sk_buff_head *namedq,
443 struct tipc_link **link) 443 struct tipc_link **link)
444{ 444{
445 char *self_str = tipc_own_id_string(net); 445 char peer_str[NODE_ID_STR_LEN] = {0,};
446 char self_str[NODE_ID_STR_LEN] = {0,};
446 struct tipc_link *l; 447 struct tipc_link *l;
447 448
448 l = kzalloc(sizeof(*l), GFP_ATOMIC); 449 l = kzalloc(sizeof(*l), GFP_ATOMIC);
@@ -451,11 +452,18 @@ bool tipc_link_create(struct net *net, char *if_name, int bearer_id,
451 *link = l; 452 *link = l;
452 l->session = session; 453 l->session = session;
453 454
454 /* Note: peer i/f name is completed by reset/activate message */ 455 /* Set link name for unicast links only */
455 if (strlen(self_str) > 16) 456 if (peer_id) {
456 sprintf(l->name, "%x:%s-%x:unknown", self, if_name, peer); 457 tipc_nodeid2string(self_str, tipc_own_id(net));
457 else 458 if (strlen(self_str) > 16)
458 sprintf(l->name, "%s:%s-%x:unknown", self_str, if_name, peer); 459 sprintf(self_str, "%x", self);
460 tipc_nodeid2string(peer_str, peer_id);
461 if (strlen(peer_str) > 16)
462 sprintf(peer_str, "%x", peer);
463 }
464 /* Peer i/f name will be completed by reset/activate message */
465 sprintf(l->name, "%s:%s-%s:unknown", self_str, if_name, peer_str);
466
459 strcpy(l->if_name, if_name); 467 strcpy(l->if_name, if_name);
460 l->addr = peer; 468 l->addr = peer;
461 l->peer_caps = peer_caps; 469 l->peer_caps = peer_caps;
@@ -503,7 +511,7 @@ bool tipc_link_bc_create(struct net *net, u32 ownnode, u32 peer,
503 struct tipc_link *l; 511 struct tipc_link *l;
504 512
505 if (!tipc_link_create(net, "", MAX_BEARERS, 0, 'Z', mtu, 0, window, 513 if (!tipc_link_create(net, "", MAX_BEARERS, 0, 'Z', mtu, 0, window,
506 0, ownnode, peer, peer_caps, bc_sndlink, 514 0, ownnode, peer, NULL, peer_caps, bc_sndlink,
507 NULL, inputq, namedq, link)) 515 NULL, inputq, namedq, link))
508 return false; 516 return false;
509 517
diff --git a/net/tipc/link.h b/net/tipc/link.h
index d1bd1787a768..ec59348a81e8 100644
--- a/net/tipc/link.h
+++ b/net/tipc/link.h
@@ -73,8 +73,8 @@ enum {
73 73
74bool tipc_link_create(struct net *net, char *if_name, int bearer_id, 74bool tipc_link_create(struct net *net, char *if_name, int bearer_id,
75 int tolerance, char net_plane, u32 mtu, int priority, 75 int tolerance, char net_plane, u32 mtu, int priority,
76 int window, u32 session, u32 ownnode, u32 peer, 76 int window, u32 session, u32 ownnode,
77 u16 peer_caps, 77 u32 peer, u8 *peer_id, u16 peer_caps,
78 struct tipc_link *bc_sndlink, 78 struct tipc_link *bc_sndlink,
79 struct tipc_link *bc_rcvlink, 79 struct tipc_link *bc_rcvlink,
80 struct sk_buff_head *inputq, 80 struct sk_buff_head *inputq,
diff --git a/net/tipc/msg.h b/net/tipc/msg.h
index b4ba1b4f9ae7..a4e944d59394 100644
--- a/net/tipc/msg.h
+++ b/net/tipc/msg.h
@@ -550,6 +550,8 @@ static inline void msg_set_nameupper(struct tipc_msg *m, u32 n)
550 */ 550 */
551#define DSC_REQ_MSG 0 551#define DSC_REQ_MSG 0
552#define DSC_RESP_MSG 1 552#define DSC_RESP_MSG 1
553#define DSC_TRIAL_MSG 2
554#define DSC_TRIAL_FAIL_MSG 3
553 555
554/* 556/*
555 * Group protocol message types 557 * Group protocol message types
@@ -627,7 +629,6 @@ static inline void msg_set_bcgap_to(struct tipc_msg *m, u32 n)
627 msg_set_bits(m, 2, 0, 0xffff, n); 629 msg_set_bits(m, 2, 0, 0xffff, n);
628} 630}
629 631
630
631/* 632/*
632 * Word 4 633 * Word 4
633 */ 634 */
@@ -925,6 +926,26 @@ static inline bool msg_is_reset(struct tipc_msg *hdr)
925 return (msg_user(hdr) == LINK_PROTOCOL) && (msg_type(hdr) == RESET_MSG); 926 return (msg_user(hdr) == LINK_PROTOCOL) && (msg_type(hdr) == RESET_MSG);
926} 927}
927 928
929static inline u32 msg_sugg_node_addr(struct tipc_msg *m)
930{
931 return msg_word(m, 14);
932}
933
934static inline void msg_set_sugg_node_addr(struct tipc_msg *m, u32 n)
935{
936 msg_set_word(m, 14, n);
937}
938
939static inline void msg_set_node_id(struct tipc_msg *hdr, u8 *id)
940{
941 memcpy(msg_data(hdr), id, 16);
942}
943
944static inline u8 *msg_node_id(struct tipc_msg *hdr)
945{
946 return (u8 *)msg_data(hdr);
947}
948
928struct sk_buff *tipc_buf_acquire(u32 size, gfp_t gfp); 949struct sk_buff *tipc_buf_acquire(u32 size, gfp_t gfp);
929bool tipc_msg_validate(struct sk_buff **_skb); 950bool tipc_msg_validate(struct sk_buff **_skb);
930bool tipc_msg_reverse(u32 own_addr, struct sk_buff **skb, int err); 951bool tipc_msg_reverse(u32 own_addr, struct sk_buff **skb, int err);
diff --git a/net/tipc/net.c b/net/tipc/net.c
index e78674891166..29538dc00857 100644
--- a/net/tipc/net.c
+++ b/net/tipc/net.c
@@ -112,10 +112,8 @@ int tipc_net_init(struct net *net, u8 *node_id, u32 addr)
112 } 112 }
113 pr_info("Started in network mode\n"); 113 pr_info("Started in network mode\n");
114 114
115 if (node_id) { 115 if (node_id)
116 tipc_set_node_id(net, node_id); 116 tipc_set_node_id(net, node_id);
117 tipc_net_finalize(net, tipc_own_addr(net));
118 }
119 if (addr) 117 if (addr)
120 tipc_net_finalize(net, addr); 118 tipc_net_finalize(net, addr);
121 return 0; 119 return 0;
diff --git a/net/tipc/node.c b/net/tipc/node.c
index 7b0c99347406..4a95c8c155c6 100644
--- a/net/tipc/node.c
+++ b/net/tipc/node.c
@@ -115,6 +115,7 @@ struct tipc_node {
115 u16 capabilities; 115 u16 capabilities;
116 u32 signature; 116 u32 signature;
117 u32 link_id; 117 u32 link_id;
118 u8 peer_id[16];
118 struct list_head publ_list; 119 struct list_head publ_list;
119 struct list_head conn_sks; 120 struct list_head conn_sks;
120 unsigned long keepalive_intv; 121 unsigned long keepalive_intv;
@@ -156,6 +157,7 @@ static void tipc_node_delete(struct tipc_node *node);
156static void tipc_node_timeout(struct timer_list *t); 157static void tipc_node_timeout(struct timer_list *t);
157static void tipc_node_fsm_evt(struct tipc_node *n, int evt); 158static void tipc_node_fsm_evt(struct tipc_node *n, int evt);
158static struct tipc_node *tipc_node_find(struct net *net, u32 addr); 159static struct tipc_node *tipc_node_find(struct net *net, u32 addr);
160static struct tipc_node *tipc_node_find_by_id(struct net *net, u8 *id);
159static void tipc_node_put(struct tipc_node *node); 161static void tipc_node_put(struct tipc_node *node);
160static bool node_is_up(struct tipc_node *n); 162static bool node_is_up(struct tipc_node *n);
161 163
@@ -245,6 +247,30 @@ static struct tipc_node *tipc_node_find(struct net *net, u32 addr)
245 return node; 247 return node;
246} 248}
247 249
250/* tipc_node_find_by_id - locate specified node object by its 128-bit id
251 * Note: this function is called only when a discovery request failed
252 * to find the node by its 32-bit id, and is not time critical
253 */
254static struct tipc_node *tipc_node_find_by_id(struct net *net, u8 *id)
255{
256 struct tipc_net *tn = tipc_net(net);
257 struct tipc_node *n;
258 bool found = false;
259
260 rcu_read_lock();
261 list_for_each_entry_rcu(n, &tn->node_list, list) {
262 read_lock_bh(&n->lock);
263 if (!memcmp(id, n->peer_id, 16) &&
264 kref_get_unless_zero(&n->kref))
265 found = true;
266 read_unlock_bh(&n->lock);
267 if (found)
268 break;
269 }
270 rcu_read_unlock();
271 return found ? n : NULL;
272}
273
248static void tipc_node_read_lock(struct tipc_node *n) 274static void tipc_node_read_lock(struct tipc_node *n)
249{ 275{
250 read_lock_bh(&n->lock); 276 read_lock_bh(&n->lock);
@@ -307,7 +333,8 @@ static void tipc_node_write_unlock(struct tipc_node *n)
307 } 333 }
308} 334}
309 335
310struct tipc_node *tipc_node_create(struct net *net, u32 addr, u16 capabilities) 336struct tipc_node *tipc_node_create(struct net *net, u32 addr,
337 u8 *peer_id, u16 capabilities)
311{ 338{
312 struct tipc_net *tn = net_generic(net, tipc_net_id); 339 struct tipc_net *tn = net_generic(net, tipc_net_id);
313 struct tipc_node *n, *temp_node; 340 struct tipc_node *n, *temp_node;
@@ -326,6 +353,7 @@ struct tipc_node *tipc_node_create(struct net *net, u32 addr, u16 capabilities)
326 goto exit; 353 goto exit;
327 } 354 }
328 n->addr = addr; 355 n->addr = addr;
356 memcpy(&n->peer_id, peer_id, 16);
329 n->net = net; 357 n->net = net;
330 n->capabilities = capabilities; 358 n->capabilities = capabilities;
331 kref_init(&n->kref); 359 kref_init(&n->kref);
@@ -344,8 +372,8 @@ struct tipc_node *tipc_node_create(struct net *net, u32 addr, u16 capabilities)
344 n->signature = INVALID_NODE_SIG; 372 n->signature = INVALID_NODE_SIG;
345 n->active_links[0] = INVALID_BEARER_ID; 373 n->active_links[0] = INVALID_BEARER_ID;
346 n->active_links[1] = INVALID_BEARER_ID; 374 n->active_links[1] = INVALID_BEARER_ID;
347 if (!tipc_link_bc_create(net, tipc_own_addr(net), n->addr, 375 if (!tipc_link_bc_create(net, tipc_own_addr(net),
348 U16_MAX, 376 addr, U16_MAX,
349 tipc_link_window(tipc_bc_sndlink(net)), 377 tipc_link_window(tipc_bc_sndlink(net)),
350 n->capabilities, 378 n->capabilities,
351 &n->bc_entry.inputq1, 379 &n->bc_entry.inputq1,
@@ -735,8 +763,51 @@ bool tipc_node_is_up(struct net *net, u32 addr)
735 return retval; 763 return retval;
736} 764}
737 765
738void tipc_node_check_dest(struct net *net, u32 onode, 766static u32 tipc_node_suggest_addr(struct net *net, u32 addr)
739 struct tipc_bearer *b, 767{
768 struct tipc_node *n;
769
770 addr ^= tipc_net(net)->random;
771 while ((n = tipc_node_find(net, addr))) {
772 tipc_node_put(n);
773 addr++;
774 }
775 return addr;
776}
777
778/* tipc_node_try_addr(): Check if addr can be used by peer, suggest other if not
779 */
780u32 tipc_node_try_addr(struct net *net, u8 *id, u32 addr)
781{
782 struct tipc_net *tn = tipc_net(net);
783 struct tipc_node *n;
784
785 /* Suggest new address if some other peer is using this one */
786 n = tipc_node_find(net, addr);
787 if (n) {
788 if (!memcmp(n->peer_id, id, NODE_ID_LEN))
789 addr = 0;
790 tipc_node_put(n);
791 if (!addr)
792 return 0;
793 return tipc_node_suggest_addr(net, addr);
794 }
795
796 /* Suggest previously used address if peer is known */
797 n = tipc_node_find_by_id(net, id);
798 if (n) {
799 addr = n->addr;
800 tipc_node_put(n);
801 }
802 /* Even this node may be in trial phase */
803 if (tn->trial_addr == addr)
804 return tipc_node_suggest_addr(net, addr);
805
806 return addr;
807}
808
809void tipc_node_check_dest(struct net *net, u32 addr,
810 u8 *peer_id, struct tipc_bearer *b,
740 u16 capabilities, u32 signature, 811 u16 capabilities, u32 signature,
741 struct tipc_media_addr *maddr, 812 struct tipc_media_addr *maddr,
742 bool *respond, bool *dupl_addr) 813 bool *respond, bool *dupl_addr)
@@ -755,7 +826,7 @@ void tipc_node_check_dest(struct net *net, u32 onode,
755 *dupl_addr = false; 826 *dupl_addr = false;
756 *respond = false; 827 *respond = false;
757 828
758 n = tipc_node_create(net, onode, capabilities); 829 n = tipc_node_create(net, addr, peer_id, capabilities);
759 if (!n) 830 if (!n)
760 return; 831 return;
761 832
@@ -840,7 +911,7 @@ void tipc_node_check_dest(struct net *net, u32 onode,
840 if (!tipc_link_create(net, if_name, b->identity, b->tolerance, 911 if (!tipc_link_create(net, if_name, b->identity, b->tolerance,
841 b->net_plane, b->mtu, b->priority, 912 b->net_plane, b->mtu, b->priority,
842 b->window, mod(tipc_net(net)->random), 913 b->window, mod(tipc_net(net)->random),
843 tipc_own_addr(net), onode, 914 tipc_own_addr(net), addr, peer_id,
844 n->capabilities, 915 n->capabilities,
845 tipc_bc_sndlink(n->net), n->bc_entry.link, 916 tipc_bc_sndlink(n->net), n->bc_entry.link,
846 &le->inputq, 917 &le->inputq,
diff --git a/net/tipc/node.h b/net/tipc/node.h
index e06faf4fa55e..f24b83500df1 100644
--- a/net/tipc/node.h
+++ b/net/tipc/node.h
@@ -60,7 +60,8 @@ enum {
60#define INVALID_BEARER_ID -1 60#define INVALID_BEARER_ID -1
61 61
62void tipc_node_stop(struct net *net); 62void tipc_node_stop(struct net *net);
63void tipc_node_check_dest(struct net *net, u32 onode, 63u32 tipc_node_try_addr(struct net *net, u8 *id, u32 addr);
64void tipc_node_check_dest(struct net *net, u32 onode, u8 *peer_id128,
64 struct tipc_bearer *bearer, 65 struct tipc_bearer *bearer,
65 u16 capabilities, u32 signature, 66 u16 capabilities, u32 signature,
66 struct tipc_media_addr *maddr, 67 struct tipc_media_addr *maddr,