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