1457c8996SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * xfrm_state.c 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * Changes: 61da177e4SLinus Torvalds * Mitsuru KANDA @USAGI 71da177e4SLinus Torvalds * Kazunori MIYAZAWA @USAGI 81da177e4SLinus Torvalds * Kunihiro Ishiguro <kunihiro@ipinfusion.com> 91da177e4SLinus Torvalds * IPv6 support 101da177e4SLinus Torvalds * YOSHIFUJI Hideaki @USAGI 111da177e4SLinus Torvalds * Split up af-specific functions 121da177e4SLinus Torvalds * Derek Atkins <derek@ihtfp.com> 131da177e4SLinus Torvalds * Add UDP Encapsulation 141da177e4SLinus Torvalds * 151da177e4SLinus Torvalds */ 161da177e4SLinus Torvalds 17b6459415SJakub Kicinski #include <linux/compat.h> 181da177e4SLinus Torvalds #include <linux/workqueue.h> 191da177e4SLinus Torvalds #include <net/xfrm.h> 201da177e4SLinus Torvalds #include <linux/pfkeyv2.h> 211da177e4SLinus Torvalds #include <linux/ipsec.h> 221da177e4SLinus Torvalds #include <linux/module.h> 23f034b5d4SDavid S. Miller #include <linux/cache.h> 2468277accSPaul Moore #include <linux/audit.h> 257c0f6ba6SLinus Torvalds #include <linux/uaccess.h> 269e0d57fdSYury Polyanskiy #include <linux/ktime.h> 275a0e3ad6STejun Heo #include <linux/slab.h> 289e0d57fdSYury Polyanskiy #include <linux/interrupt.h> 299e0d57fdSYury Polyanskiy #include <linux/kernel.h> 301da177e4SLinus Torvalds 31c7b37c76SFlorian Westphal #include <crypto/aead.h> 32c7b37c76SFlorian Westphal 3344e36b42SDavid S. Miller #include "xfrm_hash.h" 3444e36b42SDavid S. Miller 35c8406998SFlorian Westphal #define xfrm_state_deref_prot(table, net) \ 36c8406998SFlorian Westphal rcu_dereference_protected((table), lockdep_is_held(&(net)->xfrm.xfrm_state_lock)) 37c8406998SFlorian Westphal 3835db57bbSFlorian Westphal static void xfrm_state_gc_task(struct work_struct *work); 3935db57bbSFlorian Westphal 401da177e4SLinus Torvalds /* Each xfrm_state may be linked to two tables: 411da177e4SLinus Torvalds 421da177e4SLinus Torvalds 1. Hash table by (spi,daddr,ah/esp) to find SA by SPI. (input,ctl) 43a624c108SDavid S. Miller 2. Hash table by (daddr,family,reqid) to find what SAs exist for given 441da177e4SLinus Torvalds destination/tunnel endpoint. (output) 451da177e4SLinus Torvalds */ 461da177e4SLinus Torvalds 47f034b5d4SDavid S. Miller static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024; 48565f0fa9SMathias Krause static struct kmem_cache *xfrm_state_cache __ro_after_init; 491da177e4SLinus Torvalds 5035db57bbSFlorian Westphal static DECLARE_WORK(xfrm_state_gc_work, xfrm_state_gc_task); 5135db57bbSFlorian Westphal static HLIST_HEAD(xfrm_state_gc_list); 5235db57bbSFlorian Westphal 5302efdff7SFlorian Westphal static inline bool xfrm_state_hold_rcu(struct xfrm_state __rcu *x) 5402efdff7SFlorian Westphal { 5588755e9cSReshetova, Elena return refcount_inc_not_zero(&x->refcnt); 5602efdff7SFlorian Westphal } 5702efdff7SFlorian Westphal 5864d0cd00SAlexey Dobriyan static inline unsigned int xfrm_dst_hash(struct net *net, 592ab38503SDavid S. Miller const xfrm_address_t *daddr, 602ab38503SDavid S. Miller const xfrm_address_t *saddr, 61c1969f29SDavid S. Miller u32 reqid, 62a624c108SDavid S. Miller unsigned short family) 63a624c108SDavid S. Miller { 6464d0cd00SAlexey Dobriyan return __xfrm_dst_hash(daddr, saddr, reqid, family, net->xfrm.state_hmask); 65a624c108SDavid S. Miller } 66a624c108SDavid S. Miller 6764d0cd00SAlexey Dobriyan static inline unsigned int xfrm_src_hash(struct net *net, 682ab38503SDavid S. Miller const xfrm_address_t *daddr, 692ab38503SDavid S. Miller const xfrm_address_t *saddr, 7044e36b42SDavid S. Miller unsigned short family) 71f034b5d4SDavid S. Miller { 7264d0cd00SAlexey Dobriyan return __xfrm_src_hash(daddr, saddr, family, net->xfrm.state_hmask); 73f034b5d4SDavid S. Miller } 74f034b5d4SDavid S. Miller 752575b654SDavid S. Miller static inline unsigned int 762ab38503SDavid S. Miller xfrm_spi_hash(struct net *net, const xfrm_address_t *daddr, 772ab38503SDavid S. Miller __be32 spi, u8 proto, unsigned short family) 78f034b5d4SDavid S. Miller { 7964d0cd00SAlexey Dobriyan return __xfrm_spi_hash(daddr, spi, proto, family, net->xfrm.state_hmask); 80f034b5d4SDavid S. Miller } 81f034b5d4SDavid S. Miller 82fe9f1d87SSabrina Dubroca static unsigned int xfrm_seq_hash(struct net *net, u32 seq) 83fe9f1d87SSabrina Dubroca { 84fe9f1d87SSabrina Dubroca return __xfrm_seq_hash(seq, net->xfrm.state_hmask); 85fe9f1d87SSabrina Dubroca } 86fe9f1d87SSabrina Dubroca 87*3c611d40SLeon Romanovsky #define XFRM_STATE_INSERT(by, _n, _h, _type) \ 88*3c611d40SLeon Romanovsky { \ 89*3c611d40SLeon Romanovsky struct xfrm_state *_x = NULL; \ 90*3c611d40SLeon Romanovsky \ 91*3c611d40SLeon Romanovsky if (_type != XFRM_DEV_OFFLOAD_PACKET) { \ 92*3c611d40SLeon Romanovsky hlist_for_each_entry_rcu(_x, _h, by) { \ 93*3c611d40SLeon Romanovsky if (_x->xso.type == XFRM_DEV_OFFLOAD_PACKET) \ 94*3c611d40SLeon Romanovsky continue; \ 95*3c611d40SLeon Romanovsky break; \ 96*3c611d40SLeon Romanovsky } \ 97*3c611d40SLeon Romanovsky } \ 98*3c611d40SLeon Romanovsky \ 99*3c611d40SLeon Romanovsky if (!_x || _x->xso.type == XFRM_DEV_OFFLOAD_PACKET) \ 100*3c611d40SLeon Romanovsky /* SAD is empty or consist from HW SAs only */ \ 101*3c611d40SLeon Romanovsky hlist_add_head_rcu(_n, _h); \ 102*3c611d40SLeon Romanovsky else \ 103*3c611d40SLeon Romanovsky hlist_add_before_rcu(_n, &_x->by); \ 104*3c611d40SLeon Romanovsky } 105*3c611d40SLeon Romanovsky 106f034b5d4SDavid S. Miller static void xfrm_hash_transfer(struct hlist_head *list, 107f034b5d4SDavid S. Miller struct hlist_head *ndsttable, 108f034b5d4SDavid S. Miller struct hlist_head *nsrctable, 109f034b5d4SDavid S. Miller struct hlist_head *nspitable, 110fe9f1d87SSabrina Dubroca struct hlist_head *nseqtable, 111f034b5d4SDavid S. Miller unsigned int nhashmask) 112f034b5d4SDavid S. Miller { 113b67bfe0dSSasha Levin struct hlist_node *tmp; 114f034b5d4SDavid S. Miller struct xfrm_state *x; 115f034b5d4SDavid S. Miller 116b67bfe0dSSasha Levin hlist_for_each_entry_safe(x, tmp, list, bydst) { 117f034b5d4SDavid S. Miller unsigned int h; 118f034b5d4SDavid S. Miller 119c1969f29SDavid S. Miller h = __xfrm_dst_hash(&x->id.daddr, &x->props.saddr, 120c1969f29SDavid S. Miller x->props.reqid, x->props.family, 121c1969f29SDavid S. Miller nhashmask); 122*3c611d40SLeon Romanovsky XFRM_STATE_INSERT(bydst, &x->bydst, ndsttable + h, x->xso.type); 123f034b5d4SDavid S. Miller 124667bbcb6SMasahide NAKAMURA h = __xfrm_src_hash(&x->id.daddr, &x->props.saddr, 125667bbcb6SMasahide NAKAMURA x->props.family, 126f034b5d4SDavid S. Miller nhashmask); 127*3c611d40SLeon Romanovsky XFRM_STATE_INSERT(bysrc, &x->bysrc, nsrctable + h, x->xso.type); 128f034b5d4SDavid S. Miller 1297b4dc360SMasahide NAKAMURA if (x->id.spi) { 1307b4dc360SMasahide NAKAMURA h = __xfrm_spi_hash(&x->id.daddr, x->id.spi, 1317b4dc360SMasahide NAKAMURA x->id.proto, x->props.family, 1327b4dc360SMasahide NAKAMURA nhashmask); 133*3c611d40SLeon Romanovsky XFRM_STATE_INSERT(byspi, &x->byspi, nspitable + h, 134*3c611d40SLeon Romanovsky x->xso.type); 135f034b5d4SDavid S. Miller } 136fe9f1d87SSabrina Dubroca 137fe9f1d87SSabrina Dubroca if (x->km.seq) { 138fe9f1d87SSabrina Dubroca h = __xfrm_seq_hash(x->km.seq, nhashmask); 139*3c611d40SLeon Romanovsky XFRM_STATE_INSERT(byseq, &x->byseq, nseqtable + h, 140*3c611d40SLeon Romanovsky x->xso.type); 141fe9f1d87SSabrina Dubroca } 142f034b5d4SDavid S. Miller } 1437b4dc360SMasahide NAKAMURA } 144f034b5d4SDavid S. Miller 14563082733SAlexey Dobriyan static unsigned long xfrm_hash_new_size(unsigned int state_hmask) 146f034b5d4SDavid S. Miller { 14763082733SAlexey Dobriyan return ((state_hmask + 1) << 1) * sizeof(struct hlist_head); 148f034b5d4SDavid S. Miller } 149f034b5d4SDavid S. Miller 15063082733SAlexey Dobriyan static void xfrm_hash_resize(struct work_struct *work) 151f034b5d4SDavid S. Miller { 15263082733SAlexey Dobriyan struct net *net = container_of(work, struct net, xfrm.state_hash_work); 153fe9f1d87SSabrina Dubroca struct hlist_head *ndst, *nsrc, *nspi, *nseq, *odst, *osrc, *ospi, *oseq; 154f034b5d4SDavid S. Miller unsigned long nsize, osize; 155f034b5d4SDavid S. Miller unsigned int nhashmask, ohashmask; 156f034b5d4SDavid S. Miller int i; 157f034b5d4SDavid S. Miller 15863082733SAlexey Dobriyan nsize = xfrm_hash_new_size(net->xfrm.state_hmask); 15944e36b42SDavid S. Miller ndst = xfrm_hash_alloc(nsize); 160f034b5d4SDavid S. Miller if (!ndst) 1610244790cSYing Xue return; 16244e36b42SDavid S. Miller nsrc = xfrm_hash_alloc(nsize); 163f034b5d4SDavid S. Miller if (!nsrc) { 16444e36b42SDavid S. Miller xfrm_hash_free(ndst, nsize); 1650244790cSYing Xue return; 166f034b5d4SDavid S. Miller } 16744e36b42SDavid S. Miller nspi = xfrm_hash_alloc(nsize); 168f034b5d4SDavid S. Miller if (!nspi) { 16944e36b42SDavid S. Miller xfrm_hash_free(ndst, nsize); 17044e36b42SDavid S. Miller xfrm_hash_free(nsrc, nsize); 1710244790cSYing Xue return; 172f034b5d4SDavid S. Miller } 173fe9f1d87SSabrina Dubroca nseq = xfrm_hash_alloc(nsize); 174fe9f1d87SSabrina Dubroca if (!nseq) { 175fe9f1d87SSabrina Dubroca xfrm_hash_free(ndst, nsize); 176fe9f1d87SSabrina Dubroca xfrm_hash_free(nsrc, nsize); 177fe9f1d87SSabrina Dubroca xfrm_hash_free(nspi, nsize); 178fe9f1d87SSabrina Dubroca return; 179fe9f1d87SSabrina Dubroca } 180f034b5d4SDavid S. Miller 181283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 182e88add19SAhmed S. Darwish write_seqcount_begin(&net->xfrm.xfrm_state_hash_generation); 183f034b5d4SDavid S. Miller 184f034b5d4SDavid S. Miller nhashmask = (nsize / sizeof(struct hlist_head)) - 1U; 185c8406998SFlorian Westphal odst = xfrm_state_deref_prot(net->xfrm.state_bydst, net); 18663082733SAlexey Dobriyan for (i = net->xfrm.state_hmask; i >= 0; i--) 187fe9f1d87SSabrina Dubroca xfrm_hash_transfer(odst + i, ndst, nsrc, nspi, nseq, nhashmask); 188f034b5d4SDavid S. Miller 189c8406998SFlorian Westphal osrc = xfrm_state_deref_prot(net->xfrm.state_bysrc, net); 190c8406998SFlorian Westphal ospi = xfrm_state_deref_prot(net->xfrm.state_byspi, net); 191fe9f1d87SSabrina Dubroca oseq = xfrm_state_deref_prot(net->xfrm.state_byseq, net); 19263082733SAlexey Dobriyan ohashmask = net->xfrm.state_hmask; 193f034b5d4SDavid S. Miller 194c8406998SFlorian Westphal rcu_assign_pointer(net->xfrm.state_bydst, ndst); 195c8406998SFlorian Westphal rcu_assign_pointer(net->xfrm.state_bysrc, nsrc); 196c8406998SFlorian Westphal rcu_assign_pointer(net->xfrm.state_byspi, nspi); 197fe9f1d87SSabrina Dubroca rcu_assign_pointer(net->xfrm.state_byseq, nseq); 19863082733SAlexey Dobriyan net->xfrm.state_hmask = nhashmask; 199f034b5d4SDavid S. Miller 200e88add19SAhmed S. Darwish write_seqcount_end(&net->xfrm.xfrm_state_hash_generation); 201283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 202f034b5d4SDavid S. Miller 203f034b5d4SDavid S. Miller osize = (ohashmask + 1) * sizeof(struct hlist_head); 204df7274ebSFlorian Westphal 205df7274ebSFlorian Westphal synchronize_rcu(); 206df7274ebSFlorian Westphal 20744e36b42SDavid S. Miller xfrm_hash_free(odst, osize); 20844e36b42SDavid S. Miller xfrm_hash_free(osrc, osize); 20944e36b42SDavid S. Miller xfrm_hash_free(ospi, osize); 210fe9f1d87SSabrina Dubroca xfrm_hash_free(oseq, osize); 211f034b5d4SDavid S. Miller } 212f034b5d4SDavid S. Miller 21344abdc30SCong Wang static DEFINE_SPINLOCK(xfrm_state_afinfo_lock); 21444abdc30SCong Wang static struct xfrm_state_afinfo __rcu *xfrm_state_afinfo[NPROTO]; 2151da177e4SLinus Torvalds 2161da177e4SLinus Torvalds static DEFINE_SPINLOCK(xfrm_state_gc_lock); 2171da177e4SLinus Torvalds 21853bc6b4dSJamal Hadi Salim int __xfrm_state_delete(struct xfrm_state *x); 2191da177e4SLinus Torvalds 220980ebd25SJamal Hadi Salim int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol); 221bb9cd077SFlorian Westphal static bool km_is_alive(const struct km_event *c); 22215e47304SEric W. Biederman void km_state_expired(struct xfrm_state *x, int hard, u32 portid); 2231da177e4SLinus Torvalds 224533cb5b0SEric Dumazet int xfrm_register_type(const struct xfrm_type *type, unsigned short family) 225aa5d62ccSHerbert Xu { 2267a9885b9SCong Wang struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); 227aa5d62ccSHerbert Xu int err = 0; 228aa5d62ccSHerbert Xu 2294f518e80SFlorian Westphal if (!afinfo) 230aa5d62ccSHerbert Xu return -EAFNOSUPPORT; 231aa5d62ccSHerbert Xu 2324f518e80SFlorian Westphal #define X(afi, T, name) do { \ 2334f518e80SFlorian Westphal WARN_ON((afi)->type_ ## name); \ 2344f518e80SFlorian Westphal (afi)->type_ ## name = (T); \ 2354f518e80SFlorian Westphal } while (0) 2364f518e80SFlorian Westphal 2374f518e80SFlorian Westphal switch (type->proto) { 2384f518e80SFlorian Westphal case IPPROTO_COMP: 2394f518e80SFlorian Westphal X(afinfo, type, comp); 2404f518e80SFlorian Westphal break; 2414f518e80SFlorian Westphal case IPPROTO_AH: 2424f518e80SFlorian Westphal X(afinfo, type, ah); 2434f518e80SFlorian Westphal break; 2444f518e80SFlorian Westphal case IPPROTO_ESP: 2454f518e80SFlorian Westphal X(afinfo, type, esp); 2464f518e80SFlorian Westphal break; 2474f518e80SFlorian Westphal case IPPROTO_IPIP: 2484f518e80SFlorian Westphal X(afinfo, type, ipip); 2494f518e80SFlorian Westphal break; 2504f518e80SFlorian Westphal case IPPROTO_DSTOPTS: 2514f518e80SFlorian Westphal X(afinfo, type, dstopts); 2524f518e80SFlorian Westphal break; 2534f518e80SFlorian Westphal case IPPROTO_ROUTING: 2544f518e80SFlorian Westphal X(afinfo, type, routing); 2554f518e80SFlorian Westphal break; 2564f518e80SFlorian Westphal case IPPROTO_IPV6: 2574f518e80SFlorian Westphal X(afinfo, type, ipip6); 2584f518e80SFlorian Westphal break; 2594f518e80SFlorian Westphal default: 2604f518e80SFlorian Westphal WARN_ON(1); 2614f518e80SFlorian Westphal err = -EPROTONOSUPPORT; 2624f518e80SFlorian Westphal break; 2634f518e80SFlorian Westphal } 2644f518e80SFlorian Westphal #undef X 265af5d27c4SFlorian Westphal rcu_read_unlock(); 266aa5d62ccSHerbert Xu return err; 267aa5d62ccSHerbert Xu } 268aa5d62ccSHerbert Xu EXPORT_SYMBOL(xfrm_register_type); 269aa5d62ccSHerbert Xu 2704f518e80SFlorian Westphal void xfrm_unregister_type(const struct xfrm_type *type, unsigned short family) 271aa5d62ccSHerbert Xu { 2727a9885b9SCong Wang struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); 273aa5d62ccSHerbert Xu 274aa5d62ccSHerbert Xu if (unlikely(afinfo == NULL)) 2754f518e80SFlorian Westphal return; 276aa5d62ccSHerbert Xu 2774f518e80SFlorian Westphal #define X(afi, T, name) do { \ 2784f518e80SFlorian Westphal WARN_ON((afi)->type_ ## name != (T)); \ 2794f518e80SFlorian Westphal (afi)->type_ ## name = NULL; \ 2804f518e80SFlorian Westphal } while (0) 2814f518e80SFlorian Westphal 2824f518e80SFlorian Westphal switch (type->proto) { 2834f518e80SFlorian Westphal case IPPROTO_COMP: 2844f518e80SFlorian Westphal X(afinfo, type, comp); 2854f518e80SFlorian Westphal break; 2864f518e80SFlorian Westphal case IPPROTO_AH: 2874f518e80SFlorian Westphal X(afinfo, type, ah); 2884f518e80SFlorian Westphal break; 2894f518e80SFlorian Westphal case IPPROTO_ESP: 2904f518e80SFlorian Westphal X(afinfo, type, esp); 2914f518e80SFlorian Westphal break; 2924f518e80SFlorian Westphal case IPPROTO_IPIP: 2934f518e80SFlorian Westphal X(afinfo, type, ipip); 2944f518e80SFlorian Westphal break; 2954f518e80SFlorian Westphal case IPPROTO_DSTOPTS: 2964f518e80SFlorian Westphal X(afinfo, type, dstopts); 2974f518e80SFlorian Westphal break; 2984f518e80SFlorian Westphal case IPPROTO_ROUTING: 2994f518e80SFlorian Westphal X(afinfo, type, routing); 3004f518e80SFlorian Westphal break; 3014f518e80SFlorian Westphal case IPPROTO_IPV6: 3024f518e80SFlorian Westphal X(afinfo, type, ipip6); 3034f518e80SFlorian Westphal break; 3044f518e80SFlorian Westphal default: 3054f518e80SFlorian Westphal WARN_ON(1); 3064f518e80SFlorian Westphal break; 3074f518e80SFlorian Westphal } 3084f518e80SFlorian Westphal #undef X 309af5d27c4SFlorian Westphal rcu_read_unlock(); 310aa5d62ccSHerbert Xu } 311aa5d62ccSHerbert Xu EXPORT_SYMBOL(xfrm_unregister_type); 312aa5d62ccSHerbert Xu 313533cb5b0SEric Dumazet static const struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family) 314aa5d62ccSHerbert Xu { 3154f518e80SFlorian Westphal const struct xfrm_type *type = NULL; 316aa5d62ccSHerbert Xu struct xfrm_state_afinfo *afinfo; 317aa5d62ccSHerbert Xu int modload_attempted = 0; 318aa5d62ccSHerbert Xu 319aa5d62ccSHerbert Xu retry: 320aa5d62ccSHerbert Xu afinfo = xfrm_state_get_afinfo(family); 321aa5d62ccSHerbert Xu if (unlikely(afinfo == NULL)) 322aa5d62ccSHerbert Xu return NULL; 323aa5d62ccSHerbert Xu 3244f518e80SFlorian Westphal switch (proto) { 3254f518e80SFlorian Westphal case IPPROTO_COMP: 3264f518e80SFlorian Westphal type = afinfo->type_comp; 3274f518e80SFlorian Westphal break; 3284f518e80SFlorian Westphal case IPPROTO_AH: 3294f518e80SFlorian Westphal type = afinfo->type_ah; 3304f518e80SFlorian Westphal break; 3314f518e80SFlorian Westphal case IPPROTO_ESP: 3324f518e80SFlorian Westphal type = afinfo->type_esp; 3334f518e80SFlorian Westphal break; 3344f518e80SFlorian Westphal case IPPROTO_IPIP: 3354f518e80SFlorian Westphal type = afinfo->type_ipip; 3364f518e80SFlorian Westphal break; 3374f518e80SFlorian Westphal case IPPROTO_DSTOPTS: 3384f518e80SFlorian Westphal type = afinfo->type_dstopts; 3394f518e80SFlorian Westphal break; 3404f518e80SFlorian Westphal case IPPROTO_ROUTING: 3414f518e80SFlorian Westphal type = afinfo->type_routing; 3424f518e80SFlorian Westphal break; 3434f518e80SFlorian Westphal case IPPROTO_IPV6: 3444f518e80SFlorian Westphal type = afinfo->type_ipip6; 3454f518e80SFlorian Westphal break; 3464f518e80SFlorian Westphal default: 3474f518e80SFlorian Westphal break; 3484f518e80SFlorian Westphal } 3494f518e80SFlorian Westphal 350aa5d62ccSHerbert Xu if (unlikely(type && !try_module_get(type->owner))) 351aa5d62ccSHerbert Xu type = NULL; 35275cda62dSFlorian Westphal 353af5d27c4SFlorian Westphal rcu_read_unlock(); 35475cda62dSFlorian Westphal 35575cda62dSFlorian Westphal if (!type && !modload_attempted) { 356aa5d62ccSHerbert Xu request_module("xfrm-type-%d-%d", family, proto); 357aa5d62ccSHerbert Xu modload_attempted = 1; 358aa5d62ccSHerbert Xu goto retry; 359aa5d62ccSHerbert Xu } 360aa5d62ccSHerbert Xu 361aa5d62ccSHerbert Xu return type; 362aa5d62ccSHerbert Xu } 363aa5d62ccSHerbert Xu 364533cb5b0SEric Dumazet static void xfrm_put_type(const struct xfrm_type *type) 365aa5d62ccSHerbert Xu { 366aa5d62ccSHerbert Xu module_put(type->owner); 367aa5d62ccSHerbert Xu } 368aa5d62ccSHerbert Xu 3699d389d7fSSteffen Klassert int xfrm_register_type_offload(const struct xfrm_type_offload *type, 3709d389d7fSSteffen Klassert unsigned short family) 3719d389d7fSSteffen Klassert { 3729d389d7fSSteffen Klassert struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); 3739d389d7fSSteffen Klassert int err = 0; 3749d389d7fSSteffen Klassert 3759d389d7fSSteffen Klassert if (unlikely(afinfo == NULL)) 3769d389d7fSSteffen Klassert return -EAFNOSUPPORT; 3779d389d7fSSteffen Klassert 3784f518e80SFlorian Westphal switch (type->proto) { 3794f518e80SFlorian Westphal case IPPROTO_ESP: 3804f518e80SFlorian Westphal WARN_ON(afinfo->type_offload_esp); 3814f518e80SFlorian Westphal afinfo->type_offload_esp = type; 3824f518e80SFlorian Westphal break; 3834f518e80SFlorian Westphal default: 3844f518e80SFlorian Westphal WARN_ON(1); 3854f518e80SFlorian Westphal err = -EPROTONOSUPPORT; 3864f518e80SFlorian Westphal break; 3874f518e80SFlorian Westphal } 3884f518e80SFlorian Westphal 3899d389d7fSSteffen Klassert rcu_read_unlock(); 3909d389d7fSSteffen Klassert return err; 3919d389d7fSSteffen Klassert } 3929d389d7fSSteffen Klassert EXPORT_SYMBOL(xfrm_register_type_offload); 3939d389d7fSSteffen Klassert 3944f518e80SFlorian Westphal void xfrm_unregister_type_offload(const struct xfrm_type_offload *type, 3959d389d7fSSteffen Klassert unsigned short family) 3969d389d7fSSteffen Klassert { 3979d389d7fSSteffen Klassert struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); 3989d389d7fSSteffen Klassert 3999d389d7fSSteffen Klassert if (unlikely(afinfo == NULL)) 4004f518e80SFlorian Westphal return; 4019d389d7fSSteffen Klassert 4024f518e80SFlorian Westphal switch (type->proto) { 4034f518e80SFlorian Westphal case IPPROTO_ESP: 4044f518e80SFlorian Westphal WARN_ON(afinfo->type_offload_esp != type); 4054f518e80SFlorian Westphal afinfo->type_offload_esp = NULL; 4064f518e80SFlorian Westphal break; 4074f518e80SFlorian Westphal default: 4084f518e80SFlorian Westphal WARN_ON(1); 4094f518e80SFlorian Westphal break; 4104f518e80SFlorian Westphal } 4119d389d7fSSteffen Klassert rcu_read_unlock(); 4129d389d7fSSteffen Klassert } 4139d389d7fSSteffen Klassert EXPORT_SYMBOL(xfrm_unregister_type_offload); 4149d389d7fSSteffen Klassert 415ffdb5211SIlan Tayari static const struct xfrm_type_offload * 416ffdb5211SIlan Tayari xfrm_get_type_offload(u8 proto, unsigned short family, bool try_load) 4179d389d7fSSteffen Klassert { 4184f518e80SFlorian Westphal const struct xfrm_type_offload *type = NULL; 4199d389d7fSSteffen Klassert struct xfrm_state_afinfo *afinfo; 4209d389d7fSSteffen Klassert 421ffdb5211SIlan Tayari retry: 4229d389d7fSSteffen Klassert afinfo = xfrm_state_get_afinfo(family); 4239d389d7fSSteffen Klassert if (unlikely(afinfo == NULL)) 4249d389d7fSSteffen Klassert return NULL; 4259d389d7fSSteffen Klassert 4264f518e80SFlorian Westphal switch (proto) { 4274f518e80SFlorian Westphal case IPPROTO_ESP: 4284f518e80SFlorian Westphal type = afinfo->type_offload_esp; 4294f518e80SFlorian Westphal break; 4304f518e80SFlorian Westphal default: 4314f518e80SFlorian Westphal break; 4324f518e80SFlorian Westphal } 4334f518e80SFlorian Westphal 4349d389d7fSSteffen Klassert if ((type && !try_module_get(type->owner))) 4359d389d7fSSteffen Klassert type = NULL; 4369d389d7fSSteffen Klassert 4372f10a61cSSabrina Dubroca rcu_read_unlock(); 4382f10a61cSSabrina Dubroca 439ffdb5211SIlan Tayari if (!type && try_load) { 440ffdb5211SIlan Tayari request_module("xfrm-offload-%d-%d", family, proto); 441545d8ae7SGustavo A. R. Silva try_load = false; 442ffdb5211SIlan Tayari goto retry; 443ffdb5211SIlan Tayari } 444ffdb5211SIlan Tayari 4459d389d7fSSteffen Klassert return type; 4469d389d7fSSteffen Klassert } 4479d389d7fSSteffen Klassert 4489d389d7fSSteffen Klassert static void xfrm_put_type_offload(const struct xfrm_type_offload *type) 4499d389d7fSSteffen Klassert { 4509d389d7fSSteffen Klassert module_put(type->owner); 4519d389d7fSSteffen Klassert } 4529d389d7fSSteffen Klassert 4534c145dceSFlorian Westphal static const struct xfrm_mode xfrm4_mode_map[XFRM_MODE_MAX] = { 4544c145dceSFlorian Westphal [XFRM_MODE_BEET] = { 4554c145dceSFlorian Westphal .encap = XFRM_MODE_BEET, 4564c145dceSFlorian Westphal .flags = XFRM_MODE_FLAG_TUNNEL, 4574c145dceSFlorian Westphal .family = AF_INET, 4584c145dceSFlorian Westphal }, 4594c145dceSFlorian Westphal [XFRM_MODE_TRANSPORT] = { 4604c145dceSFlorian Westphal .encap = XFRM_MODE_TRANSPORT, 4614c145dceSFlorian Westphal .family = AF_INET, 4624c145dceSFlorian Westphal }, 4634c145dceSFlorian Westphal [XFRM_MODE_TUNNEL] = { 4644c145dceSFlorian Westphal .encap = XFRM_MODE_TUNNEL, 4654c145dceSFlorian Westphal .flags = XFRM_MODE_FLAG_TUNNEL, 4664c145dceSFlorian Westphal .family = AF_INET, 4674c145dceSFlorian Westphal }, 4684c145dceSFlorian Westphal }; 4694c145dceSFlorian Westphal 4704c145dceSFlorian Westphal static const struct xfrm_mode xfrm6_mode_map[XFRM_MODE_MAX] = { 4714c145dceSFlorian Westphal [XFRM_MODE_BEET] = { 4724c145dceSFlorian Westphal .encap = XFRM_MODE_BEET, 4734c145dceSFlorian Westphal .flags = XFRM_MODE_FLAG_TUNNEL, 4744c145dceSFlorian Westphal .family = AF_INET6, 4754c145dceSFlorian Westphal }, 4764c145dceSFlorian Westphal [XFRM_MODE_ROUTEOPTIMIZATION] = { 4774c145dceSFlorian Westphal .encap = XFRM_MODE_ROUTEOPTIMIZATION, 4784c145dceSFlorian Westphal .family = AF_INET6, 4794c145dceSFlorian Westphal }, 4804c145dceSFlorian Westphal [XFRM_MODE_TRANSPORT] = { 4814c145dceSFlorian Westphal .encap = XFRM_MODE_TRANSPORT, 4824c145dceSFlorian Westphal .family = AF_INET6, 4834c145dceSFlorian Westphal }, 4844c145dceSFlorian Westphal [XFRM_MODE_TUNNEL] = { 4854c145dceSFlorian Westphal .encap = XFRM_MODE_TUNNEL, 4864c145dceSFlorian Westphal .flags = XFRM_MODE_FLAG_TUNNEL, 4874c145dceSFlorian Westphal .family = AF_INET6, 4884c145dceSFlorian Westphal }, 4894c145dceSFlorian Westphal }; 4904c145dceSFlorian Westphal 4914c145dceSFlorian Westphal static const struct xfrm_mode *xfrm_get_mode(unsigned int encap, int family) 492aa5d62ccSHerbert Xu { 4934c145dceSFlorian Westphal const struct xfrm_mode *mode; 494aa5d62ccSHerbert Xu 495aa5d62ccSHerbert Xu if (unlikely(encap >= XFRM_MODE_MAX)) 496aa5d62ccSHerbert Xu return NULL; 497aa5d62ccSHerbert Xu 4984c145dceSFlorian Westphal switch (family) { 4994c145dceSFlorian Westphal case AF_INET: 5004c145dceSFlorian Westphal mode = &xfrm4_mode_map[encap]; 5014c145dceSFlorian Westphal if (mode->family == family) 502aa5d62ccSHerbert Xu return mode; 5034c145dceSFlorian Westphal break; 5044c145dceSFlorian Westphal case AF_INET6: 5054c145dceSFlorian Westphal mode = &xfrm6_mode_map[encap]; 5064c145dceSFlorian Westphal if (mode->family == family) 5074c145dceSFlorian Westphal return mode; 5084c145dceSFlorian Westphal break; 5094c145dceSFlorian Westphal default: 5104c145dceSFlorian Westphal break; 511aa5d62ccSHerbert Xu } 512aa5d62ccSHerbert Xu 5134c145dceSFlorian Westphal return NULL; 514aa5d62ccSHerbert Xu } 515aa5d62ccSHerbert Xu 5164a135e53SMathias Krause void xfrm_state_free(struct xfrm_state *x) 5174a135e53SMathias Krause { 5184a135e53SMathias Krause kmem_cache_free(xfrm_state_cache, x); 5194a135e53SMathias Krause } 5204a135e53SMathias Krause EXPORT_SYMBOL(xfrm_state_free); 5214a135e53SMathias Krause 522f75a2804SCong Wang static void ___xfrm_state_destroy(struct xfrm_state *x) 5231da177e4SLinus Torvalds { 524671422b2SThomas Gleixner hrtimer_cancel(&x->mtimer); 525a47f0ce0SDavid S. Miller del_timer_sync(&x->rtimer); 526b5884793SIlan Tayari kfree(x->aead); 5271da177e4SLinus Torvalds kfree(x->aalg); 5281da177e4SLinus Torvalds kfree(x->ealg); 5291da177e4SLinus Torvalds kfree(x->calg); 5301da177e4SLinus Torvalds kfree(x->encap); 531060f02a3SNoriaki TAKAMIYA kfree(x->coaddr); 532d8647b79SSteffen Klassert kfree(x->replay_esn); 533d8647b79SSteffen Klassert kfree(x->preplay_esn); 5349d389d7fSSteffen Klassert if (x->type_offload) 5359d389d7fSSteffen Klassert xfrm_put_type_offload(x->type_offload); 5361da177e4SLinus Torvalds if (x->type) { 5371da177e4SLinus Torvalds x->type->destructor(x); 5381da177e4SLinus Torvalds xfrm_put_type(x->type); 5391da177e4SLinus Torvalds } 54086c6739eSSteffen Klassert if (x->xfrag.page) 54186c6739eSSteffen Klassert put_page(x->xfrag.page); 542d77e38e6SSteffen Klassert xfrm_dev_state_free(x); 543df71837dSTrent Jaeger security_xfrm_state_free(x); 5444a135e53SMathias Krause xfrm_state_free(x); 5451da177e4SLinus Torvalds } 5461da177e4SLinus Torvalds 547c7837144SAlexey Dobriyan static void xfrm_state_gc_task(struct work_struct *work) 5481da177e4SLinus Torvalds { 54912a169e7SHerbert Xu struct xfrm_state *x; 550b67bfe0dSSasha Levin struct hlist_node *tmp; 55112a169e7SHerbert Xu struct hlist_head gc_list; 5521da177e4SLinus Torvalds 5531da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_gc_lock); 55435db57bbSFlorian Westphal hlist_move_list(&xfrm_state_gc_list, &gc_list); 5551da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_gc_lock); 5561da177e4SLinus Torvalds 557df7274ebSFlorian Westphal synchronize_rcu(); 558df7274ebSFlorian Westphal 559b67bfe0dSSasha Levin hlist_for_each_entry_safe(x, tmp, &gc_list, gclist) 560f75a2804SCong Wang ___xfrm_state_destroy(x); 5611da177e4SLinus Torvalds } 5621da177e4SLinus Torvalds 5639e0d57fdSYury Polyanskiy static enum hrtimer_restart xfrm_timer_handler(struct hrtimer *me) 5641da177e4SLinus Torvalds { 565671422b2SThomas Gleixner struct xfrm_state *x = container_of(me, struct xfrm_state, mtimer); 566671422b2SThomas Gleixner enum hrtimer_restart ret = HRTIMER_NORESTART; 567386c5680SArnd Bergmann time64_t now = ktime_get_real_seconds(); 568386c5680SArnd Bergmann time64_t next = TIME64_MAX; 5691da177e4SLinus Torvalds int warn = 0; 570161a09e7SJoy Latten int err = 0; 5711da177e4SLinus Torvalds 5721da177e4SLinus Torvalds spin_lock(&x->lock); 5731da177e4SLinus Torvalds if (x->km.state == XFRM_STATE_DEAD) 5741da177e4SLinus Torvalds goto out; 5751da177e4SLinus Torvalds if (x->km.state == XFRM_STATE_EXPIRED) 5761da177e4SLinus Torvalds goto expired; 5771da177e4SLinus Torvalds if (x->lft.hard_add_expires_seconds) { 5781da177e4SLinus Torvalds long tmo = x->lft.hard_add_expires_seconds + 5791da177e4SLinus Torvalds x->curlft.add_time - now; 580e3c0d047SFan Du if (tmo <= 0) { 581e3c0d047SFan Du if (x->xflags & XFRM_SOFT_EXPIRE) { 582e3c0d047SFan Du /* enter hard expire without soft expire first?! 583e3c0d047SFan Du * setting a new date could trigger this. 5841365e547SAlexander Alemayhu * workaround: fix x->curflt.add_time by below: 585e3c0d047SFan Du */ 586e3c0d047SFan Du x->curlft.add_time = now - x->saved_tmo - 1; 587e3c0d047SFan Du tmo = x->lft.hard_add_expires_seconds - x->saved_tmo; 588e3c0d047SFan Du } else 5891da177e4SLinus Torvalds goto expired; 590e3c0d047SFan Du } 5911da177e4SLinus Torvalds if (tmo < next) 5921da177e4SLinus Torvalds next = tmo; 5931da177e4SLinus Torvalds } 5941da177e4SLinus Torvalds if (x->lft.hard_use_expires_seconds) { 5951da177e4SLinus Torvalds long tmo = x->lft.hard_use_expires_seconds + 5961da177e4SLinus Torvalds (x->curlft.use_time ? : now) - now; 5971da177e4SLinus Torvalds if (tmo <= 0) 5981da177e4SLinus Torvalds goto expired; 5991da177e4SLinus Torvalds if (tmo < next) 6001da177e4SLinus Torvalds next = tmo; 6011da177e4SLinus Torvalds } 6021da177e4SLinus Torvalds if (x->km.dying) 6031da177e4SLinus Torvalds goto resched; 6041da177e4SLinus Torvalds if (x->lft.soft_add_expires_seconds) { 6051da177e4SLinus Torvalds long tmo = x->lft.soft_add_expires_seconds + 6061da177e4SLinus Torvalds x->curlft.add_time - now; 607e3c0d047SFan Du if (tmo <= 0) { 6081da177e4SLinus Torvalds warn = 1; 609e3c0d047SFan Du x->xflags &= ~XFRM_SOFT_EXPIRE; 610e3c0d047SFan Du } else if (tmo < next) { 6111da177e4SLinus Torvalds next = tmo; 612e3c0d047SFan Du x->xflags |= XFRM_SOFT_EXPIRE; 613e3c0d047SFan Du x->saved_tmo = tmo; 614e3c0d047SFan Du } 6151da177e4SLinus Torvalds } 6161da177e4SLinus Torvalds if (x->lft.soft_use_expires_seconds) { 6171da177e4SLinus Torvalds long tmo = x->lft.soft_use_expires_seconds + 6181da177e4SLinus Torvalds (x->curlft.use_time ? : now) - now; 6191da177e4SLinus Torvalds if (tmo <= 0) 6201da177e4SLinus Torvalds warn = 1; 6211da177e4SLinus Torvalds else if (tmo < next) 6221da177e4SLinus Torvalds next = tmo; 6231da177e4SLinus Torvalds } 6241da177e4SLinus Torvalds 6254666faabSHerbert Xu x->km.dying = warn; 6261da177e4SLinus Torvalds if (warn) 62753bc6b4dSJamal Hadi Salim km_state_expired(x, 0, 0); 6281da177e4SLinus Torvalds resched: 629386c5680SArnd Bergmann if (next != TIME64_MAX) { 630671422b2SThomas Gleixner hrtimer_forward_now(&x->mtimer, ktime_set(next, 0)); 631671422b2SThomas Gleixner ret = HRTIMER_RESTART; 6329e0d57fdSYury Polyanskiy } 633a47f0ce0SDavid S. Miller 6341da177e4SLinus Torvalds goto out; 6351da177e4SLinus Torvalds 6361da177e4SLinus Torvalds expired: 6375b8ef341SSteffen Klassert if (x->km.state == XFRM_STATE_ACQ && x->id.spi == 0) 6381da177e4SLinus Torvalds x->km.state = XFRM_STATE_EXPIRED; 639161a09e7SJoy Latten 640161a09e7SJoy Latten err = __xfrm_state_delete(x); 6410806ae4cSNicolas Dichtel if (!err) 64253bc6b4dSJamal Hadi Salim km_state_expired(x, 1, 0); 6431da177e4SLinus Torvalds 6442e71029eSTetsuo Handa xfrm_audit_state_delete(x, err ? 0 : 1, true); 645161a09e7SJoy Latten 6461da177e4SLinus Torvalds out: 6471da177e4SLinus Torvalds spin_unlock(&x->lock); 648671422b2SThomas Gleixner return ret; 6491da177e4SLinus Torvalds } 6501da177e4SLinus Torvalds 651e99e88a9SKees Cook static void xfrm_replay_timer_handler(struct timer_list *t); 6520ac84752SDavid S. Miller 653673c09beSAlexey Dobriyan struct xfrm_state *xfrm_state_alloc(struct net *net) 6541da177e4SLinus Torvalds { 6551da177e4SLinus Torvalds struct xfrm_state *x; 6561da177e4SLinus Torvalds 657a4c278d1SHuang Zijiang x = kmem_cache_zalloc(xfrm_state_cache, GFP_ATOMIC); 6581da177e4SLinus Torvalds 6591da177e4SLinus Torvalds if (x) { 660673c09beSAlexey Dobriyan write_pnet(&x->xs_net, net); 66188755e9cSReshetova, Elena refcount_set(&x->refcnt, 1); 6621da177e4SLinus Torvalds atomic_set(&x->tunnel_users, 0); 66312a169e7SHerbert Xu INIT_LIST_HEAD(&x->km.all); 6648f126e37SDavid S. Miller INIT_HLIST_NODE(&x->bydst); 6658f126e37SDavid S. Miller INIT_HLIST_NODE(&x->bysrc); 6668f126e37SDavid S. Miller INIT_HLIST_NODE(&x->byspi); 667fe9f1d87SSabrina Dubroca INIT_HLIST_NODE(&x->byseq); 668671422b2SThomas Gleixner hrtimer_init(&x->mtimer, CLOCK_BOOTTIME, HRTIMER_MODE_ABS_SOFT); 669671422b2SThomas Gleixner x->mtimer.function = xfrm_timer_handler; 670e99e88a9SKees Cook timer_setup(&x->rtimer, xfrm_replay_timer_handler, 0); 671386c5680SArnd Bergmann x->curlft.add_time = ktime_get_real_seconds(); 6721da177e4SLinus Torvalds x->lft.soft_byte_limit = XFRM_INF; 6731da177e4SLinus Torvalds x->lft.soft_packet_limit = XFRM_INF; 6741da177e4SLinus Torvalds x->lft.hard_byte_limit = XFRM_INF; 6751da177e4SLinus Torvalds x->lft.hard_packet_limit = XFRM_INF; 676f8cd5488SJamal Hadi Salim x->replay_maxage = 0; 677f8cd5488SJamal Hadi Salim x->replay_maxdiff = 0; 6781da177e4SLinus Torvalds spin_lock_init(&x->lock); 6791da177e4SLinus Torvalds } 6801da177e4SLinus Torvalds return x; 6811da177e4SLinus Torvalds } 6821da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_alloc); 6831da177e4SLinus Torvalds 684f75a2804SCong Wang void __xfrm_state_destroy(struct xfrm_state *x, bool sync) 6851da177e4SLinus Torvalds { 686547b792cSIlpo Järvinen WARN_ON(x->km.state != XFRM_STATE_DEAD); 6871da177e4SLinus Torvalds 688f75a2804SCong Wang if (sync) { 689f75a2804SCong Wang synchronize_rcu(); 690f75a2804SCong Wang ___xfrm_state_destroy(x); 691f75a2804SCong Wang } else { 6921da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_gc_lock); 69335db57bbSFlorian Westphal hlist_add_head(&x->gclist, &xfrm_state_gc_list); 6941da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_gc_lock); 69535db57bbSFlorian Westphal schedule_work(&xfrm_state_gc_work); 6961da177e4SLinus Torvalds } 697f75a2804SCong Wang } 6981da177e4SLinus Torvalds EXPORT_SYMBOL(__xfrm_state_destroy); 6991da177e4SLinus Torvalds 70053bc6b4dSJamal Hadi Salim int __xfrm_state_delete(struct xfrm_state *x) 7011da177e4SLinus Torvalds { 70298806f75SAlexey Dobriyan struct net *net = xs_net(x); 70326b15dadSJamal Hadi Salim int err = -ESRCH; 70426b15dadSJamal Hadi Salim 7051da177e4SLinus Torvalds if (x->km.state != XFRM_STATE_DEAD) { 7061da177e4SLinus Torvalds x->km.state = XFRM_STATE_DEAD; 707283bc9f3SFan Du spin_lock(&net->xfrm.xfrm_state_lock); 70812a169e7SHerbert Xu list_del(&x->km.all); 709ae3fb6d3SFlorian Westphal hlist_del_rcu(&x->bydst); 710ae3fb6d3SFlorian Westphal hlist_del_rcu(&x->bysrc); 711fe9f1d87SSabrina Dubroca if (x->km.seq) 712fe9f1d87SSabrina Dubroca hlist_del_rcu(&x->byseq); 713a47f0ce0SDavid S. Miller if (x->id.spi) 714ae3fb6d3SFlorian Westphal hlist_del_rcu(&x->byspi); 71598806f75SAlexey Dobriyan net->xfrm.state_num--; 716283bc9f3SFan Du spin_unlock(&net->xfrm.xfrm_state_lock); 7171da177e4SLinus Torvalds 718e27cca96SSabrina Dubroca if (x->encap_sk) 719e27cca96SSabrina Dubroca sock_put(rcu_dereference_raw(x->encap_sk)); 720e27cca96SSabrina Dubroca 721d77e38e6SSteffen Klassert xfrm_dev_state_delete(x); 722d77e38e6SSteffen Klassert 7231da177e4SLinus Torvalds /* All xfrm_state objects are created by xfrm_state_alloc. 7241da177e4SLinus Torvalds * The xfrm_state_alloc call gives a reference, and that 7251da177e4SLinus Torvalds * is what we are dropping here. 7261da177e4SLinus Torvalds */ 7275dba4797SPatrick McHardy xfrm_state_put(x); 72826b15dadSJamal Hadi Salim err = 0; 7291da177e4SLinus Torvalds } 7301da177e4SLinus Torvalds 73126b15dadSJamal Hadi Salim return err; 73226b15dadSJamal Hadi Salim } 73353bc6b4dSJamal Hadi Salim EXPORT_SYMBOL(__xfrm_state_delete); 73426b15dadSJamal Hadi Salim 73526b15dadSJamal Hadi Salim int xfrm_state_delete(struct xfrm_state *x) 7361da177e4SLinus Torvalds { 73726b15dadSJamal Hadi Salim int err; 73826b15dadSJamal Hadi Salim 7391da177e4SLinus Torvalds spin_lock_bh(&x->lock); 74026b15dadSJamal Hadi Salim err = __xfrm_state_delete(x); 7411da177e4SLinus Torvalds spin_unlock_bh(&x->lock); 74226b15dadSJamal Hadi Salim 74326b15dadSJamal Hadi Salim return err; 7441da177e4SLinus Torvalds } 7451da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_delete); 7461da177e4SLinus Torvalds 7474aa2e62cSJoy Latten #ifdef CONFIG_SECURITY_NETWORK_XFRM 7484aa2e62cSJoy Latten static inline int 7492e71029eSTetsuo Handa xfrm_state_flush_secctx_check(struct net *net, u8 proto, bool task_valid) 7501da177e4SLinus Torvalds { 7514aa2e62cSJoy Latten int i, err = 0; 7524aa2e62cSJoy Latten 7530e602451SAlexey Dobriyan for (i = 0; i <= net->xfrm.state_hmask; i++) { 7544aa2e62cSJoy Latten struct xfrm_state *x; 7554aa2e62cSJoy Latten 756b67bfe0dSSasha Levin hlist_for_each_entry(x, net->xfrm.state_bydst+i, bydst) { 7574aa2e62cSJoy Latten if (xfrm_id_proto_match(x->id.proto, proto) && 7584aa2e62cSJoy Latten (err = security_xfrm_state_delete(x)) != 0) { 7592e71029eSTetsuo Handa xfrm_audit_state_delete(x, 0, task_valid); 7604aa2e62cSJoy Latten return err; 7614aa2e62cSJoy Latten } 7624aa2e62cSJoy Latten } 7634aa2e62cSJoy Latten } 7644aa2e62cSJoy Latten 7654aa2e62cSJoy Latten return err; 7664aa2e62cSJoy Latten } 767d77e38e6SSteffen Klassert 768d77e38e6SSteffen Klassert static inline int 769d77e38e6SSteffen Klassert xfrm_dev_state_flush_secctx_check(struct net *net, struct net_device *dev, bool task_valid) 770d77e38e6SSteffen Klassert { 771d77e38e6SSteffen Klassert int i, err = 0; 772d77e38e6SSteffen Klassert 773d77e38e6SSteffen Klassert for (i = 0; i <= net->xfrm.state_hmask; i++) { 774d77e38e6SSteffen Klassert struct xfrm_state *x; 77587e0a94eSLeon Romanovsky struct xfrm_dev_offload *xso; 776d77e38e6SSteffen Klassert 777d77e38e6SSteffen Klassert hlist_for_each_entry(x, net->xfrm.state_bydst+i, bydst) { 778d77e38e6SSteffen Klassert xso = &x->xso; 779d77e38e6SSteffen Klassert 780d77e38e6SSteffen Klassert if (xso->dev == dev && 781d77e38e6SSteffen Klassert (err = security_xfrm_state_delete(x)) != 0) { 782d77e38e6SSteffen Klassert xfrm_audit_state_delete(x, 0, task_valid); 783d77e38e6SSteffen Klassert return err; 784d77e38e6SSteffen Klassert } 785d77e38e6SSteffen Klassert } 786d77e38e6SSteffen Klassert } 787d77e38e6SSteffen Klassert 788d77e38e6SSteffen Klassert return err; 789d77e38e6SSteffen Klassert } 7904aa2e62cSJoy Latten #else 7914aa2e62cSJoy Latten static inline int 7922e71029eSTetsuo Handa xfrm_state_flush_secctx_check(struct net *net, u8 proto, bool task_valid) 7934aa2e62cSJoy Latten { 7944aa2e62cSJoy Latten return 0; 7954aa2e62cSJoy Latten } 796d77e38e6SSteffen Klassert 797d77e38e6SSteffen Klassert static inline int 798d77e38e6SSteffen Klassert xfrm_dev_state_flush_secctx_check(struct net *net, struct net_device *dev, bool task_valid) 799d77e38e6SSteffen Klassert { 800d77e38e6SSteffen Klassert return 0; 801d77e38e6SSteffen Klassert } 8024aa2e62cSJoy Latten #endif 8034aa2e62cSJoy Latten 804f75a2804SCong Wang int xfrm_state_flush(struct net *net, u8 proto, bool task_valid, bool sync) 8054aa2e62cSJoy Latten { 8069e64cc95SJamal Hadi Salim int i, err = 0, cnt = 0; 8071da177e4SLinus Torvalds 808283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 8092e71029eSTetsuo Handa err = xfrm_state_flush_secctx_check(net, proto, task_valid); 8104aa2e62cSJoy Latten if (err) 8114aa2e62cSJoy Latten goto out; 8124aa2e62cSJoy Latten 8139e64cc95SJamal Hadi Salim err = -ESRCH; 8140e602451SAlexey Dobriyan for (i = 0; i <= net->xfrm.state_hmask; i++) { 8158f126e37SDavid S. Miller struct xfrm_state *x; 8161da177e4SLinus Torvalds restart: 817b67bfe0dSSasha Levin hlist_for_each_entry(x, net->xfrm.state_bydst+i, bydst) { 8181da177e4SLinus Torvalds if (!xfrm_state_kern(x) && 8195794708fSMasahide NAKAMURA xfrm_id_proto_match(x->id.proto, proto)) { 8201da177e4SLinus Torvalds xfrm_state_hold(x); 821283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 8221da177e4SLinus Torvalds 823161a09e7SJoy Latten err = xfrm_state_delete(x); 824ab5f5e8bSJoy Latten xfrm_audit_state_delete(x, err ? 0 : 1, 8252e71029eSTetsuo Handa task_valid); 826f75a2804SCong Wang if (sync) 827f75a2804SCong Wang xfrm_state_put_sync(x); 828f75a2804SCong Wang else 8291da177e4SLinus Torvalds xfrm_state_put(x); 8309e64cc95SJamal Hadi Salim if (!err) 8319e64cc95SJamal Hadi Salim cnt++; 8321da177e4SLinus Torvalds 833283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 8341da177e4SLinus Torvalds goto restart; 8351da177e4SLinus Torvalds } 8361da177e4SLinus Torvalds } 8371da177e4SLinus Torvalds } 838dd269db8SArtem Savkov out: 839dd269db8SArtem Savkov spin_unlock_bh(&net->xfrm.xfrm_state_lock); 840e4db5b61SFlorian Westphal if (cnt) 8414aa2e62cSJoy Latten err = 0; 842e4db5b61SFlorian Westphal 8434aa2e62cSJoy Latten return err; 8441da177e4SLinus Torvalds } 8451da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_flush); 8461da177e4SLinus Torvalds 847d77e38e6SSteffen Klassert int xfrm_dev_state_flush(struct net *net, struct net_device *dev, bool task_valid) 848d77e38e6SSteffen Klassert { 849d77e38e6SSteffen Klassert int i, err = 0, cnt = 0; 850d77e38e6SSteffen Klassert 851d77e38e6SSteffen Klassert spin_lock_bh(&net->xfrm.xfrm_state_lock); 852d77e38e6SSteffen Klassert err = xfrm_dev_state_flush_secctx_check(net, dev, task_valid); 853d77e38e6SSteffen Klassert if (err) 854d77e38e6SSteffen Klassert goto out; 855d77e38e6SSteffen Klassert 856d77e38e6SSteffen Klassert err = -ESRCH; 857d77e38e6SSteffen Klassert for (i = 0; i <= net->xfrm.state_hmask; i++) { 858d77e38e6SSteffen Klassert struct xfrm_state *x; 85987e0a94eSLeon Romanovsky struct xfrm_dev_offload *xso; 860d77e38e6SSteffen Klassert restart: 861d77e38e6SSteffen Klassert hlist_for_each_entry(x, net->xfrm.state_bydst+i, bydst) { 862d77e38e6SSteffen Klassert xso = &x->xso; 863d77e38e6SSteffen Klassert 864d77e38e6SSteffen Klassert if (!xfrm_state_kern(x) && xso->dev == dev) { 865d77e38e6SSteffen Klassert xfrm_state_hold(x); 866d77e38e6SSteffen Klassert spin_unlock_bh(&net->xfrm.xfrm_state_lock); 867d77e38e6SSteffen Klassert 868d77e38e6SSteffen Klassert err = xfrm_state_delete(x); 869d77e38e6SSteffen Klassert xfrm_audit_state_delete(x, err ? 0 : 1, 870d77e38e6SSteffen Klassert task_valid); 871d77e38e6SSteffen Klassert xfrm_state_put(x); 872d77e38e6SSteffen Klassert if (!err) 873d77e38e6SSteffen Klassert cnt++; 874d77e38e6SSteffen Klassert 875d77e38e6SSteffen Klassert spin_lock_bh(&net->xfrm.xfrm_state_lock); 876d77e38e6SSteffen Klassert goto restart; 877d77e38e6SSteffen Klassert } 878d77e38e6SSteffen Klassert } 879d77e38e6SSteffen Klassert } 880d77e38e6SSteffen Klassert if (cnt) 881d77e38e6SSteffen Klassert err = 0; 882d77e38e6SSteffen Klassert 883d77e38e6SSteffen Klassert out: 884d77e38e6SSteffen Klassert spin_unlock_bh(&net->xfrm.xfrm_state_lock); 885d77e38e6SSteffen Klassert return err; 886d77e38e6SSteffen Klassert } 887d77e38e6SSteffen Klassert EXPORT_SYMBOL(xfrm_dev_state_flush); 888d77e38e6SSteffen Klassert 889e071041bSAlexey Dobriyan void xfrm_sad_getinfo(struct net *net, struct xfrmk_sadinfo *si) 89028d8909bSJamal Hadi Salim { 891283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 892e071041bSAlexey Dobriyan si->sadcnt = net->xfrm.state_num; 893ca92e173SBenjamin Poirier si->sadhcnt = net->xfrm.state_hmask + 1; 89428d8909bSJamal Hadi Salim si->sadhmcnt = xfrm_state_hashmax; 895283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 89628d8909bSJamal Hadi Salim } 89728d8909bSJamal Hadi Salim EXPORT_SYMBOL(xfrm_sad_getinfo); 89828d8909bSJamal Hadi Salim 899711059b9SFlorian Westphal static void 900bac95935SFlorian Westphal __xfrm4_init_tempsel(struct xfrm_selector *sel, const struct flowi *fl) 901bac95935SFlorian Westphal { 902bac95935SFlorian Westphal const struct flowi4 *fl4 = &fl->u.ip4; 903bac95935SFlorian Westphal 904bac95935SFlorian Westphal sel->daddr.a4 = fl4->daddr; 905bac95935SFlorian Westphal sel->saddr.a4 = fl4->saddr; 906bac95935SFlorian Westphal sel->dport = xfrm_flowi_dport(fl, &fl4->uli); 907bac95935SFlorian Westphal sel->dport_mask = htons(0xffff); 908bac95935SFlorian Westphal sel->sport = xfrm_flowi_sport(fl, &fl4->uli); 909bac95935SFlorian Westphal sel->sport_mask = htons(0xffff); 910bac95935SFlorian Westphal sel->family = AF_INET; 911bac95935SFlorian Westphal sel->prefixlen_d = 32; 912bac95935SFlorian Westphal sel->prefixlen_s = 32; 913bac95935SFlorian Westphal sel->proto = fl4->flowi4_proto; 914bac95935SFlorian Westphal sel->ifindex = fl4->flowi4_oif; 915bac95935SFlorian Westphal } 916bac95935SFlorian Westphal 917bac95935SFlorian Westphal static void 918bac95935SFlorian Westphal __xfrm6_init_tempsel(struct xfrm_selector *sel, const struct flowi *fl) 919bac95935SFlorian Westphal { 920bac95935SFlorian Westphal const struct flowi6 *fl6 = &fl->u.ip6; 921bac95935SFlorian Westphal 922bac95935SFlorian Westphal /* Initialize temporary selector matching only to current session. */ 923bac95935SFlorian Westphal *(struct in6_addr *)&sel->daddr = fl6->daddr; 924bac95935SFlorian Westphal *(struct in6_addr *)&sel->saddr = fl6->saddr; 925bac95935SFlorian Westphal sel->dport = xfrm_flowi_dport(fl, &fl6->uli); 926bac95935SFlorian Westphal sel->dport_mask = htons(0xffff); 927bac95935SFlorian Westphal sel->sport = xfrm_flowi_sport(fl, &fl6->uli); 928bac95935SFlorian Westphal sel->sport_mask = htons(0xffff); 929bac95935SFlorian Westphal sel->family = AF_INET6; 930bac95935SFlorian Westphal sel->prefixlen_d = 128; 931bac95935SFlorian Westphal sel->prefixlen_s = 128; 932bac95935SFlorian Westphal sel->proto = fl6->flowi6_proto; 933bac95935SFlorian Westphal sel->ifindex = fl6->flowi6_oif; 934bac95935SFlorian Westphal } 935bac95935SFlorian Westphal 936bac95935SFlorian Westphal static void 9371a898592SDavid S. Miller xfrm_init_tempstate(struct xfrm_state *x, const struct flowi *fl, 93804686013SDavid S. Miller const struct xfrm_tmpl *tmpl, 93933765d06SDavid S. Miller const xfrm_address_t *daddr, const xfrm_address_t *saddr, 9401da177e4SLinus Torvalds unsigned short family) 9411da177e4SLinus Torvalds { 942bac95935SFlorian Westphal switch (family) { 943bac95935SFlorian Westphal case AF_INET: 944bac95935SFlorian Westphal __xfrm4_init_tempsel(&x->sel, fl); 945bac95935SFlorian Westphal break; 946bac95935SFlorian Westphal case AF_INET6: 947bac95935SFlorian Westphal __xfrm6_init_tempsel(&x->sel, fl); 948bac95935SFlorian Westphal break; 9498444cf71SThomas Egerer } 950bac95935SFlorian Westphal 9515c1b9ab3SFlorian Westphal x->id = tmpl->id; 952bac95935SFlorian Westphal 9535c1b9ab3SFlorian Westphal switch (tmpl->encap_family) { 9545c1b9ab3SFlorian Westphal case AF_INET: 9555c1b9ab3SFlorian Westphal if (x->id.daddr.a4 == 0) 9565c1b9ab3SFlorian Westphal x->id.daddr.a4 = daddr->a4; 9575c1b9ab3SFlorian Westphal x->props.saddr = tmpl->saddr; 9585c1b9ab3SFlorian Westphal if (x->props.saddr.a4 == 0) 9595c1b9ab3SFlorian Westphal x->props.saddr.a4 = saddr->a4; 9605c1b9ab3SFlorian Westphal break; 9615c1b9ab3SFlorian Westphal case AF_INET6: 9625c1b9ab3SFlorian Westphal if (ipv6_addr_any((struct in6_addr *)&x->id.daddr)) 9635c1b9ab3SFlorian Westphal memcpy(&x->id.daddr, daddr, sizeof(x->sel.daddr)); 9645c1b9ab3SFlorian Westphal memcpy(&x->props.saddr, &tmpl->saddr, sizeof(x->props.saddr)); 9655c1b9ab3SFlorian Westphal if (ipv6_addr_any((struct in6_addr *)&x->props.saddr)) 9665c1b9ab3SFlorian Westphal memcpy(&x->props.saddr, saddr, sizeof(x->props.saddr)); 9675c1b9ab3SFlorian Westphal break; 9685c1b9ab3SFlorian Westphal } 969bac95935SFlorian Westphal 9705c1b9ab3SFlorian Westphal x->props.mode = tmpl->mode; 9715c1b9ab3SFlorian Westphal x->props.reqid = tmpl->reqid; 9725c1b9ab3SFlorian Westphal x->props.family = tmpl->encap_family; 9731da177e4SLinus Torvalds } 9741da177e4SLinus Torvalds 975f8a70afaSLeon Romanovsky static struct xfrm_state *__xfrm_state_lookup_all(struct net *net, u32 mark, 976f8a70afaSLeon Romanovsky const xfrm_address_t *daddr, 977f8a70afaSLeon Romanovsky __be32 spi, u8 proto, 978f8a70afaSLeon Romanovsky unsigned short family, 979f8a70afaSLeon Romanovsky struct xfrm_dev_offload *xdo) 980f8a70afaSLeon Romanovsky { 981f8a70afaSLeon Romanovsky unsigned int h = xfrm_spi_hash(net, daddr, spi, proto, family); 982f8a70afaSLeon Romanovsky struct xfrm_state *x; 983f8a70afaSLeon Romanovsky 984f8a70afaSLeon Romanovsky hlist_for_each_entry_rcu(x, net->xfrm.state_byspi + h, byspi) { 985f8a70afaSLeon Romanovsky #ifdef CONFIG_XFRM_OFFLOAD 986f8a70afaSLeon Romanovsky if (xdo->type == XFRM_DEV_OFFLOAD_PACKET) { 987f8a70afaSLeon Romanovsky if (x->xso.type != XFRM_DEV_OFFLOAD_PACKET) 988f8a70afaSLeon Romanovsky /* HW states are in the head of list, there is 989f8a70afaSLeon Romanovsky * no need to iterate further. 990f8a70afaSLeon Romanovsky */ 991f8a70afaSLeon Romanovsky break; 992f8a70afaSLeon Romanovsky 993f8a70afaSLeon Romanovsky /* Packet offload: both policy and SA should 994f8a70afaSLeon Romanovsky * have same device. 995f8a70afaSLeon Romanovsky */ 996f8a70afaSLeon Romanovsky if (xdo->dev != x->xso.dev) 997f8a70afaSLeon Romanovsky continue; 998f8a70afaSLeon Romanovsky } else if (x->xso.type == XFRM_DEV_OFFLOAD_PACKET) 999f8a70afaSLeon Romanovsky /* Skip HW policy for SW lookups */ 1000f8a70afaSLeon Romanovsky continue; 1001f8a70afaSLeon Romanovsky #endif 1002f8a70afaSLeon Romanovsky if (x->props.family != family || 1003f8a70afaSLeon Romanovsky x->id.spi != spi || 1004f8a70afaSLeon Romanovsky x->id.proto != proto || 1005f8a70afaSLeon Romanovsky !xfrm_addr_equal(&x->id.daddr, daddr, family)) 1006f8a70afaSLeon Romanovsky continue; 1007f8a70afaSLeon Romanovsky 1008f8a70afaSLeon Romanovsky if ((mark & x->mark.m) != x->mark.v) 1009f8a70afaSLeon Romanovsky continue; 1010f8a70afaSLeon Romanovsky if (!xfrm_state_hold_rcu(x)) 1011f8a70afaSLeon Romanovsky continue; 1012f8a70afaSLeon Romanovsky return x; 1013f8a70afaSLeon Romanovsky } 1014f8a70afaSLeon Romanovsky 1015f8a70afaSLeon Romanovsky return NULL; 1016f8a70afaSLeon Romanovsky } 1017f8a70afaSLeon Romanovsky 10189aa60088SDavid S. Miller static struct xfrm_state *__xfrm_state_lookup(struct net *net, u32 mark, 10199aa60088SDavid S. Miller const xfrm_address_t *daddr, 10209aa60088SDavid S. Miller __be32 spi, u8 proto, 10219aa60088SDavid S. Miller unsigned short family) 1022edcd5821SDavid S. Miller { 1023221df1edSAlexey Dobriyan unsigned int h = xfrm_spi_hash(net, daddr, spi, proto, family); 1024edcd5821SDavid S. Miller struct xfrm_state *x; 1025edcd5821SDavid S. Miller 1026ae3fb6d3SFlorian Westphal hlist_for_each_entry_rcu(x, net->xfrm.state_byspi + h, byspi) { 1027edcd5821SDavid S. Miller if (x->props.family != family || 1028edcd5821SDavid S. Miller x->id.spi != spi || 10291802571bSWei Yongjun x->id.proto != proto || 103070e94e66SYOSHIFUJI Hideaki / 吉藤英明 !xfrm_addr_equal(&x->id.daddr, daddr, family)) 1031edcd5821SDavid S. Miller continue; 1032edcd5821SDavid S. Miller 10333d6acfa7SJamal Hadi Salim if ((mark & x->mark.m) != x->mark.v) 10343d6acfa7SJamal Hadi Salim continue; 103502efdff7SFlorian Westphal if (!xfrm_state_hold_rcu(x)) 103602efdff7SFlorian Westphal continue; 1037edcd5821SDavid S. Miller return x; 1038edcd5821SDavid S. Miller } 1039edcd5821SDavid S. Miller 1040edcd5821SDavid S. Miller return NULL; 1041edcd5821SDavid S. Miller } 1042edcd5821SDavid S. Miller 10439aa60088SDavid S. Miller static struct xfrm_state *__xfrm_state_lookup_byaddr(struct net *net, u32 mark, 10449aa60088SDavid S. Miller const xfrm_address_t *daddr, 10459aa60088SDavid S. Miller const xfrm_address_t *saddr, 10469aa60088SDavid S. Miller u8 proto, unsigned short family) 1047edcd5821SDavid S. Miller { 1048221df1edSAlexey Dobriyan unsigned int h = xfrm_src_hash(net, daddr, saddr, family); 1049edcd5821SDavid S. Miller struct xfrm_state *x; 1050edcd5821SDavid S. Miller 1051ae3fb6d3SFlorian Westphal hlist_for_each_entry_rcu(x, net->xfrm.state_bysrc + h, bysrc) { 1052edcd5821SDavid S. Miller if (x->props.family != family || 10531802571bSWei Yongjun x->id.proto != proto || 105470e94e66SYOSHIFUJI Hideaki / 吉藤英明 !xfrm_addr_equal(&x->id.daddr, daddr, family) || 105570e94e66SYOSHIFUJI Hideaki / 吉藤英明 !xfrm_addr_equal(&x->props.saddr, saddr, family)) 1056edcd5821SDavid S. Miller continue; 1057edcd5821SDavid S. Miller 10583d6acfa7SJamal Hadi Salim if ((mark & x->mark.m) != x->mark.v) 10593d6acfa7SJamal Hadi Salim continue; 106002efdff7SFlorian Westphal if (!xfrm_state_hold_rcu(x)) 106102efdff7SFlorian Westphal continue; 1062edcd5821SDavid S. Miller return x; 1063edcd5821SDavid S. Miller } 1064edcd5821SDavid S. Miller 1065edcd5821SDavid S. Miller return NULL; 1066edcd5821SDavid S. Miller } 1067edcd5821SDavid S. Miller 1068edcd5821SDavid S. Miller static inline struct xfrm_state * 1069edcd5821SDavid S. Miller __xfrm_state_locate(struct xfrm_state *x, int use_spi, int family) 1070edcd5821SDavid S. Miller { 1071221df1edSAlexey Dobriyan struct net *net = xs_net(x); 1072bd55775cSJamal Hadi Salim u32 mark = x->mark.v & x->mark.m; 1073221df1edSAlexey Dobriyan 1074edcd5821SDavid S. Miller if (use_spi) 1075bd55775cSJamal Hadi Salim return __xfrm_state_lookup(net, mark, &x->id.daddr, 1076bd55775cSJamal Hadi Salim x->id.spi, x->id.proto, family); 1077edcd5821SDavid S. Miller else 1078bd55775cSJamal Hadi Salim return __xfrm_state_lookup_byaddr(net, mark, 1079bd55775cSJamal Hadi Salim &x->id.daddr, 1080edcd5821SDavid S. Miller &x->props.saddr, 1081edcd5821SDavid S. Miller x->id.proto, family); 1082edcd5821SDavid S. Miller } 1083edcd5821SDavid S. Miller 108498806f75SAlexey Dobriyan static void xfrm_hash_grow_check(struct net *net, int have_hash_collision) 10852fab22f2SPatrick McHardy { 10862fab22f2SPatrick McHardy if (have_hash_collision && 108798806f75SAlexey Dobriyan (net->xfrm.state_hmask + 1) < xfrm_state_hashmax && 108898806f75SAlexey Dobriyan net->xfrm.state_num > net->xfrm.state_hmask) 108998806f75SAlexey Dobriyan schedule_work(&net->xfrm.state_hash_work); 10902fab22f2SPatrick McHardy } 10912fab22f2SPatrick McHardy 109208ec9af1SDavid S. Miller static void xfrm_state_look_at(struct xfrm_policy *pol, struct xfrm_state *x, 10934a08ab0fSDavid S. Miller const struct flowi *fl, unsigned short family, 109408ec9af1SDavid S. Miller struct xfrm_state **best, int *acq_in_progress, 109508ec9af1SDavid S. Miller int *error) 109608ec9af1SDavid S. Miller { 109708ec9af1SDavid S. Miller /* Resolution logic: 109808ec9af1SDavid S. Miller * 1. There is a valid state with matching selector. Done. 109908ec9af1SDavid S. Miller * 2. Valid state with inappropriate selector. Skip. 110008ec9af1SDavid S. Miller * 110108ec9af1SDavid S. Miller * Entering area of "sysdeps". 110208ec9af1SDavid S. Miller * 110308ec9af1SDavid S. Miller * 3. If state is not valid, selector is temporary, it selects 110408ec9af1SDavid S. Miller * only session which triggered previous resolution. Key 110508ec9af1SDavid S. Miller * manager will do something to install a state with proper 110608ec9af1SDavid S. Miller * selector. 110708ec9af1SDavid S. Miller */ 110808ec9af1SDavid S. Miller if (x->km.state == XFRM_STATE_VALID) { 110908ec9af1SDavid S. Miller if ((x->sel.family && 1110e94ee171SHerbert Xu (x->sel.family != family || 1111e94ee171SHerbert Xu !xfrm_selector_match(&x->sel, fl, family))) || 11123df98d79SPaul Moore !security_xfrm_state_pol_flow_match(x, pol, 11133df98d79SPaul Moore &fl->u.__fl_common)) 111408ec9af1SDavid S. Miller return; 111508ec9af1SDavid S. Miller 111608ec9af1SDavid S. Miller if (!*best || 111708ec9af1SDavid S. Miller (*best)->km.dying > x->km.dying || 111808ec9af1SDavid S. Miller ((*best)->km.dying == x->km.dying && 111908ec9af1SDavid S. Miller (*best)->curlft.add_time < x->curlft.add_time)) 112008ec9af1SDavid S. Miller *best = x; 112108ec9af1SDavid S. Miller } else if (x->km.state == XFRM_STATE_ACQ) { 112208ec9af1SDavid S. Miller *acq_in_progress = 1; 112308ec9af1SDavid S. Miller } else if (x->km.state == XFRM_STATE_ERROR || 112408ec9af1SDavid S. Miller x->km.state == XFRM_STATE_EXPIRED) { 1125e94ee171SHerbert Xu if ((!x->sel.family || 1126e94ee171SHerbert Xu (x->sel.family == family && 1127e94ee171SHerbert Xu xfrm_selector_match(&x->sel, fl, family))) && 11283df98d79SPaul Moore security_xfrm_state_pol_flow_match(x, pol, 11293df98d79SPaul Moore &fl->u.__fl_common)) 113008ec9af1SDavid S. Miller *error = -ESRCH; 113108ec9af1SDavid S. Miller } 113208ec9af1SDavid S. Miller } 113308ec9af1SDavid S. Miller 11341da177e4SLinus Torvalds struct xfrm_state * 113533765d06SDavid S. Miller xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr, 1136b520e9f6SDavid S. Miller const struct flowi *fl, struct xfrm_tmpl *tmpl, 11371da177e4SLinus Torvalds struct xfrm_policy *pol, int *err, 1138bc56b334SBenedict Wong unsigned short family, u32 if_id) 11391da177e4SLinus Torvalds { 114008ec9af1SDavid S. Miller static xfrm_address_t saddr_wildcard = { }; 11415447c5e4SAlexey Dobriyan struct net *net = xp_net(pol); 11426a783c90SNicolas Dichtel unsigned int h, h_wildcard; 114337b08e34SDavid S. Miller struct xfrm_state *x, *x0, *to_put; 11441da177e4SLinus Torvalds int acquire_in_progress = 0; 11451da177e4SLinus Torvalds int error = 0; 11461da177e4SLinus Torvalds struct xfrm_state *best = NULL; 1147bd55775cSJamal Hadi Salim u32 mark = pol->mark.v & pol->mark.m; 11488444cf71SThomas Egerer unsigned short encap_family = tmpl->encap_family; 1149b65e3d7bSFlorian Westphal unsigned int sequence; 11500f24558eSHoria Geanta struct km_event c; 11511da177e4SLinus Torvalds 115237b08e34SDavid S. Miller to_put = NULL; 115337b08e34SDavid S. Miller 1154e88add19SAhmed S. Darwish sequence = read_seqcount_begin(&net->xfrm.xfrm_state_hash_generation); 1155b65e3d7bSFlorian Westphal 1156d737a580SFlorian Westphal rcu_read_lock(); 11578444cf71SThomas Egerer h = xfrm_dst_hash(net, daddr, saddr, tmpl->reqid, encap_family); 1158ae3fb6d3SFlorian Westphal hlist_for_each_entry_rcu(x, net->xfrm.state_bydst + h, bydst) { 1159f8a70afaSLeon Romanovsky #ifdef CONFIG_XFRM_OFFLOAD 1160f8a70afaSLeon Romanovsky if (pol->xdo.type == XFRM_DEV_OFFLOAD_PACKET) { 1161f8a70afaSLeon Romanovsky if (x->xso.type != XFRM_DEV_OFFLOAD_PACKET) 1162f8a70afaSLeon Romanovsky /* HW states are in the head of list, there is 1163f8a70afaSLeon Romanovsky * no need to iterate further. 1164f8a70afaSLeon Romanovsky */ 1165f8a70afaSLeon Romanovsky break; 1166f8a70afaSLeon Romanovsky 1167f8a70afaSLeon Romanovsky /* Packet offload: both policy and SA should 1168f8a70afaSLeon Romanovsky * have same device. 1169f8a70afaSLeon Romanovsky */ 1170f8a70afaSLeon Romanovsky if (pol->xdo.dev != x->xso.dev) 1171f8a70afaSLeon Romanovsky continue; 1172f8a70afaSLeon Romanovsky } else if (x->xso.type == XFRM_DEV_OFFLOAD_PACKET) 1173f8a70afaSLeon Romanovsky /* Skip HW policy for SW lookups */ 1174f8a70afaSLeon Romanovsky continue; 1175f8a70afaSLeon Romanovsky #endif 11768444cf71SThomas Egerer if (x->props.family == encap_family && 11771da177e4SLinus Torvalds x->props.reqid == tmpl->reqid && 11783d6acfa7SJamal Hadi Salim (mark & x->mark.m) == x->mark.v && 11797e652640SSteffen Klassert x->if_id == if_id && 1180fbd9a5b4SMasahide NAKAMURA !(x->props.flags & XFRM_STATE_WILDRECV) && 11818444cf71SThomas Egerer xfrm_state_addr_check(x, daddr, saddr, encap_family) && 11821da177e4SLinus Torvalds tmpl->mode == x->props.mode && 11831da177e4SLinus Torvalds tmpl->id.proto == x->id.proto && 118408ec9af1SDavid S. Miller (tmpl->id.spi == x->id.spi || !tmpl->id.spi)) 1185e94ee171SHerbert Xu xfrm_state_look_at(pol, x, fl, family, 118608ec9af1SDavid S. Miller &best, &acquire_in_progress, &error); 11871da177e4SLinus Torvalds } 11886f115638SFan Du if (best || acquire_in_progress) 118908ec9af1SDavid S. Miller goto found; 119008ec9af1SDavid S. Miller 11918444cf71SThomas Egerer h_wildcard = xfrm_dst_hash(net, daddr, &saddr_wildcard, tmpl->reqid, encap_family); 1192ae3fb6d3SFlorian Westphal hlist_for_each_entry_rcu(x, net->xfrm.state_bydst + h_wildcard, bydst) { 1193f8a70afaSLeon Romanovsky #ifdef CONFIG_XFRM_OFFLOAD 1194f8a70afaSLeon Romanovsky if (pol->xdo.type == XFRM_DEV_OFFLOAD_PACKET) { 1195f8a70afaSLeon Romanovsky if (x->xso.type != XFRM_DEV_OFFLOAD_PACKET) 1196f8a70afaSLeon Romanovsky /* HW states are in the head of list, there is 1197f8a70afaSLeon Romanovsky * no need to iterate further. 1198f8a70afaSLeon Romanovsky */ 1199f8a70afaSLeon Romanovsky break; 1200f8a70afaSLeon Romanovsky 1201f8a70afaSLeon Romanovsky /* Packet offload: both policy and SA should 1202f8a70afaSLeon Romanovsky * have same device. 1203f8a70afaSLeon Romanovsky */ 1204f8a70afaSLeon Romanovsky if (pol->xdo.dev != x->xso.dev) 1205f8a70afaSLeon Romanovsky continue; 1206f8a70afaSLeon Romanovsky } else if (x->xso.type == XFRM_DEV_OFFLOAD_PACKET) 1207f8a70afaSLeon Romanovsky /* Skip HW policy for SW lookups */ 1208f8a70afaSLeon Romanovsky continue; 1209f8a70afaSLeon Romanovsky #endif 12108444cf71SThomas Egerer if (x->props.family == encap_family && 121108ec9af1SDavid S. Miller x->props.reqid == tmpl->reqid && 12123d6acfa7SJamal Hadi Salim (mark & x->mark.m) == x->mark.v && 12137e652640SSteffen Klassert x->if_id == if_id && 121408ec9af1SDavid S. Miller !(x->props.flags & XFRM_STATE_WILDRECV) && 1215f59bbdfaSFan Du xfrm_addr_equal(&x->id.daddr, daddr, encap_family) && 121608ec9af1SDavid S. Miller tmpl->mode == x->props.mode && 121708ec9af1SDavid S. Miller tmpl->id.proto == x->id.proto && 121808ec9af1SDavid S. Miller (tmpl->id.spi == x->id.spi || !tmpl->id.spi)) 1219e94ee171SHerbert Xu xfrm_state_look_at(pol, x, fl, family, 122008ec9af1SDavid S. Miller &best, &acquire_in_progress, &error); 12211da177e4SLinus Torvalds } 12221da177e4SLinus Torvalds 122308ec9af1SDavid S. Miller found: 12241da177e4SLinus Torvalds x = best; 12251da177e4SLinus Torvalds if (!x && !error && !acquire_in_progress) { 12265c5d281aSPatrick McHardy if (tmpl->id.spi && 1227f8a70afaSLeon Romanovsky (x0 = __xfrm_state_lookup_all(net, mark, daddr, 1228f8a70afaSLeon Romanovsky tmpl->id.spi, tmpl->id.proto, 1229f8a70afaSLeon Romanovsky encap_family, 1230f8a70afaSLeon Romanovsky &pol->xdo)) != NULL) { 123137b08e34SDavid S. Miller to_put = x0; 12321da177e4SLinus Torvalds error = -EEXIST; 12331da177e4SLinus Torvalds goto out; 12341da177e4SLinus Torvalds } 12350f24558eSHoria Geanta 12360f24558eSHoria Geanta c.net = net; 12370f24558eSHoria Geanta /* If the KMs have no listeners (yet...), avoid allocating an SA 12380f24558eSHoria Geanta * for each and every packet - garbage collection might not 12390f24558eSHoria Geanta * handle the flood. 12400f24558eSHoria Geanta */ 12410f24558eSHoria Geanta if (!km_is_alive(&c)) { 12420f24558eSHoria Geanta error = -ESRCH; 12430f24558eSHoria Geanta goto out; 12440f24558eSHoria Geanta } 12450f24558eSHoria Geanta 12465447c5e4SAlexey Dobriyan x = xfrm_state_alloc(net); 12471da177e4SLinus Torvalds if (x == NULL) { 12481da177e4SLinus Torvalds error = -ENOMEM; 12491da177e4SLinus Torvalds goto out; 12501da177e4SLinus Torvalds } 12518444cf71SThomas Egerer /* Initialize temporary state matching only 12521da177e4SLinus Torvalds * to current session. */ 12538444cf71SThomas Egerer xfrm_init_tempstate(x, fl, tmpl, daddr, saddr, family); 1254bd55775cSJamal Hadi Salim memcpy(&x->mark, &pol->mark, sizeof(x->mark)); 12557e652640SSteffen Klassert x->if_id = if_id; 12561da177e4SLinus Torvalds 12571d28f42cSDavid S. Miller error = security_xfrm_state_alloc_acquire(x, pol->security, fl->flowi_secid); 1258e0d1caa7SVenkat Yekkirala if (error) { 1259e0d1caa7SVenkat Yekkirala x->km.state = XFRM_STATE_DEAD; 126037b08e34SDavid S. Miller to_put = x; 1261e0d1caa7SVenkat Yekkirala x = NULL; 1262e0d1caa7SVenkat Yekkirala goto out; 1263e0d1caa7SVenkat Yekkirala } 1264f8a70afaSLeon Romanovsky #ifdef CONFIG_XFRM_OFFLOAD 1265f8a70afaSLeon Romanovsky if (pol->xdo.type == XFRM_DEV_OFFLOAD_PACKET) { 1266f8a70afaSLeon Romanovsky struct xfrm_dev_offload *xdo = &pol->xdo; 1267f8a70afaSLeon Romanovsky struct xfrm_dev_offload *xso = &x->xso; 1268e0d1caa7SVenkat Yekkirala 1269f8a70afaSLeon Romanovsky xso->type = XFRM_DEV_OFFLOAD_PACKET; 1270f8a70afaSLeon Romanovsky xso->dir = xdo->dir; 1271f8a70afaSLeon Romanovsky xso->dev = xdo->dev; 1272f8a70afaSLeon Romanovsky xso->real_dev = xdo->real_dev; 1273f8a70afaSLeon Romanovsky netdev_tracker_alloc(xso->dev, &xso->dev_tracker, 1274f8a70afaSLeon Romanovsky GFP_ATOMIC); 1275f8a70afaSLeon Romanovsky error = xso->dev->xfrmdev_ops->xdo_dev_state_add(x); 1276f8a70afaSLeon Romanovsky if (error) { 1277f8a70afaSLeon Romanovsky xso->dir = 0; 1278f8a70afaSLeon Romanovsky netdev_put(xso->dev, &xso->dev_tracker); 1279f8a70afaSLeon Romanovsky xso->dev = NULL; 1280f8a70afaSLeon Romanovsky xso->real_dev = NULL; 1281f8a70afaSLeon Romanovsky xso->type = XFRM_DEV_OFFLOAD_UNSPECIFIED; 1282f8a70afaSLeon Romanovsky x->km.state = XFRM_STATE_DEAD; 1283f8a70afaSLeon Romanovsky to_put = x; 1284f8a70afaSLeon Romanovsky x = NULL; 1285f8a70afaSLeon Romanovsky goto out; 1286f8a70afaSLeon Romanovsky } 1287f8a70afaSLeon Romanovsky } 1288f8a70afaSLeon Romanovsky #endif 12891da177e4SLinus Torvalds if (km_query(x, tmpl, pol) == 0) { 1290d737a580SFlorian Westphal spin_lock_bh(&net->xfrm.xfrm_state_lock); 12911da177e4SLinus Torvalds x->km.state = XFRM_STATE_ACQ; 12925447c5e4SAlexey Dobriyan list_add(&x->km.all, &net->xfrm.state_all); 1293*3c611d40SLeon Romanovsky XFRM_STATE_INSERT(bydst, &x->bydst, 1294*3c611d40SLeon Romanovsky net->xfrm.state_bydst + h, 1295*3c611d40SLeon Romanovsky x->xso.type); 12968444cf71SThomas Egerer h = xfrm_src_hash(net, daddr, saddr, encap_family); 1297*3c611d40SLeon Romanovsky XFRM_STATE_INSERT(bysrc, &x->bysrc, 1298*3c611d40SLeon Romanovsky net->xfrm.state_bysrc + h, 1299*3c611d40SLeon Romanovsky x->xso.type); 13001da177e4SLinus Torvalds if (x->id.spi) { 13018444cf71SThomas Egerer h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, encap_family); 1302*3c611d40SLeon Romanovsky XFRM_STATE_INSERT(byspi, &x->byspi, 1303*3c611d40SLeon Romanovsky net->xfrm.state_byspi + h, 1304*3c611d40SLeon Romanovsky x->xso.type); 13051da177e4SLinus Torvalds } 1306fe9f1d87SSabrina Dubroca if (x->km.seq) { 1307fe9f1d87SSabrina Dubroca h = xfrm_seq_hash(net, x->km.seq); 1308*3c611d40SLeon Romanovsky XFRM_STATE_INSERT(byseq, &x->byseq, 1309*3c611d40SLeon Romanovsky net->xfrm.state_byseq + h, 1310*3c611d40SLeon Romanovsky x->xso.type); 1311fe9f1d87SSabrina Dubroca } 1312b27aeadbSAlexey Dobriyan x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires; 1313671422b2SThomas Gleixner hrtimer_start(&x->mtimer, 1314671422b2SThomas Gleixner ktime_set(net->xfrm.sysctl_acq_expires, 0), 1315671422b2SThomas Gleixner HRTIMER_MODE_REL_SOFT); 13165447c5e4SAlexey Dobriyan net->xfrm.state_num++; 13175447c5e4SAlexey Dobriyan xfrm_hash_grow_check(net, x->bydst.next != NULL); 1318d737a580SFlorian Westphal spin_unlock_bh(&net->xfrm.xfrm_state_lock); 13191da177e4SLinus Torvalds } else { 1320f8a70afaSLeon Romanovsky #ifdef CONFIG_XFRM_OFFLOAD 1321f8a70afaSLeon Romanovsky struct xfrm_dev_offload *xso = &x->xso; 1322f8a70afaSLeon Romanovsky 1323f8a70afaSLeon Romanovsky if (xso->type == XFRM_DEV_OFFLOAD_PACKET) { 1324f8a70afaSLeon Romanovsky xso->dev->xfrmdev_ops->xdo_dev_state_delete(x); 1325f8a70afaSLeon Romanovsky xso->dir = 0; 1326f8a70afaSLeon Romanovsky netdev_put(xso->dev, &xso->dev_tracker); 1327f8a70afaSLeon Romanovsky xso->dev = NULL; 1328f8a70afaSLeon Romanovsky xso->real_dev = NULL; 1329f8a70afaSLeon Romanovsky xso->type = XFRM_DEV_OFFLOAD_UNSPECIFIED; 1330f8a70afaSLeon Romanovsky } 1331f8a70afaSLeon Romanovsky #endif 13321da177e4SLinus Torvalds x->km.state = XFRM_STATE_DEAD; 133337b08e34SDavid S. Miller to_put = x; 13341da177e4SLinus Torvalds x = NULL; 13351da177e4SLinus Torvalds error = -ESRCH; 13361da177e4SLinus Torvalds } 13371da177e4SLinus Torvalds } 13381da177e4SLinus Torvalds out: 133902efdff7SFlorian Westphal if (x) { 134002efdff7SFlorian Westphal if (!xfrm_state_hold_rcu(x)) { 134102efdff7SFlorian Westphal *err = -EAGAIN; 134202efdff7SFlorian Westphal x = NULL; 134302efdff7SFlorian Westphal } 134402efdff7SFlorian Westphal } else { 13451da177e4SLinus Torvalds *err = acquire_in_progress ? -EAGAIN : error; 134602efdff7SFlorian Westphal } 1347d737a580SFlorian Westphal rcu_read_unlock(); 134837b08e34SDavid S. Miller if (to_put) 134937b08e34SDavid S. Miller xfrm_state_put(to_put); 1350b65e3d7bSFlorian Westphal 1351e88add19SAhmed S. Darwish if (read_seqcount_retry(&net->xfrm.xfrm_state_hash_generation, sequence)) { 1352b65e3d7bSFlorian Westphal *err = -EAGAIN; 1353b65e3d7bSFlorian Westphal if (x) { 1354b65e3d7bSFlorian Westphal xfrm_state_put(x); 1355b65e3d7bSFlorian Westphal x = NULL; 1356b65e3d7bSFlorian Westphal } 1357b65e3d7bSFlorian Westphal } 1358b65e3d7bSFlorian Westphal 13591da177e4SLinus Torvalds return x; 13601da177e4SLinus Torvalds } 13611da177e4SLinus Torvalds 1362628529b6SJamal Hadi Salim struct xfrm_state * 13637e652640SSteffen Klassert xfrm_stateonly_find(struct net *net, u32 mark, u32 if_id, 13645447c5e4SAlexey Dobriyan xfrm_address_t *daddr, xfrm_address_t *saddr, 1365628529b6SJamal Hadi Salim unsigned short family, u8 mode, u8 proto, u32 reqid) 1366628529b6SJamal Hadi Salim { 13674bda4f25SPavel Emelyanov unsigned int h; 1368628529b6SJamal Hadi Salim struct xfrm_state *rx = NULL, *x = NULL; 1369628529b6SJamal Hadi Salim 13704ae770bfSFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 13715447c5e4SAlexey Dobriyan h = xfrm_dst_hash(net, daddr, saddr, reqid, family); 1372b67bfe0dSSasha Levin hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) { 1373628529b6SJamal Hadi Salim if (x->props.family == family && 1374628529b6SJamal Hadi Salim x->props.reqid == reqid && 13753d6acfa7SJamal Hadi Salim (mark & x->mark.m) == x->mark.v && 13767e652640SSteffen Klassert x->if_id == if_id && 1377628529b6SJamal Hadi Salim !(x->props.flags & XFRM_STATE_WILDRECV) && 1378628529b6SJamal Hadi Salim xfrm_state_addr_check(x, daddr, saddr, family) && 1379628529b6SJamal Hadi Salim mode == x->props.mode && 1380628529b6SJamal Hadi Salim proto == x->id.proto && 1381628529b6SJamal Hadi Salim x->km.state == XFRM_STATE_VALID) { 1382628529b6SJamal Hadi Salim rx = x; 1383628529b6SJamal Hadi Salim break; 1384628529b6SJamal Hadi Salim } 1385628529b6SJamal Hadi Salim } 1386628529b6SJamal Hadi Salim 1387628529b6SJamal Hadi Salim if (rx) 1388628529b6SJamal Hadi Salim xfrm_state_hold(rx); 13894ae770bfSFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 1390628529b6SJamal Hadi Salim 1391628529b6SJamal Hadi Salim 1392628529b6SJamal Hadi Salim return rx; 1393628529b6SJamal Hadi Salim } 1394628529b6SJamal Hadi Salim EXPORT_SYMBOL(xfrm_stateonly_find); 1395628529b6SJamal Hadi Salim 1396c454997eSFan Du struct xfrm_state *xfrm_state_lookup_byspi(struct net *net, __be32 spi, 1397c454997eSFan Du unsigned short family) 1398c454997eSFan Du { 1399c454997eSFan Du struct xfrm_state *x; 1400c454997eSFan Du struct xfrm_state_walk *w; 1401c454997eSFan Du 1402c454997eSFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 1403c454997eSFan Du list_for_each_entry(w, &net->xfrm.state_all, all) { 1404c454997eSFan Du x = container_of(w, struct xfrm_state, km); 1405c454997eSFan Du if (x->props.family != family || 1406c454997eSFan Du x->id.spi != spi) 1407c454997eSFan Du continue; 1408c454997eSFan Du 1409c454997eSFan Du xfrm_state_hold(x); 1410bdddbf69SLi RongQing spin_unlock_bh(&net->xfrm.xfrm_state_lock); 1411c454997eSFan Du return x; 1412c454997eSFan Du } 1413c454997eSFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 1414c454997eSFan Du return NULL; 1415c454997eSFan Du } 1416c454997eSFan Du EXPORT_SYMBOL(xfrm_state_lookup_byspi); 1417c454997eSFan Du 14181da177e4SLinus Torvalds static void __xfrm_state_insert(struct xfrm_state *x) 14191da177e4SLinus Torvalds { 142098806f75SAlexey Dobriyan struct net *net = xs_net(x); 1421a624c108SDavid S. Miller unsigned int h; 14221da177e4SLinus Torvalds 142398806f75SAlexey Dobriyan list_add(&x->km.all, &net->xfrm.state_all); 14244c563f76STimo Teras 142598806f75SAlexey Dobriyan h = xfrm_dst_hash(net, &x->id.daddr, &x->props.saddr, 1426c1969f29SDavid S. Miller x->props.reqid, x->props.family); 1427*3c611d40SLeon Romanovsky XFRM_STATE_INSERT(bydst, &x->bydst, net->xfrm.state_bydst + h, 1428*3c611d40SLeon Romanovsky x->xso.type); 14291da177e4SLinus Torvalds 143098806f75SAlexey Dobriyan h = xfrm_src_hash(net, &x->id.daddr, &x->props.saddr, x->props.family); 1431*3c611d40SLeon Romanovsky XFRM_STATE_INSERT(bysrc, &x->bysrc, net->xfrm.state_bysrc + h, 1432*3c611d40SLeon Romanovsky x->xso.type); 14336c44e6b7SMasahide NAKAMURA 14347b4dc360SMasahide NAKAMURA if (x->id.spi) { 143598806f75SAlexey Dobriyan h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, 14366c44e6b7SMasahide NAKAMURA x->props.family); 14371da177e4SLinus Torvalds 1438*3c611d40SLeon Romanovsky XFRM_STATE_INSERT(byspi, &x->byspi, net->xfrm.state_byspi + h, 1439*3c611d40SLeon Romanovsky x->xso.type); 14406c44e6b7SMasahide NAKAMURA } 14411da177e4SLinus Torvalds 1442fe9f1d87SSabrina Dubroca if (x->km.seq) { 1443fe9f1d87SSabrina Dubroca h = xfrm_seq_hash(net, x->km.seq); 1444fe9f1d87SSabrina Dubroca 1445*3c611d40SLeon Romanovsky XFRM_STATE_INSERT(byseq, &x->byseq, net->xfrm.state_byseq + h, 1446*3c611d40SLeon Romanovsky x->xso.type); 1447fe9f1d87SSabrina Dubroca } 1448fe9f1d87SSabrina Dubroca 1449671422b2SThomas Gleixner hrtimer_start(&x->mtimer, ktime_set(1, 0), HRTIMER_MODE_REL_SOFT); 1450a47f0ce0SDavid S. Miller if (x->replay_maxage) 1451a47f0ce0SDavid S. Miller mod_timer(&x->rtimer, jiffies + x->replay_maxage); 1452f8cd5488SJamal Hadi Salim 145398806f75SAlexey Dobriyan net->xfrm.state_num++; 1454f034b5d4SDavid S. Miller 145598806f75SAlexey Dobriyan xfrm_hash_grow_check(net, x->bydst.next != NULL); 14561da177e4SLinus Torvalds } 14571da177e4SLinus Torvalds 1458283bc9f3SFan Du /* net->xfrm.xfrm_state_lock is held */ 1459c7f5ea3aSDavid S. Miller static void __xfrm_state_bump_genids(struct xfrm_state *xnew) 1460c7f5ea3aSDavid S. Miller { 146198806f75SAlexey Dobriyan struct net *net = xs_net(xnew); 1462c7f5ea3aSDavid S. Miller unsigned short family = xnew->props.family; 1463c7f5ea3aSDavid S. Miller u32 reqid = xnew->props.reqid; 1464c7f5ea3aSDavid S. Miller struct xfrm_state *x; 1465c7f5ea3aSDavid S. Miller unsigned int h; 14663d6acfa7SJamal Hadi Salim u32 mark = xnew->mark.v & xnew->mark.m; 14677e652640SSteffen Klassert u32 if_id = xnew->if_id; 1468c7f5ea3aSDavid S. Miller 146998806f75SAlexey Dobriyan h = xfrm_dst_hash(net, &xnew->id.daddr, &xnew->props.saddr, reqid, family); 1470b67bfe0dSSasha Levin hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) { 1471c7f5ea3aSDavid S. Miller if (x->props.family == family && 1472c7f5ea3aSDavid S. Miller x->props.reqid == reqid && 14737e652640SSteffen Klassert x->if_id == if_id && 14743d6acfa7SJamal Hadi Salim (mark & x->mark.m) == x->mark.v && 147570e94e66SYOSHIFUJI Hideaki / 吉藤英明 xfrm_addr_equal(&x->id.daddr, &xnew->id.daddr, family) && 147670e94e66SYOSHIFUJI Hideaki / 吉藤英明 xfrm_addr_equal(&x->props.saddr, &xnew->props.saddr, family)) 147734996cb9SHerbert Xu x->genid++; 1478c7f5ea3aSDavid S. Miller } 1479c7f5ea3aSDavid S. Miller } 1480c7f5ea3aSDavid S. Miller 14811da177e4SLinus Torvalds void xfrm_state_insert(struct xfrm_state *x) 14821da177e4SLinus Torvalds { 1483283bc9f3SFan Du struct net *net = xs_net(x); 1484283bc9f3SFan Du 1485283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 1486c7f5ea3aSDavid S. Miller __xfrm_state_bump_genids(x); 14871da177e4SLinus Torvalds __xfrm_state_insert(x); 1488283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 14891da177e4SLinus Torvalds } 14901da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_insert); 14911da177e4SLinus Torvalds 1492283bc9f3SFan Du /* net->xfrm.xfrm_state_lock is held */ 1493e473fcb4SMathias Krause static struct xfrm_state *__find_acq_core(struct net *net, 1494e473fcb4SMathias Krause const struct xfrm_mark *m, 1495a70486f0SDavid S. Miller unsigned short family, u8 mode, 14967e652640SSteffen Klassert u32 reqid, u32 if_id, u8 proto, 1497a70486f0SDavid S. Miller const xfrm_address_t *daddr, 1498e473fcb4SMathias Krause const xfrm_address_t *saddr, 1499e473fcb4SMathias Krause int create) 15002770834cSDavid S. Miller { 15015447c5e4SAlexey Dobriyan unsigned int h = xfrm_dst_hash(net, daddr, saddr, reqid, family); 15022770834cSDavid S. Miller struct xfrm_state *x; 15033d6acfa7SJamal Hadi Salim u32 mark = m->v & m->m; 15042770834cSDavid S. Miller 1505b67bfe0dSSasha Levin hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) { 15062770834cSDavid S. Miller if (x->props.reqid != reqid || 15072770834cSDavid S. Miller x->props.mode != mode || 15082770834cSDavid S. Miller x->props.family != family || 15092770834cSDavid S. Miller x->km.state != XFRM_STATE_ACQ || 151075e252d9SJoy Latten x->id.spi != 0 || 15111802571bSWei Yongjun x->id.proto != proto || 15123d6acfa7SJamal Hadi Salim (mark & x->mark.m) != x->mark.v || 151370e94e66SYOSHIFUJI Hideaki / 吉藤英明 !xfrm_addr_equal(&x->id.daddr, daddr, family) || 151470e94e66SYOSHIFUJI Hideaki / 吉藤英明 !xfrm_addr_equal(&x->props.saddr, saddr, family)) 15152770834cSDavid S. Miller continue; 15162770834cSDavid S. Miller 15172770834cSDavid S. Miller xfrm_state_hold(x); 15182770834cSDavid S. Miller return x; 15192770834cSDavid S. Miller } 15202770834cSDavid S. Miller 15212770834cSDavid S. Miller if (!create) 15222770834cSDavid S. Miller return NULL; 15232770834cSDavid S. Miller 15245447c5e4SAlexey Dobriyan x = xfrm_state_alloc(net); 15252770834cSDavid S. Miller if (likely(x)) { 15262770834cSDavid S. Miller switch (family) { 15272770834cSDavid S. Miller case AF_INET: 15282770834cSDavid S. Miller x->sel.daddr.a4 = daddr->a4; 15292770834cSDavid S. Miller x->sel.saddr.a4 = saddr->a4; 15302770834cSDavid S. Miller x->sel.prefixlen_d = 32; 15312770834cSDavid S. Miller x->sel.prefixlen_s = 32; 15322770834cSDavid S. Miller x->props.saddr.a4 = saddr->a4; 15332770834cSDavid S. Miller x->id.daddr.a4 = daddr->a4; 15342770834cSDavid S. Miller break; 15352770834cSDavid S. Miller 15362770834cSDavid S. Miller case AF_INET6: 153715e318bdSJiri Benc x->sel.daddr.in6 = daddr->in6; 153815e318bdSJiri Benc x->sel.saddr.in6 = saddr->in6; 15392770834cSDavid S. Miller x->sel.prefixlen_d = 128; 15402770834cSDavid S. Miller x->sel.prefixlen_s = 128; 154115e318bdSJiri Benc x->props.saddr.in6 = saddr->in6; 154215e318bdSJiri Benc x->id.daddr.in6 = daddr->in6; 15432770834cSDavid S. Miller break; 15443ff50b79SStephen Hemminger } 15452770834cSDavid S. Miller 15462770834cSDavid S. Miller x->km.state = XFRM_STATE_ACQ; 15472770834cSDavid S. Miller x->id.proto = proto; 15482770834cSDavid S. Miller x->props.family = family; 15492770834cSDavid S. Miller x->props.mode = mode; 15502770834cSDavid S. Miller x->props.reqid = reqid; 15517e652640SSteffen Klassert x->if_id = if_id; 1552bd55775cSJamal Hadi Salim x->mark.v = m->v; 1553bd55775cSJamal Hadi Salim x->mark.m = m->m; 1554b27aeadbSAlexey Dobriyan x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires; 15552770834cSDavid S. Miller xfrm_state_hold(x); 1556671422b2SThomas Gleixner hrtimer_start(&x->mtimer, 1557671422b2SThomas Gleixner ktime_set(net->xfrm.sysctl_acq_expires, 0), 1558671422b2SThomas Gleixner HRTIMER_MODE_REL_SOFT); 15595447c5e4SAlexey Dobriyan list_add(&x->km.all, &net->xfrm.state_all); 1560*3c611d40SLeon Romanovsky XFRM_STATE_INSERT(bydst, &x->bydst, net->xfrm.state_bydst + h, 1561*3c611d40SLeon Romanovsky x->xso.type); 15625447c5e4SAlexey Dobriyan h = xfrm_src_hash(net, daddr, saddr, family); 1563*3c611d40SLeon Romanovsky XFRM_STATE_INSERT(bysrc, &x->bysrc, net->xfrm.state_bysrc + h, 1564*3c611d40SLeon Romanovsky x->xso.type); 1565918049f0SDavid S. Miller 15665447c5e4SAlexey Dobriyan net->xfrm.state_num++; 1567918049f0SDavid S. Miller 15685447c5e4SAlexey Dobriyan xfrm_hash_grow_check(net, x->bydst.next != NULL); 15692770834cSDavid S. Miller } 15702770834cSDavid S. Miller 15712770834cSDavid S. Miller return x; 15722770834cSDavid S. Miller } 15732770834cSDavid S. Miller 1574bd55775cSJamal Hadi Salim static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq); 15751da177e4SLinus Torvalds 15761da177e4SLinus Torvalds int xfrm_state_add(struct xfrm_state *x) 15771da177e4SLinus Torvalds { 15785447c5e4SAlexey Dobriyan struct net *net = xs_net(x); 157937b08e34SDavid S. Miller struct xfrm_state *x1, *to_put; 15801da177e4SLinus Torvalds int family; 15811da177e4SLinus Torvalds int err; 1582bd55775cSJamal Hadi Salim u32 mark = x->mark.v & x->mark.m; 1583eb2971b6SMasahide NAKAMURA int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY); 15841da177e4SLinus Torvalds 15851da177e4SLinus Torvalds family = x->props.family; 15861da177e4SLinus Torvalds 158737b08e34SDavid S. Miller to_put = NULL; 158837b08e34SDavid S. Miller 1589283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 15901da177e4SLinus Torvalds 1591edcd5821SDavid S. Miller x1 = __xfrm_state_locate(x, use_spi, family); 15921da177e4SLinus Torvalds if (x1) { 159337b08e34SDavid S. Miller to_put = x1; 15941da177e4SLinus Torvalds x1 = NULL; 15951da177e4SLinus Torvalds err = -EEXIST; 15961da177e4SLinus Torvalds goto out; 15971da177e4SLinus Torvalds } 15981da177e4SLinus Torvalds 1599eb2971b6SMasahide NAKAMURA if (use_spi && x->km.seq) { 1600bd55775cSJamal Hadi Salim x1 = __xfrm_find_acq_byseq(net, mark, x->km.seq); 160175e252d9SJoy Latten if (x1 && ((x1->id.proto != x->id.proto) || 160270e94e66SYOSHIFUJI Hideaki / 吉藤英明 !xfrm_addr_equal(&x1->id.daddr, &x->id.daddr, family))) { 160337b08e34SDavid S. Miller to_put = x1; 16041da177e4SLinus Torvalds x1 = NULL; 16051da177e4SLinus Torvalds } 16061da177e4SLinus Torvalds } 16071da177e4SLinus Torvalds 1608eb2971b6SMasahide NAKAMURA if (use_spi && !x1) 1609bd55775cSJamal Hadi Salim x1 = __find_acq_core(net, &x->mark, family, x->props.mode, 16107e652640SSteffen Klassert x->props.reqid, x->if_id, x->id.proto, 16111da177e4SLinus Torvalds &x->id.daddr, &x->props.saddr, 0); 16121da177e4SLinus Torvalds 1613c7f5ea3aSDavid S. Miller __xfrm_state_bump_genids(x); 16141da177e4SLinus Torvalds __xfrm_state_insert(x); 16151da177e4SLinus Torvalds err = 0; 16161da177e4SLinus Torvalds 16171da177e4SLinus Torvalds out: 1618283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 16191da177e4SLinus Torvalds 16201da177e4SLinus Torvalds if (x1) { 16211da177e4SLinus Torvalds xfrm_state_delete(x1); 16221da177e4SLinus Torvalds xfrm_state_put(x1); 16231da177e4SLinus Torvalds } 16241da177e4SLinus Torvalds 162537b08e34SDavid S. Miller if (to_put) 162637b08e34SDavid S. Miller xfrm_state_put(to_put); 162737b08e34SDavid S. Miller 16281da177e4SLinus Torvalds return err; 16291da177e4SLinus Torvalds } 16301da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_add); 16311da177e4SLinus Torvalds 163280c9abaaSShinta Sugimoto #ifdef CONFIG_XFRM_MIGRATE 16337aa05d30SAntony Antony static inline int clone_security(struct xfrm_state *x, struct xfrm_sec_ctx *security) 16347aa05d30SAntony Antony { 16357aa05d30SAntony Antony struct xfrm_user_sec_ctx *uctx; 16367aa05d30SAntony Antony int size = sizeof(*uctx) + security->ctx_len; 16377aa05d30SAntony Antony int err; 16387aa05d30SAntony Antony 16397aa05d30SAntony Antony uctx = kmalloc(size, GFP_KERNEL); 16407aa05d30SAntony Antony if (!uctx) 16417aa05d30SAntony Antony return -ENOMEM; 16427aa05d30SAntony Antony 16437aa05d30SAntony Antony uctx->exttype = XFRMA_SEC_CTX; 16447aa05d30SAntony Antony uctx->len = size; 16457aa05d30SAntony Antony uctx->ctx_doi = security->ctx_doi; 16467aa05d30SAntony Antony uctx->ctx_alg = security->ctx_alg; 16477aa05d30SAntony Antony uctx->ctx_len = security->ctx_len; 16487aa05d30SAntony Antony memcpy(uctx + 1, security->ctx_str, security->ctx_len); 16497aa05d30SAntony Antony err = security_xfrm_state_alloc(x, uctx); 16507aa05d30SAntony Antony kfree(uctx); 16517aa05d30SAntony Antony if (err) 16527aa05d30SAntony Antony return err; 16537aa05d30SAntony Antony 16547aa05d30SAntony Antony return 0; 16557aa05d30SAntony Antony } 16567aa05d30SAntony Antony 16574ab47d47SAntony Antony static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, 16584ab47d47SAntony Antony struct xfrm_encap_tmpl *encap) 165980c9abaaSShinta Sugimoto { 166098806f75SAlexey Dobriyan struct net *net = xs_net(orig); 166198806f75SAlexey Dobriyan struct xfrm_state *x = xfrm_state_alloc(net); 166280c9abaaSShinta Sugimoto if (!x) 1663553f9118SHerbert Xu goto out; 166480c9abaaSShinta Sugimoto 166580c9abaaSShinta Sugimoto memcpy(&x->id, &orig->id, sizeof(x->id)); 166680c9abaaSShinta Sugimoto memcpy(&x->sel, &orig->sel, sizeof(x->sel)); 166780c9abaaSShinta Sugimoto memcpy(&x->lft, &orig->lft, sizeof(x->lft)); 166880c9abaaSShinta Sugimoto x->props.mode = orig->props.mode; 166980c9abaaSShinta Sugimoto x->props.replay_window = orig->props.replay_window; 167080c9abaaSShinta Sugimoto x->props.reqid = orig->props.reqid; 167180c9abaaSShinta Sugimoto x->props.family = orig->props.family; 167280c9abaaSShinta Sugimoto x->props.saddr = orig->props.saddr; 167380c9abaaSShinta Sugimoto 167480c9abaaSShinta Sugimoto if (orig->aalg) { 16754447bb33SMartin Willi x->aalg = xfrm_algo_auth_clone(orig->aalg); 167680c9abaaSShinta Sugimoto if (!x->aalg) 167780c9abaaSShinta Sugimoto goto error; 167880c9abaaSShinta Sugimoto } 167980c9abaaSShinta Sugimoto x->props.aalgo = orig->props.aalgo; 168080c9abaaSShinta Sugimoto 1681ee5c2317SSteffen Klassert if (orig->aead) { 1682ee5c2317SSteffen Klassert x->aead = xfrm_algo_aead_clone(orig->aead); 168375bf50f4SAntony Antony x->geniv = orig->geniv; 1684ee5c2317SSteffen Klassert if (!x->aead) 1685ee5c2317SSteffen Klassert goto error; 1686ee5c2317SSteffen Klassert } 168780c9abaaSShinta Sugimoto if (orig->ealg) { 168880c9abaaSShinta Sugimoto x->ealg = xfrm_algo_clone(orig->ealg); 168980c9abaaSShinta Sugimoto if (!x->ealg) 169080c9abaaSShinta Sugimoto goto error; 169180c9abaaSShinta Sugimoto } 169280c9abaaSShinta Sugimoto x->props.ealgo = orig->props.ealgo; 169380c9abaaSShinta Sugimoto 169480c9abaaSShinta Sugimoto if (orig->calg) { 169580c9abaaSShinta Sugimoto x->calg = xfrm_algo_clone(orig->calg); 169680c9abaaSShinta Sugimoto if (!x->calg) 169780c9abaaSShinta Sugimoto goto error; 169880c9abaaSShinta Sugimoto } 169980c9abaaSShinta Sugimoto x->props.calgo = orig->props.calgo; 170080c9abaaSShinta Sugimoto 17014ab47d47SAntony Antony if (encap || orig->encap) { 17024ab47d47SAntony Antony if (encap) 17034ab47d47SAntony Antony x->encap = kmemdup(encap, sizeof(*x->encap), 17044ab47d47SAntony Antony GFP_KERNEL); 17054ab47d47SAntony Antony else 17064ab47d47SAntony Antony x->encap = kmemdup(orig->encap, sizeof(*x->encap), 17074ab47d47SAntony Antony GFP_KERNEL); 17084ab47d47SAntony Antony 170980c9abaaSShinta Sugimoto if (!x->encap) 171080c9abaaSShinta Sugimoto goto error; 171180c9abaaSShinta Sugimoto } 171280c9abaaSShinta Sugimoto 17137aa05d30SAntony Antony if (orig->security) 17147aa05d30SAntony Antony if (clone_security(x, orig->security)) 17157aa05d30SAntony Antony goto error; 17167aa05d30SAntony Antony 171780c9abaaSShinta Sugimoto if (orig->coaddr) { 171880c9abaaSShinta Sugimoto x->coaddr = kmemdup(orig->coaddr, sizeof(*x->coaddr), 171980c9abaaSShinta Sugimoto GFP_KERNEL); 172080c9abaaSShinta Sugimoto if (!x->coaddr) 172180c9abaaSShinta Sugimoto goto error; 172280c9abaaSShinta Sugimoto } 172380c9abaaSShinta Sugimoto 1724af2f464eSSteffen Klassert if (orig->replay_esn) { 1725cc9ab60eSSteffen Klassert if (xfrm_replay_clone(x, orig)) 1726af2f464eSSteffen Klassert goto error; 1727af2f464eSSteffen Klassert } 1728af2f464eSSteffen Klassert 1729bd55775cSJamal Hadi Salim memcpy(&x->mark, &orig->mark, sizeof(x->mark)); 1730545e5c57SAntony Antony memcpy(&x->props.smark, &orig->props.smark, sizeof(x->props.smark)); 1731bd55775cSJamal Hadi Salim 173280c9abaaSShinta Sugimoto x->props.flags = orig->props.flags; 1733a947b0a9SNicolas Dichtel x->props.extra_flags = orig->props.extra_flags; 173480c9abaaSShinta Sugimoto 17357e652640SSteffen Klassert x->if_id = orig->if_id; 1736ee5c2317SSteffen Klassert x->tfcpad = orig->tfcpad; 1737ee5c2317SSteffen Klassert x->replay_maxdiff = orig->replay_maxdiff; 1738ee5c2317SSteffen Klassert x->replay_maxage = orig->replay_maxage; 17398366685bSAntony Antony memcpy(&x->curlft, &orig->curlft, sizeof(x->curlft)); 174080c9abaaSShinta Sugimoto x->km.state = orig->km.state; 174180c9abaaSShinta Sugimoto x->km.seq = orig->km.seq; 1742a486cd23SAntony Antony x->replay = orig->replay; 1743a486cd23SAntony Antony x->preplay = orig->preplay; 17444e484b3eSAntony Antony x->mapping_maxage = orig->mapping_maxage; 17456aa811acSAntony Antony x->lastused = orig->lastused; 17464e484b3eSAntony Antony x->new_mapping = 0; 17474e484b3eSAntony Antony x->new_mapping_sport = 0; 174880c9abaaSShinta Sugimoto 174980c9abaaSShinta Sugimoto return x; 175080c9abaaSShinta Sugimoto 175180c9abaaSShinta Sugimoto error: 1752553f9118SHerbert Xu xfrm_state_put(x); 1753553f9118SHerbert Xu out: 175480c9abaaSShinta Sugimoto return NULL; 175580c9abaaSShinta Sugimoto } 175680c9abaaSShinta Sugimoto 1757c1aca308SYan Yan struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *net, 1758c1aca308SYan Yan u32 if_id) 175980c9abaaSShinta Sugimoto { 176080c9abaaSShinta Sugimoto unsigned int h; 17618c0cba22SSteffen Klassert struct xfrm_state *x = NULL; 17628c0cba22SSteffen Klassert 17638c0cba22SSteffen Klassert spin_lock_bh(&net->xfrm.xfrm_state_lock); 176480c9abaaSShinta Sugimoto 176580c9abaaSShinta Sugimoto if (m->reqid) { 1766283bc9f3SFan Du h = xfrm_dst_hash(net, &m->old_daddr, &m->old_saddr, 176780c9abaaSShinta Sugimoto m->reqid, m->old_family); 1768283bc9f3SFan Du hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) { 176980c9abaaSShinta Sugimoto if (x->props.mode != m->mode || 177080c9abaaSShinta Sugimoto x->id.proto != m->proto) 177180c9abaaSShinta Sugimoto continue; 177280c9abaaSShinta Sugimoto if (m->reqid && x->props.reqid != m->reqid) 177380c9abaaSShinta Sugimoto continue; 1774c1aca308SYan Yan if (if_id != 0 && x->if_id != if_id) 1775c1aca308SYan Yan continue; 177670e94e66SYOSHIFUJI Hideaki / 吉藤英明 if (!xfrm_addr_equal(&x->id.daddr, &m->old_daddr, 177780c9abaaSShinta Sugimoto m->old_family) || 177870e94e66SYOSHIFUJI Hideaki / 吉藤英明 !xfrm_addr_equal(&x->props.saddr, &m->old_saddr, 177980c9abaaSShinta Sugimoto m->old_family)) 178080c9abaaSShinta Sugimoto continue; 178180c9abaaSShinta Sugimoto xfrm_state_hold(x); 17828c0cba22SSteffen Klassert break; 178380c9abaaSShinta Sugimoto } 178480c9abaaSShinta Sugimoto } else { 1785283bc9f3SFan Du h = xfrm_src_hash(net, &m->old_daddr, &m->old_saddr, 178680c9abaaSShinta Sugimoto m->old_family); 1787283bc9f3SFan Du hlist_for_each_entry(x, net->xfrm.state_bysrc+h, bysrc) { 178880c9abaaSShinta Sugimoto if (x->props.mode != m->mode || 178980c9abaaSShinta Sugimoto x->id.proto != m->proto) 179080c9abaaSShinta Sugimoto continue; 1791c1aca308SYan Yan if (if_id != 0 && x->if_id != if_id) 1792c1aca308SYan Yan continue; 179370e94e66SYOSHIFUJI Hideaki / 吉藤英明 if (!xfrm_addr_equal(&x->id.daddr, &m->old_daddr, 179480c9abaaSShinta Sugimoto m->old_family) || 179570e94e66SYOSHIFUJI Hideaki / 吉藤英明 !xfrm_addr_equal(&x->props.saddr, &m->old_saddr, 179680c9abaaSShinta Sugimoto m->old_family)) 179780c9abaaSShinta Sugimoto continue; 179880c9abaaSShinta Sugimoto xfrm_state_hold(x); 17998c0cba22SSteffen Klassert break; 180080c9abaaSShinta Sugimoto } 180180c9abaaSShinta Sugimoto } 180280c9abaaSShinta Sugimoto 18038c0cba22SSteffen Klassert spin_unlock_bh(&net->xfrm.xfrm_state_lock); 18048c0cba22SSteffen Klassert 18058c0cba22SSteffen Klassert return x; 180680c9abaaSShinta Sugimoto } 180780c9abaaSShinta Sugimoto EXPORT_SYMBOL(xfrm_migrate_state_find); 180880c9abaaSShinta Sugimoto 180980c9abaaSShinta Sugimoto struct xfrm_state *xfrm_state_migrate(struct xfrm_state *x, 18104ab47d47SAntony Antony struct xfrm_migrate *m, 18114ab47d47SAntony Antony struct xfrm_encap_tmpl *encap) 181280c9abaaSShinta Sugimoto { 181380c9abaaSShinta Sugimoto struct xfrm_state *xc; 181480c9abaaSShinta Sugimoto 18154ab47d47SAntony Antony xc = xfrm_state_clone(x, encap); 181680c9abaaSShinta Sugimoto if (!xc) 181780c9abaaSShinta Sugimoto return NULL; 181880c9abaaSShinta Sugimoto 1819e03c3bbaSYan Yan xc->props.family = m->new_family; 1820e03c3bbaSYan Yan 1821e03c3bbaSYan Yan if (xfrm_init_state(xc) < 0) 1822e03c3bbaSYan Yan goto error; 1823e03c3bbaSYan Yan 182480c9abaaSShinta Sugimoto memcpy(&xc->id.daddr, &m->new_daddr, sizeof(xc->id.daddr)); 182580c9abaaSShinta Sugimoto memcpy(&xc->props.saddr, &m->new_saddr, sizeof(xc->props.saddr)); 182680c9abaaSShinta Sugimoto 182780c9abaaSShinta Sugimoto /* add state */ 182870e94e66SYOSHIFUJI Hideaki / 吉藤英明 if (xfrm_addr_equal(&x->id.daddr, &m->new_daddr, m->new_family)) { 182980c9abaaSShinta Sugimoto /* a care is needed when the destination address of the 183080c9abaaSShinta Sugimoto state is to be updated as it is a part of triplet */ 183180c9abaaSShinta Sugimoto xfrm_state_insert(xc); 183280c9abaaSShinta Sugimoto } else { 1833cc9ab60eSSteffen Klassert if (xfrm_state_add(xc) < 0) 183480c9abaaSShinta Sugimoto goto error; 183580c9abaaSShinta Sugimoto } 183680c9abaaSShinta Sugimoto 183780c9abaaSShinta Sugimoto return xc; 183880c9abaaSShinta Sugimoto error: 183978347c8cSThomas Egerer xfrm_state_put(xc); 184080c9abaaSShinta Sugimoto return NULL; 184180c9abaaSShinta Sugimoto } 184280c9abaaSShinta Sugimoto EXPORT_SYMBOL(xfrm_state_migrate); 184380c9abaaSShinta Sugimoto #endif 184480c9abaaSShinta Sugimoto 18451da177e4SLinus Torvalds int xfrm_state_update(struct xfrm_state *x) 18461da177e4SLinus Torvalds { 184737b08e34SDavid S. Miller struct xfrm_state *x1, *to_put; 18481da177e4SLinus Torvalds int err; 1849eb2971b6SMasahide NAKAMURA int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY); 1850283bc9f3SFan Du struct net *net = xs_net(x); 18511da177e4SLinus Torvalds 185237b08e34SDavid S. Miller to_put = NULL; 185337b08e34SDavid S. Miller 1854283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 1855edcd5821SDavid S. Miller x1 = __xfrm_state_locate(x, use_spi, x->props.family); 18561da177e4SLinus Torvalds 18571da177e4SLinus Torvalds err = -ESRCH; 18581da177e4SLinus Torvalds if (!x1) 18591da177e4SLinus Torvalds goto out; 18601da177e4SLinus Torvalds 18611da177e4SLinus Torvalds if (xfrm_state_kern(x1)) { 186237b08e34SDavid S. Miller to_put = x1; 18631da177e4SLinus Torvalds err = -EEXIST; 18641da177e4SLinus Torvalds goto out; 18651da177e4SLinus Torvalds } 18661da177e4SLinus Torvalds 18671da177e4SLinus Torvalds if (x1->km.state == XFRM_STATE_ACQ) { 18681da177e4SLinus Torvalds __xfrm_state_insert(x); 18691da177e4SLinus Torvalds x = NULL; 18701da177e4SLinus Torvalds } 18711da177e4SLinus Torvalds err = 0; 18721da177e4SLinus Torvalds 18731da177e4SLinus Torvalds out: 1874283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 18751da177e4SLinus Torvalds 187637b08e34SDavid S. Miller if (to_put) 187737b08e34SDavid S. Miller xfrm_state_put(to_put); 187837b08e34SDavid S. Miller 18791da177e4SLinus Torvalds if (err) 18801da177e4SLinus Torvalds return err; 18811da177e4SLinus Torvalds 18821da177e4SLinus Torvalds if (!x) { 18831da177e4SLinus Torvalds xfrm_state_delete(x1); 18841da177e4SLinus Torvalds xfrm_state_put(x1); 18851da177e4SLinus Torvalds return 0; 18861da177e4SLinus Torvalds } 18871da177e4SLinus Torvalds 18881da177e4SLinus Torvalds err = -EINVAL; 18891da177e4SLinus Torvalds spin_lock_bh(&x1->lock); 18901da177e4SLinus Torvalds if (likely(x1->km.state == XFRM_STATE_VALID)) { 1891257a4b01SHerbert Xu if (x->encap && x1->encap && 1892257a4b01SHerbert Xu x->encap->encap_type == x1->encap->encap_type) 18931da177e4SLinus Torvalds memcpy(x1->encap, x->encap, sizeof(*x1->encap)); 1894257a4b01SHerbert Xu else if (x->encap || x1->encap) 1895257a4b01SHerbert Xu goto fail; 1896257a4b01SHerbert Xu 1897060f02a3SNoriaki TAKAMIYA if (x->coaddr && x1->coaddr) { 1898060f02a3SNoriaki TAKAMIYA memcpy(x1->coaddr, x->coaddr, sizeof(*x1->coaddr)); 1899060f02a3SNoriaki TAKAMIYA } 1900060f02a3SNoriaki TAKAMIYA if (!use_spi && memcmp(&x1->sel, &x->sel, sizeof(x1->sel))) 1901060f02a3SNoriaki TAKAMIYA memcpy(&x1->sel, &x->sel, sizeof(x1->sel)); 19021da177e4SLinus Torvalds memcpy(&x1->lft, &x->lft, sizeof(x1->lft)); 19031da177e4SLinus Torvalds x1->km.dying = 0; 19041da177e4SLinus Torvalds 1905671422b2SThomas Gleixner hrtimer_start(&x1->mtimer, ktime_set(1, 0), 1906671422b2SThomas Gleixner HRTIMER_MODE_REL_SOFT); 19071da177e4SLinus Torvalds if (x1->curlft.use_time) 19081da177e4SLinus Torvalds xfrm_state_check_expire(x1); 19091da177e4SLinus Torvalds 19105baf4f9cSNathan Harold if (x->props.smark.m || x->props.smark.v || x->if_id) { 19116d8e85ffSNathan Harold spin_lock_bh(&net->xfrm.xfrm_state_lock); 19126d8e85ffSNathan Harold 19135baf4f9cSNathan Harold if (x->props.smark.m || x->props.smark.v) 19146d8e85ffSNathan Harold x1->props.smark = x->props.smark; 19156d8e85ffSNathan Harold 19165baf4f9cSNathan Harold if (x->if_id) 19175baf4f9cSNathan Harold x1->if_id = x->if_id; 19185baf4f9cSNathan Harold 19196d8e85ffSNathan Harold __xfrm_state_bump_genids(x1); 19206d8e85ffSNathan Harold spin_unlock_bh(&net->xfrm.xfrm_state_lock); 19216d8e85ffSNathan Harold } 19226d8e85ffSNathan Harold 19231da177e4SLinus Torvalds err = 0; 19248fcbc637STushar Gohad x->km.state = XFRM_STATE_DEAD; 19258fcbc637STushar Gohad __xfrm_state_put(x); 19261da177e4SLinus Torvalds } 1927257a4b01SHerbert Xu 1928257a4b01SHerbert Xu fail: 19291da177e4SLinus Torvalds spin_unlock_bh(&x1->lock); 19301da177e4SLinus Torvalds 19311da177e4SLinus Torvalds xfrm_state_put(x1); 19321da177e4SLinus Torvalds 19331da177e4SLinus Torvalds return err; 19341da177e4SLinus Torvalds } 19351da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_update); 19361da177e4SLinus Torvalds 19371da177e4SLinus Torvalds int xfrm_state_check_expire(struct xfrm_state *x) 19381da177e4SLinus Torvalds { 19391da177e4SLinus Torvalds if (!x->curlft.use_time) 1940386c5680SArnd Bergmann x->curlft.use_time = ktime_get_real_seconds(); 19411da177e4SLinus Torvalds 19421da177e4SLinus Torvalds if (x->curlft.bytes >= x->lft.hard_byte_limit || 19431da177e4SLinus Torvalds x->curlft.packets >= x->lft.hard_packet_limit) { 19444666faabSHerbert Xu x->km.state = XFRM_STATE_EXPIRED; 1945671422b2SThomas Gleixner hrtimer_start(&x->mtimer, 0, HRTIMER_MODE_REL_SOFT); 19461da177e4SLinus Torvalds return -EINVAL; 19471da177e4SLinus Torvalds } 19481da177e4SLinus Torvalds 19491da177e4SLinus Torvalds if (!x->km.dying && 19501da177e4SLinus Torvalds (x->curlft.bytes >= x->lft.soft_byte_limit || 19514666faabSHerbert Xu x->curlft.packets >= x->lft.soft_packet_limit)) { 19524666faabSHerbert Xu x->km.dying = 1; 195353bc6b4dSJamal Hadi Salim km_state_expired(x, 0, 0); 19544666faabSHerbert Xu } 19551da177e4SLinus Torvalds return 0; 19561da177e4SLinus Torvalds } 19571da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_check_expire); 19581da177e4SLinus Torvalds 19591da177e4SLinus Torvalds struct xfrm_state * 1960a70486f0SDavid S. Miller xfrm_state_lookup(struct net *net, u32 mark, const xfrm_address_t *daddr, __be32 spi, 1961bd55775cSJamal Hadi Salim u8 proto, unsigned short family) 19621da177e4SLinus Torvalds { 19631da177e4SLinus Torvalds struct xfrm_state *x; 19641da177e4SLinus Torvalds 1965c2f672fcSFlorian Westphal rcu_read_lock(); 1966bd55775cSJamal Hadi Salim x = __xfrm_state_lookup(net, mark, daddr, spi, proto, family); 1967c2f672fcSFlorian Westphal rcu_read_unlock(); 19681da177e4SLinus Torvalds return x; 19691da177e4SLinus Torvalds } 19701da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_lookup); 19711da177e4SLinus Torvalds 19721da177e4SLinus Torvalds struct xfrm_state * 1973bd55775cSJamal Hadi Salim xfrm_state_lookup_byaddr(struct net *net, u32 mark, 1974a70486f0SDavid S. Miller const xfrm_address_t *daddr, const xfrm_address_t *saddr, 1975eb2971b6SMasahide NAKAMURA u8 proto, unsigned short family) 1976eb2971b6SMasahide NAKAMURA { 1977eb2971b6SMasahide NAKAMURA struct xfrm_state *x; 1978eb2971b6SMasahide NAKAMURA 1979283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 1980bd55775cSJamal Hadi Salim x = __xfrm_state_lookup_byaddr(net, mark, daddr, saddr, proto, family); 1981283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 1982eb2971b6SMasahide NAKAMURA return x; 1983eb2971b6SMasahide NAKAMURA } 1984eb2971b6SMasahide NAKAMURA EXPORT_SYMBOL(xfrm_state_lookup_byaddr); 1985eb2971b6SMasahide NAKAMURA 1986eb2971b6SMasahide NAKAMURA struct xfrm_state * 1987e473fcb4SMathias Krause xfrm_find_acq(struct net *net, const struct xfrm_mark *mark, u8 mode, u32 reqid, 19887e652640SSteffen Klassert u32 if_id, u8 proto, const xfrm_address_t *daddr, 1989e473fcb4SMathias Krause const xfrm_address_t *saddr, int create, unsigned short family) 19901da177e4SLinus Torvalds { 19911da177e4SLinus Torvalds struct xfrm_state *x; 19921da177e4SLinus Torvalds 1993283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 19947e652640SSteffen Klassert x = __find_acq_core(net, mark, family, mode, reqid, if_id, proto, daddr, saddr, create); 1995283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 19962770834cSDavid S. Miller 19971da177e4SLinus Torvalds return x; 19981da177e4SLinus Torvalds } 19991da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_find_acq); 20001da177e4SLinus Torvalds 200141a49cc3SMasahide NAKAMURA #ifdef CONFIG_XFRM_SUB_POLICY 20023aaf3915SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6) 20033aaf3915SFlorian Westphal /* distribution counting sort function for xfrm_state and xfrm_tmpl */ 20043aaf3915SFlorian Westphal static void 20053aaf3915SFlorian Westphal __xfrm6_sort(void **dst, void **src, int n, 20063aaf3915SFlorian Westphal int (*cmp)(const void *p), int maxclass) 20073aaf3915SFlorian Westphal { 20083aaf3915SFlorian Westphal int count[XFRM_MAX_DEPTH] = { }; 20093aaf3915SFlorian Westphal int class[XFRM_MAX_DEPTH]; 20103aaf3915SFlorian Westphal int i; 20113aaf3915SFlorian Westphal 20123aaf3915SFlorian Westphal for (i = 0; i < n; i++) { 20133aaf3915SFlorian Westphal int c = cmp(src[i]); 20143aaf3915SFlorian Westphal 20153aaf3915SFlorian Westphal class[i] = c; 20163aaf3915SFlorian Westphal count[c]++; 20173aaf3915SFlorian Westphal } 20183aaf3915SFlorian Westphal 20193aaf3915SFlorian Westphal for (i = 2; i < maxclass; i++) 20203aaf3915SFlorian Westphal count[i] += count[i - 1]; 20213aaf3915SFlorian Westphal 20223aaf3915SFlorian Westphal for (i = 0; i < n; i++) { 20233aaf3915SFlorian Westphal dst[count[class[i] - 1]++] = src[i]; 20243aaf3915SFlorian Westphal src[i] = NULL; 20253aaf3915SFlorian Westphal } 20263aaf3915SFlorian Westphal } 20273aaf3915SFlorian Westphal 20283aaf3915SFlorian Westphal /* Rule for xfrm_state: 20293aaf3915SFlorian Westphal * 20303aaf3915SFlorian Westphal * rule 1: select IPsec transport except AH 20313aaf3915SFlorian Westphal * rule 2: select MIPv6 RO or inbound trigger 20323aaf3915SFlorian Westphal * rule 3: select IPsec transport AH 20333aaf3915SFlorian Westphal * rule 4: select IPsec tunnel 20343aaf3915SFlorian Westphal * rule 5: others 20353aaf3915SFlorian Westphal */ 20363aaf3915SFlorian Westphal static int __xfrm6_state_sort_cmp(const void *p) 20373aaf3915SFlorian Westphal { 20383aaf3915SFlorian Westphal const struct xfrm_state *v = p; 20393aaf3915SFlorian Westphal 20403aaf3915SFlorian Westphal switch (v->props.mode) { 20413aaf3915SFlorian Westphal case XFRM_MODE_TRANSPORT: 20423aaf3915SFlorian Westphal if (v->id.proto != IPPROTO_AH) 20433aaf3915SFlorian Westphal return 1; 20443aaf3915SFlorian Westphal else 20453aaf3915SFlorian Westphal return 3; 20463aaf3915SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6_MIP6) 20473aaf3915SFlorian Westphal case XFRM_MODE_ROUTEOPTIMIZATION: 20483aaf3915SFlorian Westphal case XFRM_MODE_IN_TRIGGER: 20493aaf3915SFlorian Westphal return 2; 20503aaf3915SFlorian Westphal #endif 20513aaf3915SFlorian Westphal case XFRM_MODE_TUNNEL: 20523aaf3915SFlorian Westphal case XFRM_MODE_BEET: 20533aaf3915SFlorian Westphal return 4; 20543aaf3915SFlorian Westphal } 20553aaf3915SFlorian Westphal return 5; 20563aaf3915SFlorian Westphal } 20573aaf3915SFlorian Westphal 20583aaf3915SFlorian Westphal /* Rule for xfrm_tmpl: 20593aaf3915SFlorian Westphal * 20603aaf3915SFlorian Westphal * rule 1: select IPsec transport 20613aaf3915SFlorian Westphal * rule 2: select MIPv6 RO or inbound trigger 20623aaf3915SFlorian Westphal * rule 3: select IPsec tunnel 20633aaf3915SFlorian Westphal * rule 4: others 20643aaf3915SFlorian Westphal */ 20653aaf3915SFlorian Westphal static int __xfrm6_tmpl_sort_cmp(const void *p) 20663aaf3915SFlorian Westphal { 20673aaf3915SFlorian Westphal const struct xfrm_tmpl *v = p; 20683aaf3915SFlorian Westphal 20693aaf3915SFlorian Westphal switch (v->mode) { 20703aaf3915SFlorian Westphal case XFRM_MODE_TRANSPORT: 20713aaf3915SFlorian Westphal return 1; 20723aaf3915SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6_MIP6) 20733aaf3915SFlorian Westphal case XFRM_MODE_ROUTEOPTIMIZATION: 20743aaf3915SFlorian Westphal case XFRM_MODE_IN_TRIGGER: 20753aaf3915SFlorian Westphal return 2; 20763aaf3915SFlorian Westphal #endif 20773aaf3915SFlorian Westphal case XFRM_MODE_TUNNEL: 20783aaf3915SFlorian Westphal case XFRM_MODE_BEET: 20793aaf3915SFlorian Westphal return 3; 20803aaf3915SFlorian Westphal } 20813aaf3915SFlorian Westphal return 4; 20823aaf3915SFlorian Westphal } 20833aaf3915SFlorian Westphal #else 20843aaf3915SFlorian Westphal static inline int __xfrm6_state_sort_cmp(const void *p) { return 5; } 20853aaf3915SFlorian Westphal static inline int __xfrm6_tmpl_sort_cmp(const void *p) { return 4; } 20863aaf3915SFlorian Westphal 20873aaf3915SFlorian Westphal static inline void 20883aaf3915SFlorian Westphal __xfrm6_sort(void **dst, void **src, int n, 20893aaf3915SFlorian Westphal int (*cmp)(const void *p), int maxclass) 209041a49cc3SMasahide NAKAMURA { 20913f5a95adSKoichiro Den int i; 209241a49cc3SMasahide NAKAMURA 20933aaf3915SFlorian Westphal for (i = 0; i < n; i++) 20943aaf3915SFlorian Westphal dst[i] = src[i]; 20953aaf3915SFlorian Westphal } 20963aaf3915SFlorian Westphal #endif /* CONFIG_IPV6 */ 20973aaf3915SFlorian Westphal 20983aaf3915SFlorian Westphal void 20993aaf3915SFlorian Westphal xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n, 21003aaf3915SFlorian Westphal unsigned short family) 21013aaf3915SFlorian Westphal { 21023aaf3915SFlorian Westphal int i; 21033aaf3915SFlorian Westphal 21043aaf3915SFlorian Westphal if (family == AF_INET6) 21053aaf3915SFlorian Westphal __xfrm6_sort((void **)dst, (void **)src, n, 21063aaf3915SFlorian Westphal __xfrm6_tmpl_sort_cmp, 5); 21073f5a95adSKoichiro Den else 21083f5a95adSKoichiro Den for (i = 0; i < n; i++) 21093f5a95adSKoichiro Den dst[i] = src[i]; 211041a49cc3SMasahide NAKAMURA } 211141a49cc3SMasahide NAKAMURA 21123aaf3915SFlorian Westphal void 211341a49cc3SMasahide NAKAMURA xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n, 211441a49cc3SMasahide NAKAMURA unsigned short family) 211541a49cc3SMasahide NAKAMURA { 21163f5a95adSKoichiro Den int i; 2117283bc9f3SFan Du 21183aaf3915SFlorian Westphal if (family == AF_INET6) 21193aaf3915SFlorian Westphal __xfrm6_sort((void **)dst, (void **)src, n, 21203aaf3915SFlorian Westphal __xfrm6_state_sort_cmp, 6); 21213f5a95adSKoichiro Den else 21223f5a95adSKoichiro Den for (i = 0; i < n; i++) 21233f5a95adSKoichiro Den dst[i] = src[i]; 212441a49cc3SMasahide NAKAMURA } 212541a49cc3SMasahide NAKAMURA #endif 212641a49cc3SMasahide NAKAMURA 21271da177e4SLinus Torvalds /* Silly enough, but I'm lazy to build resolution list */ 21281da177e4SLinus Torvalds 2129bd55775cSJamal Hadi Salim static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq) 21301da177e4SLinus Torvalds { 2131fe9f1d87SSabrina Dubroca unsigned int h = xfrm_seq_hash(net, seq); 21328f126e37SDavid S. Miller struct xfrm_state *x; 21338f126e37SDavid S. Miller 2134fe9f1d87SSabrina Dubroca hlist_for_each_entry_rcu(x, net->xfrm.state_byseq + h, byseq) { 21358f126e37SDavid S. Miller if (x->km.seq == seq && 21363d6acfa7SJamal Hadi Salim (mark & x->mark.m) == x->mark.v && 21378f126e37SDavid S. Miller x->km.state == XFRM_STATE_ACQ) { 21381da177e4SLinus Torvalds xfrm_state_hold(x); 21391da177e4SLinus Torvalds return x; 21401da177e4SLinus Torvalds } 21411da177e4SLinus Torvalds } 2142fe9f1d87SSabrina Dubroca 21431da177e4SLinus Torvalds return NULL; 21441da177e4SLinus Torvalds } 21451da177e4SLinus Torvalds 2146bd55775cSJamal Hadi Salim struct xfrm_state *xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq) 21471da177e4SLinus Torvalds { 21481da177e4SLinus Torvalds struct xfrm_state *x; 21491da177e4SLinus Torvalds 2150283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 2151bd55775cSJamal Hadi Salim x = __xfrm_find_acq_byseq(net, mark, seq); 2152283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 21531da177e4SLinus Torvalds return x; 21541da177e4SLinus Torvalds } 21551da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_find_acq_byseq); 21561da177e4SLinus Torvalds 21571da177e4SLinus Torvalds u32 xfrm_get_acqseq(void) 21581da177e4SLinus Torvalds { 21591da177e4SLinus Torvalds u32 res; 21606836b9bdSjamal static atomic_t acqseq; 21611da177e4SLinus Torvalds 21626836b9bdSjamal do { 21636836b9bdSjamal res = atomic_inc_return(&acqseq); 21646836b9bdSjamal } while (!res); 21656836b9bdSjamal 21661da177e4SLinus Torvalds return res; 21671da177e4SLinus Torvalds } 21681da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_get_acqseq); 21691da177e4SLinus Torvalds 2170c2dad11eSSabrina Dubroca int verify_spi_info(u8 proto, u32 min, u32 max, struct netlink_ext_ack *extack) 2171776e9dd9SFan Du { 2172776e9dd9SFan Du switch (proto) { 2173776e9dd9SFan Du case IPPROTO_AH: 2174776e9dd9SFan Du case IPPROTO_ESP: 2175776e9dd9SFan Du break; 2176776e9dd9SFan Du 2177776e9dd9SFan Du case IPPROTO_COMP: 2178776e9dd9SFan Du /* IPCOMP spi is 16-bits. */ 2179c2dad11eSSabrina Dubroca if (max >= 0x10000) { 2180c2dad11eSSabrina Dubroca NL_SET_ERR_MSG(extack, "IPCOMP SPI must be <= 65535"); 2181776e9dd9SFan Du return -EINVAL; 2182c2dad11eSSabrina Dubroca } 2183776e9dd9SFan Du break; 2184776e9dd9SFan Du 2185776e9dd9SFan Du default: 2186c2dad11eSSabrina Dubroca NL_SET_ERR_MSG(extack, "Invalid protocol, must be one of AH, ESP, IPCOMP"); 2187776e9dd9SFan Du return -EINVAL; 2188776e9dd9SFan Du } 2189776e9dd9SFan Du 2190c2dad11eSSabrina Dubroca if (min > max) { 2191c2dad11eSSabrina Dubroca NL_SET_ERR_MSG(extack, "Invalid SPI range: min > max"); 2192776e9dd9SFan Du return -EINVAL; 2193c2dad11eSSabrina Dubroca } 2194776e9dd9SFan Du 2195776e9dd9SFan Du return 0; 2196776e9dd9SFan Du } 2197776e9dd9SFan Du EXPORT_SYMBOL(verify_spi_info); 2198776e9dd9SFan Du 2199c2dad11eSSabrina Dubroca int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high, 2200c2dad11eSSabrina Dubroca struct netlink_ext_ack *extack) 22011da177e4SLinus Torvalds { 2202221df1edSAlexey Dobriyan struct net *net = xs_net(x); 2203f034b5d4SDavid S. Miller unsigned int h; 22041da177e4SLinus Torvalds struct xfrm_state *x0; 2205658b219eSHerbert Xu int err = -ENOENT; 2206658b219eSHerbert Xu __be32 minspi = htonl(low); 2207658b219eSHerbert Xu __be32 maxspi = htonl(high); 2208a779d913Szhuoliang zhang __be32 newspi = 0; 2209bd55775cSJamal Hadi Salim u32 mark = x->mark.v & x->mark.m; 22101da177e4SLinus Torvalds 2211658b219eSHerbert Xu spin_lock_bh(&x->lock); 2212c2dad11eSSabrina Dubroca if (x->km.state == XFRM_STATE_DEAD) { 2213c2dad11eSSabrina Dubroca NL_SET_ERR_MSG(extack, "Target ACQUIRE is in DEAD state"); 2214658b219eSHerbert Xu goto unlock; 2215c2dad11eSSabrina Dubroca } 2216658b219eSHerbert Xu 2217658b219eSHerbert Xu err = 0; 22181da177e4SLinus Torvalds if (x->id.spi) 2219658b219eSHerbert Xu goto unlock; 2220658b219eSHerbert Xu 2221658b219eSHerbert Xu err = -ENOENT; 22221da177e4SLinus Torvalds 22231da177e4SLinus Torvalds if (minspi == maxspi) { 2224bd55775cSJamal Hadi Salim x0 = xfrm_state_lookup(net, mark, &x->id.daddr, minspi, x->id.proto, x->props.family); 22251da177e4SLinus Torvalds if (x0) { 2226c2dad11eSSabrina Dubroca NL_SET_ERR_MSG(extack, "Requested SPI is already in use"); 22271da177e4SLinus Torvalds xfrm_state_put(x0); 2228658b219eSHerbert Xu goto unlock; 22291da177e4SLinus Torvalds } 2230a779d913Szhuoliang zhang newspi = minspi; 22311da177e4SLinus Torvalds } else { 22321da177e4SLinus Torvalds u32 spi = 0; 223326977b4eSAl Viro for (h = 0; h < high-low+1; h++) { 223481895a65SJason A. Donenfeld spi = low + prandom_u32_max(high - low + 1); 2235bd55775cSJamal Hadi Salim x0 = xfrm_state_lookup(net, mark, &x->id.daddr, htonl(spi), x->id.proto, x->props.family); 22361da177e4SLinus Torvalds if (x0 == NULL) { 2237a779d913Szhuoliang zhang newspi = htonl(spi); 22381da177e4SLinus Torvalds break; 22391da177e4SLinus Torvalds } 22401da177e4SLinus Torvalds xfrm_state_put(x0); 22411da177e4SLinus Torvalds } 22421da177e4SLinus Torvalds } 2243a779d913Szhuoliang zhang if (newspi) { 2244283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 2245a779d913Szhuoliang zhang x->id.spi = newspi; 224612604d8aSAlexey Dobriyan h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, x->props.family); 2247*3c611d40SLeon Romanovsky XFRM_STATE_INSERT(byspi, &x->byspi, net->xfrm.state_byspi + h, 2248*3c611d40SLeon Romanovsky x->xso.type); 2249283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 2250658b219eSHerbert Xu 2251658b219eSHerbert Xu err = 0; 2252c2dad11eSSabrina Dubroca } else { 2253c2dad11eSSabrina Dubroca NL_SET_ERR_MSG(extack, "No SPI available in the requested range"); 22541da177e4SLinus Torvalds } 2255658b219eSHerbert Xu 2256658b219eSHerbert Xu unlock: 2257658b219eSHerbert Xu spin_unlock_bh(&x->lock); 2258658b219eSHerbert Xu 2259658b219eSHerbert Xu return err; 22601da177e4SLinus Torvalds } 22611da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_alloc_spi); 22621da177e4SLinus Torvalds 2263d3623099SNicolas Dichtel static bool __xfrm_state_filter_match(struct xfrm_state *x, 2264870a2df4SNicolas Dichtel struct xfrm_address_filter *filter) 2265d3623099SNicolas Dichtel { 2266d3623099SNicolas Dichtel if (filter) { 2267d3623099SNicolas Dichtel if ((filter->family == AF_INET || 2268d3623099SNicolas Dichtel filter->family == AF_INET6) && 2269d3623099SNicolas Dichtel x->props.family != filter->family) 2270d3623099SNicolas Dichtel return false; 2271d3623099SNicolas Dichtel 2272d3623099SNicolas Dichtel return addr_match(&x->props.saddr, &filter->saddr, 2273d3623099SNicolas Dichtel filter->splen) && 2274d3623099SNicolas Dichtel addr_match(&x->id.daddr, &filter->daddr, 2275d3623099SNicolas Dichtel filter->dplen); 2276d3623099SNicolas Dichtel } 2277d3623099SNicolas Dichtel return true; 2278d3623099SNicolas Dichtel } 2279d3623099SNicolas Dichtel 2280284fa7daSAlexey Dobriyan int xfrm_state_walk(struct net *net, struct xfrm_state_walk *walk, 22814c563f76STimo Teras int (*func)(struct xfrm_state *, int, void*), 22821da177e4SLinus Torvalds void *data) 22831da177e4SLinus Torvalds { 228412a169e7SHerbert Xu struct xfrm_state *state; 228512a169e7SHerbert Xu struct xfrm_state_walk *x; 22861da177e4SLinus Torvalds int err = 0; 22871da177e4SLinus Torvalds 228812a169e7SHerbert Xu if (walk->seq != 0 && list_empty(&walk->all)) 22894c563f76STimo Teras return 0; 22904c563f76STimo Teras 2291283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 229212a169e7SHerbert Xu if (list_empty(&walk->all)) 2293284fa7daSAlexey Dobriyan x = list_first_entry(&net->xfrm.state_all, struct xfrm_state_walk, all); 229412a169e7SHerbert Xu else 229580077702SLi RongQing x = list_first_entry(&walk->all, struct xfrm_state_walk, all); 2296284fa7daSAlexey Dobriyan list_for_each_entry_from(x, &net->xfrm.state_all, all) { 229712a169e7SHerbert Xu if (x->state == XFRM_STATE_DEAD) 22984c563f76STimo Teras continue; 229912a169e7SHerbert Xu state = container_of(x, struct xfrm_state, km); 230012a169e7SHerbert Xu if (!xfrm_id_proto_match(state->id.proto, walk->proto)) 230194b9bb54SJamal Hadi Salim continue; 2302d3623099SNicolas Dichtel if (!__xfrm_state_filter_match(state, walk->filter)) 2303d3623099SNicolas Dichtel continue; 230412a169e7SHerbert Xu err = func(state, walk->seq, data); 23054c563f76STimo Teras if (err) { 230612a169e7SHerbert Xu list_move_tail(&walk->all, &x->all); 230794b9bb54SJamal Hadi Salim goto out; 230894b9bb54SJamal Hadi Salim } 230912a169e7SHerbert Xu walk->seq++; 23104c563f76STimo Teras } 231112a169e7SHerbert Xu if (walk->seq == 0) { 23121da177e4SLinus Torvalds err = -ENOENT; 23131da177e4SLinus Torvalds goto out; 23141da177e4SLinus Torvalds } 231512a169e7SHerbert Xu list_del_init(&walk->all); 23161da177e4SLinus Torvalds out: 2317283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 23181da177e4SLinus Torvalds return err; 23191da177e4SLinus Torvalds } 23201da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_walk); 23211da177e4SLinus Torvalds 2322d3623099SNicolas Dichtel void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto, 2323870a2df4SNicolas Dichtel struct xfrm_address_filter *filter) 23245c182458SHerbert Xu { 232512a169e7SHerbert Xu INIT_LIST_HEAD(&walk->all); 23265c182458SHerbert Xu walk->proto = proto; 232712a169e7SHerbert Xu walk->state = XFRM_STATE_DEAD; 232812a169e7SHerbert Xu walk->seq = 0; 2329d3623099SNicolas Dichtel walk->filter = filter; 23305c182458SHerbert Xu } 23315c182458SHerbert Xu EXPORT_SYMBOL(xfrm_state_walk_init); 23325c182458SHerbert Xu 2333283bc9f3SFan Du void xfrm_state_walk_done(struct xfrm_state_walk *walk, struct net *net) 2334abb81c4fSHerbert Xu { 2335d3623099SNicolas Dichtel kfree(walk->filter); 2336d3623099SNicolas Dichtel 233712a169e7SHerbert Xu if (list_empty(&walk->all)) 23385c182458SHerbert Xu return; 23395c182458SHerbert Xu 2340283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 234112a169e7SHerbert Xu list_del(&walk->all); 2342283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 2343abb81c4fSHerbert Xu } 2344abb81c4fSHerbert Xu EXPORT_SYMBOL(xfrm_state_walk_done); 2345abb81c4fSHerbert Xu 2346e99e88a9SKees Cook static void xfrm_replay_timer_handler(struct timer_list *t) 2347f8cd5488SJamal Hadi Salim { 2348e99e88a9SKees Cook struct xfrm_state *x = from_timer(x, t, rtimer); 2349f8cd5488SJamal Hadi Salim 2350f8cd5488SJamal Hadi Salim spin_lock(&x->lock); 2351f8cd5488SJamal Hadi Salim 23522717096aSJamal Hadi Salim if (x->km.state == XFRM_STATE_VALID) { 2353a6483b79SAlexey Dobriyan if (xfrm_aevent_is_on(xs_net(x))) 2354cfc61c59SFlorian Westphal xfrm_replay_notify(x, XFRM_REPLAY_TIMEOUT); 23552717096aSJamal Hadi Salim else 23562717096aSJamal Hadi Salim x->xflags |= XFRM_TIME_DEFER; 23572717096aSJamal Hadi Salim } 2358f8cd5488SJamal Hadi Salim 2359f8cd5488SJamal Hadi Salim spin_unlock(&x->lock); 2360f8cd5488SJamal Hadi Salim } 2361f8cd5488SJamal Hadi Salim 2362df01812eSDenis Cheng static LIST_HEAD(xfrm_km_list); 23631da177e4SLinus Torvalds 2364214e005bSDavid S. Miller void km_policy_notify(struct xfrm_policy *xp, int dir, const struct km_event *c) 23651da177e4SLinus Torvalds { 23661da177e4SLinus Torvalds struct xfrm_mgr *km; 23671da177e4SLinus Torvalds 236885168c00SCong Wang rcu_read_lock(); 236985168c00SCong Wang list_for_each_entry_rcu(km, &xfrm_km_list, list) 237026b15dadSJamal Hadi Salim if (km->notify_policy) 237126b15dadSJamal Hadi Salim km->notify_policy(xp, dir, c); 237285168c00SCong Wang rcu_read_unlock(); 237326b15dadSJamal Hadi Salim } 237426b15dadSJamal Hadi Salim 2375214e005bSDavid S. Miller void km_state_notify(struct xfrm_state *x, const struct km_event *c) 237626b15dadSJamal Hadi Salim { 237726b15dadSJamal Hadi Salim struct xfrm_mgr *km; 237885168c00SCong Wang rcu_read_lock(); 237985168c00SCong Wang list_for_each_entry_rcu(km, &xfrm_km_list, list) 238026b15dadSJamal Hadi Salim if (km->notify) 238126b15dadSJamal Hadi Salim km->notify(x, c); 238285168c00SCong Wang rcu_read_unlock(); 238326b15dadSJamal Hadi Salim } 238426b15dadSJamal Hadi Salim 238526b15dadSJamal Hadi Salim EXPORT_SYMBOL(km_policy_notify); 238626b15dadSJamal Hadi Salim EXPORT_SYMBOL(km_state_notify); 238726b15dadSJamal Hadi Salim 238815e47304SEric W. Biederman void km_state_expired(struct xfrm_state *x, int hard, u32 portid) 238926b15dadSJamal Hadi Salim { 239026b15dadSJamal Hadi Salim struct km_event c; 239126b15dadSJamal Hadi Salim 2392bf08867fSHerbert Xu c.data.hard = hard; 239315e47304SEric W. Biederman c.portid = portid; 2394f60f6b8fSHerbert Xu c.event = XFRM_MSG_EXPIRE; 239526b15dadSJamal Hadi Salim km_state_notify(x, &c); 23961da177e4SLinus Torvalds } 23971da177e4SLinus Torvalds 239853bc6b4dSJamal Hadi Salim EXPORT_SYMBOL(km_state_expired); 239926b15dadSJamal Hadi Salim /* 240026b15dadSJamal Hadi Salim * We send to all registered managers regardless of failure 240126b15dadSJamal Hadi Salim * We are happy with one success 240226b15dadSJamal Hadi Salim */ 2403980ebd25SJamal Hadi Salim int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol) 24041da177e4SLinus Torvalds { 240526b15dadSJamal Hadi Salim int err = -EINVAL, acqret; 24061da177e4SLinus Torvalds struct xfrm_mgr *km; 24071da177e4SLinus Torvalds 240885168c00SCong Wang rcu_read_lock(); 240985168c00SCong Wang list_for_each_entry_rcu(km, &xfrm_km_list, list) { 241065e0736bSFan Du acqret = km->acquire(x, t, pol); 241126b15dadSJamal Hadi Salim if (!acqret) 241226b15dadSJamal Hadi Salim err = acqret; 24131da177e4SLinus Torvalds } 241485168c00SCong Wang rcu_read_unlock(); 24151da177e4SLinus Torvalds return err; 24161da177e4SLinus Torvalds } 2417980ebd25SJamal Hadi Salim EXPORT_SYMBOL(km_query); 24181da177e4SLinus Torvalds 24194e484b3eSAntony Antony static int __km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport) 24201da177e4SLinus Torvalds { 24211da177e4SLinus Torvalds int err = -EINVAL; 24221da177e4SLinus Torvalds struct xfrm_mgr *km; 24231da177e4SLinus Torvalds 242485168c00SCong Wang rcu_read_lock(); 242585168c00SCong Wang list_for_each_entry_rcu(km, &xfrm_km_list, list) { 24261da177e4SLinus Torvalds if (km->new_mapping) 24271da177e4SLinus Torvalds err = km->new_mapping(x, ipaddr, sport); 24281da177e4SLinus Torvalds if (!err) 24291da177e4SLinus Torvalds break; 24301da177e4SLinus Torvalds } 243185168c00SCong Wang rcu_read_unlock(); 24321da177e4SLinus Torvalds return err; 24331da177e4SLinus Torvalds } 24344e484b3eSAntony Antony 24354e484b3eSAntony Antony int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport) 24364e484b3eSAntony Antony { 24374e484b3eSAntony Antony int ret = 0; 24384e484b3eSAntony Antony 24394e484b3eSAntony Antony if (x->mapping_maxage) { 24404e484b3eSAntony Antony if ((jiffies / HZ - x->new_mapping) > x->mapping_maxage || 24414e484b3eSAntony Antony x->new_mapping_sport != sport) { 24424e484b3eSAntony Antony x->new_mapping_sport = sport; 24434e484b3eSAntony Antony x->new_mapping = jiffies / HZ; 24444e484b3eSAntony Antony ret = __km_new_mapping(x, ipaddr, sport); 24454e484b3eSAntony Antony } 24464e484b3eSAntony Antony } else { 24474e484b3eSAntony Antony ret = __km_new_mapping(x, ipaddr, sport); 24484e484b3eSAntony Antony } 24494e484b3eSAntony Antony 24504e484b3eSAntony Antony return ret; 24514e484b3eSAntony Antony } 24521da177e4SLinus Torvalds EXPORT_SYMBOL(km_new_mapping); 24531da177e4SLinus Torvalds 245415e47304SEric W. Biederman void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 portid) 24551da177e4SLinus Torvalds { 245626b15dadSJamal Hadi Salim struct km_event c; 24571da177e4SLinus Torvalds 2458bf08867fSHerbert Xu c.data.hard = hard; 245915e47304SEric W. Biederman c.portid = portid; 2460f60f6b8fSHerbert Xu c.event = XFRM_MSG_POLEXPIRE; 246126b15dadSJamal Hadi Salim km_policy_notify(pol, dir, &c); 24621da177e4SLinus Torvalds } 2463a70fcb0bSDavid S. Miller EXPORT_SYMBOL(km_policy_expired); 24641da177e4SLinus Torvalds 24652d60abc2SEric Dumazet #ifdef CONFIG_XFRM_MIGRATE 2466183cad12SDavid S. Miller int km_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, 2467183cad12SDavid S. Miller const struct xfrm_migrate *m, int num_migrate, 24688bafd730SAntony Antony const struct xfrm_kmaddress *k, 24698bafd730SAntony Antony const struct xfrm_encap_tmpl *encap) 247080c9abaaSShinta Sugimoto { 247180c9abaaSShinta Sugimoto int err = -EINVAL; 247280c9abaaSShinta Sugimoto int ret; 247380c9abaaSShinta Sugimoto struct xfrm_mgr *km; 247480c9abaaSShinta Sugimoto 247585168c00SCong Wang rcu_read_lock(); 247685168c00SCong Wang list_for_each_entry_rcu(km, &xfrm_km_list, list) { 247780c9abaaSShinta Sugimoto if (km->migrate) { 24788bafd730SAntony Antony ret = km->migrate(sel, dir, type, m, num_migrate, k, 24798bafd730SAntony Antony encap); 248080c9abaaSShinta Sugimoto if (!ret) 248180c9abaaSShinta Sugimoto err = ret; 248280c9abaaSShinta Sugimoto } 248380c9abaaSShinta Sugimoto } 248485168c00SCong Wang rcu_read_unlock(); 248580c9abaaSShinta Sugimoto return err; 248680c9abaaSShinta Sugimoto } 248780c9abaaSShinta Sugimoto EXPORT_SYMBOL(km_migrate); 24882d60abc2SEric Dumazet #endif 248980c9abaaSShinta Sugimoto 2490db983c11SAlexey Dobriyan int km_report(struct net *net, u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr) 249197a64b45SMasahide NAKAMURA { 249297a64b45SMasahide NAKAMURA int err = -EINVAL; 249397a64b45SMasahide NAKAMURA int ret; 249497a64b45SMasahide NAKAMURA struct xfrm_mgr *km; 249597a64b45SMasahide NAKAMURA 249685168c00SCong Wang rcu_read_lock(); 249785168c00SCong Wang list_for_each_entry_rcu(km, &xfrm_km_list, list) { 249897a64b45SMasahide NAKAMURA if (km->report) { 2499db983c11SAlexey Dobriyan ret = km->report(net, proto, sel, addr); 250097a64b45SMasahide NAKAMURA if (!ret) 250197a64b45SMasahide NAKAMURA err = ret; 250297a64b45SMasahide NAKAMURA } 250397a64b45SMasahide NAKAMURA } 250485168c00SCong Wang rcu_read_unlock(); 250597a64b45SMasahide NAKAMURA return err; 250697a64b45SMasahide NAKAMURA } 250797a64b45SMasahide NAKAMURA EXPORT_SYMBOL(km_report); 250897a64b45SMasahide NAKAMURA 2509bb9cd077SFlorian Westphal static bool km_is_alive(const struct km_event *c) 25100f24558eSHoria Geanta { 25110f24558eSHoria Geanta struct xfrm_mgr *km; 25120f24558eSHoria Geanta bool is_alive = false; 25130f24558eSHoria Geanta 25140f24558eSHoria Geanta rcu_read_lock(); 25150f24558eSHoria Geanta list_for_each_entry_rcu(km, &xfrm_km_list, list) { 25160f24558eSHoria Geanta if (km->is_alive && km->is_alive(c)) { 25170f24558eSHoria Geanta is_alive = true; 25180f24558eSHoria Geanta break; 25190f24558eSHoria Geanta } 25200f24558eSHoria Geanta } 25210f24558eSHoria Geanta rcu_read_unlock(); 25220f24558eSHoria Geanta 25230f24558eSHoria Geanta return is_alive; 25240f24558eSHoria Geanta } 25250f24558eSHoria Geanta 2526c9e7c76dSDmitry Safonov #if IS_ENABLED(CONFIG_XFRM_USER_COMPAT) 2527c9e7c76dSDmitry Safonov static DEFINE_SPINLOCK(xfrm_translator_lock); 2528c9e7c76dSDmitry Safonov static struct xfrm_translator __rcu *xfrm_translator; 2529c9e7c76dSDmitry Safonov 2530c9e7c76dSDmitry Safonov struct xfrm_translator *xfrm_get_translator(void) 2531c9e7c76dSDmitry Safonov { 2532c9e7c76dSDmitry Safonov struct xfrm_translator *xtr; 2533c9e7c76dSDmitry Safonov 2534c9e7c76dSDmitry Safonov rcu_read_lock(); 2535c9e7c76dSDmitry Safonov xtr = rcu_dereference(xfrm_translator); 2536c9e7c76dSDmitry Safonov if (unlikely(!xtr)) 2537c9e7c76dSDmitry Safonov goto out; 2538c9e7c76dSDmitry Safonov if (!try_module_get(xtr->owner)) 2539c9e7c76dSDmitry Safonov xtr = NULL; 2540c9e7c76dSDmitry Safonov out: 2541c9e7c76dSDmitry Safonov rcu_read_unlock(); 2542c9e7c76dSDmitry Safonov return xtr; 2543c9e7c76dSDmitry Safonov } 2544c9e7c76dSDmitry Safonov EXPORT_SYMBOL_GPL(xfrm_get_translator); 2545c9e7c76dSDmitry Safonov 2546c9e7c76dSDmitry Safonov void xfrm_put_translator(struct xfrm_translator *xtr) 2547c9e7c76dSDmitry Safonov { 2548c9e7c76dSDmitry Safonov module_put(xtr->owner); 2549c9e7c76dSDmitry Safonov } 2550c9e7c76dSDmitry Safonov EXPORT_SYMBOL_GPL(xfrm_put_translator); 2551c9e7c76dSDmitry Safonov 2552c9e7c76dSDmitry Safonov int xfrm_register_translator(struct xfrm_translator *xtr) 2553c9e7c76dSDmitry Safonov { 2554c9e7c76dSDmitry Safonov int err = 0; 2555c9e7c76dSDmitry Safonov 2556c9e7c76dSDmitry Safonov spin_lock_bh(&xfrm_translator_lock); 2557c9e7c76dSDmitry Safonov if (unlikely(xfrm_translator != NULL)) 2558c9e7c76dSDmitry Safonov err = -EEXIST; 2559c9e7c76dSDmitry Safonov else 2560c9e7c76dSDmitry Safonov rcu_assign_pointer(xfrm_translator, xtr); 2561c9e7c76dSDmitry Safonov spin_unlock_bh(&xfrm_translator_lock); 2562c9e7c76dSDmitry Safonov 2563c9e7c76dSDmitry Safonov return err; 2564c9e7c76dSDmitry Safonov } 2565c9e7c76dSDmitry Safonov EXPORT_SYMBOL_GPL(xfrm_register_translator); 2566c9e7c76dSDmitry Safonov 2567c9e7c76dSDmitry Safonov int xfrm_unregister_translator(struct xfrm_translator *xtr) 2568c9e7c76dSDmitry Safonov { 2569c9e7c76dSDmitry Safonov int err = 0; 2570c9e7c76dSDmitry Safonov 2571c9e7c76dSDmitry Safonov spin_lock_bh(&xfrm_translator_lock); 2572c9e7c76dSDmitry Safonov if (likely(xfrm_translator != NULL)) { 2573c9e7c76dSDmitry Safonov if (rcu_access_pointer(xfrm_translator) != xtr) 2574c9e7c76dSDmitry Safonov err = -EINVAL; 2575c9e7c76dSDmitry Safonov else 2576c9e7c76dSDmitry Safonov RCU_INIT_POINTER(xfrm_translator, NULL); 2577c9e7c76dSDmitry Safonov } 2578c9e7c76dSDmitry Safonov spin_unlock_bh(&xfrm_translator_lock); 2579c9e7c76dSDmitry Safonov synchronize_rcu(); 2580c9e7c76dSDmitry Safonov 2581c9e7c76dSDmitry Safonov return err; 2582c9e7c76dSDmitry Safonov } 2583c9e7c76dSDmitry Safonov EXPORT_SYMBOL_GPL(xfrm_unregister_translator); 2584c9e7c76dSDmitry Safonov #endif 2585c9e7c76dSDmitry Safonov 2586c6d1b26aSChristoph Hellwig int xfrm_user_policy(struct sock *sk, int optname, sockptr_t optval, int optlen) 25871da177e4SLinus Torvalds { 25881da177e4SLinus Torvalds int err; 25891da177e4SLinus Torvalds u8 *data; 25901da177e4SLinus Torvalds struct xfrm_mgr *km; 25911da177e4SLinus Torvalds struct xfrm_policy *pol = NULL; 25921da177e4SLinus Torvalds 2593c6d1b26aSChristoph Hellwig if (sockptr_is_null(optval) && !optlen) { 2594be8f8284SLorenzo Colitti xfrm_sk_policy_insert(sk, XFRM_POLICY_IN, NULL); 2595be8f8284SLorenzo Colitti xfrm_sk_policy_insert(sk, XFRM_POLICY_OUT, NULL); 2596be8f8284SLorenzo Colitti __sk_dst_reset(sk); 2597be8f8284SLorenzo Colitti return 0; 2598be8f8284SLorenzo Colitti } 2599be8f8284SLorenzo Colitti 26001da177e4SLinus Torvalds if (optlen <= 0 || optlen > PAGE_SIZE) 26011da177e4SLinus Torvalds return -EMSGSIZE; 26021da177e4SLinus Torvalds 2603c6d1b26aSChristoph Hellwig data = memdup_sockptr(optval, optlen); 2604a133d930SGeliang Tang if (IS_ERR(data)) 2605a133d930SGeliang Tang return PTR_ERR(data); 26061da177e4SLinus Torvalds 260796392ee5SDmitry Safonov if (in_compat_syscall()) { 260896392ee5SDmitry Safonov struct xfrm_translator *xtr = xfrm_get_translator(); 260996392ee5SDmitry Safonov 261048f486e1SYu Kuai if (!xtr) { 261148f486e1SYu Kuai kfree(data); 261296392ee5SDmitry Safonov return -EOPNOTSUPP; 261348f486e1SYu Kuai } 261496392ee5SDmitry Safonov 261596392ee5SDmitry Safonov err = xtr->xlate_user_policy_sockptr(&data, optlen); 261696392ee5SDmitry Safonov xfrm_put_translator(xtr); 261796392ee5SDmitry Safonov if (err) { 261896392ee5SDmitry Safonov kfree(data); 261996392ee5SDmitry Safonov return err; 262096392ee5SDmitry Safonov } 262196392ee5SDmitry Safonov } 262296392ee5SDmitry Safonov 26231da177e4SLinus Torvalds err = -EINVAL; 262485168c00SCong Wang rcu_read_lock(); 262585168c00SCong Wang list_for_each_entry_rcu(km, &xfrm_km_list, list) { 2626cb969f07SVenkat Yekkirala pol = km->compile_policy(sk, optname, data, 26271da177e4SLinus Torvalds optlen, &err); 26281da177e4SLinus Torvalds if (err >= 0) 26291da177e4SLinus Torvalds break; 26301da177e4SLinus Torvalds } 263185168c00SCong Wang rcu_read_unlock(); 26321da177e4SLinus Torvalds 26331da177e4SLinus Torvalds if (err >= 0) { 26341da177e4SLinus Torvalds xfrm_sk_policy_insert(sk, err, pol); 26351da177e4SLinus Torvalds xfrm_pol_put(pol); 26362b06cdf3SJonathan Basseri __sk_dst_reset(sk); 26371da177e4SLinus Torvalds err = 0; 26381da177e4SLinus Torvalds } 26391da177e4SLinus Torvalds 26401da177e4SLinus Torvalds kfree(data); 26411da177e4SLinus Torvalds return err; 26421da177e4SLinus Torvalds } 26431da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_user_policy); 26441da177e4SLinus Torvalds 264585168c00SCong Wang static DEFINE_SPINLOCK(xfrm_km_lock); 264685168c00SCong Wang 2647f41b284aSZhengchao Shao void xfrm_register_km(struct xfrm_mgr *km) 26481da177e4SLinus Torvalds { 264985168c00SCong Wang spin_lock_bh(&xfrm_km_lock); 265085168c00SCong Wang list_add_tail_rcu(&km->list, &xfrm_km_list); 265185168c00SCong Wang spin_unlock_bh(&xfrm_km_lock); 26521da177e4SLinus Torvalds } 26531da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_register_km); 26541da177e4SLinus Torvalds 2655f41b284aSZhengchao Shao void xfrm_unregister_km(struct xfrm_mgr *km) 26561da177e4SLinus Torvalds { 265785168c00SCong Wang spin_lock_bh(&xfrm_km_lock); 265885168c00SCong Wang list_del_rcu(&km->list); 265985168c00SCong Wang spin_unlock_bh(&xfrm_km_lock); 266085168c00SCong Wang synchronize_rcu(); 26611da177e4SLinus Torvalds } 26621da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_unregister_km); 26631da177e4SLinus Torvalds 26641da177e4SLinus Torvalds int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo) 26651da177e4SLinus Torvalds { 26661da177e4SLinus Torvalds int err = 0; 2667423826a7SFlorian Westphal 2668423826a7SFlorian Westphal if (WARN_ON(afinfo->family >= NPROTO)) 26691da177e4SLinus Torvalds return -EAFNOSUPPORT; 2670423826a7SFlorian Westphal 267144abdc30SCong Wang spin_lock_bh(&xfrm_state_afinfo_lock); 26721da177e4SLinus Torvalds if (unlikely(xfrm_state_afinfo[afinfo->family] != NULL)) 2673f31e8d4fSLi RongQing err = -EEXIST; 2674edcd5821SDavid S. Miller else 267544abdc30SCong Wang rcu_assign_pointer(xfrm_state_afinfo[afinfo->family], afinfo); 267644abdc30SCong Wang spin_unlock_bh(&xfrm_state_afinfo_lock); 26771da177e4SLinus Torvalds return err; 26781da177e4SLinus Torvalds } 26791da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_register_afinfo); 26801da177e4SLinus Torvalds 26811da177e4SLinus Torvalds int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo) 26821da177e4SLinus Torvalds { 2683423826a7SFlorian Westphal int err = 0, family = afinfo->family; 2684423826a7SFlorian Westphal 2685423826a7SFlorian Westphal if (WARN_ON(family >= NPROTO)) 26861da177e4SLinus Torvalds return -EAFNOSUPPORT; 2687423826a7SFlorian Westphal 268844abdc30SCong Wang spin_lock_bh(&xfrm_state_afinfo_lock); 26891da177e4SLinus Torvalds if (likely(xfrm_state_afinfo[afinfo->family] != NULL)) { 2690423826a7SFlorian Westphal if (rcu_access_pointer(xfrm_state_afinfo[family]) != afinfo) 26911da177e4SLinus Torvalds err = -EINVAL; 2692edcd5821SDavid S. Miller else 269344abdc30SCong Wang RCU_INIT_POINTER(xfrm_state_afinfo[afinfo->family], NULL); 26941da177e4SLinus Torvalds } 269544abdc30SCong Wang spin_unlock_bh(&xfrm_state_afinfo_lock); 269644abdc30SCong Wang synchronize_rcu(); 26971da177e4SLinus Torvalds return err; 26981da177e4SLinus Torvalds } 26991da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_unregister_afinfo); 27001da177e4SLinus Torvalds 2701711059b9SFlorian Westphal struct xfrm_state_afinfo *xfrm_state_afinfo_get_rcu(unsigned int family) 2702711059b9SFlorian Westphal { 2703711059b9SFlorian Westphal if (unlikely(family >= NPROTO)) 2704711059b9SFlorian Westphal return NULL; 2705711059b9SFlorian Westphal 2706711059b9SFlorian Westphal return rcu_dereference(xfrm_state_afinfo[family]); 2707711059b9SFlorian Westphal } 2708733a5facSFlorian Westphal EXPORT_SYMBOL_GPL(xfrm_state_afinfo_get_rcu); 2709711059b9SFlorian Westphal 2710628e341fSHannes Frederic Sowa struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family) 27111da177e4SLinus Torvalds { 27121da177e4SLinus Torvalds struct xfrm_state_afinfo *afinfo; 27131da177e4SLinus Torvalds if (unlikely(family >= NPROTO)) 27141da177e4SLinus Torvalds return NULL; 271544abdc30SCong Wang rcu_read_lock(); 271644abdc30SCong Wang afinfo = rcu_dereference(xfrm_state_afinfo[family]); 2717546be240SHerbert Xu if (unlikely(!afinfo)) 271844abdc30SCong Wang rcu_read_unlock(); 27191da177e4SLinus Torvalds return afinfo; 27201da177e4SLinus Torvalds } 27211da177e4SLinus Torvalds 2722b48c05abSSteffen Klassert void xfrm_flush_gc(void) 2723b48c05abSSteffen Klassert { 2724b48c05abSSteffen Klassert flush_work(&xfrm_state_gc_work); 2725b48c05abSSteffen Klassert } 2726b48c05abSSteffen Klassert EXPORT_SYMBOL(xfrm_flush_gc); 2727b48c05abSSteffen Klassert 27281da177e4SLinus Torvalds /* Temporarily located here until net/xfrm/xfrm_tunnel.c is created */ 27291da177e4SLinus Torvalds void xfrm_state_delete_tunnel(struct xfrm_state *x) 27301da177e4SLinus Torvalds { 27311da177e4SLinus Torvalds if (x->tunnel) { 27321da177e4SLinus Torvalds struct xfrm_state *t = x->tunnel; 27331da177e4SLinus Torvalds 27341da177e4SLinus Torvalds if (atomic_read(&t->tunnel_users) == 2) 27351da177e4SLinus Torvalds xfrm_state_delete(t); 27361da177e4SLinus Torvalds atomic_dec(&t->tunnel_users); 2737f75a2804SCong Wang xfrm_state_put_sync(t); 27381da177e4SLinus Torvalds x->tunnel = NULL; 27391da177e4SLinus Torvalds } 27401da177e4SLinus Torvalds } 27411da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_delete_tunnel); 27421da177e4SLinus Torvalds 2743a6d95c5aSJiri Bohac u32 xfrm_state_mtu(struct xfrm_state *x, int mtu) 27441da177e4SLinus Torvalds { 2745b3b73b8eSFlorian Westphal const struct xfrm_type *type = READ_ONCE(x->type); 2746c7b37c76SFlorian Westphal struct crypto_aead *aead; 2747c7b37c76SFlorian Westphal u32 blksize, net_adj = 0; 27481da177e4SLinus Torvalds 2749c7b37c76SFlorian Westphal if (x->km.state != XFRM_STATE_VALID || 2750c7b37c76SFlorian Westphal !type || type->proto != IPPROTO_ESP) 2751b3b73b8eSFlorian Westphal return mtu - x->props.header_len; 2752c7b37c76SFlorian Westphal 2753c7b37c76SFlorian Westphal aead = x->data; 2754c7b37c76SFlorian Westphal blksize = ALIGN(crypto_aead_blocksize(aead), 4); 2755c7b37c76SFlorian Westphal 2756c7b37c76SFlorian Westphal switch (x->props.mode) { 2757c7b37c76SFlorian Westphal case XFRM_MODE_TRANSPORT: 2758c7b37c76SFlorian Westphal case XFRM_MODE_BEET: 2759c7b37c76SFlorian Westphal if (x->props.family == AF_INET) 2760c7b37c76SFlorian Westphal net_adj = sizeof(struct iphdr); 2761c7b37c76SFlorian Westphal else if (x->props.family == AF_INET6) 2762c7b37c76SFlorian Westphal net_adj = sizeof(struct ipv6hdr); 2763c7b37c76SFlorian Westphal break; 2764c7b37c76SFlorian Westphal case XFRM_MODE_TUNNEL: 2765c7b37c76SFlorian Westphal break; 2766c7b37c76SFlorian Westphal default: 2767c7b37c76SFlorian Westphal WARN_ON_ONCE(1); 2768c7b37c76SFlorian Westphal break; 27691da177e4SLinus Torvalds } 27701da177e4SLinus Torvalds 2771c7b37c76SFlorian Westphal return ((mtu - x->props.header_len - crypto_aead_authsize(aead) - 2772c7b37c76SFlorian Westphal net_adj) & ~(blksize - 1)) + net_adj - 2; 2773c7b37c76SFlorian Westphal } 2774a6d95c5aSJiri Bohac EXPORT_SYMBOL_GPL(xfrm_state_mtu); 2775c7b37c76SFlorian Westphal 2776741f9a10SSabrina Dubroca int __xfrm_init_state(struct xfrm_state *x, bool init_replay, bool offload, 2777741f9a10SSabrina Dubroca struct netlink_ext_ack *extack) 277872cb6962SHerbert Xu { 2779c9500d7bSFlorian Westphal const struct xfrm_mode *inner_mode; 2780c9500d7bSFlorian Westphal const struct xfrm_mode *outer_mode; 2781d094cd83SHerbert Xu int family = x->props.family; 278272cb6962SHerbert Xu int err; 278372cb6962SHerbert Xu 2784e4681747SFlorian Westphal if (family == AF_INET && 27850968d2a4SKuniyuki Iwashima READ_ONCE(xs_net(x)->ipv4.sysctl_ip_no_pmtu_disc)) 2786e4681747SFlorian Westphal x->props.flags |= XFRM_STATE_NOPMTUDISC; 2787d094cd83SHerbert Xu 2788d094cd83SHerbert Xu err = -EPROTONOSUPPORT; 2789df9dcb45SKazunori MIYAZAWA 2790df9dcb45SKazunori MIYAZAWA if (x->sel.family != AF_UNSPEC) { 2791df9dcb45SKazunori MIYAZAWA inner_mode = xfrm_get_mode(x->props.mode, x->sel.family); 2792741f9a10SSabrina Dubroca if (inner_mode == NULL) { 2793741f9a10SSabrina Dubroca NL_SET_ERR_MSG(extack, "Requested mode not found"); 279413996378SHerbert Xu goto error; 2795741f9a10SSabrina Dubroca } 279613996378SHerbert Xu 2797df9dcb45SKazunori MIYAZAWA if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL) && 2798741f9a10SSabrina Dubroca family != x->sel.family) { 2799741f9a10SSabrina Dubroca NL_SET_ERR_MSG(extack, "Only tunnel modes can accommodate a change of family"); 280013996378SHerbert Xu goto error; 2801741f9a10SSabrina Dubroca } 2802df9dcb45SKazunori MIYAZAWA 2803c9500d7bSFlorian Westphal x->inner_mode = *inner_mode; 2804df9dcb45SKazunori MIYAZAWA } else { 28054c145dceSFlorian Westphal const struct xfrm_mode *inner_mode_iaf; 2806d81d2285SMartin Willi int iafamily = AF_INET; 2807df9dcb45SKazunori MIYAZAWA 2808d81d2285SMartin Willi inner_mode = xfrm_get_mode(x->props.mode, x->props.family); 2809741f9a10SSabrina Dubroca if (inner_mode == NULL) { 2810741f9a10SSabrina Dubroca NL_SET_ERR_MSG(extack, "Requested mode not found"); 2811df9dcb45SKazunori MIYAZAWA goto error; 2812741f9a10SSabrina Dubroca } 2813df9dcb45SKazunori MIYAZAWA 2814741f9a10SSabrina Dubroca if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL)) { 2815741f9a10SSabrina Dubroca NL_SET_ERR_MSG(extack, "Only tunnel modes can accommodate an AF_UNSPEC selector"); 2816df9dcb45SKazunori MIYAZAWA goto error; 2817741f9a10SSabrina Dubroca } 28184c145dceSFlorian Westphal 2819c9500d7bSFlorian Westphal x->inner_mode = *inner_mode; 2820d81d2285SMartin Willi 2821d81d2285SMartin Willi if (x->props.family == AF_INET) 2822d81d2285SMartin Willi iafamily = AF_INET6; 2823d81d2285SMartin Willi 2824d81d2285SMartin Willi inner_mode_iaf = xfrm_get_mode(x->props.mode, iafamily); 2825d81d2285SMartin Willi if (inner_mode_iaf) { 2826d81d2285SMartin Willi if (inner_mode_iaf->flags & XFRM_MODE_FLAG_TUNNEL) 2827c9500d7bSFlorian Westphal x->inner_mode_iaf = *inner_mode_iaf; 2828df9dcb45SKazunori MIYAZAWA } 2829df9dcb45SKazunori MIYAZAWA } 283013996378SHerbert Xu 2831d094cd83SHerbert Xu x->type = xfrm_get_type(x->id.proto, family); 2832741f9a10SSabrina Dubroca if (x->type == NULL) { 2833741f9a10SSabrina Dubroca NL_SET_ERR_MSG(extack, "Requested type not found"); 283472cb6962SHerbert Xu goto error; 2835741f9a10SSabrina Dubroca } 283672cb6962SHerbert Xu 2837ffdb5211SIlan Tayari x->type_offload = xfrm_get_type_offload(x->id.proto, family, offload); 28389d389d7fSSteffen Klassert 2839e1e10b44SSabrina Dubroca err = x->type->init_state(x, extack); 284072cb6962SHerbert Xu if (err) 284172cb6962SHerbert Xu goto error; 284272cb6962SHerbert Xu 2843c9500d7bSFlorian Westphal outer_mode = xfrm_get_mode(x->props.mode, family); 2844c9500d7bSFlorian Westphal if (!outer_mode) { 2845741f9a10SSabrina Dubroca NL_SET_ERR_MSG(extack, "Requested mode not found"); 2846599901c3SJulia Lawall err = -EPROTONOSUPPORT; 2847b59f45d0SHerbert Xu goto error; 2848599901c3SJulia Lawall } 2849b59f45d0SHerbert Xu 2850c9500d7bSFlorian Westphal x->outer_mode = *outer_mode; 2851a454f0ccSWei Yongjun if (init_replay) { 28521cf9a3aeSSabrina Dubroca err = xfrm_init_replay(x, extack); 2853a454f0ccSWei Yongjun if (err) 2854a454f0ccSWei Yongjun goto error; 2855a454f0ccSWei Yongjun } 2856a454f0ccSWei Yongjun 285772cb6962SHerbert Xu error: 285872cb6962SHerbert Xu return err; 285972cb6962SHerbert Xu } 286072cb6962SHerbert Xu 2861a454f0ccSWei Yongjun EXPORT_SYMBOL(__xfrm_init_state); 2862a454f0ccSWei Yongjun 2863a454f0ccSWei Yongjun int xfrm_init_state(struct xfrm_state *x) 2864a454f0ccSWei Yongjun { 2865cc01572eSYossi Kuperman int err; 2866cc01572eSYossi Kuperman 2867741f9a10SSabrina Dubroca err = __xfrm_init_state(x, true, false, NULL); 2868cc01572eSYossi Kuperman if (!err) 2869cc01572eSYossi Kuperman x->km.state = XFRM_STATE_VALID; 2870cc01572eSYossi Kuperman 2871cc01572eSYossi Kuperman return err; 2872a454f0ccSWei Yongjun } 2873a454f0ccSWei Yongjun 287472cb6962SHerbert Xu EXPORT_SYMBOL(xfrm_init_state); 28751da177e4SLinus Torvalds 2876d62ddc21SAlexey Dobriyan int __net_init xfrm_state_init(struct net *net) 28771da177e4SLinus Torvalds { 2878f034b5d4SDavid S. Miller unsigned int sz; 28791da177e4SLinus Torvalds 2880565f0fa9SMathias Krause if (net_eq(net, &init_net)) 2881565f0fa9SMathias Krause xfrm_state_cache = KMEM_CACHE(xfrm_state, 2882565f0fa9SMathias Krause SLAB_HWCACHE_ALIGN | SLAB_PANIC); 2883565f0fa9SMathias Krause 28849d4139c7SAlexey Dobriyan INIT_LIST_HEAD(&net->xfrm.state_all); 28859d4139c7SAlexey Dobriyan 2886f034b5d4SDavid S. Miller sz = sizeof(struct hlist_head) * 8; 2887f034b5d4SDavid S. Miller 288873d189dcSAlexey Dobriyan net->xfrm.state_bydst = xfrm_hash_alloc(sz); 288973d189dcSAlexey Dobriyan if (!net->xfrm.state_bydst) 289073d189dcSAlexey Dobriyan goto out_bydst; 2891d320bbb3SAlexey Dobriyan net->xfrm.state_bysrc = xfrm_hash_alloc(sz); 2892d320bbb3SAlexey Dobriyan if (!net->xfrm.state_bysrc) 2893d320bbb3SAlexey Dobriyan goto out_bysrc; 2894b754a4fdSAlexey Dobriyan net->xfrm.state_byspi = xfrm_hash_alloc(sz); 2895b754a4fdSAlexey Dobriyan if (!net->xfrm.state_byspi) 2896b754a4fdSAlexey Dobriyan goto out_byspi; 2897fe9f1d87SSabrina Dubroca net->xfrm.state_byseq = xfrm_hash_alloc(sz); 2898fe9f1d87SSabrina Dubroca if (!net->xfrm.state_byseq) 2899fe9f1d87SSabrina Dubroca goto out_byseq; 2900529983ecSAlexey Dobriyan net->xfrm.state_hmask = ((sz / sizeof(struct hlist_head)) - 1); 2901f034b5d4SDavid S. Miller 29020bf7c5b0SAlexey Dobriyan net->xfrm.state_num = 0; 290363082733SAlexey Dobriyan INIT_WORK(&net->xfrm.state_hash_work, xfrm_hash_resize); 2904283bc9f3SFan Du spin_lock_init(&net->xfrm.xfrm_state_lock); 2905bc8e0adfSAhmed S. Darwish seqcount_spinlock_init(&net->xfrm.xfrm_state_hash_generation, 2906bc8e0adfSAhmed S. Darwish &net->xfrm.xfrm_state_lock); 2907d62ddc21SAlexey Dobriyan return 0; 290873d189dcSAlexey Dobriyan 2909fe9f1d87SSabrina Dubroca out_byseq: 2910fe9f1d87SSabrina Dubroca xfrm_hash_free(net->xfrm.state_byspi, sz); 2911b754a4fdSAlexey Dobriyan out_byspi: 2912b754a4fdSAlexey Dobriyan xfrm_hash_free(net->xfrm.state_bysrc, sz); 2913d320bbb3SAlexey Dobriyan out_bysrc: 2914d320bbb3SAlexey Dobriyan xfrm_hash_free(net->xfrm.state_bydst, sz); 291573d189dcSAlexey Dobriyan out_bydst: 291673d189dcSAlexey Dobriyan return -ENOMEM; 2917d62ddc21SAlexey Dobriyan } 2918d62ddc21SAlexey Dobriyan 2919d62ddc21SAlexey Dobriyan void xfrm_state_fini(struct net *net) 2920d62ddc21SAlexey Dobriyan { 292173d189dcSAlexey Dobriyan unsigned int sz; 292273d189dcSAlexey Dobriyan 29237c2776eeSAlexey Dobriyan flush_work(&net->xfrm.state_hash_work); 292435db57bbSFlorian Westphal flush_work(&xfrm_state_gc_work); 2925dbb2483bSCong Wang xfrm_state_flush(net, 0, false, true); 29267c2776eeSAlexey Dobriyan 29279d4139c7SAlexey Dobriyan WARN_ON(!list_empty(&net->xfrm.state_all)); 292873d189dcSAlexey Dobriyan 2929529983ecSAlexey Dobriyan sz = (net->xfrm.state_hmask + 1) * sizeof(struct hlist_head); 2930fe9f1d87SSabrina Dubroca WARN_ON(!hlist_empty(net->xfrm.state_byseq)); 2931fe9f1d87SSabrina Dubroca xfrm_hash_free(net->xfrm.state_byseq, sz); 2932b754a4fdSAlexey Dobriyan WARN_ON(!hlist_empty(net->xfrm.state_byspi)); 2933b754a4fdSAlexey Dobriyan xfrm_hash_free(net->xfrm.state_byspi, sz); 2934d320bbb3SAlexey Dobriyan WARN_ON(!hlist_empty(net->xfrm.state_bysrc)); 2935d320bbb3SAlexey Dobriyan xfrm_hash_free(net->xfrm.state_bysrc, sz); 293673d189dcSAlexey Dobriyan WARN_ON(!hlist_empty(net->xfrm.state_bydst)); 293773d189dcSAlexey Dobriyan xfrm_hash_free(net->xfrm.state_bydst, sz); 29381da177e4SLinus Torvalds } 29391da177e4SLinus Torvalds 2940ab5f5e8bSJoy Latten #ifdef CONFIG_AUDITSYSCALL 2941cf35f43eSIlpo Järvinen static void xfrm_audit_helper_sainfo(struct xfrm_state *x, 2942ab5f5e8bSJoy Latten struct audit_buffer *audit_buf) 2943ab5f5e8bSJoy Latten { 294468277accSPaul Moore struct xfrm_sec_ctx *ctx = x->security; 294568277accSPaul Moore u32 spi = ntohl(x->id.spi); 294668277accSPaul Moore 294768277accSPaul Moore if (ctx) 2948ab5f5e8bSJoy Latten audit_log_format(audit_buf, " sec_alg=%u sec_doi=%u sec_obj=%s", 294968277accSPaul Moore ctx->ctx_alg, ctx->ctx_doi, ctx->ctx_str); 2950ab5f5e8bSJoy Latten 2951ab5f5e8bSJoy Latten switch (x->props.family) { 2952ab5f5e8bSJoy Latten case AF_INET: 295321454aaaSHarvey Harrison audit_log_format(audit_buf, " src=%pI4 dst=%pI4", 295421454aaaSHarvey Harrison &x->props.saddr.a4, &x->id.daddr.a4); 2955ab5f5e8bSJoy Latten break; 2956ab5f5e8bSJoy Latten case AF_INET6: 29575b095d98SHarvey Harrison audit_log_format(audit_buf, " src=%pI6 dst=%pI6", 2958fdb46ee7SHarvey Harrison x->props.saddr.a6, x->id.daddr.a6); 2959ab5f5e8bSJoy Latten break; 2960ab5f5e8bSJoy Latten } 296168277accSPaul Moore 296268277accSPaul Moore audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi); 2963ab5f5e8bSJoy Latten } 2964ab5f5e8bSJoy Latten 2965cf35f43eSIlpo Järvinen static void xfrm_audit_helper_pktinfo(struct sk_buff *skb, u16 family, 2966afeb14b4SPaul Moore struct audit_buffer *audit_buf) 2967afeb14b4SPaul Moore { 2968b71d1d42SEric Dumazet const struct iphdr *iph4; 2969b71d1d42SEric Dumazet const struct ipv6hdr *iph6; 2970afeb14b4SPaul Moore 2971afeb14b4SPaul Moore switch (family) { 2972afeb14b4SPaul Moore case AF_INET: 2973afeb14b4SPaul Moore iph4 = ip_hdr(skb); 297421454aaaSHarvey Harrison audit_log_format(audit_buf, " src=%pI4 dst=%pI4", 297521454aaaSHarvey Harrison &iph4->saddr, &iph4->daddr); 2976afeb14b4SPaul Moore break; 2977afeb14b4SPaul Moore case AF_INET6: 2978afeb14b4SPaul Moore iph6 = ipv6_hdr(skb); 2979afeb14b4SPaul Moore audit_log_format(audit_buf, 29805b095d98SHarvey Harrison " src=%pI6 dst=%pI6 flowlbl=0x%x%02x%02x", 2981fdb46ee7SHarvey Harrison &iph6->saddr, &iph6->daddr, 2982afeb14b4SPaul Moore iph6->flow_lbl[0] & 0x0f, 2983afeb14b4SPaul Moore iph6->flow_lbl[1], 2984afeb14b4SPaul Moore iph6->flow_lbl[2]); 2985afeb14b4SPaul Moore break; 2986afeb14b4SPaul Moore } 2987afeb14b4SPaul Moore } 2988afeb14b4SPaul Moore 29892e71029eSTetsuo Handa void xfrm_audit_state_add(struct xfrm_state *x, int result, bool task_valid) 2990ab5f5e8bSJoy Latten { 2991ab5f5e8bSJoy Latten struct audit_buffer *audit_buf; 2992ab5f5e8bSJoy Latten 2993afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SAD-add"); 2994ab5f5e8bSJoy Latten if (audit_buf == NULL) 2995ab5f5e8bSJoy Latten return; 29962e71029eSTetsuo Handa xfrm_audit_helper_usrinfo(task_valid, audit_buf); 2997afeb14b4SPaul Moore xfrm_audit_helper_sainfo(x, audit_buf); 2998afeb14b4SPaul Moore audit_log_format(audit_buf, " res=%u", result); 2999ab5f5e8bSJoy Latten audit_log_end(audit_buf); 3000ab5f5e8bSJoy Latten } 3001ab5f5e8bSJoy Latten EXPORT_SYMBOL_GPL(xfrm_audit_state_add); 3002ab5f5e8bSJoy Latten 30032e71029eSTetsuo Handa void xfrm_audit_state_delete(struct xfrm_state *x, int result, bool task_valid) 3004ab5f5e8bSJoy Latten { 3005ab5f5e8bSJoy Latten struct audit_buffer *audit_buf; 3006ab5f5e8bSJoy Latten 3007afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SAD-delete"); 3008ab5f5e8bSJoy Latten if (audit_buf == NULL) 3009ab5f5e8bSJoy Latten return; 30102e71029eSTetsuo Handa xfrm_audit_helper_usrinfo(task_valid, audit_buf); 3011afeb14b4SPaul Moore xfrm_audit_helper_sainfo(x, audit_buf); 3012afeb14b4SPaul Moore audit_log_format(audit_buf, " res=%u", result); 3013ab5f5e8bSJoy Latten audit_log_end(audit_buf); 3014ab5f5e8bSJoy Latten } 3015ab5f5e8bSJoy Latten EXPORT_SYMBOL_GPL(xfrm_audit_state_delete); 3016afeb14b4SPaul Moore 3017afeb14b4SPaul Moore void xfrm_audit_state_replay_overflow(struct xfrm_state *x, 3018afeb14b4SPaul Moore struct sk_buff *skb) 3019afeb14b4SPaul Moore { 3020afeb14b4SPaul Moore struct audit_buffer *audit_buf; 3021afeb14b4SPaul Moore u32 spi; 3022afeb14b4SPaul Moore 3023afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SA-replay-overflow"); 3024afeb14b4SPaul Moore if (audit_buf == NULL) 3025afeb14b4SPaul Moore return; 3026afeb14b4SPaul Moore xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf); 3027afeb14b4SPaul Moore /* don't record the sequence number because it's inherent in this kind 3028afeb14b4SPaul Moore * of audit message */ 3029afeb14b4SPaul Moore spi = ntohl(x->id.spi); 3030afeb14b4SPaul Moore audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi); 3031afeb14b4SPaul Moore audit_log_end(audit_buf); 3032afeb14b4SPaul Moore } 3033afeb14b4SPaul Moore EXPORT_SYMBOL_GPL(xfrm_audit_state_replay_overflow); 3034afeb14b4SPaul Moore 30359fdc4883SSteffen Klassert void xfrm_audit_state_replay(struct xfrm_state *x, 3036afeb14b4SPaul Moore struct sk_buff *skb, __be32 net_seq) 3037afeb14b4SPaul Moore { 3038afeb14b4SPaul Moore struct audit_buffer *audit_buf; 3039afeb14b4SPaul Moore u32 spi; 3040afeb14b4SPaul Moore 3041afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SA-replayed-pkt"); 3042afeb14b4SPaul Moore if (audit_buf == NULL) 3043afeb14b4SPaul Moore return; 3044afeb14b4SPaul Moore xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf); 3045afeb14b4SPaul Moore spi = ntohl(x->id.spi); 3046afeb14b4SPaul Moore audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u", 3047afeb14b4SPaul Moore spi, spi, ntohl(net_seq)); 3048afeb14b4SPaul Moore audit_log_end(audit_buf); 3049afeb14b4SPaul Moore } 30509fdc4883SSteffen Klassert EXPORT_SYMBOL_GPL(xfrm_audit_state_replay); 3051afeb14b4SPaul Moore 3052afeb14b4SPaul Moore void xfrm_audit_state_notfound_simple(struct sk_buff *skb, u16 family) 3053afeb14b4SPaul Moore { 3054afeb14b4SPaul Moore struct audit_buffer *audit_buf; 3055afeb14b4SPaul Moore 3056afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SA-notfound"); 3057afeb14b4SPaul Moore if (audit_buf == NULL) 3058afeb14b4SPaul Moore return; 3059afeb14b4SPaul Moore xfrm_audit_helper_pktinfo(skb, family, audit_buf); 3060afeb14b4SPaul Moore audit_log_end(audit_buf); 3061afeb14b4SPaul Moore } 3062afeb14b4SPaul Moore EXPORT_SYMBOL_GPL(xfrm_audit_state_notfound_simple); 3063afeb14b4SPaul Moore 3064afeb14b4SPaul Moore void xfrm_audit_state_notfound(struct sk_buff *skb, u16 family, 3065afeb14b4SPaul Moore __be32 net_spi, __be32 net_seq) 3066afeb14b4SPaul Moore { 3067afeb14b4SPaul Moore struct audit_buffer *audit_buf; 3068afeb14b4SPaul Moore u32 spi; 3069afeb14b4SPaul Moore 3070afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SA-notfound"); 3071afeb14b4SPaul Moore if (audit_buf == NULL) 3072afeb14b4SPaul Moore return; 3073afeb14b4SPaul Moore xfrm_audit_helper_pktinfo(skb, family, audit_buf); 3074afeb14b4SPaul Moore spi = ntohl(net_spi); 3075afeb14b4SPaul Moore audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u", 3076afeb14b4SPaul Moore spi, spi, ntohl(net_seq)); 3077afeb14b4SPaul Moore audit_log_end(audit_buf); 3078afeb14b4SPaul Moore } 3079afeb14b4SPaul Moore EXPORT_SYMBOL_GPL(xfrm_audit_state_notfound); 3080afeb14b4SPaul Moore 3081afeb14b4SPaul Moore void xfrm_audit_state_icvfail(struct xfrm_state *x, 3082afeb14b4SPaul Moore struct sk_buff *skb, u8 proto) 3083afeb14b4SPaul Moore { 3084afeb14b4SPaul Moore struct audit_buffer *audit_buf; 3085afeb14b4SPaul Moore __be32 net_spi; 3086afeb14b4SPaul Moore __be32 net_seq; 3087afeb14b4SPaul Moore 3088afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SA-icv-failure"); 3089afeb14b4SPaul Moore if (audit_buf == NULL) 3090afeb14b4SPaul Moore return; 3091afeb14b4SPaul Moore xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf); 3092afeb14b4SPaul Moore if (xfrm_parse_spi(skb, proto, &net_spi, &net_seq) == 0) { 3093afeb14b4SPaul Moore u32 spi = ntohl(net_spi); 3094afeb14b4SPaul Moore audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u", 3095afeb14b4SPaul Moore spi, spi, ntohl(net_seq)); 3096afeb14b4SPaul Moore } 3097afeb14b4SPaul Moore audit_log_end(audit_buf); 3098afeb14b4SPaul Moore } 3099afeb14b4SPaul Moore EXPORT_SYMBOL_GPL(xfrm_audit_state_icvfail); 3100ab5f5e8bSJoy Latten #endif /* CONFIG_AUDITSYSCALL */ 3101