xref: /openbmc/linux/net/netlabel/netlabel_mgmt.c (revision ef6243ac)
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