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