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.c447
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
53static const struct nla_policy
54tipc_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
64static 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
52struct tipc_bearer __rcu *bearer_list[MAX_BEARERS + 1]; 70struct tipc_bearer __rcu *bearer_list[MAX_BEARERS + 1];
53 71
54static void bearer_disable(struct tipc_bearer *b_ptr, bool shutting_down); 72static 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 */
650static 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
685prop_msg_full:
686 nla_nest_cancel(msg->skb, prop);
687attr_msg_full:
688 nla_nest_cancel(msg->skb, attrs);
689msg_full:
690 genlmsg_cancel(msg->skb, hdr);
691
692 return -EMSGSIZE;
693}
694
695int 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
725int 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);
768err_out:
769 rtnl_unlock();
770 nlmsg_free(rep);
771
772 return err;
773}
774
775int 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
809int 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
860int 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
909static 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
944prop_msg_full:
945 nla_nest_cancel(msg->skb, prop);
946attr_msg_full:
947 nla_nest_cancel(msg->skb, attrs);
948msg_full:
949 genlmsg_cancel(msg->skb, hdr);
950
951 return -EMSGSIZE;
952}
953
954int 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
979int 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);
1022err_out:
1023 rtnl_unlock();
1024 nlmsg_free(rep);
1025
1026 return err;
1027}
1028
1029int 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}