1d15c345fSPaul Moore /* 2d15c345fSPaul Moore * NetLabel Management Support 3d15c345fSPaul Moore * 4d15c345fSPaul Moore * This file defines the management functions for the NetLabel system. The 5d15c345fSPaul Moore * NetLabel system manages static and dynamic label mappings for network 6d15c345fSPaul Moore * protocols such as CIPSO and RIPSO. 7d15c345fSPaul Moore * 882c21bfaSPaul Moore * Author: Paul Moore <paul@paul-moore.com> 9d15c345fSPaul Moore * 10d15c345fSPaul Moore */ 11d15c345fSPaul Moore 12d15c345fSPaul Moore /* 1363c41688SPaul Moore * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008 14d15c345fSPaul Moore * 15d15c345fSPaul Moore * This program is free software; you can redistribute it and/or modify 16d15c345fSPaul Moore * it under the terms of the GNU General Public License as published by 17d15c345fSPaul Moore * the Free Software Foundation; either version 2 of the License, or 18d15c345fSPaul Moore * (at your option) any later version. 19d15c345fSPaul Moore * 20d15c345fSPaul Moore * This program is distributed in the hope that it will be useful, 21d15c345fSPaul Moore * but WITHOUT ANY WARRANTY; without even the implied warranty of 22d15c345fSPaul Moore * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 23d15c345fSPaul Moore * the GNU General Public License for more details. 24d15c345fSPaul Moore * 25d15c345fSPaul Moore * You should have received a copy of the GNU General Public License 26d484ff15SJeff Kirsher * along with this program; if not, see <http://www.gnu.org/licenses/>. 27d15c345fSPaul Moore * 28d15c345fSPaul Moore */ 29d15c345fSPaul Moore 30d15c345fSPaul Moore #include <linux/types.h> 31d15c345fSPaul Moore #include <linux/socket.h> 32d15c345fSPaul Moore #include <linux/string.h> 33d15c345fSPaul Moore #include <linux/skbuff.h> 3463c41688SPaul Moore #include <linux/in.h> 3563c41688SPaul Moore #include <linux/in6.h> 365a0e3ad6STejun Heo #include <linux/slab.h> 37d15c345fSPaul Moore #include <net/sock.h> 38d15c345fSPaul Moore #include <net/netlink.h> 39d15c345fSPaul Moore #include <net/genetlink.h> 4063c41688SPaul Moore #include <net/ip.h> 4163c41688SPaul Moore #include <net/ipv6.h> 42d15c345fSPaul Moore #include <net/netlabel.h> 43d15c345fSPaul Moore #include <net/cipso_ipv4.h> 4460063497SArun Sharma #include <linux/atomic.h> 45d15c345fSPaul Moore 46d15c345fSPaul Moore #include "netlabel_domainhash.h" 47d15c345fSPaul Moore #include "netlabel_user.h" 48d15c345fSPaul Moore #include "netlabel_mgmt.h" 49d15c345fSPaul Moore 50c783f1ceSPaul Moore /* NetLabel configured protocol counter */ 51c783f1ceSPaul Moore atomic_t netlabel_mgmt_protocount = ATOMIC_INIT(0); 5223bcdc1aSPaul Moore 53fd385855SPaul Moore /* Argument struct for netlbl_domhsh_walk() */ 54fd385855SPaul Moore struct netlbl_domhsh_walk_arg { 55fd385855SPaul Moore struct netlink_callback *nl_cb; 56fd385855SPaul Moore struct sk_buff *skb; 57fd385855SPaul Moore u32 seq; 58fd385855SPaul Moore }; 59fd385855SPaul Moore 60d15c345fSPaul Moore /* NetLabel Generic NETLINK CIPSOv4 family */ 61d15c345fSPaul Moore static struct genl_family netlbl_mgmt_gnl_family = { 62d15c345fSPaul Moore .id = GENL_ID_GENERATE, 63d15c345fSPaul Moore .hdrsize = 0, 64d15c345fSPaul Moore .name = NETLBL_NLTYPE_MGMT_NAME, 65d15c345fSPaul Moore .version = NETLBL_PROTO_VERSION, 66fd385855SPaul Moore .maxattr = NLBL_MGMT_A_MAX, 67d15c345fSPaul Moore }; 68d15c345fSPaul Moore 69fd385855SPaul Moore /* NetLabel Netlink attribute policy */ 70ef7c79edSPatrick McHardy static const struct nla_policy netlbl_mgmt_genl_policy[NLBL_MGMT_A_MAX + 1] = { 71fd385855SPaul Moore [NLBL_MGMT_A_DOMAIN] = { .type = NLA_NUL_STRING }, 72fd385855SPaul Moore [NLBL_MGMT_A_PROTOCOL] = { .type = NLA_U32 }, 73fd385855SPaul Moore [NLBL_MGMT_A_VERSION] = { .type = NLA_U32 }, 74fd385855SPaul Moore [NLBL_MGMT_A_CV4DOI] = { .type = NLA_U32 }, 75fd385855SPaul Moore }; 76d15c345fSPaul Moore 77d15c345fSPaul Moore /* 7863c41688SPaul Moore * Helper Functions 7963c41688SPaul Moore */ 8063c41688SPaul Moore 8163c41688SPaul Moore /** 8263c41688SPaul Moore * netlbl_mgmt_add - Handle an ADD message 8363c41688SPaul Moore * @info: the Generic NETLINK info block 8463c41688SPaul Moore * @audit_info: NetLabel audit information 8563c41688SPaul Moore * 8663c41688SPaul Moore * Description: 8763c41688SPaul Moore * Helper function for the ADD and ADDDEF messages to add the domain mappings 8863c41688SPaul Moore * from the message to the hash table. See netlabel.h for a description of the 8963c41688SPaul Moore * message format. Returns zero on success, negative values on failure. 9063c41688SPaul Moore * 9163c41688SPaul Moore */ 9263c41688SPaul Moore static int netlbl_mgmt_add_common(struct genl_info *info, 9363c41688SPaul Moore struct netlbl_audit *audit_info) 9463c41688SPaul Moore { 9563c41688SPaul Moore int ret_val = -EINVAL; 9663c41688SPaul Moore struct netlbl_domaddr_map *addrmap = NULL; 9763c41688SPaul Moore struct cipso_v4_doi *cipsov4 = NULL; 9863c41688SPaul Moore u32 tmp_val; 994de46d5eSMarkus Elfring struct netlbl_dom_map *entry = kzalloc(sizeof(*entry), GFP_KERNEL); 10063c41688SPaul Moore 1014de46d5eSMarkus Elfring if (!entry) 1024de46d5eSMarkus Elfring return -ENOMEM; 1036a8b7f0cSPaul Moore entry->def.type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]); 10463c41688SPaul Moore if (info->attrs[NLBL_MGMT_A_DOMAIN]) { 10563c41688SPaul Moore size_t tmp_size = nla_len(info->attrs[NLBL_MGMT_A_DOMAIN]); 10663c41688SPaul Moore entry->domain = kmalloc(tmp_size, GFP_KERNEL); 10763c41688SPaul Moore if (entry->domain == NULL) { 10863c41688SPaul Moore ret_val = -ENOMEM; 1094de46d5eSMarkus Elfring goto add_free_entry; 11063c41688SPaul Moore } 11163c41688SPaul Moore nla_strlcpy(entry->domain, 11263c41688SPaul Moore info->attrs[NLBL_MGMT_A_DOMAIN], tmp_size); 11363c41688SPaul Moore } 11463c41688SPaul Moore 1156a8b7f0cSPaul Moore /* NOTE: internally we allow/use a entry->def.type value of 11663c41688SPaul Moore * NETLBL_NLTYPE_ADDRSELECT but we don't currently allow users 11763c41688SPaul Moore * to pass that as a protocol value because we need to know the 11863c41688SPaul Moore * "real" protocol */ 11963c41688SPaul Moore 1206a8b7f0cSPaul Moore switch (entry->def.type) { 12163c41688SPaul Moore case NETLBL_NLTYPE_UNLABELED: 12263c41688SPaul Moore break; 12363c41688SPaul Moore case NETLBL_NLTYPE_CIPSOV4: 12463c41688SPaul Moore if (!info->attrs[NLBL_MGMT_A_CV4DOI]) 1254de46d5eSMarkus Elfring goto add_free_domain; 12663c41688SPaul Moore 12763c41688SPaul Moore tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]); 12863c41688SPaul Moore cipsov4 = cipso_v4_doi_getdef(tmp_val); 12963c41688SPaul Moore if (cipsov4 == NULL) 1304de46d5eSMarkus Elfring goto add_free_domain; 1316a8b7f0cSPaul Moore entry->def.cipso = cipsov4; 13263c41688SPaul Moore break; 13363c41688SPaul Moore default: 1344de46d5eSMarkus Elfring goto add_free_domain; 13563c41688SPaul Moore } 13663c41688SPaul Moore 13763c41688SPaul Moore if (info->attrs[NLBL_MGMT_A_IPV4ADDR]) { 13863c41688SPaul Moore struct in_addr *addr; 13963c41688SPaul Moore struct in_addr *mask; 14063c41688SPaul Moore struct netlbl_domaddr4_map *map; 14163c41688SPaul Moore 14263c41688SPaul Moore addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL); 14363c41688SPaul Moore if (addrmap == NULL) { 14463c41688SPaul Moore ret_val = -ENOMEM; 1454de46d5eSMarkus Elfring goto add_doi_put_def; 14663c41688SPaul Moore } 14763c41688SPaul Moore INIT_LIST_HEAD(&addrmap->list4); 14863c41688SPaul Moore INIT_LIST_HEAD(&addrmap->list6); 14963c41688SPaul Moore 15063c41688SPaul Moore if (nla_len(info->attrs[NLBL_MGMT_A_IPV4ADDR]) != 15163c41688SPaul Moore sizeof(struct in_addr)) { 15263c41688SPaul Moore ret_val = -EINVAL; 1534de46d5eSMarkus Elfring goto add_free_addrmap; 15463c41688SPaul Moore } 15563c41688SPaul Moore if (nla_len(info->attrs[NLBL_MGMT_A_IPV4MASK]) != 15663c41688SPaul Moore sizeof(struct in_addr)) { 15763c41688SPaul Moore ret_val = -EINVAL; 1584de46d5eSMarkus Elfring goto add_free_addrmap; 15963c41688SPaul Moore } 16063c41688SPaul Moore addr = nla_data(info->attrs[NLBL_MGMT_A_IPV4ADDR]); 16163c41688SPaul Moore mask = nla_data(info->attrs[NLBL_MGMT_A_IPV4MASK]); 16263c41688SPaul Moore 16363c41688SPaul Moore map = kzalloc(sizeof(*map), GFP_KERNEL); 16463c41688SPaul Moore if (map == NULL) { 16563c41688SPaul Moore ret_val = -ENOMEM; 1664de46d5eSMarkus Elfring goto add_free_addrmap; 16763c41688SPaul Moore } 16863c41688SPaul Moore map->list.addr = addr->s_addr & mask->s_addr; 16963c41688SPaul Moore map->list.mask = mask->s_addr; 17063c41688SPaul Moore map->list.valid = 1; 1716a8b7f0cSPaul Moore map->def.type = entry->def.type; 17263c41688SPaul Moore if (cipsov4) 1736a8b7f0cSPaul Moore map->def.cipso = cipsov4; 17463c41688SPaul Moore 17563c41688SPaul Moore ret_val = netlbl_af4list_add(&map->list, &addrmap->list4); 17663c41688SPaul Moore if (ret_val != 0) { 17763c41688SPaul Moore kfree(map); 1784de46d5eSMarkus Elfring goto add_free_addrmap; 17963c41688SPaul Moore } 18063c41688SPaul Moore 1816a8b7f0cSPaul Moore entry->def.type = NETLBL_NLTYPE_ADDRSELECT; 1826a8b7f0cSPaul Moore entry->def.addrsel = addrmap; 183dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6) 18463c41688SPaul Moore } else if (info->attrs[NLBL_MGMT_A_IPV6ADDR]) { 18563c41688SPaul Moore struct in6_addr *addr; 18663c41688SPaul Moore struct in6_addr *mask; 18763c41688SPaul Moore struct netlbl_domaddr6_map *map; 18863c41688SPaul Moore 18963c41688SPaul Moore addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL); 19063c41688SPaul Moore if (addrmap == NULL) { 19163c41688SPaul Moore ret_val = -ENOMEM; 1924de46d5eSMarkus Elfring goto add_doi_put_def; 19363c41688SPaul Moore } 19463c41688SPaul Moore INIT_LIST_HEAD(&addrmap->list4); 19563c41688SPaul Moore INIT_LIST_HEAD(&addrmap->list6); 19663c41688SPaul Moore 19763c41688SPaul Moore if (nla_len(info->attrs[NLBL_MGMT_A_IPV6ADDR]) != 19863c41688SPaul Moore sizeof(struct in6_addr)) { 19963c41688SPaul Moore ret_val = -EINVAL; 2004de46d5eSMarkus Elfring goto add_free_addrmap; 20163c41688SPaul Moore } 20263c41688SPaul Moore if (nla_len(info->attrs[NLBL_MGMT_A_IPV6MASK]) != 20363c41688SPaul Moore sizeof(struct in6_addr)) { 20463c41688SPaul Moore ret_val = -EINVAL; 2054de46d5eSMarkus Elfring goto add_free_addrmap; 20663c41688SPaul Moore } 20763c41688SPaul Moore addr = nla_data(info->attrs[NLBL_MGMT_A_IPV6ADDR]); 20863c41688SPaul Moore mask = nla_data(info->attrs[NLBL_MGMT_A_IPV6MASK]); 20963c41688SPaul Moore 21063c41688SPaul Moore map = kzalloc(sizeof(*map), GFP_KERNEL); 21163c41688SPaul Moore if (map == NULL) { 21263c41688SPaul Moore ret_val = -ENOMEM; 2134de46d5eSMarkus Elfring goto add_free_addrmap; 21463c41688SPaul Moore } 2154e3fd7a0SAlexey Dobriyan map->list.addr = *addr; 21663c41688SPaul Moore map->list.addr.s6_addr32[0] &= mask->s6_addr32[0]; 21763c41688SPaul Moore map->list.addr.s6_addr32[1] &= mask->s6_addr32[1]; 21863c41688SPaul Moore map->list.addr.s6_addr32[2] &= mask->s6_addr32[2]; 21963c41688SPaul Moore map->list.addr.s6_addr32[3] &= mask->s6_addr32[3]; 2204e3fd7a0SAlexey Dobriyan map->list.mask = *mask; 22163c41688SPaul Moore map->list.valid = 1; 2226a8b7f0cSPaul Moore map->def.type = entry->def.type; 22363c41688SPaul Moore 22463c41688SPaul Moore ret_val = netlbl_af6list_add(&map->list, &addrmap->list6); 22563c41688SPaul Moore if (ret_val != 0) { 22663c41688SPaul Moore kfree(map); 2274de46d5eSMarkus Elfring goto add_free_addrmap; 22863c41688SPaul Moore } 22963c41688SPaul Moore 2306a8b7f0cSPaul Moore entry->def.type = NETLBL_NLTYPE_ADDRSELECT; 2316a8b7f0cSPaul Moore entry->def.addrsel = addrmap; 23263c41688SPaul Moore #endif /* IPv6 */ 23363c41688SPaul Moore } 23463c41688SPaul Moore 23563c41688SPaul Moore ret_val = netlbl_domhsh_add(entry, audit_info); 23663c41688SPaul Moore if (ret_val != 0) 2374de46d5eSMarkus Elfring goto add_free_addrmap; 23863c41688SPaul Moore 23963c41688SPaul Moore return 0; 24063c41688SPaul Moore 2414de46d5eSMarkus Elfring add_free_addrmap: 24263c41688SPaul Moore kfree(addrmap); 2434de46d5eSMarkus Elfring add_doi_put_def: 2444de46d5eSMarkus Elfring cipso_v4_doi_putdef(cipsov4); 2454de46d5eSMarkus Elfring add_free_domain: 2464de46d5eSMarkus Elfring kfree(entry->domain); 2474de46d5eSMarkus Elfring add_free_entry: 24863c41688SPaul Moore kfree(entry); 24963c41688SPaul Moore return ret_val; 25063c41688SPaul Moore } 25163c41688SPaul Moore 25263c41688SPaul Moore /** 25363c41688SPaul Moore * netlbl_mgmt_listentry - List a NetLabel/LSM domain map entry 25463c41688SPaul Moore * @skb: the NETLINK buffer 25563c41688SPaul Moore * @entry: the map entry 25663c41688SPaul Moore * 25763c41688SPaul Moore * Description: 25863c41688SPaul Moore * This function is a helper function used by the LISTALL and LISTDEF command 25925985edcSLucas De Marchi * handlers. The caller is responsible for ensuring that the RCU read lock 26063c41688SPaul Moore * is held. Returns zero on success, negative values on failure. 26163c41688SPaul Moore * 26263c41688SPaul Moore */ 26363c41688SPaul Moore static int netlbl_mgmt_listentry(struct sk_buff *skb, 26463c41688SPaul Moore struct netlbl_dom_map *entry) 26563c41688SPaul Moore { 266f8a02479SPaul Moore int ret_val = 0; 26763c41688SPaul Moore struct nlattr *nla_a; 26863c41688SPaul Moore struct nlattr *nla_b; 26963c41688SPaul Moore struct netlbl_af4list *iter4; 270dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6) 27163c41688SPaul Moore struct netlbl_af6list *iter6; 27263c41688SPaul Moore #endif 27363c41688SPaul Moore 27463c41688SPaul Moore if (entry->domain != NULL) { 27563c41688SPaul Moore ret_val = nla_put_string(skb, 27663c41688SPaul Moore NLBL_MGMT_A_DOMAIN, entry->domain); 27763c41688SPaul Moore if (ret_val != 0) 27863c41688SPaul Moore return ret_val; 27963c41688SPaul Moore } 28063c41688SPaul Moore 2816a8b7f0cSPaul Moore switch (entry->def.type) { 28263c41688SPaul Moore case NETLBL_NLTYPE_ADDRSELECT: 28363c41688SPaul Moore nla_a = nla_nest_start(skb, NLBL_MGMT_A_SELECTORLIST); 28463c41688SPaul Moore if (nla_a == NULL) 28563c41688SPaul Moore return -ENOMEM; 28663c41688SPaul Moore 2876a8b7f0cSPaul Moore netlbl_af4list_foreach_rcu(iter4, &entry->def.addrsel->list4) { 28863c41688SPaul Moore struct netlbl_domaddr4_map *map4; 28963c41688SPaul Moore struct in_addr addr_struct; 29063c41688SPaul Moore 29163c41688SPaul Moore nla_b = nla_nest_start(skb, NLBL_MGMT_A_ADDRSELECTOR); 29263c41688SPaul Moore if (nla_b == NULL) 29363c41688SPaul Moore return -ENOMEM; 29463c41688SPaul Moore 29563c41688SPaul Moore addr_struct.s_addr = iter4->addr; 29663c41688SPaul Moore ret_val = nla_put(skb, NLBL_MGMT_A_IPV4ADDR, 29763c41688SPaul Moore sizeof(struct in_addr), 29863c41688SPaul Moore &addr_struct); 29963c41688SPaul Moore if (ret_val != 0) 30063c41688SPaul Moore return ret_val; 30163c41688SPaul Moore addr_struct.s_addr = iter4->mask; 30263c41688SPaul Moore ret_val = nla_put(skb, NLBL_MGMT_A_IPV4MASK, 30363c41688SPaul Moore sizeof(struct in_addr), 30463c41688SPaul Moore &addr_struct); 30563c41688SPaul Moore if (ret_val != 0) 30663c41688SPaul Moore return ret_val; 30763c41688SPaul Moore map4 = netlbl_domhsh_addr4_entry(iter4); 30863c41688SPaul Moore ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, 3096a8b7f0cSPaul Moore map4->def.type); 31063c41688SPaul Moore if (ret_val != 0) 31163c41688SPaul Moore return ret_val; 3126a8b7f0cSPaul Moore switch (map4->def.type) { 31363c41688SPaul Moore case NETLBL_NLTYPE_CIPSOV4: 31463c41688SPaul Moore ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI, 3156a8b7f0cSPaul Moore map4->def.cipso->doi); 31663c41688SPaul Moore if (ret_val != 0) 31763c41688SPaul Moore return ret_val; 31863c41688SPaul Moore break; 31963c41688SPaul Moore } 32063c41688SPaul Moore 32163c41688SPaul Moore nla_nest_end(skb, nla_b); 32263c41688SPaul Moore } 323dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6) 3246a8b7f0cSPaul Moore netlbl_af6list_foreach_rcu(iter6, &entry->def.addrsel->list6) { 32563c41688SPaul Moore struct netlbl_domaddr6_map *map6; 32663c41688SPaul Moore 32763c41688SPaul Moore nla_b = nla_nest_start(skb, NLBL_MGMT_A_ADDRSELECTOR); 32863c41688SPaul Moore if (nla_b == NULL) 32963c41688SPaul Moore return -ENOMEM; 33063c41688SPaul Moore 33163c41688SPaul Moore ret_val = nla_put(skb, NLBL_MGMT_A_IPV6ADDR, 33263c41688SPaul Moore sizeof(struct in6_addr), 33363c41688SPaul Moore &iter6->addr); 33463c41688SPaul Moore if (ret_val != 0) 33563c41688SPaul Moore return ret_val; 33663c41688SPaul Moore ret_val = nla_put(skb, NLBL_MGMT_A_IPV6MASK, 33763c41688SPaul Moore sizeof(struct in6_addr), 33863c41688SPaul Moore &iter6->mask); 33963c41688SPaul Moore if (ret_val != 0) 34063c41688SPaul Moore return ret_val; 34163c41688SPaul Moore map6 = netlbl_domhsh_addr6_entry(iter6); 34263c41688SPaul Moore ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, 3436a8b7f0cSPaul Moore map6->def.type); 34463c41688SPaul Moore if (ret_val != 0) 34563c41688SPaul Moore return ret_val; 34663c41688SPaul Moore 34763c41688SPaul Moore nla_nest_end(skb, nla_b); 34863c41688SPaul Moore } 34963c41688SPaul Moore #endif /* IPv6 */ 35063c41688SPaul Moore 35163c41688SPaul Moore nla_nest_end(skb, nla_a); 35263c41688SPaul Moore break; 35363c41688SPaul Moore case NETLBL_NLTYPE_UNLABELED: 3546a8b7f0cSPaul Moore ret_val = nla_put_u32(skb,NLBL_MGMT_A_PROTOCOL,entry->def.type); 35563c41688SPaul Moore break; 35663c41688SPaul Moore case NETLBL_NLTYPE_CIPSOV4: 3576a8b7f0cSPaul Moore ret_val = nla_put_u32(skb,NLBL_MGMT_A_PROTOCOL,entry->def.type); 35863c41688SPaul Moore if (ret_val != 0) 35963c41688SPaul Moore return ret_val; 36063c41688SPaul Moore ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI, 3616a8b7f0cSPaul Moore entry->def.cipso->doi); 36263c41688SPaul Moore break; 36363c41688SPaul Moore } 36463c41688SPaul Moore 36563c41688SPaul Moore return ret_val; 36663c41688SPaul Moore } 36763c41688SPaul Moore 36863c41688SPaul Moore /* 369d15c345fSPaul Moore * NetLabel Command Handlers 370d15c345fSPaul Moore */ 371d15c345fSPaul Moore 372d15c345fSPaul Moore /** 373d15c345fSPaul Moore * netlbl_mgmt_add - Handle an ADD message 374d15c345fSPaul Moore * @skb: the NETLINK buffer 375d15c345fSPaul Moore * @info: the Generic NETLINK info block 376d15c345fSPaul Moore * 377d15c345fSPaul Moore * Description: 378d15c345fSPaul Moore * Process a user generated ADD message and add the domains from the message 379d15c345fSPaul Moore * to the hash table. See netlabel.h for a description of the message format. 380d15c345fSPaul Moore * Returns zero on success, negative values on failure. 381d15c345fSPaul Moore * 382d15c345fSPaul Moore */ 383d15c345fSPaul Moore static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info) 384d15c345fSPaul Moore { 38595d4e6beSPaul Moore struct netlbl_audit audit_info; 386d15c345fSPaul Moore 38763c41688SPaul Moore if ((!info->attrs[NLBL_MGMT_A_DOMAIN]) || 38863c41688SPaul Moore (!info->attrs[NLBL_MGMT_A_PROTOCOL]) || 38963c41688SPaul Moore (info->attrs[NLBL_MGMT_A_IPV4ADDR] && 39063c41688SPaul Moore info->attrs[NLBL_MGMT_A_IPV6ADDR]) || 39163c41688SPaul Moore (info->attrs[NLBL_MGMT_A_IPV4MASK] && 39263c41688SPaul Moore info->attrs[NLBL_MGMT_A_IPV6MASK]) || 39363c41688SPaul Moore ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^ 39463c41688SPaul Moore (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) || 39563c41688SPaul Moore ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^ 39663c41688SPaul Moore (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL))) 39763c41688SPaul Moore return -EINVAL; 398d15c345fSPaul Moore 39995d4e6beSPaul Moore netlbl_netlink_auditinfo(skb, &audit_info); 40095d4e6beSPaul Moore 40163c41688SPaul Moore return netlbl_mgmt_add_common(info, &audit_info); 402d15c345fSPaul Moore } 403d15c345fSPaul Moore 404d15c345fSPaul Moore /** 405d15c345fSPaul Moore * netlbl_mgmt_remove - Handle a REMOVE message 406d15c345fSPaul Moore * @skb: the NETLINK buffer 407d15c345fSPaul Moore * @info: the Generic NETLINK info block 408d15c345fSPaul Moore * 409d15c345fSPaul Moore * Description: 410d15c345fSPaul Moore * Process a user generated REMOVE message and remove the specified domain 411d15c345fSPaul Moore * mappings. Returns zero on success, negative values on failure. 412d15c345fSPaul Moore * 413d15c345fSPaul Moore */ 414d15c345fSPaul Moore static int netlbl_mgmt_remove(struct sk_buff *skb, struct genl_info *info) 415d15c345fSPaul Moore { 416fd385855SPaul Moore char *domain; 41795d4e6beSPaul Moore struct netlbl_audit audit_info; 418d15c345fSPaul Moore 419fd385855SPaul Moore if (!info->attrs[NLBL_MGMT_A_DOMAIN]) 420fd385855SPaul Moore return -EINVAL; 421d15c345fSPaul Moore 42295d4e6beSPaul Moore netlbl_netlink_auditinfo(skb, &audit_info); 42395d4e6beSPaul Moore 424fd385855SPaul Moore domain = nla_data(info->attrs[NLBL_MGMT_A_DOMAIN]); 42595d4e6beSPaul Moore return netlbl_domhsh_remove(domain, &audit_info); 426d15c345fSPaul Moore } 427d15c345fSPaul Moore 428fd385855SPaul Moore /** 429fd385855SPaul Moore * netlbl_mgmt_listall_cb - netlbl_domhsh_walk() callback for LISTALL 430fd385855SPaul Moore * @entry: the domain mapping hash table entry 431fd385855SPaul Moore * @arg: the netlbl_domhsh_walk_arg structure 432fd385855SPaul Moore * 433fd385855SPaul Moore * Description: 434fd385855SPaul Moore * This function is designed to be used as a callback to the 435fd385855SPaul Moore * netlbl_domhsh_walk() function for use in generating a response for a LISTALL 436fd385855SPaul Moore * message. Returns the size of the message on success, negative values on 437fd385855SPaul Moore * failure. 438fd385855SPaul Moore * 439fd385855SPaul Moore */ 440fd385855SPaul Moore static int netlbl_mgmt_listall_cb(struct netlbl_dom_map *entry, void *arg) 441fd385855SPaul Moore { 442fd385855SPaul Moore int ret_val = -ENOMEM; 443fd385855SPaul Moore struct netlbl_domhsh_walk_arg *cb_arg = arg; 444fd385855SPaul Moore void *data; 445d15c345fSPaul Moore 44615e47304SEric W. Biederman data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).portid, 44717c157c8SThomas Graf cb_arg->seq, &netlbl_mgmt_gnl_family, 44817c157c8SThomas Graf NLM_F_MULTI, NLBL_MGMT_C_LISTALL); 449fd385855SPaul Moore if (data == NULL) 450fd385855SPaul Moore goto listall_cb_failure; 451fd385855SPaul Moore 45263c41688SPaul Moore ret_val = netlbl_mgmt_listentry(cb_arg->skb, entry); 453fd385855SPaul Moore if (ret_val != 0) 454fd385855SPaul Moore goto listall_cb_failure; 455fd385855SPaul Moore 456fd385855SPaul Moore cb_arg->seq++; 457053c095aSJohannes Berg genlmsg_end(cb_arg->skb, data); 458053c095aSJohannes Berg return 0; 459fd385855SPaul Moore 460fd385855SPaul Moore listall_cb_failure: 461fd385855SPaul Moore genlmsg_cancel(cb_arg->skb, data); 462d15c345fSPaul Moore return ret_val; 463d15c345fSPaul Moore } 464d15c345fSPaul Moore 465d15c345fSPaul Moore /** 466fd385855SPaul Moore * netlbl_mgmt_listall - Handle a LISTALL message 467d15c345fSPaul Moore * @skb: the NETLINK buffer 468fd385855SPaul Moore * @cb: the NETLINK callback 469d15c345fSPaul Moore * 470d15c345fSPaul Moore * Description: 471fd385855SPaul Moore * Process a user generated LISTALL message and dumps the domain hash table in 472fd385855SPaul Moore * a form suitable for use in a kernel generated LISTALL message. Returns zero 473fd385855SPaul Moore * on success, negative values on failure. 474d15c345fSPaul Moore * 475d15c345fSPaul Moore */ 476fd385855SPaul Moore static int netlbl_mgmt_listall(struct sk_buff *skb, 477fd385855SPaul Moore struct netlink_callback *cb) 478d15c345fSPaul Moore { 479fd385855SPaul Moore struct netlbl_domhsh_walk_arg cb_arg; 480fd385855SPaul Moore u32 skip_bkt = cb->args[0]; 481fd385855SPaul Moore u32 skip_chain = cb->args[1]; 482d15c345fSPaul Moore 483fd385855SPaul Moore cb_arg.nl_cb = cb; 484fd385855SPaul Moore cb_arg.skb = skb; 485fd385855SPaul Moore cb_arg.seq = cb->nlh->nlmsg_seq; 486d15c345fSPaul Moore 487fd385855SPaul Moore netlbl_domhsh_walk(&skip_bkt, 488fd385855SPaul Moore &skip_chain, 489fd385855SPaul Moore netlbl_mgmt_listall_cb, 490fd385855SPaul Moore &cb_arg); 491d15c345fSPaul Moore 492fd385855SPaul Moore cb->args[0] = skip_bkt; 493fd385855SPaul Moore cb->args[1] = skip_chain; 494fd385855SPaul Moore return skb->len; 495d15c345fSPaul Moore } 496d15c345fSPaul Moore 497d15c345fSPaul Moore /** 498d15c345fSPaul Moore * netlbl_mgmt_adddef - Handle an ADDDEF message 499d15c345fSPaul Moore * @skb: the NETLINK buffer 500d15c345fSPaul Moore * @info: the Generic NETLINK info block 501d15c345fSPaul Moore * 502d15c345fSPaul Moore * Description: 503d15c345fSPaul Moore * Process a user generated ADDDEF message and respond accordingly. Returns 504d15c345fSPaul Moore * zero on success, negative values on failure. 505d15c345fSPaul Moore * 506d15c345fSPaul Moore */ 507d15c345fSPaul Moore static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info) 508d15c345fSPaul Moore { 50995d4e6beSPaul Moore struct netlbl_audit audit_info; 510d15c345fSPaul Moore 51163c41688SPaul Moore if ((!info->attrs[NLBL_MGMT_A_PROTOCOL]) || 51263c41688SPaul Moore (info->attrs[NLBL_MGMT_A_IPV4ADDR] && 51363c41688SPaul Moore info->attrs[NLBL_MGMT_A_IPV6ADDR]) || 51463c41688SPaul Moore (info->attrs[NLBL_MGMT_A_IPV4MASK] && 51563c41688SPaul Moore info->attrs[NLBL_MGMT_A_IPV6MASK]) || 51663c41688SPaul Moore ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^ 51763c41688SPaul Moore (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) || 51863c41688SPaul Moore ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^ 51963c41688SPaul Moore (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL))) 52063c41688SPaul Moore return -EINVAL; 521d15c345fSPaul Moore 52295d4e6beSPaul Moore netlbl_netlink_auditinfo(skb, &audit_info); 52395d4e6beSPaul Moore 52463c41688SPaul Moore return netlbl_mgmt_add_common(info, &audit_info); 525d15c345fSPaul Moore } 526d15c345fSPaul Moore 527d15c345fSPaul Moore /** 528d15c345fSPaul Moore * netlbl_mgmt_removedef - Handle a REMOVEDEF message 529d15c345fSPaul Moore * @skb: the NETLINK buffer 530d15c345fSPaul Moore * @info: the Generic NETLINK info block 531d15c345fSPaul Moore * 532d15c345fSPaul Moore * Description: 533d15c345fSPaul Moore * Process a user generated REMOVEDEF message and remove the default domain 534d15c345fSPaul Moore * mapping. Returns zero on success, negative values on failure. 535d15c345fSPaul Moore * 536d15c345fSPaul Moore */ 537d15c345fSPaul Moore static int netlbl_mgmt_removedef(struct sk_buff *skb, struct genl_info *info) 538d15c345fSPaul Moore { 53995d4e6beSPaul Moore struct netlbl_audit audit_info; 54095d4e6beSPaul Moore 54195d4e6beSPaul Moore netlbl_netlink_auditinfo(skb, &audit_info); 54295d4e6beSPaul Moore 54395d4e6beSPaul Moore return netlbl_domhsh_remove_default(&audit_info); 544d15c345fSPaul Moore } 545d15c345fSPaul Moore 546d15c345fSPaul Moore /** 547d15c345fSPaul Moore * netlbl_mgmt_listdef - Handle a LISTDEF message 548d15c345fSPaul Moore * @skb: the NETLINK buffer 549d15c345fSPaul Moore * @info: the Generic NETLINK info block 550d15c345fSPaul Moore * 551d15c345fSPaul Moore * Description: 552d15c345fSPaul Moore * Process a user generated LISTDEF message and dumps the default domain 553d15c345fSPaul Moore * mapping in a form suitable for use in a kernel generated LISTDEF message. 554d15c345fSPaul Moore * Returns zero on success, negative values on failure. 555d15c345fSPaul Moore * 556d15c345fSPaul Moore */ 557d15c345fSPaul Moore static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info) 558d15c345fSPaul Moore { 559d15c345fSPaul Moore int ret_val = -ENOMEM; 560fd385855SPaul Moore struct sk_buff *ans_skb = NULL; 561fd385855SPaul Moore void *data; 562fd385855SPaul Moore struct netlbl_dom_map *entry; 563d15c345fSPaul Moore 564339bf98fSThomas Graf ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 565d15c345fSPaul Moore if (ans_skb == NULL) 566fd385855SPaul Moore return -ENOMEM; 56717c157c8SThomas Graf data = genlmsg_put_reply(ans_skb, info, &netlbl_mgmt_gnl_family, 56817c157c8SThomas Graf 0, NLBL_MGMT_C_LISTDEF); 569fd385855SPaul Moore if (data == NULL) 570fd385855SPaul Moore goto listdef_failure; 571d15c345fSPaul Moore 572fd385855SPaul Moore rcu_read_lock(); 573fd385855SPaul Moore entry = netlbl_domhsh_getentry(NULL); 574fd385855SPaul Moore if (entry == NULL) { 575fd385855SPaul Moore ret_val = -ENOENT; 576fd385855SPaul Moore goto listdef_failure_lock; 577fd385855SPaul Moore } 57863c41688SPaul Moore ret_val = netlbl_mgmt_listentry(ans_skb, entry); 579fd385855SPaul Moore rcu_read_unlock(); 58063c41688SPaul Moore if (ret_val != 0) 58163c41688SPaul Moore goto listdef_failure; 582fd385855SPaul Moore 583fd385855SPaul Moore genlmsg_end(ans_skb, data); 584fe785beeSDenis V. Lunev return genlmsg_reply(ans_skb, info); 585d15c345fSPaul Moore 586fd385855SPaul Moore listdef_failure_lock: 587fd385855SPaul Moore rcu_read_unlock(); 588d15c345fSPaul Moore listdef_failure: 589fd385855SPaul Moore kfree_skb(ans_skb); 590d15c345fSPaul Moore return ret_val; 591d15c345fSPaul Moore } 592d15c345fSPaul Moore 593d15c345fSPaul Moore /** 594fd385855SPaul Moore * netlbl_mgmt_protocols_cb - Write an individual PROTOCOL message response 595fd385855SPaul Moore * @skb: the skb to write to 596fd385855SPaul Moore * @cb: the NETLINK callback 597fd385855SPaul Moore * @protocol: the NetLabel protocol to use in the message 598d15c345fSPaul Moore * 599d15c345fSPaul Moore * Description: 600fd385855SPaul Moore * This function is to be used in conjunction with netlbl_mgmt_protocols() to 601fd385855SPaul Moore * answer a application's PROTOCOLS message. Returns the size of the message 602fd385855SPaul Moore * on success, negative values on failure. 603d15c345fSPaul Moore * 604d15c345fSPaul Moore */ 605fd385855SPaul Moore static int netlbl_mgmt_protocols_cb(struct sk_buff *skb, 606fd385855SPaul Moore struct netlink_callback *cb, 607fd385855SPaul Moore u32 protocol) 608d15c345fSPaul Moore { 609d15c345fSPaul Moore int ret_val = -ENOMEM; 610fd385855SPaul Moore void *data; 611d15c345fSPaul Moore 61215e47304SEric W. Biederman data = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, 61317c157c8SThomas Graf &netlbl_mgmt_gnl_family, NLM_F_MULTI, 614fd385855SPaul Moore NLBL_MGMT_C_PROTOCOLS); 615fd385855SPaul Moore if (data == NULL) 616fd385855SPaul Moore goto protocols_cb_failure; 617d15c345fSPaul Moore 618fd385855SPaul Moore ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, protocol); 619d15c345fSPaul Moore if (ret_val != 0) 620fd385855SPaul Moore goto protocols_cb_failure; 621d15c345fSPaul Moore 622053c095aSJohannes Berg genlmsg_end(skb, data); 623053c095aSJohannes Berg return 0; 624d15c345fSPaul Moore 625fd385855SPaul Moore protocols_cb_failure: 626fd385855SPaul Moore genlmsg_cancel(skb, data); 627d15c345fSPaul Moore return ret_val; 628d15c345fSPaul Moore } 629d15c345fSPaul Moore 630d15c345fSPaul Moore /** 631fd385855SPaul Moore * netlbl_mgmt_protocols - Handle a PROTOCOLS message 632fd385855SPaul Moore * @skb: the NETLINK buffer 633fd385855SPaul Moore * @cb: the NETLINK callback 634fd385855SPaul Moore * 635fd385855SPaul Moore * Description: 636fd385855SPaul Moore * Process a user generated PROTOCOLS message and respond accordingly. 637fd385855SPaul Moore * 638fd385855SPaul Moore */ 639fd385855SPaul Moore static int netlbl_mgmt_protocols(struct sk_buff *skb, 640fd385855SPaul Moore struct netlink_callback *cb) 641fd385855SPaul Moore { 642fd385855SPaul Moore u32 protos_sent = cb->args[0]; 643fd385855SPaul Moore 644fd385855SPaul Moore if (protos_sent == 0) { 645fd385855SPaul Moore if (netlbl_mgmt_protocols_cb(skb, 646fd385855SPaul Moore cb, 647fd385855SPaul Moore NETLBL_NLTYPE_UNLABELED) < 0) 648fd385855SPaul Moore goto protocols_return; 649fd385855SPaul Moore protos_sent++; 650fd385855SPaul Moore } 651fd385855SPaul Moore if (protos_sent == 1) { 652fd385855SPaul Moore if (netlbl_mgmt_protocols_cb(skb, 653fd385855SPaul Moore cb, 654fd385855SPaul Moore NETLBL_NLTYPE_CIPSOV4) < 0) 655fd385855SPaul Moore goto protocols_return; 656fd385855SPaul Moore protos_sent++; 657fd385855SPaul Moore } 658fd385855SPaul Moore 659fd385855SPaul Moore protocols_return: 660fd385855SPaul Moore cb->args[0] = protos_sent; 661fd385855SPaul Moore return skb->len; 662fd385855SPaul Moore } 663fd385855SPaul Moore 664fd385855SPaul Moore /** 665d15c345fSPaul Moore * netlbl_mgmt_version - Handle a VERSION message 666d15c345fSPaul Moore * @skb: the NETLINK buffer 667d15c345fSPaul Moore * @info: the Generic NETLINK info block 668d15c345fSPaul Moore * 669d15c345fSPaul Moore * Description: 670d15c345fSPaul Moore * Process a user generated VERSION message and respond accordingly. Returns 671d15c345fSPaul Moore * zero on success, negative values on failure. 672d15c345fSPaul Moore * 673d15c345fSPaul Moore */ 674d15c345fSPaul Moore static int netlbl_mgmt_version(struct sk_buff *skb, struct genl_info *info) 675d15c345fSPaul Moore { 676d15c345fSPaul Moore int ret_val = -ENOMEM; 677d15c345fSPaul Moore struct sk_buff *ans_skb = NULL; 678fd385855SPaul Moore void *data; 679d15c345fSPaul Moore 680339bf98fSThomas Graf ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 681d15c345fSPaul Moore if (ans_skb == NULL) 682fd385855SPaul Moore return -ENOMEM; 68317c157c8SThomas Graf data = genlmsg_put_reply(ans_skb, info, &netlbl_mgmt_gnl_family, 68417c157c8SThomas Graf 0, NLBL_MGMT_C_VERSION); 685fd385855SPaul Moore if (data == NULL) 686d15c345fSPaul Moore goto version_failure; 687d15c345fSPaul Moore 688fd385855SPaul Moore ret_val = nla_put_u32(ans_skb, 689fd385855SPaul Moore NLBL_MGMT_A_VERSION, 690fd385855SPaul Moore NETLBL_PROTO_VERSION); 691d15c345fSPaul Moore if (ret_val != 0) 692d15c345fSPaul Moore goto version_failure; 693d15c345fSPaul Moore 694fd385855SPaul Moore genlmsg_end(ans_skb, data); 695fe785beeSDenis V. Lunev return genlmsg_reply(ans_skb, info); 696d15c345fSPaul Moore 697d15c345fSPaul Moore version_failure: 698d15c345fSPaul Moore kfree_skb(ans_skb); 699d15c345fSPaul Moore return ret_val; 700d15c345fSPaul Moore } 701d15c345fSPaul Moore 702d15c345fSPaul Moore 703d15c345fSPaul Moore /* 704d15c345fSPaul Moore * NetLabel Generic NETLINK Command Definitions 705d15c345fSPaul Moore */ 706d15c345fSPaul Moore 7074534de83SJohannes Berg static const struct genl_ops netlbl_mgmt_genl_ops[] = { 708227c43c3SPavel Emelyanov { 709d15c345fSPaul Moore .cmd = NLBL_MGMT_C_ADD, 710fd385855SPaul Moore .flags = GENL_ADMIN_PERM, 711fd385855SPaul Moore .policy = netlbl_mgmt_genl_policy, 712d15c345fSPaul Moore .doit = netlbl_mgmt_add, 713d15c345fSPaul Moore .dumpit = NULL, 714227c43c3SPavel Emelyanov }, 715227c43c3SPavel Emelyanov { 716d15c345fSPaul Moore .cmd = NLBL_MGMT_C_REMOVE, 717fd385855SPaul Moore .flags = GENL_ADMIN_PERM, 718fd385855SPaul Moore .policy = netlbl_mgmt_genl_policy, 719d15c345fSPaul Moore .doit = netlbl_mgmt_remove, 720d15c345fSPaul Moore .dumpit = NULL, 721227c43c3SPavel Emelyanov }, 722227c43c3SPavel Emelyanov { 723fd385855SPaul Moore .cmd = NLBL_MGMT_C_LISTALL, 724d15c345fSPaul Moore .flags = 0, 725fd385855SPaul Moore .policy = netlbl_mgmt_genl_policy, 726fd385855SPaul Moore .doit = NULL, 727fd385855SPaul Moore .dumpit = netlbl_mgmt_listall, 728227c43c3SPavel Emelyanov }, 729227c43c3SPavel Emelyanov { 730d15c345fSPaul Moore .cmd = NLBL_MGMT_C_ADDDEF, 731fd385855SPaul Moore .flags = GENL_ADMIN_PERM, 732fd385855SPaul Moore .policy = netlbl_mgmt_genl_policy, 733d15c345fSPaul Moore .doit = netlbl_mgmt_adddef, 734d15c345fSPaul Moore .dumpit = NULL, 735227c43c3SPavel Emelyanov }, 736227c43c3SPavel Emelyanov { 737d15c345fSPaul Moore .cmd = NLBL_MGMT_C_REMOVEDEF, 738fd385855SPaul Moore .flags = GENL_ADMIN_PERM, 739fd385855SPaul Moore .policy = netlbl_mgmt_genl_policy, 740d15c345fSPaul Moore .doit = netlbl_mgmt_removedef, 741d15c345fSPaul Moore .dumpit = NULL, 742227c43c3SPavel Emelyanov }, 743227c43c3SPavel Emelyanov { 744d15c345fSPaul Moore .cmd = NLBL_MGMT_C_LISTDEF, 745d15c345fSPaul Moore .flags = 0, 746fd385855SPaul Moore .policy = netlbl_mgmt_genl_policy, 747d15c345fSPaul Moore .doit = netlbl_mgmt_listdef, 748d15c345fSPaul Moore .dumpit = NULL, 749227c43c3SPavel Emelyanov }, 750227c43c3SPavel Emelyanov { 751fd385855SPaul Moore .cmd = NLBL_MGMT_C_PROTOCOLS, 752d15c345fSPaul Moore .flags = 0, 753fd385855SPaul Moore .policy = netlbl_mgmt_genl_policy, 754fd385855SPaul Moore .doit = NULL, 755fd385855SPaul Moore .dumpit = netlbl_mgmt_protocols, 756227c43c3SPavel Emelyanov }, 757227c43c3SPavel Emelyanov { 758d15c345fSPaul Moore .cmd = NLBL_MGMT_C_VERSION, 759d15c345fSPaul Moore .flags = 0, 760fd385855SPaul Moore .policy = netlbl_mgmt_genl_policy, 761d15c345fSPaul Moore .doit = netlbl_mgmt_version, 762d15c345fSPaul Moore .dumpit = NULL, 763227c43c3SPavel Emelyanov }, 764d15c345fSPaul Moore }; 765d15c345fSPaul Moore 766d15c345fSPaul Moore /* 767d15c345fSPaul Moore * NetLabel Generic NETLINK Protocol Functions 768d15c345fSPaul Moore */ 769d15c345fSPaul Moore 770d15c345fSPaul Moore /** 771d15c345fSPaul Moore * netlbl_mgmt_genl_init - Register the NetLabel management component 772d15c345fSPaul Moore * 773d15c345fSPaul Moore * Description: 774d15c345fSPaul Moore * Register the NetLabel management component with the Generic NETLINK 775d15c345fSPaul Moore * mechanism. Returns zero on success, negative values on failure. 776d15c345fSPaul Moore * 777d15c345fSPaul Moore */ 77805705e4eSPavel Emelyanov int __init netlbl_mgmt_genl_init(void) 779d15c345fSPaul Moore { 7807ae740dfSMichał Mirosław return genl_register_family_with_ops(&netlbl_mgmt_gnl_family, 781c53ed742SJohannes Berg netlbl_mgmt_genl_ops); 782d15c345fSPaul Moore } 783