Blame view

net/ipv4/ip_sockglue.c 40.9 KB
b24413180   Greg Kroah-Hartman   License cleanup: ...
1
  // SPDX-License-Identifier: GPL-2.0
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
7
  /*
   * INET		An implementation of the TCP/IP protocol suite for the LINUX
   *		operating system.  INET is implemented using the  BSD Socket
   *		interface as the means of communication with the user level.
   *
   *		The IP to API glue.
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
8
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
10
11
12
13
   * Authors:	see ip.c
   *
   * Fixes:
   *		Many		:	Split from ip.c , see ip.c for history.
   *		Martin Mares	:	TOS setting fixed.
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
14
   *		Alan Cox	:	Fixed a couple of oopses in Martin's
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
16
17
   *					TOS tweaks.
   *		Mike McLagan	:	Routing by source
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18
19
20
  #include <linux/module.h>
  #include <linux/types.h>
  #include <linux/mm.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
22
23
  #include <linux/skbuff.h>
  #include <linux/ip.h>
  #include <linux/icmp.h>
14c850212   Arnaldo Carvalho de Melo   [INET_SOCK]: Move...
24
  #include <linux/inetdevice.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
  #include <linux/netdevice.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
26
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
28
29
  #include <net/sock.h>
  #include <net/ip.h>
  #include <net/icmp.h>
d83d8461f   Arnaldo Carvalho de Melo   [IP_SOCKGLUE]: Re...
30
  #include <net/tcp_states.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
32
33
34
35
  #include <linux/udp.h>
  #include <linux/igmp.h>
  #include <linux/netfilter.h>
  #include <linux/route.h>
  #include <linux/mroute.h>
2c67e9acb   Maciej Żenczykowski   net: use INET_ECN...
36
  #include <net/inet_ecn.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
38
  #include <net/route.h>
  #include <net/xfrm.h>
dae502954   David L Stevens   ipv4/ipv6 compat:...
39
  #include <net/compat.h>
ad6f939ab   Tom Herbert   ip: Add offset pa...
40
  #include <net/checksum.h>
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
41
  #if IS_ENABLED(CONFIG_IPV6)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
43
  #include <net/transp_v6.h>
  #endif
35ebf65e8   David S. Miller   ipv4: Create and ...
44
  #include <net/ip_fib.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
46
  
  #include <linux/errqueue.h>
7c0f6ba68   Linus Torvalds   Replace <asm/uacc...
47
  #include <linux/uaccess.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
48

d2ba09c17   Alexei Starovoitov   net: add skeleton...
49
  #include <linux/bpfilter.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50
51
52
53
54
55
  /*
   *	SOL_IP control messages.
   */
  
  static void ip_cmsg_recv_pktinfo(struct msghdr *msg, struct sk_buff *skb)
  {
d826eb14e   Eric Dumazet   ipv4: PKTINFO doe...
56
  	struct in_pktinfo info = *PKTINFO_SKB_CB(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57

eddc9ec53   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
58
  	info.ipi_addr.s_addr = ip_hdr(skb)->daddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
59
60
61
62
63
64
  
  	put_cmsg(msg, SOL_IP, IP_PKTINFO, sizeof(info), &info);
  }
  
  static void ip_cmsg_recv_ttl(struct msghdr *msg, struct sk_buff *skb)
  {
eddc9ec53   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
65
  	int ttl = ip_hdr(skb)->ttl;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
66
67
68
69
70
  	put_cmsg(msg, SOL_IP, IP_TTL, sizeof(int), &ttl);
  }
  
  static void ip_cmsg_recv_tos(struct msghdr *msg, struct sk_buff *skb)
  {
eddc9ec53   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
71
  	put_cmsg(msg, SOL_IP, IP_TOS, 1, &ip_hdr(skb)->tos);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72
73
74
75
76
77
  }
  
  static void ip_cmsg_recv_opts(struct msghdr *msg, struct sk_buff *skb)
  {
  	if (IPCB(skb)->opt.optlen == 0)
  		return;
eddc9ec53   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
78
79
  	put_cmsg(msg, SOL_IP, IP_RECVOPTS, IPCB(skb)->opt.optlen,
  		 ip_hdr(skb) + 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
80
  }
91ed1e666   Paolo Abeni   ip/options: expli...
81
82
  static void ip_cmsg_recv_retopts(struct net *net, struct msghdr *msg,
  				 struct sk_buff *skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
83
84
  {
  	unsigned char optbuf[sizeof(struct ip_options) + 40];
5e73ea1a3   Daniel Baluta   ipv4: fix checkpa...
85
  	struct ip_options *opt = (struct ip_options *)optbuf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86
87
88
  
  	if (IPCB(skb)->opt.optlen == 0)
  		return;
91ed1e666   Paolo Abeni   ip/options: expli...
89
  	if (ip_options_echo(net, opt, skb)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
90
91
92
93
94
95
96
  		msg->msg_flags |= MSG_CTRUNC;
  		return;
  	}
  	ip_options_undo(opt);
  
  	put_cmsg(msg, SOL_IP, IP_RETOPTS, opt->optlen, opt->__data);
  }
70ecc2484   Willem de Bruijn   ipv4: add IP_RECV...
97
98
99
100
101
102
103
104
105
106
  static void ip_cmsg_recv_fragsize(struct msghdr *msg, struct sk_buff *skb)
  {
  	int val;
  
  	if (IPCB(skb)->frag_max_size == 0)
  		return;
  
  	val = IPCB(skb)->frag_max_size;
  	put_cmsg(msg, SOL_IP, IP_RECVFRAGSIZE, sizeof(val), &val);
  }
ad6f939ab   Tom Herbert   ip: Add offset pa...
107
  static void ip_cmsg_recv_checksum(struct msghdr *msg, struct sk_buff *skb,
10df8e615   Eric Dumazet   udp: fix IP_CHECK...
108
  				  int tlen, int offset)
ad6f939ab   Tom Herbert   ip: Add offset pa...
109
110
111
112
113
  {
  	__wsum csum = skb->csum;
  
  	if (skb->ip_summed != CHECKSUM_COMPLETE)
  		return;
ca4ef4574   Paolo Abeni   ip: fix IP_CHECKS...
114
115
116
117
  	if (offset != 0) {
  		int tend_off = skb_transport_offset(skb) + tlen;
  		csum = csum_sub(csum, skb_checksum(skb, tend_off, offset, 0));
  	}
ad6f939ab   Tom Herbert   ip: Add offset pa...
118
119
120
  
  	put_cmsg(msg, SOL_IP, IP_CHECKSUM, sizeof(__wsum), &csum);
  }
2c7946a7b   Catherine Zhang   [SECURITY]: TCP/U...
121
122
123
  static void ip_cmsg_recv_security(struct msghdr *msg, struct sk_buff *skb)
  {
  	char *secdata;
dc49c1f94   Catherine Zhang   [AF_UNIX]: Kernel...
124
  	u32 seclen, secid;
2c7946a7b   Catherine Zhang   [SECURITY]: TCP/U...
125
  	int err;
dc49c1f94   Catherine Zhang   [AF_UNIX]: Kernel...
126
127
128
129
130
  	err = security_socket_getpeersec_dgram(NULL, skb, &secid);
  	if (err)
  		return;
  
  	err = security_secid_to_secctx(secid, &secdata, &seclen);
2c7946a7b   Catherine Zhang   [SECURITY]: TCP/U...
131
132
133
134
  	if (err)
  		return;
  
  	put_cmsg(msg, SOL_IP, SCM_SECURITY, seclen, secdata);
dc49c1f94   Catherine Zhang   [AF_UNIX]: Kernel...
135
  	security_release_secctx(secdata, seclen);
2c7946a7b   Catherine Zhang   [SECURITY]: TCP/U...
136
  }
21d1a161f   Harvey Harrison   net: ip_sockglue....
137
  static void ip_cmsg_recv_dstaddr(struct msghdr *msg, struct sk_buff *skb)
e8b2dfe9b   Balazs Scheidler   TPROXY: implement...
138
  {
4a06fa67c   Willem de Bruijn   ip: on queued skb...
139
  	__be16 _ports[2], *ports;
e8b2dfe9b   Balazs Scheidler   TPROXY: implement...
140
  	struct sockaddr_in sin;
e8b2dfe9b   Balazs Scheidler   TPROXY: implement...
141
142
143
144
145
  
  	/* All current transport protocols have the port numbers in the
  	 * first four bytes of the transport header and this function is
  	 * written with this assumption in mind.
  	 */
4a06fa67c   Willem de Bruijn   ip: on queued skb...
146
147
148
149
  	ports = skb_header_pointer(skb, skb_transport_offset(skb),
  				   sizeof(_ports), &_ports);
  	if (!ports)
  		return;
e8b2dfe9b   Balazs Scheidler   TPROXY: implement...
150
151
  
  	sin.sin_family = AF_INET;
64199fc0a   Eric Dumazet   ipv4: fix use-aft...
152
  	sin.sin_addr.s_addr = ip_hdr(skb)->daddr;
e8b2dfe9b   Balazs Scheidler   TPROXY: implement...
153
154
155
156
157
  	sin.sin_port = ports[1];
  	memset(sin.sin_zero, 0, sizeof(sin.sin_zero));
  
  	put_cmsg(msg, SOL_IP, IP_ORIGDSTADDR, sizeof(sin), &sin);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
158

ad959036a   Paolo Abeni   net/sock: add an ...
159
160
  void ip_cmsg_recv_offset(struct msghdr *msg, struct sock *sk,
  			 struct sk_buff *skb, int tlen, int offset)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161
  {
ad959036a   Paolo Abeni   net/sock: add an ...
162
  	struct inet_sock *inet = inet_sk(sk);
95c961747   Eric Dumazet   net: cleanup unsi...
163
  	unsigned int flags = inet->cmsg_flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
164
165
  
  	/* Ordered by supposed usage frequency */
c44d13d6f   Tom Herbert   ip: IP cmsg cleanup
166
  	if (flags & IP_CMSG_PKTINFO) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
167
  		ip_cmsg_recv_pktinfo(msg, skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
168

c44d13d6f   Tom Herbert   ip: IP cmsg cleanup
169
170
171
172
173
174
  		flags &= ~IP_CMSG_PKTINFO;
  		if (!flags)
  			return;
  	}
  
  	if (flags & IP_CMSG_TTL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
175
  		ip_cmsg_recv_ttl(msg, skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
176

c44d13d6f   Tom Herbert   ip: IP cmsg cleanup
177
178
179
180
181
182
  		flags &= ~IP_CMSG_TTL;
  		if (!flags)
  			return;
  	}
  
  	if (flags & IP_CMSG_TOS) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
183
  		ip_cmsg_recv_tos(msg, skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
184

c44d13d6f   Tom Herbert   ip: IP cmsg cleanup
185
186
187
188
189
190
  		flags &= ~IP_CMSG_TOS;
  		if (!flags)
  			return;
  	}
  
  	if (flags & IP_CMSG_RECVOPTS) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
191
  		ip_cmsg_recv_opts(msg, skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
192

c44d13d6f   Tom Herbert   ip: IP cmsg cleanup
193
194
195
196
197
198
  		flags &= ~IP_CMSG_RECVOPTS;
  		if (!flags)
  			return;
  	}
  
  	if (flags & IP_CMSG_RETOPTS) {
91ed1e666   Paolo Abeni   ip/options: expli...
199
  		ip_cmsg_recv_retopts(sock_net(sk), msg, skb);
2c7946a7b   Catherine Zhang   [SECURITY]: TCP/U...
200

c44d13d6f   Tom Herbert   ip: IP cmsg cleanup
201
202
203
204
205
206
  		flags &= ~IP_CMSG_RETOPTS;
  		if (!flags)
  			return;
  	}
  
  	if (flags & IP_CMSG_PASSSEC) {
2c7946a7b   Catherine Zhang   [SECURITY]: TCP/U...
207
  		ip_cmsg_recv_security(msg, skb);
e8b2dfe9b   Balazs Scheidler   TPROXY: implement...
208

c44d13d6f   Tom Herbert   ip: IP cmsg cleanup
209
210
211
212
  		flags &= ~IP_CMSG_PASSSEC;
  		if (!flags)
  			return;
  	}
ad6f939ab   Tom Herbert   ip: Add offset pa...
213
  	if (flags & IP_CMSG_ORIGDSTADDR) {
e8b2dfe9b   Balazs Scheidler   TPROXY: implement...
214
  		ip_cmsg_recv_dstaddr(msg, skb);
ad6f939ab   Tom Herbert   ip: Add offset pa...
215
216
217
218
219
220
  		flags &= ~IP_CMSG_ORIGDSTADDR;
  		if (!flags)
  			return;
  	}
  
  	if (flags & IP_CMSG_CHECKSUM)
10df8e615   Eric Dumazet   udp: fix IP_CHECK...
221
  		ip_cmsg_recv_checksum(msg, skb, tlen, offset);
70ecc2484   Willem de Bruijn   ipv4: add IP_RECV...
222
223
224
  
  	if (flags & IP_CMSG_RECVFRAGSIZE)
  		ip_cmsg_recv_fragsize(msg, skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
225
  }
5961de9f1   Tom Herbert   ip: Add offset pa...
226
  EXPORT_SYMBOL(ip_cmsg_recv_offset);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
227

24025c465   Soheil Hassas Yeganeh   ipv4: process soc...
228
  int ip_cmsg_send(struct sock *sk, struct msghdr *msg, struct ipcm_cookie *ipc,
c8e6ad082   Hannes Frederic Sowa   ipv6: honor IPV6_...
229
  		 bool allow_ipv6)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
230
  {
f02db315b   Francesco Fusco   ipv4: IP_TOS and ...
231
  	int err, val;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
232
  	struct cmsghdr *cmsg;
24025c465   Soheil Hassas Yeganeh   ipv4: process soc...
233
  	struct net *net = sock_net(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
234

f95b414ed   Gu Zheng   net: introduce he...
235
  	for_each_cmsghdr(cmsg, msg) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
236
237
  		if (!CMSG_OK(msg, cmsg))
  			return -EINVAL;
5337b5b75   Eric Dumazet   ipv6: fix IPV6_PK...
238
  #if IS_ENABLED(CONFIG_IPV6)
c8e6ad082   Hannes Frederic Sowa   ipv6: honor IPV6_...
239
240
241
242
243
244
245
246
247
248
  		if (allow_ipv6 &&
  		    cmsg->cmsg_level == SOL_IPV6 &&
  		    cmsg->cmsg_type == IPV6_PKTINFO) {
  			struct in6_pktinfo *src_info;
  
  			if (cmsg->cmsg_len < CMSG_LEN(sizeof(*src_info)))
  				return -EINVAL;
  			src_info = (struct in6_pktinfo *)CMSG_DATA(cmsg);
  			if (!ipv6_addr_v4mapped(&src_info->ipi6_addr))
  				return -EINVAL;
1cbec0764   David Ahern   net: Only honor i...
249
250
  			if (src_info->ipi6_ifindex)
  				ipc->oif = src_info->ipi6_ifindex;
c8e6ad082   Hannes Frederic Sowa   ipv6: honor IPV6_...
251
252
253
254
  			ipc->addr = src_info->ipi6_addr.s6_addr32[3];
  			continue;
  		}
  #endif
24025c465   Soheil Hassas Yeganeh   ipv4: process soc...
255
  		if (cmsg->cmsg_level == SOL_SOCKET) {
2632616bc   Eric Dumazet   sock: propagate _...
256
257
258
  			err = __sock_cmsg_send(sk, msg, cmsg, &ipc->sockc);
  			if (err)
  				return err;
24025c465   Soheil Hassas Yeganeh   ipv4: process soc...
259
260
  			continue;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
261
262
263
264
  		if (cmsg->cmsg_level != SOL_IP)
  			continue;
  		switch (cmsg->cmsg_type) {
  		case IP_RETOPTS:
1ff8cebf4   yuan linyu   scm: remove use C...
265
  			err = cmsg->cmsg_len - sizeof(struct cmsghdr);
919483096   Eric Dumazet   ipv4: fix memory ...
266
267
  
  			/* Our caller is responsible for freeing ipc->opt */
de40a3e88   Christoph Hellwig   net/ipv4: merge i...
268
269
  			err = ip_options_get(net, &ipc->opt,
  					     KERNEL_SOCKPTR(CMSG_DATA(cmsg)),
4d52cfbef   Eric Dumazet   net: ipv4/ip_sock...
270
  					     err < 40 ? err : 40);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
271
272
273
274
275
276
277
278
279
  			if (err)
  				return err;
  			break;
  		case IP_PKTINFO:
  		{
  			struct in_pktinfo *info;
  			if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct in_pktinfo)))
  				return -EINVAL;
  			info = (struct in_pktinfo *)CMSG_DATA(cmsg);
1cbec0764   David Ahern   net: Only honor i...
280
281
  			if (info->ipi_ifindex)
  				ipc->oif = info->ipi_ifindex;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
282
283
284
  			ipc->addr = info->ipi_spec_dst.s_addr;
  			break;
  		}
f02db315b   Francesco Fusco   ipv4: IP_TOS and ...
285
286
287
288
289
290
291
292
293
  		case IP_TTL:
  			if (cmsg->cmsg_len != CMSG_LEN(sizeof(int)))
  				return -EINVAL;
  			val = *(int *)CMSG_DATA(cmsg);
  			if (val < 1 || val > 255)
  				return -EINVAL;
  			ipc->ttl = val;
  			break;
  		case IP_TOS:
e895cdce6   Eric Dumazet   ipv4: accept u8 i...
294
295
296
297
298
  			if (cmsg->cmsg_len == CMSG_LEN(sizeof(int)))
  				val = *(int *)CMSG_DATA(cmsg);
  			else if (cmsg->cmsg_len == CMSG_LEN(sizeof(u8)))
  				val = *(u8 *)CMSG_DATA(cmsg);
  			else
f02db315b   Francesco Fusco   ipv4: IP_TOS and ...
299
  				return -EINVAL;
f02db315b   Francesco Fusco   ipv4: IP_TOS and ...
300
301
302
303
304
  			if (val < 0 || val > 255)
  				return -EINVAL;
  			ipc->tos = val;
  			ipc->priority = rt_tos2priority(ipc->tos);
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
305
306
307
308
309
310
  		default:
  			return -EINVAL;
  		}
  	}
  	return 0;
  }
592fcb9df   Eric Dumazet   ip: ip_ra_control...
311
  static void ip_ra_destroy_rcu(struct rcu_head *head)
66018506e   Eric Dumazet   ip: Router Alert ...
312
  {
592fcb9df   Eric Dumazet   ip: ip_ra_control...
313
314
315
316
  	struct ip_ra_chain *ra = container_of(head, struct ip_ra_chain, rcu);
  
  	sock_put(ra->saved_sk);
  	kfree(ra);
66018506e   Eric Dumazet   ip: Router Alert ...
317
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
318

4d52cfbef   Eric Dumazet   net: ipv4/ip_sock...
319
320
  int ip_ra_control(struct sock *sk, unsigned char on,
  		  void (*destructor)(struct sock *))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
321
  {
43a951e99   Eric Dumazet   ipv4: add __rcu a...
322
323
  	struct ip_ra_chain *ra, *new_ra;
  	struct ip_ra_chain __rcu **rap;
5796ef75e   Kirill Tkhai   net: Make ip_ra_c...
324
  	struct net *net = sock_net(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
325

c720c7e83   Eric Dumazet   inet: rename some...
326
  	if (sk->sk_type != SOCK_RAW || inet_sk(sk)->inet_num == IPPROTO_RAW)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
327
328
329
  		return -EINVAL;
  
  	new_ra = on ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL;
425aa0e1d   Gen Zhang   ip_sockglue: Fix ...
330
331
  	if (on && !new_ra)
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
332

d9ff30497   Kirill Tkhai   net: Replace ip_r...
333
  	mutex_lock(&net->ipv4.ra_mutex);
5796ef75e   Kirill Tkhai   net: Make ip_ra_c...
334
  	for (rap = &net->ipv4.ra_chain;
76d3e153d   Kirill Tkhai   net: Revert "ipv4...
335
  	     (ra = rcu_dereference_protected(*rap,
d9ff30497   Kirill Tkhai   net: Replace ip_r...
336
  			lockdep_is_held(&net->ipv4.ra_mutex))) != NULL;
43a951e99   Eric Dumazet   ipv4: add __rcu a...
337
  	     rap = &ra->next) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
338
339
  		if (ra->sk == sk) {
  			if (on) {
d9ff30497   Kirill Tkhai   net: Replace ip_r...
340
  				mutex_unlock(&net->ipv4.ra_mutex);
a51482bde   Jesper Juhl   [NET]: kfree cleanup
341
  				kfree(new_ra);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
342
343
  				return -EADDRINUSE;
  			}
592fcb9df   Eric Dumazet   ip: ip_ra_control...
344
345
  			/* dont let ip_call_ra_chain() use sk again */
  			ra->sk = NULL;
8e380f004   Eric Dumazet   ipv4: rcu cleanup...
346
  			RCU_INIT_POINTER(*rap, ra->next);
d9ff30497   Kirill Tkhai   net: Replace ip_r...
347
  			mutex_unlock(&net->ipv4.ra_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
348
349
350
  
  			if (ra->destructor)
  				ra->destructor(sk);
592fcb9df   Eric Dumazet   ip: ip_ra_control...
351
352
353
354
355
356
357
  			/*
  			 * Delay sock_put(sk) and kfree(ra) after one rcu grace
  			 * period. This guarantee ip_call_ra_chain() dont need
  			 * to mess with socket refcounts.
  			 */
  			ra->saved_sk = sk;
  			call_rcu(&ra->rcu, ip_ra_destroy_rcu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
358
359
360
  			return 0;
  		}
  	}
76d3e153d   Kirill Tkhai   net: Revert "ipv4...
361
  	if (!new_ra) {
d9ff30497   Kirill Tkhai   net: Replace ip_r...
362
  		mutex_unlock(&net->ipv4.ra_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
363
  		return -ENOBUFS;
76d3e153d   Kirill Tkhai   net: Revert "ipv4...
364
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
365
366
  	new_ra->sk = sk;
  	new_ra->destructor = destructor;
8e380f004   Eric Dumazet   ipv4: rcu cleanup...
367
  	RCU_INIT_POINTER(new_ra->next, ra);
66018506e   Eric Dumazet   ip: Router Alert ...
368
  	rcu_assign_pointer(*rap, new_ra);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
369
  	sock_hold(sk);
d9ff30497   Kirill Tkhai   net: Replace ip_r...
370
  	mutex_unlock(&net->ipv4.ra_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
371
372
373
  
  	return 0;
  }
178c49d9f   Willem de Bruijn   icmp: prepare rfc...
374
375
376
377
378
379
380
381
382
383
384
  static void ipv4_icmp_error_rfc4884(const struct sk_buff *skb,
  				    struct sock_ee_data_rfc4884 *out)
  {
  	switch (icmp_hdr(skb)->type) {
  	case ICMP_DEST_UNREACH:
  	case ICMP_TIME_EXCEEDED:
  	case ICMP_PARAMETERPROB:
  		ip_icmp_error_rfc4884(skb, out, sizeof(struct icmphdr),
  				      icmp_hdr(skb)->un.reserved[1] * 4);
  	}
  }
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
385
  void ip_icmp_error(struct sock *sk, struct sk_buff *skb, int err,
35986b329   Al Viro   [IPV4]: ip_icmp_e...
386
  		   __be16 port, u32 info, u8 *payload)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
387
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
388
  	struct sock_exterr_skb *serr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
389
390
391
  	skb = skb_clone(skb, GFP_ATOMIC);
  	if (!skb)
  		return;
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
392
  	serr = SKB_EXT_ERR(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
393
394
  	serr->ee.ee_errno = err;
  	serr->ee.ee_origin = SO_EE_ORIGIN_ICMP;
88c7664f1   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
395
396
  	serr->ee.ee_type = icmp_hdr(skb)->type;
  	serr->ee.ee_code = icmp_hdr(skb)->code;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
397
398
399
  	serr->ee.ee_pad = 0;
  	serr->ee.ee_info = info;
  	serr->ee.ee_data = 0;
88c7664f1   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
400
  	serr->addr_offset = (u8 *)&(((struct iphdr *)(icmp_hdr(skb) + 1))->daddr) -
d56f90a7c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
401
  				   skb_network_header(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
402
  	serr->port = port;
00db41243   Ian Morris   ipv4: coding styl...
403
  	if (skb_pull(skb, payload - skb->data)) {
eba75c587   Willem de Bruijn   icmp: support rfc...
404
  		if (inet_sk(sk)->recverr_rfc4884)
178c49d9f   Willem de Bruijn   icmp: prepare rfc...
405
  			ipv4_icmp_error_rfc4884(skb, &serr->ee.ee_rfc4884);
eba75c587   Willem de Bruijn   icmp: support rfc...
406

bd82393ca   Arnaldo Carvalho de Melo   [SK_BUFF]: More s...
407
408
409
410
411
  		skb_reset_transport_header(skb);
  		if (sock_queue_err_skb(sk, skb) == 0)
  			return;
  	}
  	kfree_skb(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
412
  }
0579016ec   Al Viro   [IPV4]: ip_local_...
413
  void ip_local_error(struct sock *sk, int err, __be32 daddr, __be16 port, u32 info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
414
415
416
417
418
419
420
421
422
423
424
425
  {
  	struct inet_sock *inet = inet_sk(sk);
  	struct sock_exterr_skb *serr;
  	struct iphdr *iph;
  	struct sk_buff *skb;
  
  	if (!inet->recverr)
  		return;
  
  	skb = alloc_skb(sizeof(struct iphdr), GFP_ATOMIC);
  	if (!skb)
  		return;
2ca9e6f2c   Arnaldo Carvalho de Melo   [SK_BUFF]: Some m...
426
427
  	skb_put(skb, sizeof(struct iphdr));
  	skb_reset_network_header(skb);
eddc9ec53   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
428
  	iph = ip_hdr(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
429
  	iph->daddr = daddr;
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
430
  	serr = SKB_EXT_ERR(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
431
432
  	serr->ee.ee_errno = err;
  	serr->ee.ee_origin = SO_EE_ORIGIN_LOCAL;
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
433
  	serr->ee.ee_type = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
434
435
436
437
  	serr->ee.ee_code = 0;
  	serr->ee.ee_pad = 0;
  	serr->ee.ee_info = info;
  	serr->ee.ee_data = 0;
d56f90a7c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
438
  	serr->addr_offset = (u8 *)&iph->daddr - skb_network_header(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
439
  	serr->port = port;
27a884dc3   Arnaldo Carvalho de Melo   [SK_BUFF]: Conver...
440
  	__skb_pull(skb, skb_tail_pointer(skb) - skb->data);
bd82393ca   Arnaldo Carvalho de Melo   [SK_BUFF]: More s...
441
  	skb_reset_transport_header(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
442
443
444
445
  
  	if (sock_queue_err_skb(sk, skb))
  		kfree_skb(skb);
  }
34b99df4e   Julian Anastasov   ip: report the or...
446
447
448
449
450
451
452
453
  /* For some errors we have valid addr_offset even with zero payload and
   * zero port. Also, addr_offset should be supported if port is set.
   */
  static inline bool ipv4_datagram_support_addr(struct sock_exterr_skb *serr)
  {
  	return serr->ee.ee_origin == SO_EE_ORIGIN_ICMP ||
  	       serr->ee.ee_origin == SO_EE_ORIGIN_LOCAL || serr->port;
  }
c247f0534   Willem de Bruijn   ip: fix error que...
454
455
456
457
458
459
460
461
  /* IPv4 supports cmsg on all imcp errors and some timestamps
   *
   * Timestamp code paths do not initialize the fields expected by cmsg:
   * the PKTINFO fields in skb->cb[]. Fill those in here.
   */
  static bool ipv4_datagram_support_cmsg(const struct sock *sk,
  				       struct sk_buff *skb,
  				       int ee_origin)
829ae9d61   Willem de Bruijn   net-timestamp: al...
462
  {
c247f0534   Willem de Bruijn   ip: fix error que...
463
464
465
466
  	struct in_pktinfo *info;
  
  	if (ee_origin == SO_EE_ORIGIN_ICMP)
  		return true;
829ae9d61   Willem de Bruijn   net-timestamp: al...
467

c247f0534   Willem de Bruijn   ip: fix error que...
468
469
470
471
  	if (ee_origin == SO_EE_ORIGIN_LOCAL)
  		return false;
  
  	/* Support IP_PKTINFO on tstamp packets if requested, to correlate
1862d6208   Willem de Bruijn   net-timestamp: av...
472
  	 * timestamp with egress dev. Not possible for packets without iif
c247f0534   Willem de Bruijn   ip: fix error que...
473
474
  	 * or without payload (SOF_TIMESTAMPING_OPT_TSONLY).
  	 */
1862d6208   Willem de Bruijn   net-timestamp: av...
475
476
477
  	info = PKTINFO_SKB_CB(skb);
  	if (!(sk->sk_tsflags & SOF_TIMESTAMPING_OPT_CMSG) ||
  	    !info->ipi_ifindex)
829ae9d61   Willem de Bruijn   net-timestamp: al...
478
479
480
  		return false;
  
  	info->ipi_spec_dst.s_addr = ip_hdr(skb)->saddr;
829ae9d61   Willem de Bruijn   net-timestamp: al...
481
482
  	return true;
  }
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
483
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
484
485
   *	Handle MSG_ERRQUEUE
   */
85fbaa750   Hannes Frederic Sowa   inet: fix addr_le...
486
  int ip_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
487
488
  {
  	struct sock_exterr_skb *serr;
364a9e932   Willem de Bruijn   sock: deduplicate...
489
  	struct sk_buff *skb;
342dfc306   Steffen Hurrle   net: add build-ti...
490
  	DECLARE_SOCKADDR(struct sockaddr_in *, sin, msg->msg_name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
491
492
493
494
495
496
497
498
  	struct {
  		struct sock_extended_err ee;
  		struct sockaddr_in	 offender;
  	} errhdr;
  	int err;
  	int copied;
  
  	err = -EAGAIN;
364a9e932   Willem de Bruijn   sock: deduplicate...
499
  	skb = sock_dequeue_err_skb(sk);
51456b291   Ian Morris   ipv4: coding styl...
500
  	if (!skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
501
502
503
504
505
506
507
  		goto out;
  
  	copied = skb->len;
  	if (copied > len) {
  		msg->msg_flags |= MSG_TRUNC;
  		copied = len;
  	}
51f3d02b9   David S. Miller   net: Add and use ...
508
  	err = skb_copy_datagram_msg(skb, 0, msg, copied);
960a26282   Eric Dumazet   net: better drop ...
509
510
511
512
  	if (unlikely(err)) {
  		kfree_skb(skb);
  		return err;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
513
514
515
  	sock_recv_timestamp(msg, sk, skb);
  
  	serr = SKB_EXT_ERR(skb);
34b99df4e   Julian Anastasov   ip: report the or...
516
  	if (sin && ipv4_datagram_support_addr(serr)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
517
  		sin->sin_family = AF_INET;
d56f90a7c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
518
519
  		sin->sin_addr.s_addr = *(__be32 *)(skb_network_header(skb) +
  						   serr->addr_offset);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
520
521
  		sin->sin_port = serr->port;
  		memset(&sin->sin_zero, 0, sizeof(sin->sin_zero));
85fbaa750   Hannes Frederic Sowa   inet: fix addr_le...
522
  		*addr_len = sizeof(*sin);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
523
524
525
526
  	}
  
  	memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err));
  	sin = &errhdr.offender;
f812116b1   Willem de Bruijn   ip: zero sockaddr...
527
  	memset(sin, 0, sizeof(*sin));
829ae9d61   Willem de Bruijn   net-timestamp: al...
528

c247f0534   Willem de Bruijn   ip: fix error que...
529
  	if (ipv4_datagram_support_cmsg(sk, skb, serr->ee.ee_origin)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
530
  		sin->sin_family = AF_INET;
eddc9ec53   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
531
  		sin->sin_addr.s_addr = ip_hdr(skb)->saddr;
f812116b1   Willem de Bruijn   ip: zero sockaddr...
532
  		if (inet_sk(sk)->cmsg_flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
533
534
535
536
537
538
539
540
541
  			ip_cmsg_recv(msg, skb);
  	}
  
  	put_cmsg(msg, SOL_IP, IP_RECVERR, sizeof(errhdr), &errhdr);
  
  	/* Now we could try to dump offended packet options */
  
  	msg->msg_flags |= MSG_ERRQUEUE;
  	err = copied;
960a26282   Eric Dumazet   net: better drop ...
542
  	consume_skb(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
543
544
545
  out:
  	return err;
  }
6ebf71bab   Christoph Hellwig   ipv4: add ip_sock...
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
  static void __ip_sock_set_tos(struct sock *sk, int val)
  {
  	if (sk->sk_type == SOCK_STREAM) {
  		val &= ~INET_ECN_MASK;
  		val |= inet_sk(sk)->tos & INET_ECN_MASK;
  	}
  	if (inet_sk(sk)->tos != val) {
  		inet_sk(sk)->tos = val;
  		sk->sk_priority = rt_tos2priority(val);
  		sk_dst_reset(sk);
  	}
  }
  
  void ip_sock_set_tos(struct sock *sk, int val)
  {
  	lock_sock(sk);
  	__ip_sock_set_tos(sk, val);
  	release_sock(sk);
  }
  EXPORT_SYMBOL(ip_sock_set_tos);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
566

c4e446bf5   Christoph Hellwig   ipv4: add ip_sock...
567
568
569
570
571
572
573
  void ip_sock_set_freebind(struct sock *sk)
  {
  	lock_sock(sk);
  	inet_sk(sk)->freebind = true;
  	release_sock(sk);
  }
  EXPORT_SYMBOL(ip_sock_set_freebind);
db45c0ef2   Christoph Hellwig   ipv4: add ip_sock...
574
575
576
577
578
579
580
  void ip_sock_set_recverr(struct sock *sk)
  {
  	lock_sock(sk);
  	inet_sk(sk)->recverr = true;
  	release_sock(sk);
  }
  EXPORT_SYMBOL(ip_sock_set_recverr);
2de569bda   Christoph Hellwig   ipv4: add ip_sock...
581
582
583
584
585
586
587
588
589
590
  int ip_sock_set_mtu_discover(struct sock *sk, int val)
  {
  	if (val < IP_PMTUDISC_DONT || val > IP_PMTUDISC_OMIT)
  		return -EINVAL;
  	lock_sock(sk);
  	inet_sk(sk)->pmtudisc = val;
  	release_sock(sk);
  	return 0;
  }
  EXPORT_SYMBOL(ip_sock_set_mtu_discover);
c1f9ec577   Christoph Hellwig   ipv4: add ip_sock...
591
592
593
594
595
596
597
  void ip_sock_set_pktinfo(struct sock *sk)
  {
  	lock_sock(sk);
  	inet_sk(sk)->cmsg_flags |= IP_CMSG_PKTINFO;
  	release_sock(sk);
  }
  EXPORT_SYMBOL(ip_sock_set_pktinfo);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
598
  /*
4d52cfbef   Eric Dumazet   net: ipv4/ip_sock...
599
600
   *	Socket option code for IP. This is the end of the line after any
   *	TCP,UDP etc options on an IP socket.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
601
   */
baf606d9c   Marcelo Ricardo Leitner   ipv4,ipv6: grab r...
602
603
604
605
606
  static bool setsockopt_needs_rtnl(int optname)
  {
  	switch (optname) {
  	case IP_ADD_MEMBERSHIP:
  	case IP_ADD_SOURCE_MEMBERSHIP:
54ff9ef36   Marcelo Ricardo Leitner   ipv4, ipv6: kill ...
607
  	case IP_BLOCK_SOURCE:
baf606d9c   Marcelo Ricardo Leitner   ipv4,ipv6: grab r...
608
  	case IP_DROP_MEMBERSHIP:
54ff9ef36   Marcelo Ricardo Leitner   ipv4, ipv6: kill ...
609
610
611
612
613
  	case IP_DROP_SOURCE_MEMBERSHIP:
  	case IP_MSFILTER:
  	case IP_UNBLOCK_SOURCE:
  	case MCAST_BLOCK_SOURCE:
  	case MCAST_MSFILTER:
baf606d9c   Marcelo Ricardo Leitner   ipv4,ipv6: grab r...
614
  	case MCAST_JOIN_GROUP:
54ff9ef36   Marcelo Ricardo Leitner   ipv4, ipv6: kill ...
615
  	case MCAST_JOIN_SOURCE_GROUP:
baf606d9c   Marcelo Ricardo Leitner   ipv4,ipv6: grab r...
616
  	case MCAST_LEAVE_GROUP:
54ff9ef36   Marcelo Ricardo Leitner   ipv4, ipv6: kill ...
617
618
  	case MCAST_LEAVE_SOURCE_GROUP:
  	case MCAST_UNBLOCK_SOURCE:
baf606d9c   Marcelo Ricardo Leitner   ipv4,ipv6: grab r...
619
620
621
622
  		return true;
  	}
  	return false;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
623

e986d4dab   Al Viro   set_mcast_msfilte...
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
  static int set_mcast_msfilter(struct sock *sk, int ifindex,
  			      int numsrc, int fmode,
  			      struct sockaddr_storage *group,
  			      struct sockaddr_storage *list)
  {
  	int msize = IP_MSFILTER_SIZE(numsrc);
  	struct ip_msfilter *msf;
  	struct sockaddr_in *psin;
  	int err, i;
  
  	msf = kmalloc(msize, GFP_KERNEL);
  	if (!msf)
  		return -ENOBUFS;
  
  	psin = (struct sockaddr_in *)group;
  	if (psin->sin_family != AF_INET)
  		goto Eaddrnotavail;
  	msf->imsf_multiaddr = psin->sin_addr.s_addr;
  	msf->imsf_interface = 0;
  	msf->imsf_fmode = fmode;
  	msf->imsf_numsrc = numsrc;
  	for (i = 0; i < numsrc; ++i) {
  		psin = (struct sockaddr_in *)&list[i];
  
  		if (psin->sin_family != AF_INET)
  			goto Eaddrnotavail;
  		msf->imsf_slist[i] = psin->sin_addr.s_addr;
  	}
  	err = ip_mc_msfilter(sk, msf, ifindex);
  	kfree(msf);
  	return err;
  
  Eaddrnotavail:
  	kfree(msf);
  	return -EADDRNOTAVAIL;
  }
89654c5fc   Christoph Hellwig   net/ipv4: switch ...
660
661
  static int copy_group_source_from_sockptr(struct group_source_req *greqs,
  		sockptr_t optval, int optlen)
b6238c04c   Christoph Hellwig   net/ipv4: remove ...
662
663
664
665
666
667
  {
  	if (in_compat_syscall()) {
  		struct compat_group_source_req gr32;
  
  		if (optlen != sizeof(gr32))
  			return -EINVAL;
89654c5fc   Christoph Hellwig   net/ipv4: switch ...
668
  		if (copy_from_sockptr(&gr32, optval, sizeof(gr32)))
b6238c04c   Christoph Hellwig   net/ipv4: remove ...
669
670
671
672
673
674
675
  			return -EFAULT;
  		greqs->gsr_interface = gr32.gsr_interface;
  		greqs->gsr_group = gr32.gsr_group;
  		greqs->gsr_source = gr32.gsr_source;
  	} else {
  		if (optlen != sizeof(*greqs))
  			return -EINVAL;
89654c5fc   Christoph Hellwig   net/ipv4: switch ...
676
  		if (copy_from_sockptr(greqs, optval, sizeof(*greqs)))
b6238c04c   Christoph Hellwig   net/ipv4: remove ...
677
678
679
680
681
  			return -EFAULT;
  	}
  
  	return 0;
  }
2bbf8c1ea   Al Viro   ipv4: take handli...
682
  static int do_mcast_group_source(struct sock *sk, int optname,
89654c5fc   Christoph Hellwig   net/ipv4: switch ...
683
  		sockptr_t optval, int optlen)
2bbf8c1ea   Al Viro   ipv4: take handli...
684
  {
b6238c04c   Christoph Hellwig   net/ipv4: remove ...
685
  	struct group_source_req greqs;
2bbf8c1ea   Al Viro   ipv4: take handli...
686
687
688
  	struct ip_mreq_source mreqs;
  	struct sockaddr_in *psin;
  	int omode, add, err;
89654c5fc   Christoph Hellwig   net/ipv4: switch ...
689
  	err = copy_group_source_from_sockptr(&greqs, optval, optlen);
b6238c04c   Christoph Hellwig   net/ipv4: remove ...
690
691
692
693
694
  	if (err)
  		return err;
  
  	if (greqs.gsr_group.ss_family != AF_INET ||
  	    greqs.gsr_source.ss_family != AF_INET)
2bbf8c1ea   Al Viro   ipv4: take handli...
695
  		return -EADDRNOTAVAIL;
b6238c04c   Christoph Hellwig   net/ipv4: remove ...
696
  	psin = (struct sockaddr_in *)&greqs.gsr_group;
2bbf8c1ea   Al Viro   ipv4: take handli...
697
  	mreqs.imr_multiaddr = psin->sin_addr.s_addr;
b6238c04c   Christoph Hellwig   net/ipv4: remove ...
698
  	psin = (struct sockaddr_in *)&greqs.gsr_source;
2bbf8c1ea   Al Viro   ipv4: take handli...
699
700
701
702
703
704
705
706
707
708
709
  	mreqs.imr_sourceaddr = psin->sin_addr.s_addr;
  	mreqs.imr_interface = 0; /* use index for mc_source */
  
  	if (optname == MCAST_BLOCK_SOURCE) {
  		omode = MCAST_EXCLUDE;
  		add = 1;
  	} else if (optname == MCAST_UNBLOCK_SOURCE) {
  		omode = MCAST_EXCLUDE;
  		add = 0;
  	} else if (optname == MCAST_JOIN_SOURCE_GROUP) {
  		struct ip_mreqn mreq;
b6238c04c   Christoph Hellwig   net/ipv4: remove ...
710
  		psin = (struct sockaddr_in *)&greqs.gsr_group;
2bbf8c1ea   Al Viro   ipv4: take handli...
711
712
  		mreq.imr_multiaddr = psin->sin_addr;
  		mreq.imr_address.s_addr = 0;
b6238c04c   Christoph Hellwig   net/ipv4: remove ...
713
  		mreq.imr_ifindex = greqs.gsr_interface;
2bbf8c1ea   Al Viro   ipv4: take handli...
714
715
716
  		err = ip_mc_join_group_ssm(sk, &mreq, MCAST_INCLUDE);
  		if (err && err != -EADDRINUSE)
  			return err;
b6238c04c   Christoph Hellwig   net/ipv4: remove ...
717
  		greqs.gsr_interface = mreq.imr_ifindex;
2bbf8c1ea   Al Viro   ipv4: take handli...
718
719
720
721
722
723
  		omode = MCAST_INCLUDE;
  		add = 1;
  	} else /* MCAST_LEAVE_SOURCE_GROUP */ {
  		omode = MCAST_INCLUDE;
  		add = 0;
  	}
b6238c04c   Christoph Hellwig   net/ipv4: remove ...
724
  	return ip_mc_source(add, omode, sk, &mreqs, greqs.gsr_interface);
2bbf8c1ea   Al Viro   ipv4: take handli...
725
  }
89654c5fc   Christoph Hellwig   net/ipv4: switch ...
726
  static int ip_set_mcast_msfilter(struct sock *sk, sockptr_t optval, int optlen)
d62c38f6a   Christoph Hellwig   net/ipv4: factor ...
727
728
729
730
731
732
733
734
  {
  	struct group_filter *gsf = NULL;
  	int err;
  
  	if (optlen < GROUP_FILTER_SIZE(0))
  		return -EINVAL;
  	if (optlen > sysctl_optmem_max)
  		return -ENOBUFS;
89654c5fc   Christoph Hellwig   net/ipv4: switch ...
735
  	gsf = memdup_sockptr(optval, optlen);
d62c38f6a   Christoph Hellwig   net/ipv4: factor ...
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
  	if (IS_ERR(gsf))
  		return PTR_ERR(gsf);
  
  	/* numsrc >= (4G-140)/128 overflow in 32 bits */
  	err = -ENOBUFS;
  	if (gsf->gf_numsrc >= 0x1ffffff ||
  	    gsf->gf_numsrc > sock_net(sk)->ipv4.sysctl_igmp_max_msf)
  		goto out_free_gsf;
  
  	err = -EINVAL;
  	if (GROUP_FILTER_SIZE(gsf->gf_numsrc) > optlen)
  		goto out_free_gsf;
  
  	err = set_mcast_msfilter(sk, gsf->gf_interface, gsf->gf_numsrc,
  				 gsf->gf_fmode, &gsf->gf_group, gsf->gf_slist);
  out_free_gsf:
  	kfree(gsf);
  	return err;
  }
89654c5fc   Christoph Hellwig   net/ipv4: switch ...
755
  static int compat_ip_set_mcast_msfilter(struct sock *sk, sockptr_t optval,
d62c38f6a   Christoph Hellwig   net/ipv4: factor ...
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
  		int optlen)
  {
  	const int size0 = offsetof(struct compat_group_filter, gf_slist);
  	struct compat_group_filter *gf32;
  	unsigned int n;
  	void *p;
  	int err;
  
  	if (optlen < size0)
  		return -EINVAL;
  	if (optlen > sysctl_optmem_max - 4)
  		return -ENOBUFS;
  
  	p = kmalloc(optlen + 4, GFP_KERNEL);
  	if (!p)
  		return -ENOMEM;
  	gf32 = p + 4; /* we want ->gf_group and ->gf_slist aligned */
  
  	err = -EFAULT;
89654c5fc   Christoph Hellwig   net/ipv4: switch ...
775
  	if (copy_from_sockptr(gf32, optval, optlen))
d62c38f6a   Christoph Hellwig   net/ipv4: factor ...
776
777
778
779
780
781
782
783
784
785
786
  		goto out_free_gsf;
  
  	/* numsrc >= (4G-140)/128 overflow in 32 bits */
  	n = gf32->gf_numsrc;
  	err = -ENOBUFS;
  	if (n >= 0x1ffffff)
  		goto out_free_gsf;
  
  	err = -EINVAL;
  	if (offsetof(struct compat_group_filter, gf_slist[n]) > optlen)
  		goto out_free_gsf;
d62c38f6a   Christoph Hellwig   net/ipv4: factor ...
787
788
789
  	/* numsrc >= (4G-140)/128 overflow in 32 bits */
  	err = -ENOBUFS;
  	if (n > sock_net(sk)->ipv4.sysctl_igmp_max_msf)
b6238c04c   Christoph Hellwig   net/ipv4: remove ...
790
  		goto out_free_gsf;
d62c38f6a   Christoph Hellwig   net/ipv4: factor ...
791
792
  	err = set_mcast_msfilter(sk, gf32->gf_interface, n, gf32->gf_fmode,
  				 &gf32->gf_group, gf32->gf_slist);
d62c38f6a   Christoph Hellwig   net/ipv4: factor ...
793
794
795
796
  out_free_gsf:
  	kfree(p);
  	return err;
  }
d62c38f6a   Christoph Hellwig   net/ipv4: factor ...
797

02caad7cc   Christoph Hellwig   net/ipv4: factor ...
798
  static int ip_mcast_join_leave(struct sock *sk, int optname,
89654c5fc   Christoph Hellwig   net/ipv4: switch ...
799
  		sockptr_t optval, int optlen)
02caad7cc   Christoph Hellwig   net/ipv4: factor ...
800
801
802
803
804
805
806
  {
  	struct ip_mreqn mreq = { };
  	struct sockaddr_in *psin;
  	struct group_req greq;
  
  	if (optlen < sizeof(struct group_req))
  		return -EINVAL;
89654c5fc   Christoph Hellwig   net/ipv4: switch ...
807
  	if (copy_from_sockptr(&greq, optval, sizeof(greq)))
02caad7cc   Christoph Hellwig   net/ipv4: factor ...
808
809
810
811
812
813
814
815
816
817
818
  		return -EFAULT;
  
  	psin = (struct sockaddr_in *)&greq.gr_group;
  	if (psin->sin_family != AF_INET)
  		return -EINVAL;
  	mreq.imr_multiaddr = psin->sin_addr;
  	mreq.imr_ifindex = greq.gr_interface;
  	if (optname == MCAST_JOIN_GROUP)
  		return ip_mc_join_group(sk, &mreq);
  	return ip_mc_leave_group(sk, &mreq);
  }
02caad7cc   Christoph Hellwig   net/ipv4: factor ...
819
  static int compat_ip_mcast_join_leave(struct sock *sk, int optname,
89654c5fc   Christoph Hellwig   net/ipv4: switch ...
820
  		sockptr_t optval, int optlen)
02caad7cc   Christoph Hellwig   net/ipv4: factor ...
821
822
823
824
  {
  	struct compat_group_req greq;
  	struct ip_mreqn mreq = { };
  	struct sockaddr_in *psin;
02caad7cc   Christoph Hellwig   net/ipv4: factor ...
825
826
827
  
  	if (optlen < sizeof(struct compat_group_req))
  		return -EINVAL;
89654c5fc   Christoph Hellwig   net/ipv4: switch ...
828
  	if (copy_from_sockptr(&greq, optval, sizeof(greq)))
02caad7cc   Christoph Hellwig   net/ipv4: factor ...
829
830
831
832
833
834
835
  		return -EFAULT;
  
  	psin = (struct sockaddr_in *)&greq.gr_group;
  	if (psin->sin_family != AF_INET)
  		return -EINVAL;
  	mreq.imr_multiaddr = psin->sin_addr;
  	mreq.imr_ifindex = greq.gr_interface;
02caad7cc   Christoph Hellwig   net/ipv4: factor ...
836
  	if (optname == MCAST_JOIN_GROUP)
b6238c04c   Christoph Hellwig   net/ipv4: remove ...
837
838
  		return ip_mc_join_group(sk, &mreq);
  	return ip_mc_leave_group(sk, &mreq);
02caad7cc   Christoph Hellwig   net/ipv4: factor ...
839
  }
02caad7cc   Christoph Hellwig   net/ipv4: factor ...
840

89654c5fc   Christoph Hellwig   net/ipv4: switch ...
841
842
  static int do_ip_setsockopt(struct sock *sk, int level, int optname,
  		sockptr_t optval, unsigned int optlen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
843
844
  {
  	struct inet_sock *inet = inet_sk(sk);
166b6b2d6   Nikolay Borisov   igmp: Namespaceif...
845
  	struct net *net = sock_net(sk);
09cb105ea   Jianjun Kong   net: clean up net...
846
  	int val = 0, err;
baf606d9c   Marcelo Ricardo Leitner   ipv4,ipv6: grab r...
847
  	bool needs_rtnl = setsockopt_needs_rtnl(optname);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
848

0c9f79be2   Xi Wang   ipv4: avoid undef...
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
  	switch (optname) {
  	case IP_PKTINFO:
  	case IP_RECVTTL:
  	case IP_RECVOPTS:
  	case IP_RECVTOS:
  	case IP_RETOPTS:
  	case IP_TOS:
  	case IP_TTL:
  	case IP_HDRINCL:
  	case IP_MTU_DISCOVER:
  	case IP_RECVERR:
  	case IP_ROUTER_ALERT:
  	case IP_FREEBIND:
  	case IP_PASSSEC:
  	case IP_TRANSPARENT:
  	case IP_MINTTL:
  	case IP_NODEFRAG:
90c337da1   Eric Dumazet   inet: add IP_BIND...
866
  	case IP_BIND_ADDRESS_NO_PORT:
0c9f79be2   Xi Wang   ipv4: avoid undef...
867
868
869
870
871
  	case IP_UNICAST_IF:
  	case IP_MULTICAST_TTL:
  	case IP_MULTICAST_ALL:
  	case IP_MULTICAST_LOOP:
  	case IP_RECVORIGDSTADDR:
ad6f939ab   Tom Herbert   ip: Add offset pa...
872
  	case IP_CHECKSUM:
70ecc2484   Willem de Bruijn   ipv4: add IP_RECV...
873
  	case IP_RECVFRAGSIZE:
eba75c587   Willem de Bruijn   icmp: support rfc...
874
  	case IP_RECVERR_RFC4884:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
875
  		if (optlen >= sizeof(int)) {
89654c5fc   Christoph Hellwig   net/ipv4: switch ...
876
  			if (copy_from_sockptr(&val, optval, sizeof(val)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
877
878
879
  				return -EFAULT;
  		} else if (optlen >= sizeof(char)) {
  			unsigned char ucval;
89654c5fc   Christoph Hellwig   net/ipv4: switch ...
880
  			if (copy_from_sockptr(&ucval, optval, sizeof(ucval)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
881
882
883
884
885
886
  				return -EFAULT;
  			val = (int) ucval;
  		}
  	}
  
  	/* If optlen==0, it is equivalent to val == 0 */
0526947f9   Kirill Tkhai   net: Move IP_ROUT...
887
888
  	if (optname == IP_ROUTER_ALERT)
  		return ip_ra_control(sk, val ? 1 : 0, NULL);
6a9fb9479   Pavel Emelyanov   [IPV4]: Clean the...
889
  	if (ip_mroute_opt(optname))
89654c5fc   Christoph Hellwig   net/ipv4: switch ...
890
  		return ip_mroute_setsockopt(sk, optname, optval, optlen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
891
892
  
  	err = 0;
baf606d9c   Marcelo Ricardo Leitner   ipv4,ipv6: grab r...
893
894
  	if (needs_rtnl)
  		rtnl_lock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
895
896
897
  	lock_sock(sk);
  
  	switch (optname) {
132adf546   Stephen Hemminger   [IPV4]: cleanup
898
899
  	case IP_OPTIONS:
  	{
f6d8bd051   Eric Dumazet   inet: add RCU pro...
900
  		struct ip_options_rcu *old, *opt = NULL;
65a1c4fff   roel kluin   net: Cleanup redu...
901
  		if (optlen > 40)
132adf546   Stephen Hemminger   [IPV4]: cleanup
902
  			goto e_inval;
89654c5fc   Christoph Hellwig   net/ipv4: switch ...
903
  		err = ip_options_get(sock_net(sk), &opt, optval, optlen);
132adf546   Stephen Hemminger   [IPV4]: cleanup
904
905
  		if (err)
  			break;
f6d8bd051   Eric Dumazet   inet: add RCU pro...
906
  		old = rcu_dereference_protected(inet->inet_opt,
1e1d04e67   Hannes Frederic Sowa   net: introduce lo...
907
  						lockdep_sock_is_held(sk));
132adf546   Stephen Hemminger   [IPV4]: cleanup
908
909
  		if (inet->is_icsk) {
  			struct inet_connection_sock *icsk = inet_csk(sk);
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
910
  #if IS_ENABLED(CONFIG_IPV6)
132adf546   Stephen Hemminger   [IPV4]: cleanup
911
912
913
  			if (sk->sk_family == PF_INET ||
  			    (!((1 << sk->sk_state) &
  			       (TCPF_LISTEN | TCPF_CLOSE)) &&
c720c7e83   Eric Dumazet   inet: rename some...
914
  			     inet->inet_daddr != LOOPBACK4_IPV6)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
915
  #endif
f6d8bd051   Eric Dumazet   inet: add RCU pro...
916
917
  				if (old)
  					icsk->icsk_ext_hdr_len -= old->opt.optlen;
132adf546   Stephen Hemminger   [IPV4]: cleanup
918
  				if (opt)
f6d8bd051   Eric Dumazet   inet: add RCU pro...
919
  					icsk->icsk_ext_hdr_len += opt->opt.optlen;
132adf546   Stephen Hemminger   [IPV4]: cleanup
920
  				icsk->icsk_sync_mss(sk, icsk->icsk_pmtu_cookie);
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
921
  #if IS_ENABLED(CONFIG_IPV6)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
922
  			}
132adf546   Stephen Hemminger   [IPV4]: cleanup
923
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
924
  		}
f6d8bd051   Eric Dumazet   inet: add RCU pro...
925
926
  		rcu_assign_pointer(inet->inet_opt, opt);
  		if (old)
605b4afec   Paul E. McKenney   ipv4: Convert cal...
927
  			kfree_rcu(old, rcu);
132adf546   Stephen Hemminger   [IPV4]: cleanup
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
  		break;
  	}
  	case IP_PKTINFO:
  		if (val)
  			inet->cmsg_flags |= IP_CMSG_PKTINFO;
  		else
  			inet->cmsg_flags &= ~IP_CMSG_PKTINFO;
  		break;
  	case IP_RECVTTL:
  		if (val)
  			inet->cmsg_flags |=  IP_CMSG_TTL;
  		else
  			inet->cmsg_flags &= ~IP_CMSG_TTL;
  		break;
  	case IP_RECVTOS:
  		if (val)
  			inet->cmsg_flags |=  IP_CMSG_TOS;
  		else
  			inet->cmsg_flags &= ~IP_CMSG_TOS;
  		break;
  	case IP_RECVOPTS:
  		if (val)
  			inet->cmsg_flags |=  IP_CMSG_RECVOPTS;
  		else
  			inet->cmsg_flags &= ~IP_CMSG_RECVOPTS;
  		break;
  	case IP_RETOPTS:
  		if (val)
  			inet->cmsg_flags |= IP_CMSG_RETOPTS;
  		else
  			inet->cmsg_flags &= ~IP_CMSG_RETOPTS;
  		break;
  	case IP_PASSSEC:
  		if (val)
  			inet->cmsg_flags |= IP_CMSG_PASSSEC;
  		else
  			inet->cmsg_flags &= ~IP_CMSG_PASSSEC;
  		break;
e8b2dfe9b   Balazs Scheidler   TPROXY: implement...
966
967
968
969
970
971
  	case IP_RECVORIGDSTADDR:
  		if (val)
  			inet->cmsg_flags |= IP_CMSG_ORIGDSTADDR;
  		else
  			inet->cmsg_flags &= ~IP_CMSG_ORIGDSTADDR;
  		break;
ad6f939ab   Tom Herbert   ip: Add offset pa...
972
973
974
975
976
977
978
979
980
981
982
983
984
  	case IP_CHECKSUM:
  		if (val) {
  			if (!(inet->cmsg_flags & IP_CMSG_CHECKSUM)) {
  				inet_inc_convert_csum(sk);
  				inet->cmsg_flags |= IP_CMSG_CHECKSUM;
  			}
  		} else {
  			if (inet->cmsg_flags & IP_CMSG_CHECKSUM) {
  				inet_dec_convert_csum(sk);
  				inet->cmsg_flags &= ~IP_CMSG_CHECKSUM;
  			}
  		}
  		break;
70ecc2484   Willem de Bruijn   ipv4: add IP_RECV...
985
986
987
988
989
990
991
992
  	case IP_RECVFRAGSIZE:
  		if (sk->sk_type != SOCK_RAW && sk->sk_type != SOCK_DGRAM)
  			goto e_inval;
  		if (val)
  			inet->cmsg_flags |= IP_CMSG_RECVFRAGSIZE;
  		else
  			inet->cmsg_flags &= ~IP_CMSG_RECVFRAGSIZE;
  		break;
132adf546   Stephen Hemminger   [IPV4]: cleanup
993
  	case IP_TOS:	/* This sets both TOS and Precedence */
6ebf71bab   Christoph Hellwig   ipv4: add ip_sock...
994
  		__ip_sock_set_tos(sk, val);
132adf546   Stephen Hemminger   [IPV4]: cleanup
995
996
  		break;
  	case IP_TTL:
4d52cfbef   Eric Dumazet   net: ipv4/ip_sock...
997
  		if (optlen < 1)
132adf546   Stephen Hemminger   [IPV4]: cleanup
998
  			goto e_inval;
c9be4a5c4   Cong Wang   net: prevent sett...
999
  		if (val != -1 && (val < 1 || val > 255))
132adf546   Stephen Hemminger   [IPV4]: cleanup
1000
1001
1002
1003
1004
1005
  			goto e_inval;
  		inet->uc_ttl = val;
  		break;
  	case IP_HDRINCL:
  		if (sk->sk_type != SOCK_RAW) {
  			err = -ENOPROTOOPT;
2c7946a7b   Catherine Zhang   [SECURITY]: TCP/U...
1006
  			break;
132adf546   Stephen Hemminger   [IPV4]: cleanup
1007
1008
1009
  		}
  		inet->hdrincl = val ? 1 : 0;
  		break;
7b2ff18ee   Jiri Olsa   net - IP_NODEFRAG...
1010
1011
1012
1013
1014
1015
1016
  	case IP_NODEFRAG:
  		if (sk->sk_type != SOCK_RAW) {
  			err = -ENOPROTOOPT;
  			break;
  		}
  		inet->nodefrag = val ? 1 : 0;
  		break;
90c337da1   Eric Dumazet   inet: add IP_BIND...
1017
1018
1019
  	case IP_BIND_ADDRESS_NO_PORT:
  		inet->bind_address_no_port = val ? 1 : 0;
  		break;
132adf546   Stephen Hemminger   [IPV4]: cleanup
1020
  	case IP_MTU_DISCOVER:
1b3465763   Hannes Frederic Sowa   ipv4: yet another...
1021
  		if (val < IP_PMTUDISC_DONT || val > IP_PMTUDISC_OMIT)
132adf546   Stephen Hemminger   [IPV4]: cleanup
1022
1023
1024
1025
1026
1027
1028
1029
  			goto e_inval;
  		inet->pmtudisc = val;
  		break;
  	case IP_RECVERR:
  		inet->recverr = !!val;
  		if (!val)
  			skb_queue_purge(&sk->sk_error_queue);
  		break;
eba75c587   Willem de Bruijn   icmp: support rfc...
1030
1031
1032
1033
1034
  	case IP_RECVERR_RFC4884:
  		if (val < 0 || val > 1)
  			goto e_inval;
  		inet->recverr_rfc4884 = !!val;
  		break;
132adf546   Stephen Hemminger   [IPV4]: cleanup
1035
1036
1037
  	case IP_MULTICAST_TTL:
  		if (sk->sk_type == SOCK_STREAM)
  			goto e_inval;
4d52cfbef   Eric Dumazet   net: ipv4/ip_sock...
1038
  		if (optlen < 1)
132adf546   Stephen Hemminger   [IPV4]: cleanup
1039
  			goto e_inval;
09cb105ea   Jianjun Kong   net: clean up net...
1040
  		if (val == -1)
132adf546   Stephen Hemminger   [IPV4]: cleanup
1041
1042
1043
1044
1045
1046
  			val = 1;
  		if (val < 0 || val > 255)
  			goto e_inval;
  		inet->mc_ttl = val;
  		break;
  	case IP_MULTICAST_LOOP:
4d52cfbef   Eric Dumazet   net: ipv4/ip_sock...
1047
  		if (optlen < 1)
132adf546   Stephen Hemminger   [IPV4]: cleanup
1048
1049
1050
  			goto e_inval;
  		inet->mc_loop = !!val;
  		break;
76e21053b   Erich E. Hoover   ipv4: Implement I...
1051
1052
1053
1054
  	case IP_UNICAST_IF:
  	{
  		struct net_device *dev = NULL;
  		int ifindex;
9515a2e08   David Ahern   net/ipv4: Allow s...
1055
  		int midx;
76e21053b   Erich E. Hoover   ipv4: Implement I...
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
  
  		if (optlen != sizeof(int))
  			goto e_inval;
  
  		ifindex = (__force int)ntohl((__force __be32)val);
  		if (ifindex == 0) {
  			inet->uc_index = 0;
  			err = 0;
  			break;
  		}
  
  		dev = dev_get_by_index(sock_net(sk), ifindex);
  		err = -EADDRNOTAVAIL;
  		if (!dev)
  			break;
9515a2e08   David Ahern   net/ipv4: Allow s...
1071
1072
  
  		midx = l3mdev_master_ifindex(dev);
76e21053b   Erich E. Hoover   ipv4: Implement I...
1073
1074
1075
  		dev_put(dev);
  
  		err = -EINVAL;
fdf1923bf   Miaohe Lin   net: Remove dupli...
1076
  		if (sk->sk_bound_dev_if && midx != sk->sk_bound_dev_if)
76e21053b   Erich E. Hoover   ipv4: Implement I...
1077
1078
1079
1080
1081
1082
  			break;
  
  		inet->uc_index = ifindex;
  		err = 0;
  		break;
  	}
132adf546   Stephen Hemminger   [IPV4]: cleanup
1083
1084
1085
1086
  	case IP_MULTICAST_IF:
  	{
  		struct ip_mreqn mreq;
  		struct net_device *dev = NULL;
7bb387c5a   David Ahern   net: Allow IP_MUL...
1087
  		int midx;
132adf546   Stephen Hemminger   [IPV4]: cleanup
1088
1089
1090
1091
1092
1093
  
  		if (sk->sk_type == SOCK_STREAM)
  			goto e_inval;
  		/*
  		 *	Check the arguments are allowable
  		 */
0915921bd   Shan Wei   ipv4: check optle...
1094
1095
  		if (optlen < sizeof(struct in_addr))
  			goto e_inval;
132adf546   Stephen Hemminger   [IPV4]: cleanup
1096
1097
  		err = -EFAULT;
  		if (optlen >= sizeof(struct ip_mreqn)) {
89654c5fc   Christoph Hellwig   net/ipv4: switch ...
1098
  			if (copy_from_sockptr(&mreq, optval, sizeof(mreq)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1099
  				break;
132adf546   Stephen Hemminger   [IPV4]: cleanup
1100
1101
  		} else {
  			memset(&mreq, 0, sizeof(mreq));
3a084ddb4   Jiri Pirko   net: IP_MULTICAST...
1102
  			if (optlen >= sizeof(struct ip_mreq)) {
89654c5fc   Christoph Hellwig   net/ipv4: switch ...
1103
1104
  				if (copy_from_sockptr(&mreq, optval,
  						      sizeof(struct ip_mreq)))
3a084ddb4   Jiri Pirko   net: IP_MULTICAST...
1105
1106
  					break;
  			} else if (optlen >= sizeof(struct in_addr)) {
89654c5fc   Christoph Hellwig   net/ipv4: switch ...
1107
1108
  				if (copy_from_sockptr(&mreq.imr_address, optval,
  						      sizeof(struct in_addr)))
3a084ddb4   Jiri Pirko   net: IP_MULTICAST...
1109
1110
  					break;
  			}
132adf546   Stephen Hemminger   [IPV4]: cleanup
1111
1112
1113
  		}
  
  		if (!mreq.imr_ifindex) {
e6f1cebf7   Al Viro   [NET] endianness ...
1114
  			if (mreq.imr_address.s_addr == htonl(INADDR_ANY)) {
132adf546   Stephen Hemminger   [IPV4]: cleanup
1115
1116
1117
  				inet->mc_index = 0;
  				inet->mc_addr  = 0;
  				err = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1118
1119
  				break;
  			}
3b1e0a655   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
1120
  			dev = ip_dev_find(sock_net(sk), mreq.imr_address.s_addr);
55b805035   Eric Dumazet   net: Fix IP_MULTI...
1121
  			if (dev)
132adf546   Stephen Hemminger   [IPV4]: cleanup
1122
  				mreq.imr_ifindex = dev->ifindex;
132adf546   Stephen Hemminger   [IPV4]: cleanup
1123
  		} else
55b805035   Eric Dumazet   net: Fix IP_MULTI...
1124
  			dev = dev_get_by_index(sock_net(sk), mreq.imr_ifindex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1125

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1126

132adf546   Stephen Hemminger   [IPV4]: cleanup
1127
1128
1129
  		err = -EADDRNOTAVAIL;
  		if (!dev)
  			break;
7bb387c5a   David Ahern   net: Allow IP_MUL...
1130
1131
  
  		midx = l3mdev_master_ifindex(dev);
55b805035   Eric Dumazet   net: Fix IP_MULTI...
1132
  		dev_put(dev);
132adf546   Stephen Hemminger   [IPV4]: cleanup
1133
1134
1135
  
  		err = -EINVAL;
  		if (sk->sk_bound_dev_if &&
7bb387c5a   David Ahern   net: Allow IP_MUL...
1136
  		    mreq.imr_ifindex != sk->sk_bound_dev_if &&
fdf1923bf   Miaohe Lin   net: Remove dupli...
1137
  		    midx != sk->sk_bound_dev_if)
132adf546   Stephen Hemminger   [IPV4]: cleanup
1138
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1139

132adf546   Stephen Hemminger   [IPV4]: cleanup
1140
1141
1142
1143
1144
  		inet->mc_index = mreq.imr_ifindex;
  		inet->mc_addr  = mreq.imr_address.s_addr;
  		err = 0;
  		break;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1145

132adf546   Stephen Hemminger   [IPV4]: cleanup
1146
1147
1148
1149
  	case IP_ADD_MEMBERSHIP:
  	case IP_DROP_MEMBERSHIP:
  	{
  		struct ip_mreqn mreq;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1150

a96fb49be   Flavio Leitner   [NET]: Fix IP_ADD...
1151
1152
1153
  		err = -EPROTO;
  		if (inet_sk(sk)->is_icsk)
  			break;
132adf546   Stephen Hemminger   [IPV4]: cleanup
1154
1155
1156
1157
  		if (optlen < sizeof(struct ip_mreq))
  			goto e_inval;
  		err = -EFAULT;
  		if (optlen >= sizeof(struct ip_mreqn)) {
89654c5fc   Christoph Hellwig   net/ipv4: switch ...
1158
  			if (copy_from_sockptr(&mreq, optval, sizeof(mreq)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1159
  				break;
132adf546   Stephen Hemminger   [IPV4]: cleanup
1160
1161
  		} else {
  			memset(&mreq, 0, sizeof(mreq));
89654c5fc   Christoph Hellwig   net/ipv4: switch ...
1162
1163
  			if (copy_from_sockptr(&mreq, optval,
  					      sizeof(struct ip_mreq)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1164
  				break;
132adf546   Stephen Hemminger   [IPV4]: cleanup
1165
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1166

132adf546   Stephen Hemminger   [IPV4]: cleanup
1167
  		if (optname == IP_ADD_MEMBERSHIP)
54ff9ef36   Marcelo Ricardo Leitner   ipv4, ipv6: kill ...
1168
  			err = ip_mc_join_group(sk, &mreq);
132adf546   Stephen Hemminger   [IPV4]: cleanup
1169
  		else
54ff9ef36   Marcelo Ricardo Leitner   ipv4, ipv6: kill ...
1170
  			err = ip_mc_leave_group(sk, &mreq);
132adf546   Stephen Hemminger   [IPV4]: cleanup
1171
1172
1173
1174
  		break;
  	}
  	case IP_MSFILTER:
  	{
132adf546   Stephen Hemminger   [IPV4]: cleanup
1175
1176
1177
1178
1179
1180
  		struct ip_msfilter *msf;
  
  		if (optlen < IP_MSFILTER_SIZE(0))
  			goto e_inval;
  		if (optlen > sysctl_optmem_max) {
  			err = -ENOBUFS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1181
1182
  			break;
  		}
89654c5fc   Christoph Hellwig   net/ipv4: switch ...
1183
  		msf = memdup_sockptr(optval, optlen);
a2c841d94   Al Viro   do_ip_setsockopt(...
1184
1185
  		if (IS_ERR(msf)) {
  			err = PTR_ERR(msf);
132adf546   Stephen Hemminger   [IPV4]: cleanup
1186
1187
1188
1189
  			break;
  		}
  		/* numsrc >= (1G-4) overflow in 32 bits */
  		if (msf->imsf_numsrc >= 0x3ffffffcU ||
166b6b2d6   Nikolay Borisov   igmp: Namespaceif...
1190
  		    msf->imsf_numsrc > net->ipv4.sysctl_igmp_max_msf) {
132adf546   Stephen Hemminger   [IPV4]: cleanup
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
  			kfree(msf);
  			err = -ENOBUFS;
  			break;
  		}
  		if (IP_MSFILTER_SIZE(msf->imsf_numsrc) > optlen) {
  			kfree(msf);
  			err = -EINVAL;
  			break;
  		}
  		err = ip_mc_msfilter(sk, msf, 0);
  		kfree(msf);
  		break;
  	}
  	case IP_BLOCK_SOURCE:
  	case IP_UNBLOCK_SOURCE:
  	case IP_ADD_SOURCE_MEMBERSHIP:
  	case IP_DROP_SOURCE_MEMBERSHIP:
  	{
  		struct ip_mreq_source mreqs;
  		int omode, add;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1211

132adf546   Stephen Hemminger   [IPV4]: cleanup
1212
1213
  		if (optlen != sizeof(struct ip_mreq_source))
  			goto e_inval;
89654c5fc   Christoph Hellwig   net/ipv4: switch ...
1214
  		if (copy_from_sockptr(&mreqs, optval, sizeof(mreqs))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1215
  			err = -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1216
1217
  			break;
  		}
132adf546   Stephen Hemminger   [IPV4]: cleanup
1218
1219
1220
1221
1222
1223
1224
1225
  		if (optname == IP_BLOCK_SOURCE) {
  			omode = MCAST_EXCLUDE;
  			add = 1;
  		} else if (optname == IP_UNBLOCK_SOURCE) {
  			omode = MCAST_EXCLUDE;
  			add = 0;
  		} else if (optname == IP_ADD_SOURCE_MEMBERSHIP) {
  			struct ip_mreqn mreq;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1226

132adf546   Stephen Hemminger   [IPV4]: cleanup
1227
1228
1229
  			mreq.imr_multiaddr.s_addr = mreqs.imr_multiaddr;
  			mreq.imr_address.s_addr = mreqs.imr_interface;
  			mreq.imr_ifindex = 0;
6e2059b53   Hangbin Liu   ipv4/igmp: init g...
1230
  			err = ip_mc_join_group_ssm(sk, &mreq, MCAST_INCLUDE);
132adf546   Stephen Hemminger   [IPV4]: cleanup
1231
  			if (err && err != -EADDRINUSE)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1232
  				break;
132adf546   Stephen Hemminger   [IPV4]: cleanup
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
  			omode = MCAST_INCLUDE;
  			add = 1;
  		} else /* IP_DROP_SOURCE_MEMBERSHIP */ {
  			omode = MCAST_INCLUDE;
  			add = 0;
  		}
  		err = ip_mc_source(add, omode, sk, &mreqs, 0);
  		break;
  	}
  	case MCAST_JOIN_GROUP:
  	case MCAST_LEAVE_GROUP:
b6238c04c   Christoph Hellwig   net/ipv4: remove ...
1244
1245
1246
1247
1248
  		if (in_compat_syscall())
  			err = compat_ip_mcast_join_leave(sk, optname, optval,
  							 optlen);
  		else
  			err = ip_mcast_join_leave(sk, optname, optval, optlen);
132adf546   Stephen Hemminger   [IPV4]: cleanup
1249
  		break;
132adf546   Stephen Hemminger   [IPV4]: cleanup
1250
1251
1252
1253
  	case MCAST_JOIN_SOURCE_GROUP:
  	case MCAST_LEAVE_SOURCE_GROUP:
  	case MCAST_BLOCK_SOURCE:
  	case MCAST_UNBLOCK_SOURCE:
b6238c04c   Christoph Hellwig   net/ipv4: remove ...
1254
  		err = do_mcast_group_source(sk, optname, optval, optlen);
132adf546   Stephen Hemminger   [IPV4]: cleanup
1255
  		break;
132adf546   Stephen Hemminger   [IPV4]: cleanup
1256
  	case MCAST_MSFILTER:
b6238c04c   Christoph Hellwig   net/ipv4: remove ...
1257
1258
1259
1260
  		if (in_compat_syscall())
  			err = compat_ip_set_mcast_msfilter(sk, optval, optlen);
  		else
  			err = ip_set_mcast_msfilter(sk, optval, optlen);
132adf546   Stephen Hemminger   [IPV4]: cleanup
1261
  		break;
f771bef98   Nivedita Singhvi   ipv4: New multica...
1262
1263
1264
1265
1266
1267
1268
  	case IP_MULTICAST_ALL:
  		if (optlen < 1)
  			goto e_inval;
  		if (val != 0 && val != 1)
  			goto e_inval;
  		inet->mc_all = val;
  		break;
132adf546   Stephen Hemminger   [IPV4]: cleanup
1269
1270
  
  	case IP_FREEBIND:
4d52cfbef   Eric Dumazet   net: ipv4/ip_sock...
1271
  		if (optlen < 1)
132adf546   Stephen Hemminger   [IPV4]: cleanup
1272
1273
1274
1275
1276
1277
1278
  			goto e_inval;
  		inet->freebind = !!val;
  		break;
  
  	case IP_IPSEC_POLICY:
  	case IP_XFRM_POLICY:
  		err = -EPERM;
52e804c6d   Eric W. Biederman   net: Allow userns...
1279
  		if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1280
  			break;
89654c5fc   Christoph Hellwig   net/ipv4: switch ...
1281
  		err = xfrm_user_policy(sk, optname, optval, optlen);
132adf546   Stephen Hemminger   [IPV4]: cleanup
1282
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1283

f5715aea4   KOVACS Krisztian   ipv4: Implement I...
1284
  	case IP_TRANSPARENT:
52e804c6d   Eric W. Biederman   net: Allow userns...
1285
1286
  		if (!!val && !ns_capable(sock_net(sk)->user_ns, CAP_NET_RAW) &&
  		    !ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) {
f5715aea4   KOVACS Krisztian   ipv4: Implement I...
1287
1288
1289
1290
1291
1292
1293
  			err = -EPERM;
  			break;
  		}
  		if (optlen < 1)
  			goto e_inval;
  		inet->transparent = !!val;
  		break;
d218d1113   Stephen Hemminger   tcp: Generalized ...
1294
1295
1296
1297
1298
1299
1300
  	case IP_MINTTL:
  		if (optlen < 1)
  			goto e_inval;
  		if (val < 0 || val > 255)
  			goto e_inval;
  		inet->min_ttl = val;
  		break;
132adf546   Stephen Hemminger   [IPV4]: cleanup
1301
1302
1303
  	default:
  		err = -ENOPROTOOPT;
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1304
1305
  	}
  	release_sock(sk);
baf606d9c   Marcelo Ricardo Leitner   ipv4,ipv6: grab r...
1306
1307
  	if (needs_rtnl)
  		rtnl_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1308
1309
1310
1311
  	return err;
  
  e_inval:
  	release_sock(sk);
baf606d9c   Marcelo Ricardo Leitner   ipv4,ipv6: grab r...
1312
1313
  	if (needs_rtnl)
  		rtnl_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1314
1315
  	return -EINVAL;
  }
f84af32cb   Eric Dumazet   net: ip_queue_rcv...
1316
  /**
829ae9d61   Willem de Bruijn   net-timestamp: al...
1317
   * ipv4_pktinfo_prepare - transfer some info from rtable to skb
f84af32cb   Eric Dumazet   net: ip_queue_rcv...
1318
1319
1320
   * @sk: socket
   * @skb: buffer
   *
35ebf65e8   David S. Miller   ipv4: Create and ...
1321
1322
   * To support IP_CMSG_PKTINFO option, we store rt_iif and specific
   * destination in skb->cb[] before dst drop.
8e3bff96a   stephen hemminger   net: more spellin...
1323
   * This way, receiver doesn't make cache line misses to read rtable.
f84af32cb   Eric Dumazet   net: ip_queue_rcv...
1324
   */
fbf8866d6   Shawn Bohrer   net: ipv4 only po...
1325
  void ipv4_pktinfo_prepare(const struct sock *sk, struct sk_buff *skb)
f84af32cb   Eric Dumazet   net: ip_queue_rcv...
1326
  {
d826eb14e   Eric Dumazet   ipv4: PKTINFO doe...
1327
  	struct in_pktinfo *pktinfo = PKTINFO_SKB_CB(skb);
4b261c75a   Hannes Frederic Sowa   ipv6: make IPV6_R...
1328
1329
  	bool prepare = (inet_sk(sk)->cmsg_flags & IP_CMSG_PKTINFO) ||
  		       ipv6_sk_rxinfo(sk);
d826eb14e   Eric Dumazet   ipv4: PKTINFO doe...
1330

4b261c75a   Hannes Frederic Sowa   ipv6: make IPV6_R...
1331
  	if (prepare && skb_rtable(skb)) {
0b922b7a8   David Ahern   net: original ing...
1332
1333
1334
1335
  		/* skb->cb is overloaded: prior to this point it is IP{6}CB
  		 * which has interface index (iif) as the first member of the
  		 * underlying inet{6}_skb_parm struct. This code then overlays
  		 * PKTINFO_SKB_CB and in_pktinfo also has iif as the first
f0c16ba89   Wei Zhang   net: fix incorrec...
1336
1337
1338
1339
  		 * element so the iif is picked up from the prior IPCB. If iif
  		 * is the loopback interface, then return the sending interface
  		 * (e.g., process binds socket to eth0 for Tx which is
  		 * redirected to loopback in the rtable/dst).
0b922b7a8   David Ahern   net: original ing...
1340
  		 */
cbea8f020   David Ahern   net: ipv4: fix l3...
1341
1342
1343
1344
  		struct rtable *rt = skb_rtable(skb);
  		bool l3slave = ipv4_l3mdev_skb(IPCB(skb)->flags);
  
  		if (pktinfo->ipi_ifindex == LOOPBACK_IFINDEX)
f0c16ba89   Wei Zhang   net: fix incorrec...
1345
  			pktinfo->ipi_ifindex = inet_iif(skb);
cbea8f020   David Ahern   net: ipv4: fix l3...
1346
1347
  		else if (l3slave && rt && rt->rt_iif)
  			pktinfo->ipi_ifindex = rt->rt_iif;
f0c16ba89   Wei Zhang   net: fix incorrec...
1348

35ebf65e8   David S. Miller   ipv4: Create and ...
1349
  		pktinfo->ipi_spec_dst.s_addr = fib_compute_spec_dst(skb);
d826eb14e   Eric Dumazet   ipv4: PKTINFO doe...
1350
1351
1352
1353
  	} else {
  		pktinfo->ipi_ifindex = 0;
  		pktinfo->ipi_spec_dst.s_addr = 0;
  	}
61a1030ba   Paolo Abeni   Revert "ipv4: kee...
1354
  	skb_dst_drop(skb);
f84af32cb   Eric Dumazet   net: ip_queue_rcv...
1355
  }
f84af32cb   Eric Dumazet   net: ip_queue_rcv...
1356

a7b75c5a8   Christoph Hellwig   net: pass a sockp...
1357
1358
  int ip_setsockopt(struct sock *sk, int level, int optname, sockptr_t optval,
  		unsigned int optlen)
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1359
1360
1361
1362
1363
  {
  	int err;
  
  	if (level != SOL_IP)
  		return -ENOPROTOOPT;
a7b75c5a8   Christoph Hellwig   net: pass a sockp...
1364
  	err = do_ip_setsockopt(sk, level, optname, optval, optlen);
97adaddaa   Taehee Yoo   net: bpfilter: fi...
1365
  #if IS_ENABLED(CONFIG_BPFILTER_UMH)
d2ba09c17   Alexei Starovoitov   net: add skeleton...
1366
1367
  	if (optname >= BPFILTER_IPT_SO_SET_REPLACE &&
  	    optname < BPFILTER_IPT_SET_MAX)
a7b75c5a8   Christoph Hellwig   net: pass a sockp...
1368
  		err = bpfilter_ip_set_sockopt(sk, optname, optval, optlen);
d2ba09c17   Alexei Starovoitov   net: add skeleton...
1369
  #endif
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1370
1371
1372
  #ifdef CONFIG_NETFILTER
  	/* we need to exclude all possible ENOPROTOOPTs except default case */
  	if (err == -ENOPROTOOPT && optname != IP_HDRINCL &&
6a9fb9479   Pavel Emelyanov   [IPV4]: Clean the...
1373
1374
  			optname != IP_IPSEC_POLICY &&
  			optname != IP_XFRM_POLICY &&
3f34cfae1   Paolo Abeni   netfilter: on soc...
1375
  			!ip_mroute_opt(optname))
a7b75c5a8   Christoph Hellwig   net: pass a sockp...
1376
  		err = nf_setsockopt(sk, PF_INET, optname, optval, optlen);
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1377
1378
1379
  #endif
  	return err;
  }
4d52cfbef   Eric Dumazet   net: ipv4/ip_sock...
1380
  EXPORT_SYMBOL(ip_setsockopt);
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1381

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1382
  /*
4d52cfbef   Eric Dumazet   net: ipv4/ip_sock...
1383
1384
   *	Get the options. Note for future reference. The GET of IP options gets
   *	the _received_ ones. The set sets the _sent_ ones.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1385
   */
87e9f0315   WANG Cong   ipv4: fix a poten...
1386
1387
1388
1389
1390
1391
1392
1393
1394
  static bool getsockopt_needs_rtnl(int optname)
  {
  	switch (optname) {
  	case IP_MSFILTER:
  	case MCAST_MSFILTER:
  		return true;
  	}
  	return false;
  }
49e74c24f   Christoph Hellwig   net/ipv4: factor ...
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
  static int ip_get_mcast_msfilter(struct sock *sk, void __user *optval,
  		int __user *optlen, int len)
  {
  	const int size0 = offsetof(struct group_filter, gf_slist);
  	struct group_filter __user *p = optval;
  	struct group_filter gsf;
  	int num;
  	int err;
  
  	if (len < size0)
  		return -EINVAL;
  	if (copy_from_user(&gsf, p, size0))
  		return -EFAULT;
  
  	num = gsf.gf_numsrc;
  	err = ip_mc_gsfget(sk, &gsf, p->gf_slist);
  	if (err)
  		return err;
  	if (gsf.gf_numsrc < num)
  		num = gsf.gf_numsrc;
  	if (put_user(GROUP_FILTER_SIZE(num), optlen) ||
  	    copy_to_user(p, &gsf, size0))
  		return -EFAULT;
  	return 0;
  }
49e74c24f   Christoph Hellwig   net/ipv4: factor ...
1420
  static int compat_ip_get_mcast_msfilter(struct sock *sk, void __user *optval,
b6238c04c   Christoph Hellwig   net/ipv4: remove ...
1421
  		int __user *optlen, int len)
49e74c24f   Christoph Hellwig   net/ipv4: factor ...
1422
1423
1424
1425
1426
  {
  	const int size0 = offsetof(struct compat_group_filter, gf_slist);
  	struct compat_group_filter __user *p = optval;
  	struct compat_group_filter gf32;
  	struct group_filter gf;
49e74c24f   Christoph Hellwig   net/ipv4: factor ...
1427
  	int num;
b6238c04c   Christoph Hellwig   net/ipv4: remove ...
1428
  	int err;
49e74c24f   Christoph Hellwig   net/ipv4: factor ...
1429

49e74c24f   Christoph Hellwig   net/ipv4: factor ...
1430
1431
  	if (len < size0)
  		return -EINVAL;
49e74c24f   Christoph Hellwig   net/ipv4: factor ...
1432
1433
1434
1435
1436
1437
1438
  	if (copy_from_user(&gf32, p, size0))
  		return -EFAULT;
  
  	gf.gf_interface = gf32.gf_interface;
  	gf.gf_fmode = gf32.gf_fmode;
  	num = gf.gf_numsrc = gf32.gf_numsrc;
  	gf.gf_group = gf32.gf_group;
49e74c24f   Christoph Hellwig   net/ipv4: factor ...
1439
  	err = ip_mc_gsfget(sk, &gf, p->gf_slist);
49e74c24f   Christoph Hellwig   net/ipv4: factor ...
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
  	if (err)
  		return err;
  	if (gf.gf_numsrc < num)
  		num = gf.gf_numsrc;
  	len = GROUP_FILTER_SIZE(num) - (sizeof(gf) - sizeof(gf32));
  	if (put_user(len, optlen) ||
  	    put_user(gf.gf_fmode, &p->gf_fmode) ||
  	    put_user(gf.gf_numsrc, &p->gf_numsrc))
  		return -EFAULT;
  	return 0;
  }
49e74c24f   Christoph Hellwig   net/ipv4: factor ...
1451

3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1452
  static int do_ip_getsockopt(struct sock *sk, int level, int optname,
b6238c04c   Christoph Hellwig   net/ipv4: remove ...
1453
  			    char __user *optval, int __user *optlen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1454
1455
  {
  	struct inet_sock *inet = inet_sk(sk);
87e9f0315   WANG Cong   ipv4: fix a poten...
1456
1457
  	bool needs_rtnl = getsockopt_needs_rtnl(optname);
  	int val, err = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1458
  	int len;
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
1459

132adf546   Stephen Hemminger   [IPV4]: cleanup
1460
  	if (level != SOL_IP)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1461
  		return -EOPNOTSUPP;
6a9fb9479   Pavel Emelyanov   [IPV4]: Clean the...
1462
  	if (ip_mroute_opt(optname))
09cb105ea   Jianjun Kong   net: clean up net...
1463
  		return ip_mroute_getsockopt(sk, optname, optval, optlen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1464

09cb105ea   Jianjun Kong   net: clean up net...
1465
  	if (get_user(len, optlen))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1466
  		return -EFAULT;
132adf546   Stephen Hemminger   [IPV4]: cleanup
1467
  	if (len < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1468
  		return -EINVAL;
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
1469

87e9f0315   WANG Cong   ipv4: fix a poten...
1470
1471
  	if (needs_rtnl)
  		rtnl_lock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1472
  	lock_sock(sk);
132adf546   Stephen Hemminger   [IPV4]: cleanup
1473
1474
1475
1476
  	switch (optname) {
  	case IP_OPTIONS:
  	{
  		unsigned char optbuf[sizeof(struct ip_options)+40];
f6d8bd051   Eric Dumazet   inet: add RCU pro...
1477
1478
1479
1480
  		struct ip_options *opt = (struct ip_options *)optbuf;
  		struct ip_options_rcu *inet_opt;
  
  		inet_opt = rcu_dereference_protected(inet->inet_opt,
1e1d04e67   Hannes Frederic Sowa   net: introduce lo...
1481
  						     lockdep_sock_is_held(sk));
132adf546   Stephen Hemminger   [IPV4]: cleanup
1482
  		opt->optlen = 0;
f6d8bd051   Eric Dumazet   inet: add RCU pro...
1483
1484
1485
1486
  		if (inet_opt)
  			memcpy(optbuf, &inet_opt->opt,
  			       sizeof(struct ip_options) +
  			       inet_opt->opt.optlen);
132adf546   Stephen Hemminger   [IPV4]: cleanup
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
  		release_sock(sk);
  
  		if (opt->optlen == 0)
  			return put_user(0, optlen);
  
  		ip_options_undo(opt);
  
  		len = min_t(unsigned int, len, opt->optlen);
  		if (put_user(len, optlen))
  			return -EFAULT;
  		if (copy_to_user(optval, opt->__data, len))
  			return -EFAULT;
  		return 0;
  	}
  	case IP_PKTINFO:
  		val = (inet->cmsg_flags & IP_CMSG_PKTINFO) != 0;
  		break;
  	case IP_RECVTTL:
  		val = (inet->cmsg_flags & IP_CMSG_TTL) != 0;
  		break;
  	case IP_RECVTOS:
  		val = (inet->cmsg_flags & IP_CMSG_TOS) != 0;
  		break;
  	case IP_RECVOPTS:
  		val = (inet->cmsg_flags & IP_CMSG_RECVOPTS) != 0;
  		break;
  	case IP_RETOPTS:
  		val = (inet->cmsg_flags & IP_CMSG_RETOPTS) != 0;
  		break;
  	case IP_PASSSEC:
  		val = (inet->cmsg_flags & IP_CMSG_PASSSEC) != 0;
  		break;
e8b2dfe9b   Balazs Scheidler   TPROXY: implement...
1519
1520
1521
  	case IP_RECVORIGDSTADDR:
  		val = (inet->cmsg_flags & IP_CMSG_ORIGDSTADDR) != 0;
  		break;
ad6f939ab   Tom Herbert   ip: Add offset pa...
1522
1523
1524
  	case IP_CHECKSUM:
  		val = (inet->cmsg_flags & IP_CMSG_CHECKSUM) != 0;
  		break;
70ecc2484   Willem de Bruijn   ipv4: add IP_RECV...
1525
1526
1527
  	case IP_RECVFRAGSIZE:
  		val = (inet->cmsg_flags & IP_CMSG_RECVFRAGSIZE) != 0;
  		break;
132adf546   Stephen Hemminger   [IPV4]: cleanup
1528
1529
1530
1531
  	case IP_TOS:
  		val = inet->tos;
  		break;
  	case IP_TTL:
fa50d974d   Nikolay Borisov   ipv4: Namespaceif...
1532
1533
  	{
  		struct net *net = sock_net(sk);
132adf546   Stephen Hemminger   [IPV4]: cleanup
1534
  		val = (inet->uc_ttl == -1 ?
fa50d974d   Nikolay Borisov   ipv4: Namespaceif...
1535
  		       net->ipv4.sysctl_ip_default_ttl :
132adf546   Stephen Hemminger   [IPV4]: cleanup
1536
1537
  		       inet->uc_ttl);
  		break;
fa50d974d   Nikolay Borisov   ipv4: Namespaceif...
1538
  	}
132adf546   Stephen Hemminger   [IPV4]: cleanup
1539
1540
1541
  	case IP_HDRINCL:
  		val = inet->hdrincl;
  		break;
a89b47639   Michael Kerrisk   ipv4: enable gets...
1542
1543
1544
  	case IP_NODEFRAG:
  		val = inet->nodefrag;
  		break;
90c337da1   Eric Dumazet   inet: add IP_BIND...
1545
1546
1547
  	case IP_BIND_ADDRESS_NO_PORT:
  		val = inet->bind_address_no_port;
  		break;
132adf546   Stephen Hemminger   [IPV4]: cleanup
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
  	case IP_MTU_DISCOVER:
  		val = inet->pmtudisc;
  		break;
  	case IP_MTU:
  	{
  		struct dst_entry *dst;
  		val = 0;
  		dst = sk_dst_get(sk);
  		if (dst) {
  			val = dst_mtu(dst);
  			dst_release(dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1559
  		}
132adf546   Stephen Hemminger   [IPV4]: cleanup
1560
  		if (!val) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1561
  			release_sock(sk);
132adf546   Stephen Hemminger   [IPV4]: cleanup
1562
  			return -ENOTCONN;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1563
  		}
132adf546   Stephen Hemminger   [IPV4]: cleanup
1564
1565
1566
1567
1568
  		break;
  	}
  	case IP_RECVERR:
  		val = inet->recverr;
  		break;
eba75c587   Willem de Bruijn   icmp: support rfc...
1569
1570
1571
  	case IP_RECVERR_RFC4884:
  		val = inet->recverr_rfc4884;
  		break;
132adf546   Stephen Hemminger   [IPV4]: cleanup
1572
1573
1574
1575
1576
1577
  	case IP_MULTICAST_TTL:
  		val = inet->mc_ttl;
  		break;
  	case IP_MULTICAST_LOOP:
  		val = inet->mc_loop;
  		break;
76e21053b   Erich E. Hoover   ipv4: Implement I...
1578
1579
1580
  	case IP_UNICAST_IF:
  		val = (__force int)htonl((__u32) inet->uc_index);
  		break;
132adf546   Stephen Hemminger   [IPV4]: cleanup
1581
1582
1583
1584
1585
1586
  	case IP_MULTICAST_IF:
  	{
  		struct in_addr addr;
  		len = min_t(unsigned int, len, sizeof(struct in_addr));
  		addr.s_addr = inet->mc_addr;
  		release_sock(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1587

132adf546   Stephen Hemminger   [IPV4]: cleanup
1588
1589
1590
1591
1592
1593
1594
1595
1596
  		if (put_user(len, optlen))
  			return -EFAULT;
  		if (copy_to_user(optval, &addr, len))
  			return -EFAULT;
  		return 0;
  	}
  	case IP_MSFILTER:
  	{
  		struct ip_msfilter msf;
132adf546   Stephen Hemminger   [IPV4]: cleanup
1597
1598
  
  		if (len < IP_MSFILTER_SIZE(0)) {
87e9f0315   WANG Cong   ipv4: fix a poten...
1599
1600
  			err = -EINVAL;
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1601
  		}
132adf546   Stephen Hemminger   [IPV4]: cleanup
1602
  		if (copy_from_user(&msf, optval, IP_MSFILTER_SIZE(0))) {
87e9f0315   WANG Cong   ipv4: fix a poten...
1603
1604
  			err = -EFAULT;
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1605
  		}
132adf546   Stephen Hemminger   [IPV4]: cleanup
1606
1607
  		err = ip_mc_msfget(sk, &msf,
  				   (struct ip_msfilter __user *)optval, optlen);
87e9f0315   WANG Cong   ipv4: fix a poten...
1608
  		goto out;
132adf546   Stephen Hemminger   [IPV4]: cleanup
1609
1610
  	}
  	case MCAST_MSFILTER:
b6238c04c   Christoph Hellwig   net/ipv4: remove ...
1611
1612
1613
1614
1615
  		if (in_compat_syscall())
  			err = compat_ip_get_mcast_msfilter(sk, optval, optlen,
  							   len);
  		else
  			err = ip_get_mcast_msfilter(sk, optval, optlen, len);
87e9f0315   WANG Cong   ipv4: fix a poten...
1616
  		goto out;
f771bef98   Nivedita Singhvi   ipv4: New multica...
1617
1618
1619
  	case IP_MULTICAST_ALL:
  		val = inet->mc_all;
  		break;
132adf546   Stephen Hemminger   [IPV4]: cleanup
1620
1621
1622
  	case IP_PKTOPTIONS:
  	{
  		struct msghdr msg;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1623

132adf546   Stephen Hemminger   [IPV4]: cleanup
1624
  		release_sock(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1625

132adf546   Stephen Hemminger   [IPV4]: cleanup
1626
1627
  		if (sk->sk_type != SOCK_STREAM)
  			return -ENOPROTOOPT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1628

1f466e1f1   Christoph Hellwig   net: cleanly hand...
1629
1630
  		msg.msg_control_is_user = true;
  		msg.msg_control_user = optval;
132adf546   Stephen Hemminger   [IPV4]: cleanup
1631
  		msg.msg_controllen = len;
b6238c04c   Christoph Hellwig   net/ipv4: remove ...
1632
  		msg.msg_flags = in_compat_syscall() ? MSG_CMSG_COMPAT : 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1633

132adf546   Stephen Hemminger   [IPV4]: cleanup
1634
1635
  		if (inet->cmsg_flags & IP_CMSG_PKTINFO) {
  			struct in_pktinfo info;
c720c7e83   Eric Dumazet   inet: rename some...
1636
1637
  			info.ipi_addr.s_addr = inet->inet_rcv_saddr;
  			info.ipi_spec_dst.s_addr = inet->inet_rcv_saddr;
132adf546   Stephen Hemminger   [IPV4]: cleanup
1638
1639
  			info.ipi_ifindex = inet->mc_index;
  			put_cmsg(&msg, SOL_IP, IP_PKTINFO, sizeof(info), &info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1640
  		}
132adf546   Stephen Hemminger   [IPV4]: cleanup
1641
1642
1643
1644
  		if (inet->cmsg_flags & IP_CMSG_TTL) {
  			int hlim = inet->mc_ttl;
  			put_cmsg(&msg, SOL_IP, IP_TTL, sizeof(hlim), &hlim);
  		}
4c507d289   Jiri Benc   net: implement IP...
1645
1646
1647
1648
  		if (inet->cmsg_flags & IP_CMSG_TOS) {
  			int tos = inet->rcv_tos;
  			put_cmsg(&msg, SOL_IP, IP_TOS, sizeof(tos), &tos);
  		}
132adf546   Stephen Hemminger   [IPV4]: cleanup
1649
1650
1651
1652
1653
1654
  		len -= msg.msg_controllen;
  		return put_user(len, optlen);
  	}
  	case IP_FREEBIND:
  		val = inet->freebind;
  		break;
f5715aea4   KOVACS Krisztian   ipv4: Implement I...
1655
1656
1657
  	case IP_TRANSPARENT:
  		val = inet->transparent;
  		break;
d218d1113   Stephen Hemminger   tcp: Generalized ...
1658
1659
1660
  	case IP_MINTTL:
  		val = inet->min_ttl;
  		break;
132adf546   Stephen Hemminger   [IPV4]: cleanup
1661
1662
1663
  	default:
  		release_sock(sk);
  		return -ENOPROTOOPT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1664
1665
  	}
  	release_sock(sk);
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
1666

4d52cfbef   Eric Dumazet   net: ipv4/ip_sock...
1667
  	if (len < sizeof(int) && len > 0 && val >= 0 && val <= 255) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1668
1669
  		unsigned char ucval = (unsigned char)val;
  		len = 1;
132adf546   Stephen Hemminger   [IPV4]: cleanup
1670
  		if (put_user(len, optlen))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1671
  			return -EFAULT;
09cb105ea   Jianjun Kong   net: clean up net...
1672
  		if (copy_to_user(optval, &ucval, 1))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1673
1674
1675
  			return -EFAULT;
  	} else {
  		len = min_t(unsigned int, sizeof(int), len);
132adf546   Stephen Hemminger   [IPV4]: cleanup
1676
  		if (put_user(len, optlen))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1677
  			return -EFAULT;
09cb105ea   Jianjun Kong   net: clean up net...
1678
  		if (copy_to_user(optval, &val, len))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1679
1680
1681
  			return -EFAULT;
  	}
  	return 0;
87e9f0315   WANG Cong   ipv4: fix a poten...
1682
1683
1684
1685
1686
1687
  
  out:
  	release_sock(sk);
  	if (needs_rtnl)
  		rtnl_unlock();
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1688
  }
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1689
  int ip_getsockopt(struct sock *sk, int level,
132adf546   Stephen Hemminger   [IPV4]: cleanup
1690
  		  int optname, char __user *optval, int __user *optlen)
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1691
1692
  {
  	int err;
b6238c04c   Christoph Hellwig   net/ipv4: remove ...
1693
  	err = do_ip_getsockopt(sk, level, optname, optval, optlen);
42908c69f   David L Stevens   net: Add compat s...
1694

97adaddaa   Taehee Yoo   net: bpfilter: fi...
1695
  #if IS_ENABLED(CONFIG_BPFILTER_UMH)
d2ba09c17   Alexei Starovoitov   net: add skeleton...
1696
1697
1698
1699
  	if (optname >= BPFILTER_IPT_SO_GET_INFO &&
  	    optname < BPFILTER_IPT_GET_MAX)
  		err = bpfilter_ip_get_sockopt(sk, optname, optval, optlen);
  #endif
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1700
1701
  #ifdef CONFIG_NETFILTER
  	/* we need to exclude all possible ENOPROTOOPTs except default case */
6a9fb9479   Pavel Emelyanov   [IPV4]: Clean the...
1702
1703
  	if (err == -ENOPROTOOPT && optname != IP_PKTOPTIONS &&
  			!ip_mroute_opt(optname)) {
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
1704
  		int len;
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1705

543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
1706
  		if (get_user(len, optlen))
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1707
  			return -EFAULT;
77d4df41d   Christoph Hellwig   netfilter: remove...
1708
  		err = nf_getsockopt(sk, PF_INET, optname, optval, &len);
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1709
1710
1711
1712
1713
1714
1715
  		if (err >= 0)
  			err = put_user(len, optlen);
  		return err;
  	}
  #endif
  	return err;
  }
b6238c04c   Christoph Hellwig   net/ipv4: remove ...
1716
  EXPORT_SYMBOL(ip_getsockopt);