ipv6/addrlabel: fix ip6addrlbl_get()
[pandora-kernel.git] / net / ipv6 / addrlabel.c
1 /*
2  * IPv6 Address Label subsystem
3  * for the IPv6 "Default" Source Address Selection
4  *
5  * Copyright (C)2007 USAGI/WIDE Project
6  */
7 /*
8  * Author:
9  *      YOSHIFUJI Hideaki @ USAGI/WIDE Project <yoshfuji@linux-ipv6.org>
10  */
11
12 #include <linux/kernel.h>
13 #include <linux/list.h>
14 #include <linux/rcupdate.h>
15 #include <linux/in6.h>
16 #include <linux/slab.h>
17 #include <net/addrconf.h>
18 #include <linux/if_addrlabel.h>
19 #include <linux/netlink.h>
20 #include <linux/rtnetlink.h>
21
22 #if 0
23 #define ADDRLABEL(x...) printk(x)
24 #else
25 #define ADDRLABEL(x...) do { ; } while(0)
26 #endif
27
28 /*
29  * Policy Table
30  */
31 struct ip6addrlbl_entry
32 {
33 #ifdef CONFIG_NET_NS
34         struct net *lbl_net;
35 #endif
36         struct in6_addr prefix;
37         int prefixlen;
38         int ifindex;
39         int addrtype;
40         u32 label;
41         struct hlist_node list;
42         atomic_t refcnt;
43         struct rcu_head rcu;
44 };
45
46 static struct ip6addrlbl_table
47 {
48         struct hlist_head head;
49         spinlock_t lock;
50         u32 seq;
51 } ip6addrlbl_table;
52
53 static inline
54 struct net *ip6addrlbl_net(const struct ip6addrlbl_entry *lbl)
55 {
56         return read_pnet(&lbl->lbl_net);
57 }
58
59 /*
60  * Default policy table (RFC3484 + extensions)
61  *
62  * prefix               addr_type       label
63  * -------------------------------------------------------------------------
64  * ::1/128              LOOPBACK        0
65  * ::/0                 N/A             1
66  * 2002::/16            N/A             2
67  * ::/96                COMPATv4        3
68  * ::ffff:0:0/96        V4MAPPED        4
69  * fc00::/7             N/A             5               ULA (RFC 4193)
70  * 2001::/32            N/A             6               Teredo (RFC 4380)
71  * 2001:10::/28         N/A             7               ORCHID (RFC 4843)
72  *
73  * Note: 0xffffffff is used if we do not have any policies.
74  */
75
76 #define IPV6_ADDR_LABEL_DEFAULT 0xffffffffUL
77
78 static const __net_initdata struct ip6addrlbl_init_table
79 {
80         const struct in6_addr *prefix;
81         int prefixlen;
82         u32 label;
83 } ip6addrlbl_init_table[] = {
84         {       /* ::/0 */
85                 .prefix = &in6addr_any,
86                 .label = 1,
87         },{     /* fc00::/7 */
88                 .prefix = &(struct in6_addr){{{ 0xfc }}},
89                 .prefixlen = 7,
90                 .label = 5,
91         },{     /* 2002::/16 */
92                 .prefix = &(struct in6_addr){{{ 0x20, 0x02 }}},
93                 .prefixlen = 16,
94                 .label = 2,
95         },{     /* 2001::/32 */
96                 .prefix = &(struct in6_addr){{{ 0x20, 0x01 }}},
97                 .prefixlen = 32,
98                 .label = 6,
99         },{     /* 2001:10::/28 */
100                 .prefix = &(struct in6_addr){{{ 0x20, 0x01, 0x00, 0x10 }}},
101                 .prefixlen = 28,
102                 .label = 7,
103         },{     /* ::ffff:0:0 */
104                 .prefix = &(struct in6_addr){{{ [10] = 0xff, [11] = 0xff }}},
105                 .prefixlen = 96,
106                 .label = 4,
107         },{     /* ::/96 */
108                 .prefix = &in6addr_any,
109                 .prefixlen = 96,
110                 .label = 3,
111         },{     /* ::1/128 */
112                 .prefix = &in6addr_loopback,
113                 .prefixlen = 128,
114                 .label = 0,
115         }
116 };
117
118 /* Object management */
119 static inline void ip6addrlbl_free(struct ip6addrlbl_entry *p)
120 {
121 #ifdef CONFIG_NET_NS
122         release_net(p->lbl_net);
123 #endif
124         kfree(p);
125 }
126
127 static void ip6addrlbl_free_rcu(struct rcu_head *h)
128 {
129         ip6addrlbl_free(container_of(h, struct ip6addrlbl_entry, rcu));
130 }
131
132 static inline int ip6addrlbl_hold(struct ip6addrlbl_entry *p)
133 {
134         return atomic_inc_not_zero(&p->refcnt);
135 }
136
137 static inline void ip6addrlbl_put(struct ip6addrlbl_entry *p)
138 {
139         if (atomic_dec_and_test(&p->refcnt))
140                 call_rcu(&p->rcu, ip6addrlbl_free_rcu);
141 }
142
143 /* Find label */
144 static int __ip6addrlbl_match(struct net *net,
145                               struct ip6addrlbl_entry *p,
146                               const struct in6_addr *addr,
147                               int addrtype, int ifindex)
148 {
149         if (!net_eq(ip6addrlbl_net(p), net))
150                 return 0;
151         if (p->ifindex && p->ifindex != ifindex)
152                 return 0;
153         if (p->addrtype && p->addrtype != addrtype)
154                 return 0;
155         if (!ipv6_prefix_equal(addr, &p->prefix, p->prefixlen))
156                 return 0;
157         return 1;
158 }
159
160 static struct ip6addrlbl_entry *__ipv6_addr_label(struct net *net,
161                                                   const struct in6_addr *addr,
162                                                   int type, int ifindex)
163 {
164         struct hlist_node *pos;
165         struct ip6addrlbl_entry *p;
166         hlist_for_each_entry_rcu(p, pos, &ip6addrlbl_table.head, list) {
167                 if (__ip6addrlbl_match(net, p, addr, type, ifindex))
168                         return p;
169         }
170         return NULL;
171 }
172
173 u32 ipv6_addr_label(struct net *net,
174                     const struct in6_addr *addr, int type, int ifindex)
175 {
176         u32 label;
177         struct ip6addrlbl_entry *p;
178
179         type &= IPV6_ADDR_MAPPED | IPV6_ADDR_COMPATv4 | IPV6_ADDR_LOOPBACK;
180
181         rcu_read_lock();
182         p = __ipv6_addr_label(net, addr, type, ifindex);
183         label = p ? p->label : IPV6_ADDR_LABEL_DEFAULT;
184         rcu_read_unlock();
185
186         ADDRLABEL(KERN_DEBUG "%s(addr=%pI6, type=%d, ifindex=%d) => %08x\n",
187                   __func__, addr, type, ifindex, label);
188
189         return label;
190 }
191
192 /* allocate one entry */
193 static struct ip6addrlbl_entry *ip6addrlbl_alloc(struct net *net,
194                                                  const struct in6_addr *prefix,
195                                                  int prefixlen, int ifindex,
196                                                  u32 label)
197 {
198         struct ip6addrlbl_entry *newp;
199         int addrtype;
200
201         ADDRLABEL(KERN_DEBUG "%s(prefix=%pI6, prefixlen=%d, ifindex=%d, label=%u)\n",
202                   __func__, prefix, prefixlen, ifindex, (unsigned int)label);
203
204         addrtype = ipv6_addr_type(prefix) & (IPV6_ADDR_MAPPED | IPV6_ADDR_COMPATv4 | IPV6_ADDR_LOOPBACK);
205
206         switch (addrtype) {
207         case IPV6_ADDR_MAPPED:
208                 if (prefixlen > 96)
209                         return ERR_PTR(-EINVAL);
210                 if (prefixlen < 96)
211                         addrtype = 0;
212                 break;
213         case IPV6_ADDR_COMPATv4:
214                 if (prefixlen != 96)
215                         addrtype = 0;
216                 break;
217         case IPV6_ADDR_LOOPBACK:
218                 if (prefixlen != 128)
219                         addrtype = 0;
220                 break;
221         }
222
223         newp = kmalloc(sizeof(*newp), GFP_KERNEL);
224         if (!newp)
225                 return ERR_PTR(-ENOMEM);
226
227         ipv6_addr_prefix(&newp->prefix, prefix, prefixlen);
228         newp->prefixlen = prefixlen;
229         newp->ifindex = ifindex;
230         newp->addrtype = addrtype;
231         newp->label = label;
232         INIT_HLIST_NODE(&newp->list);
233 #ifdef CONFIG_NET_NS
234         newp->lbl_net = hold_net(net);
235 #endif
236         atomic_set(&newp->refcnt, 1);
237         return newp;
238 }
239
240 /* add a label */
241 static int __ip6addrlbl_add(struct ip6addrlbl_entry *newp, int replace)
242 {
243         int ret = 0;
244
245         ADDRLABEL(KERN_DEBUG "%s(newp=%p, replace=%d)\n",
246                         __func__,
247                         newp, replace);
248
249         if (hlist_empty(&ip6addrlbl_table.head)) {
250                 hlist_add_head_rcu(&newp->list, &ip6addrlbl_table.head);
251         } else {
252                 struct hlist_node *pos, *n;
253                 struct ip6addrlbl_entry *p = NULL;
254                 hlist_for_each_entry_safe(p, pos, n,
255                                           &ip6addrlbl_table.head, list) {
256                         if (p->prefixlen == newp->prefixlen &&
257                             net_eq(ip6addrlbl_net(p), ip6addrlbl_net(newp)) &&
258                             p->ifindex == newp->ifindex &&
259                             ipv6_addr_equal(&p->prefix, &newp->prefix)) {
260                                 if (!replace) {
261                                         ret = -EEXIST;
262                                         goto out;
263                                 }
264                                 hlist_replace_rcu(&p->list, &newp->list);
265                                 ip6addrlbl_put(p);
266                                 goto out;
267                         } else if ((p->prefixlen == newp->prefixlen && !p->ifindex) ||
268                                    (p->prefixlen < newp->prefixlen)) {
269                                 hlist_add_before_rcu(&newp->list, &p->list);
270                                 goto out;
271                         }
272                 }
273                 hlist_add_after_rcu(&p->list, &newp->list);
274         }
275 out:
276         if (!ret)
277                 ip6addrlbl_table.seq++;
278         return ret;
279 }
280
281 /* add a label */
282 static int ip6addrlbl_add(struct net *net,
283                           const struct in6_addr *prefix, int prefixlen,
284                           int ifindex, u32 label, int replace)
285 {
286         struct ip6addrlbl_entry *newp;
287         int ret = 0;
288
289         ADDRLABEL(KERN_DEBUG "%s(prefix=%pI6, prefixlen=%d, ifindex=%d, label=%u, replace=%d)\n",
290                   __func__, prefix, prefixlen, ifindex, (unsigned int)label,
291                   replace);
292
293         newp = ip6addrlbl_alloc(net, prefix, prefixlen, ifindex, label);
294         if (IS_ERR(newp))
295                 return PTR_ERR(newp);
296         spin_lock(&ip6addrlbl_table.lock);
297         ret = __ip6addrlbl_add(newp, replace);
298         spin_unlock(&ip6addrlbl_table.lock);
299         if (ret)
300                 ip6addrlbl_free(newp);
301         return ret;
302 }
303
304 /* remove a label */
305 static int __ip6addrlbl_del(struct net *net,
306                             const struct in6_addr *prefix, int prefixlen,
307                             int ifindex)
308 {
309         struct ip6addrlbl_entry *p = NULL;
310         struct hlist_node *pos, *n;
311         int ret = -ESRCH;
312
313         ADDRLABEL(KERN_DEBUG "%s(prefix=%pI6, prefixlen=%d, ifindex=%d)\n",
314                   __func__, prefix, prefixlen, ifindex);
315
316         hlist_for_each_entry_safe(p, pos, n, &ip6addrlbl_table.head, list) {
317                 if (p->prefixlen == prefixlen &&
318                     net_eq(ip6addrlbl_net(p), net) &&
319                     p->ifindex == ifindex &&
320                     ipv6_addr_equal(&p->prefix, prefix)) {
321                         hlist_del_rcu(&p->list);
322                         ip6addrlbl_put(p);
323                         ret = 0;
324                         break;
325                 }
326         }
327         return ret;
328 }
329
330 static int ip6addrlbl_del(struct net *net,
331                           const struct in6_addr *prefix, int prefixlen,
332                           int ifindex)
333 {
334         struct in6_addr prefix_buf;
335         int ret;
336
337         ADDRLABEL(KERN_DEBUG "%s(prefix=%pI6, prefixlen=%d, ifindex=%d)\n",
338                   __func__, prefix, prefixlen, ifindex);
339
340         ipv6_addr_prefix(&prefix_buf, prefix, prefixlen);
341         spin_lock(&ip6addrlbl_table.lock);
342         ret = __ip6addrlbl_del(net, &prefix_buf, prefixlen, ifindex);
343         spin_unlock(&ip6addrlbl_table.lock);
344         return ret;
345 }
346
347 /* add default label */
348 static int __net_init ip6addrlbl_net_init(struct net *net)
349 {
350         int err = 0;
351         int i;
352
353         ADDRLABEL(KERN_DEBUG "%s()\n", __func__);
354
355         for (i = 0; i < ARRAY_SIZE(ip6addrlbl_init_table); i++) {
356                 int ret = ip6addrlbl_add(net,
357                                          ip6addrlbl_init_table[i].prefix,
358                                          ip6addrlbl_init_table[i].prefixlen,
359                                          0,
360                                          ip6addrlbl_init_table[i].label, 0);
361                 /* XXX: should we free all rules when we catch an error? */
362                 if (ret && (!err || err != -ENOMEM))
363                         err = ret;
364         }
365         return err;
366 }
367
368 static void __net_exit ip6addrlbl_net_exit(struct net *net)
369 {
370         struct ip6addrlbl_entry *p = NULL;
371         struct hlist_node *pos, *n;
372
373         /* Remove all labels belonging to the exiting net */
374         spin_lock(&ip6addrlbl_table.lock);
375         hlist_for_each_entry_safe(p, pos, n, &ip6addrlbl_table.head, list) {
376                 if (net_eq(ip6addrlbl_net(p), net)) {
377                         hlist_del_rcu(&p->list);
378                         ip6addrlbl_put(p);
379                 }
380         }
381         spin_unlock(&ip6addrlbl_table.lock);
382 }
383
384 static struct pernet_operations ipv6_addr_label_ops = {
385         .init = ip6addrlbl_net_init,
386         .exit = ip6addrlbl_net_exit,
387 };
388
389 int __init ipv6_addr_label_init(void)
390 {
391         spin_lock_init(&ip6addrlbl_table.lock);
392
393         return register_pernet_subsys(&ipv6_addr_label_ops);
394 }
395
396 void ipv6_addr_label_cleanup(void)
397 {
398         unregister_pernet_subsys(&ipv6_addr_label_ops);
399 }
400
401 static const struct nla_policy ifal_policy[IFAL_MAX+1] = {
402         [IFAL_ADDRESS]          = { .len = sizeof(struct in6_addr), },
403         [IFAL_LABEL]            = { .len = sizeof(u32), },
404 };
405
406 static int ip6addrlbl_newdel(struct sk_buff *skb, struct nlmsghdr *nlh,
407                              void *arg)
408 {
409         struct net *net = sock_net(skb->sk);
410         struct ifaddrlblmsg *ifal;
411         struct nlattr *tb[IFAL_MAX+1];
412         struct in6_addr *pfx;
413         u32 label;
414         int err = 0;
415
416         err = nlmsg_parse(nlh, sizeof(*ifal), tb, IFAL_MAX, ifal_policy);
417         if (err < 0)
418                 return err;
419
420         ifal = nlmsg_data(nlh);
421
422         if (ifal->ifal_family != AF_INET6 ||
423             ifal->ifal_prefixlen > 128)
424                 return -EINVAL;
425
426         if (!tb[IFAL_ADDRESS])
427                 return -EINVAL;
428
429         pfx = nla_data(tb[IFAL_ADDRESS]);
430         if (!pfx)
431                 return -EINVAL;
432
433         if (!tb[IFAL_LABEL])
434                 return -EINVAL;
435         label = nla_get_u32(tb[IFAL_LABEL]);
436         if (label == IPV6_ADDR_LABEL_DEFAULT)
437                 return -EINVAL;
438
439         switch(nlh->nlmsg_type) {
440         case RTM_NEWADDRLABEL:
441                 if (ifal->ifal_index &&
442                     !__dev_get_by_index(net, ifal->ifal_index))
443                         return -EINVAL;
444
445                 err = ip6addrlbl_add(net, pfx, ifal->ifal_prefixlen,
446                                      ifal->ifal_index, label,
447                                      nlh->nlmsg_flags & NLM_F_REPLACE);
448                 break;
449         case RTM_DELADDRLABEL:
450                 err = ip6addrlbl_del(net, pfx, ifal->ifal_prefixlen,
451                                      ifal->ifal_index);
452                 break;
453         default:
454                 err = -EOPNOTSUPP;
455         }
456         return err;
457 }
458
459 static inline void ip6addrlbl_putmsg(struct nlmsghdr *nlh,
460                                      int prefixlen, int ifindex, u32 lseq)
461 {
462         struct ifaddrlblmsg *ifal = nlmsg_data(nlh);
463         ifal->ifal_family = AF_INET6;
464         ifal->ifal_prefixlen = prefixlen;
465         ifal->ifal_flags = 0;
466         ifal->ifal_index = ifindex;
467         ifal->ifal_seq = lseq;
468 };
469
470 static int ip6addrlbl_fill(struct sk_buff *skb,
471                            struct ip6addrlbl_entry *p,
472                            u32 lseq,
473                            u32 pid, u32 seq, int event,
474                            unsigned int flags)
475 {
476         struct nlmsghdr *nlh = nlmsg_put(skb, pid, seq, event,
477                                          sizeof(struct ifaddrlblmsg), flags);
478         if (!nlh)
479                 return -EMSGSIZE;
480
481         ip6addrlbl_putmsg(nlh, p->prefixlen, p->ifindex, lseq);
482
483         if (nla_put(skb, IFAL_ADDRESS, 16, &p->prefix) < 0 ||
484             nla_put_u32(skb, IFAL_LABEL, p->label) < 0) {
485                 nlmsg_cancel(skb, nlh);
486                 return -EMSGSIZE;
487         }
488
489         return nlmsg_end(skb, nlh);
490 }
491
492 static int ip6addrlbl_dump(struct sk_buff *skb, struct netlink_callback *cb)
493 {
494         struct net *net = sock_net(skb->sk);
495         struct ip6addrlbl_entry *p;
496         struct hlist_node *pos;
497         int idx = 0, s_idx = cb->args[0];
498         int err;
499
500         rcu_read_lock();
501         hlist_for_each_entry_rcu(p, pos, &ip6addrlbl_table.head, list) {
502                 if (idx >= s_idx &&
503                     net_eq(ip6addrlbl_net(p), net)) {
504                         if ((err = ip6addrlbl_fill(skb, p,
505                                                    ip6addrlbl_table.seq,
506                                                    NETLINK_CB(cb->skb).pid,
507                                                    cb->nlh->nlmsg_seq,
508                                                    RTM_NEWADDRLABEL,
509                                                    NLM_F_MULTI)) <= 0)
510                                 break;
511                 }
512                 idx++;
513         }
514         rcu_read_unlock();
515         cb->args[0] = idx;
516         return skb->len;
517 }
518
519 static inline int ip6addrlbl_msgsize(void)
520 {
521         return NLMSG_ALIGN(sizeof(struct ifaddrlblmsg))
522                 + nla_total_size(16)    /* IFAL_ADDRESS */
523                 + nla_total_size(4);    /* IFAL_LABEL */
524 }
525
526 static int ip6addrlbl_get(struct sk_buff *in_skb, struct nlmsghdr* nlh,
527                           void *arg)
528 {
529         struct net *net = sock_net(in_skb->sk);
530         struct ifaddrlblmsg *ifal;
531         struct nlattr *tb[IFAL_MAX+1];
532         struct in6_addr *addr;
533         u32 lseq;
534         int err = 0;
535         struct ip6addrlbl_entry *p;
536         struct sk_buff *skb;
537
538         err = nlmsg_parse(nlh, sizeof(*ifal), tb, IFAL_MAX, ifal_policy);
539         if (err < 0)
540                 return err;
541
542         ifal = nlmsg_data(nlh);
543
544         if (ifal->ifal_family != AF_INET6 ||
545             ifal->ifal_prefixlen != 128)
546                 return -EINVAL;
547
548         if (ifal->ifal_index &&
549             !__dev_get_by_index(net, ifal->ifal_index))
550                 return -EINVAL;
551
552         if (!tb[IFAL_ADDRESS])
553                 return -EINVAL;
554
555         addr = nla_data(tb[IFAL_ADDRESS]);
556         if (!addr)
557                 return -EINVAL;
558
559         rcu_read_lock();
560         p = __ipv6_addr_label(net, addr, ipv6_addr_type(addr), ifal->ifal_index);
561         if (p && !ip6addrlbl_hold(p))
562                 p = NULL;
563         lseq = ip6addrlbl_table.seq;
564         rcu_read_unlock();
565
566         if (!p) {
567                 err = -ESRCH;
568                 goto out;
569         }
570
571         if (!(skb = nlmsg_new(ip6addrlbl_msgsize(), GFP_KERNEL))) {
572                 ip6addrlbl_put(p);
573                 return -ENOBUFS;
574         }
575
576         err = ip6addrlbl_fill(skb, p, lseq,
577                               NETLINK_CB(in_skb).pid, nlh->nlmsg_seq,
578                               RTM_NEWADDRLABEL, 0);
579
580         ip6addrlbl_put(p);
581
582         if (err < 0) {
583                 WARN_ON(err == -EMSGSIZE);
584                 kfree_skb(skb);
585                 goto out;
586         }
587
588         err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).pid);
589 out:
590         return err;
591 }
592
593 void __init ipv6_addr_label_rtnl_register(void)
594 {
595         __rtnl_register(PF_INET6, RTM_NEWADDRLABEL, ip6addrlbl_newdel,
596                         NULL, NULL);
597         __rtnl_register(PF_INET6, RTM_DELADDRLABEL, ip6addrlbl_newdel,
598                         NULL, NULL);
599         __rtnl_register(PF_INET6, RTM_GETADDRLABEL, ip6addrlbl_get,
600                         ip6addrlbl_dump, NULL);
601 }
602