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