xref: /freebsd/sys/kern/kern_hhook.c (revision a8d61afdc24f4ba6964d85df11b8452f5151e70f)
1*a8d61afdSLawrence Stewart /*-
2*a8d61afdSLawrence Stewart  * Copyright (c) 2010 Lawrence Stewart <lstewart@freebsd.org>
3*a8d61afdSLawrence Stewart  * Copyright (c) 2010 The FreeBSD Foundation
4*a8d61afdSLawrence Stewart  * All rights reserved.
5*a8d61afdSLawrence Stewart  *
6*a8d61afdSLawrence Stewart  * This software was developed by Lawrence Stewart while studying at the Centre
7*a8d61afdSLawrence Stewart  * for Advanced Internet Architectures, Swinburne University, made possible in
8*a8d61afdSLawrence Stewart  * part by grants from the FreeBSD Foundation and Cisco University Research
9*a8d61afdSLawrence Stewart  * Program Fund at Community Foundation Silicon Valley.
10*a8d61afdSLawrence Stewart  *
11*a8d61afdSLawrence Stewart  * Portions of this software were developed at the Centre for Advanced
12*a8d61afdSLawrence Stewart  * Internet Architectures, Swinburne University of Technology, Melbourne,
13*a8d61afdSLawrence Stewart  * Australia by Lawrence Stewart under sponsorship from the FreeBSD Foundation.
14*a8d61afdSLawrence Stewart  *
15*a8d61afdSLawrence Stewart  * Redistribution and use in source and binary forms, with or without
16*a8d61afdSLawrence Stewart  * modification, are permitted provided that the following conditions
17*a8d61afdSLawrence Stewart  * are met:
18*a8d61afdSLawrence Stewart  * 1. Redistributions of source code must retain the above copyright
19*a8d61afdSLawrence Stewart  *    notice, this list of conditions and the following disclaimer.
20*a8d61afdSLawrence Stewart  * 2. Redistributions in binary form must reproduce the above copyright
21*a8d61afdSLawrence Stewart  *    notice, this list of conditions and the following disclaimer in the
22*a8d61afdSLawrence Stewart  *    documentation and/or other materials provided with the distribution.
23*a8d61afdSLawrence Stewart  *
24*a8d61afdSLawrence Stewart  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
25*a8d61afdSLawrence Stewart  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26*a8d61afdSLawrence Stewart  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27*a8d61afdSLawrence Stewart  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
28*a8d61afdSLawrence Stewart  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29*a8d61afdSLawrence Stewart  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30*a8d61afdSLawrence Stewart  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31*a8d61afdSLawrence Stewart  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32*a8d61afdSLawrence Stewart  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33*a8d61afdSLawrence Stewart  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34*a8d61afdSLawrence Stewart  * SUCH DAMAGE.
35*a8d61afdSLawrence Stewart  */
36*a8d61afdSLawrence Stewart 
37*a8d61afdSLawrence Stewart #include <sys/cdefs.h>
38*a8d61afdSLawrence Stewart __FBSDID("$FreeBSD$");
39*a8d61afdSLawrence Stewart 
40*a8d61afdSLawrence Stewart #include <sys/param.h>
41*a8d61afdSLawrence Stewart #include <sys/kernel.h>
42*a8d61afdSLawrence Stewart #include <sys/hhook.h>
43*a8d61afdSLawrence Stewart #include <sys/khelp.h>
44*a8d61afdSLawrence Stewart #include <sys/malloc.h>
45*a8d61afdSLawrence Stewart #include <sys/module.h>
46*a8d61afdSLawrence Stewart #include <sys/module_khelp.h>
47*a8d61afdSLawrence Stewart #include <sys/osd.h>
48*a8d61afdSLawrence Stewart #include <sys/queue.h>
49*a8d61afdSLawrence Stewart #include <sys/refcount.h>
50*a8d61afdSLawrence Stewart #include <sys/systm.h>
51*a8d61afdSLawrence Stewart 
52*a8d61afdSLawrence Stewart #include <net/vnet.h>
53*a8d61afdSLawrence Stewart 
54*a8d61afdSLawrence Stewart struct hhook {
55*a8d61afdSLawrence Stewart 	hhook_func_t		hhk_func;
56*a8d61afdSLawrence Stewart 	struct helper		*hhk_helper;
57*a8d61afdSLawrence Stewart 	void			*hhk_udata;
58*a8d61afdSLawrence Stewart 	STAILQ_ENTRY(hhook)	hhk_next;
59*a8d61afdSLawrence Stewart };
60*a8d61afdSLawrence Stewart 
61*a8d61afdSLawrence Stewart MALLOC_DECLARE(M_HHOOK);
62*a8d61afdSLawrence Stewart MALLOC_DEFINE(M_HHOOK, "hhook", "Helper hooks are linked off hhook_head lists");
63*a8d61afdSLawrence Stewart 
64*a8d61afdSLawrence Stewart LIST_HEAD(hhookheadhead, hhook_head);
65*a8d61afdSLawrence Stewart VNET_DEFINE(struct hhookheadhead, hhook_head_list);
66*a8d61afdSLawrence Stewart #define	V_hhook_head_list VNET(hhook_head_list)
67*a8d61afdSLawrence Stewart 
68*a8d61afdSLawrence Stewart static struct mtx hhook_head_list_lock;
69*a8d61afdSLawrence Stewart MTX_SYSINIT(hhookheadlistlock, &hhook_head_list_lock, "hhook_head list lock",
70*a8d61afdSLawrence Stewart     MTX_DEF);
71*a8d61afdSLawrence Stewart 
72*a8d61afdSLawrence Stewart /* Private function prototypes. */
73*a8d61afdSLawrence Stewart static void hhook_head_destroy(struct hhook_head *hhh);
74*a8d61afdSLawrence Stewart 
75*a8d61afdSLawrence Stewart #define	HHHLIST_LOCK() mtx_lock(&hhook_head_list_lock)
76*a8d61afdSLawrence Stewart #define	HHHLIST_UNLOCK() mtx_unlock(&hhook_head_list_lock)
77*a8d61afdSLawrence Stewart #define	HHHLIST_LOCK_ASSERT() mtx_assert(&hhook_head_list_lock, MA_OWNED)
78*a8d61afdSLawrence Stewart 
79*a8d61afdSLawrence Stewart #define	HHH_LOCK_INIT(hhh) rm_init(&(hhh)->hhh_lock, "hhook_head rm lock")
80*a8d61afdSLawrence Stewart #define	HHH_LOCK_DESTROY(hhh) rm_destroy(&(hhh)->hhh_lock)
81*a8d61afdSLawrence Stewart #define	HHH_WLOCK(hhh) rm_wlock(&(hhh)->hhh_lock)
82*a8d61afdSLawrence Stewart #define	HHH_WUNLOCK(hhh) rm_wunlock(&(hhh)->hhh_lock)
83*a8d61afdSLawrence Stewart #define	HHH_RLOCK(hhh, rmpt) rm_rlock(&(hhh)->hhh_lock, (rmpt))
84*a8d61afdSLawrence Stewart #define	HHH_RUNLOCK(hhh, rmpt) rm_runlock(&(hhh)->hhh_lock, (rmpt))
85*a8d61afdSLawrence Stewart 
86*a8d61afdSLawrence Stewart /*
87*a8d61afdSLawrence Stewart  * Run all helper hook functions for a given hook point.
88*a8d61afdSLawrence Stewart  */
89*a8d61afdSLawrence Stewart void
90*a8d61afdSLawrence Stewart hhook_run_hooks(struct hhook_head *hhh, void *ctx_data, struct osd *hosd)
91*a8d61afdSLawrence Stewart {
92*a8d61afdSLawrence Stewart 	struct hhook *hhk;
93*a8d61afdSLawrence Stewart 	void *hdata;
94*a8d61afdSLawrence Stewart 	struct rm_priotracker rmpt;
95*a8d61afdSLawrence Stewart 
96*a8d61afdSLawrence Stewart 	KASSERT(hhh->hhh_refcount > 0, ("hhook_head %p refcount is 0", hhh));
97*a8d61afdSLawrence Stewart 
98*a8d61afdSLawrence Stewart 	HHH_RLOCK(hhh, &rmpt);
99*a8d61afdSLawrence Stewart 	STAILQ_FOREACH(hhk, &hhh->hhh_hooks, hhk_next) {
100*a8d61afdSLawrence Stewart 		if (hhk->hhk_helper->h_flags & HELPER_NEEDS_OSD) {
101*a8d61afdSLawrence Stewart 			hdata = osd_get(OSD_KHELP, hosd, hhk->hhk_helper->h_id);
102*a8d61afdSLawrence Stewart 			if (hdata == NULL)
103*a8d61afdSLawrence Stewart 				continue;
104*a8d61afdSLawrence Stewart 		} else
105*a8d61afdSLawrence Stewart 			hdata = NULL;
106*a8d61afdSLawrence Stewart 
107*a8d61afdSLawrence Stewart 		/*
108*a8d61afdSLawrence Stewart 		 * XXXLAS: We currently ignore the int returned by the hook,
109*a8d61afdSLawrence Stewart 		 * but will likely want to handle it in future to allow hhook to
110*a8d61afdSLawrence Stewart 		 * be used like pfil and effect changes at the hhook calling
111*a8d61afdSLawrence Stewart 		 * site e.g. we could define a new hook type of HHOOK_TYPE_PFIL
112*a8d61afdSLawrence Stewart 		 * and standardise what particular return values mean and set
113*a8d61afdSLawrence Stewart 		 * the context data to pass exactly the same information as pfil
114*a8d61afdSLawrence Stewart 		 * hooks currently receive, thus replicating pfil with hhook.
115*a8d61afdSLawrence Stewart 		 */
116*a8d61afdSLawrence Stewart 		hhk->hhk_func(hhh->hhh_type, hhh->hhh_id, hhk->hhk_udata,
117*a8d61afdSLawrence Stewart 		    ctx_data, hdata, hosd);
118*a8d61afdSLawrence Stewart 	}
119*a8d61afdSLawrence Stewart 	HHH_RUNLOCK(hhh, &rmpt);
120*a8d61afdSLawrence Stewart }
121*a8d61afdSLawrence Stewart 
122*a8d61afdSLawrence Stewart /*
123*a8d61afdSLawrence Stewart  * Register a new helper hook function with a helper hook point.
124*a8d61afdSLawrence Stewart  */
125*a8d61afdSLawrence Stewart int
126*a8d61afdSLawrence Stewart hhook_add_hook(struct hhook_head *hhh, struct hookinfo *hki, uint32_t flags)
127*a8d61afdSLawrence Stewart {
128*a8d61afdSLawrence Stewart 	struct hhook *hhk, *tmp;
129*a8d61afdSLawrence Stewart 	int error;
130*a8d61afdSLawrence Stewart 
131*a8d61afdSLawrence Stewart 	error = 0;
132*a8d61afdSLawrence Stewart 
133*a8d61afdSLawrence Stewart 	if (hhh == NULL)
134*a8d61afdSLawrence Stewart 		return (ENOENT);
135*a8d61afdSLawrence Stewart 
136*a8d61afdSLawrence Stewart 	hhk = malloc(sizeof(struct hhook), M_HHOOK,
137*a8d61afdSLawrence Stewart 	    M_ZERO | ((flags & HHOOK_WAITOK) ? M_WAITOK : M_NOWAIT));
138*a8d61afdSLawrence Stewart 
139*a8d61afdSLawrence Stewart 	if (hhk == NULL)
140*a8d61afdSLawrence Stewart 		return (ENOMEM);
141*a8d61afdSLawrence Stewart 
142*a8d61afdSLawrence Stewart 	hhk->hhk_helper = hki->hook_helper;
143*a8d61afdSLawrence Stewart 	hhk->hhk_func = hki->hook_func;
144*a8d61afdSLawrence Stewart 	hhk->hhk_udata = hki->hook_udata;
145*a8d61afdSLawrence Stewart 
146*a8d61afdSLawrence Stewart 	HHH_WLOCK(hhh);
147*a8d61afdSLawrence Stewart 	STAILQ_FOREACH(tmp, &hhh->hhh_hooks, hhk_next) {
148*a8d61afdSLawrence Stewart 		if (tmp->hhk_func == hki->hook_func &&
149*a8d61afdSLawrence Stewart 		    tmp->hhk_udata == hki->hook_udata) {
150*a8d61afdSLawrence Stewart 			/* The helper hook function is already registered. */
151*a8d61afdSLawrence Stewart 			error = EEXIST;
152*a8d61afdSLawrence Stewart 			break;
153*a8d61afdSLawrence Stewart 		}
154*a8d61afdSLawrence Stewart 	}
155*a8d61afdSLawrence Stewart 
156*a8d61afdSLawrence Stewart 	if (!error) {
157*a8d61afdSLawrence Stewart 		STAILQ_INSERT_TAIL(&hhh->hhh_hooks, hhk, hhk_next);
158*a8d61afdSLawrence Stewart 		hhh->hhh_nhooks++;
159*a8d61afdSLawrence Stewart 	}
160*a8d61afdSLawrence Stewart 	else
161*a8d61afdSLawrence Stewart 		free(hhk, M_HHOOK);
162*a8d61afdSLawrence Stewart 
163*a8d61afdSLawrence Stewart 	HHH_WUNLOCK(hhh);
164*a8d61afdSLawrence Stewart 
165*a8d61afdSLawrence Stewart 	return (error);
166*a8d61afdSLawrence Stewart }
167*a8d61afdSLawrence Stewart 
168*a8d61afdSLawrence Stewart /*
169*a8d61afdSLawrence Stewart  * Lookup a helper hook point and register a new helper hook function with it.
170*a8d61afdSLawrence Stewart  */
171*a8d61afdSLawrence Stewart int
172*a8d61afdSLawrence Stewart hhook_add_hook_lookup(struct hookinfo *hki, uint32_t flags)
173*a8d61afdSLawrence Stewart {
174*a8d61afdSLawrence Stewart 	struct hhook_head *hhh;
175*a8d61afdSLawrence Stewart 	int error;
176*a8d61afdSLawrence Stewart 
177*a8d61afdSLawrence Stewart 	hhh = hhook_head_get(hki->hook_type, hki->hook_id);
178*a8d61afdSLawrence Stewart 
179*a8d61afdSLawrence Stewart 	if (hhh == NULL)
180*a8d61afdSLawrence Stewart 		return (ENOENT);
181*a8d61afdSLawrence Stewart 
182*a8d61afdSLawrence Stewart 	error = hhook_add_hook(hhh, hki, flags);
183*a8d61afdSLawrence Stewart 	hhook_head_release(hhh);
184*a8d61afdSLawrence Stewart 
185*a8d61afdSLawrence Stewart 	return (error);
186*a8d61afdSLawrence Stewart }
187*a8d61afdSLawrence Stewart 
188*a8d61afdSLawrence Stewart /*
189*a8d61afdSLawrence Stewart  * Remove a helper hook function from a helper hook point.
190*a8d61afdSLawrence Stewart  */
191*a8d61afdSLawrence Stewart int
192*a8d61afdSLawrence Stewart hhook_remove_hook(struct hhook_head *hhh, struct hookinfo *hki)
193*a8d61afdSLawrence Stewart {
194*a8d61afdSLawrence Stewart 	struct hhook *tmp;
195*a8d61afdSLawrence Stewart 
196*a8d61afdSLawrence Stewart 	if (hhh == NULL)
197*a8d61afdSLawrence Stewart 		return (ENOENT);
198*a8d61afdSLawrence Stewart 
199*a8d61afdSLawrence Stewart 	HHH_WLOCK(hhh);
200*a8d61afdSLawrence Stewart 	STAILQ_FOREACH(tmp, &hhh->hhh_hooks, hhk_next) {
201*a8d61afdSLawrence Stewart 		if (tmp->hhk_func == hki->hook_func &&
202*a8d61afdSLawrence Stewart 		    tmp->hhk_udata == hki->hook_udata) {
203*a8d61afdSLawrence Stewart 			STAILQ_REMOVE(&hhh->hhh_hooks, tmp, hhook, hhk_next);
204*a8d61afdSLawrence Stewart 			free(tmp, M_HHOOK);
205*a8d61afdSLawrence Stewart 			hhh->hhh_nhooks--;
206*a8d61afdSLawrence Stewart 			break;
207*a8d61afdSLawrence Stewart 		}
208*a8d61afdSLawrence Stewart 	}
209*a8d61afdSLawrence Stewart 	HHH_WUNLOCK(hhh);
210*a8d61afdSLawrence Stewart 
211*a8d61afdSLawrence Stewart 	return (0);
212*a8d61afdSLawrence Stewart }
213*a8d61afdSLawrence Stewart 
214*a8d61afdSLawrence Stewart /*
215*a8d61afdSLawrence Stewart  * Lookup a helper hook point and remove a helper hook function from it.
216*a8d61afdSLawrence Stewart  */
217*a8d61afdSLawrence Stewart int
218*a8d61afdSLawrence Stewart hhook_remove_hook_lookup(struct hookinfo *hki)
219*a8d61afdSLawrence Stewart {
220*a8d61afdSLawrence Stewart 	struct hhook_head *hhh;
221*a8d61afdSLawrence Stewart 
222*a8d61afdSLawrence Stewart 	hhh = hhook_head_get(hki->hook_type, hki->hook_id);
223*a8d61afdSLawrence Stewart 
224*a8d61afdSLawrence Stewart 	if (hhh == NULL)
225*a8d61afdSLawrence Stewart 		return (ENOENT);
226*a8d61afdSLawrence Stewart 
227*a8d61afdSLawrence Stewart 	hhook_remove_hook(hhh, hki);
228*a8d61afdSLawrence Stewart 	hhook_head_release(hhh);
229*a8d61afdSLawrence Stewart 
230*a8d61afdSLawrence Stewart 	return (0);
231*a8d61afdSLawrence Stewart }
232*a8d61afdSLawrence Stewart 
233*a8d61afdSLawrence Stewart /*
234*a8d61afdSLawrence Stewart  * Register a new helper hook point.
235*a8d61afdSLawrence Stewart  */
236*a8d61afdSLawrence Stewart int
237*a8d61afdSLawrence Stewart hhook_head_register(int32_t hhook_type, int32_t hhook_id, struct hhook_head **hhh,
238*a8d61afdSLawrence Stewart     uint32_t flags)
239*a8d61afdSLawrence Stewart {
240*a8d61afdSLawrence Stewart 	struct hhook_head *tmphhh;
241*a8d61afdSLawrence Stewart 
242*a8d61afdSLawrence Stewart 	tmphhh = hhook_head_get(hhook_type, hhook_id);
243*a8d61afdSLawrence Stewart 
244*a8d61afdSLawrence Stewart 	if (tmphhh != NULL) {
245*a8d61afdSLawrence Stewart 		/* Hook point previously registered. */
246*a8d61afdSLawrence Stewart 		hhook_head_release(tmphhh);
247*a8d61afdSLawrence Stewart 		return (EEXIST);
248*a8d61afdSLawrence Stewart 	}
249*a8d61afdSLawrence Stewart 
250*a8d61afdSLawrence Stewart 	/* XXXLAS: Need to implement support for non-virtualised hooks. */
251*a8d61afdSLawrence Stewart 	if ((flags & HHOOK_HEADISINVNET) == 0) {
252*a8d61afdSLawrence Stewart 		printf("%s: only vnet-style virtualised hooks can be used\n",
253*a8d61afdSLawrence Stewart 		    __func__);
254*a8d61afdSLawrence Stewart 		return (EINVAL);
255*a8d61afdSLawrence Stewart 	}
256*a8d61afdSLawrence Stewart 
257*a8d61afdSLawrence Stewart 	tmphhh = malloc(sizeof(struct hhook_head), M_HHOOK,
258*a8d61afdSLawrence Stewart 	    M_ZERO | ((flags & HHOOK_WAITOK) ? M_WAITOK : M_NOWAIT));
259*a8d61afdSLawrence Stewart 
260*a8d61afdSLawrence Stewart 	if (tmphhh == NULL)
261*a8d61afdSLawrence Stewart 		return (ENOMEM);
262*a8d61afdSLawrence Stewart 
263*a8d61afdSLawrence Stewart 	tmphhh->hhh_type = hhook_type;
264*a8d61afdSLawrence Stewart 	tmphhh->hhh_id = hhook_id;
265*a8d61afdSLawrence Stewart 	tmphhh->hhh_nhooks = 0;
266*a8d61afdSLawrence Stewart 	STAILQ_INIT(&tmphhh->hhh_hooks);
267*a8d61afdSLawrence Stewart 	HHH_LOCK_INIT(tmphhh);
268*a8d61afdSLawrence Stewart 
269*a8d61afdSLawrence Stewart 	if (hhh != NULL)
270*a8d61afdSLawrence Stewart 		refcount_init(&tmphhh->hhh_refcount, 1);
271*a8d61afdSLawrence Stewart 	else
272*a8d61afdSLawrence Stewart 		refcount_init(&tmphhh->hhh_refcount, 0);
273*a8d61afdSLawrence Stewart 
274*a8d61afdSLawrence Stewart 	if (flags & HHOOK_HEADISINVNET) {
275*a8d61afdSLawrence Stewart 		tmphhh->hhh_flags |= HHH_ISINVNET;
276*a8d61afdSLawrence Stewart 		HHHLIST_LOCK();
277*a8d61afdSLawrence Stewart 		LIST_INSERT_HEAD(&V_hhook_head_list, tmphhh, hhh_next);
278*a8d61afdSLawrence Stewart 		HHHLIST_UNLOCK();
279*a8d61afdSLawrence Stewart 	} else {
280*a8d61afdSLawrence Stewart 		/* XXXLAS: Add tmphhh to the non-virtualised list. */
281*a8d61afdSLawrence Stewart 	}
282*a8d61afdSLawrence Stewart 
283*a8d61afdSLawrence Stewart 	*hhh = tmphhh;
284*a8d61afdSLawrence Stewart 
285*a8d61afdSLawrence Stewart 	return (0);
286*a8d61afdSLawrence Stewart }
287*a8d61afdSLawrence Stewart 
288*a8d61afdSLawrence Stewart static void
289*a8d61afdSLawrence Stewart hhook_head_destroy(struct hhook_head *hhh)
290*a8d61afdSLawrence Stewart {
291*a8d61afdSLawrence Stewart 	struct hhook *tmp, *tmp2;
292*a8d61afdSLawrence Stewart 
293*a8d61afdSLawrence Stewart 	HHHLIST_LOCK_ASSERT();
294*a8d61afdSLawrence Stewart 
295*a8d61afdSLawrence Stewart 	LIST_REMOVE(hhh, hhh_next);
296*a8d61afdSLawrence Stewart 	HHH_WLOCK(hhh);
297*a8d61afdSLawrence Stewart 	STAILQ_FOREACH_SAFE(tmp, &hhh->hhh_hooks, hhk_next, tmp2)
298*a8d61afdSLawrence Stewart 		free(tmp, M_HHOOK);
299*a8d61afdSLawrence Stewart 	HHH_WUNLOCK(hhh);
300*a8d61afdSLawrence Stewart 	HHH_LOCK_DESTROY(hhh);
301*a8d61afdSLawrence Stewart 	free(hhh, M_HHOOK);
302*a8d61afdSLawrence Stewart }
303*a8d61afdSLawrence Stewart 
304*a8d61afdSLawrence Stewart /*
305*a8d61afdSLawrence Stewart  * Remove a helper hook point.
306*a8d61afdSLawrence Stewart  */
307*a8d61afdSLawrence Stewart int
308*a8d61afdSLawrence Stewart hhook_head_deregister(struct hhook_head *hhh)
309*a8d61afdSLawrence Stewart {
310*a8d61afdSLawrence Stewart 	int error;
311*a8d61afdSLawrence Stewart 
312*a8d61afdSLawrence Stewart 	error = 0;
313*a8d61afdSLawrence Stewart 
314*a8d61afdSLawrence Stewart 	HHHLIST_LOCK();
315*a8d61afdSLawrence Stewart 	if (hhh == NULL)
316*a8d61afdSLawrence Stewart 		error = ENOENT;
317*a8d61afdSLawrence Stewart 	else if (hhh->hhh_refcount > 1)
318*a8d61afdSLawrence Stewart 		error = EBUSY;
319*a8d61afdSLawrence Stewart 	else
320*a8d61afdSLawrence Stewart 		hhook_head_destroy(hhh);
321*a8d61afdSLawrence Stewart 	HHHLIST_UNLOCK();
322*a8d61afdSLawrence Stewart 
323*a8d61afdSLawrence Stewart 	return (error);
324*a8d61afdSLawrence Stewart }
325*a8d61afdSLawrence Stewart 
326*a8d61afdSLawrence Stewart /*
327*a8d61afdSLawrence Stewart  * Remove a helper hook point via a hhook_head lookup.
328*a8d61afdSLawrence Stewart  */
329*a8d61afdSLawrence Stewart int
330*a8d61afdSLawrence Stewart hhook_head_deregister_lookup(int32_t hhook_type, int32_t hhook_id)
331*a8d61afdSLawrence Stewart {
332*a8d61afdSLawrence Stewart 	struct hhook_head *hhh;
333*a8d61afdSLawrence Stewart 	int error;
334*a8d61afdSLawrence Stewart 
335*a8d61afdSLawrence Stewart 	error = 0;
336*a8d61afdSLawrence Stewart 	hhh = hhook_head_get(hhook_type, hhook_id);
337*a8d61afdSLawrence Stewart 	error = hhook_head_deregister(hhh);
338*a8d61afdSLawrence Stewart 
339*a8d61afdSLawrence Stewart 	if (error == EBUSY)
340*a8d61afdSLawrence Stewart 		hhook_head_release(hhh);
341*a8d61afdSLawrence Stewart 
342*a8d61afdSLawrence Stewart 	return (error);
343*a8d61afdSLawrence Stewart }
344*a8d61afdSLawrence Stewart 
345*a8d61afdSLawrence Stewart /*
346*a8d61afdSLawrence Stewart  * Lookup and return the hhook_head struct associated with the specified type
347*a8d61afdSLawrence Stewart  * and id, or NULL if not found. If found, the hhook_head's refcount is bumped.
348*a8d61afdSLawrence Stewart  */
349*a8d61afdSLawrence Stewart struct hhook_head *
350*a8d61afdSLawrence Stewart hhook_head_get(int32_t hhook_type, int32_t hhook_id)
351*a8d61afdSLawrence Stewart {
352*a8d61afdSLawrence Stewart 	struct hhook_head *hhh;
353*a8d61afdSLawrence Stewart 
354*a8d61afdSLawrence Stewart 	/* XXXLAS: Pick hhook_head_list based on hhook_head flags. */
355*a8d61afdSLawrence Stewart 	HHHLIST_LOCK();
356*a8d61afdSLawrence Stewart 	LIST_FOREACH(hhh, &V_hhook_head_list, hhh_next) {
357*a8d61afdSLawrence Stewart 		if (hhh->hhh_type == hhook_type && hhh->hhh_id == hhook_id) {
358*a8d61afdSLawrence Stewart 			refcount_acquire(&hhh->hhh_refcount);
359*a8d61afdSLawrence Stewart 			HHHLIST_UNLOCK();
360*a8d61afdSLawrence Stewart 			return (hhh);
361*a8d61afdSLawrence Stewart 		}
362*a8d61afdSLawrence Stewart 	}
363*a8d61afdSLawrence Stewart 	HHHLIST_UNLOCK();
364*a8d61afdSLawrence Stewart 
365*a8d61afdSLawrence Stewart 	return (NULL);
366*a8d61afdSLawrence Stewart }
367*a8d61afdSLawrence Stewart 
368*a8d61afdSLawrence Stewart void
369*a8d61afdSLawrence Stewart hhook_head_release(struct hhook_head *hhh)
370*a8d61afdSLawrence Stewart {
371*a8d61afdSLawrence Stewart 
372*a8d61afdSLawrence Stewart 	refcount_release(&hhh->hhh_refcount);
373*a8d61afdSLawrence Stewart }
374*a8d61afdSLawrence Stewart 
375*a8d61afdSLawrence Stewart /*
376*a8d61afdSLawrence Stewart  * Check the hhook_head private flags and return the appropriate public
377*a8d61afdSLawrence Stewart  * representation of the flag to the caller. The function is implemented in a
378*a8d61afdSLawrence Stewart  * way that allows us to cope with other subsystems becoming virtualised in the
379*a8d61afdSLawrence Stewart  * future.
380*a8d61afdSLawrence Stewart  */
381*a8d61afdSLawrence Stewart uint32_t
382*a8d61afdSLawrence Stewart hhook_head_is_virtualised(struct hhook_head *hhh)
383*a8d61afdSLawrence Stewart {
384*a8d61afdSLawrence Stewart 	uint32_t ret;
385*a8d61afdSLawrence Stewart 
386*a8d61afdSLawrence Stewart 	if (hhh == NULL)
387*a8d61afdSLawrence Stewart 		return (0);
388*a8d61afdSLawrence Stewart 
389*a8d61afdSLawrence Stewart 	if (hhh->hhh_flags & HHH_ISINVNET)
390*a8d61afdSLawrence Stewart 		ret = HHOOK_HEADISINVNET;
391*a8d61afdSLawrence Stewart 
392*a8d61afdSLawrence Stewart 	return (ret);
393*a8d61afdSLawrence Stewart }
394*a8d61afdSLawrence Stewart 
395*a8d61afdSLawrence Stewart uint32_t
396*a8d61afdSLawrence Stewart hhook_head_is_virtualised_lookup(int32_t hook_type, int32_t hook_id)
397*a8d61afdSLawrence Stewart {
398*a8d61afdSLawrence Stewart 	struct hhook_head *hhh;
399*a8d61afdSLawrence Stewart 	uint32_t ret;
400*a8d61afdSLawrence Stewart 
401*a8d61afdSLawrence Stewart 	hhh = hhook_head_get(hook_type, hook_id);
402*a8d61afdSLawrence Stewart 
403*a8d61afdSLawrence Stewart 	if (hhh == NULL)
404*a8d61afdSLawrence Stewart 		return (0);
405*a8d61afdSLawrence Stewart 
406*a8d61afdSLawrence Stewart 	ret = hhook_head_is_virtualised(hhh);
407*a8d61afdSLawrence Stewart 	hhook_head_release(hhh);
408*a8d61afdSLawrence Stewart 
409*a8d61afdSLawrence Stewart 	return (ret);
410*a8d61afdSLawrence Stewart }
411*a8d61afdSLawrence Stewart 
412*a8d61afdSLawrence Stewart /*
413*a8d61afdSLawrence Stewart  * Vnet created and being initialised.
414*a8d61afdSLawrence Stewart  */
415*a8d61afdSLawrence Stewart static void
416*a8d61afdSLawrence Stewart hhook_vnet_init(const void *unused __unused)
417*a8d61afdSLawrence Stewart {
418*a8d61afdSLawrence Stewart 
419*a8d61afdSLawrence Stewart 	LIST_INIT(&V_hhook_head_list);
420*a8d61afdSLawrence Stewart }
421*a8d61afdSLawrence Stewart 
422*a8d61afdSLawrence Stewart /*
423*a8d61afdSLawrence Stewart  * Vnet being torn down and destroyed.
424*a8d61afdSLawrence Stewart  */
425*a8d61afdSLawrence Stewart static void
426*a8d61afdSLawrence Stewart hhook_vnet_uninit(const void *unused __unused)
427*a8d61afdSLawrence Stewart {
428*a8d61afdSLawrence Stewart 	struct hhook_head *hhh, *tmphhh;
429*a8d61afdSLawrence Stewart 
430*a8d61afdSLawrence Stewart 	/*
431*a8d61afdSLawrence Stewart 	 * If subsystems which export helper hook points use the hhook KPI
432*a8d61afdSLawrence Stewart 	 * correctly, the loop below should have no work to do because the
433*a8d61afdSLawrence Stewart 	 * subsystem should have already called hhook_head_deregister().
434*a8d61afdSLawrence Stewart 	 */
435*a8d61afdSLawrence Stewart 	HHHLIST_LOCK();
436*a8d61afdSLawrence Stewart 	LIST_FOREACH_SAFE(hhh, &V_hhook_head_list, hhh_next, tmphhh) {
437*a8d61afdSLawrence Stewart 		printf("%s: hhook_head type=%d, id=%d cleanup required\n",
438*a8d61afdSLawrence Stewart 		    __func__, hhh->hhh_type, hhh->hhh_id);
439*a8d61afdSLawrence Stewart 		hhook_head_destroy(hhh);
440*a8d61afdSLawrence Stewart 	}
441*a8d61afdSLawrence Stewart 	HHHLIST_UNLOCK();
442*a8d61afdSLawrence Stewart }
443*a8d61afdSLawrence Stewart 
444*a8d61afdSLawrence Stewart 
445*a8d61afdSLawrence Stewart /*
446*a8d61afdSLawrence Stewart  * When a vnet is created and being initialised, init the V_hhook_head_list.
447*a8d61afdSLawrence Stewart  */
448*a8d61afdSLawrence Stewart VNET_SYSINIT(hhook_vnet_init, SI_SUB_PROTO_BEGIN, SI_ORDER_FIRST,
449*a8d61afdSLawrence Stewart     hhook_vnet_init, NULL);
450*a8d61afdSLawrence Stewart 
451*a8d61afdSLawrence Stewart /*
452*a8d61afdSLawrence Stewart  * The hhook KPI provides a mechanism for subsystems which export helper hook
453*a8d61afdSLawrence Stewart  * points to clean up on vnet tear down, but in case the KPI is misused,
454*a8d61afdSLawrence Stewart  * provide a function to clean up and free memory for a vnet being destroyed.
455*a8d61afdSLawrence Stewart  */
456*a8d61afdSLawrence Stewart VNET_SYSUNINIT(hhook_vnet_uninit, SI_SUB_PROTO_BEGIN, SI_ORDER_FIRST,
457*a8d61afdSLawrence Stewart     hhook_vnet_uninit, NULL);
458