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: 318ae0be8deSMichal Kubecek nla_a = nla_nest_start_noflag(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 326ae0be8deSMichal Kubecek nla_b = nla_nest_start_noflag(skb, 327ae0be8deSMichal Kubecek NLBL_MGMT_A_ADDRSELECTOR); 32863c41688SPaul Moore if (nla_b == NULL) 32963c41688SPaul Moore return -ENOMEM; 33063c41688SPaul Moore 33163c41688SPaul Moore addr_struct.s_addr = iter4->addr; 332930345eaSJiri Benc ret_val = nla_put_in_addr(skb, NLBL_MGMT_A_IPV4ADDR, 333930345eaSJiri Benc addr_struct.s_addr); 33463c41688SPaul Moore if (ret_val != 0) 33563c41688SPaul Moore return ret_val; 33663c41688SPaul Moore addr_struct.s_addr = iter4->mask; 337930345eaSJiri Benc ret_val = nla_put_in_addr(skb, NLBL_MGMT_A_IPV4MASK, 338930345eaSJiri Benc addr_struct.s_addr); 33963c41688SPaul Moore if (ret_val != 0) 34063c41688SPaul Moore return ret_val; 34163c41688SPaul Moore map4 = netlbl_domhsh_addr4_entry(iter4); 34263c41688SPaul Moore ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, 3436a8b7f0cSPaul Moore map4->def.type); 34463c41688SPaul Moore if (ret_val != 0) 34563c41688SPaul Moore return ret_val; 3466a8b7f0cSPaul Moore switch (map4->def.type) { 34763c41688SPaul Moore case NETLBL_NLTYPE_CIPSOV4: 34863c41688SPaul Moore ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI, 3496a8b7f0cSPaul Moore map4->def.cipso->doi); 35063c41688SPaul Moore if (ret_val != 0) 35163c41688SPaul Moore return ret_val; 35263c41688SPaul Moore break; 35363c41688SPaul Moore } 35463c41688SPaul Moore 35563c41688SPaul Moore nla_nest_end(skb, nla_b); 35663c41688SPaul Moore } 357dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6) 3586a8b7f0cSPaul Moore netlbl_af6list_foreach_rcu(iter6, &entry->def.addrsel->list6) { 35963c41688SPaul Moore struct netlbl_domaddr6_map *map6; 36063c41688SPaul Moore 361ae0be8deSMichal Kubecek nla_b = nla_nest_start_noflag(skb, 362ae0be8deSMichal Kubecek NLBL_MGMT_A_ADDRSELECTOR); 36363c41688SPaul Moore if (nla_b == NULL) 36463c41688SPaul Moore return -ENOMEM; 36563c41688SPaul Moore 366930345eaSJiri Benc ret_val = nla_put_in6_addr(skb, NLBL_MGMT_A_IPV6ADDR, 36763c41688SPaul Moore &iter6->addr); 36863c41688SPaul Moore if (ret_val != 0) 36963c41688SPaul Moore return ret_val; 370930345eaSJiri Benc ret_val = nla_put_in6_addr(skb, NLBL_MGMT_A_IPV6MASK, 37163c41688SPaul Moore &iter6->mask); 37263c41688SPaul Moore if (ret_val != 0) 37363c41688SPaul Moore return ret_val; 37463c41688SPaul Moore map6 = netlbl_domhsh_addr6_entry(iter6); 37563c41688SPaul Moore ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, 3766a8b7f0cSPaul Moore map6->def.type); 37763c41688SPaul Moore if (ret_val != 0) 37863c41688SPaul Moore return ret_val; 37963c41688SPaul Moore 380dc7de73fSHuw Davies switch (map6->def.type) { 381dc7de73fSHuw Davies case NETLBL_NLTYPE_CALIPSO: 382dc7de73fSHuw Davies ret_val = nla_put_u32(skb, NLBL_MGMT_A_CLPDOI, 383dc7de73fSHuw Davies map6->def.calipso->doi); 384dc7de73fSHuw Davies if (ret_val != 0) 385dc7de73fSHuw Davies return ret_val; 386dc7de73fSHuw Davies break; 387dc7de73fSHuw Davies } 388dc7de73fSHuw Davies 38963c41688SPaul Moore nla_nest_end(skb, nla_b); 39063c41688SPaul Moore } 39163c41688SPaul Moore #endif /* IPv6 */ 39263c41688SPaul Moore 39363c41688SPaul Moore nla_nest_end(skb, nla_a); 39463c41688SPaul Moore break; 39563c41688SPaul Moore case NETLBL_NLTYPE_UNLABELED: 396dc7de73fSHuw Davies ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, 397dc7de73fSHuw Davies entry->def.type); 39863c41688SPaul Moore break; 39963c41688SPaul Moore case NETLBL_NLTYPE_CIPSOV4: 400dc7de73fSHuw Davies ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, 401dc7de73fSHuw Davies entry->def.type); 40263c41688SPaul Moore if (ret_val != 0) 40363c41688SPaul Moore return ret_val; 40463c41688SPaul Moore ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI, 4056a8b7f0cSPaul Moore entry->def.cipso->doi); 40663c41688SPaul Moore break; 407dc7de73fSHuw Davies case NETLBL_NLTYPE_CALIPSO: 408dc7de73fSHuw Davies ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, 409dc7de73fSHuw Davies entry->def.type); 410dc7de73fSHuw Davies if (ret_val != 0) 411dc7de73fSHuw Davies return ret_val; 412dc7de73fSHuw Davies ret_val = nla_put_u32(skb, NLBL_MGMT_A_CLPDOI, 413dc7de73fSHuw Davies entry->def.calipso->doi); 414dc7de73fSHuw Davies break; 41563c41688SPaul Moore } 41663c41688SPaul Moore 41763c41688SPaul Moore return ret_val; 41863c41688SPaul Moore } 41963c41688SPaul Moore 42063c41688SPaul Moore /* 421d15c345fSPaul Moore * NetLabel Command Handlers 422d15c345fSPaul Moore */ 423d15c345fSPaul Moore 424d15c345fSPaul Moore /** 425d15c345fSPaul Moore * netlbl_mgmt_add - Handle an ADD message 426d15c345fSPaul Moore * @skb: the NETLINK buffer 427d15c345fSPaul Moore * @info: the Generic NETLINK info block 428d15c345fSPaul Moore * 429d15c345fSPaul Moore * Description: 430d15c345fSPaul Moore * Process a user generated ADD message and add the domains from the message 431d15c345fSPaul Moore * to the hash table. See netlabel.h for a description of the message format. 432d15c345fSPaul Moore * Returns zero on success, negative values on failure. 433d15c345fSPaul Moore * 434d15c345fSPaul Moore */ 435d15c345fSPaul Moore static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info) 436d15c345fSPaul Moore { 43795d4e6beSPaul Moore struct netlbl_audit audit_info; 438d15c345fSPaul Moore 43963c41688SPaul Moore if ((!info->attrs[NLBL_MGMT_A_DOMAIN]) || 44063c41688SPaul Moore (!info->attrs[NLBL_MGMT_A_PROTOCOL]) || 44163c41688SPaul Moore (info->attrs[NLBL_MGMT_A_IPV4ADDR] && 44263c41688SPaul Moore info->attrs[NLBL_MGMT_A_IPV6ADDR]) || 44363c41688SPaul Moore (info->attrs[NLBL_MGMT_A_IPV4MASK] && 44463c41688SPaul Moore info->attrs[NLBL_MGMT_A_IPV6MASK]) || 44563c41688SPaul Moore ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^ 44663c41688SPaul Moore (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) || 44763c41688SPaul Moore ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^ 44863c41688SPaul Moore (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL))) 44963c41688SPaul Moore return -EINVAL; 450d15c345fSPaul Moore 45195d4e6beSPaul Moore netlbl_netlink_auditinfo(skb, &audit_info); 45295d4e6beSPaul Moore 45363c41688SPaul Moore return netlbl_mgmt_add_common(info, &audit_info); 454d15c345fSPaul Moore } 455d15c345fSPaul Moore 456d15c345fSPaul Moore /** 457d15c345fSPaul Moore * netlbl_mgmt_remove - Handle a REMOVE message 458d15c345fSPaul Moore * @skb: the NETLINK buffer 459d15c345fSPaul Moore * @info: the Generic NETLINK info block 460d15c345fSPaul Moore * 461d15c345fSPaul Moore * Description: 462d15c345fSPaul Moore * Process a user generated REMOVE message and remove the specified domain 463d15c345fSPaul Moore * mappings. Returns zero on success, negative values on failure. 464d15c345fSPaul Moore * 465d15c345fSPaul Moore */ 466d15c345fSPaul Moore static int netlbl_mgmt_remove(struct sk_buff *skb, struct genl_info *info) 467d15c345fSPaul Moore { 468fd385855SPaul Moore char *domain; 46995d4e6beSPaul Moore struct netlbl_audit audit_info; 470d15c345fSPaul Moore 471fd385855SPaul Moore if (!info->attrs[NLBL_MGMT_A_DOMAIN]) 472fd385855SPaul Moore return -EINVAL; 473d15c345fSPaul Moore 47495d4e6beSPaul Moore netlbl_netlink_auditinfo(skb, &audit_info); 47595d4e6beSPaul Moore 476fd385855SPaul Moore domain = nla_data(info->attrs[NLBL_MGMT_A_DOMAIN]); 4778f18e675SHuw Davies return netlbl_domhsh_remove(domain, AF_UNSPEC, &audit_info); 478d15c345fSPaul Moore } 479d15c345fSPaul Moore 480fd385855SPaul Moore /** 481fd385855SPaul Moore * netlbl_mgmt_listall_cb - netlbl_domhsh_walk() callback for LISTALL 482fd385855SPaul Moore * @entry: the domain mapping hash table entry 483fd385855SPaul Moore * @arg: the netlbl_domhsh_walk_arg structure 484fd385855SPaul Moore * 485fd385855SPaul Moore * Description: 486fd385855SPaul Moore * This function is designed to be used as a callback to the 487fd385855SPaul Moore * netlbl_domhsh_walk() function for use in generating a response for a LISTALL 488fd385855SPaul Moore * message. Returns the size of the message on success, negative values on 489fd385855SPaul Moore * failure. 490fd385855SPaul Moore * 491fd385855SPaul Moore */ 492fd385855SPaul Moore static int netlbl_mgmt_listall_cb(struct netlbl_dom_map *entry, void *arg) 493fd385855SPaul Moore { 494fd385855SPaul Moore int ret_val = -ENOMEM; 495fd385855SPaul Moore struct netlbl_domhsh_walk_arg *cb_arg = arg; 496fd385855SPaul Moore void *data; 497d15c345fSPaul Moore 49815e47304SEric W. Biederman data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).portid, 49917c157c8SThomas Graf cb_arg->seq, &netlbl_mgmt_gnl_family, 50017c157c8SThomas Graf NLM_F_MULTI, NLBL_MGMT_C_LISTALL); 501fd385855SPaul Moore if (data == NULL) 502fd385855SPaul Moore goto listall_cb_failure; 503fd385855SPaul Moore 50463c41688SPaul Moore ret_val = netlbl_mgmt_listentry(cb_arg->skb, entry); 505fd385855SPaul Moore if (ret_val != 0) 506fd385855SPaul Moore goto listall_cb_failure; 507fd385855SPaul Moore 508fd385855SPaul Moore cb_arg->seq++; 509053c095aSJohannes Berg genlmsg_end(cb_arg->skb, data); 510053c095aSJohannes Berg return 0; 511fd385855SPaul Moore 512fd385855SPaul Moore listall_cb_failure: 513fd385855SPaul Moore genlmsg_cancel(cb_arg->skb, data); 514d15c345fSPaul Moore return ret_val; 515d15c345fSPaul Moore } 516d15c345fSPaul Moore 517d15c345fSPaul Moore /** 518fd385855SPaul Moore * netlbl_mgmt_listall - Handle a LISTALL message 519d15c345fSPaul Moore * @skb: the NETLINK buffer 520fd385855SPaul Moore * @cb: the NETLINK callback 521d15c345fSPaul Moore * 522d15c345fSPaul Moore * Description: 523fd385855SPaul Moore * Process a user generated LISTALL message and dumps the domain hash table in 524fd385855SPaul Moore * a form suitable for use in a kernel generated LISTALL message. Returns zero 525fd385855SPaul Moore * on success, negative values on failure. 526d15c345fSPaul Moore * 527d15c345fSPaul Moore */ 528fd385855SPaul Moore static int netlbl_mgmt_listall(struct sk_buff *skb, 529fd385855SPaul Moore struct netlink_callback *cb) 530d15c345fSPaul Moore { 531fd385855SPaul Moore struct netlbl_domhsh_walk_arg cb_arg; 532fd385855SPaul Moore u32 skip_bkt = cb->args[0]; 533fd385855SPaul Moore u32 skip_chain = cb->args[1]; 534d15c345fSPaul Moore 535fd385855SPaul Moore cb_arg.nl_cb = cb; 536fd385855SPaul Moore cb_arg.skb = skb; 537fd385855SPaul Moore cb_arg.seq = cb->nlh->nlmsg_seq; 538d15c345fSPaul Moore 539fd385855SPaul Moore netlbl_domhsh_walk(&skip_bkt, 540fd385855SPaul Moore &skip_chain, 541fd385855SPaul Moore netlbl_mgmt_listall_cb, 542fd385855SPaul Moore &cb_arg); 543d15c345fSPaul Moore 544fd385855SPaul Moore cb->args[0] = skip_bkt; 545fd385855SPaul Moore cb->args[1] = skip_chain; 546fd385855SPaul Moore return skb->len; 547d15c345fSPaul Moore } 548d15c345fSPaul Moore 549d15c345fSPaul Moore /** 550d15c345fSPaul Moore * netlbl_mgmt_adddef - Handle an ADDDEF message 551d15c345fSPaul Moore * @skb: the NETLINK buffer 552d15c345fSPaul Moore * @info: the Generic NETLINK info block 553d15c345fSPaul Moore * 554d15c345fSPaul Moore * Description: 555d15c345fSPaul Moore * Process a user generated ADDDEF message and respond accordingly. Returns 556d15c345fSPaul Moore * zero on success, negative values on failure. 557d15c345fSPaul Moore * 558d15c345fSPaul Moore */ 559d15c345fSPaul Moore static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info) 560d15c345fSPaul Moore { 56195d4e6beSPaul Moore struct netlbl_audit audit_info; 562d15c345fSPaul Moore 56363c41688SPaul Moore if ((!info->attrs[NLBL_MGMT_A_PROTOCOL]) || 56463c41688SPaul Moore (info->attrs[NLBL_MGMT_A_IPV4ADDR] && 56563c41688SPaul Moore info->attrs[NLBL_MGMT_A_IPV6ADDR]) || 56663c41688SPaul Moore (info->attrs[NLBL_MGMT_A_IPV4MASK] && 56763c41688SPaul Moore info->attrs[NLBL_MGMT_A_IPV6MASK]) || 56863c41688SPaul Moore ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^ 56963c41688SPaul Moore (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) || 57063c41688SPaul Moore ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^ 57163c41688SPaul Moore (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL))) 57263c41688SPaul Moore return -EINVAL; 573d15c345fSPaul Moore 57495d4e6beSPaul Moore netlbl_netlink_auditinfo(skb, &audit_info); 57595d4e6beSPaul Moore 57663c41688SPaul Moore return netlbl_mgmt_add_common(info, &audit_info); 577d15c345fSPaul Moore } 578d15c345fSPaul Moore 579d15c345fSPaul Moore /** 580d15c345fSPaul Moore * netlbl_mgmt_removedef - Handle a REMOVEDEF message 581d15c345fSPaul Moore * @skb: the NETLINK buffer 582d15c345fSPaul Moore * @info: the Generic NETLINK info block 583d15c345fSPaul Moore * 584d15c345fSPaul Moore * Description: 585d15c345fSPaul Moore * Process a user generated REMOVEDEF message and remove the default domain 586d15c345fSPaul Moore * mapping. Returns zero on success, negative values on failure. 587d15c345fSPaul Moore * 588d15c345fSPaul Moore */ 589d15c345fSPaul Moore static int netlbl_mgmt_removedef(struct sk_buff *skb, struct genl_info *info) 590d15c345fSPaul Moore { 59195d4e6beSPaul Moore struct netlbl_audit audit_info; 59295d4e6beSPaul Moore 59395d4e6beSPaul Moore netlbl_netlink_auditinfo(skb, &audit_info); 59495d4e6beSPaul Moore 5958f18e675SHuw Davies return netlbl_domhsh_remove_default(AF_UNSPEC, &audit_info); 596d15c345fSPaul Moore } 597d15c345fSPaul Moore 598d15c345fSPaul Moore /** 599d15c345fSPaul Moore * netlbl_mgmt_listdef - Handle a LISTDEF message 600d15c345fSPaul Moore * @skb: the NETLINK buffer 601d15c345fSPaul Moore * @info: the Generic NETLINK info block 602d15c345fSPaul Moore * 603d15c345fSPaul Moore * Description: 604d15c345fSPaul Moore * Process a user generated LISTDEF message and dumps the default domain 605d15c345fSPaul Moore * mapping in a form suitable for use in a kernel generated LISTDEF message. 606d15c345fSPaul Moore * Returns zero on success, negative values on failure. 607d15c345fSPaul Moore * 608d15c345fSPaul Moore */ 609d15c345fSPaul Moore static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info) 610d15c345fSPaul Moore { 611d15c345fSPaul Moore int ret_val = -ENOMEM; 612fd385855SPaul Moore struct sk_buff *ans_skb = NULL; 613fd385855SPaul Moore void *data; 614fd385855SPaul Moore struct netlbl_dom_map *entry; 6158f18e675SHuw Davies u16 family; 6168f18e675SHuw Davies 6178f18e675SHuw Davies if (info->attrs[NLBL_MGMT_A_FAMILY]) 6188f18e675SHuw Davies family = nla_get_u16(info->attrs[NLBL_MGMT_A_FAMILY]); 6198f18e675SHuw Davies else 6208f18e675SHuw Davies family = AF_INET; 621d15c345fSPaul Moore 622339bf98fSThomas Graf ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 623d15c345fSPaul Moore if (ans_skb == NULL) 624fd385855SPaul Moore return -ENOMEM; 62517c157c8SThomas Graf data = genlmsg_put_reply(ans_skb, info, &netlbl_mgmt_gnl_family, 62617c157c8SThomas Graf 0, NLBL_MGMT_C_LISTDEF); 627fd385855SPaul Moore if (data == NULL) 628fd385855SPaul Moore goto listdef_failure; 629d15c345fSPaul Moore 630fd385855SPaul Moore rcu_read_lock(); 6318f18e675SHuw Davies entry = netlbl_domhsh_getentry(NULL, family); 632fd385855SPaul Moore if (entry == NULL) { 633fd385855SPaul Moore ret_val = -ENOENT; 634fd385855SPaul Moore goto listdef_failure_lock; 635fd385855SPaul Moore } 63663c41688SPaul Moore ret_val = netlbl_mgmt_listentry(ans_skb, entry); 637fd385855SPaul Moore rcu_read_unlock(); 63863c41688SPaul Moore if (ret_val != 0) 63963c41688SPaul Moore goto listdef_failure; 640fd385855SPaul Moore 641fd385855SPaul Moore genlmsg_end(ans_skb, data); 642fe785beeSDenis V. Lunev return genlmsg_reply(ans_skb, info); 643d15c345fSPaul Moore 644fd385855SPaul Moore listdef_failure_lock: 645fd385855SPaul Moore rcu_read_unlock(); 646d15c345fSPaul Moore listdef_failure: 647fd385855SPaul Moore kfree_skb(ans_skb); 648d15c345fSPaul Moore return ret_val; 649d15c345fSPaul Moore } 650d15c345fSPaul Moore 651d15c345fSPaul Moore /** 652fd385855SPaul Moore * netlbl_mgmt_protocols_cb - Write an individual PROTOCOL message response 653fd385855SPaul Moore * @skb: the skb to write to 654fd385855SPaul Moore * @cb: the NETLINK callback 655fd385855SPaul Moore * @protocol: the NetLabel protocol to use in the message 656d15c345fSPaul Moore * 657d15c345fSPaul Moore * Description: 658fd385855SPaul Moore * This function is to be used in conjunction with netlbl_mgmt_protocols() to 659fd385855SPaul Moore * answer a application's PROTOCOLS message. Returns the size of the message 660fd385855SPaul Moore * on success, negative values on failure. 661d15c345fSPaul Moore * 662d15c345fSPaul Moore */ 663fd385855SPaul Moore static int netlbl_mgmt_protocols_cb(struct sk_buff *skb, 664fd385855SPaul Moore struct netlink_callback *cb, 665fd385855SPaul Moore u32 protocol) 666d15c345fSPaul Moore { 667d15c345fSPaul Moore int ret_val = -ENOMEM; 668fd385855SPaul Moore void *data; 669d15c345fSPaul Moore 67015e47304SEric W. Biederman data = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, 67117c157c8SThomas Graf &netlbl_mgmt_gnl_family, NLM_F_MULTI, 672fd385855SPaul Moore NLBL_MGMT_C_PROTOCOLS); 673fd385855SPaul Moore if (data == NULL) 674fd385855SPaul Moore goto protocols_cb_failure; 675d15c345fSPaul Moore 676fd385855SPaul Moore ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, protocol); 677d15c345fSPaul Moore if (ret_val != 0) 678fd385855SPaul Moore goto protocols_cb_failure; 679d15c345fSPaul Moore 680053c095aSJohannes Berg genlmsg_end(skb, data); 681053c095aSJohannes Berg return 0; 682d15c345fSPaul Moore 683fd385855SPaul Moore protocols_cb_failure: 684fd385855SPaul Moore genlmsg_cancel(skb, data); 685d15c345fSPaul Moore return ret_val; 686d15c345fSPaul Moore } 687d15c345fSPaul Moore 688d15c345fSPaul Moore /** 689fd385855SPaul Moore * netlbl_mgmt_protocols - Handle a PROTOCOLS message 690fd385855SPaul Moore * @skb: the NETLINK buffer 691fd385855SPaul Moore * @cb: the NETLINK callback 692fd385855SPaul Moore * 693fd385855SPaul Moore * Description: 694fd385855SPaul Moore * Process a user generated PROTOCOLS message and respond accordingly. 695fd385855SPaul Moore * 696fd385855SPaul Moore */ 697fd385855SPaul Moore static int netlbl_mgmt_protocols(struct sk_buff *skb, 698fd385855SPaul Moore struct netlink_callback *cb) 699fd385855SPaul Moore { 700fd385855SPaul Moore u32 protos_sent = cb->args[0]; 701fd385855SPaul Moore 702fd385855SPaul Moore if (protos_sent == 0) { 703fd385855SPaul Moore if (netlbl_mgmt_protocols_cb(skb, 704fd385855SPaul Moore cb, 705fd385855SPaul Moore NETLBL_NLTYPE_UNLABELED) < 0) 706fd385855SPaul Moore goto protocols_return; 707fd385855SPaul Moore protos_sent++; 708fd385855SPaul Moore } 709fd385855SPaul Moore if (protos_sent == 1) { 710fd385855SPaul Moore if (netlbl_mgmt_protocols_cb(skb, 711fd385855SPaul Moore cb, 712fd385855SPaul Moore NETLBL_NLTYPE_CIPSOV4) < 0) 713fd385855SPaul Moore goto protocols_return; 714fd385855SPaul Moore protos_sent++; 715fd385855SPaul Moore } 716cb72d382SHuw Davies #if IS_ENABLED(CONFIG_IPV6) 717cb72d382SHuw Davies if (protos_sent == 2) { 718cb72d382SHuw Davies if (netlbl_mgmt_protocols_cb(skb, 719cb72d382SHuw Davies cb, 720cb72d382SHuw Davies NETLBL_NLTYPE_CALIPSO) < 0) 721cb72d382SHuw Davies goto protocols_return; 722cb72d382SHuw Davies protos_sent++; 723cb72d382SHuw Davies } 724cb72d382SHuw Davies #endif 725fd385855SPaul Moore 726fd385855SPaul Moore protocols_return: 727fd385855SPaul Moore cb->args[0] = protos_sent; 728fd385855SPaul Moore return skb->len; 729fd385855SPaul Moore } 730fd385855SPaul Moore 731fd385855SPaul Moore /** 732d15c345fSPaul Moore * netlbl_mgmt_version - Handle a VERSION message 733d15c345fSPaul Moore * @skb: the NETLINK buffer 734d15c345fSPaul Moore * @info: the Generic NETLINK info block 735d15c345fSPaul Moore * 736d15c345fSPaul Moore * Description: 737d15c345fSPaul Moore * Process a user generated VERSION message and respond accordingly. Returns 738d15c345fSPaul Moore * zero on success, negative values on failure. 739d15c345fSPaul Moore * 740d15c345fSPaul Moore */ 741d15c345fSPaul Moore static int netlbl_mgmt_version(struct sk_buff *skb, struct genl_info *info) 742d15c345fSPaul Moore { 743d15c345fSPaul Moore int ret_val = -ENOMEM; 744d15c345fSPaul Moore struct sk_buff *ans_skb = NULL; 745fd385855SPaul Moore void *data; 746d15c345fSPaul Moore 747339bf98fSThomas Graf ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 748d15c345fSPaul Moore if (ans_skb == NULL) 749fd385855SPaul Moore return -ENOMEM; 75017c157c8SThomas Graf data = genlmsg_put_reply(ans_skb, info, &netlbl_mgmt_gnl_family, 75117c157c8SThomas Graf 0, NLBL_MGMT_C_VERSION); 752fd385855SPaul Moore if (data == NULL) 753d15c345fSPaul Moore goto version_failure; 754d15c345fSPaul Moore 755fd385855SPaul Moore ret_val = nla_put_u32(ans_skb, 756fd385855SPaul Moore NLBL_MGMT_A_VERSION, 757fd385855SPaul Moore NETLBL_PROTO_VERSION); 758d15c345fSPaul Moore if (ret_val != 0) 759d15c345fSPaul Moore goto version_failure; 760d15c345fSPaul Moore 761fd385855SPaul Moore genlmsg_end(ans_skb, data); 762fe785beeSDenis V. Lunev return genlmsg_reply(ans_skb, info); 763d15c345fSPaul Moore 764d15c345fSPaul Moore version_failure: 765d15c345fSPaul Moore kfree_skb(ans_skb); 766d15c345fSPaul Moore return ret_val; 767d15c345fSPaul Moore } 768d15c345fSPaul Moore 769d15c345fSPaul Moore 770d15c345fSPaul Moore /* 771d15c345fSPaul Moore * NetLabel Generic NETLINK Command Definitions 772d15c345fSPaul Moore */ 773d15c345fSPaul Moore 7744534de83SJohannes Berg static const struct genl_ops netlbl_mgmt_genl_ops[] = { 775227c43c3SPavel Emelyanov { 776d15c345fSPaul Moore .cmd = NLBL_MGMT_C_ADD, 777ef6243acSJohannes Berg .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 778fd385855SPaul Moore .flags = GENL_ADMIN_PERM, 779d15c345fSPaul Moore .doit = netlbl_mgmt_add, 780d15c345fSPaul Moore .dumpit = NULL, 781227c43c3SPavel Emelyanov }, 782227c43c3SPavel Emelyanov { 783d15c345fSPaul Moore .cmd = NLBL_MGMT_C_REMOVE, 784ef6243acSJohannes Berg .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 785fd385855SPaul Moore .flags = GENL_ADMIN_PERM, 786d15c345fSPaul Moore .doit = netlbl_mgmt_remove, 787d15c345fSPaul Moore .dumpit = NULL, 788227c43c3SPavel Emelyanov }, 789227c43c3SPavel Emelyanov { 790fd385855SPaul Moore .cmd = NLBL_MGMT_C_LISTALL, 791ef6243acSJohannes Berg .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 792d15c345fSPaul Moore .flags = 0, 793fd385855SPaul Moore .doit = NULL, 794fd385855SPaul Moore .dumpit = netlbl_mgmt_listall, 795227c43c3SPavel Emelyanov }, 796227c43c3SPavel Emelyanov { 797d15c345fSPaul Moore .cmd = NLBL_MGMT_C_ADDDEF, 798ef6243acSJohannes Berg .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 799fd385855SPaul Moore .flags = GENL_ADMIN_PERM, 800d15c345fSPaul Moore .doit = netlbl_mgmt_adddef, 801d15c345fSPaul Moore .dumpit = NULL, 802227c43c3SPavel Emelyanov }, 803227c43c3SPavel Emelyanov { 804d15c345fSPaul Moore .cmd = NLBL_MGMT_C_REMOVEDEF, 805ef6243acSJohannes Berg .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 806fd385855SPaul Moore .flags = GENL_ADMIN_PERM, 807d15c345fSPaul Moore .doit = netlbl_mgmt_removedef, 808d15c345fSPaul Moore .dumpit = NULL, 809227c43c3SPavel Emelyanov }, 810227c43c3SPavel Emelyanov { 811d15c345fSPaul Moore .cmd = NLBL_MGMT_C_LISTDEF, 812ef6243acSJohannes Berg .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 813d15c345fSPaul Moore .flags = 0, 814d15c345fSPaul Moore .doit = netlbl_mgmt_listdef, 815d15c345fSPaul Moore .dumpit = NULL, 816227c43c3SPavel Emelyanov }, 817227c43c3SPavel Emelyanov { 818fd385855SPaul Moore .cmd = NLBL_MGMT_C_PROTOCOLS, 819ef6243acSJohannes Berg .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 820d15c345fSPaul Moore .flags = 0, 821fd385855SPaul Moore .doit = NULL, 822fd385855SPaul Moore .dumpit = netlbl_mgmt_protocols, 823227c43c3SPavel Emelyanov }, 824227c43c3SPavel Emelyanov { 825d15c345fSPaul Moore .cmd = NLBL_MGMT_C_VERSION, 826ef6243acSJohannes Berg .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 827d15c345fSPaul Moore .flags = 0, 828d15c345fSPaul Moore .doit = netlbl_mgmt_version, 829d15c345fSPaul Moore .dumpit = NULL, 830227c43c3SPavel Emelyanov }, 831d15c345fSPaul Moore }; 832d15c345fSPaul Moore 83356989f6dSJohannes Berg static struct genl_family netlbl_mgmt_gnl_family __ro_after_init = { 834489111e5SJohannes Berg .hdrsize = 0, 835489111e5SJohannes Berg .name = NETLBL_NLTYPE_MGMT_NAME, 836489111e5SJohannes Berg .version = NETLBL_PROTO_VERSION, 837489111e5SJohannes Berg .maxattr = NLBL_MGMT_A_MAX, 8383b0f31f2SJohannes Berg .policy = netlbl_mgmt_genl_policy, 839489111e5SJohannes Berg .module = THIS_MODULE, 840489111e5SJohannes Berg .ops = netlbl_mgmt_genl_ops, 841489111e5SJohannes Berg .n_ops = ARRAY_SIZE(netlbl_mgmt_genl_ops), 842489111e5SJohannes Berg }; 843489111e5SJohannes Berg 844d15c345fSPaul Moore /* 845d15c345fSPaul Moore * NetLabel Generic NETLINK Protocol Functions 846d15c345fSPaul Moore */ 847d15c345fSPaul Moore 848d15c345fSPaul Moore /** 849d15c345fSPaul Moore * netlbl_mgmt_genl_init - Register the NetLabel management component 850d15c345fSPaul Moore * 851d15c345fSPaul Moore * Description: 852d15c345fSPaul Moore * Register the NetLabel management component with the Generic NETLINK 853d15c345fSPaul Moore * mechanism. Returns zero on success, negative values on failure. 854d15c345fSPaul Moore * 855d15c345fSPaul Moore */ 85605705e4eSPavel Emelyanov int __init netlbl_mgmt_genl_init(void) 857d15c345fSPaul Moore { 858489111e5SJohannes Berg return genl_register_family(&netlbl_mgmt_gnl_family); 859d15c345fSPaul Moore } 860