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