xref: /freebsd/sys/dev/pci/pci_iov_schema.c (revision bdc48af26462b937e3bca9959a219e3d807d82ae)
11191f715SRyan Stone /*-
21191f715SRyan Stone  * Copyright (c) 2014-2015 Sandvine Inc.  All rights reserved.
31191f715SRyan Stone  * All rights reserved.
41191f715SRyan Stone  *
51191f715SRyan Stone  * Redistribution and use in source and binary forms, with or without
61191f715SRyan Stone  * modification, are permitted provided that the following conditions
71191f715SRyan Stone  * are met:
81191f715SRyan Stone  * 1. Redistributions of source code must retain the above copyright
91191f715SRyan Stone  *    notice, this list of conditions and the following disclaimer.
101191f715SRyan Stone  * 2. Redistributions in binary form must reproduce the above copyright
111191f715SRyan Stone  *    notice, this list of conditions and the following disclaimer in the
121191f715SRyan Stone  *    documentation and/or other materials provided with the distribution.
131191f715SRyan Stone  *
141191f715SRyan Stone  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
151191f715SRyan Stone  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
161191f715SRyan Stone  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
171191f715SRyan Stone  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
181191f715SRyan Stone  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
191191f715SRyan Stone  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
201191f715SRyan Stone  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
211191f715SRyan Stone  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
221191f715SRyan Stone  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
231191f715SRyan Stone  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
241191f715SRyan Stone  * SUCH DAMAGE.
251191f715SRyan Stone  */
261191f715SRyan Stone 
271191f715SRyan Stone #include <sys/cdefs.h>
281191f715SRyan Stone __FBSDID("$FreeBSD$");
291191f715SRyan Stone 
301191f715SRyan Stone #include <sys/param.h>
311191f715SRyan Stone #include <sys/conf.h>
323c22f215SRyan Stone #include <sys/ctype.h>
331191f715SRyan Stone #include <sys/kernel.h>
341191f715SRyan Stone #include <sys/systm.h>
353c22f215SRyan Stone #include <sys/iov.h>
361191f715SRyan Stone #include <sys/malloc.h>
371191f715SRyan Stone #include <sys/module.h>
381191f715SRyan Stone #include <sys/queue.h>
391191f715SRyan Stone 
401191f715SRyan Stone #include <machine/stdarg.h>
411191f715SRyan Stone 
423c22f215SRyan Stone #include <sys/dnv.h>
431191f715SRyan Stone #include <sys/nv.h>
441191f715SRyan Stone #include <sys/iov_schema.h>
451191f715SRyan Stone 
463c22f215SRyan Stone #include <net/ethernet.h>
473c22f215SRyan Stone 
481191f715SRyan Stone #include <dev/pci/schema_private.h>
491191f715SRyan Stone 
503c22f215SRyan Stone struct config_type_validator;
513c22f215SRyan Stone typedef int (validate_func)(const struct config_type_validator *,
523c22f215SRyan Stone    const nvlist_t *, const char *name);
53*bdc48af2SRyan Stone typedef int (default_validate_t)(const struct config_type_validator *,
54*bdc48af2SRyan Stone    const nvlist_t *);
553c22f215SRyan Stone 
563c22f215SRyan Stone static validate_func pci_iov_schema_validate_bool;
573c22f215SRyan Stone static validate_func pci_iov_schema_validate_string;
583c22f215SRyan Stone static validate_func pci_iov_schema_validate_uint;
593c22f215SRyan Stone static validate_func pci_iov_schema_validate_unicast_mac;
603c22f215SRyan Stone 
61*bdc48af2SRyan Stone static default_validate_t pci_iov_validate_bool_default;
62*bdc48af2SRyan Stone static default_validate_t pci_iov_validate_string_default;
63*bdc48af2SRyan Stone static default_validate_t pci_iov_validate_uint_default;
64*bdc48af2SRyan Stone static default_validate_t pci_iov_validate_unicast_mac_default;
65*bdc48af2SRyan Stone 
663c22f215SRyan Stone struct config_type_validator {
673c22f215SRyan Stone 	const char *type_name;
683c22f215SRyan Stone 	validate_func *validate;
69*bdc48af2SRyan Stone 	default_validate_t *default_validate;
703c22f215SRyan Stone 	uintmax_t limit;
711191f715SRyan Stone };
721191f715SRyan Stone 
733c22f215SRyan Stone static struct config_type_validator pci_iov_schema_validators[] = {
74*bdc48af2SRyan Stone 	{
75*bdc48af2SRyan Stone 		.type_name = "bool",
76*bdc48af2SRyan Stone 		.validate = pci_iov_schema_validate_bool,
77*bdc48af2SRyan Stone 		.default_validate = pci_iov_validate_bool_default
78*bdc48af2SRyan Stone 	},
79*bdc48af2SRyan Stone 	{
80*bdc48af2SRyan Stone 		.type_name = "string",
81*bdc48af2SRyan Stone 		.validate = pci_iov_schema_validate_string,
82*bdc48af2SRyan Stone 		.default_validate = pci_iov_validate_string_default
83*bdc48af2SRyan Stone 	},
84*bdc48af2SRyan Stone 	{
85*bdc48af2SRyan Stone 		.type_name = "uint8_t",
86*bdc48af2SRyan Stone 		.validate = pci_iov_schema_validate_uint,
87*bdc48af2SRyan Stone 		.default_validate = pci_iov_validate_uint_default,
88*bdc48af2SRyan Stone 		.limit = UINT8_MAX
89*bdc48af2SRyan Stone 	},
90*bdc48af2SRyan Stone 	{
91*bdc48af2SRyan Stone 		.type_name = "uint16_t",
92*bdc48af2SRyan Stone 		.validate = pci_iov_schema_validate_uint,
93*bdc48af2SRyan Stone 		.default_validate = pci_iov_validate_uint_default,
94*bdc48af2SRyan Stone 		.limit = UINT16_MAX
95*bdc48af2SRyan Stone 	},
96*bdc48af2SRyan Stone 	{
97*bdc48af2SRyan Stone 		.type_name = "uint32_t",
98*bdc48af2SRyan Stone 		.validate = pci_iov_schema_validate_uint,
99*bdc48af2SRyan Stone 		.default_validate = pci_iov_validate_uint_default,
100*bdc48af2SRyan Stone 		.limit = UINT32_MAX
101*bdc48af2SRyan Stone 	},
102*bdc48af2SRyan Stone 	{
103*bdc48af2SRyan Stone 		.type_name = "uint64_t",
104*bdc48af2SRyan Stone 		.validate = pci_iov_schema_validate_uint,
105*bdc48af2SRyan Stone 		.default_validate = pci_iov_validate_uint_default,
106*bdc48af2SRyan Stone 		.limit = UINT64_MAX
107*bdc48af2SRyan Stone 	},
108*bdc48af2SRyan Stone 	{
109*bdc48af2SRyan Stone 		.type_name = "unicast-mac",
110*bdc48af2SRyan Stone 		.validate = pci_iov_schema_validate_unicast_mac,
111*bdc48af2SRyan Stone 		.default_validate = pci_iov_validate_unicast_mac_default,
112*bdc48af2SRyan Stone 	},
1133c22f215SRyan Stone };
1143c22f215SRyan Stone 
1153c22f215SRyan Stone static const struct config_type_validator *
1163c22f215SRyan Stone pci_iov_schema_find_validator(const char *type)
1173c22f215SRyan Stone {
1183c22f215SRyan Stone 	struct config_type_validator *validator;
1193c22f215SRyan Stone 	int i;
1203c22f215SRyan Stone 
1213c22f215SRyan Stone 	for (i = 0; i < nitems(pci_iov_schema_validators); i++) {
1223c22f215SRyan Stone 		validator = &pci_iov_schema_validators[i];
1233c22f215SRyan Stone 		if (strcmp(type, validator->type_name) == 0)
1243c22f215SRyan Stone 			return (validator);
1253c22f215SRyan Stone 	}
1263c22f215SRyan Stone 
1273c22f215SRyan Stone 	return (NULL);
1283c22f215SRyan Stone }
1293c22f215SRyan Stone 
1301191f715SRyan Stone static void
1311191f715SRyan Stone pci_iov_schema_add_type(nvlist_t *entry, const char *type)
1321191f715SRyan Stone {
1331191f715SRyan Stone 
1343c22f215SRyan Stone 	if (pci_iov_schema_find_validator(type) == NULL) {
1353c22f215SRyan Stone 		nvlist_set_error(entry, EINVAL);
1361191f715SRyan Stone 		return;
1371191f715SRyan Stone 	}
1381191f715SRyan Stone 	nvlist_add_string(entry, "type", type);
1391191f715SRyan Stone }
1401191f715SRyan Stone 
1411191f715SRyan Stone static void
1421191f715SRyan Stone pci_iov_schema_add_required(nvlist_t *entry, uint32_t flags)
1431191f715SRyan Stone {
1441191f715SRyan Stone 
1451191f715SRyan Stone 	if (flags & IOV_SCHEMA_REQUIRED) {
1461191f715SRyan Stone 		if (flags & IOV_SCHEMA_HASDEFAULT) {
1471191f715SRyan Stone 			nvlist_set_error(entry, EINVAL);
1481191f715SRyan Stone 			return;
1491191f715SRyan Stone 		}
1501191f715SRyan Stone 
1511191f715SRyan Stone 		nvlist_add_bool(entry, "required", 1);
1521191f715SRyan Stone 	}
1531191f715SRyan Stone }
1541191f715SRyan Stone 
1551191f715SRyan Stone void
1561191f715SRyan Stone pci_iov_schema_add_bool(nvlist_t *schema, const char *name, uint32_t flags,
1571191f715SRyan Stone     int defaultVal)
1581191f715SRyan Stone {
1591191f715SRyan Stone 	nvlist_t *entry;
1601191f715SRyan Stone 
1611191f715SRyan Stone 	entry = nvlist_create(NV_FLAG_IGNORE_CASE);
1621191f715SRyan Stone 	if (entry == NULL) {
1631191f715SRyan Stone 		nvlist_set_error(schema, ENOMEM);
1641191f715SRyan Stone 		return;
1651191f715SRyan Stone 	}
1661191f715SRyan Stone 
1671191f715SRyan Stone 	pci_iov_schema_add_type(entry, "bool");
1681191f715SRyan Stone 	if (flags & IOV_SCHEMA_HASDEFAULT)
1691191f715SRyan Stone 		nvlist_add_bool(entry, "default", defaultVal);
1701191f715SRyan Stone 	pci_iov_schema_add_required(entry, flags);
1711191f715SRyan Stone 
1721191f715SRyan Stone 	nvlist_move_nvlist(schema, name, entry);
1731191f715SRyan Stone }
1741191f715SRyan Stone 
1751191f715SRyan Stone void
1761191f715SRyan Stone pci_iov_schema_add_string(nvlist_t *schema, const char *name, uint32_t flags,
1771191f715SRyan Stone     const char *defaultVal)
1781191f715SRyan Stone {
1791191f715SRyan Stone 	nvlist_t *entry;
1801191f715SRyan Stone 
1811191f715SRyan Stone 	entry = nvlist_create(NV_FLAG_IGNORE_CASE);
1821191f715SRyan Stone 	if (entry == NULL) {
1831191f715SRyan Stone 		nvlist_set_error(schema, ENOMEM);
1841191f715SRyan Stone 		return;
1851191f715SRyan Stone 	}
1861191f715SRyan Stone 
1871191f715SRyan Stone 	pci_iov_schema_add_type(entry, "string");
1881191f715SRyan Stone 	if (flags & IOV_SCHEMA_HASDEFAULT)
1891191f715SRyan Stone 		nvlist_add_string(entry, "default", defaultVal);
1901191f715SRyan Stone 	pci_iov_schema_add_required(entry, flags);
1911191f715SRyan Stone 
1921191f715SRyan Stone 	nvlist_move_nvlist(schema, name, entry);
1931191f715SRyan Stone }
1941191f715SRyan Stone 
1951191f715SRyan Stone static void
1961191f715SRyan Stone pci_iov_schema_int(nvlist_t *schema, const char *name, const char *type,
1971191f715SRyan Stone     uint32_t flags, uint64_t defaultVal)
1981191f715SRyan Stone {
1991191f715SRyan Stone 	nvlist_t *entry;
2001191f715SRyan Stone 
2011191f715SRyan Stone 	entry = nvlist_create(NV_FLAG_IGNORE_CASE);
2021191f715SRyan Stone 	if (entry == NULL) {
2031191f715SRyan Stone 		nvlist_set_error(schema, ENOMEM);
2041191f715SRyan Stone 		return;
2051191f715SRyan Stone 	}
2061191f715SRyan Stone 
2071191f715SRyan Stone 	pci_iov_schema_add_type(entry, type);
2081191f715SRyan Stone 	if (flags & IOV_SCHEMA_HASDEFAULT)
2091191f715SRyan Stone 		nvlist_add_number(entry, "default", defaultVal);
2101191f715SRyan Stone 	pci_iov_schema_add_required(entry, flags);
2111191f715SRyan Stone 
2121191f715SRyan Stone 	nvlist_move_nvlist(schema, name, entry);
2131191f715SRyan Stone }
2141191f715SRyan Stone 
2151191f715SRyan Stone void
2161191f715SRyan Stone pci_iov_schema_add_uint8(nvlist_t *schema, const char *name, uint32_t flags,
2171191f715SRyan Stone     uint8_t defaultVal)
2181191f715SRyan Stone {
2191191f715SRyan Stone 
2201191f715SRyan Stone 	pci_iov_schema_int(schema, name, "uint8_t", flags, defaultVal);
2211191f715SRyan Stone }
2221191f715SRyan Stone 
2231191f715SRyan Stone void
2241191f715SRyan Stone pci_iov_schema_add_uint16(nvlist_t *schema, const char *name, uint32_t flags,
2251191f715SRyan Stone     uint16_t defaultVal)
2261191f715SRyan Stone {
2271191f715SRyan Stone 
2281191f715SRyan Stone 	pci_iov_schema_int(schema, name, "uint16_t", flags, defaultVal);
2291191f715SRyan Stone }
2301191f715SRyan Stone 
2311191f715SRyan Stone void
2321191f715SRyan Stone pci_iov_schema_add_uint32(nvlist_t *schema, const char *name, uint32_t flags,
2331191f715SRyan Stone     uint32_t defaultVal)
2341191f715SRyan Stone {
2351191f715SRyan Stone 
2361191f715SRyan Stone 	pci_iov_schema_int(schema, name, "uint32_t", flags, defaultVal);
2371191f715SRyan Stone }
2381191f715SRyan Stone 
2391191f715SRyan Stone void
2401191f715SRyan Stone pci_iov_schema_add_uint64(nvlist_t *schema, const char *name, uint32_t flags,
2411191f715SRyan Stone     uint64_t defaultVal)
2421191f715SRyan Stone {
2431191f715SRyan Stone 
2441191f715SRyan Stone 	pci_iov_schema_int(schema, name, "uint64_t", flags, defaultVal);
2451191f715SRyan Stone }
2461191f715SRyan Stone 
2471191f715SRyan Stone void
2481191f715SRyan Stone pci_iov_schema_add_unicast_mac(nvlist_t *schema, const char *name,
2491191f715SRyan Stone     uint32_t flags, const uint8_t * defaultVal)
2501191f715SRyan Stone {
2511191f715SRyan Stone 	nvlist_t *entry;
2521191f715SRyan Stone 
2531191f715SRyan Stone 	entry = nvlist_create(NV_FLAG_IGNORE_CASE);
2541191f715SRyan Stone 	if (entry == NULL) {
2551191f715SRyan Stone 		nvlist_set_error(schema, ENOMEM);
2561191f715SRyan Stone 		return;
2571191f715SRyan Stone 	}
2581191f715SRyan Stone 
2591191f715SRyan Stone 	pci_iov_schema_add_type(entry, "unicast-mac");
2601191f715SRyan Stone 	if (flags & IOV_SCHEMA_HASDEFAULT)
2611191f715SRyan Stone 		nvlist_add_binary(entry, "default", defaultVal, ETHER_ADDR_LEN);
2621191f715SRyan Stone 	pci_iov_schema_add_required(entry, flags);
2631191f715SRyan Stone 
2641191f715SRyan Stone 	nvlist_move_nvlist(schema, name, entry);
2651191f715SRyan Stone }
2661191f715SRyan Stone 
2673c22f215SRyan Stone static int
2683c22f215SRyan Stone pci_iov_schema_validate_bool(const struct config_type_validator * validator,
2693c22f215SRyan Stone    const nvlist_t *config, const char *name)
2703c22f215SRyan Stone {
2713c22f215SRyan Stone 
2723c22f215SRyan Stone 	if (!nvlist_exists_bool(config, name))
2733c22f215SRyan Stone 		return (EINVAL);
2743c22f215SRyan Stone 	return (0);
2753c22f215SRyan Stone }
2763c22f215SRyan Stone 
2773c22f215SRyan Stone static int
2783c22f215SRyan Stone pci_iov_schema_validate_string(const struct config_type_validator * validator,
2793c22f215SRyan Stone    const nvlist_t *config, const char *name)
2803c22f215SRyan Stone {
2813c22f215SRyan Stone 
2823c22f215SRyan Stone 	if (!nvlist_exists_string(config, name))
2833c22f215SRyan Stone 		return (EINVAL);
2843c22f215SRyan Stone 	return (0);
2853c22f215SRyan Stone }
2863c22f215SRyan Stone 
2873c22f215SRyan Stone static int
2883c22f215SRyan Stone pci_iov_schema_validate_uint(const struct config_type_validator * validator,
2893c22f215SRyan Stone    const nvlist_t *config, const char *name)
2903c22f215SRyan Stone {
2913c22f215SRyan Stone 	uint64_t value;
2923c22f215SRyan Stone 
2933c22f215SRyan Stone 	if (!nvlist_exists_number(config, name))
2943c22f215SRyan Stone 		return (EINVAL);
2953c22f215SRyan Stone 
2963c22f215SRyan Stone 	value = nvlist_get_number(config, name);
2973c22f215SRyan Stone 
2983c22f215SRyan Stone 	if (value > validator->limit)
2993c22f215SRyan Stone 		return (EINVAL);
3003c22f215SRyan Stone 
3013c22f215SRyan Stone 	return (0);
3023c22f215SRyan Stone }
3033c22f215SRyan Stone 
3043c22f215SRyan Stone static int
3053c22f215SRyan Stone pci_iov_schema_validate_unicast_mac(
3063c22f215SRyan Stone    const struct config_type_validator * validator,
3073c22f215SRyan Stone    const nvlist_t *config, const char *name)
3083c22f215SRyan Stone {
3093c22f215SRyan Stone 	const uint8_t *mac;
3103c22f215SRyan Stone 	size_t size;
3113c22f215SRyan Stone 
3123c22f215SRyan Stone 	if (!nvlist_exists_binary(config, name))
3133c22f215SRyan Stone 		return (EINVAL);
3143c22f215SRyan Stone 
3153c22f215SRyan Stone 	mac = nvlist_get_binary(config, name, &size);
3163c22f215SRyan Stone 
3173c22f215SRyan Stone 	if (size != ETHER_ADDR_LEN)
3183c22f215SRyan Stone 		return (EINVAL);
3193c22f215SRyan Stone 
3203c22f215SRyan Stone 	if (ETHER_IS_MULTICAST(mac))
3213c22f215SRyan Stone 		return (EINVAL);
3223c22f215SRyan Stone 
3233c22f215SRyan Stone 	return (0);
3243c22f215SRyan Stone }
3253c22f215SRyan Stone 
3263c22f215SRyan Stone static void
3273c22f215SRyan Stone pci_iov_config_add_default(const nvlist_t *param_schema, const char *name,
3283c22f215SRyan Stone     nvlist_t *config)
3293c22f215SRyan Stone {
3303c22f215SRyan Stone 	const void *binary;
3313c22f215SRyan Stone 	size_t len;
3323c22f215SRyan Stone 
3333c22f215SRyan Stone 	if (nvlist_exists_binary(param_schema, "default")) {
3343c22f215SRyan Stone 		binary = nvlist_get_binary(param_schema, "default", &len);
3353c22f215SRyan Stone 		nvlist_add_binary(config, name, binary, len);
3363c22f215SRyan Stone 	} else if (nvlist_exists_bool(param_schema, "default"))
3373c22f215SRyan Stone 		nvlist_add_bool(config, name,
3383c22f215SRyan Stone 		    nvlist_get_bool(param_schema, "default"));
3393c22f215SRyan Stone 	else if (nvlist_exists_number(param_schema, "default"))
3403c22f215SRyan Stone 		nvlist_add_number(config, name,
3413c22f215SRyan Stone 		    nvlist_get_number(param_schema, "default"));
3423c22f215SRyan Stone 	else if (nvlist_exists_nvlist(param_schema, "default"))
3433c22f215SRyan Stone 		nvlist_add_nvlist(config, name,
3443c22f215SRyan Stone 		    nvlist_get_nvlist(param_schema, "default"));
3453c22f215SRyan Stone 	else if (nvlist_exists_string(param_schema, "default"))
3463c22f215SRyan Stone 		nvlist_add_string(config, name,
3473c22f215SRyan Stone 		    nvlist_get_string(param_schema, "default"));
3483c22f215SRyan Stone 	else
3493c22f215SRyan Stone 		panic("Unexpected nvlist type");
3503c22f215SRyan Stone }
3513c22f215SRyan Stone 
352*bdc48af2SRyan Stone static int
353*bdc48af2SRyan Stone pci_iov_validate_bool_default(const struct config_type_validator * validator,
354*bdc48af2SRyan Stone    const nvlist_t *param)
355*bdc48af2SRyan Stone {
356*bdc48af2SRyan Stone 
357*bdc48af2SRyan Stone 	if (!nvlist_exists_bool(param, DEFAULT_SCHEMA_NAME))
358*bdc48af2SRyan Stone 		return (EINVAL);
359*bdc48af2SRyan Stone 	return (0);
360*bdc48af2SRyan Stone }
361*bdc48af2SRyan Stone 
362*bdc48af2SRyan Stone static int
363*bdc48af2SRyan Stone pci_iov_validate_string_default(const struct config_type_validator * validator,
364*bdc48af2SRyan Stone    const nvlist_t *param)
365*bdc48af2SRyan Stone {
366*bdc48af2SRyan Stone 
367*bdc48af2SRyan Stone 	if (!nvlist_exists_string(param, DEFAULT_SCHEMA_NAME))
368*bdc48af2SRyan Stone 		return (EINVAL);
369*bdc48af2SRyan Stone 	return (0);
370*bdc48af2SRyan Stone }
371*bdc48af2SRyan Stone 
372*bdc48af2SRyan Stone static int
373*bdc48af2SRyan Stone pci_iov_validate_uint_default(const struct config_type_validator * validator,
374*bdc48af2SRyan Stone    const nvlist_t *param)
375*bdc48af2SRyan Stone {
376*bdc48af2SRyan Stone 	uint64_t defaultVal;
377*bdc48af2SRyan Stone 
378*bdc48af2SRyan Stone 	if (!nvlist_exists_number(param, DEFAULT_SCHEMA_NAME))
379*bdc48af2SRyan Stone 		return (EINVAL);
380*bdc48af2SRyan Stone 
381*bdc48af2SRyan Stone 	defaultVal = nvlist_get_number(param, DEFAULT_SCHEMA_NAME);
382*bdc48af2SRyan Stone 	if (defaultVal > validator->limit)
383*bdc48af2SRyan Stone 		return (EINVAL);
384*bdc48af2SRyan Stone 	return (0);
385*bdc48af2SRyan Stone }
386*bdc48af2SRyan Stone 
387*bdc48af2SRyan Stone static int
388*bdc48af2SRyan Stone pci_iov_validate_unicast_mac_default(
389*bdc48af2SRyan Stone    const struct config_type_validator * validator, const nvlist_t *param)
390*bdc48af2SRyan Stone {
391*bdc48af2SRyan Stone 	const uint8_t *mac;
392*bdc48af2SRyan Stone 	size_t size;
393*bdc48af2SRyan Stone 
394*bdc48af2SRyan Stone 	if (!nvlist_exists_binary(param, DEFAULT_SCHEMA_NAME))
395*bdc48af2SRyan Stone 		return (EINVAL);
396*bdc48af2SRyan Stone 
397*bdc48af2SRyan Stone 	mac = nvlist_get_binary(param, DEFAULT_SCHEMA_NAME, &size);
398*bdc48af2SRyan Stone 	if (size != ETHER_ADDR_LEN)
399*bdc48af2SRyan Stone 		return (EINVAL);
400*bdc48af2SRyan Stone 
401*bdc48af2SRyan Stone 	if (ETHER_IS_MULTICAST(mac))
402*bdc48af2SRyan Stone 		return (EINVAL);
403*bdc48af2SRyan Stone 	return (0);
404*bdc48af2SRyan Stone }
405*bdc48af2SRyan Stone 
406*bdc48af2SRyan Stone static int
407*bdc48af2SRyan Stone pci_iov_validate_param_schema(const nvlist_t *schema)
408*bdc48af2SRyan Stone {
409*bdc48af2SRyan Stone 	const struct config_type_validator *validator;
410*bdc48af2SRyan Stone 	const char *type;
411*bdc48af2SRyan Stone 	int error;
412*bdc48af2SRyan Stone 
413*bdc48af2SRyan Stone 	/* All parameters must define a type. */
414*bdc48af2SRyan Stone 	if (!nvlist_exists_string(schema, TYPE_SCHEMA_NAME))
415*bdc48af2SRyan Stone 		return (EINVAL);
416*bdc48af2SRyan Stone 	type = nvlist_get_string(schema, TYPE_SCHEMA_NAME);
417*bdc48af2SRyan Stone 
418*bdc48af2SRyan Stone 	validator = pci_iov_schema_find_validator(type);
419*bdc48af2SRyan Stone 	if (validator == NULL)
420*bdc48af2SRyan Stone 		return (EINVAL);
421*bdc48af2SRyan Stone 
422*bdc48af2SRyan Stone 	/* Validate that the default value conforms to the type. */
423*bdc48af2SRyan Stone 	if (nvlist_exists(schema, DEFAULT_SCHEMA_NAME)) {
424*bdc48af2SRyan Stone 		error = validator->default_validate(validator, schema);
425*bdc48af2SRyan Stone 		if (error != 0)
426*bdc48af2SRyan Stone 			return (error);
427*bdc48af2SRyan Stone 
428*bdc48af2SRyan Stone 		/* Required and Default are mutually exclusive. */
429*bdc48af2SRyan Stone 		if (nvlist_exists(schema, REQUIRED_SCHEMA_NAME))
430*bdc48af2SRyan Stone 			return (EINVAL);
431*bdc48af2SRyan Stone 	}
432*bdc48af2SRyan Stone 
433*bdc48af2SRyan Stone 	/* The "Required" field must be a bool. */
434*bdc48af2SRyan Stone 	if (nvlist_exists(schema, REQUIRED_SCHEMA_NAME)) {
435*bdc48af2SRyan Stone 		if (!nvlist_exists_bool(schema, REQUIRED_SCHEMA_NAME))
436*bdc48af2SRyan Stone 			return (EINVAL);
437*bdc48af2SRyan Stone 	}
438*bdc48af2SRyan Stone 
439*bdc48af2SRyan Stone 	return (0);
440*bdc48af2SRyan Stone }
441*bdc48af2SRyan Stone 
442*bdc48af2SRyan Stone static int
443*bdc48af2SRyan Stone pci_iov_validate_subsystem_schema(const nvlist_t *dev_schema, const char *name)
444*bdc48af2SRyan Stone {
445*bdc48af2SRyan Stone 	const nvlist_t *sub_schema, *param_schema;
446*bdc48af2SRyan Stone 	const char *param_name;
447*bdc48af2SRyan Stone 	void *it;
448*bdc48af2SRyan Stone 	int type, error;
449*bdc48af2SRyan Stone 
450*bdc48af2SRyan Stone 	if (!nvlist_exists_nvlist(dev_schema, name))
451*bdc48af2SRyan Stone 		return (EINVAL);
452*bdc48af2SRyan Stone 	sub_schema = nvlist_get_nvlist(dev_schema, name);
453*bdc48af2SRyan Stone 
454*bdc48af2SRyan Stone 	it = NULL;
455*bdc48af2SRyan Stone 	while ((param_name = nvlist_next(sub_schema, &type, &it)) != NULL) {
456*bdc48af2SRyan Stone 		if (type != NV_TYPE_NVLIST)
457*bdc48af2SRyan Stone 			return (EINVAL);
458*bdc48af2SRyan Stone 		param_schema = nvlist_get_nvlist(sub_schema, param_name);
459*bdc48af2SRyan Stone 
460*bdc48af2SRyan Stone 		error = pci_iov_validate_param_schema(param_schema);
461*bdc48af2SRyan Stone 		if (error != 0)
462*bdc48af2SRyan Stone 			return (error);
463*bdc48af2SRyan Stone 	}
464*bdc48af2SRyan Stone 
465*bdc48af2SRyan Stone 	return (0);
466*bdc48af2SRyan Stone }
467*bdc48af2SRyan Stone 
468*bdc48af2SRyan Stone /*
469*bdc48af2SRyan Stone  * Validate that the driver schema does not define any configuration parameters
470*bdc48af2SRyan Stone  * whose names collide with configuration parameters defined in the iov schema.
471*bdc48af2SRyan Stone  */
472*bdc48af2SRyan Stone static int
473*bdc48af2SRyan Stone pci_iov_validate_param_collisions(const nvlist_t *dev_schema)
474*bdc48af2SRyan Stone {
475*bdc48af2SRyan Stone 	const nvlist_t *iov_schema, *driver_schema;
476*bdc48af2SRyan Stone 	const char *name;
477*bdc48af2SRyan Stone 	void *it;
478*bdc48af2SRyan Stone 	int type;
479*bdc48af2SRyan Stone 
480*bdc48af2SRyan Stone 	driver_schema = nvlist_get_nvlist(dev_schema, DRIVER_CONFIG_NAME);
481*bdc48af2SRyan Stone 	iov_schema = nvlist_get_nvlist(dev_schema, IOV_CONFIG_NAME);
482*bdc48af2SRyan Stone 
483*bdc48af2SRyan Stone 	it = NULL;
484*bdc48af2SRyan Stone 	while ((name = nvlist_next(driver_schema, &type, &it)) != NULL) {
485*bdc48af2SRyan Stone 		if (nvlist_exists(iov_schema, name))
486*bdc48af2SRyan Stone 			return (EINVAL);
487*bdc48af2SRyan Stone 	}
488*bdc48af2SRyan Stone 
489*bdc48af2SRyan Stone 	return (0);
490*bdc48af2SRyan Stone }
491*bdc48af2SRyan Stone 
492*bdc48af2SRyan Stone /*
493*bdc48af2SRyan Stone  * Validate that we only have IOV and DRIVER subsystems beneath the given
494*bdc48af2SRyan Stone  * device schema node.
495*bdc48af2SRyan Stone  */
496*bdc48af2SRyan Stone static int
497*bdc48af2SRyan Stone pci_iov_validate_schema_subsystems(const nvlist_t *dev_schema)
498*bdc48af2SRyan Stone {
499*bdc48af2SRyan Stone 	const char *name;
500*bdc48af2SRyan Stone 	void *it;
501*bdc48af2SRyan Stone 	int type;
502*bdc48af2SRyan Stone 
503*bdc48af2SRyan Stone 	it = NULL;
504*bdc48af2SRyan Stone 	while ((name = nvlist_next(dev_schema, &type, &it)) != NULL) {
505*bdc48af2SRyan Stone 		if (strcmp(name, IOV_CONFIG_NAME) != 0 &&
506*bdc48af2SRyan Stone 		    strcmp(name, DRIVER_CONFIG_NAME) != 0)
507*bdc48af2SRyan Stone 			return (EINVAL);
508*bdc48af2SRyan Stone 	}
509*bdc48af2SRyan Stone 
510*bdc48af2SRyan Stone 	return (0);
511*bdc48af2SRyan Stone }
512*bdc48af2SRyan Stone 
513*bdc48af2SRyan Stone static int
514*bdc48af2SRyan Stone pci_iov_validate_device_schema(const nvlist_t *schema, const char *name)
515*bdc48af2SRyan Stone {
516*bdc48af2SRyan Stone 	const nvlist_t *dev_schema;
517*bdc48af2SRyan Stone 	int error;
518*bdc48af2SRyan Stone 
519*bdc48af2SRyan Stone 	if (!nvlist_exists_nvlist(schema, name))
520*bdc48af2SRyan Stone 		return (EINVAL);
521*bdc48af2SRyan Stone 	dev_schema = nvlist_get_nvlist(schema, name);
522*bdc48af2SRyan Stone 
523*bdc48af2SRyan Stone 	error = pci_iov_validate_subsystem_schema(dev_schema, IOV_CONFIG_NAME);
524*bdc48af2SRyan Stone 	if (error != 0)
525*bdc48af2SRyan Stone 		return (error);
526*bdc48af2SRyan Stone 
527*bdc48af2SRyan Stone 	error = pci_iov_validate_subsystem_schema(dev_schema,
528*bdc48af2SRyan Stone 	    DRIVER_CONFIG_NAME);
529*bdc48af2SRyan Stone 	if (error != 0)
530*bdc48af2SRyan Stone 		return (error);
531*bdc48af2SRyan Stone 
532*bdc48af2SRyan Stone 	error = pci_iov_validate_param_collisions(dev_schema);
533*bdc48af2SRyan Stone 	if (error != 0)
534*bdc48af2SRyan Stone 		return (error);
535*bdc48af2SRyan Stone 
536*bdc48af2SRyan Stone 	return (pci_iov_validate_schema_subsystems(dev_schema));
537*bdc48af2SRyan Stone }
538*bdc48af2SRyan Stone 
539*bdc48af2SRyan Stone /* Validate that we only have PF and VF devices beneath the top-level schema. */
540*bdc48af2SRyan Stone static int
541*bdc48af2SRyan Stone pci_iov_validate_schema_devices(const nvlist_t *dev_schema)
542*bdc48af2SRyan Stone {
543*bdc48af2SRyan Stone 	const char *name;
544*bdc48af2SRyan Stone 	void *it;
545*bdc48af2SRyan Stone 	int type;
546*bdc48af2SRyan Stone 
547*bdc48af2SRyan Stone 	it = NULL;
548*bdc48af2SRyan Stone 	while ((name = nvlist_next(dev_schema, &type, &it)) != NULL) {
549*bdc48af2SRyan Stone 		if (strcmp(name, PF_CONFIG_NAME) != 0 &&
550*bdc48af2SRyan Stone 		    strcmp(name, VF_SCHEMA_NAME) != 0)
551*bdc48af2SRyan Stone 			return (EINVAL);
552*bdc48af2SRyan Stone 	}
553*bdc48af2SRyan Stone 
554*bdc48af2SRyan Stone 	return (0);
555*bdc48af2SRyan Stone }
556*bdc48af2SRyan Stone 
557*bdc48af2SRyan Stone int
558*bdc48af2SRyan Stone pci_iov_validate_schema(const nvlist_t *schema)
559*bdc48af2SRyan Stone {
560*bdc48af2SRyan Stone 	int error;
561*bdc48af2SRyan Stone 
562*bdc48af2SRyan Stone 	error = pci_iov_validate_device_schema(schema, PF_CONFIG_NAME);
563*bdc48af2SRyan Stone 	if (error != 0)
564*bdc48af2SRyan Stone 		return (error);
565*bdc48af2SRyan Stone 
566*bdc48af2SRyan Stone 	error = pci_iov_validate_device_schema(schema, VF_SCHEMA_NAME);
567*bdc48af2SRyan Stone 	if (error != 0)
568*bdc48af2SRyan Stone 		return (error);
569*bdc48af2SRyan Stone 
570*bdc48af2SRyan Stone 	return (pci_iov_validate_schema_devices(schema));
571*bdc48af2SRyan Stone }
572*bdc48af2SRyan Stone 
5733c22f215SRyan Stone /*
5743c22f215SRyan Stone  * Validate that all required parameters from the schema are specified in the
5753c22f215SRyan Stone  * config.  If any parameter with a default value is not specified in the
5763c22f215SRyan Stone  * config, add it to config.
5773c22f215SRyan Stone  */
5783c22f215SRyan Stone static int
5793c22f215SRyan Stone pci_iov_schema_validate_required(const nvlist_t *schema, nvlist_t *config)
5803c22f215SRyan Stone {
5813c22f215SRyan Stone 	const nvlist_t *param_schema;
5823c22f215SRyan Stone 	const char *name;
5833c22f215SRyan Stone 	void *cookie;
5843c22f215SRyan Stone 	int type;
5853c22f215SRyan Stone 
5863c22f215SRyan Stone 	cookie = NULL;
5873c22f215SRyan Stone 	while ((name = nvlist_next(schema, &type, &cookie)) != NULL) {
5883c22f215SRyan Stone 		param_schema = nvlist_get_nvlist(schema, name);
5893c22f215SRyan Stone 
5903c22f215SRyan Stone 		if (dnvlist_get_bool(param_schema, "required", 0)) {
5913c22f215SRyan Stone 			if (!nvlist_exists(config, name))
5923c22f215SRyan Stone 				return (EINVAL);
5933c22f215SRyan Stone 		}
5943c22f215SRyan Stone 
5953c22f215SRyan Stone 		if (nvlist_exists(param_schema, "default") &&
5963c22f215SRyan Stone 		    !nvlist_exists(config, name))
5973c22f215SRyan Stone 			pci_iov_config_add_default(param_schema, name, config);
5983c22f215SRyan Stone 	}
5993c22f215SRyan Stone 
6003c22f215SRyan Stone 	return (nvlist_error(config));
6013c22f215SRyan Stone }
6023c22f215SRyan Stone 
6033c22f215SRyan Stone static int
6043c22f215SRyan Stone pci_iov_schema_validate_param(const nvlist_t *schema_param, const char *name,
6053c22f215SRyan Stone     const nvlist_t *config)
6063c22f215SRyan Stone {
6073c22f215SRyan Stone 	const struct config_type_validator *validator;
6083c22f215SRyan Stone 	const char *type;
6093c22f215SRyan Stone 
6103c22f215SRyan Stone 	type = nvlist_get_string(schema_param, "type");
6113c22f215SRyan Stone 	validator = pci_iov_schema_find_validator(type);
6123c22f215SRyan Stone 
6133c22f215SRyan Stone 	KASSERT(validator != NULL,
6143c22f215SRyan Stone 	    ("Schema was not validated: Unknown type %s", type));
6153c22f215SRyan Stone 
6163c22f215SRyan Stone 	return (validator->validate(validator, config, name));
6173c22f215SRyan Stone }
6183c22f215SRyan Stone 
6193c22f215SRyan Stone /*
6203c22f215SRyan Stone  * Validate that all parameters in config are defined in the schema.  Also
6213c22f215SRyan Stone  * validate that the type of the parameter matches the type in the schema.
6223c22f215SRyan Stone  */
6233c22f215SRyan Stone static int
6243c22f215SRyan Stone pci_iov_schema_validate_types(const nvlist_t *schema, const nvlist_t *config)
6253c22f215SRyan Stone {
6263c22f215SRyan Stone 	const nvlist_t *schema_param;
6273c22f215SRyan Stone 	void *cookie;
6283c22f215SRyan Stone 	const char *name;
6293c22f215SRyan Stone 	int type, error;
6303c22f215SRyan Stone 
6313c22f215SRyan Stone 	cookie = NULL;
6323c22f215SRyan Stone 	while ((name = nvlist_next(config, &type, &cookie)) != NULL) {
6333c22f215SRyan Stone 		if (!nvlist_exists_nvlist(schema, name))
6343c22f215SRyan Stone 			return (EINVAL);
6353c22f215SRyan Stone 
6363c22f215SRyan Stone 		schema_param = nvlist_get_nvlist(schema, name);
6373c22f215SRyan Stone 
6383c22f215SRyan Stone 		error = pci_iov_schema_validate_param(schema_param, name,
6393c22f215SRyan Stone 		    config);
6403c22f215SRyan Stone 
6413c22f215SRyan Stone 		if (error != 0)
6423c22f215SRyan Stone 			return (error);
6433c22f215SRyan Stone 	}
6443c22f215SRyan Stone 
6453c22f215SRyan Stone 	return (0);
6463c22f215SRyan Stone }
6473c22f215SRyan Stone 
6483c22f215SRyan Stone static int
6493c22f215SRyan Stone pci_iov_schema_validate_device(const nvlist_t *schema, nvlist_t *config,
6503c22f215SRyan Stone     const char *schema_device, const char *config_device)
6513c22f215SRyan Stone {
6523c22f215SRyan Stone 	const nvlist_t *device_schema, *iov_schema, *driver_schema;
6533c22f215SRyan Stone 	nvlist_t *device_config, *iov_config, *driver_config;
6543c22f215SRyan Stone 	int error;
6553c22f215SRyan Stone 
6563c22f215SRyan Stone 	device_config = NULL;
6573c22f215SRyan Stone 	iov_config = NULL;
6583c22f215SRyan Stone 	driver_config = NULL;
6593c22f215SRyan Stone 
6603c22f215SRyan Stone 	device_schema = nvlist_get_nvlist(schema, schema_device);
6613c22f215SRyan Stone 	iov_schema = nvlist_get_nvlist(device_schema, IOV_CONFIG_NAME);
6623c22f215SRyan Stone 	driver_schema = nvlist_get_nvlist(device_schema, DRIVER_CONFIG_NAME);
6633c22f215SRyan Stone 
6643c22f215SRyan Stone 	device_config = dnvlist_take_nvlist(config, config_device, NULL);
6653c22f215SRyan Stone 	if (device_config == NULL) {
6663c22f215SRyan Stone 		error = EINVAL;
6673c22f215SRyan Stone 		goto out;
6683c22f215SRyan Stone 	}
6693c22f215SRyan Stone 
6703c22f215SRyan Stone 	iov_config = dnvlist_take_nvlist(device_config, IOV_CONFIG_NAME, NULL);
6713c22f215SRyan Stone 	if (iov_config == NULL) {
6723c22f215SRyan Stone 		error = EINVAL;
6733c22f215SRyan Stone 		goto out;
6743c22f215SRyan Stone 	}
6753c22f215SRyan Stone 
6763c22f215SRyan Stone 	driver_config = dnvlist_take_nvlist(device_config, DRIVER_CONFIG_NAME,
6773c22f215SRyan Stone 	    NULL);
6783c22f215SRyan Stone 	if (driver_config == NULL) {
6793c22f215SRyan Stone 		error = EINVAL;
6803c22f215SRyan Stone 		goto out;
6813c22f215SRyan Stone 	}
6823c22f215SRyan Stone 
6833c22f215SRyan Stone 	error = pci_iov_schema_validate_required(iov_schema, iov_config);
6843c22f215SRyan Stone 	if (error != 0)
6853c22f215SRyan Stone 		goto out;
6863c22f215SRyan Stone 
6873c22f215SRyan Stone 	error = pci_iov_schema_validate_required(driver_schema, driver_config);
6883c22f215SRyan Stone 	if (error != 0)
6893c22f215SRyan Stone 		goto out;
6903c22f215SRyan Stone 
6913c22f215SRyan Stone 	error = pci_iov_schema_validate_types(iov_schema, iov_config);
6923c22f215SRyan Stone 	if (error != 0)
6933c22f215SRyan Stone 		goto out;
6943c22f215SRyan Stone 
6953c22f215SRyan Stone 	error = pci_iov_schema_validate_types(driver_schema, driver_config);
6963c22f215SRyan Stone 	if (error != 0)
6973c22f215SRyan Stone 		goto out;
6983c22f215SRyan Stone 
6993c22f215SRyan Stone out:
7003c22f215SRyan Stone 	/* Note that these functions handle NULL pointers safely. */
7013c22f215SRyan Stone 	nvlist_move_nvlist(device_config, IOV_CONFIG_NAME, iov_config);
7023c22f215SRyan Stone 	nvlist_move_nvlist(device_config, DRIVER_CONFIG_NAME, driver_config);
7033c22f215SRyan Stone 	nvlist_move_nvlist(config, config_device, device_config);
7043c22f215SRyan Stone 
7053c22f215SRyan Stone 	return (error);
7063c22f215SRyan Stone }
7073c22f215SRyan Stone 
7083c22f215SRyan Stone static int
7093c22f215SRyan Stone pci_iov_schema_validate_vfs(const nvlist_t *schema, nvlist_t *config,
7103c22f215SRyan Stone     uint16_t num_vfs)
7113c22f215SRyan Stone {
7123c22f215SRyan Stone 	char device[VF_MAX_NAME];
7133c22f215SRyan Stone 	int i, error;
7143c22f215SRyan Stone 
7153c22f215SRyan Stone 	for (i = 0; i < num_vfs; i++) {
7163c22f215SRyan Stone 		snprintf(device, sizeof(device), VF_PREFIX"%d", i);
7173c22f215SRyan Stone 
7183c22f215SRyan Stone 		error = pci_iov_schema_validate_device(schema, config,
7193c22f215SRyan Stone 		    VF_SCHEMA_NAME, device);
7203c22f215SRyan Stone 		if (error != 0)
7213c22f215SRyan Stone 			return (error);
7223c22f215SRyan Stone 	}
7233c22f215SRyan Stone 
7243c22f215SRyan Stone 	return (0);
7253c22f215SRyan Stone }
7263c22f215SRyan Stone 
7273c22f215SRyan Stone /*
7283c22f215SRyan Stone  * Validate that the device node only has IOV and DRIVER subnodes.
7293c22f215SRyan Stone  */
7303c22f215SRyan Stone static int
7313c22f215SRyan Stone pci_iov_schema_validate_device_subsystems(const nvlist_t *config)
7323c22f215SRyan Stone {
7333c22f215SRyan Stone 	void *cookie;
7343c22f215SRyan Stone 	const char *name;
7353c22f215SRyan Stone 	int type;
7363c22f215SRyan Stone 
7373c22f215SRyan Stone 	cookie = NULL;
7383c22f215SRyan Stone 	while ((name = nvlist_next(config, &type, &cookie)) != NULL) {
7393c22f215SRyan Stone 		if (strcasecmp(name, IOV_CONFIG_NAME) == 0)
7403c22f215SRyan Stone 			continue;
7413c22f215SRyan Stone 		else if (strcasecmp(name, DRIVER_CONFIG_NAME) == 0)
7423c22f215SRyan Stone 			continue;
7433c22f215SRyan Stone 
7443c22f215SRyan Stone 		return (EINVAL);
7453c22f215SRyan Stone 	}
7463c22f215SRyan Stone 
7473c22f215SRyan Stone 	return (0);
7483c22f215SRyan Stone }
7493c22f215SRyan Stone 
7503c22f215SRyan Stone /*
7513c22f215SRyan Stone  * Validate that the string is a valid device node name.  It must either be "PF"
7523c22f215SRyan Stone  * or "VF-n", where n is an integer in the range [0, num_vfs).
7533c22f215SRyan Stone  */
7543c22f215SRyan Stone static int
7553c22f215SRyan Stone pci_iov_schema_validate_dev_name(const char *name, uint16_t num_vfs)
7563c22f215SRyan Stone {
7573c22f215SRyan Stone 	const char *number_start;
7583c22f215SRyan Stone 	char *endp;
7593c22f215SRyan Stone 	u_long vf_num;
7603c22f215SRyan Stone 
7613c22f215SRyan Stone 	if (strcasecmp(PF_CONFIG_NAME, name) == 0)
7623c22f215SRyan Stone 		return (0);
7633c22f215SRyan Stone 
7643c22f215SRyan Stone 	/* Ensure that we start with "VF-" */
7653c22f215SRyan Stone 	if (strncasecmp(name, VF_PREFIX, VF_PREFIX_LEN) != 0)
7663c22f215SRyan Stone 		return (EINVAL);
7673c22f215SRyan Stone 
7683c22f215SRyan Stone 	number_start = name + VF_PREFIX_LEN;
7693c22f215SRyan Stone 
7703c22f215SRyan Stone 	/* Filter out name == "VF-" (no number) */
7713c22f215SRyan Stone 	if (number_start[0] == '\0')
7723c22f215SRyan Stone 		return (EINVAL);
7733c22f215SRyan Stone 
7743c22f215SRyan Stone 	/* Disallow leading whitespace or +/- */
7753c22f215SRyan Stone 	if (!isdigit(number_start[0]))
7763c22f215SRyan Stone 		return (EINVAL);
7773c22f215SRyan Stone 
7783c22f215SRyan Stone 	vf_num = strtoul(number_start, &endp, 10);
7793c22f215SRyan Stone 	if (*endp != '\0')
7803c22f215SRyan Stone 		return (EINVAL);
7813c22f215SRyan Stone 
7823c22f215SRyan Stone 	/* Disallow leading zeros on VF-[1-9][0-9]* */
7833c22f215SRyan Stone 	if (vf_num != 0 && number_start[0] == '0')
7843c22f215SRyan Stone 		return (EINVAL);
7853c22f215SRyan Stone 
7863c22f215SRyan Stone 	/* Disallow leading zeros on VF-0 */
7873c22f215SRyan Stone 	if (vf_num == 0 && number_start[1] != '\0')
7883c22f215SRyan Stone 		return (EINVAL);
7893c22f215SRyan Stone 
7903c22f215SRyan Stone 	if (vf_num >= num_vfs)
7913c22f215SRyan Stone 		return (EINVAL);
7923c22f215SRyan Stone 
7933c22f215SRyan Stone 	return (0);
7943c22f215SRyan Stone }
7953c22f215SRyan Stone 
7963c22f215SRyan Stone /*
7973c22f215SRyan Stone  * Validate that there are no device nodes in config other than the ones for
7983c22f215SRyan Stone  * the PF and the VFs.  This includes validating that all config nodes of the
7993c22f215SRyan Stone  * form VF-n specify a VF number that is < num_vfs.
8003c22f215SRyan Stone  */
8013c22f215SRyan Stone static int
8023c22f215SRyan Stone pci_iov_schema_validate_device_names(const nvlist_t *config, uint16_t num_vfs)
8033c22f215SRyan Stone {
8043c22f215SRyan Stone 	const nvlist_t *device;
8053c22f215SRyan Stone 	void *cookie;
8063c22f215SRyan Stone 	const char *name;
8073c22f215SRyan Stone 	int type, error;
8083c22f215SRyan Stone 
8093c22f215SRyan Stone 	cookie = NULL;
8103c22f215SRyan Stone 	while ((name = nvlist_next(config, &type, &cookie)) != NULL) {
8113c22f215SRyan Stone 		error = pci_iov_schema_validate_dev_name(name, num_vfs);
8123c22f215SRyan Stone 		if (error != 0)
8133c22f215SRyan Stone 			return (error);
8143c22f215SRyan Stone 
8153c22f215SRyan Stone 		/*
8163c22f215SRyan Stone 		 * Note that as this is a valid PF/VF node, we know that
8173c22f215SRyan Stone 		 * pci_iov_schema_validate_device() has already checked that
8183c22f215SRyan Stone 		 * the PF/VF node is an nvlist.
8193c22f215SRyan Stone 		 */
8203c22f215SRyan Stone 		device = nvlist_get_nvlist(config, name);
8213c22f215SRyan Stone 		error = pci_iov_schema_validate_device_subsystems(device);
8223c22f215SRyan Stone 		if (error != 0)
8233c22f215SRyan Stone 			return (error);
8243c22f215SRyan Stone 	}
8253c22f215SRyan Stone 
8263c22f215SRyan Stone 	return (0);
8273c22f215SRyan Stone }
8283c22f215SRyan Stone 
8293c22f215SRyan Stone int
8303c22f215SRyan Stone pci_iov_schema_validate_config(const nvlist_t *schema, nvlist_t *config)
8313c22f215SRyan Stone {
8323c22f215SRyan Stone 	int error;
8333c22f215SRyan Stone 	uint16_t num_vfs;
8343c22f215SRyan Stone 
8353c22f215SRyan Stone 	error = pci_iov_schema_validate_device(schema, config, PF_CONFIG_NAME,
8363c22f215SRyan Stone 	    PF_CONFIG_NAME);
8373c22f215SRyan Stone 	if (error != 0)
8383c22f215SRyan Stone 		return (error);
8393c22f215SRyan Stone 
8403c22f215SRyan Stone 	num_vfs = pci_iov_config_get_num_vfs(config);
8413c22f215SRyan Stone 
8423c22f215SRyan Stone 	error = pci_iov_schema_validate_vfs(schema, config, num_vfs);
8433c22f215SRyan Stone 	if (error != 0)
8443c22f215SRyan Stone 		return (error);
8453c22f215SRyan Stone 
8463c22f215SRyan Stone 	return (pci_iov_schema_validate_device_names(config, num_vfs));
8473c22f215SRyan Stone }
8483c22f215SRyan Stone 
8493c22f215SRyan Stone /*
8503c22f215SRyan Stone  * Return value of the num_vfs parameter.  config must have already been
8513c22f215SRyan Stone  * validated, which guarantees that the parameter exists.
8523c22f215SRyan Stone  */
8533c22f215SRyan Stone uint16_t
8543c22f215SRyan Stone pci_iov_config_get_num_vfs(const nvlist_t *config)
8553c22f215SRyan Stone {
8563c22f215SRyan Stone 	const nvlist_t *pf, *iov;
8573c22f215SRyan Stone 
8583c22f215SRyan Stone 	pf = nvlist_get_nvlist(config, PF_CONFIG_NAME);
8593c22f215SRyan Stone 	iov = nvlist_get_nvlist(pf, IOV_CONFIG_NAME);
8603c22f215SRyan Stone 	return (nvlist_get_number(iov, "num_vfs"));
8613c22f215SRyan Stone }
8623c22f215SRyan Stone 
8631191f715SRyan Stone /* Allocate a new empty schema node. */
8641191f715SRyan Stone nvlist_t *
8651191f715SRyan Stone pci_iov_schema_alloc_node(void)
8661191f715SRyan Stone {
8671191f715SRyan Stone 
8681191f715SRyan Stone 	return (nvlist_create(NV_FLAG_IGNORE_CASE));
8691191f715SRyan Stone }
870