xref: /openbmc/linux/net/netlabel/netlabel_cipso_v4.c (revision fe785bee05f08d37b34b7399d003b74199274ce4)
196cb8e33SPaul Moore /*
296cb8e33SPaul Moore  * NetLabel CIPSO/IPv4 Support
396cb8e33SPaul Moore  *
496cb8e33SPaul Moore  * This file defines the CIPSO/IPv4 functions for the NetLabel system.  The
596cb8e33SPaul Moore  * NetLabel system manages static and dynamic label mappings for network
696cb8e33SPaul Moore  * protocols such as CIPSO and RIPSO.
796cb8e33SPaul Moore  *
896cb8e33SPaul Moore  * Author: Paul Moore <paul.moore@hp.com>
996cb8e33SPaul Moore  *
1096cb8e33SPaul Moore  */
1196cb8e33SPaul Moore 
1296cb8e33SPaul Moore /*
1396cb8e33SPaul Moore  * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
1496cb8e33SPaul Moore  *
1596cb8e33SPaul Moore  * This program is free software;  you can redistribute it and/or modify
1696cb8e33SPaul Moore  * it under the terms of the GNU General Public License as published by
1796cb8e33SPaul Moore  * the Free Software Foundation; either version 2 of the License, or
1896cb8e33SPaul Moore  * (at your option) any later version.
1996cb8e33SPaul Moore  *
2096cb8e33SPaul Moore  * This program is distributed in the hope that it will be useful,
2196cb8e33SPaul Moore  * but WITHOUT ANY WARRANTY;  without even the implied warranty of
2296cb8e33SPaul Moore  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
2396cb8e33SPaul Moore  * the GNU General Public License for more details.
2496cb8e33SPaul Moore  *
2596cb8e33SPaul Moore  * You should have received a copy of the GNU General Public License
2696cb8e33SPaul Moore  * along with this program;  if not, write to the Free Software
2796cb8e33SPaul Moore  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2896cb8e33SPaul Moore  *
2996cb8e33SPaul Moore  */
3096cb8e33SPaul Moore 
3196cb8e33SPaul Moore #include <linux/types.h>
3296cb8e33SPaul Moore #include <linux/socket.h>
3396cb8e33SPaul Moore #include <linux/string.h>
3496cb8e33SPaul Moore #include <linux/skbuff.h>
3532f50cdeSPaul Moore #include <linux/audit.h>
3696cb8e33SPaul Moore #include <net/sock.h>
3796cb8e33SPaul Moore #include <net/netlink.h>
3896cb8e33SPaul Moore #include <net/genetlink.h>
3996cb8e33SPaul Moore #include <net/netlabel.h>
4096cb8e33SPaul Moore #include <net/cipso_ipv4.h>
41c783f1ceSPaul Moore #include <asm/atomic.h>
4296cb8e33SPaul Moore 
4396cb8e33SPaul Moore #include "netlabel_user.h"
4496cb8e33SPaul Moore #include "netlabel_cipso_v4.h"
4523bcdc1aSPaul Moore #include "netlabel_mgmt.h"
4696cb8e33SPaul Moore 
47fd385855SPaul Moore /* Argument struct for cipso_v4_doi_walk() */
48fd385855SPaul Moore struct netlbl_cipsov4_doiwalk_arg {
49fd385855SPaul Moore 	struct netlink_callback *nl_cb;
50fd385855SPaul Moore 	struct sk_buff *skb;
51fd385855SPaul Moore 	u32 seq;
52fd385855SPaul Moore };
53fd385855SPaul Moore 
5496cb8e33SPaul Moore /* NetLabel Generic NETLINK CIPSOv4 family */
5596cb8e33SPaul Moore static struct genl_family netlbl_cipsov4_gnl_family = {
5696cb8e33SPaul Moore 	.id = GENL_ID_GENERATE,
5796cb8e33SPaul Moore 	.hdrsize = 0,
5896cb8e33SPaul Moore 	.name = NETLBL_NLTYPE_CIPSOV4_NAME,
5996cb8e33SPaul Moore 	.version = NETLBL_PROTO_VERSION,
60fd385855SPaul Moore 	.maxattr = NLBL_CIPSOV4_A_MAX,
6196cb8e33SPaul Moore };
6296cb8e33SPaul Moore 
63fd385855SPaul Moore /* NetLabel Netlink attribute policy */
64ef7c79edSPatrick McHardy static const struct nla_policy netlbl_cipsov4_genl_policy[NLBL_CIPSOV4_A_MAX + 1] = {
65fd385855SPaul Moore 	[NLBL_CIPSOV4_A_DOI] = { .type = NLA_U32 },
66fd385855SPaul Moore 	[NLBL_CIPSOV4_A_MTYPE] = { .type = NLA_U32 },
67fd385855SPaul Moore 	[NLBL_CIPSOV4_A_TAG] = { .type = NLA_U8 },
68fd385855SPaul Moore 	[NLBL_CIPSOV4_A_TAGLST] = { .type = NLA_NESTED },
69fd385855SPaul Moore 	[NLBL_CIPSOV4_A_MLSLVLLOC] = { .type = NLA_U32 },
70fd385855SPaul Moore 	[NLBL_CIPSOV4_A_MLSLVLREM] = { .type = NLA_U32 },
71fd385855SPaul Moore 	[NLBL_CIPSOV4_A_MLSLVL] = { .type = NLA_NESTED },
72fd385855SPaul Moore 	[NLBL_CIPSOV4_A_MLSLVLLST] = { .type = NLA_NESTED },
73fd385855SPaul Moore 	[NLBL_CIPSOV4_A_MLSCATLOC] = { .type = NLA_U32 },
74fd385855SPaul Moore 	[NLBL_CIPSOV4_A_MLSCATREM] = { .type = NLA_U32 },
75fd385855SPaul Moore 	[NLBL_CIPSOV4_A_MLSCAT] = { .type = NLA_NESTED },
76fd385855SPaul Moore 	[NLBL_CIPSOV4_A_MLSCATLST] = { .type = NLA_NESTED },
77fd385855SPaul Moore };
7896cb8e33SPaul Moore 
7996cb8e33SPaul Moore /*
8096cb8e33SPaul Moore  * Helper Functions
8196cb8e33SPaul Moore  */
8296cb8e33SPaul Moore 
8396cb8e33SPaul Moore /**
8496cb8e33SPaul Moore  * netlbl_cipsov4_doi_free - Frees a CIPSO V4 DOI definition
8596cb8e33SPaul Moore  * @entry: the entry's RCU field
8696cb8e33SPaul Moore  *
8796cb8e33SPaul Moore  * Description:
8896cb8e33SPaul Moore  * This function is designed to be used as a callback to the call_rcu()
8996cb8e33SPaul Moore  * function so that the memory allocated to the DOI definition can be released
9096cb8e33SPaul Moore  * safely.
9196cb8e33SPaul Moore  *
9296cb8e33SPaul Moore  */
93eda61d32SPaul Moore void netlbl_cipsov4_doi_free(struct rcu_head *entry)
9496cb8e33SPaul Moore {
9596cb8e33SPaul Moore 	struct cipso_v4_doi *ptr;
9696cb8e33SPaul Moore 
9796cb8e33SPaul Moore 	ptr = container_of(entry, struct cipso_v4_doi, rcu);
9896cb8e33SPaul Moore 	switch (ptr->type) {
9996cb8e33SPaul Moore 	case CIPSO_V4_MAP_STD:
10096cb8e33SPaul Moore 		kfree(ptr->map.std->lvl.cipso);
10196cb8e33SPaul Moore 		kfree(ptr->map.std->lvl.local);
10296cb8e33SPaul Moore 		kfree(ptr->map.std->cat.cipso);
10396cb8e33SPaul Moore 		kfree(ptr->map.std->cat.local);
10496cb8e33SPaul Moore 		break;
10596cb8e33SPaul Moore 	}
10696cb8e33SPaul Moore 	kfree(ptr);
10796cb8e33SPaul Moore }
10896cb8e33SPaul Moore 
109fd385855SPaul Moore /**
110fd385855SPaul Moore  * netlbl_cipsov4_add_common - Parse the common sections of a ADD message
111fd385855SPaul Moore  * @info: the Generic NETLINK info block
112fd385855SPaul Moore  * @doi_def: the CIPSO V4 DOI definition
113fd385855SPaul Moore  *
114fd385855SPaul Moore  * Description:
115fd385855SPaul Moore  * Parse the common sections of a ADD message and fill in the related values
116fd385855SPaul Moore  * in @doi_def.  Returns zero on success, negative values on failure.
117fd385855SPaul Moore  *
118fd385855SPaul Moore  */
119fd385855SPaul Moore static int netlbl_cipsov4_add_common(struct genl_info *info,
120fd385855SPaul Moore 				     struct cipso_v4_doi *doi_def)
121fd385855SPaul Moore {
122fd385855SPaul Moore 	struct nlattr *nla;
123fd385855SPaul Moore 	int nla_rem;
124fd385855SPaul Moore 	u32 iter = 0;
125fd385855SPaul Moore 
126fd385855SPaul Moore 	doi_def->doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
127fd385855SPaul Moore 
128fd385855SPaul Moore 	if (nla_validate_nested(info->attrs[NLBL_CIPSOV4_A_TAGLST],
129fd385855SPaul Moore 				NLBL_CIPSOV4_A_MAX,
130fd385855SPaul Moore 				netlbl_cipsov4_genl_policy) != 0)
131fd385855SPaul Moore 		return -EINVAL;
132fd385855SPaul Moore 
133fd385855SPaul Moore 	nla_for_each_nested(nla, info->attrs[NLBL_CIPSOV4_A_TAGLST], nla_rem)
1348f4c1f9bSThomas Graf 		if (nla_type(nla) == NLBL_CIPSOV4_A_TAG) {
1352a2f11c2SPaul Moore 			if (iter >= CIPSO_V4_TAG_MAXCNT)
136fd385855SPaul Moore 				return -EINVAL;
137fd385855SPaul Moore 			doi_def->tags[iter++] = nla_get_u8(nla);
138fd385855SPaul Moore 		}
1392a2f11c2SPaul Moore 	while (iter < CIPSO_V4_TAG_MAXCNT)
1402a2f11c2SPaul Moore 		doi_def->tags[iter++] = CIPSO_V4_TAG_INVALID;
141fd385855SPaul Moore 
142fd385855SPaul Moore 	return 0;
143fd385855SPaul Moore }
14496cb8e33SPaul Moore 
14596cb8e33SPaul Moore /*
14696cb8e33SPaul Moore  * NetLabel Command Handlers
14796cb8e33SPaul Moore  */
14896cb8e33SPaul Moore 
14996cb8e33SPaul Moore /**
15096cb8e33SPaul Moore  * netlbl_cipsov4_add_std - Adds a CIPSO V4 DOI definition
151fd385855SPaul Moore  * @info: the Generic NETLINK info block
15296cb8e33SPaul Moore  *
15396cb8e33SPaul Moore  * Description:
15496cb8e33SPaul Moore  * Create a new CIPSO_V4_MAP_STD DOI definition based on the given ADD message
15596cb8e33SPaul Moore  * and add it to the CIPSO V4 engine.  Return zero on success and non-zero on
15696cb8e33SPaul Moore  * error.
15796cb8e33SPaul Moore  *
15896cb8e33SPaul Moore  */
159fd385855SPaul Moore static int netlbl_cipsov4_add_std(struct genl_info *info)
16096cb8e33SPaul Moore {
16196cb8e33SPaul Moore 	int ret_val = -EINVAL;
16296cb8e33SPaul Moore 	struct cipso_v4_doi *doi_def = NULL;
163fd385855SPaul Moore 	struct nlattr *nla_a;
164fd385855SPaul Moore 	struct nlattr *nla_b;
165fd385855SPaul Moore 	int nla_a_rem;
166fd385855SPaul Moore 	int nla_b_rem;
167caff5b6aSPaul Moore 	u32 iter;
16896cb8e33SPaul Moore 
16932f50cdeSPaul Moore 	if (!info->attrs[NLBL_CIPSOV4_A_TAGLST] ||
170fd385855SPaul Moore 	    !info->attrs[NLBL_CIPSOV4_A_MLSLVLLST])
171fd385855SPaul Moore 		return -EINVAL;
172fd385855SPaul Moore 
173fd385855SPaul Moore 	if (nla_validate_nested(info->attrs[NLBL_CIPSOV4_A_MLSLVLLST],
174fd385855SPaul Moore 				NLBL_CIPSOV4_A_MAX,
175fd385855SPaul Moore 				netlbl_cipsov4_genl_policy) != 0)
176fd385855SPaul Moore 		return -EINVAL;
17796cb8e33SPaul Moore 
17896cb8e33SPaul Moore 	doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
179fd385855SPaul Moore 	if (doi_def == NULL)
180fd385855SPaul Moore 		return -ENOMEM;
18196cb8e33SPaul Moore 	doi_def->map.std = kzalloc(sizeof(*doi_def->map.std), GFP_KERNEL);
18296cb8e33SPaul Moore 	if (doi_def->map.std == NULL) {
18396cb8e33SPaul Moore 		ret_val = -ENOMEM;
18496cb8e33SPaul Moore 		goto add_std_failure;
18596cb8e33SPaul Moore 	}
18696cb8e33SPaul Moore 	doi_def->type = CIPSO_V4_MAP_STD;
18796cb8e33SPaul Moore 
188fd385855SPaul Moore 	ret_val = netlbl_cipsov4_add_common(info, doi_def);
189fd385855SPaul Moore 	if (ret_val != 0)
19096cb8e33SPaul Moore 		goto add_std_failure;
1911fd2a25bSPaul Moore 	ret_val = -EINVAL;
192fd385855SPaul Moore 
193fd385855SPaul Moore 	nla_for_each_nested(nla_a,
194fd385855SPaul Moore 			    info->attrs[NLBL_CIPSOV4_A_MLSLVLLST],
195fd385855SPaul Moore 			    nla_a_rem)
1968f4c1f9bSThomas Graf 		if (nla_type(nla_a) == NLBL_CIPSOV4_A_MLSLVL) {
1971fd2a25bSPaul Moore 			if (nla_validate_nested(nla_a,
1981fd2a25bSPaul Moore 					    NLBL_CIPSOV4_A_MAX,
1991fd2a25bSPaul Moore 					    netlbl_cipsov4_genl_policy) != 0)
2001fd2a25bSPaul Moore 					goto add_std_failure;
201fd385855SPaul Moore 			nla_for_each_nested(nla_b, nla_a, nla_b_rem)
2028f4c1f9bSThomas Graf 				switch (nla_type(nla_b)) {
203fd385855SPaul Moore 				case NLBL_CIPSOV4_A_MLSLVLLOC:
2041fd2a25bSPaul Moore 					if (nla_get_u32(nla_b) >
2051fd2a25bSPaul Moore 					    CIPSO_V4_MAX_LOC_LVLS)
2061fd2a25bSPaul Moore 						goto add_std_failure;
207fd385855SPaul Moore 					if (nla_get_u32(nla_b) >=
208fd385855SPaul Moore 					    doi_def->map.std->lvl.local_size)
209fd385855SPaul Moore 					     doi_def->map.std->lvl.local_size =
210fd385855SPaul Moore 						     nla_get_u32(nla_b) + 1;
21196cb8e33SPaul Moore 					break;
212fd385855SPaul Moore 				case NLBL_CIPSOV4_A_MLSLVLREM:
2131fd2a25bSPaul Moore 					if (nla_get_u32(nla_b) >
2141fd2a25bSPaul Moore 					    CIPSO_V4_MAX_REM_LVLS)
2151fd2a25bSPaul Moore 						goto add_std_failure;
216fd385855SPaul Moore 					if (nla_get_u32(nla_b) >=
217fd385855SPaul Moore 					    doi_def->map.std->lvl.cipso_size)
218fd385855SPaul Moore 					     doi_def->map.std->lvl.cipso_size =
219fd385855SPaul Moore 						     nla_get_u32(nla_b) + 1;
220fd385855SPaul Moore 					break;
22196cb8e33SPaul Moore 				}
22296cb8e33SPaul Moore 		}
22396cb8e33SPaul Moore 	doi_def->map.std->lvl.local = kcalloc(doi_def->map.std->lvl.local_size,
22496cb8e33SPaul Moore 					      sizeof(u32),
22596cb8e33SPaul Moore 					      GFP_KERNEL);
22696cb8e33SPaul Moore 	if (doi_def->map.std->lvl.local == NULL) {
22796cb8e33SPaul Moore 		ret_val = -ENOMEM;
22896cb8e33SPaul Moore 		goto add_std_failure;
22996cb8e33SPaul Moore 	}
23096cb8e33SPaul Moore 	doi_def->map.std->lvl.cipso = kcalloc(doi_def->map.std->lvl.cipso_size,
23196cb8e33SPaul Moore 					      sizeof(u32),
23296cb8e33SPaul Moore 					      GFP_KERNEL);
23396cb8e33SPaul Moore 	if (doi_def->map.std->lvl.cipso == NULL) {
23496cb8e33SPaul Moore 		ret_val = -ENOMEM;
23596cb8e33SPaul Moore 		goto add_std_failure;
23696cb8e33SPaul Moore 	}
237caff5b6aSPaul Moore 	for (iter = 0; iter < doi_def->map.std->lvl.local_size; iter++)
238caff5b6aSPaul Moore 		doi_def->map.std->lvl.local[iter] = CIPSO_V4_INV_LVL;
239caff5b6aSPaul Moore 	for (iter = 0; iter < doi_def->map.std->lvl.cipso_size; iter++)
240caff5b6aSPaul Moore 		doi_def->map.std->lvl.cipso[iter] = CIPSO_V4_INV_LVL;
241fd385855SPaul Moore 	nla_for_each_nested(nla_a,
242fd385855SPaul Moore 			    info->attrs[NLBL_CIPSOV4_A_MLSLVLLST],
243fd385855SPaul Moore 			    nla_a_rem)
2448f4c1f9bSThomas Graf 		if (nla_type(nla_a) == NLBL_CIPSOV4_A_MLSLVL) {
245fd385855SPaul Moore 			struct nlattr *lvl_loc;
246fd385855SPaul Moore 			struct nlattr *lvl_rem;
24796cb8e33SPaul Moore 
248fd385855SPaul Moore 			lvl_loc = nla_find_nested(nla_a,
249fd385855SPaul Moore 						  NLBL_CIPSOV4_A_MLSLVLLOC);
250fd385855SPaul Moore 			lvl_rem = nla_find_nested(nla_a,
251fd385855SPaul Moore 						  NLBL_CIPSOV4_A_MLSLVLREM);
252fd385855SPaul Moore 			if (lvl_loc == NULL || lvl_rem == NULL)
253fd385855SPaul Moore 				goto add_std_failure;
254fd385855SPaul Moore 			doi_def->map.std->lvl.local[nla_get_u32(lvl_loc)] =
255fd385855SPaul Moore 				nla_get_u32(lvl_rem);
256fd385855SPaul Moore 			doi_def->map.std->lvl.cipso[nla_get_u32(lvl_rem)] =
257fd385855SPaul Moore 				nla_get_u32(lvl_loc);
258fd385855SPaul Moore 		}
259fd385855SPaul Moore 
260fd385855SPaul Moore 	if (info->attrs[NLBL_CIPSOV4_A_MLSCATLST]) {
261fd385855SPaul Moore 		if (nla_validate_nested(info->attrs[NLBL_CIPSOV4_A_MLSCATLST],
262fd385855SPaul Moore 					NLBL_CIPSOV4_A_MAX,
263fd385855SPaul Moore 					netlbl_cipsov4_genl_policy) != 0)
264fd385855SPaul Moore 			goto add_std_failure;
265fd385855SPaul Moore 
266fd385855SPaul Moore 		nla_for_each_nested(nla_a,
267fd385855SPaul Moore 				    info->attrs[NLBL_CIPSOV4_A_MLSCATLST],
268fd385855SPaul Moore 				    nla_a_rem)
2698f4c1f9bSThomas Graf 			if (nla_type(nla_a) == NLBL_CIPSOV4_A_MLSCAT) {
270fd385855SPaul Moore 				if (nla_validate_nested(nla_a,
271fd385855SPaul Moore 					      NLBL_CIPSOV4_A_MAX,
272fd385855SPaul Moore 					      netlbl_cipsov4_genl_policy) != 0)
273fd385855SPaul Moore 					goto add_std_failure;
274fd385855SPaul Moore 				nla_for_each_nested(nla_b, nla_a, nla_b_rem)
2758f4c1f9bSThomas Graf 					switch (nla_type(nla_b)) {
276fd385855SPaul Moore 					case NLBL_CIPSOV4_A_MLSCATLOC:
2771fd2a25bSPaul Moore 						if (nla_get_u32(nla_b) >
2781fd2a25bSPaul Moore 						    CIPSO_V4_MAX_LOC_CATS)
2791fd2a25bSPaul Moore 							goto add_std_failure;
280fd385855SPaul Moore 						if (nla_get_u32(nla_b) >=
281fd385855SPaul Moore 					      doi_def->map.std->cat.local_size)
282fd385855SPaul Moore 					     doi_def->map.std->cat.local_size =
283fd385855SPaul Moore 						     nla_get_u32(nla_b) + 1;
284fd385855SPaul Moore 						break;
285fd385855SPaul Moore 					case NLBL_CIPSOV4_A_MLSCATREM:
2861fd2a25bSPaul Moore 						if (nla_get_u32(nla_b) >
2871fd2a25bSPaul Moore 						    CIPSO_V4_MAX_REM_CATS)
2881fd2a25bSPaul Moore 							goto add_std_failure;
289fd385855SPaul Moore 						if (nla_get_u32(nla_b) >=
290fd385855SPaul Moore 					      doi_def->map.std->cat.cipso_size)
291fd385855SPaul Moore 					     doi_def->map.std->cat.cipso_size =
292fd385855SPaul Moore 						     nla_get_u32(nla_b) + 1;
293fd385855SPaul Moore 						break;
294fd385855SPaul Moore 					}
295fd385855SPaul Moore 			}
296fd385855SPaul Moore 		doi_def->map.std->cat.local = kcalloc(
297fd385855SPaul Moore 					      doi_def->map.std->cat.local_size,
29896cb8e33SPaul Moore 					      sizeof(u32),
29996cb8e33SPaul Moore 					      GFP_KERNEL);
30096cb8e33SPaul Moore 		if (doi_def->map.std->cat.local == NULL) {
30196cb8e33SPaul Moore 			ret_val = -ENOMEM;
30296cb8e33SPaul Moore 			goto add_std_failure;
30396cb8e33SPaul Moore 		}
304fd385855SPaul Moore 		doi_def->map.std->cat.cipso = kcalloc(
305fd385855SPaul Moore 					      doi_def->map.std->cat.cipso_size,
30696cb8e33SPaul Moore 					      sizeof(u32),
30796cb8e33SPaul Moore 					      GFP_KERNEL);
30896cb8e33SPaul Moore 		if (doi_def->map.std->cat.cipso == NULL) {
30996cb8e33SPaul Moore 			ret_val = -ENOMEM;
31096cb8e33SPaul Moore 			goto add_std_failure;
31196cb8e33SPaul Moore 		}
312caff5b6aSPaul Moore 		for (iter = 0; iter < doi_def->map.std->cat.local_size; iter++)
313caff5b6aSPaul Moore 			doi_def->map.std->cat.local[iter] = CIPSO_V4_INV_CAT;
314caff5b6aSPaul Moore 		for (iter = 0; iter < doi_def->map.std->cat.cipso_size; iter++)
315caff5b6aSPaul Moore 			doi_def->map.std->cat.cipso[iter] = CIPSO_V4_INV_CAT;
316fd385855SPaul Moore 		nla_for_each_nested(nla_a,
317fd385855SPaul Moore 				    info->attrs[NLBL_CIPSOV4_A_MLSCATLST],
318fd385855SPaul Moore 				    nla_a_rem)
3198f4c1f9bSThomas Graf 			if (nla_type(nla_a) == NLBL_CIPSOV4_A_MLSCAT) {
320fd385855SPaul Moore 				struct nlattr *cat_loc;
321fd385855SPaul Moore 				struct nlattr *cat_rem;
32296cb8e33SPaul Moore 
323fd385855SPaul Moore 				cat_loc = nla_find_nested(nla_a,
324fd385855SPaul Moore 						     NLBL_CIPSOV4_A_MLSCATLOC);
325fd385855SPaul Moore 				cat_rem = nla_find_nested(nla_a,
326fd385855SPaul Moore 						     NLBL_CIPSOV4_A_MLSCATREM);
327fd385855SPaul Moore 				if (cat_loc == NULL || cat_rem == NULL)
32896cb8e33SPaul Moore 					goto add_std_failure;
329fd385855SPaul Moore 				doi_def->map.std->cat.local[
330fd385855SPaul Moore 							nla_get_u32(cat_loc)] =
331fd385855SPaul Moore 					nla_get_u32(cat_rem);
332fd385855SPaul Moore 				doi_def->map.std->cat.cipso[
333fd385855SPaul Moore 							nla_get_u32(cat_rem)] =
334fd385855SPaul Moore 					nla_get_u32(cat_loc);
335fd385855SPaul Moore 			}
33696cb8e33SPaul Moore 	}
33796cb8e33SPaul Moore 
33896cb8e33SPaul Moore 	ret_val = cipso_v4_doi_add(doi_def);
33996cb8e33SPaul Moore 	if (ret_val != 0)
34096cb8e33SPaul Moore 		goto add_std_failure;
34196cb8e33SPaul Moore 	return 0;
34296cb8e33SPaul Moore 
34396cb8e33SPaul Moore add_std_failure:
34496cb8e33SPaul Moore 	if (doi_def)
34596cb8e33SPaul Moore 		netlbl_cipsov4_doi_free(&doi_def->rcu);
34696cb8e33SPaul Moore 	return ret_val;
34796cb8e33SPaul Moore }
34896cb8e33SPaul Moore 
34996cb8e33SPaul Moore /**
35096cb8e33SPaul Moore  * netlbl_cipsov4_add_pass - Adds a CIPSO V4 DOI definition
351fd385855SPaul Moore  * @info: the Generic NETLINK info block
35296cb8e33SPaul Moore  *
35396cb8e33SPaul Moore  * Description:
35496cb8e33SPaul Moore  * Create a new CIPSO_V4_MAP_PASS DOI definition based on the given ADD message
35596cb8e33SPaul Moore  * and add it to the CIPSO V4 engine.  Return zero on success and non-zero on
35696cb8e33SPaul Moore  * error.
35796cb8e33SPaul Moore  *
35896cb8e33SPaul Moore  */
359fd385855SPaul Moore static int netlbl_cipsov4_add_pass(struct genl_info *info)
36096cb8e33SPaul Moore {
361fd385855SPaul Moore 	int ret_val;
36296cb8e33SPaul Moore 	struct cipso_v4_doi *doi_def = NULL;
36396cb8e33SPaul Moore 
36432f50cdeSPaul Moore 	if (!info->attrs[NLBL_CIPSOV4_A_TAGLST])
365fd385855SPaul Moore 		return -EINVAL;
36696cb8e33SPaul Moore 
36796cb8e33SPaul Moore 	doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
368fd385855SPaul Moore 	if (doi_def == NULL)
369fd385855SPaul Moore 		return -ENOMEM;
37096cb8e33SPaul Moore 	doi_def->type = CIPSO_V4_MAP_PASS;
37196cb8e33SPaul Moore 
372fd385855SPaul Moore 	ret_val = netlbl_cipsov4_add_common(info, doi_def);
373fd385855SPaul Moore 	if (ret_val != 0)
37496cb8e33SPaul Moore 		goto add_pass_failure;
37596cb8e33SPaul Moore 
37696cb8e33SPaul Moore 	ret_val = cipso_v4_doi_add(doi_def);
37796cb8e33SPaul Moore 	if (ret_val != 0)
37896cb8e33SPaul Moore 		goto add_pass_failure;
37996cb8e33SPaul Moore 	return 0;
38096cb8e33SPaul Moore 
38196cb8e33SPaul Moore add_pass_failure:
38296cb8e33SPaul Moore 	netlbl_cipsov4_doi_free(&doi_def->rcu);
38396cb8e33SPaul Moore 	return ret_val;
38496cb8e33SPaul Moore }
38596cb8e33SPaul Moore 
38696cb8e33SPaul Moore /**
38796cb8e33SPaul Moore  * netlbl_cipsov4_add - Handle an ADD message
38896cb8e33SPaul Moore  * @skb: the NETLINK buffer
38996cb8e33SPaul Moore  * @info: the Generic NETLINK info block
39096cb8e33SPaul Moore  *
39196cb8e33SPaul Moore  * Description:
39296cb8e33SPaul Moore  * Create a new DOI definition based on the given ADD message and add it to the
39396cb8e33SPaul Moore  * CIPSO V4 engine.  Returns zero on success, negative values on failure.
39496cb8e33SPaul Moore  *
39596cb8e33SPaul Moore  */
39696cb8e33SPaul Moore static int netlbl_cipsov4_add(struct sk_buff *skb, struct genl_info *info)
39796cb8e33SPaul Moore 
39896cb8e33SPaul Moore {
39996cb8e33SPaul Moore 	int ret_val = -EINVAL;
40032f50cdeSPaul Moore 	u32 type;
40132f50cdeSPaul Moore 	u32 doi;
40232f50cdeSPaul Moore 	const char *type_str = "(unknown)";
40332f50cdeSPaul Moore 	struct audit_buffer *audit_buf;
40495d4e6beSPaul Moore 	struct netlbl_audit audit_info;
40596cb8e33SPaul Moore 
40632f50cdeSPaul Moore 	if (!info->attrs[NLBL_CIPSOV4_A_DOI] ||
40732f50cdeSPaul Moore 	    !info->attrs[NLBL_CIPSOV4_A_MTYPE])
408fd385855SPaul Moore 		return -EINVAL;
40996cb8e33SPaul Moore 
41095d4e6beSPaul Moore 	doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
41195d4e6beSPaul Moore 	netlbl_netlink_auditinfo(skb, &audit_info);
41295d4e6beSPaul Moore 
41332f50cdeSPaul Moore 	type = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_MTYPE]);
41432f50cdeSPaul Moore 	switch (type) {
41596cb8e33SPaul Moore 	case CIPSO_V4_MAP_STD:
41632f50cdeSPaul Moore 		type_str = "std";
417fd385855SPaul Moore 		ret_val = netlbl_cipsov4_add_std(info);
41896cb8e33SPaul Moore 		break;
41996cb8e33SPaul Moore 	case CIPSO_V4_MAP_PASS:
42032f50cdeSPaul Moore 		type_str = "pass";
421fd385855SPaul Moore 		ret_val = netlbl_cipsov4_add_pass(info);
42296cb8e33SPaul Moore 		break;
42396cb8e33SPaul Moore 	}
42423bcdc1aSPaul Moore 	if (ret_val == 0)
425c783f1ceSPaul Moore 		atomic_inc(&netlabel_mgmt_protocount);
42696cb8e33SPaul Moore 
42732f50cdeSPaul Moore 	audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_ADD,
42895d4e6beSPaul Moore 					      &audit_info);
429de64688fSPaul Moore 	if (audit_buf != NULL) {
43095d4e6beSPaul Moore 		audit_log_format(audit_buf,
43195d4e6beSPaul Moore 				 " cipso_doi=%u cipso_type=%s res=%u",
43295d4e6beSPaul Moore 				 doi,
43395d4e6beSPaul Moore 				 type_str,
43495d4e6beSPaul Moore 				 ret_val == 0 ? 1 : 0);
43532f50cdeSPaul Moore 		audit_log_end(audit_buf);
436de64688fSPaul Moore 	}
43732f50cdeSPaul Moore 
43896cb8e33SPaul Moore 	return ret_val;
43996cb8e33SPaul Moore }
44096cb8e33SPaul Moore 
44196cb8e33SPaul Moore /**
44296cb8e33SPaul Moore  * netlbl_cipsov4_list - Handle a LIST message
44396cb8e33SPaul Moore  * @skb: the NETLINK buffer
44496cb8e33SPaul Moore  * @info: the Generic NETLINK info block
44596cb8e33SPaul Moore  *
44696cb8e33SPaul Moore  * Description:
447fd385855SPaul Moore  * Process a user generated LIST message and respond accordingly.  While the
448fd385855SPaul Moore  * response message generated by the kernel is straightforward, determining
449fd385855SPaul Moore  * before hand the size of the buffer to allocate is not (we have to generate
450fd385855SPaul Moore  * the message to know the size).  In order to keep this function sane what we
451fd385855SPaul Moore  * do is allocate a buffer of NLMSG_GOODSIZE and try to fit the response in
452fd385855SPaul Moore  * that size, if we fail then we restart with a larger buffer and try again.
453fd385855SPaul Moore  * We continue in this manner until we hit a limit of failed attempts then we
454fd385855SPaul Moore  * give up and just send an error message.  Returns zero on success and
455fd385855SPaul Moore  * negative values on error.
45696cb8e33SPaul Moore  *
45796cb8e33SPaul Moore  */
45896cb8e33SPaul Moore static int netlbl_cipsov4_list(struct sk_buff *skb, struct genl_info *info)
45996cb8e33SPaul Moore {
460fd385855SPaul Moore 	int ret_val;
461fd385855SPaul Moore 	struct sk_buff *ans_skb = NULL;
462fd385855SPaul Moore 	u32 nlsze_mult = 1;
463fd385855SPaul Moore 	void *data;
46496cb8e33SPaul Moore 	u32 doi;
465fd385855SPaul Moore 	struct nlattr *nla_a;
466fd385855SPaul Moore 	struct nlattr *nla_b;
467fd385855SPaul Moore 	struct cipso_v4_doi *doi_def;
468fd385855SPaul Moore 	u32 iter;
46996cb8e33SPaul Moore 
470fd385855SPaul Moore 	if (!info->attrs[NLBL_CIPSOV4_A_DOI]) {
471fd385855SPaul Moore 		ret_val = -EINVAL;
47296cb8e33SPaul Moore 		goto list_failure;
473fd385855SPaul Moore 	}
47496cb8e33SPaul Moore 
475fd385855SPaul Moore list_start:
476339bf98fSThomas Graf 	ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE * nlsze_mult, GFP_KERNEL);
47796cb8e33SPaul Moore 	if (ans_skb == NULL) {
47896cb8e33SPaul Moore 		ret_val = -ENOMEM;
47996cb8e33SPaul Moore 		goto list_failure;
48096cb8e33SPaul Moore 	}
48117c157c8SThomas Graf 	data = genlmsg_put_reply(ans_skb, info, &netlbl_cipsov4_gnl_family,
48217c157c8SThomas Graf 				 0, NLBL_CIPSOV4_C_LIST);
483fd385855SPaul Moore 	if (data == NULL) {
484fd385855SPaul Moore 		ret_val = -ENOMEM;
485fd385855SPaul Moore 		goto list_failure;
486fd385855SPaul Moore 	}
48796cb8e33SPaul Moore 
488fd385855SPaul Moore 	doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
489fd385855SPaul Moore 
490fd385855SPaul Moore 	rcu_read_lock();
491fd385855SPaul Moore 	doi_def = cipso_v4_doi_getdef(doi);
492fd385855SPaul Moore 	if (doi_def == NULL) {
493fd385855SPaul Moore 		ret_val = -EINVAL;
494fd385855SPaul Moore 		goto list_failure;
495fd385855SPaul Moore 	}
496fd385855SPaul Moore 
497fd385855SPaul Moore 	ret_val = nla_put_u32(ans_skb, NLBL_CIPSOV4_A_MTYPE, doi_def->type);
498fd385855SPaul Moore 	if (ret_val != 0)
499fd385855SPaul Moore 		goto list_failure_lock;
500fd385855SPaul Moore 
501fd385855SPaul Moore 	nla_a = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_TAGLST);
502fd385855SPaul Moore 	if (nla_a == NULL) {
503fd385855SPaul Moore 		ret_val = -ENOMEM;
504fd385855SPaul Moore 		goto list_failure_lock;
505fd385855SPaul Moore 	}
506fd385855SPaul Moore 	for (iter = 0;
507fd385855SPaul Moore 	     iter < CIPSO_V4_TAG_MAXCNT &&
508fd385855SPaul Moore 	       doi_def->tags[iter] != CIPSO_V4_TAG_INVALID;
509fd385855SPaul Moore 	     iter++) {
510fd385855SPaul Moore 		ret_val = nla_put_u8(ans_skb,
511fd385855SPaul Moore 				     NLBL_CIPSOV4_A_TAG,
512fd385855SPaul Moore 				     doi_def->tags[iter]);
513fd385855SPaul Moore 		if (ret_val != 0)
514fd385855SPaul Moore 			goto list_failure_lock;
515fd385855SPaul Moore 	}
516fd385855SPaul Moore 	nla_nest_end(ans_skb, nla_a);
517fd385855SPaul Moore 
518fd385855SPaul Moore 	switch (doi_def->type) {
519fd385855SPaul Moore 	case CIPSO_V4_MAP_STD:
520fd385855SPaul Moore 		nla_a = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSLVLLST);
521fd385855SPaul Moore 		if (nla_a == NULL) {
522fd385855SPaul Moore 			ret_val = -ENOMEM;
523fd385855SPaul Moore 			goto list_failure_lock;
524fd385855SPaul Moore 		}
525fd385855SPaul Moore 		for (iter = 0;
526fd385855SPaul Moore 		     iter < doi_def->map.std->lvl.local_size;
527fd385855SPaul Moore 		     iter++) {
528fd385855SPaul Moore 			if (doi_def->map.std->lvl.local[iter] ==
529fd385855SPaul Moore 			    CIPSO_V4_INV_LVL)
530fd385855SPaul Moore 				continue;
531fd385855SPaul Moore 
532fd385855SPaul Moore 			nla_b = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSLVL);
533fd385855SPaul Moore 			if (nla_b == NULL) {
534fd385855SPaul Moore 				ret_val = -ENOMEM;
535fd385855SPaul Moore 				goto list_retry;
536fd385855SPaul Moore 			}
537fd385855SPaul Moore 			ret_val = nla_put_u32(ans_skb,
538fd385855SPaul Moore 					      NLBL_CIPSOV4_A_MLSLVLLOC,
539fd385855SPaul Moore 					      iter);
540fd385855SPaul Moore 			if (ret_val != 0)
541fd385855SPaul Moore 				goto list_retry;
542fd385855SPaul Moore 			ret_val = nla_put_u32(ans_skb,
543fd385855SPaul Moore 					    NLBL_CIPSOV4_A_MLSLVLREM,
544fd385855SPaul Moore 					    doi_def->map.std->lvl.local[iter]);
545fd385855SPaul Moore 			if (ret_val != 0)
546fd385855SPaul Moore 				goto list_retry;
547fd385855SPaul Moore 			nla_nest_end(ans_skb, nla_b);
548fd385855SPaul Moore 		}
549fd385855SPaul Moore 		nla_nest_end(ans_skb, nla_a);
550fd385855SPaul Moore 
551fd385855SPaul Moore 		nla_a = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSCATLST);
552fd385855SPaul Moore 		if (nla_a == NULL) {
553fd385855SPaul Moore 			ret_val = -ENOMEM;
554fd385855SPaul Moore 			goto list_retry;
555fd385855SPaul Moore 		}
556fd385855SPaul Moore 		for (iter = 0;
557fd385855SPaul Moore 		     iter < doi_def->map.std->cat.local_size;
558fd385855SPaul Moore 		     iter++) {
559fd385855SPaul Moore 			if (doi_def->map.std->cat.local[iter] ==
560fd385855SPaul Moore 			    CIPSO_V4_INV_CAT)
561fd385855SPaul Moore 				continue;
562fd385855SPaul Moore 
563fd385855SPaul Moore 			nla_b = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSCAT);
564fd385855SPaul Moore 			if (nla_b == NULL) {
565fd385855SPaul Moore 				ret_val = -ENOMEM;
566fd385855SPaul Moore 				goto list_retry;
567fd385855SPaul Moore 			}
568fd385855SPaul Moore 			ret_val = nla_put_u32(ans_skb,
569fd385855SPaul Moore 					      NLBL_CIPSOV4_A_MLSCATLOC,
570fd385855SPaul Moore 					      iter);
571fd385855SPaul Moore 			if (ret_val != 0)
572fd385855SPaul Moore 				goto list_retry;
573fd385855SPaul Moore 			ret_val = nla_put_u32(ans_skb,
574fd385855SPaul Moore 					    NLBL_CIPSOV4_A_MLSCATREM,
575fd385855SPaul Moore 					    doi_def->map.std->cat.local[iter]);
576fd385855SPaul Moore 			if (ret_val != 0)
577fd385855SPaul Moore 				goto list_retry;
578fd385855SPaul Moore 			nla_nest_end(ans_skb, nla_b);
579fd385855SPaul Moore 		}
580fd385855SPaul Moore 		nla_nest_end(ans_skb, nla_a);
581fd385855SPaul Moore 
582fd385855SPaul Moore 		break;
583fd385855SPaul Moore 	}
584fd385855SPaul Moore 	rcu_read_unlock();
585fd385855SPaul Moore 
586fd385855SPaul Moore 	genlmsg_end(ans_skb, data);
587*fe785beeSDenis V. Lunev 	return genlmsg_reply(ans_skb, info);
58896cb8e33SPaul Moore 
589fd385855SPaul Moore list_retry:
590fd385855SPaul Moore 	/* XXX - this limit is a guesstimate */
591fd385855SPaul Moore 	if (nlsze_mult < 4) {
592fd385855SPaul Moore 		rcu_read_unlock();
593fd385855SPaul Moore 		kfree_skb(ans_skb);
594fd385855SPaul Moore 		nlsze_mult++;
595fd385855SPaul Moore 		goto list_start;
596fd385855SPaul Moore 	}
597fd385855SPaul Moore list_failure_lock:
598fd385855SPaul Moore 	rcu_read_unlock();
59996cb8e33SPaul Moore list_failure:
600fd385855SPaul Moore 	kfree_skb(ans_skb);
601fd385855SPaul Moore 	return ret_val;
602fd385855SPaul Moore }
603fd385855SPaul Moore 
604fd385855SPaul Moore /**
605fd385855SPaul Moore  * netlbl_cipsov4_listall_cb - cipso_v4_doi_walk() callback for LISTALL
606fd385855SPaul Moore  * @doi_def: the CIPSOv4 DOI definition
607fd385855SPaul Moore  * @arg: the netlbl_cipsov4_doiwalk_arg structure
608fd385855SPaul Moore  *
609fd385855SPaul Moore  * Description:
610fd385855SPaul Moore  * This function is designed to be used as a callback to the
611fd385855SPaul Moore  * cipso_v4_doi_walk() function for use in generating a response for a LISTALL
612fd385855SPaul Moore  * message.  Returns the size of the message on success, negative values on
613fd385855SPaul Moore  * failure.
614fd385855SPaul Moore  *
615fd385855SPaul Moore  */
616fd385855SPaul Moore static int netlbl_cipsov4_listall_cb(struct cipso_v4_doi *doi_def, void *arg)
617fd385855SPaul Moore {
618fd385855SPaul Moore 	int ret_val = -ENOMEM;
619fd385855SPaul Moore 	struct netlbl_cipsov4_doiwalk_arg *cb_arg = arg;
620fd385855SPaul Moore 	void *data;
621fd385855SPaul Moore 
62217c157c8SThomas Graf 	data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).pid,
62317c157c8SThomas Graf 			   cb_arg->seq, &netlbl_cipsov4_gnl_family,
62417c157c8SThomas Graf 			   NLM_F_MULTI, NLBL_CIPSOV4_C_LISTALL);
625fd385855SPaul Moore 	if (data == NULL)
626fd385855SPaul Moore 		goto listall_cb_failure;
627fd385855SPaul Moore 
628fd385855SPaul Moore 	ret_val = nla_put_u32(cb_arg->skb, NLBL_CIPSOV4_A_DOI, doi_def->doi);
629fd385855SPaul Moore 	if (ret_val != 0)
630fd385855SPaul Moore 		goto listall_cb_failure;
631fd385855SPaul Moore 	ret_val = nla_put_u32(cb_arg->skb,
632fd385855SPaul Moore 			      NLBL_CIPSOV4_A_MTYPE,
633fd385855SPaul Moore 			      doi_def->type);
634fd385855SPaul Moore 	if (ret_val != 0)
635fd385855SPaul Moore 		goto listall_cb_failure;
636fd385855SPaul Moore 
637fd385855SPaul Moore 	return genlmsg_end(cb_arg->skb, data);
638fd385855SPaul Moore 
639fd385855SPaul Moore listall_cb_failure:
640fd385855SPaul Moore 	genlmsg_cancel(cb_arg->skb, data);
64196cb8e33SPaul Moore 	return ret_val;
64296cb8e33SPaul Moore }
64396cb8e33SPaul Moore 
64496cb8e33SPaul Moore /**
64596cb8e33SPaul Moore  * netlbl_cipsov4_listall - Handle a LISTALL message
64696cb8e33SPaul Moore  * @skb: the NETLINK buffer
647fd385855SPaul Moore  * @cb: the NETLINK callback
64896cb8e33SPaul Moore  *
64996cb8e33SPaul Moore  * Description:
65096cb8e33SPaul Moore  * Process a user generated LISTALL message and respond accordingly.  Returns
65196cb8e33SPaul Moore  * zero on success and negative values on error.
65296cb8e33SPaul Moore  *
65396cb8e33SPaul Moore  */
654fd385855SPaul Moore static int netlbl_cipsov4_listall(struct sk_buff *skb,
655fd385855SPaul Moore 				  struct netlink_callback *cb)
65696cb8e33SPaul Moore {
657fd385855SPaul Moore 	struct netlbl_cipsov4_doiwalk_arg cb_arg;
658fd385855SPaul Moore 	int doi_skip = cb->args[0];
65996cb8e33SPaul Moore 
660fd385855SPaul Moore 	cb_arg.nl_cb = cb;
661fd385855SPaul Moore 	cb_arg.skb = skb;
662fd385855SPaul Moore 	cb_arg.seq = cb->nlh->nlmsg_seq;
66396cb8e33SPaul Moore 
664fd385855SPaul Moore 	cipso_v4_doi_walk(&doi_skip, netlbl_cipsov4_listall_cb, &cb_arg);
66596cb8e33SPaul Moore 
666fd385855SPaul Moore 	cb->args[0] = doi_skip;
667fd385855SPaul Moore 	return skb->len;
66896cb8e33SPaul Moore }
66996cb8e33SPaul Moore 
67096cb8e33SPaul Moore /**
67196cb8e33SPaul Moore  * netlbl_cipsov4_remove - Handle a REMOVE message
67296cb8e33SPaul Moore  * @skb: the NETLINK buffer
67396cb8e33SPaul Moore  * @info: the Generic NETLINK info block
67496cb8e33SPaul Moore  *
67596cb8e33SPaul Moore  * Description:
67696cb8e33SPaul Moore  * Process a user generated REMOVE message and respond accordingly.  Returns
67796cb8e33SPaul Moore  * zero on success, negative values on failure.
67896cb8e33SPaul Moore  *
67996cb8e33SPaul Moore  */
68096cb8e33SPaul Moore static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info)
68196cb8e33SPaul Moore {
682fd385855SPaul Moore 	int ret_val = -EINVAL;
68332f50cdeSPaul Moore 	u32 doi = 0;
68432f50cdeSPaul Moore 	struct audit_buffer *audit_buf;
68595d4e6beSPaul Moore 	struct netlbl_audit audit_info;
68696cb8e33SPaul Moore 
68795d4e6beSPaul Moore 	if (!info->attrs[NLBL_CIPSOV4_A_DOI])
68895d4e6beSPaul Moore 		return -EINVAL;
68995d4e6beSPaul Moore 
690fd385855SPaul Moore 	doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
69195d4e6beSPaul Moore 	netlbl_netlink_auditinfo(skb, &audit_info);
69232f50cdeSPaul Moore 
69395d4e6beSPaul Moore 	ret_val = cipso_v4_doi_remove(doi,
69495d4e6beSPaul Moore 				      &audit_info,
69595d4e6beSPaul Moore 				      netlbl_cipsov4_doi_free);
69623bcdc1aSPaul Moore 	if (ret_val == 0)
697c783f1ceSPaul Moore 		atomic_dec(&netlabel_mgmt_protocount);
69895d4e6beSPaul Moore 
69932f50cdeSPaul Moore 	audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_DEL,
70095d4e6beSPaul Moore 					      &audit_info);
701de64688fSPaul Moore 	if (audit_buf != NULL) {
70295d4e6beSPaul Moore 		audit_log_format(audit_buf,
70395d4e6beSPaul Moore 				 " cipso_doi=%u res=%u",
70495d4e6beSPaul Moore 				 doi,
70595d4e6beSPaul Moore 				 ret_val == 0 ? 1 : 0);
70632f50cdeSPaul Moore 		audit_log_end(audit_buf);
707de64688fSPaul Moore 	}
70896cb8e33SPaul Moore 
70996cb8e33SPaul Moore 	return ret_val;
71096cb8e33SPaul Moore }
71196cb8e33SPaul Moore 
71296cb8e33SPaul Moore /*
71396cb8e33SPaul Moore  * NetLabel Generic NETLINK Command Definitions
71496cb8e33SPaul Moore  */
71596cb8e33SPaul Moore 
716227c43c3SPavel Emelyanov static struct genl_ops netlbl_cipsov4_ops[] = {
717227c43c3SPavel Emelyanov 	{
71896cb8e33SPaul Moore 	.cmd = NLBL_CIPSOV4_C_ADD,
719fd385855SPaul Moore 	.flags = GENL_ADMIN_PERM,
720fd385855SPaul Moore 	.policy = netlbl_cipsov4_genl_policy,
72196cb8e33SPaul Moore 	.doit = netlbl_cipsov4_add,
72296cb8e33SPaul Moore 	.dumpit = NULL,
723227c43c3SPavel Emelyanov 	},
724227c43c3SPavel Emelyanov 	{
72596cb8e33SPaul Moore 	.cmd = NLBL_CIPSOV4_C_REMOVE,
726fd385855SPaul Moore 	.flags = GENL_ADMIN_PERM,
727fd385855SPaul Moore 	.policy = netlbl_cipsov4_genl_policy,
72896cb8e33SPaul Moore 	.doit = netlbl_cipsov4_remove,
72996cb8e33SPaul Moore 	.dumpit = NULL,
730227c43c3SPavel Emelyanov 	},
731227c43c3SPavel Emelyanov 	{
73296cb8e33SPaul Moore 	.cmd = NLBL_CIPSOV4_C_LIST,
73396cb8e33SPaul Moore 	.flags = 0,
734fd385855SPaul Moore 	.policy = netlbl_cipsov4_genl_policy,
73596cb8e33SPaul Moore 	.doit = netlbl_cipsov4_list,
73696cb8e33SPaul Moore 	.dumpit = NULL,
737227c43c3SPavel Emelyanov 	},
738227c43c3SPavel Emelyanov 	{
73996cb8e33SPaul Moore 	.cmd = NLBL_CIPSOV4_C_LISTALL,
74096cb8e33SPaul Moore 	.flags = 0,
741fd385855SPaul Moore 	.policy = netlbl_cipsov4_genl_policy,
742fd385855SPaul Moore 	.doit = NULL,
743fd385855SPaul Moore 	.dumpit = netlbl_cipsov4_listall,
744227c43c3SPavel Emelyanov 	},
74596cb8e33SPaul Moore };
74696cb8e33SPaul Moore 
74796cb8e33SPaul Moore /*
74896cb8e33SPaul Moore  * NetLabel Generic NETLINK Protocol Functions
74996cb8e33SPaul Moore  */
75096cb8e33SPaul Moore 
75196cb8e33SPaul Moore /**
75296cb8e33SPaul Moore  * netlbl_cipsov4_genl_init - Register the CIPSOv4 NetLabel component
75396cb8e33SPaul Moore  *
75496cb8e33SPaul Moore  * Description:
75596cb8e33SPaul Moore  * Register the CIPSOv4 packet NetLabel component with the Generic NETLINK
75696cb8e33SPaul Moore  * mechanism.  Returns zero on success, negative values on failure.
75796cb8e33SPaul Moore  *
75896cb8e33SPaul Moore  */
75905705e4eSPavel Emelyanov int __init netlbl_cipsov4_genl_init(void)
76096cb8e33SPaul Moore {
761227c43c3SPavel Emelyanov 	int ret_val, i;
76296cb8e33SPaul Moore 
76396cb8e33SPaul Moore 	ret_val = genl_register_family(&netlbl_cipsov4_gnl_family);
76496cb8e33SPaul Moore 	if (ret_val != 0)
76596cb8e33SPaul Moore 		return ret_val;
76696cb8e33SPaul Moore 
767227c43c3SPavel Emelyanov 	for (i = 0; i < ARRAY_SIZE(netlbl_cipsov4_ops); i++) {
76896cb8e33SPaul Moore 		ret_val = genl_register_ops(&netlbl_cipsov4_gnl_family,
769227c43c3SPavel Emelyanov 				&netlbl_cipsov4_ops[i]);
77096cb8e33SPaul Moore 		if (ret_val != 0)
77196cb8e33SPaul Moore 			return ret_val;
772227c43c3SPavel Emelyanov 	}
77396cb8e33SPaul Moore 
77496cb8e33SPaul Moore 	return 0;
77596cb8e33SPaul Moore }
776