Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * IPv6 Address Label subsystem
0004  * for the IPv6 "Default" Source Address Selection
0005  *
0006  * Copyright (C)2007 USAGI/WIDE Project
0007  */
0008 /*
0009  * Author:
0010  *  YOSHIFUJI Hideaki @ USAGI/WIDE Project <yoshfuji@linux-ipv6.org>
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  * Policy Table
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  * Default policy table (RFC6724 + extensions)
0044  *
0045  * prefix       addr_type   label
0046  * -------------------------------------------------------------------------
0047  * ::1/128      LOOPBACK    0
0048  * ::/0         N/A     1
0049  * 2002::/16        N/A     2
0050  * ::/96        COMPATv4    3
0051  * ::ffff:0:0/96    V4MAPPED    4
0052  * fc00::/7     N/A     5       ULA (RFC 4193)
0053  * 2001::/32        N/A     6       Teredo (RFC 4380)
0054  * 2001:10::/28     N/A     7       ORCHID (RFC 4843)
0055  * fec0::/10        N/A     11      Site-local
0056  *                          (deprecated by RFC3879)
0057  * 3ffe::/16        N/A     12      6bone
0058  *
0059  * Note: 0xffffffff is used if we do not have any policies.
0060  * Note: Labels for ULA and 6to4 are different from labels listed in RFC6724.
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     {   /* ::/0 */
0072         .prefix = &in6addr_any,
0073         .label = 1,
0074     }, {    /* fc00::/7 */
0075         .prefix = &(struct in6_addr){ { { 0xfc } } } ,
0076         .prefixlen = 7,
0077         .label = 5,
0078     }, {    /* fec0::/10 */
0079         .prefix = &(struct in6_addr){ { { 0xfe, 0xc0 } } },
0080         .prefixlen = 10,
0081         .label = 11,
0082     }, {    /* 2002::/16 */
0083         .prefix = &(struct in6_addr){ { { 0x20, 0x02 } } },
0084         .prefixlen = 16,
0085         .label = 2,
0086     }, {    /* 3ffe::/16 */
0087         .prefix = &(struct in6_addr){ { { 0x3f, 0xfe } } },
0088         .prefixlen = 16,
0089         .label = 12,
0090     }, {    /* 2001::/32 */
0091         .prefix = &(struct in6_addr){ { { 0x20, 0x01 } } },
0092         .prefixlen = 32,
0093         .label = 6,
0094     }, {    /* 2001:10::/28 */
0095         .prefix = &(struct in6_addr){ { { 0x20, 0x01, 0x00, 0x10 } } },
0096         .prefixlen = 28,
0097         .label = 7,
0098     }, {    /* ::ffff:0:0 */
0099         .prefix = &(struct in6_addr){ { { [10] = 0xff, [11] = 0xff } } },
0100         .prefixlen = 96,
0101         .label = 4,
0102     }, {    /* ::/96 */
0103         .prefix = &in6addr_any,
0104         .prefixlen = 96,
0105         .label = 3,
0106     }, {    /* ::1/128 */
0107         .prefix = &in6addr_loopback,
0108         .prefixlen = 128,
0109         .label = 0,
0110     }
0111 };
0112 
0113 /* Find label */
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 /* allocate one entry */
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 /* add a label */
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 /* add a label */
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 /* remove a label */
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 /* add default label */
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     /* Remove all labels belonging to the exiting net */
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)    /* IFAL_ADDRESS */
0531         + nla_total_size(4);    /* IFAL_LABEL */
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 }