xref: /openbmc/linux/net/netlabel/netlabel_cipso_v4.c (revision 96cb8e3313c7a12e026c1ed510522ae6f6023875)
1*96cb8e33SPaul Moore /*
2*96cb8e33SPaul Moore  * NetLabel CIPSO/IPv4 Support
3*96cb8e33SPaul Moore  *
4*96cb8e33SPaul Moore  * This file defines the CIPSO/IPv4 functions for the NetLabel system.  The
5*96cb8e33SPaul Moore  * NetLabel system manages static and dynamic label mappings for network
6*96cb8e33SPaul Moore  * protocols such as CIPSO and RIPSO.
7*96cb8e33SPaul Moore  *
8*96cb8e33SPaul Moore  * Author: Paul Moore <paul.moore@hp.com>
9*96cb8e33SPaul Moore  *
10*96cb8e33SPaul Moore  */
11*96cb8e33SPaul Moore 
12*96cb8e33SPaul Moore /*
13*96cb8e33SPaul Moore  * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
14*96cb8e33SPaul Moore  *
15*96cb8e33SPaul Moore  * This program is free software;  you can redistribute it and/or modify
16*96cb8e33SPaul Moore  * it under the terms of the GNU General Public License as published by
17*96cb8e33SPaul Moore  * the Free Software Foundation; either version 2 of the License, or
18*96cb8e33SPaul Moore  * (at your option) any later version.
19*96cb8e33SPaul Moore  *
20*96cb8e33SPaul Moore  * This program is distributed in the hope that it will be useful,
21*96cb8e33SPaul Moore  * but WITHOUT ANY WARRANTY;  without even the implied warranty of
22*96cb8e33SPaul Moore  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
23*96cb8e33SPaul Moore  * the GNU General Public License for more details.
24*96cb8e33SPaul Moore  *
25*96cb8e33SPaul Moore  * You should have received a copy of the GNU General Public License
26*96cb8e33SPaul Moore  * along with this program;  if not, write to the Free Software
27*96cb8e33SPaul Moore  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28*96cb8e33SPaul Moore  *
29*96cb8e33SPaul Moore  */
30*96cb8e33SPaul Moore 
31*96cb8e33SPaul Moore #include <linux/types.h>
32*96cb8e33SPaul Moore #include <linux/socket.h>
33*96cb8e33SPaul Moore #include <linux/string.h>
34*96cb8e33SPaul Moore #include <linux/skbuff.h>
35*96cb8e33SPaul Moore #include <net/sock.h>
36*96cb8e33SPaul Moore #include <net/netlink.h>
37*96cb8e33SPaul Moore #include <net/genetlink.h>
38*96cb8e33SPaul Moore #include <net/netlabel.h>
39*96cb8e33SPaul Moore #include <net/cipso_ipv4.h>
40*96cb8e33SPaul Moore 
41*96cb8e33SPaul Moore #include "netlabel_user.h"
42*96cb8e33SPaul Moore #include "netlabel_cipso_v4.h"
43*96cb8e33SPaul Moore 
44*96cb8e33SPaul Moore /* NetLabel Generic NETLINK CIPSOv4 family */
45*96cb8e33SPaul Moore static struct genl_family netlbl_cipsov4_gnl_family = {
46*96cb8e33SPaul Moore 	.id = GENL_ID_GENERATE,
47*96cb8e33SPaul Moore 	.hdrsize = 0,
48*96cb8e33SPaul Moore 	.name = NETLBL_NLTYPE_CIPSOV4_NAME,
49*96cb8e33SPaul Moore 	.version = NETLBL_PROTO_VERSION,
50*96cb8e33SPaul Moore 	.maxattr = 0,
51*96cb8e33SPaul Moore };
52*96cb8e33SPaul Moore 
53*96cb8e33SPaul Moore 
54*96cb8e33SPaul Moore /*
55*96cb8e33SPaul Moore  * Helper Functions
56*96cb8e33SPaul Moore  */
57*96cb8e33SPaul Moore 
58*96cb8e33SPaul Moore /**
59*96cb8e33SPaul Moore  * netlbl_cipsov4_doi_free - Frees a CIPSO V4 DOI definition
60*96cb8e33SPaul Moore  * @entry: the entry's RCU field
61*96cb8e33SPaul Moore  *
62*96cb8e33SPaul Moore  * Description:
63*96cb8e33SPaul Moore  * This function is designed to be used as a callback to the call_rcu()
64*96cb8e33SPaul Moore  * function so that the memory allocated to the DOI definition can be released
65*96cb8e33SPaul Moore  * safely.
66*96cb8e33SPaul Moore  *
67*96cb8e33SPaul Moore  */
68*96cb8e33SPaul Moore static void netlbl_cipsov4_doi_free(struct rcu_head *entry)
69*96cb8e33SPaul Moore {
70*96cb8e33SPaul Moore 	struct cipso_v4_doi *ptr;
71*96cb8e33SPaul Moore 
72*96cb8e33SPaul Moore 	ptr = container_of(entry, struct cipso_v4_doi, rcu);
73*96cb8e33SPaul Moore 	switch (ptr->type) {
74*96cb8e33SPaul Moore 	case CIPSO_V4_MAP_STD:
75*96cb8e33SPaul Moore 		kfree(ptr->map.std->lvl.cipso);
76*96cb8e33SPaul Moore 		kfree(ptr->map.std->lvl.local);
77*96cb8e33SPaul Moore 		kfree(ptr->map.std->cat.cipso);
78*96cb8e33SPaul Moore 		kfree(ptr->map.std->cat.local);
79*96cb8e33SPaul Moore 		break;
80*96cb8e33SPaul Moore 	}
81*96cb8e33SPaul Moore 	kfree(ptr);
82*96cb8e33SPaul Moore }
83*96cb8e33SPaul Moore 
84*96cb8e33SPaul Moore 
85*96cb8e33SPaul Moore /*
86*96cb8e33SPaul Moore  * NetLabel Command Handlers
87*96cb8e33SPaul Moore  */
88*96cb8e33SPaul Moore 
89*96cb8e33SPaul Moore /**
90*96cb8e33SPaul Moore  * netlbl_cipsov4_add_std - Adds a CIPSO V4 DOI definition
91*96cb8e33SPaul Moore  * @doi: the DOI value
92*96cb8e33SPaul Moore  * @msg: the ADD message data
93*96cb8e33SPaul Moore  * @msg_size: the size of the ADD message buffer
94*96cb8e33SPaul Moore  *
95*96cb8e33SPaul Moore  * Description:
96*96cb8e33SPaul Moore  * Create a new CIPSO_V4_MAP_STD DOI definition based on the given ADD message
97*96cb8e33SPaul Moore  * and add it to the CIPSO V4 engine.  Return zero on success and non-zero on
98*96cb8e33SPaul Moore  * error.
99*96cb8e33SPaul Moore  *
100*96cb8e33SPaul Moore  */
101*96cb8e33SPaul Moore static int netlbl_cipsov4_add_std(u32 doi, struct nlattr *msg, size_t msg_size)
102*96cb8e33SPaul Moore {
103*96cb8e33SPaul Moore 	int ret_val = -EINVAL;
104*96cb8e33SPaul Moore 	int msg_len = msg_size;
105*96cb8e33SPaul Moore 	u32 num_tags;
106*96cb8e33SPaul Moore 	u32 num_lvls;
107*96cb8e33SPaul Moore 	u32 num_cats;
108*96cb8e33SPaul Moore 	struct cipso_v4_doi *doi_def = NULL;
109*96cb8e33SPaul Moore 	u32 iter;
110*96cb8e33SPaul Moore 	u32 tmp_val_a;
111*96cb8e33SPaul Moore 	u32 tmp_val_b;
112*96cb8e33SPaul Moore 
113*96cb8e33SPaul Moore 	if (msg_len < NETLBL_LEN_U32)
114*96cb8e33SPaul Moore 		goto add_std_failure;
115*96cb8e33SPaul Moore 	num_tags = netlbl_getinc_u32(&msg, &msg_len);
116*96cb8e33SPaul Moore 	if (num_tags == 0 || num_tags > CIPSO_V4_TAG_MAXCNT)
117*96cb8e33SPaul Moore 		goto add_std_failure;
118*96cb8e33SPaul Moore 
119*96cb8e33SPaul Moore 	doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
120*96cb8e33SPaul Moore 	if (doi_def == NULL) {
121*96cb8e33SPaul Moore 		ret_val = -ENOMEM;
122*96cb8e33SPaul Moore 		goto add_std_failure;
123*96cb8e33SPaul Moore 	}
124*96cb8e33SPaul Moore 	doi_def->map.std = kzalloc(sizeof(*doi_def->map.std), GFP_KERNEL);
125*96cb8e33SPaul Moore 	if (doi_def->map.std == NULL) {
126*96cb8e33SPaul Moore 		ret_val = -ENOMEM;
127*96cb8e33SPaul Moore 		goto add_std_failure;
128*96cb8e33SPaul Moore 	}
129*96cb8e33SPaul Moore 	doi_def->type = CIPSO_V4_MAP_STD;
130*96cb8e33SPaul Moore 
131*96cb8e33SPaul Moore 	for (iter = 0; iter < num_tags; iter++) {
132*96cb8e33SPaul Moore 		if (msg_len < NETLBL_LEN_U8)
133*96cb8e33SPaul Moore 			goto add_std_failure;
134*96cb8e33SPaul Moore 		doi_def->tags[iter] = netlbl_getinc_u8(&msg, &msg_len);
135*96cb8e33SPaul Moore 		switch (doi_def->tags[iter]) {
136*96cb8e33SPaul Moore 		case CIPSO_V4_TAG_RBITMAP:
137*96cb8e33SPaul Moore 			break;
138*96cb8e33SPaul Moore 		default:
139*96cb8e33SPaul Moore 			goto add_std_failure;
140*96cb8e33SPaul Moore 		}
141*96cb8e33SPaul Moore 	}
142*96cb8e33SPaul Moore 	if (iter < CIPSO_V4_TAG_MAXCNT)
143*96cb8e33SPaul Moore 		doi_def->tags[iter] = CIPSO_V4_TAG_INVALID;
144*96cb8e33SPaul Moore 
145*96cb8e33SPaul Moore 	if (msg_len < 6 * NETLBL_LEN_U32)
146*96cb8e33SPaul Moore 		goto add_std_failure;
147*96cb8e33SPaul Moore 
148*96cb8e33SPaul Moore 	num_lvls = netlbl_getinc_u32(&msg, &msg_len);
149*96cb8e33SPaul Moore 	if (num_lvls == 0)
150*96cb8e33SPaul Moore 		goto add_std_failure;
151*96cb8e33SPaul Moore 	doi_def->map.std->lvl.local_size = netlbl_getinc_u32(&msg, &msg_len);
152*96cb8e33SPaul Moore 	if (doi_def->map.std->lvl.local_size > CIPSO_V4_MAX_LOC_LVLS)
153*96cb8e33SPaul Moore 		goto add_std_failure;
154*96cb8e33SPaul Moore 	doi_def->map.std->lvl.local = kcalloc(doi_def->map.std->lvl.local_size,
155*96cb8e33SPaul Moore 					      sizeof(u32),
156*96cb8e33SPaul Moore 					      GFP_KERNEL);
157*96cb8e33SPaul Moore 	if (doi_def->map.std->lvl.local == NULL) {
158*96cb8e33SPaul Moore 		ret_val = -ENOMEM;
159*96cb8e33SPaul Moore 		goto add_std_failure;
160*96cb8e33SPaul Moore 	}
161*96cb8e33SPaul Moore 	doi_def->map.std->lvl.cipso_size = netlbl_getinc_u8(&msg, &msg_len);
162*96cb8e33SPaul Moore 	if (doi_def->map.std->lvl.cipso_size > CIPSO_V4_MAX_REM_LVLS)
163*96cb8e33SPaul Moore 		goto add_std_failure;
164*96cb8e33SPaul Moore 	doi_def->map.std->lvl.cipso = kcalloc(doi_def->map.std->lvl.cipso_size,
165*96cb8e33SPaul Moore 					      sizeof(u32),
166*96cb8e33SPaul Moore 					      GFP_KERNEL);
167*96cb8e33SPaul Moore 	if (doi_def->map.std->lvl.cipso == NULL) {
168*96cb8e33SPaul Moore 		ret_val = -ENOMEM;
169*96cb8e33SPaul Moore 		goto add_std_failure;
170*96cb8e33SPaul Moore 	}
171*96cb8e33SPaul Moore 
172*96cb8e33SPaul Moore 	num_cats = netlbl_getinc_u32(&msg, &msg_len);
173*96cb8e33SPaul Moore 	doi_def->map.std->cat.local_size = netlbl_getinc_u32(&msg, &msg_len);
174*96cb8e33SPaul Moore 	if (doi_def->map.std->cat.local_size > CIPSO_V4_MAX_LOC_CATS)
175*96cb8e33SPaul Moore 		goto add_std_failure;
176*96cb8e33SPaul Moore 	doi_def->map.std->cat.local = kcalloc(doi_def->map.std->cat.local_size,
177*96cb8e33SPaul Moore 					      sizeof(u32),
178*96cb8e33SPaul Moore 					      GFP_KERNEL);
179*96cb8e33SPaul Moore 	if (doi_def->map.std->cat.local == NULL) {
180*96cb8e33SPaul Moore 		ret_val = -ENOMEM;
181*96cb8e33SPaul Moore 		goto add_std_failure;
182*96cb8e33SPaul Moore 	}
183*96cb8e33SPaul Moore 	doi_def->map.std->cat.cipso_size = netlbl_getinc_u16(&msg, &msg_len);
184*96cb8e33SPaul Moore 	if (doi_def->map.std->cat.cipso_size > CIPSO_V4_MAX_REM_CATS)
185*96cb8e33SPaul Moore 		goto add_std_failure;
186*96cb8e33SPaul Moore 	doi_def->map.std->cat.cipso = kcalloc(doi_def->map.std->cat.cipso_size,
187*96cb8e33SPaul Moore 					      sizeof(u32),
188*96cb8e33SPaul Moore 					      GFP_KERNEL);
189*96cb8e33SPaul Moore 	if (doi_def->map.std->cat.cipso == NULL) {
190*96cb8e33SPaul Moore 		ret_val = -ENOMEM;
191*96cb8e33SPaul Moore 		goto add_std_failure;
192*96cb8e33SPaul Moore 	}
193*96cb8e33SPaul Moore 
194*96cb8e33SPaul Moore 	if (msg_len <
195*96cb8e33SPaul Moore 	    num_lvls * (NETLBL_LEN_U32 + NETLBL_LEN_U8) +
196*96cb8e33SPaul Moore 	    num_cats * (NETLBL_LEN_U32 + NETLBL_LEN_U16))
197*96cb8e33SPaul Moore 		goto add_std_failure;
198*96cb8e33SPaul Moore 
199*96cb8e33SPaul Moore 	for (iter = 0; iter < doi_def->map.std->lvl.cipso_size; iter++)
200*96cb8e33SPaul Moore 		doi_def->map.std->lvl.cipso[iter] = CIPSO_V4_INV_LVL;
201*96cb8e33SPaul Moore 	for (iter = 0; iter < doi_def->map.std->lvl.local_size; iter++)
202*96cb8e33SPaul Moore 		doi_def->map.std->lvl.local[iter] = CIPSO_V4_INV_LVL;
203*96cb8e33SPaul Moore 	for (iter = 0; iter < doi_def->map.std->cat.cipso_size; iter++)
204*96cb8e33SPaul Moore 		doi_def->map.std->cat.cipso[iter] = CIPSO_V4_INV_CAT;
205*96cb8e33SPaul Moore 	for (iter = 0; iter < doi_def->map.std->cat.local_size; iter++)
206*96cb8e33SPaul Moore 		doi_def->map.std->cat.local[iter] = CIPSO_V4_INV_CAT;
207*96cb8e33SPaul Moore 
208*96cb8e33SPaul Moore 	for (iter = 0; iter < num_lvls; iter++) {
209*96cb8e33SPaul Moore 		tmp_val_a = netlbl_getinc_u32(&msg, &msg_len);
210*96cb8e33SPaul Moore 		tmp_val_b = netlbl_getinc_u8(&msg, &msg_len);
211*96cb8e33SPaul Moore 
212*96cb8e33SPaul Moore 		if (tmp_val_a >= doi_def->map.std->lvl.local_size ||
213*96cb8e33SPaul Moore 		    tmp_val_b >= doi_def->map.std->lvl.cipso_size)
214*96cb8e33SPaul Moore 			goto add_std_failure;
215*96cb8e33SPaul Moore 
216*96cb8e33SPaul Moore 		doi_def->map.std->lvl.cipso[tmp_val_b] = tmp_val_a;
217*96cb8e33SPaul Moore 		doi_def->map.std->lvl.local[tmp_val_a] = tmp_val_b;
218*96cb8e33SPaul Moore 	}
219*96cb8e33SPaul Moore 
220*96cb8e33SPaul Moore 	for (iter = 0; iter < num_cats; iter++) {
221*96cb8e33SPaul Moore 		tmp_val_a = netlbl_getinc_u32(&msg, &msg_len);
222*96cb8e33SPaul Moore 		tmp_val_b = netlbl_getinc_u16(&msg, &msg_len);
223*96cb8e33SPaul Moore 
224*96cb8e33SPaul Moore 		if (tmp_val_a >= doi_def->map.std->cat.local_size ||
225*96cb8e33SPaul Moore 		    tmp_val_b >= doi_def->map.std->cat.cipso_size)
226*96cb8e33SPaul Moore 			goto add_std_failure;
227*96cb8e33SPaul Moore 
228*96cb8e33SPaul Moore 		doi_def->map.std->cat.cipso[tmp_val_b] = tmp_val_a;
229*96cb8e33SPaul Moore 		doi_def->map.std->cat.local[tmp_val_a] = tmp_val_b;
230*96cb8e33SPaul Moore 	}
231*96cb8e33SPaul Moore 
232*96cb8e33SPaul Moore 	doi_def->doi = doi;
233*96cb8e33SPaul Moore 	ret_val = cipso_v4_doi_add(doi_def);
234*96cb8e33SPaul Moore 	if (ret_val != 0)
235*96cb8e33SPaul Moore 		goto add_std_failure;
236*96cb8e33SPaul Moore 	return 0;
237*96cb8e33SPaul Moore 
238*96cb8e33SPaul Moore add_std_failure:
239*96cb8e33SPaul Moore 	if (doi_def)
240*96cb8e33SPaul Moore 		netlbl_cipsov4_doi_free(&doi_def->rcu);
241*96cb8e33SPaul Moore 	return ret_val;
242*96cb8e33SPaul Moore }
243*96cb8e33SPaul Moore 
244*96cb8e33SPaul Moore /**
245*96cb8e33SPaul Moore  * netlbl_cipsov4_add_pass - Adds a CIPSO V4 DOI definition
246*96cb8e33SPaul Moore  * @doi: the DOI value
247*96cb8e33SPaul Moore  * @msg: the ADD message data
248*96cb8e33SPaul Moore  * @msg_size: the size of the ADD message buffer
249*96cb8e33SPaul Moore  *
250*96cb8e33SPaul Moore  * Description:
251*96cb8e33SPaul Moore  * Create a new CIPSO_V4_MAP_PASS DOI definition based on the given ADD message
252*96cb8e33SPaul Moore  * and add it to the CIPSO V4 engine.  Return zero on success and non-zero on
253*96cb8e33SPaul Moore  * error.
254*96cb8e33SPaul Moore  *
255*96cb8e33SPaul Moore  */
256*96cb8e33SPaul Moore static int netlbl_cipsov4_add_pass(u32 doi,
257*96cb8e33SPaul Moore 				   struct nlattr *msg,
258*96cb8e33SPaul Moore 				   size_t msg_size)
259*96cb8e33SPaul Moore {
260*96cb8e33SPaul Moore 	int ret_val = -EINVAL;
261*96cb8e33SPaul Moore 	int msg_len = msg_size;
262*96cb8e33SPaul Moore 	u32 num_tags;
263*96cb8e33SPaul Moore 	struct cipso_v4_doi *doi_def = NULL;
264*96cb8e33SPaul Moore 	u32 iter;
265*96cb8e33SPaul Moore 
266*96cb8e33SPaul Moore 	if (msg_len < NETLBL_LEN_U32)
267*96cb8e33SPaul Moore 		goto add_pass_failure;
268*96cb8e33SPaul Moore 	num_tags = netlbl_getinc_u32(&msg, &msg_len);
269*96cb8e33SPaul Moore 	if (num_tags == 0 || num_tags > CIPSO_V4_TAG_MAXCNT)
270*96cb8e33SPaul Moore 		goto add_pass_failure;
271*96cb8e33SPaul Moore 
272*96cb8e33SPaul Moore 	doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
273*96cb8e33SPaul Moore 	if (doi_def == NULL) {
274*96cb8e33SPaul Moore 		ret_val = -ENOMEM;
275*96cb8e33SPaul Moore 		goto add_pass_failure;
276*96cb8e33SPaul Moore 	}
277*96cb8e33SPaul Moore 	doi_def->type = CIPSO_V4_MAP_PASS;
278*96cb8e33SPaul Moore 
279*96cb8e33SPaul Moore 	for (iter = 0; iter < num_tags; iter++) {
280*96cb8e33SPaul Moore 		if (msg_len < NETLBL_LEN_U8)
281*96cb8e33SPaul Moore 			goto add_pass_failure;
282*96cb8e33SPaul Moore 		doi_def->tags[iter] = netlbl_getinc_u8(&msg, &msg_len);
283*96cb8e33SPaul Moore 		switch (doi_def->tags[iter]) {
284*96cb8e33SPaul Moore 		case CIPSO_V4_TAG_RBITMAP:
285*96cb8e33SPaul Moore 			break;
286*96cb8e33SPaul Moore 		default:
287*96cb8e33SPaul Moore 			goto add_pass_failure;
288*96cb8e33SPaul Moore 		}
289*96cb8e33SPaul Moore 	}
290*96cb8e33SPaul Moore 	if (iter < CIPSO_V4_TAG_MAXCNT)
291*96cb8e33SPaul Moore 		doi_def->tags[iter] = CIPSO_V4_TAG_INVALID;
292*96cb8e33SPaul Moore 
293*96cb8e33SPaul Moore 	doi_def->doi = doi;
294*96cb8e33SPaul Moore 	ret_val = cipso_v4_doi_add(doi_def);
295*96cb8e33SPaul Moore 	if (ret_val != 0)
296*96cb8e33SPaul Moore 		goto add_pass_failure;
297*96cb8e33SPaul Moore 	return 0;
298*96cb8e33SPaul Moore 
299*96cb8e33SPaul Moore add_pass_failure:
300*96cb8e33SPaul Moore 	if (doi_def)
301*96cb8e33SPaul Moore 		netlbl_cipsov4_doi_free(&doi_def->rcu);
302*96cb8e33SPaul Moore 	return ret_val;
303*96cb8e33SPaul Moore }
304*96cb8e33SPaul Moore 
305*96cb8e33SPaul Moore /**
306*96cb8e33SPaul Moore  * netlbl_cipsov4_add - Handle an ADD message
307*96cb8e33SPaul Moore  * @skb: the NETLINK buffer
308*96cb8e33SPaul Moore  * @info: the Generic NETLINK info block
309*96cb8e33SPaul Moore  *
310*96cb8e33SPaul Moore  * Description:
311*96cb8e33SPaul Moore  * Create a new DOI definition based on the given ADD message and add it to the
312*96cb8e33SPaul Moore  * CIPSO V4 engine.  Returns zero on success, negative values on failure.
313*96cb8e33SPaul Moore  *
314*96cb8e33SPaul Moore  */
315*96cb8e33SPaul Moore static int netlbl_cipsov4_add(struct sk_buff *skb, struct genl_info *info)
316*96cb8e33SPaul Moore 
317*96cb8e33SPaul Moore {
318*96cb8e33SPaul Moore 	int ret_val = -EINVAL;
319*96cb8e33SPaul Moore 	u32 doi;
320*96cb8e33SPaul Moore 	u32 map_type;
321*96cb8e33SPaul Moore 	int msg_len = netlbl_netlink_payload_len(skb);
322*96cb8e33SPaul Moore 	struct nlattr *msg = netlbl_netlink_payload_data(skb);
323*96cb8e33SPaul Moore 
324*96cb8e33SPaul Moore 	ret_val = netlbl_netlink_cap_check(skb, CAP_NET_ADMIN);
325*96cb8e33SPaul Moore 	if (ret_val != 0)
326*96cb8e33SPaul Moore 		goto add_return;
327*96cb8e33SPaul Moore 
328*96cb8e33SPaul Moore 	if (msg_len < 2 * NETLBL_LEN_U32)
329*96cb8e33SPaul Moore 		goto add_return;
330*96cb8e33SPaul Moore 
331*96cb8e33SPaul Moore 	doi = netlbl_getinc_u32(&msg, &msg_len);
332*96cb8e33SPaul Moore 	map_type = netlbl_getinc_u32(&msg, &msg_len);
333*96cb8e33SPaul Moore 	switch (map_type) {
334*96cb8e33SPaul Moore 	case CIPSO_V4_MAP_STD:
335*96cb8e33SPaul Moore 		ret_val = netlbl_cipsov4_add_std(doi, msg, msg_len);
336*96cb8e33SPaul Moore 		break;
337*96cb8e33SPaul Moore 	case CIPSO_V4_MAP_PASS:
338*96cb8e33SPaul Moore 		ret_val = netlbl_cipsov4_add_pass(doi, msg, msg_len);
339*96cb8e33SPaul Moore 		break;
340*96cb8e33SPaul Moore 	}
341*96cb8e33SPaul Moore 
342*96cb8e33SPaul Moore add_return:
343*96cb8e33SPaul Moore 	netlbl_netlink_send_ack(info,
344*96cb8e33SPaul Moore 				netlbl_cipsov4_gnl_family.id,
345*96cb8e33SPaul Moore 				NLBL_CIPSOV4_C_ACK,
346*96cb8e33SPaul Moore 				-ret_val);
347*96cb8e33SPaul Moore 	return ret_val;
348*96cb8e33SPaul Moore }
349*96cb8e33SPaul Moore 
350*96cb8e33SPaul Moore /**
351*96cb8e33SPaul Moore  * netlbl_cipsov4_list - Handle a LIST message
352*96cb8e33SPaul Moore  * @skb: the NETLINK buffer
353*96cb8e33SPaul Moore  * @info: the Generic NETLINK info block
354*96cb8e33SPaul Moore  *
355*96cb8e33SPaul Moore  * Description:
356*96cb8e33SPaul Moore  * Process a user generated LIST message and respond accordingly.  Returns
357*96cb8e33SPaul Moore  * zero on success and negative values on error.
358*96cb8e33SPaul Moore  *
359*96cb8e33SPaul Moore  */
360*96cb8e33SPaul Moore static int netlbl_cipsov4_list(struct sk_buff *skb, struct genl_info *info)
361*96cb8e33SPaul Moore {
362*96cb8e33SPaul Moore 	int ret_val = -EINVAL;
363*96cb8e33SPaul Moore 	u32 doi;
364*96cb8e33SPaul Moore 	struct nlattr *msg = netlbl_netlink_payload_data(skb);
365*96cb8e33SPaul Moore 	struct sk_buff *ans_skb;
366*96cb8e33SPaul Moore 
367*96cb8e33SPaul Moore 	if (netlbl_netlink_payload_len(skb) != NETLBL_LEN_U32)
368*96cb8e33SPaul Moore 		goto list_failure;
369*96cb8e33SPaul Moore 
370*96cb8e33SPaul Moore 	doi = nla_get_u32(msg);
371*96cb8e33SPaul Moore 	ans_skb = cipso_v4_doi_dump(doi, NLMSG_SPACE(GENL_HDRLEN));
372*96cb8e33SPaul Moore 	if (ans_skb == NULL) {
373*96cb8e33SPaul Moore 		ret_val = -ENOMEM;
374*96cb8e33SPaul Moore 		goto list_failure;
375*96cb8e33SPaul Moore 	}
376*96cb8e33SPaul Moore 	netlbl_netlink_hdr_push(ans_skb,
377*96cb8e33SPaul Moore 				info->snd_pid,
378*96cb8e33SPaul Moore 				0,
379*96cb8e33SPaul Moore 				netlbl_cipsov4_gnl_family.id,
380*96cb8e33SPaul Moore 				NLBL_CIPSOV4_C_LIST);
381*96cb8e33SPaul Moore 
382*96cb8e33SPaul Moore 	ret_val = netlbl_netlink_snd(ans_skb, info->snd_pid);
383*96cb8e33SPaul Moore 	if (ret_val != 0)
384*96cb8e33SPaul Moore 		goto list_failure;
385*96cb8e33SPaul Moore 
386*96cb8e33SPaul Moore 	return 0;
387*96cb8e33SPaul Moore 
388*96cb8e33SPaul Moore list_failure:
389*96cb8e33SPaul Moore 	netlbl_netlink_send_ack(info,
390*96cb8e33SPaul Moore 				netlbl_cipsov4_gnl_family.id,
391*96cb8e33SPaul Moore 				NLBL_CIPSOV4_C_ACK,
392*96cb8e33SPaul Moore 				-ret_val);
393*96cb8e33SPaul Moore 	return ret_val;
394*96cb8e33SPaul Moore }
395*96cb8e33SPaul Moore 
396*96cb8e33SPaul Moore /**
397*96cb8e33SPaul Moore  * netlbl_cipsov4_listall - Handle a LISTALL message
398*96cb8e33SPaul Moore  * @skb: the NETLINK buffer
399*96cb8e33SPaul Moore  * @info: the Generic NETLINK info block
400*96cb8e33SPaul Moore  *
401*96cb8e33SPaul Moore  * Description:
402*96cb8e33SPaul Moore  * Process a user generated LISTALL message and respond accordingly.  Returns
403*96cb8e33SPaul Moore  * zero on success and negative values on error.
404*96cb8e33SPaul Moore  *
405*96cb8e33SPaul Moore  */
406*96cb8e33SPaul Moore static int netlbl_cipsov4_listall(struct sk_buff *skb, struct genl_info *info)
407*96cb8e33SPaul Moore {
408*96cb8e33SPaul Moore 	int ret_val = -EINVAL;
409*96cb8e33SPaul Moore 	struct sk_buff *ans_skb;
410*96cb8e33SPaul Moore 
411*96cb8e33SPaul Moore 	ans_skb = cipso_v4_doi_dump_all(NLMSG_SPACE(GENL_HDRLEN));
412*96cb8e33SPaul Moore 	if (ans_skb == NULL) {
413*96cb8e33SPaul Moore 		ret_val = -ENOMEM;
414*96cb8e33SPaul Moore 		goto listall_failure;
415*96cb8e33SPaul Moore 	}
416*96cb8e33SPaul Moore 	netlbl_netlink_hdr_push(ans_skb,
417*96cb8e33SPaul Moore 				info->snd_pid,
418*96cb8e33SPaul Moore 				0,
419*96cb8e33SPaul Moore 				netlbl_cipsov4_gnl_family.id,
420*96cb8e33SPaul Moore 				NLBL_CIPSOV4_C_LISTALL);
421*96cb8e33SPaul Moore 
422*96cb8e33SPaul Moore 	ret_val = netlbl_netlink_snd(ans_skb, info->snd_pid);
423*96cb8e33SPaul Moore 	if (ret_val != 0)
424*96cb8e33SPaul Moore 		goto listall_failure;
425*96cb8e33SPaul Moore 
426*96cb8e33SPaul Moore 	return 0;
427*96cb8e33SPaul Moore 
428*96cb8e33SPaul Moore listall_failure:
429*96cb8e33SPaul Moore 	netlbl_netlink_send_ack(info,
430*96cb8e33SPaul Moore 				netlbl_cipsov4_gnl_family.id,
431*96cb8e33SPaul Moore 				NLBL_CIPSOV4_C_ACK,
432*96cb8e33SPaul Moore 				-ret_val);
433*96cb8e33SPaul Moore 	return ret_val;
434*96cb8e33SPaul Moore }
435*96cb8e33SPaul Moore 
436*96cb8e33SPaul Moore /**
437*96cb8e33SPaul Moore  * netlbl_cipsov4_remove - Handle a REMOVE message
438*96cb8e33SPaul Moore  * @skb: the NETLINK buffer
439*96cb8e33SPaul Moore  * @info: the Generic NETLINK info block
440*96cb8e33SPaul Moore  *
441*96cb8e33SPaul Moore  * Description:
442*96cb8e33SPaul Moore  * Process a user generated REMOVE message and respond accordingly.  Returns
443*96cb8e33SPaul Moore  * zero on success, negative values on failure.
444*96cb8e33SPaul Moore  *
445*96cb8e33SPaul Moore  */
446*96cb8e33SPaul Moore static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info)
447*96cb8e33SPaul Moore {
448*96cb8e33SPaul Moore 	int ret_val;
449*96cb8e33SPaul Moore 	u32 doi;
450*96cb8e33SPaul Moore 	struct nlattr *msg = netlbl_netlink_payload_data(skb);
451*96cb8e33SPaul Moore 
452*96cb8e33SPaul Moore 	ret_val = netlbl_netlink_cap_check(skb, CAP_NET_ADMIN);
453*96cb8e33SPaul Moore 	if (ret_val != 0)
454*96cb8e33SPaul Moore 		goto remove_return;
455*96cb8e33SPaul Moore 
456*96cb8e33SPaul Moore 	if (netlbl_netlink_payload_len(skb) != NETLBL_LEN_U32) {
457*96cb8e33SPaul Moore 		ret_val = -EINVAL;
458*96cb8e33SPaul Moore 		goto remove_return;
459*96cb8e33SPaul Moore 	}
460*96cb8e33SPaul Moore 
461*96cb8e33SPaul Moore 	doi = nla_get_u32(msg);
462*96cb8e33SPaul Moore 	ret_val = cipso_v4_doi_remove(doi, netlbl_cipsov4_doi_free);
463*96cb8e33SPaul Moore 
464*96cb8e33SPaul Moore remove_return:
465*96cb8e33SPaul Moore 	netlbl_netlink_send_ack(info,
466*96cb8e33SPaul Moore 				netlbl_cipsov4_gnl_family.id,
467*96cb8e33SPaul Moore 				NLBL_CIPSOV4_C_ACK,
468*96cb8e33SPaul Moore 				-ret_val);
469*96cb8e33SPaul Moore 	return ret_val;
470*96cb8e33SPaul Moore }
471*96cb8e33SPaul Moore 
472*96cb8e33SPaul Moore /*
473*96cb8e33SPaul Moore  * NetLabel Generic NETLINK Command Definitions
474*96cb8e33SPaul Moore  */
475*96cb8e33SPaul Moore 
476*96cb8e33SPaul Moore static struct genl_ops netlbl_cipsov4_genl_c_add = {
477*96cb8e33SPaul Moore 	.cmd = NLBL_CIPSOV4_C_ADD,
478*96cb8e33SPaul Moore 	.flags = 0,
479*96cb8e33SPaul Moore 	.doit = netlbl_cipsov4_add,
480*96cb8e33SPaul Moore 	.dumpit = NULL,
481*96cb8e33SPaul Moore };
482*96cb8e33SPaul Moore 
483*96cb8e33SPaul Moore static struct genl_ops netlbl_cipsov4_genl_c_remove = {
484*96cb8e33SPaul Moore 	.cmd = NLBL_CIPSOV4_C_REMOVE,
485*96cb8e33SPaul Moore 	.flags = 0,
486*96cb8e33SPaul Moore 	.doit = netlbl_cipsov4_remove,
487*96cb8e33SPaul Moore 	.dumpit = NULL,
488*96cb8e33SPaul Moore };
489*96cb8e33SPaul Moore 
490*96cb8e33SPaul Moore static struct genl_ops netlbl_cipsov4_genl_c_list = {
491*96cb8e33SPaul Moore 	.cmd = NLBL_CIPSOV4_C_LIST,
492*96cb8e33SPaul Moore 	.flags = 0,
493*96cb8e33SPaul Moore 	.doit = netlbl_cipsov4_list,
494*96cb8e33SPaul Moore 	.dumpit = NULL,
495*96cb8e33SPaul Moore };
496*96cb8e33SPaul Moore 
497*96cb8e33SPaul Moore static struct genl_ops netlbl_cipsov4_genl_c_listall = {
498*96cb8e33SPaul Moore 	.cmd = NLBL_CIPSOV4_C_LISTALL,
499*96cb8e33SPaul Moore 	.flags = 0,
500*96cb8e33SPaul Moore 	.doit = netlbl_cipsov4_listall,
501*96cb8e33SPaul Moore 	.dumpit = NULL,
502*96cb8e33SPaul Moore };
503*96cb8e33SPaul Moore 
504*96cb8e33SPaul Moore /*
505*96cb8e33SPaul Moore  * NetLabel Generic NETLINK Protocol Functions
506*96cb8e33SPaul Moore  */
507*96cb8e33SPaul Moore 
508*96cb8e33SPaul Moore /**
509*96cb8e33SPaul Moore  * netlbl_cipsov4_genl_init - Register the CIPSOv4 NetLabel component
510*96cb8e33SPaul Moore  *
511*96cb8e33SPaul Moore  * Description:
512*96cb8e33SPaul Moore  * Register the CIPSOv4 packet NetLabel component with the Generic NETLINK
513*96cb8e33SPaul Moore  * mechanism.  Returns zero on success, negative values on failure.
514*96cb8e33SPaul Moore  *
515*96cb8e33SPaul Moore  */
516*96cb8e33SPaul Moore int netlbl_cipsov4_genl_init(void)
517*96cb8e33SPaul Moore {
518*96cb8e33SPaul Moore 	int ret_val;
519*96cb8e33SPaul Moore 
520*96cb8e33SPaul Moore 	ret_val = genl_register_family(&netlbl_cipsov4_gnl_family);
521*96cb8e33SPaul Moore 	if (ret_val != 0)
522*96cb8e33SPaul Moore 		return ret_val;
523*96cb8e33SPaul Moore 
524*96cb8e33SPaul Moore 	ret_val = genl_register_ops(&netlbl_cipsov4_gnl_family,
525*96cb8e33SPaul Moore 				    &netlbl_cipsov4_genl_c_add);
526*96cb8e33SPaul Moore 	if (ret_val != 0)
527*96cb8e33SPaul Moore 		return ret_val;
528*96cb8e33SPaul Moore 	ret_val = genl_register_ops(&netlbl_cipsov4_gnl_family,
529*96cb8e33SPaul Moore 				    &netlbl_cipsov4_genl_c_remove);
530*96cb8e33SPaul Moore 	if (ret_val != 0)
531*96cb8e33SPaul Moore 		return ret_val;
532*96cb8e33SPaul Moore 	ret_val = genl_register_ops(&netlbl_cipsov4_gnl_family,
533*96cb8e33SPaul Moore 				    &netlbl_cipsov4_genl_c_list);
534*96cb8e33SPaul Moore 	if (ret_val != 0)
535*96cb8e33SPaul Moore 		return ret_val;
536*96cb8e33SPaul Moore 	ret_val = genl_register_ops(&netlbl_cipsov4_gnl_family,
537*96cb8e33SPaul Moore 				    &netlbl_cipsov4_genl_c_listall);
538*96cb8e33SPaul Moore 	if (ret_val != 0)
539*96cb8e33SPaul Moore 		return ret_val;
540*96cb8e33SPaul Moore 
541*96cb8e33SPaul Moore 	return 0;
542*96cb8e33SPaul Moore }
543