aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/inet6_connection_sock.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/inet6_connection_sock.c')
-rw-r--r--net/ipv6/inet6_connection_sock.c103
1 files changed, 63 insertions, 40 deletions
diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c
index e6cee5292a0b..0251a6005be8 100644
--- a/net/ipv6/inet6_connection_sock.c
+++ b/net/ipv6/inet6_connection_sock.c
@@ -55,26 +55,26 @@ int inet6_csk_bind_conflict(const struct sock *sk,
55EXPORT_SYMBOL_GPL(inet6_csk_bind_conflict); 55EXPORT_SYMBOL_GPL(inet6_csk_bind_conflict);
56 56
57struct dst_entry *inet6_csk_route_req(struct sock *sk, 57struct dst_entry *inet6_csk_route_req(struct sock *sk,
58 struct flowi6 *fl6,
58 const struct request_sock *req) 59 const struct request_sock *req)
59{ 60{
60 struct inet6_request_sock *treq = inet6_rsk(req); 61 struct inet6_request_sock *treq = inet6_rsk(req);
61 struct ipv6_pinfo *np = inet6_sk(sk); 62 struct ipv6_pinfo *np = inet6_sk(sk);
62 struct in6_addr *final_p, final; 63 struct in6_addr *final_p, final;
63 struct dst_entry *dst; 64 struct dst_entry *dst;
64 struct flowi6 fl6;
65 65
66 memset(&fl6, 0, sizeof(fl6)); 66 memset(fl6, 0, sizeof(*fl6));
67 fl6.flowi6_proto = IPPROTO_TCP; 67 fl6->flowi6_proto = IPPROTO_TCP;
68 fl6.daddr = treq->rmt_addr; 68 fl6->daddr = treq->rmt_addr;
69 final_p = fl6_update_dst(&fl6, np->opt, &final); 69 final_p = fl6_update_dst(fl6, np->opt, &final);
70 fl6.saddr = treq->loc_addr; 70 fl6->saddr = treq->loc_addr;
71 fl6.flowi6_oif = sk->sk_bound_dev_if; 71 fl6->flowi6_oif = treq->iif;
72 fl6.flowi6_mark = sk->sk_mark; 72 fl6->flowi6_mark = sk->sk_mark;
73 fl6.fl6_dport = inet_rsk(req)->rmt_port; 73 fl6->fl6_dport = inet_rsk(req)->rmt_port;
74 fl6.fl6_sport = inet_rsk(req)->loc_port; 74 fl6->fl6_sport = inet_rsk(req)->loc_port;
75 security_req_classify_flow(req, flowi6_to_flowi(&fl6)); 75 security_req_classify_flow(req, flowi6_to_flowi(fl6));
76 76
77 dst = ip6_dst_lookup_flow(sk, &fl6, final_p, false); 77 dst = ip6_dst_lookup_flow(sk, fl6, final_p, false);
78 if (IS_ERR(dst)) 78 if (IS_ERR(dst))
79 return NULL; 79 return NULL;
80 80
@@ -171,7 +171,8 @@ EXPORT_SYMBOL_GPL(inet6_csk_addr2sockaddr);
171 171
172static inline 172static inline
173void __inet6_csk_dst_store(struct sock *sk, struct dst_entry *dst, 173void __inet6_csk_dst_store(struct sock *sk, struct dst_entry *dst,
174 struct in6_addr *daddr, struct in6_addr *saddr) 174 const struct in6_addr *daddr,
175 const struct in6_addr *saddr)
175{ 176{
176 __ip6_dst_store(sk, dst, daddr, saddr); 177 __ip6_dst_store(sk, dst, daddr, saddr);
177 178
@@ -203,43 +204,52 @@ struct dst_entry *__inet6_csk_dst_check(struct sock *sk, u32 cookie)
203 return dst; 204 return dst;
204} 205}
205 206
206int inet6_csk_xmit(struct sk_buff *skb, struct flowi *fl_unused) 207static struct dst_entry *inet6_csk_route_socket(struct sock *sk,
208 struct flowi6 *fl6)
207{ 209{
208 struct sock *sk = skb->sk;
209 struct inet_sock *inet = inet_sk(sk); 210 struct inet_sock *inet = inet_sk(sk);
210 struct ipv6_pinfo *np = inet6_sk(sk); 211 struct ipv6_pinfo *np = inet6_sk(sk);
211 struct flowi6 fl6;
212 struct dst_entry *dst;
213 struct in6_addr *final_p, final; 212 struct in6_addr *final_p, final;
214 int res; 213 struct dst_entry *dst;
215 214
216 memset(&fl6, 0, sizeof(fl6)); 215 memset(fl6, 0, sizeof(*fl6));
217 fl6.flowi6_proto = sk->sk_protocol; 216 fl6->flowi6_proto = sk->sk_protocol;
218 fl6.daddr = np->daddr; 217 fl6->daddr = np->daddr;
219 fl6.saddr = np->saddr; 218 fl6->saddr = np->saddr;
220 fl6.flowlabel = np->flow_label; 219 fl6->flowlabel = np->flow_label;
221 IP6_ECN_flow_xmit(sk, fl6.flowlabel); 220 IP6_ECN_flow_xmit(sk, fl6->flowlabel);
222 fl6.flowi6_oif = sk->sk_bound_dev_if; 221 fl6->flowi6_oif = sk->sk_bound_dev_if;
223 fl6.flowi6_mark = sk->sk_mark; 222 fl6->flowi6_mark = sk->sk_mark;
224 fl6.fl6_sport = inet->inet_sport; 223 fl6->fl6_sport = inet->inet_sport;
225 fl6.fl6_dport = inet->inet_dport; 224 fl6->fl6_dport = inet->inet_dport;
226 security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); 225 security_sk_classify_flow(sk, flowi6_to_flowi(fl6));
227 226
228 final_p = fl6_update_dst(&fl6, np->opt, &final); 227 final_p = fl6_update_dst(fl6, np->opt, &final);
229 228
230 dst = __inet6_csk_dst_check(sk, np->dst_cookie); 229 dst = __inet6_csk_dst_check(sk, np->dst_cookie);
230 if (!dst) {
231 dst = ip6_dst_lookup_flow(sk, fl6, final_p, false);
231 232
232 if (dst == NULL) { 233 if (!IS_ERR(dst))
233 dst = ip6_dst_lookup_flow(sk, &fl6, final_p, false); 234 __inet6_csk_dst_store(sk, dst, NULL, NULL);
235 }
236 return dst;
237}
234 238
235 if (IS_ERR(dst)) { 239int inet6_csk_xmit(struct sk_buff *skb, struct flowi *fl_unused)
236 sk->sk_err_soft = -PTR_ERR(dst); 240{
237 sk->sk_route_caps = 0; 241 struct sock *sk = skb->sk;
238 kfree_skb(skb); 242 struct ipv6_pinfo *np = inet6_sk(sk);
239 return PTR_ERR(dst); 243 struct flowi6 fl6;
240 } 244 struct dst_entry *dst;
245 int res;
241 246
242 __inet6_csk_dst_store(sk, dst, NULL, NULL); 247 dst = inet6_csk_route_socket(sk, &fl6);
248 if (IS_ERR(dst)) {
249 sk->sk_err_soft = -PTR_ERR(dst);
250 sk->sk_route_caps = 0;
251 kfree_skb(skb);
252 return PTR_ERR(dst);
243 } 253 }
244 254
245 rcu_read_lock(); 255 rcu_read_lock();
@@ -253,3 +263,16 @@ int inet6_csk_xmit(struct sk_buff *skb, struct flowi *fl_unused)
253 return res; 263 return res;
254} 264}
255EXPORT_SYMBOL_GPL(inet6_csk_xmit); 265EXPORT_SYMBOL_GPL(inet6_csk_xmit);
266
267struct dst_entry *inet6_csk_update_pmtu(struct sock *sk, u32 mtu)
268{
269 struct flowi6 fl6;
270 struct dst_entry *dst = inet6_csk_route_socket(sk, &fl6);
271
272 if (IS_ERR(dst))
273 return NULL;
274 dst->ops->update_pmtu(dst, sk, NULL, mtu);
275
276 return inet6_csk_route_socket(sk, &fl6);
277}
278EXPORT_SYMBOL_GPL(inet6_csk_update_pmtu);