Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e7712f1a authored by YOSHIFUJI Hideaki's avatar YOSHIFUJI Hideaki Committed by David S. Miller
Browse files

[IPV6]: Share common code-paths for sticky socket options.

parent cee89473
Loading
Loading
Loading
Loading
+25 −39
Original line number Diff line number Diff line
@@ -103,6 +103,29 @@ int ip6_ra_control(struct sock *sk, int sel, void (*destructor)(struct sock *))
	return 0;
}

static
struct ipv6_txoptions *ipv6_update_options(struct sock *sk,
					   struct ipv6_txoptions *opt)
{
	if (inet_sk(sk)->is_icsk) {
		if (opt &&
		    !((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE)) &&
		    inet_sk(sk)->daddr != LOOPBACK4_IPV6) {
			struct inet_connection_sock *icsk = inet_csk(sk);
			icsk->icsk_ext_hdr_len = opt->opt_flen + opt->opt_nflen;
			icsk->icsk_sync_mss(sk, icsk->icsk_pmtu_cookie);
		}
		opt = xchg(&inet6_sk(sk)->opt, opt);
	} else {
		write_lock(&sk->sk_dst_lock);
		opt = xchg(&inet6_sk(sk)->opt, opt);
		write_unlock(&sk->sk_dst_lock);
	}
	sk_dst_reset(sk);

	return opt;
}

static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
		    char __user *optval, int optlen)
{
@@ -351,25 +374,7 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
		}

		retv = 0;
		if (inet_sk(sk)->is_icsk) {
			if (opt) {
				struct inet_connection_sock *icsk = inet_csk(sk);
				if (!((1 << sk->sk_state) &
				      (TCPF_LISTEN | TCPF_CLOSE))
				    && inet_sk(sk)->daddr != LOOPBACK4_IPV6) {
					icsk->icsk_ext_hdr_len =
						opt->opt_flen + opt->opt_nflen;
					icsk->icsk_sync_mss(sk, icsk->icsk_pmtu_cookie);
				}
			}
			opt = xchg(&np->opt, opt);
			sk_dst_reset(sk);
		} else {
			write_lock(&sk->sk_dst_lock);
			opt = xchg(&np->opt, opt);
			write_unlock(&sk->sk_dst_lock);
			sk_dst_reset(sk);
		}
		opt = ipv6_update_options(sk, opt);
sticky_done:
		if (opt)
			sock_kfree_s(sk, opt, opt->tot_len);
@@ -415,26 +420,7 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
			goto done;
update:
		retv = 0;
		if (inet_sk(sk)->is_icsk) {
			if (opt) {
				struct inet_connection_sock *icsk = inet_csk(sk);
				if (!((1 << sk->sk_state) &
				      (TCPF_LISTEN | TCPF_CLOSE))
				    && inet_sk(sk)->daddr != LOOPBACK4_IPV6) {
					icsk->icsk_ext_hdr_len =
						opt->opt_flen + opt->opt_nflen;
					icsk->icsk_sync_mss(sk, icsk->icsk_pmtu_cookie);
				}
			}
			opt = xchg(&np->opt, opt);
			sk_dst_reset(sk);
		} else {
			write_lock(&sk->sk_dst_lock);
			opt = xchg(&np->opt, opt);
			write_unlock(&sk->sk_dst_lock);
			sk_dst_reset(sk);
		}

		opt = ipv6_update_options(sk, opt);
done:
		if (opt)
			sock_kfree_s(sk, opt, opt->tot_len);