diff options
Diffstat (limited to 'net/tipc/bearer.c')
| -rw-r--r-- | net/tipc/bearer.c | 447 |
1 files changed, 446 insertions, 1 deletions
diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c index 264474394f9f..463db5b15b8b 100644 --- a/net/tipc/bearer.c +++ b/net/tipc/bearer.c | |||
| @@ -1,7 +1,7 @@ | |||
| 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, 2013, Ericsson AB | 4 | * Copyright (c) 1996-2006, 2013-2014, Ericsson AB |
| 5 | * Copyright (c) 2004-2006, 2010-2013, Wind River Systems | 5 | * Copyright (c) 2004-2006, 2010-2013, Wind River Systems |
| 6 | * All rights reserved. | 6 | * All rights reserved. |
| 7 | * | 7 | * |
| @@ -37,6 +37,7 @@ | |||
| 37 | #include "core.h" | 37 | #include "core.h" |
| 38 | #include "config.h" | 38 | #include "config.h" |
| 39 | #include "bearer.h" | 39 | #include "bearer.h" |
| 40 | #include "link.h" | ||
| 40 | #include "discover.h" | 41 | #include "discover.h" |
| 41 | 42 | ||
| 42 | #define MAX_ADDR_STR 60 | 43 | #define MAX_ADDR_STR 60 |
| @@ -49,6 +50,23 @@ static struct tipc_media * const media_info_array[] = { | |||
| 49 | NULL | 50 | NULL |
| 50 | }; | 51 | }; |
| 51 | 52 | ||
| 53 | static const struct nla_policy | ||
| 54 | tipc_nl_bearer_policy[TIPC_NLA_BEARER_MAX + 1] = { | ||
| 55 | [TIPC_NLA_BEARER_UNSPEC] = { .type = NLA_UNSPEC }, | ||
| 56 | [TIPC_NLA_BEARER_NAME] = { | ||
| 57 | .type = NLA_STRING, | ||
| 58 | .len = TIPC_MAX_BEARER_NAME | ||
| 59 | }, | ||
| 60 | [TIPC_NLA_BEARER_PROP] = { .type = NLA_NESTED }, | ||
| 61 | [TIPC_NLA_BEARER_DOMAIN] = { .type = NLA_U32 } | ||
| 62 | }; | ||
| 63 | |||
| 64 | static const struct nla_policy tipc_nl_media_policy[TIPC_NLA_MEDIA_MAX + 1] = { | ||
| 65 | [TIPC_NLA_MEDIA_UNSPEC] = { .type = NLA_UNSPEC }, | ||
| 66 | [TIPC_NLA_MEDIA_NAME] = { .type = NLA_STRING }, | ||
| 67 | [TIPC_NLA_MEDIA_PROP] = { .type = NLA_NESTED } | ||
| 68 | }; | ||
| 69 | |||
| 52 | struct tipc_bearer __rcu *bearer_list[MAX_BEARERS + 1]; | 70 | struct tipc_bearer __rcu *bearer_list[MAX_BEARERS + 1]; |
| 53 | 71 | ||
| 54 | static void bearer_disable(struct tipc_bearer *b_ptr, bool shutting_down); | 72 | static void bearer_disable(struct tipc_bearer *b_ptr, bool shutting_down); |
| @@ -627,3 +645,430 @@ void tipc_bearer_stop(void) | |||
| 627 | } | 645 | } |
| 628 | } | 646 | } |
| 629 | } | 647 | } |
| 648 | |||
| 649 | /* Caller should hold rtnl_lock to protect the bearer */ | ||
| 650 | static int __tipc_nl_add_bearer(struct tipc_nl_msg *msg, | ||
| 651 | struct tipc_bearer *bearer) | ||
| 652 | { | ||
| 653 | void *hdr; | ||
| 654 | struct nlattr *attrs; | ||
| 655 | struct nlattr *prop; | ||
| 656 | |||
| 657 | hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_v2_family, | ||
| 658 | NLM_F_MULTI, TIPC_NL_BEARER_GET); | ||
| 659 | if (!hdr) | ||
| 660 | return -EMSGSIZE; | ||
| 661 | |||
| 662 | attrs = nla_nest_start(msg->skb, TIPC_NLA_BEARER); | ||
| 663 | if (!attrs) | ||
| 664 | goto msg_full; | ||
| 665 | |||
| 666 | if (nla_put_string(msg->skb, TIPC_NLA_BEARER_NAME, bearer->name)) | ||
| 667 | goto attr_msg_full; | ||
| 668 | |||
| 669 | prop = nla_nest_start(msg->skb, TIPC_NLA_BEARER_PROP); | ||
| 670 | if (!prop) | ||
| 671 | goto prop_msg_full; | ||
| 672 | if (nla_put_u32(msg->skb, TIPC_NLA_PROP_PRIO, bearer->priority)) | ||
| 673 | goto prop_msg_full; | ||
| 674 | if (nla_put_u32(msg->skb, TIPC_NLA_PROP_TOL, bearer->tolerance)) | ||
| 675 | goto prop_msg_full; | ||
| 676 | if (nla_put_u32(msg->skb, TIPC_NLA_PROP_WIN, bearer->window)) | ||
| 677 | goto prop_msg_full; | ||
| 678 | |||
| 679 | nla_nest_end(msg->skb, prop); | ||
| 680 | nla_nest_end(msg->skb, attrs); | ||
| 681 | genlmsg_end(msg->skb, hdr); | ||
| 682 | |||
| 683 | return 0; | ||
| 684 | |||
| 685 | prop_msg_full: | ||
| 686 | nla_nest_cancel(msg->skb, prop); | ||
| 687 | attr_msg_full: | ||
| 688 | nla_nest_cancel(msg->skb, attrs); | ||
| 689 | msg_full: | ||
| 690 | genlmsg_cancel(msg->skb, hdr); | ||
| 691 | |||
| 692 | return -EMSGSIZE; | ||
| 693 | } | ||
| 694 | |||
| 695 | int tipc_nl_bearer_dump(struct sk_buff *skb, struct netlink_callback *cb) | ||
| 696 | { | ||
| 697 | int err; | ||
| 698 | int i = cb->args[0]; | ||
| 699 | struct tipc_bearer *bearer; | ||
| 700 | struct tipc_nl_msg msg; | ||
| 701 | |||
| 702 | if (i == MAX_BEARERS) | ||
| 703 | return 0; | ||
| 704 | |||
| 705 | msg.skb = skb; | ||
| 706 | msg.portid = NETLINK_CB(cb->skb).portid; | ||
| 707 | msg.seq = cb->nlh->nlmsg_seq; | ||
| 708 | |||
| 709 | rtnl_lock(); | ||
| 710 | for (i = 0; i < MAX_BEARERS; i++) { | ||
| 711 | bearer = rtnl_dereference(bearer_list[i]); | ||
| 712 | if (!bearer) | ||
| 713 | continue; | ||
| 714 | |||
| 715 | err = __tipc_nl_add_bearer(&msg, bearer); | ||
| 716 | if (err) | ||
| 717 | break; | ||
| 718 | } | ||
| 719 | rtnl_unlock(); | ||
| 720 | |||
| 721 | cb->args[0] = i; | ||
| 722 | return skb->len; | ||
| 723 | } | ||
| 724 | |||
| 725 | int tipc_nl_bearer_get(struct sk_buff *skb, struct genl_info *info) | ||
| 726 | { | ||
| 727 | int err; | ||
| 728 | char *name; | ||
| 729 | struct sk_buff *rep; | ||
| 730 | struct tipc_bearer *bearer; | ||
| 731 | struct tipc_nl_msg msg; | ||
| 732 | struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1]; | ||
| 733 | |||
| 734 | if (!info->attrs[TIPC_NLA_BEARER]) | ||
| 735 | return -EINVAL; | ||
| 736 | |||
| 737 | err = nla_parse_nested(attrs, TIPC_NLA_BEARER_MAX, | ||
| 738 | info->attrs[TIPC_NLA_BEARER], | ||
| 739 | tipc_nl_bearer_policy); | ||
| 740 | if (err) | ||
| 741 | return err; | ||
| 742 | |||
| 743 | if (!attrs[TIPC_NLA_BEARER_NAME]) | ||
| 744 | return -EINVAL; | ||
| 745 | name = nla_data(attrs[TIPC_NLA_BEARER_NAME]); | ||
| 746 | |||
| 747 | rep = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | ||
| 748 | if (!rep) | ||
| 749 | return -ENOMEM; | ||
| 750 | |||
| 751 | msg.skb = rep; | ||
| 752 | msg.portid = info->snd_portid; | ||
| 753 | msg.seq = info->snd_seq; | ||
| 754 | |||
| 755 | rtnl_lock(); | ||
| 756 | bearer = tipc_bearer_find(name); | ||
| 757 | if (!bearer) { | ||
| 758 | err = -EINVAL; | ||
| 759 | goto err_out; | ||
| 760 | } | ||
| 761 | |||
| 762 | err = __tipc_nl_add_bearer(&msg, bearer); | ||
| 763 | if (err) | ||
| 764 | goto err_out; | ||
| 765 | rtnl_unlock(); | ||
| 766 | |||
| 767 | return genlmsg_reply(rep, info); | ||
| 768 | err_out: | ||
| 769 | rtnl_unlock(); | ||
| 770 | nlmsg_free(rep); | ||
| 771 | |||
| 772 | return err; | ||
| 773 | } | ||
| 774 | |||
| 775 | int tipc_nl_bearer_disable(struct sk_buff *skb, struct genl_info *info) | ||
| 776 | { | ||
| 777 | int err; | ||
| 778 | char *name; | ||
| 779 | struct tipc_bearer *bearer; | ||
| 780 | struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1]; | ||
| 781 | |||
| 782 | if (!info->attrs[TIPC_NLA_BEARER]) | ||
| 783 | return -EINVAL; | ||
| 784 | |||
| 785 | err = nla_parse_nested(attrs, TIPC_NLA_BEARER_MAX, | ||
| 786 | info->attrs[TIPC_NLA_BEARER], | ||
| 787 | tipc_nl_bearer_policy); | ||
| 788 | if (err) | ||
| 789 | return err; | ||
| 790 | |||
| 791 | if (!attrs[TIPC_NLA_BEARER_NAME]) | ||
| 792 | return -EINVAL; | ||
| 793 | |||
| 794 | name = nla_data(attrs[TIPC_NLA_BEARER_NAME]); | ||
| 795 | |||
| 796 | rtnl_lock(); | ||
| 797 | bearer = tipc_bearer_find(name); | ||
| 798 | if (!bearer) { | ||
| 799 | rtnl_unlock(); | ||
| 800 | return -EINVAL; | ||
| 801 | } | ||
| 802 | |||
| 803 | bearer_disable(bearer, false); | ||
| 804 | rtnl_unlock(); | ||
| 805 | |||
| 806 | return 0; | ||
| 807 | } | ||
| 808 | |||
| 809 | int tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info) | ||
| 810 | { | ||
| 811 | int err; | ||
| 812 | char *bearer; | ||
| 813 | struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1]; | ||
| 814 | u32 domain; | ||
| 815 | u32 prio; | ||
| 816 | |||
| 817 | prio = TIPC_MEDIA_LINK_PRI; | ||
| 818 | domain = tipc_own_addr & TIPC_CLUSTER_MASK; | ||
| 819 | |||
| 820 | if (!info->attrs[TIPC_NLA_BEARER]) | ||
| 821 | return -EINVAL; | ||
| 822 | |||
| 823 | err = nla_parse_nested(attrs, TIPC_NLA_BEARER_MAX, | ||
| 824 | info->attrs[TIPC_NLA_BEARER], | ||
| 825 | tipc_nl_bearer_policy); | ||
| 826 | if (err) | ||
| 827 | return err; | ||
| 828 | |||
| 829 | if (!attrs[TIPC_NLA_BEARER_NAME]) | ||
| 830 | return -EINVAL; | ||
| 831 | |||
| 832 | bearer = nla_data(attrs[TIPC_NLA_BEARER_NAME]); | ||
| 833 | |||
| 834 | if (attrs[TIPC_NLA_BEARER_DOMAIN]) | ||
| 835 | domain = nla_get_u32(attrs[TIPC_NLA_BEARER_DOMAIN]); | ||
| 836 | |||
| 837 | if (attrs[TIPC_NLA_BEARER_PROP]) { | ||
| 838 | struct nlattr *props[TIPC_NLA_PROP_MAX + 1]; | ||
| 839 | |||
| 840 | err = tipc_nl_parse_link_prop(attrs[TIPC_NLA_BEARER_PROP], | ||
| 841 | props); | ||
| 842 | if (err) | ||
| 843 | return err; | ||
| 844 | |||
| 845 | if (props[TIPC_NLA_PROP_PRIO]) | ||
| 846 | prio = nla_get_u32(props[TIPC_NLA_PROP_PRIO]); | ||
| 847 | } | ||
| 848 | |||
| 849 | rtnl_lock(); | ||
| 850 | err = tipc_enable_bearer(bearer, domain, prio); | ||
| 851 | if (err) { | ||
| 852 | rtnl_unlock(); | ||
| 853 | return err; | ||
| 854 | } | ||
| 855 | rtnl_unlock(); | ||
| 856 | |||
| 857 | return 0; | ||
| 858 | } | ||
| 859 | |||
| 860 | int tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info) | ||
| 861 | { | ||
| 862 | int err; | ||
| 863 | char *name; | ||
| 864 | struct tipc_bearer *b; | ||
| 865 | struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1]; | ||
| 866 | |||
| 867 | if (!info->attrs[TIPC_NLA_BEARER]) | ||
| 868 | return -EINVAL; | ||
| 869 | |||
| 870 | err = nla_parse_nested(attrs, TIPC_NLA_BEARER_MAX, | ||
| 871 | info->attrs[TIPC_NLA_BEARER], | ||
| 872 | tipc_nl_bearer_policy); | ||
| 873 | if (err) | ||
| 874 | return err; | ||
| 875 | |||
| 876 | if (!attrs[TIPC_NLA_BEARER_NAME]) | ||
| 877 | return -EINVAL; | ||
| 878 | name = nla_data(attrs[TIPC_NLA_BEARER_NAME]); | ||
| 879 | |||
| 880 | rtnl_lock(); | ||
| 881 | b = tipc_bearer_find(name); | ||
| 882 | if (!b) { | ||
| 883 | rtnl_unlock(); | ||
| 884 | return -EINVAL; | ||
| 885 | } | ||
| 886 | |||
| 887 | if (attrs[TIPC_NLA_BEARER_PROP]) { | ||
| 888 | struct nlattr *props[TIPC_NLA_PROP_MAX + 1]; | ||
| 889 | |||
| 890 | err = tipc_nl_parse_link_prop(attrs[TIPC_NLA_BEARER_PROP], | ||
| 891 | props); | ||
| 892 | if (err) { | ||
| 893 | rtnl_unlock(); | ||
| 894 | return err; | ||
| 895 | } | ||
| 896 | |||
| 897 | if (props[TIPC_NLA_PROP_TOL]) | ||
| 898 | b->tolerance = nla_get_u32(props[TIPC_NLA_PROP_TOL]); | ||
| 899 | if (props[TIPC_NLA_PROP_PRIO]) | ||
| 900 | b->priority = nla_get_u32(props[TIPC_NLA_PROP_PRIO]); | ||
| 901 | if (props[TIPC_NLA_PROP_WIN]) | ||
| 902 | b->window = nla_get_u32(props[TIPC_NLA_PROP_WIN]); | ||
| 903 | } | ||
| 904 | rtnl_unlock(); | ||
| 905 | |||
| 906 | return 0; | ||
| 907 | } | ||
| 908 | |||
| 909 | static int __tipc_nl_add_media(struct tipc_nl_msg *msg, | ||
| 910 | struct tipc_media *media) | ||
| 911 | { | ||
| 912 | void *hdr; | ||
| 913 | struct nlattr *attrs; | ||
| 914 | struct nlattr *prop; | ||
| 915 | |||
| 916 | hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_v2_family, | ||
| 917 | NLM_F_MULTI, TIPC_NL_MEDIA_GET); | ||
| 918 | if (!hdr) | ||
| 919 | return -EMSGSIZE; | ||
| 920 | |||
| 921 | attrs = nla_nest_start(msg->skb, TIPC_NLA_MEDIA); | ||
| 922 | if (!attrs) | ||
| 923 | goto msg_full; | ||
| 924 | |||
| 925 | if (nla_put_string(msg->skb, TIPC_NLA_MEDIA_NAME, media->name)) | ||
| 926 | goto attr_msg_full; | ||
| 927 | |||
| 928 | prop = nla_nest_start(msg->skb, TIPC_NLA_MEDIA_PROP); | ||
| 929 | if (!prop) | ||
| 930 | goto prop_msg_full; | ||
| 931 | if (nla_put_u32(msg->skb, TIPC_NLA_PROP_PRIO, media->priority)) | ||
| 932 | goto prop_msg_full; | ||
| 933 | if (nla_put_u32(msg->skb, TIPC_NLA_PROP_TOL, media->tolerance)) | ||
| 934 | goto prop_msg_full; | ||
| 935 | if (nla_put_u32(msg->skb, TIPC_NLA_PROP_WIN, media->window)) | ||
| 936 | goto prop_msg_full; | ||
| 937 | |||
| 938 | nla_nest_end(msg->skb, prop); | ||
| 939 | nla_nest_end(msg->skb, attrs); | ||
| 940 | genlmsg_end(msg->skb, hdr); | ||
| 941 | |||
| 942 | return 0; | ||
| 943 | |||
| 944 | prop_msg_full: | ||
| 945 | nla_nest_cancel(msg->skb, prop); | ||
| 946 | attr_msg_full: | ||
| 947 | nla_nest_cancel(msg->skb, attrs); | ||
| 948 | msg_full: | ||
| 949 | genlmsg_cancel(msg->skb, hdr); | ||
| 950 | |||
| 951 | return -EMSGSIZE; | ||
| 952 | } | ||
| 953 | |||
| 954 | int tipc_nl_media_dump(struct sk_buff *skb, struct netlink_callback *cb) | ||
| 955 | { | ||
| 956 | int err; | ||
| 957 | int i = cb->args[0]; | ||
| 958 | struct tipc_nl_msg msg; | ||
| 959 | |||
| 960 | if (i == MAX_MEDIA) | ||
| 961 | return 0; | ||
| 962 | |||
| 963 | msg.skb = skb; | ||
| 964 | msg.portid = NETLINK_CB(cb->skb).portid; | ||
| 965 | msg.seq = cb->nlh->nlmsg_seq; | ||
| 966 | |||
| 967 | rtnl_lock(); | ||
| 968 | for (; media_info_array[i] != NULL; i++) { | ||
| 969 | err = __tipc_nl_add_media(&msg, media_info_array[i]); | ||
| 970 | if (err) | ||
| 971 | break; | ||
| 972 | } | ||
| 973 | rtnl_unlock(); | ||
| 974 | |||
| 975 | cb->args[0] = i; | ||
| 976 | return skb->len; | ||
| 977 | } | ||
| 978 | |||
| 979 | int tipc_nl_media_get(struct sk_buff *skb, struct genl_info *info) | ||
| 980 | { | ||
| 981 | int err; | ||
| 982 | char *name; | ||
| 983 | struct tipc_nl_msg msg; | ||
| 984 | struct tipc_media *media; | ||
| 985 | struct sk_buff *rep; | ||
| 986 | struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1]; | ||
| 987 | |||
| 988 | if (!info->attrs[TIPC_NLA_MEDIA]) | ||
| 989 | return -EINVAL; | ||
| 990 | |||
| 991 | err = nla_parse_nested(attrs, TIPC_NLA_MEDIA_MAX, | ||
| 992 | info->attrs[TIPC_NLA_MEDIA], | ||
| 993 | tipc_nl_media_policy); | ||
| 994 | if (err) | ||
| 995 | return err; | ||
| 996 | |||
| 997 | if (!attrs[TIPC_NLA_MEDIA_NAME]) | ||
| 998 | return -EINVAL; | ||
| 999 | name = nla_data(attrs[TIPC_NLA_MEDIA_NAME]); | ||
| 1000 | |||
| 1001 | rep = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | ||
| 1002 | if (!rep) | ||
| 1003 | return -ENOMEM; | ||
| 1004 | |||
| 1005 | msg.skb = rep; | ||
| 1006 | msg.portid = info->snd_portid; | ||
| 1007 | msg.seq = info->snd_seq; | ||
| 1008 | |||
| 1009 | rtnl_lock(); | ||
| 1010 | media = tipc_media_find(name); | ||
| 1011 | if (!media) { | ||
| 1012 | err = -EINVAL; | ||
| 1013 | goto err_out; | ||
| 1014 | } | ||
| 1015 | |||
| 1016 | err = __tipc_nl_add_media(&msg, media); | ||
| 1017 | if (err) | ||
| 1018 | goto err_out; | ||
| 1019 | rtnl_unlock(); | ||
| 1020 | |||
| 1021 | return genlmsg_reply(rep, info); | ||
| 1022 | err_out: | ||
| 1023 | rtnl_unlock(); | ||
| 1024 | nlmsg_free(rep); | ||
| 1025 | |||
| 1026 | return err; | ||
| 1027 | } | ||
| 1028 | |||
| 1029 | int tipc_nl_media_set(struct sk_buff *skb, struct genl_info *info) | ||
| 1030 | { | ||
| 1031 | int err; | ||
| 1032 | char *name; | ||
| 1033 | struct tipc_media *m; | ||
| 1034 | struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1]; | ||
| 1035 | |||
| 1036 | if (!info->attrs[TIPC_NLA_MEDIA]) | ||
| 1037 | return -EINVAL; | ||
| 1038 | |||
| 1039 | err = nla_parse_nested(attrs, TIPC_NLA_MEDIA_MAX, | ||
| 1040 | info->attrs[TIPC_NLA_MEDIA], | ||
| 1041 | tipc_nl_media_policy); | ||
| 1042 | |||
| 1043 | if (!attrs[TIPC_NLA_MEDIA_NAME]) | ||
| 1044 | return -EINVAL; | ||
| 1045 | name = nla_data(attrs[TIPC_NLA_MEDIA_NAME]); | ||
| 1046 | |||
| 1047 | rtnl_lock(); | ||
| 1048 | m = tipc_media_find(name); | ||
| 1049 | if (!m) { | ||
| 1050 | rtnl_unlock(); | ||
| 1051 | return -EINVAL; | ||
| 1052 | } | ||
| 1053 | |||
| 1054 | if (attrs[TIPC_NLA_MEDIA_PROP]) { | ||
| 1055 | struct nlattr *props[TIPC_NLA_PROP_MAX + 1]; | ||
| 1056 | |||
| 1057 | err = tipc_nl_parse_link_prop(attrs[TIPC_NLA_MEDIA_PROP], | ||
| 1058 | props); | ||
| 1059 | if (err) { | ||
| 1060 | rtnl_unlock(); | ||
| 1061 | return err; | ||
| 1062 | } | ||
| 1063 | |||
| 1064 | if (props[TIPC_NLA_PROP_TOL]) | ||
| 1065 | m->tolerance = nla_get_u32(props[TIPC_NLA_PROP_TOL]); | ||
| 1066 | if (props[TIPC_NLA_PROP_PRIO]) | ||
| 1067 | m->priority = nla_get_u32(props[TIPC_NLA_PROP_PRIO]); | ||
| 1068 | if (props[TIPC_NLA_PROP_WIN]) | ||
| 1069 | m->window = nla_get_u32(props[TIPC_NLA_PROP_WIN]); | ||
| 1070 | } | ||
| 1071 | rtnl_unlock(); | ||
| 1072 | |||
| 1073 | return 0; | ||
| 1074 | } | ||
