]> Pileus Git - ~andy/linux/blobdiff - net/ipv6/ip6_flowlabel.c
net: Add GRO support for UDP encapsulating protocols
[~andy/linux] / net / ipv6 / ip6_flowlabel.c
index e7fb7106550f1d0c45bfa59b341681175be588b2..dfa41bb4e0dc0a97a9de933716ef9dbbabe5475d 100644 (file)
@@ -210,7 +210,7 @@ static struct ip6_flowlabel *fl_intern(struct net *net,
        spin_lock_bh(&ip6_fl_lock);
        if (label == 0) {
                for (;;) {
-                       fl->label = htonl(net_random())&IPV6_FLOWLABEL_MASK;
+                       fl->label = htonl(prandom_u32())&IPV6_FLOWLABEL_MASK;
                        if (fl->label) {
                                lfl = __fl_lookup(net, fl->label);
                                if (lfl == NULL)
@@ -481,11 +481,22 @@ static inline void fl_link(struct ipv6_pinfo *np, struct ipv6_fl_socklist *sfl,
        spin_unlock_bh(&ip6_sk_fl_lock);
 }
 
-int ipv6_flowlabel_opt_get(struct sock *sk, struct in6_flowlabel_req *freq)
+int ipv6_flowlabel_opt_get(struct sock *sk, struct in6_flowlabel_req *freq,
+                          int flags)
 {
        struct ipv6_pinfo *np = inet6_sk(sk);
        struct ipv6_fl_socklist *sfl;
 
+       if (flags & IPV6_FL_F_REMOTE) {
+               freq->flr_label = np->rcv_flowinfo & IPV6_FLOWLABEL_MASK;
+               return 0;
+       }
+
+       if (np->repflow) {
+               freq->flr_label = np->flow_label;
+               return 0;
+       }
+
        rcu_read_lock_bh();
 
        for_each_sk_fl_rcu(np, sfl) {
@@ -527,6 +538,15 @@ int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen)
 
        switch (freq.flr_action) {
        case IPV6_FL_A_PUT:
+               if (freq.flr_flags & IPV6_FL_F_REFLECT) {
+                       if (sk->sk_protocol != IPPROTO_TCP)
+                               return -ENOPROTOOPT;
+                       if (!np->repflow)
+                               return -ESRCH;
+                       np->flow_label = 0;
+                       np->repflow = 0;
+                       return 0;
+               }
                spin_lock_bh(&ip6_sk_fl_lock);
                for (sflp = &np->ipv6_fl_list;
                     (sfl = rcu_dereference(*sflp))!=NULL;
@@ -567,6 +587,20 @@ int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen)
                return -ESRCH;
 
        case IPV6_FL_A_GET:
+               if (freq.flr_flags & IPV6_FL_F_REFLECT) {
+                       struct net *net = sock_net(sk);
+                       if (net->ipv6.sysctl.flowlabel_consistency) {
+                               net_info_ratelimited("Can not set IPV6_FL_F_REFLECT if flowlabel_consistency sysctl is enable\n");
+                               return -EPERM;
+                       }
+
+                       if (sk->sk_protocol != IPPROTO_TCP)
+                               return -ENOPROTOOPT;
+
+                       np->repflow = 1;
+                       return 0;
+               }
+
                if (freq.flr_label & ~IPV6_FLOWLABEL_MASK)
                        return -EINVAL;