aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/ipv6.h1
-rw-r--r--net/ipv6/ip6_flowlabel.c26
-rw-r--r--net/ipv6/ipv6_sockglue.c28
3 files changed, 55 insertions, 0 deletions
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index dd96638ab8ff..2a5f668cd683 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -250,6 +250,7 @@ struct ipv6_txoptions *fl6_merge_options(struct ipv6_txoptions *opt_space,
250 struct ipv6_txoptions *fopt); 250 struct ipv6_txoptions *fopt);
251void fl6_free_socklist(struct sock *sk); 251void fl6_free_socklist(struct sock *sk);
252int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen); 252int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen);
253int ipv6_flowlabel_opt_get(struct sock *sk, struct in6_flowlabel_req *freq);
253int ip6_flowlabel_init(void); 254int ip6_flowlabel_init(void);
254void ip6_flowlabel_cleanup(void); 255void ip6_flowlabel_cleanup(void);
255 256
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