diff options
-rw-r--r-- | include/net/ipv6.h | 1 | ||||
-rw-r--r-- | net/ipv6/ip6_flowlabel.c | 26 | ||||
-rw-r--r-- | net/ipv6/ipv6_sockglue.c | 28 |
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); |
251 | void fl6_free_socklist(struct sock *sk); | 251 | void fl6_free_socklist(struct sock *sk); |
252 | int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen); | 252 | int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen); |
253 | int ipv6_flowlabel_opt_get(struct sock *sk, struct in6_flowlabel_req *freq); | ||
253 | int ip6_flowlabel_init(void); | 254 | int ip6_flowlabel_init(void); |
254 | void ip6_flowlabel_cleanup(void); | 255 | void 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 | ||
478 | int 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 | |||
478 | int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen) | 504 | int 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 | ||