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 ---