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 873c611d40SLeon Romanovsky #define XFRM_STATE_INSERT(by, _n, _h, _type) \ 883c611d40SLeon Romanovsky { \ 893c611d40SLeon Romanovsky struct xfrm_state *_x = NULL; \ 903c611d40SLeon Romanovsky \ 913c611d40SLeon Romanovsky if (_type != XFRM_DEV_OFFLOAD_PACKET) { \ 923c611d40SLeon Romanovsky hlist_for_each_entry_rcu(_x, _h, by) { \ 933c611d40SLeon Romanovsky if (_x->xso.type == XFRM_DEV_OFFLOAD_PACKET) \ 943c611d40SLeon Romanovsky continue; \ 953c611d40SLeon Romanovsky break; \ 963c611d40SLeon Romanovsky } \ 973c611d40SLeon Romanovsky } \ 983c611d40SLeon Romanovsky \ 993c611d40SLeon Romanovsky if (!_x || _x->xso.type == XFRM_DEV_OFFLOAD_PACKET) \ 1003c611d40SLeon Romanovsky /* SAD is empty or consist from HW SAs only */ \ 1013c611d40SLeon Romanovsky hlist_add_head_rcu(_n, _h); \ 1023c611d40SLeon Romanovsky else \ 1033c611d40SLeon Romanovsky hlist_add_before_rcu(_n, &_x->by); \ 1043c611d40SLeon Romanovsky } 1053c611d40SLeon 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); 1223c611d40SLeon 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); 1273c611d40SLeon 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); 1333c611d40SLeon Romanovsky XFRM_STATE_INSERT(byspi, &x->byspi, nspitable + h, 1343c611d40SLeon 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); 1393c611d40SLeon Romanovsky XFRM_STATE_INSERT(byseq, &x->byseq, nseqtable + h, 1403c611d40SLeon 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); 573f3da86dcSLeon Romanovsky xfrm_dev_state_update_curlft(x); 574f3da86dcSLeon Romanovsky 5751da177e4SLinus Torvalds if (x->km.state == XFRM_STATE_DEAD) 5761da177e4SLinus Torvalds goto out; 5771da177e4SLinus Torvalds if (x->km.state == XFRM_STATE_EXPIRED) 5781da177e4SLinus Torvalds goto expired; 5791da177e4SLinus Torvalds if (x->lft.hard_add_expires_seconds) { 5801da177e4SLinus Torvalds long tmo = x->lft.hard_add_expires_seconds + 5811da177e4SLinus Torvalds x->curlft.add_time - now; 582e3c0d047SFan Du if (tmo <= 0) { 583e3c0d047SFan Du if (x->xflags & XFRM_SOFT_EXPIRE) { 584e3c0d047SFan Du /* enter hard expire without soft expire first?! 585e3c0d047SFan Du * setting a new date could trigger this. 5861365e547SAlexander Alemayhu * workaround: fix x->curflt.add_time by below: 587e3c0d047SFan Du */ 588e3c0d047SFan Du x->curlft.add_time = now - x->saved_tmo - 1; 589e3c0d047SFan Du tmo = x->lft.hard_add_expires_seconds - x->saved_tmo; 590e3c0d047SFan Du } else 5911da177e4SLinus Torvalds goto expired; 592e3c0d047SFan Du } 5931da177e4SLinus Torvalds if (tmo < next) 5941da177e4SLinus Torvalds next = tmo; 5951da177e4SLinus Torvalds } 5961da177e4SLinus Torvalds if (x->lft.hard_use_expires_seconds) { 5971da177e4SLinus Torvalds long tmo = x->lft.hard_use_expires_seconds + 5981da177e4SLinus Torvalds (x->curlft.use_time ? : now) - now; 5991da177e4SLinus Torvalds if (tmo <= 0) 6001da177e4SLinus Torvalds goto expired; 6011da177e4SLinus Torvalds if (tmo < next) 6021da177e4SLinus Torvalds next = tmo; 6031da177e4SLinus Torvalds } 6041da177e4SLinus Torvalds if (x->km.dying) 6051da177e4SLinus Torvalds goto resched; 6061da177e4SLinus Torvalds if (x->lft.soft_add_expires_seconds) { 6071da177e4SLinus Torvalds long tmo = x->lft.soft_add_expires_seconds + 6081da177e4SLinus Torvalds x->curlft.add_time - now; 609e3c0d047SFan Du if (tmo <= 0) { 6101da177e4SLinus Torvalds warn = 1; 611e3c0d047SFan Du x->xflags &= ~XFRM_SOFT_EXPIRE; 612e3c0d047SFan Du } else if (tmo < next) { 6131da177e4SLinus Torvalds next = tmo; 614e3c0d047SFan Du x->xflags |= XFRM_SOFT_EXPIRE; 615e3c0d047SFan Du x->saved_tmo = tmo; 616e3c0d047SFan Du } 6171da177e4SLinus Torvalds } 6181da177e4SLinus Torvalds if (x->lft.soft_use_expires_seconds) { 6191da177e4SLinus Torvalds long tmo = x->lft.soft_use_expires_seconds + 6201da177e4SLinus Torvalds (x->curlft.use_time ? : now) - now; 6211da177e4SLinus Torvalds if (tmo <= 0) 6221da177e4SLinus Torvalds warn = 1; 6231da177e4SLinus Torvalds else if (tmo < next) 6241da177e4SLinus Torvalds next = tmo; 6251da177e4SLinus Torvalds } 6261da177e4SLinus Torvalds 6274666faabSHerbert Xu x->km.dying = warn; 6281da177e4SLinus Torvalds if (warn) 62953bc6b4dSJamal Hadi Salim km_state_expired(x, 0, 0); 6301da177e4SLinus Torvalds resched: 631386c5680SArnd Bergmann if (next != TIME64_MAX) { 632671422b2SThomas Gleixner hrtimer_forward_now(&x->mtimer, ktime_set(next, 0)); 633671422b2SThomas Gleixner ret = HRTIMER_RESTART; 6349e0d57fdSYury Polyanskiy } 635a47f0ce0SDavid S. Miller 6361da177e4SLinus Torvalds goto out; 6371da177e4SLinus Torvalds 6381da177e4SLinus Torvalds expired: 6395b8ef341SSteffen Klassert if (x->km.state == XFRM_STATE_ACQ && x->id.spi == 0) 6401da177e4SLinus Torvalds x->km.state = XFRM_STATE_EXPIRED; 641161a09e7SJoy Latten 642161a09e7SJoy Latten err = __xfrm_state_delete(x); 6430806ae4cSNicolas Dichtel if (!err) 64453bc6b4dSJamal Hadi Salim km_state_expired(x, 1, 0); 6451da177e4SLinus Torvalds 6462e71029eSTetsuo Handa xfrm_audit_state_delete(x, err ? 0 : 1, true); 647161a09e7SJoy Latten 6481da177e4SLinus Torvalds out: 6491da177e4SLinus Torvalds spin_unlock(&x->lock); 650671422b2SThomas Gleixner return ret; 6511da177e4SLinus Torvalds } 6521da177e4SLinus Torvalds 653e99e88a9SKees Cook static void xfrm_replay_timer_handler(struct timer_list *t); 6540ac84752SDavid S. Miller 655673c09beSAlexey Dobriyan struct xfrm_state *xfrm_state_alloc(struct net *net) 6561da177e4SLinus Torvalds { 6571da177e4SLinus Torvalds struct xfrm_state *x; 6581da177e4SLinus Torvalds 659a4c278d1SHuang Zijiang x = kmem_cache_zalloc(xfrm_state_cache, GFP_ATOMIC); 6601da177e4SLinus Torvalds 6611da177e4SLinus Torvalds if (x) { 662673c09beSAlexey Dobriyan write_pnet(&x->xs_net, net); 66388755e9cSReshetova, Elena refcount_set(&x->refcnt, 1); 6641da177e4SLinus Torvalds atomic_set(&x->tunnel_users, 0); 66512a169e7SHerbert Xu INIT_LIST_HEAD(&x->km.all); 6668f126e37SDavid S. Miller INIT_HLIST_NODE(&x->bydst); 6678f126e37SDavid S. Miller INIT_HLIST_NODE(&x->bysrc); 6688f126e37SDavid S. Miller INIT_HLIST_NODE(&x->byspi); 669fe9f1d87SSabrina Dubroca INIT_HLIST_NODE(&x->byseq); 670671422b2SThomas Gleixner hrtimer_init(&x->mtimer, CLOCK_BOOTTIME, HRTIMER_MODE_ABS_SOFT); 671671422b2SThomas Gleixner x->mtimer.function = xfrm_timer_handler; 672e99e88a9SKees Cook timer_setup(&x->rtimer, xfrm_replay_timer_handler, 0); 673386c5680SArnd Bergmann x->curlft.add_time = ktime_get_real_seconds(); 6741da177e4SLinus Torvalds x->lft.soft_byte_limit = XFRM_INF; 6751da177e4SLinus Torvalds x->lft.soft_packet_limit = XFRM_INF; 6761da177e4SLinus Torvalds x->lft.hard_byte_limit = XFRM_INF; 6771da177e4SLinus Torvalds x->lft.hard_packet_limit = XFRM_INF; 678f8cd5488SJamal Hadi Salim x->replay_maxage = 0; 679f8cd5488SJamal Hadi Salim x->replay_maxdiff = 0; 6801da177e4SLinus Torvalds spin_lock_init(&x->lock); 6811da177e4SLinus Torvalds } 6821da177e4SLinus Torvalds return x; 6831da177e4SLinus Torvalds } 6841da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_alloc); 6851da177e4SLinus Torvalds 686f75a2804SCong Wang void __xfrm_state_destroy(struct xfrm_state *x, bool sync) 6871da177e4SLinus Torvalds { 688547b792cSIlpo Järvinen WARN_ON(x->km.state != XFRM_STATE_DEAD); 6891da177e4SLinus Torvalds 690f75a2804SCong Wang if (sync) { 691f75a2804SCong Wang synchronize_rcu(); 692f75a2804SCong Wang ___xfrm_state_destroy(x); 693f75a2804SCong Wang } else { 6941da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_gc_lock); 69535db57bbSFlorian Westphal hlist_add_head(&x->gclist, &xfrm_state_gc_list); 6961da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_gc_lock); 69735db57bbSFlorian Westphal schedule_work(&xfrm_state_gc_work); 6981da177e4SLinus Torvalds } 699f75a2804SCong Wang } 7001da177e4SLinus Torvalds EXPORT_SYMBOL(__xfrm_state_destroy); 7011da177e4SLinus Torvalds 70253bc6b4dSJamal Hadi Salim int __xfrm_state_delete(struct xfrm_state *x) 7031da177e4SLinus Torvalds { 70498806f75SAlexey Dobriyan struct net *net = xs_net(x); 70526b15dadSJamal Hadi Salim int err = -ESRCH; 70626b15dadSJamal Hadi Salim 7071da177e4SLinus Torvalds if (x->km.state != XFRM_STATE_DEAD) { 7081da177e4SLinus Torvalds x->km.state = XFRM_STATE_DEAD; 709283bc9f3SFan Du spin_lock(&net->xfrm.xfrm_state_lock); 71012a169e7SHerbert Xu list_del(&x->km.all); 711ae3fb6d3SFlorian Westphal hlist_del_rcu(&x->bydst); 712ae3fb6d3SFlorian Westphal hlist_del_rcu(&x->bysrc); 713fe9f1d87SSabrina Dubroca if (x->km.seq) 714fe9f1d87SSabrina Dubroca hlist_del_rcu(&x->byseq); 715a47f0ce0SDavid S. Miller if (x->id.spi) 716ae3fb6d3SFlorian Westphal hlist_del_rcu(&x->byspi); 71798806f75SAlexey Dobriyan net->xfrm.state_num--; 718283bc9f3SFan Du spin_unlock(&net->xfrm.xfrm_state_lock); 7191da177e4SLinus Torvalds 720e27cca96SSabrina Dubroca if (x->encap_sk) 721e27cca96SSabrina Dubroca sock_put(rcu_dereference_raw(x->encap_sk)); 722e27cca96SSabrina Dubroca 723d77e38e6SSteffen Klassert xfrm_dev_state_delete(x); 724d77e38e6SSteffen Klassert 7251da177e4SLinus Torvalds /* All xfrm_state objects are created by xfrm_state_alloc. 7261da177e4SLinus Torvalds * The xfrm_state_alloc call gives a reference, and that 7271da177e4SLinus Torvalds * is what we are dropping here. 7281da177e4SLinus Torvalds */ 7295dba4797SPatrick McHardy xfrm_state_put(x); 73026b15dadSJamal Hadi Salim err = 0; 7311da177e4SLinus Torvalds } 7321da177e4SLinus Torvalds 73326b15dadSJamal Hadi Salim return err; 73426b15dadSJamal Hadi Salim } 73553bc6b4dSJamal Hadi Salim EXPORT_SYMBOL(__xfrm_state_delete); 73626b15dadSJamal Hadi Salim 73726b15dadSJamal Hadi Salim int xfrm_state_delete(struct xfrm_state *x) 7381da177e4SLinus Torvalds { 73926b15dadSJamal Hadi Salim int err; 74026b15dadSJamal Hadi Salim 7411da177e4SLinus Torvalds spin_lock_bh(&x->lock); 74226b15dadSJamal Hadi Salim err = __xfrm_state_delete(x); 7431da177e4SLinus Torvalds spin_unlock_bh(&x->lock); 74426b15dadSJamal Hadi Salim 74526b15dadSJamal Hadi Salim return err; 7461da177e4SLinus Torvalds } 7471da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_delete); 7481da177e4SLinus Torvalds 7494aa2e62cSJoy Latten #ifdef CONFIG_SECURITY_NETWORK_XFRM 7504aa2e62cSJoy Latten static inline int 7512e71029eSTetsuo Handa xfrm_state_flush_secctx_check(struct net *net, u8 proto, bool task_valid) 7521da177e4SLinus Torvalds { 7534aa2e62cSJoy Latten int i, err = 0; 7544aa2e62cSJoy Latten 7550e602451SAlexey Dobriyan for (i = 0; i <= net->xfrm.state_hmask; i++) { 7564aa2e62cSJoy Latten struct xfrm_state *x; 7574aa2e62cSJoy Latten 758b67bfe0dSSasha Levin hlist_for_each_entry(x, net->xfrm.state_bydst+i, bydst) { 7594aa2e62cSJoy Latten if (xfrm_id_proto_match(x->id.proto, proto) && 7604aa2e62cSJoy Latten (err = security_xfrm_state_delete(x)) != 0) { 7612e71029eSTetsuo Handa xfrm_audit_state_delete(x, 0, task_valid); 7624aa2e62cSJoy Latten return err; 7634aa2e62cSJoy Latten } 7644aa2e62cSJoy Latten } 7654aa2e62cSJoy Latten } 7664aa2e62cSJoy Latten 7674aa2e62cSJoy Latten return err; 7684aa2e62cSJoy Latten } 769d77e38e6SSteffen Klassert 770d77e38e6SSteffen Klassert static inline int 771d77e38e6SSteffen Klassert xfrm_dev_state_flush_secctx_check(struct net *net, struct net_device *dev, bool task_valid) 772d77e38e6SSteffen Klassert { 773d77e38e6SSteffen Klassert int i, err = 0; 774d77e38e6SSteffen Klassert 775d77e38e6SSteffen Klassert for (i = 0; i <= net->xfrm.state_hmask; i++) { 776d77e38e6SSteffen Klassert struct xfrm_state *x; 77787e0a94eSLeon Romanovsky struct xfrm_dev_offload *xso; 778d77e38e6SSteffen Klassert 779d77e38e6SSteffen Klassert hlist_for_each_entry(x, net->xfrm.state_bydst+i, bydst) { 780d77e38e6SSteffen Klassert xso = &x->xso; 781d77e38e6SSteffen Klassert 782d77e38e6SSteffen Klassert if (xso->dev == dev && 783d77e38e6SSteffen Klassert (err = security_xfrm_state_delete(x)) != 0) { 784d77e38e6SSteffen Klassert xfrm_audit_state_delete(x, 0, task_valid); 785d77e38e6SSteffen Klassert return err; 786d77e38e6SSteffen Klassert } 787d77e38e6SSteffen Klassert } 788d77e38e6SSteffen Klassert } 789d77e38e6SSteffen Klassert 790d77e38e6SSteffen Klassert return err; 791d77e38e6SSteffen Klassert } 7924aa2e62cSJoy Latten #else 7934aa2e62cSJoy Latten static inline int 7942e71029eSTetsuo Handa xfrm_state_flush_secctx_check(struct net *net, u8 proto, bool task_valid) 7954aa2e62cSJoy Latten { 7964aa2e62cSJoy Latten return 0; 7974aa2e62cSJoy Latten } 798d77e38e6SSteffen Klassert 799d77e38e6SSteffen Klassert static inline int 800d77e38e6SSteffen Klassert xfrm_dev_state_flush_secctx_check(struct net *net, struct net_device *dev, bool task_valid) 801d77e38e6SSteffen Klassert { 802d77e38e6SSteffen Klassert return 0; 803d77e38e6SSteffen Klassert } 8044aa2e62cSJoy Latten #endif 8054aa2e62cSJoy Latten 806f75a2804SCong Wang int xfrm_state_flush(struct net *net, u8 proto, bool task_valid, bool sync) 8074aa2e62cSJoy Latten { 8089e64cc95SJamal Hadi Salim int i, err = 0, cnt = 0; 8091da177e4SLinus Torvalds 810283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 8112e71029eSTetsuo Handa err = xfrm_state_flush_secctx_check(net, proto, task_valid); 8124aa2e62cSJoy Latten if (err) 8134aa2e62cSJoy Latten goto out; 8144aa2e62cSJoy Latten 8159e64cc95SJamal Hadi Salim err = -ESRCH; 8160e602451SAlexey Dobriyan for (i = 0; i <= net->xfrm.state_hmask; i++) { 8178f126e37SDavid S. Miller struct xfrm_state *x; 8181da177e4SLinus Torvalds restart: 819b67bfe0dSSasha Levin hlist_for_each_entry(x, net->xfrm.state_bydst+i, bydst) { 8201da177e4SLinus Torvalds if (!xfrm_state_kern(x) && 8215794708fSMasahide NAKAMURA xfrm_id_proto_match(x->id.proto, proto)) { 8221da177e4SLinus Torvalds xfrm_state_hold(x); 823283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 8241da177e4SLinus Torvalds 825161a09e7SJoy Latten err = xfrm_state_delete(x); 826ab5f5e8bSJoy Latten xfrm_audit_state_delete(x, err ? 0 : 1, 8272e71029eSTetsuo Handa task_valid); 828f75a2804SCong Wang if (sync) 829f75a2804SCong Wang xfrm_state_put_sync(x); 830f75a2804SCong Wang else 8311da177e4SLinus Torvalds xfrm_state_put(x); 8329e64cc95SJamal Hadi Salim if (!err) 8339e64cc95SJamal Hadi Salim cnt++; 8341da177e4SLinus Torvalds 835283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 8361da177e4SLinus Torvalds goto restart; 8371da177e4SLinus Torvalds } 8381da177e4SLinus Torvalds } 8391da177e4SLinus Torvalds } 840dd269db8SArtem Savkov out: 841dd269db8SArtem Savkov spin_unlock_bh(&net->xfrm.xfrm_state_lock); 842e4db5b61SFlorian Westphal if (cnt) 8434aa2e62cSJoy Latten err = 0; 844e4db5b61SFlorian Westphal 8454aa2e62cSJoy Latten return err; 8461da177e4SLinus Torvalds } 8471da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_flush); 8481da177e4SLinus Torvalds 849d77e38e6SSteffen Klassert int xfrm_dev_state_flush(struct net *net, struct net_device *dev, bool task_valid) 850d77e38e6SSteffen Klassert { 851d77e38e6SSteffen Klassert int i, err = 0, cnt = 0; 852d77e38e6SSteffen Klassert 853d77e38e6SSteffen Klassert spin_lock_bh(&net->xfrm.xfrm_state_lock); 854d77e38e6SSteffen Klassert err = xfrm_dev_state_flush_secctx_check(net, dev, task_valid); 855d77e38e6SSteffen Klassert if (err) 856d77e38e6SSteffen Klassert goto out; 857d77e38e6SSteffen Klassert 858d77e38e6SSteffen Klassert err = -ESRCH; 859d77e38e6SSteffen Klassert for (i = 0; i <= net->xfrm.state_hmask; i++) { 860d77e38e6SSteffen Klassert struct xfrm_state *x; 86187e0a94eSLeon Romanovsky struct xfrm_dev_offload *xso; 862d77e38e6SSteffen Klassert restart: 863d77e38e6SSteffen Klassert hlist_for_each_entry(x, net->xfrm.state_bydst+i, bydst) { 864d77e38e6SSteffen Klassert xso = &x->xso; 865d77e38e6SSteffen Klassert 866d77e38e6SSteffen Klassert if (!xfrm_state_kern(x) && xso->dev == dev) { 867d77e38e6SSteffen Klassert xfrm_state_hold(x); 868d77e38e6SSteffen Klassert spin_unlock_bh(&net->xfrm.xfrm_state_lock); 869d77e38e6SSteffen Klassert 870d77e38e6SSteffen Klassert err = xfrm_state_delete(x); 871d77e38e6SSteffen Klassert xfrm_audit_state_delete(x, err ? 0 : 1, 872d77e38e6SSteffen Klassert task_valid); 873d77e38e6SSteffen Klassert xfrm_state_put(x); 874d77e38e6SSteffen Klassert if (!err) 875d77e38e6SSteffen Klassert cnt++; 876d77e38e6SSteffen Klassert 877d77e38e6SSteffen Klassert spin_lock_bh(&net->xfrm.xfrm_state_lock); 878d77e38e6SSteffen Klassert goto restart; 879d77e38e6SSteffen Klassert } 880d77e38e6SSteffen Klassert } 881d77e38e6SSteffen Klassert } 882d77e38e6SSteffen Klassert if (cnt) 883d77e38e6SSteffen Klassert err = 0; 884d77e38e6SSteffen Klassert 885d77e38e6SSteffen Klassert out: 886d77e38e6SSteffen Klassert spin_unlock_bh(&net->xfrm.xfrm_state_lock); 887d77e38e6SSteffen Klassert return err; 888d77e38e6SSteffen Klassert } 889d77e38e6SSteffen Klassert EXPORT_SYMBOL(xfrm_dev_state_flush); 890d77e38e6SSteffen Klassert 891e071041bSAlexey Dobriyan void xfrm_sad_getinfo(struct net *net, struct xfrmk_sadinfo *si) 89228d8909bSJamal Hadi Salim { 893283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 894e071041bSAlexey Dobriyan si->sadcnt = net->xfrm.state_num; 895ca92e173SBenjamin Poirier si->sadhcnt = net->xfrm.state_hmask + 1; 89628d8909bSJamal Hadi Salim si->sadhmcnt = xfrm_state_hashmax; 897283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 89828d8909bSJamal Hadi Salim } 89928d8909bSJamal Hadi Salim EXPORT_SYMBOL(xfrm_sad_getinfo); 90028d8909bSJamal Hadi Salim 901711059b9SFlorian Westphal static void 902bac95935SFlorian Westphal __xfrm4_init_tempsel(struct xfrm_selector *sel, const struct flowi *fl) 903bac95935SFlorian Westphal { 904bac95935SFlorian Westphal const struct flowi4 *fl4 = &fl->u.ip4; 905bac95935SFlorian Westphal 906bac95935SFlorian Westphal sel->daddr.a4 = fl4->daddr; 907bac95935SFlorian Westphal sel->saddr.a4 = fl4->saddr; 908bac95935SFlorian Westphal sel->dport = xfrm_flowi_dport(fl, &fl4->uli); 909bac95935SFlorian Westphal sel->dport_mask = htons(0xffff); 910bac95935SFlorian Westphal sel->sport = xfrm_flowi_sport(fl, &fl4->uli); 911bac95935SFlorian Westphal sel->sport_mask = htons(0xffff); 912bac95935SFlorian Westphal sel->family = AF_INET; 913bac95935SFlorian Westphal sel->prefixlen_d = 32; 914bac95935SFlorian Westphal sel->prefixlen_s = 32; 915bac95935SFlorian Westphal sel->proto = fl4->flowi4_proto; 916bac95935SFlorian Westphal sel->ifindex = fl4->flowi4_oif; 917bac95935SFlorian Westphal } 918bac95935SFlorian Westphal 919bac95935SFlorian Westphal static void 920bac95935SFlorian Westphal __xfrm6_init_tempsel(struct xfrm_selector *sel, const struct flowi *fl) 921bac95935SFlorian Westphal { 922bac95935SFlorian Westphal const struct flowi6 *fl6 = &fl->u.ip6; 923bac95935SFlorian Westphal 924bac95935SFlorian Westphal /* Initialize temporary selector matching only to current session. */ 925bac95935SFlorian Westphal *(struct in6_addr *)&sel->daddr = fl6->daddr; 926bac95935SFlorian Westphal *(struct in6_addr *)&sel->saddr = fl6->saddr; 927bac95935SFlorian Westphal sel->dport = xfrm_flowi_dport(fl, &fl6->uli); 928bac95935SFlorian Westphal sel->dport_mask = htons(0xffff); 929bac95935SFlorian Westphal sel->sport = xfrm_flowi_sport(fl, &fl6->uli); 930bac95935SFlorian Westphal sel->sport_mask = htons(0xffff); 931bac95935SFlorian Westphal sel->family = AF_INET6; 932bac95935SFlorian Westphal sel->prefixlen_d = 128; 933bac95935SFlorian Westphal sel->prefixlen_s = 128; 934bac95935SFlorian Westphal sel->proto = fl6->flowi6_proto; 935bac95935SFlorian Westphal sel->ifindex = fl6->flowi6_oif; 936bac95935SFlorian Westphal } 937bac95935SFlorian Westphal 938bac95935SFlorian Westphal static void 9391a898592SDavid S. Miller xfrm_init_tempstate(struct xfrm_state *x, const struct flowi *fl, 94004686013SDavid S. Miller const struct xfrm_tmpl *tmpl, 94133765d06SDavid S. Miller const xfrm_address_t *daddr, const xfrm_address_t *saddr, 9421da177e4SLinus Torvalds unsigned short family) 9431da177e4SLinus Torvalds { 944bac95935SFlorian Westphal switch (family) { 945bac95935SFlorian Westphal case AF_INET: 946bac95935SFlorian Westphal __xfrm4_init_tempsel(&x->sel, fl); 947bac95935SFlorian Westphal break; 948bac95935SFlorian Westphal case AF_INET6: 949bac95935SFlorian Westphal __xfrm6_init_tempsel(&x->sel, fl); 950bac95935SFlorian Westphal break; 9518444cf71SThomas Egerer } 952bac95935SFlorian Westphal 9535c1b9ab3SFlorian Westphal x->id = tmpl->id; 954bac95935SFlorian Westphal 9555c1b9ab3SFlorian Westphal switch (tmpl->encap_family) { 9565c1b9ab3SFlorian Westphal case AF_INET: 9575c1b9ab3SFlorian Westphal if (x->id.daddr.a4 == 0) 9585c1b9ab3SFlorian Westphal x->id.daddr.a4 = daddr->a4; 9595c1b9ab3SFlorian Westphal x->props.saddr = tmpl->saddr; 9605c1b9ab3SFlorian Westphal if (x->props.saddr.a4 == 0) 9615c1b9ab3SFlorian Westphal x->props.saddr.a4 = saddr->a4; 9625c1b9ab3SFlorian Westphal break; 9635c1b9ab3SFlorian Westphal case AF_INET6: 9645c1b9ab3SFlorian Westphal if (ipv6_addr_any((struct in6_addr *)&x->id.daddr)) 9655c1b9ab3SFlorian Westphal memcpy(&x->id.daddr, daddr, sizeof(x->sel.daddr)); 9665c1b9ab3SFlorian Westphal memcpy(&x->props.saddr, &tmpl->saddr, sizeof(x->props.saddr)); 9675c1b9ab3SFlorian Westphal if (ipv6_addr_any((struct in6_addr *)&x->props.saddr)) 9685c1b9ab3SFlorian Westphal memcpy(&x->props.saddr, saddr, sizeof(x->props.saddr)); 9695c1b9ab3SFlorian Westphal break; 9705c1b9ab3SFlorian Westphal } 971bac95935SFlorian Westphal 9725c1b9ab3SFlorian Westphal x->props.mode = tmpl->mode; 9735c1b9ab3SFlorian Westphal x->props.reqid = tmpl->reqid; 9745c1b9ab3SFlorian Westphal x->props.family = tmpl->encap_family; 9751da177e4SLinus Torvalds } 9761da177e4SLinus Torvalds 977f8a70afaSLeon Romanovsky static struct xfrm_state *__xfrm_state_lookup_all(struct net *net, u32 mark, 978f8a70afaSLeon Romanovsky const xfrm_address_t *daddr, 979f8a70afaSLeon Romanovsky __be32 spi, u8 proto, 980f8a70afaSLeon Romanovsky unsigned short family, 981f8a70afaSLeon Romanovsky struct xfrm_dev_offload *xdo) 982f8a70afaSLeon Romanovsky { 983f8a70afaSLeon Romanovsky unsigned int h = xfrm_spi_hash(net, daddr, spi, proto, family); 984f8a70afaSLeon Romanovsky struct xfrm_state *x; 985f8a70afaSLeon Romanovsky 986f8a70afaSLeon Romanovsky hlist_for_each_entry_rcu(x, net->xfrm.state_byspi + h, byspi) { 987f8a70afaSLeon Romanovsky #ifdef CONFIG_XFRM_OFFLOAD 988f8a70afaSLeon Romanovsky if (xdo->type == XFRM_DEV_OFFLOAD_PACKET) { 989f8a70afaSLeon Romanovsky if (x->xso.type != XFRM_DEV_OFFLOAD_PACKET) 990f8a70afaSLeon Romanovsky /* HW states are in the head of list, there is 991f8a70afaSLeon Romanovsky * no need to iterate further. 992f8a70afaSLeon Romanovsky */ 993f8a70afaSLeon Romanovsky break; 994f8a70afaSLeon Romanovsky 995f8a70afaSLeon Romanovsky /* Packet offload: both policy and SA should 996f8a70afaSLeon Romanovsky * have same device. 997f8a70afaSLeon Romanovsky */ 998f8a70afaSLeon Romanovsky if (xdo->dev != x->xso.dev) 999f8a70afaSLeon Romanovsky continue; 1000f8a70afaSLeon Romanovsky } else if (x->xso.type == XFRM_DEV_OFFLOAD_PACKET) 1001f8a70afaSLeon Romanovsky /* Skip HW policy for SW lookups */ 1002f8a70afaSLeon Romanovsky continue; 1003f8a70afaSLeon Romanovsky #endif 1004f8a70afaSLeon Romanovsky if (x->props.family != family || 1005f8a70afaSLeon Romanovsky x->id.spi != spi || 1006f8a70afaSLeon Romanovsky x->id.proto != proto || 1007f8a70afaSLeon Romanovsky !xfrm_addr_equal(&x->id.daddr, daddr, family)) 1008f8a70afaSLeon Romanovsky continue; 1009f8a70afaSLeon Romanovsky 1010f8a70afaSLeon Romanovsky if ((mark & x->mark.m) != x->mark.v) 1011f8a70afaSLeon Romanovsky continue; 1012f8a70afaSLeon Romanovsky if (!xfrm_state_hold_rcu(x)) 1013f8a70afaSLeon Romanovsky continue; 1014f8a70afaSLeon Romanovsky return x; 1015f8a70afaSLeon Romanovsky } 1016f8a70afaSLeon Romanovsky 1017f8a70afaSLeon Romanovsky return NULL; 1018f8a70afaSLeon Romanovsky } 1019f8a70afaSLeon Romanovsky 10209aa60088SDavid S. Miller static struct xfrm_state *__xfrm_state_lookup(struct net *net, u32 mark, 10219aa60088SDavid S. Miller const xfrm_address_t *daddr, 10229aa60088SDavid S. Miller __be32 spi, u8 proto, 10239aa60088SDavid S. Miller unsigned short family) 1024edcd5821SDavid S. Miller { 1025221df1edSAlexey Dobriyan unsigned int h = xfrm_spi_hash(net, daddr, spi, proto, family); 1026edcd5821SDavid S. Miller struct xfrm_state *x; 1027edcd5821SDavid S. Miller 1028ae3fb6d3SFlorian Westphal hlist_for_each_entry_rcu(x, net->xfrm.state_byspi + h, byspi) { 1029edcd5821SDavid S. Miller if (x->props.family != family || 1030edcd5821SDavid S. Miller x->id.spi != spi || 10311802571bSWei Yongjun x->id.proto != proto || 103270e94e66SYOSHIFUJI Hideaki / 吉藤英明 !xfrm_addr_equal(&x->id.daddr, daddr, family)) 1033edcd5821SDavid S. Miller continue; 1034edcd5821SDavid S. Miller 10353d6acfa7SJamal Hadi Salim if ((mark & x->mark.m) != x->mark.v) 10363d6acfa7SJamal Hadi Salim continue; 103702efdff7SFlorian Westphal if (!xfrm_state_hold_rcu(x)) 103802efdff7SFlorian Westphal continue; 1039edcd5821SDavid S. Miller return x; 1040edcd5821SDavid S. Miller } 1041edcd5821SDavid S. Miller 1042edcd5821SDavid S. Miller return NULL; 1043edcd5821SDavid S. Miller } 1044edcd5821SDavid S. Miller 10459aa60088SDavid S. Miller static struct xfrm_state *__xfrm_state_lookup_byaddr(struct net *net, u32 mark, 10469aa60088SDavid S. Miller const xfrm_address_t *daddr, 10479aa60088SDavid S. Miller const xfrm_address_t *saddr, 10489aa60088SDavid S. Miller u8 proto, unsigned short family) 1049edcd5821SDavid S. Miller { 1050221df1edSAlexey Dobriyan unsigned int h = xfrm_src_hash(net, daddr, saddr, family); 1051edcd5821SDavid S. Miller struct xfrm_state *x; 1052edcd5821SDavid S. Miller 1053ae3fb6d3SFlorian Westphal hlist_for_each_entry_rcu(x, net->xfrm.state_bysrc + h, bysrc) { 1054edcd5821SDavid S. Miller if (x->props.family != family || 10551802571bSWei Yongjun x->id.proto != proto || 105670e94e66SYOSHIFUJI Hideaki / 吉藤英明 !xfrm_addr_equal(&x->id.daddr, daddr, family) || 105770e94e66SYOSHIFUJI Hideaki / 吉藤英明 !xfrm_addr_equal(&x->props.saddr, saddr, family)) 1058edcd5821SDavid S. Miller continue; 1059edcd5821SDavid S. Miller 10603d6acfa7SJamal Hadi Salim if ((mark & x->mark.m) != x->mark.v) 10613d6acfa7SJamal Hadi Salim continue; 106202efdff7SFlorian Westphal if (!xfrm_state_hold_rcu(x)) 106302efdff7SFlorian Westphal continue; 1064edcd5821SDavid S. Miller return x; 1065edcd5821SDavid S. Miller } 1066edcd5821SDavid S. Miller 1067edcd5821SDavid S. Miller return NULL; 1068edcd5821SDavid S. Miller } 1069edcd5821SDavid S. Miller 1070edcd5821SDavid S. Miller static inline struct xfrm_state * 1071edcd5821SDavid S. Miller __xfrm_state_locate(struct xfrm_state *x, int use_spi, int family) 1072edcd5821SDavid S. Miller { 1073221df1edSAlexey Dobriyan struct net *net = xs_net(x); 1074bd55775cSJamal Hadi Salim u32 mark = x->mark.v & x->mark.m; 1075221df1edSAlexey Dobriyan 1076edcd5821SDavid S. Miller if (use_spi) 1077bd55775cSJamal Hadi Salim return __xfrm_state_lookup(net, mark, &x->id.daddr, 1078bd55775cSJamal Hadi Salim x->id.spi, x->id.proto, family); 1079edcd5821SDavid S. Miller else 1080bd55775cSJamal Hadi Salim return __xfrm_state_lookup_byaddr(net, mark, 1081bd55775cSJamal Hadi Salim &x->id.daddr, 1082edcd5821SDavid S. Miller &x->props.saddr, 1083edcd5821SDavid S. Miller x->id.proto, family); 1084edcd5821SDavid S. Miller } 1085edcd5821SDavid S. Miller 108698806f75SAlexey Dobriyan static void xfrm_hash_grow_check(struct net *net, int have_hash_collision) 10872fab22f2SPatrick McHardy { 10882fab22f2SPatrick McHardy if (have_hash_collision && 108998806f75SAlexey Dobriyan (net->xfrm.state_hmask + 1) < xfrm_state_hashmax && 109098806f75SAlexey Dobriyan net->xfrm.state_num > net->xfrm.state_hmask) 109198806f75SAlexey Dobriyan schedule_work(&net->xfrm.state_hash_work); 10922fab22f2SPatrick McHardy } 10932fab22f2SPatrick McHardy 109408ec9af1SDavid S. Miller static void xfrm_state_look_at(struct xfrm_policy *pol, struct xfrm_state *x, 10954a08ab0fSDavid S. Miller const struct flowi *fl, unsigned short family, 109608ec9af1SDavid S. Miller struct xfrm_state **best, int *acq_in_progress, 109708ec9af1SDavid S. Miller int *error) 109808ec9af1SDavid S. Miller { 109908ec9af1SDavid S. Miller /* Resolution logic: 110008ec9af1SDavid S. Miller * 1. There is a valid state with matching selector. Done. 110108ec9af1SDavid S. Miller * 2. Valid state with inappropriate selector. Skip. 110208ec9af1SDavid S. Miller * 110308ec9af1SDavid S. Miller * Entering area of "sysdeps". 110408ec9af1SDavid S. Miller * 110508ec9af1SDavid S. Miller * 3. If state is not valid, selector is temporary, it selects 110608ec9af1SDavid S. Miller * only session which triggered previous resolution. Key 110708ec9af1SDavid S. Miller * manager will do something to install a state with proper 110808ec9af1SDavid S. Miller * selector. 110908ec9af1SDavid S. Miller */ 111008ec9af1SDavid S. Miller if (x->km.state == XFRM_STATE_VALID) { 111108ec9af1SDavid S. Miller if ((x->sel.family && 1112e94ee171SHerbert Xu (x->sel.family != family || 1113e94ee171SHerbert Xu !xfrm_selector_match(&x->sel, fl, family))) || 11143df98d79SPaul Moore !security_xfrm_state_pol_flow_match(x, pol, 11153df98d79SPaul Moore &fl->u.__fl_common)) 111608ec9af1SDavid S. Miller return; 111708ec9af1SDavid S. Miller 111808ec9af1SDavid S. Miller if (!*best || 111908ec9af1SDavid S. Miller (*best)->km.dying > x->km.dying || 112008ec9af1SDavid S. Miller ((*best)->km.dying == x->km.dying && 112108ec9af1SDavid S. Miller (*best)->curlft.add_time < x->curlft.add_time)) 112208ec9af1SDavid S. Miller *best = x; 112308ec9af1SDavid S. Miller } else if (x->km.state == XFRM_STATE_ACQ) { 112408ec9af1SDavid S. Miller *acq_in_progress = 1; 112508ec9af1SDavid S. Miller } else if (x->km.state == XFRM_STATE_ERROR || 112608ec9af1SDavid S. Miller x->km.state == XFRM_STATE_EXPIRED) { 1127e94ee171SHerbert Xu if ((!x->sel.family || 1128e94ee171SHerbert Xu (x->sel.family == family && 1129e94ee171SHerbert Xu xfrm_selector_match(&x->sel, fl, family))) && 11303df98d79SPaul Moore security_xfrm_state_pol_flow_match(x, pol, 11313df98d79SPaul Moore &fl->u.__fl_common)) 113208ec9af1SDavid S. Miller *error = -ESRCH; 113308ec9af1SDavid S. Miller } 113408ec9af1SDavid S. Miller } 113508ec9af1SDavid S. Miller 11361da177e4SLinus Torvalds struct xfrm_state * 113733765d06SDavid S. Miller xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr, 1138b520e9f6SDavid S. Miller const struct flowi *fl, struct xfrm_tmpl *tmpl, 11391da177e4SLinus Torvalds struct xfrm_policy *pol, int *err, 1140bc56b334SBenedict Wong unsigned short family, u32 if_id) 11411da177e4SLinus Torvalds { 114208ec9af1SDavid S. Miller static xfrm_address_t saddr_wildcard = { }; 11435447c5e4SAlexey Dobriyan struct net *net = xp_net(pol); 11446a783c90SNicolas Dichtel unsigned int h, h_wildcard; 114537b08e34SDavid S. Miller struct xfrm_state *x, *x0, *to_put; 11461da177e4SLinus Torvalds int acquire_in_progress = 0; 11471da177e4SLinus Torvalds int error = 0; 11481da177e4SLinus Torvalds struct xfrm_state *best = NULL; 1149bd55775cSJamal Hadi Salim u32 mark = pol->mark.v & pol->mark.m; 11508444cf71SThomas Egerer unsigned short encap_family = tmpl->encap_family; 1151b65e3d7bSFlorian Westphal unsigned int sequence; 11520f24558eSHoria Geanta struct km_event c; 11531da177e4SLinus Torvalds 115437b08e34SDavid S. Miller to_put = NULL; 115537b08e34SDavid S. Miller 1156e88add19SAhmed S. Darwish sequence = read_seqcount_begin(&net->xfrm.xfrm_state_hash_generation); 1157b65e3d7bSFlorian Westphal 1158d737a580SFlorian Westphal rcu_read_lock(); 11598444cf71SThomas Egerer h = xfrm_dst_hash(net, daddr, saddr, tmpl->reqid, encap_family); 1160ae3fb6d3SFlorian Westphal hlist_for_each_entry_rcu(x, net->xfrm.state_bydst + h, bydst) { 1161f8a70afaSLeon Romanovsky #ifdef CONFIG_XFRM_OFFLOAD 1162f8a70afaSLeon Romanovsky if (pol->xdo.type == XFRM_DEV_OFFLOAD_PACKET) { 1163f8a70afaSLeon Romanovsky if (x->xso.type != XFRM_DEV_OFFLOAD_PACKET) 1164f8a70afaSLeon Romanovsky /* HW states are in the head of list, there is 1165f8a70afaSLeon Romanovsky * no need to iterate further. 1166f8a70afaSLeon Romanovsky */ 1167f8a70afaSLeon Romanovsky break; 1168f8a70afaSLeon Romanovsky 1169f8a70afaSLeon Romanovsky /* Packet offload: both policy and SA should 1170f8a70afaSLeon Romanovsky * have same device. 1171f8a70afaSLeon Romanovsky */ 1172f8a70afaSLeon Romanovsky if (pol->xdo.dev != x->xso.dev) 1173f8a70afaSLeon Romanovsky continue; 1174f8a70afaSLeon Romanovsky } else if (x->xso.type == XFRM_DEV_OFFLOAD_PACKET) 1175f8a70afaSLeon Romanovsky /* Skip HW policy for SW lookups */ 1176f8a70afaSLeon Romanovsky continue; 1177f8a70afaSLeon Romanovsky #endif 11788444cf71SThomas Egerer if (x->props.family == encap_family && 11791da177e4SLinus Torvalds x->props.reqid == tmpl->reqid && 11803d6acfa7SJamal Hadi Salim (mark & x->mark.m) == x->mark.v && 11817e652640SSteffen Klassert x->if_id == if_id && 1182fbd9a5b4SMasahide NAKAMURA !(x->props.flags & XFRM_STATE_WILDRECV) && 11838444cf71SThomas Egerer xfrm_state_addr_check(x, daddr, saddr, encap_family) && 11841da177e4SLinus Torvalds tmpl->mode == x->props.mode && 11851da177e4SLinus Torvalds tmpl->id.proto == x->id.proto && 118608ec9af1SDavid S. Miller (tmpl->id.spi == x->id.spi || !tmpl->id.spi)) 1187e94ee171SHerbert Xu xfrm_state_look_at(pol, x, fl, family, 118808ec9af1SDavid S. Miller &best, &acquire_in_progress, &error); 11891da177e4SLinus Torvalds } 11906f115638SFan Du if (best || acquire_in_progress) 119108ec9af1SDavid S. Miller goto found; 119208ec9af1SDavid S. Miller 11938444cf71SThomas Egerer h_wildcard = xfrm_dst_hash(net, daddr, &saddr_wildcard, tmpl->reqid, encap_family); 1194ae3fb6d3SFlorian Westphal hlist_for_each_entry_rcu(x, net->xfrm.state_bydst + h_wildcard, bydst) { 1195f8a70afaSLeon Romanovsky #ifdef CONFIG_XFRM_OFFLOAD 1196f8a70afaSLeon Romanovsky if (pol->xdo.type == XFRM_DEV_OFFLOAD_PACKET) { 1197f8a70afaSLeon Romanovsky if (x->xso.type != XFRM_DEV_OFFLOAD_PACKET) 1198f8a70afaSLeon Romanovsky /* HW states are in the head of list, there is 1199f8a70afaSLeon Romanovsky * no need to iterate further. 1200f8a70afaSLeon Romanovsky */ 1201f8a70afaSLeon Romanovsky break; 1202f8a70afaSLeon Romanovsky 1203f8a70afaSLeon Romanovsky /* Packet offload: both policy and SA should 1204f8a70afaSLeon Romanovsky * have same device. 1205f8a70afaSLeon Romanovsky */ 1206f8a70afaSLeon Romanovsky if (pol->xdo.dev != x->xso.dev) 1207f8a70afaSLeon Romanovsky continue; 1208f8a70afaSLeon Romanovsky } else if (x->xso.type == XFRM_DEV_OFFLOAD_PACKET) 1209f8a70afaSLeon Romanovsky /* Skip HW policy for SW lookups */ 1210f8a70afaSLeon Romanovsky continue; 1211f8a70afaSLeon Romanovsky #endif 12128444cf71SThomas Egerer if (x->props.family == encap_family && 121308ec9af1SDavid S. Miller x->props.reqid == tmpl->reqid && 12143d6acfa7SJamal Hadi Salim (mark & x->mark.m) == x->mark.v && 12157e652640SSteffen Klassert x->if_id == if_id && 121608ec9af1SDavid S. Miller !(x->props.flags & XFRM_STATE_WILDRECV) && 1217f59bbdfaSFan Du xfrm_addr_equal(&x->id.daddr, daddr, encap_family) && 121808ec9af1SDavid S. Miller tmpl->mode == x->props.mode && 121908ec9af1SDavid S. Miller tmpl->id.proto == x->id.proto && 122008ec9af1SDavid S. Miller (tmpl->id.spi == x->id.spi || !tmpl->id.spi)) 1221e94ee171SHerbert Xu xfrm_state_look_at(pol, x, fl, family, 122208ec9af1SDavid S. Miller &best, &acquire_in_progress, &error); 12231da177e4SLinus Torvalds } 12241da177e4SLinus Torvalds 122508ec9af1SDavid S. Miller found: 12261da177e4SLinus Torvalds x = best; 12271da177e4SLinus Torvalds if (!x && !error && !acquire_in_progress) { 12285c5d281aSPatrick McHardy if (tmpl->id.spi && 1229f8a70afaSLeon Romanovsky (x0 = __xfrm_state_lookup_all(net, mark, daddr, 1230f8a70afaSLeon Romanovsky tmpl->id.spi, tmpl->id.proto, 1231f8a70afaSLeon Romanovsky encap_family, 1232f8a70afaSLeon Romanovsky &pol->xdo)) != NULL) { 123337b08e34SDavid S. Miller to_put = x0; 12341da177e4SLinus Torvalds error = -EEXIST; 12351da177e4SLinus Torvalds goto out; 12361da177e4SLinus Torvalds } 12370f24558eSHoria Geanta 12380f24558eSHoria Geanta c.net = net; 12390f24558eSHoria Geanta /* If the KMs have no listeners (yet...), avoid allocating an SA 12400f24558eSHoria Geanta * for each and every packet - garbage collection might not 12410f24558eSHoria Geanta * handle the flood. 12420f24558eSHoria Geanta */ 12430f24558eSHoria Geanta if (!km_is_alive(&c)) { 12440f24558eSHoria Geanta error = -ESRCH; 12450f24558eSHoria Geanta goto out; 12460f24558eSHoria Geanta } 12470f24558eSHoria Geanta 12485447c5e4SAlexey Dobriyan x = xfrm_state_alloc(net); 12491da177e4SLinus Torvalds if (x == NULL) { 12501da177e4SLinus Torvalds error = -ENOMEM; 12511da177e4SLinus Torvalds goto out; 12521da177e4SLinus Torvalds } 12538444cf71SThomas Egerer /* Initialize temporary state matching only 12541da177e4SLinus Torvalds * to current session. */ 12558444cf71SThomas Egerer xfrm_init_tempstate(x, fl, tmpl, daddr, saddr, family); 1256bd55775cSJamal Hadi Salim memcpy(&x->mark, &pol->mark, sizeof(x->mark)); 12577e652640SSteffen Klassert x->if_id = if_id; 12581da177e4SLinus Torvalds 12591d28f42cSDavid S. Miller error = security_xfrm_state_alloc_acquire(x, pol->security, fl->flowi_secid); 1260e0d1caa7SVenkat Yekkirala if (error) { 1261e0d1caa7SVenkat Yekkirala x->km.state = XFRM_STATE_DEAD; 126237b08e34SDavid S. Miller to_put = x; 1263e0d1caa7SVenkat Yekkirala x = NULL; 1264e0d1caa7SVenkat Yekkirala goto out; 1265e0d1caa7SVenkat Yekkirala } 1266f8a70afaSLeon Romanovsky #ifdef CONFIG_XFRM_OFFLOAD 1267f8a70afaSLeon Romanovsky if (pol->xdo.type == XFRM_DEV_OFFLOAD_PACKET) { 1268f8a70afaSLeon Romanovsky struct xfrm_dev_offload *xdo = &pol->xdo; 1269f8a70afaSLeon Romanovsky struct xfrm_dev_offload *xso = &x->xso; 1270e0d1caa7SVenkat Yekkirala 1271f8a70afaSLeon Romanovsky xso->type = XFRM_DEV_OFFLOAD_PACKET; 1272f8a70afaSLeon Romanovsky xso->dir = xdo->dir; 1273f8a70afaSLeon Romanovsky xso->dev = xdo->dev; 1274f8a70afaSLeon Romanovsky xso->real_dev = xdo->real_dev; 1275f8a70afaSLeon Romanovsky netdev_tracker_alloc(xso->dev, &xso->dev_tracker, 1276f8a70afaSLeon Romanovsky GFP_ATOMIC); 1277*7681a4f5SLeon Romanovsky error = xso->dev->xfrmdev_ops->xdo_dev_state_add(x, NULL); 1278f8a70afaSLeon Romanovsky if (error) { 1279f8a70afaSLeon Romanovsky xso->dir = 0; 1280f8a70afaSLeon Romanovsky netdev_put(xso->dev, &xso->dev_tracker); 1281f8a70afaSLeon Romanovsky xso->dev = NULL; 1282f8a70afaSLeon Romanovsky xso->real_dev = NULL; 1283f8a70afaSLeon Romanovsky xso->type = XFRM_DEV_OFFLOAD_UNSPECIFIED; 1284f8a70afaSLeon Romanovsky x->km.state = XFRM_STATE_DEAD; 1285f8a70afaSLeon Romanovsky to_put = x; 1286f8a70afaSLeon Romanovsky x = NULL; 1287f8a70afaSLeon Romanovsky goto out; 1288f8a70afaSLeon Romanovsky } 1289f8a70afaSLeon Romanovsky } 1290f8a70afaSLeon Romanovsky #endif 12911da177e4SLinus Torvalds if (km_query(x, tmpl, pol) == 0) { 1292d737a580SFlorian Westphal spin_lock_bh(&net->xfrm.xfrm_state_lock); 12931da177e4SLinus Torvalds x->km.state = XFRM_STATE_ACQ; 12945447c5e4SAlexey Dobriyan list_add(&x->km.all, &net->xfrm.state_all); 12953c611d40SLeon Romanovsky XFRM_STATE_INSERT(bydst, &x->bydst, 12963c611d40SLeon Romanovsky net->xfrm.state_bydst + h, 12973c611d40SLeon Romanovsky x->xso.type); 12988444cf71SThomas Egerer h = xfrm_src_hash(net, daddr, saddr, encap_family); 12993c611d40SLeon Romanovsky XFRM_STATE_INSERT(bysrc, &x->bysrc, 13003c611d40SLeon Romanovsky net->xfrm.state_bysrc + h, 13013c611d40SLeon Romanovsky x->xso.type); 13021da177e4SLinus Torvalds if (x->id.spi) { 13038444cf71SThomas Egerer h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, encap_family); 13043c611d40SLeon Romanovsky XFRM_STATE_INSERT(byspi, &x->byspi, 13053c611d40SLeon Romanovsky net->xfrm.state_byspi + h, 13063c611d40SLeon Romanovsky x->xso.type); 13071da177e4SLinus Torvalds } 1308fe9f1d87SSabrina Dubroca if (x->km.seq) { 1309fe9f1d87SSabrina Dubroca h = xfrm_seq_hash(net, x->km.seq); 13103c611d40SLeon Romanovsky XFRM_STATE_INSERT(byseq, &x->byseq, 13113c611d40SLeon Romanovsky net->xfrm.state_byseq + h, 13123c611d40SLeon Romanovsky x->xso.type); 1313fe9f1d87SSabrina Dubroca } 1314b27aeadbSAlexey Dobriyan x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires; 1315671422b2SThomas Gleixner hrtimer_start(&x->mtimer, 1316671422b2SThomas Gleixner ktime_set(net->xfrm.sysctl_acq_expires, 0), 1317671422b2SThomas Gleixner HRTIMER_MODE_REL_SOFT); 13185447c5e4SAlexey Dobriyan net->xfrm.state_num++; 13195447c5e4SAlexey Dobriyan xfrm_hash_grow_check(net, x->bydst.next != NULL); 1320d737a580SFlorian Westphal spin_unlock_bh(&net->xfrm.xfrm_state_lock); 13211da177e4SLinus Torvalds } else { 1322f8a70afaSLeon Romanovsky #ifdef CONFIG_XFRM_OFFLOAD 1323f8a70afaSLeon Romanovsky struct xfrm_dev_offload *xso = &x->xso; 1324f8a70afaSLeon Romanovsky 1325f8a70afaSLeon Romanovsky if (xso->type == XFRM_DEV_OFFLOAD_PACKET) { 1326f8a70afaSLeon Romanovsky xso->dev->xfrmdev_ops->xdo_dev_state_delete(x); 1327f8a70afaSLeon Romanovsky xso->dir = 0; 1328f8a70afaSLeon Romanovsky netdev_put(xso->dev, &xso->dev_tracker); 1329f8a70afaSLeon Romanovsky xso->dev = NULL; 1330f8a70afaSLeon Romanovsky xso->real_dev = NULL; 1331f8a70afaSLeon Romanovsky xso->type = XFRM_DEV_OFFLOAD_UNSPECIFIED; 1332f8a70afaSLeon Romanovsky } 1333f8a70afaSLeon Romanovsky #endif 13341da177e4SLinus Torvalds x->km.state = XFRM_STATE_DEAD; 133537b08e34SDavid S. Miller to_put = x; 13361da177e4SLinus Torvalds x = NULL; 13371da177e4SLinus Torvalds error = -ESRCH; 13381da177e4SLinus Torvalds } 13391da177e4SLinus Torvalds } 13401da177e4SLinus Torvalds out: 134102efdff7SFlorian Westphal if (x) { 134202efdff7SFlorian Westphal if (!xfrm_state_hold_rcu(x)) { 134302efdff7SFlorian Westphal *err = -EAGAIN; 134402efdff7SFlorian Westphal x = NULL; 134502efdff7SFlorian Westphal } 134602efdff7SFlorian Westphal } else { 13471da177e4SLinus Torvalds *err = acquire_in_progress ? -EAGAIN : error; 134802efdff7SFlorian Westphal } 1349d737a580SFlorian Westphal rcu_read_unlock(); 135037b08e34SDavid S. Miller if (to_put) 135137b08e34SDavid S. Miller xfrm_state_put(to_put); 1352b65e3d7bSFlorian Westphal 1353e88add19SAhmed S. Darwish if (read_seqcount_retry(&net->xfrm.xfrm_state_hash_generation, sequence)) { 1354b65e3d7bSFlorian Westphal *err = -EAGAIN; 1355b65e3d7bSFlorian Westphal if (x) { 1356b65e3d7bSFlorian Westphal xfrm_state_put(x); 1357b65e3d7bSFlorian Westphal x = NULL; 1358b65e3d7bSFlorian Westphal } 1359b65e3d7bSFlorian Westphal } 1360b65e3d7bSFlorian Westphal 13611da177e4SLinus Torvalds return x; 13621da177e4SLinus Torvalds } 13631da177e4SLinus Torvalds 1364628529b6SJamal Hadi Salim struct xfrm_state * 13657e652640SSteffen Klassert xfrm_stateonly_find(struct net *net, u32 mark, u32 if_id, 13665447c5e4SAlexey Dobriyan xfrm_address_t *daddr, xfrm_address_t *saddr, 1367628529b6SJamal Hadi Salim unsigned short family, u8 mode, u8 proto, u32 reqid) 1368628529b6SJamal Hadi Salim { 13694bda4f25SPavel Emelyanov unsigned int h; 1370628529b6SJamal Hadi Salim struct xfrm_state *rx = NULL, *x = NULL; 1371628529b6SJamal Hadi Salim 13724ae770bfSFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 13735447c5e4SAlexey Dobriyan h = xfrm_dst_hash(net, daddr, saddr, reqid, family); 1374b67bfe0dSSasha Levin hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) { 1375628529b6SJamal Hadi Salim if (x->props.family == family && 1376628529b6SJamal Hadi Salim x->props.reqid == reqid && 13773d6acfa7SJamal Hadi Salim (mark & x->mark.m) == x->mark.v && 13787e652640SSteffen Klassert x->if_id == if_id && 1379628529b6SJamal Hadi Salim !(x->props.flags & XFRM_STATE_WILDRECV) && 1380628529b6SJamal Hadi Salim xfrm_state_addr_check(x, daddr, saddr, family) && 1381628529b6SJamal Hadi Salim mode == x->props.mode && 1382628529b6SJamal Hadi Salim proto == x->id.proto && 1383628529b6SJamal Hadi Salim x->km.state == XFRM_STATE_VALID) { 1384628529b6SJamal Hadi Salim rx = x; 1385628529b6SJamal Hadi Salim break; 1386628529b6SJamal Hadi Salim } 1387628529b6SJamal Hadi Salim } 1388628529b6SJamal Hadi Salim 1389628529b6SJamal Hadi Salim if (rx) 1390628529b6SJamal Hadi Salim xfrm_state_hold(rx); 13914ae770bfSFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 1392628529b6SJamal Hadi Salim 1393628529b6SJamal Hadi Salim 1394628529b6SJamal Hadi Salim return rx; 1395628529b6SJamal Hadi Salim } 1396628529b6SJamal Hadi Salim EXPORT_SYMBOL(xfrm_stateonly_find); 1397628529b6SJamal Hadi Salim 1398c454997eSFan Du struct xfrm_state *xfrm_state_lookup_byspi(struct net *net, __be32 spi, 1399c454997eSFan Du unsigned short family) 1400c454997eSFan Du { 1401c454997eSFan Du struct xfrm_state *x; 1402c454997eSFan Du struct xfrm_state_walk *w; 1403c454997eSFan Du 1404c454997eSFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 1405c454997eSFan Du list_for_each_entry(w, &net->xfrm.state_all, all) { 1406c454997eSFan Du x = container_of(w, struct xfrm_state, km); 1407c454997eSFan Du if (x->props.family != family || 1408c454997eSFan Du x->id.spi != spi) 1409c454997eSFan Du continue; 1410c454997eSFan Du 1411c454997eSFan Du xfrm_state_hold(x); 1412bdddbf69SLi RongQing spin_unlock_bh(&net->xfrm.xfrm_state_lock); 1413c454997eSFan Du return x; 1414c454997eSFan Du } 1415c454997eSFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 1416c454997eSFan Du return NULL; 1417c454997eSFan Du } 1418c454997eSFan Du EXPORT_SYMBOL(xfrm_state_lookup_byspi); 1419c454997eSFan Du 14201da177e4SLinus Torvalds static void __xfrm_state_insert(struct xfrm_state *x) 14211da177e4SLinus Torvalds { 142298806f75SAlexey Dobriyan struct net *net = xs_net(x); 1423a624c108SDavid S. Miller unsigned int h; 14241da177e4SLinus Torvalds 142598806f75SAlexey Dobriyan list_add(&x->km.all, &net->xfrm.state_all); 14264c563f76STimo Teras 142798806f75SAlexey Dobriyan h = xfrm_dst_hash(net, &x->id.daddr, &x->props.saddr, 1428c1969f29SDavid S. Miller x->props.reqid, x->props.family); 14293c611d40SLeon Romanovsky XFRM_STATE_INSERT(bydst, &x->bydst, net->xfrm.state_bydst + h, 14303c611d40SLeon Romanovsky x->xso.type); 14311da177e4SLinus Torvalds 143298806f75SAlexey Dobriyan h = xfrm_src_hash(net, &x->id.daddr, &x->props.saddr, x->props.family); 14333c611d40SLeon Romanovsky XFRM_STATE_INSERT(bysrc, &x->bysrc, net->xfrm.state_bysrc + h, 14343c611d40SLeon Romanovsky x->xso.type); 14356c44e6b7SMasahide NAKAMURA 14367b4dc360SMasahide NAKAMURA if (x->id.spi) { 143798806f75SAlexey Dobriyan h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, 14386c44e6b7SMasahide NAKAMURA x->props.family); 14391da177e4SLinus Torvalds 14403c611d40SLeon Romanovsky XFRM_STATE_INSERT(byspi, &x->byspi, net->xfrm.state_byspi + h, 14413c611d40SLeon Romanovsky x->xso.type); 14426c44e6b7SMasahide NAKAMURA } 14431da177e4SLinus Torvalds 1444fe9f1d87SSabrina Dubroca if (x->km.seq) { 1445fe9f1d87SSabrina Dubroca h = xfrm_seq_hash(net, x->km.seq); 1446fe9f1d87SSabrina Dubroca 14473c611d40SLeon Romanovsky XFRM_STATE_INSERT(byseq, &x->byseq, net->xfrm.state_byseq + h, 14483c611d40SLeon Romanovsky x->xso.type); 1449fe9f1d87SSabrina Dubroca } 1450fe9f1d87SSabrina Dubroca 1451671422b2SThomas Gleixner hrtimer_start(&x->mtimer, ktime_set(1, 0), HRTIMER_MODE_REL_SOFT); 1452a47f0ce0SDavid S. Miller if (x->replay_maxage) 1453a47f0ce0SDavid S. Miller mod_timer(&x->rtimer, jiffies + x->replay_maxage); 1454f8cd5488SJamal Hadi Salim 145598806f75SAlexey Dobriyan net->xfrm.state_num++; 1456f034b5d4SDavid S. Miller 145798806f75SAlexey Dobriyan xfrm_hash_grow_check(net, x->bydst.next != NULL); 14581da177e4SLinus Torvalds } 14591da177e4SLinus Torvalds 1460283bc9f3SFan Du /* net->xfrm.xfrm_state_lock is held */ 1461c7f5ea3aSDavid S. Miller static void __xfrm_state_bump_genids(struct xfrm_state *xnew) 1462c7f5ea3aSDavid S. Miller { 146398806f75SAlexey Dobriyan struct net *net = xs_net(xnew); 1464c7f5ea3aSDavid S. Miller unsigned short family = xnew->props.family; 1465c7f5ea3aSDavid S. Miller u32 reqid = xnew->props.reqid; 1466c7f5ea3aSDavid S. Miller struct xfrm_state *x; 1467c7f5ea3aSDavid S. Miller unsigned int h; 14683d6acfa7SJamal Hadi Salim u32 mark = xnew->mark.v & xnew->mark.m; 14697e652640SSteffen Klassert u32 if_id = xnew->if_id; 1470c7f5ea3aSDavid S. Miller 147198806f75SAlexey Dobriyan h = xfrm_dst_hash(net, &xnew->id.daddr, &xnew->props.saddr, reqid, family); 1472b67bfe0dSSasha Levin hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) { 1473c7f5ea3aSDavid S. Miller if (x->props.family == family && 1474c7f5ea3aSDavid S. Miller x->props.reqid == reqid && 14757e652640SSteffen Klassert x->if_id == if_id && 14763d6acfa7SJamal Hadi Salim (mark & x->mark.m) == x->mark.v && 147770e94e66SYOSHIFUJI Hideaki / 吉藤英明 xfrm_addr_equal(&x->id.daddr, &xnew->id.daddr, family) && 147870e94e66SYOSHIFUJI Hideaki / 吉藤英明 xfrm_addr_equal(&x->props.saddr, &xnew->props.saddr, family)) 147934996cb9SHerbert Xu x->genid++; 1480c7f5ea3aSDavid S. Miller } 1481c7f5ea3aSDavid S. Miller } 1482c7f5ea3aSDavid S. Miller 14831da177e4SLinus Torvalds void xfrm_state_insert(struct xfrm_state *x) 14841da177e4SLinus Torvalds { 1485283bc9f3SFan Du struct net *net = xs_net(x); 1486283bc9f3SFan Du 1487283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 1488c7f5ea3aSDavid S. Miller __xfrm_state_bump_genids(x); 14891da177e4SLinus Torvalds __xfrm_state_insert(x); 1490283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 14911da177e4SLinus Torvalds } 14921da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_insert); 14931da177e4SLinus Torvalds 1494283bc9f3SFan Du /* net->xfrm.xfrm_state_lock is held */ 1495e473fcb4SMathias Krause static struct xfrm_state *__find_acq_core(struct net *net, 1496e473fcb4SMathias Krause const struct xfrm_mark *m, 1497a70486f0SDavid S. Miller unsigned short family, u8 mode, 14987e652640SSteffen Klassert u32 reqid, u32 if_id, u8 proto, 1499a70486f0SDavid S. Miller const xfrm_address_t *daddr, 1500e473fcb4SMathias Krause const xfrm_address_t *saddr, 1501e473fcb4SMathias Krause int create) 15022770834cSDavid S. Miller { 15035447c5e4SAlexey Dobriyan unsigned int h = xfrm_dst_hash(net, daddr, saddr, reqid, family); 15042770834cSDavid S. Miller struct xfrm_state *x; 15053d6acfa7SJamal Hadi Salim u32 mark = m->v & m->m; 15062770834cSDavid S. Miller 1507b67bfe0dSSasha Levin hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) { 15082770834cSDavid S. Miller if (x->props.reqid != reqid || 15092770834cSDavid S. Miller x->props.mode != mode || 15102770834cSDavid S. Miller x->props.family != family || 15112770834cSDavid S. Miller x->km.state != XFRM_STATE_ACQ || 151275e252d9SJoy Latten x->id.spi != 0 || 15131802571bSWei Yongjun x->id.proto != proto || 15143d6acfa7SJamal Hadi Salim (mark & x->mark.m) != x->mark.v || 151570e94e66SYOSHIFUJI Hideaki / 吉藤英明 !xfrm_addr_equal(&x->id.daddr, daddr, family) || 151670e94e66SYOSHIFUJI Hideaki / 吉藤英明 !xfrm_addr_equal(&x->props.saddr, saddr, family)) 15172770834cSDavid S. Miller continue; 15182770834cSDavid S. Miller 15192770834cSDavid S. Miller xfrm_state_hold(x); 15202770834cSDavid S. Miller return x; 15212770834cSDavid S. Miller } 15222770834cSDavid S. Miller 15232770834cSDavid S. Miller if (!create) 15242770834cSDavid S. Miller return NULL; 15252770834cSDavid S. Miller 15265447c5e4SAlexey Dobriyan x = xfrm_state_alloc(net); 15272770834cSDavid S. Miller if (likely(x)) { 15282770834cSDavid S. Miller switch (family) { 15292770834cSDavid S. Miller case AF_INET: 15302770834cSDavid S. Miller x->sel.daddr.a4 = daddr->a4; 15312770834cSDavid S. Miller x->sel.saddr.a4 = saddr->a4; 15322770834cSDavid S. Miller x->sel.prefixlen_d = 32; 15332770834cSDavid S. Miller x->sel.prefixlen_s = 32; 15342770834cSDavid S. Miller x->props.saddr.a4 = saddr->a4; 15352770834cSDavid S. Miller x->id.daddr.a4 = daddr->a4; 15362770834cSDavid S. Miller break; 15372770834cSDavid S. Miller 15382770834cSDavid S. Miller case AF_INET6: 153915e318bdSJiri Benc x->sel.daddr.in6 = daddr->in6; 154015e318bdSJiri Benc x->sel.saddr.in6 = saddr->in6; 15412770834cSDavid S. Miller x->sel.prefixlen_d = 128; 15422770834cSDavid S. Miller x->sel.prefixlen_s = 128; 154315e318bdSJiri Benc x->props.saddr.in6 = saddr->in6; 154415e318bdSJiri Benc x->id.daddr.in6 = daddr->in6; 15452770834cSDavid S. Miller break; 15463ff50b79SStephen Hemminger } 15472770834cSDavid S. Miller 15482770834cSDavid S. Miller x->km.state = XFRM_STATE_ACQ; 15492770834cSDavid S. Miller x->id.proto = proto; 15502770834cSDavid S. Miller x->props.family = family; 15512770834cSDavid S. Miller x->props.mode = mode; 15522770834cSDavid S. Miller x->props.reqid = reqid; 15537e652640SSteffen Klassert x->if_id = if_id; 1554bd55775cSJamal Hadi Salim x->mark.v = m->v; 1555bd55775cSJamal Hadi Salim x->mark.m = m->m; 1556b27aeadbSAlexey Dobriyan x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires; 15572770834cSDavid S. Miller xfrm_state_hold(x); 1558671422b2SThomas Gleixner hrtimer_start(&x->mtimer, 1559671422b2SThomas Gleixner ktime_set(net->xfrm.sysctl_acq_expires, 0), 1560671422b2SThomas Gleixner HRTIMER_MODE_REL_SOFT); 15615447c5e4SAlexey Dobriyan list_add(&x->km.all, &net->xfrm.state_all); 15623c611d40SLeon Romanovsky XFRM_STATE_INSERT(bydst, &x->bydst, net->xfrm.state_bydst + h, 15633c611d40SLeon Romanovsky x->xso.type); 15645447c5e4SAlexey Dobriyan h = xfrm_src_hash(net, daddr, saddr, family); 15653c611d40SLeon Romanovsky XFRM_STATE_INSERT(bysrc, &x->bysrc, net->xfrm.state_bysrc + h, 15663c611d40SLeon Romanovsky x->xso.type); 1567918049f0SDavid S. Miller 15685447c5e4SAlexey Dobriyan net->xfrm.state_num++; 1569918049f0SDavid S. Miller 15705447c5e4SAlexey Dobriyan xfrm_hash_grow_check(net, x->bydst.next != NULL); 15712770834cSDavid S. Miller } 15722770834cSDavid S. Miller 15732770834cSDavid S. Miller return x; 15742770834cSDavid S. Miller } 15752770834cSDavid S. Miller 1576bd55775cSJamal Hadi Salim static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq); 15771da177e4SLinus Torvalds 15781da177e4SLinus Torvalds int xfrm_state_add(struct xfrm_state *x) 15791da177e4SLinus Torvalds { 15805447c5e4SAlexey Dobriyan struct net *net = xs_net(x); 158137b08e34SDavid S. Miller struct xfrm_state *x1, *to_put; 15821da177e4SLinus Torvalds int family; 15831da177e4SLinus Torvalds int err; 1584bd55775cSJamal Hadi Salim u32 mark = x->mark.v & x->mark.m; 1585eb2971b6SMasahide NAKAMURA int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY); 15861da177e4SLinus Torvalds 15871da177e4SLinus Torvalds family = x->props.family; 15881da177e4SLinus Torvalds 158937b08e34SDavid S. Miller to_put = NULL; 159037b08e34SDavid S. Miller 1591283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 15921da177e4SLinus Torvalds 1593edcd5821SDavid S. Miller x1 = __xfrm_state_locate(x, use_spi, family); 15941da177e4SLinus Torvalds if (x1) { 159537b08e34SDavid S. Miller to_put = x1; 15961da177e4SLinus Torvalds x1 = NULL; 15971da177e4SLinus Torvalds err = -EEXIST; 15981da177e4SLinus Torvalds goto out; 15991da177e4SLinus Torvalds } 16001da177e4SLinus Torvalds 1601eb2971b6SMasahide NAKAMURA if (use_spi && x->km.seq) { 1602bd55775cSJamal Hadi Salim x1 = __xfrm_find_acq_byseq(net, mark, x->km.seq); 160375e252d9SJoy Latten if (x1 && ((x1->id.proto != x->id.proto) || 160470e94e66SYOSHIFUJI Hideaki / 吉藤英明 !xfrm_addr_equal(&x1->id.daddr, &x->id.daddr, family))) { 160537b08e34SDavid S. Miller to_put = x1; 16061da177e4SLinus Torvalds x1 = NULL; 16071da177e4SLinus Torvalds } 16081da177e4SLinus Torvalds } 16091da177e4SLinus Torvalds 1610eb2971b6SMasahide NAKAMURA if (use_spi && !x1) 1611bd55775cSJamal Hadi Salim x1 = __find_acq_core(net, &x->mark, family, x->props.mode, 16127e652640SSteffen Klassert x->props.reqid, x->if_id, x->id.proto, 16131da177e4SLinus Torvalds &x->id.daddr, &x->props.saddr, 0); 16141da177e4SLinus Torvalds 1615c7f5ea3aSDavid S. Miller __xfrm_state_bump_genids(x); 16161da177e4SLinus Torvalds __xfrm_state_insert(x); 16171da177e4SLinus Torvalds err = 0; 16181da177e4SLinus Torvalds 16191da177e4SLinus Torvalds out: 1620283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 16211da177e4SLinus Torvalds 16221da177e4SLinus Torvalds if (x1) { 16231da177e4SLinus Torvalds xfrm_state_delete(x1); 16241da177e4SLinus Torvalds xfrm_state_put(x1); 16251da177e4SLinus Torvalds } 16261da177e4SLinus Torvalds 162737b08e34SDavid S. Miller if (to_put) 162837b08e34SDavid S. Miller xfrm_state_put(to_put); 162937b08e34SDavid S. Miller 16301da177e4SLinus Torvalds return err; 16311da177e4SLinus Torvalds } 16321da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_add); 16331da177e4SLinus Torvalds 163480c9abaaSShinta Sugimoto #ifdef CONFIG_XFRM_MIGRATE 16357aa05d30SAntony Antony static inline int clone_security(struct xfrm_state *x, struct xfrm_sec_ctx *security) 16367aa05d30SAntony Antony { 16377aa05d30SAntony Antony struct xfrm_user_sec_ctx *uctx; 16387aa05d30SAntony Antony int size = sizeof(*uctx) + security->ctx_len; 16397aa05d30SAntony Antony int err; 16407aa05d30SAntony Antony 16417aa05d30SAntony Antony uctx = kmalloc(size, GFP_KERNEL); 16427aa05d30SAntony Antony if (!uctx) 16437aa05d30SAntony Antony return -ENOMEM; 16447aa05d30SAntony Antony 16457aa05d30SAntony Antony uctx->exttype = XFRMA_SEC_CTX; 16467aa05d30SAntony Antony uctx->len = size; 16477aa05d30SAntony Antony uctx->ctx_doi = security->ctx_doi; 16487aa05d30SAntony Antony uctx->ctx_alg = security->ctx_alg; 16497aa05d30SAntony Antony uctx->ctx_len = security->ctx_len; 16507aa05d30SAntony Antony memcpy(uctx + 1, security->ctx_str, security->ctx_len); 16517aa05d30SAntony Antony err = security_xfrm_state_alloc(x, uctx); 16527aa05d30SAntony Antony kfree(uctx); 16537aa05d30SAntony Antony if (err) 16547aa05d30SAntony Antony return err; 16557aa05d30SAntony Antony 16567aa05d30SAntony Antony return 0; 16577aa05d30SAntony Antony } 16587aa05d30SAntony Antony 16594ab47d47SAntony Antony static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, 16604ab47d47SAntony Antony struct xfrm_encap_tmpl *encap) 166180c9abaaSShinta Sugimoto { 166298806f75SAlexey Dobriyan struct net *net = xs_net(orig); 166398806f75SAlexey Dobriyan struct xfrm_state *x = xfrm_state_alloc(net); 166480c9abaaSShinta Sugimoto if (!x) 1665553f9118SHerbert Xu goto out; 166680c9abaaSShinta Sugimoto 166780c9abaaSShinta Sugimoto memcpy(&x->id, &orig->id, sizeof(x->id)); 166880c9abaaSShinta Sugimoto memcpy(&x->sel, &orig->sel, sizeof(x->sel)); 166980c9abaaSShinta Sugimoto memcpy(&x->lft, &orig->lft, sizeof(x->lft)); 167080c9abaaSShinta Sugimoto x->props.mode = orig->props.mode; 167180c9abaaSShinta Sugimoto x->props.replay_window = orig->props.replay_window; 167280c9abaaSShinta Sugimoto x->props.reqid = orig->props.reqid; 167380c9abaaSShinta Sugimoto x->props.family = orig->props.family; 167480c9abaaSShinta Sugimoto x->props.saddr = orig->props.saddr; 167580c9abaaSShinta Sugimoto 167680c9abaaSShinta Sugimoto if (orig->aalg) { 16774447bb33SMartin Willi x->aalg = xfrm_algo_auth_clone(orig->aalg); 167880c9abaaSShinta Sugimoto if (!x->aalg) 167980c9abaaSShinta Sugimoto goto error; 168080c9abaaSShinta Sugimoto } 168180c9abaaSShinta Sugimoto x->props.aalgo = orig->props.aalgo; 168280c9abaaSShinta Sugimoto 1683ee5c2317SSteffen Klassert if (orig->aead) { 1684ee5c2317SSteffen Klassert x->aead = xfrm_algo_aead_clone(orig->aead); 168575bf50f4SAntony Antony x->geniv = orig->geniv; 1686ee5c2317SSteffen Klassert if (!x->aead) 1687ee5c2317SSteffen Klassert goto error; 1688ee5c2317SSteffen Klassert } 168980c9abaaSShinta Sugimoto if (orig->ealg) { 169080c9abaaSShinta Sugimoto x->ealg = xfrm_algo_clone(orig->ealg); 169180c9abaaSShinta Sugimoto if (!x->ealg) 169280c9abaaSShinta Sugimoto goto error; 169380c9abaaSShinta Sugimoto } 169480c9abaaSShinta Sugimoto x->props.ealgo = orig->props.ealgo; 169580c9abaaSShinta Sugimoto 169680c9abaaSShinta Sugimoto if (orig->calg) { 169780c9abaaSShinta Sugimoto x->calg = xfrm_algo_clone(orig->calg); 169880c9abaaSShinta Sugimoto if (!x->calg) 169980c9abaaSShinta Sugimoto goto error; 170080c9abaaSShinta Sugimoto } 170180c9abaaSShinta Sugimoto x->props.calgo = orig->props.calgo; 170280c9abaaSShinta Sugimoto 17034ab47d47SAntony Antony if (encap || orig->encap) { 17044ab47d47SAntony Antony if (encap) 17054ab47d47SAntony Antony x->encap = kmemdup(encap, sizeof(*x->encap), 17064ab47d47SAntony Antony GFP_KERNEL); 17074ab47d47SAntony Antony else 17084ab47d47SAntony Antony x->encap = kmemdup(orig->encap, sizeof(*x->encap), 17094ab47d47SAntony Antony GFP_KERNEL); 17104ab47d47SAntony Antony 171180c9abaaSShinta Sugimoto if (!x->encap) 171280c9abaaSShinta Sugimoto goto error; 171380c9abaaSShinta Sugimoto } 171480c9abaaSShinta Sugimoto 17157aa05d30SAntony Antony if (orig->security) 17167aa05d30SAntony Antony if (clone_security(x, orig->security)) 17177aa05d30SAntony Antony goto error; 17187aa05d30SAntony Antony 171980c9abaaSShinta Sugimoto if (orig->coaddr) { 172080c9abaaSShinta Sugimoto x->coaddr = kmemdup(orig->coaddr, sizeof(*x->coaddr), 172180c9abaaSShinta Sugimoto GFP_KERNEL); 172280c9abaaSShinta Sugimoto if (!x->coaddr) 172380c9abaaSShinta Sugimoto goto error; 172480c9abaaSShinta Sugimoto } 172580c9abaaSShinta Sugimoto 1726af2f464eSSteffen Klassert if (orig->replay_esn) { 1727cc9ab60eSSteffen Klassert if (xfrm_replay_clone(x, orig)) 1728af2f464eSSteffen Klassert goto error; 1729af2f464eSSteffen Klassert } 1730af2f464eSSteffen Klassert 1731bd55775cSJamal Hadi Salim memcpy(&x->mark, &orig->mark, sizeof(x->mark)); 1732545e5c57SAntony Antony memcpy(&x->props.smark, &orig->props.smark, sizeof(x->props.smark)); 1733bd55775cSJamal Hadi Salim 173480c9abaaSShinta Sugimoto x->props.flags = orig->props.flags; 1735a947b0a9SNicolas Dichtel x->props.extra_flags = orig->props.extra_flags; 173680c9abaaSShinta Sugimoto 17377e652640SSteffen Klassert x->if_id = orig->if_id; 1738ee5c2317SSteffen Klassert x->tfcpad = orig->tfcpad; 1739ee5c2317SSteffen Klassert x->replay_maxdiff = orig->replay_maxdiff; 1740ee5c2317SSteffen Klassert x->replay_maxage = orig->replay_maxage; 17418366685bSAntony Antony memcpy(&x->curlft, &orig->curlft, sizeof(x->curlft)); 174280c9abaaSShinta Sugimoto x->km.state = orig->km.state; 174380c9abaaSShinta Sugimoto x->km.seq = orig->km.seq; 1744a486cd23SAntony Antony x->replay = orig->replay; 1745a486cd23SAntony Antony x->preplay = orig->preplay; 17464e484b3eSAntony Antony x->mapping_maxage = orig->mapping_maxage; 17476aa811acSAntony Antony x->lastused = orig->lastused; 17484e484b3eSAntony Antony x->new_mapping = 0; 17494e484b3eSAntony Antony x->new_mapping_sport = 0; 175080c9abaaSShinta Sugimoto 175180c9abaaSShinta Sugimoto return x; 175280c9abaaSShinta Sugimoto 175380c9abaaSShinta Sugimoto error: 1754553f9118SHerbert Xu xfrm_state_put(x); 1755553f9118SHerbert Xu out: 175680c9abaaSShinta Sugimoto return NULL; 175780c9abaaSShinta Sugimoto } 175880c9abaaSShinta Sugimoto 1759c1aca308SYan Yan struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *net, 1760c1aca308SYan Yan u32 if_id) 176180c9abaaSShinta Sugimoto { 176280c9abaaSShinta Sugimoto unsigned int h; 17638c0cba22SSteffen Klassert struct xfrm_state *x = NULL; 17648c0cba22SSteffen Klassert 17658c0cba22SSteffen Klassert spin_lock_bh(&net->xfrm.xfrm_state_lock); 176680c9abaaSShinta Sugimoto 176780c9abaaSShinta Sugimoto if (m->reqid) { 1768283bc9f3SFan Du h = xfrm_dst_hash(net, &m->old_daddr, &m->old_saddr, 176980c9abaaSShinta Sugimoto m->reqid, m->old_family); 1770283bc9f3SFan Du hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) { 177180c9abaaSShinta Sugimoto if (x->props.mode != m->mode || 177280c9abaaSShinta Sugimoto x->id.proto != m->proto) 177380c9abaaSShinta Sugimoto continue; 177480c9abaaSShinta Sugimoto if (m->reqid && x->props.reqid != m->reqid) 177580c9abaaSShinta Sugimoto continue; 1776c1aca308SYan Yan if (if_id != 0 && x->if_id != if_id) 1777c1aca308SYan Yan continue; 177870e94e66SYOSHIFUJI Hideaki / 吉藤英明 if (!xfrm_addr_equal(&x->id.daddr, &m->old_daddr, 177980c9abaaSShinta Sugimoto m->old_family) || 178070e94e66SYOSHIFUJI Hideaki / 吉藤英明 !xfrm_addr_equal(&x->props.saddr, &m->old_saddr, 178180c9abaaSShinta Sugimoto m->old_family)) 178280c9abaaSShinta Sugimoto continue; 178380c9abaaSShinta Sugimoto xfrm_state_hold(x); 17848c0cba22SSteffen Klassert break; 178580c9abaaSShinta Sugimoto } 178680c9abaaSShinta Sugimoto } else { 1787283bc9f3SFan Du h = xfrm_src_hash(net, &m->old_daddr, &m->old_saddr, 178880c9abaaSShinta Sugimoto m->old_family); 1789283bc9f3SFan Du hlist_for_each_entry(x, net->xfrm.state_bysrc+h, bysrc) { 179080c9abaaSShinta Sugimoto if (x->props.mode != m->mode || 179180c9abaaSShinta Sugimoto x->id.proto != m->proto) 179280c9abaaSShinta Sugimoto continue; 1793c1aca308SYan Yan if (if_id != 0 && x->if_id != if_id) 1794c1aca308SYan Yan continue; 179570e94e66SYOSHIFUJI Hideaki / 吉藤英明 if (!xfrm_addr_equal(&x->id.daddr, &m->old_daddr, 179680c9abaaSShinta Sugimoto m->old_family) || 179770e94e66SYOSHIFUJI Hideaki / 吉藤英明 !xfrm_addr_equal(&x->props.saddr, &m->old_saddr, 179880c9abaaSShinta Sugimoto m->old_family)) 179980c9abaaSShinta Sugimoto continue; 180080c9abaaSShinta Sugimoto xfrm_state_hold(x); 18018c0cba22SSteffen Klassert break; 180280c9abaaSShinta Sugimoto } 180380c9abaaSShinta Sugimoto } 180480c9abaaSShinta Sugimoto 18058c0cba22SSteffen Klassert spin_unlock_bh(&net->xfrm.xfrm_state_lock); 18068c0cba22SSteffen Klassert 18078c0cba22SSteffen Klassert return x; 180880c9abaaSShinta Sugimoto } 180980c9abaaSShinta Sugimoto EXPORT_SYMBOL(xfrm_migrate_state_find); 181080c9abaaSShinta Sugimoto 181180c9abaaSShinta Sugimoto struct xfrm_state *xfrm_state_migrate(struct xfrm_state *x, 18124ab47d47SAntony Antony struct xfrm_migrate *m, 18134ab47d47SAntony Antony struct xfrm_encap_tmpl *encap) 181480c9abaaSShinta Sugimoto { 181580c9abaaSShinta Sugimoto struct xfrm_state *xc; 181680c9abaaSShinta Sugimoto 18174ab47d47SAntony Antony xc = xfrm_state_clone(x, encap); 181880c9abaaSShinta Sugimoto if (!xc) 181980c9abaaSShinta Sugimoto return NULL; 182080c9abaaSShinta Sugimoto 1821e03c3bbaSYan Yan xc->props.family = m->new_family; 1822e03c3bbaSYan Yan 1823e03c3bbaSYan Yan if (xfrm_init_state(xc) < 0) 1824e03c3bbaSYan Yan goto error; 1825e03c3bbaSYan Yan 182680c9abaaSShinta Sugimoto memcpy(&xc->id.daddr, &m->new_daddr, sizeof(xc->id.daddr)); 182780c9abaaSShinta Sugimoto memcpy(&xc->props.saddr, &m->new_saddr, sizeof(xc->props.saddr)); 182880c9abaaSShinta Sugimoto 182980c9abaaSShinta Sugimoto /* add state */ 183070e94e66SYOSHIFUJI Hideaki / 吉藤英明 if (xfrm_addr_equal(&x->id.daddr, &m->new_daddr, m->new_family)) { 183180c9abaaSShinta Sugimoto /* a care is needed when the destination address of the 183280c9abaaSShinta Sugimoto state is to be updated as it is a part of triplet */ 183380c9abaaSShinta Sugimoto xfrm_state_insert(xc); 183480c9abaaSShinta Sugimoto } else { 1835cc9ab60eSSteffen Klassert if (xfrm_state_add(xc) < 0) 183680c9abaaSShinta Sugimoto goto error; 183780c9abaaSShinta Sugimoto } 183880c9abaaSShinta Sugimoto 183980c9abaaSShinta Sugimoto return xc; 184080c9abaaSShinta Sugimoto error: 184178347c8cSThomas Egerer xfrm_state_put(xc); 184280c9abaaSShinta Sugimoto return NULL; 184380c9abaaSShinta Sugimoto } 184480c9abaaSShinta Sugimoto EXPORT_SYMBOL(xfrm_state_migrate); 184580c9abaaSShinta Sugimoto #endif 184680c9abaaSShinta Sugimoto 18471da177e4SLinus Torvalds int xfrm_state_update(struct xfrm_state *x) 18481da177e4SLinus Torvalds { 184937b08e34SDavid S. Miller struct xfrm_state *x1, *to_put; 18501da177e4SLinus Torvalds int err; 1851eb2971b6SMasahide NAKAMURA int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY); 1852283bc9f3SFan Du struct net *net = xs_net(x); 18531da177e4SLinus Torvalds 185437b08e34SDavid S. Miller to_put = NULL; 185537b08e34SDavid S. Miller 1856283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 1857edcd5821SDavid S. Miller x1 = __xfrm_state_locate(x, use_spi, x->props.family); 18581da177e4SLinus Torvalds 18591da177e4SLinus Torvalds err = -ESRCH; 18601da177e4SLinus Torvalds if (!x1) 18611da177e4SLinus Torvalds goto out; 18621da177e4SLinus Torvalds 18631da177e4SLinus Torvalds if (xfrm_state_kern(x1)) { 186437b08e34SDavid S. Miller to_put = x1; 18651da177e4SLinus Torvalds err = -EEXIST; 18661da177e4SLinus Torvalds goto out; 18671da177e4SLinus Torvalds } 18681da177e4SLinus Torvalds 18691da177e4SLinus Torvalds if (x1->km.state == XFRM_STATE_ACQ) { 18701da177e4SLinus Torvalds __xfrm_state_insert(x); 18711da177e4SLinus Torvalds x = NULL; 18721da177e4SLinus Torvalds } 18731da177e4SLinus Torvalds err = 0; 18741da177e4SLinus Torvalds 18751da177e4SLinus Torvalds out: 1876283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 18771da177e4SLinus Torvalds 187837b08e34SDavid S. Miller if (to_put) 187937b08e34SDavid S. Miller xfrm_state_put(to_put); 188037b08e34SDavid S. Miller 18811da177e4SLinus Torvalds if (err) 18821da177e4SLinus Torvalds return err; 18831da177e4SLinus Torvalds 18841da177e4SLinus Torvalds if (!x) { 18851da177e4SLinus Torvalds xfrm_state_delete(x1); 18861da177e4SLinus Torvalds xfrm_state_put(x1); 18871da177e4SLinus Torvalds return 0; 18881da177e4SLinus Torvalds } 18891da177e4SLinus Torvalds 18901da177e4SLinus Torvalds err = -EINVAL; 18911da177e4SLinus Torvalds spin_lock_bh(&x1->lock); 18921da177e4SLinus Torvalds if (likely(x1->km.state == XFRM_STATE_VALID)) { 1893257a4b01SHerbert Xu if (x->encap && x1->encap && 1894257a4b01SHerbert Xu x->encap->encap_type == x1->encap->encap_type) 18951da177e4SLinus Torvalds memcpy(x1->encap, x->encap, sizeof(*x1->encap)); 1896257a4b01SHerbert Xu else if (x->encap || x1->encap) 1897257a4b01SHerbert Xu goto fail; 1898257a4b01SHerbert Xu 1899060f02a3SNoriaki TAKAMIYA if (x->coaddr && x1->coaddr) { 1900060f02a3SNoriaki TAKAMIYA memcpy(x1->coaddr, x->coaddr, sizeof(*x1->coaddr)); 1901060f02a3SNoriaki TAKAMIYA } 1902060f02a3SNoriaki TAKAMIYA if (!use_spi && memcmp(&x1->sel, &x->sel, sizeof(x1->sel))) 1903060f02a3SNoriaki TAKAMIYA memcpy(&x1->sel, &x->sel, sizeof(x1->sel)); 19041da177e4SLinus Torvalds memcpy(&x1->lft, &x->lft, sizeof(x1->lft)); 19051da177e4SLinus Torvalds x1->km.dying = 0; 19061da177e4SLinus Torvalds 1907671422b2SThomas Gleixner hrtimer_start(&x1->mtimer, ktime_set(1, 0), 1908671422b2SThomas Gleixner HRTIMER_MODE_REL_SOFT); 19091da177e4SLinus Torvalds if (x1->curlft.use_time) 19101da177e4SLinus Torvalds xfrm_state_check_expire(x1); 19111da177e4SLinus Torvalds 19125baf4f9cSNathan Harold if (x->props.smark.m || x->props.smark.v || x->if_id) { 19136d8e85ffSNathan Harold spin_lock_bh(&net->xfrm.xfrm_state_lock); 19146d8e85ffSNathan Harold 19155baf4f9cSNathan Harold if (x->props.smark.m || x->props.smark.v) 19166d8e85ffSNathan Harold x1->props.smark = x->props.smark; 19176d8e85ffSNathan Harold 19185baf4f9cSNathan Harold if (x->if_id) 19195baf4f9cSNathan Harold x1->if_id = x->if_id; 19205baf4f9cSNathan Harold 19216d8e85ffSNathan Harold __xfrm_state_bump_genids(x1); 19226d8e85ffSNathan Harold spin_unlock_bh(&net->xfrm.xfrm_state_lock); 19236d8e85ffSNathan Harold } 19246d8e85ffSNathan Harold 19251da177e4SLinus Torvalds err = 0; 19268fcbc637STushar Gohad x->km.state = XFRM_STATE_DEAD; 19278fcbc637STushar Gohad __xfrm_state_put(x); 19281da177e4SLinus Torvalds } 1929257a4b01SHerbert Xu 1930257a4b01SHerbert Xu fail: 19311da177e4SLinus Torvalds spin_unlock_bh(&x1->lock); 19321da177e4SLinus Torvalds 19331da177e4SLinus Torvalds xfrm_state_put(x1); 19341da177e4SLinus Torvalds 19351da177e4SLinus Torvalds return err; 19361da177e4SLinus Torvalds } 19371da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_update); 19381da177e4SLinus Torvalds 19391da177e4SLinus Torvalds int xfrm_state_check_expire(struct xfrm_state *x) 19401da177e4SLinus Torvalds { 1941f3da86dcSLeon Romanovsky xfrm_dev_state_update_curlft(x); 1942f3da86dcSLeon Romanovsky 19431da177e4SLinus Torvalds if (!x->curlft.use_time) 1944386c5680SArnd Bergmann x->curlft.use_time = ktime_get_real_seconds(); 19451da177e4SLinus Torvalds 19461da177e4SLinus Torvalds if (x->curlft.bytes >= x->lft.hard_byte_limit || 19471da177e4SLinus Torvalds x->curlft.packets >= x->lft.hard_packet_limit) { 19484666faabSHerbert Xu x->km.state = XFRM_STATE_EXPIRED; 1949671422b2SThomas Gleixner hrtimer_start(&x->mtimer, 0, HRTIMER_MODE_REL_SOFT); 19501da177e4SLinus Torvalds return -EINVAL; 19511da177e4SLinus Torvalds } 19521da177e4SLinus Torvalds 19531da177e4SLinus Torvalds if (!x->km.dying && 19541da177e4SLinus Torvalds (x->curlft.bytes >= x->lft.soft_byte_limit || 19554666faabSHerbert Xu x->curlft.packets >= x->lft.soft_packet_limit)) { 19564666faabSHerbert Xu x->km.dying = 1; 195753bc6b4dSJamal Hadi Salim km_state_expired(x, 0, 0); 19584666faabSHerbert Xu } 19591da177e4SLinus Torvalds return 0; 19601da177e4SLinus Torvalds } 19611da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_check_expire); 19621da177e4SLinus Torvalds 19631da177e4SLinus Torvalds struct xfrm_state * 1964a70486f0SDavid S. Miller xfrm_state_lookup(struct net *net, u32 mark, const xfrm_address_t *daddr, __be32 spi, 1965bd55775cSJamal Hadi Salim u8 proto, unsigned short family) 19661da177e4SLinus Torvalds { 19671da177e4SLinus Torvalds struct xfrm_state *x; 19681da177e4SLinus Torvalds 1969c2f672fcSFlorian Westphal rcu_read_lock(); 1970bd55775cSJamal Hadi Salim x = __xfrm_state_lookup(net, mark, daddr, spi, proto, family); 1971c2f672fcSFlorian Westphal rcu_read_unlock(); 19721da177e4SLinus Torvalds return x; 19731da177e4SLinus Torvalds } 19741da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_lookup); 19751da177e4SLinus Torvalds 19761da177e4SLinus Torvalds struct xfrm_state * 1977bd55775cSJamal Hadi Salim xfrm_state_lookup_byaddr(struct net *net, u32 mark, 1978a70486f0SDavid S. Miller const xfrm_address_t *daddr, const xfrm_address_t *saddr, 1979eb2971b6SMasahide NAKAMURA u8 proto, unsigned short family) 1980eb2971b6SMasahide NAKAMURA { 1981eb2971b6SMasahide NAKAMURA struct xfrm_state *x; 1982eb2971b6SMasahide NAKAMURA 1983283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 1984bd55775cSJamal Hadi Salim x = __xfrm_state_lookup_byaddr(net, mark, daddr, saddr, proto, family); 1985283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 1986eb2971b6SMasahide NAKAMURA return x; 1987eb2971b6SMasahide NAKAMURA } 1988eb2971b6SMasahide NAKAMURA EXPORT_SYMBOL(xfrm_state_lookup_byaddr); 1989eb2971b6SMasahide NAKAMURA 1990eb2971b6SMasahide NAKAMURA struct xfrm_state * 1991e473fcb4SMathias Krause xfrm_find_acq(struct net *net, const struct xfrm_mark *mark, u8 mode, u32 reqid, 19927e652640SSteffen Klassert u32 if_id, u8 proto, const xfrm_address_t *daddr, 1993e473fcb4SMathias Krause const xfrm_address_t *saddr, int create, unsigned short family) 19941da177e4SLinus Torvalds { 19951da177e4SLinus Torvalds struct xfrm_state *x; 19961da177e4SLinus Torvalds 1997283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 19987e652640SSteffen Klassert x = __find_acq_core(net, mark, family, mode, reqid, if_id, proto, daddr, saddr, create); 1999283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 20002770834cSDavid S. Miller 20011da177e4SLinus Torvalds return x; 20021da177e4SLinus Torvalds } 20031da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_find_acq); 20041da177e4SLinus Torvalds 200541a49cc3SMasahide NAKAMURA #ifdef CONFIG_XFRM_SUB_POLICY 20063aaf3915SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6) 20073aaf3915SFlorian Westphal /* distribution counting sort function for xfrm_state and xfrm_tmpl */ 20083aaf3915SFlorian Westphal static void 20093aaf3915SFlorian Westphal __xfrm6_sort(void **dst, void **src, int n, 20103aaf3915SFlorian Westphal int (*cmp)(const void *p), int maxclass) 20113aaf3915SFlorian Westphal { 20123aaf3915SFlorian Westphal int count[XFRM_MAX_DEPTH] = { }; 20133aaf3915SFlorian Westphal int class[XFRM_MAX_DEPTH]; 20143aaf3915SFlorian Westphal int i; 20153aaf3915SFlorian Westphal 20163aaf3915SFlorian Westphal for (i = 0; i < n; i++) { 20173aaf3915SFlorian Westphal int c = cmp(src[i]); 20183aaf3915SFlorian Westphal 20193aaf3915SFlorian Westphal class[i] = c; 20203aaf3915SFlorian Westphal count[c]++; 20213aaf3915SFlorian Westphal } 20223aaf3915SFlorian Westphal 20233aaf3915SFlorian Westphal for (i = 2; i < maxclass; i++) 20243aaf3915SFlorian Westphal count[i] += count[i - 1]; 20253aaf3915SFlorian Westphal 20263aaf3915SFlorian Westphal for (i = 0; i < n; i++) { 20273aaf3915SFlorian Westphal dst[count[class[i] - 1]++] = src[i]; 20283aaf3915SFlorian Westphal src[i] = NULL; 20293aaf3915SFlorian Westphal } 20303aaf3915SFlorian Westphal } 20313aaf3915SFlorian Westphal 20323aaf3915SFlorian Westphal /* Rule for xfrm_state: 20333aaf3915SFlorian Westphal * 20343aaf3915SFlorian Westphal * rule 1: select IPsec transport except AH 20353aaf3915SFlorian Westphal * rule 2: select MIPv6 RO or inbound trigger 20363aaf3915SFlorian Westphal * rule 3: select IPsec transport AH 20373aaf3915SFlorian Westphal * rule 4: select IPsec tunnel 20383aaf3915SFlorian Westphal * rule 5: others 20393aaf3915SFlorian Westphal */ 20403aaf3915SFlorian Westphal static int __xfrm6_state_sort_cmp(const void *p) 20413aaf3915SFlorian Westphal { 20423aaf3915SFlorian Westphal const struct xfrm_state *v = p; 20433aaf3915SFlorian Westphal 20443aaf3915SFlorian Westphal switch (v->props.mode) { 20453aaf3915SFlorian Westphal case XFRM_MODE_TRANSPORT: 20463aaf3915SFlorian Westphal if (v->id.proto != IPPROTO_AH) 20473aaf3915SFlorian Westphal return 1; 20483aaf3915SFlorian Westphal else 20493aaf3915SFlorian Westphal return 3; 20503aaf3915SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6_MIP6) 20513aaf3915SFlorian Westphal case XFRM_MODE_ROUTEOPTIMIZATION: 20523aaf3915SFlorian Westphal case XFRM_MODE_IN_TRIGGER: 20533aaf3915SFlorian Westphal return 2; 20543aaf3915SFlorian Westphal #endif 20553aaf3915SFlorian Westphal case XFRM_MODE_TUNNEL: 20563aaf3915SFlorian Westphal case XFRM_MODE_BEET: 20573aaf3915SFlorian Westphal return 4; 20583aaf3915SFlorian Westphal } 20593aaf3915SFlorian Westphal return 5; 20603aaf3915SFlorian Westphal } 20613aaf3915SFlorian Westphal 20623aaf3915SFlorian Westphal /* Rule for xfrm_tmpl: 20633aaf3915SFlorian Westphal * 20643aaf3915SFlorian Westphal * rule 1: select IPsec transport 20653aaf3915SFlorian Westphal * rule 2: select MIPv6 RO or inbound trigger 20663aaf3915SFlorian Westphal * rule 3: select IPsec tunnel 20673aaf3915SFlorian Westphal * rule 4: others 20683aaf3915SFlorian Westphal */ 20693aaf3915SFlorian Westphal static int __xfrm6_tmpl_sort_cmp(const void *p) 20703aaf3915SFlorian Westphal { 20713aaf3915SFlorian Westphal const struct xfrm_tmpl *v = p; 20723aaf3915SFlorian Westphal 20733aaf3915SFlorian Westphal switch (v->mode) { 20743aaf3915SFlorian Westphal case XFRM_MODE_TRANSPORT: 20753aaf3915SFlorian Westphal return 1; 20763aaf3915SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6_MIP6) 20773aaf3915SFlorian Westphal case XFRM_MODE_ROUTEOPTIMIZATION: 20783aaf3915SFlorian Westphal case XFRM_MODE_IN_TRIGGER: 20793aaf3915SFlorian Westphal return 2; 20803aaf3915SFlorian Westphal #endif 20813aaf3915SFlorian Westphal case XFRM_MODE_TUNNEL: 20823aaf3915SFlorian Westphal case XFRM_MODE_BEET: 20833aaf3915SFlorian Westphal return 3; 20843aaf3915SFlorian Westphal } 20853aaf3915SFlorian Westphal return 4; 20863aaf3915SFlorian Westphal } 20873aaf3915SFlorian Westphal #else 20883aaf3915SFlorian Westphal static inline int __xfrm6_state_sort_cmp(const void *p) { return 5; } 20893aaf3915SFlorian Westphal static inline int __xfrm6_tmpl_sort_cmp(const void *p) { return 4; } 20903aaf3915SFlorian Westphal 20913aaf3915SFlorian Westphal static inline void 20923aaf3915SFlorian Westphal __xfrm6_sort(void **dst, void **src, int n, 20933aaf3915SFlorian Westphal int (*cmp)(const void *p), int maxclass) 209441a49cc3SMasahide NAKAMURA { 20953f5a95adSKoichiro Den int i; 209641a49cc3SMasahide NAKAMURA 20973aaf3915SFlorian Westphal for (i = 0; i < n; i++) 20983aaf3915SFlorian Westphal dst[i] = src[i]; 20993aaf3915SFlorian Westphal } 21003aaf3915SFlorian Westphal #endif /* CONFIG_IPV6 */ 21013aaf3915SFlorian Westphal 21023aaf3915SFlorian Westphal void 21033aaf3915SFlorian Westphal xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n, 21043aaf3915SFlorian Westphal unsigned short family) 21053aaf3915SFlorian Westphal { 21063aaf3915SFlorian Westphal int i; 21073aaf3915SFlorian Westphal 21083aaf3915SFlorian Westphal if (family == AF_INET6) 21093aaf3915SFlorian Westphal __xfrm6_sort((void **)dst, (void **)src, n, 21103aaf3915SFlorian Westphal __xfrm6_tmpl_sort_cmp, 5); 21113f5a95adSKoichiro Den else 21123f5a95adSKoichiro Den for (i = 0; i < n; i++) 21133f5a95adSKoichiro Den dst[i] = src[i]; 211441a49cc3SMasahide NAKAMURA } 211541a49cc3SMasahide NAKAMURA 21163aaf3915SFlorian Westphal void 211741a49cc3SMasahide NAKAMURA xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n, 211841a49cc3SMasahide NAKAMURA unsigned short family) 211941a49cc3SMasahide NAKAMURA { 21203f5a95adSKoichiro Den int i; 2121283bc9f3SFan Du 21223aaf3915SFlorian Westphal if (family == AF_INET6) 21233aaf3915SFlorian Westphal __xfrm6_sort((void **)dst, (void **)src, n, 21243aaf3915SFlorian Westphal __xfrm6_state_sort_cmp, 6); 21253f5a95adSKoichiro Den else 21263f5a95adSKoichiro Den for (i = 0; i < n; i++) 21273f5a95adSKoichiro Den dst[i] = src[i]; 212841a49cc3SMasahide NAKAMURA } 212941a49cc3SMasahide NAKAMURA #endif 213041a49cc3SMasahide NAKAMURA 21311da177e4SLinus Torvalds /* Silly enough, but I'm lazy to build resolution list */ 21321da177e4SLinus Torvalds 2133bd55775cSJamal Hadi Salim static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq) 21341da177e4SLinus Torvalds { 2135fe9f1d87SSabrina Dubroca unsigned int h = xfrm_seq_hash(net, seq); 21368f126e37SDavid S. Miller struct xfrm_state *x; 21378f126e37SDavid S. Miller 2138fe9f1d87SSabrina Dubroca hlist_for_each_entry_rcu(x, net->xfrm.state_byseq + h, byseq) { 21398f126e37SDavid S. Miller if (x->km.seq == seq && 21403d6acfa7SJamal Hadi Salim (mark & x->mark.m) == x->mark.v && 21418f126e37SDavid S. Miller x->km.state == XFRM_STATE_ACQ) { 21421da177e4SLinus Torvalds xfrm_state_hold(x); 21431da177e4SLinus Torvalds return x; 21441da177e4SLinus Torvalds } 21451da177e4SLinus Torvalds } 2146fe9f1d87SSabrina Dubroca 21471da177e4SLinus Torvalds return NULL; 21481da177e4SLinus Torvalds } 21491da177e4SLinus Torvalds 2150bd55775cSJamal Hadi Salim struct xfrm_state *xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq) 21511da177e4SLinus Torvalds { 21521da177e4SLinus Torvalds struct xfrm_state *x; 21531da177e4SLinus Torvalds 2154283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 2155bd55775cSJamal Hadi Salim x = __xfrm_find_acq_byseq(net, mark, seq); 2156283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 21571da177e4SLinus Torvalds return x; 21581da177e4SLinus Torvalds } 21591da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_find_acq_byseq); 21601da177e4SLinus Torvalds 21611da177e4SLinus Torvalds u32 xfrm_get_acqseq(void) 21621da177e4SLinus Torvalds { 21631da177e4SLinus Torvalds u32 res; 21646836b9bdSjamal static atomic_t acqseq; 21651da177e4SLinus Torvalds 21666836b9bdSjamal do { 21676836b9bdSjamal res = atomic_inc_return(&acqseq); 21686836b9bdSjamal } while (!res); 21696836b9bdSjamal 21701da177e4SLinus Torvalds return res; 21711da177e4SLinus Torvalds } 21721da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_get_acqseq); 21731da177e4SLinus Torvalds 2174c2dad11eSSabrina Dubroca int verify_spi_info(u8 proto, u32 min, u32 max, struct netlink_ext_ack *extack) 2175776e9dd9SFan Du { 2176776e9dd9SFan Du switch (proto) { 2177776e9dd9SFan Du case IPPROTO_AH: 2178776e9dd9SFan Du case IPPROTO_ESP: 2179776e9dd9SFan Du break; 2180776e9dd9SFan Du 2181776e9dd9SFan Du case IPPROTO_COMP: 2182776e9dd9SFan Du /* IPCOMP spi is 16-bits. */ 2183c2dad11eSSabrina Dubroca if (max >= 0x10000) { 2184c2dad11eSSabrina Dubroca NL_SET_ERR_MSG(extack, "IPCOMP SPI must be <= 65535"); 2185776e9dd9SFan Du return -EINVAL; 2186c2dad11eSSabrina Dubroca } 2187776e9dd9SFan Du break; 2188776e9dd9SFan Du 2189776e9dd9SFan Du default: 2190c2dad11eSSabrina Dubroca NL_SET_ERR_MSG(extack, "Invalid protocol, must be one of AH, ESP, IPCOMP"); 2191776e9dd9SFan Du return -EINVAL; 2192776e9dd9SFan Du } 2193776e9dd9SFan Du 2194c2dad11eSSabrina Dubroca if (min > max) { 2195c2dad11eSSabrina Dubroca NL_SET_ERR_MSG(extack, "Invalid SPI range: min > max"); 2196776e9dd9SFan Du return -EINVAL; 2197c2dad11eSSabrina Dubroca } 2198776e9dd9SFan Du 2199776e9dd9SFan Du return 0; 2200776e9dd9SFan Du } 2201776e9dd9SFan Du EXPORT_SYMBOL(verify_spi_info); 2202776e9dd9SFan Du 2203c2dad11eSSabrina Dubroca int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high, 2204c2dad11eSSabrina Dubroca struct netlink_ext_ack *extack) 22051da177e4SLinus Torvalds { 2206221df1edSAlexey Dobriyan struct net *net = xs_net(x); 2207f034b5d4SDavid S. Miller unsigned int h; 22081da177e4SLinus Torvalds struct xfrm_state *x0; 2209658b219eSHerbert Xu int err = -ENOENT; 2210658b219eSHerbert Xu __be32 minspi = htonl(low); 2211658b219eSHerbert Xu __be32 maxspi = htonl(high); 2212a779d913Szhuoliang zhang __be32 newspi = 0; 2213bd55775cSJamal Hadi Salim u32 mark = x->mark.v & x->mark.m; 22141da177e4SLinus Torvalds 2215658b219eSHerbert Xu spin_lock_bh(&x->lock); 2216c2dad11eSSabrina Dubroca if (x->km.state == XFRM_STATE_DEAD) { 2217c2dad11eSSabrina Dubroca NL_SET_ERR_MSG(extack, "Target ACQUIRE is in DEAD state"); 2218658b219eSHerbert Xu goto unlock; 2219c2dad11eSSabrina Dubroca } 2220658b219eSHerbert Xu 2221658b219eSHerbert Xu err = 0; 22221da177e4SLinus Torvalds if (x->id.spi) 2223658b219eSHerbert Xu goto unlock; 2224658b219eSHerbert Xu 2225658b219eSHerbert Xu err = -ENOENT; 22261da177e4SLinus Torvalds 22271da177e4SLinus Torvalds if (minspi == maxspi) { 2228bd55775cSJamal Hadi Salim x0 = xfrm_state_lookup(net, mark, &x->id.daddr, minspi, x->id.proto, x->props.family); 22291da177e4SLinus Torvalds if (x0) { 2230c2dad11eSSabrina Dubroca NL_SET_ERR_MSG(extack, "Requested SPI is already in use"); 22311da177e4SLinus Torvalds xfrm_state_put(x0); 2232658b219eSHerbert Xu goto unlock; 22331da177e4SLinus Torvalds } 2234a779d913Szhuoliang zhang newspi = minspi; 22351da177e4SLinus Torvalds } else { 22361da177e4SLinus Torvalds u32 spi = 0; 223726977b4eSAl Viro for (h = 0; h < high-low+1; h++) { 2238e8a533cbSJason A. Donenfeld spi = get_random_u32_inclusive(low, high); 2239bd55775cSJamal Hadi Salim x0 = xfrm_state_lookup(net, mark, &x->id.daddr, htonl(spi), x->id.proto, x->props.family); 22401da177e4SLinus Torvalds if (x0 == NULL) { 2241a779d913Szhuoliang zhang newspi = htonl(spi); 22421da177e4SLinus Torvalds break; 22431da177e4SLinus Torvalds } 22441da177e4SLinus Torvalds xfrm_state_put(x0); 22451da177e4SLinus Torvalds } 22461da177e4SLinus Torvalds } 2247a779d913Szhuoliang zhang if (newspi) { 2248283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 2249a779d913Szhuoliang zhang x->id.spi = newspi; 225012604d8aSAlexey Dobriyan h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, x->props.family); 22513c611d40SLeon Romanovsky XFRM_STATE_INSERT(byspi, &x->byspi, net->xfrm.state_byspi + h, 22523c611d40SLeon Romanovsky x->xso.type); 2253283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 2254658b219eSHerbert Xu 2255658b219eSHerbert Xu err = 0; 2256c2dad11eSSabrina Dubroca } else { 2257c2dad11eSSabrina Dubroca NL_SET_ERR_MSG(extack, "No SPI available in the requested range"); 22581da177e4SLinus Torvalds } 2259658b219eSHerbert Xu 2260658b219eSHerbert Xu unlock: 2261658b219eSHerbert Xu spin_unlock_bh(&x->lock); 2262658b219eSHerbert Xu 2263658b219eSHerbert Xu return err; 22641da177e4SLinus Torvalds } 22651da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_alloc_spi); 22661da177e4SLinus Torvalds 2267d3623099SNicolas Dichtel static bool __xfrm_state_filter_match(struct xfrm_state *x, 2268870a2df4SNicolas Dichtel struct xfrm_address_filter *filter) 2269d3623099SNicolas Dichtel { 2270d3623099SNicolas Dichtel if (filter) { 2271d3623099SNicolas Dichtel if ((filter->family == AF_INET || 2272d3623099SNicolas Dichtel filter->family == AF_INET6) && 2273d3623099SNicolas Dichtel x->props.family != filter->family) 2274d3623099SNicolas Dichtel return false; 2275d3623099SNicolas Dichtel 2276d3623099SNicolas Dichtel return addr_match(&x->props.saddr, &filter->saddr, 2277d3623099SNicolas Dichtel filter->splen) && 2278d3623099SNicolas Dichtel addr_match(&x->id.daddr, &filter->daddr, 2279d3623099SNicolas Dichtel filter->dplen); 2280d3623099SNicolas Dichtel } 2281d3623099SNicolas Dichtel return true; 2282d3623099SNicolas Dichtel } 2283d3623099SNicolas Dichtel 2284284fa7daSAlexey Dobriyan int xfrm_state_walk(struct net *net, struct xfrm_state_walk *walk, 22854c563f76STimo Teras int (*func)(struct xfrm_state *, int, void*), 22861da177e4SLinus Torvalds void *data) 22871da177e4SLinus Torvalds { 228812a169e7SHerbert Xu struct xfrm_state *state; 228912a169e7SHerbert Xu struct xfrm_state_walk *x; 22901da177e4SLinus Torvalds int err = 0; 22911da177e4SLinus Torvalds 229212a169e7SHerbert Xu if (walk->seq != 0 && list_empty(&walk->all)) 22934c563f76STimo Teras return 0; 22944c563f76STimo Teras 2295283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 229612a169e7SHerbert Xu if (list_empty(&walk->all)) 2297284fa7daSAlexey Dobriyan x = list_first_entry(&net->xfrm.state_all, struct xfrm_state_walk, all); 229812a169e7SHerbert Xu else 229980077702SLi RongQing x = list_first_entry(&walk->all, struct xfrm_state_walk, all); 2300284fa7daSAlexey Dobriyan list_for_each_entry_from(x, &net->xfrm.state_all, all) { 230112a169e7SHerbert Xu if (x->state == XFRM_STATE_DEAD) 23024c563f76STimo Teras continue; 230312a169e7SHerbert Xu state = container_of(x, struct xfrm_state, km); 230412a169e7SHerbert Xu if (!xfrm_id_proto_match(state->id.proto, walk->proto)) 230594b9bb54SJamal Hadi Salim continue; 2306d3623099SNicolas Dichtel if (!__xfrm_state_filter_match(state, walk->filter)) 2307d3623099SNicolas Dichtel continue; 230812a169e7SHerbert Xu err = func(state, walk->seq, data); 23094c563f76STimo Teras if (err) { 231012a169e7SHerbert Xu list_move_tail(&walk->all, &x->all); 231194b9bb54SJamal Hadi Salim goto out; 231294b9bb54SJamal Hadi Salim } 231312a169e7SHerbert Xu walk->seq++; 23144c563f76STimo Teras } 231512a169e7SHerbert Xu if (walk->seq == 0) { 23161da177e4SLinus Torvalds err = -ENOENT; 23171da177e4SLinus Torvalds goto out; 23181da177e4SLinus Torvalds } 231912a169e7SHerbert Xu list_del_init(&walk->all); 23201da177e4SLinus Torvalds out: 2321283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 23221da177e4SLinus Torvalds return err; 23231da177e4SLinus Torvalds } 23241da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_walk); 23251da177e4SLinus Torvalds 2326d3623099SNicolas Dichtel void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto, 2327870a2df4SNicolas Dichtel struct xfrm_address_filter *filter) 23285c182458SHerbert Xu { 232912a169e7SHerbert Xu INIT_LIST_HEAD(&walk->all); 23305c182458SHerbert Xu walk->proto = proto; 233112a169e7SHerbert Xu walk->state = XFRM_STATE_DEAD; 233212a169e7SHerbert Xu walk->seq = 0; 2333d3623099SNicolas Dichtel walk->filter = filter; 23345c182458SHerbert Xu } 23355c182458SHerbert Xu EXPORT_SYMBOL(xfrm_state_walk_init); 23365c182458SHerbert Xu 2337283bc9f3SFan Du void xfrm_state_walk_done(struct xfrm_state_walk *walk, struct net *net) 2338abb81c4fSHerbert Xu { 2339d3623099SNicolas Dichtel kfree(walk->filter); 2340d3623099SNicolas Dichtel 234112a169e7SHerbert Xu if (list_empty(&walk->all)) 23425c182458SHerbert Xu return; 23435c182458SHerbert Xu 2344283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 234512a169e7SHerbert Xu list_del(&walk->all); 2346283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 2347abb81c4fSHerbert Xu } 2348abb81c4fSHerbert Xu EXPORT_SYMBOL(xfrm_state_walk_done); 2349abb81c4fSHerbert Xu 2350e99e88a9SKees Cook static void xfrm_replay_timer_handler(struct timer_list *t) 2351f8cd5488SJamal Hadi Salim { 2352e99e88a9SKees Cook struct xfrm_state *x = from_timer(x, t, rtimer); 2353f8cd5488SJamal Hadi Salim 2354f8cd5488SJamal Hadi Salim spin_lock(&x->lock); 2355f8cd5488SJamal Hadi Salim 23562717096aSJamal Hadi Salim if (x->km.state == XFRM_STATE_VALID) { 2357a6483b79SAlexey Dobriyan if (xfrm_aevent_is_on(xs_net(x))) 2358cfc61c59SFlorian Westphal xfrm_replay_notify(x, XFRM_REPLAY_TIMEOUT); 23592717096aSJamal Hadi Salim else 23602717096aSJamal Hadi Salim x->xflags |= XFRM_TIME_DEFER; 23612717096aSJamal Hadi Salim } 2362f8cd5488SJamal Hadi Salim 2363f8cd5488SJamal Hadi Salim spin_unlock(&x->lock); 2364f8cd5488SJamal Hadi Salim } 2365f8cd5488SJamal Hadi Salim 2366df01812eSDenis Cheng static LIST_HEAD(xfrm_km_list); 23671da177e4SLinus Torvalds 2368214e005bSDavid S. Miller void km_policy_notify(struct xfrm_policy *xp, int dir, const struct km_event *c) 23691da177e4SLinus Torvalds { 23701da177e4SLinus Torvalds struct xfrm_mgr *km; 23711da177e4SLinus Torvalds 237285168c00SCong Wang rcu_read_lock(); 237385168c00SCong Wang list_for_each_entry_rcu(km, &xfrm_km_list, list) 237426b15dadSJamal Hadi Salim if (km->notify_policy) 237526b15dadSJamal Hadi Salim km->notify_policy(xp, dir, c); 237685168c00SCong Wang rcu_read_unlock(); 237726b15dadSJamal Hadi Salim } 237826b15dadSJamal Hadi Salim 2379214e005bSDavid S. Miller void km_state_notify(struct xfrm_state *x, const struct km_event *c) 238026b15dadSJamal Hadi Salim { 238126b15dadSJamal Hadi Salim struct xfrm_mgr *km; 238285168c00SCong Wang rcu_read_lock(); 238385168c00SCong Wang list_for_each_entry_rcu(km, &xfrm_km_list, list) 238426b15dadSJamal Hadi Salim if (km->notify) 238526b15dadSJamal Hadi Salim km->notify(x, c); 238685168c00SCong Wang rcu_read_unlock(); 238726b15dadSJamal Hadi Salim } 238826b15dadSJamal Hadi Salim 238926b15dadSJamal Hadi Salim EXPORT_SYMBOL(km_policy_notify); 239026b15dadSJamal Hadi Salim EXPORT_SYMBOL(km_state_notify); 239126b15dadSJamal Hadi Salim 239215e47304SEric W. Biederman void km_state_expired(struct xfrm_state *x, int hard, u32 portid) 239326b15dadSJamal Hadi Salim { 239426b15dadSJamal Hadi Salim struct km_event c; 239526b15dadSJamal Hadi Salim 2396bf08867fSHerbert Xu c.data.hard = hard; 239715e47304SEric W. Biederman c.portid = portid; 2398f60f6b8fSHerbert Xu c.event = XFRM_MSG_EXPIRE; 239926b15dadSJamal Hadi Salim km_state_notify(x, &c); 24001da177e4SLinus Torvalds } 24011da177e4SLinus Torvalds 240253bc6b4dSJamal Hadi Salim EXPORT_SYMBOL(km_state_expired); 240326b15dadSJamal Hadi Salim /* 240426b15dadSJamal Hadi Salim * We send to all registered managers regardless of failure 240526b15dadSJamal Hadi Salim * We are happy with one success 240626b15dadSJamal Hadi Salim */ 2407980ebd25SJamal Hadi Salim int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol) 24081da177e4SLinus Torvalds { 240926b15dadSJamal Hadi Salim int err = -EINVAL, acqret; 24101da177e4SLinus Torvalds struct xfrm_mgr *km; 24111da177e4SLinus Torvalds 241285168c00SCong Wang rcu_read_lock(); 241385168c00SCong Wang list_for_each_entry_rcu(km, &xfrm_km_list, list) { 241465e0736bSFan Du acqret = km->acquire(x, t, pol); 241526b15dadSJamal Hadi Salim if (!acqret) 241626b15dadSJamal Hadi Salim err = acqret; 24171da177e4SLinus Torvalds } 241885168c00SCong Wang rcu_read_unlock(); 24191da177e4SLinus Torvalds return err; 24201da177e4SLinus Torvalds } 2421980ebd25SJamal Hadi Salim EXPORT_SYMBOL(km_query); 24221da177e4SLinus Torvalds 24234e484b3eSAntony Antony static int __km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport) 24241da177e4SLinus Torvalds { 24251da177e4SLinus Torvalds int err = -EINVAL; 24261da177e4SLinus Torvalds struct xfrm_mgr *km; 24271da177e4SLinus Torvalds 242885168c00SCong Wang rcu_read_lock(); 242985168c00SCong Wang list_for_each_entry_rcu(km, &xfrm_km_list, list) { 24301da177e4SLinus Torvalds if (km->new_mapping) 24311da177e4SLinus Torvalds err = km->new_mapping(x, ipaddr, sport); 24321da177e4SLinus Torvalds if (!err) 24331da177e4SLinus Torvalds break; 24341da177e4SLinus Torvalds } 243585168c00SCong Wang rcu_read_unlock(); 24361da177e4SLinus Torvalds return err; 24371da177e4SLinus Torvalds } 24384e484b3eSAntony Antony 24394e484b3eSAntony Antony int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport) 24404e484b3eSAntony Antony { 24414e484b3eSAntony Antony int ret = 0; 24424e484b3eSAntony Antony 24434e484b3eSAntony Antony if (x->mapping_maxage) { 24444e484b3eSAntony Antony if ((jiffies / HZ - x->new_mapping) > x->mapping_maxage || 24454e484b3eSAntony Antony x->new_mapping_sport != sport) { 24464e484b3eSAntony Antony x->new_mapping_sport = sport; 24474e484b3eSAntony Antony x->new_mapping = jiffies / HZ; 24484e484b3eSAntony Antony ret = __km_new_mapping(x, ipaddr, sport); 24494e484b3eSAntony Antony } 24504e484b3eSAntony Antony } else { 24514e484b3eSAntony Antony ret = __km_new_mapping(x, ipaddr, sport); 24524e484b3eSAntony Antony } 24534e484b3eSAntony Antony 24544e484b3eSAntony Antony return ret; 24554e484b3eSAntony Antony } 24561da177e4SLinus Torvalds EXPORT_SYMBOL(km_new_mapping); 24571da177e4SLinus Torvalds 245815e47304SEric W. Biederman void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 portid) 24591da177e4SLinus Torvalds { 246026b15dadSJamal Hadi Salim struct km_event c; 24611da177e4SLinus Torvalds 2462bf08867fSHerbert Xu c.data.hard = hard; 246315e47304SEric W. Biederman c.portid = portid; 2464f60f6b8fSHerbert Xu c.event = XFRM_MSG_POLEXPIRE; 246526b15dadSJamal Hadi Salim km_policy_notify(pol, dir, &c); 24661da177e4SLinus Torvalds } 2467a70fcb0bSDavid S. Miller EXPORT_SYMBOL(km_policy_expired); 24681da177e4SLinus Torvalds 24692d60abc2SEric Dumazet #ifdef CONFIG_XFRM_MIGRATE 2470183cad12SDavid S. Miller int km_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, 2471183cad12SDavid S. Miller const struct xfrm_migrate *m, int num_migrate, 24728bafd730SAntony Antony const struct xfrm_kmaddress *k, 24738bafd730SAntony Antony const struct xfrm_encap_tmpl *encap) 247480c9abaaSShinta Sugimoto { 247580c9abaaSShinta Sugimoto int err = -EINVAL; 247680c9abaaSShinta Sugimoto int ret; 247780c9abaaSShinta Sugimoto struct xfrm_mgr *km; 247880c9abaaSShinta Sugimoto 247985168c00SCong Wang rcu_read_lock(); 248085168c00SCong Wang list_for_each_entry_rcu(km, &xfrm_km_list, list) { 248180c9abaaSShinta Sugimoto if (km->migrate) { 24828bafd730SAntony Antony ret = km->migrate(sel, dir, type, m, num_migrate, k, 24838bafd730SAntony Antony encap); 248480c9abaaSShinta Sugimoto if (!ret) 248580c9abaaSShinta Sugimoto err = ret; 248680c9abaaSShinta Sugimoto } 248780c9abaaSShinta Sugimoto } 248885168c00SCong Wang rcu_read_unlock(); 248980c9abaaSShinta Sugimoto return err; 249080c9abaaSShinta Sugimoto } 249180c9abaaSShinta Sugimoto EXPORT_SYMBOL(km_migrate); 24922d60abc2SEric Dumazet #endif 249380c9abaaSShinta Sugimoto 2494db983c11SAlexey Dobriyan int km_report(struct net *net, u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr) 249597a64b45SMasahide NAKAMURA { 249697a64b45SMasahide NAKAMURA int err = -EINVAL; 249797a64b45SMasahide NAKAMURA int ret; 249897a64b45SMasahide NAKAMURA struct xfrm_mgr *km; 249997a64b45SMasahide NAKAMURA 250085168c00SCong Wang rcu_read_lock(); 250185168c00SCong Wang list_for_each_entry_rcu(km, &xfrm_km_list, list) { 250297a64b45SMasahide NAKAMURA if (km->report) { 2503db983c11SAlexey Dobriyan ret = km->report(net, proto, sel, addr); 250497a64b45SMasahide NAKAMURA if (!ret) 250597a64b45SMasahide NAKAMURA err = ret; 250697a64b45SMasahide NAKAMURA } 250797a64b45SMasahide NAKAMURA } 250885168c00SCong Wang rcu_read_unlock(); 250997a64b45SMasahide NAKAMURA return err; 251097a64b45SMasahide NAKAMURA } 251197a64b45SMasahide NAKAMURA EXPORT_SYMBOL(km_report); 251297a64b45SMasahide NAKAMURA 2513bb9cd077SFlorian Westphal static bool km_is_alive(const struct km_event *c) 25140f24558eSHoria Geanta { 25150f24558eSHoria Geanta struct xfrm_mgr *km; 25160f24558eSHoria Geanta bool is_alive = false; 25170f24558eSHoria Geanta 25180f24558eSHoria Geanta rcu_read_lock(); 25190f24558eSHoria Geanta list_for_each_entry_rcu(km, &xfrm_km_list, list) { 25200f24558eSHoria Geanta if (km->is_alive && km->is_alive(c)) { 25210f24558eSHoria Geanta is_alive = true; 25220f24558eSHoria Geanta break; 25230f24558eSHoria Geanta } 25240f24558eSHoria Geanta } 25250f24558eSHoria Geanta rcu_read_unlock(); 25260f24558eSHoria Geanta 25270f24558eSHoria Geanta return is_alive; 25280f24558eSHoria Geanta } 25290f24558eSHoria Geanta 2530c9e7c76dSDmitry Safonov #if IS_ENABLED(CONFIG_XFRM_USER_COMPAT) 2531c9e7c76dSDmitry Safonov static DEFINE_SPINLOCK(xfrm_translator_lock); 2532c9e7c76dSDmitry Safonov static struct xfrm_translator __rcu *xfrm_translator; 2533c9e7c76dSDmitry Safonov 2534c9e7c76dSDmitry Safonov struct xfrm_translator *xfrm_get_translator(void) 2535c9e7c76dSDmitry Safonov { 2536c9e7c76dSDmitry Safonov struct xfrm_translator *xtr; 2537c9e7c76dSDmitry Safonov 2538c9e7c76dSDmitry Safonov rcu_read_lock(); 2539c9e7c76dSDmitry Safonov xtr = rcu_dereference(xfrm_translator); 2540c9e7c76dSDmitry Safonov if (unlikely(!xtr)) 2541c9e7c76dSDmitry Safonov goto out; 2542c9e7c76dSDmitry Safonov if (!try_module_get(xtr->owner)) 2543c9e7c76dSDmitry Safonov xtr = NULL; 2544c9e7c76dSDmitry Safonov out: 2545c9e7c76dSDmitry Safonov rcu_read_unlock(); 2546c9e7c76dSDmitry Safonov return xtr; 2547c9e7c76dSDmitry Safonov } 2548c9e7c76dSDmitry Safonov EXPORT_SYMBOL_GPL(xfrm_get_translator); 2549c9e7c76dSDmitry Safonov 2550c9e7c76dSDmitry Safonov void xfrm_put_translator(struct xfrm_translator *xtr) 2551c9e7c76dSDmitry Safonov { 2552c9e7c76dSDmitry Safonov module_put(xtr->owner); 2553c9e7c76dSDmitry Safonov } 2554c9e7c76dSDmitry Safonov EXPORT_SYMBOL_GPL(xfrm_put_translator); 2555c9e7c76dSDmitry Safonov 2556c9e7c76dSDmitry Safonov int xfrm_register_translator(struct xfrm_translator *xtr) 2557c9e7c76dSDmitry Safonov { 2558c9e7c76dSDmitry Safonov int err = 0; 2559c9e7c76dSDmitry Safonov 2560c9e7c76dSDmitry Safonov spin_lock_bh(&xfrm_translator_lock); 2561c9e7c76dSDmitry Safonov if (unlikely(xfrm_translator != NULL)) 2562c9e7c76dSDmitry Safonov err = -EEXIST; 2563c9e7c76dSDmitry Safonov else 2564c9e7c76dSDmitry Safonov rcu_assign_pointer(xfrm_translator, xtr); 2565c9e7c76dSDmitry Safonov spin_unlock_bh(&xfrm_translator_lock); 2566c9e7c76dSDmitry Safonov 2567c9e7c76dSDmitry Safonov return err; 2568c9e7c76dSDmitry Safonov } 2569c9e7c76dSDmitry Safonov EXPORT_SYMBOL_GPL(xfrm_register_translator); 2570c9e7c76dSDmitry Safonov 2571c9e7c76dSDmitry Safonov int xfrm_unregister_translator(struct xfrm_translator *xtr) 2572c9e7c76dSDmitry Safonov { 2573c9e7c76dSDmitry Safonov int err = 0; 2574c9e7c76dSDmitry Safonov 2575c9e7c76dSDmitry Safonov spin_lock_bh(&xfrm_translator_lock); 2576c9e7c76dSDmitry Safonov if (likely(xfrm_translator != NULL)) { 2577c9e7c76dSDmitry Safonov if (rcu_access_pointer(xfrm_translator) != xtr) 2578c9e7c76dSDmitry Safonov err = -EINVAL; 2579c9e7c76dSDmitry Safonov else 2580c9e7c76dSDmitry Safonov RCU_INIT_POINTER(xfrm_translator, NULL); 2581c9e7c76dSDmitry Safonov } 2582c9e7c76dSDmitry Safonov spin_unlock_bh(&xfrm_translator_lock); 2583c9e7c76dSDmitry Safonov synchronize_rcu(); 2584c9e7c76dSDmitry Safonov 2585c9e7c76dSDmitry Safonov return err; 2586c9e7c76dSDmitry Safonov } 2587c9e7c76dSDmitry Safonov EXPORT_SYMBOL_GPL(xfrm_unregister_translator); 2588c9e7c76dSDmitry Safonov #endif 2589c9e7c76dSDmitry Safonov 2590c6d1b26aSChristoph Hellwig int xfrm_user_policy(struct sock *sk, int optname, sockptr_t optval, int optlen) 25911da177e4SLinus Torvalds { 25921da177e4SLinus Torvalds int err; 25931da177e4SLinus Torvalds u8 *data; 25941da177e4SLinus Torvalds struct xfrm_mgr *km; 25951da177e4SLinus Torvalds struct xfrm_policy *pol = NULL; 25961da177e4SLinus Torvalds 2597c6d1b26aSChristoph Hellwig if (sockptr_is_null(optval) && !optlen) { 2598be8f8284SLorenzo Colitti xfrm_sk_policy_insert(sk, XFRM_POLICY_IN, NULL); 2599be8f8284SLorenzo Colitti xfrm_sk_policy_insert(sk, XFRM_POLICY_OUT, NULL); 2600be8f8284SLorenzo Colitti __sk_dst_reset(sk); 2601be8f8284SLorenzo Colitti return 0; 2602be8f8284SLorenzo Colitti } 2603be8f8284SLorenzo Colitti 26041da177e4SLinus Torvalds if (optlen <= 0 || optlen > PAGE_SIZE) 26051da177e4SLinus Torvalds return -EMSGSIZE; 26061da177e4SLinus Torvalds 2607c6d1b26aSChristoph Hellwig data = memdup_sockptr(optval, optlen); 2608a133d930SGeliang Tang if (IS_ERR(data)) 2609a133d930SGeliang Tang return PTR_ERR(data); 26101da177e4SLinus Torvalds 261196392ee5SDmitry Safonov if (in_compat_syscall()) { 261296392ee5SDmitry Safonov struct xfrm_translator *xtr = xfrm_get_translator(); 261396392ee5SDmitry Safonov 261448f486e1SYu Kuai if (!xtr) { 261548f486e1SYu Kuai kfree(data); 261696392ee5SDmitry Safonov return -EOPNOTSUPP; 261748f486e1SYu Kuai } 261896392ee5SDmitry Safonov 261996392ee5SDmitry Safonov err = xtr->xlate_user_policy_sockptr(&data, optlen); 262096392ee5SDmitry Safonov xfrm_put_translator(xtr); 262196392ee5SDmitry Safonov if (err) { 262296392ee5SDmitry Safonov kfree(data); 262396392ee5SDmitry Safonov return err; 262496392ee5SDmitry Safonov } 262596392ee5SDmitry Safonov } 262696392ee5SDmitry Safonov 26271da177e4SLinus Torvalds err = -EINVAL; 262885168c00SCong Wang rcu_read_lock(); 262985168c00SCong Wang list_for_each_entry_rcu(km, &xfrm_km_list, list) { 2630cb969f07SVenkat Yekkirala pol = km->compile_policy(sk, optname, data, 26311da177e4SLinus Torvalds optlen, &err); 26321da177e4SLinus Torvalds if (err >= 0) 26331da177e4SLinus Torvalds break; 26341da177e4SLinus Torvalds } 263585168c00SCong Wang rcu_read_unlock(); 26361da177e4SLinus Torvalds 26371da177e4SLinus Torvalds if (err >= 0) { 26381da177e4SLinus Torvalds xfrm_sk_policy_insert(sk, err, pol); 26391da177e4SLinus Torvalds xfrm_pol_put(pol); 26402b06cdf3SJonathan Basseri __sk_dst_reset(sk); 26411da177e4SLinus Torvalds err = 0; 26421da177e4SLinus Torvalds } 26431da177e4SLinus Torvalds 26441da177e4SLinus Torvalds kfree(data); 26451da177e4SLinus Torvalds return err; 26461da177e4SLinus Torvalds } 26471da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_user_policy); 26481da177e4SLinus Torvalds 264985168c00SCong Wang static DEFINE_SPINLOCK(xfrm_km_lock); 265085168c00SCong Wang 2651f41b284aSZhengchao Shao void xfrm_register_km(struct xfrm_mgr *km) 26521da177e4SLinus Torvalds { 265385168c00SCong Wang spin_lock_bh(&xfrm_km_lock); 265485168c00SCong Wang list_add_tail_rcu(&km->list, &xfrm_km_list); 265585168c00SCong Wang spin_unlock_bh(&xfrm_km_lock); 26561da177e4SLinus Torvalds } 26571da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_register_km); 26581da177e4SLinus Torvalds 2659f41b284aSZhengchao Shao void xfrm_unregister_km(struct xfrm_mgr *km) 26601da177e4SLinus Torvalds { 266185168c00SCong Wang spin_lock_bh(&xfrm_km_lock); 266285168c00SCong Wang list_del_rcu(&km->list); 266385168c00SCong Wang spin_unlock_bh(&xfrm_km_lock); 266485168c00SCong Wang synchronize_rcu(); 26651da177e4SLinus Torvalds } 26661da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_unregister_km); 26671da177e4SLinus Torvalds 26681da177e4SLinus Torvalds int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo) 26691da177e4SLinus Torvalds { 26701da177e4SLinus Torvalds int err = 0; 2671423826a7SFlorian Westphal 2672423826a7SFlorian Westphal if (WARN_ON(afinfo->family >= NPROTO)) 26731da177e4SLinus Torvalds return -EAFNOSUPPORT; 2674423826a7SFlorian Westphal 267544abdc30SCong Wang spin_lock_bh(&xfrm_state_afinfo_lock); 26761da177e4SLinus Torvalds if (unlikely(xfrm_state_afinfo[afinfo->family] != NULL)) 2677f31e8d4fSLi RongQing err = -EEXIST; 2678edcd5821SDavid S. Miller else 267944abdc30SCong Wang rcu_assign_pointer(xfrm_state_afinfo[afinfo->family], afinfo); 268044abdc30SCong Wang spin_unlock_bh(&xfrm_state_afinfo_lock); 26811da177e4SLinus Torvalds return err; 26821da177e4SLinus Torvalds } 26831da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_register_afinfo); 26841da177e4SLinus Torvalds 26851da177e4SLinus Torvalds int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo) 26861da177e4SLinus Torvalds { 2687423826a7SFlorian Westphal int err = 0, family = afinfo->family; 2688423826a7SFlorian Westphal 2689423826a7SFlorian Westphal if (WARN_ON(family >= NPROTO)) 26901da177e4SLinus Torvalds return -EAFNOSUPPORT; 2691423826a7SFlorian Westphal 269244abdc30SCong Wang spin_lock_bh(&xfrm_state_afinfo_lock); 26931da177e4SLinus Torvalds if (likely(xfrm_state_afinfo[afinfo->family] != NULL)) { 2694423826a7SFlorian Westphal if (rcu_access_pointer(xfrm_state_afinfo[family]) != afinfo) 26951da177e4SLinus Torvalds err = -EINVAL; 2696edcd5821SDavid S. Miller else 269744abdc30SCong Wang RCU_INIT_POINTER(xfrm_state_afinfo[afinfo->family], NULL); 26981da177e4SLinus Torvalds } 269944abdc30SCong Wang spin_unlock_bh(&xfrm_state_afinfo_lock); 270044abdc30SCong Wang synchronize_rcu(); 27011da177e4SLinus Torvalds return err; 27021da177e4SLinus Torvalds } 27031da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_unregister_afinfo); 27041da177e4SLinus Torvalds 2705711059b9SFlorian Westphal struct xfrm_state_afinfo *xfrm_state_afinfo_get_rcu(unsigned int family) 2706711059b9SFlorian Westphal { 2707711059b9SFlorian Westphal if (unlikely(family >= NPROTO)) 2708711059b9SFlorian Westphal return NULL; 2709711059b9SFlorian Westphal 2710711059b9SFlorian Westphal return rcu_dereference(xfrm_state_afinfo[family]); 2711711059b9SFlorian Westphal } 2712733a5facSFlorian Westphal EXPORT_SYMBOL_GPL(xfrm_state_afinfo_get_rcu); 2713711059b9SFlorian Westphal 2714628e341fSHannes Frederic Sowa struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family) 27151da177e4SLinus Torvalds { 27161da177e4SLinus Torvalds struct xfrm_state_afinfo *afinfo; 27171da177e4SLinus Torvalds if (unlikely(family >= NPROTO)) 27181da177e4SLinus Torvalds return NULL; 271944abdc30SCong Wang rcu_read_lock(); 272044abdc30SCong Wang afinfo = rcu_dereference(xfrm_state_afinfo[family]); 2721546be240SHerbert Xu if (unlikely(!afinfo)) 272244abdc30SCong Wang rcu_read_unlock(); 27231da177e4SLinus Torvalds return afinfo; 27241da177e4SLinus Torvalds } 27251da177e4SLinus Torvalds 2726b48c05abSSteffen Klassert void xfrm_flush_gc(void) 2727b48c05abSSteffen Klassert { 2728b48c05abSSteffen Klassert flush_work(&xfrm_state_gc_work); 2729b48c05abSSteffen Klassert } 2730b48c05abSSteffen Klassert EXPORT_SYMBOL(xfrm_flush_gc); 2731b48c05abSSteffen Klassert 27321da177e4SLinus Torvalds /* Temporarily located here until net/xfrm/xfrm_tunnel.c is created */ 27331da177e4SLinus Torvalds void xfrm_state_delete_tunnel(struct xfrm_state *x) 27341da177e4SLinus Torvalds { 27351da177e4SLinus Torvalds if (x->tunnel) { 27361da177e4SLinus Torvalds struct xfrm_state *t = x->tunnel; 27371da177e4SLinus Torvalds 27381da177e4SLinus Torvalds if (atomic_read(&t->tunnel_users) == 2) 27391da177e4SLinus Torvalds xfrm_state_delete(t); 27401da177e4SLinus Torvalds atomic_dec(&t->tunnel_users); 2741f75a2804SCong Wang xfrm_state_put_sync(t); 27421da177e4SLinus Torvalds x->tunnel = NULL; 27431da177e4SLinus Torvalds } 27441da177e4SLinus Torvalds } 27451da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_delete_tunnel); 27461da177e4SLinus Torvalds 2747a6d95c5aSJiri Bohac u32 xfrm_state_mtu(struct xfrm_state *x, int mtu) 27481da177e4SLinus Torvalds { 2749b3b73b8eSFlorian Westphal const struct xfrm_type *type = READ_ONCE(x->type); 2750c7b37c76SFlorian Westphal struct crypto_aead *aead; 2751c7b37c76SFlorian Westphal u32 blksize, net_adj = 0; 27521da177e4SLinus Torvalds 2753c7b37c76SFlorian Westphal if (x->km.state != XFRM_STATE_VALID || 2754c7b37c76SFlorian Westphal !type || type->proto != IPPROTO_ESP) 2755b3b73b8eSFlorian Westphal return mtu - x->props.header_len; 2756c7b37c76SFlorian Westphal 2757c7b37c76SFlorian Westphal aead = x->data; 2758c7b37c76SFlorian Westphal blksize = ALIGN(crypto_aead_blocksize(aead), 4); 2759c7b37c76SFlorian Westphal 2760c7b37c76SFlorian Westphal switch (x->props.mode) { 2761c7b37c76SFlorian Westphal case XFRM_MODE_TRANSPORT: 2762c7b37c76SFlorian Westphal case XFRM_MODE_BEET: 2763c7b37c76SFlorian Westphal if (x->props.family == AF_INET) 2764c7b37c76SFlorian Westphal net_adj = sizeof(struct iphdr); 2765c7b37c76SFlorian Westphal else if (x->props.family == AF_INET6) 2766c7b37c76SFlorian Westphal net_adj = sizeof(struct ipv6hdr); 2767c7b37c76SFlorian Westphal break; 2768c7b37c76SFlorian Westphal case XFRM_MODE_TUNNEL: 2769c7b37c76SFlorian Westphal break; 2770c7b37c76SFlorian Westphal default: 2771c7b37c76SFlorian Westphal WARN_ON_ONCE(1); 2772c7b37c76SFlorian Westphal break; 27731da177e4SLinus Torvalds } 27741da177e4SLinus Torvalds 2775c7b37c76SFlorian Westphal return ((mtu - x->props.header_len - crypto_aead_authsize(aead) - 2776c7b37c76SFlorian Westphal net_adj) & ~(blksize - 1)) + net_adj - 2; 2777c7b37c76SFlorian Westphal } 2778a6d95c5aSJiri Bohac EXPORT_SYMBOL_GPL(xfrm_state_mtu); 2779c7b37c76SFlorian Westphal 2780741f9a10SSabrina Dubroca int __xfrm_init_state(struct xfrm_state *x, bool init_replay, bool offload, 2781741f9a10SSabrina Dubroca struct netlink_ext_ack *extack) 278272cb6962SHerbert Xu { 2783c9500d7bSFlorian Westphal const struct xfrm_mode *inner_mode; 2784c9500d7bSFlorian Westphal const struct xfrm_mode *outer_mode; 2785d094cd83SHerbert Xu int family = x->props.family; 278672cb6962SHerbert Xu int err; 278772cb6962SHerbert Xu 2788e4681747SFlorian Westphal if (family == AF_INET && 27890968d2a4SKuniyuki Iwashima READ_ONCE(xs_net(x)->ipv4.sysctl_ip_no_pmtu_disc)) 2790e4681747SFlorian Westphal x->props.flags |= XFRM_STATE_NOPMTUDISC; 2791d094cd83SHerbert Xu 2792d094cd83SHerbert Xu err = -EPROTONOSUPPORT; 2793df9dcb45SKazunori MIYAZAWA 2794df9dcb45SKazunori MIYAZAWA if (x->sel.family != AF_UNSPEC) { 2795df9dcb45SKazunori MIYAZAWA inner_mode = xfrm_get_mode(x->props.mode, x->sel.family); 2796741f9a10SSabrina Dubroca if (inner_mode == NULL) { 2797741f9a10SSabrina Dubroca NL_SET_ERR_MSG(extack, "Requested mode not found"); 279813996378SHerbert Xu goto error; 2799741f9a10SSabrina Dubroca } 280013996378SHerbert Xu 2801df9dcb45SKazunori MIYAZAWA if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL) && 2802741f9a10SSabrina Dubroca family != x->sel.family) { 2803741f9a10SSabrina Dubroca NL_SET_ERR_MSG(extack, "Only tunnel modes can accommodate a change of family"); 280413996378SHerbert Xu goto error; 2805741f9a10SSabrina Dubroca } 2806df9dcb45SKazunori MIYAZAWA 2807c9500d7bSFlorian Westphal x->inner_mode = *inner_mode; 2808df9dcb45SKazunori MIYAZAWA } else { 28094c145dceSFlorian Westphal const struct xfrm_mode *inner_mode_iaf; 2810d81d2285SMartin Willi int iafamily = AF_INET; 2811df9dcb45SKazunori MIYAZAWA 2812d81d2285SMartin Willi inner_mode = xfrm_get_mode(x->props.mode, x->props.family); 2813741f9a10SSabrina Dubroca if (inner_mode == NULL) { 2814741f9a10SSabrina Dubroca NL_SET_ERR_MSG(extack, "Requested mode not found"); 2815df9dcb45SKazunori MIYAZAWA goto error; 2816741f9a10SSabrina Dubroca } 2817df9dcb45SKazunori MIYAZAWA 2818741f9a10SSabrina Dubroca if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL)) { 2819741f9a10SSabrina Dubroca NL_SET_ERR_MSG(extack, "Only tunnel modes can accommodate an AF_UNSPEC selector"); 2820df9dcb45SKazunori MIYAZAWA goto error; 2821741f9a10SSabrina Dubroca } 28224c145dceSFlorian Westphal 2823c9500d7bSFlorian Westphal x->inner_mode = *inner_mode; 2824d81d2285SMartin Willi 2825d81d2285SMartin Willi if (x->props.family == AF_INET) 2826d81d2285SMartin Willi iafamily = AF_INET6; 2827d81d2285SMartin Willi 2828d81d2285SMartin Willi inner_mode_iaf = xfrm_get_mode(x->props.mode, iafamily); 2829d81d2285SMartin Willi if (inner_mode_iaf) { 2830d81d2285SMartin Willi if (inner_mode_iaf->flags & XFRM_MODE_FLAG_TUNNEL) 2831c9500d7bSFlorian Westphal x->inner_mode_iaf = *inner_mode_iaf; 2832df9dcb45SKazunori MIYAZAWA } 2833df9dcb45SKazunori MIYAZAWA } 283413996378SHerbert Xu 2835d094cd83SHerbert Xu x->type = xfrm_get_type(x->id.proto, family); 2836741f9a10SSabrina Dubroca if (x->type == NULL) { 2837741f9a10SSabrina Dubroca NL_SET_ERR_MSG(extack, "Requested type not found"); 283872cb6962SHerbert Xu goto error; 2839741f9a10SSabrina Dubroca } 284072cb6962SHerbert Xu 2841ffdb5211SIlan Tayari x->type_offload = xfrm_get_type_offload(x->id.proto, family, offload); 28429d389d7fSSteffen Klassert 2843e1e10b44SSabrina Dubroca err = x->type->init_state(x, extack); 284472cb6962SHerbert Xu if (err) 284572cb6962SHerbert Xu goto error; 284672cb6962SHerbert Xu 2847c9500d7bSFlorian Westphal outer_mode = xfrm_get_mode(x->props.mode, family); 2848c9500d7bSFlorian Westphal if (!outer_mode) { 2849741f9a10SSabrina Dubroca NL_SET_ERR_MSG(extack, "Requested mode not found"); 2850599901c3SJulia Lawall err = -EPROTONOSUPPORT; 2851b59f45d0SHerbert Xu goto error; 2852599901c3SJulia Lawall } 2853b59f45d0SHerbert Xu 2854c9500d7bSFlorian Westphal x->outer_mode = *outer_mode; 2855a454f0ccSWei Yongjun if (init_replay) { 28561cf9a3aeSSabrina Dubroca err = xfrm_init_replay(x, extack); 2857a454f0ccSWei Yongjun if (err) 2858a454f0ccSWei Yongjun goto error; 2859a454f0ccSWei Yongjun } 2860a454f0ccSWei Yongjun 286172cb6962SHerbert Xu error: 286272cb6962SHerbert Xu return err; 286372cb6962SHerbert Xu } 286472cb6962SHerbert Xu 2865a454f0ccSWei Yongjun EXPORT_SYMBOL(__xfrm_init_state); 2866a454f0ccSWei Yongjun 2867a454f0ccSWei Yongjun int xfrm_init_state(struct xfrm_state *x) 2868a454f0ccSWei Yongjun { 2869cc01572eSYossi Kuperman int err; 2870cc01572eSYossi Kuperman 2871741f9a10SSabrina Dubroca err = __xfrm_init_state(x, true, false, NULL); 2872cc01572eSYossi Kuperman if (!err) 2873cc01572eSYossi Kuperman x->km.state = XFRM_STATE_VALID; 2874cc01572eSYossi Kuperman 2875cc01572eSYossi Kuperman return err; 2876a454f0ccSWei Yongjun } 2877a454f0ccSWei Yongjun 287872cb6962SHerbert Xu EXPORT_SYMBOL(xfrm_init_state); 28791da177e4SLinus Torvalds 2880d62ddc21SAlexey Dobriyan int __net_init xfrm_state_init(struct net *net) 28811da177e4SLinus Torvalds { 2882f034b5d4SDavid S. Miller unsigned int sz; 28831da177e4SLinus Torvalds 2884565f0fa9SMathias Krause if (net_eq(net, &init_net)) 2885565f0fa9SMathias Krause xfrm_state_cache = KMEM_CACHE(xfrm_state, 2886565f0fa9SMathias Krause SLAB_HWCACHE_ALIGN | SLAB_PANIC); 2887565f0fa9SMathias Krause 28889d4139c7SAlexey Dobriyan INIT_LIST_HEAD(&net->xfrm.state_all); 28899d4139c7SAlexey Dobriyan 2890f034b5d4SDavid S. Miller sz = sizeof(struct hlist_head) * 8; 2891f034b5d4SDavid S. Miller 289273d189dcSAlexey Dobriyan net->xfrm.state_bydst = xfrm_hash_alloc(sz); 289373d189dcSAlexey Dobriyan if (!net->xfrm.state_bydst) 289473d189dcSAlexey Dobriyan goto out_bydst; 2895d320bbb3SAlexey Dobriyan net->xfrm.state_bysrc = xfrm_hash_alloc(sz); 2896d320bbb3SAlexey Dobriyan if (!net->xfrm.state_bysrc) 2897d320bbb3SAlexey Dobriyan goto out_bysrc; 2898b754a4fdSAlexey Dobriyan net->xfrm.state_byspi = xfrm_hash_alloc(sz); 2899b754a4fdSAlexey Dobriyan if (!net->xfrm.state_byspi) 2900b754a4fdSAlexey Dobriyan goto out_byspi; 2901fe9f1d87SSabrina Dubroca net->xfrm.state_byseq = xfrm_hash_alloc(sz); 2902fe9f1d87SSabrina Dubroca if (!net->xfrm.state_byseq) 2903fe9f1d87SSabrina Dubroca goto out_byseq; 2904529983ecSAlexey Dobriyan net->xfrm.state_hmask = ((sz / sizeof(struct hlist_head)) - 1); 2905f034b5d4SDavid S. Miller 29060bf7c5b0SAlexey Dobriyan net->xfrm.state_num = 0; 290763082733SAlexey Dobriyan INIT_WORK(&net->xfrm.state_hash_work, xfrm_hash_resize); 2908283bc9f3SFan Du spin_lock_init(&net->xfrm.xfrm_state_lock); 2909bc8e0adfSAhmed S. Darwish seqcount_spinlock_init(&net->xfrm.xfrm_state_hash_generation, 2910bc8e0adfSAhmed S. Darwish &net->xfrm.xfrm_state_lock); 2911d62ddc21SAlexey Dobriyan return 0; 291273d189dcSAlexey Dobriyan 2913fe9f1d87SSabrina Dubroca out_byseq: 2914fe9f1d87SSabrina Dubroca xfrm_hash_free(net->xfrm.state_byspi, sz); 2915b754a4fdSAlexey Dobriyan out_byspi: 2916b754a4fdSAlexey Dobriyan xfrm_hash_free(net->xfrm.state_bysrc, sz); 2917d320bbb3SAlexey Dobriyan out_bysrc: 2918d320bbb3SAlexey Dobriyan xfrm_hash_free(net->xfrm.state_bydst, sz); 291973d189dcSAlexey Dobriyan out_bydst: 292073d189dcSAlexey Dobriyan return -ENOMEM; 2921d62ddc21SAlexey Dobriyan } 2922d62ddc21SAlexey Dobriyan 2923d62ddc21SAlexey Dobriyan void xfrm_state_fini(struct net *net) 2924d62ddc21SAlexey Dobriyan { 292573d189dcSAlexey Dobriyan unsigned int sz; 292673d189dcSAlexey Dobriyan 29277c2776eeSAlexey Dobriyan flush_work(&net->xfrm.state_hash_work); 292835db57bbSFlorian Westphal flush_work(&xfrm_state_gc_work); 2929dbb2483bSCong Wang xfrm_state_flush(net, 0, false, true); 29307c2776eeSAlexey Dobriyan 29319d4139c7SAlexey Dobriyan WARN_ON(!list_empty(&net->xfrm.state_all)); 293273d189dcSAlexey Dobriyan 2933529983ecSAlexey Dobriyan sz = (net->xfrm.state_hmask + 1) * sizeof(struct hlist_head); 2934fe9f1d87SSabrina Dubroca WARN_ON(!hlist_empty(net->xfrm.state_byseq)); 2935fe9f1d87SSabrina Dubroca xfrm_hash_free(net->xfrm.state_byseq, sz); 2936b754a4fdSAlexey Dobriyan WARN_ON(!hlist_empty(net->xfrm.state_byspi)); 2937b754a4fdSAlexey Dobriyan xfrm_hash_free(net->xfrm.state_byspi, sz); 2938d320bbb3SAlexey Dobriyan WARN_ON(!hlist_empty(net->xfrm.state_bysrc)); 2939d320bbb3SAlexey Dobriyan xfrm_hash_free(net->xfrm.state_bysrc, sz); 294073d189dcSAlexey Dobriyan WARN_ON(!hlist_empty(net->xfrm.state_bydst)); 294173d189dcSAlexey Dobriyan xfrm_hash_free(net->xfrm.state_bydst, sz); 29421da177e4SLinus Torvalds } 29431da177e4SLinus Torvalds 2944ab5f5e8bSJoy Latten #ifdef CONFIG_AUDITSYSCALL 2945cf35f43eSIlpo Järvinen static void xfrm_audit_helper_sainfo(struct xfrm_state *x, 2946ab5f5e8bSJoy Latten struct audit_buffer *audit_buf) 2947ab5f5e8bSJoy Latten { 294868277accSPaul Moore struct xfrm_sec_ctx *ctx = x->security; 294968277accSPaul Moore u32 spi = ntohl(x->id.spi); 295068277accSPaul Moore 295168277accSPaul Moore if (ctx) 2952ab5f5e8bSJoy Latten audit_log_format(audit_buf, " sec_alg=%u sec_doi=%u sec_obj=%s", 295368277accSPaul Moore ctx->ctx_alg, ctx->ctx_doi, ctx->ctx_str); 2954ab5f5e8bSJoy Latten 2955ab5f5e8bSJoy Latten switch (x->props.family) { 2956ab5f5e8bSJoy Latten case AF_INET: 295721454aaaSHarvey Harrison audit_log_format(audit_buf, " src=%pI4 dst=%pI4", 295821454aaaSHarvey Harrison &x->props.saddr.a4, &x->id.daddr.a4); 2959ab5f5e8bSJoy Latten break; 2960ab5f5e8bSJoy Latten case AF_INET6: 29615b095d98SHarvey Harrison audit_log_format(audit_buf, " src=%pI6 dst=%pI6", 2962fdb46ee7SHarvey Harrison x->props.saddr.a6, x->id.daddr.a6); 2963ab5f5e8bSJoy Latten break; 2964ab5f5e8bSJoy Latten } 296568277accSPaul Moore 296668277accSPaul Moore audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi); 2967ab5f5e8bSJoy Latten } 2968ab5f5e8bSJoy Latten 2969cf35f43eSIlpo Järvinen static void xfrm_audit_helper_pktinfo(struct sk_buff *skb, u16 family, 2970afeb14b4SPaul Moore struct audit_buffer *audit_buf) 2971afeb14b4SPaul Moore { 2972b71d1d42SEric Dumazet const struct iphdr *iph4; 2973b71d1d42SEric Dumazet const struct ipv6hdr *iph6; 2974afeb14b4SPaul Moore 2975afeb14b4SPaul Moore switch (family) { 2976afeb14b4SPaul Moore case AF_INET: 2977afeb14b4SPaul Moore iph4 = ip_hdr(skb); 297821454aaaSHarvey Harrison audit_log_format(audit_buf, " src=%pI4 dst=%pI4", 297921454aaaSHarvey Harrison &iph4->saddr, &iph4->daddr); 2980afeb14b4SPaul Moore break; 2981afeb14b4SPaul Moore case AF_INET6: 2982afeb14b4SPaul Moore iph6 = ipv6_hdr(skb); 2983afeb14b4SPaul Moore audit_log_format(audit_buf, 29845b095d98SHarvey Harrison " src=%pI6 dst=%pI6 flowlbl=0x%x%02x%02x", 2985fdb46ee7SHarvey Harrison &iph6->saddr, &iph6->daddr, 2986afeb14b4SPaul Moore iph6->flow_lbl[0] & 0x0f, 2987afeb14b4SPaul Moore iph6->flow_lbl[1], 2988afeb14b4SPaul Moore iph6->flow_lbl[2]); 2989afeb14b4SPaul Moore break; 2990afeb14b4SPaul Moore } 2991afeb14b4SPaul Moore } 2992afeb14b4SPaul Moore 29932e71029eSTetsuo Handa void xfrm_audit_state_add(struct xfrm_state *x, int result, bool task_valid) 2994ab5f5e8bSJoy Latten { 2995ab5f5e8bSJoy Latten struct audit_buffer *audit_buf; 2996ab5f5e8bSJoy Latten 2997afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SAD-add"); 2998ab5f5e8bSJoy Latten if (audit_buf == NULL) 2999ab5f5e8bSJoy Latten return; 30002e71029eSTetsuo Handa xfrm_audit_helper_usrinfo(task_valid, audit_buf); 3001afeb14b4SPaul Moore xfrm_audit_helper_sainfo(x, audit_buf); 3002afeb14b4SPaul Moore audit_log_format(audit_buf, " res=%u", result); 3003ab5f5e8bSJoy Latten audit_log_end(audit_buf); 3004ab5f5e8bSJoy Latten } 3005ab5f5e8bSJoy Latten EXPORT_SYMBOL_GPL(xfrm_audit_state_add); 3006ab5f5e8bSJoy Latten 30072e71029eSTetsuo Handa void xfrm_audit_state_delete(struct xfrm_state *x, int result, bool task_valid) 3008ab5f5e8bSJoy Latten { 3009ab5f5e8bSJoy Latten struct audit_buffer *audit_buf; 3010ab5f5e8bSJoy Latten 3011afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SAD-delete"); 3012ab5f5e8bSJoy Latten if (audit_buf == NULL) 3013ab5f5e8bSJoy Latten return; 30142e71029eSTetsuo Handa xfrm_audit_helper_usrinfo(task_valid, audit_buf); 3015afeb14b4SPaul Moore xfrm_audit_helper_sainfo(x, audit_buf); 3016afeb14b4SPaul Moore audit_log_format(audit_buf, " res=%u", result); 3017ab5f5e8bSJoy Latten audit_log_end(audit_buf); 3018ab5f5e8bSJoy Latten } 3019ab5f5e8bSJoy Latten EXPORT_SYMBOL_GPL(xfrm_audit_state_delete); 3020afeb14b4SPaul Moore 3021afeb14b4SPaul Moore void xfrm_audit_state_replay_overflow(struct xfrm_state *x, 3022afeb14b4SPaul Moore struct sk_buff *skb) 3023afeb14b4SPaul Moore { 3024afeb14b4SPaul Moore struct audit_buffer *audit_buf; 3025afeb14b4SPaul Moore u32 spi; 3026afeb14b4SPaul Moore 3027afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SA-replay-overflow"); 3028afeb14b4SPaul Moore if (audit_buf == NULL) 3029afeb14b4SPaul Moore return; 3030afeb14b4SPaul Moore xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf); 3031afeb14b4SPaul Moore /* don't record the sequence number because it's inherent in this kind 3032afeb14b4SPaul Moore * of audit message */ 3033afeb14b4SPaul Moore spi = ntohl(x->id.spi); 3034afeb14b4SPaul Moore audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi); 3035afeb14b4SPaul Moore audit_log_end(audit_buf); 3036afeb14b4SPaul Moore } 3037afeb14b4SPaul Moore EXPORT_SYMBOL_GPL(xfrm_audit_state_replay_overflow); 3038afeb14b4SPaul Moore 30399fdc4883SSteffen Klassert void xfrm_audit_state_replay(struct xfrm_state *x, 3040afeb14b4SPaul Moore struct sk_buff *skb, __be32 net_seq) 3041afeb14b4SPaul Moore { 3042afeb14b4SPaul Moore struct audit_buffer *audit_buf; 3043afeb14b4SPaul Moore u32 spi; 3044afeb14b4SPaul Moore 3045afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SA-replayed-pkt"); 3046afeb14b4SPaul Moore if (audit_buf == NULL) 3047afeb14b4SPaul Moore return; 3048afeb14b4SPaul Moore xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf); 3049afeb14b4SPaul Moore spi = ntohl(x->id.spi); 3050afeb14b4SPaul Moore audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u", 3051afeb14b4SPaul Moore spi, spi, ntohl(net_seq)); 3052afeb14b4SPaul Moore audit_log_end(audit_buf); 3053afeb14b4SPaul Moore } 30549fdc4883SSteffen Klassert EXPORT_SYMBOL_GPL(xfrm_audit_state_replay); 3055afeb14b4SPaul Moore 3056afeb14b4SPaul Moore void xfrm_audit_state_notfound_simple(struct sk_buff *skb, u16 family) 3057afeb14b4SPaul Moore { 3058afeb14b4SPaul Moore struct audit_buffer *audit_buf; 3059afeb14b4SPaul Moore 3060afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SA-notfound"); 3061afeb14b4SPaul Moore if (audit_buf == NULL) 3062afeb14b4SPaul Moore return; 3063afeb14b4SPaul Moore xfrm_audit_helper_pktinfo(skb, family, audit_buf); 3064afeb14b4SPaul Moore audit_log_end(audit_buf); 3065afeb14b4SPaul Moore } 3066afeb14b4SPaul Moore EXPORT_SYMBOL_GPL(xfrm_audit_state_notfound_simple); 3067afeb14b4SPaul Moore 3068afeb14b4SPaul Moore void xfrm_audit_state_notfound(struct sk_buff *skb, u16 family, 3069afeb14b4SPaul Moore __be32 net_spi, __be32 net_seq) 3070afeb14b4SPaul Moore { 3071afeb14b4SPaul Moore struct audit_buffer *audit_buf; 3072afeb14b4SPaul Moore u32 spi; 3073afeb14b4SPaul Moore 3074afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SA-notfound"); 3075afeb14b4SPaul Moore if (audit_buf == NULL) 3076afeb14b4SPaul Moore return; 3077afeb14b4SPaul Moore xfrm_audit_helper_pktinfo(skb, family, audit_buf); 3078afeb14b4SPaul Moore spi = ntohl(net_spi); 3079afeb14b4SPaul Moore audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u", 3080afeb14b4SPaul Moore spi, spi, ntohl(net_seq)); 3081afeb14b4SPaul Moore audit_log_end(audit_buf); 3082afeb14b4SPaul Moore } 3083afeb14b4SPaul Moore EXPORT_SYMBOL_GPL(xfrm_audit_state_notfound); 3084afeb14b4SPaul Moore 3085afeb14b4SPaul Moore void xfrm_audit_state_icvfail(struct xfrm_state *x, 3086afeb14b4SPaul Moore struct sk_buff *skb, u8 proto) 3087afeb14b4SPaul Moore { 3088afeb14b4SPaul Moore struct audit_buffer *audit_buf; 3089afeb14b4SPaul Moore __be32 net_spi; 3090afeb14b4SPaul Moore __be32 net_seq; 3091afeb14b4SPaul Moore 3092afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SA-icv-failure"); 3093afeb14b4SPaul Moore if (audit_buf == NULL) 3094afeb14b4SPaul Moore return; 3095afeb14b4SPaul Moore xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf); 3096afeb14b4SPaul Moore if (xfrm_parse_spi(skb, proto, &net_spi, &net_seq) == 0) { 3097afeb14b4SPaul Moore u32 spi = ntohl(net_spi); 3098afeb14b4SPaul Moore audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u", 3099afeb14b4SPaul Moore spi, spi, ntohl(net_seq)); 3100afeb14b4SPaul Moore } 3101afeb14b4SPaul Moore audit_log_end(audit_buf); 3102afeb14b4SPaul Moore } 3103afeb14b4SPaul Moore EXPORT_SYMBOL_GPL(xfrm_audit_state_icvfail); 3104ab5f5e8bSJoy Latten #endif /* CONFIG_AUDITSYSCALL */ 3105