~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/ipv6/ip6_flowlabel.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-or-later
  2 /*
  3  *      ip6_flowlabel.c         IPv6 flowlabel manager.
  4  *
  5  *      Authors:        Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
  6  */
  7 
  8 #include <linux/capability.h>
  9 #include <linux/errno.h>
 10 #include <linux/types.h>
 11 #include <linux/socket.h>
 12 #include <linux/net.h>
 13 #include <linux/netdevice.h>
 14 #include <linux/in6.h>
 15 #include <linux/proc_fs.h>
 16 #include <linux/seq_file.h>
 17 #include <linux/slab.h>
 18 #include <linux/export.h>
 19 #include <linux/pid_namespace.h>
 20 #include <linux/jump_label_ratelimit.h>
 21 
 22 #include <net/net_namespace.h>
 23 #include <net/sock.h>
 24 
 25 #include <net/ipv6.h>
 26 #include <net/rawv6.h>
 27 #include <net/transp_v6.h>
 28 
 29 #include <linux/uaccess.h>
 30 
 31 #define FL_MIN_LINGER   6       /* Minimal linger. It is set to 6sec specified
 32                                    in old IPv6 RFC. Well, it was reasonable value.
 33                                  */
 34 #define FL_MAX_LINGER   150     /* Maximal linger timeout */
 35 
 36 /* FL hash table */
 37 
 38 #define FL_MAX_PER_SOCK 32
 39 #define FL_MAX_SIZE     4096
 40 #define FL_HASH_MASK    255
 41 #define FL_HASH(l)      (ntohl(l)&FL_HASH_MASK)
 42 
 43 static atomic_t fl_size = ATOMIC_INIT(0);
 44 static struct ip6_flowlabel __rcu *fl_ht[FL_HASH_MASK+1];
 45 
 46 static void ip6_fl_gc(struct timer_list *unused);
 47 static DEFINE_TIMER(ip6_fl_gc_timer, ip6_fl_gc);
 48 
 49 /* FL hash table lock: it protects only of GC */
 50 
 51 static DEFINE_SPINLOCK(ip6_fl_lock);
 52 
 53 /* Big socket sock */
 54 
 55 static DEFINE_SPINLOCK(ip6_sk_fl_lock);
 56 
 57 DEFINE_STATIC_KEY_DEFERRED_FALSE(ipv6_flowlabel_exclusive, HZ);
 58 EXPORT_SYMBOL(ipv6_flowlabel_exclusive);
 59 
 60 #define for_each_fl_rcu(hash, fl)                               \
 61         for (fl = rcu_dereference(fl_ht[(hash)]);               \
 62              fl != NULL;                                        \
 63              fl = rcu_dereference(fl->next))
 64 #define for_each_fl_continue_rcu(fl)                            \
 65         for (fl = rcu_dereference(fl->next);                    \
 66              fl != NULL;                                        \
 67              fl = rcu_dereference(fl->next))
 68 
 69 #define for_each_sk_fl_rcu(np, sfl)                             \
 70         for (sfl = rcu_dereference(np->ipv6_fl_list);   \
 71              sfl != NULL;                                       \
 72              sfl = rcu_dereference(sfl->next))
 73 
 74 static inline struct ip6_flowlabel *__fl_lookup(struct net *net, __be32 label)
 75 {
 76         struct ip6_flowlabel *fl;
 77 
 78         for_each_fl_rcu(FL_HASH(label), fl) {
 79                 if (fl->label == label && net_eq(fl->fl_net, net))
 80                         return fl;
 81         }
 82         return NULL;
 83 }
 84 
 85 static struct ip6_flowlabel *fl_lookup(struct net *net, __be32 label)
 86 {
 87         struct ip6_flowlabel *fl;
 88 
 89         rcu_read_lock();
 90         fl = __fl_lookup(net, label);
 91         if (fl && !atomic_inc_not_zero(&fl->users))
 92                 fl = NULL;
 93         rcu_read_unlock();
 94         return fl;
 95 }
 96 
 97 static bool fl_shared_exclusive(struct ip6_flowlabel *fl)
 98 {
 99         return fl->share == IPV6_FL_S_EXCL ||
100                fl->share == IPV6_FL_S_PROCESS ||
101                fl->share == IPV6_FL_S_USER;
102 }
103 
104 static void fl_free_rcu(struct rcu_head *head)
105 {
106         struct ip6_flowlabel *fl = container_of(head, struct ip6_flowlabel, rcu);
107 
108         if (fl->share == IPV6_FL_S_PROCESS)
109                 put_pid(fl->owner.pid);
110         kfree(fl->opt);
111         kfree(fl);
112 }
113 
114 
115 static void fl_free(struct ip6_flowlabel *fl)
116 {
117         if (!fl)
118                 return;
119 
120         if (fl_shared_exclusive(fl) || fl->opt)
121                 static_branch_slow_dec_deferred(&ipv6_flowlabel_exclusive);
122 
123         call_rcu(&fl->rcu, fl_free_rcu);
124 }
125 
126 static void fl_release(struct ip6_flowlabel *fl)
127 {
128         spin_lock_bh(&ip6_fl_lock);
129 
130         fl->lastuse = jiffies;
131         if (atomic_dec_and_test(&fl->users)) {
132                 unsigned long ttd = fl->lastuse + fl->linger;
133                 if (time_after(ttd, fl->expires))
134                         fl->expires = ttd;
135                 ttd = fl->expires;
136                 if (fl->opt && fl->share == IPV6_FL_S_EXCL) {
137                         struct ipv6_txoptions *opt = fl->opt;
138                         fl->opt = NULL;
139                         kfree(opt);
140                 }
141                 if (!timer_pending(&ip6_fl_gc_timer) ||
142                     time_after(ip6_fl_gc_timer.expires, ttd))
143                         mod_timer(&ip6_fl_gc_timer, ttd);
144         }
145         spin_unlock_bh(&ip6_fl_lock);
146 }
147 
148 static void ip6_fl_gc(struct timer_list *unused)
149 {
150         int i;
151         unsigned long now = jiffies;
152         unsigned long sched = 0;
153 
154         spin_lock(&ip6_fl_lock);
155 
156         for (i = 0; i <= FL_HASH_MASK; i++) {
157                 struct ip6_flowlabel *fl;
158                 struct ip6_flowlabel __rcu **flp;
159 
160                 flp = &fl_ht[i];
161                 while ((fl = rcu_dereference_protected(*flp,
162                                                        lockdep_is_held(&ip6_fl_lock))) != NULL) {
163                         if (atomic_read(&fl->users) == 0) {
164                                 unsigned long ttd = fl->lastuse + fl->linger;
165                                 if (time_after(ttd, fl->expires))
166                                         fl->expires = ttd;
167                                 ttd = fl->expires;
168                                 if (time_after_eq(now, ttd)) {
169                                         *flp = fl->next;
170                                         fl_free(fl);
171                                         atomic_dec(&fl_size);
172                                         continue;
173                                 }
174                                 if (!sched || time_before(ttd, sched))
175                                         sched = ttd;
176                         }
177                         flp = &fl->next;
178                 }
179         }
180         if (!sched && atomic_read(&fl_size))
181                 sched = now + FL_MAX_LINGER;
182         if (sched) {
183                 mod_timer(&ip6_fl_gc_timer, sched);
184         }
185         spin_unlock(&ip6_fl_lock);
186 }
187 
188 static void __net_exit ip6_fl_purge(struct net *net)
189 {
190         int i;
191 
192         spin_lock_bh(&ip6_fl_lock);
193         for (i = 0; i <= FL_HASH_MASK; i++) {
194                 struct ip6_flowlabel *fl;
195                 struct ip6_flowlabel __rcu **flp;
196 
197                 flp = &fl_ht[i];
198                 while ((fl = rcu_dereference_protected(*flp,
199                                                        lockdep_is_held(&ip6_fl_lock))) != NULL) {
200                         if (net_eq(fl->fl_net, net) &&
201                             atomic_read(&fl->users) == 0) {
202                                 *flp = fl->next;
203                                 fl_free(fl);
204                                 atomic_dec(&fl_size);
205                                 continue;
206                         }
207                         flp = &fl->next;
208                 }
209         }
210         spin_unlock_bh(&ip6_fl_lock);
211 }
212 
213 static struct ip6_flowlabel *fl_intern(struct net *net,
214                                        struct ip6_flowlabel *fl, __be32 label)
215 {
216         struct ip6_flowlabel *lfl;
217 
218         fl->label = label & IPV6_FLOWLABEL_MASK;
219 
220         rcu_read_lock();
221         spin_lock_bh(&ip6_fl_lock);
222         if (label == 0) {
223                 for (;;) {
224                         fl->label = htonl(get_random_u32())&IPV6_FLOWLABEL_MASK;
225                         if (fl->label) {
226                                 lfl = __fl_lookup(net, fl->label);
227                                 if (!lfl)
228                                         break;
229                         }
230                 }
231         } else {
232                 /*
233                  * we dropper the ip6_fl_lock, so this entry could reappear
234                  * and we need to recheck with it.
235                  *
236                  * OTOH no need to search the active socket first, like it is
237                  * done in ipv6_flowlabel_opt - sock is locked, so new entry
238                  * with the same label can only appear on another sock
239                  */
240                 lfl = __fl_lookup(net, fl->label);
241                 if (lfl) {
242                         atomic_inc(&lfl->users);
243                         spin_unlock_bh(&ip6_fl_lock);
244                         rcu_read_unlock();
245                         return lfl;
246                 }
247         }
248 
249         fl->lastuse = jiffies;
250         fl->next = fl_ht[FL_HASH(fl->label)];
251         rcu_assign_pointer(fl_ht[FL_HASH(fl->label)], fl);
252         atomic_inc(&fl_size);
253         spin_unlock_bh(&ip6_fl_lock);
254         rcu_read_unlock();
255         return NULL;
256 }
257 
258 
259 
260 /* Socket flowlabel lists */
261 
262 struct ip6_flowlabel *__fl6_sock_lookup(struct sock *sk, __be32 label)
263 {
264         struct ipv6_fl_socklist *sfl;
265         struct ipv6_pinfo *np = inet6_sk(sk);
266 
267         label &= IPV6_FLOWLABEL_MASK;
268 
269         rcu_read_lock();
270         for_each_sk_fl_rcu(np, sfl) {
271                 struct ip6_flowlabel *fl = sfl->fl;
272 
273                 if (fl->label == label && atomic_inc_not_zero(&fl->users)) {
274                         fl->lastuse = jiffies;
275                         rcu_read_unlock();
276                         return fl;
277                 }
278         }
279         rcu_read_unlock();
280         return NULL;
281 }
282 EXPORT_SYMBOL_GPL(__fl6_sock_lookup);
283 
284 void fl6_free_socklist(struct sock *sk)
285 {
286         struct ipv6_pinfo *np = inet6_sk(sk);
287         struct ipv6_fl_socklist *sfl;
288 
289         if (!rcu_access_pointer(np->ipv6_fl_list))
290                 return;
291 
292         spin_lock_bh(&ip6_sk_fl_lock);
293         while ((sfl = rcu_dereference_protected(np->ipv6_fl_list,
294                                                 lockdep_is_held(&ip6_sk_fl_lock))) != NULL) {
295                 np->ipv6_fl_list = sfl->next;
296                 spin_unlock_bh(&ip6_sk_fl_lock);
297 
298                 fl_release(sfl->fl);
299                 kfree_rcu(sfl, rcu);
300 
301                 spin_lock_bh(&ip6_sk_fl_lock);
302         }
303         spin_unlock_bh(&ip6_sk_fl_lock);
304 }
305 
306 /* Service routines */
307 
308 
309 /*
310    It is the only difficult place. flowlabel enforces equal headers
311    before and including routing header, however user may supply options
312    following rthdr.
313  */
314 
315 struct ipv6_txoptions *fl6_merge_options(struct ipv6_txoptions *opt_space,
316                                          struct ip6_flowlabel *fl,
317                                          struct ipv6_txoptions *fopt)
318 {
319         struct ipv6_txoptions *fl_opt = fl->opt;
320 
321         if (!fopt || fopt->opt_flen == 0)
322                 return fl_opt;
323 
324         if (fl_opt) {
325                 opt_space->hopopt = fl_opt->hopopt;
326                 opt_space->dst0opt = fl_opt->dst0opt;
327                 opt_space->srcrt = fl_opt->srcrt;
328                 opt_space->opt_nflen = fl_opt->opt_nflen;
329         } else {
330                 if (fopt->opt_nflen == 0)
331                         return fopt;
332                 opt_space->hopopt = NULL;
333                 opt_space->dst0opt = NULL;
334                 opt_space->srcrt = NULL;
335                 opt_space->opt_nflen = 0;
336         }
337         opt_space->dst1opt = fopt->dst1opt;
338         opt_space->opt_flen = fopt->opt_flen;
339         opt_space->tot_len = fopt->tot_len;
340         return opt_space;
341 }
342 EXPORT_SYMBOL_GPL(fl6_merge_options);
343 
344 static unsigned long check_linger(unsigned long ttl)
345 {
346         if (ttl < FL_MIN_LINGER)
347                 return FL_MIN_LINGER*HZ;
348         if (ttl > FL_MAX_LINGER && !capable(CAP_NET_ADMIN))
349                 return 0;
350         return ttl*HZ;
351 }
352 
353 static int fl6_renew(struct ip6_flowlabel *fl, unsigned long linger, unsigned long expires)
354 {
355         linger = check_linger(linger);
356         if (!linger)
357                 return -EPERM;
358         expires = check_linger(expires);
359         if (!expires)
360                 return -EPERM;
361 
362         spin_lock_bh(&ip6_fl_lock);
363         fl->lastuse = jiffies;
364         if (time_before(fl->linger, linger))
365                 fl->linger = linger;
366         if (time_before(expires, fl->linger))
367                 expires = fl->linger;
368         if (time_before(fl->expires, fl->lastuse + expires))
369                 fl->expires = fl->lastuse + expires;
370         spin_unlock_bh(&ip6_fl_lock);
371 
372         return 0;
373 }
374 
375 static struct ip6_flowlabel *
376 fl_create(struct net *net, struct sock *sk, struct in6_flowlabel_req *freq,
377           sockptr_t optval, int optlen, int *err_p)
378 {
379         struct ip6_flowlabel *fl = NULL;
380         int olen;
381         int addr_type;
382         int err;
383 
384         olen = optlen - CMSG_ALIGN(sizeof(*freq));
385         err = -EINVAL;
386         if (olen > 64 * 1024)
387                 goto done;
388 
389         err = -ENOMEM;
390         fl = kzalloc(sizeof(*fl), GFP_KERNEL);
391         if (!fl)
392                 goto done;
393 
394         if (olen > 0) {
395                 struct msghdr msg;
396                 struct flowi6 flowi6;
397                 struct ipcm6_cookie ipc6;
398 
399                 err = -ENOMEM;
400                 fl->opt = kmalloc(sizeof(*fl->opt) + olen, GFP_KERNEL);
401                 if (!fl->opt)
402                         goto done;
403 
404                 memset(fl->opt, 0, sizeof(*fl->opt));
405                 fl->opt->tot_len = sizeof(*fl->opt) + olen;
406                 err = -EFAULT;
407                 if (copy_from_sockptr_offset(fl->opt + 1, optval,
408                                 CMSG_ALIGN(sizeof(*freq)), olen))
409                         goto done;
410 
411                 msg.msg_controllen = olen;
412                 msg.msg_control = (void *)(fl->opt+1);
413                 memset(&flowi6, 0, sizeof(flowi6));
414 
415                 ipc6.opt = fl->opt;
416                 err = ip6_datagram_send_ctl(net, sk, &msg, &flowi6, &ipc6);
417                 if (err)
418                         goto done;
419                 err = -EINVAL;
420                 if (fl->opt->opt_flen)
421                         goto done;
422                 if (fl->opt->opt_nflen == 0) {
423                         kfree(fl->opt);
424                         fl->opt = NULL;
425                 }
426         }
427 
428         fl->fl_net = net;
429         fl->expires = jiffies;
430         err = fl6_renew(fl, freq->flr_linger, freq->flr_expires);
431         if (err)
432                 goto done;
433         fl->share = freq->flr_share;
434         addr_type = ipv6_addr_type(&freq->flr_dst);
435         if ((addr_type & IPV6_ADDR_MAPPED) ||
436             addr_type == IPV6_ADDR_ANY) {
437                 err = -EINVAL;
438                 goto done;
439         }
440         fl->dst = freq->flr_dst;
441         atomic_set(&fl->users, 1);
442         switch (fl->share) {
443         case IPV6_FL_S_EXCL:
444         case IPV6_FL_S_ANY:
445                 break;
446         case IPV6_FL_S_PROCESS:
447                 fl->owner.pid = get_task_pid(current, PIDTYPE_PID);
448                 break;
449         case IPV6_FL_S_USER:
450                 fl->owner.uid = current_euid();
451                 break;
452         default:
453                 err = -EINVAL;
454                 goto done;
455         }
456         if (fl_shared_exclusive(fl) || fl->opt) {
457                 WRITE_ONCE(sock_net(sk)->ipv6.flowlabel_has_excl, 1);
458                 static_branch_deferred_inc(&ipv6_flowlabel_exclusive);
459         }
460         return fl;
461 
462 done:
463         if (fl) {
464                 kfree(fl->opt);
465                 kfree(fl);
466         }
467         *err_p = err;
468         return NULL;
469 }
470 
471 static int mem_check(struct sock *sk)
472 {
473         struct ipv6_pinfo *np = inet6_sk(sk);
474         struct ipv6_fl_socklist *sfl;
475         int room = FL_MAX_SIZE - atomic_read(&fl_size);
476         int count = 0;
477 
478         if (room > FL_MAX_SIZE - FL_MAX_PER_SOCK)
479                 return 0;
480 
481         rcu_read_lock();
482         for_each_sk_fl_rcu(np, sfl)
483                 count++;
484         rcu_read_unlock();
485 
486         if (room <= 0 ||
487             ((count >= FL_MAX_PER_SOCK ||
488               (count > 0 && room < FL_MAX_SIZE/2) || room < FL_MAX_SIZE/4) &&
489              !capable(CAP_NET_ADMIN)))
490                 return -ENOBUFS;
491 
492         return 0;
493 }
494 
495 static inline void fl_link(struct ipv6_pinfo *np, struct ipv6_fl_socklist *sfl,
496                 struct ip6_flowlabel *fl)
497 {
498         spin_lock_bh(&ip6_sk_fl_lock);
499         sfl->fl = fl;
500         sfl->next = np->ipv6_fl_list;
501         rcu_assign_pointer(np->ipv6_fl_list, sfl);
502         spin_unlock_bh(&ip6_sk_fl_lock);
503 }
504 
505 int ipv6_flowlabel_opt_get(struct sock *sk, struct in6_flowlabel_req *freq,
506                            int flags)
507 {
508         struct ipv6_pinfo *np = inet6_sk(sk);
509         struct ipv6_fl_socklist *sfl;
510 
511         if (flags & IPV6_FL_F_REMOTE) {
512                 freq->flr_label = np->rcv_flowinfo & IPV6_FLOWLABEL_MASK;
513                 return 0;
514         }
515 
516         if (inet6_test_bit(REPFLOW, sk)) {
517                 freq->flr_label = np->flow_label;
518                 return 0;
519         }
520 
521         rcu_read_lock();
522 
523         for_each_sk_fl_rcu(np, sfl) {
524                 if (sfl->fl->label == (np->flow_label & IPV6_FLOWLABEL_MASK)) {
525                         spin_lock_bh(&ip6_fl_lock);
526                         freq->flr_label = sfl->fl->label;
527                         freq->flr_dst = sfl->fl->dst;
528                         freq->flr_share = sfl->fl->share;
529                         freq->flr_expires = (sfl->fl->expires - jiffies) / HZ;
530                         freq->flr_linger = sfl->fl->linger / HZ;
531 
532                         spin_unlock_bh(&ip6_fl_lock);
533                         rcu_read_unlock();
534                         return 0;
535                 }
536         }
537         rcu_read_unlock();
538 
539         return -ENOENT;
540 }
541 
542 #define socklist_dereference(__sflp) \
543         rcu_dereference_protected(__sflp, lockdep_is_held(&ip6_sk_fl_lock))
544 
545 static int ipv6_flowlabel_put(struct sock *sk, struct in6_flowlabel_req *freq)
546 {
547         struct ipv6_pinfo *np = inet6_sk(sk);
548         struct ipv6_fl_socklist __rcu **sflp;
549         struct ipv6_fl_socklist *sfl;
550 
551         if (freq->flr_flags & IPV6_FL_F_REFLECT) {
552                 if (sk->sk_protocol != IPPROTO_TCP)
553                         return -ENOPROTOOPT;
554                 if (!inet6_test_bit(REPFLOW, sk))
555                         return -ESRCH;
556                 np->flow_label = 0;
557                 inet6_clear_bit(REPFLOW, sk);
558                 return 0;
559         }
560 
561         spin_lock_bh(&ip6_sk_fl_lock);
562         for (sflp = &np->ipv6_fl_list;
563              (sfl = socklist_dereference(*sflp)) != NULL;
564              sflp = &sfl->next) {
565                 if (sfl->fl->label == freq->flr_label)
566                         goto found;
567         }
568         spin_unlock_bh(&ip6_sk_fl_lock);
569         return -ESRCH;
570 found:
571         if (freq->flr_label == (np->flow_label & IPV6_FLOWLABEL_MASK))
572                 np->flow_label &= ~IPV6_FLOWLABEL_MASK;
573         *sflp = sfl->next;
574         spin_unlock_bh(&ip6_sk_fl_lock);
575         fl_release(sfl->fl);
576         kfree_rcu(sfl, rcu);
577         return 0;
578 }
579 
580 static int ipv6_flowlabel_renew(struct sock *sk, struct in6_flowlabel_req *freq)
581 {
582         struct ipv6_pinfo *np = inet6_sk(sk);
583         struct net *net = sock_net(sk);
584         struct ipv6_fl_socklist *sfl;
585         int err;
586 
587         rcu_read_lock();
588         for_each_sk_fl_rcu(np, sfl) {
589                 if (sfl->fl->label == freq->flr_label) {
590                         err = fl6_renew(sfl->fl, freq->flr_linger,
591                                         freq->flr_expires);
592                         rcu_read_unlock();
593                         return err;
594                 }
595         }
596         rcu_read_unlock();
597 
598         if (freq->flr_share == IPV6_FL_S_NONE &&
599             ns_capable(net->user_ns, CAP_NET_ADMIN)) {
600                 struct ip6_flowlabel *fl = fl_lookup(net, freq->flr_label);
601 
602                 if (fl) {
603                         err = fl6_renew(fl, freq->flr_linger,
604                                         freq->flr_expires);
605                         fl_release(fl);
606                         return err;
607                 }
608         }
609         return -ESRCH;
610 }
611 
612 static int ipv6_flowlabel_get(struct sock *sk, struct in6_flowlabel_req *freq,
613                 sockptr_t optval, int optlen)
614 {
615         struct ipv6_fl_socklist *sfl, *sfl1 = NULL;
616         struct ip6_flowlabel *fl, *fl1 = NULL;
617         struct ipv6_pinfo *np = inet6_sk(sk);
618         struct net *net = sock_net(sk);
619         int err;
620 
621         if (freq->flr_flags & IPV6_FL_F_REFLECT) {
622                 if (net->ipv6.sysctl.flowlabel_consistency) {
623                         net_info_ratelimited("Can not set IPV6_FL_F_REFLECT if flowlabel_consistency sysctl is enable\n");
624                         return -EPERM;
625                 }
626 
627                 if (sk->sk_protocol != IPPROTO_TCP)
628                         return -ENOPROTOOPT;
629                 inet6_set_bit(REPFLOW, sk);
630                 return 0;
631         }
632 
633         if (freq->flr_label & ~IPV6_FLOWLABEL_MASK)
634                 return -EINVAL;
635         if (net->ipv6.sysctl.flowlabel_state_ranges &&
636             (freq->flr_label & IPV6_FLOWLABEL_STATELESS_FLAG))
637                 return -ERANGE;
638 
639         fl = fl_create(net, sk, freq, optval, optlen, &err);
640         if (!fl)
641                 return err;
642 
643         sfl1 = kmalloc(sizeof(*sfl1), GFP_KERNEL);
644 
645         if (freq->flr_label) {
646                 err = -EEXIST;
647                 rcu_read_lock();
648                 for_each_sk_fl_rcu(np, sfl) {
649                         if (sfl->fl->label == freq->flr_label) {
650                                 if (freq->flr_flags & IPV6_FL_F_EXCL) {
651                                         rcu_read_unlock();
652                                         goto done;
653                                 }
654                                 fl1 = sfl->fl;
655                                 if (!atomic_inc_not_zero(&fl1->users))
656                                         fl1 = NULL;
657                                 break;
658                         }
659                 }
660                 rcu_read_unlock();
661 
662                 if (!fl1)
663                         fl1 = fl_lookup(net, freq->flr_label);
664                 if (fl1) {
665 recheck:
666                         err = -EEXIST;
667                         if (freq->flr_flags&IPV6_FL_F_EXCL)
668                                 goto release;
669                         err = -EPERM;
670                         if (fl1->share == IPV6_FL_S_EXCL ||
671                             fl1->share != fl->share ||
672                             ((fl1->share == IPV6_FL_S_PROCESS) &&
673                              (fl1->owner.pid != fl->owner.pid)) ||
674                             ((fl1->share == IPV6_FL_S_USER) &&
675                              !uid_eq(fl1->owner.uid, fl->owner.uid)))
676                                 goto release;
677 
678                         err = -ENOMEM;
679                         if (!sfl1)
680                                 goto release;
681                         if (fl->linger > fl1->linger)
682                                 fl1->linger = fl->linger;
683                         if ((long)(fl->expires - fl1->expires) > 0)
684                                 fl1->expires = fl->expires;
685                         fl_link(np, sfl1, fl1);
686                         fl_free(fl);
687                         return 0;
688 
689 release:
690                         fl_release(fl1);
691                         goto done;
692                 }
693         }
694         err = -ENOENT;
695         if (!(freq->flr_flags & IPV6_FL_F_CREATE))
696                 goto done;
697 
698         err = -ENOMEM;
699         if (!sfl1)
700                 goto done;
701 
702         err = mem_check(sk);
703         if (err != 0)
704                 goto done;
705 
706         fl1 = fl_intern(net, fl, freq->flr_label);
707         if (fl1)
708                 goto recheck;
709 
710         if (!freq->flr_label) {
711                 size_t offset = offsetof(struct in6_flowlabel_req, flr_label);
712 
713                 if (copy_to_sockptr_offset(optval, offset, &fl->label,
714                                 sizeof(fl->label))) {
715                         /* Intentionally ignore fault. */
716                 }
717         }
718 
719         fl_link(np, sfl1, fl);
720         return 0;
721 done:
722         fl_free(fl);
723         kfree(sfl1);
724         return err;
725 }
726 
727 int ipv6_flowlabel_opt(struct sock *sk, sockptr_t optval, int optlen)
728 {
729         struct in6_flowlabel_req freq;
730 
731         if (optlen < sizeof(freq))
732                 return -EINVAL;
733         if (copy_from_sockptr(&freq, optval, sizeof(freq)))
734                 return -EFAULT;
735 
736         switch (freq.flr_action) {
737         case IPV6_FL_A_PUT:
738                 return ipv6_flowlabel_put(sk, &freq);
739         case IPV6_FL_A_RENEW:
740                 return ipv6_flowlabel_renew(sk, &freq);
741         case IPV6_FL_A_GET:
742                 return ipv6_flowlabel_get(sk, &freq, optval, optlen);
743         default:
744                 return -EINVAL;
745         }
746 }
747 
748 #ifdef CONFIG_PROC_FS
749 
750 struct ip6fl_iter_state {
751         struct seq_net_private p;
752         struct pid_namespace *pid_ns;
753         int bucket;
754 };
755 
756 #define ip6fl_seq_private(seq)  ((struct ip6fl_iter_state *)(seq)->private)
757 
758 static struct ip6_flowlabel *ip6fl_get_first(struct seq_file *seq)
759 {
760         struct ip6_flowlabel *fl = NULL;
761         struct ip6fl_iter_state *state = ip6fl_seq_private(seq);
762         struct net *net = seq_file_net(seq);
763 
764         for (state->bucket = 0; state->bucket <= FL_HASH_MASK; ++state->bucket) {
765                 for_each_fl_rcu(state->bucket, fl) {
766                         if (net_eq(fl->fl_net, net))
767                                 goto out;
768                 }
769         }
770         fl = NULL;
771 out:
772         return fl;
773 }
774 
775 static struct ip6_flowlabel *ip6fl_get_next(struct seq_file *seq, struct ip6_flowlabel *fl)
776 {
777         struct ip6fl_iter_state *state = ip6fl_seq_private(seq);
778         struct net *net = seq_file_net(seq);
779 
780         for_each_fl_continue_rcu(fl) {
781                 if (net_eq(fl->fl_net, net))
782                         goto out;
783         }
784 
785 try_again:
786         if (++state->bucket <= FL_HASH_MASK) {
787                 for_each_fl_rcu(state->bucket, fl) {
788                         if (net_eq(fl->fl_net, net))
789                                 goto out;
790                 }
791                 goto try_again;
792         }
793         fl = NULL;
794 
795 out:
796         return fl;
797 }
798 
799 static struct ip6_flowlabel *ip6fl_get_idx(struct seq_file *seq, loff_t pos)
800 {
801         struct ip6_flowlabel *fl = ip6fl_get_first(seq);
802         if (fl)
803                 while (pos && (fl = ip6fl_get_next(seq, fl)) != NULL)
804                         --pos;
805         return pos ? NULL : fl;
806 }
807 
808 static void *ip6fl_seq_start(struct seq_file *seq, loff_t *pos)
809         __acquires(RCU)
810 {
811         struct ip6fl_iter_state *state = ip6fl_seq_private(seq);
812 
813         state->pid_ns = proc_pid_ns(file_inode(seq->file)->i_sb);
814 
815         rcu_read_lock();
816         return *pos ? ip6fl_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;
817 }
818 
819 static void *ip6fl_seq_next(struct seq_file *seq, void *v, loff_t *pos)
820 {
821         struct ip6_flowlabel *fl;
822 
823         if (v == SEQ_START_TOKEN)
824                 fl = ip6fl_get_first(seq);
825         else
826                 fl = ip6fl_get_next(seq, v);
827         ++*pos;
828         return fl;
829 }
830 
831 static void ip6fl_seq_stop(struct seq_file *seq, void *v)
832         __releases(RCU)
833 {
834         rcu_read_unlock();
835 }
836 
837 static int ip6fl_seq_show(struct seq_file *seq, void *v)
838 {
839         struct ip6fl_iter_state *state = ip6fl_seq_private(seq);
840         if (v == SEQ_START_TOKEN) {
841                 seq_puts(seq, "Label S Owner  Users  Linger Expires  Dst                              Opt\n");
842         } else {
843                 struct ip6_flowlabel *fl = v;
844                 seq_printf(seq,
845                            "%05X %-1d %-6d %-6d %-6ld %-8ld %pi6 %-4d\n",
846                            (unsigned int)ntohl(fl->label),
847                            fl->share,
848                            ((fl->share == IPV6_FL_S_PROCESS) ?
849                             pid_nr_ns(fl->owner.pid, state->pid_ns) :
850                             ((fl->share == IPV6_FL_S_USER) ?
851                              from_kuid_munged(seq_user_ns(seq), fl->owner.uid) :
852                              0)),
853                            atomic_read(&fl->users),
854                            fl->linger/HZ,
855                            (long)(fl->expires - jiffies)/HZ,
856                            &fl->dst,
857                            fl->opt ? fl->opt->opt_nflen : 0);
858         }
859         return 0;
860 }
861 
862 static const struct seq_operations ip6fl_seq_ops = {
863         .start  =       ip6fl_seq_start,
864         .next   =       ip6fl_seq_next,
865         .stop   =       ip6fl_seq_stop,
866         .show   =       ip6fl_seq_show,
867 };
868 
869 static int __net_init ip6_flowlabel_proc_init(struct net *net)
870 {
871         if (!proc_create_net("ip6_flowlabel", 0444, net->proc_net,
872                         &ip6fl_seq_ops, sizeof(struct ip6fl_iter_state)))
873                 return -ENOMEM;
874         return 0;
875 }
876 
877 static void __net_exit ip6_flowlabel_proc_fini(struct net *net)
878 {
879         remove_proc_entry("ip6_flowlabel", net->proc_net);
880 }
881 #else
882 static inline int ip6_flowlabel_proc_init(struct net *net)
883 {
884         return 0;
885 }
886 static inline void ip6_flowlabel_proc_fini(struct net *net)
887 {
888 }
889 #endif
890 
891 static void __net_exit ip6_flowlabel_net_exit(struct net *net)
892 {
893         ip6_fl_purge(net);
894         ip6_flowlabel_proc_fini(net);
895 }
896 
897 static struct pernet_operations ip6_flowlabel_net_ops = {
898         .init = ip6_flowlabel_proc_init,
899         .exit = ip6_flowlabel_net_exit,
900 };
901 
902 int ip6_flowlabel_init(void)
903 {
904         return register_pernet_subsys(&ip6_flowlabel_net_ops);
905 }
906 
907 void ip6_flowlabel_cleanup(void)
908 {
909         static_key_deferred_flush(&ipv6_flowlabel_exclusive);
910         del_timer(&ip6_fl_gc_timer);
911         unregister_pernet_subsys(&ip6_flowlabel_net_ops);
912 }
913 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php