11191f715SRyan Stone /*-
2faf139ccSRyan Stone * Copyright (c) 2014-2015 Sandvine Inc.
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/param.h>
281191f715SRyan Stone #include <sys/conf.h>
293c22f215SRyan Stone #include <sys/ctype.h>
301191f715SRyan Stone #include <sys/kernel.h>
311191f715SRyan Stone #include <sys/systm.h>
323c22f215SRyan Stone #include <sys/iov.h>
331191f715SRyan Stone #include <sys/malloc.h>
341191f715SRyan Stone #include <sys/module.h>
351191f715SRyan Stone #include <sys/queue.h>
361191f715SRyan Stone
371191f715SRyan Stone #include <machine/stdarg.h>
381191f715SRyan Stone
393c22f215SRyan Stone #include <sys/dnv.h>
401191f715SRyan Stone #include <sys/nv.h>
411191f715SRyan Stone #include <sys/iov_schema.h>
421191f715SRyan Stone
433c22f215SRyan Stone #include <net/ethernet.h>
443c22f215SRyan Stone
451191f715SRyan Stone #include <dev/pci/schema_private.h>
461191f715SRyan Stone
473c22f215SRyan Stone struct config_type_validator;
483c22f215SRyan Stone typedef int (validate_func)(const struct config_type_validator *,
493c22f215SRyan Stone const nvlist_t *, const char *name);
50bdc48af2SRyan Stone typedef int (default_validate_t)(const struct config_type_validator *,
51bdc48af2SRyan Stone const nvlist_t *);
523c22f215SRyan Stone
533c22f215SRyan Stone static validate_func pci_iov_schema_validate_bool;
543c22f215SRyan Stone static validate_func pci_iov_schema_validate_string;
553c22f215SRyan Stone static validate_func pci_iov_schema_validate_uint;
563c22f215SRyan Stone static validate_func pci_iov_schema_validate_unicast_mac;
57*c57c2617SKristof Provost static validate_func pci_iov_schema_validate_vlan;
583c22f215SRyan Stone
59bdc48af2SRyan Stone static default_validate_t pci_iov_validate_bool_default;
60bdc48af2SRyan Stone static default_validate_t pci_iov_validate_string_default;
61bdc48af2SRyan Stone static default_validate_t pci_iov_validate_uint_default;
62bdc48af2SRyan Stone static default_validate_t pci_iov_validate_unicast_mac_default;
63*c57c2617SKristof Provost static default_validate_t pci_iov_validate_vlan_default;
64bdc48af2SRyan Stone
653c22f215SRyan Stone struct config_type_validator {
663c22f215SRyan Stone const char *type_name;
673c22f215SRyan Stone validate_func *validate;
68bdc48af2SRyan Stone default_validate_t *default_validate;
693c22f215SRyan Stone uintmax_t limit;
701191f715SRyan Stone };
711191f715SRyan Stone
723c22f215SRyan Stone static struct config_type_validator pci_iov_schema_validators[] = {
73bdc48af2SRyan Stone {
74bdc48af2SRyan Stone .type_name = "bool",
75bdc48af2SRyan Stone .validate = pci_iov_schema_validate_bool,
76bdc48af2SRyan Stone .default_validate = pci_iov_validate_bool_default
77bdc48af2SRyan Stone },
78bdc48af2SRyan Stone {
79bdc48af2SRyan Stone .type_name = "string",
80bdc48af2SRyan Stone .validate = pci_iov_schema_validate_string,
81bdc48af2SRyan Stone .default_validate = pci_iov_validate_string_default
82bdc48af2SRyan Stone },
83bdc48af2SRyan Stone {
84bdc48af2SRyan Stone .type_name = "uint8_t",
85bdc48af2SRyan Stone .validate = pci_iov_schema_validate_uint,
86bdc48af2SRyan Stone .default_validate = pci_iov_validate_uint_default,
87bdc48af2SRyan Stone .limit = UINT8_MAX
88bdc48af2SRyan Stone },
89bdc48af2SRyan Stone {
90bdc48af2SRyan Stone .type_name = "uint16_t",
91bdc48af2SRyan Stone .validate = pci_iov_schema_validate_uint,
92bdc48af2SRyan Stone .default_validate = pci_iov_validate_uint_default,
93bdc48af2SRyan Stone .limit = UINT16_MAX
94bdc48af2SRyan Stone },
95bdc48af2SRyan Stone {
96bdc48af2SRyan Stone .type_name = "uint32_t",
97bdc48af2SRyan Stone .validate = pci_iov_schema_validate_uint,
98bdc48af2SRyan Stone .default_validate = pci_iov_validate_uint_default,
99bdc48af2SRyan Stone .limit = UINT32_MAX
100bdc48af2SRyan Stone },
101bdc48af2SRyan Stone {
102bdc48af2SRyan Stone .type_name = "uint64_t",
103bdc48af2SRyan Stone .validate = pci_iov_schema_validate_uint,
104bdc48af2SRyan Stone .default_validate = pci_iov_validate_uint_default,
105bdc48af2SRyan Stone .limit = UINT64_MAX
106bdc48af2SRyan Stone },
107bdc48af2SRyan Stone {
108bdc48af2SRyan Stone .type_name = "unicast-mac",
109bdc48af2SRyan Stone .validate = pci_iov_schema_validate_unicast_mac,
110bdc48af2SRyan Stone .default_validate = pci_iov_validate_unicast_mac_default,
111bdc48af2SRyan Stone },
112*c57c2617SKristof Provost {
113*c57c2617SKristof Provost .type_name = "vlan",
114*c57c2617SKristof Provost .validate = pci_iov_schema_validate_vlan,
115*c57c2617SKristof Provost .default_validate = pci_iov_validate_vlan_default,
116*c57c2617SKristof Provost },
1173c22f215SRyan Stone };
1183c22f215SRyan Stone
1193c22f215SRyan Stone static const struct config_type_validator *
pci_iov_schema_find_validator(const char * type)1203c22f215SRyan Stone pci_iov_schema_find_validator(const char *type)
1213c22f215SRyan Stone {
1223c22f215SRyan Stone struct config_type_validator *validator;
1233c22f215SRyan Stone int i;
1243c22f215SRyan Stone
1253c22f215SRyan Stone for (i = 0; i < nitems(pci_iov_schema_validators); i++) {
1263c22f215SRyan Stone validator = &pci_iov_schema_validators[i];
1273c22f215SRyan Stone if (strcmp(type, validator->type_name) == 0)
1283c22f215SRyan Stone return (validator);
1293c22f215SRyan Stone }
1303c22f215SRyan Stone
1313c22f215SRyan Stone return (NULL);
1323c22f215SRyan Stone }
1333c22f215SRyan Stone
1341191f715SRyan Stone static void
pci_iov_schema_add_type(nvlist_t * entry,const char * type)1351191f715SRyan Stone pci_iov_schema_add_type(nvlist_t *entry, const char *type)
1361191f715SRyan Stone {
1371191f715SRyan Stone
1383c22f215SRyan Stone if (pci_iov_schema_find_validator(type) == NULL) {
1393c22f215SRyan Stone nvlist_set_error(entry, EINVAL);
1401191f715SRyan Stone return;
1411191f715SRyan Stone }
1421191f715SRyan Stone nvlist_add_string(entry, "type", type);
1431191f715SRyan Stone }
1441191f715SRyan Stone
1451191f715SRyan Stone static void
pci_iov_schema_add_required(nvlist_t * entry,uint32_t flags)1461191f715SRyan Stone pci_iov_schema_add_required(nvlist_t *entry, uint32_t flags)
1471191f715SRyan Stone {
1481191f715SRyan Stone
1491191f715SRyan Stone if (flags & IOV_SCHEMA_REQUIRED) {
1501191f715SRyan Stone if (flags & IOV_SCHEMA_HASDEFAULT) {
1511191f715SRyan Stone nvlist_set_error(entry, EINVAL);
1521191f715SRyan Stone return;
1531191f715SRyan Stone }
1541191f715SRyan Stone
1551191f715SRyan Stone nvlist_add_bool(entry, "required", 1);
1561191f715SRyan Stone }
1571191f715SRyan Stone }
1581191f715SRyan Stone
1591191f715SRyan Stone void
pci_iov_schema_add_bool(nvlist_t * schema,const char * name,uint32_t flags,int defaultVal)1601191f715SRyan Stone pci_iov_schema_add_bool(nvlist_t *schema, const char *name, uint32_t flags,
1611191f715SRyan Stone int defaultVal)
1621191f715SRyan Stone {
1631191f715SRyan Stone nvlist_t *entry;
1641191f715SRyan Stone
1651191f715SRyan Stone entry = nvlist_create(NV_FLAG_IGNORE_CASE);
1661191f715SRyan Stone if (entry == NULL) {
1671191f715SRyan Stone nvlist_set_error(schema, ENOMEM);
1681191f715SRyan Stone return;
1691191f715SRyan Stone }
1701191f715SRyan Stone
1711191f715SRyan Stone pci_iov_schema_add_type(entry, "bool");
1721191f715SRyan Stone if (flags & IOV_SCHEMA_HASDEFAULT)
1731191f715SRyan Stone nvlist_add_bool(entry, "default", defaultVal);
1741191f715SRyan Stone pci_iov_schema_add_required(entry, flags);
1751191f715SRyan Stone
1761191f715SRyan Stone nvlist_move_nvlist(schema, name, entry);
1771191f715SRyan Stone }
1781191f715SRyan Stone
1791191f715SRyan Stone void
pci_iov_schema_add_string(nvlist_t * schema,const char * name,uint32_t flags,const char * defaultVal)1801191f715SRyan Stone pci_iov_schema_add_string(nvlist_t *schema, const char *name, uint32_t flags,
1811191f715SRyan Stone const char *defaultVal)
1821191f715SRyan Stone {
1831191f715SRyan Stone nvlist_t *entry;
1841191f715SRyan Stone
1851191f715SRyan Stone entry = nvlist_create(NV_FLAG_IGNORE_CASE);
1861191f715SRyan Stone if (entry == NULL) {
1871191f715SRyan Stone nvlist_set_error(schema, ENOMEM);
1881191f715SRyan Stone return;
1891191f715SRyan Stone }
1901191f715SRyan Stone
1911191f715SRyan Stone pci_iov_schema_add_type(entry, "string");
1921191f715SRyan Stone if (flags & IOV_SCHEMA_HASDEFAULT)
1931191f715SRyan Stone nvlist_add_string(entry, "default", defaultVal);
1941191f715SRyan Stone pci_iov_schema_add_required(entry, flags);
1951191f715SRyan Stone
1961191f715SRyan Stone nvlist_move_nvlist(schema, name, entry);
1971191f715SRyan Stone }
1981191f715SRyan Stone
1991191f715SRyan Stone static void
pci_iov_schema_int(nvlist_t * schema,const char * name,const char * type,uint32_t flags,uint64_t defaultVal)2001191f715SRyan Stone pci_iov_schema_int(nvlist_t *schema, const char *name, const char *type,
2011191f715SRyan Stone uint32_t flags, uint64_t defaultVal)
2021191f715SRyan Stone {
2031191f715SRyan Stone nvlist_t *entry;
2041191f715SRyan Stone
2051191f715SRyan Stone entry = nvlist_create(NV_FLAG_IGNORE_CASE);
2061191f715SRyan Stone if (entry == NULL) {
2071191f715SRyan Stone nvlist_set_error(schema, ENOMEM);
2081191f715SRyan Stone return;
2091191f715SRyan Stone }
2101191f715SRyan Stone
2111191f715SRyan Stone pci_iov_schema_add_type(entry, type);
2121191f715SRyan Stone if (flags & IOV_SCHEMA_HASDEFAULT)
2131191f715SRyan Stone nvlist_add_number(entry, "default", defaultVal);
2141191f715SRyan Stone pci_iov_schema_add_required(entry, flags);
2151191f715SRyan Stone
2161191f715SRyan Stone nvlist_move_nvlist(schema, name, entry);
2171191f715SRyan Stone }
2181191f715SRyan Stone
2191191f715SRyan Stone void
pci_iov_schema_add_uint8(nvlist_t * schema,const char * name,uint32_t flags,uint8_t defaultVal)2201191f715SRyan Stone pci_iov_schema_add_uint8(nvlist_t *schema, const char *name, uint32_t flags,
2211191f715SRyan Stone uint8_t defaultVal)
2221191f715SRyan Stone {
2231191f715SRyan Stone
2241191f715SRyan Stone pci_iov_schema_int(schema, name, "uint8_t", flags, defaultVal);
2251191f715SRyan Stone }
2261191f715SRyan Stone
2271191f715SRyan Stone void
pci_iov_schema_add_uint16(nvlist_t * schema,const char * name,uint32_t flags,uint16_t defaultVal)2281191f715SRyan Stone pci_iov_schema_add_uint16(nvlist_t *schema, const char *name, uint32_t flags,
2291191f715SRyan Stone uint16_t defaultVal)
2301191f715SRyan Stone {
2311191f715SRyan Stone
2321191f715SRyan Stone pci_iov_schema_int(schema, name, "uint16_t", flags, defaultVal);
2331191f715SRyan Stone }
2341191f715SRyan Stone
2351191f715SRyan Stone void
pci_iov_schema_add_uint32(nvlist_t * schema,const char * name,uint32_t flags,uint32_t defaultVal)2361191f715SRyan Stone pci_iov_schema_add_uint32(nvlist_t *schema, const char *name, uint32_t flags,
2371191f715SRyan Stone uint32_t defaultVal)
2381191f715SRyan Stone {
2391191f715SRyan Stone
2401191f715SRyan Stone pci_iov_schema_int(schema, name, "uint32_t", flags, defaultVal);
2411191f715SRyan Stone }
2421191f715SRyan Stone
2431191f715SRyan Stone void
pci_iov_schema_add_uint64(nvlist_t * schema,const char * name,uint32_t flags,uint64_t defaultVal)2441191f715SRyan Stone pci_iov_schema_add_uint64(nvlist_t *schema, const char *name, uint32_t flags,
2451191f715SRyan Stone uint64_t defaultVal)
2461191f715SRyan Stone {
2471191f715SRyan Stone
2481191f715SRyan Stone pci_iov_schema_int(schema, name, "uint64_t", flags, defaultVal);
2491191f715SRyan Stone }
2501191f715SRyan Stone
2511191f715SRyan Stone void
pci_iov_schema_add_unicast_mac(nvlist_t * schema,const char * name,uint32_t flags,const uint8_t * defaultVal)2521191f715SRyan Stone pci_iov_schema_add_unicast_mac(nvlist_t *schema, const char *name,
2531191f715SRyan Stone uint32_t flags, const uint8_t * defaultVal)
2541191f715SRyan Stone {
2551191f715SRyan Stone nvlist_t *entry;
2561191f715SRyan Stone
2571191f715SRyan Stone entry = nvlist_create(NV_FLAG_IGNORE_CASE);
2581191f715SRyan Stone if (entry == NULL) {
2591191f715SRyan Stone nvlist_set_error(schema, ENOMEM);
2601191f715SRyan Stone return;
2611191f715SRyan Stone }
2621191f715SRyan Stone
2631191f715SRyan Stone pci_iov_schema_add_type(entry, "unicast-mac");
2641191f715SRyan Stone if (flags & IOV_SCHEMA_HASDEFAULT)
2651191f715SRyan Stone nvlist_add_binary(entry, "default", defaultVal, ETHER_ADDR_LEN);
2661191f715SRyan Stone pci_iov_schema_add_required(entry, flags);
2671191f715SRyan Stone
2681191f715SRyan Stone nvlist_move_nvlist(schema, name, entry);
2691191f715SRyan Stone }
2701191f715SRyan Stone
271*c57c2617SKristof Provost void
pci_iov_schema_add_vlan(nvlist_t * schema,const char * name,uint32_t flags,const uint16_t defaultVal)272*c57c2617SKristof Provost pci_iov_schema_add_vlan(nvlist_t *schema, const char *name,
273*c57c2617SKristof Provost uint32_t flags, const uint16_t defaultVal)
274*c57c2617SKristof Provost {
275*c57c2617SKristof Provost nvlist_t *entry;
276*c57c2617SKristof Provost
277*c57c2617SKristof Provost entry = nvlist_create(NV_FLAG_IGNORE_CASE);
278*c57c2617SKristof Provost if (entry == NULL) {
279*c57c2617SKristof Provost nvlist_set_error(schema, ENOMEM);
280*c57c2617SKristof Provost return;
281*c57c2617SKristof Provost }
282*c57c2617SKristof Provost
283*c57c2617SKristof Provost pci_iov_schema_add_type(entry, "vlan");
284*c57c2617SKristof Provost if (flags & IOV_SCHEMA_HASDEFAULT)
285*c57c2617SKristof Provost nvlist_add_number(entry, "default", defaultVal);
286*c57c2617SKristof Provost pci_iov_schema_add_required(entry, flags);
287*c57c2617SKristof Provost
288*c57c2617SKristof Provost nvlist_move_nvlist(schema, name, entry);
289*c57c2617SKristof Provost }
290*c57c2617SKristof Provost
2913c22f215SRyan Stone static int
pci_iov_schema_validate_bool(const struct config_type_validator * validator,const nvlist_t * config,const char * name)2923c22f215SRyan Stone pci_iov_schema_validate_bool(const struct config_type_validator * validator,
2933c22f215SRyan Stone const nvlist_t *config, const char *name)
2943c22f215SRyan Stone {
2953c22f215SRyan Stone
2963c22f215SRyan Stone if (!nvlist_exists_bool(config, name))
2973c22f215SRyan Stone return (EINVAL);
2983c22f215SRyan Stone return (0);
2993c22f215SRyan Stone }
3003c22f215SRyan Stone
3013c22f215SRyan Stone static int
pci_iov_schema_validate_string(const struct config_type_validator * validator,const nvlist_t * config,const char * name)3023c22f215SRyan Stone pci_iov_schema_validate_string(const struct config_type_validator * validator,
3033c22f215SRyan Stone const nvlist_t *config, const char *name)
3043c22f215SRyan Stone {
3053c22f215SRyan Stone
3063c22f215SRyan Stone if (!nvlist_exists_string(config, name))
3073c22f215SRyan Stone return (EINVAL);
3083c22f215SRyan Stone return (0);
3093c22f215SRyan Stone }
3103c22f215SRyan Stone
3113c22f215SRyan Stone static int
pci_iov_schema_validate_uint(const struct config_type_validator * validator,const nvlist_t * config,const char * name)3123c22f215SRyan Stone pci_iov_schema_validate_uint(const struct config_type_validator * validator,
3133c22f215SRyan Stone const nvlist_t *config, const char *name)
3143c22f215SRyan Stone {
3153c22f215SRyan Stone uint64_t value;
3163c22f215SRyan Stone
3173c22f215SRyan Stone if (!nvlist_exists_number(config, name))
3183c22f215SRyan Stone return (EINVAL);
3193c22f215SRyan Stone
3203c22f215SRyan Stone value = nvlist_get_number(config, name);
3213c22f215SRyan Stone
3223c22f215SRyan Stone if (value > validator->limit)
3233c22f215SRyan Stone return (EINVAL);
3243c22f215SRyan Stone
3253c22f215SRyan Stone return (0);
3263c22f215SRyan Stone }
3273c22f215SRyan Stone
3283c22f215SRyan Stone static int
pci_iov_schema_validate_unicast_mac(const struct config_type_validator * validator,const nvlist_t * config,const char * name)3293c22f215SRyan Stone pci_iov_schema_validate_unicast_mac(
3303c22f215SRyan Stone const struct config_type_validator * validator,
3313c22f215SRyan Stone const nvlist_t *config, const char *name)
3323c22f215SRyan Stone {
3333c22f215SRyan Stone const uint8_t *mac;
3343c22f215SRyan Stone size_t size;
3353c22f215SRyan Stone
3363c22f215SRyan Stone if (!nvlist_exists_binary(config, name))
3373c22f215SRyan Stone return (EINVAL);
3383c22f215SRyan Stone
3393c22f215SRyan Stone mac = nvlist_get_binary(config, name, &size);
3403c22f215SRyan Stone
3413c22f215SRyan Stone if (size != ETHER_ADDR_LEN)
3423c22f215SRyan Stone return (EINVAL);
3433c22f215SRyan Stone
3443c22f215SRyan Stone if (ETHER_IS_MULTICAST(mac))
3453c22f215SRyan Stone return (EINVAL);
3463c22f215SRyan Stone
3473c22f215SRyan Stone return (0);
3483c22f215SRyan Stone }
3493c22f215SRyan Stone
350*c57c2617SKristof Provost static int
pci_iov_schema_validate_vlan(const struct config_type_validator * validator,const nvlist_t * config,const char * name)351*c57c2617SKristof Provost pci_iov_schema_validate_vlan(
352*c57c2617SKristof Provost const struct config_type_validator * validator,
353*c57c2617SKristof Provost const nvlist_t *config, const char *name)
354*c57c2617SKristof Provost {
355*c57c2617SKristof Provost uint16_t vlan;
356*c57c2617SKristof Provost
357*c57c2617SKristof Provost if (!nvlist_exists_number(config, name))
358*c57c2617SKristof Provost return (EINVAL);
359*c57c2617SKristof Provost
360*c57c2617SKristof Provost vlan = nvlist_get_number(config, name);
361*c57c2617SKristof Provost
362*c57c2617SKristof Provost if (vlan > 4095 && vlan != VF_VLAN_TRUNK)
363*c57c2617SKristof Provost return (EINVAL);
364*c57c2617SKristof Provost
365*c57c2617SKristof Provost return (0);
366*c57c2617SKristof Provost }
367*c57c2617SKristof Provost
3683c22f215SRyan Stone static void
pci_iov_config_add_default(const nvlist_t * param_schema,const char * name,nvlist_t * config)3693c22f215SRyan Stone pci_iov_config_add_default(const nvlist_t *param_schema, const char *name,
3703c22f215SRyan Stone nvlist_t *config)
3713c22f215SRyan Stone {
3723c22f215SRyan Stone const void *binary;
3733c22f215SRyan Stone size_t len;
3743c22f215SRyan Stone
3753c22f215SRyan Stone if (nvlist_exists_binary(param_schema, "default")) {
3763c22f215SRyan Stone binary = nvlist_get_binary(param_schema, "default", &len);
3773c22f215SRyan Stone nvlist_add_binary(config, name, binary, len);
3783c22f215SRyan Stone } else if (nvlist_exists_bool(param_schema, "default"))
3793c22f215SRyan Stone nvlist_add_bool(config, name,
3803c22f215SRyan Stone nvlist_get_bool(param_schema, "default"));
3813c22f215SRyan Stone else if (nvlist_exists_number(param_schema, "default"))
3823c22f215SRyan Stone nvlist_add_number(config, name,
3833c22f215SRyan Stone nvlist_get_number(param_schema, "default"));
3843c22f215SRyan Stone else if (nvlist_exists_nvlist(param_schema, "default"))
3853c22f215SRyan Stone nvlist_add_nvlist(config, name,
3863c22f215SRyan Stone nvlist_get_nvlist(param_schema, "default"));
3873c22f215SRyan Stone else if (nvlist_exists_string(param_schema, "default"))
3883c22f215SRyan Stone nvlist_add_string(config, name,
3893c22f215SRyan Stone nvlist_get_string(param_schema, "default"));
3903c22f215SRyan Stone else
3913c22f215SRyan Stone panic("Unexpected nvlist type");
3923c22f215SRyan Stone }
3933c22f215SRyan Stone
394bdc48af2SRyan Stone static int
pci_iov_validate_bool_default(const struct config_type_validator * validator,const nvlist_t * param)395bdc48af2SRyan Stone pci_iov_validate_bool_default(const struct config_type_validator * validator,
396bdc48af2SRyan Stone const nvlist_t *param)
397bdc48af2SRyan Stone {
398bdc48af2SRyan Stone
399bdc48af2SRyan Stone if (!nvlist_exists_bool(param, DEFAULT_SCHEMA_NAME))
400bdc48af2SRyan Stone return (EINVAL);
401bdc48af2SRyan Stone return (0);
402bdc48af2SRyan Stone }
403bdc48af2SRyan Stone
404bdc48af2SRyan Stone static int
pci_iov_validate_string_default(const struct config_type_validator * validator,const nvlist_t * param)405bdc48af2SRyan Stone pci_iov_validate_string_default(const struct config_type_validator * validator,
406bdc48af2SRyan Stone const nvlist_t *param)
407bdc48af2SRyan Stone {
408bdc48af2SRyan Stone
409bdc48af2SRyan Stone if (!nvlist_exists_string(param, DEFAULT_SCHEMA_NAME))
410bdc48af2SRyan Stone return (EINVAL);
411bdc48af2SRyan Stone return (0);
412bdc48af2SRyan Stone }
413bdc48af2SRyan Stone
414bdc48af2SRyan Stone static int
pci_iov_validate_uint_default(const struct config_type_validator * validator,const nvlist_t * param)415bdc48af2SRyan Stone pci_iov_validate_uint_default(const struct config_type_validator * validator,
416bdc48af2SRyan Stone const nvlist_t *param)
417bdc48af2SRyan Stone {
418bdc48af2SRyan Stone uint64_t defaultVal;
419bdc48af2SRyan Stone
420bdc48af2SRyan Stone if (!nvlist_exists_number(param, DEFAULT_SCHEMA_NAME))
421bdc48af2SRyan Stone return (EINVAL);
422bdc48af2SRyan Stone
423bdc48af2SRyan Stone defaultVal = nvlist_get_number(param, DEFAULT_SCHEMA_NAME);
424bdc48af2SRyan Stone if (defaultVal > validator->limit)
425bdc48af2SRyan Stone return (EINVAL);
426bdc48af2SRyan Stone return (0);
427bdc48af2SRyan Stone }
428bdc48af2SRyan Stone
429bdc48af2SRyan Stone static int
pci_iov_validate_unicast_mac_default(const struct config_type_validator * validator,const nvlist_t * param)430bdc48af2SRyan Stone pci_iov_validate_unicast_mac_default(
431bdc48af2SRyan Stone const struct config_type_validator * validator, const nvlist_t *param)
432bdc48af2SRyan Stone {
433bdc48af2SRyan Stone const uint8_t *mac;
434bdc48af2SRyan Stone size_t size;
435bdc48af2SRyan Stone
436bdc48af2SRyan Stone if (!nvlist_exists_binary(param, DEFAULT_SCHEMA_NAME))
437bdc48af2SRyan Stone return (EINVAL);
438bdc48af2SRyan Stone
439bdc48af2SRyan Stone mac = nvlist_get_binary(param, DEFAULT_SCHEMA_NAME, &size);
440bdc48af2SRyan Stone if (size != ETHER_ADDR_LEN)
441bdc48af2SRyan Stone return (EINVAL);
442bdc48af2SRyan Stone
443bdc48af2SRyan Stone if (ETHER_IS_MULTICAST(mac))
444bdc48af2SRyan Stone return (EINVAL);
445bdc48af2SRyan Stone return (0);
446bdc48af2SRyan Stone }
447bdc48af2SRyan Stone
448bdc48af2SRyan Stone static int
pci_iov_validate_vlan_default(const struct config_type_validator * validator,const nvlist_t * param)449*c57c2617SKristof Provost pci_iov_validate_vlan_default(
450*c57c2617SKristof Provost const struct config_type_validator * validator, const nvlist_t *param)
451*c57c2617SKristof Provost {
452*c57c2617SKristof Provost uint16_t vlan;
453*c57c2617SKristof Provost
454*c57c2617SKristof Provost if (! nvlist_exists_number(param, DEFAULT_SCHEMA_NAME))
455*c57c2617SKristof Provost return (EINVAL);
456*c57c2617SKristof Provost
457*c57c2617SKristof Provost vlan = nvlist_get_number(param, DEFAULT_SCHEMA_NAME);
458*c57c2617SKristof Provost if (vlan > 4095 && vlan != VF_VLAN_TRUNK)
459*c57c2617SKristof Provost return (EINVAL);
460*c57c2617SKristof Provost
461*c57c2617SKristof Provost return (0);
462*c57c2617SKristof Provost }
463*c57c2617SKristof Provost
464*c57c2617SKristof Provost static int
pci_iov_validate_param_schema(const nvlist_t * schema)465bdc48af2SRyan Stone pci_iov_validate_param_schema(const nvlist_t *schema)
466bdc48af2SRyan Stone {
467bdc48af2SRyan Stone const struct config_type_validator *validator;
468bdc48af2SRyan Stone const char *type;
469bdc48af2SRyan Stone int error;
470bdc48af2SRyan Stone
471bdc48af2SRyan Stone /* All parameters must define a type. */
472bdc48af2SRyan Stone if (!nvlist_exists_string(schema, TYPE_SCHEMA_NAME))
473bdc48af2SRyan Stone return (EINVAL);
474bdc48af2SRyan Stone type = nvlist_get_string(schema, TYPE_SCHEMA_NAME);
475bdc48af2SRyan Stone
476bdc48af2SRyan Stone validator = pci_iov_schema_find_validator(type);
477bdc48af2SRyan Stone if (validator == NULL)
478bdc48af2SRyan Stone return (EINVAL);
479bdc48af2SRyan Stone
480bdc48af2SRyan Stone /* Validate that the default value conforms to the type. */
481bdc48af2SRyan Stone if (nvlist_exists(schema, DEFAULT_SCHEMA_NAME)) {
482bdc48af2SRyan Stone error = validator->default_validate(validator, schema);
483bdc48af2SRyan Stone if (error != 0)
484bdc48af2SRyan Stone return (error);
485bdc48af2SRyan Stone
486bdc48af2SRyan Stone /* Required and Default are mutually exclusive. */
487bdc48af2SRyan Stone if (nvlist_exists(schema, REQUIRED_SCHEMA_NAME))
488bdc48af2SRyan Stone return (EINVAL);
489bdc48af2SRyan Stone }
490bdc48af2SRyan Stone
491bdc48af2SRyan Stone /* The "Required" field must be a bool. */
492bdc48af2SRyan Stone if (nvlist_exists(schema, REQUIRED_SCHEMA_NAME)) {
493bdc48af2SRyan Stone if (!nvlist_exists_bool(schema, REQUIRED_SCHEMA_NAME))
494bdc48af2SRyan Stone return (EINVAL);
495bdc48af2SRyan Stone }
496bdc48af2SRyan Stone
497bdc48af2SRyan Stone return (0);
498bdc48af2SRyan Stone }
499bdc48af2SRyan Stone
500bdc48af2SRyan Stone static int
pci_iov_validate_subsystem_schema(const nvlist_t * dev_schema,const char * name)501bdc48af2SRyan Stone pci_iov_validate_subsystem_schema(const nvlist_t *dev_schema, const char *name)
502bdc48af2SRyan Stone {
503bdc48af2SRyan Stone const nvlist_t *sub_schema, *param_schema;
504bdc48af2SRyan Stone const char *param_name;
505bdc48af2SRyan Stone void *it;
506bdc48af2SRyan Stone int type, error;
507bdc48af2SRyan Stone
508bdc48af2SRyan Stone if (!nvlist_exists_nvlist(dev_schema, name))
509bdc48af2SRyan Stone return (EINVAL);
510bdc48af2SRyan Stone sub_schema = nvlist_get_nvlist(dev_schema, name);
511bdc48af2SRyan Stone
512bdc48af2SRyan Stone it = NULL;
513bdc48af2SRyan Stone while ((param_name = nvlist_next(sub_schema, &type, &it)) != NULL) {
514bdc48af2SRyan Stone if (type != NV_TYPE_NVLIST)
515bdc48af2SRyan Stone return (EINVAL);
516bdc48af2SRyan Stone param_schema = nvlist_get_nvlist(sub_schema, param_name);
517bdc48af2SRyan Stone
518bdc48af2SRyan Stone error = pci_iov_validate_param_schema(param_schema);
519bdc48af2SRyan Stone if (error != 0)
520bdc48af2SRyan Stone return (error);
521bdc48af2SRyan Stone }
522bdc48af2SRyan Stone
523bdc48af2SRyan Stone return (0);
524bdc48af2SRyan Stone }
525bdc48af2SRyan Stone
526bdc48af2SRyan Stone /*
527bdc48af2SRyan Stone * Validate that the driver schema does not define any configuration parameters
528bdc48af2SRyan Stone * whose names collide with configuration parameters defined in the iov schema.
529bdc48af2SRyan Stone */
530bdc48af2SRyan Stone static int
pci_iov_validate_param_collisions(const nvlist_t * dev_schema)531bdc48af2SRyan Stone pci_iov_validate_param_collisions(const nvlist_t *dev_schema)
532bdc48af2SRyan Stone {
533bdc48af2SRyan Stone const nvlist_t *iov_schema, *driver_schema;
534bdc48af2SRyan Stone const char *name;
535bdc48af2SRyan Stone void *it;
536bdc48af2SRyan Stone int type;
537bdc48af2SRyan Stone
538bdc48af2SRyan Stone driver_schema = nvlist_get_nvlist(dev_schema, DRIVER_CONFIG_NAME);
539bdc48af2SRyan Stone iov_schema = nvlist_get_nvlist(dev_schema, IOV_CONFIG_NAME);
540bdc48af2SRyan Stone
541bdc48af2SRyan Stone it = NULL;
542bdc48af2SRyan Stone while ((name = nvlist_next(driver_schema, &type, &it)) != NULL) {
543bdc48af2SRyan Stone if (nvlist_exists(iov_schema, name))
544bdc48af2SRyan Stone return (EINVAL);
545bdc48af2SRyan Stone }
546bdc48af2SRyan Stone
547bdc48af2SRyan Stone return (0);
548bdc48af2SRyan Stone }
549bdc48af2SRyan Stone
550bdc48af2SRyan Stone /*
551bdc48af2SRyan Stone * Validate that we only have IOV and DRIVER subsystems beneath the given
552bdc48af2SRyan Stone * device schema node.
553bdc48af2SRyan Stone */
554bdc48af2SRyan Stone static int
pci_iov_validate_schema_subsystems(const nvlist_t * dev_schema)555bdc48af2SRyan Stone pci_iov_validate_schema_subsystems(const nvlist_t *dev_schema)
556bdc48af2SRyan Stone {
557bdc48af2SRyan Stone const char *name;
558bdc48af2SRyan Stone void *it;
559bdc48af2SRyan Stone int type;
560bdc48af2SRyan Stone
561bdc48af2SRyan Stone it = NULL;
562bdc48af2SRyan Stone while ((name = nvlist_next(dev_schema, &type, &it)) != NULL) {
563bdc48af2SRyan Stone if (strcmp(name, IOV_CONFIG_NAME) != 0 &&
564bdc48af2SRyan Stone strcmp(name, DRIVER_CONFIG_NAME) != 0)
565bdc48af2SRyan Stone return (EINVAL);
566bdc48af2SRyan Stone }
567bdc48af2SRyan Stone
568bdc48af2SRyan Stone return (0);
569bdc48af2SRyan Stone }
570bdc48af2SRyan Stone
571bdc48af2SRyan Stone static int
pci_iov_validate_device_schema(const nvlist_t * schema,const char * name)572bdc48af2SRyan Stone pci_iov_validate_device_schema(const nvlist_t *schema, const char *name)
573bdc48af2SRyan Stone {
574bdc48af2SRyan Stone const nvlist_t *dev_schema;
575bdc48af2SRyan Stone int error;
576bdc48af2SRyan Stone
577bdc48af2SRyan Stone if (!nvlist_exists_nvlist(schema, name))
578bdc48af2SRyan Stone return (EINVAL);
579bdc48af2SRyan Stone dev_schema = nvlist_get_nvlist(schema, name);
580bdc48af2SRyan Stone
581bdc48af2SRyan Stone error = pci_iov_validate_subsystem_schema(dev_schema, IOV_CONFIG_NAME);
582bdc48af2SRyan Stone if (error != 0)
583bdc48af2SRyan Stone return (error);
584bdc48af2SRyan Stone
585bdc48af2SRyan Stone error = pci_iov_validate_subsystem_schema(dev_schema,
586bdc48af2SRyan Stone DRIVER_CONFIG_NAME);
587bdc48af2SRyan Stone if (error != 0)
588bdc48af2SRyan Stone return (error);
589bdc48af2SRyan Stone
590bdc48af2SRyan Stone error = pci_iov_validate_param_collisions(dev_schema);
591bdc48af2SRyan Stone if (error != 0)
592bdc48af2SRyan Stone return (error);
593bdc48af2SRyan Stone
594bdc48af2SRyan Stone return (pci_iov_validate_schema_subsystems(dev_schema));
595bdc48af2SRyan Stone }
596bdc48af2SRyan Stone
597bdc48af2SRyan Stone /* Validate that we only have PF and VF devices beneath the top-level schema. */
598bdc48af2SRyan Stone static int
pci_iov_validate_schema_devices(const nvlist_t * dev_schema)599bdc48af2SRyan Stone pci_iov_validate_schema_devices(const nvlist_t *dev_schema)
600bdc48af2SRyan Stone {
601bdc48af2SRyan Stone const char *name;
602bdc48af2SRyan Stone void *it;
603bdc48af2SRyan Stone int type;
604bdc48af2SRyan Stone
605bdc48af2SRyan Stone it = NULL;
606bdc48af2SRyan Stone while ((name = nvlist_next(dev_schema, &type, &it)) != NULL) {
607bdc48af2SRyan Stone if (strcmp(name, PF_CONFIG_NAME) != 0 &&
608bdc48af2SRyan Stone strcmp(name, VF_SCHEMA_NAME) != 0)
609bdc48af2SRyan Stone return (EINVAL);
610bdc48af2SRyan Stone }
611bdc48af2SRyan Stone
612bdc48af2SRyan Stone return (0);
613bdc48af2SRyan Stone }
614bdc48af2SRyan Stone
615bdc48af2SRyan Stone int
pci_iov_validate_schema(const nvlist_t * schema)616bdc48af2SRyan Stone pci_iov_validate_schema(const nvlist_t *schema)
617bdc48af2SRyan Stone {
618bdc48af2SRyan Stone int error;
619bdc48af2SRyan Stone
620bdc48af2SRyan Stone error = pci_iov_validate_device_schema(schema, PF_CONFIG_NAME);
621bdc48af2SRyan Stone if (error != 0)
622bdc48af2SRyan Stone return (error);
623bdc48af2SRyan Stone
624bdc48af2SRyan Stone error = pci_iov_validate_device_schema(schema, VF_SCHEMA_NAME);
625bdc48af2SRyan Stone if (error != 0)
626bdc48af2SRyan Stone return (error);
627bdc48af2SRyan Stone
628bdc48af2SRyan Stone return (pci_iov_validate_schema_devices(schema));
629bdc48af2SRyan Stone }
630bdc48af2SRyan Stone
6313c22f215SRyan Stone /*
6323c22f215SRyan Stone * Validate that all required parameters from the schema are specified in the
6333c22f215SRyan Stone * config. If any parameter with a default value is not specified in the
6343c22f215SRyan Stone * config, add it to config.
6353c22f215SRyan Stone */
6363c22f215SRyan Stone static int
pci_iov_schema_validate_required(const nvlist_t * schema,nvlist_t * config)6373c22f215SRyan Stone pci_iov_schema_validate_required(const nvlist_t *schema, nvlist_t *config)
6383c22f215SRyan Stone {
6393c22f215SRyan Stone const nvlist_t *param_schema;
6403c22f215SRyan Stone const char *name;
6413c22f215SRyan Stone void *cookie;
6423c22f215SRyan Stone int type;
6433c22f215SRyan Stone
6443c22f215SRyan Stone cookie = NULL;
6453c22f215SRyan Stone while ((name = nvlist_next(schema, &type, &cookie)) != NULL) {
6463c22f215SRyan Stone param_schema = nvlist_get_nvlist(schema, name);
6473c22f215SRyan Stone
6483c22f215SRyan Stone if (dnvlist_get_bool(param_schema, "required", 0)) {
6493c22f215SRyan Stone if (!nvlist_exists(config, name))
6503c22f215SRyan Stone return (EINVAL);
6513c22f215SRyan Stone }
6523c22f215SRyan Stone
6533c22f215SRyan Stone if (nvlist_exists(param_schema, "default") &&
6543c22f215SRyan Stone !nvlist_exists(config, name))
6553c22f215SRyan Stone pci_iov_config_add_default(param_schema, name, config);
6563c22f215SRyan Stone }
6573c22f215SRyan Stone
6583c22f215SRyan Stone return (nvlist_error(config));
6593c22f215SRyan Stone }
6603c22f215SRyan Stone
6613c22f215SRyan Stone static int
pci_iov_schema_validate_param(const nvlist_t * schema_param,const char * name,const nvlist_t * config)6623c22f215SRyan Stone pci_iov_schema_validate_param(const nvlist_t *schema_param, const char *name,
6633c22f215SRyan Stone const nvlist_t *config)
6643c22f215SRyan Stone {
6653c22f215SRyan Stone const struct config_type_validator *validator;
6663c22f215SRyan Stone const char *type;
6673c22f215SRyan Stone
6683c22f215SRyan Stone type = nvlist_get_string(schema_param, "type");
6693c22f215SRyan Stone validator = pci_iov_schema_find_validator(type);
6703c22f215SRyan Stone
6713c22f215SRyan Stone KASSERT(validator != NULL,
6723c22f215SRyan Stone ("Schema was not validated: Unknown type %s", type));
6733c22f215SRyan Stone
6743c22f215SRyan Stone return (validator->validate(validator, config, name));
6753c22f215SRyan Stone }
6763c22f215SRyan Stone
6773c22f215SRyan Stone /*
6783c22f215SRyan Stone * Validate that all parameters in config are defined in the schema. Also
6793c22f215SRyan Stone * validate that the type of the parameter matches the type in the schema.
6803c22f215SRyan Stone */
6813c22f215SRyan Stone static int
pci_iov_schema_validate_types(const nvlist_t * schema,const nvlist_t * config)6823c22f215SRyan Stone pci_iov_schema_validate_types(const nvlist_t *schema, const nvlist_t *config)
6833c22f215SRyan Stone {
6843c22f215SRyan Stone const nvlist_t *schema_param;
6853c22f215SRyan Stone void *cookie;
6863c22f215SRyan Stone const char *name;
6873c22f215SRyan Stone int type, error;
6883c22f215SRyan Stone
6893c22f215SRyan Stone cookie = NULL;
6903c22f215SRyan Stone while ((name = nvlist_next(config, &type, &cookie)) != NULL) {
6913c22f215SRyan Stone if (!nvlist_exists_nvlist(schema, name))
6923c22f215SRyan Stone return (EINVAL);
6933c22f215SRyan Stone
6943c22f215SRyan Stone schema_param = nvlist_get_nvlist(schema, name);
6953c22f215SRyan Stone
6963c22f215SRyan Stone error = pci_iov_schema_validate_param(schema_param, name,
6973c22f215SRyan Stone config);
6983c22f215SRyan Stone
6993c22f215SRyan Stone if (error != 0)
7003c22f215SRyan Stone return (error);
7013c22f215SRyan Stone }
7023c22f215SRyan Stone
7033c22f215SRyan Stone return (0);
7043c22f215SRyan Stone }
7053c22f215SRyan Stone
7063c22f215SRyan Stone static int
pci_iov_schema_validate_device(const nvlist_t * schema,nvlist_t * config,const char * schema_device,const char * config_device)7073c22f215SRyan Stone pci_iov_schema_validate_device(const nvlist_t *schema, nvlist_t *config,
7083c22f215SRyan Stone const char *schema_device, const char *config_device)
7093c22f215SRyan Stone {
7103c22f215SRyan Stone const nvlist_t *device_schema, *iov_schema, *driver_schema;
7113c22f215SRyan Stone nvlist_t *device_config, *iov_config, *driver_config;
7123c22f215SRyan Stone int error;
7133c22f215SRyan Stone
7143c22f215SRyan Stone device_config = NULL;
7153c22f215SRyan Stone iov_config = NULL;
7163c22f215SRyan Stone driver_config = NULL;
7173c22f215SRyan Stone
7183c22f215SRyan Stone device_schema = nvlist_get_nvlist(schema, schema_device);
7193c22f215SRyan Stone iov_schema = nvlist_get_nvlist(device_schema, IOV_CONFIG_NAME);
7203c22f215SRyan Stone driver_schema = nvlist_get_nvlist(device_schema, DRIVER_CONFIG_NAME);
7213c22f215SRyan Stone
7223c22f215SRyan Stone device_config = dnvlist_take_nvlist(config, config_device, NULL);
7233c22f215SRyan Stone if (device_config == NULL) {
7243c22f215SRyan Stone error = EINVAL;
7253c22f215SRyan Stone goto out;
7263c22f215SRyan Stone }
7273c22f215SRyan Stone
7283c22f215SRyan Stone iov_config = dnvlist_take_nvlist(device_config, IOV_CONFIG_NAME, NULL);
7293c22f215SRyan Stone if (iov_config == NULL) {
7303c22f215SRyan Stone error = EINVAL;
7313c22f215SRyan Stone goto out;
7323c22f215SRyan Stone }
7333c22f215SRyan Stone
7343c22f215SRyan Stone driver_config = dnvlist_take_nvlist(device_config, DRIVER_CONFIG_NAME,
7353c22f215SRyan Stone NULL);
7363c22f215SRyan Stone if (driver_config == NULL) {
7373c22f215SRyan Stone error = EINVAL;
7383c22f215SRyan Stone goto out;
7393c22f215SRyan Stone }
7403c22f215SRyan Stone
7413c22f215SRyan Stone error = pci_iov_schema_validate_required(iov_schema, iov_config);
7423c22f215SRyan Stone if (error != 0)
7433c22f215SRyan Stone goto out;
7443c22f215SRyan Stone
7453c22f215SRyan Stone error = pci_iov_schema_validate_required(driver_schema, driver_config);
7463c22f215SRyan Stone if (error != 0)
7473c22f215SRyan Stone goto out;
7483c22f215SRyan Stone
7493c22f215SRyan Stone error = pci_iov_schema_validate_types(iov_schema, iov_config);
7503c22f215SRyan Stone if (error != 0)
7513c22f215SRyan Stone goto out;
7523c22f215SRyan Stone
7533c22f215SRyan Stone error = pci_iov_schema_validate_types(driver_schema, driver_config);
7543c22f215SRyan Stone if (error != 0)
7553c22f215SRyan Stone goto out;
7563c22f215SRyan Stone
7573c22f215SRyan Stone out:
7583c22f215SRyan Stone /* Note that these functions handle NULL pointers safely. */
7593c22f215SRyan Stone nvlist_move_nvlist(device_config, IOV_CONFIG_NAME, iov_config);
7603c22f215SRyan Stone nvlist_move_nvlist(device_config, DRIVER_CONFIG_NAME, driver_config);
7613c22f215SRyan Stone nvlist_move_nvlist(config, config_device, device_config);
7623c22f215SRyan Stone
7633c22f215SRyan Stone return (error);
7643c22f215SRyan Stone }
7653c22f215SRyan Stone
7663c22f215SRyan Stone static int
pci_iov_schema_validate_vfs(const nvlist_t * schema,nvlist_t * config,uint16_t num_vfs)7673c22f215SRyan Stone pci_iov_schema_validate_vfs(const nvlist_t *schema, nvlist_t *config,
7683c22f215SRyan Stone uint16_t num_vfs)
7693c22f215SRyan Stone {
7703c22f215SRyan Stone char device[VF_MAX_NAME];
7713c22f215SRyan Stone int i, error;
7723c22f215SRyan Stone
7733c22f215SRyan Stone for (i = 0; i < num_vfs; i++) {
7743c22f215SRyan Stone snprintf(device, sizeof(device), VF_PREFIX"%d", i);
7753c22f215SRyan Stone
7763c22f215SRyan Stone error = pci_iov_schema_validate_device(schema, config,
7773c22f215SRyan Stone VF_SCHEMA_NAME, device);
7783c22f215SRyan Stone if (error != 0)
7793c22f215SRyan Stone return (error);
7803c22f215SRyan Stone }
7813c22f215SRyan Stone
7823c22f215SRyan Stone return (0);
7833c22f215SRyan Stone }
7843c22f215SRyan Stone
7853c22f215SRyan Stone /*
7863c22f215SRyan Stone * Validate that the device node only has IOV and DRIVER subnodes.
7873c22f215SRyan Stone */
7883c22f215SRyan Stone static int
pci_iov_schema_validate_device_subsystems(const nvlist_t * config)7893c22f215SRyan Stone pci_iov_schema_validate_device_subsystems(const nvlist_t *config)
7903c22f215SRyan Stone {
7913c22f215SRyan Stone void *cookie;
7923c22f215SRyan Stone const char *name;
7933c22f215SRyan Stone int type;
7943c22f215SRyan Stone
7953c22f215SRyan Stone cookie = NULL;
7963c22f215SRyan Stone while ((name = nvlist_next(config, &type, &cookie)) != NULL) {
7973c22f215SRyan Stone if (strcasecmp(name, IOV_CONFIG_NAME) == 0)
7983c22f215SRyan Stone continue;
7993c22f215SRyan Stone else if (strcasecmp(name, DRIVER_CONFIG_NAME) == 0)
8003c22f215SRyan Stone continue;
8013c22f215SRyan Stone
8023c22f215SRyan Stone return (EINVAL);
8033c22f215SRyan Stone }
8043c22f215SRyan Stone
8053c22f215SRyan Stone return (0);
8063c22f215SRyan Stone }
8073c22f215SRyan Stone
8083c22f215SRyan Stone /*
8093c22f215SRyan Stone * Validate that the string is a valid device node name. It must either be "PF"
8103c22f215SRyan Stone * or "VF-n", where n is an integer in the range [0, num_vfs).
8113c22f215SRyan Stone */
8123c22f215SRyan Stone static int
pci_iov_schema_validate_dev_name(const char * name,uint16_t num_vfs)8133c22f215SRyan Stone pci_iov_schema_validate_dev_name(const char *name, uint16_t num_vfs)
8143c22f215SRyan Stone {
8153c22f215SRyan Stone const char *number_start;
8163c22f215SRyan Stone char *endp;
8173c22f215SRyan Stone u_long vf_num;
8183c22f215SRyan Stone
8193c22f215SRyan Stone if (strcasecmp(PF_CONFIG_NAME, name) == 0)
8203c22f215SRyan Stone return (0);
8213c22f215SRyan Stone
8223c22f215SRyan Stone /* Ensure that we start with "VF-" */
8233c22f215SRyan Stone if (strncasecmp(name, VF_PREFIX, VF_PREFIX_LEN) != 0)
8243c22f215SRyan Stone return (EINVAL);
8253c22f215SRyan Stone
8263c22f215SRyan Stone number_start = name + VF_PREFIX_LEN;
8273c22f215SRyan Stone
8283c22f215SRyan Stone /* Filter out name == "VF-" (no number) */
8293c22f215SRyan Stone if (number_start[0] == '\0')
8303c22f215SRyan Stone return (EINVAL);
8313c22f215SRyan Stone
8323c22f215SRyan Stone /* Disallow leading whitespace or +/- */
8333c22f215SRyan Stone if (!isdigit(number_start[0]))
8343c22f215SRyan Stone return (EINVAL);
8353c22f215SRyan Stone
8363c22f215SRyan Stone vf_num = strtoul(number_start, &endp, 10);
8373c22f215SRyan Stone if (*endp != '\0')
8383c22f215SRyan Stone return (EINVAL);
8393c22f215SRyan Stone
8403c22f215SRyan Stone /* Disallow leading zeros on VF-[1-9][0-9]* */
8413c22f215SRyan Stone if (vf_num != 0 && number_start[0] == '0')
8423c22f215SRyan Stone return (EINVAL);
8433c22f215SRyan Stone
8443c22f215SRyan Stone /* Disallow leading zeros on VF-0 */
8453c22f215SRyan Stone if (vf_num == 0 && number_start[1] != '\0')
8463c22f215SRyan Stone return (EINVAL);
8473c22f215SRyan Stone
8483c22f215SRyan Stone if (vf_num >= num_vfs)
8493c22f215SRyan Stone return (EINVAL);
8503c22f215SRyan Stone
8513c22f215SRyan Stone return (0);
8523c22f215SRyan Stone }
8533c22f215SRyan Stone
8543c22f215SRyan Stone /*
8553c22f215SRyan Stone * Validate that there are no device nodes in config other than the ones for
8563c22f215SRyan Stone * the PF and the VFs. This includes validating that all config nodes of the
8573c22f215SRyan Stone * form VF-n specify a VF number that is < num_vfs.
8583c22f215SRyan Stone */
8593c22f215SRyan Stone static int
pci_iov_schema_validate_device_names(const nvlist_t * config,uint16_t num_vfs)8603c22f215SRyan Stone pci_iov_schema_validate_device_names(const nvlist_t *config, uint16_t num_vfs)
8613c22f215SRyan Stone {
8623c22f215SRyan Stone const nvlist_t *device;
8633c22f215SRyan Stone void *cookie;
8643c22f215SRyan Stone const char *name;
8653c22f215SRyan Stone int type, error;
8663c22f215SRyan Stone
8673c22f215SRyan Stone cookie = NULL;
8683c22f215SRyan Stone while ((name = nvlist_next(config, &type, &cookie)) != NULL) {
8693c22f215SRyan Stone error = pci_iov_schema_validate_dev_name(name, num_vfs);
8703c22f215SRyan Stone if (error != 0)
8713c22f215SRyan Stone return (error);
8723c22f215SRyan Stone
8733c22f215SRyan Stone /*
8743c22f215SRyan Stone * Note that as this is a valid PF/VF node, we know that
8753c22f215SRyan Stone * pci_iov_schema_validate_device() has already checked that
8763c22f215SRyan Stone * the PF/VF node is an nvlist.
8773c22f215SRyan Stone */
8783c22f215SRyan Stone device = nvlist_get_nvlist(config, name);
8793c22f215SRyan Stone error = pci_iov_schema_validate_device_subsystems(device);
8803c22f215SRyan Stone if (error != 0)
8813c22f215SRyan Stone return (error);
8823c22f215SRyan Stone }
8833c22f215SRyan Stone
8843c22f215SRyan Stone return (0);
8853c22f215SRyan Stone }
8863c22f215SRyan Stone
8873c22f215SRyan Stone int
pci_iov_schema_validate_config(const nvlist_t * schema,nvlist_t * config)8883c22f215SRyan Stone pci_iov_schema_validate_config(const nvlist_t *schema, nvlist_t *config)
8893c22f215SRyan Stone {
8903c22f215SRyan Stone int error;
8913c22f215SRyan Stone uint16_t num_vfs;
8923c22f215SRyan Stone
8933c22f215SRyan Stone error = pci_iov_schema_validate_device(schema, config, PF_CONFIG_NAME,
8943c22f215SRyan Stone PF_CONFIG_NAME);
8953c22f215SRyan Stone if (error != 0)
8963c22f215SRyan Stone return (error);
8973c22f215SRyan Stone
8983c22f215SRyan Stone num_vfs = pci_iov_config_get_num_vfs(config);
8993c22f215SRyan Stone
9003c22f215SRyan Stone error = pci_iov_schema_validate_vfs(schema, config, num_vfs);
9013c22f215SRyan Stone if (error != 0)
9023c22f215SRyan Stone return (error);
9033c22f215SRyan Stone
9043c22f215SRyan Stone return (pci_iov_schema_validate_device_names(config, num_vfs));
9053c22f215SRyan Stone }
9063c22f215SRyan Stone
9073c22f215SRyan Stone /*
9083c22f215SRyan Stone * Return value of the num_vfs parameter. config must have already been
9093c22f215SRyan Stone * validated, which guarantees that the parameter exists.
9103c22f215SRyan Stone */
9113c22f215SRyan Stone uint16_t
pci_iov_config_get_num_vfs(const nvlist_t * config)9123c22f215SRyan Stone pci_iov_config_get_num_vfs(const nvlist_t *config)
9133c22f215SRyan Stone {
9143c22f215SRyan Stone const nvlist_t *pf, *iov;
9153c22f215SRyan Stone
9163c22f215SRyan Stone pf = nvlist_get_nvlist(config, PF_CONFIG_NAME);
9173c22f215SRyan Stone iov = nvlist_get_nvlist(pf, IOV_CONFIG_NAME);
9183c22f215SRyan Stone return (nvlist_get_number(iov, "num_vfs"));
9193c22f215SRyan Stone }
9203c22f215SRyan Stone
9211191f715SRyan Stone /* Allocate a new empty schema node. */
9221191f715SRyan Stone nvlist_t *
pci_iov_schema_alloc_node(void)9231191f715SRyan Stone pci_iov_schema_alloc_node(void)
9241191f715SRyan Stone {
9251191f715SRyan Stone
9261191f715SRyan Stone return (nvlist_create(NV_FLAG_IGNORE_CASE));
9271191f715SRyan Stone }
928