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