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