aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/ip6_flowlabel.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/ip6_flowlabel.c')
-rw-r--r--net/ipv6/ip6_flowlabel.c38
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
484int ipv6_flowlabel_opt_get(struct sock *sk, struct in6_flowlabel_req *freq) 484int 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