blob: be7c3b71914de1e83f6a854e25c04b951aa1aed2 [file] [log] [blame]
Greg Kroah-Hartmanb2441312017-11-01 15:07:57 +01001// SPDX-License-Identifier: GPL-2.0
Linus Torvalds1da177e2005-04-16 15:20:36 -07002/*
3 * INET An implementation of the TCP/IP protocol suite for the LINUX
4 * operating system. INET is implemented using the BSD Socket
5 * interface as the means of communication with the user level.
6 *
7 * The IP to API glue.
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09008 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 * Authors: see ip.c
10 *
11 * Fixes:
12 * Many : Split from ip.c , see ip.c for history.
13 * Martin Mares : TOS setting fixed.
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +090014 * Alan Cox : Fixed a couple of oopses in Martin's
Linus Torvalds1da177e2005-04-16 15:20:36 -070015 * TOS tweaks.
16 * Mike McLagan : Routing by source
17 */
18
Linus Torvalds1da177e2005-04-16 15:20:36 -070019#include <linux/module.h>
20#include <linux/types.h>
21#include <linux/mm.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070022#include <linux/skbuff.h>
23#include <linux/ip.h>
24#include <linux/icmp.h>
Arnaldo Carvalho de Melo14c85022005-12-27 02:43:12 -020025#include <linux/inetdevice.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/netdevice.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090027#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070028#include <net/sock.h>
29#include <net/ip.h>
30#include <net/icmp.h>
Arnaldo Carvalho de Melod83d8462005-12-13 23:26:10 -080031#include <net/tcp_states.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include <linux/udp.h>
33#include <linux/igmp.h>
34#include <linux/netfilter.h>
35#include <linux/route.h>
36#include <linux/mroute.h>
Maciej Żenczykowski2c67e9a2011-10-22 00:07:47 -040037#include <net/inet_ecn.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#include <net/route.h>
39#include <net/xfrm.h>
David L Stevensdae50292008-04-27 01:06:07 -070040#include <net/compat.h>
Tom Herbertad6f9392015-01-05 13:56:17 -080041#include <net/checksum.h>
Eric Dumazetdfd56b82011-12-10 09:48:31 +000042#if IS_ENABLED(CONFIG_IPV6)
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#include <net/transp_v6.h>
44#endif
David S. Miller35ebf652012-06-28 03:59:11 -070045#include <net/ip_fib.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070046
47#include <linux/errqueue.h>
Linus Torvalds7c0f6ba2016-12-24 11:46:01 -080048#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070049
Linus Torvalds1da177e2005-04-16 15:20:36 -070050/*
51 * SOL_IP control messages.
52 */
53
54static void ip_cmsg_recv_pktinfo(struct msghdr *msg, struct sk_buff *skb)
55{
Eric Dumazetd826eb12011-11-09 07:24:35 +000056 struct in_pktinfo info = *PKTINFO_SKB_CB(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -070057
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -070058 info.ipi_addr.s_addr = ip_hdr(skb)->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070059
60 put_cmsg(msg, SOL_IP, IP_PKTINFO, sizeof(info), &info);
61}
62
63static void ip_cmsg_recv_ttl(struct msghdr *msg, struct sk_buff *skb)
64{
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -070065 int ttl = ip_hdr(skb)->ttl;
Linus Torvalds1da177e2005-04-16 15:20:36 -070066 put_cmsg(msg, SOL_IP, IP_TTL, sizeof(int), &ttl);
67}
68
69static void ip_cmsg_recv_tos(struct msghdr *msg, struct sk_buff *skb)
70{
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -070071 put_cmsg(msg, SOL_IP, IP_TOS, 1, &ip_hdr(skb)->tos);
Linus Torvalds1da177e2005-04-16 15:20:36 -070072}
73
74static void ip_cmsg_recv_opts(struct msghdr *msg, struct sk_buff *skb)
75{
76 if (IPCB(skb)->opt.optlen == 0)
77 return;
78
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -070079 put_cmsg(msg, SOL_IP, IP_RECVOPTS, IPCB(skb)->opt.optlen,
80 ip_hdr(skb) + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070081}
82
83
Paolo Abeni91ed1e62017-08-03 18:07:06 +020084static void ip_cmsg_recv_retopts(struct net *net, struct msghdr *msg,
85 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -070086{
87 unsigned char optbuf[sizeof(struct ip_options) + 40];
Daniel Baluta5e73ea12012-04-15 01:34:41 +000088 struct ip_options *opt = (struct ip_options *)optbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -070089
90 if (IPCB(skb)->opt.optlen == 0)
91 return;
92
Paolo Abeni91ed1e62017-08-03 18:07:06 +020093 if (ip_options_echo(net, opt, skb)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070094 msg->msg_flags |= MSG_CTRUNC;
95 return;
96 }
97 ip_options_undo(opt);
98
99 put_cmsg(msg, SOL_IP, IP_RETOPTS, opt->optlen, opt->__data);
100}
101
Willem de Bruijn70ecc242016-11-02 11:02:16 -0400102static void ip_cmsg_recv_fragsize(struct msghdr *msg, struct sk_buff *skb)
103{
104 int val;
105
106 if (IPCB(skb)->frag_max_size == 0)
107 return;
108
109 val = IPCB(skb)->frag_max_size;
110 put_cmsg(msg, SOL_IP, IP_RECVFRAGSIZE, sizeof(val), &val);
111}
112
Tom Herbertad6f9392015-01-05 13:56:17 -0800113static void ip_cmsg_recv_checksum(struct msghdr *msg, struct sk_buff *skb,
Eric Dumazet10df8e62016-10-23 18:03:06 -0700114 int tlen, int offset)
Tom Herbertad6f9392015-01-05 13:56:17 -0800115{
116 __wsum csum = skb->csum;
117
118 if (skb->ip_summed != CHECKSUM_COMPLETE)
119 return;
120
Paolo Abenica4ef452017-02-21 09:33:18 +0100121 if (offset != 0) {
122 int tend_off = skb_transport_offset(skb) + tlen;
123 csum = csum_sub(csum, skb_checksum(skb, tend_off, offset, 0));
124 }
Tom Herbertad6f9392015-01-05 13:56:17 -0800125
126 put_cmsg(msg, SOL_IP, IP_CHECKSUM, sizeof(__wsum), &csum);
127}
128
Catherine Zhang2c7946a2006-03-20 22:41:23 -0800129static void ip_cmsg_recv_security(struct msghdr *msg, struct sk_buff *skb)
130{
131 char *secdata;
Catherine Zhangdc49c1f2006-08-02 14:12:06 -0700132 u32 seclen, secid;
Catherine Zhang2c7946a2006-03-20 22:41:23 -0800133 int err;
134
Catherine Zhangdc49c1f2006-08-02 14:12:06 -0700135 err = security_socket_getpeersec_dgram(NULL, skb, &secid);
136 if (err)
137 return;
138
139 err = security_secid_to_secctx(secid, &secdata, &seclen);
Catherine Zhang2c7946a2006-03-20 22:41:23 -0800140 if (err)
141 return;
142
143 put_cmsg(msg, SOL_IP, SCM_SECURITY, seclen, secdata);
Catherine Zhangdc49c1f2006-08-02 14:12:06 -0700144 security_release_secctx(secdata, seclen);
Catherine Zhang2c7946a2006-03-20 22:41:23 -0800145}
146
Harvey Harrison21d1a162008-11-20 01:54:27 -0800147static void ip_cmsg_recv_dstaddr(struct msghdr *msg, struct sk_buff *skb)
Balazs Scheidlere8b2dfe2008-11-16 19:32:39 -0800148{
149 struct sockaddr_in sin;
Eric Dumazetb71d1d42011-04-22 04:53:02 +0000150 const struct iphdr *iph = ip_hdr(skb);
Harvey Harrison21d1a162008-11-20 01:54:27 -0800151 __be16 *ports = (__be16 *)skb_transport_header(skb);
Balazs Scheidlere8b2dfe2008-11-16 19:32:39 -0800152
Willem de Bruijn39b2dd72016-12-22 18:19:16 -0500153 if (skb_transport_offset(skb) + 4 > (int)skb->len)
Balazs Scheidlere8b2dfe2008-11-16 19:32:39 -0800154 return;
155
156 /* All current transport protocols have the port numbers in the
157 * first four bytes of the transport header and this function is
158 * written with this assumption in mind.
159 */
160
161 sin.sin_family = AF_INET;
162 sin.sin_addr.s_addr = iph->daddr;
163 sin.sin_port = ports[1];
164 memset(sin.sin_zero, 0, sizeof(sin.sin_zero));
165
166 put_cmsg(msg, SOL_IP, IP_ORIGDSTADDR, sizeof(sin), &sin);
167}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168
Paolo Abeniad959032016-11-04 11:28:58 +0100169void ip_cmsg_recv_offset(struct msghdr *msg, struct sock *sk,
170 struct sk_buff *skb, int tlen, int offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171{
Paolo Abeniad959032016-11-04 11:28:58 +0100172 struct inet_sock *inet = inet_sk(sk);
Eric Dumazet95c96172012-04-15 05:58:06 +0000173 unsigned int flags = inet->cmsg_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174
175 /* Ordered by supposed usage frequency */
Tom Herbertc44d13d2015-01-05 13:56:15 -0800176 if (flags & IP_CMSG_PKTINFO) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177 ip_cmsg_recv_pktinfo(msg, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178
Tom Herbertc44d13d2015-01-05 13:56:15 -0800179 flags &= ~IP_CMSG_PKTINFO;
180 if (!flags)
181 return;
182 }
183
184 if (flags & IP_CMSG_TTL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185 ip_cmsg_recv_ttl(msg, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186
Tom Herbertc44d13d2015-01-05 13:56:15 -0800187 flags &= ~IP_CMSG_TTL;
188 if (!flags)
189 return;
190 }
191
192 if (flags & IP_CMSG_TOS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 ip_cmsg_recv_tos(msg, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
Tom Herbertc44d13d2015-01-05 13:56:15 -0800195 flags &= ~IP_CMSG_TOS;
196 if (!flags)
197 return;
198 }
199
200 if (flags & IP_CMSG_RECVOPTS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 ip_cmsg_recv_opts(msg, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202
Tom Herbertc44d13d2015-01-05 13:56:15 -0800203 flags &= ~IP_CMSG_RECVOPTS;
204 if (!flags)
205 return;
206 }
207
208 if (flags & IP_CMSG_RETOPTS) {
Paolo Abeni91ed1e62017-08-03 18:07:06 +0200209 ip_cmsg_recv_retopts(sock_net(sk), msg, skb);
Catherine Zhang2c7946a2006-03-20 22:41:23 -0800210
Tom Herbertc44d13d2015-01-05 13:56:15 -0800211 flags &= ~IP_CMSG_RETOPTS;
212 if (!flags)
213 return;
214 }
215
216 if (flags & IP_CMSG_PASSSEC) {
Catherine Zhang2c7946a2006-03-20 22:41:23 -0800217 ip_cmsg_recv_security(msg, skb);
Balazs Scheidlere8b2dfe2008-11-16 19:32:39 -0800218
Tom Herbertc44d13d2015-01-05 13:56:15 -0800219 flags &= ~IP_CMSG_PASSSEC;
220 if (!flags)
221 return;
222 }
223
Tom Herbertad6f9392015-01-05 13:56:17 -0800224 if (flags & IP_CMSG_ORIGDSTADDR) {
Balazs Scheidlere8b2dfe2008-11-16 19:32:39 -0800225 ip_cmsg_recv_dstaddr(msg, skb);
226
Tom Herbertad6f9392015-01-05 13:56:17 -0800227 flags &= ~IP_CMSG_ORIGDSTADDR;
228 if (!flags)
229 return;
230 }
231
232 if (flags & IP_CMSG_CHECKSUM)
Eric Dumazet10df8e62016-10-23 18:03:06 -0700233 ip_cmsg_recv_checksum(msg, skb, tlen, offset);
Willem de Bruijn70ecc242016-11-02 11:02:16 -0400234
235 if (flags & IP_CMSG_RECVFRAGSIZE)
236 ip_cmsg_recv_fragsize(msg, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237}
Tom Herbert5961de92015-01-05 13:56:16 -0800238EXPORT_SYMBOL(ip_cmsg_recv_offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239
Soheil Hassas Yeganeh24025c42016-04-02 23:08:10 -0400240int ip_cmsg_send(struct sock *sk, struct msghdr *msg, struct ipcm_cookie *ipc,
Hannes Frederic Sowac8e6ad02014-02-18 21:38:08 +0100241 bool allow_ipv6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242{
Francesco Fuscof02db312013-09-24 15:43:08 +0200243 int err, val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244 struct cmsghdr *cmsg;
Soheil Hassas Yeganeh24025c42016-04-02 23:08:10 -0400245 struct net *net = sock_net(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246
Gu Zhengf95b4142014-12-11 11:22:04 +0800247 for_each_cmsghdr(cmsg, msg) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 if (!CMSG_OK(msg, cmsg))
249 return -EINVAL;
Eric Dumazet5337b5b2014-11-10 17:54:25 -0800250#if IS_ENABLED(CONFIG_IPV6)
Hannes Frederic Sowac8e6ad02014-02-18 21:38:08 +0100251 if (allow_ipv6 &&
252 cmsg->cmsg_level == SOL_IPV6 &&
253 cmsg->cmsg_type == IPV6_PKTINFO) {
254 struct in6_pktinfo *src_info;
255
256 if (cmsg->cmsg_len < CMSG_LEN(sizeof(*src_info)))
257 return -EINVAL;
258 src_info = (struct in6_pktinfo *)CMSG_DATA(cmsg);
259 if (!ipv6_addr_v4mapped(&src_info->ipi6_addr))
260 return -EINVAL;
David Ahern1cbec072018-02-16 11:03:03 -0800261 if (src_info->ipi6_ifindex)
262 ipc->oif = src_info->ipi6_ifindex;
Hannes Frederic Sowac8e6ad02014-02-18 21:38:08 +0100263 ipc->addr = src_info->ipi6_addr.s6_addr32[3];
264 continue;
265 }
266#endif
Soheil Hassas Yeganeh24025c42016-04-02 23:08:10 -0400267 if (cmsg->cmsg_level == SOL_SOCKET) {
Eric Dumazet26326162016-05-13 06:14:37 -0700268 err = __sock_cmsg_send(sk, msg, cmsg, &ipc->sockc);
269 if (err)
270 return err;
Soheil Hassas Yeganeh24025c42016-04-02 23:08:10 -0400271 continue;
272 }
273
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 if (cmsg->cmsg_level != SOL_IP)
275 continue;
276 switch (cmsg->cmsg_type) {
277 case IP_RETOPTS:
yuan linyu1ff8ceb2017-01-03 20:42:17 +0800278 err = cmsg->cmsg_len - sizeof(struct cmsghdr);
Eric Dumazet91948302016-02-04 06:23:28 -0800279
280 /* Our caller is responsible for freeing ipc->opt */
Eric Dumazet4d52cfb2009-06-02 00:42:16 -0700281 err = ip_options_get(net, &ipc->opt, CMSG_DATA(cmsg),
282 err < 40 ? err : 40);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 if (err)
284 return err;
285 break;
286 case IP_PKTINFO:
287 {
288 struct in_pktinfo *info;
289 if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct in_pktinfo)))
290 return -EINVAL;
291 info = (struct in_pktinfo *)CMSG_DATA(cmsg);
David Ahern1cbec072018-02-16 11:03:03 -0800292 if (info->ipi_ifindex)
293 ipc->oif = info->ipi_ifindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 ipc->addr = info->ipi_spec_dst.s_addr;
295 break;
296 }
Francesco Fuscof02db312013-09-24 15:43:08 +0200297 case IP_TTL:
298 if (cmsg->cmsg_len != CMSG_LEN(sizeof(int)))
299 return -EINVAL;
300 val = *(int *)CMSG_DATA(cmsg);
301 if (val < 1 || val > 255)
302 return -EINVAL;
303 ipc->ttl = val;
304 break;
305 case IP_TOS:
Eric Dumazete895cdc2016-09-07 21:52:56 -0700306 if (cmsg->cmsg_len == CMSG_LEN(sizeof(int)))
307 val = *(int *)CMSG_DATA(cmsg);
308 else if (cmsg->cmsg_len == CMSG_LEN(sizeof(u8)))
309 val = *(u8 *)CMSG_DATA(cmsg);
310 else
Francesco Fuscof02db312013-09-24 15:43:08 +0200311 return -EINVAL;
Francesco Fuscof02db312013-09-24 15:43:08 +0200312 if (val < 0 || val > 255)
313 return -EINVAL;
314 ipc->tos = val;
315 ipc->priority = rt_tos2priority(ipc->tos);
316 break;
317
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 default:
319 return -EINVAL;
320 }
321 }
322 return 0;
323}
324
325
326/* Special input handler for packets caught by router alert option.
327 They are selected only by protocol field, and then processed likely
328 local ones; but only if someone wants them! Otherwise, router
329 not running rsvpd will kill RSVP.
330
331 It is user level problem, what it will make with them.
332 I have no idea, how it will masquearde or NAT them (it is joke, joke :-)),
333 but receiver should be enough clever f.e. to forward mtrace requests,
334 sent to multicast group to reach destination designated router.
335 */
Eric Dumazet43a951e2010-10-25 03:32:44 +0000336struct ip_ra_chain __rcu *ip_ra_chain;
Kirill Tkhai76d3e152018-03-22 12:45:02 +0300337static DEFINE_SPINLOCK(ip_ra_lock);
Eric Dumazet66018502010-06-07 03:12:08 +0000338
Eric Dumazet592fcb92010-06-09 16:21:07 +0000339
340static void ip_ra_destroy_rcu(struct rcu_head *head)
Eric Dumazet66018502010-06-07 03:12:08 +0000341{
Eric Dumazet592fcb92010-06-09 16:21:07 +0000342 struct ip_ra_chain *ra = container_of(head, struct ip_ra_chain, rcu);
343
344 sock_put(ra->saved_sk);
345 kfree(ra);
Eric Dumazet66018502010-06-07 03:12:08 +0000346}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347
Eric Dumazet4d52cfb2009-06-02 00:42:16 -0700348int ip_ra_control(struct sock *sk, unsigned char on,
349 void (*destructor)(struct sock *))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350{
Eric Dumazet43a951e2010-10-25 03:32:44 +0000351 struct ip_ra_chain *ra, *new_ra;
352 struct ip_ra_chain __rcu **rap;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000354 if (sk->sk_type != SOCK_RAW || inet_sk(sk)->inet_num == IPPROTO_RAW)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 return -EINVAL;
356
357 new_ra = on ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL;
358
Kirill Tkhai76d3e152018-03-22 12:45:02 +0300359 spin_lock_bh(&ip_ra_lock);
Eric Dumazet43a951e2010-10-25 03:32:44 +0000360 for (rap = &ip_ra_chain;
Kirill Tkhai76d3e152018-03-22 12:45:02 +0300361 (ra = rcu_dereference_protected(*rap,
362 lockdep_is_held(&ip_ra_lock))) != NULL;
Eric Dumazet43a951e2010-10-25 03:32:44 +0000363 rap = &ra->next) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364 if (ra->sk == sk) {
365 if (on) {
Kirill Tkhai76d3e152018-03-22 12:45:02 +0300366 spin_unlock_bh(&ip_ra_lock);
Jesper Juhla51482b2005-11-08 09:41:34 -0800367 kfree(new_ra);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 return -EADDRINUSE;
369 }
Eric Dumazet592fcb92010-06-09 16:21:07 +0000370 /* dont let ip_call_ra_chain() use sk again */
371 ra->sk = NULL;
Eric Dumazet8e380f02014-09-09 08:11:41 -0700372 RCU_INIT_POINTER(*rap, ra->next);
Kirill Tkhai76d3e152018-03-22 12:45:02 +0300373 spin_unlock_bh(&ip_ra_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374
375 if (ra->destructor)
376 ra->destructor(sk);
Eric Dumazet592fcb92010-06-09 16:21:07 +0000377 /*
378 * Delay sock_put(sk) and kfree(ra) after one rcu grace
379 * period. This guarantee ip_call_ra_chain() dont need
380 * to mess with socket refcounts.
381 */
382 ra->saved_sk = sk;
383 call_rcu(&ra->rcu, ip_ra_destroy_rcu);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 return 0;
385 }
386 }
Kirill Tkhai76d3e152018-03-22 12:45:02 +0300387 if (!new_ra) {
388 spin_unlock_bh(&ip_ra_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 return -ENOBUFS;
Kirill Tkhai76d3e152018-03-22 12:45:02 +0300390 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 new_ra->sk = sk;
392 new_ra->destructor = destructor;
393
Eric Dumazet8e380f02014-09-09 08:11:41 -0700394 RCU_INIT_POINTER(new_ra->next, ra);
Eric Dumazet66018502010-06-07 03:12:08 +0000395 rcu_assign_pointer(*rap, new_ra);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 sock_hold(sk);
Kirill Tkhai76d3e152018-03-22 12:45:02 +0300397 spin_unlock_bh(&ip_ra_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398
399 return 0;
400}
401
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900402void ip_icmp_error(struct sock *sk, struct sk_buff *skb, int err,
Al Viro35986b32006-09-27 18:34:21 -0700403 __be16 port, u32 info, u8 *payload)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 struct sock_exterr_skb *serr;
406
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 skb = skb_clone(skb, GFP_ATOMIC);
408 if (!skb)
409 return;
410
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900411 serr = SKB_EXT_ERR(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 serr->ee.ee_errno = err;
413 serr->ee.ee_origin = SO_EE_ORIGIN_ICMP;
Arnaldo Carvalho de Melo88c76642007-03-13 14:43:18 -0300414 serr->ee.ee_type = icmp_hdr(skb)->type;
415 serr->ee.ee_code = icmp_hdr(skb)->code;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 serr->ee.ee_pad = 0;
417 serr->ee.ee_info = info;
418 serr->ee.ee_data = 0;
Arnaldo Carvalho de Melo88c76642007-03-13 14:43:18 -0300419 serr->addr_offset = (u8 *)&(((struct iphdr *)(icmp_hdr(skb) + 1))->daddr) -
Arnaldo Carvalho de Melod56f90a2007-04-10 20:50:43 -0700420 skb_network_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 serr->port = port;
422
Ian Morris00db4122015-04-03 09:17:27 +0100423 if (skb_pull(skb, payload - skb->data)) {
Arnaldo Carvalho de Melobd823932007-03-13 17:10:43 -0300424 skb_reset_transport_header(skb);
425 if (sock_queue_err_skb(sk, skb) == 0)
426 return;
427 }
428 kfree_skb(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429}
430
Al Viro05790162006-09-27 18:33:40 -0700431void ip_local_error(struct sock *sk, int err, __be32 daddr, __be16 port, u32 info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432{
433 struct inet_sock *inet = inet_sk(sk);
434 struct sock_exterr_skb *serr;
435 struct iphdr *iph;
436 struct sk_buff *skb;
437
438 if (!inet->recverr)
439 return;
440
441 skb = alloc_skb(sizeof(struct iphdr), GFP_ATOMIC);
442 if (!skb)
443 return;
444
Arnaldo Carvalho de Melo2ca9e6f2007-03-10 19:15:25 -0300445 skb_put(skb, sizeof(struct iphdr));
446 skb_reset_network_header(skb);
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700447 iph = ip_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 iph->daddr = daddr;
449
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900450 serr = SKB_EXT_ERR(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 serr->ee.ee_errno = err;
452 serr->ee.ee_origin = SO_EE_ORIGIN_LOCAL;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900453 serr->ee.ee_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 serr->ee.ee_code = 0;
455 serr->ee.ee_pad = 0;
456 serr->ee.ee_info = info;
457 serr->ee.ee_data = 0;
Arnaldo Carvalho de Melod56f90a2007-04-10 20:50:43 -0700458 serr->addr_offset = (u8 *)&iph->daddr - skb_network_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 serr->port = port;
460
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -0700461 __skb_pull(skb, skb_tail_pointer(skb) - skb->data);
Arnaldo Carvalho de Melobd823932007-03-13 17:10:43 -0300462 skb_reset_transport_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463
464 if (sock_queue_err_skb(sk, skb))
465 kfree_skb(skb);
466}
467
Julian Anastasov34b99df2015-06-23 08:34:39 +0300468/* For some errors we have valid addr_offset even with zero payload and
469 * zero port. Also, addr_offset should be supported if port is set.
470 */
471static inline bool ipv4_datagram_support_addr(struct sock_exterr_skb *serr)
472{
473 return serr->ee.ee_origin == SO_EE_ORIGIN_ICMP ||
474 serr->ee.ee_origin == SO_EE_ORIGIN_LOCAL || serr->port;
475}
476
Willem de Bruijnc247f052015-03-07 20:33:22 -0500477/* IPv4 supports cmsg on all imcp errors and some timestamps
478 *
479 * Timestamp code paths do not initialize the fields expected by cmsg:
480 * the PKTINFO fields in skb->cb[]. Fill those in here.
481 */
482static bool ipv4_datagram_support_cmsg(const struct sock *sk,
483 struct sk_buff *skb,
484 int ee_origin)
Willem de Bruijn829ae9d2014-11-30 22:22:34 -0500485{
Willem de Bruijnc247f052015-03-07 20:33:22 -0500486 struct in_pktinfo *info;
Willem de Bruijn829ae9d2014-11-30 22:22:34 -0500487
Willem de Bruijnc247f052015-03-07 20:33:22 -0500488 if (ee_origin == SO_EE_ORIGIN_ICMP)
489 return true;
490
491 if (ee_origin == SO_EE_ORIGIN_LOCAL)
492 return false;
493
494 /* Support IP_PKTINFO on tstamp packets if requested, to correlate
Willem de Bruijn1862d622017-04-12 19:24:35 -0400495 * timestamp with egress dev. Not possible for packets without iif
Willem de Bruijnc247f052015-03-07 20:33:22 -0500496 * or without payload (SOF_TIMESTAMPING_OPT_TSONLY).
497 */
Willem de Bruijn1862d622017-04-12 19:24:35 -0400498 info = PKTINFO_SKB_CB(skb);
499 if (!(sk->sk_tsflags & SOF_TIMESTAMPING_OPT_CMSG) ||
500 !info->ipi_ifindex)
Willem de Bruijn829ae9d2014-11-30 22:22:34 -0500501 return false;
502
503 info->ipi_spec_dst.s_addr = ip_hdr(skb)->saddr;
Willem de Bruijn829ae9d2014-11-30 22:22:34 -0500504 return true;
505}
506
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900507/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 * Handle MSG_ERRQUEUE
509 */
Hannes Frederic Sowa85fbaa72013-11-23 00:46:12 +0100510int ip_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511{
512 struct sock_exterr_skb *serr;
Willem de Bruijn364a9e92014-08-31 21:30:27 -0400513 struct sk_buff *skb;
Steffen Hurrle342dfc32014-01-17 22:53:15 +0100514 DECLARE_SOCKADDR(struct sockaddr_in *, sin, msg->msg_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 struct {
516 struct sock_extended_err ee;
517 struct sockaddr_in offender;
518 } errhdr;
519 int err;
520 int copied;
521
Willem de Bruijn7ce875e2014-11-30 22:22:33 -0500522 WARN_ON_ONCE(sk->sk_family == AF_INET6);
523
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 err = -EAGAIN;
Willem de Bruijn364a9e92014-08-31 21:30:27 -0400525 skb = sock_dequeue_err_skb(sk);
Ian Morris51456b22015-04-03 09:17:26 +0100526 if (!skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 goto out;
528
529 copied = skb->len;
530 if (copied > len) {
531 msg->msg_flags |= MSG_TRUNC;
532 copied = len;
533 }
David S. Miller51f3d022014-11-05 16:46:40 -0500534 err = skb_copy_datagram_msg(skb, 0, msg, copied);
Eric Dumazet960a2622016-04-21 22:27:32 -0700535 if (unlikely(err)) {
536 kfree_skb(skb);
537 return err;
538 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 sock_recv_timestamp(msg, sk, skb);
540
541 serr = SKB_EXT_ERR(skb);
542
Julian Anastasov34b99df2015-06-23 08:34:39 +0300543 if (sin && ipv4_datagram_support_addr(serr)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 sin->sin_family = AF_INET;
Arnaldo Carvalho de Melod56f90a2007-04-10 20:50:43 -0700545 sin->sin_addr.s_addr = *(__be32 *)(skb_network_header(skb) +
546 serr->addr_offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 sin->sin_port = serr->port;
548 memset(&sin->sin_zero, 0, sizeof(sin->sin_zero));
Hannes Frederic Sowa85fbaa72013-11-23 00:46:12 +0100549 *addr_len = sizeof(*sin);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 }
551
552 memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err));
553 sin = &errhdr.offender;
Willem de Bruijnf8121162015-01-15 13:18:40 -0500554 memset(sin, 0, sizeof(*sin));
Willem de Bruijn829ae9d2014-11-30 22:22:34 -0500555
Willem de Bruijnc247f052015-03-07 20:33:22 -0500556 if (ipv4_datagram_support_cmsg(sk, skb, serr->ee.ee_origin)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 sin->sin_family = AF_INET;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700558 sin->sin_addr.s_addr = ip_hdr(skb)->saddr;
Willem de Bruijnf8121162015-01-15 13:18:40 -0500559 if (inet_sk(sk)->cmsg_flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 ip_cmsg_recv(msg, skb);
561 }
562
563 put_cmsg(msg, SOL_IP, IP_RECVERR, sizeof(errhdr), &errhdr);
564
565 /* Now we could try to dump offended packet options */
566
567 msg->msg_flags |= MSG_ERRQUEUE;
568 err = copied;
569
Eric Dumazet960a2622016-04-21 22:27:32 -0700570 consume_skb(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571out:
572 return err;
573}
574
575
576/*
Eric Dumazet4d52cfb2009-06-02 00:42:16 -0700577 * Socket option code for IP. This is the end of the line after any
578 * TCP,UDP etc options on an IP socket.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 */
Marcelo Ricardo Leitnerbaf606d2015-03-18 14:50:42 -0300580static bool setsockopt_needs_rtnl(int optname)
581{
582 switch (optname) {
583 case IP_ADD_MEMBERSHIP:
584 case IP_ADD_SOURCE_MEMBERSHIP:
Marcelo Ricardo Leitner54ff9ef2015-03-18 14:50:43 -0300585 case IP_BLOCK_SOURCE:
Marcelo Ricardo Leitnerbaf606d2015-03-18 14:50:42 -0300586 case IP_DROP_MEMBERSHIP:
Marcelo Ricardo Leitner54ff9ef2015-03-18 14:50:43 -0300587 case IP_DROP_SOURCE_MEMBERSHIP:
588 case IP_MSFILTER:
589 case IP_UNBLOCK_SOURCE:
590 case MCAST_BLOCK_SOURCE:
591 case MCAST_MSFILTER:
Marcelo Ricardo Leitnerbaf606d2015-03-18 14:50:42 -0300592 case MCAST_JOIN_GROUP:
Marcelo Ricardo Leitner54ff9ef2015-03-18 14:50:43 -0300593 case MCAST_JOIN_SOURCE_GROUP:
Marcelo Ricardo Leitnerbaf606d2015-03-18 14:50:42 -0300594 case MCAST_LEAVE_GROUP:
Marcelo Ricardo Leitner54ff9ef2015-03-18 14:50:43 -0300595 case MCAST_LEAVE_SOURCE_GROUP:
596 case MCAST_UNBLOCK_SOURCE:
WANG Cong1215e512017-04-12 12:32:13 -0700597 case IP_ROUTER_ALERT:
Marcelo Ricardo Leitnerbaf606d2015-03-18 14:50:42 -0300598 return true;
599 }
600 return false;
601}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602
Dmitry Mishin3fdadf72006-03-20 22:45:21 -0800603static int do_ip_setsockopt(struct sock *sk, int level,
David S. Millerb7058842009-09-30 16:12:20 -0700604 int optname, char __user *optval, unsigned int optlen)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605{
606 struct inet_sock *inet = inet_sk(sk);
Nikolay Borisov166b6b22016-02-08 23:29:22 +0200607 struct net *net = sock_net(sk);
Jianjun Kong09cb1052008-11-03 00:27:11 -0800608 int val = 0, err;
Marcelo Ricardo Leitnerbaf606d2015-03-18 14:50:42 -0300609 bool needs_rtnl = setsockopt_needs_rtnl(optname);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610
Xi Wang0c9f79b2012-11-11 11:20:01 +0000611 switch (optname) {
612 case IP_PKTINFO:
613 case IP_RECVTTL:
614 case IP_RECVOPTS:
615 case IP_RECVTOS:
616 case IP_RETOPTS:
617 case IP_TOS:
618 case IP_TTL:
619 case IP_HDRINCL:
620 case IP_MTU_DISCOVER:
621 case IP_RECVERR:
622 case IP_ROUTER_ALERT:
623 case IP_FREEBIND:
624 case IP_PASSSEC:
625 case IP_TRANSPARENT:
626 case IP_MINTTL:
627 case IP_NODEFRAG:
Eric Dumazet90c337d2015-06-06 21:17:57 -0700628 case IP_BIND_ADDRESS_NO_PORT:
Xi Wang0c9f79b2012-11-11 11:20:01 +0000629 case IP_UNICAST_IF:
630 case IP_MULTICAST_TTL:
631 case IP_MULTICAST_ALL:
632 case IP_MULTICAST_LOOP:
633 case IP_RECVORIGDSTADDR:
Tom Herbertad6f9392015-01-05 13:56:17 -0800634 case IP_CHECKSUM:
Willem de Bruijn70ecc242016-11-02 11:02:16 -0400635 case IP_RECVFRAGSIZE:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 if (optlen >= sizeof(int)) {
637 if (get_user(val, (int __user *) optval))
638 return -EFAULT;
639 } else if (optlen >= sizeof(char)) {
640 unsigned char ucval;
641
642 if (get_user(ucval, (unsigned char __user *) optval))
643 return -EFAULT;
644 val = (int) ucval;
645 }
646 }
647
648 /* If optlen==0, it is equivalent to val == 0 */
649
Pavel Emelyanov6a9fb942007-11-05 21:32:31 -0800650 if (ip_mroute_opt(optname))
Jianjun Kong09cb1052008-11-03 00:27:11 -0800651 return ip_mroute_setsockopt(sk, optname, optval, optlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652
653 err = 0;
Marcelo Ricardo Leitnerbaf606d2015-03-18 14:50:42 -0300654 if (needs_rtnl)
655 rtnl_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 lock_sock(sk);
657
658 switch (optname) {
Stephen Hemminger132adf52007-03-08 20:44:43 -0800659 case IP_OPTIONS:
660 {
Eric Dumazetf6d8bd02011-04-21 09:45:37 +0000661 struct ip_options_rcu *old, *opt = NULL;
662
roel kluin65a1c4f2009-10-23 05:59:21 +0000663 if (optlen > 40)
Stephen Hemminger132adf52007-03-08 20:44:43 -0800664 goto e_inval;
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +0900665 err = ip_options_get_from_user(sock_net(sk), &opt,
Denis V. Lunevcb846632008-03-24 15:31:00 -0700666 optval, optlen);
Stephen Hemminger132adf52007-03-08 20:44:43 -0800667 if (err)
668 break;
Eric Dumazetf6d8bd02011-04-21 09:45:37 +0000669 old = rcu_dereference_protected(inet->inet_opt,
Hannes Frederic Sowa1e1d04e2016-04-05 17:10:15 +0200670 lockdep_sock_is_held(sk));
Stephen Hemminger132adf52007-03-08 20:44:43 -0800671 if (inet->is_icsk) {
672 struct inet_connection_sock *icsk = inet_csk(sk);
Eric Dumazetdfd56b82011-12-10 09:48:31 +0000673#if IS_ENABLED(CONFIG_IPV6)
Stephen Hemminger132adf52007-03-08 20:44:43 -0800674 if (sk->sk_family == PF_INET ||
675 (!((1 << sk->sk_state) &
676 (TCPF_LISTEN | TCPF_CLOSE)) &&
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000677 inet->inet_daddr != LOOPBACK4_IPV6)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678#endif
Eric Dumazetf6d8bd02011-04-21 09:45:37 +0000679 if (old)
680 icsk->icsk_ext_hdr_len -= old->opt.optlen;
Stephen Hemminger132adf52007-03-08 20:44:43 -0800681 if (opt)
Eric Dumazetf6d8bd02011-04-21 09:45:37 +0000682 icsk->icsk_ext_hdr_len += opt->opt.optlen;
Stephen Hemminger132adf52007-03-08 20:44:43 -0800683 icsk->icsk_sync_mss(sk, icsk->icsk_pmtu_cookie);
Eric Dumazetdfd56b82011-12-10 09:48:31 +0000684#if IS_ENABLED(CONFIG_IPV6)
Stephen Hemminger132adf52007-03-08 20:44:43 -0800685 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 }
Eric Dumazetf6d8bd02011-04-21 09:45:37 +0000688 rcu_assign_pointer(inet->inet_opt, opt);
689 if (old)
Paul E. McKenney605b4af2012-01-06 17:08:33 -0800690 kfree_rcu(old, rcu);
Stephen Hemminger132adf52007-03-08 20:44:43 -0800691 break;
692 }
693 case IP_PKTINFO:
694 if (val)
695 inet->cmsg_flags |= IP_CMSG_PKTINFO;
696 else
697 inet->cmsg_flags &= ~IP_CMSG_PKTINFO;
698 break;
699 case IP_RECVTTL:
700 if (val)
701 inet->cmsg_flags |= IP_CMSG_TTL;
702 else
703 inet->cmsg_flags &= ~IP_CMSG_TTL;
704 break;
705 case IP_RECVTOS:
706 if (val)
707 inet->cmsg_flags |= IP_CMSG_TOS;
708 else
709 inet->cmsg_flags &= ~IP_CMSG_TOS;
710 break;
711 case IP_RECVOPTS:
712 if (val)
713 inet->cmsg_flags |= IP_CMSG_RECVOPTS;
714 else
715 inet->cmsg_flags &= ~IP_CMSG_RECVOPTS;
716 break;
717 case IP_RETOPTS:
718 if (val)
719 inet->cmsg_flags |= IP_CMSG_RETOPTS;
720 else
721 inet->cmsg_flags &= ~IP_CMSG_RETOPTS;
722 break;
723 case IP_PASSSEC:
724 if (val)
725 inet->cmsg_flags |= IP_CMSG_PASSSEC;
726 else
727 inet->cmsg_flags &= ~IP_CMSG_PASSSEC;
728 break;
Balazs Scheidlere8b2dfe2008-11-16 19:32:39 -0800729 case IP_RECVORIGDSTADDR:
730 if (val)
731 inet->cmsg_flags |= IP_CMSG_ORIGDSTADDR;
732 else
733 inet->cmsg_flags &= ~IP_CMSG_ORIGDSTADDR;
734 break;
Tom Herbertad6f9392015-01-05 13:56:17 -0800735 case IP_CHECKSUM:
736 if (val) {
737 if (!(inet->cmsg_flags & IP_CMSG_CHECKSUM)) {
738 inet_inc_convert_csum(sk);
739 inet->cmsg_flags |= IP_CMSG_CHECKSUM;
740 }
741 } else {
742 if (inet->cmsg_flags & IP_CMSG_CHECKSUM) {
743 inet_dec_convert_csum(sk);
744 inet->cmsg_flags &= ~IP_CMSG_CHECKSUM;
745 }
746 }
747 break;
Willem de Bruijn70ecc242016-11-02 11:02:16 -0400748 case IP_RECVFRAGSIZE:
749 if (sk->sk_type != SOCK_RAW && sk->sk_type != SOCK_DGRAM)
750 goto e_inval;
751 if (val)
752 inet->cmsg_flags |= IP_CMSG_RECVFRAGSIZE;
753 else
754 inet->cmsg_flags &= ~IP_CMSG_RECVFRAGSIZE;
755 break;
Stephen Hemminger132adf52007-03-08 20:44:43 -0800756 case IP_TOS: /* This sets both TOS and Precedence */
757 if (sk->sk_type == SOCK_STREAM) {
Maciej Żenczykowski2c67e9a2011-10-22 00:07:47 -0400758 val &= ~INET_ECN_MASK;
759 val |= inet->tos & INET_ECN_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 }
Stephen Hemminger132adf52007-03-08 20:44:43 -0800761 if (inet->tos != val) {
762 inet->tos = val;
763 sk->sk_priority = rt_tos2priority(val);
764 sk_dst_reset(sk);
765 }
766 break;
767 case IP_TTL:
Eric Dumazet4d52cfb2009-06-02 00:42:16 -0700768 if (optlen < 1)
Stephen Hemminger132adf52007-03-08 20:44:43 -0800769 goto e_inval;
Cong Wangc9be4a52013-01-07 21:17:00 +0000770 if (val != -1 && (val < 1 || val > 255))
Stephen Hemminger132adf52007-03-08 20:44:43 -0800771 goto e_inval;
772 inet->uc_ttl = val;
773 break;
774 case IP_HDRINCL:
775 if (sk->sk_type != SOCK_RAW) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 err = -ENOPROTOOPT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 break;
Stephen Hemminger132adf52007-03-08 20:44:43 -0800778 }
779 inet->hdrincl = val ? 1 : 0;
780 break;
Jiri Olsa7b2ff182010-06-15 01:07:31 +0000781 case IP_NODEFRAG:
782 if (sk->sk_type != SOCK_RAW) {
783 err = -ENOPROTOOPT;
784 break;
785 }
786 inet->nodefrag = val ? 1 : 0;
787 break;
Eric Dumazet90c337d2015-06-06 21:17:57 -0700788 case IP_BIND_ADDRESS_NO_PORT:
789 inet->bind_address_no_port = val ? 1 : 0;
790 break;
Stephen Hemminger132adf52007-03-08 20:44:43 -0800791 case IP_MTU_DISCOVER:
Hannes Frederic Sowa1b346572014-02-26 01:20:42 +0100792 if (val < IP_PMTUDISC_DONT || val > IP_PMTUDISC_OMIT)
Stephen Hemminger132adf52007-03-08 20:44:43 -0800793 goto e_inval;
794 inet->pmtudisc = val;
795 break;
796 case IP_RECVERR:
797 inet->recverr = !!val;
798 if (!val)
799 skb_queue_purge(&sk->sk_error_queue);
800 break;
801 case IP_MULTICAST_TTL:
802 if (sk->sk_type == SOCK_STREAM)
803 goto e_inval;
Eric Dumazet4d52cfb2009-06-02 00:42:16 -0700804 if (optlen < 1)
Stephen Hemminger132adf52007-03-08 20:44:43 -0800805 goto e_inval;
Jianjun Kong09cb1052008-11-03 00:27:11 -0800806 if (val == -1)
Stephen Hemminger132adf52007-03-08 20:44:43 -0800807 val = 1;
808 if (val < 0 || val > 255)
809 goto e_inval;
810 inet->mc_ttl = val;
811 break;
812 case IP_MULTICAST_LOOP:
Eric Dumazet4d52cfb2009-06-02 00:42:16 -0700813 if (optlen < 1)
Stephen Hemminger132adf52007-03-08 20:44:43 -0800814 goto e_inval;
815 inet->mc_loop = !!val;
816 break;
Erich E. Hoover76e21052012-02-08 09:11:07 +0000817 case IP_UNICAST_IF:
818 {
819 struct net_device *dev = NULL;
820 int ifindex;
David Ahern9515a2e2018-01-24 19:37:38 -0800821 int midx;
Erich E. Hoover76e21052012-02-08 09:11:07 +0000822
823 if (optlen != sizeof(int))
824 goto e_inval;
825
826 ifindex = (__force int)ntohl((__force __be32)val);
827 if (ifindex == 0) {
828 inet->uc_index = 0;
829 err = 0;
830 break;
831 }
832
833 dev = dev_get_by_index(sock_net(sk), ifindex);
834 err = -EADDRNOTAVAIL;
835 if (!dev)
836 break;
David Ahern9515a2e2018-01-24 19:37:38 -0800837
838 midx = l3mdev_master_ifindex(dev);
Erich E. Hoover76e21052012-02-08 09:11:07 +0000839 dev_put(dev);
840
841 err = -EINVAL;
David Ahern9515a2e2018-01-24 19:37:38 -0800842 if (sk->sk_bound_dev_if &&
843 (!midx || midx != sk->sk_bound_dev_if))
Erich E. Hoover76e21052012-02-08 09:11:07 +0000844 break;
845
846 inet->uc_index = ifindex;
847 err = 0;
848 break;
849 }
Stephen Hemminger132adf52007-03-08 20:44:43 -0800850 case IP_MULTICAST_IF:
851 {
852 struct ip_mreqn mreq;
853 struct net_device *dev = NULL;
David Ahern7bb387c2016-12-29 15:39:37 -0800854 int midx;
Stephen Hemminger132adf52007-03-08 20:44:43 -0800855
856 if (sk->sk_type == SOCK_STREAM)
857 goto e_inval;
858 /*
859 * Check the arguments are allowable
860 */
861
Shan Wei09159212009-09-22 15:41:10 +0000862 if (optlen < sizeof(struct in_addr))
863 goto e_inval;
864
Stephen Hemminger132adf52007-03-08 20:44:43 -0800865 err = -EFAULT;
866 if (optlen >= sizeof(struct ip_mreqn)) {
Jianjun Kong09cb1052008-11-03 00:27:11 -0800867 if (copy_from_user(&mreq, optval, sizeof(mreq)))
Stephen Hemminger132adf52007-03-08 20:44:43 -0800868 break;
869 } else {
870 memset(&mreq, 0, sizeof(mreq));
Jiri Pirko3a084dd2012-05-03 22:37:45 +0000871 if (optlen >= sizeof(struct ip_mreq)) {
872 if (copy_from_user(&mreq, optval,
873 sizeof(struct ip_mreq)))
874 break;
875 } else if (optlen >= sizeof(struct in_addr)) {
876 if (copy_from_user(&mreq.imr_address, optval,
877 sizeof(struct in_addr)))
878 break;
879 }
Stephen Hemminger132adf52007-03-08 20:44:43 -0800880 }
881
882 if (!mreq.imr_ifindex) {
Al Viroe6f1ceb2008-03-17 22:44:53 -0700883 if (mreq.imr_address.s_addr == htonl(INADDR_ANY)) {
Stephen Hemminger132adf52007-03-08 20:44:43 -0800884 inet->mc_index = 0;
885 inet->mc_addr = 0;
886 err = 0;
887 break;
888 }
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +0900889 dev = ip_dev_find(sock_net(sk), mreq.imr_address.s_addr);
Eric Dumazet55b80502009-10-19 06:41:58 +0000890 if (dev)
Stephen Hemminger132adf52007-03-08 20:44:43 -0800891 mreq.imr_ifindex = dev->ifindex;
Stephen Hemminger132adf52007-03-08 20:44:43 -0800892 } else
Eric Dumazet55b80502009-10-19 06:41:58 +0000893 dev = dev_get_by_index(sock_net(sk), mreq.imr_ifindex);
Stephen Hemminger132adf52007-03-08 20:44:43 -0800894
895
896 err = -EADDRNOTAVAIL;
897 if (!dev)
898 break;
David Ahern7bb387c2016-12-29 15:39:37 -0800899
900 midx = l3mdev_master_ifindex(dev);
901
Eric Dumazet55b80502009-10-19 06:41:58 +0000902 dev_put(dev);
Stephen Hemminger132adf52007-03-08 20:44:43 -0800903
904 err = -EINVAL;
905 if (sk->sk_bound_dev_if &&
David Ahern7bb387c2016-12-29 15:39:37 -0800906 mreq.imr_ifindex != sk->sk_bound_dev_if &&
907 (!midx || midx != sk->sk_bound_dev_if))
Stephen Hemminger132adf52007-03-08 20:44:43 -0800908 break;
909
910 inet->mc_index = mreq.imr_ifindex;
911 inet->mc_addr = mreq.imr_address.s_addr;
912 err = 0;
913 break;
914 }
915
916 case IP_ADD_MEMBERSHIP:
917 case IP_DROP_MEMBERSHIP:
918 {
919 struct ip_mreqn mreq;
920
Flavio Leitnera96fb492007-08-24 22:16:39 -0700921 err = -EPROTO;
922 if (inet_sk(sk)->is_icsk)
923 break;
924
Stephen Hemminger132adf52007-03-08 20:44:43 -0800925 if (optlen < sizeof(struct ip_mreq))
926 goto e_inval;
927 err = -EFAULT;
928 if (optlen >= sizeof(struct ip_mreqn)) {
Jianjun Kong09cb1052008-11-03 00:27:11 -0800929 if (copy_from_user(&mreq, optval, sizeof(mreq)))
Stephen Hemminger132adf52007-03-08 20:44:43 -0800930 break;
931 } else {
932 memset(&mreq, 0, sizeof(mreq));
Jianjun Kong09cb1052008-11-03 00:27:11 -0800933 if (copy_from_user(&mreq, optval, sizeof(struct ip_mreq)))
Stephen Hemminger132adf52007-03-08 20:44:43 -0800934 break;
935 }
936
937 if (optname == IP_ADD_MEMBERSHIP)
Marcelo Ricardo Leitner54ff9ef2015-03-18 14:50:43 -0300938 err = ip_mc_join_group(sk, &mreq);
Stephen Hemminger132adf52007-03-08 20:44:43 -0800939 else
Marcelo Ricardo Leitner54ff9ef2015-03-18 14:50:43 -0300940 err = ip_mc_leave_group(sk, &mreq);
Stephen Hemminger132adf52007-03-08 20:44:43 -0800941 break;
942 }
943 case IP_MSFILTER:
944 {
Stephen Hemminger132adf52007-03-08 20:44:43 -0800945 struct ip_msfilter *msf;
946
947 if (optlen < IP_MSFILTER_SIZE(0))
948 goto e_inval;
949 if (optlen > sysctl_optmem_max) {
950 err = -ENOBUFS;
951 break;
952 }
Al Viroa2c841d2017-05-13 18:26:06 -0400953 msf = memdup_user(optval, optlen);
954 if (IS_ERR(msf)) {
955 err = PTR_ERR(msf);
Stephen Hemminger132adf52007-03-08 20:44:43 -0800956 break;
957 }
958 /* numsrc >= (1G-4) overflow in 32 bits */
959 if (msf->imsf_numsrc >= 0x3ffffffcU ||
Nikolay Borisov166b6b22016-02-08 23:29:22 +0200960 msf->imsf_numsrc > net->ipv4.sysctl_igmp_max_msf) {
Stephen Hemminger132adf52007-03-08 20:44:43 -0800961 kfree(msf);
962 err = -ENOBUFS;
963 break;
964 }
965 if (IP_MSFILTER_SIZE(msf->imsf_numsrc) > optlen) {
966 kfree(msf);
967 err = -EINVAL;
968 break;
969 }
970 err = ip_mc_msfilter(sk, msf, 0);
971 kfree(msf);
972 break;
973 }
974 case IP_BLOCK_SOURCE:
975 case IP_UNBLOCK_SOURCE:
976 case IP_ADD_SOURCE_MEMBERSHIP:
977 case IP_DROP_SOURCE_MEMBERSHIP:
978 {
979 struct ip_mreq_source mreqs;
980 int omode, add;
981
982 if (optlen != sizeof(struct ip_mreq_source))
983 goto e_inval;
984 if (copy_from_user(&mreqs, optval, sizeof(mreqs))) {
985 err = -EFAULT;
986 break;
987 }
988 if (optname == IP_BLOCK_SOURCE) {
989 omode = MCAST_EXCLUDE;
990 add = 1;
991 } else if (optname == IP_UNBLOCK_SOURCE) {
992 omode = MCAST_EXCLUDE;
993 add = 0;
994 } else if (optname == IP_ADD_SOURCE_MEMBERSHIP) {
995 struct ip_mreqn mreq;
996
997 mreq.imr_multiaddr.s_addr = mreqs.imr_multiaddr;
998 mreq.imr_address.s_addr = mreqs.imr_interface;
999 mreq.imr_ifindex = 0;
Marcelo Ricardo Leitner54ff9ef2015-03-18 14:50:43 -03001000 err = ip_mc_join_group(sk, &mreq);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001001 if (err && err != -EADDRINUSE)
1002 break;
1003 omode = MCAST_INCLUDE;
1004 add = 1;
1005 } else /* IP_DROP_SOURCE_MEMBERSHIP */ {
1006 omode = MCAST_INCLUDE;
1007 add = 0;
1008 }
1009 err = ip_mc_source(add, omode, sk, &mreqs, 0);
1010 break;
1011 }
1012 case MCAST_JOIN_GROUP:
1013 case MCAST_LEAVE_GROUP:
1014 {
1015 struct group_req greq;
1016 struct sockaddr_in *psin;
1017 struct ip_mreqn mreq;
1018
1019 if (optlen < sizeof(struct group_req))
1020 goto e_inval;
1021 err = -EFAULT;
1022 if (copy_from_user(&greq, optval, sizeof(greq)))
1023 break;
1024 psin = (struct sockaddr_in *)&greq.gr_group;
1025 if (psin->sin_family != AF_INET)
1026 goto e_inval;
1027 memset(&mreq, 0, sizeof(mreq));
1028 mreq.imr_multiaddr = psin->sin_addr;
1029 mreq.imr_ifindex = greq.gr_interface;
1030
1031 if (optname == MCAST_JOIN_GROUP)
Marcelo Ricardo Leitner54ff9ef2015-03-18 14:50:43 -03001032 err = ip_mc_join_group(sk, &mreq);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001033 else
Marcelo Ricardo Leitner54ff9ef2015-03-18 14:50:43 -03001034 err = ip_mc_leave_group(sk, &mreq);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001035 break;
1036 }
1037 case MCAST_JOIN_SOURCE_GROUP:
1038 case MCAST_LEAVE_SOURCE_GROUP:
1039 case MCAST_BLOCK_SOURCE:
1040 case MCAST_UNBLOCK_SOURCE:
1041 {
1042 struct group_source_req greqs;
1043 struct ip_mreq_source mreqs;
1044 struct sockaddr_in *psin;
1045 int omode, add;
1046
1047 if (optlen != sizeof(struct group_source_req))
1048 goto e_inval;
1049 if (copy_from_user(&greqs, optval, sizeof(greqs))) {
1050 err = -EFAULT;
1051 break;
1052 }
1053 if (greqs.gsr_group.ss_family != AF_INET ||
1054 greqs.gsr_source.ss_family != AF_INET) {
1055 err = -EADDRNOTAVAIL;
1056 break;
1057 }
1058 psin = (struct sockaddr_in *)&greqs.gsr_group;
1059 mreqs.imr_multiaddr = psin->sin_addr.s_addr;
1060 psin = (struct sockaddr_in *)&greqs.gsr_source;
1061 mreqs.imr_sourceaddr = psin->sin_addr.s_addr;
1062 mreqs.imr_interface = 0; /* use index for mc_source */
1063
1064 if (optname == MCAST_BLOCK_SOURCE) {
1065 omode = MCAST_EXCLUDE;
1066 add = 1;
1067 } else if (optname == MCAST_UNBLOCK_SOURCE) {
1068 omode = MCAST_EXCLUDE;
1069 add = 0;
1070 } else if (optname == MCAST_JOIN_SOURCE_GROUP) {
1071 struct ip_mreqn mreq;
1072
1073 psin = (struct sockaddr_in *)&greqs.gsr_group;
1074 mreq.imr_multiaddr = psin->sin_addr;
1075 mreq.imr_address.s_addr = 0;
1076 mreq.imr_ifindex = greqs.gsr_interface;
Marcelo Ricardo Leitner54ff9ef2015-03-18 14:50:43 -03001077 err = ip_mc_join_group(sk, &mreq);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001078 if (err && err != -EADDRINUSE)
1079 break;
1080 greqs.gsr_interface = mreq.imr_ifindex;
1081 omode = MCAST_INCLUDE;
1082 add = 1;
1083 } else /* MCAST_LEAVE_SOURCE_GROUP */ {
1084 omode = MCAST_INCLUDE;
1085 add = 0;
1086 }
1087 err = ip_mc_source(add, omode, sk, &mreqs,
1088 greqs.gsr_interface);
1089 break;
1090 }
1091 case MCAST_MSFILTER:
1092 {
Stephen Hemminger132adf52007-03-08 20:44:43 -08001093 struct sockaddr_in *psin;
1094 struct ip_msfilter *msf = NULL;
1095 struct group_filter *gsf = NULL;
1096 int msize, i, ifindex;
1097
1098 if (optlen < GROUP_FILTER_SIZE(0))
1099 goto e_inval;
1100 if (optlen > sysctl_optmem_max) {
1101 err = -ENOBUFS;
1102 break;
1103 }
Al Viroa2c841d2017-05-13 18:26:06 -04001104 gsf = memdup_user(optval, optlen);
1105 if (IS_ERR(gsf)) {
1106 err = PTR_ERR(gsf);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001107 break;
1108 }
Eric Dumazet4d52cfb2009-06-02 00:42:16 -07001109
Stephen Hemminger132adf52007-03-08 20:44:43 -08001110 /* numsrc >= (4G-140)/128 overflow in 32 bits */
1111 if (gsf->gf_numsrc >= 0x1ffffff ||
Nikolay Borisov166b6b22016-02-08 23:29:22 +02001112 gsf->gf_numsrc > net->ipv4.sysctl_igmp_max_msf) {
Stephen Hemminger132adf52007-03-08 20:44:43 -08001113 err = -ENOBUFS;
1114 goto mc_msf_out;
1115 }
1116 if (GROUP_FILTER_SIZE(gsf->gf_numsrc) > optlen) {
1117 err = -EINVAL;
1118 goto mc_msf_out;
1119 }
1120 msize = IP_MSFILTER_SIZE(gsf->gf_numsrc);
Jianjun Kong09cb1052008-11-03 00:27:11 -08001121 msf = kmalloc(msize, GFP_KERNEL);
Stephen Hemmingercfcabdc2007-10-09 01:59:42 -07001122 if (!msf) {
Stephen Hemminger132adf52007-03-08 20:44:43 -08001123 err = -ENOBUFS;
1124 goto mc_msf_out;
1125 }
1126 ifindex = gsf->gf_interface;
1127 psin = (struct sockaddr_in *)&gsf->gf_group;
1128 if (psin->sin_family != AF_INET) {
1129 err = -EADDRNOTAVAIL;
1130 goto mc_msf_out;
1131 }
1132 msf->imsf_multiaddr = psin->sin_addr.s_addr;
1133 msf->imsf_interface = 0;
1134 msf->imsf_fmode = gsf->gf_fmode;
1135 msf->imsf_numsrc = gsf->gf_numsrc;
1136 err = -EADDRNOTAVAIL;
Eric Dumazet4d52cfb2009-06-02 00:42:16 -07001137 for (i = 0; i < gsf->gf_numsrc; ++i) {
Stephen Hemminger132adf52007-03-08 20:44:43 -08001138 psin = (struct sockaddr_in *)&gsf->gf_slist[i];
1139
1140 if (psin->sin_family != AF_INET)
1141 goto mc_msf_out;
1142 msf->imsf_slist[i] = psin->sin_addr.s_addr;
1143 }
1144 kfree(gsf);
1145 gsf = NULL;
1146
1147 err = ip_mc_msfilter(sk, msf, ifindex);
Eric Dumazet4d52cfb2009-06-02 00:42:16 -07001148mc_msf_out:
Stephen Hemminger132adf52007-03-08 20:44:43 -08001149 kfree(msf);
1150 kfree(gsf);
1151 break;
1152 }
Nivedita Singhvif771bef2009-05-28 07:00:46 +00001153 case IP_MULTICAST_ALL:
1154 if (optlen < 1)
1155 goto e_inval;
1156 if (val != 0 && val != 1)
1157 goto e_inval;
1158 inet->mc_all = val;
1159 break;
Stephen Hemminger132adf52007-03-08 20:44:43 -08001160 case IP_ROUTER_ALERT:
1161 err = ip_ra_control(sk, val ? 1 : 0, NULL);
1162 break;
1163
1164 case IP_FREEBIND:
Eric Dumazet4d52cfb2009-06-02 00:42:16 -07001165 if (optlen < 1)
Stephen Hemminger132adf52007-03-08 20:44:43 -08001166 goto e_inval;
1167 inet->freebind = !!val;
1168 break;
1169
1170 case IP_IPSEC_POLICY:
1171 case IP_XFRM_POLICY:
1172 err = -EPERM;
Eric W. Biederman52e804c2012-11-16 03:03:05 +00001173 if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
Stephen Hemminger132adf52007-03-08 20:44:43 -08001174 break;
1175 err = xfrm_user_policy(sk, optname, optval, optlen);
1176 break;
1177
KOVACS Krisztianf5715ae2008-10-01 07:30:02 -07001178 case IP_TRANSPARENT:
Eric W. Biederman52e804c2012-11-16 03:03:05 +00001179 if (!!val && !ns_capable(sock_net(sk)->user_ns, CAP_NET_RAW) &&
1180 !ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) {
KOVACS Krisztianf5715ae2008-10-01 07:30:02 -07001181 err = -EPERM;
1182 break;
1183 }
1184 if (optlen < 1)
1185 goto e_inval;
1186 inet->transparent = !!val;
1187 break;
1188
Stephen Hemmingerd218d112010-01-11 16:28:01 -08001189 case IP_MINTTL:
1190 if (optlen < 1)
1191 goto e_inval;
1192 if (val < 0 || val > 255)
1193 goto e_inval;
1194 inet->min_ttl = val;
1195 break;
1196
Stephen Hemminger132adf52007-03-08 20:44:43 -08001197 default:
1198 err = -ENOPROTOOPT;
1199 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 }
1201 release_sock(sk);
Marcelo Ricardo Leitnerbaf606d2015-03-18 14:50:42 -03001202 if (needs_rtnl)
1203 rtnl_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204 return err;
1205
1206e_inval:
1207 release_sock(sk);
Marcelo Ricardo Leitnerbaf606d2015-03-18 14:50:42 -03001208 if (needs_rtnl)
1209 rtnl_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210 return -EINVAL;
1211}
1212
Eric Dumazetf84af322010-04-28 15:31:51 -07001213/**
Willem de Bruijn829ae9d2014-11-30 22:22:34 -05001214 * ipv4_pktinfo_prepare - transfer some info from rtable to skb
Eric Dumazetf84af322010-04-28 15:31:51 -07001215 * @sk: socket
1216 * @skb: buffer
1217 *
David S. Miller35ebf652012-06-28 03:59:11 -07001218 * To support IP_CMSG_PKTINFO option, we store rt_iif and specific
1219 * destination in skb->cb[] before dst drop.
stephen hemminger8e3bff92013-12-08 12:15:44 -08001220 * This way, receiver doesn't make cache line misses to read rtable.
Eric Dumazetf84af322010-04-28 15:31:51 -07001221 */
Shawn Bohrerfbf88662013-10-07 11:01:40 -05001222void ipv4_pktinfo_prepare(const struct sock *sk, struct sk_buff *skb)
Eric Dumazetf84af322010-04-28 15:31:51 -07001223{
Eric Dumazetd826eb12011-11-09 07:24:35 +00001224 struct in_pktinfo *pktinfo = PKTINFO_SKB_CB(skb);
Hannes Frederic Sowa4b261c72014-01-20 03:43:08 +01001225 bool prepare = (inet_sk(sk)->cmsg_flags & IP_CMSG_PKTINFO) ||
1226 ipv6_sk_rxinfo(sk);
Eric Dumazetd826eb12011-11-09 07:24:35 +00001227
Hannes Frederic Sowa4b261c72014-01-20 03:43:08 +01001228 if (prepare && skb_rtable(skb)) {
David Ahern0b922b72016-05-10 11:19:51 -07001229 /* skb->cb is overloaded: prior to this point it is IP{6}CB
1230 * which has interface index (iif) as the first member of the
1231 * underlying inet{6}_skb_parm struct. This code then overlays
1232 * PKTINFO_SKB_CB and in_pktinfo also has iif as the first
Wei Zhangf0c16ba2016-12-29 16:45:04 +08001233 * element so the iif is picked up from the prior IPCB. If iif
1234 * is the loopback interface, then return the sending interface
1235 * (e.g., process binds socket to eth0 for Tx which is
1236 * redirected to loopback in the rtable/dst).
David Ahern0b922b72016-05-10 11:19:51 -07001237 */
David Aherncbea8f02017-09-13 17:11:37 -07001238 struct rtable *rt = skb_rtable(skb);
1239 bool l3slave = ipv4_l3mdev_skb(IPCB(skb)->flags);
1240
1241 if (pktinfo->ipi_ifindex == LOOPBACK_IFINDEX)
Wei Zhangf0c16ba2016-12-29 16:45:04 +08001242 pktinfo->ipi_ifindex = inet_iif(skb);
David Aherncbea8f02017-09-13 17:11:37 -07001243 else if (l3slave && rt && rt->rt_iif)
1244 pktinfo->ipi_ifindex = rt->rt_iif;
Wei Zhangf0c16ba2016-12-29 16:45:04 +08001245
David S. Miller35ebf652012-06-28 03:59:11 -07001246 pktinfo->ipi_spec_dst.s_addr = fib_compute_spec_dst(skb);
Eric Dumazetd826eb12011-11-09 07:24:35 +00001247 } else {
1248 pktinfo->ipi_ifindex = 0;
1249 pktinfo->ipi_spec_dst.s_addr = 0;
1250 }
Paolo Abeni61a10302017-08-03 18:07:07 +02001251 skb_dst_drop(skb);
Eric Dumazetf84af322010-04-28 15:31:51 -07001252}
Eric Dumazetf84af322010-04-28 15:31:51 -07001253
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001254int ip_setsockopt(struct sock *sk, int level,
David S. Millerb7058842009-09-30 16:12:20 -07001255 int optname, char __user *optval, unsigned int optlen)
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001256{
1257 int err;
1258
1259 if (level != SOL_IP)
1260 return -ENOPROTOOPT;
1261
1262 err = do_ip_setsockopt(sk, level, optname, optval, optlen);
1263#ifdef CONFIG_NETFILTER
1264 /* we need to exclude all possible ENOPROTOOPTs except default case */
1265 if (err == -ENOPROTOOPT && optname != IP_HDRINCL &&
Pavel Emelyanov6a9fb942007-11-05 21:32:31 -08001266 optname != IP_IPSEC_POLICY &&
1267 optname != IP_XFRM_POLICY &&
Paolo Abeni3f34cfa2018-01-30 19:01:40 +01001268 !ip_mroute_opt(optname))
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001269 err = nf_setsockopt(sk, PF_INET, optname, optval, optlen);
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001270#endif
1271 return err;
1272}
Eric Dumazet4d52cfb2009-06-02 00:42:16 -07001273EXPORT_SYMBOL(ip_setsockopt);
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001274
1275#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001276int compat_ip_setsockopt(struct sock *sk, int level, int optname,
David S. Millerb7058842009-09-30 16:12:20 -07001277 char __user *optval, unsigned int optlen)
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001278{
1279 int err;
1280
1281 if (level != SOL_IP)
1282 return -ENOPROTOOPT;
1283
David L Stevensdae50292008-04-27 01:06:07 -07001284 if (optname >= MCAST_JOIN_GROUP && optname <= MCAST_MSFILTER)
1285 return compat_mc_setsockopt(sk, level, optname, optval, optlen,
1286 ip_setsockopt);
1287
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001288 err = do_ip_setsockopt(sk, level, optname, optval, optlen);
1289#ifdef CONFIG_NETFILTER
1290 /* we need to exclude all possible ENOPROTOOPTs except default case */
1291 if (err == -ENOPROTOOPT && optname != IP_HDRINCL &&
Pavel Emelyanov6a9fb942007-11-05 21:32:31 -08001292 optname != IP_IPSEC_POLICY &&
1293 optname != IP_XFRM_POLICY &&
Paolo Abeni3f34cfa2018-01-30 19:01:40 +01001294 !ip_mroute_opt(optname))
1295 err = compat_nf_setsockopt(sk, PF_INET, optname, optval,
1296 optlen);
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001297#endif
1298 return err;
1299}
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001300EXPORT_SYMBOL(compat_ip_setsockopt);
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001301#endif
1302
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303/*
Eric Dumazet4d52cfb2009-06-02 00:42:16 -07001304 * Get the options. Note for future reference. The GET of IP options gets
1305 * the _received_ ones. The set sets the _sent_ ones.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 */
1307
WANG Cong87e9f032015-11-03 15:41:16 -08001308static bool getsockopt_needs_rtnl(int optname)
1309{
1310 switch (optname) {
1311 case IP_MSFILTER:
1312 case MCAST_MSFILTER:
1313 return true;
1314 }
1315 return false;
1316}
1317
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001318static int do_ip_getsockopt(struct sock *sk, int level, int optname,
Eric Dumazet95c96172012-04-15 05:58:06 +00001319 char __user *optval, int __user *optlen, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320{
1321 struct inet_sock *inet = inet_sk(sk);
WANG Cong87e9f032015-11-03 15:41:16 -08001322 bool needs_rtnl = getsockopt_needs_rtnl(optname);
1323 int val, err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 int len;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001325
Stephen Hemminger132adf52007-03-08 20:44:43 -08001326 if (level != SOL_IP)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 return -EOPNOTSUPP;
1328
Pavel Emelyanov6a9fb942007-11-05 21:32:31 -08001329 if (ip_mroute_opt(optname))
Jianjun Kong09cb1052008-11-03 00:27:11 -08001330 return ip_mroute_getsockopt(sk, optname, optval, optlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331
Jianjun Kong09cb1052008-11-03 00:27:11 -08001332 if (get_user(len, optlen))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333 return -EFAULT;
Stephen Hemminger132adf52007-03-08 20:44:43 -08001334 if (len < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335 return -EINVAL;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001336
WANG Cong87e9f032015-11-03 15:41:16 -08001337 if (needs_rtnl)
1338 rtnl_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339 lock_sock(sk);
1340
Stephen Hemminger132adf52007-03-08 20:44:43 -08001341 switch (optname) {
1342 case IP_OPTIONS:
1343 {
1344 unsigned char optbuf[sizeof(struct ip_options)+40];
Eric Dumazetf6d8bd02011-04-21 09:45:37 +00001345 struct ip_options *opt = (struct ip_options *)optbuf;
1346 struct ip_options_rcu *inet_opt;
1347
1348 inet_opt = rcu_dereference_protected(inet->inet_opt,
Hannes Frederic Sowa1e1d04e2016-04-05 17:10:15 +02001349 lockdep_sock_is_held(sk));
Stephen Hemminger132adf52007-03-08 20:44:43 -08001350 opt->optlen = 0;
Eric Dumazetf6d8bd02011-04-21 09:45:37 +00001351 if (inet_opt)
1352 memcpy(optbuf, &inet_opt->opt,
1353 sizeof(struct ip_options) +
1354 inet_opt->opt.optlen);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001355 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356
Stephen Hemminger132adf52007-03-08 20:44:43 -08001357 if (opt->optlen == 0)
1358 return put_user(0, optlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359
Stephen Hemminger132adf52007-03-08 20:44:43 -08001360 ip_options_undo(opt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361
Stephen Hemminger132adf52007-03-08 20:44:43 -08001362 len = min_t(unsigned int, len, opt->optlen);
1363 if (put_user(len, optlen))
1364 return -EFAULT;
1365 if (copy_to_user(optval, opt->__data, len))
1366 return -EFAULT;
1367 return 0;
1368 }
1369 case IP_PKTINFO:
1370 val = (inet->cmsg_flags & IP_CMSG_PKTINFO) != 0;
1371 break;
1372 case IP_RECVTTL:
1373 val = (inet->cmsg_flags & IP_CMSG_TTL) != 0;
1374 break;
1375 case IP_RECVTOS:
1376 val = (inet->cmsg_flags & IP_CMSG_TOS) != 0;
1377 break;
1378 case IP_RECVOPTS:
1379 val = (inet->cmsg_flags & IP_CMSG_RECVOPTS) != 0;
1380 break;
1381 case IP_RETOPTS:
1382 val = (inet->cmsg_flags & IP_CMSG_RETOPTS) != 0;
1383 break;
1384 case IP_PASSSEC:
1385 val = (inet->cmsg_flags & IP_CMSG_PASSSEC) != 0;
1386 break;
Balazs Scheidlere8b2dfe2008-11-16 19:32:39 -08001387 case IP_RECVORIGDSTADDR:
1388 val = (inet->cmsg_flags & IP_CMSG_ORIGDSTADDR) != 0;
1389 break;
Tom Herbertad6f9392015-01-05 13:56:17 -08001390 case IP_CHECKSUM:
1391 val = (inet->cmsg_flags & IP_CMSG_CHECKSUM) != 0;
1392 break;
Willem de Bruijn70ecc242016-11-02 11:02:16 -04001393 case IP_RECVFRAGSIZE:
1394 val = (inet->cmsg_flags & IP_CMSG_RECVFRAGSIZE) != 0;
1395 break;
Stephen Hemminger132adf52007-03-08 20:44:43 -08001396 case IP_TOS:
1397 val = inet->tos;
1398 break;
1399 case IP_TTL:
Nikolay Borisovfa50d972016-02-15 12:11:27 +02001400 {
1401 struct net *net = sock_net(sk);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001402 val = (inet->uc_ttl == -1 ?
Nikolay Borisovfa50d972016-02-15 12:11:27 +02001403 net->ipv4.sysctl_ip_default_ttl :
Stephen Hemminger132adf52007-03-08 20:44:43 -08001404 inet->uc_ttl);
1405 break;
Nikolay Borisovfa50d972016-02-15 12:11:27 +02001406 }
Stephen Hemminger132adf52007-03-08 20:44:43 -08001407 case IP_HDRINCL:
1408 val = inet->hdrincl;
1409 break;
Michael Kerriska89b4762010-09-10 20:26:56 +00001410 case IP_NODEFRAG:
1411 val = inet->nodefrag;
1412 break;
Eric Dumazet90c337d2015-06-06 21:17:57 -07001413 case IP_BIND_ADDRESS_NO_PORT:
1414 val = inet->bind_address_no_port;
1415 break;
Stephen Hemminger132adf52007-03-08 20:44:43 -08001416 case IP_MTU_DISCOVER:
1417 val = inet->pmtudisc;
1418 break;
1419 case IP_MTU:
1420 {
1421 struct dst_entry *dst;
1422 val = 0;
1423 dst = sk_dst_get(sk);
1424 if (dst) {
1425 val = dst_mtu(dst);
1426 dst_release(dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427 }
Stephen Hemminger132adf52007-03-08 20:44:43 -08001428 if (!val) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429 release_sock(sk);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001430 return -ENOTCONN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431 }
Stephen Hemminger132adf52007-03-08 20:44:43 -08001432 break;
1433 }
1434 case IP_RECVERR:
1435 val = inet->recverr;
1436 break;
1437 case IP_MULTICAST_TTL:
1438 val = inet->mc_ttl;
1439 break;
1440 case IP_MULTICAST_LOOP:
1441 val = inet->mc_loop;
1442 break;
Erich E. Hoover76e21052012-02-08 09:11:07 +00001443 case IP_UNICAST_IF:
1444 val = (__force int)htonl((__u32) inet->uc_index);
1445 break;
Stephen Hemminger132adf52007-03-08 20:44:43 -08001446 case IP_MULTICAST_IF:
1447 {
1448 struct in_addr addr;
1449 len = min_t(unsigned int, len, sizeof(struct in_addr));
1450 addr.s_addr = inet->mc_addr;
1451 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452
Stephen Hemminger132adf52007-03-08 20:44:43 -08001453 if (put_user(len, optlen))
1454 return -EFAULT;
1455 if (copy_to_user(optval, &addr, len))
1456 return -EFAULT;
1457 return 0;
1458 }
1459 case IP_MSFILTER:
1460 {
1461 struct ip_msfilter msf;
Stephen Hemminger132adf52007-03-08 20:44:43 -08001462
1463 if (len < IP_MSFILTER_SIZE(0)) {
WANG Cong87e9f032015-11-03 15:41:16 -08001464 err = -EINVAL;
1465 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 }
Stephen Hemminger132adf52007-03-08 20:44:43 -08001467 if (copy_from_user(&msf, optval, IP_MSFILTER_SIZE(0))) {
WANG Cong87e9f032015-11-03 15:41:16 -08001468 err = -EFAULT;
1469 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470 }
Stephen Hemminger132adf52007-03-08 20:44:43 -08001471 err = ip_mc_msfget(sk, &msf,
1472 (struct ip_msfilter __user *)optval, optlen);
WANG Cong87e9f032015-11-03 15:41:16 -08001473 goto out;
Stephen Hemminger132adf52007-03-08 20:44:43 -08001474 }
1475 case MCAST_MSFILTER:
1476 {
1477 struct group_filter gsf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478
Stephen Hemminger132adf52007-03-08 20:44:43 -08001479 if (len < GROUP_FILTER_SIZE(0)) {
WANG Cong87e9f032015-11-03 15:41:16 -08001480 err = -EINVAL;
1481 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 }
Stephen Hemminger132adf52007-03-08 20:44:43 -08001483 if (copy_from_user(&gsf, optval, GROUP_FILTER_SIZE(0))) {
WANG Cong87e9f032015-11-03 15:41:16 -08001484 err = -EFAULT;
1485 goto out;
Stephen Hemminger132adf52007-03-08 20:44:43 -08001486 }
1487 err = ip_mc_gsfget(sk, &gsf,
Eric Dumazet4d52cfb2009-06-02 00:42:16 -07001488 (struct group_filter __user *)optval,
1489 optlen);
WANG Cong87e9f032015-11-03 15:41:16 -08001490 goto out;
Stephen Hemminger132adf52007-03-08 20:44:43 -08001491 }
Nivedita Singhvif771bef2009-05-28 07:00:46 +00001492 case IP_MULTICAST_ALL:
1493 val = inet->mc_all;
1494 break;
Stephen Hemminger132adf52007-03-08 20:44:43 -08001495 case IP_PKTOPTIONS:
1496 {
1497 struct msghdr msg;
1498
1499 release_sock(sk);
1500
1501 if (sk->sk_type != SOCK_STREAM)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502 return -ENOPROTOOPT;
Stephen Hemminger132adf52007-03-08 20:44:43 -08001503
Karoly Kemenyc54a5e02014-07-27 12:29:07 +02001504 msg.msg_control = (__force void *) optval;
Stephen Hemminger132adf52007-03-08 20:44:43 -08001505 msg.msg_controllen = len;
Daniel Balutadd23198e2011-08-07 22:31:07 -07001506 msg.msg_flags = flags;
Stephen Hemminger132adf52007-03-08 20:44:43 -08001507
1508 if (inet->cmsg_flags & IP_CMSG_PKTINFO) {
1509 struct in_pktinfo info;
1510
Eric Dumazetc720c7e2009-10-15 06:30:45 +00001511 info.ipi_addr.s_addr = inet->inet_rcv_saddr;
1512 info.ipi_spec_dst.s_addr = inet->inet_rcv_saddr;
Stephen Hemminger132adf52007-03-08 20:44:43 -08001513 info.ipi_ifindex = inet->mc_index;
1514 put_cmsg(&msg, SOL_IP, IP_PKTINFO, sizeof(info), &info);
1515 }
1516 if (inet->cmsg_flags & IP_CMSG_TTL) {
1517 int hlim = inet->mc_ttl;
1518 put_cmsg(&msg, SOL_IP, IP_TTL, sizeof(hlim), &hlim);
1519 }
Jiri Benc4c507d22012-02-09 09:35:49 +00001520 if (inet->cmsg_flags & IP_CMSG_TOS) {
1521 int tos = inet->rcv_tos;
1522 put_cmsg(&msg, SOL_IP, IP_TOS, sizeof(tos), &tos);
1523 }
Stephen Hemminger132adf52007-03-08 20:44:43 -08001524 len -= msg.msg_controllen;
1525 return put_user(len, optlen);
1526 }
1527 case IP_FREEBIND:
1528 val = inet->freebind;
1529 break;
KOVACS Krisztianf5715ae2008-10-01 07:30:02 -07001530 case IP_TRANSPARENT:
1531 val = inet->transparent;
1532 break;
Stephen Hemmingerd218d112010-01-11 16:28:01 -08001533 case IP_MINTTL:
1534 val = inet->min_ttl;
1535 break;
Stephen Hemminger132adf52007-03-08 20:44:43 -08001536 default:
1537 release_sock(sk);
1538 return -ENOPROTOOPT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 }
1540 release_sock(sk);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001541
Eric Dumazet4d52cfb2009-06-02 00:42:16 -07001542 if (len < sizeof(int) && len > 0 && val >= 0 && val <= 255) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543 unsigned char ucval = (unsigned char)val;
1544 len = 1;
Stephen Hemminger132adf52007-03-08 20:44:43 -08001545 if (put_user(len, optlen))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546 return -EFAULT;
Jianjun Kong09cb1052008-11-03 00:27:11 -08001547 if (copy_to_user(optval, &ucval, 1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548 return -EFAULT;
1549 } else {
1550 len = min_t(unsigned int, sizeof(int), len);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001551 if (put_user(len, optlen))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552 return -EFAULT;
Jianjun Kong09cb1052008-11-03 00:27:11 -08001553 if (copy_to_user(optval, &val, len))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554 return -EFAULT;
1555 }
1556 return 0;
WANG Cong87e9f032015-11-03 15:41:16 -08001557
1558out:
1559 release_sock(sk);
1560 if (needs_rtnl)
1561 rtnl_unlock();
1562 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563}
1564
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001565int ip_getsockopt(struct sock *sk, int level,
Stephen Hemminger132adf52007-03-08 20:44:43 -08001566 int optname, char __user *optval, int __user *optlen)
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001567{
1568 int err;
1569
Daniel Balutadd23198e2011-08-07 22:31:07 -07001570 err = do_ip_getsockopt(sk, level, optname, optval, optlen, 0);
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001571#ifdef CONFIG_NETFILTER
1572 /* we need to exclude all possible ENOPROTOOPTs except default case */
Pavel Emelyanov6a9fb942007-11-05 21:32:31 -08001573 if (err == -ENOPROTOOPT && optname != IP_PKTOPTIONS &&
1574 !ip_mroute_opt(optname)) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001575 int len;
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001576
Jianjun Kong09cb1052008-11-03 00:27:11 -08001577 if (get_user(len, optlen))
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001578 return -EFAULT;
1579
Paolo Abeni01ea3062018-02-08 12:19:00 +01001580 err = nf_getsockopt(sk, PF_INET, optname, optval, &len);
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001581 if (err >= 0)
1582 err = put_user(len, optlen);
1583 return err;
1584 }
1585#endif
1586 return err;
1587}
Eric Dumazet4d52cfb2009-06-02 00:42:16 -07001588EXPORT_SYMBOL(ip_getsockopt);
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001589
1590#ifdef CONFIG_COMPAT
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001591int compat_ip_getsockopt(struct sock *sk, int level, int optname,
1592 char __user *optval, int __user *optlen)
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001593{
David L Stevens42908c62008-04-29 03:23:22 -07001594 int err;
1595
1596 if (optname == MCAST_MSFILTER)
1597 return compat_mc_getsockopt(sk, level, optname, optval, optlen,
1598 ip_getsockopt);
1599
Daniel Balutadd23198e2011-08-07 22:31:07 -07001600 err = do_ip_getsockopt(sk, level, optname, optval, optlen,
1601 MSG_CMSG_COMPAT);
David L Stevens42908c62008-04-29 03:23:22 -07001602
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001603#ifdef CONFIG_NETFILTER
1604 /* we need to exclude all possible ENOPROTOOPTs except default case */
Pavel Emelyanov6a9fb942007-11-05 21:32:31 -08001605 if (err == -ENOPROTOOPT && optname != IP_PKTOPTIONS &&
1606 !ip_mroute_opt(optname)) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001607 int len;
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001608
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001609 if (get_user(len, optlen))
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001610 return -EFAULT;
1611
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001612 err = compat_nf_getsockopt(sk, PF_INET, optname, optval, &len);
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001613 if (err >= 0)
1614 err = put_user(len, optlen);
1615 return err;
1616 }
1617#endif
1618 return err;
1619}
Arnaldo Carvalho de Melo543d9cf2006-03-20 22:48:35 -08001620EXPORT_SYMBOL(compat_ip_getsockopt);
Dmitry Mishin3fdadf72006-03-20 22:45:21 -08001621#endif