aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorErik Hugne <erik.hugne@ericsson.com>2015-03-05 04:23:49 -0500
committerDavid S. Miller <davem@davemloft.net>2015-03-05 22:08:42 -0500
commitd0f91938bede204a343473792529e0db7d599836 (patch)
tree2790139d615e9e9aa28565b539ae08760be2fba6
parent948fa2d115c553ae32aced66e0f00f89245dc05e (diff)
tipc: add ip/udp media type
The ip/udp bearer can be configured in a point-to-point mode by specifying both local and remote ip/hostname, or it can be enabled in multicast mode, where links are established to all tipc nodes that have joined the same multicast group. The multicast IP address is generated based on the TIPC network ID, but can be overridden by using another multicast address as remote ip. Signed-off-by: Erik Hugne <erik.hugne@ericsson.com> Reviewed-by: Jon Maloy <jon.maloy@ericsson.com> Reviewed-by: Ying Xue <ying.xue@windriver.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/uapi/linux/tipc_netlink.h9
-rw-r--r--net/tipc/Kconfig8
-rw-r--r--net/tipc/Makefile1
-rw-r--r--net/tipc/bearer.c13
-rw-r--r--net/tipc/bearer.h12
-rw-r--r--net/tipc/msg.h2
-rw-r--r--net/tipc/udp_media.c442
7 files changed, 479 insertions, 8 deletions
diff --git a/include/uapi/linux/tipc_netlink.h b/include/uapi/linux/tipc_netlink.h
index 8d723824ad69..d4c8f142ba63 100644
--- a/include/uapi/linux/tipc_netlink.h
+++ b/include/uapi/linux/tipc_netlink.h
@@ -83,11 +83,20 @@ enum {
83 TIPC_NLA_BEARER_NAME, /* string */ 83 TIPC_NLA_BEARER_NAME, /* string */
84 TIPC_NLA_BEARER_PROP, /* nest */ 84 TIPC_NLA_BEARER_PROP, /* nest */
85 TIPC_NLA_BEARER_DOMAIN, /* u32 */ 85 TIPC_NLA_BEARER_DOMAIN, /* u32 */
86 TIPC_NLA_BEARER_UDP_OPTS, /* nest */
86 87
87 __TIPC_NLA_BEARER_MAX, 88 __TIPC_NLA_BEARER_MAX,
88 TIPC_NLA_BEARER_MAX = __TIPC_NLA_BEARER_MAX - 1 89 TIPC_NLA_BEARER_MAX = __TIPC_NLA_BEARER_MAX - 1
89}; 90};
90 91
92enum {
93 TIPC_NLA_UDP_UNSPEC,
94 TIPC_NLA_UDP_LOCAL, /* sockaddr_storage */
95 TIPC_NLA_UDP_REMOTE, /* sockaddr_storage */
96
97 __TIPC_NLA_UDP_MAX,
98 TIPC_NLA_UDP_MAX = __TIPC_NLA_UDP_MAX - 1
99};
91/* Socket info */ 100/* Socket info */
92enum { 101enum {
93 TIPC_NLA_SOCK_UNSPEC, 102 TIPC_NLA_SOCK_UNSPEC,
diff --git a/net/tipc/Kconfig b/net/tipc/Kconfig
index 91c8a8e031db..c25a3a149dc4 100644
--- a/net/tipc/Kconfig
+++ b/net/tipc/Kconfig
@@ -26,3 +26,11 @@ config TIPC_MEDIA_IB
26 help 26 help
27 Saying Y here will enable support for running TIPC on 27 Saying Y here will enable support for running TIPC on
28 IP-over-InfiniBand devices. 28 IP-over-InfiniBand devices.
29config TIPC_MEDIA_UDP
30 bool "IP/UDP media type support"
31 depends on TIPC
32 select NET_UDP_TUNNEL
33 help
34 Saying Y here will enable support for running TIPC over IP/UDP
35 bool
36 default y
diff --git a/net/tipc/Makefile b/net/tipc/Makefile
index 599b1a540d2b..57e460be4692 100644
--- a/net/tipc/Makefile
+++ b/net/tipc/Makefile
@@ -10,5 +10,6 @@ tipc-y += addr.o bcast.o bearer.o \
10 netlink.o netlink_compat.o node.o socket.o eth_media.o \ 10 netlink.o netlink_compat.o node.o socket.o eth_media.o \
11 server.o socket.o 11 server.o socket.o
12 12
13tipc-$(CONFIG_TIPC_MEDIA_UDP) += udp_media.o
13tipc-$(CONFIG_TIPC_MEDIA_IB) += ib_media.o 14tipc-$(CONFIG_TIPC_MEDIA_IB) += ib_media.o
14tipc-$(CONFIG_SYSCTL) += sysctl.o 15tipc-$(CONFIG_SYSCTL) += sysctl.o
diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c
index af6deeb397a8..840db89e4283 100644
--- a/net/tipc/bearer.c
+++ b/net/tipc/bearer.c
@@ -48,6 +48,9 @@ static struct tipc_media * const media_info_array[] = {
48#ifdef CONFIG_TIPC_MEDIA_IB 48#ifdef CONFIG_TIPC_MEDIA_IB
49 &ib_media_info, 49 &ib_media_info,
50#endif 50#endif
51#ifdef CONFIG_TIPC_MEDIA_UDP
52 &udp_media_info,
53#endif
51 NULL 54 NULL
52}; 55};
53 56
@@ -216,7 +219,8 @@ void tipc_bearer_remove_dest(struct net *net, u32 bearer_id, u32 dest)
216 * tipc_enable_bearer - enable bearer with the given name 219 * tipc_enable_bearer - enable bearer with the given name
217 */ 220 */
218static int tipc_enable_bearer(struct net *net, const char *name, 221static int tipc_enable_bearer(struct net *net, const char *name,
219 u32 disc_domain, u32 priority) 222 u32 disc_domain, u32 priority,
223 struct nlattr *attr[])
220{ 224{
221 struct tipc_net *tn = net_generic(net, tipc_net_id); 225 struct tipc_net *tn = net_generic(net, tipc_net_id);
222 struct tipc_bearer *b_ptr; 226 struct tipc_bearer *b_ptr;
@@ -304,7 +308,7 @@ restart:
304 308
305 strcpy(b_ptr->name, name); 309 strcpy(b_ptr->name, name);
306 b_ptr->media = m_ptr; 310 b_ptr->media = m_ptr;
307 res = m_ptr->enable_media(net, b_ptr); 311 res = m_ptr->enable_media(net, b_ptr, attr);
308 if (res) { 312 if (res) {
309 pr_warn("Bearer <%s> rejected, enable failure (%d)\n", 313 pr_warn("Bearer <%s> rejected, enable failure (%d)\n",
310 name, -res); 314 name, -res);
@@ -372,7 +376,8 @@ static void bearer_disable(struct net *net, struct tipc_bearer *b_ptr,
372 kfree_rcu(b_ptr, rcu); 376 kfree_rcu(b_ptr, rcu);
373} 377}
374 378
375int tipc_enable_l2_media(struct net *net, struct tipc_bearer *b) 379int tipc_enable_l2_media(struct net *net, struct tipc_bearer *b,
380 struct nlattr *attr[])
376{ 381{
377 struct net_device *dev; 382 struct net_device *dev;
378 char *driver_name = strchr((const char *)b->name, ':') + 1; 383 char *driver_name = strchr((const char *)b->name, ':') + 1;
@@ -791,7 +796,7 @@ int tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info)
791 } 796 }
792 797
793 rtnl_lock(); 798 rtnl_lock();
794 err = tipc_enable_bearer(net, bearer, domain, prio); 799 err = tipc_enable_bearer(net, bearer, domain, prio, attrs);
795 if (err) { 800 if (err) {
796 rtnl_unlock(); 801 rtnl_unlock();
797 return err; 802 return err;
diff --git a/net/tipc/bearer.h b/net/tipc/bearer.h
index 097aff08ad5b..5cad243ee8fc 100644
--- a/net/tipc/bearer.h
+++ b/net/tipc/bearer.h
@@ -41,7 +41,7 @@
41#include <net/genetlink.h> 41#include <net/genetlink.h>
42 42
43#define MAX_BEARERS 2 43#define MAX_BEARERS 2
44#define MAX_MEDIA 2 44#define MAX_MEDIA 3
45#define MAX_NODES 4096 45#define MAX_NODES 4096
46#define WSIZE 32 46#define WSIZE 32
47 47
@@ -59,6 +59,7 @@
59 */ 59 */
60#define TIPC_MEDIA_TYPE_ETH 1 60#define TIPC_MEDIA_TYPE_ETH 1
61#define TIPC_MEDIA_TYPE_IB 2 61#define TIPC_MEDIA_TYPE_IB 2
62#define TIPC_MEDIA_TYPE_UDP 3
62 63
63/** 64/**
64 * struct tipc_node_map - set of node identifiers 65 * struct tipc_node_map - set of node identifiers
@@ -104,7 +105,8 @@ struct tipc_media {
104 int (*send_msg)(struct net *net, struct sk_buff *buf, 105 int (*send_msg)(struct net *net, struct sk_buff *buf,
105 struct tipc_bearer *b_ptr, 106 struct tipc_bearer *b_ptr,
106 struct tipc_media_addr *dest); 107 struct tipc_media_addr *dest);
107 int (*enable_media)(struct net *net, struct tipc_bearer *b_ptr); 108 int (*enable_media)(struct net *net, struct tipc_bearer *b_ptr,
109 struct nlattr *attr[]);
108 void (*disable_media)(struct tipc_bearer *b_ptr); 110 void (*disable_media)(struct tipc_bearer *b_ptr);
109 int (*addr2str)(struct tipc_media_addr *addr, 111 int (*addr2str)(struct tipc_media_addr *addr,
110 char *strbuf, 112 char *strbuf,
@@ -183,6 +185,9 @@ extern struct tipc_media eth_media_info;
183#ifdef CONFIG_TIPC_MEDIA_IB 185#ifdef CONFIG_TIPC_MEDIA_IB
184extern struct tipc_media ib_media_info; 186extern struct tipc_media ib_media_info;
185#endif 187#endif
188#ifdef CONFIG_TIPC_MEDIA_UDP
189extern struct tipc_media udp_media_info;
190#endif
186 191
187int tipc_nl_bearer_disable(struct sk_buff *skb, struct genl_info *info); 192int tipc_nl_bearer_disable(struct sk_buff *skb, struct genl_info *info);
188int tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info); 193int tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info);
@@ -197,7 +202,8 @@ int tipc_nl_media_set(struct sk_buff *skb, struct genl_info *info);
197int tipc_media_set_priority(const char *name, u32 new_value); 202int tipc_media_set_priority(const char *name, u32 new_value);
198int tipc_media_set_window(const char *name, u32 new_value); 203int tipc_media_set_window(const char *name, u32 new_value);
199void tipc_media_addr_printf(char *buf, int len, struct tipc_media_addr *a); 204void tipc_media_addr_printf(char *buf, int len, struct tipc_media_addr *a);
200int tipc_enable_l2_media(struct net *net, struct tipc_bearer *b); 205int tipc_enable_l2_media(struct net *net, struct tipc_bearer *b,
206 struct nlattr *attrs[]);
201void tipc_disable_l2_media(struct tipc_bearer *b); 207void tipc_disable_l2_media(struct tipc_bearer *b);
202int tipc_l2_send_msg(struct net *net, struct sk_buff *buf, 208int tipc_l2_send_msg(struct net *net, struct sk_buff *buf,
203 struct tipc_bearer *b, struct tipc_media_addr *dest); 209 struct tipc_bearer *b, struct tipc_media_addr *dest);
diff --git a/net/tipc/msg.h b/net/tipc/msg.h
index c1cc8d7a5d52..fa167846d1ab 100644
--- a/net/tipc/msg.h
+++ b/net/tipc/msg.h
@@ -87,7 +87,7 @@ struct plist;
87 * Note: Headroom should be a multiple of 4 to ensure the TIPC header fields 87 * Note: Headroom should be a multiple of 4 to ensure the TIPC header fields
88 * are word aligned for quicker access 88 * are word aligned for quicker access
89 */ 89 */
90#define BUF_HEADROOM LL_MAX_HEADER 90#define BUF_HEADROOM (LL_MAX_HEADER + 48)
91 91
92struct tipc_skb_cb { 92struct tipc_skb_cb {
93 void *handle; 93 void *handle;
diff --git a/net/tipc/udp_media.c b/net/tipc/udp_media.c
new file mode 100644
index 000000000000..0d10001db40d
--- /dev/null
+++ b/net/tipc/udp_media.c
@@ -0,0 +1,442 @@
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 <linux/tipc_netlink.h>
48#include "core.h"
49#include "bearer.h"
50
51/* IANA assigned UDP port */
52#define UDP_PORT_DEFAULT 6118
53
54static const struct nla_policy tipc_nl_udp_policy[TIPC_NLA_UDP_MAX + 1] = {
55 [TIPC_NLA_UDP_UNSPEC] = {.type = NLA_UNSPEC},
56 [TIPC_NLA_UDP_LOCAL] = {.type = NLA_BINARY,
57 .len = sizeof(struct sockaddr_storage)},
58 [TIPC_NLA_UDP_REMOTE] = {.type = NLA_BINARY,
59 .len = sizeof(struct sockaddr_storage)},
60};
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 */
68struct udp_media_addr {
69 __be16 proto;
70 __be16 udp_port;
71 union {
72 struct in_addr ipv4;
73 struct in6_addr ipv6;
74 };
75};
76
77/**
78 * struct udp_bearer - ip/udp bearer data structure
79 * @bearer: associated generic tipc bearer
80 * @ubsock: bearer associated socket
81 * @ifindex: local address scope
82 * @work: used to schedule deferred work on a bearer
83 */
84struct udp_bearer {
85 struct tipc_bearer __rcu *bearer;
86 struct socket *ubsock;
87 u32 ifindex;
88 struct work_struct work;
89};
90
91/* udp_media_addr_set - convert a ip/udp address to a TIPC media address */
92static void tipc_udp_media_addr_set(struct tipc_media_addr *addr,
93 struct udp_media_addr *ua)
94{
95 memset(addr, 0, sizeof(struct tipc_media_addr));
96 addr->media_id = TIPC_MEDIA_TYPE_UDP;
97 memcpy(addr->value, ua, sizeof(struct udp_media_addr));
98 if (ntohs(ua->proto) == ETH_P_IP) {
99 if (ipv4_is_multicast(ua->ipv4.s_addr))
100 addr->broadcast = 1;
101 } else if (ntohs(ua->proto) == ETH_P_IPV6) {
102 if (ipv6_addr_type(&ua->ipv6) & IPV6_ADDR_MULTICAST)
103 addr->broadcast = 1;
104 } else {
105 pr_err("Invalid UDP media address\n");
106 }
107}
108
109/* tipc_udp_addr2str - convert ip/udp address to string */
110static int tipc_udp_addr2str(struct tipc_media_addr *a, char *buf, int size)
111{
112 struct udp_media_addr *ua = (struct udp_media_addr *)&a->value;
113
114 if (ntohs(ua->proto) == ETH_P_IP)
115 snprintf(buf, size, "%pI4:%u", &ua->ipv4, ntohs(ua->udp_port));
116 else if (ntohs(ua->proto) == ETH_P_IPV6)
117 snprintf(buf, size, "%pI6:%u", &ua->ipv6, ntohs(ua->udp_port));
118 else
119 pr_err("Invalid UDP media address\n");
120 return 0;
121}
122
123/* tipc_udp_msg2addr - extract an ip/udp address from a TIPC ndisc message */
124static int tipc_udp_msg2addr(struct tipc_bearer *b, struct tipc_media_addr *a,
125 char *msg)
126{
127 struct udp_media_addr *ua;
128
129 ua = (struct udp_media_addr *) (msg + TIPC_MEDIA_ADDR_OFFSET);
130 if (msg[TIPC_MEDIA_TYPE_OFFSET] != TIPC_MEDIA_TYPE_UDP)
131 return -EINVAL;
132 tipc_udp_media_addr_set(a, ua);
133 return 0;
134}
135
136/* tipc_udp_addr2msg - write an ip/udp address to a TIPC ndisc message */
137static int tipc_udp_addr2msg(char *msg, struct tipc_media_addr *a)
138{
139 memset(msg, 0, TIPC_MEDIA_INFO_SIZE);
140 msg[TIPC_MEDIA_TYPE_OFFSET] = TIPC_MEDIA_TYPE_UDP;
141 memcpy(msg + TIPC_MEDIA_ADDR_OFFSET, a->value,
142 sizeof(struct udp_media_addr));
143 return 0;
144}
145
146/* tipc_send_msg - enqueue a send request */
147static int tipc_udp_send_msg(struct net *net, struct sk_buff *skb,
148 struct tipc_bearer *b,
149 struct tipc_media_addr *dest)
150{
151 int ttl, err = 0;
152 struct udp_bearer *ub;
153 struct udp_media_addr *dst = (struct udp_media_addr *)&dest->value;
154 struct udp_media_addr *src = (struct udp_media_addr *)&b->addr.value;
155 struct sk_buff *clone;
156 struct rtable *rt;
157
158 clone = skb_clone(skb, GFP_ATOMIC);
159 skb_set_inner_protocol(clone, htons(ETH_P_TIPC));
160 ub = rcu_dereference_rtnl(b->media_ptr);
161 if (!ub) {
162 err = -ENODEV;
163 goto tx_error;
164 }
165 if (htons(dst->proto) == ETH_P_IP) {
166 struct flowi4 fl = {
167 .daddr = dst->ipv4.s_addr,
168 .saddr = src->ipv4.s_addr,
169 .flowi4_mark = clone->mark,
170 .flowi4_proto = IPPROTO_UDP
171 };
172 rt = ip_route_output_key(net, &fl);
173 if (IS_ERR(rt)) {
174 err = PTR_ERR(rt);
175 goto tx_error;
176 }
177 ttl = ip4_dst_hoplimit(&rt->dst);
178 err = udp_tunnel_xmit_skb(rt, clone, src->ipv4.s_addr,
179 dst->ipv4.s_addr, 0, ttl, 0,
180 src->udp_port, dst->udp_port,
181 false, true);
182 if (err < 0) {
183 ip_rt_put(rt);
184 goto tx_error;
185 }
186#if IS_ENABLED(CONFIG_IPV6)
187 } else {
188 struct dst_entry *ndst;
189 struct flowi6 fl6 = {
190 .flowi6_oif = ub->ifindex,
191 .daddr = dst->ipv6,
192 .saddr = src->ipv6,
193 .flowi6_proto = IPPROTO_UDP
194 };
195 err = ip6_dst_lookup(ub->ubsock->sk, &ndst, &fl6);
196 if (err)
197 goto tx_error;
198 ttl = ip6_dst_hoplimit(ndst);
199 err = udp_tunnel6_xmit_skb(ndst, clone, ndst->dev, &src->ipv6,
200 &dst->ipv6, 0, ttl, src->udp_port,
201 dst->udp_port, false);
202#endif
203 }
204 return err;
205
206tx_error:
207 kfree_skb(clone);
208 return err;
209}
210
211/* tipc_udp_recv - read data from bearer socket */
212static int tipc_udp_recv(struct sock *sk, struct sk_buff *skb)
213{
214 struct udp_bearer *ub;
215 struct tipc_bearer *b;
216
217 ub = rcu_dereference_sk_user_data(sk);
218 if (!ub) {
219 pr_err_ratelimited("Failed to get UDP bearer reference");
220 kfree_skb(skb);
221 return 0;
222 }
223
224 skb_pull(skb, sizeof(struct udphdr));
225 rcu_read_lock();
226 b = rcu_dereference_rtnl(ub->bearer);
227
228 if (b) {
229 tipc_rcv(sock_net(sk), skb, b);
230 rcu_read_unlock();
231 return 0;
232 }
233 rcu_read_unlock();
234 kfree_skb(skb);
235 return 0;
236}
237
238static int enable_mcast(struct udp_bearer *ub, struct udp_media_addr *remote)
239{
240 int err = 0;
241 struct ip_mreqn mreqn;
242 struct sock *sk = ub->ubsock->sk;
243
244 if (ntohs(remote->proto) == ETH_P_IP) {
245 if (!ipv4_is_multicast(remote->ipv4.s_addr))
246 return 0;
247 mreqn.imr_multiaddr = remote->ipv4;
248 mreqn.imr_ifindex = ub->ifindex;
249 err = __ip_mc_join_group(sk, &mreqn);
250 } else {
251 if (!ipv6_addr_is_multicast(&remote->ipv6))
252 return 0;
253 err = __ipv6_sock_mc_join(sk, ub->ifindex, &remote->ipv6);
254 }
255 return err;
256}
257
258/**
259 * parse_options - build local/remote addresses from configuration
260 * @attrs: netlink config data
261 * @ub: UDP bearer instance
262 * @local: local bearer IP address/port
263 * @remote: peer or multicast IP/port
264 */
265static int parse_options(struct nlattr *attrs[], struct udp_bearer *ub,
266 struct udp_media_addr *local,
267 struct udp_media_addr *remote)
268{
269 struct nlattr *opts[TIPC_NLA_UDP_MAX + 1];
270 struct sockaddr_storage *sa_local, *sa_remote;
271
272 if (!attrs[TIPC_NLA_BEARER_UDP_OPTS])
273 goto err;
274 if (nla_parse_nested(opts, TIPC_NLA_UDP_MAX,
275 attrs[TIPC_NLA_BEARER_UDP_OPTS],
276 tipc_nl_udp_policy))
277 goto err;
278 if (opts[TIPC_NLA_UDP_LOCAL] && opts[TIPC_NLA_UDP_REMOTE]) {
279 sa_local = nla_data(opts[TIPC_NLA_UDP_LOCAL]);
280 sa_remote = nla_data(opts[TIPC_NLA_UDP_REMOTE]);
281 } else {
282err:
283 pr_err("Invalid UDP bearer configuration");
284 return -EINVAL;
285 }
286 if ((sa_local->ss_family & sa_remote->ss_family) == AF_INET) {
287 struct sockaddr_in *ip4;
288
289 ip4 = (struct sockaddr_in *)sa_local;
290 local->proto = htons(ETH_P_IP);
291 local->udp_port = ip4->sin_port;
292 local->ipv4.s_addr = ip4->sin_addr.s_addr;
293
294 ip4 = (struct sockaddr_in *)sa_remote;
295 remote->proto = htons(ETH_P_IP);
296 remote->udp_port = ip4->sin_port;
297 remote->ipv4.s_addr = ip4->sin_addr.s_addr;
298 return 0;
299
300#if IS_ENABLED(CONFIG_IPV6)
301 } else if ((sa_local->ss_family & sa_remote->ss_family) == AF_INET6) {
302 struct sockaddr_in6 *ip6;
303
304 ip6 = (struct sockaddr_in6 *)sa_local;
305 local->proto = htons(ETH_P_IPV6);
306 local->udp_port = ip6->sin6_port;
307 local->ipv6 = ip6->sin6_addr;
308 ub->ifindex = ip6->sin6_scope_id;
309
310 ip6 = (struct sockaddr_in6 *)sa_remote;
311 remote->proto = htons(ETH_P_IPV6);
312 remote->udp_port = ip6->sin6_port;
313 remote->ipv6 = ip6->sin6_addr;
314 return 0;
315#endif
316 }
317 return -EADDRNOTAVAIL;
318}
319
320/**
321 * tipc_udp_enable - callback to create a new udp bearer instance
322 * @net: network namespace
323 * @b: pointer to generic tipc_bearer
324 * @attrs: netlink bearer configuration
325 *
326 * validate the bearer parameters and initialize the udp bearer
327 * rtnl_lock should be held
328 */
329static int tipc_udp_enable(struct net *net, struct tipc_bearer *b,
330 struct nlattr *attrs[])
331{
332 int err = -EINVAL;
333 struct udp_bearer *ub;
334 struct udp_media_addr *remote;
335 struct udp_media_addr local = {0};
336 struct udp_port_cfg udp_conf = {0};
337 struct udp_tunnel_sock_cfg tuncfg = {0};
338
339 ub = kzalloc(sizeof(*ub), GFP_ATOMIC);
340 if (!ub)
341 return -ENOMEM;
342
343 remote = (struct udp_media_addr *)&b->bcast_addr.value;
344 memset(remote, 0, sizeof(struct udp_media_addr));
345 err = parse_options(attrs, ub, &local, remote);
346 if (err)
347 goto err;
348
349 b->bcast_addr.media_id = TIPC_MEDIA_TYPE_UDP;
350 b->bcast_addr.broadcast = 1;
351 rcu_assign_pointer(b->media_ptr, ub);
352 rcu_assign_pointer(ub->bearer, b);
353 tipc_udp_media_addr_set(&b->addr, &local);
354 if (htons(local.proto) == ETH_P_IP) {
355 struct net_device *dev;
356
357 dev = __ip_dev_find(net, local.ipv4.s_addr, false);
358 if (!dev) {
359 err = -ENODEV;
360 goto err;
361 }
362 udp_conf.family = AF_INET;
363 udp_conf.local_ip.s_addr = htonl(INADDR_ANY);
364 udp_conf.use_udp_checksums = false;
365 ub->ifindex = dev->ifindex;
366 b->mtu = dev->mtu - sizeof(struct iphdr)
367 - sizeof(struct udphdr);
368#if IS_ENABLED(CONFIG_IPV6)
369 } else if (htons(local.proto) == ETH_P_IPV6) {
370 udp_conf.family = AF_INET6;
371 udp_conf.use_udp6_tx_checksums = true;
372 udp_conf.use_udp6_rx_checksums = true;
373 udp_conf.local_ip6 = in6addr_any;
374 b->mtu = 1280;
375#endif
376 } else {
377 err = -EAFNOSUPPORT;
378 goto err;
379 }
380 udp_conf.local_udp_port = local.udp_port;
381 err = udp_sock_create(net, &udp_conf, &ub->ubsock);
382 if (err)
383 goto err;
384 tuncfg.sk_user_data = ub;
385 tuncfg.encap_type = 1;
386 tuncfg.encap_rcv = tipc_udp_recv;
387 tuncfg.encap_destroy = NULL;
388 setup_udp_tunnel_sock(net, ub->ubsock, &tuncfg);
389
390 if (enable_mcast(ub, remote))
391 goto err;
392 return 0;
393err:
394 kfree(ub);
395 return err;
396}
397
398/* cleanup_bearer - break the socket/bearer association */
399static void cleanup_bearer(struct work_struct *work)
400{
401 struct udp_bearer *ub = container_of(work, struct udp_bearer, work);
402
403 if (ub->ubsock)
404 udp_tunnel_sock_release(ub->ubsock);
405 synchronize_net();
406 kfree(ub);
407}
408
409/* tipc_udp_disable - detach bearer from socket */
410static void tipc_udp_disable(struct tipc_bearer *b)
411{
412 struct udp_bearer *ub;
413
414 ub = rcu_dereference_rtnl(b->media_ptr);
415 if (!ub) {
416 pr_err("UDP bearer instance not found\n");
417 return;
418 }
419 if (ub->ubsock)
420 sock_set_flag(ub->ubsock->sk, SOCK_DEAD);
421 RCU_INIT_POINTER(b->media_ptr, NULL);
422 RCU_INIT_POINTER(ub->bearer, NULL);
423
424 /* sock_release need to be done outside of rtnl lock */
425 INIT_WORK(&ub->work, cleanup_bearer);
426 schedule_work(&ub->work);
427}
428
429struct tipc_media udp_media_info = {
430 .send_msg = tipc_udp_send_msg,
431 .enable_media = tipc_udp_enable,
432 .disable_media = tipc_udp_disable,
433 .addr2str = tipc_udp_addr2str,
434 .addr2msg = tipc_udp_addr2msg,
435 .msg2addr = tipc_udp_msg2addr,
436 .priority = TIPC_DEF_LINK_PRI,
437 .tolerance = TIPC_DEF_LINK_TOL,
438 .window = TIPC_DEF_LINK_WIN,
439 .type_id = TIPC_MEDIA_TYPE_UDP,
440 .hwaddr_len = 0,
441 .name = "udp"
442};