diff options
Diffstat (limited to 'net/tipc/udp_media.c')
-rw-r--r-- | net/tipc/udp_media.c | 118 |
1 files changed, 106 insertions, 12 deletions
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); |