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(char *buf, int len, 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;
137
	int ret;
Per Liden's avatar
Per Liden committed
138

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

141
	if (m_ptr && !m_ptr->addr2str(a, addr_str, sizeof(addr_str)))
142
		ret = tipc_snprintf(buf, len, "%s(%s)", m_ptr->name, addr_str);
143
144
	else {
		u32 i;
Per Liden's avatar
Per Liden committed
145

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

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

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

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

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

	/* validate component parts of bearer name */
208
209
	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
210
211
212
213
214
215
216
217
218
219
220
221
222
	    (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;
}

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

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

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

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

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

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

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

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

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

/*
 * 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.
302
 * 'tipc_net_lock' is read_locked when this function is called
Per Liden's avatar
Per Liden committed
303
304
305
 * bearer.lock must be taken before calling
 * Returns binary true(1) ore false(0)
 */
306
static int bearer_push(struct tipc_bearer *b_ptr)
Per Liden's avatar
Per Liden committed
307
{
308
	u32 res = 0;
309
	struct tipc_link *ln, *tln;
Per Liden's avatar
Per Liden committed
310

311
	if (b_ptr->blocked)
Per Liden's avatar
Per Liden committed
312
313
314
315
		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) {
316
			res = tipc_link_push_packet(ln);
Per Liden's avatar
Per Liden committed
317
318
319
320
321
322
323
324
325
			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);
}

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


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

/*
348
349
350
 * 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
351
 * the bearer is congested. 'tipc_net_lock' is in read_lock here
Per Liden's avatar
Per Liden committed
352
353
 * bearer.lock is busy
 */
354
355
static void tipc_bearer_schedule_unlocked(struct tipc_bearer *b_ptr,
						struct tipc_link *l_ptr)
Per Liden's avatar
Per Liden committed
356
357
358
359
360
{
	list_move_tail(&l_ptr->link_list, &b_ptr->cong_links);
}

/*
361
362
363
 * 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
364
 * the bearer is congested. 'tipc_net_lock' is in read_lock here,
Per Liden's avatar
Per Liden committed
365
366
 * bearer.lock is free
 */
367
void tipc_bearer_schedule(struct tipc_bearer *b_ptr, struct tipc_link *l_ptr)
Per Liden's avatar
Per Liden committed
368
{
369
	spin_lock_bh(&b_ptr->lock);
370
	tipc_bearer_schedule_unlocked(b_ptr, l_ptr);
371
	spin_unlock_bh(&b_ptr->lock);
Per Liden's avatar
Per Liden committed
372
373
374
375
}


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

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

396
397
398
/**
 * tipc_bearer_congested - determines if bearer is currently congested
 */
399
int tipc_bearer_congested(struct tipc_bearer *b_ptr, struct tipc_link *l_ptr)
400
{
401
	if (unlikely(b_ptr->blocked))
402
403
404
405
406
		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
407
408
409

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

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

450
	write_lock_bh(&tipc_net_lock);
Per Liden's avatar
Per Liden committed
451

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

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

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

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

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

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

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

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

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

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

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

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

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

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



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

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