addrlabel.c 16 KB

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