~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/ipv6/ipv6_sockglue.c

Version: ~ [ linux-5.6 ] ~ [ linux-5.5.13 ] ~ [ linux-5.4.28 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.113 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.174 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.217 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.217 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.82 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  *      IPv6 BSD socket options interface
  3  *      Linux INET6 implementation 
  4  *
  5  *      Authors:
  6  *      Pedro Roque             <pedro_m@yahoo.com>     
  7  *
  8  *      Based on linux/net/ipv4/ip_sockglue.c
  9  *
 10  *      $Id: ipv6_sockglue.c,v 1.40 2001/09/18 22:29:10 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/config.h>
 30 #include <linux/errno.h>
 31 #include <linux/types.h>
 32 #include <linux/socket.h>
 33 #include <linux/sockios.h>
 34 #include <linux/sched.h>
 35 #include <linux/net.h>
 36 #include <linux/in6.h>
 37 #include <linux/netdevice.h>
 38 #include <linux/if_arp.h>
 39 #include <linux/init.h>
 40 #include <linux/sysctl.h>
 41 #include <linux/netfilter.h>
 42 
 43 #include <net/sock.h>
 44 #include <net/snmp.h>
 45 #include <net/ipv6.h>
 46 #include <net/ndisc.h>
 47 #include <net/protocol.h>
 48 #include <net/transp_v6.h>
 49 #include <net/ip6_route.h>
 50 #include <net/addrconf.h>
 51 #include <net/inet_common.h>
 52 #include <net/tcp.h>
 53 #include <net/udp.h>
 54 
 55 #include <asm/uaccess.h>
 56 
 57 struct ipv6_mib ipv6_statistics[NR_CPUS*2];
 58 
 59 struct packet_type ipv6_packet_type =
 60 {
 61         __constant_htons(ETH_P_IPV6), 
 62         NULL,                                   /* All devices */
 63         ipv6_rcv,
 64         (void*)1,
 65         NULL
 66 };
 67 
 68 /*
 69  *      addrconf module should be notifyed of a device going up
 70  */
 71 static struct notifier_block ipv6_dev_notf = {
 72         addrconf_notify,
 73         NULL,
 74         0
 75 };
 76 
 77 struct ip6_ra_chain *ip6_ra_chain;
 78 rwlock_t ip6_ra_lock = RW_LOCK_UNLOCKED;
 79 
 80 int ip6_ra_control(struct sock *sk, int sel, void (*destructor)(struct sock *))
 81 {
 82         struct ip6_ra_chain *ra, *new_ra, **rap;
 83 
 84         /* RA packet may be delivered ONLY to IPPROTO_RAW socket */
 85         if (sk->type != SOCK_RAW || sk->num != IPPROTO_RAW)
 86                 return -EINVAL;
 87 
 88         new_ra = (sel>=0) ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL;
 89 
 90         write_lock_bh(&ip6_ra_lock);
 91         for (rap = &ip6_ra_chain; (ra=*rap) != NULL; rap = &ra->next) {
 92                 if (ra->sk == sk) {
 93                         if (sel>=0) {
 94                                 write_unlock_bh(&ip6_ra_lock);
 95                                 if (new_ra)
 96                                         kfree(new_ra);
 97                                 return -EADDRINUSE;
 98                         }
 99 
100                         *rap = ra->next;
101                         write_unlock_bh(&ip6_ra_lock);
102 
103                         if (ra->destructor)
104                                 ra->destructor(sk);
105                         sock_put(sk);
106                         kfree(ra);
107                         return 0;
108                 }
109         }
110         if (new_ra == NULL) {
111                 write_unlock_bh(&ip6_ra_lock);
112                 return -ENOBUFS;
113         }
114         new_ra->sk = sk;
115         new_ra->sel = sel;
116         new_ra->destructor = destructor;
117         new_ra->next = ra;
118         *rap = new_ra;
119         sock_hold(sk);
120         write_unlock_bh(&ip6_ra_lock);
121         return 0;
122 }
123 
124 extern int ip6_mc_source(int add, int omode, struct sock *sk,
125         struct group_source_req *pgsr);
126 extern int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf);
127 extern int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf,
128         struct group_filter *optval, int *optlen);
129 
130 
131 int ipv6_setsockopt(struct sock *sk, int level, int optname, char *optval, 
132                     int optlen)
133 {
134         struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
135         int val, valbool;
136         int retv = -ENOPROTOOPT;
137 
138         if(level==SOL_IP && sk->type != SOCK_RAW)
139                 return udp_prot.setsockopt(sk, level, optname, optval, optlen);
140 
141         if(level!=SOL_IPV6)
142                 goto out;
143 
144         if (optval == NULL)
145                 val=0;
146         else if (get_user(val, (int *) optval))
147                 return -EFAULT;
148 
149         valbool = (val!=0);
150 
151         lock_sock(sk);
152 
153         switch (optname) {
154 
155         case IPV6_ADDRFORM:
156                 if (val == PF_INET) {
157                         struct ipv6_txoptions *opt;
158                         struct sk_buff *pktopt;
159 
160                         if (sk->protocol != IPPROTO_UDP &&
161                             sk->protocol != IPPROTO_TCP)
162                                 break;
163 
164                         if (sk->state != TCP_ESTABLISHED) {
165                                 retv = -ENOTCONN;
166                                 break;
167                         }
168 
169                         if (ipv6_only_sock(sk) ||
170                             !(ipv6_addr_type(&np->daddr) & IPV6_ADDR_MAPPED)) {
171                                 retv = -EADDRNOTAVAIL;
172                                 break;
173                         }
174 
175                         fl6_free_socklist(sk);
176                         ipv6_sock_mc_close(sk);
177 
178                         if (sk->protocol == IPPROTO_TCP) {
179                                 struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
180 
181                                 local_bh_disable();
182                                 sock_prot_dec_use(sk->prot);
183                                 sock_prot_inc_use(&tcp_prot);
184                                 local_bh_enable();
185                                 sk->prot = &tcp_prot;
186                                 tp->af_specific = &ipv4_specific;
187                                 sk->socket->ops = &inet_stream_ops;
188                                 sk->family = PF_INET;
189                                 tcp_sync_mss(sk, tp->pmtu_cookie);
190                         } else {
191                                 local_bh_disable();
192                                 sock_prot_dec_use(sk->prot);
193                                 sock_prot_inc_use(&udp_prot);
194                                 local_bh_enable();
195                                 sk->prot = &udp_prot;
196                                 sk->socket->ops = &inet_dgram_ops;
197                                 sk->family = PF_INET;
198                         }
199                         opt = xchg(&np->opt, NULL);
200                         if (opt)
201                                 sock_kfree_s(sk, opt, opt->tot_len);
202                         pktopt = xchg(&np->pktoptions, NULL);
203                         if (pktopt)
204                                 kfree_skb(pktopt);
205 
206                         sk->destruct = inet_sock_destruct;
207 #ifdef INET_REFCNT_DEBUG
208                         atomic_dec(&inet6_sock_nr);
209 #endif
210                         MOD_DEC_USE_COUNT;
211                         retv = 0;
212                         break;
213                 }
214                 goto e_inval;
215 
216         case IPV6_V6ONLY:
217                 if (sk->num)
218                         goto e_inval;
219                 np->ipv6only = valbool;
220                 retv = 0;
221                 break;
222 
223         case IPV6_PKTINFO:
224                 np->rxopt.bits.rxinfo = valbool;
225                 retv = 0;
226                 break;
227 
228         case IPV6_HOPLIMIT:
229                 np->rxopt.bits.rxhlim = valbool;
230                 retv = 0;
231                 break;
232 
233         case IPV6_RTHDR:
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_HOPOPTS:
241                 np->rxopt.bits.hopopts = valbool;
242                 retv = 0;
243                 break;
244 
245         case IPV6_AUTHHDR:
246                 np->rxopt.bits.authhdr = valbool;
247                 retv = 0;
248                 break;
249 
250         case IPV6_DSTOPTS:
251                 np->rxopt.bits.dstopts = valbool;
252                 retv = 0;
253                 break;
254 
255         case IPV6_FLOWINFO:
256                 np->rxopt.bits.rxflow = valbool;
257                 retv = 0;
258                 break;
259 
260         case IPV6_PKTOPTIONS:
261         {
262                 struct ipv6_txoptions *opt = NULL;
263                 struct msghdr msg;
264                 struct flowi fl;
265                 int junk;
266 
267                 fl.fl6_flowlabel = 0;
268                 fl.oif = sk->bound_dev_if;
269 
270                 if (optlen == 0)
271                         goto update;
272 
273                 /* 1K is probably excessive
274                  * 1K is surely not enough, 2K per standard header is 16K.
275                  */
276                 retv = -EINVAL;
277                 if (optlen > 64*1024)
278                         break;
279 
280                 opt = sock_kmalloc(sk, sizeof(*opt) + optlen, GFP_KERNEL);
281                 retv = -ENOBUFS;
282                 if (opt == NULL)
283                         break;
284 
285                 memset(opt, 0, sizeof(*opt));
286                 opt->tot_len = sizeof(*opt) + optlen;
287                 retv = -EFAULT;
288                 if (copy_from_user(opt+1, optval, optlen))
289                         goto done;
290 
291                 msg.msg_controllen = optlen;
292                 msg.msg_control = (void*)(opt+1);
293 
294                 retv = datagram_send_ctl(&msg, &fl, opt, &junk);
295                 if (retv)
296                         goto done;
297 update:
298                 retv = 0;
299                 if (sk->type == SOCK_STREAM) {
300                         if (opt) {
301                                 struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
302                                 if (!((1<<sk->state)&(TCPF_LISTEN|TCPF_CLOSE))
303                                     && sk->daddr != LOOPBACK4_IPV6) {
304                                         tp->ext_header_len = opt->opt_flen + opt->opt_nflen;
305                                         tcp_sync_mss(sk, tp->pmtu_cookie);
306                                 }
307                         }
308                         opt = xchg(&np->opt, opt);
309                         sk_dst_reset(sk);
310                 } else {
311                         write_lock(&sk->dst_lock);
312                         opt = xchg(&np->opt, opt);
313                         write_unlock(&sk->dst_lock);
314                         sk_dst_reset(sk);
315                 }
316 
317 done:
318                 if (opt)
319                         sock_kfree_s(sk, opt, opt->tot_len);
320                 break;
321         }
322         case IPV6_UNICAST_HOPS:
323                 if (val > 255 || val < -1)
324                         goto e_inval;
325                 np->hop_limit = val;
326                 retv = 0;
327                 break;
328 
329         case IPV6_MULTICAST_HOPS:
330                 if (sk->type == SOCK_STREAM)
331                         goto e_inval;
332                 if (val > 255 || val < -1)
333                         goto e_inval;
334                 np->mcast_hops = val;
335                 retv = 0;
336                 break;
337 
338         case IPV6_MULTICAST_LOOP:
339                 np->mc_loop = valbool;
340                 retv = 0;
341                 break;
342 
343         case IPV6_MULTICAST_IF:
344                 if (sk->type == SOCK_STREAM)
345                         goto e_inval;
346                 if (sk->bound_dev_if && sk->bound_dev_if != val)
347                         goto e_inval;
348 
349                 if (__dev_get_by_index(val) == NULL) {
350                         retv = -ENODEV;
351                         break;
352                 }
353                 np->mcast_oif = val;
354                 retv = 0;
355                 break;
356         case IPV6_ADD_MEMBERSHIP:
357         case IPV6_DROP_MEMBERSHIP:
358         {
359                 struct ipv6_mreq mreq;
360 
361                 retv = -EFAULT;
362                 if (copy_from_user(&mreq, optval, sizeof(struct ipv6_mreq)))
363                         break;
364 
365                 if (optname == IPV6_ADD_MEMBERSHIP)
366                         retv = ipv6_sock_mc_join(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_multiaddr);
367                 else
368                         retv = ipv6_sock_mc_drop(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_multiaddr);
369                 break;
370         }
371         case IPV6_JOIN_ANYCAST:
372         case IPV6_LEAVE_ANYCAST:
373         {
374                 struct ipv6_mreq mreq;
375 
376                 if (optlen != sizeof(struct ipv6_mreq))
377                         goto e_inval;
378 
379                 retv = -EFAULT;
380                 if (copy_from_user(&mreq, optval, sizeof(struct ipv6_mreq)))
381                         break;
382 
383                 if (optname == IPV6_JOIN_ANYCAST)
384                         retv = ipv6_sock_ac_join(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_acaddr);
385                 else
386                         retv = ipv6_sock_ac_drop(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_acaddr);
387                 break;
388         }
389         case MCAST_JOIN_GROUP:
390         case MCAST_LEAVE_GROUP:
391         {
392                 struct group_req greq;
393                 struct sockaddr_in6 *psin6;
394 
395                 retv = -EFAULT;
396                 if (copy_from_user(&greq, optval, sizeof(struct group_req)))
397                         break;
398                 if (greq.gr_group.ss_family != AF_INET6) {
399                         retv = -EADDRNOTAVAIL;
400                         break;
401                 }
402                 psin6 = (struct sockaddr_in6 *)&greq.gr_group;
403                 if (optname == MCAST_JOIN_GROUP)
404                         retv = ipv6_sock_mc_join(sk, greq.gr_interface,
405                                 &psin6->sin6_addr);
406                 else
407                         retv = ipv6_sock_mc_drop(sk, greq.gr_interface,
408                                 &psin6->sin6_addr);
409                 break;
410         }
411         case MCAST_JOIN_SOURCE_GROUP:
412         case MCAST_LEAVE_SOURCE_GROUP:
413         case MCAST_BLOCK_SOURCE:
414         case MCAST_UNBLOCK_SOURCE:
415         {
416                 struct group_source_req greqs;
417                 int omode, add;
418 
419                 if (optlen != sizeof(struct group_source_req))
420                         goto e_inval;
421                 if (copy_from_user(&greqs, optval, sizeof(greqs))) {
422                         retv = -EFAULT;
423                         break;
424                 }
425                 if (greqs.gsr_group.ss_family != AF_INET6 ||
426                     greqs.gsr_source.ss_family != AF_INET6) {
427                         retv = -EADDRNOTAVAIL;
428                         break;
429                 }
430                 if (optname == MCAST_BLOCK_SOURCE) {
431                         omode = MCAST_EXCLUDE;
432                         add = 1;
433                 } else if (optname == MCAST_UNBLOCK_SOURCE) {
434                         omode = MCAST_EXCLUDE;
435                         add = 0;
436                 } else if (optname == MCAST_JOIN_SOURCE_GROUP) {
437                         struct sockaddr_in6 *psin6;
438 
439                         psin6 = (struct sockaddr_in6 *)&greqs.gsr_group;
440                         retv = ipv6_sock_mc_join(sk, greqs.gsr_interface,
441                                 &psin6->sin6_addr);
442                         if (retv)
443                                 break;
444                         omode = MCAST_INCLUDE;
445                         add = 1;
446                 } else /*IP_DROP_SOURCE_MEMBERSHIP */ {
447                         omode = MCAST_INCLUDE;
448                         add = 0;
449                 }
450                 retv = ip6_mc_source(add, omode, sk, &greqs);
451                 break;
452         }
453         case MCAST_MSFILTER:
454         {
455                 extern int sysctl_optmem_max;
456                 extern int sysctl_mld_max_msf;
457                 struct group_filter *gsf;
458 
459                 if (optlen < GROUP_FILTER_SIZE(0))
460                         goto e_inval;
461                 if (optlen > sysctl_optmem_max) {
462                         retv = -ENOBUFS;
463                         break;
464                 }
465                 gsf = (struct group_filter *)kmalloc(optlen,GFP_KERNEL);
466                 if (gsf == 0) {
467                         retv = -ENOBUFS;
468                         break;
469                 }
470                 retv = -EFAULT;
471                 if (copy_from_user(gsf, optval, optlen)) {
472                         kfree(gsf);
473                         break;
474                 }
475                 /* numsrc >= (4G-140)/128 overflow in 32 bits */
476                 if (gsf->gf_numsrc >= 0x1ffffffU ||
477                     gsf->gf_numsrc > sysctl_mld_max_msf) {
478                         kfree(gsf);
479                         retv = -ENOBUFS;
480                         break;
481                 }
482                 if (GROUP_FILTER_SIZE(gsf->gf_numsrc) > optlen) {
483                         kfree(gsf);
484                         retv = -EINVAL;
485                         break;
486                 }
487                 retv = ip6_mc_msfilter(sk, gsf);
488                 kfree(gsf);
489 
490                 break;
491         }
492         case IPV6_ROUTER_ALERT:
493                 retv = ip6_ra_control(sk, val, NULL);
494                 break;
495         case IPV6_MTU_DISCOVER:
496                 if (val<0 || val>2)
497                         goto e_inval;
498                 np->pmtudisc = val;
499                 retv = 0;
500                 break;
501         case IPV6_MTU:
502                 if (val && val < IPV6_MIN_MTU)
503                         goto e_inval;
504                 np->frag_size = val;
505                 retv = 0;
506                 break;
507         case IPV6_RECVERR:
508                 np->recverr = valbool;
509                 if (!val)
510                         skb_queue_purge(&sk->error_queue);
511                 retv = 0;
512                 break;
513         case IPV6_FLOWINFO_SEND:
514                 np->sndflow = valbool;
515                 retv = 0;
516                 break;
517         case IPV6_FLOWLABEL_MGR:
518                 retv = ipv6_flowlabel_opt(sk, optval, optlen);
519                 break;
520 
521 #ifdef CONFIG_NETFILTER
522         default:
523                 retv = nf_setsockopt(sk, PF_INET6, optname, optval, 
524                                             optlen);
525                 break;
526 #endif
527 
528         }
529         release_sock(sk);
530 
531 out:
532         return retv;
533 
534 e_inval:
535         release_sock(sk);
536         return -EINVAL;
537 }
538 
539 int ipv6_getsockopt(struct sock *sk, int level, int optname, char *optval, 
540                     int *optlen)
541 {
542         struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
543         int len;
544         int val;
545 
546         if(level==SOL_IP && sk->type != SOCK_RAW)
547                 return udp_prot.getsockopt(sk, level, optname, optval, optlen);
548         if(level!=SOL_IPV6)
549                 return -ENOPROTOOPT;
550         if (get_user(len, optlen))
551                 return -EFAULT;
552         switch (optname) {
553         case IPV6_PKTOPTIONS:
554         {
555                 struct msghdr msg;
556                 struct sk_buff *skb;
557 
558                 if (sk->type != SOCK_STREAM)
559                         return -ENOPROTOOPT;
560 
561                 msg.msg_control = optval;
562                 msg.msg_controllen = len;
563                 msg.msg_flags = 0;
564 
565                 lock_sock(sk);
566                 skb = np->pktoptions;
567                 if (skb)
568                         atomic_inc(&skb->users);
569                 release_sock(sk);
570 
571                 if (skb) {
572                         int err = datagram_recv_ctl(sk, &msg, skb);
573                         kfree_skb(skb);
574                         if (err)
575                                 return err;
576                 } else {
577                         if (np->rxopt.bits.rxinfo) {
578                                 struct in6_pktinfo src_info;
579                                 src_info.ipi6_ifindex = np->mcast_oif;
580                                 ipv6_addr_copy(&src_info.ipi6_addr, &np->daddr);
581                                 put_cmsg(&msg, SOL_IPV6, IPV6_PKTINFO, sizeof(src_info), &src_info);
582                         }
583                         if (np->rxopt.bits.rxhlim) {
584                                 int hlim = np->mcast_hops;
585                                 put_cmsg(&msg, SOL_IPV6, IPV6_HOPLIMIT, sizeof(hlim), &hlim);
586                         }
587                 }
588                 len -= msg.msg_controllen;
589                 return put_user(len, optlen);
590         }
591         case IPV6_MTU:
592         {
593                 struct dst_entry *dst;
594                 val = 0;        
595                 lock_sock(sk);
596                 dst = sk_dst_get(sk);
597                 if (dst) {
598                         val = dst->pmtu;
599                         dst_release(dst);
600                 }
601                 release_sock(sk);
602                 if (!val)
603                         return -ENOTCONN;
604                 break;
605         }
606 
607         case IPV6_V6ONLY:
608                 val = np->ipv6only;
609                 break;
610 
611         case IPV6_PKTINFO:
612                 val = np->rxopt.bits.rxinfo;
613                 break;
614         case MCAST_MSFILTER:
615         {
616                 struct group_filter gsf;
617                 int err;
618 
619                 if (len < GROUP_FILTER_SIZE(0))
620                         return -EINVAL;
621                 if (copy_from_user(&gsf, optval, GROUP_FILTER_SIZE(0)))
622                         return -EFAULT;
623                 lock_sock(sk);
624                 err = ip6_mc_msfget(sk, &gsf,
625                         (struct group_filter *)optval, optlen);
626                 release_sock(sk);
627                 return err;
628         }
629 
630         case IPV6_HOPLIMIT:
631                 val = np->rxopt.bits.rxhlim;
632                 break;
633 
634         case IPV6_RTHDR:
635                 val = np->rxopt.bits.srcrt;
636                 break;
637 
638         case IPV6_HOPOPTS:
639                 val = np->rxopt.bits.hopopts;
640                 break;
641 
642         case IPV6_AUTHHDR:
643                 val = np->rxopt.bits.authhdr;
644                 break;
645 
646         case IPV6_DSTOPTS:
647                 val = np->rxopt.bits.dstopts;
648                 break;
649 
650         case IPV6_FLOWINFO:
651                 val = np->rxopt.bits.rxflow;
652                 break;
653 
654         case IPV6_UNICAST_HOPS:
655                 val = np->hop_limit;
656                 break;
657 
658         case IPV6_MULTICAST_HOPS:
659                 val = np->mcast_hops;
660                 break;
661 
662         case IPV6_MULTICAST_LOOP:
663                 val = np->mc_loop;
664                 break;
665 
666         case IPV6_MULTICAST_IF:
667                 val = np->mcast_oif;
668                 break;
669 
670         case IPV6_MTU_DISCOVER:
671                 val = np->pmtudisc;
672                 break;
673 
674         case IPV6_RECVERR:
675                 val = np->recverr;
676                 break;
677 
678         case IPV6_FLOWINFO_SEND:
679                 val = np->sndflow;
680                 break;
681 
682         default:
683 #ifdef CONFIG_NETFILTER
684                 lock_sock(sk);
685                 val = nf_getsockopt(sk, PF_INET6, optname, optval, 
686                                     &len);
687                 release_sock(sk);
688                 if (val >= 0)
689                         val = put_user(len, optlen);
690                 return val;
691 #else
692                 return -EINVAL;
693 #endif
694         }
695         len = min_t(unsigned int, sizeof(int), len);
696         if(put_user(len, optlen))
697                 return -EFAULT;
698         if(copy_to_user(optval,&val,len))
699                 return -EFAULT;
700         return 0;
701 }
702 
703 #if defined(MODULE) && defined(CONFIG_SYSCTL)
704 
705 /*
706  *      sysctl registration functions defined in sysctl_net_ipv6.c
707  */
708 
709 extern void ipv6_sysctl_register(void);
710 extern void ipv6_sysctl_unregister(void);
711 #endif
712 
713 void __init ipv6_packet_init(void)
714 {
715         dev_add_pack(&ipv6_packet_type);
716 }
717 
718 void __init ipv6_netdev_notif_init(void)
719 {
720         register_netdevice_notifier(&ipv6_dev_notf);
721 }
722 
723 #ifdef MODULE
724 void ipv6_packet_cleanup(void)
725 {
726         dev_remove_pack(&ipv6_packet_type);
727 }
728 
729 void ipv6_netdev_notif_cleanup(void)
730 {
731         unregister_netdevice_notifier(&ipv6_dev_notf);
732 }
733 #endif
734 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp