1 /*- 2 * Copyright (c) 2014-2015 Sandvine Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/param.h> 28 #include <sys/conf.h> 29 #include <sys/ctype.h> 30 #include <sys/kernel.h> 31 #include <sys/systm.h> 32 #include <sys/iov.h> 33 #include <sys/malloc.h> 34 #include <sys/module.h> 35 #include <sys/queue.h> 36 #include <sys/stdarg.h> 37 38 #include <sys/dnv.h> 39 #include <sys/nv.h> 40 #include <sys/iov_schema.h> 41 42 #include <net/ethernet.h> 43 44 #include <dev/pci/schema_private.h> 45 46 struct config_type_validator; 47 typedef int (validate_func)(const struct config_type_validator *, 48 const nvlist_t *, const char *name); 49 typedef int (default_validate_t)(const struct config_type_validator *, 50 const nvlist_t *); 51 52 static validate_func pci_iov_schema_validate_bool; 53 static validate_func pci_iov_schema_validate_string; 54 static validate_func pci_iov_schema_validate_uint; 55 static validate_func pci_iov_schema_validate_unicast_mac; 56 static validate_func pci_iov_schema_validate_vlan; 57 58 static default_validate_t pci_iov_validate_bool_default; 59 static default_validate_t pci_iov_validate_string_default; 60 static default_validate_t pci_iov_validate_uint_default; 61 static default_validate_t pci_iov_validate_unicast_mac_default; 62 static default_validate_t pci_iov_validate_vlan_default; 63 64 struct config_type_validator { 65 const char *type_name; 66 validate_func *validate; 67 default_validate_t *default_validate; 68 uintmax_t limit; 69 }; 70 71 static struct config_type_validator pci_iov_schema_validators[] = { 72 { 73 .type_name = "bool", 74 .validate = pci_iov_schema_validate_bool, 75 .default_validate = pci_iov_validate_bool_default 76 }, 77 { 78 .type_name = "string", 79 .validate = pci_iov_schema_validate_string, 80 .default_validate = pci_iov_validate_string_default 81 }, 82 { 83 .type_name = "uint8_t", 84 .validate = pci_iov_schema_validate_uint, 85 .default_validate = pci_iov_validate_uint_default, 86 .limit = UINT8_MAX 87 }, 88 { 89 .type_name = "uint16_t", 90 .validate = pci_iov_schema_validate_uint, 91 .default_validate = pci_iov_validate_uint_default, 92 .limit = UINT16_MAX 93 }, 94 { 95 .type_name = "uint32_t", 96 .validate = pci_iov_schema_validate_uint, 97 .default_validate = pci_iov_validate_uint_default, 98 .limit = UINT32_MAX 99 }, 100 { 101 .type_name = "uint64_t", 102 .validate = pci_iov_schema_validate_uint, 103 .default_validate = pci_iov_validate_uint_default, 104 .limit = UINT64_MAX 105 }, 106 { 107 .type_name = "unicast-mac", 108 .validate = pci_iov_schema_validate_unicast_mac, 109 .default_validate = pci_iov_validate_unicast_mac_default, 110 }, 111 { 112 .type_name = "vlan", 113 .validate = pci_iov_schema_validate_vlan, 114 .default_validate = pci_iov_validate_vlan_default, 115 }, 116 }; 117 118 static const struct config_type_validator * 119 pci_iov_schema_find_validator(const char *type) 120 { 121 struct config_type_validator *validator; 122 int i; 123 124 for (i = 0; i < nitems(pci_iov_schema_validators); i++) { 125 validator = &pci_iov_schema_validators[i]; 126 if (strcmp(type, validator->type_name) == 0) 127 return (validator); 128 } 129 130 return (NULL); 131 } 132 133 static void 134 pci_iov_schema_add_type(nvlist_t *entry, const char *type) 135 { 136 137 if (pci_iov_schema_find_validator(type) == NULL) { 138 nvlist_set_error(entry, EINVAL); 139 return; 140 } 141 nvlist_add_string(entry, "type", type); 142 } 143 144 static void 145 pci_iov_schema_add_required(nvlist_t *entry, uint32_t flags) 146 { 147 148 if (flags & IOV_SCHEMA_REQUIRED) { 149 if (flags & IOV_SCHEMA_HASDEFAULT) { 150 nvlist_set_error(entry, EINVAL); 151 return; 152 } 153 154 nvlist_add_bool(entry, "required", 1); 155 } 156 } 157 158 void 159 pci_iov_schema_add_bool(nvlist_t *schema, const char *name, uint32_t flags, 160 int defaultVal) 161 { 162 nvlist_t *entry; 163 164 entry = nvlist_create(NV_FLAG_IGNORE_CASE); 165 if (entry == NULL) { 166 nvlist_set_error(schema, ENOMEM); 167 return; 168 } 169 170 pci_iov_schema_add_type(entry, "bool"); 171 if (flags & IOV_SCHEMA_HASDEFAULT) 172 nvlist_add_bool(entry, "default", defaultVal); 173 pci_iov_schema_add_required(entry, flags); 174 175 nvlist_move_nvlist(schema, name, entry); 176 } 177 178 void 179 pci_iov_schema_add_string(nvlist_t *schema, const char *name, uint32_t flags, 180 const char *defaultVal) 181 { 182 nvlist_t *entry; 183 184 entry = nvlist_create(NV_FLAG_IGNORE_CASE); 185 if (entry == NULL) { 186 nvlist_set_error(schema, ENOMEM); 187 return; 188 } 189 190 pci_iov_schema_add_type(entry, "string"); 191 if (flags & IOV_SCHEMA_HASDEFAULT) 192 nvlist_add_string(entry, "default", defaultVal); 193 pci_iov_schema_add_required(entry, flags); 194 195 nvlist_move_nvlist(schema, name, entry); 196 } 197 198 static void 199 pci_iov_schema_int(nvlist_t *schema, const char *name, const char *type, 200 uint32_t flags, uint64_t defaultVal) 201 { 202 nvlist_t *entry; 203 204 entry = nvlist_create(NV_FLAG_IGNORE_CASE); 205 if (entry == NULL) { 206 nvlist_set_error(schema, ENOMEM); 207 return; 208 } 209 210 pci_iov_schema_add_type(entry, type); 211 if (flags & IOV_SCHEMA_HASDEFAULT) 212 nvlist_add_number(entry, "default", defaultVal); 213 pci_iov_schema_add_required(entry, flags); 214 215 nvlist_move_nvlist(schema, name, entry); 216 } 217 218 void 219 pci_iov_schema_add_uint8(nvlist_t *schema, const char *name, uint32_t flags, 220 uint8_t defaultVal) 221 { 222 223 pci_iov_schema_int(schema, name, "uint8_t", flags, defaultVal); 224 } 225 226 void 227 pci_iov_schema_add_uint16(nvlist_t *schema, const char *name, uint32_t flags, 228 uint16_t defaultVal) 229 { 230 231 pci_iov_schema_int(schema, name, "uint16_t", flags, defaultVal); 232 } 233 234 void 235 pci_iov_schema_add_uint32(nvlist_t *schema, const char *name, uint32_t flags, 236 uint32_t defaultVal) 237 { 238 239 pci_iov_schema_int(schema, name, "uint32_t", flags, defaultVal); 240 } 241 242 void 243 pci_iov_schema_add_uint64(nvlist_t *schema, const char *name, uint32_t flags, 244 uint64_t defaultVal) 245 { 246 247 pci_iov_schema_int(schema, name, "uint64_t", flags, defaultVal); 248 } 249 250 void 251 pci_iov_schema_add_unicast_mac(nvlist_t *schema, const char *name, 252 uint32_t flags, const uint8_t * defaultVal) 253 { 254 nvlist_t *entry; 255 256 entry = nvlist_create(NV_FLAG_IGNORE_CASE); 257 if (entry == NULL) { 258 nvlist_set_error(schema, ENOMEM); 259 return; 260 } 261 262 pci_iov_schema_add_type(entry, "unicast-mac"); 263 if (flags & IOV_SCHEMA_HASDEFAULT) 264 nvlist_add_binary(entry, "default", defaultVal, ETHER_ADDR_LEN); 265 pci_iov_schema_add_required(entry, flags); 266 267 nvlist_move_nvlist(schema, name, entry); 268 } 269 270 void 271 pci_iov_schema_add_vlan(nvlist_t *schema, const char *name, 272 uint32_t flags, const uint16_t defaultVal) 273 { 274 nvlist_t *entry; 275 276 entry = nvlist_create(NV_FLAG_IGNORE_CASE); 277 if (entry == NULL) { 278 nvlist_set_error(schema, ENOMEM); 279 return; 280 } 281 282 pci_iov_schema_add_type(entry, "vlan"); 283 if (flags & IOV_SCHEMA_HASDEFAULT) 284 nvlist_add_number(entry, "default", defaultVal); 285 pci_iov_schema_add_required(entry, flags); 286 287 nvlist_move_nvlist(schema, name, entry); 288 } 289 290 static int 291 pci_iov_schema_validate_bool(const struct config_type_validator * validator, 292 const nvlist_t *config, const char *name) 293 { 294 295 if (!nvlist_exists_bool(config, name)) 296 return (EINVAL); 297 return (0); 298 } 299 300 static int 301 pci_iov_schema_validate_string(const struct config_type_validator * validator, 302 const nvlist_t *config, const char *name) 303 { 304 305 if (!nvlist_exists_string(config, name)) 306 return (EINVAL); 307 return (0); 308 } 309 310 static int 311 pci_iov_schema_validate_uint(const struct config_type_validator * validator, 312 const nvlist_t *config, const char *name) 313 { 314 uint64_t value; 315 316 if (!nvlist_exists_number(config, name)) 317 return (EINVAL); 318 319 value = nvlist_get_number(config, name); 320 321 if (value > validator->limit) 322 return (EINVAL); 323 324 return (0); 325 } 326 327 static int 328 pci_iov_schema_validate_unicast_mac( 329 const struct config_type_validator * validator, 330 const nvlist_t *config, const char *name) 331 { 332 const uint8_t *mac; 333 size_t size; 334 335 if (!nvlist_exists_binary(config, name)) 336 return (EINVAL); 337 338 mac = nvlist_get_binary(config, name, &size); 339 340 if (size != ETHER_ADDR_LEN) 341 return (EINVAL); 342 343 if (ETHER_IS_MULTICAST(mac)) 344 return (EINVAL); 345 346 return (0); 347 } 348 349 static int 350 pci_iov_schema_validate_vlan( 351 const struct config_type_validator * validator, 352 const nvlist_t *config, const char *name) 353 { 354 uint16_t vlan; 355 356 if (!nvlist_exists_number(config, name)) 357 return (EINVAL); 358 359 vlan = nvlist_get_number(config, name); 360 361 if (vlan > 4095 && vlan != VF_VLAN_TRUNK) 362 return (EINVAL); 363 364 return (0); 365 } 366 367 static void 368 pci_iov_config_add_default(const nvlist_t *param_schema, const char *name, 369 nvlist_t *config) 370 { 371 const void *binary; 372 size_t len; 373 374 if (nvlist_exists_binary(param_schema, "default")) { 375 binary = nvlist_get_binary(param_schema, "default", &len); 376 nvlist_add_binary(config, name, binary, len); 377 } else if (nvlist_exists_bool(param_schema, "default")) 378 nvlist_add_bool(config, name, 379 nvlist_get_bool(param_schema, "default")); 380 else if (nvlist_exists_number(param_schema, "default")) 381 nvlist_add_number(config, name, 382 nvlist_get_number(param_schema, "default")); 383 else if (nvlist_exists_nvlist(param_schema, "default")) 384 nvlist_add_nvlist(config, name, 385 nvlist_get_nvlist(param_schema, "default")); 386 else if (nvlist_exists_string(param_schema, "default")) 387 nvlist_add_string(config, name, 388 nvlist_get_string(param_schema, "default")); 389 else 390 panic("Unexpected nvlist type"); 391 } 392 393 static int 394 pci_iov_validate_bool_default(const struct config_type_validator * validator, 395 const nvlist_t *param) 396 { 397 398 if (!nvlist_exists_bool(param, DEFAULT_SCHEMA_NAME)) 399 return (EINVAL); 400 return (0); 401 } 402 403 static int 404 pci_iov_validate_string_default(const struct config_type_validator * validator, 405 const nvlist_t *param) 406 { 407 408 if (!nvlist_exists_string(param, DEFAULT_SCHEMA_NAME)) 409 return (EINVAL); 410 return (0); 411 } 412 413 static int 414 pci_iov_validate_uint_default(const struct config_type_validator * validator, 415 const nvlist_t *param) 416 { 417 uint64_t defaultVal; 418 419 if (!nvlist_exists_number(param, DEFAULT_SCHEMA_NAME)) 420 return (EINVAL); 421 422 defaultVal = nvlist_get_number(param, DEFAULT_SCHEMA_NAME); 423 if (defaultVal > validator->limit) 424 return (EINVAL); 425 return (0); 426 } 427 428 static int 429 pci_iov_validate_unicast_mac_default( 430 const struct config_type_validator * validator, const nvlist_t *param) 431 { 432 const uint8_t *mac; 433 size_t size; 434 435 if (!nvlist_exists_binary(param, DEFAULT_SCHEMA_NAME)) 436 return (EINVAL); 437 438 mac = nvlist_get_binary(param, DEFAULT_SCHEMA_NAME, &size); 439 if (size != ETHER_ADDR_LEN) 440 return (EINVAL); 441 442 if (ETHER_IS_MULTICAST(mac)) 443 return (EINVAL); 444 return (0); 445 } 446 447 static int 448 pci_iov_validate_vlan_default( 449 const struct config_type_validator * validator, const nvlist_t *param) 450 { 451 uint16_t vlan; 452 453 if (! nvlist_exists_number(param, DEFAULT_SCHEMA_NAME)) 454 return (EINVAL); 455 456 vlan = nvlist_get_number(param, DEFAULT_SCHEMA_NAME); 457 if (vlan > 4095 && vlan != VF_VLAN_TRUNK) 458 return (EINVAL); 459 460 return (0); 461 } 462 463 static int 464 pci_iov_validate_param_schema(const nvlist_t *schema) 465 { 466 const struct config_type_validator *validator; 467 const char *type; 468 int error; 469 470 /* All parameters must define a type. */ 471 if (!nvlist_exists_string(schema, TYPE_SCHEMA_NAME)) 472 return (EINVAL); 473 type = nvlist_get_string(schema, TYPE_SCHEMA_NAME); 474 475 validator = pci_iov_schema_find_validator(type); 476 if (validator == NULL) 477 return (EINVAL); 478 479 /* Validate that the default value conforms to the type. */ 480 if (nvlist_exists(schema, DEFAULT_SCHEMA_NAME)) { 481 error = validator->default_validate(validator, schema); 482 if (error != 0) 483 return (error); 484 485 /* Required and Default are mutually exclusive. */ 486 if (nvlist_exists(schema, REQUIRED_SCHEMA_NAME)) 487 return (EINVAL); 488 } 489 490 /* The "Required" field must be a bool. */ 491 if (nvlist_exists(schema, REQUIRED_SCHEMA_NAME)) { 492 if (!nvlist_exists_bool(schema, REQUIRED_SCHEMA_NAME)) 493 return (EINVAL); 494 } 495 496 return (0); 497 } 498 499 static int 500 pci_iov_validate_subsystem_schema(const nvlist_t *dev_schema, const char *name) 501 { 502 const nvlist_t *sub_schema, *param_schema; 503 const char *param_name; 504 void *it; 505 int type, error; 506 507 if (!nvlist_exists_nvlist(dev_schema, name)) 508 return (EINVAL); 509 sub_schema = nvlist_get_nvlist(dev_schema, name); 510 511 it = NULL; 512 while ((param_name = nvlist_next(sub_schema, &type, &it)) != NULL) { 513 if (type != NV_TYPE_NVLIST) 514 return (EINVAL); 515 param_schema = nvlist_get_nvlist(sub_schema, param_name); 516 517 error = pci_iov_validate_param_schema(param_schema); 518 if (error != 0) 519 return (error); 520 } 521 522 return (0); 523 } 524 525 /* 526 * Validate that the driver schema does not define any configuration parameters 527 * whose names collide with configuration parameters defined in the iov schema. 528 */ 529 static int 530 pci_iov_validate_param_collisions(const nvlist_t *dev_schema) 531 { 532 const nvlist_t *iov_schema, *driver_schema; 533 const char *name; 534 void *it; 535 int type; 536 537 driver_schema = nvlist_get_nvlist(dev_schema, DRIVER_CONFIG_NAME); 538 iov_schema = nvlist_get_nvlist(dev_schema, IOV_CONFIG_NAME); 539 540 it = NULL; 541 while ((name = nvlist_next(driver_schema, &type, &it)) != NULL) { 542 if (nvlist_exists(iov_schema, name)) 543 return (EINVAL); 544 } 545 546 return (0); 547 } 548 549 /* 550 * Validate that we only have IOV and DRIVER subsystems beneath the given 551 * device schema node. 552 */ 553 static int 554 pci_iov_validate_schema_subsystems(const nvlist_t *dev_schema) 555 { 556 const char *name; 557 void *it; 558 int type; 559 560 it = NULL; 561 while ((name = nvlist_next(dev_schema, &type, &it)) != NULL) { 562 if (strcmp(name, IOV_CONFIG_NAME) != 0 && 563 strcmp(name, DRIVER_CONFIG_NAME) != 0) 564 return (EINVAL); 565 } 566 567 return (0); 568 } 569 570 static int 571 pci_iov_validate_device_schema(const nvlist_t *schema, const char *name) 572 { 573 const nvlist_t *dev_schema; 574 int error; 575 576 if (!nvlist_exists_nvlist(schema, name)) 577 return (EINVAL); 578 dev_schema = nvlist_get_nvlist(schema, name); 579 580 error = pci_iov_validate_subsystem_schema(dev_schema, IOV_CONFIG_NAME); 581 if (error != 0) 582 return (error); 583 584 error = pci_iov_validate_subsystem_schema(dev_schema, 585 DRIVER_CONFIG_NAME); 586 if (error != 0) 587 return (error); 588 589 error = pci_iov_validate_param_collisions(dev_schema); 590 if (error != 0) 591 return (error); 592 593 return (pci_iov_validate_schema_subsystems(dev_schema)); 594 } 595 596 /* Validate that we only have PF and VF devices beneath the top-level schema. */ 597 static int 598 pci_iov_validate_schema_devices(const nvlist_t *dev_schema) 599 { 600 const char *name; 601 void *it; 602 int type; 603 604 it = NULL; 605 while ((name = nvlist_next(dev_schema, &type, &it)) != NULL) { 606 if (strcmp(name, PF_CONFIG_NAME) != 0 && 607 strcmp(name, VF_SCHEMA_NAME) != 0) 608 return (EINVAL); 609 } 610 611 return (0); 612 } 613 614 int 615 pci_iov_validate_schema(const nvlist_t *schema) 616 { 617 int error; 618 619 error = pci_iov_validate_device_schema(schema, PF_CONFIG_NAME); 620 if (error != 0) 621 return (error); 622 623 error = pci_iov_validate_device_schema(schema, VF_SCHEMA_NAME); 624 if (error != 0) 625 return (error); 626 627 return (pci_iov_validate_schema_devices(schema)); 628 } 629 630 /* 631 * Validate that all required parameters from the schema are specified in the 632 * config. If any parameter with a default value is not specified in the 633 * config, add it to config. 634 */ 635 static int 636 pci_iov_schema_validate_required(const nvlist_t *schema, nvlist_t *config) 637 { 638 const nvlist_t *param_schema; 639 const char *name; 640 void *cookie; 641 int type; 642 643 cookie = NULL; 644 while ((name = nvlist_next(schema, &type, &cookie)) != NULL) { 645 param_schema = nvlist_get_nvlist(schema, name); 646 647 if (dnvlist_get_bool(param_schema, "required", 0)) { 648 if (!nvlist_exists(config, name)) 649 return (EINVAL); 650 } 651 652 if (nvlist_exists(param_schema, "default") && 653 !nvlist_exists(config, name)) 654 pci_iov_config_add_default(param_schema, name, config); 655 } 656 657 return (nvlist_error(config)); 658 } 659 660 static int 661 pci_iov_schema_validate_param(const nvlist_t *schema_param, const char *name, 662 const nvlist_t *config) 663 { 664 const struct config_type_validator *validator; 665 const char *type; 666 667 type = nvlist_get_string(schema_param, "type"); 668 validator = pci_iov_schema_find_validator(type); 669 670 KASSERT(validator != NULL, 671 ("Schema was not validated: Unknown type %s", type)); 672 673 return (validator->validate(validator, config, name)); 674 } 675 676 /* 677 * Validate that all parameters in config are defined in the schema. Also 678 * validate that the type of the parameter matches the type in the schema. 679 */ 680 static int 681 pci_iov_schema_validate_types(const nvlist_t *schema, const nvlist_t *config) 682 { 683 const nvlist_t *schema_param; 684 void *cookie; 685 const char *name; 686 int type, error; 687 688 cookie = NULL; 689 while ((name = nvlist_next(config, &type, &cookie)) != NULL) { 690 if (!nvlist_exists_nvlist(schema, name)) 691 return (EINVAL); 692 693 schema_param = nvlist_get_nvlist(schema, name); 694 695 error = pci_iov_schema_validate_param(schema_param, name, 696 config); 697 698 if (error != 0) 699 return (error); 700 } 701 702 return (0); 703 } 704 705 static int 706 pci_iov_schema_validate_device(const nvlist_t *schema, nvlist_t *config, 707 const char *schema_device, const char *config_device) 708 { 709 const nvlist_t *device_schema, *iov_schema, *driver_schema; 710 nvlist_t *device_config, *iov_config, *driver_config; 711 int error; 712 713 device_config = NULL; 714 iov_config = NULL; 715 driver_config = NULL; 716 717 device_schema = nvlist_get_nvlist(schema, schema_device); 718 iov_schema = nvlist_get_nvlist(device_schema, IOV_CONFIG_NAME); 719 driver_schema = nvlist_get_nvlist(device_schema, DRIVER_CONFIG_NAME); 720 721 device_config = dnvlist_take_nvlist(config, config_device, NULL); 722 if (device_config == NULL) { 723 error = EINVAL; 724 goto out; 725 } 726 727 iov_config = dnvlist_take_nvlist(device_config, IOV_CONFIG_NAME, NULL); 728 if (iov_config == NULL) { 729 error = EINVAL; 730 goto out; 731 } 732 733 driver_config = dnvlist_take_nvlist(device_config, DRIVER_CONFIG_NAME, 734 NULL); 735 if (driver_config == NULL) { 736 error = EINVAL; 737 goto out; 738 } 739 740 error = pci_iov_schema_validate_required(iov_schema, iov_config); 741 if (error != 0) 742 goto out; 743 744 error = pci_iov_schema_validate_required(driver_schema, driver_config); 745 if (error != 0) 746 goto out; 747 748 error = pci_iov_schema_validate_types(iov_schema, iov_config); 749 if (error != 0) 750 goto out; 751 752 error = pci_iov_schema_validate_types(driver_schema, driver_config); 753 if (error != 0) 754 goto out; 755 756 out: 757 /* Note that these functions handle NULL pointers safely. */ 758 nvlist_move_nvlist(device_config, IOV_CONFIG_NAME, iov_config); 759 nvlist_move_nvlist(device_config, DRIVER_CONFIG_NAME, driver_config); 760 nvlist_move_nvlist(config, config_device, device_config); 761 762 return (error); 763 } 764 765 static int 766 pci_iov_schema_validate_vfs(const nvlist_t *schema, nvlist_t *config, 767 uint16_t num_vfs) 768 { 769 char device[VF_MAX_NAME]; 770 int i, error; 771 772 for (i = 0; i < num_vfs; i++) { 773 snprintf(device, sizeof(device), VF_PREFIX"%d", i); 774 775 error = pci_iov_schema_validate_device(schema, config, 776 VF_SCHEMA_NAME, device); 777 if (error != 0) 778 return (error); 779 } 780 781 return (0); 782 } 783 784 /* 785 * Validate that the device node only has IOV and DRIVER subnodes. 786 */ 787 static int 788 pci_iov_schema_validate_device_subsystems(const nvlist_t *config) 789 { 790 void *cookie; 791 const char *name; 792 int type; 793 794 cookie = NULL; 795 while ((name = nvlist_next(config, &type, &cookie)) != NULL) { 796 if (strcasecmp(name, IOV_CONFIG_NAME) == 0) 797 continue; 798 else if (strcasecmp(name, DRIVER_CONFIG_NAME) == 0) 799 continue; 800 801 return (EINVAL); 802 } 803 804 return (0); 805 } 806 807 /* 808 * Validate that the string is a valid device node name. It must either be "PF" 809 * or "VF-n", where n is an integer in the range [0, num_vfs). 810 */ 811 static int 812 pci_iov_schema_validate_dev_name(const char *name, uint16_t num_vfs) 813 { 814 const char *number_start; 815 char *endp; 816 u_long vf_num; 817 818 if (strcasecmp(PF_CONFIG_NAME, name) == 0) 819 return (0); 820 821 /* Ensure that we start with "VF-" */ 822 if (strncasecmp(name, VF_PREFIX, VF_PREFIX_LEN) != 0) 823 return (EINVAL); 824 825 number_start = name + VF_PREFIX_LEN; 826 827 /* Filter out name == "VF-" (no number) */ 828 if (number_start[0] == '\0') 829 return (EINVAL); 830 831 /* Disallow leading whitespace or +/- */ 832 if (!isdigit(number_start[0])) 833 return (EINVAL); 834 835 vf_num = strtoul(number_start, &endp, 10); 836 if (*endp != '\0') 837 return (EINVAL); 838 839 /* Disallow leading zeros on VF-[1-9][0-9]* */ 840 if (vf_num != 0 && number_start[0] == '0') 841 return (EINVAL); 842 843 /* Disallow leading zeros on VF-0 */ 844 if (vf_num == 0 && number_start[1] != '\0') 845 return (EINVAL); 846 847 if (vf_num >= num_vfs) 848 return (EINVAL); 849 850 return (0); 851 } 852 853 /* 854 * Validate that there are no device nodes in config other than the ones for 855 * the PF and the VFs. This includes validating that all config nodes of the 856 * form VF-n specify a VF number that is < num_vfs. 857 */ 858 static int 859 pci_iov_schema_validate_device_names(const nvlist_t *config, uint16_t num_vfs) 860 { 861 const nvlist_t *device; 862 void *cookie; 863 const char *name; 864 int type, error; 865 866 cookie = NULL; 867 while ((name = nvlist_next(config, &type, &cookie)) != NULL) { 868 error = pci_iov_schema_validate_dev_name(name, num_vfs); 869 if (error != 0) 870 return (error); 871 872 /* 873 * Note that as this is a valid PF/VF node, we know that 874 * pci_iov_schema_validate_device() has already checked that 875 * the PF/VF node is an nvlist. 876 */ 877 device = nvlist_get_nvlist(config, name); 878 error = pci_iov_schema_validate_device_subsystems(device); 879 if (error != 0) 880 return (error); 881 } 882 883 return (0); 884 } 885 886 int 887 pci_iov_schema_validate_config(const nvlist_t *schema, nvlist_t *config) 888 { 889 int error; 890 uint16_t num_vfs; 891 892 error = pci_iov_schema_validate_device(schema, config, PF_CONFIG_NAME, 893 PF_CONFIG_NAME); 894 if (error != 0) 895 return (error); 896 897 num_vfs = pci_iov_config_get_num_vfs(config); 898 899 error = pci_iov_schema_validate_vfs(schema, config, num_vfs); 900 if (error != 0) 901 return (error); 902 903 return (pci_iov_schema_validate_device_names(config, num_vfs)); 904 } 905 906 /* 907 * Return value of the num_vfs parameter. config must have already been 908 * validated, which guarantees that the parameter exists. 909 */ 910 uint16_t 911 pci_iov_config_get_num_vfs(const nvlist_t *config) 912 { 913 const nvlist_t *pf, *iov; 914 915 pf = nvlist_get_nvlist(config, PF_CONFIG_NAME); 916 iov = nvlist_get_nvlist(pf, IOV_CONFIG_NAME); 917 return (nvlist_get_number(iov, "num_vfs")); 918 } 919 920 /* Allocate a new empty schema node. */ 921 nvlist_t * 922 pci_iov_schema_alloc_node(void) 923 { 924 925 return (nvlist_create(NV_FLAG_IGNORE_CASE)); 926 } 927