ipv6_sockglue.c (188933ac139a6f8ab06cad369bd0200af947b00d) | ipv6_sockglue.c (63159f29be1df7f93563a8a0f78c5e65fc844ed6) |
---|---|
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 --- 71 unchanged lines hidden (view full) --- 80 *rap = ra->next; 81 write_unlock_bh(&ip6_ra_lock); 82 83 sock_put(sk); 84 kfree(ra); 85 return 0; 86 } 87 } | 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 --- 71 unchanged lines hidden (view full) --- 80 *rap = ra->next; 81 write_unlock_bh(&ip6_ra_lock); 82 83 sock_put(sk); 84 kfree(ra); 85 return 0; 86 } 87 } |
88 if (new_ra == NULL) { | 88 if (!new_ra) { |
89 write_unlock_bh(&ip6_ra_lock); 90 return -ENOBUFS; 91 } 92 new_ra->sk = sk; 93 new_ra->sel = sel; 94 new_ra->next = ra; 95 *rap = new_ra; 96 sock_hold(sk); --- 15 unchanged lines hidden (view full) --- 112 } 113 } 114 opt = xchg(&inet6_sk(sk)->opt, opt); 115 sk_dst_reset(sk); 116 117 return opt; 118} 119 | 89 write_unlock_bh(&ip6_ra_lock); 90 return -ENOBUFS; 91 } 92 new_ra->sk = sk; 93 new_ra->sel = sel; 94 new_ra->next = ra; 95 *rap = new_ra; 96 sock_hold(sk); --- 15 unchanged lines hidden (view full) --- 112 } 113 } 114 opt = xchg(&inet6_sk(sk)->opt, opt); 115 sk_dst_reset(sk); 116 117 return opt; 118} 119 |
120static bool setsockopt_needs_rtnl(int optname) 121{ 122 switch (optname) { 123 case IPV6_ADD_MEMBERSHIP: 124 case IPV6_DROP_MEMBERSHIP: 125 case IPV6_JOIN_ANYCAST: 126 case IPV6_LEAVE_ANYCAST: 127 case MCAST_JOIN_GROUP: 128 case MCAST_LEAVE_GROUP: 129 case MCAST_JOIN_SOURCE_GROUP: 130 case MCAST_LEAVE_SOURCE_GROUP: 131 case MCAST_BLOCK_SOURCE: 132 case MCAST_UNBLOCK_SOURCE: 133 case MCAST_MSFILTER: 134 return true; 135 } 136 return false; 137} 138 |
|
120static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, 121 char __user *optval, unsigned int optlen) 122{ 123 struct ipv6_pinfo *np = inet6_sk(sk); 124 struct net *net = sock_net(sk); 125 int val, valbool; 126 int retv = -ENOPROTOOPT; | 139static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, 140 char __user *optval, unsigned int optlen) 141{ 142 struct ipv6_pinfo *np = inet6_sk(sk); 143 struct net *net = sock_net(sk); 144 int val, valbool; 145 int retv = -ENOPROTOOPT; |
146 bool needs_rtnl = setsockopt_needs_rtnl(optname); |
|
127 | 147 |
128 if (optval == NULL) | 148 if (!optval) |
129 val = 0; 130 else { 131 if (optlen >= sizeof(int)) { 132 if (get_user(val, (int __user *) optval)) 133 return -EFAULT; 134 } else 135 val = 0; 136 } 137 138 valbool = (val != 0); 139 140 if (ip6_mroute_opt(optname)) 141 return ip6_mroute_setsockopt(sk, optname, optval, optlen); 142 | 149 val = 0; 150 else { 151 if (optlen >= sizeof(int)) { 152 if (get_user(val, (int __user *) optval)) 153 return -EFAULT; 154 } else 155 val = 0; 156 } 157 158 valbool = (val != 0); 159 160 if (ip6_mroute_opt(optname)) 161 return ip6_mroute_setsockopt(sk, optname, optval, optlen); 162 |
163 if (needs_rtnl) 164 rtnl_lock(); |
|
143 lock_sock(sk); 144 145 switch (optname) { 146 147 case IPV6_ADDRFORM: 148 if (optlen < sizeof(int)) 149 goto e_inval; 150 if (val == PF_INET) { --- 214 unchanged lines hidden (view full) --- 365 { 366 struct ipv6_txoptions *opt; 367 368 /* remove any sticky options header with a zero option 369 * length, per RFC3542. 370 */ 371 if (optlen == 0) 372 optval = NULL; | 165 lock_sock(sk); 166 167 switch (optname) { 168 169 case IPV6_ADDRFORM: 170 if (optlen < sizeof(int)) 171 goto e_inval; 172 if (val == PF_INET) { --- 214 unchanged lines hidden (view full) --- 387 { 388 struct ipv6_txoptions *opt; 389 390 /* remove any sticky options header with a zero option 391 * length, per RFC3542. 392 */ 393 if (optlen == 0) 394 optval = NULL; |
373 else if (optval == NULL) | 395 else if (!optval) |
374 goto e_inval; 375 else if (optlen < sizeof(struct ipv6_opt_hdr) || 376 optlen & 0x7 || optlen > 8 * 255) 377 goto e_inval; 378 379 /* hop-by-hop / destination options are privileged option */ 380 retv = -EPERM; 381 if (optname != IPV6_RTHDR && !ns_capable(net->user_ns, CAP_NET_RAW)) --- 34 unchanged lines hidden (view full) --- 416 } 417 418 case IPV6_PKTINFO: 419 { 420 struct in6_pktinfo pkt; 421 422 if (optlen == 0) 423 goto e_inval; | 396 goto e_inval; 397 else if (optlen < sizeof(struct ipv6_opt_hdr) || 398 optlen & 0x7 || optlen > 8 * 255) 399 goto e_inval; 400 401 /* hop-by-hop / destination options are privileged option */ 402 retv = -EPERM; 403 if (optname != IPV6_RTHDR && !ns_capable(net->user_ns, CAP_NET_RAW)) --- 34 unchanged lines hidden (view full) --- 438 } 439 440 case IPV6_PKTINFO: 441 { 442 struct in6_pktinfo pkt; 443 444 if (optlen == 0) 445 goto e_inval; |
424 else if (optlen < sizeof(struct in6_pktinfo) || optval == NULL) | 446 else if (optlen < sizeof(struct in6_pktinfo) || !optval) |
425 goto e_inval; 426 427 if (copy_from_user(&pkt, optval, sizeof(struct in6_pktinfo))) { 428 retv = -EFAULT; 429 break; 430 } 431 if (sk->sk_bound_dev_if && pkt.ipi6_ifindex != sk->sk_bound_dev_if) 432 goto e_inval; --- 22 unchanged lines hidden (view full) --- 455 * 1K is surely not enough, 2K per standard header is 16K. 456 */ 457 retv = -EINVAL; 458 if (optlen > 64*1024) 459 break; 460 461 opt = sock_kmalloc(sk, sizeof(*opt) + optlen, GFP_KERNEL); 462 retv = -ENOBUFS; | 447 goto e_inval; 448 449 if (copy_from_user(&pkt, optval, sizeof(struct in6_pktinfo))) { 450 retv = -EFAULT; 451 break; 452 } 453 if (sk->sk_bound_dev_if && pkt.ipi6_ifindex != sk->sk_bound_dev_if) 454 goto e_inval; --- 22 unchanged lines hidden (view full) --- 477 * 1K is surely not enough, 2K per standard header is 16K. 478 */ 479 retv = -EINVAL; 480 if (optlen > 64*1024) 481 break; 482 483 opt = sock_kmalloc(sk, sizeof(*opt) + optlen, GFP_KERNEL); 484 retv = -ENOBUFS; |
463 if (opt == NULL) | 485 if (!opt) |
464 break; 465 466 memset(opt, 0, sizeof(*opt)); 467 opt->tot_len = sizeof(*opt) + optlen; 468 retv = -EFAULT; 469 if (copy_from_user(opt+1, optval, optlen)) 470 goto done; 471 --- 147 unchanged lines hidden (view full) --- 619 break; 620 if (greq.gr_group.ss_family != AF_INET6) { 621 retv = -EADDRNOTAVAIL; 622 break; 623 } 624 psin6 = (struct sockaddr_in6 *)&greq.gr_group; 625 if (optname == MCAST_JOIN_GROUP) 626 retv = ipv6_sock_mc_join(sk, greq.gr_interface, | 486 break; 487 488 memset(opt, 0, sizeof(*opt)); 489 opt->tot_len = sizeof(*opt) + optlen; 490 retv = -EFAULT; 491 if (copy_from_user(opt+1, optval, optlen)) 492 goto done; 493 --- 147 unchanged lines hidden (view full) --- 641 break; 642 if (greq.gr_group.ss_family != AF_INET6) { 643 retv = -EADDRNOTAVAIL; 644 break; 645 } 646 psin6 = (struct sockaddr_in6 *)&greq.gr_group; 647 if (optname == MCAST_JOIN_GROUP) 648 retv = ipv6_sock_mc_join(sk, greq.gr_interface, |
627 &psin6->sin6_addr); | 649 &psin6->sin6_addr); |
628 else 629 retv = ipv6_sock_mc_drop(sk, greq.gr_interface, | 650 else 651 retv = ipv6_sock_mc_drop(sk, greq.gr_interface, |
630 &psin6->sin6_addr); | 652 &psin6->sin6_addr); |
631 break; 632 } 633 case MCAST_JOIN_SOURCE_GROUP: 634 case MCAST_LEAVE_SOURCE_GROUP: 635 case MCAST_BLOCK_SOURCE: 636 case MCAST_UNBLOCK_SOURCE: 637 { 638 struct group_source_req greqs; --- 16 unchanged lines hidden (view full) --- 655 } else if (optname == MCAST_UNBLOCK_SOURCE) { 656 omode = MCAST_EXCLUDE; 657 add = 0; 658 } else if (optname == MCAST_JOIN_SOURCE_GROUP) { 659 struct sockaddr_in6 *psin6; 660 661 psin6 = (struct sockaddr_in6 *)&greqs.gsr_group; 662 retv = ipv6_sock_mc_join(sk, greqs.gsr_interface, | 653 break; 654 } 655 case MCAST_JOIN_SOURCE_GROUP: 656 case MCAST_LEAVE_SOURCE_GROUP: 657 case MCAST_BLOCK_SOURCE: 658 case MCAST_UNBLOCK_SOURCE: 659 { 660 struct group_source_req greqs; --- 16 unchanged lines hidden (view full) --- 677 } else if (optname == MCAST_UNBLOCK_SOURCE) { 678 omode = MCAST_EXCLUDE; 679 add = 0; 680 } else if (optname == MCAST_JOIN_SOURCE_GROUP) { 681 struct sockaddr_in6 *psin6; 682 683 psin6 = (struct sockaddr_in6 *)&greqs.gsr_group; 684 retv = ipv6_sock_mc_join(sk, greqs.gsr_interface, |
663 &psin6->sin6_addr); | 685 &psin6->sin6_addr); |
664 /* prior join w/ different source is ok */ 665 if (retv && retv != -EADDRINUSE) 666 break; 667 omode = MCAST_INCLUDE; 668 add = 1; 669 } else /* MCAST_LEAVE_SOURCE_GROUP */ { 670 omode = MCAST_INCLUDE; 671 add = 0; --- 160 unchanged lines hidden (view full) --- 832 break; 833 case IPV6_AUTOFLOWLABEL: 834 np->autoflowlabel = valbool; 835 retv = 0; 836 break; 837 } 838 839 release_sock(sk); | 686 /* prior join w/ different source is ok */ 687 if (retv && retv != -EADDRINUSE) 688 break; 689 omode = MCAST_INCLUDE; 690 add = 1; 691 } else /* MCAST_LEAVE_SOURCE_GROUP */ { 692 omode = MCAST_INCLUDE; 693 add = 0; --- 160 unchanged lines hidden (view full) --- 854 break; 855 case IPV6_AUTOFLOWLABEL: 856 np->autoflowlabel = valbool; 857 retv = 0; 858 break; 859 } 860 861 release_sock(sk); |
862 if (needs_rtnl) 863 rtnl_unlock(); |
|
840 841 return retv; 842 843e_inval: 844 release_sock(sk); | 864 865 return retv; 866 867e_inval: 868 release_sock(sk); |
869 if (needs_rtnl) 870 rtnl_unlock(); |
|
845 return -EINVAL; 846} 847 848int ipv6_setsockopt(struct sock *sk, int level, int optname, 849 char __user *optval, unsigned int optlen) 850{ 851 int err; 852 --- 506 unchanged lines hidden --- | 871 return -EINVAL; 872} 873 874int ipv6_setsockopt(struct sock *sk, int level, int optname, 875 char __user *optval, unsigned int optlen) 876{ 877 int err; 878 --- 506 unchanged lines hidden --- |