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 "opt_netlink.h" 293e5d0784SAlexander V. Chernikov 303e5d0784SAlexander V. Chernikov #include <sys/param.h> 313e5d0784SAlexander V. Chernikov #include <sys/refcount.h> 323e5d0784SAlexander V. Chernikov #include <sys/types.h> 333e5d0784SAlexander V. Chernikov #include <sys/kernel.h> 343e5d0784SAlexander V. Chernikov #include <sys/lock.h> 35*f656a960SAlexander V. Chernikov #include <sys/mutex.h> 363e5d0784SAlexander V. Chernikov #include <sys/malloc.h> 373e5d0784SAlexander V. Chernikov #include <sys/module.h> 383e5d0784SAlexander V. Chernikov #include <sys/socket.h> 393e5d0784SAlexander V. Chernikov #include <sys/priv.h> 403e5d0784SAlexander V. Chernikov 413e5d0784SAlexander V. Chernikov #include <netlink/netlink.h> 423e5d0784SAlexander V. Chernikov #include <netlink/netlink_ctl.h> 433e5d0784SAlexander V. Chernikov #include <netlink/netlink_generic.h> 443e5d0784SAlexander V. Chernikov #include <netlink/netlink_message_parser.h> 453e5d0784SAlexander V. Chernikov 463e5d0784SAlexander V. Chernikov #include <machine/stdarg.h> 473e5d0784SAlexander V. Chernikov #include <tests/ktest.h> 483e5d0784SAlexander V. Chernikov 493e5d0784SAlexander V. Chernikov struct mtx ktest_mtx; 503e5d0784SAlexander V. Chernikov #define KTEST_LOCK() mtx_lock(&ktest_mtx) 513e5d0784SAlexander V. Chernikov #define KTEST_UNLOCK() mtx_unlock(&ktest_mtx) 523e5d0784SAlexander V. Chernikov #define KTEST_LOCK_ASSERT() mtx_assert(&ktest_mtx, MA_OWNED) 533e5d0784SAlexander V. Chernikov 543e5d0784SAlexander V. Chernikov MTX_SYSINIT(ktest_mtx, &ktest_mtx, "ktest mutex", MTX_DEF); 553e5d0784SAlexander V. Chernikov 563e5d0784SAlexander V. Chernikov struct ktest_module { 573e5d0784SAlexander V. Chernikov struct ktest_module_info *info; 583e5d0784SAlexander V. Chernikov volatile u_int refcount; 593e5d0784SAlexander V. Chernikov TAILQ_ENTRY(ktest_module) entries; 603e5d0784SAlexander V. Chernikov }; 613e5d0784SAlexander V. Chernikov static TAILQ_HEAD(, ktest_module) module_list = TAILQ_HEAD_INITIALIZER(module_list); 623e5d0784SAlexander V. Chernikov 633e5d0784SAlexander V. Chernikov struct nl_ktest_parsed { 643e5d0784SAlexander V. Chernikov char *mod_name; 653e5d0784SAlexander V. Chernikov char *test_name; 663e5d0784SAlexander V. Chernikov struct nlattr *test_meta; 673e5d0784SAlexander V. Chernikov }; 683e5d0784SAlexander V. Chernikov 693e5d0784SAlexander V. Chernikov #define _IN(_field) offsetof(struct genlmsghdr, _field) 703e5d0784SAlexander V. Chernikov #define _OUT(_field) offsetof(struct nl_ktest_parsed, _field) 713e5d0784SAlexander V. Chernikov 723e5d0784SAlexander V. Chernikov static const struct nlattr_parser nla_p_get[] = { 733e5d0784SAlexander V. Chernikov { .type = KTEST_ATTR_MOD_NAME, .off = _OUT(mod_name), .cb = nlattr_get_string }, 743e5d0784SAlexander V. Chernikov { .type = KTEST_ATTR_TEST_NAME, .off = _OUT(test_name), .cb = nlattr_get_string }, 753e5d0784SAlexander V. Chernikov { .type = KTEST_ATTR_TEST_META, .off = _OUT(test_meta), .cb = nlattr_get_nla }, 763e5d0784SAlexander V. Chernikov }; 773e5d0784SAlexander V. Chernikov static const struct nlfield_parser nlf_p_get[] = { 783e5d0784SAlexander V. Chernikov }; 793e5d0784SAlexander V. Chernikov NL_DECLARE_PARSER(ktest_parser, struct genlmsghdr, nlf_p_get, nla_p_get); 803e5d0784SAlexander V. Chernikov #undef _IN 813e5d0784SAlexander V. Chernikov #undef _OUT 823e5d0784SAlexander V. Chernikov 833e5d0784SAlexander V. Chernikov static bool 843e5d0784SAlexander V. Chernikov create_reply(struct nl_writer *nw, struct nlmsghdr *hdr, int cmd) 853e5d0784SAlexander V. Chernikov { 863e5d0784SAlexander V. Chernikov if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr))) 873e5d0784SAlexander V. Chernikov return (false); 883e5d0784SAlexander V. Chernikov 893e5d0784SAlexander V. Chernikov struct genlmsghdr *ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr); 903e5d0784SAlexander V. Chernikov ghdr_new->cmd = cmd; 913e5d0784SAlexander V. Chernikov ghdr_new->version = 0; 923e5d0784SAlexander V. Chernikov ghdr_new->reserved = 0; 933e5d0784SAlexander V. Chernikov 943e5d0784SAlexander V. Chernikov return (true); 953e5d0784SAlexander V. Chernikov } 963e5d0784SAlexander V. Chernikov 973e5d0784SAlexander V. Chernikov static int 983e5d0784SAlexander V. Chernikov dump_mod_test(struct nlmsghdr *hdr, struct nl_pstate *npt, 993e5d0784SAlexander V. Chernikov struct ktest_module *mod, const struct ktest_test_info *test_info) 1003e5d0784SAlexander V. Chernikov { 1013e5d0784SAlexander V. Chernikov struct nl_writer *nw = npt->nw; 1023e5d0784SAlexander V. Chernikov 1033e5d0784SAlexander V. Chernikov if (!create_reply(nw, hdr, KTEST_CMD_NEWTEST)) 1043e5d0784SAlexander V. Chernikov goto enomem; 1053e5d0784SAlexander V. Chernikov 1063e5d0784SAlexander V. Chernikov nlattr_add_string(nw, KTEST_ATTR_MOD_NAME, mod->info->name); 1073e5d0784SAlexander V. Chernikov nlattr_add_string(nw, KTEST_ATTR_TEST_NAME, test_info->name); 1083e5d0784SAlexander V. Chernikov nlattr_add_string(nw, KTEST_ATTR_TEST_DESCR, test_info->desc); 1093e5d0784SAlexander V. Chernikov 1103e5d0784SAlexander V. Chernikov if (nlmsg_end(nw)) 1113e5d0784SAlexander V. Chernikov return (0); 1123e5d0784SAlexander V. Chernikov enomem: 1133e5d0784SAlexander V. Chernikov nlmsg_abort(nw); 1143e5d0784SAlexander V. Chernikov return (ENOMEM); 1153e5d0784SAlexander V. Chernikov } 1163e5d0784SAlexander V. Chernikov 1173e5d0784SAlexander V. Chernikov static int 1183e5d0784SAlexander V. Chernikov dump_mod_tests(struct nlmsghdr *hdr, struct nl_pstate *npt, 1193e5d0784SAlexander V. Chernikov struct ktest_module *mod, struct nl_ktest_parsed *attrs) 1203e5d0784SAlexander V. Chernikov { 1213e5d0784SAlexander V. Chernikov for (int i = 0; i < mod->info->num_tests; i++) { 1223e5d0784SAlexander V. Chernikov const struct ktest_test_info *test_info = &mod->info->tests[i]; 1233e5d0784SAlexander V. Chernikov if (attrs->test_name != NULL && strcmp(attrs->test_name, test_info->name)) 1243e5d0784SAlexander V. Chernikov continue; 1253e5d0784SAlexander V. Chernikov int error = dump_mod_test(hdr, npt, mod, test_info); 1263e5d0784SAlexander V. Chernikov if (error != 0) 1273e5d0784SAlexander V. Chernikov return (error); 1283e5d0784SAlexander V. Chernikov } 1293e5d0784SAlexander V. Chernikov 1303e5d0784SAlexander V. Chernikov return (0); 1313e5d0784SAlexander V. Chernikov } 1323e5d0784SAlexander V. Chernikov 1333e5d0784SAlexander V. Chernikov static int 1343e5d0784SAlexander V. Chernikov dump_tests(struct nlmsghdr *hdr, struct nl_pstate *npt) 1353e5d0784SAlexander V. Chernikov { 1363e5d0784SAlexander V. Chernikov struct nl_ktest_parsed attrs = { }; 1373e5d0784SAlexander V. Chernikov struct ktest_module *mod; 1383e5d0784SAlexander V. Chernikov int error; 1393e5d0784SAlexander V. Chernikov 1403e5d0784SAlexander V. Chernikov error = nl_parse_nlmsg(hdr, &ktest_parser, npt, &attrs); 1413e5d0784SAlexander V. Chernikov if (error != 0) 1423e5d0784SAlexander V. Chernikov return (error); 1433e5d0784SAlexander V. Chernikov 1443e5d0784SAlexander V. Chernikov hdr->nlmsg_flags |= NLM_F_MULTI; 1453e5d0784SAlexander V. Chernikov 1463e5d0784SAlexander V. Chernikov KTEST_LOCK(); 1473e5d0784SAlexander V. Chernikov TAILQ_FOREACH(mod, &module_list, entries) { 1483e5d0784SAlexander V. Chernikov if (attrs.mod_name && strcmp(attrs.mod_name, mod->info->name)) 1493e5d0784SAlexander V. Chernikov continue; 1503e5d0784SAlexander V. Chernikov error = dump_mod_tests(hdr, npt, mod, &attrs); 1513e5d0784SAlexander V. Chernikov if (error != 0) 1523e5d0784SAlexander V. Chernikov break; 1533e5d0784SAlexander V. Chernikov } 1543e5d0784SAlexander V. Chernikov KTEST_UNLOCK(); 1553e5d0784SAlexander V. Chernikov 1563e5d0784SAlexander V. Chernikov if (!nlmsg_end_dump(npt->nw, error, hdr)) { 1573e5d0784SAlexander V. Chernikov //NL_LOG(LOG_DEBUG, "Unable to finalize the dump"); 1583e5d0784SAlexander V. Chernikov return (ENOMEM); 1593e5d0784SAlexander V. Chernikov } 1603e5d0784SAlexander V. Chernikov 1613e5d0784SAlexander V. Chernikov return (error); 1623e5d0784SAlexander V. Chernikov } 1633e5d0784SAlexander V. Chernikov 1643e5d0784SAlexander V. Chernikov static int 1653e5d0784SAlexander V. Chernikov run_test(struct nlmsghdr *hdr, struct nl_pstate *npt) 1663e5d0784SAlexander V. Chernikov { 1673e5d0784SAlexander V. Chernikov struct nl_ktest_parsed attrs = { }; 1683e5d0784SAlexander V. Chernikov struct ktest_module *mod; 1693e5d0784SAlexander V. Chernikov int error; 1703e5d0784SAlexander V. Chernikov 1713e5d0784SAlexander V. Chernikov error = nl_parse_nlmsg(hdr, &ktest_parser, npt, &attrs); 1723e5d0784SAlexander V. Chernikov if (error != 0) 1733e5d0784SAlexander V. Chernikov return (error); 1743e5d0784SAlexander V. Chernikov 1753e5d0784SAlexander V. Chernikov if (attrs.mod_name == NULL) { 1763e5d0784SAlexander V. Chernikov nlmsg_report_err_msg(npt, "KTEST_ATTR_MOD_NAME not set"); 1773e5d0784SAlexander V. Chernikov return (EINVAL); 1783e5d0784SAlexander V. Chernikov } 1793e5d0784SAlexander V. Chernikov 1803e5d0784SAlexander V. Chernikov if (attrs.test_name == NULL) { 1813e5d0784SAlexander V. Chernikov nlmsg_report_err_msg(npt, "KTEST_ATTR_TEST_NAME not set"); 1823e5d0784SAlexander V. Chernikov return (EINVAL); 1833e5d0784SAlexander V. Chernikov } 1843e5d0784SAlexander V. Chernikov 1853e5d0784SAlexander V. Chernikov const struct ktest_test_info *test = NULL; 1863e5d0784SAlexander V. Chernikov 1873e5d0784SAlexander V. Chernikov KTEST_LOCK(); 1883e5d0784SAlexander V. Chernikov TAILQ_FOREACH(mod, &module_list, entries) { 1893e5d0784SAlexander V. Chernikov if (strcmp(attrs.mod_name, mod->info->name)) 1903e5d0784SAlexander V. Chernikov continue; 1913e5d0784SAlexander V. Chernikov 1923e5d0784SAlexander V. Chernikov const struct ktest_module_info *info = mod->info; 1933e5d0784SAlexander V. Chernikov 1943e5d0784SAlexander V. Chernikov for (int i = 0; i < info->num_tests; i++) { 1953e5d0784SAlexander V. Chernikov const struct ktest_test_info *test_info = &info->tests[i]; 1963e5d0784SAlexander V. Chernikov 1973e5d0784SAlexander V. Chernikov if (!strcmp(attrs.test_name, test_info->name)) { 1983e5d0784SAlexander V. Chernikov test = test_info; 1993e5d0784SAlexander V. Chernikov break; 2003e5d0784SAlexander V. Chernikov } 2013e5d0784SAlexander V. Chernikov } 2023e5d0784SAlexander V. Chernikov break; 2033e5d0784SAlexander V. Chernikov } 2043e5d0784SAlexander V. Chernikov if (test != NULL) 2053e5d0784SAlexander V. Chernikov refcount_acquire(&mod->refcount); 2063e5d0784SAlexander V. Chernikov KTEST_UNLOCK(); 2073e5d0784SAlexander V. Chernikov 2083e5d0784SAlexander V. Chernikov if (test == NULL) 2093e5d0784SAlexander V. Chernikov return (ESRCH); 2103e5d0784SAlexander V. Chernikov 2113e5d0784SAlexander V. Chernikov /* Run the test */ 2123e5d0784SAlexander V. Chernikov struct ktest_test_context ctx = { 2133e5d0784SAlexander V. Chernikov .npt = npt, 2143e5d0784SAlexander V. Chernikov .hdr = hdr, 2153e5d0784SAlexander V. Chernikov .buf = npt_alloc(npt, KTEST_MAX_BUF), 2163e5d0784SAlexander V. Chernikov .bufsize = KTEST_MAX_BUF, 2173e5d0784SAlexander V. Chernikov }; 2183e5d0784SAlexander V. Chernikov 2193e5d0784SAlexander V. Chernikov if (ctx.buf == NULL) { 2203e5d0784SAlexander V. Chernikov //NL_LOG(LOG_DEBUG, "unable to allocate temporary buffer"); 2213e5d0784SAlexander V. Chernikov return (ENOMEM); 2223e5d0784SAlexander V. Chernikov } 2233e5d0784SAlexander V. Chernikov 2243e5d0784SAlexander V. Chernikov if (test->parse != NULL && attrs.test_meta != NULL) { 2253e5d0784SAlexander V. Chernikov error = test->parse(&ctx, attrs.test_meta); 2263e5d0784SAlexander V. Chernikov if (error != 0) 2273e5d0784SAlexander V. Chernikov return (error); 2283e5d0784SAlexander V. Chernikov } 2293e5d0784SAlexander V. Chernikov 2303e5d0784SAlexander V. Chernikov hdr->nlmsg_flags |= NLM_F_MULTI; 2313e5d0784SAlexander V. Chernikov 2323e5d0784SAlexander V. Chernikov KTEST_LOG_LEVEL(&ctx, LOG_INFO, "start running %s", test->name); 2333e5d0784SAlexander V. Chernikov error = test->func(&ctx); 2343e5d0784SAlexander V. Chernikov KTEST_LOG_LEVEL(&ctx, LOG_INFO, "end running %s", test->name); 2353e5d0784SAlexander V. Chernikov 2363e5d0784SAlexander V. Chernikov refcount_release(&mod->refcount); 2373e5d0784SAlexander V. Chernikov 2383e5d0784SAlexander V. Chernikov if (!nlmsg_end_dump(npt->nw, error, hdr)) { 2393e5d0784SAlexander V. Chernikov //NL_LOG(LOG_DEBUG, "Unable to finalize the dump"); 2403e5d0784SAlexander V. Chernikov return (ENOMEM); 2413e5d0784SAlexander V. Chernikov } 2423e5d0784SAlexander V. Chernikov 2433e5d0784SAlexander V. Chernikov return (error); 2443e5d0784SAlexander V. Chernikov } 2453e5d0784SAlexander V. Chernikov 2463e5d0784SAlexander V. Chernikov 2473e5d0784SAlexander V. Chernikov /* USER API */ 2483e5d0784SAlexander V. Chernikov static void 2493e5d0784SAlexander V. Chernikov register_test_module(struct ktest_module_info *info) 2503e5d0784SAlexander V. Chernikov { 2513e5d0784SAlexander V. Chernikov struct ktest_module *mod = malloc(sizeof(*mod), M_TEMP, M_WAITOK | M_ZERO); 2523e5d0784SAlexander V. Chernikov 2533e5d0784SAlexander V. Chernikov mod->info = info; 2543e5d0784SAlexander V. Chernikov info->module_ptr = mod; 2553e5d0784SAlexander V. Chernikov KTEST_LOCK(); 2563e5d0784SAlexander V. Chernikov TAILQ_INSERT_TAIL(&module_list, mod, entries); 2573e5d0784SAlexander V. Chernikov KTEST_UNLOCK(); 2583e5d0784SAlexander V. Chernikov } 2593e5d0784SAlexander V. Chernikov 2603e5d0784SAlexander V. Chernikov static void 2613e5d0784SAlexander V. Chernikov unregister_test_module(struct ktest_module_info *info) 2623e5d0784SAlexander V. Chernikov { 2633e5d0784SAlexander V. Chernikov struct ktest_module *mod = info->module_ptr; 2643e5d0784SAlexander V. Chernikov 2653e5d0784SAlexander V. Chernikov info->module_ptr = NULL; 2663e5d0784SAlexander V. Chernikov 2673e5d0784SAlexander V. Chernikov KTEST_LOCK(); 2683e5d0784SAlexander V. Chernikov TAILQ_REMOVE(&module_list, mod, entries); 2693e5d0784SAlexander V. Chernikov KTEST_UNLOCK(); 2703e5d0784SAlexander V. Chernikov 2713e5d0784SAlexander V. Chernikov free(mod, M_TEMP); 2723e5d0784SAlexander V. Chernikov } 2733e5d0784SAlexander V. Chernikov 2743e5d0784SAlexander V. Chernikov static bool 2753e5d0784SAlexander V. Chernikov can_unregister(struct ktest_module_info *info) 2763e5d0784SAlexander V. Chernikov { 2773e5d0784SAlexander V. Chernikov struct ktest_module *mod = info->module_ptr; 2783e5d0784SAlexander V. Chernikov 2793e5d0784SAlexander V. Chernikov return (refcount_load(&mod->refcount) == 0); 2803e5d0784SAlexander V. Chernikov } 2813e5d0784SAlexander V. Chernikov 2823e5d0784SAlexander V. Chernikov int 2833e5d0784SAlexander V. Chernikov ktest_default_modevent(module_t mod, int type, void *arg) 2843e5d0784SAlexander V. Chernikov { 2853e5d0784SAlexander V. Chernikov struct ktest_module_info *info = (struct ktest_module_info *)arg; 2863e5d0784SAlexander V. Chernikov int error = 0; 2873e5d0784SAlexander V. Chernikov 2883e5d0784SAlexander V. Chernikov switch (type) { 2893e5d0784SAlexander V. Chernikov case MOD_LOAD: 2903e5d0784SAlexander V. Chernikov register_test_module(info); 2913e5d0784SAlexander V. Chernikov break; 2923e5d0784SAlexander V. Chernikov case MOD_UNLOAD: 2933e5d0784SAlexander V. Chernikov if (!can_unregister(info)) 2943e5d0784SAlexander V. Chernikov return (EBUSY); 2953e5d0784SAlexander V. Chernikov unregister_test_module(info); 2963e5d0784SAlexander V. Chernikov break; 2973e5d0784SAlexander V. Chernikov default: 2983e5d0784SAlexander V. Chernikov error = EOPNOTSUPP; 2993e5d0784SAlexander V. Chernikov break; 3003e5d0784SAlexander V. Chernikov } 3013e5d0784SAlexander V. Chernikov return (error); 3023e5d0784SAlexander V. Chernikov } 3033e5d0784SAlexander V. Chernikov 3043e5d0784SAlexander V. Chernikov bool 3053e5d0784SAlexander V. Chernikov ktest_start_msg(struct ktest_test_context *ctx) 3063e5d0784SAlexander V. Chernikov { 3073e5d0784SAlexander V. Chernikov return (create_reply(ctx->npt->nw, ctx->hdr, KTEST_CMD_NEWMESSAGE)); 3083e5d0784SAlexander V. Chernikov } 3093e5d0784SAlexander V. Chernikov 3103e5d0784SAlexander V. Chernikov void 3113e5d0784SAlexander V. Chernikov ktest_add_msg_meta(struct ktest_test_context *ctx, const char *func, 3123e5d0784SAlexander V. Chernikov const char *fname, int line) 3133e5d0784SAlexander V. Chernikov { 3143e5d0784SAlexander V. Chernikov struct nl_writer *nw = ctx->npt->nw; 3153e5d0784SAlexander V. Chernikov struct timespec ts; 3163e5d0784SAlexander V. Chernikov 3173e5d0784SAlexander V. Chernikov nanouptime(&ts); 3183e5d0784SAlexander V. Chernikov nlattr_add(nw, KTEST_MSG_ATTR_TS, sizeof(ts), &ts); 3193e5d0784SAlexander V. Chernikov 3203e5d0784SAlexander V. Chernikov nlattr_add_string(nw, KTEST_MSG_ATTR_FUNC, func); 3213e5d0784SAlexander V. Chernikov nlattr_add_string(nw, KTEST_MSG_ATTR_FILE, fname); 3223e5d0784SAlexander V. Chernikov nlattr_add_u32(nw, KTEST_MSG_ATTR_LINE, line); 3233e5d0784SAlexander V. Chernikov } 3243e5d0784SAlexander V. Chernikov 3253e5d0784SAlexander V. Chernikov void 3263e5d0784SAlexander V. Chernikov ktest_add_msg_text(struct ktest_test_context *ctx, int msg_level, 3273e5d0784SAlexander V. Chernikov const char *fmt, ...) 3283e5d0784SAlexander V. Chernikov { 3293e5d0784SAlexander V. Chernikov va_list ap; 3303e5d0784SAlexander V. Chernikov 3313e5d0784SAlexander V. Chernikov va_start(ap, fmt); 3323e5d0784SAlexander V. Chernikov vsnprintf(ctx->buf, ctx->bufsize, fmt, ap); 3333e5d0784SAlexander V. Chernikov va_end(ap); 3343e5d0784SAlexander V. Chernikov 3353e5d0784SAlexander V. Chernikov nlattr_add_u8(ctx->npt->nw, KTEST_MSG_ATTR_LEVEL, msg_level); 3363e5d0784SAlexander V. Chernikov nlattr_add_string(ctx->npt->nw, KTEST_MSG_ATTR_TEXT, ctx->buf); 3373e5d0784SAlexander V. Chernikov } 3383e5d0784SAlexander V. Chernikov 3393e5d0784SAlexander V. Chernikov void 3403e5d0784SAlexander V. Chernikov ktest_end_msg(struct ktest_test_context *ctx) 3413e5d0784SAlexander V. Chernikov { 3423e5d0784SAlexander V. Chernikov nlmsg_end(ctx->npt->nw); 3433e5d0784SAlexander V. Chernikov } 3443e5d0784SAlexander V. Chernikov 3453e5d0784SAlexander V. Chernikov /* Module glue */ 3463e5d0784SAlexander V. Chernikov 3473e5d0784SAlexander V. Chernikov static const struct nlhdr_parser *all_parsers[] = { &ktest_parser }; 3483e5d0784SAlexander V. Chernikov 3493e5d0784SAlexander V. Chernikov static const struct genl_cmd ktest_cmds[] = { 3503e5d0784SAlexander V. Chernikov { 3513e5d0784SAlexander V. Chernikov .cmd_num = KTEST_CMD_LIST, 3523e5d0784SAlexander V. Chernikov .cmd_name = "KTEST_CMD_LIST", 3533e5d0784SAlexander V. Chernikov .cmd_cb = dump_tests, 3543e5d0784SAlexander V. Chernikov .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL, 3553e5d0784SAlexander V. Chernikov }, 3563e5d0784SAlexander V. Chernikov { 3573e5d0784SAlexander V. Chernikov .cmd_num = KTEST_CMD_RUN, 3583e5d0784SAlexander V. Chernikov .cmd_name = "KTEST_CMD_RUN", 3593e5d0784SAlexander V. Chernikov .cmd_cb = run_test, 3603e5d0784SAlexander V. Chernikov .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL, 3613e5d0784SAlexander V. Chernikov .cmd_priv = PRIV_KLD_LOAD, 3623e5d0784SAlexander V. Chernikov }, 3633e5d0784SAlexander V. Chernikov }; 3643e5d0784SAlexander V. Chernikov 3653e5d0784SAlexander V. Chernikov static void 3663e5d0784SAlexander V. Chernikov ktest_nl_register(void) 3673e5d0784SAlexander V. Chernikov { 3683e5d0784SAlexander V. Chernikov bool ret __diagused; 3693e5d0784SAlexander V. Chernikov int family_id __diagused; 3703e5d0784SAlexander V. Chernikov 3713e5d0784SAlexander V. Chernikov NL_VERIFY_PARSERS(all_parsers); 3723e5d0784SAlexander V. Chernikov family_id = genl_register_family(KTEST_FAMILY_NAME, 0, 1, KTEST_CMD_MAX); 3733e5d0784SAlexander V. Chernikov MPASS(family_id != 0); 3743e5d0784SAlexander V. Chernikov 3753e5d0784SAlexander V. Chernikov ret = genl_register_cmds(KTEST_FAMILY_NAME, ktest_cmds, NL_ARRAY_LEN(ktest_cmds)); 3763e5d0784SAlexander V. Chernikov MPASS(ret); 3773e5d0784SAlexander V. Chernikov } 3783e5d0784SAlexander V. Chernikov 3793e5d0784SAlexander V. Chernikov static void 3803e5d0784SAlexander V. Chernikov ktest_nl_unregister(void) 3813e5d0784SAlexander V. Chernikov { 3823e5d0784SAlexander V. Chernikov MPASS(TAILQ_EMPTY(&module_list)); 3833e5d0784SAlexander V. Chernikov 3843e5d0784SAlexander V. Chernikov genl_unregister_family(KTEST_FAMILY_NAME); 3853e5d0784SAlexander V. Chernikov } 3863e5d0784SAlexander V. Chernikov 3873e5d0784SAlexander V. Chernikov static int 3883e5d0784SAlexander V. Chernikov ktest_modevent(module_t mod, int type, void *unused) 3893e5d0784SAlexander V. Chernikov { 3903e5d0784SAlexander V. Chernikov int error = 0; 3913e5d0784SAlexander V. Chernikov 3923e5d0784SAlexander V. Chernikov switch (type) { 3933e5d0784SAlexander V. Chernikov case MOD_LOAD: 3943e5d0784SAlexander V. Chernikov ktest_nl_register(); 3953e5d0784SAlexander V. Chernikov break; 3963e5d0784SAlexander V. Chernikov case MOD_UNLOAD: 3973e5d0784SAlexander V. Chernikov ktest_nl_unregister(); 3983e5d0784SAlexander V. Chernikov break; 3993e5d0784SAlexander V. Chernikov default: 4003e5d0784SAlexander V. Chernikov error = EOPNOTSUPP; 4013e5d0784SAlexander V. Chernikov break; 4023e5d0784SAlexander V. Chernikov } 4033e5d0784SAlexander V. Chernikov return (error); 4043e5d0784SAlexander V. Chernikov } 4053e5d0784SAlexander V. Chernikov 4063e5d0784SAlexander V. Chernikov static moduledata_t ktestmod = { 4073e5d0784SAlexander V. Chernikov "ktest", 4083e5d0784SAlexander V. Chernikov ktest_modevent, 4093e5d0784SAlexander V. Chernikov 0 4103e5d0784SAlexander V. Chernikov }; 4113e5d0784SAlexander V. Chernikov 4123e5d0784SAlexander V. Chernikov DECLARE_MODULE(ktestmod, ktestmod, SI_SUB_PSEUDO, SI_ORDER_ANY); 4133e5d0784SAlexander V. Chernikov MODULE_VERSION(ktestmod, 1); 4143e5d0784SAlexander V. Chernikov MODULE_DEPEND(ktestmod, netlink, 1, 1, 1); 4153e5d0784SAlexander V. Chernikov 416