diff options
-rw-r--r-- | include/net/lwtunnel.h | 11 | ||||
-rw-r--r-- | net/core/lwtunnel.c | 62 | ||||
-rw-r--r-- | net/ipv4/fib_frontend.c | 8 | ||||
-rw-r--r-- | net/ipv6/route.c | 12 |
4 files changed, 86 insertions, 7 deletions
diff --git a/include/net/lwtunnel.h b/include/net/lwtunnel.h index d4c1c75b8862..0b585f1fd340 100644 --- a/include/net/lwtunnel.h +++ b/include/net/lwtunnel.h | |||
@@ -105,6 +105,8 @@ int lwtunnel_encap_add_ops(const struct lwtunnel_encap_ops *op, | |||
105 | unsigned int num); | 105 | unsigned int num); |
106 | int lwtunnel_encap_del_ops(const struct lwtunnel_encap_ops *op, | 106 | int lwtunnel_encap_del_ops(const struct lwtunnel_encap_ops *op, |
107 | unsigned int num); | 107 | unsigned int num); |
108 | int lwtunnel_valid_encap_type(u16 encap_type); | ||
109 | int lwtunnel_valid_encap_type_attr(struct nlattr *attr, int len); | ||
108 | int lwtunnel_build_state(struct net_device *dev, u16 encap_type, | 110 | int lwtunnel_build_state(struct net_device *dev, u16 encap_type, |
109 | struct nlattr *encap, | 111 | struct nlattr *encap, |
110 | unsigned int family, const void *cfg, | 112 | unsigned int family, const void *cfg, |
@@ -168,6 +170,15 @@ static inline int lwtunnel_encap_del_ops(const struct lwtunnel_encap_ops *op, | |||
168 | return -EOPNOTSUPP; | 170 | return -EOPNOTSUPP; |
169 | } | 171 | } |
170 | 172 | ||
173 | static inline int lwtunnel_valid_encap_type(u16 encap_type) | ||
174 | { | ||
175 | return -EOPNOTSUPP; | ||
176 | } | ||
177 | static inline int lwtunnel_valid_encap_type_attr(struct nlattr *attr, int len) | ||
178 | { | ||
179 | return -EOPNOTSUPP; | ||
180 | } | ||
181 | |||
171 | static inline int lwtunnel_build_state(struct net_device *dev, u16 encap_type, | 182 | static inline int lwtunnel_build_state(struct net_device *dev, u16 encap_type, |
172 | struct nlattr *encap, | 183 | struct nlattr *encap, |
173 | unsigned int family, const void *cfg, | 184 | unsigned int family, const void *cfg, |
diff --git a/net/core/lwtunnel.c b/net/core/lwtunnel.c index a5d4e866ce88..47b1dd65947b 100644 --- a/net/core/lwtunnel.c +++ b/net/core/lwtunnel.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <net/lwtunnel.h> | 26 | #include <net/lwtunnel.h> |
27 | #include <net/rtnetlink.h> | 27 | #include <net/rtnetlink.h> |
28 | #include <net/ip6_fib.h> | 28 | #include <net/ip6_fib.h> |
29 | #include <net/nexthop.h> | ||
29 | 30 | ||
30 | #ifdef CONFIG_MODULES | 31 | #ifdef CONFIG_MODULES |
31 | 32 | ||
@@ -114,25 +115,74 @@ int lwtunnel_build_state(struct net_device *dev, u16 encap_type, | |||
114 | ret = -EOPNOTSUPP; | 115 | ret = -EOPNOTSUPP; |
115 | rcu_read_lock(); | 116 | rcu_read_lock(); |
116 | ops = rcu_dereference(lwtun_encaps[encap_type]); | 117 | ops = rcu_dereference(lwtun_encaps[encap_type]); |
118 | if (likely(ops && ops->build_state)) | ||
119 | ret = ops->build_state(dev, encap, family, cfg, lws); | ||
120 | rcu_read_unlock(); | ||
121 | |||
122 | return ret; | ||
123 | } | ||
124 | EXPORT_SYMBOL(lwtunnel_build_state); | ||
125 | |||
126 | int lwtunnel_valid_encap_type(u16 encap_type) | ||
127 | { | ||
128 | const struct lwtunnel_encap_ops *ops; | ||
129 | int ret = -EINVAL; | ||
130 | |||
131 | if (encap_type == LWTUNNEL_ENCAP_NONE || | ||
132 | encap_type > LWTUNNEL_ENCAP_MAX) | ||
133 | return ret; | ||
134 | |||
135 | rcu_read_lock(); | ||
136 | ops = rcu_dereference(lwtun_encaps[encap_type]); | ||
137 | rcu_read_unlock(); | ||
117 | #ifdef CONFIG_MODULES | 138 | #ifdef CONFIG_MODULES |
118 | if (!ops) { | 139 | if (!ops) { |
119 | const char *encap_type_str = lwtunnel_encap_str(encap_type); | 140 | const char *encap_type_str = lwtunnel_encap_str(encap_type); |
120 | 141 | ||
121 | if (encap_type_str) { | 142 | if (encap_type_str) { |
122 | rcu_read_unlock(); | 143 | __rtnl_unlock(); |
123 | request_module("rtnl-lwt-%s", encap_type_str); | 144 | request_module("rtnl-lwt-%s", encap_type_str); |
145 | rtnl_lock(); | ||
146 | |||
124 | rcu_read_lock(); | 147 | rcu_read_lock(); |
125 | ops = rcu_dereference(lwtun_encaps[encap_type]); | 148 | ops = rcu_dereference(lwtun_encaps[encap_type]); |
149 | rcu_read_unlock(); | ||
126 | } | 150 | } |
127 | } | 151 | } |
128 | #endif | 152 | #endif |
129 | if (likely(ops && ops->build_state)) | 153 | return ops ? 0 : -EOPNOTSUPP; |
130 | ret = ops->build_state(dev, encap, family, cfg, lws); | 154 | } |
131 | rcu_read_unlock(); | 155 | EXPORT_SYMBOL(lwtunnel_valid_encap_type); |
132 | 156 | ||
133 | return ret; | 157 | int lwtunnel_valid_encap_type_attr(struct nlattr *attr, int remaining) |
158 | { | ||
159 | struct rtnexthop *rtnh = (struct rtnexthop *)attr; | ||
160 | struct nlattr *nla_entype; | ||
161 | struct nlattr *attrs; | ||
162 | struct nlattr *nla; | ||
163 | u16 encap_type; | ||
164 | int attrlen; | ||
165 | |||
166 | while (rtnh_ok(rtnh, remaining)) { | ||
167 | attrlen = rtnh_attrlen(rtnh); | ||
168 | if (attrlen > 0) { | ||
169 | attrs = rtnh_attrs(rtnh); | ||
170 | nla = nla_find(attrs, attrlen, RTA_ENCAP); | ||
171 | nla_entype = nla_find(attrs, attrlen, RTA_ENCAP_TYPE); | ||
172 | |||
173 | if (nla_entype) { | ||
174 | encap_type = nla_get_u16(nla_entype); | ||
175 | |||
176 | if (lwtunnel_valid_encap_type(encap_type) != 0) | ||
177 | return -EOPNOTSUPP; | ||
178 | } | ||
179 | } | ||
180 | rtnh = rtnh_next(rtnh, &remaining); | ||
181 | } | ||
182 | |||
183 | return 0; | ||
134 | } | 184 | } |
135 | EXPORT_SYMBOL(lwtunnel_build_state); | 185 | EXPORT_SYMBOL(lwtunnel_valid_encap_type_attr); |
136 | 186 | ||
137 | void lwtstate_free(struct lwtunnel_state *lws) | 187 | void lwtstate_free(struct lwtunnel_state *lws) |
138 | { | 188 | { |
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index eae0332b0e8c..7db2ad2e82d3 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c | |||
@@ -46,6 +46,7 @@ | |||
46 | #include <net/rtnetlink.h> | 46 | #include <net/rtnetlink.h> |
47 | #include <net/xfrm.h> | 47 | #include <net/xfrm.h> |
48 | #include <net/l3mdev.h> | 48 | #include <net/l3mdev.h> |
49 | #include <net/lwtunnel.h> | ||
49 | #include <trace/events/fib.h> | 50 | #include <trace/events/fib.h> |
50 | 51 | ||
51 | #ifndef CONFIG_IP_MULTIPLE_TABLES | 52 | #ifndef CONFIG_IP_MULTIPLE_TABLES |
@@ -677,6 +678,10 @@ static int rtm_to_fib_config(struct net *net, struct sk_buff *skb, | |||
677 | cfg->fc_mx_len = nla_len(attr); | 678 | cfg->fc_mx_len = nla_len(attr); |
678 | break; | 679 | break; |
679 | case RTA_MULTIPATH: | 680 | case RTA_MULTIPATH: |
681 | err = lwtunnel_valid_encap_type_attr(nla_data(attr), | ||
682 | nla_len(attr)); | ||
683 | if (err < 0) | ||
684 | goto errout; | ||
680 | cfg->fc_mp = nla_data(attr); | 685 | cfg->fc_mp = nla_data(attr); |
681 | cfg->fc_mp_len = nla_len(attr); | 686 | cfg->fc_mp_len = nla_len(attr); |
682 | break; | 687 | break; |
@@ -691,6 +696,9 @@ static int rtm_to_fib_config(struct net *net, struct sk_buff *skb, | |||
691 | break; | 696 | break; |
692 | case RTA_ENCAP_TYPE: | 697 | case RTA_ENCAP_TYPE: |
693 | cfg->fc_encap_type = nla_get_u16(attr); | 698 | cfg->fc_encap_type = nla_get_u16(attr); |
699 | err = lwtunnel_valid_encap_type(cfg->fc_encap_type); | ||
700 | if (err < 0) | ||
701 | goto errout; | ||
694 | break; | 702 | break; |
695 | } | 703 | } |
696 | } | 704 | } |
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 4f6b067c8753..7ea85370c11c 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -2896,6 +2896,11 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
2896 | if (tb[RTA_MULTIPATH]) { | 2896 | if (tb[RTA_MULTIPATH]) { |
2897 | cfg->fc_mp = nla_data(tb[RTA_MULTIPATH]); | 2897 | cfg->fc_mp = nla_data(tb[RTA_MULTIPATH]); |
2898 | cfg->fc_mp_len = nla_len(tb[RTA_MULTIPATH]); | 2898 | cfg->fc_mp_len = nla_len(tb[RTA_MULTIPATH]); |
2899 | |||
2900 | err = lwtunnel_valid_encap_type_attr(cfg->fc_mp, | ||
2901 | cfg->fc_mp_len); | ||
2902 | if (err < 0) | ||
2903 | goto errout; | ||
2899 | } | 2904 | } |
2900 | 2905 | ||
2901 | if (tb[RTA_PREF]) { | 2906 | if (tb[RTA_PREF]) { |
@@ -2909,9 +2914,14 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
2909 | if (tb[RTA_ENCAP]) | 2914 | if (tb[RTA_ENCAP]) |
2910 | cfg->fc_encap = tb[RTA_ENCAP]; | 2915 | cfg->fc_encap = tb[RTA_ENCAP]; |
2911 | 2916 | ||
2912 | if (tb[RTA_ENCAP_TYPE]) | 2917 | if (tb[RTA_ENCAP_TYPE]) { |
2913 | cfg->fc_encap_type = nla_get_u16(tb[RTA_ENCAP_TYPE]); | 2918 | cfg->fc_encap_type = nla_get_u16(tb[RTA_ENCAP_TYPE]); |
2914 | 2919 | ||
2920 | err = lwtunnel_valid_encap_type(cfg->fc_encap_type); | ||
2921 | if (err < 0) | ||
2922 | goto errout; | ||
2923 | } | ||
2924 | |||
2915 | if (tb[RTA_EXPIRES]) { | 2925 | if (tb[RTA_EXPIRES]) { |
2916 | unsigned long timeout = addrconf_timeout_fixup(nla_get_u32(tb[RTA_EXPIRES]), HZ); | 2926 | unsigned long timeout = addrconf_timeout_fixup(nla_get_u32(tb[RTA_EXPIRES]), HZ); |
2917 | 2927 | ||