13e5d0784SAlexander V. Chernikov /*-
23e5d0784SAlexander V. Chernikov * SPDX-License-Identifier: BSD-2-Clause
33e5d0784SAlexander V. Chernikov *
43e5d0784SAlexander V. Chernikov * Copyright (c) 2023 Alexander V. Chernikov
53e5d0784SAlexander V. Chernikov *
63e5d0784SAlexander V. Chernikov * Redistribution and use in source and binary forms, with or without
73e5d0784SAlexander V. Chernikov * modification, are permitted provided that the following conditions
83e5d0784SAlexander V. Chernikov * are met:
93e5d0784SAlexander V. Chernikov * 1. Redistributions of source code must retain the above copyright
103e5d0784SAlexander V. Chernikov * notice, this list of conditions and the following disclaimer.
113e5d0784SAlexander V. Chernikov * 2. Redistributions in binary form must reproduce the above copyright
123e5d0784SAlexander V. Chernikov * notice, this list of conditions and the following disclaimer in the
133e5d0784SAlexander V. Chernikov * documentation and/or other materials provided with the distribution.
143e5d0784SAlexander V. Chernikov *
153e5d0784SAlexander V. Chernikov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
163e5d0784SAlexander V. Chernikov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
173e5d0784SAlexander V. Chernikov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
183e5d0784SAlexander V. Chernikov * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
193e5d0784SAlexander V. Chernikov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
203e5d0784SAlexander V. Chernikov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
213e5d0784SAlexander V. Chernikov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
223e5d0784SAlexander V. Chernikov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
233e5d0784SAlexander V. Chernikov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
243e5d0784SAlexander V. Chernikov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
253e5d0784SAlexander V. Chernikov * SUCH DAMAGE.
263e5d0784SAlexander V. Chernikov */
273e5d0784SAlexander V. Chernikov
283e5d0784SAlexander V. Chernikov #include <sys/param.h>
293e5d0784SAlexander V. Chernikov #include <sys/refcount.h>
303e5d0784SAlexander V. Chernikov #include <sys/types.h>
313e5d0784SAlexander V. Chernikov #include <sys/kernel.h>
323e5d0784SAlexander V. Chernikov #include <sys/lock.h>
33f656a960SAlexander V. Chernikov #include <sys/mutex.h>
343e5d0784SAlexander V. Chernikov #include <sys/malloc.h>
353e5d0784SAlexander V. Chernikov #include <sys/module.h>
363e5d0784SAlexander V. Chernikov #include <sys/socket.h>
373e5d0784SAlexander V. Chernikov #include <sys/priv.h>
383e5d0784SAlexander V. Chernikov
393e5d0784SAlexander V. Chernikov #include <netlink/netlink.h>
403e5d0784SAlexander V. Chernikov #include <netlink/netlink_ctl.h>
413e5d0784SAlexander V. Chernikov #include <netlink/netlink_generic.h>
423e5d0784SAlexander V. Chernikov #include <netlink/netlink_message_parser.h>
433e5d0784SAlexander V. Chernikov
443e5d0784SAlexander V. Chernikov #include <machine/stdarg.h>
453e5d0784SAlexander V. Chernikov #include <tests/ktest.h>
463e5d0784SAlexander V. Chernikov
473e5d0784SAlexander V. Chernikov struct mtx ktest_mtx;
483e5d0784SAlexander V. Chernikov #define KTEST_LOCK() mtx_lock(&ktest_mtx)
493e5d0784SAlexander V. Chernikov #define KTEST_UNLOCK() mtx_unlock(&ktest_mtx)
503e5d0784SAlexander V. Chernikov #define KTEST_LOCK_ASSERT() mtx_assert(&ktest_mtx, MA_OWNED)
513e5d0784SAlexander V. Chernikov
523e5d0784SAlexander V. Chernikov MTX_SYSINIT(ktest_mtx, &ktest_mtx, "ktest mutex", MTX_DEF);
533e5d0784SAlexander V. Chernikov
543e5d0784SAlexander V. Chernikov struct ktest_module {
553e5d0784SAlexander V. Chernikov struct ktest_module_info *info;
563e5d0784SAlexander V. Chernikov volatile u_int refcount;
573e5d0784SAlexander V. Chernikov TAILQ_ENTRY(ktest_module) entries;
583e5d0784SAlexander V. Chernikov };
593e5d0784SAlexander V. Chernikov static TAILQ_HEAD(, ktest_module) module_list = TAILQ_HEAD_INITIALIZER(module_list);
603e5d0784SAlexander V. Chernikov
613e5d0784SAlexander V. Chernikov struct nl_ktest_parsed {
623e5d0784SAlexander V. Chernikov char *mod_name;
633e5d0784SAlexander V. Chernikov char *test_name;
643e5d0784SAlexander V. Chernikov struct nlattr *test_meta;
653e5d0784SAlexander V. Chernikov };
663e5d0784SAlexander V. Chernikov
673e5d0784SAlexander V. Chernikov #define _IN(_field) offsetof(struct genlmsghdr, _field)
683e5d0784SAlexander V. Chernikov #define _OUT(_field) offsetof(struct nl_ktest_parsed, _field)
693e5d0784SAlexander V. Chernikov
703e5d0784SAlexander V. Chernikov static const struct nlattr_parser nla_p_get[] = {
713e5d0784SAlexander V. Chernikov { .type = KTEST_ATTR_MOD_NAME, .off = _OUT(mod_name), .cb = nlattr_get_string },
723e5d0784SAlexander V. Chernikov { .type = KTEST_ATTR_TEST_NAME, .off = _OUT(test_name), .cb = nlattr_get_string },
733e5d0784SAlexander V. Chernikov { .type = KTEST_ATTR_TEST_META, .off = _OUT(test_meta), .cb = nlattr_get_nla },
743e5d0784SAlexander V. Chernikov };
753e5d0784SAlexander V. Chernikov static const struct nlfield_parser nlf_p_get[] = {
763e5d0784SAlexander V. Chernikov };
773e5d0784SAlexander V. Chernikov NL_DECLARE_PARSER(ktest_parser, struct genlmsghdr, nlf_p_get, nla_p_get);
783e5d0784SAlexander V. Chernikov #undef _IN
793e5d0784SAlexander V. Chernikov #undef _OUT
803e5d0784SAlexander V. Chernikov
813e5d0784SAlexander V. Chernikov static bool
create_reply(struct nl_writer * nw,struct nlmsghdr * hdr,int cmd)823e5d0784SAlexander V. Chernikov create_reply(struct nl_writer *nw, struct nlmsghdr *hdr, int cmd)
833e5d0784SAlexander V. Chernikov {
843e5d0784SAlexander V. Chernikov if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
853e5d0784SAlexander V. Chernikov return (false);
863e5d0784SAlexander V. Chernikov
873e5d0784SAlexander V. Chernikov struct genlmsghdr *ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
883e5d0784SAlexander V. Chernikov ghdr_new->cmd = cmd;
893e5d0784SAlexander V. Chernikov ghdr_new->version = 0;
903e5d0784SAlexander V. Chernikov ghdr_new->reserved = 0;
913e5d0784SAlexander V. Chernikov
923e5d0784SAlexander V. Chernikov return (true);
933e5d0784SAlexander V. Chernikov }
943e5d0784SAlexander V. Chernikov
953e5d0784SAlexander V. Chernikov static int
dump_mod_test(struct nlmsghdr * hdr,struct nl_pstate * npt,struct ktest_module * mod,const struct ktest_test_info * test_info)963e5d0784SAlexander V. Chernikov dump_mod_test(struct nlmsghdr *hdr, struct nl_pstate *npt,
973e5d0784SAlexander V. Chernikov struct ktest_module *mod, const struct ktest_test_info *test_info)
983e5d0784SAlexander V. Chernikov {
993e5d0784SAlexander V. Chernikov struct nl_writer *nw = npt->nw;
1003e5d0784SAlexander V. Chernikov
1013e5d0784SAlexander V. Chernikov if (!create_reply(nw, hdr, KTEST_CMD_NEWTEST))
1023e5d0784SAlexander V. Chernikov goto enomem;
1033e5d0784SAlexander V. Chernikov
1043e5d0784SAlexander V. Chernikov nlattr_add_string(nw, KTEST_ATTR_MOD_NAME, mod->info->name);
1053e5d0784SAlexander V. Chernikov nlattr_add_string(nw, KTEST_ATTR_TEST_NAME, test_info->name);
1063e5d0784SAlexander V. Chernikov nlattr_add_string(nw, KTEST_ATTR_TEST_DESCR, test_info->desc);
1073e5d0784SAlexander V. Chernikov
1083e5d0784SAlexander V. Chernikov if (nlmsg_end(nw))
1093e5d0784SAlexander V. Chernikov return (0);
1103e5d0784SAlexander V. Chernikov enomem:
1113e5d0784SAlexander V. Chernikov nlmsg_abort(nw);
1123e5d0784SAlexander V. Chernikov return (ENOMEM);
1133e5d0784SAlexander V. Chernikov }
1143e5d0784SAlexander V. Chernikov
1153e5d0784SAlexander V. Chernikov static int
dump_mod_tests(struct nlmsghdr * hdr,struct nl_pstate * npt,struct ktest_module * mod,struct nl_ktest_parsed * attrs)1163e5d0784SAlexander V. Chernikov dump_mod_tests(struct nlmsghdr *hdr, struct nl_pstate *npt,
1173e5d0784SAlexander V. Chernikov struct ktest_module *mod, struct nl_ktest_parsed *attrs)
1183e5d0784SAlexander V. Chernikov {
1193e5d0784SAlexander V. Chernikov for (int i = 0; i < mod->info->num_tests; i++) {
1203e5d0784SAlexander V. Chernikov const struct ktest_test_info *test_info = &mod->info->tests[i];
1213e5d0784SAlexander V. Chernikov if (attrs->test_name != NULL && strcmp(attrs->test_name, test_info->name))
1223e5d0784SAlexander V. Chernikov continue;
1233e5d0784SAlexander V. Chernikov int error = dump_mod_test(hdr, npt, mod, test_info);
1243e5d0784SAlexander V. Chernikov if (error != 0)
1253e5d0784SAlexander V. Chernikov return (error);
1263e5d0784SAlexander V. Chernikov }
1273e5d0784SAlexander V. Chernikov
1283e5d0784SAlexander V. Chernikov return (0);
1293e5d0784SAlexander V. Chernikov }
1303e5d0784SAlexander V. Chernikov
1313e5d0784SAlexander V. Chernikov static int
dump_tests(struct nlmsghdr * hdr,struct nl_pstate * npt)1323e5d0784SAlexander V. Chernikov dump_tests(struct nlmsghdr *hdr, struct nl_pstate *npt)
1333e5d0784SAlexander V. Chernikov {
1343e5d0784SAlexander V. Chernikov struct nl_ktest_parsed attrs = { };
1353e5d0784SAlexander V. Chernikov struct ktest_module *mod;
1363e5d0784SAlexander V. Chernikov int error;
1373e5d0784SAlexander V. Chernikov
1383e5d0784SAlexander V. Chernikov error = nl_parse_nlmsg(hdr, &ktest_parser, npt, &attrs);
1393e5d0784SAlexander V. Chernikov if (error != 0)
1403e5d0784SAlexander V. Chernikov return (error);
1413e5d0784SAlexander V. Chernikov
1423e5d0784SAlexander V. Chernikov hdr->nlmsg_flags |= NLM_F_MULTI;
1433e5d0784SAlexander V. Chernikov
1443e5d0784SAlexander V. Chernikov KTEST_LOCK();
1453e5d0784SAlexander V. Chernikov TAILQ_FOREACH(mod, &module_list, entries) {
1463e5d0784SAlexander V. Chernikov if (attrs.mod_name && strcmp(attrs.mod_name, mod->info->name))
1473e5d0784SAlexander V. Chernikov continue;
1483e5d0784SAlexander V. Chernikov error = dump_mod_tests(hdr, npt, mod, &attrs);
1493e5d0784SAlexander V. Chernikov if (error != 0)
1503e5d0784SAlexander V. Chernikov break;
1513e5d0784SAlexander V. Chernikov }
1523e5d0784SAlexander V. Chernikov KTEST_UNLOCK();
1533e5d0784SAlexander V. Chernikov
1543e5d0784SAlexander V. Chernikov if (!nlmsg_end_dump(npt->nw, error, hdr)) {
1553e5d0784SAlexander V. Chernikov //NL_LOG(LOG_DEBUG, "Unable to finalize the dump");
1563e5d0784SAlexander V. Chernikov return (ENOMEM);
1573e5d0784SAlexander V. Chernikov }
1583e5d0784SAlexander V. Chernikov
1593e5d0784SAlexander V. Chernikov return (error);
1603e5d0784SAlexander V. Chernikov }
1613e5d0784SAlexander V. Chernikov
1623e5d0784SAlexander V. Chernikov static int
run_test(struct nlmsghdr * hdr,struct nl_pstate * npt)1633e5d0784SAlexander V. Chernikov run_test(struct nlmsghdr *hdr, struct nl_pstate *npt)
1643e5d0784SAlexander V. Chernikov {
1653e5d0784SAlexander V. Chernikov struct nl_ktest_parsed attrs = { };
1663e5d0784SAlexander V. Chernikov struct ktest_module *mod;
1673e5d0784SAlexander V. Chernikov int error;
1683e5d0784SAlexander V. Chernikov
1693e5d0784SAlexander V. Chernikov error = nl_parse_nlmsg(hdr, &ktest_parser, npt, &attrs);
1703e5d0784SAlexander V. Chernikov if (error != 0)
1713e5d0784SAlexander V. Chernikov return (error);
1723e5d0784SAlexander V. Chernikov
1733e5d0784SAlexander V. Chernikov if (attrs.mod_name == NULL) {
1743e5d0784SAlexander V. Chernikov nlmsg_report_err_msg(npt, "KTEST_ATTR_MOD_NAME not set");
1753e5d0784SAlexander V. Chernikov return (EINVAL);
1763e5d0784SAlexander V. Chernikov }
1773e5d0784SAlexander V. Chernikov
1783e5d0784SAlexander V. Chernikov if (attrs.test_name == NULL) {
1793e5d0784SAlexander V. Chernikov nlmsg_report_err_msg(npt, "KTEST_ATTR_TEST_NAME not set");
1803e5d0784SAlexander V. Chernikov return (EINVAL);
1813e5d0784SAlexander V. Chernikov }
1823e5d0784SAlexander V. Chernikov
1833e5d0784SAlexander V. Chernikov const struct ktest_test_info *test = NULL;
1843e5d0784SAlexander V. Chernikov
1853e5d0784SAlexander V. Chernikov KTEST_LOCK();
1863e5d0784SAlexander V. Chernikov TAILQ_FOREACH(mod, &module_list, entries) {
1873e5d0784SAlexander V. Chernikov if (strcmp(attrs.mod_name, mod->info->name))
1883e5d0784SAlexander V. Chernikov continue;
1893e5d0784SAlexander V. Chernikov
1903e5d0784SAlexander V. Chernikov const struct ktest_module_info *info = mod->info;
1913e5d0784SAlexander V. Chernikov
1923e5d0784SAlexander V. Chernikov for (int i = 0; i < info->num_tests; i++) {
1933e5d0784SAlexander V. Chernikov const struct ktest_test_info *test_info = &info->tests[i];
1943e5d0784SAlexander V. Chernikov
1953e5d0784SAlexander V. Chernikov if (!strcmp(attrs.test_name, test_info->name)) {
1963e5d0784SAlexander V. Chernikov test = test_info;
1973e5d0784SAlexander V. Chernikov break;
1983e5d0784SAlexander V. Chernikov }
1993e5d0784SAlexander V. Chernikov }
2003e5d0784SAlexander V. Chernikov break;
2013e5d0784SAlexander V. Chernikov }
2023e5d0784SAlexander V. Chernikov if (test != NULL)
2033e5d0784SAlexander V. Chernikov refcount_acquire(&mod->refcount);
2043e5d0784SAlexander V. Chernikov KTEST_UNLOCK();
2053e5d0784SAlexander V. Chernikov
2063e5d0784SAlexander V. Chernikov if (test == NULL)
2073e5d0784SAlexander V. Chernikov return (ESRCH);
2083e5d0784SAlexander V. Chernikov
2093e5d0784SAlexander V. Chernikov /* Run the test */
2103e5d0784SAlexander V. Chernikov struct ktest_test_context ctx = {
2113e5d0784SAlexander V. Chernikov .npt = npt,
2123e5d0784SAlexander V. Chernikov .hdr = hdr,
2133e5d0784SAlexander V. Chernikov .buf = npt_alloc(npt, KTEST_MAX_BUF),
2143e5d0784SAlexander V. Chernikov .bufsize = KTEST_MAX_BUF,
2153e5d0784SAlexander V. Chernikov };
2163e5d0784SAlexander V. Chernikov
2173e5d0784SAlexander V. Chernikov if (ctx.buf == NULL) {
2183e5d0784SAlexander V. Chernikov //NL_LOG(LOG_DEBUG, "unable to allocate temporary buffer");
2193e5d0784SAlexander V. Chernikov return (ENOMEM);
2203e5d0784SAlexander V. Chernikov }
2213e5d0784SAlexander V. Chernikov
2223e5d0784SAlexander V. Chernikov if (test->parse != NULL && attrs.test_meta != NULL) {
2233e5d0784SAlexander V. Chernikov error = test->parse(&ctx, attrs.test_meta);
2243e5d0784SAlexander V. Chernikov if (error != 0)
2253e5d0784SAlexander V. Chernikov return (error);
2263e5d0784SAlexander V. Chernikov }
2273e5d0784SAlexander V. Chernikov
2283e5d0784SAlexander V. Chernikov hdr->nlmsg_flags |= NLM_F_MULTI;
2293e5d0784SAlexander V. Chernikov
2303e5d0784SAlexander V. Chernikov KTEST_LOG_LEVEL(&ctx, LOG_INFO, "start running %s", test->name);
2313e5d0784SAlexander V. Chernikov error = test->func(&ctx);
2323e5d0784SAlexander V. Chernikov KTEST_LOG_LEVEL(&ctx, LOG_INFO, "end running %s", test->name);
2333e5d0784SAlexander V. Chernikov
2343e5d0784SAlexander V. Chernikov refcount_release(&mod->refcount);
2353e5d0784SAlexander V. Chernikov
2363e5d0784SAlexander V. Chernikov if (!nlmsg_end_dump(npt->nw, error, hdr)) {
2373e5d0784SAlexander V. Chernikov //NL_LOG(LOG_DEBUG, "Unable to finalize the dump");
2383e5d0784SAlexander V. Chernikov return (ENOMEM);
2393e5d0784SAlexander V. Chernikov }
2403e5d0784SAlexander V. Chernikov
2413e5d0784SAlexander V. Chernikov return (error);
2423e5d0784SAlexander V. Chernikov }
2433e5d0784SAlexander V. Chernikov
2443e5d0784SAlexander V. Chernikov
2453e5d0784SAlexander V. Chernikov /* USER API */
2463e5d0784SAlexander V. Chernikov static void
register_test_module(struct ktest_module_info * info)2473e5d0784SAlexander V. Chernikov register_test_module(struct ktest_module_info *info)
2483e5d0784SAlexander V. Chernikov {
2493e5d0784SAlexander V. Chernikov struct ktest_module *mod = malloc(sizeof(*mod), M_TEMP, M_WAITOK | M_ZERO);
2503e5d0784SAlexander V. Chernikov
2513e5d0784SAlexander V. Chernikov mod->info = info;
2523e5d0784SAlexander V. Chernikov info->module_ptr = mod;
2533e5d0784SAlexander V. Chernikov KTEST_LOCK();
2543e5d0784SAlexander V. Chernikov TAILQ_INSERT_TAIL(&module_list, mod, entries);
2553e5d0784SAlexander V. Chernikov KTEST_UNLOCK();
2563e5d0784SAlexander V. Chernikov }
2573e5d0784SAlexander V. Chernikov
2583e5d0784SAlexander V. Chernikov static void
unregister_test_module(struct ktest_module_info * info)2593e5d0784SAlexander V. Chernikov unregister_test_module(struct ktest_module_info *info)
2603e5d0784SAlexander V. Chernikov {
2613e5d0784SAlexander V. Chernikov struct ktest_module *mod = info->module_ptr;
2623e5d0784SAlexander V. Chernikov
2633e5d0784SAlexander V. Chernikov info->module_ptr = NULL;
2643e5d0784SAlexander V. Chernikov
2653e5d0784SAlexander V. Chernikov KTEST_LOCK();
2663e5d0784SAlexander V. Chernikov TAILQ_REMOVE(&module_list, mod, entries);
2673e5d0784SAlexander V. Chernikov KTEST_UNLOCK();
2683e5d0784SAlexander V. Chernikov
2693e5d0784SAlexander V. Chernikov free(mod, M_TEMP);
2703e5d0784SAlexander V. Chernikov }
2713e5d0784SAlexander V. Chernikov
2723e5d0784SAlexander V. Chernikov static bool
can_unregister(struct ktest_module_info * info)2733e5d0784SAlexander V. Chernikov can_unregister(struct ktest_module_info *info)
2743e5d0784SAlexander V. Chernikov {
2753e5d0784SAlexander V. Chernikov struct ktest_module *mod = info->module_ptr;
2763e5d0784SAlexander V. Chernikov
2773e5d0784SAlexander V. Chernikov return (refcount_load(&mod->refcount) == 0);
2783e5d0784SAlexander V. Chernikov }
2793e5d0784SAlexander V. Chernikov
2803e5d0784SAlexander V. Chernikov int
ktest_default_modevent(module_t mod,int type,void * arg)2813e5d0784SAlexander V. Chernikov ktest_default_modevent(module_t mod, int type, void *arg)
2823e5d0784SAlexander V. Chernikov {
2833e5d0784SAlexander V. Chernikov struct ktest_module_info *info = (struct ktest_module_info *)arg;
2843e5d0784SAlexander V. Chernikov int error = 0;
2853e5d0784SAlexander V. Chernikov
2863e5d0784SAlexander V. Chernikov switch (type) {
2873e5d0784SAlexander V. Chernikov case MOD_LOAD:
2883e5d0784SAlexander V. Chernikov register_test_module(info);
2893e5d0784SAlexander V. Chernikov break;
2903e5d0784SAlexander V. Chernikov case MOD_UNLOAD:
2913e5d0784SAlexander V. Chernikov if (!can_unregister(info))
2923e5d0784SAlexander V. Chernikov return (EBUSY);
2933e5d0784SAlexander V. Chernikov unregister_test_module(info);
2943e5d0784SAlexander V. Chernikov break;
2953e5d0784SAlexander V. Chernikov default:
2963e5d0784SAlexander V. Chernikov error = EOPNOTSUPP;
2973e5d0784SAlexander V. Chernikov break;
2983e5d0784SAlexander V. Chernikov }
2993e5d0784SAlexander V. Chernikov return (error);
3003e5d0784SAlexander V. Chernikov }
3013e5d0784SAlexander V. Chernikov
3023e5d0784SAlexander V. Chernikov bool
ktest_start_msg(struct ktest_test_context * ctx)3033e5d0784SAlexander V. Chernikov ktest_start_msg(struct ktest_test_context *ctx)
3043e5d0784SAlexander V. Chernikov {
3053e5d0784SAlexander V. Chernikov return (create_reply(ctx->npt->nw, ctx->hdr, KTEST_CMD_NEWMESSAGE));
3063e5d0784SAlexander V. Chernikov }
3073e5d0784SAlexander V. Chernikov
3083e5d0784SAlexander V. Chernikov void
ktest_add_msg_meta(struct ktest_test_context * ctx,const char * func,const char * fname,int line)3093e5d0784SAlexander V. Chernikov ktest_add_msg_meta(struct ktest_test_context *ctx, const char *func,
3103e5d0784SAlexander V. Chernikov const char *fname, int line)
3113e5d0784SAlexander V. Chernikov {
3123e5d0784SAlexander V. Chernikov struct nl_writer *nw = ctx->npt->nw;
3133e5d0784SAlexander V. Chernikov struct timespec ts;
3143e5d0784SAlexander V. Chernikov
3153e5d0784SAlexander V. Chernikov nanouptime(&ts);
3163e5d0784SAlexander V. Chernikov nlattr_add(nw, KTEST_MSG_ATTR_TS, sizeof(ts), &ts);
3173e5d0784SAlexander V. Chernikov
3183e5d0784SAlexander V. Chernikov nlattr_add_string(nw, KTEST_MSG_ATTR_FUNC, func);
3193e5d0784SAlexander V. Chernikov nlattr_add_string(nw, KTEST_MSG_ATTR_FILE, fname);
3203e5d0784SAlexander V. Chernikov nlattr_add_u32(nw, KTEST_MSG_ATTR_LINE, line);
3213e5d0784SAlexander V. Chernikov }
3223e5d0784SAlexander V. Chernikov
3233e5d0784SAlexander V. Chernikov void
ktest_add_msg_text(struct ktest_test_context * ctx,int msg_level,const char * fmt,...)3243e5d0784SAlexander V. Chernikov ktest_add_msg_text(struct ktest_test_context *ctx, int msg_level,
3253e5d0784SAlexander V. Chernikov const char *fmt, ...)
3263e5d0784SAlexander V. Chernikov {
3273e5d0784SAlexander V. Chernikov va_list ap;
3283e5d0784SAlexander V. Chernikov
3293e5d0784SAlexander V. Chernikov va_start(ap, fmt);
3303e5d0784SAlexander V. Chernikov vsnprintf(ctx->buf, ctx->bufsize, fmt, ap);
3313e5d0784SAlexander V. Chernikov va_end(ap);
3323e5d0784SAlexander V. Chernikov
3333e5d0784SAlexander V. Chernikov nlattr_add_u8(ctx->npt->nw, KTEST_MSG_ATTR_LEVEL, msg_level);
3343e5d0784SAlexander V. Chernikov nlattr_add_string(ctx->npt->nw, KTEST_MSG_ATTR_TEXT, ctx->buf);
3353e5d0784SAlexander V. Chernikov }
3363e5d0784SAlexander V. Chernikov
3373e5d0784SAlexander V. Chernikov void
ktest_end_msg(struct ktest_test_context * ctx)3383e5d0784SAlexander V. Chernikov ktest_end_msg(struct ktest_test_context *ctx)
3393e5d0784SAlexander V. Chernikov {
3403e5d0784SAlexander V. Chernikov nlmsg_end(ctx->npt->nw);
3413e5d0784SAlexander V. Chernikov }
3423e5d0784SAlexander V. Chernikov
3433e5d0784SAlexander V. Chernikov /* Module glue */
3443e5d0784SAlexander V. Chernikov
3453e5d0784SAlexander V. Chernikov static const struct nlhdr_parser *all_parsers[] = { &ktest_parser };
3463e5d0784SAlexander V. Chernikov
3473e5d0784SAlexander V. Chernikov static const struct genl_cmd ktest_cmds[] = {
3483e5d0784SAlexander V. Chernikov {
3493e5d0784SAlexander V. Chernikov .cmd_num = KTEST_CMD_LIST,
3503e5d0784SAlexander V. Chernikov .cmd_name = "KTEST_CMD_LIST",
3513e5d0784SAlexander V. Chernikov .cmd_cb = dump_tests,
3523e5d0784SAlexander V. Chernikov .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
3533e5d0784SAlexander V. Chernikov },
3543e5d0784SAlexander V. Chernikov {
3553e5d0784SAlexander V. Chernikov .cmd_num = KTEST_CMD_RUN,
3563e5d0784SAlexander V. Chernikov .cmd_name = "KTEST_CMD_RUN",
3573e5d0784SAlexander V. Chernikov .cmd_cb = run_test,
3583e5d0784SAlexander V. Chernikov .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
3593e5d0784SAlexander V. Chernikov .cmd_priv = PRIV_KLD_LOAD,
3603e5d0784SAlexander V. Chernikov },
3613e5d0784SAlexander V. Chernikov };
3623e5d0784SAlexander V. Chernikov
363*ee507b70SGleb Smirnoff static int family_id;
3643e5d0784SAlexander V. Chernikov static void
ktest_nl_register(void)3653e5d0784SAlexander V. Chernikov ktest_nl_register(void)
3663e5d0784SAlexander V. Chernikov {
3673e5d0784SAlexander V. Chernikov bool ret __diagused;
3683e5d0784SAlexander V. Chernikov
3693e5d0784SAlexander V. Chernikov NL_VERIFY_PARSERS(all_parsers);
3703e5d0784SAlexander V. Chernikov family_id = genl_register_family(KTEST_FAMILY_NAME, 0, 1, KTEST_CMD_MAX);
3713e5d0784SAlexander V. Chernikov MPASS(family_id != 0);
3723e5d0784SAlexander V. Chernikov
373*ee507b70SGleb Smirnoff ret = genl_register_cmds(family_id, ktest_cmds, nitems(ktest_cmds));
3743e5d0784SAlexander V. Chernikov MPASS(ret);
3753e5d0784SAlexander V. Chernikov }
3763e5d0784SAlexander V. Chernikov
3773e5d0784SAlexander V. Chernikov static void
ktest_nl_unregister(void)3783e5d0784SAlexander V. Chernikov ktest_nl_unregister(void)
3793e5d0784SAlexander V. Chernikov {
3803e5d0784SAlexander V. Chernikov MPASS(TAILQ_EMPTY(&module_list));
3813e5d0784SAlexander V. Chernikov
382*ee507b70SGleb Smirnoff genl_unregister_family(family_id);
3833e5d0784SAlexander V. Chernikov }
3843e5d0784SAlexander V. Chernikov
3853e5d0784SAlexander V. Chernikov static int
ktest_modevent(module_t mod,int type,void * unused)3863e5d0784SAlexander V. Chernikov ktest_modevent(module_t mod, int type, void *unused)
3873e5d0784SAlexander V. Chernikov {
3883e5d0784SAlexander V. Chernikov int error = 0;
3893e5d0784SAlexander V. Chernikov
3903e5d0784SAlexander V. Chernikov switch (type) {
3913e5d0784SAlexander V. Chernikov case MOD_LOAD:
3923e5d0784SAlexander V. Chernikov ktest_nl_register();
3933e5d0784SAlexander V. Chernikov break;
3943e5d0784SAlexander V. Chernikov case MOD_UNLOAD:
3953e5d0784SAlexander V. Chernikov ktest_nl_unregister();
3963e5d0784SAlexander V. Chernikov break;
3973e5d0784SAlexander V. Chernikov default:
3983e5d0784SAlexander V. Chernikov error = EOPNOTSUPP;
3993e5d0784SAlexander V. Chernikov break;
4003e5d0784SAlexander V. Chernikov }
4013e5d0784SAlexander V. Chernikov return (error);
4023e5d0784SAlexander V. Chernikov }
4033e5d0784SAlexander V. Chernikov
4043e5d0784SAlexander V. Chernikov static moduledata_t ktestmod = {
4053e5d0784SAlexander V. Chernikov "ktest",
4063e5d0784SAlexander V. Chernikov ktest_modevent,
4073e5d0784SAlexander V. Chernikov 0
4083e5d0784SAlexander V. Chernikov };
4093e5d0784SAlexander V. Chernikov
4103e5d0784SAlexander V. Chernikov DECLARE_MODULE(ktestmod, ktestmod, SI_SUB_PSEUDO, SI_ORDER_ANY);
4113e5d0784SAlexander V. Chernikov MODULE_VERSION(ktestmod, 1);
4123e5d0784SAlexander V. Chernikov MODULE_DEPEND(ktestmod, netlink, 1, 1, 1);
4133e5d0784SAlexander V. Chernikov
414