bearer.c 16.6 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
223
224
225
226
227
	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();
Per Liden's avatar
Per Liden committed
228
229
}

230
void tipc_bearer_remove_dest(u32 bearer_id, u32 dest)
Per Liden's avatar
Per Liden committed
231
{
232
233
234
235
236
237
238
239
240
241
	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();
Per Liden's avatar
Per Liden committed
242
243
244
245
}

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

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

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

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

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

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

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

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

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

356
	rcu_assign_pointer(bearer_list[bearer_id], b_ptr);
357

358
359
360
	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
361
362
363
364
	return res;
}

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

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

385
	pr_info("Disabling bearer <%s>\n", b_ptr->name);
386
	b_ptr->media->disable_media(b_ptr);
387

388
389
390
	tipc_link_delete_list(b_ptr->identity, shutting_down);
	if (b_ptr->link_req)
		tipc_disc_delete(b_ptr->link_req);
391
392

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

int tipc_disable_bearer(const char *name)
{
403
	struct tipc_bearer *b_ptr;
Per Liden's avatar
Per Liden committed
404
405
	int res;

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

417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449

/* 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 */
450
	rcu_assign_pointer(b->media_ptr, dev);
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
	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)
{
469
470
471
472
	struct net_device *dev;

	dev = (struct net_device *)rtnl_dereference(b->media_ptr);
	RCU_INIT_POINTER(b->media_ptr, NULL);
473
474
475
476
477
478
479
	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
stephen hemminger's avatar
stephen hemminger committed
480
 * @b_ptr: the bearer through which the packet is to be sent
481
482
483
484
485
486
 * @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;
487
	struct net_device *dev;
488
	int delta;
489
490
491
492

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

	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!
 */
520
void tipc_bearer_send(u32 bearer_id, struct sk_buff *buf,
521
522
		      struct tipc_media_addr *dest)
{
523
524
525
526
527
528
529
	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();
530
531
}

532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
/**
 * 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();
554
	b_ptr = rcu_dereference_rtnl(dev->tipc_ptr);
555
556
557
	if (likely(b_ptr)) {
		if (likely(buf->pkt_type <= PACKET_BROADCAST)) {
			buf->next = NULL;
558
			tipc_rcv(buf, b_ptr);
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
			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
583

584
585
586
	if (!net_eq(dev_net(dev), &init_net))
		return NOTIFY_DONE;

587
588
	b_ptr = rtnl_dereference(dev->tipc_ptr);
	if (!b_ptr)
589
590
591
592
593
594
595
596
597
598
		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:
599
600
		tipc_reset_bearer(b_ptr);
		break;
601
	case NETDEV_CHANGEADDR:
602
603
		tipc_l2_media_addr_set(b_ptr, &b_ptr->addr,
				       (char *)dev->dev_addr);
604
605
606
607
608
609
610
611
612
613
614
		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 = {
615
	.type = htons(ETH_P_TIPC),
616
617
618
619
620
621
622
623
624
625
	.func = tipc_l2_rcv_msg,
};

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

int tipc_bearer_setup(void)
{
626
627
628
629
630
	int err;

	err = register_netdevice_notifier(&notifier);
	if (err)
		return err;
631
	dev_add_pack(&tipc_packet_type);
632
	return 0;
633
634
635
636
637
638
639
}

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

641
void tipc_bearer_stop(void)
Per Liden's avatar
Per Liden committed
642
{
643
	struct tipc_bearer *b_ptr;
Per Liden's avatar
Per Liden committed
644
645
646
	u32 i;

	for (i = 0; i < MAX_BEARERS; i++) {
647
		b_ptr = rtnl_dereference(bearer_list[i]);
648
		if (b_ptr) {
649
650
651
			bearer_disable(b_ptr, true);
			bearer_list[i] = NULL;
		}
Per Liden's avatar
Per Liden committed
652
653
	}
}