1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * NetLabel CIPSO/IPv4 Support
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * This file defines the CIPSO/IPv4 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
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/audit.h>
21*4882a593Smuzhiyun #include <linux/slab.h>
22*4882a593Smuzhiyun #include <net/sock.h>
23*4882a593Smuzhiyun #include <net/netlink.h>
24*4882a593Smuzhiyun #include <net/genetlink.h>
25*4882a593Smuzhiyun #include <net/netlabel.h>
26*4882a593Smuzhiyun #include <net/cipso_ipv4.h>
27*4882a593Smuzhiyun #include <linux/atomic.h>
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun #include "netlabel_user.h"
30*4882a593Smuzhiyun #include "netlabel_cipso_v4.h"
31*4882a593Smuzhiyun #include "netlabel_mgmt.h"
32*4882a593Smuzhiyun #include "netlabel_domainhash.h"
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun /* Argument struct for cipso_v4_doi_walk() */
35*4882a593Smuzhiyun struct netlbl_cipsov4_doiwalk_arg {
36*4882a593Smuzhiyun struct netlink_callback *nl_cb;
37*4882a593Smuzhiyun struct sk_buff *skb;
38*4882a593Smuzhiyun u32 seq;
39*4882a593Smuzhiyun };
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun /* Argument struct for netlbl_domhsh_walk() */
42*4882a593Smuzhiyun struct netlbl_domhsh_walk_arg {
43*4882a593Smuzhiyun struct netlbl_audit *audit_info;
44*4882a593Smuzhiyun u32 doi;
45*4882a593Smuzhiyun };
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun /* NetLabel Generic NETLINK CIPSOv4 family */
48*4882a593Smuzhiyun static struct genl_family netlbl_cipsov4_gnl_family;
49*4882a593Smuzhiyun /* NetLabel Netlink attribute policy */
50*4882a593Smuzhiyun static const struct nla_policy netlbl_cipsov4_genl_policy[NLBL_CIPSOV4_A_MAX + 1] = {
51*4882a593Smuzhiyun [NLBL_CIPSOV4_A_DOI] = { .type = NLA_U32 },
52*4882a593Smuzhiyun [NLBL_CIPSOV4_A_MTYPE] = { .type = NLA_U32 },
53*4882a593Smuzhiyun [NLBL_CIPSOV4_A_TAG] = { .type = NLA_U8 },
54*4882a593Smuzhiyun [NLBL_CIPSOV4_A_TAGLST] = { .type = NLA_NESTED },
55*4882a593Smuzhiyun [NLBL_CIPSOV4_A_MLSLVLLOC] = { .type = NLA_U32 },
56*4882a593Smuzhiyun [NLBL_CIPSOV4_A_MLSLVLREM] = { .type = NLA_U32 },
57*4882a593Smuzhiyun [NLBL_CIPSOV4_A_MLSLVL] = { .type = NLA_NESTED },
58*4882a593Smuzhiyun [NLBL_CIPSOV4_A_MLSLVLLST] = { .type = NLA_NESTED },
59*4882a593Smuzhiyun [NLBL_CIPSOV4_A_MLSCATLOC] = { .type = NLA_U32 },
60*4882a593Smuzhiyun [NLBL_CIPSOV4_A_MLSCATREM] = { .type = NLA_U32 },
61*4882a593Smuzhiyun [NLBL_CIPSOV4_A_MLSCAT] = { .type = NLA_NESTED },
62*4882a593Smuzhiyun [NLBL_CIPSOV4_A_MLSCATLST] = { .type = NLA_NESTED },
63*4882a593Smuzhiyun };
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun /*
66*4882a593Smuzhiyun * Helper Functions
67*4882a593Smuzhiyun */
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun /**
70*4882a593Smuzhiyun * netlbl_cipsov4_add_common - Parse the common sections of a ADD message
71*4882a593Smuzhiyun * @info: the Generic NETLINK info block
72*4882a593Smuzhiyun * @doi_def: the CIPSO V4 DOI definition
73*4882a593Smuzhiyun *
74*4882a593Smuzhiyun * Description:
75*4882a593Smuzhiyun * Parse the common sections of a ADD message and fill in the related values
76*4882a593Smuzhiyun * in @doi_def. Returns zero on success, negative values on failure.
77*4882a593Smuzhiyun *
78*4882a593Smuzhiyun */
netlbl_cipsov4_add_common(struct genl_info * info,struct cipso_v4_doi * doi_def)79*4882a593Smuzhiyun static int netlbl_cipsov4_add_common(struct genl_info *info,
80*4882a593Smuzhiyun struct cipso_v4_doi *doi_def)
81*4882a593Smuzhiyun {
82*4882a593Smuzhiyun struct nlattr *nla;
83*4882a593Smuzhiyun int nla_rem;
84*4882a593Smuzhiyun u32 iter = 0;
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun doi_def->doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun if (nla_validate_nested_deprecated(info->attrs[NLBL_CIPSOV4_A_TAGLST],
89*4882a593Smuzhiyun NLBL_CIPSOV4_A_MAX,
90*4882a593Smuzhiyun netlbl_cipsov4_genl_policy,
91*4882a593Smuzhiyun NULL) != 0)
92*4882a593Smuzhiyun return -EINVAL;
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun nla_for_each_nested(nla, info->attrs[NLBL_CIPSOV4_A_TAGLST], nla_rem)
95*4882a593Smuzhiyun if (nla_type(nla) == NLBL_CIPSOV4_A_TAG) {
96*4882a593Smuzhiyun if (iter >= CIPSO_V4_TAG_MAXCNT)
97*4882a593Smuzhiyun return -EINVAL;
98*4882a593Smuzhiyun doi_def->tags[iter++] = nla_get_u8(nla);
99*4882a593Smuzhiyun }
100*4882a593Smuzhiyun while (iter < CIPSO_V4_TAG_MAXCNT)
101*4882a593Smuzhiyun doi_def->tags[iter++] = CIPSO_V4_TAG_INVALID;
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun return 0;
104*4882a593Smuzhiyun }
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun /*
107*4882a593Smuzhiyun * NetLabel Command Handlers
108*4882a593Smuzhiyun */
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun /**
111*4882a593Smuzhiyun * netlbl_cipsov4_add_std - Adds a CIPSO V4 DOI definition
112*4882a593Smuzhiyun * @info: the Generic NETLINK info block
113*4882a593Smuzhiyun * @audit_info: NetLabel audit information
114*4882a593Smuzhiyun *
115*4882a593Smuzhiyun * Description:
116*4882a593Smuzhiyun * Create a new CIPSO_V4_MAP_TRANS DOI definition based on the given ADD
117*4882a593Smuzhiyun * message and add it to the CIPSO V4 engine. Return zero on success and
118*4882a593Smuzhiyun * non-zero on error.
119*4882a593Smuzhiyun *
120*4882a593Smuzhiyun */
netlbl_cipsov4_add_std(struct genl_info * info,struct netlbl_audit * audit_info)121*4882a593Smuzhiyun static int netlbl_cipsov4_add_std(struct genl_info *info,
122*4882a593Smuzhiyun struct netlbl_audit *audit_info)
123*4882a593Smuzhiyun {
124*4882a593Smuzhiyun int ret_val = -EINVAL;
125*4882a593Smuzhiyun struct cipso_v4_doi *doi_def = NULL;
126*4882a593Smuzhiyun struct nlattr *nla_a;
127*4882a593Smuzhiyun struct nlattr *nla_b;
128*4882a593Smuzhiyun int nla_a_rem;
129*4882a593Smuzhiyun int nla_b_rem;
130*4882a593Smuzhiyun u32 iter;
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun if (!info->attrs[NLBL_CIPSOV4_A_TAGLST] ||
133*4882a593Smuzhiyun !info->attrs[NLBL_CIPSOV4_A_MLSLVLLST])
134*4882a593Smuzhiyun return -EINVAL;
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun if (nla_validate_nested_deprecated(info->attrs[NLBL_CIPSOV4_A_MLSLVLLST],
137*4882a593Smuzhiyun NLBL_CIPSOV4_A_MAX,
138*4882a593Smuzhiyun netlbl_cipsov4_genl_policy,
139*4882a593Smuzhiyun NULL) != 0)
140*4882a593Smuzhiyun return -EINVAL;
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
143*4882a593Smuzhiyun if (doi_def == NULL)
144*4882a593Smuzhiyun return -ENOMEM;
145*4882a593Smuzhiyun doi_def->map.std = kzalloc(sizeof(*doi_def->map.std), GFP_KERNEL);
146*4882a593Smuzhiyun if (doi_def->map.std == NULL) {
147*4882a593Smuzhiyun kfree(doi_def);
148*4882a593Smuzhiyun return -ENOMEM;
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun doi_def->type = CIPSO_V4_MAP_TRANS;
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun ret_val = netlbl_cipsov4_add_common(info, doi_def);
153*4882a593Smuzhiyun if (ret_val != 0)
154*4882a593Smuzhiyun goto add_std_failure;
155*4882a593Smuzhiyun ret_val = -EINVAL;
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun nla_for_each_nested(nla_a,
158*4882a593Smuzhiyun info->attrs[NLBL_CIPSOV4_A_MLSLVLLST],
159*4882a593Smuzhiyun nla_a_rem)
160*4882a593Smuzhiyun if (nla_type(nla_a) == NLBL_CIPSOV4_A_MLSLVL) {
161*4882a593Smuzhiyun if (nla_validate_nested_deprecated(nla_a,
162*4882a593Smuzhiyun NLBL_CIPSOV4_A_MAX,
163*4882a593Smuzhiyun netlbl_cipsov4_genl_policy,
164*4882a593Smuzhiyun NULL) != 0)
165*4882a593Smuzhiyun goto add_std_failure;
166*4882a593Smuzhiyun nla_for_each_nested(nla_b, nla_a, nla_b_rem)
167*4882a593Smuzhiyun switch (nla_type(nla_b)) {
168*4882a593Smuzhiyun case NLBL_CIPSOV4_A_MLSLVLLOC:
169*4882a593Smuzhiyun if (nla_get_u32(nla_b) >
170*4882a593Smuzhiyun CIPSO_V4_MAX_LOC_LVLS)
171*4882a593Smuzhiyun goto add_std_failure;
172*4882a593Smuzhiyun if (nla_get_u32(nla_b) >=
173*4882a593Smuzhiyun doi_def->map.std->lvl.local_size)
174*4882a593Smuzhiyun doi_def->map.std->lvl.local_size =
175*4882a593Smuzhiyun nla_get_u32(nla_b) + 1;
176*4882a593Smuzhiyun break;
177*4882a593Smuzhiyun case NLBL_CIPSOV4_A_MLSLVLREM:
178*4882a593Smuzhiyun if (nla_get_u32(nla_b) >
179*4882a593Smuzhiyun CIPSO_V4_MAX_REM_LVLS)
180*4882a593Smuzhiyun goto add_std_failure;
181*4882a593Smuzhiyun if (nla_get_u32(nla_b) >=
182*4882a593Smuzhiyun doi_def->map.std->lvl.cipso_size)
183*4882a593Smuzhiyun doi_def->map.std->lvl.cipso_size =
184*4882a593Smuzhiyun nla_get_u32(nla_b) + 1;
185*4882a593Smuzhiyun break;
186*4882a593Smuzhiyun }
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun doi_def->map.std->lvl.local = kcalloc(doi_def->map.std->lvl.local_size,
189*4882a593Smuzhiyun sizeof(u32),
190*4882a593Smuzhiyun GFP_KERNEL | __GFP_NOWARN);
191*4882a593Smuzhiyun if (doi_def->map.std->lvl.local == NULL) {
192*4882a593Smuzhiyun ret_val = -ENOMEM;
193*4882a593Smuzhiyun goto add_std_failure;
194*4882a593Smuzhiyun }
195*4882a593Smuzhiyun doi_def->map.std->lvl.cipso = kcalloc(doi_def->map.std->lvl.cipso_size,
196*4882a593Smuzhiyun sizeof(u32),
197*4882a593Smuzhiyun GFP_KERNEL | __GFP_NOWARN);
198*4882a593Smuzhiyun if (doi_def->map.std->lvl.cipso == NULL) {
199*4882a593Smuzhiyun ret_val = -ENOMEM;
200*4882a593Smuzhiyun goto add_std_failure;
201*4882a593Smuzhiyun }
202*4882a593Smuzhiyun for (iter = 0; iter < doi_def->map.std->lvl.local_size; iter++)
203*4882a593Smuzhiyun doi_def->map.std->lvl.local[iter] = CIPSO_V4_INV_LVL;
204*4882a593Smuzhiyun for (iter = 0; iter < doi_def->map.std->lvl.cipso_size; iter++)
205*4882a593Smuzhiyun doi_def->map.std->lvl.cipso[iter] = CIPSO_V4_INV_LVL;
206*4882a593Smuzhiyun nla_for_each_nested(nla_a,
207*4882a593Smuzhiyun info->attrs[NLBL_CIPSOV4_A_MLSLVLLST],
208*4882a593Smuzhiyun nla_a_rem)
209*4882a593Smuzhiyun if (nla_type(nla_a) == NLBL_CIPSOV4_A_MLSLVL) {
210*4882a593Smuzhiyun struct nlattr *lvl_loc;
211*4882a593Smuzhiyun struct nlattr *lvl_rem;
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun lvl_loc = nla_find_nested(nla_a,
214*4882a593Smuzhiyun NLBL_CIPSOV4_A_MLSLVLLOC);
215*4882a593Smuzhiyun lvl_rem = nla_find_nested(nla_a,
216*4882a593Smuzhiyun NLBL_CIPSOV4_A_MLSLVLREM);
217*4882a593Smuzhiyun if (lvl_loc == NULL || lvl_rem == NULL)
218*4882a593Smuzhiyun goto add_std_failure;
219*4882a593Smuzhiyun doi_def->map.std->lvl.local[nla_get_u32(lvl_loc)] =
220*4882a593Smuzhiyun nla_get_u32(lvl_rem);
221*4882a593Smuzhiyun doi_def->map.std->lvl.cipso[nla_get_u32(lvl_rem)] =
222*4882a593Smuzhiyun nla_get_u32(lvl_loc);
223*4882a593Smuzhiyun }
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun if (info->attrs[NLBL_CIPSOV4_A_MLSCATLST]) {
226*4882a593Smuzhiyun if (nla_validate_nested_deprecated(info->attrs[NLBL_CIPSOV4_A_MLSCATLST],
227*4882a593Smuzhiyun NLBL_CIPSOV4_A_MAX,
228*4882a593Smuzhiyun netlbl_cipsov4_genl_policy,
229*4882a593Smuzhiyun NULL) != 0)
230*4882a593Smuzhiyun goto add_std_failure;
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun nla_for_each_nested(nla_a,
233*4882a593Smuzhiyun info->attrs[NLBL_CIPSOV4_A_MLSCATLST],
234*4882a593Smuzhiyun nla_a_rem)
235*4882a593Smuzhiyun if (nla_type(nla_a) == NLBL_CIPSOV4_A_MLSCAT) {
236*4882a593Smuzhiyun if (nla_validate_nested_deprecated(nla_a,
237*4882a593Smuzhiyun NLBL_CIPSOV4_A_MAX,
238*4882a593Smuzhiyun netlbl_cipsov4_genl_policy,
239*4882a593Smuzhiyun NULL) != 0)
240*4882a593Smuzhiyun goto add_std_failure;
241*4882a593Smuzhiyun nla_for_each_nested(nla_b, nla_a, nla_b_rem)
242*4882a593Smuzhiyun switch (nla_type(nla_b)) {
243*4882a593Smuzhiyun case NLBL_CIPSOV4_A_MLSCATLOC:
244*4882a593Smuzhiyun if (nla_get_u32(nla_b) >
245*4882a593Smuzhiyun CIPSO_V4_MAX_LOC_CATS)
246*4882a593Smuzhiyun goto add_std_failure;
247*4882a593Smuzhiyun if (nla_get_u32(nla_b) >=
248*4882a593Smuzhiyun doi_def->map.std->cat.local_size)
249*4882a593Smuzhiyun doi_def->map.std->cat.local_size =
250*4882a593Smuzhiyun nla_get_u32(nla_b) + 1;
251*4882a593Smuzhiyun break;
252*4882a593Smuzhiyun case NLBL_CIPSOV4_A_MLSCATREM:
253*4882a593Smuzhiyun if (nla_get_u32(nla_b) >
254*4882a593Smuzhiyun CIPSO_V4_MAX_REM_CATS)
255*4882a593Smuzhiyun goto add_std_failure;
256*4882a593Smuzhiyun if (nla_get_u32(nla_b) >=
257*4882a593Smuzhiyun doi_def->map.std->cat.cipso_size)
258*4882a593Smuzhiyun doi_def->map.std->cat.cipso_size =
259*4882a593Smuzhiyun nla_get_u32(nla_b) + 1;
260*4882a593Smuzhiyun break;
261*4882a593Smuzhiyun }
262*4882a593Smuzhiyun }
263*4882a593Smuzhiyun doi_def->map.std->cat.local = kcalloc(
264*4882a593Smuzhiyun doi_def->map.std->cat.local_size,
265*4882a593Smuzhiyun sizeof(u32),
266*4882a593Smuzhiyun GFP_KERNEL | __GFP_NOWARN);
267*4882a593Smuzhiyun if (doi_def->map.std->cat.local == NULL) {
268*4882a593Smuzhiyun ret_val = -ENOMEM;
269*4882a593Smuzhiyun goto add_std_failure;
270*4882a593Smuzhiyun }
271*4882a593Smuzhiyun doi_def->map.std->cat.cipso = kcalloc(
272*4882a593Smuzhiyun doi_def->map.std->cat.cipso_size,
273*4882a593Smuzhiyun sizeof(u32),
274*4882a593Smuzhiyun GFP_KERNEL | __GFP_NOWARN);
275*4882a593Smuzhiyun if (doi_def->map.std->cat.cipso == NULL) {
276*4882a593Smuzhiyun ret_val = -ENOMEM;
277*4882a593Smuzhiyun goto add_std_failure;
278*4882a593Smuzhiyun }
279*4882a593Smuzhiyun for (iter = 0; iter < doi_def->map.std->cat.local_size; iter++)
280*4882a593Smuzhiyun doi_def->map.std->cat.local[iter] = CIPSO_V4_INV_CAT;
281*4882a593Smuzhiyun for (iter = 0; iter < doi_def->map.std->cat.cipso_size; iter++)
282*4882a593Smuzhiyun doi_def->map.std->cat.cipso[iter] = CIPSO_V4_INV_CAT;
283*4882a593Smuzhiyun nla_for_each_nested(nla_a,
284*4882a593Smuzhiyun info->attrs[NLBL_CIPSOV4_A_MLSCATLST],
285*4882a593Smuzhiyun nla_a_rem)
286*4882a593Smuzhiyun if (nla_type(nla_a) == NLBL_CIPSOV4_A_MLSCAT) {
287*4882a593Smuzhiyun struct nlattr *cat_loc;
288*4882a593Smuzhiyun struct nlattr *cat_rem;
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun cat_loc = nla_find_nested(nla_a,
291*4882a593Smuzhiyun NLBL_CIPSOV4_A_MLSCATLOC);
292*4882a593Smuzhiyun cat_rem = nla_find_nested(nla_a,
293*4882a593Smuzhiyun NLBL_CIPSOV4_A_MLSCATREM);
294*4882a593Smuzhiyun if (cat_loc == NULL || cat_rem == NULL)
295*4882a593Smuzhiyun goto add_std_failure;
296*4882a593Smuzhiyun doi_def->map.std->cat.local[
297*4882a593Smuzhiyun nla_get_u32(cat_loc)] =
298*4882a593Smuzhiyun nla_get_u32(cat_rem);
299*4882a593Smuzhiyun doi_def->map.std->cat.cipso[
300*4882a593Smuzhiyun nla_get_u32(cat_rem)] =
301*4882a593Smuzhiyun nla_get_u32(cat_loc);
302*4882a593Smuzhiyun }
303*4882a593Smuzhiyun }
304*4882a593Smuzhiyun
305*4882a593Smuzhiyun ret_val = cipso_v4_doi_add(doi_def, audit_info);
306*4882a593Smuzhiyun if (ret_val != 0)
307*4882a593Smuzhiyun goto add_std_failure;
308*4882a593Smuzhiyun return 0;
309*4882a593Smuzhiyun
310*4882a593Smuzhiyun add_std_failure:
311*4882a593Smuzhiyun cipso_v4_doi_free(doi_def);
312*4882a593Smuzhiyun return ret_val;
313*4882a593Smuzhiyun }
314*4882a593Smuzhiyun
315*4882a593Smuzhiyun /**
316*4882a593Smuzhiyun * netlbl_cipsov4_add_pass - Adds a CIPSO V4 DOI definition
317*4882a593Smuzhiyun * @info: the Generic NETLINK info block
318*4882a593Smuzhiyun * @audit_info: NetLabel audit information
319*4882a593Smuzhiyun *
320*4882a593Smuzhiyun * Description:
321*4882a593Smuzhiyun * Create a new CIPSO_V4_MAP_PASS DOI definition based on the given ADD message
322*4882a593Smuzhiyun * and add it to the CIPSO V4 engine. Return zero on success and non-zero on
323*4882a593Smuzhiyun * error.
324*4882a593Smuzhiyun *
325*4882a593Smuzhiyun */
netlbl_cipsov4_add_pass(struct genl_info * info,struct netlbl_audit * audit_info)326*4882a593Smuzhiyun static int netlbl_cipsov4_add_pass(struct genl_info *info,
327*4882a593Smuzhiyun struct netlbl_audit *audit_info)
328*4882a593Smuzhiyun {
329*4882a593Smuzhiyun int ret_val;
330*4882a593Smuzhiyun struct cipso_v4_doi *doi_def = NULL;
331*4882a593Smuzhiyun
332*4882a593Smuzhiyun if (!info->attrs[NLBL_CIPSOV4_A_TAGLST])
333*4882a593Smuzhiyun return -EINVAL;
334*4882a593Smuzhiyun
335*4882a593Smuzhiyun doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
336*4882a593Smuzhiyun if (doi_def == NULL)
337*4882a593Smuzhiyun return -ENOMEM;
338*4882a593Smuzhiyun doi_def->type = CIPSO_V4_MAP_PASS;
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun ret_val = netlbl_cipsov4_add_common(info, doi_def);
341*4882a593Smuzhiyun if (ret_val != 0)
342*4882a593Smuzhiyun goto add_pass_failure;
343*4882a593Smuzhiyun
344*4882a593Smuzhiyun ret_val = cipso_v4_doi_add(doi_def, audit_info);
345*4882a593Smuzhiyun if (ret_val != 0)
346*4882a593Smuzhiyun goto add_pass_failure;
347*4882a593Smuzhiyun return 0;
348*4882a593Smuzhiyun
349*4882a593Smuzhiyun add_pass_failure:
350*4882a593Smuzhiyun cipso_v4_doi_free(doi_def);
351*4882a593Smuzhiyun return ret_val;
352*4882a593Smuzhiyun }
353*4882a593Smuzhiyun
354*4882a593Smuzhiyun /**
355*4882a593Smuzhiyun * netlbl_cipsov4_add_local - Adds a CIPSO V4 DOI definition
356*4882a593Smuzhiyun * @info: the Generic NETLINK info block
357*4882a593Smuzhiyun * @audit_info: NetLabel audit information
358*4882a593Smuzhiyun *
359*4882a593Smuzhiyun * Description:
360*4882a593Smuzhiyun * Create a new CIPSO_V4_MAP_LOCAL DOI definition based on the given ADD
361*4882a593Smuzhiyun * message and add it to the CIPSO V4 engine. Return zero on success and
362*4882a593Smuzhiyun * non-zero on error.
363*4882a593Smuzhiyun *
364*4882a593Smuzhiyun */
netlbl_cipsov4_add_local(struct genl_info * info,struct netlbl_audit * audit_info)365*4882a593Smuzhiyun static int netlbl_cipsov4_add_local(struct genl_info *info,
366*4882a593Smuzhiyun struct netlbl_audit *audit_info)
367*4882a593Smuzhiyun {
368*4882a593Smuzhiyun int ret_val;
369*4882a593Smuzhiyun struct cipso_v4_doi *doi_def = NULL;
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun if (!info->attrs[NLBL_CIPSOV4_A_TAGLST])
372*4882a593Smuzhiyun return -EINVAL;
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
375*4882a593Smuzhiyun if (doi_def == NULL)
376*4882a593Smuzhiyun return -ENOMEM;
377*4882a593Smuzhiyun doi_def->type = CIPSO_V4_MAP_LOCAL;
378*4882a593Smuzhiyun
379*4882a593Smuzhiyun ret_val = netlbl_cipsov4_add_common(info, doi_def);
380*4882a593Smuzhiyun if (ret_val != 0)
381*4882a593Smuzhiyun goto add_local_failure;
382*4882a593Smuzhiyun
383*4882a593Smuzhiyun ret_val = cipso_v4_doi_add(doi_def, audit_info);
384*4882a593Smuzhiyun if (ret_val != 0)
385*4882a593Smuzhiyun goto add_local_failure;
386*4882a593Smuzhiyun return 0;
387*4882a593Smuzhiyun
388*4882a593Smuzhiyun add_local_failure:
389*4882a593Smuzhiyun cipso_v4_doi_free(doi_def);
390*4882a593Smuzhiyun return ret_val;
391*4882a593Smuzhiyun }
392*4882a593Smuzhiyun
393*4882a593Smuzhiyun /**
394*4882a593Smuzhiyun * netlbl_cipsov4_add - Handle an ADD message
395*4882a593Smuzhiyun * @skb: the NETLINK buffer
396*4882a593Smuzhiyun * @info: the Generic NETLINK info block
397*4882a593Smuzhiyun *
398*4882a593Smuzhiyun * Description:
399*4882a593Smuzhiyun * Create a new DOI definition based on the given ADD message and add it to the
400*4882a593Smuzhiyun * CIPSO V4 engine. Returns zero on success, negative values on failure.
401*4882a593Smuzhiyun *
402*4882a593Smuzhiyun */
netlbl_cipsov4_add(struct sk_buff * skb,struct genl_info * info)403*4882a593Smuzhiyun static int netlbl_cipsov4_add(struct sk_buff *skb, struct genl_info *info)
404*4882a593Smuzhiyun
405*4882a593Smuzhiyun {
406*4882a593Smuzhiyun int ret_val = -EINVAL;
407*4882a593Smuzhiyun struct netlbl_audit audit_info;
408*4882a593Smuzhiyun
409*4882a593Smuzhiyun if (!info->attrs[NLBL_CIPSOV4_A_DOI] ||
410*4882a593Smuzhiyun !info->attrs[NLBL_CIPSOV4_A_MTYPE])
411*4882a593Smuzhiyun return -EINVAL;
412*4882a593Smuzhiyun
413*4882a593Smuzhiyun netlbl_netlink_auditinfo(skb, &audit_info);
414*4882a593Smuzhiyun switch (nla_get_u32(info->attrs[NLBL_CIPSOV4_A_MTYPE])) {
415*4882a593Smuzhiyun case CIPSO_V4_MAP_TRANS:
416*4882a593Smuzhiyun ret_val = netlbl_cipsov4_add_std(info, &audit_info);
417*4882a593Smuzhiyun break;
418*4882a593Smuzhiyun case CIPSO_V4_MAP_PASS:
419*4882a593Smuzhiyun ret_val = netlbl_cipsov4_add_pass(info, &audit_info);
420*4882a593Smuzhiyun break;
421*4882a593Smuzhiyun case CIPSO_V4_MAP_LOCAL:
422*4882a593Smuzhiyun ret_val = netlbl_cipsov4_add_local(info, &audit_info);
423*4882a593Smuzhiyun break;
424*4882a593Smuzhiyun }
425*4882a593Smuzhiyun if (ret_val == 0)
426*4882a593Smuzhiyun atomic_inc(&netlabel_mgmt_protocount);
427*4882a593Smuzhiyun
428*4882a593Smuzhiyun return ret_val;
429*4882a593Smuzhiyun }
430*4882a593Smuzhiyun
431*4882a593Smuzhiyun /**
432*4882a593Smuzhiyun * netlbl_cipsov4_list - Handle a LIST message
433*4882a593Smuzhiyun * @skb: the NETLINK buffer
434*4882a593Smuzhiyun * @info: the Generic NETLINK info block
435*4882a593Smuzhiyun *
436*4882a593Smuzhiyun * Description:
437*4882a593Smuzhiyun * Process a user generated LIST message and respond accordingly. While the
438*4882a593Smuzhiyun * response message generated by the kernel is straightforward, determining
439*4882a593Smuzhiyun * before hand the size of the buffer to allocate is not (we have to generate
440*4882a593Smuzhiyun * the message to know the size). In order to keep this function sane what we
441*4882a593Smuzhiyun * do is allocate a buffer of NLMSG_GOODSIZE and try to fit the response in
442*4882a593Smuzhiyun * that size, if we fail then we restart with a larger buffer and try again.
443*4882a593Smuzhiyun * We continue in this manner until we hit a limit of failed attempts then we
444*4882a593Smuzhiyun * give up and just send an error message. Returns zero on success and
445*4882a593Smuzhiyun * negative values on error.
446*4882a593Smuzhiyun *
447*4882a593Smuzhiyun */
netlbl_cipsov4_list(struct sk_buff * skb,struct genl_info * info)448*4882a593Smuzhiyun static int netlbl_cipsov4_list(struct sk_buff *skb, struct genl_info *info)
449*4882a593Smuzhiyun {
450*4882a593Smuzhiyun int ret_val;
451*4882a593Smuzhiyun struct sk_buff *ans_skb = NULL;
452*4882a593Smuzhiyun u32 nlsze_mult = 1;
453*4882a593Smuzhiyun void *data;
454*4882a593Smuzhiyun u32 doi;
455*4882a593Smuzhiyun struct nlattr *nla_a;
456*4882a593Smuzhiyun struct nlattr *nla_b;
457*4882a593Smuzhiyun struct cipso_v4_doi *doi_def;
458*4882a593Smuzhiyun u32 iter;
459*4882a593Smuzhiyun
460*4882a593Smuzhiyun if (!info->attrs[NLBL_CIPSOV4_A_DOI]) {
461*4882a593Smuzhiyun ret_val = -EINVAL;
462*4882a593Smuzhiyun goto list_failure;
463*4882a593Smuzhiyun }
464*4882a593Smuzhiyun
465*4882a593Smuzhiyun list_start:
466*4882a593Smuzhiyun ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE * nlsze_mult, GFP_KERNEL);
467*4882a593Smuzhiyun if (ans_skb == NULL) {
468*4882a593Smuzhiyun ret_val = -ENOMEM;
469*4882a593Smuzhiyun goto list_failure;
470*4882a593Smuzhiyun }
471*4882a593Smuzhiyun data = genlmsg_put_reply(ans_skb, info, &netlbl_cipsov4_gnl_family,
472*4882a593Smuzhiyun 0, NLBL_CIPSOV4_C_LIST);
473*4882a593Smuzhiyun if (data == NULL) {
474*4882a593Smuzhiyun ret_val = -ENOMEM;
475*4882a593Smuzhiyun goto list_failure;
476*4882a593Smuzhiyun }
477*4882a593Smuzhiyun
478*4882a593Smuzhiyun doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
479*4882a593Smuzhiyun
480*4882a593Smuzhiyun rcu_read_lock();
481*4882a593Smuzhiyun doi_def = cipso_v4_doi_getdef(doi);
482*4882a593Smuzhiyun if (doi_def == NULL) {
483*4882a593Smuzhiyun ret_val = -EINVAL;
484*4882a593Smuzhiyun goto list_failure_lock;
485*4882a593Smuzhiyun }
486*4882a593Smuzhiyun
487*4882a593Smuzhiyun ret_val = nla_put_u32(ans_skb, NLBL_CIPSOV4_A_MTYPE, doi_def->type);
488*4882a593Smuzhiyun if (ret_val != 0)
489*4882a593Smuzhiyun goto list_failure_lock;
490*4882a593Smuzhiyun
491*4882a593Smuzhiyun nla_a = nla_nest_start_noflag(ans_skb, NLBL_CIPSOV4_A_TAGLST);
492*4882a593Smuzhiyun if (nla_a == NULL) {
493*4882a593Smuzhiyun ret_val = -ENOMEM;
494*4882a593Smuzhiyun goto list_failure_lock;
495*4882a593Smuzhiyun }
496*4882a593Smuzhiyun for (iter = 0;
497*4882a593Smuzhiyun iter < CIPSO_V4_TAG_MAXCNT &&
498*4882a593Smuzhiyun doi_def->tags[iter] != CIPSO_V4_TAG_INVALID;
499*4882a593Smuzhiyun iter++) {
500*4882a593Smuzhiyun ret_val = nla_put_u8(ans_skb,
501*4882a593Smuzhiyun NLBL_CIPSOV4_A_TAG,
502*4882a593Smuzhiyun doi_def->tags[iter]);
503*4882a593Smuzhiyun if (ret_val != 0)
504*4882a593Smuzhiyun goto list_failure_lock;
505*4882a593Smuzhiyun }
506*4882a593Smuzhiyun nla_nest_end(ans_skb, nla_a);
507*4882a593Smuzhiyun
508*4882a593Smuzhiyun switch (doi_def->type) {
509*4882a593Smuzhiyun case CIPSO_V4_MAP_TRANS:
510*4882a593Smuzhiyun nla_a = nla_nest_start_noflag(ans_skb,
511*4882a593Smuzhiyun NLBL_CIPSOV4_A_MLSLVLLST);
512*4882a593Smuzhiyun if (nla_a == NULL) {
513*4882a593Smuzhiyun ret_val = -ENOMEM;
514*4882a593Smuzhiyun goto list_failure_lock;
515*4882a593Smuzhiyun }
516*4882a593Smuzhiyun for (iter = 0;
517*4882a593Smuzhiyun iter < doi_def->map.std->lvl.local_size;
518*4882a593Smuzhiyun iter++) {
519*4882a593Smuzhiyun if (doi_def->map.std->lvl.local[iter] ==
520*4882a593Smuzhiyun CIPSO_V4_INV_LVL)
521*4882a593Smuzhiyun continue;
522*4882a593Smuzhiyun
523*4882a593Smuzhiyun nla_b = nla_nest_start_noflag(ans_skb,
524*4882a593Smuzhiyun NLBL_CIPSOV4_A_MLSLVL);
525*4882a593Smuzhiyun if (nla_b == NULL) {
526*4882a593Smuzhiyun ret_val = -ENOMEM;
527*4882a593Smuzhiyun goto list_retry;
528*4882a593Smuzhiyun }
529*4882a593Smuzhiyun ret_val = nla_put_u32(ans_skb,
530*4882a593Smuzhiyun NLBL_CIPSOV4_A_MLSLVLLOC,
531*4882a593Smuzhiyun iter);
532*4882a593Smuzhiyun if (ret_val != 0)
533*4882a593Smuzhiyun goto list_retry;
534*4882a593Smuzhiyun ret_val = nla_put_u32(ans_skb,
535*4882a593Smuzhiyun NLBL_CIPSOV4_A_MLSLVLREM,
536*4882a593Smuzhiyun doi_def->map.std->lvl.local[iter]);
537*4882a593Smuzhiyun if (ret_val != 0)
538*4882a593Smuzhiyun goto list_retry;
539*4882a593Smuzhiyun nla_nest_end(ans_skb, nla_b);
540*4882a593Smuzhiyun }
541*4882a593Smuzhiyun nla_nest_end(ans_skb, nla_a);
542*4882a593Smuzhiyun
543*4882a593Smuzhiyun nla_a = nla_nest_start_noflag(ans_skb,
544*4882a593Smuzhiyun NLBL_CIPSOV4_A_MLSCATLST);
545*4882a593Smuzhiyun if (nla_a == NULL) {
546*4882a593Smuzhiyun ret_val = -ENOMEM;
547*4882a593Smuzhiyun goto list_retry;
548*4882a593Smuzhiyun }
549*4882a593Smuzhiyun for (iter = 0;
550*4882a593Smuzhiyun iter < doi_def->map.std->cat.local_size;
551*4882a593Smuzhiyun iter++) {
552*4882a593Smuzhiyun if (doi_def->map.std->cat.local[iter] ==
553*4882a593Smuzhiyun CIPSO_V4_INV_CAT)
554*4882a593Smuzhiyun continue;
555*4882a593Smuzhiyun
556*4882a593Smuzhiyun nla_b = nla_nest_start_noflag(ans_skb,
557*4882a593Smuzhiyun NLBL_CIPSOV4_A_MLSCAT);
558*4882a593Smuzhiyun if (nla_b == NULL) {
559*4882a593Smuzhiyun ret_val = -ENOMEM;
560*4882a593Smuzhiyun goto list_retry;
561*4882a593Smuzhiyun }
562*4882a593Smuzhiyun ret_val = nla_put_u32(ans_skb,
563*4882a593Smuzhiyun NLBL_CIPSOV4_A_MLSCATLOC,
564*4882a593Smuzhiyun iter);
565*4882a593Smuzhiyun if (ret_val != 0)
566*4882a593Smuzhiyun goto list_retry;
567*4882a593Smuzhiyun ret_val = nla_put_u32(ans_skb,
568*4882a593Smuzhiyun NLBL_CIPSOV4_A_MLSCATREM,
569*4882a593Smuzhiyun doi_def->map.std->cat.local[iter]);
570*4882a593Smuzhiyun if (ret_val != 0)
571*4882a593Smuzhiyun goto list_retry;
572*4882a593Smuzhiyun nla_nest_end(ans_skb, nla_b);
573*4882a593Smuzhiyun }
574*4882a593Smuzhiyun nla_nest_end(ans_skb, nla_a);
575*4882a593Smuzhiyun
576*4882a593Smuzhiyun break;
577*4882a593Smuzhiyun }
578*4882a593Smuzhiyun cipso_v4_doi_putdef(doi_def);
579*4882a593Smuzhiyun rcu_read_unlock();
580*4882a593Smuzhiyun
581*4882a593Smuzhiyun genlmsg_end(ans_skb, data);
582*4882a593Smuzhiyun return genlmsg_reply(ans_skb, info);
583*4882a593Smuzhiyun
584*4882a593Smuzhiyun list_retry:
585*4882a593Smuzhiyun /* XXX - this limit is a guesstimate */
586*4882a593Smuzhiyun if (nlsze_mult < 4) {
587*4882a593Smuzhiyun cipso_v4_doi_putdef(doi_def);
588*4882a593Smuzhiyun rcu_read_unlock();
589*4882a593Smuzhiyun kfree_skb(ans_skb);
590*4882a593Smuzhiyun nlsze_mult *= 2;
591*4882a593Smuzhiyun goto list_start;
592*4882a593Smuzhiyun }
593*4882a593Smuzhiyun list_failure_lock:
594*4882a593Smuzhiyun cipso_v4_doi_putdef(doi_def);
595*4882a593Smuzhiyun rcu_read_unlock();
596*4882a593Smuzhiyun list_failure:
597*4882a593Smuzhiyun kfree_skb(ans_skb);
598*4882a593Smuzhiyun return ret_val;
599*4882a593Smuzhiyun }
600*4882a593Smuzhiyun
601*4882a593Smuzhiyun /**
602*4882a593Smuzhiyun * netlbl_cipsov4_listall_cb - cipso_v4_doi_walk() callback for LISTALL
603*4882a593Smuzhiyun * @doi_def: the CIPSOv4 DOI definition
604*4882a593Smuzhiyun * @arg: the netlbl_cipsov4_doiwalk_arg structure
605*4882a593Smuzhiyun *
606*4882a593Smuzhiyun * Description:
607*4882a593Smuzhiyun * This function is designed to be used as a callback to the
608*4882a593Smuzhiyun * cipso_v4_doi_walk() function for use in generating a response for a LISTALL
609*4882a593Smuzhiyun * message. Returns the size of the message on success, negative values on
610*4882a593Smuzhiyun * failure.
611*4882a593Smuzhiyun *
612*4882a593Smuzhiyun */
netlbl_cipsov4_listall_cb(struct cipso_v4_doi * doi_def,void * arg)613*4882a593Smuzhiyun static int netlbl_cipsov4_listall_cb(struct cipso_v4_doi *doi_def, void *arg)
614*4882a593Smuzhiyun {
615*4882a593Smuzhiyun int ret_val = -ENOMEM;
616*4882a593Smuzhiyun struct netlbl_cipsov4_doiwalk_arg *cb_arg = arg;
617*4882a593Smuzhiyun void *data;
618*4882a593Smuzhiyun
619*4882a593Smuzhiyun data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).portid,
620*4882a593Smuzhiyun cb_arg->seq, &netlbl_cipsov4_gnl_family,
621*4882a593Smuzhiyun NLM_F_MULTI, NLBL_CIPSOV4_C_LISTALL);
622*4882a593Smuzhiyun if (data == NULL)
623*4882a593Smuzhiyun goto listall_cb_failure;
624*4882a593Smuzhiyun
625*4882a593Smuzhiyun ret_val = nla_put_u32(cb_arg->skb, NLBL_CIPSOV4_A_DOI, doi_def->doi);
626*4882a593Smuzhiyun if (ret_val != 0)
627*4882a593Smuzhiyun goto listall_cb_failure;
628*4882a593Smuzhiyun ret_val = nla_put_u32(cb_arg->skb,
629*4882a593Smuzhiyun NLBL_CIPSOV4_A_MTYPE,
630*4882a593Smuzhiyun doi_def->type);
631*4882a593Smuzhiyun if (ret_val != 0)
632*4882a593Smuzhiyun goto listall_cb_failure;
633*4882a593Smuzhiyun
634*4882a593Smuzhiyun genlmsg_end(cb_arg->skb, data);
635*4882a593Smuzhiyun return 0;
636*4882a593Smuzhiyun
637*4882a593Smuzhiyun listall_cb_failure:
638*4882a593Smuzhiyun genlmsg_cancel(cb_arg->skb, data);
639*4882a593Smuzhiyun return ret_val;
640*4882a593Smuzhiyun }
641*4882a593Smuzhiyun
642*4882a593Smuzhiyun /**
643*4882a593Smuzhiyun * netlbl_cipsov4_listall - Handle a LISTALL message
644*4882a593Smuzhiyun * @skb: the NETLINK buffer
645*4882a593Smuzhiyun * @cb: the NETLINK callback
646*4882a593Smuzhiyun *
647*4882a593Smuzhiyun * Description:
648*4882a593Smuzhiyun * Process a user generated LISTALL message and respond accordingly. Returns
649*4882a593Smuzhiyun * zero on success and negative values on error.
650*4882a593Smuzhiyun *
651*4882a593Smuzhiyun */
netlbl_cipsov4_listall(struct sk_buff * skb,struct netlink_callback * cb)652*4882a593Smuzhiyun static int netlbl_cipsov4_listall(struct sk_buff *skb,
653*4882a593Smuzhiyun struct netlink_callback *cb)
654*4882a593Smuzhiyun {
655*4882a593Smuzhiyun struct netlbl_cipsov4_doiwalk_arg cb_arg;
656*4882a593Smuzhiyun u32 doi_skip = cb->args[0];
657*4882a593Smuzhiyun
658*4882a593Smuzhiyun cb_arg.nl_cb = cb;
659*4882a593Smuzhiyun cb_arg.skb = skb;
660*4882a593Smuzhiyun cb_arg.seq = cb->nlh->nlmsg_seq;
661*4882a593Smuzhiyun
662*4882a593Smuzhiyun cipso_v4_doi_walk(&doi_skip, netlbl_cipsov4_listall_cb, &cb_arg);
663*4882a593Smuzhiyun
664*4882a593Smuzhiyun cb->args[0] = doi_skip;
665*4882a593Smuzhiyun return skb->len;
666*4882a593Smuzhiyun }
667*4882a593Smuzhiyun
668*4882a593Smuzhiyun /**
669*4882a593Smuzhiyun * netlbl_cipsov4_remove_cb - netlbl_cipsov4_remove() callback for REMOVE
670*4882a593Smuzhiyun * @entry: LSM domain mapping entry
671*4882a593Smuzhiyun * @arg: the netlbl_domhsh_walk_arg structure
672*4882a593Smuzhiyun *
673*4882a593Smuzhiyun * Description:
674*4882a593Smuzhiyun * This function is intended for use by netlbl_cipsov4_remove() as the callback
675*4882a593Smuzhiyun * for the netlbl_domhsh_walk() function; it removes LSM domain map entries
676*4882a593Smuzhiyun * which are associated with the CIPSO DOI specified in @arg. Returns zero on
677*4882a593Smuzhiyun * success, negative values on failure.
678*4882a593Smuzhiyun *
679*4882a593Smuzhiyun */
netlbl_cipsov4_remove_cb(struct netlbl_dom_map * entry,void * arg)680*4882a593Smuzhiyun static int netlbl_cipsov4_remove_cb(struct netlbl_dom_map *entry, void *arg)
681*4882a593Smuzhiyun {
682*4882a593Smuzhiyun struct netlbl_domhsh_walk_arg *cb_arg = arg;
683*4882a593Smuzhiyun
684*4882a593Smuzhiyun if (entry->def.type == NETLBL_NLTYPE_CIPSOV4 &&
685*4882a593Smuzhiyun entry->def.cipso->doi == cb_arg->doi)
686*4882a593Smuzhiyun return netlbl_domhsh_remove_entry(entry, cb_arg->audit_info);
687*4882a593Smuzhiyun
688*4882a593Smuzhiyun return 0;
689*4882a593Smuzhiyun }
690*4882a593Smuzhiyun
691*4882a593Smuzhiyun /**
692*4882a593Smuzhiyun * netlbl_cipsov4_remove - Handle a REMOVE message
693*4882a593Smuzhiyun * @skb: the NETLINK buffer
694*4882a593Smuzhiyun * @info: the Generic NETLINK info block
695*4882a593Smuzhiyun *
696*4882a593Smuzhiyun * Description:
697*4882a593Smuzhiyun * Process a user generated REMOVE message and respond accordingly. Returns
698*4882a593Smuzhiyun * zero on success, negative values on failure.
699*4882a593Smuzhiyun *
700*4882a593Smuzhiyun */
netlbl_cipsov4_remove(struct sk_buff * skb,struct genl_info * info)701*4882a593Smuzhiyun static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info)
702*4882a593Smuzhiyun {
703*4882a593Smuzhiyun int ret_val = -EINVAL;
704*4882a593Smuzhiyun struct netlbl_domhsh_walk_arg cb_arg;
705*4882a593Smuzhiyun struct netlbl_audit audit_info;
706*4882a593Smuzhiyun u32 skip_bkt = 0;
707*4882a593Smuzhiyun u32 skip_chain = 0;
708*4882a593Smuzhiyun
709*4882a593Smuzhiyun if (!info->attrs[NLBL_CIPSOV4_A_DOI])
710*4882a593Smuzhiyun return -EINVAL;
711*4882a593Smuzhiyun
712*4882a593Smuzhiyun netlbl_netlink_auditinfo(skb, &audit_info);
713*4882a593Smuzhiyun cb_arg.doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
714*4882a593Smuzhiyun cb_arg.audit_info = &audit_info;
715*4882a593Smuzhiyun ret_val = netlbl_domhsh_walk(&skip_bkt, &skip_chain,
716*4882a593Smuzhiyun netlbl_cipsov4_remove_cb, &cb_arg);
717*4882a593Smuzhiyun if (ret_val == 0 || ret_val == -ENOENT) {
718*4882a593Smuzhiyun ret_val = cipso_v4_doi_remove(cb_arg.doi, &audit_info);
719*4882a593Smuzhiyun if (ret_val == 0)
720*4882a593Smuzhiyun atomic_dec(&netlabel_mgmt_protocount);
721*4882a593Smuzhiyun }
722*4882a593Smuzhiyun
723*4882a593Smuzhiyun return ret_val;
724*4882a593Smuzhiyun }
725*4882a593Smuzhiyun
726*4882a593Smuzhiyun /*
727*4882a593Smuzhiyun * NetLabel Generic NETLINK Command Definitions
728*4882a593Smuzhiyun */
729*4882a593Smuzhiyun
730*4882a593Smuzhiyun static const struct genl_small_ops netlbl_cipsov4_ops[] = {
731*4882a593Smuzhiyun {
732*4882a593Smuzhiyun .cmd = NLBL_CIPSOV4_C_ADD,
733*4882a593Smuzhiyun .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
734*4882a593Smuzhiyun .flags = GENL_ADMIN_PERM,
735*4882a593Smuzhiyun .doit = netlbl_cipsov4_add,
736*4882a593Smuzhiyun .dumpit = NULL,
737*4882a593Smuzhiyun },
738*4882a593Smuzhiyun {
739*4882a593Smuzhiyun .cmd = NLBL_CIPSOV4_C_REMOVE,
740*4882a593Smuzhiyun .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
741*4882a593Smuzhiyun .flags = GENL_ADMIN_PERM,
742*4882a593Smuzhiyun .doit = netlbl_cipsov4_remove,
743*4882a593Smuzhiyun .dumpit = NULL,
744*4882a593Smuzhiyun },
745*4882a593Smuzhiyun {
746*4882a593Smuzhiyun .cmd = NLBL_CIPSOV4_C_LIST,
747*4882a593Smuzhiyun .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
748*4882a593Smuzhiyun .flags = 0,
749*4882a593Smuzhiyun .doit = netlbl_cipsov4_list,
750*4882a593Smuzhiyun .dumpit = NULL,
751*4882a593Smuzhiyun },
752*4882a593Smuzhiyun {
753*4882a593Smuzhiyun .cmd = NLBL_CIPSOV4_C_LISTALL,
754*4882a593Smuzhiyun .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
755*4882a593Smuzhiyun .flags = 0,
756*4882a593Smuzhiyun .doit = NULL,
757*4882a593Smuzhiyun .dumpit = netlbl_cipsov4_listall,
758*4882a593Smuzhiyun },
759*4882a593Smuzhiyun };
760*4882a593Smuzhiyun
761*4882a593Smuzhiyun static struct genl_family netlbl_cipsov4_gnl_family __ro_after_init = {
762*4882a593Smuzhiyun .hdrsize = 0,
763*4882a593Smuzhiyun .name = NETLBL_NLTYPE_CIPSOV4_NAME,
764*4882a593Smuzhiyun .version = NETLBL_PROTO_VERSION,
765*4882a593Smuzhiyun .maxattr = NLBL_CIPSOV4_A_MAX,
766*4882a593Smuzhiyun .policy = netlbl_cipsov4_genl_policy,
767*4882a593Smuzhiyun .module = THIS_MODULE,
768*4882a593Smuzhiyun .small_ops = netlbl_cipsov4_ops,
769*4882a593Smuzhiyun .n_small_ops = ARRAY_SIZE(netlbl_cipsov4_ops),
770*4882a593Smuzhiyun };
771*4882a593Smuzhiyun
772*4882a593Smuzhiyun /*
773*4882a593Smuzhiyun * NetLabel Generic NETLINK Protocol Functions
774*4882a593Smuzhiyun */
775*4882a593Smuzhiyun
776*4882a593Smuzhiyun /**
777*4882a593Smuzhiyun * netlbl_cipsov4_genl_init - Register the CIPSOv4 NetLabel component
778*4882a593Smuzhiyun *
779*4882a593Smuzhiyun * Description:
780*4882a593Smuzhiyun * Register the CIPSOv4 packet NetLabel component with the Generic NETLINK
781*4882a593Smuzhiyun * mechanism. Returns zero on success, negative values on failure.
782*4882a593Smuzhiyun *
783*4882a593Smuzhiyun */
netlbl_cipsov4_genl_init(void)784*4882a593Smuzhiyun int __init netlbl_cipsov4_genl_init(void)
785*4882a593Smuzhiyun {
786*4882a593Smuzhiyun return genl_register_family(&netlbl_cipsov4_gnl_family);
787*4882a593Smuzhiyun }
788