blob: c6c8a101f2ff03eb643b53b29d742ffefd237d32 [file] [log] [blame]
Paul Moored15c3452006-08-03 16:48:37 -07001/*
2 * NetLabel Management Support
3 *
4 * This file defines the management functions for the NetLabel system. The
5 * NetLabel system manages static and dynamic label mappings for network
6 * protocols such as CIPSO and RIPSO.
7 *
Paul Moore82c21bf2011-08-01 11:10:33 +00008 * Author: Paul Moore <paul@paul-moore.com>
Paul Moored15c3452006-08-03 16:48:37 -07009 *
10 */
11
12/*
Paul Moore63c41682008-10-10 10:16:32 -040013 * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
Paul Moored15c3452006-08-03 16:48:37 -070014 *
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
23 * the GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
Jeff Kirsherd484ff12013-12-06 09:13:41 -080026 * along with this program; if not, see <http://www.gnu.org/licenses/>.
Paul Moored15c3452006-08-03 16:48:37 -070027 *
28 */
29
30#include <linux/types.h>
31#include <linux/socket.h>
32#include <linux/string.h>
33#include <linux/skbuff.h>
Paul Moore63c41682008-10-10 10:16:32 -040034#include <linux/in.h>
35#include <linux/in6.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090036#include <linux/slab.h>
Paul Moored15c3452006-08-03 16:48:37 -070037#include <net/sock.h>
38#include <net/netlink.h>
39#include <net/genetlink.h>
Paul Moore63c41682008-10-10 10:16:32 -040040#include <net/ip.h>
41#include <net/ipv6.h>
Paul Moored15c3452006-08-03 16:48:37 -070042#include <net/netlabel.h>
43#include <net/cipso_ipv4.h>
Huw Daviesdc7de732016-06-27 15:02:49 -040044#include <net/calipso.h>
Arun Sharma600634972011-07-26 16:09:06 -070045#include <linux/atomic.h>
Paul Moored15c3452006-08-03 16:48:37 -070046
Huw Daviesdc7de732016-06-27 15:02:49 -040047#include "netlabel_calipso.h"
Paul Moored15c3452006-08-03 16:48:37 -070048#include "netlabel_domainhash.h"
49#include "netlabel_user.h"
50#include "netlabel_mgmt.h"
51
Paul Moorec783f1c2008-01-29 08:37:52 -050052/* NetLabel configured protocol counter */
53atomic_t netlabel_mgmt_protocount = ATOMIC_INIT(0);
Paul Moore23bcdc12007-07-18 12:28:45 -040054
Paul Moorefd385852006-09-25 15:56:37 -070055/* Argument struct for netlbl_domhsh_walk() */
56struct netlbl_domhsh_walk_arg {
57 struct netlink_callback *nl_cb;
58 struct sk_buff *skb;
59 u32 seq;
60};
61
Paul Moored15c3452006-08-03 16:48:37 -070062/* NetLabel Generic NETLINK CIPSOv4 family */
Johannes Berg489111e2016-10-24 14:40:03 +020063static struct genl_family netlbl_mgmt_gnl_family;
Paul Moored15c3452006-08-03 16:48:37 -070064
Paul Moorefd385852006-09-25 15:56:37 -070065/* NetLabel Netlink attribute policy */
Patrick McHardyef7c79e2007-06-05 12:38:30 -070066static const struct nla_policy netlbl_mgmt_genl_policy[NLBL_MGMT_A_MAX + 1] = {
Paul Moorefd385852006-09-25 15:56:37 -070067 [NLBL_MGMT_A_DOMAIN] = { .type = NLA_NUL_STRING },
68 [NLBL_MGMT_A_PROTOCOL] = { .type = NLA_U32 },
69 [NLBL_MGMT_A_VERSION] = { .type = NLA_U32 },
70 [NLBL_MGMT_A_CV4DOI] = { .type = NLA_U32 },
Huw Davies8f18e672016-06-27 15:02:46 -040071 [NLBL_MGMT_A_FAMILY] = { .type = NLA_U16 },
Huw Daviesdc7de732016-06-27 15:02:49 -040072 [NLBL_MGMT_A_CLPDOI] = { .type = NLA_U32 },
Paul Moorefd385852006-09-25 15:56:37 -070073};
Paul Moored15c3452006-08-03 16:48:37 -070074
75/*
Paul Moore63c41682008-10-10 10:16:32 -040076 * Helper Functions
77 */
78
79/**
80 * netlbl_mgmt_add - Handle an ADD message
81 * @info: the Generic NETLINK info block
82 * @audit_info: NetLabel audit information
83 *
84 * Description:
85 * Helper function for the ADD and ADDDEF messages to add the domain mappings
86 * from the message to the hash table. See netlabel.h for a description of the
87 * message format. Returns zero on success, negative values on failure.
88 *
89 */
90static int netlbl_mgmt_add_common(struct genl_info *info,
91 struct netlbl_audit *audit_info)
92{
93 int ret_val = -EINVAL;
Paul Moore63c41682008-10-10 10:16:32 -040094 struct netlbl_domaddr_map *addrmap = NULL;
95 struct cipso_v4_doi *cipsov4 = NULL;
Huw Daviesdc7de732016-06-27 15:02:49 -040096#if IS_ENABLED(CONFIG_IPV6)
97 struct calipso_doi *calipso = NULL;
98#endif
Paul Moore63c41682008-10-10 10:16:32 -040099 u32 tmp_val;
Markus Elfring4de46d52015-02-02 11:00:24 +0100100 struct netlbl_dom_map *entry = kzalloc(sizeof(*entry), GFP_KERNEL);
Paul Moore63c41682008-10-10 10:16:32 -0400101
Markus Elfring4de46d52015-02-02 11:00:24 +0100102 if (!entry)
103 return -ENOMEM;
Paul Moore6a8b7f02013-08-02 14:45:08 -0400104 entry->def.type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]);
Paul Moore63c41682008-10-10 10:16:32 -0400105 if (info->attrs[NLBL_MGMT_A_DOMAIN]) {
106 size_t tmp_size = nla_len(info->attrs[NLBL_MGMT_A_DOMAIN]);
107 entry->domain = kmalloc(tmp_size, GFP_KERNEL);
108 if (entry->domain == NULL) {
109 ret_val = -ENOMEM;
Markus Elfring4de46d52015-02-02 11:00:24 +0100110 goto add_free_entry;
Paul Moore63c41682008-10-10 10:16:32 -0400111 }
112 nla_strlcpy(entry->domain,
113 info->attrs[NLBL_MGMT_A_DOMAIN], tmp_size);
114 }
115
Paul Moore6a8b7f02013-08-02 14:45:08 -0400116 /* NOTE: internally we allow/use a entry->def.type value of
Paul Moore63c41682008-10-10 10:16:32 -0400117 * NETLBL_NLTYPE_ADDRSELECT but we don't currently allow users
118 * to pass that as a protocol value because we need to know the
119 * "real" protocol */
120
Paul Moore6a8b7f02013-08-02 14:45:08 -0400121 switch (entry->def.type) {
Paul Moore63c41682008-10-10 10:16:32 -0400122 case NETLBL_NLTYPE_UNLABELED:
Huw Davies8f18e672016-06-27 15:02:46 -0400123 if (info->attrs[NLBL_MGMT_A_FAMILY])
124 entry->family =
125 nla_get_u16(info->attrs[NLBL_MGMT_A_FAMILY]);
126 else
127 entry->family = AF_UNSPEC;
Paul Moore63c41682008-10-10 10:16:32 -0400128 break;
129 case NETLBL_NLTYPE_CIPSOV4:
130 if (!info->attrs[NLBL_MGMT_A_CV4DOI])
Markus Elfring4de46d52015-02-02 11:00:24 +0100131 goto add_free_domain;
Paul Moore63c41682008-10-10 10:16:32 -0400132
133 tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]);
134 cipsov4 = cipso_v4_doi_getdef(tmp_val);
135 if (cipsov4 == NULL)
Markus Elfring4de46d52015-02-02 11:00:24 +0100136 goto add_free_domain;
Huw Davies8f18e672016-06-27 15:02:46 -0400137 entry->family = AF_INET;
Paul Moore6a8b7f02013-08-02 14:45:08 -0400138 entry->def.cipso = cipsov4;
Paul Moore63c41682008-10-10 10:16:32 -0400139 break;
Huw Daviesdc7de732016-06-27 15:02:49 -0400140#if IS_ENABLED(CONFIG_IPV6)
141 case NETLBL_NLTYPE_CALIPSO:
142 if (!info->attrs[NLBL_MGMT_A_CLPDOI])
143 goto add_free_domain;
144
145 tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CLPDOI]);
146 calipso = calipso_doi_getdef(tmp_val);
147 if (calipso == NULL)
148 goto add_free_domain;
149 entry->family = AF_INET6;
150 entry->def.calipso = calipso;
151 break;
152#endif /* IPv6 */
Paul Moore63c41682008-10-10 10:16:32 -0400153 default:
Markus Elfring4de46d52015-02-02 11:00:24 +0100154 goto add_free_domain;
Paul Moore63c41682008-10-10 10:16:32 -0400155 }
156
Huw Davies8f18e672016-06-27 15:02:46 -0400157 if ((entry->family == AF_INET && info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
158 (entry->family == AF_INET6 && info->attrs[NLBL_MGMT_A_IPV4ADDR]))
159 goto add_doi_put_def;
160
Paul Moore63c41682008-10-10 10:16:32 -0400161 if (info->attrs[NLBL_MGMT_A_IPV4ADDR]) {
162 struct in_addr *addr;
163 struct in_addr *mask;
164 struct netlbl_domaddr4_map *map;
165
166 addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL);
167 if (addrmap == NULL) {
168 ret_val = -ENOMEM;
Markus Elfring4de46d52015-02-02 11:00:24 +0100169 goto add_doi_put_def;
Paul Moore63c41682008-10-10 10:16:32 -0400170 }
171 INIT_LIST_HEAD(&addrmap->list4);
172 INIT_LIST_HEAD(&addrmap->list6);
173
174 if (nla_len(info->attrs[NLBL_MGMT_A_IPV4ADDR]) !=
175 sizeof(struct in_addr)) {
176 ret_val = -EINVAL;
Markus Elfring4de46d52015-02-02 11:00:24 +0100177 goto add_free_addrmap;
Paul Moore63c41682008-10-10 10:16:32 -0400178 }
179 if (nla_len(info->attrs[NLBL_MGMT_A_IPV4MASK]) !=
180 sizeof(struct in_addr)) {
181 ret_val = -EINVAL;
Markus Elfring4de46d52015-02-02 11:00:24 +0100182 goto add_free_addrmap;
Paul Moore63c41682008-10-10 10:16:32 -0400183 }
184 addr = nla_data(info->attrs[NLBL_MGMT_A_IPV4ADDR]);
185 mask = nla_data(info->attrs[NLBL_MGMT_A_IPV4MASK]);
186
187 map = kzalloc(sizeof(*map), GFP_KERNEL);
188 if (map == NULL) {
189 ret_val = -ENOMEM;
Markus Elfring4de46d52015-02-02 11:00:24 +0100190 goto add_free_addrmap;
Paul Moore63c41682008-10-10 10:16:32 -0400191 }
192 map->list.addr = addr->s_addr & mask->s_addr;
193 map->list.mask = mask->s_addr;
194 map->list.valid = 1;
Paul Moore6a8b7f02013-08-02 14:45:08 -0400195 map->def.type = entry->def.type;
Paul Moore63c41682008-10-10 10:16:32 -0400196 if (cipsov4)
Paul Moore6a8b7f02013-08-02 14:45:08 -0400197 map->def.cipso = cipsov4;
Paul Moore63c41682008-10-10 10:16:32 -0400198
199 ret_val = netlbl_af4list_add(&map->list, &addrmap->list4);
200 if (ret_val != 0) {
201 kfree(map);
Markus Elfring4de46d52015-02-02 11:00:24 +0100202 goto add_free_addrmap;
Paul Moore63c41682008-10-10 10:16:32 -0400203 }
204
Huw Davies8f18e672016-06-27 15:02:46 -0400205 entry->family = AF_INET;
Paul Moore6a8b7f02013-08-02 14:45:08 -0400206 entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
207 entry->def.addrsel = addrmap;
Eric Dumazetdfd56b82011-12-10 09:48:31 +0000208#if IS_ENABLED(CONFIG_IPV6)
Paul Moore63c41682008-10-10 10:16:32 -0400209 } else if (info->attrs[NLBL_MGMT_A_IPV6ADDR]) {
210 struct in6_addr *addr;
211 struct in6_addr *mask;
212 struct netlbl_domaddr6_map *map;
213
214 addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL);
215 if (addrmap == NULL) {
216 ret_val = -ENOMEM;
Markus Elfring4de46d52015-02-02 11:00:24 +0100217 goto add_doi_put_def;
Paul Moore63c41682008-10-10 10:16:32 -0400218 }
219 INIT_LIST_HEAD(&addrmap->list4);
220 INIT_LIST_HEAD(&addrmap->list6);
221
222 if (nla_len(info->attrs[NLBL_MGMT_A_IPV6ADDR]) !=
223 sizeof(struct in6_addr)) {
224 ret_val = -EINVAL;
Markus Elfring4de46d52015-02-02 11:00:24 +0100225 goto add_free_addrmap;
Paul Moore63c41682008-10-10 10:16:32 -0400226 }
227 if (nla_len(info->attrs[NLBL_MGMT_A_IPV6MASK]) !=
228 sizeof(struct in6_addr)) {
229 ret_val = -EINVAL;
Markus Elfring4de46d52015-02-02 11:00:24 +0100230 goto add_free_addrmap;
Paul Moore63c41682008-10-10 10:16:32 -0400231 }
232 addr = nla_data(info->attrs[NLBL_MGMT_A_IPV6ADDR]);
233 mask = nla_data(info->attrs[NLBL_MGMT_A_IPV6MASK]);
234
235 map = kzalloc(sizeof(*map), GFP_KERNEL);
236 if (map == NULL) {
237 ret_val = -ENOMEM;
Markus Elfring4de46d52015-02-02 11:00:24 +0100238 goto add_free_addrmap;
Paul Moore63c41682008-10-10 10:16:32 -0400239 }
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000240 map->list.addr = *addr;
Paul Moore63c41682008-10-10 10:16:32 -0400241 map->list.addr.s6_addr32[0] &= mask->s6_addr32[0];
242 map->list.addr.s6_addr32[1] &= mask->s6_addr32[1];
243 map->list.addr.s6_addr32[2] &= mask->s6_addr32[2];
244 map->list.addr.s6_addr32[3] &= mask->s6_addr32[3];
Alexey Dobriyan4e3fd7a2011-11-21 03:39:03 +0000245 map->list.mask = *mask;
Paul Moore63c41682008-10-10 10:16:32 -0400246 map->list.valid = 1;
Paul Moore6a8b7f02013-08-02 14:45:08 -0400247 map->def.type = entry->def.type;
Huw Daviesdc7de732016-06-27 15:02:49 -0400248 if (calipso)
249 map->def.calipso = calipso;
Paul Moore63c41682008-10-10 10:16:32 -0400250
251 ret_val = netlbl_af6list_add(&map->list, &addrmap->list6);
252 if (ret_val != 0) {
253 kfree(map);
Markus Elfring4de46d52015-02-02 11:00:24 +0100254 goto add_free_addrmap;
Paul Moore63c41682008-10-10 10:16:32 -0400255 }
256
Huw Davies8f18e672016-06-27 15:02:46 -0400257 entry->family = AF_INET6;
Paul Moore6a8b7f02013-08-02 14:45:08 -0400258 entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
259 entry->def.addrsel = addrmap;
Paul Moore63c41682008-10-10 10:16:32 -0400260#endif /* IPv6 */
261 }
262
263 ret_val = netlbl_domhsh_add(entry, audit_info);
264 if (ret_val != 0)
Markus Elfring4de46d52015-02-02 11:00:24 +0100265 goto add_free_addrmap;
Paul Moore63c41682008-10-10 10:16:32 -0400266
267 return 0;
268
Markus Elfring4de46d52015-02-02 11:00:24 +0100269add_free_addrmap:
Paul Moore63c41682008-10-10 10:16:32 -0400270 kfree(addrmap);
Markus Elfring4de46d52015-02-02 11:00:24 +0100271add_doi_put_def:
272 cipso_v4_doi_putdef(cipsov4);
Huw Daviesdc7de732016-06-27 15:02:49 -0400273#if IS_ENABLED(CONFIG_IPV6)
274 calipso_doi_putdef(calipso);
275#endif
Markus Elfring4de46d52015-02-02 11:00:24 +0100276add_free_domain:
277 kfree(entry->domain);
278add_free_entry:
Paul Moore63c41682008-10-10 10:16:32 -0400279 kfree(entry);
280 return ret_val;
281}
282
283/**
284 * netlbl_mgmt_listentry - List a NetLabel/LSM domain map entry
285 * @skb: the NETLINK buffer
286 * @entry: the map entry
287 *
288 * Description:
289 * This function is a helper function used by the LISTALL and LISTDEF command
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300290 * handlers. The caller is responsible for ensuring that the RCU read lock
Paul Moore63c41682008-10-10 10:16:32 -0400291 * is held. Returns zero on success, negative values on failure.
292 *
293 */
294static int netlbl_mgmt_listentry(struct sk_buff *skb,
295 struct netlbl_dom_map *entry)
296{
Paul Mooref8a02472008-10-29 16:09:12 -0400297 int ret_val = 0;
Paul Moore63c41682008-10-10 10:16:32 -0400298 struct nlattr *nla_a;
299 struct nlattr *nla_b;
300 struct netlbl_af4list *iter4;
Eric Dumazetdfd56b82011-12-10 09:48:31 +0000301#if IS_ENABLED(CONFIG_IPV6)
Paul Moore63c41682008-10-10 10:16:32 -0400302 struct netlbl_af6list *iter6;
303#endif
304
305 if (entry->domain != NULL) {
306 ret_val = nla_put_string(skb,
307 NLBL_MGMT_A_DOMAIN, entry->domain);
308 if (ret_val != 0)
309 return ret_val;
310 }
311
Huw Davies8f18e672016-06-27 15:02:46 -0400312 ret_val = nla_put_u16(skb, NLBL_MGMT_A_FAMILY, entry->family);
313 if (ret_val != 0)
314 return ret_val;
315
Paul Moore6a8b7f02013-08-02 14:45:08 -0400316 switch (entry->def.type) {
Paul Moore63c41682008-10-10 10:16:32 -0400317 case NETLBL_NLTYPE_ADDRSELECT:
Michal Kubecekae0be8d2019-04-26 11:13:06 +0200318 nla_a = nla_nest_start_noflag(skb, NLBL_MGMT_A_SELECTORLIST);
Paul Moore63c41682008-10-10 10:16:32 -0400319 if (nla_a == NULL)
320 return -ENOMEM;
321
Paul Moore6a8b7f02013-08-02 14:45:08 -0400322 netlbl_af4list_foreach_rcu(iter4, &entry->def.addrsel->list4) {
Paul Moore63c41682008-10-10 10:16:32 -0400323 struct netlbl_domaddr4_map *map4;
324 struct in_addr addr_struct;
325
Michal Kubecekae0be8d2019-04-26 11:13:06 +0200326 nla_b = nla_nest_start_noflag(skb,
327 NLBL_MGMT_A_ADDRSELECTOR);
Paul Moore63c41682008-10-10 10:16:32 -0400328 if (nla_b == NULL)
329 return -ENOMEM;
330
331 addr_struct.s_addr = iter4->addr;
Jiri Benc930345e2015-03-29 16:59:25 +0200332 ret_val = nla_put_in_addr(skb, NLBL_MGMT_A_IPV4ADDR,
333 addr_struct.s_addr);
Paul Moore63c41682008-10-10 10:16:32 -0400334 if (ret_val != 0)
335 return ret_val;
336 addr_struct.s_addr = iter4->mask;
Jiri Benc930345e2015-03-29 16:59:25 +0200337 ret_val = nla_put_in_addr(skb, NLBL_MGMT_A_IPV4MASK,
338 addr_struct.s_addr);
Paul Moore63c41682008-10-10 10:16:32 -0400339 if (ret_val != 0)
340 return ret_val;
341 map4 = netlbl_domhsh_addr4_entry(iter4);
342 ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
Paul Moore6a8b7f02013-08-02 14:45:08 -0400343 map4->def.type);
Paul Moore63c41682008-10-10 10:16:32 -0400344 if (ret_val != 0)
345 return ret_val;
Paul Moore6a8b7f02013-08-02 14:45:08 -0400346 switch (map4->def.type) {
Paul Moore63c41682008-10-10 10:16:32 -0400347 case NETLBL_NLTYPE_CIPSOV4:
348 ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI,
Paul Moore6a8b7f02013-08-02 14:45:08 -0400349 map4->def.cipso->doi);
Paul Moore63c41682008-10-10 10:16:32 -0400350 if (ret_val != 0)
351 return ret_val;
352 break;
353 }
354
355 nla_nest_end(skb, nla_b);
356 }
Eric Dumazetdfd56b82011-12-10 09:48:31 +0000357#if IS_ENABLED(CONFIG_IPV6)
Paul Moore6a8b7f02013-08-02 14:45:08 -0400358 netlbl_af6list_foreach_rcu(iter6, &entry->def.addrsel->list6) {
Paul Moore63c41682008-10-10 10:16:32 -0400359 struct netlbl_domaddr6_map *map6;
360
Michal Kubecekae0be8d2019-04-26 11:13:06 +0200361 nla_b = nla_nest_start_noflag(skb,
362 NLBL_MGMT_A_ADDRSELECTOR);
Paul Moore63c41682008-10-10 10:16:32 -0400363 if (nla_b == NULL)
364 return -ENOMEM;
365
Jiri Benc930345e2015-03-29 16:59:25 +0200366 ret_val = nla_put_in6_addr(skb, NLBL_MGMT_A_IPV6ADDR,
367 &iter6->addr);
Paul Moore63c41682008-10-10 10:16:32 -0400368 if (ret_val != 0)
369 return ret_val;
Jiri Benc930345e2015-03-29 16:59:25 +0200370 ret_val = nla_put_in6_addr(skb, NLBL_MGMT_A_IPV6MASK,
371 &iter6->mask);
Paul Moore63c41682008-10-10 10:16:32 -0400372 if (ret_val != 0)
373 return ret_val;
374 map6 = netlbl_domhsh_addr6_entry(iter6);
375 ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
Paul Moore6a8b7f02013-08-02 14:45:08 -0400376 map6->def.type);
Paul Moore63c41682008-10-10 10:16:32 -0400377 if (ret_val != 0)
378 return ret_val;
379
Huw Daviesdc7de732016-06-27 15:02:49 -0400380 switch (map6->def.type) {
381 case NETLBL_NLTYPE_CALIPSO:
382 ret_val = nla_put_u32(skb, NLBL_MGMT_A_CLPDOI,
383 map6->def.calipso->doi);
384 if (ret_val != 0)
385 return ret_val;
386 break;
387 }
388
Paul Moore63c41682008-10-10 10:16:32 -0400389 nla_nest_end(skb, nla_b);
390 }
391#endif /* IPv6 */
392
393 nla_nest_end(skb, nla_a);
394 break;
395 case NETLBL_NLTYPE_UNLABELED:
Huw Daviesdc7de732016-06-27 15:02:49 -0400396 ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
397 entry->def.type);
Paul Moore63c41682008-10-10 10:16:32 -0400398 break;
399 case NETLBL_NLTYPE_CIPSOV4:
Huw Daviesdc7de732016-06-27 15:02:49 -0400400 ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
401 entry->def.type);
Paul Moore63c41682008-10-10 10:16:32 -0400402 if (ret_val != 0)
403 return ret_val;
404 ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI,
Paul Moore6a8b7f02013-08-02 14:45:08 -0400405 entry->def.cipso->doi);
Paul Moore63c41682008-10-10 10:16:32 -0400406 break;
Huw Daviesdc7de732016-06-27 15:02:49 -0400407 case NETLBL_NLTYPE_CALIPSO:
408 ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
409 entry->def.type);
410 if (ret_val != 0)
411 return ret_val;
412 ret_val = nla_put_u32(skb, NLBL_MGMT_A_CLPDOI,
413 entry->def.calipso->doi);
414 break;
Paul Moore63c41682008-10-10 10:16:32 -0400415 }
416
417 return ret_val;
418}
419
420/*
Paul Moored15c3452006-08-03 16:48:37 -0700421 * NetLabel Command Handlers
422 */
423
424/**
425 * netlbl_mgmt_add - Handle an ADD message
426 * @skb: the NETLINK buffer
427 * @info: the Generic NETLINK info block
428 *
429 * Description:
430 * Process a user generated ADD message and add the domains from the message
431 * to the hash table. See netlabel.h for a description of the message format.
432 * Returns zero on success, negative values on failure.
433 *
434 */
435static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info)
436{
Paul Moore95d4e6b2006-09-29 17:05:05 -0700437 struct netlbl_audit audit_info;
Paul Moored15c3452006-08-03 16:48:37 -0700438
Paul Moore63c41682008-10-10 10:16:32 -0400439 if ((!info->attrs[NLBL_MGMT_A_DOMAIN]) ||
440 (!info->attrs[NLBL_MGMT_A_PROTOCOL]) ||
441 (info->attrs[NLBL_MGMT_A_IPV4ADDR] &&
442 info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
443 (info->attrs[NLBL_MGMT_A_IPV4MASK] &&
444 info->attrs[NLBL_MGMT_A_IPV6MASK]) ||
445 ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^
446 (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) ||
447 ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^
448 (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL)))
449 return -EINVAL;
Paul Moorefd385852006-09-25 15:56:37 -0700450
Paul Moore95d4e6b2006-09-29 17:05:05 -0700451 netlbl_netlink_auditinfo(skb, &audit_info);
452
Paul Moore63c41682008-10-10 10:16:32 -0400453 return netlbl_mgmt_add_common(info, &audit_info);
Paul Moored15c3452006-08-03 16:48:37 -0700454}
455
456/**
457 * netlbl_mgmt_remove - Handle a REMOVE message
458 * @skb: the NETLINK buffer
459 * @info: the Generic NETLINK info block
460 *
461 * Description:
462 * Process a user generated REMOVE message and remove the specified domain
463 * mappings. Returns zero on success, negative values on failure.
464 *
465 */
466static int netlbl_mgmt_remove(struct sk_buff *skb, struct genl_info *info)
467{
Paul Moorefd385852006-09-25 15:56:37 -0700468 char *domain;
Paul Moore95d4e6b2006-09-29 17:05:05 -0700469 struct netlbl_audit audit_info;
Paul Moored15c3452006-08-03 16:48:37 -0700470
Paul Moorefd385852006-09-25 15:56:37 -0700471 if (!info->attrs[NLBL_MGMT_A_DOMAIN])
472 return -EINVAL;
473
Paul Moore95d4e6b2006-09-29 17:05:05 -0700474 netlbl_netlink_auditinfo(skb, &audit_info);
475
Paul Moorefd385852006-09-25 15:56:37 -0700476 domain = nla_data(info->attrs[NLBL_MGMT_A_DOMAIN]);
Huw Davies8f18e672016-06-27 15:02:46 -0400477 return netlbl_domhsh_remove(domain, AF_UNSPEC, &audit_info);
Paul Moorefd385852006-09-25 15:56:37 -0700478}
479
480/**
481 * netlbl_mgmt_listall_cb - netlbl_domhsh_walk() callback for LISTALL
482 * @entry: the domain mapping hash table entry
483 * @arg: the netlbl_domhsh_walk_arg structure
484 *
485 * Description:
486 * This function is designed to be used as a callback to the
487 * netlbl_domhsh_walk() function for use in generating a response for a LISTALL
488 * message. Returns the size of the message on success, negative values on
489 * failure.
490 *
491 */
492static int netlbl_mgmt_listall_cb(struct netlbl_dom_map *entry, void *arg)
493{
494 int ret_val = -ENOMEM;
495 struct netlbl_domhsh_walk_arg *cb_arg = arg;
496 void *data;
497
Eric W. Biederman15e47302012-09-07 20:12:54 +0000498 data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).portid,
Thomas Graf17c157c2006-11-14 19:46:02 -0800499 cb_arg->seq, &netlbl_mgmt_gnl_family,
500 NLM_F_MULTI, NLBL_MGMT_C_LISTALL);
Paul Moorefd385852006-09-25 15:56:37 -0700501 if (data == NULL)
502 goto listall_cb_failure;
503
Paul Moore63c41682008-10-10 10:16:32 -0400504 ret_val = netlbl_mgmt_listentry(cb_arg->skb, entry);
Paul Moored15c3452006-08-03 16:48:37 -0700505 if (ret_val != 0)
Paul Moorefd385852006-09-25 15:56:37 -0700506 goto listall_cb_failure;
Paul Moored15c3452006-08-03 16:48:37 -0700507
Paul Moorefd385852006-09-25 15:56:37 -0700508 cb_arg->seq++;
Johannes Berg053c0952015-01-16 22:09:00 +0100509 genlmsg_end(cb_arg->skb, data);
510 return 0;
Paul Moored15c3452006-08-03 16:48:37 -0700511
Paul Moorefd385852006-09-25 15:56:37 -0700512listall_cb_failure:
513 genlmsg_cancel(cb_arg->skb, data);
Paul Moored15c3452006-08-03 16:48:37 -0700514 return ret_val;
515}
516
517/**
Paul Moorefd385852006-09-25 15:56:37 -0700518 * netlbl_mgmt_listall - Handle a LISTALL message
Paul Moored15c3452006-08-03 16:48:37 -0700519 * @skb: the NETLINK buffer
Paul Moorefd385852006-09-25 15:56:37 -0700520 * @cb: the NETLINK callback
Paul Moored15c3452006-08-03 16:48:37 -0700521 *
522 * Description:
Paul Moorefd385852006-09-25 15:56:37 -0700523 * Process a user generated LISTALL message and dumps the domain hash table in
524 * a form suitable for use in a kernel generated LISTALL message. Returns zero
525 * on success, negative values on failure.
Paul Moored15c3452006-08-03 16:48:37 -0700526 *
527 */
Paul Moorefd385852006-09-25 15:56:37 -0700528static int netlbl_mgmt_listall(struct sk_buff *skb,
529 struct netlink_callback *cb)
Paul Moored15c3452006-08-03 16:48:37 -0700530{
Paul Moorefd385852006-09-25 15:56:37 -0700531 struct netlbl_domhsh_walk_arg cb_arg;
532 u32 skip_bkt = cb->args[0];
533 u32 skip_chain = cb->args[1];
Paul Moored15c3452006-08-03 16:48:37 -0700534
Paul Moorefd385852006-09-25 15:56:37 -0700535 cb_arg.nl_cb = cb;
536 cb_arg.skb = skb;
537 cb_arg.seq = cb->nlh->nlmsg_seq;
Paul Moored15c3452006-08-03 16:48:37 -0700538
Paul Moorefd385852006-09-25 15:56:37 -0700539 netlbl_domhsh_walk(&skip_bkt,
540 &skip_chain,
541 netlbl_mgmt_listall_cb,
542 &cb_arg);
Paul Moored15c3452006-08-03 16:48:37 -0700543
Paul Moorefd385852006-09-25 15:56:37 -0700544 cb->args[0] = skip_bkt;
545 cb->args[1] = skip_chain;
546 return skb->len;
Paul Moored15c3452006-08-03 16:48:37 -0700547}
548
549/**
550 * netlbl_mgmt_adddef - Handle an ADDDEF message
551 * @skb: the NETLINK buffer
552 * @info: the Generic NETLINK info block
553 *
554 * Description:
555 * Process a user generated ADDDEF message and respond accordingly. Returns
556 * zero on success, negative values on failure.
557 *
558 */
559static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info)
560{
Paul Moore95d4e6b2006-09-29 17:05:05 -0700561 struct netlbl_audit audit_info;
Paul Moored15c3452006-08-03 16:48:37 -0700562
Paul Moore63c41682008-10-10 10:16:32 -0400563 if ((!info->attrs[NLBL_MGMT_A_PROTOCOL]) ||
564 (info->attrs[NLBL_MGMT_A_IPV4ADDR] &&
565 info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
566 (info->attrs[NLBL_MGMT_A_IPV4MASK] &&
567 info->attrs[NLBL_MGMT_A_IPV6MASK]) ||
568 ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^
569 (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) ||
570 ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^
571 (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL)))
572 return -EINVAL;
Paul Moored15c3452006-08-03 16:48:37 -0700573
Paul Moore95d4e6b2006-09-29 17:05:05 -0700574 netlbl_netlink_auditinfo(skb, &audit_info);
575
Paul Moore63c41682008-10-10 10:16:32 -0400576 return netlbl_mgmt_add_common(info, &audit_info);
Paul Moored15c3452006-08-03 16:48:37 -0700577}
578
579/**
580 * netlbl_mgmt_removedef - Handle a REMOVEDEF message
581 * @skb: the NETLINK buffer
582 * @info: the Generic NETLINK info block
583 *
584 * Description:
585 * Process a user generated REMOVEDEF message and remove the default domain
586 * mapping. Returns zero on success, negative values on failure.
587 *
588 */
589static int netlbl_mgmt_removedef(struct sk_buff *skb, struct genl_info *info)
590{
Paul Moore95d4e6b2006-09-29 17:05:05 -0700591 struct netlbl_audit audit_info;
592
593 netlbl_netlink_auditinfo(skb, &audit_info);
594
Huw Davies8f18e672016-06-27 15:02:46 -0400595 return netlbl_domhsh_remove_default(AF_UNSPEC, &audit_info);
Paul Moored15c3452006-08-03 16:48:37 -0700596}
597
598/**
599 * netlbl_mgmt_listdef - Handle a LISTDEF message
600 * @skb: the NETLINK buffer
601 * @info: the Generic NETLINK info block
602 *
603 * Description:
604 * Process a user generated LISTDEF message and dumps the default domain
605 * mapping in a form suitable for use in a kernel generated LISTDEF message.
606 * Returns zero on success, negative values on failure.
607 *
608 */
609static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info)
610{
611 int ret_val = -ENOMEM;
Paul Moorefd385852006-09-25 15:56:37 -0700612 struct sk_buff *ans_skb = NULL;
613 void *data;
614 struct netlbl_dom_map *entry;
Huw Davies8f18e672016-06-27 15:02:46 -0400615 u16 family;
616
617 if (info->attrs[NLBL_MGMT_A_FAMILY])
618 family = nla_get_u16(info->attrs[NLBL_MGMT_A_FAMILY]);
619 else
620 family = AF_INET;
Paul Moored15c3452006-08-03 16:48:37 -0700621
Thomas Graf339bf982006-11-10 14:10:15 -0800622 ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Paul Moored15c3452006-08-03 16:48:37 -0700623 if (ans_skb == NULL)
Paul Moorefd385852006-09-25 15:56:37 -0700624 return -ENOMEM;
Thomas Graf17c157c2006-11-14 19:46:02 -0800625 data = genlmsg_put_reply(ans_skb, info, &netlbl_mgmt_gnl_family,
626 0, NLBL_MGMT_C_LISTDEF);
Paul Moorefd385852006-09-25 15:56:37 -0700627 if (data == NULL)
Paul Moored15c3452006-08-03 16:48:37 -0700628 goto listdef_failure;
Paul Moored15c3452006-08-03 16:48:37 -0700629
Paul Moorefd385852006-09-25 15:56:37 -0700630 rcu_read_lock();
Huw Davies8f18e672016-06-27 15:02:46 -0400631 entry = netlbl_domhsh_getentry(NULL, family);
Paul Moorefd385852006-09-25 15:56:37 -0700632 if (entry == NULL) {
633 ret_val = -ENOENT;
634 goto listdef_failure_lock;
635 }
Paul Moore63c41682008-10-10 10:16:32 -0400636 ret_val = netlbl_mgmt_listentry(ans_skb, entry);
Paul Moorefd385852006-09-25 15:56:37 -0700637 rcu_read_unlock();
Paul Moore63c41682008-10-10 10:16:32 -0400638 if (ret_val != 0)
639 goto listdef_failure;
Paul Moorefd385852006-09-25 15:56:37 -0700640
641 genlmsg_end(ans_skb, data);
Denis V. Lunevfe785be2008-07-10 16:53:39 -0700642 return genlmsg_reply(ans_skb, info);
Paul Moored15c3452006-08-03 16:48:37 -0700643
Paul Moorefd385852006-09-25 15:56:37 -0700644listdef_failure_lock:
645 rcu_read_unlock();
Paul Moored15c3452006-08-03 16:48:37 -0700646listdef_failure:
Paul Moorefd385852006-09-25 15:56:37 -0700647 kfree_skb(ans_skb);
Paul Moored15c3452006-08-03 16:48:37 -0700648 return ret_val;
649}
650
651/**
Paul Moorefd385852006-09-25 15:56:37 -0700652 * netlbl_mgmt_protocols_cb - Write an individual PROTOCOL message response
653 * @skb: the skb to write to
Paul Moorefd385852006-09-25 15:56:37 -0700654 * @cb: the NETLINK callback
655 * @protocol: the NetLabel protocol to use in the message
Paul Moored15c3452006-08-03 16:48:37 -0700656 *
657 * Description:
Paul Moorefd385852006-09-25 15:56:37 -0700658 * This function is to be used in conjunction with netlbl_mgmt_protocols() to
659 * answer a application's PROTOCOLS message. Returns the size of the message
660 * on success, negative values on failure.
Paul Moored15c3452006-08-03 16:48:37 -0700661 *
662 */
Paul Moorefd385852006-09-25 15:56:37 -0700663static int netlbl_mgmt_protocols_cb(struct sk_buff *skb,
664 struct netlink_callback *cb,
665 u32 protocol)
Paul Moored15c3452006-08-03 16:48:37 -0700666{
667 int ret_val = -ENOMEM;
Paul Moorefd385852006-09-25 15:56:37 -0700668 void *data;
Paul Moored15c3452006-08-03 16:48:37 -0700669
Eric W. Biederman15e47302012-09-07 20:12:54 +0000670 data = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
Thomas Graf17c157c2006-11-14 19:46:02 -0800671 &netlbl_mgmt_gnl_family, NLM_F_MULTI,
672 NLBL_MGMT_C_PROTOCOLS);
Paul Moorefd385852006-09-25 15:56:37 -0700673 if (data == NULL)
674 goto protocols_cb_failure;
Paul Moored15c3452006-08-03 16:48:37 -0700675
Paul Moorefd385852006-09-25 15:56:37 -0700676 ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, protocol);
Paul Moored15c3452006-08-03 16:48:37 -0700677 if (ret_val != 0)
Paul Moorefd385852006-09-25 15:56:37 -0700678 goto protocols_cb_failure;
Paul Moored15c3452006-08-03 16:48:37 -0700679
Johannes Berg053c0952015-01-16 22:09:00 +0100680 genlmsg_end(skb, data);
681 return 0;
Paul Moored15c3452006-08-03 16:48:37 -0700682
Paul Moorefd385852006-09-25 15:56:37 -0700683protocols_cb_failure:
684 genlmsg_cancel(skb, data);
Paul Moored15c3452006-08-03 16:48:37 -0700685 return ret_val;
686}
687
688/**
Paul Moorefd385852006-09-25 15:56:37 -0700689 * netlbl_mgmt_protocols - Handle a PROTOCOLS message
690 * @skb: the NETLINK buffer
691 * @cb: the NETLINK callback
692 *
693 * Description:
694 * Process a user generated PROTOCOLS message and respond accordingly.
695 *
696 */
697static int netlbl_mgmt_protocols(struct sk_buff *skb,
698 struct netlink_callback *cb)
699{
700 u32 protos_sent = cb->args[0];
701
702 if (protos_sent == 0) {
703 if (netlbl_mgmt_protocols_cb(skb,
704 cb,
705 NETLBL_NLTYPE_UNLABELED) < 0)
706 goto protocols_return;
707 protos_sent++;
708 }
709 if (protos_sent == 1) {
710 if (netlbl_mgmt_protocols_cb(skb,
711 cb,
712 NETLBL_NLTYPE_CIPSOV4) < 0)
713 goto protocols_return;
714 protos_sent++;
715 }
Huw Daviescb72d382016-06-27 15:02:46 -0400716#if IS_ENABLED(CONFIG_IPV6)
717 if (protos_sent == 2) {
718 if (netlbl_mgmt_protocols_cb(skb,
719 cb,
720 NETLBL_NLTYPE_CALIPSO) < 0)
721 goto protocols_return;
722 protos_sent++;
723 }
724#endif
Paul Moorefd385852006-09-25 15:56:37 -0700725
726protocols_return:
727 cb->args[0] = protos_sent;
728 return skb->len;
729}
730
731/**
Paul Moored15c3452006-08-03 16:48:37 -0700732 * netlbl_mgmt_version - Handle a VERSION message
733 * @skb: the NETLINK buffer
734 * @info: the Generic NETLINK info block
735 *
736 * Description:
737 * Process a user generated VERSION message and respond accordingly. Returns
738 * zero on success, negative values on failure.
739 *
740 */
741static int netlbl_mgmt_version(struct sk_buff *skb, struct genl_info *info)
742{
743 int ret_val = -ENOMEM;
744 struct sk_buff *ans_skb = NULL;
Paul Moorefd385852006-09-25 15:56:37 -0700745 void *data;
Paul Moored15c3452006-08-03 16:48:37 -0700746
Thomas Graf339bf982006-11-10 14:10:15 -0800747 ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Paul Moored15c3452006-08-03 16:48:37 -0700748 if (ans_skb == NULL)
Paul Moorefd385852006-09-25 15:56:37 -0700749 return -ENOMEM;
Thomas Graf17c157c2006-11-14 19:46:02 -0800750 data = genlmsg_put_reply(ans_skb, info, &netlbl_mgmt_gnl_family,
751 0, NLBL_MGMT_C_VERSION);
Paul Moorefd385852006-09-25 15:56:37 -0700752 if (data == NULL)
Paul Moored15c3452006-08-03 16:48:37 -0700753 goto version_failure;
754
Paul Moorefd385852006-09-25 15:56:37 -0700755 ret_val = nla_put_u32(ans_skb,
756 NLBL_MGMT_A_VERSION,
757 NETLBL_PROTO_VERSION);
Paul Moored15c3452006-08-03 16:48:37 -0700758 if (ret_val != 0)
759 goto version_failure;
760
Paul Moorefd385852006-09-25 15:56:37 -0700761 genlmsg_end(ans_skb, data);
Denis V. Lunevfe785be2008-07-10 16:53:39 -0700762 return genlmsg_reply(ans_skb, info);
Paul Moored15c3452006-08-03 16:48:37 -0700763
764version_failure:
765 kfree_skb(ans_skb);
Paul Moored15c3452006-08-03 16:48:37 -0700766 return ret_val;
767}
768
769
770/*
771 * NetLabel Generic NETLINK Command Definitions
772 */
773
Johannes Berg4534de82013-11-14 17:14:46 +0100774static const struct genl_ops netlbl_mgmt_genl_ops[] = {
Pavel Emelyanov227c43c2008-02-17 22:33:16 -0800775 {
Paul Moored15c3452006-08-03 16:48:37 -0700776 .cmd = NLBL_MGMT_C_ADD,
Paul Moorefd385852006-09-25 15:56:37 -0700777 .flags = GENL_ADMIN_PERM,
Paul Moored15c3452006-08-03 16:48:37 -0700778 .doit = netlbl_mgmt_add,
779 .dumpit = NULL,
Pavel Emelyanov227c43c2008-02-17 22:33:16 -0800780 },
781 {
Paul Moored15c3452006-08-03 16:48:37 -0700782 .cmd = NLBL_MGMT_C_REMOVE,
Paul Moorefd385852006-09-25 15:56:37 -0700783 .flags = GENL_ADMIN_PERM,
Paul Moored15c3452006-08-03 16:48:37 -0700784 .doit = netlbl_mgmt_remove,
785 .dumpit = NULL,
Pavel Emelyanov227c43c2008-02-17 22:33:16 -0800786 },
787 {
Paul Moorefd385852006-09-25 15:56:37 -0700788 .cmd = NLBL_MGMT_C_LISTALL,
Paul Moored15c3452006-08-03 16:48:37 -0700789 .flags = 0,
Paul Moorefd385852006-09-25 15:56:37 -0700790 .doit = NULL,
791 .dumpit = netlbl_mgmt_listall,
Pavel Emelyanov227c43c2008-02-17 22:33:16 -0800792 },
793 {
Paul Moored15c3452006-08-03 16:48:37 -0700794 .cmd = NLBL_MGMT_C_ADDDEF,
Paul Moorefd385852006-09-25 15:56:37 -0700795 .flags = GENL_ADMIN_PERM,
Paul Moored15c3452006-08-03 16:48:37 -0700796 .doit = netlbl_mgmt_adddef,
797 .dumpit = NULL,
Pavel Emelyanov227c43c2008-02-17 22:33:16 -0800798 },
799 {
Paul Moored15c3452006-08-03 16:48:37 -0700800 .cmd = NLBL_MGMT_C_REMOVEDEF,
Paul Moorefd385852006-09-25 15:56:37 -0700801 .flags = GENL_ADMIN_PERM,
Paul Moored15c3452006-08-03 16:48:37 -0700802 .doit = netlbl_mgmt_removedef,
803 .dumpit = NULL,
Pavel Emelyanov227c43c2008-02-17 22:33:16 -0800804 },
805 {
Paul Moored15c3452006-08-03 16:48:37 -0700806 .cmd = NLBL_MGMT_C_LISTDEF,
807 .flags = 0,
808 .doit = netlbl_mgmt_listdef,
809 .dumpit = NULL,
Pavel Emelyanov227c43c2008-02-17 22:33:16 -0800810 },
811 {
Paul Moorefd385852006-09-25 15:56:37 -0700812 .cmd = NLBL_MGMT_C_PROTOCOLS,
Paul Moored15c3452006-08-03 16:48:37 -0700813 .flags = 0,
Paul Moorefd385852006-09-25 15:56:37 -0700814 .doit = NULL,
815 .dumpit = netlbl_mgmt_protocols,
Pavel Emelyanov227c43c2008-02-17 22:33:16 -0800816 },
817 {
Paul Moored15c3452006-08-03 16:48:37 -0700818 .cmd = NLBL_MGMT_C_VERSION,
819 .flags = 0,
820 .doit = netlbl_mgmt_version,
821 .dumpit = NULL,
Pavel Emelyanov227c43c2008-02-17 22:33:16 -0800822 },
Paul Moored15c3452006-08-03 16:48:37 -0700823};
824
Johannes Berg56989f62016-10-24 14:40:05 +0200825static struct genl_family netlbl_mgmt_gnl_family __ro_after_init = {
Johannes Berg489111e2016-10-24 14:40:03 +0200826 .hdrsize = 0,
827 .name = NETLBL_NLTYPE_MGMT_NAME,
828 .version = NETLBL_PROTO_VERSION,
829 .maxattr = NLBL_MGMT_A_MAX,
Johannes Berg3b0f31f2019-03-21 22:51:02 +0100830 .policy = netlbl_mgmt_genl_policy,
Johannes Berg489111e2016-10-24 14:40:03 +0200831 .module = THIS_MODULE,
832 .ops = netlbl_mgmt_genl_ops,
833 .n_ops = ARRAY_SIZE(netlbl_mgmt_genl_ops),
834};
835
Paul Moored15c3452006-08-03 16:48:37 -0700836/*
837 * NetLabel Generic NETLINK Protocol Functions
838 */
839
840/**
841 * netlbl_mgmt_genl_init - Register the NetLabel management component
842 *
843 * Description:
844 * Register the NetLabel management component with the Generic NETLINK
845 * mechanism. Returns zero on success, negative values on failure.
846 *
847 */
Pavel Emelyanov05705e42008-02-17 22:33:57 -0800848int __init netlbl_mgmt_genl_init(void)
Paul Moored15c3452006-08-03 16:48:37 -0700849{
Johannes Berg489111e2016-10-24 14:40:03 +0200850 return genl_register_family(&netlbl_mgmt_gnl_family);
Paul Moored15c3452006-08-03 16:48:37 -0700851}