bearer.c 13.8 KB
Newer Older
P
Per Liden 已提交
1 2
/*
 * net/tipc/bearer.c: TIPC bearer code
3
 *
4
 * Copyright (c) 1996-2006, 2013, Ericsson AB
5
 * Copyright (c) 2004-2006, 2010-2011, Wind River Systems
P
Per Liden 已提交
6 7
 * All rights reserved.
 *
P
Per Liden 已提交
8
 * Redistribution and use in source and binary forms, with or without
P
Per Liden 已提交
9 10
 * modification, are permitted provided that the following conditions are met:
 *
P
Per Liden 已提交
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.
P
Per Liden 已提交
19
 *
P
Per Liden 已提交
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
P
Per Liden 已提交
34 35 36 37 38 39 40 41
 * POSSIBILITY OF SUCH DAMAGE.
 */

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

42
#define MAX_ADDR_STR 60
P
Per Liden 已提交
43

44
static struct tipc_media * const media_info_array[] = {
45 46 47 48 49 50
	&eth_media_info,
#ifdef CONFIG_TIPC_MEDIA_IB
	&ib_media_info,
#endif
	NULL
};
P
Per Liden 已提交
51

52
struct tipc_bearer tipc_bearers[MAX_BEARERS];
P
Per Liden 已提交
53

54 55
static void bearer_disable(struct tipc_bearer *b_ptr);

P
Per Liden 已提交
56
/**
57
 * tipc_media_find - locates specified media object by name
P
Per Liden 已提交
58
 */
59
struct tipc_media *tipc_media_find(const char *name)
P
Per Liden 已提交
60 61 62
{
	u32 i;

63 64
	for (i = 0; media_info_array[i] != NULL; i++) {
		if (!strcmp(media_info_array[i]->name, name))
65
			break;
P
Per Liden 已提交
66
	}
67
	return media_info_array[i];
P
Per Liden 已提交
68 69
}

70 71 72
/**
 * media_find_id - locates specified media object by type identifier
 */
73
static struct tipc_media *media_find_id(u8 type)
74 75 76
{
	u32 i;

77 78
	for (i = 0; media_info_array[i] != NULL; i++) {
		if (media_info_array[i]->type_id == type)
79
			break;
80
	}
81
	return media_info_array[i];
P
Per Liden 已提交
82 83 84
}

/**
85
 * tipc_media_addr_printf - record media address in print buffer
P
Per Liden 已提交
86
 */
87
void tipc_media_addr_printf(char *buf, int len, struct tipc_media_addr *a)
P
Per Liden 已提交
88
{
89
	char addr_str[MAX_ADDR_STR];
90
	struct tipc_media *m_ptr;
91
	int ret;
P
Per Liden 已提交
92

93
	m_ptr = media_find_id(a->media_id);
P
Per Liden 已提交
94

95
	if (m_ptr && !m_ptr->addr2str(a, addr_str, sizeof(addr_str)))
96
		ret = tipc_snprintf(buf, len, "%s(%s)", m_ptr->name, addr_str);
97 98
	else {
		u32 i;
P
Per Liden 已提交
99

100
		ret = tipc_snprintf(buf, len, "UNKNOWN(%u)", a->media_id);
101
		for (i = 0; i < sizeof(a->value); i++)
102 103
			ret += tipc_snprintf(buf - ret, len + ret,
					    "-%02x", a->value[i]);
P
Per Liden 已提交
104 105 106 107
	}
}

/**
108
 * tipc_media_get_names - record names of registered media in buffer
P
Per Liden 已提交
109
 */
110
struct sk_buff *tipc_media_get_names(void)
P
Per Liden 已提交
111 112 113 114
{
	struct sk_buff *buf;
	int i;

115
	buf = tipc_cfg_reply_alloc(MAX_MEDIA * TLV_SPACE(TIPC_MAX_MEDIA_NAME));
P
Per Liden 已提交
116 117 118
	if (!buf)
		return NULL;

119
	for (i = 0; media_info_array[i] != NULL; i++) {
120
		tipc_cfg_append_tlv(buf, TIPC_TLV_MEDIA_NAME,
121 122
				    media_info_array[i]->name,
				    strlen(media_info_array[i]->name) + 1);
P
Per Liden 已提交
123 124 125 126 127 128
	}
	return buf;
}

/**
 * bearer_name_validate - validate & (optionally) deconstruct bearer name
129 130
 * @name: ptr to bearer name string
 * @name_parts: ptr to area for bearer name components (or NULL if not needed)
131
 *
P
Per Liden 已提交
132 133
 * Returns 1 if bearer name is valid, otherwise 0.
 */
134
static int bearer_name_validate(const char *name,
135
				struct tipc_bearer_names *name_parts)
P
Per Liden 已提交
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
{
	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;
152 153
	if_name = strchr(media_name, ':');
	if (if_name == NULL)
P
Per Liden 已提交
154 155 156 157 158 159
		return 0;
	*(if_name++) = 0;
	media_len = if_name - media_name;
	if_len = strlen(if_name) + 1;

	/* validate component parts of bearer name */
160
	if ((media_len <= 1) || (media_len > TIPC_MAX_MEDIA_NAME) ||
161
	    (if_len <= 1) || (if_len > TIPC_MAX_IF_NAME))
P
Per Liden 已提交
162 163 164 165 166 167 168 169 170 171 172
		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;
}

/**
173
 * tipc_bearer_find - locates bearer object with matching bearer name
P
Per Liden 已提交
174
 */
175
struct tipc_bearer *tipc_bearer_find(const char *name)
P
Per Liden 已提交
176
{
177
	struct tipc_bearer *b_ptr;
P
Per Liden 已提交
178 179
	u32 i;

180
	for (i = 0, b_ptr = tipc_bearers; i < MAX_BEARERS; i++, b_ptr++) {
181
		if (b_ptr->active && (!strcmp(b_ptr->name, name)))
P
Per Liden 已提交
182 183
			return b_ptr;
	}
184
	return NULL;
P
Per Liden 已提交
185 186 187
}

/**
188
 * tipc_bearer_find_interface - locates bearer object with matching interface name
P
Per Liden 已提交
189
 */
190
struct tipc_bearer *tipc_bearer_find_interface(const char *if_name)
P
Per Liden 已提交
191
{
192
	struct tipc_bearer *b_ptr;
P
Per Liden 已提交
193 194 195
	char *b_if_name;
	u32 i;

196
	for (i = 0, b_ptr = tipc_bearers; i < MAX_BEARERS; i++, b_ptr++) {
P
Per Liden 已提交
197 198
		if (!b_ptr->active)
			continue;
199
		b_if_name = strchr(b_ptr->name, ':') + 1;
P
Per Liden 已提交
200 201 202
		if (!strcmp(b_if_name, if_name))
			return b_ptr;
	}
203
	return NULL;
P
Per Liden 已提交
204 205 206
}

/**
207
 * tipc_bearer_get_names - record names of bearers in buffer
P
Per Liden 已提交
208
 */
209
struct sk_buff *tipc_bearer_get_names(void)
P
Per Liden 已提交
210 211
{
	struct sk_buff *buf;
212
	struct tipc_bearer *b;
P
Per Liden 已提交
213 214
	int i, j;

215
	buf = tipc_cfg_reply_alloc(MAX_BEARERS * TLV_SPACE(TIPC_MAX_BEARER_NAME));
P
Per Liden 已提交
216 217 218
	if (!buf)
		return NULL;

219
	read_lock_bh(&tipc_net_lock);
220
	for (i = 0; media_info_array[i] != NULL; i++) {
P
Per Liden 已提交
221
		for (j = 0; j < MAX_BEARERS; j++) {
222 223
			b = &tipc_bearers[j];
			if (b->active && (b->media == media_info_array[i])) {
224
				tipc_cfg_append_tlv(buf, TIPC_TLV_BEARER_NAME,
225 226
						    b->name,
						    strlen(b->name) + 1);
P
Per Liden 已提交
227 228 229
			}
		}
	}
230
	read_unlock_bh(&tipc_net_lock);
P
Per Liden 已提交
231 232 233
	return buf;
}

234
void tipc_bearer_add_dest(struct tipc_bearer *b_ptr, u32 dest)
P
Per Liden 已提交
235
{
236 237
	tipc_nmap_add(&b_ptr->nodes, dest);
	tipc_bcbearer_sort();
238
	tipc_disc_add_dest(b_ptr->link_req);
P
Per Liden 已提交
239 240
}

241
void tipc_bearer_remove_dest(struct tipc_bearer *b_ptr, u32 dest)
P
Per Liden 已提交
242
{
243 244
	tipc_nmap_remove(&b_ptr->nodes, dest);
	tipc_bcbearer_sort();
245
	tipc_disc_remove_dest(b_ptr->link_req);
P
Per Liden 已提交
246 247 248 249
}

/**
 * tipc_enable_bearer - enable bearer with the given name
250
 */
251
int tipc_enable_bearer(const char *name, u32 disc_domain, u32 priority)
P
Per Liden 已提交
252
{
253
	struct tipc_bearer *b_ptr;
254
	struct tipc_media *m_ptr;
255
	struct tipc_bearer_names b_names;
P
Per Liden 已提交
256 257 258 259 260 261
	char addr_string[16];
	u32 bearer_id;
	u32 with_this_prio;
	u32 i;
	int res = -EINVAL;

262
	if (!tipc_own_addr) {
263 264
		pr_warn("Bearer <%s> rejected, not supported in standalone mode\n",
			name);
P
Per Liden 已提交
265
		return -ENOPROTOOPT;
266
	}
267
	if (!bearer_name_validate(name, &b_names)) {
268
		pr_warn("Bearer <%s> rejected, illegal name\n", name);
P
Per Liden 已提交
269
		return -EINVAL;
270
	}
271 272 273 274 275
	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 */
276
		} else if (in_own_cluster_exact(disc_domain))
277 278 279
			res = 0;   /* accept specified node in own cluster */
	}
	if (res) {
280 281
		pr_warn("Bearer <%s> rejected, illegal discovery domain\n",
			name);
282 283
		return -EINVAL;
	}
284
	if ((priority > TIPC_MAX_LINK_PRI) &&
285
	    (priority != TIPC_MEDIA_LINK_PRI)) {
286
		pr_warn("Bearer <%s> rejected, illegal priority\n", name);
P
Per Liden 已提交
287
		return -EINVAL;
288
	}
P
Per Liden 已提交
289

290
	write_lock_bh(&tipc_net_lock);
P
Per Liden 已提交
291

292
	m_ptr = tipc_media_find(b_names.media_name);
P
Per Liden 已提交
293
	if (!m_ptr) {
294 295
		pr_warn("Bearer <%s> rejected, media <%s> not registered\n",
			name, b_names.media_name);
296
		goto exit;
P
Per Liden 已提交
297
	}
P
Per Liden 已提交
298 299

	if (priority == TIPC_MEDIA_LINK_PRI)
P
Per Liden 已提交
300 301 302 303 304 305
		priority = m_ptr->priority;

restart:
	bearer_id = MAX_BEARERS;
	with_this_prio = 1;
	for (i = MAX_BEARERS; i-- != 0; ) {
306
		if (!tipc_bearers[i].active) {
P
Per Liden 已提交
307 308 309
			bearer_id = i;
			continue;
		}
310
		if (!strcmp(name, tipc_bearers[i].name)) {
311 312
			pr_warn("Bearer <%s> rejected, already enabled\n",
				name);
313
			goto exit;
P
Per Liden 已提交
314
		}
315
		if ((tipc_bearers[i].priority == priority) &&
P
Per Liden 已提交
316 317
		    (++with_this_prio > 2)) {
			if (priority-- == 0) {
318 319
				pr_warn("Bearer <%s> rejected, duplicate priority\n",
					name);
320
				goto exit;
P
Per Liden 已提交
321
			}
322 323
			pr_warn("Bearer <%s> priority adjustment required %u->%u\n",
				name, priority + 1, priority);
P
Per Liden 已提交
324 325 326 327
			goto restart;
		}
	}
	if (bearer_id >= MAX_BEARERS) {
328 329
		pr_warn("Bearer <%s> rejected, bearer limit reached (%u)\n",
			name, MAX_BEARERS);
330
		goto exit;
P
Per Liden 已提交
331 332
	}

333
	b_ptr = &tipc_bearers[bearer_id];
334
	strcpy(b_ptr->name, name);
335
	res = m_ptr->enable_media(b_ptr);
P
Per Liden 已提交
336
	if (res) {
337 338
		pr_warn("Bearer <%s> rejected, enable failure (%d)\n",
			name, -res);
339
		goto exit;
P
Per Liden 已提交
340 341 342 343
	}

	b_ptr->identity = bearer_id;
	b_ptr->media = m_ptr;
344 345
	b_ptr->tolerance = m_ptr->tolerance;
	b_ptr->window = m_ptr->window;
P
Per Liden 已提交
346 347 348 349
	b_ptr->net_plane = bearer_id + 'A';
	b_ptr->active = 1;
	b_ptr->priority = priority;
	INIT_LIST_HEAD(&b_ptr->links);
350
	spin_lock_init(&b_ptr->lock);
351

352
	res = tipc_disc_create(b_ptr, &b_ptr->bcast_addr, disc_domain);
353 354
	if (res) {
		bearer_disable(b_ptr);
355 356
		pr_warn("Bearer <%s> rejected, discovery object creation failed\n",
			name);
357 358
		goto exit;
	}
359 360 361
	pr_info("Enabled bearer <%s>, discovery domain %s, priority %u\n",
		name,
		tipc_addr_string_fill(addr_string, disc_domain), priority);
362
exit:
363
	write_unlock_bh(&tipc_net_lock);
P
Per Liden 已提交
364 365 366 367
	return res;
}

/**
368
 * tipc_reset_bearer - Reset all links established over this bearer
P
Per Liden 已提交
369
 */
370
static int tipc_reset_bearer(struct tipc_bearer *b_ptr)
P
Per Liden 已提交
371
{
372 373
	struct tipc_link *l_ptr;
	struct tipc_link *temp_l_ptr;
P
Per Liden 已提交
374

375
	read_lock_bh(&tipc_net_lock);
376
	pr_info("Resetting bearer <%s>\n", b_ptr->name);
377
	spin_lock_bh(&b_ptr->lock);
P
Per Liden 已提交
378
	list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) {
379
		struct tipc_node *n_ptr = l_ptr->owner;
P
Per Liden 已提交
380 381

		spin_lock_bh(&n_ptr->lock);
382
		tipc_link_reset(l_ptr);
P
Per Liden 已提交
383 384
		spin_unlock_bh(&n_ptr->lock);
	}
385
	spin_unlock_bh(&b_ptr->lock);
386
	read_unlock_bh(&tipc_net_lock);
387
	return 0;
P
Per Liden 已提交
388 389 390
}

/**
391
 * bearer_disable
392
 *
393
 * Note: This routine assumes caller holds tipc_net_lock.
P
Per Liden 已提交
394
 */
395
static void bearer_disable(struct tipc_bearer *b_ptr)
P
Per Liden 已提交
396
{
397 398
	struct tipc_link *l_ptr;
	struct tipc_link *temp_l_ptr;
399
	struct tipc_link_req *temp_req;
P
Per Liden 已提交
400

401
	pr_info("Disabling bearer <%s>\n", b_ptr->name);
402
	spin_lock_bh(&b_ptr->lock);
403
	b_ptr->media->disable_media(b_ptr);
P
Per Liden 已提交
404
	list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) {
405
		tipc_link_delete(l_ptr);
P
Per Liden 已提交
406
	}
407 408
	temp_req = b_ptr->link_req;
	b_ptr->link_req = NULL;
409
	spin_unlock_bh(&b_ptr->lock);
410 411 412 413

	if (temp_req)
		tipc_disc_delete(temp_req);

414
	memset(b_ptr, 0, sizeof(struct tipc_bearer));
P
Per Liden 已提交
415 416 417 418
}

int tipc_disable_bearer(const char *name)
{
419
	struct tipc_bearer *b_ptr;
P
Per Liden 已提交
420 421
	int res;

422
	write_lock_bh(&tipc_net_lock);
423
	b_ptr = tipc_bearer_find(name);
424
	if (b_ptr == NULL) {
425
		pr_warn("Attempt to disable unknown bearer <%s>\n", name);
426
		res = -EINVAL;
427 428 429 430
	} else {
		bearer_disable(b_ptr);
		res = 0;
	}
431
	write_unlock_bh(&tipc_net_lock);
P
Per Liden 已提交
432 433 434
	return res;
}

435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485
/**
 * tipc_l2_rcv_msg - handle incoming TIPC message from an interface
 * @buf: the received packet
 * @dev: the net device that the packet was received on
 * @pt: the packet_type structure which was used to register this handler
 * @orig_dev: the original receive net device in case the device is a bond
 *
 * Accept only packets explicitly sent to this node, or broadcast packets;
 * ignores packets sent using interface multicast, and traffic sent to other
 * nodes (which can happen if interface is running in promiscuous mode).
 */
static int tipc_l2_rcv_msg(struct sk_buff *buf, struct net_device *dev,
			   struct packet_type *pt, struct net_device *orig_dev)
{
	struct tipc_bearer *b_ptr;

	if (!net_eq(dev_net(dev), &init_net)) {
		kfree_skb(buf);
		return NET_RX_DROP;
	}

	rcu_read_lock();
	b_ptr = rcu_dereference(dev->tipc_ptr);
	if (likely(b_ptr)) {
		if (likely(buf->pkt_type <= PACKET_BROADCAST)) {
			buf->next = NULL;
			tipc_recv_msg(buf, b_ptr);
			rcu_read_unlock();
			return NET_RX_SUCCESS;
		}
	}
	rcu_read_unlock();

	kfree_skb(buf);
	return NET_RX_DROP;
}

/**
 * tipc_l2_device_event - handle device events from network device
 * @nb: the context of the notification
 * @evt: the type of event
 * @ptr: the net device that the event was on
 *
 * This function is called by the Ethernet driver in case of link
 * change event.
 */
static int tipc_l2_device_event(struct notifier_block *nb, unsigned long evt,
				void *ptr)
{
	struct tipc_bearer *b_ptr;
	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
P
Per Liden 已提交
486

487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538
	if (!net_eq(dev_net(dev), &init_net))
		return NOTIFY_DONE;

	rcu_read_lock();
	b_ptr = rcu_dereference(dev->tipc_ptr);
	if (!b_ptr) {
		rcu_read_unlock();
		return NOTIFY_DONE;
	}

	b_ptr->mtu = dev->mtu;

	switch (evt) {
	case NETDEV_CHANGE:
		if (netif_carrier_ok(dev))
			break;
	case NETDEV_DOWN:
	case NETDEV_CHANGEMTU:
	case NETDEV_CHANGEADDR:
		tipc_reset_bearer(b_ptr);
		break;
	case NETDEV_UNREGISTER:
	case NETDEV_CHANGENAME:
		tipc_disable_bearer(b_ptr->name);
		break;
	}
	rcu_read_unlock();

	return NOTIFY_OK;
}

static struct packet_type tipc_packet_type __read_mostly = {
	.type = __constant_htons(ETH_P_TIPC),
	.func = tipc_l2_rcv_msg,
};

static struct notifier_block notifier = {
	.notifier_call  = tipc_l2_device_event,
	.priority	= 0,
};

int tipc_bearer_setup(void)
{
	dev_add_pack(&tipc_packet_type);
	return register_netdevice_notifier(&notifier);
}

void tipc_bearer_cleanup(void)
{
	unregister_netdevice_notifier(&notifier);
	dev_remove_pack(&tipc_packet_type);
}
P
Per Liden 已提交
539

540
void tipc_bearer_stop(void)
P
Per Liden 已提交
541 542 543 544
{
	u32 i;

	for (i = 0; i < MAX_BEARERS; i++) {
545
		if (tipc_bearers[i].active)
546
			bearer_disable(&tipc_bearers[i]);
P
Per Liden 已提交
547 548
	}
}