1ef2a572bSKonstantin Belousov /*- 2ef2a572bSKonstantin Belousov * Copyright (c) 2021,2022 NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED. 3ef2a572bSKonstantin Belousov * 4ef2a572bSKonstantin Belousov * Redistribution and use in source and binary forms, with or without 5ef2a572bSKonstantin Belousov * modification, are permitted provided that the following conditions 6ef2a572bSKonstantin Belousov * are met: 7ef2a572bSKonstantin Belousov * 1. Redistributions of source code must retain the above copyright 8ef2a572bSKonstantin Belousov * notice, this list of conditions and the following disclaimer. 9ef2a572bSKonstantin Belousov * 2. Redistributions in binary form must reproduce the above copyright 10ef2a572bSKonstantin Belousov * notice, this list of conditions and the following disclaimer in the 11ef2a572bSKonstantin Belousov * documentation and/or other materials provided with the distribution. 12ef2a572bSKonstantin Belousov * 13ef2a572bSKonstantin Belousov * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS `AS IS' AND 14ef2a572bSKonstantin Belousov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15ef2a572bSKonstantin Belousov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16ef2a572bSKonstantin Belousov * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 17ef2a572bSKonstantin Belousov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18ef2a572bSKonstantin Belousov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19ef2a572bSKonstantin Belousov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20ef2a572bSKonstantin Belousov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21ef2a572bSKonstantin Belousov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22ef2a572bSKonstantin Belousov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23ef2a572bSKonstantin Belousov * SUCH DAMAGE. 24ef2a572bSKonstantin Belousov */ 25ef2a572bSKonstantin Belousov 26ef2a572bSKonstantin Belousov #include "opt_inet.h" 27ef2a572bSKonstantin Belousov #include "opt_inet6.h" 28ef2a572bSKonstantin Belousov #include "opt_ipsec.h" 29ef2a572bSKonstantin Belousov 30ef2a572bSKonstantin Belousov #include <sys/param.h> 31ef2a572bSKonstantin Belousov #include <sys/systm.h> 32ef2a572bSKonstantin Belousov #include <sys/ck.h> 33ef2a572bSKonstantin Belousov #include <sys/kernel.h> 34ef2a572bSKonstantin Belousov #include <sys/mbuf.h> 35ef2a572bSKonstantin Belousov #include <sys/pctrie.h> 36ef2a572bSKonstantin Belousov #include <sys/proc.h> 37ef2a572bSKonstantin Belousov #include <sys/socket.h> 38ef2a572bSKonstantin Belousov #include <sys/protosw.h> 39ef2a572bSKonstantin Belousov #include <sys/taskqueue.h> 40ef2a572bSKonstantin Belousov 41ef2a572bSKonstantin Belousov #include <net/if.h> 42ef2a572bSKonstantin Belousov #include <net/if_var.h> 43ef2a572bSKonstantin Belousov #include <net/vnet.h> 44ef2a572bSKonstantin Belousov #include <netinet/in.h> 45ef2a572bSKonstantin Belousov #include <netinet/ip.h> 46ef2a572bSKonstantin Belousov #include <netinet/ip_var.h> 47ef2a572bSKonstantin Belousov #include <netinet/ip6.h> 48ef2a572bSKonstantin Belousov #include <netinet6/ip6_var.h> 49ef2a572bSKonstantin Belousov #include <netinet/in_pcb.h> 50ef2a572bSKonstantin Belousov 51ef2a572bSKonstantin Belousov #include <netipsec/key.h> 52ef2a572bSKonstantin Belousov #include <netipsec/keydb.h> 53ef2a572bSKonstantin Belousov #include <netipsec/key_debug.h> 54ef2a572bSKonstantin Belousov #include <netipsec/xform.h> 55ef2a572bSKonstantin Belousov #include <netipsec/ipsec.h> 56ef2a572bSKonstantin Belousov #include <netipsec/ipsec_offload.h> 57ef2a572bSKonstantin Belousov #include <netipsec/ah_var.h> 58ef2a572bSKonstantin Belousov #include <netipsec/esp.h> 59ef2a572bSKonstantin Belousov #include <netipsec/esp_var.h> 60ef2a572bSKonstantin Belousov #include <netipsec/ipcomp_var.h> 61ef2a572bSKonstantin Belousov 62ef2a572bSKonstantin Belousov #ifdef IPSEC_OFFLOAD 63ef2a572bSKonstantin Belousov 64ef2a572bSKonstantin Belousov static struct mtx ipsec_accel_sav_tmp; 65ef2a572bSKonstantin Belousov static struct unrhdr *drv_spi_unr; 66ef2a572bSKonstantin Belousov static struct mtx ipsec_accel_cnt_lock; 67ef2a572bSKonstantin Belousov 68ef2a572bSKonstantin Belousov struct ipsec_accel_install_newkey_tq { 69ef2a572bSKonstantin Belousov struct secasvar *sav; 70ef2a572bSKonstantin Belousov struct vnet *install_vnet; 71ef2a572bSKonstantin Belousov struct task install_task; 72ef2a572bSKonstantin Belousov }; 73ef2a572bSKonstantin Belousov 74ef2a572bSKonstantin Belousov struct ipsec_accel_forget_tq { 75ef2a572bSKonstantin Belousov struct vnet *forget_vnet; 76ef2a572bSKonstantin Belousov struct task forget_task; 77ef2a572bSKonstantin Belousov struct secasvar *sav; 78ef2a572bSKonstantin Belousov }; 79ef2a572bSKonstantin Belousov 80ef2a572bSKonstantin Belousov struct ifp_handle_sav { 81ef2a572bSKonstantin Belousov CK_LIST_ENTRY(ifp_handle_sav) sav_link; 82ef2a572bSKonstantin Belousov CK_LIST_ENTRY(ifp_handle_sav) sav_allh_link; 83ef2a572bSKonstantin Belousov struct secasvar *sav; 84ef2a572bSKonstantin Belousov struct ifnet *ifp; 85ef2a572bSKonstantin Belousov void *ifdata; 86ef2a572bSKonstantin Belousov uint64_t drv_spi; 87ef2a572bSKonstantin Belousov uint32_t flags; 88ef2a572bSKonstantin Belousov size_t hdr_ext_size; 89ef2a572bSKonstantin Belousov uint64_t cnt_octets; 90ef2a572bSKonstantin Belousov uint64_t cnt_allocs; 91ef2a572bSKonstantin Belousov }; 92ef2a572bSKonstantin Belousov 93ef2a572bSKonstantin Belousov #define IFP_HS_HANDLED 0x00000001 94ef2a572bSKonstantin Belousov #define IFP_HS_REJECTED 0x00000002 95ef2a572bSKonstantin Belousov #define IFP_HS_INPUT 0x00000004 96ef2a572bSKonstantin Belousov #define IFP_HS_OUTPUT 0x00000008 97ef2a572bSKonstantin Belousov #define IFP_HS_MARKER 0x00000010 98ef2a572bSKonstantin Belousov 99ef2a572bSKonstantin Belousov static CK_LIST_HEAD(, ifp_handle_sav) ipsec_accel_all_sav_handles; 100ef2a572bSKonstantin Belousov 101ef2a572bSKonstantin Belousov struct ifp_handle_sp { 102ef2a572bSKonstantin Belousov CK_LIST_ENTRY(ifp_handle_sp) sp_link; 103ef2a572bSKonstantin Belousov CK_LIST_ENTRY(ifp_handle_sp) sp_allh_link; 104ef2a572bSKonstantin Belousov struct secpolicy *sp; 105ef2a572bSKonstantin Belousov struct ifnet *ifp; 106ef2a572bSKonstantin Belousov void *ifdata; 107ef2a572bSKonstantin Belousov uint32_t flags; 108ef2a572bSKonstantin Belousov }; 109ef2a572bSKonstantin Belousov 110ef2a572bSKonstantin Belousov #define IFP_HP_HANDLED 0x00000001 111ef2a572bSKonstantin Belousov #define IFP_HP_REJECTED 0x00000002 112ef2a572bSKonstantin Belousov #define IFP_HP_MARKER 0x00000004 113ef2a572bSKonstantin Belousov 114ef2a572bSKonstantin Belousov static CK_LIST_HEAD(, ifp_handle_sp) ipsec_accel_all_sp_handles; 115ef2a572bSKonstantin Belousov 116ef2a572bSKonstantin Belousov static void * 117ef2a572bSKonstantin Belousov drvspi_sa_trie_alloc(struct pctrie *ptree) 118ef2a572bSKonstantin Belousov { 119ef2a572bSKonstantin Belousov void *res; 120ef2a572bSKonstantin Belousov 121ef2a572bSKonstantin Belousov res = malloc(pctrie_node_size(), M_IPSEC_MISC, M_ZERO | M_NOWAIT); 122ef2a572bSKonstantin Belousov if (res != NULL) 123ef2a572bSKonstantin Belousov pctrie_zone_init(res, 0, 0); 124ef2a572bSKonstantin Belousov return (res); 125ef2a572bSKonstantin Belousov } 126ef2a572bSKonstantin Belousov 127ef2a572bSKonstantin Belousov static void 128ef2a572bSKonstantin Belousov drvspi_sa_trie_free(struct pctrie *ptree, void *node) 129ef2a572bSKonstantin Belousov { 130ef2a572bSKonstantin Belousov free(node, M_IPSEC_MISC); 131ef2a572bSKonstantin Belousov } 132ef2a572bSKonstantin Belousov 133ef2a572bSKonstantin Belousov PCTRIE_DEFINE(DRVSPI_SA, ifp_handle_sav, drv_spi, 134ef2a572bSKonstantin Belousov drvspi_sa_trie_alloc, drvspi_sa_trie_free); 135ef2a572bSKonstantin Belousov static struct pctrie drv_spi_pctrie; 136ef2a572bSKonstantin Belousov 137ef2a572bSKonstantin Belousov static void ipsec_accel_sa_newkey_impl(struct secasvar *sav); 138ef2a572bSKonstantin Belousov static int ipsec_accel_handle_sav(struct secasvar *sav, struct ifnet *ifp, 139ef2a572bSKonstantin Belousov u_int drv_spi, void *priv, uint32_t flags, struct ifp_handle_sav **ires); 140ef2a572bSKonstantin Belousov static void ipsec_accel_forget_sav_clear(struct secasvar *sav); 141ef2a572bSKonstantin Belousov static struct ifp_handle_sav *ipsec_accel_is_accel_sav_ptr(struct secasvar *sav, 142ef2a572bSKonstantin Belousov struct ifnet *ifp); 143ef2a572bSKonstantin Belousov static int ipsec_accel_sa_lifetime_op_impl(struct secasvar *sav, 144ef2a572bSKonstantin Belousov struct seclifetime *lft_c, if_t ifp, enum IF_SA_CNT_WHICH op, 145ef2a572bSKonstantin Belousov struct rm_priotracker *sahtree_trackerp); 146ef2a572bSKonstantin Belousov static void ipsec_accel_sa_recordxfer(struct secasvar *sav, struct mbuf *m); 147ef2a572bSKonstantin Belousov static void ipsec_accel_sync_imp(void); 148ef2a572bSKonstantin Belousov static bool ipsec_accel_is_accel_sav_impl(struct secasvar *sav); 149ef2a572bSKonstantin Belousov static struct mbuf *ipsec_accel_key_setaccelif_impl(struct secasvar *sav); 150ef2a572bSKonstantin Belousov 151ef2a572bSKonstantin Belousov static void 152ef2a572bSKonstantin Belousov ipsec_accel_init(void *arg) 153ef2a572bSKonstantin Belousov { 154ef2a572bSKonstantin Belousov mtx_init(&ipsec_accel_sav_tmp, "ipasat", MTX_DEF, 0); 155ef2a572bSKonstantin Belousov mtx_init(&ipsec_accel_cnt_lock, "ipascn", MTX_DEF, 0); 156ef2a572bSKonstantin Belousov drv_spi_unr = new_unrhdr(IPSEC_ACCEL_DRV_SPI_MIN, 157ef2a572bSKonstantin Belousov IPSEC_ACCEL_DRV_SPI_MAX, &ipsec_accel_sav_tmp); 158ef2a572bSKonstantin Belousov ipsec_accel_sa_newkey_p = ipsec_accel_sa_newkey_impl; 159ef2a572bSKonstantin Belousov ipsec_accel_forget_sav_p = ipsec_accel_forget_sav_impl; 160ef2a572bSKonstantin Belousov ipsec_accel_spdadd_p = ipsec_accel_spdadd_impl; 161ef2a572bSKonstantin Belousov ipsec_accel_spddel_p = ipsec_accel_spddel_impl; 162ef2a572bSKonstantin Belousov ipsec_accel_sa_lifetime_op_p = ipsec_accel_sa_lifetime_op_impl; 163ef2a572bSKonstantin Belousov ipsec_accel_sync_p = ipsec_accel_sync_imp; 164ef2a572bSKonstantin Belousov ipsec_accel_is_accel_sav_p = ipsec_accel_is_accel_sav_impl; 165ef2a572bSKonstantin Belousov ipsec_accel_key_setaccelif_p = ipsec_accel_key_setaccelif_impl; 166ef2a572bSKonstantin Belousov pctrie_init(&drv_spi_pctrie); 167ef2a572bSKonstantin Belousov } 168ef2a572bSKonstantin Belousov SYSINIT(ipsec_accel_init, SI_SUB_VNET_DONE, SI_ORDER_ANY, 169ef2a572bSKonstantin Belousov ipsec_accel_init, NULL); 170ef2a572bSKonstantin Belousov 171ef2a572bSKonstantin Belousov static void 172ef2a572bSKonstantin Belousov ipsec_accel_fini(void *arg) 173ef2a572bSKonstantin Belousov { 174ef2a572bSKonstantin Belousov ipsec_accel_sa_newkey_p = NULL; 175ef2a572bSKonstantin Belousov ipsec_accel_forget_sav_p = NULL; 176ef2a572bSKonstantin Belousov ipsec_accel_spdadd_p = NULL; 177ef2a572bSKonstantin Belousov ipsec_accel_spddel_p = NULL; 178ef2a572bSKonstantin Belousov ipsec_accel_sa_lifetime_op_p = NULL; 179ef2a572bSKonstantin Belousov ipsec_accel_sync_p = NULL; 180ef2a572bSKonstantin Belousov ipsec_accel_is_accel_sav_p = NULL; 181ef2a572bSKonstantin Belousov ipsec_accel_key_setaccelif_p = NULL; 182ef2a572bSKonstantin Belousov ipsec_accel_sync_imp(); 183ef2a572bSKonstantin Belousov clean_unrhdr(drv_spi_unr); /* avoid panic, should go later */ 184ef2a572bSKonstantin Belousov clear_unrhdr(drv_spi_unr); 185ef2a572bSKonstantin Belousov delete_unrhdr(drv_spi_unr); 186ef2a572bSKonstantin Belousov mtx_destroy(&ipsec_accel_sav_tmp); 187ef2a572bSKonstantin Belousov mtx_destroy(&ipsec_accel_cnt_lock); 188ef2a572bSKonstantin Belousov } 189ef2a572bSKonstantin Belousov SYSUNINIT(ipsec_accel_fini, SI_SUB_VNET_DONE, SI_ORDER_ANY, 190ef2a572bSKonstantin Belousov ipsec_accel_fini, NULL); 191ef2a572bSKonstantin Belousov 192ef2a572bSKonstantin Belousov static void 193ef2a572bSKonstantin Belousov ipsec_accel_alloc_forget_tq(struct secasvar *sav) 194ef2a572bSKonstantin Belousov { 195ef2a572bSKonstantin Belousov void *ftq; 196ef2a572bSKonstantin Belousov 197ef2a572bSKonstantin Belousov if (sav->accel_forget_tq != 0) 198ef2a572bSKonstantin Belousov return; 199ef2a572bSKonstantin Belousov 200ef2a572bSKonstantin Belousov ftq = malloc(sizeof(struct ipsec_accel_forget_tq), M_TEMP, M_WAITOK); 201ef2a572bSKonstantin Belousov if (!atomic_cmpset_ptr(&sav->accel_forget_tq, 0, (uintptr_t)ftq)) 202ef2a572bSKonstantin Belousov free(ftq, M_TEMP); 203ef2a572bSKonstantin Belousov } 204ef2a572bSKonstantin Belousov 205ef2a572bSKonstantin Belousov static bool 206ef2a572bSKonstantin Belousov ipsec_accel_sa_install_match(if_t ifp, void *arg) 207ef2a572bSKonstantin Belousov { 208ef2a572bSKonstantin Belousov if ((ifp->if_capenable2 & IFCAP2_BIT(IFCAP2_IPSEC_OFFLOAD)) == 0) 209ef2a572bSKonstantin Belousov return (false); 210ef2a572bSKonstantin Belousov if (ifp->if_ipsec_accel_m->if_sa_newkey == NULL) { 211ef2a572bSKonstantin Belousov printf("driver bug ifp %s if_sa_newkey NULL\n", 212ef2a572bSKonstantin Belousov if_name(ifp)); 213ef2a572bSKonstantin Belousov return (false); 214ef2a572bSKonstantin Belousov } 215ef2a572bSKonstantin Belousov return (true); 216ef2a572bSKonstantin Belousov } 217ef2a572bSKonstantin Belousov 218ef2a572bSKonstantin Belousov static int 219ef2a572bSKonstantin Belousov ipsec_accel_sa_newkey_cb(if_t ifp, void *arg) 220ef2a572bSKonstantin Belousov { 221ef2a572bSKonstantin Belousov struct ipsec_accel_install_newkey_tq *tq; 222ef2a572bSKonstantin Belousov void *priv; 223ef2a572bSKonstantin Belousov u_int drv_spi; 224ef2a572bSKonstantin Belousov int error; 225ef2a572bSKonstantin Belousov 226ef2a572bSKonstantin Belousov tq = arg; 227ef2a572bSKonstantin Belousov 228ef2a572bSKonstantin Belousov printf("ipsec_accel_sa_newkey_act: ifp %s h %p spi %#x " 229ef2a572bSKonstantin Belousov "flags %#x seq %d\n", 230ef2a572bSKonstantin Belousov if_name(ifp), ifp->if_ipsec_accel_m->if_sa_newkey, 231ef2a572bSKonstantin Belousov be32toh(tq->sav->spi), tq->sav->flags, tq->sav->seq); 232ef2a572bSKonstantin Belousov priv = NULL; 233ef2a572bSKonstantin Belousov drv_spi = alloc_unr(drv_spi_unr); 234ef2a572bSKonstantin Belousov if (tq->sav->accel_ifname != NULL && 235ef2a572bSKonstantin Belousov strcmp(tq->sav->accel_ifname, if_name(ifp)) != 0) { 236ef2a572bSKonstantin Belousov error = ipsec_accel_handle_sav(tq->sav, 237ef2a572bSKonstantin Belousov ifp, drv_spi, priv, IFP_HS_REJECTED, NULL); 238ef2a572bSKonstantin Belousov goto out; 239ef2a572bSKonstantin Belousov } 240ef2a572bSKonstantin Belousov if (drv_spi == -1) { 241ef2a572bSKonstantin Belousov /* XXXKIB */ 242ef2a572bSKonstantin Belousov printf("ipsec_accel_sa_install_newkey: cannot alloc " 243ef2a572bSKonstantin Belousov "drv_spi if %s spi %#x\n", if_name(ifp), 244ef2a572bSKonstantin Belousov be32toh(tq->sav->spi)); 245ef2a572bSKonstantin Belousov return (ENOMEM); 246ef2a572bSKonstantin Belousov } 247ef2a572bSKonstantin Belousov error = ifp->if_ipsec_accel_m->if_sa_newkey(ifp, tq->sav, 248ef2a572bSKonstantin Belousov drv_spi, &priv); 249ef2a572bSKonstantin Belousov if (error != 0) { 250ef2a572bSKonstantin Belousov if (error == EOPNOTSUPP) { 251ef2a572bSKonstantin Belousov printf("ipsec_accel_sa_newkey: driver " 252ef2a572bSKonstantin Belousov "refused sa if %s spi %#x\n", 253ef2a572bSKonstantin Belousov if_name(ifp), be32toh(tq->sav->spi)); 254ef2a572bSKonstantin Belousov error = ipsec_accel_handle_sav(tq->sav, 255ef2a572bSKonstantin Belousov ifp, drv_spi, priv, IFP_HS_REJECTED, NULL); 256ef2a572bSKonstantin Belousov /* XXXKIB */ 257ef2a572bSKonstantin Belousov } else { 258ef2a572bSKonstantin Belousov printf("ipsec_accel_sa_newkey: driver " 259ef2a572bSKonstantin Belousov "error %d if %s spi %#x\n", 260ef2a572bSKonstantin Belousov error, if_name(ifp), be32toh(tq->sav->spi)); 261ef2a572bSKonstantin Belousov /* XXXKIB */ 262ef2a572bSKonstantin Belousov } 263ef2a572bSKonstantin Belousov } else { 264ef2a572bSKonstantin Belousov error = ipsec_accel_handle_sav(tq->sav, ifp, 265ef2a572bSKonstantin Belousov drv_spi, priv, IFP_HS_HANDLED, NULL); 266ef2a572bSKonstantin Belousov if (error != 0) { 267ef2a572bSKonstantin Belousov /* XXXKIB */ 268ef2a572bSKonstantin Belousov printf("ipsec_accel_sa_newkey: handle_sav " 269ef2a572bSKonstantin Belousov "err %d if %s spi %#x\n", error, 270ef2a572bSKonstantin Belousov if_name(ifp), be32toh(tq->sav->spi)); 271ef2a572bSKonstantin Belousov } 272ef2a572bSKonstantin Belousov } 273ef2a572bSKonstantin Belousov out: 274ef2a572bSKonstantin Belousov return (error); 275ef2a572bSKonstantin Belousov } 276ef2a572bSKonstantin Belousov 277ef2a572bSKonstantin Belousov static void 278ef2a572bSKonstantin Belousov ipsec_accel_sa_newkey_act(void *context, int pending) 279ef2a572bSKonstantin Belousov { 280ef2a572bSKonstantin Belousov struct ipsec_accel_install_newkey_tq *tq; 281ef2a572bSKonstantin Belousov void *tqf; 282ef2a572bSKonstantin Belousov struct secasvar *sav; 283ef2a572bSKonstantin Belousov 284ef2a572bSKonstantin Belousov tq = context; 285ef2a572bSKonstantin Belousov tqf = NULL; 286ef2a572bSKonstantin Belousov sav = tq->sav; 287ef2a572bSKonstantin Belousov CURVNET_SET(tq->install_vnet); 288ef2a572bSKonstantin Belousov mtx_lock(&ipsec_accel_sav_tmp); 289ef2a572bSKonstantin Belousov if ((sav->accel_flags & (SADB_KEY_ACCEL_INST | 290ef2a572bSKonstantin Belousov SADB_KEY_ACCEL_DEINST)) == 0 && 291ef2a572bSKonstantin Belousov sav->state == SADB_SASTATE_MATURE) { 292ef2a572bSKonstantin Belousov sav->accel_flags |= SADB_KEY_ACCEL_INST; 293ef2a572bSKonstantin Belousov mtx_unlock(&ipsec_accel_sav_tmp); 294ef2a572bSKonstantin Belousov if_foreach_sleep(ipsec_accel_sa_install_match, context, 295ef2a572bSKonstantin Belousov ipsec_accel_sa_newkey_cb, context); 296ef2a572bSKonstantin Belousov ipsec_accel_alloc_forget_tq(sav); 297ef2a572bSKonstantin Belousov mtx_lock(&ipsec_accel_sav_tmp); 298ef2a572bSKonstantin Belousov 299ef2a572bSKonstantin Belousov /* 300ef2a572bSKonstantin Belousov * If ipsec_accel_forget_sav() raced with us and set 301ef2a572bSKonstantin Belousov * the flag, do its work. Its task cannot execute in 302ef2a572bSKonstantin Belousov * parallel since taskqueue_thread is single-threaded. 303ef2a572bSKonstantin Belousov */ 304ef2a572bSKonstantin Belousov if ((sav->accel_flags & SADB_KEY_ACCEL_DEINST) != 0) { 305ef2a572bSKonstantin Belousov tqf = (void *)sav->accel_forget_tq; 306ef2a572bSKonstantin Belousov sav->accel_forget_tq = 0; 307ef2a572bSKonstantin Belousov ipsec_accel_forget_sav_clear(sav); 308ef2a572bSKonstantin Belousov } 309ef2a572bSKonstantin Belousov } 310ef2a572bSKonstantin Belousov mtx_unlock(&ipsec_accel_sav_tmp); 311ef2a572bSKonstantin Belousov key_freesav(&tq->sav); 312ef2a572bSKonstantin Belousov CURVNET_RESTORE(); 313ef2a572bSKonstantin Belousov free(tq, M_TEMP); 314ef2a572bSKonstantin Belousov free(tqf, M_TEMP); 315ef2a572bSKonstantin Belousov } 316ef2a572bSKonstantin Belousov 317ef2a572bSKonstantin Belousov static void 318ef2a572bSKonstantin Belousov ipsec_accel_sa_newkey_impl(struct secasvar *sav) 319ef2a572bSKonstantin Belousov { 320ef2a572bSKonstantin Belousov struct ipsec_accel_install_newkey_tq *tq; 321ef2a572bSKonstantin Belousov 322ef2a572bSKonstantin Belousov if ((sav->accel_flags & (SADB_KEY_ACCEL_INST | 323ef2a572bSKonstantin Belousov SADB_KEY_ACCEL_DEINST)) != 0) 324ef2a572bSKonstantin Belousov return; 325ef2a572bSKonstantin Belousov 326ef2a572bSKonstantin Belousov printf( 327ef2a572bSKonstantin Belousov "ipsec_accel_sa_install_newkey: spi %#x flags %#x seq %d\n", 328ef2a572bSKonstantin Belousov be32toh(sav->spi), sav->flags, sav->seq); 329ef2a572bSKonstantin Belousov 330ef2a572bSKonstantin Belousov tq = malloc(sizeof(*tq), M_TEMP, M_NOWAIT); 331ef2a572bSKonstantin Belousov if (tq == NULL) { 332ef2a572bSKonstantin Belousov printf("ipsec_accel_sa_install_newkey: no memory for tq, " 333ef2a572bSKonstantin Belousov "spi %#x\n", be32toh(sav->spi)); 334ef2a572bSKonstantin Belousov /* XXXKIB */ 335ef2a572bSKonstantin Belousov return; 336ef2a572bSKonstantin Belousov } 337ef2a572bSKonstantin Belousov 338ef2a572bSKonstantin Belousov refcount_acquire(&sav->refcnt); 339ef2a572bSKonstantin Belousov 340ef2a572bSKonstantin Belousov TASK_INIT(&tq->install_task, 0, ipsec_accel_sa_newkey_act, tq); 341ef2a572bSKonstantin Belousov tq->sav = sav; 342ef2a572bSKonstantin Belousov tq->install_vnet = curthread->td_vnet; /* XXXKIB liveness */ 343ef2a572bSKonstantin Belousov taskqueue_enqueue(taskqueue_thread, &tq->install_task); 344ef2a572bSKonstantin Belousov } 345ef2a572bSKonstantin Belousov 346ef2a572bSKonstantin Belousov static int 347ef2a572bSKonstantin Belousov ipsec_accel_handle_sav(struct secasvar *sav, struct ifnet *ifp, 348ef2a572bSKonstantin Belousov u_int drv_spi, void *priv, uint32_t flags, struct ifp_handle_sav **ires) 349ef2a572bSKonstantin Belousov { 350ef2a572bSKonstantin Belousov struct ifp_handle_sav *ihs, *i; 351ef2a572bSKonstantin Belousov int error; 352ef2a572bSKonstantin Belousov 353ef2a572bSKonstantin Belousov MPASS(__bitcount(flags & (IFP_HS_HANDLED | IFP_HS_REJECTED)) == 1); 354ef2a572bSKonstantin Belousov 355ef2a572bSKonstantin Belousov ihs = malloc(sizeof(*ihs), M_IPSEC_MISC, M_WAITOK | M_ZERO); 356ef2a572bSKonstantin Belousov ihs->ifp = ifp; 357ef2a572bSKonstantin Belousov ihs->sav = sav; 358ef2a572bSKonstantin Belousov ihs->drv_spi = drv_spi; 359ef2a572bSKonstantin Belousov ihs->ifdata = priv; 360ef2a572bSKonstantin Belousov ihs->flags = flags; 361ef2a572bSKonstantin Belousov if ((flags & IFP_HS_OUTPUT) != 0) 362ef2a572bSKonstantin Belousov ihs->hdr_ext_size = esp_hdrsiz(sav); 363ef2a572bSKonstantin Belousov mtx_lock(&ipsec_accel_sav_tmp); 364ef2a572bSKonstantin Belousov CK_LIST_FOREACH(i, &sav->accel_ifps, sav_link) { 365ef2a572bSKonstantin Belousov if (i->ifp == ifp) { 366ef2a572bSKonstantin Belousov error = EALREADY; 367ef2a572bSKonstantin Belousov goto errout; 368ef2a572bSKonstantin Belousov } 369ef2a572bSKonstantin Belousov } 370ef2a572bSKonstantin Belousov error = DRVSPI_SA_PCTRIE_INSERT(&drv_spi_pctrie, ihs); 371ef2a572bSKonstantin Belousov if (error != 0) 372ef2a572bSKonstantin Belousov goto errout; 373ef2a572bSKonstantin Belousov if_ref(ihs->ifp); 374ef2a572bSKonstantin Belousov CK_LIST_INSERT_HEAD(&sav->accel_ifps, ihs, sav_link); 375ef2a572bSKonstantin Belousov CK_LIST_INSERT_HEAD(&ipsec_accel_all_sav_handles, ihs, sav_allh_link); 376ef2a572bSKonstantin Belousov mtx_unlock(&ipsec_accel_sav_tmp); 377ef2a572bSKonstantin Belousov if (ires != NULL) 378ef2a572bSKonstantin Belousov *ires = ihs; 379ef2a572bSKonstantin Belousov return (0); 380ef2a572bSKonstantin Belousov errout: 381ef2a572bSKonstantin Belousov mtx_unlock(&ipsec_accel_sav_tmp); 382ef2a572bSKonstantin Belousov free(ihs, M_IPSEC_MISC); 383ef2a572bSKonstantin Belousov if (ires != NULL) 384ef2a572bSKonstantin Belousov *ires = NULL; 385ef2a572bSKonstantin Belousov return (error); 386ef2a572bSKonstantin Belousov } 387ef2a572bSKonstantin Belousov 388ef2a572bSKonstantin Belousov static void 389ef2a572bSKonstantin Belousov ipsec_accel_forget_handle_sav(struct ifp_handle_sav *i, bool freesav) 390ef2a572bSKonstantin Belousov { 391ef2a572bSKonstantin Belousov struct ifnet *ifp; 392ef2a572bSKonstantin Belousov struct secasvar *sav; 393ef2a572bSKonstantin Belousov 394ef2a572bSKonstantin Belousov mtx_assert(&ipsec_accel_sav_tmp, MA_OWNED); 395ef2a572bSKonstantin Belousov 396ef2a572bSKonstantin Belousov CK_LIST_REMOVE(i, sav_link); 397ef2a572bSKonstantin Belousov CK_LIST_REMOVE(i, sav_allh_link); 398ef2a572bSKonstantin Belousov DRVSPI_SA_PCTRIE_REMOVE(&drv_spi_pctrie, i->drv_spi); 399ef2a572bSKonstantin Belousov mtx_unlock(&ipsec_accel_sav_tmp); 400ef2a572bSKonstantin Belousov NET_EPOCH_WAIT(); 401ef2a572bSKonstantin Belousov ifp = i->ifp; 402ef2a572bSKonstantin Belousov sav = i->sav; 403ef2a572bSKonstantin Belousov if ((i->flags & (IFP_HS_HANDLED | IFP_HS_REJECTED)) == 404ef2a572bSKonstantin Belousov IFP_HS_HANDLED) { 405ef2a572bSKonstantin Belousov printf("sa deinstall %s %p spi %#x ifl %#x\n", 406ef2a572bSKonstantin Belousov if_name(ifp), sav, be32toh(sav->spi), i->flags); 407ef2a572bSKonstantin Belousov ifp->if_ipsec_accel_m->if_sa_deinstall(ifp, 408ef2a572bSKonstantin Belousov i->drv_spi, i->ifdata); 409ef2a572bSKonstantin Belousov } 410ef2a572bSKonstantin Belousov if_rele(ifp); 411ef2a572bSKonstantin Belousov free_unr(drv_spi_unr, i->drv_spi); 412ef2a572bSKonstantin Belousov free(i, M_IPSEC_MISC); 413ef2a572bSKonstantin Belousov if (freesav) 414ef2a572bSKonstantin Belousov key_freesav(&sav); 415ef2a572bSKonstantin Belousov mtx_lock(&ipsec_accel_sav_tmp); 416ef2a572bSKonstantin Belousov } 417ef2a572bSKonstantin Belousov 418ef2a572bSKonstantin Belousov static void 419ef2a572bSKonstantin Belousov ipsec_accel_forget_sav_clear(struct secasvar *sav) 420ef2a572bSKonstantin Belousov { 421ef2a572bSKonstantin Belousov struct ifp_handle_sav *i; 422ef2a572bSKonstantin Belousov 423ef2a572bSKonstantin Belousov for (;;) { 424ef2a572bSKonstantin Belousov i = CK_LIST_FIRST(&sav->accel_ifps); 425ef2a572bSKonstantin Belousov if (i == NULL) 426ef2a572bSKonstantin Belousov break; 427ef2a572bSKonstantin Belousov ipsec_accel_forget_handle_sav(i, false); 428ef2a572bSKonstantin Belousov } 429ef2a572bSKonstantin Belousov } 430ef2a572bSKonstantin Belousov 431ef2a572bSKonstantin Belousov static void 432ef2a572bSKonstantin Belousov ipsec_accel_forget_sav_act(void *arg, int pending) 433ef2a572bSKonstantin Belousov { 434ef2a572bSKonstantin Belousov struct ipsec_accel_forget_tq *tq; 435ef2a572bSKonstantin Belousov struct secasvar *sav; 436ef2a572bSKonstantin Belousov 437ef2a572bSKonstantin Belousov tq = arg; 438ef2a572bSKonstantin Belousov sav = tq->sav; 439ef2a572bSKonstantin Belousov CURVNET_SET(tq->forget_vnet); 440ef2a572bSKonstantin Belousov mtx_lock(&ipsec_accel_sav_tmp); 441ef2a572bSKonstantin Belousov ipsec_accel_forget_sav_clear(sav); 442ef2a572bSKonstantin Belousov mtx_unlock(&ipsec_accel_sav_tmp); 443ef2a572bSKonstantin Belousov key_freesav(&sav); 444ef2a572bSKonstantin Belousov CURVNET_RESTORE(); 445ef2a572bSKonstantin Belousov free(tq, M_TEMP); 446ef2a572bSKonstantin Belousov } 447ef2a572bSKonstantin Belousov 448ef2a572bSKonstantin Belousov void 449ef2a572bSKonstantin Belousov ipsec_accel_forget_sav_impl(struct secasvar *sav) 450ef2a572bSKonstantin Belousov { 451ef2a572bSKonstantin Belousov struct ipsec_accel_forget_tq *tq; 452ef2a572bSKonstantin Belousov 453ef2a572bSKonstantin Belousov mtx_lock(&ipsec_accel_sav_tmp); 454ef2a572bSKonstantin Belousov sav->accel_flags |= SADB_KEY_ACCEL_DEINST; 455ef2a572bSKonstantin Belousov tq = (void *)atomic_load_ptr(&sav->accel_forget_tq); 456ef2a572bSKonstantin Belousov if (tq == NULL || !atomic_cmpset_ptr(&sav->accel_forget_tq, 457ef2a572bSKonstantin Belousov (uintptr_t)tq, 0)) { 458ef2a572bSKonstantin Belousov mtx_unlock(&ipsec_accel_sav_tmp); 459ef2a572bSKonstantin Belousov return; 460ef2a572bSKonstantin Belousov } 461ef2a572bSKonstantin Belousov mtx_unlock(&ipsec_accel_sav_tmp); 462ef2a572bSKonstantin Belousov 463ef2a572bSKonstantin Belousov refcount_acquire(&sav->refcnt); 464ef2a572bSKonstantin Belousov TASK_INIT(&tq->forget_task, 0, ipsec_accel_forget_sav_act, tq); 465ef2a572bSKonstantin Belousov tq->forget_vnet = curthread->td_vnet; 466ef2a572bSKonstantin Belousov tq->sav = sav; 467ef2a572bSKonstantin Belousov taskqueue_enqueue(taskqueue_thread, &tq->forget_task); 468ef2a572bSKonstantin Belousov } 469ef2a572bSKonstantin Belousov 470ef2a572bSKonstantin Belousov static void 471ef2a572bSKonstantin Belousov ipsec_accel_on_ifdown_sav(struct ifnet *ifp) 472ef2a572bSKonstantin Belousov { 473ef2a572bSKonstantin Belousov struct ifp_handle_sav *i, *marker; 474ef2a572bSKonstantin Belousov 475ef2a572bSKonstantin Belousov marker = malloc(sizeof(*marker), M_IPSEC_MISC, M_WAITOK | M_ZERO); 476ef2a572bSKonstantin Belousov marker->flags = IFP_HS_MARKER; 477ef2a572bSKonstantin Belousov 478ef2a572bSKonstantin Belousov mtx_lock(&ipsec_accel_sav_tmp); 479ef2a572bSKonstantin Belousov CK_LIST_INSERT_HEAD(&ipsec_accel_all_sav_handles, marker, 480ef2a572bSKonstantin Belousov sav_allh_link); 481ef2a572bSKonstantin Belousov for (;;) { 482ef2a572bSKonstantin Belousov i = CK_LIST_NEXT(marker, sav_allh_link); 483ef2a572bSKonstantin Belousov if (i == NULL) 484ef2a572bSKonstantin Belousov break; 485ef2a572bSKonstantin Belousov CK_LIST_REMOVE(marker, sav_allh_link); 486ef2a572bSKonstantin Belousov CK_LIST_INSERT_AFTER(i, marker, sav_allh_link); 487ef2a572bSKonstantin Belousov if (i->ifp == ifp) { 488ef2a572bSKonstantin Belousov refcount_acquire(&i->sav->refcnt); /* XXXKIB wrap ? */ 489ef2a572bSKonstantin Belousov ipsec_accel_forget_handle_sav(i, true); 490ef2a572bSKonstantin Belousov } 491ef2a572bSKonstantin Belousov } 492ef2a572bSKonstantin Belousov CK_LIST_REMOVE(marker, sav_allh_link); 493ef2a572bSKonstantin Belousov mtx_unlock(&ipsec_accel_sav_tmp); 494ef2a572bSKonstantin Belousov free(marker, M_IPSEC_MISC); 495ef2a572bSKonstantin Belousov } 496ef2a572bSKonstantin Belousov 497ef2a572bSKonstantin Belousov static struct ifp_handle_sav * 498ef2a572bSKonstantin Belousov ipsec_accel_is_accel_sav_ptr_raw(struct secasvar *sav, struct ifnet *ifp) 499ef2a572bSKonstantin Belousov { 500ef2a572bSKonstantin Belousov struct ifp_handle_sav *i; 501ef2a572bSKonstantin Belousov 502ef2a572bSKonstantin Belousov if ((ifp->if_capenable2 & IFCAP2_BIT(IFCAP2_IPSEC_OFFLOAD)) == 0) 503ef2a572bSKonstantin Belousov return (NULL); 504ef2a572bSKonstantin Belousov CK_LIST_FOREACH(i, &sav->accel_ifps, sav_link) { 505ef2a572bSKonstantin Belousov if (i->ifp == ifp) 506ef2a572bSKonstantin Belousov return (i); 507ef2a572bSKonstantin Belousov } 508ef2a572bSKonstantin Belousov return (NULL); 509ef2a572bSKonstantin Belousov } 510ef2a572bSKonstantin Belousov 511ef2a572bSKonstantin Belousov static struct ifp_handle_sav * 512ef2a572bSKonstantin Belousov ipsec_accel_is_accel_sav_ptr(struct secasvar *sav, struct ifnet *ifp) 513ef2a572bSKonstantin Belousov { 514ef2a572bSKonstantin Belousov NET_EPOCH_ASSERT(); 515ef2a572bSKonstantin Belousov return (ipsec_accel_is_accel_sav_ptr_raw(sav, ifp)); 516ef2a572bSKonstantin Belousov } 517ef2a572bSKonstantin Belousov 518ef2a572bSKonstantin Belousov static bool 519ef2a572bSKonstantin Belousov ipsec_accel_is_accel_sav_impl(struct secasvar *sav) 520ef2a572bSKonstantin Belousov { 521ef2a572bSKonstantin Belousov return (!CK_LIST_EMPTY(&sav->accel_ifps)); 522ef2a572bSKonstantin Belousov } 523ef2a572bSKonstantin Belousov 524ef2a572bSKonstantin Belousov static struct secasvar * 525ef2a572bSKonstantin Belousov ipsec_accel_drvspi_to_sa(u_int drv_spi) 526ef2a572bSKonstantin Belousov { 527ef2a572bSKonstantin Belousov struct ifp_handle_sav *i; 528ef2a572bSKonstantin Belousov 529ef2a572bSKonstantin Belousov i = DRVSPI_SA_PCTRIE_LOOKUP(&drv_spi_pctrie, drv_spi); 530ef2a572bSKonstantin Belousov if (i == NULL) 531ef2a572bSKonstantin Belousov return (NULL); 532ef2a572bSKonstantin Belousov return (i->sav); 533ef2a572bSKonstantin Belousov } 534ef2a572bSKonstantin Belousov 535ef2a572bSKonstantin Belousov static struct ifp_handle_sp * 536ef2a572bSKonstantin Belousov ipsec_accel_find_accel_sp(struct secpolicy *sp, if_t ifp) 537ef2a572bSKonstantin Belousov { 538ef2a572bSKonstantin Belousov struct ifp_handle_sp *i; 539ef2a572bSKonstantin Belousov 540ef2a572bSKonstantin Belousov CK_LIST_FOREACH(i, &sp->accel_ifps, sp_link) { 541ef2a572bSKonstantin Belousov if (i->ifp == ifp) 542ef2a572bSKonstantin Belousov return (i); 543ef2a572bSKonstantin Belousov } 544ef2a572bSKonstantin Belousov return (NULL); 545ef2a572bSKonstantin Belousov } 546ef2a572bSKonstantin Belousov 547ef2a572bSKonstantin Belousov static bool 548ef2a572bSKonstantin Belousov ipsec_accel_is_accel_sp(struct secpolicy *sp, if_t ifp) 549ef2a572bSKonstantin Belousov { 550ef2a572bSKonstantin Belousov return (ipsec_accel_find_accel_sp(sp, ifp) != NULL); 551ef2a572bSKonstantin Belousov } 552ef2a572bSKonstantin Belousov 553ef2a572bSKonstantin Belousov static int 554ef2a572bSKonstantin Belousov ipsec_accel_remember_sp(struct secpolicy *sp, if_t ifp, 555ef2a572bSKonstantin Belousov struct ifp_handle_sp **ip) 556ef2a572bSKonstantin Belousov { 557ef2a572bSKonstantin Belousov struct ifp_handle_sp *i; 558ef2a572bSKonstantin Belousov 559ef2a572bSKonstantin Belousov i = malloc(sizeof(*i), M_IPSEC_MISC, M_WAITOK | M_ZERO); 560ef2a572bSKonstantin Belousov i->sp = sp; 561ef2a572bSKonstantin Belousov i->ifp = ifp; 562ef2a572bSKonstantin Belousov if_ref(ifp); 563ef2a572bSKonstantin Belousov i->flags = IFP_HP_HANDLED; 564ef2a572bSKonstantin Belousov mtx_lock(&ipsec_accel_sav_tmp); 565ef2a572bSKonstantin Belousov CK_LIST_INSERT_HEAD(&sp->accel_ifps, i, sp_link); 566ef2a572bSKonstantin Belousov CK_LIST_INSERT_HEAD(&ipsec_accel_all_sp_handles, i, sp_allh_link); 567ef2a572bSKonstantin Belousov mtx_unlock(&ipsec_accel_sav_tmp); 568ef2a572bSKonstantin Belousov *ip = i; 569ef2a572bSKonstantin Belousov return (0); 570ef2a572bSKonstantin Belousov } 571ef2a572bSKonstantin Belousov 572ef2a572bSKonstantin Belousov static bool 573ef2a572bSKonstantin Belousov ipsec_accel_spdadd_match(if_t ifp, void *arg) 574ef2a572bSKonstantin Belousov { 575ef2a572bSKonstantin Belousov struct secpolicy *sp; 576ef2a572bSKonstantin Belousov 577ef2a572bSKonstantin Belousov if ((ifp->if_capenable2 & IFCAP2_BIT(IFCAP2_IPSEC_OFFLOAD)) == 0 || 578ef2a572bSKonstantin Belousov ifp->if_ipsec_accel_m->if_spdadd == NULL) 579ef2a572bSKonstantin Belousov return (false); 580ef2a572bSKonstantin Belousov sp = arg; 581ef2a572bSKonstantin Belousov if (sp->accel_ifname != NULL && 582ef2a572bSKonstantin Belousov strcmp(sp->accel_ifname, if_name(ifp)) != 0) 583ef2a572bSKonstantin Belousov return (false); 584ef2a572bSKonstantin Belousov if (ipsec_accel_is_accel_sp(sp, ifp)) 585ef2a572bSKonstantin Belousov return (false); 586ef2a572bSKonstantin Belousov return (true); 587ef2a572bSKonstantin Belousov } 588ef2a572bSKonstantin Belousov 589ef2a572bSKonstantin Belousov static int 590ef2a572bSKonstantin Belousov ipsec_accel_spdadd_cb(if_t ifp, void *arg) 591ef2a572bSKonstantin Belousov { 592ef2a572bSKonstantin Belousov struct secpolicy *sp; 593ef2a572bSKonstantin Belousov struct inpcb *inp; 594ef2a572bSKonstantin Belousov struct ifp_handle_sp *i; 595ef2a572bSKonstantin Belousov int error; 596ef2a572bSKonstantin Belousov 597ef2a572bSKonstantin Belousov sp = arg; 598ef2a572bSKonstantin Belousov inp = sp->ipsec_accel_add_sp_inp; 599ef2a572bSKonstantin Belousov printf("ipsec_accel_spdadd_cb: ifp %s m %p sp %p inp %p\n", 600ef2a572bSKonstantin Belousov if_name(ifp), ifp->if_ipsec_accel_m->if_spdadd, sp, inp); 601ef2a572bSKonstantin Belousov error = ipsec_accel_remember_sp(sp, ifp, &i); 602ef2a572bSKonstantin Belousov if (error != 0) { 603ef2a572bSKonstantin Belousov printf("ipsec_accel_spdadd: %s if_spdadd %p remember res %d\n", 604ef2a572bSKonstantin Belousov if_name(ifp), sp, error); 605ef2a572bSKonstantin Belousov return (error); 606ef2a572bSKonstantin Belousov } 607ef2a572bSKonstantin Belousov error = ifp->if_ipsec_accel_m->if_spdadd(ifp, sp, inp, &i->ifdata); 608ef2a572bSKonstantin Belousov if (error != 0) { 609ef2a572bSKonstantin Belousov i->flags |= IFP_HP_REJECTED; 610ef2a572bSKonstantin Belousov printf("ipsec_accel_spdadd: %s if_spdadd %p res %d\n", 611ef2a572bSKonstantin Belousov if_name(ifp), sp, error); 612ef2a572bSKonstantin Belousov } 613ef2a572bSKonstantin Belousov return (error); 614ef2a572bSKonstantin Belousov } 615ef2a572bSKonstantin Belousov 616ef2a572bSKonstantin Belousov static void 617ef2a572bSKonstantin Belousov ipsec_accel_spdadd_act(void *arg, int pending) 618ef2a572bSKonstantin Belousov { 619ef2a572bSKonstantin Belousov struct secpolicy *sp; 620ef2a572bSKonstantin Belousov struct inpcb *inp; 621ef2a572bSKonstantin Belousov 622ef2a572bSKonstantin Belousov sp = arg; 623ef2a572bSKonstantin Belousov CURVNET_SET(sp->accel_add_tq.adddel_vnet); 624ef2a572bSKonstantin Belousov if_foreach_sleep(ipsec_accel_spdadd_match, arg, 625ef2a572bSKonstantin Belousov ipsec_accel_spdadd_cb, arg); 626ef2a572bSKonstantin Belousov inp = sp->ipsec_accel_add_sp_inp; 627ef2a572bSKonstantin Belousov if (inp != NULL) { 628ef2a572bSKonstantin Belousov INP_WLOCK(inp); 629ef2a572bSKonstantin Belousov if (!in_pcbrele_wlocked(inp)) 630ef2a572bSKonstantin Belousov INP_WUNLOCK(inp); 631ef2a572bSKonstantin Belousov sp->ipsec_accel_add_sp_inp = NULL; 632ef2a572bSKonstantin Belousov } 633ef2a572bSKonstantin Belousov CURVNET_RESTORE(); 634ef2a572bSKonstantin Belousov key_freesp(&sp); 635ef2a572bSKonstantin Belousov } 636ef2a572bSKonstantin Belousov 637ef2a572bSKonstantin Belousov void 638ef2a572bSKonstantin Belousov ipsec_accel_spdadd_impl(struct secpolicy *sp, struct inpcb *inp) 639ef2a572bSKonstantin Belousov { 640ef2a572bSKonstantin Belousov struct ipsec_accel_adddel_sp_tq *tq; 641ef2a572bSKonstantin Belousov 642ef2a572bSKonstantin Belousov if (sp == NULL) 643ef2a572bSKonstantin Belousov return; 644ef2a572bSKonstantin Belousov if (sp->tcount == 0 && inp == NULL) 645ef2a572bSKonstantin Belousov return; 646ef2a572bSKonstantin Belousov tq = &sp->accel_add_tq; 647ef2a572bSKonstantin Belousov if (atomic_cmpset_int(&tq->adddel_scheduled, 0, 1) == 0) 648ef2a572bSKonstantin Belousov return; 649ef2a572bSKonstantin Belousov tq->adddel_vnet = curthread->td_vnet; 650ef2a572bSKonstantin Belousov sp->ipsec_accel_add_sp_inp = inp; 651ef2a572bSKonstantin Belousov if (inp != NULL) 652ef2a572bSKonstantin Belousov in_pcbref(inp); 653ef2a572bSKonstantin Belousov TASK_INIT(&tq->adddel_task, 0, ipsec_accel_spdadd_act, sp); 654ef2a572bSKonstantin Belousov key_addref(sp); 655ef2a572bSKonstantin Belousov taskqueue_enqueue(taskqueue_thread, &tq->adddel_task); 656ef2a572bSKonstantin Belousov } 657ef2a572bSKonstantin Belousov 658ef2a572bSKonstantin Belousov static void 659ef2a572bSKonstantin Belousov ipsec_accel_spddel_act(void *arg, int pending) 660ef2a572bSKonstantin Belousov { 661ef2a572bSKonstantin Belousov struct ifp_handle_sp *i; 662ef2a572bSKonstantin Belousov struct secpolicy *sp; 663ef2a572bSKonstantin Belousov int error; 664ef2a572bSKonstantin Belousov 665ef2a572bSKonstantin Belousov sp = arg; 666ef2a572bSKonstantin Belousov CURVNET_SET(sp->accel_del_tq.adddel_vnet); 667ef2a572bSKonstantin Belousov mtx_lock(&ipsec_accel_sav_tmp); 668ef2a572bSKonstantin Belousov for (;;) { 669ef2a572bSKonstantin Belousov i = CK_LIST_FIRST(&sp->accel_ifps); 670ef2a572bSKonstantin Belousov if (i == NULL) 671ef2a572bSKonstantin Belousov break; 672ef2a572bSKonstantin Belousov CK_LIST_REMOVE(i, sp_link); 673ef2a572bSKonstantin Belousov CK_LIST_REMOVE(i, sp_allh_link); 674ef2a572bSKonstantin Belousov mtx_unlock(&ipsec_accel_sav_tmp); 675ef2a572bSKonstantin Belousov NET_EPOCH_WAIT(); 676ef2a572bSKonstantin Belousov if ((i->flags & (IFP_HP_HANDLED | IFP_HP_REJECTED)) == 677ef2a572bSKonstantin Belousov IFP_HP_HANDLED) { 678ef2a572bSKonstantin Belousov printf("spd deinstall %s %p\n", if_name(i->ifp), sp); 679ef2a572bSKonstantin Belousov error = i->ifp->if_ipsec_accel_m->if_spddel(i->ifp, 680ef2a572bSKonstantin Belousov sp, i->ifdata); 681ef2a572bSKonstantin Belousov if (error != 0) { 682ef2a572bSKonstantin Belousov printf( 683ef2a572bSKonstantin Belousov "ipsec_accel_spddel: %s if_spddel %p res %d\n", 684ef2a572bSKonstantin Belousov if_name(i->ifp), sp, error); 685ef2a572bSKonstantin Belousov } 686ef2a572bSKonstantin Belousov } 687ef2a572bSKonstantin Belousov if_rele(i->ifp); 688ef2a572bSKonstantin Belousov free(i, M_IPSEC_MISC); 689ef2a572bSKonstantin Belousov mtx_lock(&ipsec_accel_sav_tmp); 690ef2a572bSKonstantin Belousov } 691ef2a572bSKonstantin Belousov mtx_unlock(&ipsec_accel_sav_tmp); 692ef2a572bSKonstantin Belousov key_freesp(&sp); 693ef2a572bSKonstantin Belousov CURVNET_RESTORE(); 694ef2a572bSKonstantin Belousov } 695ef2a572bSKonstantin Belousov 696ef2a572bSKonstantin Belousov void 697ef2a572bSKonstantin Belousov ipsec_accel_spddel_impl(struct secpolicy *sp) 698ef2a572bSKonstantin Belousov { 699ef2a572bSKonstantin Belousov struct ipsec_accel_adddel_sp_tq *tq; 700ef2a572bSKonstantin Belousov 701ef2a572bSKonstantin Belousov if (sp == NULL) 702ef2a572bSKonstantin Belousov return; 703ef2a572bSKonstantin Belousov 704ef2a572bSKonstantin Belousov tq = &sp->accel_del_tq; 705ef2a572bSKonstantin Belousov if (atomic_cmpset_int(&tq->adddel_scheduled, 0, 1) == 0) 706ef2a572bSKonstantin Belousov return; 707ef2a572bSKonstantin Belousov tq->adddel_vnet = curthread->td_vnet; 708ef2a572bSKonstantin Belousov TASK_INIT(&tq->adddel_task, 0, ipsec_accel_spddel_act, sp); 709ef2a572bSKonstantin Belousov key_addref(sp); 710ef2a572bSKonstantin Belousov taskqueue_enqueue(taskqueue_thread, &tq->adddel_task); 711ef2a572bSKonstantin Belousov } 712ef2a572bSKonstantin Belousov 713ef2a572bSKonstantin Belousov static void 714ef2a572bSKonstantin Belousov ipsec_accel_on_ifdown_sp(struct ifnet *ifp) 715ef2a572bSKonstantin Belousov { 716ef2a572bSKonstantin Belousov struct ifp_handle_sp *i, *marker; 717ef2a572bSKonstantin Belousov struct secpolicy *sp; 718ef2a572bSKonstantin Belousov int error; 719ef2a572bSKonstantin Belousov 720ef2a572bSKonstantin Belousov marker = malloc(sizeof(*marker), M_IPSEC_MISC, M_WAITOK | M_ZERO); 721ef2a572bSKonstantin Belousov marker->flags = IFP_HS_MARKER; 722ef2a572bSKonstantin Belousov 723ef2a572bSKonstantin Belousov mtx_lock(&ipsec_accel_sav_tmp); 724ef2a572bSKonstantin Belousov CK_LIST_INSERT_HEAD(&ipsec_accel_all_sp_handles, marker, 725ef2a572bSKonstantin Belousov sp_allh_link); 726ef2a572bSKonstantin Belousov for (;;) { 727ef2a572bSKonstantin Belousov i = CK_LIST_NEXT(marker, sp_allh_link); 728ef2a572bSKonstantin Belousov if (i == NULL) 729ef2a572bSKonstantin Belousov break; 730ef2a572bSKonstantin Belousov CK_LIST_REMOVE(marker, sp_allh_link); 731ef2a572bSKonstantin Belousov CK_LIST_INSERT_AFTER(i, marker, sp_allh_link); 732ef2a572bSKonstantin Belousov if (i->ifp != ifp) 733ef2a572bSKonstantin Belousov continue; 734ef2a572bSKonstantin Belousov 735ef2a572bSKonstantin Belousov sp = i->sp; 736ef2a572bSKonstantin Belousov key_addref(sp); 737ef2a572bSKonstantin Belousov CK_LIST_REMOVE(i, sp_link); 738ef2a572bSKonstantin Belousov CK_LIST_REMOVE(i, sp_allh_link); 739ef2a572bSKonstantin Belousov mtx_unlock(&ipsec_accel_sav_tmp); 740ef2a572bSKonstantin Belousov NET_EPOCH_WAIT(); 741ef2a572bSKonstantin Belousov if ((i->flags & (IFP_HP_HANDLED | IFP_HP_REJECTED)) == 742ef2a572bSKonstantin Belousov IFP_HP_HANDLED) { 743ef2a572bSKonstantin Belousov printf("spd deinstall %s %p\n", if_name(ifp), sp); 744ef2a572bSKonstantin Belousov error = ifp->if_ipsec_accel_m->if_spddel(ifp, 745ef2a572bSKonstantin Belousov sp, i->ifdata); 746ef2a572bSKonstantin Belousov } 747ef2a572bSKonstantin Belousov if (error != 0) { 748ef2a572bSKonstantin Belousov printf( 749ef2a572bSKonstantin Belousov "ipsec_accel_on_ifdown_sp: %s if_spddel %p res %d\n", 750ef2a572bSKonstantin Belousov if_name(ifp), sp, error); 751ef2a572bSKonstantin Belousov } 752ef2a572bSKonstantin Belousov key_freesp(&sp); 753ef2a572bSKonstantin Belousov if_rele(ifp); 754ef2a572bSKonstantin Belousov free(i, M_IPSEC_MISC); 755ef2a572bSKonstantin Belousov mtx_lock(&ipsec_accel_sav_tmp); 756ef2a572bSKonstantin Belousov } 757ef2a572bSKonstantin Belousov CK_LIST_REMOVE(marker, sp_allh_link); 758ef2a572bSKonstantin Belousov mtx_unlock(&ipsec_accel_sav_tmp); 759ef2a572bSKonstantin Belousov free(marker, M_IPSEC_MISC); 760ef2a572bSKonstantin Belousov } 761ef2a572bSKonstantin Belousov 762ef2a572bSKonstantin Belousov void 763ef2a572bSKonstantin Belousov ipsec_accel_on_ifdown(struct ifnet *ifp) 764ef2a572bSKonstantin Belousov { 765ef2a572bSKonstantin Belousov ipsec_accel_on_ifdown_sp(ifp); 766ef2a572bSKonstantin Belousov ipsec_accel_on_ifdown_sav(ifp); 767ef2a572bSKonstantin Belousov } 768ef2a572bSKonstantin Belousov 769ef2a572bSKonstantin Belousov static bool 770ef2a572bSKonstantin Belousov ipsec_accel_output_pad(struct mbuf *m, struct secasvar *sav, int skip, int mtu) 771ef2a572bSKonstantin Belousov { 772ef2a572bSKonstantin Belousov int alen, blks, hlen, padding, rlen; 773ef2a572bSKonstantin Belousov 774ef2a572bSKonstantin Belousov rlen = m->m_pkthdr.len - skip; 775ef2a572bSKonstantin Belousov hlen = ((sav->flags & SADB_X_EXT_OLD) != 0 ? sizeof(struct esp) : 776ef2a572bSKonstantin Belousov sizeof(struct newesp)) + sav->ivlen; 777ef2a572bSKonstantin Belousov blks = MAX(4, SAV_ISCTR(sav) && VNET(esp_ctr_compatibility) ? 778ef2a572bSKonstantin Belousov sav->tdb_encalgxform->native_blocksize : 779ef2a572bSKonstantin Belousov sav->tdb_encalgxform->blocksize); 780ef2a572bSKonstantin Belousov padding = ((blks - ((rlen + 2) % blks)) % blks) + 2; 781ef2a572bSKonstantin Belousov alen = xform_ah_authsize(sav->tdb_authalgxform); 782ef2a572bSKonstantin Belousov 783ef2a572bSKonstantin Belousov return (skip + hlen + rlen + padding + alen <= mtu); 784ef2a572bSKonstantin Belousov } 785ef2a572bSKonstantin Belousov 786ef2a572bSKonstantin Belousov static bool 787ef2a572bSKonstantin Belousov ipsec_accel_output_tag(struct mbuf *m, u_int drv_spi) 788ef2a572bSKonstantin Belousov { 789ef2a572bSKonstantin Belousov struct ipsec_accel_out_tag *tag; 790ef2a572bSKonstantin Belousov 791ef2a572bSKonstantin Belousov tag = (struct ipsec_accel_out_tag *)m_tag_get( 792ef2a572bSKonstantin Belousov PACKET_TAG_IPSEC_ACCEL_OUT, sizeof(*tag), M_NOWAIT); 793ef2a572bSKonstantin Belousov if (tag == NULL) 794ef2a572bSKonstantin Belousov return (false); 795ef2a572bSKonstantin Belousov tag->drv_spi = drv_spi; 796ef2a572bSKonstantin Belousov m_tag_prepend(m, &tag->tag); 797ef2a572bSKonstantin Belousov return (true); 798ef2a572bSKonstantin Belousov } 799ef2a572bSKonstantin Belousov 800ef2a572bSKonstantin Belousov bool 801ef2a572bSKonstantin Belousov ipsec_accel_output(struct ifnet *ifp, struct mbuf *m, struct inpcb *inp, 802*240b7bfeSKonstantin Belousov struct secpolicy *sp, struct secasvar *sav, int af, int mtu, int *hwassist) 803ef2a572bSKonstantin Belousov { 804ef2a572bSKonstantin Belousov struct ifp_handle_sav *i; 805ef2a572bSKonstantin Belousov struct ip *ip; 806ef2a572bSKonstantin Belousov u_long ip_len, skip; 807ef2a572bSKonstantin Belousov 808*240b7bfeSKonstantin Belousov *hwassist = 0; 809ef2a572bSKonstantin Belousov if (ifp == NULL) 810ef2a572bSKonstantin Belousov return (false); 811ef2a572bSKonstantin Belousov 812ef2a572bSKonstantin Belousov M_ASSERTPKTHDR(m); 813ef2a572bSKonstantin Belousov NET_EPOCH_ASSERT(); 814ef2a572bSKonstantin Belousov 815ef2a572bSKonstantin Belousov if (sav == NULL) 816ef2a572bSKonstantin Belousov return (ipsec_accel_output_tag(m, IPSEC_ACCEL_DRV_SPI_BYPASS)); 817ef2a572bSKonstantin Belousov 818ef2a572bSKonstantin Belousov i = ipsec_accel_is_accel_sav_ptr(sav, ifp); 819ef2a572bSKonstantin Belousov if (i == NULL) 820ef2a572bSKonstantin Belousov return (false); 821ef2a572bSKonstantin Belousov 822ef2a572bSKonstantin Belousov if ((m->m_pkthdr.csum_flags & CSUM_TSO) == 0) { 823ef2a572bSKonstantin Belousov ip_len = m->m_pkthdr.len; 824ef2a572bSKonstantin Belousov if (ip_len + i->hdr_ext_size > mtu) 825ef2a572bSKonstantin Belousov return (false); 826ef2a572bSKonstantin Belousov switch (af) { 827ef2a572bSKonstantin Belousov case AF_INET: 828ef2a572bSKonstantin Belousov ip = mtod(m, struct ip *); 829ef2a572bSKonstantin Belousov skip = ip->ip_hl << 2; 830ef2a572bSKonstantin Belousov break; 831ef2a572bSKonstantin Belousov case AF_INET6: 832ef2a572bSKonstantin Belousov skip = sizeof(struct ip6_hdr); 833ef2a572bSKonstantin Belousov break; 834ef2a572bSKonstantin Belousov default: 835ef2a572bSKonstantin Belousov __unreachable(); 836ef2a572bSKonstantin Belousov } 837ef2a572bSKonstantin Belousov if (!ipsec_accel_output_pad(m, sav, skip, mtu)) 838ef2a572bSKonstantin Belousov return (false); 839ef2a572bSKonstantin Belousov } 840ef2a572bSKonstantin Belousov 841ef2a572bSKonstantin Belousov if (!ipsec_accel_output_tag(m, i->drv_spi)) 842ef2a572bSKonstantin Belousov return (false); 843ef2a572bSKonstantin Belousov 844ef2a572bSKonstantin Belousov ipsec_accel_sa_recordxfer(sav, m); 845ef2a572bSKonstantin Belousov key_freesav(&sav); 846ef2a572bSKonstantin Belousov if (sp != NULL) 847ef2a572bSKonstantin Belousov key_freesp(&sp); 848ef2a572bSKonstantin Belousov 849*240b7bfeSKonstantin Belousov *hwassist = ifp->if_ipsec_accel_m->if_hwassist(ifp, sav, 850*240b7bfeSKonstantin Belousov i->drv_spi, i->ifdata); 851ef2a572bSKonstantin Belousov return (true); 852ef2a572bSKonstantin Belousov } 853ef2a572bSKonstantin Belousov 854ef2a572bSKonstantin Belousov struct ipsec_accel_in_tag * 855ef2a572bSKonstantin Belousov ipsec_accel_input_tag_lookup(const struct mbuf *m) 856ef2a572bSKonstantin Belousov { 857ef2a572bSKonstantin Belousov struct ipsec_accel_in_tag *tag; 858ef2a572bSKonstantin Belousov struct m_tag *xtag; 859ef2a572bSKonstantin Belousov 860ef2a572bSKonstantin Belousov xtag = m_tag_find(__DECONST(struct mbuf *, m), 861ef2a572bSKonstantin Belousov PACKET_TAG_IPSEC_ACCEL_IN, NULL); 862ef2a572bSKonstantin Belousov if (xtag == NULL) 863ef2a572bSKonstantin Belousov return (NULL); 864ef2a572bSKonstantin Belousov tag = __containerof(xtag, struct ipsec_accel_in_tag, tag); 865ef2a572bSKonstantin Belousov return (tag); 866ef2a572bSKonstantin Belousov } 867ef2a572bSKonstantin Belousov 868ef2a572bSKonstantin Belousov int 869ef2a572bSKonstantin Belousov ipsec_accel_input(struct mbuf *m, int offset, int proto) 870ef2a572bSKonstantin Belousov { 871ef2a572bSKonstantin Belousov struct secasvar *sav; 872ef2a572bSKonstantin Belousov struct ipsec_accel_in_tag *tag; 873ef2a572bSKonstantin Belousov 874ef2a572bSKonstantin Belousov tag = ipsec_accel_input_tag_lookup(m); 875ef2a572bSKonstantin Belousov if (tag == NULL) 876ef2a572bSKonstantin Belousov return (ENXIO); 877ef2a572bSKonstantin Belousov 878ef2a572bSKonstantin Belousov if (tag->drv_spi < IPSEC_ACCEL_DRV_SPI_MIN || 879ef2a572bSKonstantin Belousov tag->drv_spi > IPSEC_ACCEL_DRV_SPI_MAX) { 880ef2a572bSKonstantin Belousov printf("if %s mbuf %p drv_spi %d invalid, packet dropped\n", 881ef2a572bSKonstantin Belousov (m->m_flags & M_PKTHDR) != 0 ? if_name(m->m_pkthdr.rcvif) : 882ef2a572bSKonstantin Belousov "<unknwn>", m, tag->drv_spi); 883ef2a572bSKonstantin Belousov m_freem(m); 884ef2a572bSKonstantin Belousov return (EINPROGRESS); 885ef2a572bSKonstantin Belousov } 886ef2a572bSKonstantin Belousov 887ef2a572bSKonstantin Belousov sav = ipsec_accel_drvspi_to_sa(tag->drv_spi); 888ef2a572bSKonstantin Belousov if (sav != NULL) 889ef2a572bSKonstantin Belousov ipsec_accel_sa_recordxfer(sav, m); 890ef2a572bSKonstantin Belousov return (0); 891ef2a572bSKonstantin Belousov } 892ef2a572bSKonstantin Belousov 893ef2a572bSKonstantin Belousov static void 894ef2a572bSKonstantin Belousov ipsec_accel_sa_recordxfer(struct secasvar *sav, struct mbuf *m) 895ef2a572bSKonstantin Belousov { 896ef2a572bSKonstantin Belousov counter_u64_add(sav->accel_lft_sw, 1); 897ef2a572bSKonstantin Belousov counter_u64_add(sav->accel_lft_sw + 1, m->m_pkthdr.len); 898ef2a572bSKonstantin Belousov if (sav->accel_firstused == 0) 899ef2a572bSKonstantin Belousov sav->accel_firstused = time_second; 900ef2a572bSKonstantin Belousov } 901ef2a572bSKonstantin Belousov 902ef2a572bSKonstantin Belousov static void 903ef2a572bSKonstantin Belousov ipsec_accel_sa_lifetime_update(struct seclifetime *lft_c, 904ef2a572bSKonstantin Belousov const struct seclifetime *lft_l) 905ef2a572bSKonstantin Belousov { 906ef2a572bSKonstantin Belousov lft_c->allocations += lft_l->allocations; 907ef2a572bSKonstantin Belousov lft_c->bytes += lft_l->bytes; 908ef2a572bSKonstantin Belousov lft_c->usetime = min(lft_c->usetime, lft_l->usetime); 909ef2a572bSKonstantin Belousov } 910ef2a572bSKonstantin Belousov 911ef2a572bSKonstantin Belousov void 912ef2a572bSKonstantin Belousov ipsec_accel_drv_sa_lifetime_update(struct secasvar *sav, if_t ifp, 913ef2a572bSKonstantin Belousov u_int drv_spi, uint64_t octets, uint64_t allocs) 914ef2a572bSKonstantin Belousov { 915ef2a572bSKonstantin Belousov struct epoch_tracker et; 916ef2a572bSKonstantin Belousov struct ifp_handle_sav *i; 917ef2a572bSKonstantin Belousov uint64_t odiff, adiff; 918ef2a572bSKonstantin Belousov 919ef2a572bSKonstantin Belousov NET_EPOCH_ENTER(et); 920ef2a572bSKonstantin Belousov mtx_lock(&ipsec_accel_cnt_lock); 921ef2a572bSKonstantin Belousov 922ef2a572bSKonstantin Belousov if (allocs != 0) { 923ef2a572bSKonstantin Belousov if (sav->firstused == 0) 924ef2a572bSKonstantin Belousov sav->firstused = time_second; 925ef2a572bSKonstantin Belousov if (sav->accel_firstused == 0) 926ef2a572bSKonstantin Belousov sav->accel_firstused = time_second; 927ef2a572bSKonstantin Belousov } 928ef2a572bSKonstantin Belousov 929ef2a572bSKonstantin Belousov CK_LIST_FOREACH(i, &sav->accel_ifps, sav_link) { 930ef2a572bSKonstantin Belousov if (i->ifp == ifp && i->drv_spi == drv_spi) 931ef2a572bSKonstantin Belousov break; 932ef2a572bSKonstantin Belousov } 933ef2a572bSKonstantin Belousov if (i == NULL) 934ef2a572bSKonstantin Belousov goto out; 935ef2a572bSKonstantin Belousov 936ef2a572bSKonstantin Belousov odiff = octets - i->cnt_octets; 937ef2a572bSKonstantin Belousov adiff = allocs - i->cnt_allocs; 938ef2a572bSKonstantin Belousov 939ef2a572bSKonstantin Belousov if (sav->lft_c != NULL) { 940ef2a572bSKonstantin Belousov counter_u64_add(sav->lft_c_bytes, odiff); 941ef2a572bSKonstantin Belousov counter_u64_add(sav->lft_c_allocations, adiff); 942ef2a572bSKonstantin Belousov } 943ef2a572bSKonstantin Belousov 944ef2a572bSKonstantin Belousov i->cnt_octets = octets; 945ef2a572bSKonstantin Belousov i->cnt_allocs = allocs; 946ef2a572bSKonstantin Belousov sav->accel_hw_octets += odiff; 947ef2a572bSKonstantin Belousov sav->accel_hw_allocs += adiff; 948ef2a572bSKonstantin Belousov 949ef2a572bSKonstantin Belousov out: 950ef2a572bSKonstantin Belousov mtx_unlock(&ipsec_accel_cnt_lock); 951ef2a572bSKonstantin Belousov NET_EPOCH_EXIT(et); 952ef2a572bSKonstantin Belousov } 953ef2a572bSKonstantin Belousov 954ef2a572bSKonstantin Belousov static void 955ef2a572bSKonstantin Belousov ipsec_accel_sa_lifetime_hw(struct secasvar *sav, if_t ifp, 956ef2a572bSKonstantin Belousov struct seclifetime *lft) 957ef2a572bSKonstantin Belousov { 958ef2a572bSKonstantin Belousov struct ifp_handle_sav *i; 959ef2a572bSKonstantin Belousov if_sa_cnt_fn_t p; 960ef2a572bSKonstantin Belousov 961ef2a572bSKonstantin Belousov IFNET_RLOCK_ASSERT(); 962ef2a572bSKonstantin Belousov 963ef2a572bSKonstantin Belousov i = ipsec_accel_is_accel_sav_ptr(sav, ifp); 964ef2a572bSKonstantin Belousov if (i != NULL && (i->flags & (IFP_HS_HANDLED | IFP_HS_REJECTED)) == 965ef2a572bSKonstantin Belousov IFP_HS_HANDLED) { 966ef2a572bSKonstantin Belousov p = ifp->if_ipsec_accel_m->if_sa_cnt; 967ef2a572bSKonstantin Belousov if (p != NULL) 968ef2a572bSKonstantin Belousov p(ifp, sav, i->drv_spi, i->ifdata, lft); 969ef2a572bSKonstantin Belousov } 970ef2a572bSKonstantin Belousov } 971ef2a572bSKonstantin Belousov 972ef2a572bSKonstantin Belousov static int 973ef2a572bSKonstantin Belousov ipsec_accel_sa_lifetime_op_impl(struct secasvar *sav, 974ef2a572bSKonstantin Belousov struct seclifetime *lft_c, if_t ifp, enum IF_SA_CNT_WHICH op, 975ef2a572bSKonstantin Belousov struct rm_priotracker *sahtree_trackerp) 976ef2a572bSKonstantin Belousov { 977ef2a572bSKonstantin Belousov struct seclifetime lft_l, lft_s; 978ef2a572bSKonstantin Belousov struct ifp_handle_sav *i; 979ef2a572bSKonstantin Belousov if_t ifp1; 980ef2a572bSKonstantin Belousov if_sa_cnt_fn_t p; 981ef2a572bSKonstantin Belousov int error; 982ef2a572bSKonstantin Belousov 983ef2a572bSKonstantin Belousov error = 0; 984ef2a572bSKonstantin Belousov memset(&lft_l, 0, sizeof(lft_l)); 985ef2a572bSKonstantin Belousov memset(&lft_s, 0, sizeof(lft_s)); 986ef2a572bSKonstantin Belousov 987ef2a572bSKonstantin Belousov switch (op & ~IF_SA_CNT_UPD) { 988ef2a572bSKonstantin Belousov case IF_SA_CNT_IFP_HW_VAL: 989ef2a572bSKonstantin Belousov ipsec_accel_sa_lifetime_hw(sav, ifp, &lft_l); 990ef2a572bSKonstantin Belousov ipsec_accel_sa_lifetime_update(&lft_l, &lft_s); 991ef2a572bSKonstantin Belousov break; 992ef2a572bSKonstantin Belousov 993ef2a572bSKonstantin Belousov case IF_SA_CNT_TOTAL_SW_VAL: 994ef2a572bSKonstantin Belousov lft_l.allocations = (uint32_t)counter_u64_fetch( 995ef2a572bSKonstantin Belousov sav->accel_lft_sw); 996ef2a572bSKonstantin Belousov lft_l.bytes = counter_u64_fetch(sav->accel_lft_sw + 1); 997ef2a572bSKonstantin Belousov lft_l.usetime = sav->accel_firstused; 998ef2a572bSKonstantin Belousov break; 999ef2a572bSKonstantin Belousov 1000ef2a572bSKonstantin Belousov case IF_SA_CNT_TOTAL_HW_VAL: 1001ef2a572bSKonstantin Belousov IFNET_RLOCK_ASSERT(); 1002ef2a572bSKonstantin Belousov CK_LIST_FOREACH(i, &sav->accel_ifps, sav_link) { 1003ef2a572bSKonstantin Belousov if ((i->flags & (IFP_HS_HANDLED | IFP_HS_REJECTED)) != 1004ef2a572bSKonstantin Belousov IFP_HS_HANDLED) 1005ef2a572bSKonstantin Belousov continue; 1006ef2a572bSKonstantin Belousov ifp1 = i->ifp; 1007ef2a572bSKonstantin Belousov p = ifp1->if_ipsec_accel_m->if_sa_cnt; 1008ef2a572bSKonstantin Belousov if (p == NULL) 1009ef2a572bSKonstantin Belousov continue; 1010ef2a572bSKonstantin Belousov memset(&lft_s, 0, sizeof(lft_s)); 1011ef2a572bSKonstantin Belousov if (sahtree_trackerp != NULL) 1012ef2a572bSKonstantin Belousov ipsec_sahtree_runlock(sahtree_trackerp); 1013ef2a572bSKonstantin Belousov error = p(ifp1, sav, i->drv_spi, i->ifdata, &lft_s); 1014ef2a572bSKonstantin Belousov if (sahtree_trackerp != NULL) 1015ef2a572bSKonstantin Belousov ipsec_sahtree_rlock(sahtree_trackerp); 1016ef2a572bSKonstantin Belousov if (error == 0) 1017ef2a572bSKonstantin Belousov ipsec_accel_sa_lifetime_update(&lft_l, &lft_s); 1018ef2a572bSKonstantin Belousov } 1019ef2a572bSKonstantin Belousov break; 1020ef2a572bSKonstantin Belousov } 1021ef2a572bSKonstantin Belousov 1022ef2a572bSKonstantin Belousov if (error == 0) { 1023ef2a572bSKonstantin Belousov if ((op & IF_SA_CNT_UPD) == 0) 1024ef2a572bSKonstantin Belousov memset(lft_c, 0, sizeof(*lft_c)); 1025ef2a572bSKonstantin Belousov ipsec_accel_sa_lifetime_update(lft_c, &lft_l); 1026ef2a572bSKonstantin Belousov } 1027ef2a572bSKonstantin Belousov 1028ef2a572bSKonstantin Belousov return (error); 1029ef2a572bSKonstantin Belousov } 1030ef2a572bSKonstantin Belousov 1031ef2a572bSKonstantin Belousov static void 1032ef2a572bSKonstantin Belousov ipsec_accel_sync_imp(void) 1033ef2a572bSKonstantin Belousov { 1034ef2a572bSKonstantin Belousov taskqueue_drain_all(taskqueue_thread); 1035ef2a572bSKonstantin Belousov } 1036ef2a572bSKonstantin Belousov 1037ef2a572bSKonstantin Belousov static struct mbuf * 1038ef2a572bSKonstantin Belousov ipsec_accel_key_setaccelif_impl(struct secasvar *sav) 1039ef2a572bSKonstantin Belousov { 1040ef2a572bSKonstantin Belousov struct mbuf *m, *m1; 1041ef2a572bSKonstantin Belousov struct ifp_handle_sav *i; 1042ef2a572bSKonstantin Belousov struct epoch_tracker et; 1043ef2a572bSKonstantin Belousov 1044ef2a572bSKonstantin Belousov if (sav->accel_ifname != NULL) 1045ef2a572bSKonstantin Belousov return (key_setaccelif(sav->accel_ifname)); 1046ef2a572bSKonstantin Belousov 1047ef2a572bSKonstantin Belousov m = m1 = NULL; 1048ef2a572bSKonstantin Belousov 1049ef2a572bSKonstantin Belousov NET_EPOCH_ENTER(et); 1050ef2a572bSKonstantin Belousov CK_LIST_FOREACH(i, &sav->accel_ifps, sav_link) { 1051ef2a572bSKonstantin Belousov if ((i->flags & (IFP_HS_HANDLED | IFP_HS_REJECTED)) == 1052ef2a572bSKonstantin Belousov IFP_HS_HANDLED) { 1053ef2a572bSKonstantin Belousov m1 = key_setaccelif(if_name(i->ifp)); 1054ef2a572bSKonstantin Belousov if (m == NULL) 1055ef2a572bSKonstantin Belousov m = m1; 1056ef2a572bSKonstantin Belousov else if (m1 != NULL) 1057ef2a572bSKonstantin Belousov m_cat(m, m1); 1058ef2a572bSKonstantin Belousov } 1059ef2a572bSKonstantin Belousov } 1060ef2a572bSKonstantin Belousov NET_EPOCH_EXIT(et); 1061ef2a572bSKonstantin Belousov return (m); 1062ef2a572bSKonstantin Belousov } 1063ef2a572bSKonstantin Belousov 1064ef2a572bSKonstantin Belousov #endif /* IPSEC_OFFLOAD */ 1065