diff options
Diffstat (limited to 'net/tipc')
-rw-r--r-- | net/tipc/bearer.c | 44 | ||||
-rw-r--r-- | net/tipc/bearer.h | 1 | ||||
-rw-r--r-- | net/tipc/netlink.c | 5 | ||||
-rw-r--r-- | net/tipc/udp_media.c | 118 | ||||
-rw-r--r-- | net/tipc/udp_media.h | 44 |
5 files changed, 200 insertions, 12 deletions
diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c index 28056fa8f77a..d7b442dd6669 100644 --- a/net/tipc/bearer.c +++ b/net/tipc/bearer.c | |||
@@ -42,6 +42,7 @@ | |||
42 | #include "monitor.h" | 42 | #include "monitor.h" |
43 | #include "bcast.h" | 43 | #include "bcast.h" |
44 | #include "netlink.h" | 44 | #include "netlink.h" |
45 | #include "udp_media.h" | ||
45 | 46 | ||
46 | #define MAX_ADDR_STR 60 | 47 | #define MAX_ADDR_STR 60 |
47 | 48 | ||
@@ -897,6 +898,49 @@ int tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info) | |||
897 | return 0; | 898 | return 0; |
898 | } | 899 | } |
899 | 900 | ||
901 | int tipc_nl_bearer_add(struct sk_buff *skb, struct genl_info *info) | ||
902 | { | ||
903 | int err; | ||
904 | char *name; | ||
905 | struct tipc_bearer *b; | ||
906 | struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1]; | ||
907 | struct net *net = sock_net(skb->sk); | ||
908 | |||
909 | if (!info->attrs[TIPC_NLA_BEARER]) | ||
910 | return -EINVAL; | ||
911 | |||
912 | err = nla_parse_nested(attrs, TIPC_NLA_BEARER_MAX, | ||
913 | info->attrs[TIPC_NLA_BEARER], | ||
914 | tipc_nl_bearer_policy); | ||
915 | if (err) | ||
916 | return err; | ||
917 | |||
918 | if (!attrs[TIPC_NLA_BEARER_NAME]) | ||
919 | return -EINVAL; | ||
920 | name = nla_data(attrs[TIPC_NLA_BEARER_NAME]); | ||
921 | |||
922 | rtnl_lock(); | ||
923 | b = tipc_bearer_find(net, name); | ||
924 | if (!b) { | ||
925 | rtnl_unlock(); | ||
926 | return -EINVAL; | ||
927 | } | ||
928 | |||
929 | #ifdef CONFIG_TIPC_MEDIA_UDP | ||
930 | if (attrs[TIPC_NLA_BEARER_UDP_OPTS]) { | ||
931 | err = tipc_udp_nl_bearer_add(b, | ||
932 | attrs[TIPC_NLA_BEARER_UDP_OPTS]); | ||
933 | if (err) { | ||
934 | rtnl_unlock(); | ||
935 | return err; | ||
936 | } | ||
937 | } | ||
938 | #endif | ||
939 | rtnl_unlock(); | ||
940 | |||
941 | return 0; | ||
942 | } | ||
943 | |||
900 | int tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info) | 944 | int tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info) |
901 | { | 945 | { |
902 | int err; | 946 | int err; |
diff --git a/net/tipc/bearer.h b/net/tipc/bearer.h index 83a9abbfe32c..78892e2f53e3 100644 --- a/net/tipc/bearer.h +++ b/net/tipc/bearer.h | |||
@@ -181,6 +181,7 @@ int tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info); | |||
181 | int tipc_nl_bearer_dump(struct sk_buff *skb, struct netlink_callback *cb); | 181 | int tipc_nl_bearer_dump(struct sk_buff *skb, struct netlink_callback *cb); |
182 | int tipc_nl_bearer_get(struct sk_buff *skb, struct genl_info *info); | 182 | int tipc_nl_bearer_get(struct sk_buff *skb, struct genl_info *info); |
183 | int tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info); | 183 | int tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info); |
184 | int tipc_nl_bearer_add(struct sk_buff *skb, struct genl_info *info); | ||
184 | 185 | ||
185 | int tipc_nl_media_dump(struct sk_buff *skb, struct netlink_callback *cb); | 186 | int tipc_nl_media_dump(struct sk_buff *skb, struct netlink_callback *cb); |
186 | int tipc_nl_media_get(struct sk_buff *skb, struct genl_info *info); | 187 | int tipc_nl_media_get(struct sk_buff *skb, struct genl_info *info); |
diff --git a/net/tipc/netlink.c b/net/tipc/netlink.c index 2718de667828..3122f21ca979 100644 --- a/net/tipc/netlink.c +++ b/net/tipc/netlink.c | |||
@@ -161,6 +161,11 @@ static const struct genl_ops tipc_genl_v2_ops[] = { | |||
161 | .policy = tipc_nl_policy, | 161 | .policy = tipc_nl_policy, |
162 | }, | 162 | }, |
163 | { | 163 | { |
164 | .cmd = TIPC_NL_BEARER_ADD, | ||
165 | .doit = tipc_nl_bearer_add, | ||
166 | .policy = tipc_nl_policy, | ||
167 | }, | ||
168 | { | ||
164 | .cmd = TIPC_NL_BEARER_SET, | 169 | .cmd = TIPC_NL_BEARER_SET, |
165 | .doit = tipc_nl_bearer_set, | 170 | .doit = tipc_nl_bearer_set, |
166 | .policy = tipc_nl_policy, | 171 | .policy = tipc_nl_policy, |
diff --git a/net/tipc/udp_media.c b/net/tipc/udp_media.c index b8ec1a18241e..6b938cc15daf 100644 --- a/net/tipc/udp_media.c +++ b/net/tipc/udp_media.c | |||
@@ -49,6 +49,7 @@ | |||
49 | #include "core.h" | 49 | #include "core.h" |
50 | #include "bearer.h" | 50 | #include "bearer.h" |
51 | #include "netlink.h" | 51 | #include "netlink.h" |
52 | #include "msg.h" | ||
52 | 53 | ||
53 | /* IANA assigned UDP port */ | 54 | /* IANA assigned UDP port */ |
54 | #define UDP_PORT_DEFAULT 6118 | 55 | #define UDP_PORT_DEFAULT 6118 |
@@ -70,6 +71,13 @@ struct udp_media_addr { | |||
70 | }; | 71 | }; |
71 | }; | 72 | }; |
72 | 73 | ||
74 | /* struct udp_replicast - container for UDP remote addresses */ | ||
75 | struct udp_replicast { | ||
76 | struct udp_media_addr addr; | ||
77 | struct rcu_head rcu; | ||
78 | struct list_head list; | ||
79 | }; | ||
80 | |||
73 | /** | 81 | /** |
74 | * struct udp_bearer - ip/udp bearer data structure | 82 | * struct udp_bearer - ip/udp bearer data structure |
75 | * @bearer: associated generic tipc bearer | 83 | * @bearer: associated generic tipc bearer |
@@ -82,6 +90,7 @@ struct udp_bearer { | |||
82 | struct socket *ubsock; | 90 | struct socket *ubsock; |
83 | u32 ifindex; | 91 | u32 ifindex; |
84 | struct work_struct work; | 92 | struct work_struct work; |
93 | struct udp_replicast rcast; | ||
85 | }; | 94 | }; |
86 | 95 | ||
87 | static int tipc_udp_is_mcast_addr(struct udp_media_addr *addr) | 96 | static int tipc_udp_is_mcast_addr(struct udp_media_addr *addr) |
@@ -203,29 +212,75 @@ static int tipc_udp_send_msg(struct net *net, struct sk_buff *skb, | |||
203 | { | 212 | { |
204 | struct udp_media_addr *src = (struct udp_media_addr *)&b->addr.value; | 213 | struct udp_media_addr *src = (struct udp_media_addr *)&b->addr.value; |
205 | struct udp_media_addr *dst = (struct udp_media_addr *)&addr->value; | 214 | struct udp_media_addr *dst = (struct udp_media_addr *)&addr->value; |
215 | struct udp_replicast *rcast; | ||
206 | struct udp_bearer *ub; | 216 | struct udp_bearer *ub; |
207 | int err = 0; | 217 | int err = 0; |
208 | 218 | ||
209 | if (skb_headroom(skb) < UDP_MIN_HEADROOM) { | 219 | if (skb_headroom(skb) < UDP_MIN_HEADROOM) { |
210 | err = pskb_expand_head(skb, UDP_MIN_HEADROOM, 0, GFP_ATOMIC); | 220 | err = pskb_expand_head(skb, UDP_MIN_HEADROOM, 0, GFP_ATOMIC); |
211 | if (err) | 221 | if (err) |
212 | goto tx_error; | 222 | goto out; |
213 | } | 223 | } |
214 | 224 | ||
215 | skb_set_inner_protocol(skb, htons(ETH_P_TIPC)); | 225 | skb_set_inner_protocol(skb, htons(ETH_P_TIPC)); |
216 | ub = rcu_dereference_rtnl(b->media_ptr); | 226 | ub = rcu_dereference_rtnl(b->media_ptr); |
217 | if (!ub) { | 227 | if (!ub) { |
218 | err = -ENODEV; | 228 | err = -ENODEV; |
219 | goto tx_error; | 229 | goto out; |
220 | } | 230 | } |
221 | 231 | ||
222 | return tipc_udp_xmit(net, skb, ub, src, dst); | 232 | if (!addr->broadcast || list_empty(&ub->rcast.list)) |
233 | return tipc_udp_xmit(net, skb, ub, src, dst); | ||
223 | 234 | ||
224 | tx_error: | 235 | /* Replicast, send an skb to each configured IP address */ |
236 | list_for_each_entry_rcu(rcast, &ub->rcast.list, list) { | ||
237 | struct sk_buff *_skb; | ||
238 | |||
239 | _skb = pskb_copy(skb, GFP_ATOMIC); | ||
240 | if (!_skb) { | ||
241 | err = -ENOMEM; | ||
242 | goto out; | ||
243 | } | ||
244 | |||
245 | err = tipc_udp_xmit(net, _skb, ub, src, &rcast->addr); | ||
246 | if (err) { | ||
247 | kfree_skb(_skb); | ||
248 | goto out; | ||
249 | } | ||
250 | } | ||
251 | err = 0; | ||
252 | out: | ||
225 | kfree_skb(skb); | 253 | kfree_skb(skb); |
226 | return err; | 254 | return err; |
227 | } | 255 | } |
228 | 256 | ||
257 | static int tipc_udp_rcast_add(struct tipc_bearer *b, | ||
258 | struct udp_media_addr *addr) | ||
259 | { | ||
260 | struct udp_replicast *rcast; | ||
261 | struct udp_bearer *ub; | ||
262 | |||
263 | ub = rcu_dereference_rtnl(b->media_ptr); | ||
264 | if (!ub) | ||
265 | return -ENODEV; | ||
266 | |||
267 | rcast = kmalloc(sizeof(*rcast), GFP_ATOMIC); | ||
268 | if (!rcast) | ||
269 | return -ENOMEM; | ||
270 | |||
271 | memcpy(&rcast->addr, addr, sizeof(struct udp_media_addr)); | ||
272 | |||
273 | if (ntohs(addr->proto) == ETH_P_IP) | ||
274 | pr_info("New replicast peer: %pI4\n", &rcast->addr.ipv4); | ||
275 | #if IS_ENABLED(CONFIG_IPV6) | ||
276 | else if (ntohs(addr->proto) == ETH_P_IPV6) | ||
277 | pr_info("New replicast peer: %pI6\n", &rcast->addr.ipv6); | ||
278 | #endif | ||
279 | |||
280 | list_add_rcu(&rcast->list, &ub->rcast.list); | ||
281 | return 0; | ||
282 | } | ||
283 | |||
229 | /* tipc_udp_recv - read data from bearer socket */ | 284 | /* tipc_udp_recv - read data from bearer socket */ |
230 | static int tipc_udp_recv(struct sock *sk, struct sk_buff *skb) | 285 | static int tipc_udp_recv(struct sock *sk, struct sk_buff *skb) |
231 | { | 286 | { |
@@ -320,6 +375,32 @@ static int tipc_parse_udp_addr(struct nlattr *nla, struct udp_media_addr *addr, | |||
320 | return -EADDRNOTAVAIL; | 375 | return -EADDRNOTAVAIL; |
321 | } | 376 | } |
322 | 377 | ||
378 | int tipc_udp_nl_bearer_add(struct tipc_bearer *b, struct nlattr *attr) | ||
379 | { | ||
380 | int err; | ||
381 | struct udp_media_addr addr = {0}; | ||
382 | struct nlattr *opts[TIPC_NLA_UDP_MAX + 1]; | ||
383 | struct udp_media_addr *dst; | ||
384 | |||
385 | if (nla_parse_nested(opts, TIPC_NLA_UDP_MAX, attr, tipc_nl_udp_policy)) | ||
386 | return -EINVAL; | ||
387 | |||
388 | if (!opts[TIPC_NLA_UDP_REMOTE]) | ||
389 | return -EINVAL; | ||
390 | |||
391 | err = tipc_parse_udp_addr(opts[TIPC_NLA_UDP_REMOTE], &addr, NULL); | ||
392 | if (err) | ||
393 | return err; | ||
394 | |||
395 | dst = (struct udp_media_addr *)&b->bcast_addr.value; | ||
396 | if (tipc_udp_is_mcast_addr(dst)) { | ||
397 | pr_err("Can't add remote ip to TIPC UDP multicast bearer\n"); | ||
398 | return -EINVAL; | ||
399 | } | ||
400 | |||
401 | return tipc_udp_rcast_add(b, &addr); | ||
402 | } | ||
403 | |||
323 | /** | 404 | /** |
324 | * tipc_udp_enable - callback to create a new udp bearer instance | 405 | * tipc_udp_enable - callback to create a new udp bearer instance |
325 | * @net: network namespace | 406 | * @net: network namespace |
@@ -334,7 +415,7 @@ static int tipc_udp_enable(struct net *net, struct tipc_bearer *b, | |||
334 | { | 415 | { |
335 | int err = -EINVAL; | 416 | int err = -EINVAL; |
336 | struct udp_bearer *ub; | 417 | struct udp_bearer *ub; |
337 | struct udp_media_addr *remote; | 418 | struct udp_media_addr remote = {0}; |
338 | struct udp_media_addr local = {0}; | 419 | struct udp_media_addr local = {0}; |
339 | struct udp_port_cfg udp_conf = {0}; | 420 | struct udp_port_cfg udp_conf = {0}; |
340 | struct udp_tunnel_sock_cfg tuncfg = {NULL}; | 421 | struct udp_tunnel_sock_cfg tuncfg = {NULL}; |
@@ -344,6 +425,8 @@ static int tipc_udp_enable(struct net *net, struct tipc_bearer *b, | |||
344 | if (!ub) | 425 | if (!ub) |
345 | return -ENOMEM; | 426 | return -ENOMEM; |
346 | 427 | ||
428 | INIT_LIST_HEAD(&ub->rcast.list); | ||
429 | |||
347 | if (!attrs[TIPC_NLA_BEARER_UDP_OPTS]) | 430 | if (!attrs[TIPC_NLA_BEARER_UDP_OPTS]) |
348 | goto err; | 431 | goto err; |
349 | 432 | ||
@@ -362,9 +445,7 @@ static int tipc_udp_enable(struct net *net, struct tipc_bearer *b, | |||
362 | if (err) | 445 | if (err) |
363 | goto err; | 446 | goto err; |
364 | 447 | ||
365 | remote = (struct udp_media_addr *)&b->bcast_addr.value; | 448 | err = tipc_parse_udp_addr(opts[TIPC_NLA_UDP_REMOTE], &remote, NULL); |
366 | memset(remote, 0, sizeof(struct udp_media_addr)); | ||
367 | err = tipc_parse_udp_addr(opts[TIPC_NLA_UDP_REMOTE], remote, NULL); | ||
368 | if (err) | 449 | if (err) |
369 | goto err; | 450 | goto err; |
370 | 451 | ||
@@ -409,10 +490,17 @@ static int tipc_udp_enable(struct net *net, struct tipc_bearer *b, | |||
409 | tuncfg.encap_destroy = NULL; | 490 | tuncfg.encap_destroy = NULL; |
410 | setup_udp_tunnel_sock(net, ub->ubsock, &tuncfg); | 491 | setup_udp_tunnel_sock(net, ub->ubsock, &tuncfg); |
411 | 492 | ||
412 | if (tipc_udp_is_mcast_addr(remote)) { | 493 | /** |
413 | if (enable_mcast(ub, remote)) | 494 | * The bcast media address port is used for all peers and the ip |
414 | goto err; | 495 | * is used if it's a multicast address. |
415 | } | 496 | */ |
497 | memcpy(&b->bcast_addr.value, &remote, sizeof(remote)); | ||
498 | if (tipc_udp_is_mcast_addr(&remote)) | ||
499 | err = enable_mcast(ub, &remote); | ||
500 | else | ||
501 | err = tipc_udp_rcast_add(b, &remote); | ||
502 | if (err) | ||
503 | goto err; | ||
416 | 504 | ||
417 | return 0; | 505 | return 0; |
418 | err: | 506 | err: |
@@ -424,6 +512,12 @@ err: | |||
424 | static void cleanup_bearer(struct work_struct *work) | 512 | static void cleanup_bearer(struct work_struct *work) |
425 | { | 513 | { |
426 | struct udp_bearer *ub = container_of(work, struct udp_bearer, work); | 514 | struct udp_bearer *ub = container_of(work, struct udp_bearer, work); |
515 | struct udp_replicast *rcast, *tmp; | ||
516 | |||
517 | list_for_each_entry_safe(rcast, tmp, &ub->rcast.list, list) { | ||
518 | list_del_rcu(&rcast->list); | ||
519 | kfree_rcu(rcast, rcu); | ||
520 | } | ||
427 | 521 | ||
428 | if (ub->ubsock) | 522 | if (ub->ubsock) |
429 | udp_tunnel_sock_release(ub->ubsock); | 523 | udp_tunnel_sock_release(ub->ubsock); |
diff --git a/net/tipc/udp_media.h b/net/tipc/udp_media.h new file mode 100644 index 000000000000..4dcb54880aa6 --- /dev/null +++ b/net/tipc/udp_media.h | |||
@@ -0,0 +1,44 @@ | |||
1 | /* | ||
2 | * net/tipc/udp_media.h: Include file for UDP bearer media | ||
3 | * | ||
4 | * Copyright (c) 1996-2006, 2013-2016, Ericsson AB | ||
5 | * Copyright (c) 2005, 2010-2011, Wind River Systems | ||
6 | * All rights reserved. | ||
7 | * | ||
8 | * Redistribution and use in source and binary forms, with or without | ||
9 | * modification, are permitted provided that the following conditions are met: | ||
10 | * | ||
11 | * 1. Redistributions of source code must retain the above copyright | ||
12 | * notice, this list of conditions and the following disclaimer. | ||
13 | * 2. Redistributions in binary form must reproduce the above copyright | ||
14 | * notice, this list of conditions and the following disclaimer in the | ||
15 | * documentation and/or other materials provided with the distribution. | ||
16 | * 3. Neither the names of the copyright holders nor the names of its | ||
17 | * contributors may be used to endorse or promote products derived from | ||
18 | * this software without specific prior written permission. | ||
19 | * | ||
20 | * Alternatively, this software may be distributed under the terms of the | ||
21 | * GNU General Public License ("GPL") version 2 as published by the Free | ||
22 | * Software Foundation. | ||
23 | * | ||
24 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
25 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
27 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
28 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
29 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
30 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||
31 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||
32 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
33 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
34 | * POSSIBILITY OF SUCH DAMAGE. | ||
35 | */ | ||
36 | |||
37 | #ifdef CONFIG_TIPC_MEDIA_UDP | ||
38 | #ifndef _TIPC_UDP_MEDIA_H | ||
39 | #define _TIPC_UDP_MEDIA_H | ||
40 | |||
41 | int tipc_udp_nl_bearer_add(struct tipc_bearer *b, struct nlattr *attr); | ||
42 | |||
43 | #endif | ||
44 | #endif | ||