X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fipv6%2Fipv6_sockglue.c;h=b20726fa0f8f387b50ab746595eaa39b79b8990f;hb=refs%2Fheads%2Fvserver;hp=1c50e6a63d119b4a7b68ae16dbb90830d30d6899;hpb=16c70f8c1b54b61c3b951b6fb220df250fe09b32;p=linux-2.6.git diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 1c50e6a63..b20726fa0 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -51,6 +51,7 @@ #include #include #include +#include #include #include @@ -239,6 +240,7 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, struct sk_buff *pktopt; if (sk->sk_protocol != IPPROTO_UDP && + sk->sk_protocol != IPPROTO_UDPLITE && sk->sk_protocol != IPPROTO_TCP) break; @@ -276,11 +278,15 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, sk->sk_family = PF_INET; tcp_sync_mss(sk, icsk->icsk_pmtu_cookie); } else { + struct proto *prot = &udp_prot; + + if (sk->sk_protocol == IPPROTO_UDPLITE) + prot = &udplite_prot; local_bh_disable(); sock_prot_dec_use(sk->sk_prot); - sock_prot_inc_use(&udp_prot); + sock_prot_inc_use(prot); local_bh_enable(); - sk->sk_prot = &udp_prot; + sk->sk_prot = prot; sk->sk_socket->ops = &inet_dgram_ops; sk->sk_family = PF_INET; } @@ -408,10 +414,18 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, } /* routing header option needs extra check */ - if (optname == IPV6_RTHDR && opt->srcrt) { + if (optname == IPV6_RTHDR && opt && opt->srcrt) { struct ipv6_rt_hdr *rthdr = opt->srcrt; - if (rthdr->type) + switch (rthdr->type) { + case IPV6_SRCRT_TYPE_0: +#ifdef CONFIG_IPV6_MIP6 + case IPV6_SRCRT_TYPE_2: +#endif + break; + default: goto sticky_done; + } + if ((rthdr->hdrlen & 1) || (rthdr->hdrlen >> 1) != rthdr->segments_left) goto sticky_done; @@ -782,11 +796,15 @@ int compat_ipv6_setsockopt(struct sock *sk, int level, int optname, EXPORT_SYMBOL(compat_ipv6_setsockopt); #endif -static int ipv6_getsockopt_sticky(struct sock *sk, struct ipv6_opt_hdr *hdr, +static int ipv6_getsockopt_sticky(struct sock *sk, struct ipv6_txoptions *opt, char __user *optval, int len) { - if (!hdr) + struct ipv6_opt_hdr *hdr; + + if (!opt || !opt->hopopt) return 0; + hdr = opt->hopopt; + len = min_t(int, len, ipv6_optlen(hdr)); if (copy_to_user(optval, hdr, ipv6_optlen(hdr))) return -EFAULT; @@ -805,6 +823,7 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, switch (optname) { case IPV6_ADDRFORM: if (sk->sk_protocol != IPPROTO_UDP && + sk->sk_protocol != IPPROTO_UDPLITE && sk->sk_protocol != IPPROTO_TCP) return -EINVAL; if (sk->sk_state != TCP_ESTABLISHED) @@ -926,7 +945,7 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, { lock_sock(sk); - len = ipv6_getsockopt_sticky(sk, np->opt->hopopt, + len = ipv6_getsockopt_sticky(sk, np->opt, optval, len); release_sock(sk); return put_user(len, optlen); @@ -963,12 +982,27 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, break; case IPV6_UNICAST_HOPS: - val = np->hop_limit; - break; - case IPV6_MULTICAST_HOPS: - val = np->mcast_hops; + { + struct dst_entry *dst; + + if (optname == IPV6_UNICAST_HOPS) + val = np->hop_limit; + else + val = np->mcast_hops; + + dst = sk_dst_get(sk); + if (dst) { + if (val < 0) + val = dst_metric(dst, RTAX_HOPLIMIT); + if (val < 0) + val = ipv6_get_hoplimit(dst->dev); + dst_release(dst); + } + if (val < 0) + val = ipv6_devconf.hop_limit; break; + } case IPV6_MULTICAST_LOOP: val = np->mc_loop;