Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.13-rc1 783 lines 20 kB view raw
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 <paul@paul-moore.com> 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 <linux/atomic.h> 46 47#include "netlabel_domainhash.h" 48#include "netlabel_user.h" 49#include "netlabel_mgmt.h" 50 51/* NetLabel configured protocol counter */ 52atomic_t netlabel_mgmt_protocount = ATOMIC_INIT(0); 53 54/* Argument struct for netlbl_domhsh_walk() */ 55struct 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 */ 62static 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 */ 71static 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 */ 93static 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->def.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->def.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->def.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->def.cipso = 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->def.type = entry->def.type; 176 if (cipsov4) 177 map->def.cipso = 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->def.type = NETLBL_NLTYPE_ADDRSELECT; 186 entry->def.addrsel = addrmap; 187#if IS_ENABLED(CONFIG_IPV6) 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 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 map->list.mask = *mask; 225 map->list.valid = 1; 226 map->def.type = entry->def.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->def.type = NETLBL_NLTYPE_ADDRSELECT; 235 entry->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 245add_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 */ 266static 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 IS_ENABLED(CONFIG_IPV6) 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->def.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, &entry->def.addrsel->list4) { 291 struct netlbl_domaddr4_map *map4; 292 struct in_addr addr_struct; 293 294 nla_b = nla_nest_start(skb, NLBL_MGMT_A_ADDRSELECTOR); 295 if (nla_b == NULL) 296 return -ENOMEM; 297 298 addr_struct.s_addr = iter4->addr; 299 ret_val = nla_put(skb, NLBL_MGMT_A_IPV4ADDR, 300 sizeof(struct in_addr), 301 &addr_struct); 302 if (ret_val != 0) 303 return ret_val; 304 addr_struct.s_addr = iter4->mask; 305 ret_val = nla_put(skb, NLBL_MGMT_A_IPV4MASK, 306 sizeof(struct in_addr), 307 &addr_struct); 308 if (ret_val != 0) 309 return ret_val; 310 map4 = netlbl_domhsh_addr4_entry(iter4); 311 ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, 312 map4->def.type); 313 if (ret_val != 0) 314 return ret_val; 315 switch (map4->def.type) { 316 case NETLBL_NLTYPE_CIPSOV4: 317 ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI, 318 map4->def.cipso->doi); 319 if (ret_val != 0) 320 return ret_val; 321 break; 322 } 323 324 nla_nest_end(skb, nla_b); 325 } 326#if IS_ENABLED(CONFIG_IPV6) 327 netlbl_af6list_foreach_rcu(iter6, &entry->def.addrsel->list6) { 328 struct netlbl_domaddr6_map *map6; 329 330 nla_b = nla_nest_start(skb, NLBL_MGMT_A_ADDRSELECTOR); 331 if (nla_b == NULL) 332 return -ENOMEM; 333 334 ret_val = nla_put(skb, NLBL_MGMT_A_IPV6ADDR, 335 sizeof(struct in6_addr), 336 &iter6->addr); 337 if (ret_val != 0) 338 return ret_val; 339 ret_val = nla_put(skb, NLBL_MGMT_A_IPV6MASK, 340 sizeof(struct in6_addr), 341 &iter6->mask); 342 if (ret_val != 0) 343 return ret_val; 344 map6 = netlbl_domhsh_addr6_entry(iter6); 345 ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, 346 map6->def.type); 347 if (ret_val != 0) 348 return ret_val; 349 350 nla_nest_end(skb, nla_b); 351 } 352#endif /* IPv6 */ 353 354 nla_nest_end(skb, nla_a); 355 break; 356 case NETLBL_NLTYPE_UNLABELED: 357 ret_val = nla_put_u32(skb,NLBL_MGMT_A_PROTOCOL,entry->def.type); 358 break; 359 case NETLBL_NLTYPE_CIPSOV4: 360 ret_val = nla_put_u32(skb,NLBL_MGMT_A_PROTOCOL,entry->def.type); 361 if (ret_val != 0) 362 return ret_val; 363 ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI, 364 entry->def.cipso->doi); 365 break; 366 } 367 368 return ret_val; 369} 370 371/* 372 * NetLabel Command Handlers 373 */ 374 375/** 376 * netlbl_mgmt_add - Handle an ADD message 377 * @skb: the NETLINK buffer 378 * @info: the Generic NETLINK info block 379 * 380 * Description: 381 * Process a user generated ADD message and add the domains from the message 382 * to the hash table. See netlabel.h for a description of the message format. 383 * Returns zero on success, negative values on failure. 384 * 385 */ 386static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info) 387{ 388 struct netlbl_audit audit_info; 389 390 if ((!info->attrs[NLBL_MGMT_A_DOMAIN]) || 391 (!info->attrs[NLBL_MGMT_A_PROTOCOL]) || 392 (info->attrs[NLBL_MGMT_A_IPV4ADDR] && 393 info->attrs[NLBL_MGMT_A_IPV6ADDR]) || 394 (info->attrs[NLBL_MGMT_A_IPV4MASK] && 395 info->attrs[NLBL_MGMT_A_IPV6MASK]) || 396 ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^ 397 (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) || 398 ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^ 399 (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL))) 400 return -EINVAL; 401 402 netlbl_netlink_auditinfo(skb, &audit_info); 403 404 return netlbl_mgmt_add_common(info, &audit_info); 405} 406 407/** 408 * netlbl_mgmt_remove - Handle a REMOVE message 409 * @skb: the NETLINK buffer 410 * @info: the Generic NETLINK info block 411 * 412 * Description: 413 * Process a user generated REMOVE message and remove the specified domain 414 * mappings. Returns zero on success, negative values on failure. 415 * 416 */ 417static int netlbl_mgmt_remove(struct sk_buff *skb, struct genl_info *info) 418{ 419 char *domain; 420 struct netlbl_audit audit_info; 421 422 if (!info->attrs[NLBL_MGMT_A_DOMAIN]) 423 return -EINVAL; 424 425 netlbl_netlink_auditinfo(skb, &audit_info); 426 427 domain = nla_data(info->attrs[NLBL_MGMT_A_DOMAIN]); 428 return netlbl_domhsh_remove(domain, &audit_info); 429} 430 431/** 432 * netlbl_mgmt_listall_cb - netlbl_domhsh_walk() callback for LISTALL 433 * @entry: the domain mapping hash table entry 434 * @arg: the netlbl_domhsh_walk_arg structure 435 * 436 * Description: 437 * This function is designed to be used as a callback to the 438 * netlbl_domhsh_walk() function for use in generating a response for a LISTALL 439 * message. Returns the size of the message on success, negative values on 440 * failure. 441 * 442 */ 443static int netlbl_mgmt_listall_cb(struct netlbl_dom_map *entry, void *arg) 444{ 445 int ret_val = -ENOMEM; 446 struct netlbl_domhsh_walk_arg *cb_arg = arg; 447 void *data; 448 449 data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).portid, 450 cb_arg->seq, &netlbl_mgmt_gnl_family, 451 NLM_F_MULTI, NLBL_MGMT_C_LISTALL); 452 if (data == NULL) 453 goto listall_cb_failure; 454 455 ret_val = netlbl_mgmt_listentry(cb_arg->skb, entry); 456 if (ret_val != 0) 457 goto listall_cb_failure; 458 459 cb_arg->seq++; 460 return genlmsg_end(cb_arg->skb, data); 461 462listall_cb_failure: 463 genlmsg_cancel(cb_arg->skb, data); 464 return ret_val; 465} 466 467/** 468 * netlbl_mgmt_listall - Handle a LISTALL message 469 * @skb: the NETLINK buffer 470 * @cb: the NETLINK callback 471 * 472 * Description: 473 * Process a user generated LISTALL message and dumps the domain hash table in 474 * a form suitable for use in a kernel generated LISTALL message. Returns zero 475 * on success, negative values on failure. 476 * 477 */ 478static int netlbl_mgmt_listall(struct sk_buff *skb, 479 struct netlink_callback *cb) 480{ 481 struct netlbl_domhsh_walk_arg cb_arg; 482 u32 skip_bkt = cb->args[0]; 483 u32 skip_chain = cb->args[1]; 484 485 cb_arg.nl_cb = cb; 486 cb_arg.skb = skb; 487 cb_arg.seq = cb->nlh->nlmsg_seq; 488 489 netlbl_domhsh_walk(&skip_bkt, 490 &skip_chain, 491 netlbl_mgmt_listall_cb, 492 &cb_arg); 493 494 cb->args[0] = skip_bkt; 495 cb->args[1] = skip_chain; 496 return skb->len; 497} 498 499/** 500 * netlbl_mgmt_adddef - Handle an ADDDEF message 501 * @skb: the NETLINK buffer 502 * @info: the Generic NETLINK info block 503 * 504 * Description: 505 * Process a user generated ADDDEF message and respond accordingly. Returns 506 * zero on success, negative values on failure. 507 * 508 */ 509static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info) 510{ 511 struct netlbl_audit audit_info; 512 513 if ((!info->attrs[NLBL_MGMT_A_PROTOCOL]) || 514 (info->attrs[NLBL_MGMT_A_IPV4ADDR] && 515 info->attrs[NLBL_MGMT_A_IPV6ADDR]) || 516 (info->attrs[NLBL_MGMT_A_IPV4MASK] && 517 info->attrs[NLBL_MGMT_A_IPV6MASK]) || 518 ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^ 519 (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) || 520 ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^ 521 (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL))) 522 return -EINVAL; 523 524 netlbl_netlink_auditinfo(skb, &audit_info); 525 526 return netlbl_mgmt_add_common(info, &audit_info); 527} 528 529/** 530 * netlbl_mgmt_removedef - Handle a REMOVEDEF message 531 * @skb: the NETLINK buffer 532 * @info: the Generic NETLINK info block 533 * 534 * Description: 535 * Process a user generated REMOVEDEF message and remove the default domain 536 * mapping. Returns zero on success, negative values on failure. 537 * 538 */ 539static int netlbl_mgmt_removedef(struct sk_buff *skb, struct genl_info *info) 540{ 541 struct netlbl_audit audit_info; 542 543 netlbl_netlink_auditinfo(skb, &audit_info); 544 545 return netlbl_domhsh_remove_default(&audit_info); 546} 547 548/** 549 * netlbl_mgmt_listdef - Handle a LISTDEF message 550 * @skb: the NETLINK buffer 551 * @info: the Generic NETLINK info block 552 * 553 * Description: 554 * Process a user generated LISTDEF message and dumps the default domain 555 * mapping in a form suitable for use in a kernel generated LISTDEF message. 556 * Returns zero on success, negative values on failure. 557 * 558 */ 559static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info) 560{ 561 int ret_val = -ENOMEM; 562 struct sk_buff *ans_skb = NULL; 563 void *data; 564 struct netlbl_dom_map *entry; 565 566 ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 567 if (ans_skb == NULL) 568 return -ENOMEM; 569 data = genlmsg_put_reply(ans_skb, info, &netlbl_mgmt_gnl_family, 570 0, NLBL_MGMT_C_LISTDEF); 571 if (data == NULL) 572 goto listdef_failure; 573 574 rcu_read_lock(); 575 entry = netlbl_domhsh_getentry(NULL); 576 if (entry == NULL) { 577 ret_val = -ENOENT; 578 goto listdef_failure_lock; 579 } 580 ret_val = netlbl_mgmt_listentry(ans_skb, entry); 581 rcu_read_unlock(); 582 if (ret_val != 0) 583 goto listdef_failure; 584 585 genlmsg_end(ans_skb, data); 586 return genlmsg_reply(ans_skb, info); 587 588listdef_failure_lock: 589 rcu_read_unlock(); 590listdef_failure: 591 kfree_skb(ans_skb); 592 return ret_val; 593} 594 595/** 596 * netlbl_mgmt_protocols_cb - Write an individual PROTOCOL message response 597 * @skb: the skb to write to 598 * @cb: the NETLINK callback 599 * @protocol: the NetLabel protocol to use in the message 600 * 601 * Description: 602 * This function is to be used in conjunction with netlbl_mgmt_protocols() to 603 * answer a application's PROTOCOLS message. Returns the size of the message 604 * on success, negative values on failure. 605 * 606 */ 607static int netlbl_mgmt_protocols_cb(struct sk_buff *skb, 608 struct netlink_callback *cb, 609 u32 protocol) 610{ 611 int ret_val = -ENOMEM; 612 void *data; 613 614 data = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, 615 &netlbl_mgmt_gnl_family, NLM_F_MULTI, 616 NLBL_MGMT_C_PROTOCOLS); 617 if (data == NULL) 618 goto protocols_cb_failure; 619 620 ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, protocol); 621 if (ret_val != 0) 622 goto protocols_cb_failure; 623 624 return genlmsg_end(skb, data); 625 626protocols_cb_failure: 627 genlmsg_cancel(skb, data); 628 return ret_val; 629} 630 631/** 632 * netlbl_mgmt_protocols - Handle a PROTOCOLS message 633 * @skb: the NETLINK buffer 634 * @cb: the NETLINK callback 635 * 636 * Description: 637 * Process a user generated PROTOCOLS message and respond accordingly. 638 * 639 */ 640static int netlbl_mgmt_protocols(struct sk_buff *skb, 641 struct netlink_callback *cb) 642{ 643 u32 protos_sent = cb->args[0]; 644 645 if (protos_sent == 0) { 646 if (netlbl_mgmt_protocols_cb(skb, 647 cb, 648 NETLBL_NLTYPE_UNLABELED) < 0) 649 goto protocols_return; 650 protos_sent++; 651 } 652 if (protos_sent == 1) { 653 if (netlbl_mgmt_protocols_cb(skb, 654 cb, 655 NETLBL_NLTYPE_CIPSOV4) < 0) 656 goto protocols_return; 657 protos_sent++; 658 } 659 660protocols_return: 661 cb->args[0] = protos_sent; 662 return skb->len; 663} 664 665/** 666 * netlbl_mgmt_version - Handle a VERSION message 667 * @skb: the NETLINK buffer 668 * @info: the Generic NETLINK info block 669 * 670 * Description: 671 * Process a user generated VERSION message and respond accordingly. Returns 672 * zero on success, negative values on failure. 673 * 674 */ 675static int netlbl_mgmt_version(struct sk_buff *skb, struct genl_info *info) 676{ 677 int ret_val = -ENOMEM; 678 struct sk_buff *ans_skb = NULL; 679 void *data; 680 681 ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 682 if (ans_skb == NULL) 683 return -ENOMEM; 684 data = genlmsg_put_reply(ans_skb, info, &netlbl_mgmt_gnl_family, 685 0, NLBL_MGMT_C_VERSION); 686 if (data == NULL) 687 goto version_failure; 688 689 ret_val = nla_put_u32(ans_skb, 690 NLBL_MGMT_A_VERSION, 691 NETLBL_PROTO_VERSION); 692 if (ret_val != 0) 693 goto version_failure; 694 695 genlmsg_end(ans_skb, data); 696 return genlmsg_reply(ans_skb, info); 697 698version_failure: 699 kfree_skb(ans_skb); 700 return ret_val; 701} 702 703 704/* 705 * NetLabel Generic NETLINK Command Definitions 706 */ 707 708static const struct genl_ops netlbl_mgmt_genl_ops[] = { 709 { 710 .cmd = NLBL_MGMT_C_ADD, 711 .flags = GENL_ADMIN_PERM, 712 .policy = netlbl_mgmt_genl_policy, 713 .doit = netlbl_mgmt_add, 714 .dumpit = NULL, 715 }, 716 { 717 .cmd = NLBL_MGMT_C_REMOVE, 718 .flags = GENL_ADMIN_PERM, 719 .policy = netlbl_mgmt_genl_policy, 720 .doit = netlbl_mgmt_remove, 721 .dumpit = NULL, 722 }, 723 { 724 .cmd = NLBL_MGMT_C_LISTALL, 725 .flags = 0, 726 .policy = netlbl_mgmt_genl_policy, 727 .doit = NULL, 728 .dumpit = netlbl_mgmt_listall, 729 }, 730 { 731 .cmd = NLBL_MGMT_C_ADDDEF, 732 .flags = GENL_ADMIN_PERM, 733 .policy = netlbl_mgmt_genl_policy, 734 .doit = netlbl_mgmt_adddef, 735 .dumpit = NULL, 736 }, 737 { 738 .cmd = NLBL_MGMT_C_REMOVEDEF, 739 .flags = GENL_ADMIN_PERM, 740 .policy = netlbl_mgmt_genl_policy, 741 .doit = netlbl_mgmt_removedef, 742 .dumpit = NULL, 743 }, 744 { 745 .cmd = NLBL_MGMT_C_LISTDEF, 746 .flags = 0, 747 .policy = netlbl_mgmt_genl_policy, 748 .doit = netlbl_mgmt_listdef, 749 .dumpit = NULL, 750 }, 751 { 752 .cmd = NLBL_MGMT_C_PROTOCOLS, 753 .flags = 0, 754 .policy = netlbl_mgmt_genl_policy, 755 .doit = NULL, 756 .dumpit = netlbl_mgmt_protocols, 757 }, 758 { 759 .cmd = NLBL_MGMT_C_VERSION, 760 .flags = 0, 761 .policy = netlbl_mgmt_genl_policy, 762 .doit = netlbl_mgmt_version, 763 .dumpit = NULL, 764 }, 765}; 766 767/* 768 * NetLabel Generic NETLINK Protocol Functions 769 */ 770 771/** 772 * netlbl_mgmt_genl_init - Register the NetLabel management component 773 * 774 * Description: 775 * Register the NetLabel management component with the Generic NETLINK 776 * mechanism. Returns zero on success, negative values on failure. 777 * 778 */ 779int __init netlbl_mgmt_genl_init(void) 780{ 781 return genl_register_family_with_ops(&netlbl_mgmt_gnl_family, 782 netlbl_mgmt_genl_ops); 783}