xref: /openbmc/linux/net/netlabel/netlabel_mgmt.c (revision 9c5d03d3)
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 /**
663ba937fbSXiongfeng Wang  * netlbl_mgmt_add_common - 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  */
netlbl_mgmt_add_common(struct genl_info * info,struct netlbl_audit * audit_info)7663c41688SPaul Moore static int netlbl_mgmt_add_common(struct genl_info *info,
7763c41688SPaul Moore 				  struct netlbl_audit *audit_info)
7863c41688SPaul Moore {
79b8f6b052SLiu Shixin 	void *pmap = NULL;
8063c41688SPaul Moore 	int ret_val = -EINVAL;
8163c41688SPaul Moore 	struct netlbl_domaddr_map *addrmap = NULL;
8263c41688SPaul Moore 	struct cipso_v4_doi *cipsov4 = NULL;
83dc7de73fSHuw Davies #if IS_ENABLED(CONFIG_IPV6)
84dc7de73fSHuw Davies 	struct calipso_doi *calipso = NULL;
85dc7de73fSHuw Davies #endif
8663c41688SPaul Moore 	u32 tmp_val;
874de46d5eSMarkus Elfring 	struct netlbl_dom_map *entry = kzalloc(sizeof(*entry), GFP_KERNEL);
8863c41688SPaul Moore 
894de46d5eSMarkus Elfring 	if (!entry)
904de46d5eSMarkus Elfring 		return -ENOMEM;
916a8b7f0cSPaul Moore 	entry->def.type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]);
9263c41688SPaul Moore 	if (info->attrs[NLBL_MGMT_A_DOMAIN]) {
9363c41688SPaul Moore 		size_t tmp_size = nla_len(info->attrs[NLBL_MGMT_A_DOMAIN]);
9463c41688SPaul Moore 		entry->domain = kmalloc(tmp_size, GFP_KERNEL);
9563c41688SPaul Moore 		if (entry->domain == NULL) {
9663c41688SPaul Moore 			ret_val = -ENOMEM;
974de46d5eSMarkus Elfring 			goto add_free_entry;
9863c41688SPaul Moore 		}
99872f6903SFrancis Laniel 		nla_strscpy(entry->domain,
10063c41688SPaul Moore 			    info->attrs[NLBL_MGMT_A_DOMAIN], tmp_size);
10163c41688SPaul Moore 	}
10263c41688SPaul Moore 
1036a8b7f0cSPaul Moore 	/* NOTE: internally we allow/use a entry->def.type value of
10463c41688SPaul Moore 	 *       NETLBL_NLTYPE_ADDRSELECT but we don't currently allow users
10563c41688SPaul Moore 	 *       to pass that as a protocol value because we need to know the
10663c41688SPaul Moore 	 *       "real" protocol */
10763c41688SPaul Moore 
1086a8b7f0cSPaul Moore 	switch (entry->def.type) {
10963c41688SPaul Moore 	case NETLBL_NLTYPE_UNLABELED:
1108f18e675SHuw Davies 		if (info->attrs[NLBL_MGMT_A_FAMILY])
1118f18e675SHuw Davies 			entry->family =
1128f18e675SHuw Davies 				nla_get_u16(info->attrs[NLBL_MGMT_A_FAMILY]);
1138f18e675SHuw Davies 		else
1148f18e675SHuw Davies 			entry->family = AF_UNSPEC;
11563c41688SPaul Moore 		break;
11663c41688SPaul Moore 	case NETLBL_NLTYPE_CIPSOV4:
11763c41688SPaul Moore 		if (!info->attrs[NLBL_MGMT_A_CV4DOI])
1184de46d5eSMarkus Elfring 			goto add_free_domain;
11963c41688SPaul Moore 
12063c41688SPaul Moore 		tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]);
12163c41688SPaul Moore 		cipsov4 = cipso_v4_doi_getdef(tmp_val);
12263c41688SPaul Moore 		if (cipsov4 == NULL)
1234de46d5eSMarkus Elfring 			goto add_free_domain;
1248f18e675SHuw Davies 		entry->family = AF_INET;
1256a8b7f0cSPaul Moore 		entry->def.cipso = cipsov4;
12663c41688SPaul Moore 		break;
127dc7de73fSHuw Davies #if IS_ENABLED(CONFIG_IPV6)
128dc7de73fSHuw Davies 	case NETLBL_NLTYPE_CALIPSO:
129dc7de73fSHuw Davies 		if (!info->attrs[NLBL_MGMT_A_CLPDOI])
130dc7de73fSHuw Davies 			goto add_free_domain;
131dc7de73fSHuw Davies 
132dc7de73fSHuw Davies 		tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CLPDOI]);
133dc7de73fSHuw Davies 		calipso = calipso_doi_getdef(tmp_val);
134dc7de73fSHuw Davies 		if (calipso == NULL)
135dc7de73fSHuw Davies 			goto add_free_domain;
136dc7de73fSHuw Davies 		entry->family = AF_INET6;
137dc7de73fSHuw Davies 		entry->def.calipso = calipso;
138dc7de73fSHuw Davies 		break;
139dc7de73fSHuw Davies #endif /* IPv6 */
14063c41688SPaul Moore 	default:
1414de46d5eSMarkus Elfring 		goto add_free_domain;
14263c41688SPaul Moore 	}
14363c41688SPaul Moore 
1448f18e675SHuw Davies 	if ((entry->family == AF_INET && info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
1458f18e675SHuw Davies 	    (entry->family == AF_INET6 && info->attrs[NLBL_MGMT_A_IPV4ADDR]))
1468f18e675SHuw Davies 		goto add_doi_put_def;
1478f18e675SHuw Davies 
14863c41688SPaul Moore 	if (info->attrs[NLBL_MGMT_A_IPV4ADDR]) {
14963c41688SPaul Moore 		struct in_addr *addr;
15063c41688SPaul Moore 		struct in_addr *mask;
15163c41688SPaul Moore 		struct netlbl_domaddr4_map *map;
15263c41688SPaul Moore 
15363c41688SPaul Moore 		addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL);
15463c41688SPaul Moore 		if (addrmap == NULL) {
15563c41688SPaul Moore 			ret_val = -ENOMEM;
1564de46d5eSMarkus Elfring 			goto add_doi_put_def;
15763c41688SPaul Moore 		}
15863c41688SPaul Moore 		INIT_LIST_HEAD(&addrmap->list4);
15963c41688SPaul Moore 		INIT_LIST_HEAD(&addrmap->list6);
16063c41688SPaul Moore 
16163c41688SPaul Moore 		if (nla_len(info->attrs[NLBL_MGMT_A_IPV4ADDR]) !=
16263c41688SPaul Moore 		    sizeof(struct in_addr)) {
16363c41688SPaul Moore 			ret_val = -EINVAL;
1644de46d5eSMarkus Elfring 			goto add_free_addrmap;
16563c41688SPaul Moore 		}
16663c41688SPaul Moore 		if (nla_len(info->attrs[NLBL_MGMT_A_IPV4MASK]) !=
16763c41688SPaul Moore 		    sizeof(struct in_addr)) {
16863c41688SPaul Moore 			ret_val = -EINVAL;
1694de46d5eSMarkus Elfring 			goto add_free_addrmap;
17063c41688SPaul Moore 		}
17163c41688SPaul Moore 		addr = nla_data(info->attrs[NLBL_MGMT_A_IPV4ADDR]);
17263c41688SPaul Moore 		mask = nla_data(info->attrs[NLBL_MGMT_A_IPV4MASK]);
17363c41688SPaul Moore 
17463c41688SPaul Moore 		map = kzalloc(sizeof(*map), GFP_KERNEL);
17563c41688SPaul Moore 		if (map == NULL) {
17663c41688SPaul Moore 			ret_val = -ENOMEM;
1774de46d5eSMarkus Elfring 			goto add_free_addrmap;
17863c41688SPaul Moore 		}
179b8f6b052SLiu Shixin 		pmap = map;
18063c41688SPaul Moore 		map->list.addr = addr->s_addr & mask->s_addr;
18163c41688SPaul Moore 		map->list.mask = mask->s_addr;
18263c41688SPaul Moore 		map->list.valid = 1;
1836a8b7f0cSPaul Moore 		map->def.type = entry->def.type;
18463c41688SPaul Moore 		if (cipsov4)
1856a8b7f0cSPaul Moore 			map->def.cipso = cipsov4;
18663c41688SPaul Moore 
18763c41688SPaul Moore 		ret_val = netlbl_af4list_add(&map->list, &addrmap->list4);
188b8f6b052SLiu Shixin 		if (ret_val != 0)
189b8f6b052SLiu Shixin 			goto add_free_map;
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 		}
226b8f6b052SLiu Shixin 		pmap = map;
2274e3fd7a0SAlexey Dobriyan 		map->list.addr = *addr;
22863c41688SPaul Moore 		map->list.addr.s6_addr32[0] &= mask->s6_addr32[0];
22963c41688SPaul Moore 		map->list.addr.s6_addr32[1] &= mask->s6_addr32[1];
23063c41688SPaul Moore 		map->list.addr.s6_addr32[2] &= mask->s6_addr32[2];
23163c41688SPaul Moore 		map->list.addr.s6_addr32[3] &= mask->s6_addr32[3];
2324e3fd7a0SAlexey Dobriyan 		map->list.mask = *mask;
23363c41688SPaul Moore 		map->list.valid = 1;
2346a8b7f0cSPaul Moore 		map->def.type = entry->def.type;
235dc7de73fSHuw Davies 		if (calipso)
236dc7de73fSHuw Davies 			map->def.calipso = calipso;
23763c41688SPaul Moore 
23863c41688SPaul Moore 		ret_val = netlbl_af6list_add(&map->list, &addrmap->list6);
239b8f6b052SLiu Shixin 		if (ret_val != 0)
240b8f6b052SLiu Shixin 			goto add_free_map;
24163c41688SPaul Moore 
2428f18e675SHuw Davies 		entry->family = AF_INET6;
2436a8b7f0cSPaul Moore 		entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
2446a8b7f0cSPaul Moore 		entry->def.addrsel = addrmap;
24563c41688SPaul Moore #endif /* IPv6 */
24663c41688SPaul Moore 	}
24763c41688SPaul Moore 
24863c41688SPaul Moore 	ret_val = netlbl_domhsh_add(entry, audit_info);
24963c41688SPaul Moore 	if (ret_val != 0)
250b8f6b052SLiu Shixin 		goto add_free_map;
25163c41688SPaul Moore 
25263c41688SPaul Moore 	return 0;
25363c41688SPaul Moore 
254b8f6b052SLiu Shixin add_free_map:
255b8f6b052SLiu Shixin 	kfree(pmap);
2564de46d5eSMarkus Elfring add_free_addrmap:
25763c41688SPaul Moore 	kfree(addrmap);
2584de46d5eSMarkus Elfring add_doi_put_def:
2594de46d5eSMarkus Elfring 	cipso_v4_doi_putdef(cipsov4);
260dc7de73fSHuw Davies #if IS_ENABLED(CONFIG_IPV6)
261dc7de73fSHuw Davies 	calipso_doi_putdef(calipso);
262dc7de73fSHuw Davies #endif
2634de46d5eSMarkus Elfring add_free_domain:
2644de46d5eSMarkus Elfring 	kfree(entry->domain);
2654de46d5eSMarkus Elfring add_free_entry:
26663c41688SPaul Moore 	kfree(entry);
26763c41688SPaul Moore 	return ret_val;
26863c41688SPaul Moore }
26963c41688SPaul Moore 
27063c41688SPaul Moore /**
27163c41688SPaul Moore  * netlbl_mgmt_listentry - List a NetLabel/LSM domain map entry
27263c41688SPaul Moore  * @skb: the NETLINK buffer
27363c41688SPaul Moore  * @entry: the map entry
27463c41688SPaul Moore  *
27563c41688SPaul Moore  * Description:
27663c41688SPaul Moore  * This function is a helper function used by the LISTALL and LISTDEF command
27725985edcSLucas De Marchi  * handlers.  The caller is responsible for ensuring that the RCU read lock
27863c41688SPaul Moore  * is held.  Returns zero on success, negative values on failure.
27963c41688SPaul Moore  *
28063c41688SPaul Moore  */
netlbl_mgmt_listentry(struct sk_buff * skb,struct netlbl_dom_map * entry)28163c41688SPaul Moore static int netlbl_mgmt_listentry(struct sk_buff *skb,
28263c41688SPaul Moore 				 struct netlbl_dom_map *entry)
28363c41688SPaul Moore {
284f8a02479SPaul Moore 	int ret_val = 0;
28563c41688SPaul Moore 	struct nlattr *nla_a;
28663c41688SPaul Moore 	struct nlattr *nla_b;
28763c41688SPaul Moore 	struct netlbl_af4list *iter4;
288dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6)
28963c41688SPaul Moore 	struct netlbl_af6list *iter6;
29063c41688SPaul Moore #endif
29163c41688SPaul Moore 
29263c41688SPaul Moore 	if (entry->domain != NULL) {
29363c41688SPaul Moore 		ret_val = nla_put_string(skb,
29463c41688SPaul Moore 					 NLBL_MGMT_A_DOMAIN, entry->domain);
29563c41688SPaul Moore 		if (ret_val != 0)
29663c41688SPaul Moore 			return ret_val;
29763c41688SPaul Moore 	}
29863c41688SPaul Moore 
2998f18e675SHuw Davies 	ret_val = nla_put_u16(skb, NLBL_MGMT_A_FAMILY, entry->family);
3008f18e675SHuw Davies 	if (ret_val != 0)
3018f18e675SHuw Davies 		return ret_val;
3028f18e675SHuw Davies 
3036a8b7f0cSPaul Moore 	switch (entry->def.type) {
30463c41688SPaul Moore 	case NETLBL_NLTYPE_ADDRSELECT:
305ae0be8deSMichal Kubecek 		nla_a = nla_nest_start_noflag(skb, NLBL_MGMT_A_SELECTORLIST);
30663c41688SPaul Moore 		if (nla_a == NULL)
30763c41688SPaul Moore 			return -ENOMEM;
30863c41688SPaul Moore 
3096a8b7f0cSPaul Moore 		netlbl_af4list_foreach_rcu(iter4, &entry->def.addrsel->list4) {
31063c41688SPaul Moore 			struct netlbl_domaddr4_map *map4;
31163c41688SPaul Moore 			struct in_addr addr_struct;
31263c41688SPaul Moore 
313ae0be8deSMichal Kubecek 			nla_b = nla_nest_start_noflag(skb,
314ae0be8deSMichal Kubecek 						      NLBL_MGMT_A_ADDRSELECTOR);
31563c41688SPaul Moore 			if (nla_b == NULL)
31663c41688SPaul Moore 				return -ENOMEM;
31763c41688SPaul Moore 
31863c41688SPaul Moore 			addr_struct.s_addr = iter4->addr;
319930345eaSJiri Benc 			ret_val = nla_put_in_addr(skb, NLBL_MGMT_A_IPV4ADDR,
320930345eaSJiri Benc 						  addr_struct.s_addr);
32163c41688SPaul Moore 			if (ret_val != 0)
32263c41688SPaul Moore 				return ret_val;
32363c41688SPaul Moore 			addr_struct.s_addr = iter4->mask;
324930345eaSJiri Benc 			ret_val = nla_put_in_addr(skb, NLBL_MGMT_A_IPV4MASK,
325930345eaSJiri Benc 						  addr_struct.s_addr);
32663c41688SPaul Moore 			if (ret_val != 0)
32763c41688SPaul Moore 				return ret_val;
32863c41688SPaul Moore 			map4 = netlbl_domhsh_addr4_entry(iter4);
32963c41688SPaul Moore 			ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
3306a8b7f0cSPaul Moore 					      map4->def.type);
33163c41688SPaul Moore 			if (ret_val != 0)
33263c41688SPaul Moore 				return ret_val;
3336a8b7f0cSPaul Moore 			switch (map4->def.type) {
33463c41688SPaul Moore 			case NETLBL_NLTYPE_CIPSOV4:
33563c41688SPaul Moore 				ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI,
3366a8b7f0cSPaul Moore 						      map4->def.cipso->doi);
33763c41688SPaul Moore 				if (ret_val != 0)
33863c41688SPaul Moore 					return ret_val;
33963c41688SPaul Moore 				break;
34063c41688SPaul Moore 			}
34163c41688SPaul Moore 
34263c41688SPaul Moore 			nla_nest_end(skb, nla_b);
34363c41688SPaul Moore 		}
344dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6)
3456a8b7f0cSPaul Moore 		netlbl_af6list_foreach_rcu(iter6, &entry->def.addrsel->list6) {
34663c41688SPaul Moore 			struct netlbl_domaddr6_map *map6;
34763c41688SPaul Moore 
348ae0be8deSMichal Kubecek 			nla_b = nla_nest_start_noflag(skb,
349ae0be8deSMichal Kubecek 						      NLBL_MGMT_A_ADDRSELECTOR);
35063c41688SPaul Moore 			if (nla_b == NULL)
35163c41688SPaul Moore 				return -ENOMEM;
35263c41688SPaul Moore 
353930345eaSJiri Benc 			ret_val = nla_put_in6_addr(skb, NLBL_MGMT_A_IPV6ADDR,
35463c41688SPaul Moore 						   &iter6->addr);
35563c41688SPaul Moore 			if (ret_val != 0)
35663c41688SPaul Moore 				return ret_val;
357930345eaSJiri Benc 			ret_val = nla_put_in6_addr(skb, NLBL_MGMT_A_IPV6MASK,
35863c41688SPaul Moore 						   &iter6->mask);
35963c41688SPaul Moore 			if (ret_val != 0)
36063c41688SPaul Moore 				return ret_val;
36163c41688SPaul Moore 			map6 = netlbl_domhsh_addr6_entry(iter6);
36263c41688SPaul Moore 			ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
3636a8b7f0cSPaul Moore 					      map6->def.type);
36463c41688SPaul Moore 			if (ret_val != 0)
36563c41688SPaul Moore 				return ret_val;
36663c41688SPaul Moore 
367dc7de73fSHuw Davies 			switch (map6->def.type) {
368dc7de73fSHuw Davies 			case NETLBL_NLTYPE_CALIPSO:
369dc7de73fSHuw Davies 				ret_val = nla_put_u32(skb, NLBL_MGMT_A_CLPDOI,
370dc7de73fSHuw Davies 						      map6->def.calipso->doi);
371dc7de73fSHuw Davies 				if (ret_val != 0)
372dc7de73fSHuw Davies 					return ret_val;
373dc7de73fSHuw Davies 				break;
374dc7de73fSHuw Davies 			}
375dc7de73fSHuw Davies 
37663c41688SPaul Moore 			nla_nest_end(skb, nla_b);
37763c41688SPaul Moore 		}
37863c41688SPaul Moore #endif /* IPv6 */
37963c41688SPaul Moore 
38063c41688SPaul Moore 		nla_nest_end(skb, nla_a);
38163c41688SPaul Moore 		break;
38263c41688SPaul Moore 	case NETLBL_NLTYPE_UNLABELED:
383dc7de73fSHuw Davies 		ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
384dc7de73fSHuw Davies 				      entry->def.type);
38563c41688SPaul Moore 		break;
38663c41688SPaul Moore 	case NETLBL_NLTYPE_CIPSOV4:
387dc7de73fSHuw Davies 		ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
388dc7de73fSHuw Davies 				      entry->def.type);
38963c41688SPaul Moore 		if (ret_val != 0)
39063c41688SPaul Moore 			return ret_val;
39163c41688SPaul Moore 		ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI,
3926a8b7f0cSPaul Moore 				      entry->def.cipso->doi);
39363c41688SPaul Moore 		break;
394dc7de73fSHuw Davies 	case NETLBL_NLTYPE_CALIPSO:
395dc7de73fSHuw Davies 		ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
396dc7de73fSHuw Davies 				      entry->def.type);
397dc7de73fSHuw Davies 		if (ret_val != 0)
398dc7de73fSHuw Davies 			return ret_val;
399dc7de73fSHuw Davies 		ret_val = nla_put_u32(skb, NLBL_MGMT_A_CLPDOI,
400dc7de73fSHuw Davies 				      entry->def.calipso->doi);
401dc7de73fSHuw Davies 		break;
40263c41688SPaul Moore 	}
40363c41688SPaul Moore 
40463c41688SPaul Moore 	return ret_val;
40563c41688SPaul Moore }
40663c41688SPaul Moore 
40763c41688SPaul Moore /*
408d15c345fSPaul Moore  * NetLabel Command Handlers
409d15c345fSPaul Moore  */
410d15c345fSPaul Moore 
411d15c345fSPaul Moore /**
412d15c345fSPaul Moore  * netlbl_mgmt_add - Handle an ADD message
413d15c345fSPaul Moore  * @skb: the NETLINK buffer
414d15c345fSPaul Moore  * @info: the Generic NETLINK info block
415d15c345fSPaul Moore  *
416d15c345fSPaul Moore  * Description:
417d15c345fSPaul Moore  * Process a user generated ADD message and add the domains from the message
418d15c345fSPaul Moore  * to the hash table.  See netlabel.h for a description of the message format.
419d15c345fSPaul Moore  * Returns zero on success, negative values on failure.
420d15c345fSPaul Moore  *
421d15c345fSPaul Moore  */
netlbl_mgmt_add(struct sk_buff * skb,struct genl_info * info)422d15c345fSPaul Moore static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info)
423d15c345fSPaul Moore {
42495d4e6beSPaul Moore 	struct netlbl_audit audit_info;
425d15c345fSPaul Moore 
42663c41688SPaul Moore 	if ((!info->attrs[NLBL_MGMT_A_DOMAIN]) ||
42763c41688SPaul Moore 	    (!info->attrs[NLBL_MGMT_A_PROTOCOL]) ||
42863c41688SPaul Moore 	    (info->attrs[NLBL_MGMT_A_IPV4ADDR] &&
42963c41688SPaul Moore 	     info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
43063c41688SPaul Moore 	    (info->attrs[NLBL_MGMT_A_IPV4MASK] &&
43163c41688SPaul Moore 	     info->attrs[NLBL_MGMT_A_IPV6MASK]) ||
43263c41688SPaul Moore 	    ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^
43363c41688SPaul Moore 	     (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) ||
43463c41688SPaul Moore 	    ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^
43563c41688SPaul Moore 	     (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL)))
43663c41688SPaul Moore 		return -EINVAL;
437d15c345fSPaul Moore 
438f7e0318aSZheng Yejian 	netlbl_netlink_auditinfo(&audit_info);
43995d4e6beSPaul Moore 
44063c41688SPaul Moore 	return netlbl_mgmt_add_common(info, &audit_info);
441d15c345fSPaul Moore }
442d15c345fSPaul Moore 
443d15c345fSPaul Moore /**
444d15c345fSPaul Moore  * netlbl_mgmt_remove - Handle a REMOVE message
445d15c345fSPaul Moore  * @skb: the NETLINK buffer
446d15c345fSPaul Moore  * @info: the Generic NETLINK info block
447d15c345fSPaul Moore  *
448d15c345fSPaul Moore  * Description:
449d15c345fSPaul Moore  * Process a user generated REMOVE message and remove the specified domain
450d15c345fSPaul Moore  * mappings.  Returns zero on success, negative values on failure.
451d15c345fSPaul Moore  *
452d15c345fSPaul Moore  */
netlbl_mgmt_remove(struct sk_buff * skb,struct genl_info * info)453d15c345fSPaul Moore static int netlbl_mgmt_remove(struct sk_buff *skb, struct genl_info *info)
454d15c345fSPaul Moore {
455fd385855SPaul Moore 	char *domain;
45695d4e6beSPaul Moore 	struct netlbl_audit audit_info;
457d15c345fSPaul Moore 
458fd385855SPaul Moore 	if (!info->attrs[NLBL_MGMT_A_DOMAIN])
459fd385855SPaul Moore 		return -EINVAL;
460d15c345fSPaul Moore 
461f7e0318aSZheng Yejian 	netlbl_netlink_auditinfo(&audit_info);
46295d4e6beSPaul Moore 
463fd385855SPaul Moore 	domain = nla_data(info->attrs[NLBL_MGMT_A_DOMAIN]);
4648f18e675SHuw Davies 	return netlbl_domhsh_remove(domain, AF_UNSPEC, &audit_info);
465d15c345fSPaul Moore }
466d15c345fSPaul Moore 
467fd385855SPaul Moore /**
468fd385855SPaul Moore  * netlbl_mgmt_listall_cb - netlbl_domhsh_walk() callback for LISTALL
469fd385855SPaul Moore  * @entry: the domain mapping hash table entry
470fd385855SPaul Moore  * @arg: the netlbl_domhsh_walk_arg structure
471fd385855SPaul Moore  *
472fd385855SPaul Moore  * Description:
473fd385855SPaul Moore  * This function is designed to be used as a callback to the
474fd385855SPaul Moore  * netlbl_domhsh_walk() function for use in generating a response for a LISTALL
475fd385855SPaul Moore  * message.  Returns the size of the message on success, negative values on
476fd385855SPaul Moore  * failure.
477fd385855SPaul Moore  *
478fd385855SPaul Moore  */
netlbl_mgmt_listall_cb(struct netlbl_dom_map * entry,void * arg)479fd385855SPaul Moore static int netlbl_mgmt_listall_cb(struct netlbl_dom_map *entry, void *arg)
480fd385855SPaul Moore {
481fd385855SPaul Moore 	int ret_val = -ENOMEM;
482fd385855SPaul Moore 	struct netlbl_domhsh_walk_arg *cb_arg = arg;
483fd385855SPaul Moore 	void *data;
484d15c345fSPaul Moore 
48515e47304SEric W. Biederman 	data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).portid,
48617c157c8SThomas Graf 			   cb_arg->seq, &netlbl_mgmt_gnl_family,
48717c157c8SThomas Graf 			   NLM_F_MULTI, NLBL_MGMT_C_LISTALL);
488fd385855SPaul Moore 	if (data == NULL)
489fd385855SPaul Moore 		goto listall_cb_failure;
490fd385855SPaul Moore 
49163c41688SPaul Moore 	ret_val = netlbl_mgmt_listentry(cb_arg->skb, entry);
492fd385855SPaul Moore 	if (ret_val != 0)
493fd385855SPaul Moore 		goto listall_cb_failure;
494fd385855SPaul Moore 
495fd385855SPaul Moore 	cb_arg->seq++;
496053c095aSJohannes Berg 	genlmsg_end(cb_arg->skb, data);
497053c095aSJohannes Berg 	return 0;
498fd385855SPaul Moore 
499fd385855SPaul Moore listall_cb_failure:
500fd385855SPaul Moore 	genlmsg_cancel(cb_arg->skb, data);
501d15c345fSPaul Moore 	return ret_val;
502d15c345fSPaul Moore }
503d15c345fSPaul Moore 
504d15c345fSPaul Moore /**
505fd385855SPaul Moore  * netlbl_mgmt_listall - Handle a LISTALL message
506d15c345fSPaul Moore  * @skb: the NETLINK buffer
507fd385855SPaul Moore  * @cb: the NETLINK callback
508d15c345fSPaul Moore  *
509d15c345fSPaul Moore  * Description:
510fd385855SPaul Moore  * Process a user generated LISTALL message and dumps the domain hash table in
511fd385855SPaul Moore  * a form suitable for use in a kernel generated LISTALL message.  Returns zero
512fd385855SPaul Moore  * on success, negative values on failure.
513d15c345fSPaul Moore  *
514d15c345fSPaul Moore  */
netlbl_mgmt_listall(struct sk_buff * skb,struct netlink_callback * cb)515fd385855SPaul Moore static int netlbl_mgmt_listall(struct sk_buff *skb,
516fd385855SPaul Moore 			       struct netlink_callback *cb)
517d15c345fSPaul Moore {
518fd385855SPaul Moore 	struct netlbl_domhsh_walk_arg cb_arg;
519fd385855SPaul Moore 	u32 skip_bkt = cb->args[0];
520fd385855SPaul Moore 	u32 skip_chain = cb->args[1];
521d15c345fSPaul Moore 
522fd385855SPaul Moore 	cb_arg.nl_cb = cb;
523fd385855SPaul Moore 	cb_arg.skb = skb;
524fd385855SPaul Moore 	cb_arg.seq = cb->nlh->nlmsg_seq;
525d15c345fSPaul Moore 
526fd385855SPaul Moore 	netlbl_domhsh_walk(&skip_bkt,
527fd385855SPaul Moore 			   &skip_chain,
528fd385855SPaul Moore 			   netlbl_mgmt_listall_cb,
529fd385855SPaul Moore 			   &cb_arg);
530d15c345fSPaul Moore 
531fd385855SPaul Moore 	cb->args[0] = skip_bkt;
532fd385855SPaul Moore 	cb->args[1] = skip_chain;
533fd385855SPaul Moore 	return skb->len;
534d15c345fSPaul Moore }
535d15c345fSPaul Moore 
536d15c345fSPaul Moore /**
537d15c345fSPaul Moore  * netlbl_mgmt_adddef - Handle an ADDDEF message
538d15c345fSPaul Moore  * @skb: the NETLINK buffer
539d15c345fSPaul Moore  * @info: the Generic NETLINK info block
540d15c345fSPaul Moore  *
541d15c345fSPaul Moore  * Description:
542d15c345fSPaul Moore  * Process a user generated ADDDEF message and respond accordingly.  Returns
543d15c345fSPaul Moore  * zero on success, negative values on failure.
544d15c345fSPaul Moore  *
545d15c345fSPaul Moore  */
netlbl_mgmt_adddef(struct sk_buff * skb,struct genl_info * info)546d15c345fSPaul Moore static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info)
547d15c345fSPaul Moore {
54895d4e6beSPaul Moore 	struct netlbl_audit audit_info;
549d15c345fSPaul Moore 
55063c41688SPaul Moore 	if ((!info->attrs[NLBL_MGMT_A_PROTOCOL]) ||
55163c41688SPaul Moore 	    (info->attrs[NLBL_MGMT_A_IPV4ADDR] &&
55263c41688SPaul Moore 	     info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
55363c41688SPaul Moore 	    (info->attrs[NLBL_MGMT_A_IPV4MASK] &&
55463c41688SPaul Moore 	     info->attrs[NLBL_MGMT_A_IPV6MASK]) ||
55563c41688SPaul Moore 	    ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^
55663c41688SPaul Moore 	     (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) ||
55763c41688SPaul Moore 	    ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^
55863c41688SPaul Moore 	     (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL)))
55963c41688SPaul Moore 		return -EINVAL;
560d15c345fSPaul Moore 
561f7e0318aSZheng Yejian 	netlbl_netlink_auditinfo(&audit_info);
56295d4e6beSPaul Moore 
56363c41688SPaul Moore 	return netlbl_mgmt_add_common(info, &audit_info);
564d15c345fSPaul Moore }
565d15c345fSPaul Moore 
566d15c345fSPaul Moore /**
567d15c345fSPaul Moore  * netlbl_mgmt_removedef - Handle a REMOVEDEF message
568d15c345fSPaul Moore  * @skb: the NETLINK buffer
569d15c345fSPaul Moore  * @info: the Generic NETLINK info block
570d15c345fSPaul Moore  *
571d15c345fSPaul Moore  * Description:
572d15c345fSPaul Moore  * Process a user generated REMOVEDEF message and remove the default domain
573d15c345fSPaul Moore  * mapping.  Returns zero on success, negative values on failure.
574d15c345fSPaul Moore  *
575d15c345fSPaul Moore  */
netlbl_mgmt_removedef(struct sk_buff * skb,struct genl_info * info)576d15c345fSPaul Moore static int netlbl_mgmt_removedef(struct sk_buff *skb, struct genl_info *info)
577d15c345fSPaul Moore {
57895d4e6beSPaul Moore 	struct netlbl_audit audit_info;
57995d4e6beSPaul Moore 
580f7e0318aSZheng Yejian 	netlbl_netlink_auditinfo(&audit_info);
58195d4e6beSPaul Moore 
5828f18e675SHuw Davies 	return netlbl_domhsh_remove_default(AF_UNSPEC, &audit_info);
583d15c345fSPaul Moore }
584d15c345fSPaul Moore 
585d15c345fSPaul Moore /**
586d15c345fSPaul Moore  * netlbl_mgmt_listdef - Handle a LISTDEF message
587d15c345fSPaul Moore  * @skb: the NETLINK buffer
588d15c345fSPaul Moore  * @info: the Generic NETLINK info block
589d15c345fSPaul Moore  *
590d15c345fSPaul Moore  * Description:
591d15c345fSPaul Moore  * Process a user generated LISTDEF message and dumps the default domain
592d15c345fSPaul Moore  * mapping in a form suitable for use in a kernel generated LISTDEF message.
593d15c345fSPaul Moore  * Returns zero on success, negative values on failure.
594d15c345fSPaul Moore  *
595d15c345fSPaul Moore  */
netlbl_mgmt_listdef(struct sk_buff * skb,struct genl_info * info)596d15c345fSPaul Moore static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info)
597d15c345fSPaul Moore {
598d15c345fSPaul Moore 	int ret_val = -ENOMEM;
599fd385855SPaul Moore 	struct sk_buff *ans_skb = NULL;
600fd385855SPaul Moore 	void *data;
601fd385855SPaul Moore 	struct netlbl_dom_map *entry;
6028f18e675SHuw Davies 	u16 family;
6038f18e675SHuw Davies 
6048f18e675SHuw Davies 	if (info->attrs[NLBL_MGMT_A_FAMILY])
6058f18e675SHuw Davies 		family = nla_get_u16(info->attrs[NLBL_MGMT_A_FAMILY]);
6068f18e675SHuw Davies 	else
6078f18e675SHuw Davies 		family = AF_INET;
608d15c345fSPaul Moore 
609339bf98fSThomas Graf 	ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
610d15c345fSPaul Moore 	if (ans_skb == NULL)
611fd385855SPaul Moore 		return -ENOMEM;
61217c157c8SThomas Graf 	data = genlmsg_put_reply(ans_skb, info, &netlbl_mgmt_gnl_family,
61317c157c8SThomas Graf 				 0, NLBL_MGMT_C_LISTDEF);
614fd385855SPaul Moore 	if (data == NULL)
615fd385855SPaul Moore 		goto listdef_failure;
616d15c345fSPaul Moore 
617fd385855SPaul Moore 	rcu_read_lock();
6188f18e675SHuw Davies 	entry = netlbl_domhsh_getentry(NULL, family);
619fd385855SPaul Moore 	if (entry == NULL) {
620fd385855SPaul Moore 		ret_val = -ENOENT;
621fd385855SPaul Moore 		goto listdef_failure_lock;
622fd385855SPaul Moore 	}
62363c41688SPaul Moore 	ret_val = netlbl_mgmt_listentry(ans_skb, entry);
624fd385855SPaul Moore 	rcu_read_unlock();
62563c41688SPaul Moore 	if (ret_val != 0)
62663c41688SPaul Moore 		goto listdef_failure;
627fd385855SPaul Moore 
628fd385855SPaul Moore 	genlmsg_end(ans_skb, data);
629fe785beeSDenis V. Lunev 	return genlmsg_reply(ans_skb, info);
630d15c345fSPaul Moore 
631fd385855SPaul Moore listdef_failure_lock:
632fd385855SPaul Moore 	rcu_read_unlock();
633d15c345fSPaul Moore listdef_failure:
634fd385855SPaul Moore 	kfree_skb(ans_skb);
635d15c345fSPaul Moore 	return ret_val;
636d15c345fSPaul Moore }
637d15c345fSPaul Moore 
638d15c345fSPaul Moore /**
639fd385855SPaul Moore  * netlbl_mgmt_protocols_cb - Write an individual PROTOCOL message response
640fd385855SPaul Moore  * @skb: the skb to write to
641fd385855SPaul Moore  * @cb: the NETLINK callback
642fd385855SPaul Moore  * @protocol: the NetLabel protocol to use in the message
643d15c345fSPaul Moore  *
644d15c345fSPaul Moore  * Description:
645fd385855SPaul Moore  * This function is to be used in conjunction with netlbl_mgmt_protocols() to
646fd385855SPaul Moore  * answer a application's PROTOCOLS message.  Returns the size of the message
647fd385855SPaul Moore  * on success, negative values on failure.
648d15c345fSPaul Moore  *
649d15c345fSPaul Moore  */
netlbl_mgmt_protocols_cb(struct sk_buff * skb,struct netlink_callback * cb,u32 protocol)650fd385855SPaul Moore static int netlbl_mgmt_protocols_cb(struct sk_buff *skb,
651fd385855SPaul Moore 				    struct netlink_callback *cb,
652fd385855SPaul Moore 				    u32 protocol)
653d15c345fSPaul Moore {
654d15c345fSPaul Moore 	int ret_val = -ENOMEM;
655fd385855SPaul Moore 	void *data;
656d15c345fSPaul Moore 
65715e47304SEric W. Biederman 	data = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
65817c157c8SThomas Graf 			   &netlbl_mgmt_gnl_family, NLM_F_MULTI,
659fd385855SPaul Moore 			   NLBL_MGMT_C_PROTOCOLS);
660fd385855SPaul Moore 	if (data == NULL)
661fd385855SPaul Moore 		goto protocols_cb_failure;
662d15c345fSPaul Moore 
663fd385855SPaul Moore 	ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, protocol);
664d15c345fSPaul Moore 	if (ret_val != 0)
665fd385855SPaul Moore 		goto protocols_cb_failure;
666d15c345fSPaul Moore 
667053c095aSJohannes Berg 	genlmsg_end(skb, data);
668053c095aSJohannes Berg 	return 0;
669d15c345fSPaul Moore 
670fd385855SPaul Moore protocols_cb_failure:
671fd385855SPaul Moore 	genlmsg_cancel(skb, data);
672d15c345fSPaul Moore 	return ret_val;
673d15c345fSPaul Moore }
674d15c345fSPaul Moore 
675d15c345fSPaul Moore /**
676fd385855SPaul Moore  * netlbl_mgmt_protocols - Handle a PROTOCOLS message
677fd385855SPaul Moore  * @skb: the NETLINK buffer
678fd385855SPaul Moore  * @cb: the NETLINK callback
679fd385855SPaul Moore  *
680fd385855SPaul Moore  * Description:
681fd385855SPaul Moore  * Process a user generated PROTOCOLS message and respond accordingly.
682fd385855SPaul Moore  *
683fd385855SPaul Moore  */
netlbl_mgmt_protocols(struct sk_buff * skb,struct netlink_callback * cb)684fd385855SPaul Moore static int netlbl_mgmt_protocols(struct sk_buff *skb,
685fd385855SPaul Moore 				 struct netlink_callback *cb)
686fd385855SPaul Moore {
687fd385855SPaul Moore 	u32 protos_sent = cb->args[0];
688fd385855SPaul Moore 
689fd385855SPaul Moore 	if (protos_sent == 0) {
690fd385855SPaul Moore 		if (netlbl_mgmt_protocols_cb(skb,
691fd385855SPaul Moore 					     cb,
692fd385855SPaul Moore 					     NETLBL_NLTYPE_UNLABELED) < 0)
693fd385855SPaul Moore 			goto protocols_return;
694fd385855SPaul Moore 		protos_sent++;
695fd385855SPaul Moore 	}
696fd385855SPaul Moore 	if (protos_sent == 1) {
697fd385855SPaul Moore 		if (netlbl_mgmt_protocols_cb(skb,
698fd385855SPaul Moore 					     cb,
699fd385855SPaul Moore 					     NETLBL_NLTYPE_CIPSOV4) < 0)
700fd385855SPaul Moore 			goto protocols_return;
701fd385855SPaul Moore 		protos_sent++;
702fd385855SPaul Moore 	}
703cb72d382SHuw Davies #if IS_ENABLED(CONFIG_IPV6)
704cb72d382SHuw Davies 	if (protos_sent == 2) {
705cb72d382SHuw Davies 		if (netlbl_mgmt_protocols_cb(skb,
706cb72d382SHuw Davies 					     cb,
707cb72d382SHuw Davies 					     NETLBL_NLTYPE_CALIPSO) < 0)
708cb72d382SHuw Davies 			goto protocols_return;
709cb72d382SHuw Davies 		protos_sent++;
710cb72d382SHuw Davies 	}
711cb72d382SHuw Davies #endif
712fd385855SPaul Moore 
713fd385855SPaul Moore protocols_return:
714fd385855SPaul Moore 	cb->args[0] = protos_sent;
715fd385855SPaul Moore 	return skb->len;
716fd385855SPaul Moore }
717fd385855SPaul Moore 
718fd385855SPaul Moore /**
719d15c345fSPaul Moore  * netlbl_mgmt_version - Handle a VERSION message
720d15c345fSPaul Moore  * @skb: the NETLINK buffer
721d15c345fSPaul Moore  * @info: the Generic NETLINK info block
722d15c345fSPaul Moore  *
723d15c345fSPaul Moore  * Description:
724d15c345fSPaul Moore  * Process a user generated VERSION message and respond accordingly.  Returns
725d15c345fSPaul Moore  * zero on success, negative values on failure.
726d15c345fSPaul Moore  *
727d15c345fSPaul Moore  */
netlbl_mgmt_version(struct sk_buff * skb,struct genl_info * info)728d15c345fSPaul Moore static int netlbl_mgmt_version(struct sk_buff *skb, struct genl_info *info)
729d15c345fSPaul Moore {
730d15c345fSPaul Moore 	int ret_val = -ENOMEM;
731d15c345fSPaul Moore 	struct sk_buff *ans_skb = NULL;
732fd385855SPaul Moore 	void *data;
733d15c345fSPaul Moore 
734339bf98fSThomas Graf 	ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
735d15c345fSPaul Moore 	if (ans_skb == NULL)
736fd385855SPaul Moore 		return -ENOMEM;
73717c157c8SThomas Graf 	data = genlmsg_put_reply(ans_skb, info, &netlbl_mgmt_gnl_family,
73817c157c8SThomas Graf 				 0, NLBL_MGMT_C_VERSION);
739fd385855SPaul Moore 	if (data == NULL)
740d15c345fSPaul Moore 		goto version_failure;
741d15c345fSPaul Moore 
742fd385855SPaul Moore 	ret_val = nla_put_u32(ans_skb,
743fd385855SPaul Moore 			      NLBL_MGMT_A_VERSION,
744fd385855SPaul Moore 			      NETLBL_PROTO_VERSION);
745d15c345fSPaul Moore 	if (ret_val != 0)
746d15c345fSPaul Moore 		goto version_failure;
747d15c345fSPaul Moore 
748fd385855SPaul Moore 	genlmsg_end(ans_skb, data);
749fe785beeSDenis V. Lunev 	return genlmsg_reply(ans_skb, info);
750d15c345fSPaul Moore 
751d15c345fSPaul Moore version_failure:
752d15c345fSPaul Moore 	kfree_skb(ans_skb);
753d15c345fSPaul Moore 	return ret_val;
754d15c345fSPaul Moore }
755d15c345fSPaul Moore 
756d15c345fSPaul Moore 
757d15c345fSPaul Moore /*
758d15c345fSPaul Moore  * NetLabel Generic NETLINK Command Definitions
759d15c345fSPaul Moore  */
760d15c345fSPaul Moore 
76166a9b928SJakub Kicinski static const struct genl_small_ops netlbl_mgmt_genl_ops[] = {
762227c43c3SPavel Emelyanov 	{
763d15c345fSPaul Moore 	.cmd = NLBL_MGMT_C_ADD,
764ef6243acSJohannes Berg 	.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
765fd385855SPaul Moore 	.flags = GENL_ADMIN_PERM,
766d15c345fSPaul Moore 	.doit = netlbl_mgmt_add,
767d15c345fSPaul Moore 	.dumpit = NULL,
768227c43c3SPavel Emelyanov 	},
769227c43c3SPavel Emelyanov 	{
770d15c345fSPaul Moore 	.cmd = NLBL_MGMT_C_REMOVE,
771ef6243acSJohannes Berg 	.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
772fd385855SPaul Moore 	.flags = GENL_ADMIN_PERM,
773d15c345fSPaul Moore 	.doit = netlbl_mgmt_remove,
774d15c345fSPaul Moore 	.dumpit = NULL,
775227c43c3SPavel Emelyanov 	},
776227c43c3SPavel Emelyanov 	{
777fd385855SPaul Moore 	.cmd = NLBL_MGMT_C_LISTALL,
778ef6243acSJohannes Berg 	.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
779d15c345fSPaul Moore 	.flags = 0,
780fd385855SPaul Moore 	.doit = NULL,
781fd385855SPaul Moore 	.dumpit = netlbl_mgmt_listall,
782227c43c3SPavel Emelyanov 	},
783227c43c3SPavel Emelyanov 	{
784d15c345fSPaul Moore 	.cmd = NLBL_MGMT_C_ADDDEF,
785ef6243acSJohannes Berg 	.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
786fd385855SPaul Moore 	.flags = GENL_ADMIN_PERM,
787d15c345fSPaul Moore 	.doit = netlbl_mgmt_adddef,
788d15c345fSPaul Moore 	.dumpit = NULL,
789227c43c3SPavel Emelyanov 	},
790227c43c3SPavel Emelyanov 	{
791d15c345fSPaul Moore 	.cmd = NLBL_MGMT_C_REMOVEDEF,
792ef6243acSJohannes Berg 	.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
793fd385855SPaul Moore 	.flags = GENL_ADMIN_PERM,
794d15c345fSPaul Moore 	.doit = netlbl_mgmt_removedef,
795d15c345fSPaul Moore 	.dumpit = NULL,
796227c43c3SPavel Emelyanov 	},
797227c43c3SPavel Emelyanov 	{
798d15c345fSPaul Moore 	.cmd = NLBL_MGMT_C_LISTDEF,
799ef6243acSJohannes Berg 	.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
800d15c345fSPaul Moore 	.flags = 0,
801d15c345fSPaul Moore 	.doit = netlbl_mgmt_listdef,
802d15c345fSPaul Moore 	.dumpit = NULL,
803227c43c3SPavel Emelyanov 	},
804227c43c3SPavel Emelyanov 	{
805fd385855SPaul Moore 	.cmd = NLBL_MGMT_C_PROTOCOLS,
806ef6243acSJohannes Berg 	.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
807d15c345fSPaul Moore 	.flags = 0,
808fd385855SPaul Moore 	.doit = NULL,
809fd385855SPaul Moore 	.dumpit = netlbl_mgmt_protocols,
810227c43c3SPavel Emelyanov 	},
811227c43c3SPavel Emelyanov 	{
812d15c345fSPaul Moore 	.cmd = NLBL_MGMT_C_VERSION,
813ef6243acSJohannes Berg 	.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
814d15c345fSPaul Moore 	.flags = 0,
815d15c345fSPaul Moore 	.doit = netlbl_mgmt_version,
816d15c345fSPaul Moore 	.dumpit = NULL,
817227c43c3SPavel Emelyanov 	},
818d15c345fSPaul Moore };
819d15c345fSPaul Moore 
82056989f6dSJohannes Berg static struct genl_family netlbl_mgmt_gnl_family __ro_after_init = {
821489111e5SJohannes Berg 	.hdrsize = 0,
822489111e5SJohannes Berg 	.name = NETLBL_NLTYPE_MGMT_NAME,
823489111e5SJohannes Berg 	.version = NETLBL_PROTO_VERSION,
824489111e5SJohannes Berg 	.maxattr = NLBL_MGMT_A_MAX,
8253b0f31f2SJohannes Berg 	.policy = netlbl_mgmt_genl_policy,
826489111e5SJohannes Berg 	.module = THIS_MODULE,
82766a9b928SJakub Kicinski 	.small_ops = netlbl_mgmt_genl_ops,
82866a9b928SJakub Kicinski 	.n_small_ops = ARRAY_SIZE(netlbl_mgmt_genl_ops),
829*9c5d03d3SJakub Kicinski 	.resv_start_op = NLBL_MGMT_C_VERSION + 1,
830489111e5SJohannes Berg };
831489111e5SJohannes Berg 
832d15c345fSPaul Moore /*
833d15c345fSPaul Moore  * NetLabel Generic NETLINK Protocol Functions
834d15c345fSPaul Moore  */
835d15c345fSPaul Moore 
836d15c345fSPaul Moore /**
837d15c345fSPaul Moore  * netlbl_mgmt_genl_init - Register the NetLabel management component
838d15c345fSPaul Moore  *
839d15c345fSPaul Moore  * Description:
840d15c345fSPaul Moore  * Register the NetLabel management component with the Generic NETLINK
841d15c345fSPaul Moore  * mechanism.  Returns zero on success, negative values on failure.
842d15c345fSPaul Moore  *
843d15c345fSPaul Moore  */
netlbl_mgmt_genl_init(void)84405705e4eSPavel Emelyanov int __init netlbl_mgmt_genl_init(void)
845d15c345fSPaul Moore {
846489111e5SJohannes Berg 	return genl_register_family(&netlbl_mgmt_gnl_family);
847d15c345fSPaul Moore }
848