addrlabel.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651
  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. net->ipv6.ip6addrlbl_table.seq++;
  215. return ret;
  216. }
  217. /* add a label */
  218. static int ip6addrlbl_add(struct net *net,
  219. const struct in6_addr *prefix, int prefixlen,
  220. int ifindex, u32 label, int replace)
  221. {
  222. struct ip6addrlbl_entry *newp;
  223. int ret = 0;
  224. ADDRLABEL(KERN_DEBUG "%s(prefix=%pI6, prefixlen=%d, ifindex=%d, label=%u, replace=%d)\n",
  225. __func__, prefix, prefixlen, ifindex, (unsigned int)label,
  226. replace);
  227. newp = ip6addrlbl_alloc(prefix, prefixlen, ifindex, label);
  228. if (IS_ERR(newp))
  229. return PTR_ERR(newp);
  230. spin_lock(&net->ipv6.ip6addrlbl_table.lock);
  231. ret = __ip6addrlbl_add(net, newp, replace);
  232. spin_unlock(&net->ipv6.ip6addrlbl_table.lock);
  233. if (ret)
  234. kfree(newp);
  235. return ret;
  236. }
  237. /* remove a label */
  238. static int __ip6addrlbl_del(struct net *net,
  239. const struct in6_addr *prefix, int prefixlen,
  240. int ifindex)
  241. {
  242. struct ip6addrlbl_entry *p = NULL;
  243. struct hlist_node *n;
  244. int ret = -ESRCH;
  245. ADDRLABEL(KERN_DEBUG "%s(prefix=%pI6, prefixlen=%d, ifindex=%d)\n",
  246. __func__, prefix, prefixlen, ifindex);
  247. hlist_for_each_entry_safe(p, n, &net->ipv6.ip6addrlbl_table.head, list) {
  248. if (p->prefixlen == prefixlen &&
  249. p->ifindex == ifindex &&
  250. ipv6_addr_equal(&p->prefix, prefix)) {
  251. hlist_del_rcu(&p->list);
  252. kfree_rcu(p, rcu);
  253. ret = 0;
  254. break;
  255. }
  256. }
  257. return ret;
  258. }
  259. static int ip6addrlbl_del(struct net *net,
  260. const struct in6_addr *prefix, int prefixlen,
  261. int ifindex)
  262. {
  263. struct in6_addr prefix_buf;
  264. int ret;
  265. ADDRLABEL(KERN_DEBUG "%s(prefix=%pI6, prefixlen=%d, ifindex=%d)\n",
  266. __func__, prefix, prefixlen, ifindex);
  267. ipv6_addr_prefix(&prefix_buf, prefix, prefixlen);
  268. spin_lock(&net->ipv6.ip6addrlbl_table.lock);
  269. ret = __ip6addrlbl_del(net, &prefix_buf, prefixlen, ifindex);
  270. spin_unlock(&net->ipv6.ip6addrlbl_table.lock);
  271. return ret;
  272. }
  273. /* add default label */
  274. static int __net_init ip6addrlbl_net_init(struct net *net)
  275. {
  276. struct ip6addrlbl_entry *p = NULL;
  277. struct hlist_node *n;
  278. int err;
  279. int i;
  280. ADDRLABEL(KERN_DEBUG "%s\n", __func__);
  281. spin_lock_init(&net->ipv6.ip6addrlbl_table.lock);
  282. INIT_HLIST_HEAD(&net->ipv6.ip6addrlbl_table.head);
  283. for (i = 0; i < ARRAY_SIZE(ip6addrlbl_init_table); i++) {
  284. err = ip6addrlbl_add(net,
  285. ip6addrlbl_init_table[i].prefix,
  286. ip6addrlbl_init_table[i].prefixlen,
  287. 0,
  288. ip6addrlbl_init_table[i].label, 0);
  289. if (err)
  290. goto err_ip6addrlbl_add;
  291. }
  292. return 0;
  293. err_ip6addrlbl_add:
  294. hlist_for_each_entry_safe(p, n, &net->ipv6.ip6addrlbl_table.head, list) {
  295. hlist_del_rcu(&p->list);
  296. kfree_rcu(p, rcu);
  297. }
  298. return err;
  299. }
  300. static void __net_exit ip6addrlbl_net_exit(struct net *net)
  301. {
  302. struct ip6addrlbl_entry *p = NULL;
  303. struct hlist_node *n;
  304. /* Remove all labels belonging to the exiting net */
  305. spin_lock(&net->ipv6.ip6addrlbl_table.lock);
  306. hlist_for_each_entry_safe(p, n, &net->ipv6.ip6addrlbl_table.head, list) {
  307. hlist_del_rcu(&p->list);
  308. kfree_rcu(p, rcu);
  309. }
  310. spin_unlock(&net->ipv6.ip6addrlbl_table.lock);
  311. }
  312. static struct pernet_operations ipv6_addr_label_ops = {
  313. .init = ip6addrlbl_net_init,
  314. .exit = ip6addrlbl_net_exit,
  315. };
  316. int __init ipv6_addr_label_init(void)
  317. {
  318. return register_pernet_subsys(&ipv6_addr_label_ops);
  319. }
  320. void ipv6_addr_label_cleanup(void)
  321. {
  322. unregister_pernet_subsys(&ipv6_addr_label_ops);
  323. }
  324. static const struct nla_policy ifal_policy[IFAL_MAX+1] = {
  325. [IFAL_ADDRESS] = { .len = sizeof(struct in6_addr), },
  326. [IFAL_LABEL] = { .len = sizeof(u32), },
  327. };
  328. static bool addrlbl_ifindex_exists(struct net *net, int ifindex)
  329. {
  330. struct net_device *dev;
  331. rcu_read_lock();
  332. dev = dev_get_by_index_rcu(net, ifindex);
  333. rcu_read_unlock();
  334. return dev != NULL;
  335. }
  336. static int ip6addrlbl_newdel(struct sk_buff *skb, struct nlmsghdr *nlh,
  337. struct netlink_ext_ack *extack)
  338. {
  339. struct net *net = sock_net(skb->sk);
  340. struct ifaddrlblmsg *ifal;
  341. struct nlattr *tb[IFAL_MAX+1];
  342. struct in6_addr *pfx;
  343. u32 label;
  344. int err = 0;
  345. err = nlmsg_parse_deprecated(nlh, sizeof(*ifal), tb, IFAL_MAX,
  346. ifal_policy, extack);
  347. if (err < 0)
  348. return err;
  349. ifal = nlmsg_data(nlh);
  350. if (ifal->ifal_family != AF_INET6 ||
  351. ifal->ifal_prefixlen > 128)
  352. return -EINVAL;
  353. if (!tb[IFAL_ADDRESS])
  354. return -EINVAL;
  355. pfx = nla_data(tb[IFAL_ADDRESS]);
  356. if (!tb[IFAL_LABEL])
  357. return -EINVAL;
  358. label = nla_get_u32(tb[IFAL_LABEL]);
  359. if (label == IPV6_ADDR_LABEL_DEFAULT)
  360. return -EINVAL;
  361. switch (nlh->nlmsg_type) {
  362. case RTM_NEWADDRLABEL:
  363. if (ifal->ifal_index &&
  364. !addrlbl_ifindex_exists(net, ifal->ifal_index))
  365. return -EINVAL;
  366. err = ip6addrlbl_add(net, pfx, ifal->ifal_prefixlen,
  367. ifal->ifal_index, label,
  368. nlh->nlmsg_flags & NLM_F_REPLACE);
  369. break;
  370. case RTM_DELADDRLABEL:
  371. err = ip6addrlbl_del(net, pfx, ifal->ifal_prefixlen,
  372. ifal->ifal_index);
  373. break;
  374. default:
  375. err = -EOPNOTSUPP;
  376. }
  377. return err;
  378. }
  379. static void ip6addrlbl_putmsg(struct nlmsghdr *nlh,
  380. int prefixlen, int ifindex, u32 lseq)
  381. {
  382. struct ifaddrlblmsg *ifal = nlmsg_data(nlh);
  383. ifal->ifal_family = AF_INET6;
  384. ifal->ifal_prefixlen = prefixlen;
  385. ifal->ifal_flags = 0;
  386. ifal->ifal_index = ifindex;
  387. ifal->ifal_seq = lseq;
  388. };
  389. static int ip6addrlbl_fill(struct sk_buff *skb,
  390. struct ip6addrlbl_entry *p,
  391. u32 lseq,
  392. u32 portid, u32 seq, int event,
  393. unsigned int flags)
  394. {
  395. struct nlmsghdr *nlh = nlmsg_put(skb, portid, seq, event,
  396. sizeof(struct ifaddrlblmsg), flags);
  397. if (!nlh)
  398. return -EMSGSIZE;
  399. ip6addrlbl_putmsg(nlh, p->prefixlen, p->ifindex, lseq);
  400. if (nla_put_in6_addr(skb, IFAL_ADDRESS, &p->prefix) < 0 ||
  401. nla_put_u32(skb, IFAL_LABEL, p->label) < 0) {
  402. nlmsg_cancel(skb, nlh);
  403. return -EMSGSIZE;
  404. }
  405. nlmsg_end(skb, nlh);
  406. return 0;
  407. }
  408. static int ip6addrlbl_valid_dump_req(const struct nlmsghdr *nlh,
  409. struct netlink_ext_ack *extack)
  410. {
  411. struct ifaddrlblmsg *ifal;
  412. if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ifal))) {
  413. NL_SET_ERR_MSG_MOD(extack, "Invalid header for address label dump request");
  414. return -EINVAL;
  415. }
  416. ifal = nlmsg_data(nlh);
  417. if (ifal->__ifal_reserved || ifal->ifal_prefixlen ||
  418. ifal->ifal_flags || ifal->ifal_index || ifal->ifal_seq) {
  419. NL_SET_ERR_MSG_MOD(extack, "Invalid values in header for address label dump request");
  420. return -EINVAL;
  421. }
  422. if (nlmsg_attrlen(nlh, sizeof(*ifal))) {
  423. NL_SET_ERR_MSG_MOD(extack, "Invalid data after header for address label dump request");
  424. return -EINVAL;
  425. }
  426. return 0;
  427. }
  428. static int ip6addrlbl_dump(struct sk_buff *skb, struct netlink_callback *cb)
  429. {
  430. const struct nlmsghdr *nlh = cb->nlh;
  431. struct net *net = sock_net(skb->sk);
  432. struct ip6addrlbl_entry *p;
  433. int idx = 0, s_idx = cb->args[0];
  434. int err;
  435. if (cb->strict_check) {
  436. err = ip6addrlbl_valid_dump_req(nlh, cb->extack);
  437. if (err < 0)
  438. return err;
  439. }
  440. rcu_read_lock();
  441. hlist_for_each_entry_rcu(p, &net->ipv6.ip6addrlbl_table.head, list) {
  442. if (idx >= s_idx) {
  443. err = ip6addrlbl_fill(skb, p,
  444. net->ipv6.ip6addrlbl_table.seq,
  445. NETLINK_CB(cb->skb).portid,
  446. nlh->nlmsg_seq,
  447. RTM_NEWADDRLABEL,
  448. NLM_F_MULTI);
  449. if (err < 0)
  450. break;
  451. }
  452. idx++;
  453. }
  454. rcu_read_unlock();
  455. cb->args[0] = idx;
  456. return skb->len;
  457. }
  458. static inline int ip6addrlbl_msgsize(void)
  459. {
  460. return NLMSG_ALIGN(sizeof(struct ifaddrlblmsg))
  461. + nla_total_size(16) /* IFAL_ADDRESS */
  462. + nla_total_size(4); /* IFAL_LABEL */
  463. }
  464. static int ip6addrlbl_valid_get_req(struct sk_buff *skb,
  465. const struct nlmsghdr *nlh,
  466. struct nlattr **tb,
  467. struct netlink_ext_ack *extack)
  468. {
  469. struct ifaddrlblmsg *ifal;
  470. int i, err;
  471. if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ifal))) {
  472. NL_SET_ERR_MSG_MOD(extack, "Invalid header for addrlabel get request");
  473. return -EINVAL;
  474. }
  475. if (!netlink_strict_get_check(skb))
  476. return nlmsg_parse_deprecated(nlh, sizeof(*ifal), tb,
  477. IFAL_MAX, ifal_policy, extack);
  478. ifal = nlmsg_data(nlh);
  479. if (ifal->__ifal_reserved || ifal->ifal_flags || ifal->ifal_seq) {
  480. NL_SET_ERR_MSG_MOD(extack, "Invalid values in header for addrlabel get request");
  481. return -EINVAL;
  482. }
  483. err = nlmsg_parse_deprecated_strict(nlh, sizeof(*ifal), tb, IFAL_MAX,
  484. ifal_policy, extack);
  485. if (err)
  486. return err;
  487. for (i = 0; i <= IFAL_MAX; i++) {
  488. if (!tb[i])
  489. continue;
  490. switch (i) {
  491. case IFAL_ADDRESS:
  492. break;
  493. default:
  494. NL_SET_ERR_MSG_MOD(extack, "Unsupported attribute in addrlabel get request");
  495. return -EINVAL;
  496. }
  497. }
  498. return 0;
  499. }
  500. static int ip6addrlbl_get(struct sk_buff *in_skb, struct nlmsghdr *nlh,
  501. struct netlink_ext_ack *extack)
  502. {
  503. struct net *net = sock_net(in_skb->sk);
  504. struct ifaddrlblmsg *ifal;
  505. struct nlattr *tb[IFAL_MAX+1];
  506. struct in6_addr *addr;
  507. u32 lseq;
  508. int err = 0;
  509. struct ip6addrlbl_entry *p;
  510. struct sk_buff *skb;
  511. err = ip6addrlbl_valid_get_req(in_skb, nlh, tb, extack);
  512. if (err < 0)
  513. return err;
  514. ifal = nlmsg_data(nlh);
  515. if (ifal->ifal_family != AF_INET6 ||
  516. ifal->ifal_prefixlen != 128)
  517. return -EINVAL;
  518. if (ifal->ifal_index &&
  519. !addrlbl_ifindex_exists(net, ifal->ifal_index))
  520. return -EINVAL;
  521. if (!tb[IFAL_ADDRESS])
  522. return -EINVAL;
  523. addr = nla_data(tb[IFAL_ADDRESS]);
  524. skb = nlmsg_new(ip6addrlbl_msgsize(), GFP_KERNEL);
  525. if (!skb)
  526. return -ENOBUFS;
  527. err = -ESRCH;
  528. rcu_read_lock();
  529. p = __ipv6_addr_label(net, addr, ipv6_addr_type(addr), ifal->ifal_index);
  530. lseq = net->ipv6.ip6addrlbl_table.seq;
  531. if (p)
  532. err = ip6addrlbl_fill(skb, p, lseq,
  533. NETLINK_CB(in_skb).portid,
  534. nlh->nlmsg_seq,
  535. RTM_NEWADDRLABEL, 0);
  536. rcu_read_unlock();
  537. if (err < 0) {
  538. WARN_ON(err == -EMSGSIZE);
  539. kfree_skb(skb);
  540. } else {
  541. err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
  542. }
  543. return err;
  544. }
  545. int __init ipv6_addr_label_rtnl_register(void)
  546. {
  547. int ret;
  548. ret = rtnl_register_module(THIS_MODULE, PF_INET6, RTM_NEWADDRLABEL,
  549. ip6addrlbl_newdel,
  550. NULL, RTNL_FLAG_DOIT_UNLOCKED);
  551. if (ret < 0)
  552. return ret;
  553. ret = rtnl_register_module(THIS_MODULE, PF_INET6, RTM_DELADDRLABEL,
  554. ip6addrlbl_newdel,
  555. NULL, RTNL_FLAG_DOIT_UNLOCKED);
  556. if (ret < 0)
  557. return ret;
  558. ret = rtnl_register_module(THIS_MODULE, PF_INET6, RTM_GETADDRLABEL,
  559. ip6addrlbl_get,
  560. ip6addrlbl_dump, RTNL_FLAG_DOIT_UNLOCKED);
  561. return ret;
  562. }