xref: /openbmc/linux/net/netlabel/netlabel_mgmt.c (revision 1ccea77e)
11ccea77eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2d15c345fSPaul Moore /*
3d15c345fSPaul Moore  * NetLabel Management Support
4d15c345fSPaul Moore  *
5d15c345fSPaul Moore  * This file defines the management functions for the NetLabel system.  The
6d15c345fSPaul Moore  * NetLabel system manages static and dynamic label mappings for network
7d15c345fSPaul Moore  * protocols such as CIPSO and RIPSO.
8d15c345fSPaul Moore  *
982c21bfaSPaul Moore  * Author: Paul Moore <paul@paul-moore.com>
10d15c345fSPaul Moore  */
11d15c345fSPaul Moore 
12d15c345fSPaul Moore /*
1363c41688SPaul Moore  * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
14d15c345fSPaul Moore  */
15d15c345fSPaul Moore 
16d15c345fSPaul Moore #include <linux/types.h>
17d15c345fSPaul Moore #include <linux/socket.h>
18d15c345fSPaul Moore #include <linux/string.h>
19d15c345fSPaul Moore #include <linux/skbuff.h>
2063c41688SPaul Moore #include <linux/in.h>
2163c41688SPaul Moore #include <linux/in6.h>
225a0e3ad6STejun Heo #include <linux/slab.h>
23d15c345fSPaul Moore #include <net/sock.h>
24d15c345fSPaul Moore #include <net/netlink.h>
25d15c345fSPaul Moore #include <net/genetlink.h>
2663c41688SPaul Moore #include <net/ip.h>
2763c41688SPaul Moore #include <net/ipv6.h>
28d15c345fSPaul Moore #include <net/netlabel.h>
29d15c345fSPaul Moore #include <net/cipso_ipv4.h>
30dc7de73fSHuw Davies #include <net/calipso.h>
3160063497SArun Sharma #include <linux/atomic.h>
32d15c345fSPaul Moore 
33dc7de73fSHuw Davies #include "netlabel_calipso.h"
34d15c345fSPaul Moore #include "netlabel_domainhash.h"
35d15c345fSPaul Moore #include "netlabel_user.h"
36d15c345fSPaul Moore #include "netlabel_mgmt.h"
37d15c345fSPaul Moore 
38c783f1ceSPaul Moore /* NetLabel configured protocol counter */
39c783f1ceSPaul Moore atomic_t netlabel_mgmt_protocount = ATOMIC_INIT(0);
4023bcdc1aSPaul Moore 
41fd385855SPaul Moore /* Argument struct for netlbl_domhsh_walk() */
42fd385855SPaul Moore struct netlbl_domhsh_walk_arg {
43fd385855SPaul Moore 	struct netlink_callback *nl_cb;
44fd385855SPaul Moore 	struct sk_buff *skb;
45fd385855SPaul Moore 	u32 seq;
46fd385855SPaul Moore };
47fd385855SPaul Moore 
48d15c345fSPaul Moore /* NetLabel Generic NETLINK CIPSOv4 family */
49489111e5SJohannes Berg static struct genl_family netlbl_mgmt_gnl_family;
50d15c345fSPaul Moore 
51fd385855SPaul Moore /* NetLabel Netlink attribute policy */
52ef7c79edSPatrick McHardy static const struct nla_policy netlbl_mgmt_genl_policy[NLBL_MGMT_A_MAX + 1] = {
53fd385855SPaul Moore 	[NLBL_MGMT_A_DOMAIN] = { .type = NLA_NUL_STRING },
54fd385855SPaul Moore 	[NLBL_MGMT_A_PROTOCOL] = { .type = NLA_U32 },
55fd385855SPaul Moore 	[NLBL_MGMT_A_VERSION] = { .type = NLA_U32 },
56fd385855SPaul Moore 	[NLBL_MGMT_A_CV4DOI] = { .type = NLA_U32 },
578f18e675SHuw Davies 	[NLBL_MGMT_A_FAMILY] = { .type = NLA_U16 },
58dc7de73fSHuw Davies 	[NLBL_MGMT_A_CLPDOI] = { .type = NLA_U32 },
59fd385855SPaul Moore };
60d15c345fSPaul Moore 
61d15c345fSPaul Moore /*
6263c41688SPaul Moore  * Helper Functions
6363c41688SPaul Moore  */
6463c41688SPaul Moore 
6563c41688SPaul Moore /**
6663c41688SPaul Moore  * netlbl_mgmt_add - Handle an ADD message
6763c41688SPaul Moore  * @info: the Generic NETLINK info block
6863c41688SPaul Moore  * @audit_info: NetLabel audit information
6963c41688SPaul Moore  *
7063c41688SPaul Moore  * Description:
7163c41688SPaul Moore  * Helper function for the ADD and ADDDEF messages to add the domain mappings
7263c41688SPaul Moore  * from the message to the hash table.  See netlabel.h for a description of the
7363c41688SPaul Moore  * message format.  Returns zero on success, negative values on failure.
7463c41688SPaul Moore  *
7563c41688SPaul Moore  */
7663c41688SPaul Moore static int netlbl_mgmt_add_common(struct genl_info *info,
7763c41688SPaul Moore 				  struct netlbl_audit *audit_info)
7863c41688SPaul Moore {
7963c41688SPaul Moore 	int ret_val = -EINVAL;
8063c41688SPaul Moore 	struct netlbl_domaddr_map *addrmap = NULL;
8163c41688SPaul Moore 	struct cipso_v4_doi *cipsov4 = NULL;
82dc7de73fSHuw Davies #if IS_ENABLED(CONFIG_IPV6)
83dc7de73fSHuw Davies 	struct calipso_doi *calipso = NULL;
84dc7de73fSHuw Davies #endif
8563c41688SPaul Moore 	u32 tmp_val;
864de46d5eSMarkus Elfring 	struct netlbl_dom_map *entry = kzalloc(sizeof(*entry), GFP_KERNEL);
8763c41688SPaul Moore 
884de46d5eSMarkus Elfring 	if (!entry)
894de46d5eSMarkus Elfring 		return -ENOMEM;
906a8b7f0cSPaul Moore 	entry->def.type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]);
9163c41688SPaul Moore 	if (info->attrs[NLBL_MGMT_A_DOMAIN]) {
9263c41688SPaul Moore 		size_t tmp_size = nla_len(info->attrs[NLBL_MGMT_A_DOMAIN]);
9363c41688SPaul Moore 		entry->domain = kmalloc(tmp_size, GFP_KERNEL);
9463c41688SPaul Moore 		if (entry->domain == NULL) {
9563c41688SPaul Moore 			ret_val = -ENOMEM;
964de46d5eSMarkus Elfring 			goto add_free_entry;
9763c41688SPaul Moore 		}
9863c41688SPaul Moore 		nla_strlcpy(entry->domain,
9963c41688SPaul Moore 			    info->attrs[NLBL_MGMT_A_DOMAIN], tmp_size);
10063c41688SPaul Moore 	}
10163c41688SPaul Moore 
1026a8b7f0cSPaul Moore 	/* NOTE: internally we allow/use a entry->def.type value of
10363c41688SPaul Moore 	 *       NETLBL_NLTYPE_ADDRSELECT but we don't currently allow users
10463c41688SPaul Moore 	 *       to pass that as a protocol value because we need to know the
10563c41688SPaul Moore 	 *       "real" protocol */
10663c41688SPaul Moore 
1076a8b7f0cSPaul Moore 	switch (entry->def.type) {
10863c41688SPaul Moore 	case NETLBL_NLTYPE_UNLABELED:
1098f18e675SHuw Davies 		if (info->attrs[NLBL_MGMT_A_FAMILY])
1108f18e675SHuw Davies 			entry->family =
1118f18e675SHuw Davies 				nla_get_u16(info->attrs[NLBL_MGMT_A_FAMILY]);
1128f18e675SHuw Davies 		else
1138f18e675SHuw Davies 			entry->family = AF_UNSPEC;
11463c41688SPaul Moore 		break;
11563c41688SPaul Moore 	case NETLBL_NLTYPE_CIPSOV4:
11663c41688SPaul Moore 		if (!info->attrs[NLBL_MGMT_A_CV4DOI])
1174de46d5eSMarkus Elfring 			goto add_free_domain;
11863c41688SPaul Moore 
11963c41688SPaul Moore 		tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]);
12063c41688SPaul Moore 		cipsov4 = cipso_v4_doi_getdef(tmp_val);
12163c41688SPaul Moore 		if (cipsov4 == NULL)
1224de46d5eSMarkus Elfring 			goto add_free_domain;
1238f18e675SHuw Davies 		entry->family = AF_INET;
1246a8b7f0cSPaul Moore 		entry->def.cipso = cipsov4;
12563c41688SPaul Moore 		break;
126dc7de73fSHuw Davies #if IS_ENABLED(CONFIG_IPV6)
127dc7de73fSHuw Davies 	case NETLBL_NLTYPE_CALIPSO:
128dc7de73fSHuw Davies 		if (!info->attrs[NLBL_MGMT_A_CLPDOI])
129dc7de73fSHuw Davies 			goto add_free_domain;
130dc7de73fSHuw Davies 
131dc7de73fSHuw Davies 		tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CLPDOI]);
132dc7de73fSHuw Davies 		calipso = calipso_doi_getdef(tmp_val);
133dc7de73fSHuw Davies 		if (calipso == NULL)
134dc7de73fSHuw Davies 			goto add_free_domain;
135dc7de73fSHuw Davies 		entry->family = AF_INET6;
136dc7de73fSHuw Davies 		entry->def.calipso = calipso;
137dc7de73fSHuw Davies 		break;
138dc7de73fSHuw Davies #endif /* IPv6 */
13963c41688SPaul Moore 	default:
1404de46d5eSMarkus Elfring 		goto add_free_domain;
14163c41688SPaul Moore 	}
14263c41688SPaul Moore 
1438f18e675SHuw Davies 	if ((entry->family == AF_INET && info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
1448f18e675SHuw Davies 	    (entry->family == AF_INET6 && info->attrs[NLBL_MGMT_A_IPV4ADDR]))
1458f18e675SHuw Davies 		goto add_doi_put_def;
1468f18e675SHuw Davies 
14763c41688SPaul Moore 	if (info->attrs[NLBL_MGMT_A_IPV4ADDR]) {
14863c41688SPaul Moore 		struct in_addr *addr;
14963c41688SPaul Moore 		struct in_addr *mask;
15063c41688SPaul Moore 		struct netlbl_domaddr4_map *map;
15163c41688SPaul Moore 
15263c41688SPaul Moore 		addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL);
15363c41688SPaul Moore 		if (addrmap == NULL) {
15463c41688SPaul Moore 			ret_val = -ENOMEM;
1554de46d5eSMarkus Elfring 			goto add_doi_put_def;
15663c41688SPaul Moore 		}
15763c41688SPaul Moore 		INIT_LIST_HEAD(&addrmap->list4);
15863c41688SPaul Moore 		INIT_LIST_HEAD(&addrmap->list6);
15963c41688SPaul Moore 
16063c41688SPaul Moore 		if (nla_len(info->attrs[NLBL_MGMT_A_IPV4ADDR]) !=
16163c41688SPaul Moore 		    sizeof(struct in_addr)) {
16263c41688SPaul Moore 			ret_val = -EINVAL;
1634de46d5eSMarkus Elfring 			goto add_free_addrmap;
16463c41688SPaul Moore 		}
16563c41688SPaul Moore 		if (nla_len(info->attrs[NLBL_MGMT_A_IPV4MASK]) !=
16663c41688SPaul Moore 		    sizeof(struct in_addr)) {
16763c41688SPaul Moore 			ret_val = -EINVAL;
1684de46d5eSMarkus Elfring 			goto add_free_addrmap;
16963c41688SPaul Moore 		}
17063c41688SPaul Moore 		addr = nla_data(info->attrs[NLBL_MGMT_A_IPV4ADDR]);
17163c41688SPaul Moore 		mask = nla_data(info->attrs[NLBL_MGMT_A_IPV4MASK]);
17263c41688SPaul Moore 
17363c41688SPaul Moore 		map = kzalloc(sizeof(*map), GFP_KERNEL);
17463c41688SPaul Moore 		if (map == NULL) {
17563c41688SPaul Moore 			ret_val = -ENOMEM;
1764de46d5eSMarkus Elfring 			goto add_free_addrmap;
17763c41688SPaul Moore 		}
17863c41688SPaul Moore 		map->list.addr = addr->s_addr & mask->s_addr;
17963c41688SPaul Moore 		map->list.mask = mask->s_addr;
18063c41688SPaul Moore 		map->list.valid = 1;
1816a8b7f0cSPaul Moore 		map->def.type = entry->def.type;
18263c41688SPaul Moore 		if (cipsov4)
1836a8b7f0cSPaul Moore 			map->def.cipso = cipsov4;
18463c41688SPaul Moore 
18563c41688SPaul Moore 		ret_val = netlbl_af4list_add(&map->list, &addrmap->list4);
18663c41688SPaul Moore 		if (ret_val != 0) {
18763c41688SPaul Moore 			kfree(map);
1884de46d5eSMarkus Elfring 			goto add_free_addrmap;
18963c41688SPaul Moore 		}
19063c41688SPaul Moore 
1918f18e675SHuw Davies 		entry->family = AF_INET;
1926a8b7f0cSPaul Moore 		entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
1936a8b7f0cSPaul Moore 		entry->def.addrsel = addrmap;
194dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6)
19563c41688SPaul Moore 	} else if (info->attrs[NLBL_MGMT_A_IPV6ADDR]) {
19663c41688SPaul Moore 		struct in6_addr *addr;
19763c41688SPaul Moore 		struct in6_addr *mask;
19863c41688SPaul Moore 		struct netlbl_domaddr6_map *map;
19963c41688SPaul Moore 
20063c41688SPaul Moore 		addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL);
20163c41688SPaul Moore 		if (addrmap == NULL) {
20263c41688SPaul Moore 			ret_val = -ENOMEM;
2034de46d5eSMarkus Elfring 			goto add_doi_put_def;
20463c41688SPaul Moore 		}
20563c41688SPaul Moore 		INIT_LIST_HEAD(&addrmap->list4);
20663c41688SPaul Moore 		INIT_LIST_HEAD(&addrmap->list6);
20763c41688SPaul Moore 
20863c41688SPaul Moore 		if (nla_len(info->attrs[NLBL_MGMT_A_IPV6ADDR]) !=
20963c41688SPaul Moore 		    sizeof(struct in6_addr)) {
21063c41688SPaul Moore 			ret_val = -EINVAL;
2114de46d5eSMarkus Elfring 			goto add_free_addrmap;
21263c41688SPaul Moore 		}
21363c41688SPaul Moore 		if (nla_len(info->attrs[NLBL_MGMT_A_IPV6MASK]) !=
21463c41688SPaul Moore 		    sizeof(struct in6_addr)) {
21563c41688SPaul Moore 			ret_val = -EINVAL;
2164de46d5eSMarkus Elfring 			goto add_free_addrmap;
21763c41688SPaul Moore 		}
21863c41688SPaul Moore 		addr = nla_data(info->attrs[NLBL_MGMT_A_IPV6ADDR]);
21963c41688SPaul Moore 		mask = nla_data(info->attrs[NLBL_MGMT_A_IPV6MASK]);
22063c41688SPaul Moore 
22163c41688SPaul Moore 		map = kzalloc(sizeof(*map), GFP_KERNEL);
22263c41688SPaul Moore 		if (map == NULL) {
22363c41688SPaul Moore 			ret_val = -ENOMEM;
2244de46d5eSMarkus Elfring 			goto add_free_addrmap;
22563c41688SPaul Moore 		}
2264e3fd7a0SAlexey Dobriyan 		map->list.addr = *addr;
22763c41688SPaul Moore 		map->list.addr.s6_addr32[0] &= mask->s6_addr32[0];
22863c41688SPaul Moore 		map->list.addr.s6_addr32[1] &= mask->s6_addr32[1];
22963c41688SPaul Moore 		map->list.addr.s6_addr32[2] &= mask->s6_addr32[2];
23063c41688SPaul Moore 		map->list.addr.s6_addr32[3] &= mask->s6_addr32[3];
2314e3fd7a0SAlexey Dobriyan 		map->list.mask = *mask;
23263c41688SPaul Moore 		map->list.valid = 1;
2336a8b7f0cSPaul Moore 		map->def.type = entry->def.type;
234dc7de73fSHuw Davies 		if (calipso)
235dc7de73fSHuw Davies 			map->def.calipso = calipso;
23663c41688SPaul Moore 
23763c41688SPaul Moore 		ret_val = netlbl_af6list_add(&map->list, &addrmap->list6);
23863c41688SPaul Moore 		if (ret_val != 0) {
23963c41688SPaul Moore 			kfree(map);
2404de46d5eSMarkus Elfring 			goto add_free_addrmap;
24163c41688SPaul Moore 		}
24263c41688SPaul Moore 
2438f18e675SHuw Davies 		entry->family = AF_INET6;
2446a8b7f0cSPaul Moore 		entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
2456a8b7f0cSPaul Moore 		entry->def.addrsel = addrmap;
24663c41688SPaul Moore #endif /* IPv6 */
24763c41688SPaul Moore 	}
24863c41688SPaul Moore 
24963c41688SPaul Moore 	ret_val = netlbl_domhsh_add(entry, audit_info);
25063c41688SPaul Moore 	if (ret_val != 0)
2514de46d5eSMarkus Elfring 		goto add_free_addrmap;
25263c41688SPaul Moore 
25363c41688SPaul Moore 	return 0;
25463c41688SPaul Moore 
2554de46d5eSMarkus Elfring add_free_addrmap:
25663c41688SPaul Moore 	kfree(addrmap);
2574de46d5eSMarkus Elfring add_doi_put_def:
2584de46d5eSMarkus Elfring 	cipso_v4_doi_putdef(cipsov4);
259dc7de73fSHuw Davies #if IS_ENABLED(CONFIG_IPV6)
260dc7de73fSHuw Davies 	calipso_doi_putdef(calipso);
261dc7de73fSHuw Davies #endif
2624de46d5eSMarkus Elfring add_free_domain:
2634de46d5eSMarkus Elfring 	kfree(entry->domain);
2644de46d5eSMarkus Elfring add_free_entry:
26563c41688SPaul Moore 	kfree(entry);
26663c41688SPaul Moore 	return ret_val;
26763c41688SPaul Moore }
26863c41688SPaul Moore 
26963c41688SPaul Moore /**
27063c41688SPaul Moore  * netlbl_mgmt_listentry - List a NetLabel/LSM domain map entry
27163c41688SPaul Moore  * @skb: the NETLINK buffer
27263c41688SPaul Moore  * @entry: the map entry
27363c41688SPaul Moore  *
27463c41688SPaul Moore  * Description:
27563c41688SPaul Moore  * This function is a helper function used by the LISTALL and LISTDEF command
27625985edcSLucas De Marchi  * handlers.  The caller is responsible for ensuring that the RCU read lock
27763c41688SPaul Moore  * is held.  Returns zero on success, negative values on failure.
27863c41688SPaul Moore  *
27963c41688SPaul Moore  */
28063c41688SPaul Moore static int netlbl_mgmt_listentry(struct sk_buff *skb,
28163c41688SPaul Moore 				 struct netlbl_dom_map *entry)
28263c41688SPaul Moore {
283f8a02479SPaul Moore 	int ret_val = 0;
28463c41688SPaul Moore 	struct nlattr *nla_a;
28563c41688SPaul Moore 	struct nlattr *nla_b;
28663c41688SPaul Moore 	struct netlbl_af4list *iter4;
287dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6)
28863c41688SPaul Moore 	struct netlbl_af6list *iter6;
28963c41688SPaul Moore #endif
29063c41688SPaul Moore 
29163c41688SPaul Moore 	if (entry->domain != NULL) {
29263c41688SPaul Moore 		ret_val = nla_put_string(skb,
29363c41688SPaul Moore 					 NLBL_MGMT_A_DOMAIN, entry->domain);
29463c41688SPaul Moore 		if (ret_val != 0)
29563c41688SPaul Moore 			return ret_val;
29663c41688SPaul Moore 	}
29763c41688SPaul Moore 
2988f18e675SHuw Davies 	ret_val = nla_put_u16(skb, NLBL_MGMT_A_FAMILY, entry->family);
2998f18e675SHuw Davies 	if (ret_val != 0)
3008f18e675SHuw Davies 		return ret_val;
3018f18e675SHuw Davies 
3026a8b7f0cSPaul Moore 	switch (entry->def.type) {
30363c41688SPaul Moore 	case NETLBL_NLTYPE_ADDRSELECT:
304ae0be8deSMichal Kubecek 		nla_a = nla_nest_start_noflag(skb, NLBL_MGMT_A_SELECTORLIST);
30563c41688SPaul Moore 		if (nla_a == NULL)
30663c41688SPaul Moore 			return -ENOMEM;
30763c41688SPaul Moore 
3086a8b7f0cSPaul Moore 		netlbl_af4list_foreach_rcu(iter4, &entry->def.addrsel->list4) {
30963c41688SPaul Moore 			struct netlbl_domaddr4_map *map4;
31063c41688SPaul Moore 			struct in_addr addr_struct;
31163c41688SPaul Moore 
312ae0be8deSMichal Kubecek 			nla_b = nla_nest_start_noflag(skb,
313ae0be8deSMichal Kubecek 						      NLBL_MGMT_A_ADDRSELECTOR);
31463c41688SPaul Moore 			if (nla_b == NULL)
31563c41688SPaul Moore 				return -ENOMEM;
31663c41688SPaul Moore 
31763c41688SPaul Moore 			addr_struct.s_addr = iter4->addr;
318930345eaSJiri Benc 			ret_val = nla_put_in_addr(skb, NLBL_MGMT_A_IPV4ADDR,
319930345eaSJiri Benc 						  addr_struct.s_addr);
32063c41688SPaul Moore 			if (ret_val != 0)
32163c41688SPaul Moore 				return ret_val;
32263c41688SPaul Moore 			addr_struct.s_addr = iter4->mask;
323930345eaSJiri Benc 			ret_val = nla_put_in_addr(skb, NLBL_MGMT_A_IPV4MASK,
324930345eaSJiri Benc 						  addr_struct.s_addr);
32563c41688SPaul Moore 			if (ret_val != 0)
32663c41688SPaul Moore 				return ret_val;
32763c41688SPaul Moore 			map4 = netlbl_domhsh_addr4_entry(iter4);
32863c41688SPaul Moore 			ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
3296a8b7f0cSPaul Moore 					      map4->def.type);
33063c41688SPaul Moore 			if (ret_val != 0)
33163c41688SPaul Moore 				return ret_val;
3326a8b7f0cSPaul Moore 			switch (map4->def.type) {
33363c41688SPaul Moore 			case NETLBL_NLTYPE_CIPSOV4:
33463c41688SPaul Moore 				ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI,
3356a8b7f0cSPaul Moore 						      map4->def.cipso->doi);
33663c41688SPaul Moore 				if (ret_val != 0)
33763c41688SPaul Moore 					return ret_val;
33863c41688SPaul Moore 				break;
33963c41688SPaul Moore 			}
34063c41688SPaul Moore 
34163c41688SPaul Moore 			nla_nest_end(skb, nla_b);
34263c41688SPaul Moore 		}
343dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6)
3446a8b7f0cSPaul Moore 		netlbl_af6list_foreach_rcu(iter6, &entry->def.addrsel->list6) {
34563c41688SPaul Moore 			struct netlbl_domaddr6_map *map6;
34663c41688SPaul Moore 
347ae0be8deSMichal Kubecek 			nla_b = nla_nest_start_noflag(skb,
348ae0be8deSMichal Kubecek 						      NLBL_MGMT_A_ADDRSELECTOR);
34963c41688SPaul Moore 			if (nla_b == NULL)
35063c41688SPaul Moore 				return -ENOMEM;
35163c41688SPaul Moore 
352930345eaSJiri Benc 			ret_val = nla_put_in6_addr(skb, NLBL_MGMT_A_IPV6ADDR,
35363c41688SPaul Moore 						   &iter6->addr);
35463c41688SPaul Moore 			if (ret_val != 0)
35563c41688SPaul Moore 				return ret_val;
356930345eaSJiri Benc 			ret_val = nla_put_in6_addr(skb, NLBL_MGMT_A_IPV6MASK,
35763c41688SPaul Moore 						   &iter6->mask);
35863c41688SPaul Moore 			if (ret_val != 0)
35963c41688SPaul Moore 				return ret_val;
36063c41688SPaul Moore 			map6 = netlbl_domhsh_addr6_entry(iter6);
36163c41688SPaul Moore 			ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
3626a8b7f0cSPaul Moore 					      map6->def.type);
36363c41688SPaul Moore 			if (ret_val != 0)
36463c41688SPaul Moore 				return ret_val;
36563c41688SPaul Moore 
366dc7de73fSHuw Davies 			switch (map6->def.type) {
367dc7de73fSHuw Davies 			case NETLBL_NLTYPE_CALIPSO:
368dc7de73fSHuw Davies 				ret_val = nla_put_u32(skb, NLBL_MGMT_A_CLPDOI,
369dc7de73fSHuw Davies 						      map6->def.calipso->doi);
370dc7de73fSHuw Davies 				if (ret_val != 0)
371dc7de73fSHuw Davies 					return ret_val;
372dc7de73fSHuw Davies 				break;
373dc7de73fSHuw Davies 			}
374dc7de73fSHuw Davies 
37563c41688SPaul Moore 			nla_nest_end(skb, nla_b);
37663c41688SPaul Moore 		}
37763c41688SPaul Moore #endif /* IPv6 */
37863c41688SPaul Moore 
37963c41688SPaul Moore 		nla_nest_end(skb, nla_a);
38063c41688SPaul Moore 		break;
38163c41688SPaul Moore 	case NETLBL_NLTYPE_UNLABELED:
382dc7de73fSHuw Davies 		ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
383dc7de73fSHuw Davies 				      entry->def.type);
38463c41688SPaul Moore 		break;
38563c41688SPaul Moore 	case NETLBL_NLTYPE_CIPSOV4:
386dc7de73fSHuw Davies 		ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
387dc7de73fSHuw Davies 				      entry->def.type);
38863c41688SPaul Moore 		if (ret_val != 0)
38963c41688SPaul Moore 			return ret_val;
39063c41688SPaul Moore 		ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI,
3916a8b7f0cSPaul Moore 				      entry->def.cipso->doi);
39263c41688SPaul Moore 		break;
393dc7de73fSHuw Davies 	case NETLBL_NLTYPE_CALIPSO:
394dc7de73fSHuw Davies 		ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
395dc7de73fSHuw Davies 				      entry->def.type);
396dc7de73fSHuw Davies 		if (ret_val != 0)
397dc7de73fSHuw Davies 			return ret_val;
398dc7de73fSHuw Davies 		ret_val = nla_put_u32(skb, NLBL_MGMT_A_CLPDOI,
399dc7de73fSHuw Davies 				      entry->def.calipso->doi);
400dc7de73fSHuw Davies 		break;
40163c41688SPaul Moore 	}
40263c41688SPaul Moore 
40363c41688SPaul Moore 	return ret_val;
40463c41688SPaul Moore }
40563c41688SPaul Moore 
40663c41688SPaul Moore /*
407d15c345fSPaul Moore  * NetLabel Command Handlers
408d15c345fSPaul Moore  */
409d15c345fSPaul Moore 
410d15c345fSPaul Moore /**
411d15c345fSPaul Moore  * netlbl_mgmt_add - Handle an ADD message
412d15c345fSPaul Moore  * @skb: the NETLINK buffer
413d15c345fSPaul Moore  * @info: the Generic NETLINK info block
414d15c345fSPaul Moore  *
415d15c345fSPaul Moore  * Description:
416d15c345fSPaul Moore  * Process a user generated ADD message and add the domains from the message
417d15c345fSPaul Moore  * to the hash table.  See netlabel.h for a description of the message format.
418d15c345fSPaul Moore  * Returns zero on success, negative values on failure.
419d15c345fSPaul Moore  *
420d15c345fSPaul Moore  */
421d15c345fSPaul Moore static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info)
422d15c345fSPaul Moore {
42395d4e6beSPaul Moore 	struct netlbl_audit audit_info;
424d15c345fSPaul Moore 
42563c41688SPaul Moore 	if ((!info->attrs[NLBL_MGMT_A_DOMAIN]) ||
42663c41688SPaul Moore 	    (!info->attrs[NLBL_MGMT_A_PROTOCOL]) ||
42763c41688SPaul Moore 	    (info->attrs[NLBL_MGMT_A_IPV4ADDR] &&
42863c41688SPaul Moore 	     info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
42963c41688SPaul Moore 	    (info->attrs[NLBL_MGMT_A_IPV4MASK] &&
43063c41688SPaul Moore 	     info->attrs[NLBL_MGMT_A_IPV6MASK]) ||
43163c41688SPaul Moore 	    ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^
43263c41688SPaul Moore 	     (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) ||
43363c41688SPaul Moore 	    ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^
43463c41688SPaul Moore 	     (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL)))
43563c41688SPaul Moore 		return -EINVAL;
436d15c345fSPaul Moore 
43795d4e6beSPaul Moore 	netlbl_netlink_auditinfo(skb, &audit_info);
43895d4e6beSPaul Moore 
43963c41688SPaul Moore 	return netlbl_mgmt_add_common(info, &audit_info);
440d15c345fSPaul Moore }
441d15c345fSPaul Moore 
442d15c345fSPaul Moore /**
443d15c345fSPaul Moore  * netlbl_mgmt_remove - Handle a REMOVE message
444d15c345fSPaul Moore  * @skb: the NETLINK buffer
445d15c345fSPaul Moore  * @info: the Generic NETLINK info block
446d15c345fSPaul Moore  *
447d15c345fSPaul Moore  * Description:
448d15c345fSPaul Moore  * Process a user generated REMOVE message and remove the specified domain
449d15c345fSPaul Moore  * mappings.  Returns zero on success, negative values on failure.
450d15c345fSPaul Moore  *
451d15c345fSPaul Moore  */
452d15c345fSPaul Moore static int netlbl_mgmt_remove(struct sk_buff *skb, struct genl_info *info)
453d15c345fSPaul Moore {
454fd385855SPaul Moore 	char *domain;
45595d4e6beSPaul Moore 	struct netlbl_audit audit_info;
456d15c345fSPaul Moore 
457fd385855SPaul Moore 	if (!info->attrs[NLBL_MGMT_A_DOMAIN])
458fd385855SPaul Moore 		return -EINVAL;
459d15c345fSPaul Moore 
46095d4e6beSPaul Moore 	netlbl_netlink_auditinfo(skb, &audit_info);
46195d4e6beSPaul Moore 
462fd385855SPaul Moore 	domain = nla_data(info->attrs[NLBL_MGMT_A_DOMAIN]);
4638f18e675SHuw Davies 	return netlbl_domhsh_remove(domain, AF_UNSPEC, &audit_info);
464d15c345fSPaul Moore }
465d15c345fSPaul Moore 
466fd385855SPaul Moore /**
467fd385855SPaul Moore  * netlbl_mgmt_listall_cb - netlbl_domhsh_walk() callback for LISTALL
468fd385855SPaul Moore  * @entry: the domain mapping hash table entry
469fd385855SPaul Moore  * @arg: the netlbl_domhsh_walk_arg structure
470fd385855SPaul Moore  *
471fd385855SPaul Moore  * Description:
472fd385855SPaul Moore  * This function is designed to be used as a callback to the
473fd385855SPaul Moore  * netlbl_domhsh_walk() function for use in generating a response for a LISTALL
474fd385855SPaul Moore  * message.  Returns the size of the message on success, negative values on
475fd385855SPaul Moore  * failure.
476fd385855SPaul Moore  *
477fd385855SPaul Moore  */
478fd385855SPaul Moore static int netlbl_mgmt_listall_cb(struct netlbl_dom_map *entry, void *arg)
479fd385855SPaul Moore {
480fd385855SPaul Moore 	int ret_val = -ENOMEM;
481fd385855SPaul Moore 	struct netlbl_domhsh_walk_arg *cb_arg = arg;
482fd385855SPaul Moore 	void *data;
483d15c345fSPaul Moore 
48415e47304SEric W. Biederman 	data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).portid,
48517c157c8SThomas Graf 			   cb_arg->seq, &netlbl_mgmt_gnl_family,
48617c157c8SThomas Graf 			   NLM_F_MULTI, NLBL_MGMT_C_LISTALL);
487fd385855SPaul Moore 	if (data == NULL)
488fd385855SPaul Moore 		goto listall_cb_failure;
489fd385855SPaul Moore 
49063c41688SPaul Moore 	ret_val = netlbl_mgmt_listentry(cb_arg->skb, entry);
491fd385855SPaul Moore 	if (ret_val != 0)
492fd385855SPaul Moore 		goto listall_cb_failure;
493fd385855SPaul Moore 
494fd385855SPaul Moore 	cb_arg->seq++;
495053c095aSJohannes Berg 	genlmsg_end(cb_arg->skb, data);
496053c095aSJohannes Berg 	return 0;
497fd385855SPaul Moore 
498fd385855SPaul Moore listall_cb_failure:
499fd385855SPaul Moore 	genlmsg_cancel(cb_arg->skb, data);
500d15c345fSPaul Moore 	return ret_val;
501d15c345fSPaul Moore }
502d15c345fSPaul Moore 
503d15c345fSPaul Moore /**
504fd385855SPaul Moore  * netlbl_mgmt_listall - Handle a LISTALL message
505d15c345fSPaul Moore  * @skb: the NETLINK buffer
506fd385855SPaul Moore  * @cb: the NETLINK callback
507d15c345fSPaul Moore  *
508d15c345fSPaul Moore  * Description:
509fd385855SPaul Moore  * Process a user generated LISTALL message and dumps the domain hash table in
510fd385855SPaul Moore  * a form suitable for use in a kernel generated LISTALL message.  Returns zero
511fd385855SPaul Moore  * on success, negative values on failure.
512d15c345fSPaul Moore  *
513d15c345fSPaul Moore  */
514fd385855SPaul Moore static int netlbl_mgmt_listall(struct sk_buff *skb,
515fd385855SPaul Moore 			       struct netlink_callback *cb)
516d15c345fSPaul Moore {
517fd385855SPaul Moore 	struct netlbl_domhsh_walk_arg cb_arg;
518fd385855SPaul Moore 	u32 skip_bkt = cb->args[0];
519fd385855SPaul Moore 	u32 skip_chain = cb->args[1];
520d15c345fSPaul Moore 
521fd385855SPaul Moore 	cb_arg.nl_cb = cb;
522fd385855SPaul Moore 	cb_arg.skb = skb;
523fd385855SPaul Moore 	cb_arg.seq = cb->nlh->nlmsg_seq;
524d15c345fSPaul Moore 
525fd385855SPaul Moore 	netlbl_domhsh_walk(&skip_bkt,
526fd385855SPaul Moore 			   &skip_chain,
527fd385855SPaul Moore 			   netlbl_mgmt_listall_cb,
528fd385855SPaul Moore 			   &cb_arg);
529d15c345fSPaul Moore 
530fd385855SPaul Moore 	cb->args[0] = skip_bkt;
531fd385855SPaul Moore 	cb->args[1] = skip_chain;
532fd385855SPaul Moore 	return skb->len;
533d15c345fSPaul Moore }
534d15c345fSPaul Moore 
535d15c345fSPaul Moore /**
536d15c345fSPaul Moore  * netlbl_mgmt_adddef - Handle an ADDDEF message
537d15c345fSPaul Moore  * @skb: the NETLINK buffer
538d15c345fSPaul Moore  * @info: the Generic NETLINK info block
539d15c345fSPaul Moore  *
540d15c345fSPaul Moore  * Description:
541d15c345fSPaul Moore  * Process a user generated ADDDEF message and respond accordingly.  Returns
542d15c345fSPaul Moore  * zero on success, negative values on failure.
543d15c345fSPaul Moore  *
544d15c345fSPaul Moore  */
545d15c345fSPaul Moore static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info)
546d15c345fSPaul Moore {
54795d4e6beSPaul Moore 	struct netlbl_audit audit_info;
548d15c345fSPaul Moore 
54963c41688SPaul Moore 	if ((!info->attrs[NLBL_MGMT_A_PROTOCOL]) ||
55063c41688SPaul Moore 	    (info->attrs[NLBL_MGMT_A_IPV4ADDR] &&
55163c41688SPaul Moore 	     info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
55263c41688SPaul Moore 	    (info->attrs[NLBL_MGMT_A_IPV4MASK] &&
55363c41688SPaul Moore 	     info->attrs[NLBL_MGMT_A_IPV6MASK]) ||
55463c41688SPaul Moore 	    ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^
55563c41688SPaul Moore 	     (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) ||
55663c41688SPaul Moore 	    ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^
55763c41688SPaul Moore 	     (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL)))
55863c41688SPaul Moore 		return -EINVAL;
559d15c345fSPaul Moore 
56095d4e6beSPaul Moore 	netlbl_netlink_auditinfo(skb, &audit_info);
56195d4e6beSPaul Moore 
56263c41688SPaul Moore 	return netlbl_mgmt_add_common(info, &audit_info);
563d15c345fSPaul Moore }
564d15c345fSPaul Moore 
565d15c345fSPaul Moore /**
566d15c345fSPaul Moore  * netlbl_mgmt_removedef - Handle a REMOVEDEF message
567d15c345fSPaul Moore  * @skb: the NETLINK buffer
568d15c345fSPaul Moore  * @info: the Generic NETLINK info block
569d15c345fSPaul Moore  *
570d15c345fSPaul Moore  * Description:
571d15c345fSPaul Moore  * Process a user generated REMOVEDEF message and remove the default domain
572d15c345fSPaul Moore  * mapping.  Returns zero on success, negative values on failure.
573d15c345fSPaul Moore  *
574d15c345fSPaul Moore  */
575d15c345fSPaul Moore static int netlbl_mgmt_removedef(struct sk_buff *skb, struct genl_info *info)
576d15c345fSPaul Moore {
57795d4e6beSPaul Moore 	struct netlbl_audit audit_info;
57895d4e6beSPaul Moore 
57995d4e6beSPaul Moore 	netlbl_netlink_auditinfo(skb, &audit_info);
58095d4e6beSPaul Moore 
5818f18e675SHuw Davies 	return netlbl_domhsh_remove_default(AF_UNSPEC, &audit_info);
582d15c345fSPaul Moore }
583d15c345fSPaul Moore 
584d15c345fSPaul Moore /**
585d15c345fSPaul Moore  * netlbl_mgmt_listdef - Handle a LISTDEF message
586d15c345fSPaul Moore  * @skb: the NETLINK buffer
587d15c345fSPaul Moore  * @info: the Generic NETLINK info block
588d15c345fSPaul Moore  *
589d15c345fSPaul Moore  * Description:
590d15c345fSPaul Moore  * Process a user generated LISTDEF message and dumps the default domain
591d15c345fSPaul Moore  * mapping in a form suitable for use in a kernel generated LISTDEF message.
592d15c345fSPaul Moore  * Returns zero on success, negative values on failure.
593d15c345fSPaul Moore  *
594d15c345fSPaul Moore  */
595d15c345fSPaul Moore static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info)
596d15c345fSPaul Moore {
597d15c345fSPaul Moore 	int ret_val = -ENOMEM;
598fd385855SPaul Moore 	struct sk_buff *ans_skb = NULL;
599fd385855SPaul Moore 	void *data;
600fd385855SPaul Moore 	struct netlbl_dom_map *entry;
6018f18e675SHuw Davies 	u16 family;
6028f18e675SHuw Davies 
6038f18e675SHuw Davies 	if (info->attrs[NLBL_MGMT_A_FAMILY])
6048f18e675SHuw Davies 		family = nla_get_u16(info->attrs[NLBL_MGMT_A_FAMILY]);
6058f18e675SHuw Davies 	else
6068f18e675SHuw Davies 		family = AF_INET;
607d15c345fSPaul Moore 
608339bf98fSThomas Graf 	ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
609d15c345fSPaul Moore 	if (ans_skb == NULL)
610fd385855SPaul Moore 		return -ENOMEM;
61117c157c8SThomas Graf 	data = genlmsg_put_reply(ans_skb, info, &netlbl_mgmt_gnl_family,
61217c157c8SThomas Graf 				 0, NLBL_MGMT_C_LISTDEF);
613fd385855SPaul Moore 	if (data == NULL)
614fd385855SPaul Moore 		goto listdef_failure;
615d15c345fSPaul Moore 
616fd385855SPaul Moore 	rcu_read_lock();
6178f18e675SHuw Davies 	entry = netlbl_domhsh_getentry(NULL, family);
618fd385855SPaul Moore 	if (entry == NULL) {
619fd385855SPaul Moore 		ret_val = -ENOENT;
620fd385855SPaul Moore 		goto listdef_failure_lock;
621fd385855SPaul Moore 	}
62263c41688SPaul Moore 	ret_val = netlbl_mgmt_listentry(ans_skb, entry);
623fd385855SPaul Moore 	rcu_read_unlock();
62463c41688SPaul Moore 	if (ret_val != 0)
62563c41688SPaul Moore 		goto listdef_failure;
626fd385855SPaul Moore 
627fd385855SPaul Moore 	genlmsg_end(ans_skb, data);
628fe785beeSDenis V. Lunev 	return genlmsg_reply(ans_skb, info);
629d15c345fSPaul Moore 
630fd385855SPaul Moore listdef_failure_lock:
631fd385855SPaul Moore 	rcu_read_unlock();
632d15c345fSPaul Moore listdef_failure:
633fd385855SPaul Moore 	kfree_skb(ans_skb);
634d15c345fSPaul Moore 	return ret_val;
635d15c345fSPaul Moore }
636d15c345fSPaul Moore 
637d15c345fSPaul Moore /**
638fd385855SPaul Moore  * netlbl_mgmt_protocols_cb - Write an individual PROTOCOL message response
639fd385855SPaul Moore  * @skb: the skb to write to
640fd385855SPaul Moore  * @cb: the NETLINK callback
641fd385855SPaul Moore  * @protocol: the NetLabel protocol to use in the message
642d15c345fSPaul Moore  *
643d15c345fSPaul Moore  * Description:
644fd385855SPaul Moore  * This function is to be used in conjunction with netlbl_mgmt_protocols() to
645fd385855SPaul Moore  * answer a application's PROTOCOLS message.  Returns the size of the message
646fd385855SPaul Moore  * on success, negative values on failure.
647d15c345fSPaul Moore  *
648d15c345fSPaul Moore  */
649fd385855SPaul Moore static int netlbl_mgmt_protocols_cb(struct sk_buff *skb,
650fd385855SPaul Moore 				    struct netlink_callback *cb,
651fd385855SPaul Moore 				    u32 protocol)
652d15c345fSPaul Moore {
653d15c345fSPaul Moore 	int ret_val = -ENOMEM;
654fd385855SPaul Moore 	void *data;
655d15c345fSPaul Moore 
65615e47304SEric W. Biederman 	data = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
65717c157c8SThomas Graf 			   &netlbl_mgmt_gnl_family, NLM_F_MULTI,
658fd385855SPaul Moore 			   NLBL_MGMT_C_PROTOCOLS);
659fd385855SPaul Moore 	if (data == NULL)
660fd385855SPaul Moore 		goto protocols_cb_failure;
661d15c345fSPaul Moore 
662fd385855SPaul Moore 	ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, protocol);
663d15c345fSPaul Moore 	if (ret_val != 0)
664fd385855SPaul Moore 		goto protocols_cb_failure;
665d15c345fSPaul Moore 
666053c095aSJohannes Berg 	genlmsg_end(skb, data);
667053c095aSJohannes Berg 	return 0;
668d15c345fSPaul Moore 
669fd385855SPaul Moore protocols_cb_failure:
670fd385855SPaul Moore 	genlmsg_cancel(skb, data);
671d15c345fSPaul Moore 	return ret_val;
672d15c345fSPaul Moore }
673d15c345fSPaul Moore 
674d15c345fSPaul Moore /**
675fd385855SPaul Moore  * netlbl_mgmt_protocols - Handle a PROTOCOLS message
676fd385855SPaul Moore  * @skb: the NETLINK buffer
677fd385855SPaul Moore  * @cb: the NETLINK callback
678fd385855SPaul Moore  *
679fd385855SPaul Moore  * Description:
680fd385855SPaul Moore  * Process a user generated PROTOCOLS message and respond accordingly.
681fd385855SPaul Moore  *
682fd385855SPaul Moore  */
683fd385855SPaul Moore static int netlbl_mgmt_protocols(struct sk_buff *skb,
684fd385855SPaul Moore 				 struct netlink_callback *cb)
685fd385855SPaul Moore {
686fd385855SPaul Moore 	u32 protos_sent = cb->args[0];
687fd385855SPaul Moore 
688fd385855SPaul Moore 	if (protos_sent == 0) {
689fd385855SPaul Moore 		if (netlbl_mgmt_protocols_cb(skb,
690fd385855SPaul Moore 					     cb,
691fd385855SPaul Moore 					     NETLBL_NLTYPE_UNLABELED) < 0)
692fd385855SPaul Moore 			goto protocols_return;
693fd385855SPaul Moore 		protos_sent++;
694fd385855SPaul Moore 	}
695fd385855SPaul Moore 	if (protos_sent == 1) {
696fd385855SPaul Moore 		if (netlbl_mgmt_protocols_cb(skb,
697fd385855SPaul Moore 					     cb,
698fd385855SPaul Moore 					     NETLBL_NLTYPE_CIPSOV4) < 0)
699fd385855SPaul Moore 			goto protocols_return;
700fd385855SPaul Moore 		protos_sent++;
701fd385855SPaul Moore 	}
702cb72d382SHuw Davies #if IS_ENABLED(CONFIG_IPV6)
703cb72d382SHuw Davies 	if (protos_sent == 2) {
704cb72d382SHuw Davies 		if (netlbl_mgmt_protocols_cb(skb,
705cb72d382SHuw Davies 					     cb,
706cb72d382SHuw Davies 					     NETLBL_NLTYPE_CALIPSO) < 0)
707cb72d382SHuw Davies 			goto protocols_return;
708cb72d382SHuw Davies 		protos_sent++;
709cb72d382SHuw Davies 	}
710cb72d382SHuw Davies #endif
711fd385855SPaul Moore 
712fd385855SPaul Moore protocols_return:
713fd385855SPaul Moore 	cb->args[0] = protos_sent;
714fd385855SPaul Moore 	return skb->len;
715fd385855SPaul Moore }
716fd385855SPaul Moore 
717fd385855SPaul Moore /**
718d15c345fSPaul Moore  * netlbl_mgmt_version - Handle a VERSION message
719d15c345fSPaul Moore  * @skb: the NETLINK buffer
720d15c345fSPaul Moore  * @info: the Generic NETLINK info block
721d15c345fSPaul Moore  *
722d15c345fSPaul Moore  * Description:
723d15c345fSPaul Moore  * Process a user generated VERSION message and respond accordingly.  Returns
724d15c345fSPaul Moore  * zero on success, negative values on failure.
725d15c345fSPaul Moore  *
726d15c345fSPaul Moore  */
727d15c345fSPaul Moore static int netlbl_mgmt_version(struct sk_buff *skb, struct genl_info *info)
728d15c345fSPaul Moore {
729d15c345fSPaul Moore 	int ret_val = -ENOMEM;
730d15c345fSPaul Moore 	struct sk_buff *ans_skb = NULL;
731fd385855SPaul Moore 	void *data;
732d15c345fSPaul Moore 
733339bf98fSThomas Graf 	ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
734d15c345fSPaul Moore 	if (ans_skb == NULL)
735fd385855SPaul Moore 		return -ENOMEM;
73617c157c8SThomas Graf 	data = genlmsg_put_reply(ans_skb, info, &netlbl_mgmt_gnl_family,
73717c157c8SThomas Graf 				 0, NLBL_MGMT_C_VERSION);
738fd385855SPaul Moore 	if (data == NULL)
739d15c345fSPaul Moore 		goto version_failure;
740d15c345fSPaul Moore 
741fd385855SPaul Moore 	ret_val = nla_put_u32(ans_skb,
742fd385855SPaul Moore 			      NLBL_MGMT_A_VERSION,
743fd385855SPaul Moore 			      NETLBL_PROTO_VERSION);
744d15c345fSPaul Moore 	if (ret_val != 0)
745d15c345fSPaul Moore 		goto version_failure;
746d15c345fSPaul Moore 
747fd385855SPaul Moore 	genlmsg_end(ans_skb, data);
748fe785beeSDenis V. Lunev 	return genlmsg_reply(ans_skb, info);
749d15c345fSPaul Moore 
750d15c345fSPaul Moore version_failure:
751d15c345fSPaul Moore 	kfree_skb(ans_skb);
752d15c345fSPaul Moore 	return ret_val;
753d15c345fSPaul Moore }
754d15c345fSPaul Moore 
755d15c345fSPaul Moore 
756d15c345fSPaul Moore /*
757d15c345fSPaul Moore  * NetLabel Generic NETLINK Command Definitions
758d15c345fSPaul Moore  */
759d15c345fSPaul Moore 
7604534de83SJohannes Berg static const struct genl_ops netlbl_mgmt_genl_ops[] = {
761227c43c3SPavel Emelyanov 	{
762d15c345fSPaul Moore 	.cmd = NLBL_MGMT_C_ADD,
763ef6243acSJohannes Berg 	.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
764fd385855SPaul Moore 	.flags = GENL_ADMIN_PERM,
765d15c345fSPaul Moore 	.doit = netlbl_mgmt_add,
766d15c345fSPaul Moore 	.dumpit = NULL,
767227c43c3SPavel Emelyanov 	},
768227c43c3SPavel Emelyanov 	{
769d15c345fSPaul Moore 	.cmd = NLBL_MGMT_C_REMOVE,
770ef6243acSJohannes Berg 	.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
771fd385855SPaul Moore 	.flags = GENL_ADMIN_PERM,
772d15c345fSPaul Moore 	.doit = netlbl_mgmt_remove,
773d15c345fSPaul Moore 	.dumpit = NULL,
774227c43c3SPavel Emelyanov 	},
775227c43c3SPavel Emelyanov 	{
776fd385855SPaul Moore 	.cmd = NLBL_MGMT_C_LISTALL,
777ef6243acSJohannes Berg 	.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
778d15c345fSPaul Moore 	.flags = 0,
779fd385855SPaul Moore 	.doit = NULL,
780fd385855SPaul Moore 	.dumpit = netlbl_mgmt_listall,
781227c43c3SPavel Emelyanov 	},
782227c43c3SPavel Emelyanov 	{
783d15c345fSPaul Moore 	.cmd = NLBL_MGMT_C_ADDDEF,
784ef6243acSJohannes Berg 	.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
785fd385855SPaul Moore 	.flags = GENL_ADMIN_PERM,
786d15c345fSPaul Moore 	.doit = netlbl_mgmt_adddef,
787d15c345fSPaul Moore 	.dumpit = NULL,
788227c43c3SPavel Emelyanov 	},
789227c43c3SPavel Emelyanov 	{
790d15c345fSPaul Moore 	.cmd = NLBL_MGMT_C_REMOVEDEF,
791ef6243acSJohannes Berg 	.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
792fd385855SPaul Moore 	.flags = GENL_ADMIN_PERM,
793d15c345fSPaul Moore 	.doit = netlbl_mgmt_removedef,
794d15c345fSPaul Moore 	.dumpit = NULL,
795227c43c3SPavel Emelyanov 	},
796227c43c3SPavel Emelyanov 	{
797d15c345fSPaul Moore 	.cmd = NLBL_MGMT_C_LISTDEF,
798ef6243acSJohannes Berg 	.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
799d15c345fSPaul Moore 	.flags = 0,
800d15c345fSPaul Moore 	.doit = netlbl_mgmt_listdef,
801d15c345fSPaul Moore 	.dumpit = NULL,
802227c43c3SPavel Emelyanov 	},
803227c43c3SPavel Emelyanov 	{
804fd385855SPaul Moore 	.cmd = NLBL_MGMT_C_PROTOCOLS,
805ef6243acSJohannes Berg 	.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
806d15c345fSPaul Moore 	.flags = 0,
807fd385855SPaul Moore 	.doit = NULL,
808fd385855SPaul Moore 	.dumpit = netlbl_mgmt_protocols,
809227c43c3SPavel Emelyanov 	},
810227c43c3SPavel Emelyanov 	{
811d15c345fSPaul Moore 	.cmd = NLBL_MGMT_C_VERSION,
812ef6243acSJohannes Berg 	.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
813d15c345fSPaul Moore 	.flags = 0,
814d15c345fSPaul Moore 	.doit = netlbl_mgmt_version,
815d15c345fSPaul Moore 	.dumpit = NULL,
816227c43c3SPavel Emelyanov 	},
817d15c345fSPaul Moore };
818d15c345fSPaul Moore 
81956989f6dSJohannes Berg static struct genl_family netlbl_mgmt_gnl_family __ro_after_init = {
820489111e5SJohannes Berg 	.hdrsize = 0,
821489111e5SJohannes Berg 	.name = NETLBL_NLTYPE_MGMT_NAME,
822489111e5SJohannes Berg 	.version = NETLBL_PROTO_VERSION,
823489111e5SJohannes Berg 	.maxattr = NLBL_MGMT_A_MAX,
8243b0f31f2SJohannes Berg 	.policy = netlbl_mgmt_genl_policy,
825489111e5SJohannes Berg 	.module = THIS_MODULE,
826489111e5SJohannes Berg 	.ops = netlbl_mgmt_genl_ops,
827489111e5SJohannes Berg 	.n_ops = ARRAY_SIZE(netlbl_mgmt_genl_ops),
828489111e5SJohannes Berg };
829489111e5SJohannes Berg 
830d15c345fSPaul Moore /*
831d15c345fSPaul Moore  * NetLabel Generic NETLINK Protocol Functions
832d15c345fSPaul Moore  */
833d15c345fSPaul Moore 
834d15c345fSPaul Moore /**
835d15c345fSPaul Moore  * netlbl_mgmt_genl_init - Register the NetLabel management component
836d15c345fSPaul Moore  *
837d15c345fSPaul Moore  * Description:
838d15c345fSPaul Moore  * Register the NetLabel management component with the Generic NETLINK
839d15c345fSPaul Moore  * mechanism.  Returns zero on success, negative values on failure.
840d15c345fSPaul Moore  *
841d15c345fSPaul Moore  */
84205705e4eSPavel Emelyanov int __init netlbl_mgmt_genl_init(void)
843d15c345fSPaul Moore {
844489111e5SJohannes Berg 	return genl_register_family(&netlbl_mgmt_gnl_family);
845d15c345fSPaul Moore }
846