Merge branch 'misc' of git://git.kernel.org/pub/scm/linux/kernel/git/mmarek/kbuild
[firefly-linux-kernel-4.4.55.git] / net / ipv6 / inet6_connection_sock.c
index e6cee5292a0bf583b66e7478d7a4d7b29f35040a..0251a6005be8ff8d35cffe7fb0e2611b43296158 100644 (file)
@@ -55,26 +55,26 @@ int inet6_csk_bind_conflict(const struct sock *sk,
 EXPORT_SYMBOL_GPL(inet6_csk_bind_conflict);
 
 struct dst_entry *inet6_csk_route_req(struct sock *sk,
+                                     struct flowi6 *fl6,
                                      const struct request_sock *req)
 {
        struct inet6_request_sock *treq = inet6_rsk(req);
        struct ipv6_pinfo *np = inet6_sk(sk);
        struct in6_addr *final_p, final;
        struct dst_entry *dst;
-       struct flowi6 fl6;
 
-       memset(&fl6, 0, sizeof(fl6));
-       fl6.flowi6_proto = IPPROTO_TCP;
-       fl6.daddr = treq->rmt_addr;
-       final_p = fl6_update_dst(&fl6, np->opt, &final);
-       fl6.saddr = treq->loc_addr;
-       fl6.flowi6_oif = sk->sk_bound_dev_if;
-       fl6.flowi6_mark = sk->sk_mark;
-       fl6.fl6_dport = inet_rsk(req)->rmt_port;
-       fl6.fl6_sport = inet_rsk(req)->loc_port;
-       security_req_classify_flow(req, flowi6_to_flowi(&fl6));
-
-       dst = ip6_dst_lookup_flow(sk, &fl6, final_p, false);
+       memset(fl6, 0, sizeof(*fl6));
+       fl6->flowi6_proto = IPPROTO_TCP;
+       fl6->daddr = treq->rmt_addr;
+       final_p = fl6_update_dst(fl6, np->opt, &final);
+       fl6->saddr = treq->loc_addr;
+       fl6->flowi6_oif = treq->iif;
+       fl6->flowi6_mark = sk->sk_mark;
+       fl6->fl6_dport = inet_rsk(req)->rmt_port;
+       fl6->fl6_sport = inet_rsk(req)->loc_port;
+       security_req_classify_flow(req, flowi6_to_flowi(fl6));
+
+       dst = ip6_dst_lookup_flow(sk, fl6, final_p, false);
        if (IS_ERR(dst))
                return NULL;
 
@@ -171,7 +171,8 @@ EXPORT_SYMBOL_GPL(inet6_csk_addr2sockaddr);
 
 static inline
 void __inet6_csk_dst_store(struct sock *sk, struct dst_entry *dst,
-                          struct in6_addr *daddr, struct in6_addr *saddr)
+                          const struct in6_addr *daddr,
+                          const struct in6_addr *saddr)
 {
        __ip6_dst_store(sk, dst, daddr, saddr);
 
@@ -203,43 +204,52 @@ struct dst_entry *__inet6_csk_dst_check(struct sock *sk, u32 cookie)
        return dst;
 }
 
-int inet6_csk_xmit(struct sk_buff *skb, struct flowi *fl_unused)
+static struct dst_entry *inet6_csk_route_socket(struct sock *sk,
+                                               struct flowi6 *fl6)
 {
-       struct sock *sk = skb->sk;
        struct inet_sock *inet = inet_sk(sk);
        struct ipv6_pinfo *np = inet6_sk(sk);
-       struct flowi6 fl6;
-       struct dst_entry *dst;
        struct in6_addr *final_p, final;
-       int res;
+       struct dst_entry *dst;
 
-       memset(&fl6, 0, sizeof(fl6));
-       fl6.flowi6_proto = sk->sk_protocol;
-       fl6.daddr = np->daddr;
-       fl6.saddr = np->saddr;
-       fl6.flowlabel = np->flow_label;
-       IP6_ECN_flow_xmit(sk, fl6.flowlabel);
-       fl6.flowi6_oif = sk->sk_bound_dev_if;
-       fl6.flowi6_mark = sk->sk_mark;
-       fl6.fl6_sport = inet->inet_sport;
-       fl6.fl6_dport = inet->inet_dport;
-       security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
+       memset(fl6, 0, sizeof(*fl6));
+       fl6->flowi6_proto = sk->sk_protocol;
+       fl6->daddr = np->daddr;
+       fl6->saddr = np->saddr;
+       fl6->flowlabel = np->flow_label;
+       IP6_ECN_flow_xmit(sk, fl6->flowlabel);
+       fl6->flowi6_oif = sk->sk_bound_dev_if;
+       fl6->flowi6_mark = sk->sk_mark;
+       fl6->fl6_sport = inet->inet_sport;
+       fl6->fl6_dport = inet->inet_dport;
+       security_sk_classify_flow(sk, flowi6_to_flowi(fl6));
 
-       final_p = fl6_update_dst(&fl6, np->opt, &final);
+       final_p = fl6_update_dst(fl6, np->opt, &final);
 
        dst = __inet6_csk_dst_check(sk, np->dst_cookie);
+       if (!dst) {
+               dst = ip6_dst_lookup_flow(sk, fl6, final_p, false);
 
-       if (dst == NULL) {
-               dst = ip6_dst_lookup_flow(sk, &fl6, final_p, false);
+               if (!IS_ERR(dst))
+                       __inet6_csk_dst_store(sk, dst, NULL, NULL);
+       }
+       return dst;
+}
 
-               if (IS_ERR(dst)) {
-                       sk->sk_err_soft = -PTR_ERR(dst);
-                       sk->sk_route_caps = 0;
-                       kfree_skb(skb);
-                       return PTR_ERR(dst);
-               }
+int inet6_csk_xmit(struct sk_buff *skb, struct flowi *fl_unused)
+{
+       struct sock *sk = skb->sk;
+       struct ipv6_pinfo *np = inet6_sk(sk);
+       struct flowi6 fl6;
+       struct dst_entry *dst;
+       int res;
 
-               __inet6_csk_dst_store(sk, dst, NULL, NULL);
+       dst = inet6_csk_route_socket(sk, &fl6);
+       if (IS_ERR(dst)) {
+               sk->sk_err_soft = -PTR_ERR(dst);
+               sk->sk_route_caps = 0;
+               kfree_skb(skb);
+               return PTR_ERR(dst);
        }
 
        rcu_read_lock();
@@ -253,3 +263,16 @@ int inet6_csk_xmit(struct sk_buff *skb, struct flowi *fl_unused)
        return res;
 }
 EXPORT_SYMBOL_GPL(inet6_csk_xmit);
+
+struct dst_entry *inet6_csk_update_pmtu(struct sock *sk, u32 mtu)
+{
+       struct flowi6 fl6;
+       struct dst_entry *dst = inet6_csk_route_socket(sk, &fl6);
+
+       if (IS_ERR(dst))
+               return NULL;
+       dst->ops->update_pmtu(dst, sk, NULL, mtu);
+
+       return inet6_csk_route_socket(sk, &fl6);
+}
+EXPORT_SYMBOL_GPL(inet6_csk_update_pmtu);