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 * 8d15c345fSPaul Moore * Author: Paul Moore <paul.moore@hp.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 26d15c345fSPaul Moore * along with this program; if not, write to the Free Software 27d15c345fSPaul Moore * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 28d15c345fSPaul Moore * 29d15c345fSPaul Moore */ 30d15c345fSPaul Moore 31d15c345fSPaul Moore #include <linux/types.h> 32d15c345fSPaul Moore #include <linux/socket.h> 33d15c345fSPaul Moore #include <linux/string.h> 34d15c345fSPaul Moore #include <linux/skbuff.h> 3563c41688SPaul Moore #include <linux/in.h> 3663c41688SPaul Moore #include <linux/in6.h> 375a0e3ad6STejun Heo #include <linux/slab.h> 38d15c345fSPaul Moore #include <net/sock.h> 39d15c345fSPaul Moore #include <net/netlink.h> 40d15c345fSPaul Moore #include <net/genetlink.h> 4163c41688SPaul Moore #include <net/ip.h> 4263c41688SPaul Moore #include <net/ipv6.h> 43d15c345fSPaul Moore #include <net/netlabel.h> 44d15c345fSPaul Moore #include <net/cipso_ipv4.h> 4560063497SArun Sharma #include <linux/atomic.h> 46d15c345fSPaul Moore 47d15c345fSPaul Moore #include "netlabel_domainhash.h" 48d15c345fSPaul Moore #include "netlabel_user.h" 49d15c345fSPaul Moore #include "netlabel_mgmt.h" 50d15c345fSPaul Moore 51c783f1ceSPaul Moore /* NetLabel configured protocol counter */ 52c783f1ceSPaul Moore atomic_t netlabel_mgmt_protocount = ATOMIC_INIT(0); 5323bcdc1aSPaul Moore 54fd385855SPaul Moore /* Argument struct for netlbl_domhsh_walk() */ 55fd385855SPaul Moore struct netlbl_domhsh_walk_arg { 56fd385855SPaul Moore struct netlink_callback *nl_cb; 57fd385855SPaul Moore struct sk_buff *skb; 58fd385855SPaul Moore u32 seq; 59fd385855SPaul Moore }; 60fd385855SPaul Moore 61d15c345fSPaul Moore /* NetLabel Generic NETLINK CIPSOv4 family */ 62d15c345fSPaul Moore static struct genl_family netlbl_mgmt_gnl_family = { 63d15c345fSPaul Moore .id = GENL_ID_GENERATE, 64d15c345fSPaul Moore .hdrsize = 0, 65d15c345fSPaul Moore .name = NETLBL_NLTYPE_MGMT_NAME, 66d15c345fSPaul Moore .version = NETLBL_PROTO_VERSION, 67fd385855SPaul Moore .maxattr = NLBL_MGMT_A_MAX, 68d15c345fSPaul Moore }; 69d15c345fSPaul Moore 70fd385855SPaul Moore /* NetLabel Netlink attribute policy */ 71ef7c79edSPatrick McHardy static const struct nla_policy netlbl_mgmt_genl_policy[NLBL_MGMT_A_MAX + 1] = { 72fd385855SPaul Moore [NLBL_MGMT_A_DOMAIN] = { .type = NLA_NUL_STRING }, 73fd385855SPaul Moore [NLBL_MGMT_A_PROTOCOL] = { .type = NLA_U32 }, 74fd385855SPaul Moore [NLBL_MGMT_A_VERSION] = { .type = NLA_U32 }, 75fd385855SPaul Moore [NLBL_MGMT_A_CV4DOI] = { .type = NLA_U32 }, 76fd385855SPaul Moore }; 77d15c345fSPaul Moore 78d15c345fSPaul Moore /* 7963c41688SPaul Moore * Helper Functions 8063c41688SPaul Moore */ 8163c41688SPaul Moore 8263c41688SPaul Moore /** 8363c41688SPaul Moore * netlbl_mgmt_add - Handle an ADD message 8463c41688SPaul Moore * @info: the Generic NETLINK info block 8563c41688SPaul Moore * @audit_info: NetLabel audit information 8663c41688SPaul Moore * 8763c41688SPaul Moore * Description: 8863c41688SPaul Moore * Helper function for the ADD and ADDDEF messages to add the domain mappings 8963c41688SPaul Moore * from the message to the hash table. See netlabel.h for a description of the 9063c41688SPaul Moore * message format. Returns zero on success, negative values on failure. 9163c41688SPaul Moore * 9263c41688SPaul Moore */ 9363c41688SPaul Moore static int netlbl_mgmt_add_common(struct genl_info *info, 9463c41688SPaul Moore struct netlbl_audit *audit_info) 9563c41688SPaul Moore { 9663c41688SPaul Moore int ret_val = -EINVAL; 9763c41688SPaul Moore struct netlbl_dom_map *entry = NULL; 9863c41688SPaul Moore struct netlbl_domaddr_map *addrmap = NULL; 9963c41688SPaul Moore struct cipso_v4_doi *cipsov4 = NULL; 10063c41688SPaul Moore u32 tmp_val; 10163c41688SPaul Moore 10263c41688SPaul Moore entry = kzalloc(sizeof(*entry), GFP_KERNEL); 10363c41688SPaul Moore if (entry == NULL) { 10463c41688SPaul Moore ret_val = -ENOMEM; 10563c41688SPaul Moore goto add_failure; 10663c41688SPaul Moore } 10763c41688SPaul Moore entry->type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]); 10863c41688SPaul Moore if (info->attrs[NLBL_MGMT_A_DOMAIN]) { 10963c41688SPaul Moore size_t tmp_size = nla_len(info->attrs[NLBL_MGMT_A_DOMAIN]); 11063c41688SPaul Moore entry->domain = kmalloc(tmp_size, GFP_KERNEL); 11163c41688SPaul Moore if (entry->domain == NULL) { 11263c41688SPaul Moore ret_val = -ENOMEM; 11363c41688SPaul Moore goto add_failure; 11463c41688SPaul Moore } 11563c41688SPaul Moore nla_strlcpy(entry->domain, 11663c41688SPaul Moore info->attrs[NLBL_MGMT_A_DOMAIN], tmp_size); 11763c41688SPaul Moore } 11863c41688SPaul Moore 11963c41688SPaul Moore /* NOTE: internally we allow/use a entry->type value of 12063c41688SPaul Moore * NETLBL_NLTYPE_ADDRSELECT but we don't currently allow users 12163c41688SPaul Moore * to pass that as a protocol value because we need to know the 12263c41688SPaul Moore * "real" protocol */ 12363c41688SPaul Moore 12463c41688SPaul Moore switch (entry->type) { 12563c41688SPaul Moore case NETLBL_NLTYPE_UNLABELED: 12663c41688SPaul Moore break; 12763c41688SPaul Moore case NETLBL_NLTYPE_CIPSOV4: 12863c41688SPaul Moore if (!info->attrs[NLBL_MGMT_A_CV4DOI]) 12963c41688SPaul Moore goto add_failure; 13063c41688SPaul Moore 13163c41688SPaul Moore tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]); 13263c41688SPaul Moore cipsov4 = cipso_v4_doi_getdef(tmp_val); 13363c41688SPaul Moore if (cipsov4 == NULL) 13463c41688SPaul Moore goto add_failure; 13563c41688SPaul Moore entry->type_def.cipsov4 = cipsov4; 13663c41688SPaul Moore break; 13763c41688SPaul Moore default: 13863c41688SPaul Moore goto add_failure; 13963c41688SPaul Moore } 14063c41688SPaul Moore 14163c41688SPaul Moore if (info->attrs[NLBL_MGMT_A_IPV4ADDR]) { 14263c41688SPaul Moore struct in_addr *addr; 14363c41688SPaul Moore struct in_addr *mask; 14463c41688SPaul Moore struct netlbl_domaddr4_map *map; 14563c41688SPaul Moore 14663c41688SPaul Moore addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL); 14763c41688SPaul Moore if (addrmap == NULL) { 14863c41688SPaul Moore ret_val = -ENOMEM; 14963c41688SPaul Moore goto add_failure; 15063c41688SPaul Moore } 15163c41688SPaul Moore INIT_LIST_HEAD(&addrmap->list4); 15263c41688SPaul Moore INIT_LIST_HEAD(&addrmap->list6); 15363c41688SPaul Moore 15463c41688SPaul Moore if (nla_len(info->attrs[NLBL_MGMT_A_IPV4ADDR]) != 15563c41688SPaul Moore sizeof(struct in_addr)) { 15663c41688SPaul Moore ret_val = -EINVAL; 15763c41688SPaul Moore goto add_failure; 15863c41688SPaul Moore } 15963c41688SPaul Moore if (nla_len(info->attrs[NLBL_MGMT_A_IPV4MASK]) != 16063c41688SPaul Moore sizeof(struct in_addr)) { 16163c41688SPaul Moore ret_val = -EINVAL; 16263c41688SPaul Moore goto add_failure; 16363c41688SPaul Moore } 16463c41688SPaul Moore addr = nla_data(info->attrs[NLBL_MGMT_A_IPV4ADDR]); 16563c41688SPaul Moore mask = nla_data(info->attrs[NLBL_MGMT_A_IPV4MASK]); 16663c41688SPaul Moore 16763c41688SPaul Moore map = kzalloc(sizeof(*map), GFP_KERNEL); 16863c41688SPaul Moore if (map == NULL) { 16963c41688SPaul Moore ret_val = -ENOMEM; 17063c41688SPaul Moore goto add_failure; 17163c41688SPaul Moore } 17263c41688SPaul Moore map->list.addr = addr->s_addr & mask->s_addr; 17363c41688SPaul Moore map->list.mask = mask->s_addr; 17463c41688SPaul Moore map->list.valid = 1; 17563c41688SPaul Moore map->type = entry->type; 17663c41688SPaul Moore if (cipsov4) 17763c41688SPaul Moore map->type_def.cipsov4 = cipsov4; 17863c41688SPaul Moore 17963c41688SPaul Moore ret_val = netlbl_af4list_add(&map->list, &addrmap->list4); 18063c41688SPaul Moore if (ret_val != 0) { 18163c41688SPaul Moore kfree(map); 18263c41688SPaul Moore goto add_failure; 18363c41688SPaul Moore } 18463c41688SPaul Moore 18563c41688SPaul Moore entry->type = NETLBL_NLTYPE_ADDRSELECT; 18663c41688SPaul Moore entry->type_def.addrsel = addrmap; 18763c41688SPaul Moore #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 18863c41688SPaul Moore } else if (info->attrs[NLBL_MGMT_A_IPV6ADDR]) { 18963c41688SPaul Moore struct in6_addr *addr; 19063c41688SPaul Moore struct in6_addr *mask; 19163c41688SPaul Moore struct netlbl_domaddr6_map *map; 19263c41688SPaul Moore 19363c41688SPaul Moore addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL); 19463c41688SPaul Moore if (addrmap == NULL) { 19563c41688SPaul Moore ret_val = -ENOMEM; 19663c41688SPaul Moore goto add_failure; 19763c41688SPaul Moore } 19863c41688SPaul Moore INIT_LIST_HEAD(&addrmap->list4); 19963c41688SPaul Moore INIT_LIST_HEAD(&addrmap->list6); 20063c41688SPaul Moore 20163c41688SPaul Moore if (nla_len(info->attrs[NLBL_MGMT_A_IPV6ADDR]) != 20263c41688SPaul Moore sizeof(struct in6_addr)) { 20363c41688SPaul Moore ret_val = -EINVAL; 20463c41688SPaul Moore goto add_failure; 20563c41688SPaul Moore } 20663c41688SPaul Moore if (nla_len(info->attrs[NLBL_MGMT_A_IPV6MASK]) != 20763c41688SPaul Moore sizeof(struct in6_addr)) { 20863c41688SPaul Moore ret_val = -EINVAL; 20963c41688SPaul Moore goto add_failure; 21063c41688SPaul Moore } 21163c41688SPaul Moore addr = nla_data(info->attrs[NLBL_MGMT_A_IPV6ADDR]); 21263c41688SPaul Moore mask = nla_data(info->attrs[NLBL_MGMT_A_IPV6MASK]); 21363c41688SPaul Moore 21463c41688SPaul Moore map = kzalloc(sizeof(*map), GFP_KERNEL); 21563c41688SPaul Moore if (map == NULL) { 21663c41688SPaul Moore ret_val = -ENOMEM; 21763c41688SPaul Moore goto add_failure; 21863c41688SPaul Moore } 21963c41688SPaul Moore ipv6_addr_copy(&map->list.addr, addr); 22063c41688SPaul Moore map->list.addr.s6_addr32[0] &= mask->s6_addr32[0]; 22163c41688SPaul Moore map->list.addr.s6_addr32[1] &= mask->s6_addr32[1]; 22263c41688SPaul Moore map->list.addr.s6_addr32[2] &= mask->s6_addr32[2]; 22363c41688SPaul Moore map->list.addr.s6_addr32[3] &= mask->s6_addr32[3]; 22463c41688SPaul Moore ipv6_addr_copy(&map->list.mask, mask); 22563c41688SPaul Moore map->list.valid = 1; 22663c41688SPaul Moore map->type = entry->type; 22763c41688SPaul Moore 22863c41688SPaul Moore ret_val = netlbl_af6list_add(&map->list, &addrmap->list6); 22963c41688SPaul Moore if (ret_val != 0) { 23063c41688SPaul Moore kfree(map); 23163c41688SPaul Moore goto add_failure; 23263c41688SPaul Moore } 23363c41688SPaul Moore 23463c41688SPaul Moore entry->type = NETLBL_NLTYPE_ADDRSELECT; 23563c41688SPaul Moore entry->type_def.addrsel = addrmap; 23663c41688SPaul Moore #endif /* IPv6 */ 23763c41688SPaul Moore } 23863c41688SPaul Moore 23963c41688SPaul Moore ret_val = netlbl_domhsh_add(entry, audit_info); 24063c41688SPaul Moore if (ret_val != 0) 24163c41688SPaul Moore goto add_failure; 24263c41688SPaul Moore 24363c41688SPaul Moore return 0; 24463c41688SPaul Moore 24563c41688SPaul Moore add_failure: 24663c41688SPaul Moore if (cipsov4) 24763c41688SPaul Moore cipso_v4_doi_putdef(cipsov4); 24863c41688SPaul Moore if (entry) 24963c41688SPaul Moore kfree(entry->domain); 25063c41688SPaul Moore kfree(addrmap); 25163c41688SPaul Moore kfree(entry); 25263c41688SPaul Moore return ret_val; 25363c41688SPaul Moore } 25463c41688SPaul Moore 25563c41688SPaul Moore /** 25663c41688SPaul Moore * netlbl_mgmt_listentry - List a NetLabel/LSM domain map entry 25763c41688SPaul Moore * @skb: the NETLINK buffer 25863c41688SPaul Moore * @entry: the map entry 25963c41688SPaul Moore * 26063c41688SPaul Moore * Description: 26163c41688SPaul Moore * This function is a helper function used by the LISTALL and LISTDEF command 26225985edcSLucas De Marchi * handlers. The caller is responsible for ensuring that the RCU read lock 26363c41688SPaul Moore * is held. Returns zero on success, negative values on failure. 26463c41688SPaul Moore * 26563c41688SPaul Moore */ 26663c41688SPaul Moore static int netlbl_mgmt_listentry(struct sk_buff *skb, 26763c41688SPaul Moore struct netlbl_dom_map *entry) 26863c41688SPaul Moore { 269f8a02479SPaul Moore int ret_val = 0; 27063c41688SPaul Moore struct nlattr *nla_a; 27163c41688SPaul Moore struct nlattr *nla_b; 27263c41688SPaul Moore struct netlbl_af4list *iter4; 27363c41688SPaul Moore #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 27463c41688SPaul Moore struct netlbl_af6list *iter6; 27563c41688SPaul Moore #endif 27663c41688SPaul Moore 27763c41688SPaul Moore if (entry->domain != NULL) { 27863c41688SPaul Moore ret_val = nla_put_string(skb, 27963c41688SPaul Moore NLBL_MGMT_A_DOMAIN, entry->domain); 28063c41688SPaul Moore if (ret_val != 0) 28163c41688SPaul Moore return ret_val; 28263c41688SPaul Moore } 28363c41688SPaul Moore 28463c41688SPaul Moore switch (entry->type) { 28563c41688SPaul Moore case NETLBL_NLTYPE_ADDRSELECT: 28663c41688SPaul Moore nla_a = nla_nest_start(skb, NLBL_MGMT_A_SELECTORLIST); 28763c41688SPaul Moore if (nla_a == NULL) 28863c41688SPaul Moore return -ENOMEM; 28963c41688SPaul Moore 29063c41688SPaul Moore netlbl_af4list_foreach_rcu(iter4, 29163c41688SPaul Moore &entry->type_def.addrsel->list4) { 29263c41688SPaul Moore struct netlbl_domaddr4_map *map4; 29363c41688SPaul Moore struct in_addr addr_struct; 29463c41688SPaul Moore 29563c41688SPaul Moore nla_b = nla_nest_start(skb, NLBL_MGMT_A_ADDRSELECTOR); 29663c41688SPaul Moore if (nla_b == NULL) 29763c41688SPaul Moore return -ENOMEM; 29863c41688SPaul Moore 29963c41688SPaul Moore addr_struct.s_addr = iter4->addr; 30063c41688SPaul Moore ret_val = nla_put(skb, NLBL_MGMT_A_IPV4ADDR, 30163c41688SPaul Moore sizeof(struct in_addr), 30263c41688SPaul Moore &addr_struct); 30363c41688SPaul Moore if (ret_val != 0) 30463c41688SPaul Moore return ret_val; 30563c41688SPaul Moore addr_struct.s_addr = iter4->mask; 30663c41688SPaul Moore ret_val = nla_put(skb, NLBL_MGMT_A_IPV4MASK, 30763c41688SPaul Moore sizeof(struct in_addr), 30863c41688SPaul Moore &addr_struct); 30963c41688SPaul Moore if (ret_val != 0) 31063c41688SPaul Moore return ret_val; 31163c41688SPaul Moore map4 = netlbl_domhsh_addr4_entry(iter4); 31263c41688SPaul Moore ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, 31363c41688SPaul Moore map4->type); 31463c41688SPaul Moore if (ret_val != 0) 31563c41688SPaul Moore return ret_val; 31663c41688SPaul Moore switch (map4->type) { 31763c41688SPaul Moore case NETLBL_NLTYPE_CIPSOV4: 31863c41688SPaul Moore ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI, 31963c41688SPaul Moore map4->type_def.cipsov4->doi); 32063c41688SPaul Moore if (ret_val != 0) 32163c41688SPaul Moore return ret_val; 32263c41688SPaul Moore break; 32363c41688SPaul Moore } 32463c41688SPaul Moore 32563c41688SPaul Moore nla_nest_end(skb, nla_b); 32663c41688SPaul Moore } 32763c41688SPaul Moore #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 32863c41688SPaul Moore netlbl_af6list_foreach_rcu(iter6, 32963c41688SPaul Moore &entry->type_def.addrsel->list6) { 33063c41688SPaul Moore struct netlbl_domaddr6_map *map6; 33163c41688SPaul Moore 33263c41688SPaul Moore nla_b = nla_nest_start(skb, NLBL_MGMT_A_ADDRSELECTOR); 33363c41688SPaul Moore if (nla_b == NULL) 33463c41688SPaul Moore return -ENOMEM; 33563c41688SPaul Moore 33663c41688SPaul Moore ret_val = nla_put(skb, NLBL_MGMT_A_IPV6ADDR, 33763c41688SPaul Moore sizeof(struct in6_addr), 33863c41688SPaul Moore &iter6->addr); 33963c41688SPaul Moore if (ret_val != 0) 34063c41688SPaul Moore return ret_val; 34163c41688SPaul Moore ret_val = nla_put(skb, NLBL_MGMT_A_IPV6MASK, 34263c41688SPaul Moore sizeof(struct in6_addr), 34363c41688SPaul Moore &iter6->mask); 34463c41688SPaul Moore if (ret_val != 0) 34563c41688SPaul Moore return ret_val; 34663c41688SPaul Moore map6 = netlbl_domhsh_addr6_entry(iter6); 34763c41688SPaul Moore ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, 34863c41688SPaul Moore map6->type); 34963c41688SPaul Moore if (ret_val != 0) 35063c41688SPaul Moore return ret_val; 35163c41688SPaul Moore 35263c41688SPaul Moore nla_nest_end(skb, nla_b); 35363c41688SPaul Moore } 35463c41688SPaul Moore #endif /* IPv6 */ 35563c41688SPaul Moore 35663c41688SPaul Moore nla_nest_end(skb, nla_a); 35763c41688SPaul Moore break; 35863c41688SPaul Moore case NETLBL_NLTYPE_UNLABELED: 35963c41688SPaul Moore ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, entry->type); 36063c41688SPaul Moore break; 36163c41688SPaul Moore case NETLBL_NLTYPE_CIPSOV4: 36263c41688SPaul Moore ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, entry->type); 36363c41688SPaul Moore if (ret_val != 0) 36463c41688SPaul Moore return ret_val; 36563c41688SPaul Moore ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI, 36663c41688SPaul Moore entry->type_def.cipsov4->doi); 36763c41688SPaul Moore break; 36863c41688SPaul Moore } 36963c41688SPaul Moore 37063c41688SPaul Moore return ret_val; 37163c41688SPaul Moore } 37263c41688SPaul Moore 37363c41688SPaul Moore /* 374d15c345fSPaul Moore * NetLabel Command Handlers 375d15c345fSPaul Moore */ 376d15c345fSPaul Moore 377d15c345fSPaul Moore /** 378d15c345fSPaul Moore * netlbl_mgmt_add - Handle an ADD message 379d15c345fSPaul Moore * @skb: the NETLINK buffer 380d15c345fSPaul Moore * @info: the Generic NETLINK info block 381d15c345fSPaul Moore * 382d15c345fSPaul Moore * Description: 383d15c345fSPaul Moore * Process a user generated ADD message and add the domains from the message 384d15c345fSPaul Moore * to the hash table. See netlabel.h for a description of the message format. 385d15c345fSPaul Moore * Returns zero on success, negative values on failure. 386d15c345fSPaul Moore * 387d15c345fSPaul Moore */ 388d15c345fSPaul Moore static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info) 389d15c345fSPaul Moore { 39095d4e6beSPaul Moore struct netlbl_audit audit_info; 391d15c345fSPaul Moore 39263c41688SPaul Moore if ((!info->attrs[NLBL_MGMT_A_DOMAIN]) || 39363c41688SPaul Moore (!info->attrs[NLBL_MGMT_A_PROTOCOL]) || 39463c41688SPaul Moore (info->attrs[NLBL_MGMT_A_IPV4ADDR] && 39563c41688SPaul Moore info->attrs[NLBL_MGMT_A_IPV6ADDR]) || 39663c41688SPaul Moore (info->attrs[NLBL_MGMT_A_IPV4MASK] && 39763c41688SPaul Moore info->attrs[NLBL_MGMT_A_IPV6MASK]) || 39863c41688SPaul Moore ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^ 39963c41688SPaul Moore (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) || 40063c41688SPaul Moore ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^ 40163c41688SPaul Moore (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL))) 40263c41688SPaul Moore return -EINVAL; 403d15c345fSPaul Moore 40495d4e6beSPaul Moore netlbl_netlink_auditinfo(skb, &audit_info); 40595d4e6beSPaul Moore 40663c41688SPaul Moore return netlbl_mgmt_add_common(info, &audit_info); 407d15c345fSPaul Moore } 408d15c345fSPaul Moore 409d15c345fSPaul Moore /** 410d15c345fSPaul Moore * netlbl_mgmt_remove - Handle a REMOVE message 411d15c345fSPaul Moore * @skb: the NETLINK buffer 412d15c345fSPaul Moore * @info: the Generic NETLINK info block 413d15c345fSPaul Moore * 414d15c345fSPaul Moore * Description: 415d15c345fSPaul Moore * Process a user generated REMOVE message and remove the specified domain 416d15c345fSPaul Moore * mappings. Returns zero on success, negative values on failure. 417d15c345fSPaul Moore * 418d15c345fSPaul Moore */ 419d15c345fSPaul Moore static int netlbl_mgmt_remove(struct sk_buff *skb, struct genl_info *info) 420d15c345fSPaul Moore { 421fd385855SPaul Moore char *domain; 42295d4e6beSPaul Moore struct netlbl_audit audit_info; 423d15c345fSPaul Moore 424fd385855SPaul Moore if (!info->attrs[NLBL_MGMT_A_DOMAIN]) 425fd385855SPaul Moore return -EINVAL; 426d15c345fSPaul Moore 42795d4e6beSPaul Moore netlbl_netlink_auditinfo(skb, &audit_info); 42895d4e6beSPaul Moore 429fd385855SPaul Moore domain = nla_data(info->attrs[NLBL_MGMT_A_DOMAIN]); 43095d4e6beSPaul Moore return netlbl_domhsh_remove(domain, &audit_info); 431d15c345fSPaul Moore } 432d15c345fSPaul Moore 433fd385855SPaul Moore /** 434fd385855SPaul Moore * netlbl_mgmt_listall_cb - netlbl_domhsh_walk() callback for LISTALL 435fd385855SPaul Moore * @entry: the domain mapping hash table entry 436fd385855SPaul Moore * @arg: the netlbl_domhsh_walk_arg structure 437fd385855SPaul Moore * 438fd385855SPaul Moore * Description: 439fd385855SPaul Moore * This function is designed to be used as a callback to the 440fd385855SPaul Moore * netlbl_domhsh_walk() function for use in generating a response for a LISTALL 441fd385855SPaul Moore * message. Returns the size of the message on success, negative values on 442fd385855SPaul Moore * failure. 443fd385855SPaul Moore * 444fd385855SPaul Moore */ 445fd385855SPaul Moore static int netlbl_mgmt_listall_cb(struct netlbl_dom_map *entry, void *arg) 446fd385855SPaul Moore { 447fd385855SPaul Moore int ret_val = -ENOMEM; 448fd385855SPaul Moore struct netlbl_domhsh_walk_arg *cb_arg = arg; 449fd385855SPaul Moore void *data; 450d15c345fSPaul Moore 45117c157c8SThomas Graf data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).pid, 45217c157c8SThomas Graf cb_arg->seq, &netlbl_mgmt_gnl_family, 45317c157c8SThomas Graf NLM_F_MULTI, NLBL_MGMT_C_LISTALL); 454fd385855SPaul Moore if (data == NULL) 455fd385855SPaul Moore goto listall_cb_failure; 456fd385855SPaul Moore 45763c41688SPaul Moore ret_val = netlbl_mgmt_listentry(cb_arg->skb, entry); 458fd385855SPaul Moore if (ret_val != 0) 459fd385855SPaul Moore goto listall_cb_failure; 460fd385855SPaul Moore 461fd385855SPaul Moore cb_arg->seq++; 462fd385855SPaul Moore return genlmsg_end(cb_arg->skb, data); 463fd385855SPaul Moore 464fd385855SPaul Moore listall_cb_failure: 465fd385855SPaul Moore genlmsg_cancel(cb_arg->skb, data); 466d15c345fSPaul Moore return ret_val; 467d15c345fSPaul Moore } 468d15c345fSPaul Moore 469d15c345fSPaul Moore /** 470fd385855SPaul Moore * netlbl_mgmt_listall - Handle a LISTALL message 471d15c345fSPaul Moore * @skb: the NETLINK buffer 472fd385855SPaul Moore * @cb: the NETLINK callback 473d15c345fSPaul Moore * 474d15c345fSPaul Moore * Description: 475fd385855SPaul Moore * Process a user generated LISTALL message and dumps the domain hash table in 476fd385855SPaul Moore * a form suitable for use in a kernel generated LISTALL message. Returns zero 477fd385855SPaul Moore * on success, negative values on failure. 478d15c345fSPaul Moore * 479d15c345fSPaul Moore */ 480fd385855SPaul Moore static int netlbl_mgmt_listall(struct sk_buff *skb, 481fd385855SPaul Moore struct netlink_callback *cb) 482d15c345fSPaul Moore { 483fd385855SPaul Moore struct netlbl_domhsh_walk_arg cb_arg; 484fd385855SPaul Moore u32 skip_bkt = cb->args[0]; 485fd385855SPaul Moore u32 skip_chain = cb->args[1]; 486d15c345fSPaul Moore 487fd385855SPaul Moore cb_arg.nl_cb = cb; 488fd385855SPaul Moore cb_arg.skb = skb; 489fd385855SPaul Moore cb_arg.seq = cb->nlh->nlmsg_seq; 490d15c345fSPaul Moore 491fd385855SPaul Moore netlbl_domhsh_walk(&skip_bkt, 492fd385855SPaul Moore &skip_chain, 493fd385855SPaul Moore netlbl_mgmt_listall_cb, 494fd385855SPaul Moore &cb_arg); 495d15c345fSPaul Moore 496fd385855SPaul Moore cb->args[0] = skip_bkt; 497fd385855SPaul Moore cb->args[1] = skip_chain; 498fd385855SPaul Moore return skb->len; 499d15c345fSPaul Moore } 500d15c345fSPaul Moore 501d15c345fSPaul Moore /** 502d15c345fSPaul Moore * netlbl_mgmt_adddef - Handle an ADDDEF message 503d15c345fSPaul Moore * @skb: the NETLINK buffer 504d15c345fSPaul Moore * @info: the Generic NETLINK info block 505d15c345fSPaul Moore * 506d15c345fSPaul Moore * Description: 507d15c345fSPaul Moore * Process a user generated ADDDEF message and respond accordingly. Returns 508d15c345fSPaul Moore * zero on success, negative values on failure. 509d15c345fSPaul Moore * 510d15c345fSPaul Moore */ 511d15c345fSPaul Moore static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info) 512d15c345fSPaul Moore { 51395d4e6beSPaul Moore struct netlbl_audit audit_info; 514d15c345fSPaul Moore 51563c41688SPaul Moore if ((!info->attrs[NLBL_MGMT_A_PROTOCOL]) || 51663c41688SPaul Moore (info->attrs[NLBL_MGMT_A_IPV4ADDR] && 51763c41688SPaul Moore info->attrs[NLBL_MGMT_A_IPV6ADDR]) || 51863c41688SPaul Moore (info->attrs[NLBL_MGMT_A_IPV4MASK] && 51963c41688SPaul Moore info->attrs[NLBL_MGMT_A_IPV6MASK]) || 52063c41688SPaul Moore ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^ 52163c41688SPaul Moore (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) || 52263c41688SPaul Moore ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^ 52363c41688SPaul Moore (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL))) 52463c41688SPaul Moore return -EINVAL; 525d15c345fSPaul Moore 52695d4e6beSPaul Moore netlbl_netlink_auditinfo(skb, &audit_info); 52795d4e6beSPaul Moore 52863c41688SPaul Moore return netlbl_mgmt_add_common(info, &audit_info); 529d15c345fSPaul Moore } 530d15c345fSPaul Moore 531d15c345fSPaul Moore /** 532d15c345fSPaul Moore * netlbl_mgmt_removedef - Handle a REMOVEDEF message 533d15c345fSPaul Moore * @skb: the NETLINK buffer 534d15c345fSPaul Moore * @info: the Generic NETLINK info block 535d15c345fSPaul Moore * 536d15c345fSPaul Moore * Description: 537d15c345fSPaul Moore * Process a user generated REMOVEDEF message and remove the default domain 538d15c345fSPaul Moore * mapping. Returns zero on success, negative values on failure. 539d15c345fSPaul Moore * 540d15c345fSPaul Moore */ 541d15c345fSPaul Moore static int netlbl_mgmt_removedef(struct sk_buff *skb, struct genl_info *info) 542d15c345fSPaul Moore { 54395d4e6beSPaul Moore struct netlbl_audit audit_info; 54495d4e6beSPaul Moore 54595d4e6beSPaul Moore netlbl_netlink_auditinfo(skb, &audit_info); 54695d4e6beSPaul Moore 54795d4e6beSPaul Moore return netlbl_domhsh_remove_default(&audit_info); 548d15c345fSPaul Moore } 549d15c345fSPaul Moore 550d15c345fSPaul Moore /** 551d15c345fSPaul Moore * netlbl_mgmt_listdef - Handle a LISTDEF message 552d15c345fSPaul Moore * @skb: the NETLINK buffer 553d15c345fSPaul Moore * @info: the Generic NETLINK info block 554d15c345fSPaul Moore * 555d15c345fSPaul Moore * Description: 556d15c345fSPaul Moore * Process a user generated LISTDEF message and dumps the default domain 557d15c345fSPaul Moore * mapping in a form suitable for use in a kernel generated LISTDEF message. 558d15c345fSPaul Moore * Returns zero on success, negative values on failure. 559d15c345fSPaul Moore * 560d15c345fSPaul Moore */ 561d15c345fSPaul Moore static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info) 562d15c345fSPaul Moore { 563d15c345fSPaul Moore int ret_val = -ENOMEM; 564fd385855SPaul Moore struct sk_buff *ans_skb = NULL; 565fd385855SPaul Moore void *data; 566fd385855SPaul Moore struct netlbl_dom_map *entry; 567d15c345fSPaul Moore 568339bf98fSThomas Graf ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 569d15c345fSPaul Moore if (ans_skb == NULL) 570fd385855SPaul Moore return -ENOMEM; 57117c157c8SThomas Graf data = genlmsg_put_reply(ans_skb, info, &netlbl_mgmt_gnl_family, 57217c157c8SThomas Graf 0, NLBL_MGMT_C_LISTDEF); 573fd385855SPaul Moore if (data == NULL) 574fd385855SPaul Moore goto listdef_failure; 575d15c345fSPaul Moore 576fd385855SPaul Moore rcu_read_lock(); 577fd385855SPaul Moore entry = netlbl_domhsh_getentry(NULL); 578fd385855SPaul Moore if (entry == NULL) { 579fd385855SPaul Moore ret_val = -ENOENT; 580fd385855SPaul Moore goto listdef_failure_lock; 581fd385855SPaul Moore } 58263c41688SPaul Moore ret_val = netlbl_mgmt_listentry(ans_skb, entry); 583fd385855SPaul Moore rcu_read_unlock(); 58463c41688SPaul Moore if (ret_val != 0) 58563c41688SPaul Moore goto listdef_failure; 586fd385855SPaul Moore 587fd385855SPaul Moore genlmsg_end(ans_skb, data); 588fe785beeSDenis V. Lunev return genlmsg_reply(ans_skb, info); 589d15c345fSPaul Moore 590fd385855SPaul Moore listdef_failure_lock: 591fd385855SPaul Moore rcu_read_unlock(); 592d15c345fSPaul Moore listdef_failure: 593fd385855SPaul Moore kfree_skb(ans_skb); 594d15c345fSPaul Moore return ret_val; 595d15c345fSPaul Moore } 596d15c345fSPaul Moore 597d15c345fSPaul Moore /** 598fd385855SPaul Moore * netlbl_mgmt_protocols_cb - Write an individual PROTOCOL message response 599fd385855SPaul Moore * @skb: the skb to write to 600fd385855SPaul Moore * @cb: the NETLINK callback 601fd385855SPaul Moore * @protocol: the NetLabel protocol to use in the message 602d15c345fSPaul Moore * 603d15c345fSPaul Moore * Description: 604fd385855SPaul Moore * This function is to be used in conjunction with netlbl_mgmt_protocols() to 605fd385855SPaul Moore * answer a application's PROTOCOLS message. Returns the size of the message 606fd385855SPaul Moore * on success, negative values on failure. 607d15c345fSPaul Moore * 608d15c345fSPaul Moore */ 609fd385855SPaul Moore static int netlbl_mgmt_protocols_cb(struct sk_buff *skb, 610fd385855SPaul Moore struct netlink_callback *cb, 611fd385855SPaul Moore u32 protocol) 612d15c345fSPaul Moore { 613d15c345fSPaul Moore int ret_val = -ENOMEM; 614fd385855SPaul Moore void *data; 615d15c345fSPaul Moore 61617c157c8SThomas Graf data = genlmsg_put(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, 61717c157c8SThomas Graf &netlbl_mgmt_gnl_family, NLM_F_MULTI, 618fd385855SPaul Moore NLBL_MGMT_C_PROTOCOLS); 619fd385855SPaul Moore if (data == NULL) 620fd385855SPaul Moore goto protocols_cb_failure; 621d15c345fSPaul Moore 622fd385855SPaul Moore ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, protocol); 623d15c345fSPaul Moore if (ret_val != 0) 624fd385855SPaul Moore goto protocols_cb_failure; 625d15c345fSPaul Moore 626fd385855SPaul Moore return genlmsg_end(skb, data); 627d15c345fSPaul Moore 628fd385855SPaul Moore protocols_cb_failure: 629fd385855SPaul Moore genlmsg_cancel(skb, data); 630d15c345fSPaul Moore return ret_val; 631d15c345fSPaul Moore } 632d15c345fSPaul Moore 633d15c345fSPaul Moore /** 634fd385855SPaul Moore * netlbl_mgmt_protocols - Handle a PROTOCOLS message 635fd385855SPaul Moore * @skb: the NETLINK buffer 636fd385855SPaul Moore * @cb: the NETLINK callback 637fd385855SPaul Moore * 638fd385855SPaul Moore * Description: 639fd385855SPaul Moore * Process a user generated PROTOCOLS message and respond accordingly. 640fd385855SPaul Moore * 641fd385855SPaul Moore */ 642fd385855SPaul Moore static int netlbl_mgmt_protocols(struct sk_buff *skb, 643fd385855SPaul Moore struct netlink_callback *cb) 644fd385855SPaul Moore { 645fd385855SPaul Moore u32 protos_sent = cb->args[0]; 646fd385855SPaul Moore 647fd385855SPaul Moore if (protos_sent == 0) { 648fd385855SPaul Moore if (netlbl_mgmt_protocols_cb(skb, 649fd385855SPaul Moore cb, 650fd385855SPaul Moore NETLBL_NLTYPE_UNLABELED) < 0) 651fd385855SPaul Moore goto protocols_return; 652fd385855SPaul Moore protos_sent++; 653fd385855SPaul Moore } 654fd385855SPaul Moore if (protos_sent == 1) { 655fd385855SPaul Moore if (netlbl_mgmt_protocols_cb(skb, 656fd385855SPaul Moore cb, 657fd385855SPaul Moore NETLBL_NLTYPE_CIPSOV4) < 0) 658fd385855SPaul Moore goto protocols_return; 659fd385855SPaul Moore protos_sent++; 660fd385855SPaul Moore } 661fd385855SPaul Moore 662fd385855SPaul Moore protocols_return: 663fd385855SPaul Moore cb->args[0] = protos_sent; 664fd385855SPaul Moore return skb->len; 665fd385855SPaul Moore } 666fd385855SPaul Moore 667fd385855SPaul Moore /** 668d15c345fSPaul Moore * netlbl_mgmt_version - Handle a VERSION message 669d15c345fSPaul Moore * @skb: the NETLINK buffer 670d15c345fSPaul Moore * @info: the Generic NETLINK info block 671d15c345fSPaul Moore * 672d15c345fSPaul Moore * Description: 673d15c345fSPaul Moore * Process a user generated VERSION message and respond accordingly. Returns 674d15c345fSPaul Moore * zero on success, negative values on failure. 675d15c345fSPaul Moore * 676d15c345fSPaul Moore */ 677d15c345fSPaul Moore static int netlbl_mgmt_version(struct sk_buff *skb, struct genl_info *info) 678d15c345fSPaul Moore { 679d15c345fSPaul Moore int ret_val = -ENOMEM; 680d15c345fSPaul Moore struct sk_buff *ans_skb = NULL; 681fd385855SPaul Moore void *data; 682d15c345fSPaul Moore 683339bf98fSThomas Graf ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 684d15c345fSPaul Moore if (ans_skb == NULL) 685fd385855SPaul Moore return -ENOMEM; 68617c157c8SThomas Graf data = genlmsg_put_reply(ans_skb, info, &netlbl_mgmt_gnl_family, 68717c157c8SThomas Graf 0, NLBL_MGMT_C_VERSION); 688fd385855SPaul Moore if (data == NULL) 689d15c345fSPaul Moore goto version_failure; 690d15c345fSPaul Moore 691fd385855SPaul Moore ret_val = nla_put_u32(ans_skb, 692fd385855SPaul Moore NLBL_MGMT_A_VERSION, 693fd385855SPaul Moore NETLBL_PROTO_VERSION); 694d15c345fSPaul Moore if (ret_val != 0) 695d15c345fSPaul Moore goto version_failure; 696d15c345fSPaul Moore 697fd385855SPaul Moore genlmsg_end(ans_skb, data); 698fe785beeSDenis V. Lunev return genlmsg_reply(ans_skb, info); 699d15c345fSPaul Moore 700d15c345fSPaul Moore version_failure: 701d15c345fSPaul Moore kfree_skb(ans_skb); 702d15c345fSPaul Moore return ret_val; 703d15c345fSPaul Moore } 704d15c345fSPaul Moore 705d15c345fSPaul Moore 706d15c345fSPaul Moore /* 707d15c345fSPaul Moore * NetLabel Generic NETLINK Command Definitions 708d15c345fSPaul Moore */ 709d15c345fSPaul Moore 710227c43c3SPavel Emelyanov static struct genl_ops netlbl_mgmt_genl_ops[] = { 711227c43c3SPavel Emelyanov { 712d15c345fSPaul Moore .cmd = NLBL_MGMT_C_ADD, 713fd385855SPaul Moore .flags = GENL_ADMIN_PERM, 714fd385855SPaul Moore .policy = netlbl_mgmt_genl_policy, 715d15c345fSPaul Moore .doit = netlbl_mgmt_add, 716d15c345fSPaul Moore .dumpit = NULL, 717227c43c3SPavel Emelyanov }, 718227c43c3SPavel Emelyanov { 719d15c345fSPaul Moore .cmd = NLBL_MGMT_C_REMOVE, 720fd385855SPaul Moore .flags = GENL_ADMIN_PERM, 721fd385855SPaul Moore .policy = netlbl_mgmt_genl_policy, 722d15c345fSPaul Moore .doit = netlbl_mgmt_remove, 723d15c345fSPaul Moore .dumpit = NULL, 724227c43c3SPavel Emelyanov }, 725227c43c3SPavel Emelyanov { 726fd385855SPaul Moore .cmd = NLBL_MGMT_C_LISTALL, 727d15c345fSPaul Moore .flags = 0, 728fd385855SPaul Moore .policy = netlbl_mgmt_genl_policy, 729fd385855SPaul Moore .doit = NULL, 730fd385855SPaul Moore .dumpit = netlbl_mgmt_listall, 731227c43c3SPavel Emelyanov }, 732227c43c3SPavel Emelyanov { 733d15c345fSPaul Moore .cmd = NLBL_MGMT_C_ADDDEF, 734fd385855SPaul Moore .flags = GENL_ADMIN_PERM, 735fd385855SPaul Moore .policy = netlbl_mgmt_genl_policy, 736d15c345fSPaul Moore .doit = netlbl_mgmt_adddef, 737d15c345fSPaul Moore .dumpit = NULL, 738227c43c3SPavel Emelyanov }, 739227c43c3SPavel Emelyanov { 740d15c345fSPaul Moore .cmd = NLBL_MGMT_C_REMOVEDEF, 741fd385855SPaul Moore .flags = GENL_ADMIN_PERM, 742fd385855SPaul Moore .policy = netlbl_mgmt_genl_policy, 743d15c345fSPaul Moore .doit = netlbl_mgmt_removedef, 744d15c345fSPaul Moore .dumpit = NULL, 745227c43c3SPavel Emelyanov }, 746227c43c3SPavel Emelyanov { 747d15c345fSPaul Moore .cmd = NLBL_MGMT_C_LISTDEF, 748d15c345fSPaul Moore .flags = 0, 749fd385855SPaul Moore .policy = netlbl_mgmt_genl_policy, 750d15c345fSPaul Moore .doit = netlbl_mgmt_listdef, 751d15c345fSPaul Moore .dumpit = NULL, 752227c43c3SPavel Emelyanov }, 753227c43c3SPavel Emelyanov { 754fd385855SPaul Moore .cmd = NLBL_MGMT_C_PROTOCOLS, 755d15c345fSPaul Moore .flags = 0, 756fd385855SPaul Moore .policy = netlbl_mgmt_genl_policy, 757fd385855SPaul Moore .doit = NULL, 758fd385855SPaul Moore .dumpit = netlbl_mgmt_protocols, 759227c43c3SPavel Emelyanov }, 760227c43c3SPavel Emelyanov { 761d15c345fSPaul Moore .cmd = NLBL_MGMT_C_VERSION, 762d15c345fSPaul Moore .flags = 0, 763fd385855SPaul Moore .policy = netlbl_mgmt_genl_policy, 764d15c345fSPaul Moore .doit = netlbl_mgmt_version, 765d15c345fSPaul Moore .dumpit = NULL, 766227c43c3SPavel Emelyanov }, 767d15c345fSPaul Moore }; 768d15c345fSPaul Moore 769d15c345fSPaul Moore /* 770d15c345fSPaul Moore * NetLabel Generic NETLINK Protocol Functions 771d15c345fSPaul Moore */ 772d15c345fSPaul Moore 773d15c345fSPaul Moore /** 774d15c345fSPaul Moore * netlbl_mgmt_genl_init - Register the NetLabel management component 775d15c345fSPaul Moore * 776d15c345fSPaul Moore * Description: 777d15c345fSPaul Moore * Register the NetLabel management component with the Generic NETLINK 778d15c345fSPaul Moore * mechanism. Returns zero on success, negative values on failure. 779d15c345fSPaul Moore * 780d15c345fSPaul Moore */ 78105705e4eSPavel Emelyanov int __init netlbl_mgmt_genl_init(void) 782d15c345fSPaul Moore { 7837ae740dfSMichał Mirosław return genl_register_family_with_ops(&netlbl_mgmt_gnl_family, 7847ae740dfSMichał Mirosław netlbl_mgmt_genl_ops, ARRAY_SIZE(netlbl_mgmt_genl_ops)); 785d15c345fSPaul Moore } 786