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> 44dc7de73fSHuw Davies #include <net/calipso.h> 4560063497SArun Sharma #include <linux/atomic.h> 46d15c345fSPaul Moore 47dc7de73fSHuw Davies #include "netlabel_calipso.h" 48d15c345fSPaul Moore #include "netlabel_domainhash.h" 49d15c345fSPaul Moore #include "netlabel_user.h" 50d15c345fSPaul Moore #include "netlabel_mgmt.h" 51d15c345fSPaul Moore 52c783f1ceSPaul Moore /* NetLabel configured protocol counter */ 53c783f1ceSPaul Moore atomic_t netlabel_mgmt_protocount = ATOMIC_INIT(0); 5423bcdc1aSPaul Moore 55fd385855SPaul Moore /* Argument struct for netlbl_domhsh_walk() */ 56fd385855SPaul Moore struct netlbl_domhsh_walk_arg { 57fd385855SPaul Moore struct netlink_callback *nl_cb; 58fd385855SPaul Moore struct sk_buff *skb; 59fd385855SPaul Moore u32 seq; 60fd385855SPaul Moore }; 61fd385855SPaul Moore 62d15c345fSPaul Moore /* NetLabel Generic NETLINK CIPSOv4 family */ 63489111e5SJohannes Berg static struct genl_family netlbl_mgmt_gnl_family; 64d15c345fSPaul Moore 65fd385855SPaul Moore /* NetLabel Netlink attribute policy */ 66ef7c79edSPatrick McHardy static const struct nla_policy netlbl_mgmt_genl_policy[NLBL_MGMT_A_MAX + 1] = { 67fd385855SPaul Moore [NLBL_MGMT_A_DOMAIN] = { .type = NLA_NUL_STRING }, 68fd385855SPaul Moore [NLBL_MGMT_A_PROTOCOL] = { .type = NLA_U32 }, 69fd385855SPaul Moore [NLBL_MGMT_A_VERSION] = { .type = NLA_U32 }, 70fd385855SPaul Moore [NLBL_MGMT_A_CV4DOI] = { .type = NLA_U32 }, 718f18e675SHuw Davies [NLBL_MGMT_A_FAMILY] = { .type = NLA_U16 }, 72dc7de73fSHuw Davies [NLBL_MGMT_A_CLPDOI] = { .type = NLA_U32 }, 73fd385855SPaul Moore }; 74d15c345fSPaul Moore 75d15c345fSPaul Moore /* 7663c41688SPaul Moore * Helper Functions 7763c41688SPaul Moore */ 7863c41688SPaul Moore 7963c41688SPaul Moore /** 8063c41688SPaul Moore * netlbl_mgmt_add - Handle an ADD message 8163c41688SPaul Moore * @info: the Generic NETLINK info block 8263c41688SPaul Moore * @audit_info: NetLabel audit information 8363c41688SPaul Moore * 8463c41688SPaul Moore * Description: 8563c41688SPaul Moore * Helper function for the ADD and ADDDEF messages to add the domain mappings 8663c41688SPaul Moore * from the message to the hash table. See netlabel.h for a description of the 8763c41688SPaul Moore * message format. Returns zero on success, negative values on failure. 8863c41688SPaul Moore * 8963c41688SPaul Moore */ 9063c41688SPaul Moore static int netlbl_mgmt_add_common(struct genl_info *info, 9163c41688SPaul Moore struct netlbl_audit *audit_info) 9263c41688SPaul Moore { 9363c41688SPaul Moore int ret_val = -EINVAL; 9463c41688SPaul Moore struct netlbl_domaddr_map *addrmap = NULL; 9563c41688SPaul Moore struct cipso_v4_doi *cipsov4 = NULL; 96dc7de73fSHuw Davies #if IS_ENABLED(CONFIG_IPV6) 97dc7de73fSHuw Davies struct calipso_doi *calipso = NULL; 98dc7de73fSHuw Davies #endif 9963c41688SPaul Moore u32 tmp_val; 1004de46d5eSMarkus Elfring struct netlbl_dom_map *entry = kzalloc(sizeof(*entry), GFP_KERNEL); 10163c41688SPaul Moore 1024de46d5eSMarkus Elfring if (!entry) 1034de46d5eSMarkus Elfring return -ENOMEM; 1046a8b7f0cSPaul Moore entry->def.type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]); 10563c41688SPaul Moore if (info->attrs[NLBL_MGMT_A_DOMAIN]) { 10663c41688SPaul Moore size_t tmp_size = nla_len(info->attrs[NLBL_MGMT_A_DOMAIN]); 10763c41688SPaul Moore entry->domain = kmalloc(tmp_size, GFP_KERNEL); 10863c41688SPaul Moore if (entry->domain == NULL) { 10963c41688SPaul Moore ret_val = -ENOMEM; 1104de46d5eSMarkus Elfring goto add_free_entry; 11163c41688SPaul Moore } 11263c41688SPaul Moore nla_strlcpy(entry->domain, 11363c41688SPaul Moore info->attrs[NLBL_MGMT_A_DOMAIN], tmp_size); 11463c41688SPaul Moore } 11563c41688SPaul Moore 1166a8b7f0cSPaul Moore /* NOTE: internally we allow/use a entry->def.type value of 11763c41688SPaul Moore * NETLBL_NLTYPE_ADDRSELECT but we don't currently allow users 11863c41688SPaul Moore * to pass that as a protocol value because we need to know the 11963c41688SPaul Moore * "real" protocol */ 12063c41688SPaul Moore 1216a8b7f0cSPaul Moore switch (entry->def.type) { 12263c41688SPaul Moore case NETLBL_NLTYPE_UNLABELED: 1238f18e675SHuw Davies if (info->attrs[NLBL_MGMT_A_FAMILY]) 1248f18e675SHuw Davies entry->family = 1258f18e675SHuw Davies nla_get_u16(info->attrs[NLBL_MGMT_A_FAMILY]); 1268f18e675SHuw Davies else 1278f18e675SHuw Davies entry->family = AF_UNSPEC; 12863c41688SPaul Moore break; 12963c41688SPaul Moore case NETLBL_NLTYPE_CIPSOV4: 13063c41688SPaul Moore if (!info->attrs[NLBL_MGMT_A_CV4DOI]) 1314de46d5eSMarkus Elfring goto add_free_domain; 13263c41688SPaul Moore 13363c41688SPaul Moore tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]); 13463c41688SPaul Moore cipsov4 = cipso_v4_doi_getdef(tmp_val); 13563c41688SPaul Moore if (cipsov4 == NULL) 1364de46d5eSMarkus Elfring goto add_free_domain; 1378f18e675SHuw Davies entry->family = AF_INET; 1386a8b7f0cSPaul Moore entry->def.cipso = cipsov4; 13963c41688SPaul Moore break; 140dc7de73fSHuw Davies #if IS_ENABLED(CONFIG_IPV6) 141dc7de73fSHuw Davies case NETLBL_NLTYPE_CALIPSO: 142dc7de73fSHuw Davies if (!info->attrs[NLBL_MGMT_A_CLPDOI]) 143dc7de73fSHuw Davies goto add_free_domain; 144dc7de73fSHuw Davies 145dc7de73fSHuw Davies tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CLPDOI]); 146dc7de73fSHuw Davies calipso = calipso_doi_getdef(tmp_val); 147dc7de73fSHuw Davies if (calipso == NULL) 148dc7de73fSHuw Davies goto add_free_domain; 149dc7de73fSHuw Davies entry->family = AF_INET6; 150dc7de73fSHuw Davies entry->def.calipso = calipso; 151dc7de73fSHuw Davies break; 152dc7de73fSHuw Davies #endif /* IPv6 */ 15363c41688SPaul Moore default: 1544de46d5eSMarkus Elfring goto add_free_domain; 15563c41688SPaul Moore } 15663c41688SPaul Moore 1578f18e675SHuw Davies if ((entry->family == AF_INET && info->attrs[NLBL_MGMT_A_IPV6ADDR]) || 1588f18e675SHuw Davies (entry->family == AF_INET6 && info->attrs[NLBL_MGMT_A_IPV4ADDR])) 1598f18e675SHuw Davies goto add_doi_put_def; 1608f18e675SHuw Davies 16163c41688SPaul Moore if (info->attrs[NLBL_MGMT_A_IPV4ADDR]) { 16263c41688SPaul Moore struct in_addr *addr; 16363c41688SPaul Moore struct in_addr *mask; 16463c41688SPaul Moore struct netlbl_domaddr4_map *map; 16563c41688SPaul Moore 16663c41688SPaul Moore addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL); 16763c41688SPaul Moore if (addrmap == NULL) { 16863c41688SPaul Moore ret_val = -ENOMEM; 1694de46d5eSMarkus Elfring goto add_doi_put_def; 17063c41688SPaul Moore } 17163c41688SPaul Moore INIT_LIST_HEAD(&addrmap->list4); 17263c41688SPaul Moore INIT_LIST_HEAD(&addrmap->list6); 17363c41688SPaul Moore 17463c41688SPaul Moore if (nla_len(info->attrs[NLBL_MGMT_A_IPV4ADDR]) != 17563c41688SPaul Moore sizeof(struct in_addr)) { 17663c41688SPaul Moore ret_val = -EINVAL; 1774de46d5eSMarkus Elfring goto add_free_addrmap; 17863c41688SPaul Moore } 17963c41688SPaul Moore if (nla_len(info->attrs[NLBL_MGMT_A_IPV4MASK]) != 18063c41688SPaul Moore sizeof(struct in_addr)) { 18163c41688SPaul Moore ret_val = -EINVAL; 1824de46d5eSMarkus Elfring goto add_free_addrmap; 18363c41688SPaul Moore } 18463c41688SPaul Moore addr = nla_data(info->attrs[NLBL_MGMT_A_IPV4ADDR]); 18563c41688SPaul Moore mask = nla_data(info->attrs[NLBL_MGMT_A_IPV4MASK]); 18663c41688SPaul Moore 18763c41688SPaul Moore map = kzalloc(sizeof(*map), GFP_KERNEL); 18863c41688SPaul Moore if (map == NULL) { 18963c41688SPaul Moore ret_val = -ENOMEM; 1904de46d5eSMarkus Elfring goto add_free_addrmap; 19163c41688SPaul Moore } 19263c41688SPaul Moore map->list.addr = addr->s_addr & mask->s_addr; 19363c41688SPaul Moore map->list.mask = mask->s_addr; 19463c41688SPaul Moore map->list.valid = 1; 1956a8b7f0cSPaul Moore map->def.type = entry->def.type; 19663c41688SPaul Moore if (cipsov4) 1976a8b7f0cSPaul Moore map->def.cipso = cipsov4; 19863c41688SPaul Moore 19963c41688SPaul Moore ret_val = netlbl_af4list_add(&map->list, &addrmap->list4); 20063c41688SPaul Moore if (ret_val != 0) { 20163c41688SPaul Moore kfree(map); 2024de46d5eSMarkus Elfring goto add_free_addrmap; 20363c41688SPaul Moore } 20463c41688SPaul Moore 2058f18e675SHuw Davies entry->family = AF_INET; 2066a8b7f0cSPaul Moore entry->def.type = NETLBL_NLTYPE_ADDRSELECT; 2076a8b7f0cSPaul Moore entry->def.addrsel = addrmap; 208dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6) 20963c41688SPaul Moore } else if (info->attrs[NLBL_MGMT_A_IPV6ADDR]) { 21063c41688SPaul Moore struct in6_addr *addr; 21163c41688SPaul Moore struct in6_addr *mask; 21263c41688SPaul Moore struct netlbl_domaddr6_map *map; 21363c41688SPaul Moore 21463c41688SPaul Moore addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL); 21563c41688SPaul Moore if (addrmap == NULL) { 21663c41688SPaul Moore ret_val = -ENOMEM; 2174de46d5eSMarkus Elfring goto add_doi_put_def; 21863c41688SPaul Moore } 21963c41688SPaul Moore INIT_LIST_HEAD(&addrmap->list4); 22063c41688SPaul Moore INIT_LIST_HEAD(&addrmap->list6); 22163c41688SPaul Moore 22263c41688SPaul Moore if (nla_len(info->attrs[NLBL_MGMT_A_IPV6ADDR]) != 22363c41688SPaul Moore sizeof(struct in6_addr)) { 22463c41688SPaul Moore ret_val = -EINVAL; 2254de46d5eSMarkus Elfring goto add_free_addrmap; 22663c41688SPaul Moore } 22763c41688SPaul Moore if (nla_len(info->attrs[NLBL_MGMT_A_IPV6MASK]) != 22863c41688SPaul Moore sizeof(struct in6_addr)) { 22963c41688SPaul Moore ret_val = -EINVAL; 2304de46d5eSMarkus Elfring goto add_free_addrmap; 23163c41688SPaul Moore } 23263c41688SPaul Moore addr = nla_data(info->attrs[NLBL_MGMT_A_IPV6ADDR]); 23363c41688SPaul Moore mask = nla_data(info->attrs[NLBL_MGMT_A_IPV6MASK]); 23463c41688SPaul Moore 23563c41688SPaul Moore map = kzalloc(sizeof(*map), GFP_KERNEL); 23663c41688SPaul Moore if (map == NULL) { 23763c41688SPaul Moore ret_val = -ENOMEM; 2384de46d5eSMarkus Elfring goto add_free_addrmap; 23963c41688SPaul Moore } 2404e3fd7a0SAlexey Dobriyan map->list.addr = *addr; 24163c41688SPaul Moore map->list.addr.s6_addr32[0] &= mask->s6_addr32[0]; 24263c41688SPaul Moore map->list.addr.s6_addr32[1] &= mask->s6_addr32[1]; 24363c41688SPaul Moore map->list.addr.s6_addr32[2] &= mask->s6_addr32[2]; 24463c41688SPaul Moore map->list.addr.s6_addr32[3] &= mask->s6_addr32[3]; 2454e3fd7a0SAlexey Dobriyan map->list.mask = *mask; 24663c41688SPaul Moore map->list.valid = 1; 2476a8b7f0cSPaul Moore map->def.type = entry->def.type; 248dc7de73fSHuw Davies if (calipso) 249dc7de73fSHuw Davies map->def.calipso = calipso; 25063c41688SPaul Moore 25163c41688SPaul Moore ret_val = netlbl_af6list_add(&map->list, &addrmap->list6); 25263c41688SPaul Moore if (ret_val != 0) { 25363c41688SPaul Moore kfree(map); 2544de46d5eSMarkus Elfring goto add_free_addrmap; 25563c41688SPaul Moore } 25663c41688SPaul Moore 2578f18e675SHuw Davies entry->family = AF_INET6; 2586a8b7f0cSPaul Moore entry->def.type = NETLBL_NLTYPE_ADDRSELECT; 2596a8b7f0cSPaul Moore entry->def.addrsel = addrmap; 26063c41688SPaul Moore #endif /* IPv6 */ 26163c41688SPaul Moore } 26263c41688SPaul Moore 26363c41688SPaul Moore ret_val = netlbl_domhsh_add(entry, audit_info); 26463c41688SPaul Moore if (ret_val != 0) 2654de46d5eSMarkus Elfring goto add_free_addrmap; 26663c41688SPaul Moore 26763c41688SPaul Moore return 0; 26863c41688SPaul Moore 2694de46d5eSMarkus Elfring add_free_addrmap: 27063c41688SPaul Moore kfree(addrmap); 2714de46d5eSMarkus Elfring add_doi_put_def: 2724de46d5eSMarkus Elfring cipso_v4_doi_putdef(cipsov4); 273dc7de73fSHuw Davies #if IS_ENABLED(CONFIG_IPV6) 274dc7de73fSHuw Davies calipso_doi_putdef(calipso); 275dc7de73fSHuw Davies #endif 2764de46d5eSMarkus Elfring add_free_domain: 2774de46d5eSMarkus Elfring kfree(entry->domain); 2784de46d5eSMarkus Elfring add_free_entry: 27963c41688SPaul Moore kfree(entry); 28063c41688SPaul Moore return ret_val; 28163c41688SPaul Moore } 28263c41688SPaul Moore 28363c41688SPaul Moore /** 28463c41688SPaul Moore * netlbl_mgmt_listentry - List a NetLabel/LSM domain map entry 28563c41688SPaul Moore * @skb: the NETLINK buffer 28663c41688SPaul Moore * @entry: the map entry 28763c41688SPaul Moore * 28863c41688SPaul Moore * Description: 28963c41688SPaul Moore * This function is a helper function used by the LISTALL and LISTDEF command 29025985edcSLucas De Marchi * handlers. The caller is responsible for ensuring that the RCU read lock 29163c41688SPaul Moore * is held. Returns zero on success, negative values on failure. 29263c41688SPaul Moore * 29363c41688SPaul Moore */ 29463c41688SPaul Moore static int netlbl_mgmt_listentry(struct sk_buff *skb, 29563c41688SPaul Moore struct netlbl_dom_map *entry) 29663c41688SPaul Moore { 297f8a02479SPaul Moore int ret_val = 0; 29863c41688SPaul Moore struct nlattr *nla_a; 29963c41688SPaul Moore struct nlattr *nla_b; 30063c41688SPaul Moore struct netlbl_af4list *iter4; 301dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6) 30263c41688SPaul Moore struct netlbl_af6list *iter6; 30363c41688SPaul Moore #endif 30463c41688SPaul Moore 30563c41688SPaul Moore if (entry->domain != NULL) { 30663c41688SPaul Moore ret_val = nla_put_string(skb, 30763c41688SPaul Moore NLBL_MGMT_A_DOMAIN, entry->domain); 30863c41688SPaul Moore if (ret_val != 0) 30963c41688SPaul Moore return ret_val; 31063c41688SPaul Moore } 31163c41688SPaul Moore 3128f18e675SHuw Davies ret_val = nla_put_u16(skb, NLBL_MGMT_A_FAMILY, entry->family); 3138f18e675SHuw Davies if (ret_val != 0) 3148f18e675SHuw Davies return ret_val; 3158f18e675SHuw Davies 3166a8b7f0cSPaul Moore switch (entry->def.type) { 31763c41688SPaul Moore case NETLBL_NLTYPE_ADDRSELECT: 31863c41688SPaul Moore nla_a = nla_nest_start(skb, NLBL_MGMT_A_SELECTORLIST); 31963c41688SPaul Moore if (nla_a == NULL) 32063c41688SPaul Moore return -ENOMEM; 32163c41688SPaul Moore 3226a8b7f0cSPaul Moore netlbl_af4list_foreach_rcu(iter4, &entry->def.addrsel->list4) { 32363c41688SPaul Moore struct netlbl_domaddr4_map *map4; 32463c41688SPaul Moore struct in_addr addr_struct; 32563c41688SPaul Moore 32663c41688SPaul Moore nla_b = nla_nest_start(skb, NLBL_MGMT_A_ADDRSELECTOR); 32763c41688SPaul Moore if (nla_b == NULL) 32863c41688SPaul Moore return -ENOMEM; 32963c41688SPaul Moore 33063c41688SPaul Moore addr_struct.s_addr = iter4->addr; 331930345eaSJiri Benc ret_val = nla_put_in_addr(skb, NLBL_MGMT_A_IPV4ADDR, 332930345eaSJiri Benc addr_struct.s_addr); 33363c41688SPaul Moore if (ret_val != 0) 33463c41688SPaul Moore return ret_val; 33563c41688SPaul Moore addr_struct.s_addr = iter4->mask; 336930345eaSJiri Benc ret_val = nla_put_in_addr(skb, NLBL_MGMT_A_IPV4MASK, 337930345eaSJiri Benc addr_struct.s_addr); 33863c41688SPaul Moore if (ret_val != 0) 33963c41688SPaul Moore return ret_val; 34063c41688SPaul Moore map4 = netlbl_domhsh_addr4_entry(iter4); 34163c41688SPaul Moore ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, 3426a8b7f0cSPaul Moore map4->def.type); 34363c41688SPaul Moore if (ret_val != 0) 34463c41688SPaul Moore return ret_val; 3456a8b7f0cSPaul Moore switch (map4->def.type) { 34663c41688SPaul Moore case NETLBL_NLTYPE_CIPSOV4: 34763c41688SPaul Moore ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI, 3486a8b7f0cSPaul Moore map4->def.cipso->doi); 34963c41688SPaul Moore if (ret_val != 0) 35063c41688SPaul Moore return ret_val; 35163c41688SPaul Moore break; 35263c41688SPaul Moore } 35363c41688SPaul Moore 35463c41688SPaul Moore nla_nest_end(skb, nla_b); 35563c41688SPaul Moore } 356dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6) 3576a8b7f0cSPaul Moore netlbl_af6list_foreach_rcu(iter6, &entry->def.addrsel->list6) { 35863c41688SPaul Moore struct netlbl_domaddr6_map *map6; 35963c41688SPaul Moore 36063c41688SPaul Moore nla_b = nla_nest_start(skb, NLBL_MGMT_A_ADDRSELECTOR); 36163c41688SPaul Moore if (nla_b == NULL) 36263c41688SPaul Moore return -ENOMEM; 36363c41688SPaul Moore 364930345eaSJiri Benc ret_val = nla_put_in6_addr(skb, NLBL_MGMT_A_IPV6ADDR, 36563c41688SPaul Moore &iter6->addr); 36663c41688SPaul Moore if (ret_val != 0) 36763c41688SPaul Moore return ret_val; 368930345eaSJiri Benc ret_val = nla_put_in6_addr(skb, NLBL_MGMT_A_IPV6MASK, 36963c41688SPaul Moore &iter6->mask); 37063c41688SPaul Moore if (ret_val != 0) 37163c41688SPaul Moore return ret_val; 37263c41688SPaul Moore map6 = netlbl_domhsh_addr6_entry(iter6); 37363c41688SPaul Moore ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, 3746a8b7f0cSPaul Moore map6->def.type); 37563c41688SPaul Moore if (ret_val != 0) 37663c41688SPaul Moore return ret_val; 37763c41688SPaul Moore 378dc7de73fSHuw Davies switch (map6->def.type) { 379dc7de73fSHuw Davies case NETLBL_NLTYPE_CALIPSO: 380dc7de73fSHuw Davies ret_val = nla_put_u32(skb, NLBL_MGMT_A_CLPDOI, 381dc7de73fSHuw Davies map6->def.calipso->doi); 382dc7de73fSHuw Davies if (ret_val != 0) 383dc7de73fSHuw Davies return ret_val; 384dc7de73fSHuw Davies break; 385dc7de73fSHuw Davies } 386dc7de73fSHuw Davies 38763c41688SPaul Moore nla_nest_end(skb, nla_b); 38863c41688SPaul Moore } 38963c41688SPaul Moore #endif /* IPv6 */ 39063c41688SPaul Moore 39163c41688SPaul Moore nla_nest_end(skb, nla_a); 39263c41688SPaul Moore break; 39363c41688SPaul Moore case NETLBL_NLTYPE_UNLABELED: 394dc7de73fSHuw Davies ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, 395dc7de73fSHuw Davies entry->def.type); 39663c41688SPaul Moore break; 39763c41688SPaul Moore case NETLBL_NLTYPE_CIPSOV4: 398dc7de73fSHuw Davies ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, 399dc7de73fSHuw Davies entry->def.type); 40063c41688SPaul Moore if (ret_val != 0) 40163c41688SPaul Moore return ret_val; 40263c41688SPaul Moore ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI, 4036a8b7f0cSPaul Moore entry->def.cipso->doi); 40463c41688SPaul Moore break; 405dc7de73fSHuw Davies case NETLBL_NLTYPE_CALIPSO: 406dc7de73fSHuw Davies ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, 407dc7de73fSHuw Davies entry->def.type); 408dc7de73fSHuw Davies if (ret_val != 0) 409dc7de73fSHuw Davies return ret_val; 410dc7de73fSHuw Davies ret_val = nla_put_u32(skb, NLBL_MGMT_A_CLPDOI, 411dc7de73fSHuw Davies entry->def.calipso->doi); 412dc7de73fSHuw Davies break; 41363c41688SPaul Moore } 41463c41688SPaul Moore 41563c41688SPaul Moore return ret_val; 41663c41688SPaul Moore } 41763c41688SPaul Moore 41863c41688SPaul Moore /* 419d15c345fSPaul Moore * NetLabel Command Handlers 420d15c345fSPaul Moore */ 421d15c345fSPaul Moore 422d15c345fSPaul Moore /** 423d15c345fSPaul Moore * netlbl_mgmt_add - Handle an ADD message 424d15c345fSPaul Moore * @skb: the NETLINK buffer 425d15c345fSPaul Moore * @info: the Generic NETLINK info block 426d15c345fSPaul Moore * 427d15c345fSPaul Moore * Description: 428d15c345fSPaul Moore * Process a user generated ADD message and add the domains from the message 429d15c345fSPaul Moore * to the hash table. See netlabel.h for a description of the message format. 430d15c345fSPaul Moore * Returns zero on success, negative values on failure. 431d15c345fSPaul Moore * 432d15c345fSPaul Moore */ 433d15c345fSPaul Moore static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info) 434d15c345fSPaul Moore { 43595d4e6beSPaul Moore struct netlbl_audit audit_info; 436d15c345fSPaul Moore 43763c41688SPaul Moore if ((!info->attrs[NLBL_MGMT_A_DOMAIN]) || 43863c41688SPaul Moore (!info->attrs[NLBL_MGMT_A_PROTOCOL]) || 43963c41688SPaul Moore (info->attrs[NLBL_MGMT_A_IPV4ADDR] && 44063c41688SPaul Moore info->attrs[NLBL_MGMT_A_IPV6ADDR]) || 44163c41688SPaul Moore (info->attrs[NLBL_MGMT_A_IPV4MASK] && 44263c41688SPaul Moore info->attrs[NLBL_MGMT_A_IPV6MASK]) || 44363c41688SPaul Moore ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^ 44463c41688SPaul Moore (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) || 44563c41688SPaul Moore ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^ 44663c41688SPaul Moore (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL))) 44763c41688SPaul Moore return -EINVAL; 448d15c345fSPaul Moore 44995d4e6beSPaul Moore netlbl_netlink_auditinfo(skb, &audit_info); 45095d4e6beSPaul Moore 45163c41688SPaul Moore return netlbl_mgmt_add_common(info, &audit_info); 452d15c345fSPaul Moore } 453d15c345fSPaul Moore 454d15c345fSPaul Moore /** 455d15c345fSPaul Moore * netlbl_mgmt_remove - Handle a REMOVE message 456d15c345fSPaul Moore * @skb: the NETLINK buffer 457d15c345fSPaul Moore * @info: the Generic NETLINK info block 458d15c345fSPaul Moore * 459d15c345fSPaul Moore * Description: 460d15c345fSPaul Moore * Process a user generated REMOVE message and remove the specified domain 461d15c345fSPaul Moore * mappings. Returns zero on success, negative values on failure. 462d15c345fSPaul Moore * 463d15c345fSPaul Moore */ 464d15c345fSPaul Moore static int netlbl_mgmt_remove(struct sk_buff *skb, struct genl_info *info) 465d15c345fSPaul Moore { 466fd385855SPaul Moore char *domain; 46795d4e6beSPaul Moore struct netlbl_audit audit_info; 468d15c345fSPaul Moore 469fd385855SPaul Moore if (!info->attrs[NLBL_MGMT_A_DOMAIN]) 470fd385855SPaul Moore return -EINVAL; 471d15c345fSPaul Moore 47295d4e6beSPaul Moore netlbl_netlink_auditinfo(skb, &audit_info); 47395d4e6beSPaul Moore 474fd385855SPaul Moore domain = nla_data(info->attrs[NLBL_MGMT_A_DOMAIN]); 4758f18e675SHuw Davies return netlbl_domhsh_remove(domain, AF_UNSPEC, &audit_info); 476d15c345fSPaul Moore } 477d15c345fSPaul Moore 478fd385855SPaul Moore /** 479fd385855SPaul Moore * netlbl_mgmt_listall_cb - netlbl_domhsh_walk() callback for LISTALL 480fd385855SPaul Moore * @entry: the domain mapping hash table entry 481fd385855SPaul Moore * @arg: the netlbl_domhsh_walk_arg structure 482fd385855SPaul Moore * 483fd385855SPaul Moore * Description: 484fd385855SPaul Moore * This function is designed to be used as a callback to the 485fd385855SPaul Moore * netlbl_domhsh_walk() function for use in generating a response for a LISTALL 486fd385855SPaul Moore * message. Returns the size of the message on success, negative values on 487fd385855SPaul Moore * failure. 488fd385855SPaul Moore * 489fd385855SPaul Moore */ 490fd385855SPaul Moore static int netlbl_mgmt_listall_cb(struct netlbl_dom_map *entry, void *arg) 491fd385855SPaul Moore { 492fd385855SPaul Moore int ret_val = -ENOMEM; 493fd385855SPaul Moore struct netlbl_domhsh_walk_arg *cb_arg = arg; 494fd385855SPaul Moore void *data; 495d15c345fSPaul Moore 49615e47304SEric W. Biederman data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).portid, 49717c157c8SThomas Graf cb_arg->seq, &netlbl_mgmt_gnl_family, 49817c157c8SThomas Graf NLM_F_MULTI, NLBL_MGMT_C_LISTALL); 499fd385855SPaul Moore if (data == NULL) 500fd385855SPaul Moore goto listall_cb_failure; 501fd385855SPaul Moore 50263c41688SPaul Moore ret_val = netlbl_mgmt_listentry(cb_arg->skb, entry); 503fd385855SPaul Moore if (ret_val != 0) 504fd385855SPaul Moore goto listall_cb_failure; 505fd385855SPaul Moore 506fd385855SPaul Moore cb_arg->seq++; 507053c095aSJohannes Berg genlmsg_end(cb_arg->skb, data); 508053c095aSJohannes Berg return 0; 509fd385855SPaul Moore 510fd385855SPaul Moore listall_cb_failure: 511fd385855SPaul Moore genlmsg_cancel(cb_arg->skb, data); 512d15c345fSPaul Moore return ret_val; 513d15c345fSPaul Moore } 514d15c345fSPaul Moore 515d15c345fSPaul Moore /** 516fd385855SPaul Moore * netlbl_mgmt_listall - Handle a LISTALL message 517d15c345fSPaul Moore * @skb: the NETLINK buffer 518fd385855SPaul Moore * @cb: the NETLINK callback 519d15c345fSPaul Moore * 520d15c345fSPaul Moore * Description: 521fd385855SPaul Moore * Process a user generated LISTALL message and dumps the domain hash table in 522fd385855SPaul Moore * a form suitable for use in a kernel generated LISTALL message. Returns zero 523fd385855SPaul Moore * on success, negative values on failure. 524d15c345fSPaul Moore * 525d15c345fSPaul Moore */ 526fd385855SPaul Moore static int netlbl_mgmt_listall(struct sk_buff *skb, 527fd385855SPaul Moore struct netlink_callback *cb) 528d15c345fSPaul Moore { 529fd385855SPaul Moore struct netlbl_domhsh_walk_arg cb_arg; 530fd385855SPaul Moore u32 skip_bkt = cb->args[0]; 531fd385855SPaul Moore u32 skip_chain = cb->args[1]; 532d15c345fSPaul Moore 533fd385855SPaul Moore cb_arg.nl_cb = cb; 534fd385855SPaul Moore cb_arg.skb = skb; 535fd385855SPaul Moore cb_arg.seq = cb->nlh->nlmsg_seq; 536d15c345fSPaul Moore 537fd385855SPaul Moore netlbl_domhsh_walk(&skip_bkt, 538fd385855SPaul Moore &skip_chain, 539fd385855SPaul Moore netlbl_mgmt_listall_cb, 540fd385855SPaul Moore &cb_arg); 541d15c345fSPaul Moore 542fd385855SPaul Moore cb->args[0] = skip_bkt; 543fd385855SPaul Moore cb->args[1] = skip_chain; 544fd385855SPaul Moore return skb->len; 545d15c345fSPaul Moore } 546d15c345fSPaul Moore 547d15c345fSPaul Moore /** 548d15c345fSPaul Moore * netlbl_mgmt_adddef - Handle an ADDDEF message 549d15c345fSPaul Moore * @skb: the NETLINK buffer 550d15c345fSPaul Moore * @info: the Generic NETLINK info block 551d15c345fSPaul Moore * 552d15c345fSPaul Moore * Description: 553d15c345fSPaul Moore * Process a user generated ADDDEF message and respond accordingly. Returns 554d15c345fSPaul Moore * zero on success, negative values on failure. 555d15c345fSPaul Moore * 556d15c345fSPaul Moore */ 557d15c345fSPaul Moore static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info) 558d15c345fSPaul Moore { 55995d4e6beSPaul Moore struct netlbl_audit audit_info; 560d15c345fSPaul Moore 56163c41688SPaul Moore if ((!info->attrs[NLBL_MGMT_A_PROTOCOL]) || 56263c41688SPaul Moore (info->attrs[NLBL_MGMT_A_IPV4ADDR] && 56363c41688SPaul Moore info->attrs[NLBL_MGMT_A_IPV6ADDR]) || 56463c41688SPaul Moore (info->attrs[NLBL_MGMT_A_IPV4MASK] && 56563c41688SPaul Moore info->attrs[NLBL_MGMT_A_IPV6MASK]) || 56663c41688SPaul Moore ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^ 56763c41688SPaul Moore (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) || 56863c41688SPaul Moore ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^ 56963c41688SPaul Moore (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL))) 57063c41688SPaul Moore return -EINVAL; 571d15c345fSPaul Moore 57295d4e6beSPaul Moore netlbl_netlink_auditinfo(skb, &audit_info); 57395d4e6beSPaul Moore 57463c41688SPaul Moore return netlbl_mgmt_add_common(info, &audit_info); 575d15c345fSPaul Moore } 576d15c345fSPaul Moore 577d15c345fSPaul Moore /** 578d15c345fSPaul Moore * netlbl_mgmt_removedef - Handle a REMOVEDEF message 579d15c345fSPaul Moore * @skb: the NETLINK buffer 580d15c345fSPaul Moore * @info: the Generic NETLINK info block 581d15c345fSPaul Moore * 582d15c345fSPaul Moore * Description: 583d15c345fSPaul Moore * Process a user generated REMOVEDEF message and remove the default domain 584d15c345fSPaul Moore * mapping. Returns zero on success, negative values on failure. 585d15c345fSPaul Moore * 586d15c345fSPaul Moore */ 587d15c345fSPaul Moore static int netlbl_mgmt_removedef(struct sk_buff *skb, struct genl_info *info) 588d15c345fSPaul Moore { 58995d4e6beSPaul Moore struct netlbl_audit audit_info; 59095d4e6beSPaul Moore 59195d4e6beSPaul Moore netlbl_netlink_auditinfo(skb, &audit_info); 59295d4e6beSPaul Moore 5938f18e675SHuw Davies return netlbl_domhsh_remove_default(AF_UNSPEC, &audit_info); 594d15c345fSPaul Moore } 595d15c345fSPaul Moore 596d15c345fSPaul Moore /** 597d15c345fSPaul Moore * netlbl_mgmt_listdef - Handle a LISTDEF message 598d15c345fSPaul Moore * @skb: the NETLINK buffer 599d15c345fSPaul Moore * @info: the Generic NETLINK info block 600d15c345fSPaul Moore * 601d15c345fSPaul Moore * Description: 602d15c345fSPaul Moore * Process a user generated LISTDEF message and dumps the default domain 603d15c345fSPaul Moore * mapping in a form suitable for use in a kernel generated LISTDEF message. 604d15c345fSPaul Moore * Returns zero on success, negative values on failure. 605d15c345fSPaul Moore * 606d15c345fSPaul Moore */ 607d15c345fSPaul Moore static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info) 608d15c345fSPaul Moore { 609d15c345fSPaul Moore int ret_val = -ENOMEM; 610fd385855SPaul Moore struct sk_buff *ans_skb = NULL; 611fd385855SPaul Moore void *data; 612fd385855SPaul Moore struct netlbl_dom_map *entry; 6138f18e675SHuw Davies u16 family; 6148f18e675SHuw Davies 6158f18e675SHuw Davies if (info->attrs[NLBL_MGMT_A_FAMILY]) 6168f18e675SHuw Davies family = nla_get_u16(info->attrs[NLBL_MGMT_A_FAMILY]); 6178f18e675SHuw Davies else 6188f18e675SHuw Davies family = AF_INET; 619d15c345fSPaul Moore 620339bf98fSThomas Graf ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 621d15c345fSPaul Moore if (ans_skb == NULL) 622fd385855SPaul Moore return -ENOMEM; 62317c157c8SThomas Graf data = genlmsg_put_reply(ans_skb, info, &netlbl_mgmt_gnl_family, 62417c157c8SThomas Graf 0, NLBL_MGMT_C_LISTDEF); 625fd385855SPaul Moore if (data == NULL) 626fd385855SPaul Moore goto listdef_failure; 627d15c345fSPaul Moore 628fd385855SPaul Moore rcu_read_lock(); 6298f18e675SHuw Davies entry = netlbl_domhsh_getentry(NULL, family); 630fd385855SPaul Moore if (entry == NULL) { 631fd385855SPaul Moore ret_val = -ENOENT; 632fd385855SPaul Moore goto listdef_failure_lock; 633fd385855SPaul Moore } 63463c41688SPaul Moore ret_val = netlbl_mgmt_listentry(ans_skb, entry); 635fd385855SPaul Moore rcu_read_unlock(); 63663c41688SPaul Moore if (ret_val != 0) 63763c41688SPaul Moore goto listdef_failure; 638fd385855SPaul Moore 639fd385855SPaul Moore genlmsg_end(ans_skb, data); 640fe785beeSDenis V. Lunev return genlmsg_reply(ans_skb, info); 641d15c345fSPaul Moore 642fd385855SPaul Moore listdef_failure_lock: 643fd385855SPaul Moore rcu_read_unlock(); 644d15c345fSPaul Moore listdef_failure: 645fd385855SPaul Moore kfree_skb(ans_skb); 646d15c345fSPaul Moore return ret_val; 647d15c345fSPaul Moore } 648d15c345fSPaul Moore 649d15c345fSPaul Moore /** 650fd385855SPaul Moore * netlbl_mgmt_protocols_cb - Write an individual PROTOCOL message response 651fd385855SPaul Moore * @skb: the skb to write to 652fd385855SPaul Moore * @cb: the NETLINK callback 653fd385855SPaul Moore * @protocol: the NetLabel protocol to use in the message 654d15c345fSPaul Moore * 655d15c345fSPaul Moore * Description: 656fd385855SPaul Moore * This function is to be used in conjunction with netlbl_mgmt_protocols() to 657fd385855SPaul Moore * answer a application's PROTOCOLS message. Returns the size of the message 658fd385855SPaul Moore * on success, negative values on failure. 659d15c345fSPaul Moore * 660d15c345fSPaul Moore */ 661fd385855SPaul Moore static int netlbl_mgmt_protocols_cb(struct sk_buff *skb, 662fd385855SPaul Moore struct netlink_callback *cb, 663fd385855SPaul Moore u32 protocol) 664d15c345fSPaul Moore { 665d15c345fSPaul Moore int ret_val = -ENOMEM; 666fd385855SPaul Moore void *data; 667d15c345fSPaul Moore 66815e47304SEric W. Biederman data = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, 66917c157c8SThomas Graf &netlbl_mgmt_gnl_family, NLM_F_MULTI, 670fd385855SPaul Moore NLBL_MGMT_C_PROTOCOLS); 671fd385855SPaul Moore if (data == NULL) 672fd385855SPaul Moore goto protocols_cb_failure; 673d15c345fSPaul Moore 674fd385855SPaul Moore ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, protocol); 675d15c345fSPaul Moore if (ret_val != 0) 676fd385855SPaul Moore goto protocols_cb_failure; 677d15c345fSPaul Moore 678053c095aSJohannes Berg genlmsg_end(skb, data); 679053c095aSJohannes Berg return 0; 680d15c345fSPaul Moore 681fd385855SPaul Moore protocols_cb_failure: 682fd385855SPaul Moore genlmsg_cancel(skb, data); 683d15c345fSPaul Moore return ret_val; 684d15c345fSPaul Moore } 685d15c345fSPaul Moore 686d15c345fSPaul Moore /** 687fd385855SPaul Moore * netlbl_mgmt_protocols - Handle a PROTOCOLS message 688fd385855SPaul Moore * @skb: the NETLINK buffer 689fd385855SPaul Moore * @cb: the NETLINK callback 690fd385855SPaul Moore * 691fd385855SPaul Moore * Description: 692fd385855SPaul Moore * Process a user generated PROTOCOLS message and respond accordingly. 693fd385855SPaul Moore * 694fd385855SPaul Moore */ 695fd385855SPaul Moore static int netlbl_mgmt_protocols(struct sk_buff *skb, 696fd385855SPaul Moore struct netlink_callback *cb) 697fd385855SPaul Moore { 698fd385855SPaul Moore u32 protos_sent = cb->args[0]; 699fd385855SPaul Moore 700fd385855SPaul Moore if (protos_sent == 0) { 701fd385855SPaul Moore if (netlbl_mgmt_protocols_cb(skb, 702fd385855SPaul Moore cb, 703fd385855SPaul Moore NETLBL_NLTYPE_UNLABELED) < 0) 704fd385855SPaul Moore goto protocols_return; 705fd385855SPaul Moore protos_sent++; 706fd385855SPaul Moore } 707fd385855SPaul Moore if (protos_sent == 1) { 708fd385855SPaul Moore if (netlbl_mgmt_protocols_cb(skb, 709fd385855SPaul Moore cb, 710fd385855SPaul Moore NETLBL_NLTYPE_CIPSOV4) < 0) 711fd385855SPaul Moore goto protocols_return; 712fd385855SPaul Moore protos_sent++; 713fd385855SPaul Moore } 714cb72d382SHuw Davies #if IS_ENABLED(CONFIG_IPV6) 715cb72d382SHuw Davies if (protos_sent == 2) { 716cb72d382SHuw Davies if (netlbl_mgmt_protocols_cb(skb, 717cb72d382SHuw Davies cb, 718cb72d382SHuw Davies NETLBL_NLTYPE_CALIPSO) < 0) 719cb72d382SHuw Davies goto protocols_return; 720cb72d382SHuw Davies protos_sent++; 721cb72d382SHuw Davies } 722cb72d382SHuw Davies #endif 723fd385855SPaul Moore 724fd385855SPaul Moore protocols_return: 725fd385855SPaul Moore cb->args[0] = protos_sent; 726fd385855SPaul Moore return skb->len; 727fd385855SPaul Moore } 728fd385855SPaul Moore 729fd385855SPaul Moore /** 730d15c345fSPaul Moore * netlbl_mgmt_version - Handle a VERSION message 731d15c345fSPaul Moore * @skb: the NETLINK buffer 732d15c345fSPaul Moore * @info: the Generic NETLINK info block 733d15c345fSPaul Moore * 734d15c345fSPaul Moore * Description: 735d15c345fSPaul Moore * Process a user generated VERSION message and respond accordingly. Returns 736d15c345fSPaul Moore * zero on success, negative values on failure. 737d15c345fSPaul Moore * 738d15c345fSPaul Moore */ 739d15c345fSPaul Moore static int netlbl_mgmt_version(struct sk_buff *skb, struct genl_info *info) 740d15c345fSPaul Moore { 741d15c345fSPaul Moore int ret_val = -ENOMEM; 742d15c345fSPaul Moore struct sk_buff *ans_skb = NULL; 743fd385855SPaul Moore void *data; 744d15c345fSPaul Moore 745339bf98fSThomas Graf ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 746d15c345fSPaul Moore if (ans_skb == NULL) 747fd385855SPaul Moore return -ENOMEM; 74817c157c8SThomas Graf data = genlmsg_put_reply(ans_skb, info, &netlbl_mgmt_gnl_family, 74917c157c8SThomas Graf 0, NLBL_MGMT_C_VERSION); 750fd385855SPaul Moore if (data == NULL) 751d15c345fSPaul Moore goto version_failure; 752d15c345fSPaul Moore 753fd385855SPaul Moore ret_val = nla_put_u32(ans_skb, 754fd385855SPaul Moore NLBL_MGMT_A_VERSION, 755fd385855SPaul Moore NETLBL_PROTO_VERSION); 756d15c345fSPaul Moore if (ret_val != 0) 757d15c345fSPaul Moore goto version_failure; 758d15c345fSPaul Moore 759fd385855SPaul Moore genlmsg_end(ans_skb, data); 760fe785beeSDenis V. Lunev return genlmsg_reply(ans_skb, info); 761d15c345fSPaul Moore 762d15c345fSPaul Moore version_failure: 763d15c345fSPaul Moore kfree_skb(ans_skb); 764d15c345fSPaul Moore return ret_val; 765d15c345fSPaul Moore } 766d15c345fSPaul Moore 767d15c345fSPaul Moore 768d15c345fSPaul Moore /* 769d15c345fSPaul Moore * NetLabel Generic NETLINK Command Definitions 770d15c345fSPaul Moore */ 771d15c345fSPaul Moore 7724534de83SJohannes Berg static const struct genl_ops netlbl_mgmt_genl_ops[] = { 773227c43c3SPavel Emelyanov { 774d15c345fSPaul Moore .cmd = NLBL_MGMT_C_ADD, 775fd385855SPaul Moore .flags = GENL_ADMIN_PERM, 776fd385855SPaul Moore .policy = netlbl_mgmt_genl_policy, 777d15c345fSPaul Moore .doit = netlbl_mgmt_add, 778d15c345fSPaul Moore .dumpit = NULL, 779227c43c3SPavel Emelyanov }, 780227c43c3SPavel Emelyanov { 781d15c345fSPaul Moore .cmd = NLBL_MGMT_C_REMOVE, 782fd385855SPaul Moore .flags = GENL_ADMIN_PERM, 783fd385855SPaul Moore .policy = netlbl_mgmt_genl_policy, 784d15c345fSPaul Moore .doit = netlbl_mgmt_remove, 785d15c345fSPaul Moore .dumpit = NULL, 786227c43c3SPavel Emelyanov }, 787227c43c3SPavel Emelyanov { 788fd385855SPaul Moore .cmd = NLBL_MGMT_C_LISTALL, 789d15c345fSPaul Moore .flags = 0, 790fd385855SPaul Moore .policy = netlbl_mgmt_genl_policy, 791fd385855SPaul Moore .doit = NULL, 792fd385855SPaul Moore .dumpit = netlbl_mgmt_listall, 793227c43c3SPavel Emelyanov }, 794227c43c3SPavel Emelyanov { 795d15c345fSPaul Moore .cmd = NLBL_MGMT_C_ADDDEF, 796fd385855SPaul Moore .flags = GENL_ADMIN_PERM, 797fd385855SPaul Moore .policy = netlbl_mgmt_genl_policy, 798d15c345fSPaul Moore .doit = netlbl_mgmt_adddef, 799d15c345fSPaul Moore .dumpit = NULL, 800227c43c3SPavel Emelyanov }, 801227c43c3SPavel Emelyanov { 802d15c345fSPaul Moore .cmd = NLBL_MGMT_C_REMOVEDEF, 803fd385855SPaul Moore .flags = GENL_ADMIN_PERM, 804fd385855SPaul Moore .policy = netlbl_mgmt_genl_policy, 805d15c345fSPaul Moore .doit = netlbl_mgmt_removedef, 806d15c345fSPaul Moore .dumpit = NULL, 807227c43c3SPavel Emelyanov }, 808227c43c3SPavel Emelyanov { 809d15c345fSPaul Moore .cmd = NLBL_MGMT_C_LISTDEF, 810d15c345fSPaul Moore .flags = 0, 811fd385855SPaul Moore .policy = netlbl_mgmt_genl_policy, 812d15c345fSPaul Moore .doit = netlbl_mgmt_listdef, 813d15c345fSPaul Moore .dumpit = NULL, 814227c43c3SPavel Emelyanov }, 815227c43c3SPavel Emelyanov { 816fd385855SPaul Moore .cmd = NLBL_MGMT_C_PROTOCOLS, 817d15c345fSPaul Moore .flags = 0, 818fd385855SPaul Moore .policy = netlbl_mgmt_genl_policy, 819fd385855SPaul Moore .doit = NULL, 820fd385855SPaul Moore .dumpit = netlbl_mgmt_protocols, 821227c43c3SPavel Emelyanov }, 822227c43c3SPavel Emelyanov { 823d15c345fSPaul Moore .cmd = NLBL_MGMT_C_VERSION, 824d15c345fSPaul Moore .flags = 0, 825fd385855SPaul Moore .policy = netlbl_mgmt_genl_policy, 826d15c345fSPaul Moore .doit = netlbl_mgmt_version, 827d15c345fSPaul Moore .dumpit = NULL, 828227c43c3SPavel Emelyanov }, 829d15c345fSPaul Moore }; 830d15c345fSPaul Moore 83156989f6dSJohannes Berg static struct genl_family netlbl_mgmt_gnl_family __ro_after_init = { 832489111e5SJohannes Berg .hdrsize = 0, 833489111e5SJohannes Berg .name = NETLBL_NLTYPE_MGMT_NAME, 834489111e5SJohannes Berg .version = NETLBL_PROTO_VERSION, 835489111e5SJohannes Berg .maxattr = NLBL_MGMT_A_MAX, 836489111e5SJohannes Berg .module = THIS_MODULE, 837489111e5SJohannes Berg .ops = netlbl_mgmt_genl_ops, 838489111e5SJohannes Berg .n_ops = ARRAY_SIZE(netlbl_mgmt_genl_ops), 839489111e5SJohannes Berg }; 840489111e5SJohannes Berg 841d15c345fSPaul Moore /* 842d15c345fSPaul Moore * NetLabel Generic NETLINK Protocol Functions 843d15c345fSPaul Moore */ 844d15c345fSPaul Moore 845d15c345fSPaul Moore /** 846d15c345fSPaul Moore * netlbl_mgmt_genl_init - Register the NetLabel management component 847d15c345fSPaul Moore * 848d15c345fSPaul Moore * Description: 849d15c345fSPaul Moore * Register the NetLabel management component with the Generic NETLINK 850d15c345fSPaul Moore * mechanism. Returns zero on success, negative values on failure. 851d15c345fSPaul Moore * 852d15c345fSPaul Moore */ 85305705e4eSPavel Emelyanov int __init netlbl_mgmt_genl_init(void) 854d15c345fSPaul Moore { 855489111e5SJohannes Berg return genl_register_family(&netlbl_mgmt_gnl_family); 856d15c345fSPaul Moore } 857