1*3e5d0784SAlexander V. Chernikov /*- 2*3e5d0784SAlexander V. Chernikov * SPDX-License-Identifier: BSD-2-Clause 3*3e5d0784SAlexander V. Chernikov * 4*3e5d0784SAlexander V. Chernikov * Copyright (c) 2023 Alexander V. Chernikov 5*3e5d0784SAlexander V. Chernikov * 6*3e5d0784SAlexander V. Chernikov * Redistribution and use in source and binary forms, with or without 7*3e5d0784SAlexander V. Chernikov * modification, are permitted provided that the following conditions 8*3e5d0784SAlexander V. Chernikov * are met: 9*3e5d0784SAlexander V. Chernikov * 1. Redistributions of source code must retain the above copyright 10*3e5d0784SAlexander V. Chernikov * notice, this list of conditions and the following disclaimer. 11*3e5d0784SAlexander V. Chernikov * 2. Redistributions in binary form must reproduce the above copyright 12*3e5d0784SAlexander V. Chernikov * notice, this list of conditions and the following disclaimer in the 13*3e5d0784SAlexander V. Chernikov * documentation and/or other materials provided with the distribution. 14*3e5d0784SAlexander V. Chernikov * 15*3e5d0784SAlexander V. Chernikov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16*3e5d0784SAlexander V. Chernikov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17*3e5d0784SAlexander V. Chernikov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18*3e5d0784SAlexander V. Chernikov * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19*3e5d0784SAlexander V. Chernikov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20*3e5d0784SAlexander V. Chernikov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21*3e5d0784SAlexander V. Chernikov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22*3e5d0784SAlexander V. Chernikov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23*3e5d0784SAlexander V. Chernikov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24*3e5d0784SAlexander V. Chernikov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25*3e5d0784SAlexander V. Chernikov * SUCH DAMAGE. 26*3e5d0784SAlexander V. Chernikov */ 27*3e5d0784SAlexander V. Chernikov 28*3e5d0784SAlexander V. Chernikov #include "opt_netlink.h" 29*3e5d0784SAlexander V. Chernikov 30*3e5d0784SAlexander V. Chernikov #include <sys/param.h> 31*3e5d0784SAlexander V. Chernikov #include <sys/refcount.h> 32*3e5d0784SAlexander V. Chernikov #include <sys/types.h> 33*3e5d0784SAlexander V. Chernikov #include <sys/kernel.h> 34*3e5d0784SAlexander V. Chernikov #include <sys/lock.h> 35*3e5d0784SAlexander V. Chernikov #include <sys/malloc.h> 36*3e5d0784SAlexander V. Chernikov #include <sys/module.h> 37*3e5d0784SAlexander V. Chernikov #include <sys/socket.h> 38*3e5d0784SAlexander V. Chernikov #include <sys/priv.h> 39*3e5d0784SAlexander V. Chernikov 40*3e5d0784SAlexander V. Chernikov #include <netlink/netlink.h> 41*3e5d0784SAlexander V. Chernikov #include <netlink/netlink_ctl.h> 42*3e5d0784SAlexander V. Chernikov #include <netlink/netlink_generic.h> 43*3e5d0784SAlexander V. Chernikov #include <netlink/netlink_message_parser.h> 44*3e5d0784SAlexander V. Chernikov 45*3e5d0784SAlexander V. Chernikov #include <machine/stdarg.h> 46*3e5d0784SAlexander V. Chernikov #include <tests/ktest.h> 47*3e5d0784SAlexander V. Chernikov 48*3e5d0784SAlexander V. Chernikov struct mtx ktest_mtx; 49*3e5d0784SAlexander V. Chernikov #define KTEST_LOCK() mtx_lock(&ktest_mtx) 50*3e5d0784SAlexander V. Chernikov #define KTEST_UNLOCK() mtx_unlock(&ktest_mtx) 51*3e5d0784SAlexander V. Chernikov #define KTEST_LOCK_ASSERT() mtx_assert(&ktest_mtx, MA_OWNED) 52*3e5d0784SAlexander V. Chernikov 53*3e5d0784SAlexander V. Chernikov MTX_SYSINIT(ktest_mtx, &ktest_mtx, "ktest mutex", MTX_DEF); 54*3e5d0784SAlexander V. Chernikov 55*3e5d0784SAlexander V. Chernikov struct ktest_module { 56*3e5d0784SAlexander V. Chernikov struct ktest_module_info *info; 57*3e5d0784SAlexander V. Chernikov volatile u_int refcount; 58*3e5d0784SAlexander V. Chernikov TAILQ_ENTRY(ktest_module) entries; 59*3e5d0784SAlexander V. Chernikov }; 60*3e5d0784SAlexander V. Chernikov static TAILQ_HEAD(, ktest_module) module_list = TAILQ_HEAD_INITIALIZER(module_list); 61*3e5d0784SAlexander V. Chernikov 62*3e5d0784SAlexander V. Chernikov struct nl_ktest_parsed { 63*3e5d0784SAlexander V. Chernikov char *mod_name; 64*3e5d0784SAlexander V. Chernikov char *test_name; 65*3e5d0784SAlexander V. Chernikov struct nlattr *test_meta; 66*3e5d0784SAlexander V. Chernikov }; 67*3e5d0784SAlexander V. Chernikov 68*3e5d0784SAlexander V. Chernikov #define _IN(_field) offsetof(struct genlmsghdr, _field) 69*3e5d0784SAlexander V. Chernikov #define _OUT(_field) offsetof(struct nl_ktest_parsed, _field) 70*3e5d0784SAlexander V. Chernikov 71*3e5d0784SAlexander V. Chernikov static const struct nlattr_parser nla_p_get[] = { 72*3e5d0784SAlexander V. Chernikov { .type = KTEST_ATTR_MOD_NAME, .off = _OUT(mod_name), .cb = nlattr_get_string }, 73*3e5d0784SAlexander V. Chernikov { .type = KTEST_ATTR_TEST_NAME, .off = _OUT(test_name), .cb = nlattr_get_string }, 74*3e5d0784SAlexander V. Chernikov { .type = KTEST_ATTR_TEST_META, .off = _OUT(test_meta), .cb = nlattr_get_nla }, 75*3e5d0784SAlexander V. Chernikov }; 76*3e5d0784SAlexander V. Chernikov static const struct nlfield_parser nlf_p_get[] = { 77*3e5d0784SAlexander V. Chernikov }; 78*3e5d0784SAlexander V. Chernikov NL_DECLARE_PARSER(ktest_parser, struct genlmsghdr, nlf_p_get, nla_p_get); 79*3e5d0784SAlexander V. Chernikov #undef _IN 80*3e5d0784SAlexander V. Chernikov #undef _OUT 81*3e5d0784SAlexander V. Chernikov 82*3e5d0784SAlexander V. Chernikov static bool 83*3e5d0784SAlexander V. Chernikov create_reply(struct nl_writer *nw, struct nlmsghdr *hdr, int cmd) 84*3e5d0784SAlexander V. Chernikov { 85*3e5d0784SAlexander V. Chernikov if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr))) 86*3e5d0784SAlexander V. Chernikov return (false); 87*3e5d0784SAlexander V. Chernikov 88*3e5d0784SAlexander V. Chernikov struct genlmsghdr *ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr); 89*3e5d0784SAlexander V. Chernikov ghdr_new->cmd = cmd; 90*3e5d0784SAlexander V. Chernikov ghdr_new->version = 0; 91*3e5d0784SAlexander V. Chernikov ghdr_new->reserved = 0; 92*3e5d0784SAlexander V. Chernikov 93*3e5d0784SAlexander V. Chernikov return (true); 94*3e5d0784SAlexander V. Chernikov } 95*3e5d0784SAlexander V. Chernikov 96*3e5d0784SAlexander V. Chernikov static int 97*3e5d0784SAlexander V. Chernikov dump_mod_test(struct nlmsghdr *hdr, struct nl_pstate *npt, 98*3e5d0784SAlexander V. Chernikov struct ktest_module *mod, const struct ktest_test_info *test_info) 99*3e5d0784SAlexander V. Chernikov { 100*3e5d0784SAlexander V. Chernikov struct nl_writer *nw = npt->nw; 101*3e5d0784SAlexander V. Chernikov 102*3e5d0784SAlexander V. Chernikov if (!create_reply(nw, hdr, KTEST_CMD_NEWTEST)) 103*3e5d0784SAlexander V. Chernikov goto enomem; 104*3e5d0784SAlexander V. Chernikov 105*3e5d0784SAlexander V. Chernikov nlattr_add_string(nw, KTEST_ATTR_MOD_NAME, mod->info->name); 106*3e5d0784SAlexander V. Chernikov nlattr_add_string(nw, KTEST_ATTR_TEST_NAME, test_info->name); 107*3e5d0784SAlexander V. Chernikov nlattr_add_string(nw, KTEST_ATTR_TEST_DESCR, test_info->desc); 108*3e5d0784SAlexander V. Chernikov 109*3e5d0784SAlexander V. Chernikov if (nlmsg_end(nw)) 110*3e5d0784SAlexander V. Chernikov return (0); 111*3e5d0784SAlexander V. Chernikov enomem: 112*3e5d0784SAlexander V. Chernikov nlmsg_abort(nw); 113*3e5d0784SAlexander V. Chernikov return (ENOMEM); 114*3e5d0784SAlexander V. Chernikov } 115*3e5d0784SAlexander V. Chernikov 116*3e5d0784SAlexander V. Chernikov static int 117*3e5d0784SAlexander V. Chernikov dump_mod_tests(struct nlmsghdr *hdr, struct nl_pstate *npt, 118*3e5d0784SAlexander V. Chernikov struct ktest_module *mod, struct nl_ktest_parsed *attrs) 119*3e5d0784SAlexander V. Chernikov { 120*3e5d0784SAlexander V. Chernikov for (int i = 0; i < mod->info->num_tests; i++) { 121*3e5d0784SAlexander V. Chernikov const struct ktest_test_info *test_info = &mod->info->tests[i]; 122*3e5d0784SAlexander V. Chernikov if (attrs->test_name != NULL && strcmp(attrs->test_name, test_info->name)) 123*3e5d0784SAlexander V. Chernikov continue; 124*3e5d0784SAlexander V. Chernikov int error = dump_mod_test(hdr, npt, mod, test_info); 125*3e5d0784SAlexander V. Chernikov if (error != 0) 126*3e5d0784SAlexander V. Chernikov return (error); 127*3e5d0784SAlexander V. Chernikov } 128*3e5d0784SAlexander V. Chernikov 129*3e5d0784SAlexander V. Chernikov return (0); 130*3e5d0784SAlexander V. Chernikov } 131*3e5d0784SAlexander V. Chernikov 132*3e5d0784SAlexander V. Chernikov static int 133*3e5d0784SAlexander V. Chernikov dump_tests(struct nlmsghdr *hdr, struct nl_pstate *npt) 134*3e5d0784SAlexander V. Chernikov { 135*3e5d0784SAlexander V. Chernikov struct nl_ktest_parsed attrs = { }; 136*3e5d0784SAlexander V. Chernikov struct ktest_module *mod; 137*3e5d0784SAlexander V. Chernikov int error; 138*3e5d0784SAlexander V. Chernikov 139*3e5d0784SAlexander V. Chernikov error = nl_parse_nlmsg(hdr, &ktest_parser, npt, &attrs); 140*3e5d0784SAlexander V. Chernikov if (error != 0) 141*3e5d0784SAlexander V. Chernikov return (error); 142*3e5d0784SAlexander V. Chernikov 143*3e5d0784SAlexander V. Chernikov hdr->nlmsg_flags |= NLM_F_MULTI; 144*3e5d0784SAlexander V. Chernikov 145*3e5d0784SAlexander V. Chernikov KTEST_LOCK(); 146*3e5d0784SAlexander V. Chernikov TAILQ_FOREACH(mod, &module_list, entries) { 147*3e5d0784SAlexander V. Chernikov if (attrs.mod_name && strcmp(attrs.mod_name, mod->info->name)) 148*3e5d0784SAlexander V. Chernikov continue; 149*3e5d0784SAlexander V. Chernikov error = dump_mod_tests(hdr, npt, mod, &attrs); 150*3e5d0784SAlexander V. Chernikov if (error != 0) 151*3e5d0784SAlexander V. Chernikov break; 152*3e5d0784SAlexander V. Chernikov } 153*3e5d0784SAlexander V. Chernikov KTEST_UNLOCK(); 154*3e5d0784SAlexander V. Chernikov 155*3e5d0784SAlexander V. Chernikov if (!nlmsg_end_dump(npt->nw, error, hdr)) { 156*3e5d0784SAlexander V. Chernikov //NL_LOG(LOG_DEBUG, "Unable to finalize the dump"); 157*3e5d0784SAlexander V. Chernikov return (ENOMEM); 158*3e5d0784SAlexander V. Chernikov } 159*3e5d0784SAlexander V. Chernikov 160*3e5d0784SAlexander V. Chernikov return (error); 161*3e5d0784SAlexander V. Chernikov } 162*3e5d0784SAlexander V. Chernikov 163*3e5d0784SAlexander V. Chernikov static int 164*3e5d0784SAlexander V. Chernikov run_test(struct nlmsghdr *hdr, struct nl_pstate *npt) 165*3e5d0784SAlexander V. Chernikov { 166*3e5d0784SAlexander V. Chernikov struct nl_ktest_parsed attrs = { }; 167*3e5d0784SAlexander V. Chernikov struct ktest_module *mod; 168*3e5d0784SAlexander V. Chernikov int error; 169*3e5d0784SAlexander V. Chernikov 170*3e5d0784SAlexander V. Chernikov error = nl_parse_nlmsg(hdr, &ktest_parser, npt, &attrs); 171*3e5d0784SAlexander V. Chernikov if (error != 0) 172*3e5d0784SAlexander V. Chernikov return (error); 173*3e5d0784SAlexander V. Chernikov 174*3e5d0784SAlexander V. Chernikov if (attrs.mod_name == NULL) { 175*3e5d0784SAlexander V. Chernikov nlmsg_report_err_msg(npt, "KTEST_ATTR_MOD_NAME not set"); 176*3e5d0784SAlexander V. Chernikov return (EINVAL); 177*3e5d0784SAlexander V. Chernikov } 178*3e5d0784SAlexander V. Chernikov 179*3e5d0784SAlexander V. Chernikov if (attrs.test_name == NULL) { 180*3e5d0784SAlexander V. Chernikov nlmsg_report_err_msg(npt, "KTEST_ATTR_TEST_NAME not set"); 181*3e5d0784SAlexander V. Chernikov return (EINVAL); 182*3e5d0784SAlexander V. Chernikov } 183*3e5d0784SAlexander V. Chernikov 184*3e5d0784SAlexander V. Chernikov const struct ktest_test_info *test = NULL; 185*3e5d0784SAlexander V. Chernikov 186*3e5d0784SAlexander V. Chernikov KTEST_LOCK(); 187*3e5d0784SAlexander V. Chernikov TAILQ_FOREACH(mod, &module_list, entries) { 188*3e5d0784SAlexander V. Chernikov if (strcmp(attrs.mod_name, mod->info->name)) 189*3e5d0784SAlexander V. Chernikov continue; 190*3e5d0784SAlexander V. Chernikov 191*3e5d0784SAlexander V. Chernikov const struct ktest_module_info *info = mod->info; 192*3e5d0784SAlexander V. Chernikov 193*3e5d0784SAlexander V. Chernikov for (int i = 0; i < info->num_tests; i++) { 194*3e5d0784SAlexander V. Chernikov const struct ktest_test_info *test_info = &info->tests[i]; 195*3e5d0784SAlexander V. Chernikov 196*3e5d0784SAlexander V. Chernikov if (!strcmp(attrs.test_name, test_info->name)) { 197*3e5d0784SAlexander V. Chernikov test = test_info; 198*3e5d0784SAlexander V. Chernikov break; 199*3e5d0784SAlexander V. Chernikov } 200*3e5d0784SAlexander V. Chernikov } 201*3e5d0784SAlexander V. Chernikov break; 202*3e5d0784SAlexander V. Chernikov } 203*3e5d0784SAlexander V. Chernikov if (test != NULL) 204*3e5d0784SAlexander V. Chernikov refcount_acquire(&mod->refcount); 205*3e5d0784SAlexander V. Chernikov KTEST_UNLOCK(); 206*3e5d0784SAlexander V. Chernikov 207*3e5d0784SAlexander V. Chernikov if (test == NULL) 208*3e5d0784SAlexander V. Chernikov return (ESRCH); 209*3e5d0784SAlexander V. Chernikov 210*3e5d0784SAlexander V. Chernikov /* Run the test */ 211*3e5d0784SAlexander V. Chernikov struct ktest_test_context ctx = { 212*3e5d0784SAlexander V. Chernikov .npt = npt, 213*3e5d0784SAlexander V. Chernikov .hdr = hdr, 214*3e5d0784SAlexander V. Chernikov .buf = npt_alloc(npt, KTEST_MAX_BUF), 215*3e5d0784SAlexander V. Chernikov .bufsize = KTEST_MAX_BUF, 216*3e5d0784SAlexander V. Chernikov }; 217*3e5d0784SAlexander V. Chernikov 218*3e5d0784SAlexander V. Chernikov if (ctx.buf == NULL) { 219*3e5d0784SAlexander V. Chernikov //NL_LOG(LOG_DEBUG, "unable to allocate temporary buffer"); 220*3e5d0784SAlexander V. Chernikov return (ENOMEM); 221*3e5d0784SAlexander V. Chernikov } 222*3e5d0784SAlexander V. Chernikov 223*3e5d0784SAlexander V. Chernikov if (test->parse != NULL && attrs.test_meta != NULL) { 224*3e5d0784SAlexander V. Chernikov error = test->parse(&ctx, attrs.test_meta); 225*3e5d0784SAlexander V. Chernikov if (error != 0) 226*3e5d0784SAlexander V. Chernikov return (error); 227*3e5d0784SAlexander V. Chernikov } 228*3e5d0784SAlexander V. Chernikov 229*3e5d0784SAlexander V. Chernikov hdr->nlmsg_flags |= NLM_F_MULTI; 230*3e5d0784SAlexander V. Chernikov 231*3e5d0784SAlexander V. Chernikov KTEST_LOG_LEVEL(&ctx, LOG_INFO, "start running %s", test->name); 232*3e5d0784SAlexander V. Chernikov error = test->func(&ctx); 233*3e5d0784SAlexander V. Chernikov KTEST_LOG_LEVEL(&ctx, LOG_INFO, "end running %s", test->name); 234*3e5d0784SAlexander V. Chernikov 235*3e5d0784SAlexander V. Chernikov refcount_release(&mod->refcount); 236*3e5d0784SAlexander V. Chernikov 237*3e5d0784SAlexander V. Chernikov if (!nlmsg_end_dump(npt->nw, error, hdr)) { 238*3e5d0784SAlexander V. Chernikov //NL_LOG(LOG_DEBUG, "Unable to finalize the dump"); 239*3e5d0784SAlexander V. Chernikov return (ENOMEM); 240*3e5d0784SAlexander V. Chernikov } 241*3e5d0784SAlexander V. Chernikov 242*3e5d0784SAlexander V. Chernikov return (error); 243*3e5d0784SAlexander V. Chernikov } 244*3e5d0784SAlexander V. Chernikov 245*3e5d0784SAlexander V. Chernikov 246*3e5d0784SAlexander V. Chernikov /* USER API */ 247*3e5d0784SAlexander V. Chernikov static void 248*3e5d0784SAlexander V. Chernikov register_test_module(struct ktest_module_info *info) 249*3e5d0784SAlexander V. Chernikov { 250*3e5d0784SAlexander V. Chernikov struct ktest_module *mod = malloc(sizeof(*mod), M_TEMP, M_WAITOK | M_ZERO); 251*3e5d0784SAlexander V. Chernikov 252*3e5d0784SAlexander V. Chernikov mod->info = info; 253*3e5d0784SAlexander V. Chernikov info->module_ptr = mod; 254*3e5d0784SAlexander V. Chernikov KTEST_LOCK(); 255*3e5d0784SAlexander V. Chernikov TAILQ_INSERT_TAIL(&module_list, mod, entries); 256*3e5d0784SAlexander V. Chernikov KTEST_UNLOCK(); 257*3e5d0784SAlexander V. Chernikov } 258*3e5d0784SAlexander V. Chernikov 259*3e5d0784SAlexander V. Chernikov static void 260*3e5d0784SAlexander V. Chernikov unregister_test_module(struct ktest_module_info *info) 261*3e5d0784SAlexander V. Chernikov { 262*3e5d0784SAlexander V. Chernikov struct ktest_module *mod = info->module_ptr; 263*3e5d0784SAlexander V. Chernikov 264*3e5d0784SAlexander V. Chernikov info->module_ptr = NULL; 265*3e5d0784SAlexander V. Chernikov 266*3e5d0784SAlexander V. Chernikov KTEST_LOCK(); 267*3e5d0784SAlexander V. Chernikov TAILQ_REMOVE(&module_list, mod, entries); 268*3e5d0784SAlexander V. Chernikov KTEST_UNLOCK(); 269*3e5d0784SAlexander V. Chernikov 270*3e5d0784SAlexander V. Chernikov free(mod, M_TEMP); 271*3e5d0784SAlexander V. Chernikov } 272*3e5d0784SAlexander V. Chernikov 273*3e5d0784SAlexander V. Chernikov static bool 274*3e5d0784SAlexander V. Chernikov can_unregister(struct ktest_module_info *info) 275*3e5d0784SAlexander V. Chernikov { 276*3e5d0784SAlexander V. Chernikov struct ktest_module *mod = info->module_ptr; 277*3e5d0784SAlexander V. Chernikov 278*3e5d0784SAlexander V. Chernikov return (refcount_load(&mod->refcount) == 0); 279*3e5d0784SAlexander V. Chernikov } 280*3e5d0784SAlexander V. Chernikov 281*3e5d0784SAlexander V. Chernikov int 282*3e5d0784SAlexander V. Chernikov ktest_default_modevent(module_t mod, int type, void *arg) 283*3e5d0784SAlexander V. Chernikov { 284*3e5d0784SAlexander V. Chernikov struct ktest_module_info *info = (struct ktest_module_info *)arg; 285*3e5d0784SAlexander V. Chernikov int error = 0; 286*3e5d0784SAlexander V. Chernikov 287*3e5d0784SAlexander V. Chernikov switch (type) { 288*3e5d0784SAlexander V. Chernikov case MOD_LOAD: 289*3e5d0784SAlexander V. Chernikov register_test_module(info); 290*3e5d0784SAlexander V. Chernikov break; 291*3e5d0784SAlexander V. Chernikov case MOD_UNLOAD: 292*3e5d0784SAlexander V. Chernikov if (!can_unregister(info)) 293*3e5d0784SAlexander V. Chernikov return (EBUSY); 294*3e5d0784SAlexander V. Chernikov unregister_test_module(info); 295*3e5d0784SAlexander V. Chernikov break; 296*3e5d0784SAlexander V. Chernikov default: 297*3e5d0784SAlexander V. Chernikov error = EOPNOTSUPP; 298*3e5d0784SAlexander V. Chernikov break; 299*3e5d0784SAlexander V. Chernikov } 300*3e5d0784SAlexander V. Chernikov return (error); 301*3e5d0784SAlexander V. Chernikov } 302*3e5d0784SAlexander V. Chernikov 303*3e5d0784SAlexander V. Chernikov bool 304*3e5d0784SAlexander V. Chernikov ktest_start_msg(struct ktest_test_context *ctx) 305*3e5d0784SAlexander V. Chernikov { 306*3e5d0784SAlexander V. Chernikov return (create_reply(ctx->npt->nw, ctx->hdr, KTEST_CMD_NEWMESSAGE)); 307*3e5d0784SAlexander V. Chernikov } 308*3e5d0784SAlexander V. Chernikov 309*3e5d0784SAlexander V. Chernikov void 310*3e5d0784SAlexander V. Chernikov ktest_add_msg_meta(struct ktest_test_context *ctx, const char *func, 311*3e5d0784SAlexander V. Chernikov const char *fname, int line) 312*3e5d0784SAlexander V. Chernikov { 313*3e5d0784SAlexander V. Chernikov struct nl_writer *nw = ctx->npt->nw; 314*3e5d0784SAlexander V. Chernikov struct timespec ts; 315*3e5d0784SAlexander V. Chernikov 316*3e5d0784SAlexander V. Chernikov nanouptime(&ts); 317*3e5d0784SAlexander V. Chernikov nlattr_add(nw, KTEST_MSG_ATTR_TS, sizeof(ts), &ts); 318*3e5d0784SAlexander V. Chernikov 319*3e5d0784SAlexander V. Chernikov nlattr_add_string(nw, KTEST_MSG_ATTR_FUNC, func); 320*3e5d0784SAlexander V. Chernikov nlattr_add_string(nw, KTEST_MSG_ATTR_FILE, fname); 321*3e5d0784SAlexander V. Chernikov nlattr_add_u32(nw, KTEST_MSG_ATTR_LINE, line); 322*3e5d0784SAlexander V. Chernikov } 323*3e5d0784SAlexander V. Chernikov 324*3e5d0784SAlexander V. Chernikov void 325*3e5d0784SAlexander V. Chernikov ktest_add_msg_text(struct ktest_test_context *ctx, int msg_level, 326*3e5d0784SAlexander V. Chernikov const char *fmt, ...) 327*3e5d0784SAlexander V. Chernikov { 328*3e5d0784SAlexander V. Chernikov va_list ap; 329*3e5d0784SAlexander V. Chernikov 330*3e5d0784SAlexander V. Chernikov va_start(ap, fmt); 331*3e5d0784SAlexander V. Chernikov vsnprintf(ctx->buf, ctx->bufsize, fmt, ap); 332*3e5d0784SAlexander V. Chernikov va_end(ap); 333*3e5d0784SAlexander V. Chernikov 334*3e5d0784SAlexander V. Chernikov nlattr_add_u8(ctx->npt->nw, KTEST_MSG_ATTR_LEVEL, msg_level); 335*3e5d0784SAlexander V. Chernikov nlattr_add_string(ctx->npt->nw, KTEST_MSG_ATTR_TEXT, ctx->buf); 336*3e5d0784SAlexander V. Chernikov } 337*3e5d0784SAlexander V. Chernikov 338*3e5d0784SAlexander V. Chernikov void 339*3e5d0784SAlexander V. Chernikov ktest_end_msg(struct ktest_test_context *ctx) 340*3e5d0784SAlexander V. Chernikov { 341*3e5d0784SAlexander V. Chernikov nlmsg_end(ctx->npt->nw); 342*3e5d0784SAlexander V. Chernikov } 343*3e5d0784SAlexander V. Chernikov 344*3e5d0784SAlexander V. Chernikov /* Module glue */ 345*3e5d0784SAlexander V. Chernikov 346*3e5d0784SAlexander V. Chernikov static const struct nlhdr_parser *all_parsers[] = { &ktest_parser }; 347*3e5d0784SAlexander V. Chernikov 348*3e5d0784SAlexander V. Chernikov static const struct genl_cmd ktest_cmds[] = { 349*3e5d0784SAlexander V. Chernikov { 350*3e5d0784SAlexander V. Chernikov .cmd_num = KTEST_CMD_LIST, 351*3e5d0784SAlexander V. Chernikov .cmd_name = "KTEST_CMD_LIST", 352*3e5d0784SAlexander V. Chernikov .cmd_cb = dump_tests, 353*3e5d0784SAlexander V. Chernikov .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL, 354*3e5d0784SAlexander V. Chernikov }, 355*3e5d0784SAlexander V. Chernikov { 356*3e5d0784SAlexander V. Chernikov .cmd_num = KTEST_CMD_RUN, 357*3e5d0784SAlexander V. Chernikov .cmd_name = "KTEST_CMD_RUN", 358*3e5d0784SAlexander V. Chernikov .cmd_cb = run_test, 359*3e5d0784SAlexander V. Chernikov .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL, 360*3e5d0784SAlexander V. Chernikov .cmd_priv = PRIV_KLD_LOAD, 361*3e5d0784SAlexander V. Chernikov }, 362*3e5d0784SAlexander V. Chernikov }; 363*3e5d0784SAlexander V. Chernikov 364*3e5d0784SAlexander V. Chernikov static void 365*3e5d0784SAlexander V. Chernikov ktest_nl_register(void) 366*3e5d0784SAlexander V. Chernikov { 367*3e5d0784SAlexander V. Chernikov bool ret __diagused; 368*3e5d0784SAlexander V. Chernikov int family_id __diagused; 369*3e5d0784SAlexander V. Chernikov 370*3e5d0784SAlexander V. Chernikov NL_VERIFY_PARSERS(all_parsers); 371*3e5d0784SAlexander V. Chernikov family_id = genl_register_family(KTEST_FAMILY_NAME, 0, 1, KTEST_CMD_MAX); 372*3e5d0784SAlexander V. Chernikov MPASS(family_id != 0); 373*3e5d0784SAlexander V. Chernikov 374*3e5d0784SAlexander V. Chernikov ret = genl_register_cmds(KTEST_FAMILY_NAME, ktest_cmds, NL_ARRAY_LEN(ktest_cmds)); 375*3e5d0784SAlexander V. Chernikov MPASS(ret); 376*3e5d0784SAlexander V. Chernikov } 377*3e5d0784SAlexander V. Chernikov 378*3e5d0784SAlexander V. Chernikov static void 379*3e5d0784SAlexander V. Chernikov ktest_nl_unregister(void) 380*3e5d0784SAlexander V. Chernikov { 381*3e5d0784SAlexander V. Chernikov MPASS(TAILQ_EMPTY(&module_list)); 382*3e5d0784SAlexander V. Chernikov 383*3e5d0784SAlexander V. Chernikov genl_unregister_family(KTEST_FAMILY_NAME); 384*3e5d0784SAlexander V. Chernikov } 385*3e5d0784SAlexander V. Chernikov 386*3e5d0784SAlexander V. Chernikov static int 387*3e5d0784SAlexander V. Chernikov ktest_modevent(module_t mod, int type, void *unused) 388*3e5d0784SAlexander V. Chernikov { 389*3e5d0784SAlexander V. Chernikov int error = 0; 390*3e5d0784SAlexander V. Chernikov 391*3e5d0784SAlexander V. Chernikov switch (type) { 392*3e5d0784SAlexander V. Chernikov case MOD_LOAD: 393*3e5d0784SAlexander V. Chernikov ktest_nl_register(); 394*3e5d0784SAlexander V. Chernikov break; 395*3e5d0784SAlexander V. Chernikov case MOD_UNLOAD: 396*3e5d0784SAlexander V. Chernikov ktest_nl_unregister(); 397*3e5d0784SAlexander V. Chernikov break; 398*3e5d0784SAlexander V. Chernikov default: 399*3e5d0784SAlexander V. Chernikov error = EOPNOTSUPP; 400*3e5d0784SAlexander V. Chernikov break; 401*3e5d0784SAlexander V. Chernikov } 402*3e5d0784SAlexander V. Chernikov return (error); 403*3e5d0784SAlexander V. Chernikov } 404*3e5d0784SAlexander V. Chernikov 405*3e5d0784SAlexander V. Chernikov static moduledata_t ktestmod = { 406*3e5d0784SAlexander V. Chernikov "ktest", 407*3e5d0784SAlexander V. Chernikov ktest_modevent, 408*3e5d0784SAlexander V. Chernikov 0 409*3e5d0784SAlexander V. Chernikov }; 410*3e5d0784SAlexander V. Chernikov 411*3e5d0784SAlexander V. Chernikov DECLARE_MODULE(ktestmod, ktestmod, SI_SUB_PSEUDO, SI_ORDER_ANY); 412*3e5d0784SAlexander V. Chernikov MODULE_VERSION(ktestmod, 1); 413*3e5d0784SAlexander V. Chernikov MODULE_DEPEND(ktestmod, netlink, 1, 1, 1); 414*3e5d0784SAlexander V. Chernikov 415