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