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