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); 334aa5d62ccSHerbert Xu int xfrm_register_mode(struct xfrm_mode *mode, int family) 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 3437a9885b9SCong Wang afinfo = xfrm_state_get_afinfo(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 35717c2a42aSHerbert Xu mode->afinfo = afinfo; 358aa5d62ccSHerbert Xu modemap[mode->encap] = mode; 359aa5d62ccSHerbert Xu err = 0; 360aa5d62ccSHerbert Xu 36117c2a42aSHerbert Xu out: 3627a9885b9SCong Wang spin_unlock_bh(&xfrm_mode_lock); 363af5d27c4SFlorian Westphal rcu_read_unlock(); 364aa5d62ccSHerbert Xu return err; 365aa5d62ccSHerbert Xu } 366aa5d62ccSHerbert Xu EXPORT_SYMBOL(xfrm_register_mode); 367aa5d62ccSHerbert Xu 368aa5d62ccSHerbert Xu int xfrm_unregister_mode(struct xfrm_mode *mode, int family) 369aa5d62ccSHerbert Xu { 370aa5d62ccSHerbert Xu struct xfrm_state_afinfo *afinfo; 371aa5d62ccSHerbert Xu struct xfrm_mode **modemap; 372aa5d62ccSHerbert Xu int err; 373aa5d62ccSHerbert Xu 374aa5d62ccSHerbert Xu if (unlikely(mode->encap >= XFRM_MODE_MAX)) 375aa5d62ccSHerbert Xu return -EINVAL; 376aa5d62ccSHerbert Xu 3777a9885b9SCong Wang afinfo = xfrm_state_get_afinfo(family); 378aa5d62ccSHerbert Xu if (unlikely(afinfo == NULL)) 379aa5d62ccSHerbert Xu return -EAFNOSUPPORT; 380aa5d62ccSHerbert Xu 381aa5d62ccSHerbert Xu err = -ENOENT; 382aa5d62ccSHerbert Xu modemap = afinfo->mode_map; 3837a9885b9SCong Wang spin_lock_bh(&xfrm_mode_lock); 384aa5d62ccSHerbert Xu if (likely(modemap[mode->encap] == mode)) { 385aa5d62ccSHerbert Xu modemap[mode->encap] = NULL; 38617c2a42aSHerbert Xu module_put(mode->afinfo->owner); 387aa5d62ccSHerbert Xu err = 0; 388aa5d62ccSHerbert Xu } 389aa5d62ccSHerbert Xu 3907a9885b9SCong Wang spin_unlock_bh(&xfrm_mode_lock); 391af5d27c4SFlorian Westphal rcu_read_unlock(); 392aa5d62ccSHerbert Xu return err; 393aa5d62ccSHerbert Xu } 394aa5d62ccSHerbert Xu EXPORT_SYMBOL(xfrm_unregister_mode); 395aa5d62ccSHerbert Xu 396aa5d62ccSHerbert Xu static struct xfrm_mode *xfrm_get_mode(unsigned int encap, int family) 397aa5d62ccSHerbert Xu { 398aa5d62ccSHerbert Xu struct xfrm_state_afinfo *afinfo; 399aa5d62ccSHerbert Xu struct xfrm_mode *mode; 400aa5d62ccSHerbert Xu int modload_attempted = 0; 401aa5d62ccSHerbert Xu 402aa5d62ccSHerbert Xu if (unlikely(encap >= XFRM_MODE_MAX)) 403aa5d62ccSHerbert Xu return NULL; 404aa5d62ccSHerbert Xu 405aa5d62ccSHerbert Xu retry: 406aa5d62ccSHerbert Xu afinfo = xfrm_state_get_afinfo(family); 407aa5d62ccSHerbert Xu if (unlikely(afinfo == NULL)) 408aa5d62ccSHerbert Xu return NULL; 409aa5d62ccSHerbert Xu 41075cda62dSFlorian Westphal mode = READ_ONCE(afinfo->mode_map[encap]); 411aa5d62ccSHerbert Xu if (unlikely(mode && !try_module_get(mode->owner))) 412aa5d62ccSHerbert Xu mode = NULL; 41375cda62dSFlorian Westphal 414af5d27c4SFlorian Westphal rcu_read_unlock(); 41575cda62dSFlorian Westphal if (!mode && !modload_attempted) { 416aa5d62ccSHerbert Xu request_module("xfrm-mode-%d-%d", family, encap); 417aa5d62ccSHerbert Xu modload_attempted = 1; 418aa5d62ccSHerbert Xu goto retry; 419aa5d62ccSHerbert Xu } 420aa5d62ccSHerbert Xu 421aa5d62ccSHerbert Xu return mode; 422aa5d62ccSHerbert Xu } 423aa5d62ccSHerbert Xu 424aa5d62ccSHerbert Xu static void xfrm_put_mode(struct xfrm_mode *mode) 425aa5d62ccSHerbert Xu { 426aa5d62ccSHerbert Xu module_put(mode->owner); 427aa5d62ccSHerbert Xu } 428aa5d62ccSHerbert Xu 4294a135e53SMathias Krause void xfrm_state_free(struct xfrm_state *x) 4304a135e53SMathias Krause { 4314a135e53SMathias Krause kmem_cache_free(xfrm_state_cache, x); 4324a135e53SMathias Krause } 4334a135e53SMathias Krause EXPORT_SYMBOL(xfrm_state_free); 4344a135e53SMathias Krause 435f75a2804SCong Wang static void ___xfrm_state_destroy(struct xfrm_state *x) 4361da177e4SLinus Torvalds { 437671422b2SThomas Gleixner hrtimer_cancel(&x->mtimer); 438a47f0ce0SDavid S. Miller del_timer_sync(&x->rtimer); 439b5884793SIlan Tayari kfree(x->aead); 4401da177e4SLinus Torvalds kfree(x->aalg); 4411da177e4SLinus Torvalds kfree(x->ealg); 4421da177e4SLinus Torvalds kfree(x->calg); 4431da177e4SLinus Torvalds kfree(x->encap); 444060f02a3SNoriaki TAKAMIYA kfree(x->coaddr); 445d8647b79SSteffen Klassert kfree(x->replay_esn); 446d8647b79SSteffen Klassert kfree(x->preplay_esn); 44713996378SHerbert Xu if (x->inner_mode) 44813996378SHerbert Xu xfrm_put_mode(x->inner_mode); 449df9dcb45SKazunori MIYAZAWA if (x->inner_mode_iaf) 450df9dcb45SKazunori MIYAZAWA xfrm_put_mode(x->inner_mode_iaf); 45113996378SHerbert Xu if (x->outer_mode) 45213996378SHerbert Xu xfrm_put_mode(x->outer_mode); 4539d389d7fSSteffen Klassert if (x->type_offload) 4549d389d7fSSteffen Klassert xfrm_put_type_offload(x->type_offload); 4551da177e4SLinus Torvalds if (x->type) { 4561da177e4SLinus Torvalds x->type->destructor(x); 4571da177e4SLinus Torvalds xfrm_put_type(x->type); 4581da177e4SLinus Torvalds } 459d77e38e6SSteffen Klassert xfrm_dev_state_free(x); 460df71837dSTrent Jaeger security_xfrm_state_free(x); 4614a135e53SMathias Krause xfrm_state_free(x); 4621da177e4SLinus Torvalds } 4631da177e4SLinus Torvalds 464c7837144SAlexey Dobriyan static void xfrm_state_gc_task(struct work_struct *work) 4651da177e4SLinus Torvalds { 46612a169e7SHerbert Xu struct xfrm_state *x; 467b67bfe0dSSasha Levin struct hlist_node *tmp; 46812a169e7SHerbert Xu struct hlist_head gc_list; 4691da177e4SLinus Torvalds 4701da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_gc_lock); 47135db57bbSFlorian Westphal hlist_move_list(&xfrm_state_gc_list, &gc_list); 4721da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_gc_lock); 4731da177e4SLinus Torvalds 474df7274ebSFlorian Westphal synchronize_rcu(); 475df7274ebSFlorian Westphal 476b67bfe0dSSasha Levin hlist_for_each_entry_safe(x, tmp, &gc_list, gclist) 477f75a2804SCong Wang ___xfrm_state_destroy(x); 4781da177e4SLinus Torvalds } 4791da177e4SLinus Torvalds 4809e0d57fdSYury Polyanskiy static enum hrtimer_restart xfrm_timer_handler(struct hrtimer *me) 4811da177e4SLinus Torvalds { 482671422b2SThomas Gleixner struct xfrm_state *x = container_of(me, struct xfrm_state, mtimer); 483671422b2SThomas Gleixner enum hrtimer_restart ret = HRTIMER_NORESTART; 484386c5680SArnd Bergmann time64_t now = ktime_get_real_seconds(); 485386c5680SArnd Bergmann time64_t next = TIME64_MAX; 4861da177e4SLinus Torvalds int warn = 0; 487161a09e7SJoy Latten int err = 0; 4881da177e4SLinus Torvalds 4891da177e4SLinus Torvalds spin_lock(&x->lock); 4901da177e4SLinus Torvalds if (x->km.state == XFRM_STATE_DEAD) 4911da177e4SLinus Torvalds goto out; 4921da177e4SLinus Torvalds if (x->km.state == XFRM_STATE_EXPIRED) 4931da177e4SLinus Torvalds goto expired; 4941da177e4SLinus Torvalds if (x->lft.hard_add_expires_seconds) { 4951da177e4SLinus Torvalds long tmo = x->lft.hard_add_expires_seconds + 4961da177e4SLinus Torvalds x->curlft.add_time - now; 497e3c0d047SFan Du if (tmo <= 0) { 498e3c0d047SFan Du if (x->xflags & XFRM_SOFT_EXPIRE) { 499e3c0d047SFan Du /* enter hard expire without soft expire first?! 500e3c0d047SFan Du * setting a new date could trigger this. 5011365e547SAlexander Alemayhu * workaround: fix x->curflt.add_time by below: 502e3c0d047SFan Du */ 503e3c0d047SFan Du x->curlft.add_time = now - x->saved_tmo - 1; 504e3c0d047SFan Du tmo = x->lft.hard_add_expires_seconds - x->saved_tmo; 505e3c0d047SFan Du } else 5061da177e4SLinus Torvalds goto expired; 507e3c0d047SFan Du } 5081da177e4SLinus Torvalds if (tmo < next) 5091da177e4SLinus Torvalds next = tmo; 5101da177e4SLinus Torvalds } 5111da177e4SLinus Torvalds if (x->lft.hard_use_expires_seconds) { 5121da177e4SLinus Torvalds long tmo = x->lft.hard_use_expires_seconds + 5131da177e4SLinus Torvalds (x->curlft.use_time ? : now) - now; 5141da177e4SLinus Torvalds if (tmo <= 0) 5151da177e4SLinus Torvalds goto expired; 5161da177e4SLinus Torvalds if (tmo < next) 5171da177e4SLinus Torvalds next = tmo; 5181da177e4SLinus Torvalds } 5191da177e4SLinus Torvalds if (x->km.dying) 5201da177e4SLinus Torvalds goto resched; 5211da177e4SLinus Torvalds if (x->lft.soft_add_expires_seconds) { 5221da177e4SLinus Torvalds long tmo = x->lft.soft_add_expires_seconds + 5231da177e4SLinus Torvalds x->curlft.add_time - now; 524e3c0d047SFan Du if (tmo <= 0) { 5251da177e4SLinus Torvalds warn = 1; 526e3c0d047SFan Du x->xflags &= ~XFRM_SOFT_EXPIRE; 527e3c0d047SFan Du } else if (tmo < next) { 5281da177e4SLinus Torvalds next = tmo; 529e3c0d047SFan Du x->xflags |= XFRM_SOFT_EXPIRE; 530e3c0d047SFan Du x->saved_tmo = tmo; 531e3c0d047SFan Du } 5321da177e4SLinus Torvalds } 5331da177e4SLinus Torvalds if (x->lft.soft_use_expires_seconds) { 5341da177e4SLinus Torvalds long tmo = x->lft.soft_use_expires_seconds + 5351da177e4SLinus Torvalds (x->curlft.use_time ? : now) - now; 5361da177e4SLinus Torvalds if (tmo <= 0) 5371da177e4SLinus Torvalds warn = 1; 5381da177e4SLinus Torvalds else if (tmo < next) 5391da177e4SLinus Torvalds next = tmo; 5401da177e4SLinus Torvalds } 5411da177e4SLinus Torvalds 5424666faabSHerbert Xu x->km.dying = warn; 5431da177e4SLinus Torvalds if (warn) 54453bc6b4dSJamal Hadi Salim km_state_expired(x, 0, 0); 5451da177e4SLinus Torvalds resched: 546386c5680SArnd Bergmann if (next != TIME64_MAX) { 547671422b2SThomas Gleixner hrtimer_forward_now(&x->mtimer, ktime_set(next, 0)); 548671422b2SThomas Gleixner ret = HRTIMER_RESTART; 5499e0d57fdSYury Polyanskiy } 550a47f0ce0SDavid S. Miller 5511da177e4SLinus Torvalds goto out; 5521da177e4SLinus Torvalds 5531da177e4SLinus Torvalds expired: 5545b8ef341SSteffen Klassert if (x->km.state == XFRM_STATE_ACQ && x->id.spi == 0) 5551da177e4SLinus Torvalds x->km.state = XFRM_STATE_EXPIRED; 556161a09e7SJoy Latten 557161a09e7SJoy Latten err = __xfrm_state_delete(x); 5580806ae4cSNicolas Dichtel if (!err) 55953bc6b4dSJamal Hadi Salim km_state_expired(x, 1, 0); 5601da177e4SLinus Torvalds 5612e71029eSTetsuo Handa xfrm_audit_state_delete(x, err ? 0 : 1, true); 562161a09e7SJoy Latten 5631da177e4SLinus Torvalds out: 5641da177e4SLinus Torvalds spin_unlock(&x->lock); 565671422b2SThomas Gleixner return ret; 5661da177e4SLinus Torvalds } 5671da177e4SLinus Torvalds 568e99e88a9SKees Cook static void xfrm_replay_timer_handler(struct timer_list *t); 5690ac84752SDavid S. Miller 570673c09beSAlexey Dobriyan struct xfrm_state *xfrm_state_alloc(struct net *net) 5711da177e4SLinus Torvalds { 5721da177e4SLinus Torvalds struct xfrm_state *x; 5731da177e4SLinus Torvalds 574565f0fa9SMathias Krause x = kmem_cache_alloc(xfrm_state_cache, GFP_ATOMIC | __GFP_ZERO); 5751da177e4SLinus Torvalds 5761da177e4SLinus Torvalds if (x) { 577673c09beSAlexey Dobriyan write_pnet(&x->xs_net, net); 57888755e9cSReshetova, Elena refcount_set(&x->refcnt, 1); 5791da177e4SLinus Torvalds atomic_set(&x->tunnel_users, 0); 58012a169e7SHerbert Xu INIT_LIST_HEAD(&x->km.all); 5818f126e37SDavid S. Miller INIT_HLIST_NODE(&x->bydst); 5828f126e37SDavid S. Miller INIT_HLIST_NODE(&x->bysrc); 5838f126e37SDavid S. Miller INIT_HLIST_NODE(&x->byspi); 584671422b2SThomas Gleixner hrtimer_init(&x->mtimer, CLOCK_BOOTTIME, HRTIMER_MODE_ABS_SOFT); 585671422b2SThomas Gleixner x->mtimer.function = xfrm_timer_handler; 586e99e88a9SKees Cook timer_setup(&x->rtimer, xfrm_replay_timer_handler, 0); 587386c5680SArnd Bergmann x->curlft.add_time = ktime_get_real_seconds(); 5881da177e4SLinus Torvalds x->lft.soft_byte_limit = XFRM_INF; 5891da177e4SLinus Torvalds x->lft.soft_packet_limit = XFRM_INF; 5901da177e4SLinus Torvalds x->lft.hard_byte_limit = XFRM_INF; 5911da177e4SLinus Torvalds x->lft.hard_packet_limit = XFRM_INF; 592f8cd5488SJamal Hadi Salim x->replay_maxage = 0; 593f8cd5488SJamal Hadi Salim x->replay_maxdiff = 0; 594df9dcb45SKazunori MIYAZAWA x->inner_mode = NULL; 595df9dcb45SKazunori MIYAZAWA x->inner_mode_iaf = NULL; 5961da177e4SLinus Torvalds spin_lock_init(&x->lock); 5971da177e4SLinus Torvalds } 5981da177e4SLinus Torvalds return x; 5991da177e4SLinus Torvalds } 6001da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_alloc); 6011da177e4SLinus Torvalds 602f75a2804SCong Wang void __xfrm_state_destroy(struct xfrm_state *x, bool sync) 6031da177e4SLinus Torvalds { 604547b792cSIlpo Järvinen WARN_ON(x->km.state != XFRM_STATE_DEAD); 6051da177e4SLinus Torvalds 606f75a2804SCong Wang if (sync) { 607f75a2804SCong Wang synchronize_rcu(); 608f75a2804SCong Wang ___xfrm_state_destroy(x); 609f75a2804SCong Wang } else { 6101da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_gc_lock); 61135db57bbSFlorian Westphal hlist_add_head(&x->gclist, &xfrm_state_gc_list); 6121da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_gc_lock); 61335db57bbSFlorian Westphal schedule_work(&xfrm_state_gc_work); 6141da177e4SLinus Torvalds } 615f75a2804SCong Wang } 6161da177e4SLinus Torvalds EXPORT_SYMBOL(__xfrm_state_destroy); 6171da177e4SLinus Torvalds 61853bc6b4dSJamal Hadi Salim int __xfrm_state_delete(struct xfrm_state *x) 6191da177e4SLinus Torvalds { 62098806f75SAlexey Dobriyan struct net *net = xs_net(x); 62126b15dadSJamal Hadi Salim int err = -ESRCH; 62226b15dadSJamal Hadi Salim 6231da177e4SLinus Torvalds if (x->km.state != XFRM_STATE_DEAD) { 6241da177e4SLinus Torvalds x->km.state = XFRM_STATE_DEAD; 625283bc9f3SFan Du spin_lock(&net->xfrm.xfrm_state_lock); 62612a169e7SHerbert Xu list_del(&x->km.all); 627ae3fb6d3SFlorian Westphal hlist_del_rcu(&x->bydst); 628ae3fb6d3SFlorian Westphal hlist_del_rcu(&x->bysrc); 629a47f0ce0SDavid S. Miller if (x->id.spi) 630ae3fb6d3SFlorian Westphal hlist_del_rcu(&x->byspi); 63198806f75SAlexey Dobriyan net->xfrm.state_num--; 632283bc9f3SFan Du spin_unlock(&net->xfrm.xfrm_state_lock); 6331da177e4SLinus Torvalds 634d77e38e6SSteffen Klassert xfrm_dev_state_delete(x); 635d77e38e6SSteffen Klassert 6361da177e4SLinus Torvalds /* All xfrm_state objects are created by xfrm_state_alloc. 6371da177e4SLinus Torvalds * The xfrm_state_alloc call gives a reference, and that 6381da177e4SLinus Torvalds * is what we are dropping here. 6391da177e4SLinus Torvalds */ 6405dba4797SPatrick McHardy xfrm_state_put(x); 64126b15dadSJamal Hadi Salim err = 0; 6421da177e4SLinus Torvalds } 6431da177e4SLinus Torvalds 64426b15dadSJamal Hadi Salim return err; 64526b15dadSJamal Hadi Salim } 64653bc6b4dSJamal Hadi Salim EXPORT_SYMBOL(__xfrm_state_delete); 64726b15dadSJamal Hadi Salim 64826b15dadSJamal Hadi Salim int xfrm_state_delete(struct xfrm_state *x) 6491da177e4SLinus Torvalds { 65026b15dadSJamal Hadi Salim int err; 65126b15dadSJamal Hadi Salim 6521da177e4SLinus Torvalds spin_lock_bh(&x->lock); 65326b15dadSJamal Hadi Salim err = __xfrm_state_delete(x); 6541da177e4SLinus Torvalds spin_unlock_bh(&x->lock); 65526b15dadSJamal Hadi Salim 65626b15dadSJamal Hadi Salim return err; 6571da177e4SLinus Torvalds } 6581da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_delete); 6591da177e4SLinus Torvalds 6604aa2e62cSJoy Latten #ifdef CONFIG_SECURITY_NETWORK_XFRM 6614aa2e62cSJoy Latten static inline int 6622e71029eSTetsuo Handa xfrm_state_flush_secctx_check(struct net *net, u8 proto, bool task_valid) 6631da177e4SLinus Torvalds { 6644aa2e62cSJoy Latten int i, err = 0; 6654aa2e62cSJoy Latten 6660e602451SAlexey Dobriyan for (i = 0; i <= net->xfrm.state_hmask; i++) { 6674aa2e62cSJoy Latten struct xfrm_state *x; 6684aa2e62cSJoy Latten 669b67bfe0dSSasha Levin hlist_for_each_entry(x, net->xfrm.state_bydst+i, bydst) { 6704aa2e62cSJoy Latten if (xfrm_id_proto_match(x->id.proto, proto) && 6714aa2e62cSJoy Latten (err = security_xfrm_state_delete(x)) != 0) { 6722e71029eSTetsuo Handa xfrm_audit_state_delete(x, 0, task_valid); 6734aa2e62cSJoy Latten return err; 6744aa2e62cSJoy Latten } 6754aa2e62cSJoy Latten } 6764aa2e62cSJoy Latten } 6774aa2e62cSJoy Latten 6784aa2e62cSJoy Latten return err; 6794aa2e62cSJoy Latten } 680d77e38e6SSteffen Klassert 681d77e38e6SSteffen Klassert static inline int 682d77e38e6SSteffen Klassert xfrm_dev_state_flush_secctx_check(struct net *net, struct net_device *dev, bool task_valid) 683d77e38e6SSteffen Klassert { 684d77e38e6SSteffen Klassert int i, err = 0; 685d77e38e6SSteffen Klassert 686d77e38e6SSteffen Klassert for (i = 0; i <= net->xfrm.state_hmask; i++) { 687d77e38e6SSteffen Klassert struct xfrm_state *x; 688d77e38e6SSteffen Klassert struct xfrm_state_offload *xso; 689d77e38e6SSteffen Klassert 690d77e38e6SSteffen Klassert hlist_for_each_entry(x, net->xfrm.state_bydst+i, bydst) { 691d77e38e6SSteffen Klassert xso = &x->xso; 692d77e38e6SSteffen Klassert 693d77e38e6SSteffen Klassert if (xso->dev == dev && 694d77e38e6SSteffen Klassert (err = security_xfrm_state_delete(x)) != 0) { 695d77e38e6SSteffen Klassert xfrm_audit_state_delete(x, 0, task_valid); 696d77e38e6SSteffen Klassert return err; 697d77e38e6SSteffen Klassert } 698d77e38e6SSteffen Klassert } 699d77e38e6SSteffen Klassert } 700d77e38e6SSteffen Klassert 701d77e38e6SSteffen Klassert return err; 702d77e38e6SSteffen Klassert } 7034aa2e62cSJoy Latten #else 7044aa2e62cSJoy Latten static inline int 7052e71029eSTetsuo Handa xfrm_state_flush_secctx_check(struct net *net, u8 proto, bool task_valid) 7064aa2e62cSJoy Latten { 7074aa2e62cSJoy Latten return 0; 7084aa2e62cSJoy Latten } 709d77e38e6SSteffen Klassert 710d77e38e6SSteffen Klassert static inline int 711d77e38e6SSteffen Klassert xfrm_dev_state_flush_secctx_check(struct net *net, struct net_device *dev, bool task_valid) 712d77e38e6SSteffen Klassert { 713d77e38e6SSteffen Klassert return 0; 714d77e38e6SSteffen Klassert } 7154aa2e62cSJoy Latten #endif 7164aa2e62cSJoy Latten 717f75a2804SCong Wang int xfrm_state_flush(struct net *net, u8 proto, bool task_valid, bool sync) 7184aa2e62cSJoy Latten { 7199e64cc95SJamal Hadi Salim int i, err = 0, cnt = 0; 7201da177e4SLinus Torvalds 721283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 7222e71029eSTetsuo Handa err = xfrm_state_flush_secctx_check(net, proto, task_valid); 7234aa2e62cSJoy Latten if (err) 7244aa2e62cSJoy Latten goto out; 7254aa2e62cSJoy Latten 7269e64cc95SJamal Hadi Salim err = -ESRCH; 7270e602451SAlexey Dobriyan for (i = 0; i <= net->xfrm.state_hmask; i++) { 7288f126e37SDavid S. Miller struct xfrm_state *x; 7291da177e4SLinus Torvalds restart: 730b67bfe0dSSasha Levin hlist_for_each_entry(x, net->xfrm.state_bydst+i, bydst) { 7311da177e4SLinus Torvalds if (!xfrm_state_kern(x) && 7325794708fSMasahide NAKAMURA xfrm_id_proto_match(x->id.proto, proto)) { 7331da177e4SLinus Torvalds xfrm_state_hold(x); 734283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 7351da177e4SLinus Torvalds 736161a09e7SJoy Latten err = xfrm_state_delete(x); 737ab5f5e8bSJoy Latten xfrm_audit_state_delete(x, err ? 0 : 1, 7382e71029eSTetsuo Handa task_valid); 739f75a2804SCong Wang if (sync) 740f75a2804SCong Wang xfrm_state_put_sync(x); 741f75a2804SCong Wang else 7421da177e4SLinus Torvalds xfrm_state_put(x); 7439e64cc95SJamal Hadi Salim if (!err) 7449e64cc95SJamal Hadi Salim cnt++; 7451da177e4SLinus Torvalds 746283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 7471da177e4SLinus Torvalds goto restart; 7481da177e4SLinus Torvalds } 7491da177e4SLinus Torvalds } 7501da177e4SLinus Torvalds } 751dd269db8SArtem Savkov out: 752dd269db8SArtem Savkov spin_unlock_bh(&net->xfrm.xfrm_state_lock); 753e4db5b61SFlorian Westphal if (cnt) 7544aa2e62cSJoy Latten err = 0; 755e4db5b61SFlorian Westphal 7564aa2e62cSJoy Latten return err; 7571da177e4SLinus Torvalds } 7581da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_flush); 7591da177e4SLinus Torvalds 760d77e38e6SSteffen Klassert int xfrm_dev_state_flush(struct net *net, struct net_device *dev, bool task_valid) 761d77e38e6SSteffen Klassert { 762d77e38e6SSteffen Klassert int i, err = 0, cnt = 0; 763d77e38e6SSteffen Klassert 764d77e38e6SSteffen Klassert spin_lock_bh(&net->xfrm.xfrm_state_lock); 765d77e38e6SSteffen Klassert err = xfrm_dev_state_flush_secctx_check(net, dev, task_valid); 766d77e38e6SSteffen Klassert if (err) 767d77e38e6SSteffen Klassert goto out; 768d77e38e6SSteffen Klassert 769d77e38e6SSteffen Klassert err = -ESRCH; 770d77e38e6SSteffen Klassert for (i = 0; i <= net->xfrm.state_hmask; i++) { 771d77e38e6SSteffen Klassert struct xfrm_state *x; 772d77e38e6SSteffen Klassert struct xfrm_state_offload *xso; 773d77e38e6SSteffen Klassert restart: 774d77e38e6SSteffen Klassert hlist_for_each_entry(x, net->xfrm.state_bydst+i, bydst) { 775d77e38e6SSteffen Klassert xso = &x->xso; 776d77e38e6SSteffen Klassert 777d77e38e6SSteffen Klassert if (!xfrm_state_kern(x) && xso->dev == dev) { 778d77e38e6SSteffen Klassert xfrm_state_hold(x); 779d77e38e6SSteffen Klassert spin_unlock_bh(&net->xfrm.xfrm_state_lock); 780d77e38e6SSteffen Klassert 781d77e38e6SSteffen Klassert err = xfrm_state_delete(x); 782d77e38e6SSteffen Klassert xfrm_audit_state_delete(x, err ? 0 : 1, 783d77e38e6SSteffen Klassert task_valid); 784d77e38e6SSteffen Klassert xfrm_state_put(x); 785d77e38e6SSteffen Klassert if (!err) 786d77e38e6SSteffen Klassert cnt++; 787d77e38e6SSteffen Klassert 788d77e38e6SSteffen Klassert spin_lock_bh(&net->xfrm.xfrm_state_lock); 789d77e38e6SSteffen Klassert goto restart; 790d77e38e6SSteffen Klassert } 791d77e38e6SSteffen Klassert } 792d77e38e6SSteffen Klassert } 793d77e38e6SSteffen Klassert if (cnt) 794d77e38e6SSteffen Klassert err = 0; 795d77e38e6SSteffen Klassert 796d77e38e6SSteffen Klassert out: 797d77e38e6SSteffen Klassert spin_unlock_bh(&net->xfrm.xfrm_state_lock); 798d77e38e6SSteffen Klassert return err; 799d77e38e6SSteffen Klassert } 800d77e38e6SSteffen Klassert EXPORT_SYMBOL(xfrm_dev_state_flush); 801d77e38e6SSteffen Klassert 802e071041bSAlexey Dobriyan void xfrm_sad_getinfo(struct net *net, struct xfrmk_sadinfo *si) 80328d8909bSJamal Hadi Salim { 804283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 805e071041bSAlexey Dobriyan si->sadcnt = net->xfrm.state_num; 806ca92e173SBenjamin Poirier si->sadhcnt = net->xfrm.state_hmask + 1; 80728d8909bSJamal Hadi Salim si->sadhmcnt = xfrm_state_hashmax; 808283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 80928d8909bSJamal Hadi Salim } 81028d8909bSJamal Hadi Salim EXPORT_SYMBOL(xfrm_sad_getinfo); 81128d8909bSJamal Hadi Salim 812711059b9SFlorian Westphal static void 8131a898592SDavid S. Miller xfrm_init_tempstate(struct xfrm_state *x, const struct flowi *fl, 81404686013SDavid S. Miller const struct xfrm_tmpl *tmpl, 81533765d06SDavid S. Miller const xfrm_address_t *daddr, const xfrm_address_t *saddr, 8161da177e4SLinus Torvalds unsigned short family) 8171da177e4SLinus Torvalds { 818711059b9SFlorian Westphal struct xfrm_state_afinfo *afinfo = xfrm_state_afinfo_get_rcu(family); 819711059b9SFlorian Westphal 8203819a35fSFlorian Westphal if (!afinfo) 8213819a35fSFlorian Westphal return; 8223819a35fSFlorian Westphal 8238444cf71SThomas Egerer afinfo->init_tempsel(&x->sel, fl); 8248444cf71SThomas Egerer 8258444cf71SThomas Egerer if (family != tmpl->encap_family) { 826711059b9SFlorian Westphal afinfo = xfrm_state_afinfo_get_rcu(tmpl->encap_family); 8278444cf71SThomas Egerer if (!afinfo) 828711059b9SFlorian Westphal return; 8298444cf71SThomas Egerer } 8308444cf71SThomas Egerer afinfo->init_temprop(x, tmpl, daddr, saddr); 8311da177e4SLinus Torvalds } 8321da177e4SLinus Torvalds 8339aa60088SDavid S. Miller static struct xfrm_state *__xfrm_state_lookup(struct net *net, u32 mark, 8349aa60088SDavid S. Miller const xfrm_address_t *daddr, 8359aa60088SDavid S. Miller __be32 spi, u8 proto, 8369aa60088SDavid S. Miller unsigned short family) 837edcd5821SDavid S. Miller { 838221df1edSAlexey Dobriyan unsigned int h = xfrm_spi_hash(net, daddr, spi, proto, family); 839edcd5821SDavid S. Miller struct xfrm_state *x; 840edcd5821SDavid S. Miller 841ae3fb6d3SFlorian Westphal hlist_for_each_entry_rcu(x, net->xfrm.state_byspi + h, byspi) { 842edcd5821SDavid S. Miller if (x->props.family != family || 843edcd5821SDavid S. Miller x->id.spi != spi || 8441802571bSWei Yongjun x->id.proto != proto || 84570e94e66SYOSHIFUJI Hideaki / 吉藤英明 !xfrm_addr_equal(&x->id.daddr, daddr, family)) 846edcd5821SDavid S. Miller continue; 847edcd5821SDavid S. Miller 8483d6acfa7SJamal Hadi Salim if ((mark & x->mark.m) != x->mark.v) 8493d6acfa7SJamal Hadi Salim continue; 85002efdff7SFlorian Westphal if (!xfrm_state_hold_rcu(x)) 85102efdff7SFlorian Westphal continue; 852edcd5821SDavid S. Miller return x; 853edcd5821SDavid S. Miller } 854edcd5821SDavid S. Miller 855edcd5821SDavid S. Miller return NULL; 856edcd5821SDavid S. Miller } 857edcd5821SDavid S. Miller 8589aa60088SDavid S. Miller static struct xfrm_state *__xfrm_state_lookup_byaddr(struct net *net, u32 mark, 8599aa60088SDavid S. Miller const xfrm_address_t *daddr, 8609aa60088SDavid S. Miller const xfrm_address_t *saddr, 8619aa60088SDavid S. Miller u8 proto, unsigned short family) 862edcd5821SDavid S. Miller { 863221df1edSAlexey Dobriyan unsigned int h = xfrm_src_hash(net, daddr, saddr, family); 864edcd5821SDavid S. Miller struct xfrm_state *x; 865edcd5821SDavid S. Miller 866ae3fb6d3SFlorian Westphal hlist_for_each_entry_rcu(x, net->xfrm.state_bysrc + h, bysrc) { 867edcd5821SDavid S. Miller if (x->props.family != family || 8681802571bSWei Yongjun x->id.proto != proto || 86970e94e66SYOSHIFUJI Hideaki / 吉藤英明 !xfrm_addr_equal(&x->id.daddr, daddr, family) || 87070e94e66SYOSHIFUJI Hideaki / 吉藤英明 !xfrm_addr_equal(&x->props.saddr, saddr, family)) 871edcd5821SDavid S. Miller continue; 872edcd5821SDavid S. Miller 8733d6acfa7SJamal Hadi Salim if ((mark & x->mark.m) != x->mark.v) 8743d6acfa7SJamal Hadi Salim continue; 87502efdff7SFlorian Westphal if (!xfrm_state_hold_rcu(x)) 87602efdff7SFlorian Westphal continue; 877edcd5821SDavid S. Miller return x; 878edcd5821SDavid S. Miller } 879edcd5821SDavid S. Miller 880edcd5821SDavid S. Miller return NULL; 881edcd5821SDavid S. Miller } 882edcd5821SDavid S. Miller 883edcd5821SDavid S. Miller static inline struct xfrm_state * 884edcd5821SDavid S. Miller __xfrm_state_locate(struct xfrm_state *x, int use_spi, int family) 885edcd5821SDavid S. Miller { 886221df1edSAlexey Dobriyan struct net *net = xs_net(x); 887bd55775cSJamal Hadi Salim u32 mark = x->mark.v & x->mark.m; 888221df1edSAlexey Dobriyan 889edcd5821SDavid S. Miller if (use_spi) 890bd55775cSJamal Hadi Salim return __xfrm_state_lookup(net, mark, &x->id.daddr, 891bd55775cSJamal Hadi Salim x->id.spi, x->id.proto, family); 892edcd5821SDavid S. Miller else 893bd55775cSJamal Hadi Salim return __xfrm_state_lookup_byaddr(net, mark, 894bd55775cSJamal Hadi Salim &x->id.daddr, 895edcd5821SDavid S. Miller &x->props.saddr, 896edcd5821SDavid S. Miller x->id.proto, family); 897edcd5821SDavid S. Miller } 898edcd5821SDavid S. Miller 89998806f75SAlexey Dobriyan static void xfrm_hash_grow_check(struct net *net, int have_hash_collision) 9002fab22f2SPatrick McHardy { 9012fab22f2SPatrick McHardy if (have_hash_collision && 90298806f75SAlexey Dobriyan (net->xfrm.state_hmask + 1) < xfrm_state_hashmax && 90398806f75SAlexey Dobriyan net->xfrm.state_num > net->xfrm.state_hmask) 90498806f75SAlexey Dobriyan schedule_work(&net->xfrm.state_hash_work); 9052fab22f2SPatrick McHardy } 9062fab22f2SPatrick McHardy 90708ec9af1SDavid S. Miller static void xfrm_state_look_at(struct xfrm_policy *pol, struct xfrm_state *x, 9084a08ab0fSDavid S. Miller const struct flowi *fl, unsigned short family, 90908ec9af1SDavid S. Miller struct xfrm_state **best, int *acq_in_progress, 91008ec9af1SDavid S. Miller int *error) 91108ec9af1SDavid S. Miller { 91208ec9af1SDavid S. Miller /* Resolution logic: 91308ec9af1SDavid S. Miller * 1. There is a valid state with matching selector. Done. 91408ec9af1SDavid S. Miller * 2. Valid state with inappropriate selector. Skip. 91508ec9af1SDavid S. Miller * 91608ec9af1SDavid S. Miller * Entering area of "sysdeps". 91708ec9af1SDavid S. Miller * 91808ec9af1SDavid S. Miller * 3. If state is not valid, selector is temporary, it selects 91908ec9af1SDavid S. Miller * only session which triggered previous resolution. Key 92008ec9af1SDavid S. Miller * manager will do something to install a state with proper 92108ec9af1SDavid S. Miller * selector. 92208ec9af1SDavid S. Miller */ 92308ec9af1SDavid S. Miller if (x->km.state == XFRM_STATE_VALID) { 92408ec9af1SDavid S. Miller if ((x->sel.family && 92508ec9af1SDavid S. Miller !xfrm_selector_match(&x->sel, fl, x->sel.family)) || 92608ec9af1SDavid S. Miller !security_xfrm_state_pol_flow_match(x, pol, fl)) 92708ec9af1SDavid S. Miller return; 92808ec9af1SDavid S. Miller 92908ec9af1SDavid S. Miller if (!*best || 93008ec9af1SDavid S. Miller (*best)->km.dying > x->km.dying || 93108ec9af1SDavid S. Miller ((*best)->km.dying == x->km.dying && 93208ec9af1SDavid S. Miller (*best)->curlft.add_time < x->curlft.add_time)) 93308ec9af1SDavid S. Miller *best = x; 93408ec9af1SDavid S. Miller } else if (x->km.state == XFRM_STATE_ACQ) { 93508ec9af1SDavid S. Miller *acq_in_progress = 1; 93608ec9af1SDavid S. Miller } else if (x->km.state == XFRM_STATE_ERROR || 93708ec9af1SDavid S. Miller x->km.state == XFRM_STATE_EXPIRED) { 93808ec9af1SDavid S. Miller if (xfrm_selector_match(&x->sel, fl, x->sel.family) && 93908ec9af1SDavid S. Miller security_xfrm_state_pol_flow_match(x, pol, fl)) 94008ec9af1SDavid S. Miller *error = -ESRCH; 94108ec9af1SDavid S. Miller } 94208ec9af1SDavid S. Miller } 94308ec9af1SDavid S. Miller 9441da177e4SLinus Torvalds struct xfrm_state * 94533765d06SDavid S. Miller xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr, 946b520e9f6SDavid S. Miller const struct flowi *fl, struct xfrm_tmpl *tmpl, 9471da177e4SLinus Torvalds struct xfrm_policy *pol, int *err, 948bc56b334SBenedict Wong unsigned short family, u32 if_id) 9491da177e4SLinus Torvalds { 95008ec9af1SDavid S. Miller static xfrm_address_t saddr_wildcard = { }; 9515447c5e4SAlexey Dobriyan struct net *net = xp_net(pol); 9526a783c90SNicolas Dichtel unsigned int h, h_wildcard; 95337b08e34SDavid S. Miller struct xfrm_state *x, *x0, *to_put; 9541da177e4SLinus Torvalds int acquire_in_progress = 0; 9551da177e4SLinus Torvalds int error = 0; 9561da177e4SLinus Torvalds struct xfrm_state *best = NULL; 957bd55775cSJamal Hadi Salim u32 mark = pol->mark.v & pol->mark.m; 9588444cf71SThomas Egerer unsigned short encap_family = tmpl->encap_family; 959b65e3d7bSFlorian Westphal unsigned int sequence; 9600f24558eSHoria Geanta struct km_event c; 9611da177e4SLinus Torvalds 96237b08e34SDavid S. Miller to_put = NULL; 96337b08e34SDavid S. Miller 964b65e3d7bSFlorian Westphal sequence = read_seqcount_begin(&xfrm_state_hash_generation); 965b65e3d7bSFlorian Westphal 966d737a580SFlorian Westphal rcu_read_lock(); 9678444cf71SThomas Egerer h = xfrm_dst_hash(net, daddr, saddr, tmpl->reqid, encap_family); 968ae3fb6d3SFlorian Westphal hlist_for_each_entry_rcu(x, net->xfrm.state_bydst + h, bydst) { 9698444cf71SThomas Egerer if (x->props.family == encap_family && 9701da177e4SLinus Torvalds x->props.reqid == tmpl->reqid && 9713d6acfa7SJamal Hadi Salim (mark & x->mark.m) == x->mark.v && 9727e652640SSteffen Klassert x->if_id == if_id && 973fbd9a5b4SMasahide NAKAMURA !(x->props.flags & XFRM_STATE_WILDRECV) && 9748444cf71SThomas Egerer xfrm_state_addr_check(x, daddr, saddr, encap_family) && 9751da177e4SLinus Torvalds tmpl->mode == x->props.mode && 9761da177e4SLinus Torvalds tmpl->id.proto == x->id.proto && 97708ec9af1SDavid S. Miller (tmpl->id.spi == x->id.spi || !tmpl->id.spi)) 9781f673c5fSDavid S. Miller xfrm_state_look_at(pol, x, fl, encap_family, 97908ec9af1SDavid S. Miller &best, &acquire_in_progress, &error); 9801da177e4SLinus Torvalds } 9816f115638SFan Du if (best || acquire_in_progress) 98208ec9af1SDavid S. Miller goto found; 98308ec9af1SDavid S. Miller 9848444cf71SThomas Egerer h_wildcard = xfrm_dst_hash(net, daddr, &saddr_wildcard, tmpl->reqid, encap_family); 985ae3fb6d3SFlorian Westphal hlist_for_each_entry_rcu(x, net->xfrm.state_bydst + h_wildcard, bydst) { 9868444cf71SThomas Egerer if (x->props.family == encap_family && 98708ec9af1SDavid S. Miller x->props.reqid == tmpl->reqid && 9883d6acfa7SJamal Hadi Salim (mark & x->mark.m) == x->mark.v && 9897e652640SSteffen Klassert x->if_id == if_id && 99008ec9af1SDavid S. Miller !(x->props.flags & XFRM_STATE_WILDRECV) && 991f59bbdfaSFan Du xfrm_addr_equal(&x->id.daddr, daddr, encap_family) && 99208ec9af1SDavid S. Miller tmpl->mode == x->props.mode && 99308ec9af1SDavid S. Miller tmpl->id.proto == x->id.proto && 99408ec9af1SDavid S. Miller (tmpl->id.spi == x->id.spi || !tmpl->id.spi)) 9951f673c5fSDavid S. Miller xfrm_state_look_at(pol, x, fl, encap_family, 99608ec9af1SDavid S. Miller &best, &acquire_in_progress, &error); 9971da177e4SLinus Torvalds } 9981da177e4SLinus Torvalds 99908ec9af1SDavid S. Miller found: 10001da177e4SLinus Torvalds x = best; 10011da177e4SLinus Torvalds if (!x && !error && !acquire_in_progress) { 10025c5d281aSPatrick McHardy if (tmpl->id.spi && 1003bd55775cSJamal Hadi Salim (x0 = __xfrm_state_lookup(net, mark, daddr, tmpl->id.spi, 10048444cf71SThomas Egerer tmpl->id.proto, encap_family)) != NULL) { 100537b08e34SDavid S. Miller to_put = x0; 10061da177e4SLinus Torvalds error = -EEXIST; 10071da177e4SLinus Torvalds goto out; 10081da177e4SLinus Torvalds } 10090f24558eSHoria Geanta 10100f24558eSHoria Geanta c.net = net; 10110f24558eSHoria Geanta /* If the KMs have no listeners (yet...), avoid allocating an SA 10120f24558eSHoria Geanta * for each and every packet - garbage collection might not 10130f24558eSHoria Geanta * handle the flood. 10140f24558eSHoria Geanta */ 10150f24558eSHoria Geanta if (!km_is_alive(&c)) { 10160f24558eSHoria Geanta error = -ESRCH; 10170f24558eSHoria Geanta goto out; 10180f24558eSHoria Geanta } 10190f24558eSHoria Geanta 10205447c5e4SAlexey Dobriyan x = xfrm_state_alloc(net); 10211da177e4SLinus Torvalds if (x == NULL) { 10221da177e4SLinus Torvalds error = -ENOMEM; 10231da177e4SLinus Torvalds goto out; 10241da177e4SLinus Torvalds } 10258444cf71SThomas Egerer /* Initialize temporary state matching only 10261da177e4SLinus Torvalds * to current session. */ 10278444cf71SThomas Egerer xfrm_init_tempstate(x, fl, tmpl, daddr, saddr, family); 1028bd55775cSJamal Hadi Salim memcpy(&x->mark, &pol->mark, sizeof(x->mark)); 10297e652640SSteffen Klassert x->if_id = if_id; 10301da177e4SLinus Torvalds 10311d28f42cSDavid S. Miller error = security_xfrm_state_alloc_acquire(x, pol->security, fl->flowi_secid); 1032e0d1caa7SVenkat Yekkirala if (error) { 1033e0d1caa7SVenkat Yekkirala x->km.state = XFRM_STATE_DEAD; 103437b08e34SDavid S. Miller to_put = x; 1035e0d1caa7SVenkat Yekkirala x = NULL; 1036e0d1caa7SVenkat Yekkirala goto out; 1037e0d1caa7SVenkat Yekkirala } 1038e0d1caa7SVenkat Yekkirala 10391da177e4SLinus Torvalds if (km_query(x, tmpl, pol) == 0) { 1040d737a580SFlorian Westphal spin_lock_bh(&net->xfrm.xfrm_state_lock); 10411da177e4SLinus Torvalds x->km.state = XFRM_STATE_ACQ; 10425447c5e4SAlexey Dobriyan list_add(&x->km.all, &net->xfrm.state_all); 1043ae3fb6d3SFlorian Westphal hlist_add_head_rcu(&x->bydst, net->xfrm.state_bydst + h); 10448444cf71SThomas Egerer h = xfrm_src_hash(net, daddr, saddr, encap_family); 1045ae3fb6d3SFlorian Westphal hlist_add_head_rcu(&x->bysrc, net->xfrm.state_bysrc + h); 10461da177e4SLinus Torvalds if (x->id.spi) { 10478444cf71SThomas Egerer h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, encap_family); 1048ae3fb6d3SFlorian Westphal hlist_add_head_rcu(&x->byspi, net->xfrm.state_byspi + h); 10491da177e4SLinus Torvalds } 1050b27aeadbSAlexey Dobriyan x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires; 1051671422b2SThomas Gleixner hrtimer_start(&x->mtimer, 1052671422b2SThomas Gleixner ktime_set(net->xfrm.sysctl_acq_expires, 0), 1053671422b2SThomas Gleixner HRTIMER_MODE_REL_SOFT); 10545447c5e4SAlexey Dobriyan net->xfrm.state_num++; 10555447c5e4SAlexey Dobriyan xfrm_hash_grow_check(net, x->bydst.next != NULL); 1056d737a580SFlorian Westphal spin_unlock_bh(&net->xfrm.xfrm_state_lock); 10571da177e4SLinus Torvalds } else { 10581da177e4SLinus Torvalds x->km.state = XFRM_STATE_DEAD; 105937b08e34SDavid S. Miller to_put = x; 10601da177e4SLinus Torvalds x = NULL; 10611da177e4SLinus Torvalds error = -ESRCH; 10621da177e4SLinus Torvalds } 10631da177e4SLinus Torvalds } 10641da177e4SLinus Torvalds out: 106502efdff7SFlorian Westphal if (x) { 106602efdff7SFlorian Westphal if (!xfrm_state_hold_rcu(x)) { 106702efdff7SFlorian Westphal *err = -EAGAIN; 106802efdff7SFlorian Westphal x = NULL; 106902efdff7SFlorian Westphal } 107002efdff7SFlorian Westphal } else { 10711da177e4SLinus Torvalds *err = acquire_in_progress ? -EAGAIN : error; 107202efdff7SFlorian Westphal } 1073d737a580SFlorian Westphal rcu_read_unlock(); 107437b08e34SDavid S. Miller if (to_put) 107537b08e34SDavid S. Miller xfrm_state_put(to_put); 1076b65e3d7bSFlorian Westphal 1077b65e3d7bSFlorian Westphal if (read_seqcount_retry(&xfrm_state_hash_generation, sequence)) { 1078b65e3d7bSFlorian Westphal *err = -EAGAIN; 1079b65e3d7bSFlorian Westphal if (x) { 1080b65e3d7bSFlorian Westphal xfrm_state_put(x); 1081b65e3d7bSFlorian Westphal x = NULL; 1082b65e3d7bSFlorian Westphal } 1083b65e3d7bSFlorian Westphal } 1084b65e3d7bSFlorian Westphal 10851da177e4SLinus Torvalds return x; 10861da177e4SLinus Torvalds } 10871da177e4SLinus Torvalds 1088628529b6SJamal Hadi Salim struct xfrm_state * 10897e652640SSteffen Klassert xfrm_stateonly_find(struct net *net, u32 mark, u32 if_id, 10905447c5e4SAlexey Dobriyan xfrm_address_t *daddr, xfrm_address_t *saddr, 1091628529b6SJamal Hadi Salim unsigned short family, u8 mode, u8 proto, u32 reqid) 1092628529b6SJamal Hadi Salim { 10934bda4f25SPavel Emelyanov unsigned int h; 1094628529b6SJamal Hadi Salim struct xfrm_state *rx = NULL, *x = NULL; 1095628529b6SJamal Hadi Salim 10964ae770bfSFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 10975447c5e4SAlexey Dobriyan h = xfrm_dst_hash(net, daddr, saddr, reqid, family); 1098b67bfe0dSSasha Levin hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) { 1099628529b6SJamal Hadi Salim if (x->props.family == family && 1100628529b6SJamal Hadi Salim x->props.reqid == reqid && 11013d6acfa7SJamal Hadi Salim (mark & x->mark.m) == x->mark.v && 11027e652640SSteffen Klassert x->if_id == if_id && 1103628529b6SJamal Hadi Salim !(x->props.flags & XFRM_STATE_WILDRECV) && 1104628529b6SJamal Hadi Salim xfrm_state_addr_check(x, daddr, saddr, family) && 1105628529b6SJamal Hadi Salim mode == x->props.mode && 1106628529b6SJamal Hadi Salim proto == x->id.proto && 1107628529b6SJamal Hadi Salim x->km.state == XFRM_STATE_VALID) { 1108628529b6SJamal Hadi Salim rx = x; 1109628529b6SJamal Hadi Salim break; 1110628529b6SJamal Hadi Salim } 1111628529b6SJamal Hadi Salim } 1112628529b6SJamal Hadi Salim 1113628529b6SJamal Hadi Salim if (rx) 1114628529b6SJamal Hadi Salim xfrm_state_hold(rx); 11154ae770bfSFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 1116628529b6SJamal Hadi Salim 1117628529b6SJamal Hadi Salim 1118628529b6SJamal Hadi Salim return rx; 1119628529b6SJamal Hadi Salim } 1120628529b6SJamal Hadi Salim EXPORT_SYMBOL(xfrm_stateonly_find); 1121628529b6SJamal Hadi Salim 1122c454997eSFan Du struct xfrm_state *xfrm_state_lookup_byspi(struct net *net, __be32 spi, 1123c454997eSFan Du unsigned short family) 1124c454997eSFan Du { 1125c454997eSFan Du struct xfrm_state *x; 1126c454997eSFan Du struct xfrm_state_walk *w; 1127c454997eSFan Du 1128c454997eSFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 1129c454997eSFan Du list_for_each_entry(w, &net->xfrm.state_all, all) { 1130c454997eSFan Du x = container_of(w, struct xfrm_state, km); 1131c454997eSFan Du if (x->props.family != family || 1132c454997eSFan Du x->id.spi != spi) 1133c454997eSFan Du continue; 1134c454997eSFan Du 1135c454997eSFan Du xfrm_state_hold(x); 1136bdddbf69SLi RongQing spin_unlock_bh(&net->xfrm.xfrm_state_lock); 1137c454997eSFan Du return x; 1138c454997eSFan Du } 1139c454997eSFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 1140c454997eSFan Du return NULL; 1141c454997eSFan Du } 1142c454997eSFan Du EXPORT_SYMBOL(xfrm_state_lookup_byspi); 1143c454997eSFan Du 11441da177e4SLinus Torvalds static void __xfrm_state_insert(struct xfrm_state *x) 11451da177e4SLinus Torvalds { 114698806f75SAlexey Dobriyan struct net *net = xs_net(x); 1147a624c108SDavid S. Miller unsigned int h; 11481da177e4SLinus Torvalds 114998806f75SAlexey Dobriyan list_add(&x->km.all, &net->xfrm.state_all); 11504c563f76STimo Teras 115198806f75SAlexey Dobriyan h = xfrm_dst_hash(net, &x->id.daddr, &x->props.saddr, 1152c1969f29SDavid S. Miller x->props.reqid, x->props.family); 1153ae3fb6d3SFlorian Westphal hlist_add_head_rcu(&x->bydst, net->xfrm.state_bydst + h); 11541da177e4SLinus Torvalds 115598806f75SAlexey Dobriyan h = xfrm_src_hash(net, &x->id.daddr, &x->props.saddr, x->props.family); 1156ae3fb6d3SFlorian Westphal hlist_add_head_rcu(&x->bysrc, net->xfrm.state_bysrc + h); 11576c44e6b7SMasahide NAKAMURA 11587b4dc360SMasahide NAKAMURA if (x->id.spi) { 115998806f75SAlexey Dobriyan h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, 11606c44e6b7SMasahide NAKAMURA x->props.family); 11611da177e4SLinus Torvalds 1162ae3fb6d3SFlorian Westphal hlist_add_head_rcu(&x->byspi, net->xfrm.state_byspi + h); 11636c44e6b7SMasahide NAKAMURA } 11641da177e4SLinus Torvalds 1165671422b2SThomas Gleixner hrtimer_start(&x->mtimer, ktime_set(1, 0), HRTIMER_MODE_REL_SOFT); 1166a47f0ce0SDavid S. Miller if (x->replay_maxage) 1167a47f0ce0SDavid S. Miller mod_timer(&x->rtimer, jiffies + x->replay_maxage); 1168f8cd5488SJamal Hadi Salim 116998806f75SAlexey Dobriyan net->xfrm.state_num++; 1170f034b5d4SDavid S. Miller 117198806f75SAlexey Dobriyan xfrm_hash_grow_check(net, x->bydst.next != NULL); 11721da177e4SLinus Torvalds } 11731da177e4SLinus Torvalds 1174283bc9f3SFan Du /* net->xfrm.xfrm_state_lock is held */ 1175c7f5ea3aSDavid S. Miller static void __xfrm_state_bump_genids(struct xfrm_state *xnew) 1176c7f5ea3aSDavid S. Miller { 117798806f75SAlexey Dobriyan struct net *net = xs_net(xnew); 1178c7f5ea3aSDavid S. Miller unsigned short family = xnew->props.family; 1179c7f5ea3aSDavid S. Miller u32 reqid = xnew->props.reqid; 1180c7f5ea3aSDavid S. Miller struct xfrm_state *x; 1181c7f5ea3aSDavid S. Miller unsigned int h; 11823d6acfa7SJamal Hadi Salim u32 mark = xnew->mark.v & xnew->mark.m; 11837e652640SSteffen Klassert u32 if_id = xnew->if_id; 1184c7f5ea3aSDavid S. Miller 118598806f75SAlexey Dobriyan h = xfrm_dst_hash(net, &xnew->id.daddr, &xnew->props.saddr, reqid, family); 1186b67bfe0dSSasha Levin hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) { 1187c7f5ea3aSDavid S. Miller if (x->props.family == family && 1188c7f5ea3aSDavid S. Miller x->props.reqid == reqid && 11897e652640SSteffen Klassert x->if_id == if_id && 11903d6acfa7SJamal Hadi Salim (mark & x->mark.m) == x->mark.v && 119170e94e66SYOSHIFUJI Hideaki / 吉藤英明 xfrm_addr_equal(&x->id.daddr, &xnew->id.daddr, family) && 119270e94e66SYOSHIFUJI Hideaki / 吉藤英明 xfrm_addr_equal(&x->props.saddr, &xnew->props.saddr, family)) 119334996cb9SHerbert Xu x->genid++; 1194c7f5ea3aSDavid S. Miller } 1195c7f5ea3aSDavid S. Miller } 1196c7f5ea3aSDavid S. Miller 11971da177e4SLinus Torvalds void xfrm_state_insert(struct xfrm_state *x) 11981da177e4SLinus Torvalds { 1199283bc9f3SFan Du struct net *net = xs_net(x); 1200283bc9f3SFan Du 1201283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 1202c7f5ea3aSDavid S. Miller __xfrm_state_bump_genids(x); 12031da177e4SLinus Torvalds __xfrm_state_insert(x); 1204283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 12051da177e4SLinus Torvalds } 12061da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_insert); 12071da177e4SLinus Torvalds 1208283bc9f3SFan Du /* net->xfrm.xfrm_state_lock is held */ 1209e473fcb4SMathias Krause static struct xfrm_state *__find_acq_core(struct net *net, 1210e473fcb4SMathias Krause const struct xfrm_mark *m, 1211a70486f0SDavid S. Miller unsigned short family, u8 mode, 12127e652640SSteffen Klassert u32 reqid, u32 if_id, u8 proto, 1213a70486f0SDavid S. Miller const xfrm_address_t *daddr, 1214e473fcb4SMathias Krause const xfrm_address_t *saddr, 1215e473fcb4SMathias Krause int create) 12162770834cSDavid S. Miller { 12175447c5e4SAlexey Dobriyan unsigned int h = xfrm_dst_hash(net, daddr, saddr, reqid, family); 12182770834cSDavid S. Miller struct xfrm_state *x; 12193d6acfa7SJamal Hadi Salim u32 mark = m->v & m->m; 12202770834cSDavid S. Miller 1221b67bfe0dSSasha Levin hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) { 12222770834cSDavid S. Miller if (x->props.reqid != reqid || 12232770834cSDavid S. Miller x->props.mode != mode || 12242770834cSDavid S. Miller x->props.family != family || 12252770834cSDavid S. Miller x->km.state != XFRM_STATE_ACQ || 122675e252d9SJoy Latten x->id.spi != 0 || 12271802571bSWei Yongjun x->id.proto != proto || 12283d6acfa7SJamal Hadi Salim (mark & x->mark.m) != x->mark.v || 122970e94e66SYOSHIFUJI Hideaki / 吉藤英明 !xfrm_addr_equal(&x->id.daddr, daddr, family) || 123070e94e66SYOSHIFUJI Hideaki / 吉藤英明 !xfrm_addr_equal(&x->props.saddr, saddr, family)) 12312770834cSDavid S. Miller continue; 12322770834cSDavid S. Miller 12332770834cSDavid S. Miller xfrm_state_hold(x); 12342770834cSDavid S. Miller return x; 12352770834cSDavid S. Miller } 12362770834cSDavid S. Miller 12372770834cSDavid S. Miller if (!create) 12382770834cSDavid S. Miller return NULL; 12392770834cSDavid S. Miller 12405447c5e4SAlexey Dobriyan x = xfrm_state_alloc(net); 12412770834cSDavid S. Miller if (likely(x)) { 12422770834cSDavid S. Miller switch (family) { 12432770834cSDavid S. Miller case AF_INET: 12442770834cSDavid S. Miller x->sel.daddr.a4 = daddr->a4; 12452770834cSDavid S. Miller x->sel.saddr.a4 = saddr->a4; 12462770834cSDavid S. Miller x->sel.prefixlen_d = 32; 12472770834cSDavid S. Miller x->sel.prefixlen_s = 32; 12482770834cSDavid S. Miller x->props.saddr.a4 = saddr->a4; 12492770834cSDavid S. Miller x->id.daddr.a4 = daddr->a4; 12502770834cSDavid S. Miller break; 12512770834cSDavid S. Miller 12522770834cSDavid S. Miller case AF_INET6: 125315e318bdSJiri Benc x->sel.daddr.in6 = daddr->in6; 125415e318bdSJiri Benc x->sel.saddr.in6 = saddr->in6; 12552770834cSDavid S. Miller x->sel.prefixlen_d = 128; 12562770834cSDavid S. Miller x->sel.prefixlen_s = 128; 125715e318bdSJiri Benc x->props.saddr.in6 = saddr->in6; 125815e318bdSJiri Benc x->id.daddr.in6 = daddr->in6; 12592770834cSDavid S. Miller break; 12603ff50b79SStephen Hemminger } 12612770834cSDavid S. Miller 12622770834cSDavid S. Miller x->km.state = XFRM_STATE_ACQ; 12632770834cSDavid S. Miller x->id.proto = proto; 12642770834cSDavid S. Miller x->props.family = family; 12652770834cSDavid S. Miller x->props.mode = mode; 12662770834cSDavid S. Miller x->props.reqid = reqid; 12677e652640SSteffen Klassert x->if_id = if_id; 1268bd55775cSJamal Hadi Salim x->mark.v = m->v; 1269bd55775cSJamal Hadi Salim x->mark.m = m->m; 1270b27aeadbSAlexey Dobriyan x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires; 12712770834cSDavid S. Miller xfrm_state_hold(x); 1272671422b2SThomas Gleixner hrtimer_start(&x->mtimer, 1273671422b2SThomas Gleixner ktime_set(net->xfrm.sysctl_acq_expires, 0), 1274671422b2SThomas Gleixner HRTIMER_MODE_REL_SOFT); 12755447c5e4SAlexey Dobriyan list_add(&x->km.all, &net->xfrm.state_all); 1276ae3fb6d3SFlorian Westphal hlist_add_head_rcu(&x->bydst, net->xfrm.state_bydst + h); 12775447c5e4SAlexey Dobriyan h = xfrm_src_hash(net, daddr, saddr, family); 1278ae3fb6d3SFlorian Westphal hlist_add_head_rcu(&x->bysrc, net->xfrm.state_bysrc + h); 1279918049f0SDavid S. Miller 12805447c5e4SAlexey Dobriyan net->xfrm.state_num++; 1281918049f0SDavid S. Miller 12825447c5e4SAlexey Dobriyan xfrm_hash_grow_check(net, x->bydst.next != NULL); 12832770834cSDavid S. Miller } 12842770834cSDavid S. Miller 12852770834cSDavid S. Miller return x; 12862770834cSDavid S. Miller } 12872770834cSDavid S. Miller 1288bd55775cSJamal Hadi Salim static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq); 12891da177e4SLinus Torvalds 12901da177e4SLinus Torvalds int xfrm_state_add(struct xfrm_state *x) 12911da177e4SLinus Torvalds { 12925447c5e4SAlexey Dobriyan struct net *net = xs_net(x); 129337b08e34SDavid S. Miller struct xfrm_state *x1, *to_put; 12941da177e4SLinus Torvalds int family; 12951da177e4SLinus Torvalds int err; 1296bd55775cSJamal Hadi Salim u32 mark = x->mark.v & x->mark.m; 1297eb2971b6SMasahide NAKAMURA int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY); 12981da177e4SLinus Torvalds 12991da177e4SLinus Torvalds family = x->props.family; 13001da177e4SLinus Torvalds 130137b08e34SDavid S. Miller to_put = NULL; 130237b08e34SDavid S. Miller 1303283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 13041da177e4SLinus Torvalds 1305edcd5821SDavid S. Miller x1 = __xfrm_state_locate(x, use_spi, family); 13061da177e4SLinus Torvalds if (x1) { 130737b08e34SDavid S. Miller to_put = x1; 13081da177e4SLinus Torvalds x1 = NULL; 13091da177e4SLinus Torvalds err = -EEXIST; 13101da177e4SLinus Torvalds goto out; 13111da177e4SLinus Torvalds } 13121da177e4SLinus Torvalds 1313eb2971b6SMasahide NAKAMURA if (use_spi && x->km.seq) { 1314bd55775cSJamal Hadi Salim x1 = __xfrm_find_acq_byseq(net, mark, x->km.seq); 131575e252d9SJoy Latten if (x1 && ((x1->id.proto != x->id.proto) || 131670e94e66SYOSHIFUJI Hideaki / 吉藤英明 !xfrm_addr_equal(&x1->id.daddr, &x->id.daddr, family))) { 131737b08e34SDavid S. Miller to_put = x1; 13181da177e4SLinus Torvalds x1 = NULL; 13191da177e4SLinus Torvalds } 13201da177e4SLinus Torvalds } 13211da177e4SLinus Torvalds 1322eb2971b6SMasahide NAKAMURA if (use_spi && !x1) 1323bd55775cSJamal Hadi Salim x1 = __find_acq_core(net, &x->mark, family, x->props.mode, 13247e652640SSteffen Klassert x->props.reqid, x->if_id, x->id.proto, 13251da177e4SLinus Torvalds &x->id.daddr, &x->props.saddr, 0); 13261da177e4SLinus Torvalds 1327c7f5ea3aSDavid S. Miller __xfrm_state_bump_genids(x); 13281da177e4SLinus Torvalds __xfrm_state_insert(x); 13291da177e4SLinus Torvalds err = 0; 13301da177e4SLinus Torvalds 13311da177e4SLinus Torvalds out: 1332283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 13331da177e4SLinus Torvalds 13341da177e4SLinus Torvalds if (x1) { 13351da177e4SLinus Torvalds xfrm_state_delete(x1); 13361da177e4SLinus Torvalds xfrm_state_put(x1); 13371da177e4SLinus Torvalds } 13381da177e4SLinus Torvalds 133937b08e34SDavid S. Miller if (to_put) 134037b08e34SDavid S. Miller xfrm_state_put(to_put); 134137b08e34SDavid S. Miller 13421da177e4SLinus Torvalds return err; 13431da177e4SLinus Torvalds } 13441da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_add); 13451da177e4SLinus Torvalds 134680c9abaaSShinta Sugimoto #ifdef CONFIG_XFRM_MIGRATE 13474ab47d47SAntony Antony static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, 13484ab47d47SAntony Antony struct xfrm_encap_tmpl *encap) 134980c9abaaSShinta Sugimoto { 135098806f75SAlexey Dobriyan struct net *net = xs_net(orig); 135198806f75SAlexey Dobriyan struct xfrm_state *x = xfrm_state_alloc(net); 135280c9abaaSShinta Sugimoto if (!x) 1353553f9118SHerbert Xu goto out; 135480c9abaaSShinta Sugimoto 135580c9abaaSShinta Sugimoto memcpy(&x->id, &orig->id, sizeof(x->id)); 135680c9abaaSShinta Sugimoto memcpy(&x->sel, &orig->sel, sizeof(x->sel)); 135780c9abaaSShinta Sugimoto memcpy(&x->lft, &orig->lft, sizeof(x->lft)); 135880c9abaaSShinta Sugimoto x->props.mode = orig->props.mode; 135980c9abaaSShinta Sugimoto x->props.replay_window = orig->props.replay_window; 136080c9abaaSShinta Sugimoto x->props.reqid = orig->props.reqid; 136180c9abaaSShinta Sugimoto x->props.family = orig->props.family; 136280c9abaaSShinta Sugimoto x->props.saddr = orig->props.saddr; 136380c9abaaSShinta Sugimoto 136480c9abaaSShinta Sugimoto if (orig->aalg) { 13654447bb33SMartin Willi x->aalg = xfrm_algo_auth_clone(orig->aalg); 136680c9abaaSShinta Sugimoto if (!x->aalg) 136780c9abaaSShinta Sugimoto goto error; 136880c9abaaSShinta Sugimoto } 136980c9abaaSShinta Sugimoto x->props.aalgo = orig->props.aalgo; 137080c9abaaSShinta Sugimoto 1371ee5c2317SSteffen Klassert if (orig->aead) { 1372ee5c2317SSteffen Klassert x->aead = xfrm_algo_aead_clone(orig->aead); 137375bf50f4SAntony Antony x->geniv = orig->geniv; 1374ee5c2317SSteffen Klassert if (!x->aead) 1375ee5c2317SSteffen Klassert goto error; 1376ee5c2317SSteffen Klassert } 137780c9abaaSShinta Sugimoto if (orig->ealg) { 137880c9abaaSShinta Sugimoto x->ealg = xfrm_algo_clone(orig->ealg); 137980c9abaaSShinta Sugimoto if (!x->ealg) 138080c9abaaSShinta Sugimoto goto error; 138180c9abaaSShinta Sugimoto } 138280c9abaaSShinta Sugimoto x->props.ealgo = orig->props.ealgo; 138380c9abaaSShinta Sugimoto 138480c9abaaSShinta Sugimoto if (orig->calg) { 138580c9abaaSShinta Sugimoto x->calg = xfrm_algo_clone(orig->calg); 138680c9abaaSShinta Sugimoto if (!x->calg) 138780c9abaaSShinta Sugimoto goto error; 138880c9abaaSShinta Sugimoto } 138980c9abaaSShinta Sugimoto x->props.calgo = orig->props.calgo; 139080c9abaaSShinta Sugimoto 13914ab47d47SAntony Antony if (encap || orig->encap) { 13924ab47d47SAntony Antony if (encap) 13934ab47d47SAntony Antony x->encap = kmemdup(encap, sizeof(*x->encap), 13944ab47d47SAntony Antony GFP_KERNEL); 13954ab47d47SAntony Antony else 13964ab47d47SAntony Antony x->encap = kmemdup(orig->encap, sizeof(*x->encap), 13974ab47d47SAntony Antony GFP_KERNEL); 13984ab47d47SAntony Antony 139980c9abaaSShinta Sugimoto if (!x->encap) 140080c9abaaSShinta Sugimoto goto error; 140180c9abaaSShinta Sugimoto } 140280c9abaaSShinta Sugimoto 140380c9abaaSShinta Sugimoto if (orig->coaddr) { 140480c9abaaSShinta Sugimoto x->coaddr = kmemdup(orig->coaddr, sizeof(*x->coaddr), 140580c9abaaSShinta Sugimoto GFP_KERNEL); 140680c9abaaSShinta Sugimoto if (!x->coaddr) 140780c9abaaSShinta Sugimoto goto error; 140880c9abaaSShinta Sugimoto } 140980c9abaaSShinta Sugimoto 1410af2f464eSSteffen Klassert if (orig->replay_esn) { 1411cc9ab60eSSteffen Klassert if (xfrm_replay_clone(x, orig)) 1412af2f464eSSteffen Klassert goto error; 1413af2f464eSSteffen Klassert } 1414af2f464eSSteffen Klassert 1415bd55775cSJamal Hadi Salim memcpy(&x->mark, &orig->mark, sizeof(x->mark)); 1416bd55775cSJamal Hadi Salim 1417cc9ab60eSSteffen Klassert if (xfrm_init_state(x) < 0) 141880c9abaaSShinta Sugimoto goto error; 141980c9abaaSShinta Sugimoto 142080c9abaaSShinta Sugimoto x->props.flags = orig->props.flags; 1421a947b0a9SNicolas Dichtel x->props.extra_flags = orig->props.extra_flags; 142280c9abaaSShinta Sugimoto 14237e652640SSteffen Klassert x->if_id = orig->if_id; 1424ee5c2317SSteffen Klassert x->tfcpad = orig->tfcpad; 1425ee5c2317SSteffen Klassert x->replay_maxdiff = orig->replay_maxdiff; 1426ee5c2317SSteffen Klassert x->replay_maxage = orig->replay_maxage; 142780c9abaaSShinta Sugimoto x->curlft.add_time = orig->curlft.add_time; 142880c9abaaSShinta Sugimoto x->km.state = orig->km.state; 142980c9abaaSShinta Sugimoto x->km.seq = orig->km.seq; 1430a486cd23SAntony Antony x->replay = orig->replay; 1431a486cd23SAntony Antony x->preplay = orig->preplay; 143280c9abaaSShinta Sugimoto 143380c9abaaSShinta Sugimoto return x; 143480c9abaaSShinta Sugimoto 143580c9abaaSShinta Sugimoto error: 1436553f9118SHerbert Xu xfrm_state_put(x); 1437553f9118SHerbert Xu out: 143880c9abaaSShinta Sugimoto return NULL; 143980c9abaaSShinta Sugimoto } 144080c9abaaSShinta Sugimoto 1441283bc9f3SFan Du struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *net) 144280c9abaaSShinta Sugimoto { 144380c9abaaSShinta Sugimoto unsigned int h; 14448c0cba22SSteffen Klassert struct xfrm_state *x = NULL; 14458c0cba22SSteffen Klassert 14468c0cba22SSteffen Klassert spin_lock_bh(&net->xfrm.xfrm_state_lock); 144780c9abaaSShinta Sugimoto 144880c9abaaSShinta Sugimoto if (m->reqid) { 1449283bc9f3SFan Du h = xfrm_dst_hash(net, &m->old_daddr, &m->old_saddr, 145080c9abaaSShinta Sugimoto m->reqid, m->old_family); 1451283bc9f3SFan Du hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) { 145280c9abaaSShinta Sugimoto if (x->props.mode != m->mode || 145380c9abaaSShinta Sugimoto x->id.proto != m->proto) 145480c9abaaSShinta Sugimoto continue; 145580c9abaaSShinta Sugimoto if (m->reqid && x->props.reqid != m->reqid) 145680c9abaaSShinta Sugimoto continue; 145770e94e66SYOSHIFUJI Hideaki / 吉藤英明 if (!xfrm_addr_equal(&x->id.daddr, &m->old_daddr, 145880c9abaaSShinta Sugimoto m->old_family) || 145970e94e66SYOSHIFUJI Hideaki / 吉藤英明 !xfrm_addr_equal(&x->props.saddr, &m->old_saddr, 146080c9abaaSShinta Sugimoto m->old_family)) 146180c9abaaSShinta Sugimoto continue; 146280c9abaaSShinta Sugimoto xfrm_state_hold(x); 14638c0cba22SSteffen Klassert break; 146480c9abaaSShinta Sugimoto } 146580c9abaaSShinta Sugimoto } else { 1466283bc9f3SFan Du h = xfrm_src_hash(net, &m->old_daddr, &m->old_saddr, 146780c9abaaSShinta Sugimoto m->old_family); 1468283bc9f3SFan Du hlist_for_each_entry(x, net->xfrm.state_bysrc+h, bysrc) { 146980c9abaaSShinta Sugimoto if (x->props.mode != m->mode || 147080c9abaaSShinta Sugimoto x->id.proto != m->proto) 147180c9abaaSShinta Sugimoto continue; 147270e94e66SYOSHIFUJI Hideaki / 吉藤英明 if (!xfrm_addr_equal(&x->id.daddr, &m->old_daddr, 147380c9abaaSShinta Sugimoto m->old_family) || 147470e94e66SYOSHIFUJI Hideaki / 吉藤英明 !xfrm_addr_equal(&x->props.saddr, &m->old_saddr, 147580c9abaaSShinta Sugimoto m->old_family)) 147680c9abaaSShinta Sugimoto continue; 147780c9abaaSShinta Sugimoto xfrm_state_hold(x); 14788c0cba22SSteffen Klassert break; 147980c9abaaSShinta Sugimoto } 148080c9abaaSShinta Sugimoto } 148180c9abaaSShinta Sugimoto 14828c0cba22SSteffen Klassert spin_unlock_bh(&net->xfrm.xfrm_state_lock); 14838c0cba22SSteffen Klassert 14848c0cba22SSteffen Klassert return x; 148580c9abaaSShinta Sugimoto } 148680c9abaaSShinta Sugimoto EXPORT_SYMBOL(xfrm_migrate_state_find); 148780c9abaaSShinta Sugimoto 148880c9abaaSShinta Sugimoto struct xfrm_state *xfrm_state_migrate(struct xfrm_state *x, 14894ab47d47SAntony Antony struct xfrm_migrate *m, 14904ab47d47SAntony Antony struct xfrm_encap_tmpl *encap) 149180c9abaaSShinta Sugimoto { 149280c9abaaSShinta Sugimoto struct xfrm_state *xc; 149380c9abaaSShinta Sugimoto 14944ab47d47SAntony Antony xc = xfrm_state_clone(x, encap); 149580c9abaaSShinta Sugimoto if (!xc) 149680c9abaaSShinta Sugimoto return NULL; 149780c9abaaSShinta Sugimoto 149880c9abaaSShinta Sugimoto memcpy(&xc->id.daddr, &m->new_daddr, sizeof(xc->id.daddr)); 149980c9abaaSShinta Sugimoto memcpy(&xc->props.saddr, &m->new_saddr, sizeof(xc->props.saddr)); 150080c9abaaSShinta Sugimoto 150180c9abaaSShinta Sugimoto /* add state */ 150270e94e66SYOSHIFUJI Hideaki / 吉藤英明 if (xfrm_addr_equal(&x->id.daddr, &m->new_daddr, m->new_family)) { 150380c9abaaSShinta Sugimoto /* a care is needed when the destination address of the 150480c9abaaSShinta Sugimoto state is to be updated as it is a part of triplet */ 150580c9abaaSShinta Sugimoto xfrm_state_insert(xc); 150680c9abaaSShinta Sugimoto } else { 1507cc9ab60eSSteffen Klassert if (xfrm_state_add(xc) < 0) 150880c9abaaSShinta Sugimoto goto error; 150980c9abaaSShinta Sugimoto } 151080c9abaaSShinta Sugimoto 151180c9abaaSShinta Sugimoto return xc; 151280c9abaaSShinta Sugimoto error: 151378347c8cSThomas Egerer xfrm_state_put(xc); 151480c9abaaSShinta Sugimoto return NULL; 151580c9abaaSShinta Sugimoto } 151680c9abaaSShinta Sugimoto EXPORT_SYMBOL(xfrm_state_migrate); 151780c9abaaSShinta Sugimoto #endif 151880c9abaaSShinta Sugimoto 15191da177e4SLinus Torvalds int xfrm_state_update(struct xfrm_state *x) 15201da177e4SLinus Torvalds { 152137b08e34SDavid S. Miller struct xfrm_state *x1, *to_put; 15221da177e4SLinus Torvalds int err; 1523eb2971b6SMasahide NAKAMURA int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY); 1524283bc9f3SFan Du struct net *net = xs_net(x); 15251da177e4SLinus Torvalds 152637b08e34SDavid S. Miller to_put = NULL; 152737b08e34SDavid S. Miller 1528283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 1529edcd5821SDavid S. Miller x1 = __xfrm_state_locate(x, use_spi, x->props.family); 15301da177e4SLinus Torvalds 15311da177e4SLinus Torvalds err = -ESRCH; 15321da177e4SLinus Torvalds if (!x1) 15331da177e4SLinus Torvalds goto out; 15341da177e4SLinus Torvalds 15351da177e4SLinus Torvalds if (xfrm_state_kern(x1)) { 153637b08e34SDavid S. Miller to_put = x1; 15371da177e4SLinus Torvalds err = -EEXIST; 15381da177e4SLinus Torvalds goto out; 15391da177e4SLinus Torvalds } 15401da177e4SLinus Torvalds 15411da177e4SLinus Torvalds if (x1->km.state == XFRM_STATE_ACQ) { 15421da177e4SLinus Torvalds __xfrm_state_insert(x); 15431da177e4SLinus Torvalds x = NULL; 15441da177e4SLinus Torvalds } 15451da177e4SLinus Torvalds err = 0; 15461da177e4SLinus Torvalds 15471da177e4SLinus Torvalds out: 1548283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 15491da177e4SLinus Torvalds 155037b08e34SDavid S. Miller if (to_put) 155137b08e34SDavid S. Miller xfrm_state_put(to_put); 155237b08e34SDavid S. Miller 15531da177e4SLinus Torvalds if (err) 15541da177e4SLinus Torvalds return err; 15551da177e4SLinus Torvalds 15561da177e4SLinus Torvalds if (!x) { 15571da177e4SLinus Torvalds xfrm_state_delete(x1); 15581da177e4SLinus Torvalds xfrm_state_put(x1); 15591da177e4SLinus Torvalds return 0; 15601da177e4SLinus Torvalds } 15611da177e4SLinus Torvalds 15621da177e4SLinus Torvalds err = -EINVAL; 15631da177e4SLinus Torvalds spin_lock_bh(&x1->lock); 15641da177e4SLinus Torvalds if (likely(x1->km.state == XFRM_STATE_VALID)) { 1565257a4b01SHerbert Xu if (x->encap && x1->encap && 1566257a4b01SHerbert Xu x->encap->encap_type == x1->encap->encap_type) 15671da177e4SLinus Torvalds memcpy(x1->encap, x->encap, sizeof(*x1->encap)); 1568257a4b01SHerbert Xu else if (x->encap || x1->encap) 1569257a4b01SHerbert Xu goto fail; 1570257a4b01SHerbert Xu 1571060f02a3SNoriaki TAKAMIYA if (x->coaddr && x1->coaddr) { 1572060f02a3SNoriaki TAKAMIYA memcpy(x1->coaddr, x->coaddr, sizeof(*x1->coaddr)); 1573060f02a3SNoriaki TAKAMIYA } 1574060f02a3SNoriaki TAKAMIYA if (!use_spi && memcmp(&x1->sel, &x->sel, sizeof(x1->sel))) 1575060f02a3SNoriaki TAKAMIYA memcpy(&x1->sel, &x->sel, sizeof(x1->sel)); 15761da177e4SLinus Torvalds memcpy(&x1->lft, &x->lft, sizeof(x1->lft)); 15771da177e4SLinus Torvalds x1->km.dying = 0; 15781da177e4SLinus Torvalds 1579671422b2SThomas Gleixner hrtimer_start(&x1->mtimer, ktime_set(1, 0), 1580671422b2SThomas Gleixner HRTIMER_MODE_REL_SOFT); 15811da177e4SLinus Torvalds if (x1->curlft.use_time) 15821da177e4SLinus Torvalds xfrm_state_check_expire(x1); 15831da177e4SLinus Torvalds 15845baf4f9cSNathan Harold if (x->props.smark.m || x->props.smark.v || x->if_id) { 15856d8e85ffSNathan Harold spin_lock_bh(&net->xfrm.xfrm_state_lock); 15866d8e85ffSNathan Harold 15875baf4f9cSNathan Harold if (x->props.smark.m || x->props.smark.v) 15886d8e85ffSNathan Harold x1->props.smark = x->props.smark; 15896d8e85ffSNathan Harold 15905baf4f9cSNathan Harold if (x->if_id) 15915baf4f9cSNathan Harold x1->if_id = x->if_id; 15925baf4f9cSNathan Harold 15936d8e85ffSNathan Harold __xfrm_state_bump_genids(x1); 15946d8e85ffSNathan Harold spin_unlock_bh(&net->xfrm.xfrm_state_lock); 15956d8e85ffSNathan Harold } 15966d8e85ffSNathan Harold 15971da177e4SLinus Torvalds err = 0; 15988fcbc637STushar Gohad x->km.state = XFRM_STATE_DEAD; 15998fcbc637STushar Gohad __xfrm_state_put(x); 16001da177e4SLinus Torvalds } 1601257a4b01SHerbert Xu 1602257a4b01SHerbert Xu fail: 16031da177e4SLinus Torvalds spin_unlock_bh(&x1->lock); 16041da177e4SLinus Torvalds 16051da177e4SLinus Torvalds xfrm_state_put(x1); 16061da177e4SLinus Torvalds 16071da177e4SLinus Torvalds return err; 16081da177e4SLinus Torvalds } 16091da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_update); 16101da177e4SLinus Torvalds 16111da177e4SLinus Torvalds int xfrm_state_check_expire(struct xfrm_state *x) 16121da177e4SLinus Torvalds { 16131da177e4SLinus Torvalds if (!x->curlft.use_time) 1614386c5680SArnd Bergmann x->curlft.use_time = ktime_get_real_seconds(); 16151da177e4SLinus Torvalds 16161da177e4SLinus Torvalds if (x->curlft.bytes >= x->lft.hard_byte_limit || 16171da177e4SLinus Torvalds x->curlft.packets >= x->lft.hard_packet_limit) { 16184666faabSHerbert Xu x->km.state = XFRM_STATE_EXPIRED; 1619671422b2SThomas Gleixner hrtimer_start(&x->mtimer, 0, HRTIMER_MODE_REL_SOFT); 16201da177e4SLinus Torvalds return -EINVAL; 16211da177e4SLinus Torvalds } 16221da177e4SLinus Torvalds 16231da177e4SLinus Torvalds if (!x->km.dying && 16241da177e4SLinus Torvalds (x->curlft.bytes >= x->lft.soft_byte_limit || 16254666faabSHerbert Xu x->curlft.packets >= x->lft.soft_packet_limit)) { 16264666faabSHerbert Xu x->km.dying = 1; 162753bc6b4dSJamal Hadi Salim km_state_expired(x, 0, 0); 16284666faabSHerbert Xu } 16291da177e4SLinus Torvalds return 0; 16301da177e4SLinus Torvalds } 16311da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_check_expire); 16321da177e4SLinus Torvalds 16331da177e4SLinus Torvalds struct xfrm_state * 1634a70486f0SDavid S. Miller xfrm_state_lookup(struct net *net, u32 mark, const xfrm_address_t *daddr, __be32 spi, 1635bd55775cSJamal Hadi Salim u8 proto, unsigned short family) 16361da177e4SLinus Torvalds { 16371da177e4SLinus Torvalds struct xfrm_state *x; 16381da177e4SLinus Torvalds 1639c2f672fcSFlorian Westphal rcu_read_lock(); 1640bd55775cSJamal Hadi Salim x = __xfrm_state_lookup(net, mark, daddr, spi, proto, family); 1641c2f672fcSFlorian Westphal rcu_read_unlock(); 16421da177e4SLinus Torvalds return x; 16431da177e4SLinus Torvalds } 16441da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_lookup); 16451da177e4SLinus Torvalds 16461da177e4SLinus Torvalds struct xfrm_state * 1647bd55775cSJamal Hadi Salim xfrm_state_lookup_byaddr(struct net *net, u32 mark, 1648a70486f0SDavid S. Miller const xfrm_address_t *daddr, const xfrm_address_t *saddr, 1649eb2971b6SMasahide NAKAMURA u8 proto, unsigned short family) 1650eb2971b6SMasahide NAKAMURA { 1651eb2971b6SMasahide NAKAMURA struct xfrm_state *x; 1652eb2971b6SMasahide NAKAMURA 1653283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 1654bd55775cSJamal Hadi Salim x = __xfrm_state_lookup_byaddr(net, mark, daddr, saddr, proto, family); 1655283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 1656eb2971b6SMasahide NAKAMURA return x; 1657eb2971b6SMasahide NAKAMURA } 1658eb2971b6SMasahide NAKAMURA EXPORT_SYMBOL(xfrm_state_lookup_byaddr); 1659eb2971b6SMasahide NAKAMURA 1660eb2971b6SMasahide NAKAMURA struct xfrm_state * 1661e473fcb4SMathias Krause xfrm_find_acq(struct net *net, const struct xfrm_mark *mark, u8 mode, u32 reqid, 16627e652640SSteffen Klassert u32 if_id, u8 proto, const xfrm_address_t *daddr, 1663e473fcb4SMathias Krause const xfrm_address_t *saddr, int create, unsigned short family) 16641da177e4SLinus Torvalds { 16651da177e4SLinus Torvalds struct xfrm_state *x; 16661da177e4SLinus Torvalds 1667283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 16687e652640SSteffen Klassert x = __find_acq_core(net, mark, family, mode, reqid, if_id, proto, daddr, saddr, create); 1669283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 16702770834cSDavid S. Miller 16711da177e4SLinus Torvalds return x; 16721da177e4SLinus Torvalds } 16731da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_find_acq); 16741da177e4SLinus Torvalds 167541a49cc3SMasahide NAKAMURA #ifdef CONFIG_XFRM_SUB_POLICY 167641a49cc3SMasahide NAKAMURA int 167741a49cc3SMasahide NAKAMURA xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n, 1678283bc9f3SFan Du unsigned short family, struct net *net) 167941a49cc3SMasahide NAKAMURA { 16803f5a95adSKoichiro Den int i; 168141a49cc3SMasahide NAKAMURA int err = 0; 168241a49cc3SMasahide NAKAMURA struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); 168341a49cc3SMasahide NAKAMURA if (!afinfo) 168441a49cc3SMasahide NAKAMURA return -EAFNOSUPPORT; 168541a49cc3SMasahide NAKAMURA 1686283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); /*FIXME*/ 168741a49cc3SMasahide NAKAMURA if (afinfo->tmpl_sort) 168841a49cc3SMasahide NAKAMURA err = afinfo->tmpl_sort(dst, src, n); 16893f5a95adSKoichiro Den else 16903f5a95adSKoichiro Den for (i = 0; i < n; i++) 16913f5a95adSKoichiro Den dst[i] = src[i]; 1692283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 1693af5d27c4SFlorian Westphal rcu_read_unlock(); 169441a49cc3SMasahide NAKAMURA return err; 169541a49cc3SMasahide NAKAMURA } 169641a49cc3SMasahide NAKAMURA EXPORT_SYMBOL(xfrm_tmpl_sort); 169741a49cc3SMasahide NAKAMURA 169841a49cc3SMasahide NAKAMURA int 169941a49cc3SMasahide NAKAMURA xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n, 170041a49cc3SMasahide NAKAMURA unsigned short family) 170141a49cc3SMasahide NAKAMURA { 17023f5a95adSKoichiro Den int i; 170341a49cc3SMasahide NAKAMURA int err = 0; 170441a49cc3SMasahide NAKAMURA struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); 170535ea790dSSteffen Klassert struct net *net = xs_net(*src); 1706283bc9f3SFan Du 170741a49cc3SMasahide NAKAMURA if (!afinfo) 170841a49cc3SMasahide NAKAMURA return -EAFNOSUPPORT; 170941a49cc3SMasahide NAKAMURA 1710283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 171141a49cc3SMasahide NAKAMURA if (afinfo->state_sort) 171241a49cc3SMasahide NAKAMURA err = afinfo->state_sort(dst, src, n); 17133f5a95adSKoichiro Den else 17143f5a95adSKoichiro Den for (i = 0; i < n; i++) 17153f5a95adSKoichiro Den dst[i] = src[i]; 1716283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 1717af5d27c4SFlorian Westphal rcu_read_unlock(); 171841a49cc3SMasahide NAKAMURA return err; 171941a49cc3SMasahide NAKAMURA } 172041a49cc3SMasahide NAKAMURA EXPORT_SYMBOL(xfrm_state_sort); 172141a49cc3SMasahide NAKAMURA #endif 172241a49cc3SMasahide NAKAMURA 17231da177e4SLinus Torvalds /* Silly enough, but I'm lazy to build resolution list */ 17241da177e4SLinus Torvalds 1725bd55775cSJamal Hadi Salim static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq) 17261da177e4SLinus Torvalds { 17271da177e4SLinus Torvalds int i; 17281da177e4SLinus Torvalds 17295447c5e4SAlexey Dobriyan for (i = 0; i <= net->xfrm.state_hmask; i++) { 17308f126e37SDavid S. Miller struct xfrm_state *x; 17318f126e37SDavid S. Miller 1732b67bfe0dSSasha Levin hlist_for_each_entry(x, net->xfrm.state_bydst+i, bydst) { 17338f126e37SDavid S. Miller if (x->km.seq == seq && 17343d6acfa7SJamal Hadi Salim (mark & x->mark.m) == x->mark.v && 17358f126e37SDavid S. Miller x->km.state == XFRM_STATE_ACQ) { 17361da177e4SLinus Torvalds xfrm_state_hold(x); 17371da177e4SLinus Torvalds return x; 17381da177e4SLinus Torvalds } 17391da177e4SLinus Torvalds } 17401da177e4SLinus Torvalds } 17411da177e4SLinus Torvalds return NULL; 17421da177e4SLinus Torvalds } 17431da177e4SLinus Torvalds 1744bd55775cSJamal Hadi Salim struct xfrm_state *xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq) 17451da177e4SLinus Torvalds { 17461da177e4SLinus Torvalds struct xfrm_state *x; 17471da177e4SLinus Torvalds 1748283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 1749bd55775cSJamal Hadi Salim x = __xfrm_find_acq_byseq(net, mark, seq); 1750283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 17511da177e4SLinus Torvalds return x; 17521da177e4SLinus Torvalds } 17531da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_find_acq_byseq); 17541da177e4SLinus Torvalds 17551da177e4SLinus Torvalds u32 xfrm_get_acqseq(void) 17561da177e4SLinus Torvalds { 17571da177e4SLinus Torvalds u32 res; 17586836b9bdSjamal static atomic_t acqseq; 17591da177e4SLinus Torvalds 17606836b9bdSjamal do { 17616836b9bdSjamal res = atomic_inc_return(&acqseq); 17626836b9bdSjamal } while (!res); 17636836b9bdSjamal 17641da177e4SLinus Torvalds return res; 17651da177e4SLinus Torvalds } 17661da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_get_acqseq); 17671da177e4SLinus Torvalds 1768776e9dd9SFan Du int verify_spi_info(u8 proto, u32 min, u32 max) 1769776e9dd9SFan Du { 1770776e9dd9SFan Du switch (proto) { 1771776e9dd9SFan Du case IPPROTO_AH: 1772776e9dd9SFan Du case IPPROTO_ESP: 1773776e9dd9SFan Du break; 1774776e9dd9SFan Du 1775776e9dd9SFan Du case IPPROTO_COMP: 1776776e9dd9SFan Du /* IPCOMP spi is 16-bits. */ 1777776e9dd9SFan Du if (max >= 0x10000) 1778776e9dd9SFan Du return -EINVAL; 1779776e9dd9SFan Du break; 1780776e9dd9SFan Du 1781776e9dd9SFan Du default: 1782776e9dd9SFan Du return -EINVAL; 1783776e9dd9SFan Du } 1784776e9dd9SFan Du 1785776e9dd9SFan Du if (min > max) 1786776e9dd9SFan Du return -EINVAL; 1787776e9dd9SFan Du 1788776e9dd9SFan Du return 0; 1789776e9dd9SFan Du } 1790776e9dd9SFan Du EXPORT_SYMBOL(verify_spi_info); 1791776e9dd9SFan Du 1792658b219eSHerbert Xu int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high) 17931da177e4SLinus Torvalds { 1794221df1edSAlexey Dobriyan struct net *net = xs_net(x); 1795f034b5d4SDavid S. Miller unsigned int h; 17961da177e4SLinus Torvalds struct xfrm_state *x0; 1797658b219eSHerbert Xu int err = -ENOENT; 1798658b219eSHerbert Xu __be32 minspi = htonl(low); 1799658b219eSHerbert Xu __be32 maxspi = htonl(high); 1800bd55775cSJamal Hadi Salim u32 mark = x->mark.v & x->mark.m; 18011da177e4SLinus Torvalds 1802658b219eSHerbert Xu spin_lock_bh(&x->lock); 1803658b219eSHerbert Xu if (x->km.state == XFRM_STATE_DEAD) 1804658b219eSHerbert Xu goto unlock; 1805658b219eSHerbert Xu 1806658b219eSHerbert Xu err = 0; 18071da177e4SLinus Torvalds if (x->id.spi) 1808658b219eSHerbert Xu goto unlock; 1809658b219eSHerbert Xu 1810658b219eSHerbert Xu err = -ENOENT; 18111da177e4SLinus Torvalds 18121da177e4SLinus Torvalds if (minspi == maxspi) { 1813bd55775cSJamal Hadi Salim x0 = xfrm_state_lookup(net, mark, &x->id.daddr, minspi, x->id.proto, x->props.family); 18141da177e4SLinus Torvalds if (x0) { 18151da177e4SLinus Torvalds xfrm_state_put(x0); 1816658b219eSHerbert Xu goto unlock; 18171da177e4SLinus Torvalds } 18181da177e4SLinus Torvalds x->id.spi = minspi; 18191da177e4SLinus Torvalds } else { 18201da177e4SLinus Torvalds u32 spi = 0; 182126977b4eSAl Viro for (h = 0; h < high-low+1; h++) { 182263862b5bSAruna-Hewapathirane spi = low + prandom_u32()%(high-low+1); 1823bd55775cSJamal Hadi Salim x0 = xfrm_state_lookup(net, mark, &x->id.daddr, htonl(spi), x->id.proto, x->props.family); 18241da177e4SLinus Torvalds if (x0 == NULL) { 18251da177e4SLinus Torvalds x->id.spi = htonl(spi); 18261da177e4SLinus Torvalds break; 18271da177e4SLinus Torvalds } 18281da177e4SLinus Torvalds xfrm_state_put(x0); 18291da177e4SLinus Torvalds } 18301da177e4SLinus Torvalds } 18311da177e4SLinus Torvalds if (x->id.spi) { 1832283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 183312604d8aSAlexey Dobriyan h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, x->props.family); 1834ae3fb6d3SFlorian Westphal hlist_add_head_rcu(&x->byspi, net->xfrm.state_byspi + h); 1835283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 1836658b219eSHerbert Xu 1837658b219eSHerbert Xu err = 0; 18381da177e4SLinus Torvalds } 1839658b219eSHerbert Xu 1840658b219eSHerbert Xu unlock: 1841658b219eSHerbert Xu spin_unlock_bh(&x->lock); 1842658b219eSHerbert Xu 1843658b219eSHerbert Xu return err; 18441da177e4SLinus Torvalds } 18451da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_alloc_spi); 18461da177e4SLinus Torvalds 1847d3623099SNicolas Dichtel static bool __xfrm_state_filter_match(struct xfrm_state *x, 1848870a2df4SNicolas Dichtel struct xfrm_address_filter *filter) 1849d3623099SNicolas Dichtel { 1850d3623099SNicolas Dichtel if (filter) { 1851d3623099SNicolas Dichtel if ((filter->family == AF_INET || 1852d3623099SNicolas Dichtel filter->family == AF_INET6) && 1853d3623099SNicolas Dichtel x->props.family != filter->family) 1854d3623099SNicolas Dichtel return false; 1855d3623099SNicolas Dichtel 1856d3623099SNicolas Dichtel return addr_match(&x->props.saddr, &filter->saddr, 1857d3623099SNicolas Dichtel filter->splen) && 1858d3623099SNicolas Dichtel addr_match(&x->id.daddr, &filter->daddr, 1859d3623099SNicolas Dichtel filter->dplen); 1860d3623099SNicolas Dichtel } 1861d3623099SNicolas Dichtel return true; 1862d3623099SNicolas Dichtel } 1863d3623099SNicolas Dichtel 1864284fa7daSAlexey Dobriyan int xfrm_state_walk(struct net *net, struct xfrm_state_walk *walk, 18654c563f76STimo Teras int (*func)(struct xfrm_state *, int, void*), 18661da177e4SLinus Torvalds void *data) 18671da177e4SLinus Torvalds { 186812a169e7SHerbert Xu struct xfrm_state *state; 186912a169e7SHerbert Xu struct xfrm_state_walk *x; 18701da177e4SLinus Torvalds int err = 0; 18711da177e4SLinus Torvalds 187212a169e7SHerbert Xu if (walk->seq != 0 && list_empty(&walk->all)) 18734c563f76STimo Teras return 0; 18744c563f76STimo Teras 1875283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 187612a169e7SHerbert Xu if (list_empty(&walk->all)) 1877284fa7daSAlexey Dobriyan x = list_first_entry(&net->xfrm.state_all, struct xfrm_state_walk, all); 187812a169e7SHerbert Xu else 187980077702SLi RongQing x = list_first_entry(&walk->all, struct xfrm_state_walk, all); 1880284fa7daSAlexey Dobriyan list_for_each_entry_from(x, &net->xfrm.state_all, all) { 188112a169e7SHerbert Xu if (x->state == XFRM_STATE_DEAD) 18824c563f76STimo Teras continue; 188312a169e7SHerbert Xu state = container_of(x, struct xfrm_state, km); 188412a169e7SHerbert Xu if (!xfrm_id_proto_match(state->id.proto, walk->proto)) 188594b9bb54SJamal Hadi Salim continue; 1886d3623099SNicolas Dichtel if (!__xfrm_state_filter_match(state, walk->filter)) 1887d3623099SNicolas Dichtel continue; 188812a169e7SHerbert Xu err = func(state, walk->seq, data); 18894c563f76STimo Teras if (err) { 189012a169e7SHerbert Xu list_move_tail(&walk->all, &x->all); 189194b9bb54SJamal Hadi Salim goto out; 189294b9bb54SJamal Hadi Salim } 189312a169e7SHerbert Xu walk->seq++; 18944c563f76STimo Teras } 189512a169e7SHerbert Xu if (walk->seq == 0) { 18961da177e4SLinus Torvalds err = -ENOENT; 18971da177e4SLinus Torvalds goto out; 18981da177e4SLinus Torvalds } 189912a169e7SHerbert Xu list_del_init(&walk->all); 19001da177e4SLinus Torvalds out: 1901283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 19021da177e4SLinus Torvalds return err; 19031da177e4SLinus Torvalds } 19041da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_walk); 19051da177e4SLinus Torvalds 1906d3623099SNicolas Dichtel void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto, 1907870a2df4SNicolas Dichtel struct xfrm_address_filter *filter) 19085c182458SHerbert Xu { 190912a169e7SHerbert Xu INIT_LIST_HEAD(&walk->all); 19105c182458SHerbert Xu walk->proto = proto; 191112a169e7SHerbert Xu walk->state = XFRM_STATE_DEAD; 191212a169e7SHerbert Xu walk->seq = 0; 1913d3623099SNicolas Dichtel walk->filter = filter; 19145c182458SHerbert Xu } 19155c182458SHerbert Xu EXPORT_SYMBOL(xfrm_state_walk_init); 19165c182458SHerbert Xu 1917283bc9f3SFan Du void xfrm_state_walk_done(struct xfrm_state_walk *walk, struct net *net) 1918abb81c4fSHerbert Xu { 1919d3623099SNicolas Dichtel kfree(walk->filter); 1920d3623099SNicolas Dichtel 192112a169e7SHerbert Xu if (list_empty(&walk->all)) 19225c182458SHerbert Xu return; 19235c182458SHerbert Xu 1924283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 192512a169e7SHerbert Xu list_del(&walk->all); 1926283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 1927abb81c4fSHerbert Xu } 1928abb81c4fSHerbert Xu EXPORT_SYMBOL(xfrm_state_walk_done); 1929abb81c4fSHerbert Xu 1930e99e88a9SKees Cook static void xfrm_replay_timer_handler(struct timer_list *t) 1931f8cd5488SJamal Hadi Salim { 1932e99e88a9SKees Cook struct xfrm_state *x = from_timer(x, t, rtimer); 1933f8cd5488SJamal Hadi Salim 1934f8cd5488SJamal Hadi Salim spin_lock(&x->lock); 1935f8cd5488SJamal Hadi Salim 19362717096aSJamal Hadi Salim if (x->km.state == XFRM_STATE_VALID) { 1937a6483b79SAlexey Dobriyan if (xfrm_aevent_is_on(xs_net(x))) 19389fdc4883SSteffen Klassert x->repl->notify(x, XFRM_REPLAY_TIMEOUT); 19392717096aSJamal Hadi Salim else 19402717096aSJamal Hadi Salim x->xflags |= XFRM_TIME_DEFER; 19412717096aSJamal Hadi Salim } 1942f8cd5488SJamal Hadi Salim 1943f8cd5488SJamal Hadi Salim spin_unlock(&x->lock); 1944f8cd5488SJamal Hadi Salim } 1945f8cd5488SJamal Hadi Salim 1946df01812eSDenis Cheng static LIST_HEAD(xfrm_km_list); 19471da177e4SLinus Torvalds 1948214e005bSDavid S. Miller void km_policy_notify(struct xfrm_policy *xp, int dir, const struct km_event *c) 19491da177e4SLinus Torvalds { 19501da177e4SLinus Torvalds struct xfrm_mgr *km; 19511da177e4SLinus Torvalds 195285168c00SCong Wang rcu_read_lock(); 195385168c00SCong Wang list_for_each_entry_rcu(km, &xfrm_km_list, list) 195426b15dadSJamal Hadi Salim if (km->notify_policy) 195526b15dadSJamal Hadi Salim km->notify_policy(xp, dir, c); 195685168c00SCong Wang rcu_read_unlock(); 195726b15dadSJamal Hadi Salim } 195826b15dadSJamal Hadi Salim 1959214e005bSDavid S. Miller void km_state_notify(struct xfrm_state *x, const struct km_event *c) 196026b15dadSJamal Hadi Salim { 196126b15dadSJamal Hadi Salim struct xfrm_mgr *km; 196285168c00SCong Wang rcu_read_lock(); 196385168c00SCong Wang list_for_each_entry_rcu(km, &xfrm_km_list, list) 196426b15dadSJamal Hadi Salim if (km->notify) 196526b15dadSJamal Hadi Salim km->notify(x, c); 196685168c00SCong Wang rcu_read_unlock(); 196726b15dadSJamal Hadi Salim } 196826b15dadSJamal Hadi Salim 196926b15dadSJamal Hadi Salim EXPORT_SYMBOL(km_policy_notify); 197026b15dadSJamal Hadi Salim EXPORT_SYMBOL(km_state_notify); 197126b15dadSJamal Hadi Salim 197215e47304SEric W. Biederman void km_state_expired(struct xfrm_state *x, int hard, u32 portid) 197326b15dadSJamal Hadi Salim { 197426b15dadSJamal Hadi Salim struct km_event c; 197526b15dadSJamal Hadi Salim 1976bf08867fSHerbert Xu c.data.hard = hard; 197715e47304SEric W. Biederman c.portid = portid; 1978f60f6b8fSHerbert Xu c.event = XFRM_MSG_EXPIRE; 197926b15dadSJamal Hadi Salim km_state_notify(x, &c); 19801da177e4SLinus Torvalds } 19811da177e4SLinus Torvalds 198253bc6b4dSJamal Hadi Salim EXPORT_SYMBOL(km_state_expired); 198326b15dadSJamal Hadi Salim /* 198426b15dadSJamal Hadi Salim * We send to all registered managers regardless of failure 198526b15dadSJamal Hadi Salim * We are happy with one success 198626b15dadSJamal Hadi Salim */ 1987980ebd25SJamal Hadi Salim int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol) 19881da177e4SLinus Torvalds { 198926b15dadSJamal Hadi Salim int err = -EINVAL, acqret; 19901da177e4SLinus Torvalds struct xfrm_mgr *km; 19911da177e4SLinus Torvalds 199285168c00SCong Wang rcu_read_lock(); 199385168c00SCong Wang list_for_each_entry_rcu(km, &xfrm_km_list, list) { 199465e0736bSFan Du acqret = km->acquire(x, t, pol); 199526b15dadSJamal Hadi Salim if (!acqret) 199626b15dadSJamal Hadi Salim err = acqret; 19971da177e4SLinus Torvalds } 199885168c00SCong Wang rcu_read_unlock(); 19991da177e4SLinus Torvalds return err; 20001da177e4SLinus Torvalds } 2001980ebd25SJamal Hadi Salim EXPORT_SYMBOL(km_query); 20021da177e4SLinus Torvalds 20035d36b180SAl Viro int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport) 20041da177e4SLinus Torvalds { 20051da177e4SLinus Torvalds int err = -EINVAL; 20061da177e4SLinus Torvalds struct xfrm_mgr *km; 20071da177e4SLinus Torvalds 200885168c00SCong Wang rcu_read_lock(); 200985168c00SCong Wang list_for_each_entry_rcu(km, &xfrm_km_list, list) { 20101da177e4SLinus Torvalds if (km->new_mapping) 20111da177e4SLinus Torvalds err = km->new_mapping(x, ipaddr, sport); 20121da177e4SLinus Torvalds if (!err) 20131da177e4SLinus Torvalds break; 20141da177e4SLinus Torvalds } 201585168c00SCong Wang rcu_read_unlock(); 20161da177e4SLinus Torvalds return err; 20171da177e4SLinus Torvalds } 20181da177e4SLinus Torvalds EXPORT_SYMBOL(km_new_mapping); 20191da177e4SLinus Torvalds 202015e47304SEric W. Biederman void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 portid) 20211da177e4SLinus Torvalds { 202226b15dadSJamal Hadi Salim struct km_event c; 20231da177e4SLinus Torvalds 2024bf08867fSHerbert Xu c.data.hard = hard; 202515e47304SEric W. Biederman c.portid = portid; 2026f60f6b8fSHerbert Xu c.event = XFRM_MSG_POLEXPIRE; 202726b15dadSJamal Hadi Salim km_policy_notify(pol, dir, &c); 20281da177e4SLinus Torvalds } 2029a70fcb0bSDavid S. Miller EXPORT_SYMBOL(km_policy_expired); 20301da177e4SLinus Torvalds 20312d60abc2SEric Dumazet #ifdef CONFIG_XFRM_MIGRATE 2032183cad12SDavid S. Miller int km_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, 2033183cad12SDavid S. Miller const struct xfrm_migrate *m, int num_migrate, 20348bafd730SAntony Antony const struct xfrm_kmaddress *k, 20358bafd730SAntony Antony const struct xfrm_encap_tmpl *encap) 203680c9abaaSShinta Sugimoto { 203780c9abaaSShinta Sugimoto int err = -EINVAL; 203880c9abaaSShinta Sugimoto int ret; 203980c9abaaSShinta Sugimoto struct xfrm_mgr *km; 204080c9abaaSShinta Sugimoto 204185168c00SCong Wang rcu_read_lock(); 204285168c00SCong Wang list_for_each_entry_rcu(km, &xfrm_km_list, list) { 204380c9abaaSShinta Sugimoto if (km->migrate) { 20448bafd730SAntony Antony ret = km->migrate(sel, dir, type, m, num_migrate, k, 20458bafd730SAntony Antony encap); 204680c9abaaSShinta Sugimoto if (!ret) 204780c9abaaSShinta Sugimoto err = ret; 204880c9abaaSShinta Sugimoto } 204980c9abaaSShinta Sugimoto } 205085168c00SCong Wang rcu_read_unlock(); 205180c9abaaSShinta Sugimoto return err; 205280c9abaaSShinta Sugimoto } 205380c9abaaSShinta Sugimoto EXPORT_SYMBOL(km_migrate); 20542d60abc2SEric Dumazet #endif 205580c9abaaSShinta Sugimoto 2056db983c11SAlexey Dobriyan int km_report(struct net *net, u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr) 205797a64b45SMasahide NAKAMURA { 205897a64b45SMasahide NAKAMURA int err = -EINVAL; 205997a64b45SMasahide NAKAMURA int ret; 206097a64b45SMasahide NAKAMURA struct xfrm_mgr *km; 206197a64b45SMasahide NAKAMURA 206285168c00SCong Wang rcu_read_lock(); 206385168c00SCong Wang list_for_each_entry_rcu(km, &xfrm_km_list, list) { 206497a64b45SMasahide NAKAMURA if (km->report) { 2065db983c11SAlexey Dobriyan ret = km->report(net, proto, sel, addr); 206697a64b45SMasahide NAKAMURA if (!ret) 206797a64b45SMasahide NAKAMURA err = ret; 206897a64b45SMasahide NAKAMURA } 206997a64b45SMasahide NAKAMURA } 207085168c00SCong Wang rcu_read_unlock(); 207197a64b45SMasahide NAKAMURA return err; 207297a64b45SMasahide NAKAMURA } 207397a64b45SMasahide NAKAMURA EXPORT_SYMBOL(km_report); 207497a64b45SMasahide NAKAMURA 20750f24558eSHoria Geanta bool km_is_alive(const struct km_event *c) 20760f24558eSHoria Geanta { 20770f24558eSHoria Geanta struct xfrm_mgr *km; 20780f24558eSHoria Geanta bool is_alive = false; 20790f24558eSHoria Geanta 20800f24558eSHoria Geanta rcu_read_lock(); 20810f24558eSHoria Geanta list_for_each_entry_rcu(km, &xfrm_km_list, list) { 20820f24558eSHoria Geanta if (km->is_alive && km->is_alive(c)) { 20830f24558eSHoria Geanta is_alive = true; 20840f24558eSHoria Geanta break; 20850f24558eSHoria Geanta } 20860f24558eSHoria Geanta } 20870f24558eSHoria Geanta rcu_read_unlock(); 20880f24558eSHoria Geanta 20890f24558eSHoria Geanta return is_alive; 20900f24558eSHoria Geanta } 20910f24558eSHoria Geanta EXPORT_SYMBOL(km_is_alive); 20920f24558eSHoria Geanta 20931da177e4SLinus Torvalds int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen) 20941da177e4SLinus Torvalds { 20951da177e4SLinus Torvalds int err; 20961da177e4SLinus Torvalds u8 *data; 20971da177e4SLinus Torvalds struct xfrm_mgr *km; 20981da177e4SLinus Torvalds struct xfrm_policy *pol = NULL; 20991da177e4SLinus Torvalds 210019d7df69SSteffen Klassert if (in_compat_syscall()) 210119d7df69SSteffen Klassert return -EOPNOTSUPP; 210219d7df69SSteffen Klassert 2103be8f8284SLorenzo Colitti if (!optval && !optlen) { 2104be8f8284SLorenzo Colitti xfrm_sk_policy_insert(sk, XFRM_POLICY_IN, NULL); 2105be8f8284SLorenzo Colitti xfrm_sk_policy_insert(sk, XFRM_POLICY_OUT, NULL); 2106be8f8284SLorenzo Colitti __sk_dst_reset(sk); 2107be8f8284SLorenzo Colitti return 0; 2108be8f8284SLorenzo Colitti } 2109be8f8284SLorenzo Colitti 21101da177e4SLinus Torvalds if (optlen <= 0 || optlen > PAGE_SIZE) 21111da177e4SLinus Torvalds return -EMSGSIZE; 21121da177e4SLinus Torvalds 2113a133d930SGeliang Tang data = memdup_user(optval, optlen); 2114a133d930SGeliang Tang if (IS_ERR(data)) 2115a133d930SGeliang Tang return PTR_ERR(data); 21161da177e4SLinus Torvalds 21171da177e4SLinus Torvalds err = -EINVAL; 211885168c00SCong Wang rcu_read_lock(); 211985168c00SCong Wang list_for_each_entry_rcu(km, &xfrm_km_list, list) { 2120cb969f07SVenkat Yekkirala pol = km->compile_policy(sk, optname, data, 21211da177e4SLinus Torvalds optlen, &err); 21221da177e4SLinus Torvalds if (err >= 0) 21231da177e4SLinus Torvalds break; 21241da177e4SLinus Torvalds } 212585168c00SCong Wang rcu_read_unlock(); 21261da177e4SLinus Torvalds 21271da177e4SLinus Torvalds if (err >= 0) { 21281da177e4SLinus Torvalds xfrm_sk_policy_insert(sk, err, pol); 21291da177e4SLinus Torvalds xfrm_pol_put(pol); 21302b06cdf3SJonathan Basseri __sk_dst_reset(sk); 21311da177e4SLinus Torvalds err = 0; 21321da177e4SLinus Torvalds } 21331da177e4SLinus Torvalds 21341da177e4SLinus Torvalds kfree(data); 21351da177e4SLinus Torvalds return err; 21361da177e4SLinus Torvalds } 21371da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_user_policy); 21381da177e4SLinus Torvalds 213985168c00SCong Wang static DEFINE_SPINLOCK(xfrm_km_lock); 214085168c00SCong Wang 21411da177e4SLinus Torvalds int xfrm_register_km(struct xfrm_mgr *km) 21421da177e4SLinus Torvalds { 214385168c00SCong Wang spin_lock_bh(&xfrm_km_lock); 214485168c00SCong Wang list_add_tail_rcu(&km->list, &xfrm_km_list); 214585168c00SCong Wang spin_unlock_bh(&xfrm_km_lock); 21461da177e4SLinus Torvalds return 0; 21471da177e4SLinus Torvalds } 21481da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_register_km); 21491da177e4SLinus Torvalds 21501da177e4SLinus Torvalds int xfrm_unregister_km(struct xfrm_mgr *km) 21511da177e4SLinus Torvalds { 215285168c00SCong Wang spin_lock_bh(&xfrm_km_lock); 215385168c00SCong Wang list_del_rcu(&km->list); 215485168c00SCong Wang spin_unlock_bh(&xfrm_km_lock); 215585168c00SCong Wang synchronize_rcu(); 21561da177e4SLinus Torvalds return 0; 21571da177e4SLinus Torvalds } 21581da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_unregister_km); 21591da177e4SLinus Torvalds 21601da177e4SLinus Torvalds int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo) 21611da177e4SLinus Torvalds { 21621da177e4SLinus Torvalds int err = 0; 2163423826a7SFlorian Westphal 2164423826a7SFlorian Westphal if (WARN_ON(afinfo->family >= NPROTO)) 21651da177e4SLinus Torvalds return -EAFNOSUPPORT; 2166423826a7SFlorian Westphal 216744abdc30SCong Wang spin_lock_bh(&xfrm_state_afinfo_lock); 21681da177e4SLinus Torvalds if (unlikely(xfrm_state_afinfo[afinfo->family] != NULL)) 2169f31e8d4fSLi RongQing err = -EEXIST; 2170edcd5821SDavid S. Miller else 217144abdc30SCong Wang rcu_assign_pointer(xfrm_state_afinfo[afinfo->family], afinfo); 217244abdc30SCong Wang spin_unlock_bh(&xfrm_state_afinfo_lock); 21731da177e4SLinus Torvalds return err; 21741da177e4SLinus Torvalds } 21751da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_register_afinfo); 21761da177e4SLinus Torvalds 21771da177e4SLinus Torvalds int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo) 21781da177e4SLinus Torvalds { 2179423826a7SFlorian Westphal int err = 0, family = afinfo->family; 2180423826a7SFlorian Westphal 2181423826a7SFlorian Westphal if (WARN_ON(family >= NPROTO)) 21821da177e4SLinus Torvalds return -EAFNOSUPPORT; 2183423826a7SFlorian Westphal 218444abdc30SCong Wang spin_lock_bh(&xfrm_state_afinfo_lock); 21851da177e4SLinus Torvalds if (likely(xfrm_state_afinfo[afinfo->family] != NULL)) { 2186423826a7SFlorian Westphal if (rcu_access_pointer(xfrm_state_afinfo[family]) != afinfo) 21871da177e4SLinus Torvalds err = -EINVAL; 2188edcd5821SDavid S. Miller else 218944abdc30SCong Wang RCU_INIT_POINTER(xfrm_state_afinfo[afinfo->family], NULL); 21901da177e4SLinus Torvalds } 219144abdc30SCong Wang spin_unlock_bh(&xfrm_state_afinfo_lock); 219244abdc30SCong Wang synchronize_rcu(); 21931da177e4SLinus Torvalds return err; 21941da177e4SLinus Torvalds } 21951da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_unregister_afinfo); 21961da177e4SLinus Torvalds 2197711059b9SFlorian Westphal struct xfrm_state_afinfo *xfrm_state_afinfo_get_rcu(unsigned int family) 2198711059b9SFlorian Westphal { 2199711059b9SFlorian Westphal if (unlikely(family >= NPROTO)) 2200711059b9SFlorian Westphal return NULL; 2201711059b9SFlorian Westphal 2202711059b9SFlorian Westphal return rcu_dereference(xfrm_state_afinfo[family]); 2203711059b9SFlorian Westphal } 2204711059b9SFlorian Westphal 2205628e341fSHannes Frederic Sowa struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family) 22061da177e4SLinus Torvalds { 22071da177e4SLinus Torvalds struct xfrm_state_afinfo *afinfo; 22081da177e4SLinus Torvalds if (unlikely(family >= NPROTO)) 22091da177e4SLinus Torvalds return NULL; 221044abdc30SCong Wang rcu_read_lock(); 221144abdc30SCong Wang afinfo = rcu_dereference(xfrm_state_afinfo[family]); 2212546be240SHerbert Xu if (unlikely(!afinfo)) 221344abdc30SCong Wang rcu_read_unlock(); 22141da177e4SLinus Torvalds return afinfo; 22151da177e4SLinus Torvalds } 22161da177e4SLinus Torvalds 2217b48c05abSSteffen Klassert void xfrm_flush_gc(void) 2218b48c05abSSteffen Klassert { 2219b48c05abSSteffen Klassert flush_work(&xfrm_state_gc_work); 2220b48c05abSSteffen Klassert } 2221b48c05abSSteffen Klassert EXPORT_SYMBOL(xfrm_flush_gc); 2222b48c05abSSteffen Klassert 22231da177e4SLinus Torvalds /* Temporarily located here until net/xfrm/xfrm_tunnel.c is created */ 22241da177e4SLinus Torvalds void xfrm_state_delete_tunnel(struct xfrm_state *x) 22251da177e4SLinus Torvalds { 22261da177e4SLinus Torvalds if (x->tunnel) { 22271da177e4SLinus Torvalds struct xfrm_state *t = x->tunnel; 22281da177e4SLinus Torvalds 22291da177e4SLinus Torvalds if (atomic_read(&t->tunnel_users) == 2) 22301da177e4SLinus Torvalds xfrm_state_delete(t); 22311da177e4SLinus Torvalds atomic_dec(&t->tunnel_users); 2232f75a2804SCong Wang xfrm_state_put_sync(t); 22331da177e4SLinus Torvalds x->tunnel = NULL; 22341da177e4SLinus Torvalds } 22351da177e4SLinus Torvalds } 22361da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_delete_tunnel); 22371da177e4SLinus Torvalds 22381da177e4SLinus Torvalds int xfrm_state_mtu(struct xfrm_state *x, int mtu) 22391da177e4SLinus Torvalds { 2240b3b73b8eSFlorian Westphal const struct xfrm_type *type = READ_ONCE(x->type); 22411da177e4SLinus Torvalds 22421da177e4SLinus Torvalds if (x->km.state == XFRM_STATE_VALID && 2243b3b73b8eSFlorian Westphal type && type->get_mtu) 2244b3b73b8eSFlorian Westphal return type->get_mtu(x, mtu); 2245b3b73b8eSFlorian Westphal 2246b3b73b8eSFlorian Westphal return mtu - x->props.header_len; 22471da177e4SLinus Torvalds } 22481da177e4SLinus Torvalds 2249ffdb5211SIlan Tayari int __xfrm_init_state(struct xfrm_state *x, bool init_replay, bool offload) 225072cb6962SHerbert Xu { 2251d094cd83SHerbert Xu struct xfrm_state_afinfo *afinfo; 2252df9dcb45SKazunori MIYAZAWA struct xfrm_mode *inner_mode; 2253d094cd83SHerbert Xu int family = x->props.family; 225472cb6962SHerbert Xu int err; 225572cb6962SHerbert Xu 2256d094cd83SHerbert Xu err = -EAFNOSUPPORT; 2257d094cd83SHerbert Xu afinfo = xfrm_state_get_afinfo(family); 2258d094cd83SHerbert Xu if (!afinfo) 2259d094cd83SHerbert Xu goto error; 2260d094cd83SHerbert Xu 2261d094cd83SHerbert Xu err = 0; 2262d094cd83SHerbert Xu if (afinfo->init_flags) 2263d094cd83SHerbert Xu err = afinfo->init_flags(x); 2264d094cd83SHerbert Xu 2265af5d27c4SFlorian Westphal rcu_read_unlock(); 2266d094cd83SHerbert Xu 2267d094cd83SHerbert Xu if (err) 2268d094cd83SHerbert Xu goto error; 2269d094cd83SHerbert Xu 2270d094cd83SHerbert Xu err = -EPROTONOSUPPORT; 2271df9dcb45SKazunori MIYAZAWA 2272df9dcb45SKazunori MIYAZAWA if (x->sel.family != AF_UNSPEC) { 2273df9dcb45SKazunori MIYAZAWA inner_mode = xfrm_get_mode(x->props.mode, x->sel.family); 2274df9dcb45SKazunori MIYAZAWA if (inner_mode == NULL) 227513996378SHerbert Xu goto error; 227613996378SHerbert Xu 2277df9dcb45SKazunori MIYAZAWA if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL) && 2278df9dcb45SKazunori MIYAZAWA family != x->sel.family) { 2279df9dcb45SKazunori MIYAZAWA xfrm_put_mode(inner_mode); 228013996378SHerbert Xu goto error; 2281df9dcb45SKazunori MIYAZAWA } 2282df9dcb45SKazunori MIYAZAWA 2283df9dcb45SKazunori MIYAZAWA x->inner_mode = inner_mode; 2284df9dcb45SKazunori MIYAZAWA } else { 2285df9dcb45SKazunori MIYAZAWA struct xfrm_mode *inner_mode_iaf; 2286d81d2285SMartin Willi int iafamily = AF_INET; 2287df9dcb45SKazunori MIYAZAWA 2288d81d2285SMartin Willi inner_mode = xfrm_get_mode(x->props.mode, x->props.family); 2289df9dcb45SKazunori MIYAZAWA if (inner_mode == NULL) 2290df9dcb45SKazunori MIYAZAWA goto error; 2291df9dcb45SKazunori MIYAZAWA 2292df9dcb45SKazunori MIYAZAWA if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL)) { 2293df9dcb45SKazunori MIYAZAWA xfrm_put_mode(inner_mode); 2294df9dcb45SKazunori MIYAZAWA goto error; 2295df9dcb45SKazunori MIYAZAWA } 2296df9dcb45SKazunori MIYAZAWA x->inner_mode = inner_mode; 2297d81d2285SMartin Willi 2298d81d2285SMartin Willi if (x->props.family == AF_INET) 2299d81d2285SMartin Willi iafamily = AF_INET6; 2300d81d2285SMartin Willi 2301d81d2285SMartin Willi inner_mode_iaf = xfrm_get_mode(x->props.mode, iafamily); 2302d81d2285SMartin Willi if (inner_mode_iaf) { 2303d81d2285SMartin Willi if (inner_mode_iaf->flags & XFRM_MODE_FLAG_TUNNEL) 2304df9dcb45SKazunori MIYAZAWA x->inner_mode_iaf = inner_mode_iaf; 2305d81d2285SMartin Willi else 2306d81d2285SMartin Willi xfrm_put_mode(inner_mode_iaf); 2307df9dcb45SKazunori MIYAZAWA } 2308df9dcb45SKazunori MIYAZAWA } 230913996378SHerbert Xu 2310d094cd83SHerbert Xu x->type = xfrm_get_type(x->id.proto, family); 231172cb6962SHerbert Xu if (x->type == NULL) 231272cb6962SHerbert Xu goto error; 231372cb6962SHerbert Xu 2314ffdb5211SIlan Tayari x->type_offload = xfrm_get_type_offload(x->id.proto, family, offload); 23159d389d7fSSteffen Klassert 231672cb6962SHerbert Xu err = x->type->init_state(x); 231772cb6962SHerbert Xu if (err) 231872cb6962SHerbert Xu goto error; 231972cb6962SHerbert Xu 232013996378SHerbert Xu x->outer_mode = xfrm_get_mode(x->props.mode, family); 2321599901c3SJulia Lawall if (x->outer_mode == NULL) { 2322599901c3SJulia Lawall err = -EPROTONOSUPPORT; 2323b59f45d0SHerbert Xu goto error; 2324599901c3SJulia Lawall } 2325b59f45d0SHerbert Xu 2326a454f0ccSWei Yongjun if (init_replay) { 2327a454f0ccSWei Yongjun err = xfrm_init_replay(x); 2328a454f0ccSWei Yongjun if (err) 2329a454f0ccSWei Yongjun goto error; 2330a454f0ccSWei Yongjun } 2331a454f0ccSWei Yongjun 233272cb6962SHerbert Xu error: 233372cb6962SHerbert Xu return err; 233472cb6962SHerbert Xu } 233572cb6962SHerbert Xu 2336a454f0ccSWei Yongjun EXPORT_SYMBOL(__xfrm_init_state); 2337a454f0ccSWei Yongjun 2338a454f0ccSWei Yongjun int xfrm_init_state(struct xfrm_state *x) 2339a454f0ccSWei Yongjun { 2340cc01572eSYossi Kuperman int err; 2341cc01572eSYossi Kuperman 2342cc01572eSYossi Kuperman err = __xfrm_init_state(x, true, false); 2343cc01572eSYossi Kuperman if (!err) 2344cc01572eSYossi Kuperman x->km.state = XFRM_STATE_VALID; 2345cc01572eSYossi Kuperman 2346cc01572eSYossi Kuperman return err; 2347a454f0ccSWei Yongjun } 2348a454f0ccSWei Yongjun 234972cb6962SHerbert Xu EXPORT_SYMBOL(xfrm_init_state); 23501da177e4SLinus Torvalds 2351d62ddc21SAlexey Dobriyan int __net_init xfrm_state_init(struct net *net) 23521da177e4SLinus Torvalds { 2353f034b5d4SDavid S. Miller unsigned int sz; 23541da177e4SLinus Torvalds 2355565f0fa9SMathias Krause if (net_eq(net, &init_net)) 2356565f0fa9SMathias Krause xfrm_state_cache = KMEM_CACHE(xfrm_state, 2357565f0fa9SMathias Krause SLAB_HWCACHE_ALIGN | SLAB_PANIC); 2358565f0fa9SMathias Krause 23599d4139c7SAlexey Dobriyan INIT_LIST_HEAD(&net->xfrm.state_all); 23609d4139c7SAlexey Dobriyan 2361f034b5d4SDavid S. Miller sz = sizeof(struct hlist_head) * 8; 2362f034b5d4SDavid S. Miller 236373d189dcSAlexey Dobriyan net->xfrm.state_bydst = xfrm_hash_alloc(sz); 236473d189dcSAlexey Dobriyan if (!net->xfrm.state_bydst) 236573d189dcSAlexey Dobriyan goto out_bydst; 2366d320bbb3SAlexey Dobriyan net->xfrm.state_bysrc = xfrm_hash_alloc(sz); 2367d320bbb3SAlexey Dobriyan if (!net->xfrm.state_bysrc) 2368d320bbb3SAlexey Dobriyan goto out_bysrc; 2369b754a4fdSAlexey Dobriyan net->xfrm.state_byspi = xfrm_hash_alloc(sz); 2370b754a4fdSAlexey Dobriyan if (!net->xfrm.state_byspi) 2371b754a4fdSAlexey Dobriyan goto out_byspi; 2372529983ecSAlexey Dobriyan net->xfrm.state_hmask = ((sz / sizeof(struct hlist_head)) - 1); 2373f034b5d4SDavid S. Miller 23740bf7c5b0SAlexey Dobriyan net->xfrm.state_num = 0; 237563082733SAlexey Dobriyan INIT_WORK(&net->xfrm.state_hash_work, xfrm_hash_resize); 2376283bc9f3SFan Du spin_lock_init(&net->xfrm.xfrm_state_lock); 2377d62ddc21SAlexey Dobriyan return 0; 237873d189dcSAlexey Dobriyan 2379b754a4fdSAlexey Dobriyan out_byspi: 2380b754a4fdSAlexey Dobriyan xfrm_hash_free(net->xfrm.state_bysrc, sz); 2381d320bbb3SAlexey Dobriyan out_bysrc: 2382d320bbb3SAlexey Dobriyan xfrm_hash_free(net->xfrm.state_bydst, sz); 238373d189dcSAlexey Dobriyan out_bydst: 238473d189dcSAlexey Dobriyan return -ENOMEM; 2385d62ddc21SAlexey Dobriyan } 2386d62ddc21SAlexey Dobriyan 2387d62ddc21SAlexey Dobriyan void xfrm_state_fini(struct net *net) 2388d62ddc21SAlexey Dobriyan { 238973d189dcSAlexey Dobriyan unsigned int sz; 239073d189dcSAlexey Dobriyan 23917c2776eeSAlexey Dobriyan flush_work(&net->xfrm.state_hash_work); 239235db57bbSFlorian Westphal flush_work(&xfrm_state_gc_work); 2393f75a2804SCong Wang xfrm_state_flush(net, IPSEC_PROTO_ANY, false, true); 23947c2776eeSAlexey Dobriyan 23959d4139c7SAlexey Dobriyan WARN_ON(!list_empty(&net->xfrm.state_all)); 239673d189dcSAlexey Dobriyan 2397529983ecSAlexey Dobriyan sz = (net->xfrm.state_hmask + 1) * sizeof(struct hlist_head); 2398b754a4fdSAlexey Dobriyan WARN_ON(!hlist_empty(net->xfrm.state_byspi)); 2399b754a4fdSAlexey Dobriyan xfrm_hash_free(net->xfrm.state_byspi, sz); 2400d320bbb3SAlexey Dobriyan WARN_ON(!hlist_empty(net->xfrm.state_bysrc)); 2401d320bbb3SAlexey Dobriyan xfrm_hash_free(net->xfrm.state_bysrc, sz); 240273d189dcSAlexey Dobriyan WARN_ON(!hlist_empty(net->xfrm.state_bydst)); 240373d189dcSAlexey Dobriyan xfrm_hash_free(net->xfrm.state_bydst, sz); 24041da177e4SLinus Torvalds } 24051da177e4SLinus Torvalds 2406ab5f5e8bSJoy Latten #ifdef CONFIG_AUDITSYSCALL 2407cf35f43eSIlpo Järvinen static void xfrm_audit_helper_sainfo(struct xfrm_state *x, 2408ab5f5e8bSJoy Latten struct audit_buffer *audit_buf) 2409ab5f5e8bSJoy Latten { 241068277accSPaul Moore struct xfrm_sec_ctx *ctx = x->security; 241168277accSPaul Moore u32 spi = ntohl(x->id.spi); 241268277accSPaul Moore 241368277accSPaul Moore if (ctx) 2414ab5f5e8bSJoy Latten audit_log_format(audit_buf, " sec_alg=%u sec_doi=%u sec_obj=%s", 241568277accSPaul Moore ctx->ctx_alg, ctx->ctx_doi, ctx->ctx_str); 2416ab5f5e8bSJoy Latten 2417ab5f5e8bSJoy Latten switch (x->props.family) { 2418ab5f5e8bSJoy Latten case AF_INET: 241921454aaaSHarvey Harrison audit_log_format(audit_buf, " src=%pI4 dst=%pI4", 242021454aaaSHarvey Harrison &x->props.saddr.a4, &x->id.daddr.a4); 2421ab5f5e8bSJoy Latten break; 2422ab5f5e8bSJoy Latten case AF_INET6: 24235b095d98SHarvey Harrison audit_log_format(audit_buf, " src=%pI6 dst=%pI6", 2424fdb46ee7SHarvey Harrison x->props.saddr.a6, x->id.daddr.a6); 2425ab5f5e8bSJoy Latten break; 2426ab5f5e8bSJoy Latten } 242768277accSPaul Moore 242868277accSPaul Moore audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi); 2429ab5f5e8bSJoy Latten } 2430ab5f5e8bSJoy Latten 2431cf35f43eSIlpo Järvinen static void xfrm_audit_helper_pktinfo(struct sk_buff *skb, u16 family, 2432afeb14b4SPaul Moore struct audit_buffer *audit_buf) 2433afeb14b4SPaul Moore { 2434b71d1d42SEric Dumazet const struct iphdr *iph4; 2435b71d1d42SEric Dumazet const struct ipv6hdr *iph6; 2436afeb14b4SPaul Moore 2437afeb14b4SPaul Moore switch (family) { 2438afeb14b4SPaul Moore case AF_INET: 2439afeb14b4SPaul Moore iph4 = ip_hdr(skb); 244021454aaaSHarvey Harrison audit_log_format(audit_buf, " src=%pI4 dst=%pI4", 244121454aaaSHarvey Harrison &iph4->saddr, &iph4->daddr); 2442afeb14b4SPaul Moore break; 2443afeb14b4SPaul Moore case AF_INET6: 2444afeb14b4SPaul Moore iph6 = ipv6_hdr(skb); 2445afeb14b4SPaul Moore audit_log_format(audit_buf, 24465b095d98SHarvey Harrison " src=%pI6 dst=%pI6 flowlbl=0x%x%02x%02x", 2447fdb46ee7SHarvey Harrison &iph6->saddr, &iph6->daddr, 2448afeb14b4SPaul Moore iph6->flow_lbl[0] & 0x0f, 2449afeb14b4SPaul Moore iph6->flow_lbl[1], 2450afeb14b4SPaul Moore iph6->flow_lbl[2]); 2451afeb14b4SPaul Moore break; 2452afeb14b4SPaul Moore } 2453afeb14b4SPaul Moore } 2454afeb14b4SPaul Moore 24552e71029eSTetsuo Handa void xfrm_audit_state_add(struct xfrm_state *x, int result, bool task_valid) 2456ab5f5e8bSJoy Latten { 2457ab5f5e8bSJoy Latten struct audit_buffer *audit_buf; 2458ab5f5e8bSJoy Latten 2459afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SAD-add"); 2460ab5f5e8bSJoy Latten if (audit_buf == NULL) 2461ab5f5e8bSJoy Latten return; 24622e71029eSTetsuo Handa xfrm_audit_helper_usrinfo(task_valid, audit_buf); 2463afeb14b4SPaul Moore xfrm_audit_helper_sainfo(x, audit_buf); 2464afeb14b4SPaul Moore audit_log_format(audit_buf, " res=%u", result); 2465ab5f5e8bSJoy Latten audit_log_end(audit_buf); 2466ab5f5e8bSJoy Latten } 2467ab5f5e8bSJoy Latten EXPORT_SYMBOL_GPL(xfrm_audit_state_add); 2468ab5f5e8bSJoy Latten 24692e71029eSTetsuo Handa void xfrm_audit_state_delete(struct xfrm_state *x, int result, bool task_valid) 2470ab5f5e8bSJoy Latten { 2471ab5f5e8bSJoy Latten struct audit_buffer *audit_buf; 2472ab5f5e8bSJoy Latten 2473afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SAD-delete"); 2474ab5f5e8bSJoy Latten if (audit_buf == NULL) 2475ab5f5e8bSJoy Latten return; 24762e71029eSTetsuo Handa xfrm_audit_helper_usrinfo(task_valid, audit_buf); 2477afeb14b4SPaul Moore xfrm_audit_helper_sainfo(x, audit_buf); 2478afeb14b4SPaul Moore audit_log_format(audit_buf, " res=%u", result); 2479ab5f5e8bSJoy Latten audit_log_end(audit_buf); 2480ab5f5e8bSJoy Latten } 2481ab5f5e8bSJoy Latten EXPORT_SYMBOL_GPL(xfrm_audit_state_delete); 2482afeb14b4SPaul Moore 2483afeb14b4SPaul Moore void xfrm_audit_state_replay_overflow(struct xfrm_state *x, 2484afeb14b4SPaul Moore struct sk_buff *skb) 2485afeb14b4SPaul Moore { 2486afeb14b4SPaul Moore struct audit_buffer *audit_buf; 2487afeb14b4SPaul Moore u32 spi; 2488afeb14b4SPaul Moore 2489afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SA-replay-overflow"); 2490afeb14b4SPaul Moore if (audit_buf == NULL) 2491afeb14b4SPaul Moore return; 2492afeb14b4SPaul Moore xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf); 2493afeb14b4SPaul Moore /* don't record the sequence number because it's inherent in this kind 2494afeb14b4SPaul Moore * of audit message */ 2495afeb14b4SPaul Moore spi = ntohl(x->id.spi); 2496afeb14b4SPaul Moore audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi); 2497afeb14b4SPaul Moore audit_log_end(audit_buf); 2498afeb14b4SPaul Moore } 2499afeb14b4SPaul Moore EXPORT_SYMBOL_GPL(xfrm_audit_state_replay_overflow); 2500afeb14b4SPaul Moore 25019fdc4883SSteffen Klassert void xfrm_audit_state_replay(struct xfrm_state *x, 2502afeb14b4SPaul Moore struct sk_buff *skb, __be32 net_seq) 2503afeb14b4SPaul Moore { 2504afeb14b4SPaul Moore struct audit_buffer *audit_buf; 2505afeb14b4SPaul Moore u32 spi; 2506afeb14b4SPaul Moore 2507afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SA-replayed-pkt"); 2508afeb14b4SPaul Moore if (audit_buf == NULL) 2509afeb14b4SPaul Moore return; 2510afeb14b4SPaul Moore xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf); 2511afeb14b4SPaul Moore spi = ntohl(x->id.spi); 2512afeb14b4SPaul Moore audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u", 2513afeb14b4SPaul Moore spi, spi, ntohl(net_seq)); 2514afeb14b4SPaul Moore audit_log_end(audit_buf); 2515afeb14b4SPaul Moore } 25169fdc4883SSteffen Klassert EXPORT_SYMBOL_GPL(xfrm_audit_state_replay); 2517afeb14b4SPaul Moore 2518afeb14b4SPaul Moore void xfrm_audit_state_notfound_simple(struct sk_buff *skb, u16 family) 2519afeb14b4SPaul Moore { 2520afeb14b4SPaul Moore struct audit_buffer *audit_buf; 2521afeb14b4SPaul Moore 2522afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SA-notfound"); 2523afeb14b4SPaul Moore if (audit_buf == NULL) 2524afeb14b4SPaul Moore return; 2525afeb14b4SPaul Moore xfrm_audit_helper_pktinfo(skb, family, audit_buf); 2526afeb14b4SPaul Moore audit_log_end(audit_buf); 2527afeb14b4SPaul Moore } 2528afeb14b4SPaul Moore EXPORT_SYMBOL_GPL(xfrm_audit_state_notfound_simple); 2529afeb14b4SPaul Moore 2530afeb14b4SPaul Moore void xfrm_audit_state_notfound(struct sk_buff *skb, u16 family, 2531afeb14b4SPaul Moore __be32 net_spi, __be32 net_seq) 2532afeb14b4SPaul Moore { 2533afeb14b4SPaul Moore struct audit_buffer *audit_buf; 2534afeb14b4SPaul Moore u32 spi; 2535afeb14b4SPaul Moore 2536afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SA-notfound"); 2537afeb14b4SPaul Moore if (audit_buf == NULL) 2538afeb14b4SPaul Moore return; 2539afeb14b4SPaul Moore xfrm_audit_helper_pktinfo(skb, family, audit_buf); 2540afeb14b4SPaul Moore spi = ntohl(net_spi); 2541afeb14b4SPaul Moore audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u", 2542afeb14b4SPaul Moore spi, spi, ntohl(net_seq)); 2543afeb14b4SPaul Moore audit_log_end(audit_buf); 2544afeb14b4SPaul Moore } 2545afeb14b4SPaul Moore EXPORT_SYMBOL_GPL(xfrm_audit_state_notfound); 2546afeb14b4SPaul Moore 2547afeb14b4SPaul Moore void xfrm_audit_state_icvfail(struct xfrm_state *x, 2548afeb14b4SPaul Moore struct sk_buff *skb, u8 proto) 2549afeb14b4SPaul Moore { 2550afeb14b4SPaul Moore struct audit_buffer *audit_buf; 2551afeb14b4SPaul Moore __be32 net_spi; 2552afeb14b4SPaul Moore __be32 net_seq; 2553afeb14b4SPaul Moore 2554afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SA-icv-failure"); 2555afeb14b4SPaul Moore if (audit_buf == NULL) 2556afeb14b4SPaul Moore return; 2557afeb14b4SPaul Moore xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf); 2558afeb14b4SPaul Moore if (xfrm_parse_spi(skb, proto, &net_spi, &net_seq) == 0) { 2559afeb14b4SPaul Moore u32 spi = ntohl(net_spi); 2560afeb14b4SPaul Moore audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u", 2561afeb14b4SPaul Moore spi, spi, ntohl(net_seq)); 2562afeb14b4SPaul Moore } 2563afeb14b4SPaul Moore audit_log_end(audit_buf); 2564afeb14b4SPaul Moore } 2565afeb14b4SPaul Moore EXPORT_SYMBOL_GPL(xfrm_audit_state_icvfail); 2566ab5f5e8bSJoy Latten #endif /* CONFIG_AUDITSYSCALL */ 2567