aboutsummaryrefslogtreecommitdiffstats
path: root/net/tipc/bearer.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/tipc/bearer.c')
-rw-r--r--net/tipc/bearer.c342
1 files changed, 235 insertions, 107 deletions
diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c
index 3f9707a16d06..a38c89969c68 100644
--- a/net/tipc/bearer.c
+++ b/net/tipc/bearer.c
@@ -1,8 +1,8 @@
1/* 1/*
2 * net/tipc/bearer.c: TIPC bearer code 2 * net/tipc/bearer.c: TIPC bearer code
3 * 3 *
4 * Copyright (c) 1996-2006, Ericsson AB 4 * Copyright (c) 1996-2006, 2013, Ericsson AB
5 * Copyright (c) 2004-2006, 2010-2011, Wind River Systems 5 * Copyright (c) 2004-2006, 2010-2013, Wind River Systems
6 * All rights reserved. 6 * All rights reserved.
7 * 7 *
8 * Redistribution and use in source and binary forms, with or without 8 * Redistribution and use in source and binary forms, with or without
@@ -41,8 +41,13 @@
41 41
42#define MAX_ADDR_STR 60 42#define MAX_ADDR_STR 60
43 43
44static struct tipc_media *media_list[MAX_MEDIA]; 44static struct tipc_media * const media_info_array[] = {
45static u32 media_count; 45 &eth_media_info,
46#ifdef CONFIG_TIPC_MEDIA_IB
47 &ib_media_info,
48#endif
49 NULL
50};
46 51
47struct tipc_bearer tipc_bearers[MAX_BEARERS]; 52struct tipc_bearer tipc_bearers[MAX_BEARERS];
48 53
@@ -55,11 +60,11 @@ struct tipc_media *tipc_media_find(const char *name)
55{ 60{
56 u32 i; 61 u32 i;
57 62
58 for (i = 0; i < media_count; i++) { 63 for (i = 0; media_info_array[i] != NULL; i++) {
59 if (!strcmp(media_list[i]->name, name)) 64 if (!strcmp(media_info_array[i]->name, name))
60 return media_list[i]; 65 break;
61 } 66 }
62 return NULL; 67 return media_info_array[i];
63} 68}
64 69
65/** 70/**
@@ -69,44 +74,11 @@ static struct tipc_media *media_find_id(u8 type)
69{ 74{
70 u32 i; 75 u32 i;
71 76
72 for (i = 0; i < media_count; i++) { 77 for (i = 0; media_info_array[i] != NULL; i++) {
73 if (media_list[i]->type_id == type) 78 if (media_info_array[i]->type_id == type)
74 return media_list[i]; 79 break;
75 } 80 }
76 return NULL; 81 return media_info_array[i];
77}
78
79/**
80 * tipc_register_media - register a media type
81 *
82 * Bearers for this media type must be activated separately at a later stage.
83 */
84int tipc_register_media(struct tipc_media *m_ptr)
85{
86 int res = -EINVAL;
87
88 write_lock_bh(&tipc_net_lock);
89
90 if ((strlen(m_ptr->name) + 1) > TIPC_MAX_MEDIA_NAME)
91 goto exit;
92 if (m_ptr->priority > TIPC_MAX_LINK_PRI)
93 goto exit;
94 if ((m_ptr->tolerance < TIPC_MIN_LINK_TOL) ||
95 (m_ptr->tolerance > TIPC_MAX_LINK_TOL))
96 goto exit;
97 if (media_count >= MAX_MEDIA)
98 goto exit;
99 if (tipc_media_find(m_ptr->name) || media_find_id(m_ptr->type_id))
100 goto exit;
101
102 media_list[media_count] = m_ptr;
103 media_count++;
104 res = 0;
105exit:
106 write_unlock_bh(&tipc_net_lock);
107 if (res)
108 pr_warn("Media <%s> registration error\n", m_ptr->name);
109 return res;
110} 82}
111 83
112/** 84/**
@@ -144,13 +116,11 @@ struct sk_buff *tipc_media_get_names(void)
144 if (!buf) 116 if (!buf)
145 return NULL; 117 return NULL;
146 118
147 read_lock_bh(&tipc_net_lock); 119 for (i = 0; media_info_array[i] != NULL; i++) {
148 for (i = 0; i < media_count; i++) {
149 tipc_cfg_append_tlv(buf, TIPC_TLV_MEDIA_NAME, 120 tipc_cfg_append_tlv(buf, TIPC_TLV_MEDIA_NAME,
150 media_list[i]->name, 121 media_info_array[i]->name,
151 strlen(media_list[i]->name) + 1); 122 strlen(media_info_array[i]->name) + 1);
152 } 123 }
153 read_unlock_bh(&tipc_net_lock);
154 return buf; 124 return buf;
155} 125}
156 126
@@ -215,31 +185,12 @@ struct tipc_bearer *tipc_bearer_find(const char *name)
215} 185}
216 186
217/** 187/**
218 * tipc_bearer_find_interface - locates bearer object with matching interface name
219 */
220struct tipc_bearer *tipc_bearer_find_interface(const char *if_name)
221{
222 struct tipc_bearer *b_ptr;
223 char *b_if_name;
224 u32 i;
225
226 for (i = 0, b_ptr = tipc_bearers; i < MAX_BEARERS; i++, b_ptr++) {
227 if (!b_ptr->active)
228 continue;
229 b_if_name = strchr(b_ptr->name, ':') + 1;
230 if (!strcmp(b_if_name, if_name))
231 return b_ptr;
232 }
233 return NULL;
234}
235
236/**
237 * tipc_bearer_get_names - record names of bearers in buffer 188 * tipc_bearer_get_names - record names of bearers in buffer
238 */ 189 */
239struct sk_buff *tipc_bearer_get_names(void) 190struct sk_buff *tipc_bearer_get_names(void)
240{ 191{
241 struct sk_buff *buf; 192 struct sk_buff *buf;
242 struct tipc_bearer *b_ptr; 193 struct tipc_bearer *b;
243 int i, j; 194 int i, j;
244 195
245 buf = tipc_cfg_reply_alloc(MAX_BEARERS * TLV_SPACE(TIPC_MAX_BEARER_NAME)); 196 buf = tipc_cfg_reply_alloc(MAX_BEARERS * TLV_SPACE(TIPC_MAX_BEARER_NAME));
@@ -247,13 +198,13 @@ struct sk_buff *tipc_bearer_get_names(void)
247 return NULL; 198 return NULL;
248 199
249 read_lock_bh(&tipc_net_lock); 200 read_lock_bh(&tipc_net_lock);
250 for (i = 0; i < media_count; i++) { 201 for (i = 0; media_info_array[i] != NULL; i++) {
251 for (j = 0; j < MAX_BEARERS; j++) { 202 for (j = 0; j < MAX_BEARERS; j++) {
252 b_ptr = &tipc_bearers[j]; 203 b = &tipc_bearers[j];
253 if (b_ptr->active && (b_ptr->media == media_list[i])) { 204 if (b->active && (b->media == media_info_array[i])) {
254 tipc_cfg_append_tlv(buf, TIPC_TLV_BEARER_NAME, 205 tipc_cfg_append_tlv(buf, TIPC_TLV_BEARER_NAME,
255 b_ptr->name, 206 b->name,
256 strlen(b_ptr->name) + 1); 207 strlen(b->name) + 1);
257 } 208 }
258 } 209 }
259 } 210 }
@@ -275,31 +226,6 @@ void tipc_bearer_remove_dest(struct tipc_bearer *b_ptr, u32 dest)
275 tipc_disc_remove_dest(b_ptr->link_req); 226 tipc_disc_remove_dest(b_ptr->link_req);
276} 227}
277 228
278/*
279 * Interrupt enabling new requests after bearer blocking:
280 * See bearer_send().
281 */
282void tipc_continue(struct tipc_bearer *b)
283{
284 spin_lock_bh(&b->lock);
285 b->blocked = 0;
286 spin_unlock_bh(&b->lock);
287}
288
289/*
290 * tipc_bearer_blocked - determines if bearer is currently blocked
291 */
292int tipc_bearer_blocked(struct tipc_bearer *b)
293{
294 int res;
295
296 spin_lock_bh(&b->lock);
297 res = b->blocked;
298 spin_unlock_bh(&b->lock);
299
300 return res;
301}
302
303/** 229/**
304 * tipc_enable_bearer - enable bearer with the given name 230 * tipc_enable_bearer - enable bearer with the given name
305 */ 231 */
@@ -387,6 +313,7 @@ restart:
387 313
388 b_ptr = &tipc_bearers[bearer_id]; 314 b_ptr = &tipc_bearers[bearer_id];
389 strcpy(b_ptr->name, name); 315 strcpy(b_ptr->name, name);
316 b_ptr->media = m_ptr;
390 res = m_ptr->enable_media(b_ptr); 317 res = m_ptr->enable_media(b_ptr);
391 if (res) { 318 if (res) {
392 pr_warn("Bearer <%s> rejected, enable failure (%d)\n", 319 pr_warn("Bearer <%s> rejected, enable failure (%d)\n",
@@ -395,7 +322,6 @@ restart:
395 } 322 }
396 323
397 b_ptr->identity = bearer_id; 324 b_ptr->identity = bearer_id;
398 b_ptr->media = m_ptr;
399 b_ptr->tolerance = m_ptr->tolerance; 325 b_ptr->tolerance = m_ptr->tolerance;
400 b_ptr->window = m_ptr->window; 326 b_ptr->window = m_ptr->window;
401 b_ptr->net_plane = bearer_id + 'A'; 327 b_ptr->net_plane = bearer_id + 'A';
@@ -420,17 +346,16 @@ exit:
420} 346}
421 347
422/** 348/**
423 * tipc_block_bearer - Block the bearer, and reset all its links 349 * tipc_reset_bearer - Reset all links established over this bearer
424 */ 350 */
425int tipc_block_bearer(struct tipc_bearer *b_ptr) 351static int tipc_reset_bearer(struct tipc_bearer *b_ptr)
426{ 352{
427 struct tipc_link *l_ptr; 353 struct tipc_link *l_ptr;
428 struct tipc_link *temp_l_ptr; 354 struct tipc_link *temp_l_ptr;
429 355
430 read_lock_bh(&tipc_net_lock); 356 read_lock_bh(&tipc_net_lock);
431 pr_info("Blocking bearer <%s>\n", b_ptr->name); 357 pr_info("Resetting bearer <%s>\n", b_ptr->name);
432 spin_lock_bh(&b_ptr->lock); 358 spin_lock_bh(&b_ptr->lock);
433 b_ptr->blocked = 1;
434 list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) { 359 list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) {
435 struct tipc_node *n_ptr = l_ptr->owner; 360 struct tipc_node *n_ptr = l_ptr->owner;
436 361
@@ -456,7 +381,6 @@ static void bearer_disable(struct tipc_bearer *b_ptr)
456 381
457 pr_info("Disabling bearer <%s>\n", b_ptr->name); 382 pr_info("Disabling bearer <%s>\n", b_ptr->name);
458 spin_lock_bh(&b_ptr->lock); 383 spin_lock_bh(&b_ptr->lock);
459 b_ptr->blocked = 1;
460 b_ptr->media->disable_media(b_ptr); 384 b_ptr->media->disable_media(b_ptr);
461 list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) { 385 list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) {
462 tipc_link_delete(l_ptr); 386 tipc_link_delete(l_ptr);
@@ -490,6 +414,211 @@ int tipc_disable_bearer(const char *name)
490} 414}
491 415
492 416
417/* tipc_l2_media_addr_set - initialize Ethernet media address structure
418 *
419 * Media-dependent "value" field stores MAC address in first 6 bytes
420 * and zeroes out the remaining bytes.
421 */
422void tipc_l2_media_addr_set(const struct tipc_bearer *b,
423 struct tipc_media_addr *a, char *mac)
424{
425 int len = b->media->hwaddr_len;
426
427 if (unlikely(sizeof(a->value) < len)) {
428 WARN_ONCE(1, "Media length invalid\n");
429 return;
430 }
431
432 memcpy(a->value, mac, len);
433 memset(a->value + len, 0, sizeof(a->value) - len);
434 a->media_id = b->media->type_id;
435 a->broadcast = !memcmp(mac, b->bcast_addr.value, len);
436}
437
438int tipc_enable_l2_media(struct tipc_bearer *b)
439{
440 struct net_device *dev;
441 char *driver_name = strchr((const char *)b->name, ':') + 1;
442
443 /* Find device with specified name */
444 dev = dev_get_by_name(&init_net, driver_name);
445 if (!dev)
446 return -ENODEV;
447
448 /* Associate TIPC bearer with Ethernet bearer */
449 b->media_ptr = dev;
450 memset(b->bcast_addr.value, 0, sizeof(b->bcast_addr.value));
451 memcpy(b->bcast_addr.value, dev->broadcast, b->media->hwaddr_len);
452 b->bcast_addr.media_id = b->media->type_id;
453 b->bcast_addr.broadcast = 1;
454 b->mtu = dev->mtu;
455 tipc_l2_media_addr_set(b, &b->addr, (char *)dev->dev_addr);
456 rcu_assign_pointer(dev->tipc_ptr, b);
457 return 0;
458}
459
460/* tipc_disable_l2_media - detach TIPC bearer from an Ethernet interface
461 *
462 * Mark Ethernet bearer as inactive so that incoming buffers are thrown away,
463 * then get worker thread to complete bearer cleanup. (Can't do cleanup
464 * here because cleanup code needs to sleep and caller holds spinlocks.)
465 */
466void tipc_disable_l2_media(struct tipc_bearer *b)
467{
468 struct net_device *dev = (struct net_device *)b->media_ptr;
469 RCU_INIT_POINTER(dev->tipc_ptr, NULL);
470 dev_put(dev);
471}
472
473/**
474 * tipc_l2_send_msg - send a TIPC packet out over an Ethernet interface
475 * @buf: the packet to be sent
476 * @b_ptr: the bearer through which the packet is to be sent
477 * @dest: peer destination address
478 */
479int tipc_l2_send_msg(struct sk_buff *buf, struct tipc_bearer *b,
480 struct tipc_media_addr *dest)
481{
482 struct sk_buff *clone;
483 int delta;
484 struct net_device *dev = (struct net_device *)b->media_ptr;
485
486 clone = skb_clone(buf, GFP_ATOMIC);
487 if (!clone)
488 return 0;
489
490 delta = dev->hard_header_len - skb_headroom(buf);
491 if ((delta > 0) &&
492 pskb_expand_head(clone, SKB_DATA_ALIGN(delta), 0, GFP_ATOMIC)) {
493 kfree_skb(clone);
494 return 0;
495 }
496
497 skb_reset_network_header(clone);
498 clone->dev = dev;
499 clone->protocol = htons(ETH_P_TIPC);
500 dev_hard_header(clone, dev, ETH_P_TIPC, dest->value,
501 dev->dev_addr, clone->len);
502 dev_queue_xmit(clone);
503 return 0;
504}
505
506/* tipc_bearer_send- sends buffer to destination over bearer
507 *
508 * IMPORTANT:
509 * The media send routine must not alter the buffer being passed in
510 * as it may be needed for later retransmission!
511 */
512void tipc_bearer_send(struct tipc_bearer *b, struct sk_buff *buf,
513 struct tipc_media_addr *dest)
514{
515 b->media->send_msg(buf, b, dest);
516}
517
518/**
519 * tipc_l2_rcv_msg - handle incoming TIPC message from an interface
520 * @buf: the received packet
521 * @dev: the net device that the packet was received on
522 * @pt: the packet_type structure which was used to register this handler
523 * @orig_dev: the original receive net device in case the device is a bond
524 *
525 * Accept only packets explicitly sent to this node, or broadcast packets;
526 * ignores packets sent using interface multicast, and traffic sent to other
527 * nodes (which can happen if interface is running in promiscuous mode).
528 */
529static int tipc_l2_rcv_msg(struct sk_buff *buf, struct net_device *dev,
530 struct packet_type *pt, struct net_device *orig_dev)
531{
532 struct tipc_bearer *b_ptr;
533
534 if (!net_eq(dev_net(dev), &init_net)) {
535 kfree_skb(buf);
536 return NET_RX_DROP;
537 }
538
539 rcu_read_lock();
540 b_ptr = rcu_dereference(dev->tipc_ptr);
541 if (likely(b_ptr)) {
542 if (likely(buf->pkt_type <= PACKET_BROADCAST)) {
543 buf->next = NULL;
544 tipc_rcv(buf, b_ptr);
545 rcu_read_unlock();
546 return NET_RX_SUCCESS;
547 }
548 }
549 rcu_read_unlock();
550
551 kfree_skb(buf);
552 return NET_RX_DROP;
553}
554
555/**
556 * tipc_l2_device_event - handle device events from network device
557 * @nb: the context of the notification
558 * @evt: the type of event
559 * @ptr: the net device that the event was on
560 *
561 * This function is called by the Ethernet driver in case of link
562 * change event.
563 */
564static int tipc_l2_device_event(struct notifier_block *nb, unsigned long evt,
565 void *ptr)
566{
567 struct tipc_bearer *b_ptr;
568 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
569
570 if (!net_eq(dev_net(dev), &init_net))
571 return NOTIFY_DONE;
572
573 rcu_read_lock();
574 b_ptr = rcu_dereference(dev->tipc_ptr);
575 if (!b_ptr) {
576 rcu_read_unlock();
577 return NOTIFY_DONE;
578 }
579
580 b_ptr->mtu = dev->mtu;
581
582 switch (evt) {
583 case NETDEV_CHANGE:
584 if (netif_carrier_ok(dev))
585 break;
586 case NETDEV_DOWN:
587 case NETDEV_CHANGEMTU:
588 case NETDEV_CHANGEADDR:
589 tipc_reset_bearer(b_ptr);
590 break;
591 case NETDEV_UNREGISTER:
592 case NETDEV_CHANGENAME:
593 tipc_disable_bearer(b_ptr->name);
594 break;
595 }
596 rcu_read_unlock();
597
598 return NOTIFY_OK;
599}
600
601static struct packet_type tipc_packet_type __read_mostly = {
602 .type = __constant_htons(ETH_P_TIPC),
603 .func = tipc_l2_rcv_msg,
604};
605
606static struct notifier_block notifier = {
607 .notifier_call = tipc_l2_device_event,
608 .priority = 0,
609};
610
611int tipc_bearer_setup(void)
612{
613 dev_add_pack(&tipc_packet_type);
614 return register_netdevice_notifier(&notifier);
615}
616
617void tipc_bearer_cleanup(void)
618{
619 unregister_netdevice_notifier(&notifier);
620 dev_remove_pack(&tipc_packet_type);
621}
493 622
494void tipc_bearer_stop(void) 623void tipc_bearer_stop(void)
495{ 624{
@@ -499,5 +628,4 @@ void tipc_bearer_stop(void)
499 if (tipc_bearers[i].active) 628 if (tipc_bearers[i].active)
500 bearer_disable(&tipc_bearers[i]); 629 bearer_disable(&tipc_bearers[i]);
501 } 630 }
502 media_count = 0;
503} 631}