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