aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorFlorent Fourcot <florent.fourcot@enst-bretagne.fr>2013-11-07 11:53:12 -0500
committerDavid S. Miller <davem@davemloft.net>2013-11-08 13:42:57 -0500
commit3fdfa5ff50aee5b524fb22b6e0e511b73752a257 (patch)
tree8f29df0bc744c02169588a0719bb67a306705c8e /net
parent3797d3e8462efdaadb64164ca540626b55fe8336 (diff)
ipv6: enable IPV6_FLOWLABEL_MGR for getsockopt
It is already possible to set/put/renew a label with IPV6_FLOWLABEL_MGR and setsockopt. This patch add the possibility to get information about this label (current value, time before expiration, etc). It helps application to take decision for a renew or a release of the label. v2: * Add spin_lock to prevent race condition * return -ENOENT if no result found * check if flr_action is GET v3: * move the spin_lock to protect only the relevant code Signed-off-by: Florent Fourcot <florent.fourcot@enst-bretagne.fr> Acked-by: Hannes Frederic Sowa <hannes@stressinduktion.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/ipv6/ip6_flowlabel.c26
-rw-r--r--net/ipv6/ipv6_sockglue.c28
2 files changed, 54 insertions, 0 deletions
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c
index 819578e92499..4a06ed01d0c3 100644
--- a/net/ipv6/ip6_flowlabel.c
+++ b/net/ipv6/ip6_flowlabel.c
@@ -475,6 +475,32 @@ static inline void fl_link(struct ipv6_pinfo *np, struct ipv6_fl_socklist *sfl,
475 spin_unlock_bh(&ip6_sk_fl_lock); 475 spin_unlock_bh(&ip6_sk_fl_lock);
476} 476}
477 477
478int ipv6_flowlabel_opt_get(struct sock *sk, struct in6_flowlabel_req *freq)
479{
480 struct ipv6_pinfo *np = inet6_sk(sk);
481 struct ipv6_fl_socklist *sfl;
482
483 rcu_read_lock_bh();
484
485 for_each_sk_fl_rcu(np, sfl) {
486 if (sfl->fl->label == (np->flow_label & IPV6_FLOWLABEL_MASK)) {
487 spin_lock_bh(&ip6_fl_lock);
488 freq->flr_label = sfl->fl->label;
489 freq->flr_dst = sfl->fl->dst;
490 freq->flr_share = sfl->fl->share;
491 freq->flr_expires = (sfl->fl->expires - jiffies) / HZ;
492 freq->flr_linger = sfl->fl->linger / HZ;
493
494 spin_unlock_bh(&ip6_fl_lock);
495 rcu_read_unlock_bh();
496 return 0;
497 }
498 }
499 rcu_read_unlock_bh();
500
501 return -ENOENT;
502}
503
478int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen) 504int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen)
479{ 505{
480 int uninitialized_var(err); 506 int uninitialized_var(err);
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index 4919a8e6063e..1c6ce3119ff8 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -1212,6 +1212,34 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
1212 val = np->sndflow; 1212 val = np->sndflow;
1213 break; 1213 break;
1214 1214
1215 case IPV6_FLOWLABEL_MGR:
1216 {
1217 struct in6_flowlabel_req freq;
1218
1219 if (len < sizeof(freq))
1220 return -EINVAL;
1221
1222 if (copy_from_user(&freq, optval, sizeof(freq)))
1223 return -EFAULT;
1224
1225 if (freq.flr_action != IPV6_FL_A_GET)
1226 return -EINVAL;
1227
1228 len = sizeof(freq);
1229 memset(&freq, 0, sizeof(freq));
1230
1231 val = ipv6_flowlabel_opt_get(sk, &freq);
1232 if (val < 0)
1233 return val;
1234
1235 if (put_user(len, optlen))
1236 return -EFAULT;
1237 if (copy_to_user(optval, &freq, len))
1238 return -EFAULT;
1239
1240 return 0;
1241 }
1242
1215 case IPV6_ADDR_PREFERENCES: 1243 case IPV6_ADDR_PREFERENCES:
1216 val = 0; 1244 val = 0;
1217 1245