bearer.c 16.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-2013, 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

Y
Ying Xue 已提交
52
struct tipc_bearer __rcu *bearer_list[MAX_BEARERS + 1];
P
Per Liden 已提交
53

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

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; i < MAX_BEARERS; i++) {
Y
Ying Xue 已提交
181
		b_ptr = rtnl_dereference(bearer_list[i]);
182
		if (b_ptr && (!strcmp(b_ptr->name, name)))
P
Per Liden 已提交
183 184
			return b_ptr;
	}
185
	return NULL;
P
Per Liden 已提交
186 187 188
}

/**
189
 * tipc_bearer_get_names - record names of bearers in buffer
P
Per Liden 已提交
190
 */
191
struct sk_buff *tipc_bearer_get_names(void)
P
Per Liden 已提交
192 193
{
	struct sk_buff *buf;
194
	struct tipc_bearer *b;
P
Per Liden 已提交
195 196
	int i, j;

197
	buf = tipc_cfg_reply_alloc(MAX_BEARERS * TLV_SPACE(TIPC_MAX_BEARER_NAME));
P
Per Liden 已提交
198 199 200
	if (!buf)
		return NULL;

201
	read_lock_bh(&tipc_net_lock);
202
	for (i = 0; media_info_array[i] != NULL; i++) {
P
Per Liden 已提交
203
		for (j = 0; j < MAX_BEARERS; j++) {
Y
Ying Xue 已提交
204
			b = rtnl_dereference(bearer_list[j]);
205 206
			if (!b)
				continue;
207
			if (b->media == media_info_array[i]) {
208
				tipc_cfg_append_tlv(buf, TIPC_TLV_BEARER_NAME,
209 210
						    b->name,
						    strlen(b->name) + 1);
P
Per Liden 已提交
211 212 213
			}
		}
	}
214
	read_unlock_bh(&tipc_net_lock);
P
Per Liden 已提交
215 216 217
	return buf;
}

218
void tipc_bearer_add_dest(u32 bearer_id, u32 dest)
P
Per Liden 已提交
219
{
220 221 222 223 224 225 226 227 228 229
	struct tipc_bearer *b_ptr;

	rcu_read_lock();
	b_ptr = rcu_dereference_rtnl(bearer_list[bearer_id]);
	if (b_ptr) {
		tipc_nmap_add(&b_ptr->nodes, dest);
		tipc_bcbearer_sort();
		tipc_disc_add_dest(b_ptr->link_req);
	}
	rcu_read_unlock();
P
Per Liden 已提交
230 231
}

232
void tipc_bearer_remove_dest(u32 bearer_id, u32 dest)
P
Per Liden 已提交
233
{
234 235 236 237 238 239 240 241 242 243
	struct tipc_bearer *b_ptr;

	rcu_read_lock();
	b_ptr = rcu_dereference_rtnl(bearer_list[bearer_id]);
	if (b_ptr) {
		tipc_nmap_remove(&b_ptr->nodes, dest);
		tipc_bcbearer_sort();
		tipc_disc_remove_dest(b_ptr->link_req);
	}
	rcu_read_unlock();
P
Per Liden 已提交
244 245 246 247
}

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

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

288
	write_lock_bh(&tipc_net_lock);
P
Per Liden 已提交
289

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

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

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

332 333 334 335 336
	b_ptr = kzalloc(sizeof(*b_ptr), GFP_ATOMIC);
	if (!b_ptr) {
		res = -ENOMEM;
		goto exit;
	}
337
	strcpy(b_ptr->name, name);
338
	b_ptr->media = m_ptr;
339
	res = m_ptr->enable_media(b_ptr);
P
Per Liden 已提交
340
	if (res) {
341 342
		pr_warn("Bearer <%s> rejected, enable failure (%d)\n",
			name, -res);
343
		goto exit;
P
Per Liden 已提交
344 345 346
	}

	b_ptr->identity = bearer_id;
347 348
	b_ptr->tolerance = m_ptr->tolerance;
	b_ptr->window = m_ptr->window;
349
	b_ptr->domain = disc_domain;
P
Per Liden 已提交
350 351
	b_ptr->net_plane = bearer_id + 'A';
	b_ptr->priority = priority;
352

353
	res = tipc_disc_create(b_ptr, &b_ptr->bcast_addr);
354
	if (res) {
355
		bearer_disable(b_ptr, false);
356 357
		pr_warn("Bearer <%s> rejected, discovery object creation failed\n",
			name);
358 359
		goto exit;
	}
360

Y
Ying Xue 已提交
361
	rcu_assign_pointer(bearer_list[bearer_id], b_ptr);
362

363 364 365
	pr_info("Enabled bearer <%s>, discovery domain %s, priority %u\n",
		name,
		tipc_addr_string_fill(addr_string, disc_domain), priority);
366
exit:
367
	write_unlock_bh(&tipc_net_lock);
P
Per Liden 已提交
368 369 370 371
	return res;
}

/**
372
 * tipc_reset_bearer - Reset all links established over this bearer
P
Per Liden 已提交
373
 */
374
static int tipc_reset_bearer(struct tipc_bearer *b_ptr)
P
Per Liden 已提交
375
{
376
	read_lock_bh(&tipc_net_lock);
377
	pr_info("Resetting bearer <%s>\n", b_ptr->name);
378
	tipc_disc_delete(b_ptr->link_req);
379
	tipc_link_reset_list(b_ptr->identity);
380
	tipc_disc_create(b_ptr, &b_ptr->bcast_addr);
381
	read_unlock_bh(&tipc_net_lock);
382
	return 0;
P
Per Liden 已提交
383 384 385
}

/**
386
 * bearer_disable
387
 *
388
 * Note: This routine assumes caller holds tipc_net_lock.
P
Per Liden 已提交
389
 */
390
static void bearer_disable(struct tipc_bearer *b_ptr, bool shutting_down)
P
Per Liden 已提交
391
{
392 393
	u32 i;

394
	pr_info("Disabling bearer <%s>\n", b_ptr->name);
395
	b_ptr->media->disable_media(b_ptr);
396

397 398 399
	tipc_link_delete_list(b_ptr->identity, shutting_down);
	if (b_ptr->link_req)
		tipc_disc_delete(b_ptr->link_req);
400 401

	for (i = 0; i < MAX_BEARERS; i++) {
Y
Ying Xue 已提交
402 403
		if (b_ptr == rtnl_dereference(bearer_list[i])) {
			RCU_INIT_POINTER(bearer_list[i], NULL);
404 405 406
			break;
		}
	}
Y
Ying Xue 已提交
407
	kfree_rcu(b_ptr, rcu);
P
Per Liden 已提交
408 409 410 411
}

int tipc_disable_bearer(const char *name)
{
412
	struct tipc_bearer *b_ptr;
P
Per Liden 已提交
413 414
	int res;

415
	write_lock_bh(&tipc_net_lock);
416
	b_ptr = tipc_bearer_find(name);
417
	if (b_ptr == NULL) {
418
		pr_warn("Attempt to disable unknown bearer <%s>\n", name);
419
		res = -EINVAL;
420
	} else {
421
		bearer_disable(b_ptr, false);
422 423
		res = 0;
	}
424
	write_unlock_bh(&tipc_net_lock);
P
Per Liden 已提交
425 426 427
	return res;
}

428 429 430 431 432 433 434 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

/* tipc_l2_media_addr_set - initialize Ethernet media address structure
 *
 * Media-dependent "value" field stores MAC address in first 6 bytes
 * and zeroes out the remaining bytes.
 */
void tipc_l2_media_addr_set(const struct tipc_bearer *b,
			    struct tipc_media_addr *a, char *mac)
{
	int len = b->media->hwaddr_len;

	if (unlikely(sizeof(a->value) < len)) {
		WARN_ONCE(1, "Media length invalid\n");
		return;
	}

	memcpy(a->value, mac, len);
	memset(a->value + len, 0, sizeof(a->value) - len);
	a->media_id = b->media->type_id;
	a->broadcast = !memcmp(mac, b->bcast_addr.value, len);
}

int tipc_enable_l2_media(struct tipc_bearer *b)
{
	struct net_device *dev;
	char *driver_name = strchr((const char *)b->name, ':') + 1;

	/* Find device with specified name */
	dev = dev_get_by_name(&init_net, driver_name);
	if (!dev)
		return -ENODEV;

	/* Associate TIPC bearer with Ethernet bearer */
461
	rcu_assign_pointer(b->media_ptr, dev);
462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479
	memset(b->bcast_addr.value, 0, sizeof(b->bcast_addr.value));
	memcpy(b->bcast_addr.value, dev->broadcast, b->media->hwaddr_len);
	b->bcast_addr.media_id = b->media->type_id;
	b->bcast_addr.broadcast = 1;
	b->mtu = dev->mtu;
	tipc_l2_media_addr_set(b, &b->addr, (char *)dev->dev_addr);
	rcu_assign_pointer(dev->tipc_ptr, b);
	return 0;
}

/* tipc_disable_l2_media - detach TIPC bearer from an Ethernet interface
 *
 * Mark Ethernet bearer as inactive so that incoming buffers are thrown away,
 * then get worker thread to complete bearer cleanup.  (Can't do cleanup
 * here because cleanup code needs to sleep and caller holds spinlocks.)
 */
void tipc_disable_l2_media(struct tipc_bearer *b)
{
480 481 482 483
	struct net_device *dev;

	dev = (struct net_device *)rtnl_dereference(b->media_ptr);
	RCU_INIT_POINTER(b->media_ptr, NULL);
484 485 486 487 488 489 490
	RCU_INIT_POINTER(dev->tipc_ptr, NULL);
	dev_put(dev);
}

/**
 * tipc_l2_send_msg - send a TIPC packet out over an Ethernet interface
 * @buf: the packet to be sent
S
stephen hemminger 已提交
491
 * @b_ptr: the bearer through which the packet is to be sent
492 493 494 495 496 497
 * @dest: peer destination address
 */
int tipc_l2_send_msg(struct sk_buff *buf, struct tipc_bearer *b,
		     struct tipc_media_addr *dest)
{
	struct sk_buff *clone;
498
	struct net_device *dev;
499
	int delta;
500 501 502 503

	dev = (struct net_device *)rcu_dereference_rtnl(b->media_ptr);
	if (!dev)
		return 0;
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

	clone = skb_clone(buf, GFP_ATOMIC);
	if (!clone)
		return 0;

	delta = dev->hard_header_len - skb_headroom(buf);
	if ((delta > 0) &&
	    pskb_expand_head(clone, SKB_DATA_ALIGN(delta), 0, GFP_ATOMIC)) {
		kfree_skb(clone);
		return 0;
	}

	skb_reset_network_header(clone);
	clone->dev = dev;
	clone->protocol = htons(ETH_P_TIPC);
	dev_hard_header(clone, dev, ETH_P_TIPC, dest->value,
			dev->dev_addr, clone->len);
	dev_queue_xmit(clone);
	return 0;
}

/* tipc_bearer_send- sends buffer to destination over bearer
 *
 * IMPORTANT:
 * The media send routine must not alter the buffer being passed in
 * as it may be needed for later retransmission!
 */
531
void tipc_bearer_send(u32 bearer_id, struct sk_buff *buf,
532 533
		      struct tipc_media_addr *dest)
{
534 535 536 537 538 539 540
	struct tipc_bearer *b_ptr;

	rcu_read_lock();
	b_ptr = rcu_dereference_rtnl(bearer_list[bearer_id]);
	if (likely(b_ptr))
		b_ptr->media->send_msg(buf, b_ptr, dest);
	rcu_read_unlock();
541 542
}

543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564
/**
 * 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();
565
	b_ptr = rcu_dereference_rtnl(dev->tipc_ptr);
566 567 568
	if (likely(b_ptr)) {
		if (likely(buf->pkt_type <= PACKET_BROADCAST)) {
			buf->next = NULL;
569
			tipc_rcv(buf, b_ptr);
570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593
			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 已提交
594

595 596 597
	if (!net_eq(dev_net(dev), &init_net))
		return NOTIFY_DONE;

598 599
	b_ptr = rtnl_dereference(dev->tipc_ptr);
	if (!b_ptr)
600 601 602 603 604 605 606 607 608 609
		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:
610 611
		tipc_reset_bearer(b_ptr);
		break;
612
	case NETDEV_CHANGEADDR:
613 614
		tipc_l2_media_addr_set(b_ptr, &b_ptr->addr,
				       (char *)dev->dev_addr);
615 616 617 618 619 620 621 622 623 624 625
		tipc_reset_bearer(b_ptr);
		break;
	case NETDEV_UNREGISTER:
	case NETDEV_CHANGENAME:
		tipc_disable_bearer(b_ptr->name);
		break;
	}
	return NOTIFY_OK;
}

static struct packet_type tipc_packet_type __read_mostly = {
626
	.type = htons(ETH_P_TIPC),
627 628 629 630 631 632 633 634 635 636
	.func = tipc_l2_rcv_msg,
};

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

int tipc_bearer_setup(void)
{
637 638 639 640 641
	int err;

	err = register_netdevice_notifier(&notifier);
	if (err)
		return err;
642
	dev_add_pack(&tipc_packet_type);
643
	return 0;
644 645 646 647 648 649 650
}

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

652
void tipc_bearer_stop(void)
P
Per Liden 已提交
653
{
654
	struct tipc_bearer *b_ptr;
P
Per Liden 已提交
655 656 657
	u32 i;

	for (i = 0; i < MAX_BEARERS; i++) {
Y
Ying Xue 已提交
658
		b_ptr = rtnl_dereference(bearer_list[i]);
659
		if (b_ptr) {
660 661 662
			bearer_disable(b_ptr, true);
			bearer_list[i] = NULL;
		}
P
Per Liden 已提交
663 664
	}
}