xref: /openbmc/linux/net/netlabel/netlabel_cipso_v4.c (revision 1fd2a25b77bb6755d38aca50b826ff8dca81d762)
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>
4196cb8e33SPaul Moore 
4296cb8e33SPaul Moore #include "netlabel_user.h"
4396cb8e33SPaul Moore #include "netlabel_cipso_v4.h"
4496cb8e33SPaul Moore 
45fd385855SPaul Moore /* Argument struct for cipso_v4_doi_walk() */
46fd385855SPaul Moore struct netlbl_cipsov4_doiwalk_arg {
47fd385855SPaul Moore 	struct netlink_callback *nl_cb;
48fd385855SPaul Moore 	struct sk_buff *skb;
49fd385855SPaul Moore 	u32 seq;
50fd385855SPaul Moore };
51fd385855SPaul Moore 
5296cb8e33SPaul Moore /* NetLabel Generic NETLINK CIPSOv4 family */
5396cb8e33SPaul Moore static struct genl_family netlbl_cipsov4_gnl_family = {
5496cb8e33SPaul Moore 	.id = GENL_ID_GENERATE,
5596cb8e33SPaul Moore 	.hdrsize = 0,
5696cb8e33SPaul Moore 	.name = NETLBL_NLTYPE_CIPSOV4_NAME,
5796cb8e33SPaul Moore 	.version = NETLBL_PROTO_VERSION,
58fd385855SPaul Moore 	.maxattr = NLBL_CIPSOV4_A_MAX,
5996cb8e33SPaul Moore };
6096cb8e33SPaul Moore 
61fd385855SPaul Moore /* NetLabel Netlink attribute policy */
62fd385855SPaul Moore static struct nla_policy netlbl_cipsov4_genl_policy[NLBL_CIPSOV4_A_MAX + 1] = {
63fd385855SPaul Moore 	[NLBL_CIPSOV4_A_DOI] = { .type = NLA_U32 },
64fd385855SPaul Moore 	[NLBL_CIPSOV4_A_MTYPE] = { .type = NLA_U32 },
65fd385855SPaul Moore 	[NLBL_CIPSOV4_A_TAG] = { .type = NLA_U8 },
66fd385855SPaul Moore 	[NLBL_CIPSOV4_A_TAGLST] = { .type = NLA_NESTED },
67fd385855SPaul Moore 	[NLBL_CIPSOV4_A_MLSLVLLOC] = { .type = NLA_U32 },
68fd385855SPaul Moore 	[NLBL_CIPSOV4_A_MLSLVLREM] = { .type = NLA_U32 },
69fd385855SPaul Moore 	[NLBL_CIPSOV4_A_MLSLVL] = { .type = NLA_NESTED },
70fd385855SPaul Moore 	[NLBL_CIPSOV4_A_MLSLVLLST] = { .type = NLA_NESTED },
71fd385855SPaul Moore 	[NLBL_CIPSOV4_A_MLSCATLOC] = { .type = NLA_U32 },
72fd385855SPaul Moore 	[NLBL_CIPSOV4_A_MLSCATREM] = { .type = NLA_U32 },
73fd385855SPaul Moore 	[NLBL_CIPSOV4_A_MLSCAT] = { .type = NLA_NESTED },
74fd385855SPaul Moore 	[NLBL_CIPSOV4_A_MLSCATLST] = { .type = NLA_NESTED },
75fd385855SPaul Moore };
7696cb8e33SPaul Moore 
7796cb8e33SPaul Moore /*
7896cb8e33SPaul Moore  * Helper Functions
7996cb8e33SPaul Moore  */
8096cb8e33SPaul Moore 
8196cb8e33SPaul Moore /**
8296cb8e33SPaul Moore  * netlbl_cipsov4_doi_free - Frees a CIPSO V4 DOI definition
8396cb8e33SPaul Moore  * @entry: the entry's RCU field
8496cb8e33SPaul Moore  *
8596cb8e33SPaul Moore  * Description:
8696cb8e33SPaul Moore  * This function is designed to be used as a callback to the call_rcu()
8796cb8e33SPaul Moore  * function so that the memory allocated to the DOI definition can be released
8896cb8e33SPaul Moore  * safely.
8996cb8e33SPaul Moore  *
9096cb8e33SPaul Moore  */
9196cb8e33SPaul Moore static void netlbl_cipsov4_doi_free(struct rcu_head *entry)
9296cb8e33SPaul Moore {
9396cb8e33SPaul Moore 	struct cipso_v4_doi *ptr;
9496cb8e33SPaul Moore 
9596cb8e33SPaul Moore 	ptr = container_of(entry, struct cipso_v4_doi, rcu);
9696cb8e33SPaul Moore 	switch (ptr->type) {
9796cb8e33SPaul Moore 	case CIPSO_V4_MAP_STD:
9896cb8e33SPaul Moore 		kfree(ptr->map.std->lvl.cipso);
9996cb8e33SPaul Moore 		kfree(ptr->map.std->lvl.local);
10096cb8e33SPaul Moore 		kfree(ptr->map.std->cat.cipso);
10196cb8e33SPaul Moore 		kfree(ptr->map.std->cat.local);
10296cb8e33SPaul Moore 		break;
10396cb8e33SPaul Moore 	}
10496cb8e33SPaul Moore 	kfree(ptr);
10596cb8e33SPaul Moore }
10696cb8e33SPaul Moore 
107fd385855SPaul Moore /**
108fd385855SPaul Moore  * netlbl_cipsov4_add_common - Parse the common sections of a ADD message
109fd385855SPaul Moore  * @info: the Generic NETLINK info block
110fd385855SPaul Moore  * @doi_def: the CIPSO V4 DOI definition
111fd385855SPaul Moore  *
112fd385855SPaul Moore  * Description:
113fd385855SPaul Moore  * Parse the common sections of a ADD message and fill in the related values
114fd385855SPaul Moore  * in @doi_def.  Returns zero on success, negative values on failure.
115fd385855SPaul Moore  *
116fd385855SPaul Moore  */
117fd385855SPaul Moore static int netlbl_cipsov4_add_common(struct genl_info *info,
118fd385855SPaul Moore 				     struct cipso_v4_doi *doi_def)
119fd385855SPaul Moore {
120fd385855SPaul Moore 	struct nlattr *nla;
121fd385855SPaul Moore 	int nla_rem;
122fd385855SPaul Moore 	u32 iter = 0;
123fd385855SPaul Moore 
124fd385855SPaul Moore 	doi_def->doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
125fd385855SPaul Moore 
126fd385855SPaul Moore 	if (nla_validate_nested(info->attrs[NLBL_CIPSOV4_A_TAGLST],
127fd385855SPaul Moore 				NLBL_CIPSOV4_A_MAX,
128fd385855SPaul Moore 				netlbl_cipsov4_genl_policy) != 0)
129fd385855SPaul Moore 		return -EINVAL;
130fd385855SPaul Moore 
131fd385855SPaul Moore 	nla_for_each_nested(nla, info->attrs[NLBL_CIPSOV4_A_TAGLST], nla_rem)
132fd385855SPaul Moore 		if (nla->nla_type == NLBL_CIPSOV4_A_TAG) {
133fd385855SPaul Moore 			if (iter > CIPSO_V4_TAG_MAXCNT)
134fd385855SPaul Moore 				return -EINVAL;
135fd385855SPaul Moore 			doi_def->tags[iter++] = nla_get_u8(nla);
136fd385855SPaul Moore 		}
137fd385855SPaul Moore 	if (iter < CIPSO_V4_TAG_MAXCNT)
138fd385855SPaul Moore 		doi_def->tags[iter] = CIPSO_V4_TAG_INVALID;
139fd385855SPaul Moore 
140fd385855SPaul Moore 	return 0;
141fd385855SPaul Moore }
14296cb8e33SPaul Moore 
14396cb8e33SPaul Moore /*
14496cb8e33SPaul Moore  * NetLabel Command Handlers
14596cb8e33SPaul Moore  */
14696cb8e33SPaul Moore 
14796cb8e33SPaul Moore /**
14896cb8e33SPaul Moore  * netlbl_cipsov4_add_std - Adds a CIPSO V4 DOI definition
149fd385855SPaul Moore  * @info: the Generic NETLINK info block
15096cb8e33SPaul Moore  *
15196cb8e33SPaul Moore  * Description:
15296cb8e33SPaul Moore  * Create a new CIPSO_V4_MAP_STD DOI definition based on the given ADD message
15396cb8e33SPaul Moore  * and add it to the CIPSO V4 engine.  Return zero on success and non-zero on
15496cb8e33SPaul Moore  * error.
15596cb8e33SPaul Moore  *
15696cb8e33SPaul Moore  */
157fd385855SPaul Moore static int netlbl_cipsov4_add_std(struct genl_info *info)
15896cb8e33SPaul Moore {
15996cb8e33SPaul Moore 	int ret_val = -EINVAL;
16096cb8e33SPaul Moore 	struct cipso_v4_doi *doi_def = NULL;
161fd385855SPaul Moore 	struct nlattr *nla_a;
162fd385855SPaul Moore 	struct nlattr *nla_b;
163fd385855SPaul Moore 	int nla_a_rem;
164fd385855SPaul Moore 	int nla_b_rem;
16596cb8e33SPaul Moore 
16632f50cdeSPaul Moore 	if (!info->attrs[NLBL_CIPSOV4_A_TAGLST] ||
167fd385855SPaul Moore 	    !info->attrs[NLBL_CIPSOV4_A_MLSLVLLST])
168fd385855SPaul Moore 		return -EINVAL;
169fd385855SPaul Moore 
170fd385855SPaul Moore 	if (nla_validate_nested(info->attrs[NLBL_CIPSOV4_A_MLSLVLLST],
171fd385855SPaul Moore 				NLBL_CIPSOV4_A_MAX,
172fd385855SPaul Moore 				netlbl_cipsov4_genl_policy) != 0)
173fd385855SPaul Moore 		return -EINVAL;
17496cb8e33SPaul Moore 
17596cb8e33SPaul Moore 	doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
176fd385855SPaul Moore 	if (doi_def == NULL)
177fd385855SPaul Moore 		return -ENOMEM;
17896cb8e33SPaul Moore 	doi_def->map.std = kzalloc(sizeof(*doi_def->map.std), GFP_KERNEL);
17996cb8e33SPaul Moore 	if (doi_def->map.std == NULL) {
18096cb8e33SPaul Moore 		ret_val = -ENOMEM;
18196cb8e33SPaul Moore 		goto add_std_failure;
18296cb8e33SPaul Moore 	}
18396cb8e33SPaul Moore 	doi_def->type = CIPSO_V4_MAP_STD;
18496cb8e33SPaul Moore 
185fd385855SPaul Moore 	ret_val = netlbl_cipsov4_add_common(info, doi_def);
186fd385855SPaul Moore 	if (ret_val != 0)
18796cb8e33SPaul Moore 		goto add_std_failure;
188*1fd2a25bSPaul Moore 	ret_val = -EINVAL;
189fd385855SPaul Moore 
190fd385855SPaul Moore 	nla_for_each_nested(nla_a,
191fd385855SPaul Moore 			    info->attrs[NLBL_CIPSOV4_A_MLSLVLLST],
192fd385855SPaul Moore 			    nla_a_rem)
193fd385855SPaul Moore 		if (nla_a->nla_type == NLBL_CIPSOV4_A_MLSLVL) {
194*1fd2a25bSPaul Moore 			if (nla_validate_nested(nla_a,
195*1fd2a25bSPaul Moore 					    NLBL_CIPSOV4_A_MAX,
196*1fd2a25bSPaul Moore 					    netlbl_cipsov4_genl_policy) != 0)
197*1fd2a25bSPaul Moore 					goto add_std_failure;
198fd385855SPaul Moore 			nla_for_each_nested(nla_b, nla_a, nla_b_rem)
199fd385855SPaul Moore 				switch (nla_b->nla_type) {
200fd385855SPaul Moore 				case NLBL_CIPSOV4_A_MLSLVLLOC:
201*1fd2a25bSPaul Moore 					if (nla_get_u32(nla_b) >
202*1fd2a25bSPaul Moore 					    CIPSO_V4_MAX_LOC_LVLS)
203*1fd2a25bSPaul Moore 						goto add_std_failure;
204fd385855SPaul Moore 					if (nla_get_u32(nla_b) >=
205fd385855SPaul Moore 					    doi_def->map.std->lvl.local_size)
206fd385855SPaul Moore 					     doi_def->map.std->lvl.local_size =
207fd385855SPaul Moore 						     nla_get_u32(nla_b) + 1;
20896cb8e33SPaul Moore 					break;
209fd385855SPaul Moore 				case NLBL_CIPSOV4_A_MLSLVLREM:
210*1fd2a25bSPaul Moore 					if (nla_get_u32(nla_b) >
211*1fd2a25bSPaul Moore 					    CIPSO_V4_MAX_REM_LVLS)
212*1fd2a25bSPaul Moore 						goto add_std_failure;
213fd385855SPaul Moore 					if (nla_get_u32(nla_b) >=
214fd385855SPaul Moore 					    doi_def->map.std->lvl.cipso_size)
215fd385855SPaul Moore 					     doi_def->map.std->lvl.cipso_size =
216fd385855SPaul Moore 						     nla_get_u32(nla_b) + 1;
217fd385855SPaul Moore 					break;
21896cb8e33SPaul Moore 				}
21996cb8e33SPaul Moore 		}
22096cb8e33SPaul Moore 	doi_def->map.std->lvl.local = kcalloc(doi_def->map.std->lvl.local_size,
22196cb8e33SPaul Moore 					      sizeof(u32),
22296cb8e33SPaul Moore 					      GFP_KERNEL);
22396cb8e33SPaul Moore 	if (doi_def->map.std->lvl.local == NULL) {
22496cb8e33SPaul Moore 		ret_val = -ENOMEM;
22596cb8e33SPaul Moore 		goto add_std_failure;
22696cb8e33SPaul Moore 	}
22796cb8e33SPaul Moore 	doi_def->map.std->lvl.cipso = kcalloc(doi_def->map.std->lvl.cipso_size,
22896cb8e33SPaul Moore 					      sizeof(u32),
22996cb8e33SPaul Moore 					      GFP_KERNEL);
23096cb8e33SPaul Moore 	if (doi_def->map.std->lvl.cipso == NULL) {
23196cb8e33SPaul Moore 		ret_val = -ENOMEM;
23296cb8e33SPaul Moore 		goto add_std_failure;
23396cb8e33SPaul Moore 	}
234fd385855SPaul Moore 	nla_for_each_nested(nla_a,
235fd385855SPaul Moore 			    info->attrs[NLBL_CIPSOV4_A_MLSLVLLST],
236fd385855SPaul Moore 			    nla_a_rem)
237fd385855SPaul Moore 		if (nla_a->nla_type == NLBL_CIPSOV4_A_MLSLVL) {
238fd385855SPaul Moore 			struct nlattr *lvl_loc;
239fd385855SPaul Moore 			struct nlattr *lvl_rem;
24096cb8e33SPaul Moore 
241fd385855SPaul Moore 			lvl_loc = nla_find_nested(nla_a,
242fd385855SPaul Moore 						  NLBL_CIPSOV4_A_MLSLVLLOC);
243fd385855SPaul Moore 			lvl_rem = nla_find_nested(nla_a,
244fd385855SPaul Moore 						  NLBL_CIPSOV4_A_MLSLVLREM);
245fd385855SPaul Moore 			if (lvl_loc == NULL || lvl_rem == NULL)
246fd385855SPaul Moore 				goto add_std_failure;
247fd385855SPaul Moore 			doi_def->map.std->lvl.local[nla_get_u32(lvl_loc)] =
248fd385855SPaul Moore 				nla_get_u32(lvl_rem);
249fd385855SPaul Moore 			doi_def->map.std->lvl.cipso[nla_get_u32(lvl_rem)] =
250fd385855SPaul Moore 				nla_get_u32(lvl_loc);
251fd385855SPaul Moore 		}
252fd385855SPaul Moore 
253fd385855SPaul Moore 	if (info->attrs[NLBL_CIPSOV4_A_MLSCATLST]) {
254fd385855SPaul Moore 		if (nla_validate_nested(info->attrs[NLBL_CIPSOV4_A_MLSCATLST],
255fd385855SPaul Moore 					NLBL_CIPSOV4_A_MAX,
256fd385855SPaul Moore 					netlbl_cipsov4_genl_policy) != 0)
257fd385855SPaul Moore 			goto add_std_failure;
258fd385855SPaul Moore 
259fd385855SPaul Moore 		nla_for_each_nested(nla_a,
260fd385855SPaul Moore 				    info->attrs[NLBL_CIPSOV4_A_MLSCATLST],
261fd385855SPaul Moore 				    nla_a_rem)
262fd385855SPaul Moore 			if (nla_a->nla_type == NLBL_CIPSOV4_A_MLSCAT) {
263fd385855SPaul Moore 				if (nla_validate_nested(nla_a,
264fd385855SPaul Moore 					      NLBL_CIPSOV4_A_MAX,
265fd385855SPaul Moore 					      netlbl_cipsov4_genl_policy) != 0)
266fd385855SPaul Moore 					goto add_std_failure;
267fd385855SPaul Moore 				nla_for_each_nested(nla_b, nla_a, nla_b_rem)
268fd385855SPaul Moore 					switch (nla_b->nla_type) {
269fd385855SPaul Moore 					case NLBL_CIPSOV4_A_MLSCATLOC:
270*1fd2a25bSPaul Moore 						if (nla_get_u32(nla_b) >
271*1fd2a25bSPaul Moore 						    CIPSO_V4_MAX_LOC_CATS)
272*1fd2a25bSPaul Moore 							goto add_std_failure;
273fd385855SPaul Moore 						if (nla_get_u32(nla_b) >=
274fd385855SPaul Moore 					      doi_def->map.std->cat.local_size)
275fd385855SPaul Moore 					     doi_def->map.std->cat.local_size =
276fd385855SPaul Moore 						     nla_get_u32(nla_b) + 1;
277fd385855SPaul Moore 						break;
278fd385855SPaul Moore 					case NLBL_CIPSOV4_A_MLSCATREM:
279*1fd2a25bSPaul Moore 						if (nla_get_u32(nla_b) >
280*1fd2a25bSPaul Moore 						    CIPSO_V4_MAX_REM_CATS)
281*1fd2a25bSPaul Moore 							goto add_std_failure;
282fd385855SPaul Moore 						if (nla_get_u32(nla_b) >=
283fd385855SPaul Moore 					      doi_def->map.std->cat.cipso_size)
284fd385855SPaul Moore 					     doi_def->map.std->cat.cipso_size =
285fd385855SPaul Moore 						     nla_get_u32(nla_b) + 1;
286fd385855SPaul Moore 						break;
287fd385855SPaul Moore 					}
288fd385855SPaul Moore 			}
289fd385855SPaul Moore 		doi_def->map.std->cat.local = kcalloc(
290fd385855SPaul Moore 			                      doi_def->map.std->cat.local_size,
29196cb8e33SPaul Moore 					      sizeof(u32),
29296cb8e33SPaul Moore 					      GFP_KERNEL);
29396cb8e33SPaul Moore 		if (doi_def->map.std->cat.local == NULL) {
29496cb8e33SPaul Moore 			ret_val = -ENOMEM;
29596cb8e33SPaul Moore 			goto add_std_failure;
29696cb8e33SPaul Moore 		}
297fd385855SPaul Moore 		doi_def->map.std->cat.cipso = kcalloc(
298fd385855SPaul Moore 			                      doi_def->map.std->cat.cipso_size,
29996cb8e33SPaul Moore 					      sizeof(u32),
30096cb8e33SPaul Moore 					      GFP_KERNEL);
30196cb8e33SPaul Moore 		if (doi_def->map.std->cat.cipso == NULL) {
30296cb8e33SPaul Moore 			ret_val = -ENOMEM;
30396cb8e33SPaul Moore 			goto add_std_failure;
30496cb8e33SPaul Moore 		}
305fd385855SPaul Moore 		nla_for_each_nested(nla_a,
306fd385855SPaul Moore 				    info->attrs[NLBL_CIPSOV4_A_MLSCATLST],
307fd385855SPaul Moore 				    nla_a_rem)
308fd385855SPaul Moore 			if (nla_a->nla_type == NLBL_CIPSOV4_A_MLSCAT) {
309fd385855SPaul Moore 				struct nlattr *cat_loc;
310fd385855SPaul Moore 				struct nlattr *cat_rem;
31196cb8e33SPaul Moore 
312fd385855SPaul Moore 				cat_loc = nla_find_nested(nla_a,
313fd385855SPaul Moore 						     NLBL_CIPSOV4_A_MLSCATLOC);
314fd385855SPaul Moore 				cat_rem = nla_find_nested(nla_a,
315fd385855SPaul Moore 						     NLBL_CIPSOV4_A_MLSCATREM);
316fd385855SPaul Moore 				if (cat_loc == NULL || cat_rem == NULL)
31796cb8e33SPaul Moore 					goto add_std_failure;
318fd385855SPaul Moore 				doi_def->map.std->cat.local[
319fd385855SPaul Moore 				                        nla_get_u32(cat_loc)] =
320fd385855SPaul Moore 					nla_get_u32(cat_rem);
321fd385855SPaul Moore 				doi_def->map.std->cat.cipso[
322fd385855SPaul Moore 					                nla_get_u32(cat_rem)] =
323fd385855SPaul Moore 					nla_get_u32(cat_loc);
324fd385855SPaul Moore 			}
32596cb8e33SPaul Moore 	}
32696cb8e33SPaul Moore 
32796cb8e33SPaul Moore 	ret_val = cipso_v4_doi_add(doi_def);
32896cb8e33SPaul Moore 	if (ret_val != 0)
32996cb8e33SPaul Moore 		goto add_std_failure;
33096cb8e33SPaul Moore 	return 0;
33196cb8e33SPaul Moore 
33296cb8e33SPaul Moore add_std_failure:
33396cb8e33SPaul Moore 	if (doi_def)
33496cb8e33SPaul Moore 		netlbl_cipsov4_doi_free(&doi_def->rcu);
33596cb8e33SPaul Moore 	return ret_val;
33696cb8e33SPaul Moore }
33796cb8e33SPaul Moore 
33896cb8e33SPaul Moore /**
33996cb8e33SPaul Moore  * netlbl_cipsov4_add_pass - Adds a CIPSO V4 DOI definition
340fd385855SPaul Moore  * @info: the Generic NETLINK info block
34196cb8e33SPaul Moore  *
34296cb8e33SPaul Moore  * Description:
34396cb8e33SPaul Moore  * Create a new CIPSO_V4_MAP_PASS DOI definition based on the given ADD message
34496cb8e33SPaul Moore  * and add it to the CIPSO V4 engine.  Return zero on success and non-zero on
34596cb8e33SPaul Moore  * error.
34696cb8e33SPaul Moore  *
34796cb8e33SPaul Moore  */
348fd385855SPaul Moore static int netlbl_cipsov4_add_pass(struct genl_info *info)
34996cb8e33SPaul Moore {
350fd385855SPaul Moore 	int ret_val;
35196cb8e33SPaul Moore 	struct cipso_v4_doi *doi_def = NULL;
35296cb8e33SPaul Moore 
35332f50cdeSPaul Moore 	if (!info->attrs[NLBL_CIPSOV4_A_TAGLST])
354fd385855SPaul Moore 		return -EINVAL;
35596cb8e33SPaul Moore 
35696cb8e33SPaul Moore 	doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
357fd385855SPaul Moore 	if (doi_def == NULL)
358fd385855SPaul Moore 		return -ENOMEM;
35996cb8e33SPaul Moore 	doi_def->type = CIPSO_V4_MAP_PASS;
36096cb8e33SPaul Moore 
361fd385855SPaul Moore 	ret_val = netlbl_cipsov4_add_common(info, doi_def);
362fd385855SPaul Moore 	if (ret_val != 0)
36396cb8e33SPaul Moore 		goto add_pass_failure;
36496cb8e33SPaul Moore 
36596cb8e33SPaul Moore 	ret_val = cipso_v4_doi_add(doi_def);
36696cb8e33SPaul Moore 	if (ret_val != 0)
36796cb8e33SPaul Moore 		goto add_pass_failure;
36896cb8e33SPaul Moore 	return 0;
36996cb8e33SPaul Moore 
37096cb8e33SPaul Moore add_pass_failure:
37196cb8e33SPaul Moore 	netlbl_cipsov4_doi_free(&doi_def->rcu);
37296cb8e33SPaul Moore 	return ret_val;
37396cb8e33SPaul Moore }
37496cb8e33SPaul Moore 
37596cb8e33SPaul Moore /**
37696cb8e33SPaul Moore  * netlbl_cipsov4_add - Handle an ADD message
37796cb8e33SPaul Moore  * @skb: the NETLINK buffer
37896cb8e33SPaul Moore  * @info: the Generic NETLINK info block
37996cb8e33SPaul Moore  *
38096cb8e33SPaul Moore  * Description:
38196cb8e33SPaul Moore  * Create a new DOI definition based on the given ADD message and add it to the
38296cb8e33SPaul Moore  * CIPSO V4 engine.  Returns zero on success, negative values on failure.
38396cb8e33SPaul Moore  *
38496cb8e33SPaul Moore  */
38596cb8e33SPaul Moore static int netlbl_cipsov4_add(struct sk_buff *skb, struct genl_info *info)
38696cb8e33SPaul Moore 
38796cb8e33SPaul Moore {
38896cb8e33SPaul Moore 	int ret_val = -EINVAL;
38932f50cdeSPaul Moore 	u32 type;
39032f50cdeSPaul Moore 	u32 doi;
39132f50cdeSPaul Moore 	const char *type_str = "(unknown)";
39232f50cdeSPaul Moore 	struct audit_buffer *audit_buf;
39395d4e6beSPaul Moore 	struct netlbl_audit audit_info;
39496cb8e33SPaul Moore 
39532f50cdeSPaul Moore 	if (!info->attrs[NLBL_CIPSOV4_A_DOI] ||
39632f50cdeSPaul Moore 	    !info->attrs[NLBL_CIPSOV4_A_MTYPE])
397fd385855SPaul Moore 		return -EINVAL;
39896cb8e33SPaul Moore 
39995d4e6beSPaul Moore 	doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
40095d4e6beSPaul Moore 	netlbl_netlink_auditinfo(skb, &audit_info);
40195d4e6beSPaul Moore 
40232f50cdeSPaul Moore 	type = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_MTYPE]);
40332f50cdeSPaul Moore 	switch (type) {
40496cb8e33SPaul Moore 	case CIPSO_V4_MAP_STD:
40532f50cdeSPaul Moore 		type_str = "std";
406fd385855SPaul Moore 		ret_val = netlbl_cipsov4_add_std(info);
40796cb8e33SPaul Moore 		break;
40896cb8e33SPaul Moore 	case CIPSO_V4_MAP_PASS:
40932f50cdeSPaul Moore 		type_str = "pass";
410fd385855SPaul Moore 		ret_val = netlbl_cipsov4_add_pass(info);
41196cb8e33SPaul Moore 		break;
41296cb8e33SPaul Moore 	}
41396cb8e33SPaul Moore 
41432f50cdeSPaul Moore 	audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_ADD,
41595d4e6beSPaul Moore 					      &audit_info);
416de64688fSPaul Moore 	if (audit_buf != NULL) {
41795d4e6beSPaul Moore 		audit_log_format(audit_buf,
41895d4e6beSPaul Moore 				 " cipso_doi=%u cipso_type=%s res=%u",
41995d4e6beSPaul Moore 				 doi,
42095d4e6beSPaul Moore 				 type_str,
42195d4e6beSPaul Moore 				 ret_val == 0 ? 1 : 0);
42232f50cdeSPaul Moore 		audit_log_end(audit_buf);
423de64688fSPaul Moore 	}
42432f50cdeSPaul Moore 
42596cb8e33SPaul Moore 	return ret_val;
42696cb8e33SPaul Moore }
42796cb8e33SPaul Moore 
42896cb8e33SPaul Moore /**
42996cb8e33SPaul Moore  * netlbl_cipsov4_list - Handle a LIST message
43096cb8e33SPaul Moore  * @skb: the NETLINK buffer
43196cb8e33SPaul Moore  * @info: the Generic NETLINK info block
43296cb8e33SPaul Moore  *
43396cb8e33SPaul Moore  * Description:
434fd385855SPaul Moore  * Process a user generated LIST message and respond accordingly.  While the
435fd385855SPaul Moore  * response message generated by the kernel is straightforward, determining
436fd385855SPaul Moore  * before hand the size of the buffer to allocate is not (we have to generate
437fd385855SPaul Moore  * the message to know the size).  In order to keep this function sane what we
438fd385855SPaul Moore  * do is allocate a buffer of NLMSG_GOODSIZE and try to fit the response in
439fd385855SPaul Moore  * that size, if we fail then we restart with a larger buffer and try again.
440fd385855SPaul Moore  * We continue in this manner until we hit a limit of failed attempts then we
441fd385855SPaul Moore  * give up and just send an error message.  Returns zero on success and
442fd385855SPaul Moore  * negative values on error.
44396cb8e33SPaul Moore  *
44496cb8e33SPaul Moore  */
44596cb8e33SPaul Moore static int netlbl_cipsov4_list(struct sk_buff *skb, struct genl_info *info)
44696cb8e33SPaul Moore {
447fd385855SPaul Moore 	int ret_val;
448fd385855SPaul Moore 	struct sk_buff *ans_skb = NULL;
449fd385855SPaul Moore 	u32 nlsze_mult = 1;
450fd385855SPaul Moore 	void *data;
45196cb8e33SPaul Moore 	u32 doi;
452fd385855SPaul Moore 	struct nlattr *nla_a;
453fd385855SPaul Moore 	struct nlattr *nla_b;
454fd385855SPaul Moore 	struct cipso_v4_doi *doi_def;
455fd385855SPaul Moore 	u32 iter;
45696cb8e33SPaul Moore 
457fd385855SPaul Moore 	if (!info->attrs[NLBL_CIPSOV4_A_DOI]) {
458fd385855SPaul Moore 		ret_val = -EINVAL;
45996cb8e33SPaul Moore 		goto list_failure;
460fd385855SPaul Moore 	}
46196cb8e33SPaul Moore 
462fd385855SPaul Moore list_start:
463339bf98fSThomas Graf 	ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE * nlsze_mult, GFP_KERNEL);
46496cb8e33SPaul Moore 	if (ans_skb == NULL) {
46596cb8e33SPaul Moore 		ret_val = -ENOMEM;
46696cb8e33SPaul Moore 		goto list_failure;
46796cb8e33SPaul Moore 	}
46817c157c8SThomas Graf 	data = genlmsg_put_reply(ans_skb, info, &netlbl_cipsov4_gnl_family,
46917c157c8SThomas Graf 				 0, NLBL_CIPSOV4_C_LIST);
470fd385855SPaul Moore 	if (data == NULL) {
471fd385855SPaul Moore 		ret_val = -ENOMEM;
472fd385855SPaul Moore 		goto list_failure;
473fd385855SPaul Moore 	}
47496cb8e33SPaul Moore 
475fd385855SPaul Moore 	doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
476fd385855SPaul Moore 
477fd385855SPaul Moore 	rcu_read_lock();
478fd385855SPaul Moore 	doi_def = cipso_v4_doi_getdef(doi);
479fd385855SPaul Moore 	if (doi_def == NULL) {
480fd385855SPaul Moore 		ret_val = -EINVAL;
481fd385855SPaul Moore 		goto list_failure;
482fd385855SPaul Moore 	}
483fd385855SPaul Moore 
484fd385855SPaul Moore 	ret_val = nla_put_u32(ans_skb, NLBL_CIPSOV4_A_MTYPE, doi_def->type);
485fd385855SPaul Moore 	if (ret_val != 0)
486fd385855SPaul Moore 		goto list_failure_lock;
487fd385855SPaul Moore 
488fd385855SPaul Moore 	nla_a = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_TAGLST);
489fd385855SPaul Moore 	if (nla_a == NULL) {
490fd385855SPaul Moore 		ret_val = -ENOMEM;
491fd385855SPaul Moore 		goto list_failure_lock;
492fd385855SPaul Moore 	}
493fd385855SPaul Moore 	for (iter = 0;
494fd385855SPaul Moore 	     iter < CIPSO_V4_TAG_MAXCNT &&
495fd385855SPaul Moore 	       doi_def->tags[iter] != CIPSO_V4_TAG_INVALID;
496fd385855SPaul Moore 	     iter++) {
497fd385855SPaul Moore 		ret_val = nla_put_u8(ans_skb,
498fd385855SPaul Moore 				     NLBL_CIPSOV4_A_TAG,
499fd385855SPaul Moore 				     doi_def->tags[iter]);
500fd385855SPaul Moore 		if (ret_val != 0)
501fd385855SPaul Moore 			goto list_failure_lock;
502fd385855SPaul Moore 	}
503fd385855SPaul Moore 	nla_nest_end(ans_skb, nla_a);
504fd385855SPaul Moore 
505fd385855SPaul Moore 	switch (doi_def->type) {
506fd385855SPaul Moore 	case CIPSO_V4_MAP_STD:
507fd385855SPaul Moore 		nla_a = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSLVLLST);
508fd385855SPaul Moore 		if (nla_a == NULL) {
509fd385855SPaul Moore 			ret_val = -ENOMEM;
510fd385855SPaul Moore 			goto list_failure_lock;
511fd385855SPaul Moore 		}
512fd385855SPaul Moore 		for (iter = 0;
513fd385855SPaul Moore 		     iter < doi_def->map.std->lvl.local_size;
514fd385855SPaul Moore 		     iter++) {
515fd385855SPaul Moore 			if (doi_def->map.std->lvl.local[iter] ==
516fd385855SPaul Moore 			    CIPSO_V4_INV_LVL)
517fd385855SPaul Moore 				continue;
518fd385855SPaul Moore 
519fd385855SPaul Moore 			nla_b = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSLVL);
520fd385855SPaul Moore 			if (nla_b == NULL) {
521fd385855SPaul Moore 				ret_val = -ENOMEM;
522fd385855SPaul Moore 				goto list_retry;
523fd385855SPaul Moore 			}
524fd385855SPaul Moore 			ret_val = nla_put_u32(ans_skb,
525fd385855SPaul Moore 					      NLBL_CIPSOV4_A_MLSLVLLOC,
526fd385855SPaul Moore 					      iter);
527fd385855SPaul Moore 			if (ret_val != 0)
528fd385855SPaul Moore 				goto list_retry;
529fd385855SPaul Moore 			ret_val = nla_put_u32(ans_skb,
530fd385855SPaul Moore 					    NLBL_CIPSOV4_A_MLSLVLREM,
531fd385855SPaul Moore 					    doi_def->map.std->lvl.local[iter]);
532fd385855SPaul Moore 			if (ret_val != 0)
533fd385855SPaul Moore 				goto list_retry;
534fd385855SPaul Moore 			nla_nest_end(ans_skb, nla_b);
535fd385855SPaul Moore 		}
536fd385855SPaul Moore 		nla_nest_end(ans_skb, nla_a);
537fd385855SPaul Moore 
538fd385855SPaul Moore 		nla_a = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSCATLST);
539fd385855SPaul Moore 		if (nla_a == NULL) {
540fd385855SPaul Moore 			ret_val = -ENOMEM;
541fd385855SPaul Moore 			goto list_retry;
542fd385855SPaul Moore 		}
543fd385855SPaul Moore 		for (iter = 0;
544fd385855SPaul Moore 		     iter < doi_def->map.std->cat.local_size;
545fd385855SPaul Moore 		     iter++) {
546fd385855SPaul Moore 			if (doi_def->map.std->cat.local[iter] ==
547fd385855SPaul Moore 			    CIPSO_V4_INV_CAT)
548fd385855SPaul Moore 				continue;
549fd385855SPaul Moore 
550fd385855SPaul Moore 			nla_b = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSCAT);
551fd385855SPaul Moore 			if (nla_b == NULL) {
552fd385855SPaul Moore 				ret_val = -ENOMEM;
553fd385855SPaul Moore 				goto list_retry;
554fd385855SPaul Moore 			}
555fd385855SPaul Moore 			ret_val = nla_put_u32(ans_skb,
556fd385855SPaul Moore 					      NLBL_CIPSOV4_A_MLSCATLOC,
557fd385855SPaul Moore 					      iter);
558fd385855SPaul Moore 			if (ret_val != 0)
559fd385855SPaul Moore 				goto list_retry;
560fd385855SPaul Moore 			ret_val = nla_put_u32(ans_skb,
561fd385855SPaul Moore 					    NLBL_CIPSOV4_A_MLSCATREM,
562fd385855SPaul Moore 					    doi_def->map.std->cat.local[iter]);
563fd385855SPaul Moore 			if (ret_val != 0)
564fd385855SPaul Moore 				goto list_retry;
565fd385855SPaul Moore 			nla_nest_end(ans_skb, nla_b);
566fd385855SPaul Moore 		}
567fd385855SPaul Moore 		nla_nest_end(ans_skb, nla_a);
568fd385855SPaul Moore 
569fd385855SPaul Moore 		break;
570fd385855SPaul Moore 	}
571fd385855SPaul Moore 	rcu_read_unlock();
572fd385855SPaul Moore 
573fd385855SPaul Moore 	genlmsg_end(ans_skb, data);
574fd385855SPaul Moore 
57581878d27SThomas Graf 	ret_val = genlmsg_reply(ans_skb, info);
57696cb8e33SPaul Moore 	if (ret_val != 0)
57796cb8e33SPaul Moore 		goto list_failure;
57896cb8e33SPaul Moore 
57996cb8e33SPaul Moore 	return 0;
58096cb8e33SPaul Moore 
581fd385855SPaul Moore list_retry:
582fd385855SPaul Moore 	/* XXX - this limit is a guesstimate */
583fd385855SPaul Moore 	if (nlsze_mult < 4) {
584fd385855SPaul Moore 		rcu_read_unlock();
585fd385855SPaul Moore 		kfree_skb(ans_skb);
586fd385855SPaul Moore 		nlsze_mult++;
587fd385855SPaul Moore 		goto list_start;
588fd385855SPaul Moore 	}
589fd385855SPaul Moore list_failure_lock:
590fd385855SPaul Moore 	rcu_read_unlock();
59196cb8e33SPaul Moore list_failure:
592fd385855SPaul Moore 	kfree_skb(ans_skb);
593fd385855SPaul Moore 	return ret_val;
594fd385855SPaul Moore }
595fd385855SPaul Moore 
596fd385855SPaul Moore /**
597fd385855SPaul Moore  * netlbl_cipsov4_listall_cb - cipso_v4_doi_walk() callback for LISTALL
598fd385855SPaul Moore  * @doi_def: the CIPSOv4 DOI definition
599fd385855SPaul Moore  * @arg: the netlbl_cipsov4_doiwalk_arg structure
600fd385855SPaul Moore  *
601fd385855SPaul Moore  * Description:
602fd385855SPaul Moore  * This function is designed to be used as a callback to the
603fd385855SPaul Moore  * cipso_v4_doi_walk() function for use in generating a response for a LISTALL
604fd385855SPaul Moore  * message.  Returns the size of the message on success, negative values on
605fd385855SPaul Moore  * failure.
606fd385855SPaul Moore  *
607fd385855SPaul Moore  */
608fd385855SPaul Moore static int netlbl_cipsov4_listall_cb(struct cipso_v4_doi *doi_def, void *arg)
609fd385855SPaul Moore {
610fd385855SPaul Moore 	int ret_val = -ENOMEM;
611fd385855SPaul Moore 	struct netlbl_cipsov4_doiwalk_arg *cb_arg = arg;
612fd385855SPaul Moore 	void *data;
613fd385855SPaul Moore 
61417c157c8SThomas Graf 	data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).pid,
61517c157c8SThomas Graf 			   cb_arg->seq, &netlbl_cipsov4_gnl_family,
61617c157c8SThomas Graf 			   NLM_F_MULTI, NLBL_CIPSOV4_C_LISTALL);
617fd385855SPaul Moore 	if (data == NULL)
618fd385855SPaul Moore 		goto listall_cb_failure;
619fd385855SPaul Moore 
620fd385855SPaul Moore 	ret_val = nla_put_u32(cb_arg->skb, NLBL_CIPSOV4_A_DOI, doi_def->doi);
621fd385855SPaul Moore 	if (ret_val != 0)
622fd385855SPaul Moore 		goto listall_cb_failure;
623fd385855SPaul Moore 	ret_val = nla_put_u32(cb_arg->skb,
624fd385855SPaul Moore 			      NLBL_CIPSOV4_A_MTYPE,
625fd385855SPaul Moore 			      doi_def->type);
626fd385855SPaul Moore 	if (ret_val != 0)
627fd385855SPaul Moore 		goto listall_cb_failure;
628fd385855SPaul Moore 
629fd385855SPaul Moore 	return genlmsg_end(cb_arg->skb, data);
630fd385855SPaul Moore 
631fd385855SPaul Moore listall_cb_failure:
632fd385855SPaul Moore 	genlmsg_cancel(cb_arg->skb, data);
63396cb8e33SPaul Moore 	return ret_val;
63496cb8e33SPaul Moore }
63596cb8e33SPaul Moore 
63696cb8e33SPaul Moore /**
63796cb8e33SPaul Moore  * netlbl_cipsov4_listall - Handle a LISTALL message
63896cb8e33SPaul Moore  * @skb: the NETLINK buffer
639fd385855SPaul Moore  * @cb: the NETLINK callback
64096cb8e33SPaul Moore  *
64196cb8e33SPaul Moore  * Description:
64296cb8e33SPaul Moore  * Process a user generated LISTALL message and respond accordingly.  Returns
64396cb8e33SPaul Moore  * zero on success and negative values on error.
64496cb8e33SPaul Moore  *
64596cb8e33SPaul Moore  */
646fd385855SPaul Moore static int netlbl_cipsov4_listall(struct sk_buff *skb,
647fd385855SPaul Moore 				  struct netlink_callback *cb)
64896cb8e33SPaul Moore {
649fd385855SPaul Moore 	struct netlbl_cipsov4_doiwalk_arg cb_arg;
650fd385855SPaul Moore 	int doi_skip = cb->args[0];
65196cb8e33SPaul Moore 
652fd385855SPaul Moore 	cb_arg.nl_cb = cb;
653fd385855SPaul Moore 	cb_arg.skb = skb;
654fd385855SPaul Moore 	cb_arg.seq = cb->nlh->nlmsg_seq;
65596cb8e33SPaul Moore 
656fd385855SPaul Moore 	cipso_v4_doi_walk(&doi_skip, netlbl_cipsov4_listall_cb, &cb_arg);
65796cb8e33SPaul Moore 
658fd385855SPaul Moore 	cb->args[0] = doi_skip;
659fd385855SPaul Moore 	return skb->len;
66096cb8e33SPaul Moore }
66196cb8e33SPaul Moore 
66296cb8e33SPaul Moore /**
66396cb8e33SPaul Moore  * netlbl_cipsov4_remove - Handle a REMOVE message
66496cb8e33SPaul Moore  * @skb: the NETLINK buffer
66596cb8e33SPaul Moore  * @info: the Generic NETLINK info block
66696cb8e33SPaul Moore  *
66796cb8e33SPaul Moore  * Description:
66896cb8e33SPaul Moore  * Process a user generated REMOVE message and respond accordingly.  Returns
66996cb8e33SPaul Moore  * zero on success, negative values on failure.
67096cb8e33SPaul Moore  *
67196cb8e33SPaul Moore  */
67296cb8e33SPaul Moore static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info)
67396cb8e33SPaul Moore {
674fd385855SPaul Moore 	int ret_val = -EINVAL;
67532f50cdeSPaul Moore 	u32 doi = 0;
67632f50cdeSPaul Moore 	struct audit_buffer *audit_buf;
67795d4e6beSPaul Moore 	struct netlbl_audit audit_info;
67896cb8e33SPaul Moore 
67995d4e6beSPaul Moore 	if (!info->attrs[NLBL_CIPSOV4_A_DOI])
68095d4e6beSPaul Moore 		return -EINVAL;
68195d4e6beSPaul Moore 
682fd385855SPaul Moore 	doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
68395d4e6beSPaul Moore 	netlbl_netlink_auditinfo(skb, &audit_info);
68432f50cdeSPaul Moore 
68595d4e6beSPaul Moore 	ret_val = cipso_v4_doi_remove(doi,
68695d4e6beSPaul Moore 				      &audit_info,
68795d4e6beSPaul Moore 				      netlbl_cipsov4_doi_free);
68895d4e6beSPaul Moore 
68932f50cdeSPaul Moore 	audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_DEL,
69095d4e6beSPaul Moore 					      &audit_info);
691de64688fSPaul Moore 	if (audit_buf != NULL) {
69295d4e6beSPaul Moore 		audit_log_format(audit_buf,
69395d4e6beSPaul Moore 				 " cipso_doi=%u res=%u",
69495d4e6beSPaul Moore 				 doi,
69595d4e6beSPaul Moore 				 ret_val == 0 ? 1 : 0);
69632f50cdeSPaul Moore 		audit_log_end(audit_buf);
697de64688fSPaul Moore 	}
69896cb8e33SPaul Moore 
69996cb8e33SPaul Moore 	return ret_val;
70096cb8e33SPaul Moore }
70196cb8e33SPaul Moore 
70296cb8e33SPaul Moore /*
70396cb8e33SPaul Moore  * NetLabel Generic NETLINK Command Definitions
70496cb8e33SPaul Moore  */
70596cb8e33SPaul Moore 
70696cb8e33SPaul Moore static struct genl_ops netlbl_cipsov4_genl_c_add = {
70796cb8e33SPaul Moore 	.cmd = NLBL_CIPSOV4_C_ADD,
708fd385855SPaul Moore 	.flags = GENL_ADMIN_PERM,
709fd385855SPaul Moore 	.policy = netlbl_cipsov4_genl_policy,
71096cb8e33SPaul Moore 	.doit = netlbl_cipsov4_add,
71196cb8e33SPaul Moore 	.dumpit = NULL,
71296cb8e33SPaul Moore };
71396cb8e33SPaul Moore 
71496cb8e33SPaul Moore static struct genl_ops netlbl_cipsov4_genl_c_remove = {
71596cb8e33SPaul Moore 	.cmd = NLBL_CIPSOV4_C_REMOVE,
716fd385855SPaul Moore 	.flags = GENL_ADMIN_PERM,
717fd385855SPaul Moore 	.policy = netlbl_cipsov4_genl_policy,
71896cb8e33SPaul Moore 	.doit = netlbl_cipsov4_remove,
71996cb8e33SPaul Moore 	.dumpit = NULL,
72096cb8e33SPaul Moore };
72196cb8e33SPaul Moore 
72296cb8e33SPaul Moore static struct genl_ops netlbl_cipsov4_genl_c_list = {
72396cb8e33SPaul Moore 	.cmd = NLBL_CIPSOV4_C_LIST,
72496cb8e33SPaul Moore 	.flags = 0,
725fd385855SPaul Moore 	.policy = netlbl_cipsov4_genl_policy,
72696cb8e33SPaul Moore 	.doit = netlbl_cipsov4_list,
72796cb8e33SPaul Moore 	.dumpit = NULL,
72896cb8e33SPaul Moore };
72996cb8e33SPaul Moore 
73096cb8e33SPaul Moore static struct genl_ops netlbl_cipsov4_genl_c_listall = {
73196cb8e33SPaul Moore 	.cmd = NLBL_CIPSOV4_C_LISTALL,
73296cb8e33SPaul Moore 	.flags = 0,
733fd385855SPaul Moore 	.policy = netlbl_cipsov4_genl_policy,
734fd385855SPaul Moore 	.doit = NULL,
735fd385855SPaul Moore 	.dumpit = netlbl_cipsov4_listall,
73696cb8e33SPaul Moore };
73796cb8e33SPaul Moore 
73896cb8e33SPaul Moore /*
73996cb8e33SPaul Moore  * NetLabel Generic NETLINK Protocol Functions
74096cb8e33SPaul Moore  */
74196cb8e33SPaul Moore 
74296cb8e33SPaul Moore /**
74396cb8e33SPaul Moore  * netlbl_cipsov4_genl_init - Register the CIPSOv4 NetLabel component
74496cb8e33SPaul Moore  *
74596cb8e33SPaul Moore  * Description:
74696cb8e33SPaul Moore  * Register the CIPSOv4 packet NetLabel component with the Generic NETLINK
74796cb8e33SPaul Moore  * mechanism.  Returns zero on success, negative values on failure.
74896cb8e33SPaul Moore  *
74996cb8e33SPaul Moore  */
75096cb8e33SPaul Moore int netlbl_cipsov4_genl_init(void)
75196cb8e33SPaul Moore {
75296cb8e33SPaul Moore 	int ret_val;
75396cb8e33SPaul Moore 
75496cb8e33SPaul Moore 	ret_val = genl_register_family(&netlbl_cipsov4_gnl_family);
75596cb8e33SPaul Moore 	if (ret_val != 0)
75696cb8e33SPaul Moore 		return ret_val;
75796cb8e33SPaul Moore 
75896cb8e33SPaul Moore 	ret_val = genl_register_ops(&netlbl_cipsov4_gnl_family,
75996cb8e33SPaul Moore 				    &netlbl_cipsov4_genl_c_add);
76096cb8e33SPaul Moore 	if (ret_val != 0)
76196cb8e33SPaul Moore 		return ret_val;
76296cb8e33SPaul Moore 	ret_val = genl_register_ops(&netlbl_cipsov4_gnl_family,
76396cb8e33SPaul Moore 				    &netlbl_cipsov4_genl_c_remove);
76496cb8e33SPaul Moore 	if (ret_val != 0)
76596cb8e33SPaul Moore 		return ret_val;
76696cb8e33SPaul Moore 	ret_val = genl_register_ops(&netlbl_cipsov4_gnl_family,
76796cb8e33SPaul Moore 				    &netlbl_cipsov4_genl_c_list);
76896cb8e33SPaul Moore 	if (ret_val != 0)
76996cb8e33SPaul Moore 		return ret_val;
77096cb8e33SPaul Moore 	ret_val = genl_register_ops(&netlbl_cipsov4_gnl_family,
77196cb8e33SPaul Moore 				    &netlbl_cipsov4_genl_c_listall);
77296cb8e33SPaul Moore 	if (ret_val != 0)
77396cb8e33SPaul Moore 		return ret_val;
77496cb8e33SPaul Moore 
77596cb8e33SPaul Moore 	return 0;
77696cb8e33SPaul Moore }
777