diff options
Diffstat (limited to 'net/dccp/ipv6.c')
| -rw-r--r-- | net/dccp/ipv6.c | 61 | 
1 files changed, 16 insertions, 45 deletions
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index fa9512d86f3..56840b249f3 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -130,6 +130,13 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,  	np = inet6_sk(sk); +	if (type == NDISC_REDIRECT) { +		struct dst_entry *dst = __sk_dst_check(sk, np->dst_cookie); + +		if (dst) +			dst->ops->redirect(dst, sk, skb); +	} +  	if (type == ICMPV6_PKT_TOOBIG) {  		struct dst_entry *dst = NULL; @@ -138,37 +145,12 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,  		if ((1 << sk->sk_state) & (DCCPF_LISTEN | DCCPF_CLOSED))  			goto out; -		/* icmp should have updated the destination cache entry */ -		dst = __sk_dst_check(sk, np->dst_cookie); -		if (dst == NULL) { -			struct inet_sock *inet = inet_sk(sk); -			struct flowi6 fl6; - -			/* BUGGG_FUTURE: Again, it is not clear how -			   to handle rthdr case. Ignore this complexity -			   for now. -			 */ -			memset(&fl6, 0, sizeof(fl6)); -			fl6.flowi6_proto = IPPROTO_DCCP; -			fl6.daddr = np->daddr; -			fl6.saddr = np->saddr; -			fl6.flowi6_oif = sk->sk_bound_dev_if; -			fl6.fl6_dport = inet->inet_dport; -			fl6.fl6_sport = inet->inet_sport; -			security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); - -			dst = ip6_dst_lookup_flow(sk, &fl6, NULL, false); -			if (IS_ERR(dst)) { -				sk->sk_err_soft = -PTR_ERR(dst); -				goto out; -			} -		} else -			dst_hold(dst); +		dst = inet6_csk_update_pmtu(sk, ntohl(info)); +		if (!dst) +			goto out; -		if (inet_csk(sk)->icsk_pmtu_cookie > dst_mtu(dst)) { +		if (inet_csk(sk)->icsk_pmtu_cookie > dst_mtu(dst))  			dccp_sync_mss(sk, dst_mtu(dst)); -		} /* else let the usual retransmit timer handle it */ -		dst_release(dst);  		goto out;  	} @@ -237,7 +219,6 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req,  	struct inet6_request_sock *ireq6 = inet6_rsk(req);  	struct ipv6_pinfo *np = inet6_sk(sk);  	struct sk_buff *skb; -	struct ipv6_txoptions *opt = NULL;  	struct in6_addr *final_p, final;  	struct flowi6 fl6;  	int err = -1; @@ -253,9 +234,8 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req,  	fl6.fl6_sport = inet_rsk(req)->loc_port;  	security_req_classify_flow(req, flowi6_to_flowi(&fl6)); -	opt = np->opt; -	final_p = fl6_update_dst(&fl6, opt, &final); +	final_p = fl6_update_dst(&fl6, np->opt, &final);  	dst = ip6_dst_lookup_flow(sk, &fl6, final_p, false);  	if (IS_ERR(dst)) { @@ -272,13 +252,11 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req,  							 &ireq6->loc_addr,  							 &ireq6->rmt_addr);  		fl6.daddr = ireq6->rmt_addr; -		err = ip6_xmit(sk, skb, &fl6, opt, np->tclass); +		err = ip6_xmit(sk, skb, &fl6, np->opt, np->tclass);  		err = net_xmit_eval(err);  	}  done: -	if (opt != NULL && opt != np->opt) -		sock_kfree_s(sk, opt, opt->tot_len);  	dst_release(dst);  	return err;  } @@ -473,7 +451,6 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk,  	struct inet_sock *newinet;  	struct dccp6_sock *newdp6;  	struct sock *newsk; -	struct ipv6_txoptions *opt;  	if (skb->protocol == htons(ETH_P_IP)) {  		/* @@ -518,7 +495,6 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk,  		return newsk;  	} -	opt = np->opt;  	if (sk_acceptq_is_full(sk))  		goto out_overflow; @@ -530,7 +506,7 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk,  		memset(&fl6, 0, sizeof(fl6));  		fl6.flowi6_proto = IPPROTO_DCCP;  		fl6.daddr = ireq6->rmt_addr; -		final_p = fl6_update_dst(&fl6, opt, &final); +		final_p = fl6_update_dst(&fl6, np->opt, &final);  		fl6.saddr = ireq6->loc_addr;  		fl6.flowi6_oif = sk->sk_bound_dev_if;  		fl6.fl6_dport = inet_rsk(req)->rmt_port; @@ -595,11 +571,8 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk,  	 * Yes, keeping reference count would be much more clever, but we make  	 * one more one thing there: reattach optmem to newsk.  	 */ -	if (opt != NULL) { -		newnp->opt = ipv6_dup_options(newsk, opt); -		if (opt != np->opt) -			sock_kfree_s(sk, opt, opt->tot_len); -	} +	if (np->opt != NULL) +		newnp->opt = ipv6_dup_options(newsk, np->opt);  	inet_csk(newsk)->icsk_ext_hdr_len = 0;  	if (newnp->opt != NULL) @@ -625,8 +598,6 @@ out_nonewsk:  	dst_release(dst);  out:  	NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS); -	if (opt != NULL && opt != np->opt) -		sock_kfree_s(sk, opt, opt->tot_len);  	return NULL;  }  |