cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

addrlabel.c (15930B)


      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 */
     32struct 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
     65static 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 */
    114static 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
    127static 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
    140u32 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 */
    160static 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 */
    203static 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);
    235out:
    236	if (!ret)
    237		net->ipv6.ip6addrlbl_table.seq++;
    238	return ret;
    239}
    240
    241/* add a label */
    242static 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 */
    265static 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
    289static 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 */
    307static int __net_init ip6addrlbl_net_init(struct net *net)
    308{
    309	struct ip6addrlbl_entry *p = NULL;
    310	struct hlist_node *n;
    311	int err;
    312	int i;
    313
    314	ADDRLABEL(KERN_DEBUG "%s\n", __func__);
    315
    316	spin_lock_init(&net->ipv6.ip6addrlbl_table.lock);
    317	INIT_HLIST_HEAD(&net->ipv6.ip6addrlbl_table.head);
    318
    319	for (i = 0; i < ARRAY_SIZE(ip6addrlbl_init_table); i++) {
    320		err = ip6addrlbl_add(net,
    321				     ip6addrlbl_init_table[i].prefix,
    322				     ip6addrlbl_init_table[i].prefixlen,
    323				     0,
    324				     ip6addrlbl_init_table[i].label, 0);
    325		if (err)
    326			goto err_ip6addrlbl_add;
    327	}
    328	return 0;
    329
    330err_ip6addrlbl_add:
    331	hlist_for_each_entry_safe(p, n, &net->ipv6.ip6addrlbl_table.head, list) {
    332		hlist_del_rcu(&p->list);
    333		kfree_rcu(p, rcu);
    334	}
    335	return err;
    336}
    337
    338static void __net_exit ip6addrlbl_net_exit(struct net *net)
    339{
    340	struct ip6addrlbl_entry *p = NULL;
    341	struct hlist_node *n;
    342
    343	/* Remove all labels belonging to the exiting net */
    344	spin_lock(&net->ipv6.ip6addrlbl_table.lock);
    345	hlist_for_each_entry_safe(p, n, &net->ipv6.ip6addrlbl_table.head, list) {
    346		hlist_del_rcu(&p->list);
    347		kfree_rcu(p, rcu);
    348	}
    349	spin_unlock(&net->ipv6.ip6addrlbl_table.lock);
    350}
    351
    352static struct pernet_operations ipv6_addr_label_ops = {
    353	.init = ip6addrlbl_net_init,
    354	.exit = ip6addrlbl_net_exit,
    355};
    356
    357int __init ipv6_addr_label_init(void)
    358{
    359	return register_pernet_subsys(&ipv6_addr_label_ops);
    360}
    361
    362void ipv6_addr_label_cleanup(void)
    363{
    364	unregister_pernet_subsys(&ipv6_addr_label_ops);
    365}
    366
    367static const struct nla_policy ifal_policy[IFAL_MAX+1] = {
    368	[IFAL_ADDRESS]		= { .len = sizeof(struct in6_addr), },
    369	[IFAL_LABEL]		= { .len = sizeof(u32), },
    370};
    371
    372static bool addrlbl_ifindex_exists(struct net *net, int ifindex)
    373{
    374
    375	struct net_device *dev;
    376
    377	rcu_read_lock();
    378	dev = dev_get_by_index_rcu(net, ifindex);
    379	rcu_read_unlock();
    380
    381	return dev != NULL;
    382}
    383
    384static int ip6addrlbl_newdel(struct sk_buff *skb, struct nlmsghdr *nlh,
    385			     struct netlink_ext_ack *extack)
    386{
    387	struct net *net = sock_net(skb->sk);
    388	struct ifaddrlblmsg *ifal;
    389	struct nlattr *tb[IFAL_MAX+1];
    390	struct in6_addr *pfx;
    391	u32 label;
    392	int err = 0;
    393
    394	err = nlmsg_parse_deprecated(nlh, sizeof(*ifal), tb, IFAL_MAX,
    395				     ifal_policy, extack);
    396	if (err < 0)
    397		return err;
    398
    399	ifal = nlmsg_data(nlh);
    400
    401	if (ifal->ifal_family != AF_INET6 ||
    402	    ifal->ifal_prefixlen > 128)
    403		return -EINVAL;
    404
    405	if (!tb[IFAL_ADDRESS])
    406		return -EINVAL;
    407	pfx = nla_data(tb[IFAL_ADDRESS]);
    408
    409	if (!tb[IFAL_LABEL])
    410		return -EINVAL;
    411	label = nla_get_u32(tb[IFAL_LABEL]);
    412	if (label == IPV6_ADDR_LABEL_DEFAULT)
    413		return -EINVAL;
    414
    415	switch (nlh->nlmsg_type) {
    416	case RTM_NEWADDRLABEL:
    417		if (ifal->ifal_index &&
    418		    !addrlbl_ifindex_exists(net, ifal->ifal_index))
    419			return -EINVAL;
    420
    421		err = ip6addrlbl_add(net, pfx, ifal->ifal_prefixlen,
    422				     ifal->ifal_index, label,
    423				     nlh->nlmsg_flags & NLM_F_REPLACE);
    424		break;
    425	case RTM_DELADDRLABEL:
    426		err = ip6addrlbl_del(net, pfx, ifal->ifal_prefixlen,
    427				     ifal->ifal_index);
    428		break;
    429	default:
    430		err = -EOPNOTSUPP;
    431	}
    432	return err;
    433}
    434
    435static void ip6addrlbl_putmsg(struct nlmsghdr *nlh,
    436			      int prefixlen, int ifindex, u32 lseq)
    437{
    438	struct ifaddrlblmsg *ifal = nlmsg_data(nlh);
    439	ifal->ifal_family = AF_INET6;
    440	ifal->ifal_prefixlen = prefixlen;
    441	ifal->ifal_flags = 0;
    442	ifal->ifal_index = ifindex;
    443	ifal->ifal_seq = lseq;
    444};
    445
    446static int ip6addrlbl_fill(struct sk_buff *skb,
    447			   struct ip6addrlbl_entry *p,
    448			   u32 lseq,
    449			   u32 portid, u32 seq, int event,
    450			   unsigned int flags)
    451{
    452	struct nlmsghdr *nlh = nlmsg_put(skb, portid, seq, event,
    453					 sizeof(struct ifaddrlblmsg), flags);
    454	if (!nlh)
    455		return -EMSGSIZE;
    456
    457	ip6addrlbl_putmsg(nlh, p->prefixlen, p->ifindex, lseq);
    458
    459	if (nla_put_in6_addr(skb, IFAL_ADDRESS, &p->prefix) < 0 ||
    460	    nla_put_u32(skb, IFAL_LABEL, p->label) < 0) {
    461		nlmsg_cancel(skb, nlh);
    462		return -EMSGSIZE;
    463	}
    464
    465	nlmsg_end(skb, nlh);
    466	return 0;
    467}
    468
    469static int ip6addrlbl_valid_dump_req(const struct nlmsghdr *nlh,
    470				     struct netlink_ext_ack *extack)
    471{
    472	struct ifaddrlblmsg *ifal;
    473
    474	if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ifal))) {
    475		NL_SET_ERR_MSG_MOD(extack, "Invalid header for address label dump request");
    476		return -EINVAL;
    477	}
    478
    479	ifal = nlmsg_data(nlh);
    480	if (ifal->__ifal_reserved || ifal->ifal_prefixlen ||
    481	    ifal->ifal_flags || ifal->ifal_index || ifal->ifal_seq) {
    482		NL_SET_ERR_MSG_MOD(extack, "Invalid values in header for address label dump request");
    483		return -EINVAL;
    484	}
    485
    486	if (nlmsg_attrlen(nlh, sizeof(*ifal))) {
    487		NL_SET_ERR_MSG_MOD(extack, "Invalid data after header for address label dump request");
    488		return -EINVAL;
    489	}
    490
    491	return 0;
    492}
    493
    494static int ip6addrlbl_dump(struct sk_buff *skb, struct netlink_callback *cb)
    495{
    496	const struct nlmsghdr *nlh = cb->nlh;
    497	struct net *net = sock_net(skb->sk);
    498	struct ip6addrlbl_entry *p;
    499	int idx = 0, s_idx = cb->args[0];
    500	int err;
    501
    502	if (cb->strict_check) {
    503		err = ip6addrlbl_valid_dump_req(nlh, cb->extack);
    504		if (err < 0)
    505			return err;
    506	}
    507
    508	rcu_read_lock();
    509	hlist_for_each_entry_rcu(p, &net->ipv6.ip6addrlbl_table.head, list) {
    510		if (idx >= s_idx) {
    511			err = ip6addrlbl_fill(skb, p,
    512					      net->ipv6.ip6addrlbl_table.seq,
    513					      NETLINK_CB(cb->skb).portid,
    514					      nlh->nlmsg_seq,
    515					      RTM_NEWADDRLABEL,
    516					      NLM_F_MULTI);
    517			if (err < 0)
    518				break;
    519		}
    520		idx++;
    521	}
    522	rcu_read_unlock();
    523	cb->args[0] = idx;
    524	return skb->len;
    525}
    526
    527static inline int ip6addrlbl_msgsize(void)
    528{
    529	return NLMSG_ALIGN(sizeof(struct ifaddrlblmsg))
    530		+ nla_total_size(16)	/* IFAL_ADDRESS */
    531		+ nla_total_size(4);	/* IFAL_LABEL */
    532}
    533
    534static int ip6addrlbl_valid_get_req(struct sk_buff *skb,
    535				    const struct nlmsghdr *nlh,
    536				    struct nlattr **tb,
    537				    struct netlink_ext_ack *extack)
    538{
    539	struct ifaddrlblmsg *ifal;
    540	int i, err;
    541
    542	if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ifal))) {
    543		NL_SET_ERR_MSG_MOD(extack, "Invalid header for addrlabel get request");
    544		return -EINVAL;
    545	}
    546
    547	if (!netlink_strict_get_check(skb))
    548		return nlmsg_parse_deprecated(nlh, sizeof(*ifal), tb,
    549					      IFAL_MAX, ifal_policy, extack);
    550
    551	ifal = nlmsg_data(nlh);
    552	if (ifal->__ifal_reserved || ifal->ifal_flags || ifal->ifal_seq) {
    553		NL_SET_ERR_MSG_MOD(extack, "Invalid values in header for addrlabel get request");
    554		return -EINVAL;
    555	}
    556
    557	err = nlmsg_parse_deprecated_strict(nlh, sizeof(*ifal), tb, IFAL_MAX,
    558					    ifal_policy, extack);
    559	if (err)
    560		return err;
    561
    562	for (i = 0; i <= IFAL_MAX; i++) {
    563		if (!tb[i])
    564			continue;
    565
    566		switch (i) {
    567		case IFAL_ADDRESS:
    568			break;
    569		default:
    570			NL_SET_ERR_MSG_MOD(extack, "Unsupported attribute in addrlabel get request");
    571			return -EINVAL;
    572		}
    573	}
    574
    575	return 0;
    576}
    577
    578static int ip6addrlbl_get(struct sk_buff *in_skb, struct nlmsghdr *nlh,
    579			  struct netlink_ext_ack *extack)
    580{
    581	struct net *net = sock_net(in_skb->sk);
    582	struct ifaddrlblmsg *ifal;
    583	struct nlattr *tb[IFAL_MAX+1];
    584	struct in6_addr *addr;
    585	u32 lseq;
    586	int err = 0;
    587	struct ip6addrlbl_entry *p;
    588	struct sk_buff *skb;
    589
    590	err = ip6addrlbl_valid_get_req(in_skb, nlh, tb, extack);
    591	if (err < 0)
    592		return err;
    593
    594	ifal = nlmsg_data(nlh);
    595
    596	if (ifal->ifal_family != AF_INET6 ||
    597	    ifal->ifal_prefixlen != 128)
    598		return -EINVAL;
    599
    600	if (ifal->ifal_index &&
    601	    !addrlbl_ifindex_exists(net, ifal->ifal_index))
    602		return -EINVAL;
    603
    604	if (!tb[IFAL_ADDRESS])
    605		return -EINVAL;
    606	addr = nla_data(tb[IFAL_ADDRESS]);
    607
    608	skb = nlmsg_new(ip6addrlbl_msgsize(), GFP_KERNEL);
    609	if (!skb)
    610		return -ENOBUFS;
    611
    612	err = -ESRCH;
    613
    614	rcu_read_lock();
    615	p = __ipv6_addr_label(net, addr, ipv6_addr_type(addr), ifal->ifal_index);
    616	lseq = net->ipv6.ip6addrlbl_table.seq;
    617	if (p)
    618		err = ip6addrlbl_fill(skb, p, lseq,
    619				      NETLINK_CB(in_skb).portid,
    620				      nlh->nlmsg_seq,
    621				      RTM_NEWADDRLABEL, 0);
    622	rcu_read_unlock();
    623
    624	if (err < 0) {
    625		WARN_ON(err == -EMSGSIZE);
    626		kfree_skb(skb);
    627	} else {
    628		err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
    629	}
    630	return err;
    631}
    632
    633int __init ipv6_addr_label_rtnl_register(void)
    634{
    635	int ret;
    636
    637	ret = rtnl_register_module(THIS_MODULE, PF_INET6, RTM_NEWADDRLABEL,
    638				   ip6addrlbl_newdel,
    639				   NULL, RTNL_FLAG_DOIT_UNLOCKED);
    640	if (ret < 0)
    641		return ret;
    642	ret = rtnl_register_module(THIS_MODULE, PF_INET6, RTM_DELADDRLABEL,
    643				   ip6addrlbl_newdel,
    644				   NULL, RTNL_FLAG_DOIT_UNLOCKED);
    645	if (ret < 0)
    646		return ret;
    647	ret = rtnl_register_module(THIS_MODULE, PF_INET6, RTM_GETADDRLABEL,
    648				   ip6addrlbl_get,
    649				   ip6addrlbl_dump, RTNL_FLAG_DOIT_UNLOCKED);
    650	return ret;
    651}