| 1 | /*- |
| 2 | * SPDX-License-Identifier: BSD-2-Clause |
| 3 | * |
| 4 | * Copyright (c) 2010,2013 Lawrence Stewart <lstewart@freebsd.org> |
| 5 | * Copyright (c) 2010 The FreeBSD Foundation |
| 6 | * All rights reserved. |
| 7 | * |
| 8 | * This software was developed by Lawrence Stewart while studying at the Centre |
| 9 | * for Advanced Internet Architectures, Swinburne University of Technology, made |
| 10 | * possible in part by grants from the FreeBSD Foundation and Cisco University |
| 11 | * Research Program Fund at Community Foundation Silicon Valley. |
| 12 | * |
| 13 | * Portions of this software were developed at the Centre for Advanced |
| 14 | * Internet Architectures, Swinburne University of Technology, Melbourne, |
| 15 | * Australia by Lawrence Stewart under sponsorship from the FreeBSD Foundation. |
| 16 | * |
| 17 | * Redistribution and use in source and binary forms, with or without |
| 18 | * modification, are permitted provided that the following conditions |
| 19 | * are met: |
| 20 | * 1. Redistributions of source code must retain the above copyright |
| 21 | * notice, this list of conditions and the following disclaimer. |
| 22 | * 2. Redistributions in binary form must reproduce the above copyright |
| 23 | * notice, this list of conditions and the following disclaimer in the |
| 24 | * documentation and/or other materials provided with the distribution. |
| 25 | * |
| 26 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
| 27 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 28 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| 29 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
| 30 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| 31 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| 32 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| 33 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| 34 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| 35 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| 36 | * SUCH DAMAGE. |
| 37 | */ |
| 38 | |
| 39 | /* |
| 40 | * A KPI modelled on the pfil framework for instantiating helper hook points |
| 41 | * within the kernel for use by Khelp modules. Originally released as part of |
| 42 | * the NewTCP research project at Swinburne University of Technology's Centre |
| 43 | * for Advanced Internet Architectures, Melbourne, Australia, which was made |
| 44 | * possible in part by a grant from the Cisco University Research Program Fund |
| 45 | * at Community Foundation Silicon Valley. More details are available at: |
| 46 | * http://caia.swin.edu.au/urp/newtcp/ |
| 47 | */ |
| 48 | |
| 49 | #ifndef _SYS_HHOOK_H_ |
| 50 | #define _SYS_HHOOK_H_ |
| 51 | |
| 52 | /* XXXLAS: Is there a way around this? */ |
| 53 | #include <sys/lock.h> |
| 54 | #include <sys/rmlock.h> |
| 55 | |
| 56 | /* hhook_head flags. */ |
| 57 | #define	HHH_ISINVNET		0x00000001 /* Is the hook point in a vnet? */ |
| 58 | |
| 59 | /* Flags common to all register functions. */ |
| 60 | #define	HHOOK_WAITOK		0x00000001 /* Sleeping allowed. */ |
| 61 | #define	HHOOK_NOWAIT		0x00000002 /* Sleeping disallowed. */ |
| 62 | /* Flags only relevant to hhook_head_register() and hhook_head_is_virtual(). */ |
| 63 | #define	HHOOK_HEADISINVNET	0x00000100 /* Public proxy for HHH_ISINVNET. */ |
| 64 | |
| 65 | /* Helper hook types. */ |
| 66 | #define	HHOOK_TYPE_TCP		1 |
| 67 | #define	HHOOK_TYPE_SOCKET	2 |
| 68 | #define	HHOOK_TYPE_IPSEC_IN	3 |
| 69 | #define	HHOOK_TYPE_IPSEC_OUT	4 |
| 70 | |
| 71 | struct helper; |
| 72 | struct osd; |
| 73 | |
| 74 | /* Signature for helper hook functions. */ |
| 75 | typedef int (*hhook_func_t)(int32_t hhook_type, int32_t hhook_id, void *udata, |
| 76 | void *ctx_data, void *hdata, struct osd *hosd); |
| 77 | |
| 78 | /* |
| 79 | * Information required to add/remove a helper hook function to/from a helper |
| 80 | * hook point. |
| 81 | */ |
| 82 | struct hookinfo { |
| 83 | 	hhook_func_t	hook_func; |
| 84 | 	struct helper	*hook_helper; |
| 85 | 	void		*hook_udata; |
| 86 | 	int32_t		hook_id; |
| 87 | 	int32_t		hook_type; |
| 88 | }; |
| 89 | |
| 90 | /* |
| 91 | * Ideally this would be private but we need access to the hhh_nhooks member |
| 92 | * variable in order to make the HHOOKS_RUN_IF() macro low impact. |
| 93 | */ |
| 94 | struct hhook_head { |
| 95 | 	STAILQ_HEAD(hhook_list, hhook)	hhh_hooks; |
| 96 | 	struct rmlock			hhh_lock; |
| 97 | 	uintptr_t			hhh_vid; |
| 98 | 	int32_t				hhh_id; |
| 99 | 	int32_t				hhh_nhooks; |
| 100 | 	int32_t				hhh_type; |
| 101 | 	uint32_t			hhh_flags; |
| 102 | 	volatile uint32_t		hhh_refcount; |
| 103 | 	LIST_ENTRY(hhook_head)		hhh_next; |
| 104 | 	LIST_ENTRY(hhook_head)		hhh_vnext; |
| 105 | }; |
| 106 | |
| 107 | /* Public KPI functions. */ |
| 108 | void	hhook_run_hooks(struct hhook_head *hhh, void *ctx_data, struct osd *hosd); |
| 109 | |
| 110 | int	hhook_add_hook(struct hhook_head *hhh, const struct hookinfo *hki, |
| 111 | uint32_t flags); |
| 112 | |
| 113 | int	hhook_add_hook_lookup(const struct hookinfo *hki, uint32_t flags); |
| 114 | |
| 115 | int	hhook_remove_hook(struct hhook_head *hhh, const struct hookinfo *hki); |
| 116 | |
| 117 | int	hhook_remove_hook_lookup(const struct hookinfo *hki); |
| 118 | |
| 119 | int	hhook_head_register(int32_t hhook_type, int32_t hhook_id, |
| 120 | struct hhook_head **hhh, uint32_t flags); |
| 121 | |
| 122 | int	hhook_head_deregister(struct hhook_head *hhh); |
| 123 | |
| 124 | int	hhook_head_deregister_lookup(int32_t hhook_type, int32_t hhook_id); |
| 125 | |
| 126 | struct hhook_head * hhook_head_get(int32_t hhook_type, int32_t hhook_id); |
| 127 | |
| 128 | void	hhook_head_release(struct hhook_head *hhh); |
| 129 | |
| 130 | uint32_t hhook_head_is_virtualised(struct hhook_head *hhh); |
| 131 | |
| 132 | uint32_t hhook_head_is_virtualised_lookup(int32_t hook_type, int32_t hook_id); |
| 133 | |
| 134 | /* |
| 135 | * A wrapper around hhook_run_hooks() that only calls the function if at least |
| 136 | * one helper hook function is registered for the specified helper hook point. |
| 137 | */ |
| 138 | #define	HHOOKS_RUN_IF(hhh, ctx_data, hosd) do {				\ |
| 139 | 	if (hhh != NULL && hhh->hhh_nhooks > 0)				\ |
| 140 | 		hhook_run_hooks(hhh, ctx_data, hosd);			\ |
| 141 | } while (0) |
| 142 | |
| 143 | /* |
| 144 | * WARNING: This macro should only be used in code paths that execute |
| 145 | * infrequently, otherwise the refcounting overhead would be excessive. |
| 146 | * |
| 147 | * A similar wrapper to HHOOKS_RUN_IF() for situations where the caller prefers |
| 148 | * not to lookup and store the appropriate hhook_head pointer themselves. |
| 149 | */ |
| 150 | #define	HHOOKS_RUN_LOOKUP_IF(hhook_type, hhook_id, ctx_data, hosd) do {	\ |
| 151 | 	struct hhook_head *_hhh;					\ |
| 152 | 									\ |
| 153 | 	_hhh = hhook_head_get(hhook_type, hhook_id);			\ |
| 154 | 	if (_hhh != NULL) {						\ |
| 155 | 		if (_hhh->hhh_nhooks > 0)				\ |
| 156 | 			hhook_run_hooks(_hhh, ctx_data, hosd);		\ |
| 157 | 		hhook_head_release(_hhh);				\ |
| 158 | 	}								\ |
| 159 | } while (0) |
| 160 | |
| 161 | #endif /* _SYS_HHOOK_H_ */ |