diff options
Diffstat (limited to 'net/tipc/discover.c')
-rw-r--r-- | net/tipc/discover.c | 126 |
1 files changed, 107 insertions, 19 deletions
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 | */ |
80 | static void tipc_disc_init_msg(struct net *net, struct sk_buff *skb, | 80 | static 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 | ||
99 | static void tipc_disc_msg_xmit(struct net *net, u32 mtyp, u32 dst, u32 src, | 100 | static 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 | */ | ||
137 | bool 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) | |||
216 | static void tipc_disc_timeout(struct timer_list *t) | 283 | static 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; |
242 | exit: | 324 | exit: |
243 | spin_unlock_bh(&d->lock); | 325 | spin_unlock_bh(&d->lock); |
@@ -257,18 +339,24 @@ exit: | |||
257 | int tipc_disc_create(struct net *net, struct tipc_bearer *b, | 339 | int 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; |