]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
ipv6: Allow request socks to contain IPv6 options.
authorHuw Davies <huw@codeweavers.com>
Mon, 27 Jun 2016 19:05:28 +0000 (15:05 -0400)
committerPaul Moore <paul@paul-moore.com>
Mon, 27 Jun 2016 19:05:28 +0000 (15:05 -0400)
If set, these will take precedence over the parent's options during
both sending and child creation.  If they're not set, the parent's
options (if any) will be used.

This is to allow the security_inet_conn_request() hook to modify the
IPv6 options in just the same way that it already may do for IPv4.

Signed-off-by: Huw Davies <huw@codeweavers.com>
Signed-off-by: Paul Moore <paul@paul-moore.com>
include/net/inet_sock.h
net/dccp/ipv6.c
net/ipv4/tcp_input.c
net/ipv6/tcp_ipv6.c

index 012b1f91f3ec4e3b018fb1b900692342eaefe108..236a81034fefec203e27bb73b5a1e5d7d512f8d5 100644 (file)
@@ -97,7 +97,12 @@ struct inet_request_sock {
        u32                     ir_mark;
        union {
                struct ip_options_rcu   *opt;
-               struct sk_buff          *pktopts;
+#if IS_ENABLED(CONFIG_IPV6)
+               struct {
+                       struct ipv6_txoptions   *ipv6_opt;
+                       struct sk_buff          *pktopts;
+               };
+#endif
        };
 };
 
index 4663a01d503991c138c56da530544791832fee5f..3381748bd0f3ba00526207a4f3598a1ddf753a9e 100644 (file)
@@ -216,14 +216,17 @@ static int dccp_v6_send_response(const struct sock *sk, struct request_sock *req
        skb = dccp_make_response(sk, dst, req);
        if (skb != NULL) {
                struct dccp_hdr *dh = dccp_hdr(skb);
+               struct ipv6_txoptions *opt;
 
                dh->dccph_checksum = dccp_v6_csum_finish(skb,
                                                         &ireq->ir_v6_loc_addr,
                                                         &ireq->ir_v6_rmt_addr);
                fl6.daddr = ireq->ir_v6_rmt_addr;
                rcu_read_lock();
-               err = ip6_xmit(sk, skb, &fl6, rcu_dereference(np->opt),
-                              np->tclass);
+               opt = ireq->ipv6_opt;
+               if (!opt)
+                       opt = rcu_dereference(np->opt);
+               err = ip6_xmit(sk, skb, &fl6, opt, np->tclass);
                rcu_read_unlock();
                err = net_xmit_eval(err);
        }
@@ -236,6 +239,7 @@ done:
 static void dccp_v6_reqsk_destructor(struct request_sock *req)
 {
        dccp_feat_list_purge(&dccp_rsk(req)->dreq_featneg);
+       kfree(inet_rsk(req)->ipv6_opt);
        kfree_skb(inet_rsk(req)->pktopts);
 }
 
@@ -494,7 +498,9 @@ static struct sock *dccp_v6_request_recv_sock(const struct sock *sk,
         * Yes, keeping reference count would be much more clever, but we make
         * one more one thing there: reattach optmem to newsk.
         */
-       opt = rcu_dereference(np->opt);
+       opt = ireq->ipv6_opt;
+       if (!opt)
+               opt = rcu_dereference(np->opt);
        if (opt) {
                opt = ipv6_dup_options(newsk, opt);
                RCU_INIT_POINTER(newnp->opt, opt);
index e6e65f79ade82132e1a2e5578ba01f43aed15140..071174c13bf95e195844a63b0f8b5bb84e05b662 100644 (file)
@@ -6146,6 +6146,9 @@ struct request_sock *inet_reqsk_alloc(const struct request_sock_ops *ops,
 
                kmemcheck_annotate_bitfield(ireq, flags);
                ireq->opt = NULL;
+#if IS_ENABLED(CONFIG_IPV6)
+               ireq->pktopts = NULL;
+#endif
                atomic64_set(&ireq->ir_cookie, 0);
                ireq->ireq_state = TCP_NEW_SYN_RECV;
                write_pnet(&ireq->ireq_net, sock_net(sk_listener));
index 711d209f912473b28eddf3eb7f83a51d568d9f4d..18daddc6001c5063a2223f0fc2d90658ce6813f7 100644 (file)
@@ -443,6 +443,7 @@ static int tcp_v6_send_synack(const struct sock *sk, struct dst_entry *dst,
 {
        struct inet_request_sock *ireq = inet_rsk(req);
        struct ipv6_pinfo *np = inet6_sk(sk);
+       struct ipv6_txoptions *opt;
        struct flowi6 *fl6 = &fl->u.ip6;
        struct sk_buff *skb;
        int err = -ENOMEM;
@@ -463,8 +464,10 @@ static int tcp_v6_send_synack(const struct sock *sk, struct dst_entry *dst,
                        fl6->flowlabel = ip6_flowlabel(ipv6_hdr(ireq->pktopts));
 
                rcu_read_lock();
-               err = ip6_xmit(sk, skb, fl6, rcu_dereference(np->opt),
-                              np->tclass);
+               opt = ireq->ipv6_opt;
+               if (!opt)
+                       opt = rcu_dereference(np->opt);
+               err = ip6_xmit(sk, skb, fl6, opt, np->tclass);
                rcu_read_unlock();
                err = net_xmit_eval(err);
        }
@@ -476,6 +479,7 @@ done:
 
 static void tcp_v6_reqsk_destructor(struct request_sock *req)
 {
+       kfree(inet_rsk(req)->ipv6_opt);
        kfree_skb(inet_rsk(req)->pktopts);
 }
 
@@ -1107,7 +1111,9 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *
           but we make one more one thing there: reattach optmem
           to newsk.
         */
-       opt = rcu_dereference(np->opt);
+       opt = ireq->ipv6_opt;
+       if (!opt)
+               opt = rcu_dereference(np->opt);
        if (opt) {
                opt = ipv6_dup_options(newsk, opt);
                RCU_INIT_POINTER(newnp->opt, opt);