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