Blame view

net/ipv4/ip_sockglue.c 30.6 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
  /*
   * 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...
7
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8
9
10
11
12
   * 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...
13
   *		Alan Cox	:	Fixed a couple of oopses in Martin's
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
15
16
   *					TOS tweaks.
   *		Mike McLagan	:	Routing by source
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
18
19
  #include <linux/module.h>
  #include <linux/types.h>
  #include <linux/mm.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20
21
22
  #include <linux/skbuff.h>
  #include <linux/ip.h>
  #include <linux/icmp.h>
14c850212   Arnaldo Carvalho de Melo   [INET_SOCK]: Move...
23
  #include <linux/inetdevice.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
  #include <linux/netdevice.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
25
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26
27
28
  #include <net/sock.h>
  #include <net/ip.h>
  #include <net/icmp.h>
d83d8461f   Arnaldo Carvalho de Melo   [IP_SOCKGLUE]: Re...
29
  #include <net/tcp_states.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
31
32
33
34
  #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...
35
  #include <net/inet_ecn.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
37
  #include <net/route.h>
  #include <net/xfrm.h>
dae502954   David L Stevens   ipv4/ipv6 compat:...
38
  #include <net/compat.h>
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
39
  #if IS_ENABLED(CONFIG_IPV6)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40
41
42
43
44
45
46
47
48
49
50
  #include <net/transp_v6.h>
  #endif
  
  #include <linux/errqueue.h>
  #include <asm/uaccess.h>
  
  #define IP_CMSG_PKTINFO		1
  #define IP_CMSG_TTL		2
  #define IP_CMSG_TOS		4
  #define IP_CMSG_RECVOPTS	8
  #define IP_CMSG_RETOPTS		16
2c7946a7b   Catherine Zhang   [SECURITY]: TCP/U...
51
  #define IP_CMSG_PASSSEC		32
e8b2dfe9b   Balazs Scheidler   TPROXY: implement...
52
  #define IP_CMSG_ORIGDSTADDR     64
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
53
54
55
56
  
  /*
   *	SOL_IP control messages.
   */
d826eb14e   Eric Dumazet   ipv4: PKTINFO doe...
57
  #define PKTINFO_SKB_CB(__skb) ((struct in_pktinfo *)((__skb)->cb))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
59
60
  
  static void ip_cmsg_recv_pktinfo(struct msghdr *msg, struct sk_buff *skb)
  {
d826eb14e   Eric Dumazet   ipv4: PKTINFO doe...
61
  	struct in_pktinfo info = *PKTINFO_SKB_CB(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62

eddc9ec53   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
63
  	info.ipi_addr.s_addr = ip_hdr(skb)->daddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64
65
66
67
68
69
  
  	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...
70
  	int ttl = ip_hdr(skb)->ttl;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
72
73
74
75
  	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...
76
  	put_cmsg(msg, SOL_IP, IP_TOS, 1, &ip_hdr(skb)->tos);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
77
78
79
80
81
82
  }
  
  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...
83
84
  	put_cmsg(msg, SOL_IP, IP_RECVOPTS, IPCB(skb)->opt.optlen,
  		 ip_hdr(skb) + 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
85
86
87
88
89
90
  }
  
  
  static void ip_cmsg_recv_retopts(struct msghdr *msg, struct sk_buff *skb)
  {
  	unsigned char optbuf[sizeof(struct ip_options) + 40];
09cb105ea   Jianjun Kong   net: clean up net...
91
  	struct ip_options * opt = (struct ip_options *)optbuf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
92
93
94
95
96
97
98
99
100
101
102
103
  
  	if (IPCB(skb)->opt.optlen == 0)
  		return;
  
  	if (ip_options_echo(opt, skb)) {
  		msg->msg_flags |= MSG_CTRUNC;
  		return;
  	}
  	ip_options_undo(opt);
  
  	put_cmsg(msg, SOL_IP, IP_RETOPTS, opt->optlen, opt->__data);
  }
2c7946a7b   Catherine Zhang   [SECURITY]: TCP/U...
104
105
106
  static void ip_cmsg_recv_security(struct msghdr *msg, struct sk_buff *skb)
  {
  	char *secdata;
dc49c1f94   Catherine Zhang   [AF_UNIX]: Kernel...
107
  	u32 seclen, secid;
2c7946a7b   Catherine Zhang   [SECURITY]: TCP/U...
108
  	int err;
dc49c1f94   Catherine Zhang   [AF_UNIX]: Kernel...
109
110
111
112
113
  	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...
114
115
116
117
  	if (err)
  		return;
  
  	put_cmsg(msg, SOL_IP, SCM_SECURITY, seclen, secdata);
dc49c1f94   Catherine Zhang   [AF_UNIX]: Kernel...
118
  	security_release_secctx(secdata, seclen);
2c7946a7b   Catherine Zhang   [SECURITY]: TCP/U...
119
  }
21d1a161f   Harvey Harrison   net: ip_sockglue....
120
  static void ip_cmsg_recv_dstaddr(struct msghdr *msg, struct sk_buff *skb)
e8b2dfe9b   Balazs Scheidler   TPROXY: implement...
121
122
  {
  	struct sockaddr_in sin;
b71d1d426   Eric Dumazet   inet: constify ip...
123
  	const struct iphdr *iph = ip_hdr(skb);
21d1a161f   Harvey Harrison   net: ip_sockglue....
124
  	__be16 *ports = (__be16 *)skb_transport_header(skb);
e8b2dfe9b   Balazs Scheidler   TPROXY: implement...
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
  
  	if (skb_transport_offset(skb) + 4 > skb->len)
  		return;
  
  	/* 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.
  	 */
  
  	sin.sin_family = AF_INET;
  	sin.sin_addr.s_addr = iph->daddr;
  	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
141
142
143
144
145
146
147
148
149
  
  void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb)
  {
  	struct inet_sock *inet = inet_sk(skb->sk);
  	unsigned flags = inet->cmsg_flags;
  
  	/* Ordered by supposed usage frequency */
  	if (flags & 1)
  		ip_cmsg_recv_pktinfo(msg, skb);
4d52cfbef   Eric Dumazet   net: ipv4/ip_sock...
150
  	if ((flags >>= 1) == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
151
152
153
154
  		return;
  
  	if (flags & 1)
  		ip_cmsg_recv_ttl(msg, skb);
4d52cfbef   Eric Dumazet   net: ipv4/ip_sock...
155
  	if ((flags >>= 1) == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
156
157
158
159
  		return;
  
  	if (flags & 1)
  		ip_cmsg_recv_tos(msg, skb);
4d52cfbef   Eric Dumazet   net: ipv4/ip_sock...
160
  	if ((flags >>= 1) == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161
162
163
164
  		return;
  
  	if (flags & 1)
  		ip_cmsg_recv_opts(msg, skb);
4d52cfbef   Eric Dumazet   net: ipv4/ip_sock...
165
  	if ((flags >>= 1) == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
166
167
168
169
  		return;
  
  	if (flags & 1)
  		ip_cmsg_recv_retopts(msg, skb);
4d52cfbef   Eric Dumazet   net: ipv4/ip_sock...
170
  	if ((flags >>= 1) == 0)
2c7946a7b   Catherine Zhang   [SECURITY]: TCP/U...
171
172
173
174
  		return;
  
  	if (flags & 1)
  		ip_cmsg_recv_security(msg, skb);
e8b2dfe9b   Balazs Scheidler   TPROXY: implement...
175

4d52cfbef   Eric Dumazet   net: ipv4/ip_sock...
176
  	if ((flags >>= 1) == 0)
e8b2dfe9b   Balazs Scheidler   TPROXY: implement...
177
178
179
  		return;
  	if (flags & 1)
  		ip_cmsg_recv_dstaddr(msg, skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
180
  }
4d52cfbef   Eric Dumazet   net: ipv4/ip_sock...
181
  EXPORT_SYMBOL(ip_cmsg_recv);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
182

7a6adb92f   Denis V. Lunev   [NETNS]: Add name...
183
  int ip_cmsg_send(struct net *net, struct msghdr *msg, struct ipcm_cookie *ipc)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
184
185
186
187
188
189
190
191
192
193
194
195
  {
  	int err;
  	struct cmsghdr *cmsg;
  
  	for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
  		if (!CMSG_OK(msg, cmsg))
  			return -EINVAL;
  		if (cmsg->cmsg_level != SOL_IP)
  			continue;
  		switch (cmsg->cmsg_type) {
  		case IP_RETOPTS:
  			err = cmsg->cmsg_len - CMSG_ALIGN(sizeof(struct cmsghdr));
4d52cfbef   Eric Dumazet   net: ipv4/ip_sock...
196
197
  			err = ip_options_get(net, &ipc->opt, CMSG_DATA(cmsg),
  					     err < 40 ? err : 40);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
  			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);
  			ipc->oif = info->ipi_ifindex;
  			ipc->addr = info->ipi_spec_dst.s_addr;
  			break;
  		}
  		default:
  			return -EINVAL;
  		}
  	}
  	return 0;
  }
  
  
  /* Special input handler for packets caught by router alert option.
     They are selected only by protocol field, and then processed likely
     local ones; but only if someone wants them! Otherwise, router
     not running rsvpd will kill RSVP.
  
     It is user level problem, what it will make with them.
     I have no idea, how it will masquearde or NAT them (it is joke, joke :-)),
     but receiver should be enough clever f.e. to forward mtrace requests,
     sent to multicast group to reach destination designated router.
   */
43a951e99   Eric Dumazet   ipv4: add __rcu a...
229
  struct ip_ra_chain __rcu *ip_ra_chain;
66018506e   Eric Dumazet   ip: Router Alert ...
230
  static DEFINE_SPINLOCK(ip_ra_lock);
592fcb9df   Eric Dumazet   ip: ip_ra_control...
231
232
  
  static void ip_ra_destroy_rcu(struct rcu_head *head)
66018506e   Eric Dumazet   ip: Router Alert ...
233
  {
592fcb9df   Eric Dumazet   ip: ip_ra_control...
234
235
236
237
  	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 ...
238
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
239

4d52cfbef   Eric Dumazet   net: ipv4/ip_sock...
240
241
  int ip_ra_control(struct sock *sk, unsigned char on,
  		  void (*destructor)(struct sock *))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
242
  {
43a951e99   Eric Dumazet   ipv4: add __rcu a...
243
244
  	struct ip_ra_chain *ra, *new_ra;
  	struct ip_ra_chain __rcu **rap;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
245

c720c7e83   Eric Dumazet   inet: rename some...
246
  	if (sk->sk_type != SOCK_RAW || inet_sk(sk)->inet_num == IPPROTO_RAW)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
247
248
249
  		return -EINVAL;
  
  	new_ra = on ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL;
66018506e   Eric Dumazet   ip: Router Alert ...
250
  	spin_lock_bh(&ip_ra_lock);
43a951e99   Eric Dumazet   ipv4: add __rcu a...
251
252
253
254
  	for (rap = &ip_ra_chain;
  	     (ra = rcu_dereference_protected(*rap,
  			lockdep_is_held(&ip_ra_lock))) != NULL;
  	     rap = &ra->next) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
255
256
  		if (ra->sk == sk) {
  			if (on) {
66018506e   Eric Dumazet   ip: Router Alert ...
257
  				spin_unlock_bh(&ip_ra_lock);
a51482bde   Jesper Juhl   [NET]: kfree cleanup
258
  				kfree(new_ra);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
259
260
  				return -EADDRINUSE;
  			}
592fcb9df   Eric Dumazet   ip: ip_ra_control...
261
262
  			/* dont let ip_call_ra_chain() use sk again */
  			ra->sk = NULL;
66018506e   Eric Dumazet   ip: Router Alert ...
263
264
  			rcu_assign_pointer(*rap, ra->next);
  			spin_unlock_bh(&ip_ra_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
265
266
267
  
  			if (ra->destructor)
  				ra->destructor(sk);
592fcb9df   Eric Dumazet   ip: ip_ra_control...
268
269
270
271
272
273
274
  			/*
  			 * 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
275
276
277
278
  			return 0;
  		}
  	}
  	if (new_ra == NULL) {
66018506e   Eric Dumazet   ip: Router Alert ...
279
  		spin_unlock_bh(&ip_ra_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
280
281
282
283
284
285
  		return -ENOBUFS;
  	}
  	new_ra->sk = sk;
  	new_ra->destructor = destructor;
  
  	new_ra->next = ra;
66018506e   Eric Dumazet   ip: Router Alert ...
286
  	rcu_assign_pointer(*rap, new_ra);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
287
  	sock_hold(sk);
66018506e   Eric Dumazet   ip: Router Alert ...
288
  	spin_unlock_bh(&ip_ra_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
289
290
291
  
  	return 0;
  }
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
292
  void ip_icmp_error(struct sock *sk, struct sk_buff *skb, int err,
35986b329   Al Viro   [IPV4]: ip_icmp_e...
293
  		   __be16 port, u32 info, u8 *payload)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
294
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
295
  	struct sock_exterr_skb *serr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
296
297
298
  	skb = skb_clone(skb, GFP_ATOMIC);
  	if (!skb)
  		return;
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
299
  	serr = SKB_EXT_ERR(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
300
301
  	serr->ee.ee_errno = err;
  	serr->ee.ee_origin = SO_EE_ORIGIN_ICMP;
88c7664f1   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
302
303
  	serr->ee.ee_type = icmp_hdr(skb)->type;
  	serr->ee.ee_code = icmp_hdr(skb)->code;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
304
305
306
  	serr->ee.ee_pad = 0;
  	serr->ee.ee_info = info;
  	serr->ee.ee_data = 0;
88c7664f1   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
307
  	serr->addr_offset = (u8 *)&(((struct iphdr *)(icmp_hdr(skb) + 1))->daddr) -
d56f90a7c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
308
  				   skb_network_header(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
309
  	serr->port = port;
bd82393ca   Arnaldo Carvalho de Melo   [SK_BUFF]: More s...
310
311
312
313
314
315
  	if (skb_pull(skb, payload - skb->data) != NULL) {
  		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
316
  }
0579016ec   Al Viro   [IPV4]: ip_local_...
317
  void ip_local_error(struct sock *sk, int err, __be32 daddr, __be16 port, u32 info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
318
319
320
321
322
323
324
325
326
327
328
329
  {
  	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...
330
331
  	skb_put(skb, sizeof(struct iphdr));
  	skb_reset_network_header(skb);
eddc9ec53   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
332
  	iph = ip_hdr(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
333
  	iph->daddr = daddr;
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
334
  	serr = SKB_EXT_ERR(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
335
336
  	serr->ee.ee_errno = err;
  	serr->ee.ee_origin = SO_EE_ORIGIN_LOCAL;
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
337
  	serr->ee.ee_type = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
338
339
340
341
  	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...
342
  	serr->addr_offset = (u8 *)&iph->daddr - skb_network_header(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
343
  	serr->port = port;
27a884dc3   Arnaldo Carvalho de Melo   [SK_BUFF]: Conver...
344
  	__skb_pull(skb, skb_tail_pointer(skb) - skb->data);
bd82393ca   Arnaldo Carvalho de Melo   [SK_BUFF]: More s...
345
  	skb_reset_transport_header(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
346
347
348
349
  
  	if (sock_queue_err_skb(sk, skb))
  		kfree_skb(skb);
  }
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
350
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
   *	Handle MSG_ERRQUEUE
   */
  int ip_recv_error(struct sock *sk, struct msghdr *msg, int len)
  {
  	struct sock_exterr_skb *serr;
  	struct sk_buff *skb, *skb2;
  	struct sockaddr_in *sin;
  	struct {
  		struct sock_extended_err ee;
  		struct sockaddr_in	 offender;
  	} errhdr;
  	int err;
  	int copied;
  
  	err = -EAGAIN;
  	skb = skb_dequeue(&sk->sk_error_queue);
  	if (skb == NULL)
  		goto out;
  
  	copied = skb->len;
  	if (copied > len) {
  		msg->msg_flags |= MSG_TRUNC;
  		copied = len;
  	}
  	err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
  	if (err)
  		goto out_free_skb;
  
  	sock_recv_timestamp(msg, sk, skb);
  
  	serr = SKB_EXT_ERR(skb);
  
  	sin = (struct sockaddr_in *)msg->msg_name;
  	if (sin) {
  		sin->sin_family = AF_INET;
d56f90a7c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
386
387
  		sin->sin_addr.s_addr = *(__be32 *)(skb_network_header(skb) +
  						   serr->addr_offset);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
388
389
390
391
392
393
394
395
396
397
398
  		sin->sin_port = serr->port;
  		memset(&sin->sin_zero, 0, sizeof(sin->sin_zero));
  	}
  
  	memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err));
  	sin = &errhdr.offender;
  	sin->sin_family = AF_UNSPEC;
  	if (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP) {
  		struct inet_sock *inet = inet_sk(sk);
  
  		sin->sin_family = AF_INET;
eddc9ec53   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
399
  		sin->sin_addr.s_addr = ip_hdr(skb)->saddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
400
401
402
403
404
405
406
407
408
409
410
411
412
413
  		sin->sin_port = 0;
  		memset(&sin->sin_zero, 0, sizeof(sin->sin_zero));
  		if (inet->cmsg_flags)
  			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;
  
  	/* Reset and regenerate socket error */
e0f9f8586   Herbert Xu   [IPV4/IPV6]: Repl...
414
  	spin_lock_bh(&sk->sk_error_queue.lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
415
  	sk->sk_err = 0;
4d52cfbef   Eric Dumazet   net: ipv4/ip_sock...
416
417
  	skb2 = skb_peek(&sk->sk_error_queue);
  	if (skb2 != NULL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
418
  		sk->sk_err = SKB_EXT_ERR(skb2)->ee.ee_errno;
e0f9f8586   Herbert Xu   [IPV4/IPV6]: Repl...
419
  		spin_unlock_bh(&sk->sk_error_queue.lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
420
421
  		sk->sk_error_report(sk);
  	} else
e0f9f8586   Herbert Xu   [IPV4/IPV6]: Repl...
422
  		spin_unlock_bh(&sk->sk_error_queue.lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
423

e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
424
  out_free_skb:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
425
426
427
428
  	kfree_skb(skb);
  out:
  	return err;
  }
f6d8bd051   Eric Dumazet   inet: add RCU pro...
429
430
431
432
  static void opt_kfree_rcu(struct rcu_head *head)
  {
  	kfree(container_of(head, struct ip_options_rcu, rcu));
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
433
  /*
4d52cfbef   Eric Dumazet   net: ipv4/ip_sock...
434
435
   *	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
436
   */
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
437
  static int do_ip_setsockopt(struct sock *sk, int level,
b7058842c   David S. Miller   net: Make setsock...
438
  			    int optname, char __user *optval, unsigned int optlen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
439
440
  {
  	struct inet_sock *inet = inet_sk(sk);
09cb105ea   Jianjun Kong   net: clean up net...
441
  	int val = 0, err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
442

e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
443
  	if (((1<<optname) & ((1<<IP_PKTINFO) | (1<<IP_RECVTTL) |
132adf546   Stephen Hemminger   [IPV4]: cleanup
444
445
446
447
448
  			     (1<<IP_RECVOPTS) | (1<<IP_RECVTOS) |
  			     (1<<IP_RETOPTS) | (1<<IP_TOS) |
  			     (1<<IP_TTL) | (1<<IP_HDRINCL) |
  			     (1<<IP_MTU_DISCOVER) | (1<<IP_RECVERR) |
  			     (1<<IP_ROUTER_ALERT) | (1<<IP_FREEBIND) |
d218d1113   Stephen Hemminger   tcp: Generalized ...
449
  			     (1<<IP_PASSSEC) | (1<<IP_TRANSPARENT) |
7b2ff18ee   Jiri Olsa   net - IP_NODEFRAG...
450
  			     (1<<IP_MINTTL) | (1<<IP_NODEFRAG))) ||
132adf546   Stephen Hemminger   [IPV4]: cleanup
451
  	    optname == IP_MULTICAST_TTL ||
f771bef98   Nivedita Singhvi   ipv4: New multica...
452
  	    optname == IP_MULTICAST_ALL ||
e8b2dfe9b   Balazs Scheidler   TPROXY: implement...
453
454
  	    optname == IP_MULTICAST_LOOP ||
  	    optname == IP_RECVORIGDSTADDR) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
455
456
457
458
459
460
461
462
463
464
465
466
467
  		if (optlen >= sizeof(int)) {
  			if (get_user(val, (int __user *) optval))
  				return -EFAULT;
  		} else if (optlen >= sizeof(char)) {
  			unsigned char ucval;
  
  			if (get_user(ucval, (unsigned char __user *) optval))
  				return -EFAULT;
  			val = (int) ucval;
  		}
  	}
  
  	/* If optlen==0, it is equivalent to val == 0 */
6a9fb9479   Pavel Emelyanov   [IPV4]: Clean the...
468
  	if (ip_mroute_opt(optname))
09cb105ea   Jianjun Kong   net: clean up net...
469
  		return ip_mroute_setsockopt(sk, optname, optval, optlen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
470
471
472
473
474
  
  	err = 0;
  	lock_sock(sk);
  
  	switch (optname) {
132adf546   Stephen Hemminger   [IPV4]: cleanup
475
476
  	case IP_OPTIONS:
  	{
f6d8bd051   Eric Dumazet   inet: add RCU pro...
477
  		struct ip_options_rcu *old, *opt = NULL;
65a1c4fff   roel kluin   net: Cleanup redu...
478
  		if (optlen > 40)
132adf546   Stephen Hemminger   [IPV4]: cleanup
479
  			goto e_inval;
3b1e0a655   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
480
  		err = ip_options_get_from_user(sock_net(sk), &opt,
cb84663e4   Denis V. Lunev   [NETNS]: Process ...
481
  					       optval, optlen);
132adf546   Stephen Hemminger   [IPV4]: cleanup
482
483
  		if (err)
  			break;
f6d8bd051   Eric Dumazet   inet: add RCU pro...
484
485
  		old = rcu_dereference_protected(inet->inet_opt,
  						sock_owned_by_user(sk));
132adf546   Stephen Hemminger   [IPV4]: cleanup
486
487
  		if (inet->is_icsk) {
  			struct inet_connection_sock *icsk = inet_csk(sk);
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
488
  #if IS_ENABLED(CONFIG_IPV6)
132adf546   Stephen Hemminger   [IPV4]: cleanup
489
490
491
  			if (sk->sk_family == PF_INET ||
  			    (!((1 << sk->sk_state) &
  			       (TCPF_LISTEN | TCPF_CLOSE)) &&
c720c7e83   Eric Dumazet   inet: rename some...
492
  			     inet->inet_daddr != LOOPBACK4_IPV6)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
493
  #endif
f6d8bd051   Eric Dumazet   inet: add RCU pro...
494
495
  				if (old)
  					icsk->icsk_ext_hdr_len -= old->opt.optlen;
132adf546   Stephen Hemminger   [IPV4]: cleanup
496
  				if (opt)
f6d8bd051   Eric Dumazet   inet: add RCU pro...
497
  					icsk->icsk_ext_hdr_len += opt->opt.optlen;
132adf546   Stephen Hemminger   [IPV4]: cleanup
498
  				icsk->icsk_sync_mss(sk, icsk->icsk_pmtu_cookie);
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
499
  #if IS_ENABLED(CONFIG_IPV6)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
500
  			}
132adf546   Stephen Hemminger   [IPV4]: cleanup
501
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
502
  		}
f6d8bd051   Eric Dumazet   inet: add RCU pro...
503
504
505
  		rcu_assign_pointer(inet->inet_opt, opt);
  		if (old)
  			call_rcu(&old->rcu, opt_kfree_rcu);
132adf546   Stephen Hemminger   [IPV4]: cleanup
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
  		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...
544
545
546
547
548
549
  	case IP_RECVORIGDSTADDR:
  		if (val)
  			inet->cmsg_flags |= IP_CMSG_ORIGDSTADDR;
  		else
  			inet->cmsg_flags &= ~IP_CMSG_ORIGDSTADDR;
  		break;
132adf546   Stephen Hemminger   [IPV4]: cleanup
550
551
  	case IP_TOS:	/* This sets both TOS and Precedence */
  		if (sk->sk_type == SOCK_STREAM) {
2c67e9acb   Maciej Żenczykowski   net: use INET_ECN...
552
553
  			val &= ~INET_ECN_MASK;
  			val |= inet->tos & INET_ECN_MASK;
132adf546   Stephen Hemminger   [IPV4]: cleanup
554
  		}
132adf546   Stephen Hemminger   [IPV4]: cleanup
555
556
557
558
559
560
561
  		if (inet->tos != val) {
  			inet->tos = val;
  			sk->sk_priority = rt_tos2priority(val);
  			sk_dst_reset(sk);
  		}
  		break;
  	case IP_TTL:
4d52cfbef   Eric Dumazet   net: ipv4/ip_sock...
562
  		if (optlen < 1)
132adf546   Stephen Hemminger   [IPV4]: cleanup
563
  			goto e_inval;
4d52cfbef   Eric Dumazet   net: ipv4/ip_sock...
564
  		if (val != -1 && (val < 0 || val > 255))
132adf546   Stephen Hemminger   [IPV4]: cleanup
565
566
567
568
569
570
  			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...
571
  			break;
132adf546   Stephen Hemminger   [IPV4]: cleanup
572
573
574
  		}
  		inet->hdrincl = val ? 1 : 0;
  		break;
7b2ff18ee   Jiri Olsa   net - IP_NODEFRAG...
575
576
577
578
579
580
581
  	case IP_NODEFRAG:
  		if (sk->sk_type != SOCK_RAW) {
  			err = -ENOPROTOOPT;
  			break;
  		}
  		inet->nodefrag = val ? 1 : 0;
  		break;
132adf546   Stephen Hemminger   [IPV4]: cleanup
582
  	case IP_MTU_DISCOVER:
0eae750e6   John Dykstra   IP: Cleanups
583
  		if (val < IP_PMTUDISC_DONT || val > IP_PMTUDISC_PROBE)
132adf546   Stephen Hemminger   [IPV4]: cleanup
584
585
586
587
588
589
590
591
592
593
594
  			goto e_inval;
  		inet->pmtudisc = val;
  		break;
  	case IP_RECVERR:
  		inet->recverr = !!val;
  		if (!val)
  			skb_queue_purge(&sk->sk_error_queue);
  		break;
  	case IP_MULTICAST_TTL:
  		if (sk->sk_type == SOCK_STREAM)
  			goto e_inval;
4d52cfbef   Eric Dumazet   net: ipv4/ip_sock...
595
  		if (optlen < 1)
132adf546   Stephen Hemminger   [IPV4]: cleanup
596
  			goto e_inval;
09cb105ea   Jianjun Kong   net: clean up net...
597
  		if (val == -1)
132adf546   Stephen Hemminger   [IPV4]: cleanup
598
599
600
601
602
603
  			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...
604
  		if (optlen < 1)
132adf546   Stephen Hemminger   [IPV4]: cleanup
605
606
607
608
609
610
611
612
613
614
615
616
617
  			goto e_inval;
  		inet->mc_loop = !!val;
  		break;
  	case IP_MULTICAST_IF:
  	{
  		struct ip_mreqn mreq;
  		struct net_device *dev = NULL;
  
  		if (sk->sk_type == SOCK_STREAM)
  			goto e_inval;
  		/*
  		 *	Check the arguments are allowable
  		 */
0915921bd   Shan Wei   ipv4: check optle...
618
619
  		if (optlen < sizeof(struct in_addr))
  			goto e_inval;
132adf546   Stephen Hemminger   [IPV4]: cleanup
620
621
  		err = -EFAULT;
  		if (optlen >= sizeof(struct ip_mreqn)) {
09cb105ea   Jianjun Kong   net: clean up net...
622
  			if (copy_from_user(&mreq, optval, sizeof(mreq)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
623
  				break;
132adf546   Stephen Hemminger   [IPV4]: cleanup
624
625
626
  		} else {
  			memset(&mreq, 0, sizeof(mreq));
  			if (optlen >= sizeof(struct in_addr) &&
4d52cfbef   Eric Dumazet   net: ipv4/ip_sock...
627
628
  			    copy_from_user(&mreq.imr_address, optval,
  					   sizeof(struct in_addr)))
132adf546   Stephen Hemminger   [IPV4]: cleanup
629
630
631
632
  				break;
  		}
  
  		if (!mreq.imr_ifindex) {
e6f1cebf7   Al Viro   [NET] endianness ...
633
  			if (mreq.imr_address.s_addr == htonl(INADDR_ANY)) {
132adf546   Stephen Hemminger   [IPV4]: cleanup
634
635
636
  				inet->mc_index = 0;
  				inet->mc_addr  = 0;
  				err = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
637
638
  				break;
  			}
3b1e0a655   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
639
  			dev = ip_dev_find(sock_net(sk), mreq.imr_address.s_addr);
55b805035   Eric Dumazet   net: Fix IP_MULTI...
640
  			if (dev)
132adf546   Stephen Hemminger   [IPV4]: cleanup
641
  				mreq.imr_ifindex = dev->ifindex;
132adf546   Stephen Hemminger   [IPV4]: cleanup
642
  		} else
55b805035   Eric Dumazet   net: Fix IP_MULTI...
643
  			dev = dev_get_by_index(sock_net(sk), mreq.imr_ifindex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
644

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
645

132adf546   Stephen Hemminger   [IPV4]: cleanup
646
647
648
  		err = -EADDRNOTAVAIL;
  		if (!dev)
  			break;
55b805035   Eric Dumazet   net: Fix IP_MULTI...
649
  		dev_put(dev);
132adf546   Stephen Hemminger   [IPV4]: cleanup
650
651
652
653
654
  
  		err = -EINVAL;
  		if (sk->sk_bound_dev_if &&
  		    mreq.imr_ifindex != sk->sk_bound_dev_if)
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
655

132adf546   Stephen Hemminger   [IPV4]: cleanup
656
657
658
659
660
  		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
661

132adf546   Stephen Hemminger   [IPV4]: cleanup
662
663
664
665
  	case IP_ADD_MEMBERSHIP:
  	case IP_DROP_MEMBERSHIP:
  	{
  		struct ip_mreqn mreq;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
666

a96fb49be   Flavio Leitner   [NET]: Fix IP_ADD...
667
668
669
  		err = -EPROTO;
  		if (inet_sk(sk)->is_icsk)
  			break;
132adf546   Stephen Hemminger   [IPV4]: cleanup
670
671
672
673
  		if (optlen < sizeof(struct ip_mreq))
  			goto e_inval;
  		err = -EFAULT;
  		if (optlen >= sizeof(struct ip_mreqn)) {
09cb105ea   Jianjun Kong   net: clean up net...
674
  			if (copy_from_user(&mreq, optval, sizeof(mreq)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
675
  				break;
132adf546   Stephen Hemminger   [IPV4]: cleanup
676
677
  		} else {
  			memset(&mreq, 0, sizeof(mreq));
09cb105ea   Jianjun Kong   net: clean up net...
678
  			if (copy_from_user(&mreq, optval, sizeof(struct ip_mreq)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
679
  				break;
132adf546   Stephen Hemminger   [IPV4]: cleanup
680
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
681

132adf546   Stephen Hemminger   [IPV4]: cleanup
682
683
684
685
686
687
688
689
  		if (optname == IP_ADD_MEMBERSHIP)
  			err = ip_mc_join_group(sk, &mreq);
  		else
  			err = ip_mc_leave_group(sk, &mreq);
  		break;
  	}
  	case IP_MSFILTER:
  	{
132adf546   Stephen Hemminger   [IPV4]: cleanup
690
691
692
693
694
695
  		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
696
697
  			break;
  		}
132adf546   Stephen Hemminger   [IPV4]: cleanup
698
  		msf = kmalloc(optlen, GFP_KERNEL);
cfcabdcc2   Stephen Hemminger   [NET]: sparse war...
699
  		if (!msf) {
132adf546   Stephen Hemminger   [IPV4]: cleanup
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
  			err = -ENOBUFS;
  			break;
  		}
  		err = -EFAULT;
  		if (copy_from_user(msf, optval, optlen)) {
  			kfree(msf);
  			break;
  		}
  		/* numsrc >= (1G-4) overflow in 32 bits */
  		if (msf->imsf_numsrc >= 0x3ffffffcU ||
  		    msf->imsf_numsrc > sysctl_igmp_max_msf) {
  			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
731

132adf546   Stephen Hemminger   [IPV4]: cleanup
732
733
734
  		if (optlen != sizeof(struct ip_mreq_source))
  			goto e_inval;
  		if (copy_from_user(&mreqs, optval, sizeof(mreqs))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
735
  			err = -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
736
737
  			break;
  		}
132adf546   Stephen Hemminger   [IPV4]: cleanup
738
739
740
741
742
743
744
745
  		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
746

132adf546   Stephen Hemminger   [IPV4]: cleanup
747
748
749
750
751
  			mreq.imr_multiaddr.s_addr = mreqs.imr_multiaddr;
  			mreq.imr_address.s_addr = mreqs.imr_interface;
  			mreq.imr_ifindex = 0;
  			err = ip_mc_join_group(sk, &mreq);
  			if (err && err != -EADDRINUSE)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
752
  				break;
132adf546   Stephen Hemminger   [IPV4]: cleanup
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
  			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:
  	{
  		struct group_req greq;
  		struct sockaddr_in *psin;
  		struct ip_mreqn mreq;
  
  		if (optlen < sizeof(struct group_req))
  			goto e_inval;
  		err = -EFAULT;
  		if (copy_from_user(&greq, optval, sizeof(greq)))
  			break;
  		psin = (struct sockaddr_in *)&greq.gr_group;
  		if (psin->sin_family != AF_INET)
  			goto e_inval;
  		memset(&mreq, 0, sizeof(mreq));
  		mreq.imr_multiaddr = psin->sin_addr;
  		mreq.imr_ifindex = greq.gr_interface;
  
  		if (optname == MCAST_JOIN_GROUP)
  			err = ip_mc_join_group(sk, &mreq);
  		else
  			err = ip_mc_leave_group(sk, &mreq);
  		break;
  	}
  	case MCAST_JOIN_SOURCE_GROUP:
  	case MCAST_LEAVE_SOURCE_GROUP:
  	case MCAST_BLOCK_SOURCE:
  	case MCAST_UNBLOCK_SOURCE:
  	{
  		struct group_source_req greqs;
  		struct ip_mreq_source mreqs;
  		struct sockaddr_in *psin;
  		int omode, add;
  
  		if (optlen != sizeof(struct group_source_req))
  			goto e_inval;
  		if (copy_from_user(&greqs, optval, sizeof(greqs))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
800
  			err = -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
801
802
  			break;
  		}
132adf546   Stephen Hemminger   [IPV4]: cleanup
803
804
805
  		if (greqs.gsr_group.ss_family != AF_INET ||
  		    greqs.gsr_source.ss_family != AF_INET) {
  			err = -EADDRNOTAVAIL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
806
807
  			break;
  		}
132adf546   Stephen Hemminger   [IPV4]: cleanup
808
809
810
811
812
813
814
815
816
817
818
819
820
  		psin = (struct sockaddr_in *)&greqs.gsr_group;
  		mreqs.imr_multiaddr = psin->sin_addr.s_addr;
  		psin = (struct sockaddr_in *)&greqs.gsr_source;
  		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) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
821
  			struct ip_mreqn mreq;
132adf546   Stephen Hemminger   [IPV4]: cleanup
822
  			psin = (struct sockaddr_in *)&greqs.gsr_group;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
823
  			mreq.imr_multiaddr = psin->sin_addr;
132adf546   Stephen Hemminger   [IPV4]: cleanup
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
  			mreq.imr_address.s_addr = 0;
  			mreq.imr_ifindex = greqs.gsr_interface;
  			err = ip_mc_join_group(sk, &mreq);
  			if (err && err != -EADDRINUSE)
  				break;
  			greqs.gsr_interface = mreq.imr_ifindex;
  			omode = MCAST_INCLUDE;
  			add = 1;
  		} else /* MCAST_LEAVE_SOURCE_GROUP */ {
  			omode = MCAST_INCLUDE;
  			add = 0;
  		}
  		err = ip_mc_source(add, omode, sk, &mreqs,
  				   greqs.gsr_interface);
  		break;
  	}
  	case MCAST_MSFILTER:
  	{
132adf546   Stephen Hemminger   [IPV4]: cleanup
842
843
844
845
846
847
848
849
850
  		struct sockaddr_in *psin;
  		struct ip_msfilter *msf = NULL;
  		struct group_filter *gsf = NULL;
  		int msize, i, ifindex;
  
  		if (optlen < GROUP_FILTER_SIZE(0))
  			goto e_inval;
  		if (optlen > sysctl_optmem_max) {
  			err = -ENOBUFS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
851
852
  			break;
  		}
09cb105ea   Jianjun Kong   net: clean up net...
853
  		gsf = kmalloc(optlen, GFP_KERNEL);
cfcabdcc2   Stephen Hemminger   [NET]: sparse war...
854
  		if (!gsf) {
132adf546   Stephen Hemminger   [IPV4]: cleanup
855
  			err = -ENOBUFS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
856
857
  			break;
  		}
132adf546   Stephen Hemminger   [IPV4]: cleanup
858
  		err = -EFAULT;
4d52cfbef   Eric Dumazet   net: ipv4/ip_sock...
859
  		if (copy_from_user(gsf, optval, optlen))
132adf546   Stephen Hemminger   [IPV4]: cleanup
860
  			goto mc_msf_out;
4d52cfbef   Eric Dumazet   net: ipv4/ip_sock...
861

132adf546   Stephen Hemminger   [IPV4]: cleanup
862
863
864
865
866
867
868
869
870
871
872
  		/* numsrc >= (4G-140)/128 overflow in 32 bits */
  		if (gsf->gf_numsrc >= 0x1ffffff ||
  		    gsf->gf_numsrc > sysctl_igmp_max_msf) {
  			err = -ENOBUFS;
  			goto mc_msf_out;
  		}
  		if (GROUP_FILTER_SIZE(gsf->gf_numsrc) > optlen) {
  			err = -EINVAL;
  			goto mc_msf_out;
  		}
  		msize = IP_MSFILTER_SIZE(gsf->gf_numsrc);
09cb105ea   Jianjun Kong   net: clean up net...
873
  		msf = kmalloc(msize, GFP_KERNEL);
cfcabdcc2   Stephen Hemminger   [NET]: sparse war...
874
  		if (!msf) {
132adf546   Stephen Hemminger   [IPV4]: cleanup
875
876
877
878
879
880
  			err = -ENOBUFS;
  			goto mc_msf_out;
  		}
  		ifindex = gsf->gf_interface;
  		psin = (struct sockaddr_in *)&gsf->gf_group;
  		if (psin->sin_family != AF_INET) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
881
  			err = -EADDRNOTAVAIL;
132adf546   Stephen Hemminger   [IPV4]: cleanup
882
  			goto mc_msf_out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
883
  		}
132adf546   Stephen Hemminger   [IPV4]: cleanup
884
885
886
887
888
  		msf->imsf_multiaddr = psin->sin_addr.s_addr;
  		msf->imsf_interface = 0;
  		msf->imsf_fmode = gsf->gf_fmode;
  		msf->imsf_numsrc = gsf->gf_numsrc;
  		err = -EADDRNOTAVAIL;
4d52cfbef   Eric Dumazet   net: ipv4/ip_sock...
889
  		for (i = 0; i < gsf->gf_numsrc; ++i) {
132adf546   Stephen Hemminger   [IPV4]: cleanup
890
  			psin = (struct sockaddr_in *)&gsf->gf_slist[i];
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
891

132adf546   Stephen Hemminger   [IPV4]: cleanup
892
893
894
895
896
897
898
899
  			if (psin->sin_family != AF_INET)
  				goto mc_msf_out;
  			msf->imsf_slist[i] = psin->sin_addr.s_addr;
  		}
  		kfree(gsf);
  		gsf = NULL;
  
  		err = ip_mc_msfilter(sk, msf, ifindex);
4d52cfbef   Eric Dumazet   net: ipv4/ip_sock...
900
  mc_msf_out:
132adf546   Stephen Hemminger   [IPV4]: cleanup
901
902
903
904
  		kfree(msf);
  		kfree(gsf);
  		break;
  	}
f771bef98   Nivedita Singhvi   ipv4: New multica...
905
906
907
908
909
910
911
  	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
912
913
914
915
916
  	case IP_ROUTER_ALERT:
  		err = ip_ra_control(sk, val ? 1 : 0, NULL);
  		break;
  
  	case IP_FREEBIND:
4d52cfbef   Eric Dumazet   net: ipv4/ip_sock...
917
  		if (optlen < 1)
132adf546   Stephen Hemminger   [IPV4]: cleanup
918
919
920
921
922
923
924
925
  			goto e_inval;
  		inet->freebind = !!val;
  		break;
  
  	case IP_IPSEC_POLICY:
  	case IP_XFRM_POLICY:
  		err = -EPERM;
  		if (!capable(CAP_NET_ADMIN))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
926
  			break;
132adf546   Stephen Hemminger   [IPV4]: cleanup
927
928
  		err = xfrm_user_policy(sk, optname, optval, optlen);
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
929

f5715aea4   KOVACS Krisztian   ipv4: Implement I...
930
  	case IP_TRANSPARENT:
6cc7a765c   Maciej Żenczykowski   net: allow CAP_NE...
931
  		if (!!val && !capable(CAP_NET_RAW) && !capable(CAP_NET_ADMIN)) {
f5715aea4   KOVACS Krisztian   ipv4: Implement I...
932
933
934
935
936
937
938
  			err = -EPERM;
  			break;
  		}
  		if (optlen < 1)
  			goto e_inval;
  		inet->transparent = !!val;
  		break;
d218d1113   Stephen Hemminger   tcp: Generalized ...
939
940
941
942
943
944
945
  	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
946
947
948
  	default:
  		err = -ENOPROTOOPT;
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
949
950
951
952
953
954
955
956
  	}
  	release_sock(sk);
  	return err;
  
  e_inval:
  	release_sock(sk);
  	return -EINVAL;
  }
f84af32cb   Eric Dumazet   net: ip_queue_rcv...
957
  /**
d826eb14e   Eric Dumazet   ipv4: PKTINFO doe...
958
   * ipv4_pktinfo_prepare - transfert some info from rtable to skb
f84af32cb   Eric Dumazet   net: ip_queue_rcv...
959
960
961
   * @sk: socket
   * @skb: buffer
   *
d826eb14e   Eric Dumazet   ipv4: PKTINFO doe...
962
963
964
   * To support IP_CMSG_PKTINFO option, we store rt_iif and rt_spec_dst
   * in skb->cb[] before dst drop.
   * This way, receiver doesnt make cache line misses to read rtable.
f84af32cb   Eric Dumazet   net: ip_queue_rcv...
965
   */
d826eb14e   Eric Dumazet   ipv4: PKTINFO doe...
966
  void ipv4_pktinfo_prepare(struct sk_buff *skb)
f84af32cb   Eric Dumazet   net: ip_queue_rcv...
967
  {
d826eb14e   Eric Dumazet   ipv4: PKTINFO doe...
968
969
970
971
972
973
974
975
976
977
978
  	struct in_pktinfo *pktinfo = PKTINFO_SKB_CB(skb);
  	const struct rtable *rt = skb_rtable(skb);
  
  	if (rt) {
  		pktinfo->ipi_ifindex = rt->rt_iif;
  		pktinfo->ipi_spec_dst.s_addr = rt->rt_spec_dst;
  	} else {
  		pktinfo->ipi_ifindex = 0;
  		pktinfo->ipi_spec_dst.s_addr = 0;
  	}
  	skb_dst_drop(skb);
f84af32cb   Eric Dumazet   net: ip_queue_rcv...
979
  }
f84af32cb   Eric Dumazet   net: ip_queue_rcv...
980

3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
981
  int ip_setsockopt(struct sock *sk, int level,
b7058842c   David S. Miller   net: Make setsock...
982
  		int optname, char __user *optval, unsigned int optlen)
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
983
984
985
986
987
988
989
990
991
992
  {
  	int err;
  
  	if (level != SOL_IP)
  		return -ENOPROTOOPT;
  
  	err = do_ip_setsockopt(sk, level, optname, optval, optlen);
  #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...
993
994
995
  			optname != IP_IPSEC_POLICY &&
  			optname != IP_XFRM_POLICY &&
  			!ip_mroute_opt(optname)) {
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
996
997
998
999
1000
1001
1002
  		lock_sock(sk);
  		err = nf_setsockopt(sk, PF_INET, optname, optval, optlen);
  		release_sock(sk);
  	}
  #endif
  	return err;
  }
4d52cfbef   Eric Dumazet   net: ipv4/ip_sock...
1003
  EXPORT_SYMBOL(ip_setsockopt);
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1004
1005
  
  #ifdef CONFIG_COMPAT
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
1006
  int compat_ip_setsockopt(struct sock *sk, int level, int optname,
b7058842c   David S. Miller   net: Make setsock...
1007
  			 char __user *optval, unsigned int optlen)
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1008
1009
1010
1011
1012
  {
  	int err;
  
  	if (level != SOL_IP)
  		return -ENOPROTOOPT;
dae502954   David L Stevens   ipv4/ipv6 compat:...
1013
1014
1015
  	if (optname >= MCAST_JOIN_GROUP && optname <= MCAST_MSFILTER)
  		return compat_mc_setsockopt(sk, level, optname, optval, optlen,
  			ip_setsockopt);
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1016
1017
1018
1019
  	err = do_ip_setsockopt(sk, level, optname, optval, optlen);
  #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...
1020
1021
1022
  			optname != IP_IPSEC_POLICY &&
  			optname != IP_XFRM_POLICY &&
  			!ip_mroute_opt(optname)) {
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1023
  		lock_sock(sk);
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
1024
1025
  		err = compat_nf_setsockopt(sk, PF_INET, optname,
  					   optval, optlen);
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1026
1027
1028
1029
1030
  		release_sock(sk);
  	}
  #endif
  	return err;
  }
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
1031
  EXPORT_SYMBOL(compat_ip_setsockopt);
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1032
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1033
  /*
4d52cfbef   Eric Dumazet   net: ipv4/ip_sock...
1034
1035
   *	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
1036
   */
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1037
  static int do_ip_getsockopt(struct sock *sk, int level, int optname,
dd23198e5   Daniel Baluta   ipv4: Fix ip_gets...
1038
  			    char __user *optval, int __user *optlen, unsigned flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1039
1040
1041
1042
  {
  	struct inet_sock *inet = inet_sk(sk);
  	int val;
  	int len;
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
1043

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

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1054
  	lock_sock(sk);
132adf546   Stephen Hemminger   [IPV4]: cleanup
1055
1056
1057
1058
  	switch (optname) {
  	case IP_OPTIONS:
  	{
  		unsigned char optbuf[sizeof(struct ip_options)+40];
f6d8bd051   Eric Dumazet   inet: add RCU pro...
1059
1060
1061
1062
1063
  		struct ip_options *opt = (struct ip_options *)optbuf;
  		struct ip_options_rcu *inet_opt;
  
  		inet_opt = rcu_dereference_protected(inet->inet_opt,
  						     sock_owned_by_user(sk));
132adf546   Stephen Hemminger   [IPV4]: cleanup
1064
  		opt->optlen = 0;
f6d8bd051   Eric Dumazet   inet: add RCU pro...
1065
1066
1067
1068
  		if (inet_opt)
  			memcpy(optbuf, &inet_opt->opt,
  			       sizeof(struct ip_options) +
  			       inet_opt->opt.optlen);
132adf546   Stephen Hemminger   [IPV4]: cleanup
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
  		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...
1101
1102
1103
  	case IP_RECVORIGDSTADDR:
  		val = (inet->cmsg_flags & IP_CMSG_ORIGDSTADDR) != 0;
  		break;
132adf546   Stephen Hemminger   [IPV4]: cleanup
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
  	case IP_TOS:
  		val = inet->tos;
  		break;
  	case IP_TTL:
  		val = (inet->uc_ttl == -1 ?
  		       sysctl_ip_default_ttl :
  		       inet->uc_ttl);
  		break;
  	case IP_HDRINCL:
  		val = inet->hdrincl;
  		break;
a89b47639   Michael Kerrisk   ipv4: enable gets...
1115
1116
1117
  	case IP_NODEFRAG:
  		val = inet->nodefrag;
  		break;
132adf546   Stephen Hemminger   [IPV4]: cleanup
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
  	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
1129
  		}
132adf546   Stephen Hemminger   [IPV4]: cleanup
1130
  		if (!val) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1131
  			release_sock(sk);
132adf546   Stephen Hemminger   [IPV4]: cleanup
1132
  			return -ENOTCONN;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1133
  		}
132adf546   Stephen Hemminger   [IPV4]: cleanup
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
  		break;
  	}
  	case IP_RECVERR:
  		val = inet->recverr;
  		break;
  	case IP_MULTICAST_TTL:
  		val = inet->mc_ttl;
  		break;
  	case IP_MULTICAST_LOOP:
  		val = inet->mc_loop;
  		break;
  	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
1151

132adf546   Stephen Hemminger   [IPV4]: cleanup
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
  		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;
  		int err;
  
  		if (len < IP_MSFILTER_SIZE(0)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1164
  			release_sock(sk);
132adf546   Stephen Hemminger   [IPV4]: cleanup
1165
  			return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1166
  		}
132adf546   Stephen Hemminger   [IPV4]: cleanup
1167
  		if (copy_from_user(&msf, optval, IP_MSFILTER_SIZE(0))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1168
  			release_sock(sk);
132adf546   Stephen Hemminger   [IPV4]: cleanup
1169
  			return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1170
  		}
132adf546   Stephen Hemminger   [IPV4]: cleanup
1171
1172
1173
1174
1175
1176
1177
1178
1179
  		err = ip_mc_msfget(sk, &msf,
  				   (struct ip_msfilter __user *)optval, optlen);
  		release_sock(sk);
  		return err;
  	}
  	case MCAST_MSFILTER:
  	{
  		struct group_filter gsf;
  		int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1180

132adf546   Stephen Hemminger   [IPV4]: cleanup
1181
  		if (len < GROUP_FILTER_SIZE(0)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1182
  			release_sock(sk);
132adf546   Stephen Hemminger   [IPV4]: cleanup
1183
1184
1185
1186
1187
1188
1189
  			return -EINVAL;
  		}
  		if (copy_from_user(&gsf, optval, GROUP_FILTER_SIZE(0))) {
  			release_sock(sk);
  			return -EFAULT;
  		}
  		err = ip_mc_gsfget(sk, &gsf,
4d52cfbef   Eric Dumazet   net: ipv4/ip_sock...
1190
1191
  				   (struct group_filter __user *)optval,
  				   optlen);
132adf546   Stephen Hemminger   [IPV4]: cleanup
1192
1193
1194
  		release_sock(sk);
  		return err;
  	}
f771bef98   Nivedita Singhvi   ipv4: New multica...
1195
1196
1197
  	case IP_MULTICAST_ALL:
  		val = inet->mc_all;
  		break;
132adf546   Stephen Hemminger   [IPV4]: cleanup
1198
1199
1200
  	case IP_PKTOPTIONS:
  	{
  		struct msghdr msg;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1201

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

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

132adf546   Stephen Hemminger   [IPV4]: cleanup
1207
1208
  		msg.msg_control = optval;
  		msg.msg_controllen = len;
dd23198e5   Daniel Baluta   ipv4: Fix ip_gets...
1209
  		msg.msg_flags = flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1210

132adf546   Stephen Hemminger   [IPV4]: cleanup
1211
1212
  		if (inet->cmsg_flags & IP_CMSG_PKTINFO) {
  			struct in_pktinfo info;
c720c7e83   Eric Dumazet   inet: rename some...
1213
1214
  			info.ipi_addr.s_addr = inet->inet_rcv_saddr;
  			info.ipi_spec_dst.s_addr = inet->inet_rcv_saddr;
132adf546   Stephen Hemminger   [IPV4]: cleanup
1215
1216
  			info.ipi_ifindex = inet->mc_index;
  			put_cmsg(&msg, SOL_IP, IP_PKTINFO, sizeof(info), &info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1217
  		}
132adf546   Stephen Hemminger   [IPV4]: cleanup
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
  		if (inet->cmsg_flags & IP_CMSG_TTL) {
  			int hlim = inet->mc_ttl;
  			put_cmsg(&msg, SOL_IP, IP_TTL, sizeof(hlim), &hlim);
  		}
  		len -= msg.msg_controllen;
  		return put_user(len, optlen);
  	}
  	case IP_FREEBIND:
  		val = inet->freebind;
  		break;
f5715aea4   KOVACS Krisztian   ipv4: Implement I...
1228
1229
1230
  	case IP_TRANSPARENT:
  		val = inet->transparent;
  		break;
d218d1113   Stephen Hemminger   tcp: Generalized ...
1231
1232
1233
  	case IP_MINTTL:
  		val = inet->min_ttl;
  		break;
132adf546   Stephen Hemminger   [IPV4]: cleanup
1234
1235
1236
  	default:
  		release_sock(sk);
  		return -ENOPROTOOPT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1237
1238
  	}
  	release_sock(sk);
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
1239

4d52cfbef   Eric Dumazet   net: ipv4/ip_sock...
1240
  	if (len < sizeof(int) && len > 0 && val >= 0 && val <= 255) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1241
1242
  		unsigned char ucval = (unsigned char)val;
  		len = 1;
132adf546   Stephen Hemminger   [IPV4]: cleanup
1243
  		if (put_user(len, optlen))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1244
  			return -EFAULT;
09cb105ea   Jianjun Kong   net: clean up net...
1245
  		if (copy_to_user(optval, &ucval, 1))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1246
1247
1248
  			return -EFAULT;
  	} else {
  		len = min_t(unsigned int, sizeof(int), len);
132adf546   Stephen Hemminger   [IPV4]: cleanup
1249
  		if (put_user(len, optlen))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1250
  			return -EFAULT;
09cb105ea   Jianjun Kong   net: clean up net...
1251
  		if (copy_to_user(optval, &val, len))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1252
1253
1254
1255
  			return -EFAULT;
  	}
  	return 0;
  }
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1256
  int ip_getsockopt(struct sock *sk, int level,
132adf546   Stephen Hemminger   [IPV4]: cleanup
1257
  		  int optname, char __user *optval, int __user *optlen)
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1258
1259
  {
  	int err;
dd23198e5   Daniel Baluta   ipv4: Fix ip_gets...
1260
  	err = do_ip_getsockopt(sk, level, optname, optval, optlen, 0);
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1261
1262
  #ifdef CONFIG_NETFILTER
  	/* we need to exclude all possible ENOPROTOOPTs except default case */
6a9fb9479   Pavel Emelyanov   [IPV4]: Clean the...
1263
1264
  	if (err == -ENOPROTOOPT && optname != IP_PKTOPTIONS &&
  			!ip_mroute_opt(optname)) {
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
1265
  		int len;
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1266

09cb105ea   Jianjun Kong   net: clean up net...
1267
  		if (get_user(len, optlen))
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
  			return -EFAULT;
  
  		lock_sock(sk);
  		err = nf_getsockopt(sk, PF_INET, optname, optval,
  				&len);
  		release_sock(sk);
  		if (err >= 0)
  			err = put_user(len, optlen);
  		return err;
  	}
  #endif
  	return err;
  }
4d52cfbef   Eric Dumazet   net: ipv4/ip_sock...
1281
  EXPORT_SYMBOL(ip_getsockopt);
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1282
1283
  
  #ifdef CONFIG_COMPAT
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
1284
1285
  int compat_ip_getsockopt(struct sock *sk, int level, int optname,
  			 char __user *optval, int __user *optlen)
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1286
  {
42908c69f   David L Stevens   net: Add compat s...
1287
1288
1289
1290
1291
  	int err;
  
  	if (optname == MCAST_MSFILTER)
  		return compat_mc_getsockopt(sk, level, optname, optval, optlen,
  			ip_getsockopt);
dd23198e5   Daniel Baluta   ipv4: Fix ip_gets...
1292
1293
  	err = do_ip_getsockopt(sk, level, optname, optval, optlen,
  		MSG_CMSG_COMPAT);
42908c69f   David L Stevens   net: Add compat s...
1294

3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1295
1296
  #ifdef CONFIG_NETFILTER
  	/* we need to exclude all possible ENOPROTOOPTs except default case */
6a9fb9479   Pavel Emelyanov   [IPV4]: Clean the...
1297
1298
  	if (err == -ENOPROTOOPT && optname != IP_PKTOPTIONS &&
  			!ip_mroute_opt(optname)) {
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
1299
  		int len;
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1300

543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
1301
  		if (get_user(len, optlen))
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1302
1303
1304
  			return -EFAULT;
  
  		lock_sock(sk);
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
1305
  		err = compat_nf_getsockopt(sk, PF_INET, optname, optval, &len);
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1306
1307
1308
1309
1310
1311
1312
1313
  		release_sock(sk);
  		if (err >= 0)
  			err = put_user(len, optlen);
  		return err;
  	}
  #endif
  	return err;
  }
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
1314
  EXPORT_SYMBOL(compat_ip_getsockopt);
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1315
  #endif