xref: /openbmc/linux/net/netlabel/netlabel_cipso_v4.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
11ccea77eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
296cb8e33SPaul Moore /*
396cb8e33SPaul Moore  * NetLabel CIPSO/IPv4 Support
496cb8e33SPaul Moore  *
596cb8e33SPaul Moore  * This file defines the CIPSO/IPv4 functions for the NetLabel system.  The
696cb8e33SPaul Moore  * NetLabel system manages static and dynamic label mappings for network
796cb8e33SPaul Moore  * protocols such as CIPSO and RIPSO.
896cb8e33SPaul Moore  *
982c21bfaSPaul Moore  * Author: Paul Moore <paul@paul-moore.com>
1096cb8e33SPaul Moore  */
1196cb8e33SPaul Moore 
1296cb8e33SPaul Moore /*
1396cb8e33SPaul Moore  * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
1496cb8e33SPaul Moore  */
1596cb8e33SPaul Moore 
1696cb8e33SPaul Moore #include <linux/types.h>
1796cb8e33SPaul Moore #include <linux/socket.h>
1896cb8e33SPaul Moore #include <linux/string.h>
1996cb8e33SPaul Moore #include <linux/skbuff.h>
2032f50cdeSPaul Moore #include <linux/audit.h>
215a0e3ad6STejun Heo #include <linux/slab.h>
2296cb8e33SPaul Moore #include <net/sock.h>
2396cb8e33SPaul Moore #include <net/netlink.h>
2496cb8e33SPaul Moore #include <net/genetlink.h>
2596cb8e33SPaul Moore #include <net/netlabel.h>
2696cb8e33SPaul Moore #include <net/cipso_ipv4.h>
2760063497SArun Sharma #include <linux/atomic.h>
2896cb8e33SPaul Moore 
2996cb8e33SPaul Moore #include "netlabel_user.h"
3096cb8e33SPaul Moore #include "netlabel_cipso_v4.h"
3123bcdc1aSPaul Moore #include "netlabel_mgmt.h"
32b1edeb10SPaul Moore #include "netlabel_domainhash.h"
3396cb8e33SPaul Moore 
34fd385855SPaul Moore /* Argument struct for cipso_v4_doi_walk() */
35fd385855SPaul Moore struct netlbl_cipsov4_doiwalk_arg {
36fd385855SPaul Moore 	struct netlink_callback *nl_cb;
37fd385855SPaul Moore 	struct sk_buff *skb;
38fd385855SPaul Moore 	u32 seq;
39fd385855SPaul Moore };
40fd385855SPaul Moore 
41b1edeb10SPaul Moore /* Argument struct for netlbl_domhsh_walk() */
42b1edeb10SPaul Moore struct netlbl_domhsh_walk_arg {
43b1edeb10SPaul Moore 	struct netlbl_audit *audit_info;
44b1edeb10SPaul Moore 	u32 doi;
45b1edeb10SPaul Moore };
46b1edeb10SPaul Moore 
4796cb8e33SPaul Moore /* NetLabel Generic NETLINK CIPSOv4 family */
48489111e5SJohannes Berg static struct genl_family netlbl_cipsov4_gnl_family;
49fd385855SPaul Moore /* NetLabel Netlink attribute policy */
50ef7c79edSPatrick McHardy static const struct nla_policy netlbl_cipsov4_genl_policy[NLBL_CIPSOV4_A_MAX + 1] = {
51fd385855SPaul Moore 	[NLBL_CIPSOV4_A_DOI] = { .type = NLA_U32 },
52fd385855SPaul Moore 	[NLBL_CIPSOV4_A_MTYPE] = { .type = NLA_U32 },
53fd385855SPaul Moore 	[NLBL_CIPSOV4_A_TAG] = { .type = NLA_U8 },
54fd385855SPaul Moore 	[NLBL_CIPSOV4_A_TAGLST] = { .type = NLA_NESTED },
55fd385855SPaul Moore 	[NLBL_CIPSOV4_A_MLSLVLLOC] = { .type = NLA_U32 },
56fd385855SPaul Moore 	[NLBL_CIPSOV4_A_MLSLVLREM] = { .type = NLA_U32 },
57fd385855SPaul Moore 	[NLBL_CIPSOV4_A_MLSLVL] = { .type = NLA_NESTED },
58fd385855SPaul Moore 	[NLBL_CIPSOV4_A_MLSLVLLST] = { .type = NLA_NESTED },
59fd385855SPaul Moore 	[NLBL_CIPSOV4_A_MLSCATLOC] = { .type = NLA_U32 },
60fd385855SPaul Moore 	[NLBL_CIPSOV4_A_MLSCATREM] = { .type = NLA_U32 },
61fd385855SPaul Moore 	[NLBL_CIPSOV4_A_MLSCAT] = { .type = NLA_NESTED },
62fd385855SPaul Moore 	[NLBL_CIPSOV4_A_MLSCATLST] = { .type = NLA_NESTED },
63fd385855SPaul Moore };
6496cb8e33SPaul Moore 
6596cb8e33SPaul Moore /*
6696cb8e33SPaul Moore  * Helper Functions
6796cb8e33SPaul Moore  */
6896cb8e33SPaul Moore 
6996cb8e33SPaul Moore /**
70fd385855SPaul Moore  * netlbl_cipsov4_add_common - Parse the common sections of a ADD message
71fd385855SPaul Moore  * @info: the Generic NETLINK info block
72fd385855SPaul Moore  * @doi_def: the CIPSO V4 DOI definition
73fd385855SPaul Moore  *
74fd385855SPaul Moore  * Description:
75fd385855SPaul Moore  * Parse the common sections of a ADD message and fill in the related values
76fd385855SPaul Moore  * in @doi_def.  Returns zero on success, negative values on failure.
77fd385855SPaul Moore  *
78fd385855SPaul Moore  */
netlbl_cipsov4_add_common(struct genl_info * info,struct cipso_v4_doi * doi_def)79fd385855SPaul Moore static int netlbl_cipsov4_add_common(struct genl_info *info,
80fd385855SPaul Moore 				     struct cipso_v4_doi *doi_def)
81fd385855SPaul Moore {
82fd385855SPaul Moore 	struct nlattr *nla;
83fd385855SPaul Moore 	int nla_rem;
84fd385855SPaul Moore 	u32 iter = 0;
85fd385855SPaul Moore 
86fd385855SPaul Moore 	doi_def->doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
87fd385855SPaul Moore 
888cb08174SJohannes Berg 	if (nla_validate_nested_deprecated(info->attrs[NLBL_CIPSOV4_A_TAGLST],
89fd385855SPaul Moore 					   NLBL_CIPSOV4_A_MAX,
908cb08174SJohannes Berg 					   netlbl_cipsov4_genl_policy,
918cb08174SJohannes Berg 					   NULL) != 0)
92fd385855SPaul Moore 		return -EINVAL;
93fd385855SPaul Moore 
94fd385855SPaul Moore 	nla_for_each_nested(nla, info->attrs[NLBL_CIPSOV4_A_TAGLST], nla_rem)
958f4c1f9bSThomas Graf 		if (nla_type(nla) == NLBL_CIPSOV4_A_TAG) {
962a2f11c2SPaul Moore 			if (iter >= CIPSO_V4_TAG_MAXCNT)
97fd385855SPaul Moore 				return -EINVAL;
98fd385855SPaul Moore 			doi_def->tags[iter++] = nla_get_u8(nla);
99fd385855SPaul Moore 		}
1002a2f11c2SPaul Moore 	while (iter < CIPSO_V4_TAG_MAXCNT)
1012a2f11c2SPaul Moore 		doi_def->tags[iter++] = CIPSO_V4_TAG_INVALID;
102fd385855SPaul Moore 
103fd385855SPaul Moore 	return 0;
104fd385855SPaul Moore }
10596cb8e33SPaul Moore 
10696cb8e33SPaul Moore /*
10796cb8e33SPaul Moore  * NetLabel Command Handlers
10896cb8e33SPaul Moore  */
10996cb8e33SPaul Moore 
11096cb8e33SPaul Moore /**
11196cb8e33SPaul Moore  * netlbl_cipsov4_add_std - Adds a CIPSO V4 DOI definition
112fd385855SPaul Moore  * @info: the Generic NETLINK info block
1136c2e8ac0SPaul Moore  * @audit_info: NetLabel audit information
11496cb8e33SPaul Moore  *
11596cb8e33SPaul Moore  * Description:
11615c45f7bSPaul Moore  * Create a new CIPSO_V4_MAP_TRANS DOI definition based on the given ADD
11715c45f7bSPaul Moore  * message and add it to the CIPSO V4 engine.  Return zero on success and
11815c45f7bSPaul Moore  * non-zero on error.
11996cb8e33SPaul Moore  *
12096cb8e33SPaul Moore  */
netlbl_cipsov4_add_std(struct genl_info * info,struct netlbl_audit * audit_info)1216c2e8ac0SPaul Moore static int netlbl_cipsov4_add_std(struct genl_info *info,
1226c2e8ac0SPaul Moore 				  struct netlbl_audit *audit_info)
12396cb8e33SPaul Moore {
12496cb8e33SPaul Moore 	int ret_val = -EINVAL;
12596cb8e33SPaul Moore 	struct cipso_v4_doi *doi_def = NULL;
126fd385855SPaul Moore 	struct nlattr *nla_a;
127fd385855SPaul Moore 	struct nlattr *nla_b;
128fd385855SPaul Moore 	int nla_a_rem;
129fd385855SPaul Moore 	int nla_b_rem;
130caff5b6aSPaul Moore 	u32 iter;
13196cb8e33SPaul Moore 
13232f50cdeSPaul Moore 	if (!info->attrs[NLBL_CIPSOV4_A_TAGLST] ||
133fd385855SPaul Moore 	    !info->attrs[NLBL_CIPSOV4_A_MLSLVLLST])
134fd385855SPaul Moore 		return -EINVAL;
135fd385855SPaul Moore 
1368cb08174SJohannes Berg 	if (nla_validate_nested_deprecated(info->attrs[NLBL_CIPSOV4_A_MLSLVLLST],
137fd385855SPaul Moore 					   NLBL_CIPSOV4_A_MAX,
1388cb08174SJohannes Berg 					   netlbl_cipsov4_genl_policy,
1398cb08174SJohannes Berg 					   NULL) != 0)
140fd385855SPaul Moore 		return -EINVAL;
14196cb8e33SPaul Moore 
14296cb8e33SPaul Moore 	doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
143fd385855SPaul Moore 	if (doi_def == NULL)
144fd385855SPaul Moore 		return -ENOMEM;
14596cb8e33SPaul Moore 	doi_def->map.std = kzalloc(sizeof(*doi_def->map.std), GFP_KERNEL);
14696cb8e33SPaul Moore 	if (doi_def->map.std == NULL) {
147e842cb60S王贇 		kfree(doi_def);
148e842cb60S王贇 		return -ENOMEM;
14996cb8e33SPaul Moore 	}
15015c45f7bSPaul Moore 	doi_def->type = CIPSO_V4_MAP_TRANS;
15196cb8e33SPaul Moore 
152fd385855SPaul Moore 	ret_val = netlbl_cipsov4_add_common(info, doi_def);
153fd385855SPaul Moore 	if (ret_val != 0)
15496cb8e33SPaul Moore 		goto add_std_failure;
1551fd2a25bSPaul Moore 	ret_val = -EINVAL;
156fd385855SPaul Moore 
157fd385855SPaul Moore 	nla_for_each_nested(nla_a,
158fd385855SPaul Moore 			    info->attrs[NLBL_CIPSOV4_A_MLSLVLLST],
159fd385855SPaul Moore 			    nla_a_rem)
1608f4c1f9bSThomas Graf 		if (nla_type(nla_a) == NLBL_CIPSOV4_A_MLSLVL) {
1618cb08174SJohannes Berg 			if (nla_validate_nested_deprecated(nla_a,
1628cb08174SJohannes Berg 							   NLBL_CIPSOV4_A_MAX,
163fceb6435SJohannes Berg 							   netlbl_cipsov4_genl_policy,
164fceb6435SJohannes Berg 							   NULL) != 0)
1651fd2a25bSPaul Moore 				goto add_std_failure;
166fd385855SPaul Moore 			nla_for_each_nested(nla_b, nla_a, nla_b_rem)
1678f4c1f9bSThomas Graf 				switch (nla_type(nla_b)) {
168fd385855SPaul Moore 				case NLBL_CIPSOV4_A_MLSLVLLOC:
1691fd2a25bSPaul Moore 					if (nla_get_u32(nla_b) >
1701fd2a25bSPaul Moore 					    CIPSO_V4_MAX_LOC_LVLS)
1711fd2a25bSPaul Moore 						goto add_std_failure;
172fd385855SPaul Moore 					if (nla_get_u32(nla_b) >=
173fd385855SPaul Moore 					    doi_def->map.std->lvl.local_size)
174fd385855SPaul Moore 					     doi_def->map.std->lvl.local_size =
175fd385855SPaul Moore 						     nla_get_u32(nla_b) + 1;
17696cb8e33SPaul Moore 					break;
177fd385855SPaul Moore 				case NLBL_CIPSOV4_A_MLSLVLREM:
1781fd2a25bSPaul Moore 					if (nla_get_u32(nla_b) >
1791fd2a25bSPaul Moore 					    CIPSO_V4_MAX_REM_LVLS)
1801fd2a25bSPaul Moore 						goto add_std_failure;
181fd385855SPaul Moore 					if (nla_get_u32(nla_b) >=
182fd385855SPaul Moore 					    doi_def->map.std->lvl.cipso_size)
183fd385855SPaul Moore 					     doi_def->map.std->lvl.cipso_size =
184fd385855SPaul Moore 						     nla_get_u32(nla_b) + 1;
185fd385855SPaul Moore 					break;
18696cb8e33SPaul Moore 				}
18796cb8e33SPaul Moore 		}
18896cb8e33SPaul Moore 	doi_def->map.std->lvl.local = kcalloc(doi_def->map.std->lvl.local_size,
18996cb8e33SPaul Moore 					      sizeof(u32),
1908ca34a13SPavel Skripkin 					      GFP_KERNEL | __GFP_NOWARN);
19196cb8e33SPaul Moore 	if (doi_def->map.std->lvl.local == NULL) {
19296cb8e33SPaul Moore 		ret_val = -ENOMEM;
19396cb8e33SPaul Moore 		goto add_std_failure;
19496cb8e33SPaul Moore 	}
19596cb8e33SPaul Moore 	doi_def->map.std->lvl.cipso = kcalloc(doi_def->map.std->lvl.cipso_size,
19696cb8e33SPaul Moore 					      sizeof(u32),
1978ca34a13SPavel Skripkin 					      GFP_KERNEL | __GFP_NOWARN);
19896cb8e33SPaul Moore 	if (doi_def->map.std->lvl.cipso == NULL) {
19996cb8e33SPaul Moore 		ret_val = -ENOMEM;
20096cb8e33SPaul Moore 		goto add_std_failure;
20196cb8e33SPaul Moore 	}
202caff5b6aSPaul Moore 	for (iter = 0; iter < doi_def->map.std->lvl.local_size; iter++)
203caff5b6aSPaul Moore 		doi_def->map.std->lvl.local[iter] = CIPSO_V4_INV_LVL;
204caff5b6aSPaul Moore 	for (iter = 0; iter < doi_def->map.std->lvl.cipso_size; iter++)
205caff5b6aSPaul Moore 		doi_def->map.std->lvl.cipso[iter] = CIPSO_V4_INV_LVL;
206fd385855SPaul Moore 	nla_for_each_nested(nla_a,
207fd385855SPaul Moore 			    info->attrs[NLBL_CIPSOV4_A_MLSLVLLST],
208fd385855SPaul Moore 			    nla_a_rem)
2098f4c1f9bSThomas Graf 		if (nla_type(nla_a) == NLBL_CIPSOV4_A_MLSLVL) {
210fd385855SPaul Moore 			struct nlattr *lvl_loc;
211fd385855SPaul Moore 			struct nlattr *lvl_rem;
21296cb8e33SPaul Moore 
213fd385855SPaul Moore 			lvl_loc = nla_find_nested(nla_a,
214fd385855SPaul Moore 						  NLBL_CIPSOV4_A_MLSLVLLOC);
215fd385855SPaul Moore 			lvl_rem = nla_find_nested(nla_a,
216fd385855SPaul Moore 						  NLBL_CIPSOV4_A_MLSLVLREM);
217fd385855SPaul Moore 			if (lvl_loc == NULL || lvl_rem == NULL)
218fd385855SPaul Moore 				goto add_std_failure;
219fd385855SPaul Moore 			doi_def->map.std->lvl.local[nla_get_u32(lvl_loc)] =
220fd385855SPaul Moore 				nla_get_u32(lvl_rem);
221fd385855SPaul Moore 			doi_def->map.std->lvl.cipso[nla_get_u32(lvl_rem)] =
222fd385855SPaul Moore 				nla_get_u32(lvl_loc);
223fd385855SPaul Moore 		}
224fd385855SPaul Moore 
225fd385855SPaul Moore 	if (info->attrs[NLBL_CIPSOV4_A_MLSCATLST]) {
2268cb08174SJohannes Berg 		if (nla_validate_nested_deprecated(info->attrs[NLBL_CIPSOV4_A_MLSCATLST],
227fd385855SPaul Moore 						   NLBL_CIPSOV4_A_MAX,
2288cb08174SJohannes Berg 						   netlbl_cipsov4_genl_policy,
2298cb08174SJohannes Berg 						   NULL) != 0)
230fd385855SPaul Moore 			goto add_std_failure;
231fd385855SPaul Moore 
232fd385855SPaul Moore 		nla_for_each_nested(nla_a,
233fd385855SPaul Moore 				    info->attrs[NLBL_CIPSOV4_A_MLSCATLST],
234fd385855SPaul Moore 				    nla_a_rem)
2358f4c1f9bSThomas Graf 			if (nla_type(nla_a) == NLBL_CIPSOV4_A_MLSCAT) {
2368cb08174SJohannes Berg 				if (nla_validate_nested_deprecated(nla_a,
237fd385855SPaul Moore 								   NLBL_CIPSOV4_A_MAX,
238fceb6435SJohannes Berg 								   netlbl_cipsov4_genl_policy,
239fceb6435SJohannes Berg 								   NULL) != 0)
240fd385855SPaul Moore 					goto add_std_failure;
241fd385855SPaul Moore 				nla_for_each_nested(nla_b, nla_a, nla_b_rem)
2428f4c1f9bSThomas Graf 					switch (nla_type(nla_b)) {
243fd385855SPaul Moore 					case NLBL_CIPSOV4_A_MLSCATLOC:
2441fd2a25bSPaul Moore 						if (nla_get_u32(nla_b) >
2451fd2a25bSPaul Moore 						    CIPSO_V4_MAX_LOC_CATS)
2461fd2a25bSPaul Moore 							goto add_std_failure;
247fd385855SPaul Moore 						if (nla_get_u32(nla_b) >=
248fd385855SPaul Moore 					      doi_def->map.std->cat.local_size)
249fd385855SPaul Moore 					     doi_def->map.std->cat.local_size =
250fd385855SPaul Moore 						     nla_get_u32(nla_b) + 1;
251fd385855SPaul Moore 						break;
252fd385855SPaul Moore 					case NLBL_CIPSOV4_A_MLSCATREM:
2531fd2a25bSPaul Moore 						if (nla_get_u32(nla_b) >
2541fd2a25bSPaul Moore 						    CIPSO_V4_MAX_REM_CATS)
2551fd2a25bSPaul Moore 							goto add_std_failure;
256fd385855SPaul Moore 						if (nla_get_u32(nla_b) >=
257fd385855SPaul Moore 					      doi_def->map.std->cat.cipso_size)
258fd385855SPaul Moore 					     doi_def->map.std->cat.cipso_size =
259fd385855SPaul Moore 						     nla_get_u32(nla_b) + 1;
260fd385855SPaul Moore 						break;
261fd385855SPaul Moore 					}
262fd385855SPaul Moore 			}
263fd385855SPaul Moore 		doi_def->map.std->cat.local = kcalloc(
264fd385855SPaul Moore 					      doi_def->map.std->cat.local_size,
26596cb8e33SPaul Moore 					      sizeof(u32),
2668ca34a13SPavel Skripkin 					      GFP_KERNEL | __GFP_NOWARN);
26796cb8e33SPaul Moore 		if (doi_def->map.std->cat.local == NULL) {
26896cb8e33SPaul Moore 			ret_val = -ENOMEM;
26996cb8e33SPaul Moore 			goto add_std_failure;
27096cb8e33SPaul Moore 		}
271fd385855SPaul Moore 		doi_def->map.std->cat.cipso = kcalloc(
272fd385855SPaul Moore 					      doi_def->map.std->cat.cipso_size,
27396cb8e33SPaul Moore 					      sizeof(u32),
2748ca34a13SPavel Skripkin 					      GFP_KERNEL | __GFP_NOWARN);
27596cb8e33SPaul Moore 		if (doi_def->map.std->cat.cipso == NULL) {
27696cb8e33SPaul Moore 			ret_val = -ENOMEM;
27796cb8e33SPaul Moore 			goto add_std_failure;
27896cb8e33SPaul Moore 		}
279caff5b6aSPaul Moore 		for (iter = 0; iter < doi_def->map.std->cat.local_size; iter++)
280caff5b6aSPaul Moore 			doi_def->map.std->cat.local[iter] = CIPSO_V4_INV_CAT;
281caff5b6aSPaul Moore 		for (iter = 0; iter < doi_def->map.std->cat.cipso_size; iter++)
282caff5b6aSPaul Moore 			doi_def->map.std->cat.cipso[iter] = CIPSO_V4_INV_CAT;
283fd385855SPaul Moore 		nla_for_each_nested(nla_a,
284fd385855SPaul Moore 				    info->attrs[NLBL_CIPSOV4_A_MLSCATLST],
285fd385855SPaul Moore 				    nla_a_rem)
2868f4c1f9bSThomas Graf 			if (nla_type(nla_a) == NLBL_CIPSOV4_A_MLSCAT) {
287fd385855SPaul Moore 				struct nlattr *cat_loc;
288fd385855SPaul Moore 				struct nlattr *cat_rem;
28996cb8e33SPaul Moore 
290fd385855SPaul Moore 				cat_loc = nla_find_nested(nla_a,
291fd385855SPaul Moore 						     NLBL_CIPSOV4_A_MLSCATLOC);
292fd385855SPaul Moore 				cat_rem = nla_find_nested(nla_a,
293fd385855SPaul Moore 						     NLBL_CIPSOV4_A_MLSCATREM);
294fd385855SPaul Moore 				if (cat_loc == NULL || cat_rem == NULL)
29596cb8e33SPaul Moore 					goto add_std_failure;
296fd385855SPaul Moore 				doi_def->map.std->cat.local[
297fd385855SPaul Moore 							nla_get_u32(cat_loc)] =
298fd385855SPaul Moore 					nla_get_u32(cat_rem);
299fd385855SPaul Moore 				doi_def->map.std->cat.cipso[
300fd385855SPaul Moore 							nla_get_u32(cat_rem)] =
301fd385855SPaul Moore 					nla_get_u32(cat_loc);
302fd385855SPaul Moore 			}
30396cb8e33SPaul Moore 	}
30496cb8e33SPaul Moore 
3056c2e8ac0SPaul Moore 	ret_val = cipso_v4_doi_add(doi_def, audit_info);
30696cb8e33SPaul Moore 	if (ret_val != 0)
30796cb8e33SPaul Moore 		goto add_std_failure;
30896cb8e33SPaul Moore 	return 0;
30996cb8e33SPaul Moore 
31096cb8e33SPaul Moore add_std_failure:
311b1edeb10SPaul Moore 	cipso_v4_doi_free(doi_def);
31296cb8e33SPaul Moore 	return ret_val;
31396cb8e33SPaul Moore }
31496cb8e33SPaul Moore 
31596cb8e33SPaul Moore /**
31696cb8e33SPaul Moore  * netlbl_cipsov4_add_pass - Adds a CIPSO V4 DOI definition
317fd385855SPaul Moore  * @info: the Generic NETLINK info block
3186c2e8ac0SPaul Moore  * @audit_info: NetLabel audit information
31996cb8e33SPaul Moore  *
32096cb8e33SPaul Moore  * Description:
32196cb8e33SPaul Moore  * Create a new CIPSO_V4_MAP_PASS DOI definition based on the given ADD message
32296cb8e33SPaul Moore  * and add it to the CIPSO V4 engine.  Return zero on success and non-zero on
32396cb8e33SPaul Moore  * error.
32496cb8e33SPaul Moore  *
32596cb8e33SPaul Moore  */
netlbl_cipsov4_add_pass(struct genl_info * info,struct netlbl_audit * audit_info)3266c2e8ac0SPaul Moore static int netlbl_cipsov4_add_pass(struct genl_info *info,
3276c2e8ac0SPaul Moore 				   struct netlbl_audit *audit_info)
32896cb8e33SPaul Moore {
329fd385855SPaul Moore 	int ret_val;
33096cb8e33SPaul Moore 	struct cipso_v4_doi *doi_def = NULL;
33196cb8e33SPaul Moore 
33232f50cdeSPaul Moore 	if (!info->attrs[NLBL_CIPSOV4_A_TAGLST])
333fd385855SPaul Moore 		return -EINVAL;
33496cb8e33SPaul Moore 
33596cb8e33SPaul Moore 	doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
336fd385855SPaul Moore 	if (doi_def == NULL)
337fd385855SPaul Moore 		return -ENOMEM;
33896cb8e33SPaul Moore 	doi_def->type = CIPSO_V4_MAP_PASS;
33996cb8e33SPaul Moore 
340fd385855SPaul Moore 	ret_val = netlbl_cipsov4_add_common(info, doi_def);
341fd385855SPaul Moore 	if (ret_val != 0)
34296cb8e33SPaul Moore 		goto add_pass_failure;
34396cb8e33SPaul Moore 
3446c2e8ac0SPaul Moore 	ret_val = cipso_v4_doi_add(doi_def, audit_info);
34596cb8e33SPaul Moore 	if (ret_val != 0)
34696cb8e33SPaul Moore 		goto add_pass_failure;
34796cb8e33SPaul Moore 	return 0;
34896cb8e33SPaul Moore 
34996cb8e33SPaul Moore add_pass_failure:
350b1edeb10SPaul Moore 	cipso_v4_doi_free(doi_def);
35196cb8e33SPaul Moore 	return ret_val;
35296cb8e33SPaul Moore }
35396cb8e33SPaul Moore 
35496cb8e33SPaul Moore /**
355d91d4079SPaul Moore  * netlbl_cipsov4_add_local - Adds a CIPSO V4 DOI definition
356d91d4079SPaul Moore  * @info: the Generic NETLINK info block
3576c2e8ac0SPaul Moore  * @audit_info: NetLabel audit information
358d91d4079SPaul Moore  *
359d91d4079SPaul Moore  * Description:
360d91d4079SPaul Moore  * Create a new CIPSO_V4_MAP_LOCAL DOI definition based on the given ADD
361d91d4079SPaul Moore  * message and add it to the CIPSO V4 engine.  Return zero on success and
362d91d4079SPaul Moore  * non-zero on error.
363d91d4079SPaul Moore  *
364d91d4079SPaul Moore  */
netlbl_cipsov4_add_local(struct genl_info * info,struct netlbl_audit * audit_info)3656c2e8ac0SPaul Moore static int netlbl_cipsov4_add_local(struct genl_info *info,
3666c2e8ac0SPaul Moore 				    struct netlbl_audit *audit_info)
367d91d4079SPaul Moore {
368d91d4079SPaul Moore 	int ret_val;
369d91d4079SPaul Moore 	struct cipso_v4_doi *doi_def = NULL;
370d91d4079SPaul Moore 
371d91d4079SPaul Moore 	if (!info->attrs[NLBL_CIPSOV4_A_TAGLST])
372d91d4079SPaul Moore 		return -EINVAL;
373d91d4079SPaul Moore 
374d91d4079SPaul Moore 	doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
375d91d4079SPaul Moore 	if (doi_def == NULL)
376d91d4079SPaul Moore 		return -ENOMEM;
377d91d4079SPaul Moore 	doi_def->type = CIPSO_V4_MAP_LOCAL;
378d91d4079SPaul Moore 
379d91d4079SPaul Moore 	ret_val = netlbl_cipsov4_add_common(info, doi_def);
380d91d4079SPaul Moore 	if (ret_val != 0)
381d91d4079SPaul Moore 		goto add_local_failure;
382d91d4079SPaul Moore 
3836c2e8ac0SPaul Moore 	ret_val = cipso_v4_doi_add(doi_def, audit_info);
384d91d4079SPaul Moore 	if (ret_val != 0)
385d91d4079SPaul Moore 		goto add_local_failure;
386d91d4079SPaul Moore 	return 0;
387d91d4079SPaul Moore 
388d91d4079SPaul Moore add_local_failure:
389d91d4079SPaul Moore 	cipso_v4_doi_free(doi_def);
390d91d4079SPaul Moore 	return ret_val;
391d91d4079SPaul Moore }
392d91d4079SPaul Moore 
393d91d4079SPaul Moore /**
39496cb8e33SPaul Moore  * netlbl_cipsov4_add - Handle an ADD message
39596cb8e33SPaul Moore  * @skb: the NETLINK buffer
39696cb8e33SPaul Moore  * @info: the Generic NETLINK info block
39796cb8e33SPaul Moore  *
39896cb8e33SPaul Moore  * Description:
39996cb8e33SPaul Moore  * Create a new DOI definition based on the given ADD message and add it to the
40096cb8e33SPaul Moore  * CIPSO V4 engine.  Returns zero on success, negative values on failure.
40196cb8e33SPaul Moore  *
40296cb8e33SPaul Moore  */
netlbl_cipsov4_add(struct sk_buff * skb,struct genl_info * info)40396cb8e33SPaul Moore static int netlbl_cipsov4_add(struct sk_buff *skb, struct genl_info *info)
40496cb8e33SPaul Moore 
40596cb8e33SPaul Moore {
40696cb8e33SPaul Moore 	int ret_val = -EINVAL;
40795d4e6beSPaul Moore 	struct netlbl_audit audit_info;
40896cb8e33SPaul Moore 
40932f50cdeSPaul Moore 	if (!info->attrs[NLBL_CIPSOV4_A_DOI] ||
41032f50cdeSPaul Moore 	    !info->attrs[NLBL_CIPSOV4_A_MTYPE])
411fd385855SPaul Moore 		return -EINVAL;
41296cb8e33SPaul Moore 
413f7e0318aSZheng Yejian 	netlbl_netlink_auditinfo(&audit_info);
4146c2e8ac0SPaul Moore 	switch (nla_get_u32(info->attrs[NLBL_CIPSOV4_A_MTYPE])) {
41515c45f7bSPaul Moore 	case CIPSO_V4_MAP_TRANS:
4166c2e8ac0SPaul Moore 		ret_val = netlbl_cipsov4_add_std(info, &audit_info);
41796cb8e33SPaul Moore 		break;
41896cb8e33SPaul Moore 	case CIPSO_V4_MAP_PASS:
4196c2e8ac0SPaul Moore 		ret_val = netlbl_cipsov4_add_pass(info, &audit_info);
42096cb8e33SPaul Moore 		break;
421d91d4079SPaul Moore 	case CIPSO_V4_MAP_LOCAL:
4226c2e8ac0SPaul Moore 		ret_val = netlbl_cipsov4_add_local(info, &audit_info);
423d91d4079SPaul Moore 		break;
42496cb8e33SPaul Moore 	}
42523bcdc1aSPaul Moore 	if (ret_val == 0)
426c783f1ceSPaul Moore 		atomic_inc(&netlabel_mgmt_protocount);
42796cb8e33SPaul Moore 
42896cb8e33SPaul Moore 	return ret_val;
42996cb8e33SPaul Moore }
43096cb8e33SPaul Moore 
43196cb8e33SPaul Moore /**
43296cb8e33SPaul Moore  * netlbl_cipsov4_list - Handle a LIST message
43396cb8e33SPaul Moore  * @skb: the NETLINK buffer
43496cb8e33SPaul Moore  * @info: the Generic NETLINK info block
43596cb8e33SPaul Moore  *
43696cb8e33SPaul Moore  * Description:
437fd385855SPaul Moore  * Process a user generated LIST message and respond accordingly.  While the
438fd385855SPaul Moore  * response message generated by the kernel is straightforward, determining
439fd385855SPaul Moore  * before hand the size of the buffer to allocate is not (we have to generate
440fd385855SPaul Moore  * the message to know the size).  In order to keep this function sane what we
441fd385855SPaul Moore  * do is allocate a buffer of NLMSG_GOODSIZE and try to fit the response in
442fd385855SPaul Moore  * that size, if we fail then we restart with a larger buffer and try again.
443fd385855SPaul Moore  * We continue in this manner until we hit a limit of failed attempts then we
444fd385855SPaul Moore  * give up and just send an error message.  Returns zero on success and
445fd385855SPaul Moore  * negative values on error.
44696cb8e33SPaul Moore  *
44796cb8e33SPaul Moore  */
netlbl_cipsov4_list(struct sk_buff * skb,struct genl_info * info)44896cb8e33SPaul Moore static int netlbl_cipsov4_list(struct sk_buff *skb, struct genl_info *info)
44996cb8e33SPaul Moore {
450fd385855SPaul Moore 	int ret_val;
451fd385855SPaul Moore 	struct sk_buff *ans_skb = NULL;
452fd385855SPaul Moore 	u32 nlsze_mult = 1;
453fd385855SPaul Moore 	void *data;
45496cb8e33SPaul Moore 	u32 doi;
455fd385855SPaul Moore 	struct nlattr *nla_a;
456fd385855SPaul Moore 	struct nlattr *nla_b;
457fd385855SPaul Moore 	struct cipso_v4_doi *doi_def;
458fd385855SPaul Moore 	u32 iter;
45996cb8e33SPaul Moore 
460fd385855SPaul Moore 	if (!info->attrs[NLBL_CIPSOV4_A_DOI]) {
461fd385855SPaul Moore 		ret_val = -EINVAL;
46296cb8e33SPaul Moore 		goto list_failure;
463fd385855SPaul Moore 	}
46496cb8e33SPaul Moore 
465fd385855SPaul Moore list_start:
466339bf98fSThomas Graf 	ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE * nlsze_mult, GFP_KERNEL);
46796cb8e33SPaul Moore 	if (ans_skb == NULL) {
46896cb8e33SPaul Moore 		ret_val = -ENOMEM;
46996cb8e33SPaul Moore 		goto list_failure;
47096cb8e33SPaul Moore 	}
47117c157c8SThomas Graf 	data = genlmsg_put_reply(ans_skb, info, &netlbl_cipsov4_gnl_family,
47217c157c8SThomas Graf 				 0, NLBL_CIPSOV4_C_LIST);
473fd385855SPaul Moore 	if (data == NULL) {
474fd385855SPaul Moore 		ret_val = -ENOMEM;
475fd385855SPaul Moore 		goto list_failure;
476fd385855SPaul Moore 	}
47796cb8e33SPaul Moore 
478fd385855SPaul Moore 	doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
479fd385855SPaul Moore 
480fd385855SPaul Moore 	rcu_read_lock();
481fd385855SPaul Moore 	doi_def = cipso_v4_doi_getdef(doi);
482fd385855SPaul Moore 	if (doi_def == NULL) {
483fd385855SPaul Moore 		ret_val = -EINVAL;
48456196701SPaul Moore 		goto list_failure_lock;
485fd385855SPaul Moore 	}
486fd385855SPaul Moore 
487fd385855SPaul Moore 	ret_val = nla_put_u32(ans_skb, NLBL_CIPSOV4_A_MTYPE, doi_def->type);
488fd385855SPaul Moore 	if (ret_val != 0)
489fd385855SPaul Moore 		goto list_failure_lock;
490fd385855SPaul Moore 
491ae0be8deSMichal Kubecek 	nla_a = nla_nest_start_noflag(ans_skb, NLBL_CIPSOV4_A_TAGLST);
492fd385855SPaul Moore 	if (nla_a == NULL) {
493fd385855SPaul Moore 		ret_val = -ENOMEM;
494fd385855SPaul Moore 		goto list_failure_lock;
495fd385855SPaul Moore 	}
496fd385855SPaul Moore 	for (iter = 0;
497fd385855SPaul Moore 	     iter < CIPSO_V4_TAG_MAXCNT &&
498fd385855SPaul Moore 	       doi_def->tags[iter] != CIPSO_V4_TAG_INVALID;
499fd385855SPaul Moore 	     iter++) {
500fd385855SPaul Moore 		ret_val = nla_put_u8(ans_skb,
501fd385855SPaul Moore 				     NLBL_CIPSOV4_A_TAG,
502fd385855SPaul Moore 				     doi_def->tags[iter]);
503fd385855SPaul Moore 		if (ret_val != 0)
504fd385855SPaul Moore 			goto list_failure_lock;
505fd385855SPaul Moore 	}
506fd385855SPaul Moore 	nla_nest_end(ans_skb, nla_a);
507fd385855SPaul Moore 
508fd385855SPaul Moore 	switch (doi_def->type) {
50915c45f7bSPaul Moore 	case CIPSO_V4_MAP_TRANS:
510ae0be8deSMichal Kubecek 		nla_a = nla_nest_start_noflag(ans_skb,
511ae0be8deSMichal Kubecek 					      NLBL_CIPSOV4_A_MLSLVLLST);
512fd385855SPaul Moore 		if (nla_a == NULL) {
513fd385855SPaul Moore 			ret_val = -ENOMEM;
514fd385855SPaul Moore 			goto list_failure_lock;
515fd385855SPaul Moore 		}
516fd385855SPaul Moore 		for (iter = 0;
517fd385855SPaul Moore 		     iter < doi_def->map.std->lvl.local_size;
518fd385855SPaul Moore 		     iter++) {
519fd385855SPaul Moore 			if (doi_def->map.std->lvl.local[iter] ==
520fd385855SPaul Moore 			    CIPSO_V4_INV_LVL)
521fd385855SPaul Moore 				continue;
522fd385855SPaul Moore 
523ae0be8deSMichal Kubecek 			nla_b = nla_nest_start_noflag(ans_skb,
524ae0be8deSMichal Kubecek 						      NLBL_CIPSOV4_A_MLSLVL);
525fd385855SPaul Moore 			if (nla_b == NULL) {
526fd385855SPaul Moore 				ret_val = -ENOMEM;
527fd385855SPaul Moore 				goto list_retry;
528fd385855SPaul Moore 			}
529fd385855SPaul Moore 			ret_val = nla_put_u32(ans_skb,
530fd385855SPaul Moore 					      NLBL_CIPSOV4_A_MLSLVLLOC,
531fd385855SPaul Moore 					      iter);
532fd385855SPaul Moore 			if (ret_val != 0)
533fd385855SPaul Moore 				goto list_retry;
534fd385855SPaul Moore 			ret_val = nla_put_u32(ans_skb,
535fd385855SPaul Moore 					    NLBL_CIPSOV4_A_MLSLVLREM,
536fd385855SPaul Moore 					    doi_def->map.std->lvl.local[iter]);
537fd385855SPaul Moore 			if (ret_val != 0)
538fd385855SPaul Moore 				goto list_retry;
539fd385855SPaul Moore 			nla_nest_end(ans_skb, nla_b);
540fd385855SPaul Moore 		}
541fd385855SPaul Moore 		nla_nest_end(ans_skb, nla_a);
542fd385855SPaul Moore 
543ae0be8deSMichal Kubecek 		nla_a = nla_nest_start_noflag(ans_skb,
544ae0be8deSMichal Kubecek 					      NLBL_CIPSOV4_A_MLSCATLST);
545fd385855SPaul Moore 		if (nla_a == NULL) {
546fd385855SPaul Moore 			ret_val = -ENOMEM;
547fd385855SPaul Moore 			goto list_retry;
548fd385855SPaul Moore 		}
549fd385855SPaul Moore 		for (iter = 0;
550fd385855SPaul Moore 		     iter < doi_def->map.std->cat.local_size;
551fd385855SPaul Moore 		     iter++) {
552fd385855SPaul Moore 			if (doi_def->map.std->cat.local[iter] ==
553fd385855SPaul Moore 			    CIPSO_V4_INV_CAT)
554fd385855SPaul Moore 				continue;
555fd385855SPaul Moore 
556ae0be8deSMichal Kubecek 			nla_b = nla_nest_start_noflag(ans_skb,
557ae0be8deSMichal Kubecek 						      NLBL_CIPSOV4_A_MLSCAT);
558fd385855SPaul Moore 			if (nla_b == NULL) {
559fd385855SPaul Moore 				ret_val = -ENOMEM;
560fd385855SPaul Moore 				goto list_retry;
561fd385855SPaul Moore 			}
562fd385855SPaul Moore 			ret_val = nla_put_u32(ans_skb,
563fd385855SPaul Moore 					      NLBL_CIPSOV4_A_MLSCATLOC,
564fd385855SPaul Moore 					      iter);
565fd385855SPaul Moore 			if (ret_val != 0)
566fd385855SPaul Moore 				goto list_retry;
567fd385855SPaul Moore 			ret_val = nla_put_u32(ans_skb,
568fd385855SPaul Moore 					    NLBL_CIPSOV4_A_MLSCATREM,
569fd385855SPaul Moore 					    doi_def->map.std->cat.local[iter]);
570fd385855SPaul Moore 			if (ret_val != 0)
571fd385855SPaul Moore 				goto list_retry;
572fd385855SPaul Moore 			nla_nest_end(ans_skb, nla_b);
573fd385855SPaul Moore 		}
574fd385855SPaul Moore 		nla_nest_end(ans_skb, nla_a);
575fd385855SPaul Moore 
576fd385855SPaul Moore 		break;
577fd385855SPaul Moore 	}
578ad5d07f4SPaul Moore 	cipso_v4_doi_putdef(doi_def);
579fd385855SPaul Moore 	rcu_read_unlock();
580fd385855SPaul Moore 
581fd385855SPaul Moore 	genlmsg_end(ans_skb, data);
582fe785beeSDenis V. Lunev 	return genlmsg_reply(ans_skb, info);
58396cb8e33SPaul Moore 
584fd385855SPaul Moore list_retry:
585fd385855SPaul Moore 	/* XXX - this limit is a guesstimate */
586fd385855SPaul Moore 	if (nlsze_mult < 4) {
587ad5d07f4SPaul Moore 		cipso_v4_doi_putdef(doi_def);
588fd385855SPaul Moore 		rcu_read_unlock();
589fd385855SPaul Moore 		kfree_skb(ans_skb);
59083aa2e96SDenis V. Lunev 		nlsze_mult *= 2;
591fd385855SPaul Moore 		goto list_start;
592fd385855SPaul Moore 	}
593fd385855SPaul Moore list_failure_lock:
594ad5d07f4SPaul Moore 	cipso_v4_doi_putdef(doi_def);
595fd385855SPaul Moore 	rcu_read_unlock();
59696cb8e33SPaul Moore list_failure:
597fd385855SPaul Moore 	kfree_skb(ans_skb);
598fd385855SPaul Moore 	return ret_val;
599fd385855SPaul Moore }
600fd385855SPaul Moore 
601fd385855SPaul Moore /**
602fd385855SPaul Moore  * netlbl_cipsov4_listall_cb - cipso_v4_doi_walk() callback for LISTALL
603fd385855SPaul Moore  * @doi_def: the CIPSOv4 DOI definition
604fd385855SPaul Moore  * @arg: the netlbl_cipsov4_doiwalk_arg structure
605fd385855SPaul Moore  *
606fd385855SPaul Moore  * Description:
607fd385855SPaul Moore  * This function is designed to be used as a callback to the
608fd385855SPaul Moore  * cipso_v4_doi_walk() function for use in generating a response for a LISTALL
609fd385855SPaul Moore  * message.  Returns the size of the message on success, negative values on
610fd385855SPaul Moore  * failure.
611fd385855SPaul Moore  *
612fd385855SPaul Moore  */
netlbl_cipsov4_listall_cb(struct cipso_v4_doi * doi_def,void * arg)613fd385855SPaul Moore static int netlbl_cipsov4_listall_cb(struct cipso_v4_doi *doi_def, void *arg)
614fd385855SPaul Moore {
615fd385855SPaul Moore 	int ret_val = -ENOMEM;
616fd385855SPaul Moore 	struct netlbl_cipsov4_doiwalk_arg *cb_arg = arg;
617fd385855SPaul Moore 	void *data;
618fd385855SPaul Moore 
61915e47304SEric W. Biederman 	data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).portid,
62017c157c8SThomas Graf 			   cb_arg->seq, &netlbl_cipsov4_gnl_family,
62117c157c8SThomas Graf 			   NLM_F_MULTI, NLBL_CIPSOV4_C_LISTALL);
622fd385855SPaul Moore 	if (data == NULL)
623fd385855SPaul Moore 		goto listall_cb_failure;
624fd385855SPaul Moore 
625fd385855SPaul Moore 	ret_val = nla_put_u32(cb_arg->skb, NLBL_CIPSOV4_A_DOI, doi_def->doi);
626fd385855SPaul Moore 	if (ret_val != 0)
627fd385855SPaul Moore 		goto listall_cb_failure;
628fd385855SPaul Moore 	ret_val = nla_put_u32(cb_arg->skb,
629fd385855SPaul Moore 			      NLBL_CIPSOV4_A_MTYPE,
630fd385855SPaul Moore 			      doi_def->type);
631fd385855SPaul Moore 	if (ret_val != 0)
632fd385855SPaul Moore 		goto listall_cb_failure;
633fd385855SPaul Moore 
634053c095aSJohannes Berg 	genlmsg_end(cb_arg->skb, data);
635053c095aSJohannes Berg 	return 0;
636fd385855SPaul Moore 
637fd385855SPaul Moore listall_cb_failure:
638fd385855SPaul Moore 	genlmsg_cancel(cb_arg->skb, data);
63996cb8e33SPaul Moore 	return ret_val;
64096cb8e33SPaul Moore }
64196cb8e33SPaul Moore 
64296cb8e33SPaul Moore /**
64396cb8e33SPaul Moore  * netlbl_cipsov4_listall - Handle a LISTALL message
64496cb8e33SPaul Moore  * @skb: the NETLINK buffer
645fd385855SPaul Moore  * @cb: the NETLINK callback
64696cb8e33SPaul Moore  *
64796cb8e33SPaul Moore  * Description:
64896cb8e33SPaul Moore  * Process a user generated LISTALL message and respond accordingly.  Returns
64996cb8e33SPaul Moore  * zero on success and negative values on error.
65096cb8e33SPaul Moore  *
65196cb8e33SPaul Moore  */
netlbl_cipsov4_listall(struct sk_buff * skb,struct netlink_callback * cb)652fd385855SPaul Moore static int netlbl_cipsov4_listall(struct sk_buff *skb,
653fd385855SPaul Moore 				  struct netlink_callback *cb)
65496cb8e33SPaul Moore {
655fd385855SPaul Moore 	struct netlbl_cipsov4_doiwalk_arg cb_arg;
65656196701SPaul Moore 	u32 doi_skip = cb->args[0];
65796cb8e33SPaul Moore 
658fd385855SPaul Moore 	cb_arg.nl_cb = cb;
659fd385855SPaul Moore 	cb_arg.skb = skb;
660fd385855SPaul Moore 	cb_arg.seq = cb->nlh->nlmsg_seq;
66196cb8e33SPaul Moore 
662fd385855SPaul Moore 	cipso_v4_doi_walk(&doi_skip, netlbl_cipsov4_listall_cb, &cb_arg);
66396cb8e33SPaul Moore 
664fd385855SPaul Moore 	cb->args[0] = doi_skip;
665fd385855SPaul Moore 	return skb->len;
66696cb8e33SPaul Moore }
66796cb8e33SPaul Moore 
66896cb8e33SPaul Moore /**
669b1edeb10SPaul Moore  * netlbl_cipsov4_remove_cb - netlbl_cipsov4_remove() callback for REMOVE
670b1edeb10SPaul Moore  * @entry: LSM domain mapping entry
671b1edeb10SPaul Moore  * @arg: the netlbl_domhsh_walk_arg structure
672b1edeb10SPaul Moore  *
673b1edeb10SPaul Moore  * Description:
674b1edeb10SPaul Moore  * This function is intended for use by netlbl_cipsov4_remove() as the callback
675b1edeb10SPaul Moore  * for the netlbl_domhsh_walk() function; it removes LSM domain map entries
676b1edeb10SPaul Moore  * which are associated with the CIPSO DOI specified in @arg.  Returns zero on
677b1edeb10SPaul Moore  * success, negative values on failure.
678b1edeb10SPaul Moore  *
679b1edeb10SPaul Moore  */
netlbl_cipsov4_remove_cb(struct netlbl_dom_map * entry,void * arg)680b1edeb10SPaul Moore static int netlbl_cipsov4_remove_cb(struct netlbl_dom_map *entry, void *arg)
681b1edeb10SPaul Moore {
682b1edeb10SPaul Moore 	struct netlbl_domhsh_walk_arg *cb_arg = arg;
683b1edeb10SPaul Moore 
6846a8b7f0cSPaul Moore 	if (entry->def.type == NETLBL_NLTYPE_CIPSOV4 &&
6856a8b7f0cSPaul Moore 	    entry->def.cipso->doi == cb_arg->doi)
686b1edeb10SPaul Moore 		return netlbl_domhsh_remove_entry(entry, cb_arg->audit_info);
687b1edeb10SPaul Moore 
688b1edeb10SPaul Moore 	return 0;
689b1edeb10SPaul Moore }
690b1edeb10SPaul Moore 
691b1edeb10SPaul Moore /**
69296cb8e33SPaul Moore  * netlbl_cipsov4_remove - Handle a REMOVE message
69396cb8e33SPaul Moore  * @skb: the NETLINK buffer
69496cb8e33SPaul Moore  * @info: the Generic NETLINK info block
69596cb8e33SPaul Moore  *
69696cb8e33SPaul Moore  * Description:
69796cb8e33SPaul Moore  * Process a user generated REMOVE message and respond accordingly.  Returns
69896cb8e33SPaul Moore  * zero on success, negative values on failure.
69996cb8e33SPaul Moore  *
70096cb8e33SPaul Moore  */
netlbl_cipsov4_remove(struct sk_buff * skb,struct genl_info * info)70196cb8e33SPaul Moore static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info)
70296cb8e33SPaul Moore {
703fd385855SPaul Moore 	int ret_val = -EINVAL;
704b1edeb10SPaul Moore 	struct netlbl_domhsh_walk_arg cb_arg;
70595d4e6beSPaul Moore 	struct netlbl_audit audit_info;
706b1edeb10SPaul Moore 	u32 skip_bkt = 0;
707b1edeb10SPaul Moore 	u32 skip_chain = 0;
70896cb8e33SPaul Moore 
70995d4e6beSPaul Moore 	if (!info->attrs[NLBL_CIPSOV4_A_DOI])
71095d4e6beSPaul Moore 		return -EINVAL;
71195d4e6beSPaul Moore 
712f7e0318aSZheng Yejian 	netlbl_netlink_auditinfo(&audit_info);
7136c2e8ac0SPaul Moore 	cb_arg.doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
714b1edeb10SPaul Moore 	cb_arg.audit_info = &audit_info;
715b1edeb10SPaul Moore 	ret_val = netlbl_domhsh_walk(&skip_bkt, &skip_chain,
716b1edeb10SPaul Moore 				     netlbl_cipsov4_remove_cb, &cb_arg);
717b1edeb10SPaul Moore 	if (ret_val == 0 || ret_val == -ENOENT) {
7186c2e8ac0SPaul Moore 		ret_val = cipso_v4_doi_remove(cb_arg.doi, &audit_info);
71923bcdc1aSPaul Moore 		if (ret_val == 0)
720c783f1ceSPaul Moore 			atomic_dec(&netlabel_mgmt_protocount);
721b1edeb10SPaul Moore 	}
72295d4e6beSPaul Moore 
72396cb8e33SPaul Moore 	return ret_val;
72496cb8e33SPaul Moore }
72596cb8e33SPaul Moore 
72696cb8e33SPaul Moore /*
72796cb8e33SPaul Moore  * NetLabel Generic NETLINK Command Definitions
72896cb8e33SPaul Moore  */
72996cb8e33SPaul Moore 
73066a9b928SJakub Kicinski static const struct genl_small_ops netlbl_cipsov4_ops[] = {
731227c43c3SPavel Emelyanov 	{
73296cb8e33SPaul Moore 	.cmd = NLBL_CIPSOV4_C_ADD,
733ef6243acSJohannes Berg 	.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
734fd385855SPaul Moore 	.flags = GENL_ADMIN_PERM,
73596cb8e33SPaul Moore 	.doit = netlbl_cipsov4_add,
73696cb8e33SPaul Moore 	.dumpit = NULL,
737227c43c3SPavel Emelyanov 	},
738227c43c3SPavel Emelyanov 	{
73996cb8e33SPaul Moore 	.cmd = NLBL_CIPSOV4_C_REMOVE,
740ef6243acSJohannes Berg 	.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
741fd385855SPaul Moore 	.flags = GENL_ADMIN_PERM,
74296cb8e33SPaul Moore 	.doit = netlbl_cipsov4_remove,
74396cb8e33SPaul Moore 	.dumpit = NULL,
744227c43c3SPavel Emelyanov 	},
745227c43c3SPavel Emelyanov 	{
74696cb8e33SPaul Moore 	.cmd = NLBL_CIPSOV4_C_LIST,
747ef6243acSJohannes Berg 	.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
74896cb8e33SPaul Moore 	.flags = 0,
74996cb8e33SPaul Moore 	.doit = netlbl_cipsov4_list,
75096cb8e33SPaul Moore 	.dumpit = NULL,
751227c43c3SPavel Emelyanov 	},
752227c43c3SPavel Emelyanov 	{
75396cb8e33SPaul Moore 	.cmd = NLBL_CIPSOV4_C_LISTALL,
754ef6243acSJohannes Berg 	.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
75596cb8e33SPaul Moore 	.flags = 0,
756fd385855SPaul Moore 	.doit = NULL,
757fd385855SPaul Moore 	.dumpit = netlbl_cipsov4_listall,
758227c43c3SPavel Emelyanov 	},
75996cb8e33SPaul Moore };
76096cb8e33SPaul Moore 
76156989f6dSJohannes Berg static struct genl_family netlbl_cipsov4_gnl_family __ro_after_init = {
762489111e5SJohannes Berg 	.hdrsize = 0,
763489111e5SJohannes Berg 	.name = NETLBL_NLTYPE_CIPSOV4_NAME,
764489111e5SJohannes Berg 	.version = NETLBL_PROTO_VERSION,
765489111e5SJohannes Berg 	.maxattr = NLBL_CIPSOV4_A_MAX,
7663b0f31f2SJohannes Berg 	.policy = netlbl_cipsov4_genl_policy,
767489111e5SJohannes Berg 	.module = THIS_MODULE,
76866a9b928SJakub Kicinski 	.small_ops = netlbl_cipsov4_ops,
76966a9b928SJakub Kicinski 	.n_small_ops = ARRAY_SIZE(netlbl_cipsov4_ops),
770*9c5d03d3SJakub Kicinski 	.resv_start_op = NLBL_CIPSOV4_C_LISTALL + 1,
771489111e5SJohannes Berg };
772489111e5SJohannes Berg 
77396cb8e33SPaul Moore /*
77496cb8e33SPaul Moore  * NetLabel Generic NETLINK Protocol Functions
77596cb8e33SPaul Moore  */
77696cb8e33SPaul Moore 
77796cb8e33SPaul Moore /**
77896cb8e33SPaul Moore  * netlbl_cipsov4_genl_init - Register the CIPSOv4 NetLabel component
77996cb8e33SPaul Moore  *
78096cb8e33SPaul Moore  * Description:
78196cb8e33SPaul Moore  * Register the CIPSOv4 packet NetLabel component with the Generic NETLINK
78296cb8e33SPaul Moore  * mechanism.  Returns zero on success, negative values on failure.
78396cb8e33SPaul Moore  *
78496cb8e33SPaul Moore  */
netlbl_cipsov4_genl_init(void)78505705e4eSPavel Emelyanov int __init netlbl_cipsov4_genl_init(void)
78696cb8e33SPaul Moore {
787489111e5SJohannes Berg 	return genl_register_family(&netlbl_cipsov4_gnl_family);
78896cb8e33SPaul Moore }
789