aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/ipv6_sockglue.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/ipv6_sockglue.c')
-rw-r--r--net/ipv6/ipv6_sockglue.c33
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;
422update: 430update:
@@ -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
838static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, 848static 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