Blame view

net/ipv6/ipv6_sockglue.c 30 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
  /*
   *	IPv6 BSD socket options interface
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
3
   *	Linux INET6 implementation
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4
5
   *
   *	Authors:
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
6
   *	Pedro Roque		<roque@di.fc.ul.pt>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7
8
9
   *
   *	Based on linux/net/ipv4/ip_sockglue.c
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
10
11
12
13
14
15
16
   *	This program is free software; you can redistribute it and/or
   *      modify it under the terms of the GNU General Public License
   *      as published by the Free Software Foundation; either version
   *      2 of the License, or (at your option) any later version.
   *
   *	FIXME: Make the setsockopt code POSIX compliant: That is
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
18
19
20
21
22
23
24
25
   *	o	Truncate getsockopt returns
   *	o	Return an optlen of the truncated length if need be
   *
   *	Changes:
   *	David L Stevens <dlstevens@us.ibm.com>:
   *		- added multicast source filtering API for MLDv2
   */
  
  #include <linux/module.h>
4fc268d24   Randy Dunlap   [PATCH] capable/c...
26
  #include <linux/capability.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
28
29
30
  #include <linux/errno.h>
  #include <linux/types.h>
  #include <linux/socket.h>
  #include <linux/sockios.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
32
  #include <linux/net.h>
  #include <linux/in6.h>
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
33
  #include <linux/mroute6.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
35
36
37
38
  #include <linux/netdevice.h>
  #include <linux/if_arp.h>
  #include <linux/init.h>
  #include <linux/sysctl.h>
  #include <linux/netfilter.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
39
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40
41
42
43
44
45
46
47
48
49
50
51
  
  #include <net/sock.h>
  #include <net/snmp.h>
  #include <net/ipv6.h>
  #include <net/ndisc.h>
  #include <net/protocol.h>
  #include <net/transp_v6.h>
  #include <net/ip6_route.h>
  #include <net/addrconf.h>
  #include <net/inet_common.h>
  #include <net/tcp.h>
  #include <net/udp.h>
ba4e58eca   Gerrit Renker   [NET]: Supporting...
52
  #include <net/udplite.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
53
  #include <net/xfrm.h>
dae502954   David L Stevens   ipv4/ipv6 compat:...
54
  #include <net/compat.h>
a149e7c7c   David Lebrun   ipv6: sr: add sup...
55
  #include <net/seg6.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56

7c0f6ba68   Linus Torvalds   Replace <asm/uacc...
57
  #include <linux/uaccess.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
59
60
  struct ip6_ra_chain *ip6_ra_chain;
  DEFINE_RWLOCK(ip6_ra_lock);
725a8ff04   Denis V. Lunev   ipv6: remove unus...
61
  int ip6_ra_control(struct sock *sk, int sel)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62
63
64
65
  {
  	struct ip6_ra_chain *ra, *new_ra, **rap;
  
  	/* RA packet may be delivered ONLY to IPPROTO_RAW socket */
c720c7e83   Eric Dumazet   inet: rename some...
66
  	if (sk->sk_type != SOCK_RAW || inet_sk(sk)->inet_num != IPPROTO_RAW)
1717699cd   YOSHIFUJI Hideaki   ipv6: Fail with a...
67
  		return -ENOPROTOOPT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68

67ba4152e   Ian Morris   ipv6: White-space...
69
  	new_ra = (sel >= 0) ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70
71
  
  	write_lock_bh(&ip6_ra_lock);
67ba4152e   Ian Morris   ipv6: White-space...
72
  	for (rap = &ip6_ra_chain; (ra = *rap) != NULL; rap = &ra->next) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
73
  		if (ra->sk == sk) {
67ba4152e   Ian Morris   ipv6: White-space...
74
  			if (sel >= 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75
  				write_unlock_bh(&ip6_ra_lock);
a51482bde   Jesper Juhl   [NET]: kfree cleanup
76
  				kfree(new_ra);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
77
78
79
80
81
  				return -EADDRINUSE;
  			}
  
  			*rap = ra->next;
  			write_unlock_bh(&ip6_ra_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
82
83
84
85
86
  			sock_put(sk);
  			kfree(ra);
  			return 0;
  		}
  	}
63159f29b   Ian Morris   ipv6: coding styl...
87
  	if (!new_ra) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
88
89
90
91
92
  		write_unlock_bh(&ip6_ra_lock);
  		return -ENOBUFS;
  	}
  	new_ra->sk = sk;
  	new_ra->sel = sel;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
93
94
95
96
97
98
  	new_ra->next = ra;
  	*rap = new_ra;
  	sock_hold(sk);
  	write_unlock_bh(&ip6_ra_lock);
  	return 0;
  }
e7712f1a7   YOSHIFUJI Hideaki   [IPV6]: Share com...
99
100
101
102
103
104
  struct ipv6_txoptions *ipv6_update_options(struct sock *sk,
  					   struct ipv6_txoptions *opt)
  {
  	if (inet_sk(sk)->is_icsk) {
  		if (opt &&
  		    !((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE)) &&
c720c7e83   Eric Dumazet   inet: rename some...
105
  		    inet_sk(sk)->inet_daddr != LOOPBACK4_IPV6) {
e7712f1a7   YOSHIFUJI Hideaki   [IPV6]: Share com...
106
107
108
109
  			struct inet_connection_sock *icsk = inet_csk(sk);
  			icsk->icsk_ext_hdr_len = opt->opt_flen + opt->opt_nflen;
  			icsk->icsk_sync_mss(sk, icsk->icsk_pmtu_cookie);
  		}
e7712f1a7   YOSHIFUJI Hideaki   [IPV6]: Share com...
110
  	}
45f6fad84   Eric Dumazet   ipv6: add complet...
111
112
  	opt = xchg((__force struct ipv6_txoptions **)&inet6_sk(sk)->opt,
  		   opt);
e7712f1a7   YOSHIFUJI Hideaki   [IPV6]: Share com...
113
114
115
116
  	sk_dst_reset(sk);
  
  	return opt;
  }
baf606d9c   Marcelo Ricardo Leitner   ipv4,ipv6: grab r...
117
118
119
  static bool setsockopt_needs_rtnl(int optname)
  {
  	switch (optname) {
8651be8f1   WANG Cong   ipv6: fix a poten...
120
  	case IPV6_ADDRFORM:
baf606d9c   Marcelo Ricardo Leitner   ipv4,ipv6: grab r...
121
122
  	case IPV6_ADD_MEMBERSHIP:
  	case IPV6_DROP_MEMBERSHIP:
c4a6853d8   Marcelo Ricardo Leitner   ipv6: invert join...
123
124
  	case IPV6_JOIN_ANYCAST:
  	case IPV6_LEAVE_ANYCAST:
baf606d9c   Marcelo Ricardo Leitner   ipv4,ipv6: grab r...
125
126
  	case MCAST_JOIN_GROUP:
  	case MCAST_LEAVE_GROUP:
54ff9ef36   Marcelo Ricardo Leitner   ipv4, ipv6: kill ...
127
128
129
130
131
  	case MCAST_JOIN_SOURCE_GROUP:
  	case MCAST_LEAVE_SOURCE_GROUP:
  	case MCAST_BLOCK_SOURCE:
  	case MCAST_UNBLOCK_SOURCE:
  	case MCAST_MSFILTER:
baf606d9c   Marcelo Ricardo Leitner   ipv4,ipv6: grab r...
132
133
134
135
  		return true;
  	}
  	return false;
  }
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
136
  static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
b7058842c   David S. Miller   net: Make setsock...
137
  		    char __user *optval, unsigned int optlen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
138
139
  {
  	struct ipv6_pinfo *np = inet6_sk(sk);
3b1e0a655   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
140
  	struct net *net = sock_net(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141
142
  	int val, valbool;
  	int retv = -ENOPROTOOPT;
baf606d9c   Marcelo Ricardo Leitner   ipv4,ipv6: grab r...
143
  	bool needs_rtnl = setsockopt_needs_rtnl(optname);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144

63159f29b   Ian Morris   ipv6: coding styl...
145
  	if (!optval)
67ba4152e   Ian Morris   ipv6: White-space...
146
  		val = 0;
b2a9d7c2f   YOSHIFUJI Hideaki   [IPV6]: Check len...
147
148
149
150
151
152
153
  	else {
  		if (optlen >= sizeof(int)) {
  			if (get_user(val, (int __user *) optval))
  				return -EFAULT;
  		} else
  			val = 0;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
154

67ba4152e   Ian Morris   ipv6: White-space...
155
  	valbool = (val != 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
156

7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
157
158
  	if (ip6_mroute_opt(optname))
  		return ip6_mroute_setsockopt(sk, optname, optval, optlen);
baf606d9c   Marcelo Ricardo Leitner   ipv4,ipv6: grab r...
159
160
  	if (needs_rtnl)
  		rtnl_lock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161
162
163
164
165
  	lock_sock(sk);
  
  	switch (optname) {
  
  	case IPV6_ADDRFORM:
b2a9d7c2f   YOSHIFUJI Hideaki   [IPV6]: Check len...
166
167
  		if (optlen < sizeof(int))
  			goto e_inval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
168
169
170
  		if (val == PF_INET) {
  			struct ipv6_txoptions *opt;
  			struct sk_buff *pktopt;
49d074f40   Denis V. Lunev   [IPV6]: Do not ch...
171
172
  			if (sk->sk_type == SOCK_RAW)
  				break;
9596cc826   Denis V. Lunev   [IPV6]: Do not ch...
173
174
175
176
177
178
179
180
  			if (sk->sk_protocol == IPPROTO_UDP ||
  			    sk->sk_protocol == IPPROTO_UDPLITE) {
  				struct udp_sock *up = udp_sk(sk);
  				if (up->pending == AF_INET6) {
  					retv = -EBUSY;
  					break;
  				}
  			} else if (sk->sk_protocol != IPPROTO_TCP)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181
182
183
184
185
186
187
188
  				break;
  
  			if (sk->sk_state != TCP_ESTABLISHED) {
  				retv = -ENOTCONN;
  				break;
  			}
  
  			if (ipv6_only_sock(sk) ||
efe4208f4   Eric Dumazet   ipv6: make lookup...
189
  			    !ipv6_addr_v4mapped(&sk->sk_v6_daddr)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
190
191
192
193
194
  				retv = -EADDRNOTAVAIL;
  				break;
  			}
  
  			fl6_free_socklist(sk);
8651be8f1   WANG Cong   ipv6: fix a poten...
195
  			__ipv6_sock_mc_close(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
196

e6848976b   Arnaldo Carvalho de Melo   [NET]: Cleanup IN...
197
198
199
200
201
202
  			/*
  			 * Sock is moving from IPv6 to IPv4 (sk_prot), so
  			 * remove it from the refcnt debug socks count in the
  			 * original family...
  			 */
  			sk_refcnt_debug_dec(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
203
  			if (sk->sk_protocol == IPPROTO_TCP) {
d83d8461f   Arnaldo Carvalho de Melo   [IP_SOCKGLUE]: Re...
204
  				struct inet_connection_sock *icsk = inet_csk(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
205
  				local_bh_disable();
c29a0bc4d   Pavel Emelyanov   [SOCK][NETNS]: Ad...
206
207
  				sock_prot_inuse_add(net, sk->sk_prot, -1);
  				sock_prot_inuse_add(net, &tcp_prot, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208
209
  				local_bh_enable();
  				sk->sk_prot = &tcp_prot;
d83d8461f   Arnaldo Carvalho de Melo   [IP_SOCKGLUE]: Re...
210
  				icsk->icsk_af_ops = &ipv4_specific;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
211
212
  				sk->sk_socket->ops = &inet_stream_ops;
  				sk->sk_family = PF_INET;
d83d8461f   Arnaldo Carvalho de Melo   [IP_SOCKGLUE]: Re...
213
  				tcp_sync_mss(sk, icsk->icsk_pmtu_cookie);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
214
  			} else {
ba4e58eca   Gerrit Renker   [NET]: Supporting...
215
  				struct proto *prot = &udp_prot;
db8dac20d   David S. Miller   [UDP]: Revert udp...
216
  				if (sk->sk_protocol == IPPROTO_UDPLITE)
ba4e58eca   Gerrit Renker   [NET]: Supporting...
217
  					prot = &udplite_prot;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
218
  				local_bh_disable();
c29a0bc4d   Pavel Emelyanov   [SOCK][NETNS]: Ad...
219
220
  				sock_prot_inuse_add(net, sk->sk_prot, -1);
  				sock_prot_inuse_add(net, prot, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
221
  				local_bh_enable();
ba4e58eca   Gerrit Renker   [NET]: Supporting...
222
  				sk->sk_prot = prot;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
223
224
225
  				sk->sk_socket->ops = &inet_dgram_ops;
  				sk->sk_family = PF_INET;
  			}
45f6fad84   Eric Dumazet   ipv6: add complet...
226
227
228
229
230
231
  			opt = xchg((__force struct ipv6_txoptions **)&np->opt,
  				   NULL);
  			if (opt) {
  				atomic_sub(opt->tot_len, &sk->sk_omem_alloc);
  				txopt_put(opt);
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
232
  			pktopt = xchg(&np->pktoptions, NULL);
800d55f14   Wei Yongjun   ipv6: Remove some...
233
  			kfree_skb(pktopt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
234

e6848976b   Arnaldo Carvalho de Melo   [NET]: Cleanup IN...
235
236
237
238
239
  			/*
  			 * ... and add it to the refcnt debug socks count
  			 * in the new family. -acme
  			 */
  			sk_refcnt_debug_inc(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
240
241
242
243
244
245
246
  			module_put(THIS_MODULE);
  			retv = 0;
  			break;
  		}
  		goto e_inval;
  
  	case IPV6_V6ONLY:
b2a9d7c2f   YOSHIFUJI Hideaki   [IPV6]: Check len...
247
  		if (optlen < sizeof(int) ||
c720c7e83   Eric Dumazet   inet: rename some...
248
  		    inet_sk(sk)->inet_num)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
249
  			goto e_inval;
9fe516ba3   Eric Dumazet   inet: move ipv6on...
250
  		sk->sk_ipv6only = valbool;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
251
252
  		retv = 0;
  		break;
333fad536   YOSHIFUJI Hideaki   [IPV6]: Support s...
253
  	case IPV6_RECVPKTINFO:
b2a9d7c2f   YOSHIFUJI Hideaki   [IPV6]: Check len...
254
255
  		if (optlen < sizeof(int))
  			goto e_inval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
256
257
258
  		np->rxopt.bits.rxinfo = valbool;
  		retv = 0;
  		break;
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
259

333fad536   YOSHIFUJI Hideaki   [IPV6]: Support s...
260
  	case IPV6_2292PKTINFO:
b2a9d7c2f   YOSHIFUJI Hideaki   [IPV6]: Check len...
261
262
  		if (optlen < sizeof(int))
  			goto e_inval;
333fad536   YOSHIFUJI Hideaki   [IPV6]: Support s...
263
264
265
  		np->rxopt.bits.rxoinfo = valbool;
  		retv = 0;
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
266

333fad536   YOSHIFUJI Hideaki   [IPV6]: Support s...
267
  	case IPV6_RECVHOPLIMIT:
b2a9d7c2f   YOSHIFUJI Hideaki   [IPV6]: Check len...
268
269
  		if (optlen < sizeof(int))
  			goto e_inval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
270
271
272
  		np->rxopt.bits.rxhlim = valbool;
  		retv = 0;
  		break;
333fad536   YOSHIFUJI Hideaki   [IPV6]: Support s...
273
  	case IPV6_2292HOPLIMIT:
b2a9d7c2f   YOSHIFUJI Hideaki   [IPV6]: Check len...
274
275
  		if (optlen < sizeof(int))
  			goto e_inval;
333fad536   YOSHIFUJI Hideaki   [IPV6]: Support s...
276
277
278
279
280
  		np->rxopt.bits.rxohlim = valbool;
  		retv = 0;
  		break;
  
  	case IPV6_RECVRTHDR:
b2a9d7c2f   YOSHIFUJI Hideaki   [IPV6]: Check len...
281
282
  		if (optlen < sizeof(int))
  			goto e_inval;
4c752098f   YOSHIFUJI Hideaki   [IPV6]: Make IPV6...
283
  		np->rxopt.bits.srcrt = valbool;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
284
285
  		retv = 0;
  		break;
333fad536   YOSHIFUJI Hideaki   [IPV6]: Support s...
286
  	case IPV6_2292RTHDR:
b2a9d7c2f   YOSHIFUJI Hideaki   [IPV6]: Check len...
287
288
  		if (optlen < sizeof(int))
  			goto e_inval;
4c752098f   YOSHIFUJI Hideaki   [IPV6]: Make IPV6...
289
  		np->rxopt.bits.osrcrt = valbool;
333fad536   YOSHIFUJI Hideaki   [IPV6]: Support s...
290
291
292
293
  		retv = 0;
  		break;
  
  	case IPV6_RECVHOPOPTS:
b2a9d7c2f   YOSHIFUJI Hideaki   [IPV6]: Check len...
294
295
  		if (optlen < sizeof(int))
  			goto e_inval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
296
297
298
  		np->rxopt.bits.hopopts = valbool;
  		retv = 0;
  		break;
333fad536   YOSHIFUJI Hideaki   [IPV6]: Support s...
299
  	case IPV6_2292HOPOPTS:
b2a9d7c2f   YOSHIFUJI Hideaki   [IPV6]: Check len...
300
301
  		if (optlen < sizeof(int))
  			goto e_inval;
333fad536   YOSHIFUJI Hideaki   [IPV6]: Support s...
302
303
304
305
306
  		np->rxopt.bits.ohopopts = valbool;
  		retv = 0;
  		break;
  
  	case IPV6_RECVDSTOPTS:
b2a9d7c2f   YOSHIFUJI Hideaki   [IPV6]: Check len...
307
308
  		if (optlen < sizeof(int))
  			goto e_inval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
309
310
311
  		np->rxopt.bits.dstopts = valbool;
  		retv = 0;
  		break;
333fad536   YOSHIFUJI Hideaki   [IPV6]: Support s...
312
  	case IPV6_2292DSTOPTS:
b2a9d7c2f   YOSHIFUJI Hideaki   [IPV6]: Check len...
313
314
  		if (optlen < sizeof(int))
  			goto e_inval;
333fad536   YOSHIFUJI Hideaki   [IPV6]: Support s...
315
316
317
  		np->rxopt.bits.odstopts = valbool;
  		retv = 0;
  		break;
41a1f8ea4   YOSHIFUJI Hideaki   [IPV6]: Support I...
318
  	case IPV6_TCLASS:
b2a9d7c2f   YOSHIFUJI Hideaki   [IPV6]: Check len...
319
320
  		if (optlen < sizeof(int))
  			goto e_inval;
d0ee011f7   Rémi Denis-Courmont   [IPV6]: Accept -1...
321
  		if (val < -1 || val > 0xff)
41a1f8ea4   YOSHIFUJI Hideaki   [IPV6]: Support I...
322
  			goto e_inval;
26ced1e4a   Gerrit Renker   inet6: Set defaul...
323
324
325
  		/* RFC 3542, 6.5: default traffic class of 0x0 */
  		if (val == -1)
  			val = 0;
41a1f8ea4   YOSHIFUJI Hideaki   [IPV6]: Support I...
326
327
328
  		np->tclass = val;
  		retv = 0;
  		break;
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
329

41a1f8ea4   YOSHIFUJI Hideaki   [IPV6]: Support I...
330
  	case IPV6_RECVTCLASS:
b2a9d7c2f   YOSHIFUJI Hideaki   [IPV6]: Check len...
331
332
  		if (optlen < sizeof(int))
  			goto e_inval;
41a1f8ea4   YOSHIFUJI Hideaki   [IPV6]: Support I...
333
334
335
  		np->rxopt.bits.rxtclass = valbool;
  		retv = 0;
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
336
  	case IPV6_FLOWINFO:
b2a9d7c2f   YOSHIFUJI Hideaki   [IPV6]: Check len...
337
338
  		if (optlen < sizeof(int))
  			goto e_inval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
339
340
341
  		np->rxopt.bits.rxflow = valbool;
  		retv = 0;
  		break;
793b14731   Brian Haley   IPv6: data struct...
342
343
344
345
346
347
  	case IPV6_RECVPATHMTU:
  		if (optlen < sizeof(int))
  			goto e_inval;
  		np->rxopt.bits.rxpmtu = valbool;
  		retv = 0;
  		break;
6c4686228   Balazs Scheidler   tproxy: added tpr...
348
  	case IPV6_TRANSPARENT:
af31f412c   Eric W. Biederman   net: Allow userns...
349
350
  		if (valbool && !ns_capable(net->user_ns, CAP_NET_ADMIN) &&
  		    !ns_capable(net->user_ns, CAP_NET_RAW)) {
b889416b5   Balazs Scheidler   tproxy: Add missi...
351
352
353
  			retv = -EPERM;
  			break;
  		}
6c4686228   Balazs Scheidler   tproxy: added tpr...
354
355
356
357
358
359
360
361
362
363
364
365
366
  		if (optlen < sizeof(int))
  			goto e_inval;
  		/* we don't have a separate transparent bit for IPV6 we use the one in the IPv4 socket */
  		inet_sk(sk)->transparent = valbool;
  		retv = 0;
  		break;
  
  	case IPV6_RECVORIGDSTADDR:
  		if (optlen < sizeof(int))
  			goto e_inval;
  		np->rxopt.bits.rxorigdstaddr = valbool;
  		retv = 0;
  		break;
333fad536   YOSHIFUJI Hideaki   [IPV6]: Support s...
367
368
369
370
371
372
  	case IPV6_HOPOPTS:
  	case IPV6_RTHDRDSTOPTS:
  	case IPV6_RTHDR:
  	case IPV6_DSTOPTS:
  	{
  		struct ipv6_txoptions *opt;
8e39e96f2   Paul Moore   ipv6: make ipv6_r...
373
374
375
376
377
378
  		struct ipv6_opt_hdr *new = NULL;
  
  		/* hop-by-hop / destination options are privileged option */
  		retv = -EPERM;
  		if (optname != IPV6_RTHDR && !ns_capable(net->user_ns, CAP_NET_RAW))
  			break;
aea7427f7   Shan Wei   ipv6: Remove opti...
379
380
381
382
  
  		/* remove any sticky options header with a zero option
  		 * length, per RFC3542.
  		 */
333fad536   YOSHIFUJI Hideaki   [IPV6]: Support s...
383
  		if (optlen == 0)
cb422c464   Luiz Capitulino   [IPV6]: Fixes spa...
384
  			optval = NULL;
63159f29b   Ian Morris   ipv6: coding styl...
385
  		else if (!optval)
cfb266c0e   Yang Hongyang   ipv6: Fix the ret...
386
  			goto e_inval;
aea7427f7   Shan Wei   ipv6: Remove opti...
387
388
389
  		else if (optlen < sizeof(struct ipv6_opt_hdr) ||
  			 optlen & 0x7 || optlen > 8 * 255)
  			goto e_inval;
8e39e96f2   Paul Moore   ipv6: make ipv6_r...
390
391
392
393
394
395
396
397
398
399
400
  		else {
  			new = memdup_user(optval, optlen);
  			if (IS_ERR(new)) {
  				retv = PTR_ERR(new);
  				break;
  			}
  			if (unlikely(ipv6_optlen(new) > optlen)) {
  				kfree(new);
  				goto e_inval;
  			}
  		}
333fad536   YOSHIFUJI Hideaki   [IPV6]: Support s...
401

1e1d04e67   Hannes Frederic Sowa   net: introduce lo...
402
403
  		opt = rcu_dereference_protected(np->opt,
  						lockdep_sock_is_held(sk));
8e39e96f2   Paul Moore   ipv6: make ipv6_r...
404
405
  		opt = ipv6_renew_options(sk, opt, optname, new);
  		kfree(new);
333fad536   YOSHIFUJI Hideaki   [IPV6]: Support s...
406
407
408
409
410
411
  		if (IS_ERR(opt)) {
  			retv = PTR_ERR(opt);
  			break;
  		}
  
  		/* routing header option needs extra check */
6e093d9df   Brian Haley   ipv6: routing hea...
412
  		retv = -EINVAL;
dfee0a725   Olaf Kirch   [IPV6]: Fix for i...
413
  		if (optname == IPV6_RTHDR && opt && opt->srcrt) {
333fad536   YOSHIFUJI Hideaki   [IPV6]: Support s...
414
  			struct ipv6_rt_hdr *rthdr = opt->srcrt;
280a9d340   Masahide NAKAMURA   [IPV6] MIP6: Add ...
415
  			switch (rthdr->type) {
07a936260   Amerigo Wang   ipv6: use IS_ENAB...
416
  #if IS_ENABLED(CONFIG_IPV6_MIP6)
280a9d340   Masahide NAKAMURA   [IPV6] MIP6: Add ...
417
  			case IPV6_SRCRT_TYPE_2:
6e093d9df   Brian Haley   ipv6: routing hea...
418
419
420
  				if (rthdr->hdrlen != 2 ||
  				    rthdr->segments_left != 1)
  					goto sticky_done;
280a9d340   Masahide NAKAMURA   [IPV6] MIP6: Add ...
421
  				break;
bb4dbf9e6   YOSHIFUJI Hideaki   [IPV6]: Do not se...
422
  #endif
a149e7c7c   David Lebrun   ipv6: sr: add sup...
423
424
425
426
427
428
429
430
431
  			case IPV6_SRCRT_TYPE_4:
  			{
  				struct ipv6_sr_hdr *srh = (struct ipv6_sr_hdr *)
  							  opt->srcrt;
  
  				if (!seg6_validate_srh(srh, optlen))
  					goto sticky_done;
  				break;
  			}
280a9d340   Masahide NAKAMURA   [IPV6] MIP6: Add ...
432
  			default:
333fad536   YOSHIFUJI Hideaki   [IPV6]: Support s...
433
  				goto sticky_done;
280a9d340   Masahide NAKAMURA   [IPV6] MIP6: Add ...
434
  			}
333fad536   YOSHIFUJI Hideaki   [IPV6]: Support s...
435
436
437
  		}
  
  		retv = 0;
e7712f1a7   YOSHIFUJI Hideaki   [IPV6]: Share com...
438
  		opt = ipv6_update_options(sk, opt);
333fad536   YOSHIFUJI Hideaki   [IPV6]: Support s...
439
  sticky_done:
45f6fad84   Eric Dumazet   ipv6: add complet...
440
441
442
443
  		if (opt) {
  			atomic_sub(opt->tot_len, &sk->sk_omem_alloc);
  			txopt_put(opt);
  		}
333fad536   YOSHIFUJI Hideaki   [IPV6]: Support s...
444
445
  		break;
  	}
b24a2516d   Yang Hongyang   ipv6: Add IPV6_PK...
446
447
448
449
450
451
  	case IPV6_PKTINFO:
  	{
  		struct in6_pktinfo pkt;
  
  		if (optlen == 0)
  			goto e_inval;
63159f29b   Ian Morris   ipv6: coding styl...
452
  		else if (optlen < sizeof(struct in6_pktinfo) || !optval)
b24a2516d   Yang Hongyang   ipv6: Add IPV6_PK...
453
  			goto e_inval;
914d11647   Ilpo Järvinen   ipv6: IPV6_PKTINF...
454
  		if (copy_from_user(&pkt, optval, sizeof(struct in6_pktinfo))) {
b24a2516d   Yang Hongyang   ipv6: Add IPV6_PK...
455
456
457
458
459
460
461
  				retv = -EFAULT;
  				break;
  		}
  		if (sk->sk_bound_dev_if && pkt.ipi6_ifindex != sk->sk_bound_dev_if)
  			goto e_inval;
  
  		np->sticky_pktinfo.ipi6_ifindex = pkt.ipi6_ifindex;
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
462
  		np->sticky_pktinfo.ipi6_addr = pkt.ipi6_addr;
b24a2516d   Yang Hongyang   ipv6: Add IPV6_PK...
463
464
465
  		retv = 0;
  		break;
  	}
333fad536   YOSHIFUJI Hideaki   [IPV6]: Support s...
466
  	case IPV6_2292PKTOPTIONS:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
467
468
469
  	{
  		struct ipv6_txoptions *opt = NULL;
  		struct msghdr msg;
4c9483b2f   David S. Miller   ipv6: Convert to ...
470
  		struct flowi6 fl6;
ad1e46a83   Soheil Hassas Yeganeh   ipv6: process soc...
471
  		struct sockcm_cookie sockc_junk;
26879da58   Wei Wang   ipv6: add new str...
472
  		struct ipcm6_cookie ipc6;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
473

4c9483b2f   David S. Miller   ipv6: Convert to ...
474
475
476
  		memset(&fl6, 0, sizeof(fl6));
  		fl6.flowi6_oif = sk->sk_bound_dev_if;
  		fl6.flowi6_mark = sk->sk_mark;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
477
478
479
480
481
482
483
484
485
486
487
488
489
  
  		if (optlen == 0)
  			goto update;
  
  		/* 1K is probably excessive
  		 * 1K is surely not enough, 2K per standard header is 16K.
  		 */
  		retv = -EINVAL;
  		if (optlen > 64*1024)
  			break;
  
  		opt = sock_kmalloc(sk, sizeof(*opt) + optlen, GFP_KERNEL);
  		retv = -ENOBUFS;
63159f29b   Ian Morris   ipv6: coding styl...
490
  		if (!opt)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
491
492
493
  			break;
  
  		memset(opt, 0, sizeof(*opt));
0aeea21ad   Reshetova, Elena   net, ipv6: conver...
494
  		refcount_set(&opt->refcnt, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
495
496
497
498
499
500
  		opt->tot_len = sizeof(*opt) + optlen;
  		retv = -EFAULT;
  		if (copy_from_user(opt+1, optval, optlen))
  			goto done;
  
  		msg.msg_controllen = optlen;
67ba4152e   Ian Morris   ipv6: White-space...
501
  		msg.msg_control = (void *)(opt+1);
26879da58   Wei Wang   ipv6: add new str...
502
  		ipc6.opt = opt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
503

26879da58   Wei Wang   ipv6: add new str...
504
  		retv = ip6_datagram_send_ctl(net, sk, &msg, &fl6, &ipc6, &sockc_junk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
505
506
507
508
  		if (retv)
  			goto done;
  update:
  		retv = 0;
e7712f1a7   YOSHIFUJI Hideaki   [IPV6]: Share com...
509
  		opt = ipv6_update_options(sk, opt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
510
  done:
45f6fad84   Eric Dumazet   ipv6: add complet...
511
512
513
514
  		if (opt) {
  			atomic_sub(opt->tot_len, &sk->sk_omem_alloc);
  			txopt_put(opt);
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
515
516
517
  		break;
  	}
  	case IPV6_UNICAST_HOPS:
b2a9d7c2f   YOSHIFUJI Hideaki   [IPV6]: Check len...
518
519
  		if (optlen < sizeof(int))
  			goto e_inval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
520
521
522
523
524
525
526
527
  		if (val > 255 || val < -1)
  			goto e_inval;
  		np->hop_limit = val;
  		retv = 0;
  		break;
  
  	case IPV6_MULTICAST_HOPS:
  		if (sk->sk_type == SOCK_STREAM)
1717699cd   YOSHIFUJI Hideaki   ipv6: Fail with a...
528
  			break;
b2a9d7c2f   YOSHIFUJI Hideaki   [IPV6]: Check len...
529
530
  		if (optlen < sizeof(int))
  			goto e_inval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
531
532
  		if (val > 255 || val < -1)
  			goto e_inval;
2a38e6d5a   Li Wei   ipv6: Set mcast_h...
533
  		np->mcast_hops = (val == -1 ? IPV6_DEFAULT_MCASTHOPS : val);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
534
535
536
537
  		retv = 0;
  		break;
  
  	case IPV6_MULTICAST_LOOP:
b2a9d7c2f   YOSHIFUJI Hideaki   [IPV6]: Check len...
538
539
  		if (optlen < sizeof(int))
  			goto e_inval;
28d448821   YOSHIFUJI Hideaki   ipv6: Check IPV6_...
540
541
  		if (val != valbool)
  			goto e_inval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
542
543
544
  		np->mc_loop = valbool;
  		retv = 0;
  		break;
c4062dfc4   Erich E. Hoover   ipv6: Implement I...
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
  	case IPV6_UNICAST_IF:
  	{
  		struct net_device *dev = NULL;
  		int ifindex;
  
  		if (optlen != sizeof(int))
  			goto e_inval;
  
  		ifindex = (__force int)ntohl((__force __be32)val);
  		if (ifindex == 0) {
  			np->ucast_oif = 0;
  			retv = 0;
  			break;
  		}
  
  		dev = dev_get_by_index(net, ifindex);
  		retv = -EADDRNOTAVAIL;
  		if (!dev)
  			break;
  		dev_put(dev);
  
  		retv = -EINVAL;
  		if (sk->sk_bound_dev_if)
  			break;
  
  		np->ucast_oif = ifindex;
  		retv = 0;
  		break;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
574
575
  	case IPV6_MULTICAST_IF:
  		if (sk->sk_type == SOCK_STREAM)
1717699cd   YOSHIFUJI Hideaki   ipv6: Fail with a...
576
  			break;
b2a9d7c2f   YOSHIFUJI Hideaki   [IPV6]: Check len...
577
578
  		if (optlen < sizeof(int))
  			goto e_inval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
579

4953f0fcc   Brian Haley   [IPv6]: Update se...
580
  		if (val) {
55b805035   Eric Dumazet   net: Fix IP_MULTI...
581
  			struct net_device *dev;
7bb387c5a   David Ahern   net: Allow IP_MUL...
582
  			int midx;
55b805035   Eric Dumazet   net: Fix IP_MULTI...
583

7bb387c5a   David Ahern   net: Allow IP_MUL...
584
  			rcu_read_lock();
4953f0fcc   Brian Haley   [IPv6]: Update se...
585

7bb387c5a   David Ahern   net: Allow IP_MUL...
586
  			dev = dev_get_by_index_rcu(net, val);
55b805035   Eric Dumazet   net: Fix IP_MULTI...
587
  			if (!dev) {
7bb387c5a   David Ahern   net: Allow IP_MUL...
588
  				rcu_read_unlock();
4953f0fcc   Brian Haley   [IPv6]: Update se...
589
590
591
  				retv = -ENODEV;
  				break;
  			}
7bb387c5a   David Ahern   net: Allow IP_MUL...
592
593
594
595
596
597
598
599
  			midx = l3mdev_master_ifindex_rcu(dev);
  
  			rcu_read_unlock();
  
  			if (sk->sk_bound_dev_if &&
  			    sk->sk_bound_dev_if != val &&
  			    (!midx || midx != sk->sk_bound_dev_if))
  				goto e_inval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
600
601
602
603
604
605
606
607
  		}
  		np->mcast_oif = val;
  		retv = 0;
  		break;
  	case IPV6_ADD_MEMBERSHIP:
  	case IPV6_DROP_MEMBERSHIP:
  	{
  		struct ipv6_mreq mreq;
a28398ba6   Wang Chen   [IPV6]: Check len...
608
609
  		if (optlen < sizeof(struct ipv6_mreq))
  			goto e_inval;
a96fb49be   Flavio Leitner   [NET]: Fix IP_ADD...
610
611
612
  		retv = -EPROTO;
  		if (inet_sk(sk)->is_icsk)
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
613
614
615
616
617
  		retv = -EFAULT;
  		if (copy_from_user(&mreq, optval, sizeof(struct ipv6_mreq)))
  			break;
  
  		if (optname == IPV6_ADD_MEMBERSHIP)
54ff9ef36   Marcelo Ricardo Leitner   ipv4, ipv6: kill ...
618
  			retv = ipv6_sock_mc_join(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_multiaddr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
619
  		else
54ff9ef36   Marcelo Ricardo Leitner   ipv4, ipv6: kill ...
620
  			retv = ipv6_sock_mc_drop(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_multiaddr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
621
622
623
624
625
626
  		break;
  	}
  	case IPV6_JOIN_ANYCAST:
  	case IPV6_LEAVE_ANYCAST:
  	{
  		struct ipv6_mreq mreq;
a28398ba6   Wang Chen   [IPV6]: Check len...
627
  		if (optlen < sizeof(struct ipv6_mreq))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
  			goto e_inval;
  
  		retv = -EFAULT;
  		if (copy_from_user(&mreq, optval, sizeof(struct ipv6_mreq)))
  			break;
  
  		if (optname == IPV6_JOIN_ANYCAST)
  			retv = ipv6_sock_ac_join(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_acaddr);
  		else
  			retv = ipv6_sock_ac_drop(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_acaddr);
  		break;
  	}
  	case MCAST_JOIN_GROUP:
  	case MCAST_LEAVE_GROUP:
  	{
  		struct group_req greq;
  		struct sockaddr_in6 *psin6;
a28398ba6   Wang Chen   [IPV6]: Check len...
645
646
  		if (optlen < sizeof(struct group_req))
  			goto e_inval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
647
648
649
650
651
652
653
654
655
  		retv = -EFAULT;
  		if (copy_from_user(&greq, optval, sizeof(struct group_req)))
  			break;
  		if (greq.gr_group.ss_family != AF_INET6) {
  			retv = -EADDRNOTAVAIL;
  			break;
  		}
  		psin6 = (struct sockaddr_in6 *)&greq.gr_group;
  		if (optname == MCAST_JOIN_GROUP)
54ff9ef36   Marcelo Ricardo Leitner   ipv4, ipv6: kill ...
656
657
  			retv = ipv6_sock_mc_join(sk, greq.gr_interface,
  						 &psin6->sin6_addr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
658
  		else
54ff9ef36   Marcelo Ricardo Leitner   ipv4, ipv6: kill ...
659
660
  			retv = ipv6_sock_mc_drop(sk, greq.gr_interface,
  						 &psin6->sin6_addr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
661
662
663
664
665
666
667
668
669
  		break;
  	}
  	case MCAST_JOIN_SOURCE_GROUP:
  	case MCAST_LEAVE_SOURCE_GROUP:
  	case MCAST_BLOCK_SOURCE:
  	case MCAST_UNBLOCK_SOURCE:
  	{
  		struct group_source_req greqs;
  		int omode, add;
a28398ba6   Wang Chen   [IPV6]: Check len...
670
  		if (optlen < sizeof(struct group_source_req))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
  			goto e_inval;
  		if (copy_from_user(&greqs, optval, sizeof(greqs))) {
  			retv = -EFAULT;
  			break;
  		}
  		if (greqs.gsr_group.ss_family != AF_INET6 ||
  		    greqs.gsr_source.ss_family != AF_INET6) {
  			retv = -EADDRNOTAVAIL;
  			break;
  		}
  		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 sockaddr_in6 *psin6;
  
  			psin6 = (struct sockaddr_in6 *)&greqs.gsr_group;
54ff9ef36   Marcelo Ricardo Leitner   ipv4, ipv6: kill ...
691
692
  			retv = ipv6_sock_mc_join(sk, greqs.gsr_interface,
  						 &psin6->sin6_addr);
c9e3e8b69   David L Stevens   [IPV6]: multicast...
693
694
  			/* prior join w/ different source is ok */
  			if (retv && retv != -EADDRINUSE)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
695
696
697
  				break;
  			omode = MCAST_INCLUDE;
  			add = 1;
c9e3e8b69   David L Stevens   [IPV6]: multicast...
698
  		} else /* MCAST_LEAVE_SOURCE_GROUP */ {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
699
700
701
702
703
704
705
706
  			omode = MCAST_INCLUDE;
  			add = 0;
  		}
  		retv = ip6_mc_source(add, omode, sk, &greqs);
  		break;
  	}
  	case MCAST_MSFILTER:
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
707
708
709
710
711
712
713
714
  		struct group_filter *gsf;
  
  		if (optlen < GROUP_FILTER_SIZE(0))
  			goto e_inval;
  		if (optlen > sysctl_optmem_max) {
  			retv = -ENOBUFS;
  			break;
  		}
43727da90   Al Viro   do_ipv6_setsockop...
715
716
717
  		gsf = memdup_user(optval, optlen);
  		if (IS_ERR(gsf)) {
  			retv = PTR_ERR(gsf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
  			break;
  		}
  		/* numsrc >= (4G-140)/128 overflow in 32 bits */
  		if (gsf->gf_numsrc >= 0x1ffffffU ||
  		    gsf->gf_numsrc > sysctl_mld_max_msf) {
  			kfree(gsf);
  			retv = -ENOBUFS;
  			break;
  		}
  		if (GROUP_FILTER_SIZE(gsf->gf_numsrc) > optlen) {
  			kfree(gsf);
  			retv = -EINVAL;
  			break;
  		}
  		retv = ip6_mc_msfilter(sk, gsf);
  		kfree(gsf);
  
  		break;
  	}
  	case IPV6_ROUTER_ALERT:
b2a9d7c2f   YOSHIFUJI Hideaki   [IPV6]: Check len...
738
739
  		if (optlen < sizeof(int))
  			goto e_inval;
725a8ff04   Denis V. Lunev   ipv6: remove unus...
740
  		retv = ip6_ra_control(sk, val);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
741
742
  		break;
  	case IPV6_MTU_DISCOVER:
b2a9d7c2f   YOSHIFUJI Hideaki   [IPV6]: Check len...
743
744
  		if (optlen < sizeof(int))
  			goto e_inval;
0b95227a7   Hannes Frederic Sowa   ipv6: yet another...
745
  		if (val < IPV6_PMTUDISC_DONT || val > IPV6_PMTUDISC_OMIT)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
746
747
748
749
750
  			goto e_inval;
  		np->pmtudisc = val;
  		retv = 0;
  		break;
  	case IPV6_MTU:
b2a9d7c2f   YOSHIFUJI Hideaki   [IPV6]: Check len...
751
752
  		if (optlen < sizeof(int))
  			goto e_inval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
753
754
755
756
757
758
  		if (val && val < IPV6_MIN_MTU)
  			goto e_inval;
  		np->frag_size = val;
  		retv = 0;
  		break;
  	case IPV6_RECVERR:
b2a9d7c2f   YOSHIFUJI Hideaki   [IPV6]: Check len...
759
760
  		if (optlen < sizeof(int))
  			goto e_inval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
761
762
763
764
765
766
  		np->recverr = valbool;
  		if (!val)
  			skb_queue_purge(&sk->sk_error_queue);
  		retv = 0;
  		break;
  	case IPV6_FLOWINFO_SEND:
b2a9d7c2f   YOSHIFUJI Hideaki   [IPV6]: Check len...
767
768
  		if (optlen < sizeof(int))
  			goto e_inval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
769
770
771
772
773
774
775
776
  		np->sndflow = valbool;
  		retv = 0;
  		break;
  	case IPV6_FLOWLABEL_MGR:
  		retv = ipv6_flowlabel_opt(sk, optval, optlen);
  		break;
  	case IPV6_IPSEC_POLICY:
  	case IPV6_XFRM_POLICY:
6fc0b4a7a   Herbert Xu   [IPSEC]: Restrict...
777
  		retv = -EPERM;
af31f412c   Eric W. Biederman   net: Allow userns...
778
  		if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
6fc0b4a7a   Herbert Xu   [IPSEC]: Restrict...
779
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
780
781
  		retv = xfrm_user_policy(sk, optname, optval, optlen);
  		break;
7cbca67c0   YOSHIFUJI Hideaki   [IPV6]: Support S...
782
783
784
785
  	case IPV6_ADDR_PREFERENCES:
  	    {
  		unsigned int pref = 0;
  		unsigned int prefmask = ~0;
b2a9d7c2f   YOSHIFUJI Hideaki   [IPV6]: Check len...
786
787
  		if (optlen < sizeof(int))
  			goto e_inval;
7cbca67c0   YOSHIFUJI Hideaki   [IPV6]: Support S...
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
  		retv = -EINVAL;
  
  		/* check PUBLIC/TMP/PUBTMP_DEFAULT conflicts */
  		switch (val & (IPV6_PREFER_SRC_PUBLIC|
  			       IPV6_PREFER_SRC_TMP|
  			       IPV6_PREFER_SRC_PUBTMP_DEFAULT)) {
  		case IPV6_PREFER_SRC_PUBLIC:
  			pref |= IPV6_PREFER_SRC_PUBLIC;
  			break;
  		case IPV6_PREFER_SRC_TMP:
  			pref |= IPV6_PREFER_SRC_TMP;
  			break;
  		case IPV6_PREFER_SRC_PUBTMP_DEFAULT:
  			break;
  		case 0:
  			goto pref_skip_pubtmp;
  		default:
  			goto e_inval;
  		}
  
  		prefmask &= ~(IPV6_PREFER_SRC_PUBLIC|
  			      IPV6_PREFER_SRC_TMP);
  pref_skip_pubtmp:
  
  		/* check HOME/COA conflicts */
  		switch (val & (IPV6_PREFER_SRC_HOME|IPV6_PREFER_SRC_COA)) {
  		case IPV6_PREFER_SRC_HOME:
  			break;
  		case IPV6_PREFER_SRC_COA:
  			pref |= IPV6_PREFER_SRC_COA;
  		case 0:
  			goto pref_skip_coa;
  		default:
  			goto e_inval;
  		}
  
  		prefmask &= ~IPV6_PREFER_SRC_COA;
  pref_skip_coa:
  
  		/* check CGA/NONCGA conflicts */
  		switch (val & (IPV6_PREFER_SRC_CGA|IPV6_PREFER_SRC_NONCGA)) {
  		case IPV6_PREFER_SRC_CGA:
  		case IPV6_PREFER_SRC_NONCGA:
  		case 0:
  			break;
  		default:
  			goto e_inval;
  		}
  
  		np->srcprefs = (np->srcprefs & prefmask) | pref;
  		retv = 0;
  
  		break;
  	    }
e802af9ca   Stephen Hemminger   IPv6: Generic TTL...
842
843
844
845
846
847
  	case IPV6_MINHOPCOUNT:
  		if (optlen < sizeof(int))
  			goto e_inval;
  		if (val < 0 || val > 255)
  			goto e_inval;
  		np->min_hopcount = val;
d4596bad2   Hannes Frederic Sowa   ipv6: setsockopt(...
848
  		retv = 0;
793b14731   Brian Haley   IPv6: data struct...
849
850
851
  		break;
  	case IPV6_DONTFRAG:
  		np->dontfrag = valbool;
e802af9ca   Stephen Hemminger   IPv6: Generic TTL...
852
853
  		retv = 0;
  		break;
cb1ce2ef3   Tom Herbert   ipv6: Implement a...
854
855
  	case IPV6_AUTOFLOWLABEL:
  		np->autoflowlabel = valbool;
6d0317869   Shaohua Li   net: reevalulate ...
856
  		np->autoflowlabel_set = 1;
cb1ce2ef3   Tom Herbert   ipv6: Implement a...
857
858
  		retv = 0;
  		break;
0cc0aa614   Willem de Bruijn   ipv6: add IPV6_RE...
859
860
861
862
  	case IPV6_RECVFRAGSIZE:
  		np->rxopt.bits.recvfragsize = valbool;
  		retv = 0;
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
863
  	}
7cbca67c0   YOSHIFUJI Hideaki   [IPV6]: Support S...
864

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
865
  	release_sock(sk);
baf606d9c   Marcelo Ricardo Leitner   ipv4,ipv6: grab r...
866
867
  	if (needs_rtnl)
  		rtnl_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
868

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
869
870
871
872
  	return retv;
  
  e_inval:
  	release_sock(sk);
baf606d9c   Marcelo Ricardo Leitner   ipv4,ipv6: grab r...
873
874
  	if (needs_rtnl)
  		rtnl_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
875
876
  	return -EINVAL;
  }
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
877
  int ipv6_setsockopt(struct sock *sk, int level, int optname,
b7058842c   David S. Miller   net: Make setsock...
878
  		    char __user *optval, unsigned int optlen)
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
879
880
881
882
883
884
885
886
887
888
889
890
891
  {
  	int err;
  
  	if (level == SOL_IP && sk->sk_type != SOCK_RAW)
  		return udp_prot.setsockopt(sk, level, optname, optval, optlen);
  
  	if (level != SOL_IPV6)
  		return -ENOPROTOOPT;
  
  	err = do_ipv6_setsockopt(sk, level, optname, optval, optlen);
  #ifdef CONFIG_NETFILTER
  	/* we need to exclude all possible ENOPROTOOPTs except default case */
  	if (err == -ENOPROTOOPT && optname != IPV6_IPSEC_POLICY &&
516c855cf   Paolo Abeni   netfilter: on soc...
892
893
  			optname != IPV6_XFRM_POLICY)
  		err = nf_setsockopt(sk, PF_INET6, optname, optval, optlen);
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
894
895
896
  #endif
  	return err;
  }
7159039a1   YOSHIFUJI Hideaki   [IPV6]: Decentral...
897
  EXPORT_SYMBOL(ipv6_setsockopt);
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
898
899
900
  
  #ifdef CONFIG_COMPAT
  int compat_ipv6_setsockopt(struct sock *sk, int level, int optname,
b7058842c   David S. Miller   net: Make setsock...
901
  			   char __user *optval, unsigned int optlen)
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
902
903
904
905
  {
  	int err;
  
  	if (level == SOL_IP && sk->sk_type != SOCK_RAW) {
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
906
907
908
909
  		if (udp_prot.compat_setsockopt != NULL)
  			return udp_prot.compat_setsockopt(sk, level, optname,
  							  optval, optlen);
  		return udp_prot.setsockopt(sk, level, optname, optval, optlen);
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
910
911
912
913
  	}
  
  	if (level != SOL_IPV6)
  		return -ENOPROTOOPT;
dae502954   David L Stevens   ipv4/ipv6 compat:...
914
915
916
  	if (optname >= MCAST_JOIN_GROUP && optname <= MCAST_MSFILTER)
  		return compat_mc_setsockopt(sk, level, optname, optval, optlen,
  			ipv6_setsockopt);
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
917
918
919
920
  	err = do_ipv6_setsockopt(sk, level, optname, optval, optlen);
  #ifdef CONFIG_NETFILTER
  	/* we need to exclude all possible ENOPROTOOPTs except default case */
  	if (err == -ENOPROTOOPT && optname != IPV6_IPSEC_POLICY &&
516c855cf   Paolo Abeni   netfilter: on soc...
921
922
923
  	    optname != IPV6_XFRM_POLICY)
  		err = compat_nf_setsockopt(sk, PF_INET6, optname, optval,
  					   optlen);
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
924
925
926
  #endif
  	return err;
  }
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
927
  EXPORT_SYMBOL(compat_ipv6_setsockopt);
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
928
  #endif
286930797   David S. Miller   [IPV6]: Handle np...
929
  static int ipv6_getsockopt_sticky(struct sock *sk, struct ipv6_txoptions *opt,
4c6510a73   YOSHIFUJI Hideaki   [IPV6]: Return co...
930
  				  int optname, char __user *optval, int len)
333fad536   YOSHIFUJI Hideaki   [IPV6]: Support s...
931
  {
286930797   David S. Miller   [IPV6]: Handle np...
932
  	struct ipv6_opt_hdr *hdr;
4c6510a73   YOSHIFUJI Hideaki   [IPV6]: Return co...
933
934
  	if (!opt)
  		return 0;
67ba4152e   Ian Morris   ipv6: White-space...
935
  	switch (optname) {
4c6510a73   YOSHIFUJI Hideaki   [IPV6]: Return co...
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
  	case IPV6_HOPOPTS:
  		hdr = opt->hopopt;
  		break;
  	case IPV6_RTHDRDSTOPTS:
  		hdr = opt->dst0opt;
  		break;
  	case IPV6_RTHDR:
  		hdr = (struct ipv6_opt_hdr *)opt->srcrt;
  		break;
  	case IPV6_DSTOPTS:
  		hdr = opt->dst1opt;
  		break;
  	default:
  		return -EINVAL;	/* should not happen */
  	}
  
  	if (!hdr)
333fad536   YOSHIFUJI Hideaki   [IPV6]: Support s...
953
  		return 0;
286930797   David S. Miller   [IPV6]: Handle np...
954

d2b02ed94   Chris Wright   [IPV6] fix ipv6_g...
955
  	len = min_t(unsigned int, len, ipv6_optlen(hdr));
660adc6e6   Ilpo Järvinen   [IPv6]: Invalid s...
956
  	if (copy_to_user(optval, hdr, len))
333fad536   YOSHIFUJI Hideaki   [IPV6]: Support s...
957
  		return -EFAULT;
95b496b66   Yang Hongyang   [IPV6]: Fix the d...
958
  	return len;
333fad536   YOSHIFUJI Hideaki   [IPV6]: Support s...
959
  }
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
960
  static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
95c961747   Eric Dumazet   net: cleanup unsi...
961
  		    char __user *optval, int __user *optlen, unsigned int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
962
963
964
965
  {
  	struct ipv6_pinfo *np = inet6_sk(sk);
  	int len;
  	int val;
7bc570c8b   YOSHIFUJI Hideaki   [IPV6] MROUTE: Su...
966
967
  	if (ip6_mroute_opt(optname))
  		return ip6_mroute_getsockopt(sk, optname, optval, optlen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
968
969
970
971
972
  	if (get_user(len, optlen))
  		return -EFAULT;
  	switch (optname) {
  	case IPV6_ADDRFORM:
  		if (sk->sk_protocol != IPPROTO_UDP &&
ba4e58eca   Gerrit Renker   [NET]: Supporting...
973
  		    sk->sk_protocol != IPPROTO_UDPLITE &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
974
  		    sk->sk_protocol != IPPROTO_TCP)
1717699cd   YOSHIFUJI Hideaki   ipv6: Fail with a...
975
  			return -ENOPROTOOPT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
976
977
978
979
980
981
982
983
984
985
986
987
988
  		if (sk->sk_state != TCP_ESTABLISHED)
  			return -ENOTCONN;
  		val = sk->sk_family;
  		break;
  	case MCAST_MSFILTER:
  	{
  		struct group_filter gsf;
  		int err;
  
  		if (len < GROUP_FILTER_SIZE(0))
  			return -EINVAL;
  		if (copy_from_user(&gsf, optval, GROUP_FILTER_SIZE(0)))
  			return -EFAULT;
20c61fbd8   YOSHIFUJI Hideaki   ipv6 mcast: Check...
989
990
  		if (gsf.gf_group.ss_family != AF_INET6)
  			return -EADDRNOTAVAIL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
991
992
993
994
995
996
  		lock_sock(sk);
  		err = ip6_mc_msfget(sk, &gsf,
  			(struct group_filter __user *)optval, optlen);
  		release_sock(sk);
  		return err;
  	}
333fad536   YOSHIFUJI Hideaki   [IPV6]: Support s...
997
  	case IPV6_2292PKTOPTIONS:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
998
999
1000
1001
1002
1003
1004
1005
1006
  	{
  		struct msghdr msg;
  		struct sk_buff *skb;
  
  		if (sk->sk_type != SOCK_STREAM)
  			return -ENOPROTOOPT;
  
  		msg.msg_control = optval;
  		msg.msg_controllen = len;
98e77438a   Daniel Baluta   ipv6: Fix ipv6_ge...
1007
  		msg.msg_flags = flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1008
1009
1010
1011
  
  		lock_sock(sk);
  		skb = np->pktoptions;
  		if (skb)
4b261c75a   Hannes Frederic Sowa   ipv6: make IPV6_R...
1012
  			ip6_datagram_recv_ctl(sk, &msg, skb);
1dc7b90f7   Eric Dumazet   ipv6: tcp: fix ra...
1013
1014
  		release_sock(sk);
  		if (!skb) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1015
1016
  			if (np->rxopt.bits.rxinfo) {
  				struct in6_pktinfo src_info;
f250dcdac   Yang Hongyang   ipv6: fix the ret...
1017
1018
  				src_info.ipi6_ifindex = np->mcast_oif ? np->mcast_oif :
  					np->sticky_pktinfo.ipi6_ifindex;
efe4208f4   Eric Dumazet   ipv6: make lookup...
1019
  				src_info.ipi6_addr = np->mcast_oif ? sk->sk_v6_daddr : np->sticky_pktinfo.ipi6_addr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1020
1021
1022
1023
1024
1025
  				put_cmsg(&msg, SOL_IPV6, IPV6_PKTINFO, sizeof(src_info), &src_info);
  			}
  			if (np->rxopt.bits.rxhlim) {
  				int hlim = np->mcast_hops;
  				put_cmsg(&msg, SOL_IPV6, IPV6_HOPLIMIT, sizeof(hlim), &hlim);
  			}
4c507d289   Jiri Benc   net: implement IP...
1026
  			if (np->rxopt.bits.rxtclass) {
d76ed22b2   Li RongQing   ipv6: move IPV6_T...
1027
  				int tclass = (int)ip6_tclass(np->rcv_flowinfo);
4c507d289   Jiri Benc   net: implement IP...
1028
1029
  				put_cmsg(&msg, SOL_IPV6, IPV6_TCLASS, sizeof(tclass), &tclass);
  			}
333fad536   YOSHIFUJI Hideaki   [IPV6]: Support s...
1030
1031
  			if (np->rxopt.bits.rxoinfo) {
  				struct in6_pktinfo src_info;
f250dcdac   Yang Hongyang   ipv6: fix the ret...
1032
1033
  				src_info.ipi6_ifindex = np->mcast_oif ? np->mcast_oif :
  					np->sticky_pktinfo.ipi6_ifindex;
efe4208f4   Eric Dumazet   ipv6: make lookup...
1034
1035
  				src_info.ipi6_addr = np->mcast_oif ? sk->sk_v6_daddr :
  								     np->sticky_pktinfo.ipi6_addr;
333fad536   YOSHIFUJI Hideaki   [IPV6]: Support s...
1036
1037
1038
1039
1040
1041
  				put_cmsg(&msg, SOL_IPV6, IPV6_2292PKTINFO, sizeof(src_info), &src_info);
  			}
  			if (np->rxopt.bits.rxohlim) {
  				int hlim = np->mcast_hops;
  				put_cmsg(&msg, SOL_IPV6, IPV6_2292HOPLIMIT, sizeof(hlim), &hlim);
  			}
1397ed35f   Florent Fourcot   ipv6: add flowinf...
1042
  			if (np->rxopt.bits.rxflow) {
685360536   Florent Fourcot   ipv6: fix incorre...
1043
  				__be32 flowinfo = np->rcv_flowinfo;
1397ed35f   Florent Fourcot   ipv6: add flowinf...
1044
1045
  				put_cmsg(&msg, SOL_IPV6, IPV6_FLOWINFO, sizeof(flowinfo), &flowinfo);
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1046
1047
1048
1049
1050
1051
1052
  		}
  		len -= msg.msg_controllen;
  		return put_user(len, optlen);
  	}
  	case IPV6_MTU:
  	{
  		struct dst_entry *dst;
b6c6712a4   Eric Dumazet   net: sk_dst_cache...
1053

1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
1054
  		val = 0;
b6c6712a4   Eric Dumazet   net: sk_dst_cache...
1055
1056
1057
  		rcu_read_lock();
  		dst = __sk_dst_get(sk);
  		if (dst)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1058
  			val = dst_mtu(dst);
b6c6712a4   Eric Dumazet   net: sk_dst_cache...
1059
  		rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1060
1061
1062
1063
1064
1065
  		if (!val)
  			return -ENOTCONN;
  		break;
  	}
  
  	case IPV6_V6ONLY:
9fe516ba3   Eric Dumazet   inet: move ipv6on...
1066
  		val = sk->sk_ipv6only;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1067
  		break;
333fad536   YOSHIFUJI Hideaki   [IPV6]: Support s...
1068
  	case IPV6_RECVPKTINFO:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1069
1070
  		val = np->rxopt.bits.rxinfo;
  		break;
333fad536   YOSHIFUJI Hideaki   [IPV6]: Support s...
1071
1072
1073
1074
1075
  	case IPV6_2292PKTINFO:
  		val = np->rxopt.bits.rxoinfo;
  		break;
  
  	case IPV6_RECVHOPLIMIT:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1076
1077
  		val = np->rxopt.bits.rxhlim;
  		break;
333fad536   YOSHIFUJI Hideaki   [IPV6]: Support s...
1078
1079
1080
1081
1082
  	case IPV6_2292HOPLIMIT:
  		val = np->rxopt.bits.rxohlim;
  		break;
  
  	case IPV6_RECVRTHDR:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1083
1084
  		val = np->rxopt.bits.srcrt;
  		break;
333fad536   YOSHIFUJI Hideaki   [IPV6]: Support s...
1085
1086
1087
  	case IPV6_2292RTHDR:
  		val = np->rxopt.bits.osrcrt;
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1088
  	case IPV6_HOPOPTS:
333fad536   YOSHIFUJI Hideaki   [IPV6]: Support s...
1089
1090
1091
1092
  	case IPV6_RTHDRDSTOPTS:
  	case IPV6_RTHDR:
  	case IPV6_DSTOPTS:
  	{
45f6fad84   Eric Dumazet   ipv6: add complet...
1093
  		struct ipv6_txoptions *opt;
333fad536   YOSHIFUJI Hideaki   [IPV6]: Support s...
1094
1095
  
  		lock_sock(sk);
1e1d04e67   Hannes Frederic Sowa   net: introduce lo...
1096
1097
  		opt = rcu_dereference_protected(np->opt,
  						lockdep_sock_is_held(sk));
45f6fad84   Eric Dumazet   ipv6: add complet...
1098
  		len = ipv6_getsockopt_sticky(sk, opt, optname, optval, len);
333fad536   YOSHIFUJI Hideaki   [IPV6]: Support s...
1099
  		release_sock(sk);
05335c222   Yang Hongyang   [IPV6]: Fix the r...
1100
1101
1102
  		/* check if ipv6_getsockopt_sticky() returns err code */
  		if (len < 0)
  			return len;
333fad536   YOSHIFUJI Hideaki   [IPV6]: Support s...
1103
1104
1105
1106
  		return put_user(len, optlen);
  	}
  
  	case IPV6_RECVHOPOPTS:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1107
1108
  		val = np->rxopt.bits.hopopts;
  		break;
333fad536   YOSHIFUJI Hideaki   [IPV6]: Support s...
1109
1110
1111
1112
1113
  	case IPV6_2292HOPOPTS:
  		val = np->rxopt.bits.ohopopts;
  		break;
  
  	case IPV6_RECVDSTOPTS:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1114
1115
  		val = np->rxopt.bits.dstopts;
  		break;
333fad536   YOSHIFUJI Hideaki   [IPV6]: Support s...
1116
1117
1118
  	case IPV6_2292DSTOPTS:
  		val = np->rxopt.bits.odstopts;
  		break;
41a1f8ea4   YOSHIFUJI Hideaki   [IPV6]: Support I...
1119
1120
1121
1122
1123
1124
1125
  	case IPV6_TCLASS:
  		val = np->tclass;
  		break;
  
  	case IPV6_RECVTCLASS:
  		val = np->rxopt.bits.rxtclass;
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1126
1127
1128
  	case IPV6_FLOWINFO:
  		val = np->rxopt.bits.rxflow;
  		break;
793b14731   Brian Haley   IPv6: data struct...
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
  	case IPV6_RECVPATHMTU:
  		val = np->rxopt.bits.rxpmtu;
  		break;
  
  	case IPV6_PATHMTU:
  	{
  		struct dst_entry *dst;
  		struct ip6_mtuinfo mtuinfo;
  
  		if (len < sizeof(mtuinfo))
  			return -EINVAL;
  
  		len = sizeof(mtuinfo);
  		memset(&mtuinfo, 0, sizeof(mtuinfo));
  
  		rcu_read_lock();
  		dst = __sk_dst_get(sk);
  		if (dst)
  			mtuinfo.ip6m_mtu = dst_mtu(dst);
  		rcu_read_unlock();
  		if (!mtuinfo.ip6m_mtu)
  			return -ENOTCONN;
  
  		if (put_user(len, optlen))
  			return -EFAULT;
  		if (copy_to_user(optval, &mtuinfo, len))
  			return -EFAULT;
  
  		return 0;
793b14731   Brian Haley   IPv6: data struct...
1158
  	}
6c4686228   Balazs Scheidler   tproxy: added tpr...
1159
1160
1161
1162
1163
1164
1165
  	case IPV6_TRANSPARENT:
  		val = inet_sk(sk)->transparent;
  		break;
  
  	case IPV6_RECVORIGDSTADDR:
  		val = np->rxopt.bits.rxorigdstaddr;
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1166
  	case IPV6_UNICAST_HOPS:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1167
  	case IPV6_MULTICAST_HOPS:
befffe901   Brian Haley   [IPV6]: Fix IPV6_...
1168
1169
1170
1171
1172
1173
1174
  	{
  		struct dst_entry *dst;
  
  		if (optname == IPV6_UNICAST_HOPS)
  			val = np->hop_limit;
  		else
  			val = np->mcast_hops;
b6c6712a4   Eric Dumazet   net: sk_dst_cache...
1175
1176
1177
1178
  		if (val < 0) {
  			rcu_read_lock();
  			dst = __sk_dst_get(sk);
  			if (dst)
6b75d0908   YOSHIFUJI Hideaki   [IPV6]: Optimize ...
1179
  				val = ip6_dst_hoplimit(dst);
b6c6712a4   Eric Dumazet   net: sk_dst_cache...
1180
  			rcu_read_unlock();
befffe901   Brian Haley   [IPV6]: Fix IPV6_...
1181
  		}
b6c6712a4   Eric Dumazet   net: sk_dst_cache...
1182

befffe901   Brian Haley   [IPV6]: Fix IPV6_...
1183
  		if (val < 0)
53b7997fd   YOSHIFUJI Hideaki   ipv6 netns: Make ...
1184
  			val = sock_net(sk)->ipv6.devconf_all->hop_limit;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1185
  		break;
befffe901   Brian Haley   [IPV6]: Fix IPV6_...
1186
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1187
1188
1189
1190
1191
1192
1193
1194
  
  	case IPV6_MULTICAST_LOOP:
  		val = np->mc_loop;
  		break;
  
  	case IPV6_MULTICAST_IF:
  		val = np->mcast_oif;
  		break;
c4062dfc4   Erich E. Hoover   ipv6: Implement I...
1195
1196
1197
  	case IPV6_UNICAST_IF:
  		val = (__force int)htonl((__u32) np->ucast_oif);
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
  	case IPV6_MTU_DISCOVER:
  		val = np->pmtudisc;
  		break;
  
  	case IPV6_RECVERR:
  		val = np->recverr;
  		break;
  
  	case IPV6_FLOWINFO_SEND:
  		val = np->sndflow;
  		break;
3fdfa5ff5   Florent Fourcot   ipv6: enable IPV6...
1209
1210
1211
  	case IPV6_FLOWLABEL_MGR:
  	{
  		struct in6_flowlabel_req freq;
46e5f4017   Florent Fourcot   ipv6: add a flag ...
1212
  		int flags;
3fdfa5ff5   Florent Fourcot   ipv6: enable IPV6...
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
  
  		if (len < sizeof(freq))
  			return -EINVAL;
  
  		if (copy_from_user(&freq, optval, sizeof(freq)))
  			return -EFAULT;
  
  		if (freq.flr_action != IPV6_FL_A_GET)
  			return -EINVAL;
  
  		len = sizeof(freq);
46e5f4017   Florent Fourcot   ipv6: add a flag ...
1224
  		flags = freq.flr_flags;
3fdfa5ff5   Florent Fourcot   ipv6: enable IPV6...
1225
  		memset(&freq, 0, sizeof(freq));
46e5f4017   Florent Fourcot   ipv6: add a flag ...
1226
  		val = ipv6_flowlabel_opt_get(sk, &freq, flags);
3fdfa5ff5   Florent Fourcot   ipv6: enable IPV6...
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
  		if (val < 0)
  			return val;
  
  		if (put_user(len, optlen))
  			return -EFAULT;
  		if (copy_to_user(optval, &freq, len))
  			return -EFAULT;
  
  		return 0;
  	}
7cbca67c0   YOSHIFUJI Hideaki   [IPV6]: Support S...
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
  	case IPV6_ADDR_PREFERENCES:
  		val = 0;
  
  		if (np->srcprefs & IPV6_PREFER_SRC_TMP)
  			val |= IPV6_PREFER_SRC_TMP;
  		else if (np->srcprefs & IPV6_PREFER_SRC_PUBLIC)
  			val |= IPV6_PREFER_SRC_PUBLIC;
  		else {
  			/* XXX: should we return system default? */
  			val |= IPV6_PREFER_SRC_PUBTMP_DEFAULT;
  		}
  
  		if (np->srcprefs & IPV6_PREFER_SRC_COA)
  			val |= IPV6_PREFER_SRC_COA;
  		else
  			val |= IPV6_PREFER_SRC_HOME;
  		break;
e802af9ca   Stephen Hemminger   IPv6: Generic TTL...
1254
1255
1256
1257
  
  	case IPV6_MINHOPCOUNT:
  		val = np->min_hopcount;
  		break;
793b14731   Brian Haley   IPv6: data struct...
1258
1259
1260
1261
  
  	case IPV6_DONTFRAG:
  		val = np->dontfrag;
  		break;
7cbca67c0   YOSHIFUJI Hideaki   [IPV6]: Support S...
1262

cb1ce2ef3   Tom Herbert   ipv6: Implement a...
1263
  	case IPV6_AUTOFLOWLABEL:
2295b3dd5   Ben Hutchings   ipv6: Fix getsock...
1264
  		val = ip6_autoflowlabel(sock_net(sk), np);
cb1ce2ef3   Tom Herbert   ipv6: Implement a...
1265
  		break;
0cc0aa614   Willem de Bruijn   ipv6: add IPV6_RE...
1266
1267
1268
  	case IPV6_RECVFRAGSIZE:
  		val = np->rxopt.bits.recvfragsize;
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1269
  	default:
cf6fc4a92   Wei Yongjun   [IPV6]: Fix the r...
1270
  		return -ENOPROTOOPT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1271
1272
  	}
  	len = min_t(unsigned int, sizeof(int), len);
67ba4152e   Ian Morris   ipv6: White-space...
1273
  	if (put_user(len, optlen))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1274
  		return -EFAULT;
67ba4152e   Ian Morris   ipv6: White-space...
1275
  	if (copy_to_user(optval, &val, len))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1276
1277
1278
  		return -EFAULT;
  	return 0;
  }
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1279
1280
1281
1282
1283
1284
1285
  int ipv6_getsockopt(struct sock *sk, int level, int optname,
  		    char __user *optval, int __user *optlen)
  {
  	int err;
  
  	if (level == SOL_IP && sk->sk_type != SOCK_RAW)
  		return udp_prot.getsockopt(sk, level, optname, optval, optlen);
67ba4152e   Ian Morris   ipv6: White-space...
1286
  	if (level != SOL_IPV6)
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1287
  		return -ENOPROTOOPT;
98e77438a   Daniel Baluta   ipv6: Fix ipv6_ge...
1288
  	err = do_ipv6_getsockopt(sk, level, optname, optval, optlen, 0);
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1289
  #ifdef CONFIG_NETFILTER
cf6fc4a92   Wei Yongjun   [IPV6]: Fix the r...
1290
1291
  	/* we need to exclude all possible ENOPROTOOPTs except default case */
  	if (err == -ENOPROTOOPT && optname != IPV6_2292PKTOPTIONS) {
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1292
1293
1294
1295
  		int len;
  
  		if (get_user(len, optlen))
  			return -EFAULT;
485595768   Paolo Abeni   netfilter: drop o...
1296
  		err = nf_getsockopt(sk, PF_INET6, optname, optval, &len);
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1297
1298
1299
1300
1301
1302
  		if (err >= 0)
  			err = put_user(len, optlen);
  	}
  #endif
  	return err;
  }
7159039a1   YOSHIFUJI Hideaki   [IPV6]: Decentral...
1303
  EXPORT_SYMBOL(ipv6_getsockopt);
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1304
1305
  #ifdef CONFIG_COMPAT
  int compat_ipv6_getsockopt(struct sock *sk, int level, int optname,
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
1306
  			   char __user *optval, int __user *optlen)
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1307
1308
1309
1310
  {
  	int err;
  
  	if (level == SOL_IP && sk->sk_type != SOCK_RAW) {
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
1311
1312
1313
1314
  		if (udp_prot.compat_getsockopt != NULL)
  			return udp_prot.compat_getsockopt(sk, level, optname,
  							  optval, optlen);
  		return udp_prot.getsockopt(sk, level, optname, optval, optlen);
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1315
  	}
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
1316
  	if (level != SOL_IPV6)
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1317
  		return -ENOPROTOOPT;
809917903   Pavel Emelyanov   ipv6: Compilation...
1318
1319
1320
  	if (optname == MCAST_MSFILTER)
  		return compat_mc_getsockopt(sk, level, optname, optval, optlen,
  			ipv6_getsockopt);
98e77438a   Daniel Baluta   ipv6: Fix ipv6_ge...
1321
1322
  	err = do_ipv6_getsockopt(sk, level, optname, optval, optlen,
  				 MSG_CMSG_COMPAT);
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1323
  #ifdef CONFIG_NETFILTER
cf6fc4a92   Wei Yongjun   [IPV6]: Fix the r...
1324
1325
  	/* we need to exclude all possible ENOPROTOOPTs except default case */
  	if (err == -ENOPROTOOPT && optname != IPV6_2292PKTOPTIONS) {
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1326
1327
1328
1329
  		int len;
  
  		if (get_user(len, optlen))
  			return -EFAULT;
485595768   Paolo Abeni   netfilter: drop o...
1330
  		err = compat_nf_getsockopt(sk, PF_INET6, optname, optval, &len);
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1331
1332
1333
1334
1335
1336
  		if (err >= 0)
  			err = put_user(len, optlen);
  	}
  #endif
  	return err;
  }
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
1337
  EXPORT_SYMBOL(compat_ipv6_getsockopt);
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1338
  #endif