bearer.c 15.9 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, 2013, Ericsson AB
5
 * Copyright (c) 2004-2006, 2010-2013, 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
 * POSSIBILITY OF SUCH DAMAGE.
 */

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

42
#define MAX_ADDR_STR 60
Per Liden's avatar
Per Liden committed
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
};
Per Liden's avatar
Per Liden committed
51

52
struct tipc_bearer __rcu *bearer_list[MAX_BEARERS + 1];
Per Liden's avatar
Per Liden committed
53

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

Per Liden's avatar
Per Liden committed
56
/**
57
 * tipc_media_find - locates specified media object by name
Per Liden's avatar
Per Liden committed
58
 */
59
struct tipc_media *tipc_media_find(const char *name)
Per Liden's avatar
Per Liden committed
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;
Per Liden's avatar
Per Liden committed
66
	}
67
	return media_info_array[i];
Per Liden's avatar
Per Liden committed
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];
Per Liden's avatar
Per Liden committed
82
83
84
}

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

93
	m_ptr = media_find_id(a->media_id);
Per Liden's avatar
Per Liden committed
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;
Per Liden's avatar
Per Liden committed
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]);
Per Liden's avatar
Per Liden committed
104
105
106
107
	}
}

/**
108
 * tipc_media_get_names - record names of registered media in buffer
Per Liden's avatar
Per Liden committed
109
 */
110
struct sk_buff *tipc_media_get_names(void)
Per Liden's avatar
Per Liden committed
111
112
113
114
{
	struct sk_buff *buf;
	int i;

115
	buf = tipc_cfg_reply_alloc(MAX_MEDIA * TLV_SPACE(TIPC_MAX_MEDIA_NAME));
Per Liden's avatar
Per Liden committed
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);
Per Liden's avatar
Per Liden committed
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
 *
Per Liden's avatar
Per Liden committed
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)
Per Liden's avatar
Per Liden committed
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)
Per Liden's avatar
Per Liden committed
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))
Per Liden's avatar
Per Liden committed
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
Per Liden's avatar
Per Liden committed
174
 */
175
struct tipc_bearer *tipc_bearer_find(const char *name)
Per Liden's avatar
Per Liden committed
176
{
177
	struct tipc_bearer *b_ptr;
Per Liden's avatar
Per Liden committed
178
179
	u32 i;

180
	for (i = 0; i < MAX_BEARERS; i++) {
181
		b_ptr = rtnl_dereference(bearer_list[i]);
182
		if (b_ptr && (!strcmp(b_ptr->name, name)))
Per Liden's avatar
Per Liden committed
183
184
			return b_ptr;
	}
185
	return NULL;
Per Liden's avatar
Per Liden committed
186
187
188
}

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

197
	buf = tipc_cfg_reply_alloc(MAX_BEARERS * TLV_SPACE(TIPC_MAX_BEARER_NAME));
Per Liden's avatar
Per Liden committed
198
199
200
	if (!buf)
		return NULL;

201
	for (i = 0; media_info_array[i] != NULL; i++) {
Per Liden's avatar
Per Liden committed
202
		for (j = 0; j < MAX_BEARERS; j++) {
203
			b = rtnl_dereference(bearer_list[j]);
204
205
			if (!b)
				continue;
206
			if (b->media == media_info_array[i]) {
207
				tipc_cfg_append_tlv(buf, TIPC_TLV_BEARER_NAME,
208
209
						    b->name,
						    strlen(b->name) + 1);
Per Liden's avatar
Per Liden committed
210
211
212
213
214
215
			}
		}
	}
	return buf;
}

216
void tipc_bearer_add_dest(u32 bearer_id, u32 dest)
Per Liden's avatar
Per Liden committed
217
{
218
219
220
221
222
	struct tipc_bearer *b_ptr;

	rcu_read_lock();
	b_ptr = rcu_dereference_rtnl(bearer_list[bearer_id]);
	if (b_ptr) {
223
		tipc_bcbearer_sort(&b_ptr->nodes, dest, true);
224
225
226
		tipc_disc_add_dest(b_ptr->link_req);
	}
	rcu_read_unlock();
Per Liden's avatar
Per Liden committed
227
228
}

229
void tipc_bearer_remove_dest(u32 bearer_id, u32 dest)
Per Liden's avatar
Per Liden committed
230
{
231
232
233
234
235
	struct tipc_bearer *b_ptr;

	rcu_read_lock();
	b_ptr = rcu_dereference_rtnl(bearer_list[bearer_id]);
	if (b_ptr) {
236
		tipc_bcbearer_sort(&b_ptr->nodes, dest, false);
237
238
239
		tipc_disc_remove_dest(b_ptr->link_req);
	}
	rcu_read_unlock();
Per Liden's avatar
Per Liden committed
240
241
242
243
}

/**
 * tipc_enable_bearer - enable bearer with the given name
244
 */
245
int tipc_enable_bearer(const char *name, u32 disc_domain, u32 priority)
Per Liden's avatar
Per Liden committed
246
{
247
	struct tipc_bearer *b_ptr;
248
	struct tipc_media *m_ptr;
249
	struct tipc_bearer_names b_names;
Per Liden's avatar
Per Liden committed
250
251
252
253
254
255
	char addr_string[16];
	u32 bearer_id;
	u32 with_this_prio;
	u32 i;
	int res = -EINVAL;

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

284
	m_ptr = tipc_media_find(b_names.media_name);
Per Liden's avatar
Per Liden committed
285
	if (!m_ptr) {
286
287
		pr_warn("Bearer <%s> rejected, media <%s> not registered\n",
			name, b_names.media_name);
Ying Xue's avatar
Ying Xue committed
288
		return -EINVAL;
Per Liden's avatar
Per Liden committed
289
	}
290
291

	if (priority == TIPC_MEDIA_LINK_PRI)
Per Liden's avatar
Per Liden committed
292
293
294
295
296
297
		priority = m_ptr->priority;

restart:
	bearer_id = MAX_BEARERS;
	with_this_prio = 1;
	for (i = MAX_BEARERS; i-- != 0; ) {
298
		b_ptr = rtnl_dereference(bearer_list[i]);
299
		if (!b_ptr) {
Per Liden's avatar
Per Liden committed
300
301
302
			bearer_id = i;
			continue;
		}
303
		if (!strcmp(name, b_ptr->name)) {
304
305
			pr_warn("Bearer <%s> rejected, already enabled\n",
				name);
Ying Xue's avatar
Ying Xue committed
306
			return -EINVAL;
Per Liden's avatar
Per Liden committed
307
		}
308
		if ((b_ptr->priority == priority) &&
Per Liden's avatar
Per Liden committed
309
310
		    (++with_this_prio > 2)) {
			if (priority-- == 0) {
311
312
				pr_warn("Bearer <%s> rejected, duplicate priority\n",
					name);
Ying Xue's avatar
Ying Xue committed
313
				return -EINVAL;
Per Liden's avatar
Per Liden committed
314
			}
315
316
			pr_warn("Bearer <%s> priority adjustment required %u->%u\n",
				name, priority + 1, priority);
Per Liden's avatar
Per Liden committed
317
318
319
320
			goto restart;
		}
	}
	if (bearer_id >= MAX_BEARERS) {
321
322
		pr_warn("Bearer <%s> rejected, bearer limit reached (%u)\n",
			name, MAX_BEARERS);
Ying Xue's avatar
Ying Xue committed
323
		return -EINVAL;
Per Liden's avatar
Per Liden committed
324
325
	}

326
	b_ptr = kzalloc(sizeof(*b_ptr), GFP_ATOMIC);
Ying Xue's avatar
Ying Xue committed
327
328
329
	if (!b_ptr)
		return -ENOMEM;

330
	strcpy(b_ptr->name, name);
331
	b_ptr->media = m_ptr;
332
	res = m_ptr->enable_media(b_ptr);
Per Liden's avatar
Per Liden committed
333
	if (res) {
334
335
		pr_warn("Bearer <%s> rejected, enable failure (%d)\n",
			name, -res);
Ying Xue's avatar
Ying Xue committed
336
		return -EINVAL;
Per Liden's avatar
Per Liden committed
337
338
339
	}

	b_ptr->identity = bearer_id;
340
341
	b_ptr->tolerance = m_ptr->tolerance;
	b_ptr->window = m_ptr->window;
342
	b_ptr->domain = disc_domain;
Per Liden's avatar
Per Liden committed
343
344
	b_ptr->net_plane = bearer_id + 'A';
	b_ptr->priority = priority;
345

346
	res = tipc_disc_create(b_ptr, &b_ptr->bcast_addr);
347
	if (res) {
348
		bearer_disable(b_ptr, false);
349
350
		pr_warn("Bearer <%s> rejected, discovery object creation failed\n",
			name);
Ying Xue's avatar
Ying Xue committed
351
		return -EINVAL;
352
	}
353

354
	rcu_assign_pointer(bearer_list[bearer_id], b_ptr);
355

356
357
358
	pr_info("Enabled bearer <%s>, discovery domain %s, priority %u\n",
		name,
		tipc_addr_string_fill(addr_string, disc_domain), priority);
Per Liden's avatar
Per Liden committed
359
360
361
362
	return res;
}

/**
363
 * tipc_reset_bearer - Reset all links established over this bearer
Per Liden's avatar
Per Liden committed
364
 */
365
static int tipc_reset_bearer(struct tipc_bearer *b_ptr)
Per Liden's avatar
Per Liden committed
366
{
367
	pr_info("Resetting bearer <%s>\n", b_ptr->name);
368
	tipc_link_reset_list(b_ptr->identity);
369
	tipc_disc_reset(b_ptr);
370
	return 0;
Per Liden's avatar
Per Liden committed
371
372
373
}

/**
374
 * bearer_disable
375
 *
Ying Xue's avatar
Ying Xue committed
376
 * Note: This routine assumes caller holds RTNL lock.
Per Liden's avatar
Per Liden committed
377
 */
378
static void bearer_disable(struct tipc_bearer *b_ptr, bool shutting_down)
Per Liden's avatar
Per Liden committed
379
{
380
381
	u32 i;

382
	pr_info("Disabling bearer <%s>\n", b_ptr->name);
383
	b_ptr->media->disable_media(b_ptr);
384

385
386
387
	tipc_link_delete_list(b_ptr->identity, shutting_down);
	if (b_ptr->link_req)
		tipc_disc_delete(b_ptr->link_req);
388
389

	for (i = 0; i < MAX_BEARERS; i++) {
390
391
		if (b_ptr == rtnl_dereference(bearer_list[i])) {
			RCU_INIT_POINTER(bearer_list[i], NULL);
392
393
394
			break;
		}
	}
395
	kfree_rcu(b_ptr, rcu);
Per Liden's avatar
Per Liden committed
396
397
398
399
}

int tipc_disable_bearer(const char *name)
{
400
	struct tipc_bearer *b_ptr;
Per Liden's avatar
Per Liden committed
401
402
	int res;

403
	b_ptr = tipc_bearer_find(name);
404
	if (b_ptr == NULL) {
405
		pr_warn("Attempt to disable unknown bearer <%s>\n", name);
406
		res = -EINVAL;
407
	} else {
408
		bearer_disable(b_ptr, false);
409
410
		res = 0;
	}
Per Liden's avatar
Per Liden committed
411
412
413
	return res;
}

414
415
416
417
418
419
420
421
422
423
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;

424
	/* Associate TIPC bearer with L2 bearer */
425
	rcu_assign_pointer(b->media_ptr, dev);
426
	memset(&b->bcast_addr, 0, sizeof(b->bcast_addr));
427
428
429
430
	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;
431
	b->media->raw2addr(b, &b->addr, (char *)dev->dev_addr);
432
433
434
435
	rcu_assign_pointer(dev->tipc_ptr, b);
	return 0;
}

436
/* tipc_disable_l2_media - detach TIPC bearer from an L2 interface
437
 *
438
 * Mark L2 bearer as inactive so that incoming buffers are thrown away,
439
440
441
442
443
 * 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)
{
444
445
446
447
	struct net_device *dev;

	dev = (struct net_device *)rtnl_dereference(b->media_ptr);
	RCU_INIT_POINTER(b->media_ptr, NULL);
448
	RCU_INIT_POINTER(dev->tipc_ptr, NULL);
449
	synchronize_net();
450
451
452
453
	dev_put(dev);
}

/**
454
 * tipc_l2_send_msg - send a TIPC packet out over an L2 interface
455
 * @buf: the packet to be sent
stephen hemminger's avatar
stephen hemminger committed
456
 * @b_ptr: the bearer through which the packet is to be sent
457
458
459
460
461
462
 * @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;
463
	struct net_device *dev;
464
	int delta;
465
466
467
468

	dev = (struct net_device *)rcu_dereference_rtnl(b->media_ptr);
	if (!dev)
		return 0;
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495

	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!
 */
496
void tipc_bearer_send(u32 bearer_id, struct sk_buff *buf,
497
498
		      struct tipc_media_addr *dest)
{
499
500
501
502
503
504
505
	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();
506
507
}

508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
/**
 * 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();
530
	b_ptr = rcu_dereference_rtnl(dev->tipc_ptr);
531
532
533
	if (likely(b_ptr)) {
		if (likely(buf->pkt_type <= PACKET_BROADCAST)) {
			buf->next = NULL;
534
			tipc_rcv(buf, b_ptr);
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
			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);
Per Liden's avatar
Per Liden committed
559

560
561
562
	if (!net_eq(dev_net(dev), &init_net))
		return NOTIFY_DONE;

563
564
	b_ptr = rtnl_dereference(dev->tipc_ptr);
	if (!b_ptr)
565
566
567
568
569
570
571
572
573
574
		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:
575
576
		tipc_reset_bearer(b_ptr);
		break;
577
	case NETDEV_CHANGEADDR:
578
		b_ptr->media->raw2addr(b_ptr, &b_ptr->addr,
579
				       (char *)dev->dev_addr);
580
581
582
583
		tipc_reset_bearer(b_ptr);
		break;
	case NETDEV_UNREGISTER:
	case NETDEV_CHANGENAME:
584
		bearer_disable(b_ptr, false);
585
586
587
588
589
590
		break;
	}
	return NOTIFY_OK;
}

static struct packet_type tipc_packet_type __read_mostly = {
591
	.type = htons(ETH_P_TIPC),
592
593
594
595
596
597
598
599
600
601
	.func = tipc_l2_rcv_msg,
};

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

int tipc_bearer_setup(void)
{
602
603
604
605
606
	int err;

	err = register_netdevice_notifier(&notifier);
	if (err)
		return err;
607
	dev_add_pack(&tipc_packet_type);
608
	return 0;
609
610
611
612
613
614
615
}

void tipc_bearer_cleanup(void)
{
	unregister_netdevice_notifier(&notifier);
	dev_remove_pack(&tipc_packet_type);
}
Per Liden's avatar
Per Liden committed
616

617
void tipc_bearer_stop(void)
Per Liden's avatar
Per Liden committed
618
{
619
	struct tipc_bearer *b_ptr;
Per Liden's avatar
Per Liden committed
620
621
622
	u32 i;

	for (i = 0; i < MAX_BEARERS; i++) {
623
		b_ptr = rtnl_dereference(bearer_list[i]);
624
		if (b_ptr) {
625
626
627
			bearer_disable(b_ptr, true);
			bearer_list[i] = NULL;
		}
Per Liden's avatar
Per Liden committed
628
629
	}
}