12a8cc6c8SYOSHIFUJI Hideaki /* 22a8cc6c8SYOSHIFUJI Hideaki * IPv6 Address Label subsystem 32a8cc6c8SYOSHIFUJI Hideaki * for the IPv6 "Default" Source Address Selection 42a8cc6c8SYOSHIFUJI Hideaki * 52a8cc6c8SYOSHIFUJI Hideaki * Copyright (C)2007 USAGI/WIDE Project 62a8cc6c8SYOSHIFUJI Hideaki */ 72a8cc6c8SYOSHIFUJI Hideaki /* 82a8cc6c8SYOSHIFUJI Hideaki * Author: 92a8cc6c8SYOSHIFUJI Hideaki * YOSHIFUJI Hideaki @ USAGI/WIDE Project <yoshfuji@linux-ipv6.org> 102a8cc6c8SYOSHIFUJI Hideaki */ 112a8cc6c8SYOSHIFUJI Hideaki 122a8cc6c8SYOSHIFUJI Hideaki #include <linux/kernel.h> 132a8cc6c8SYOSHIFUJI Hideaki #include <linux/list.h> 142a8cc6c8SYOSHIFUJI Hideaki #include <linux/rcupdate.h> 152a8cc6c8SYOSHIFUJI Hideaki #include <linux/in6.h> 165a0e3ad6STejun Heo #include <linux/slab.h> 172a8cc6c8SYOSHIFUJI Hideaki #include <net/addrconf.h> 182a8cc6c8SYOSHIFUJI Hideaki #include <linux/if_addrlabel.h> 192a8cc6c8SYOSHIFUJI Hideaki #include <linux/netlink.h> 202a8cc6c8SYOSHIFUJI Hideaki #include <linux/rtnetlink.h> 212a8cc6c8SYOSHIFUJI Hideaki 222a8cc6c8SYOSHIFUJI Hideaki #if 0 232a8cc6c8SYOSHIFUJI Hideaki #define ADDRLABEL(x...) printk(x) 242a8cc6c8SYOSHIFUJI Hideaki #else 252a8cc6c8SYOSHIFUJI Hideaki #define ADDRLABEL(x...) do { ; } while (0) 262a8cc6c8SYOSHIFUJI Hideaki #endif 272a8cc6c8SYOSHIFUJI Hideaki 282a8cc6c8SYOSHIFUJI Hideaki /* 292a8cc6c8SYOSHIFUJI Hideaki * Policy Table 302a8cc6c8SYOSHIFUJI Hideaki */ 3122b285d6SWang Yufen struct ip6addrlbl_entry { 323de23255SBenjamin Thery #ifdef CONFIG_NET_NS 333de23255SBenjamin Thery struct net *lbl_net; 343de23255SBenjamin Thery #endif 352a8cc6c8SYOSHIFUJI Hideaki struct in6_addr prefix; 362a8cc6c8SYOSHIFUJI Hideaki int prefixlen; 372a8cc6c8SYOSHIFUJI Hideaki int ifindex; 382a8cc6c8SYOSHIFUJI Hideaki int addrtype; 392a8cc6c8SYOSHIFUJI Hideaki u32 label; 402a8cc6c8SYOSHIFUJI Hideaki struct hlist_node list; 412a8cc6c8SYOSHIFUJI Hideaki atomic_t refcnt; 422a8cc6c8SYOSHIFUJI Hideaki struct rcu_head rcu; 432a8cc6c8SYOSHIFUJI Hideaki }; 442a8cc6c8SYOSHIFUJI Hideaki 452a8cc6c8SYOSHIFUJI Hideaki static struct ip6addrlbl_table 462a8cc6c8SYOSHIFUJI Hideaki { 472a8cc6c8SYOSHIFUJI Hideaki struct hlist_head head; 482a8cc6c8SYOSHIFUJI Hideaki spinlock_t lock; 492a8cc6c8SYOSHIFUJI Hideaki u32 seq; 502a8cc6c8SYOSHIFUJI Hideaki } ip6addrlbl_table; 512a8cc6c8SYOSHIFUJI Hideaki 523de23255SBenjamin Thery static inline 533de23255SBenjamin Thery struct net *ip6addrlbl_net(const struct ip6addrlbl_entry *lbl) 543de23255SBenjamin Thery { 55c2d9ba9bSEric Dumazet return read_pnet(&lbl->lbl_net); 563de23255SBenjamin Thery } 573de23255SBenjamin Thery 582a8cc6c8SYOSHIFUJI Hideaki /* 59417962a0SYOSHIFUJI Hideaki / 吉藤英明 * Default policy table (RFC6724 + extensions) 602a8cc6c8SYOSHIFUJI Hideaki * 612a8cc6c8SYOSHIFUJI Hideaki * prefix addr_type label 622a8cc6c8SYOSHIFUJI Hideaki * ------------------------------------------------------------------------- 632a8cc6c8SYOSHIFUJI Hideaki * ::1/128 LOOPBACK 0 642a8cc6c8SYOSHIFUJI Hideaki * ::/0 N/A 1 652a8cc6c8SYOSHIFUJI Hideaki * 2002::/16 N/A 2 662a8cc6c8SYOSHIFUJI Hideaki * ::/96 COMPATv4 3 672a8cc6c8SYOSHIFUJI Hideaki * ::ffff:0:0/96 V4MAPPED 4 682a8cc6c8SYOSHIFUJI Hideaki * fc00::/7 N/A 5 ULA (RFC 4193) 692a8cc6c8SYOSHIFUJI Hideaki * 2001::/32 N/A 6 Teredo (RFC 4380) 705fe47b8aSJuha-Matti Tapio * 2001:10::/28 N/A 7 ORCHID (RFC 4843) 71417962a0SYOSHIFUJI Hideaki / 吉藤英明 * fec0::/10 N/A 11 Site-local 72417962a0SYOSHIFUJI Hideaki / 吉藤英明 * (deprecated by RFC3879) 73417962a0SYOSHIFUJI Hideaki / 吉藤英明 * 3ffe::/16 N/A 12 6bone 742a8cc6c8SYOSHIFUJI Hideaki * 752a8cc6c8SYOSHIFUJI Hideaki * Note: 0xffffffff is used if we do not have any policies. 76417962a0SYOSHIFUJI Hideaki / 吉藤英明 * Note: Labels for ULA and 6to4 are different from labels listed in RFC6724. 772a8cc6c8SYOSHIFUJI Hideaki */ 782a8cc6c8SYOSHIFUJI Hideaki 792a8cc6c8SYOSHIFUJI Hideaki #define IPV6_ADDR_LABEL_DEFAULT 0xffffffffUL 802a8cc6c8SYOSHIFUJI Hideaki 8104a6f82cSAndi Kleen static const __net_initconst struct ip6addrlbl_init_table 822a8cc6c8SYOSHIFUJI Hideaki { 832a8cc6c8SYOSHIFUJI Hideaki const struct in6_addr *prefix; 842a8cc6c8SYOSHIFUJI Hideaki int prefixlen; 852a8cc6c8SYOSHIFUJI Hideaki u32 label; 862a8cc6c8SYOSHIFUJI Hideaki } ip6addrlbl_init_table[] = { 872a8cc6c8SYOSHIFUJI Hideaki { /* ::/0 */ 882a8cc6c8SYOSHIFUJI Hideaki .prefix = &in6addr_any, 892a8cc6c8SYOSHIFUJI Hideaki .label = 1, 902a8cc6c8SYOSHIFUJI Hideaki }, { /* fc00::/7 */ 912a8cc6c8SYOSHIFUJI Hideaki .prefix = &(struct in6_addr){ { { 0xfc } } } , 922a8cc6c8SYOSHIFUJI Hideaki .prefixlen = 7, 932a8cc6c8SYOSHIFUJI Hideaki .label = 5, 94417962a0SYOSHIFUJI Hideaki / 吉藤英明 }, { /* fec0::/10 */ 95417962a0SYOSHIFUJI Hideaki / 吉藤英明 .prefix = &(struct in6_addr){ { { 0xfe, 0xc0 } } }, 96417962a0SYOSHIFUJI Hideaki / 吉藤英明 .prefixlen = 10, 97417962a0SYOSHIFUJI Hideaki / 吉藤英明 .label = 11, 982a8cc6c8SYOSHIFUJI Hideaki }, { /* 2002::/16 */ 992a8cc6c8SYOSHIFUJI Hideaki .prefix = &(struct in6_addr){ { { 0x20, 0x02 } } }, 1002a8cc6c8SYOSHIFUJI Hideaki .prefixlen = 16, 1012a8cc6c8SYOSHIFUJI Hideaki .label = 2, 102417962a0SYOSHIFUJI Hideaki / 吉藤英明 }, { /* 3ffe::/16 */ 103417962a0SYOSHIFUJI Hideaki / 吉藤英明 .prefix = &(struct in6_addr){ { { 0x3f, 0xfe } } }, 104417962a0SYOSHIFUJI Hideaki / 吉藤英明 .prefixlen = 16, 105417962a0SYOSHIFUJI Hideaki / 吉藤英明 .label = 12, 1062a8cc6c8SYOSHIFUJI Hideaki }, { /* 2001::/32 */ 1072a8cc6c8SYOSHIFUJI Hideaki .prefix = &(struct in6_addr){ { { 0x20, 0x01 } } }, 1082a8cc6c8SYOSHIFUJI Hideaki .prefixlen = 32, 1092a8cc6c8SYOSHIFUJI Hideaki .label = 6, 1105fe47b8aSJuha-Matti Tapio }, { /* 2001:10::/28 */ 1115fe47b8aSJuha-Matti Tapio .prefix = &(struct in6_addr){ { { 0x20, 0x01, 0x00, 0x10 } } }, 1125fe47b8aSJuha-Matti Tapio .prefixlen = 28, 1135fe47b8aSJuha-Matti Tapio .label = 7, 1142a8cc6c8SYOSHIFUJI Hideaki }, { /* ::ffff:0:0 */ 1152a8cc6c8SYOSHIFUJI Hideaki .prefix = &(struct in6_addr){ { { [10] = 0xff, [11] = 0xff } } }, 1162a8cc6c8SYOSHIFUJI Hideaki .prefixlen = 96, 1172a8cc6c8SYOSHIFUJI Hideaki .label = 4, 1182a8cc6c8SYOSHIFUJI Hideaki }, { /* ::/96 */ 1192a8cc6c8SYOSHIFUJI Hideaki .prefix = &in6addr_any, 1202a8cc6c8SYOSHIFUJI Hideaki .prefixlen = 96, 1212a8cc6c8SYOSHIFUJI Hideaki .label = 3, 1222a8cc6c8SYOSHIFUJI Hideaki }, { /* ::1/128 */ 1232a8cc6c8SYOSHIFUJI Hideaki .prefix = &in6addr_loopback, 1242a8cc6c8SYOSHIFUJI Hideaki .prefixlen = 128, 1252a8cc6c8SYOSHIFUJI Hideaki .label = 0, 1262a8cc6c8SYOSHIFUJI Hideaki } 1272a8cc6c8SYOSHIFUJI Hideaki }; 1282a8cc6c8SYOSHIFUJI Hideaki 1292a8cc6c8SYOSHIFUJI Hideaki /* Object management */ 1302a8cc6c8SYOSHIFUJI Hideaki static inline void ip6addrlbl_free(struct ip6addrlbl_entry *p) 1312a8cc6c8SYOSHIFUJI Hideaki { 1323de23255SBenjamin Thery #ifdef CONFIG_NET_NS 1333de23255SBenjamin Thery release_net(p->lbl_net); 1343de23255SBenjamin Thery #endif 1352a8cc6c8SYOSHIFUJI Hideaki kfree(p); 1362a8cc6c8SYOSHIFUJI Hideaki } 1372a8cc6c8SYOSHIFUJI Hideaki 13885040bcbSYOSHIFUJI Hideaki static void ip6addrlbl_free_rcu(struct rcu_head *h) 13985040bcbSYOSHIFUJI Hideaki { 14085040bcbSYOSHIFUJI Hideaki ip6addrlbl_free(container_of(h, struct ip6addrlbl_entry, rcu)); 14185040bcbSYOSHIFUJI Hideaki } 14285040bcbSYOSHIFUJI Hideaki 143a50feda5SEric Dumazet static bool ip6addrlbl_hold(struct ip6addrlbl_entry *p) 1442a8cc6c8SYOSHIFUJI Hideaki { 1452a8cc6c8SYOSHIFUJI Hideaki return atomic_inc_not_zero(&p->refcnt); 1462a8cc6c8SYOSHIFUJI Hideaki } 1472a8cc6c8SYOSHIFUJI Hideaki 1482a8cc6c8SYOSHIFUJI Hideaki static inline void ip6addrlbl_put(struct ip6addrlbl_entry *p) 1492a8cc6c8SYOSHIFUJI Hideaki { 1502a8cc6c8SYOSHIFUJI Hideaki if (atomic_dec_and_test(&p->refcnt)) 15185040bcbSYOSHIFUJI Hideaki call_rcu(&p->rcu, ip6addrlbl_free_rcu); 1522a8cc6c8SYOSHIFUJI Hideaki } 1532a8cc6c8SYOSHIFUJI Hideaki 1542a8cc6c8SYOSHIFUJI Hideaki /* Find label */ 155a50feda5SEric Dumazet static bool __ip6addrlbl_match(struct net *net, 156a50feda5SEric Dumazet const struct ip6addrlbl_entry *p, 1572a8cc6c8SYOSHIFUJI Hideaki const struct in6_addr *addr, 1582a8cc6c8SYOSHIFUJI Hideaki int addrtype, int ifindex) 1592a8cc6c8SYOSHIFUJI Hideaki { 1603de23255SBenjamin Thery if (!net_eq(ip6addrlbl_net(p), net)) 161a50feda5SEric Dumazet return false; 1622a8cc6c8SYOSHIFUJI Hideaki if (p->ifindex && p->ifindex != ifindex) 163a50feda5SEric Dumazet return false; 1642a8cc6c8SYOSHIFUJI Hideaki if (p->addrtype && p->addrtype != addrtype) 165a50feda5SEric Dumazet return false; 1662a8cc6c8SYOSHIFUJI Hideaki if (!ipv6_prefix_equal(addr, &p->prefix, p->prefixlen)) 167a50feda5SEric Dumazet return false; 168a50feda5SEric Dumazet return true; 1692a8cc6c8SYOSHIFUJI Hideaki } 1702a8cc6c8SYOSHIFUJI Hideaki 1713de23255SBenjamin Thery static struct ip6addrlbl_entry *__ipv6_addr_label(struct net *net, 1723de23255SBenjamin Thery const struct in6_addr *addr, 1732a8cc6c8SYOSHIFUJI Hideaki int type, int ifindex) 1742a8cc6c8SYOSHIFUJI Hideaki { 1752a8cc6c8SYOSHIFUJI Hideaki struct ip6addrlbl_entry *p; 176b67bfe0dSSasha Levin hlist_for_each_entry_rcu(p, &ip6addrlbl_table.head, list) { 1773de23255SBenjamin Thery if (__ip6addrlbl_match(net, p, addr, type, ifindex)) 1782a8cc6c8SYOSHIFUJI Hideaki return p; 1792a8cc6c8SYOSHIFUJI Hideaki } 1802a8cc6c8SYOSHIFUJI Hideaki return NULL; 1812a8cc6c8SYOSHIFUJI Hideaki } 1822a8cc6c8SYOSHIFUJI Hideaki 1833de23255SBenjamin Thery u32 ipv6_addr_label(struct net *net, 1843de23255SBenjamin Thery const struct in6_addr *addr, int type, int ifindex) 1852a8cc6c8SYOSHIFUJI Hideaki { 1862a8cc6c8SYOSHIFUJI Hideaki u32 label; 1872a8cc6c8SYOSHIFUJI Hideaki struct ip6addrlbl_entry *p; 1882a8cc6c8SYOSHIFUJI Hideaki 1892a8cc6c8SYOSHIFUJI Hideaki type &= IPV6_ADDR_MAPPED | IPV6_ADDR_COMPATv4 | IPV6_ADDR_LOOPBACK; 1902a8cc6c8SYOSHIFUJI Hideaki 1912a8cc6c8SYOSHIFUJI Hideaki rcu_read_lock(); 1923de23255SBenjamin Thery p = __ipv6_addr_label(net, addr, type, ifindex); 1932a8cc6c8SYOSHIFUJI Hideaki label = p ? p->label : IPV6_ADDR_LABEL_DEFAULT; 1942a8cc6c8SYOSHIFUJI Hideaki rcu_read_unlock(); 1952a8cc6c8SYOSHIFUJI Hideaki 1965b095d98SHarvey Harrison ADDRLABEL(KERN_DEBUG "%s(addr=%pI6, type=%d, ifindex=%d) => %08x\n", 1970c6ce78aSHarvey Harrison __func__, addr, type, ifindex, label); 1982a8cc6c8SYOSHIFUJI Hideaki 1992a8cc6c8SYOSHIFUJI Hideaki return label; 2002a8cc6c8SYOSHIFUJI Hideaki } 2012a8cc6c8SYOSHIFUJI Hideaki 2022a8cc6c8SYOSHIFUJI Hideaki /* allocate one entry */ 2033de23255SBenjamin Thery static struct ip6addrlbl_entry *ip6addrlbl_alloc(struct net *net, 2043de23255SBenjamin Thery const struct in6_addr *prefix, 2052a8cc6c8SYOSHIFUJI Hideaki int prefixlen, int ifindex, 2062a8cc6c8SYOSHIFUJI Hideaki u32 label) 2072a8cc6c8SYOSHIFUJI Hideaki { 2082a8cc6c8SYOSHIFUJI Hideaki struct ip6addrlbl_entry *newp; 2092a8cc6c8SYOSHIFUJI Hideaki int addrtype; 2102a8cc6c8SYOSHIFUJI Hideaki 2115b095d98SHarvey Harrison ADDRLABEL(KERN_DEBUG "%s(prefix=%pI6, prefixlen=%d, ifindex=%d, label=%u)\n", 2120c6ce78aSHarvey Harrison __func__, prefix, prefixlen, ifindex, (unsigned int)label); 2132a8cc6c8SYOSHIFUJI Hideaki 2142a8cc6c8SYOSHIFUJI Hideaki addrtype = ipv6_addr_type(prefix) & (IPV6_ADDR_MAPPED | IPV6_ADDR_COMPATv4 | IPV6_ADDR_LOOPBACK); 2152a8cc6c8SYOSHIFUJI Hideaki 2162a8cc6c8SYOSHIFUJI Hideaki switch (addrtype) { 2172a8cc6c8SYOSHIFUJI Hideaki case IPV6_ADDR_MAPPED: 2182a8cc6c8SYOSHIFUJI Hideaki if (prefixlen > 96) 2192a8cc6c8SYOSHIFUJI Hideaki return ERR_PTR(-EINVAL); 2202a8cc6c8SYOSHIFUJI Hideaki if (prefixlen < 96) 2212a8cc6c8SYOSHIFUJI Hideaki addrtype = 0; 2222a8cc6c8SYOSHIFUJI Hideaki break; 2232a8cc6c8SYOSHIFUJI Hideaki case IPV6_ADDR_COMPATv4: 2242a8cc6c8SYOSHIFUJI Hideaki if (prefixlen != 96) 2252a8cc6c8SYOSHIFUJI Hideaki addrtype = 0; 2262a8cc6c8SYOSHIFUJI Hideaki break; 2272a8cc6c8SYOSHIFUJI Hideaki case IPV6_ADDR_LOOPBACK: 2282a8cc6c8SYOSHIFUJI Hideaki if (prefixlen != 128) 2292a8cc6c8SYOSHIFUJI Hideaki addrtype = 0; 2302a8cc6c8SYOSHIFUJI Hideaki break; 2312a8cc6c8SYOSHIFUJI Hideaki } 2322a8cc6c8SYOSHIFUJI Hideaki 2332a8cc6c8SYOSHIFUJI Hideaki newp = kmalloc(sizeof(*newp), GFP_KERNEL); 2342a8cc6c8SYOSHIFUJI Hideaki if (!newp) 2352a8cc6c8SYOSHIFUJI Hideaki return ERR_PTR(-ENOMEM); 2362a8cc6c8SYOSHIFUJI Hideaki 2372a8cc6c8SYOSHIFUJI Hideaki ipv6_addr_prefix(&newp->prefix, prefix, prefixlen); 2382a8cc6c8SYOSHIFUJI Hideaki newp->prefixlen = prefixlen; 2392a8cc6c8SYOSHIFUJI Hideaki newp->ifindex = ifindex; 2402a8cc6c8SYOSHIFUJI Hideaki newp->addrtype = addrtype; 2412a8cc6c8SYOSHIFUJI Hideaki newp->label = label; 2422a8cc6c8SYOSHIFUJI Hideaki INIT_HLIST_NODE(&newp->list); 2433de23255SBenjamin Thery #ifdef CONFIG_NET_NS 2443de23255SBenjamin Thery newp->lbl_net = hold_net(net); 2453de23255SBenjamin Thery #endif 2462a8cc6c8SYOSHIFUJI Hideaki atomic_set(&newp->refcnt, 1); 2472a8cc6c8SYOSHIFUJI Hideaki return newp; 2482a8cc6c8SYOSHIFUJI Hideaki } 2492a8cc6c8SYOSHIFUJI Hideaki 2502a8cc6c8SYOSHIFUJI Hideaki /* add a label */ 25140fee36eSYOSHIFUJI Hideaki static int __ip6addrlbl_add(struct ip6addrlbl_entry *newp, int replace) 2522a8cc6c8SYOSHIFUJI Hideaki { 253639739b5SHannes Frederic Sowa struct hlist_node *n; 254639739b5SHannes Frederic Sowa struct ip6addrlbl_entry *last = NULL, *p = NULL; 2552a8cc6c8SYOSHIFUJI Hideaki int ret = 0; 2562a8cc6c8SYOSHIFUJI Hideaki 257639739b5SHannes Frederic Sowa ADDRLABEL(KERN_DEBUG "%s(newp=%p, replace=%d)\n", __func__, newp, 258639739b5SHannes Frederic Sowa replace); 2592a8cc6c8SYOSHIFUJI Hideaki 260639739b5SHannes Frederic Sowa hlist_for_each_entry_safe(p, n, &ip6addrlbl_table.head, list) { 2612a8cc6c8SYOSHIFUJI Hideaki if (p->prefixlen == newp->prefixlen && 2623de23255SBenjamin Thery net_eq(ip6addrlbl_net(p), ip6addrlbl_net(newp)) && 2632a8cc6c8SYOSHIFUJI Hideaki p->ifindex == newp->ifindex && 2642a8cc6c8SYOSHIFUJI Hideaki ipv6_addr_equal(&p->prefix, &newp->prefix)) { 2652a8cc6c8SYOSHIFUJI Hideaki if (!replace) { 2662a8cc6c8SYOSHIFUJI Hideaki ret = -EEXIST; 2672a8cc6c8SYOSHIFUJI Hideaki goto out; 2682a8cc6c8SYOSHIFUJI Hideaki } 2692a8cc6c8SYOSHIFUJI Hideaki hlist_replace_rcu(&p->list, &newp->list); 2702a8cc6c8SYOSHIFUJI Hideaki ip6addrlbl_put(p); 2712a8cc6c8SYOSHIFUJI Hideaki goto out; 2722a8cc6c8SYOSHIFUJI Hideaki } else if ((p->prefixlen == newp->prefixlen && !p->ifindex) || 2732a8cc6c8SYOSHIFUJI Hideaki (p->prefixlen < newp->prefixlen)) { 2742a8cc6c8SYOSHIFUJI Hideaki hlist_add_before_rcu(&newp->list, &p->list); 2752a8cc6c8SYOSHIFUJI Hideaki goto out; 2762a8cc6c8SYOSHIFUJI Hideaki } 277639739b5SHannes Frederic Sowa last = p; 2782a8cc6c8SYOSHIFUJI Hideaki } 279639739b5SHannes Frederic Sowa if (last) 2801d023284SKen Helias hlist_add_behind_rcu(&newp->list, &last->list); 281639739b5SHannes Frederic Sowa else 282639739b5SHannes Frederic Sowa hlist_add_head_rcu(&newp->list, &ip6addrlbl_table.head); 2832a8cc6c8SYOSHIFUJI Hideaki out: 2842a8cc6c8SYOSHIFUJI Hideaki if (!ret) 2852a8cc6c8SYOSHIFUJI Hideaki ip6addrlbl_table.seq++; 2862a8cc6c8SYOSHIFUJI Hideaki return ret; 2872a8cc6c8SYOSHIFUJI Hideaki } 2882a8cc6c8SYOSHIFUJI Hideaki 2892a8cc6c8SYOSHIFUJI Hideaki /* add a label */ 2903de23255SBenjamin Thery static int ip6addrlbl_add(struct net *net, 2913de23255SBenjamin Thery const struct in6_addr *prefix, int prefixlen, 2922a8cc6c8SYOSHIFUJI Hideaki int ifindex, u32 label, int replace) 2932a8cc6c8SYOSHIFUJI Hideaki { 2942a8cc6c8SYOSHIFUJI Hideaki struct ip6addrlbl_entry *newp; 2952a8cc6c8SYOSHIFUJI Hideaki int ret = 0; 2962a8cc6c8SYOSHIFUJI Hideaki 2975b095d98SHarvey Harrison ADDRLABEL(KERN_DEBUG "%s(prefix=%pI6, prefixlen=%d, ifindex=%d, label=%u, replace=%d)\n", 2980c6ce78aSHarvey Harrison __func__, prefix, prefixlen, ifindex, (unsigned int)label, 2992a8cc6c8SYOSHIFUJI Hideaki replace); 3002a8cc6c8SYOSHIFUJI Hideaki 3013de23255SBenjamin Thery newp = ip6addrlbl_alloc(net, prefix, prefixlen, ifindex, label); 3022a8cc6c8SYOSHIFUJI Hideaki if (IS_ERR(newp)) 3032a8cc6c8SYOSHIFUJI Hideaki return PTR_ERR(newp); 3042a8cc6c8SYOSHIFUJI Hideaki spin_lock(&ip6addrlbl_table.lock); 3052a8cc6c8SYOSHIFUJI Hideaki ret = __ip6addrlbl_add(newp, replace); 3062a8cc6c8SYOSHIFUJI Hideaki spin_unlock(&ip6addrlbl_table.lock); 3072a8cc6c8SYOSHIFUJI Hideaki if (ret) 3082a8cc6c8SYOSHIFUJI Hideaki ip6addrlbl_free(newp); 3092a8cc6c8SYOSHIFUJI Hideaki return ret; 3102a8cc6c8SYOSHIFUJI Hideaki } 3112a8cc6c8SYOSHIFUJI Hideaki 3122a8cc6c8SYOSHIFUJI Hideaki /* remove a label */ 3133de23255SBenjamin Thery static int __ip6addrlbl_del(struct net *net, 3143de23255SBenjamin Thery const struct in6_addr *prefix, int prefixlen, 3152a8cc6c8SYOSHIFUJI Hideaki int ifindex) 3162a8cc6c8SYOSHIFUJI Hideaki { 3172a8cc6c8SYOSHIFUJI Hideaki struct ip6addrlbl_entry *p = NULL; 318b67bfe0dSSasha Levin struct hlist_node *n; 3192a8cc6c8SYOSHIFUJI Hideaki int ret = -ESRCH; 3202a8cc6c8SYOSHIFUJI Hideaki 3215b095d98SHarvey Harrison ADDRLABEL(KERN_DEBUG "%s(prefix=%pI6, prefixlen=%d, ifindex=%d)\n", 3220c6ce78aSHarvey Harrison __func__, prefix, prefixlen, ifindex); 3232a8cc6c8SYOSHIFUJI Hideaki 324b67bfe0dSSasha Levin hlist_for_each_entry_safe(p, n, &ip6addrlbl_table.head, list) { 3252a8cc6c8SYOSHIFUJI Hideaki if (p->prefixlen == prefixlen && 3263de23255SBenjamin Thery net_eq(ip6addrlbl_net(p), net) && 3272a8cc6c8SYOSHIFUJI Hideaki p->ifindex == ifindex && 3282a8cc6c8SYOSHIFUJI Hideaki ipv6_addr_equal(&p->prefix, prefix)) { 3292a8cc6c8SYOSHIFUJI Hideaki hlist_del_rcu(&p->list); 3302a8cc6c8SYOSHIFUJI Hideaki ip6addrlbl_put(p); 3312a8cc6c8SYOSHIFUJI Hideaki ret = 0; 3322a8cc6c8SYOSHIFUJI Hideaki break; 3332a8cc6c8SYOSHIFUJI Hideaki } 3342a8cc6c8SYOSHIFUJI Hideaki } 3352a8cc6c8SYOSHIFUJI Hideaki return ret; 3362a8cc6c8SYOSHIFUJI Hideaki } 3372a8cc6c8SYOSHIFUJI Hideaki 3383de23255SBenjamin Thery static int ip6addrlbl_del(struct net *net, 3393de23255SBenjamin Thery const struct in6_addr *prefix, int prefixlen, 3402a8cc6c8SYOSHIFUJI Hideaki int ifindex) 3412a8cc6c8SYOSHIFUJI Hideaki { 3422a8cc6c8SYOSHIFUJI Hideaki struct in6_addr prefix_buf; 3432a8cc6c8SYOSHIFUJI Hideaki int ret; 3442a8cc6c8SYOSHIFUJI Hideaki 3455b095d98SHarvey Harrison ADDRLABEL(KERN_DEBUG "%s(prefix=%pI6, prefixlen=%d, ifindex=%d)\n", 3460c6ce78aSHarvey Harrison __func__, prefix, prefixlen, ifindex); 3472a8cc6c8SYOSHIFUJI Hideaki 3482a8cc6c8SYOSHIFUJI Hideaki ipv6_addr_prefix(&prefix_buf, prefix, prefixlen); 3492a8cc6c8SYOSHIFUJI Hideaki spin_lock(&ip6addrlbl_table.lock); 3503de23255SBenjamin Thery ret = __ip6addrlbl_del(net, &prefix_buf, prefixlen, ifindex); 3512a8cc6c8SYOSHIFUJI Hideaki spin_unlock(&ip6addrlbl_table.lock); 3522a8cc6c8SYOSHIFUJI Hideaki return ret; 3532a8cc6c8SYOSHIFUJI Hideaki } 3542a8cc6c8SYOSHIFUJI Hideaki 3552a8cc6c8SYOSHIFUJI Hideaki /* add default label */ 3563de23255SBenjamin Thery static int __net_init ip6addrlbl_net_init(struct net *net) 3572a8cc6c8SYOSHIFUJI Hideaki { 3582a8cc6c8SYOSHIFUJI Hideaki int err = 0; 3592a8cc6c8SYOSHIFUJI Hideaki int i; 3602a8cc6c8SYOSHIFUJI Hideaki 361f3213831SJoe Perches ADDRLABEL(KERN_DEBUG "%s\n", __func__); 3622a8cc6c8SYOSHIFUJI Hideaki 3632a8cc6c8SYOSHIFUJI Hideaki for (i = 0; i < ARRAY_SIZE(ip6addrlbl_init_table); i++) { 3643de23255SBenjamin Thery int ret = ip6addrlbl_add(net, 3653de23255SBenjamin Thery ip6addrlbl_init_table[i].prefix, 3662a8cc6c8SYOSHIFUJI Hideaki ip6addrlbl_init_table[i].prefixlen, 3672a8cc6c8SYOSHIFUJI Hideaki 0, 3682a8cc6c8SYOSHIFUJI Hideaki ip6addrlbl_init_table[i].label, 0); 3692a8cc6c8SYOSHIFUJI Hideaki /* XXX: should we free all rules when we catch an error? */ 3702a8cc6c8SYOSHIFUJI Hideaki if (ret && (!err || err != -ENOMEM)) 3712a8cc6c8SYOSHIFUJI Hideaki err = ret; 3722a8cc6c8SYOSHIFUJI Hideaki } 3732a8cc6c8SYOSHIFUJI Hideaki return err; 3742a8cc6c8SYOSHIFUJI Hideaki } 3752a8cc6c8SYOSHIFUJI Hideaki 3763de23255SBenjamin Thery static void __net_exit ip6addrlbl_net_exit(struct net *net) 3773de23255SBenjamin Thery { 3783de23255SBenjamin Thery struct ip6addrlbl_entry *p = NULL; 379b67bfe0dSSasha Levin struct hlist_node *n; 3803de23255SBenjamin Thery 3813de23255SBenjamin Thery /* Remove all labels belonging to the exiting net */ 3823de23255SBenjamin Thery spin_lock(&ip6addrlbl_table.lock); 383b67bfe0dSSasha Levin hlist_for_each_entry_safe(p, n, &ip6addrlbl_table.head, list) { 3843de23255SBenjamin Thery if (net_eq(ip6addrlbl_net(p), net)) { 3853de23255SBenjamin Thery hlist_del_rcu(&p->list); 3863de23255SBenjamin Thery ip6addrlbl_put(p); 3873de23255SBenjamin Thery } 3883de23255SBenjamin Thery } 3893de23255SBenjamin Thery spin_unlock(&ip6addrlbl_table.lock); 3903de23255SBenjamin Thery } 3913de23255SBenjamin Thery 3923de23255SBenjamin Thery static struct pernet_operations ipv6_addr_label_ops = { 3933de23255SBenjamin Thery .init = ip6addrlbl_net_init, 3943de23255SBenjamin Thery .exit = ip6addrlbl_net_exit, 3953de23255SBenjamin Thery }; 3963de23255SBenjamin Thery 3972a8cc6c8SYOSHIFUJI Hideaki int __init ipv6_addr_label_init(void) 3982a8cc6c8SYOSHIFUJI Hideaki { 3992a8cc6c8SYOSHIFUJI Hideaki spin_lock_init(&ip6addrlbl_table.lock); 4002a8cc6c8SYOSHIFUJI Hideaki 4013de23255SBenjamin Thery return register_pernet_subsys(&ipv6_addr_label_ops); 4022a8cc6c8SYOSHIFUJI Hideaki } 4032a8cc6c8SYOSHIFUJI Hideaki 4042cc6d2bfSNeil Horman void ipv6_addr_label_cleanup(void) 4052cc6d2bfSNeil Horman { 4062cc6d2bfSNeil Horman unregister_pernet_subsys(&ipv6_addr_label_ops); 4072cc6d2bfSNeil Horman } 4082cc6d2bfSNeil Horman 4092a8cc6c8SYOSHIFUJI Hideaki static const struct nla_policy ifal_policy[IFAL_MAX+1] = { 4102a8cc6c8SYOSHIFUJI Hideaki [IFAL_ADDRESS] = { .len = sizeof(struct in6_addr), }, 4112a8cc6c8SYOSHIFUJI Hideaki [IFAL_LABEL] = { .len = sizeof(u32), }, 4122a8cc6c8SYOSHIFUJI Hideaki }; 4132a8cc6c8SYOSHIFUJI Hideaki 414661d2967SThomas Graf static int ip6addrlbl_newdel(struct sk_buff *skb, struct nlmsghdr *nlh) 4152a8cc6c8SYOSHIFUJI Hideaki { 4163b1e0a65SYOSHIFUJI Hideaki struct net *net = sock_net(skb->sk); 4172a8cc6c8SYOSHIFUJI Hideaki struct ifaddrlblmsg *ifal; 4182a8cc6c8SYOSHIFUJI Hideaki struct nlattr *tb[IFAL_MAX+1]; 4192a8cc6c8SYOSHIFUJI Hideaki struct in6_addr *pfx; 4202a8cc6c8SYOSHIFUJI Hideaki u32 label; 4212a8cc6c8SYOSHIFUJI Hideaki int err = 0; 4222a8cc6c8SYOSHIFUJI Hideaki 4232a8cc6c8SYOSHIFUJI Hideaki err = nlmsg_parse(nlh, sizeof(*ifal), tb, IFAL_MAX, ifal_policy); 4242a8cc6c8SYOSHIFUJI Hideaki if (err < 0) 4252a8cc6c8SYOSHIFUJI Hideaki return err; 4262a8cc6c8SYOSHIFUJI Hideaki 4272a8cc6c8SYOSHIFUJI Hideaki ifal = nlmsg_data(nlh); 4282a8cc6c8SYOSHIFUJI Hideaki 4292a8cc6c8SYOSHIFUJI Hideaki if (ifal->ifal_family != AF_INET6 || 4302a8cc6c8SYOSHIFUJI Hideaki ifal->ifal_prefixlen > 128) 4312a8cc6c8SYOSHIFUJI Hideaki return -EINVAL; 4322a8cc6c8SYOSHIFUJI Hideaki 4332a8cc6c8SYOSHIFUJI Hideaki if (!tb[IFAL_ADDRESS]) 4342a8cc6c8SYOSHIFUJI Hideaki return -EINVAL; 4352a8cc6c8SYOSHIFUJI Hideaki pfx = nla_data(tb[IFAL_ADDRESS]); 4362a8cc6c8SYOSHIFUJI Hideaki 4372a8cc6c8SYOSHIFUJI Hideaki if (!tb[IFAL_LABEL]) 4382a8cc6c8SYOSHIFUJI Hideaki return -EINVAL; 4392a8cc6c8SYOSHIFUJI Hideaki label = nla_get_u32(tb[IFAL_LABEL]); 4402a8cc6c8SYOSHIFUJI Hideaki if (label == IPV6_ADDR_LABEL_DEFAULT) 4412a8cc6c8SYOSHIFUJI Hideaki return -EINVAL; 4422a8cc6c8SYOSHIFUJI Hideaki 4432a8cc6c8SYOSHIFUJI Hideaki switch (nlh->nlmsg_type) { 4442a8cc6c8SYOSHIFUJI Hideaki case RTM_NEWADDRLABEL: 4450771275bSFlorian Westphal if (ifal->ifal_index && 4460771275bSFlorian Westphal !__dev_get_by_index(net, ifal->ifal_index)) 4470771275bSFlorian Westphal return -EINVAL; 4480771275bSFlorian Westphal 4493de23255SBenjamin Thery err = ip6addrlbl_add(net, pfx, ifal->ifal_prefixlen, 4502a8cc6c8SYOSHIFUJI Hideaki ifal->ifal_index, label, 4512a8cc6c8SYOSHIFUJI Hideaki nlh->nlmsg_flags & NLM_F_REPLACE); 4522a8cc6c8SYOSHIFUJI Hideaki break; 4532a8cc6c8SYOSHIFUJI Hideaki case RTM_DELADDRLABEL: 4543de23255SBenjamin Thery err = ip6addrlbl_del(net, pfx, ifal->ifal_prefixlen, 4552a8cc6c8SYOSHIFUJI Hideaki ifal->ifal_index); 4562a8cc6c8SYOSHIFUJI Hideaki break; 4572a8cc6c8SYOSHIFUJI Hideaki default: 4582a8cc6c8SYOSHIFUJI Hideaki err = -EOPNOTSUPP; 4592a8cc6c8SYOSHIFUJI Hideaki } 4602a8cc6c8SYOSHIFUJI Hideaki return err; 4612a8cc6c8SYOSHIFUJI Hideaki } 4622a8cc6c8SYOSHIFUJI Hideaki 463a50feda5SEric Dumazet static void ip6addrlbl_putmsg(struct nlmsghdr *nlh, 4642a8cc6c8SYOSHIFUJI Hideaki int prefixlen, int ifindex, u32 lseq) 4652a8cc6c8SYOSHIFUJI Hideaki { 4662a8cc6c8SYOSHIFUJI Hideaki struct ifaddrlblmsg *ifal = nlmsg_data(nlh); 4672a8cc6c8SYOSHIFUJI Hideaki ifal->ifal_family = AF_INET6; 4682a8cc6c8SYOSHIFUJI Hideaki ifal->ifal_prefixlen = prefixlen; 4692a8cc6c8SYOSHIFUJI Hideaki ifal->ifal_flags = 0; 4702a8cc6c8SYOSHIFUJI Hideaki ifal->ifal_index = ifindex; 4712a8cc6c8SYOSHIFUJI Hideaki ifal->ifal_seq = lseq; 4722a8cc6c8SYOSHIFUJI Hideaki }; 4732a8cc6c8SYOSHIFUJI Hideaki 4742a8cc6c8SYOSHIFUJI Hideaki static int ip6addrlbl_fill(struct sk_buff *skb, 4752a8cc6c8SYOSHIFUJI Hideaki struct ip6addrlbl_entry *p, 4762a8cc6c8SYOSHIFUJI Hideaki u32 lseq, 47715e47304SEric W. Biederman u32 portid, u32 seq, int event, 4782a8cc6c8SYOSHIFUJI Hideaki unsigned int flags) 4792a8cc6c8SYOSHIFUJI Hideaki { 48015e47304SEric W. Biederman struct nlmsghdr *nlh = nlmsg_put(skb, portid, seq, event, 4812a8cc6c8SYOSHIFUJI Hideaki sizeof(struct ifaddrlblmsg), flags); 4822a8cc6c8SYOSHIFUJI Hideaki if (!nlh) 4832a8cc6c8SYOSHIFUJI Hideaki return -EMSGSIZE; 4842a8cc6c8SYOSHIFUJI Hideaki 4852a8cc6c8SYOSHIFUJI Hideaki ip6addrlbl_putmsg(nlh, p->prefixlen, p->ifindex, lseq); 4862a8cc6c8SYOSHIFUJI Hideaki 4872a8cc6c8SYOSHIFUJI Hideaki if (nla_put(skb, IFAL_ADDRESS, 16, &p->prefix) < 0 || 4882a8cc6c8SYOSHIFUJI Hideaki nla_put_u32(skb, IFAL_LABEL, p->label) < 0) { 4892a8cc6c8SYOSHIFUJI Hideaki nlmsg_cancel(skb, nlh); 4902a8cc6c8SYOSHIFUJI Hideaki return -EMSGSIZE; 4912a8cc6c8SYOSHIFUJI Hideaki } 4922a8cc6c8SYOSHIFUJI Hideaki 493053c095aSJohannes Berg nlmsg_end(skb, nlh); 494053c095aSJohannes Berg return 0; 4952a8cc6c8SYOSHIFUJI Hideaki } 4962a8cc6c8SYOSHIFUJI Hideaki 4972a8cc6c8SYOSHIFUJI Hideaki static int ip6addrlbl_dump(struct sk_buff *skb, struct netlink_callback *cb) 4982a8cc6c8SYOSHIFUJI Hideaki { 4993b1e0a65SYOSHIFUJI Hideaki struct net *net = sock_net(skb->sk); 5002a8cc6c8SYOSHIFUJI Hideaki struct ip6addrlbl_entry *p; 5012a8cc6c8SYOSHIFUJI Hideaki int idx = 0, s_idx = cb->args[0]; 5022a8cc6c8SYOSHIFUJI Hideaki int err; 5032a8cc6c8SYOSHIFUJI Hideaki 5042a8cc6c8SYOSHIFUJI Hideaki rcu_read_lock(); 505b67bfe0dSSasha Levin hlist_for_each_entry_rcu(p, &ip6addrlbl_table.head, list) { 5063de23255SBenjamin Thery if (idx >= s_idx && 5073de23255SBenjamin Thery net_eq(ip6addrlbl_net(p), net)) { 508cb6e926eSWang Yufen err = ip6addrlbl_fill(skb, p, 5092a8cc6c8SYOSHIFUJI Hideaki ip6addrlbl_table.seq, 51015e47304SEric W. Biederman NETLINK_CB(cb->skb).portid, 5112a8cc6c8SYOSHIFUJI Hideaki cb->nlh->nlmsg_seq, 5122a8cc6c8SYOSHIFUJI Hideaki RTM_NEWADDRLABEL, 513cb6e926eSWang Yufen NLM_F_MULTI); 514053c095aSJohannes Berg if (err < 0) 5152a8cc6c8SYOSHIFUJI Hideaki break; 5162a8cc6c8SYOSHIFUJI Hideaki } 5172a8cc6c8SYOSHIFUJI Hideaki idx++; 5182a8cc6c8SYOSHIFUJI Hideaki } 5192a8cc6c8SYOSHIFUJI Hideaki rcu_read_unlock(); 5202a8cc6c8SYOSHIFUJI Hideaki cb->args[0] = idx; 5212a8cc6c8SYOSHIFUJI Hideaki return skb->len; 5222a8cc6c8SYOSHIFUJI Hideaki } 5232a8cc6c8SYOSHIFUJI Hideaki 5242a8cc6c8SYOSHIFUJI Hideaki static inline int ip6addrlbl_msgsize(void) 5252a8cc6c8SYOSHIFUJI Hideaki { 526a02cec21SEric Dumazet return NLMSG_ALIGN(sizeof(struct ifaddrlblmsg)) 5272a8cc6c8SYOSHIFUJI Hideaki + nla_total_size(16) /* IFAL_ADDRESS */ 528a02cec21SEric Dumazet + nla_total_size(4); /* IFAL_LABEL */ 5292a8cc6c8SYOSHIFUJI Hideaki } 5302a8cc6c8SYOSHIFUJI Hideaki 531661d2967SThomas Graf static int ip6addrlbl_get(struct sk_buff *in_skb, struct nlmsghdr *nlh) 5322a8cc6c8SYOSHIFUJI Hideaki { 5333b1e0a65SYOSHIFUJI Hideaki struct net *net = sock_net(in_skb->sk); 5342a8cc6c8SYOSHIFUJI Hideaki struct ifaddrlblmsg *ifal; 5352a8cc6c8SYOSHIFUJI Hideaki struct nlattr *tb[IFAL_MAX+1]; 5362a8cc6c8SYOSHIFUJI Hideaki struct in6_addr *addr; 5372a8cc6c8SYOSHIFUJI Hideaki u32 lseq; 5382a8cc6c8SYOSHIFUJI Hideaki int err = 0; 5392a8cc6c8SYOSHIFUJI Hideaki struct ip6addrlbl_entry *p; 5402a8cc6c8SYOSHIFUJI Hideaki struct sk_buff *skb; 5412a8cc6c8SYOSHIFUJI Hideaki 5422a8cc6c8SYOSHIFUJI Hideaki err = nlmsg_parse(nlh, sizeof(*ifal), tb, IFAL_MAX, ifal_policy); 5432a8cc6c8SYOSHIFUJI Hideaki if (err < 0) 5442a8cc6c8SYOSHIFUJI Hideaki return err; 5452a8cc6c8SYOSHIFUJI Hideaki 5462a8cc6c8SYOSHIFUJI Hideaki ifal = nlmsg_data(nlh); 5472a8cc6c8SYOSHIFUJI Hideaki 5482a8cc6c8SYOSHIFUJI Hideaki if (ifal->ifal_family != AF_INET6 || 5492a8cc6c8SYOSHIFUJI Hideaki ifal->ifal_prefixlen != 128) 5502a8cc6c8SYOSHIFUJI Hideaki return -EINVAL; 5512a8cc6c8SYOSHIFUJI Hideaki 5522a8cc6c8SYOSHIFUJI Hideaki if (ifal->ifal_index && 5533de23255SBenjamin Thery !__dev_get_by_index(net, ifal->ifal_index)) 5542a8cc6c8SYOSHIFUJI Hideaki return -EINVAL; 5552a8cc6c8SYOSHIFUJI Hideaki 5562a8cc6c8SYOSHIFUJI Hideaki if (!tb[IFAL_ADDRESS]) 5572a8cc6c8SYOSHIFUJI Hideaki return -EINVAL; 5582a8cc6c8SYOSHIFUJI Hideaki addr = nla_data(tb[IFAL_ADDRESS]); 5592a8cc6c8SYOSHIFUJI Hideaki 5602a8cc6c8SYOSHIFUJI Hideaki rcu_read_lock(); 5613de23255SBenjamin Thery p = __ipv6_addr_label(net, addr, ipv6_addr_type(addr), ifal->ifal_index); 5622a8cc6c8SYOSHIFUJI Hideaki if (p && ip6addrlbl_hold(p)) 5632a8cc6c8SYOSHIFUJI Hideaki p = NULL; 5642a8cc6c8SYOSHIFUJI Hideaki lseq = ip6addrlbl_table.seq; 5652a8cc6c8SYOSHIFUJI Hideaki rcu_read_unlock(); 5662a8cc6c8SYOSHIFUJI Hideaki 5672a8cc6c8SYOSHIFUJI Hideaki if (!p) { 5682a8cc6c8SYOSHIFUJI Hideaki err = -ESRCH; 5692a8cc6c8SYOSHIFUJI Hideaki goto out; 5702a8cc6c8SYOSHIFUJI Hideaki } 5712a8cc6c8SYOSHIFUJI Hideaki 572cb6e926eSWang Yufen skb = nlmsg_new(ip6addrlbl_msgsize(), GFP_KERNEL); 573cb6e926eSWang Yufen if (!skb) { 5742a8cc6c8SYOSHIFUJI Hideaki ip6addrlbl_put(p); 5752a8cc6c8SYOSHIFUJI Hideaki return -ENOBUFS; 5762a8cc6c8SYOSHIFUJI Hideaki } 5772a8cc6c8SYOSHIFUJI Hideaki 5782a8cc6c8SYOSHIFUJI Hideaki err = ip6addrlbl_fill(skb, p, lseq, 57915e47304SEric W. Biederman NETLINK_CB(in_skb).portid, nlh->nlmsg_seq, 5802a8cc6c8SYOSHIFUJI Hideaki RTM_NEWADDRLABEL, 0); 5812a8cc6c8SYOSHIFUJI Hideaki 5822a8cc6c8SYOSHIFUJI Hideaki ip6addrlbl_put(p); 5832a8cc6c8SYOSHIFUJI Hideaki 5842a8cc6c8SYOSHIFUJI Hideaki if (err < 0) { 5852a8cc6c8SYOSHIFUJI Hideaki WARN_ON(err == -EMSGSIZE); 5862a8cc6c8SYOSHIFUJI Hideaki kfree_skb(skb); 5872a8cc6c8SYOSHIFUJI Hideaki goto out; 5882a8cc6c8SYOSHIFUJI Hideaki } 5892a8cc6c8SYOSHIFUJI Hideaki 59015e47304SEric W. Biederman err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid); 5912a8cc6c8SYOSHIFUJI Hideaki out: 5922a8cc6c8SYOSHIFUJI Hideaki return err; 5932a8cc6c8SYOSHIFUJI Hideaki } 5942a8cc6c8SYOSHIFUJI Hideaki 5952a8cc6c8SYOSHIFUJI Hideaki void __init ipv6_addr_label_rtnl_register(void) 5962a8cc6c8SYOSHIFUJI Hideaki { 597c7ac8679SGreg Rose __rtnl_register(PF_INET6, RTM_NEWADDRLABEL, ip6addrlbl_newdel, 598c7ac8679SGreg Rose NULL, NULL); 599c7ac8679SGreg Rose __rtnl_register(PF_INET6, RTM_DELADDRLABEL, ip6addrlbl_newdel, 600c7ac8679SGreg Rose NULL, NULL); 601c7ac8679SGreg Rose __rtnl_register(PF_INET6, RTM_GETADDRLABEL, ip6addrlbl_get, 602c7ac8679SGreg Rose ip6addrlbl_dump, NULL); 6032a8cc6c8SYOSHIFUJI Hideaki } 6042a8cc6c8SYOSHIFUJI Hideaki 605