0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #include <linux/kernel.h>
0014 #include <linux/list.h>
0015 #include <linux/rcupdate.h>
0016 #include <linux/in6.h>
0017 #include <linux/slab.h>
0018 #include <net/addrconf.h>
0019 #include <linux/if_addrlabel.h>
0020 #include <linux/netlink.h>
0021 #include <linux/rtnetlink.h>
0022
0023 #if 0
0024 #define ADDRLABEL(x...) printk(x)
0025 #else
0026 #define ADDRLABEL(x...) do { ; } while (0)
0027 #endif
0028
0029
0030
0031
0032 struct ip6addrlbl_entry {
0033 struct in6_addr prefix;
0034 int prefixlen;
0035 int ifindex;
0036 int addrtype;
0037 u32 label;
0038 struct hlist_node list;
0039 struct rcu_head rcu;
0040 };
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063 #define IPV6_ADDR_LABEL_DEFAULT 0xffffffffUL
0064
0065 static const __net_initconst struct ip6addrlbl_init_table
0066 {
0067 const struct in6_addr *prefix;
0068 int prefixlen;
0069 u32 label;
0070 } ip6addrlbl_init_table[] = {
0071 {
0072 .prefix = &in6addr_any,
0073 .label = 1,
0074 }, {
0075 .prefix = &(struct in6_addr){ { { 0xfc } } } ,
0076 .prefixlen = 7,
0077 .label = 5,
0078 }, {
0079 .prefix = &(struct in6_addr){ { { 0xfe, 0xc0 } } },
0080 .prefixlen = 10,
0081 .label = 11,
0082 }, {
0083 .prefix = &(struct in6_addr){ { { 0x20, 0x02 } } },
0084 .prefixlen = 16,
0085 .label = 2,
0086 }, {
0087 .prefix = &(struct in6_addr){ { { 0x3f, 0xfe } } },
0088 .prefixlen = 16,
0089 .label = 12,
0090 }, {
0091 .prefix = &(struct in6_addr){ { { 0x20, 0x01 } } },
0092 .prefixlen = 32,
0093 .label = 6,
0094 }, {
0095 .prefix = &(struct in6_addr){ { { 0x20, 0x01, 0x00, 0x10 } } },
0096 .prefixlen = 28,
0097 .label = 7,
0098 }, {
0099 .prefix = &(struct in6_addr){ { { [10] = 0xff, [11] = 0xff } } },
0100 .prefixlen = 96,
0101 .label = 4,
0102 }, {
0103 .prefix = &in6addr_any,
0104 .prefixlen = 96,
0105 .label = 3,
0106 }, {
0107 .prefix = &in6addr_loopback,
0108 .prefixlen = 128,
0109 .label = 0,
0110 }
0111 };
0112
0113
0114 static bool __ip6addrlbl_match(const struct ip6addrlbl_entry *p,
0115 const struct in6_addr *addr,
0116 int addrtype, int ifindex)
0117 {
0118 if (p->ifindex && p->ifindex != ifindex)
0119 return false;
0120 if (p->addrtype && p->addrtype != addrtype)
0121 return false;
0122 if (!ipv6_prefix_equal(addr, &p->prefix, p->prefixlen))
0123 return false;
0124 return true;
0125 }
0126
0127 static struct ip6addrlbl_entry *__ipv6_addr_label(struct net *net,
0128 const struct in6_addr *addr,
0129 int type, int ifindex)
0130 {
0131 struct ip6addrlbl_entry *p;
0132
0133 hlist_for_each_entry_rcu(p, &net->ipv6.ip6addrlbl_table.head, list) {
0134 if (__ip6addrlbl_match(p, addr, type, ifindex))
0135 return p;
0136 }
0137 return NULL;
0138 }
0139
0140 u32 ipv6_addr_label(struct net *net,
0141 const struct in6_addr *addr, int type, int ifindex)
0142 {
0143 u32 label;
0144 struct ip6addrlbl_entry *p;
0145
0146 type &= IPV6_ADDR_MAPPED | IPV6_ADDR_COMPATv4 | IPV6_ADDR_LOOPBACK;
0147
0148 rcu_read_lock();
0149 p = __ipv6_addr_label(net, addr, type, ifindex);
0150 label = p ? p->label : IPV6_ADDR_LABEL_DEFAULT;
0151 rcu_read_unlock();
0152
0153 ADDRLABEL(KERN_DEBUG "%s(addr=%pI6, type=%d, ifindex=%d) => %08x\n",
0154 __func__, addr, type, ifindex, label);
0155
0156 return label;
0157 }
0158
0159
0160 static struct ip6addrlbl_entry *ip6addrlbl_alloc(const struct in6_addr *prefix,
0161 int prefixlen, int ifindex,
0162 u32 label)
0163 {
0164 struct ip6addrlbl_entry *newp;
0165 int addrtype;
0166
0167 ADDRLABEL(KERN_DEBUG "%s(prefix=%pI6, prefixlen=%d, ifindex=%d, label=%u)\n",
0168 __func__, prefix, prefixlen, ifindex, (unsigned int)label);
0169
0170 addrtype = ipv6_addr_type(prefix) & (IPV6_ADDR_MAPPED | IPV6_ADDR_COMPATv4 | IPV6_ADDR_LOOPBACK);
0171
0172 switch (addrtype) {
0173 case IPV6_ADDR_MAPPED:
0174 if (prefixlen > 96)
0175 return ERR_PTR(-EINVAL);
0176 if (prefixlen < 96)
0177 addrtype = 0;
0178 break;
0179 case IPV6_ADDR_COMPATv4:
0180 if (prefixlen != 96)
0181 addrtype = 0;
0182 break;
0183 case IPV6_ADDR_LOOPBACK:
0184 if (prefixlen != 128)
0185 addrtype = 0;
0186 break;
0187 }
0188
0189 newp = kmalloc(sizeof(*newp), GFP_KERNEL);
0190 if (!newp)
0191 return ERR_PTR(-ENOMEM);
0192
0193 ipv6_addr_prefix(&newp->prefix, prefix, prefixlen);
0194 newp->prefixlen = prefixlen;
0195 newp->ifindex = ifindex;
0196 newp->addrtype = addrtype;
0197 newp->label = label;
0198 INIT_HLIST_NODE(&newp->list);
0199 return newp;
0200 }
0201
0202
0203 static int __ip6addrlbl_add(struct net *net, struct ip6addrlbl_entry *newp,
0204 int replace)
0205 {
0206 struct ip6addrlbl_entry *last = NULL, *p = NULL;
0207 struct hlist_node *n;
0208 int ret = 0;
0209
0210 ADDRLABEL(KERN_DEBUG "%s(newp=%p, replace=%d)\n", __func__, newp,
0211 replace);
0212
0213 hlist_for_each_entry_safe(p, n, &net->ipv6.ip6addrlbl_table.head, list) {
0214 if (p->prefixlen == newp->prefixlen &&
0215 p->ifindex == newp->ifindex &&
0216 ipv6_addr_equal(&p->prefix, &newp->prefix)) {
0217 if (!replace) {
0218 ret = -EEXIST;
0219 goto out;
0220 }
0221 hlist_replace_rcu(&p->list, &newp->list);
0222 kfree_rcu(p, rcu);
0223 goto out;
0224 } else if ((p->prefixlen == newp->prefixlen && !p->ifindex) ||
0225 (p->prefixlen < newp->prefixlen)) {
0226 hlist_add_before_rcu(&newp->list, &p->list);
0227 goto out;
0228 }
0229 last = p;
0230 }
0231 if (last)
0232 hlist_add_behind_rcu(&newp->list, &last->list);
0233 else
0234 hlist_add_head_rcu(&newp->list, &net->ipv6.ip6addrlbl_table.head);
0235 out:
0236 if (!ret)
0237 net->ipv6.ip6addrlbl_table.seq++;
0238 return ret;
0239 }
0240
0241
0242 static int ip6addrlbl_add(struct net *net,
0243 const struct in6_addr *prefix, int prefixlen,
0244 int ifindex, u32 label, int replace)
0245 {
0246 struct ip6addrlbl_entry *newp;
0247 int ret = 0;
0248
0249 ADDRLABEL(KERN_DEBUG "%s(prefix=%pI6, prefixlen=%d, ifindex=%d, label=%u, replace=%d)\n",
0250 __func__, prefix, prefixlen, ifindex, (unsigned int)label,
0251 replace);
0252
0253 newp = ip6addrlbl_alloc(prefix, prefixlen, ifindex, label);
0254 if (IS_ERR(newp))
0255 return PTR_ERR(newp);
0256 spin_lock(&net->ipv6.ip6addrlbl_table.lock);
0257 ret = __ip6addrlbl_add(net, newp, replace);
0258 spin_unlock(&net->ipv6.ip6addrlbl_table.lock);
0259 if (ret)
0260 kfree(newp);
0261 return ret;
0262 }
0263
0264
0265 static int __ip6addrlbl_del(struct net *net,
0266 const struct in6_addr *prefix, int prefixlen,
0267 int ifindex)
0268 {
0269 struct ip6addrlbl_entry *p = NULL;
0270 struct hlist_node *n;
0271 int ret = -ESRCH;
0272
0273 ADDRLABEL(KERN_DEBUG "%s(prefix=%pI6, prefixlen=%d, ifindex=%d)\n",
0274 __func__, prefix, prefixlen, ifindex);
0275
0276 hlist_for_each_entry_safe(p, n, &net->ipv6.ip6addrlbl_table.head, list) {
0277 if (p->prefixlen == prefixlen &&
0278 p->ifindex == ifindex &&
0279 ipv6_addr_equal(&p->prefix, prefix)) {
0280 hlist_del_rcu(&p->list);
0281 kfree_rcu(p, rcu);
0282 ret = 0;
0283 break;
0284 }
0285 }
0286 return ret;
0287 }
0288
0289 static int ip6addrlbl_del(struct net *net,
0290 const struct in6_addr *prefix, int prefixlen,
0291 int ifindex)
0292 {
0293 struct in6_addr prefix_buf;
0294 int ret;
0295
0296 ADDRLABEL(KERN_DEBUG "%s(prefix=%pI6, prefixlen=%d, ifindex=%d)\n",
0297 __func__, prefix, prefixlen, ifindex);
0298
0299 ipv6_addr_prefix(&prefix_buf, prefix, prefixlen);
0300 spin_lock(&net->ipv6.ip6addrlbl_table.lock);
0301 ret = __ip6addrlbl_del(net, &prefix_buf, prefixlen, ifindex);
0302 spin_unlock(&net->ipv6.ip6addrlbl_table.lock);
0303 return ret;
0304 }
0305
0306
0307 static int __net_init ip6addrlbl_net_init(struct net *net)
0308 {
0309 struct ip6addrlbl_entry *p = NULL;
0310 struct hlist_node *n;
0311 int err;
0312 int i;
0313
0314 ADDRLABEL(KERN_DEBUG "%s\n", __func__);
0315
0316 spin_lock_init(&net->ipv6.ip6addrlbl_table.lock);
0317 INIT_HLIST_HEAD(&net->ipv6.ip6addrlbl_table.head);
0318
0319 for (i = 0; i < ARRAY_SIZE(ip6addrlbl_init_table); i++) {
0320 err = ip6addrlbl_add(net,
0321 ip6addrlbl_init_table[i].prefix,
0322 ip6addrlbl_init_table[i].prefixlen,
0323 0,
0324 ip6addrlbl_init_table[i].label, 0);
0325 if (err)
0326 goto err_ip6addrlbl_add;
0327 }
0328 return 0;
0329
0330 err_ip6addrlbl_add:
0331 hlist_for_each_entry_safe(p, n, &net->ipv6.ip6addrlbl_table.head, list) {
0332 hlist_del_rcu(&p->list);
0333 kfree_rcu(p, rcu);
0334 }
0335 return err;
0336 }
0337
0338 static void __net_exit ip6addrlbl_net_exit(struct net *net)
0339 {
0340 struct ip6addrlbl_entry *p = NULL;
0341 struct hlist_node *n;
0342
0343
0344 spin_lock(&net->ipv6.ip6addrlbl_table.lock);
0345 hlist_for_each_entry_safe(p, n, &net->ipv6.ip6addrlbl_table.head, list) {
0346 hlist_del_rcu(&p->list);
0347 kfree_rcu(p, rcu);
0348 }
0349 spin_unlock(&net->ipv6.ip6addrlbl_table.lock);
0350 }
0351
0352 static struct pernet_operations ipv6_addr_label_ops = {
0353 .init = ip6addrlbl_net_init,
0354 .exit = ip6addrlbl_net_exit,
0355 };
0356
0357 int __init ipv6_addr_label_init(void)
0358 {
0359 return register_pernet_subsys(&ipv6_addr_label_ops);
0360 }
0361
0362 void ipv6_addr_label_cleanup(void)
0363 {
0364 unregister_pernet_subsys(&ipv6_addr_label_ops);
0365 }
0366
0367 static const struct nla_policy ifal_policy[IFAL_MAX+1] = {
0368 [IFAL_ADDRESS] = { .len = sizeof(struct in6_addr), },
0369 [IFAL_LABEL] = { .len = sizeof(u32), },
0370 };
0371
0372 static bool addrlbl_ifindex_exists(struct net *net, int ifindex)
0373 {
0374
0375 struct net_device *dev;
0376
0377 rcu_read_lock();
0378 dev = dev_get_by_index_rcu(net, ifindex);
0379 rcu_read_unlock();
0380
0381 return dev != NULL;
0382 }
0383
0384 static int ip6addrlbl_newdel(struct sk_buff *skb, struct nlmsghdr *nlh,
0385 struct netlink_ext_ack *extack)
0386 {
0387 struct net *net = sock_net(skb->sk);
0388 struct ifaddrlblmsg *ifal;
0389 struct nlattr *tb[IFAL_MAX+1];
0390 struct in6_addr *pfx;
0391 u32 label;
0392 int err = 0;
0393
0394 err = nlmsg_parse_deprecated(nlh, sizeof(*ifal), tb, IFAL_MAX,
0395 ifal_policy, extack);
0396 if (err < 0)
0397 return err;
0398
0399 ifal = nlmsg_data(nlh);
0400
0401 if (ifal->ifal_family != AF_INET6 ||
0402 ifal->ifal_prefixlen > 128)
0403 return -EINVAL;
0404
0405 if (!tb[IFAL_ADDRESS])
0406 return -EINVAL;
0407 pfx = nla_data(tb[IFAL_ADDRESS]);
0408
0409 if (!tb[IFAL_LABEL])
0410 return -EINVAL;
0411 label = nla_get_u32(tb[IFAL_LABEL]);
0412 if (label == IPV6_ADDR_LABEL_DEFAULT)
0413 return -EINVAL;
0414
0415 switch (nlh->nlmsg_type) {
0416 case RTM_NEWADDRLABEL:
0417 if (ifal->ifal_index &&
0418 !addrlbl_ifindex_exists(net, ifal->ifal_index))
0419 return -EINVAL;
0420
0421 err = ip6addrlbl_add(net, pfx, ifal->ifal_prefixlen,
0422 ifal->ifal_index, label,
0423 nlh->nlmsg_flags & NLM_F_REPLACE);
0424 break;
0425 case RTM_DELADDRLABEL:
0426 err = ip6addrlbl_del(net, pfx, ifal->ifal_prefixlen,
0427 ifal->ifal_index);
0428 break;
0429 default:
0430 err = -EOPNOTSUPP;
0431 }
0432 return err;
0433 }
0434
0435 static void ip6addrlbl_putmsg(struct nlmsghdr *nlh,
0436 int prefixlen, int ifindex, u32 lseq)
0437 {
0438 struct ifaddrlblmsg *ifal = nlmsg_data(nlh);
0439 ifal->ifal_family = AF_INET6;
0440 ifal->ifal_prefixlen = prefixlen;
0441 ifal->ifal_flags = 0;
0442 ifal->ifal_index = ifindex;
0443 ifal->ifal_seq = lseq;
0444 };
0445
0446 static int ip6addrlbl_fill(struct sk_buff *skb,
0447 struct ip6addrlbl_entry *p,
0448 u32 lseq,
0449 u32 portid, u32 seq, int event,
0450 unsigned int flags)
0451 {
0452 struct nlmsghdr *nlh = nlmsg_put(skb, portid, seq, event,
0453 sizeof(struct ifaddrlblmsg), flags);
0454 if (!nlh)
0455 return -EMSGSIZE;
0456
0457 ip6addrlbl_putmsg(nlh, p->prefixlen, p->ifindex, lseq);
0458
0459 if (nla_put_in6_addr(skb, IFAL_ADDRESS, &p->prefix) < 0 ||
0460 nla_put_u32(skb, IFAL_LABEL, p->label) < 0) {
0461 nlmsg_cancel(skb, nlh);
0462 return -EMSGSIZE;
0463 }
0464
0465 nlmsg_end(skb, nlh);
0466 return 0;
0467 }
0468
0469 static int ip6addrlbl_valid_dump_req(const struct nlmsghdr *nlh,
0470 struct netlink_ext_ack *extack)
0471 {
0472 struct ifaddrlblmsg *ifal;
0473
0474 if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ifal))) {
0475 NL_SET_ERR_MSG_MOD(extack, "Invalid header for address label dump request");
0476 return -EINVAL;
0477 }
0478
0479 ifal = nlmsg_data(nlh);
0480 if (ifal->__ifal_reserved || ifal->ifal_prefixlen ||
0481 ifal->ifal_flags || ifal->ifal_index || ifal->ifal_seq) {
0482 NL_SET_ERR_MSG_MOD(extack, "Invalid values in header for address label dump request");
0483 return -EINVAL;
0484 }
0485
0486 if (nlmsg_attrlen(nlh, sizeof(*ifal))) {
0487 NL_SET_ERR_MSG_MOD(extack, "Invalid data after header for address label dump request");
0488 return -EINVAL;
0489 }
0490
0491 return 0;
0492 }
0493
0494 static int ip6addrlbl_dump(struct sk_buff *skb, struct netlink_callback *cb)
0495 {
0496 const struct nlmsghdr *nlh = cb->nlh;
0497 struct net *net = sock_net(skb->sk);
0498 struct ip6addrlbl_entry *p;
0499 int idx = 0, s_idx = cb->args[0];
0500 int err;
0501
0502 if (cb->strict_check) {
0503 err = ip6addrlbl_valid_dump_req(nlh, cb->extack);
0504 if (err < 0)
0505 return err;
0506 }
0507
0508 rcu_read_lock();
0509 hlist_for_each_entry_rcu(p, &net->ipv6.ip6addrlbl_table.head, list) {
0510 if (idx >= s_idx) {
0511 err = ip6addrlbl_fill(skb, p,
0512 net->ipv6.ip6addrlbl_table.seq,
0513 NETLINK_CB(cb->skb).portid,
0514 nlh->nlmsg_seq,
0515 RTM_NEWADDRLABEL,
0516 NLM_F_MULTI);
0517 if (err < 0)
0518 break;
0519 }
0520 idx++;
0521 }
0522 rcu_read_unlock();
0523 cb->args[0] = idx;
0524 return skb->len;
0525 }
0526
0527 static inline int ip6addrlbl_msgsize(void)
0528 {
0529 return NLMSG_ALIGN(sizeof(struct ifaddrlblmsg))
0530 + nla_total_size(16)
0531 + nla_total_size(4);
0532 }
0533
0534 static int ip6addrlbl_valid_get_req(struct sk_buff *skb,
0535 const struct nlmsghdr *nlh,
0536 struct nlattr **tb,
0537 struct netlink_ext_ack *extack)
0538 {
0539 struct ifaddrlblmsg *ifal;
0540 int i, err;
0541
0542 if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ifal))) {
0543 NL_SET_ERR_MSG_MOD(extack, "Invalid header for addrlabel get request");
0544 return -EINVAL;
0545 }
0546
0547 if (!netlink_strict_get_check(skb))
0548 return nlmsg_parse_deprecated(nlh, sizeof(*ifal), tb,
0549 IFAL_MAX, ifal_policy, extack);
0550
0551 ifal = nlmsg_data(nlh);
0552 if (ifal->__ifal_reserved || ifal->ifal_flags || ifal->ifal_seq) {
0553 NL_SET_ERR_MSG_MOD(extack, "Invalid values in header for addrlabel get request");
0554 return -EINVAL;
0555 }
0556
0557 err = nlmsg_parse_deprecated_strict(nlh, sizeof(*ifal), tb, IFAL_MAX,
0558 ifal_policy, extack);
0559 if (err)
0560 return err;
0561
0562 for (i = 0; i <= IFAL_MAX; i++) {
0563 if (!tb[i])
0564 continue;
0565
0566 switch (i) {
0567 case IFAL_ADDRESS:
0568 break;
0569 default:
0570 NL_SET_ERR_MSG_MOD(extack, "Unsupported attribute in addrlabel get request");
0571 return -EINVAL;
0572 }
0573 }
0574
0575 return 0;
0576 }
0577
0578 static int ip6addrlbl_get(struct sk_buff *in_skb, struct nlmsghdr *nlh,
0579 struct netlink_ext_ack *extack)
0580 {
0581 struct net *net = sock_net(in_skb->sk);
0582 struct ifaddrlblmsg *ifal;
0583 struct nlattr *tb[IFAL_MAX+1];
0584 struct in6_addr *addr;
0585 u32 lseq;
0586 int err = 0;
0587 struct ip6addrlbl_entry *p;
0588 struct sk_buff *skb;
0589
0590 err = ip6addrlbl_valid_get_req(in_skb, nlh, tb, extack);
0591 if (err < 0)
0592 return err;
0593
0594 ifal = nlmsg_data(nlh);
0595
0596 if (ifal->ifal_family != AF_INET6 ||
0597 ifal->ifal_prefixlen != 128)
0598 return -EINVAL;
0599
0600 if (ifal->ifal_index &&
0601 !addrlbl_ifindex_exists(net, ifal->ifal_index))
0602 return -EINVAL;
0603
0604 if (!tb[IFAL_ADDRESS])
0605 return -EINVAL;
0606 addr = nla_data(tb[IFAL_ADDRESS]);
0607
0608 skb = nlmsg_new(ip6addrlbl_msgsize(), GFP_KERNEL);
0609 if (!skb)
0610 return -ENOBUFS;
0611
0612 err = -ESRCH;
0613
0614 rcu_read_lock();
0615 p = __ipv6_addr_label(net, addr, ipv6_addr_type(addr), ifal->ifal_index);
0616 lseq = net->ipv6.ip6addrlbl_table.seq;
0617 if (p)
0618 err = ip6addrlbl_fill(skb, p, lseq,
0619 NETLINK_CB(in_skb).portid,
0620 nlh->nlmsg_seq,
0621 RTM_NEWADDRLABEL, 0);
0622 rcu_read_unlock();
0623
0624 if (err < 0) {
0625 WARN_ON(err == -EMSGSIZE);
0626 kfree_skb(skb);
0627 } else {
0628 err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
0629 }
0630 return err;
0631 }
0632
0633 int __init ipv6_addr_label_rtnl_register(void)
0634 {
0635 int ret;
0636
0637 ret = rtnl_register_module(THIS_MODULE, PF_INET6, RTM_NEWADDRLABEL,
0638 ip6addrlbl_newdel,
0639 NULL, RTNL_FLAG_DOIT_UNLOCKED);
0640 if (ret < 0)
0641 return ret;
0642 ret = rtnl_register_module(THIS_MODULE, PF_INET6, RTM_DELADDRLABEL,
0643 ip6addrlbl_newdel,
0644 NULL, RTNL_FLAG_DOIT_UNLOCKED);
0645 if (ret < 0)
0646 return ret;
0647 ret = rtnl_register_module(THIS_MODULE, PF_INET6, RTM_GETADDRLABEL,
0648 ip6addrlbl_get,
0649 ip6addrlbl_dump, RTNL_FLAG_DOIT_UNLOCKED);
0650 return ret;
0651 }