ipv6_sockglue.c revision 42908c69f61f75dd70e424263ab89ee52040382b
1/*
2 *	IPv6 BSD socket options interface
3 *	Linux INET6 implementation
4 *
5 *	Authors:
6 *	Pedro Roque		<roque@di.fc.ul.pt>
7 *
8 *	Based on linux/net/ipv4/ip_sockglue.c
9 *
10 *	$Id: ipv6_sockglue.c,v 1.41 2002/02/01 22:01:04 davem Exp $
11 *
12 *	This program is free software; you can redistribute it and/or
13 *      modify it under the terms of the GNU General Public License
14 *      as published by the Free Software Foundation; either version
15 *      2 of the License, or (at your option) any later version.
16 *
17 *	FIXME: Make the setsockopt code POSIX compliant: That is
18 *
19 *	o	Truncate getsockopt returns
20 *	o	Return an optlen of the truncated length if need be
21 *
22 *	Changes:
23 *	David L Stevens <dlstevens@us.ibm.com>:
24 *		- added multicast source filtering API for MLDv2
25 */
26
27#include <linux/module.h>
28#include <linux/capability.h>
29#include <linux/errno.h>
30#include <linux/types.h>
31#include <linux/socket.h>
32#include <linux/sockios.h>
33#include <linux/net.h>
34#include <linux/in6.h>
35#include <linux/mroute6.h>
36#include <linux/netdevice.h>
37#include <linux/if_arp.h>
38#include <linux/init.h>
39#include <linux/sysctl.h>
40#include <linux/netfilter.h>
41
42#include <net/sock.h>
43#include <net/snmp.h>
44#include <net/ipv6.h>
45#include <net/ndisc.h>
46#include <net/protocol.h>
47#include <net/transp_v6.h>
48#include <net/ip6_route.h>
49#include <net/addrconf.h>
50#include <net/inet_common.h>
51#include <net/tcp.h>
52#include <net/udp.h>
53#include <net/udplite.h>
54#include <net/xfrm.h>
55#include <net/compat.h>
56
57#include <asm/uaccess.h>
58
59DEFINE_SNMP_STAT(struct ipstats_mib, ipv6_statistics) __read_mostly;
60
61struct ip6_ra_chain *ip6_ra_chain;
62DEFINE_RWLOCK(ip6_ra_lock);
63
64int ip6_ra_control(struct sock *sk, int sel, void (*destructor)(struct sock *))
65{
66	struct ip6_ra_chain *ra, *new_ra, **rap;
67
68	/* RA packet may be delivered ONLY to IPPROTO_RAW socket */
69	if (sk->sk_type != SOCK_RAW || inet_sk(sk)->num != IPPROTO_RAW)
70		return -EINVAL;
71
72	new_ra = (sel>=0) ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL;
73
74	write_lock_bh(&ip6_ra_lock);
75	for (rap = &ip6_ra_chain; (ra=*rap) != NULL; rap = &ra->next) {
76		if (ra->sk == sk) {
77			if (sel>=0) {
78				write_unlock_bh(&ip6_ra_lock);
79				kfree(new_ra);
80				return -EADDRINUSE;
81			}
82
83			*rap = ra->next;
84			write_unlock_bh(&ip6_ra_lock);
85
86			if (ra->destructor)
87				ra->destructor(sk);
88			sock_put(sk);
89			kfree(ra);
90			return 0;
91		}
92	}
93	if (new_ra == NULL) {
94		write_unlock_bh(&ip6_ra_lock);
95		return -ENOBUFS;
96	}
97	new_ra->sk = sk;
98	new_ra->sel = sel;
99	new_ra->destructor = destructor;
100	new_ra->next = ra;
101	*rap = new_ra;
102	sock_hold(sk);
103	write_unlock_bh(&ip6_ra_lock);
104	return 0;
105}
106
107static
108struct ipv6_txoptions *ipv6_update_options(struct sock *sk,
109					   struct ipv6_txoptions *opt)
110{
111	if (inet_sk(sk)->is_icsk) {
112		if (opt &&
113		    !((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE)) &&
114		    inet_sk(sk)->daddr != LOOPBACK4_IPV6) {
115			struct inet_connection_sock *icsk = inet_csk(sk);
116			icsk->icsk_ext_hdr_len = opt->opt_flen + opt->opt_nflen;
117			icsk->icsk_sync_mss(sk, icsk->icsk_pmtu_cookie);
118		}
119		opt = xchg(&inet6_sk(sk)->opt, opt);
120	} else {
121		write_lock(&sk->sk_dst_lock);
122		opt = xchg(&inet6_sk(sk)->opt, opt);
123		write_unlock(&sk->sk_dst_lock);
124	}
125	sk_dst_reset(sk);
126
127	return opt;
128}
129
130static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
131		    char __user *optval, int optlen)
132{
133	struct ipv6_pinfo *np = inet6_sk(sk);
134	struct net *net = sock_net(sk);
135	int val, valbool;
136	int retv = -ENOPROTOOPT;
137
138	if (optval == NULL)
139		val=0;
140	else {
141		if (optlen >= sizeof(int)) {
142			if (get_user(val, (int __user *) optval))
143				return -EFAULT;
144		} else
145			val = 0;
146	}
147
148	valbool = (val!=0);
149
150	if (ip6_mroute_opt(optname))
151		return ip6_mroute_setsockopt(sk, optname, optval, optlen);
152
153	lock_sock(sk);
154
155	switch (optname) {
156
157	case IPV6_ADDRFORM:
158		if (optlen < sizeof(int))
159			goto e_inval;
160		if (val == PF_INET) {
161			struct ipv6_txoptions *opt;
162			struct sk_buff *pktopt;
163
164			if (sk->sk_protocol != IPPROTO_UDP &&
165			    sk->sk_protocol != IPPROTO_UDPLITE &&
166			    sk->sk_protocol != IPPROTO_TCP)
167				break;
168
169			if (sk->sk_state != TCP_ESTABLISHED) {
170				retv = -ENOTCONN;
171				break;
172			}
173
174			if (ipv6_only_sock(sk) ||
175			    !ipv6_addr_v4mapped(&np->daddr)) {
176				retv = -EADDRNOTAVAIL;
177				break;
178			}
179
180			fl6_free_socklist(sk);
181			ipv6_sock_mc_close(sk);
182
183			/*
184			 * Sock is moving from IPv6 to IPv4 (sk_prot), so
185			 * remove it from the refcnt debug socks count in the
186			 * original family...
187			 */
188			sk_refcnt_debug_dec(sk);
189
190			if (sk->sk_protocol == IPPROTO_TCP) {
191				struct inet_connection_sock *icsk = inet_csk(sk);
192				local_bh_disable();
193				sock_prot_inuse_add(net, sk->sk_prot, -1);
194				sock_prot_inuse_add(net, &tcp_prot, 1);
195				local_bh_enable();
196				sk->sk_prot = &tcp_prot;
197				icsk->icsk_af_ops = &ipv4_specific;
198				sk->sk_socket->ops = &inet_stream_ops;
199				sk->sk_family = PF_INET;
200				tcp_sync_mss(sk, icsk->icsk_pmtu_cookie);
201			} else {
202				struct proto *prot = &udp_prot;
203
204				if (sk->sk_protocol == IPPROTO_UDPLITE)
205					prot = &udplite_prot;
206				local_bh_disable();
207				sock_prot_inuse_add(net, sk->sk_prot, -1);
208				sock_prot_inuse_add(net, prot, 1);
209				local_bh_enable();
210				sk->sk_prot = prot;
211				sk->sk_socket->ops = &inet_dgram_ops;
212				sk->sk_family = PF_INET;
213			}
214			opt = xchg(&np->opt, NULL);
215			if (opt)
216				sock_kfree_s(sk, opt, opt->tot_len);
217			pktopt = xchg(&np->pktoptions, NULL);
218			if (pktopt)
219				kfree_skb(pktopt);
220
221			sk->sk_destruct = inet_sock_destruct;
222			/*
223			 * ... and add it to the refcnt debug socks count
224			 * in the new family. -acme
225			 */
226			sk_refcnt_debug_inc(sk);
227			module_put(THIS_MODULE);
228			retv = 0;
229			break;
230		}
231		goto e_inval;
232
233	case IPV6_V6ONLY:
234		if (optlen < sizeof(int) ||
235		    inet_sk(sk)->num)
236			goto e_inval;
237		np->ipv6only = valbool;
238		retv = 0;
239		break;
240
241	case IPV6_RECVPKTINFO:
242		if (optlen < sizeof(int))
243			goto e_inval;
244		np->rxopt.bits.rxinfo = valbool;
245		retv = 0;
246		break;
247
248	case IPV6_2292PKTINFO:
249		if (optlen < sizeof(int))
250			goto e_inval;
251		np->rxopt.bits.rxoinfo = valbool;
252		retv = 0;
253		break;
254
255	case IPV6_RECVHOPLIMIT:
256		if (optlen < sizeof(int))
257			goto e_inval;
258		np->rxopt.bits.rxhlim = valbool;
259		retv = 0;
260		break;
261
262	case IPV6_2292HOPLIMIT:
263		if (optlen < sizeof(int))
264			goto e_inval;
265		np->rxopt.bits.rxohlim = valbool;
266		retv = 0;
267		break;
268
269	case IPV6_RECVRTHDR:
270		if (optlen < sizeof(int))
271			goto e_inval;
272		np->rxopt.bits.srcrt = valbool;
273		retv = 0;
274		break;
275
276	case IPV6_2292RTHDR:
277		if (optlen < sizeof(int))
278			goto e_inval;
279		np->rxopt.bits.osrcrt = valbool;
280		retv = 0;
281		break;
282
283	case IPV6_RECVHOPOPTS:
284		if (optlen < sizeof(int))
285			goto e_inval;
286		np->rxopt.bits.hopopts = valbool;
287		retv = 0;
288		break;
289
290	case IPV6_2292HOPOPTS:
291		if (optlen < sizeof(int))
292			goto e_inval;
293		np->rxopt.bits.ohopopts = valbool;
294		retv = 0;
295		break;
296
297	case IPV6_RECVDSTOPTS:
298		if (optlen < sizeof(int))
299			goto e_inval;
300		np->rxopt.bits.dstopts = valbool;
301		retv = 0;
302		break;
303
304	case IPV6_2292DSTOPTS:
305		if (optlen < sizeof(int))
306			goto e_inval;
307		np->rxopt.bits.odstopts = valbool;
308		retv = 0;
309		break;
310
311	case IPV6_TCLASS:
312		if (optlen < sizeof(int))
313			goto e_inval;
314		if (val < -1 || val > 0xff)
315			goto e_inval;
316		np->tclass = val;
317		retv = 0;
318		break;
319
320	case IPV6_RECVTCLASS:
321		if (optlen < sizeof(int))
322			goto e_inval;
323		np->rxopt.bits.rxtclass = valbool;
324		retv = 0;
325		break;
326
327	case IPV6_FLOWINFO:
328		if (optlen < sizeof(int))
329			goto e_inval;
330		np->rxopt.bits.rxflow = valbool;
331		retv = 0;
332		break;
333
334	case IPV6_HOPOPTS:
335	case IPV6_RTHDRDSTOPTS:
336	case IPV6_RTHDR:
337	case IPV6_DSTOPTS:
338	{
339		struct ipv6_txoptions *opt;
340		if (optlen == 0)
341			optval = NULL;
342
343		/* hop-by-hop / destination options are privileged option */
344		retv = -EPERM;
345		if (optname != IPV6_RTHDR && !capable(CAP_NET_RAW))
346			break;
347
348		if (optlen < sizeof(struct ipv6_opt_hdr) ||
349		    optlen & 0x7 || optlen > 8 * 255)
350			goto e_inval;
351
352		opt = ipv6_renew_options(sk, np->opt, optname,
353					 (struct ipv6_opt_hdr __user *)optval,
354					 optlen);
355		if (IS_ERR(opt)) {
356			retv = PTR_ERR(opt);
357			break;
358		}
359
360		/* routing header option needs extra check */
361		if (optname == IPV6_RTHDR && opt && opt->srcrt) {
362			struct ipv6_rt_hdr *rthdr = opt->srcrt;
363			switch (rthdr->type) {
364#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
365			case IPV6_SRCRT_TYPE_2:
366				break;
367#endif
368			default:
369				goto sticky_done;
370			}
371
372			if ((rthdr->hdrlen & 1) ||
373			    (rthdr->hdrlen >> 1) != rthdr->segments_left)
374				goto sticky_done;
375		}
376
377		retv = 0;
378		opt = ipv6_update_options(sk, opt);
379sticky_done:
380		if (opt)
381			sock_kfree_s(sk, opt, opt->tot_len);
382		break;
383	}
384
385	case IPV6_2292PKTOPTIONS:
386	{
387		struct ipv6_txoptions *opt = NULL;
388		struct msghdr msg;
389		struct flowi fl;
390		int junk;
391
392		fl.fl6_flowlabel = 0;
393		fl.oif = sk->sk_bound_dev_if;
394
395		if (optlen == 0)
396			goto update;
397
398		/* 1K is probably excessive
399		 * 1K is surely not enough, 2K per standard header is 16K.
400		 */
401		retv = -EINVAL;
402		if (optlen > 64*1024)
403			break;
404
405		opt = sock_kmalloc(sk, sizeof(*opt) + optlen, GFP_KERNEL);
406		retv = -ENOBUFS;
407		if (opt == NULL)
408			break;
409
410		memset(opt, 0, sizeof(*opt));
411		opt->tot_len = sizeof(*opt) + optlen;
412		retv = -EFAULT;
413		if (copy_from_user(opt+1, optval, optlen))
414			goto done;
415
416		msg.msg_controllen = optlen;
417		msg.msg_control = (void*)(opt+1);
418
419		retv = datagram_send_ctl(&msg, &fl, opt, &junk, &junk);
420		if (retv)
421			goto done;
422update:
423		retv = 0;
424		opt = ipv6_update_options(sk, opt);
425done:
426		if (opt)
427			sock_kfree_s(sk, opt, opt->tot_len);
428		break;
429	}
430	case IPV6_UNICAST_HOPS:
431		if (optlen < sizeof(int))
432			goto e_inval;
433		if (val > 255 || val < -1)
434			goto e_inval;
435		np->hop_limit = val;
436		retv = 0;
437		break;
438
439	case IPV6_MULTICAST_HOPS:
440		if (sk->sk_type == SOCK_STREAM)
441			goto e_inval;
442		if (optlen < sizeof(int))
443			goto e_inval;
444		if (val > 255 || val < -1)
445			goto e_inval;
446		np->mcast_hops = val;
447		retv = 0;
448		break;
449
450	case IPV6_MULTICAST_LOOP:
451		if (optlen < sizeof(int))
452			goto e_inval;
453		np->mc_loop = valbool;
454		retv = 0;
455		break;
456
457	case IPV6_MULTICAST_IF:
458		if (sk->sk_type == SOCK_STREAM)
459			goto e_inval;
460		if (optlen < sizeof(int))
461			goto e_inval;
462
463		if (val) {
464			if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != val)
465				goto e_inval;
466
467			if (__dev_get_by_index(net, val) == NULL) {
468				retv = -ENODEV;
469				break;
470			}
471		}
472		np->mcast_oif = val;
473		retv = 0;
474		break;
475	case IPV6_ADD_MEMBERSHIP:
476	case IPV6_DROP_MEMBERSHIP:
477	{
478		struct ipv6_mreq mreq;
479
480		if (optlen < sizeof(struct ipv6_mreq))
481			goto e_inval;
482
483		retv = -EPROTO;
484		if (inet_sk(sk)->is_icsk)
485			break;
486
487		retv = -EFAULT;
488		if (copy_from_user(&mreq, optval, sizeof(struct ipv6_mreq)))
489			break;
490
491		if (optname == IPV6_ADD_MEMBERSHIP)
492			retv = ipv6_sock_mc_join(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_multiaddr);
493		else
494			retv = ipv6_sock_mc_drop(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_multiaddr);
495		break;
496	}
497	case IPV6_JOIN_ANYCAST:
498	case IPV6_LEAVE_ANYCAST:
499	{
500		struct ipv6_mreq mreq;
501
502		if (optlen < sizeof(struct ipv6_mreq))
503			goto e_inval;
504
505		retv = -EFAULT;
506		if (copy_from_user(&mreq, optval, sizeof(struct ipv6_mreq)))
507			break;
508
509		if (optname == IPV6_JOIN_ANYCAST)
510			retv = ipv6_sock_ac_join(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_acaddr);
511		else
512			retv = ipv6_sock_ac_drop(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_acaddr);
513		break;
514	}
515	case MCAST_JOIN_GROUP:
516	case MCAST_LEAVE_GROUP:
517	{
518		struct group_req greq;
519		struct sockaddr_in6 *psin6;
520
521		if (optlen < sizeof(struct group_req))
522			goto e_inval;
523
524		retv = -EFAULT;
525		if (copy_from_user(&greq, optval, sizeof(struct group_req)))
526			break;
527		if (greq.gr_group.ss_family != AF_INET6) {
528			retv = -EADDRNOTAVAIL;
529			break;
530		}
531		psin6 = (struct sockaddr_in6 *)&greq.gr_group;
532		if (optname == MCAST_JOIN_GROUP)
533			retv = ipv6_sock_mc_join(sk, greq.gr_interface,
534				&psin6->sin6_addr);
535		else
536			retv = ipv6_sock_mc_drop(sk, greq.gr_interface,
537				&psin6->sin6_addr);
538		break;
539	}
540	case MCAST_JOIN_SOURCE_GROUP:
541	case MCAST_LEAVE_SOURCE_GROUP:
542	case MCAST_BLOCK_SOURCE:
543	case MCAST_UNBLOCK_SOURCE:
544	{
545		struct group_source_req greqs;
546		int omode, add;
547
548		if (optlen < sizeof(struct group_source_req))
549			goto e_inval;
550		if (copy_from_user(&greqs, optval, sizeof(greqs))) {
551			retv = -EFAULT;
552			break;
553		}
554		if (greqs.gsr_group.ss_family != AF_INET6 ||
555		    greqs.gsr_source.ss_family != AF_INET6) {
556			retv = -EADDRNOTAVAIL;
557			break;
558		}
559		if (optname == MCAST_BLOCK_SOURCE) {
560			omode = MCAST_EXCLUDE;
561			add = 1;
562		} else if (optname == MCAST_UNBLOCK_SOURCE) {
563			omode = MCAST_EXCLUDE;
564			add = 0;
565		} else if (optname == MCAST_JOIN_SOURCE_GROUP) {
566			struct sockaddr_in6 *psin6;
567
568			psin6 = (struct sockaddr_in6 *)&greqs.gsr_group;
569			retv = ipv6_sock_mc_join(sk, greqs.gsr_interface,
570				&psin6->sin6_addr);
571			/* prior join w/ different source is ok */
572			if (retv && retv != -EADDRINUSE)
573				break;
574			omode = MCAST_INCLUDE;
575			add = 1;
576		} else /* MCAST_LEAVE_SOURCE_GROUP */ {
577			omode = MCAST_INCLUDE;
578			add = 0;
579		}
580		retv = ip6_mc_source(add, omode, sk, &greqs);
581		break;
582	}
583	case MCAST_MSFILTER:
584	{
585		extern int sysctl_mld_max_msf;
586		struct group_filter *gsf;
587
588		if (optlen < GROUP_FILTER_SIZE(0))
589			goto e_inval;
590		if (optlen > sysctl_optmem_max) {
591			retv = -ENOBUFS;
592			break;
593		}
594		gsf = kmalloc(optlen,GFP_KERNEL);
595		if (!gsf) {
596			retv = -ENOBUFS;
597			break;
598		}
599		retv = -EFAULT;
600		if (copy_from_user(gsf, optval, optlen)) {
601			kfree(gsf);
602			break;
603		}
604		/* numsrc >= (4G-140)/128 overflow in 32 bits */
605		if (gsf->gf_numsrc >= 0x1ffffffU ||
606		    gsf->gf_numsrc > sysctl_mld_max_msf) {
607			kfree(gsf);
608			retv = -ENOBUFS;
609			break;
610		}
611		if (GROUP_FILTER_SIZE(gsf->gf_numsrc) > optlen) {
612			kfree(gsf);
613			retv = -EINVAL;
614			break;
615		}
616		retv = ip6_mc_msfilter(sk, gsf);
617		kfree(gsf);
618
619		break;
620	}
621	case IPV6_ROUTER_ALERT:
622		if (optlen < sizeof(int))
623			goto e_inval;
624		retv = ip6_ra_control(sk, val, NULL);
625		break;
626	case IPV6_MTU_DISCOVER:
627		if (optlen < sizeof(int))
628			goto e_inval;
629		if (val<0 || val>3)
630			goto e_inval;
631		np->pmtudisc = val;
632		retv = 0;
633		break;
634	case IPV6_MTU:
635		if (optlen < sizeof(int))
636			goto e_inval;
637		if (val && val < IPV6_MIN_MTU)
638			goto e_inval;
639		np->frag_size = val;
640		retv = 0;
641		break;
642	case IPV6_RECVERR:
643		if (optlen < sizeof(int))
644			goto e_inval;
645		np->recverr = valbool;
646		if (!val)
647			skb_queue_purge(&sk->sk_error_queue);
648		retv = 0;
649		break;
650	case IPV6_FLOWINFO_SEND:
651		if (optlen < sizeof(int))
652			goto e_inval;
653		np->sndflow = valbool;
654		retv = 0;
655		break;
656	case IPV6_FLOWLABEL_MGR:
657		retv = ipv6_flowlabel_opt(sk, optval, optlen);
658		break;
659	case IPV6_IPSEC_POLICY:
660	case IPV6_XFRM_POLICY:
661		retv = -EPERM;
662		if (!capable(CAP_NET_ADMIN))
663			break;
664		retv = xfrm_user_policy(sk, optname, optval, optlen);
665		break;
666
667	case IPV6_ADDR_PREFERENCES:
668	    {
669		unsigned int pref = 0;
670		unsigned int prefmask = ~0;
671
672		if (optlen < sizeof(int))
673			goto e_inval;
674
675		retv = -EINVAL;
676
677		/* check PUBLIC/TMP/PUBTMP_DEFAULT conflicts */
678		switch (val & (IPV6_PREFER_SRC_PUBLIC|
679			       IPV6_PREFER_SRC_TMP|
680			       IPV6_PREFER_SRC_PUBTMP_DEFAULT)) {
681		case IPV6_PREFER_SRC_PUBLIC:
682			pref |= IPV6_PREFER_SRC_PUBLIC;
683			break;
684		case IPV6_PREFER_SRC_TMP:
685			pref |= IPV6_PREFER_SRC_TMP;
686			break;
687		case IPV6_PREFER_SRC_PUBTMP_DEFAULT:
688			break;
689		case 0:
690			goto pref_skip_pubtmp;
691		default:
692			goto e_inval;
693		}
694
695		prefmask &= ~(IPV6_PREFER_SRC_PUBLIC|
696			      IPV6_PREFER_SRC_TMP);
697pref_skip_pubtmp:
698
699		/* check HOME/COA conflicts */
700		switch (val & (IPV6_PREFER_SRC_HOME|IPV6_PREFER_SRC_COA)) {
701		case IPV6_PREFER_SRC_HOME:
702			break;
703		case IPV6_PREFER_SRC_COA:
704			pref |= IPV6_PREFER_SRC_COA;
705		case 0:
706			goto pref_skip_coa;
707		default:
708			goto e_inval;
709		}
710
711		prefmask &= ~IPV6_PREFER_SRC_COA;
712pref_skip_coa:
713
714		/* check CGA/NONCGA conflicts */
715		switch (val & (IPV6_PREFER_SRC_CGA|IPV6_PREFER_SRC_NONCGA)) {
716		case IPV6_PREFER_SRC_CGA:
717		case IPV6_PREFER_SRC_NONCGA:
718		case 0:
719			break;
720		default:
721			goto e_inval;
722		}
723
724		np->srcprefs = (np->srcprefs & prefmask) | pref;
725		retv = 0;
726
727		break;
728	    }
729	}
730
731	release_sock(sk);
732
733	return retv;
734
735e_inval:
736	release_sock(sk);
737	return -EINVAL;
738}
739
740int ipv6_setsockopt(struct sock *sk, int level, int optname,
741		    char __user *optval, int optlen)
742{
743	int err;
744
745	if (level == SOL_IP && sk->sk_type != SOCK_RAW)
746		return udp_prot.setsockopt(sk, level, optname, optval, optlen);
747
748	if (level != SOL_IPV6)
749		return -ENOPROTOOPT;
750
751	err = do_ipv6_setsockopt(sk, level, optname, optval, optlen);
752#ifdef CONFIG_NETFILTER
753	/* we need to exclude all possible ENOPROTOOPTs except default case */
754	if (err == -ENOPROTOOPT && optname != IPV6_IPSEC_POLICY &&
755			optname != IPV6_XFRM_POLICY) {
756		lock_sock(sk);
757		err = nf_setsockopt(sk, PF_INET6, optname, optval,
758				optlen);
759		release_sock(sk);
760	}
761#endif
762	return err;
763}
764
765EXPORT_SYMBOL(ipv6_setsockopt);
766
767#ifdef CONFIG_COMPAT
768int compat_ipv6_setsockopt(struct sock *sk, int level, int optname,
769			   char __user *optval, int optlen)
770{
771	int err;
772
773	if (level == SOL_IP && sk->sk_type != SOCK_RAW) {
774		if (udp_prot.compat_setsockopt != NULL)
775			return udp_prot.compat_setsockopt(sk, level, optname,
776							  optval, optlen);
777		return udp_prot.setsockopt(sk, level, optname, optval, optlen);
778	}
779
780	if (level != SOL_IPV6)
781		return -ENOPROTOOPT;
782
783	if (optname >= MCAST_JOIN_GROUP && optname <= MCAST_MSFILTER)
784		return compat_mc_setsockopt(sk, level, optname, optval, optlen,
785			ipv6_setsockopt);
786
787	err = do_ipv6_setsockopt(sk, level, optname, optval, optlen);
788#ifdef CONFIG_NETFILTER
789	/* we need to exclude all possible ENOPROTOOPTs except default case */
790	if (err == -ENOPROTOOPT && optname != IPV6_IPSEC_POLICY &&
791	    optname != IPV6_XFRM_POLICY) {
792		lock_sock(sk);
793		err = compat_nf_setsockopt(sk, PF_INET6, optname,
794					   optval, optlen);
795		release_sock(sk);
796	}
797#endif
798	return err;
799}
800
801EXPORT_SYMBOL(compat_ipv6_setsockopt);
802#endif
803
804static int ipv6_getsockopt_sticky(struct sock *sk, struct ipv6_txoptions *opt,
805				  int optname, char __user *optval, int len)
806{
807	struct ipv6_opt_hdr *hdr;
808
809	if (!opt)
810		return 0;
811
812	switch(optname) {
813	case IPV6_HOPOPTS:
814		hdr = opt->hopopt;
815		break;
816	case IPV6_RTHDRDSTOPTS:
817		hdr = opt->dst0opt;
818		break;
819	case IPV6_RTHDR:
820		hdr = (struct ipv6_opt_hdr *)opt->srcrt;
821		break;
822	case IPV6_DSTOPTS:
823		hdr = opt->dst1opt;
824		break;
825	default:
826		return -EINVAL;	/* should not happen */
827	}
828
829	if (!hdr)
830		return 0;
831
832	len = min_t(unsigned int, len, ipv6_optlen(hdr));
833	if (copy_to_user(optval, hdr, len))
834		return -EFAULT;
835	return ipv6_optlen(hdr);
836}
837
838static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
839		    char __user *optval, int __user *optlen)
840{
841	struct ipv6_pinfo *np = inet6_sk(sk);
842	int len;
843	int val;
844
845	if (ip6_mroute_opt(optname))
846		return ip6_mroute_getsockopt(sk, optname, optval, optlen);
847
848	if (get_user(len, optlen))
849		return -EFAULT;
850	switch (optname) {
851	case IPV6_ADDRFORM:
852		if (sk->sk_protocol != IPPROTO_UDP &&
853		    sk->sk_protocol != IPPROTO_UDPLITE &&
854		    sk->sk_protocol != IPPROTO_TCP)
855			return -EINVAL;
856		if (sk->sk_state != TCP_ESTABLISHED)
857			return -ENOTCONN;
858		val = sk->sk_family;
859		break;
860	case MCAST_MSFILTER:
861	{
862		struct group_filter gsf;
863		int err;
864
865		if (len < GROUP_FILTER_SIZE(0))
866			return -EINVAL;
867		if (copy_from_user(&gsf, optval, GROUP_FILTER_SIZE(0)))
868			return -EFAULT;
869		lock_sock(sk);
870		err = ip6_mc_msfget(sk, &gsf,
871			(struct group_filter __user *)optval, optlen);
872		release_sock(sk);
873		return err;
874	}
875
876	case IPV6_2292PKTOPTIONS:
877	{
878		struct msghdr msg;
879		struct sk_buff *skb;
880
881		if (sk->sk_type != SOCK_STREAM)
882			return -ENOPROTOOPT;
883
884		msg.msg_control = optval;
885		msg.msg_controllen = len;
886		msg.msg_flags = 0;
887
888		lock_sock(sk);
889		skb = np->pktoptions;
890		if (skb)
891			atomic_inc(&skb->users);
892		release_sock(sk);
893
894		if (skb) {
895			int err = datagram_recv_ctl(sk, &msg, skb);
896			kfree_skb(skb);
897			if (err)
898				return err;
899		} else {
900			if (np->rxopt.bits.rxinfo) {
901				struct in6_pktinfo src_info;
902				src_info.ipi6_ifindex = np->mcast_oif;
903				ipv6_addr_copy(&src_info.ipi6_addr, &np->daddr);
904				put_cmsg(&msg, SOL_IPV6, IPV6_PKTINFO, sizeof(src_info), &src_info);
905			}
906			if (np->rxopt.bits.rxhlim) {
907				int hlim = np->mcast_hops;
908				put_cmsg(&msg, SOL_IPV6, IPV6_HOPLIMIT, sizeof(hlim), &hlim);
909			}
910			if (np->rxopt.bits.rxoinfo) {
911				struct in6_pktinfo src_info;
912				src_info.ipi6_ifindex = np->mcast_oif;
913				ipv6_addr_copy(&src_info.ipi6_addr, &np->daddr);
914				put_cmsg(&msg, SOL_IPV6, IPV6_2292PKTINFO, sizeof(src_info), &src_info);
915			}
916			if (np->rxopt.bits.rxohlim) {
917				int hlim = np->mcast_hops;
918				put_cmsg(&msg, SOL_IPV6, IPV6_2292HOPLIMIT, sizeof(hlim), &hlim);
919			}
920		}
921		len -= msg.msg_controllen;
922		return put_user(len, optlen);
923	}
924	case IPV6_MTU:
925	{
926		struct dst_entry *dst;
927		val = 0;
928		lock_sock(sk);
929		dst = sk_dst_get(sk);
930		if (dst) {
931			val = dst_mtu(dst);
932			dst_release(dst);
933		}
934		release_sock(sk);
935		if (!val)
936			return -ENOTCONN;
937		break;
938	}
939
940	case IPV6_V6ONLY:
941		val = np->ipv6only;
942		break;
943
944	case IPV6_RECVPKTINFO:
945		val = np->rxopt.bits.rxinfo;
946		break;
947
948	case IPV6_2292PKTINFO:
949		val = np->rxopt.bits.rxoinfo;
950		break;
951
952	case IPV6_RECVHOPLIMIT:
953		val = np->rxopt.bits.rxhlim;
954		break;
955
956	case IPV6_2292HOPLIMIT:
957		val = np->rxopt.bits.rxohlim;
958		break;
959
960	case IPV6_RECVRTHDR:
961		val = np->rxopt.bits.srcrt;
962		break;
963
964	case IPV6_2292RTHDR:
965		val = np->rxopt.bits.osrcrt;
966		break;
967
968	case IPV6_HOPOPTS:
969	case IPV6_RTHDRDSTOPTS:
970	case IPV6_RTHDR:
971	case IPV6_DSTOPTS:
972	{
973
974		lock_sock(sk);
975		len = ipv6_getsockopt_sticky(sk, np->opt,
976					     optname, optval, len);
977		release_sock(sk);
978		return put_user(len, optlen);
979	}
980
981	case IPV6_RECVHOPOPTS:
982		val = np->rxopt.bits.hopopts;
983		break;
984
985	case IPV6_2292HOPOPTS:
986		val = np->rxopt.bits.ohopopts;
987		break;
988
989	case IPV6_RECVDSTOPTS:
990		val = np->rxopt.bits.dstopts;
991		break;
992
993	case IPV6_2292DSTOPTS:
994		val = np->rxopt.bits.odstopts;
995		break;
996
997	case IPV6_TCLASS:
998		val = np->tclass;
999		if (val < 0)
1000			val = 0;
1001		break;
1002
1003	case IPV6_RECVTCLASS:
1004		val = np->rxopt.bits.rxtclass;
1005		break;
1006
1007	case IPV6_FLOWINFO:
1008		val = np->rxopt.bits.rxflow;
1009		break;
1010
1011	case IPV6_UNICAST_HOPS:
1012	case IPV6_MULTICAST_HOPS:
1013	{
1014		struct dst_entry *dst;
1015
1016		if (optname == IPV6_UNICAST_HOPS)
1017			val = np->hop_limit;
1018		else
1019			val = np->mcast_hops;
1020
1021		dst = sk_dst_get(sk);
1022		if (dst) {
1023			if (val < 0)
1024				val = ip6_dst_hoplimit(dst);
1025			dst_release(dst);
1026		}
1027		if (val < 0)
1028			val = ipv6_devconf.hop_limit;
1029		break;
1030	}
1031
1032	case IPV6_MULTICAST_LOOP:
1033		val = np->mc_loop;
1034		break;
1035
1036	case IPV6_MULTICAST_IF:
1037		val = np->mcast_oif;
1038		break;
1039
1040	case IPV6_MTU_DISCOVER:
1041		val = np->pmtudisc;
1042		break;
1043
1044	case IPV6_RECVERR:
1045		val = np->recverr;
1046		break;
1047
1048	case IPV6_FLOWINFO_SEND:
1049		val = np->sndflow;
1050		break;
1051
1052	case IPV6_ADDR_PREFERENCES:
1053		val = 0;
1054
1055		if (np->srcprefs & IPV6_PREFER_SRC_TMP)
1056			val |= IPV6_PREFER_SRC_TMP;
1057		else if (np->srcprefs & IPV6_PREFER_SRC_PUBLIC)
1058			val |= IPV6_PREFER_SRC_PUBLIC;
1059		else {
1060			/* XXX: should we return system default? */
1061			val |= IPV6_PREFER_SRC_PUBTMP_DEFAULT;
1062		}
1063
1064		if (np->srcprefs & IPV6_PREFER_SRC_COA)
1065			val |= IPV6_PREFER_SRC_COA;
1066		else
1067			val |= IPV6_PREFER_SRC_HOME;
1068		break;
1069
1070	default:
1071		return -ENOPROTOOPT;
1072	}
1073	len = min_t(unsigned int, sizeof(int), len);
1074	if(put_user(len, optlen))
1075		return -EFAULT;
1076	if(copy_to_user(optval,&val,len))
1077		return -EFAULT;
1078	return 0;
1079}
1080
1081int ipv6_getsockopt(struct sock *sk, int level, int optname,
1082		    char __user *optval, int __user *optlen)
1083{
1084	int err;
1085
1086	if (level == SOL_IP && sk->sk_type != SOCK_RAW)
1087		return udp_prot.getsockopt(sk, level, optname, optval, optlen);
1088
1089	if(level != SOL_IPV6)
1090		return -ENOPROTOOPT;
1091
1092	if (optname == MCAST_MSFILTER)
1093		return compat_mc_getsockopt(sk, level, optname, optval, optlen,
1094			ipv6_getsockopt);
1095
1096	err = do_ipv6_getsockopt(sk, level, optname, optval, optlen);
1097#ifdef CONFIG_NETFILTER
1098	/* we need to exclude all possible ENOPROTOOPTs except default case */
1099	if (err == -ENOPROTOOPT && optname != IPV6_2292PKTOPTIONS) {
1100		int len;
1101
1102		if (get_user(len, optlen))
1103			return -EFAULT;
1104
1105		lock_sock(sk);
1106		err = nf_getsockopt(sk, PF_INET6, optname, optval,
1107				&len);
1108		release_sock(sk);
1109		if (err >= 0)
1110			err = put_user(len, optlen);
1111	}
1112#endif
1113	return err;
1114}
1115
1116EXPORT_SYMBOL(ipv6_getsockopt);
1117
1118#ifdef CONFIG_COMPAT
1119int compat_ipv6_getsockopt(struct sock *sk, int level, int optname,
1120			   char __user *optval, int __user *optlen)
1121{
1122	int err;
1123
1124	if (level == SOL_IP && sk->sk_type != SOCK_RAW) {
1125		if (udp_prot.compat_getsockopt != NULL)
1126			return udp_prot.compat_getsockopt(sk, level, optname,
1127							  optval, optlen);
1128		return udp_prot.getsockopt(sk, level, optname, optval, optlen);
1129	}
1130
1131	if (level != SOL_IPV6)
1132		return -ENOPROTOOPT;
1133
1134	err = do_ipv6_getsockopt(sk, level, optname, optval, optlen);
1135#ifdef CONFIG_NETFILTER
1136	/* we need to exclude all possible ENOPROTOOPTs except default case */
1137	if (err == -ENOPROTOOPT && optname != IPV6_2292PKTOPTIONS) {
1138		int len;
1139
1140		if (get_user(len, optlen))
1141			return -EFAULT;
1142
1143		lock_sock(sk);
1144		err = compat_nf_getsockopt(sk, PF_INET6,
1145					   optname, optval, &len);
1146		release_sock(sk);
1147		if (err >= 0)
1148			err = put_user(len, optlen);
1149	}
1150#endif
1151	return err;
1152}
1153
1154EXPORT_SYMBOL(compat_ipv6_getsockopt);
1155#endif
1156
1157