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