diff options
Diffstat (limited to 'net/ipv6/ipv6_sockglue.c')
-rw-r--r-- | net/ipv6/ipv6_sockglue.c | 33 |
1 files changed, 24 insertions, 9 deletions
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 56d55fecf8ec..c042ce19bd14 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c | |||
@@ -67,7 +67,7 @@ int ip6_ra_control(struct sock *sk, int sel, void (*destructor)(struct sock *)) | |||
67 | 67 | ||
68 | /* RA packet may be delivered ONLY to IPPROTO_RAW socket */ | 68 | /* RA packet may be delivered ONLY to IPPROTO_RAW socket */ |
69 | if (sk->sk_type != SOCK_RAW || inet_sk(sk)->num != IPPROTO_RAW) | 69 | if (sk->sk_type != SOCK_RAW || inet_sk(sk)->num != IPPROTO_RAW) |
70 | return -EINVAL; | 70 | return -ENOPROTOOPT; |
71 | 71 | ||
72 | new_ra = (sel>=0) ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL; | 72 | new_ra = (sel>=0) ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL; |
73 | 73 | ||
@@ -161,9 +161,17 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, | |||
161 | struct ipv6_txoptions *opt; | 161 | struct ipv6_txoptions *opt; |
162 | struct sk_buff *pktopt; | 162 | struct sk_buff *pktopt; |
163 | 163 | ||
164 | if (sk->sk_protocol != IPPROTO_UDP && | 164 | if (sk->sk_type == SOCK_RAW) |
165 | sk->sk_protocol != IPPROTO_UDPLITE && | 165 | break; |
166 | sk->sk_protocol != IPPROTO_TCP) | 166 | |
167 | if (sk->sk_protocol == IPPROTO_UDP || | ||
168 | sk->sk_protocol == IPPROTO_UDPLITE) { | ||
169 | struct udp_sock *up = udp_sk(sk); | ||
170 | if (up->pending == AF_INET6) { | ||
171 | retv = -EBUSY; | ||
172 | break; | ||
173 | } | ||
174 | } else if (sk->sk_protocol != IPPROTO_TCP) | ||
167 | break; | 175 | break; |
168 | 176 | ||
169 | if (sk->sk_state != TCP_ESTABLISHED) { | 177 | if (sk->sk_state != TCP_ESTABLISHED) { |
@@ -416,7 +424,7 @@ sticky_done: | |||
416 | msg.msg_controllen = optlen; | 424 | msg.msg_controllen = optlen; |
417 | msg.msg_control = (void*)(opt+1); | 425 | msg.msg_control = (void*)(opt+1); |
418 | 426 | ||
419 | retv = datagram_send_ctl(&msg, &fl, opt, &junk, &junk); | 427 | retv = datagram_send_ctl(net, &msg, &fl, opt, &junk, &junk); |
420 | if (retv) | 428 | if (retv) |
421 | goto done; | 429 | goto done; |
422 | update: | 430 | update: |
@@ -438,7 +446,7 @@ done: | |||
438 | 446 | ||
439 | case IPV6_MULTICAST_HOPS: | 447 | case IPV6_MULTICAST_HOPS: |
440 | if (sk->sk_type == SOCK_STREAM) | 448 | if (sk->sk_type == SOCK_STREAM) |
441 | goto e_inval; | 449 | break; |
442 | if (optlen < sizeof(int)) | 450 | if (optlen < sizeof(int)) |
443 | goto e_inval; | 451 | goto e_inval; |
444 | if (val > 255 || val < -1) | 452 | if (val > 255 || val < -1) |
@@ -450,13 +458,15 @@ done: | |||
450 | case IPV6_MULTICAST_LOOP: | 458 | case IPV6_MULTICAST_LOOP: |
451 | if (optlen < sizeof(int)) | 459 | if (optlen < sizeof(int)) |
452 | goto e_inval; | 460 | goto e_inval; |
461 | if (val != valbool) | ||
462 | goto e_inval; | ||
453 | np->mc_loop = valbool; | 463 | np->mc_loop = valbool; |
454 | retv = 0; | 464 | retv = 0; |
455 | break; | 465 | break; |
456 | 466 | ||
457 | case IPV6_MULTICAST_IF: | 467 | case IPV6_MULTICAST_IF: |
458 | if (sk->sk_type == SOCK_STREAM) | 468 | if (sk->sk_type == SOCK_STREAM) |
459 | goto e_inval; | 469 | break; |
460 | if (optlen < sizeof(int)) | 470 | if (optlen < sizeof(int)) |
461 | goto e_inval; | 471 | goto e_inval; |
462 | 472 | ||
@@ -832,7 +842,7 @@ static int ipv6_getsockopt_sticky(struct sock *sk, struct ipv6_txoptions *opt, | |||
832 | len = min_t(unsigned int, len, ipv6_optlen(hdr)); | 842 | len = min_t(unsigned int, len, ipv6_optlen(hdr)); |
833 | if (copy_to_user(optval, hdr, len)) | 843 | if (copy_to_user(optval, hdr, len)) |
834 | return -EFAULT; | 844 | return -EFAULT; |
835 | return ipv6_optlen(hdr); | 845 | return len; |
836 | } | 846 | } |
837 | 847 | ||
838 | static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, | 848 | static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, |
@@ -852,7 +862,7 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, | |||
852 | if (sk->sk_protocol != IPPROTO_UDP && | 862 | if (sk->sk_protocol != IPPROTO_UDP && |
853 | sk->sk_protocol != IPPROTO_UDPLITE && | 863 | sk->sk_protocol != IPPROTO_UDPLITE && |
854 | sk->sk_protocol != IPPROTO_TCP) | 864 | sk->sk_protocol != IPPROTO_TCP) |
855 | return -EINVAL; | 865 | return -ENOPROTOOPT; |
856 | if (sk->sk_state != TCP_ESTABLISHED) | 866 | if (sk->sk_state != TCP_ESTABLISHED) |
857 | return -ENOTCONN; | 867 | return -ENOTCONN; |
858 | val = sk->sk_family; | 868 | val = sk->sk_family; |
@@ -866,6 +876,8 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, | |||
866 | return -EINVAL; | 876 | return -EINVAL; |
867 | if (copy_from_user(&gsf, optval, GROUP_FILTER_SIZE(0))) | 877 | if (copy_from_user(&gsf, optval, GROUP_FILTER_SIZE(0))) |
868 | return -EFAULT; | 878 | return -EFAULT; |
879 | if (gsf.gf_group.ss_family != AF_INET6) | ||
880 | return -EADDRNOTAVAIL; | ||
869 | lock_sock(sk); | 881 | lock_sock(sk); |
870 | err = ip6_mc_msfget(sk, &gsf, | 882 | err = ip6_mc_msfget(sk, &gsf, |
871 | (struct group_filter __user *)optval, optlen); | 883 | (struct group_filter __user *)optval, optlen); |
@@ -975,6 +987,9 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, | |||
975 | len = ipv6_getsockopt_sticky(sk, np->opt, | 987 | len = ipv6_getsockopt_sticky(sk, np->opt, |
976 | optname, optval, len); | 988 | optname, optval, len); |
977 | release_sock(sk); | 989 | release_sock(sk); |
990 | /* check if ipv6_getsockopt_sticky() returns err code */ | ||
991 | if (len < 0) | ||
992 | return len; | ||
978 | return put_user(len, optlen); | 993 | return put_user(len, optlen); |
979 | } | 994 | } |
980 | 995 | ||