root/net/ipv6/addrlabel.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. __ip6addrlbl_match
  2. __ipv6_addr_label
  3. ipv6_addr_label
  4. ip6addrlbl_alloc
  5. __ip6addrlbl_add
  6. ip6addrlbl_add
  7. __ip6addrlbl_del
  8. ip6addrlbl_del
  9. ip6addrlbl_net_init
  10. ip6addrlbl_net_exit
  11. ipv6_addr_label_init
  12. ipv6_addr_label_cleanup
  13. addrlbl_ifindex_exists
  14. ip6addrlbl_newdel
  15. ip6addrlbl_putmsg
  16. ip6addrlbl_fill
  17. ip6addrlbl_valid_dump_req
  18. ip6addrlbl_dump
  19. ip6addrlbl_msgsize
  20. ip6addrlbl_valid_get_req
  21. ip6addrlbl_get
  22. ipv6_addr_label_rtnl_register

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

/* [<][>][^][v][top][bottom][index][help] */