1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * NetLabel Management Support
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * This file defines the management functions for the NetLabel system. The
6*4882a593Smuzhiyun * NetLabel system manages static and dynamic label mappings for network
7*4882a593Smuzhiyun * protocols such as CIPSO and RIPSO.
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * Author: Paul Moore <paul@paul-moore.com>
10*4882a593Smuzhiyun */
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun /*
13*4882a593Smuzhiyun * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
14*4882a593Smuzhiyun */
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun #include <linux/types.h>
17*4882a593Smuzhiyun #include <linux/socket.h>
18*4882a593Smuzhiyun #include <linux/string.h>
19*4882a593Smuzhiyun #include <linux/skbuff.h>
20*4882a593Smuzhiyun #include <linux/in.h>
21*4882a593Smuzhiyun #include <linux/in6.h>
22*4882a593Smuzhiyun #include <linux/slab.h>
23*4882a593Smuzhiyun #include <net/sock.h>
24*4882a593Smuzhiyun #include <net/netlink.h>
25*4882a593Smuzhiyun #include <net/genetlink.h>
26*4882a593Smuzhiyun #include <net/ip.h>
27*4882a593Smuzhiyun #include <net/ipv6.h>
28*4882a593Smuzhiyun #include <net/netlabel.h>
29*4882a593Smuzhiyun #include <net/cipso_ipv4.h>
30*4882a593Smuzhiyun #include <net/calipso.h>
31*4882a593Smuzhiyun #include <linux/atomic.h>
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun #include "netlabel_calipso.h"
34*4882a593Smuzhiyun #include "netlabel_domainhash.h"
35*4882a593Smuzhiyun #include "netlabel_user.h"
36*4882a593Smuzhiyun #include "netlabel_mgmt.h"
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun /* NetLabel configured protocol counter */
39*4882a593Smuzhiyun atomic_t netlabel_mgmt_protocount = ATOMIC_INIT(0);
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun /* Argument struct for netlbl_domhsh_walk() */
42*4882a593Smuzhiyun struct netlbl_domhsh_walk_arg {
43*4882a593Smuzhiyun struct netlink_callback *nl_cb;
44*4882a593Smuzhiyun struct sk_buff *skb;
45*4882a593Smuzhiyun u32 seq;
46*4882a593Smuzhiyun };
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun /* NetLabel Generic NETLINK CIPSOv4 family */
49*4882a593Smuzhiyun static struct genl_family netlbl_mgmt_gnl_family;
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun /* NetLabel Netlink attribute policy */
52*4882a593Smuzhiyun static const struct nla_policy netlbl_mgmt_genl_policy[NLBL_MGMT_A_MAX + 1] = {
53*4882a593Smuzhiyun [NLBL_MGMT_A_DOMAIN] = { .type = NLA_NUL_STRING },
54*4882a593Smuzhiyun [NLBL_MGMT_A_PROTOCOL] = { .type = NLA_U32 },
55*4882a593Smuzhiyun [NLBL_MGMT_A_VERSION] = { .type = NLA_U32 },
56*4882a593Smuzhiyun [NLBL_MGMT_A_CV4DOI] = { .type = NLA_U32 },
57*4882a593Smuzhiyun [NLBL_MGMT_A_FAMILY] = { .type = NLA_U16 },
58*4882a593Smuzhiyun [NLBL_MGMT_A_CLPDOI] = { .type = NLA_U32 },
59*4882a593Smuzhiyun };
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun /*
62*4882a593Smuzhiyun * Helper Functions
63*4882a593Smuzhiyun */
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun /**
66*4882a593Smuzhiyun * netlbl_mgmt_add - Handle an ADD message
67*4882a593Smuzhiyun * @info: the Generic NETLINK info block
68*4882a593Smuzhiyun * @audit_info: NetLabel audit information
69*4882a593Smuzhiyun *
70*4882a593Smuzhiyun * Description:
71*4882a593Smuzhiyun * Helper function for the ADD and ADDDEF messages to add the domain mappings
72*4882a593Smuzhiyun * from the message to the hash table. See netlabel.h for a description of the
73*4882a593Smuzhiyun * message format. Returns zero on success, negative values on failure.
74*4882a593Smuzhiyun *
75*4882a593Smuzhiyun */
netlbl_mgmt_add_common(struct genl_info * info,struct netlbl_audit * audit_info)76*4882a593Smuzhiyun static int netlbl_mgmt_add_common(struct genl_info *info,
77*4882a593Smuzhiyun struct netlbl_audit *audit_info)
78*4882a593Smuzhiyun {
79*4882a593Smuzhiyun void *pmap = NULL;
80*4882a593Smuzhiyun int ret_val = -EINVAL;
81*4882a593Smuzhiyun struct netlbl_domaddr_map *addrmap = NULL;
82*4882a593Smuzhiyun struct cipso_v4_doi *cipsov4 = NULL;
83*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_IPV6)
84*4882a593Smuzhiyun struct calipso_doi *calipso = NULL;
85*4882a593Smuzhiyun #endif
86*4882a593Smuzhiyun u32 tmp_val;
87*4882a593Smuzhiyun struct netlbl_dom_map *entry = kzalloc(sizeof(*entry), GFP_KERNEL);
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun if (!entry)
90*4882a593Smuzhiyun return -ENOMEM;
91*4882a593Smuzhiyun entry->def.type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]);
92*4882a593Smuzhiyun if (info->attrs[NLBL_MGMT_A_DOMAIN]) {
93*4882a593Smuzhiyun size_t tmp_size = nla_len(info->attrs[NLBL_MGMT_A_DOMAIN]);
94*4882a593Smuzhiyun entry->domain = kmalloc(tmp_size, GFP_KERNEL);
95*4882a593Smuzhiyun if (entry->domain == NULL) {
96*4882a593Smuzhiyun ret_val = -ENOMEM;
97*4882a593Smuzhiyun goto add_free_entry;
98*4882a593Smuzhiyun }
99*4882a593Smuzhiyun nla_strlcpy(entry->domain,
100*4882a593Smuzhiyun info->attrs[NLBL_MGMT_A_DOMAIN], tmp_size);
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun /* NOTE: internally we allow/use a entry->def.type value of
104*4882a593Smuzhiyun * NETLBL_NLTYPE_ADDRSELECT but we don't currently allow users
105*4882a593Smuzhiyun * to pass that as a protocol value because we need to know the
106*4882a593Smuzhiyun * "real" protocol */
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun switch (entry->def.type) {
109*4882a593Smuzhiyun case NETLBL_NLTYPE_UNLABELED:
110*4882a593Smuzhiyun if (info->attrs[NLBL_MGMT_A_FAMILY])
111*4882a593Smuzhiyun entry->family =
112*4882a593Smuzhiyun nla_get_u16(info->attrs[NLBL_MGMT_A_FAMILY]);
113*4882a593Smuzhiyun else
114*4882a593Smuzhiyun entry->family = AF_UNSPEC;
115*4882a593Smuzhiyun break;
116*4882a593Smuzhiyun case NETLBL_NLTYPE_CIPSOV4:
117*4882a593Smuzhiyun if (!info->attrs[NLBL_MGMT_A_CV4DOI])
118*4882a593Smuzhiyun goto add_free_domain;
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]);
121*4882a593Smuzhiyun cipsov4 = cipso_v4_doi_getdef(tmp_val);
122*4882a593Smuzhiyun if (cipsov4 == NULL)
123*4882a593Smuzhiyun goto add_free_domain;
124*4882a593Smuzhiyun entry->family = AF_INET;
125*4882a593Smuzhiyun entry->def.cipso = cipsov4;
126*4882a593Smuzhiyun break;
127*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_IPV6)
128*4882a593Smuzhiyun case NETLBL_NLTYPE_CALIPSO:
129*4882a593Smuzhiyun if (!info->attrs[NLBL_MGMT_A_CLPDOI])
130*4882a593Smuzhiyun goto add_free_domain;
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CLPDOI]);
133*4882a593Smuzhiyun calipso = calipso_doi_getdef(tmp_val);
134*4882a593Smuzhiyun if (calipso == NULL)
135*4882a593Smuzhiyun goto add_free_domain;
136*4882a593Smuzhiyun entry->family = AF_INET6;
137*4882a593Smuzhiyun entry->def.calipso = calipso;
138*4882a593Smuzhiyun break;
139*4882a593Smuzhiyun #endif /* IPv6 */
140*4882a593Smuzhiyun default:
141*4882a593Smuzhiyun goto add_free_domain;
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun if ((entry->family == AF_INET && info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
145*4882a593Smuzhiyun (entry->family == AF_INET6 && info->attrs[NLBL_MGMT_A_IPV4ADDR]))
146*4882a593Smuzhiyun goto add_doi_put_def;
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun if (info->attrs[NLBL_MGMT_A_IPV4ADDR]) {
149*4882a593Smuzhiyun struct in_addr *addr;
150*4882a593Smuzhiyun struct in_addr *mask;
151*4882a593Smuzhiyun struct netlbl_domaddr4_map *map;
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL);
154*4882a593Smuzhiyun if (addrmap == NULL) {
155*4882a593Smuzhiyun ret_val = -ENOMEM;
156*4882a593Smuzhiyun goto add_doi_put_def;
157*4882a593Smuzhiyun }
158*4882a593Smuzhiyun INIT_LIST_HEAD(&addrmap->list4);
159*4882a593Smuzhiyun INIT_LIST_HEAD(&addrmap->list6);
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun if (nla_len(info->attrs[NLBL_MGMT_A_IPV4ADDR]) !=
162*4882a593Smuzhiyun sizeof(struct in_addr)) {
163*4882a593Smuzhiyun ret_val = -EINVAL;
164*4882a593Smuzhiyun goto add_free_addrmap;
165*4882a593Smuzhiyun }
166*4882a593Smuzhiyun if (nla_len(info->attrs[NLBL_MGMT_A_IPV4MASK]) !=
167*4882a593Smuzhiyun sizeof(struct in_addr)) {
168*4882a593Smuzhiyun ret_val = -EINVAL;
169*4882a593Smuzhiyun goto add_free_addrmap;
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun addr = nla_data(info->attrs[NLBL_MGMT_A_IPV4ADDR]);
172*4882a593Smuzhiyun mask = nla_data(info->attrs[NLBL_MGMT_A_IPV4MASK]);
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun map = kzalloc(sizeof(*map), GFP_KERNEL);
175*4882a593Smuzhiyun if (map == NULL) {
176*4882a593Smuzhiyun ret_val = -ENOMEM;
177*4882a593Smuzhiyun goto add_free_addrmap;
178*4882a593Smuzhiyun }
179*4882a593Smuzhiyun pmap = map;
180*4882a593Smuzhiyun map->list.addr = addr->s_addr & mask->s_addr;
181*4882a593Smuzhiyun map->list.mask = mask->s_addr;
182*4882a593Smuzhiyun map->list.valid = 1;
183*4882a593Smuzhiyun map->def.type = entry->def.type;
184*4882a593Smuzhiyun if (cipsov4)
185*4882a593Smuzhiyun map->def.cipso = cipsov4;
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun ret_val = netlbl_af4list_add(&map->list, &addrmap->list4);
188*4882a593Smuzhiyun if (ret_val != 0)
189*4882a593Smuzhiyun goto add_free_map;
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun entry->family = AF_INET;
192*4882a593Smuzhiyun entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
193*4882a593Smuzhiyun entry->def.addrsel = addrmap;
194*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_IPV6)
195*4882a593Smuzhiyun } else if (info->attrs[NLBL_MGMT_A_IPV6ADDR]) {
196*4882a593Smuzhiyun struct in6_addr *addr;
197*4882a593Smuzhiyun struct in6_addr *mask;
198*4882a593Smuzhiyun struct netlbl_domaddr6_map *map;
199*4882a593Smuzhiyun
200*4882a593Smuzhiyun addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL);
201*4882a593Smuzhiyun if (addrmap == NULL) {
202*4882a593Smuzhiyun ret_val = -ENOMEM;
203*4882a593Smuzhiyun goto add_doi_put_def;
204*4882a593Smuzhiyun }
205*4882a593Smuzhiyun INIT_LIST_HEAD(&addrmap->list4);
206*4882a593Smuzhiyun INIT_LIST_HEAD(&addrmap->list6);
207*4882a593Smuzhiyun
208*4882a593Smuzhiyun if (nla_len(info->attrs[NLBL_MGMT_A_IPV6ADDR]) !=
209*4882a593Smuzhiyun sizeof(struct in6_addr)) {
210*4882a593Smuzhiyun ret_val = -EINVAL;
211*4882a593Smuzhiyun goto add_free_addrmap;
212*4882a593Smuzhiyun }
213*4882a593Smuzhiyun if (nla_len(info->attrs[NLBL_MGMT_A_IPV6MASK]) !=
214*4882a593Smuzhiyun sizeof(struct in6_addr)) {
215*4882a593Smuzhiyun ret_val = -EINVAL;
216*4882a593Smuzhiyun goto add_free_addrmap;
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun addr = nla_data(info->attrs[NLBL_MGMT_A_IPV6ADDR]);
219*4882a593Smuzhiyun mask = nla_data(info->attrs[NLBL_MGMT_A_IPV6MASK]);
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun map = kzalloc(sizeof(*map), GFP_KERNEL);
222*4882a593Smuzhiyun if (map == NULL) {
223*4882a593Smuzhiyun ret_val = -ENOMEM;
224*4882a593Smuzhiyun goto add_free_addrmap;
225*4882a593Smuzhiyun }
226*4882a593Smuzhiyun pmap = map;
227*4882a593Smuzhiyun map->list.addr = *addr;
228*4882a593Smuzhiyun map->list.addr.s6_addr32[0] &= mask->s6_addr32[0];
229*4882a593Smuzhiyun map->list.addr.s6_addr32[1] &= mask->s6_addr32[1];
230*4882a593Smuzhiyun map->list.addr.s6_addr32[2] &= mask->s6_addr32[2];
231*4882a593Smuzhiyun map->list.addr.s6_addr32[3] &= mask->s6_addr32[3];
232*4882a593Smuzhiyun map->list.mask = *mask;
233*4882a593Smuzhiyun map->list.valid = 1;
234*4882a593Smuzhiyun map->def.type = entry->def.type;
235*4882a593Smuzhiyun if (calipso)
236*4882a593Smuzhiyun map->def.calipso = calipso;
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun ret_val = netlbl_af6list_add(&map->list, &addrmap->list6);
239*4882a593Smuzhiyun if (ret_val != 0)
240*4882a593Smuzhiyun goto add_free_map;
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun entry->family = AF_INET6;
243*4882a593Smuzhiyun entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
244*4882a593Smuzhiyun entry->def.addrsel = addrmap;
245*4882a593Smuzhiyun #endif /* IPv6 */
246*4882a593Smuzhiyun }
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun ret_val = netlbl_domhsh_add(entry, audit_info);
249*4882a593Smuzhiyun if (ret_val != 0)
250*4882a593Smuzhiyun goto add_free_map;
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun return 0;
253*4882a593Smuzhiyun
254*4882a593Smuzhiyun add_free_map:
255*4882a593Smuzhiyun kfree(pmap);
256*4882a593Smuzhiyun add_free_addrmap:
257*4882a593Smuzhiyun kfree(addrmap);
258*4882a593Smuzhiyun add_doi_put_def:
259*4882a593Smuzhiyun cipso_v4_doi_putdef(cipsov4);
260*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_IPV6)
261*4882a593Smuzhiyun calipso_doi_putdef(calipso);
262*4882a593Smuzhiyun #endif
263*4882a593Smuzhiyun add_free_domain:
264*4882a593Smuzhiyun kfree(entry->domain);
265*4882a593Smuzhiyun add_free_entry:
266*4882a593Smuzhiyun kfree(entry);
267*4882a593Smuzhiyun return ret_val;
268*4882a593Smuzhiyun }
269*4882a593Smuzhiyun
270*4882a593Smuzhiyun /**
271*4882a593Smuzhiyun * netlbl_mgmt_listentry - List a NetLabel/LSM domain map entry
272*4882a593Smuzhiyun * @skb: the NETLINK buffer
273*4882a593Smuzhiyun * @entry: the map entry
274*4882a593Smuzhiyun *
275*4882a593Smuzhiyun * Description:
276*4882a593Smuzhiyun * This function is a helper function used by the LISTALL and LISTDEF command
277*4882a593Smuzhiyun * handlers. The caller is responsible for ensuring that the RCU read lock
278*4882a593Smuzhiyun * is held. Returns zero on success, negative values on failure.
279*4882a593Smuzhiyun *
280*4882a593Smuzhiyun */
netlbl_mgmt_listentry(struct sk_buff * skb,struct netlbl_dom_map * entry)281*4882a593Smuzhiyun static int netlbl_mgmt_listentry(struct sk_buff *skb,
282*4882a593Smuzhiyun struct netlbl_dom_map *entry)
283*4882a593Smuzhiyun {
284*4882a593Smuzhiyun int ret_val = 0;
285*4882a593Smuzhiyun struct nlattr *nla_a;
286*4882a593Smuzhiyun struct nlattr *nla_b;
287*4882a593Smuzhiyun struct netlbl_af4list *iter4;
288*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_IPV6)
289*4882a593Smuzhiyun struct netlbl_af6list *iter6;
290*4882a593Smuzhiyun #endif
291*4882a593Smuzhiyun
292*4882a593Smuzhiyun if (entry->domain != NULL) {
293*4882a593Smuzhiyun ret_val = nla_put_string(skb,
294*4882a593Smuzhiyun NLBL_MGMT_A_DOMAIN, entry->domain);
295*4882a593Smuzhiyun if (ret_val != 0)
296*4882a593Smuzhiyun return ret_val;
297*4882a593Smuzhiyun }
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun ret_val = nla_put_u16(skb, NLBL_MGMT_A_FAMILY, entry->family);
300*4882a593Smuzhiyun if (ret_val != 0)
301*4882a593Smuzhiyun return ret_val;
302*4882a593Smuzhiyun
303*4882a593Smuzhiyun switch (entry->def.type) {
304*4882a593Smuzhiyun case NETLBL_NLTYPE_ADDRSELECT:
305*4882a593Smuzhiyun nla_a = nla_nest_start_noflag(skb, NLBL_MGMT_A_SELECTORLIST);
306*4882a593Smuzhiyun if (nla_a == NULL)
307*4882a593Smuzhiyun return -ENOMEM;
308*4882a593Smuzhiyun
309*4882a593Smuzhiyun netlbl_af4list_foreach_rcu(iter4, &entry->def.addrsel->list4) {
310*4882a593Smuzhiyun struct netlbl_domaddr4_map *map4;
311*4882a593Smuzhiyun struct in_addr addr_struct;
312*4882a593Smuzhiyun
313*4882a593Smuzhiyun nla_b = nla_nest_start_noflag(skb,
314*4882a593Smuzhiyun NLBL_MGMT_A_ADDRSELECTOR);
315*4882a593Smuzhiyun if (nla_b == NULL)
316*4882a593Smuzhiyun return -ENOMEM;
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun addr_struct.s_addr = iter4->addr;
319*4882a593Smuzhiyun ret_val = nla_put_in_addr(skb, NLBL_MGMT_A_IPV4ADDR,
320*4882a593Smuzhiyun addr_struct.s_addr);
321*4882a593Smuzhiyun if (ret_val != 0)
322*4882a593Smuzhiyun return ret_val;
323*4882a593Smuzhiyun addr_struct.s_addr = iter4->mask;
324*4882a593Smuzhiyun ret_val = nla_put_in_addr(skb, NLBL_MGMT_A_IPV4MASK,
325*4882a593Smuzhiyun addr_struct.s_addr);
326*4882a593Smuzhiyun if (ret_val != 0)
327*4882a593Smuzhiyun return ret_val;
328*4882a593Smuzhiyun map4 = netlbl_domhsh_addr4_entry(iter4);
329*4882a593Smuzhiyun ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
330*4882a593Smuzhiyun map4->def.type);
331*4882a593Smuzhiyun if (ret_val != 0)
332*4882a593Smuzhiyun return ret_val;
333*4882a593Smuzhiyun switch (map4->def.type) {
334*4882a593Smuzhiyun case NETLBL_NLTYPE_CIPSOV4:
335*4882a593Smuzhiyun ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI,
336*4882a593Smuzhiyun map4->def.cipso->doi);
337*4882a593Smuzhiyun if (ret_val != 0)
338*4882a593Smuzhiyun return ret_val;
339*4882a593Smuzhiyun break;
340*4882a593Smuzhiyun }
341*4882a593Smuzhiyun
342*4882a593Smuzhiyun nla_nest_end(skb, nla_b);
343*4882a593Smuzhiyun }
344*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_IPV6)
345*4882a593Smuzhiyun netlbl_af6list_foreach_rcu(iter6, &entry->def.addrsel->list6) {
346*4882a593Smuzhiyun struct netlbl_domaddr6_map *map6;
347*4882a593Smuzhiyun
348*4882a593Smuzhiyun nla_b = nla_nest_start_noflag(skb,
349*4882a593Smuzhiyun NLBL_MGMT_A_ADDRSELECTOR);
350*4882a593Smuzhiyun if (nla_b == NULL)
351*4882a593Smuzhiyun return -ENOMEM;
352*4882a593Smuzhiyun
353*4882a593Smuzhiyun ret_val = nla_put_in6_addr(skb, NLBL_MGMT_A_IPV6ADDR,
354*4882a593Smuzhiyun &iter6->addr);
355*4882a593Smuzhiyun if (ret_val != 0)
356*4882a593Smuzhiyun return ret_val;
357*4882a593Smuzhiyun ret_val = nla_put_in6_addr(skb, NLBL_MGMT_A_IPV6MASK,
358*4882a593Smuzhiyun &iter6->mask);
359*4882a593Smuzhiyun if (ret_val != 0)
360*4882a593Smuzhiyun return ret_val;
361*4882a593Smuzhiyun map6 = netlbl_domhsh_addr6_entry(iter6);
362*4882a593Smuzhiyun ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
363*4882a593Smuzhiyun map6->def.type);
364*4882a593Smuzhiyun if (ret_val != 0)
365*4882a593Smuzhiyun return ret_val;
366*4882a593Smuzhiyun
367*4882a593Smuzhiyun switch (map6->def.type) {
368*4882a593Smuzhiyun case NETLBL_NLTYPE_CALIPSO:
369*4882a593Smuzhiyun ret_val = nla_put_u32(skb, NLBL_MGMT_A_CLPDOI,
370*4882a593Smuzhiyun map6->def.calipso->doi);
371*4882a593Smuzhiyun if (ret_val != 0)
372*4882a593Smuzhiyun return ret_val;
373*4882a593Smuzhiyun break;
374*4882a593Smuzhiyun }
375*4882a593Smuzhiyun
376*4882a593Smuzhiyun nla_nest_end(skb, nla_b);
377*4882a593Smuzhiyun }
378*4882a593Smuzhiyun #endif /* IPv6 */
379*4882a593Smuzhiyun
380*4882a593Smuzhiyun nla_nest_end(skb, nla_a);
381*4882a593Smuzhiyun break;
382*4882a593Smuzhiyun case NETLBL_NLTYPE_UNLABELED:
383*4882a593Smuzhiyun ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
384*4882a593Smuzhiyun entry->def.type);
385*4882a593Smuzhiyun break;
386*4882a593Smuzhiyun case NETLBL_NLTYPE_CIPSOV4:
387*4882a593Smuzhiyun ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
388*4882a593Smuzhiyun entry->def.type);
389*4882a593Smuzhiyun if (ret_val != 0)
390*4882a593Smuzhiyun return ret_val;
391*4882a593Smuzhiyun ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI,
392*4882a593Smuzhiyun entry->def.cipso->doi);
393*4882a593Smuzhiyun break;
394*4882a593Smuzhiyun case NETLBL_NLTYPE_CALIPSO:
395*4882a593Smuzhiyun ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
396*4882a593Smuzhiyun entry->def.type);
397*4882a593Smuzhiyun if (ret_val != 0)
398*4882a593Smuzhiyun return ret_val;
399*4882a593Smuzhiyun ret_val = nla_put_u32(skb, NLBL_MGMT_A_CLPDOI,
400*4882a593Smuzhiyun entry->def.calipso->doi);
401*4882a593Smuzhiyun break;
402*4882a593Smuzhiyun }
403*4882a593Smuzhiyun
404*4882a593Smuzhiyun return ret_val;
405*4882a593Smuzhiyun }
406*4882a593Smuzhiyun
407*4882a593Smuzhiyun /*
408*4882a593Smuzhiyun * NetLabel Command Handlers
409*4882a593Smuzhiyun */
410*4882a593Smuzhiyun
411*4882a593Smuzhiyun /**
412*4882a593Smuzhiyun * netlbl_mgmt_add - Handle an ADD message
413*4882a593Smuzhiyun * @skb: the NETLINK buffer
414*4882a593Smuzhiyun * @info: the Generic NETLINK info block
415*4882a593Smuzhiyun *
416*4882a593Smuzhiyun * Description:
417*4882a593Smuzhiyun * Process a user generated ADD message and add the domains from the message
418*4882a593Smuzhiyun * to the hash table. See netlabel.h for a description of the message format.
419*4882a593Smuzhiyun * Returns zero on success, negative values on failure.
420*4882a593Smuzhiyun *
421*4882a593Smuzhiyun */
netlbl_mgmt_add(struct sk_buff * skb,struct genl_info * info)422*4882a593Smuzhiyun static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info)
423*4882a593Smuzhiyun {
424*4882a593Smuzhiyun struct netlbl_audit audit_info;
425*4882a593Smuzhiyun
426*4882a593Smuzhiyun if ((!info->attrs[NLBL_MGMT_A_DOMAIN]) ||
427*4882a593Smuzhiyun (!info->attrs[NLBL_MGMT_A_PROTOCOL]) ||
428*4882a593Smuzhiyun (info->attrs[NLBL_MGMT_A_IPV4ADDR] &&
429*4882a593Smuzhiyun info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
430*4882a593Smuzhiyun (info->attrs[NLBL_MGMT_A_IPV4MASK] &&
431*4882a593Smuzhiyun info->attrs[NLBL_MGMT_A_IPV6MASK]) ||
432*4882a593Smuzhiyun ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^
433*4882a593Smuzhiyun (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) ||
434*4882a593Smuzhiyun ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^
435*4882a593Smuzhiyun (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL)))
436*4882a593Smuzhiyun return -EINVAL;
437*4882a593Smuzhiyun
438*4882a593Smuzhiyun netlbl_netlink_auditinfo(skb, &audit_info);
439*4882a593Smuzhiyun
440*4882a593Smuzhiyun return netlbl_mgmt_add_common(info, &audit_info);
441*4882a593Smuzhiyun }
442*4882a593Smuzhiyun
443*4882a593Smuzhiyun /**
444*4882a593Smuzhiyun * netlbl_mgmt_remove - Handle a REMOVE message
445*4882a593Smuzhiyun * @skb: the NETLINK buffer
446*4882a593Smuzhiyun * @info: the Generic NETLINK info block
447*4882a593Smuzhiyun *
448*4882a593Smuzhiyun * Description:
449*4882a593Smuzhiyun * Process a user generated REMOVE message and remove the specified domain
450*4882a593Smuzhiyun * mappings. Returns zero on success, negative values on failure.
451*4882a593Smuzhiyun *
452*4882a593Smuzhiyun */
netlbl_mgmt_remove(struct sk_buff * skb,struct genl_info * info)453*4882a593Smuzhiyun static int netlbl_mgmt_remove(struct sk_buff *skb, struct genl_info *info)
454*4882a593Smuzhiyun {
455*4882a593Smuzhiyun char *domain;
456*4882a593Smuzhiyun struct netlbl_audit audit_info;
457*4882a593Smuzhiyun
458*4882a593Smuzhiyun if (!info->attrs[NLBL_MGMT_A_DOMAIN])
459*4882a593Smuzhiyun return -EINVAL;
460*4882a593Smuzhiyun
461*4882a593Smuzhiyun netlbl_netlink_auditinfo(skb, &audit_info);
462*4882a593Smuzhiyun
463*4882a593Smuzhiyun domain = nla_data(info->attrs[NLBL_MGMT_A_DOMAIN]);
464*4882a593Smuzhiyun return netlbl_domhsh_remove(domain, AF_UNSPEC, &audit_info);
465*4882a593Smuzhiyun }
466*4882a593Smuzhiyun
467*4882a593Smuzhiyun /**
468*4882a593Smuzhiyun * netlbl_mgmt_listall_cb - netlbl_domhsh_walk() callback for LISTALL
469*4882a593Smuzhiyun * @entry: the domain mapping hash table entry
470*4882a593Smuzhiyun * @arg: the netlbl_domhsh_walk_arg structure
471*4882a593Smuzhiyun *
472*4882a593Smuzhiyun * Description:
473*4882a593Smuzhiyun * This function is designed to be used as a callback to the
474*4882a593Smuzhiyun * netlbl_domhsh_walk() function for use in generating a response for a LISTALL
475*4882a593Smuzhiyun * message. Returns the size of the message on success, negative values on
476*4882a593Smuzhiyun * failure.
477*4882a593Smuzhiyun *
478*4882a593Smuzhiyun */
netlbl_mgmt_listall_cb(struct netlbl_dom_map * entry,void * arg)479*4882a593Smuzhiyun static int netlbl_mgmt_listall_cb(struct netlbl_dom_map *entry, void *arg)
480*4882a593Smuzhiyun {
481*4882a593Smuzhiyun int ret_val = -ENOMEM;
482*4882a593Smuzhiyun struct netlbl_domhsh_walk_arg *cb_arg = arg;
483*4882a593Smuzhiyun void *data;
484*4882a593Smuzhiyun
485*4882a593Smuzhiyun data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).portid,
486*4882a593Smuzhiyun cb_arg->seq, &netlbl_mgmt_gnl_family,
487*4882a593Smuzhiyun NLM_F_MULTI, NLBL_MGMT_C_LISTALL);
488*4882a593Smuzhiyun if (data == NULL)
489*4882a593Smuzhiyun goto listall_cb_failure;
490*4882a593Smuzhiyun
491*4882a593Smuzhiyun ret_val = netlbl_mgmt_listentry(cb_arg->skb, entry);
492*4882a593Smuzhiyun if (ret_val != 0)
493*4882a593Smuzhiyun goto listall_cb_failure;
494*4882a593Smuzhiyun
495*4882a593Smuzhiyun cb_arg->seq++;
496*4882a593Smuzhiyun genlmsg_end(cb_arg->skb, data);
497*4882a593Smuzhiyun return 0;
498*4882a593Smuzhiyun
499*4882a593Smuzhiyun listall_cb_failure:
500*4882a593Smuzhiyun genlmsg_cancel(cb_arg->skb, data);
501*4882a593Smuzhiyun return ret_val;
502*4882a593Smuzhiyun }
503*4882a593Smuzhiyun
504*4882a593Smuzhiyun /**
505*4882a593Smuzhiyun * netlbl_mgmt_listall - Handle a LISTALL message
506*4882a593Smuzhiyun * @skb: the NETLINK buffer
507*4882a593Smuzhiyun * @cb: the NETLINK callback
508*4882a593Smuzhiyun *
509*4882a593Smuzhiyun * Description:
510*4882a593Smuzhiyun * Process a user generated LISTALL message and dumps the domain hash table in
511*4882a593Smuzhiyun * a form suitable for use in a kernel generated LISTALL message. Returns zero
512*4882a593Smuzhiyun * on success, negative values on failure.
513*4882a593Smuzhiyun *
514*4882a593Smuzhiyun */
netlbl_mgmt_listall(struct sk_buff * skb,struct netlink_callback * cb)515*4882a593Smuzhiyun static int netlbl_mgmt_listall(struct sk_buff *skb,
516*4882a593Smuzhiyun struct netlink_callback *cb)
517*4882a593Smuzhiyun {
518*4882a593Smuzhiyun struct netlbl_domhsh_walk_arg cb_arg;
519*4882a593Smuzhiyun u32 skip_bkt = cb->args[0];
520*4882a593Smuzhiyun u32 skip_chain = cb->args[1];
521*4882a593Smuzhiyun
522*4882a593Smuzhiyun cb_arg.nl_cb = cb;
523*4882a593Smuzhiyun cb_arg.skb = skb;
524*4882a593Smuzhiyun cb_arg.seq = cb->nlh->nlmsg_seq;
525*4882a593Smuzhiyun
526*4882a593Smuzhiyun netlbl_domhsh_walk(&skip_bkt,
527*4882a593Smuzhiyun &skip_chain,
528*4882a593Smuzhiyun netlbl_mgmt_listall_cb,
529*4882a593Smuzhiyun &cb_arg);
530*4882a593Smuzhiyun
531*4882a593Smuzhiyun cb->args[0] = skip_bkt;
532*4882a593Smuzhiyun cb->args[1] = skip_chain;
533*4882a593Smuzhiyun return skb->len;
534*4882a593Smuzhiyun }
535*4882a593Smuzhiyun
536*4882a593Smuzhiyun /**
537*4882a593Smuzhiyun * netlbl_mgmt_adddef - Handle an ADDDEF message
538*4882a593Smuzhiyun * @skb: the NETLINK buffer
539*4882a593Smuzhiyun * @info: the Generic NETLINK info block
540*4882a593Smuzhiyun *
541*4882a593Smuzhiyun * Description:
542*4882a593Smuzhiyun * Process a user generated ADDDEF message and respond accordingly. Returns
543*4882a593Smuzhiyun * zero on success, negative values on failure.
544*4882a593Smuzhiyun *
545*4882a593Smuzhiyun */
netlbl_mgmt_adddef(struct sk_buff * skb,struct genl_info * info)546*4882a593Smuzhiyun static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info)
547*4882a593Smuzhiyun {
548*4882a593Smuzhiyun struct netlbl_audit audit_info;
549*4882a593Smuzhiyun
550*4882a593Smuzhiyun if ((!info->attrs[NLBL_MGMT_A_PROTOCOL]) ||
551*4882a593Smuzhiyun (info->attrs[NLBL_MGMT_A_IPV4ADDR] &&
552*4882a593Smuzhiyun info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
553*4882a593Smuzhiyun (info->attrs[NLBL_MGMT_A_IPV4MASK] &&
554*4882a593Smuzhiyun info->attrs[NLBL_MGMT_A_IPV6MASK]) ||
555*4882a593Smuzhiyun ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^
556*4882a593Smuzhiyun (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) ||
557*4882a593Smuzhiyun ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^
558*4882a593Smuzhiyun (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL)))
559*4882a593Smuzhiyun return -EINVAL;
560*4882a593Smuzhiyun
561*4882a593Smuzhiyun netlbl_netlink_auditinfo(skb, &audit_info);
562*4882a593Smuzhiyun
563*4882a593Smuzhiyun return netlbl_mgmt_add_common(info, &audit_info);
564*4882a593Smuzhiyun }
565*4882a593Smuzhiyun
566*4882a593Smuzhiyun /**
567*4882a593Smuzhiyun * netlbl_mgmt_removedef - Handle a REMOVEDEF message
568*4882a593Smuzhiyun * @skb: the NETLINK buffer
569*4882a593Smuzhiyun * @info: the Generic NETLINK info block
570*4882a593Smuzhiyun *
571*4882a593Smuzhiyun * Description:
572*4882a593Smuzhiyun * Process a user generated REMOVEDEF message and remove the default domain
573*4882a593Smuzhiyun * mapping. Returns zero on success, negative values on failure.
574*4882a593Smuzhiyun *
575*4882a593Smuzhiyun */
netlbl_mgmt_removedef(struct sk_buff * skb,struct genl_info * info)576*4882a593Smuzhiyun static int netlbl_mgmt_removedef(struct sk_buff *skb, struct genl_info *info)
577*4882a593Smuzhiyun {
578*4882a593Smuzhiyun struct netlbl_audit audit_info;
579*4882a593Smuzhiyun
580*4882a593Smuzhiyun netlbl_netlink_auditinfo(skb, &audit_info);
581*4882a593Smuzhiyun
582*4882a593Smuzhiyun return netlbl_domhsh_remove_default(AF_UNSPEC, &audit_info);
583*4882a593Smuzhiyun }
584*4882a593Smuzhiyun
585*4882a593Smuzhiyun /**
586*4882a593Smuzhiyun * netlbl_mgmt_listdef - Handle a LISTDEF message
587*4882a593Smuzhiyun * @skb: the NETLINK buffer
588*4882a593Smuzhiyun * @info: the Generic NETLINK info block
589*4882a593Smuzhiyun *
590*4882a593Smuzhiyun * Description:
591*4882a593Smuzhiyun * Process a user generated LISTDEF message and dumps the default domain
592*4882a593Smuzhiyun * mapping in a form suitable for use in a kernel generated LISTDEF message.
593*4882a593Smuzhiyun * Returns zero on success, negative values on failure.
594*4882a593Smuzhiyun *
595*4882a593Smuzhiyun */
netlbl_mgmt_listdef(struct sk_buff * skb,struct genl_info * info)596*4882a593Smuzhiyun static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info)
597*4882a593Smuzhiyun {
598*4882a593Smuzhiyun int ret_val = -ENOMEM;
599*4882a593Smuzhiyun struct sk_buff *ans_skb = NULL;
600*4882a593Smuzhiyun void *data;
601*4882a593Smuzhiyun struct netlbl_dom_map *entry;
602*4882a593Smuzhiyun u16 family;
603*4882a593Smuzhiyun
604*4882a593Smuzhiyun if (info->attrs[NLBL_MGMT_A_FAMILY])
605*4882a593Smuzhiyun family = nla_get_u16(info->attrs[NLBL_MGMT_A_FAMILY]);
606*4882a593Smuzhiyun else
607*4882a593Smuzhiyun family = AF_INET;
608*4882a593Smuzhiyun
609*4882a593Smuzhiyun ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
610*4882a593Smuzhiyun if (ans_skb == NULL)
611*4882a593Smuzhiyun return -ENOMEM;
612*4882a593Smuzhiyun data = genlmsg_put_reply(ans_skb, info, &netlbl_mgmt_gnl_family,
613*4882a593Smuzhiyun 0, NLBL_MGMT_C_LISTDEF);
614*4882a593Smuzhiyun if (data == NULL)
615*4882a593Smuzhiyun goto listdef_failure;
616*4882a593Smuzhiyun
617*4882a593Smuzhiyun rcu_read_lock();
618*4882a593Smuzhiyun entry = netlbl_domhsh_getentry(NULL, family);
619*4882a593Smuzhiyun if (entry == NULL) {
620*4882a593Smuzhiyun ret_val = -ENOENT;
621*4882a593Smuzhiyun goto listdef_failure_lock;
622*4882a593Smuzhiyun }
623*4882a593Smuzhiyun ret_val = netlbl_mgmt_listentry(ans_skb, entry);
624*4882a593Smuzhiyun rcu_read_unlock();
625*4882a593Smuzhiyun if (ret_val != 0)
626*4882a593Smuzhiyun goto listdef_failure;
627*4882a593Smuzhiyun
628*4882a593Smuzhiyun genlmsg_end(ans_skb, data);
629*4882a593Smuzhiyun return genlmsg_reply(ans_skb, info);
630*4882a593Smuzhiyun
631*4882a593Smuzhiyun listdef_failure_lock:
632*4882a593Smuzhiyun rcu_read_unlock();
633*4882a593Smuzhiyun listdef_failure:
634*4882a593Smuzhiyun kfree_skb(ans_skb);
635*4882a593Smuzhiyun return ret_val;
636*4882a593Smuzhiyun }
637*4882a593Smuzhiyun
638*4882a593Smuzhiyun /**
639*4882a593Smuzhiyun * netlbl_mgmt_protocols_cb - Write an individual PROTOCOL message response
640*4882a593Smuzhiyun * @skb: the skb to write to
641*4882a593Smuzhiyun * @cb: the NETLINK callback
642*4882a593Smuzhiyun * @protocol: the NetLabel protocol to use in the message
643*4882a593Smuzhiyun *
644*4882a593Smuzhiyun * Description:
645*4882a593Smuzhiyun * This function is to be used in conjunction with netlbl_mgmt_protocols() to
646*4882a593Smuzhiyun * answer a application's PROTOCOLS message. Returns the size of the message
647*4882a593Smuzhiyun * on success, negative values on failure.
648*4882a593Smuzhiyun *
649*4882a593Smuzhiyun */
netlbl_mgmt_protocols_cb(struct sk_buff * skb,struct netlink_callback * cb,u32 protocol)650*4882a593Smuzhiyun static int netlbl_mgmt_protocols_cb(struct sk_buff *skb,
651*4882a593Smuzhiyun struct netlink_callback *cb,
652*4882a593Smuzhiyun u32 protocol)
653*4882a593Smuzhiyun {
654*4882a593Smuzhiyun int ret_val = -ENOMEM;
655*4882a593Smuzhiyun void *data;
656*4882a593Smuzhiyun
657*4882a593Smuzhiyun data = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
658*4882a593Smuzhiyun &netlbl_mgmt_gnl_family, NLM_F_MULTI,
659*4882a593Smuzhiyun NLBL_MGMT_C_PROTOCOLS);
660*4882a593Smuzhiyun if (data == NULL)
661*4882a593Smuzhiyun goto protocols_cb_failure;
662*4882a593Smuzhiyun
663*4882a593Smuzhiyun ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, protocol);
664*4882a593Smuzhiyun if (ret_val != 0)
665*4882a593Smuzhiyun goto protocols_cb_failure;
666*4882a593Smuzhiyun
667*4882a593Smuzhiyun genlmsg_end(skb, data);
668*4882a593Smuzhiyun return 0;
669*4882a593Smuzhiyun
670*4882a593Smuzhiyun protocols_cb_failure:
671*4882a593Smuzhiyun genlmsg_cancel(skb, data);
672*4882a593Smuzhiyun return ret_val;
673*4882a593Smuzhiyun }
674*4882a593Smuzhiyun
675*4882a593Smuzhiyun /**
676*4882a593Smuzhiyun * netlbl_mgmt_protocols - Handle a PROTOCOLS message
677*4882a593Smuzhiyun * @skb: the NETLINK buffer
678*4882a593Smuzhiyun * @cb: the NETLINK callback
679*4882a593Smuzhiyun *
680*4882a593Smuzhiyun * Description:
681*4882a593Smuzhiyun * Process a user generated PROTOCOLS message and respond accordingly.
682*4882a593Smuzhiyun *
683*4882a593Smuzhiyun */
netlbl_mgmt_protocols(struct sk_buff * skb,struct netlink_callback * cb)684*4882a593Smuzhiyun static int netlbl_mgmt_protocols(struct sk_buff *skb,
685*4882a593Smuzhiyun struct netlink_callback *cb)
686*4882a593Smuzhiyun {
687*4882a593Smuzhiyun u32 protos_sent = cb->args[0];
688*4882a593Smuzhiyun
689*4882a593Smuzhiyun if (protos_sent == 0) {
690*4882a593Smuzhiyun if (netlbl_mgmt_protocols_cb(skb,
691*4882a593Smuzhiyun cb,
692*4882a593Smuzhiyun NETLBL_NLTYPE_UNLABELED) < 0)
693*4882a593Smuzhiyun goto protocols_return;
694*4882a593Smuzhiyun protos_sent++;
695*4882a593Smuzhiyun }
696*4882a593Smuzhiyun if (protos_sent == 1) {
697*4882a593Smuzhiyun if (netlbl_mgmt_protocols_cb(skb,
698*4882a593Smuzhiyun cb,
699*4882a593Smuzhiyun NETLBL_NLTYPE_CIPSOV4) < 0)
700*4882a593Smuzhiyun goto protocols_return;
701*4882a593Smuzhiyun protos_sent++;
702*4882a593Smuzhiyun }
703*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_IPV6)
704*4882a593Smuzhiyun if (protos_sent == 2) {
705*4882a593Smuzhiyun if (netlbl_mgmt_protocols_cb(skb,
706*4882a593Smuzhiyun cb,
707*4882a593Smuzhiyun NETLBL_NLTYPE_CALIPSO) < 0)
708*4882a593Smuzhiyun goto protocols_return;
709*4882a593Smuzhiyun protos_sent++;
710*4882a593Smuzhiyun }
711*4882a593Smuzhiyun #endif
712*4882a593Smuzhiyun
713*4882a593Smuzhiyun protocols_return:
714*4882a593Smuzhiyun cb->args[0] = protos_sent;
715*4882a593Smuzhiyun return skb->len;
716*4882a593Smuzhiyun }
717*4882a593Smuzhiyun
718*4882a593Smuzhiyun /**
719*4882a593Smuzhiyun * netlbl_mgmt_version - Handle a VERSION message
720*4882a593Smuzhiyun * @skb: the NETLINK buffer
721*4882a593Smuzhiyun * @info: the Generic NETLINK info block
722*4882a593Smuzhiyun *
723*4882a593Smuzhiyun * Description:
724*4882a593Smuzhiyun * Process a user generated VERSION message and respond accordingly. Returns
725*4882a593Smuzhiyun * zero on success, negative values on failure.
726*4882a593Smuzhiyun *
727*4882a593Smuzhiyun */
netlbl_mgmt_version(struct sk_buff * skb,struct genl_info * info)728*4882a593Smuzhiyun static int netlbl_mgmt_version(struct sk_buff *skb, struct genl_info *info)
729*4882a593Smuzhiyun {
730*4882a593Smuzhiyun int ret_val = -ENOMEM;
731*4882a593Smuzhiyun struct sk_buff *ans_skb = NULL;
732*4882a593Smuzhiyun void *data;
733*4882a593Smuzhiyun
734*4882a593Smuzhiyun ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
735*4882a593Smuzhiyun if (ans_skb == NULL)
736*4882a593Smuzhiyun return -ENOMEM;
737*4882a593Smuzhiyun data = genlmsg_put_reply(ans_skb, info, &netlbl_mgmt_gnl_family,
738*4882a593Smuzhiyun 0, NLBL_MGMT_C_VERSION);
739*4882a593Smuzhiyun if (data == NULL)
740*4882a593Smuzhiyun goto version_failure;
741*4882a593Smuzhiyun
742*4882a593Smuzhiyun ret_val = nla_put_u32(ans_skb,
743*4882a593Smuzhiyun NLBL_MGMT_A_VERSION,
744*4882a593Smuzhiyun NETLBL_PROTO_VERSION);
745*4882a593Smuzhiyun if (ret_val != 0)
746*4882a593Smuzhiyun goto version_failure;
747*4882a593Smuzhiyun
748*4882a593Smuzhiyun genlmsg_end(ans_skb, data);
749*4882a593Smuzhiyun return genlmsg_reply(ans_skb, info);
750*4882a593Smuzhiyun
751*4882a593Smuzhiyun version_failure:
752*4882a593Smuzhiyun kfree_skb(ans_skb);
753*4882a593Smuzhiyun return ret_val;
754*4882a593Smuzhiyun }
755*4882a593Smuzhiyun
756*4882a593Smuzhiyun
757*4882a593Smuzhiyun /*
758*4882a593Smuzhiyun * NetLabel Generic NETLINK Command Definitions
759*4882a593Smuzhiyun */
760*4882a593Smuzhiyun
761*4882a593Smuzhiyun static const struct genl_small_ops netlbl_mgmt_genl_ops[] = {
762*4882a593Smuzhiyun {
763*4882a593Smuzhiyun .cmd = NLBL_MGMT_C_ADD,
764*4882a593Smuzhiyun .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
765*4882a593Smuzhiyun .flags = GENL_ADMIN_PERM,
766*4882a593Smuzhiyun .doit = netlbl_mgmt_add,
767*4882a593Smuzhiyun .dumpit = NULL,
768*4882a593Smuzhiyun },
769*4882a593Smuzhiyun {
770*4882a593Smuzhiyun .cmd = NLBL_MGMT_C_REMOVE,
771*4882a593Smuzhiyun .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
772*4882a593Smuzhiyun .flags = GENL_ADMIN_PERM,
773*4882a593Smuzhiyun .doit = netlbl_mgmt_remove,
774*4882a593Smuzhiyun .dumpit = NULL,
775*4882a593Smuzhiyun },
776*4882a593Smuzhiyun {
777*4882a593Smuzhiyun .cmd = NLBL_MGMT_C_LISTALL,
778*4882a593Smuzhiyun .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
779*4882a593Smuzhiyun .flags = 0,
780*4882a593Smuzhiyun .doit = NULL,
781*4882a593Smuzhiyun .dumpit = netlbl_mgmt_listall,
782*4882a593Smuzhiyun },
783*4882a593Smuzhiyun {
784*4882a593Smuzhiyun .cmd = NLBL_MGMT_C_ADDDEF,
785*4882a593Smuzhiyun .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
786*4882a593Smuzhiyun .flags = GENL_ADMIN_PERM,
787*4882a593Smuzhiyun .doit = netlbl_mgmt_adddef,
788*4882a593Smuzhiyun .dumpit = NULL,
789*4882a593Smuzhiyun },
790*4882a593Smuzhiyun {
791*4882a593Smuzhiyun .cmd = NLBL_MGMT_C_REMOVEDEF,
792*4882a593Smuzhiyun .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
793*4882a593Smuzhiyun .flags = GENL_ADMIN_PERM,
794*4882a593Smuzhiyun .doit = netlbl_mgmt_removedef,
795*4882a593Smuzhiyun .dumpit = NULL,
796*4882a593Smuzhiyun },
797*4882a593Smuzhiyun {
798*4882a593Smuzhiyun .cmd = NLBL_MGMT_C_LISTDEF,
799*4882a593Smuzhiyun .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
800*4882a593Smuzhiyun .flags = 0,
801*4882a593Smuzhiyun .doit = netlbl_mgmt_listdef,
802*4882a593Smuzhiyun .dumpit = NULL,
803*4882a593Smuzhiyun },
804*4882a593Smuzhiyun {
805*4882a593Smuzhiyun .cmd = NLBL_MGMT_C_PROTOCOLS,
806*4882a593Smuzhiyun .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
807*4882a593Smuzhiyun .flags = 0,
808*4882a593Smuzhiyun .doit = NULL,
809*4882a593Smuzhiyun .dumpit = netlbl_mgmt_protocols,
810*4882a593Smuzhiyun },
811*4882a593Smuzhiyun {
812*4882a593Smuzhiyun .cmd = NLBL_MGMT_C_VERSION,
813*4882a593Smuzhiyun .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
814*4882a593Smuzhiyun .flags = 0,
815*4882a593Smuzhiyun .doit = netlbl_mgmt_version,
816*4882a593Smuzhiyun .dumpit = NULL,
817*4882a593Smuzhiyun },
818*4882a593Smuzhiyun };
819*4882a593Smuzhiyun
820*4882a593Smuzhiyun static struct genl_family netlbl_mgmt_gnl_family __ro_after_init = {
821*4882a593Smuzhiyun .hdrsize = 0,
822*4882a593Smuzhiyun .name = NETLBL_NLTYPE_MGMT_NAME,
823*4882a593Smuzhiyun .version = NETLBL_PROTO_VERSION,
824*4882a593Smuzhiyun .maxattr = NLBL_MGMT_A_MAX,
825*4882a593Smuzhiyun .policy = netlbl_mgmt_genl_policy,
826*4882a593Smuzhiyun .module = THIS_MODULE,
827*4882a593Smuzhiyun .small_ops = netlbl_mgmt_genl_ops,
828*4882a593Smuzhiyun .n_small_ops = ARRAY_SIZE(netlbl_mgmt_genl_ops),
829*4882a593Smuzhiyun };
830*4882a593Smuzhiyun
831*4882a593Smuzhiyun /*
832*4882a593Smuzhiyun * NetLabel Generic NETLINK Protocol Functions
833*4882a593Smuzhiyun */
834*4882a593Smuzhiyun
835*4882a593Smuzhiyun /**
836*4882a593Smuzhiyun * netlbl_mgmt_genl_init - Register the NetLabel management component
837*4882a593Smuzhiyun *
838*4882a593Smuzhiyun * Description:
839*4882a593Smuzhiyun * Register the NetLabel management component with the Generic NETLINK
840*4882a593Smuzhiyun * mechanism. Returns zero on success, negative values on failure.
841*4882a593Smuzhiyun *
842*4882a593Smuzhiyun */
netlbl_mgmt_genl_init(void)843*4882a593Smuzhiyun int __init netlbl_mgmt_genl_init(void)
844*4882a593Smuzhiyun {
845*4882a593Smuzhiyun return genl_register_family(&netlbl_mgmt_gnl_family);
846*4882a593Smuzhiyun }
847