sctp: add support for setting flowlabel when adding a transport
authorXin Long <lucien.xin@gmail.com>
Mon, 2 Jul 2018 10:21:14 +0000 (18:21 +0800)
committerDavid S. Miller <davem@davemloft.net>
Wed, 4 Jul 2018 02:36:54 +0000 (11:36 +0900)
Struct sockaddr_in6 has the member sin6_flowinfo that includes the
ipv6 flowlabel, it should also support for setting flowlabel when
adding a transport whose ipaddr is from userspace.

Note that addrinfo in sctp_sendmsg is using struct in6_addr for
the secondary addrs, which doesn't contain sin6_flowinfo, and
it needs to copy sin6_flowinfo from the primary addr.

Signed-off-by: Xin Long <lucien.xin@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/sctp/associola.c
net/sctp/socket.c

index 16ecfbc956149a6066fd961f1d5cda15852a1bdb..297d9cf960b928532aa2769c47f76fdb5f64efbf 100644 (file)
@@ -650,8 +650,16 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
        peer->sackdelay = asoc->sackdelay;
        peer->sackfreq = asoc->sackfreq;
 
-       if (addr->sa.sa_family == AF_INET6)
-               peer->flowlabel = asoc->flowlabel;
+       if (addr->sa.sa_family == AF_INET6) {
+               __be32 info = addr->v6.sin6_flowinfo;
+
+               if (info) {
+                       peer->flowlabel = ntohl(info & IPV6_FLOWLABEL_MASK);
+                       peer->flowlabel |= SCTP_FLOWLABEL_SET_MASK;
+               } else {
+                       peer->flowlabel = asoc->flowlabel;
+               }
+       }
        peer->dscp = asoc->dscp;
 
        /* Enable/disable heartbeat, SACK delay, and path MTU discovery
index 50b7ef975b42c16897bdb50d695ae4a961fe799a..502c0d7cb105e27306df08155527d147e4fdac5f 100644 (file)
@@ -1697,6 +1697,7 @@ static int sctp_sendmsg_new_asoc(struct sock *sk, __u16 sflags,
        struct sctp_association *asoc;
        enum sctp_scope scope;
        struct cmsghdr *cmsg;
+       __be32 flowinfo = 0;
        struct sctp_af *af;
        int err;
 
@@ -1781,6 +1782,9 @@ static int sctp_sendmsg_new_asoc(struct sock *sk, __u16 sflags,
        if (!cmsgs->addrs_msg)
                return 0;
 
+       if (daddr->sa.sa_family == AF_INET6)
+               flowinfo = daddr->v6.sin6_flowinfo;
+
        /* sendv addr list parse */
        for_each_cmsghdr(cmsg, cmsgs->addrs_msg) {
                struct sctp_transport *transport;
@@ -1813,6 +1817,7 @@ static int sctp_sendmsg_new_asoc(struct sock *sk, __u16 sflags,
                        }
 
                        dlen = sizeof(struct in6_addr);
+                       daddr->v6.sin6_flowinfo = flowinfo;
                        daddr->v6.sin6_family = AF_INET6;
                        daddr->v6.sin6_port = htons(asoc->peer.port);
                        memcpy(&daddr->v6.sin6_addr, CMSG_DATA(cmsg), dlen);