11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * xfrm_state.c 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Changes: 51da177e4SLinus Torvalds * Mitsuru KANDA @USAGI 61da177e4SLinus Torvalds * Kazunori MIYAZAWA @USAGI 71da177e4SLinus Torvalds * Kunihiro Ishiguro <kunihiro@ipinfusion.com> 81da177e4SLinus Torvalds * IPv6 support 91da177e4SLinus Torvalds * YOSHIFUJI Hideaki @USAGI 101da177e4SLinus Torvalds * Split up af-specific functions 111da177e4SLinus Torvalds * Derek Atkins <derek@ihtfp.com> 121da177e4SLinus Torvalds * Add UDP Encapsulation 131da177e4SLinus Torvalds * 141da177e4SLinus Torvalds */ 151da177e4SLinus Torvalds 161da177e4SLinus Torvalds #include <linux/workqueue.h> 171da177e4SLinus Torvalds #include <net/xfrm.h> 181da177e4SLinus Torvalds #include <linux/pfkeyv2.h> 191da177e4SLinus Torvalds #include <linux/ipsec.h> 201da177e4SLinus Torvalds #include <linux/module.h> 21f034b5d4SDavid S. Miller #include <linux/cache.h> 2268277accSPaul Moore #include <linux/audit.h> 237c0f6ba6SLinus Torvalds #include <linux/uaccess.h> 249e0d57fdSYury Polyanskiy #include <linux/ktime.h> 255a0e3ad6STejun Heo #include <linux/slab.h> 269e0d57fdSYury Polyanskiy #include <linux/interrupt.h> 279e0d57fdSYury Polyanskiy #include <linux/kernel.h> 281da177e4SLinus Torvalds 2944e36b42SDavid S. Miller #include "xfrm_hash.h" 3044e36b42SDavid S. Miller 31c8406998SFlorian Westphal #define xfrm_state_deref_prot(table, net) \ 32c8406998SFlorian Westphal rcu_dereference_protected((table), lockdep_is_held(&(net)->xfrm.xfrm_state_lock)) 33c8406998SFlorian Westphal 3435db57bbSFlorian Westphal static void xfrm_state_gc_task(struct work_struct *work); 3535db57bbSFlorian Westphal 361da177e4SLinus Torvalds /* Each xfrm_state may be linked to two tables: 371da177e4SLinus Torvalds 381da177e4SLinus Torvalds 1. Hash table by (spi,daddr,ah/esp) to find SA by SPI. (input,ctl) 39a624c108SDavid S. Miller 2. Hash table by (daddr,family,reqid) to find what SAs exist for given 401da177e4SLinus Torvalds destination/tunnel endpoint. (output) 411da177e4SLinus Torvalds */ 421da177e4SLinus Torvalds 43f034b5d4SDavid S. Miller static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024; 44b65e3d7bSFlorian Westphal static __read_mostly seqcount_t xfrm_state_hash_generation = SEQCNT_ZERO(xfrm_state_hash_generation); 45565f0fa9SMathias Krause static struct kmem_cache *xfrm_state_cache __ro_after_init; 461da177e4SLinus Torvalds 4735db57bbSFlorian Westphal static DECLARE_WORK(xfrm_state_gc_work, xfrm_state_gc_task); 4835db57bbSFlorian Westphal static HLIST_HEAD(xfrm_state_gc_list); 4935db57bbSFlorian Westphal 5002efdff7SFlorian Westphal static inline bool xfrm_state_hold_rcu(struct xfrm_state __rcu *x) 5102efdff7SFlorian Westphal { 5288755e9cSReshetova, Elena return refcount_inc_not_zero(&x->refcnt); 5302efdff7SFlorian Westphal } 5402efdff7SFlorian Westphal 5564d0cd00SAlexey Dobriyan static inline unsigned int xfrm_dst_hash(struct net *net, 562ab38503SDavid S. Miller const xfrm_address_t *daddr, 572ab38503SDavid S. Miller const xfrm_address_t *saddr, 58c1969f29SDavid S. Miller u32 reqid, 59a624c108SDavid S. Miller unsigned short family) 60a624c108SDavid S. Miller { 6164d0cd00SAlexey Dobriyan return __xfrm_dst_hash(daddr, saddr, reqid, family, net->xfrm.state_hmask); 62a624c108SDavid S. Miller } 63a624c108SDavid S. Miller 6464d0cd00SAlexey Dobriyan static inline unsigned int xfrm_src_hash(struct net *net, 652ab38503SDavid S. Miller const xfrm_address_t *daddr, 662ab38503SDavid S. Miller const xfrm_address_t *saddr, 6744e36b42SDavid S. Miller unsigned short family) 68f034b5d4SDavid S. Miller { 6964d0cd00SAlexey Dobriyan return __xfrm_src_hash(daddr, saddr, family, net->xfrm.state_hmask); 70f034b5d4SDavid S. Miller } 71f034b5d4SDavid S. Miller 722575b654SDavid S. Miller static inline unsigned int 732ab38503SDavid S. Miller xfrm_spi_hash(struct net *net, const xfrm_address_t *daddr, 742ab38503SDavid S. Miller __be32 spi, u8 proto, unsigned short family) 75f034b5d4SDavid S. Miller { 7664d0cd00SAlexey Dobriyan return __xfrm_spi_hash(daddr, spi, proto, family, net->xfrm.state_hmask); 77f034b5d4SDavid S. Miller } 78f034b5d4SDavid S. Miller 79f034b5d4SDavid S. Miller static void xfrm_hash_transfer(struct hlist_head *list, 80f034b5d4SDavid S. Miller struct hlist_head *ndsttable, 81f034b5d4SDavid S. Miller struct hlist_head *nsrctable, 82f034b5d4SDavid S. Miller struct hlist_head *nspitable, 83f034b5d4SDavid S. Miller unsigned int nhashmask) 84f034b5d4SDavid S. Miller { 85b67bfe0dSSasha Levin struct hlist_node *tmp; 86f034b5d4SDavid S. Miller struct xfrm_state *x; 87f034b5d4SDavid S. Miller 88b67bfe0dSSasha Levin hlist_for_each_entry_safe(x, tmp, list, bydst) { 89f034b5d4SDavid S. Miller unsigned int h; 90f034b5d4SDavid S. Miller 91c1969f29SDavid S. Miller h = __xfrm_dst_hash(&x->id.daddr, &x->props.saddr, 92c1969f29SDavid S. Miller x->props.reqid, x->props.family, 93c1969f29SDavid S. Miller nhashmask); 94ae3fb6d3SFlorian Westphal hlist_add_head_rcu(&x->bydst, ndsttable + h); 95f034b5d4SDavid S. Miller 96667bbcb6SMasahide NAKAMURA h = __xfrm_src_hash(&x->id.daddr, &x->props.saddr, 97667bbcb6SMasahide NAKAMURA x->props.family, 98f034b5d4SDavid S. Miller nhashmask); 99ae3fb6d3SFlorian Westphal hlist_add_head_rcu(&x->bysrc, nsrctable + h); 100f034b5d4SDavid S. Miller 1017b4dc360SMasahide NAKAMURA if (x->id.spi) { 1027b4dc360SMasahide NAKAMURA h = __xfrm_spi_hash(&x->id.daddr, x->id.spi, 1037b4dc360SMasahide NAKAMURA x->id.proto, x->props.family, 1047b4dc360SMasahide NAKAMURA nhashmask); 105ae3fb6d3SFlorian Westphal hlist_add_head_rcu(&x->byspi, nspitable + h); 106f034b5d4SDavid S. Miller } 107f034b5d4SDavid S. Miller } 1087b4dc360SMasahide NAKAMURA } 109f034b5d4SDavid S. Miller 11063082733SAlexey Dobriyan static unsigned long xfrm_hash_new_size(unsigned int state_hmask) 111f034b5d4SDavid S. Miller { 11263082733SAlexey Dobriyan return ((state_hmask + 1) << 1) * sizeof(struct hlist_head); 113f034b5d4SDavid S. Miller } 114f034b5d4SDavid S. Miller 11563082733SAlexey Dobriyan static void xfrm_hash_resize(struct work_struct *work) 116f034b5d4SDavid S. Miller { 11763082733SAlexey Dobriyan struct net *net = container_of(work, struct net, xfrm.state_hash_work); 118f034b5d4SDavid S. Miller struct hlist_head *ndst, *nsrc, *nspi, *odst, *osrc, *ospi; 119f034b5d4SDavid S. Miller unsigned long nsize, osize; 120f034b5d4SDavid S. Miller unsigned int nhashmask, ohashmask; 121f034b5d4SDavid S. Miller int i; 122f034b5d4SDavid S. Miller 12363082733SAlexey Dobriyan nsize = xfrm_hash_new_size(net->xfrm.state_hmask); 12444e36b42SDavid S. Miller ndst = xfrm_hash_alloc(nsize); 125f034b5d4SDavid S. Miller if (!ndst) 1260244790cSYing Xue return; 12744e36b42SDavid S. Miller nsrc = xfrm_hash_alloc(nsize); 128f034b5d4SDavid S. Miller if (!nsrc) { 12944e36b42SDavid S. Miller xfrm_hash_free(ndst, nsize); 1300244790cSYing Xue return; 131f034b5d4SDavid S. Miller } 13244e36b42SDavid S. Miller nspi = xfrm_hash_alloc(nsize); 133f034b5d4SDavid S. Miller if (!nspi) { 13444e36b42SDavid S. Miller xfrm_hash_free(ndst, nsize); 13544e36b42SDavid S. Miller xfrm_hash_free(nsrc, nsize); 1360244790cSYing Xue return; 137f034b5d4SDavid S. Miller } 138f034b5d4SDavid S. Miller 139283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 140b65e3d7bSFlorian Westphal write_seqcount_begin(&xfrm_state_hash_generation); 141f034b5d4SDavid S. Miller 142f034b5d4SDavid S. Miller nhashmask = (nsize / sizeof(struct hlist_head)) - 1U; 143c8406998SFlorian Westphal odst = xfrm_state_deref_prot(net->xfrm.state_bydst, net); 14463082733SAlexey Dobriyan for (i = net->xfrm.state_hmask; i >= 0; i--) 145c8406998SFlorian Westphal xfrm_hash_transfer(odst + i, ndst, nsrc, nspi, nhashmask); 146f034b5d4SDavid S. Miller 147c8406998SFlorian Westphal osrc = xfrm_state_deref_prot(net->xfrm.state_bysrc, net); 148c8406998SFlorian Westphal ospi = xfrm_state_deref_prot(net->xfrm.state_byspi, net); 14963082733SAlexey Dobriyan ohashmask = net->xfrm.state_hmask; 150f034b5d4SDavid S. Miller 151c8406998SFlorian Westphal rcu_assign_pointer(net->xfrm.state_bydst, ndst); 152c8406998SFlorian Westphal rcu_assign_pointer(net->xfrm.state_bysrc, nsrc); 153c8406998SFlorian Westphal rcu_assign_pointer(net->xfrm.state_byspi, nspi); 15463082733SAlexey Dobriyan net->xfrm.state_hmask = nhashmask; 155f034b5d4SDavid S. Miller 156b65e3d7bSFlorian Westphal write_seqcount_end(&xfrm_state_hash_generation); 157283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 158f034b5d4SDavid S. Miller 159f034b5d4SDavid S. Miller osize = (ohashmask + 1) * sizeof(struct hlist_head); 160df7274ebSFlorian Westphal 161df7274ebSFlorian Westphal synchronize_rcu(); 162df7274ebSFlorian Westphal 16344e36b42SDavid S. Miller xfrm_hash_free(odst, osize); 16444e36b42SDavid S. Miller xfrm_hash_free(osrc, osize); 16544e36b42SDavid S. Miller xfrm_hash_free(ospi, osize); 166f034b5d4SDavid S. Miller } 167f034b5d4SDavid S. Miller 16844abdc30SCong Wang static DEFINE_SPINLOCK(xfrm_state_afinfo_lock); 16944abdc30SCong Wang static struct xfrm_state_afinfo __rcu *xfrm_state_afinfo[NPROTO]; 1701da177e4SLinus Torvalds 1711da177e4SLinus Torvalds static DEFINE_SPINLOCK(xfrm_state_gc_lock); 1721da177e4SLinus Torvalds 17353bc6b4dSJamal Hadi Salim int __xfrm_state_delete(struct xfrm_state *x); 1741da177e4SLinus Torvalds 175980ebd25SJamal Hadi Salim int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol); 1760f24558eSHoria Geanta bool km_is_alive(const struct km_event *c); 17715e47304SEric W. Biederman void km_state_expired(struct xfrm_state *x, int hard, u32 portid); 1781da177e4SLinus Torvalds 1797a9885b9SCong Wang static DEFINE_SPINLOCK(xfrm_type_lock); 180533cb5b0SEric Dumazet int xfrm_register_type(const struct xfrm_type *type, unsigned short family) 181aa5d62ccSHerbert Xu { 1827a9885b9SCong Wang struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); 183533cb5b0SEric Dumazet const struct xfrm_type **typemap; 184aa5d62ccSHerbert Xu int err = 0; 185aa5d62ccSHerbert Xu 186aa5d62ccSHerbert Xu if (unlikely(afinfo == NULL)) 187aa5d62ccSHerbert Xu return -EAFNOSUPPORT; 188aa5d62ccSHerbert Xu typemap = afinfo->type_map; 1897a9885b9SCong Wang spin_lock_bh(&xfrm_type_lock); 190aa5d62ccSHerbert Xu 191aa5d62ccSHerbert Xu if (likely(typemap[type->proto] == NULL)) 192aa5d62ccSHerbert Xu typemap[type->proto] = type; 193aa5d62ccSHerbert Xu else 194aa5d62ccSHerbert Xu err = -EEXIST; 1957a9885b9SCong Wang spin_unlock_bh(&xfrm_type_lock); 196af5d27c4SFlorian Westphal rcu_read_unlock(); 197aa5d62ccSHerbert Xu return err; 198aa5d62ccSHerbert Xu } 199aa5d62ccSHerbert Xu EXPORT_SYMBOL(xfrm_register_type); 200aa5d62ccSHerbert Xu 201533cb5b0SEric Dumazet int xfrm_unregister_type(const struct xfrm_type *type, unsigned short family) 202aa5d62ccSHerbert Xu { 2037a9885b9SCong Wang struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); 204533cb5b0SEric Dumazet const struct xfrm_type **typemap; 205aa5d62ccSHerbert Xu int err = 0; 206aa5d62ccSHerbert Xu 207aa5d62ccSHerbert Xu if (unlikely(afinfo == NULL)) 208aa5d62ccSHerbert Xu return -EAFNOSUPPORT; 209aa5d62ccSHerbert Xu typemap = afinfo->type_map; 2107a9885b9SCong Wang spin_lock_bh(&xfrm_type_lock); 211aa5d62ccSHerbert Xu 212aa5d62ccSHerbert Xu if (unlikely(typemap[type->proto] != type)) 213aa5d62ccSHerbert Xu err = -ENOENT; 214aa5d62ccSHerbert Xu else 215aa5d62ccSHerbert Xu typemap[type->proto] = NULL; 2167a9885b9SCong Wang spin_unlock_bh(&xfrm_type_lock); 217af5d27c4SFlorian Westphal rcu_read_unlock(); 218aa5d62ccSHerbert Xu return err; 219aa5d62ccSHerbert Xu } 220aa5d62ccSHerbert Xu EXPORT_SYMBOL(xfrm_unregister_type); 221aa5d62ccSHerbert Xu 222533cb5b0SEric Dumazet static const struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family) 223aa5d62ccSHerbert Xu { 224aa5d62ccSHerbert Xu struct xfrm_state_afinfo *afinfo; 225533cb5b0SEric Dumazet const struct xfrm_type **typemap; 226533cb5b0SEric Dumazet const struct xfrm_type *type; 227aa5d62ccSHerbert Xu int modload_attempted = 0; 228aa5d62ccSHerbert Xu 229aa5d62ccSHerbert Xu retry: 230aa5d62ccSHerbert Xu afinfo = xfrm_state_get_afinfo(family); 231aa5d62ccSHerbert Xu if (unlikely(afinfo == NULL)) 232aa5d62ccSHerbert Xu return NULL; 233aa5d62ccSHerbert Xu typemap = afinfo->type_map; 234aa5d62ccSHerbert Xu 23575cda62dSFlorian Westphal type = READ_ONCE(typemap[proto]); 236aa5d62ccSHerbert Xu if (unlikely(type && !try_module_get(type->owner))) 237aa5d62ccSHerbert Xu type = NULL; 23875cda62dSFlorian Westphal 239af5d27c4SFlorian Westphal rcu_read_unlock(); 24075cda62dSFlorian Westphal 24175cda62dSFlorian Westphal if (!type && !modload_attempted) { 242aa5d62ccSHerbert Xu request_module("xfrm-type-%d-%d", family, proto); 243aa5d62ccSHerbert Xu modload_attempted = 1; 244aa5d62ccSHerbert Xu goto retry; 245aa5d62ccSHerbert Xu } 246aa5d62ccSHerbert Xu 247aa5d62ccSHerbert Xu return type; 248aa5d62ccSHerbert Xu } 249aa5d62ccSHerbert Xu 250533cb5b0SEric Dumazet static void xfrm_put_type(const struct xfrm_type *type) 251aa5d62ccSHerbert Xu { 252aa5d62ccSHerbert Xu module_put(type->owner); 253aa5d62ccSHerbert Xu } 254aa5d62ccSHerbert Xu 2559d389d7fSSteffen Klassert static DEFINE_SPINLOCK(xfrm_type_offload_lock); 2569d389d7fSSteffen Klassert int xfrm_register_type_offload(const struct xfrm_type_offload *type, 2579d389d7fSSteffen Klassert unsigned short family) 2589d389d7fSSteffen Klassert { 2599d389d7fSSteffen Klassert struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); 2609d389d7fSSteffen Klassert const struct xfrm_type_offload **typemap; 2619d389d7fSSteffen Klassert int err = 0; 2629d389d7fSSteffen Klassert 2639d389d7fSSteffen Klassert if (unlikely(afinfo == NULL)) 2649d389d7fSSteffen Klassert return -EAFNOSUPPORT; 2659d389d7fSSteffen Klassert typemap = afinfo->type_offload_map; 2669d389d7fSSteffen Klassert spin_lock_bh(&xfrm_type_offload_lock); 2679d389d7fSSteffen Klassert 2689d389d7fSSteffen Klassert if (likely(typemap[type->proto] == NULL)) 2699d389d7fSSteffen Klassert typemap[type->proto] = type; 2709d389d7fSSteffen Klassert else 2719d389d7fSSteffen Klassert err = -EEXIST; 2729d389d7fSSteffen Klassert spin_unlock_bh(&xfrm_type_offload_lock); 2739d389d7fSSteffen Klassert rcu_read_unlock(); 2749d389d7fSSteffen Klassert return err; 2759d389d7fSSteffen Klassert } 2769d389d7fSSteffen Klassert EXPORT_SYMBOL(xfrm_register_type_offload); 2779d389d7fSSteffen Klassert 2789d389d7fSSteffen Klassert int xfrm_unregister_type_offload(const struct xfrm_type_offload *type, 2799d389d7fSSteffen Klassert unsigned short family) 2809d389d7fSSteffen Klassert { 2819d389d7fSSteffen Klassert struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); 2829d389d7fSSteffen Klassert const struct xfrm_type_offload **typemap; 2839d389d7fSSteffen Klassert int err = 0; 2849d389d7fSSteffen Klassert 2859d389d7fSSteffen Klassert if (unlikely(afinfo == NULL)) 2869d389d7fSSteffen Klassert return -EAFNOSUPPORT; 2879d389d7fSSteffen Klassert typemap = afinfo->type_offload_map; 2889d389d7fSSteffen Klassert spin_lock_bh(&xfrm_type_offload_lock); 2899d389d7fSSteffen Klassert 2909d389d7fSSteffen Klassert if (unlikely(typemap[type->proto] != type)) 2919d389d7fSSteffen Klassert err = -ENOENT; 2929d389d7fSSteffen Klassert else 2939d389d7fSSteffen Klassert typemap[type->proto] = NULL; 2949d389d7fSSteffen Klassert spin_unlock_bh(&xfrm_type_offload_lock); 2959d389d7fSSteffen Klassert rcu_read_unlock(); 2969d389d7fSSteffen Klassert return err; 2979d389d7fSSteffen Klassert } 2989d389d7fSSteffen Klassert EXPORT_SYMBOL(xfrm_unregister_type_offload); 2999d389d7fSSteffen Klassert 300ffdb5211SIlan Tayari static const struct xfrm_type_offload * 301ffdb5211SIlan Tayari xfrm_get_type_offload(u8 proto, unsigned short family, bool try_load) 3029d389d7fSSteffen Klassert { 3039d389d7fSSteffen Klassert struct xfrm_state_afinfo *afinfo; 3049d389d7fSSteffen Klassert const struct xfrm_type_offload **typemap; 3059d389d7fSSteffen Klassert const struct xfrm_type_offload *type; 3069d389d7fSSteffen Klassert 307ffdb5211SIlan Tayari retry: 3089d389d7fSSteffen Klassert afinfo = xfrm_state_get_afinfo(family); 3099d389d7fSSteffen Klassert if (unlikely(afinfo == NULL)) 3109d389d7fSSteffen Klassert return NULL; 3119d389d7fSSteffen Klassert typemap = afinfo->type_offload_map; 3129d389d7fSSteffen Klassert 3139d389d7fSSteffen Klassert type = typemap[proto]; 3149d389d7fSSteffen Klassert if ((type && !try_module_get(type->owner))) 3159d389d7fSSteffen Klassert type = NULL; 3169d389d7fSSteffen Klassert 3172f10a61cSSabrina Dubroca rcu_read_unlock(); 3182f10a61cSSabrina Dubroca 319ffdb5211SIlan Tayari if (!type && try_load) { 320ffdb5211SIlan Tayari request_module("xfrm-offload-%d-%d", family, proto); 321545d8ae7SGustavo A. R. Silva try_load = false; 322ffdb5211SIlan Tayari goto retry; 323ffdb5211SIlan Tayari } 324ffdb5211SIlan Tayari 3259d389d7fSSteffen Klassert return type; 3269d389d7fSSteffen Klassert } 3279d389d7fSSteffen Klassert 3289d389d7fSSteffen Klassert static void xfrm_put_type_offload(const struct xfrm_type_offload *type) 3299d389d7fSSteffen Klassert { 3309d389d7fSSteffen Klassert module_put(type->owner); 3319d389d7fSSteffen Klassert } 3329d389d7fSSteffen Klassert 3337a9885b9SCong Wang static DEFINE_SPINLOCK(xfrm_mode_lock); 334b262a695SFlorian Westphal int xfrm_register_mode(struct xfrm_mode *mode) 335aa5d62ccSHerbert Xu { 336aa5d62ccSHerbert Xu struct xfrm_state_afinfo *afinfo; 337aa5d62ccSHerbert Xu struct xfrm_mode **modemap; 338aa5d62ccSHerbert Xu int err; 339aa5d62ccSHerbert Xu 340aa5d62ccSHerbert Xu if (unlikely(mode->encap >= XFRM_MODE_MAX)) 341aa5d62ccSHerbert Xu return -EINVAL; 342aa5d62ccSHerbert Xu 343b262a695SFlorian Westphal afinfo = xfrm_state_get_afinfo(mode->family); 344aa5d62ccSHerbert Xu if (unlikely(afinfo == NULL)) 345aa5d62ccSHerbert Xu return -EAFNOSUPPORT; 346aa5d62ccSHerbert Xu 347aa5d62ccSHerbert Xu err = -EEXIST; 348aa5d62ccSHerbert Xu modemap = afinfo->mode_map; 3497a9885b9SCong Wang spin_lock_bh(&xfrm_mode_lock); 35017c2a42aSHerbert Xu if (modemap[mode->encap]) 35117c2a42aSHerbert Xu goto out; 35217c2a42aSHerbert Xu 35317c2a42aSHerbert Xu err = -ENOENT; 35417c2a42aSHerbert Xu if (!try_module_get(afinfo->owner)) 35517c2a42aSHerbert Xu goto out; 35617c2a42aSHerbert Xu 357aa5d62ccSHerbert Xu modemap[mode->encap] = mode; 358aa5d62ccSHerbert Xu err = 0; 359aa5d62ccSHerbert Xu 36017c2a42aSHerbert Xu out: 3617a9885b9SCong Wang spin_unlock_bh(&xfrm_mode_lock); 362af5d27c4SFlorian Westphal rcu_read_unlock(); 363aa5d62ccSHerbert Xu return err; 364aa5d62ccSHerbert Xu } 365aa5d62ccSHerbert Xu EXPORT_SYMBOL(xfrm_register_mode); 366aa5d62ccSHerbert Xu 367b262a695SFlorian Westphal void xfrm_unregister_mode(struct xfrm_mode *mode) 368aa5d62ccSHerbert Xu { 369aa5d62ccSHerbert Xu struct xfrm_state_afinfo *afinfo; 370aa5d62ccSHerbert Xu struct xfrm_mode **modemap; 371aa5d62ccSHerbert Xu 372b262a695SFlorian Westphal afinfo = xfrm_state_get_afinfo(mode->family); 373b262a695SFlorian Westphal if (WARN_ON_ONCE(!afinfo)) 374b262a695SFlorian Westphal return; 375aa5d62ccSHerbert Xu 376aa5d62ccSHerbert Xu modemap = afinfo->mode_map; 3777a9885b9SCong Wang spin_lock_bh(&xfrm_mode_lock); 378aa5d62ccSHerbert Xu if (likely(modemap[mode->encap] == mode)) { 379aa5d62ccSHerbert Xu modemap[mode->encap] = NULL; 380733a5facSFlorian Westphal module_put(afinfo->owner); 381aa5d62ccSHerbert Xu } 382aa5d62ccSHerbert Xu 3837a9885b9SCong Wang spin_unlock_bh(&xfrm_mode_lock); 384af5d27c4SFlorian Westphal rcu_read_unlock(); 385aa5d62ccSHerbert Xu } 386aa5d62ccSHerbert Xu EXPORT_SYMBOL(xfrm_unregister_mode); 387aa5d62ccSHerbert Xu 388aa5d62ccSHerbert Xu static struct xfrm_mode *xfrm_get_mode(unsigned int encap, int family) 389aa5d62ccSHerbert Xu { 390aa5d62ccSHerbert Xu struct xfrm_state_afinfo *afinfo; 391aa5d62ccSHerbert Xu struct xfrm_mode *mode; 392aa5d62ccSHerbert Xu int modload_attempted = 0; 393aa5d62ccSHerbert Xu 394aa5d62ccSHerbert Xu if (unlikely(encap >= XFRM_MODE_MAX)) 395aa5d62ccSHerbert Xu return NULL; 396aa5d62ccSHerbert Xu 397aa5d62ccSHerbert Xu retry: 398aa5d62ccSHerbert Xu afinfo = xfrm_state_get_afinfo(family); 399aa5d62ccSHerbert Xu if (unlikely(afinfo == NULL)) 400aa5d62ccSHerbert Xu return NULL; 401aa5d62ccSHerbert Xu 40275cda62dSFlorian Westphal mode = READ_ONCE(afinfo->mode_map[encap]); 403aa5d62ccSHerbert Xu if (unlikely(mode && !try_module_get(mode->owner))) 404aa5d62ccSHerbert Xu mode = NULL; 40575cda62dSFlorian Westphal 406af5d27c4SFlorian Westphal rcu_read_unlock(); 40775cda62dSFlorian Westphal if (!mode && !modload_attempted) { 408aa5d62ccSHerbert Xu request_module("xfrm-mode-%d-%d", family, encap); 409aa5d62ccSHerbert Xu modload_attempted = 1; 410aa5d62ccSHerbert Xu goto retry; 411aa5d62ccSHerbert Xu } 412aa5d62ccSHerbert Xu 413aa5d62ccSHerbert Xu return mode; 414aa5d62ccSHerbert Xu } 415aa5d62ccSHerbert Xu 416aa5d62ccSHerbert Xu static void xfrm_put_mode(struct xfrm_mode *mode) 417aa5d62ccSHerbert Xu { 418aa5d62ccSHerbert Xu module_put(mode->owner); 419aa5d62ccSHerbert Xu } 420aa5d62ccSHerbert Xu 4214a135e53SMathias Krause void xfrm_state_free(struct xfrm_state *x) 4224a135e53SMathias Krause { 4234a135e53SMathias Krause kmem_cache_free(xfrm_state_cache, x); 4244a135e53SMathias Krause } 4254a135e53SMathias Krause EXPORT_SYMBOL(xfrm_state_free); 4264a135e53SMathias Krause 427f75a2804SCong Wang static void ___xfrm_state_destroy(struct xfrm_state *x) 4281da177e4SLinus Torvalds { 4299e0d57fdSYury Polyanskiy tasklet_hrtimer_cancel(&x->mtimer); 430a47f0ce0SDavid S. Miller del_timer_sync(&x->rtimer); 431b5884793SIlan Tayari kfree(x->aead); 4321da177e4SLinus Torvalds kfree(x->aalg); 4331da177e4SLinus Torvalds kfree(x->ealg); 4341da177e4SLinus Torvalds kfree(x->calg); 4351da177e4SLinus Torvalds kfree(x->encap); 436060f02a3SNoriaki TAKAMIYA kfree(x->coaddr); 437d8647b79SSteffen Klassert kfree(x->replay_esn); 438d8647b79SSteffen Klassert kfree(x->preplay_esn); 43913996378SHerbert Xu if (x->inner_mode) 44013996378SHerbert Xu xfrm_put_mode(x->inner_mode); 441df9dcb45SKazunori MIYAZAWA if (x->inner_mode_iaf) 442df9dcb45SKazunori MIYAZAWA xfrm_put_mode(x->inner_mode_iaf); 44313996378SHerbert Xu if (x->outer_mode) 44413996378SHerbert Xu xfrm_put_mode(x->outer_mode); 4459d389d7fSSteffen Klassert if (x->type_offload) 4469d389d7fSSteffen Klassert xfrm_put_type_offload(x->type_offload); 4471da177e4SLinus Torvalds if (x->type) { 4481da177e4SLinus Torvalds x->type->destructor(x); 4491da177e4SLinus Torvalds xfrm_put_type(x->type); 4501da177e4SLinus Torvalds } 451d77e38e6SSteffen Klassert xfrm_dev_state_free(x); 452df71837dSTrent Jaeger security_xfrm_state_free(x); 4534a135e53SMathias Krause xfrm_state_free(x); 4541da177e4SLinus Torvalds } 4551da177e4SLinus Torvalds 456c7837144SAlexey Dobriyan static void xfrm_state_gc_task(struct work_struct *work) 4571da177e4SLinus Torvalds { 45812a169e7SHerbert Xu struct xfrm_state *x; 459b67bfe0dSSasha Levin struct hlist_node *tmp; 46012a169e7SHerbert Xu struct hlist_head gc_list; 4611da177e4SLinus Torvalds 4621da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_gc_lock); 46335db57bbSFlorian Westphal hlist_move_list(&xfrm_state_gc_list, &gc_list); 4641da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_gc_lock); 4651da177e4SLinus Torvalds 466df7274ebSFlorian Westphal synchronize_rcu(); 467df7274ebSFlorian Westphal 468b67bfe0dSSasha Levin hlist_for_each_entry_safe(x, tmp, &gc_list, gclist) 469f75a2804SCong Wang ___xfrm_state_destroy(x); 4701da177e4SLinus Torvalds } 4711da177e4SLinus Torvalds 4729e0d57fdSYury Polyanskiy static enum hrtimer_restart xfrm_timer_handler(struct hrtimer *me) 4731da177e4SLinus Torvalds { 4749e0d57fdSYury Polyanskiy struct tasklet_hrtimer *thr = container_of(me, struct tasklet_hrtimer, timer); 4759e0d57fdSYury Polyanskiy struct xfrm_state *x = container_of(thr, struct xfrm_state, mtimer); 476386c5680SArnd Bergmann time64_t now = ktime_get_real_seconds(); 477386c5680SArnd Bergmann time64_t next = TIME64_MAX; 4781da177e4SLinus Torvalds int warn = 0; 479161a09e7SJoy Latten int err = 0; 4801da177e4SLinus Torvalds 4811da177e4SLinus Torvalds spin_lock(&x->lock); 4821da177e4SLinus Torvalds if (x->km.state == XFRM_STATE_DEAD) 4831da177e4SLinus Torvalds goto out; 4841da177e4SLinus Torvalds if (x->km.state == XFRM_STATE_EXPIRED) 4851da177e4SLinus Torvalds goto expired; 4861da177e4SLinus Torvalds if (x->lft.hard_add_expires_seconds) { 4871da177e4SLinus Torvalds long tmo = x->lft.hard_add_expires_seconds + 4881da177e4SLinus Torvalds x->curlft.add_time - now; 489e3c0d047SFan Du if (tmo <= 0) { 490e3c0d047SFan Du if (x->xflags & XFRM_SOFT_EXPIRE) { 491e3c0d047SFan Du /* enter hard expire without soft expire first?! 492e3c0d047SFan Du * setting a new date could trigger this. 4931365e547SAlexander Alemayhu * workaround: fix x->curflt.add_time by below: 494e3c0d047SFan Du */ 495e3c0d047SFan Du x->curlft.add_time = now - x->saved_tmo - 1; 496e3c0d047SFan Du tmo = x->lft.hard_add_expires_seconds - x->saved_tmo; 497e3c0d047SFan Du } else 4981da177e4SLinus Torvalds goto expired; 499e3c0d047SFan Du } 5001da177e4SLinus Torvalds if (tmo < next) 5011da177e4SLinus Torvalds next = tmo; 5021da177e4SLinus Torvalds } 5031da177e4SLinus Torvalds if (x->lft.hard_use_expires_seconds) { 5041da177e4SLinus Torvalds long tmo = x->lft.hard_use_expires_seconds + 5051da177e4SLinus Torvalds (x->curlft.use_time ? : now) - now; 5061da177e4SLinus Torvalds if (tmo <= 0) 5071da177e4SLinus Torvalds goto expired; 5081da177e4SLinus Torvalds if (tmo < next) 5091da177e4SLinus Torvalds next = tmo; 5101da177e4SLinus Torvalds } 5111da177e4SLinus Torvalds if (x->km.dying) 5121da177e4SLinus Torvalds goto resched; 5131da177e4SLinus Torvalds if (x->lft.soft_add_expires_seconds) { 5141da177e4SLinus Torvalds long tmo = x->lft.soft_add_expires_seconds + 5151da177e4SLinus Torvalds x->curlft.add_time - now; 516e3c0d047SFan Du if (tmo <= 0) { 5171da177e4SLinus Torvalds warn = 1; 518e3c0d047SFan Du x->xflags &= ~XFRM_SOFT_EXPIRE; 519e3c0d047SFan Du } else if (tmo < next) { 5201da177e4SLinus Torvalds next = tmo; 521e3c0d047SFan Du x->xflags |= XFRM_SOFT_EXPIRE; 522e3c0d047SFan Du x->saved_tmo = tmo; 523e3c0d047SFan Du } 5241da177e4SLinus Torvalds } 5251da177e4SLinus Torvalds if (x->lft.soft_use_expires_seconds) { 5261da177e4SLinus Torvalds long tmo = x->lft.soft_use_expires_seconds + 5271da177e4SLinus Torvalds (x->curlft.use_time ? : now) - now; 5281da177e4SLinus Torvalds if (tmo <= 0) 5291da177e4SLinus Torvalds warn = 1; 5301da177e4SLinus Torvalds else if (tmo < next) 5311da177e4SLinus Torvalds next = tmo; 5321da177e4SLinus Torvalds } 5331da177e4SLinus Torvalds 5344666faabSHerbert Xu x->km.dying = warn; 5351da177e4SLinus Torvalds if (warn) 53653bc6b4dSJamal Hadi Salim km_state_expired(x, 0, 0); 5371da177e4SLinus Torvalds resched: 538386c5680SArnd Bergmann if (next != TIME64_MAX) { 5399e0d57fdSYury Polyanskiy tasklet_hrtimer_start(&x->mtimer, ktime_set(next, 0), HRTIMER_MODE_REL); 5409e0d57fdSYury Polyanskiy } 541a47f0ce0SDavid S. Miller 5421da177e4SLinus Torvalds goto out; 5431da177e4SLinus Torvalds 5441da177e4SLinus Torvalds expired: 5455b8ef341SSteffen Klassert if (x->km.state == XFRM_STATE_ACQ && x->id.spi == 0) 5461da177e4SLinus Torvalds x->km.state = XFRM_STATE_EXPIRED; 547161a09e7SJoy Latten 548161a09e7SJoy Latten err = __xfrm_state_delete(x); 5490806ae4cSNicolas Dichtel if (!err) 55053bc6b4dSJamal Hadi Salim km_state_expired(x, 1, 0); 5511da177e4SLinus Torvalds 5522e71029eSTetsuo Handa xfrm_audit_state_delete(x, err ? 0 : 1, true); 553161a09e7SJoy Latten 5541da177e4SLinus Torvalds out: 5551da177e4SLinus Torvalds spin_unlock(&x->lock); 5569e0d57fdSYury Polyanskiy return HRTIMER_NORESTART; 5571da177e4SLinus Torvalds } 5581da177e4SLinus Torvalds 559e99e88a9SKees Cook static void xfrm_replay_timer_handler(struct timer_list *t); 5600ac84752SDavid S. Miller 561673c09beSAlexey Dobriyan struct xfrm_state *xfrm_state_alloc(struct net *net) 5621da177e4SLinus Torvalds { 5631da177e4SLinus Torvalds struct xfrm_state *x; 5641da177e4SLinus Torvalds 565565f0fa9SMathias Krause x = kmem_cache_alloc(xfrm_state_cache, GFP_ATOMIC | __GFP_ZERO); 5661da177e4SLinus Torvalds 5671da177e4SLinus Torvalds if (x) { 568673c09beSAlexey Dobriyan write_pnet(&x->xs_net, net); 56988755e9cSReshetova, Elena refcount_set(&x->refcnt, 1); 5701da177e4SLinus Torvalds atomic_set(&x->tunnel_users, 0); 57112a169e7SHerbert Xu INIT_LIST_HEAD(&x->km.all); 5728f126e37SDavid S. Miller INIT_HLIST_NODE(&x->bydst); 5738f126e37SDavid S. Miller INIT_HLIST_NODE(&x->bysrc); 5748f126e37SDavid S. Miller INIT_HLIST_NODE(&x->byspi); 57599565a6cSFan Du tasklet_hrtimer_init(&x->mtimer, xfrm_timer_handler, 57699565a6cSFan Du CLOCK_BOOTTIME, HRTIMER_MODE_ABS); 577e99e88a9SKees Cook timer_setup(&x->rtimer, xfrm_replay_timer_handler, 0); 578386c5680SArnd Bergmann x->curlft.add_time = ktime_get_real_seconds(); 5791da177e4SLinus Torvalds x->lft.soft_byte_limit = XFRM_INF; 5801da177e4SLinus Torvalds x->lft.soft_packet_limit = XFRM_INF; 5811da177e4SLinus Torvalds x->lft.hard_byte_limit = XFRM_INF; 5821da177e4SLinus Torvalds x->lft.hard_packet_limit = XFRM_INF; 583f8cd5488SJamal Hadi Salim x->replay_maxage = 0; 584f8cd5488SJamal Hadi Salim x->replay_maxdiff = 0; 585df9dcb45SKazunori MIYAZAWA x->inner_mode = NULL; 586df9dcb45SKazunori MIYAZAWA x->inner_mode_iaf = NULL; 5871da177e4SLinus Torvalds spin_lock_init(&x->lock); 5881da177e4SLinus Torvalds } 5891da177e4SLinus Torvalds return x; 5901da177e4SLinus Torvalds } 5911da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_alloc); 5921da177e4SLinus Torvalds 593f75a2804SCong Wang void __xfrm_state_destroy(struct xfrm_state *x, bool sync) 5941da177e4SLinus Torvalds { 595547b792cSIlpo Järvinen WARN_ON(x->km.state != XFRM_STATE_DEAD); 5961da177e4SLinus Torvalds 597f75a2804SCong Wang if (sync) { 598f75a2804SCong Wang synchronize_rcu(); 599f75a2804SCong Wang ___xfrm_state_destroy(x); 600f75a2804SCong Wang } else { 6011da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_gc_lock); 60235db57bbSFlorian Westphal hlist_add_head(&x->gclist, &xfrm_state_gc_list); 6031da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_gc_lock); 60435db57bbSFlorian Westphal schedule_work(&xfrm_state_gc_work); 6051da177e4SLinus Torvalds } 606f75a2804SCong Wang } 6071da177e4SLinus Torvalds EXPORT_SYMBOL(__xfrm_state_destroy); 6081da177e4SLinus Torvalds 60953bc6b4dSJamal Hadi Salim int __xfrm_state_delete(struct xfrm_state *x) 6101da177e4SLinus Torvalds { 61198806f75SAlexey Dobriyan struct net *net = xs_net(x); 61226b15dadSJamal Hadi Salim int err = -ESRCH; 61326b15dadSJamal Hadi Salim 6141da177e4SLinus Torvalds if (x->km.state != XFRM_STATE_DEAD) { 6151da177e4SLinus Torvalds x->km.state = XFRM_STATE_DEAD; 616283bc9f3SFan Du spin_lock(&net->xfrm.xfrm_state_lock); 61712a169e7SHerbert Xu list_del(&x->km.all); 618ae3fb6d3SFlorian Westphal hlist_del_rcu(&x->bydst); 619ae3fb6d3SFlorian Westphal hlist_del_rcu(&x->bysrc); 620a47f0ce0SDavid S. Miller if (x->id.spi) 621ae3fb6d3SFlorian Westphal hlist_del_rcu(&x->byspi); 62298806f75SAlexey Dobriyan net->xfrm.state_num--; 623283bc9f3SFan Du spin_unlock(&net->xfrm.xfrm_state_lock); 6241da177e4SLinus Torvalds 625d77e38e6SSteffen Klassert xfrm_dev_state_delete(x); 626d77e38e6SSteffen Klassert 6271da177e4SLinus Torvalds /* All xfrm_state objects are created by xfrm_state_alloc. 6281da177e4SLinus Torvalds * The xfrm_state_alloc call gives a reference, and that 6291da177e4SLinus Torvalds * is what we are dropping here. 6301da177e4SLinus Torvalds */ 6315dba4797SPatrick McHardy xfrm_state_put(x); 63226b15dadSJamal Hadi Salim err = 0; 6331da177e4SLinus Torvalds } 6341da177e4SLinus Torvalds 63526b15dadSJamal Hadi Salim return err; 63626b15dadSJamal Hadi Salim } 63753bc6b4dSJamal Hadi Salim EXPORT_SYMBOL(__xfrm_state_delete); 63826b15dadSJamal Hadi Salim 63926b15dadSJamal Hadi Salim int xfrm_state_delete(struct xfrm_state *x) 6401da177e4SLinus Torvalds { 64126b15dadSJamal Hadi Salim int err; 64226b15dadSJamal Hadi Salim 6431da177e4SLinus Torvalds spin_lock_bh(&x->lock); 64426b15dadSJamal Hadi Salim err = __xfrm_state_delete(x); 6451da177e4SLinus Torvalds spin_unlock_bh(&x->lock); 64626b15dadSJamal Hadi Salim 64726b15dadSJamal Hadi Salim return err; 6481da177e4SLinus Torvalds } 6491da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_delete); 6501da177e4SLinus Torvalds 6514aa2e62cSJoy Latten #ifdef CONFIG_SECURITY_NETWORK_XFRM 6524aa2e62cSJoy Latten static inline int 6532e71029eSTetsuo Handa xfrm_state_flush_secctx_check(struct net *net, u8 proto, bool task_valid) 6541da177e4SLinus Torvalds { 6554aa2e62cSJoy Latten int i, err = 0; 6564aa2e62cSJoy Latten 6570e602451SAlexey Dobriyan for (i = 0; i <= net->xfrm.state_hmask; i++) { 6584aa2e62cSJoy Latten struct xfrm_state *x; 6594aa2e62cSJoy Latten 660b67bfe0dSSasha Levin hlist_for_each_entry(x, net->xfrm.state_bydst+i, bydst) { 6614aa2e62cSJoy Latten if (xfrm_id_proto_match(x->id.proto, proto) && 6624aa2e62cSJoy Latten (err = security_xfrm_state_delete(x)) != 0) { 6632e71029eSTetsuo Handa xfrm_audit_state_delete(x, 0, task_valid); 6644aa2e62cSJoy Latten return err; 6654aa2e62cSJoy Latten } 6664aa2e62cSJoy Latten } 6674aa2e62cSJoy Latten } 6684aa2e62cSJoy Latten 6694aa2e62cSJoy Latten return err; 6704aa2e62cSJoy Latten } 671d77e38e6SSteffen Klassert 672d77e38e6SSteffen Klassert static inline int 673d77e38e6SSteffen Klassert xfrm_dev_state_flush_secctx_check(struct net *net, struct net_device *dev, bool task_valid) 674d77e38e6SSteffen Klassert { 675d77e38e6SSteffen Klassert int i, err = 0; 676d77e38e6SSteffen Klassert 677d77e38e6SSteffen Klassert for (i = 0; i <= net->xfrm.state_hmask; i++) { 678d77e38e6SSteffen Klassert struct xfrm_state *x; 679d77e38e6SSteffen Klassert struct xfrm_state_offload *xso; 680d77e38e6SSteffen Klassert 681d77e38e6SSteffen Klassert hlist_for_each_entry(x, net->xfrm.state_bydst+i, bydst) { 682d77e38e6SSteffen Klassert xso = &x->xso; 683d77e38e6SSteffen Klassert 684d77e38e6SSteffen Klassert if (xso->dev == dev && 685d77e38e6SSteffen Klassert (err = security_xfrm_state_delete(x)) != 0) { 686d77e38e6SSteffen Klassert xfrm_audit_state_delete(x, 0, task_valid); 687d77e38e6SSteffen Klassert return err; 688d77e38e6SSteffen Klassert } 689d77e38e6SSteffen Klassert } 690d77e38e6SSteffen Klassert } 691d77e38e6SSteffen Klassert 692d77e38e6SSteffen Klassert return err; 693d77e38e6SSteffen Klassert } 6944aa2e62cSJoy Latten #else 6954aa2e62cSJoy Latten static inline int 6962e71029eSTetsuo Handa xfrm_state_flush_secctx_check(struct net *net, u8 proto, bool task_valid) 6974aa2e62cSJoy Latten { 6984aa2e62cSJoy Latten return 0; 6994aa2e62cSJoy Latten } 700d77e38e6SSteffen Klassert 701d77e38e6SSteffen Klassert static inline int 702d77e38e6SSteffen Klassert xfrm_dev_state_flush_secctx_check(struct net *net, struct net_device *dev, bool task_valid) 703d77e38e6SSteffen Klassert { 704d77e38e6SSteffen Klassert return 0; 705d77e38e6SSteffen Klassert } 7064aa2e62cSJoy Latten #endif 7074aa2e62cSJoy Latten 708f75a2804SCong Wang int xfrm_state_flush(struct net *net, u8 proto, bool task_valid, bool sync) 7094aa2e62cSJoy Latten { 7109e64cc95SJamal Hadi Salim int i, err = 0, cnt = 0; 7111da177e4SLinus Torvalds 712283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 7132e71029eSTetsuo Handa err = xfrm_state_flush_secctx_check(net, proto, task_valid); 7144aa2e62cSJoy Latten if (err) 7154aa2e62cSJoy Latten goto out; 7164aa2e62cSJoy Latten 7179e64cc95SJamal Hadi Salim err = -ESRCH; 7180e602451SAlexey Dobriyan for (i = 0; i <= net->xfrm.state_hmask; i++) { 7198f126e37SDavid S. Miller struct xfrm_state *x; 7201da177e4SLinus Torvalds restart: 721b67bfe0dSSasha Levin hlist_for_each_entry(x, net->xfrm.state_bydst+i, bydst) { 7221da177e4SLinus Torvalds if (!xfrm_state_kern(x) && 7235794708fSMasahide NAKAMURA xfrm_id_proto_match(x->id.proto, proto)) { 7241da177e4SLinus Torvalds xfrm_state_hold(x); 725283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 7261da177e4SLinus Torvalds 727161a09e7SJoy Latten err = xfrm_state_delete(x); 728ab5f5e8bSJoy Latten xfrm_audit_state_delete(x, err ? 0 : 1, 7292e71029eSTetsuo Handa task_valid); 730f75a2804SCong Wang if (sync) 731f75a2804SCong Wang xfrm_state_put_sync(x); 732f75a2804SCong Wang else 7331da177e4SLinus Torvalds xfrm_state_put(x); 7349e64cc95SJamal Hadi Salim if (!err) 7359e64cc95SJamal Hadi Salim cnt++; 7361da177e4SLinus Torvalds 737283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 7381da177e4SLinus Torvalds goto restart; 7391da177e4SLinus Torvalds } 7401da177e4SLinus Torvalds } 7411da177e4SLinus Torvalds } 742dd269db8SArtem Savkov out: 743dd269db8SArtem Savkov spin_unlock_bh(&net->xfrm.xfrm_state_lock); 744e4db5b61SFlorian Westphal if (cnt) 7454aa2e62cSJoy Latten err = 0; 746e4db5b61SFlorian Westphal 7474aa2e62cSJoy Latten return err; 7481da177e4SLinus Torvalds } 7491da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_flush); 7501da177e4SLinus Torvalds 751d77e38e6SSteffen Klassert int xfrm_dev_state_flush(struct net *net, struct net_device *dev, bool task_valid) 752d77e38e6SSteffen Klassert { 753d77e38e6SSteffen Klassert int i, err = 0, cnt = 0; 754d77e38e6SSteffen Klassert 755d77e38e6SSteffen Klassert spin_lock_bh(&net->xfrm.xfrm_state_lock); 756d77e38e6SSteffen Klassert err = xfrm_dev_state_flush_secctx_check(net, dev, task_valid); 757d77e38e6SSteffen Klassert if (err) 758d77e38e6SSteffen Klassert goto out; 759d77e38e6SSteffen Klassert 760d77e38e6SSteffen Klassert err = -ESRCH; 761d77e38e6SSteffen Klassert for (i = 0; i <= net->xfrm.state_hmask; i++) { 762d77e38e6SSteffen Klassert struct xfrm_state *x; 763d77e38e6SSteffen Klassert struct xfrm_state_offload *xso; 764d77e38e6SSteffen Klassert restart: 765d77e38e6SSteffen Klassert hlist_for_each_entry(x, net->xfrm.state_bydst+i, bydst) { 766d77e38e6SSteffen Klassert xso = &x->xso; 767d77e38e6SSteffen Klassert 768d77e38e6SSteffen Klassert if (!xfrm_state_kern(x) && xso->dev == dev) { 769d77e38e6SSteffen Klassert xfrm_state_hold(x); 770d77e38e6SSteffen Klassert spin_unlock_bh(&net->xfrm.xfrm_state_lock); 771d77e38e6SSteffen Klassert 772d77e38e6SSteffen Klassert err = xfrm_state_delete(x); 773d77e38e6SSteffen Klassert xfrm_audit_state_delete(x, err ? 0 : 1, 774d77e38e6SSteffen Klassert task_valid); 775d77e38e6SSteffen Klassert xfrm_state_put(x); 776d77e38e6SSteffen Klassert if (!err) 777d77e38e6SSteffen Klassert cnt++; 778d77e38e6SSteffen Klassert 779d77e38e6SSteffen Klassert spin_lock_bh(&net->xfrm.xfrm_state_lock); 780d77e38e6SSteffen Klassert goto restart; 781d77e38e6SSteffen Klassert } 782d77e38e6SSteffen Klassert } 783d77e38e6SSteffen Klassert } 784d77e38e6SSteffen Klassert if (cnt) 785d77e38e6SSteffen Klassert err = 0; 786d77e38e6SSteffen Klassert 787d77e38e6SSteffen Klassert out: 788d77e38e6SSteffen Klassert spin_unlock_bh(&net->xfrm.xfrm_state_lock); 789d77e38e6SSteffen Klassert return err; 790d77e38e6SSteffen Klassert } 791d77e38e6SSteffen Klassert EXPORT_SYMBOL(xfrm_dev_state_flush); 792d77e38e6SSteffen Klassert 793e071041bSAlexey Dobriyan void xfrm_sad_getinfo(struct net *net, struct xfrmk_sadinfo *si) 79428d8909bSJamal Hadi Salim { 795283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 796e071041bSAlexey Dobriyan si->sadcnt = net->xfrm.state_num; 797ca92e173SBenjamin Poirier si->sadhcnt = net->xfrm.state_hmask + 1; 79828d8909bSJamal Hadi Salim si->sadhmcnt = xfrm_state_hashmax; 799283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 80028d8909bSJamal Hadi Salim } 80128d8909bSJamal Hadi Salim EXPORT_SYMBOL(xfrm_sad_getinfo); 80228d8909bSJamal Hadi Salim 803711059b9SFlorian Westphal static void 8041a898592SDavid S. Miller xfrm_init_tempstate(struct xfrm_state *x, const struct flowi *fl, 80504686013SDavid S. Miller const struct xfrm_tmpl *tmpl, 80633765d06SDavid S. Miller const xfrm_address_t *daddr, const xfrm_address_t *saddr, 8071da177e4SLinus Torvalds unsigned short family) 8081da177e4SLinus Torvalds { 809711059b9SFlorian Westphal struct xfrm_state_afinfo *afinfo = xfrm_state_afinfo_get_rcu(family); 810711059b9SFlorian Westphal 8113819a35fSFlorian Westphal if (!afinfo) 8123819a35fSFlorian Westphal return; 8133819a35fSFlorian Westphal 8148444cf71SThomas Egerer afinfo->init_tempsel(&x->sel, fl); 8158444cf71SThomas Egerer 8168444cf71SThomas Egerer if (family != tmpl->encap_family) { 817711059b9SFlorian Westphal afinfo = xfrm_state_afinfo_get_rcu(tmpl->encap_family); 8188444cf71SThomas Egerer if (!afinfo) 819711059b9SFlorian Westphal return; 8208444cf71SThomas Egerer } 8218444cf71SThomas Egerer afinfo->init_temprop(x, tmpl, daddr, saddr); 8221da177e4SLinus Torvalds } 8231da177e4SLinus Torvalds 8249aa60088SDavid S. Miller static struct xfrm_state *__xfrm_state_lookup(struct net *net, u32 mark, 8259aa60088SDavid S. Miller const xfrm_address_t *daddr, 8269aa60088SDavid S. Miller __be32 spi, u8 proto, 8279aa60088SDavid S. Miller unsigned short family) 828edcd5821SDavid S. Miller { 829221df1edSAlexey Dobriyan unsigned int h = xfrm_spi_hash(net, daddr, spi, proto, family); 830edcd5821SDavid S. Miller struct xfrm_state *x; 831edcd5821SDavid S. Miller 832ae3fb6d3SFlorian Westphal hlist_for_each_entry_rcu(x, net->xfrm.state_byspi + h, byspi) { 833edcd5821SDavid S. Miller if (x->props.family != family || 834edcd5821SDavid S. Miller x->id.spi != spi || 8351802571bSWei Yongjun x->id.proto != proto || 83670e94e66SYOSHIFUJI Hideaki / 吉藤英明 !xfrm_addr_equal(&x->id.daddr, daddr, family)) 837edcd5821SDavid S. Miller continue; 838edcd5821SDavid S. Miller 8393d6acfa7SJamal Hadi Salim if ((mark & x->mark.m) != x->mark.v) 8403d6acfa7SJamal Hadi Salim continue; 84102efdff7SFlorian Westphal if (!xfrm_state_hold_rcu(x)) 84202efdff7SFlorian Westphal continue; 843edcd5821SDavid S. Miller return x; 844edcd5821SDavid S. Miller } 845edcd5821SDavid S. Miller 846edcd5821SDavid S. Miller return NULL; 847edcd5821SDavid S. Miller } 848edcd5821SDavid S. Miller 8499aa60088SDavid S. Miller static struct xfrm_state *__xfrm_state_lookup_byaddr(struct net *net, u32 mark, 8509aa60088SDavid S. Miller const xfrm_address_t *daddr, 8519aa60088SDavid S. Miller const xfrm_address_t *saddr, 8529aa60088SDavid S. Miller u8 proto, unsigned short family) 853edcd5821SDavid S. Miller { 854221df1edSAlexey Dobriyan unsigned int h = xfrm_src_hash(net, daddr, saddr, family); 855edcd5821SDavid S. Miller struct xfrm_state *x; 856edcd5821SDavid S. Miller 857ae3fb6d3SFlorian Westphal hlist_for_each_entry_rcu(x, net->xfrm.state_bysrc + h, bysrc) { 858edcd5821SDavid S. Miller if (x->props.family != family || 8591802571bSWei Yongjun x->id.proto != proto || 86070e94e66SYOSHIFUJI Hideaki / 吉藤英明 !xfrm_addr_equal(&x->id.daddr, daddr, family) || 86170e94e66SYOSHIFUJI Hideaki / 吉藤英明 !xfrm_addr_equal(&x->props.saddr, saddr, family)) 862edcd5821SDavid S. Miller continue; 863edcd5821SDavid S. Miller 8643d6acfa7SJamal Hadi Salim if ((mark & x->mark.m) != x->mark.v) 8653d6acfa7SJamal Hadi Salim continue; 86602efdff7SFlorian Westphal if (!xfrm_state_hold_rcu(x)) 86702efdff7SFlorian Westphal continue; 868edcd5821SDavid S. Miller return x; 869edcd5821SDavid S. Miller } 870edcd5821SDavid S. Miller 871edcd5821SDavid S. Miller return NULL; 872edcd5821SDavid S. Miller } 873edcd5821SDavid S. Miller 874edcd5821SDavid S. Miller static inline struct xfrm_state * 875edcd5821SDavid S. Miller __xfrm_state_locate(struct xfrm_state *x, int use_spi, int family) 876edcd5821SDavid S. Miller { 877221df1edSAlexey Dobriyan struct net *net = xs_net(x); 878bd55775cSJamal Hadi Salim u32 mark = x->mark.v & x->mark.m; 879221df1edSAlexey Dobriyan 880edcd5821SDavid S. Miller if (use_spi) 881bd55775cSJamal Hadi Salim return __xfrm_state_lookup(net, mark, &x->id.daddr, 882bd55775cSJamal Hadi Salim x->id.spi, x->id.proto, family); 883edcd5821SDavid S. Miller else 884bd55775cSJamal Hadi Salim return __xfrm_state_lookup_byaddr(net, mark, 885bd55775cSJamal Hadi Salim &x->id.daddr, 886edcd5821SDavid S. Miller &x->props.saddr, 887edcd5821SDavid S. Miller x->id.proto, family); 888edcd5821SDavid S. Miller } 889edcd5821SDavid S. Miller 89098806f75SAlexey Dobriyan static void xfrm_hash_grow_check(struct net *net, int have_hash_collision) 8912fab22f2SPatrick McHardy { 8922fab22f2SPatrick McHardy if (have_hash_collision && 89398806f75SAlexey Dobriyan (net->xfrm.state_hmask + 1) < xfrm_state_hashmax && 89498806f75SAlexey Dobriyan net->xfrm.state_num > net->xfrm.state_hmask) 89598806f75SAlexey Dobriyan schedule_work(&net->xfrm.state_hash_work); 8962fab22f2SPatrick McHardy } 8972fab22f2SPatrick McHardy 89808ec9af1SDavid S. Miller static void xfrm_state_look_at(struct xfrm_policy *pol, struct xfrm_state *x, 8994a08ab0fSDavid S. Miller const struct flowi *fl, unsigned short family, 90008ec9af1SDavid S. Miller struct xfrm_state **best, int *acq_in_progress, 90108ec9af1SDavid S. Miller int *error) 90208ec9af1SDavid S. Miller { 90308ec9af1SDavid S. Miller /* Resolution logic: 90408ec9af1SDavid S. Miller * 1. There is a valid state with matching selector. Done. 90508ec9af1SDavid S. Miller * 2. Valid state with inappropriate selector. Skip. 90608ec9af1SDavid S. Miller * 90708ec9af1SDavid S. Miller * Entering area of "sysdeps". 90808ec9af1SDavid S. Miller * 90908ec9af1SDavid S. Miller * 3. If state is not valid, selector is temporary, it selects 91008ec9af1SDavid S. Miller * only session which triggered previous resolution. Key 91108ec9af1SDavid S. Miller * manager will do something to install a state with proper 91208ec9af1SDavid S. Miller * selector. 91308ec9af1SDavid S. Miller */ 91408ec9af1SDavid S. Miller if (x->km.state == XFRM_STATE_VALID) { 91508ec9af1SDavid S. Miller if ((x->sel.family && 91608ec9af1SDavid S. Miller !xfrm_selector_match(&x->sel, fl, x->sel.family)) || 91708ec9af1SDavid S. Miller !security_xfrm_state_pol_flow_match(x, pol, fl)) 91808ec9af1SDavid S. Miller return; 91908ec9af1SDavid S. Miller 92008ec9af1SDavid S. Miller if (!*best || 92108ec9af1SDavid S. Miller (*best)->km.dying > x->km.dying || 92208ec9af1SDavid S. Miller ((*best)->km.dying == x->km.dying && 92308ec9af1SDavid S. Miller (*best)->curlft.add_time < x->curlft.add_time)) 92408ec9af1SDavid S. Miller *best = x; 92508ec9af1SDavid S. Miller } else if (x->km.state == XFRM_STATE_ACQ) { 92608ec9af1SDavid S. Miller *acq_in_progress = 1; 92708ec9af1SDavid S. Miller } else if (x->km.state == XFRM_STATE_ERROR || 92808ec9af1SDavid S. Miller x->km.state == XFRM_STATE_EXPIRED) { 92908ec9af1SDavid S. Miller if (xfrm_selector_match(&x->sel, fl, x->sel.family) && 93008ec9af1SDavid S. Miller security_xfrm_state_pol_flow_match(x, pol, fl)) 93108ec9af1SDavid S. Miller *error = -ESRCH; 93208ec9af1SDavid S. Miller } 93308ec9af1SDavid S. Miller } 93408ec9af1SDavid S. Miller 9351da177e4SLinus Torvalds struct xfrm_state * 93633765d06SDavid S. Miller xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr, 937b520e9f6SDavid S. Miller const struct flowi *fl, struct xfrm_tmpl *tmpl, 9381da177e4SLinus Torvalds struct xfrm_policy *pol, int *err, 939bc56b334SBenedict Wong unsigned short family, u32 if_id) 9401da177e4SLinus Torvalds { 94108ec9af1SDavid S. Miller static xfrm_address_t saddr_wildcard = { }; 9425447c5e4SAlexey Dobriyan struct net *net = xp_net(pol); 9436a783c90SNicolas Dichtel unsigned int h, h_wildcard; 94437b08e34SDavid S. Miller struct xfrm_state *x, *x0, *to_put; 9451da177e4SLinus Torvalds int acquire_in_progress = 0; 9461da177e4SLinus Torvalds int error = 0; 9471da177e4SLinus Torvalds struct xfrm_state *best = NULL; 948bd55775cSJamal Hadi Salim u32 mark = pol->mark.v & pol->mark.m; 9498444cf71SThomas Egerer unsigned short encap_family = tmpl->encap_family; 950b65e3d7bSFlorian Westphal unsigned int sequence; 9510f24558eSHoria Geanta struct km_event c; 9521da177e4SLinus Torvalds 95337b08e34SDavid S. Miller to_put = NULL; 95437b08e34SDavid S. Miller 955b65e3d7bSFlorian Westphal sequence = read_seqcount_begin(&xfrm_state_hash_generation); 956b65e3d7bSFlorian Westphal 957d737a580SFlorian Westphal rcu_read_lock(); 9588444cf71SThomas Egerer h = xfrm_dst_hash(net, daddr, saddr, tmpl->reqid, encap_family); 959ae3fb6d3SFlorian Westphal hlist_for_each_entry_rcu(x, net->xfrm.state_bydst + h, bydst) { 9608444cf71SThomas Egerer if (x->props.family == encap_family && 9611da177e4SLinus Torvalds x->props.reqid == tmpl->reqid && 9623d6acfa7SJamal Hadi Salim (mark & x->mark.m) == x->mark.v && 9637e652640SSteffen Klassert x->if_id == if_id && 964fbd9a5b4SMasahide NAKAMURA !(x->props.flags & XFRM_STATE_WILDRECV) && 9658444cf71SThomas Egerer xfrm_state_addr_check(x, daddr, saddr, encap_family) && 9661da177e4SLinus Torvalds tmpl->mode == x->props.mode && 9671da177e4SLinus Torvalds tmpl->id.proto == x->id.proto && 96808ec9af1SDavid S. Miller (tmpl->id.spi == x->id.spi || !tmpl->id.spi)) 9691f673c5fSDavid S. Miller xfrm_state_look_at(pol, x, fl, encap_family, 97008ec9af1SDavid S. Miller &best, &acquire_in_progress, &error); 9711da177e4SLinus Torvalds } 9726f115638SFan Du if (best || acquire_in_progress) 97308ec9af1SDavid S. Miller goto found; 97408ec9af1SDavid S. Miller 9758444cf71SThomas Egerer h_wildcard = xfrm_dst_hash(net, daddr, &saddr_wildcard, tmpl->reqid, encap_family); 976ae3fb6d3SFlorian Westphal hlist_for_each_entry_rcu(x, net->xfrm.state_bydst + h_wildcard, bydst) { 9778444cf71SThomas Egerer if (x->props.family == encap_family && 97808ec9af1SDavid S. Miller x->props.reqid == tmpl->reqid && 9793d6acfa7SJamal Hadi Salim (mark & x->mark.m) == x->mark.v && 9807e652640SSteffen Klassert x->if_id == if_id && 98108ec9af1SDavid S. Miller !(x->props.flags & XFRM_STATE_WILDRECV) && 982f59bbdfaSFan Du xfrm_addr_equal(&x->id.daddr, daddr, encap_family) && 98308ec9af1SDavid S. Miller tmpl->mode == x->props.mode && 98408ec9af1SDavid S. Miller tmpl->id.proto == x->id.proto && 98508ec9af1SDavid S. Miller (tmpl->id.spi == x->id.spi || !tmpl->id.spi)) 9861f673c5fSDavid S. Miller xfrm_state_look_at(pol, x, fl, encap_family, 98708ec9af1SDavid S. Miller &best, &acquire_in_progress, &error); 9881da177e4SLinus Torvalds } 9891da177e4SLinus Torvalds 99008ec9af1SDavid S. Miller found: 9911da177e4SLinus Torvalds x = best; 9921da177e4SLinus Torvalds if (!x && !error && !acquire_in_progress) { 9935c5d281aSPatrick McHardy if (tmpl->id.spi && 994bd55775cSJamal Hadi Salim (x0 = __xfrm_state_lookup(net, mark, daddr, tmpl->id.spi, 9958444cf71SThomas Egerer tmpl->id.proto, encap_family)) != NULL) { 99637b08e34SDavid S. Miller to_put = x0; 9971da177e4SLinus Torvalds error = -EEXIST; 9981da177e4SLinus Torvalds goto out; 9991da177e4SLinus Torvalds } 10000f24558eSHoria Geanta 10010f24558eSHoria Geanta c.net = net; 10020f24558eSHoria Geanta /* If the KMs have no listeners (yet...), avoid allocating an SA 10030f24558eSHoria Geanta * for each and every packet - garbage collection might not 10040f24558eSHoria Geanta * handle the flood. 10050f24558eSHoria Geanta */ 10060f24558eSHoria Geanta if (!km_is_alive(&c)) { 10070f24558eSHoria Geanta error = -ESRCH; 10080f24558eSHoria Geanta goto out; 10090f24558eSHoria Geanta } 10100f24558eSHoria Geanta 10115447c5e4SAlexey Dobriyan x = xfrm_state_alloc(net); 10121da177e4SLinus Torvalds if (x == NULL) { 10131da177e4SLinus Torvalds error = -ENOMEM; 10141da177e4SLinus Torvalds goto out; 10151da177e4SLinus Torvalds } 10168444cf71SThomas Egerer /* Initialize temporary state matching only 10171da177e4SLinus Torvalds * to current session. */ 10188444cf71SThomas Egerer xfrm_init_tempstate(x, fl, tmpl, daddr, saddr, family); 1019bd55775cSJamal Hadi Salim memcpy(&x->mark, &pol->mark, sizeof(x->mark)); 10207e652640SSteffen Klassert x->if_id = if_id; 10211da177e4SLinus Torvalds 10221d28f42cSDavid S. Miller error = security_xfrm_state_alloc_acquire(x, pol->security, fl->flowi_secid); 1023e0d1caa7SVenkat Yekkirala if (error) { 1024e0d1caa7SVenkat Yekkirala x->km.state = XFRM_STATE_DEAD; 102537b08e34SDavid S. Miller to_put = x; 1026e0d1caa7SVenkat Yekkirala x = NULL; 1027e0d1caa7SVenkat Yekkirala goto out; 1028e0d1caa7SVenkat Yekkirala } 1029e0d1caa7SVenkat Yekkirala 10301da177e4SLinus Torvalds if (km_query(x, tmpl, pol) == 0) { 1031d737a580SFlorian Westphal spin_lock_bh(&net->xfrm.xfrm_state_lock); 10321da177e4SLinus Torvalds x->km.state = XFRM_STATE_ACQ; 10335447c5e4SAlexey Dobriyan list_add(&x->km.all, &net->xfrm.state_all); 1034ae3fb6d3SFlorian Westphal hlist_add_head_rcu(&x->bydst, net->xfrm.state_bydst + h); 10358444cf71SThomas Egerer h = xfrm_src_hash(net, daddr, saddr, encap_family); 1036ae3fb6d3SFlorian Westphal hlist_add_head_rcu(&x->bysrc, net->xfrm.state_bysrc + h); 10371da177e4SLinus Torvalds if (x->id.spi) { 10388444cf71SThomas Egerer h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, encap_family); 1039ae3fb6d3SFlorian Westphal hlist_add_head_rcu(&x->byspi, net->xfrm.state_byspi + h); 10401da177e4SLinus Torvalds } 1041b27aeadbSAlexey Dobriyan x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires; 10429e0d57fdSYury Polyanskiy tasklet_hrtimer_start(&x->mtimer, ktime_set(net->xfrm.sysctl_acq_expires, 0), HRTIMER_MODE_REL); 10435447c5e4SAlexey Dobriyan net->xfrm.state_num++; 10445447c5e4SAlexey Dobriyan xfrm_hash_grow_check(net, x->bydst.next != NULL); 1045d737a580SFlorian Westphal spin_unlock_bh(&net->xfrm.xfrm_state_lock); 10461da177e4SLinus Torvalds } else { 10471da177e4SLinus Torvalds x->km.state = XFRM_STATE_DEAD; 104837b08e34SDavid S. Miller to_put = x; 10491da177e4SLinus Torvalds x = NULL; 10501da177e4SLinus Torvalds error = -ESRCH; 10511da177e4SLinus Torvalds } 10521da177e4SLinus Torvalds } 10531da177e4SLinus Torvalds out: 105402efdff7SFlorian Westphal if (x) { 105502efdff7SFlorian Westphal if (!xfrm_state_hold_rcu(x)) { 105602efdff7SFlorian Westphal *err = -EAGAIN; 105702efdff7SFlorian Westphal x = NULL; 105802efdff7SFlorian Westphal } 105902efdff7SFlorian Westphal } else { 10601da177e4SLinus Torvalds *err = acquire_in_progress ? -EAGAIN : error; 106102efdff7SFlorian Westphal } 1062d737a580SFlorian Westphal rcu_read_unlock(); 106337b08e34SDavid S. Miller if (to_put) 106437b08e34SDavid S. Miller xfrm_state_put(to_put); 1065b65e3d7bSFlorian Westphal 1066b65e3d7bSFlorian Westphal if (read_seqcount_retry(&xfrm_state_hash_generation, sequence)) { 1067b65e3d7bSFlorian Westphal *err = -EAGAIN; 1068b65e3d7bSFlorian Westphal if (x) { 1069b65e3d7bSFlorian Westphal xfrm_state_put(x); 1070b65e3d7bSFlorian Westphal x = NULL; 1071b65e3d7bSFlorian Westphal } 1072b65e3d7bSFlorian Westphal } 1073b65e3d7bSFlorian Westphal 10741da177e4SLinus Torvalds return x; 10751da177e4SLinus Torvalds } 10761da177e4SLinus Torvalds 1077628529b6SJamal Hadi Salim struct xfrm_state * 10787e652640SSteffen Klassert xfrm_stateonly_find(struct net *net, u32 mark, u32 if_id, 10795447c5e4SAlexey Dobriyan xfrm_address_t *daddr, xfrm_address_t *saddr, 1080628529b6SJamal Hadi Salim unsigned short family, u8 mode, u8 proto, u32 reqid) 1081628529b6SJamal Hadi Salim { 10824bda4f25SPavel Emelyanov unsigned int h; 1083628529b6SJamal Hadi Salim struct xfrm_state *rx = NULL, *x = NULL; 1084628529b6SJamal Hadi Salim 10854ae770bfSFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 10865447c5e4SAlexey Dobriyan h = xfrm_dst_hash(net, daddr, saddr, reqid, family); 1087b67bfe0dSSasha Levin hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) { 1088628529b6SJamal Hadi Salim if (x->props.family == family && 1089628529b6SJamal Hadi Salim x->props.reqid == reqid && 10903d6acfa7SJamal Hadi Salim (mark & x->mark.m) == x->mark.v && 10917e652640SSteffen Klassert x->if_id == if_id && 1092628529b6SJamal Hadi Salim !(x->props.flags & XFRM_STATE_WILDRECV) && 1093628529b6SJamal Hadi Salim xfrm_state_addr_check(x, daddr, saddr, family) && 1094628529b6SJamal Hadi Salim mode == x->props.mode && 1095628529b6SJamal Hadi Salim proto == x->id.proto && 1096628529b6SJamal Hadi Salim x->km.state == XFRM_STATE_VALID) { 1097628529b6SJamal Hadi Salim rx = x; 1098628529b6SJamal Hadi Salim break; 1099628529b6SJamal Hadi Salim } 1100628529b6SJamal Hadi Salim } 1101628529b6SJamal Hadi Salim 1102628529b6SJamal Hadi Salim if (rx) 1103628529b6SJamal Hadi Salim xfrm_state_hold(rx); 11044ae770bfSFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 1105628529b6SJamal Hadi Salim 1106628529b6SJamal Hadi Salim 1107628529b6SJamal Hadi Salim return rx; 1108628529b6SJamal Hadi Salim } 1109628529b6SJamal Hadi Salim EXPORT_SYMBOL(xfrm_stateonly_find); 1110628529b6SJamal Hadi Salim 1111c454997eSFan Du struct xfrm_state *xfrm_state_lookup_byspi(struct net *net, __be32 spi, 1112c454997eSFan Du unsigned short family) 1113c454997eSFan Du { 1114c454997eSFan Du struct xfrm_state *x; 1115c454997eSFan Du struct xfrm_state_walk *w; 1116c454997eSFan Du 1117c454997eSFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 1118c454997eSFan Du list_for_each_entry(w, &net->xfrm.state_all, all) { 1119c454997eSFan Du x = container_of(w, struct xfrm_state, km); 1120c454997eSFan Du if (x->props.family != family || 1121c454997eSFan Du x->id.spi != spi) 1122c454997eSFan Du continue; 1123c454997eSFan Du 1124c454997eSFan Du xfrm_state_hold(x); 1125bdddbf69SLi RongQing spin_unlock_bh(&net->xfrm.xfrm_state_lock); 1126c454997eSFan Du return x; 1127c454997eSFan Du } 1128c454997eSFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 1129c454997eSFan Du return NULL; 1130c454997eSFan Du } 1131c454997eSFan Du EXPORT_SYMBOL(xfrm_state_lookup_byspi); 1132c454997eSFan Du 11331da177e4SLinus Torvalds static void __xfrm_state_insert(struct xfrm_state *x) 11341da177e4SLinus Torvalds { 113598806f75SAlexey Dobriyan struct net *net = xs_net(x); 1136a624c108SDavid S. Miller unsigned int h; 11371da177e4SLinus Torvalds 113898806f75SAlexey Dobriyan list_add(&x->km.all, &net->xfrm.state_all); 11394c563f76STimo Teras 114098806f75SAlexey Dobriyan h = xfrm_dst_hash(net, &x->id.daddr, &x->props.saddr, 1141c1969f29SDavid S. Miller x->props.reqid, x->props.family); 1142ae3fb6d3SFlorian Westphal hlist_add_head_rcu(&x->bydst, net->xfrm.state_bydst + h); 11431da177e4SLinus Torvalds 114498806f75SAlexey Dobriyan h = xfrm_src_hash(net, &x->id.daddr, &x->props.saddr, x->props.family); 1145ae3fb6d3SFlorian Westphal hlist_add_head_rcu(&x->bysrc, net->xfrm.state_bysrc + h); 11466c44e6b7SMasahide NAKAMURA 11477b4dc360SMasahide NAKAMURA if (x->id.spi) { 114898806f75SAlexey Dobriyan h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, 11496c44e6b7SMasahide NAKAMURA x->props.family); 11501da177e4SLinus Torvalds 1151ae3fb6d3SFlorian Westphal hlist_add_head_rcu(&x->byspi, net->xfrm.state_byspi + h); 11526c44e6b7SMasahide NAKAMURA } 11531da177e4SLinus Torvalds 11549e0d57fdSYury Polyanskiy tasklet_hrtimer_start(&x->mtimer, ktime_set(1, 0), HRTIMER_MODE_REL); 1155a47f0ce0SDavid S. Miller if (x->replay_maxage) 1156a47f0ce0SDavid S. Miller mod_timer(&x->rtimer, jiffies + x->replay_maxage); 1157f8cd5488SJamal Hadi Salim 115898806f75SAlexey Dobriyan net->xfrm.state_num++; 1159f034b5d4SDavid S. Miller 116098806f75SAlexey Dobriyan xfrm_hash_grow_check(net, x->bydst.next != NULL); 11611da177e4SLinus Torvalds } 11621da177e4SLinus Torvalds 1163283bc9f3SFan Du /* net->xfrm.xfrm_state_lock is held */ 1164c7f5ea3aSDavid S. Miller static void __xfrm_state_bump_genids(struct xfrm_state *xnew) 1165c7f5ea3aSDavid S. Miller { 116698806f75SAlexey Dobriyan struct net *net = xs_net(xnew); 1167c7f5ea3aSDavid S. Miller unsigned short family = xnew->props.family; 1168c7f5ea3aSDavid S. Miller u32 reqid = xnew->props.reqid; 1169c7f5ea3aSDavid S. Miller struct xfrm_state *x; 1170c7f5ea3aSDavid S. Miller unsigned int h; 11713d6acfa7SJamal Hadi Salim u32 mark = xnew->mark.v & xnew->mark.m; 11727e652640SSteffen Klassert u32 if_id = xnew->if_id; 1173c7f5ea3aSDavid S. Miller 117498806f75SAlexey Dobriyan h = xfrm_dst_hash(net, &xnew->id.daddr, &xnew->props.saddr, reqid, family); 1175b67bfe0dSSasha Levin hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) { 1176c7f5ea3aSDavid S. Miller if (x->props.family == family && 1177c7f5ea3aSDavid S. Miller x->props.reqid == reqid && 11787e652640SSteffen Klassert x->if_id == if_id && 11793d6acfa7SJamal Hadi Salim (mark & x->mark.m) == x->mark.v && 118070e94e66SYOSHIFUJI Hideaki / 吉藤英明 xfrm_addr_equal(&x->id.daddr, &xnew->id.daddr, family) && 118170e94e66SYOSHIFUJI Hideaki / 吉藤英明 xfrm_addr_equal(&x->props.saddr, &xnew->props.saddr, family)) 118234996cb9SHerbert Xu x->genid++; 1183c7f5ea3aSDavid S. Miller } 1184c7f5ea3aSDavid S. Miller } 1185c7f5ea3aSDavid S. Miller 11861da177e4SLinus Torvalds void xfrm_state_insert(struct xfrm_state *x) 11871da177e4SLinus Torvalds { 1188283bc9f3SFan Du struct net *net = xs_net(x); 1189283bc9f3SFan Du 1190283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 1191c7f5ea3aSDavid S. Miller __xfrm_state_bump_genids(x); 11921da177e4SLinus Torvalds __xfrm_state_insert(x); 1193283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 11941da177e4SLinus Torvalds } 11951da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_insert); 11961da177e4SLinus Torvalds 1197283bc9f3SFan Du /* net->xfrm.xfrm_state_lock is held */ 1198e473fcb4SMathias Krause static struct xfrm_state *__find_acq_core(struct net *net, 1199e473fcb4SMathias Krause const struct xfrm_mark *m, 1200a70486f0SDavid S. Miller unsigned short family, u8 mode, 12017e652640SSteffen Klassert u32 reqid, u32 if_id, u8 proto, 1202a70486f0SDavid S. Miller const xfrm_address_t *daddr, 1203e473fcb4SMathias Krause const xfrm_address_t *saddr, 1204e473fcb4SMathias Krause int create) 12052770834cSDavid S. Miller { 12065447c5e4SAlexey Dobriyan unsigned int h = xfrm_dst_hash(net, daddr, saddr, reqid, family); 12072770834cSDavid S. Miller struct xfrm_state *x; 12083d6acfa7SJamal Hadi Salim u32 mark = m->v & m->m; 12092770834cSDavid S. Miller 1210b67bfe0dSSasha Levin hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) { 12112770834cSDavid S. Miller if (x->props.reqid != reqid || 12122770834cSDavid S. Miller x->props.mode != mode || 12132770834cSDavid S. Miller x->props.family != family || 12142770834cSDavid S. Miller x->km.state != XFRM_STATE_ACQ || 121575e252d9SJoy Latten x->id.spi != 0 || 12161802571bSWei Yongjun x->id.proto != proto || 12173d6acfa7SJamal Hadi Salim (mark & x->mark.m) != x->mark.v || 121870e94e66SYOSHIFUJI Hideaki / 吉藤英明 !xfrm_addr_equal(&x->id.daddr, daddr, family) || 121970e94e66SYOSHIFUJI Hideaki / 吉藤英明 !xfrm_addr_equal(&x->props.saddr, saddr, family)) 12202770834cSDavid S. Miller continue; 12212770834cSDavid S. Miller 12222770834cSDavid S. Miller xfrm_state_hold(x); 12232770834cSDavid S. Miller return x; 12242770834cSDavid S. Miller } 12252770834cSDavid S. Miller 12262770834cSDavid S. Miller if (!create) 12272770834cSDavid S. Miller return NULL; 12282770834cSDavid S. Miller 12295447c5e4SAlexey Dobriyan x = xfrm_state_alloc(net); 12302770834cSDavid S. Miller if (likely(x)) { 12312770834cSDavid S. Miller switch (family) { 12322770834cSDavid S. Miller case AF_INET: 12332770834cSDavid S. Miller x->sel.daddr.a4 = daddr->a4; 12342770834cSDavid S. Miller x->sel.saddr.a4 = saddr->a4; 12352770834cSDavid S. Miller x->sel.prefixlen_d = 32; 12362770834cSDavid S. Miller x->sel.prefixlen_s = 32; 12372770834cSDavid S. Miller x->props.saddr.a4 = saddr->a4; 12382770834cSDavid S. Miller x->id.daddr.a4 = daddr->a4; 12392770834cSDavid S. Miller break; 12402770834cSDavid S. Miller 12412770834cSDavid S. Miller case AF_INET6: 124215e318bdSJiri Benc x->sel.daddr.in6 = daddr->in6; 124315e318bdSJiri Benc x->sel.saddr.in6 = saddr->in6; 12442770834cSDavid S. Miller x->sel.prefixlen_d = 128; 12452770834cSDavid S. Miller x->sel.prefixlen_s = 128; 124615e318bdSJiri Benc x->props.saddr.in6 = saddr->in6; 124715e318bdSJiri Benc x->id.daddr.in6 = daddr->in6; 12482770834cSDavid S. Miller break; 12493ff50b79SStephen Hemminger } 12502770834cSDavid S. Miller 12512770834cSDavid S. Miller x->km.state = XFRM_STATE_ACQ; 12522770834cSDavid S. Miller x->id.proto = proto; 12532770834cSDavid S. Miller x->props.family = family; 12542770834cSDavid S. Miller x->props.mode = mode; 12552770834cSDavid S. Miller x->props.reqid = reqid; 12567e652640SSteffen Klassert x->if_id = if_id; 1257bd55775cSJamal Hadi Salim x->mark.v = m->v; 1258bd55775cSJamal Hadi Salim x->mark.m = m->m; 1259b27aeadbSAlexey Dobriyan x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires; 12602770834cSDavid S. Miller xfrm_state_hold(x); 12619e0d57fdSYury Polyanskiy tasklet_hrtimer_start(&x->mtimer, ktime_set(net->xfrm.sysctl_acq_expires, 0), HRTIMER_MODE_REL); 12625447c5e4SAlexey Dobriyan list_add(&x->km.all, &net->xfrm.state_all); 1263ae3fb6d3SFlorian Westphal hlist_add_head_rcu(&x->bydst, net->xfrm.state_bydst + h); 12645447c5e4SAlexey Dobriyan h = xfrm_src_hash(net, daddr, saddr, family); 1265ae3fb6d3SFlorian Westphal hlist_add_head_rcu(&x->bysrc, net->xfrm.state_bysrc + h); 1266918049f0SDavid S. Miller 12675447c5e4SAlexey Dobriyan net->xfrm.state_num++; 1268918049f0SDavid S. Miller 12695447c5e4SAlexey Dobriyan xfrm_hash_grow_check(net, x->bydst.next != NULL); 12702770834cSDavid S. Miller } 12712770834cSDavid S. Miller 12722770834cSDavid S. Miller return x; 12732770834cSDavid S. Miller } 12742770834cSDavid S. Miller 1275bd55775cSJamal Hadi Salim static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq); 12761da177e4SLinus Torvalds 12771da177e4SLinus Torvalds int xfrm_state_add(struct xfrm_state *x) 12781da177e4SLinus Torvalds { 12795447c5e4SAlexey Dobriyan struct net *net = xs_net(x); 128037b08e34SDavid S. Miller struct xfrm_state *x1, *to_put; 12811da177e4SLinus Torvalds int family; 12821da177e4SLinus Torvalds int err; 1283bd55775cSJamal Hadi Salim u32 mark = x->mark.v & x->mark.m; 1284eb2971b6SMasahide NAKAMURA int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY); 12851da177e4SLinus Torvalds 12861da177e4SLinus Torvalds family = x->props.family; 12871da177e4SLinus Torvalds 128837b08e34SDavid S. Miller to_put = NULL; 128937b08e34SDavid S. Miller 1290283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 12911da177e4SLinus Torvalds 1292edcd5821SDavid S. Miller x1 = __xfrm_state_locate(x, use_spi, family); 12931da177e4SLinus Torvalds if (x1) { 129437b08e34SDavid S. Miller to_put = x1; 12951da177e4SLinus Torvalds x1 = NULL; 12961da177e4SLinus Torvalds err = -EEXIST; 12971da177e4SLinus Torvalds goto out; 12981da177e4SLinus Torvalds } 12991da177e4SLinus Torvalds 1300eb2971b6SMasahide NAKAMURA if (use_spi && x->km.seq) { 1301bd55775cSJamal Hadi Salim x1 = __xfrm_find_acq_byseq(net, mark, x->km.seq); 130275e252d9SJoy Latten if (x1 && ((x1->id.proto != x->id.proto) || 130370e94e66SYOSHIFUJI Hideaki / 吉藤英明 !xfrm_addr_equal(&x1->id.daddr, &x->id.daddr, family))) { 130437b08e34SDavid S. Miller to_put = x1; 13051da177e4SLinus Torvalds x1 = NULL; 13061da177e4SLinus Torvalds } 13071da177e4SLinus Torvalds } 13081da177e4SLinus Torvalds 1309eb2971b6SMasahide NAKAMURA if (use_spi && !x1) 1310bd55775cSJamal Hadi Salim x1 = __find_acq_core(net, &x->mark, family, x->props.mode, 13117e652640SSteffen Klassert x->props.reqid, x->if_id, x->id.proto, 13121da177e4SLinus Torvalds &x->id.daddr, &x->props.saddr, 0); 13131da177e4SLinus Torvalds 1314c7f5ea3aSDavid S. Miller __xfrm_state_bump_genids(x); 13151da177e4SLinus Torvalds __xfrm_state_insert(x); 13161da177e4SLinus Torvalds err = 0; 13171da177e4SLinus Torvalds 13181da177e4SLinus Torvalds out: 1319283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 13201da177e4SLinus Torvalds 13211da177e4SLinus Torvalds if (x1) { 13221da177e4SLinus Torvalds xfrm_state_delete(x1); 13231da177e4SLinus Torvalds xfrm_state_put(x1); 13241da177e4SLinus Torvalds } 13251da177e4SLinus Torvalds 132637b08e34SDavid S. Miller if (to_put) 132737b08e34SDavid S. Miller xfrm_state_put(to_put); 132837b08e34SDavid S. Miller 13291da177e4SLinus Torvalds return err; 13301da177e4SLinus Torvalds } 13311da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_add); 13321da177e4SLinus Torvalds 133380c9abaaSShinta Sugimoto #ifdef CONFIG_XFRM_MIGRATE 13344ab47d47SAntony Antony static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, 13354ab47d47SAntony Antony struct xfrm_encap_tmpl *encap) 133680c9abaaSShinta Sugimoto { 133798806f75SAlexey Dobriyan struct net *net = xs_net(orig); 133898806f75SAlexey Dobriyan struct xfrm_state *x = xfrm_state_alloc(net); 133980c9abaaSShinta Sugimoto if (!x) 1340553f9118SHerbert Xu goto out; 134180c9abaaSShinta Sugimoto 134280c9abaaSShinta Sugimoto memcpy(&x->id, &orig->id, sizeof(x->id)); 134380c9abaaSShinta Sugimoto memcpy(&x->sel, &orig->sel, sizeof(x->sel)); 134480c9abaaSShinta Sugimoto memcpy(&x->lft, &orig->lft, sizeof(x->lft)); 134580c9abaaSShinta Sugimoto x->props.mode = orig->props.mode; 134680c9abaaSShinta Sugimoto x->props.replay_window = orig->props.replay_window; 134780c9abaaSShinta Sugimoto x->props.reqid = orig->props.reqid; 134880c9abaaSShinta Sugimoto x->props.family = orig->props.family; 134980c9abaaSShinta Sugimoto x->props.saddr = orig->props.saddr; 135080c9abaaSShinta Sugimoto 135180c9abaaSShinta Sugimoto if (orig->aalg) { 13524447bb33SMartin Willi x->aalg = xfrm_algo_auth_clone(orig->aalg); 135380c9abaaSShinta Sugimoto if (!x->aalg) 135480c9abaaSShinta Sugimoto goto error; 135580c9abaaSShinta Sugimoto } 135680c9abaaSShinta Sugimoto x->props.aalgo = orig->props.aalgo; 135780c9abaaSShinta Sugimoto 1358ee5c2317SSteffen Klassert if (orig->aead) { 1359ee5c2317SSteffen Klassert x->aead = xfrm_algo_aead_clone(orig->aead); 136075bf50f4SAntony Antony x->geniv = orig->geniv; 1361ee5c2317SSteffen Klassert if (!x->aead) 1362ee5c2317SSteffen Klassert goto error; 1363ee5c2317SSteffen Klassert } 136480c9abaaSShinta Sugimoto if (orig->ealg) { 136580c9abaaSShinta Sugimoto x->ealg = xfrm_algo_clone(orig->ealg); 136680c9abaaSShinta Sugimoto if (!x->ealg) 136780c9abaaSShinta Sugimoto goto error; 136880c9abaaSShinta Sugimoto } 136980c9abaaSShinta Sugimoto x->props.ealgo = orig->props.ealgo; 137080c9abaaSShinta Sugimoto 137180c9abaaSShinta Sugimoto if (orig->calg) { 137280c9abaaSShinta Sugimoto x->calg = xfrm_algo_clone(orig->calg); 137380c9abaaSShinta Sugimoto if (!x->calg) 137480c9abaaSShinta Sugimoto goto error; 137580c9abaaSShinta Sugimoto } 137680c9abaaSShinta Sugimoto x->props.calgo = orig->props.calgo; 137780c9abaaSShinta Sugimoto 13784ab47d47SAntony Antony if (encap || orig->encap) { 13794ab47d47SAntony Antony if (encap) 13804ab47d47SAntony Antony x->encap = kmemdup(encap, sizeof(*x->encap), 13814ab47d47SAntony Antony GFP_KERNEL); 13824ab47d47SAntony Antony else 13834ab47d47SAntony Antony x->encap = kmemdup(orig->encap, sizeof(*x->encap), 13844ab47d47SAntony Antony GFP_KERNEL); 13854ab47d47SAntony Antony 138680c9abaaSShinta Sugimoto if (!x->encap) 138780c9abaaSShinta Sugimoto goto error; 138880c9abaaSShinta Sugimoto } 138980c9abaaSShinta Sugimoto 139080c9abaaSShinta Sugimoto if (orig->coaddr) { 139180c9abaaSShinta Sugimoto x->coaddr = kmemdup(orig->coaddr, sizeof(*x->coaddr), 139280c9abaaSShinta Sugimoto GFP_KERNEL); 139380c9abaaSShinta Sugimoto if (!x->coaddr) 139480c9abaaSShinta Sugimoto goto error; 139580c9abaaSShinta Sugimoto } 139680c9abaaSShinta Sugimoto 1397af2f464eSSteffen Klassert if (orig->replay_esn) { 1398cc9ab60eSSteffen Klassert if (xfrm_replay_clone(x, orig)) 1399af2f464eSSteffen Klassert goto error; 1400af2f464eSSteffen Klassert } 1401af2f464eSSteffen Klassert 1402bd55775cSJamal Hadi Salim memcpy(&x->mark, &orig->mark, sizeof(x->mark)); 1403bd55775cSJamal Hadi Salim 1404cc9ab60eSSteffen Klassert if (xfrm_init_state(x) < 0) 140580c9abaaSShinta Sugimoto goto error; 140680c9abaaSShinta Sugimoto 140780c9abaaSShinta Sugimoto x->props.flags = orig->props.flags; 1408a947b0a9SNicolas Dichtel x->props.extra_flags = orig->props.extra_flags; 140980c9abaaSShinta Sugimoto 14107e652640SSteffen Klassert x->if_id = orig->if_id; 1411ee5c2317SSteffen Klassert x->tfcpad = orig->tfcpad; 1412ee5c2317SSteffen Klassert x->replay_maxdiff = orig->replay_maxdiff; 1413ee5c2317SSteffen Klassert x->replay_maxage = orig->replay_maxage; 141480c9abaaSShinta Sugimoto x->curlft.add_time = orig->curlft.add_time; 141580c9abaaSShinta Sugimoto x->km.state = orig->km.state; 141680c9abaaSShinta Sugimoto x->km.seq = orig->km.seq; 1417a486cd23SAntony Antony x->replay = orig->replay; 1418a486cd23SAntony Antony x->preplay = orig->preplay; 141980c9abaaSShinta Sugimoto 142080c9abaaSShinta Sugimoto return x; 142180c9abaaSShinta Sugimoto 142280c9abaaSShinta Sugimoto error: 1423553f9118SHerbert Xu xfrm_state_put(x); 1424553f9118SHerbert Xu out: 142580c9abaaSShinta Sugimoto return NULL; 142680c9abaaSShinta Sugimoto } 142780c9abaaSShinta Sugimoto 1428283bc9f3SFan Du struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *net) 142980c9abaaSShinta Sugimoto { 143080c9abaaSShinta Sugimoto unsigned int h; 14318c0cba22SSteffen Klassert struct xfrm_state *x = NULL; 14328c0cba22SSteffen Klassert 14338c0cba22SSteffen Klassert spin_lock_bh(&net->xfrm.xfrm_state_lock); 143480c9abaaSShinta Sugimoto 143580c9abaaSShinta Sugimoto if (m->reqid) { 1436283bc9f3SFan Du h = xfrm_dst_hash(net, &m->old_daddr, &m->old_saddr, 143780c9abaaSShinta Sugimoto m->reqid, m->old_family); 1438283bc9f3SFan Du hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) { 143980c9abaaSShinta Sugimoto if (x->props.mode != m->mode || 144080c9abaaSShinta Sugimoto x->id.proto != m->proto) 144180c9abaaSShinta Sugimoto continue; 144280c9abaaSShinta Sugimoto if (m->reqid && x->props.reqid != m->reqid) 144380c9abaaSShinta Sugimoto continue; 144470e94e66SYOSHIFUJI Hideaki / 吉藤英明 if (!xfrm_addr_equal(&x->id.daddr, &m->old_daddr, 144580c9abaaSShinta Sugimoto m->old_family) || 144670e94e66SYOSHIFUJI Hideaki / 吉藤英明 !xfrm_addr_equal(&x->props.saddr, &m->old_saddr, 144780c9abaaSShinta Sugimoto m->old_family)) 144880c9abaaSShinta Sugimoto continue; 144980c9abaaSShinta Sugimoto xfrm_state_hold(x); 14508c0cba22SSteffen Klassert break; 145180c9abaaSShinta Sugimoto } 145280c9abaaSShinta Sugimoto } else { 1453283bc9f3SFan Du h = xfrm_src_hash(net, &m->old_daddr, &m->old_saddr, 145480c9abaaSShinta Sugimoto m->old_family); 1455283bc9f3SFan Du hlist_for_each_entry(x, net->xfrm.state_bysrc+h, bysrc) { 145680c9abaaSShinta Sugimoto if (x->props.mode != m->mode || 145780c9abaaSShinta Sugimoto x->id.proto != m->proto) 145880c9abaaSShinta Sugimoto continue; 145970e94e66SYOSHIFUJI Hideaki / 吉藤英明 if (!xfrm_addr_equal(&x->id.daddr, &m->old_daddr, 146080c9abaaSShinta Sugimoto m->old_family) || 146170e94e66SYOSHIFUJI Hideaki / 吉藤英明 !xfrm_addr_equal(&x->props.saddr, &m->old_saddr, 146280c9abaaSShinta Sugimoto m->old_family)) 146380c9abaaSShinta Sugimoto continue; 146480c9abaaSShinta Sugimoto xfrm_state_hold(x); 14658c0cba22SSteffen Klassert break; 146680c9abaaSShinta Sugimoto } 146780c9abaaSShinta Sugimoto } 146880c9abaaSShinta Sugimoto 14698c0cba22SSteffen Klassert spin_unlock_bh(&net->xfrm.xfrm_state_lock); 14708c0cba22SSteffen Klassert 14718c0cba22SSteffen Klassert return x; 147280c9abaaSShinta Sugimoto } 147380c9abaaSShinta Sugimoto EXPORT_SYMBOL(xfrm_migrate_state_find); 147480c9abaaSShinta Sugimoto 147580c9abaaSShinta Sugimoto struct xfrm_state *xfrm_state_migrate(struct xfrm_state *x, 14764ab47d47SAntony Antony struct xfrm_migrate *m, 14774ab47d47SAntony Antony struct xfrm_encap_tmpl *encap) 147880c9abaaSShinta Sugimoto { 147980c9abaaSShinta Sugimoto struct xfrm_state *xc; 148080c9abaaSShinta Sugimoto 14814ab47d47SAntony Antony xc = xfrm_state_clone(x, encap); 148280c9abaaSShinta Sugimoto if (!xc) 148380c9abaaSShinta Sugimoto return NULL; 148480c9abaaSShinta Sugimoto 148580c9abaaSShinta Sugimoto memcpy(&xc->id.daddr, &m->new_daddr, sizeof(xc->id.daddr)); 148680c9abaaSShinta Sugimoto memcpy(&xc->props.saddr, &m->new_saddr, sizeof(xc->props.saddr)); 148780c9abaaSShinta Sugimoto 148880c9abaaSShinta Sugimoto /* add state */ 148970e94e66SYOSHIFUJI Hideaki / 吉藤英明 if (xfrm_addr_equal(&x->id.daddr, &m->new_daddr, m->new_family)) { 149080c9abaaSShinta Sugimoto /* a care is needed when the destination address of the 149180c9abaaSShinta Sugimoto state is to be updated as it is a part of triplet */ 149280c9abaaSShinta Sugimoto xfrm_state_insert(xc); 149380c9abaaSShinta Sugimoto } else { 1494cc9ab60eSSteffen Klassert if (xfrm_state_add(xc) < 0) 149580c9abaaSShinta Sugimoto goto error; 149680c9abaaSShinta Sugimoto } 149780c9abaaSShinta Sugimoto 149880c9abaaSShinta Sugimoto return xc; 149980c9abaaSShinta Sugimoto error: 150078347c8cSThomas Egerer xfrm_state_put(xc); 150180c9abaaSShinta Sugimoto return NULL; 150280c9abaaSShinta Sugimoto } 150380c9abaaSShinta Sugimoto EXPORT_SYMBOL(xfrm_state_migrate); 150480c9abaaSShinta Sugimoto #endif 150580c9abaaSShinta Sugimoto 15061da177e4SLinus Torvalds int xfrm_state_update(struct xfrm_state *x) 15071da177e4SLinus Torvalds { 150837b08e34SDavid S. Miller struct xfrm_state *x1, *to_put; 15091da177e4SLinus Torvalds int err; 1510eb2971b6SMasahide NAKAMURA int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY); 1511283bc9f3SFan Du struct net *net = xs_net(x); 15121da177e4SLinus Torvalds 151337b08e34SDavid S. Miller to_put = NULL; 151437b08e34SDavid S. Miller 1515283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 1516edcd5821SDavid S. Miller x1 = __xfrm_state_locate(x, use_spi, x->props.family); 15171da177e4SLinus Torvalds 15181da177e4SLinus Torvalds err = -ESRCH; 15191da177e4SLinus Torvalds if (!x1) 15201da177e4SLinus Torvalds goto out; 15211da177e4SLinus Torvalds 15221da177e4SLinus Torvalds if (xfrm_state_kern(x1)) { 152337b08e34SDavid S. Miller to_put = x1; 15241da177e4SLinus Torvalds err = -EEXIST; 15251da177e4SLinus Torvalds goto out; 15261da177e4SLinus Torvalds } 15271da177e4SLinus Torvalds 15281da177e4SLinus Torvalds if (x1->km.state == XFRM_STATE_ACQ) { 15291da177e4SLinus Torvalds __xfrm_state_insert(x); 15301da177e4SLinus Torvalds x = NULL; 15311da177e4SLinus Torvalds } 15321da177e4SLinus Torvalds err = 0; 15331da177e4SLinus Torvalds 15341da177e4SLinus Torvalds out: 1535283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 15361da177e4SLinus Torvalds 153737b08e34SDavid S. Miller if (to_put) 153837b08e34SDavid S. Miller xfrm_state_put(to_put); 153937b08e34SDavid S. Miller 15401da177e4SLinus Torvalds if (err) 15411da177e4SLinus Torvalds return err; 15421da177e4SLinus Torvalds 15431da177e4SLinus Torvalds if (!x) { 15441da177e4SLinus Torvalds xfrm_state_delete(x1); 15451da177e4SLinus Torvalds xfrm_state_put(x1); 15461da177e4SLinus Torvalds return 0; 15471da177e4SLinus Torvalds } 15481da177e4SLinus Torvalds 15491da177e4SLinus Torvalds err = -EINVAL; 15501da177e4SLinus Torvalds spin_lock_bh(&x1->lock); 15511da177e4SLinus Torvalds if (likely(x1->km.state == XFRM_STATE_VALID)) { 1552257a4b01SHerbert Xu if (x->encap && x1->encap && 1553257a4b01SHerbert Xu x->encap->encap_type == x1->encap->encap_type) 15541da177e4SLinus Torvalds memcpy(x1->encap, x->encap, sizeof(*x1->encap)); 1555257a4b01SHerbert Xu else if (x->encap || x1->encap) 1556257a4b01SHerbert Xu goto fail; 1557257a4b01SHerbert Xu 1558060f02a3SNoriaki TAKAMIYA if (x->coaddr && x1->coaddr) { 1559060f02a3SNoriaki TAKAMIYA memcpy(x1->coaddr, x->coaddr, sizeof(*x1->coaddr)); 1560060f02a3SNoriaki TAKAMIYA } 1561060f02a3SNoriaki TAKAMIYA if (!use_spi && memcmp(&x1->sel, &x->sel, sizeof(x1->sel))) 1562060f02a3SNoriaki TAKAMIYA memcpy(&x1->sel, &x->sel, sizeof(x1->sel)); 15631da177e4SLinus Torvalds memcpy(&x1->lft, &x->lft, sizeof(x1->lft)); 15641da177e4SLinus Torvalds x1->km.dying = 0; 15651da177e4SLinus Torvalds 15669e0d57fdSYury Polyanskiy tasklet_hrtimer_start(&x1->mtimer, ktime_set(1, 0), HRTIMER_MODE_REL); 15671da177e4SLinus Torvalds if (x1->curlft.use_time) 15681da177e4SLinus Torvalds xfrm_state_check_expire(x1); 15691da177e4SLinus Torvalds 15705baf4f9cSNathan Harold if (x->props.smark.m || x->props.smark.v || x->if_id) { 15716d8e85ffSNathan Harold spin_lock_bh(&net->xfrm.xfrm_state_lock); 15726d8e85ffSNathan Harold 15735baf4f9cSNathan Harold if (x->props.smark.m || x->props.smark.v) 15746d8e85ffSNathan Harold x1->props.smark = x->props.smark; 15756d8e85ffSNathan Harold 15765baf4f9cSNathan Harold if (x->if_id) 15775baf4f9cSNathan Harold x1->if_id = x->if_id; 15785baf4f9cSNathan Harold 15796d8e85ffSNathan Harold __xfrm_state_bump_genids(x1); 15806d8e85ffSNathan Harold spin_unlock_bh(&net->xfrm.xfrm_state_lock); 15816d8e85ffSNathan Harold } 15826d8e85ffSNathan Harold 15831da177e4SLinus Torvalds err = 0; 15848fcbc637STushar Gohad x->km.state = XFRM_STATE_DEAD; 15858fcbc637STushar Gohad __xfrm_state_put(x); 15861da177e4SLinus Torvalds } 1587257a4b01SHerbert Xu 1588257a4b01SHerbert Xu fail: 15891da177e4SLinus Torvalds spin_unlock_bh(&x1->lock); 15901da177e4SLinus Torvalds 15911da177e4SLinus Torvalds xfrm_state_put(x1); 15921da177e4SLinus Torvalds 15931da177e4SLinus Torvalds return err; 15941da177e4SLinus Torvalds } 15951da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_update); 15961da177e4SLinus Torvalds 15971da177e4SLinus Torvalds int xfrm_state_check_expire(struct xfrm_state *x) 15981da177e4SLinus Torvalds { 15991da177e4SLinus Torvalds if (!x->curlft.use_time) 1600386c5680SArnd Bergmann x->curlft.use_time = ktime_get_real_seconds(); 16011da177e4SLinus Torvalds 16021da177e4SLinus Torvalds if (x->curlft.bytes >= x->lft.hard_byte_limit || 16031da177e4SLinus Torvalds x->curlft.packets >= x->lft.hard_packet_limit) { 16044666faabSHerbert Xu x->km.state = XFRM_STATE_EXPIRED; 16058b0e1953SThomas Gleixner tasklet_hrtimer_start(&x->mtimer, 0, HRTIMER_MODE_REL); 16061da177e4SLinus Torvalds return -EINVAL; 16071da177e4SLinus Torvalds } 16081da177e4SLinus Torvalds 16091da177e4SLinus Torvalds if (!x->km.dying && 16101da177e4SLinus Torvalds (x->curlft.bytes >= x->lft.soft_byte_limit || 16114666faabSHerbert Xu x->curlft.packets >= x->lft.soft_packet_limit)) { 16124666faabSHerbert Xu x->km.dying = 1; 161353bc6b4dSJamal Hadi Salim km_state_expired(x, 0, 0); 16144666faabSHerbert Xu } 16151da177e4SLinus Torvalds return 0; 16161da177e4SLinus Torvalds } 16171da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_check_expire); 16181da177e4SLinus Torvalds 16191da177e4SLinus Torvalds struct xfrm_state * 1620a70486f0SDavid S. Miller xfrm_state_lookup(struct net *net, u32 mark, const xfrm_address_t *daddr, __be32 spi, 1621bd55775cSJamal Hadi Salim u8 proto, unsigned short family) 16221da177e4SLinus Torvalds { 16231da177e4SLinus Torvalds struct xfrm_state *x; 16241da177e4SLinus Torvalds 1625c2f672fcSFlorian Westphal rcu_read_lock(); 1626bd55775cSJamal Hadi Salim x = __xfrm_state_lookup(net, mark, daddr, spi, proto, family); 1627c2f672fcSFlorian Westphal rcu_read_unlock(); 16281da177e4SLinus Torvalds return x; 16291da177e4SLinus Torvalds } 16301da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_lookup); 16311da177e4SLinus Torvalds 16321da177e4SLinus Torvalds struct xfrm_state * 1633bd55775cSJamal Hadi Salim xfrm_state_lookup_byaddr(struct net *net, u32 mark, 1634a70486f0SDavid S. Miller const xfrm_address_t *daddr, const xfrm_address_t *saddr, 1635eb2971b6SMasahide NAKAMURA u8 proto, unsigned short family) 1636eb2971b6SMasahide NAKAMURA { 1637eb2971b6SMasahide NAKAMURA struct xfrm_state *x; 1638eb2971b6SMasahide NAKAMURA 1639283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 1640bd55775cSJamal Hadi Salim x = __xfrm_state_lookup_byaddr(net, mark, daddr, saddr, proto, family); 1641283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 1642eb2971b6SMasahide NAKAMURA return x; 1643eb2971b6SMasahide NAKAMURA } 1644eb2971b6SMasahide NAKAMURA EXPORT_SYMBOL(xfrm_state_lookup_byaddr); 1645eb2971b6SMasahide NAKAMURA 1646eb2971b6SMasahide NAKAMURA struct xfrm_state * 1647e473fcb4SMathias Krause xfrm_find_acq(struct net *net, const struct xfrm_mark *mark, u8 mode, u32 reqid, 16487e652640SSteffen Klassert u32 if_id, u8 proto, const xfrm_address_t *daddr, 1649e473fcb4SMathias Krause const xfrm_address_t *saddr, int create, unsigned short family) 16501da177e4SLinus Torvalds { 16511da177e4SLinus Torvalds struct xfrm_state *x; 16521da177e4SLinus Torvalds 1653283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 16547e652640SSteffen Klassert x = __find_acq_core(net, mark, family, mode, reqid, if_id, proto, daddr, saddr, create); 1655283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 16562770834cSDavid S. Miller 16571da177e4SLinus Torvalds return x; 16581da177e4SLinus Torvalds } 16591da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_find_acq); 16601da177e4SLinus Torvalds 166141a49cc3SMasahide NAKAMURA #ifdef CONFIG_XFRM_SUB_POLICY 166241a49cc3SMasahide NAKAMURA int 166341a49cc3SMasahide NAKAMURA xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n, 1664283bc9f3SFan Du unsigned short family, struct net *net) 166541a49cc3SMasahide NAKAMURA { 16663f5a95adSKoichiro Den int i; 166741a49cc3SMasahide NAKAMURA int err = 0; 166841a49cc3SMasahide NAKAMURA struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); 166941a49cc3SMasahide NAKAMURA if (!afinfo) 167041a49cc3SMasahide NAKAMURA return -EAFNOSUPPORT; 167141a49cc3SMasahide NAKAMURA 1672283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); /*FIXME*/ 167341a49cc3SMasahide NAKAMURA if (afinfo->tmpl_sort) 167441a49cc3SMasahide NAKAMURA err = afinfo->tmpl_sort(dst, src, n); 16753f5a95adSKoichiro Den else 16763f5a95adSKoichiro Den for (i = 0; i < n; i++) 16773f5a95adSKoichiro Den dst[i] = src[i]; 1678283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 1679af5d27c4SFlorian Westphal rcu_read_unlock(); 168041a49cc3SMasahide NAKAMURA return err; 168141a49cc3SMasahide NAKAMURA } 168241a49cc3SMasahide NAKAMURA EXPORT_SYMBOL(xfrm_tmpl_sort); 168341a49cc3SMasahide NAKAMURA 168441a49cc3SMasahide NAKAMURA int 168541a49cc3SMasahide NAKAMURA xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n, 168641a49cc3SMasahide NAKAMURA unsigned short family) 168741a49cc3SMasahide NAKAMURA { 16883f5a95adSKoichiro Den int i; 168941a49cc3SMasahide NAKAMURA int err = 0; 169041a49cc3SMasahide NAKAMURA struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); 169135ea790dSSteffen Klassert struct net *net = xs_net(*src); 1692283bc9f3SFan Du 169341a49cc3SMasahide NAKAMURA if (!afinfo) 169441a49cc3SMasahide NAKAMURA return -EAFNOSUPPORT; 169541a49cc3SMasahide NAKAMURA 1696283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 169741a49cc3SMasahide NAKAMURA if (afinfo->state_sort) 169841a49cc3SMasahide NAKAMURA err = afinfo->state_sort(dst, src, n); 16993f5a95adSKoichiro Den else 17003f5a95adSKoichiro Den for (i = 0; i < n; i++) 17013f5a95adSKoichiro Den dst[i] = src[i]; 1702283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 1703af5d27c4SFlorian Westphal rcu_read_unlock(); 170441a49cc3SMasahide NAKAMURA return err; 170541a49cc3SMasahide NAKAMURA } 170641a49cc3SMasahide NAKAMURA EXPORT_SYMBOL(xfrm_state_sort); 170741a49cc3SMasahide NAKAMURA #endif 170841a49cc3SMasahide NAKAMURA 17091da177e4SLinus Torvalds /* Silly enough, but I'm lazy to build resolution list */ 17101da177e4SLinus Torvalds 1711bd55775cSJamal Hadi Salim static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq) 17121da177e4SLinus Torvalds { 17131da177e4SLinus Torvalds int i; 17141da177e4SLinus Torvalds 17155447c5e4SAlexey Dobriyan for (i = 0; i <= net->xfrm.state_hmask; i++) { 17168f126e37SDavid S. Miller struct xfrm_state *x; 17178f126e37SDavid S. Miller 1718b67bfe0dSSasha Levin hlist_for_each_entry(x, net->xfrm.state_bydst+i, bydst) { 17198f126e37SDavid S. Miller if (x->km.seq == seq && 17203d6acfa7SJamal Hadi Salim (mark & x->mark.m) == x->mark.v && 17218f126e37SDavid S. Miller x->km.state == XFRM_STATE_ACQ) { 17221da177e4SLinus Torvalds xfrm_state_hold(x); 17231da177e4SLinus Torvalds return x; 17241da177e4SLinus Torvalds } 17251da177e4SLinus Torvalds } 17261da177e4SLinus Torvalds } 17271da177e4SLinus Torvalds return NULL; 17281da177e4SLinus Torvalds } 17291da177e4SLinus Torvalds 1730bd55775cSJamal Hadi Salim struct xfrm_state *xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq) 17311da177e4SLinus Torvalds { 17321da177e4SLinus Torvalds struct xfrm_state *x; 17331da177e4SLinus Torvalds 1734283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 1735bd55775cSJamal Hadi Salim x = __xfrm_find_acq_byseq(net, mark, seq); 1736283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 17371da177e4SLinus Torvalds return x; 17381da177e4SLinus Torvalds } 17391da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_find_acq_byseq); 17401da177e4SLinus Torvalds 17411da177e4SLinus Torvalds u32 xfrm_get_acqseq(void) 17421da177e4SLinus Torvalds { 17431da177e4SLinus Torvalds u32 res; 17446836b9bdSjamal static atomic_t acqseq; 17451da177e4SLinus Torvalds 17466836b9bdSjamal do { 17476836b9bdSjamal res = atomic_inc_return(&acqseq); 17486836b9bdSjamal } while (!res); 17496836b9bdSjamal 17501da177e4SLinus Torvalds return res; 17511da177e4SLinus Torvalds } 17521da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_get_acqseq); 17531da177e4SLinus Torvalds 1754776e9dd9SFan Du int verify_spi_info(u8 proto, u32 min, u32 max) 1755776e9dd9SFan Du { 1756776e9dd9SFan Du switch (proto) { 1757776e9dd9SFan Du case IPPROTO_AH: 1758776e9dd9SFan Du case IPPROTO_ESP: 1759776e9dd9SFan Du break; 1760776e9dd9SFan Du 1761776e9dd9SFan Du case IPPROTO_COMP: 1762776e9dd9SFan Du /* IPCOMP spi is 16-bits. */ 1763776e9dd9SFan Du if (max >= 0x10000) 1764776e9dd9SFan Du return -EINVAL; 1765776e9dd9SFan Du break; 1766776e9dd9SFan Du 1767776e9dd9SFan Du default: 1768776e9dd9SFan Du return -EINVAL; 1769776e9dd9SFan Du } 1770776e9dd9SFan Du 1771776e9dd9SFan Du if (min > max) 1772776e9dd9SFan Du return -EINVAL; 1773776e9dd9SFan Du 1774776e9dd9SFan Du return 0; 1775776e9dd9SFan Du } 1776776e9dd9SFan Du EXPORT_SYMBOL(verify_spi_info); 1777776e9dd9SFan Du 1778658b219eSHerbert Xu int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high) 17791da177e4SLinus Torvalds { 1780221df1edSAlexey Dobriyan struct net *net = xs_net(x); 1781f034b5d4SDavid S. Miller unsigned int h; 17821da177e4SLinus Torvalds struct xfrm_state *x0; 1783658b219eSHerbert Xu int err = -ENOENT; 1784658b219eSHerbert Xu __be32 minspi = htonl(low); 1785658b219eSHerbert Xu __be32 maxspi = htonl(high); 1786bd55775cSJamal Hadi Salim u32 mark = x->mark.v & x->mark.m; 17871da177e4SLinus Torvalds 1788658b219eSHerbert Xu spin_lock_bh(&x->lock); 1789658b219eSHerbert Xu if (x->km.state == XFRM_STATE_DEAD) 1790658b219eSHerbert Xu goto unlock; 1791658b219eSHerbert Xu 1792658b219eSHerbert Xu err = 0; 17931da177e4SLinus Torvalds if (x->id.spi) 1794658b219eSHerbert Xu goto unlock; 1795658b219eSHerbert Xu 1796658b219eSHerbert Xu err = -ENOENT; 17971da177e4SLinus Torvalds 17981da177e4SLinus Torvalds if (minspi == maxspi) { 1799bd55775cSJamal Hadi Salim x0 = xfrm_state_lookup(net, mark, &x->id.daddr, minspi, x->id.proto, x->props.family); 18001da177e4SLinus Torvalds if (x0) { 18011da177e4SLinus Torvalds xfrm_state_put(x0); 1802658b219eSHerbert Xu goto unlock; 18031da177e4SLinus Torvalds } 18041da177e4SLinus Torvalds x->id.spi = minspi; 18051da177e4SLinus Torvalds } else { 18061da177e4SLinus Torvalds u32 spi = 0; 180726977b4eSAl Viro for (h = 0; h < high-low+1; h++) { 180863862b5bSAruna-Hewapathirane spi = low + prandom_u32()%(high-low+1); 1809bd55775cSJamal Hadi Salim x0 = xfrm_state_lookup(net, mark, &x->id.daddr, htonl(spi), x->id.proto, x->props.family); 18101da177e4SLinus Torvalds if (x0 == NULL) { 18111da177e4SLinus Torvalds x->id.spi = htonl(spi); 18121da177e4SLinus Torvalds break; 18131da177e4SLinus Torvalds } 18141da177e4SLinus Torvalds xfrm_state_put(x0); 18151da177e4SLinus Torvalds } 18161da177e4SLinus Torvalds } 18171da177e4SLinus Torvalds if (x->id.spi) { 1818283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 181912604d8aSAlexey Dobriyan h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, x->props.family); 1820ae3fb6d3SFlorian Westphal hlist_add_head_rcu(&x->byspi, net->xfrm.state_byspi + h); 1821283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 1822658b219eSHerbert Xu 1823658b219eSHerbert Xu err = 0; 18241da177e4SLinus Torvalds } 1825658b219eSHerbert Xu 1826658b219eSHerbert Xu unlock: 1827658b219eSHerbert Xu spin_unlock_bh(&x->lock); 1828658b219eSHerbert Xu 1829658b219eSHerbert Xu return err; 18301da177e4SLinus Torvalds } 18311da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_alloc_spi); 18321da177e4SLinus Torvalds 1833d3623099SNicolas Dichtel static bool __xfrm_state_filter_match(struct xfrm_state *x, 1834870a2df4SNicolas Dichtel struct xfrm_address_filter *filter) 1835d3623099SNicolas Dichtel { 1836d3623099SNicolas Dichtel if (filter) { 1837d3623099SNicolas Dichtel if ((filter->family == AF_INET || 1838d3623099SNicolas Dichtel filter->family == AF_INET6) && 1839d3623099SNicolas Dichtel x->props.family != filter->family) 1840d3623099SNicolas Dichtel return false; 1841d3623099SNicolas Dichtel 1842d3623099SNicolas Dichtel return addr_match(&x->props.saddr, &filter->saddr, 1843d3623099SNicolas Dichtel filter->splen) && 1844d3623099SNicolas Dichtel addr_match(&x->id.daddr, &filter->daddr, 1845d3623099SNicolas Dichtel filter->dplen); 1846d3623099SNicolas Dichtel } 1847d3623099SNicolas Dichtel return true; 1848d3623099SNicolas Dichtel } 1849d3623099SNicolas Dichtel 1850284fa7daSAlexey Dobriyan int xfrm_state_walk(struct net *net, struct xfrm_state_walk *walk, 18514c563f76STimo Teras int (*func)(struct xfrm_state *, int, void*), 18521da177e4SLinus Torvalds void *data) 18531da177e4SLinus Torvalds { 185412a169e7SHerbert Xu struct xfrm_state *state; 185512a169e7SHerbert Xu struct xfrm_state_walk *x; 18561da177e4SLinus Torvalds int err = 0; 18571da177e4SLinus Torvalds 185812a169e7SHerbert Xu if (walk->seq != 0 && list_empty(&walk->all)) 18594c563f76STimo Teras return 0; 18604c563f76STimo Teras 1861283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 186212a169e7SHerbert Xu if (list_empty(&walk->all)) 1863284fa7daSAlexey Dobriyan x = list_first_entry(&net->xfrm.state_all, struct xfrm_state_walk, all); 186412a169e7SHerbert Xu else 186580077702SLi RongQing x = list_first_entry(&walk->all, struct xfrm_state_walk, all); 1866284fa7daSAlexey Dobriyan list_for_each_entry_from(x, &net->xfrm.state_all, all) { 186712a169e7SHerbert Xu if (x->state == XFRM_STATE_DEAD) 18684c563f76STimo Teras continue; 186912a169e7SHerbert Xu state = container_of(x, struct xfrm_state, km); 187012a169e7SHerbert Xu if (!xfrm_id_proto_match(state->id.proto, walk->proto)) 187194b9bb54SJamal Hadi Salim continue; 1872d3623099SNicolas Dichtel if (!__xfrm_state_filter_match(state, walk->filter)) 1873d3623099SNicolas Dichtel continue; 187412a169e7SHerbert Xu err = func(state, walk->seq, data); 18754c563f76STimo Teras if (err) { 187612a169e7SHerbert Xu list_move_tail(&walk->all, &x->all); 187794b9bb54SJamal Hadi Salim goto out; 187894b9bb54SJamal Hadi Salim } 187912a169e7SHerbert Xu walk->seq++; 18804c563f76STimo Teras } 188112a169e7SHerbert Xu if (walk->seq == 0) { 18821da177e4SLinus Torvalds err = -ENOENT; 18831da177e4SLinus Torvalds goto out; 18841da177e4SLinus Torvalds } 188512a169e7SHerbert Xu list_del_init(&walk->all); 18861da177e4SLinus Torvalds out: 1887283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 18881da177e4SLinus Torvalds return err; 18891da177e4SLinus Torvalds } 18901da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_walk); 18911da177e4SLinus Torvalds 1892d3623099SNicolas Dichtel void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto, 1893870a2df4SNicolas Dichtel struct xfrm_address_filter *filter) 18945c182458SHerbert Xu { 189512a169e7SHerbert Xu INIT_LIST_HEAD(&walk->all); 18965c182458SHerbert Xu walk->proto = proto; 189712a169e7SHerbert Xu walk->state = XFRM_STATE_DEAD; 189812a169e7SHerbert Xu walk->seq = 0; 1899d3623099SNicolas Dichtel walk->filter = filter; 19005c182458SHerbert Xu } 19015c182458SHerbert Xu EXPORT_SYMBOL(xfrm_state_walk_init); 19025c182458SHerbert Xu 1903283bc9f3SFan Du void xfrm_state_walk_done(struct xfrm_state_walk *walk, struct net *net) 1904abb81c4fSHerbert Xu { 1905d3623099SNicolas Dichtel kfree(walk->filter); 1906d3623099SNicolas Dichtel 190712a169e7SHerbert Xu if (list_empty(&walk->all)) 19085c182458SHerbert Xu return; 19095c182458SHerbert Xu 1910283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 191112a169e7SHerbert Xu list_del(&walk->all); 1912283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 1913abb81c4fSHerbert Xu } 1914abb81c4fSHerbert Xu EXPORT_SYMBOL(xfrm_state_walk_done); 1915abb81c4fSHerbert Xu 1916e99e88a9SKees Cook static void xfrm_replay_timer_handler(struct timer_list *t) 1917f8cd5488SJamal Hadi Salim { 1918e99e88a9SKees Cook struct xfrm_state *x = from_timer(x, t, rtimer); 1919f8cd5488SJamal Hadi Salim 1920f8cd5488SJamal Hadi Salim spin_lock(&x->lock); 1921f8cd5488SJamal Hadi Salim 19222717096aSJamal Hadi Salim if (x->km.state == XFRM_STATE_VALID) { 1923a6483b79SAlexey Dobriyan if (xfrm_aevent_is_on(xs_net(x))) 19249fdc4883SSteffen Klassert x->repl->notify(x, XFRM_REPLAY_TIMEOUT); 19252717096aSJamal Hadi Salim else 19262717096aSJamal Hadi Salim x->xflags |= XFRM_TIME_DEFER; 19272717096aSJamal Hadi Salim } 1928f8cd5488SJamal Hadi Salim 1929f8cd5488SJamal Hadi Salim spin_unlock(&x->lock); 1930f8cd5488SJamal Hadi Salim } 1931f8cd5488SJamal Hadi Salim 1932df01812eSDenis Cheng static LIST_HEAD(xfrm_km_list); 19331da177e4SLinus Torvalds 1934214e005bSDavid S. Miller void km_policy_notify(struct xfrm_policy *xp, int dir, const struct km_event *c) 19351da177e4SLinus Torvalds { 19361da177e4SLinus Torvalds struct xfrm_mgr *km; 19371da177e4SLinus Torvalds 193885168c00SCong Wang rcu_read_lock(); 193985168c00SCong Wang list_for_each_entry_rcu(km, &xfrm_km_list, list) 194026b15dadSJamal Hadi Salim if (km->notify_policy) 194126b15dadSJamal Hadi Salim km->notify_policy(xp, dir, c); 194285168c00SCong Wang rcu_read_unlock(); 194326b15dadSJamal Hadi Salim } 194426b15dadSJamal Hadi Salim 1945214e005bSDavid S. Miller void km_state_notify(struct xfrm_state *x, const struct km_event *c) 194626b15dadSJamal Hadi Salim { 194726b15dadSJamal Hadi Salim struct xfrm_mgr *km; 194885168c00SCong Wang rcu_read_lock(); 194985168c00SCong Wang list_for_each_entry_rcu(km, &xfrm_km_list, list) 195026b15dadSJamal Hadi Salim if (km->notify) 195126b15dadSJamal Hadi Salim km->notify(x, c); 195285168c00SCong Wang rcu_read_unlock(); 195326b15dadSJamal Hadi Salim } 195426b15dadSJamal Hadi Salim 195526b15dadSJamal Hadi Salim EXPORT_SYMBOL(km_policy_notify); 195626b15dadSJamal Hadi Salim EXPORT_SYMBOL(km_state_notify); 195726b15dadSJamal Hadi Salim 195815e47304SEric W. Biederman void km_state_expired(struct xfrm_state *x, int hard, u32 portid) 195926b15dadSJamal Hadi Salim { 196026b15dadSJamal Hadi Salim struct km_event c; 196126b15dadSJamal Hadi Salim 1962bf08867fSHerbert Xu c.data.hard = hard; 196315e47304SEric W. Biederman c.portid = portid; 1964f60f6b8fSHerbert Xu c.event = XFRM_MSG_EXPIRE; 196526b15dadSJamal Hadi Salim km_state_notify(x, &c); 19661da177e4SLinus Torvalds } 19671da177e4SLinus Torvalds 196853bc6b4dSJamal Hadi Salim EXPORT_SYMBOL(km_state_expired); 196926b15dadSJamal Hadi Salim /* 197026b15dadSJamal Hadi Salim * We send to all registered managers regardless of failure 197126b15dadSJamal Hadi Salim * We are happy with one success 197226b15dadSJamal Hadi Salim */ 1973980ebd25SJamal Hadi Salim int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol) 19741da177e4SLinus Torvalds { 197526b15dadSJamal Hadi Salim int err = -EINVAL, acqret; 19761da177e4SLinus Torvalds struct xfrm_mgr *km; 19771da177e4SLinus Torvalds 197885168c00SCong Wang rcu_read_lock(); 197985168c00SCong Wang list_for_each_entry_rcu(km, &xfrm_km_list, list) { 198065e0736bSFan Du acqret = km->acquire(x, t, pol); 198126b15dadSJamal Hadi Salim if (!acqret) 198226b15dadSJamal Hadi Salim err = acqret; 19831da177e4SLinus Torvalds } 198485168c00SCong Wang rcu_read_unlock(); 19851da177e4SLinus Torvalds return err; 19861da177e4SLinus Torvalds } 1987980ebd25SJamal Hadi Salim EXPORT_SYMBOL(km_query); 19881da177e4SLinus Torvalds 19895d36b180SAl Viro int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport) 19901da177e4SLinus Torvalds { 19911da177e4SLinus Torvalds int err = -EINVAL; 19921da177e4SLinus Torvalds struct xfrm_mgr *km; 19931da177e4SLinus Torvalds 199485168c00SCong Wang rcu_read_lock(); 199585168c00SCong Wang list_for_each_entry_rcu(km, &xfrm_km_list, list) { 19961da177e4SLinus Torvalds if (km->new_mapping) 19971da177e4SLinus Torvalds err = km->new_mapping(x, ipaddr, sport); 19981da177e4SLinus Torvalds if (!err) 19991da177e4SLinus Torvalds break; 20001da177e4SLinus Torvalds } 200185168c00SCong Wang rcu_read_unlock(); 20021da177e4SLinus Torvalds return err; 20031da177e4SLinus Torvalds } 20041da177e4SLinus Torvalds EXPORT_SYMBOL(km_new_mapping); 20051da177e4SLinus Torvalds 200615e47304SEric W. Biederman void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 portid) 20071da177e4SLinus Torvalds { 200826b15dadSJamal Hadi Salim struct km_event c; 20091da177e4SLinus Torvalds 2010bf08867fSHerbert Xu c.data.hard = hard; 201115e47304SEric W. Biederman c.portid = portid; 2012f60f6b8fSHerbert Xu c.event = XFRM_MSG_POLEXPIRE; 201326b15dadSJamal Hadi Salim km_policy_notify(pol, dir, &c); 20141da177e4SLinus Torvalds } 2015a70fcb0bSDavid S. Miller EXPORT_SYMBOL(km_policy_expired); 20161da177e4SLinus Torvalds 20172d60abc2SEric Dumazet #ifdef CONFIG_XFRM_MIGRATE 2018183cad12SDavid S. Miller int km_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, 2019183cad12SDavid S. Miller const struct xfrm_migrate *m, int num_migrate, 20208bafd730SAntony Antony const struct xfrm_kmaddress *k, 20218bafd730SAntony Antony const struct xfrm_encap_tmpl *encap) 202280c9abaaSShinta Sugimoto { 202380c9abaaSShinta Sugimoto int err = -EINVAL; 202480c9abaaSShinta Sugimoto int ret; 202580c9abaaSShinta Sugimoto struct xfrm_mgr *km; 202680c9abaaSShinta Sugimoto 202785168c00SCong Wang rcu_read_lock(); 202885168c00SCong Wang list_for_each_entry_rcu(km, &xfrm_km_list, list) { 202980c9abaaSShinta Sugimoto if (km->migrate) { 20308bafd730SAntony Antony ret = km->migrate(sel, dir, type, m, num_migrate, k, 20318bafd730SAntony Antony encap); 203280c9abaaSShinta Sugimoto if (!ret) 203380c9abaaSShinta Sugimoto err = ret; 203480c9abaaSShinta Sugimoto } 203580c9abaaSShinta Sugimoto } 203685168c00SCong Wang rcu_read_unlock(); 203780c9abaaSShinta Sugimoto return err; 203880c9abaaSShinta Sugimoto } 203980c9abaaSShinta Sugimoto EXPORT_SYMBOL(km_migrate); 20402d60abc2SEric Dumazet #endif 204180c9abaaSShinta Sugimoto 2042db983c11SAlexey Dobriyan int km_report(struct net *net, u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr) 204397a64b45SMasahide NAKAMURA { 204497a64b45SMasahide NAKAMURA int err = -EINVAL; 204597a64b45SMasahide NAKAMURA int ret; 204697a64b45SMasahide NAKAMURA struct xfrm_mgr *km; 204797a64b45SMasahide NAKAMURA 204885168c00SCong Wang rcu_read_lock(); 204985168c00SCong Wang list_for_each_entry_rcu(km, &xfrm_km_list, list) { 205097a64b45SMasahide NAKAMURA if (km->report) { 2051db983c11SAlexey Dobriyan ret = km->report(net, proto, sel, addr); 205297a64b45SMasahide NAKAMURA if (!ret) 205397a64b45SMasahide NAKAMURA err = ret; 205497a64b45SMasahide NAKAMURA } 205597a64b45SMasahide NAKAMURA } 205685168c00SCong Wang rcu_read_unlock(); 205797a64b45SMasahide NAKAMURA return err; 205897a64b45SMasahide NAKAMURA } 205997a64b45SMasahide NAKAMURA EXPORT_SYMBOL(km_report); 206097a64b45SMasahide NAKAMURA 20610f24558eSHoria Geanta bool km_is_alive(const struct km_event *c) 20620f24558eSHoria Geanta { 20630f24558eSHoria Geanta struct xfrm_mgr *km; 20640f24558eSHoria Geanta bool is_alive = false; 20650f24558eSHoria Geanta 20660f24558eSHoria Geanta rcu_read_lock(); 20670f24558eSHoria Geanta list_for_each_entry_rcu(km, &xfrm_km_list, list) { 20680f24558eSHoria Geanta if (km->is_alive && km->is_alive(c)) { 20690f24558eSHoria Geanta is_alive = true; 20700f24558eSHoria Geanta break; 20710f24558eSHoria Geanta } 20720f24558eSHoria Geanta } 20730f24558eSHoria Geanta rcu_read_unlock(); 20740f24558eSHoria Geanta 20750f24558eSHoria Geanta return is_alive; 20760f24558eSHoria Geanta } 20770f24558eSHoria Geanta EXPORT_SYMBOL(km_is_alive); 20780f24558eSHoria Geanta 20791da177e4SLinus Torvalds int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen) 20801da177e4SLinus Torvalds { 20811da177e4SLinus Torvalds int err; 20821da177e4SLinus Torvalds u8 *data; 20831da177e4SLinus Torvalds struct xfrm_mgr *km; 20841da177e4SLinus Torvalds struct xfrm_policy *pol = NULL; 20851da177e4SLinus Torvalds 208619d7df69SSteffen Klassert if (in_compat_syscall()) 208719d7df69SSteffen Klassert return -EOPNOTSUPP; 208819d7df69SSteffen Klassert 2089be8f8284SLorenzo Colitti if (!optval && !optlen) { 2090be8f8284SLorenzo Colitti xfrm_sk_policy_insert(sk, XFRM_POLICY_IN, NULL); 2091be8f8284SLorenzo Colitti xfrm_sk_policy_insert(sk, XFRM_POLICY_OUT, NULL); 2092be8f8284SLorenzo Colitti __sk_dst_reset(sk); 2093be8f8284SLorenzo Colitti return 0; 2094be8f8284SLorenzo Colitti } 2095be8f8284SLorenzo Colitti 20961da177e4SLinus Torvalds if (optlen <= 0 || optlen > PAGE_SIZE) 20971da177e4SLinus Torvalds return -EMSGSIZE; 20981da177e4SLinus Torvalds 2099a133d930SGeliang Tang data = memdup_user(optval, optlen); 2100a133d930SGeliang Tang if (IS_ERR(data)) 2101a133d930SGeliang Tang return PTR_ERR(data); 21021da177e4SLinus Torvalds 21031da177e4SLinus Torvalds err = -EINVAL; 210485168c00SCong Wang rcu_read_lock(); 210585168c00SCong Wang list_for_each_entry_rcu(km, &xfrm_km_list, list) { 2106cb969f07SVenkat Yekkirala pol = km->compile_policy(sk, optname, data, 21071da177e4SLinus Torvalds optlen, &err); 21081da177e4SLinus Torvalds if (err >= 0) 21091da177e4SLinus Torvalds break; 21101da177e4SLinus Torvalds } 211185168c00SCong Wang rcu_read_unlock(); 21121da177e4SLinus Torvalds 21131da177e4SLinus Torvalds if (err >= 0) { 21141da177e4SLinus Torvalds xfrm_sk_policy_insert(sk, err, pol); 21151da177e4SLinus Torvalds xfrm_pol_put(pol); 21162b06cdf3SJonathan Basseri __sk_dst_reset(sk); 21171da177e4SLinus Torvalds err = 0; 21181da177e4SLinus Torvalds } 21191da177e4SLinus Torvalds 21201da177e4SLinus Torvalds kfree(data); 21211da177e4SLinus Torvalds return err; 21221da177e4SLinus Torvalds } 21231da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_user_policy); 21241da177e4SLinus Torvalds 212585168c00SCong Wang static DEFINE_SPINLOCK(xfrm_km_lock); 212685168c00SCong Wang 21271da177e4SLinus Torvalds int xfrm_register_km(struct xfrm_mgr *km) 21281da177e4SLinus Torvalds { 212985168c00SCong Wang spin_lock_bh(&xfrm_km_lock); 213085168c00SCong Wang list_add_tail_rcu(&km->list, &xfrm_km_list); 213185168c00SCong Wang spin_unlock_bh(&xfrm_km_lock); 21321da177e4SLinus Torvalds return 0; 21331da177e4SLinus Torvalds } 21341da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_register_km); 21351da177e4SLinus Torvalds 21361da177e4SLinus Torvalds int xfrm_unregister_km(struct xfrm_mgr *km) 21371da177e4SLinus Torvalds { 213885168c00SCong Wang spin_lock_bh(&xfrm_km_lock); 213985168c00SCong Wang list_del_rcu(&km->list); 214085168c00SCong Wang spin_unlock_bh(&xfrm_km_lock); 214185168c00SCong Wang synchronize_rcu(); 21421da177e4SLinus Torvalds return 0; 21431da177e4SLinus Torvalds } 21441da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_unregister_km); 21451da177e4SLinus Torvalds 21461da177e4SLinus Torvalds int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo) 21471da177e4SLinus Torvalds { 21481da177e4SLinus Torvalds int err = 0; 2149423826a7SFlorian Westphal 2150423826a7SFlorian Westphal if (WARN_ON(afinfo->family >= NPROTO)) 21511da177e4SLinus Torvalds return -EAFNOSUPPORT; 2152423826a7SFlorian Westphal 215344abdc30SCong Wang spin_lock_bh(&xfrm_state_afinfo_lock); 21541da177e4SLinus Torvalds if (unlikely(xfrm_state_afinfo[afinfo->family] != NULL)) 2155f31e8d4fSLi RongQing err = -EEXIST; 2156edcd5821SDavid S. Miller else 215744abdc30SCong Wang rcu_assign_pointer(xfrm_state_afinfo[afinfo->family], afinfo); 215844abdc30SCong Wang spin_unlock_bh(&xfrm_state_afinfo_lock); 21591da177e4SLinus Torvalds return err; 21601da177e4SLinus Torvalds } 21611da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_register_afinfo); 21621da177e4SLinus Torvalds 21631da177e4SLinus Torvalds int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo) 21641da177e4SLinus Torvalds { 2165423826a7SFlorian Westphal int err = 0, family = afinfo->family; 2166423826a7SFlorian Westphal 2167423826a7SFlorian Westphal if (WARN_ON(family >= NPROTO)) 21681da177e4SLinus Torvalds return -EAFNOSUPPORT; 2169423826a7SFlorian Westphal 217044abdc30SCong Wang spin_lock_bh(&xfrm_state_afinfo_lock); 21711da177e4SLinus Torvalds if (likely(xfrm_state_afinfo[afinfo->family] != NULL)) { 2172423826a7SFlorian Westphal if (rcu_access_pointer(xfrm_state_afinfo[family]) != afinfo) 21731da177e4SLinus Torvalds err = -EINVAL; 2174edcd5821SDavid S. Miller else 217544abdc30SCong Wang RCU_INIT_POINTER(xfrm_state_afinfo[afinfo->family], NULL); 21761da177e4SLinus Torvalds } 217744abdc30SCong Wang spin_unlock_bh(&xfrm_state_afinfo_lock); 217844abdc30SCong Wang synchronize_rcu(); 21791da177e4SLinus Torvalds return err; 21801da177e4SLinus Torvalds } 21811da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_unregister_afinfo); 21821da177e4SLinus Torvalds 2183711059b9SFlorian Westphal struct xfrm_state_afinfo *xfrm_state_afinfo_get_rcu(unsigned int family) 2184711059b9SFlorian Westphal { 2185711059b9SFlorian Westphal if (unlikely(family >= NPROTO)) 2186711059b9SFlorian Westphal return NULL; 2187711059b9SFlorian Westphal 2188711059b9SFlorian Westphal return rcu_dereference(xfrm_state_afinfo[family]); 2189711059b9SFlorian Westphal } 2190733a5facSFlorian Westphal EXPORT_SYMBOL_GPL(xfrm_state_afinfo_get_rcu); 2191711059b9SFlorian Westphal 2192628e341fSHannes Frederic Sowa struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family) 21931da177e4SLinus Torvalds { 21941da177e4SLinus Torvalds struct xfrm_state_afinfo *afinfo; 21951da177e4SLinus Torvalds if (unlikely(family >= NPROTO)) 21961da177e4SLinus Torvalds return NULL; 219744abdc30SCong Wang rcu_read_lock(); 219844abdc30SCong Wang afinfo = rcu_dereference(xfrm_state_afinfo[family]); 2199546be240SHerbert Xu if (unlikely(!afinfo)) 220044abdc30SCong Wang rcu_read_unlock(); 22011da177e4SLinus Torvalds return afinfo; 22021da177e4SLinus Torvalds } 22031da177e4SLinus Torvalds 2204b48c05abSSteffen Klassert void xfrm_flush_gc(void) 2205b48c05abSSteffen Klassert { 2206b48c05abSSteffen Klassert flush_work(&xfrm_state_gc_work); 2207b48c05abSSteffen Klassert } 2208b48c05abSSteffen Klassert EXPORT_SYMBOL(xfrm_flush_gc); 2209b48c05abSSteffen Klassert 22101da177e4SLinus Torvalds /* Temporarily located here until net/xfrm/xfrm_tunnel.c is created */ 22111da177e4SLinus Torvalds void xfrm_state_delete_tunnel(struct xfrm_state *x) 22121da177e4SLinus Torvalds { 22131da177e4SLinus Torvalds if (x->tunnel) { 22141da177e4SLinus Torvalds struct xfrm_state *t = x->tunnel; 22151da177e4SLinus Torvalds 22161da177e4SLinus Torvalds if (atomic_read(&t->tunnel_users) == 2) 22171da177e4SLinus Torvalds xfrm_state_delete(t); 22181da177e4SLinus Torvalds atomic_dec(&t->tunnel_users); 2219f75a2804SCong Wang xfrm_state_put_sync(t); 22201da177e4SLinus Torvalds x->tunnel = NULL; 22211da177e4SLinus Torvalds } 22221da177e4SLinus Torvalds } 22231da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_delete_tunnel); 22241da177e4SLinus Torvalds 22251da177e4SLinus Torvalds int xfrm_state_mtu(struct xfrm_state *x, int mtu) 22261da177e4SLinus Torvalds { 2227b3b73b8eSFlorian Westphal const struct xfrm_type *type = READ_ONCE(x->type); 22281da177e4SLinus Torvalds 22291da177e4SLinus Torvalds if (x->km.state == XFRM_STATE_VALID && 2230b3b73b8eSFlorian Westphal type && type->get_mtu) 2231b3b73b8eSFlorian Westphal return type->get_mtu(x, mtu); 2232b3b73b8eSFlorian Westphal 2233b3b73b8eSFlorian Westphal return mtu - x->props.header_len; 22341da177e4SLinus Torvalds } 22351da177e4SLinus Torvalds 2236ffdb5211SIlan Tayari int __xfrm_init_state(struct xfrm_state *x, bool init_replay, bool offload) 223772cb6962SHerbert Xu { 2238d094cd83SHerbert Xu struct xfrm_state_afinfo *afinfo; 2239df9dcb45SKazunori MIYAZAWA struct xfrm_mode *inner_mode; 2240d094cd83SHerbert Xu int family = x->props.family; 224172cb6962SHerbert Xu int err; 224272cb6962SHerbert Xu 2243d094cd83SHerbert Xu err = -EAFNOSUPPORT; 2244d094cd83SHerbert Xu afinfo = xfrm_state_get_afinfo(family); 2245d094cd83SHerbert Xu if (!afinfo) 2246d094cd83SHerbert Xu goto error; 2247d094cd83SHerbert Xu 2248d094cd83SHerbert Xu err = 0; 2249d094cd83SHerbert Xu if (afinfo->init_flags) 2250d094cd83SHerbert Xu err = afinfo->init_flags(x); 2251d094cd83SHerbert Xu 2252af5d27c4SFlorian Westphal rcu_read_unlock(); 2253d094cd83SHerbert Xu 2254d094cd83SHerbert Xu if (err) 2255d094cd83SHerbert Xu goto error; 2256d094cd83SHerbert Xu 2257d094cd83SHerbert Xu err = -EPROTONOSUPPORT; 2258df9dcb45SKazunori MIYAZAWA 2259df9dcb45SKazunori MIYAZAWA if (x->sel.family != AF_UNSPEC) { 2260df9dcb45SKazunori MIYAZAWA inner_mode = xfrm_get_mode(x->props.mode, x->sel.family); 2261df9dcb45SKazunori MIYAZAWA if (inner_mode == NULL) 226213996378SHerbert Xu goto error; 226313996378SHerbert Xu 2264df9dcb45SKazunori MIYAZAWA if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL) && 2265df9dcb45SKazunori MIYAZAWA family != x->sel.family) { 2266df9dcb45SKazunori MIYAZAWA xfrm_put_mode(inner_mode); 226713996378SHerbert Xu goto error; 2268df9dcb45SKazunori MIYAZAWA } 2269df9dcb45SKazunori MIYAZAWA 2270df9dcb45SKazunori MIYAZAWA x->inner_mode = inner_mode; 2271df9dcb45SKazunori MIYAZAWA } else { 2272df9dcb45SKazunori MIYAZAWA struct xfrm_mode *inner_mode_iaf; 2273d81d2285SMartin Willi int iafamily = AF_INET; 2274df9dcb45SKazunori MIYAZAWA 2275d81d2285SMartin Willi inner_mode = xfrm_get_mode(x->props.mode, x->props.family); 2276df9dcb45SKazunori MIYAZAWA if (inner_mode == NULL) 2277df9dcb45SKazunori MIYAZAWA goto error; 2278df9dcb45SKazunori MIYAZAWA 2279df9dcb45SKazunori MIYAZAWA if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL)) { 2280df9dcb45SKazunori MIYAZAWA xfrm_put_mode(inner_mode); 2281df9dcb45SKazunori MIYAZAWA goto error; 2282df9dcb45SKazunori MIYAZAWA } 2283df9dcb45SKazunori MIYAZAWA x->inner_mode = inner_mode; 2284d81d2285SMartin Willi 2285d81d2285SMartin Willi if (x->props.family == AF_INET) 2286d81d2285SMartin Willi iafamily = AF_INET6; 2287d81d2285SMartin Willi 2288d81d2285SMartin Willi inner_mode_iaf = xfrm_get_mode(x->props.mode, iafamily); 2289d81d2285SMartin Willi if (inner_mode_iaf) { 2290d81d2285SMartin Willi if (inner_mode_iaf->flags & XFRM_MODE_FLAG_TUNNEL) 2291df9dcb45SKazunori MIYAZAWA x->inner_mode_iaf = inner_mode_iaf; 2292d81d2285SMartin Willi else 2293d81d2285SMartin Willi xfrm_put_mode(inner_mode_iaf); 2294df9dcb45SKazunori MIYAZAWA } 2295df9dcb45SKazunori MIYAZAWA } 229613996378SHerbert Xu 2297d094cd83SHerbert Xu x->type = xfrm_get_type(x->id.proto, family); 229872cb6962SHerbert Xu if (x->type == NULL) 229972cb6962SHerbert Xu goto error; 230072cb6962SHerbert Xu 2301ffdb5211SIlan Tayari x->type_offload = xfrm_get_type_offload(x->id.proto, family, offload); 23029d389d7fSSteffen Klassert 230372cb6962SHerbert Xu err = x->type->init_state(x); 230472cb6962SHerbert Xu if (err) 230572cb6962SHerbert Xu goto error; 230672cb6962SHerbert Xu 230713996378SHerbert Xu x->outer_mode = xfrm_get_mode(x->props.mode, family); 2308599901c3SJulia Lawall if (x->outer_mode == NULL) { 2309599901c3SJulia Lawall err = -EPROTONOSUPPORT; 2310b59f45d0SHerbert Xu goto error; 2311599901c3SJulia Lawall } 2312b59f45d0SHerbert Xu 2313a454f0ccSWei Yongjun if (init_replay) { 2314a454f0ccSWei Yongjun err = xfrm_init_replay(x); 2315a454f0ccSWei Yongjun if (err) 2316a454f0ccSWei Yongjun goto error; 2317a454f0ccSWei Yongjun } 2318a454f0ccSWei Yongjun 231972cb6962SHerbert Xu error: 232072cb6962SHerbert Xu return err; 232172cb6962SHerbert Xu } 232272cb6962SHerbert Xu 2323a454f0ccSWei Yongjun EXPORT_SYMBOL(__xfrm_init_state); 2324a454f0ccSWei Yongjun 2325a454f0ccSWei Yongjun int xfrm_init_state(struct xfrm_state *x) 2326a454f0ccSWei Yongjun { 2327cc01572eSYossi Kuperman int err; 2328cc01572eSYossi Kuperman 2329cc01572eSYossi Kuperman err = __xfrm_init_state(x, true, false); 2330cc01572eSYossi Kuperman if (!err) 2331cc01572eSYossi Kuperman x->km.state = XFRM_STATE_VALID; 2332cc01572eSYossi Kuperman 2333cc01572eSYossi Kuperman return err; 2334a454f0ccSWei Yongjun } 2335a454f0ccSWei Yongjun 233672cb6962SHerbert Xu EXPORT_SYMBOL(xfrm_init_state); 23371da177e4SLinus Torvalds 2338d62ddc21SAlexey Dobriyan int __net_init xfrm_state_init(struct net *net) 23391da177e4SLinus Torvalds { 2340f034b5d4SDavid S. Miller unsigned int sz; 23411da177e4SLinus Torvalds 2342565f0fa9SMathias Krause if (net_eq(net, &init_net)) 2343565f0fa9SMathias Krause xfrm_state_cache = KMEM_CACHE(xfrm_state, 2344565f0fa9SMathias Krause SLAB_HWCACHE_ALIGN | SLAB_PANIC); 2345565f0fa9SMathias Krause 23469d4139c7SAlexey Dobriyan INIT_LIST_HEAD(&net->xfrm.state_all); 23479d4139c7SAlexey Dobriyan 2348f034b5d4SDavid S. Miller sz = sizeof(struct hlist_head) * 8; 2349f034b5d4SDavid S. Miller 235073d189dcSAlexey Dobriyan net->xfrm.state_bydst = xfrm_hash_alloc(sz); 235173d189dcSAlexey Dobriyan if (!net->xfrm.state_bydst) 235273d189dcSAlexey Dobriyan goto out_bydst; 2353d320bbb3SAlexey Dobriyan net->xfrm.state_bysrc = xfrm_hash_alloc(sz); 2354d320bbb3SAlexey Dobriyan if (!net->xfrm.state_bysrc) 2355d320bbb3SAlexey Dobriyan goto out_bysrc; 2356b754a4fdSAlexey Dobriyan net->xfrm.state_byspi = xfrm_hash_alloc(sz); 2357b754a4fdSAlexey Dobriyan if (!net->xfrm.state_byspi) 2358b754a4fdSAlexey Dobriyan goto out_byspi; 2359529983ecSAlexey Dobriyan net->xfrm.state_hmask = ((sz / sizeof(struct hlist_head)) - 1); 2360f034b5d4SDavid S. Miller 23610bf7c5b0SAlexey Dobriyan net->xfrm.state_num = 0; 236263082733SAlexey Dobriyan INIT_WORK(&net->xfrm.state_hash_work, xfrm_hash_resize); 2363283bc9f3SFan Du spin_lock_init(&net->xfrm.xfrm_state_lock); 2364d62ddc21SAlexey Dobriyan return 0; 236573d189dcSAlexey Dobriyan 2366b754a4fdSAlexey Dobriyan out_byspi: 2367b754a4fdSAlexey Dobriyan xfrm_hash_free(net->xfrm.state_bysrc, sz); 2368d320bbb3SAlexey Dobriyan out_bysrc: 2369d320bbb3SAlexey Dobriyan xfrm_hash_free(net->xfrm.state_bydst, sz); 237073d189dcSAlexey Dobriyan out_bydst: 237173d189dcSAlexey Dobriyan return -ENOMEM; 2372d62ddc21SAlexey Dobriyan } 2373d62ddc21SAlexey Dobriyan 2374d62ddc21SAlexey Dobriyan void xfrm_state_fini(struct net *net) 2375d62ddc21SAlexey Dobriyan { 237673d189dcSAlexey Dobriyan unsigned int sz; 237773d189dcSAlexey Dobriyan 23787c2776eeSAlexey Dobriyan flush_work(&net->xfrm.state_hash_work); 237935db57bbSFlorian Westphal flush_work(&xfrm_state_gc_work); 2380f75a2804SCong Wang xfrm_state_flush(net, IPSEC_PROTO_ANY, false, true); 23817c2776eeSAlexey Dobriyan 23829d4139c7SAlexey Dobriyan WARN_ON(!list_empty(&net->xfrm.state_all)); 238373d189dcSAlexey Dobriyan 2384529983ecSAlexey Dobriyan sz = (net->xfrm.state_hmask + 1) * sizeof(struct hlist_head); 2385b754a4fdSAlexey Dobriyan WARN_ON(!hlist_empty(net->xfrm.state_byspi)); 2386b754a4fdSAlexey Dobriyan xfrm_hash_free(net->xfrm.state_byspi, sz); 2387d320bbb3SAlexey Dobriyan WARN_ON(!hlist_empty(net->xfrm.state_bysrc)); 2388d320bbb3SAlexey Dobriyan xfrm_hash_free(net->xfrm.state_bysrc, sz); 238973d189dcSAlexey Dobriyan WARN_ON(!hlist_empty(net->xfrm.state_bydst)); 239073d189dcSAlexey Dobriyan xfrm_hash_free(net->xfrm.state_bydst, sz); 23911da177e4SLinus Torvalds } 23921da177e4SLinus Torvalds 2393ab5f5e8bSJoy Latten #ifdef CONFIG_AUDITSYSCALL 2394cf35f43eSIlpo Järvinen static void xfrm_audit_helper_sainfo(struct xfrm_state *x, 2395ab5f5e8bSJoy Latten struct audit_buffer *audit_buf) 2396ab5f5e8bSJoy Latten { 239768277accSPaul Moore struct xfrm_sec_ctx *ctx = x->security; 239868277accSPaul Moore u32 spi = ntohl(x->id.spi); 239968277accSPaul Moore 240068277accSPaul Moore if (ctx) 2401ab5f5e8bSJoy Latten audit_log_format(audit_buf, " sec_alg=%u sec_doi=%u sec_obj=%s", 240268277accSPaul Moore ctx->ctx_alg, ctx->ctx_doi, ctx->ctx_str); 2403ab5f5e8bSJoy Latten 2404ab5f5e8bSJoy Latten switch (x->props.family) { 2405ab5f5e8bSJoy Latten case AF_INET: 240621454aaaSHarvey Harrison audit_log_format(audit_buf, " src=%pI4 dst=%pI4", 240721454aaaSHarvey Harrison &x->props.saddr.a4, &x->id.daddr.a4); 2408ab5f5e8bSJoy Latten break; 2409ab5f5e8bSJoy Latten case AF_INET6: 24105b095d98SHarvey Harrison audit_log_format(audit_buf, " src=%pI6 dst=%pI6", 2411fdb46ee7SHarvey Harrison x->props.saddr.a6, x->id.daddr.a6); 2412ab5f5e8bSJoy Latten break; 2413ab5f5e8bSJoy Latten } 241468277accSPaul Moore 241568277accSPaul Moore audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi); 2416ab5f5e8bSJoy Latten } 2417ab5f5e8bSJoy Latten 2418cf35f43eSIlpo Järvinen static void xfrm_audit_helper_pktinfo(struct sk_buff *skb, u16 family, 2419afeb14b4SPaul Moore struct audit_buffer *audit_buf) 2420afeb14b4SPaul Moore { 2421b71d1d42SEric Dumazet const struct iphdr *iph4; 2422b71d1d42SEric Dumazet const struct ipv6hdr *iph6; 2423afeb14b4SPaul Moore 2424afeb14b4SPaul Moore switch (family) { 2425afeb14b4SPaul Moore case AF_INET: 2426afeb14b4SPaul Moore iph4 = ip_hdr(skb); 242721454aaaSHarvey Harrison audit_log_format(audit_buf, " src=%pI4 dst=%pI4", 242821454aaaSHarvey Harrison &iph4->saddr, &iph4->daddr); 2429afeb14b4SPaul Moore break; 2430afeb14b4SPaul Moore case AF_INET6: 2431afeb14b4SPaul Moore iph6 = ipv6_hdr(skb); 2432afeb14b4SPaul Moore audit_log_format(audit_buf, 24335b095d98SHarvey Harrison " src=%pI6 dst=%pI6 flowlbl=0x%x%02x%02x", 2434fdb46ee7SHarvey Harrison &iph6->saddr, &iph6->daddr, 2435afeb14b4SPaul Moore iph6->flow_lbl[0] & 0x0f, 2436afeb14b4SPaul Moore iph6->flow_lbl[1], 2437afeb14b4SPaul Moore iph6->flow_lbl[2]); 2438afeb14b4SPaul Moore break; 2439afeb14b4SPaul Moore } 2440afeb14b4SPaul Moore } 2441afeb14b4SPaul Moore 24422e71029eSTetsuo Handa void xfrm_audit_state_add(struct xfrm_state *x, int result, bool task_valid) 2443ab5f5e8bSJoy Latten { 2444ab5f5e8bSJoy Latten struct audit_buffer *audit_buf; 2445ab5f5e8bSJoy Latten 2446afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SAD-add"); 2447ab5f5e8bSJoy Latten if (audit_buf == NULL) 2448ab5f5e8bSJoy Latten return; 24492e71029eSTetsuo Handa xfrm_audit_helper_usrinfo(task_valid, audit_buf); 2450afeb14b4SPaul Moore xfrm_audit_helper_sainfo(x, audit_buf); 2451afeb14b4SPaul Moore audit_log_format(audit_buf, " res=%u", result); 2452ab5f5e8bSJoy Latten audit_log_end(audit_buf); 2453ab5f5e8bSJoy Latten } 2454ab5f5e8bSJoy Latten EXPORT_SYMBOL_GPL(xfrm_audit_state_add); 2455ab5f5e8bSJoy Latten 24562e71029eSTetsuo Handa void xfrm_audit_state_delete(struct xfrm_state *x, int result, bool task_valid) 2457ab5f5e8bSJoy Latten { 2458ab5f5e8bSJoy Latten struct audit_buffer *audit_buf; 2459ab5f5e8bSJoy Latten 2460afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SAD-delete"); 2461ab5f5e8bSJoy Latten if (audit_buf == NULL) 2462ab5f5e8bSJoy Latten return; 24632e71029eSTetsuo Handa xfrm_audit_helper_usrinfo(task_valid, audit_buf); 2464afeb14b4SPaul Moore xfrm_audit_helper_sainfo(x, audit_buf); 2465afeb14b4SPaul Moore audit_log_format(audit_buf, " res=%u", result); 2466ab5f5e8bSJoy Latten audit_log_end(audit_buf); 2467ab5f5e8bSJoy Latten } 2468ab5f5e8bSJoy Latten EXPORT_SYMBOL_GPL(xfrm_audit_state_delete); 2469afeb14b4SPaul Moore 2470afeb14b4SPaul Moore void xfrm_audit_state_replay_overflow(struct xfrm_state *x, 2471afeb14b4SPaul Moore struct sk_buff *skb) 2472afeb14b4SPaul Moore { 2473afeb14b4SPaul Moore struct audit_buffer *audit_buf; 2474afeb14b4SPaul Moore u32 spi; 2475afeb14b4SPaul Moore 2476afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SA-replay-overflow"); 2477afeb14b4SPaul Moore if (audit_buf == NULL) 2478afeb14b4SPaul Moore return; 2479afeb14b4SPaul Moore xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf); 2480afeb14b4SPaul Moore /* don't record the sequence number because it's inherent in this kind 2481afeb14b4SPaul Moore * of audit message */ 2482afeb14b4SPaul Moore spi = ntohl(x->id.spi); 2483afeb14b4SPaul Moore audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi); 2484afeb14b4SPaul Moore audit_log_end(audit_buf); 2485afeb14b4SPaul Moore } 2486afeb14b4SPaul Moore EXPORT_SYMBOL_GPL(xfrm_audit_state_replay_overflow); 2487afeb14b4SPaul Moore 24889fdc4883SSteffen Klassert void xfrm_audit_state_replay(struct xfrm_state *x, 2489afeb14b4SPaul Moore struct sk_buff *skb, __be32 net_seq) 2490afeb14b4SPaul Moore { 2491afeb14b4SPaul Moore struct audit_buffer *audit_buf; 2492afeb14b4SPaul Moore u32 spi; 2493afeb14b4SPaul Moore 2494afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SA-replayed-pkt"); 2495afeb14b4SPaul Moore if (audit_buf == NULL) 2496afeb14b4SPaul Moore return; 2497afeb14b4SPaul Moore xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf); 2498afeb14b4SPaul Moore spi = ntohl(x->id.spi); 2499afeb14b4SPaul Moore audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u", 2500afeb14b4SPaul Moore spi, spi, ntohl(net_seq)); 2501afeb14b4SPaul Moore audit_log_end(audit_buf); 2502afeb14b4SPaul Moore } 25039fdc4883SSteffen Klassert EXPORT_SYMBOL_GPL(xfrm_audit_state_replay); 2504afeb14b4SPaul Moore 2505afeb14b4SPaul Moore void xfrm_audit_state_notfound_simple(struct sk_buff *skb, u16 family) 2506afeb14b4SPaul Moore { 2507afeb14b4SPaul Moore struct audit_buffer *audit_buf; 2508afeb14b4SPaul Moore 2509afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SA-notfound"); 2510afeb14b4SPaul Moore if (audit_buf == NULL) 2511afeb14b4SPaul Moore return; 2512afeb14b4SPaul Moore xfrm_audit_helper_pktinfo(skb, family, audit_buf); 2513afeb14b4SPaul Moore audit_log_end(audit_buf); 2514afeb14b4SPaul Moore } 2515afeb14b4SPaul Moore EXPORT_SYMBOL_GPL(xfrm_audit_state_notfound_simple); 2516afeb14b4SPaul Moore 2517afeb14b4SPaul Moore void xfrm_audit_state_notfound(struct sk_buff *skb, u16 family, 2518afeb14b4SPaul Moore __be32 net_spi, __be32 net_seq) 2519afeb14b4SPaul Moore { 2520afeb14b4SPaul Moore struct audit_buffer *audit_buf; 2521afeb14b4SPaul Moore u32 spi; 2522afeb14b4SPaul Moore 2523afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SA-notfound"); 2524afeb14b4SPaul Moore if (audit_buf == NULL) 2525afeb14b4SPaul Moore return; 2526afeb14b4SPaul Moore xfrm_audit_helper_pktinfo(skb, family, audit_buf); 2527afeb14b4SPaul Moore spi = ntohl(net_spi); 2528afeb14b4SPaul Moore audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u", 2529afeb14b4SPaul Moore spi, spi, ntohl(net_seq)); 2530afeb14b4SPaul Moore audit_log_end(audit_buf); 2531afeb14b4SPaul Moore } 2532afeb14b4SPaul Moore EXPORT_SYMBOL_GPL(xfrm_audit_state_notfound); 2533afeb14b4SPaul Moore 2534afeb14b4SPaul Moore void xfrm_audit_state_icvfail(struct xfrm_state *x, 2535afeb14b4SPaul Moore struct sk_buff *skb, u8 proto) 2536afeb14b4SPaul Moore { 2537afeb14b4SPaul Moore struct audit_buffer *audit_buf; 2538afeb14b4SPaul Moore __be32 net_spi; 2539afeb14b4SPaul Moore __be32 net_seq; 2540afeb14b4SPaul Moore 2541afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SA-icv-failure"); 2542afeb14b4SPaul Moore if (audit_buf == NULL) 2543afeb14b4SPaul Moore return; 2544afeb14b4SPaul Moore xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf); 2545afeb14b4SPaul Moore if (xfrm_parse_spi(skb, proto, &net_spi, &net_seq) == 0) { 2546afeb14b4SPaul Moore u32 spi = ntohl(net_spi); 2547afeb14b4SPaul Moore audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u", 2548afeb14b4SPaul Moore spi, spi, ntohl(net_seq)); 2549afeb14b4SPaul Moore } 2550afeb14b4SPaul Moore audit_log_end(audit_buf); 2551afeb14b4SPaul Moore } 2552afeb14b4SPaul Moore EXPORT_SYMBOL_GPL(xfrm_audit_state_icvfail); 2553ab5f5e8bSJoy Latten #endif /* CONFIG_AUDITSYSCALL */ 2554