1457c8996SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * xfrm_state.c 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * Changes: 61da177e4SLinus Torvalds * Mitsuru KANDA @USAGI 71da177e4SLinus Torvalds * Kazunori MIYAZAWA @USAGI 81da177e4SLinus Torvalds * Kunihiro Ishiguro <kunihiro@ipinfusion.com> 91da177e4SLinus Torvalds * IPv6 support 101da177e4SLinus Torvalds * YOSHIFUJI Hideaki @USAGI 111da177e4SLinus Torvalds * Split up af-specific functions 121da177e4SLinus Torvalds * Derek Atkins <derek@ihtfp.com> 131da177e4SLinus Torvalds * Add UDP Encapsulation 141da177e4SLinus Torvalds * 151da177e4SLinus Torvalds */ 161da177e4SLinus Torvalds 171da177e4SLinus Torvalds #include <linux/workqueue.h> 181da177e4SLinus Torvalds #include <net/xfrm.h> 191da177e4SLinus Torvalds #include <linux/pfkeyv2.h> 201da177e4SLinus Torvalds #include <linux/ipsec.h> 211da177e4SLinus Torvalds #include <linux/module.h> 22f034b5d4SDavid S. Miller #include <linux/cache.h> 2368277accSPaul Moore #include <linux/audit.h> 247c0f6ba6SLinus Torvalds #include <linux/uaccess.h> 259e0d57fdSYury Polyanskiy #include <linux/ktime.h> 265a0e3ad6STejun Heo #include <linux/slab.h> 279e0d57fdSYury Polyanskiy #include <linux/interrupt.h> 289e0d57fdSYury Polyanskiy #include <linux/kernel.h> 291da177e4SLinus Torvalds 30c7b37c76SFlorian Westphal #include <crypto/aead.h> 31c7b37c76SFlorian Westphal 3244e36b42SDavid S. Miller #include "xfrm_hash.h" 3344e36b42SDavid S. Miller 34c8406998SFlorian Westphal #define xfrm_state_deref_prot(table, net) \ 35c8406998SFlorian Westphal rcu_dereference_protected((table), lockdep_is_held(&(net)->xfrm.xfrm_state_lock)) 36c8406998SFlorian Westphal 3735db57bbSFlorian Westphal static void xfrm_state_gc_task(struct work_struct *work); 3835db57bbSFlorian Westphal 391da177e4SLinus Torvalds /* Each xfrm_state may be linked to two tables: 401da177e4SLinus Torvalds 411da177e4SLinus Torvalds 1. Hash table by (spi,daddr,ah/esp) to find SA by SPI. (input,ctl) 42a624c108SDavid S. Miller 2. Hash table by (daddr,family,reqid) to find what SAs exist for given 431da177e4SLinus Torvalds destination/tunnel endpoint. (output) 441da177e4SLinus Torvalds */ 451da177e4SLinus Torvalds 46f034b5d4SDavid S. Miller static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024; 47b65e3d7bSFlorian Westphal static __read_mostly seqcount_t xfrm_state_hash_generation = SEQCNT_ZERO(xfrm_state_hash_generation); 48565f0fa9SMathias Krause static struct kmem_cache *xfrm_state_cache __ro_after_init; 491da177e4SLinus Torvalds 5035db57bbSFlorian Westphal static DECLARE_WORK(xfrm_state_gc_work, xfrm_state_gc_task); 5135db57bbSFlorian Westphal static HLIST_HEAD(xfrm_state_gc_list); 5235db57bbSFlorian Westphal 5302efdff7SFlorian Westphal static inline bool xfrm_state_hold_rcu(struct xfrm_state __rcu *x) 5402efdff7SFlorian Westphal { 5588755e9cSReshetova, Elena return refcount_inc_not_zero(&x->refcnt); 5602efdff7SFlorian Westphal } 5702efdff7SFlorian Westphal 5864d0cd00SAlexey Dobriyan static inline unsigned int xfrm_dst_hash(struct net *net, 592ab38503SDavid S. Miller const xfrm_address_t *daddr, 602ab38503SDavid S. Miller const xfrm_address_t *saddr, 61c1969f29SDavid S. Miller u32 reqid, 62a624c108SDavid S. Miller unsigned short family) 63a624c108SDavid S. Miller { 6464d0cd00SAlexey Dobriyan return __xfrm_dst_hash(daddr, saddr, reqid, family, net->xfrm.state_hmask); 65a624c108SDavid S. Miller } 66a624c108SDavid S. Miller 6764d0cd00SAlexey Dobriyan static inline unsigned int xfrm_src_hash(struct net *net, 682ab38503SDavid S. Miller const xfrm_address_t *daddr, 692ab38503SDavid S. Miller const xfrm_address_t *saddr, 7044e36b42SDavid S. Miller unsigned short family) 71f034b5d4SDavid S. Miller { 7264d0cd00SAlexey Dobriyan return __xfrm_src_hash(daddr, saddr, family, net->xfrm.state_hmask); 73f034b5d4SDavid S. Miller } 74f034b5d4SDavid S. Miller 752575b654SDavid S. Miller static inline unsigned int 762ab38503SDavid S. Miller xfrm_spi_hash(struct net *net, const xfrm_address_t *daddr, 772ab38503SDavid S. Miller __be32 spi, u8 proto, unsigned short family) 78f034b5d4SDavid S. Miller { 7964d0cd00SAlexey Dobriyan return __xfrm_spi_hash(daddr, spi, proto, family, net->xfrm.state_hmask); 80f034b5d4SDavid S. Miller } 81f034b5d4SDavid S. Miller 82f034b5d4SDavid S. Miller static void xfrm_hash_transfer(struct hlist_head *list, 83f034b5d4SDavid S. Miller struct hlist_head *ndsttable, 84f034b5d4SDavid S. Miller struct hlist_head *nsrctable, 85f034b5d4SDavid S. Miller struct hlist_head *nspitable, 86f034b5d4SDavid S. Miller unsigned int nhashmask) 87f034b5d4SDavid S. Miller { 88b67bfe0dSSasha Levin struct hlist_node *tmp; 89f034b5d4SDavid S. Miller struct xfrm_state *x; 90f034b5d4SDavid S. Miller 91b67bfe0dSSasha Levin hlist_for_each_entry_safe(x, tmp, list, bydst) { 92f034b5d4SDavid S. Miller unsigned int h; 93f034b5d4SDavid S. Miller 94c1969f29SDavid S. Miller h = __xfrm_dst_hash(&x->id.daddr, &x->props.saddr, 95c1969f29SDavid S. Miller x->props.reqid, x->props.family, 96c1969f29SDavid S. Miller nhashmask); 97ae3fb6d3SFlorian Westphal hlist_add_head_rcu(&x->bydst, ndsttable + h); 98f034b5d4SDavid S. Miller 99667bbcb6SMasahide NAKAMURA h = __xfrm_src_hash(&x->id.daddr, &x->props.saddr, 100667bbcb6SMasahide NAKAMURA x->props.family, 101f034b5d4SDavid S. Miller nhashmask); 102ae3fb6d3SFlorian Westphal hlist_add_head_rcu(&x->bysrc, nsrctable + h); 103f034b5d4SDavid S. Miller 1047b4dc360SMasahide NAKAMURA if (x->id.spi) { 1057b4dc360SMasahide NAKAMURA h = __xfrm_spi_hash(&x->id.daddr, x->id.spi, 1067b4dc360SMasahide NAKAMURA x->id.proto, x->props.family, 1077b4dc360SMasahide NAKAMURA nhashmask); 108ae3fb6d3SFlorian Westphal hlist_add_head_rcu(&x->byspi, nspitable + h); 109f034b5d4SDavid S. Miller } 110f034b5d4SDavid S. Miller } 1117b4dc360SMasahide NAKAMURA } 112f034b5d4SDavid S. Miller 11363082733SAlexey Dobriyan static unsigned long xfrm_hash_new_size(unsigned int state_hmask) 114f034b5d4SDavid S. Miller { 11563082733SAlexey Dobriyan return ((state_hmask + 1) << 1) * sizeof(struct hlist_head); 116f034b5d4SDavid S. Miller } 117f034b5d4SDavid S. Miller 11863082733SAlexey Dobriyan static void xfrm_hash_resize(struct work_struct *work) 119f034b5d4SDavid S. Miller { 12063082733SAlexey Dobriyan struct net *net = container_of(work, struct net, xfrm.state_hash_work); 121f034b5d4SDavid S. Miller struct hlist_head *ndst, *nsrc, *nspi, *odst, *osrc, *ospi; 122f034b5d4SDavid S. Miller unsigned long nsize, osize; 123f034b5d4SDavid S. Miller unsigned int nhashmask, ohashmask; 124f034b5d4SDavid S. Miller int i; 125f034b5d4SDavid S. Miller 12663082733SAlexey Dobriyan nsize = xfrm_hash_new_size(net->xfrm.state_hmask); 12744e36b42SDavid S. Miller ndst = xfrm_hash_alloc(nsize); 128f034b5d4SDavid S. Miller if (!ndst) 1290244790cSYing Xue return; 13044e36b42SDavid S. Miller nsrc = xfrm_hash_alloc(nsize); 131f034b5d4SDavid S. Miller if (!nsrc) { 13244e36b42SDavid S. Miller xfrm_hash_free(ndst, nsize); 1330244790cSYing Xue return; 134f034b5d4SDavid S. Miller } 13544e36b42SDavid S. Miller nspi = xfrm_hash_alloc(nsize); 136f034b5d4SDavid S. Miller if (!nspi) { 13744e36b42SDavid S. Miller xfrm_hash_free(ndst, nsize); 13844e36b42SDavid S. Miller xfrm_hash_free(nsrc, nsize); 1390244790cSYing Xue return; 140f034b5d4SDavid S. Miller } 141f034b5d4SDavid S. Miller 142283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 143b65e3d7bSFlorian Westphal write_seqcount_begin(&xfrm_state_hash_generation); 144f034b5d4SDavid S. Miller 145f034b5d4SDavid S. Miller nhashmask = (nsize / sizeof(struct hlist_head)) - 1U; 146c8406998SFlorian Westphal odst = xfrm_state_deref_prot(net->xfrm.state_bydst, net); 14763082733SAlexey Dobriyan for (i = net->xfrm.state_hmask; i >= 0; i--) 148c8406998SFlorian Westphal xfrm_hash_transfer(odst + i, ndst, nsrc, nspi, nhashmask); 149f034b5d4SDavid S. Miller 150c8406998SFlorian Westphal osrc = xfrm_state_deref_prot(net->xfrm.state_bysrc, net); 151c8406998SFlorian Westphal ospi = xfrm_state_deref_prot(net->xfrm.state_byspi, net); 15263082733SAlexey Dobriyan ohashmask = net->xfrm.state_hmask; 153f034b5d4SDavid S. Miller 154c8406998SFlorian Westphal rcu_assign_pointer(net->xfrm.state_bydst, ndst); 155c8406998SFlorian Westphal rcu_assign_pointer(net->xfrm.state_bysrc, nsrc); 156c8406998SFlorian Westphal rcu_assign_pointer(net->xfrm.state_byspi, nspi); 15763082733SAlexey Dobriyan net->xfrm.state_hmask = nhashmask; 158f034b5d4SDavid S. Miller 159b65e3d7bSFlorian Westphal write_seqcount_end(&xfrm_state_hash_generation); 160283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 161f034b5d4SDavid S. Miller 162f034b5d4SDavid S. Miller osize = (ohashmask + 1) * sizeof(struct hlist_head); 163df7274ebSFlorian Westphal 164df7274ebSFlorian Westphal synchronize_rcu(); 165df7274ebSFlorian Westphal 16644e36b42SDavid S. Miller xfrm_hash_free(odst, osize); 16744e36b42SDavid S. Miller xfrm_hash_free(osrc, osize); 16844e36b42SDavid S. Miller xfrm_hash_free(ospi, osize); 169f034b5d4SDavid S. Miller } 170f034b5d4SDavid S. Miller 17144abdc30SCong Wang static DEFINE_SPINLOCK(xfrm_state_afinfo_lock); 17244abdc30SCong Wang static struct xfrm_state_afinfo __rcu *xfrm_state_afinfo[NPROTO]; 1731da177e4SLinus Torvalds 1741da177e4SLinus Torvalds static DEFINE_SPINLOCK(xfrm_state_gc_lock); 1751da177e4SLinus Torvalds 17653bc6b4dSJamal Hadi Salim int __xfrm_state_delete(struct xfrm_state *x); 1771da177e4SLinus Torvalds 178980ebd25SJamal Hadi Salim int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol); 179bb9cd077SFlorian Westphal static bool km_is_alive(const struct km_event *c); 18015e47304SEric W. Biederman void km_state_expired(struct xfrm_state *x, int hard, u32 portid); 1811da177e4SLinus Torvalds 182533cb5b0SEric Dumazet int xfrm_register_type(const struct xfrm_type *type, unsigned short family) 183aa5d62ccSHerbert Xu { 1847a9885b9SCong Wang struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); 185aa5d62ccSHerbert Xu int err = 0; 186aa5d62ccSHerbert Xu 1874f518e80SFlorian Westphal if (!afinfo) 188aa5d62ccSHerbert Xu return -EAFNOSUPPORT; 189aa5d62ccSHerbert Xu 1904f518e80SFlorian Westphal #define X(afi, T, name) do { \ 1914f518e80SFlorian Westphal WARN_ON((afi)->type_ ## name); \ 1924f518e80SFlorian Westphal (afi)->type_ ## name = (T); \ 1934f518e80SFlorian Westphal } while (0) 1944f518e80SFlorian Westphal 1954f518e80SFlorian Westphal switch (type->proto) { 1964f518e80SFlorian Westphal case IPPROTO_COMP: 1974f518e80SFlorian Westphal X(afinfo, type, comp); 1984f518e80SFlorian Westphal break; 1994f518e80SFlorian Westphal case IPPROTO_AH: 2004f518e80SFlorian Westphal X(afinfo, type, ah); 2014f518e80SFlorian Westphal break; 2024f518e80SFlorian Westphal case IPPROTO_ESP: 2034f518e80SFlorian Westphal X(afinfo, type, esp); 2044f518e80SFlorian Westphal break; 2054f518e80SFlorian Westphal case IPPROTO_IPIP: 2064f518e80SFlorian Westphal X(afinfo, type, ipip); 2074f518e80SFlorian Westphal break; 2084f518e80SFlorian Westphal case IPPROTO_DSTOPTS: 2094f518e80SFlorian Westphal X(afinfo, type, dstopts); 2104f518e80SFlorian Westphal break; 2114f518e80SFlorian Westphal case IPPROTO_ROUTING: 2124f518e80SFlorian Westphal X(afinfo, type, routing); 2134f518e80SFlorian Westphal break; 2144f518e80SFlorian Westphal case IPPROTO_IPV6: 2154f518e80SFlorian Westphal X(afinfo, type, ipip6); 2164f518e80SFlorian Westphal break; 2174f518e80SFlorian Westphal default: 2184f518e80SFlorian Westphal WARN_ON(1); 2194f518e80SFlorian Westphal err = -EPROTONOSUPPORT; 2204f518e80SFlorian Westphal break; 2214f518e80SFlorian Westphal } 2224f518e80SFlorian Westphal #undef X 223af5d27c4SFlorian Westphal rcu_read_unlock(); 224aa5d62ccSHerbert Xu return err; 225aa5d62ccSHerbert Xu } 226aa5d62ccSHerbert Xu EXPORT_SYMBOL(xfrm_register_type); 227aa5d62ccSHerbert Xu 2284f518e80SFlorian Westphal void xfrm_unregister_type(const struct xfrm_type *type, unsigned short family) 229aa5d62ccSHerbert Xu { 2307a9885b9SCong Wang struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); 231aa5d62ccSHerbert Xu 232aa5d62ccSHerbert Xu if (unlikely(afinfo == NULL)) 2334f518e80SFlorian Westphal return; 234aa5d62ccSHerbert Xu 2354f518e80SFlorian Westphal #define X(afi, T, name) do { \ 2364f518e80SFlorian Westphal WARN_ON((afi)->type_ ## name != (T)); \ 2374f518e80SFlorian Westphal (afi)->type_ ## name = NULL; \ 2384f518e80SFlorian Westphal } while (0) 2394f518e80SFlorian Westphal 2404f518e80SFlorian Westphal switch (type->proto) { 2414f518e80SFlorian Westphal case IPPROTO_COMP: 2424f518e80SFlorian Westphal X(afinfo, type, comp); 2434f518e80SFlorian Westphal break; 2444f518e80SFlorian Westphal case IPPROTO_AH: 2454f518e80SFlorian Westphal X(afinfo, type, ah); 2464f518e80SFlorian Westphal break; 2474f518e80SFlorian Westphal case IPPROTO_ESP: 2484f518e80SFlorian Westphal X(afinfo, type, esp); 2494f518e80SFlorian Westphal break; 2504f518e80SFlorian Westphal case IPPROTO_IPIP: 2514f518e80SFlorian Westphal X(afinfo, type, ipip); 2524f518e80SFlorian Westphal break; 2534f518e80SFlorian Westphal case IPPROTO_DSTOPTS: 2544f518e80SFlorian Westphal X(afinfo, type, dstopts); 2554f518e80SFlorian Westphal break; 2564f518e80SFlorian Westphal case IPPROTO_ROUTING: 2574f518e80SFlorian Westphal X(afinfo, type, routing); 2584f518e80SFlorian Westphal break; 2594f518e80SFlorian Westphal case IPPROTO_IPV6: 2604f518e80SFlorian Westphal X(afinfo, type, ipip6); 2614f518e80SFlorian Westphal break; 2624f518e80SFlorian Westphal default: 2634f518e80SFlorian Westphal WARN_ON(1); 2644f518e80SFlorian Westphal break; 2654f518e80SFlorian Westphal } 2664f518e80SFlorian Westphal #undef X 267af5d27c4SFlorian Westphal rcu_read_unlock(); 268aa5d62ccSHerbert Xu } 269aa5d62ccSHerbert Xu EXPORT_SYMBOL(xfrm_unregister_type); 270aa5d62ccSHerbert Xu 271533cb5b0SEric Dumazet static const struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family) 272aa5d62ccSHerbert Xu { 2734f518e80SFlorian Westphal const struct xfrm_type *type = NULL; 274aa5d62ccSHerbert Xu struct xfrm_state_afinfo *afinfo; 275aa5d62ccSHerbert Xu int modload_attempted = 0; 276aa5d62ccSHerbert Xu 277aa5d62ccSHerbert Xu retry: 278aa5d62ccSHerbert Xu afinfo = xfrm_state_get_afinfo(family); 279aa5d62ccSHerbert Xu if (unlikely(afinfo == NULL)) 280aa5d62ccSHerbert Xu return NULL; 281aa5d62ccSHerbert Xu 2824f518e80SFlorian Westphal switch (proto) { 2834f518e80SFlorian Westphal case IPPROTO_COMP: 2844f518e80SFlorian Westphal type = afinfo->type_comp; 2854f518e80SFlorian Westphal break; 2864f518e80SFlorian Westphal case IPPROTO_AH: 2874f518e80SFlorian Westphal type = afinfo->type_ah; 2884f518e80SFlorian Westphal break; 2894f518e80SFlorian Westphal case IPPROTO_ESP: 2904f518e80SFlorian Westphal type = afinfo->type_esp; 2914f518e80SFlorian Westphal break; 2924f518e80SFlorian Westphal case IPPROTO_IPIP: 2934f518e80SFlorian Westphal type = afinfo->type_ipip; 2944f518e80SFlorian Westphal break; 2954f518e80SFlorian Westphal case IPPROTO_DSTOPTS: 2964f518e80SFlorian Westphal type = afinfo->type_dstopts; 2974f518e80SFlorian Westphal break; 2984f518e80SFlorian Westphal case IPPROTO_ROUTING: 2994f518e80SFlorian Westphal type = afinfo->type_routing; 3004f518e80SFlorian Westphal break; 3014f518e80SFlorian Westphal case IPPROTO_IPV6: 3024f518e80SFlorian Westphal type = afinfo->type_ipip6; 3034f518e80SFlorian Westphal break; 3044f518e80SFlorian Westphal default: 3054f518e80SFlorian Westphal break; 3064f518e80SFlorian Westphal } 3074f518e80SFlorian Westphal 308aa5d62ccSHerbert Xu if (unlikely(type && !try_module_get(type->owner))) 309aa5d62ccSHerbert Xu type = NULL; 31075cda62dSFlorian Westphal 311af5d27c4SFlorian Westphal rcu_read_unlock(); 31275cda62dSFlorian Westphal 31375cda62dSFlorian Westphal if (!type && !modload_attempted) { 314aa5d62ccSHerbert Xu request_module("xfrm-type-%d-%d", family, proto); 315aa5d62ccSHerbert Xu modload_attempted = 1; 316aa5d62ccSHerbert Xu goto retry; 317aa5d62ccSHerbert Xu } 318aa5d62ccSHerbert Xu 319aa5d62ccSHerbert Xu return type; 320aa5d62ccSHerbert Xu } 321aa5d62ccSHerbert Xu 322533cb5b0SEric Dumazet static void xfrm_put_type(const struct xfrm_type *type) 323aa5d62ccSHerbert Xu { 324aa5d62ccSHerbert Xu module_put(type->owner); 325aa5d62ccSHerbert Xu } 326aa5d62ccSHerbert Xu 3279d389d7fSSteffen Klassert int xfrm_register_type_offload(const struct xfrm_type_offload *type, 3289d389d7fSSteffen Klassert unsigned short family) 3299d389d7fSSteffen Klassert { 3309d389d7fSSteffen Klassert struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); 3319d389d7fSSteffen Klassert int err = 0; 3329d389d7fSSteffen Klassert 3339d389d7fSSteffen Klassert if (unlikely(afinfo == NULL)) 3349d389d7fSSteffen Klassert return -EAFNOSUPPORT; 3359d389d7fSSteffen Klassert 3364f518e80SFlorian Westphal switch (type->proto) { 3374f518e80SFlorian Westphal case IPPROTO_ESP: 3384f518e80SFlorian Westphal WARN_ON(afinfo->type_offload_esp); 3394f518e80SFlorian Westphal afinfo->type_offload_esp = type; 3404f518e80SFlorian Westphal break; 3414f518e80SFlorian Westphal default: 3424f518e80SFlorian Westphal WARN_ON(1); 3434f518e80SFlorian Westphal err = -EPROTONOSUPPORT; 3444f518e80SFlorian Westphal break; 3454f518e80SFlorian Westphal } 3464f518e80SFlorian Westphal 3479d389d7fSSteffen Klassert rcu_read_unlock(); 3489d389d7fSSteffen Klassert return err; 3499d389d7fSSteffen Klassert } 3509d389d7fSSteffen Klassert EXPORT_SYMBOL(xfrm_register_type_offload); 3519d389d7fSSteffen Klassert 3524f518e80SFlorian Westphal void xfrm_unregister_type_offload(const struct xfrm_type_offload *type, 3539d389d7fSSteffen Klassert unsigned short family) 3549d389d7fSSteffen Klassert { 3559d389d7fSSteffen Klassert struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); 3569d389d7fSSteffen Klassert 3579d389d7fSSteffen Klassert if (unlikely(afinfo == NULL)) 3584f518e80SFlorian Westphal return; 3599d389d7fSSteffen Klassert 3604f518e80SFlorian Westphal switch (type->proto) { 3614f518e80SFlorian Westphal case IPPROTO_ESP: 3624f518e80SFlorian Westphal WARN_ON(afinfo->type_offload_esp != type); 3634f518e80SFlorian Westphal afinfo->type_offload_esp = NULL; 3644f518e80SFlorian Westphal break; 3654f518e80SFlorian Westphal default: 3664f518e80SFlorian Westphal WARN_ON(1); 3674f518e80SFlorian Westphal break; 3684f518e80SFlorian Westphal } 3699d389d7fSSteffen Klassert rcu_read_unlock(); 3709d389d7fSSteffen Klassert } 3719d389d7fSSteffen Klassert EXPORT_SYMBOL(xfrm_unregister_type_offload); 3729d389d7fSSteffen Klassert 373ffdb5211SIlan Tayari static const struct xfrm_type_offload * 374ffdb5211SIlan Tayari xfrm_get_type_offload(u8 proto, unsigned short family, bool try_load) 3759d389d7fSSteffen Klassert { 3764f518e80SFlorian Westphal const struct xfrm_type_offload *type = NULL; 3779d389d7fSSteffen Klassert struct xfrm_state_afinfo *afinfo; 3789d389d7fSSteffen Klassert 379ffdb5211SIlan Tayari retry: 3809d389d7fSSteffen Klassert afinfo = xfrm_state_get_afinfo(family); 3819d389d7fSSteffen Klassert if (unlikely(afinfo == NULL)) 3829d389d7fSSteffen Klassert return NULL; 3839d389d7fSSteffen Klassert 3844f518e80SFlorian Westphal switch (proto) { 3854f518e80SFlorian Westphal case IPPROTO_ESP: 3864f518e80SFlorian Westphal type = afinfo->type_offload_esp; 3874f518e80SFlorian Westphal break; 3884f518e80SFlorian Westphal default: 3894f518e80SFlorian Westphal break; 3904f518e80SFlorian Westphal } 3914f518e80SFlorian Westphal 3929d389d7fSSteffen Klassert if ((type && !try_module_get(type->owner))) 3939d389d7fSSteffen Klassert type = NULL; 3949d389d7fSSteffen Klassert 3952f10a61cSSabrina Dubroca rcu_read_unlock(); 3962f10a61cSSabrina Dubroca 397ffdb5211SIlan Tayari if (!type && try_load) { 398ffdb5211SIlan Tayari request_module("xfrm-offload-%d-%d", family, proto); 399545d8ae7SGustavo A. R. Silva try_load = false; 400ffdb5211SIlan Tayari goto retry; 401ffdb5211SIlan Tayari } 402ffdb5211SIlan Tayari 4039d389d7fSSteffen Klassert return type; 4049d389d7fSSteffen Klassert } 4059d389d7fSSteffen Klassert 4069d389d7fSSteffen Klassert static void xfrm_put_type_offload(const struct xfrm_type_offload *type) 4079d389d7fSSteffen Klassert { 4089d389d7fSSteffen Klassert module_put(type->owner); 4099d389d7fSSteffen Klassert } 4109d389d7fSSteffen Klassert 4114c145dceSFlorian Westphal static const struct xfrm_mode xfrm4_mode_map[XFRM_MODE_MAX] = { 4124c145dceSFlorian Westphal [XFRM_MODE_BEET] = { 4134c145dceSFlorian Westphal .encap = XFRM_MODE_BEET, 4144c145dceSFlorian Westphal .flags = XFRM_MODE_FLAG_TUNNEL, 4154c145dceSFlorian Westphal .family = AF_INET, 4164c145dceSFlorian Westphal }, 4174c145dceSFlorian Westphal [XFRM_MODE_TRANSPORT] = { 4184c145dceSFlorian Westphal .encap = XFRM_MODE_TRANSPORT, 4194c145dceSFlorian Westphal .family = AF_INET, 4204c145dceSFlorian Westphal }, 4214c145dceSFlorian Westphal [XFRM_MODE_TUNNEL] = { 4224c145dceSFlorian Westphal .encap = XFRM_MODE_TUNNEL, 4234c145dceSFlorian Westphal .flags = XFRM_MODE_FLAG_TUNNEL, 4244c145dceSFlorian Westphal .family = AF_INET, 4254c145dceSFlorian Westphal }, 4264c145dceSFlorian Westphal }; 4274c145dceSFlorian Westphal 4284c145dceSFlorian Westphal static const struct xfrm_mode xfrm6_mode_map[XFRM_MODE_MAX] = { 4294c145dceSFlorian Westphal [XFRM_MODE_BEET] = { 4304c145dceSFlorian Westphal .encap = XFRM_MODE_BEET, 4314c145dceSFlorian Westphal .flags = XFRM_MODE_FLAG_TUNNEL, 4324c145dceSFlorian Westphal .family = AF_INET6, 4334c145dceSFlorian Westphal }, 4344c145dceSFlorian Westphal [XFRM_MODE_ROUTEOPTIMIZATION] = { 4354c145dceSFlorian Westphal .encap = XFRM_MODE_ROUTEOPTIMIZATION, 4364c145dceSFlorian Westphal .family = AF_INET6, 4374c145dceSFlorian Westphal }, 4384c145dceSFlorian Westphal [XFRM_MODE_TRANSPORT] = { 4394c145dceSFlorian Westphal .encap = XFRM_MODE_TRANSPORT, 4404c145dceSFlorian Westphal .family = AF_INET6, 4414c145dceSFlorian Westphal }, 4424c145dceSFlorian Westphal [XFRM_MODE_TUNNEL] = { 4434c145dceSFlorian Westphal .encap = XFRM_MODE_TUNNEL, 4444c145dceSFlorian Westphal .flags = XFRM_MODE_FLAG_TUNNEL, 4454c145dceSFlorian Westphal .family = AF_INET6, 4464c145dceSFlorian Westphal }, 4474c145dceSFlorian Westphal }; 4484c145dceSFlorian Westphal 4494c145dceSFlorian Westphal static const struct xfrm_mode *xfrm_get_mode(unsigned int encap, int family) 450aa5d62ccSHerbert Xu { 4514c145dceSFlorian Westphal const struct xfrm_mode *mode; 452aa5d62ccSHerbert Xu 453aa5d62ccSHerbert Xu if (unlikely(encap >= XFRM_MODE_MAX)) 454aa5d62ccSHerbert Xu return NULL; 455aa5d62ccSHerbert Xu 4564c145dceSFlorian Westphal switch (family) { 4574c145dceSFlorian Westphal case AF_INET: 4584c145dceSFlorian Westphal mode = &xfrm4_mode_map[encap]; 4594c145dceSFlorian Westphal if (mode->family == family) 460aa5d62ccSHerbert Xu return mode; 4614c145dceSFlorian Westphal break; 4624c145dceSFlorian Westphal case AF_INET6: 4634c145dceSFlorian Westphal mode = &xfrm6_mode_map[encap]; 4644c145dceSFlorian Westphal if (mode->family == family) 4654c145dceSFlorian Westphal return mode; 4664c145dceSFlorian Westphal break; 4674c145dceSFlorian Westphal default: 4684c145dceSFlorian Westphal break; 469aa5d62ccSHerbert Xu } 470aa5d62ccSHerbert Xu 4714c145dceSFlorian Westphal return NULL; 472aa5d62ccSHerbert Xu } 473aa5d62ccSHerbert Xu 4744a135e53SMathias Krause void xfrm_state_free(struct xfrm_state *x) 4754a135e53SMathias Krause { 4764a135e53SMathias Krause kmem_cache_free(xfrm_state_cache, x); 4774a135e53SMathias Krause } 4784a135e53SMathias Krause EXPORT_SYMBOL(xfrm_state_free); 4794a135e53SMathias Krause 480f75a2804SCong Wang static void ___xfrm_state_destroy(struct xfrm_state *x) 4811da177e4SLinus Torvalds { 482671422b2SThomas Gleixner hrtimer_cancel(&x->mtimer); 483a47f0ce0SDavid S. Miller del_timer_sync(&x->rtimer); 484b5884793SIlan Tayari kfree(x->aead); 4851da177e4SLinus Torvalds kfree(x->aalg); 4861da177e4SLinus Torvalds kfree(x->ealg); 4871da177e4SLinus Torvalds kfree(x->calg); 4881da177e4SLinus Torvalds kfree(x->encap); 489060f02a3SNoriaki TAKAMIYA kfree(x->coaddr); 490d8647b79SSteffen Klassert kfree(x->replay_esn); 491d8647b79SSteffen Klassert kfree(x->preplay_esn); 4929d389d7fSSteffen Klassert if (x->type_offload) 4939d389d7fSSteffen Klassert xfrm_put_type_offload(x->type_offload); 4941da177e4SLinus Torvalds if (x->type) { 4951da177e4SLinus Torvalds x->type->destructor(x); 4961da177e4SLinus Torvalds xfrm_put_type(x->type); 4971da177e4SLinus Torvalds } 49886c6739eSSteffen Klassert if (x->xfrag.page) 49986c6739eSSteffen Klassert put_page(x->xfrag.page); 500d77e38e6SSteffen Klassert xfrm_dev_state_free(x); 501df71837dSTrent Jaeger security_xfrm_state_free(x); 5024a135e53SMathias Krause xfrm_state_free(x); 5031da177e4SLinus Torvalds } 5041da177e4SLinus Torvalds 505c7837144SAlexey Dobriyan static void xfrm_state_gc_task(struct work_struct *work) 5061da177e4SLinus Torvalds { 50712a169e7SHerbert Xu struct xfrm_state *x; 508b67bfe0dSSasha Levin struct hlist_node *tmp; 50912a169e7SHerbert Xu struct hlist_head gc_list; 5101da177e4SLinus Torvalds 5111da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_gc_lock); 51235db57bbSFlorian Westphal hlist_move_list(&xfrm_state_gc_list, &gc_list); 5131da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_gc_lock); 5141da177e4SLinus Torvalds 515df7274ebSFlorian Westphal synchronize_rcu(); 516df7274ebSFlorian Westphal 517b67bfe0dSSasha Levin hlist_for_each_entry_safe(x, tmp, &gc_list, gclist) 518f75a2804SCong Wang ___xfrm_state_destroy(x); 5191da177e4SLinus Torvalds } 5201da177e4SLinus Torvalds 5219e0d57fdSYury Polyanskiy static enum hrtimer_restart xfrm_timer_handler(struct hrtimer *me) 5221da177e4SLinus Torvalds { 523671422b2SThomas Gleixner struct xfrm_state *x = container_of(me, struct xfrm_state, mtimer); 524671422b2SThomas Gleixner enum hrtimer_restart ret = HRTIMER_NORESTART; 525386c5680SArnd Bergmann time64_t now = ktime_get_real_seconds(); 526386c5680SArnd Bergmann time64_t next = TIME64_MAX; 5271da177e4SLinus Torvalds int warn = 0; 528161a09e7SJoy Latten int err = 0; 5291da177e4SLinus Torvalds 5301da177e4SLinus Torvalds spin_lock(&x->lock); 5311da177e4SLinus Torvalds if (x->km.state == XFRM_STATE_DEAD) 5321da177e4SLinus Torvalds goto out; 5331da177e4SLinus Torvalds if (x->km.state == XFRM_STATE_EXPIRED) 5341da177e4SLinus Torvalds goto expired; 5351da177e4SLinus Torvalds if (x->lft.hard_add_expires_seconds) { 5361da177e4SLinus Torvalds long tmo = x->lft.hard_add_expires_seconds + 5371da177e4SLinus Torvalds x->curlft.add_time - now; 538e3c0d047SFan Du if (tmo <= 0) { 539e3c0d047SFan Du if (x->xflags & XFRM_SOFT_EXPIRE) { 540e3c0d047SFan Du /* enter hard expire without soft expire first?! 541e3c0d047SFan Du * setting a new date could trigger this. 5421365e547SAlexander Alemayhu * workaround: fix x->curflt.add_time by below: 543e3c0d047SFan Du */ 544e3c0d047SFan Du x->curlft.add_time = now - x->saved_tmo - 1; 545e3c0d047SFan Du tmo = x->lft.hard_add_expires_seconds - x->saved_tmo; 546e3c0d047SFan Du } else 5471da177e4SLinus Torvalds goto expired; 548e3c0d047SFan Du } 5491da177e4SLinus Torvalds if (tmo < next) 5501da177e4SLinus Torvalds next = tmo; 5511da177e4SLinus Torvalds } 5521da177e4SLinus Torvalds if (x->lft.hard_use_expires_seconds) { 5531da177e4SLinus Torvalds long tmo = x->lft.hard_use_expires_seconds + 5541da177e4SLinus Torvalds (x->curlft.use_time ? : now) - now; 5551da177e4SLinus Torvalds if (tmo <= 0) 5561da177e4SLinus Torvalds goto expired; 5571da177e4SLinus Torvalds if (tmo < next) 5581da177e4SLinus Torvalds next = tmo; 5591da177e4SLinus Torvalds } 5601da177e4SLinus Torvalds if (x->km.dying) 5611da177e4SLinus Torvalds goto resched; 5621da177e4SLinus Torvalds if (x->lft.soft_add_expires_seconds) { 5631da177e4SLinus Torvalds long tmo = x->lft.soft_add_expires_seconds + 5641da177e4SLinus Torvalds x->curlft.add_time - now; 565e3c0d047SFan Du if (tmo <= 0) { 5661da177e4SLinus Torvalds warn = 1; 567e3c0d047SFan Du x->xflags &= ~XFRM_SOFT_EXPIRE; 568e3c0d047SFan Du } else if (tmo < next) { 5691da177e4SLinus Torvalds next = tmo; 570e3c0d047SFan Du x->xflags |= XFRM_SOFT_EXPIRE; 571e3c0d047SFan Du x->saved_tmo = tmo; 572e3c0d047SFan Du } 5731da177e4SLinus Torvalds } 5741da177e4SLinus Torvalds if (x->lft.soft_use_expires_seconds) { 5751da177e4SLinus Torvalds long tmo = x->lft.soft_use_expires_seconds + 5761da177e4SLinus Torvalds (x->curlft.use_time ? : now) - now; 5771da177e4SLinus Torvalds if (tmo <= 0) 5781da177e4SLinus Torvalds warn = 1; 5791da177e4SLinus Torvalds else if (tmo < next) 5801da177e4SLinus Torvalds next = tmo; 5811da177e4SLinus Torvalds } 5821da177e4SLinus Torvalds 5834666faabSHerbert Xu x->km.dying = warn; 5841da177e4SLinus Torvalds if (warn) 58553bc6b4dSJamal Hadi Salim km_state_expired(x, 0, 0); 5861da177e4SLinus Torvalds resched: 587386c5680SArnd Bergmann if (next != TIME64_MAX) { 588671422b2SThomas Gleixner hrtimer_forward_now(&x->mtimer, ktime_set(next, 0)); 589671422b2SThomas Gleixner ret = HRTIMER_RESTART; 5909e0d57fdSYury Polyanskiy } 591a47f0ce0SDavid S. Miller 5921da177e4SLinus Torvalds goto out; 5931da177e4SLinus Torvalds 5941da177e4SLinus Torvalds expired: 5955b8ef341SSteffen Klassert if (x->km.state == XFRM_STATE_ACQ && x->id.spi == 0) 5961da177e4SLinus Torvalds x->km.state = XFRM_STATE_EXPIRED; 597161a09e7SJoy Latten 598161a09e7SJoy Latten err = __xfrm_state_delete(x); 5990806ae4cSNicolas Dichtel if (!err) 60053bc6b4dSJamal Hadi Salim km_state_expired(x, 1, 0); 6011da177e4SLinus Torvalds 6022e71029eSTetsuo Handa xfrm_audit_state_delete(x, err ? 0 : 1, true); 603161a09e7SJoy Latten 6041da177e4SLinus Torvalds out: 6051da177e4SLinus Torvalds spin_unlock(&x->lock); 606671422b2SThomas Gleixner return ret; 6071da177e4SLinus Torvalds } 6081da177e4SLinus Torvalds 609e99e88a9SKees Cook static void xfrm_replay_timer_handler(struct timer_list *t); 6100ac84752SDavid S. Miller 611673c09beSAlexey Dobriyan struct xfrm_state *xfrm_state_alloc(struct net *net) 6121da177e4SLinus Torvalds { 6131da177e4SLinus Torvalds struct xfrm_state *x; 6141da177e4SLinus Torvalds 615a4c278d1SHuang Zijiang x = kmem_cache_zalloc(xfrm_state_cache, GFP_ATOMIC); 6161da177e4SLinus Torvalds 6171da177e4SLinus Torvalds if (x) { 618673c09beSAlexey Dobriyan write_pnet(&x->xs_net, net); 61988755e9cSReshetova, Elena refcount_set(&x->refcnt, 1); 6201da177e4SLinus Torvalds atomic_set(&x->tunnel_users, 0); 62112a169e7SHerbert Xu INIT_LIST_HEAD(&x->km.all); 6228f126e37SDavid S. Miller INIT_HLIST_NODE(&x->bydst); 6238f126e37SDavid S. Miller INIT_HLIST_NODE(&x->bysrc); 6248f126e37SDavid S. Miller INIT_HLIST_NODE(&x->byspi); 625671422b2SThomas Gleixner hrtimer_init(&x->mtimer, CLOCK_BOOTTIME, HRTIMER_MODE_ABS_SOFT); 626671422b2SThomas Gleixner x->mtimer.function = xfrm_timer_handler; 627e99e88a9SKees Cook timer_setup(&x->rtimer, xfrm_replay_timer_handler, 0); 628386c5680SArnd Bergmann x->curlft.add_time = ktime_get_real_seconds(); 6291da177e4SLinus Torvalds x->lft.soft_byte_limit = XFRM_INF; 6301da177e4SLinus Torvalds x->lft.soft_packet_limit = XFRM_INF; 6311da177e4SLinus Torvalds x->lft.hard_byte_limit = XFRM_INF; 6321da177e4SLinus Torvalds x->lft.hard_packet_limit = XFRM_INF; 633f8cd5488SJamal Hadi Salim x->replay_maxage = 0; 634f8cd5488SJamal Hadi Salim x->replay_maxdiff = 0; 6351da177e4SLinus Torvalds spin_lock_init(&x->lock); 6361da177e4SLinus Torvalds } 6371da177e4SLinus Torvalds return x; 6381da177e4SLinus Torvalds } 6391da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_alloc); 6401da177e4SLinus Torvalds 641f75a2804SCong Wang void __xfrm_state_destroy(struct xfrm_state *x, bool sync) 6421da177e4SLinus Torvalds { 643547b792cSIlpo Järvinen WARN_ON(x->km.state != XFRM_STATE_DEAD); 6441da177e4SLinus Torvalds 645f75a2804SCong Wang if (sync) { 646f75a2804SCong Wang synchronize_rcu(); 647f75a2804SCong Wang ___xfrm_state_destroy(x); 648f75a2804SCong Wang } else { 6491da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_gc_lock); 65035db57bbSFlorian Westphal hlist_add_head(&x->gclist, &xfrm_state_gc_list); 6511da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_gc_lock); 65235db57bbSFlorian Westphal schedule_work(&xfrm_state_gc_work); 6531da177e4SLinus Torvalds } 654f75a2804SCong Wang } 6551da177e4SLinus Torvalds EXPORT_SYMBOL(__xfrm_state_destroy); 6561da177e4SLinus Torvalds 65753bc6b4dSJamal Hadi Salim int __xfrm_state_delete(struct xfrm_state *x) 6581da177e4SLinus Torvalds { 65998806f75SAlexey Dobriyan struct net *net = xs_net(x); 66026b15dadSJamal Hadi Salim int err = -ESRCH; 66126b15dadSJamal Hadi Salim 6621da177e4SLinus Torvalds if (x->km.state != XFRM_STATE_DEAD) { 6631da177e4SLinus Torvalds x->km.state = XFRM_STATE_DEAD; 664283bc9f3SFan Du spin_lock(&net->xfrm.xfrm_state_lock); 66512a169e7SHerbert Xu list_del(&x->km.all); 666ae3fb6d3SFlorian Westphal hlist_del_rcu(&x->bydst); 667ae3fb6d3SFlorian Westphal hlist_del_rcu(&x->bysrc); 668a47f0ce0SDavid S. Miller if (x->id.spi) 669ae3fb6d3SFlorian Westphal hlist_del_rcu(&x->byspi); 67098806f75SAlexey Dobriyan net->xfrm.state_num--; 671283bc9f3SFan Du spin_unlock(&net->xfrm.xfrm_state_lock); 6721da177e4SLinus Torvalds 673e27cca96SSabrina Dubroca if (x->encap_sk) 674e27cca96SSabrina Dubroca sock_put(rcu_dereference_raw(x->encap_sk)); 675e27cca96SSabrina Dubroca 676d77e38e6SSteffen Klassert xfrm_dev_state_delete(x); 677d77e38e6SSteffen Klassert 6781da177e4SLinus Torvalds /* All xfrm_state objects are created by xfrm_state_alloc. 6791da177e4SLinus Torvalds * The xfrm_state_alloc call gives a reference, and that 6801da177e4SLinus Torvalds * is what we are dropping here. 6811da177e4SLinus Torvalds */ 6825dba4797SPatrick McHardy xfrm_state_put(x); 68326b15dadSJamal Hadi Salim err = 0; 6841da177e4SLinus Torvalds } 6851da177e4SLinus Torvalds 68626b15dadSJamal Hadi Salim return err; 68726b15dadSJamal Hadi Salim } 68853bc6b4dSJamal Hadi Salim EXPORT_SYMBOL(__xfrm_state_delete); 68926b15dadSJamal Hadi Salim 69026b15dadSJamal Hadi Salim int xfrm_state_delete(struct xfrm_state *x) 6911da177e4SLinus Torvalds { 69226b15dadSJamal Hadi Salim int err; 69326b15dadSJamal Hadi Salim 6941da177e4SLinus Torvalds spin_lock_bh(&x->lock); 69526b15dadSJamal Hadi Salim err = __xfrm_state_delete(x); 6961da177e4SLinus Torvalds spin_unlock_bh(&x->lock); 69726b15dadSJamal Hadi Salim 69826b15dadSJamal Hadi Salim return err; 6991da177e4SLinus Torvalds } 7001da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_delete); 7011da177e4SLinus Torvalds 7024aa2e62cSJoy Latten #ifdef CONFIG_SECURITY_NETWORK_XFRM 7034aa2e62cSJoy Latten static inline int 7042e71029eSTetsuo Handa xfrm_state_flush_secctx_check(struct net *net, u8 proto, bool task_valid) 7051da177e4SLinus Torvalds { 7064aa2e62cSJoy Latten int i, err = 0; 7074aa2e62cSJoy Latten 7080e602451SAlexey Dobriyan for (i = 0; i <= net->xfrm.state_hmask; i++) { 7094aa2e62cSJoy Latten struct xfrm_state *x; 7104aa2e62cSJoy Latten 711b67bfe0dSSasha Levin hlist_for_each_entry(x, net->xfrm.state_bydst+i, bydst) { 7124aa2e62cSJoy Latten if (xfrm_id_proto_match(x->id.proto, proto) && 7134aa2e62cSJoy Latten (err = security_xfrm_state_delete(x)) != 0) { 7142e71029eSTetsuo Handa xfrm_audit_state_delete(x, 0, task_valid); 7154aa2e62cSJoy Latten return err; 7164aa2e62cSJoy Latten } 7174aa2e62cSJoy Latten } 7184aa2e62cSJoy Latten } 7194aa2e62cSJoy Latten 7204aa2e62cSJoy Latten return err; 7214aa2e62cSJoy Latten } 722d77e38e6SSteffen Klassert 723d77e38e6SSteffen Klassert static inline int 724d77e38e6SSteffen Klassert xfrm_dev_state_flush_secctx_check(struct net *net, struct net_device *dev, bool task_valid) 725d77e38e6SSteffen Klassert { 726d77e38e6SSteffen Klassert int i, err = 0; 727d77e38e6SSteffen Klassert 728d77e38e6SSteffen Klassert for (i = 0; i <= net->xfrm.state_hmask; i++) { 729d77e38e6SSteffen Klassert struct xfrm_state *x; 730d77e38e6SSteffen Klassert struct xfrm_state_offload *xso; 731d77e38e6SSteffen Klassert 732d77e38e6SSteffen Klassert hlist_for_each_entry(x, net->xfrm.state_bydst+i, bydst) { 733d77e38e6SSteffen Klassert xso = &x->xso; 734d77e38e6SSteffen Klassert 735d77e38e6SSteffen Klassert if (xso->dev == dev && 736d77e38e6SSteffen Klassert (err = security_xfrm_state_delete(x)) != 0) { 737d77e38e6SSteffen Klassert xfrm_audit_state_delete(x, 0, task_valid); 738d77e38e6SSteffen Klassert return err; 739d77e38e6SSteffen Klassert } 740d77e38e6SSteffen Klassert } 741d77e38e6SSteffen Klassert } 742d77e38e6SSteffen Klassert 743d77e38e6SSteffen Klassert return err; 744d77e38e6SSteffen Klassert } 7454aa2e62cSJoy Latten #else 7464aa2e62cSJoy Latten static inline int 7472e71029eSTetsuo Handa xfrm_state_flush_secctx_check(struct net *net, u8 proto, bool task_valid) 7484aa2e62cSJoy Latten { 7494aa2e62cSJoy Latten return 0; 7504aa2e62cSJoy Latten } 751d77e38e6SSteffen Klassert 752d77e38e6SSteffen Klassert static inline int 753d77e38e6SSteffen Klassert xfrm_dev_state_flush_secctx_check(struct net *net, struct net_device *dev, bool task_valid) 754d77e38e6SSteffen Klassert { 755d77e38e6SSteffen Klassert return 0; 756d77e38e6SSteffen Klassert } 7574aa2e62cSJoy Latten #endif 7584aa2e62cSJoy Latten 759f75a2804SCong Wang int xfrm_state_flush(struct net *net, u8 proto, bool task_valid, bool sync) 7604aa2e62cSJoy Latten { 7619e64cc95SJamal Hadi Salim int i, err = 0, cnt = 0; 7621da177e4SLinus Torvalds 763283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 7642e71029eSTetsuo Handa err = xfrm_state_flush_secctx_check(net, proto, task_valid); 7654aa2e62cSJoy Latten if (err) 7664aa2e62cSJoy Latten goto out; 7674aa2e62cSJoy Latten 7689e64cc95SJamal Hadi Salim err = -ESRCH; 7690e602451SAlexey Dobriyan for (i = 0; i <= net->xfrm.state_hmask; i++) { 7708f126e37SDavid S. Miller struct xfrm_state *x; 7711da177e4SLinus Torvalds restart: 772b67bfe0dSSasha Levin hlist_for_each_entry(x, net->xfrm.state_bydst+i, bydst) { 7731da177e4SLinus Torvalds if (!xfrm_state_kern(x) && 7745794708fSMasahide NAKAMURA xfrm_id_proto_match(x->id.proto, proto)) { 7751da177e4SLinus Torvalds xfrm_state_hold(x); 776283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 7771da177e4SLinus Torvalds 778161a09e7SJoy Latten err = xfrm_state_delete(x); 779ab5f5e8bSJoy Latten xfrm_audit_state_delete(x, err ? 0 : 1, 7802e71029eSTetsuo Handa task_valid); 781f75a2804SCong Wang if (sync) 782f75a2804SCong Wang xfrm_state_put_sync(x); 783f75a2804SCong Wang else 7841da177e4SLinus Torvalds xfrm_state_put(x); 7859e64cc95SJamal Hadi Salim if (!err) 7869e64cc95SJamal Hadi Salim cnt++; 7871da177e4SLinus Torvalds 788283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 7891da177e4SLinus Torvalds goto restart; 7901da177e4SLinus Torvalds } 7911da177e4SLinus Torvalds } 7921da177e4SLinus Torvalds } 793dd269db8SArtem Savkov out: 794dd269db8SArtem Savkov spin_unlock_bh(&net->xfrm.xfrm_state_lock); 795e4db5b61SFlorian Westphal if (cnt) 7964aa2e62cSJoy Latten err = 0; 797e4db5b61SFlorian Westphal 7984aa2e62cSJoy Latten return err; 7991da177e4SLinus Torvalds } 8001da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_flush); 8011da177e4SLinus Torvalds 802d77e38e6SSteffen Klassert int xfrm_dev_state_flush(struct net *net, struct net_device *dev, bool task_valid) 803d77e38e6SSteffen Klassert { 804d77e38e6SSteffen Klassert int i, err = 0, cnt = 0; 805d77e38e6SSteffen Klassert 806d77e38e6SSteffen Klassert spin_lock_bh(&net->xfrm.xfrm_state_lock); 807d77e38e6SSteffen Klassert err = xfrm_dev_state_flush_secctx_check(net, dev, task_valid); 808d77e38e6SSteffen Klassert if (err) 809d77e38e6SSteffen Klassert goto out; 810d77e38e6SSteffen Klassert 811d77e38e6SSteffen Klassert err = -ESRCH; 812d77e38e6SSteffen Klassert for (i = 0; i <= net->xfrm.state_hmask; i++) { 813d77e38e6SSteffen Klassert struct xfrm_state *x; 814d77e38e6SSteffen Klassert struct xfrm_state_offload *xso; 815d77e38e6SSteffen Klassert restart: 816d77e38e6SSteffen Klassert hlist_for_each_entry(x, net->xfrm.state_bydst+i, bydst) { 817d77e38e6SSteffen Klassert xso = &x->xso; 818d77e38e6SSteffen Klassert 819d77e38e6SSteffen Klassert if (!xfrm_state_kern(x) && xso->dev == dev) { 820d77e38e6SSteffen Klassert xfrm_state_hold(x); 821d77e38e6SSteffen Klassert spin_unlock_bh(&net->xfrm.xfrm_state_lock); 822d77e38e6SSteffen Klassert 823d77e38e6SSteffen Klassert err = xfrm_state_delete(x); 824d77e38e6SSteffen Klassert xfrm_audit_state_delete(x, err ? 0 : 1, 825d77e38e6SSteffen Klassert task_valid); 826d77e38e6SSteffen Klassert xfrm_state_put(x); 827d77e38e6SSteffen Klassert if (!err) 828d77e38e6SSteffen Klassert cnt++; 829d77e38e6SSteffen Klassert 830d77e38e6SSteffen Klassert spin_lock_bh(&net->xfrm.xfrm_state_lock); 831d77e38e6SSteffen Klassert goto restart; 832d77e38e6SSteffen Klassert } 833d77e38e6SSteffen Klassert } 834d77e38e6SSteffen Klassert } 835d77e38e6SSteffen Klassert if (cnt) 836d77e38e6SSteffen Klassert err = 0; 837d77e38e6SSteffen Klassert 838d77e38e6SSteffen Klassert out: 839d77e38e6SSteffen Klassert spin_unlock_bh(&net->xfrm.xfrm_state_lock); 840d77e38e6SSteffen Klassert return err; 841d77e38e6SSteffen Klassert } 842d77e38e6SSteffen Klassert EXPORT_SYMBOL(xfrm_dev_state_flush); 843d77e38e6SSteffen Klassert 844e071041bSAlexey Dobriyan void xfrm_sad_getinfo(struct net *net, struct xfrmk_sadinfo *si) 84528d8909bSJamal Hadi Salim { 846283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 847e071041bSAlexey Dobriyan si->sadcnt = net->xfrm.state_num; 848ca92e173SBenjamin Poirier si->sadhcnt = net->xfrm.state_hmask + 1; 84928d8909bSJamal Hadi Salim si->sadhmcnt = xfrm_state_hashmax; 850283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 85128d8909bSJamal Hadi Salim } 85228d8909bSJamal Hadi Salim EXPORT_SYMBOL(xfrm_sad_getinfo); 85328d8909bSJamal Hadi Salim 854711059b9SFlorian Westphal static void 855bac95935SFlorian Westphal __xfrm4_init_tempsel(struct xfrm_selector *sel, const struct flowi *fl) 856bac95935SFlorian Westphal { 857bac95935SFlorian Westphal const struct flowi4 *fl4 = &fl->u.ip4; 858bac95935SFlorian Westphal 859bac95935SFlorian Westphal sel->daddr.a4 = fl4->daddr; 860bac95935SFlorian Westphal sel->saddr.a4 = fl4->saddr; 861bac95935SFlorian Westphal sel->dport = xfrm_flowi_dport(fl, &fl4->uli); 862bac95935SFlorian Westphal sel->dport_mask = htons(0xffff); 863bac95935SFlorian Westphal sel->sport = xfrm_flowi_sport(fl, &fl4->uli); 864bac95935SFlorian Westphal sel->sport_mask = htons(0xffff); 865bac95935SFlorian Westphal sel->family = AF_INET; 866bac95935SFlorian Westphal sel->prefixlen_d = 32; 867bac95935SFlorian Westphal sel->prefixlen_s = 32; 868bac95935SFlorian Westphal sel->proto = fl4->flowi4_proto; 869bac95935SFlorian Westphal sel->ifindex = fl4->flowi4_oif; 870bac95935SFlorian Westphal } 871bac95935SFlorian Westphal 872bac95935SFlorian Westphal static void 873bac95935SFlorian Westphal __xfrm6_init_tempsel(struct xfrm_selector *sel, const struct flowi *fl) 874bac95935SFlorian Westphal { 875bac95935SFlorian Westphal const struct flowi6 *fl6 = &fl->u.ip6; 876bac95935SFlorian Westphal 877bac95935SFlorian Westphal /* Initialize temporary selector matching only to current session. */ 878bac95935SFlorian Westphal *(struct in6_addr *)&sel->daddr = fl6->daddr; 879bac95935SFlorian Westphal *(struct in6_addr *)&sel->saddr = fl6->saddr; 880bac95935SFlorian Westphal sel->dport = xfrm_flowi_dport(fl, &fl6->uli); 881bac95935SFlorian Westphal sel->dport_mask = htons(0xffff); 882bac95935SFlorian Westphal sel->sport = xfrm_flowi_sport(fl, &fl6->uli); 883bac95935SFlorian Westphal sel->sport_mask = htons(0xffff); 884bac95935SFlorian Westphal sel->family = AF_INET6; 885bac95935SFlorian Westphal sel->prefixlen_d = 128; 886bac95935SFlorian Westphal sel->prefixlen_s = 128; 887bac95935SFlorian Westphal sel->proto = fl6->flowi6_proto; 888bac95935SFlorian Westphal sel->ifindex = fl6->flowi6_oif; 889bac95935SFlorian Westphal } 890bac95935SFlorian Westphal 891bac95935SFlorian Westphal static void 8921a898592SDavid S. Miller xfrm_init_tempstate(struct xfrm_state *x, const struct flowi *fl, 89304686013SDavid S. Miller const struct xfrm_tmpl *tmpl, 89433765d06SDavid S. Miller const xfrm_address_t *daddr, const xfrm_address_t *saddr, 8951da177e4SLinus Torvalds unsigned short family) 8961da177e4SLinus Torvalds { 897bac95935SFlorian Westphal switch (family) { 898bac95935SFlorian Westphal case AF_INET: 899bac95935SFlorian Westphal __xfrm4_init_tempsel(&x->sel, fl); 900bac95935SFlorian Westphal break; 901bac95935SFlorian Westphal case AF_INET6: 902bac95935SFlorian Westphal __xfrm6_init_tempsel(&x->sel, fl); 903bac95935SFlorian Westphal break; 9048444cf71SThomas Egerer } 905bac95935SFlorian Westphal 9065c1b9ab3SFlorian Westphal x->id = tmpl->id; 907bac95935SFlorian Westphal 9085c1b9ab3SFlorian Westphal switch (tmpl->encap_family) { 9095c1b9ab3SFlorian Westphal case AF_INET: 9105c1b9ab3SFlorian Westphal if (x->id.daddr.a4 == 0) 9115c1b9ab3SFlorian Westphal x->id.daddr.a4 = daddr->a4; 9125c1b9ab3SFlorian Westphal x->props.saddr = tmpl->saddr; 9135c1b9ab3SFlorian Westphal if (x->props.saddr.a4 == 0) 9145c1b9ab3SFlorian Westphal x->props.saddr.a4 = saddr->a4; 9155c1b9ab3SFlorian Westphal break; 9165c1b9ab3SFlorian Westphal case AF_INET6: 9175c1b9ab3SFlorian Westphal if (ipv6_addr_any((struct in6_addr *)&x->id.daddr)) 9185c1b9ab3SFlorian Westphal memcpy(&x->id.daddr, daddr, sizeof(x->sel.daddr)); 9195c1b9ab3SFlorian Westphal memcpy(&x->props.saddr, &tmpl->saddr, sizeof(x->props.saddr)); 9205c1b9ab3SFlorian Westphal if (ipv6_addr_any((struct in6_addr *)&x->props.saddr)) 9215c1b9ab3SFlorian Westphal memcpy(&x->props.saddr, saddr, sizeof(x->props.saddr)); 9225c1b9ab3SFlorian Westphal break; 9235c1b9ab3SFlorian Westphal } 924bac95935SFlorian Westphal 9255c1b9ab3SFlorian Westphal x->props.mode = tmpl->mode; 9265c1b9ab3SFlorian Westphal x->props.reqid = tmpl->reqid; 9275c1b9ab3SFlorian Westphal x->props.family = tmpl->encap_family; 9281da177e4SLinus Torvalds } 9291da177e4SLinus Torvalds 9309aa60088SDavid S. Miller static struct xfrm_state *__xfrm_state_lookup(struct net *net, u32 mark, 9319aa60088SDavid S. Miller const xfrm_address_t *daddr, 9329aa60088SDavid S. Miller __be32 spi, u8 proto, 9339aa60088SDavid S. Miller unsigned short family) 934edcd5821SDavid S. Miller { 935221df1edSAlexey Dobriyan unsigned int h = xfrm_spi_hash(net, daddr, spi, proto, family); 936edcd5821SDavid S. Miller struct xfrm_state *x; 937edcd5821SDavid S. Miller 938ae3fb6d3SFlorian Westphal hlist_for_each_entry_rcu(x, net->xfrm.state_byspi + h, byspi) { 939edcd5821SDavid S. Miller if (x->props.family != family || 940edcd5821SDavid S. Miller x->id.spi != spi || 9411802571bSWei Yongjun x->id.proto != proto || 94270e94e66SYOSHIFUJI Hideaki / 吉藤英明 !xfrm_addr_equal(&x->id.daddr, daddr, family)) 943edcd5821SDavid S. Miller continue; 944edcd5821SDavid S. Miller 9453d6acfa7SJamal Hadi Salim if ((mark & x->mark.m) != x->mark.v) 9463d6acfa7SJamal Hadi Salim continue; 94702efdff7SFlorian Westphal if (!xfrm_state_hold_rcu(x)) 94802efdff7SFlorian Westphal continue; 949edcd5821SDavid S. Miller return x; 950edcd5821SDavid S. Miller } 951edcd5821SDavid S. Miller 952edcd5821SDavid S. Miller return NULL; 953edcd5821SDavid S. Miller } 954edcd5821SDavid S. Miller 9559aa60088SDavid S. Miller static struct xfrm_state *__xfrm_state_lookup_byaddr(struct net *net, u32 mark, 9569aa60088SDavid S. Miller const xfrm_address_t *daddr, 9579aa60088SDavid S. Miller const xfrm_address_t *saddr, 9589aa60088SDavid S. Miller u8 proto, unsigned short family) 959edcd5821SDavid S. Miller { 960221df1edSAlexey Dobriyan unsigned int h = xfrm_src_hash(net, daddr, saddr, family); 961edcd5821SDavid S. Miller struct xfrm_state *x; 962edcd5821SDavid S. Miller 963ae3fb6d3SFlorian Westphal hlist_for_each_entry_rcu(x, net->xfrm.state_bysrc + h, bysrc) { 964edcd5821SDavid S. Miller if (x->props.family != family || 9651802571bSWei Yongjun x->id.proto != proto || 96670e94e66SYOSHIFUJI Hideaki / 吉藤英明 !xfrm_addr_equal(&x->id.daddr, daddr, family) || 96770e94e66SYOSHIFUJI Hideaki / 吉藤英明 !xfrm_addr_equal(&x->props.saddr, saddr, family)) 968edcd5821SDavid S. Miller continue; 969edcd5821SDavid S. Miller 9703d6acfa7SJamal Hadi Salim if ((mark & x->mark.m) != x->mark.v) 9713d6acfa7SJamal Hadi Salim continue; 97202efdff7SFlorian Westphal if (!xfrm_state_hold_rcu(x)) 97302efdff7SFlorian Westphal continue; 974edcd5821SDavid S. Miller return x; 975edcd5821SDavid S. Miller } 976edcd5821SDavid S. Miller 977edcd5821SDavid S. Miller return NULL; 978edcd5821SDavid S. Miller } 979edcd5821SDavid S. Miller 980edcd5821SDavid S. Miller static inline struct xfrm_state * 981edcd5821SDavid S. Miller __xfrm_state_locate(struct xfrm_state *x, int use_spi, int family) 982edcd5821SDavid S. Miller { 983221df1edSAlexey Dobriyan struct net *net = xs_net(x); 984bd55775cSJamal Hadi Salim u32 mark = x->mark.v & x->mark.m; 985221df1edSAlexey Dobriyan 986edcd5821SDavid S. Miller if (use_spi) 987bd55775cSJamal Hadi Salim return __xfrm_state_lookup(net, mark, &x->id.daddr, 988bd55775cSJamal Hadi Salim x->id.spi, x->id.proto, family); 989edcd5821SDavid S. Miller else 990bd55775cSJamal Hadi Salim return __xfrm_state_lookup_byaddr(net, mark, 991bd55775cSJamal Hadi Salim &x->id.daddr, 992edcd5821SDavid S. Miller &x->props.saddr, 993edcd5821SDavid S. Miller x->id.proto, family); 994edcd5821SDavid S. Miller } 995edcd5821SDavid S. Miller 99698806f75SAlexey Dobriyan static void xfrm_hash_grow_check(struct net *net, int have_hash_collision) 9972fab22f2SPatrick McHardy { 9982fab22f2SPatrick McHardy if (have_hash_collision && 99998806f75SAlexey Dobriyan (net->xfrm.state_hmask + 1) < xfrm_state_hashmax && 100098806f75SAlexey Dobriyan net->xfrm.state_num > net->xfrm.state_hmask) 100198806f75SAlexey Dobriyan schedule_work(&net->xfrm.state_hash_work); 10022fab22f2SPatrick McHardy } 10032fab22f2SPatrick McHardy 100408ec9af1SDavid S. Miller static void xfrm_state_look_at(struct xfrm_policy *pol, struct xfrm_state *x, 10054a08ab0fSDavid S. Miller const struct flowi *fl, unsigned short family, 100608ec9af1SDavid S. Miller struct xfrm_state **best, int *acq_in_progress, 100708ec9af1SDavid S. Miller int *error) 100808ec9af1SDavid S. Miller { 100908ec9af1SDavid S. Miller /* Resolution logic: 101008ec9af1SDavid S. Miller * 1. There is a valid state with matching selector. Done. 101108ec9af1SDavid S. Miller * 2. Valid state with inappropriate selector. Skip. 101208ec9af1SDavid S. Miller * 101308ec9af1SDavid S. Miller * Entering area of "sysdeps". 101408ec9af1SDavid S. Miller * 101508ec9af1SDavid S. Miller * 3. If state is not valid, selector is temporary, it selects 101608ec9af1SDavid S. Miller * only session which triggered previous resolution. Key 101708ec9af1SDavid S. Miller * manager will do something to install a state with proper 101808ec9af1SDavid S. Miller * selector. 101908ec9af1SDavid S. Miller */ 102008ec9af1SDavid S. Miller if (x->km.state == XFRM_STATE_VALID) { 102108ec9af1SDavid S. Miller if ((x->sel.family && 102208ec9af1SDavid S. Miller !xfrm_selector_match(&x->sel, fl, x->sel.family)) || 102308ec9af1SDavid S. Miller !security_xfrm_state_pol_flow_match(x, pol, fl)) 102408ec9af1SDavid S. Miller return; 102508ec9af1SDavid S. Miller 102608ec9af1SDavid S. Miller if (!*best || 102708ec9af1SDavid S. Miller (*best)->km.dying > x->km.dying || 102808ec9af1SDavid S. Miller ((*best)->km.dying == x->km.dying && 102908ec9af1SDavid S. Miller (*best)->curlft.add_time < x->curlft.add_time)) 103008ec9af1SDavid S. Miller *best = x; 103108ec9af1SDavid S. Miller } else if (x->km.state == XFRM_STATE_ACQ) { 103208ec9af1SDavid S. Miller *acq_in_progress = 1; 103308ec9af1SDavid S. Miller } else if (x->km.state == XFRM_STATE_ERROR || 103408ec9af1SDavid S. Miller x->km.state == XFRM_STATE_EXPIRED) { 103508ec9af1SDavid S. Miller if (xfrm_selector_match(&x->sel, fl, x->sel.family) && 103608ec9af1SDavid S. Miller security_xfrm_state_pol_flow_match(x, pol, fl)) 103708ec9af1SDavid S. Miller *error = -ESRCH; 103808ec9af1SDavid S. Miller } 103908ec9af1SDavid S. Miller } 104008ec9af1SDavid S. Miller 10411da177e4SLinus Torvalds struct xfrm_state * 104233765d06SDavid S. Miller xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr, 1043b520e9f6SDavid S. Miller const struct flowi *fl, struct xfrm_tmpl *tmpl, 10441da177e4SLinus Torvalds struct xfrm_policy *pol, int *err, 1045bc56b334SBenedict Wong unsigned short family, u32 if_id) 10461da177e4SLinus Torvalds { 104708ec9af1SDavid S. Miller static xfrm_address_t saddr_wildcard = { }; 10485447c5e4SAlexey Dobriyan struct net *net = xp_net(pol); 10496a783c90SNicolas Dichtel unsigned int h, h_wildcard; 105037b08e34SDavid S. Miller struct xfrm_state *x, *x0, *to_put; 10511da177e4SLinus Torvalds int acquire_in_progress = 0; 10521da177e4SLinus Torvalds int error = 0; 10531da177e4SLinus Torvalds struct xfrm_state *best = NULL; 1054bd55775cSJamal Hadi Salim u32 mark = pol->mark.v & pol->mark.m; 10558444cf71SThomas Egerer unsigned short encap_family = tmpl->encap_family; 1056b65e3d7bSFlorian Westphal unsigned int sequence; 10570f24558eSHoria Geanta struct km_event c; 10581da177e4SLinus Torvalds 105937b08e34SDavid S. Miller to_put = NULL; 106037b08e34SDavid S. Miller 1061b65e3d7bSFlorian Westphal sequence = read_seqcount_begin(&xfrm_state_hash_generation); 1062b65e3d7bSFlorian Westphal 1063d737a580SFlorian Westphal rcu_read_lock(); 10648444cf71SThomas Egerer h = xfrm_dst_hash(net, daddr, saddr, tmpl->reqid, encap_family); 1065ae3fb6d3SFlorian Westphal hlist_for_each_entry_rcu(x, net->xfrm.state_bydst + h, bydst) { 10668444cf71SThomas Egerer if (x->props.family == encap_family && 10671da177e4SLinus Torvalds x->props.reqid == tmpl->reqid && 10683d6acfa7SJamal Hadi Salim (mark & x->mark.m) == x->mark.v && 10697e652640SSteffen Klassert x->if_id == if_id && 1070fbd9a5b4SMasahide NAKAMURA !(x->props.flags & XFRM_STATE_WILDRECV) && 10718444cf71SThomas Egerer xfrm_state_addr_check(x, daddr, saddr, encap_family) && 10721da177e4SLinus Torvalds tmpl->mode == x->props.mode && 10731da177e4SLinus Torvalds tmpl->id.proto == x->id.proto && 107408ec9af1SDavid S. Miller (tmpl->id.spi == x->id.spi || !tmpl->id.spi)) 10751f673c5fSDavid S. Miller xfrm_state_look_at(pol, x, fl, encap_family, 107608ec9af1SDavid S. Miller &best, &acquire_in_progress, &error); 10771da177e4SLinus Torvalds } 10786f115638SFan Du if (best || acquire_in_progress) 107908ec9af1SDavid S. Miller goto found; 108008ec9af1SDavid S. Miller 10818444cf71SThomas Egerer h_wildcard = xfrm_dst_hash(net, daddr, &saddr_wildcard, tmpl->reqid, encap_family); 1082ae3fb6d3SFlorian Westphal hlist_for_each_entry_rcu(x, net->xfrm.state_bydst + h_wildcard, bydst) { 10838444cf71SThomas Egerer if (x->props.family == encap_family && 108408ec9af1SDavid S. Miller x->props.reqid == tmpl->reqid && 10853d6acfa7SJamal Hadi Salim (mark & x->mark.m) == x->mark.v && 10867e652640SSteffen Klassert x->if_id == if_id && 108708ec9af1SDavid S. Miller !(x->props.flags & XFRM_STATE_WILDRECV) && 1088f59bbdfaSFan Du xfrm_addr_equal(&x->id.daddr, daddr, encap_family) && 108908ec9af1SDavid S. Miller tmpl->mode == x->props.mode && 109008ec9af1SDavid S. Miller tmpl->id.proto == x->id.proto && 109108ec9af1SDavid S. Miller (tmpl->id.spi == x->id.spi || !tmpl->id.spi)) 10921f673c5fSDavid S. Miller xfrm_state_look_at(pol, x, fl, encap_family, 109308ec9af1SDavid S. Miller &best, &acquire_in_progress, &error); 10941da177e4SLinus Torvalds } 10951da177e4SLinus Torvalds 109608ec9af1SDavid S. Miller found: 10971da177e4SLinus Torvalds x = best; 10981da177e4SLinus Torvalds if (!x && !error && !acquire_in_progress) { 10995c5d281aSPatrick McHardy if (tmpl->id.spi && 1100bd55775cSJamal Hadi Salim (x0 = __xfrm_state_lookup(net, mark, daddr, tmpl->id.spi, 11018444cf71SThomas Egerer tmpl->id.proto, encap_family)) != NULL) { 110237b08e34SDavid S. Miller to_put = x0; 11031da177e4SLinus Torvalds error = -EEXIST; 11041da177e4SLinus Torvalds goto out; 11051da177e4SLinus Torvalds } 11060f24558eSHoria Geanta 11070f24558eSHoria Geanta c.net = net; 11080f24558eSHoria Geanta /* If the KMs have no listeners (yet...), avoid allocating an SA 11090f24558eSHoria Geanta * for each and every packet - garbage collection might not 11100f24558eSHoria Geanta * handle the flood. 11110f24558eSHoria Geanta */ 11120f24558eSHoria Geanta if (!km_is_alive(&c)) { 11130f24558eSHoria Geanta error = -ESRCH; 11140f24558eSHoria Geanta goto out; 11150f24558eSHoria Geanta } 11160f24558eSHoria Geanta 11175447c5e4SAlexey Dobriyan x = xfrm_state_alloc(net); 11181da177e4SLinus Torvalds if (x == NULL) { 11191da177e4SLinus Torvalds error = -ENOMEM; 11201da177e4SLinus Torvalds goto out; 11211da177e4SLinus Torvalds } 11228444cf71SThomas Egerer /* Initialize temporary state matching only 11231da177e4SLinus Torvalds * to current session. */ 11248444cf71SThomas Egerer xfrm_init_tempstate(x, fl, tmpl, daddr, saddr, family); 1125bd55775cSJamal Hadi Salim memcpy(&x->mark, &pol->mark, sizeof(x->mark)); 11267e652640SSteffen Klassert x->if_id = if_id; 11271da177e4SLinus Torvalds 11281d28f42cSDavid S. Miller error = security_xfrm_state_alloc_acquire(x, pol->security, fl->flowi_secid); 1129e0d1caa7SVenkat Yekkirala if (error) { 1130e0d1caa7SVenkat Yekkirala x->km.state = XFRM_STATE_DEAD; 113137b08e34SDavid S. Miller to_put = x; 1132e0d1caa7SVenkat Yekkirala x = NULL; 1133e0d1caa7SVenkat Yekkirala goto out; 1134e0d1caa7SVenkat Yekkirala } 1135e0d1caa7SVenkat Yekkirala 11361da177e4SLinus Torvalds if (km_query(x, tmpl, pol) == 0) { 1137d737a580SFlorian Westphal spin_lock_bh(&net->xfrm.xfrm_state_lock); 11381da177e4SLinus Torvalds x->km.state = XFRM_STATE_ACQ; 11395447c5e4SAlexey Dobriyan list_add(&x->km.all, &net->xfrm.state_all); 1140ae3fb6d3SFlorian Westphal hlist_add_head_rcu(&x->bydst, net->xfrm.state_bydst + h); 11418444cf71SThomas Egerer h = xfrm_src_hash(net, daddr, saddr, encap_family); 1142ae3fb6d3SFlorian Westphal hlist_add_head_rcu(&x->bysrc, net->xfrm.state_bysrc + h); 11431da177e4SLinus Torvalds if (x->id.spi) { 11448444cf71SThomas Egerer h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, encap_family); 1145ae3fb6d3SFlorian Westphal hlist_add_head_rcu(&x->byspi, net->xfrm.state_byspi + h); 11461da177e4SLinus Torvalds } 1147b27aeadbSAlexey Dobriyan x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires; 1148671422b2SThomas Gleixner hrtimer_start(&x->mtimer, 1149671422b2SThomas Gleixner ktime_set(net->xfrm.sysctl_acq_expires, 0), 1150671422b2SThomas Gleixner HRTIMER_MODE_REL_SOFT); 11515447c5e4SAlexey Dobriyan net->xfrm.state_num++; 11525447c5e4SAlexey Dobriyan xfrm_hash_grow_check(net, x->bydst.next != NULL); 1153d737a580SFlorian Westphal spin_unlock_bh(&net->xfrm.xfrm_state_lock); 11541da177e4SLinus Torvalds } else { 11551da177e4SLinus Torvalds x->km.state = XFRM_STATE_DEAD; 115637b08e34SDavid S. Miller to_put = x; 11571da177e4SLinus Torvalds x = NULL; 11581da177e4SLinus Torvalds error = -ESRCH; 11591da177e4SLinus Torvalds } 11601da177e4SLinus Torvalds } 11611da177e4SLinus Torvalds out: 116202efdff7SFlorian Westphal if (x) { 116302efdff7SFlorian Westphal if (!xfrm_state_hold_rcu(x)) { 116402efdff7SFlorian Westphal *err = -EAGAIN; 116502efdff7SFlorian Westphal x = NULL; 116602efdff7SFlorian Westphal } 116702efdff7SFlorian Westphal } else { 11681da177e4SLinus Torvalds *err = acquire_in_progress ? -EAGAIN : error; 116902efdff7SFlorian Westphal } 1170d737a580SFlorian Westphal rcu_read_unlock(); 117137b08e34SDavid S. Miller if (to_put) 117237b08e34SDavid S. Miller xfrm_state_put(to_put); 1173b65e3d7bSFlorian Westphal 1174b65e3d7bSFlorian Westphal if (read_seqcount_retry(&xfrm_state_hash_generation, sequence)) { 1175b65e3d7bSFlorian Westphal *err = -EAGAIN; 1176b65e3d7bSFlorian Westphal if (x) { 1177b65e3d7bSFlorian Westphal xfrm_state_put(x); 1178b65e3d7bSFlorian Westphal x = NULL; 1179b65e3d7bSFlorian Westphal } 1180b65e3d7bSFlorian Westphal } 1181b65e3d7bSFlorian Westphal 11821da177e4SLinus Torvalds return x; 11831da177e4SLinus Torvalds } 11841da177e4SLinus Torvalds 1185628529b6SJamal Hadi Salim struct xfrm_state * 11867e652640SSteffen Klassert xfrm_stateonly_find(struct net *net, u32 mark, u32 if_id, 11875447c5e4SAlexey Dobriyan xfrm_address_t *daddr, xfrm_address_t *saddr, 1188628529b6SJamal Hadi Salim unsigned short family, u8 mode, u8 proto, u32 reqid) 1189628529b6SJamal Hadi Salim { 11904bda4f25SPavel Emelyanov unsigned int h; 1191628529b6SJamal Hadi Salim struct xfrm_state *rx = NULL, *x = NULL; 1192628529b6SJamal Hadi Salim 11934ae770bfSFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 11945447c5e4SAlexey Dobriyan h = xfrm_dst_hash(net, daddr, saddr, reqid, family); 1195b67bfe0dSSasha Levin hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) { 1196628529b6SJamal Hadi Salim if (x->props.family == family && 1197628529b6SJamal Hadi Salim x->props.reqid == reqid && 11983d6acfa7SJamal Hadi Salim (mark & x->mark.m) == x->mark.v && 11997e652640SSteffen Klassert x->if_id == if_id && 1200628529b6SJamal Hadi Salim !(x->props.flags & XFRM_STATE_WILDRECV) && 1201628529b6SJamal Hadi Salim xfrm_state_addr_check(x, daddr, saddr, family) && 1202628529b6SJamal Hadi Salim mode == x->props.mode && 1203628529b6SJamal Hadi Salim proto == x->id.proto && 1204628529b6SJamal Hadi Salim x->km.state == XFRM_STATE_VALID) { 1205628529b6SJamal Hadi Salim rx = x; 1206628529b6SJamal Hadi Salim break; 1207628529b6SJamal Hadi Salim } 1208628529b6SJamal Hadi Salim } 1209628529b6SJamal Hadi Salim 1210628529b6SJamal Hadi Salim if (rx) 1211628529b6SJamal Hadi Salim xfrm_state_hold(rx); 12124ae770bfSFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 1213628529b6SJamal Hadi Salim 1214628529b6SJamal Hadi Salim 1215628529b6SJamal Hadi Salim return rx; 1216628529b6SJamal Hadi Salim } 1217628529b6SJamal Hadi Salim EXPORT_SYMBOL(xfrm_stateonly_find); 1218628529b6SJamal Hadi Salim 1219c454997eSFan Du struct xfrm_state *xfrm_state_lookup_byspi(struct net *net, __be32 spi, 1220c454997eSFan Du unsigned short family) 1221c454997eSFan Du { 1222c454997eSFan Du struct xfrm_state *x; 1223c454997eSFan Du struct xfrm_state_walk *w; 1224c454997eSFan Du 1225c454997eSFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 1226c454997eSFan Du list_for_each_entry(w, &net->xfrm.state_all, all) { 1227c454997eSFan Du x = container_of(w, struct xfrm_state, km); 1228c454997eSFan Du if (x->props.family != family || 1229c454997eSFan Du x->id.spi != spi) 1230c454997eSFan Du continue; 1231c454997eSFan Du 1232c454997eSFan Du xfrm_state_hold(x); 1233bdddbf69SLi RongQing spin_unlock_bh(&net->xfrm.xfrm_state_lock); 1234c454997eSFan Du return x; 1235c454997eSFan Du } 1236c454997eSFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 1237c454997eSFan Du return NULL; 1238c454997eSFan Du } 1239c454997eSFan Du EXPORT_SYMBOL(xfrm_state_lookup_byspi); 1240c454997eSFan Du 12411da177e4SLinus Torvalds static void __xfrm_state_insert(struct xfrm_state *x) 12421da177e4SLinus Torvalds { 124398806f75SAlexey Dobriyan struct net *net = xs_net(x); 1244a624c108SDavid S. Miller unsigned int h; 12451da177e4SLinus Torvalds 124698806f75SAlexey Dobriyan list_add(&x->km.all, &net->xfrm.state_all); 12474c563f76STimo Teras 124898806f75SAlexey Dobriyan h = xfrm_dst_hash(net, &x->id.daddr, &x->props.saddr, 1249c1969f29SDavid S. Miller x->props.reqid, x->props.family); 1250ae3fb6d3SFlorian Westphal hlist_add_head_rcu(&x->bydst, net->xfrm.state_bydst + h); 12511da177e4SLinus Torvalds 125298806f75SAlexey Dobriyan h = xfrm_src_hash(net, &x->id.daddr, &x->props.saddr, x->props.family); 1253ae3fb6d3SFlorian Westphal hlist_add_head_rcu(&x->bysrc, net->xfrm.state_bysrc + h); 12546c44e6b7SMasahide NAKAMURA 12557b4dc360SMasahide NAKAMURA if (x->id.spi) { 125698806f75SAlexey Dobriyan h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, 12576c44e6b7SMasahide NAKAMURA x->props.family); 12581da177e4SLinus Torvalds 1259ae3fb6d3SFlorian Westphal hlist_add_head_rcu(&x->byspi, net->xfrm.state_byspi + h); 12606c44e6b7SMasahide NAKAMURA } 12611da177e4SLinus Torvalds 1262671422b2SThomas Gleixner hrtimer_start(&x->mtimer, ktime_set(1, 0), HRTIMER_MODE_REL_SOFT); 1263a47f0ce0SDavid S. Miller if (x->replay_maxage) 1264a47f0ce0SDavid S. Miller mod_timer(&x->rtimer, jiffies + x->replay_maxage); 1265f8cd5488SJamal Hadi Salim 126698806f75SAlexey Dobriyan net->xfrm.state_num++; 1267f034b5d4SDavid S. Miller 126898806f75SAlexey Dobriyan xfrm_hash_grow_check(net, x->bydst.next != NULL); 12691da177e4SLinus Torvalds } 12701da177e4SLinus Torvalds 1271283bc9f3SFan Du /* net->xfrm.xfrm_state_lock is held */ 1272c7f5ea3aSDavid S. Miller static void __xfrm_state_bump_genids(struct xfrm_state *xnew) 1273c7f5ea3aSDavid S. Miller { 127498806f75SAlexey Dobriyan struct net *net = xs_net(xnew); 1275c7f5ea3aSDavid S. Miller unsigned short family = xnew->props.family; 1276c7f5ea3aSDavid S. Miller u32 reqid = xnew->props.reqid; 1277c7f5ea3aSDavid S. Miller struct xfrm_state *x; 1278c7f5ea3aSDavid S. Miller unsigned int h; 12793d6acfa7SJamal Hadi Salim u32 mark = xnew->mark.v & xnew->mark.m; 12807e652640SSteffen Klassert u32 if_id = xnew->if_id; 1281c7f5ea3aSDavid S. Miller 128298806f75SAlexey Dobriyan h = xfrm_dst_hash(net, &xnew->id.daddr, &xnew->props.saddr, reqid, family); 1283b67bfe0dSSasha Levin hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) { 1284c7f5ea3aSDavid S. Miller if (x->props.family == family && 1285c7f5ea3aSDavid S. Miller x->props.reqid == reqid && 12867e652640SSteffen Klassert x->if_id == if_id && 12873d6acfa7SJamal Hadi Salim (mark & x->mark.m) == x->mark.v && 128870e94e66SYOSHIFUJI Hideaki / 吉藤英明 xfrm_addr_equal(&x->id.daddr, &xnew->id.daddr, family) && 128970e94e66SYOSHIFUJI Hideaki / 吉藤英明 xfrm_addr_equal(&x->props.saddr, &xnew->props.saddr, family)) 129034996cb9SHerbert Xu x->genid++; 1291c7f5ea3aSDavid S. Miller } 1292c7f5ea3aSDavid S. Miller } 1293c7f5ea3aSDavid S. Miller 12941da177e4SLinus Torvalds void xfrm_state_insert(struct xfrm_state *x) 12951da177e4SLinus Torvalds { 1296283bc9f3SFan Du struct net *net = xs_net(x); 1297283bc9f3SFan Du 1298283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 1299c7f5ea3aSDavid S. Miller __xfrm_state_bump_genids(x); 13001da177e4SLinus Torvalds __xfrm_state_insert(x); 1301283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 13021da177e4SLinus Torvalds } 13031da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_insert); 13041da177e4SLinus Torvalds 1305283bc9f3SFan Du /* net->xfrm.xfrm_state_lock is held */ 1306e473fcb4SMathias Krause static struct xfrm_state *__find_acq_core(struct net *net, 1307e473fcb4SMathias Krause const struct xfrm_mark *m, 1308a70486f0SDavid S. Miller unsigned short family, u8 mode, 13097e652640SSteffen Klassert u32 reqid, u32 if_id, u8 proto, 1310a70486f0SDavid S. Miller const xfrm_address_t *daddr, 1311e473fcb4SMathias Krause const xfrm_address_t *saddr, 1312e473fcb4SMathias Krause int create) 13132770834cSDavid S. Miller { 13145447c5e4SAlexey Dobriyan unsigned int h = xfrm_dst_hash(net, daddr, saddr, reqid, family); 13152770834cSDavid S. Miller struct xfrm_state *x; 13163d6acfa7SJamal Hadi Salim u32 mark = m->v & m->m; 13172770834cSDavid S. Miller 1318b67bfe0dSSasha Levin hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) { 13192770834cSDavid S. Miller if (x->props.reqid != reqid || 13202770834cSDavid S. Miller x->props.mode != mode || 13212770834cSDavid S. Miller x->props.family != family || 13222770834cSDavid S. Miller x->km.state != XFRM_STATE_ACQ || 132375e252d9SJoy Latten x->id.spi != 0 || 13241802571bSWei Yongjun x->id.proto != proto || 13253d6acfa7SJamal Hadi Salim (mark & x->mark.m) != x->mark.v || 132670e94e66SYOSHIFUJI Hideaki / 吉藤英明 !xfrm_addr_equal(&x->id.daddr, daddr, family) || 132770e94e66SYOSHIFUJI Hideaki / 吉藤英明 !xfrm_addr_equal(&x->props.saddr, saddr, family)) 13282770834cSDavid S. Miller continue; 13292770834cSDavid S. Miller 13302770834cSDavid S. Miller xfrm_state_hold(x); 13312770834cSDavid S. Miller return x; 13322770834cSDavid S. Miller } 13332770834cSDavid S. Miller 13342770834cSDavid S. Miller if (!create) 13352770834cSDavid S. Miller return NULL; 13362770834cSDavid S. Miller 13375447c5e4SAlexey Dobriyan x = xfrm_state_alloc(net); 13382770834cSDavid S. Miller if (likely(x)) { 13392770834cSDavid S. Miller switch (family) { 13402770834cSDavid S. Miller case AF_INET: 13412770834cSDavid S. Miller x->sel.daddr.a4 = daddr->a4; 13422770834cSDavid S. Miller x->sel.saddr.a4 = saddr->a4; 13432770834cSDavid S. Miller x->sel.prefixlen_d = 32; 13442770834cSDavid S. Miller x->sel.prefixlen_s = 32; 13452770834cSDavid S. Miller x->props.saddr.a4 = saddr->a4; 13462770834cSDavid S. Miller x->id.daddr.a4 = daddr->a4; 13472770834cSDavid S. Miller break; 13482770834cSDavid S. Miller 13492770834cSDavid S. Miller case AF_INET6: 135015e318bdSJiri Benc x->sel.daddr.in6 = daddr->in6; 135115e318bdSJiri Benc x->sel.saddr.in6 = saddr->in6; 13522770834cSDavid S. Miller x->sel.prefixlen_d = 128; 13532770834cSDavid S. Miller x->sel.prefixlen_s = 128; 135415e318bdSJiri Benc x->props.saddr.in6 = saddr->in6; 135515e318bdSJiri Benc x->id.daddr.in6 = daddr->in6; 13562770834cSDavid S. Miller break; 13573ff50b79SStephen Hemminger } 13582770834cSDavid S. Miller 13592770834cSDavid S. Miller x->km.state = XFRM_STATE_ACQ; 13602770834cSDavid S. Miller x->id.proto = proto; 13612770834cSDavid S. Miller x->props.family = family; 13622770834cSDavid S. Miller x->props.mode = mode; 13632770834cSDavid S. Miller x->props.reqid = reqid; 13647e652640SSteffen Klassert x->if_id = if_id; 1365bd55775cSJamal Hadi Salim x->mark.v = m->v; 1366bd55775cSJamal Hadi Salim x->mark.m = m->m; 1367b27aeadbSAlexey Dobriyan x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires; 13682770834cSDavid S. Miller xfrm_state_hold(x); 1369671422b2SThomas Gleixner hrtimer_start(&x->mtimer, 1370671422b2SThomas Gleixner ktime_set(net->xfrm.sysctl_acq_expires, 0), 1371671422b2SThomas Gleixner HRTIMER_MODE_REL_SOFT); 13725447c5e4SAlexey Dobriyan list_add(&x->km.all, &net->xfrm.state_all); 1373ae3fb6d3SFlorian Westphal hlist_add_head_rcu(&x->bydst, net->xfrm.state_bydst + h); 13745447c5e4SAlexey Dobriyan h = xfrm_src_hash(net, daddr, saddr, family); 1375ae3fb6d3SFlorian Westphal hlist_add_head_rcu(&x->bysrc, net->xfrm.state_bysrc + h); 1376918049f0SDavid S. Miller 13775447c5e4SAlexey Dobriyan net->xfrm.state_num++; 1378918049f0SDavid S. Miller 13795447c5e4SAlexey Dobriyan xfrm_hash_grow_check(net, x->bydst.next != NULL); 13802770834cSDavid S. Miller } 13812770834cSDavid S. Miller 13822770834cSDavid S. Miller return x; 13832770834cSDavid S. Miller } 13842770834cSDavid S. Miller 1385bd55775cSJamal Hadi Salim static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq); 13861da177e4SLinus Torvalds 13871da177e4SLinus Torvalds int xfrm_state_add(struct xfrm_state *x) 13881da177e4SLinus Torvalds { 13895447c5e4SAlexey Dobriyan struct net *net = xs_net(x); 139037b08e34SDavid S. Miller struct xfrm_state *x1, *to_put; 13911da177e4SLinus Torvalds int family; 13921da177e4SLinus Torvalds int err; 1393bd55775cSJamal Hadi Salim u32 mark = x->mark.v & x->mark.m; 1394eb2971b6SMasahide NAKAMURA int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY); 13951da177e4SLinus Torvalds 13961da177e4SLinus Torvalds family = x->props.family; 13971da177e4SLinus Torvalds 139837b08e34SDavid S. Miller to_put = NULL; 139937b08e34SDavid S. Miller 1400283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 14011da177e4SLinus Torvalds 1402edcd5821SDavid S. Miller x1 = __xfrm_state_locate(x, use_spi, family); 14031da177e4SLinus Torvalds if (x1) { 140437b08e34SDavid S. Miller to_put = x1; 14051da177e4SLinus Torvalds x1 = NULL; 14061da177e4SLinus Torvalds err = -EEXIST; 14071da177e4SLinus Torvalds goto out; 14081da177e4SLinus Torvalds } 14091da177e4SLinus Torvalds 1410eb2971b6SMasahide NAKAMURA if (use_spi && x->km.seq) { 1411bd55775cSJamal Hadi Salim x1 = __xfrm_find_acq_byseq(net, mark, x->km.seq); 141275e252d9SJoy Latten if (x1 && ((x1->id.proto != x->id.proto) || 141370e94e66SYOSHIFUJI Hideaki / 吉藤英明 !xfrm_addr_equal(&x1->id.daddr, &x->id.daddr, family))) { 141437b08e34SDavid S. Miller to_put = x1; 14151da177e4SLinus Torvalds x1 = NULL; 14161da177e4SLinus Torvalds } 14171da177e4SLinus Torvalds } 14181da177e4SLinus Torvalds 1419eb2971b6SMasahide NAKAMURA if (use_spi && !x1) 1420bd55775cSJamal Hadi Salim x1 = __find_acq_core(net, &x->mark, family, x->props.mode, 14217e652640SSteffen Klassert x->props.reqid, x->if_id, x->id.proto, 14221da177e4SLinus Torvalds &x->id.daddr, &x->props.saddr, 0); 14231da177e4SLinus Torvalds 1424c7f5ea3aSDavid S. Miller __xfrm_state_bump_genids(x); 14251da177e4SLinus Torvalds __xfrm_state_insert(x); 14261da177e4SLinus Torvalds err = 0; 14271da177e4SLinus Torvalds 14281da177e4SLinus Torvalds out: 1429283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 14301da177e4SLinus Torvalds 14311da177e4SLinus Torvalds if (x1) { 14321da177e4SLinus Torvalds xfrm_state_delete(x1); 14331da177e4SLinus Torvalds xfrm_state_put(x1); 14341da177e4SLinus Torvalds } 14351da177e4SLinus Torvalds 143637b08e34SDavid S. Miller if (to_put) 143737b08e34SDavid S. Miller xfrm_state_put(to_put); 143837b08e34SDavid S. Miller 14391da177e4SLinus Torvalds return err; 14401da177e4SLinus Torvalds } 14411da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_add); 14421da177e4SLinus Torvalds 144380c9abaaSShinta Sugimoto #ifdef CONFIG_XFRM_MIGRATE 14444ab47d47SAntony Antony static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, 14454ab47d47SAntony Antony struct xfrm_encap_tmpl *encap) 144680c9abaaSShinta Sugimoto { 144798806f75SAlexey Dobriyan struct net *net = xs_net(orig); 144898806f75SAlexey Dobriyan struct xfrm_state *x = xfrm_state_alloc(net); 144980c9abaaSShinta Sugimoto if (!x) 1450553f9118SHerbert Xu goto out; 145180c9abaaSShinta Sugimoto 145280c9abaaSShinta Sugimoto memcpy(&x->id, &orig->id, sizeof(x->id)); 145380c9abaaSShinta Sugimoto memcpy(&x->sel, &orig->sel, sizeof(x->sel)); 145480c9abaaSShinta Sugimoto memcpy(&x->lft, &orig->lft, sizeof(x->lft)); 145580c9abaaSShinta Sugimoto x->props.mode = orig->props.mode; 145680c9abaaSShinta Sugimoto x->props.replay_window = orig->props.replay_window; 145780c9abaaSShinta Sugimoto x->props.reqid = orig->props.reqid; 145880c9abaaSShinta Sugimoto x->props.family = orig->props.family; 145980c9abaaSShinta Sugimoto x->props.saddr = orig->props.saddr; 146080c9abaaSShinta Sugimoto 146180c9abaaSShinta Sugimoto if (orig->aalg) { 14624447bb33SMartin Willi x->aalg = xfrm_algo_auth_clone(orig->aalg); 146380c9abaaSShinta Sugimoto if (!x->aalg) 146480c9abaaSShinta Sugimoto goto error; 146580c9abaaSShinta Sugimoto } 146680c9abaaSShinta Sugimoto x->props.aalgo = orig->props.aalgo; 146780c9abaaSShinta Sugimoto 1468ee5c2317SSteffen Klassert if (orig->aead) { 1469ee5c2317SSteffen Klassert x->aead = xfrm_algo_aead_clone(orig->aead); 147075bf50f4SAntony Antony x->geniv = orig->geniv; 1471ee5c2317SSteffen Klassert if (!x->aead) 1472ee5c2317SSteffen Klassert goto error; 1473ee5c2317SSteffen Klassert } 147480c9abaaSShinta Sugimoto if (orig->ealg) { 147580c9abaaSShinta Sugimoto x->ealg = xfrm_algo_clone(orig->ealg); 147680c9abaaSShinta Sugimoto if (!x->ealg) 147780c9abaaSShinta Sugimoto goto error; 147880c9abaaSShinta Sugimoto } 147980c9abaaSShinta Sugimoto x->props.ealgo = orig->props.ealgo; 148080c9abaaSShinta Sugimoto 148180c9abaaSShinta Sugimoto if (orig->calg) { 148280c9abaaSShinta Sugimoto x->calg = xfrm_algo_clone(orig->calg); 148380c9abaaSShinta Sugimoto if (!x->calg) 148480c9abaaSShinta Sugimoto goto error; 148580c9abaaSShinta Sugimoto } 148680c9abaaSShinta Sugimoto x->props.calgo = orig->props.calgo; 148780c9abaaSShinta Sugimoto 14884ab47d47SAntony Antony if (encap || orig->encap) { 14894ab47d47SAntony Antony if (encap) 14904ab47d47SAntony Antony x->encap = kmemdup(encap, sizeof(*x->encap), 14914ab47d47SAntony Antony GFP_KERNEL); 14924ab47d47SAntony Antony else 14934ab47d47SAntony Antony x->encap = kmemdup(orig->encap, sizeof(*x->encap), 14944ab47d47SAntony Antony GFP_KERNEL); 14954ab47d47SAntony Antony 149680c9abaaSShinta Sugimoto if (!x->encap) 149780c9abaaSShinta Sugimoto goto error; 149880c9abaaSShinta Sugimoto } 149980c9abaaSShinta Sugimoto 150080c9abaaSShinta Sugimoto if (orig->coaddr) { 150180c9abaaSShinta Sugimoto x->coaddr = kmemdup(orig->coaddr, sizeof(*x->coaddr), 150280c9abaaSShinta Sugimoto GFP_KERNEL); 150380c9abaaSShinta Sugimoto if (!x->coaddr) 150480c9abaaSShinta Sugimoto goto error; 150580c9abaaSShinta Sugimoto } 150680c9abaaSShinta Sugimoto 1507af2f464eSSteffen Klassert if (orig->replay_esn) { 1508cc9ab60eSSteffen Klassert if (xfrm_replay_clone(x, orig)) 1509af2f464eSSteffen Klassert goto error; 1510af2f464eSSteffen Klassert } 1511af2f464eSSteffen Klassert 1512bd55775cSJamal Hadi Salim memcpy(&x->mark, &orig->mark, sizeof(x->mark)); 1513bd55775cSJamal Hadi Salim 1514cc9ab60eSSteffen Klassert if (xfrm_init_state(x) < 0) 151580c9abaaSShinta Sugimoto goto error; 151680c9abaaSShinta Sugimoto 151780c9abaaSShinta Sugimoto x->props.flags = orig->props.flags; 1518a947b0a9SNicolas Dichtel x->props.extra_flags = orig->props.extra_flags; 151980c9abaaSShinta Sugimoto 15207e652640SSteffen Klassert x->if_id = orig->if_id; 1521ee5c2317SSteffen Klassert x->tfcpad = orig->tfcpad; 1522ee5c2317SSteffen Klassert x->replay_maxdiff = orig->replay_maxdiff; 1523ee5c2317SSteffen Klassert x->replay_maxage = orig->replay_maxage; 152480c9abaaSShinta Sugimoto x->curlft.add_time = orig->curlft.add_time; 152580c9abaaSShinta Sugimoto x->km.state = orig->km.state; 152680c9abaaSShinta Sugimoto x->km.seq = orig->km.seq; 1527a486cd23SAntony Antony x->replay = orig->replay; 1528a486cd23SAntony Antony x->preplay = orig->preplay; 152980c9abaaSShinta Sugimoto 153080c9abaaSShinta Sugimoto return x; 153180c9abaaSShinta Sugimoto 153280c9abaaSShinta Sugimoto error: 1533553f9118SHerbert Xu xfrm_state_put(x); 1534553f9118SHerbert Xu out: 153580c9abaaSShinta Sugimoto return NULL; 153680c9abaaSShinta Sugimoto } 153780c9abaaSShinta Sugimoto 1538283bc9f3SFan Du struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *net) 153980c9abaaSShinta Sugimoto { 154080c9abaaSShinta Sugimoto unsigned int h; 15418c0cba22SSteffen Klassert struct xfrm_state *x = NULL; 15428c0cba22SSteffen Klassert 15438c0cba22SSteffen Klassert spin_lock_bh(&net->xfrm.xfrm_state_lock); 154480c9abaaSShinta Sugimoto 154580c9abaaSShinta Sugimoto if (m->reqid) { 1546283bc9f3SFan Du h = xfrm_dst_hash(net, &m->old_daddr, &m->old_saddr, 154780c9abaaSShinta Sugimoto m->reqid, m->old_family); 1548283bc9f3SFan Du hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) { 154980c9abaaSShinta Sugimoto if (x->props.mode != m->mode || 155080c9abaaSShinta Sugimoto x->id.proto != m->proto) 155180c9abaaSShinta Sugimoto continue; 155280c9abaaSShinta Sugimoto if (m->reqid && x->props.reqid != m->reqid) 155380c9abaaSShinta Sugimoto continue; 155470e94e66SYOSHIFUJI Hideaki / 吉藤英明 if (!xfrm_addr_equal(&x->id.daddr, &m->old_daddr, 155580c9abaaSShinta Sugimoto m->old_family) || 155670e94e66SYOSHIFUJI Hideaki / 吉藤英明 !xfrm_addr_equal(&x->props.saddr, &m->old_saddr, 155780c9abaaSShinta Sugimoto m->old_family)) 155880c9abaaSShinta Sugimoto continue; 155980c9abaaSShinta Sugimoto xfrm_state_hold(x); 15608c0cba22SSteffen Klassert break; 156180c9abaaSShinta Sugimoto } 156280c9abaaSShinta Sugimoto } else { 1563283bc9f3SFan Du h = xfrm_src_hash(net, &m->old_daddr, &m->old_saddr, 156480c9abaaSShinta Sugimoto m->old_family); 1565283bc9f3SFan Du hlist_for_each_entry(x, net->xfrm.state_bysrc+h, bysrc) { 156680c9abaaSShinta Sugimoto if (x->props.mode != m->mode || 156780c9abaaSShinta Sugimoto x->id.proto != m->proto) 156880c9abaaSShinta Sugimoto continue; 156970e94e66SYOSHIFUJI Hideaki / 吉藤英明 if (!xfrm_addr_equal(&x->id.daddr, &m->old_daddr, 157080c9abaaSShinta Sugimoto m->old_family) || 157170e94e66SYOSHIFUJI Hideaki / 吉藤英明 !xfrm_addr_equal(&x->props.saddr, &m->old_saddr, 157280c9abaaSShinta Sugimoto m->old_family)) 157380c9abaaSShinta Sugimoto continue; 157480c9abaaSShinta Sugimoto xfrm_state_hold(x); 15758c0cba22SSteffen Klassert break; 157680c9abaaSShinta Sugimoto } 157780c9abaaSShinta Sugimoto } 157880c9abaaSShinta Sugimoto 15798c0cba22SSteffen Klassert spin_unlock_bh(&net->xfrm.xfrm_state_lock); 15808c0cba22SSteffen Klassert 15818c0cba22SSteffen Klassert return x; 158280c9abaaSShinta Sugimoto } 158380c9abaaSShinta Sugimoto EXPORT_SYMBOL(xfrm_migrate_state_find); 158480c9abaaSShinta Sugimoto 158580c9abaaSShinta Sugimoto struct xfrm_state *xfrm_state_migrate(struct xfrm_state *x, 15864ab47d47SAntony Antony struct xfrm_migrate *m, 15874ab47d47SAntony Antony struct xfrm_encap_tmpl *encap) 158880c9abaaSShinta Sugimoto { 158980c9abaaSShinta Sugimoto struct xfrm_state *xc; 159080c9abaaSShinta Sugimoto 15914ab47d47SAntony Antony xc = xfrm_state_clone(x, encap); 159280c9abaaSShinta Sugimoto if (!xc) 159380c9abaaSShinta Sugimoto return NULL; 159480c9abaaSShinta Sugimoto 159580c9abaaSShinta Sugimoto memcpy(&xc->id.daddr, &m->new_daddr, sizeof(xc->id.daddr)); 159680c9abaaSShinta Sugimoto memcpy(&xc->props.saddr, &m->new_saddr, sizeof(xc->props.saddr)); 159780c9abaaSShinta Sugimoto 159880c9abaaSShinta Sugimoto /* add state */ 159970e94e66SYOSHIFUJI Hideaki / 吉藤英明 if (xfrm_addr_equal(&x->id.daddr, &m->new_daddr, m->new_family)) { 160080c9abaaSShinta Sugimoto /* a care is needed when the destination address of the 160180c9abaaSShinta Sugimoto state is to be updated as it is a part of triplet */ 160280c9abaaSShinta Sugimoto xfrm_state_insert(xc); 160380c9abaaSShinta Sugimoto } else { 1604cc9ab60eSSteffen Klassert if (xfrm_state_add(xc) < 0) 160580c9abaaSShinta Sugimoto goto error; 160680c9abaaSShinta Sugimoto } 160780c9abaaSShinta Sugimoto 160880c9abaaSShinta Sugimoto return xc; 160980c9abaaSShinta Sugimoto error: 161078347c8cSThomas Egerer xfrm_state_put(xc); 161180c9abaaSShinta Sugimoto return NULL; 161280c9abaaSShinta Sugimoto } 161380c9abaaSShinta Sugimoto EXPORT_SYMBOL(xfrm_state_migrate); 161480c9abaaSShinta Sugimoto #endif 161580c9abaaSShinta Sugimoto 16161da177e4SLinus Torvalds int xfrm_state_update(struct xfrm_state *x) 16171da177e4SLinus Torvalds { 161837b08e34SDavid S. Miller struct xfrm_state *x1, *to_put; 16191da177e4SLinus Torvalds int err; 1620eb2971b6SMasahide NAKAMURA int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY); 1621283bc9f3SFan Du struct net *net = xs_net(x); 16221da177e4SLinus Torvalds 162337b08e34SDavid S. Miller to_put = NULL; 162437b08e34SDavid S. Miller 1625283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 1626edcd5821SDavid S. Miller x1 = __xfrm_state_locate(x, use_spi, x->props.family); 16271da177e4SLinus Torvalds 16281da177e4SLinus Torvalds err = -ESRCH; 16291da177e4SLinus Torvalds if (!x1) 16301da177e4SLinus Torvalds goto out; 16311da177e4SLinus Torvalds 16321da177e4SLinus Torvalds if (xfrm_state_kern(x1)) { 163337b08e34SDavid S. Miller to_put = x1; 16341da177e4SLinus Torvalds err = -EEXIST; 16351da177e4SLinus Torvalds goto out; 16361da177e4SLinus Torvalds } 16371da177e4SLinus Torvalds 16381da177e4SLinus Torvalds if (x1->km.state == XFRM_STATE_ACQ) { 16391da177e4SLinus Torvalds __xfrm_state_insert(x); 16401da177e4SLinus Torvalds x = NULL; 16411da177e4SLinus Torvalds } 16421da177e4SLinus Torvalds err = 0; 16431da177e4SLinus Torvalds 16441da177e4SLinus Torvalds out: 1645283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 16461da177e4SLinus Torvalds 164737b08e34SDavid S. Miller if (to_put) 164837b08e34SDavid S. Miller xfrm_state_put(to_put); 164937b08e34SDavid S. Miller 16501da177e4SLinus Torvalds if (err) 16511da177e4SLinus Torvalds return err; 16521da177e4SLinus Torvalds 16531da177e4SLinus Torvalds if (!x) { 16541da177e4SLinus Torvalds xfrm_state_delete(x1); 16551da177e4SLinus Torvalds xfrm_state_put(x1); 16561da177e4SLinus Torvalds return 0; 16571da177e4SLinus Torvalds } 16581da177e4SLinus Torvalds 16591da177e4SLinus Torvalds err = -EINVAL; 16601da177e4SLinus Torvalds spin_lock_bh(&x1->lock); 16611da177e4SLinus Torvalds if (likely(x1->km.state == XFRM_STATE_VALID)) { 1662257a4b01SHerbert Xu if (x->encap && x1->encap && 1663257a4b01SHerbert Xu x->encap->encap_type == x1->encap->encap_type) 16641da177e4SLinus Torvalds memcpy(x1->encap, x->encap, sizeof(*x1->encap)); 1665257a4b01SHerbert Xu else if (x->encap || x1->encap) 1666257a4b01SHerbert Xu goto fail; 1667257a4b01SHerbert Xu 1668060f02a3SNoriaki TAKAMIYA if (x->coaddr && x1->coaddr) { 1669060f02a3SNoriaki TAKAMIYA memcpy(x1->coaddr, x->coaddr, sizeof(*x1->coaddr)); 1670060f02a3SNoriaki TAKAMIYA } 1671060f02a3SNoriaki TAKAMIYA if (!use_spi && memcmp(&x1->sel, &x->sel, sizeof(x1->sel))) 1672060f02a3SNoriaki TAKAMIYA memcpy(&x1->sel, &x->sel, sizeof(x1->sel)); 16731da177e4SLinus Torvalds memcpy(&x1->lft, &x->lft, sizeof(x1->lft)); 16741da177e4SLinus Torvalds x1->km.dying = 0; 16751da177e4SLinus Torvalds 1676671422b2SThomas Gleixner hrtimer_start(&x1->mtimer, ktime_set(1, 0), 1677671422b2SThomas Gleixner HRTIMER_MODE_REL_SOFT); 16781da177e4SLinus Torvalds if (x1->curlft.use_time) 16791da177e4SLinus Torvalds xfrm_state_check_expire(x1); 16801da177e4SLinus Torvalds 16815baf4f9cSNathan Harold if (x->props.smark.m || x->props.smark.v || x->if_id) { 16826d8e85ffSNathan Harold spin_lock_bh(&net->xfrm.xfrm_state_lock); 16836d8e85ffSNathan Harold 16845baf4f9cSNathan Harold if (x->props.smark.m || x->props.smark.v) 16856d8e85ffSNathan Harold x1->props.smark = x->props.smark; 16866d8e85ffSNathan Harold 16875baf4f9cSNathan Harold if (x->if_id) 16885baf4f9cSNathan Harold x1->if_id = x->if_id; 16895baf4f9cSNathan Harold 16906d8e85ffSNathan Harold __xfrm_state_bump_genids(x1); 16916d8e85ffSNathan Harold spin_unlock_bh(&net->xfrm.xfrm_state_lock); 16926d8e85ffSNathan Harold } 16936d8e85ffSNathan Harold 16941da177e4SLinus Torvalds err = 0; 16958fcbc637STushar Gohad x->km.state = XFRM_STATE_DEAD; 16968fcbc637STushar Gohad __xfrm_state_put(x); 16971da177e4SLinus Torvalds } 1698257a4b01SHerbert Xu 1699257a4b01SHerbert Xu fail: 17001da177e4SLinus Torvalds spin_unlock_bh(&x1->lock); 17011da177e4SLinus Torvalds 17021da177e4SLinus Torvalds xfrm_state_put(x1); 17031da177e4SLinus Torvalds 17041da177e4SLinus Torvalds return err; 17051da177e4SLinus Torvalds } 17061da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_update); 17071da177e4SLinus Torvalds 17081da177e4SLinus Torvalds int xfrm_state_check_expire(struct xfrm_state *x) 17091da177e4SLinus Torvalds { 17101da177e4SLinus Torvalds if (!x->curlft.use_time) 1711386c5680SArnd Bergmann x->curlft.use_time = ktime_get_real_seconds(); 17121da177e4SLinus Torvalds 17131da177e4SLinus Torvalds if (x->curlft.bytes >= x->lft.hard_byte_limit || 17141da177e4SLinus Torvalds x->curlft.packets >= x->lft.hard_packet_limit) { 17154666faabSHerbert Xu x->km.state = XFRM_STATE_EXPIRED; 1716671422b2SThomas Gleixner hrtimer_start(&x->mtimer, 0, HRTIMER_MODE_REL_SOFT); 17171da177e4SLinus Torvalds return -EINVAL; 17181da177e4SLinus Torvalds } 17191da177e4SLinus Torvalds 17201da177e4SLinus Torvalds if (!x->km.dying && 17211da177e4SLinus Torvalds (x->curlft.bytes >= x->lft.soft_byte_limit || 17224666faabSHerbert Xu x->curlft.packets >= x->lft.soft_packet_limit)) { 17234666faabSHerbert Xu x->km.dying = 1; 172453bc6b4dSJamal Hadi Salim km_state_expired(x, 0, 0); 17254666faabSHerbert Xu } 17261da177e4SLinus Torvalds return 0; 17271da177e4SLinus Torvalds } 17281da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_check_expire); 17291da177e4SLinus Torvalds 17301da177e4SLinus Torvalds struct xfrm_state * 1731a70486f0SDavid S. Miller xfrm_state_lookup(struct net *net, u32 mark, const xfrm_address_t *daddr, __be32 spi, 1732bd55775cSJamal Hadi Salim u8 proto, unsigned short family) 17331da177e4SLinus Torvalds { 17341da177e4SLinus Torvalds struct xfrm_state *x; 17351da177e4SLinus Torvalds 1736c2f672fcSFlorian Westphal rcu_read_lock(); 1737bd55775cSJamal Hadi Salim x = __xfrm_state_lookup(net, mark, daddr, spi, proto, family); 1738c2f672fcSFlorian Westphal rcu_read_unlock(); 17391da177e4SLinus Torvalds return x; 17401da177e4SLinus Torvalds } 17411da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_lookup); 17421da177e4SLinus Torvalds 17431da177e4SLinus Torvalds struct xfrm_state * 1744bd55775cSJamal Hadi Salim xfrm_state_lookup_byaddr(struct net *net, u32 mark, 1745a70486f0SDavid S. Miller const xfrm_address_t *daddr, const xfrm_address_t *saddr, 1746eb2971b6SMasahide NAKAMURA u8 proto, unsigned short family) 1747eb2971b6SMasahide NAKAMURA { 1748eb2971b6SMasahide NAKAMURA struct xfrm_state *x; 1749eb2971b6SMasahide NAKAMURA 1750283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 1751bd55775cSJamal Hadi Salim x = __xfrm_state_lookup_byaddr(net, mark, daddr, saddr, proto, family); 1752283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 1753eb2971b6SMasahide NAKAMURA return x; 1754eb2971b6SMasahide NAKAMURA } 1755eb2971b6SMasahide NAKAMURA EXPORT_SYMBOL(xfrm_state_lookup_byaddr); 1756eb2971b6SMasahide NAKAMURA 1757eb2971b6SMasahide NAKAMURA struct xfrm_state * 1758e473fcb4SMathias Krause xfrm_find_acq(struct net *net, const struct xfrm_mark *mark, u8 mode, u32 reqid, 17597e652640SSteffen Klassert u32 if_id, u8 proto, const xfrm_address_t *daddr, 1760e473fcb4SMathias Krause const xfrm_address_t *saddr, int create, unsigned short family) 17611da177e4SLinus Torvalds { 17621da177e4SLinus Torvalds struct xfrm_state *x; 17631da177e4SLinus Torvalds 1764283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 17657e652640SSteffen Klassert x = __find_acq_core(net, mark, family, mode, reqid, if_id, proto, daddr, saddr, create); 1766283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 17672770834cSDavid S. Miller 17681da177e4SLinus Torvalds return x; 17691da177e4SLinus Torvalds } 17701da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_find_acq); 17711da177e4SLinus Torvalds 177241a49cc3SMasahide NAKAMURA #ifdef CONFIG_XFRM_SUB_POLICY 17733aaf3915SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6) 17743aaf3915SFlorian Westphal /* distribution counting sort function for xfrm_state and xfrm_tmpl */ 17753aaf3915SFlorian Westphal static void 17763aaf3915SFlorian Westphal __xfrm6_sort(void **dst, void **src, int n, 17773aaf3915SFlorian Westphal int (*cmp)(const void *p), int maxclass) 17783aaf3915SFlorian Westphal { 17793aaf3915SFlorian Westphal int count[XFRM_MAX_DEPTH] = { }; 17803aaf3915SFlorian Westphal int class[XFRM_MAX_DEPTH]; 17813aaf3915SFlorian Westphal int i; 17823aaf3915SFlorian Westphal 17833aaf3915SFlorian Westphal for (i = 0; i < n; i++) { 17843aaf3915SFlorian Westphal int c = cmp(src[i]); 17853aaf3915SFlorian Westphal 17863aaf3915SFlorian Westphal class[i] = c; 17873aaf3915SFlorian Westphal count[c]++; 17883aaf3915SFlorian Westphal } 17893aaf3915SFlorian Westphal 17903aaf3915SFlorian Westphal for (i = 2; i < maxclass; i++) 17913aaf3915SFlorian Westphal count[i] += count[i - 1]; 17923aaf3915SFlorian Westphal 17933aaf3915SFlorian Westphal for (i = 0; i < n; i++) { 17943aaf3915SFlorian Westphal dst[count[class[i] - 1]++] = src[i]; 17953aaf3915SFlorian Westphal src[i] = NULL; 17963aaf3915SFlorian Westphal } 17973aaf3915SFlorian Westphal } 17983aaf3915SFlorian Westphal 17993aaf3915SFlorian Westphal /* Rule for xfrm_state: 18003aaf3915SFlorian Westphal * 18013aaf3915SFlorian Westphal * rule 1: select IPsec transport except AH 18023aaf3915SFlorian Westphal * rule 2: select MIPv6 RO or inbound trigger 18033aaf3915SFlorian Westphal * rule 3: select IPsec transport AH 18043aaf3915SFlorian Westphal * rule 4: select IPsec tunnel 18053aaf3915SFlorian Westphal * rule 5: others 18063aaf3915SFlorian Westphal */ 18073aaf3915SFlorian Westphal static int __xfrm6_state_sort_cmp(const void *p) 18083aaf3915SFlorian Westphal { 18093aaf3915SFlorian Westphal const struct xfrm_state *v = p; 18103aaf3915SFlorian Westphal 18113aaf3915SFlorian Westphal switch (v->props.mode) { 18123aaf3915SFlorian Westphal case XFRM_MODE_TRANSPORT: 18133aaf3915SFlorian Westphal if (v->id.proto != IPPROTO_AH) 18143aaf3915SFlorian Westphal return 1; 18153aaf3915SFlorian Westphal else 18163aaf3915SFlorian Westphal return 3; 18173aaf3915SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6_MIP6) 18183aaf3915SFlorian Westphal case XFRM_MODE_ROUTEOPTIMIZATION: 18193aaf3915SFlorian Westphal case XFRM_MODE_IN_TRIGGER: 18203aaf3915SFlorian Westphal return 2; 18213aaf3915SFlorian Westphal #endif 18223aaf3915SFlorian Westphal case XFRM_MODE_TUNNEL: 18233aaf3915SFlorian Westphal case XFRM_MODE_BEET: 18243aaf3915SFlorian Westphal return 4; 18253aaf3915SFlorian Westphal } 18263aaf3915SFlorian Westphal return 5; 18273aaf3915SFlorian Westphal } 18283aaf3915SFlorian Westphal 18293aaf3915SFlorian Westphal /* Rule for xfrm_tmpl: 18303aaf3915SFlorian Westphal * 18313aaf3915SFlorian Westphal * rule 1: select IPsec transport 18323aaf3915SFlorian Westphal * rule 2: select MIPv6 RO or inbound trigger 18333aaf3915SFlorian Westphal * rule 3: select IPsec tunnel 18343aaf3915SFlorian Westphal * rule 4: others 18353aaf3915SFlorian Westphal */ 18363aaf3915SFlorian Westphal static int __xfrm6_tmpl_sort_cmp(const void *p) 18373aaf3915SFlorian Westphal { 18383aaf3915SFlorian Westphal const struct xfrm_tmpl *v = p; 18393aaf3915SFlorian Westphal 18403aaf3915SFlorian Westphal switch (v->mode) { 18413aaf3915SFlorian Westphal case XFRM_MODE_TRANSPORT: 18423aaf3915SFlorian Westphal return 1; 18433aaf3915SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6_MIP6) 18443aaf3915SFlorian Westphal case XFRM_MODE_ROUTEOPTIMIZATION: 18453aaf3915SFlorian Westphal case XFRM_MODE_IN_TRIGGER: 18463aaf3915SFlorian Westphal return 2; 18473aaf3915SFlorian Westphal #endif 18483aaf3915SFlorian Westphal case XFRM_MODE_TUNNEL: 18493aaf3915SFlorian Westphal case XFRM_MODE_BEET: 18503aaf3915SFlorian Westphal return 3; 18513aaf3915SFlorian Westphal } 18523aaf3915SFlorian Westphal return 4; 18533aaf3915SFlorian Westphal } 18543aaf3915SFlorian Westphal #else 18553aaf3915SFlorian Westphal static inline int __xfrm6_state_sort_cmp(const void *p) { return 5; } 18563aaf3915SFlorian Westphal static inline int __xfrm6_tmpl_sort_cmp(const void *p) { return 4; } 18573aaf3915SFlorian Westphal 18583aaf3915SFlorian Westphal static inline void 18593aaf3915SFlorian Westphal __xfrm6_sort(void **dst, void **src, int n, 18603aaf3915SFlorian Westphal int (*cmp)(const void *p), int maxclass) 186141a49cc3SMasahide NAKAMURA { 18623f5a95adSKoichiro Den int i; 186341a49cc3SMasahide NAKAMURA 18643aaf3915SFlorian Westphal for (i = 0; i < n; i++) 18653aaf3915SFlorian Westphal dst[i] = src[i]; 18663aaf3915SFlorian Westphal } 18673aaf3915SFlorian Westphal #endif /* CONFIG_IPV6 */ 18683aaf3915SFlorian Westphal 18693aaf3915SFlorian Westphal void 18703aaf3915SFlorian Westphal xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n, 18713aaf3915SFlorian Westphal unsigned short family) 18723aaf3915SFlorian Westphal { 18733aaf3915SFlorian Westphal int i; 18743aaf3915SFlorian Westphal 18753aaf3915SFlorian Westphal if (family == AF_INET6) 18763aaf3915SFlorian Westphal __xfrm6_sort((void **)dst, (void **)src, n, 18773aaf3915SFlorian Westphal __xfrm6_tmpl_sort_cmp, 5); 18783f5a95adSKoichiro Den else 18793f5a95adSKoichiro Den for (i = 0; i < n; i++) 18803f5a95adSKoichiro Den dst[i] = src[i]; 188141a49cc3SMasahide NAKAMURA } 188241a49cc3SMasahide NAKAMURA 18833aaf3915SFlorian Westphal void 188441a49cc3SMasahide NAKAMURA xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n, 188541a49cc3SMasahide NAKAMURA unsigned short family) 188641a49cc3SMasahide NAKAMURA { 18873f5a95adSKoichiro Den int i; 1888283bc9f3SFan Du 18893aaf3915SFlorian Westphal if (family == AF_INET6) 18903aaf3915SFlorian Westphal __xfrm6_sort((void **)dst, (void **)src, n, 18913aaf3915SFlorian Westphal __xfrm6_state_sort_cmp, 6); 18923f5a95adSKoichiro Den else 18933f5a95adSKoichiro Den for (i = 0; i < n; i++) 18943f5a95adSKoichiro Den dst[i] = src[i]; 189541a49cc3SMasahide NAKAMURA } 189641a49cc3SMasahide NAKAMURA #endif 189741a49cc3SMasahide NAKAMURA 18981da177e4SLinus Torvalds /* Silly enough, but I'm lazy to build resolution list */ 18991da177e4SLinus Torvalds 1900bd55775cSJamal Hadi Salim static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq) 19011da177e4SLinus Torvalds { 19021da177e4SLinus Torvalds int i; 19031da177e4SLinus Torvalds 19045447c5e4SAlexey Dobriyan for (i = 0; i <= net->xfrm.state_hmask; i++) { 19058f126e37SDavid S. Miller struct xfrm_state *x; 19068f126e37SDavid S. Miller 1907b67bfe0dSSasha Levin hlist_for_each_entry(x, net->xfrm.state_bydst+i, bydst) { 19088f126e37SDavid S. Miller if (x->km.seq == seq && 19093d6acfa7SJamal Hadi Salim (mark & x->mark.m) == x->mark.v && 19108f126e37SDavid S. Miller x->km.state == XFRM_STATE_ACQ) { 19111da177e4SLinus Torvalds xfrm_state_hold(x); 19121da177e4SLinus Torvalds return x; 19131da177e4SLinus Torvalds } 19141da177e4SLinus Torvalds } 19151da177e4SLinus Torvalds } 19161da177e4SLinus Torvalds return NULL; 19171da177e4SLinus Torvalds } 19181da177e4SLinus Torvalds 1919bd55775cSJamal Hadi Salim struct xfrm_state *xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq) 19201da177e4SLinus Torvalds { 19211da177e4SLinus Torvalds struct xfrm_state *x; 19221da177e4SLinus Torvalds 1923283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 1924bd55775cSJamal Hadi Salim x = __xfrm_find_acq_byseq(net, mark, seq); 1925283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 19261da177e4SLinus Torvalds return x; 19271da177e4SLinus Torvalds } 19281da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_find_acq_byseq); 19291da177e4SLinus Torvalds 19301da177e4SLinus Torvalds u32 xfrm_get_acqseq(void) 19311da177e4SLinus Torvalds { 19321da177e4SLinus Torvalds u32 res; 19336836b9bdSjamal static atomic_t acqseq; 19341da177e4SLinus Torvalds 19356836b9bdSjamal do { 19366836b9bdSjamal res = atomic_inc_return(&acqseq); 19376836b9bdSjamal } while (!res); 19386836b9bdSjamal 19391da177e4SLinus Torvalds return res; 19401da177e4SLinus Torvalds } 19411da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_get_acqseq); 19421da177e4SLinus Torvalds 1943776e9dd9SFan Du int verify_spi_info(u8 proto, u32 min, u32 max) 1944776e9dd9SFan Du { 1945776e9dd9SFan Du switch (proto) { 1946776e9dd9SFan Du case IPPROTO_AH: 1947776e9dd9SFan Du case IPPROTO_ESP: 1948776e9dd9SFan Du break; 1949776e9dd9SFan Du 1950776e9dd9SFan Du case IPPROTO_COMP: 1951776e9dd9SFan Du /* IPCOMP spi is 16-bits. */ 1952776e9dd9SFan Du if (max >= 0x10000) 1953776e9dd9SFan Du return -EINVAL; 1954776e9dd9SFan Du break; 1955776e9dd9SFan Du 1956776e9dd9SFan Du default: 1957776e9dd9SFan Du return -EINVAL; 1958776e9dd9SFan Du } 1959776e9dd9SFan Du 1960776e9dd9SFan Du if (min > max) 1961776e9dd9SFan Du return -EINVAL; 1962776e9dd9SFan Du 1963776e9dd9SFan Du return 0; 1964776e9dd9SFan Du } 1965776e9dd9SFan Du EXPORT_SYMBOL(verify_spi_info); 1966776e9dd9SFan Du 1967658b219eSHerbert Xu int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high) 19681da177e4SLinus Torvalds { 1969221df1edSAlexey Dobriyan struct net *net = xs_net(x); 1970f034b5d4SDavid S. Miller unsigned int h; 19711da177e4SLinus Torvalds struct xfrm_state *x0; 1972658b219eSHerbert Xu int err = -ENOENT; 1973658b219eSHerbert Xu __be32 minspi = htonl(low); 1974658b219eSHerbert Xu __be32 maxspi = htonl(high); 1975bd55775cSJamal Hadi Salim u32 mark = x->mark.v & x->mark.m; 19761da177e4SLinus Torvalds 1977658b219eSHerbert Xu spin_lock_bh(&x->lock); 1978658b219eSHerbert Xu if (x->km.state == XFRM_STATE_DEAD) 1979658b219eSHerbert Xu goto unlock; 1980658b219eSHerbert Xu 1981658b219eSHerbert Xu err = 0; 19821da177e4SLinus Torvalds if (x->id.spi) 1983658b219eSHerbert Xu goto unlock; 1984658b219eSHerbert Xu 1985658b219eSHerbert Xu err = -ENOENT; 19861da177e4SLinus Torvalds 19871da177e4SLinus Torvalds if (minspi == maxspi) { 1988bd55775cSJamal Hadi Salim x0 = xfrm_state_lookup(net, mark, &x->id.daddr, minspi, x->id.proto, x->props.family); 19891da177e4SLinus Torvalds if (x0) { 19901da177e4SLinus Torvalds xfrm_state_put(x0); 1991658b219eSHerbert Xu goto unlock; 19921da177e4SLinus Torvalds } 19931da177e4SLinus Torvalds x->id.spi = minspi; 19941da177e4SLinus Torvalds } else { 19951da177e4SLinus Torvalds u32 spi = 0; 199626977b4eSAl Viro for (h = 0; h < high-low+1; h++) { 199763862b5bSAruna-Hewapathirane spi = low + prandom_u32()%(high-low+1); 1998bd55775cSJamal Hadi Salim x0 = xfrm_state_lookup(net, mark, &x->id.daddr, htonl(spi), x->id.proto, x->props.family); 19991da177e4SLinus Torvalds if (x0 == NULL) { 20001da177e4SLinus Torvalds x->id.spi = htonl(spi); 20011da177e4SLinus Torvalds break; 20021da177e4SLinus Torvalds } 20031da177e4SLinus Torvalds xfrm_state_put(x0); 20041da177e4SLinus Torvalds } 20051da177e4SLinus Torvalds } 20061da177e4SLinus Torvalds if (x->id.spi) { 2007283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 200812604d8aSAlexey Dobriyan h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, x->props.family); 2009ae3fb6d3SFlorian Westphal hlist_add_head_rcu(&x->byspi, net->xfrm.state_byspi + h); 2010283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 2011658b219eSHerbert Xu 2012658b219eSHerbert Xu err = 0; 20131da177e4SLinus Torvalds } 2014658b219eSHerbert Xu 2015658b219eSHerbert Xu unlock: 2016658b219eSHerbert Xu spin_unlock_bh(&x->lock); 2017658b219eSHerbert Xu 2018658b219eSHerbert Xu return err; 20191da177e4SLinus Torvalds } 20201da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_alloc_spi); 20211da177e4SLinus Torvalds 2022d3623099SNicolas Dichtel static bool __xfrm_state_filter_match(struct xfrm_state *x, 2023870a2df4SNicolas Dichtel struct xfrm_address_filter *filter) 2024d3623099SNicolas Dichtel { 2025d3623099SNicolas Dichtel if (filter) { 2026d3623099SNicolas Dichtel if ((filter->family == AF_INET || 2027d3623099SNicolas Dichtel filter->family == AF_INET6) && 2028d3623099SNicolas Dichtel x->props.family != filter->family) 2029d3623099SNicolas Dichtel return false; 2030d3623099SNicolas Dichtel 2031d3623099SNicolas Dichtel return addr_match(&x->props.saddr, &filter->saddr, 2032d3623099SNicolas Dichtel filter->splen) && 2033d3623099SNicolas Dichtel addr_match(&x->id.daddr, &filter->daddr, 2034d3623099SNicolas Dichtel filter->dplen); 2035d3623099SNicolas Dichtel } 2036d3623099SNicolas Dichtel return true; 2037d3623099SNicolas Dichtel } 2038d3623099SNicolas Dichtel 2039284fa7daSAlexey Dobriyan int xfrm_state_walk(struct net *net, struct xfrm_state_walk *walk, 20404c563f76STimo Teras int (*func)(struct xfrm_state *, int, void*), 20411da177e4SLinus Torvalds void *data) 20421da177e4SLinus Torvalds { 204312a169e7SHerbert Xu struct xfrm_state *state; 204412a169e7SHerbert Xu struct xfrm_state_walk *x; 20451da177e4SLinus Torvalds int err = 0; 20461da177e4SLinus Torvalds 204712a169e7SHerbert Xu if (walk->seq != 0 && list_empty(&walk->all)) 20484c563f76STimo Teras return 0; 20494c563f76STimo Teras 2050283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 205112a169e7SHerbert Xu if (list_empty(&walk->all)) 2052284fa7daSAlexey Dobriyan x = list_first_entry(&net->xfrm.state_all, struct xfrm_state_walk, all); 205312a169e7SHerbert Xu else 205480077702SLi RongQing x = list_first_entry(&walk->all, struct xfrm_state_walk, all); 2055284fa7daSAlexey Dobriyan list_for_each_entry_from(x, &net->xfrm.state_all, all) { 205612a169e7SHerbert Xu if (x->state == XFRM_STATE_DEAD) 20574c563f76STimo Teras continue; 205812a169e7SHerbert Xu state = container_of(x, struct xfrm_state, km); 205912a169e7SHerbert Xu if (!xfrm_id_proto_match(state->id.proto, walk->proto)) 206094b9bb54SJamal Hadi Salim continue; 2061d3623099SNicolas Dichtel if (!__xfrm_state_filter_match(state, walk->filter)) 2062d3623099SNicolas Dichtel continue; 206312a169e7SHerbert Xu err = func(state, walk->seq, data); 20644c563f76STimo Teras if (err) { 206512a169e7SHerbert Xu list_move_tail(&walk->all, &x->all); 206694b9bb54SJamal Hadi Salim goto out; 206794b9bb54SJamal Hadi Salim } 206812a169e7SHerbert Xu walk->seq++; 20694c563f76STimo Teras } 207012a169e7SHerbert Xu if (walk->seq == 0) { 20711da177e4SLinus Torvalds err = -ENOENT; 20721da177e4SLinus Torvalds goto out; 20731da177e4SLinus Torvalds } 207412a169e7SHerbert Xu list_del_init(&walk->all); 20751da177e4SLinus Torvalds out: 2076283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 20771da177e4SLinus Torvalds return err; 20781da177e4SLinus Torvalds } 20791da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_walk); 20801da177e4SLinus Torvalds 2081d3623099SNicolas Dichtel void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto, 2082870a2df4SNicolas Dichtel struct xfrm_address_filter *filter) 20835c182458SHerbert Xu { 208412a169e7SHerbert Xu INIT_LIST_HEAD(&walk->all); 20855c182458SHerbert Xu walk->proto = proto; 208612a169e7SHerbert Xu walk->state = XFRM_STATE_DEAD; 208712a169e7SHerbert Xu walk->seq = 0; 2088d3623099SNicolas Dichtel walk->filter = filter; 20895c182458SHerbert Xu } 20905c182458SHerbert Xu EXPORT_SYMBOL(xfrm_state_walk_init); 20915c182458SHerbert Xu 2092283bc9f3SFan Du void xfrm_state_walk_done(struct xfrm_state_walk *walk, struct net *net) 2093abb81c4fSHerbert Xu { 2094d3623099SNicolas Dichtel kfree(walk->filter); 2095d3623099SNicolas Dichtel 209612a169e7SHerbert Xu if (list_empty(&walk->all)) 20975c182458SHerbert Xu return; 20985c182458SHerbert Xu 2099283bc9f3SFan Du spin_lock_bh(&net->xfrm.xfrm_state_lock); 210012a169e7SHerbert Xu list_del(&walk->all); 2101283bc9f3SFan Du spin_unlock_bh(&net->xfrm.xfrm_state_lock); 2102abb81c4fSHerbert Xu } 2103abb81c4fSHerbert Xu EXPORT_SYMBOL(xfrm_state_walk_done); 2104abb81c4fSHerbert Xu 2105e99e88a9SKees Cook static void xfrm_replay_timer_handler(struct timer_list *t) 2106f8cd5488SJamal Hadi Salim { 2107e99e88a9SKees Cook struct xfrm_state *x = from_timer(x, t, rtimer); 2108f8cd5488SJamal Hadi Salim 2109f8cd5488SJamal Hadi Salim spin_lock(&x->lock); 2110f8cd5488SJamal Hadi Salim 21112717096aSJamal Hadi Salim if (x->km.state == XFRM_STATE_VALID) { 2112a6483b79SAlexey Dobriyan if (xfrm_aevent_is_on(xs_net(x))) 21139fdc4883SSteffen Klassert x->repl->notify(x, XFRM_REPLAY_TIMEOUT); 21142717096aSJamal Hadi Salim else 21152717096aSJamal Hadi Salim x->xflags |= XFRM_TIME_DEFER; 21162717096aSJamal Hadi Salim } 2117f8cd5488SJamal Hadi Salim 2118f8cd5488SJamal Hadi Salim spin_unlock(&x->lock); 2119f8cd5488SJamal Hadi Salim } 2120f8cd5488SJamal Hadi Salim 2121df01812eSDenis Cheng static LIST_HEAD(xfrm_km_list); 21221da177e4SLinus Torvalds 2123214e005bSDavid S. Miller void km_policy_notify(struct xfrm_policy *xp, int dir, const struct km_event *c) 21241da177e4SLinus Torvalds { 21251da177e4SLinus Torvalds struct xfrm_mgr *km; 21261da177e4SLinus Torvalds 212785168c00SCong Wang rcu_read_lock(); 212885168c00SCong Wang list_for_each_entry_rcu(km, &xfrm_km_list, list) 212926b15dadSJamal Hadi Salim if (km->notify_policy) 213026b15dadSJamal Hadi Salim km->notify_policy(xp, dir, c); 213185168c00SCong Wang rcu_read_unlock(); 213226b15dadSJamal Hadi Salim } 213326b15dadSJamal Hadi Salim 2134214e005bSDavid S. Miller void km_state_notify(struct xfrm_state *x, const struct km_event *c) 213526b15dadSJamal Hadi Salim { 213626b15dadSJamal Hadi Salim struct xfrm_mgr *km; 213785168c00SCong Wang rcu_read_lock(); 213885168c00SCong Wang list_for_each_entry_rcu(km, &xfrm_km_list, list) 213926b15dadSJamal Hadi Salim if (km->notify) 214026b15dadSJamal Hadi Salim km->notify(x, c); 214185168c00SCong Wang rcu_read_unlock(); 214226b15dadSJamal Hadi Salim } 214326b15dadSJamal Hadi Salim 214426b15dadSJamal Hadi Salim EXPORT_SYMBOL(km_policy_notify); 214526b15dadSJamal Hadi Salim EXPORT_SYMBOL(km_state_notify); 214626b15dadSJamal Hadi Salim 214715e47304SEric W. Biederman void km_state_expired(struct xfrm_state *x, int hard, u32 portid) 214826b15dadSJamal Hadi Salim { 214926b15dadSJamal Hadi Salim struct km_event c; 215026b15dadSJamal Hadi Salim 2151bf08867fSHerbert Xu c.data.hard = hard; 215215e47304SEric W. Biederman c.portid = portid; 2153f60f6b8fSHerbert Xu c.event = XFRM_MSG_EXPIRE; 215426b15dadSJamal Hadi Salim km_state_notify(x, &c); 21551da177e4SLinus Torvalds } 21561da177e4SLinus Torvalds 215753bc6b4dSJamal Hadi Salim EXPORT_SYMBOL(km_state_expired); 215826b15dadSJamal Hadi Salim /* 215926b15dadSJamal Hadi Salim * We send to all registered managers regardless of failure 216026b15dadSJamal Hadi Salim * We are happy with one success 216126b15dadSJamal Hadi Salim */ 2162980ebd25SJamal Hadi Salim int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol) 21631da177e4SLinus Torvalds { 216426b15dadSJamal Hadi Salim int err = -EINVAL, acqret; 21651da177e4SLinus Torvalds struct xfrm_mgr *km; 21661da177e4SLinus Torvalds 216785168c00SCong Wang rcu_read_lock(); 216885168c00SCong Wang list_for_each_entry_rcu(km, &xfrm_km_list, list) { 216965e0736bSFan Du acqret = km->acquire(x, t, pol); 217026b15dadSJamal Hadi Salim if (!acqret) 217126b15dadSJamal Hadi Salim err = acqret; 21721da177e4SLinus Torvalds } 217385168c00SCong Wang rcu_read_unlock(); 21741da177e4SLinus Torvalds return err; 21751da177e4SLinus Torvalds } 2176980ebd25SJamal Hadi Salim EXPORT_SYMBOL(km_query); 21771da177e4SLinus Torvalds 21785d36b180SAl Viro int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport) 21791da177e4SLinus Torvalds { 21801da177e4SLinus Torvalds int err = -EINVAL; 21811da177e4SLinus Torvalds struct xfrm_mgr *km; 21821da177e4SLinus Torvalds 218385168c00SCong Wang rcu_read_lock(); 218485168c00SCong Wang list_for_each_entry_rcu(km, &xfrm_km_list, list) { 21851da177e4SLinus Torvalds if (km->new_mapping) 21861da177e4SLinus Torvalds err = km->new_mapping(x, ipaddr, sport); 21871da177e4SLinus Torvalds if (!err) 21881da177e4SLinus Torvalds break; 21891da177e4SLinus Torvalds } 219085168c00SCong Wang rcu_read_unlock(); 21911da177e4SLinus Torvalds return err; 21921da177e4SLinus Torvalds } 21931da177e4SLinus Torvalds EXPORT_SYMBOL(km_new_mapping); 21941da177e4SLinus Torvalds 219515e47304SEric W. Biederman void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 portid) 21961da177e4SLinus Torvalds { 219726b15dadSJamal Hadi Salim struct km_event c; 21981da177e4SLinus Torvalds 2199bf08867fSHerbert Xu c.data.hard = hard; 220015e47304SEric W. Biederman c.portid = portid; 2201f60f6b8fSHerbert Xu c.event = XFRM_MSG_POLEXPIRE; 220226b15dadSJamal Hadi Salim km_policy_notify(pol, dir, &c); 22031da177e4SLinus Torvalds } 2204a70fcb0bSDavid S. Miller EXPORT_SYMBOL(km_policy_expired); 22051da177e4SLinus Torvalds 22062d60abc2SEric Dumazet #ifdef CONFIG_XFRM_MIGRATE 2207183cad12SDavid S. Miller int km_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, 2208183cad12SDavid S. Miller const struct xfrm_migrate *m, int num_migrate, 22098bafd730SAntony Antony const struct xfrm_kmaddress *k, 22108bafd730SAntony Antony const struct xfrm_encap_tmpl *encap) 221180c9abaaSShinta Sugimoto { 221280c9abaaSShinta Sugimoto int err = -EINVAL; 221380c9abaaSShinta Sugimoto int ret; 221480c9abaaSShinta Sugimoto struct xfrm_mgr *km; 221580c9abaaSShinta Sugimoto 221685168c00SCong Wang rcu_read_lock(); 221785168c00SCong Wang list_for_each_entry_rcu(km, &xfrm_km_list, list) { 221880c9abaaSShinta Sugimoto if (km->migrate) { 22198bafd730SAntony Antony ret = km->migrate(sel, dir, type, m, num_migrate, k, 22208bafd730SAntony Antony encap); 222180c9abaaSShinta Sugimoto if (!ret) 222280c9abaaSShinta Sugimoto err = ret; 222380c9abaaSShinta Sugimoto } 222480c9abaaSShinta Sugimoto } 222585168c00SCong Wang rcu_read_unlock(); 222680c9abaaSShinta Sugimoto return err; 222780c9abaaSShinta Sugimoto } 222880c9abaaSShinta Sugimoto EXPORT_SYMBOL(km_migrate); 22292d60abc2SEric Dumazet #endif 223080c9abaaSShinta Sugimoto 2231db983c11SAlexey Dobriyan int km_report(struct net *net, u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr) 223297a64b45SMasahide NAKAMURA { 223397a64b45SMasahide NAKAMURA int err = -EINVAL; 223497a64b45SMasahide NAKAMURA int ret; 223597a64b45SMasahide NAKAMURA struct xfrm_mgr *km; 223697a64b45SMasahide NAKAMURA 223785168c00SCong Wang rcu_read_lock(); 223885168c00SCong Wang list_for_each_entry_rcu(km, &xfrm_km_list, list) { 223997a64b45SMasahide NAKAMURA if (km->report) { 2240db983c11SAlexey Dobriyan ret = km->report(net, proto, sel, addr); 224197a64b45SMasahide NAKAMURA if (!ret) 224297a64b45SMasahide NAKAMURA err = ret; 224397a64b45SMasahide NAKAMURA } 224497a64b45SMasahide NAKAMURA } 224585168c00SCong Wang rcu_read_unlock(); 224697a64b45SMasahide NAKAMURA return err; 224797a64b45SMasahide NAKAMURA } 224897a64b45SMasahide NAKAMURA EXPORT_SYMBOL(km_report); 224997a64b45SMasahide NAKAMURA 2250bb9cd077SFlorian Westphal static bool km_is_alive(const struct km_event *c) 22510f24558eSHoria Geanta { 22520f24558eSHoria Geanta struct xfrm_mgr *km; 22530f24558eSHoria Geanta bool is_alive = false; 22540f24558eSHoria Geanta 22550f24558eSHoria Geanta rcu_read_lock(); 22560f24558eSHoria Geanta list_for_each_entry_rcu(km, &xfrm_km_list, list) { 22570f24558eSHoria Geanta if (km->is_alive && km->is_alive(c)) { 22580f24558eSHoria Geanta is_alive = true; 22590f24558eSHoria Geanta break; 22600f24558eSHoria Geanta } 22610f24558eSHoria Geanta } 22620f24558eSHoria Geanta rcu_read_unlock(); 22630f24558eSHoria Geanta 22640f24558eSHoria Geanta return is_alive; 22650f24558eSHoria Geanta } 22660f24558eSHoria Geanta 2267c9e7c76dSDmitry Safonov #if IS_ENABLED(CONFIG_XFRM_USER_COMPAT) 2268c9e7c76dSDmitry Safonov static DEFINE_SPINLOCK(xfrm_translator_lock); 2269c9e7c76dSDmitry Safonov static struct xfrm_translator __rcu *xfrm_translator; 2270c9e7c76dSDmitry Safonov 2271c9e7c76dSDmitry Safonov struct xfrm_translator *xfrm_get_translator(void) 2272c9e7c76dSDmitry Safonov { 2273c9e7c76dSDmitry Safonov struct xfrm_translator *xtr; 2274c9e7c76dSDmitry Safonov 2275c9e7c76dSDmitry Safonov rcu_read_lock(); 2276c9e7c76dSDmitry Safonov xtr = rcu_dereference(xfrm_translator); 2277c9e7c76dSDmitry Safonov if (unlikely(!xtr)) 2278c9e7c76dSDmitry Safonov goto out; 2279c9e7c76dSDmitry Safonov if (!try_module_get(xtr->owner)) 2280c9e7c76dSDmitry Safonov xtr = NULL; 2281c9e7c76dSDmitry Safonov out: 2282c9e7c76dSDmitry Safonov rcu_read_unlock(); 2283c9e7c76dSDmitry Safonov return xtr; 2284c9e7c76dSDmitry Safonov } 2285c9e7c76dSDmitry Safonov EXPORT_SYMBOL_GPL(xfrm_get_translator); 2286c9e7c76dSDmitry Safonov 2287c9e7c76dSDmitry Safonov void xfrm_put_translator(struct xfrm_translator *xtr) 2288c9e7c76dSDmitry Safonov { 2289c9e7c76dSDmitry Safonov module_put(xtr->owner); 2290c9e7c76dSDmitry Safonov } 2291c9e7c76dSDmitry Safonov EXPORT_SYMBOL_GPL(xfrm_put_translator); 2292c9e7c76dSDmitry Safonov 2293c9e7c76dSDmitry Safonov int xfrm_register_translator(struct xfrm_translator *xtr) 2294c9e7c76dSDmitry Safonov { 2295c9e7c76dSDmitry Safonov int err = 0; 2296c9e7c76dSDmitry Safonov 2297c9e7c76dSDmitry Safonov spin_lock_bh(&xfrm_translator_lock); 2298c9e7c76dSDmitry Safonov if (unlikely(xfrm_translator != NULL)) 2299c9e7c76dSDmitry Safonov err = -EEXIST; 2300c9e7c76dSDmitry Safonov else 2301c9e7c76dSDmitry Safonov rcu_assign_pointer(xfrm_translator, xtr); 2302c9e7c76dSDmitry Safonov spin_unlock_bh(&xfrm_translator_lock); 2303c9e7c76dSDmitry Safonov 2304c9e7c76dSDmitry Safonov return err; 2305c9e7c76dSDmitry Safonov } 2306c9e7c76dSDmitry Safonov EXPORT_SYMBOL_GPL(xfrm_register_translator); 2307c9e7c76dSDmitry Safonov 2308c9e7c76dSDmitry Safonov int xfrm_unregister_translator(struct xfrm_translator *xtr) 2309c9e7c76dSDmitry Safonov { 2310c9e7c76dSDmitry Safonov int err = 0; 2311c9e7c76dSDmitry Safonov 2312c9e7c76dSDmitry Safonov spin_lock_bh(&xfrm_translator_lock); 2313c9e7c76dSDmitry Safonov if (likely(xfrm_translator != NULL)) { 2314c9e7c76dSDmitry Safonov if (rcu_access_pointer(xfrm_translator) != xtr) 2315c9e7c76dSDmitry Safonov err = -EINVAL; 2316c9e7c76dSDmitry Safonov else 2317c9e7c76dSDmitry Safonov RCU_INIT_POINTER(xfrm_translator, NULL); 2318c9e7c76dSDmitry Safonov } 2319c9e7c76dSDmitry Safonov spin_unlock_bh(&xfrm_translator_lock); 2320c9e7c76dSDmitry Safonov synchronize_rcu(); 2321c9e7c76dSDmitry Safonov 2322c9e7c76dSDmitry Safonov return err; 2323c9e7c76dSDmitry Safonov } 2324c9e7c76dSDmitry Safonov EXPORT_SYMBOL_GPL(xfrm_unregister_translator); 2325c9e7c76dSDmitry Safonov #endif 2326c9e7c76dSDmitry Safonov 2327c6d1b26aSChristoph Hellwig int xfrm_user_policy(struct sock *sk, int optname, sockptr_t optval, int optlen) 23281da177e4SLinus Torvalds { 23291da177e4SLinus Torvalds int err; 23301da177e4SLinus Torvalds u8 *data; 23311da177e4SLinus Torvalds struct xfrm_mgr *km; 23321da177e4SLinus Torvalds struct xfrm_policy *pol = NULL; 23331da177e4SLinus Torvalds 233419d7df69SSteffen Klassert if (in_compat_syscall()) 233519d7df69SSteffen Klassert return -EOPNOTSUPP; 233619d7df69SSteffen Klassert 2337c6d1b26aSChristoph Hellwig if (sockptr_is_null(optval) && !optlen) { 2338be8f8284SLorenzo Colitti xfrm_sk_policy_insert(sk, XFRM_POLICY_IN, NULL); 2339be8f8284SLorenzo Colitti xfrm_sk_policy_insert(sk, XFRM_POLICY_OUT, NULL); 2340be8f8284SLorenzo Colitti __sk_dst_reset(sk); 2341be8f8284SLorenzo Colitti return 0; 2342be8f8284SLorenzo Colitti } 2343be8f8284SLorenzo Colitti 23441da177e4SLinus Torvalds if (optlen <= 0 || optlen > PAGE_SIZE) 23451da177e4SLinus Torvalds return -EMSGSIZE; 23461da177e4SLinus Torvalds 2347c6d1b26aSChristoph Hellwig data = memdup_sockptr(optval, optlen); 2348a133d930SGeliang Tang if (IS_ERR(data)) 2349a133d930SGeliang Tang return PTR_ERR(data); 23501da177e4SLinus Torvalds 23511da177e4SLinus Torvalds err = -EINVAL; 235285168c00SCong Wang rcu_read_lock(); 235385168c00SCong Wang list_for_each_entry_rcu(km, &xfrm_km_list, list) { 2354cb969f07SVenkat Yekkirala pol = km->compile_policy(sk, optname, data, 23551da177e4SLinus Torvalds optlen, &err); 23561da177e4SLinus Torvalds if (err >= 0) 23571da177e4SLinus Torvalds break; 23581da177e4SLinus Torvalds } 235985168c00SCong Wang rcu_read_unlock(); 23601da177e4SLinus Torvalds 23611da177e4SLinus Torvalds if (err >= 0) { 23621da177e4SLinus Torvalds xfrm_sk_policy_insert(sk, err, pol); 23631da177e4SLinus Torvalds xfrm_pol_put(pol); 23642b06cdf3SJonathan Basseri __sk_dst_reset(sk); 23651da177e4SLinus Torvalds err = 0; 23661da177e4SLinus Torvalds } 23671da177e4SLinus Torvalds 23681da177e4SLinus Torvalds kfree(data); 23691da177e4SLinus Torvalds return err; 23701da177e4SLinus Torvalds } 23711da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_user_policy); 23721da177e4SLinus Torvalds 237385168c00SCong Wang static DEFINE_SPINLOCK(xfrm_km_lock); 237485168c00SCong Wang 23751da177e4SLinus Torvalds int xfrm_register_km(struct xfrm_mgr *km) 23761da177e4SLinus Torvalds { 237785168c00SCong Wang spin_lock_bh(&xfrm_km_lock); 237885168c00SCong Wang list_add_tail_rcu(&km->list, &xfrm_km_list); 237985168c00SCong Wang spin_unlock_bh(&xfrm_km_lock); 23801da177e4SLinus Torvalds return 0; 23811da177e4SLinus Torvalds } 23821da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_register_km); 23831da177e4SLinus Torvalds 23841da177e4SLinus Torvalds int xfrm_unregister_km(struct xfrm_mgr *km) 23851da177e4SLinus Torvalds { 238685168c00SCong Wang spin_lock_bh(&xfrm_km_lock); 238785168c00SCong Wang list_del_rcu(&km->list); 238885168c00SCong Wang spin_unlock_bh(&xfrm_km_lock); 238985168c00SCong Wang synchronize_rcu(); 23901da177e4SLinus Torvalds return 0; 23911da177e4SLinus Torvalds } 23921da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_unregister_km); 23931da177e4SLinus Torvalds 23941da177e4SLinus Torvalds int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo) 23951da177e4SLinus Torvalds { 23961da177e4SLinus Torvalds int err = 0; 2397423826a7SFlorian Westphal 2398423826a7SFlorian Westphal if (WARN_ON(afinfo->family >= NPROTO)) 23991da177e4SLinus Torvalds return -EAFNOSUPPORT; 2400423826a7SFlorian Westphal 240144abdc30SCong Wang spin_lock_bh(&xfrm_state_afinfo_lock); 24021da177e4SLinus Torvalds if (unlikely(xfrm_state_afinfo[afinfo->family] != NULL)) 2403f31e8d4fSLi RongQing err = -EEXIST; 2404edcd5821SDavid S. Miller else 240544abdc30SCong Wang rcu_assign_pointer(xfrm_state_afinfo[afinfo->family], afinfo); 240644abdc30SCong Wang spin_unlock_bh(&xfrm_state_afinfo_lock); 24071da177e4SLinus Torvalds return err; 24081da177e4SLinus Torvalds } 24091da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_register_afinfo); 24101da177e4SLinus Torvalds 24111da177e4SLinus Torvalds int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo) 24121da177e4SLinus Torvalds { 2413423826a7SFlorian Westphal int err = 0, family = afinfo->family; 2414423826a7SFlorian Westphal 2415423826a7SFlorian Westphal if (WARN_ON(family >= NPROTO)) 24161da177e4SLinus Torvalds return -EAFNOSUPPORT; 2417423826a7SFlorian Westphal 241844abdc30SCong Wang spin_lock_bh(&xfrm_state_afinfo_lock); 24191da177e4SLinus Torvalds if (likely(xfrm_state_afinfo[afinfo->family] != NULL)) { 2420423826a7SFlorian Westphal if (rcu_access_pointer(xfrm_state_afinfo[family]) != afinfo) 24211da177e4SLinus Torvalds err = -EINVAL; 2422edcd5821SDavid S. Miller else 242344abdc30SCong Wang RCU_INIT_POINTER(xfrm_state_afinfo[afinfo->family], NULL); 24241da177e4SLinus Torvalds } 242544abdc30SCong Wang spin_unlock_bh(&xfrm_state_afinfo_lock); 242644abdc30SCong Wang synchronize_rcu(); 24271da177e4SLinus Torvalds return err; 24281da177e4SLinus Torvalds } 24291da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_unregister_afinfo); 24301da177e4SLinus Torvalds 2431711059b9SFlorian Westphal struct xfrm_state_afinfo *xfrm_state_afinfo_get_rcu(unsigned int family) 2432711059b9SFlorian Westphal { 2433711059b9SFlorian Westphal if (unlikely(family >= NPROTO)) 2434711059b9SFlorian Westphal return NULL; 2435711059b9SFlorian Westphal 2436711059b9SFlorian Westphal return rcu_dereference(xfrm_state_afinfo[family]); 2437711059b9SFlorian Westphal } 2438733a5facSFlorian Westphal EXPORT_SYMBOL_GPL(xfrm_state_afinfo_get_rcu); 2439711059b9SFlorian Westphal 2440628e341fSHannes Frederic Sowa struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family) 24411da177e4SLinus Torvalds { 24421da177e4SLinus Torvalds struct xfrm_state_afinfo *afinfo; 24431da177e4SLinus Torvalds if (unlikely(family >= NPROTO)) 24441da177e4SLinus Torvalds return NULL; 244544abdc30SCong Wang rcu_read_lock(); 244644abdc30SCong Wang afinfo = rcu_dereference(xfrm_state_afinfo[family]); 2447546be240SHerbert Xu if (unlikely(!afinfo)) 244844abdc30SCong Wang rcu_read_unlock(); 24491da177e4SLinus Torvalds return afinfo; 24501da177e4SLinus Torvalds } 24511da177e4SLinus Torvalds 2452b48c05abSSteffen Klassert void xfrm_flush_gc(void) 2453b48c05abSSteffen Klassert { 2454b48c05abSSteffen Klassert flush_work(&xfrm_state_gc_work); 2455b48c05abSSteffen Klassert } 2456b48c05abSSteffen Klassert EXPORT_SYMBOL(xfrm_flush_gc); 2457b48c05abSSteffen Klassert 24581da177e4SLinus Torvalds /* Temporarily located here until net/xfrm/xfrm_tunnel.c is created */ 24591da177e4SLinus Torvalds void xfrm_state_delete_tunnel(struct xfrm_state *x) 24601da177e4SLinus Torvalds { 24611da177e4SLinus Torvalds if (x->tunnel) { 24621da177e4SLinus Torvalds struct xfrm_state *t = x->tunnel; 24631da177e4SLinus Torvalds 24641da177e4SLinus Torvalds if (atomic_read(&t->tunnel_users) == 2) 24651da177e4SLinus Torvalds xfrm_state_delete(t); 24661da177e4SLinus Torvalds atomic_dec(&t->tunnel_users); 2467f75a2804SCong Wang xfrm_state_put_sync(t); 24681da177e4SLinus Torvalds x->tunnel = NULL; 24691da177e4SLinus Torvalds } 24701da177e4SLinus Torvalds } 24711da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_delete_tunnel); 24721da177e4SLinus Torvalds 2473c7b37c76SFlorian Westphal u32 xfrm_state_mtu(struct xfrm_state *x, int mtu) 24741da177e4SLinus Torvalds { 2475b3b73b8eSFlorian Westphal const struct xfrm_type *type = READ_ONCE(x->type); 2476c7b37c76SFlorian Westphal struct crypto_aead *aead; 2477c7b37c76SFlorian Westphal u32 blksize, net_adj = 0; 24781da177e4SLinus Torvalds 2479c7b37c76SFlorian Westphal if (x->km.state != XFRM_STATE_VALID || 2480c7b37c76SFlorian Westphal !type || type->proto != IPPROTO_ESP) 2481b3b73b8eSFlorian Westphal return mtu - x->props.header_len; 2482c7b37c76SFlorian Westphal 2483c7b37c76SFlorian Westphal aead = x->data; 2484c7b37c76SFlorian Westphal blksize = ALIGN(crypto_aead_blocksize(aead), 4); 2485c7b37c76SFlorian Westphal 2486c7b37c76SFlorian Westphal switch (x->props.mode) { 2487c7b37c76SFlorian Westphal case XFRM_MODE_TRANSPORT: 2488c7b37c76SFlorian Westphal case XFRM_MODE_BEET: 2489c7b37c76SFlorian Westphal if (x->props.family == AF_INET) 2490c7b37c76SFlorian Westphal net_adj = sizeof(struct iphdr); 2491c7b37c76SFlorian Westphal else if (x->props.family == AF_INET6) 2492c7b37c76SFlorian Westphal net_adj = sizeof(struct ipv6hdr); 2493c7b37c76SFlorian Westphal break; 2494c7b37c76SFlorian Westphal case XFRM_MODE_TUNNEL: 2495c7b37c76SFlorian Westphal break; 2496c7b37c76SFlorian Westphal default: 2497c7b37c76SFlorian Westphal WARN_ON_ONCE(1); 2498c7b37c76SFlorian Westphal break; 24991da177e4SLinus Torvalds } 25001da177e4SLinus Torvalds 2501c7b37c76SFlorian Westphal return ((mtu - x->props.header_len - crypto_aead_authsize(aead) - 2502c7b37c76SFlorian Westphal net_adj) & ~(blksize - 1)) + net_adj - 2; 2503c7b37c76SFlorian Westphal } 2504c7b37c76SFlorian Westphal EXPORT_SYMBOL_GPL(xfrm_state_mtu); 2505c7b37c76SFlorian Westphal 2506ffdb5211SIlan Tayari int __xfrm_init_state(struct xfrm_state *x, bool init_replay, bool offload) 250772cb6962SHerbert Xu { 2508c9500d7bSFlorian Westphal const struct xfrm_mode *inner_mode; 2509c9500d7bSFlorian Westphal const struct xfrm_mode *outer_mode; 2510d094cd83SHerbert Xu int family = x->props.family; 251172cb6962SHerbert Xu int err; 251272cb6962SHerbert Xu 2513e4681747SFlorian Westphal if (family == AF_INET && 2514e4681747SFlorian Westphal xs_net(x)->ipv4.sysctl_ip_no_pmtu_disc) 2515e4681747SFlorian Westphal x->props.flags |= XFRM_STATE_NOPMTUDISC; 2516d094cd83SHerbert Xu 2517d094cd83SHerbert Xu err = -EPROTONOSUPPORT; 2518df9dcb45SKazunori MIYAZAWA 2519df9dcb45SKazunori MIYAZAWA if (x->sel.family != AF_UNSPEC) { 2520df9dcb45SKazunori MIYAZAWA inner_mode = xfrm_get_mode(x->props.mode, x->sel.family); 2521df9dcb45SKazunori MIYAZAWA if (inner_mode == NULL) 252213996378SHerbert Xu goto error; 252313996378SHerbert Xu 2524df9dcb45SKazunori MIYAZAWA if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL) && 25254c145dceSFlorian Westphal family != x->sel.family) 252613996378SHerbert Xu goto error; 2527df9dcb45SKazunori MIYAZAWA 2528c9500d7bSFlorian Westphal x->inner_mode = *inner_mode; 2529df9dcb45SKazunori MIYAZAWA } else { 25304c145dceSFlorian Westphal const struct xfrm_mode *inner_mode_iaf; 2531d81d2285SMartin Willi int iafamily = AF_INET; 2532df9dcb45SKazunori MIYAZAWA 2533d81d2285SMartin Willi inner_mode = xfrm_get_mode(x->props.mode, x->props.family); 2534df9dcb45SKazunori MIYAZAWA if (inner_mode == NULL) 2535df9dcb45SKazunori MIYAZAWA goto error; 2536df9dcb45SKazunori MIYAZAWA 25374c145dceSFlorian Westphal if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL)) 2538df9dcb45SKazunori MIYAZAWA goto error; 25394c145dceSFlorian Westphal 2540c9500d7bSFlorian Westphal x->inner_mode = *inner_mode; 2541d81d2285SMartin Willi 2542d81d2285SMartin Willi if (x->props.family == AF_INET) 2543d81d2285SMartin Willi iafamily = AF_INET6; 2544d81d2285SMartin Willi 2545d81d2285SMartin Willi inner_mode_iaf = xfrm_get_mode(x->props.mode, iafamily); 2546d81d2285SMartin Willi if (inner_mode_iaf) { 2547d81d2285SMartin Willi if (inner_mode_iaf->flags & XFRM_MODE_FLAG_TUNNEL) 2548c9500d7bSFlorian Westphal x->inner_mode_iaf = *inner_mode_iaf; 2549df9dcb45SKazunori MIYAZAWA } 2550df9dcb45SKazunori MIYAZAWA } 255113996378SHerbert Xu 2552d094cd83SHerbert Xu x->type = xfrm_get_type(x->id.proto, family); 255372cb6962SHerbert Xu if (x->type == NULL) 255472cb6962SHerbert Xu goto error; 255572cb6962SHerbert Xu 2556ffdb5211SIlan Tayari x->type_offload = xfrm_get_type_offload(x->id.proto, family, offload); 25579d389d7fSSteffen Klassert 255872cb6962SHerbert Xu err = x->type->init_state(x); 255972cb6962SHerbert Xu if (err) 256072cb6962SHerbert Xu goto error; 256172cb6962SHerbert Xu 2562c9500d7bSFlorian Westphal outer_mode = xfrm_get_mode(x->props.mode, family); 2563c9500d7bSFlorian Westphal if (!outer_mode) { 2564599901c3SJulia Lawall err = -EPROTONOSUPPORT; 2565b59f45d0SHerbert Xu goto error; 2566599901c3SJulia Lawall } 2567b59f45d0SHerbert Xu 2568c9500d7bSFlorian Westphal x->outer_mode = *outer_mode; 2569a454f0ccSWei Yongjun if (init_replay) { 2570a454f0ccSWei Yongjun err = xfrm_init_replay(x); 2571a454f0ccSWei Yongjun if (err) 2572a454f0ccSWei Yongjun goto error; 2573a454f0ccSWei Yongjun } 2574a454f0ccSWei Yongjun 257572cb6962SHerbert Xu error: 257672cb6962SHerbert Xu return err; 257772cb6962SHerbert Xu } 257872cb6962SHerbert Xu 2579a454f0ccSWei Yongjun EXPORT_SYMBOL(__xfrm_init_state); 2580a454f0ccSWei Yongjun 2581a454f0ccSWei Yongjun int xfrm_init_state(struct xfrm_state *x) 2582a454f0ccSWei Yongjun { 2583cc01572eSYossi Kuperman int err; 2584cc01572eSYossi Kuperman 2585cc01572eSYossi Kuperman err = __xfrm_init_state(x, true, false); 2586cc01572eSYossi Kuperman if (!err) 2587cc01572eSYossi Kuperman x->km.state = XFRM_STATE_VALID; 2588cc01572eSYossi Kuperman 2589cc01572eSYossi Kuperman return err; 2590a454f0ccSWei Yongjun } 2591a454f0ccSWei Yongjun 259272cb6962SHerbert Xu EXPORT_SYMBOL(xfrm_init_state); 25931da177e4SLinus Torvalds 2594d62ddc21SAlexey Dobriyan int __net_init xfrm_state_init(struct net *net) 25951da177e4SLinus Torvalds { 2596f034b5d4SDavid S. Miller unsigned int sz; 25971da177e4SLinus Torvalds 2598565f0fa9SMathias Krause if (net_eq(net, &init_net)) 2599565f0fa9SMathias Krause xfrm_state_cache = KMEM_CACHE(xfrm_state, 2600565f0fa9SMathias Krause SLAB_HWCACHE_ALIGN | SLAB_PANIC); 2601565f0fa9SMathias Krause 26029d4139c7SAlexey Dobriyan INIT_LIST_HEAD(&net->xfrm.state_all); 26039d4139c7SAlexey Dobriyan 2604f034b5d4SDavid S. Miller sz = sizeof(struct hlist_head) * 8; 2605f034b5d4SDavid S. Miller 260673d189dcSAlexey Dobriyan net->xfrm.state_bydst = xfrm_hash_alloc(sz); 260773d189dcSAlexey Dobriyan if (!net->xfrm.state_bydst) 260873d189dcSAlexey Dobriyan goto out_bydst; 2609d320bbb3SAlexey Dobriyan net->xfrm.state_bysrc = xfrm_hash_alloc(sz); 2610d320bbb3SAlexey Dobriyan if (!net->xfrm.state_bysrc) 2611d320bbb3SAlexey Dobriyan goto out_bysrc; 2612b754a4fdSAlexey Dobriyan net->xfrm.state_byspi = xfrm_hash_alloc(sz); 2613b754a4fdSAlexey Dobriyan if (!net->xfrm.state_byspi) 2614b754a4fdSAlexey Dobriyan goto out_byspi; 2615529983ecSAlexey Dobriyan net->xfrm.state_hmask = ((sz / sizeof(struct hlist_head)) - 1); 2616f034b5d4SDavid S. Miller 26170bf7c5b0SAlexey Dobriyan net->xfrm.state_num = 0; 261863082733SAlexey Dobriyan INIT_WORK(&net->xfrm.state_hash_work, xfrm_hash_resize); 2619283bc9f3SFan Du spin_lock_init(&net->xfrm.xfrm_state_lock); 2620d62ddc21SAlexey Dobriyan return 0; 262173d189dcSAlexey Dobriyan 2622b754a4fdSAlexey Dobriyan out_byspi: 2623b754a4fdSAlexey Dobriyan xfrm_hash_free(net->xfrm.state_bysrc, sz); 2624d320bbb3SAlexey Dobriyan out_bysrc: 2625d320bbb3SAlexey Dobriyan xfrm_hash_free(net->xfrm.state_bydst, sz); 262673d189dcSAlexey Dobriyan out_bydst: 262773d189dcSAlexey Dobriyan return -ENOMEM; 2628d62ddc21SAlexey Dobriyan } 2629d62ddc21SAlexey Dobriyan 2630d62ddc21SAlexey Dobriyan void xfrm_state_fini(struct net *net) 2631d62ddc21SAlexey Dobriyan { 263273d189dcSAlexey Dobriyan unsigned int sz; 263373d189dcSAlexey Dobriyan 26347c2776eeSAlexey Dobriyan flush_work(&net->xfrm.state_hash_work); 263535db57bbSFlorian Westphal flush_work(&xfrm_state_gc_work); 2636dbb2483bSCong Wang xfrm_state_flush(net, 0, false, true); 26377c2776eeSAlexey Dobriyan 26389d4139c7SAlexey Dobriyan WARN_ON(!list_empty(&net->xfrm.state_all)); 263973d189dcSAlexey Dobriyan 2640529983ecSAlexey Dobriyan sz = (net->xfrm.state_hmask + 1) * sizeof(struct hlist_head); 2641b754a4fdSAlexey Dobriyan WARN_ON(!hlist_empty(net->xfrm.state_byspi)); 2642b754a4fdSAlexey Dobriyan xfrm_hash_free(net->xfrm.state_byspi, sz); 2643d320bbb3SAlexey Dobriyan WARN_ON(!hlist_empty(net->xfrm.state_bysrc)); 2644d320bbb3SAlexey Dobriyan xfrm_hash_free(net->xfrm.state_bysrc, sz); 264573d189dcSAlexey Dobriyan WARN_ON(!hlist_empty(net->xfrm.state_bydst)); 264673d189dcSAlexey Dobriyan xfrm_hash_free(net->xfrm.state_bydst, sz); 26471da177e4SLinus Torvalds } 26481da177e4SLinus Torvalds 2649ab5f5e8bSJoy Latten #ifdef CONFIG_AUDITSYSCALL 2650cf35f43eSIlpo Järvinen static void xfrm_audit_helper_sainfo(struct xfrm_state *x, 2651ab5f5e8bSJoy Latten struct audit_buffer *audit_buf) 2652ab5f5e8bSJoy Latten { 265368277accSPaul Moore struct xfrm_sec_ctx *ctx = x->security; 265468277accSPaul Moore u32 spi = ntohl(x->id.spi); 265568277accSPaul Moore 265668277accSPaul Moore if (ctx) 2657ab5f5e8bSJoy Latten audit_log_format(audit_buf, " sec_alg=%u sec_doi=%u sec_obj=%s", 265868277accSPaul Moore ctx->ctx_alg, ctx->ctx_doi, ctx->ctx_str); 2659ab5f5e8bSJoy Latten 2660ab5f5e8bSJoy Latten switch (x->props.family) { 2661ab5f5e8bSJoy Latten case AF_INET: 266221454aaaSHarvey Harrison audit_log_format(audit_buf, " src=%pI4 dst=%pI4", 266321454aaaSHarvey Harrison &x->props.saddr.a4, &x->id.daddr.a4); 2664ab5f5e8bSJoy Latten break; 2665ab5f5e8bSJoy Latten case AF_INET6: 26665b095d98SHarvey Harrison audit_log_format(audit_buf, " src=%pI6 dst=%pI6", 2667fdb46ee7SHarvey Harrison x->props.saddr.a6, x->id.daddr.a6); 2668ab5f5e8bSJoy Latten break; 2669ab5f5e8bSJoy Latten } 267068277accSPaul Moore 267168277accSPaul Moore audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi); 2672ab5f5e8bSJoy Latten } 2673ab5f5e8bSJoy Latten 2674cf35f43eSIlpo Järvinen static void xfrm_audit_helper_pktinfo(struct sk_buff *skb, u16 family, 2675afeb14b4SPaul Moore struct audit_buffer *audit_buf) 2676afeb14b4SPaul Moore { 2677b71d1d42SEric Dumazet const struct iphdr *iph4; 2678b71d1d42SEric Dumazet const struct ipv6hdr *iph6; 2679afeb14b4SPaul Moore 2680afeb14b4SPaul Moore switch (family) { 2681afeb14b4SPaul Moore case AF_INET: 2682afeb14b4SPaul Moore iph4 = ip_hdr(skb); 268321454aaaSHarvey Harrison audit_log_format(audit_buf, " src=%pI4 dst=%pI4", 268421454aaaSHarvey Harrison &iph4->saddr, &iph4->daddr); 2685afeb14b4SPaul Moore break; 2686afeb14b4SPaul Moore case AF_INET6: 2687afeb14b4SPaul Moore iph6 = ipv6_hdr(skb); 2688afeb14b4SPaul Moore audit_log_format(audit_buf, 26895b095d98SHarvey Harrison " src=%pI6 dst=%pI6 flowlbl=0x%x%02x%02x", 2690fdb46ee7SHarvey Harrison &iph6->saddr, &iph6->daddr, 2691afeb14b4SPaul Moore iph6->flow_lbl[0] & 0x0f, 2692afeb14b4SPaul Moore iph6->flow_lbl[1], 2693afeb14b4SPaul Moore iph6->flow_lbl[2]); 2694afeb14b4SPaul Moore break; 2695afeb14b4SPaul Moore } 2696afeb14b4SPaul Moore } 2697afeb14b4SPaul Moore 26982e71029eSTetsuo Handa void xfrm_audit_state_add(struct xfrm_state *x, int result, bool task_valid) 2699ab5f5e8bSJoy Latten { 2700ab5f5e8bSJoy Latten struct audit_buffer *audit_buf; 2701ab5f5e8bSJoy Latten 2702afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SAD-add"); 2703ab5f5e8bSJoy Latten if (audit_buf == NULL) 2704ab5f5e8bSJoy Latten return; 27052e71029eSTetsuo Handa xfrm_audit_helper_usrinfo(task_valid, audit_buf); 2706afeb14b4SPaul Moore xfrm_audit_helper_sainfo(x, audit_buf); 2707afeb14b4SPaul Moore audit_log_format(audit_buf, " res=%u", result); 2708ab5f5e8bSJoy Latten audit_log_end(audit_buf); 2709ab5f5e8bSJoy Latten } 2710ab5f5e8bSJoy Latten EXPORT_SYMBOL_GPL(xfrm_audit_state_add); 2711ab5f5e8bSJoy Latten 27122e71029eSTetsuo Handa void xfrm_audit_state_delete(struct xfrm_state *x, int result, bool task_valid) 2713ab5f5e8bSJoy Latten { 2714ab5f5e8bSJoy Latten struct audit_buffer *audit_buf; 2715ab5f5e8bSJoy Latten 2716afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SAD-delete"); 2717ab5f5e8bSJoy Latten if (audit_buf == NULL) 2718ab5f5e8bSJoy Latten return; 27192e71029eSTetsuo Handa xfrm_audit_helper_usrinfo(task_valid, audit_buf); 2720afeb14b4SPaul Moore xfrm_audit_helper_sainfo(x, audit_buf); 2721afeb14b4SPaul Moore audit_log_format(audit_buf, " res=%u", result); 2722ab5f5e8bSJoy Latten audit_log_end(audit_buf); 2723ab5f5e8bSJoy Latten } 2724ab5f5e8bSJoy Latten EXPORT_SYMBOL_GPL(xfrm_audit_state_delete); 2725afeb14b4SPaul Moore 2726afeb14b4SPaul Moore void xfrm_audit_state_replay_overflow(struct xfrm_state *x, 2727afeb14b4SPaul Moore struct sk_buff *skb) 2728afeb14b4SPaul Moore { 2729afeb14b4SPaul Moore struct audit_buffer *audit_buf; 2730afeb14b4SPaul Moore u32 spi; 2731afeb14b4SPaul Moore 2732afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SA-replay-overflow"); 2733afeb14b4SPaul Moore if (audit_buf == NULL) 2734afeb14b4SPaul Moore return; 2735afeb14b4SPaul Moore xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf); 2736afeb14b4SPaul Moore /* don't record the sequence number because it's inherent in this kind 2737afeb14b4SPaul Moore * of audit message */ 2738afeb14b4SPaul Moore spi = ntohl(x->id.spi); 2739afeb14b4SPaul Moore audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi); 2740afeb14b4SPaul Moore audit_log_end(audit_buf); 2741afeb14b4SPaul Moore } 2742afeb14b4SPaul Moore EXPORT_SYMBOL_GPL(xfrm_audit_state_replay_overflow); 2743afeb14b4SPaul Moore 27449fdc4883SSteffen Klassert void xfrm_audit_state_replay(struct xfrm_state *x, 2745afeb14b4SPaul Moore struct sk_buff *skb, __be32 net_seq) 2746afeb14b4SPaul Moore { 2747afeb14b4SPaul Moore struct audit_buffer *audit_buf; 2748afeb14b4SPaul Moore u32 spi; 2749afeb14b4SPaul Moore 2750afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SA-replayed-pkt"); 2751afeb14b4SPaul Moore if (audit_buf == NULL) 2752afeb14b4SPaul Moore return; 2753afeb14b4SPaul Moore xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf); 2754afeb14b4SPaul Moore spi = ntohl(x->id.spi); 2755afeb14b4SPaul Moore audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u", 2756afeb14b4SPaul Moore spi, spi, ntohl(net_seq)); 2757afeb14b4SPaul Moore audit_log_end(audit_buf); 2758afeb14b4SPaul Moore } 27599fdc4883SSteffen Klassert EXPORT_SYMBOL_GPL(xfrm_audit_state_replay); 2760afeb14b4SPaul Moore 2761afeb14b4SPaul Moore void xfrm_audit_state_notfound_simple(struct sk_buff *skb, u16 family) 2762afeb14b4SPaul Moore { 2763afeb14b4SPaul Moore struct audit_buffer *audit_buf; 2764afeb14b4SPaul Moore 2765afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SA-notfound"); 2766afeb14b4SPaul Moore if (audit_buf == NULL) 2767afeb14b4SPaul Moore return; 2768afeb14b4SPaul Moore xfrm_audit_helper_pktinfo(skb, family, audit_buf); 2769afeb14b4SPaul Moore audit_log_end(audit_buf); 2770afeb14b4SPaul Moore } 2771afeb14b4SPaul Moore EXPORT_SYMBOL_GPL(xfrm_audit_state_notfound_simple); 2772afeb14b4SPaul Moore 2773afeb14b4SPaul Moore void xfrm_audit_state_notfound(struct sk_buff *skb, u16 family, 2774afeb14b4SPaul Moore __be32 net_spi, __be32 net_seq) 2775afeb14b4SPaul Moore { 2776afeb14b4SPaul Moore struct audit_buffer *audit_buf; 2777afeb14b4SPaul Moore u32 spi; 2778afeb14b4SPaul Moore 2779afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SA-notfound"); 2780afeb14b4SPaul Moore if (audit_buf == NULL) 2781afeb14b4SPaul Moore return; 2782afeb14b4SPaul Moore xfrm_audit_helper_pktinfo(skb, family, audit_buf); 2783afeb14b4SPaul Moore spi = ntohl(net_spi); 2784afeb14b4SPaul Moore audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u", 2785afeb14b4SPaul Moore spi, spi, ntohl(net_seq)); 2786afeb14b4SPaul Moore audit_log_end(audit_buf); 2787afeb14b4SPaul Moore } 2788afeb14b4SPaul Moore EXPORT_SYMBOL_GPL(xfrm_audit_state_notfound); 2789afeb14b4SPaul Moore 2790afeb14b4SPaul Moore void xfrm_audit_state_icvfail(struct xfrm_state *x, 2791afeb14b4SPaul Moore struct sk_buff *skb, u8 proto) 2792afeb14b4SPaul Moore { 2793afeb14b4SPaul Moore struct audit_buffer *audit_buf; 2794afeb14b4SPaul Moore __be32 net_spi; 2795afeb14b4SPaul Moore __be32 net_seq; 2796afeb14b4SPaul Moore 2797afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SA-icv-failure"); 2798afeb14b4SPaul Moore if (audit_buf == NULL) 2799afeb14b4SPaul Moore return; 2800afeb14b4SPaul Moore xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf); 2801afeb14b4SPaul Moore if (xfrm_parse_spi(skb, proto, &net_spi, &net_seq) == 0) { 2802afeb14b4SPaul Moore u32 spi = ntohl(net_spi); 2803afeb14b4SPaul Moore audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u", 2804afeb14b4SPaul Moore spi, spi, ntohl(net_seq)); 2805afeb14b4SPaul Moore } 2806afeb14b4SPaul Moore audit_log_end(audit_buf); 2807afeb14b4SPaul Moore } 2808afeb14b4SPaul Moore EXPORT_SYMBOL_GPL(xfrm_audit_state_icvfail); 2809ab5f5e8bSJoy Latten #endif /* CONFIG_AUDITSYSCALL */ 2810