diff options
Diffstat (limited to 'net/ipv6/ip6_flowlabel.c')
-rw-r--r-- | net/ipv6/ip6_flowlabel.c | 38 |
1 files changed, 36 insertions, 2 deletions
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c index e7fb7106550f..dfa41bb4e0dc 100644 --- a/net/ipv6/ip6_flowlabel.c +++ b/net/ipv6/ip6_flowlabel.c | |||
@@ -210,7 +210,7 @@ static struct ip6_flowlabel *fl_intern(struct net *net, | |||
210 | spin_lock_bh(&ip6_fl_lock); | 210 | spin_lock_bh(&ip6_fl_lock); |
211 | if (label == 0) { | 211 | if (label == 0) { |
212 | for (;;) { | 212 | for (;;) { |
213 | fl->label = htonl(net_random())&IPV6_FLOWLABEL_MASK; | 213 | fl->label = htonl(prandom_u32())&IPV6_FLOWLABEL_MASK; |
214 | if (fl->label) { | 214 | if (fl->label) { |
215 | lfl = __fl_lookup(net, fl->label); | 215 | lfl = __fl_lookup(net, fl->label); |
216 | if (lfl == NULL) | 216 | if (lfl == NULL) |
@@ -481,11 +481,22 @@ static inline void fl_link(struct ipv6_pinfo *np, struct ipv6_fl_socklist *sfl, | |||
481 | spin_unlock_bh(&ip6_sk_fl_lock); | 481 | spin_unlock_bh(&ip6_sk_fl_lock); |
482 | } | 482 | } |
483 | 483 | ||
484 | int ipv6_flowlabel_opt_get(struct sock *sk, struct in6_flowlabel_req *freq) | 484 | int ipv6_flowlabel_opt_get(struct sock *sk, struct in6_flowlabel_req *freq, |
485 | int flags) | ||
485 | { | 486 | { |
486 | struct ipv6_pinfo *np = inet6_sk(sk); | 487 | struct ipv6_pinfo *np = inet6_sk(sk); |
487 | struct ipv6_fl_socklist *sfl; | 488 | struct ipv6_fl_socklist *sfl; |
488 | 489 | ||
490 | if (flags & IPV6_FL_F_REMOTE) { | ||
491 | freq->flr_label = np->rcv_flowinfo & IPV6_FLOWLABEL_MASK; | ||
492 | return 0; | ||
493 | } | ||
494 | |||
495 | if (np->repflow) { | ||
496 | freq->flr_label = np->flow_label; | ||
497 | return 0; | ||
498 | } | ||
499 | |||
489 | rcu_read_lock_bh(); | 500 | rcu_read_lock_bh(); |
490 | 501 | ||
491 | for_each_sk_fl_rcu(np, sfl) { | 502 | for_each_sk_fl_rcu(np, sfl) { |
@@ -527,6 +538,15 @@ int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen) | |||
527 | 538 | ||
528 | switch (freq.flr_action) { | 539 | switch (freq.flr_action) { |
529 | case IPV6_FL_A_PUT: | 540 | case IPV6_FL_A_PUT: |
541 | if (freq.flr_flags & IPV6_FL_F_REFLECT) { | ||
542 | if (sk->sk_protocol != IPPROTO_TCP) | ||
543 | return -ENOPROTOOPT; | ||
544 | if (!np->repflow) | ||
545 | return -ESRCH; | ||
546 | np->flow_label = 0; | ||
547 | np->repflow = 0; | ||
548 | return 0; | ||
549 | } | ||
530 | spin_lock_bh(&ip6_sk_fl_lock); | 550 | spin_lock_bh(&ip6_sk_fl_lock); |
531 | for (sflp = &np->ipv6_fl_list; | 551 | for (sflp = &np->ipv6_fl_list; |
532 | (sfl = rcu_dereference(*sflp))!=NULL; | 552 | (sfl = rcu_dereference(*sflp))!=NULL; |
@@ -567,6 +587,20 @@ int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen) | |||
567 | return -ESRCH; | 587 | return -ESRCH; |
568 | 588 | ||
569 | case IPV6_FL_A_GET: | 589 | case IPV6_FL_A_GET: |
590 | if (freq.flr_flags & IPV6_FL_F_REFLECT) { | ||
591 | struct net *net = sock_net(sk); | ||
592 | if (net->ipv6.sysctl.flowlabel_consistency) { | ||
593 | net_info_ratelimited("Can not set IPV6_FL_F_REFLECT if flowlabel_consistency sysctl is enable\n"); | ||
594 | return -EPERM; | ||
595 | } | ||
596 | |||
597 | if (sk->sk_protocol != IPPROTO_TCP) | ||
598 | return -ENOPROTOOPT; | ||
599 | |||
600 | np->repflow = 1; | ||
601 | return 0; | ||
602 | } | ||
603 | |||
570 | if (freq.flr_label & ~IPV6_FLOWLABEL_MASK) | 604 | if (freq.flr_label & ~IPV6_FLOWLABEL_MASK) |
571 | return -EINVAL; | 605 | return -EINVAL; |
572 | 606 | ||