1 | /* net/tipc/udp_media.c: IP bearer support for TIPC |
2 | * |
3 | * Copyright (c) 2015, Ericsson AB |
4 | * All rights reserved. |
5 | * |
6 | * Redistribution and use in source and binary forms, with or without |
7 | * modification, are permitted provided that the following conditions are met: |
8 | * |
9 | * 1. Redistributions of source code must retain the above copyright |
10 | * notice, this list of conditions and the following disclaimer. |
11 | * 2. Redistributions in binary form must reproduce the above copyright |
12 | * notice, this list of conditions and the following disclaimer in the |
13 | * documentation and/or other materials provided with the distribution. |
14 | * 3. Neither the names of the copyright holders nor the names of its |
15 | * contributors may be used to endorse or promote products derived from |
16 | * this software without specific prior written permission. |
17 | * |
18 | * Alternatively, this software may be distributed under the terms of the |
19 | * GNU General Public License ("GPL") version 2 as published by the Free |
20 | * Software Foundation. |
21 | * |
22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
23 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
26 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
29 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
30 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
31 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
32 | * POSSIBILITY OF SUCH DAMAGE. |
33 | */ |
34 | |
35 | #include <linux/socket.h> |
36 | #include <linux/ip.h> |
37 | #include <linux/udp.h> |
38 | #include <linux/inet.h> |
39 | #include <linux/inetdevice.h> |
40 | #include <linux/igmp.h> |
41 | #include <linux/kernel.h> |
42 | #include <linux/workqueue.h> |
43 | #include <linux/list.h> |
44 | #include <net/sock.h> |
45 | #include <net/ip.h> |
46 | #include <net/udp_tunnel.h> |
47 | #include <net/ipv6_stubs.h> |
48 | #include <linux/tipc_netlink.h> |
49 | #include "core.h" |
50 | #include "addr.h" |
51 | #include "net.h" |
52 | #include "bearer.h" |
53 | #include "netlink.h" |
54 | #include "msg.h" |
55 | #include "udp_media.h" |
56 | |
57 | /* IANA assigned UDP port */ |
58 | #define UDP_PORT_DEFAULT 6118 |
59 | |
60 | #define UDP_MIN_HEADROOM 48 |
61 | |
62 | /** |
63 | * struct udp_media_addr - IP/UDP addressing information |
64 | * |
65 | * This is the bearer level originating address used in neighbor discovery |
66 | * messages, and all fields should be in network byte order |
67 | * |
68 | * @proto: Ethernet protocol in use |
69 | * @port: port being used |
70 | * @ipv4: IPv4 address of neighbor |
71 | * @ipv6: IPv6 address of neighbor |
72 | */ |
73 | struct udp_media_addr { |
74 | __be16 proto; |
75 | __be16 port; |
76 | union { |
77 | struct in_addr ipv4; |
78 | struct in6_addr ipv6; |
79 | }; |
80 | }; |
81 | |
82 | /* struct udp_replicast - container for UDP remote addresses */ |
83 | struct udp_replicast { |
84 | struct udp_media_addr addr; |
85 | struct dst_cache dst_cache; |
86 | struct rcu_head rcu; |
87 | struct list_head list; |
88 | }; |
89 | |
90 | /** |
91 | * struct udp_bearer - ip/udp bearer data structure |
92 | * @bearer: associated generic tipc bearer |
93 | * @ubsock: bearer associated socket |
94 | * @ifindex: local address scope |
95 | * @work: used to schedule deferred work on a bearer |
96 | * @rcast: associated udp_replicast container |
97 | */ |
98 | struct udp_bearer { |
99 | struct tipc_bearer __rcu *bearer; |
100 | struct socket *ubsock; |
101 | u32 ifindex; |
102 | struct work_struct work; |
103 | struct udp_replicast rcast; |
104 | }; |
105 | |
106 | static int tipc_udp_is_mcast_addr(struct udp_media_addr *addr) |
107 | { |
108 | if (ntohs(addr->proto) == ETH_P_IP) |
109 | return ipv4_is_multicast(addr: addr->ipv4.s_addr); |
110 | #if IS_ENABLED(CONFIG_IPV6) |
111 | else |
112 | return ipv6_addr_is_multicast(addr: &addr->ipv6); |
113 | #endif |
114 | return 0; |
115 | } |
116 | |
117 | /* udp_media_addr_set - convert a ip/udp address to a TIPC media address */ |
118 | static void tipc_udp_media_addr_set(struct tipc_media_addr *addr, |
119 | struct udp_media_addr *ua) |
120 | { |
121 | memset(addr, 0, sizeof(struct tipc_media_addr)); |
122 | addr->media_id = TIPC_MEDIA_TYPE_UDP; |
123 | memcpy(addr->value, ua, sizeof(struct udp_media_addr)); |
124 | |
125 | if (tipc_udp_is_mcast_addr(addr: ua)) |
126 | addr->broadcast = TIPC_BROADCAST_SUPPORT; |
127 | } |
128 | |
129 | /* tipc_udp_addr2str - convert ip/udp address to string */ |
130 | static int tipc_udp_addr2str(struct tipc_media_addr *a, char *buf, int size) |
131 | { |
132 | struct udp_media_addr *ua = (struct udp_media_addr *)&a->value; |
133 | |
134 | if (ntohs(ua->proto) == ETH_P_IP) |
135 | snprintf(buf, size, fmt: "%pI4:%u" , &ua->ipv4, ntohs(ua->port)); |
136 | else if (ntohs(ua->proto) == ETH_P_IPV6) |
137 | snprintf(buf, size, fmt: "%pI6:%u" , &ua->ipv6, ntohs(ua->port)); |
138 | else |
139 | pr_err("Invalid UDP media address\n" ); |
140 | return 0; |
141 | } |
142 | |
143 | /* tipc_udp_msg2addr - extract an ip/udp address from a TIPC ndisc message */ |
144 | static int tipc_udp_msg2addr(struct tipc_bearer *b, struct tipc_media_addr *a, |
145 | char *msg) |
146 | { |
147 | struct udp_media_addr *ua; |
148 | |
149 | ua = (struct udp_media_addr *) (msg + TIPC_MEDIA_ADDR_OFFSET); |
150 | if (msg[TIPC_MEDIA_TYPE_OFFSET] != TIPC_MEDIA_TYPE_UDP) |
151 | return -EINVAL; |
152 | tipc_udp_media_addr_set(addr: a, ua); |
153 | return 0; |
154 | } |
155 | |
156 | /* tipc_udp_addr2msg - write an ip/udp address to a TIPC ndisc message */ |
157 | static int tipc_udp_addr2msg(char *msg, struct tipc_media_addr *a) |
158 | { |
159 | memset(msg, 0, TIPC_MEDIA_INFO_SIZE); |
160 | msg[TIPC_MEDIA_TYPE_OFFSET] = TIPC_MEDIA_TYPE_UDP; |
161 | memcpy(msg + TIPC_MEDIA_ADDR_OFFSET, a->value, |
162 | sizeof(struct udp_media_addr)); |
163 | return 0; |
164 | } |
165 | |
166 | /* tipc_send_msg - enqueue a send request */ |
167 | static int tipc_udp_xmit(struct net *net, struct sk_buff *skb, |
168 | struct udp_bearer *ub, struct udp_media_addr *src, |
169 | struct udp_media_addr *dst, struct dst_cache *cache) |
170 | { |
171 | struct dst_entry *ndst; |
172 | int ttl, err = 0; |
173 | |
174 | local_bh_disable(); |
175 | ndst = dst_cache_get(dst_cache: cache); |
176 | if (dst->proto == htons(ETH_P_IP)) { |
177 | struct rtable *rt = (struct rtable *)ndst; |
178 | |
179 | if (!rt) { |
180 | struct flowi4 fl = { |
181 | .daddr = dst->ipv4.s_addr, |
182 | .saddr = src->ipv4.s_addr, |
183 | .flowi4_mark = skb->mark, |
184 | .flowi4_proto = IPPROTO_UDP |
185 | }; |
186 | rt = ip_route_output_key(net, flp: &fl); |
187 | if (IS_ERR(ptr: rt)) { |
188 | err = PTR_ERR(ptr: rt); |
189 | goto tx_error; |
190 | } |
191 | dst_cache_set_ip4(dst_cache: cache, dst: &rt->dst, saddr: fl.saddr); |
192 | } |
193 | |
194 | ttl = ip4_dst_hoplimit(dst: &rt->dst); |
195 | udp_tunnel_xmit_skb(rt, sk: ub->ubsock->sk, skb, src: src->ipv4.s_addr, |
196 | dst: dst->ipv4.s_addr, tos: 0, ttl, df: 0, src_port: src->port, |
197 | dst_port: dst->port, xnet: false, nocheck: true); |
198 | #if IS_ENABLED(CONFIG_IPV6) |
199 | } else { |
200 | if (!ndst) { |
201 | struct flowi6 fl6 = { |
202 | .flowi6_oif = ub->ifindex, |
203 | .daddr = dst->ipv6, |
204 | .saddr = src->ipv6, |
205 | .flowi6_proto = IPPROTO_UDP |
206 | }; |
207 | ndst = ipv6_stub->ipv6_dst_lookup_flow(net, |
208 | ub->ubsock->sk, |
209 | &fl6, NULL); |
210 | if (IS_ERR(ptr: ndst)) { |
211 | err = PTR_ERR(ptr: ndst); |
212 | goto tx_error; |
213 | } |
214 | dst_cache_set_ip6(dst_cache: cache, dst: ndst, saddr: &fl6.saddr); |
215 | } |
216 | ttl = ip6_dst_hoplimit(dst: ndst); |
217 | err = udp_tunnel6_xmit_skb(dst: ndst, sk: ub->ubsock->sk, skb, NULL, |
218 | saddr: &src->ipv6, daddr: &dst->ipv6, prio: 0, ttl, label: 0, |
219 | src_port: src->port, dst_port: dst->port, nocheck: false); |
220 | #endif |
221 | } |
222 | local_bh_enable(); |
223 | return err; |
224 | |
225 | tx_error: |
226 | local_bh_enable(); |
227 | kfree_skb(skb); |
228 | return err; |
229 | } |
230 | |
231 | static int tipc_udp_send_msg(struct net *net, struct sk_buff *skb, |
232 | struct tipc_bearer *b, |
233 | struct tipc_media_addr *addr) |
234 | { |
235 | struct udp_media_addr *src = (struct udp_media_addr *)&b->addr.value; |
236 | struct udp_media_addr *dst = (struct udp_media_addr *)&addr->value; |
237 | struct udp_replicast *rcast; |
238 | struct udp_bearer *ub; |
239 | int err = 0; |
240 | |
241 | if (skb_headroom(skb) < UDP_MIN_HEADROOM) { |
242 | err = pskb_expand_head(skb, UDP_MIN_HEADROOM, ntail: 0, GFP_ATOMIC); |
243 | if (err) |
244 | goto out; |
245 | } |
246 | |
247 | skb_set_inner_protocol(skb, htons(ETH_P_TIPC)); |
248 | ub = rcu_dereference(b->media_ptr); |
249 | if (!ub) { |
250 | err = -ENODEV; |
251 | goto out; |
252 | } |
253 | |
254 | if (addr->broadcast != TIPC_REPLICAST_SUPPORT) |
255 | return tipc_udp_xmit(net, skb, ub, src, dst, |
256 | cache: &ub->rcast.dst_cache); |
257 | |
258 | /* Replicast, send an skb to each configured IP address */ |
259 | list_for_each_entry_rcu(rcast, &ub->rcast.list, list) { |
260 | struct sk_buff *_skb; |
261 | |
262 | _skb = pskb_copy(skb, GFP_ATOMIC); |
263 | if (!_skb) { |
264 | err = -ENOMEM; |
265 | goto out; |
266 | } |
267 | |
268 | err = tipc_udp_xmit(net, skb: _skb, ub, src, dst: &rcast->addr, |
269 | cache: &rcast->dst_cache); |
270 | if (err) |
271 | goto out; |
272 | } |
273 | err = 0; |
274 | out: |
275 | kfree_skb(skb); |
276 | return err; |
277 | } |
278 | |
279 | static bool tipc_udp_is_known_peer(struct tipc_bearer *b, |
280 | struct udp_media_addr *addr) |
281 | { |
282 | struct udp_replicast *rcast, *tmp; |
283 | struct udp_bearer *ub; |
284 | |
285 | ub = rcu_dereference_rtnl(b->media_ptr); |
286 | if (!ub) { |
287 | pr_err_ratelimited("UDP bearer instance not found\n" ); |
288 | return false; |
289 | } |
290 | |
291 | list_for_each_entry_safe(rcast, tmp, &ub->rcast.list, list) { |
292 | if (!memcmp(p: &rcast->addr, q: addr, size: sizeof(struct udp_media_addr))) |
293 | return true; |
294 | } |
295 | |
296 | return false; |
297 | } |
298 | |
299 | static int tipc_udp_rcast_add(struct tipc_bearer *b, |
300 | struct udp_media_addr *addr) |
301 | { |
302 | struct udp_replicast *rcast; |
303 | struct udp_bearer *ub; |
304 | |
305 | ub = rcu_dereference_rtnl(b->media_ptr); |
306 | if (!ub) |
307 | return -ENODEV; |
308 | |
309 | rcast = kmalloc(size: sizeof(*rcast), GFP_ATOMIC); |
310 | if (!rcast) |
311 | return -ENOMEM; |
312 | |
313 | if (dst_cache_init(dst_cache: &rcast->dst_cache, GFP_ATOMIC)) { |
314 | kfree(objp: rcast); |
315 | return -ENOMEM; |
316 | } |
317 | |
318 | memcpy(&rcast->addr, addr, sizeof(struct udp_media_addr)); |
319 | |
320 | if (ntohs(addr->proto) == ETH_P_IP) |
321 | pr_info("New replicast peer: %pI4\n" , &rcast->addr.ipv4); |
322 | #if IS_ENABLED(CONFIG_IPV6) |
323 | else if (ntohs(addr->proto) == ETH_P_IPV6) |
324 | pr_info("New replicast peer: %pI6\n" , &rcast->addr.ipv6); |
325 | #endif |
326 | b->bcast_addr.broadcast = TIPC_REPLICAST_SUPPORT; |
327 | list_add_rcu(new: &rcast->list, head: &ub->rcast.list); |
328 | return 0; |
329 | } |
330 | |
331 | static int tipc_udp_rcast_disc(struct tipc_bearer *b, struct sk_buff *skb) |
332 | { |
333 | struct udp_media_addr src = {0}; |
334 | struct udp_media_addr *dst; |
335 | |
336 | dst = (struct udp_media_addr *)&b->bcast_addr.value; |
337 | if (tipc_udp_is_mcast_addr(addr: dst)) |
338 | return 0; |
339 | |
340 | src.port = udp_hdr(skb)->source; |
341 | |
342 | if (ip_hdr(skb)->version == 4) { |
343 | struct iphdr *iphdr = ip_hdr(skb); |
344 | |
345 | src.proto = htons(ETH_P_IP); |
346 | src.ipv4.s_addr = iphdr->saddr; |
347 | if (ipv4_is_multicast(addr: iphdr->daddr)) |
348 | return 0; |
349 | #if IS_ENABLED(CONFIG_IPV6) |
350 | } else if (ip_hdr(skb)->version == 6) { |
351 | struct ipv6hdr *iphdr = ipv6_hdr(skb); |
352 | |
353 | src.proto = htons(ETH_P_IPV6); |
354 | src.ipv6 = iphdr->saddr; |
355 | if (ipv6_addr_is_multicast(addr: &iphdr->daddr)) |
356 | return 0; |
357 | #endif |
358 | } else { |
359 | return 0; |
360 | } |
361 | |
362 | if (likely(tipc_udp_is_known_peer(b, &src))) |
363 | return 0; |
364 | |
365 | return tipc_udp_rcast_add(b, addr: &src); |
366 | } |
367 | |
368 | /* tipc_udp_recv - read data from bearer socket */ |
369 | static int tipc_udp_recv(struct sock *sk, struct sk_buff *skb) |
370 | { |
371 | struct udp_bearer *ub; |
372 | struct tipc_bearer *b; |
373 | struct tipc_msg *hdr; |
374 | int err; |
375 | |
376 | ub = rcu_dereference_sk_user_data(sk); |
377 | if (!ub) { |
378 | pr_err_ratelimited("Failed to get UDP bearer reference" ); |
379 | goto out; |
380 | } |
381 | skb_pull(skb, len: sizeof(struct udphdr)); |
382 | hdr = buf_msg(skb); |
383 | |
384 | b = rcu_dereference(ub->bearer); |
385 | if (!b) |
386 | goto out; |
387 | |
388 | if (b && test_bit(0, &b->up)) { |
389 | TIPC_SKB_CB(skb)->flags = 0; |
390 | tipc_rcv(net: sock_net(sk), skb, b); |
391 | return 0; |
392 | } |
393 | |
394 | if (unlikely(msg_user(hdr) == LINK_CONFIG)) { |
395 | err = tipc_udp_rcast_disc(b, skb); |
396 | if (err) |
397 | goto out; |
398 | } |
399 | |
400 | out: |
401 | kfree_skb(skb); |
402 | return 0; |
403 | } |
404 | |
405 | static int enable_mcast(struct udp_bearer *ub, struct udp_media_addr *remote) |
406 | { |
407 | int err = 0; |
408 | struct ip_mreqn mreqn; |
409 | struct sock *sk = ub->ubsock->sk; |
410 | |
411 | if (ntohs(remote->proto) == ETH_P_IP) { |
412 | mreqn.imr_multiaddr = remote->ipv4; |
413 | mreqn.imr_ifindex = ub->ifindex; |
414 | err = ip_mc_join_group(sk, imr: &mreqn); |
415 | #if IS_ENABLED(CONFIG_IPV6) |
416 | } else { |
417 | lock_sock(sk); |
418 | err = ipv6_stub->ipv6_sock_mc_join(sk, ub->ifindex, |
419 | &remote->ipv6); |
420 | release_sock(sk); |
421 | #endif |
422 | } |
423 | return err; |
424 | } |
425 | |
426 | static int __tipc_nl_add_udp_addr(struct sk_buff *skb, |
427 | struct udp_media_addr *addr, int nla_t) |
428 | { |
429 | if (ntohs(addr->proto) == ETH_P_IP) { |
430 | struct sockaddr_in ip4; |
431 | |
432 | memset(&ip4, 0, sizeof(ip4)); |
433 | ip4.sin_family = AF_INET; |
434 | ip4.sin_port = addr->port; |
435 | ip4.sin_addr.s_addr = addr->ipv4.s_addr; |
436 | if (nla_put(skb, attrtype: nla_t, attrlen: sizeof(ip4), data: &ip4)) |
437 | return -EMSGSIZE; |
438 | |
439 | #if IS_ENABLED(CONFIG_IPV6) |
440 | } else if (ntohs(addr->proto) == ETH_P_IPV6) { |
441 | struct sockaddr_in6 ip6; |
442 | |
443 | memset(&ip6, 0, sizeof(ip6)); |
444 | ip6.sin6_family = AF_INET6; |
445 | ip6.sin6_port = addr->port; |
446 | memcpy(&ip6.sin6_addr, &addr->ipv6, sizeof(struct in6_addr)); |
447 | if (nla_put(skb, attrtype: nla_t, attrlen: sizeof(ip6), data: &ip6)) |
448 | return -EMSGSIZE; |
449 | #endif |
450 | } |
451 | |
452 | return 0; |
453 | } |
454 | |
455 | int tipc_udp_nl_dump_remoteip(struct sk_buff *skb, struct netlink_callback *cb) |
456 | { |
457 | u32 bid = cb->args[0]; |
458 | u32 skip_cnt = cb->args[1]; |
459 | u32 portid = NETLINK_CB(cb->skb).portid; |
460 | struct udp_replicast *rcast, *tmp; |
461 | struct tipc_bearer *b; |
462 | struct udp_bearer *ub; |
463 | void *hdr; |
464 | int err; |
465 | int i; |
466 | |
467 | if (!bid && !skip_cnt) { |
468 | struct nlattr **attrs = genl_dumpit_info(cb)->info.attrs; |
469 | struct net *net = sock_net(sk: skb->sk); |
470 | struct nlattr *battrs[TIPC_NLA_BEARER_MAX + 1]; |
471 | char *bname; |
472 | |
473 | if (!attrs[TIPC_NLA_BEARER]) |
474 | return -EINVAL; |
475 | |
476 | err = nla_parse_nested_deprecated(tb: battrs, maxtype: TIPC_NLA_BEARER_MAX, |
477 | nla: attrs[TIPC_NLA_BEARER], |
478 | policy: tipc_nl_bearer_policy, NULL); |
479 | if (err) |
480 | return err; |
481 | |
482 | if (!battrs[TIPC_NLA_BEARER_NAME]) |
483 | return -EINVAL; |
484 | |
485 | bname = nla_data(nla: battrs[TIPC_NLA_BEARER_NAME]); |
486 | |
487 | rtnl_lock(); |
488 | b = tipc_bearer_find(net, name: bname); |
489 | if (!b) { |
490 | rtnl_unlock(); |
491 | return -EINVAL; |
492 | } |
493 | bid = b->identity; |
494 | } else { |
495 | struct net *net = sock_net(sk: skb->sk); |
496 | struct tipc_net *tn = net_generic(net, id: tipc_net_id); |
497 | |
498 | rtnl_lock(); |
499 | b = rtnl_dereference(tn->bearer_list[bid]); |
500 | if (!b) { |
501 | rtnl_unlock(); |
502 | return -EINVAL; |
503 | } |
504 | } |
505 | |
506 | ub = rtnl_dereference(b->media_ptr); |
507 | if (!ub) { |
508 | rtnl_unlock(); |
509 | return -EINVAL; |
510 | } |
511 | |
512 | i = 0; |
513 | list_for_each_entry_safe(rcast, tmp, &ub->rcast.list, list) { |
514 | if (i < skip_cnt) |
515 | goto count; |
516 | |
517 | hdr = genlmsg_put(skb, portid, seq: cb->nlh->nlmsg_seq, |
518 | family: &tipc_genl_family, NLM_F_MULTI, |
519 | cmd: TIPC_NL_BEARER_GET); |
520 | if (!hdr) |
521 | goto done; |
522 | |
523 | err = __tipc_nl_add_udp_addr(skb, addr: &rcast->addr, |
524 | nla_t: TIPC_NLA_UDP_REMOTE); |
525 | if (err) { |
526 | genlmsg_cancel(skb, hdr); |
527 | goto done; |
528 | } |
529 | genlmsg_end(skb, hdr); |
530 | count: |
531 | i++; |
532 | } |
533 | done: |
534 | rtnl_unlock(); |
535 | cb->args[0] = bid; |
536 | cb->args[1] = i; |
537 | |
538 | return skb->len; |
539 | } |
540 | |
541 | int tipc_udp_nl_add_bearer_data(struct tipc_nl_msg *msg, struct tipc_bearer *b) |
542 | { |
543 | struct udp_media_addr *src = (struct udp_media_addr *)&b->addr.value; |
544 | struct udp_media_addr *dst; |
545 | struct udp_bearer *ub; |
546 | struct nlattr *nest; |
547 | |
548 | ub = rtnl_dereference(b->media_ptr); |
549 | if (!ub) |
550 | return -ENODEV; |
551 | |
552 | nest = nla_nest_start_noflag(skb: msg->skb, attrtype: TIPC_NLA_BEARER_UDP_OPTS); |
553 | if (!nest) |
554 | goto msg_full; |
555 | |
556 | if (__tipc_nl_add_udp_addr(skb: msg->skb, addr: src, nla_t: TIPC_NLA_UDP_LOCAL)) |
557 | goto msg_full; |
558 | |
559 | dst = (struct udp_media_addr *)&b->bcast_addr.value; |
560 | if (__tipc_nl_add_udp_addr(skb: msg->skb, addr: dst, nla_t: TIPC_NLA_UDP_REMOTE)) |
561 | goto msg_full; |
562 | |
563 | if (!list_empty(head: &ub->rcast.list)) { |
564 | if (nla_put_flag(skb: msg->skb, attrtype: TIPC_NLA_UDP_MULTI_REMOTEIP)) |
565 | goto msg_full; |
566 | } |
567 | |
568 | nla_nest_end(skb: msg->skb, start: nest); |
569 | return 0; |
570 | msg_full: |
571 | nla_nest_cancel(skb: msg->skb, start: nest); |
572 | return -EMSGSIZE; |
573 | } |
574 | |
575 | /** |
576 | * tipc_parse_udp_addr - build udp media address from netlink data |
577 | * @nla: netlink attribute containing sockaddr storage aligned address |
578 | * @addr: tipc media address to fill with address, port and protocol type |
579 | * @scope_id: IPv6 scope id pointer, not NULL indicates it's required |
580 | */ |
581 | |
582 | static int tipc_parse_udp_addr(struct nlattr *nla, struct udp_media_addr *addr, |
583 | u32 *scope_id) |
584 | { |
585 | struct sockaddr_storage sa; |
586 | |
587 | nla_memcpy(dest: &sa, src: nla, count: sizeof(sa)); |
588 | if (sa.ss_family == AF_INET) { |
589 | struct sockaddr_in *ip4 = (struct sockaddr_in *)&sa; |
590 | |
591 | addr->proto = htons(ETH_P_IP); |
592 | addr->port = ip4->sin_port; |
593 | addr->ipv4.s_addr = ip4->sin_addr.s_addr; |
594 | return 0; |
595 | |
596 | #if IS_ENABLED(CONFIG_IPV6) |
597 | } else if (sa.ss_family == AF_INET6) { |
598 | struct sockaddr_in6 *ip6 = (struct sockaddr_in6 *)&sa; |
599 | |
600 | addr->proto = htons(ETH_P_IPV6); |
601 | addr->port = ip6->sin6_port; |
602 | memcpy(&addr->ipv6, &ip6->sin6_addr, sizeof(struct in6_addr)); |
603 | |
604 | /* Scope ID is only interesting for local addresses */ |
605 | if (scope_id) { |
606 | int atype; |
607 | |
608 | atype = ipv6_addr_type(addr: &ip6->sin6_addr); |
609 | if (__ipv6_addr_needs_scope_id(type: atype) && |
610 | !ip6->sin6_scope_id) { |
611 | return -EINVAL; |
612 | } |
613 | |
614 | *scope_id = ip6->sin6_scope_id ? : 0; |
615 | } |
616 | |
617 | return 0; |
618 | #endif |
619 | } |
620 | return -EADDRNOTAVAIL; |
621 | } |
622 | |
623 | int tipc_udp_nl_bearer_add(struct tipc_bearer *b, struct nlattr *attr) |
624 | { |
625 | int err; |
626 | struct udp_media_addr addr = {0}; |
627 | struct nlattr *opts[TIPC_NLA_UDP_MAX + 1]; |
628 | struct udp_media_addr *dst; |
629 | |
630 | if (nla_parse_nested_deprecated(tb: opts, maxtype: TIPC_NLA_UDP_MAX, nla: attr, policy: tipc_nl_udp_policy, NULL)) |
631 | return -EINVAL; |
632 | |
633 | if (!opts[TIPC_NLA_UDP_REMOTE]) |
634 | return -EINVAL; |
635 | |
636 | err = tipc_parse_udp_addr(nla: opts[TIPC_NLA_UDP_REMOTE], addr: &addr, NULL); |
637 | if (err) |
638 | return err; |
639 | |
640 | dst = (struct udp_media_addr *)&b->bcast_addr.value; |
641 | if (tipc_udp_is_mcast_addr(addr: dst)) { |
642 | pr_err("Can't add remote ip to TIPC UDP multicast bearer\n" ); |
643 | return -EINVAL; |
644 | } |
645 | |
646 | if (tipc_udp_is_known_peer(b, addr: &addr)) |
647 | return 0; |
648 | |
649 | return tipc_udp_rcast_add(b, addr: &addr); |
650 | } |
651 | |
652 | /** |
653 | * tipc_udp_enable - callback to create a new udp bearer instance |
654 | * @net: network namespace |
655 | * @b: pointer to generic tipc_bearer |
656 | * @attrs: netlink bearer configuration |
657 | * |
658 | * validate the bearer parameters and initialize the udp bearer |
659 | * rtnl_lock should be held |
660 | */ |
661 | static int tipc_udp_enable(struct net *net, struct tipc_bearer *b, |
662 | struct nlattr *attrs[]) |
663 | { |
664 | int err = -EINVAL; |
665 | struct udp_bearer *ub; |
666 | struct udp_media_addr remote = {0}; |
667 | struct udp_media_addr local = {0}; |
668 | struct udp_port_cfg udp_conf = {0}; |
669 | struct udp_tunnel_sock_cfg tuncfg = {NULL}; |
670 | struct nlattr *opts[TIPC_NLA_UDP_MAX + 1]; |
671 | u8 node_id[NODE_ID_LEN] = {0,}; |
672 | struct net_device *dev; |
673 | int rmcast = 0; |
674 | |
675 | ub = kzalloc(size: sizeof(*ub), GFP_ATOMIC); |
676 | if (!ub) |
677 | return -ENOMEM; |
678 | |
679 | INIT_LIST_HEAD(list: &ub->rcast.list); |
680 | |
681 | if (!attrs[TIPC_NLA_BEARER_UDP_OPTS]) |
682 | goto err; |
683 | |
684 | if (nla_parse_nested_deprecated(tb: opts, maxtype: TIPC_NLA_UDP_MAX, nla: attrs[TIPC_NLA_BEARER_UDP_OPTS], policy: tipc_nl_udp_policy, NULL)) |
685 | goto err; |
686 | |
687 | if (!opts[TIPC_NLA_UDP_LOCAL] || !opts[TIPC_NLA_UDP_REMOTE]) { |
688 | pr_err("Invalid UDP bearer configuration" ); |
689 | err = -EINVAL; |
690 | goto err; |
691 | } |
692 | |
693 | err = tipc_parse_udp_addr(nla: opts[TIPC_NLA_UDP_LOCAL], addr: &local, |
694 | scope_id: &ub->ifindex); |
695 | if (err) |
696 | goto err; |
697 | |
698 | err = tipc_parse_udp_addr(nla: opts[TIPC_NLA_UDP_REMOTE], addr: &remote, NULL); |
699 | if (err) |
700 | goto err; |
701 | |
702 | if (remote.proto != local.proto) { |
703 | err = -EINVAL; |
704 | goto err; |
705 | } |
706 | |
707 | /* Checking remote ip address */ |
708 | rmcast = tipc_udp_is_mcast_addr(addr: &remote); |
709 | |
710 | /* Autoconfigure own node identity if needed */ |
711 | if (!tipc_own_id(net)) { |
712 | memcpy(node_id, local.ipv6.in6_u.u6_addr8, 16); |
713 | tipc_net_init(net, node_id, addr: 0); |
714 | } |
715 | if (!tipc_own_id(net)) { |
716 | pr_warn("Failed to set node id, please configure manually\n" ); |
717 | err = -EINVAL; |
718 | goto err; |
719 | } |
720 | |
721 | b->bcast_addr.media_id = TIPC_MEDIA_TYPE_UDP; |
722 | b->bcast_addr.broadcast = TIPC_BROADCAST_SUPPORT; |
723 | rcu_assign_pointer(b->media_ptr, ub); |
724 | rcu_assign_pointer(ub->bearer, b); |
725 | tipc_udp_media_addr_set(addr: &b->addr, ua: &local); |
726 | if (local.proto == htons(ETH_P_IP)) { |
727 | dev = __ip_dev_find(net, addr: local.ipv4.s_addr, devref: false); |
728 | if (!dev) { |
729 | err = -ENODEV; |
730 | goto err; |
731 | } |
732 | udp_conf.family = AF_INET; |
733 | |
734 | /* Switch to use ANY to receive packets from group */ |
735 | if (rmcast) |
736 | udp_conf.local_ip.s_addr = htonl(INADDR_ANY); |
737 | else |
738 | udp_conf.local_ip.s_addr = local.ipv4.s_addr; |
739 | udp_conf.use_udp_checksums = false; |
740 | ub->ifindex = dev->ifindex; |
741 | b->encap_hlen = sizeof(struct iphdr) + sizeof(struct udphdr); |
742 | b->mtu = b->media->mtu; |
743 | #if IS_ENABLED(CONFIG_IPV6) |
744 | } else if (local.proto == htons(ETH_P_IPV6)) { |
745 | dev = ub->ifindex ? __dev_get_by_index(net, ifindex: ub->ifindex) : NULL; |
746 | dev = ipv6_dev_find(net, addr: &local.ipv6, dev); |
747 | if (!dev) { |
748 | err = -ENODEV; |
749 | goto err; |
750 | } |
751 | udp_conf.family = AF_INET6; |
752 | udp_conf.use_udp6_tx_checksums = true; |
753 | udp_conf.use_udp6_rx_checksums = true; |
754 | if (rmcast) |
755 | udp_conf.local_ip6 = in6addr_any; |
756 | else |
757 | udp_conf.local_ip6 = local.ipv6; |
758 | ub->ifindex = dev->ifindex; |
759 | b->encap_hlen = sizeof(struct ipv6hdr) + sizeof(struct udphdr); |
760 | b->mtu = 1280; |
761 | #endif |
762 | } else { |
763 | err = -EAFNOSUPPORT; |
764 | goto err; |
765 | } |
766 | udp_conf.local_udp_port = local.port; |
767 | err = udp_sock_create(net, cfg: &udp_conf, sockp: &ub->ubsock); |
768 | if (err) |
769 | goto err; |
770 | tuncfg.sk_user_data = ub; |
771 | tuncfg.encap_type = 1; |
772 | tuncfg.encap_rcv = tipc_udp_recv; |
773 | tuncfg.encap_destroy = NULL; |
774 | setup_udp_tunnel_sock(net, sock: ub->ubsock, sock_cfg: &tuncfg); |
775 | |
776 | err = dst_cache_init(dst_cache: &ub->rcast.dst_cache, GFP_ATOMIC); |
777 | if (err) |
778 | goto free; |
779 | |
780 | /* |
781 | * The bcast media address port is used for all peers and the ip |
782 | * is used if it's a multicast address. |
783 | */ |
784 | memcpy(&b->bcast_addr.value, &remote, sizeof(remote)); |
785 | if (rmcast) |
786 | err = enable_mcast(ub, remote: &remote); |
787 | else |
788 | err = tipc_udp_rcast_add(b, addr: &remote); |
789 | if (err) |
790 | goto free; |
791 | |
792 | return 0; |
793 | |
794 | free: |
795 | dst_cache_destroy(dst_cache: &ub->rcast.dst_cache); |
796 | udp_tunnel_sock_release(sock: ub->ubsock); |
797 | err: |
798 | kfree(objp: ub); |
799 | return err; |
800 | } |
801 | |
802 | /* cleanup_bearer - break the socket/bearer association */ |
803 | static void cleanup_bearer(struct work_struct *work) |
804 | { |
805 | struct udp_bearer *ub = container_of(work, struct udp_bearer, work); |
806 | struct udp_replicast *rcast, *tmp; |
807 | |
808 | list_for_each_entry_safe(rcast, tmp, &ub->rcast.list, list) { |
809 | dst_cache_destroy(dst_cache: &rcast->dst_cache); |
810 | list_del_rcu(entry: &rcast->list); |
811 | kfree_rcu(rcast, rcu); |
812 | } |
813 | |
814 | atomic_dec(v: &tipc_net(net: sock_net(sk: ub->ubsock->sk))->wq_count); |
815 | dst_cache_destroy(dst_cache: &ub->rcast.dst_cache); |
816 | udp_tunnel_sock_release(sock: ub->ubsock); |
817 | synchronize_net(); |
818 | kfree(objp: ub); |
819 | } |
820 | |
821 | /* tipc_udp_disable - detach bearer from socket */ |
822 | static void tipc_udp_disable(struct tipc_bearer *b) |
823 | { |
824 | struct udp_bearer *ub; |
825 | |
826 | ub = rtnl_dereference(b->media_ptr); |
827 | if (!ub) { |
828 | pr_err("UDP bearer instance not found\n" ); |
829 | return; |
830 | } |
831 | sock_set_flag(sk: ub->ubsock->sk, flag: SOCK_DEAD); |
832 | RCU_INIT_POINTER(ub->bearer, NULL); |
833 | |
834 | /* sock_release need to be done outside of rtnl lock */ |
835 | atomic_inc(v: &tipc_net(net: sock_net(sk: ub->ubsock->sk))->wq_count); |
836 | INIT_WORK(&ub->work, cleanup_bearer); |
837 | schedule_work(work: &ub->work); |
838 | } |
839 | |
840 | struct tipc_media udp_media_info = { |
841 | .send_msg = tipc_udp_send_msg, |
842 | .enable_media = tipc_udp_enable, |
843 | .disable_media = tipc_udp_disable, |
844 | .addr2str = tipc_udp_addr2str, |
845 | .addr2msg = tipc_udp_addr2msg, |
846 | .msg2addr = tipc_udp_msg2addr, |
847 | .priority = TIPC_DEF_LINK_PRI, |
848 | .tolerance = TIPC_DEF_LINK_TOL, |
849 | .min_win = TIPC_DEF_LINK_WIN, |
850 | .max_win = TIPC_DEF_LINK_WIN, |
851 | .mtu = TIPC_DEF_LINK_UDP_MTU, |
852 | .type_id = TIPC_MEDIA_TYPE_UDP, |
853 | .hwaddr_len = 0, |
854 | .name = "udp" |
855 | }; |
856 | |