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