xref: /netbsd-src/sys/rump/kern/lib/libsimplehook_tester/simplehook_tester.c (revision 75d2abaeb1baf9839167f74fdcc44faa66addc35)
1*75d2abaeSandvar /*	$NetBSD: simplehook_tester.c,v 1.2 2022/04/10 09:50:46 andvar Exp $	*/
25256dbbcSyamaguchi /*
35256dbbcSyamaguchi  * Copyright (c) 2021 Internet Initiative Japan Inc.
45256dbbcSyamaguchi  * All rights reserved.
55256dbbcSyamaguchi  *
65256dbbcSyamaguchi  * Redistribution and use in source and binary forms, with or without
75256dbbcSyamaguchi  * modification, are permitted provided that the following conditions
85256dbbcSyamaguchi  * are met:
95256dbbcSyamaguchi  * 1. Redistributions of source code must retain the above copyright
105256dbbcSyamaguchi  *    notice, this list of conditions and the following disclaimer.
115256dbbcSyamaguchi  * 2. Redistributions in binary form must reproduce the above copyright
125256dbbcSyamaguchi  *    notice, this list of conditions and the following disclaimer in the
135256dbbcSyamaguchi  *    documentation and/or other materials provided with the distribution.
145256dbbcSyamaguchi  *
155256dbbcSyamaguchi  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
165256dbbcSyamaguchi  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
175256dbbcSyamaguchi  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
185256dbbcSyamaguchi  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
195256dbbcSyamaguchi  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
205256dbbcSyamaguchi  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
215256dbbcSyamaguchi  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
225256dbbcSyamaguchi  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
235256dbbcSyamaguchi  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
245256dbbcSyamaguchi  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
255256dbbcSyamaguchi  * POSSIBILITY OF SUCH DAMAGE.
265256dbbcSyamaguchi  */
275256dbbcSyamaguchi 
285256dbbcSyamaguchi #include <sys/cdefs.h>
29*75d2abaeSandvar __KERNEL_RCSID(0, "$NetBSD: simplehook_tester.c,v 1.2 2022/04/10 09:50:46 andvar Exp $");
305256dbbcSyamaguchi 
315256dbbcSyamaguchi #include <sys/param.h>
325256dbbcSyamaguchi 
335256dbbcSyamaguchi #include <sys/condvar.h>
345256dbbcSyamaguchi #include <sys/hook.h>
355256dbbcSyamaguchi #include <sys/module.h>
365256dbbcSyamaguchi #include <sys/mutex.h>
375256dbbcSyamaguchi #include <sys/sysctl.h>
385256dbbcSyamaguchi #include <sys/workqueue.h>
395256dbbcSyamaguchi 
405256dbbcSyamaguchi #ifdef SIMPLEHOOK_TESTER_DEBUG
415256dbbcSyamaguchi #define HK_DPRINTF(a)	printf a
425256dbbcSyamaguchi #else
435256dbbcSyamaguchi #define HK_DPRINTF(a)	__nothing
445256dbbcSyamaguchi #endif
455256dbbcSyamaguchi 
465256dbbcSyamaguchi MODULE(MODULE_CLASS_MISC, simplehook_tester, NULL);
475256dbbcSyamaguchi extern int simplehook_tester_init(void);
485256dbbcSyamaguchi struct tester_context;
495256dbbcSyamaguchi 
505256dbbcSyamaguchi struct tester_hook {
515256dbbcSyamaguchi 	struct tester_context	*th_ctx;
525256dbbcSyamaguchi 	khook_t			*th_hook;
535256dbbcSyamaguchi 	size_t			 th_idx;
545256dbbcSyamaguchi 	int			 th_count;
555256dbbcSyamaguchi 	bool			 th_stopping;
565256dbbcSyamaguchi 	bool			 th_stopped;
575256dbbcSyamaguchi 	bool			 th_disestablish;
585256dbbcSyamaguchi };
595256dbbcSyamaguchi 
605256dbbcSyamaguchi static struct tester_context {
615256dbbcSyamaguchi 	kmutex_t		 ctx_mutex;
625256dbbcSyamaguchi 	kcondvar_t		 ctx_cv;
635256dbbcSyamaguchi 	struct sysctllog	*ctx_sysctllog;
645256dbbcSyamaguchi 	struct workqueue	*ctx_wq;
655256dbbcSyamaguchi 	struct work		 ctx_wk;
665256dbbcSyamaguchi 	bool			 ctx_wk_enqueued;
675256dbbcSyamaguchi 	bool			 ctx_wk_waiting;
685256dbbcSyamaguchi 
695256dbbcSyamaguchi 	khook_list_t		*ctx_hooks;
705256dbbcSyamaguchi 	struct tester_hook	 ctx_hook[2];
715256dbbcSyamaguchi 
725256dbbcSyamaguchi 	khook_t			*ctx_nbhook;
735256dbbcSyamaguchi } tester_ctx;
745256dbbcSyamaguchi 
755256dbbcSyamaguchi static int
simplehook_tester_created(SYSCTLFN_ARGS)765256dbbcSyamaguchi simplehook_tester_created(SYSCTLFN_ARGS)
775256dbbcSyamaguchi {
785256dbbcSyamaguchi 	struct sysctlnode node;
795256dbbcSyamaguchi 	struct tester_context *ctx;
805256dbbcSyamaguchi 	int error, val;
815256dbbcSyamaguchi 	size_t i;
825256dbbcSyamaguchi 
835256dbbcSyamaguchi 	node = *rnode;
845256dbbcSyamaguchi 	ctx = node.sysctl_data;
855256dbbcSyamaguchi 
865256dbbcSyamaguchi 	mutex_enter(&ctx->ctx_mutex);
875256dbbcSyamaguchi 	val = ctx->ctx_hooks != NULL ? 1 : 0;
885256dbbcSyamaguchi 	mutex_exit(&ctx->ctx_mutex);
895256dbbcSyamaguchi 
905256dbbcSyamaguchi 	node.sysctl_data = &val;
915256dbbcSyamaguchi 	node.sysctl_size = sizeof(val);
925256dbbcSyamaguchi 
935256dbbcSyamaguchi 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
945256dbbcSyamaguchi 	if (error || newp == NULL)
955256dbbcSyamaguchi 		return error;
965256dbbcSyamaguchi 
975256dbbcSyamaguchi 	if (val != 0 && val != 1)
985256dbbcSyamaguchi 		return EINVAL;
995256dbbcSyamaguchi 
1005256dbbcSyamaguchi 	error = 0;
1015256dbbcSyamaguchi 	mutex_enter(&ctx->ctx_mutex);
1025256dbbcSyamaguchi 	if (val == 1) {
1035256dbbcSyamaguchi 		if (ctx->ctx_hooks != NULL) {
1045256dbbcSyamaguchi 			error = EEXIST;
1055256dbbcSyamaguchi 		} else {
1065256dbbcSyamaguchi 			HK_DPRINTF(("[%s, %d]: create hook list\n",
1075256dbbcSyamaguchi 			    __func__, __LINE__));
1085256dbbcSyamaguchi 			ctx->ctx_hooks = simplehook_create(IPL_NONE,
1095256dbbcSyamaguchi 			    "tester hooks");
1105256dbbcSyamaguchi 			KASSERT(ctx->ctx_hooks != NULL);
1115256dbbcSyamaguchi 		}
1125256dbbcSyamaguchi 	} else {
1135256dbbcSyamaguchi 		if (ctx->ctx_hooks == NULL) {
1145256dbbcSyamaguchi 			error = ENXIO;
1155256dbbcSyamaguchi 		} else if (ctx->ctx_wk_waiting) {
1165256dbbcSyamaguchi 			error = EBUSY;
1175256dbbcSyamaguchi 		} else {
1185256dbbcSyamaguchi 			ctx->ctx_wk_waiting = true;
1195256dbbcSyamaguchi 			mutex_exit(&ctx->ctx_mutex);
1205256dbbcSyamaguchi 
1215256dbbcSyamaguchi 			workqueue_wait(ctx->ctx_wq, &ctx->ctx_wk);
1225256dbbcSyamaguchi 
1235256dbbcSyamaguchi 			mutex_enter(&ctx->ctx_mutex);
1245256dbbcSyamaguchi 			ctx->ctx_wk_waiting = false;
1255256dbbcSyamaguchi 
1265256dbbcSyamaguchi 			HK_DPRINTF(("[%s, %d]: destroy hook list\n",
1275256dbbcSyamaguchi 			    __func__, __LINE__));
1285256dbbcSyamaguchi 			simplehook_destroy(ctx->ctx_hooks);
1295256dbbcSyamaguchi 			ctx->ctx_hooks = NULL;
1305256dbbcSyamaguchi 			ctx->ctx_nbhook = NULL;
1315256dbbcSyamaguchi 			for (i = 0; i < __arraycount(ctx->ctx_hook); i++) {
1325256dbbcSyamaguchi 				ctx->ctx_hook[i].th_hook = NULL;
1335256dbbcSyamaguchi 			}
1345256dbbcSyamaguchi 		}
1355256dbbcSyamaguchi 	}
1365256dbbcSyamaguchi 	mutex_exit(&ctx->ctx_mutex);
1375256dbbcSyamaguchi 
1385256dbbcSyamaguchi 	return error;
1395256dbbcSyamaguchi }
1405256dbbcSyamaguchi 
1415256dbbcSyamaguchi static void
simplehook_tester_work(struct work * wk,void * xctx)1425256dbbcSyamaguchi simplehook_tester_work(struct work *wk, void *xctx)
1435256dbbcSyamaguchi {
1445256dbbcSyamaguchi 	struct tester_context *ctx;
1455256dbbcSyamaguchi 
1465256dbbcSyamaguchi 	ctx = xctx;
1475256dbbcSyamaguchi 
1485256dbbcSyamaguchi 	mutex_enter(&ctx->ctx_mutex);
1495256dbbcSyamaguchi 	ctx->ctx_wk_enqueued = false;
1505256dbbcSyamaguchi 	mutex_exit(&ctx->ctx_mutex);
1515256dbbcSyamaguchi 
1525256dbbcSyamaguchi 	simplehook_dohooks(ctx->ctx_hooks);
1535256dbbcSyamaguchi }
1545256dbbcSyamaguchi 
1555256dbbcSyamaguchi static int
simplehook_tester_dohooks(SYSCTLFN_ARGS)1565256dbbcSyamaguchi simplehook_tester_dohooks(SYSCTLFN_ARGS)
1575256dbbcSyamaguchi {
1585256dbbcSyamaguchi 	struct sysctlnode node;
1595256dbbcSyamaguchi 	struct tester_context *ctx;
1605256dbbcSyamaguchi 	int error, val;
1615256dbbcSyamaguchi 
1625256dbbcSyamaguchi 	node = *rnode;
1635256dbbcSyamaguchi 	ctx = node.sysctl_data;
1645256dbbcSyamaguchi 
1655256dbbcSyamaguchi 	mutex_enter(&ctx->ctx_mutex);
1665256dbbcSyamaguchi 	val = ctx->ctx_wk_enqueued ? 1 : 0;
1675256dbbcSyamaguchi 	mutex_exit(&ctx->ctx_mutex);
1685256dbbcSyamaguchi 
1695256dbbcSyamaguchi 	node.sysctl_data = &val;
1705256dbbcSyamaguchi 	node.sysctl_size = sizeof(val);
1715256dbbcSyamaguchi 
1725256dbbcSyamaguchi 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
1735256dbbcSyamaguchi 	if (error || newp == NULL)
1745256dbbcSyamaguchi 		return error;
1755256dbbcSyamaguchi 
1765256dbbcSyamaguchi 	if (val != 0 && val != 1)
1775256dbbcSyamaguchi 		return EINVAL;
1785256dbbcSyamaguchi 
1795256dbbcSyamaguchi 	mutex_enter(&ctx->ctx_mutex);
1805256dbbcSyamaguchi 	if (val == 1) {
1815256dbbcSyamaguchi 		if (ctx->ctx_wk_enqueued) {
1825256dbbcSyamaguchi 			error = EEXIST;
1835256dbbcSyamaguchi 		} else if (ctx->ctx_wk_waiting) {
1845256dbbcSyamaguchi 			error = EBUSY;
1855256dbbcSyamaguchi 		} else if (ctx->ctx_hooks == NULL) {
1865256dbbcSyamaguchi 			error = ENXIO;
1875256dbbcSyamaguchi 		} else {
1885256dbbcSyamaguchi 			HK_DPRINTF(("[%s, %d]: dohook\n", __func__, __LINE__));
1895256dbbcSyamaguchi 			ctx->ctx_wk_enqueued = true;
1905256dbbcSyamaguchi 			workqueue_enqueue(ctx->ctx_wq,
1915256dbbcSyamaguchi 			    &ctx->ctx_wk, NULL);
1925256dbbcSyamaguchi 		}
1935256dbbcSyamaguchi 	} else {
1945256dbbcSyamaguchi 		if (ctx->ctx_wk_waiting) {
1955256dbbcSyamaguchi 			error = EBUSY;
1965256dbbcSyamaguchi 		} else {
1975256dbbcSyamaguchi 			ctx->ctx_wk_waiting = true;
1985256dbbcSyamaguchi 			mutex_exit(&ctx->ctx_mutex);
1995256dbbcSyamaguchi 
2005256dbbcSyamaguchi 			workqueue_wait(ctx->ctx_wq, &ctx->ctx_wk);
2015256dbbcSyamaguchi 
2025256dbbcSyamaguchi 			mutex_enter(&ctx->ctx_mutex);
2035256dbbcSyamaguchi 			ctx->ctx_wk_waiting = false;
2045256dbbcSyamaguchi 		}
2055256dbbcSyamaguchi 	}
2065256dbbcSyamaguchi 	mutex_exit(&ctx->ctx_mutex);
2075256dbbcSyamaguchi 
2085256dbbcSyamaguchi 	return error;
2095256dbbcSyamaguchi }
2105256dbbcSyamaguchi 
2115256dbbcSyamaguchi static void
simplehook_tester_hook(void * xth)2125256dbbcSyamaguchi simplehook_tester_hook(void *xth)
2135256dbbcSyamaguchi {
2145256dbbcSyamaguchi 	struct tester_context *ctx;
2155256dbbcSyamaguchi 	struct tester_hook *th;
2165256dbbcSyamaguchi 
2175256dbbcSyamaguchi 	th = xth;
2185256dbbcSyamaguchi 	ctx = th->th_ctx;
2195256dbbcSyamaguchi 	mutex_enter(&ctx->ctx_mutex);
2205256dbbcSyamaguchi 
2215256dbbcSyamaguchi 	HK_DPRINTF(("[%s, %d]: hook%zu called\n",
2225256dbbcSyamaguchi 	    __func__, __LINE__, th->th_idx));
2235256dbbcSyamaguchi 
2245256dbbcSyamaguchi 	th->th_stopped = false;
2255256dbbcSyamaguchi 
2265256dbbcSyamaguchi 	while (th->th_stopping) {
2275256dbbcSyamaguchi 		HK_DPRINTF(("[%s, %d]: hook%zu stopping\n",
2285256dbbcSyamaguchi 		    __func__, __LINE__, th->th_idx));
2295256dbbcSyamaguchi 		th->th_stopped = true;
2305256dbbcSyamaguchi 		cv_wait(&ctx->ctx_cv, &ctx->ctx_mutex);
2315256dbbcSyamaguchi 	}
2325256dbbcSyamaguchi 
2335256dbbcSyamaguchi 	if (th->th_stopped) {
2345256dbbcSyamaguchi 		HK_DPRINTF(("[%s, %d]: hook%zu restart\n",
2355256dbbcSyamaguchi 		    __func__, __LINE__, th->th_idx));
2365256dbbcSyamaguchi 		th->th_stopped = false;
2375256dbbcSyamaguchi 	}
2385256dbbcSyamaguchi 
2395256dbbcSyamaguchi 	th->th_count++;
2405256dbbcSyamaguchi 
2415256dbbcSyamaguchi 	if (th->th_disestablish && th->th_hook != NULL) {
242*75d2abaeSandvar 		HK_DPRINTF(("[%s, %d]: disestablish running hook%zu\n",
2435256dbbcSyamaguchi 		    __func__, __LINE__, th->th_idx));
2445256dbbcSyamaguchi 		simplehook_disestablish(ctx->ctx_hooks,
2455256dbbcSyamaguchi 		    th->th_hook, &ctx->ctx_mutex);
2465256dbbcSyamaguchi 		th->th_hook = NULL;
2475256dbbcSyamaguchi 	}
2485256dbbcSyamaguchi 
2495256dbbcSyamaguchi 	HK_DPRINTF(("[%s, %d]: hook%zu exit\n",
2505256dbbcSyamaguchi 	    __func__, __LINE__, th->th_idx));
2515256dbbcSyamaguchi 
2525256dbbcSyamaguchi 	mutex_exit(&ctx->ctx_mutex);
2535256dbbcSyamaguchi }
2545256dbbcSyamaguchi 
2555256dbbcSyamaguchi static void
simplehook_tester_hook_nb(void * xctx)2565256dbbcSyamaguchi simplehook_tester_hook_nb(void *xctx)
2575256dbbcSyamaguchi {
2585256dbbcSyamaguchi 
2595256dbbcSyamaguchi 	HK_DPRINTF(("[%s, %d]: non-block hook called\n",
2605256dbbcSyamaguchi 	    __func__, __LINE__));
2615256dbbcSyamaguchi 
2625256dbbcSyamaguchi 	HK_DPRINTF(("[%s, %d]: sleep 1 sec\n",
2635256dbbcSyamaguchi 	    __func__, __LINE__));
2645256dbbcSyamaguchi 	kpause("smplhk_nb", true, 1 * hz, NULL);
2655256dbbcSyamaguchi 
2665256dbbcSyamaguchi 	HK_DPRINTF(("[%s, %d]: non-block hook exit\n",
2675256dbbcSyamaguchi 	    __func__, __LINE__));
2685256dbbcSyamaguchi }
2695256dbbcSyamaguchi 
2705256dbbcSyamaguchi static int
simplehook_tester_established(SYSCTLFN_ARGS)2715256dbbcSyamaguchi simplehook_tester_established(SYSCTLFN_ARGS)
2725256dbbcSyamaguchi {
2735256dbbcSyamaguchi 	struct sysctlnode node;
2745256dbbcSyamaguchi 	struct tester_context *ctx;
2755256dbbcSyamaguchi 	struct tester_hook *th;
2765256dbbcSyamaguchi 	int val, error;
2775256dbbcSyamaguchi 
2785256dbbcSyamaguchi 	node = *rnode;
2795256dbbcSyamaguchi 	th = node.sysctl_data;
2805256dbbcSyamaguchi 	ctx = th->th_ctx;
2815256dbbcSyamaguchi 
2825256dbbcSyamaguchi 	mutex_enter(&ctx->ctx_mutex);
2835256dbbcSyamaguchi 	val = th->th_hook == NULL ? 0 : 1;
2845256dbbcSyamaguchi 	mutex_exit(&ctx->ctx_mutex);
2855256dbbcSyamaguchi 
2865256dbbcSyamaguchi 	node.sysctl_data = &val;
2875256dbbcSyamaguchi 	node.sysctl_size = sizeof(val);
2885256dbbcSyamaguchi 
2895256dbbcSyamaguchi 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
2905256dbbcSyamaguchi 	if (error || newp == NULL)
2915256dbbcSyamaguchi 		return error;
2925256dbbcSyamaguchi 
2935256dbbcSyamaguchi 	error = 0;
2945256dbbcSyamaguchi 	mutex_enter(&ctx->ctx_mutex);
2955256dbbcSyamaguchi 
2965256dbbcSyamaguchi 	if (val == 1) {
2975256dbbcSyamaguchi 		if (th->th_hook != NULL) {
2985256dbbcSyamaguchi 			error = EEXIST;
2995256dbbcSyamaguchi 		} else {
3005256dbbcSyamaguchi 			th->th_hook = simplehook_establish(ctx->ctx_hooks,
3015256dbbcSyamaguchi 			    simplehook_tester_hook, th);
3025256dbbcSyamaguchi 			KASSERT(th->th_hook != NULL);
3035256dbbcSyamaguchi 			HK_DPRINTF(("[%s, %d]: established hook%zu (%p)\n",
3045256dbbcSyamaguchi 			    __func__, __LINE__, th->th_idx, th->th_hook));
3055256dbbcSyamaguchi 		}
3065256dbbcSyamaguchi 	} else {
3075256dbbcSyamaguchi 		if (th->th_hook == NULL) {
3085256dbbcSyamaguchi 			error = ENXIO;
3095256dbbcSyamaguchi 		} else {
3105256dbbcSyamaguchi 			bool stopped = false;
3115256dbbcSyamaguchi 			if (th->th_stopping) {
3125256dbbcSyamaguchi 				HK_DPRINTF(("[%s, %d]: stopping = false\n",
3135256dbbcSyamaguchi 				    __func__, __LINE__));
3145256dbbcSyamaguchi 				th->th_stopping = false;
3155256dbbcSyamaguchi 				cv_broadcast(&ctx->ctx_cv);
3165256dbbcSyamaguchi 				stopped = true;
3175256dbbcSyamaguchi 			}
3185256dbbcSyamaguchi 			HK_DPRINTF(("[%s, %d]: disestablish hook%zu (%p)\n",
3195256dbbcSyamaguchi 			    __func__, __LINE__, th->th_idx, th->th_hook));
3205256dbbcSyamaguchi 			simplehook_disestablish(ctx->ctx_hooks,
3215256dbbcSyamaguchi 			    th->th_hook, &ctx->ctx_mutex);
3225256dbbcSyamaguchi 			th->th_hook = NULL;
3235256dbbcSyamaguchi 			if (stopped) {
3245256dbbcSyamaguchi 				HK_DPRINTF(("[%s, %d]: disestablished hook%zu\n",
3255256dbbcSyamaguchi 				    __func__, __LINE__, th->th_idx));
3265256dbbcSyamaguchi 			}
3275256dbbcSyamaguchi 		}
3285256dbbcSyamaguchi 	}
3295256dbbcSyamaguchi 
3305256dbbcSyamaguchi 	mutex_exit(&ctx->ctx_mutex);
3315256dbbcSyamaguchi 
3325256dbbcSyamaguchi 	return error;
3335256dbbcSyamaguchi }
3345256dbbcSyamaguchi 
3355256dbbcSyamaguchi static int
simplehook_tester_established_nb(SYSCTLFN_ARGS)3365256dbbcSyamaguchi simplehook_tester_established_nb(SYSCTLFN_ARGS)
3375256dbbcSyamaguchi {
3385256dbbcSyamaguchi 	struct sysctlnode node;
3395256dbbcSyamaguchi 	struct tester_context *ctx;
3405256dbbcSyamaguchi 	int val, error;
3415256dbbcSyamaguchi 
3425256dbbcSyamaguchi 	node = *rnode;
3435256dbbcSyamaguchi 	ctx = node.sysctl_data;
3445256dbbcSyamaguchi 
3455256dbbcSyamaguchi 	mutex_enter(&ctx->ctx_mutex);
3465256dbbcSyamaguchi 	val = ctx->ctx_nbhook == NULL ? 0 : 1;
3475256dbbcSyamaguchi 	mutex_exit(&ctx->ctx_mutex);
3485256dbbcSyamaguchi 
3495256dbbcSyamaguchi 	node.sysctl_data = &val;
3505256dbbcSyamaguchi 	node.sysctl_size = sizeof(val);
3515256dbbcSyamaguchi 
3525256dbbcSyamaguchi 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
3535256dbbcSyamaguchi 	if (error || newp == NULL)
3545256dbbcSyamaguchi 		return error;
3555256dbbcSyamaguchi 
3565256dbbcSyamaguchi 	error = 0;
3575256dbbcSyamaguchi 	mutex_enter(&ctx->ctx_mutex);
3585256dbbcSyamaguchi 
3595256dbbcSyamaguchi 	if (val == 1) {
3605256dbbcSyamaguchi 		if (ctx->ctx_nbhook != NULL) {
3615256dbbcSyamaguchi 			error = EEXIST;
3625256dbbcSyamaguchi 		} else {
3635256dbbcSyamaguchi 			ctx->ctx_nbhook = simplehook_establish(ctx->ctx_hooks,
3645256dbbcSyamaguchi 			    simplehook_tester_hook_nb, ctx);
3655256dbbcSyamaguchi 			KASSERT(ctx->ctx_nbhook != NULL);
3665256dbbcSyamaguchi 			HK_DPRINTF(("[%s, %d]: established nbhook (%p)\n",
3675256dbbcSyamaguchi 			    __func__, __LINE__, ctx->ctx_nbhook));
3685256dbbcSyamaguchi 		}
3695256dbbcSyamaguchi 	} else {
3705256dbbcSyamaguchi 		if (ctx->ctx_nbhook == NULL) {
3715256dbbcSyamaguchi 			error = ENXIO;
3725256dbbcSyamaguchi 		} else {
3735256dbbcSyamaguchi 			HK_DPRINTF(("[%s, %d]: disestablish nbhook (%p)\n",
3745256dbbcSyamaguchi 			    __func__, __LINE__, ctx->ctx_nbhook));
3755256dbbcSyamaguchi 			simplehook_disestablish(ctx->ctx_hooks,
3765256dbbcSyamaguchi 			    ctx->ctx_nbhook, NULL);
3775256dbbcSyamaguchi 			ctx->ctx_nbhook = NULL;
3785256dbbcSyamaguchi 			HK_DPRINTF(("[%s, %d]: disestablished\n",
3795256dbbcSyamaguchi 			    __func__, __LINE__));
3805256dbbcSyamaguchi 		}
3815256dbbcSyamaguchi 	}
3825256dbbcSyamaguchi 
3835256dbbcSyamaguchi 	mutex_exit(&ctx->ctx_mutex);
3845256dbbcSyamaguchi 
3855256dbbcSyamaguchi 	return error;
3865256dbbcSyamaguchi }
3875256dbbcSyamaguchi 
3885256dbbcSyamaguchi static int
simplehook_tester_stopping(SYSCTLFN_ARGS)3895256dbbcSyamaguchi simplehook_tester_stopping(SYSCTLFN_ARGS)
3905256dbbcSyamaguchi {
3915256dbbcSyamaguchi 	struct sysctlnode node;
3925256dbbcSyamaguchi 	struct tester_context *ctx;
3935256dbbcSyamaguchi 	struct tester_hook *th;
3945256dbbcSyamaguchi 	int error;
3955256dbbcSyamaguchi 	bool val;
3965256dbbcSyamaguchi 
3975256dbbcSyamaguchi 	node = *rnode;
3985256dbbcSyamaguchi 	th = node.sysctl_data;
3995256dbbcSyamaguchi 	ctx = th->th_ctx;
4005256dbbcSyamaguchi 
4015256dbbcSyamaguchi 	mutex_enter(&ctx->ctx_mutex);
4025256dbbcSyamaguchi 	val = th->th_stopping;
4035256dbbcSyamaguchi 	mutex_exit(&ctx->ctx_mutex);
4045256dbbcSyamaguchi 
4055256dbbcSyamaguchi 	node.sysctl_data = &val;
4065256dbbcSyamaguchi 	node.sysctl_size = sizeof(val);
4075256dbbcSyamaguchi 
4085256dbbcSyamaguchi 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
4095256dbbcSyamaguchi 	if (error || newp == NULL)
4105256dbbcSyamaguchi 		return error;
4115256dbbcSyamaguchi 
4125256dbbcSyamaguchi 	error = 0;
4135256dbbcSyamaguchi 	mutex_enter(&ctx->ctx_mutex);
4145256dbbcSyamaguchi 	if (val == true && !th->th_stopping) {
4155256dbbcSyamaguchi 		th->th_stopping = true;
4165256dbbcSyamaguchi 	} else if (val == false && th->th_stopping) {
4175256dbbcSyamaguchi 		th->th_stopping = false;
4185256dbbcSyamaguchi 		cv_broadcast(&ctx->ctx_cv);
4195256dbbcSyamaguchi 	}
4205256dbbcSyamaguchi 	mutex_exit(&ctx->ctx_mutex);
4215256dbbcSyamaguchi 
4225256dbbcSyamaguchi 	return error;
4235256dbbcSyamaguchi }
4245256dbbcSyamaguchi 
4255256dbbcSyamaguchi static int
simplehook_tester_stopped(SYSCTLFN_ARGS)4265256dbbcSyamaguchi simplehook_tester_stopped(SYSCTLFN_ARGS)
4275256dbbcSyamaguchi {
4285256dbbcSyamaguchi 	struct sysctlnode node;
4295256dbbcSyamaguchi 	struct tester_context *ctx;
4305256dbbcSyamaguchi 	struct tester_hook *th;
4315256dbbcSyamaguchi 	bool val;
4325256dbbcSyamaguchi 
4335256dbbcSyamaguchi 	node = *rnode;
4345256dbbcSyamaguchi 	th = node.sysctl_data;
4355256dbbcSyamaguchi 	ctx = th->th_ctx;
4365256dbbcSyamaguchi 
4375256dbbcSyamaguchi 	mutex_enter(&ctx->ctx_mutex);
4385256dbbcSyamaguchi 	val = th->th_stopped;
4395256dbbcSyamaguchi 	mutex_exit(&ctx->ctx_mutex);
4405256dbbcSyamaguchi 
4415256dbbcSyamaguchi 	node.sysctl_data = &val;
4425256dbbcSyamaguchi 	node.sysctl_size = sizeof(val);
4435256dbbcSyamaguchi 
4445256dbbcSyamaguchi 	return sysctl_lookup(SYSCTLFN_CALL(&node));
4455256dbbcSyamaguchi }
4465256dbbcSyamaguchi 
4475256dbbcSyamaguchi static int
simplehook_tester_disestablish(SYSCTLFN_ARGS)4485256dbbcSyamaguchi simplehook_tester_disestablish(SYSCTLFN_ARGS)
4495256dbbcSyamaguchi {
4505256dbbcSyamaguchi 	struct sysctlnode node;
4515256dbbcSyamaguchi 	struct tester_context *ctx;
4525256dbbcSyamaguchi 	struct tester_hook *th;
4535256dbbcSyamaguchi 	int error;
4545256dbbcSyamaguchi 	bool val;
4555256dbbcSyamaguchi 
4565256dbbcSyamaguchi 	node = *rnode;
4575256dbbcSyamaguchi 	th = node.sysctl_data;
4585256dbbcSyamaguchi 	ctx = th->th_ctx;
4595256dbbcSyamaguchi 
4605256dbbcSyamaguchi 	mutex_enter(&ctx->ctx_mutex);
4615256dbbcSyamaguchi 	val = th->th_disestablish;
4625256dbbcSyamaguchi 	mutex_exit(&ctx->ctx_mutex);
4635256dbbcSyamaguchi 
4645256dbbcSyamaguchi 	node.sysctl_data = &val;
4655256dbbcSyamaguchi 	node.sysctl_size = sizeof(val);
4665256dbbcSyamaguchi 
4675256dbbcSyamaguchi 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
4685256dbbcSyamaguchi 	if (error || newp == NULL)
4695256dbbcSyamaguchi 		return error;
4705256dbbcSyamaguchi 
4715256dbbcSyamaguchi 	if (val != 0 && val != 1)
4725256dbbcSyamaguchi 		return EINVAL;
4735256dbbcSyamaguchi 
4745256dbbcSyamaguchi 	error = 0;
4755256dbbcSyamaguchi 	mutex_enter(&ctx->ctx_mutex);
4765256dbbcSyamaguchi 	if (val == true && !th->th_disestablish) {
4775256dbbcSyamaguchi 		th->th_disestablish = true;
4785256dbbcSyamaguchi 	} else if (val == false && th->th_disestablish) {
4795256dbbcSyamaguchi 		th->th_disestablish = false;
4805256dbbcSyamaguchi 	}
4815256dbbcSyamaguchi 	mutex_exit(&ctx->ctx_mutex);
4825256dbbcSyamaguchi 
4835256dbbcSyamaguchi 	return 0;
4845256dbbcSyamaguchi }
4855256dbbcSyamaguchi 
4865256dbbcSyamaguchi static int
simplehook_tester_count(SYSCTLFN_ARGS)4875256dbbcSyamaguchi simplehook_tester_count(SYSCTLFN_ARGS)
4885256dbbcSyamaguchi {
4895256dbbcSyamaguchi 	struct sysctlnode node;
4905256dbbcSyamaguchi 	struct tester_context *ctx;
4915256dbbcSyamaguchi 	struct tester_hook *th;
4925256dbbcSyamaguchi 	int error, val;
4935256dbbcSyamaguchi 
4945256dbbcSyamaguchi 	node = *rnode;
4955256dbbcSyamaguchi 	th = node.sysctl_data;
4965256dbbcSyamaguchi 	ctx = th->th_ctx;
4975256dbbcSyamaguchi 
4985256dbbcSyamaguchi 	mutex_enter(&ctx->ctx_mutex);
4995256dbbcSyamaguchi 	val = th->th_count;
5005256dbbcSyamaguchi 	mutex_exit(&ctx->ctx_mutex);
5015256dbbcSyamaguchi 
5025256dbbcSyamaguchi 	node.sysctl_data = &val;
5035256dbbcSyamaguchi 	node.sysctl_size = sizeof(val);
5045256dbbcSyamaguchi 
5055256dbbcSyamaguchi 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
5065256dbbcSyamaguchi 	if (error || newp == NULL)
5075256dbbcSyamaguchi 		return error;
5085256dbbcSyamaguchi 
5095256dbbcSyamaguchi 	mutex_enter(&ctx->ctx_mutex);
5105256dbbcSyamaguchi 	th->th_count = val;
5115256dbbcSyamaguchi 	mutex_exit(&ctx->ctx_mutex);
5125256dbbcSyamaguchi 
5135256dbbcSyamaguchi 	return 0;
5145256dbbcSyamaguchi }
5155256dbbcSyamaguchi 
5165256dbbcSyamaguchi static int
simplehook_tester_create_sysctl(struct tester_context * ctx)5175256dbbcSyamaguchi simplehook_tester_create_sysctl(struct tester_context *ctx)
5185256dbbcSyamaguchi {
5195256dbbcSyamaguchi 	struct sysctllog **log;
5205256dbbcSyamaguchi 	const struct sysctlnode *rnode, *cnode;
5215256dbbcSyamaguchi 	void *ptr;
5225256dbbcSyamaguchi 	char buf[32];
5235256dbbcSyamaguchi 	int error;
5245256dbbcSyamaguchi 	size_t i;
5255256dbbcSyamaguchi 
5265256dbbcSyamaguchi 	log = &ctx->ctx_sysctllog;
5275256dbbcSyamaguchi 	ptr = (void *)ctx;
5285256dbbcSyamaguchi 
5295256dbbcSyamaguchi 	error = sysctl_createv(log, 0, NULL, &rnode, CTLFLAG_PERMANENT,
5305256dbbcSyamaguchi 	    CTLTYPE_NODE, "simplehook_tester",
5315256dbbcSyamaguchi 	    SYSCTL_DESCR("simplehook testing interface"),
5325256dbbcSyamaguchi 	    NULL, 0, NULL, 0, CTL_KERN, CTL_CREATE, CTL_EOL);
5335256dbbcSyamaguchi 	if (error != 0)
5345256dbbcSyamaguchi 		goto bad;
5355256dbbcSyamaguchi 
5365256dbbcSyamaguchi 	error = sysctl_createv(log, 0, &rnode, &cnode,
5375256dbbcSyamaguchi 	    CTLFLAG_PERMANENT, CTLTYPE_NODE, "hook_list",
5385256dbbcSyamaguchi 	    SYSCTL_DESCR("hook list"), NULL, 0, NULL, 0,
5395256dbbcSyamaguchi 	    CTL_CREATE, CTL_EOL);
5405256dbbcSyamaguchi 
5415256dbbcSyamaguchi 	error = sysctl_createv(log, 0, &cnode, NULL,
5425256dbbcSyamaguchi 	    CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT,
5435256dbbcSyamaguchi 	    "created", SYSCTL_DESCR("create and destroy hook list"),
5445256dbbcSyamaguchi 	    simplehook_tester_created, 0, ptr, 0,
5455256dbbcSyamaguchi 	    CTL_CREATE, CTL_EOL);
5465256dbbcSyamaguchi 	if (error != 0)
5475256dbbcSyamaguchi 		goto bad;
5485256dbbcSyamaguchi 
5495256dbbcSyamaguchi 	error = sysctl_createv(log, 0, &cnode, NULL,
5505256dbbcSyamaguchi 	    CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT,
5515256dbbcSyamaguchi 	    "dohooks", SYSCTL_DESCR("do hooks"),
5525256dbbcSyamaguchi 	    simplehook_tester_dohooks, 0, ptr, 0,
5535256dbbcSyamaguchi 	    CTL_CREATE, CTL_EOL);
5545256dbbcSyamaguchi 	if (error != 0)
5555256dbbcSyamaguchi 		goto bad;
5565256dbbcSyamaguchi 
5575256dbbcSyamaguchi 	error = sysctl_createv(log, 0, &rnode, &cnode,
5585256dbbcSyamaguchi 	    CTLFLAG_PERMANENT, CTLTYPE_NODE, "nbhook",
5595256dbbcSyamaguchi 	    SYSCTL_DESCR("non-blocking hook"), NULL, 0, NULL, 0,
5605256dbbcSyamaguchi 	    CTL_CREATE, CTL_EOL);
5615256dbbcSyamaguchi 	if (error != 0)
5625256dbbcSyamaguchi 		goto bad;
5635256dbbcSyamaguchi 
5645256dbbcSyamaguchi 	error = sysctl_createv(log, 0, &cnode, NULL,
5655256dbbcSyamaguchi 	    CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
5665256dbbcSyamaguchi 	    CTLTYPE_INT, "established",
5675256dbbcSyamaguchi 	    SYSCTL_DESCR("establish and disestablish hook"),
5685256dbbcSyamaguchi 	    simplehook_tester_established_nb,
5695256dbbcSyamaguchi 	    0, ptr, 0, CTL_CREATE, CTL_EOL);
5705256dbbcSyamaguchi 	if (error != 0)
5715256dbbcSyamaguchi 		goto bad;
5725256dbbcSyamaguchi 
5735256dbbcSyamaguchi 	for (i = 0; i < __arraycount(ctx->ctx_hook); i++) {
5745256dbbcSyamaguchi 		snprintf(buf, sizeof(buf), "hook%zu", i);
5755256dbbcSyamaguchi 		ptr = (void *)&ctx->ctx_hook[i];
5765256dbbcSyamaguchi 
5775256dbbcSyamaguchi 		error = sysctl_createv(log, 0, &rnode, &cnode,
5785256dbbcSyamaguchi 		    CTLFLAG_PERMANENT, CTLTYPE_NODE, buf,
5795256dbbcSyamaguchi 		    SYSCTL_DESCR("hook information"), NULL, 0, NULL, 0,
5805256dbbcSyamaguchi 		    CTL_CREATE, CTL_EOL);
5815256dbbcSyamaguchi 		if (error != 0)
5825256dbbcSyamaguchi 			goto bad;
5835256dbbcSyamaguchi 
5845256dbbcSyamaguchi 		error = sysctl_createv(log, 0, &cnode, NULL,
5855256dbbcSyamaguchi 		    CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
5865256dbbcSyamaguchi 		    CTLTYPE_INT, "established",
5875256dbbcSyamaguchi 		    SYSCTL_DESCR("establish and disestablish hook"),
5885256dbbcSyamaguchi 		    simplehook_tester_established,
5895256dbbcSyamaguchi 		    0, ptr, 0, CTL_CREATE, CTL_EOL);
5905256dbbcSyamaguchi 		if (error != 0)
5915256dbbcSyamaguchi 			goto bad;
5925256dbbcSyamaguchi 
5935256dbbcSyamaguchi 		error = sysctl_createv(log, 0, &cnode, NULL,
5945256dbbcSyamaguchi 		    CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
5955256dbbcSyamaguchi 		    CTLTYPE_BOOL, "stopping",
5965256dbbcSyamaguchi 		    SYSCTL_DESCR("stopping at beginning of the hook"),
5975256dbbcSyamaguchi 		    simplehook_tester_stopping, 0, ptr, 0,
5985256dbbcSyamaguchi 		    CTL_CREATE, CTL_EOL);
5995256dbbcSyamaguchi 		if (error != 0)
6005256dbbcSyamaguchi 			goto bad;
6015256dbbcSyamaguchi 
6025256dbbcSyamaguchi 		error = sysctl_createv(log, 0, &cnode, NULL,
6035256dbbcSyamaguchi 		    CTLFLAG_PERMANENT|CTLFLAG_READONLY,
6045256dbbcSyamaguchi 		    CTLTYPE_BOOL, "stopped",
6055256dbbcSyamaguchi 		    SYSCTL_DESCR("the hook is stopped"),
6065256dbbcSyamaguchi 		    simplehook_tester_stopped, 0, ptr, 0,
6075256dbbcSyamaguchi 		    CTL_CREATE, CTL_EOL);
6085256dbbcSyamaguchi 		if (error != 0)
6095256dbbcSyamaguchi 			goto bad;
6105256dbbcSyamaguchi 
6115256dbbcSyamaguchi 		error = sysctl_createv(log, 0, &cnode, NULL,
6125256dbbcSyamaguchi 		    CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_BOOL,
6135256dbbcSyamaguchi 		    "disestablish_in_hook",
6145256dbbcSyamaguchi 		    SYSCTL_DESCR("disestablish this hook in it"),
6155256dbbcSyamaguchi 		    simplehook_tester_disestablish, 0, ptr, 0,
6165256dbbcSyamaguchi 		    CTL_CREATE, CTL_EOL);
6175256dbbcSyamaguchi 		if (error != 0)
6185256dbbcSyamaguchi 			goto bad;
6195256dbbcSyamaguchi 
6205256dbbcSyamaguchi 		error = sysctl_createv(log, 0, &cnode, NULL,
6215256dbbcSyamaguchi 		    CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
6225256dbbcSyamaguchi 		    CTLTYPE_INT, "count",
6235256dbbcSyamaguchi 		    SYSCTL_DESCR("the number of calls of the hook"),
6245256dbbcSyamaguchi 		    simplehook_tester_count, 0, ptr, 0,
6255256dbbcSyamaguchi 		    CTL_CREATE, CTL_EOL);
6265256dbbcSyamaguchi 		if (error != 0)
6275256dbbcSyamaguchi 			goto bad;
6285256dbbcSyamaguchi 	}
6295256dbbcSyamaguchi 
6305256dbbcSyamaguchi 	HK_DPRINTF(("[%s, %d]: created sysctls\n", __func__, __LINE__));
6315256dbbcSyamaguchi 	return 0;
6325256dbbcSyamaguchi 
6335256dbbcSyamaguchi bad:
6345256dbbcSyamaguchi 	sysctl_teardown(log);
6355256dbbcSyamaguchi 	return error;
6365256dbbcSyamaguchi }
6375256dbbcSyamaguchi 
6385256dbbcSyamaguchi static void
simplehook_tester_init_ctx(struct tester_context * ctx)6395256dbbcSyamaguchi simplehook_tester_init_ctx(struct tester_context *ctx)
6405256dbbcSyamaguchi {
6415256dbbcSyamaguchi 	size_t i;
6425256dbbcSyamaguchi 
6435256dbbcSyamaguchi 	memset(ctx, 0, sizeof(*ctx));
6445256dbbcSyamaguchi 	mutex_init(&ctx->ctx_mutex, MUTEX_DEFAULT, IPL_NONE);
6455256dbbcSyamaguchi 	workqueue_create(&ctx->ctx_wq, "shook_tester_wq",
6465256dbbcSyamaguchi 	    simplehook_tester_work, ctx, PRI_NONE, IPL_NONE, WQ_MPSAFE);
6475256dbbcSyamaguchi 	cv_init(&ctx->ctx_cv, "simplehook_tester_cv");
6485256dbbcSyamaguchi 
6495256dbbcSyamaguchi 	for (i = 0; i < __arraycount(ctx->ctx_hook); i++) {
6505256dbbcSyamaguchi 		ctx->ctx_hook[i].th_ctx = ctx;
6515256dbbcSyamaguchi 		ctx->ctx_hook[i].th_idx = i;
6525256dbbcSyamaguchi 	}
6535256dbbcSyamaguchi }
6545256dbbcSyamaguchi 
6555256dbbcSyamaguchi 
6565256dbbcSyamaguchi int
simplehook_tester_init(void)6575256dbbcSyamaguchi simplehook_tester_init(void)
6585256dbbcSyamaguchi {
6595256dbbcSyamaguchi 	int error;
6605256dbbcSyamaguchi 
6615256dbbcSyamaguchi 	simplehook_tester_init_ctx(&tester_ctx);
6625256dbbcSyamaguchi 	error = simplehook_tester_create_sysctl(&tester_ctx);
6635256dbbcSyamaguchi 
6645256dbbcSyamaguchi 	return error;
6655256dbbcSyamaguchi }
6665256dbbcSyamaguchi 
6675256dbbcSyamaguchi static int
simplehook_tester_fini(void)6685256dbbcSyamaguchi simplehook_tester_fini(void)
6695256dbbcSyamaguchi {
6705256dbbcSyamaguchi 	struct tester_context *ctx;
6715256dbbcSyamaguchi 	struct tester_hook *th;
6725256dbbcSyamaguchi 	khook_list_t *hooks;
6735256dbbcSyamaguchi 	size_t i;
6745256dbbcSyamaguchi 
6755256dbbcSyamaguchi 	ctx = &tester_ctx;
6765256dbbcSyamaguchi 
6775256dbbcSyamaguchi 	sysctl_teardown(&ctx->ctx_sysctllog);
6785256dbbcSyamaguchi 
6795256dbbcSyamaguchi 	mutex_enter(&ctx->ctx_mutex);
6805256dbbcSyamaguchi 
6815256dbbcSyamaguchi 	hooks = ctx->ctx_hooks;
6825256dbbcSyamaguchi 	ctx->ctx_hooks = NULL;
6835256dbbcSyamaguchi 	ctx->ctx_wk_waiting = true;
6845256dbbcSyamaguchi 
6855256dbbcSyamaguchi 	for (i = 0; i < __arraycount(ctx->ctx_hook); i++) {
6865256dbbcSyamaguchi 		th = &ctx->ctx_hook[i];
6875256dbbcSyamaguchi 		th->th_stopping = false;
6885256dbbcSyamaguchi 	}
6895256dbbcSyamaguchi 	cv_broadcast(&ctx->ctx_cv);
6905256dbbcSyamaguchi 
6915256dbbcSyamaguchi 	mutex_exit(&ctx->ctx_mutex);
6925256dbbcSyamaguchi 
6935256dbbcSyamaguchi 	workqueue_wait(ctx->ctx_wq, &ctx->ctx_wk);
6945256dbbcSyamaguchi 
6955256dbbcSyamaguchi 	workqueue_destroy(ctx->ctx_wq);
6965256dbbcSyamaguchi 	if (hooks != NULL)
6975256dbbcSyamaguchi 		simplehook_destroy(hooks);
6985256dbbcSyamaguchi 	cv_destroy(&ctx->ctx_cv);
6995256dbbcSyamaguchi 	mutex_destroy(&ctx->ctx_mutex);
7005256dbbcSyamaguchi 
7015256dbbcSyamaguchi 	return 0;
7025256dbbcSyamaguchi }
7035256dbbcSyamaguchi 
7045256dbbcSyamaguchi static int
simplehook_tester_modcmd(modcmd_t cmd,void * arg __unused)7055256dbbcSyamaguchi simplehook_tester_modcmd(modcmd_t cmd, void *arg __unused)
7065256dbbcSyamaguchi {
7075256dbbcSyamaguchi 	int error;
7085256dbbcSyamaguchi 
7095256dbbcSyamaguchi 	switch (cmd) {
7105256dbbcSyamaguchi 	case MODULE_CMD_INIT:
7115256dbbcSyamaguchi 		error = simplehook_tester_init();
7125256dbbcSyamaguchi 		break;
7135256dbbcSyamaguchi 
7145256dbbcSyamaguchi 	case MODULE_CMD_FINI:
7155256dbbcSyamaguchi 		error = simplehook_tester_fini();
7165256dbbcSyamaguchi 		break;
7175256dbbcSyamaguchi 
7185256dbbcSyamaguchi 	case MODULE_CMD_STAT:
7195256dbbcSyamaguchi 	default:
7205256dbbcSyamaguchi 		error = ENOTTY;
7215256dbbcSyamaguchi 	}
7225256dbbcSyamaguchi 
7235256dbbcSyamaguchi 	return error;
7245256dbbcSyamaguchi }
725