0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016 #include <linux/types.h>
0017 #include <linux/socket.h>
0018 #include <linux/string.h>
0019 #include <linux/skbuff.h>
0020 #include <linux/in.h>
0021 #include <linux/in6.h>
0022 #include <linux/slab.h>
0023 #include <net/sock.h>
0024 #include <net/netlink.h>
0025 #include <net/genetlink.h>
0026 #include <net/ip.h>
0027 #include <net/ipv6.h>
0028 #include <net/netlabel.h>
0029 #include <net/cipso_ipv4.h>
0030 #include <net/calipso.h>
0031 #include <linux/atomic.h>
0032
0033 #include "netlabel_calipso.h"
0034 #include "netlabel_domainhash.h"
0035 #include "netlabel_user.h"
0036 #include "netlabel_mgmt.h"
0037
0038
0039 atomic_t netlabel_mgmt_protocount = ATOMIC_INIT(0);
0040
0041
0042 struct netlbl_domhsh_walk_arg {
0043 struct netlink_callback *nl_cb;
0044 struct sk_buff *skb;
0045 u32 seq;
0046 };
0047
0048
0049 static struct genl_family netlbl_mgmt_gnl_family;
0050
0051
0052 static const struct nla_policy netlbl_mgmt_genl_policy[NLBL_MGMT_A_MAX + 1] = {
0053 [NLBL_MGMT_A_DOMAIN] = { .type = NLA_NUL_STRING },
0054 [NLBL_MGMT_A_PROTOCOL] = { .type = NLA_U32 },
0055 [NLBL_MGMT_A_VERSION] = { .type = NLA_U32 },
0056 [NLBL_MGMT_A_CV4DOI] = { .type = NLA_U32 },
0057 [NLBL_MGMT_A_FAMILY] = { .type = NLA_U16 },
0058 [NLBL_MGMT_A_CLPDOI] = { .type = NLA_U32 },
0059 };
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076 static int netlbl_mgmt_add_common(struct genl_info *info,
0077 struct netlbl_audit *audit_info)
0078 {
0079 void *pmap = NULL;
0080 int ret_val = -EINVAL;
0081 struct netlbl_domaddr_map *addrmap = NULL;
0082 struct cipso_v4_doi *cipsov4 = NULL;
0083 #if IS_ENABLED(CONFIG_IPV6)
0084 struct calipso_doi *calipso = NULL;
0085 #endif
0086 u32 tmp_val;
0087 struct netlbl_dom_map *entry = kzalloc(sizeof(*entry), GFP_KERNEL);
0088
0089 if (!entry)
0090 return -ENOMEM;
0091 entry->def.type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]);
0092 if (info->attrs[NLBL_MGMT_A_DOMAIN]) {
0093 size_t tmp_size = nla_len(info->attrs[NLBL_MGMT_A_DOMAIN]);
0094 entry->domain = kmalloc(tmp_size, GFP_KERNEL);
0095 if (entry->domain == NULL) {
0096 ret_val = -ENOMEM;
0097 goto add_free_entry;
0098 }
0099 nla_strscpy(entry->domain,
0100 info->attrs[NLBL_MGMT_A_DOMAIN], tmp_size);
0101 }
0102
0103
0104
0105
0106
0107
0108 switch (entry->def.type) {
0109 case NETLBL_NLTYPE_UNLABELED:
0110 if (info->attrs[NLBL_MGMT_A_FAMILY])
0111 entry->family =
0112 nla_get_u16(info->attrs[NLBL_MGMT_A_FAMILY]);
0113 else
0114 entry->family = AF_UNSPEC;
0115 break;
0116 case NETLBL_NLTYPE_CIPSOV4:
0117 if (!info->attrs[NLBL_MGMT_A_CV4DOI])
0118 goto add_free_domain;
0119
0120 tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]);
0121 cipsov4 = cipso_v4_doi_getdef(tmp_val);
0122 if (cipsov4 == NULL)
0123 goto add_free_domain;
0124 entry->family = AF_INET;
0125 entry->def.cipso = cipsov4;
0126 break;
0127 #if IS_ENABLED(CONFIG_IPV6)
0128 case NETLBL_NLTYPE_CALIPSO:
0129 if (!info->attrs[NLBL_MGMT_A_CLPDOI])
0130 goto add_free_domain;
0131
0132 tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CLPDOI]);
0133 calipso = calipso_doi_getdef(tmp_val);
0134 if (calipso == NULL)
0135 goto add_free_domain;
0136 entry->family = AF_INET6;
0137 entry->def.calipso = calipso;
0138 break;
0139 #endif
0140 default:
0141 goto add_free_domain;
0142 }
0143
0144 if ((entry->family == AF_INET && info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
0145 (entry->family == AF_INET6 && info->attrs[NLBL_MGMT_A_IPV4ADDR]))
0146 goto add_doi_put_def;
0147
0148 if (info->attrs[NLBL_MGMT_A_IPV4ADDR]) {
0149 struct in_addr *addr;
0150 struct in_addr *mask;
0151 struct netlbl_domaddr4_map *map;
0152
0153 addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL);
0154 if (addrmap == NULL) {
0155 ret_val = -ENOMEM;
0156 goto add_doi_put_def;
0157 }
0158 INIT_LIST_HEAD(&addrmap->list4);
0159 INIT_LIST_HEAD(&addrmap->list6);
0160
0161 if (nla_len(info->attrs[NLBL_MGMT_A_IPV4ADDR]) !=
0162 sizeof(struct in_addr)) {
0163 ret_val = -EINVAL;
0164 goto add_free_addrmap;
0165 }
0166 if (nla_len(info->attrs[NLBL_MGMT_A_IPV4MASK]) !=
0167 sizeof(struct in_addr)) {
0168 ret_val = -EINVAL;
0169 goto add_free_addrmap;
0170 }
0171 addr = nla_data(info->attrs[NLBL_MGMT_A_IPV4ADDR]);
0172 mask = nla_data(info->attrs[NLBL_MGMT_A_IPV4MASK]);
0173
0174 map = kzalloc(sizeof(*map), GFP_KERNEL);
0175 if (map == NULL) {
0176 ret_val = -ENOMEM;
0177 goto add_free_addrmap;
0178 }
0179 pmap = map;
0180 map->list.addr = addr->s_addr & mask->s_addr;
0181 map->list.mask = mask->s_addr;
0182 map->list.valid = 1;
0183 map->def.type = entry->def.type;
0184 if (cipsov4)
0185 map->def.cipso = cipsov4;
0186
0187 ret_val = netlbl_af4list_add(&map->list, &addrmap->list4);
0188 if (ret_val != 0)
0189 goto add_free_map;
0190
0191 entry->family = AF_INET;
0192 entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
0193 entry->def.addrsel = addrmap;
0194 #if IS_ENABLED(CONFIG_IPV6)
0195 } else if (info->attrs[NLBL_MGMT_A_IPV6ADDR]) {
0196 struct in6_addr *addr;
0197 struct in6_addr *mask;
0198 struct netlbl_domaddr6_map *map;
0199
0200 addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL);
0201 if (addrmap == NULL) {
0202 ret_val = -ENOMEM;
0203 goto add_doi_put_def;
0204 }
0205 INIT_LIST_HEAD(&addrmap->list4);
0206 INIT_LIST_HEAD(&addrmap->list6);
0207
0208 if (nla_len(info->attrs[NLBL_MGMT_A_IPV6ADDR]) !=
0209 sizeof(struct in6_addr)) {
0210 ret_val = -EINVAL;
0211 goto add_free_addrmap;
0212 }
0213 if (nla_len(info->attrs[NLBL_MGMT_A_IPV6MASK]) !=
0214 sizeof(struct in6_addr)) {
0215 ret_val = -EINVAL;
0216 goto add_free_addrmap;
0217 }
0218 addr = nla_data(info->attrs[NLBL_MGMT_A_IPV6ADDR]);
0219 mask = nla_data(info->attrs[NLBL_MGMT_A_IPV6MASK]);
0220
0221 map = kzalloc(sizeof(*map), GFP_KERNEL);
0222 if (map == NULL) {
0223 ret_val = -ENOMEM;
0224 goto add_free_addrmap;
0225 }
0226 pmap = map;
0227 map->list.addr = *addr;
0228 map->list.addr.s6_addr32[0] &= mask->s6_addr32[0];
0229 map->list.addr.s6_addr32[1] &= mask->s6_addr32[1];
0230 map->list.addr.s6_addr32[2] &= mask->s6_addr32[2];
0231 map->list.addr.s6_addr32[3] &= mask->s6_addr32[3];
0232 map->list.mask = *mask;
0233 map->list.valid = 1;
0234 map->def.type = entry->def.type;
0235 if (calipso)
0236 map->def.calipso = calipso;
0237
0238 ret_val = netlbl_af6list_add(&map->list, &addrmap->list6);
0239 if (ret_val != 0)
0240 goto add_free_map;
0241
0242 entry->family = AF_INET6;
0243 entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
0244 entry->def.addrsel = addrmap;
0245 #endif
0246 }
0247
0248 ret_val = netlbl_domhsh_add(entry, audit_info);
0249 if (ret_val != 0)
0250 goto add_free_map;
0251
0252 return 0;
0253
0254 add_free_map:
0255 kfree(pmap);
0256 add_free_addrmap:
0257 kfree(addrmap);
0258 add_doi_put_def:
0259 cipso_v4_doi_putdef(cipsov4);
0260 #if IS_ENABLED(CONFIG_IPV6)
0261 calipso_doi_putdef(calipso);
0262 #endif
0263 add_free_domain:
0264 kfree(entry->domain);
0265 add_free_entry:
0266 kfree(entry);
0267 return ret_val;
0268 }
0269
0270
0271
0272
0273
0274
0275
0276
0277
0278
0279
0280
0281 static int netlbl_mgmt_listentry(struct sk_buff *skb,
0282 struct netlbl_dom_map *entry)
0283 {
0284 int ret_val = 0;
0285 struct nlattr *nla_a;
0286 struct nlattr *nla_b;
0287 struct netlbl_af4list *iter4;
0288 #if IS_ENABLED(CONFIG_IPV6)
0289 struct netlbl_af6list *iter6;
0290 #endif
0291
0292 if (entry->domain != NULL) {
0293 ret_val = nla_put_string(skb,
0294 NLBL_MGMT_A_DOMAIN, entry->domain);
0295 if (ret_val != 0)
0296 return ret_val;
0297 }
0298
0299 ret_val = nla_put_u16(skb, NLBL_MGMT_A_FAMILY, entry->family);
0300 if (ret_val != 0)
0301 return ret_val;
0302
0303 switch (entry->def.type) {
0304 case NETLBL_NLTYPE_ADDRSELECT:
0305 nla_a = nla_nest_start_noflag(skb, NLBL_MGMT_A_SELECTORLIST);
0306 if (nla_a == NULL)
0307 return -ENOMEM;
0308
0309 netlbl_af4list_foreach_rcu(iter4, &entry->def.addrsel->list4) {
0310 struct netlbl_domaddr4_map *map4;
0311 struct in_addr addr_struct;
0312
0313 nla_b = nla_nest_start_noflag(skb,
0314 NLBL_MGMT_A_ADDRSELECTOR);
0315 if (nla_b == NULL)
0316 return -ENOMEM;
0317
0318 addr_struct.s_addr = iter4->addr;
0319 ret_val = nla_put_in_addr(skb, NLBL_MGMT_A_IPV4ADDR,
0320 addr_struct.s_addr);
0321 if (ret_val != 0)
0322 return ret_val;
0323 addr_struct.s_addr = iter4->mask;
0324 ret_val = nla_put_in_addr(skb, NLBL_MGMT_A_IPV4MASK,
0325 addr_struct.s_addr);
0326 if (ret_val != 0)
0327 return ret_val;
0328 map4 = netlbl_domhsh_addr4_entry(iter4);
0329 ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
0330 map4->def.type);
0331 if (ret_val != 0)
0332 return ret_val;
0333 switch (map4->def.type) {
0334 case NETLBL_NLTYPE_CIPSOV4:
0335 ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI,
0336 map4->def.cipso->doi);
0337 if (ret_val != 0)
0338 return ret_val;
0339 break;
0340 }
0341
0342 nla_nest_end(skb, nla_b);
0343 }
0344 #if IS_ENABLED(CONFIG_IPV6)
0345 netlbl_af6list_foreach_rcu(iter6, &entry->def.addrsel->list6) {
0346 struct netlbl_domaddr6_map *map6;
0347
0348 nla_b = nla_nest_start_noflag(skb,
0349 NLBL_MGMT_A_ADDRSELECTOR);
0350 if (nla_b == NULL)
0351 return -ENOMEM;
0352
0353 ret_val = nla_put_in6_addr(skb, NLBL_MGMT_A_IPV6ADDR,
0354 &iter6->addr);
0355 if (ret_val != 0)
0356 return ret_val;
0357 ret_val = nla_put_in6_addr(skb, NLBL_MGMT_A_IPV6MASK,
0358 &iter6->mask);
0359 if (ret_val != 0)
0360 return ret_val;
0361 map6 = netlbl_domhsh_addr6_entry(iter6);
0362 ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
0363 map6->def.type);
0364 if (ret_val != 0)
0365 return ret_val;
0366
0367 switch (map6->def.type) {
0368 case NETLBL_NLTYPE_CALIPSO:
0369 ret_val = nla_put_u32(skb, NLBL_MGMT_A_CLPDOI,
0370 map6->def.calipso->doi);
0371 if (ret_val != 0)
0372 return ret_val;
0373 break;
0374 }
0375
0376 nla_nest_end(skb, nla_b);
0377 }
0378 #endif
0379
0380 nla_nest_end(skb, nla_a);
0381 break;
0382 case NETLBL_NLTYPE_UNLABELED:
0383 ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
0384 entry->def.type);
0385 break;
0386 case NETLBL_NLTYPE_CIPSOV4:
0387 ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
0388 entry->def.type);
0389 if (ret_val != 0)
0390 return ret_val;
0391 ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI,
0392 entry->def.cipso->doi);
0393 break;
0394 case NETLBL_NLTYPE_CALIPSO:
0395 ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
0396 entry->def.type);
0397 if (ret_val != 0)
0398 return ret_val;
0399 ret_val = nla_put_u32(skb, NLBL_MGMT_A_CLPDOI,
0400 entry->def.calipso->doi);
0401 break;
0402 }
0403
0404 return ret_val;
0405 }
0406
0407
0408
0409
0410
0411
0412
0413
0414
0415
0416
0417
0418
0419
0420
0421
0422 static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info)
0423 {
0424 struct netlbl_audit audit_info;
0425
0426 if ((!info->attrs[NLBL_MGMT_A_DOMAIN]) ||
0427 (!info->attrs[NLBL_MGMT_A_PROTOCOL]) ||
0428 (info->attrs[NLBL_MGMT_A_IPV4ADDR] &&
0429 info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
0430 (info->attrs[NLBL_MGMT_A_IPV4MASK] &&
0431 info->attrs[NLBL_MGMT_A_IPV6MASK]) ||
0432 ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^
0433 (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) ||
0434 ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^
0435 (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL)))
0436 return -EINVAL;
0437
0438 netlbl_netlink_auditinfo(&audit_info);
0439
0440 return netlbl_mgmt_add_common(info, &audit_info);
0441 }
0442
0443
0444
0445
0446
0447
0448
0449
0450
0451
0452
0453 static int netlbl_mgmt_remove(struct sk_buff *skb, struct genl_info *info)
0454 {
0455 char *domain;
0456 struct netlbl_audit audit_info;
0457
0458 if (!info->attrs[NLBL_MGMT_A_DOMAIN])
0459 return -EINVAL;
0460
0461 netlbl_netlink_auditinfo(&audit_info);
0462
0463 domain = nla_data(info->attrs[NLBL_MGMT_A_DOMAIN]);
0464 return netlbl_domhsh_remove(domain, AF_UNSPEC, &audit_info);
0465 }
0466
0467
0468
0469
0470
0471
0472
0473
0474
0475
0476
0477
0478
0479 static int netlbl_mgmt_listall_cb(struct netlbl_dom_map *entry, void *arg)
0480 {
0481 int ret_val = -ENOMEM;
0482 struct netlbl_domhsh_walk_arg *cb_arg = arg;
0483 void *data;
0484
0485 data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).portid,
0486 cb_arg->seq, &netlbl_mgmt_gnl_family,
0487 NLM_F_MULTI, NLBL_MGMT_C_LISTALL);
0488 if (data == NULL)
0489 goto listall_cb_failure;
0490
0491 ret_val = netlbl_mgmt_listentry(cb_arg->skb, entry);
0492 if (ret_val != 0)
0493 goto listall_cb_failure;
0494
0495 cb_arg->seq++;
0496 genlmsg_end(cb_arg->skb, data);
0497 return 0;
0498
0499 listall_cb_failure:
0500 genlmsg_cancel(cb_arg->skb, data);
0501 return ret_val;
0502 }
0503
0504
0505
0506
0507
0508
0509
0510
0511
0512
0513
0514
0515 static int netlbl_mgmt_listall(struct sk_buff *skb,
0516 struct netlink_callback *cb)
0517 {
0518 struct netlbl_domhsh_walk_arg cb_arg;
0519 u32 skip_bkt = cb->args[0];
0520 u32 skip_chain = cb->args[1];
0521
0522 cb_arg.nl_cb = cb;
0523 cb_arg.skb = skb;
0524 cb_arg.seq = cb->nlh->nlmsg_seq;
0525
0526 netlbl_domhsh_walk(&skip_bkt,
0527 &skip_chain,
0528 netlbl_mgmt_listall_cb,
0529 &cb_arg);
0530
0531 cb->args[0] = skip_bkt;
0532 cb->args[1] = skip_chain;
0533 return skb->len;
0534 }
0535
0536
0537
0538
0539
0540
0541
0542
0543
0544
0545
0546 static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info)
0547 {
0548 struct netlbl_audit audit_info;
0549
0550 if ((!info->attrs[NLBL_MGMT_A_PROTOCOL]) ||
0551 (info->attrs[NLBL_MGMT_A_IPV4ADDR] &&
0552 info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
0553 (info->attrs[NLBL_MGMT_A_IPV4MASK] &&
0554 info->attrs[NLBL_MGMT_A_IPV6MASK]) ||
0555 ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^
0556 (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) ||
0557 ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^
0558 (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL)))
0559 return -EINVAL;
0560
0561 netlbl_netlink_auditinfo(&audit_info);
0562
0563 return netlbl_mgmt_add_common(info, &audit_info);
0564 }
0565
0566
0567
0568
0569
0570
0571
0572
0573
0574
0575
0576 static int netlbl_mgmt_removedef(struct sk_buff *skb, struct genl_info *info)
0577 {
0578 struct netlbl_audit audit_info;
0579
0580 netlbl_netlink_auditinfo(&audit_info);
0581
0582 return netlbl_domhsh_remove_default(AF_UNSPEC, &audit_info);
0583 }
0584
0585
0586
0587
0588
0589
0590
0591
0592
0593
0594
0595
0596 static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info)
0597 {
0598 int ret_val = -ENOMEM;
0599 struct sk_buff *ans_skb = NULL;
0600 void *data;
0601 struct netlbl_dom_map *entry;
0602 u16 family;
0603
0604 if (info->attrs[NLBL_MGMT_A_FAMILY])
0605 family = nla_get_u16(info->attrs[NLBL_MGMT_A_FAMILY]);
0606 else
0607 family = AF_INET;
0608
0609 ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
0610 if (ans_skb == NULL)
0611 return -ENOMEM;
0612 data = genlmsg_put_reply(ans_skb, info, &netlbl_mgmt_gnl_family,
0613 0, NLBL_MGMT_C_LISTDEF);
0614 if (data == NULL)
0615 goto listdef_failure;
0616
0617 rcu_read_lock();
0618 entry = netlbl_domhsh_getentry(NULL, family);
0619 if (entry == NULL) {
0620 ret_val = -ENOENT;
0621 goto listdef_failure_lock;
0622 }
0623 ret_val = netlbl_mgmt_listentry(ans_skb, entry);
0624 rcu_read_unlock();
0625 if (ret_val != 0)
0626 goto listdef_failure;
0627
0628 genlmsg_end(ans_skb, data);
0629 return genlmsg_reply(ans_skb, info);
0630
0631 listdef_failure_lock:
0632 rcu_read_unlock();
0633 listdef_failure:
0634 kfree_skb(ans_skb);
0635 return ret_val;
0636 }
0637
0638
0639
0640
0641
0642
0643
0644
0645
0646
0647
0648
0649
0650 static int netlbl_mgmt_protocols_cb(struct sk_buff *skb,
0651 struct netlink_callback *cb,
0652 u32 protocol)
0653 {
0654 int ret_val = -ENOMEM;
0655 void *data;
0656
0657 data = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
0658 &netlbl_mgmt_gnl_family, NLM_F_MULTI,
0659 NLBL_MGMT_C_PROTOCOLS);
0660 if (data == NULL)
0661 goto protocols_cb_failure;
0662
0663 ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, protocol);
0664 if (ret_val != 0)
0665 goto protocols_cb_failure;
0666
0667 genlmsg_end(skb, data);
0668 return 0;
0669
0670 protocols_cb_failure:
0671 genlmsg_cancel(skb, data);
0672 return ret_val;
0673 }
0674
0675
0676
0677
0678
0679
0680
0681
0682
0683
0684 static int netlbl_mgmt_protocols(struct sk_buff *skb,
0685 struct netlink_callback *cb)
0686 {
0687 u32 protos_sent = cb->args[0];
0688
0689 if (protos_sent == 0) {
0690 if (netlbl_mgmt_protocols_cb(skb,
0691 cb,
0692 NETLBL_NLTYPE_UNLABELED) < 0)
0693 goto protocols_return;
0694 protos_sent++;
0695 }
0696 if (protos_sent == 1) {
0697 if (netlbl_mgmt_protocols_cb(skb,
0698 cb,
0699 NETLBL_NLTYPE_CIPSOV4) < 0)
0700 goto protocols_return;
0701 protos_sent++;
0702 }
0703 #if IS_ENABLED(CONFIG_IPV6)
0704 if (protos_sent == 2) {
0705 if (netlbl_mgmt_protocols_cb(skb,
0706 cb,
0707 NETLBL_NLTYPE_CALIPSO) < 0)
0708 goto protocols_return;
0709 protos_sent++;
0710 }
0711 #endif
0712
0713 protocols_return:
0714 cb->args[0] = protos_sent;
0715 return skb->len;
0716 }
0717
0718
0719
0720
0721
0722
0723
0724
0725
0726
0727
0728 static int netlbl_mgmt_version(struct sk_buff *skb, struct genl_info *info)
0729 {
0730 int ret_val = -ENOMEM;
0731 struct sk_buff *ans_skb = NULL;
0732 void *data;
0733
0734 ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
0735 if (ans_skb == NULL)
0736 return -ENOMEM;
0737 data = genlmsg_put_reply(ans_skb, info, &netlbl_mgmt_gnl_family,
0738 0, NLBL_MGMT_C_VERSION);
0739 if (data == NULL)
0740 goto version_failure;
0741
0742 ret_val = nla_put_u32(ans_skb,
0743 NLBL_MGMT_A_VERSION,
0744 NETLBL_PROTO_VERSION);
0745 if (ret_val != 0)
0746 goto version_failure;
0747
0748 genlmsg_end(ans_skb, data);
0749 return genlmsg_reply(ans_skb, info);
0750
0751 version_failure:
0752 kfree_skb(ans_skb);
0753 return ret_val;
0754 }
0755
0756
0757
0758
0759
0760
0761 static const struct genl_small_ops netlbl_mgmt_genl_ops[] = {
0762 {
0763 .cmd = NLBL_MGMT_C_ADD,
0764 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
0765 .flags = GENL_ADMIN_PERM,
0766 .doit = netlbl_mgmt_add,
0767 .dumpit = NULL,
0768 },
0769 {
0770 .cmd = NLBL_MGMT_C_REMOVE,
0771 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
0772 .flags = GENL_ADMIN_PERM,
0773 .doit = netlbl_mgmt_remove,
0774 .dumpit = NULL,
0775 },
0776 {
0777 .cmd = NLBL_MGMT_C_LISTALL,
0778 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
0779 .flags = 0,
0780 .doit = NULL,
0781 .dumpit = netlbl_mgmt_listall,
0782 },
0783 {
0784 .cmd = NLBL_MGMT_C_ADDDEF,
0785 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
0786 .flags = GENL_ADMIN_PERM,
0787 .doit = netlbl_mgmt_adddef,
0788 .dumpit = NULL,
0789 },
0790 {
0791 .cmd = NLBL_MGMT_C_REMOVEDEF,
0792 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
0793 .flags = GENL_ADMIN_PERM,
0794 .doit = netlbl_mgmt_removedef,
0795 .dumpit = NULL,
0796 },
0797 {
0798 .cmd = NLBL_MGMT_C_LISTDEF,
0799 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
0800 .flags = 0,
0801 .doit = netlbl_mgmt_listdef,
0802 .dumpit = NULL,
0803 },
0804 {
0805 .cmd = NLBL_MGMT_C_PROTOCOLS,
0806 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
0807 .flags = 0,
0808 .doit = NULL,
0809 .dumpit = netlbl_mgmt_protocols,
0810 },
0811 {
0812 .cmd = NLBL_MGMT_C_VERSION,
0813 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
0814 .flags = 0,
0815 .doit = netlbl_mgmt_version,
0816 .dumpit = NULL,
0817 },
0818 };
0819
0820 static struct genl_family netlbl_mgmt_gnl_family __ro_after_init = {
0821 .hdrsize = 0,
0822 .name = NETLBL_NLTYPE_MGMT_NAME,
0823 .version = NETLBL_PROTO_VERSION,
0824 .maxattr = NLBL_MGMT_A_MAX,
0825 .policy = netlbl_mgmt_genl_policy,
0826 .module = THIS_MODULE,
0827 .small_ops = netlbl_mgmt_genl_ops,
0828 .n_small_ops = ARRAY_SIZE(netlbl_mgmt_genl_ops),
0829 };
0830
0831
0832
0833
0834
0835
0836
0837
0838
0839
0840
0841
0842
0843 int __init netlbl_mgmt_genl_init(void)
0844 {
0845 return genl_register_family(&netlbl_mgmt_gnl_family);
0846 }