bearer.c 15.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
/**
 * 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
	if (res)
126
		pr_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
		pr_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
		pr_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
439
		pr_warn("Bearer <%s> rejected, illegal discovery domain\n",
			name);
440
441
		return -EINVAL;
	}
442
	if ((priority > TIPC_MAX_LINK_PRI) &&
443
	    (priority != TIPC_MEDIA_LINK_PRI)) {
444
		pr_warn("Bearer <%s> rejected, illegal priority\n", name);
Per Liden's avatar
Per Liden committed
445
		return -EINVAL;
446
	}
Per Liden's avatar
Per Liden committed
447

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

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

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

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

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

	b_ptr->identity = bearer_id;
	b_ptr->media = m_ptr;
502
503
	b_ptr->tolerance = m_ptr->tolerance;
	b_ptr->window = m_ptr->window;
Per Liden's avatar
Per Liden committed
504
505
506
507
508
	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);
509
	spin_lock_init(&b_ptr->lock);
510
511
512
513

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

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

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

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

		spin_lock_bh(&n_ptr->lock);
551
		tipc_link_reset(l_ptr);
Per Liden's avatar
Per Liden committed
552
553
		spin_unlock_bh(&n_ptr->lock);
	}
554
	spin_unlock_bh(&b_ptr->lock);
555
	read_unlock_bh(&tipc_net_lock);
556
	return 0;
Per Liden's avatar
Per Liden committed
557
558
559
}

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

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

int tipc_disable_bearer(const char *name)
{
585
	struct tipc_bearer *b_ptr;
Per Liden's avatar
Per Liden committed
586
587
	int res;

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



603
void tipc_bearer_stop(void)
Per Liden's avatar
Per Liden committed
604
605
606
607
{
	u32 i;

	for (i = 0; i < MAX_BEARERS; i++) {
608
		if (tipc_bearers[i].active)
609
			bearer_disable(&tipc_bearers[i]);
Per Liden's avatar
Per Liden committed
610
611
612
	}
	media_count = 0;
}