11ccea77eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2d15c345fSPaul Moore /*
3d15c345fSPaul Moore * NetLabel Management Support
4d15c345fSPaul Moore *
5d15c345fSPaul Moore * This file defines the management functions for the NetLabel system. The
6d15c345fSPaul Moore * NetLabel system manages static and dynamic label mappings for network
7d15c345fSPaul Moore * protocols such as CIPSO and RIPSO.
8d15c345fSPaul Moore *
982c21bfaSPaul Moore * Author: Paul Moore <paul@paul-moore.com>
10d15c345fSPaul Moore */
11d15c345fSPaul Moore
12d15c345fSPaul Moore /*
1363c41688SPaul Moore * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
14d15c345fSPaul Moore */
15d15c345fSPaul Moore
16d15c345fSPaul Moore #include <linux/types.h>
17d15c345fSPaul Moore #include <linux/socket.h>
18d15c345fSPaul Moore #include <linux/string.h>
19d15c345fSPaul Moore #include <linux/skbuff.h>
2063c41688SPaul Moore #include <linux/in.h>
2163c41688SPaul Moore #include <linux/in6.h>
225a0e3ad6STejun Heo #include <linux/slab.h>
23d15c345fSPaul Moore #include <net/sock.h>
24d15c345fSPaul Moore #include <net/netlink.h>
25d15c345fSPaul Moore #include <net/genetlink.h>
2663c41688SPaul Moore #include <net/ip.h>
2763c41688SPaul Moore #include <net/ipv6.h>
28d15c345fSPaul Moore #include <net/netlabel.h>
29d15c345fSPaul Moore #include <net/cipso_ipv4.h>
30dc7de73fSHuw Davies #include <net/calipso.h>
3160063497SArun Sharma #include <linux/atomic.h>
32d15c345fSPaul Moore
33dc7de73fSHuw Davies #include "netlabel_calipso.h"
34d15c345fSPaul Moore #include "netlabel_domainhash.h"
35d15c345fSPaul Moore #include "netlabel_user.h"
36d15c345fSPaul Moore #include "netlabel_mgmt.h"
37d15c345fSPaul Moore
38c783f1ceSPaul Moore /* NetLabel configured protocol counter */
39c783f1ceSPaul Moore atomic_t netlabel_mgmt_protocount = ATOMIC_INIT(0);
4023bcdc1aSPaul Moore
41fd385855SPaul Moore /* Argument struct for netlbl_domhsh_walk() */
42fd385855SPaul Moore struct netlbl_domhsh_walk_arg {
43fd385855SPaul Moore struct netlink_callback *nl_cb;
44fd385855SPaul Moore struct sk_buff *skb;
45fd385855SPaul Moore u32 seq;
46fd385855SPaul Moore };
47fd385855SPaul Moore
48d15c345fSPaul Moore /* NetLabel Generic NETLINK CIPSOv4 family */
49489111e5SJohannes Berg static struct genl_family netlbl_mgmt_gnl_family;
50d15c345fSPaul Moore
51fd385855SPaul Moore /* NetLabel Netlink attribute policy */
52ef7c79edSPatrick McHardy static const struct nla_policy netlbl_mgmt_genl_policy[NLBL_MGMT_A_MAX + 1] = {
53fd385855SPaul Moore [NLBL_MGMT_A_DOMAIN] = { .type = NLA_NUL_STRING },
54fd385855SPaul Moore [NLBL_MGMT_A_PROTOCOL] = { .type = NLA_U32 },
55fd385855SPaul Moore [NLBL_MGMT_A_VERSION] = { .type = NLA_U32 },
56fd385855SPaul Moore [NLBL_MGMT_A_CV4DOI] = { .type = NLA_U32 },
578f18e675SHuw Davies [NLBL_MGMT_A_FAMILY] = { .type = NLA_U16 },
58dc7de73fSHuw Davies [NLBL_MGMT_A_CLPDOI] = { .type = NLA_U32 },
59fd385855SPaul Moore };
60d15c345fSPaul Moore
61d15c345fSPaul Moore /*
6263c41688SPaul Moore * Helper Functions
6363c41688SPaul Moore */
6463c41688SPaul Moore
6563c41688SPaul Moore /**
663ba937fbSXiongfeng Wang * netlbl_mgmt_add_common - Handle an ADD message
6763c41688SPaul Moore * @info: the Generic NETLINK info block
6863c41688SPaul Moore * @audit_info: NetLabel audit information
6963c41688SPaul Moore *
7063c41688SPaul Moore * Description:
7163c41688SPaul Moore * Helper function for the ADD and ADDDEF messages to add the domain mappings
7263c41688SPaul Moore * from the message to the hash table. See netlabel.h for a description of the
7363c41688SPaul Moore * message format. Returns zero on success, negative values on failure.
7463c41688SPaul Moore *
7563c41688SPaul Moore */
netlbl_mgmt_add_common(struct genl_info * info,struct netlbl_audit * audit_info)7663c41688SPaul Moore static int netlbl_mgmt_add_common(struct genl_info *info,
7763c41688SPaul Moore struct netlbl_audit *audit_info)
7863c41688SPaul Moore {
79b8f6b052SLiu Shixin void *pmap = NULL;
8063c41688SPaul Moore int ret_val = -EINVAL;
8163c41688SPaul Moore struct netlbl_domaddr_map *addrmap = NULL;
8263c41688SPaul Moore struct cipso_v4_doi *cipsov4 = NULL;
83dc7de73fSHuw Davies #if IS_ENABLED(CONFIG_IPV6)
84dc7de73fSHuw Davies struct calipso_doi *calipso = NULL;
85dc7de73fSHuw Davies #endif
8663c41688SPaul Moore u32 tmp_val;
874de46d5eSMarkus Elfring struct netlbl_dom_map *entry = kzalloc(sizeof(*entry), GFP_KERNEL);
8863c41688SPaul Moore
894de46d5eSMarkus Elfring if (!entry)
904de46d5eSMarkus Elfring return -ENOMEM;
916a8b7f0cSPaul Moore entry->def.type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]);
9263c41688SPaul Moore if (info->attrs[NLBL_MGMT_A_DOMAIN]) {
9363c41688SPaul Moore size_t tmp_size = nla_len(info->attrs[NLBL_MGMT_A_DOMAIN]);
9463c41688SPaul Moore entry->domain = kmalloc(tmp_size, GFP_KERNEL);
9563c41688SPaul Moore if (entry->domain == NULL) {
9663c41688SPaul Moore ret_val = -ENOMEM;
974de46d5eSMarkus Elfring goto add_free_entry;
9863c41688SPaul Moore }
99872f6903SFrancis Laniel nla_strscpy(entry->domain,
10063c41688SPaul Moore info->attrs[NLBL_MGMT_A_DOMAIN], tmp_size);
10163c41688SPaul Moore }
10263c41688SPaul Moore
1036a8b7f0cSPaul Moore /* NOTE: internally we allow/use a entry->def.type value of
10463c41688SPaul Moore * NETLBL_NLTYPE_ADDRSELECT but we don't currently allow users
10563c41688SPaul Moore * to pass that as a protocol value because we need to know the
10663c41688SPaul Moore * "real" protocol */
10763c41688SPaul Moore
1086a8b7f0cSPaul Moore switch (entry->def.type) {
10963c41688SPaul Moore case NETLBL_NLTYPE_UNLABELED:
1108f18e675SHuw Davies if (info->attrs[NLBL_MGMT_A_FAMILY])
1118f18e675SHuw Davies entry->family =
1128f18e675SHuw Davies nla_get_u16(info->attrs[NLBL_MGMT_A_FAMILY]);
1138f18e675SHuw Davies else
1148f18e675SHuw Davies entry->family = AF_UNSPEC;
11563c41688SPaul Moore break;
11663c41688SPaul Moore case NETLBL_NLTYPE_CIPSOV4:
11763c41688SPaul Moore if (!info->attrs[NLBL_MGMT_A_CV4DOI])
1184de46d5eSMarkus Elfring goto add_free_domain;
11963c41688SPaul Moore
12063c41688SPaul Moore tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]);
12163c41688SPaul Moore cipsov4 = cipso_v4_doi_getdef(tmp_val);
12263c41688SPaul Moore if (cipsov4 == NULL)
1234de46d5eSMarkus Elfring goto add_free_domain;
1248f18e675SHuw Davies entry->family = AF_INET;
1256a8b7f0cSPaul Moore entry->def.cipso = cipsov4;
12663c41688SPaul Moore break;
127dc7de73fSHuw Davies #if IS_ENABLED(CONFIG_IPV6)
128dc7de73fSHuw Davies case NETLBL_NLTYPE_CALIPSO:
129dc7de73fSHuw Davies if (!info->attrs[NLBL_MGMT_A_CLPDOI])
130dc7de73fSHuw Davies goto add_free_domain;
131dc7de73fSHuw Davies
132dc7de73fSHuw Davies tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CLPDOI]);
133dc7de73fSHuw Davies calipso = calipso_doi_getdef(tmp_val);
134dc7de73fSHuw Davies if (calipso == NULL)
135dc7de73fSHuw Davies goto add_free_domain;
136dc7de73fSHuw Davies entry->family = AF_INET6;
137dc7de73fSHuw Davies entry->def.calipso = calipso;
138dc7de73fSHuw Davies break;
139dc7de73fSHuw Davies #endif /* IPv6 */
14063c41688SPaul Moore default:
1414de46d5eSMarkus Elfring goto add_free_domain;
14263c41688SPaul Moore }
14363c41688SPaul Moore
1448f18e675SHuw Davies if ((entry->family == AF_INET && info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
1458f18e675SHuw Davies (entry->family == AF_INET6 && info->attrs[NLBL_MGMT_A_IPV4ADDR]))
1468f18e675SHuw Davies goto add_doi_put_def;
1478f18e675SHuw Davies
14863c41688SPaul Moore if (info->attrs[NLBL_MGMT_A_IPV4ADDR]) {
14963c41688SPaul Moore struct in_addr *addr;
15063c41688SPaul Moore struct in_addr *mask;
15163c41688SPaul Moore struct netlbl_domaddr4_map *map;
15263c41688SPaul Moore
15363c41688SPaul Moore addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL);
15463c41688SPaul Moore if (addrmap == NULL) {
15563c41688SPaul Moore ret_val = -ENOMEM;
1564de46d5eSMarkus Elfring goto add_doi_put_def;
15763c41688SPaul Moore }
15863c41688SPaul Moore INIT_LIST_HEAD(&addrmap->list4);
15963c41688SPaul Moore INIT_LIST_HEAD(&addrmap->list6);
16063c41688SPaul Moore
16163c41688SPaul Moore if (nla_len(info->attrs[NLBL_MGMT_A_IPV4ADDR]) !=
16263c41688SPaul Moore sizeof(struct in_addr)) {
16363c41688SPaul Moore ret_val = -EINVAL;
1644de46d5eSMarkus Elfring goto add_free_addrmap;
16563c41688SPaul Moore }
16663c41688SPaul Moore if (nla_len(info->attrs[NLBL_MGMT_A_IPV4MASK]) !=
16763c41688SPaul Moore sizeof(struct in_addr)) {
16863c41688SPaul Moore ret_val = -EINVAL;
1694de46d5eSMarkus Elfring goto add_free_addrmap;
17063c41688SPaul Moore }
17163c41688SPaul Moore addr = nla_data(info->attrs[NLBL_MGMT_A_IPV4ADDR]);
17263c41688SPaul Moore mask = nla_data(info->attrs[NLBL_MGMT_A_IPV4MASK]);
17363c41688SPaul Moore
17463c41688SPaul Moore map = kzalloc(sizeof(*map), GFP_KERNEL);
17563c41688SPaul Moore if (map == NULL) {
17663c41688SPaul Moore ret_val = -ENOMEM;
1774de46d5eSMarkus Elfring goto add_free_addrmap;
17863c41688SPaul Moore }
179b8f6b052SLiu Shixin pmap = map;
18063c41688SPaul Moore map->list.addr = addr->s_addr & mask->s_addr;
18163c41688SPaul Moore map->list.mask = mask->s_addr;
18263c41688SPaul Moore map->list.valid = 1;
1836a8b7f0cSPaul Moore map->def.type = entry->def.type;
18463c41688SPaul Moore if (cipsov4)
1856a8b7f0cSPaul Moore map->def.cipso = cipsov4;
18663c41688SPaul Moore
18763c41688SPaul Moore ret_val = netlbl_af4list_add(&map->list, &addrmap->list4);
188b8f6b052SLiu Shixin if (ret_val != 0)
189b8f6b052SLiu Shixin goto add_free_map;
19063c41688SPaul Moore
1918f18e675SHuw Davies entry->family = AF_INET;
1926a8b7f0cSPaul Moore entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
1936a8b7f0cSPaul Moore entry->def.addrsel = addrmap;
194dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6)
19563c41688SPaul Moore } else if (info->attrs[NLBL_MGMT_A_IPV6ADDR]) {
19663c41688SPaul Moore struct in6_addr *addr;
19763c41688SPaul Moore struct in6_addr *mask;
19863c41688SPaul Moore struct netlbl_domaddr6_map *map;
19963c41688SPaul Moore
20063c41688SPaul Moore addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL);
20163c41688SPaul Moore if (addrmap == NULL) {
20263c41688SPaul Moore ret_val = -ENOMEM;
2034de46d5eSMarkus Elfring goto add_doi_put_def;
20463c41688SPaul Moore }
20563c41688SPaul Moore INIT_LIST_HEAD(&addrmap->list4);
20663c41688SPaul Moore INIT_LIST_HEAD(&addrmap->list6);
20763c41688SPaul Moore
20863c41688SPaul Moore if (nla_len(info->attrs[NLBL_MGMT_A_IPV6ADDR]) !=
20963c41688SPaul Moore sizeof(struct in6_addr)) {
21063c41688SPaul Moore ret_val = -EINVAL;
2114de46d5eSMarkus Elfring goto add_free_addrmap;
21263c41688SPaul Moore }
21363c41688SPaul Moore if (nla_len(info->attrs[NLBL_MGMT_A_IPV6MASK]) !=
21463c41688SPaul Moore sizeof(struct in6_addr)) {
21563c41688SPaul Moore ret_val = -EINVAL;
2164de46d5eSMarkus Elfring goto add_free_addrmap;
21763c41688SPaul Moore }
21863c41688SPaul Moore addr = nla_data(info->attrs[NLBL_MGMT_A_IPV6ADDR]);
21963c41688SPaul Moore mask = nla_data(info->attrs[NLBL_MGMT_A_IPV6MASK]);
22063c41688SPaul Moore
22163c41688SPaul Moore map = kzalloc(sizeof(*map), GFP_KERNEL);
22263c41688SPaul Moore if (map == NULL) {
22363c41688SPaul Moore ret_val = -ENOMEM;
2244de46d5eSMarkus Elfring goto add_free_addrmap;
22563c41688SPaul Moore }
226b8f6b052SLiu Shixin pmap = map;
2274e3fd7a0SAlexey Dobriyan map->list.addr = *addr;
22863c41688SPaul Moore map->list.addr.s6_addr32[0] &= mask->s6_addr32[0];
22963c41688SPaul Moore map->list.addr.s6_addr32[1] &= mask->s6_addr32[1];
23063c41688SPaul Moore map->list.addr.s6_addr32[2] &= mask->s6_addr32[2];
23163c41688SPaul Moore map->list.addr.s6_addr32[3] &= mask->s6_addr32[3];
2324e3fd7a0SAlexey Dobriyan map->list.mask = *mask;
23363c41688SPaul Moore map->list.valid = 1;
2346a8b7f0cSPaul Moore map->def.type = entry->def.type;
235dc7de73fSHuw Davies if (calipso)
236dc7de73fSHuw Davies map->def.calipso = calipso;
23763c41688SPaul Moore
23863c41688SPaul Moore ret_val = netlbl_af6list_add(&map->list, &addrmap->list6);
239b8f6b052SLiu Shixin if (ret_val != 0)
240b8f6b052SLiu Shixin goto add_free_map;
24163c41688SPaul Moore
2428f18e675SHuw Davies entry->family = AF_INET6;
2436a8b7f0cSPaul Moore entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
2446a8b7f0cSPaul Moore entry->def.addrsel = addrmap;
24563c41688SPaul Moore #endif /* IPv6 */
24663c41688SPaul Moore }
24763c41688SPaul Moore
24863c41688SPaul Moore ret_val = netlbl_domhsh_add(entry, audit_info);
24963c41688SPaul Moore if (ret_val != 0)
250b8f6b052SLiu Shixin goto add_free_map;
25163c41688SPaul Moore
25263c41688SPaul Moore return 0;
25363c41688SPaul Moore
254b8f6b052SLiu Shixin add_free_map:
255b8f6b052SLiu Shixin kfree(pmap);
2564de46d5eSMarkus Elfring add_free_addrmap:
25763c41688SPaul Moore kfree(addrmap);
2584de46d5eSMarkus Elfring add_doi_put_def:
2594de46d5eSMarkus Elfring cipso_v4_doi_putdef(cipsov4);
260dc7de73fSHuw Davies #if IS_ENABLED(CONFIG_IPV6)
261dc7de73fSHuw Davies calipso_doi_putdef(calipso);
262dc7de73fSHuw Davies #endif
2634de46d5eSMarkus Elfring add_free_domain:
2644de46d5eSMarkus Elfring kfree(entry->domain);
2654de46d5eSMarkus Elfring add_free_entry:
26663c41688SPaul Moore kfree(entry);
26763c41688SPaul Moore return ret_val;
26863c41688SPaul Moore }
26963c41688SPaul Moore
27063c41688SPaul Moore /**
27163c41688SPaul Moore * netlbl_mgmt_listentry - List a NetLabel/LSM domain map entry
27263c41688SPaul Moore * @skb: the NETLINK buffer
27363c41688SPaul Moore * @entry: the map entry
27463c41688SPaul Moore *
27563c41688SPaul Moore * Description:
27663c41688SPaul Moore * This function is a helper function used by the LISTALL and LISTDEF command
27725985edcSLucas De Marchi * handlers. The caller is responsible for ensuring that the RCU read lock
27863c41688SPaul Moore * is held. Returns zero on success, negative values on failure.
27963c41688SPaul Moore *
28063c41688SPaul Moore */
netlbl_mgmt_listentry(struct sk_buff * skb,struct netlbl_dom_map * entry)28163c41688SPaul Moore static int netlbl_mgmt_listentry(struct sk_buff *skb,
28263c41688SPaul Moore struct netlbl_dom_map *entry)
28363c41688SPaul Moore {
284f8a02479SPaul Moore int ret_val = 0;
28563c41688SPaul Moore struct nlattr *nla_a;
28663c41688SPaul Moore struct nlattr *nla_b;
28763c41688SPaul Moore struct netlbl_af4list *iter4;
288dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6)
28963c41688SPaul Moore struct netlbl_af6list *iter6;
29063c41688SPaul Moore #endif
29163c41688SPaul Moore
29263c41688SPaul Moore if (entry->domain != NULL) {
29363c41688SPaul Moore ret_val = nla_put_string(skb,
29463c41688SPaul Moore NLBL_MGMT_A_DOMAIN, entry->domain);
29563c41688SPaul Moore if (ret_val != 0)
29663c41688SPaul Moore return ret_val;
29763c41688SPaul Moore }
29863c41688SPaul Moore
2998f18e675SHuw Davies ret_val = nla_put_u16(skb, NLBL_MGMT_A_FAMILY, entry->family);
3008f18e675SHuw Davies if (ret_val != 0)
3018f18e675SHuw Davies return ret_val;
3028f18e675SHuw Davies
3036a8b7f0cSPaul Moore switch (entry->def.type) {
30463c41688SPaul Moore case NETLBL_NLTYPE_ADDRSELECT:
305ae0be8deSMichal Kubecek nla_a = nla_nest_start_noflag(skb, NLBL_MGMT_A_SELECTORLIST);
30663c41688SPaul Moore if (nla_a == NULL)
30763c41688SPaul Moore return -ENOMEM;
30863c41688SPaul Moore
3096a8b7f0cSPaul Moore netlbl_af4list_foreach_rcu(iter4, &entry->def.addrsel->list4) {
31063c41688SPaul Moore struct netlbl_domaddr4_map *map4;
31163c41688SPaul Moore struct in_addr addr_struct;
31263c41688SPaul Moore
313ae0be8deSMichal Kubecek nla_b = nla_nest_start_noflag(skb,
314ae0be8deSMichal Kubecek NLBL_MGMT_A_ADDRSELECTOR);
31563c41688SPaul Moore if (nla_b == NULL)
31663c41688SPaul Moore return -ENOMEM;
31763c41688SPaul Moore
31863c41688SPaul Moore addr_struct.s_addr = iter4->addr;
319930345eaSJiri Benc ret_val = nla_put_in_addr(skb, NLBL_MGMT_A_IPV4ADDR,
320930345eaSJiri Benc addr_struct.s_addr);
32163c41688SPaul Moore if (ret_val != 0)
32263c41688SPaul Moore return ret_val;
32363c41688SPaul Moore addr_struct.s_addr = iter4->mask;
324930345eaSJiri Benc ret_val = nla_put_in_addr(skb, NLBL_MGMT_A_IPV4MASK,
325930345eaSJiri Benc addr_struct.s_addr);
32663c41688SPaul Moore if (ret_val != 0)
32763c41688SPaul Moore return ret_val;
32863c41688SPaul Moore map4 = netlbl_domhsh_addr4_entry(iter4);
32963c41688SPaul Moore ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
3306a8b7f0cSPaul Moore map4->def.type);
33163c41688SPaul Moore if (ret_val != 0)
33263c41688SPaul Moore return ret_val;
3336a8b7f0cSPaul Moore switch (map4->def.type) {
33463c41688SPaul Moore case NETLBL_NLTYPE_CIPSOV4:
33563c41688SPaul Moore ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI,
3366a8b7f0cSPaul Moore map4->def.cipso->doi);
33763c41688SPaul Moore if (ret_val != 0)
33863c41688SPaul Moore return ret_val;
33963c41688SPaul Moore break;
34063c41688SPaul Moore }
34163c41688SPaul Moore
34263c41688SPaul Moore nla_nest_end(skb, nla_b);
34363c41688SPaul Moore }
344dfd56b8bSEric Dumazet #if IS_ENABLED(CONFIG_IPV6)
3456a8b7f0cSPaul Moore netlbl_af6list_foreach_rcu(iter6, &entry->def.addrsel->list6) {
34663c41688SPaul Moore struct netlbl_domaddr6_map *map6;
34763c41688SPaul Moore
348ae0be8deSMichal Kubecek nla_b = nla_nest_start_noflag(skb,
349ae0be8deSMichal Kubecek NLBL_MGMT_A_ADDRSELECTOR);
35063c41688SPaul Moore if (nla_b == NULL)
35163c41688SPaul Moore return -ENOMEM;
35263c41688SPaul Moore
353930345eaSJiri Benc ret_val = nla_put_in6_addr(skb, NLBL_MGMT_A_IPV6ADDR,
35463c41688SPaul Moore &iter6->addr);
35563c41688SPaul Moore if (ret_val != 0)
35663c41688SPaul Moore return ret_val;
357930345eaSJiri Benc ret_val = nla_put_in6_addr(skb, NLBL_MGMT_A_IPV6MASK,
35863c41688SPaul Moore &iter6->mask);
35963c41688SPaul Moore if (ret_val != 0)
36063c41688SPaul Moore return ret_val;
36163c41688SPaul Moore map6 = netlbl_domhsh_addr6_entry(iter6);
36263c41688SPaul Moore ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
3636a8b7f0cSPaul Moore map6->def.type);
36463c41688SPaul Moore if (ret_val != 0)
36563c41688SPaul Moore return ret_val;
36663c41688SPaul Moore
367dc7de73fSHuw Davies switch (map6->def.type) {
368dc7de73fSHuw Davies case NETLBL_NLTYPE_CALIPSO:
369dc7de73fSHuw Davies ret_val = nla_put_u32(skb, NLBL_MGMT_A_CLPDOI,
370dc7de73fSHuw Davies map6->def.calipso->doi);
371dc7de73fSHuw Davies if (ret_val != 0)
372dc7de73fSHuw Davies return ret_val;
373dc7de73fSHuw Davies break;
374dc7de73fSHuw Davies }
375dc7de73fSHuw Davies
37663c41688SPaul Moore nla_nest_end(skb, nla_b);
37763c41688SPaul Moore }
37863c41688SPaul Moore #endif /* IPv6 */
37963c41688SPaul Moore
38063c41688SPaul Moore nla_nest_end(skb, nla_a);
38163c41688SPaul Moore break;
38263c41688SPaul Moore case NETLBL_NLTYPE_UNLABELED:
383dc7de73fSHuw Davies ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
384dc7de73fSHuw Davies entry->def.type);
38563c41688SPaul Moore break;
38663c41688SPaul Moore case NETLBL_NLTYPE_CIPSOV4:
387dc7de73fSHuw Davies ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
388dc7de73fSHuw Davies entry->def.type);
38963c41688SPaul Moore if (ret_val != 0)
39063c41688SPaul Moore return ret_val;
39163c41688SPaul Moore ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI,
3926a8b7f0cSPaul Moore entry->def.cipso->doi);
39363c41688SPaul Moore break;
394dc7de73fSHuw Davies case NETLBL_NLTYPE_CALIPSO:
395dc7de73fSHuw Davies ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
396dc7de73fSHuw Davies entry->def.type);
397dc7de73fSHuw Davies if (ret_val != 0)
398dc7de73fSHuw Davies return ret_val;
399dc7de73fSHuw Davies ret_val = nla_put_u32(skb, NLBL_MGMT_A_CLPDOI,
400dc7de73fSHuw Davies entry->def.calipso->doi);
401dc7de73fSHuw Davies break;
40263c41688SPaul Moore }
40363c41688SPaul Moore
40463c41688SPaul Moore return ret_val;
40563c41688SPaul Moore }
40663c41688SPaul Moore
40763c41688SPaul Moore /*
408d15c345fSPaul Moore * NetLabel Command Handlers
409d15c345fSPaul Moore */
410d15c345fSPaul Moore
411d15c345fSPaul Moore /**
412d15c345fSPaul Moore * netlbl_mgmt_add - Handle an ADD message
413d15c345fSPaul Moore * @skb: the NETLINK buffer
414d15c345fSPaul Moore * @info: the Generic NETLINK info block
415d15c345fSPaul Moore *
416d15c345fSPaul Moore * Description:
417d15c345fSPaul Moore * Process a user generated ADD message and add the domains from the message
418d15c345fSPaul Moore * to the hash table. See netlabel.h for a description of the message format.
419d15c345fSPaul Moore * Returns zero on success, negative values on failure.
420d15c345fSPaul Moore *
421d15c345fSPaul Moore */
netlbl_mgmt_add(struct sk_buff * skb,struct genl_info * info)422d15c345fSPaul Moore static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info)
423d15c345fSPaul Moore {
42495d4e6beSPaul Moore struct netlbl_audit audit_info;
425d15c345fSPaul Moore
42663c41688SPaul Moore if ((!info->attrs[NLBL_MGMT_A_DOMAIN]) ||
42763c41688SPaul Moore (!info->attrs[NLBL_MGMT_A_PROTOCOL]) ||
42863c41688SPaul Moore (info->attrs[NLBL_MGMT_A_IPV4ADDR] &&
42963c41688SPaul Moore info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
43063c41688SPaul Moore (info->attrs[NLBL_MGMT_A_IPV4MASK] &&
43163c41688SPaul Moore info->attrs[NLBL_MGMT_A_IPV6MASK]) ||
43263c41688SPaul Moore ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^
43363c41688SPaul Moore (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) ||
43463c41688SPaul Moore ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^
43563c41688SPaul Moore (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL)))
43663c41688SPaul Moore return -EINVAL;
437d15c345fSPaul Moore
438f7e0318aSZheng Yejian netlbl_netlink_auditinfo(&audit_info);
43995d4e6beSPaul Moore
44063c41688SPaul Moore return netlbl_mgmt_add_common(info, &audit_info);
441d15c345fSPaul Moore }
442d15c345fSPaul Moore
443d15c345fSPaul Moore /**
444d15c345fSPaul Moore * netlbl_mgmt_remove - Handle a REMOVE message
445d15c345fSPaul Moore * @skb: the NETLINK buffer
446d15c345fSPaul Moore * @info: the Generic NETLINK info block
447d15c345fSPaul Moore *
448d15c345fSPaul Moore * Description:
449d15c345fSPaul Moore * Process a user generated REMOVE message and remove the specified domain
450d15c345fSPaul Moore * mappings. Returns zero on success, negative values on failure.
451d15c345fSPaul Moore *
452d15c345fSPaul Moore */
netlbl_mgmt_remove(struct sk_buff * skb,struct genl_info * info)453d15c345fSPaul Moore static int netlbl_mgmt_remove(struct sk_buff *skb, struct genl_info *info)
454d15c345fSPaul Moore {
455fd385855SPaul Moore char *domain;
45695d4e6beSPaul Moore struct netlbl_audit audit_info;
457d15c345fSPaul Moore
458fd385855SPaul Moore if (!info->attrs[NLBL_MGMT_A_DOMAIN])
459fd385855SPaul Moore return -EINVAL;
460d15c345fSPaul Moore
461f7e0318aSZheng Yejian netlbl_netlink_auditinfo(&audit_info);
46295d4e6beSPaul Moore
463fd385855SPaul Moore domain = nla_data(info->attrs[NLBL_MGMT_A_DOMAIN]);
4648f18e675SHuw Davies return netlbl_domhsh_remove(domain, AF_UNSPEC, &audit_info);
465d15c345fSPaul Moore }
466d15c345fSPaul Moore
467fd385855SPaul Moore /**
468fd385855SPaul Moore * netlbl_mgmt_listall_cb - netlbl_domhsh_walk() callback for LISTALL
469fd385855SPaul Moore * @entry: the domain mapping hash table entry
470fd385855SPaul Moore * @arg: the netlbl_domhsh_walk_arg structure
471fd385855SPaul Moore *
472fd385855SPaul Moore * Description:
473fd385855SPaul Moore * This function is designed to be used as a callback to the
474fd385855SPaul Moore * netlbl_domhsh_walk() function for use in generating a response for a LISTALL
475fd385855SPaul Moore * message. Returns the size of the message on success, negative values on
476fd385855SPaul Moore * failure.
477fd385855SPaul Moore *
478fd385855SPaul Moore */
netlbl_mgmt_listall_cb(struct netlbl_dom_map * entry,void * arg)479fd385855SPaul Moore static int netlbl_mgmt_listall_cb(struct netlbl_dom_map *entry, void *arg)
480fd385855SPaul Moore {
481fd385855SPaul Moore int ret_val = -ENOMEM;
482fd385855SPaul Moore struct netlbl_domhsh_walk_arg *cb_arg = arg;
483fd385855SPaul Moore void *data;
484d15c345fSPaul Moore
48515e47304SEric W. Biederman data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).portid,
48617c157c8SThomas Graf cb_arg->seq, &netlbl_mgmt_gnl_family,
48717c157c8SThomas Graf NLM_F_MULTI, NLBL_MGMT_C_LISTALL);
488fd385855SPaul Moore if (data == NULL)
489fd385855SPaul Moore goto listall_cb_failure;
490fd385855SPaul Moore
49163c41688SPaul Moore ret_val = netlbl_mgmt_listentry(cb_arg->skb, entry);
492fd385855SPaul Moore if (ret_val != 0)
493fd385855SPaul Moore goto listall_cb_failure;
494fd385855SPaul Moore
495fd385855SPaul Moore cb_arg->seq++;
496053c095aSJohannes Berg genlmsg_end(cb_arg->skb, data);
497053c095aSJohannes Berg return 0;
498fd385855SPaul Moore
499fd385855SPaul Moore listall_cb_failure:
500fd385855SPaul Moore genlmsg_cancel(cb_arg->skb, data);
501d15c345fSPaul Moore return ret_val;
502d15c345fSPaul Moore }
503d15c345fSPaul Moore
504d15c345fSPaul Moore /**
505fd385855SPaul Moore * netlbl_mgmt_listall - Handle a LISTALL message
506d15c345fSPaul Moore * @skb: the NETLINK buffer
507fd385855SPaul Moore * @cb: the NETLINK callback
508d15c345fSPaul Moore *
509d15c345fSPaul Moore * Description:
510fd385855SPaul Moore * Process a user generated LISTALL message and dumps the domain hash table in
511fd385855SPaul Moore * a form suitable for use in a kernel generated LISTALL message. Returns zero
512fd385855SPaul Moore * on success, negative values on failure.
513d15c345fSPaul Moore *
514d15c345fSPaul Moore */
netlbl_mgmt_listall(struct sk_buff * skb,struct netlink_callback * cb)515fd385855SPaul Moore static int netlbl_mgmt_listall(struct sk_buff *skb,
516fd385855SPaul Moore struct netlink_callback *cb)
517d15c345fSPaul Moore {
518fd385855SPaul Moore struct netlbl_domhsh_walk_arg cb_arg;
519fd385855SPaul Moore u32 skip_bkt = cb->args[0];
520fd385855SPaul Moore u32 skip_chain = cb->args[1];
521d15c345fSPaul Moore
522fd385855SPaul Moore cb_arg.nl_cb = cb;
523fd385855SPaul Moore cb_arg.skb = skb;
524fd385855SPaul Moore cb_arg.seq = cb->nlh->nlmsg_seq;
525d15c345fSPaul Moore
526fd385855SPaul Moore netlbl_domhsh_walk(&skip_bkt,
527fd385855SPaul Moore &skip_chain,
528fd385855SPaul Moore netlbl_mgmt_listall_cb,
529fd385855SPaul Moore &cb_arg);
530d15c345fSPaul Moore
531fd385855SPaul Moore cb->args[0] = skip_bkt;
532fd385855SPaul Moore cb->args[1] = skip_chain;
533fd385855SPaul Moore return skb->len;
534d15c345fSPaul Moore }
535d15c345fSPaul Moore
536d15c345fSPaul Moore /**
537d15c345fSPaul Moore * netlbl_mgmt_adddef - Handle an ADDDEF message
538d15c345fSPaul Moore * @skb: the NETLINK buffer
539d15c345fSPaul Moore * @info: the Generic NETLINK info block
540d15c345fSPaul Moore *
541d15c345fSPaul Moore * Description:
542d15c345fSPaul Moore * Process a user generated ADDDEF message and respond accordingly. Returns
543d15c345fSPaul Moore * zero on success, negative values on failure.
544d15c345fSPaul Moore *
545d15c345fSPaul Moore */
netlbl_mgmt_adddef(struct sk_buff * skb,struct genl_info * info)546d15c345fSPaul Moore static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info)
547d15c345fSPaul Moore {
54895d4e6beSPaul Moore struct netlbl_audit audit_info;
549d15c345fSPaul Moore
55063c41688SPaul Moore if ((!info->attrs[NLBL_MGMT_A_PROTOCOL]) ||
55163c41688SPaul Moore (info->attrs[NLBL_MGMT_A_IPV4ADDR] &&
55263c41688SPaul Moore info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
55363c41688SPaul Moore (info->attrs[NLBL_MGMT_A_IPV4MASK] &&
55463c41688SPaul Moore info->attrs[NLBL_MGMT_A_IPV6MASK]) ||
55563c41688SPaul Moore ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^
55663c41688SPaul Moore (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) ||
55763c41688SPaul Moore ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^
55863c41688SPaul Moore (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL)))
55963c41688SPaul Moore return -EINVAL;
560d15c345fSPaul Moore
561f7e0318aSZheng Yejian netlbl_netlink_auditinfo(&audit_info);
56295d4e6beSPaul Moore
56363c41688SPaul Moore return netlbl_mgmt_add_common(info, &audit_info);
564d15c345fSPaul Moore }
565d15c345fSPaul Moore
566d15c345fSPaul Moore /**
567d15c345fSPaul Moore * netlbl_mgmt_removedef - Handle a REMOVEDEF message
568d15c345fSPaul Moore * @skb: the NETLINK buffer
569d15c345fSPaul Moore * @info: the Generic NETLINK info block
570d15c345fSPaul Moore *
571d15c345fSPaul Moore * Description:
572d15c345fSPaul Moore * Process a user generated REMOVEDEF message and remove the default domain
573d15c345fSPaul Moore * mapping. Returns zero on success, negative values on failure.
574d15c345fSPaul Moore *
575d15c345fSPaul Moore */
netlbl_mgmt_removedef(struct sk_buff * skb,struct genl_info * info)576d15c345fSPaul Moore static int netlbl_mgmt_removedef(struct sk_buff *skb, struct genl_info *info)
577d15c345fSPaul Moore {
57895d4e6beSPaul Moore struct netlbl_audit audit_info;
57995d4e6beSPaul Moore
580f7e0318aSZheng Yejian netlbl_netlink_auditinfo(&audit_info);
58195d4e6beSPaul Moore
5828f18e675SHuw Davies return netlbl_domhsh_remove_default(AF_UNSPEC, &audit_info);
583d15c345fSPaul Moore }
584d15c345fSPaul Moore
585d15c345fSPaul Moore /**
586d15c345fSPaul Moore * netlbl_mgmt_listdef - Handle a LISTDEF message
587d15c345fSPaul Moore * @skb: the NETLINK buffer
588d15c345fSPaul Moore * @info: the Generic NETLINK info block
589d15c345fSPaul Moore *
590d15c345fSPaul Moore * Description:
591d15c345fSPaul Moore * Process a user generated LISTDEF message and dumps the default domain
592d15c345fSPaul Moore * mapping in a form suitable for use in a kernel generated LISTDEF message.
593d15c345fSPaul Moore * Returns zero on success, negative values on failure.
594d15c345fSPaul Moore *
595d15c345fSPaul Moore */
netlbl_mgmt_listdef(struct sk_buff * skb,struct genl_info * info)596d15c345fSPaul Moore static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info)
597d15c345fSPaul Moore {
598d15c345fSPaul Moore int ret_val = -ENOMEM;
599fd385855SPaul Moore struct sk_buff *ans_skb = NULL;
600fd385855SPaul Moore void *data;
601fd385855SPaul Moore struct netlbl_dom_map *entry;
6028f18e675SHuw Davies u16 family;
6038f18e675SHuw Davies
6048f18e675SHuw Davies if (info->attrs[NLBL_MGMT_A_FAMILY])
6058f18e675SHuw Davies family = nla_get_u16(info->attrs[NLBL_MGMT_A_FAMILY]);
6068f18e675SHuw Davies else
6078f18e675SHuw Davies family = AF_INET;
608d15c345fSPaul Moore
609339bf98fSThomas Graf ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
610d15c345fSPaul Moore if (ans_skb == NULL)
611fd385855SPaul Moore return -ENOMEM;
61217c157c8SThomas Graf data = genlmsg_put_reply(ans_skb, info, &netlbl_mgmt_gnl_family,
61317c157c8SThomas Graf 0, NLBL_MGMT_C_LISTDEF);
614fd385855SPaul Moore if (data == NULL)
615fd385855SPaul Moore goto listdef_failure;
616d15c345fSPaul Moore
617fd385855SPaul Moore rcu_read_lock();
6188f18e675SHuw Davies entry = netlbl_domhsh_getentry(NULL, family);
619fd385855SPaul Moore if (entry == NULL) {
620fd385855SPaul Moore ret_val = -ENOENT;
621fd385855SPaul Moore goto listdef_failure_lock;
622fd385855SPaul Moore }
62363c41688SPaul Moore ret_val = netlbl_mgmt_listentry(ans_skb, entry);
624fd385855SPaul Moore rcu_read_unlock();
62563c41688SPaul Moore if (ret_val != 0)
62663c41688SPaul Moore goto listdef_failure;
627fd385855SPaul Moore
628fd385855SPaul Moore genlmsg_end(ans_skb, data);
629fe785beeSDenis V. Lunev return genlmsg_reply(ans_skb, info);
630d15c345fSPaul Moore
631fd385855SPaul Moore listdef_failure_lock:
632fd385855SPaul Moore rcu_read_unlock();
633d15c345fSPaul Moore listdef_failure:
634fd385855SPaul Moore kfree_skb(ans_skb);
635d15c345fSPaul Moore return ret_val;
636d15c345fSPaul Moore }
637d15c345fSPaul Moore
638d15c345fSPaul Moore /**
639fd385855SPaul Moore * netlbl_mgmt_protocols_cb - Write an individual PROTOCOL message response
640fd385855SPaul Moore * @skb: the skb to write to
641fd385855SPaul Moore * @cb: the NETLINK callback
642fd385855SPaul Moore * @protocol: the NetLabel protocol to use in the message
643d15c345fSPaul Moore *
644d15c345fSPaul Moore * Description:
645fd385855SPaul Moore * This function is to be used in conjunction with netlbl_mgmt_protocols() to
646fd385855SPaul Moore * answer a application's PROTOCOLS message. Returns the size of the message
647fd385855SPaul Moore * on success, negative values on failure.
648d15c345fSPaul Moore *
649d15c345fSPaul Moore */
netlbl_mgmt_protocols_cb(struct sk_buff * skb,struct netlink_callback * cb,u32 protocol)650fd385855SPaul Moore static int netlbl_mgmt_protocols_cb(struct sk_buff *skb,
651fd385855SPaul Moore struct netlink_callback *cb,
652fd385855SPaul Moore u32 protocol)
653d15c345fSPaul Moore {
654d15c345fSPaul Moore int ret_val = -ENOMEM;
655fd385855SPaul Moore void *data;
656d15c345fSPaul Moore
65715e47304SEric W. Biederman data = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
65817c157c8SThomas Graf &netlbl_mgmt_gnl_family, NLM_F_MULTI,
659fd385855SPaul Moore NLBL_MGMT_C_PROTOCOLS);
660fd385855SPaul Moore if (data == NULL)
661fd385855SPaul Moore goto protocols_cb_failure;
662d15c345fSPaul Moore
663fd385855SPaul Moore ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, protocol);
664d15c345fSPaul Moore if (ret_val != 0)
665fd385855SPaul Moore goto protocols_cb_failure;
666d15c345fSPaul Moore
667053c095aSJohannes Berg genlmsg_end(skb, data);
668053c095aSJohannes Berg return 0;
669d15c345fSPaul Moore
670fd385855SPaul Moore protocols_cb_failure:
671fd385855SPaul Moore genlmsg_cancel(skb, data);
672d15c345fSPaul Moore return ret_val;
673d15c345fSPaul Moore }
674d15c345fSPaul Moore
675d15c345fSPaul Moore /**
676fd385855SPaul Moore * netlbl_mgmt_protocols - Handle a PROTOCOLS message
677fd385855SPaul Moore * @skb: the NETLINK buffer
678fd385855SPaul Moore * @cb: the NETLINK callback
679fd385855SPaul Moore *
680fd385855SPaul Moore * Description:
681fd385855SPaul Moore * Process a user generated PROTOCOLS message and respond accordingly.
682fd385855SPaul Moore *
683fd385855SPaul Moore */
netlbl_mgmt_protocols(struct sk_buff * skb,struct netlink_callback * cb)684fd385855SPaul Moore static int netlbl_mgmt_protocols(struct sk_buff *skb,
685fd385855SPaul Moore struct netlink_callback *cb)
686fd385855SPaul Moore {
687fd385855SPaul Moore u32 protos_sent = cb->args[0];
688fd385855SPaul Moore
689fd385855SPaul Moore if (protos_sent == 0) {
690fd385855SPaul Moore if (netlbl_mgmt_protocols_cb(skb,
691fd385855SPaul Moore cb,
692fd385855SPaul Moore NETLBL_NLTYPE_UNLABELED) < 0)
693fd385855SPaul Moore goto protocols_return;
694fd385855SPaul Moore protos_sent++;
695fd385855SPaul Moore }
696fd385855SPaul Moore if (protos_sent == 1) {
697fd385855SPaul Moore if (netlbl_mgmt_protocols_cb(skb,
698fd385855SPaul Moore cb,
699fd385855SPaul Moore NETLBL_NLTYPE_CIPSOV4) < 0)
700fd385855SPaul Moore goto protocols_return;
701fd385855SPaul Moore protos_sent++;
702fd385855SPaul Moore }
703cb72d382SHuw Davies #if IS_ENABLED(CONFIG_IPV6)
704cb72d382SHuw Davies if (protos_sent == 2) {
705cb72d382SHuw Davies if (netlbl_mgmt_protocols_cb(skb,
706cb72d382SHuw Davies cb,
707cb72d382SHuw Davies NETLBL_NLTYPE_CALIPSO) < 0)
708cb72d382SHuw Davies goto protocols_return;
709cb72d382SHuw Davies protos_sent++;
710cb72d382SHuw Davies }
711cb72d382SHuw Davies #endif
712fd385855SPaul Moore
713fd385855SPaul Moore protocols_return:
714fd385855SPaul Moore cb->args[0] = protos_sent;
715fd385855SPaul Moore return skb->len;
716fd385855SPaul Moore }
717fd385855SPaul Moore
718fd385855SPaul Moore /**
719d15c345fSPaul Moore * netlbl_mgmt_version - Handle a VERSION message
720d15c345fSPaul Moore * @skb: the NETLINK buffer
721d15c345fSPaul Moore * @info: the Generic NETLINK info block
722d15c345fSPaul Moore *
723d15c345fSPaul Moore * Description:
724d15c345fSPaul Moore * Process a user generated VERSION message and respond accordingly. Returns
725d15c345fSPaul Moore * zero on success, negative values on failure.
726d15c345fSPaul Moore *
727d15c345fSPaul Moore */
netlbl_mgmt_version(struct sk_buff * skb,struct genl_info * info)728d15c345fSPaul Moore static int netlbl_mgmt_version(struct sk_buff *skb, struct genl_info *info)
729d15c345fSPaul Moore {
730d15c345fSPaul Moore int ret_val = -ENOMEM;
731d15c345fSPaul Moore struct sk_buff *ans_skb = NULL;
732fd385855SPaul Moore void *data;
733d15c345fSPaul Moore
734339bf98fSThomas Graf ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
735d15c345fSPaul Moore if (ans_skb == NULL)
736fd385855SPaul Moore return -ENOMEM;
73717c157c8SThomas Graf data = genlmsg_put_reply(ans_skb, info, &netlbl_mgmt_gnl_family,
73817c157c8SThomas Graf 0, NLBL_MGMT_C_VERSION);
739fd385855SPaul Moore if (data == NULL)
740d15c345fSPaul Moore goto version_failure;
741d15c345fSPaul Moore
742fd385855SPaul Moore ret_val = nla_put_u32(ans_skb,
743fd385855SPaul Moore NLBL_MGMT_A_VERSION,
744fd385855SPaul Moore NETLBL_PROTO_VERSION);
745d15c345fSPaul Moore if (ret_val != 0)
746d15c345fSPaul Moore goto version_failure;
747d15c345fSPaul Moore
748fd385855SPaul Moore genlmsg_end(ans_skb, data);
749fe785beeSDenis V. Lunev return genlmsg_reply(ans_skb, info);
750d15c345fSPaul Moore
751d15c345fSPaul Moore version_failure:
752d15c345fSPaul Moore kfree_skb(ans_skb);
753d15c345fSPaul Moore return ret_val;
754d15c345fSPaul Moore }
755d15c345fSPaul Moore
756d15c345fSPaul Moore
757d15c345fSPaul Moore /*
758d15c345fSPaul Moore * NetLabel Generic NETLINK Command Definitions
759d15c345fSPaul Moore */
760d15c345fSPaul Moore
76166a9b928SJakub Kicinski static const struct genl_small_ops netlbl_mgmt_genl_ops[] = {
762227c43c3SPavel Emelyanov {
763d15c345fSPaul Moore .cmd = NLBL_MGMT_C_ADD,
764ef6243acSJohannes Berg .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
765fd385855SPaul Moore .flags = GENL_ADMIN_PERM,
766d15c345fSPaul Moore .doit = netlbl_mgmt_add,
767d15c345fSPaul Moore .dumpit = NULL,
768227c43c3SPavel Emelyanov },
769227c43c3SPavel Emelyanov {
770d15c345fSPaul Moore .cmd = NLBL_MGMT_C_REMOVE,
771ef6243acSJohannes Berg .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
772fd385855SPaul Moore .flags = GENL_ADMIN_PERM,
773d15c345fSPaul Moore .doit = netlbl_mgmt_remove,
774d15c345fSPaul Moore .dumpit = NULL,
775227c43c3SPavel Emelyanov },
776227c43c3SPavel Emelyanov {
777fd385855SPaul Moore .cmd = NLBL_MGMT_C_LISTALL,
778ef6243acSJohannes Berg .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
779d15c345fSPaul Moore .flags = 0,
780fd385855SPaul Moore .doit = NULL,
781fd385855SPaul Moore .dumpit = netlbl_mgmt_listall,
782227c43c3SPavel Emelyanov },
783227c43c3SPavel Emelyanov {
784d15c345fSPaul Moore .cmd = NLBL_MGMT_C_ADDDEF,
785ef6243acSJohannes Berg .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
786fd385855SPaul Moore .flags = GENL_ADMIN_PERM,
787d15c345fSPaul Moore .doit = netlbl_mgmt_adddef,
788d15c345fSPaul Moore .dumpit = NULL,
789227c43c3SPavel Emelyanov },
790227c43c3SPavel Emelyanov {
791d15c345fSPaul Moore .cmd = NLBL_MGMT_C_REMOVEDEF,
792ef6243acSJohannes Berg .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
793fd385855SPaul Moore .flags = GENL_ADMIN_PERM,
794d15c345fSPaul Moore .doit = netlbl_mgmt_removedef,
795d15c345fSPaul Moore .dumpit = NULL,
796227c43c3SPavel Emelyanov },
797227c43c3SPavel Emelyanov {
798d15c345fSPaul Moore .cmd = NLBL_MGMT_C_LISTDEF,
799ef6243acSJohannes Berg .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
800d15c345fSPaul Moore .flags = 0,
801d15c345fSPaul Moore .doit = netlbl_mgmt_listdef,
802d15c345fSPaul Moore .dumpit = NULL,
803227c43c3SPavel Emelyanov },
804227c43c3SPavel Emelyanov {
805fd385855SPaul Moore .cmd = NLBL_MGMT_C_PROTOCOLS,
806ef6243acSJohannes Berg .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
807d15c345fSPaul Moore .flags = 0,
808fd385855SPaul Moore .doit = NULL,
809fd385855SPaul Moore .dumpit = netlbl_mgmt_protocols,
810227c43c3SPavel Emelyanov },
811227c43c3SPavel Emelyanov {
812d15c345fSPaul Moore .cmd = NLBL_MGMT_C_VERSION,
813ef6243acSJohannes Berg .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
814d15c345fSPaul Moore .flags = 0,
815d15c345fSPaul Moore .doit = netlbl_mgmt_version,
816d15c345fSPaul Moore .dumpit = NULL,
817227c43c3SPavel Emelyanov },
818d15c345fSPaul Moore };
819d15c345fSPaul Moore
82056989f6dSJohannes Berg static struct genl_family netlbl_mgmt_gnl_family __ro_after_init = {
821489111e5SJohannes Berg .hdrsize = 0,
822489111e5SJohannes Berg .name = NETLBL_NLTYPE_MGMT_NAME,
823489111e5SJohannes Berg .version = NETLBL_PROTO_VERSION,
824489111e5SJohannes Berg .maxattr = NLBL_MGMT_A_MAX,
8253b0f31f2SJohannes Berg .policy = netlbl_mgmt_genl_policy,
826489111e5SJohannes Berg .module = THIS_MODULE,
82766a9b928SJakub Kicinski .small_ops = netlbl_mgmt_genl_ops,
82866a9b928SJakub Kicinski .n_small_ops = ARRAY_SIZE(netlbl_mgmt_genl_ops),
829*9c5d03d3SJakub Kicinski .resv_start_op = NLBL_MGMT_C_VERSION + 1,
830489111e5SJohannes Berg };
831489111e5SJohannes Berg
832d15c345fSPaul Moore /*
833d15c345fSPaul Moore * NetLabel Generic NETLINK Protocol Functions
834d15c345fSPaul Moore */
835d15c345fSPaul Moore
836d15c345fSPaul Moore /**
837d15c345fSPaul Moore * netlbl_mgmt_genl_init - Register the NetLabel management component
838d15c345fSPaul Moore *
839d15c345fSPaul Moore * Description:
840d15c345fSPaul Moore * Register the NetLabel management component with the Generic NETLINK
841d15c345fSPaul Moore * mechanism. Returns zero on success, negative values on failure.
842d15c345fSPaul Moore *
843d15c345fSPaul Moore */
netlbl_mgmt_genl_init(void)84405705e4eSPavel Emelyanov int __init netlbl_mgmt_genl_init(void)
845d15c345fSPaul Moore {
846489111e5SJohannes Berg return genl_register_family(&netlbl_mgmt_gnl_family);
847d15c345fSPaul Moore }
848