blob: 0d10001db40dc406114de911c45c43034640869c [file] [log] [blame]
Erik Hugned0f91932015-03-05 10:23:49 +01001/* 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};