discover.c 13 KB
Newer Older
Per Liden's avatar
Per Liden committed
1
2
/*
 * net/tipc/discover.c
3
 *
4
 * Copyright (c) 2003-2006, 2014-2015, Ericsson AB
5
 * Copyright (c) 2005-2006, 2010-2011, Wind River Systems
Per Liden's avatar
Per Liden committed
6
7
 * All rights reserved.
 *
Per Liden's avatar
Per Liden committed
8
 * Redistribution and use in source and binary forms, with or without
Per Liden's avatar
Per Liden committed
9
10
 * modification, are permitted provided that the following conditions are met:
 *
Per Liden's avatar
Per Liden committed
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.
Per Liden's avatar
Per Liden committed
19
 *
Per Liden's avatar
Per Liden committed
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
Per Liden's avatar
Per Liden committed
34
35
36
37
38
39
40
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "core.h"
#include "link.h"
#include "discover.h"

41
42
43
44
45
46
47
48
/* min delay during bearer start up */
#define TIPC_LINK_REQ_INIT	msecs_to_jiffies(125)
/* max delay if bearer has no links */
#define TIPC_LINK_REQ_FAST	msecs_to_jiffies(1000)
/* max delay if bearer has links */
#define TIPC_LINK_REQ_SLOW	msecs_to_jiffies(60000)
/* indicates no timer in use */
#define TIPC_LINK_REQ_INACTIVE	0xffffffff
Per Liden's avatar
Per Liden committed
49
50

/**
51
 * struct tipc_link_req - information about an ongoing link setup request
52
 * @bearer_id: identity of bearer issuing requests
53
 * @net: network namespace instance
Per Liden's avatar
Per Liden committed
54
 * @dest: destination address for request messages
55
 * @domain: network domain to which links can be established
56
 * @num_nodes: number of nodes currently discovered (i.e. with an active link)
57
 * @lock: spinlock for controlling access to requests
Per Liden's avatar
Per Liden committed
58
59
60
61
 * @buf: request message to be (repeatedly) sent
 * @timer: timer governing period between requests
 * @timer_intv: current interval between requests (in ms)
 */
62
struct tipc_link_req {
63
	u32 bearer_id;
Per Liden's avatar
Per Liden committed
64
	struct tipc_media_addr dest;
65
	struct net *net;
66
	u32 domain;
67
	int num_nodes;
68
	spinlock_t lock;
Per Liden's avatar
Per Liden committed
69
70
	struct sk_buff *buf;
	struct timer_list timer;
71
	unsigned long timer_intv;
Per Liden's avatar
Per Liden committed
72
73
};

74
/**
75
 * tipc_disc_init_msg - initialize a link setup message
76
 * @net: the applicable net namespace
Per Liden's avatar
Per Liden committed
77
78
79
 * @type: message type (request or response)
 * @b_ptr: ptr to bearer issuing message
 */
80
static void tipc_disc_init_msg(struct net *net, struct sk_buff *buf, u32 type,
81
			       struct tipc_bearer *b_ptr)
Per Liden's avatar
Per Liden committed
82
{
83
	struct tipc_net *tn = net_generic(net, tipc_net_id);
Per Liden's avatar
Per Liden committed
84
	struct tipc_msg *msg;
85
	u32 dest_domain = b_ptr->domain;
Per Liden's avatar
Per Liden committed
86

87
	msg = buf_msg(buf);
88
	tipc_msg_init(tn->own_addr, msg, LINK_CONFIG, type,
89
		      MAX_H_SIZE, dest_domain);
90
	msg_set_non_seq(msg, 1);
91
	msg_set_node_sig(msg, tn->random);
92
	msg_set_node_capabilities(msg, 0);
93
	msg_set_dest_domain(msg, dest_domain);
94
	msg_set_bc_netid(msg, tn->net_id);
95
	b_ptr->media->addr2msg(msg_media_addr(msg), &b_ptr->addr);
Per Liden's avatar
Per Liden committed
96
97
}

98
99
100
101
102
103
/**
 * disc_dupl_alert - issue node address duplication alert
 * @b_ptr: pointer to bearer detecting duplication
 * @node_addr: duplicated node address
 * @media_addr: media address advertised by duplicated node
 */
104
static void disc_dupl_alert(struct tipc_bearer *b_ptr, u32 node_addr,
105
106
107
108
109
			    struct tipc_media_addr *media_addr)
{
	char node_addr_str[16];
	char media_addr_str[64];

110
	tipc_addr_string_fill(node_addr_str, node_addr);
111
112
	tipc_media_addr_printf(media_addr_str, sizeof(media_addr_str),
			       media_addr);
113
114
	pr_warn("Duplicate %s using %s seen on <%s>\n", node_addr_str,
		media_addr_str, b_ptr->name);
115
116
}

Per Liden's avatar
Per Liden committed
117
/**
118
 * tipc_disc_rcv - handle incoming discovery message (request or response)
119
 * @net: the applicable net namespace
Per Liden's avatar
Per Liden committed
120
 * @buf: buffer containing message
121
 * @bearer: bearer that message arrived on
Per Liden's avatar
Per Liden committed
122
 */
123
124
void tipc_disc_rcv(struct net *net, struct sk_buff *buf,
		   struct tipc_bearer *bearer)
Per Liden's avatar
Per Liden committed
125
{
126
	struct tipc_net *tn = net_generic(net, tipc_net_id);
127
	struct tipc_node *node;
128
	struct tipc_link *link;
129
	struct tipc_media_addr maddr;
130
	struct sk_buff *rbuf;
Per Liden's avatar
Per Liden committed
131
	struct tipc_msg *msg = buf_msg(buf);
132
133
	u32 ddom = msg_dest_domain(msg);
	u32 onode = msg_prevnode(msg);
Per Liden's avatar
Per Liden committed
134
	u32 net_id = msg_bc_netid(msg);
135
	u32 mtyp = msg_type(msg);
136
	u32 signature = msg_node_sig(msg);
137
	u16 caps = msg_node_capabilities(msg);
138
139
140
141
142
143
	bool addr_match = false;
	bool sign_match = false;
	bool link_up = false;
	bool accept_addr = false;
	bool accept_sign = false;
	bool respond = false;
Per Liden's avatar
Per Liden committed
144

145
	bearer->media->msg2addr(bearer, &maddr, msg_media_addr(msg));
146
	kfree_skb(buf);
Per Liden's avatar
Per Liden committed
147

148
	/* Ensure message from node is valid and communication is permitted */
149
	if (net_id != tn->net_id)
Per Liden's avatar
Per Liden committed
150
		return;
151
	if (maddr.broadcast)
152
		return;
153
	if (!tipc_addr_domain_valid(ddom))
Per Liden's avatar
Per Liden committed
154
		return;
155
	if (!tipc_addr_node_valid(onode))
Per Liden's avatar
Per Liden committed
156
		return;
157

158
	if (in_own_node(net, onode)) {
159
		if (memcmp(&maddr, &bearer->addr, sizeof(maddr)))
160
			disc_dupl_alert(bearer, tn->own_addr, &maddr);
Per Liden's avatar
Per Liden committed
161
		return;
162
	}
163
	if (!tipc_in_scope(ddom, tn->own_addr))
Per Liden's avatar
Per Liden committed
164
		return;
165
	if (!tipc_in_scope(bearer->domain, onode))
166
		return;
167

168
	node = tipc_node_create(net, onode);
169
170
171
	if (!node)
		return;
	tipc_node_lock(node);
172
	node->capabilities = caps;
173
	link = node->links[bearer->identity].link;
174

175
	/* Prepare to validate requesting node's signature and media address */
176
177
178
	sign_match = (signature == node->signature);
	addr_match = link && !memcmp(&link->media_addr, &maddr, sizeof(maddr));
	link_up = link && tipc_link_is_up(link);
179

180

181
	/* These three flags give us eight permutations: */
182

183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
	if (sign_match && addr_match && link_up) {
		/* All is fine. Do nothing. */
	} else if (sign_match && addr_match && !link_up) {
		/* Respond. The link will come up in due time */
		respond = true;
	} else if (sign_match && !addr_match && link_up) {
		/* Peer has changed i/f address without rebooting.
		 * If so, the link will reset soon, and the next
		 * discovery will be accepted. So we can ignore it.
		 * It may also be an cloned or malicious peer having
		 * chosen the same node address and signature as an
		 * existing one.
		 * Ignore requests until the link goes down, if ever.
		 */
		disc_dupl_alert(bearer, onode, &maddr);
	} else if (sign_match && !addr_match && !link_up) {
		/* Peer link has changed i/f address without rebooting.
		 * It may also be a cloned or malicious peer; we can't
		 * distinguish between the two.
		 * The signature is correct, so we must accept.
		 */
		accept_addr = true;
		respond = true;
	} else if (!sign_match && addr_match && link_up) {
		/* Peer node rebooted. Two possibilities:
		 *  - Delayed re-discovery; this link endpoint has already
		 *    reset and re-established contact with the peer, before
		 *    receiving a discovery message from that node.
		 *    (The peer happened to receive one from this node first).
		 *  - The peer came back so fast that our side has not
		 *    discovered it yet. Probing from this side will soon
		 *    reset the link, since there can be no working link
		 *    endpoint at the peer end, and the link will re-establish.
		 *  Accept the signature, since it comes from a known peer.
		 */
		accept_sign = true;
	} else if (!sign_match && addr_match && !link_up) {
		/*  The peer node has rebooted.
		 *  Accept signature, since it is a known peer.
		 */
		accept_sign = true;
		respond = true;
	} else if (!sign_match && !addr_match && link_up) {
		/* Peer rebooted with new address, or a new/duplicate peer.
		 * Ignore until the link goes down, if ever.
		 */
		disc_dupl_alert(bearer, onode, &maddr);
	} else if (!sign_match && !addr_match && !link_up) {
		/* Peer rebooted with new address, or it is a new peer.
		 * Accept signature and address.
		*/
		accept_sign = true;
		accept_addr = true;
		respond = true;
237
238
	}

239
240
241
242
243
244
245
246
247
248
249
	if (accept_sign)
		node->signature = signature;

	if (accept_addr) {
		if (!link)
			link = tipc_link_create(node, bearer, &maddr);
		if (link) {
			memcpy(&link->media_addr, &maddr, sizeof(maddr));
			tipc_link_reset(link);
		} else {
			respond = false;
Per Liden's avatar
Per Liden committed
250
		}
251
252
	}

253
254
	/* Send response, if necessary */
	if (respond && (mtyp == DSC_REQ_MSG)) {
255
		rbuf = tipc_buf_acquire(MAX_H_SIZE);
256
		if (rbuf) {
257
			tipc_disc_init_msg(net, rbuf, DSC_RESP_MSG, bearer);
258
			tipc_bearer_send(net, bearer->identity, rbuf, &maddr);
259
			kfree_skb(rbuf);
260
		}
Per Liden's avatar
Per Liden committed
261
	}
262
	tipc_node_unlock(node);
263
	tipc_node_put(node);
Per Liden's avatar
Per Liden committed
264
265
266
}

/**
267
 * disc_update - update frequency of periodic link setup requests
Per Liden's avatar
Per Liden committed
268
 * @req: ptr to link request structure
269
270
271
 *
 * Reinitiates discovery process if discovery object has no associated nodes
 * and is either not currently searching or is searching at a slow rate
Per Liden's avatar
Per Liden committed
272
 */
273
static void disc_update(struct tipc_link_req *req)
Per Liden's avatar
Per Liden committed
274
{
275
276
277
278
	if (!req->num_nodes) {
		if ((req->timer_intv == TIPC_LINK_REQ_INACTIVE) ||
		    (req->timer_intv > TIPC_LINK_REQ_FAST)) {
			req->timer_intv = TIPC_LINK_REQ_INIT;
279
			mod_timer(&req->timer, jiffies + req->timer_intv);
Per Liden's avatar
Per Liden committed
280
281
		}
	}
282
}
Per Liden's avatar
Per Liden committed
283

284
285
286
287
/**
 * tipc_disc_add_dest - increment set of discovered nodes
 * @req: ptr to link request structure
 */
288
void tipc_disc_add_dest(struct tipc_link_req *req)
289
{
290
	spin_lock_bh(&req->lock);
291
	req->num_nodes++;
292
	spin_unlock_bh(&req->lock);
293
294
295
296
297
298
}

/**
 * tipc_disc_remove_dest - decrement set of discovered nodes
 * @req: ptr to link request structure
 */
299
void tipc_disc_remove_dest(struct tipc_link_req *req)
300
{
301
	spin_lock_bh(&req->lock);
302
303
	req->num_nodes--;
	disc_update(req);
304
	spin_unlock_bh(&req->lock);
305
306
}

Per Liden's avatar
Per Liden committed
307
308
/**
 * disc_timeout - send a periodic link setup request
309
 * @data: ptr to link request structure
310
 *
Per Liden's avatar
Per Liden committed
311
312
 * Called whenever a link setup request timer associated with a bearer expires.
 */
313
static void disc_timeout(unsigned long data)
Per Liden's avatar
Per Liden committed
314
{
315
	struct tipc_link_req *req = (struct tipc_link_req *)data;
316
317
	int max_delay;

318
	spin_lock_bh(&req->lock);
Per Liden's avatar
Per Liden committed
319

320
	/* Stop searching if only desired node has been found */
321
	if (tipc_node(req->domain) && req->num_nodes) {
322
323
		req->timer_intv = TIPC_LINK_REQ_INACTIVE;
		goto exit;
Per Liden's avatar
Per Liden committed
324
325
	}

326
327
328
329
330
331
332
	/*
	 * Send discovery message, then update discovery timer
	 *
	 * Keep doubling time between requests until limit is reached;
	 * hold at fast polling rate if don't have any associated nodes,
	 * otherwise hold at slow polling rate
	 */
333
	tipc_bearer_send(req->net, req->bearer_id, req->buf, &req->dest);
334

335
336
337
338
339
340
341
342
343

	req->timer_intv *= 2;
	if (req->num_nodes)
		max_delay = TIPC_LINK_REQ_SLOW;
	else
		max_delay = TIPC_LINK_REQ_FAST;
	if (req->timer_intv > max_delay)
		req->timer_intv = max_delay;

344
	mod_timer(&req->timer, jiffies + req->timer_intv);
345
exit:
346
	spin_unlock_bh(&req->lock);
Per Liden's avatar
Per Liden committed
347
348
349
}

/**
350
 * tipc_disc_create - create object to send periodic link setup requests
351
 * @net: the applicable net namespace
Per Liden's avatar
Per Liden committed
352
353
 * @b_ptr: ptr to bearer issuing requests
 * @dest: destination address for request messages
354
 * @dest_domain: network domain to which links can be established
355
 *
356
 * Returns 0 if successful, otherwise -errno.
Per Liden's avatar
Per Liden committed
357
 */
358
359
int tipc_disc_create(struct net *net, struct tipc_bearer *b_ptr,
		     struct tipc_media_addr *dest)
Per Liden's avatar
Per Liden committed
360
{
361
	struct tipc_link_req *req;
Per Liden's avatar
Per Liden committed
362

363
	req = kmalloc(sizeof(*req), GFP_ATOMIC);
Per Liden's avatar
Per Liden committed
364
	if (!req)
365
		return -ENOMEM;
366
	req->buf = tipc_buf_acquire(MAX_H_SIZE);
Ying Xue's avatar
Ying Xue committed
367
368
	if (!req->buf) {
		kfree(req);
369
		return -ENOMEM;
Ying Xue's avatar
Ying Xue committed
370
	}
Per Liden's avatar
Per Liden committed
371

372
	tipc_disc_init_msg(net, req->buf, DSC_REQ_MSG, b_ptr);
Per Liden's avatar
Per Liden committed
373
	memcpy(&req->dest, dest, sizeof(*dest));
374
	req->net = net;
375
376
	req->bearer_id = b_ptr->identity;
	req->domain = b_ptr->domain;
377
	req->num_nodes = 0;
Per Liden's avatar
Per Liden committed
378
	req->timer_intv = TIPC_LINK_REQ_INIT;
379
	spin_lock_init(&req->lock);
380
381
	setup_timer(&req->timer, disc_timeout, (unsigned long)req);
	mod_timer(&req->timer, jiffies + req->timer_intv);
382
	b_ptr->link_req = req;
383
	tipc_bearer_send(net, req->bearer_id, req->buf, &req->dest);
384
385
386
387
388
389
390
	return 0;
}

/**
 * tipc_disc_delete - destroy object sending periodic link setup requests
 * @req: ptr to link request structure
 */
391
void tipc_disc_delete(struct tipc_link_req *req)
392
{
393
	del_timer_sync(&req->timer);
394
	kfree_skb(req->buf);
395
	kfree(req);
396
}
397
398
399

/**
 * tipc_disc_reset - reset object to send periodic link setup requests
400
 * @net: the applicable net namespace
401
402
403
 * @b_ptr: ptr to bearer issuing requests
 * @dest_domain: network domain to which links can be established
 */
404
void tipc_disc_reset(struct net *net, struct tipc_bearer *b_ptr)
405
406
407
408
{
	struct tipc_link_req *req = b_ptr->link_req;

	spin_lock_bh(&req->lock);
409
	tipc_disc_init_msg(net, req->buf, DSC_REQ_MSG, b_ptr);
410
	req->net = net;
411
412
413
414
	req->bearer_id = b_ptr->identity;
	req->domain = b_ptr->domain;
	req->num_nodes = 0;
	req->timer_intv = TIPC_LINK_REQ_INIT;
415
	mod_timer(&req->timer, jiffies + req->timer_intv);
416
	tipc_bearer_send(net, req->bearer_id, req->buf, &req->dest);
417
418
	spin_unlock_bh(&req->lock);
}