xref: /openbmc/linux/net/netlabel/netlabel_mgmt.c (revision 95d4e6be)
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 */
62fd385855SPaul Moore static 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 
191fd385855SPaul Moore 	data = netlbl_netlink_hdr_put(cb_arg->skb,
192fd385855SPaul Moore 				      NETLINK_CB(cb_arg->nl_cb->skb).pid,
193fd385855SPaul Moore 				      cb_arg->seq,
194d15c345fSPaul Moore 				      netlbl_mgmt_gnl_family.id,
195fd385855SPaul Moore 				      NLM_F_MULTI,
196fd385855SPaul Moore 				      NLBL_MGMT_C_LISTALL);
197fd385855SPaul Moore 	if (data == NULL)
198fd385855SPaul Moore 		goto listall_cb_failure;
199fd385855SPaul Moore 
200fd385855SPaul Moore 	ret_val = nla_put_string(cb_arg->skb,
201fd385855SPaul Moore 				 NLBL_MGMT_A_DOMAIN,
202fd385855SPaul Moore 				 entry->domain);
203fd385855SPaul Moore 	if (ret_val != 0)
204fd385855SPaul Moore 		goto listall_cb_failure;
205fd385855SPaul Moore 	ret_val = nla_put_u32(cb_arg->skb, NLBL_MGMT_A_PROTOCOL, entry->type);
206fd385855SPaul Moore 	if (ret_val != 0)
207fd385855SPaul Moore 		goto listall_cb_failure;
208fd385855SPaul Moore 	switch (entry->type) {
209fd385855SPaul Moore 	case NETLBL_NLTYPE_CIPSOV4:
210fd385855SPaul Moore 		ret_val = nla_put_u32(cb_arg->skb,
211fd385855SPaul Moore 				      NLBL_MGMT_A_CV4DOI,
212fd385855SPaul Moore 				      entry->type_def.cipsov4->doi);
213fd385855SPaul Moore 		if (ret_val != 0)
214fd385855SPaul Moore 			goto listall_cb_failure;
215fd385855SPaul Moore 		break;
216fd385855SPaul Moore 	}
217fd385855SPaul Moore 
218fd385855SPaul Moore 	cb_arg->seq++;
219fd385855SPaul Moore 	return genlmsg_end(cb_arg->skb, data);
220fd385855SPaul Moore 
221fd385855SPaul Moore listall_cb_failure:
222fd385855SPaul Moore 	genlmsg_cancel(cb_arg->skb, data);
223d15c345fSPaul Moore 	return ret_val;
224d15c345fSPaul Moore }
225d15c345fSPaul Moore 
226d15c345fSPaul Moore /**
227fd385855SPaul Moore  * netlbl_mgmt_listall - Handle a LISTALL message
228d15c345fSPaul Moore  * @skb: the NETLINK buffer
229fd385855SPaul Moore  * @cb: the NETLINK callback
230d15c345fSPaul Moore  *
231d15c345fSPaul Moore  * Description:
232fd385855SPaul Moore  * Process a user generated LISTALL message and dumps the domain hash table in
233fd385855SPaul Moore  * a form suitable for use in a kernel generated LISTALL message.  Returns zero
234fd385855SPaul Moore  * on success, negative values on failure.
235d15c345fSPaul Moore  *
236d15c345fSPaul Moore  */
237fd385855SPaul Moore static int netlbl_mgmt_listall(struct sk_buff *skb,
238fd385855SPaul Moore 			       struct netlink_callback *cb)
239d15c345fSPaul Moore {
240fd385855SPaul Moore 	struct netlbl_domhsh_walk_arg cb_arg;
241fd385855SPaul Moore 	u32 skip_bkt = cb->args[0];
242fd385855SPaul Moore 	u32 skip_chain = cb->args[1];
243d15c345fSPaul Moore 
244fd385855SPaul Moore 	cb_arg.nl_cb = cb;
245fd385855SPaul Moore 	cb_arg.skb = skb;
246fd385855SPaul Moore 	cb_arg.seq = cb->nlh->nlmsg_seq;
247d15c345fSPaul Moore 
248fd385855SPaul Moore 	netlbl_domhsh_walk(&skip_bkt,
249fd385855SPaul Moore 			   &skip_chain,
250fd385855SPaul Moore 			   netlbl_mgmt_listall_cb,
251fd385855SPaul Moore 			   &cb_arg);
252d15c345fSPaul Moore 
253fd385855SPaul Moore 	cb->args[0] = skip_bkt;
254fd385855SPaul Moore 	cb->args[1] = skip_chain;
255fd385855SPaul Moore 	return skb->len;
256d15c345fSPaul Moore }
257d15c345fSPaul Moore 
258d15c345fSPaul Moore /**
259d15c345fSPaul Moore  * netlbl_mgmt_adddef - Handle an ADDDEF message
260d15c345fSPaul Moore  * @skb: the NETLINK buffer
261d15c345fSPaul Moore  * @info: the Generic NETLINK info block
262d15c345fSPaul Moore  *
263d15c345fSPaul Moore  * Description:
264d15c345fSPaul Moore  * Process a user generated ADDDEF message and respond accordingly.  Returns
265d15c345fSPaul Moore  * zero on success, negative values on failure.
266d15c345fSPaul Moore  *
267d15c345fSPaul Moore  */
268d15c345fSPaul Moore static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info)
269d15c345fSPaul Moore {
270d15c345fSPaul Moore 	int ret_val = -EINVAL;
271d15c345fSPaul Moore 	struct netlbl_dom_map *entry = NULL;
272d15c345fSPaul Moore 	u32 tmp_val;
27395d4e6beSPaul Moore 	struct netlbl_audit audit_info;
274d15c345fSPaul Moore 
275fd385855SPaul Moore 	if (!info->attrs[NLBL_MGMT_A_PROTOCOL])
276d15c345fSPaul Moore 		goto adddef_failure;
277d15c345fSPaul Moore 
27895d4e6beSPaul Moore 	netlbl_netlink_auditinfo(skb, &audit_info);
27995d4e6beSPaul Moore 
280d15c345fSPaul Moore 	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
281d15c345fSPaul Moore 	if (entry == NULL) {
282d15c345fSPaul Moore 		ret_val = -ENOMEM;
283d15c345fSPaul Moore 		goto adddef_failure;
284d15c345fSPaul Moore 	}
285fd385855SPaul Moore 	entry->type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]);
286d15c345fSPaul Moore 
287d15c345fSPaul Moore 	switch (entry->type) {
288d15c345fSPaul Moore 	case NETLBL_NLTYPE_UNLABELED:
28995d4e6beSPaul Moore 		ret_val = netlbl_domhsh_add_default(entry, &audit_info);
290d15c345fSPaul Moore 		break;
291d15c345fSPaul Moore 	case NETLBL_NLTYPE_CIPSOV4:
292fd385855SPaul Moore 		if (!info->attrs[NLBL_MGMT_A_CV4DOI])
293d15c345fSPaul Moore 			goto adddef_failure;
294fd385855SPaul Moore 
295fd385855SPaul Moore 		tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]);
296fd385855SPaul Moore 		/* We should be holding a rcu_read_lock() here while we hold
297fd385855SPaul Moore 		 * the result but since the entry will always be deleted when
298fd385855SPaul Moore 		 * the CIPSO DOI is deleted we aren't going to keep the
299fd385855SPaul Moore 		 * lock. */
300d15c345fSPaul Moore 		rcu_read_lock();
301d15c345fSPaul Moore 		entry->type_def.cipsov4 = cipso_v4_doi_getdef(tmp_val);
302d15c345fSPaul Moore 		if (entry->type_def.cipsov4 == NULL) {
303d15c345fSPaul Moore 			rcu_read_unlock();
304d15c345fSPaul Moore 			goto adddef_failure;
305d15c345fSPaul Moore 		}
30695d4e6beSPaul Moore 		ret_val = netlbl_domhsh_add_default(entry, &audit_info);
307d15c345fSPaul Moore 		rcu_read_unlock();
308d15c345fSPaul Moore 		break;
309d15c345fSPaul Moore 	default:
310fd385855SPaul Moore 		goto adddef_failure;
311d15c345fSPaul Moore 	}
312d15c345fSPaul Moore 	if (ret_val != 0)
313d15c345fSPaul Moore 		goto adddef_failure;
314d15c345fSPaul Moore 
315d15c345fSPaul Moore 	return 0;
316d15c345fSPaul Moore 
317d15c345fSPaul Moore adddef_failure:
318d15c345fSPaul Moore 	kfree(entry);
319d15c345fSPaul Moore 	return ret_val;
320d15c345fSPaul Moore }
321d15c345fSPaul Moore 
322d15c345fSPaul Moore /**
323d15c345fSPaul Moore  * netlbl_mgmt_removedef - Handle a REMOVEDEF message
324d15c345fSPaul Moore  * @skb: the NETLINK buffer
325d15c345fSPaul Moore  * @info: the Generic NETLINK info block
326d15c345fSPaul Moore  *
327d15c345fSPaul Moore  * Description:
328d15c345fSPaul Moore  * Process a user generated REMOVEDEF message and remove the default domain
329d15c345fSPaul Moore  * mapping.  Returns zero on success, negative values on failure.
330d15c345fSPaul Moore  *
331d15c345fSPaul Moore  */
332d15c345fSPaul Moore static int netlbl_mgmt_removedef(struct sk_buff *skb, struct genl_info *info)
333d15c345fSPaul Moore {
33495d4e6beSPaul Moore 	struct netlbl_audit audit_info;
33595d4e6beSPaul Moore 
33695d4e6beSPaul Moore 	netlbl_netlink_auditinfo(skb, &audit_info);
33795d4e6beSPaul Moore 
33895d4e6beSPaul Moore 	return netlbl_domhsh_remove_default(&audit_info);
339d15c345fSPaul Moore }
340d15c345fSPaul Moore 
341d15c345fSPaul Moore /**
342d15c345fSPaul Moore  * netlbl_mgmt_listdef - Handle a LISTDEF message
343d15c345fSPaul Moore  * @skb: the NETLINK buffer
344d15c345fSPaul Moore  * @info: the Generic NETLINK info block
345d15c345fSPaul Moore  *
346d15c345fSPaul Moore  * Description:
347d15c345fSPaul Moore  * Process a user generated LISTDEF message and dumps the default domain
348d15c345fSPaul Moore  * mapping in a form suitable for use in a kernel generated LISTDEF message.
349d15c345fSPaul Moore  * Returns zero on success, negative values on failure.
350d15c345fSPaul Moore  *
351d15c345fSPaul Moore  */
352d15c345fSPaul Moore static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info)
353d15c345fSPaul Moore {
354d15c345fSPaul Moore 	int ret_val = -ENOMEM;
355fd385855SPaul Moore 	struct sk_buff *ans_skb = NULL;
356fd385855SPaul Moore 	void *data;
357fd385855SPaul Moore 	struct netlbl_dom_map *entry;
358d15c345fSPaul Moore 
359fd385855SPaul Moore 	ans_skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
360d15c345fSPaul Moore 	if (ans_skb == NULL)
361fd385855SPaul Moore 		return -ENOMEM;
362fd385855SPaul Moore 	data = netlbl_netlink_hdr_put(ans_skb,
363d15c345fSPaul Moore 				      info->snd_pid,
364fd385855SPaul Moore 				      info->snd_seq,
365d15c345fSPaul Moore 				      netlbl_mgmt_gnl_family.id,
366fd385855SPaul Moore 				      0,
367d15c345fSPaul Moore 				      NLBL_MGMT_C_LISTDEF);
368fd385855SPaul Moore 	if (data == NULL)
369fd385855SPaul Moore 		goto listdef_failure;
370d15c345fSPaul Moore 
371fd385855SPaul Moore 	rcu_read_lock();
372fd385855SPaul Moore 	entry = netlbl_domhsh_getentry(NULL);
373fd385855SPaul Moore 	if (entry == NULL) {
374fd385855SPaul Moore 		ret_val = -ENOENT;
375fd385855SPaul Moore 		goto listdef_failure_lock;
376fd385855SPaul Moore 	}
377fd385855SPaul Moore 	ret_val = nla_put_u32(ans_skb, NLBL_MGMT_A_PROTOCOL, entry->type);
378fd385855SPaul Moore 	if (ret_val != 0)
379fd385855SPaul Moore 		goto listdef_failure_lock;
380fd385855SPaul Moore 	switch (entry->type) {
381fd385855SPaul Moore 	case NETLBL_NLTYPE_CIPSOV4:
382fd385855SPaul Moore 		ret_val = nla_put_u32(ans_skb,
383fd385855SPaul Moore 				      NLBL_MGMT_A_CV4DOI,
384fd385855SPaul Moore 				      entry->type_def.cipsov4->doi);
385fd385855SPaul Moore 		if (ret_val != 0)
386fd385855SPaul Moore 			goto listdef_failure_lock;
387fd385855SPaul Moore 		break;
388fd385855SPaul Moore 	}
389fd385855SPaul Moore 	rcu_read_unlock();
390fd385855SPaul Moore 
391fd385855SPaul Moore 	genlmsg_end(ans_skb, data);
392fd385855SPaul Moore 
393fd385855SPaul Moore 	ret_val = genlmsg_unicast(ans_skb, info->snd_pid);
394d15c345fSPaul Moore 	if (ret_val != 0)
395d15c345fSPaul Moore 		goto listdef_failure;
396d15c345fSPaul Moore 	return 0;
397d15c345fSPaul Moore 
398fd385855SPaul Moore listdef_failure_lock:
399fd385855SPaul Moore 	rcu_read_unlock();
400d15c345fSPaul Moore listdef_failure:
401fd385855SPaul Moore 	kfree_skb(ans_skb);
402d15c345fSPaul Moore 	return ret_val;
403d15c345fSPaul Moore }
404d15c345fSPaul Moore 
405d15c345fSPaul Moore /**
406fd385855SPaul Moore  * netlbl_mgmt_protocols_cb - Write an individual PROTOCOL message response
407fd385855SPaul Moore  * @skb: the skb to write to
408fd385855SPaul Moore  * @seq: the NETLINK sequence number
409fd385855SPaul Moore  * @cb: the NETLINK callback
410fd385855SPaul Moore  * @protocol: the NetLabel protocol to use in the message
411d15c345fSPaul Moore  *
412d15c345fSPaul Moore  * Description:
413fd385855SPaul Moore  * This function is to be used in conjunction with netlbl_mgmt_protocols() to
414fd385855SPaul Moore  * answer a application's PROTOCOLS message.  Returns the size of the message
415fd385855SPaul Moore  * on success, negative values on failure.
416d15c345fSPaul Moore  *
417d15c345fSPaul Moore  */
418fd385855SPaul Moore static int netlbl_mgmt_protocols_cb(struct sk_buff *skb,
419fd385855SPaul Moore 				    struct netlink_callback *cb,
420fd385855SPaul Moore 				    u32 protocol)
421d15c345fSPaul Moore {
422d15c345fSPaul Moore 	int ret_val = -ENOMEM;
423fd385855SPaul Moore 	void *data;
424d15c345fSPaul Moore 
425fd385855SPaul Moore 	data = netlbl_netlink_hdr_put(skb,
426fd385855SPaul Moore 				      NETLINK_CB(cb->skb).pid,
427fd385855SPaul Moore 				      cb->nlh->nlmsg_seq,
428d15c345fSPaul Moore 				      netlbl_mgmt_gnl_family.id,
429fd385855SPaul Moore 				      NLM_F_MULTI,
430fd385855SPaul Moore 				      NLBL_MGMT_C_PROTOCOLS);
431fd385855SPaul Moore 	if (data == NULL)
432fd385855SPaul Moore 		goto protocols_cb_failure;
433d15c345fSPaul Moore 
434fd385855SPaul Moore 	ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, protocol);
435d15c345fSPaul Moore 	if (ret_val != 0)
436fd385855SPaul Moore 		goto protocols_cb_failure;
437d15c345fSPaul Moore 
438fd385855SPaul Moore 	return genlmsg_end(skb, data);
439d15c345fSPaul Moore 
440fd385855SPaul Moore protocols_cb_failure:
441fd385855SPaul Moore 	genlmsg_cancel(skb, data);
442d15c345fSPaul Moore 	return ret_val;
443d15c345fSPaul Moore }
444d15c345fSPaul Moore 
445d15c345fSPaul Moore /**
446fd385855SPaul Moore  * netlbl_mgmt_protocols - Handle a PROTOCOLS message
447fd385855SPaul Moore  * @skb: the NETLINK buffer
448fd385855SPaul Moore  * @cb: the NETLINK callback
449fd385855SPaul Moore  *
450fd385855SPaul Moore  * Description:
451fd385855SPaul Moore  * Process a user generated PROTOCOLS message and respond accordingly.
452fd385855SPaul Moore  *
453fd385855SPaul Moore  */
454fd385855SPaul Moore static int netlbl_mgmt_protocols(struct sk_buff *skb,
455fd385855SPaul Moore 				 struct netlink_callback *cb)
456fd385855SPaul Moore {
457fd385855SPaul Moore 	u32 protos_sent = cb->args[0];
458fd385855SPaul Moore 
459fd385855SPaul Moore 	if (protos_sent == 0) {
460fd385855SPaul Moore 		if (netlbl_mgmt_protocols_cb(skb,
461fd385855SPaul Moore 					     cb,
462fd385855SPaul Moore 					     NETLBL_NLTYPE_UNLABELED) < 0)
463fd385855SPaul Moore 			goto protocols_return;
464fd385855SPaul Moore 		protos_sent++;
465fd385855SPaul Moore 	}
466fd385855SPaul Moore 	if (protos_sent == 1) {
467fd385855SPaul Moore 		if (netlbl_mgmt_protocols_cb(skb,
468fd385855SPaul Moore 					     cb,
469fd385855SPaul Moore 					     NETLBL_NLTYPE_CIPSOV4) < 0)
470fd385855SPaul Moore 			goto protocols_return;
471fd385855SPaul Moore 		protos_sent++;
472fd385855SPaul Moore 	}
473fd385855SPaul Moore 
474fd385855SPaul Moore protocols_return:
475fd385855SPaul Moore 	cb->args[0] = protos_sent;
476fd385855SPaul Moore 	return skb->len;
477fd385855SPaul Moore }
478fd385855SPaul Moore 
479fd385855SPaul Moore /**
480d15c345fSPaul Moore  * netlbl_mgmt_version - Handle a VERSION message
481d15c345fSPaul Moore  * @skb: the NETLINK buffer
482d15c345fSPaul Moore  * @info: the Generic NETLINK info block
483d15c345fSPaul Moore  *
484d15c345fSPaul Moore  * Description:
485d15c345fSPaul Moore  * Process a user generated VERSION message and respond accordingly.  Returns
486d15c345fSPaul Moore  * zero on success, negative values on failure.
487d15c345fSPaul Moore  *
488d15c345fSPaul Moore  */
489d15c345fSPaul Moore static int netlbl_mgmt_version(struct sk_buff *skb, struct genl_info *info)
490d15c345fSPaul Moore {
491d15c345fSPaul Moore 	int ret_val = -ENOMEM;
492d15c345fSPaul Moore 	struct sk_buff *ans_skb = NULL;
493fd385855SPaul Moore 	void *data;
494d15c345fSPaul Moore 
495fd385855SPaul Moore 	ans_skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
496d15c345fSPaul Moore 	if (ans_skb == NULL)
497fd385855SPaul Moore 		return -ENOMEM;
498fd385855SPaul Moore 	data = netlbl_netlink_hdr_put(ans_skb,
499d15c345fSPaul Moore 				      info->snd_pid,
500fd385855SPaul Moore 				      info->snd_seq,
501d15c345fSPaul Moore 				      netlbl_mgmt_gnl_family.id,
502fd385855SPaul Moore 				      0,
503fd385855SPaul Moore 				      NLBL_MGMT_C_VERSION);
504fd385855SPaul Moore 	if (data == NULL)
505d15c345fSPaul Moore 		goto version_failure;
506d15c345fSPaul Moore 
507fd385855SPaul Moore 	ret_val = nla_put_u32(ans_skb,
508fd385855SPaul Moore 			      NLBL_MGMT_A_VERSION,
509fd385855SPaul Moore 			      NETLBL_PROTO_VERSION);
510d15c345fSPaul Moore 	if (ret_val != 0)
511d15c345fSPaul Moore 		goto version_failure;
512d15c345fSPaul Moore 
513fd385855SPaul Moore 	genlmsg_end(ans_skb, data);
514fd385855SPaul Moore 
515fd385855SPaul Moore 	ret_val = genlmsg_unicast(ans_skb, info->snd_pid);
516d15c345fSPaul Moore 	if (ret_val != 0)
517d15c345fSPaul Moore 		goto version_failure;
518d15c345fSPaul Moore 	return 0;
519d15c345fSPaul Moore 
520d15c345fSPaul Moore version_failure:
521d15c345fSPaul Moore 	kfree_skb(ans_skb);
522d15c345fSPaul Moore 	return ret_val;
523d15c345fSPaul Moore }
524d15c345fSPaul Moore 
525d15c345fSPaul Moore 
526d15c345fSPaul Moore /*
527d15c345fSPaul Moore  * NetLabel Generic NETLINK Command Definitions
528d15c345fSPaul Moore  */
529d15c345fSPaul Moore 
530d15c345fSPaul Moore static struct genl_ops netlbl_mgmt_genl_c_add = {
531d15c345fSPaul Moore 	.cmd = NLBL_MGMT_C_ADD,
532fd385855SPaul Moore 	.flags = GENL_ADMIN_PERM,
533fd385855SPaul Moore 	.policy = netlbl_mgmt_genl_policy,
534d15c345fSPaul Moore 	.doit = netlbl_mgmt_add,
535d15c345fSPaul Moore 	.dumpit = NULL,
536d15c345fSPaul Moore };
537d15c345fSPaul Moore 
538d15c345fSPaul Moore static struct genl_ops netlbl_mgmt_genl_c_remove = {
539d15c345fSPaul Moore 	.cmd = NLBL_MGMT_C_REMOVE,
540fd385855SPaul Moore 	.flags = GENL_ADMIN_PERM,
541fd385855SPaul Moore 	.policy = netlbl_mgmt_genl_policy,
542d15c345fSPaul Moore 	.doit = netlbl_mgmt_remove,
543d15c345fSPaul Moore 	.dumpit = NULL,
544d15c345fSPaul Moore };
545d15c345fSPaul Moore 
546fd385855SPaul Moore static struct genl_ops netlbl_mgmt_genl_c_listall = {
547fd385855SPaul Moore 	.cmd = NLBL_MGMT_C_LISTALL,
548d15c345fSPaul Moore 	.flags = 0,
549fd385855SPaul Moore 	.policy = netlbl_mgmt_genl_policy,
550fd385855SPaul Moore 	.doit = NULL,
551fd385855SPaul Moore 	.dumpit = netlbl_mgmt_listall,
552d15c345fSPaul Moore };
553d15c345fSPaul Moore 
554d15c345fSPaul Moore static struct genl_ops netlbl_mgmt_genl_c_adddef = {
555d15c345fSPaul Moore 	.cmd = NLBL_MGMT_C_ADDDEF,
556fd385855SPaul Moore 	.flags = GENL_ADMIN_PERM,
557fd385855SPaul Moore 	.policy = netlbl_mgmt_genl_policy,
558d15c345fSPaul Moore 	.doit = netlbl_mgmt_adddef,
559d15c345fSPaul Moore 	.dumpit = NULL,
560d15c345fSPaul Moore };
561d15c345fSPaul Moore 
562d15c345fSPaul Moore static struct genl_ops netlbl_mgmt_genl_c_removedef = {
563d15c345fSPaul Moore 	.cmd = NLBL_MGMT_C_REMOVEDEF,
564fd385855SPaul Moore 	.flags = GENL_ADMIN_PERM,
565fd385855SPaul Moore 	.policy = netlbl_mgmt_genl_policy,
566d15c345fSPaul Moore 	.doit = netlbl_mgmt_removedef,
567d15c345fSPaul Moore 	.dumpit = NULL,
568d15c345fSPaul Moore };
569d15c345fSPaul Moore 
570d15c345fSPaul Moore static struct genl_ops netlbl_mgmt_genl_c_listdef = {
571d15c345fSPaul Moore 	.cmd = NLBL_MGMT_C_LISTDEF,
572d15c345fSPaul Moore 	.flags = 0,
573fd385855SPaul Moore 	.policy = netlbl_mgmt_genl_policy,
574d15c345fSPaul Moore 	.doit = netlbl_mgmt_listdef,
575d15c345fSPaul Moore 	.dumpit = NULL,
576d15c345fSPaul Moore };
577d15c345fSPaul Moore 
578fd385855SPaul Moore static struct genl_ops netlbl_mgmt_genl_c_protocols = {
579fd385855SPaul Moore 	.cmd = NLBL_MGMT_C_PROTOCOLS,
580d15c345fSPaul Moore 	.flags = 0,
581fd385855SPaul Moore 	.policy = netlbl_mgmt_genl_policy,
582fd385855SPaul Moore 	.doit = NULL,
583fd385855SPaul Moore 	.dumpit = netlbl_mgmt_protocols,
584d15c345fSPaul Moore };
585d15c345fSPaul Moore 
586d15c345fSPaul Moore static struct genl_ops netlbl_mgmt_genl_c_version = {
587d15c345fSPaul Moore 	.cmd = NLBL_MGMT_C_VERSION,
588d15c345fSPaul Moore 	.flags = 0,
589fd385855SPaul Moore 	.policy = netlbl_mgmt_genl_policy,
590d15c345fSPaul Moore 	.doit = netlbl_mgmt_version,
591d15c345fSPaul Moore 	.dumpit = NULL,
592d15c345fSPaul Moore };
593d15c345fSPaul Moore 
594d15c345fSPaul Moore /*
595d15c345fSPaul Moore  * NetLabel Generic NETLINK Protocol Functions
596d15c345fSPaul Moore  */
597d15c345fSPaul Moore 
598d15c345fSPaul Moore /**
599d15c345fSPaul Moore  * netlbl_mgmt_genl_init - Register the NetLabel management component
600d15c345fSPaul Moore  *
601d15c345fSPaul Moore  * Description:
602d15c345fSPaul Moore  * Register the NetLabel management component with the Generic NETLINK
603d15c345fSPaul Moore  * mechanism.  Returns zero on success, negative values on failure.
604d15c345fSPaul Moore  *
605d15c345fSPaul Moore  */
606d15c345fSPaul Moore int netlbl_mgmt_genl_init(void)
607d15c345fSPaul Moore {
608d15c345fSPaul Moore 	int ret_val;
609d15c345fSPaul Moore 
610d15c345fSPaul Moore 	ret_val = genl_register_family(&netlbl_mgmt_gnl_family);
611d15c345fSPaul Moore 	if (ret_val != 0)
612d15c345fSPaul Moore 		return ret_val;
613d15c345fSPaul Moore 
614d15c345fSPaul Moore 	ret_val = genl_register_ops(&netlbl_mgmt_gnl_family,
615d15c345fSPaul Moore 				    &netlbl_mgmt_genl_c_add);
616d15c345fSPaul Moore 	if (ret_val != 0)
617d15c345fSPaul Moore 		return ret_val;
618d15c345fSPaul Moore 	ret_val = genl_register_ops(&netlbl_mgmt_gnl_family,
619d15c345fSPaul Moore 				    &netlbl_mgmt_genl_c_remove);
620d15c345fSPaul Moore 	if (ret_val != 0)
621d15c345fSPaul Moore 		return ret_val;
622d15c345fSPaul Moore 	ret_val = genl_register_ops(&netlbl_mgmt_gnl_family,
623fd385855SPaul Moore 				    &netlbl_mgmt_genl_c_listall);
624d15c345fSPaul Moore 	if (ret_val != 0)
625d15c345fSPaul Moore 		return ret_val;
626d15c345fSPaul Moore 	ret_val = genl_register_ops(&netlbl_mgmt_gnl_family,
627d15c345fSPaul Moore 				    &netlbl_mgmt_genl_c_adddef);
628d15c345fSPaul Moore 	if (ret_val != 0)
629d15c345fSPaul Moore 		return ret_val;
630d15c345fSPaul Moore 	ret_val = genl_register_ops(&netlbl_mgmt_gnl_family,
631d15c345fSPaul Moore 				    &netlbl_mgmt_genl_c_removedef);
632d15c345fSPaul Moore 	if (ret_val != 0)
633d15c345fSPaul Moore 		return ret_val;
634d15c345fSPaul Moore 	ret_val = genl_register_ops(&netlbl_mgmt_gnl_family,
635d15c345fSPaul Moore 				    &netlbl_mgmt_genl_c_listdef);
636d15c345fSPaul Moore 	if (ret_val != 0)
637d15c345fSPaul Moore 		return ret_val;
638d15c345fSPaul Moore 	ret_val = genl_register_ops(&netlbl_mgmt_gnl_family,
639fd385855SPaul Moore 				    &netlbl_mgmt_genl_c_protocols);
640d15c345fSPaul Moore 	if (ret_val != 0)
641d15c345fSPaul Moore 		return ret_val;
642d15c345fSPaul Moore 	ret_val = genl_register_ops(&netlbl_mgmt_gnl_family,
643d15c345fSPaul Moore 				    &netlbl_mgmt_genl_c_version);
644d15c345fSPaul Moore 	if (ret_val != 0)
645d15c345fSPaul Moore 		return ret_val;
646d15c345fSPaul Moore 
647d15c345fSPaul Moore 	return 0;
648d15c345fSPaul Moore }
649