addrlabel.c 16 KB

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