diff options
Diffstat (limited to 'net/ipv6/inet6_connection_sock.c')
| -rw-r--r-- | net/ipv6/inet6_connection_sock.c | 103 |
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, | |||
| 55 | EXPORT_SYMBOL_GPL(inet6_csk_bind_conflict); | 55 | EXPORT_SYMBOL_GPL(inet6_csk_bind_conflict); |
| 56 | 56 | ||
| 57 | struct dst_entry *inet6_csk_route_req(struct sock *sk, | 57 | struct 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 | ||
| 172 | static inline | 172 | static inline |
| 173 | void __inet6_csk_dst_store(struct sock *sk, struct dst_entry *dst, | 173 | void __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 | ||
| 206 | int inet6_csk_xmit(struct sk_buff *skb, struct flowi *fl_unused) | 207 | static 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)) { | 239 | int 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 | } |
| 255 | EXPORT_SYMBOL_GPL(inet6_csk_xmit); | 265 | EXPORT_SYMBOL_GPL(inet6_csk_xmit); |
| 266 | |||
| 267 | struct 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 | } | ||
| 278 | EXPORT_SYMBOL_GPL(inet6_csk_update_pmtu); | ||
