aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/inet6_connection_sock.h2
-rw-r--r--net/dccp/ipv6.c35
-rw-r--r--net/ipv6/inet6_connection_sock.c49
-rw-r--r--net/ipv6/tcp_ipv6.c37
4 files changed, 45 insertions, 78 deletions
diff --git a/include/net/inet6_connection_sock.h b/include/net/inet6_connection_sock.h
index df2a857e853d..04642c920431 100644
--- a/include/net/inet6_connection_sock.h
+++ b/include/net/inet6_connection_sock.h
@@ -43,4 +43,6 @@ extern void inet6_csk_reqsk_queue_hash_add(struct sock *sk,
43extern void inet6_csk_addr2sockaddr(struct sock *sk, struct sockaddr *uaddr); 43extern void inet6_csk_addr2sockaddr(struct sock *sk, struct sockaddr *uaddr);
44 44
45extern int inet6_csk_xmit(struct sk_buff *skb, struct flowi *fl); 45extern int inet6_csk_xmit(struct sk_buff *skb, struct flowi *fl);
46
47extern struct dst_entry *inet6_csk_update_pmtu(struct sock *sk, u32 mtu);
46#endif /* _INET6_CONNECTION_SOCK_H */ 48#endif /* _INET6_CONNECTION_SOCK_H */
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index 090c0800ce03..3ee0342e1cec 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -145,39 +145,12 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
145 if ((1 << sk->sk_state) & (DCCPF_LISTEN | DCCPF_CLOSED)) 145 if ((1 << sk->sk_state) & (DCCPF_LISTEN | DCCPF_CLOSED))
146 goto out; 146 goto out;
147 147
148 /* icmp should have updated the destination cache entry */ 148 dst = inet6_csk_update_pmtu(sk, ntohl(info));
149 dst = __sk_dst_check(sk, np->dst_cookie); 149 if (!dst)
150 if (dst == NULL) { 150 goto out;
151 struct inet_sock *inet = inet_sk(sk);
152 struct flowi6 fl6;
153
154 /* BUGGG_FUTURE: Again, it is not clear how
155 to handle rthdr case. Ignore this complexity
156 for now.
157 */
158 memset(&fl6, 0, sizeof(fl6));
159 fl6.flowi6_proto = IPPROTO_DCCP;
160 fl6.daddr = np->daddr;
161 fl6.saddr = np->saddr;
162 fl6.flowi6_oif = sk->sk_bound_dev_if;
163 fl6.fl6_dport = inet->inet_dport;
164 fl6.fl6_sport = inet->inet_sport;
165 security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
166
167 dst = ip6_dst_lookup_flow(sk, &fl6, NULL, false);
168 if (IS_ERR(dst)) {
169 sk->sk_err_soft = -PTR_ERR(dst);
170 goto out;
171 }
172 } else
173 dst_hold(dst);
174
175 dst->ops->update_pmtu(dst, ntohl(info));
176 151
177 if (inet_csk(sk)->icsk_pmtu_cookie > dst_mtu(dst)) { 152 if (inet_csk(sk)->icsk_pmtu_cookie > dst_mtu(dst))
178 dccp_sync_mss(sk, dst_mtu(dst)); 153 dccp_sync_mss(sk, dst_mtu(dst));
179 } /* else let the usual retransmit timer handle it */
180 dst_release(dst);
181 goto out; 154 goto out;
182 } 155 }
183 156
diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c
index bceb14450a1d..62539a4b2dc7 100644
--- a/net/ipv6/inet6_connection_sock.c
+++ b/net/ipv6/inet6_connection_sock.c
@@ -203,15 +203,13 @@ struct dst_entry *__inet6_csk_dst_check(struct sock *sk, u32 cookie)
203 return dst; 203 return dst;
204} 204}
205 205
206int inet6_csk_xmit(struct sk_buff *skb, struct flowi *fl_unused) 206static struct dst_entry *inet6_csk_route_socket(struct sock *sk)
207{ 207{
208 struct sock *sk = skb->sk;
209 struct inet_sock *inet = inet_sk(sk); 208 struct inet_sock *inet = inet_sk(sk);
210 struct ipv6_pinfo *np = inet6_sk(sk); 209 struct ipv6_pinfo *np = inet6_sk(sk);
211 struct flowi6 fl6;
212 struct dst_entry *dst;
213 struct in6_addr *final_p, final; 210 struct in6_addr *final_p, final;
214 int res; 211 struct dst_entry *dst;
212 struct flowi6 fl6;
215 213
216 memset(&fl6, 0, sizeof(fl6)); 214 memset(&fl6, 0, sizeof(fl6));
217 fl6.flowi6_proto = sk->sk_protocol; 215 fl6.flowi6_proto = sk->sk_protocol;
@@ -228,18 +226,29 @@ int inet6_csk_xmit(struct sk_buff *skb, struct flowi *fl_unused)
228 final_p = fl6_update_dst(&fl6, np->opt, &final); 226 final_p = fl6_update_dst(&fl6, np->opt, &final);
229 227
230 dst = __inet6_csk_dst_check(sk, np->dst_cookie); 228 dst = __inet6_csk_dst_check(sk, np->dst_cookie);
231 229 if (!dst) {
232 if (dst == NULL) {
233 dst = ip6_dst_lookup_flow(sk, &fl6, final_p, false); 230 dst = ip6_dst_lookup_flow(sk, &fl6, final_p, false);
234 231
235 if (IS_ERR(dst)) { 232 if (!IS_ERR(dst))
236 sk->sk_err_soft = -PTR_ERR(dst); 233 __inet6_csk_dst_store(sk, dst, NULL, NULL);
237 sk->sk_route_caps = 0; 234 }
238 kfree_skb(skb); 235 return dst;
239 return PTR_ERR(dst); 236}
240 }
241 237
242 __inet6_csk_dst_store(sk, dst, NULL, NULL); 238int inet6_csk_xmit(struct sk_buff *skb, struct flowi *fl_unused)
239{
240 struct sock *sk = skb->sk;
241 struct ipv6_pinfo *np = inet6_sk(sk);
242 struct flowi6 fl6;
243 struct dst_entry *dst;
244 int res;
245
246 dst = inet6_csk_route_socket(sk);
247 if (IS_ERR(dst)) {
248 sk->sk_err_soft = -PTR_ERR(dst);
249 sk->sk_route_caps = 0;
250 kfree_skb(skb);
251 return PTR_ERR(dst);
243 } 252 }
244 253
245 rcu_read_lock(); 254 rcu_read_lock();
@@ -253,3 +262,15 @@ int inet6_csk_xmit(struct sk_buff *skb, struct flowi *fl_unused)
253 return res; 262 return res;
254} 263}
255EXPORT_SYMBOL_GPL(inet6_csk_xmit); 264EXPORT_SYMBOL_GPL(inet6_csk_xmit);
265
266struct dst_entry *inet6_csk_update_pmtu(struct sock *sk, u32 mtu)
267{
268 struct dst_entry *dst = inet6_csk_route_socket(sk);
269
270 if (IS_ERR(dst))
271 return NULL;
272 dst->ops->update_pmtu(dst, mtu);
273
274 return inet6_csk_route_socket(sk);
275}
276EXPORT_SYMBOL_GPL(inet6_csk_update_pmtu);
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 3071f377145c..ecdf241cad02 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -378,43 +378,14 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
378 if ((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE)) 378 if ((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE))
379 goto out; 379 goto out;
380 380
381 /* icmp should have updated the destination cache entry */ 381 dst = inet6_csk_update_pmtu(sk, ntohl(info));
382 dst = __sk_dst_check(sk, np->dst_cookie); 382 if (!dst)
383 383 goto out;
384 if (dst == NULL) {
385 struct inet_sock *inet = inet_sk(sk);
386 struct flowi6 fl6;
387
388 /* BUGGG_FUTURE: Again, it is not clear how
389 to handle rthdr case. Ignore this complexity
390 for now.
391 */
392 memset(&fl6, 0, sizeof(fl6));
393 fl6.flowi6_proto = IPPROTO_TCP;
394 fl6.daddr = np->daddr;
395 fl6.saddr = np->saddr;
396 fl6.flowi6_oif = sk->sk_bound_dev_if;
397 fl6.flowi6_mark = sk->sk_mark;
398 fl6.fl6_dport = inet->inet_dport;
399 fl6.fl6_sport = inet->inet_sport;
400 security_skb_classify_flow(skb, flowi6_to_flowi(&fl6));
401
402 dst = ip6_dst_lookup_flow(sk, &fl6, NULL, false);
403 if (IS_ERR(dst)) {
404 sk->sk_err_soft = -PTR_ERR(dst);
405 goto out;
406 }
407
408 } else
409 dst_hold(dst);
410
411 dst->ops->update_pmtu(dst, ntohl(info));
412 384
413 if (inet_csk(sk)->icsk_pmtu_cookie > dst_mtu(dst)) { 385 if (inet_csk(sk)->icsk_pmtu_cookie > dst_mtu(dst)) {
414 tcp_sync_mss(sk, dst_mtu(dst)); 386 tcp_sync_mss(sk, dst_mtu(dst));
415 tcp_simple_retransmit(sk); 387 tcp_simple_retransmit(sk);
416 } /* else let the usual retransmit timer handle it */ 388 }
417 dst_release(dst);
418 goto out; 389 goto out;
419 } 390 }
420 391