discover.c 9.92 KB
Newer Older
Per Liden's avatar
Per Liden committed
1
2
/*
 * net/tipc/discover.c
3
 *
Per Liden's avatar
Per Liden committed
4
 * Copyright (c) 2003-2006, 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
41
42
43
44
 * POSSIBILITY OF SUCH DAMAGE.
 */

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

#define TIPC_LINK_REQ_INIT	125	/* min delay during bearer start up */
#define TIPC_LINK_REQ_FAST	2000	/* normal delay if bearer has no links */
#define TIPC_LINK_REQ_SLOW	600000	/* normal delay if bearer has links */

45
/*
Per Liden's avatar
Per Liden committed
46
47
 * TODO: Most of the inter-cluster setup stuff should be
 * rewritten, and be made conformant with specification.
48
 */
Per Liden's avatar
Per Liden committed
49
50
51
52
53
54


/**
 * struct link_req - information about an ongoing link setup request
 * @bearer: bearer issuing requests
 * @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)
Per Liden's avatar
Per Liden committed
57
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)
 */
struct link_req {
62
	struct tipc_bearer *bearer;
Per Liden's avatar
Per Liden committed
63
	struct tipc_media_addr dest;
64
	u32 domain;
65
	int num_nodes;
Per Liden's avatar
Per Liden committed
66
67
68
69
70
	struct sk_buff *buf;
	struct timer_list timer;
	unsigned int timer_intv;
};

71
/**
72
 * tipc_disc_init_msg - initialize a link setup message
Per Liden's avatar
Per Liden committed
73
74
75
76
77
 * @type: message type (request or response)
 * @dest_domain: network domain of node(s) which should respond to message
 * @b_ptr: ptr to bearer issuing message
 */

Adrian Bunk's avatar
Adrian Bunk committed
78
79
static struct sk_buff *tipc_disc_init_msg(u32 type,
					  u32 dest_domain,
80
					  struct tipc_bearer *b_ptr)
Per Liden's avatar
Per Liden committed
81
{
82
	struct sk_buff *buf = tipc_buf_acquire(INT_H_SIZE);
Per Liden's avatar
Per Liden committed
83
84
85
86
	struct tipc_msg *msg;

	if (buf) {
		msg = buf_msg(buf);
87
		tipc_msg_init(msg, LINK_CONFIG, type, INT_H_SIZE, dest_domain);
88
		msg_set_non_seq(msg, 1);
Per Liden's avatar
Per Liden committed
89
90
		msg_set_dest_domain(msg, dest_domain);
		msg_set_bc_netid(msg, tipc_net_id);
91
		msg_set_media_addr(msg, &b_ptr->addr);
Per Liden's avatar
Per Liden committed
92
93
94
95
	}
	return buf;
}

96
97
98
99
100
101
102
/**
 * 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
 */

103
static void disc_dupl_alert(struct tipc_bearer *b_ptr, u32 node_addr,
104
105
106
107
108
109
			    struct tipc_media_addr *media_addr)
{
	char node_addr_str[16];
	char media_addr_str[64];
	struct print_buf pb;

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

Per Liden's avatar
Per Liden committed
118
/**
119
 * tipc_disc_recv_msg - handle incoming link setup message (request or response)
Per Liden's avatar
Per Liden committed
120
 * @buf: buffer containing message
121
 * @b_ptr: bearer that message arrived on
Per Liden's avatar
Per Liden committed
122
123
 */

124
void tipc_disc_recv_msg(struct sk_buff *buf, struct tipc_bearer *b_ptr)
Per Liden's avatar
Per Liden committed
125
{
126
	struct tipc_node *n_ptr;
Per Liden's avatar
Per Liden committed
127
	struct link *link;
128
129
	struct tipc_media_addr media_addr, *addr;
	struct sk_buff *rbuf;
Per Liden's avatar
Per Liden committed
130
131
132
133
134
	struct tipc_msg *msg = buf_msg(buf);
	u32 dest = msg_dest_domain(msg);
	u32 orig = msg_prevnode(msg);
	u32 net_id = msg_bc_netid(msg);
	u32 type = msg_type(msg);
135
	int link_fully_up;
Per Liden's avatar
Per Liden committed
136

137
	msg_get_media_addr(msg, &media_addr);
Per Liden's avatar
Per Liden committed
138
139
	buf_discard(buf);

140
	/* Validate discovery message from requesting node */
Per Liden's avatar
Per Liden committed
141
142
	if (net_id != tipc_net_id)
		return;
143
	if (!tipc_addr_domain_valid(dest))
Per Liden's avatar
Per Liden committed
144
		return;
145
	if (!tipc_addr_node_valid(orig))
Per Liden's avatar
Per Liden committed
146
		return;
147
	if (orig == tipc_own_addr) {
148
		if (memcmp(&media_addr, &b_ptr->addr, sizeof(media_addr)))
149
			disc_dupl_alert(b_ptr, tipc_own_addr, &media_addr);
Per Liden's avatar
Per Liden committed
150
		return;
151
	}
152
	if (!tipc_in_scope(dest, tipc_own_addr))
Per Liden's avatar
Per Liden committed
153
		return;
154
	if (!tipc_in_scope(b_ptr->link_req->domain, orig))
155
		return;
156

157
158
159
160
161
	/* Locate structure corresponding to requesting node */
	n_ptr = tipc_node_find(orig);
	if (!n_ptr) {
		n_ptr = tipc_node_create(orig);
		if (!n_ptr)
162
			return;
163
164
165
166
167
168
169
170
	}
	tipc_node_lock(n_ptr);

	/* Don't talk to neighbor during cleanup after last session */
	if (n_ptr->cleanup_required) {
		tipc_node_unlock(n_ptr);
		return;
	}
171

172
173
174
175
	link = n_ptr->links[b_ptr->identity];

	/* Create a link endpoint for this bearer, if necessary */
	if (!link) {
176
		link = tipc_link_create(n_ptr, b_ptr, &media_addr);
Per Liden's avatar
Per Liden committed
177
		if (!link) {
178
179
			tipc_node_unlock(n_ptr);
			return;
Per Liden's avatar
Per Liden committed
180
		}
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
	}

	/*
	 * Ensure requesting node's media address is correct
	 *
	 * If media address doesn't match and the link is working, reject the
	 * request (must be from a duplicate node).
	 *
	 * If media address doesn't match and the link is not working, accept
	 * the new media address and reset the link to ensure it starts up
	 * cleanly.
	 */
	addr = &link->media_addr;
	if (memcmp(addr, &media_addr, sizeof(*addr))) {
		if (tipc_link_is_up(link) || (!link->started)) {
			disc_dupl_alert(b_ptr, orig, &media_addr);
			tipc_node_unlock(n_ptr);
Per Liden's avatar
Per Liden committed
198
199
			return;
		}
200
201
202
203
204
205
206
207
		warn("Resetting link <%s>, peer interface address changed\n",
		     link->name);
		memcpy(addr, &media_addr, sizeof(*addr));
		tipc_link_reset(link);
	}

	/* Accept discovery message & send response, if necessary */
	link_fully_up = link_working_working(link);
208

209
	if ((type == DSC_REQ_MSG) && !link_fully_up && !b_ptr->blocked) {
210
211
212
213
214
		rbuf = tipc_disc_init_msg(DSC_RESP_MSG, orig, b_ptr);
		if (rbuf) {
			b_ptr->media->send_msg(rbuf, b_ptr, &media_addr);
			buf_discard(rbuf);
		}
Per Liden's avatar
Per Liden committed
215
	}
216
217

	tipc_node_unlock(n_ptr);
Per Liden's avatar
Per Liden committed
218
219
220
}

/**
221
 * disc_update - update frequency of periodic link setup requests
Per Liden's avatar
Per Liden committed
222
223
224
 * @req: ptr to link request structure
 */

225
static void disc_update(struct link_req *req)
Per Liden's avatar
Per Liden committed
226
227
228
229
230
231
232
233
234
235
236
237
238
239
{
	if (req->timer_intv == TIPC_LINK_REQ_SLOW) {
		if (!req->bearer->nodes.count) {
			req->timer_intv = TIPC_LINK_REQ_FAST;
			k_start_timer(&req->timer, req->timer_intv);
		}
	} else if (req->timer_intv == TIPC_LINK_REQ_FAST) {
		if (req->bearer->nodes.count) {
			req->timer_intv = TIPC_LINK_REQ_SLOW;
			k_start_timer(&req->timer, req->timer_intv);
		}
	} else {
		/* leave timer "as is" if haven't yet reached a "normal" rate */
	}
240
}
Per Liden's avatar
Per Liden committed
241

242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
/**
 * tipc_disc_add_dest - increment set of discovered nodes
 * @req: ptr to link request structure
 */

void tipc_disc_add_dest(struct link_req *req)
{
	req->num_nodes++;
	disc_update(req);
}

/**
 * tipc_disc_remove_dest - decrement set of discovered nodes
 * @req: ptr to link request structure
 */

void tipc_disc_remove_dest(struct link_req *req)
{
	req->num_nodes--;
	disc_update(req);
}

264
265
266
267
268
269
270
271
272
273
274
/**
 * disc_send_msg - send link setup request message
 * @req: ptr to link request structure
 */

static void disc_send_msg(struct link_req *req)
{
	if (!req->bearer->blocked)
		tipc_bearer_send(req->bearer, req->buf, &req->dest);
}

Per Liden's avatar
Per Liden committed
275
276
277
/**
 * disc_timeout - send a periodic link setup request
 * @req: ptr to link request structure
278
 *
Per Liden's avatar
Per Liden committed
279
280
281
 * Called whenever a link setup request timer associated with a bearer expires.
 */

282
static void disc_timeout(struct link_req *req)
Per Liden's avatar
Per Liden committed
283
{
284
	spin_lock_bh(&req->bearer->lock);
Per Liden's avatar
Per Liden committed
285

286
	disc_send_msg(req);
Per Liden's avatar
Per Liden committed
287
288
289
290
291
292

	if ((req->timer_intv == TIPC_LINK_REQ_SLOW) ||
	    (req->timer_intv == TIPC_LINK_REQ_FAST)) {
		/* leave timer interval "as is" if already at a "normal" rate */
	} else {
		req->timer_intv *= 2;
293
294
		if (req->timer_intv > TIPC_LINK_REQ_FAST)
			req->timer_intv = TIPC_LINK_REQ_FAST;
295
		if ((req->timer_intv == TIPC_LINK_REQ_FAST) &&
Per Liden's avatar
Per Liden committed
296
297
298
299
300
		    (req->bearer->nodes.count))
			req->timer_intv = TIPC_LINK_REQ_SLOW;
	}
	k_start_timer(&req->timer, req->timer_intv);

301
	spin_unlock_bh(&req->bearer->lock);
Per Liden's avatar
Per Liden committed
302
303
304
}

/**
305
 * tipc_disc_create - create object to send periodic link setup requests
Per Liden's avatar
Per Liden committed
306
307
 * @b_ptr: ptr to bearer issuing requests
 * @dest: destination address for request messages
308
 * @dest_domain: network domain to which links can be established
309
 *
310
 * Returns 0 if successful, otherwise -errno.
Per Liden's avatar
Per Liden committed
311
312
 */

313
314
int tipc_disc_create(struct tipc_bearer *b_ptr,
		     struct tipc_media_addr *dest, u32 dest_domain)
Per Liden's avatar
Per Liden committed
315
316
317
{
	struct link_req *req;

318
	req = kmalloc(sizeof(*req), GFP_ATOMIC);
Per Liden's avatar
Per Liden committed
319
	if (!req)
320
		return -ENOMEM;
Per Liden's avatar
Per Liden committed
321

322
	req->buf = tipc_disc_init_msg(DSC_REQ_MSG, dest_domain, b_ptr);
Per Liden's avatar
Per Liden committed
323
324
	if (!req->buf) {
		kfree(req);
325
		return -ENOMSG;
Per Liden's avatar
Per Liden committed
326
327
328
329
	}

	memcpy(&req->dest, dest, sizeof(*dest));
	req->bearer = b_ptr;
330
	req->domain = dest_domain;
331
	req->num_nodes = 0;
Per Liden's avatar
Per Liden committed
332
333
334
	req->timer_intv = TIPC_LINK_REQ_INIT;
	k_init_timer(&req->timer, (Handler)disc_timeout, (unsigned long)req);
	k_start_timer(&req->timer, req->timer_intv);
335
	b_ptr->link_req = req;
336
	disc_send_msg(req);
337
338
339
340
341
342
343
344
345
346
347
348
349
350
	return 0;
}

/**
 * tipc_disc_delete - destroy object sending periodic link setup requests
 * @req: ptr to link request structure
 */

void tipc_disc_delete(struct link_req *req)
{
	k_cancel_timer(&req->timer);
	k_term_timer(&req->timer);
	buf_discard(req->buf);
	kfree(req);
351
}
Per Liden's avatar
Per Liden committed
352