Blame view
net/tipc/discover.c
12.6 KB
b97bf3fd8
|
1 2 |
/* * net/tipc/discover.c |
c43072852
|
3 |
* |
25b0b9c4e
|
4 |
* Copyright (c) 2003-2006, 2014-2018, Ericsson AB |
2d627b92f
|
5 |
* Copyright (c) 2005-2006, 2010-2011, Wind River Systems |
b97bf3fd8
|
6 7 |
* All rights reserved. * |
9ea1fd3c1
|
8 |
* Redistribution and use in source and binary forms, with or without |
b97bf3fd8
|
9 10 |
* modification, are permitted provided that the following conditions are met: * |
9ea1fd3c1
|
11 12 13 14 15 16 17 18 |
* 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the names of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. |
b97bf3fd8
|
19 |
* |
9ea1fd3c1
|
20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
* Alternatively, this software may be distributed under the terms of the * GNU General Public License ("GPL") version 2 as published by the Free * Software Foundation. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
b97bf3fd8
|
34 35 36 37 |
* POSSIBILITY OF SUCH DAMAGE. */ #include "core.h" |
d3a43b907
|
38 |
#include "node.h" |
b97bf3fd8
|
39 |
#include "discover.h" |
b97bf3fd8
|
40 |
|
2f55c4378
|
41 |
/* min delay during bearer start up */ |
b39e465e5
|
42 |
#define TIPC_DISC_INIT msecs_to_jiffies(125) |
2f55c4378
|
43 |
/* max delay if bearer has no links */ |
b39e465e5
|
44 |
#define TIPC_DISC_FAST msecs_to_jiffies(1000) |
2f55c4378
|
45 |
/* max delay if bearer has links */ |
b39e465e5
|
46 |
#define TIPC_DISC_SLOW msecs_to_jiffies(60000) |
2f55c4378
|
47 |
/* indicates no timer in use */ |
b39e465e5
|
48 |
#define TIPC_DISC_INACTIVE 0xffffffff |
b97bf3fd8
|
49 |
|
b97bf3fd8
|
50 |
/** |
b39e465e5
|
51 |
* struct tipc_discoverer - information about an ongoing link setup request |
7a2f7d18e
|
52 |
* @bearer_id: identity of bearer issuing requests |
7f9f95d9d
|
53 |
* @net: network namespace instance |
b97bf3fd8
|
54 |
* @dest: destination address for request messages |
7a2f7d18e
|
55 |
* @domain: network domain to which links can be established |
1209966cd
|
56 |
* @num_nodes: number of nodes currently discovered (i.e. with an active link) |
f9a2c80b8
|
57 |
* @lock: spinlock for controlling access to requests |
b39e465e5
|
58 |
* @skb: request message to be (repeatedly) sent |
b97bf3fd8
|
59 60 61 |
* @timer: timer governing period between requests * @timer_intv: current interval between requests (in ms) */ |
b39e465e5
|
62 |
struct tipc_discoverer { |
7a2f7d18e
|
63 |
u32 bearer_id; |
b97bf3fd8
|
64 |
struct tipc_media_addr dest; |
7f9f95d9d
|
65 |
struct net *net; |
7a2f7d18e
|
66 |
u32 domain; |
1209966cd
|
67 |
int num_nodes; |
f9a2c80b8
|
68 |
spinlock_t lock; |
b39e465e5
|
69 |
struct sk_buff *skb; |
b97bf3fd8
|
70 |
struct timer_list timer; |
2f55c4378
|
71 |
unsigned long timer_intv; |
b97bf3fd8
|
72 |
}; |
c43072852
|
73 |
/** |
4323add67
|
74 |
* tipc_disc_init_msg - initialize a link setup message |
c93d3baa2
|
75 |
* @net: the applicable net namespace |
b97bf3fd8
|
76 |
* @type: message type (request or response) |
1a90632da
|
77 |
* @b: ptr to bearer issuing message |
b97bf3fd8
|
78 |
*/ |
b39e465e5
|
79 |
static void tipc_disc_init_msg(struct net *net, struct sk_buff *skb, |
25b0b9c4e
|
80 |
u32 mtyp, struct tipc_bearer *b) |
b97bf3fd8
|
81 |
{ |
b39e465e5
|
82 |
struct tipc_net *tn = tipc_net(net); |
1a90632da
|
83 |
u32 dest_domain = b->domain; |
b39e465e5
|
84 |
struct tipc_msg *hdr; |
b97bf3fd8
|
85 |
|
b39e465e5
|
86 |
hdr = buf_msg(skb); |
25b0b9c4e
|
87 |
tipc_msg_init(tn->trial_addr, hdr, LINK_CONFIG, mtyp, |
948fa2d11
|
88 |
MAX_H_SIZE, dest_domain); |
25b0b9c4e
|
89 |
msg_set_size(hdr, MAX_H_SIZE + NODE_ID_LEN); |
b39e465e5
|
90 91 92 93 94 95 |
msg_set_non_seq(hdr, 1); msg_set_node_sig(hdr, tn->random); msg_set_node_capabilities(hdr, TIPC_NODE_CAPABILITIES); msg_set_dest_domain(hdr, dest_domain); msg_set_bc_netid(hdr, tn->net_id); b->media->addr2msg(msg_media_addr(hdr), &b->addr); |
25b0b9c4e
|
96 |
msg_set_node_id(hdr, tipc_own_id(net)); |
b39e465e5
|
97 |
} |
25b0b9c4e
|
98 99 |
static void tipc_disc_msg_xmit(struct net *net, u32 mtyp, u32 dst, u32 src, u32 sugg_addr, |
b39e465e5
|
100 101 102 |
struct tipc_media_addr *maddr, struct tipc_bearer *b) { |
25b0b9c4e
|
103 |
struct tipc_msg *hdr; |
b39e465e5
|
104 |
struct sk_buff *skb; |
25b0b9c4e
|
105 |
skb = tipc_buf_acquire(MAX_H_SIZE + NODE_ID_LEN, GFP_ATOMIC); |
b39e465e5
|
106 107 |
if (!skb) return; |
25b0b9c4e
|
108 |
hdr = buf_msg(skb); |
b39e465e5
|
109 |
tipc_disc_init_msg(net, skb, mtyp, b); |
25b0b9c4e
|
110 111 |
msg_set_sugg_node_addr(hdr, sugg_addr); msg_set_dest_domain(hdr, dst); |
b39e465e5
|
112 |
tipc_bearer_xmit_skb(net, b->identity, skb, maddr); |
b97bf3fd8
|
113 114 115 |
} /** |
e91ed0bcd
|
116 |
* disc_dupl_alert - issue node address duplication alert |
1a90632da
|
117 |
* @b: pointer to bearer detecting duplication |
e91ed0bcd
|
118 119 120 |
* @node_addr: duplicated node address * @media_addr: media address advertised by duplicated node */ |
1a90632da
|
121 |
static void disc_dupl_alert(struct tipc_bearer *b, u32 node_addr, |
e91ed0bcd
|
122 123 |
struct tipc_media_addr *media_addr) { |
e91ed0bcd
|
124 |
char media_addr_str[64]; |
e91ed0bcd
|
125 |
|
dc1aed37d
|
126 127 |
tipc_media_addr_printf(media_addr_str, sizeof(media_addr_str), media_addr); |
d50ccc2d3
|
128 129 |
pr_warn("Duplicate %x using %s seen on <%s> ", node_addr, |
1a90632da
|
130 |
media_addr_str, b->name); |
e91ed0bcd
|
131 |
} |
25b0b9c4e
|
132 |
/* tipc_disc_addr_trial(): - handle an address uniqueness trial from peer |
e415577f5
|
133 134 |
* Returns true if message should be dropped by caller, i.e., if it is a * trial message or we are inside trial period. Otherwise false. |
25b0b9c4e
|
135 |
*/ |
da18ab32d
|
136 137 138 139 140 141 142 |
static bool tipc_disc_addr_trial_msg(struct tipc_discoverer *d, struct tipc_media_addr *maddr, struct tipc_bearer *b, u32 dst, u32 src, u32 sugg_addr, u8 *peer_id, int mtyp) |
25b0b9c4e
|
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 |
{ struct net *net = d->net; struct tipc_net *tn = tipc_net(net); bool trial = time_before(jiffies, tn->addr_trial_end); u32 self = tipc_own_addr(net); if (mtyp == DSC_TRIAL_FAIL_MSG) { if (!trial) return true; /* Ignore if somebody else already gave new suggestion */ if (dst != tn->trial_addr) return true; /* Otherwise update trial address and restart trial period */ tn->trial_addr = sugg_addr; msg_set_prevnode(buf_msg(d->skb), sugg_addr); tn->addr_trial_end = jiffies + msecs_to_jiffies(1000); return true; } /* Apply trial address if we just left trial period */ if (!trial && !self) { |
adba75be0
|
166 167 |
tipc_sched_net_finalize(net, tn->trial_addr); msg_set_prevnode(buf_msg(d->skb), tn->trial_addr); |
25b0b9c4e
|
168 169 |
msg_set_type(buf_msg(d->skb), DSC_REQ_MSG); } |
e415577f5
|
170 |
/* Accept regular link requests/responses only after trial period */ |
25b0b9c4e
|
171 |
if (mtyp != DSC_TRIAL_MSG) |
e415577f5
|
172 |
return trial; |
25b0b9c4e
|
173 174 175 176 177 178 179 |
sugg_addr = tipc_node_try_addr(net, peer_id, src); if (sugg_addr) tipc_disc_msg_xmit(net, DSC_TRIAL_FAIL_MSG, src, self, sugg_addr, maddr, b); return true; } |
e91ed0bcd
|
180 |
/** |
c82910e2a
|
181 |
* tipc_disc_rcv - handle incoming discovery message (request or response) |
b39e465e5
|
182 183 184 |
* @net: applicable net namespace * @skb: buffer containing message * @b: bearer that message arrived on |
b97bf3fd8
|
185 |
*/ |
cf148816a
|
186 |
void tipc_disc_rcv(struct net *net, struct sk_buff *skb, |
b39e465e5
|
187 |
struct tipc_bearer *b) |
b97bf3fd8
|
188 |
{ |
b39e465e5
|
189 |
struct tipc_net *tn = tipc_net(net); |
cf148816a
|
190 |
struct tipc_msg *hdr = buf_msg(skb); |
b39e465e5
|
191 |
u16 caps = msg_node_capabilities(hdr); |
b89afb116
|
192 |
bool legacy = tn->legacy_addr_format; |
25b0b9c4e
|
193 |
u32 sugg = msg_sugg_node_addr(hdr); |
b39e465e5
|
194 |
u32 signature = msg_node_sig(hdr); |
25b0b9c4e
|
195 |
u8 peer_id[NODE_ID_LEN] = {0,}; |
b39e465e5
|
196 |
u32 dst = msg_dest_domain(hdr); |
cf148816a
|
197 |
u32 net_id = msg_bc_netid(hdr); |
b39e465e5
|
198 199 |
struct tipc_media_addr maddr; u32 src = msg_prevnode(hdr); |
cf148816a
|
200 |
u32 mtyp = msg_type(hdr); |
cf148816a
|
201 |
bool dupl_addr = false; |
b39e465e5
|
202 |
bool respond = false; |
25b0b9c4e
|
203 |
u32 self; |
e99429232
|
204 |
int err; |
b97bf3fd8
|
205 |
|
25b0b9c4e
|
206 207 208 209 210 211 212 |
skb_linearize(skb); hdr = buf_msg(skb); if (caps & TIPC_NODE_ID128) memcpy(peer_id, msg_node_id(hdr), NODE_ID_LEN); else sprintf(peer_id, "%x", src); |
b39e465e5
|
213 |
err = b->media->msg2addr(b, &maddr, msg_media_addr(hdr)); |
cf148816a
|
214 |
kfree_skb(skb); |
b39e465e5
|
215 216 217 |
if (err || maddr.broadcast) { pr_warn_ratelimited("Rcv corrupt discovery message "); |
e99429232
|
218 |
return; |
b39e465e5
|
219 220 221 |
} /* Ignore discovery messages from own node */ if (!memcmp(&maddr, &b->addr, sizeof(maddr))) |
b97bf3fd8
|
222 |
return; |
b39e465e5
|
223 |
if (net_id != tn->net_id) |
d6d4577ae
|
224 |
return; |
25b0b9c4e
|
225 226 227 228 229 230 |
if (tipc_disc_addr_trial_msg(b->disc, &maddr, b, dst, src, sugg, peer_id, mtyp)) return; self = tipc_own_addr(net); /* Message from somebody using this node's address */ |
b39e465e5
|
231 232 |
if (in_own_node(net, src)) { disc_dupl_alert(b, self, &maddr); |
b97bf3fd8
|
233 |
return; |
e91ed0bcd
|
234 |
} |
b89afb116
|
235 236 237 238 |
if (!tipc_in_scope(legacy, dst, self)) return; if (!tipc_in_scope(legacy, b->domain, src)) return; |
25b0b9c4e
|
239 |
tipc_node_check_dest(net, src, peer_id, b, caps, signature, |
cf148816a
|
240 241 |
&maddr, &respond, &dupl_addr); if (dupl_addr) |
b39e465e5
|
242 243 244 245 246 |
disc_dupl_alert(b, src, &maddr); if (!respond) return; if (mtyp != DSC_REQ_MSG) return; |
25b0b9c4e
|
247 |
tipc_disc_msg_xmit(net, DSC_RESP_MSG, src, self, 0, &maddr, b); |
b97bf3fd8
|
248 |
} |
b39e465e5
|
249 |
/* tipc_disc_add_dest - increment set of discovered nodes |
b97bf3fd8
|
250 |
*/ |
b39e465e5
|
251 |
void tipc_disc_add_dest(struct tipc_discoverer *d) |
b97bf3fd8
|
252 |
{ |
b39e465e5
|
253 254 255 |
spin_lock_bh(&d->lock); d->num_nodes++; spin_unlock_bh(&d->lock); |
c43072852
|
256 |
} |
b97bf3fd8
|
257 |
|
b39e465e5
|
258 |
/* tipc_disc_remove_dest - decrement set of discovered nodes |
1209966cd
|
259 |
*/ |
b39e465e5
|
260 |
void tipc_disc_remove_dest(struct tipc_discoverer *d) |
1209966cd
|
261 |
{ |
b39e465e5
|
262 |
int intv, num; |
1209966cd
|
263 |
|
b39e465e5
|
264 265 266 267 268 269 270 271 272 |
spin_lock_bh(&d->lock); d->num_nodes--; num = d->num_nodes; intv = d->timer_intv; if (!num && (intv == TIPC_DISC_INACTIVE || intv > TIPC_DISC_FAST)) { d->timer_intv = TIPC_DISC_INIT; mod_timer(&d->timer, jiffies + d->timer_intv); } spin_unlock_bh(&d->lock); |
1209966cd
|
273 |
} |
b39e465e5
|
274 |
/* tipc_disc_timeout - send a periodic link setup request |
b97bf3fd8
|
275 |
* Called whenever a link setup request timer associated with a bearer expires. |
b39e465e5
|
276 277 278 |
* - Keep doubling time between sent request until limit is reached; * - Hold at fast polling rate if we don't have any associated nodes * - Otherwise hold at slow polling rate |
b97bf3fd8
|
279 |
*/ |
b39e465e5
|
280 |
static void tipc_disc_timeout(struct timer_list *t) |
b97bf3fd8
|
281 |
{ |
b39e465e5
|
282 |
struct tipc_discoverer *d = from_timer(d, t, timer); |
25b0b9c4e
|
283 |
struct tipc_net *tn = tipc_net(d->net); |
b39e465e5
|
284 285 |
struct tipc_media_addr maddr; struct sk_buff *skb = NULL; |
25b0b9c4e
|
286 |
struct net *net = d->net; |
b39e465e5
|
287 |
u32 bearer_id; |
972a77fbf
|
288 |
|
b39e465e5
|
289 |
spin_lock_bh(&d->lock); |
b97bf3fd8
|
290 |
|
972a77fbf
|
291 |
/* Stop searching if only desired node has been found */ |
b39e465e5
|
292 293 |
if (tipc_node(d->domain) && d->num_nodes) { d->timer_intv = TIPC_DISC_INACTIVE; |
972a77fbf
|
294 |
goto exit; |
b97bf3fd8
|
295 |
} |
25b0b9c4e
|
296 |
|
adba75be0
|
297 298 299 300 301 302 |
/* Did we just leave trial period ? */ if (!time_before(jiffies, tn->addr_trial_end) && !tipc_own_addr(net)) { mod_timer(&d->timer, jiffies + TIPC_DISC_INIT); spin_unlock_bh(&d->lock); tipc_sched_net_finalize(net, tn->trial_addr); return; |
25b0b9c4e
|
303 |
} |
b39e465e5
|
304 |
/* Adjust timeout interval according to discovery phase */ |
25b0b9c4e
|
305 306 307 308 309 310 311 312 |
if (time_before(jiffies, tn->addr_trial_end)) { d->timer_intv = TIPC_DISC_INIT; } else { d->timer_intv *= 2; if (d->num_nodes && d->timer_intv > TIPC_DISC_SLOW) d->timer_intv = TIPC_DISC_SLOW; else if (!d->num_nodes && d->timer_intv > TIPC_DISC_FAST) d->timer_intv = TIPC_DISC_FAST; |
adba75be0
|
313 314 |
msg_set_type(buf_msg(d->skb), DSC_REQ_MSG); msg_set_prevnode(buf_msg(d->skb), tn->trial_addr); |
25b0b9c4e
|
315 |
} |
b39e465e5
|
316 317 318 |
mod_timer(&d->timer, jiffies + d->timer_intv); memcpy(&maddr, &d->dest, sizeof(maddr)); skb = skb_clone(d->skb, GFP_ATOMIC); |
b39e465e5
|
319 |
bearer_id = d->bearer_id; |
972a77fbf
|
320 |
exit: |
b39e465e5
|
321 322 323 |
spin_unlock_bh(&d->lock); if (skb) tipc_bearer_xmit_skb(net, bearer_id, skb, &maddr); |
b97bf3fd8
|
324 325 326 |
} /** |
3a777ff8b
|
327 |
* tipc_disc_create - create object to send periodic link setup requests |
c93d3baa2
|
328 |
* @net: the applicable net namespace |
1a90632da
|
329 |
* @b: ptr to bearer issuing requests |
b97bf3fd8
|
330 |
* @dest: destination address for request messages |
66e019a6a
|
331 |
* @dest_domain: network domain to which links can be established |
c43072852
|
332 |
* |
3a777ff8b
|
333 |
* Returns 0 if successful, otherwise -errno. |
b97bf3fd8
|
334 |
*/ |
1a90632da
|
335 |
int tipc_disc_create(struct net *net, struct tipc_bearer *b, |
4e801fa14
|
336 |
struct tipc_media_addr *dest, struct sk_buff **skb) |
b97bf3fd8
|
337 |
{ |
25b0b9c4e
|
338 |
struct tipc_net *tn = tipc_net(net); |
b39e465e5
|
339 |
struct tipc_discoverer *d; |
b97bf3fd8
|
340 |
|
b39e465e5
|
341 342 |
d = kmalloc(sizeof(*d), GFP_ATOMIC); if (!d) |
3a777ff8b
|
343 |
return -ENOMEM; |
25b0b9c4e
|
344 |
d->skb = tipc_buf_acquire(MAX_H_SIZE + NODE_ID_LEN, GFP_ATOMIC); |
b39e465e5
|
345 346 |
if (!d->skb) { kfree(d); |
a8b9b96e9
|
347 |
return -ENOMEM; |
22e7987ae
|
348 |
} |
b39e465e5
|
349 |
tipc_disc_init_msg(net, d->skb, DSC_REQ_MSG, b); |
25b0b9c4e
|
350 351 352 353 354 355 |
/* Do we need an address trial period first ? */ if (!tipc_own_addr(net)) { tn->addr_trial_end = jiffies + msecs_to_jiffies(1000); msg_set_type(buf_msg(d->skb), DSC_TRIAL_MSG); } |
b39e465e5
|
356 357 358 359 360 361 362 363 364 365 366 |
memcpy(&d->dest, dest, sizeof(*dest)); d->net = net; d->bearer_id = b->identity; d->domain = b->domain; d->num_nodes = 0; d->timer_intv = TIPC_DISC_INIT; spin_lock_init(&d->lock); timer_setup(&d->timer, tipc_disc_timeout, 0); mod_timer(&d->timer, jiffies + d->timer_intv); b->disc = d; *skb = skb_clone(d->skb, GFP_ATOMIC); |
3a777ff8b
|
367 368 369 370 371 |
return 0; } /** * tipc_disc_delete - destroy object sending periodic link setup requests |
b39e465e5
|
372 |
* @d: ptr to link duest structure |
3a777ff8b
|
373 |
*/ |
b39e465e5
|
374 |
void tipc_disc_delete(struct tipc_discoverer *d) |
3a777ff8b
|
375 |
{ |
b39e465e5
|
376 377 378 |
del_timer_sync(&d->timer); kfree_skb(d->skb); kfree(d); |
c43072852
|
379 |
} |
a8b9b96e9
|
380 381 382 |
/** * tipc_disc_reset - reset object to send periodic link setup requests |
c93d3baa2
|
383 |
* @net: the applicable net namespace |
1a90632da
|
384 |
* @b: ptr to bearer issuing requests |
a8b9b96e9
|
385 386 |
* @dest_domain: network domain to which links can be established */ |
1a90632da
|
387 |
void tipc_disc_reset(struct net *net, struct tipc_bearer *b) |
a8b9b96e9
|
388 |
{ |
b39e465e5
|
389 390 |
struct tipc_discoverer *d = b->disc; struct tipc_media_addr maddr; |
60852d679
|
391 |
struct sk_buff *skb; |
a8b9b96e9
|
392 |
|
b39e465e5
|
393 394 395 396 397 398 399 400 401 402 403 |
spin_lock_bh(&d->lock); tipc_disc_init_msg(net, d->skb, DSC_REQ_MSG, b); d->net = net; d->bearer_id = b->identity; d->domain = b->domain; d->num_nodes = 0; d->timer_intv = TIPC_DISC_INIT; memcpy(&maddr, &d->dest, sizeof(maddr)); mod_timer(&d->timer, jiffies + d->timer_intv); skb = skb_clone(d->skb, GFP_ATOMIC); spin_unlock_bh(&d->lock); |
60852d679
|
404 |
if (skb) |
b39e465e5
|
405 |
tipc_bearer_xmit_skb(net, b->identity, skb, &maddr); |
a8b9b96e9
|
406 |
} |