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