Blame view

net/tipc/udp_media.c 20.9 KB
d0f91938b   Erik Hugne   tipc: add ip/udp ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
  /* net/tipc/udp_media.c: IP bearer support for TIPC
   *
   * Copyright (c) 2015, Ericsson AB
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in the
   *    documentation and/or other materials provided with the distribution.
   * 3. Neither the names of the copyright holders nor the names of its
   *    contributors may be used to endorse or promote products derived from
   *    this software without specific prior written permission.
   *
   * Alternatively, this software may be distributed under the terms of the
   * GNU General Public License ("GPL") version 2 as published by the Free
   * Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   * POSSIBILITY OF SUCH DAMAGE.
   */
  
  #include <linux/socket.h>
  #include <linux/ip.h>
  #include <linux/udp.h>
  #include <linux/inet.h>
  #include <linux/inetdevice.h>
  #include <linux/igmp.h>
  #include <linux/kernel.h>
  #include <linux/workqueue.h>
  #include <linux/list.h>
  #include <net/sock.h>
  #include <net/ip.h>
  #include <net/udp_tunnel.h>
3616d08bc   David Ahern   ipv6: Move ipv6 s...
47
  #include <net/ipv6_stubs.h>
d0f91938b   Erik Hugne   tipc: add ip/udp ...
48
49
  #include <linux/tipc_netlink.h>
  #include "core.h"
52dfae5c8   Jon Maloy   tipc: obtain node...
50
51
  #include "addr.h"
  #include "net.h"
d0f91938b   Erik Hugne   tipc: add ip/udp ...
52
  #include "bearer.h"
49cc66eae   Richard Alpe   tipc: move netlin...
53
  #include "netlink.h"
ef20cd4dd   Richard Alpe   tipc: introduce U...
54
  #include "msg.h"
d0f91938b   Erik Hugne   tipc: add ip/udp ...
55
56
57
  
  /* IANA assigned UDP port */
  #define UDP_PORT_DEFAULT	6118
9bd160bfa   Richard Alpe   tipc: make sure I...
58
  #define UDP_MIN_HEADROOM        48
e53567948   Jon Paul Maloy   tipc: conditional...
59

d0f91938b   Erik Hugne   tipc: add ip/udp ...
60
61
62
63
64
65
66
67
  /**
   * struct udp_media_addr - IP/UDP addressing information
   *
   * This is the bearer level originating address used in neighbor discovery
   * messages, and all fields should be in network byte order
   */
  struct udp_media_addr {
  	__be16	proto;
bc3a334cc   Richard Alpe   tipc: rename udp_...
68
  	__be16	port;
d0f91938b   Erik Hugne   tipc: add ip/udp ...
69
70
71
72
73
  	union {
  		struct in_addr ipv4;
  		struct in6_addr ipv6;
  	};
  };
ef20cd4dd   Richard Alpe   tipc: introduce U...
74
75
76
  /* struct udp_replicast - container for UDP remote addresses */
  struct udp_replicast {
  	struct udp_media_addr addr;
e9c1a7932   Xin Long   tipc: add dst_cac...
77
  	struct dst_cache dst_cache;
ef20cd4dd   Richard Alpe   tipc: introduce U...
78
79
80
  	struct rcu_head rcu;
  	struct list_head list;
  };
d0f91938b   Erik Hugne   tipc: add ip/udp ...
81
82
83
84
85
86
87
88
89
90
91
92
  /**
   * struct udp_bearer - ip/udp bearer data structure
   * @bearer:	associated generic tipc bearer
   * @ubsock:	bearer associated socket
   * @ifindex:	local address scope
   * @work:	used to schedule deferred work on a bearer
   */
  struct udp_bearer {
  	struct tipc_bearer __rcu *bearer;
  	struct socket *ubsock;
  	u32 ifindex;
  	struct work_struct work;
ef20cd4dd   Richard Alpe   tipc: introduce U...
93
  	struct udp_replicast rcast;
d0f91938b   Erik Hugne   tipc: add ip/udp ...
94
  };
1ca73e3fa   Richard Alpe   tipc: refactor mu...
95
96
97
98
99
100
101
102
103
104
  static int tipc_udp_is_mcast_addr(struct udp_media_addr *addr)
  {
  	if (ntohs(addr->proto) == ETH_P_IP)
  		return ipv4_is_multicast(addr->ipv4.s_addr);
  #if IS_ENABLED(CONFIG_IPV6)
  	else
  		return ipv6_addr_is_multicast(&addr->ipv6);
  #endif
  	return 0;
  }
d0f91938b   Erik Hugne   tipc: add ip/udp ...
105
106
107
108
109
110
111
  /* udp_media_addr_set - convert a ip/udp address to a TIPC media address */
  static void tipc_udp_media_addr_set(struct tipc_media_addr *addr,
  				    struct udp_media_addr *ua)
  {
  	memset(addr, 0, sizeof(struct tipc_media_addr));
  	addr->media_id = TIPC_MEDIA_TYPE_UDP;
  	memcpy(addr->value, ua, sizeof(struct udp_media_addr));
1ca73e3fa   Richard Alpe   tipc: refactor mu...
112
113
  
  	if (tipc_udp_is_mcast_addr(ua))
9999974a8   Jon Paul Maloy   tipc: add functio...
114
  		addr->broadcast = TIPC_BROADCAST_SUPPORT;
d0f91938b   Erik Hugne   tipc: add ip/udp ...
115
116
117
118
119
120
121
122
  }
  
  /* tipc_udp_addr2str - convert ip/udp address to string */
  static int tipc_udp_addr2str(struct tipc_media_addr *a, char *buf, int size)
  {
  	struct udp_media_addr *ua = (struct udp_media_addr *)&a->value;
  
  	if (ntohs(ua->proto) == ETH_P_IP)
bc3a334cc   Richard Alpe   tipc: rename udp_...
123
  		snprintf(buf, size, "%pI4:%u", &ua->ipv4, ntohs(ua->port));
d0f91938b   Erik Hugne   tipc: add ip/udp ...
124
  	else if (ntohs(ua->proto) == ETH_P_IPV6)
bc3a334cc   Richard Alpe   tipc: rename udp_...
125
  		snprintf(buf, size, "%pI6:%u", &ua->ipv6, ntohs(ua->port));
d0f91938b   Erik Hugne   tipc: add ip/udp ...
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
  	else
  		pr_err("Invalid UDP media address
  ");
  	return 0;
  }
  
  /* tipc_udp_msg2addr - extract an ip/udp address from a TIPC ndisc message */
  static int tipc_udp_msg2addr(struct tipc_bearer *b, struct tipc_media_addr *a,
  			     char *msg)
  {
  	struct udp_media_addr *ua;
  
  	ua = (struct udp_media_addr *) (msg + TIPC_MEDIA_ADDR_OFFSET);
  	if (msg[TIPC_MEDIA_TYPE_OFFSET] != TIPC_MEDIA_TYPE_UDP)
  		return -EINVAL;
  	tipc_udp_media_addr_set(a, ua);
  	return 0;
  }
  
  /* tipc_udp_addr2msg - write an ip/udp address to a TIPC ndisc message */
  static int tipc_udp_addr2msg(char *msg, struct tipc_media_addr *a)
  {
  	memset(msg, 0, TIPC_MEDIA_INFO_SIZE);
  	msg[TIPC_MEDIA_TYPE_OFFSET] = TIPC_MEDIA_TYPE_UDP;
  	memcpy(msg + TIPC_MEDIA_ADDR_OFFSET, a->value,
  	       sizeof(struct udp_media_addr));
  	return 0;
  }
  
  /* tipc_send_msg - enqueue a send request */
ce984da36   Richard Alpe   tipc: split UDP s...
156
157
  static int tipc_udp_xmit(struct net *net, struct sk_buff *skb,
  			 struct udp_bearer *ub, struct udp_media_addr *src,
e9c1a7932   Xin Long   tipc: add dst_cac...
158
  			 struct udp_media_addr *dst, struct dst_cache *cache)
d0f91938b   Erik Hugne   tipc: add ip/udp ...
159
  {
e9c1a7932   Xin Long   tipc: add dst_cac...
160
  	struct dst_entry *ndst = dst_cache_get(cache);
d0f91938b   Erik Hugne   tipc: add ip/udp ...
161
  	int ttl, err = 0;
d0f91938b   Erik Hugne   tipc: add ip/udp ...
162

4fee6be81   Erik Hugne   tipc: sparse: fix...
163
  	if (dst->proto == htons(ETH_P_IP)) {
e9c1a7932   Xin Long   tipc: add dst_cac...
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
  		struct rtable *rt = (struct rtable *)ndst;
  
  		if (!rt) {
  			struct flowi4 fl = {
  				.daddr = dst->ipv4.s_addr,
  				.saddr = src->ipv4.s_addr,
  				.flowi4_mark = skb->mark,
  				.flowi4_proto = IPPROTO_UDP
  			};
  			rt = ip_route_output_key(net, &fl);
  			if (IS_ERR(rt)) {
  				err = PTR_ERR(rt);
  				goto tx_error;
  			}
  			dst_cache_set_ip4(cache, &rt->dst, fl.saddr);
d0f91938b   Erik Hugne   tipc: add ip/udp ...
179
  		}
9b3009604   Richard Alpe   tipc: add net dev...
180

d0f91938b   Erik Hugne   tipc: add ip/udp ...
181
  		ttl = ip4_dst_hoplimit(&rt->dst);
039f50629   Pravin B Shelar   ip_tunnel: Move s...
182
  		udp_tunnel_xmit_skb(rt, ub->ubsock->sk, skb, src->ipv4.s_addr,
bc3a334cc   Richard Alpe   tipc: rename udp_...
183
184
  				    dst->ipv4.s_addr, 0, ttl, 0, src->port,
  				    dst->port, false, true);
d0f91938b   Erik Hugne   tipc: add ip/udp ...
185
186
  #if IS_ENABLED(CONFIG_IPV6)
  	} else {
e9c1a7932   Xin Long   tipc: add dst_cac...
187
188
189
190
191
192
193
  		if (!ndst) {
  			struct flowi6 fl6 = {
  				.flowi6_oif = ub->ifindex,
  				.daddr = dst->ipv6,
  				.saddr = src->ipv6,
  				.flowi6_proto = IPPROTO_UDP
  			};
48d58ae9e   Sabrina Dubroca   net: ipv6_stub: u...
194
195
196
197
198
  			ndst = ipv6_stub->ipv6_dst_lookup_flow(net,
  							       ub->ubsock->sk,
  							       &fl6, NULL);
  			if (IS_ERR(ndst)) {
  				err = PTR_ERR(ndst);
e9c1a7932   Xin Long   tipc: add dst_cac...
199
  				goto tx_error;
48d58ae9e   Sabrina Dubroca   net: ipv6_stub: u...
200
  			}
e9c1a7932   Xin Long   tipc: add dst_cac...
201
202
  			dst_cache_set_ip6(cache, ndst, &fl6.saddr);
  		}
d0f91938b   Erik Hugne   tipc: add ip/udp ...
203
  		ttl = ip6_dst_hoplimit(ndst);
c3bcde026   Xin Long   tipc: pass tunnel...
204
205
206
  		err = udp_tunnel6_xmit_skb(ndst, ub->ubsock->sk, skb, NULL,
  					   &src->ipv6, &dst->ipv6, 0, ttl, 0,
  					   src->port, dst->port, false);
d0f91938b   Erik Hugne   tipc: add ip/udp ...
207
208
209
210
211
  #endif
  	}
  	return err;
  
  tx_error:
7214bcf87   Jon Paul Maloy   tipc: eliminate r...
212
  	kfree_skb(skb);
d0f91938b   Erik Hugne   tipc: add ip/udp ...
213
214
  	return err;
  }
ce984da36   Richard Alpe   tipc: split UDP s...
215
216
217
218
219
220
  static int tipc_udp_send_msg(struct net *net, struct sk_buff *skb,
  			     struct tipc_bearer *b,
  			     struct tipc_media_addr *addr)
  {
  	struct udp_media_addr *src = (struct udp_media_addr *)&b->addr.value;
  	struct udp_media_addr *dst = (struct udp_media_addr *)&addr->value;
ef20cd4dd   Richard Alpe   tipc: introduce U...
221
  	struct udp_replicast *rcast;
ce984da36   Richard Alpe   tipc: split UDP s...
222
223
224
225
226
227
  	struct udp_bearer *ub;
  	int err = 0;
  
  	if (skb_headroom(skb) < UDP_MIN_HEADROOM) {
  		err = pskb_expand_head(skb, UDP_MIN_HEADROOM, 0, GFP_ATOMIC);
  		if (err)
ef20cd4dd   Richard Alpe   tipc: introduce U...
228
  			goto out;
ce984da36   Richard Alpe   tipc: split UDP s...
229
230
231
  	}
  
  	skb_set_inner_protocol(skb, htons(ETH_P_TIPC));
30a4616c1   Xin Long   tipc: use rcu der...
232
  	ub = rcu_dereference(b->media_ptr);
ce984da36   Richard Alpe   tipc: split UDP s...
233
234
  	if (!ub) {
  		err = -ENODEV;
ef20cd4dd   Richard Alpe   tipc: introduce U...
235
  		goto out;
ce984da36   Richard Alpe   tipc: split UDP s...
236
  	}
9999974a8   Jon Paul Maloy   tipc: add functio...
237
  	if (addr->broadcast != TIPC_REPLICAST_SUPPORT)
e9c1a7932   Xin Long   tipc: add dst_cac...
238
239
  		return tipc_udp_xmit(net, skb, ub, src, dst,
  				     &ub->rcast.dst_cache);
ce984da36   Richard Alpe   tipc: split UDP s...
240

ef20cd4dd   Richard Alpe   tipc: introduce U...
241
242
243
244
245
246
247
248
249
  	/* Replicast, send an skb to each configured IP address */
  	list_for_each_entry_rcu(rcast, &ub->rcast.list, list) {
  		struct sk_buff *_skb;
  
  		_skb = pskb_copy(skb, GFP_ATOMIC);
  		if (!_skb) {
  			err = -ENOMEM;
  			goto out;
  		}
e9c1a7932   Xin Long   tipc: add dst_cac...
250
251
  		err = tipc_udp_xmit(net, _skb, ub, src, &rcast->addr,
  				    &rcast->dst_cache);
acb4a33e9   Cong Wang   tipc: fix a doubl...
252
  		if (err)
ef20cd4dd   Richard Alpe   tipc: introduce U...
253
  			goto out;
ef20cd4dd   Richard Alpe   tipc: introduce U...
254
255
256
  	}
  	err = 0;
  out:
ce984da36   Richard Alpe   tipc: split UDP s...
257
258
259
  	kfree_skb(skb);
  	return err;
  }
c9b64d492   Richard Alpe   tipc: add replica...
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
  static bool tipc_udp_is_known_peer(struct tipc_bearer *b,
  				   struct udp_media_addr *addr)
  {
  	struct udp_replicast *rcast, *tmp;
  	struct udp_bearer *ub;
  
  	ub = rcu_dereference_rtnl(b->media_ptr);
  	if (!ub) {
  		pr_err_ratelimited("UDP bearer instance not found
  ");
  		return false;
  	}
  
  	list_for_each_entry_safe(rcast, tmp, &ub->rcast.list, list) {
  		if (!memcmp(&rcast->addr, addr, sizeof(struct udp_media_addr)))
  			return true;
  	}
  
  	return false;
  }
ef20cd4dd   Richard Alpe   tipc: introduce U...
280
281
282
283
284
285
286
287
288
289
290
291
292
  static int tipc_udp_rcast_add(struct tipc_bearer *b,
  			      struct udp_media_addr *addr)
  {
  	struct udp_replicast *rcast;
  	struct udp_bearer *ub;
  
  	ub = rcu_dereference_rtnl(b->media_ptr);
  	if (!ub)
  		return -ENODEV;
  
  	rcast = kmalloc(sizeof(*rcast), GFP_ATOMIC);
  	if (!rcast)
  		return -ENOMEM;
e9c1a7932   Xin Long   tipc: add dst_cac...
293
294
295
296
  	if (dst_cache_init(&rcast->dst_cache, GFP_ATOMIC)) {
  		kfree(rcast);
  		return -ENOMEM;
  	}
ef20cd4dd   Richard Alpe   tipc: introduce U...
297
298
299
300
301
302
303
304
305
306
  	memcpy(&rcast->addr, addr, sizeof(struct udp_media_addr));
  
  	if (ntohs(addr->proto) == ETH_P_IP)
  		pr_info("New replicast peer: %pI4
  ", &rcast->addr.ipv4);
  #if IS_ENABLED(CONFIG_IPV6)
  	else if (ntohs(addr->proto) == ETH_P_IPV6)
  		pr_info("New replicast peer: %pI6
  ", &rcast->addr.ipv6);
  #endif
9999974a8   Jon Paul Maloy   tipc: add functio...
307
  	b->bcast_addr.broadcast = TIPC_REPLICAST_SUPPORT;
ef20cd4dd   Richard Alpe   tipc: introduce U...
308
309
310
  	list_add_rcu(&rcast->list, &ub->rcast.list);
  	return 0;
  }
c9b64d492   Richard Alpe   tipc: add replica...
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
  static int tipc_udp_rcast_disc(struct tipc_bearer *b, struct sk_buff *skb)
  {
  	struct udp_media_addr src = {0};
  	struct udp_media_addr *dst;
  
  	dst = (struct udp_media_addr *)&b->bcast_addr.value;
  	if (tipc_udp_is_mcast_addr(dst))
  		return 0;
  
  	src.port = udp_hdr(skb)->source;
  
  	if (ip_hdr(skb)->version == 4) {
  		struct iphdr *iphdr = ip_hdr(skb);
  
  		src.proto = htons(ETH_P_IP);
  		src.ipv4.s_addr = iphdr->saddr;
  		if (ipv4_is_multicast(iphdr->daddr))
  			return 0;
  #if IS_ENABLED(CONFIG_IPV6)
  	} else if (ip_hdr(skb)->version == 6) {
  		struct ipv6hdr *iphdr = ipv6_hdr(skb);
  
  		src.proto = htons(ETH_P_IPV6);
  		src.ipv6 = iphdr->saddr;
  		if (ipv6_addr_is_multicast(&iphdr->daddr))
  			return 0;
  #endif
  	} else {
  		return 0;
  	}
  
  	if (likely(tipc_udp_is_known_peer(b, &src)))
  		return 0;
  
  	return tipc_udp_rcast_add(b, &src);
  }
d0f91938b   Erik Hugne   tipc: add ip/udp ...
347
348
349
350
351
  /* tipc_udp_recv - read data from bearer socket */
  static int tipc_udp_recv(struct sock *sk, struct sk_buff *skb)
  {
  	struct udp_bearer *ub;
  	struct tipc_bearer *b;
c9b64d492   Richard Alpe   tipc: add replica...
352
353
  	struct tipc_msg *hdr;
  	int err;
d0f91938b   Erik Hugne   tipc: add ip/udp ...
354
355
356
357
  
  	ub = rcu_dereference_sk_user_data(sk);
  	if (!ub) {
  		pr_err_ratelimited("Failed to get UDP bearer reference");
c9b64d492   Richard Alpe   tipc: add replica...
358
  		goto out;
d0f91938b   Erik Hugne   tipc: add ip/udp ...
359
  	}
d0f91938b   Erik Hugne   tipc: add ip/udp ...
360
  	skb_pull(skb, sizeof(struct udphdr));
c9b64d492   Richard Alpe   tipc: add replica...
361
  	hdr = buf_msg(skb);
4109a2c3b   Eric Dumazet   tipc: tipc_udp_re...
362
  	b = rcu_dereference(ub->bearer);
c9b64d492   Richard Alpe   tipc: add replica...
363
  	if (!b)
4109a2c3b   Eric Dumazet   tipc: tipc_udp_re...
364
  		goto out;
d0f91938b   Erik Hugne   tipc: add ip/udp ...
365

0d051bf93   Jon Paul Maloy   tipc: make bearer...
366
  	if (b && test_bit(0, &b->up)) {
d0f91938b   Erik Hugne   tipc: add ip/udp ...
367
  		tipc_rcv(sock_net(sk), skb, b);
d0f91938b   Erik Hugne   tipc: add ip/udp ...
368
369
  		return 0;
  	}
c9b64d492   Richard Alpe   tipc: add replica...
370
371
372
373
  
  	if (unlikely(msg_user(hdr) == LINK_CONFIG)) {
  		err = tipc_udp_rcast_disc(b, skb);
  		if (err)
4109a2c3b   Eric Dumazet   tipc: tipc_udp_re...
374
  			goto out;
c9b64d492   Richard Alpe   tipc: add replica...
375
  	}
c9b64d492   Richard Alpe   tipc: add replica...
376
  out:
d0f91938b   Erik Hugne   tipc: add ip/udp ...
377
378
379
380
381
382
383
384
385
386
387
  	kfree_skb(skb);
  	return 0;
  }
  
  static int enable_mcast(struct udp_bearer *ub, struct udp_media_addr *remote)
  {
  	int err = 0;
  	struct ip_mreqn mreqn;
  	struct sock *sk = ub->ubsock->sk;
  
  	if (ntohs(remote->proto) == ETH_P_IP) {
d0f91938b   Erik Hugne   tipc: add ip/udp ...
388
389
  		mreqn.imr_multiaddr = remote->ipv4;
  		mreqn.imr_ifindex = ub->ifindex;
54ff9ef36   Marcelo Ricardo Leitner   ipv4, ipv6: kill ...
390
  		err = ip_mc_join_group(sk, &mreqn);
446981e5f   Marcelo Ricardo Leitner   tipc: fix build i...
391
  #if IS_ENABLED(CONFIG_IPV6)
d0f91938b   Erik Hugne   tipc: add ip/udp ...
392
  	} else {
446981e5f   Marcelo Ricardo Leitner   tipc: fix build i...
393
394
395
  		err = ipv6_stub->ipv6_sock_mc_join(sk, ub->ifindex,
  						   &remote->ipv6);
  #endif
d0f91938b   Erik Hugne   tipc: add ip/udp ...
396
397
398
  	}
  	return err;
  }
fdb3accc2   Richard Alpe   tipc: add the abi...
399
400
401
402
403
  static int __tipc_nl_add_udp_addr(struct sk_buff *skb,
  				  struct udp_media_addr *addr, int nla_t)
  {
  	if (ntohs(addr->proto) == ETH_P_IP) {
  		struct sockaddr_in ip4;
730761624   Dan Carpenter   tipc: info leak i...
404
  		memset(&ip4, 0, sizeof(ip4));
fdb3accc2   Richard Alpe   tipc: add the abi...
405
406
407
408
409
410
411
412
413
  		ip4.sin_family = AF_INET;
  		ip4.sin_port = addr->port;
  		ip4.sin_addr.s_addr = addr->ipv4.s_addr;
  		if (nla_put(skb, nla_t, sizeof(ip4), &ip4))
  			return -EMSGSIZE;
  
  #if IS_ENABLED(CONFIG_IPV6)
  	} else if (ntohs(addr->proto) == ETH_P_IPV6) {
  		struct sockaddr_in6 ip6;
730761624   Dan Carpenter   tipc: info leak i...
414
  		memset(&ip6, 0, sizeof(ip6));
fdb3accc2   Richard Alpe   tipc: add the abi...
415
416
417
418
419
420
421
422
423
424
  		ip6.sin6_family = AF_INET6;
  		ip6.sin6_port  = addr->port;
  		memcpy(&ip6.sin6_addr, &addr->ipv6, sizeof(struct in6_addr));
  		if (nla_put(skb, nla_t, sizeof(ip6), &ip6))
  			return -EMSGSIZE;
  #endif
  	}
  
  	return 0;
  }
832629ca5   Richard Alpe   tipc: add UDP rem...
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
  int tipc_udp_nl_dump_remoteip(struct sk_buff *skb, struct netlink_callback *cb)
  {
  	u32 bid = cb->args[0];
  	u32 skip_cnt = cb->args[1];
  	u32 portid = NETLINK_CB(cb->skb).portid;
  	struct udp_replicast *rcast, *tmp;
  	struct tipc_bearer *b;
  	struct udp_bearer *ub;
  	void *hdr;
  	int err;
  	int i;
  
  	if (!bid && !skip_cnt) {
  		struct net *net = sock_net(skb->sk);
  		struct nlattr *battrs[TIPC_NLA_BEARER_MAX + 1];
  		struct nlattr **attrs;
  		char *bname;
  
  		err = tipc_nlmsg_parse(cb->nlh, &attrs);
  		if (err)
  			return err;
  
  		if (!attrs[TIPC_NLA_BEARER])
  			return -EINVAL;
8cb081746   Johannes Berg   netlink: make val...
449
450
451
  		err = nla_parse_nested_deprecated(battrs, TIPC_NLA_BEARER_MAX,
  						  attrs[TIPC_NLA_BEARER],
  						  tipc_nl_bearer_policy, NULL);
832629ca5   Richard Alpe   tipc: add UDP rem...
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
  		if (err)
  			return err;
  
  		if (!battrs[TIPC_NLA_BEARER_NAME])
  			return -EINVAL;
  
  		bname = nla_data(battrs[TIPC_NLA_BEARER_NAME]);
  
  		rtnl_lock();
  		b = tipc_bearer_find(net, bname);
  		if (!b) {
  			rtnl_unlock();
  			return -EINVAL;
  		}
  		bid = b->identity;
  	} else {
  		struct net *net = sock_net(skb->sk);
  		struct tipc_net *tn = net_generic(net, tipc_net_id);
  
  		rtnl_lock();
  		b = rtnl_dereference(tn->bearer_list[bid]);
  		if (!b) {
  			rtnl_unlock();
  			return -EINVAL;
  		}
  	}
30a4616c1   Xin Long   tipc: use rcu der...
478
  	ub = rtnl_dereference(b->media_ptr);
832629ca5   Richard Alpe   tipc: add UDP rem...
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
  	if (!ub) {
  		rtnl_unlock();
  		return -EINVAL;
  	}
  
  	i = 0;
  	list_for_each_entry_safe(rcast, tmp, &ub->rcast.list, list) {
  		if (i < skip_cnt)
  			goto count;
  
  		hdr = genlmsg_put(skb, portid, cb->nlh->nlmsg_seq,
  				  &tipc_genl_family, NLM_F_MULTI,
  				  TIPC_NL_BEARER_GET);
  		if (!hdr)
  			goto done;
  
  		err = __tipc_nl_add_udp_addr(skb, &rcast->addr,
  					     TIPC_NLA_UDP_REMOTE);
  		if (err) {
  			genlmsg_cancel(skb, hdr);
  			goto done;
  		}
  		genlmsg_end(skb, hdr);
  count:
  		i++;
  	}
  done:
  	rtnl_unlock();
  	cb->args[0] = bid;
  	cb->args[1] = i;
  
  	return skb->len;
  }
fdb3accc2   Richard Alpe   tipc: add the abi...
512
513
514
515
516
517
  int tipc_udp_nl_add_bearer_data(struct tipc_nl_msg *msg, struct tipc_bearer *b)
  {
  	struct udp_media_addr *src = (struct udp_media_addr *)&b->addr.value;
  	struct udp_media_addr *dst;
  	struct udp_bearer *ub;
  	struct nlattr *nest;
30a4616c1   Xin Long   tipc: use rcu der...
518
  	ub = rtnl_dereference(b->media_ptr);
fdb3accc2   Richard Alpe   tipc: add the abi...
519
520
  	if (!ub)
  		return -ENODEV;
ae0be8de9   Michal Kubecek   netlink: make nla...
521
  	nest = nla_nest_start_noflag(msg->skb, TIPC_NLA_BEARER_UDP_OPTS);
fdb3accc2   Richard Alpe   tipc: add the abi...
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
  	if (!nest)
  		goto msg_full;
  
  	if (__tipc_nl_add_udp_addr(msg->skb, src, TIPC_NLA_UDP_LOCAL))
  		goto msg_full;
  
  	dst = (struct udp_media_addr *)&b->bcast_addr.value;
  	if (__tipc_nl_add_udp_addr(msg->skb, dst, TIPC_NLA_UDP_REMOTE))
  		goto msg_full;
  
  	if (!list_empty(&ub->rcast.list)) {
  		if (nla_put_flag(msg->skb, TIPC_NLA_UDP_MULTI_REMOTEIP))
  			goto msg_full;
  	}
  
  	nla_nest_end(msg->skb, nest);
  	return 0;
  msg_full:
  	nla_nest_cancel(msg->skb, nest);
  	return -EMSGSIZE;
  }
d0f91938b   Erik Hugne   tipc: add ip/udp ...
543
  /**
ba5aa84a2   Richard Alpe   tipc: split UDP n...
544
545
546
547
   * tipc_parse_udp_addr - build udp media address from netlink data
   * @nlattr:	netlink attribute containing sockaddr storage aligned address
   * @addr:	tipc media address to fill with address, port and protocol type
   * @scope_id:	IPv6 scope id pointer, not NULL indicates it's required
d0f91938b   Erik Hugne   tipc: add ip/udp ...
548
   */
ba5aa84a2   Richard Alpe   tipc: split UDP n...
549
550
551
  
  static int tipc_parse_udp_addr(struct nlattr *nla, struct udp_media_addr *addr,
  			       u32 *scope_id)
d0f91938b   Erik Hugne   tipc: add ip/udp ...
552
  {
ba5aa84a2   Richard Alpe   tipc: split UDP n...
553
  	struct sockaddr_storage sa;
d0f91938b   Erik Hugne   tipc: add ip/udp ...
554

ba5aa84a2   Richard Alpe   tipc: split UDP n...
555
556
557
558
559
560
561
  	nla_memcpy(&sa, nla, sizeof(sa));
  	if (sa.ss_family == AF_INET) {
  		struct sockaddr_in *ip4 = (struct sockaddr_in *)&sa;
  
  		addr->proto = htons(ETH_P_IP);
  		addr->port = ip4->sin_port;
  		addr->ipv4.s_addr = ip4->sin_addr.s_addr;
d0f91938b   Erik Hugne   tipc: add ip/udp ...
562
563
564
  		return 0;
  
  #if IS_ENABLED(CONFIG_IPV6)
ba5aa84a2   Richard Alpe   tipc: split UDP n...
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
  	} else if (sa.ss_family == AF_INET6) {
  		struct sockaddr_in6 *ip6 = (struct sockaddr_in6 *)&sa;
  
  		addr->proto = htons(ETH_P_IPV6);
  		addr->port = ip6->sin6_port;
  		memcpy(&addr->ipv6, &ip6->sin6_addr, sizeof(struct in6_addr));
  
  		/* Scope ID is only interesting for local addresses */
  		if (scope_id) {
  			int atype;
  
  			atype = ipv6_addr_type(&ip6->sin6_addr);
  			if (__ipv6_addr_needs_scope_id(atype) &&
  			    !ip6->sin6_scope_id) {
  				return -EINVAL;
  			}
  
  			*scope_id = ip6->sin6_scope_id ? : 0;
  		}
d0f91938b   Erik Hugne   tipc: add ip/udp ...
584
585
586
587
588
  		return 0;
  #endif
  	}
  	return -EADDRNOTAVAIL;
  }
ef20cd4dd   Richard Alpe   tipc: introduce U...
589
590
591
592
593
594
  int tipc_udp_nl_bearer_add(struct tipc_bearer *b, struct nlattr *attr)
  {
  	int err;
  	struct udp_media_addr addr = {0};
  	struct nlattr *opts[TIPC_NLA_UDP_MAX + 1];
  	struct udp_media_addr *dst;
8cb081746   Johannes Berg   netlink: make val...
595
  	if (nla_parse_nested_deprecated(opts, TIPC_NLA_UDP_MAX, attr, tipc_nl_udp_policy, NULL))
ef20cd4dd   Richard Alpe   tipc: introduce U...
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
  		return -EINVAL;
  
  	if (!opts[TIPC_NLA_UDP_REMOTE])
  		return -EINVAL;
  
  	err = tipc_parse_udp_addr(opts[TIPC_NLA_UDP_REMOTE], &addr, NULL);
  	if (err)
  		return err;
  
  	dst = (struct udp_media_addr *)&b->bcast_addr.value;
  	if (tipc_udp_is_mcast_addr(dst)) {
  		pr_err("Can't add remote ip to TIPC UDP multicast bearer
  ");
  		return -EINVAL;
  	}
c9b64d492   Richard Alpe   tipc: add replica...
611
612
  	if (tipc_udp_is_known_peer(b, &addr))
  		return 0;
ef20cd4dd   Richard Alpe   tipc: introduce U...
613
614
  	return tipc_udp_rcast_add(b, &addr);
  }
d0f91938b   Erik Hugne   tipc: add ip/udp ...
615
616
617
618
619
620
621
622
623
624
625
626
627
628
  /**
   * tipc_udp_enable - callback to create a new udp bearer instance
   * @net:	network namespace
   * @b:		pointer to generic tipc_bearer
   * @attrs:	netlink bearer configuration
   *
   * validate the bearer parameters and initialize the udp bearer
   * rtnl_lock should be held
   */
  static int tipc_udp_enable(struct net *net, struct tipc_bearer *b,
  			   struct nlattr *attrs[])
  {
  	int err = -EINVAL;
  	struct udp_bearer *ub;
ef20cd4dd   Richard Alpe   tipc: introduce U...
629
  	struct udp_media_addr remote = {0};
d0f91938b   Erik Hugne   tipc: add ip/udp ...
630
631
  	struct udp_media_addr local = {0};
  	struct udp_port_cfg udp_conf = {0};
4fee6be81   Erik Hugne   tipc: sparse: fix...
632
  	struct udp_tunnel_sock_cfg tuncfg = {NULL};
ba5aa84a2   Richard Alpe   tipc: split UDP n...
633
  	struct nlattr *opts[TIPC_NLA_UDP_MAX + 1];
52dfae5c8   Jon Maloy   tipc: obtain node...
634
  	u8 node_id[NODE_ID_LEN] = {0,};
acad76a5f   Hoang Le   tipc: support bin...
635
  	int rmcast = 0;
d0f91938b   Erik Hugne   tipc: add ip/udp ...
636
637
638
639
  
  	ub = kzalloc(sizeof(*ub), GFP_ATOMIC);
  	if (!ub)
  		return -ENOMEM;
ef20cd4dd   Richard Alpe   tipc: introduce U...
640
  	INIT_LIST_HEAD(&ub->rcast.list);
ba5aa84a2   Richard Alpe   tipc: split UDP n...
641
642
  	if (!attrs[TIPC_NLA_BEARER_UDP_OPTS])
  		goto err;
8cb081746   Johannes Berg   netlink: make val...
643
  	if (nla_parse_nested_deprecated(opts, TIPC_NLA_UDP_MAX, attrs[TIPC_NLA_BEARER_UDP_OPTS], tipc_nl_udp_policy, NULL))
ba5aa84a2   Richard Alpe   tipc: split UDP n...
644
645
646
647
  		goto err;
  
  	if (!opts[TIPC_NLA_UDP_LOCAL] || !opts[TIPC_NLA_UDP_REMOTE]) {
  		pr_err("Invalid UDP bearer configuration");
c20cb8119   Wei Yongjun   tipc: fix possibl...
648
649
  		err = -EINVAL;
  		goto err;
ba5aa84a2   Richard Alpe   tipc: split UDP n...
650
651
652
653
654
655
  	}
  
  	err = tipc_parse_udp_addr(opts[TIPC_NLA_UDP_LOCAL], &local,
  				  &ub->ifindex);
  	if (err)
  		goto err;
ef20cd4dd   Richard Alpe   tipc: introduce U...
656
  	err = tipc_parse_udp_addr(opts[TIPC_NLA_UDP_REMOTE], &remote, NULL);
d0f91938b   Erik Hugne   tipc: add ip/udp ...
657
658
  	if (err)
  		goto err;
fb83ed496   Cong Wang   tipc: compare rem...
659
660
661
662
  	if (remote.proto != local.proto) {
  		err = -EINVAL;
  		goto err;
  	}
acad76a5f   Hoang Le   tipc: support bin...
663
664
  	/* Checking remote ip address */
  	rmcast = tipc_udp_is_mcast_addr(&remote);
52dfae5c8   Jon Maloy   tipc: obtain node...
665
666
667
668
669
670
671
672
  	/* Autoconfigure own node identity if needed */
  	if (!tipc_own_id(net)) {
  		memcpy(node_id, local.ipv6.in6_u.u6_addr8, 16);
  		tipc_net_init(net, node_id, 0);
  	}
  	if (!tipc_own_id(net)) {
  		pr_warn("Failed to set node id, please configure manually
  ");
c76f2481b   Wei Yongjun   tipc: fix error h...
673
674
  		err = -EINVAL;
  		goto err;
52dfae5c8   Jon Maloy   tipc: obtain node...
675
  	}
d0f91938b   Erik Hugne   tipc: add ip/udp ...
676
  	b->bcast_addr.media_id = TIPC_MEDIA_TYPE_UDP;
9999974a8   Jon Paul Maloy   tipc: add functio...
677
  	b->bcast_addr.broadcast = TIPC_BROADCAST_SUPPORT;
d0f91938b   Erik Hugne   tipc: add ip/udp ...
678
679
680
  	rcu_assign_pointer(b->media_ptr, ub);
  	rcu_assign_pointer(ub->bearer, b);
  	tipc_udp_media_addr_set(&b->addr, &local);
4fee6be81   Erik Hugne   tipc: sparse: fix...
681
  	if (local.proto == htons(ETH_P_IP)) {
d0f91938b   Erik Hugne   tipc: add ip/udp ...
682
683
684
685
686
687
688
689
  		struct net_device *dev;
  
  		dev = __ip_dev_find(net, local.ipv4.s_addr, false);
  		if (!dev) {
  			err = -ENODEV;
  			goto err;
  		}
  		udp_conf.family = AF_INET;
acad76a5f   Hoang Le   tipc: support bin...
690
691
692
693
694
695
  
  		/* Switch to use ANY to receive packets from group */
  		if (rmcast)
  			udp_conf.local_ip.s_addr = htonl(INADDR_ANY);
  		else
  			udp_conf.local_ip.s_addr = local.ipv4.s_addr;
d0f91938b   Erik Hugne   tipc: add ip/udp ...
696
697
  		udp_conf.use_udp_checksums = false;
  		ub->ifindex = dev->ifindex;
3de81b758   Michal Kubeček   tipc: check minim...
698
699
700
701
702
  		if (tipc_mtu_bad(dev, sizeof(struct iphdr) +
  				      sizeof(struct udphdr))) {
  			err = -EINVAL;
  			goto err;
  		}
a4dfa72d0   GhantaKrishnamurthy MohanKrishna   tipc: set default...
703
  		b->mtu = b->media->mtu;
d0f91938b   Erik Hugne   tipc: add ip/udp ...
704
  #if IS_ENABLED(CONFIG_IPV6)
4fee6be81   Erik Hugne   tipc: sparse: fix...
705
  	} else if (local.proto == htons(ETH_P_IPV6)) {
d0f91938b   Erik Hugne   tipc: add ip/udp ...
706
707
708
  		udp_conf.family = AF_INET6;
  		udp_conf.use_udp6_tx_checksums = true;
  		udp_conf.use_udp6_rx_checksums = true;
acad76a5f   Hoang Le   tipc: support bin...
709
710
711
712
  		if (rmcast)
  			udp_conf.local_ip6 = in6addr_any;
  		else
  			udp_conf.local_ip6 = local.ipv6;
d0f91938b   Erik Hugne   tipc: add ip/udp ...
713
714
715
716
717
718
  		b->mtu = 1280;
  #endif
  	} else {
  		err = -EAFNOSUPPORT;
  		goto err;
  	}
bc3a334cc   Richard Alpe   tipc: rename udp_...
719
  	udp_conf.local_udp_port = local.port;
d0f91938b   Erik Hugne   tipc: add ip/udp ...
720
721
722
723
724
725
726
727
  	err = udp_sock_create(net, &udp_conf, &ub->ubsock);
  	if (err)
  		goto err;
  	tuncfg.sk_user_data = ub;
  	tuncfg.encap_type = 1;
  	tuncfg.encap_rcv = tipc_udp_recv;
  	tuncfg.encap_destroy = NULL;
  	setup_udp_tunnel_sock(net, ub->ubsock, &tuncfg);
e9c1a7932   Xin Long   tipc: add dst_cac...
728
729
  	err = dst_cache_init(&ub->rcast.dst_cache, GFP_ATOMIC);
  	if (err)
d2c3a4ba2   Xin Long   tipc: remove ub->...
730
  		goto free;
e9c1a7932   Xin Long   tipc: add dst_cac...
731

ef20cd4dd   Richard Alpe   tipc: introduce U...
732
733
734
735
736
  	/**
  	 * The bcast media address port is used for all peers and the ip
  	 * is used if it's a multicast address.
  	 */
  	memcpy(&b->bcast_addr.value, &remote, sizeof(remote));
acad76a5f   Hoang Le   tipc: support bin...
737
  	if (rmcast)
ef20cd4dd   Richard Alpe   tipc: introduce U...
738
739
740
741
  		err = enable_mcast(ub, &remote);
  	else
  		err = tipc_udp_rcast_add(b, &remote);
  	if (err)
d2c3a4ba2   Xin Long   tipc: remove ub->...
742
  		goto free;
1ca73e3fa   Richard Alpe   tipc: refactor mu...
743

d0f91938b   Erik Hugne   tipc: add ip/udp ...
744
  	return 0;
d2c3a4ba2   Xin Long   tipc: remove ub->...
745
746
  
  free:
e9c1a7932   Xin Long   tipc: add dst_cac...
747
  	dst_cache_destroy(&ub->rcast.dst_cache);
d2c3a4ba2   Xin Long   tipc: remove ub->...
748
749
  	udp_tunnel_sock_release(ub->ubsock);
  err:
d0f91938b   Erik Hugne   tipc: add ip/udp ...
750
751
752
753
754
755
756
757
  	kfree(ub);
  	return err;
  }
  
  /* cleanup_bearer - break the socket/bearer association */
  static void cleanup_bearer(struct work_struct *work)
  {
  	struct udp_bearer *ub = container_of(work, struct udp_bearer, work);
ef20cd4dd   Richard Alpe   tipc: introduce U...
758
759
760
  	struct udp_replicast *rcast, *tmp;
  
  	list_for_each_entry_safe(rcast, tmp, &ub->rcast.list, list) {
e9c1a7932   Xin Long   tipc: add dst_cac...
761
  		dst_cache_destroy(&rcast->dst_cache);
ef20cd4dd   Richard Alpe   tipc: introduce U...
762
763
764
  		list_del_rcu(&rcast->list);
  		kfree_rcu(rcast, rcu);
  	}
d0f91938b   Erik Hugne   tipc: add ip/udp ...
765

e9c1a7932   Xin Long   tipc: add dst_cac...
766
  	dst_cache_destroy(&ub->rcast.dst_cache);
d2c3a4ba2   Xin Long   tipc: remove ub->...
767
  	udp_tunnel_sock_release(ub->ubsock);
d0f91938b   Erik Hugne   tipc: add ip/udp ...
768
769
770
771
772
773
774
775
  	synchronize_net();
  	kfree(ub);
  }
  
  /* tipc_udp_disable - detach bearer from socket */
  static void tipc_udp_disable(struct tipc_bearer *b)
  {
  	struct udp_bearer *ub;
30a4616c1   Xin Long   tipc: use rcu der...
776
  	ub = rtnl_dereference(b->media_ptr);
d0f91938b   Erik Hugne   tipc: add ip/udp ...
777
778
779
780
781
  	if (!ub) {
  		pr_err("UDP bearer instance not found
  ");
  		return;
  	}
d2c3a4ba2   Xin Long   tipc: remove ub->...
782
  	sock_set_flag(ub->ubsock->sk, SOCK_DEAD);
d0f91938b   Erik Hugne   tipc: add ip/udp ...
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
  	RCU_INIT_POINTER(ub->bearer, NULL);
  
  	/* sock_release need to be done outside of rtnl lock */
  	INIT_WORK(&ub->work, cleanup_bearer);
  	schedule_work(&ub->work);
  }
  
  struct tipc_media udp_media_info = {
  	.send_msg	= tipc_udp_send_msg,
  	.enable_media	= tipc_udp_enable,
  	.disable_media	= tipc_udp_disable,
  	.addr2str	= tipc_udp_addr2str,
  	.addr2msg	= tipc_udp_addr2msg,
  	.msg2addr	= tipc_udp_msg2addr,
  	.priority	= TIPC_DEF_LINK_PRI,
  	.tolerance	= TIPC_DEF_LINK_TOL,
  	.window		= TIPC_DEF_LINK_WIN,
a4dfa72d0   GhantaKrishnamurthy MohanKrishna   tipc: set default...
800
  	.mtu		= TIPC_DEF_LINK_UDP_MTU,
d0f91938b   Erik Hugne   tipc: add ip/udp ...
801
802
803
804
  	.type_id	= TIPC_MEDIA_TYPE_UDP,
  	.hwaddr_len	= 0,
  	.name		= "udp"
  };