xref: /openbmc/linux/net/netlabel/netlabel_mgmt.c (revision ef7c79ed)
1d15c345fSPaul Moore /*
2d15c345fSPaul Moore  * NetLabel Management Support
3d15c345fSPaul Moore  *
4d15c345fSPaul Moore  * This file defines the management functions for the NetLabel system.  The
5d15c345fSPaul Moore  * NetLabel system manages static and dynamic label mappings for network
6d15c345fSPaul Moore  * protocols such as CIPSO and RIPSO.
7d15c345fSPaul Moore  *
8d15c345fSPaul Moore  * Author: Paul Moore <paul.moore@hp.com>
9d15c345fSPaul Moore  *
10d15c345fSPaul Moore  */
11d15c345fSPaul Moore 
12d15c345fSPaul Moore /*
13d15c345fSPaul Moore  * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
14d15c345fSPaul Moore  *
15d15c345fSPaul Moore  * This program is free software;  you can redistribute it and/or modify
16d15c345fSPaul Moore  * it under the terms of the GNU General Public License as published by
17d15c345fSPaul Moore  * the Free Software Foundation; either version 2 of the License, or
18d15c345fSPaul Moore  * (at your option) any later version.
19d15c345fSPaul Moore  *
20d15c345fSPaul Moore  * This program is distributed in the hope that it will be useful,
21d15c345fSPaul Moore  * but WITHOUT ANY WARRANTY;  without even the implied warranty of
22d15c345fSPaul Moore  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
23d15c345fSPaul Moore  * the GNU General Public License for more details.
24d15c345fSPaul Moore  *
25d15c345fSPaul Moore  * You should have received a copy of the GNU General Public License
26d15c345fSPaul Moore  * along with this program;  if not, write to the Free Software
27d15c345fSPaul Moore  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28d15c345fSPaul Moore  *
29d15c345fSPaul Moore  */
30d15c345fSPaul Moore 
31d15c345fSPaul Moore #include <linux/types.h>
32d15c345fSPaul Moore #include <linux/socket.h>
33d15c345fSPaul Moore #include <linux/string.h>
34d15c345fSPaul Moore #include <linux/skbuff.h>
35d15c345fSPaul Moore #include <net/sock.h>
36d15c345fSPaul Moore #include <net/netlink.h>
37d15c345fSPaul Moore #include <net/genetlink.h>
38d15c345fSPaul Moore #include <net/netlabel.h>
39d15c345fSPaul Moore #include <net/cipso_ipv4.h>
40d15c345fSPaul Moore 
41d15c345fSPaul Moore #include "netlabel_domainhash.h"
42d15c345fSPaul Moore #include "netlabel_user.h"
43d15c345fSPaul Moore #include "netlabel_mgmt.h"
44d15c345fSPaul Moore 
45fd385855SPaul Moore /* Argument struct for netlbl_domhsh_walk() */
46fd385855SPaul Moore struct netlbl_domhsh_walk_arg {
47fd385855SPaul Moore 	struct netlink_callback *nl_cb;
48fd385855SPaul Moore 	struct sk_buff *skb;
49fd385855SPaul Moore 	u32 seq;
50fd385855SPaul Moore };
51fd385855SPaul Moore 
52d15c345fSPaul Moore /* NetLabel Generic NETLINK CIPSOv4 family */
53d15c345fSPaul Moore static struct genl_family netlbl_mgmt_gnl_family = {
54d15c345fSPaul Moore 	.id = GENL_ID_GENERATE,
55d15c345fSPaul Moore 	.hdrsize = 0,
56d15c345fSPaul Moore 	.name = NETLBL_NLTYPE_MGMT_NAME,
57d15c345fSPaul Moore 	.version = NETLBL_PROTO_VERSION,
58fd385855SPaul Moore 	.maxattr = NLBL_MGMT_A_MAX,
59d15c345fSPaul Moore };
60d15c345fSPaul Moore 
61fd385855SPaul Moore /* NetLabel Netlink attribute policy */
62ef7c79edSPatrick McHardy static const struct nla_policy netlbl_mgmt_genl_policy[NLBL_MGMT_A_MAX + 1] = {
63fd385855SPaul Moore 	[NLBL_MGMT_A_DOMAIN] = { .type = NLA_NUL_STRING },
64fd385855SPaul Moore 	[NLBL_MGMT_A_PROTOCOL] = { .type = NLA_U32 },
65fd385855SPaul Moore 	[NLBL_MGMT_A_VERSION] = { .type = NLA_U32 },
66fd385855SPaul Moore 	[NLBL_MGMT_A_CV4DOI] = { .type = NLA_U32 },
67fd385855SPaul Moore };
68d15c345fSPaul Moore 
69d15c345fSPaul Moore /*
70d15c345fSPaul Moore  * NetLabel Command Handlers
71d15c345fSPaul Moore  */
72d15c345fSPaul Moore 
73d15c345fSPaul Moore /**
74d15c345fSPaul Moore  * netlbl_mgmt_add - Handle an ADD message
75d15c345fSPaul Moore  * @skb: the NETLINK buffer
76d15c345fSPaul Moore  * @info: the Generic NETLINK info block
77d15c345fSPaul Moore  *
78d15c345fSPaul Moore  * Description:
79d15c345fSPaul Moore  * Process a user generated ADD message and add the domains from the message
80d15c345fSPaul Moore  * to the hash table.  See netlabel.h for a description of the message format.
81d15c345fSPaul Moore  * Returns zero on success, negative values on failure.
82d15c345fSPaul Moore  *
83d15c345fSPaul Moore  */
84d15c345fSPaul Moore static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info)
85d15c345fSPaul Moore {
86d15c345fSPaul Moore 	int ret_val = -EINVAL;
87d15c345fSPaul Moore 	struct netlbl_dom_map *entry = NULL;
88fd385855SPaul Moore 	size_t tmp_size;
89d15c345fSPaul Moore 	u32 tmp_val;
9095d4e6beSPaul Moore 	struct netlbl_audit audit_info;
91d15c345fSPaul Moore 
92fd385855SPaul Moore 	if (!info->attrs[NLBL_MGMT_A_DOMAIN] ||
93fd385855SPaul Moore 	    !info->attrs[NLBL_MGMT_A_PROTOCOL])
94d15c345fSPaul Moore 		goto add_failure;
95d15c345fSPaul Moore 
9695d4e6beSPaul Moore 	netlbl_netlink_auditinfo(skb, &audit_info);
9795d4e6beSPaul Moore 
98d15c345fSPaul Moore 	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
99d15c345fSPaul Moore 	if (entry == NULL) {
100d15c345fSPaul Moore 		ret_val = -ENOMEM;
101d15c345fSPaul Moore 		goto add_failure;
102d15c345fSPaul Moore 	}
103fd385855SPaul Moore 	tmp_size = nla_len(info->attrs[NLBL_MGMT_A_DOMAIN]);
104d15c345fSPaul Moore 	entry->domain = kmalloc(tmp_size, GFP_KERNEL);
105d15c345fSPaul Moore 	if (entry->domain == NULL) {
106d15c345fSPaul Moore 		ret_val = -ENOMEM;
107d15c345fSPaul Moore 		goto add_failure;
108d15c345fSPaul Moore 	}
109fd385855SPaul Moore 	entry->type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]);
110fd385855SPaul Moore 	nla_strlcpy(entry->domain, info->attrs[NLBL_MGMT_A_DOMAIN], tmp_size);
111d15c345fSPaul Moore 
112fd385855SPaul Moore 	switch (entry->type) {
113d15c345fSPaul Moore 	case NETLBL_NLTYPE_UNLABELED:
11495d4e6beSPaul Moore 		ret_val = netlbl_domhsh_add(entry, &audit_info);
115d15c345fSPaul Moore 		break;
116d15c345fSPaul Moore 	case NETLBL_NLTYPE_CIPSOV4:
117fd385855SPaul Moore 		if (!info->attrs[NLBL_MGMT_A_CV4DOI])
118d15c345fSPaul Moore 			goto add_failure;
119fd385855SPaul Moore 
120fd385855SPaul Moore 		tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]);
121fd385855SPaul Moore 		/* We should be holding a rcu_read_lock() here while we hold
122fd385855SPaul Moore 		 * the result but since the entry will always be deleted when
123fd385855SPaul Moore 		 * the CIPSO DOI is deleted we aren't going to keep the
124fd385855SPaul Moore 		 * lock. */
125d15c345fSPaul Moore 		rcu_read_lock();
126d15c345fSPaul Moore 		entry->type_def.cipsov4 = cipso_v4_doi_getdef(tmp_val);
127d15c345fSPaul Moore 		if (entry->type_def.cipsov4 == NULL) {
128d15c345fSPaul Moore 			rcu_read_unlock();
129d15c345fSPaul Moore 			goto add_failure;
130d15c345fSPaul Moore 		}
13195d4e6beSPaul Moore 		ret_val = netlbl_domhsh_add(entry, &audit_info);
132d15c345fSPaul Moore 		rcu_read_unlock();
133d15c345fSPaul Moore 		break;
134d15c345fSPaul Moore 	default:
135fd385855SPaul Moore 		goto add_failure;
136d15c345fSPaul Moore 	}
137d15c345fSPaul Moore 	if (ret_val != 0)
138d15c345fSPaul Moore 		goto add_failure;
139d15c345fSPaul Moore 
140d15c345fSPaul Moore 	return 0;
141d15c345fSPaul Moore 
142d15c345fSPaul Moore add_failure:
143d15c345fSPaul Moore 	if (entry)
144d15c345fSPaul Moore 		kfree(entry->domain);
145d15c345fSPaul Moore 	kfree(entry);
146d15c345fSPaul Moore 	return ret_val;
147d15c345fSPaul Moore }
148d15c345fSPaul Moore 
149d15c345fSPaul Moore /**
150d15c345fSPaul Moore  * netlbl_mgmt_remove - Handle a REMOVE message
151d15c345fSPaul Moore  * @skb: the NETLINK buffer
152d15c345fSPaul Moore  * @info: the Generic NETLINK info block
153d15c345fSPaul Moore  *
154d15c345fSPaul Moore  * Description:
155d15c345fSPaul Moore  * Process a user generated REMOVE message and remove the specified domain
156d15c345fSPaul Moore  * mappings.  Returns zero on success, negative values on failure.
157d15c345fSPaul Moore  *
158d15c345fSPaul Moore  */
159d15c345fSPaul Moore static int netlbl_mgmt_remove(struct sk_buff *skb, struct genl_info *info)
160d15c345fSPaul Moore {
161fd385855SPaul Moore 	char *domain;
16295d4e6beSPaul Moore 	struct netlbl_audit audit_info;
163d15c345fSPaul Moore 
164fd385855SPaul Moore 	if (!info->attrs[NLBL_MGMT_A_DOMAIN])
165fd385855SPaul Moore 		return -EINVAL;
166d15c345fSPaul Moore 
16795d4e6beSPaul Moore 	netlbl_netlink_auditinfo(skb, &audit_info);
16895d4e6beSPaul Moore 
169fd385855SPaul Moore 	domain = nla_data(info->attrs[NLBL_MGMT_A_DOMAIN]);
17095d4e6beSPaul Moore 	return netlbl_domhsh_remove(domain, &audit_info);
171d15c345fSPaul Moore }
172d15c345fSPaul Moore 
173fd385855SPaul Moore /**
174fd385855SPaul Moore  * netlbl_mgmt_listall_cb - netlbl_domhsh_walk() callback for LISTALL
175fd385855SPaul Moore  * @entry: the domain mapping hash table entry
176fd385855SPaul Moore  * @arg: the netlbl_domhsh_walk_arg structure
177fd385855SPaul Moore  *
178fd385855SPaul Moore  * Description:
179fd385855SPaul Moore  * This function is designed to be used as a callback to the
180fd385855SPaul Moore  * netlbl_domhsh_walk() function for use in generating a response for a LISTALL
181fd385855SPaul Moore  * message.  Returns the size of the message on success, negative values on
182fd385855SPaul Moore  * failure.
183fd385855SPaul Moore  *
184fd385855SPaul Moore  */
185fd385855SPaul Moore static int netlbl_mgmt_listall_cb(struct netlbl_dom_map *entry, void *arg)
186fd385855SPaul Moore {
187fd385855SPaul Moore 	int ret_val = -ENOMEM;
188fd385855SPaul Moore 	struct netlbl_domhsh_walk_arg *cb_arg = arg;
189fd385855SPaul Moore 	void *data;
190d15c345fSPaul Moore 
19117c157c8SThomas Graf 	data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).pid,
19217c157c8SThomas Graf 			   cb_arg->seq, &netlbl_mgmt_gnl_family,
19317c157c8SThomas Graf 			   NLM_F_MULTI, NLBL_MGMT_C_LISTALL);
194fd385855SPaul Moore 	if (data == NULL)
195fd385855SPaul Moore 		goto listall_cb_failure;
196fd385855SPaul Moore 
197fd385855SPaul Moore 	ret_val = nla_put_string(cb_arg->skb,
198fd385855SPaul Moore 				 NLBL_MGMT_A_DOMAIN,
199fd385855SPaul Moore 				 entry->domain);
200fd385855SPaul Moore 	if (ret_val != 0)
201fd385855SPaul Moore 		goto listall_cb_failure;
202fd385855SPaul Moore 	ret_val = nla_put_u32(cb_arg->skb, NLBL_MGMT_A_PROTOCOL, entry->type);
203fd385855SPaul Moore 	if (ret_val != 0)
204fd385855SPaul Moore 		goto listall_cb_failure;
205fd385855SPaul Moore 	switch (entry->type) {
206fd385855SPaul Moore 	case NETLBL_NLTYPE_CIPSOV4:
207fd385855SPaul Moore 		ret_val = nla_put_u32(cb_arg->skb,
208fd385855SPaul Moore 				      NLBL_MGMT_A_CV4DOI,
209fd385855SPaul Moore 				      entry->type_def.cipsov4->doi);
210fd385855SPaul Moore 		if (ret_val != 0)
211fd385855SPaul Moore 			goto listall_cb_failure;
212fd385855SPaul Moore 		break;
213fd385855SPaul Moore 	}
214fd385855SPaul Moore 
215fd385855SPaul Moore 	cb_arg->seq++;
216fd385855SPaul Moore 	return genlmsg_end(cb_arg->skb, data);
217fd385855SPaul Moore 
218fd385855SPaul Moore listall_cb_failure:
219fd385855SPaul Moore 	genlmsg_cancel(cb_arg->skb, data);
220d15c345fSPaul Moore 	return ret_val;
221d15c345fSPaul Moore }
222d15c345fSPaul Moore 
223d15c345fSPaul Moore /**
224fd385855SPaul Moore  * netlbl_mgmt_listall - Handle a LISTALL message
225d15c345fSPaul Moore  * @skb: the NETLINK buffer
226fd385855SPaul Moore  * @cb: the NETLINK callback
227d15c345fSPaul Moore  *
228d15c345fSPaul Moore  * Description:
229fd385855SPaul Moore  * Process a user generated LISTALL message and dumps the domain hash table in
230fd385855SPaul Moore  * a form suitable for use in a kernel generated LISTALL message.  Returns zero
231fd385855SPaul Moore  * on success, negative values on failure.
232d15c345fSPaul Moore  *
233d15c345fSPaul Moore  */
234fd385855SPaul Moore static int netlbl_mgmt_listall(struct sk_buff *skb,
235fd385855SPaul Moore 			       struct netlink_callback *cb)
236d15c345fSPaul Moore {
237fd385855SPaul Moore 	struct netlbl_domhsh_walk_arg cb_arg;
238fd385855SPaul Moore 	u32 skip_bkt = cb->args[0];
239fd385855SPaul Moore 	u32 skip_chain = cb->args[1];
240d15c345fSPaul Moore 
241fd385855SPaul Moore 	cb_arg.nl_cb = cb;
242fd385855SPaul Moore 	cb_arg.skb = skb;
243fd385855SPaul Moore 	cb_arg.seq = cb->nlh->nlmsg_seq;
244d15c345fSPaul Moore 
245fd385855SPaul Moore 	netlbl_domhsh_walk(&skip_bkt,
246fd385855SPaul Moore 			   &skip_chain,
247fd385855SPaul Moore 			   netlbl_mgmt_listall_cb,
248fd385855SPaul Moore 			   &cb_arg);
249d15c345fSPaul Moore 
250fd385855SPaul Moore 	cb->args[0] = skip_bkt;
251fd385855SPaul Moore 	cb->args[1] = skip_chain;
252fd385855SPaul Moore 	return skb->len;
253d15c345fSPaul Moore }
254d15c345fSPaul Moore 
255d15c345fSPaul Moore /**
256d15c345fSPaul Moore  * netlbl_mgmt_adddef - Handle an ADDDEF message
257d15c345fSPaul Moore  * @skb: the NETLINK buffer
258d15c345fSPaul Moore  * @info: the Generic NETLINK info block
259d15c345fSPaul Moore  *
260d15c345fSPaul Moore  * Description:
261d15c345fSPaul Moore  * Process a user generated ADDDEF message and respond accordingly.  Returns
262d15c345fSPaul Moore  * zero on success, negative values on failure.
263d15c345fSPaul Moore  *
264d15c345fSPaul Moore  */
265d15c345fSPaul Moore static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info)
266d15c345fSPaul Moore {
267d15c345fSPaul Moore 	int ret_val = -EINVAL;
268d15c345fSPaul Moore 	struct netlbl_dom_map *entry = NULL;
269d15c345fSPaul Moore 	u32 tmp_val;
27095d4e6beSPaul Moore 	struct netlbl_audit audit_info;
271d15c345fSPaul Moore 
272fd385855SPaul Moore 	if (!info->attrs[NLBL_MGMT_A_PROTOCOL])
273d15c345fSPaul Moore 		goto adddef_failure;
274d15c345fSPaul Moore 
27595d4e6beSPaul Moore 	netlbl_netlink_auditinfo(skb, &audit_info);
27695d4e6beSPaul Moore 
277d15c345fSPaul Moore 	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
278d15c345fSPaul Moore 	if (entry == NULL) {
279d15c345fSPaul Moore 		ret_val = -ENOMEM;
280d15c345fSPaul Moore 		goto adddef_failure;
281d15c345fSPaul Moore 	}
282fd385855SPaul Moore 	entry->type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]);
283d15c345fSPaul Moore 
284d15c345fSPaul Moore 	switch (entry->type) {
285d15c345fSPaul Moore 	case NETLBL_NLTYPE_UNLABELED:
28695d4e6beSPaul Moore 		ret_val = netlbl_domhsh_add_default(entry, &audit_info);
287d15c345fSPaul Moore 		break;
288d15c345fSPaul Moore 	case NETLBL_NLTYPE_CIPSOV4:
289fd385855SPaul Moore 		if (!info->attrs[NLBL_MGMT_A_CV4DOI])
290d15c345fSPaul Moore 			goto adddef_failure;
291fd385855SPaul Moore 
292fd385855SPaul Moore 		tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]);
293fd385855SPaul Moore 		/* We should be holding a rcu_read_lock() here while we hold
294fd385855SPaul Moore 		 * the result but since the entry will always be deleted when
295fd385855SPaul Moore 		 * the CIPSO DOI is deleted we aren't going to keep the
296fd385855SPaul Moore 		 * lock. */
297d15c345fSPaul Moore 		rcu_read_lock();
298d15c345fSPaul Moore 		entry->type_def.cipsov4 = cipso_v4_doi_getdef(tmp_val);
299d15c345fSPaul Moore 		if (entry->type_def.cipsov4 == NULL) {
300d15c345fSPaul Moore 			rcu_read_unlock();
301d15c345fSPaul Moore 			goto adddef_failure;
302d15c345fSPaul Moore 		}
30395d4e6beSPaul Moore 		ret_val = netlbl_domhsh_add_default(entry, &audit_info);
304d15c345fSPaul Moore 		rcu_read_unlock();
305d15c345fSPaul Moore 		break;
306d15c345fSPaul Moore 	default:
307fd385855SPaul Moore 		goto adddef_failure;
308d15c345fSPaul Moore 	}
309d15c345fSPaul Moore 	if (ret_val != 0)
310d15c345fSPaul Moore 		goto adddef_failure;
311d15c345fSPaul Moore 
312d15c345fSPaul Moore 	return 0;
313d15c345fSPaul Moore 
314d15c345fSPaul Moore adddef_failure:
315d15c345fSPaul Moore 	kfree(entry);
316d15c345fSPaul Moore 	return ret_val;
317d15c345fSPaul Moore }
318d15c345fSPaul Moore 
319d15c345fSPaul Moore /**
320d15c345fSPaul Moore  * netlbl_mgmt_removedef - Handle a REMOVEDEF message
321d15c345fSPaul Moore  * @skb: the NETLINK buffer
322d15c345fSPaul Moore  * @info: the Generic NETLINK info block
323d15c345fSPaul Moore  *
324d15c345fSPaul Moore  * Description:
325d15c345fSPaul Moore  * Process a user generated REMOVEDEF message and remove the default domain
326d15c345fSPaul Moore  * mapping.  Returns zero on success, negative values on failure.
327d15c345fSPaul Moore  *
328d15c345fSPaul Moore  */
329d15c345fSPaul Moore static int netlbl_mgmt_removedef(struct sk_buff *skb, struct genl_info *info)
330d15c345fSPaul Moore {
33195d4e6beSPaul Moore 	struct netlbl_audit audit_info;
33295d4e6beSPaul Moore 
33395d4e6beSPaul Moore 	netlbl_netlink_auditinfo(skb, &audit_info);
33495d4e6beSPaul Moore 
33595d4e6beSPaul Moore 	return netlbl_domhsh_remove_default(&audit_info);
336d15c345fSPaul Moore }
337d15c345fSPaul Moore 
338d15c345fSPaul Moore /**
339d15c345fSPaul Moore  * netlbl_mgmt_listdef - Handle a LISTDEF message
340d15c345fSPaul Moore  * @skb: the NETLINK buffer
341d15c345fSPaul Moore  * @info: the Generic NETLINK info block
342d15c345fSPaul Moore  *
343d15c345fSPaul Moore  * Description:
344d15c345fSPaul Moore  * Process a user generated LISTDEF message and dumps the default domain
345d15c345fSPaul Moore  * mapping in a form suitable for use in a kernel generated LISTDEF message.
346d15c345fSPaul Moore  * Returns zero on success, negative values on failure.
347d15c345fSPaul Moore  *
348d15c345fSPaul Moore  */
349d15c345fSPaul Moore static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info)
350d15c345fSPaul Moore {
351d15c345fSPaul Moore 	int ret_val = -ENOMEM;
352fd385855SPaul Moore 	struct sk_buff *ans_skb = NULL;
353fd385855SPaul Moore 	void *data;
354fd385855SPaul Moore 	struct netlbl_dom_map *entry;
355d15c345fSPaul Moore 
356339bf98fSThomas Graf 	ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
357d15c345fSPaul Moore 	if (ans_skb == NULL)
358fd385855SPaul Moore 		return -ENOMEM;
35917c157c8SThomas Graf 	data = genlmsg_put_reply(ans_skb, info, &netlbl_mgmt_gnl_family,
36017c157c8SThomas Graf 				 0, NLBL_MGMT_C_LISTDEF);
361fd385855SPaul Moore 	if (data == NULL)
362fd385855SPaul Moore 		goto listdef_failure;
363d15c345fSPaul Moore 
364fd385855SPaul Moore 	rcu_read_lock();
365fd385855SPaul Moore 	entry = netlbl_domhsh_getentry(NULL);
366fd385855SPaul Moore 	if (entry == NULL) {
367fd385855SPaul Moore 		ret_val = -ENOENT;
368fd385855SPaul Moore 		goto listdef_failure_lock;
369fd385855SPaul Moore 	}
370fd385855SPaul Moore 	ret_val = nla_put_u32(ans_skb, NLBL_MGMT_A_PROTOCOL, entry->type);
371fd385855SPaul Moore 	if (ret_val != 0)
372fd385855SPaul Moore 		goto listdef_failure_lock;
373fd385855SPaul Moore 	switch (entry->type) {
374fd385855SPaul Moore 	case NETLBL_NLTYPE_CIPSOV4:
375fd385855SPaul Moore 		ret_val = nla_put_u32(ans_skb,
376fd385855SPaul Moore 				      NLBL_MGMT_A_CV4DOI,
377fd385855SPaul Moore 				      entry->type_def.cipsov4->doi);
378fd385855SPaul Moore 		if (ret_val != 0)
379fd385855SPaul Moore 			goto listdef_failure_lock;
380fd385855SPaul Moore 		break;
381fd385855SPaul Moore 	}
382fd385855SPaul Moore 	rcu_read_unlock();
383fd385855SPaul Moore 
384fd385855SPaul Moore 	genlmsg_end(ans_skb, data);
385fd385855SPaul Moore 
38681878d27SThomas Graf 	ret_val = genlmsg_reply(ans_skb, info);
387d15c345fSPaul Moore 	if (ret_val != 0)
388d15c345fSPaul Moore 		goto listdef_failure;
389d15c345fSPaul Moore 	return 0;
390d15c345fSPaul Moore 
391fd385855SPaul Moore listdef_failure_lock:
392fd385855SPaul Moore 	rcu_read_unlock();
393d15c345fSPaul Moore listdef_failure:
394fd385855SPaul Moore 	kfree_skb(ans_skb);
395d15c345fSPaul Moore 	return ret_val;
396d15c345fSPaul Moore }
397d15c345fSPaul Moore 
398d15c345fSPaul Moore /**
399fd385855SPaul Moore  * netlbl_mgmt_protocols_cb - Write an individual PROTOCOL message response
400fd385855SPaul Moore  * @skb: the skb to write to
401fd385855SPaul Moore  * @seq: the NETLINK sequence number
402fd385855SPaul Moore  * @cb: the NETLINK callback
403fd385855SPaul Moore  * @protocol: the NetLabel protocol to use in the message
404d15c345fSPaul Moore  *
405d15c345fSPaul Moore  * Description:
406fd385855SPaul Moore  * This function is to be used in conjunction with netlbl_mgmt_protocols() to
407fd385855SPaul Moore  * answer a application's PROTOCOLS message.  Returns the size of the message
408fd385855SPaul Moore  * on success, negative values on failure.
409d15c345fSPaul Moore  *
410d15c345fSPaul Moore  */
411fd385855SPaul Moore static int netlbl_mgmt_protocols_cb(struct sk_buff *skb,
412fd385855SPaul Moore 				    struct netlink_callback *cb,
413fd385855SPaul Moore 				    u32 protocol)
414d15c345fSPaul Moore {
415d15c345fSPaul Moore 	int ret_val = -ENOMEM;
416fd385855SPaul Moore 	void *data;
417d15c345fSPaul Moore 
41817c157c8SThomas Graf 	data = genlmsg_put(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq,
41917c157c8SThomas Graf 			   &netlbl_mgmt_gnl_family, NLM_F_MULTI,
420fd385855SPaul Moore 			   NLBL_MGMT_C_PROTOCOLS);
421fd385855SPaul Moore 	if (data == NULL)
422fd385855SPaul Moore 		goto protocols_cb_failure;
423d15c345fSPaul Moore 
424fd385855SPaul Moore 	ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, protocol);
425d15c345fSPaul Moore 	if (ret_val != 0)
426fd385855SPaul Moore 		goto protocols_cb_failure;
427d15c345fSPaul Moore 
428fd385855SPaul Moore 	return genlmsg_end(skb, data);
429d15c345fSPaul Moore 
430fd385855SPaul Moore protocols_cb_failure:
431fd385855SPaul Moore 	genlmsg_cancel(skb, data);
432d15c345fSPaul Moore 	return ret_val;
433d15c345fSPaul Moore }
434d15c345fSPaul Moore 
435d15c345fSPaul Moore /**
436fd385855SPaul Moore  * netlbl_mgmt_protocols - Handle a PROTOCOLS message
437fd385855SPaul Moore  * @skb: the NETLINK buffer
438fd385855SPaul Moore  * @cb: the NETLINK callback
439fd385855SPaul Moore  *
440fd385855SPaul Moore  * Description:
441fd385855SPaul Moore  * Process a user generated PROTOCOLS message and respond accordingly.
442fd385855SPaul Moore  *
443fd385855SPaul Moore  */
444fd385855SPaul Moore static int netlbl_mgmt_protocols(struct sk_buff *skb,
445fd385855SPaul Moore 				 struct netlink_callback *cb)
446fd385855SPaul Moore {
447fd385855SPaul Moore 	u32 protos_sent = cb->args[0];
448fd385855SPaul Moore 
449fd385855SPaul Moore 	if (protos_sent == 0) {
450fd385855SPaul Moore 		if (netlbl_mgmt_protocols_cb(skb,
451fd385855SPaul Moore 					     cb,
452fd385855SPaul Moore 					     NETLBL_NLTYPE_UNLABELED) < 0)
453fd385855SPaul Moore 			goto protocols_return;
454fd385855SPaul Moore 		protos_sent++;
455fd385855SPaul Moore 	}
456fd385855SPaul Moore 	if (protos_sent == 1) {
457fd385855SPaul Moore 		if (netlbl_mgmt_protocols_cb(skb,
458fd385855SPaul Moore 					     cb,
459fd385855SPaul Moore 					     NETLBL_NLTYPE_CIPSOV4) < 0)
460fd385855SPaul Moore 			goto protocols_return;
461fd385855SPaul Moore 		protos_sent++;
462fd385855SPaul Moore 	}
463fd385855SPaul Moore 
464fd385855SPaul Moore protocols_return:
465fd385855SPaul Moore 	cb->args[0] = protos_sent;
466fd385855SPaul Moore 	return skb->len;
467fd385855SPaul Moore }
468fd385855SPaul Moore 
469fd385855SPaul Moore /**
470d15c345fSPaul Moore  * netlbl_mgmt_version - Handle a VERSION message
471d15c345fSPaul Moore  * @skb: the NETLINK buffer
472d15c345fSPaul Moore  * @info: the Generic NETLINK info block
473d15c345fSPaul Moore  *
474d15c345fSPaul Moore  * Description:
475d15c345fSPaul Moore  * Process a user generated VERSION message and respond accordingly.  Returns
476d15c345fSPaul Moore  * zero on success, negative values on failure.
477d15c345fSPaul Moore  *
478d15c345fSPaul Moore  */
479d15c345fSPaul Moore static int netlbl_mgmt_version(struct sk_buff *skb, struct genl_info *info)
480d15c345fSPaul Moore {
481d15c345fSPaul Moore 	int ret_val = -ENOMEM;
482d15c345fSPaul Moore 	struct sk_buff *ans_skb = NULL;
483fd385855SPaul Moore 	void *data;
484d15c345fSPaul Moore 
485339bf98fSThomas Graf 	ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
486d15c345fSPaul Moore 	if (ans_skb == NULL)
487fd385855SPaul Moore 		return -ENOMEM;
48817c157c8SThomas Graf 	data = genlmsg_put_reply(ans_skb, info, &netlbl_mgmt_gnl_family,
48917c157c8SThomas Graf 				 0, NLBL_MGMT_C_VERSION);
490fd385855SPaul Moore 	if (data == NULL)
491d15c345fSPaul Moore 		goto version_failure;
492d15c345fSPaul Moore 
493fd385855SPaul Moore 	ret_val = nla_put_u32(ans_skb,
494fd385855SPaul Moore 			      NLBL_MGMT_A_VERSION,
495fd385855SPaul Moore 			      NETLBL_PROTO_VERSION);
496d15c345fSPaul Moore 	if (ret_val != 0)
497d15c345fSPaul Moore 		goto version_failure;
498d15c345fSPaul Moore 
499fd385855SPaul Moore 	genlmsg_end(ans_skb, data);
500fd385855SPaul Moore 
50181878d27SThomas Graf 	ret_val = genlmsg_reply(ans_skb, info);
502d15c345fSPaul Moore 	if (ret_val != 0)
503d15c345fSPaul Moore 		goto version_failure;
504d15c345fSPaul Moore 	return 0;
505d15c345fSPaul Moore 
506d15c345fSPaul Moore version_failure:
507d15c345fSPaul Moore 	kfree_skb(ans_skb);
508d15c345fSPaul Moore 	return ret_val;
509d15c345fSPaul Moore }
510d15c345fSPaul Moore 
511d15c345fSPaul Moore 
512d15c345fSPaul Moore /*
513d15c345fSPaul Moore  * NetLabel Generic NETLINK Command Definitions
514d15c345fSPaul Moore  */
515d15c345fSPaul Moore 
516d15c345fSPaul Moore static struct genl_ops netlbl_mgmt_genl_c_add = {
517d15c345fSPaul Moore 	.cmd = NLBL_MGMT_C_ADD,
518fd385855SPaul Moore 	.flags = GENL_ADMIN_PERM,
519fd385855SPaul Moore 	.policy = netlbl_mgmt_genl_policy,
520d15c345fSPaul Moore 	.doit = netlbl_mgmt_add,
521d15c345fSPaul Moore 	.dumpit = NULL,
522d15c345fSPaul Moore };
523d15c345fSPaul Moore 
524d15c345fSPaul Moore static struct genl_ops netlbl_mgmt_genl_c_remove = {
525d15c345fSPaul Moore 	.cmd = NLBL_MGMT_C_REMOVE,
526fd385855SPaul Moore 	.flags = GENL_ADMIN_PERM,
527fd385855SPaul Moore 	.policy = netlbl_mgmt_genl_policy,
528d15c345fSPaul Moore 	.doit = netlbl_mgmt_remove,
529d15c345fSPaul Moore 	.dumpit = NULL,
530d15c345fSPaul Moore };
531d15c345fSPaul Moore 
532fd385855SPaul Moore static struct genl_ops netlbl_mgmt_genl_c_listall = {
533fd385855SPaul Moore 	.cmd = NLBL_MGMT_C_LISTALL,
534d15c345fSPaul Moore 	.flags = 0,
535fd385855SPaul Moore 	.policy = netlbl_mgmt_genl_policy,
536fd385855SPaul Moore 	.doit = NULL,
537fd385855SPaul Moore 	.dumpit = netlbl_mgmt_listall,
538d15c345fSPaul Moore };
539d15c345fSPaul Moore 
540d15c345fSPaul Moore static struct genl_ops netlbl_mgmt_genl_c_adddef = {
541d15c345fSPaul Moore 	.cmd = NLBL_MGMT_C_ADDDEF,
542fd385855SPaul Moore 	.flags = GENL_ADMIN_PERM,
543fd385855SPaul Moore 	.policy = netlbl_mgmt_genl_policy,
544d15c345fSPaul Moore 	.doit = netlbl_mgmt_adddef,
545d15c345fSPaul Moore 	.dumpit = NULL,
546d15c345fSPaul Moore };
547d15c345fSPaul Moore 
548d15c345fSPaul Moore static struct genl_ops netlbl_mgmt_genl_c_removedef = {
549d15c345fSPaul Moore 	.cmd = NLBL_MGMT_C_REMOVEDEF,
550fd385855SPaul Moore 	.flags = GENL_ADMIN_PERM,
551fd385855SPaul Moore 	.policy = netlbl_mgmt_genl_policy,
552d15c345fSPaul Moore 	.doit = netlbl_mgmt_removedef,
553d15c345fSPaul Moore 	.dumpit = NULL,
554d15c345fSPaul Moore };
555d15c345fSPaul Moore 
556d15c345fSPaul Moore static struct genl_ops netlbl_mgmt_genl_c_listdef = {
557d15c345fSPaul Moore 	.cmd = NLBL_MGMT_C_LISTDEF,
558d15c345fSPaul Moore 	.flags = 0,
559fd385855SPaul Moore 	.policy = netlbl_mgmt_genl_policy,
560d15c345fSPaul Moore 	.doit = netlbl_mgmt_listdef,
561d15c345fSPaul Moore 	.dumpit = NULL,
562d15c345fSPaul Moore };
563d15c345fSPaul Moore 
564fd385855SPaul Moore static struct genl_ops netlbl_mgmt_genl_c_protocols = {
565fd385855SPaul Moore 	.cmd = NLBL_MGMT_C_PROTOCOLS,
566d15c345fSPaul Moore 	.flags = 0,
567fd385855SPaul Moore 	.policy = netlbl_mgmt_genl_policy,
568fd385855SPaul Moore 	.doit = NULL,
569fd385855SPaul Moore 	.dumpit = netlbl_mgmt_protocols,
570d15c345fSPaul Moore };
571d15c345fSPaul Moore 
572d15c345fSPaul Moore static struct genl_ops netlbl_mgmt_genl_c_version = {
573d15c345fSPaul Moore 	.cmd = NLBL_MGMT_C_VERSION,
574d15c345fSPaul Moore 	.flags = 0,
575fd385855SPaul Moore 	.policy = netlbl_mgmt_genl_policy,
576d15c345fSPaul Moore 	.doit = netlbl_mgmt_version,
577d15c345fSPaul Moore 	.dumpit = NULL,
578d15c345fSPaul Moore };
579d15c345fSPaul Moore 
580d15c345fSPaul Moore /*
581d15c345fSPaul Moore  * NetLabel Generic NETLINK Protocol Functions
582d15c345fSPaul Moore  */
583d15c345fSPaul Moore 
584d15c345fSPaul Moore /**
585d15c345fSPaul Moore  * netlbl_mgmt_genl_init - Register the NetLabel management component
586d15c345fSPaul Moore  *
587d15c345fSPaul Moore  * Description:
588d15c345fSPaul Moore  * Register the NetLabel management component with the Generic NETLINK
589d15c345fSPaul Moore  * mechanism.  Returns zero on success, negative values on failure.
590d15c345fSPaul Moore  *
591d15c345fSPaul Moore  */
592d15c345fSPaul Moore int netlbl_mgmt_genl_init(void)
593d15c345fSPaul Moore {
594d15c345fSPaul Moore 	int ret_val;
595d15c345fSPaul Moore 
596d15c345fSPaul Moore 	ret_val = genl_register_family(&netlbl_mgmt_gnl_family);
597d15c345fSPaul Moore 	if (ret_val != 0)
598d15c345fSPaul Moore 		return ret_val;
599d15c345fSPaul Moore 
600d15c345fSPaul Moore 	ret_val = genl_register_ops(&netlbl_mgmt_gnl_family,
601d15c345fSPaul Moore 				    &netlbl_mgmt_genl_c_add);
602d15c345fSPaul Moore 	if (ret_val != 0)
603d15c345fSPaul Moore 		return ret_val;
604d15c345fSPaul Moore 	ret_val = genl_register_ops(&netlbl_mgmt_gnl_family,
605d15c345fSPaul Moore 				    &netlbl_mgmt_genl_c_remove);
606d15c345fSPaul Moore 	if (ret_val != 0)
607d15c345fSPaul Moore 		return ret_val;
608d15c345fSPaul Moore 	ret_val = genl_register_ops(&netlbl_mgmt_gnl_family,
609fd385855SPaul Moore 				    &netlbl_mgmt_genl_c_listall);
610d15c345fSPaul Moore 	if (ret_val != 0)
611d15c345fSPaul Moore 		return ret_val;
612d15c345fSPaul Moore 	ret_val = genl_register_ops(&netlbl_mgmt_gnl_family,
613d15c345fSPaul Moore 				    &netlbl_mgmt_genl_c_adddef);
614d15c345fSPaul Moore 	if (ret_val != 0)
615d15c345fSPaul Moore 		return ret_val;
616d15c345fSPaul Moore 	ret_val = genl_register_ops(&netlbl_mgmt_gnl_family,
617d15c345fSPaul Moore 				    &netlbl_mgmt_genl_c_removedef);
618d15c345fSPaul Moore 	if (ret_val != 0)
619d15c345fSPaul Moore 		return ret_val;
620d15c345fSPaul Moore 	ret_val = genl_register_ops(&netlbl_mgmt_gnl_family,
621d15c345fSPaul Moore 				    &netlbl_mgmt_genl_c_listdef);
622d15c345fSPaul Moore 	if (ret_val != 0)
623d15c345fSPaul Moore 		return ret_val;
624d15c345fSPaul Moore 	ret_val = genl_register_ops(&netlbl_mgmt_gnl_family,
625fd385855SPaul Moore 				    &netlbl_mgmt_genl_c_protocols);
626d15c345fSPaul Moore 	if (ret_val != 0)
627d15c345fSPaul Moore 		return ret_val;
628d15c345fSPaul Moore 	ret_val = genl_register_ops(&netlbl_mgmt_gnl_family,
629d15c345fSPaul Moore 				    &netlbl_mgmt_genl_c_version);
630d15c345fSPaul Moore 	if (ret_val != 0)
631d15c345fSPaul Moore 		return ret_val;
632d15c345fSPaul Moore 
633d15c345fSPaul Moore 	return 0;
634d15c345fSPaul Moore }
635