diff options
Diffstat (limited to 'net/tipc/bearer.c')
-rw-r--r-- | net/tipc/bearer.c | 342 |
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 | ||
44 | static struct tipc_media *media_list[MAX_MEDIA]; | 44 | static struct tipc_media * const media_info_array[] = { |
45 | static u32 media_count; | 45 | ð_media_info, |
46 | #ifdef CONFIG_TIPC_MEDIA_IB | ||
47 | &ib_media_info, | ||
48 | #endif | ||
49 | NULL | ||
50 | }; | ||
46 | 51 | ||
47 | struct tipc_bearer tipc_bearers[MAX_BEARERS]; | 52 | struct 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 | */ | ||
84 | int 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; | ||
105 | exit: | ||
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 | */ | ||
220 | struct 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 | */ |
239 | struct sk_buff *tipc_bearer_get_names(void) | 190 | struct 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 | */ | ||
282 | void 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 | */ | ||
292 | int 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 | */ |
425 | int tipc_block_bearer(struct tipc_bearer *b_ptr) | 351 | static 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 | */ | ||
422 | void 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 | |||
438 | int 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 | */ | ||
466 | void 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 | */ | ||
479 | int 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 | */ | ||
512 | void 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 | */ | ||
529 | static 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 | */ | ||
564 | static 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 | |||
601 | static struct packet_type tipc_packet_type __read_mostly = { | ||
602 | .type = __constant_htons(ETH_P_TIPC), | ||
603 | .func = tipc_l2_rcv_msg, | ||
604 | }; | ||
605 | |||
606 | static struct notifier_block notifier = { | ||
607 | .notifier_call = tipc_l2_device_event, | ||
608 | .priority = 0, | ||
609 | }; | ||
610 | |||
611 | int tipc_bearer_setup(void) | ||
612 | { | ||
613 | dev_add_pack(&tipc_packet_type); | ||
614 | return register_netdevice_notifier(¬ifier); | ||
615 | } | ||
616 | |||
617 | void tipc_bearer_cleanup(void) | ||
618 | { | ||
619 | unregister_netdevice_notifier(¬ifier); | ||
620 | dev_remove_pack(&tipc_packet_type); | ||
621 | } | ||
493 | 622 | ||
494 | void tipc_bearer_stop(void) | 623 | void 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 | } |