18c2ecf20Sopenharmony_ci/* net/tipc/udp_media.c: IP bearer support for TIPC
28c2ecf20Sopenharmony_ci *
38c2ecf20Sopenharmony_ci * Copyright (c) 2015, Ericsson AB
48c2ecf20Sopenharmony_ci * All rights reserved.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without
78c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions are met:
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright
108c2ecf20Sopenharmony_ci *    notice, this list of conditions and the following disclaimer.
118c2ecf20Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright
128c2ecf20Sopenharmony_ci *    notice, this list of conditions and the following disclaimer in the
138c2ecf20Sopenharmony_ci *    documentation and/or other materials provided with the distribution.
148c2ecf20Sopenharmony_ci * 3. Neither the names of the copyright holders nor the names of its
158c2ecf20Sopenharmony_ci *    contributors may be used to endorse or promote products derived from
168c2ecf20Sopenharmony_ci *    this software without specific prior written permission.
178c2ecf20Sopenharmony_ci *
188c2ecf20Sopenharmony_ci * Alternatively, this software may be distributed under the terms of the
198c2ecf20Sopenharmony_ci * GNU General Public License ("GPL") version 2 as published by the Free
208c2ecf20Sopenharmony_ci * Software Foundation.
218c2ecf20Sopenharmony_ci *
228c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
238c2ecf20Sopenharmony_ci * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
248c2ecf20Sopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
258c2ecf20Sopenharmony_ci * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
268c2ecf20Sopenharmony_ci * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
278c2ecf20Sopenharmony_ci * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
288c2ecf20Sopenharmony_ci * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
298c2ecf20Sopenharmony_ci * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
308c2ecf20Sopenharmony_ci * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
318c2ecf20Sopenharmony_ci * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
328c2ecf20Sopenharmony_ci * POSSIBILITY OF SUCH DAMAGE.
338c2ecf20Sopenharmony_ci */
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci#include <linux/socket.h>
368c2ecf20Sopenharmony_ci#include <linux/ip.h>
378c2ecf20Sopenharmony_ci#include <linux/udp.h>
388c2ecf20Sopenharmony_ci#include <linux/inet.h>
398c2ecf20Sopenharmony_ci#include <linux/inetdevice.h>
408c2ecf20Sopenharmony_ci#include <linux/igmp.h>
418c2ecf20Sopenharmony_ci#include <linux/kernel.h>
428c2ecf20Sopenharmony_ci#include <linux/workqueue.h>
438c2ecf20Sopenharmony_ci#include <linux/list.h>
448c2ecf20Sopenharmony_ci#include <net/sock.h>
458c2ecf20Sopenharmony_ci#include <net/ip.h>
468c2ecf20Sopenharmony_ci#include <net/udp_tunnel.h>
478c2ecf20Sopenharmony_ci#include <net/ipv6_stubs.h>
488c2ecf20Sopenharmony_ci#include <linux/tipc_netlink.h>
498c2ecf20Sopenharmony_ci#include "core.h"
508c2ecf20Sopenharmony_ci#include "addr.h"
518c2ecf20Sopenharmony_ci#include "net.h"
528c2ecf20Sopenharmony_ci#include "bearer.h"
538c2ecf20Sopenharmony_ci#include "netlink.h"
548c2ecf20Sopenharmony_ci#include "msg.h"
558c2ecf20Sopenharmony_ci#include "udp_media.h"
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci/* IANA assigned UDP port */
588c2ecf20Sopenharmony_ci#define UDP_PORT_DEFAULT	6118
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci#define UDP_MIN_HEADROOM        48
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci/**
638c2ecf20Sopenharmony_ci * struct udp_media_addr - IP/UDP addressing information
648c2ecf20Sopenharmony_ci *
658c2ecf20Sopenharmony_ci * This is the bearer level originating address used in neighbor discovery
668c2ecf20Sopenharmony_ci * messages, and all fields should be in network byte order
678c2ecf20Sopenharmony_ci */
688c2ecf20Sopenharmony_cistruct udp_media_addr {
698c2ecf20Sopenharmony_ci	__be16	proto;
708c2ecf20Sopenharmony_ci	__be16	port;
718c2ecf20Sopenharmony_ci	union {
728c2ecf20Sopenharmony_ci		struct in_addr ipv4;
738c2ecf20Sopenharmony_ci		struct in6_addr ipv6;
748c2ecf20Sopenharmony_ci	};
758c2ecf20Sopenharmony_ci};
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci/* struct udp_replicast - container for UDP remote addresses */
788c2ecf20Sopenharmony_cistruct udp_replicast {
798c2ecf20Sopenharmony_ci	struct udp_media_addr addr;
808c2ecf20Sopenharmony_ci	struct dst_cache dst_cache;
818c2ecf20Sopenharmony_ci	struct rcu_head rcu;
828c2ecf20Sopenharmony_ci	struct list_head list;
838c2ecf20Sopenharmony_ci};
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci/**
868c2ecf20Sopenharmony_ci * struct udp_bearer - ip/udp bearer data structure
878c2ecf20Sopenharmony_ci * @bearer:	associated generic tipc bearer
888c2ecf20Sopenharmony_ci * @ubsock:	bearer associated socket
898c2ecf20Sopenharmony_ci * @ifindex:	local address scope
908c2ecf20Sopenharmony_ci * @work:	used to schedule deferred work on a bearer
918c2ecf20Sopenharmony_ci */
928c2ecf20Sopenharmony_cistruct udp_bearer {
938c2ecf20Sopenharmony_ci	struct tipc_bearer __rcu *bearer;
948c2ecf20Sopenharmony_ci	struct socket *ubsock;
958c2ecf20Sopenharmony_ci	u32 ifindex;
968c2ecf20Sopenharmony_ci	struct work_struct work;
978c2ecf20Sopenharmony_ci	struct udp_replicast rcast;
988c2ecf20Sopenharmony_ci};
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_cistatic int tipc_udp_is_mcast_addr(struct udp_media_addr *addr)
1018c2ecf20Sopenharmony_ci{
1028c2ecf20Sopenharmony_ci	if (ntohs(addr->proto) == ETH_P_IP)
1038c2ecf20Sopenharmony_ci		return ipv4_is_multicast(addr->ipv4.s_addr);
1048c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
1058c2ecf20Sopenharmony_ci	else
1068c2ecf20Sopenharmony_ci		return ipv6_addr_is_multicast(&addr->ipv6);
1078c2ecf20Sopenharmony_ci#endif
1088c2ecf20Sopenharmony_ci	return 0;
1098c2ecf20Sopenharmony_ci}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci/* udp_media_addr_set - convert a ip/udp address to a TIPC media address */
1128c2ecf20Sopenharmony_cistatic void tipc_udp_media_addr_set(struct tipc_media_addr *addr,
1138c2ecf20Sopenharmony_ci				    struct udp_media_addr *ua)
1148c2ecf20Sopenharmony_ci{
1158c2ecf20Sopenharmony_ci	memset(addr, 0, sizeof(struct tipc_media_addr));
1168c2ecf20Sopenharmony_ci	addr->media_id = TIPC_MEDIA_TYPE_UDP;
1178c2ecf20Sopenharmony_ci	memcpy(addr->value, ua, sizeof(struct udp_media_addr));
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	if (tipc_udp_is_mcast_addr(ua))
1208c2ecf20Sopenharmony_ci		addr->broadcast = TIPC_BROADCAST_SUPPORT;
1218c2ecf20Sopenharmony_ci}
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci/* tipc_udp_addr2str - convert ip/udp address to string */
1248c2ecf20Sopenharmony_cistatic int tipc_udp_addr2str(struct tipc_media_addr *a, char *buf, int size)
1258c2ecf20Sopenharmony_ci{
1268c2ecf20Sopenharmony_ci	struct udp_media_addr *ua = (struct udp_media_addr *)&a->value;
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	if (ntohs(ua->proto) == ETH_P_IP)
1298c2ecf20Sopenharmony_ci		snprintf(buf, size, "%pI4:%u", &ua->ipv4, ntohs(ua->port));
1308c2ecf20Sopenharmony_ci	else if (ntohs(ua->proto) == ETH_P_IPV6)
1318c2ecf20Sopenharmony_ci		snprintf(buf, size, "%pI6:%u", &ua->ipv6, ntohs(ua->port));
1328c2ecf20Sopenharmony_ci	else
1338c2ecf20Sopenharmony_ci		pr_err("Invalid UDP media address\n");
1348c2ecf20Sopenharmony_ci	return 0;
1358c2ecf20Sopenharmony_ci}
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci/* tipc_udp_msg2addr - extract an ip/udp address from a TIPC ndisc message */
1388c2ecf20Sopenharmony_cistatic int tipc_udp_msg2addr(struct tipc_bearer *b, struct tipc_media_addr *a,
1398c2ecf20Sopenharmony_ci			     char *msg)
1408c2ecf20Sopenharmony_ci{
1418c2ecf20Sopenharmony_ci	struct udp_media_addr *ua;
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	ua = (struct udp_media_addr *) (msg + TIPC_MEDIA_ADDR_OFFSET);
1448c2ecf20Sopenharmony_ci	if (msg[TIPC_MEDIA_TYPE_OFFSET] != TIPC_MEDIA_TYPE_UDP)
1458c2ecf20Sopenharmony_ci		return -EINVAL;
1468c2ecf20Sopenharmony_ci	tipc_udp_media_addr_set(a, ua);
1478c2ecf20Sopenharmony_ci	return 0;
1488c2ecf20Sopenharmony_ci}
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci/* tipc_udp_addr2msg - write an ip/udp address to a TIPC ndisc message */
1518c2ecf20Sopenharmony_cistatic int tipc_udp_addr2msg(char *msg, struct tipc_media_addr *a)
1528c2ecf20Sopenharmony_ci{
1538c2ecf20Sopenharmony_ci	memset(msg, 0, TIPC_MEDIA_INFO_SIZE);
1548c2ecf20Sopenharmony_ci	msg[TIPC_MEDIA_TYPE_OFFSET] = TIPC_MEDIA_TYPE_UDP;
1558c2ecf20Sopenharmony_ci	memcpy(msg + TIPC_MEDIA_ADDR_OFFSET, a->value,
1568c2ecf20Sopenharmony_ci	       sizeof(struct udp_media_addr));
1578c2ecf20Sopenharmony_ci	return 0;
1588c2ecf20Sopenharmony_ci}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci/* tipc_send_msg - enqueue a send request */
1618c2ecf20Sopenharmony_cistatic int tipc_udp_xmit(struct net *net, struct sk_buff *skb,
1628c2ecf20Sopenharmony_ci			 struct udp_bearer *ub, struct udp_media_addr *src,
1638c2ecf20Sopenharmony_ci			 struct udp_media_addr *dst, struct dst_cache *cache)
1648c2ecf20Sopenharmony_ci{
1658c2ecf20Sopenharmony_ci	struct dst_entry *ndst;
1668c2ecf20Sopenharmony_ci	int ttl, err = 0;
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	local_bh_disable();
1698c2ecf20Sopenharmony_ci	ndst = dst_cache_get(cache);
1708c2ecf20Sopenharmony_ci	if (dst->proto == htons(ETH_P_IP)) {
1718c2ecf20Sopenharmony_ci		struct rtable *rt = (struct rtable *)ndst;
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci		if (!rt) {
1748c2ecf20Sopenharmony_ci			struct flowi4 fl = {
1758c2ecf20Sopenharmony_ci				.daddr = dst->ipv4.s_addr,
1768c2ecf20Sopenharmony_ci				.saddr = src->ipv4.s_addr,
1778c2ecf20Sopenharmony_ci				.flowi4_mark = skb->mark,
1788c2ecf20Sopenharmony_ci				.flowi4_proto = IPPROTO_UDP
1798c2ecf20Sopenharmony_ci			};
1808c2ecf20Sopenharmony_ci			rt = ip_route_output_key(net, &fl);
1818c2ecf20Sopenharmony_ci			if (IS_ERR(rt)) {
1828c2ecf20Sopenharmony_ci				err = PTR_ERR(rt);
1838c2ecf20Sopenharmony_ci				goto tx_error;
1848c2ecf20Sopenharmony_ci			}
1858c2ecf20Sopenharmony_ci			dst_cache_set_ip4(cache, &rt->dst, fl.saddr);
1868c2ecf20Sopenharmony_ci		}
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci		ttl = ip4_dst_hoplimit(&rt->dst);
1898c2ecf20Sopenharmony_ci		udp_tunnel_xmit_skb(rt, ub->ubsock->sk, skb, src->ipv4.s_addr,
1908c2ecf20Sopenharmony_ci				    dst->ipv4.s_addr, 0, ttl, 0, src->port,
1918c2ecf20Sopenharmony_ci				    dst->port, false, true);
1928c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
1938c2ecf20Sopenharmony_ci	} else {
1948c2ecf20Sopenharmony_ci		if (!ndst) {
1958c2ecf20Sopenharmony_ci			struct flowi6 fl6 = {
1968c2ecf20Sopenharmony_ci				.flowi6_oif = ub->ifindex,
1978c2ecf20Sopenharmony_ci				.daddr = dst->ipv6,
1988c2ecf20Sopenharmony_ci				.saddr = src->ipv6,
1998c2ecf20Sopenharmony_ci				.flowi6_proto = IPPROTO_UDP
2008c2ecf20Sopenharmony_ci			};
2018c2ecf20Sopenharmony_ci			ndst = ipv6_stub->ipv6_dst_lookup_flow(net,
2028c2ecf20Sopenharmony_ci							       ub->ubsock->sk,
2038c2ecf20Sopenharmony_ci							       &fl6, NULL);
2048c2ecf20Sopenharmony_ci			if (IS_ERR(ndst)) {
2058c2ecf20Sopenharmony_ci				err = PTR_ERR(ndst);
2068c2ecf20Sopenharmony_ci				goto tx_error;
2078c2ecf20Sopenharmony_ci			}
2088c2ecf20Sopenharmony_ci			dst_cache_set_ip6(cache, ndst, &fl6.saddr);
2098c2ecf20Sopenharmony_ci		}
2108c2ecf20Sopenharmony_ci		ttl = ip6_dst_hoplimit(ndst);
2118c2ecf20Sopenharmony_ci		err = udp_tunnel6_xmit_skb(ndst, ub->ubsock->sk, skb, NULL,
2128c2ecf20Sopenharmony_ci					   &src->ipv6, &dst->ipv6, 0, ttl, 0,
2138c2ecf20Sopenharmony_ci					   src->port, dst->port, false);
2148c2ecf20Sopenharmony_ci#endif
2158c2ecf20Sopenharmony_ci	}
2168c2ecf20Sopenharmony_ci	local_bh_enable();
2178c2ecf20Sopenharmony_ci	return err;
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_citx_error:
2208c2ecf20Sopenharmony_ci	local_bh_enable();
2218c2ecf20Sopenharmony_ci	kfree_skb(skb);
2228c2ecf20Sopenharmony_ci	return err;
2238c2ecf20Sopenharmony_ci}
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_cistatic int tipc_udp_send_msg(struct net *net, struct sk_buff *skb,
2268c2ecf20Sopenharmony_ci			     struct tipc_bearer *b,
2278c2ecf20Sopenharmony_ci			     struct tipc_media_addr *addr)
2288c2ecf20Sopenharmony_ci{
2298c2ecf20Sopenharmony_ci	struct udp_media_addr *src = (struct udp_media_addr *)&b->addr.value;
2308c2ecf20Sopenharmony_ci	struct udp_media_addr *dst = (struct udp_media_addr *)&addr->value;
2318c2ecf20Sopenharmony_ci	struct udp_replicast *rcast;
2328c2ecf20Sopenharmony_ci	struct udp_bearer *ub;
2338c2ecf20Sopenharmony_ci	int err = 0;
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	if (skb_headroom(skb) < UDP_MIN_HEADROOM) {
2368c2ecf20Sopenharmony_ci		err = pskb_expand_head(skb, UDP_MIN_HEADROOM, 0, GFP_ATOMIC);
2378c2ecf20Sopenharmony_ci		if (err)
2388c2ecf20Sopenharmony_ci			goto out;
2398c2ecf20Sopenharmony_ci	}
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	skb_set_inner_protocol(skb, htons(ETH_P_TIPC));
2428c2ecf20Sopenharmony_ci	ub = rcu_dereference(b->media_ptr);
2438c2ecf20Sopenharmony_ci	if (!ub) {
2448c2ecf20Sopenharmony_ci		err = -ENODEV;
2458c2ecf20Sopenharmony_ci		goto out;
2468c2ecf20Sopenharmony_ci	}
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	if (addr->broadcast != TIPC_REPLICAST_SUPPORT)
2498c2ecf20Sopenharmony_ci		return tipc_udp_xmit(net, skb, ub, src, dst,
2508c2ecf20Sopenharmony_ci				     &ub->rcast.dst_cache);
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	/* Replicast, send an skb to each configured IP address */
2538c2ecf20Sopenharmony_ci	list_for_each_entry_rcu(rcast, &ub->rcast.list, list) {
2548c2ecf20Sopenharmony_ci		struct sk_buff *_skb;
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci		_skb = pskb_copy(skb, GFP_ATOMIC);
2578c2ecf20Sopenharmony_ci		if (!_skb) {
2588c2ecf20Sopenharmony_ci			err = -ENOMEM;
2598c2ecf20Sopenharmony_ci			goto out;
2608c2ecf20Sopenharmony_ci		}
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci		err = tipc_udp_xmit(net, _skb, ub, src, &rcast->addr,
2638c2ecf20Sopenharmony_ci				    &rcast->dst_cache);
2648c2ecf20Sopenharmony_ci		if (err)
2658c2ecf20Sopenharmony_ci			goto out;
2668c2ecf20Sopenharmony_ci	}
2678c2ecf20Sopenharmony_ci	err = 0;
2688c2ecf20Sopenharmony_ciout:
2698c2ecf20Sopenharmony_ci	kfree_skb(skb);
2708c2ecf20Sopenharmony_ci	return err;
2718c2ecf20Sopenharmony_ci}
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_cistatic bool tipc_udp_is_known_peer(struct tipc_bearer *b,
2748c2ecf20Sopenharmony_ci				   struct udp_media_addr *addr)
2758c2ecf20Sopenharmony_ci{
2768c2ecf20Sopenharmony_ci	struct udp_replicast *rcast, *tmp;
2778c2ecf20Sopenharmony_ci	struct udp_bearer *ub;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	ub = rcu_dereference_rtnl(b->media_ptr);
2808c2ecf20Sopenharmony_ci	if (!ub) {
2818c2ecf20Sopenharmony_ci		pr_err_ratelimited("UDP bearer instance not found\n");
2828c2ecf20Sopenharmony_ci		return false;
2838c2ecf20Sopenharmony_ci	}
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	list_for_each_entry_safe(rcast, tmp, &ub->rcast.list, list) {
2868c2ecf20Sopenharmony_ci		if (!memcmp(&rcast->addr, addr, sizeof(struct udp_media_addr)))
2878c2ecf20Sopenharmony_ci			return true;
2888c2ecf20Sopenharmony_ci	}
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	return false;
2918c2ecf20Sopenharmony_ci}
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_cistatic int tipc_udp_rcast_add(struct tipc_bearer *b,
2948c2ecf20Sopenharmony_ci			      struct udp_media_addr *addr)
2958c2ecf20Sopenharmony_ci{
2968c2ecf20Sopenharmony_ci	struct udp_replicast *rcast;
2978c2ecf20Sopenharmony_ci	struct udp_bearer *ub;
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	ub = rcu_dereference_rtnl(b->media_ptr);
3008c2ecf20Sopenharmony_ci	if (!ub)
3018c2ecf20Sopenharmony_ci		return -ENODEV;
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	rcast = kmalloc(sizeof(*rcast), GFP_ATOMIC);
3048c2ecf20Sopenharmony_ci	if (!rcast)
3058c2ecf20Sopenharmony_ci		return -ENOMEM;
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	if (dst_cache_init(&rcast->dst_cache, GFP_ATOMIC)) {
3088c2ecf20Sopenharmony_ci		kfree(rcast);
3098c2ecf20Sopenharmony_ci		return -ENOMEM;
3108c2ecf20Sopenharmony_ci	}
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	memcpy(&rcast->addr, addr, sizeof(struct udp_media_addr));
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	if (ntohs(addr->proto) == ETH_P_IP)
3158c2ecf20Sopenharmony_ci		pr_info("New replicast peer: %pI4\n", &rcast->addr.ipv4);
3168c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
3178c2ecf20Sopenharmony_ci	else if (ntohs(addr->proto) == ETH_P_IPV6)
3188c2ecf20Sopenharmony_ci		pr_info("New replicast peer: %pI6\n", &rcast->addr.ipv6);
3198c2ecf20Sopenharmony_ci#endif
3208c2ecf20Sopenharmony_ci	b->bcast_addr.broadcast = TIPC_REPLICAST_SUPPORT;
3218c2ecf20Sopenharmony_ci	list_add_rcu(&rcast->list, &ub->rcast.list);
3228c2ecf20Sopenharmony_ci	return 0;
3238c2ecf20Sopenharmony_ci}
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_cistatic int tipc_udp_rcast_disc(struct tipc_bearer *b, struct sk_buff *skb)
3268c2ecf20Sopenharmony_ci{
3278c2ecf20Sopenharmony_ci	struct udp_media_addr src = {0};
3288c2ecf20Sopenharmony_ci	struct udp_media_addr *dst;
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	dst = (struct udp_media_addr *)&b->bcast_addr.value;
3318c2ecf20Sopenharmony_ci	if (tipc_udp_is_mcast_addr(dst))
3328c2ecf20Sopenharmony_ci		return 0;
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	src.port = udp_hdr(skb)->source;
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	if (ip_hdr(skb)->version == 4) {
3378c2ecf20Sopenharmony_ci		struct iphdr *iphdr = ip_hdr(skb);
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci		src.proto = htons(ETH_P_IP);
3408c2ecf20Sopenharmony_ci		src.ipv4.s_addr = iphdr->saddr;
3418c2ecf20Sopenharmony_ci		if (ipv4_is_multicast(iphdr->daddr))
3428c2ecf20Sopenharmony_ci			return 0;
3438c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
3448c2ecf20Sopenharmony_ci	} else if (ip_hdr(skb)->version == 6) {
3458c2ecf20Sopenharmony_ci		struct ipv6hdr *iphdr = ipv6_hdr(skb);
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci		src.proto = htons(ETH_P_IPV6);
3488c2ecf20Sopenharmony_ci		src.ipv6 = iphdr->saddr;
3498c2ecf20Sopenharmony_ci		if (ipv6_addr_is_multicast(&iphdr->daddr))
3508c2ecf20Sopenharmony_ci			return 0;
3518c2ecf20Sopenharmony_ci#endif
3528c2ecf20Sopenharmony_ci	} else {
3538c2ecf20Sopenharmony_ci		return 0;
3548c2ecf20Sopenharmony_ci	}
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	if (likely(tipc_udp_is_known_peer(b, &src)))
3578c2ecf20Sopenharmony_ci		return 0;
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	return tipc_udp_rcast_add(b, &src);
3608c2ecf20Sopenharmony_ci}
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci/* tipc_udp_recv - read data from bearer socket */
3638c2ecf20Sopenharmony_cistatic int tipc_udp_recv(struct sock *sk, struct sk_buff *skb)
3648c2ecf20Sopenharmony_ci{
3658c2ecf20Sopenharmony_ci	struct udp_bearer *ub;
3668c2ecf20Sopenharmony_ci	struct tipc_bearer *b;
3678c2ecf20Sopenharmony_ci	struct tipc_msg *hdr;
3688c2ecf20Sopenharmony_ci	int err;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	ub = rcu_dereference_sk_user_data(sk);
3718c2ecf20Sopenharmony_ci	if (!ub) {
3728c2ecf20Sopenharmony_ci		pr_err_ratelimited("Failed to get UDP bearer reference");
3738c2ecf20Sopenharmony_ci		goto out;
3748c2ecf20Sopenharmony_ci	}
3758c2ecf20Sopenharmony_ci	skb_pull(skb, sizeof(struct udphdr));
3768c2ecf20Sopenharmony_ci	hdr = buf_msg(skb);
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	b = rcu_dereference(ub->bearer);
3798c2ecf20Sopenharmony_ci	if (!b)
3808c2ecf20Sopenharmony_ci		goto out;
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	if (b && test_bit(0, &b->up)) {
3838c2ecf20Sopenharmony_ci		TIPC_SKB_CB(skb)->flags = 0;
3848c2ecf20Sopenharmony_ci		tipc_rcv(sock_net(sk), skb, b);
3858c2ecf20Sopenharmony_ci		return 0;
3868c2ecf20Sopenharmony_ci	}
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	if (unlikely(msg_user(hdr) == LINK_CONFIG)) {
3898c2ecf20Sopenharmony_ci		err = tipc_udp_rcast_disc(b, skb);
3908c2ecf20Sopenharmony_ci		if (err)
3918c2ecf20Sopenharmony_ci			goto out;
3928c2ecf20Sopenharmony_ci	}
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ciout:
3958c2ecf20Sopenharmony_ci	kfree_skb(skb);
3968c2ecf20Sopenharmony_ci	return 0;
3978c2ecf20Sopenharmony_ci}
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_cistatic int enable_mcast(struct udp_bearer *ub, struct udp_media_addr *remote)
4008c2ecf20Sopenharmony_ci{
4018c2ecf20Sopenharmony_ci	int err = 0;
4028c2ecf20Sopenharmony_ci	struct ip_mreqn mreqn;
4038c2ecf20Sopenharmony_ci	struct sock *sk = ub->ubsock->sk;
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	if (ntohs(remote->proto) == ETH_P_IP) {
4068c2ecf20Sopenharmony_ci		mreqn.imr_multiaddr = remote->ipv4;
4078c2ecf20Sopenharmony_ci		mreqn.imr_ifindex = ub->ifindex;
4088c2ecf20Sopenharmony_ci		err = ip_mc_join_group(sk, &mreqn);
4098c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
4108c2ecf20Sopenharmony_ci	} else {
4118c2ecf20Sopenharmony_ci		err = ipv6_stub->ipv6_sock_mc_join(sk, ub->ifindex,
4128c2ecf20Sopenharmony_ci						   &remote->ipv6);
4138c2ecf20Sopenharmony_ci#endif
4148c2ecf20Sopenharmony_ci	}
4158c2ecf20Sopenharmony_ci	return err;
4168c2ecf20Sopenharmony_ci}
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_cistatic int __tipc_nl_add_udp_addr(struct sk_buff *skb,
4198c2ecf20Sopenharmony_ci				  struct udp_media_addr *addr, int nla_t)
4208c2ecf20Sopenharmony_ci{
4218c2ecf20Sopenharmony_ci	if (ntohs(addr->proto) == ETH_P_IP) {
4228c2ecf20Sopenharmony_ci		struct sockaddr_in ip4;
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci		memset(&ip4, 0, sizeof(ip4));
4258c2ecf20Sopenharmony_ci		ip4.sin_family = AF_INET;
4268c2ecf20Sopenharmony_ci		ip4.sin_port = addr->port;
4278c2ecf20Sopenharmony_ci		ip4.sin_addr.s_addr = addr->ipv4.s_addr;
4288c2ecf20Sopenharmony_ci		if (nla_put(skb, nla_t, sizeof(ip4), &ip4))
4298c2ecf20Sopenharmony_ci			return -EMSGSIZE;
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
4328c2ecf20Sopenharmony_ci	} else if (ntohs(addr->proto) == ETH_P_IPV6) {
4338c2ecf20Sopenharmony_ci		struct sockaddr_in6 ip6;
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci		memset(&ip6, 0, sizeof(ip6));
4368c2ecf20Sopenharmony_ci		ip6.sin6_family = AF_INET6;
4378c2ecf20Sopenharmony_ci		ip6.sin6_port  = addr->port;
4388c2ecf20Sopenharmony_ci		memcpy(&ip6.sin6_addr, &addr->ipv6, sizeof(struct in6_addr));
4398c2ecf20Sopenharmony_ci		if (nla_put(skb, nla_t, sizeof(ip6), &ip6))
4408c2ecf20Sopenharmony_ci			return -EMSGSIZE;
4418c2ecf20Sopenharmony_ci#endif
4428c2ecf20Sopenharmony_ci	}
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	return 0;
4458c2ecf20Sopenharmony_ci}
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ciint tipc_udp_nl_dump_remoteip(struct sk_buff *skb, struct netlink_callback *cb)
4488c2ecf20Sopenharmony_ci{
4498c2ecf20Sopenharmony_ci	u32 bid = cb->args[0];
4508c2ecf20Sopenharmony_ci	u32 skip_cnt = cb->args[1];
4518c2ecf20Sopenharmony_ci	u32 portid = NETLINK_CB(cb->skb).portid;
4528c2ecf20Sopenharmony_ci	struct udp_replicast *rcast, *tmp;
4538c2ecf20Sopenharmony_ci	struct tipc_bearer *b;
4548c2ecf20Sopenharmony_ci	struct udp_bearer *ub;
4558c2ecf20Sopenharmony_ci	void *hdr;
4568c2ecf20Sopenharmony_ci	int err;
4578c2ecf20Sopenharmony_ci	int i;
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	if (!bid && !skip_cnt) {
4608c2ecf20Sopenharmony_ci		struct nlattr **attrs = genl_dumpit_info(cb)->attrs;
4618c2ecf20Sopenharmony_ci		struct net *net = sock_net(skb->sk);
4628c2ecf20Sopenharmony_ci		struct nlattr *battrs[TIPC_NLA_BEARER_MAX + 1];
4638c2ecf20Sopenharmony_ci		char *bname;
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci		if (!attrs[TIPC_NLA_BEARER])
4668c2ecf20Sopenharmony_ci			return -EINVAL;
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci		err = nla_parse_nested_deprecated(battrs, TIPC_NLA_BEARER_MAX,
4698c2ecf20Sopenharmony_ci						  attrs[TIPC_NLA_BEARER],
4708c2ecf20Sopenharmony_ci						  tipc_nl_bearer_policy, NULL);
4718c2ecf20Sopenharmony_ci		if (err)
4728c2ecf20Sopenharmony_ci			return err;
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci		if (!battrs[TIPC_NLA_BEARER_NAME])
4758c2ecf20Sopenharmony_ci			return -EINVAL;
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci		bname = nla_data(battrs[TIPC_NLA_BEARER_NAME]);
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci		rtnl_lock();
4808c2ecf20Sopenharmony_ci		b = tipc_bearer_find(net, bname);
4818c2ecf20Sopenharmony_ci		if (!b) {
4828c2ecf20Sopenharmony_ci			rtnl_unlock();
4838c2ecf20Sopenharmony_ci			return -EINVAL;
4848c2ecf20Sopenharmony_ci		}
4858c2ecf20Sopenharmony_ci		bid = b->identity;
4868c2ecf20Sopenharmony_ci	} else {
4878c2ecf20Sopenharmony_ci		struct net *net = sock_net(skb->sk);
4888c2ecf20Sopenharmony_ci		struct tipc_net *tn = net_generic(net, tipc_net_id);
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci		rtnl_lock();
4918c2ecf20Sopenharmony_ci		b = rtnl_dereference(tn->bearer_list[bid]);
4928c2ecf20Sopenharmony_ci		if (!b) {
4938c2ecf20Sopenharmony_ci			rtnl_unlock();
4948c2ecf20Sopenharmony_ci			return -EINVAL;
4958c2ecf20Sopenharmony_ci		}
4968c2ecf20Sopenharmony_ci	}
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci	ub = rtnl_dereference(b->media_ptr);
4998c2ecf20Sopenharmony_ci	if (!ub) {
5008c2ecf20Sopenharmony_ci		rtnl_unlock();
5018c2ecf20Sopenharmony_ci		return -EINVAL;
5028c2ecf20Sopenharmony_ci	}
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci	i = 0;
5058c2ecf20Sopenharmony_ci	list_for_each_entry_safe(rcast, tmp, &ub->rcast.list, list) {
5068c2ecf20Sopenharmony_ci		if (i < skip_cnt)
5078c2ecf20Sopenharmony_ci			goto count;
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci		hdr = genlmsg_put(skb, portid, cb->nlh->nlmsg_seq,
5108c2ecf20Sopenharmony_ci				  &tipc_genl_family, NLM_F_MULTI,
5118c2ecf20Sopenharmony_ci				  TIPC_NL_BEARER_GET);
5128c2ecf20Sopenharmony_ci		if (!hdr)
5138c2ecf20Sopenharmony_ci			goto done;
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci		err = __tipc_nl_add_udp_addr(skb, &rcast->addr,
5168c2ecf20Sopenharmony_ci					     TIPC_NLA_UDP_REMOTE);
5178c2ecf20Sopenharmony_ci		if (err) {
5188c2ecf20Sopenharmony_ci			genlmsg_cancel(skb, hdr);
5198c2ecf20Sopenharmony_ci			goto done;
5208c2ecf20Sopenharmony_ci		}
5218c2ecf20Sopenharmony_ci		genlmsg_end(skb, hdr);
5228c2ecf20Sopenharmony_cicount:
5238c2ecf20Sopenharmony_ci		i++;
5248c2ecf20Sopenharmony_ci	}
5258c2ecf20Sopenharmony_cidone:
5268c2ecf20Sopenharmony_ci	rtnl_unlock();
5278c2ecf20Sopenharmony_ci	cb->args[0] = bid;
5288c2ecf20Sopenharmony_ci	cb->args[1] = i;
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci	return skb->len;
5318c2ecf20Sopenharmony_ci}
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ciint tipc_udp_nl_add_bearer_data(struct tipc_nl_msg *msg, struct tipc_bearer *b)
5348c2ecf20Sopenharmony_ci{
5358c2ecf20Sopenharmony_ci	struct udp_media_addr *src = (struct udp_media_addr *)&b->addr.value;
5368c2ecf20Sopenharmony_ci	struct udp_media_addr *dst;
5378c2ecf20Sopenharmony_ci	struct udp_bearer *ub;
5388c2ecf20Sopenharmony_ci	struct nlattr *nest;
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	ub = rtnl_dereference(b->media_ptr);
5418c2ecf20Sopenharmony_ci	if (!ub)
5428c2ecf20Sopenharmony_ci		return -ENODEV;
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci	nest = nla_nest_start_noflag(msg->skb, TIPC_NLA_BEARER_UDP_OPTS);
5458c2ecf20Sopenharmony_ci	if (!nest)
5468c2ecf20Sopenharmony_ci		goto msg_full;
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci	if (__tipc_nl_add_udp_addr(msg->skb, src, TIPC_NLA_UDP_LOCAL))
5498c2ecf20Sopenharmony_ci		goto msg_full;
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci	dst = (struct udp_media_addr *)&b->bcast_addr.value;
5528c2ecf20Sopenharmony_ci	if (__tipc_nl_add_udp_addr(msg->skb, dst, TIPC_NLA_UDP_REMOTE))
5538c2ecf20Sopenharmony_ci		goto msg_full;
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci	if (!list_empty(&ub->rcast.list)) {
5568c2ecf20Sopenharmony_ci		if (nla_put_flag(msg->skb, TIPC_NLA_UDP_MULTI_REMOTEIP))
5578c2ecf20Sopenharmony_ci			goto msg_full;
5588c2ecf20Sopenharmony_ci	}
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci	nla_nest_end(msg->skb, nest);
5618c2ecf20Sopenharmony_ci	return 0;
5628c2ecf20Sopenharmony_cimsg_full:
5638c2ecf20Sopenharmony_ci	nla_nest_cancel(msg->skb, nest);
5648c2ecf20Sopenharmony_ci	return -EMSGSIZE;
5658c2ecf20Sopenharmony_ci}
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci/**
5688c2ecf20Sopenharmony_ci * tipc_parse_udp_addr - build udp media address from netlink data
5698c2ecf20Sopenharmony_ci * @nla:	netlink attribute containing sockaddr storage aligned address
5708c2ecf20Sopenharmony_ci * @addr:	tipc media address to fill with address, port and protocol type
5718c2ecf20Sopenharmony_ci * @scope_id:	IPv6 scope id pointer, not NULL indicates it's required
5728c2ecf20Sopenharmony_ci */
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_cistatic int tipc_parse_udp_addr(struct nlattr *nla, struct udp_media_addr *addr,
5758c2ecf20Sopenharmony_ci			       u32 *scope_id)
5768c2ecf20Sopenharmony_ci{
5778c2ecf20Sopenharmony_ci	struct sockaddr_storage sa;
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci	nla_memcpy(&sa, nla, sizeof(sa));
5808c2ecf20Sopenharmony_ci	if (sa.ss_family == AF_INET) {
5818c2ecf20Sopenharmony_ci		struct sockaddr_in *ip4 = (struct sockaddr_in *)&sa;
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci		addr->proto = htons(ETH_P_IP);
5848c2ecf20Sopenharmony_ci		addr->port = ip4->sin_port;
5858c2ecf20Sopenharmony_ci		addr->ipv4.s_addr = ip4->sin_addr.s_addr;
5868c2ecf20Sopenharmony_ci		return 0;
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
5898c2ecf20Sopenharmony_ci	} else if (sa.ss_family == AF_INET6) {
5908c2ecf20Sopenharmony_ci		struct sockaddr_in6 *ip6 = (struct sockaddr_in6 *)&sa;
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci		addr->proto = htons(ETH_P_IPV6);
5938c2ecf20Sopenharmony_ci		addr->port = ip6->sin6_port;
5948c2ecf20Sopenharmony_ci		memcpy(&addr->ipv6, &ip6->sin6_addr, sizeof(struct in6_addr));
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ci		/* Scope ID is only interesting for local addresses */
5978c2ecf20Sopenharmony_ci		if (scope_id) {
5988c2ecf20Sopenharmony_ci			int atype;
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci			atype = ipv6_addr_type(&ip6->sin6_addr);
6018c2ecf20Sopenharmony_ci			if (__ipv6_addr_needs_scope_id(atype) &&
6028c2ecf20Sopenharmony_ci			    !ip6->sin6_scope_id) {
6038c2ecf20Sopenharmony_ci				return -EINVAL;
6048c2ecf20Sopenharmony_ci			}
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci			*scope_id = ip6->sin6_scope_id ? : 0;
6078c2ecf20Sopenharmony_ci		}
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci		return 0;
6108c2ecf20Sopenharmony_ci#endif
6118c2ecf20Sopenharmony_ci	}
6128c2ecf20Sopenharmony_ci	return -EADDRNOTAVAIL;
6138c2ecf20Sopenharmony_ci}
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ciint tipc_udp_nl_bearer_add(struct tipc_bearer *b, struct nlattr *attr)
6168c2ecf20Sopenharmony_ci{
6178c2ecf20Sopenharmony_ci	int err;
6188c2ecf20Sopenharmony_ci	struct udp_media_addr addr = {0};
6198c2ecf20Sopenharmony_ci	struct nlattr *opts[TIPC_NLA_UDP_MAX + 1];
6208c2ecf20Sopenharmony_ci	struct udp_media_addr *dst;
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci	if (nla_parse_nested_deprecated(opts, TIPC_NLA_UDP_MAX, attr, tipc_nl_udp_policy, NULL))
6238c2ecf20Sopenharmony_ci		return -EINVAL;
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci	if (!opts[TIPC_NLA_UDP_REMOTE])
6268c2ecf20Sopenharmony_ci		return -EINVAL;
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci	err = tipc_parse_udp_addr(opts[TIPC_NLA_UDP_REMOTE], &addr, NULL);
6298c2ecf20Sopenharmony_ci	if (err)
6308c2ecf20Sopenharmony_ci		return err;
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	dst = (struct udp_media_addr *)&b->bcast_addr.value;
6338c2ecf20Sopenharmony_ci	if (tipc_udp_is_mcast_addr(dst)) {
6348c2ecf20Sopenharmony_ci		pr_err("Can't add remote ip to TIPC UDP multicast bearer\n");
6358c2ecf20Sopenharmony_ci		return -EINVAL;
6368c2ecf20Sopenharmony_ci	}
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci	if (tipc_udp_is_known_peer(b, &addr))
6398c2ecf20Sopenharmony_ci		return 0;
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci	return tipc_udp_rcast_add(b, &addr);
6428c2ecf20Sopenharmony_ci}
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_ci/**
6458c2ecf20Sopenharmony_ci * tipc_udp_enable - callback to create a new udp bearer instance
6468c2ecf20Sopenharmony_ci * @net:	network namespace
6478c2ecf20Sopenharmony_ci * @b:		pointer to generic tipc_bearer
6488c2ecf20Sopenharmony_ci * @attrs:	netlink bearer configuration
6498c2ecf20Sopenharmony_ci *
6508c2ecf20Sopenharmony_ci * validate the bearer parameters and initialize the udp bearer
6518c2ecf20Sopenharmony_ci * rtnl_lock should be held
6528c2ecf20Sopenharmony_ci */
6538c2ecf20Sopenharmony_cistatic int tipc_udp_enable(struct net *net, struct tipc_bearer *b,
6548c2ecf20Sopenharmony_ci			   struct nlattr *attrs[])
6558c2ecf20Sopenharmony_ci{
6568c2ecf20Sopenharmony_ci	int err = -EINVAL;
6578c2ecf20Sopenharmony_ci	struct udp_bearer *ub;
6588c2ecf20Sopenharmony_ci	struct udp_media_addr remote = {0};
6598c2ecf20Sopenharmony_ci	struct udp_media_addr local = {0};
6608c2ecf20Sopenharmony_ci	struct udp_port_cfg udp_conf = {0};
6618c2ecf20Sopenharmony_ci	struct udp_tunnel_sock_cfg tuncfg = {NULL};
6628c2ecf20Sopenharmony_ci	struct nlattr *opts[TIPC_NLA_UDP_MAX + 1];
6638c2ecf20Sopenharmony_ci	u8 node_id[NODE_ID_LEN] = {0,};
6648c2ecf20Sopenharmony_ci	struct net_device *dev;
6658c2ecf20Sopenharmony_ci	int rmcast = 0;
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci	ub = kzalloc(sizeof(*ub), GFP_ATOMIC);
6688c2ecf20Sopenharmony_ci	if (!ub)
6698c2ecf20Sopenharmony_ci		return -ENOMEM;
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&ub->rcast.list);
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_ci	if (!attrs[TIPC_NLA_BEARER_UDP_OPTS])
6748c2ecf20Sopenharmony_ci		goto err;
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ci	if (nla_parse_nested_deprecated(opts, TIPC_NLA_UDP_MAX, attrs[TIPC_NLA_BEARER_UDP_OPTS], tipc_nl_udp_policy, NULL))
6778c2ecf20Sopenharmony_ci		goto err;
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_ci	if (!opts[TIPC_NLA_UDP_LOCAL] || !opts[TIPC_NLA_UDP_REMOTE]) {
6808c2ecf20Sopenharmony_ci		pr_err("Invalid UDP bearer configuration");
6818c2ecf20Sopenharmony_ci		err = -EINVAL;
6828c2ecf20Sopenharmony_ci		goto err;
6838c2ecf20Sopenharmony_ci	}
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci	err = tipc_parse_udp_addr(opts[TIPC_NLA_UDP_LOCAL], &local,
6868c2ecf20Sopenharmony_ci				  &ub->ifindex);
6878c2ecf20Sopenharmony_ci	if (err)
6888c2ecf20Sopenharmony_ci		goto err;
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_ci	err = tipc_parse_udp_addr(opts[TIPC_NLA_UDP_REMOTE], &remote, NULL);
6918c2ecf20Sopenharmony_ci	if (err)
6928c2ecf20Sopenharmony_ci		goto err;
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_ci	if (remote.proto != local.proto) {
6958c2ecf20Sopenharmony_ci		err = -EINVAL;
6968c2ecf20Sopenharmony_ci		goto err;
6978c2ecf20Sopenharmony_ci	}
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_ci	/* Checking remote ip address */
7008c2ecf20Sopenharmony_ci	rmcast = tipc_udp_is_mcast_addr(&remote);
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci	/* Autoconfigure own node identity if needed */
7038c2ecf20Sopenharmony_ci	if (!tipc_own_id(net)) {
7048c2ecf20Sopenharmony_ci		memcpy(node_id, local.ipv6.in6_u.u6_addr8, 16);
7058c2ecf20Sopenharmony_ci		tipc_net_init(net, node_id, 0);
7068c2ecf20Sopenharmony_ci	}
7078c2ecf20Sopenharmony_ci	if (!tipc_own_id(net)) {
7088c2ecf20Sopenharmony_ci		pr_warn("Failed to set node id, please configure manually\n");
7098c2ecf20Sopenharmony_ci		err = -EINVAL;
7108c2ecf20Sopenharmony_ci		goto err;
7118c2ecf20Sopenharmony_ci	}
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_ci	b->bcast_addr.media_id = TIPC_MEDIA_TYPE_UDP;
7148c2ecf20Sopenharmony_ci	b->bcast_addr.broadcast = TIPC_BROADCAST_SUPPORT;
7158c2ecf20Sopenharmony_ci	rcu_assign_pointer(b->media_ptr, ub);
7168c2ecf20Sopenharmony_ci	rcu_assign_pointer(ub->bearer, b);
7178c2ecf20Sopenharmony_ci	tipc_udp_media_addr_set(&b->addr, &local);
7188c2ecf20Sopenharmony_ci	if (local.proto == htons(ETH_P_IP)) {
7198c2ecf20Sopenharmony_ci		dev = __ip_dev_find(net, local.ipv4.s_addr, false);
7208c2ecf20Sopenharmony_ci		if (!dev) {
7218c2ecf20Sopenharmony_ci			err = -ENODEV;
7228c2ecf20Sopenharmony_ci			goto err;
7238c2ecf20Sopenharmony_ci		}
7248c2ecf20Sopenharmony_ci		udp_conf.family = AF_INET;
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_ci		/* Switch to use ANY to receive packets from group */
7278c2ecf20Sopenharmony_ci		if (rmcast)
7288c2ecf20Sopenharmony_ci			udp_conf.local_ip.s_addr = htonl(INADDR_ANY);
7298c2ecf20Sopenharmony_ci		else
7308c2ecf20Sopenharmony_ci			udp_conf.local_ip.s_addr = local.ipv4.s_addr;
7318c2ecf20Sopenharmony_ci		udp_conf.use_udp_checksums = false;
7328c2ecf20Sopenharmony_ci		ub->ifindex = dev->ifindex;
7338c2ecf20Sopenharmony_ci		b->encap_hlen = sizeof(struct iphdr) + sizeof(struct udphdr);
7348c2ecf20Sopenharmony_ci		if (tipc_mtu_bad(dev, b->encap_hlen)) {
7358c2ecf20Sopenharmony_ci			err = -EINVAL;
7368c2ecf20Sopenharmony_ci			goto err;
7378c2ecf20Sopenharmony_ci		}
7388c2ecf20Sopenharmony_ci		b->mtu = b->media->mtu;
7398c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
7408c2ecf20Sopenharmony_ci	} else if (local.proto == htons(ETH_P_IPV6)) {
7418c2ecf20Sopenharmony_ci		dev = ub->ifindex ? __dev_get_by_index(net, ub->ifindex) : NULL;
7428c2ecf20Sopenharmony_ci		dev = ipv6_dev_find(net, &local.ipv6, dev);
7438c2ecf20Sopenharmony_ci		if (!dev) {
7448c2ecf20Sopenharmony_ci			err = -ENODEV;
7458c2ecf20Sopenharmony_ci			goto err;
7468c2ecf20Sopenharmony_ci		}
7478c2ecf20Sopenharmony_ci		udp_conf.family = AF_INET6;
7488c2ecf20Sopenharmony_ci		udp_conf.use_udp6_tx_checksums = true;
7498c2ecf20Sopenharmony_ci		udp_conf.use_udp6_rx_checksums = true;
7508c2ecf20Sopenharmony_ci		if (rmcast)
7518c2ecf20Sopenharmony_ci			udp_conf.local_ip6 = in6addr_any;
7528c2ecf20Sopenharmony_ci		else
7538c2ecf20Sopenharmony_ci			udp_conf.local_ip6 = local.ipv6;
7548c2ecf20Sopenharmony_ci		ub->ifindex = dev->ifindex;
7558c2ecf20Sopenharmony_ci		b->encap_hlen = sizeof(struct ipv6hdr) + sizeof(struct udphdr);
7568c2ecf20Sopenharmony_ci		b->mtu = 1280;
7578c2ecf20Sopenharmony_ci#endif
7588c2ecf20Sopenharmony_ci	} else {
7598c2ecf20Sopenharmony_ci		err = -EAFNOSUPPORT;
7608c2ecf20Sopenharmony_ci		goto err;
7618c2ecf20Sopenharmony_ci	}
7628c2ecf20Sopenharmony_ci	udp_conf.local_udp_port = local.port;
7638c2ecf20Sopenharmony_ci	err = udp_sock_create(net, &udp_conf, &ub->ubsock);
7648c2ecf20Sopenharmony_ci	if (err)
7658c2ecf20Sopenharmony_ci		goto err;
7668c2ecf20Sopenharmony_ci	tuncfg.sk_user_data = ub;
7678c2ecf20Sopenharmony_ci	tuncfg.encap_type = 1;
7688c2ecf20Sopenharmony_ci	tuncfg.encap_rcv = tipc_udp_recv;
7698c2ecf20Sopenharmony_ci	tuncfg.encap_destroy = NULL;
7708c2ecf20Sopenharmony_ci	setup_udp_tunnel_sock(net, ub->ubsock, &tuncfg);
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_ci	err = dst_cache_init(&ub->rcast.dst_cache, GFP_ATOMIC);
7738c2ecf20Sopenharmony_ci	if (err)
7748c2ecf20Sopenharmony_ci		goto free;
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_ci	/**
7778c2ecf20Sopenharmony_ci	 * The bcast media address port is used for all peers and the ip
7788c2ecf20Sopenharmony_ci	 * is used if it's a multicast address.
7798c2ecf20Sopenharmony_ci	 */
7808c2ecf20Sopenharmony_ci	memcpy(&b->bcast_addr.value, &remote, sizeof(remote));
7818c2ecf20Sopenharmony_ci	if (rmcast)
7828c2ecf20Sopenharmony_ci		err = enable_mcast(ub, &remote);
7838c2ecf20Sopenharmony_ci	else
7848c2ecf20Sopenharmony_ci		err = tipc_udp_rcast_add(b, &remote);
7858c2ecf20Sopenharmony_ci	if (err)
7868c2ecf20Sopenharmony_ci		goto free;
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_ci	return 0;
7898c2ecf20Sopenharmony_ci
7908c2ecf20Sopenharmony_cifree:
7918c2ecf20Sopenharmony_ci	dst_cache_destroy(&ub->rcast.dst_cache);
7928c2ecf20Sopenharmony_ci	udp_tunnel_sock_release(ub->ubsock);
7938c2ecf20Sopenharmony_cierr:
7948c2ecf20Sopenharmony_ci	kfree(ub);
7958c2ecf20Sopenharmony_ci	return err;
7968c2ecf20Sopenharmony_ci}
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci/* cleanup_bearer - break the socket/bearer association */
7998c2ecf20Sopenharmony_cistatic void cleanup_bearer(struct work_struct *work)
8008c2ecf20Sopenharmony_ci{
8018c2ecf20Sopenharmony_ci	struct udp_bearer *ub = container_of(work, struct udp_bearer, work);
8028c2ecf20Sopenharmony_ci	struct udp_replicast *rcast, *tmp;
8038c2ecf20Sopenharmony_ci
8048c2ecf20Sopenharmony_ci	list_for_each_entry_safe(rcast, tmp, &ub->rcast.list, list) {
8058c2ecf20Sopenharmony_ci		dst_cache_destroy(&rcast->dst_cache);
8068c2ecf20Sopenharmony_ci		list_del_rcu(&rcast->list);
8078c2ecf20Sopenharmony_ci		kfree_rcu(rcast, rcu);
8088c2ecf20Sopenharmony_ci	}
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_ci	atomic_dec(&tipc_net(sock_net(ub->ubsock->sk))->wq_count);
8118c2ecf20Sopenharmony_ci	dst_cache_destroy(&ub->rcast.dst_cache);
8128c2ecf20Sopenharmony_ci	udp_tunnel_sock_release(ub->ubsock);
8138c2ecf20Sopenharmony_ci	synchronize_net();
8148c2ecf20Sopenharmony_ci	kfree(ub);
8158c2ecf20Sopenharmony_ci}
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_ci/* tipc_udp_disable - detach bearer from socket */
8188c2ecf20Sopenharmony_cistatic void tipc_udp_disable(struct tipc_bearer *b)
8198c2ecf20Sopenharmony_ci{
8208c2ecf20Sopenharmony_ci	struct udp_bearer *ub;
8218c2ecf20Sopenharmony_ci
8228c2ecf20Sopenharmony_ci	ub = rtnl_dereference(b->media_ptr);
8238c2ecf20Sopenharmony_ci	if (!ub) {
8248c2ecf20Sopenharmony_ci		pr_err("UDP bearer instance not found\n");
8258c2ecf20Sopenharmony_ci		return;
8268c2ecf20Sopenharmony_ci	}
8278c2ecf20Sopenharmony_ci	sock_set_flag(ub->ubsock->sk, SOCK_DEAD);
8288c2ecf20Sopenharmony_ci	RCU_INIT_POINTER(ub->bearer, NULL);
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_ci	/* sock_release need to be done outside of rtnl lock */
8318c2ecf20Sopenharmony_ci	atomic_inc(&tipc_net(sock_net(ub->ubsock->sk))->wq_count);
8328c2ecf20Sopenharmony_ci	INIT_WORK(&ub->work, cleanup_bearer);
8338c2ecf20Sopenharmony_ci	schedule_work(&ub->work);
8348c2ecf20Sopenharmony_ci}
8358c2ecf20Sopenharmony_ci
8368c2ecf20Sopenharmony_cistruct tipc_media udp_media_info = {
8378c2ecf20Sopenharmony_ci	.send_msg	= tipc_udp_send_msg,
8388c2ecf20Sopenharmony_ci	.enable_media	= tipc_udp_enable,
8398c2ecf20Sopenharmony_ci	.disable_media	= tipc_udp_disable,
8408c2ecf20Sopenharmony_ci	.addr2str	= tipc_udp_addr2str,
8418c2ecf20Sopenharmony_ci	.addr2msg	= tipc_udp_addr2msg,
8428c2ecf20Sopenharmony_ci	.msg2addr	= tipc_udp_msg2addr,
8438c2ecf20Sopenharmony_ci	.priority	= TIPC_DEF_LINK_PRI,
8448c2ecf20Sopenharmony_ci	.tolerance	= TIPC_DEF_LINK_TOL,
8458c2ecf20Sopenharmony_ci	.min_win	= TIPC_DEF_LINK_WIN,
8468c2ecf20Sopenharmony_ci	.max_win	= TIPC_DEF_LINK_WIN,
8478c2ecf20Sopenharmony_ci	.mtu		= TIPC_DEF_LINK_UDP_MTU,
8488c2ecf20Sopenharmony_ci	.type_id	= TIPC_MEDIA_TYPE_UDP,
8498c2ecf20Sopenharmony_ci	.hwaddr_len	= 0,
8508c2ecf20Sopenharmony_ci	.name		= "udp"
8518c2ecf20Sopenharmony_ci};
852