ipv6: process socket-level control messages in IPv6
authorSoheil Hassas Yeganeh <soheil@google.com>
Sun, 3 Apr 2016 03:08:11 +0000 (23:08 -0400)
committerDavid S. Miller <davem@davemloft.net>
Mon, 4 Apr 2016 19:50:30 +0000 (15:50 -0400)
Process socket-level control messages by invoking
__sock_cmsg_send in ip6_datagram_send_ctl for control messages on
the SOL_SOCKET layer.

This makes sure whenever ip6_datagram_send_ctl is called for
udp and raw, we also process socket-level control messages.

This is a bit uglier than IPv4, since IPv6 does not have
something like ipcm_cookie. Perhaps we can later create
a control message cookie for IPv6?

Note that this commit interprets new control messages that
were ignored before. As such, this commit does not change
the behavior of IPv6 control messages.

Signed-off-by: Soheil Hassas Yeganeh <soheil@google.com>
Acked-by: Willem de Bruijn <willemb@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/transp_v6.h
net/ipv6/datagram.c
net/ipv6/ip6_flowlabel.c
net/ipv6/ipv6_sockglue.c
net/ipv6/raw.c
net/ipv6/udp.c
net/l2tp/l2tp_ip6.c

index b927413dde861c9db9cfaa621745de0c376de865..2b1c3450ab20d57f9faa1268291252179b232efb 100644 (file)
@@ -42,7 +42,8 @@ void ip6_datagram_recv_specific_ctl(struct sock *sk, struct msghdr *msg,
 
 int ip6_datagram_send_ctl(struct net *net, struct sock *sk, struct msghdr *msg,
                          struct flowi6 *fl6, struct ipv6_txoptions *opt,
-                         int *hlimit, int *tclass, int *dontfrag);
+                         int *hlimit, int *tclass, int *dontfrag,
+                         struct sockcm_cookie *sockc);
 
 void ip6_dgram_sock_seq_show(struct seq_file *seq, struct sock *sp,
                             __u16 srcp, __u16 destp, int bucket);
index 428162155280ca2af782ea9fd9fa26e0d1666d89..a73d70119fcd7748aef5d906dad09cb59c99fb75 100644 (file)
@@ -685,7 +685,8 @@ EXPORT_SYMBOL_GPL(ip6_datagram_recv_ctl);
 int ip6_datagram_send_ctl(struct net *net, struct sock *sk,
                          struct msghdr *msg, struct flowi6 *fl6,
                          struct ipv6_txoptions *opt,
-                         int *hlimit, int *tclass, int *dontfrag)
+                         int *hlimit, int *tclass, int *dontfrag,
+                         struct sockcm_cookie *sockc)
 {
        struct in6_pktinfo *src_info;
        struct cmsghdr *cmsg;
@@ -702,6 +703,12 @@ int ip6_datagram_send_ctl(struct net *net, struct sock *sk,
                        goto exit_f;
                }
 
+               if (cmsg->cmsg_level == SOL_SOCKET) {
+                       if (__sock_cmsg_send(sk, msg, cmsg, sockc))
+                               return -EINVAL;
+                       continue;
+               }
+
                if (cmsg->cmsg_level != SOL_IPV6)
                        continue;
 
index dc2db4f7b182c4ebc1a8a51487a3d2e893955df9..35d3ddc328f807a2d25edd99510f313d153eca62 100644 (file)
@@ -372,6 +372,7 @@ fl_create(struct net *net, struct sock *sk, struct in6_flowlabel_req *freq,
        if (olen > 0) {
                struct msghdr msg;
                struct flowi6 flowi6;
+               struct sockcm_cookie sockc_junk;
                int junk;
 
                err = -ENOMEM;
@@ -390,7 +391,7 @@ fl_create(struct net *net, struct sock *sk, struct in6_flowlabel_req *freq,
                memset(&flowi6, 0, sizeof(flowi6));
 
                err = ip6_datagram_send_ctl(net, sk, &msg, &flowi6, fl->opt,
-                                           &junk, &junk, &junk);
+                                           &junk, &junk, &junk, &sockc_junk);
                if (err)
                        goto done;
                err = -EINVAL;
index 4449ad1f81147cab79c44209f3f2a73dc1f6a934..a5557d22f89ea9dde0fb9d33811449fdcf8b3134 100644 (file)
@@ -471,6 +471,7 @@ sticky_done:
                struct ipv6_txoptions *opt = NULL;
                struct msghdr msg;
                struct flowi6 fl6;
+               struct sockcm_cookie sockc_junk;
                int junk;
 
                memset(&fl6, 0, sizeof(fl6));
@@ -503,7 +504,7 @@ sticky_done:
                msg.msg_control = (void *)(opt+1);
 
                retv = ip6_datagram_send_ctl(net, sk, &msg, &fl6, opt, &junk,
-                                            &junk, &junk);
+                                            &junk, &junk, &sockc_junk);
                if (retv)
                        goto done;
 update:
index fa59dd7a427e88a4da70575ae66556bf02923369..f175ec0a97ce9cc25ca4dc8f4f6ddf5b2185e148 100644 (file)
@@ -745,6 +745,7 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
        struct dst_entry *dst = NULL;
        struct raw6_frag_vec rfv;
        struct flowi6 fl6;
+       struct sockcm_cookie sockc;
        int addr_len = msg->msg_namelen;
        int hlimit = -1;
        int tclass = -1;
@@ -821,13 +822,16 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
        if (fl6.flowi6_oif == 0)
                fl6.flowi6_oif = sk->sk_bound_dev_if;
 
+       sockc.tsflags = 0;
+
        if (msg->msg_controllen) {
                opt = &opt_space;
                memset(opt, 0, sizeof(struct ipv6_txoptions));
                opt->tot_len = sizeof(struct ipv6_txoptions);
 
                err = ip6_datagram_send_ctl(sock_net(sk), sk, msg, &fl6, opt,
-                                           &hlimit, &tclass, &dontfrag);
+                                           &hlimit, &tclass, &dontfrag,
+                                           &sockc);
                if (err < 0) {
                        fl6_sock_release(flowlabel);
                        return err;
index 8125931106be670b13e186c577141bc3d1fb574b..2a787af421637c4e54e921299ef563e16ca86c92 100644 (file)
@@ -1128,6 +1128,7 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
        int connected = 0;
        int is_udplite = IS_UDPLITE(sk);
        int (*getfrag)(void *, char *, int, int, int, struct sk_buff *);
+       struct sockcm_cookie sockc;
 
        /* destination address check */
        if (sin6) {
@@ -1247,6 +1248,7 @@ do_udp_sendmsg:
                fl6.flowi6_oif = np->sticky_pktinfo.ipi6_ifindex;
 
        fl6.flowi6_mark = sk->sk_mark;
+       sockc.tsflags = 0;
 
        if (msg->msg_controllen) {
                opt = &opt_space;
@@ -1254,7 +1256,8 @@ do_udp_sendmsg:
                opt->tot_len = sizeof(*opt);
 
                err = ip6_datagram_send_ctl(sock_net(sk), sk, msg, &fl6, opt,
-                                           &hlimit, &tclass, &dontfrag);
+                                           &hlimit, &tclass, &dontfrag,
+                                           &sockc);
                if (err < 0) {
                        fl6_sock_release(flowlabel);
                        return err;
index 6b54ff3ff4cb8e7af49e7ee315cc78cfca148007..4f29a4a0f3606266b0114f0e394077e1b185e977 100644 (file)
@@ -492,6 +492,7 @@ static int l2tp_ip6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
        struct ip6_flowlabel *flowlabel = NULL;
        struct dst_entry *dst = NULL;
        struct flowi6 fl6;
+       struct sockcm_cookie sockc_unused = {0};
        int addr_len = msg->msg_namelen;
        int hlimit = -1;
        int tclass = -1;
@@ -562,9 +563,10 @@ static int l2tp_ip6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
                memset(opt, 0, sizeof(struct ipv6_txoptions));
                opt->tot_len = sizeof(struct ipv6_txoptions);
 
-               err = ip6_datagram_send_ctl(sock_net(sk), sk, msg, &fl6, opt,
-                                           &hlimit, &tclass, &dontfrag);
-               if (err < 0) {
+                err = ip6_datagram_send_ctl(sock_net(sk), sk, msg, &fl6, opt,
+                                            &hlimit, &tclass, &dontfrag,
+                                            &sockc_unused);
+                if (err < 0) {
                        fl6_sock_release(flowlabel);
                        return err;
                }