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