bearer.c 12.8 KB
Newer Older
Per Liden's avatar
Per Liden committed
1
2
/*
 * net/tipc/bearer.c: TIPC bearer code
3
 *
4
 * Copyright (c) 1996-2006, Ericsson AB
5
 * Copyright (c) 2004-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
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "core.h"
#include "config.h"
#include "bearer.h"
#include "discover.h"

#define MAX_ADDR_STR 32

44
static struct tipc_media *media_list[MAX_MEDIA];
45
static u32 media_count;
Per Liden's avatar
Per Liden committed
46

47
struct tipc_bearer tipc_bearers[MAX_BEARERS];
Per Liden's avatar
Per Liden committed
48

49
50
static void bearer_disable(struct tipc_bearer *b_ptr);

Per Liden's avatar
Per Liden committed
51
/**
52
 * tipc_media_find - locates specified media object by name
Per Liden's avatar
Per Liden committed
53
 */
54
struct tipc_media *tipc_media_find(const char *name)
Per Liden's avatar
Per Liden committed
55
56
57
{
	u32 i;

58
59
60
	for (i = 0; i < media_count; i++) {
		if (!strcmp(media_list[i]->name, name))
			return media_list[i];
Per Liden's avatar
Per Liden committed
61
	}
62
	return NULL;
Per Liden's avatar
Per Liden committed
63
64
}

65
66
67
/**
 * media_find_id - locates specified media object by type identifier
 */
68
static struct tipc_media *media_find_id(u8 type)
69
70
71
72
{
	u32 i;

	for (i = 0; i < media_count; i++) {
73
74
		if (media_list[i]->type_id == type)
			return media_list[i];
75
76
77
78
	}
	return NULL;
}

Per Liden's avatar
Per Liden committed
79
80
/**
 * tipc_register_media - register a media type
81
 *
Per Liden's avatar
Per Liden committed
82
83
 * Bearers for this media type must be activated separately at a later stage.
 */
84
int tipc_register_media(struct tipc_media *m_ptr)
Per Liden's avatar
Per Liden committed
85
86
87
{
	int res = -EINVAL;

88
	write_lock_bh(&tipc_net_lock);
Per Liden's avatar
Per Liden committed
89

90
	if ((strlen(m_ptr->name) + 1) > TIPC_MAX_MEDIA_NAME)
91
		goto exit;
92
93
	if ((m_ptr->bcast_addr.media_id != m_ptr->type_id) ||
	    !m_ptr->bcast_addr.broadcast)
Per Liden's avatar
Per Liden committed
94
		goto exit;
95
	if (m_ptr->priority > TIPC_MAX_LINK_PRI)
Per Liden's avatar
Per Liden committed
96
		goto exit;
97
	if ((m_ptr->tolerance < TIPC_MIN_LINK_TOL) ||
98
	    (m_ptr->tolerance > TIPC_MAX_LINK_TOL))
Per Liden's avatar
Per Liden committed
99
		goto exit;
100
	if (media_count >= MAX_MEDIA)
Per Liden's avatar
Per Liden committed
101
		goto exit;
102
	if (tipc_media_find(m_ptr->name) || media_find_id(m_ptr->type_id))
103
		goto exit;
Per Liden's avatar
Per Liden committed
104

105
	media_list[media_count] = m_ptr;
106
	media_count++;
Per Liden's avatar
Per Liden committed
107
108
	res = 0;
exit:
109
	write_unlock_bh(&tipc_net_lock);
110
	if (res)
111
		pr_warn("Media <%s> registration error\n", m_ptr->name);
Per Liden's avatar
Per Liden committed
112
113
114
115
	return res;
}

/**
116
 * tipc_media_addr_printf - record media address in print buffer
Per Liden's avatar
Per Liden committed
117
 */
118
void tipc_media_addr_printf(char *buf, int len, struct tipc_media_addr *a)
Per Liden's avatar
Per Liden committed
119
{
120
	char addr_str[MAX_ADDR_STR];
121
	struct tipc_media *m_ptr;
122
	int ret;
Per Liden's avatar
Per Liden committed
123

124
	m_ptr = media_find_id(a->media_id);
Per Liden's avatar
Per Liden committed
125

126
	if (m_ptr && !m_ptr->addr2str(a, addr_str, sizeof(addr_str)))
127
		ret = tipc_snprintf(buf, len, "%s(%s)", m_ptr->name, addr_str);
128
129
	else {
		u32 i;
Per Liden's avatar
Per Liden committed
130

131
		ret = tipc_snprintf(buf, len, "UNKNOWN(%u)", a->media_id);
132
		for (i = 0; i < sizeof(a->value); i++)
133
134
			ret += tipc_snprintf(buf - ret, len + ret,
					    "-%02x", a->value[i]);
Per Liden's avatar
Per Liden committed
135
136
137
138
	}
}

/**
139
 * tipc_media_get_names - record names of registered media in buffer
Per Liden's avatar
Per Liden committed
140
 */
141
struct sk_buff *tipc_media_get_names(void)
Per Liden's avatar
Per Liden committed
142
143
144
145
{
	struct sk_buff *buf;
	int i;

146
	buf = tipc_cfg_reply_alloc(MAX_MEDIA * TLV_SPACE(TIPC_MAX_MEDIA_NAME));
Per Liden's avatar
Per Liden committed
147
148
149
	if (!buf)
		return NULL;

150
	read_lock_bh(&tipc_net_lock);
151
152
153
154
	for (i = 0; i < media_count; i++) {
		tipc_cfg_append_tlv(buf, TIPC_TLV_MEDIA_NAME,
				    media_list[i]->name,
				    strlen(media_list[i]->name) + 1);
Per Liden's avatar
Per Liden committed
155
	}
156
	read_unlock_bh(&tipc_net_lock);
Per Liden's avatar
Per Liden committed
157
158
159
160
161
	return buf;
}

/**
 * bearer_name_validate - validate & (optionally) deconstruct bearer name
162
163
 * @name: ptr to bearer name string
 * @name_parts: ptr to area for bearer name components (or NULL if not needed)
164
 *
Per Liden's avatar
Per Liden committed
165
166
 * Returns 1 if bearer name is valid, otherwise 0.
 */
167
static int bearer_name_validate(const char *name,
168
				struct tipc_bearer_names *name_parts)
Per Liden's avatar
Per Liden committed
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
{
	char name_copy[TIPC_MAX_BEARER_NAME];
	char *media_name;
	char *if_name;
	u32 media_len;
	u32 if_len;

	/* copy bearer name & ensure length is OK */
	name_copy[TIPC_MAX_BEARER_NAME - 1] = 0;
	/* need above in case non-Posix strncpy() doesn't pad with nulls */
	strncpy(name_copy, name, TIPC_MAX_BEARER_NAME);
	if (name_copy[TIPC_MAX_BEARER_NAME - 1] != 0)
		return 0;

	/* ensure all component parts of bearer name are present */
	media_name = name_copy;
185
186
	if_name = strchr(media_name, ':');
	if (if_name == NULL)
Per Liden's avatar
Per Liden committed
187
188
189
190
191
192
		return 0;
	*(if_name++) = 0;
	media_len = if_name - media_name;
	if_len = strlen(if_name) + 1;

	/* validate component parts of bearer name */
193
	if ((media_len <= 1) || (media_len > TIPC_MAX_MEDIA_NAME) ||
194
	    (if_len <= 1) || (if_len > TIPC_MAX_IF_NAME))
Per Liden's avatar
Per Liden committed
195
196
197
198
199
200
201
202
203
204
205
		return 0;

	/* return bearer name components, if necessary */
	if (name_parts) {
		strcpy(name_parts->media_name, media_name);
		strcpy(name_parts->if_name, if_name);
	}
	return 1;
}

/**
206
 * tipc_bearer_find - locates bearer object with matching bearer name
Per Liden's avatar
Per Liden committed
207
 */
208
struct tipc_bearer *tipc_bearer_find(const char *name)
Per Liden's avatar
Per Liden committed
209
{
210
	struct tipc_bearer *b_ptr;
Per Liden's avatar
Per Liden committed
211
212
	u32 i;

213
	for (i = 0, b_ptr = tipc_bearers; i < MAX_BEARERS; i++, b_ptr++) {
214
		if (b_ptr->active && (!strcmp(b_ptr->name, name)))
Per Liden's avatar
Per Liden committed
215
216
			return b_ptr;
	}
217
	return NULL;
Per Liden's avatar
Per Liden committed
218
219
220
}

/**
221
 * tipc_bearer_find_interface - locates bearer object with matching interface name
Per Liden's avatar
Per Liden committed
222
 */
223
struct tipc_bearer *tipc_bearer_find_interface(const char *if_name)
Per Liden's avatar
Per Liden committed
224
{
225
	struct tipc_bearer *b_ptr;
Per Liden's avatar
Per Liden committed
226
227
228
	char *b_if_name;
	u32 i;

229
	for (i = 0, b_ptr = tipc_bearers; i < MAX_BEARERS; i++, b_ptr++) {
Per Liden's avatar
Per Liden committed
230
231
		if (!b_ptr->active)
			continue;
232
		b_if_name = strchr(b_ptr->name, ':') + 1;
Per Liden's avatar
Per Liden committed
233
234
235
		if (!strcmp(b_if_name, if_name))
			return b_ptr;
	}
236
	return NULL;
Per Liden's avatar
Per Liden committed
237
238
239
}

/**
240
 * tipc_bearer_get_names - record names of bearers in buffer
Per Liden's avatar
Per Liden committed
241
 */
242
struct sk_buff *tipc_bearer_get_names(void)
Per Liden's avatar
Per Liden committed
243
244
{
	struct sk_buff *buf;
245
	struct tipc_bearer *b_ptr;
Per Liden's avatar
Per Liden committed
246
247
	int i, j;

248
	buf = tipc_cfg_reply_alloc(MAX_BEARERS * TLV_SPACE(TIPC_MAX_BEARER_NAME));
Per Liden's avatar
Per Liden committed
249
250
251
	if (!buf)
		return NULL;

252
	read_lock_bh(&tipc_net_lock);
253
	for (i = 0; i < media_count; i++) {
Per Liden's avatar
Per Liden committed
254
		for (j = 0; j < MAX_BEARERS; j++) {
255
			b_ptr = &tipc_bearers[j];
256
			if (b_ptr->active && (b_ptr->media == media_list[i])) {
257
				tipc_cfg_append_tlv(buf, TIPC_TLV_BEARER_NAME,
258
259
						    b_ptr->name,
						    strlen(b_ptr->name) + 1);
Per Liden's avatar
Per Liden committed
260
261
262
			}
		}
	}
263
	read_unlock_bh(&tipc_net_lock);
Per Liden's avatar
Per Liden committed
264
265
266
	return buf;
}

267
void tipc_bearer_add_dest(struct tipc_bearer *b_ptr, u32 dest)
Per Liden's avatar
Per Liden committed
268
{
269
270
	tipc_nmap_add(&b_ptr->nodes, dest);
	tipc_bcbearer_sort();
271
	tipc_disc_add_dest(b_ptr->link_req);
Per Liden's avatar
Per Liden committed
272
273
}

274
void tipc_bearer_remove_dest(struct tipc_bearer *b_ptr, u32 dest)
Per Liden's avatar
Per Liden committed
275
{
276
277
	tipc_nmap_remove(&b_ptr->nodes, dest);
	tipc_bcbearer_sort();
278
	tipc_disc_remove_dest(b_ptr->link_req);
Per Liden's avatar
Per Liden committed
279
280
281
}

/*
282
 * Interrupt enabling new requests after bearer blocking:
283
 * See bearer_send().
Per Liden's avatar
Per Liden committed
284
 */
285
void tipc_continue(struct tipc_bearer *b)
Per Liden's avatar
Per Liden committed
286
{
287
288
289
	spin_lock_bh(&b->lock);
	b->blocked = 0;
	spin_unlock_bh(&b->lock);
Per Liden's avatar
Per Liden committed
290
291
292
}

/*
293
 * tipc_bearer_blocked - determines if bearer is currently blocked
Per Liden's avatar
Per Liden committed
294
 */
295
int tipc_bearer_blocked(struct tipc_bearer *b)
Per Liden's avatar
Per Liden committed
296
{
297
	int res;
Per Liden's avatar
Per Liden committed
298

299
300
301
	spin_lock_bh(&b->lock);
	res = b->blocked;
	spin_unlock_bh(&b->lock);
Per Liden's avatar
Per Liden committed
302
303
304
305
306
307

	return res;
}

/**
 * tipc_enable_bearer - enable bearer with the given name
308
 */
309
int tipc_enable_bearer(const char *name, u32 disc_domain, u32 priority)
Per Liden's avatar
Per Liden committed
310
{
311
	struct tipc_bearer *b_ptr;
312
	struct tipc_media *m_ptr;
313
	struct tipc_bearer_names b_names;
Per Liden's avatar
Per Liden committed
314
315
316
317
318
319
	char addr_string[16];
	u32 bearer_id;
	u32 with_this_prio;
	u32 i;
	int res = -EINVAL;

320
	if (!tipc_own_addr) {
321
322
		pr_warn("Bearer <%s> rejected, not supported in standalone mode\n",
			name);
Per Liden's avatar
Per Liden committed
323
		return -ENOPROTOOPT;
324
	}
325
	if (!bearer_name_validate(name, &b_names)) {
326
		pr_warn("Bearer <%s> rejected, illegal name\n", name);
327
		return -EINVAL;
328
	}
329
330
331
332
333
	if (tipc_addr_domain_valid(disc_domain) &&
	    (disc_domain != tipc_own_addr)) {
		if (tipc_in_scope(disc_domain, tipc_own_addr)) {
			disc_domain = tipc_own_addr & TIPC_CLUSTER_MASK;
			res = 0;   /* accept any node in own cluster */
334
		} else if (in_own_cluster_exact(disc_domain))
335
336
337
			res = 0;   /* accept specified node in own cluster */
	}
	if (res) {
338
339
		pr_warn("Bearer <%s> rejected, illegal discovery domain\n",
			name);
340
341
		return -EINVAL;
	}
342
	if ((priority > TIPC_MAX_LINK_PRI) &&
343
	    (priority != TIPC_MEDIA_LINK_PRI)) {
344
		pr_warn("Bearer <%s> rejected, illegal priority\n", name);
Per Liden's avatar
Per Liden committed
345
		return -EINVAL;
346
	}
Per Liden's avatar
Per Liden committed
347

348
	write_lock_bh(&tipc_net_lock);
Per Liden's avatar
Per Liden committed
349

350
	m_ptr = tipc_media_find(b_names.media_name);
Per Liden's avatar
Per Liden committed
351
	if (!m_ptr) {
352
353
		pr_warn("Bearer <%s> rejected, media <%s> not registered\n",
			name, b_names.media_name);
354
		goto exit;
Per Liden's avatar
Per Liden committed
355
	}
356
357

	if (priority == TIPC_MEDIA_LINK_PRI)
Per Liden's avatar
Per Liden committed
358
359
360
361
362
363
		priority = m_ptr->priority;

restart:
	bearer_id = MAX_BEARERS;
	with_this_prio = 1;
	for (i = MAX_BEARERS; i-- != 0; ) {
364
		if (!tipc_bearers[i].active) {
Per Liden's avatar
Per Liden committed
365
366
367
			bearer_id = i;
			continue;
		}
368
		if (!strcmp(name, tipc_bearers[i].name)) {
369
370
			pr_warn("Bearer <%s> rejected, already enabled\n",
				name);
371
			goto exit;
Per Liden's avatar
Per Liden committed
372
		}
373
		if ((tipc_bearers[i].priority == priority) &&
Per Liden's avatar
Per Liden committed
374
375
		    (++with_this_prio > 2)) {
			if (priority-- == 0) {
376
377
				pr_warn("Bearer <%s> rejected, duplicate priority\n",
					name);
378
				goto exit;
Per Liden's avatar
Per Liden committed
379
			}
380
381
			pr_warn("Bearer <%s> priority adjustment required %u->%u\n",
				name, priority + 1, priority);
Per Liden's avatar
Per Liden committed
382
383
384
385
			goto restart;
		}
	}
	if (bearer_id >= MAX_BEARERS) {
386
387
		pr_warn("Bearer <%s> rejected, bearer limit reached (%u)\n",
			name, MAX_BEARERS);
388
		goto exit;
Per Liden's avatar
Per Liden committed
389
390
	}

391
	b_ptr = &tipc_bearers[bearer_id];
392
393
	strcpy(b_ptr->name, name);
	res = m_ptr->enable_bearer(b_ptr);
Per Liden's avatar
Per Liden committed
394
	if (res) {
395
396
		pr_warn("Bearer <%s> rejected, enable failure (%d)\n",
			name, -res);
397
		goto exit;
Per Liden's avatar
Per Liden committed
398
399
400
401
	}

	b_ptr->identity = bearer_id;
	b_ptr->media = m_ptr;
402
403
	b_ptr->tolerance = m_ptr->tolerance;
	b_ptr->window = m_ptr->window;
Per Liden's avatar
Per Liden committed
404
405
406
407
	b_ptr->net_plane = bearer_id + 'A';
	b_ptr->active = 1;
	b_ptr->priority = priority;
	INIT_LIST_HEAD(&b_ptr->links);
408
	spin_lock_init(&b_ptr->lock);
409
410
411
412

	res = tipc_disc_create(b_ptr, &m_ptr->bcast_addr, disc_domain);
	if (res) {
		bearer_disable(b_ptr);
413
414
		pr_warn("Bearer <%s> rejected, discovery object creation failed\n",
			name);
415
416
		goto exit;
	}
417
418
419
	pr_info("Enabled bearer <%s>, discovery domain %s, priority %u\n",
		name,
		tipc_addr_string_fill(addr_string, disc_domain), priority);
420
exit:
421
	write_unlock_bh(&tipc_net_lock);
Per Liden's avatar
Per Liden committed
422
423
424
425
	return res;
}

/**
426
 * tipc_block_bearer - Block the bearer with the given name, and reset all its links
Per Liden's avatar
Per Liden committed
427
428
429
 */
int tipc_block_bearer(const char *name)
{
430
	struct tipc_bearer *b_ptr = NULL;
431
432
	struct tipc_link *l_ptr;
	struct tipc_link *temp_l_ptr;
Per Liden's avatar
Per Liden committed
433

434
	read_lock_bh(&tipc_net_lock);
435
	b_ptr = tipc_bearer_find(name);
Per Liden's avatar
Per Liden committed
436
	if (!b_ptr) {
437
		pr_warn("Attempt to block unknown bearer <%s>\n", name);
438
		read_unlock_bh(&tipc_net_lock);
Per Liden's avatar
Per Liden committed
439
440
441
		return -EINVAL;
	}

442
	pr_info("Blocking bearer <%s>\n", name);
443
444
	spin_lock_bh(&b_ptr->lock);
	b_ptr->blocked = 1;
Per Liden's avatar
Per Liden committed
445
	list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) {
446
		struct tipc_node *n_ptr = l_ptr->owner;
Per Liden's avatar
Per Liden committed
447
448

		spin_lock_bh(&n_ptr->lock);
449
		tipc_link_reset(l_ptr);
Per Liden's avatar
Per Liden committed
450
451
		spin_unlock_bh(&n_ptr->lock);
	}
452
	spin_unlock_bh(&b_ptr->lock);
453
	read_unlock_bh(&tipc_net_lock);
454
	return 0;
Per Liden's avatar
Per Liden committed
455
456
457
}

/**
458
 * bearer_disable
459
 *
460
 * Note: This routine assumes caller holds tipc_net_lock.
Per Liden's avatar
Per Liden committed
461
 */
462
static void bearer_disable(struct tipc_bearer *b_ptr)
Per Liden's avatar
Per Liden committed
463
{
464
465
	struct tipc_link *l_ptr;
	struct tipc_link *temp_l_ptr;
Per Liden's avatar
Per Liden committed
466

467
	pr_info("Disabling bearer <%s>\n", b_ptr->name);
468
469
470
	spin_lock_bh(&b_ptr->lock);
	b_ptr->blocked = 1;
	b_ptr->media->disable_bearer(b_ptr);
Per Liden's avatar
Per Liden committed
471
	list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) {
472
		tipc_link_delete(l_ptr);
Per Liden's avatar
Per Liden committed
473
	}
474
475
	if (b_ptr->link_req)
		tipc_disc_delete(b_ptr->link_req);
476
477
	spin_unlock_bh(&b_ptr->lock);
	memset(b_ptr, 0, sizeof(struct tipc_bearer));
Per Liden's avatar
Per Liden committed
478
479
480
481
}

int tipc_disable_bearer(const char *name)
{
482
	struct tipc_bearer *b_ptr;
Per Liden's avatar
Per Liden committed
483
484
	int res;

485
	write_lock_bh(&tipc_net_lock);
486
	b_ptr = tipc_bearer_find(name);
487
	if (b_ptr == NULL) {
488
		pr_warn("Attempt to disable unknown bearer <%s>\n", name);
489
		res = -EINVAL;
490
491
492
493
	} else {
		bearer_disable(b_ptr);
		res = 0;
	}
494
	write_unlock_bh(&tipc_net_lock);
Per Liden's avatar
Per Liden committed
495
496
497
498
499
	return res;
}



500
void tipc_bearer_stop(void)
Per Liden's avatar
Per Liden committed
501
502
503
504
{
	u32 i;

	for (i = 0; i < MAX_BEARERS; i++) {
505
		if (tipc_bearers[i].active)
506
			bearer_disable(&tipc_bearers[i]);
Per Liden's avatar
Per Liden committed
507
508
509
	}
	media_count = 0;
}