bearer.c 15.7 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
/**
 * media_name_valid - validate media name
53
 *
Per Liden's avatar
Per Liden committed
54
55
56
57
58
59
60
61
62
 * Returns 1 if media name is valid, otherwise 0.
 */
static int media_name_valid(const char *name)
{
	u32 len;

	len = strlen(name);
	if ((len + 1) > TIPC_MAX_MEDIA_NAME)
		return 0;
Eric Dumazet's avatar
Eric Dumazet committed
63
	return strspn(name, tipc_alphabet) == len;
Per Liden's avatar
Per Liden committed
64
65
66
}

/**
67
 * tipc_media_find - locates specified media object by name
Per Liden's avatar
Per Liden committed
68
 */
69
struct tipc_media *tipc_media_find(const char *name)
Per Liden's avatar
Per Liden committed
70
71
72
{
	u32 i;

73
74
75
	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
76
	}
77
	return NULL;
Per Liden's avatar
Per Liden committed
78
79
}

80
81
82
/**
 * media_find_id - locates specified media object by type identifier
 */
83
static struct tipc_media *media_find_id(u8 type)
84
85
86
87
{
	u32 i;

	for (i = 0; i < media_count; i++) {
88
89
		if (media_list[i]->type_id == type)
			return media_list[i];
90
91
92
93
	}
	return NULL;
}

Per Liden's avatar
Per Liden committed
94
95
/**
 * tipc_register_media - register a media type
96
 *
Per Liden's avatar
Per Liden committed
97
98
 * Bearers for this media type must be activated separately at a later stage.
 */
99
int tipc_register_media(struct tipc_media *m_ptr)
Per Liden's avatar
Per Liden committed
100
101
102
{
	int res = -EINVAL;

103
	write_lock_bh(&tipc_net_lock);
Per Liden's avatar
Per Liden committed
104

105
	if (!media_name_valid(m_ptr->name))
106
		goto exit;
107
108
	if ((m_ptr->bcast_addr.media_id != m_ptr->type_id) ||
	    !m_ptr->bcast_addr.broadcast)
Per Liden's avatar
Per Liden committed
109
		goto exit;
110
	if (m_ptr->priority > TIPC_MAX_LINK_PRI)
Per Liden's avatar
Per Liden committed
111
		goto exit;
112
	if ((m_ptr->tolerance < TIPC_MIN_LINK_TOL) ||
113
	    (m_ptr->tolerance > TIPC_MAX_LINK_TOL))
Per Liden's avatar
Per Liden committed
114
		goto exit;
115
	if (media_count >= MAX_MEDIA)
Per Liden's avatar
Per Liden committed
116
		goto exit;
117
	if (tipc_media_find(m_ptr->name) || media_find_id(m_ptr->type_id))
118
		goto exit;
Per Liden's avatar
Per Liden committed
119

120
	media_list[media_count] = m_ptr;
121
	media_count++;
Per Liden's avatar
Per Liden committed
122
123
	res = 0;
exit:
124
	write_unlock_bh(&tipc_net_lock);
125
126
	if (res)
		warn("Media <%s> registration error\n", m_ptr->name);
Per Liden's avatar
Per Liden committed
127
128
129
130
	return res;
}

/**
131
 * tipc_media_addr_printf - record media address in print buffer
Per Liden's avatar
Per Liden committed
132
 */
133
void tipc_media_addr_printf(struct print_buf *pb, struct tipc_media_addr *a)
Per Liden's avatar
Per Liden committed
134
{
135
	char addr_str[MAX_ADDR_STR];
136
	struct tipc_media *m_ptr;
Per Liden's avatar
Per Liden committed
137

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

140
141
142
143
	if (m_ptr && !m_ptr->addr2str(a, addr_str, sizeof(addr_str)))
		tipc_printf(pb, "%s(%s)", m_ptr->name, addr_str);
	else {
		u32 i;
Per Liden's avatar
Per Liden committed
144

145
146
147
		tipc_printf(pb, "UNKNOWN(%u)", a->media_id);
		for (i = 0; i < sizeof(a->value); i++)
			tipc_printf(pb, "-%02x", a->value[i]);
Per Liden's avatar
Per Liden committed
148
149
150
151
	}
}

/**
152
 * tipc_media_get_names - record names of registered media in buffer
Per Liden's avatar
Per Liden committed
153
 */
154
struct sk_buff *tipc_media_get_names(void)
Per Liden's avatar
Per Liden committed
155
156
157
158
{
	struct sk_buff *buf;
	int i;

159
	buf = tipc_cfg_reply_alloc(MAX_MEDIA * TLV_SPACE(TIPC_MAX_MEDIA_NAME));
Per Liden's avatar
Per Liden committed
160
161
162
	if (!buf)
		return NULL;

163
	read_lock_bh(&tipc_net_lock);
164
165
166
167
	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
168
	}
169
	read_unlock_bh(&tipc_net_lock);
Per Liden's avatar
Per Liden committed
170
171
172
173
174
	return buf;
}

/**
 * bearer_name_validate - validate & (optionally) deconstruct bearer name
175
176
 * @name: ptr to bearer name string
 * @name_parts: ptr to area for bearer name components (or NULL if not needed)
177
 *
Per Liden's avatar
Per Liden committed
178
179
 * Returns 1 if bearer name is valid, otherwise 0.
 */
180
static int bearer_name_validate(const char *name,
181
				struct tipc_bearer_names *name_parts)
Per Liden's avatar
Per Liden committed
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
{
	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;
198
199
	if_name = strchr(media_name, ':');
	if (if_name == NULL)
Per Liden's avatar
Per Liden committed
200
201
202
203
204
205
		return 0;
	*(if_name++) = 0;
	media_len = if_name - media_name;
	if_len = strlen(if_name) + 1;

	/* validate component parts of bearer name */
206
207
	if ((media_len <= 1) || (media_len > TIPC_MAX_MEDIA_NAME) ||
	    (if_len <= 1) || (if_len > TIPC_MAX_IF_NAME) ||
Per Liden's avatar
Per Liden committed
208
209
210
211
212
213
214
215
216
217
218
219
220
	    (strspn(media_name, tipc_alphabet) != (media_len - 1)) ||
	    (strspn(if_name, tipc_alphabet) != (if_len - 1)))
		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;
}

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

228
	for (i = 0, b_ptr = tipc_bearers; i < MAX_BEARERS; i++, b_ptr++) {
229
		if (b_ptr->active && (!strcmp(b_ptr->name, name)))
Per Liden's avatar
Per Liden committed
230
231
			return b_ptr;
	}
232
	return NULL;
Per Liden's avatar
Per Liden committed
233
234
235
}

/**
236
 * tipc_bearer_find_interface - locates bearer object with matching interface name
Per Liden's avatar
Per Liden committed
237
 */
238
struct tipc_bearer *tipc_bearer_find_interface(const char *if_name)
Per Liden's avatar
Per Liden committed
239
{
240
	struct tipc_bearer *b_ptr;
Per Liden's avatar
Per Liden committed
241
242
243
	char *b_if_name;
	u32 i;

244
	for (i = 0, b_ptr = tipc_bearers; i < MAX_BEARERS; i++, b_ptr++) {
Per Liden's avatar
Per Liden committed
245
246
		if (!b_ptr->active)
			continue;
247
		b_if_name = strchr(b_ptr->name, ':') + 1;
Per Liden's avatar
Per Liden committed
248
249
250
		if (!strcmp(b_if_name, if_name))
			return b_ptr;
	}
251
	return NULL;
Per Liden's avatar
Per Liden committed
252
253
254
}

/**
255
 * tipc_bearer_get_names - record names of bearers in buffer
Per Liden's avatar
Per Liden committed
256
 */
257
struct sk_buff *tipc_bearer_get_names(void)
Per Liden's avatar
Per Liden committed
258
259
{
	struct sk_buff *buf;
260
	struct tipc_bearer *b_ptr;
Per Liden's avatar
Per Liden committed
261
262
	int i, j;

263
	buf = tipc_cfg_reply_alloc(MAX_BEARERS * TLV_SPACE(TIPC_MAX_BEARER_NAME));
Per Liden's avatar
Per Liden committed
264
265
266
	if (!buf)
		return NULL;

267
	read_lock_bh(&tipc_net_lock);
268
	for (i = 0; i < media_count; i++) {
Per Liden's avatar
Per Liden committed
269
		for (j = 0; j < MAX_BEARERS; j++) {
270
			b_ptr = &tipc_bearers[j];
271
			if (b_ptr->active && (b_ptr->media == media_list[i])) {
272
				tipc_cfg_append_tlv(buf, TIPC_TLV_BEARER_NAME,
273
274
						    b_ptr->name,
						    strlen(b_ptr->name) + 1);
Per Liden's avatar
Per Liden committed
275
276
277
			}
		}
	}
278
	read_unlock_bh(&tipc_net_lock);
Per Liden's avatar
Per Liden committed
279
280
281
	return buf;
}

282
void tipc_bearer_add_dest(struct tipc_bearer *b_ptr, u32 dest)
Per Liden's avatar
Per Liden committed
283
{
284
285
	tipc_nmap_add(&b_ptr->nodes, dest);
	tipc_bcbearer_sort();
286
	tipc_disc_add_dest(b_ptr->link_req);
Per Liden's avatar
Per Liden committed
287
288
}

289
void tipc_bearer_remove_dest(struct tipc_bearer *b_ptr, u32 dest)
Per Liden's avatar
Per Liden committed
290
{
291
292
	tipc_nmap_remove(&b_ptr->nodes, dest);
	tipc_bcbearer_sort();
293
	tipc_disc_remove_dest(b_ptr->link_req);
Per Liden's avatar
Per Liden committed
294
295
296
297
298
299
}

/*
 * bearer_push(): Resolve bearer congestion. Force the waiting
 * links to push out their unsent packets, one packet per link
 * per iteration, until all packets are gone or congestion reoccurs.
300
 * 'tipc_net_lock' is read_locked when this function is called
Per Liden's avatar
Per Liden committed
301
302
303
 * bearer.lock must be taken before calling
 * Returns binary true(1) ore false(0)
 */
304
static int bearer_push(struct tipc_bearer *b_ptr)
Per Liden's avatar
Per Liden committed
305
{
306
	u32 res = 0;
307
	struct tipc_link *ln, *tln;
Per Liden's avatar
Per Liden committed
308

309
	if (b_ptr->blocked)
Per Liden's avatar
Per Liden committed
310
311
312
313
		return 0;

	while (!list_empty(&b_ptr->cong_links) && (res != PUSH_FAILED)) {
		list_for_each_entry_safe(ln, tln, &b_ptr->cong_links, link_list) {
314
			res = tipc_link_push_packet(ln);
Per Liden's avatar
Per Liden committed
315
316
317
318
319
320
321
322
323
			if (res == PUSH_FAILED)
				break;
			if (res == PUSH_FINISHED)
				list_move_tail(&ln->link_list, &b_ptr->links);
		}
	}
	return list_empty(&b_ptr->cong_links);
}

324
void tipc_bearer_lock_push(struct tipc_bearer *b_ptr)
Per Liden's avatar
Per Liden committed
325
{
326
	spin_lock_bh(&b_ptr->lock);
327
	bearer_push(b_ptr);
328
	spin_unlock_bh(&b_ptr->lock);
Per Liden's avatar
Per Liden committed
329
330
331
332
}


/*
333
334
 * Interrupt enabling new requests after bearer congestion or blocking:
 * See bearer_send().
Per Liden's avatar
Per Liden committed
335
 */
336
void tipc_continue(struct tipc_bearer *b_ptr)
Per Liden's avatar
Per Liden committed
337
{
338
	spin_lock_bh(&b_ptr->lock);
Per Liden's avatar
Per Liden committed
339
	if (!list_empty(&b_ptr->cong_links))
340
		tipc_k_signal((Handler)tipc_bearer_lock_push, (unsigned long)b_ptr);
341
342
	b_ptr->blocked = 0;
	spin_unlock_bh(&b_ptr->lock);
Per Liden's avatar
Per Liden committed
343
344
345
}

/*
346
347
348
 * Schedule link for sending of messages after the bearer
 * has been deblocked by 'continue()'. This method is called
 * when somebody tries to send a message via this link while
349
 * the bearer is congested. 'tipc_net_lock' is in read_lock here
Per Liden's avatar
Per Liden committed
350
351
 * bearer.lock is busy
 */
352
353
static void tipc_bearer_schedule_unlocked(struct tipc_bearer *b_ptr,
						struct tipc_link *l_ptr)
Per Liden's avatar
Per Liden committed
354
355
356
357
358
{
	list_move_tail(&l_ptr->link_list, &b_ptr->cong_links);
}

/*
359
360
361
 * Schedule link for sending of messages after the bearer
 * has been deblocked by 'continue()'. This method is called
 * when somebody tries to send a message via this link while
362
 * the bearer is congested. 'tipc_net_lock' is in read_lock here,
Per Liden's avatar
Per Liden committed
363
364
 * bearer.lock is free
 */
365
void tipc_bearer_schedule(struct tipc_bearer *b_ptr, struct tipc_link *l_ptr)
Per Liden's avatar
Per Liden committed
366
{
367
	spin_lock_bh(&b_ptr->lock);
368
	tipc_bearer_schedule_unlocked(b_ptr, l_ptr);
369
	spin_unlock_bh(&b_ptr->lock);
Per Liden's avatar
Per Liden committed
370
371
372
373
}


/*
374
 * tipc_bearer_resolve_congestion(): Check if there is bearer congestion,
Per Liden's avatar
Per Liden committed
375
 * and if there is, try to resolve it before returning.
376
 * 'tipc_net_lock' is read_locked when this function is called
Per Liden's avatar
Per Liden committed
377
 */
378
379
int tipc_bearer_resolve_congestion(struct tipc_bearer *b_ptr,
					struct tipc_link *l_ptr)
Per Liden's avatar
Per Liden committed
380
381
382
383
384
{
	int res = 1;

	if (list_empty(&b_ptr->cong_links))
		return 1;
385
	spin_lock_bh(&b_ptr->lock);
Per Liden's avatar
Per Liden committed
386
	if (!bearer_push(b_ptr)) {
387
		tipc_bearer_schedule_unlocked(b_ptr, l_ptr);
Per Liden's avatar
Per Liden committed
388
389
		res = 0;
	}
390
	spin_unlock_bh(&b_ptr->lock);
Per Liden's avatar
Per Liden committed
391
392
393
	return res;
}

394
395
396
/**
 * tipc_bearer_congested - determines if bearer is currently congested
 */
397
int tipc_bearer_congested(struct tipc_bearer *b_ptr, struct tipc_link *l_ptr)
398
{
399
	if (unlikely(b_ptr->blocked))
400
401
402
403
404
		return 1;
	if (likely(list_empty(&b_ptr->cong_links)))
		return 0;
	return !tipc_bearer_resolve_congestion(b_ptr, l_ptr);
}
Per Liden's avatar
Per Liden committed
405
406
407

/**
 * tipc_enable_bearer - enable bearer with the given name
408
 */
409
int tipc_enable_bearer(const char *name, u32 disc_domain, u32 priority)
Per Liden's avatar
Per Liden committed
410
{
411
	struct tipc_bearer *b_ptr;
412
	struct tipc_media *m_ptr;
413
	struct tipc_bearer_names b_names;
Per Liden's avatar
Per Liden committed
414
415
416
417
418
419
	char addr_string[16];
	u32 bearer_id;
	u32 with_this_prio;
	u32 i;
	int res = -EINVAL;

420
	if (!tipc_own_addr) {
421
422
		warn("Bearer <%s> rejected, not supported in standalone mode\n",
		     name);
Per Liden's avatar
Per Liden committed
423
		return -ENOPROTOOPT;
424
	}
425
	if (!bearer_name_validate(name, &b_names)) {
426
		warn("Bearer <%s> rejected, illegal name\n", name);
427
		return -EINVAL;
428
	}
429
430
431
432
433
	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 */
434
		} else if (in_own_cluster_exact(disc_domain))
435
436
437
			res = 0;   /* accept specified node in own cluster */
	}
	if (res) {
438
		warn("Bearer <%s> rejected, illegal discovery domain\n", name);
439
440
		return -EINVAL;
	}
441
	if ((priority > TIPC_MAX_LINK_PRI) &&
442
443
	    (priority != TIPC_MEDIA_LINK_PRI)) {
		warn("Bearer <%s> rejected, illegal priority\n", name);
Per Liden's avatar
Per Liden committed
444
		return -EINVAL;
445
	}
Per Liden's avatar
Per Liden committed
446

447
	write_lock_bh(&tipc_net_lock);
Per Liden's avatar
Per Liden committed
448

449
	m_ptr = tipc_media_find(b_names.media_name);
Per Liden's avatar
Per Liden committed
450
	if (!m_ptr) {
451
		warn("Bearer <%s> rejected, media <%s> not registered\n", name,
452
		     b_names.media_name);
453
		goto exit;
Per Liden's avatar
Per Liden committed
454
	}
455
456

	if (priority == TIPC_MEDIA_LINK_PRI)
Per Liden's avatar
Per Liden committed
457
458
459
460
461
462
		priority = m_ptr->priority;

restart:
	bearer_id = MAX_BEARERS;
	with_this_prio = 1;
	for (i = MAX_BEARERS; i-- != 0; ) {
463
		if (!tipc_bearers[i].active) {
Per Liden's avatar
Per Liden committed
464
465
466
			bearer_id = i;
			continue;
		}
467
		if (!strcmp(name, tipc_bearers[i].name)) {
468
			warn("Bearer <%s> rejected, already enabled\n", name);
469
			goto exit;
Per Liden's avatar
Per Liden committed
470
		}
471
		if ((tipc_bearers[i].priority == priority) &&
Per Liden's avatar
Per Liden committed
472
473
		    (++with_this_prio > 2)) {
			if (priority-- == 0) {
474
475
				warn("Bearer <%s> rejected, duplicate priority\n",
				     name);
476
				goto exit;
Per Liden's avatar
Per Liden committed
477
			}
478
			warn("Bearer <%s> priority adjustment required %u->%u\n",
Per Liden's avatar
Per Liden committed
479
480
481
482
483
			     name, priority + 1, priority);
			goto restart;
		}
	}
	if (bearer_id >= MAX_BEARERS) {
484
		warn("Bearer <%s> rejected, bearer limit reached (%u)\n",
485
		     name, MAX_BEARERS);
486
		goto exit;
Per Liden's avatar
Per Liden committed
487
488
	}

489
	b_ptr = &tipc_bearers[bearer_id];
490
491
	strcpy(b_ptr->name, name);
	res = m_ptr->enable_bearer(b_ptr);
Per Liden's avatar
Per Liden committed
492
	if (res) {
493
		warn("Bearer <%s> rejected, enable failure (%d)\n", name, -res);
494
		goto exit;
Per Liden's avatar
Per Liden committed
495
496
497
498
	}

	b_ptr->identity = bearer_id;
	b_ptr->media = m_ptr;
499
500
	b_ptr->tolerance = m_ptr->tolerance;
	b_ptr->window = m_ptr->window;
Per Liden's avatar
Per Liden committed
501
502
503
504
505
	b_ptr->net_plane = bearer_id + 'A';
	b_ptr->active = 1;
	b_ptr->priority = priority;
	INIT_LIST_HEAD(&b_ptr->cong_links);
	INIT_LIST_HEAD(&b_ptr->links);
506
	spin_lock_init(&b_ptr->lock);
507
508
509
510
511
512
513
514

	res = tipc_disc_create(b_ptr, &m_ptr->bcast_addr, disc_domain);
	if (res) {
		bearer_disable(b_ptr);
		warn("Bearer <%s> rejected, discovery object creation failed\n",
		     name);
		goto exit;
	}
515
	info("Enabled bearer <%s>, discovery domain %s, priority %u\n",
516
	     name, tipc_addr_string_fill(addr_string, disc_domain), priority);
517
exit:
518
	write_unlock_bh(&tipc_net_lock);
Per Liden's avatar
Per Liden committed
519
520
521
522
	return res;
}

/**
523
 * tipc_block_bearer - Block the bearer with the given name, and reset all its links
Per Liden's avatar
Per Liden committed
524
525
526
 */
int tipc_block_bearer(const char *name)
{
527
	struct tipc_bearer *b_ptr = NULL;
528
529
	struct tipc_link *l_ptr;
	struct tipc_link *temp_l_ptr;
Per Liden's avatar
Per Liden committed
530

531
	read_lock_bh(&tipc_net_lock);
532
	b_ptr = tipc_bearer_find(name);
Per Liden's avatar
Per Liden committed
533
534
	if (!b_ptr) {
		warn("Attempt to block unknown bearer <%s>\n", name);
535
		read_unlock_bh(&tipc_net_lock);
Per Liden's avatar
Per Liden committed
536
537
538
		return -EINVAL;
	}

539
	info("Blocking bearer <%s>\n", name);
540
541
	spin_lock_bh(&b_ptr->lock);
	b_ptr->blocked = 1;
542
	list_splice_init(&b_ptr->cong_links, &b_ptr->links);
Per Liden's avatar
Per Liden committed
543
	list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) {
544
		struct tipc_node *n_ptr = l_ptr->owner;
Per Liden's avatar
Per Liden committed
545
546

		spin_lock_bh(&n_ptr->lock);
547
		tipc_link_reset(l_ptr);
Per Liden's avatar
Per Liden committed
548
549
		spin_unlock_bh(&n_ptr->lock);
	}
550
	spin_unlock_bh(&b_ptr->lock);
551
	read_unlock_bh(&tipc_net_lock);
552
	return 0;
Per Liden's avatar
Per Liden committed
553
554
555
}

/**
556
 * bearer_disable
557
 *
558
 * Note: This routine assumes caller holds tipc_net_lock.
Per Liden's avatar
Per Liden committed
559
 */
560
static void bearer_disable(struct tipc_bearer *b_ptr)
Per Liden's avatar
Per Liden committed
561
{
562
563
	struct tipc_link *l_ptr;
	struct tipc_link *temp_l_ptr;
Per Liden's avatar
Per Liden committed
564

565
566
567
568
	info("Disabling bearer <%s>\n", b_ptr->name);
	spin_lock_bh(&b_ptr->lock);
	b_ptr->blocked = 1;
	b_ptr->media->disable_bearer(b_ptr);
569
	list_splice_init(&b_ptr->cong_links, &b_ptr->links);
Per Liden's avatar
Per Liden committed
570
	list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) {
571
		tipc_link_delete(l_ptr);
Per Liden's avatar
Per Liden committed
572
	}
573
574
	if (b_ptr->link_req)
		tipc_disc_delete(b_ptr->link_req);
575
576
	spin_unlock_bh(&b_ptr->lock);
	memset(b_ptr, 0, sizeof(struct tipc_bearer));
Per Liden's avatar
Per Liden committed
577
578
579
580
}

int tipc_disable_bearer(const char *name)
{
581
	struct tipc_bearer *b_ptr;
Per Liden's avatar
Per Liden committed
582
583
	int res;

584
	write_lock_bh(&tipc_net_lock);
585
	b_ptr = tipc_bearer_find(name);
586
587
588
	if (b_ptr == NULL) {
		warn("Attempt to disable unknown bearer <%s>\n", name);
		res = -EINVAL;
589
590
591
592
	} else {
		bearer_disable(b_ptr);
		res = 0;
	}
593
	write_unlock_bh(&tipc_net_lock);
Per Liden's avatar
Per Liden committed
594
595
596
597
598
	return res;
}



599
void tipc_bearer_stop(void)
Per Liden's avatar
Per Liden committed
600
601
602
603
{
	u32 i;

	for (i = 0; i < MAX_BEARERS; i++) {
604
		if (tipc_bearers[i].active)
605
			bearer_disable(&tipc_bearers[i]);
Per Liden's avatar
Per Liden committed
606
607
608
	}
	media_count = 0;
}