11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * xfrm_state.c 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Changes: 51da177e4SLinus Torvalds * Mitsuru KANDA @USAGI 61da177e4SLinus Torvalds * Kazunori MIYAZAWA @USAGI 71da177e4SLinus Torvalds * Kunihiro Ishiguro <kunihiro@ipinfusion.com> 81da177e4SLinus Torvalds * IPv6 support 91da177e4SLinus Torvalds * YOSHIFUJI Hideaki @USAGI 101da177e4SLinus Torvalds * Split up af-specific functions 111da177e4SLinus Torvalds * Derek Atkins <derek@ihtfp.com> 121da177e4SLinus Torvalds * Add UDP Encapsulation 131da177e4SLinus Torvalds * 141da177e4SLinus Torvalds */ 151da177e4SLinus Torvalds 161da177e4SLinus Torvalds #include <linux/workqueue.h> 171da177e4SLinus Torvalds #include <net/xfrm.h> 181da177e4SLinus Torvalds #include <linux/pfkeyv2.h> 191da177e4SLinus Torvalds #include <linux/ipsec.h> 201da177e4SLinus Torvalds #include <linux/module.h> 21f034b5d4SDavid S. Miller #include <linux/cache.h> 2268277accSPaul Moore #include <linux/audit.h> 23b5890d8bSJesper Juhl #include <asm/uaccess.h> 241da177e4SLinus Torvalds 2544e36b42SDavid S. Miller #include "xfrm_hash.h" 2644e36b42SDavid S. Miller 27ee857a7dSDavid S. Miller struct sock *xfrm_nl; 28ee857a7dSDavid S. Miller EXPORT_SYMBOL(xfrm_nl); 29ee857a7dSDavid S. Miller 3001e67d08SDavid S. Miller u32 sysctl_xfrm_aevent_etime __read_mostly = XFRM_AE_ETIME; 31a70fcb0bSDavid S. Miller EXPORT_SYMBOL(sysctl_xfrm_aevent_etime); 32a70fcb0bSDavid S. Miller 3301e67d08SDavid S. Miller u32 sysctl_xfrm_aevent_rseqth __read_mostly = XFRM_AE_SEQT_SIZE; 34a70fcb0bSDavid S. Miller EXPORT_SYMBOL(sysctl_xfrm_aevent_rseqth); 35a70fcb0bSDavid S. Miller 3601e67d08SDavid S. Miller u32 sysctl_xfrm_acq_expires __read_mostly = 30; 3701e67d08SDavid S. Miller 381da177e4SLinus Torvalds /* Each xfrm_state may be linked to two tables: 391da177e4SLinus Torvalds 401da177e4SLinus Torvalds 1. Hash table by (spi,daddr,ah/esp) to find SA by SPI. (input,ctl) 41a624c108SDavid S. Miller 2. Hash table by (daddr,family,reqid) to find what SAs exist for given 421da177e4SLinus Torvalds destination/tunnel endpoint. (output) 431da177e4SLinus Torvalds */ 441da177e4SLinus Torvalds 451da177e4SLinus Torvalds static DEFINE_SPINLOCK(xfrm_state_lock); 461da177e4SLinus Torvalds 47f034b5d4SDavid S. Miller static unsigned int xfrm_state_hmask __read_mostly; 48f034b5d4SDavid S. Miller static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024; 49f034b5d4SDavid S. Miller static unsigned int xfrm_state_num; 509d4a706dSDavid S. Miller static unsigned int xfrm_state_genid; 511da177e4SLinus Torvalds 5217c2a42aSHerbert Xu static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family); 5317c2a42aSHerbert Xu static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo); 5417c2a42aSHerbert Xu 55afeb14b4SPaul Moore #ifdef CONFIG_AUDITSYSCALL 56afeb14b4SPaul Moore static void xfrm_audit_state_replay(struct xfrm_state *x, 57afeb14b4SPaul Moore struct sk_buff *skb, __be32 net_seq); 58afeb14b4SPaul Moore #else 59afeb14b4SPaul Moore #define xfrm_audit_state_replay(x, s, sq) do { ; } while (0) 60afeb14b4SPaul Moore #endif /* CONFIG_AUDITSYSCALL */ 61afeb14b4SPaul Moore 62c1969f29SDavid S. Miller static inline unsigned int xfrm_dst_hash(xfrm_address_t *daddr, 63c1969f29SDavid S. Miller xfrm_address_t *saddr, 64c1969f29SDavid S. Miller u32 reqid, 65a624c108SDavid S. Miller unsigned short family) 66a624c108SDavid S. Miller { 67c1969f29SDavid S. Miller return __xfrm_dst_hash(daddr, saddr, reqid, family, xfrm_state_hmask); 68a624c108SDavid S. Miller } 69a624c108SDavid S. Miller 70667bbcb6SMasahide NAKAMURA static inline unsigned int xfrm_src_hash(xfrm_address_t *daddr, 71667bbcb6SMasahide NAKAMURA xfrm_address_t *saddr, 7244e36b42SDavid S. Miller unsigned short family) 73f034b5d4SDavid S. Miller { 74667bbcb6SMasahide NAKAMURA return __xfrm_src_hash(daddr, saddr, family, xfrm_state_hmask); 75f034b5d4SDavid S. Miller } 76f034b5d4SDavid S. Miller 772575b654SDavid S. Miller static inline unsigned int 788122adf0SAl Viro xfrm_spi_hash(xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family) 79f034b5d4SDavid S. Miller { 80c1969f29SDavid S. Miller return __xfrm_spi_hash(daddr, spi, proto, family, xfrm_state_hmask); 81f034b5d4SDavid S. Miller } 82f034b5d4SDavid S. Miller 83f034b5d4SDavid S. Miller static void xfrm_hash_transfer(struct hlist_head *list, 84f034b5d4SDavid S. Miller struct hlist_head *ndsttable, 85f034b5d4SDavid S. Miller struct hlist_head *nsrctable, 86f034b5d4SDavid S. Miller struct hlist_head *nspitable, 87f034b5d4SDavid S. Miller unsigned int nhashmask) 88f034b5d4SDavid S. Miller { 89f034b5d4SDavid S. Miller struct hlist_node *entry, *tmp; 90f034b5d4SDavid S. Miller struct xfrm_state *x; 91f034b5d4SDavid S. Miller 92f034b5d4SDavid S. Miller hlist_for_each_entry_safe(x, entry, tmp, list, bydst) { 93f034b5d4SDavid S. Miller unsigned int h; 94f034b5d4SDavid S. Miller 95c1969f29SDavid S. Miller h = __xfrm_dst_hash(&x->id.daddr, &x->props.saddr, 96c1969f29SDavid S. Miller x->props.reqid, x->props.family, 97c1969f29SDavid S. Miller nhashmask); 98f034b5d4SDavid S. Miller hlist_add_head(&x->bydst, ndsttable+h); 99f034b5d4SDavid S. Miller 100667bbcb6SMasahide NAKAMURA h = __xfrm_src_hash(&x->id.daddr, &x->props.saddr, 101667bbcb6SMasahide NAKAMURA x->props.family, 102f034b5d4SDavid S. Miller nhashmask); 103f034b5d4SDavid S. Miller hlist_add_head(&x->bysrc, nsrctable+h); 104f034b5d4SDavid S. Miller 1057b4dc360SMasahide NAKAMURA if (x->id.spi) { 1067b4dc360SMasahide NAKAMURA h = __xfrm_spi_hash(&x->id.daddr, x->id.spi, 1077b4dc360SMasahide NAKAMURA x->id.proto, x->props.family, 1087b4dc360SMasahide NAKAMURA nhashmask); 109f034b5d4SDavid S. Miller hlist_add_head(&x->byspi, nspitable+h); 110f034b5d4SDavid S. Miller } 111f034b5d4SDavid S. Miller } 1127b4dc360SMasahide NAKAMURA } 113f034b5d4SDavid S. Miller 114f034b5d4SDavid S. Miller static unsigned long xfrm_hash_new_size(void) 115f034b5d4SDavid S. Miller { 116f034b5d4SDavid S. Miller return ((xfrm_state_hmask + 1) << 1) * 117f034b5d4SDavid S. Miller sizeof(struct hlist_head); 118f034b5d4SDavid S. Miller } 119f034b5d4SDavid S. Miller 120f034b5d4SDavid S. Miller static DEFINE_MUTEX(hash_resize_mutex); 121f034b5d4SDavid S. Miller 122c4028958SDavid Howells static void xfrm_hash_resize(struct work_struct *__unused) 123f034b5d4SDavid S. Miller { 124f034b5d4SDavid S. Miller struct hlist_head *ndst, *nsrc, *nspi, *odst, *osrc, *ospi; 125f034b5d4SDavid S. Miller unsigned long nsize, osize; 126f034b5d4SDavid S. Miller unsigned int nhashmask, ohashmask; 127f034b5d4SDavid S. Miller int i; 128f034b5d4SDavid S. Miller 129f034b5d4SDavid S. Miller mutex_lock(&hash_resize_mutex); 130f034b5d4SDavid S. Miller 131f034b5d4SDavid S. Miller nsize = xfrm_hash_new_size(); 13244e36b42SDavid S. Miller ndst = xfrm_hash_alloc(nsize); 133f034b5d4SDavid S. Miller if (!ndst) 134f034b5d4SDavid S. Miller goto out_unlock; 13544e36b42SDavid S. Miller nsrc = xfrm_hash_alloc(nsize); 136f034b5d4SDavid S. Miller if (!nsrc) { 13744e36b42SDavid S. Miller xfrm_hash_free(ndst, nsize); 138f034b5d4SDavid S. Miller goto out_unlock; 139f034b5d4SDavid S. Miller } 14044e36b42SDavid S. Miller nspi = xfrm_hash_alloc(nsize); 141f034b5d4SDavid S. Miller if (!nspi) { 14244e36b42SDavid S. Miller xfrm_hash_free(ndst, nsize); 14344e36b42SDavid S. Miller xfrm_hash_free(nsrc, nsize); 144f034b5d4SDavid S. Miller goto out_unlock; 145f034b5d4SDavid S. Miller } 146f034b5d4SDavid S. Miller 147f034b5d4SDavid S. Miller spin_lock_bh(&xfrm_state_lock); 148f034b5d4SDavid S. Miller 149f034b5d4SDavid S. Miller nhashmask = (nsize / sizeof(struct hlist_head)) - 1U; 150f034b5d4SDavid S. Miller for (i = xfrm_state_hmask; i >= 0; i--) 15173d189dcSAlexey Dobriyan xfrm_hash_transfer(init_net.xfrm.state_bydst+i, ndst, nsrc, nspi, 152f034b5d4SDavid S. Miller nhashmask); 153f034b5d4SDavid S. Miller 15473d189dcSAlexey Dobriyan odst = init_net.xfrm.state_bydst; 155d320bbb3SAlexey Dobriyan osrc = init_net.xfrm.state_bysrc; 156b754a4fdSAlexey Dobriyan ospi = init_net.xfrm.state_byspi; 157f034b5d4SDavid S. Miller ohashmask = xfrm_state_hmask; 158f034b5d4SDavid S. Miller 15973d189dcSAlexey Dobriyan init_net.xfrm.state_bydst = ndst; 160d320bbb3SAlexey Dobriyan init_net.xfrm.state_bysrc = nsrc; 161b754a4fdSAlexey Dobriyan init_net.xfrm.state_byspi = nspi; 162f034b5d4SDavid S. Miller xfrm_state_hmask = nhashmask; 163f034b5d4SDavid S. Miller 164f034b5d4SDavid S. Miller spin_unlock_bh(&xfrm_state_lock); 165f034b5d4SDavid S. Miller 166f034b5d4SDavid S. Miller osize = (ohashmask + 1) * sizeof(struct hlist_head); 16744e36b42SDavid S. Miller xfrm_hash_free(odst, osize); 16844e36b42SDavid S. Miller xfrm_hash_free(osrc, osize); 16944e36b42SDavid S. Miller xfrm_hash_free(ospi, osize); 170f034b5d4SDavid S. Miller 171f034b5d4SDavid S. Miller out_unlock: 172f034b5d4SDavid S. Miller mutex_unlock(&hash_resize_mutex); 173f034b5d4SDavid S. Miller } 174f034b5d4SDavid S. Miller 175c4028958SDavid Howells static DECLARE_WORK(xfrm_hash_work, xfrm_hash_resize); 176f034b5d4SDavid S. Miller 1771da177e4SLinus Torvalds DECLARE_WAIT_QUEUE_HEAD(km_waitq); 1781da177e4SLinus Torvalds EXPORT_SYMBOL(km_waitq); 1791da177e4SLinus Torvalds 1801da177e4SLinus Torvalds static DEFINE_RWLOCK(xfrm_state_afinfo_lock); 1811da177e4SLinus Torvalds static struct xfrm_state_afinfo *xfrm_state_afinfo[NPROTO]; 1821da177e4SLinus Torvalds 1831da177e4SLinus Torvalds static struct work_struct xfrm_state_gc_work; 18412a169e7SHerbert Xu static HLIST_HEAD(xfrm_state_gc_list); 1851da177e4SLinus Torvalds static DEFINE_SPINLOCK(xfrm_state_gc_lock); 1861da177e4SLinus Torvalds 18753bc6b4dSJamal Hadi Salim int __xfrm_state_delete(struct xfrm_state *x); 1881da177e4SLinus Torvalds 189980ebd25SJamal Hadi Salim int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol); 19053bc6b4dSJamal Hadi Salim void km_state_expired(struct xfrm_state *x, int hard, u32 pid); 1911da177e4SLinus Torvalds 192aa5d62ccSHerbert Xu static struct xfrm_state_afinfo *xfrm_state_lock_afinfo(unsigned int family) 193aa5d62ccSHerbert Xu { 194aa5d62ccSHerbert Xu struct xfrm_state_afinfo *afinfo; 195aa5d62ccSHerbert Xu if (unlikely(family >= NPROTO)) 196aa5d62ccSHerbert Xu return NULL; 197aa5d62ccSHerbert Xu write_lock_bh(&xfrm_state_afinfo_lock); 198aa5d62ccSHerbert Xu afinfo = xfrm_state_afinfo[family]; 199aa5d62ccSHerbert Xu if (unlikely(!afinfo)) 200aa5d62ccSHerbert Xu write_unlock_bh(&xfrm_state_afinfo_lock); 201aa5d62ccSHerbert Xu return afinfo; 202aa5d62ccSHerbert Xu } 203aa5d62ccSHerbert Xu 204aa5d62ccSHerbert Xu static void xfrm_state_unlock_afinfo(struct xfrm_state_afinfo *afinfo) 2059a429c49SEric Dumazet __releases(xfrm_state_afinfo_lock) 206aa5d62ccSHerbert Xu { 207aa5d62ccSHerbert Xu write_unlock_bh(&xfrm_state_afinfo_lock); 208aa5d62ccSHerbert Xu } 209aa5d62ccSHerbert Xu 210533cb5b0SEric Dumazet int xfrm_register_type(const struct xfrm_type *type, unsigned short family) 211aa5d62ccSHerbert Xu { 212aa5d62ccSHerbert Xu struct xfrm_state_afinfo *afinfo = xfrm_state_lock_afinfo(family); 213533cb5b0SEric Dumazet const struct xfrm_type **typemap; 214aa5d62ccSHerbert Xu int err = 0; 215aa5d62ccSHerbert Xu 216aa5d62ccSHerbert Xu if (unlikely(afinfo == NULL)) 217aa5d62ccSHerbert Xu return -EAFNOSUPPORT; 218aa5d62ccSHerbert Xu typemap = afinfo->type_map; 219aa5d62ccSHerbert Xu 220aa5d62ccSHerbert Xu if (likely(typemap[type->proto] == NULL)) 221aa5d62ccSHerbert Xu typemap[type->proto] = type; 222aa5d62ccSHerbert Xu else 223aa5d62ccSHerbert Xu err = -EEXIST; 224aa5d62ccSHerbert Xu xfrm_state_unlock_afinfo(afinfo); 225aa5d62ccSHerbert Xu return err; 226aa5d62ccSHerbert Xu } 227aa5d62ccSHerbert Xu EXPORT_SYMBOL(xfrm_register_type); 228aa5d62ccSHerbert Xu 229533cb5b0SEric Dumazet int xfrm_unregister_type(const struct xfrm_type *type, unsigned short family) 230aa5d62ccSHerbert Xu { 231aa5d62ccSHerbert Xu struct xfrm_state_afinfo *afinfo = xfrm_state_lock_afinfo(family); 232533cb5b0SEric Dumazet const struct xfrm_type **typemap; 233aa5d62ccSHerbert Xu int err = 0; 234aa5d62ccSHerbert Xu 235aa5d62ccSHerbert Xu if (unlikely(afinfo == NULL)) 236aa5d62ccSHerbert Xu return -EAFNOSUPPORT; 237aa5d62ccSHerbert Xu typemap = afinfo->type_map; 238aa5d62ccSHerbert Xu 239aa5d62ccSHerbert Xu if (unlikely(typemap[type->proto] != type)) 240aa5d62ccSHerbert Xu err = -ENOENT; 241aa5d62ccSHerbert Xu else 242aa5d62ccSHerbert Xu typemap[type->proto] = NULL; 243aa5d62ccSHerbert Xu xfrm_state_unlock_afinfo(afinfo); 244aa5d62ccSHerbert Xu return err; 245aa5d62ccSHerbert Xu } 246aa5d62ccSHerbert Xu EXPORT_SYMBOL(xfrm_unregister_type); 247aa5d62ccSHerbert Xu 248533cb5b0SEric Dumazet static const struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family) 249aa5d62ccSHerbert Xu { 250aa5d62ccSHerbert Xu struct xfrm_state_afinfo *afinfo; 251533cb5b0SEric Dumazet const struct xfrm_type **typemap; 252533cb5b0SEric Dumazet const struct xfrm_type *type; 253aa5d62ccSHerbert Xu int modload_attempted = 0; 254aa5d62ccSHerbert Xu 255aa5d62ccSHerbert Xu retry: 256aa5d62ccSHerbert Xu afinfo = xfrm_state_get_afinfo(family); 257aa5d62ccSHerbert Xu if (unlikely(afinfo == NULL)) 258aa5d62ccSHerbert Xu return NULL; 259aa5d62ccSHerbert Xu typemap = afinfo->type_map; 260aa5d62ccSHerbert Xu 261aa5d62ccSHerbert Xu type = typemap[proto]; 262aa5d62ccSHerbert Xu if (unlikely(type && !try_module_get(type->owner))) 263aa5d62ccSHerbert Xu type = NULL; 264aa5d62ccSHerbert Xu if (!type && !modload_attempted) { 265aa5d62ccSHerbert Xu xfrm_state_put_afinfo(afinfo); 266aa5d62ccSHerbert Xu request_module("xfrm-type-%d-%d", family, proto); 267aa5d62ccSHerbert Xu modload_attempted = 1; 268aa5d62ccSHerbert Xu goto retry; 269aa5d62ccSHerbert Xu } 270aa5d62ccSHerbert Xu 271aa5d62ccSHerbert Xu xfrm_state_put_afinfo(afinfo); 272aa5d62ccSHerbert Xu return type; 273aa5d62ccSHerbert Xu } 274aa5d62ccSHerbert Xu 275533cb5b0SEric Dumazet static void xfrm_put_type(const struct xfrm_type *type) 276aa5d62ccSHerbert Xu { 277aa5d62ccSHerbert Xu module_put(type->owner); 278aa5d62ccSHerbert Xu } 279aa5d62ccSHerbert Xu 280aa5d62ccSHerbert Xu int xfrm_register_mode(struct xfrm_mode *mode, int family) 281aa5d62ccSHerbert Xu { 282aa5d62ccSHerbert Xu struct xfrm_state_afinfo *afinfo; 283aa5d62ccSHerbert Xu struct xfrm_mode **modemap; 284aa5d62ccSHerbert Xu int err; 285aa5d62ccSHerbert Xu 286aa5d62ccSHerbert Xu if (unlikely(mode->encap >= XFRM_MODE_MAX)) 287aa5d62ccSHerbert Xu return -EINVAL; 288aa5d62ccSHerbert Xu 289aa5d62ccSHerbert Xu afinfo = xfrm_state_lock_afinfo(family); 290aa5d62ccSHerbert Xu if (unlikely(afinfo == NULL)) 291aa5d62ccSHerbert Xu return -EAFNOSUPPORT; 292aa5d62ccSHerbert Xu 293aa5d62ccSHerbert Xu err = -EEXIST; 294aa5d62ccSHerbert Xu modemap = afinfo->mode_map; 29517c2a42aSHerbert Xu if (modemap[mode->encap]) 29617c2a42aSHerbert Xu goto out; 29717c2a42aSHerbert Xu 29817c2a42aSHerbert Xu err = -ENOENT; 29917c2a42aSHerbert Xu if (!try_module_get(afinfo->owner)) 30017c2a42aSHerbert Xu goto out; 30117c2a42aSHerbert Xu 30217c2a42aSHerbert Xu mode->afinfo = afinfo; 303aa5d62ccSHerbert Xu modemap[mode->encap] = mode; 304aa5d62ccSHerbert Xu err = 0; 305aa5d62ccSHerbert Xu 30617c2a42aSHerbert Xu out: 307aa5d62ccSHerbert Xu xfrm_state_unlock_afinfo(afinfo); 308aa5d62ccSHerbert Xu return err; 309aa5d62ccSHerbert Xu } 310aa5d62ccSHerbert Xu EXPORT_SYMBOL(xfrm_register_mode); 311aa5d62ccSHerbert Xu 312aa5d62ccSHerbert Xu int xfrm_unregister_mode(struct xfrm_mode *mode, int family) 313aa5d62ccSHerbert Xu { 314aa5d62ccSHerbert Xu struct xfrm_state_afinfo *afinfo; 315aa5d62ccSHerbert Xu struct xfrm_mode **modemap; 316aa5d62ccSHerbert Xu int err; 317aa5d62ccSHerbert Xu 318aa5d62ccSHerbert Xu if (unlikely(mode->encap >= XFRM_MODE_MAX)) 319aa5d62ccSHerbert Xu return -EINVAL; 320aa5d62ccSHerbert Xu 321aa5d62ccSHerbert Xu afinfo = xfrm_state_lock_afinfo(family); 322aa5d62ccSHerbert Xu if (unlikely(afinfo == NULL)) 323aa5d62ccSHerbert Xu return -EAFNOSUPPORT; 324aa5d62ccSHerbert Xu 325aa5d62ccSHerbert Xu err = -ENOENT; 326aa5d62ccSHerbert Xu modemap = afinfo->mode_map; 327aa5d62ccSHerbert Xu if (likely(modemap[mode->encap] == mode)) { 328aa5d62ccSHerbert Xu modemap[mode->encap] = NULL; 32917c2a42aSHerbert Xu module_put(mode->afinfo->owner); 330aa5d62ccSHerbert Xu err = 0; 331aa5d62ccSHerbert Xu } 332aa5d62ccSHerbert Xu 333aa5d62ccSHerbert Xu xfrm_state_unlock_afinfo(afinfo); 334aa5d62ccSHerbert Xu return err; 335aa5d62ccSHerbert Xu } 336aa5d62ccSHerbert Xu EXPORT_SYMBOL(xfrm_unregister_mode); 337aa5d62ccSHerbert Xu 338aa5d62ccSHerbert Xu static struct xfrm_mode *xfrm_get_mode(unsigned int encap, int family) 339aa5d62ccSHerbert Xu { 340aa5d62ccSHerbert Xu struct xfrm_state_afinfo *afinfo; 341aa5d62ccSHerbert Xu struct xfrm_mode *mode; 342aa5d62ccSHerbert Xu int modload_attempted = 0; 343aa5d62ccSHerbert Xu 344aa5d62ccSHerbert Xu if (unlikely(encap >= XFRM_MODE_MAX)) 345aa5d62ccSHerbert Xu return NULL; 346aa5d62ccSHerbert Xu 347aa5d62ccSHerbert Xu retry: 348aa5d62ccSHerbert Xu afinfo = xfrm_state_get_afinfo(family); 349aa5d62ccSHerbert Xu if (unlikely(afinfo == NULL)) 350aa5d62ccSHerbert Xu return NULL; 351aa5d62ccSHerbert Xu 352aa5d62ccSHerbert Xu mode = afinfo->mode_map[encap]; 353aa5d62ccSHerbert Xu if (unlikely(mode && !try_module_get(mode->owner))) 354aa5d62ccSHerbert Xu mode = NULL; 355aa5d62ccSHerbert Xu if (!mode && !modload_attempted) { 356aa5d62ccSHerbert Xu xfrm_state_put_afinfo(afinfo); 357aa5d62ccSHerbert Xu request_module("xfrm-mode-%d-%d", family, encap); 358aa5d62ccSHerbert Xu modload_attempted = 1; 359aa5d62ccSHerbert Xu goto retry; 360aa5d62ccSHerbert Xu } 361aa5d62ccSHerbert Xu 362aa5d62ccSHerbert Xu xfrm_state_put_afinfo(afinfo); 363aa5d62ccSHerbert Xu return mode; 364aa5d62ccSHerbert Xu } 365aa5d62ccSHerbert Xu 366aa5d62ccSHerbert Xu static void xfrm_put_mode(struct xfrm_mode *mode) 367aa5d62ccSHerbert Xu { 368aa5d62ccSHerbert Xu module_put(mode->owner); 369aa5d62ccSHerbert Xu } 370aa5d62ccSHerbert Xu 3711da177e4SLinus Torvalds static void xfrm_state_gc_destroy(struct xfrm_state *x) 3721da177e4SLinus Torvalds { 373a47f0ce0SDavid S. Miller del_timer_sync(&x->timer); 374a47f0ce0SDavid S. Miller del_timer_sync(&x->rtimer); 3751da177e4SLinus Torvalds kfree(x->aalg); 3761da177e4SLinus Torvalds kfree(x->ealg); 3771da177e4SLinus Torvalds kfree(x->calg); 3781da177e4SLinus Torvalds kfree(x->encap); 379060f02a3SNoriaki TAKAMIYA kfree(x->coaddr); 38013996378SHerbert Xu if (x->inner_mode) 38113996378SHerbert Xu xfrm_put_mode(x->inner_mode); 382df9dcb45SKazunori MIYAZAWA if (x->inner_mode_iaf) 383df9dcb45SKazunori MIYAZAWA xfrm_put_mode(x->inner_mode_iaf); 38413996378SHerbert Xu if (x->outer_mode) 38513996378SHerbert Xu xfrm_put_mode(x->outer_mode); 3861da177e4SLinus Torvalds if (x->type) { 3871da177e4SLinus Torvalds x->type->destructor(x); 3881da177e4SLinus Torvalds xfrm_put_type(x->type); 3891da177e4SLinus Torvalds } 390df71837dSTrent Jaeger security_xfrm_state_free(x); 3911da177e4SLinus Torvalds kfree(x); 3921da177e4SLinus Torvalds } 3931da177e4SLinus Torvalds 394c4028958SDavid Howells static void xfrm_state_gc_task(struct work_struct *data) 3951da177e4SLinus Torvalds { 39612a169e7SHerbert Xu struct xfrm_state *x; 39712a169e7SHerbert Xu struct hlist_node *entry, *tmp; 39812a169e7SHerbert Xu struct hlist_head gc_list; 3991da177e4SLinus Torvalds 4001da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_gc_lock); 40112a169e7SHerbert Xu hlist_move_list(&xfrm_state_gc_list, &gc_list); 4021da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_gc_lock); 4031da177e4SLinus Torvalds 40412a169e7SHerbert Xu hlist_for_each_entry_safe(x, entry, tmp, &gc_list, gclist) 4051da177e4SLinus Torvalds xfrm_state_gc_destroy(x); 4068f126e37SDavid S. Miller 4071da177e4SLinus Torvalds wake_up(&km_waitq); 4081da177e4SLinus Torvalds } 4091da177e4SLinus Torvalds 4101da177e4SLinus Torvalds static inline unsigned long make_jiffies(long secs) 4111da177e4SLinus Torvalds { 4121da177e4SLinus Torvalds if (secs >= (MAX_SCHEDULE_TIMEOUT-1)/HZ) 4131da177e4SLinus Torvalds return MAX_SCHEDULE_TIMEOUT-1; 4141da177e4SLinus Torvalds else 4151da177e4SLinus Torvalds return secs*HZ; 4161da177e4SLinus Torvalds } 4171da177e4SLinus Torvalds 4181da177e4SLinus Torvalds static void xfrm_timer_handler(unsigned long data) 4191da177e4SLinus Torvalds { 4201da177e4SLinus Torvalds struct xfrm_state *x = (struct xfrm_state*)data; 4219d729f72SJames Morris unsigned long now = get_seconds(); 4221da177e4SLinus Torvalds long next = LONG_MAX; 4231da177e4SLinus Torvalds int warn = 0; 424161a09e7SJoy Latten int err = 0; 4251da177e4SLinus Torvalds 4261da177e4SLinus Torvalds spin_lock(&x->lock); 4271da177e4SLinus Torvalds if (x->km.state == XFRM_STATE_DEAD) 4281da177e4SLinus Torvalds goto out; 4291da177e4SLinus Torvalds if (x->km.state == XFRM_STATE_EXPIRED) 4301da177e4SLinus Torvalds goto expired; 4311da177e4SLinus Torvalds if (x->lft.hard_add_expires_seconds) { 4321da177e4SLinus Torvalds long tmo = x->lft.hard_add_expires_seconds + 4331da177e4SLinus Torvalds x->curlft.add_time - now; 4341da177e4SLinus Torvalds if (tmo <= 0) 4351da177e4SLinus Torvalds goto expired; 4361da177e4SLinus Torvalds if (tmo < next) 4371da177e4SLinus Torvalds next = tmo; 4381da177e4SLinus Torvalds } 4391da177e4SLinus Torvalds if (x->lft.hard_use_expires_seconds) { 4401da177e4SLinus Torvalds long tmo = x->lft.hard_use_expires_seconds + 4411da177e4SLinus Torvalds (x->curlft.use_time ? : now) - now; 4421da177e4SLinus Torvalds if (tmo <= 0) 4431da177e4SLinus Torvalds goto expired; 4441da177e4SLinus Torvalds if (tmo < next) 4451da177e4SLinus Torvalds next = tmo; 4461da177e4SLinus Torvalds } 4471da177e4SLinus Torvalds if (x->km.dying) 4481da177e4SLinus Torvalds goto resched; 4491da177e4SLinus Torvalds if (x->lft.soft_add_expires_seconds) { 4501da177e4SLinus Torvalds long tmo = x->lft.soft_add_expires_seconds + 4511da177e4SLinus Torvalds x->curlft.add_time - now; 4521da177e4SLinus Torvalds if (tmo <= 0) 4531da177e4SLinus Torvalds warn = 1; 4541da177e4SLinus Torvalds else if (tmo < next) 4551da177e4SLinus Torvalds next = tmo; 4561da177e4SLinus Torvalds } 4571da177e4SLinus Torvalds if (x->lft.soft_use_expires_seconds) { 4581da177e4SLinus Torvalds long tmo = x->lft.soft_use_expires_seconds + 4591da177e4SLinus Torvalds (x->curlft.use_time ? : now) - now; 4601da177e4SLinus Torvalds if (tmo <= 0) 4611da177e4SLinus Torvalds warn = 1; 4621da177e4SLinus Torvalds else if (tmo < next) 4631da177e4SLinus Torvalds next = tmo; 4641da177e4SLinus Torvalds } 4651da177e4SLinus Torvalds 4664666faabSHerbert Xu x->km.dying = warn; 4671da177e4SLinus Torvalds if (warn) 46853bc6b4dSJamal Hadi Salim km_state_expired(x, 0, 0); 4691da177e4SLinus Torvalds resched: 470a47f0ce0SDavid S. Miller if (next != LONG_MAX) 471a47f0ce0SDavid S. Miller mod_timer(&x->timer, jiffies + make_jiffies(next)); 472a47f0ce0SDavid S. Miller 4731da177e4SLinus Torvalds goto out; 4741da177e4SLinus Torvalds 4751da177e4SLinus Torvalds expired: 4761da177e4SLinus Torvalds if (x->km.state == XFRM_STATE_ACQ && x->id.spi == 0) { 4771da177e4SLinus Torvalds x->km.state = XFRM_STATE_EXPIRED; 4781da177e4SLinus Torvalds wake_up(&km_waitq); 4791da177e4SLinus Torvalds next = 2; 4801da177e4SLinus Torvalds goto resched; 4811da177e4SLinus Torvalds } 482161a09e7SJoy Latten 483161a09e7SJoy Latten err = __xfrm_state_delete(x); 484161a09e7SJoy Latten if (!err && x->id.spi) 48553bc6b4dSJamal Hadi Salim km_state_expired(x, 1, 0); 4861da177e4SLinus Torvalds 487ab5f5e8bSJoy Latten xfrm_audit_state_delete(x, err ? 0 : 1, 4882532386fSEric Paris audit_get_loginuid(current), 4892532386fSEric Paris audit_get_sessionid(current), 0); 490161a09e7SJoy Latten 4911da177e4SLinus Torvalds out: 4921da177e4SLinus Torvalds spin_unlock(&x->lock); 4931da177e4SLinus Torvalds } 4941da177e4SLinus Torvalds 4950ac84752SDavid S. Miller static void xfrm_replay_timer_handler(unsigned long data); 4960ac84752SDavid S. Miller 497673c09beSAlexey Dobriyan struct xfrm_state *xfrm_state_alloc(struct net *net) 4981da177e4SLinus Torvalds { 4991da177e4SLinus Torvalds struct xfrm_state *x; 5001da177e4SLinus Torvalds 5010da974f4SPanagiotis Issaris x = kzalloc(sizeof(struct xfrm_state), GFP_ATOMIC); 5021da177e4SLinus Torvalds 5031da177e4SLinus Torvalds if (x) { 504673c09beSAlexey Dobriyan write_pnet(&x->xs_net, net); 5051da177e4SLinus Torvalds atomic_set(&x->refcnt, 1); 5061da177e4SLinus Torvalds atomic_set(&x->tunnel_users, 0); 50712a169e7SHerbert Xu INIT_LIST_HEAD(&x->km.all); 5088f126e37SDavid S. Miller INIT_HLIST_NODE(&x->bydst); 5098f126e37SDavid S. Miller INIT_HLIST_NODE(&x->bysrc); 5108f126e37SDavid S. Miller INIT_HLIST_NODE(&x->byspi); 511b24b8a24SPavel Emelyanov setup_timer(&x->timer, xfrm_timer_handler, (unsigned long)x); 512b24b8a24SPavel Emelyanov setup_timer(&x->rtimer, xfrm_replay_timer_handler, 513b24b8a24SPavel Emelyanov (unsigned long)x); 5149d729f72SJames Morris x->curlft.add_time = get_seconds(); 5151da177e4SLinus Torvalds x->lft.soft_byte_limit = XFRM_INF; 5161da177e4SLinus Torvalds x->lft.soft_packet_limit = XFRM_INF; 5171da177e4SLinus Torvalds x->lft.hard_byte_limit = XFRM_INF; 5181da177e4SLinus Torvalds x->lft.hard_packet_limit = XFRM_INF; 519f8cd5488SJamal Hadi Salim x->replay_maxage = 0; 520f8cd5488SJamal Hadi Salim x->replay_maxdiff = 0; 521df9dcb45SKazunori MIYAZAWA x->inner_mode = NULL; 522df9dcb45SKazunori MIYAZAWA x->inner_mode_iaf = NULL; 5231da177e4SLinus Torvalds spin_lock_init(&x->lock); 5241da177e4SLinus Torvalds } 5251da177e4SLinus Torvalds return x; 5261da177e4SLinus Torvalds } 5271da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_alloc); 5281da177e4SLinus Torvalds 5291da177e4SLinus Torvalds void __xfrm_state_destroy(struct xfrm_state *x) 5301da177e4SLinus Torvalds { 531547b792cSIlpo Järvinen WARN_ON(x->km.state != XFRM_STATE_DEAD); 5321da177e4SLinus Torvalds 5331da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_gc_lock); 53412a169e7SHerbert Xu hlist_add_head(&x->gclist, &xfrm_state_gc_list); 5351da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_gc_lock); 5361da177e4SLinus Torvalds schedule_work(&xfrm_state_gc_work); 5371da177e4SLinus Torvalds } 5381da177e4SLinus Torvalds EXPORT_SYMBOL(__xfrm_state_destroy); 5391da177e4SLinus Torvalds 54053bc6b4dSJamal Hadi Salim int __xfrm_state_delete(struct xfrm_state *x) 5411da177e4SLinus Torvalds { 54226b15dadSJamal Hadi Salim int err = -ESRCH; 54326b15dadSJamal Hadi Salim 5441da177e4SLinus Torvalds if (x->km.state != XFRM_STATE_DEAD) { 5451da177e4SLinus Torvalds x->km.state = XFRM_STATE_DEAD; 5461da177e4SLinus Torvalds spin_lock(&xfrm_state_lock); 54712a169e7SHerbert Xu list_del(&x->km.all); 5488f126e37SDavid S. Miller hlist_del(&x->bydst); 5498f126e37SDavid S. Miller hlist_del(&x->bysrc); 550a47f0ce0SDavid S. Miller if (x->id.spi) 5518f126e37SDavid S. Miller hlist_del(&x->byspi); 552f034b5d4SDavid S. Miller xfrm_state_num--; 5531da177e4SLinus Torvalds spin_unlock(&xfrm_state_lock); 5541da177e4SLinus Torvalds 5551da177e4SLinus Torvalds /* All xfrm_state objects are created by xfrm_state_alloc. 5561da177e4SLinus Torvalds * The xfrm_state_alloc call gives a reference, and that 5571da177e4SLinus Torvalds * is what we are dropping here. 5581da177e4SLinus Torvalds */ 5595dba4797SPatrick McHardy xfrm_state_put(x); 56026b15dadSJamal Hadi Salim err = 0; 5611da177e4SLinus Torvalds } 5621da177e4SLinus Torvalds 56326b15dadSJamal Hadi Salim return err; 56426b15dadSJamal Hadi Salim } 56553bc6b4dSJamal Hadi Salim EXPORT_SYMBOL(__xfrm_state_delete); 56626b15dadSJamal Hadi Salim 56726b15dadSJamal Hadi Salim int xfrm_state_delete(struct xfrm_state *x) 5681da177e4SLinus Torvalds { 56926b15dadSJamal Hadi Salim int err; 57026b15dadSJamal Hadi Salim 5711da177e4SLinus Torvalds spin_lock_bh(&x->lock); 57226b15dadSJamal Hadi Salim err = __xfrm_state_delete(x); 5731da177e4SLinus Torvalds spin_unlock_bh(&x->lock); 57426b15dadSJamal Hadi Salim 57526b15dadSJamal Hadi Salim return err; 5761da177e4SLinus Torvalds } 5771da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_delete); 5781da177e4SLinus Torvalds 5794aa2e62cSJoy Latten #ifdef CONFIG_SECURITY_NETWORK_XFRM 5804aa2e62cSJoy Latten static inline int 5814aa2e62cSJoy Latten xfrm_state_flush_secctx_check(u8 proto, struct xfrm_audit *audit_info) 5821da177e4SLinus Torvalds { 5834aa2e62cSJoy Latten int i, err = 0; 5844aa2e62cSJoy Latten 5854aa2e62cSJoy Latten for (i = 0; i <= xfrm_state_hmask; i++) { 5864aa2e62cSJoy Latten struct hlist_node *entry; 5874aa2e62cSJoy Latten struct xfrm_state *x; 5884aa2e62cSJoy Latten 58973d189dcSAlexey Dobriyan hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+i, bydst) { 5904aa2e62cSJoy Latten if (xfrm_id_proto_match(x->id.proto, proto) && 5914aa2e62cSJoy Latten (err = security_xfrm_state_delete(x)) != 0) { 592ab5f5e8bSJoy Latten xfrm_audit_state_delete(x, 0, 593ab5f5e8bSJoy Latten audit_info->loginuid, 5942532386fSEric Paris audit_info->sessionid, 595ab5f5e8bSJoy Latten audit_info->secid); 5964aa2e62cSJoy Latten return err; 5974aa2e62cSJoy Latten } 5984aa2e62cSJoy Latten } 5994aa2e62cSJoy Latten } 6004aa2e62cSJoy Latten 6014aa2e62cSJoy Latten return err; 6024aa2e62cSJoy Latten } 6034aa2e62cSJoy Latten #else 6044aa2e62cSJoy Latten static inline int 6054aa2e62cSJoy Latten xfrm_state_flush_secctx_check(u8 proto, struct xfrm_audit *audit_info) 6064aa2e62cSJoy Latten { 6074aa2e62cSJoy Latten return 0; 6084aa2e62cSJoy Latten } 6094aa2e62cSJoy Latten #endif 6104aa2e62cSJoy Latten 6114aa2e62cSJoy Latten int xfrm_state_flush(u8 proto, struct xfrm_audit *audit_info) 6124aa2e62cSJoy Latten { 6134aa2e62cSJoy Latten int i, err = 0; 6141da177e4SLinus Torvalds 6151da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_lock); 6164aa2e62cSJoy Latten err = xfrm_state_flush_secctx_check(proto, audit_info); 6174aa2e62cSJoy Latten if (err) 6184aa2e62cSJoy Latten goto out; 6194aa2e62cSJoy Latten 620a9917c06SMasahide NAKAMURA for (i = 0; i <= xfrm_state_hmask; i++) { 6218f126e37SDavid S. Miller struct hlist_node *entry; 6228f126e37SDavid S. Miller struct xfrm_state *x; 6231da177e4SLinus Torvalds restart: 62473d189dcSAlexey Dobriyan hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+i, bydst) { 6251da177e4SLinus Torvalds if (!xfrm_state_kern(x) && 6265794708fSMasahide NAKAMURA xfrm_id_proto_match(x->id.proto, proto)) { 6271da177e4SLinus Torvalds xfrm_state_hold(x); 6281da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_lock); 6291da177e4SLinus Torvalds 630161a09e7SJoy Latten err = xfrm_state_delete(x); 631ab5f5e8bSJoy Latten xfrm_audit_state_delete(x, err ? 0 : 1, 632ab5f5e8bSJoy Latten audit_info->loginuid, 6332532386fSEric Paris audit_info->sessionid, 634ab5f5e8bSJoy Latten audit_info->secid); 6351da177e4SLinus Torvalds xfrm_state_put(x); 6361da177e4SLinus Torvalds 6371da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_lock); 6381da177e4SLinus Torvalds goto restart; 6391da177e4SLinus Torvalds } 6401da177e4SLinus Torvalds } 6411da177e4SLinus Torvalds } 6424aa2e62cSJoy Latten err = 0; 6434aa2e62cSJoy Latten 6444aa2e62cSJoy Latten out: 6451da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_lock); 6461da177e4SLinus Torvalds wake_up(&km_waitq); 6474aa2e62cSJoy Latten return err; 6481da177e4SLinus Torvalds } 6491da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_flush); 6501da177e4SLinus Torvalds 651af11e316SJamal Hadi Salim void xfrm_sad_getinfo(struct xfrmk_sadinfo *si) 65228d8909bSJamal Hadi Salim { 65328d8909bSJamal Hadi Salim spin_lock_bh(&xfrm_state_lock); 65428d8909bSJamal Hadi Salim si->sadcnt = xfrm_state_num; 65528d8909bSJamal Hadi Salim si->sadhcnt = xfrm_state_hmask; 65628d8909bSJamal Hadi Salim si->sadhmcnt = xfrm_state_hashmax; 65728d8909bSJamal Hadi Salim spin_unlock_bh(&xfrm_state_lock); 65828d8909bSJamal Hadi Salim } 65928d8909bSJamal Hadi Salim EXPORT_SYMBOL(xfrm_sad_getinfo); 66028d8909bSJamal Hadi Salim 6611da177e4SLinus Torvalds static int 6621da177e4SLinus Torvalds xfrm_init_tempsel(struct xfrm_state *x, struct flowi *fl, 6631da177e4SLinus Torvalds struct xfrm_tmpl *tmpl, 6641da177e4SLinus Torvalds xfrm_address_t *daddr, xfrm_address_t *saddr, 6651da177e4SLinus Torvalds unsigned short family) 6661da177e4SLinus Torvalds { 6671da177e4SLinus Torvalds struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); 6681da177e4SLinus Torvalds if (!afinfo) 6691da177e4SLinus Torvalds return -1; 6701da177e4SLinus Torvalds afinfo->init_tempsel(x, fl, tmpl, daddr, saddr); 6711da177e4SLinus Torvalds xfrm_state_put_afinfo(afinfo); 6721da177e4SLinus Torvalds return 0; 6731da177e4SLinus Torvalds } 6741da177e4SLinus Torvalds 675a94cfd19SAl Viro static struct xfrm_state *__xfrm_state_lookup(xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family) 676edcd5821SDavid S. Miller { 677edcd5821SDavid S. Miller unsigned int h = xfrm_spi_hash(daddr, spi, proto, family); 678edcd5821SDavid S. Miller struct xfrm_state *x; 6798f126e37SDavid S. Miller struct hlist_node *entry; 680edcd5821SDavid S. Miller 681b754a4fdSAlexey Dobriyan hlist_for_each_entry(x, entry, init_net.xfrm.state_byspi+h, byspi) { 682edcd5821SDavid S. Miller if (x->props.family != family || 683edcd5821SDavid S. Miller x->id.spi != spi || 684edcd5821SDavid S. Miller x->id.proto != proto) 685edcd5821SDavid S. Miller continue; 686edcd5821SDavid S. Miller 687edcd5821SDavid S. Miller switch (family) { 688edcd5821SDavid S. Miller case AF_INET: 689edcd5821SDavid S. Miller if (x->id.daddr.a4 != daddr->a4) 690edcd5821SDavid S. Miller continue; 691edcd5821SDavid S. Miller break; 692edcd5821SDavid S. Miller case AF_INET6: 693edcd5821SDavid S. Miller if (!ipv6_addr_equal((struct in6_addr *)daddr, 694edcd5821SDavid S. Miller (struct in6_addr *) 695edcd5821SDavid S. Miller x->id.daddr.a6)) 696edcd5821SDavid S. Miller continue; 697edcd5821SDavid S. Miller break; 6983ff50b79SStephen Hemminger } 699edcd5821SDavid S. Miller 700edcd5821SDavid S. Miller xfrm_state_hold(x); 701edcd5821SDavid S. Miller return x; 702edcd5821SDavid S. Miller } 703edcd5821SDavid S. Miller 704edcd5821SDavid S. Miller return NULL; 705edcd5821SDavid S. Miller } 706edcd5821SDavid S. Miller 707edcd5821SDavid S. Miller static struct xfrm_state *__xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto, unsigned short family) 708edcd5821SDavid S. Miller { 709667bbcb6SMasahide NAKAMURA unsigned int h = xfrm_src_hash(daddr, saddr, family); 710edcd5821SDavid S. Miller struct xfrm_state *x; 7118f126e37SDavid S. Miller struct hlist_node *entry; 712edcd5821SDavid S. Miller 713d320bbb3SAlexey Dobriyan hlist_for_each_entry(x, entry, init_net.xfrm.state_bysrc+h, bysrc) { 714edcd5821SDavid S. Miller if (x->props.family != family || 715edcd5821SDavid S. Miller x->id.proto != proto) 716edcd5821SDavid S. Miller continue; 717edcd5821SDavid S. Miller 718edcd5821SDavid S. Miller switch (family) { 719edcd5821SDavid S. Miller case AF_INET: 720edcd5821SDavid S. Miller if (x->id.daddr.a4 != daddr->a4 || 721edcd5821SDavid S. Miller x->props.saddr.a4 != saddr->a4) 722edcd5821SDavid S. Miller continue; 723edcd5821SDavid S. Miller break; 724edcd5821SDavid S. Miller case AF_INET6: 725edcd5821SDavid S. Miller if (!ipv6_addr_equal((struct in6_addr *)daddr, 726edcd5821SDavid S. Miller (struct in6_addr *) 727edcd5821SDavid S. Miller x->id.daddr.a6) || 728edcd5821SDavid S. Miller !ipv6_addr_equal((struct in6_addr *)saddr, 729edcd5821SDavid S. Miller (struct in6_addr *) 730edcd5821SDavid S. Miller x->props.saddr.a6)) 731edcd5821SDavid S. Miller continue; 732edcd5821SDavid S. Miller break; 7333ff50b79SStephen Hemminger } 734edcd5821SDavid S. Miller 735edcd5821SDavid S. Miller xfrm_state_hold(x); 736edcd5821SDavid S. Miller return x; 737edcd5821SDavid S. Miller } 738edcd5821SDavid S. Miller 739edcd5821SDavid S. Miller return NULL; 740edcd5821SDavid S. Miller } 741edcd5821SDavid S. Miller 742edcd5821SDavid S. Miller static inline struct xfrm_state * 743edcd5821SDavid S. Miller __xfrm_state_locate(struct xfrm_state *x, int use_spi, int family) 744edcd5821SDavid S. Miller { 745edcd5821SDavid S. Miller if (use_spi) 746edcd5821SDavid S. Miller return __xfrm_state_lookup(&x->id.daddr, x->id.spi, 747edcd5821SDavid S. Miller x->id.proto, family); 748edcd5821SDavid S. Miller else 749edcd5821SDavid S. Miller return __xfrm_state_lookup_byaddr(&x->id.daddr, 750edcd5821SDavid S. Miller &x->props.saddr, 751edcd5821SDavid S. Miller x->id.proto, family); 752edcd5821SDavid S. Miller } 753edcd5821SDavid S. Miller 7542fab22f2SPatrick McHardy static void xfrm_hash_grow_check(int have_hash_collision) 7552fab22f2SPatrick McHardy { 7562fab22f2SPatrick McHardy if (have_hash_collision && 7572fab22f2SPatrick McHardy (xfrm_state_hmask + 1) < xfrm_state_hashmax && 7582fab22f2SPatrick McHardy xfrm_state_num > xfrm_state_hmask) 7592fab22f2SPatrick McHardy schedule_work(&xfrm_hash_work); 7602fab22f2SPatrick McHardy } 7612fab22f2SPatrick McHardy 7621da177e4SLinus Torvalds struct xfrm_state * 7631da177e4SLinus Torvalds xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, 7641da177e4SLinus Torvalds struct flowi *fl, struct xfrm_tmpl *tmpl, 7651da177e4SLinus Torvalds struct xfrm_policy *pol, int *err, 7661da177e4SLinus Torvalds unsigned short family) 7671da177e4SLinus Torvalds { 7684bda4f25SPavel Emelyanov unsigned int h; 7698f126e37SDavid S. Miller struct hlist_node *entry; 77037b08e34SDavid S. Miller struct xfrm_state *x, *x0, *to_put; 7711da177e4SLinus Torvalds int acquire_in_progress = 0; 7721da177e4SLinus Torvalds int error = 0; 7731da177e4SLinus Torvalds struct xfrm_state *best = NULL; 7741da177e4SLinus Torvalds 77537b08e34SDavid S. Miller to_put = NULL; 77637b08e34SDavid S. Miller 7771da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_lock); 7784bda4f25SPavel Emelyanov h = xfrm_dst_hash(daddr, saddr, tmpl->reqid, family); 77973d189dcSAlexey Dobriyan hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+h, bydst) { 7801da177e4SLinus Torvalds if (x->props.family == family && 7811da177e4SLinus Torvalds x->props.reqid == tmpl->reqid && 782fbd9a5b4SMasahide NAKAMURA !(x->props.flags & XFRM_STATE_WILDRECV) && 7831da177e4SLinus Torvalds xfrm_state_addr_check(x, daddr, saddr, family) && 7841da177e4SLinus Torvalds tmpl->mode == x->props.mode && 7851da177e4SLinus Torvalds tmpl->id.proto == x->id.proto && 7861da177e4SLinus Torvalds (tmpl->id.spi == x->id.spi || !tmpl->id.spi)) { 7871da177e4SLinus Torvalds /* Resolution logic: 7881da177e4SLinus Torvalds 1. There is a valid state with matching selector. 7891da177e4SLinus Torvalds Done. 7901da177e4SLinus Torvalds 2. Valid state with inappropriate selector. Skip. 7911da177e4SLinus Torvalds 7921da177e4SLinus Torvalds Entering area of "sysdeps". 7931da177e4SLinus Torvalds 7941da177e4SLinus Torvalds 3. If state is not valid, selector is temporary, 7951da177e4SLinus Torvalds it selects only session which triggered 7961da177e4SLinus Torvalds previous resolution. Key manager will do 7971da177e4SLinus Torvalds something to install a state with proper 7981da177e4SLinus Torvalds selector. 7991da177e4SLinus Torvalds */ 8001da177e4SLinus Torvalds if (x->km.state == XFRM_STATE_VALID) { 801df9dcb45SKazunori MIYAZAWA if ((x->sel.family && !xfrm_selector_match(&x->sel, fl, x->sel.family)) || 802e0d1caa7SVenkat Yekkirala !security_xfrm_state_pol_flow_match(x, pol, fl)) 8031da177e4SLinus Torvalds continue; 8041da177e4SLinus Torvalds if (!best || 8051da177e4SLinus Torvalds best->km.dying > x->km.dying || 8061da177e4SLinus Torvalds (best->km.dying == x->km.dying && 8071da177e4SLinus Torvalds best->curlft.add_time < x->curlft.add_time)) 8081da177e4SLinus Torvalds best = x; 8091da177e4SLinus Torvalds } else if (x->km.state == XFRM_STATE_ACQ) { 8101da177e4SLinus Torvalds acquire_in_progress = 1; 8111da177e4SLinus Torvalds } else if (x->km.state == XFRM_STATE_ERROR || 8121da177e4SLinus Torvalds x->km.state == XFRM_STATE_EXPIRED) { 81348b8d783SJoakim Koskela if (xfrm_selector_match(&x->sel, fl, x->sel.family) && 814e0d1caa7SVenkat Yekkirala security_xfrm_state_pol_flow_match(x, pol, fl)) 8151da177e4SLinus Torvalds error = -ESRCH; 8161da177e4SLinus Torvalds } 8171da177e4SLinus Torvalds } 8181da177e4SLinus Torvalds } 8191da177e4SLinus Torvalds 8201da177e4SLinus Torvalds x = best; 8211da177e4SLinus Torvalds if (!x && !error && !acquire_in_progress) { 8225c5d281aSPatrick McHardy if (tmpl->id.spi && 823edcd5821SDavid S. Miller (x0 = __xfrm_state_lookup(daddr, tmpl->id.spi, 824edcd5821SDavid S. Miller tmpl->id.proto, family)) != NULL) { 82537b08e34SDavid S. Miller to_put = x0; 8261da177e4SLinus Torvalds error = -EEXIST; 8271da177e4SLinus Torvalds goto out; 8281da177e4SLinus Torvalds } 829673c09beSAlexey Dobriyan x = xfrm_state_alloc(&init_net); 8301da177e4SLinus Torvalds if (x == NULL) { 8311da177e4SLinus Torvalds error = -ENOMEM; 8321da177e4SLinus Torvalds goto out; 8331da177e4SLinus Torvalds } 8341da177e4SLinus Torvalds /* Initialize temporary selector matching only 8351da177e4SLinus Torvalds * to current session. */ 8361da177e4SLinus Torvalds xfrm_init_tempsel(x, fl, tmpl, daddr, saddr, family); 8371da177e4SLinus Torvalds 838e0d1caa7SVenkat Yekkirala error = security_xfrm_state_alloc_acquire(x, pol->security, fl->secid); 839e0d1caa7SVenkat Yekkirala if (error) { 840e0d1caa7SVenkat Yekkirala x->km.state = XFRM_STATE_DEAD; 84137b08e34SDavid S. Miller to_put = x; 842e0d1caa7SVenkat Yekkirala x = NULL; 843e0d1caa7SVenkat Yekkirala goto out; 844e0d1caa7SVenkat Yekkirala } 845e0d1caa7SVenkat Yekkirala 8461da177e4SLinus Torvalds if (km_query(x, tmpl, pol) == 0) { 8471da177e4SLinus Torvalds x->km.state = XFRM_STATE_ACQ; 8489d4139c7SAlexey Dobriyan list_add(&x->km.all, &init_net.xfrm.state_all); 84973d189dcSAlexey Dobriyan hlist_add_head(&x->bydst, init_net.xfrm.state_bydst+h); 850667bbcb6SMasahide NAKAMURA h = xfrm_src_hash(daddr, saddr, family); 851d320bbb3SAlexey Dobriyan hlist_add_head(&x->bysrc, init_net.xfrm.state_bysrc+h); 8521da177e4SLinus Torvalds if (x->id.spi) { 8531da177e4SLinus Torvalds h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, family); 854b754a4fdSAlexey Dobriyan hlist_add_head(&x->byspi, init_net.xfrm.state_byspi+h); 8551da177e4SLinus Torvalds } 85601e67d08SDavid S. Miller x->lft.hard_add_expires_seconds = sysctl_xfrm_acq_expires; 85701e67d08SDavid S. Miller x->timer.expires = jiffies + sysctl_xfrm_acq_expires*HZ; 8581da177e4SLinus Torvalds add_timer(&x->timer); 8592fab22f2SPatrick McHardy xfrm_state_num++; 8602fab22f2SPatrick McHardy xfrm_hash_grow_check(x->bydst.next != NULL); 8611da177e4SLinus Torvalds } else { 8621da177e4SLinus Torvalds x->km.state = XFRM_STATE_DEAD; 86337b08e34SDavid S. Miller to_put = x; 8641da177e4SLinus Torvalds x = NULL; 8651da177e4SLinus Torvalds error = -ESRCH; 8661da177e4SLinus Torvalds } 8671da177e4SLinus Torvalds } 8681da177e4SLinus Torvalds out: 8691da177e4SLinus Torvalds if (x) 8701da177e4SLinus Torvalds xfrm_state_hold(x); 8711da177e4SLinus Torvalds else 8721da177e4SLinus Torvalds *err = acquire_in_progress ? -EAGAIN : error; 8731da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_lock); 87437b08e34SDavid S. Miller if (to_put) 87537b08e34SDavid S. Miller xfrm_state_put(to_put); 8761da177e4SLinus Torvalds return x; 8771da177e4SLinus Torvalds } 8781da177e4SLinus Torvalds 879628529b6SJamal Hadi Salim struct xfrm_state * 880628529b6SJamal Hadi Salim xfrm_stateonly_find(xfrm_address_t *daddr, xfrm_address_t *saddr, 881628529b6SJamal Hadi Salim unsigned short family, u8 mode, u8 proto, u32 reqid) 882628529b6SJamal Hadi Salim { 8834bda4f25SPavel Emelyanov unsigned int h; 884628529b6SJamal Hadi Salim struct xfrm_state *rx = NULL, *x = NULL; 885628529b6SJamal Hadi Salim struct hlist_node *entry; 886628529b6SJamal Hadi Salim 887628529b6SJamal Hadi Salim spin_lock(&xfrm_state_lock); 8884bda4f25SPavel Emelyanov h = xfrm_dst_hash(daddr, saddr, reqid, family); 88973d189dcSAlexey Dobriyan hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+h, bydst) { 890628529b6SJamal Hadi Salim if (x->props.family == family && 891628529b6SJamal Hadi Salim x->props.reqid == reqid && 892628529b6SJamal Hadi Salim !(x->props.flags & XFRM_STATE_WILDRECV) && 893628529b6SJamal Hadi Salim xfrm_state_addr_check(x, daddr, saddr, family) && 894628529b6SJamal Hadi Salim mode == x->props.mode && 895628529b6SJamal Hadi Salim proto == x->id.proto && 896628529b6SJamal Hadi Salim x->km.state == XFRM_STATE_VALID) { 897628529b6SJamal Hadi Salim rx = x; 898628529b6SJamal Hadi Salim break; 899628529b6SJamal Hadi Salim } 900628529b6SJamal Hadi Salim } 901628529b6SJamal Hadi Salim 902628529b6SJamal Hadi Salim if (rx) 903628529b6SJamal Hadi Salim xfrm_state_hold(rx); 904628529b6SJamal Hadi Salim spin_unlock(&xfrm_state_lock); 905628529b6SJamal Hadi Salim 906628529b6SJamal Hadi Salim 907628529b6SJamal Hadi Salim return rx; 908628529b6SJamal Hadi Salim } 909628529b6SJamal Hadi Salim EXPORT_SYMBOL(xfrm_stateonly_find); 910628529b6SJamal Hadi Salim 9111da177e4SLinus Torvalds static void __xfrm_state_insert(struct xfrm_state *x) 9121da177e4SLinus Torvalds { 913a624c108SDavid S. Miller unsigned int h; 9141da177e4SLinus Torvalds 9159d4a706dSDavid S. Miller x->genid = ++xfrm_state_genid; 9169d4a706dSDavid S. Miller 9179d4139c7SAlexey Dobriyan list_add(&x->km.all, &init_net.xfrm.state_all); 9184c563f76STimo Teras 919c1969f29SDavid S. Miller h = xfrm_dst_hash(&x->id.daddr, &x->props.saddr, 920c1969f29SDavid S. Miller x->props.reqid, x->props.family); 92173d189dcSAlexey Dobriyan hlist_add_head(&x->bydst, init_net.xfrm.state_bydst+h); 9221da177e4SLinus Torvalds 923667bbcb6SMasahide NAKAMURA h = xfrm_src_hash(&x->id.daddr, &x->props.saddr, x->props.family); 924d320bbb3SAlexey Dobriyan hlist_add_head(&x->bysrc, init_net.xfrm.state_bysrc+h); 9256c44e6b7SMasahide NAKAMURA 9267b4dc360SMasahide NAKAMURA if (x->id.spi) { 9276c44e6b7SMasahide NAKAMURA h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, 9286c44e6b7SMasahide NAKAMURA x->props.family); 9291da177e4SLinus Torvalds 930b754a4fdSAlexey Dobriyan hlist_add_head(&x->byspi, init_net.xfrm.state_byspi+h); 9316c44e6b7SMasahide NAKAMURA } 9321da177e4SLinus Torvalds 933a47f0ce0SDavid S. Miller mod_timer(&x->timer, jiffies + HZ); 934a47f0ce0SDavid S. Miller if (x->replay_maxage) 935a47f0ce0SDavid S. Miller mod_timer(&x->rtimer, jiffies + x->replay_maxage); 936f8cd5488SJamal Hadi Salim 9371da177e4SLinus Torvalds wake_up(&km_waitq); 938f034b5d4SDavid S. Miller 939f034b5d4SDavid S. Miller xfrm_state_num++; 940f034b5d4SDavid S. Miller 941918049f0SDavid S. Miller xfrm_hash_grow_check(x->bydst.next != NULL); 9421da177e4SLinus Torvalds } 9431da177e4SLinus Torvalds 944c7f5ea3aSDavid S. Miller /* xfrm_state_lock is held */ 945c7f5ea3aSDavid S. Miller static void __xfrm_state_bump_genids(struct xfrm_state *xnew) 946c7f5ea3aSDavid S. Miller { 947c7f5ea3aSDavid S. Miller unsigned short family = xnew->props.family; 948c7f5ea3aSDavid S. Miller u32 reqid = xnew->props.reqid; 949c7f5ea3aSDavid S. Miller struct xfrm_state *x; 950c7f5ea3aSDavid S. Miller struct hlist_node *entry; 951c7f5ea3aSDavid S. Miller unsigned int h; 952c7f5ea3aSDavid S. Miller 953c1969f29SDavid S. Miller h = xfrm_dst_hash(&xnew->id.daddr, &xnew->props.saddr, reqid, family); 95473d189dcSAlexey Dobriyan hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+h, bydst) { 955c7f5ea3aSDavid S. Miller if (x->props.family == family && 956c7f5ea3aSDavid S. Miller x->props.reqid == reqid && 957c1969f29SDavid S. Miller !xfrm_addr_cmp(&x->id.daddr, &xnew->id.daddr, family) && 958c1969f29SDavid S. Miller !xfrm_addr_cmp(&x->props.saddr, &xnew->props.saddr, family)) 959c7f5ea3aSDavid S. Miller x->genid = xfrm_state_genid; 960c7f5ea3aSDavid S. Miller } 961c7f5ea3aSDavid S. Miller } 962c7f5ea3aSDavid S. Miller 9631da177e4SLinus Torvalds void xfrm_state_insert(struct xfrm_state *x) 9641da177e4SLinus Torvalds { 9651da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_lock); 966c7f5ea3aSDavid S. Miller __xfrm_state_bump_genids(x); 9671da177e4SLinus Torvalds __xfrm_state_insert(x); 9681da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_lock); 9691da177e4SLinus Torvalds } 9701da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_insert); 9711da177e4SLinus Torvalds 9722770834cSDavid S. Miller /* xfrm_state_lock is held */ 9732770834cSDavid S. Miller static struct xfrm_state *__find_acq_core(unsigned short family, u8 mode, u32 reqid, u8 proto, xfrm_address_t *daddr, xfrm_address_t *saddr, int create) 9742770834cSDavid S. Miller { 975c1969f29SDavid S. Miller unsigned int h = xfrm_dst_hash(daddr, saddr, reqid, family); 9768f126e37SDavid S. Miller struct hlist_node *entry; 9772770834cSDavid S. Miller struct xfrm_state *x; 9782770834cSDavid S. Miller 97973d189dcSAlexey Dobriyan hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+h, bydst) { 9802770834cSDavid S. Miller if (x->props.reqid != reqid || 9812770834cSDavid S. Miller x->props.mode != mode || 9822770834cSDavid S. Miller x->props.family != family || 9832770834cSDavid S. Miller x->km.state != XFRM_STATE_ACQ || 98475e252d9SJoy Latten x->id.spi != 0 || 98575e252d9SJoy Latten x->id.proto != proto) 9862770834cSDavid S. Miller continue; 9872770834cSDavid S. Miller 9882770834cSDavid S. Miller switch (family) { 9892770834cSDavid S. Miller case AF_INET: 9902770834cSDavid S. Miller if (x->id.daddr.a4 != daddr->a4 || 9912770834cSDavid S. Miller x->props.saddr.a4 != saddr->a4) 9922770834cSDavid S. Miller continue; 9932770834cSDavid S. Miller break; 9942770834cSDavid S. Miller case AF_INET6: 9952770834cSDavid S. Miller if (!ipv6_addr_equal((struct in6_addr *)x->id.daddr.a6, 9962770834cSDavid S. Miller (struct in6_addr *)daddr) || 9972770834cSDavid S. Miller !ipv6_addr_equal((struct in6_addr *) 9982770834cSDavid S. Miller x->props.saddr.a6, 9992770834cSDavid S. Miller (struct in6_addr *)saddr)) 10002770834cSDavid S. Miller continue; 10012770834cSDavid S. Miller break; 10023ff50b79SStephen Hemminger } 10032770834cSDavid S. Miller 10042770834cSDavid S. Miller xfrm_state_hold(x); 10052770834cSDavid S. Miller return x; 10062770834cSDavid S. Miller } 10072770834cSDavid S. Miller 10082770834cSDavid S. Miller if (!create) 10092770834cSDavid S. Miller return NULL; 10102770834cSDavid S. Miller 1011673c09beSAlexey Dobriyan x = xfrm_state_alloc(&init_net); 10122770834cSDavid S. Miller if (likely(x)) { 10132770834cSDavid S. Miller switch (family) { 10142770834cSDavid S. Miller case AF_INET: 10152770834cSDavid S. Miller x->sel.daddr.a4 = daddr->a4; 10162770834cSDavid S. Miller x->sel.saddr.a4 = saddr->a4; 10172770834cSDavid S. Miller x->sel.prefixlen_d = 32; 10182770834cSDavid S. Miller x->sel.prefixlen_s = 32; 10192770834cSDavid S. Miller x->props.saddr.a4 = saddr->a4; 10202770834cSDavid S. Miller x->id.daddr.a4 = daddr->a4; 10212770834cSDavid S. Miller break; 10222770834cSDavid S. Miller 10232770834cSDavid S. Miller case AF_INET6: 10242770834cSDavid S. Miller ipv6_addr_copy((struct in6_addr *)x->sel.daddr.a6, 10252770834cSDavid S. Miller (struct in6_addr *)daddr); 10262770834cSDavid S. Miller ipv6_addr_copy((struct in6_addr *)x->sel.saddr.a6, 10272770834cSDavid S. Miller (struct in6_addr *)saddr); 10282770834cSDavid S. Miller x->sel.prefixlen_d = 128; 10292770834cSDavid S. Miller x->sel.prefixlen_s = 128; 10302770834cSDavid S. Miller ipv6_addr_copy((struct in6_addr *)x->props.saddr.a6, 10312770834cSDavid S. Miller (struct in6_addr *)saddr); 10322770834cSDavid S. Miller ipv6_addr_copy((struct in6_addr *)x->id.daddr.a6, 10332770834cSDavid S. Miller (struct in6_addr *)daddr); 10342770834cSDavid S. Miller break; 10353ff50b79SStephen Hemminger } 10362770834cSDavid S. Miller 10372770834cSDavid S. Miller x->km.state = XFRM_STATE_ACQ; 10382770834cSDavid S. Miller x->id.proto = proto; 10392770834cSDavid S. Miller x->props.family = family; 10402770834cSDavid S. Miller x->props.mode = mode; 10412770834cSDavid S. Miller x->props.reqid = reqid; 104201e67d08SDavid S. Miller x->lft.hard_add_expires_seconds = sysctl_xfrm_acq_expires; 10432770834cSDavid S. Miller xfrm_state_hold(x); 104401e67d08SDavid S. Miller x->timer.expires = jiffies + sysctl_xfrm_acq_expires*HZ; 10452770834cSDavid S. Miller add_timer(&x->timer); 10469d4139c7SAlexey Dobriyan list_add(&x->km.all, &init_net.xfrm.state_all); 104773d189dcSAlexey Dobriyan hlist_add_head(&x->bydst, init_net.xfrm.state_bydst+h); 1048667bbcb6SMasahide NAKAMURA h = xfrm_src_hash(daddr, saddr, family); 1049d320bbb3SAlexey Dobriyan hlist_add_head(&x->bysrc, init_net.xfrm.state_bysrc+h); 1050918049f0SDavid S. Miller 1051918049f0SDavid S. Miller xfrm_state_num++; 1052918049f0SDavid S. Miller 1053918049f0SDavid S. Miller xfrm_hash_grow_check(x->bydst.next != NULL); 10542770834cSDavid S. Miller } 10552770834cSDavid S. Miller 10562770834cSDavid S. Miller return x; 10572770834cSDavid S. Miller } 10582770834cSDavid S. Miller 10591da177e4SLinus Torvalds static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq); 10601da177e4SLinus Torvalds 10611da177e4SLinus Torvalds int xfrm_state_add(struct xfrm_state *x) 10621da177e4SLinus Torvalds { 106337b08e34SDavid S. Miller struct xfrm_state *x1, *to_put; 10641da177e4SLinus Torvalds int family; 10651da177e4SLinus Torvalds int err; 1066eb2971b6SMasahide NAKAMURA int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY); 10671da177e4SLinus Torvalds 10681da177e4SLinus Torvalds family = x->props.family; 10691da177e4SLinus Torvalds 107037b08e34SDavid S. Miller to_put = NULL; 107137b08e34SDavid S. Miller 10721da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_lock); 10731da177e4SLinus Torvalds 1074edcd5821SDavid S. Miller x1 = __xfrm_state_locate(x, use_spi, family); 10751da177e4SLinus Torvalds if (x1) { 107637b08e34SDavid S. Miller to_put = x1; 10771da177e4SLinus Torvalds x1 = NULL; 10781da177e4SLinus Torvalds err = -EEXIST; 10791da177e4SLinus Torvalds goto out; 10801da177e4SLinus Torvalds } 10811da177e4SLinus Torvalds 1082eb2971b6SMasahide NAKAMURA if (use_spi && x->km.seq) { 10831da177e4SLinus Torvalds x1 = __xfrm_find_acq_byseq(x->km.seq); 108475e252d9SJoy Latten if (x1 && ((x1->id.proto != x->id.proto) || 108575e252d9SJoy Latten xfrm_addr_cmp(&x1->id.daddr, &x->id.daddr, family))) { 108637b08e34SDavid S. Miller to_put = x1; 10871da177e4SLinus Torvalds x1 = NULL; 10881da177e4SLinus Torvalds } 10891da177e4SLinus Torvalds } 10901da177e4SLinus Torvalds 1091eb2971b6SMasahide NAKAMURA if (use_spi && !x1) 10922770834cSDavid S. Miller x1 = __find_acq_core(family, x->props.mode, x->props.reqid, 10932770834cSDavid S. Miller x->id.proto, 10941da177e4SLinus Torvalds &x->id.daddr, &x->props.saddr, 0); 10951da177e4SLinus Torvalds 1096c7f5ea3aSDavid S. Miller __xfrm_state_bump_genids(x); 10971da177e4SLinus Torvalds __xfrm_state_insert(x); 10981da177e4SLinus Torvalds err = 0; 10991da177e4SLinus Torvalds 11001da177e4SLinus Torvalds out: 11011da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_lock); 11021da177e4SLinus Torvalds 11031da177e4SLinus Torvalds if (x1) { 11041da177e4SLinus Torvalds xfrm_state_delete(x1); 11051da177e4SLinus Torvalds xfrm_state_put(x1); 11061da177e4SLinus Torvalds } 11071da177e4SLinus Torvalds 110837b08e34SDavid S. Miller if (to_put) 110937b08e34SDavid S. Miller xfrm_state_put(to_put); 111037b08e34SDavid S. Miller 11111da177e4SLinus Torvalds return err; 11121da177e4SLinus Torvalds } 11131da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_add); 11141da177e4SLinus Torvalds 111580c9abaaSShinta Sugimoto #ifdef CONFIG_XFRM_MIGRATE 11166666351dSEric Dumazet static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp) 111780c9abaaSShinta Sugimoto { 111880c9abaaSShinta Sugimoto int err = -ENOMEM; 1119673c09beSAlexey Dobriyan struct xfrm_state *x = xfrm_state_alloc(&init_net); 112080c9abaaSShinta Sugimoto if (!x) 112180c9abaaSShinta Sugimoto goto error; 112280c9abaaSShinta Sugimoto 112380c9abaaSShinta Sugimoto memcpy(&x->id, &orig->id, sizeof(x->id)); 112480c9abaaSShinta Sugimoto memcpy(&x->sel, &orig->sel, sizeof(x->sel)); 112580c9abaaSShinta Sugimoto memcpy(&x->lft, &orig->lft, sizeof(x->lft)); 112680c9abaaSShinta Sugimoto x->props.mode = orig->props.mode; 112780c9abaaSShinta Sugimoto x->props.replay_window = orig->props.replay_window; 112880c9abaaSShinta Sugimoto x->props.reqid = orig->props.reqid; 112980c9abaaSShinta Sugimoto x->props.family = orig->props.family; 113080c9abaaSShinta Sugimoto x->props.saddr = orig->props.saddr; 113180c9abaaSShinta Sugimoto 113280c9abaaSShinta Sugimoto if (orig->aalg) { 113380c9abaaSShinta Sugimoto x->aalg = xfrm_algo_clone(orig->aalg); 113480c9abaaSShinta Sugimoto if (!x->aalg) 113580c9abaaSShinta Sugimoto goto error; 113680c9abaaSShinta Sugimoto } 113780c9abaaSShinta Sugimoto x->props.aalgo = orig->props.aalgo; 113880c9abaaSShinta Sugimoto 113980c9abaaSShinta Sugimoto if (orig->ealg) { 114080c9abaaSShinta Sugimoto x->ealg = xfrm_algo_clone(orig->ealg); 114180c9abaaSShinta Sugimoto if (!x->ealg) 114280c9abaaSShinta Sugimoto goto error; 114380c9abaaSShinta Sugimoto } 114480c9abaaSShinta Sugimoto x->props.ealgo = orig->props.ealgo; 114580c9abaaSShinta Sugimoto 114680c9abaaSShinta Sugimoto if (orig->calg) { 114780c9abaaSShinta Sugimoto x->calg = xfrm_algo_clone(orig->calg); 114880c9abaaSShinta Sugimoto if (!x->calg) 114980c9abaaSShinta Sugimoto goto error; 115080c9abaaSShinta Sugimoto } 115180c9abaaSShinta Sugimoto x->props.calgo = orig->props.calgo; 115280c9abaaSShinta Sugimoto 115380c9abaaSShinta Sugimoto if (orig->encap) { 115480c9abaaSShinta Sugimoto x->encap = kmemdup(orig->encap, sizeof(*x->encap), GFP_KERNEL); 115580c9abaaSShinta Sugimoto if (!x->encap) 115680c9abaaSShinta Sugimoto goto error; 115780c9abaaSShinta Sugimoto } 115880c9abaaSShinta Sugimoto 115980c9abaaSShinta Sugimoto if (orig->coaddr) { 116080c9abaaSShinta Sugimoto x->coaddr = kmemdup(orig->coaddr, sizeof(*x->coaddr), 116180c9abaaSShinta Sugimoto GFP_KERNEL); 116280c9abaaSShinta Sugimoto if (!x->coaddr) 116380c9abaaSShinta Sugimoto goto error; 116480c9abaaSShinta Sugimoto } 116580c9abaaSShinta Sugimoto 116680c9abaaSShinta Sugimoto err = xfrm_init_state(x); 116780c9abaaSShinta Sugimoto if (err) 116880c9abaaSShinta Sugimoto goto error; 116980c9abaaSShinta Sugimoto 117080c9abaaSShinta Sugimoto x->props.flags = orig->props.flags; 117180c9abaaSShinta Sugimoto 117280c9abaaSShinta Sugimoto x->curlft.add_time = orig->curlft.add_time; 117380c9abaaSShinta Sugimoto x->km.state = orig->km.state; 117480c9abaaSShinta Sugimoto x->km.seq = orig->km.seq; 117580c9abaaSShinta Sugimoto 117680c9abaaSShinta Sugimoto return x; 117780c9abaaSShinta Sugimoto 117880c9abaaSShinta Sugimoto error: 117980c9abaaSShinta Sugimoto if (errp) 118080c9abaaSShinta Sugimoto *errp = err; 118180c9abaaSShinta Sugimoto if (x) { 118280c9abaaSShinta Sugimoto kfree(x->aalg); 118380c9abaaSShinta Sugimoto kfree(x->ealg); 118480c9abaaSShinta Sugimoto kfree(x->calg); 118580c9abaaSShinta Sugimoto kfree(x->encap); 118680c9abaaSShinta Sugimoto kfree(x->coaddr); 118780c9abaaSShinta Sugimoto } 118880c9abaaSShinta Sugimoto kfree(x); 118980c9abaaSShinta Sugimoto return NULL; 119080c9abaaSShinta Sugimoto } 119180c9abaaSShinta Sugimoto 119280c9abaaSShinta Sugimoto /* xfrm_state_lock is held */ 119380c9abaaSShinta Sugimoto struct xfrm_state * xfrm_migrate_state_find(struct xfrm_migrate *m) 119480c9abaaSShinta Sugimoto { 119580c9abaaSShinta Sugimoto unsigned int h; 119680c9abaaSShinta Sugimoto struct xfrm_state *x; 119780c9abaaSShinta Sugimoto struct hlist_node *entry; 119880c9abaaSShinta Sugimoto 119980c9abaaSShinta Sugimoto if (m->reqid) { 120080c9abaaSShinta Sugimoto h = xfrm_dst_hash(&m->old_daddr, &m->old_saddr, 120180c9abaaSShinta Sugimoto m->reqid, m->old_family); 120273d189dcSAlexey Dobriyan hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+h, bydst) { 120380c9abaaSShinta Sugimoto if (x->props.mode != m->mode || 120480c9abaaSShinta Sugimoto x->id.proto != m->proto) 120580c9abaaSShinta Sugimoto continue; 120680c9abaaSShinta Sugimoto if (m->reqid && x->props.reqid != m->reqid) 120780c9abaaSShinta Sugimoto continue; 120880c9abaaSShinta Sugimoto if (xfrm_addr_cmp(&x->id.daddr, &m->old_daddr, 120980c9abaaSShinta Sugimoto m->old_family) || 121080c9abaaSShinta Sugimoto xfrm_addr_cmp(&x->props.saddr, &m->old_saddr, 121180c9abaaSShinta Sugimoto m->old_family)) 121280c9abaaSShinta Sugimoto continue; 121380c9abaaSShinta Sugimoto xfrm_state_hold(x); 121480c9abaaSShinta Sugimoto return x; 121580c9abaaSShinta Sugimoto } 121680c9abaaSShinta Sugimoto } else { 121780c9abaaSShinta Sugimoto h = xfrm_src_hash(&m->old_daddr, &m->old_saddr, 121880c9abaaSShinta Sugimoto m->old_family); 1219d320bbb3SAlexey Dobriyan hlist_for_each_entry(x, entry, init_net.xfrm.state_bysrc+h, bysrc) { 122080c9abaaSShinta Sugimoto if (x->props.mode != m->mode || 122180c9abaaSShinta Sugimoto x->id.proto != m->proto) 122280c9abaaSShinta Sugimoto continue; 122380c9abaaSShinta Sugimoto if (xfrm_addr_cmp(&x->id.daddr, &m->old_daddr, 122480c9abaaSShinta Sugimoto m->old_family) || 122580c9abaaSShinta Sugimoto xfrm_addr_cmp(&x->props.saddr, &m->old_saddr, 122680c9abaaSShinta Sugimoto m->old_family)) 122780c9abaaSShinta Sugimoto continue; 122880c9abaaSShinta Sugimoto xfrm_state_hold(x); 122980c9abaaSShinta Sugimoto return x; 123080c9abaaSShinta Sugimoto } 123180c9abaaSShinta Sugimoto } 123280c9abaaSShinta Sugimoto 123380c9abaaSShinta Sugimoto return NULL; 123480c9abaaSShinta Sugimoto } 123580c9abaaSShinta Sugimoto EXPORT_SYMBOL(xfrm_migrate_state_find); 123680c9abaaSShinta Sugimoto 123780c9abaaSShinta Sugimoto struct xfrm_state * xfrm_state_migrate(struct xfrm_state *x, 123880c9abaaSShinta Sugimoto struct xfrm_migrate *m) 123980c9abaaSShinta Sugimoto { 124080c9abaaSShinta Sugimoto struct xfrm_state *xc; 124180c9abaaSShinta Sugimoto int err; 124280c9abaaSShinta Sugimoto 124380c9abaaSShinta Sugimoto xc = xfrm_state_clone(x, &err); 124480c9abaaSShinta Sugimoto if (!xc) 124580c9abaaSShinta Sugimoto return NULL; 124680c9abaaSShinta Sugimoto 124780c9abaaSShinta Sugimoto memcpy(&xc->id.daddr, &m->new_daddr, sizeof(xc->id.daddr)); 124880c9abaaSShinta Sugimoto memcpy(&xc->props.saddr, &m->new_saddr, sizeof(xc->props.saddr)); 124980c9abaaSShinta Sugimoto 125080c9abaaSShinta Sugimoto /* add state */ 125180c9abaaSShinta Sugimoto if (!xfrm_addr_cmp(&x->id.daddr, &m->new_daddr, m->new_family)) { 125280c9abaaSShinta Sugimoto /* a care is needed when the destination address of the 125380c9abaaSShinta Sugimoto state is to be updated as it is a part of triplet */ 125480c9abaaSShinta Sugimoto xfrm_state_insert(xc); 125580c9abaaSShinta Sugimoto } else { 125680c9abaaSShinta Sugimoto if ((err = xfrm_state_add(xc)) < 0) 125780c9abaaSShinta Sugimoto goto error; 125880c9abaaSShinta Sugimoto } 125980c9abaaSShinta Sugimoto 126080c9abaaSShinta Sugimoto return xc; 126180c9abaaSShinta Sugimoto error: 126280c9abaaSShinta Sugimoto kfree(xc); 126380c9abaaSShinta Sugimoto return NULL; 126480c9abaaSShinta Sugimoto } 126580c9abaaSShinta Sugimoto EXPORT_SYMBOL(xfrm_state_migrate); 126680c9abaaSShinta Sugimoto #endif 126780c9abaaSShinta Sugimoto 12681da177e4SLinus Torvalds int xfrm_state_update(struct xfrm_state *x) 12691da177e4SLinus Torvalds { 127037b08e34SDavid S. Miller struct xfrm_state *x1, *to_put; 12711da177e4SLinus Torvalds int err; 1272eb2971b6SMasahide NAKAMURA int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY); 12731da177e4SLinus Torvalds 127437b08e34SDavid S. Miller to_put = NULL; 127537b08e34SDavid S. Miller 12761da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_lock); 1277edcd5821SDavid S. Miller x1 = __xfrm_state_locate(x, use_spi, x->props.family); 12781da177e4SLinus Torvalds 12791da177e4SLinus Torvalds err = -ESRCH; 12801da177e4SLinus Torvalds if (!x1) 12811da177e4SLinus Torvalds goto out; 12821da177e4SLinus Torvalds 12831da177e4SLinus Torvalds if (xfrm_state_kern(x1)) { 128437b08e34SDavid S. Miller to_put = x1; 12851da177e4SLinus Torvalds err = -EEXIST; 12861da177e4SLinus Torvalds goto out; 12871da177e4SLinus Torvalds } 12881da177e4SLinus Torvalds 12891da177e4SLinus Torvalds if (x1->km.state == XFRM_STATE_ACQ) { 12901da177e4SLinus Torvalds __xfrm_state_insert(x); 12911da177e4SLinus Torvalds x = NULL; 12921da177e4SLinus Torvalds } 12931da177e4SLinus Torvalds err = 0; 12941da177e4SLinus Torvalds 12951da177e4SLinus Torvalds out: 12961da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_lock); 12971da177e4SLinus Torvalds 129837b08e34SDavid S. Miller if (to_put) 129937b08e34SDavid S. Miller xfrm_state_put(to_put); 130037b08e34SDavid S. Miller 13011da177e4SLinus Torvalds if (err) 13021da177e4SLinus Torvalds return err; 13031da177e4SLinus Torvalds 13041da177e4SLinus Torvalds if (!x) { 13051da177e4SLinus Torvalds xfrm_state_delete(x1); 13061da177e4SLinus Torvalds xfrm_state_put(x1); 13071da177e4SLinus Torvalds return 0; 13081da177e4SLinus Torvalds } 13091da177e4SLinus Torvalds 13101da177e4SLinus Torvalds err = -EINVAL; 13111da177e4SLinus Torvalds spin_lock_bh(&x1->lock); 13121da177e4SLinus Torvalds if (likely(x1->km.state == XFRM_STATE_VALID)) { 13131da177e4SLinus Torvalds if (x->encap && x1->encap) 13141da177e4SLinus Torvalds memcpy(x1->encap, x->encap, sizeof(*x1->encap)); 1315060f02a3SNoriaki TAKAMIYA if (x->coaddr && x1->coaddr) { 1316060f02a3SNoriaki TAKAMIYA memcpy(x1->coaddr, x->coaddr, sizeof(*x1->coaddr)); 1317060f02a3SNoriaki TAKAMIYA } 1318060f02a3SNoriaki TAKAMIYA if (!use_spi && memcmp(&x1->sel, &x->sel, sizeof(x1->sel))) 1319060f02a3SNoriaki TAKAMIYA memcpy(&x1->sel, &x->sel, sizeof(x1->sel)); 13201da177e4SLinus Torvalds memcpy(&x1->lft, &x->lft, sizeof(x1->lft)); 13211da177e4SLinus Torvalds x1->km.dying = 0; 13221da177e4SLinus Torvalds 1323a47f0ce0SDavid S. Miller mod_timer(&x1->timer, jiffies + HZ); 13241da177e4SLinus Torvalds if (x1->curlft.use_time) 13251da177e4SLinus Torvalds xfrm_state_check_expire(x1); 13261da177e4SLinus Torvalds 13271da177e4SLinus Torvalds err = 0; 13281da177e4SLinus Torvalds } 13291da177e4SLinus Torvalds spin_unlock_bh(&x1->lock); 13301da177e4SLinus Torvalds 13311da177e4SLinus Torvalds xfrm_state_put(x1); 13321da177e4SLinus Torvalds 13331da177e4SLinus Torvalds return err; 13341da177e4SLinus Torvalds } 13351da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_update); 13361da177e4SLinus Torvalds 13371da177e4SLinus Torvalds int xfrm_state_check_expire(struct xfrm_state *x) 13381da177e4SLinus Torvalds { 13391da177e4SLinus Torvalds if (!x->curlft.use_time) 13409d729f72SJames Morris x->curlft.use_time = get_seconds(); 13411da177e4SLinus Torvalds 13421da177e4SLinus Torvalds if (x->km.state != XFRM_STATE_VALID) 13431da177e4SLinus Torvalds return -EINVAL; 13441da177e4SLinus Torvalds 13451da177e4SLinus Torvalds if (x->curlft.bytes >= x->lft.hard_byte_limit || 13461da177e4SLinus Torvalds x->curlft.packets >= x->lft.hard_packet_limit) { 13474666faabSHerbert Xu x->km.state = XFRM_STATE_EXPIRED; 1348a47f0ce0SDavid S. Miller mod_timer(&x->timer, jiffies); 13491da177e4SLinus Torvalds return -EINVAL; 13501da177e4SLinus Torvalds } 13511da177e4SLinus Torvalds 13521da177e4SLinus Torvalds if (!x->km.dying && 13531da177e4SLinus Torvalds (x->curlft.bytes >= x->lft.soft_byte_limit || 13544666faabSHerbert Xu x->curlft.packets >= x->lft.soft_packet_limit)) { 13554666faabSHerbert Xu x->km.dying = 1; 135653bc6b4dSJamal Hadi Salim km_state_expired(x, 0, 0); 13574666faabSHerbert Xu } 13581da177e4SLinus Torvalds return 0; 13591da177e4SLinus Torvalds } 13601da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_check_expire); 13611da177e4SLinus Torvalds 13621da177e4SLinus Torvalds struct xfrm_state * 1363a94cfd19SAl Viro xfrm_state_lookup(xfrm_address_t *daddr, __be32 spi, u8 proto, 13641da177e4SLinus Torvalds unsigned short family) 13651da177e4SLinus Torvalds { 13661da177e4SLinus Torvalds struct xfrm_state *x; 13671da177e4SLinus Torvalds 13681da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_lock); 1369edcd5821SDavid S. Miller x = __xfrm_state_lookup(daddr, spi, proto, family); 13701da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_lock); 13711da177e4SLinus Torvalds return x; 13721da177e4SLinus Torvalds } 13731da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_lookup); 13741da177e4SLinus Torvalds 13751da177e4SLinus Torvalds struct xfrm_state * 1376eb2971b6SMasahide NAKAMURA xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr, 1377eb2971b6SMasahide NAKAMURA u8 proto, unsigned short family) 1378eb2971b6SMasahide NAKAMURA { 1379eb2971b6SMasahide NAKAMURA struct xfrm_state *x; 1380eb2971b6SMasahide NAKAMURA 1381eb2971b6SMasahide NAKAMURA spin_lock_bh(&xfrm_state_lock); 1382edcd5821SDavid S. Miller x = __xfrm_state_lookup_byaddr(daddr, saddr, proto, family); 1383eb2971b6SMasahide NAKAMURA spin_unlock_bh(&xfrm_state_lock); 1384eb2971b6SMasahide NAKAMURA return x; 1385eb2971b6SMasahide NAKAMURA } 1386eb2971b6SMasahide NAKAMURA EXPORT_SYMBOL(xfrm_state_lookup_byaddr); 1387eb2971b6SMasahide NAKAMURA 1388eb2971b6SMasahide NAKAMURA struct xfrm_state * 13891da177e4SLinus Torvalds xfrm_find_acq(u8 mode, u32 reqid, u8 proto, 13901da177e4SLinus Torvalds xfrm_address_t *daddr, xfrm_address_t *saddr, 13911da177e4SLinus Torvalds int create, unsigned short family) 13921da177e4SLinus Torvalds { 13931da177e4SLinus Torvalds struct xfrm_state *x; 13941da177e4SLinus Torvalds 13951da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_lock); 13962770834cSDavid S. Miller x = __find_acq_core(family, mode, reqid, proto, daddr, saddr, create); 13971da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_lock); 13982770834cSDavid S. Miller 13991da177e4SLinus Torvalds return x; 14001da177e4SLinus Torvalds } 14011da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_find_acq); 14021da177e4SLinus Torvalds 140341a49cc3SMasahide NAKAMURA #ifdef CONFIG_XFRM_SUB_POLICY 140441a49cc3SMasahide NAKAMURA int 140541a49cc3SMasahide NAKAMURA xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n, 140641a49cc3SMasahide NAKAMURA unsigned short family) 140741a49cc3SMasahide NAKAMURA { 140841a49cc3SMasahide NAKAMURA int err = 0; 140941a49cc3SMasahide NAKAMURA struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); 141041a49cc3SMasahide NAKAMURA if (!afinfo) 141141a49cc3SMasahide NAKAMURA return -EAFNOSUPPORT; 141241a49cc3SMasahide NAKAMURA 141341a49cc3SMasahide NAKAMURA spin_lock_bh(&xfrm_state_lock); 141441a49cc3SMasahide NAKAMURA if (afinfo->tmpl_sort) 141541a49cc3SMasahide NAKAMURA err = afinfo->tmpl_sort(dst, src, n); 141641a49cc3SMasahide NAKAMURA spin_unlock_bh(&xfrm_state_lock); 141741a49cc3SMasahide NAKAMURA xfrm_state_put_afinfo(afinfo); 141841a49cc3SMasahide NAKAMURA return err; 141941a49cc3SMasahide NAKAMURA } 142041a49cc3SMasahide NAKAMURA EXPORT_SYMBOL(xfrm_tmpl_sort); 142141a49cc3SMasahide NAKAMURA 142241a49cc3SMasahide NAKAMURA int 142341a49cc3SMasahide NAKAMURA xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n, 142441a49cc3SMasahide NAKAMURA unsigned short family) 142541a49cc3SMasahide NAKAMURA { 142641a49cc3SMasahide NAKAMURA int err = 0; 142741a49cc3SMasahide NAKAMURA struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); 142841a49cc3SMasahide NAKAMURA if (!afinfo) 142941a49cc3SMasahide NAKAMURA return -EAFNOSUPPORT; 143041a49cc3SMasahide NAKAMURA 143141a49cc3SMasahide NAKAMURA spin_lock_bh(&xfrm_state_lock); 143241a49cc3SMasahide NAKAMURA if (afinfo->state_sort) 143341a49cc3SMasahide NAKAMURA err = afinfo->state_sort(dst, src, n); 143441a49cc3SMasahide NAKAMURA spin_unlock_bh(&xfrm_state_lock); 143541a49cc3SMasahide NAKAMURA xfrm_state_put_afinfo(afinfo); 143641a49cc3SMasahide NAKAMURA return err; 143741a49cc3SMasahide NAKAMURA } 143841a49cc3SMasahide NAKAMURA EXPORT_SYMBOL(xfrm_state_sort); 143941a49cc3SMasahide NAKAMURA #endif 144041a49cc3SMasahide NAKAMURA 14411da177e4SLinus Torvalds /* Silly enough, but I'm lazy to build resolution list */ 14421da177e4SLinus Torvalds 14431da177e4SLinus Torvalds static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq) 14441da177e4SLinus Torvalds { 14451da177e4SLinus Torvalds int i; 14461da177e4SLinus Torvalds 1447f034b5d4SDavid S. Miller for (i = 0; i <= xfrm_state_hmask; i++) { 14488f126e37SDavid S. Miller struct hlist_node *entry; 14498f126e37SDavid S. Miller struct xfrm_state *x; 14508f126e37SDavid S. Miller 145173d189dcSAlexey Dobriyan hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+i, bydst) { 14528f126e37SDavid S. Miller if (x->km.seq == seq && 14538f126e37SDavid S. Miller x->km.state == XFRM_STATE_ACQ) { 14541da177e4SLinus Torvalds xfrm_state_hold(x); 14551da177e4SLinus Torvalds return x; 14561da177e4SLinus Torvalds } 14571da177e4SLinus Torvalds } 14581da177e4SLinus Torvalds } 14591da177e4SLinus Torvalds return NULL; 14601da177e4SLinus Torvalds } 14611da177e4SLinus Torvalds 14621da177e4SLinus Torvalds struct xfrm_state *xfrm_find_acq_byseq(u32 seq) 14631da177e4SLinus Torvalds { 14641da177e4SLinus Torvalds struct xfrm_state *x; 14651da177e4SLinus Torvalds 14661da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_lock); 14671da177e4SLinus Torvalds x = __xfrm_find_acq_byseq(seq); 14681da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_lock); 14691da177e4SLinus Torvalds return x; 14701da177e4SLinus Torvalds } 14711da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_find_acq_byseq); 14721da177e4SLinus Torvalds 14731da177e4SLinus Torvalds u32 xfrm_get_acqseq(void) 14741da177e4SLinus Torvalds { 14751da177e4SLinus Torvalds u32 res; 14761da177e4SLinus Torvalds static u32 acqseq; 14771da177e4SLinus Torvalds static DEFINE_SPINLOCK(acqseq_lock); 14781da177e4SLinus Torvalds 14791da177e4SLinus Torvalds spin_lock_bh(&acqseq_lock); 14801da177e4SLinus Torvalds res = (++acqseq ? : ++acqseq); 14811da177e4SLinus Torvalds spin_unlock_bh(&acqseq_lock); 14821da177e4SLinus Torvalds return res; 14831da177e4SLinus Torvalds } 14841da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_get_acqseq); 14851da177e4SLinus Torvalds 1486658b219eSHerbert Xu int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high) 14871da177e4SLinus Torvalds { 1488f034b5d4SDavid S. Miller unsigned int h; 14891da177e4SLinus Torvalds struct xfrm_state *x0; 1490658b219eSHerbert Xu int err = -ENOENT; 1491658b219eSHerbert Xu __be32 minspi = htonl(low); 1492658b219eSHerbert Xu __be32 maxspi = htonl(high); 14931da177e4SLinus Torvalds 1494658b219eSHerbert Xu spin_lock_bh(&x->lock); 1495658b219eSHerbert Xu if (x->km.state == XFRM_STATE_DEAD) 1496658b219eSHerbert Xu goto unlock; 1497658b219eSHerbert Xu 1498658b219eSHerbert Xu err = 0; 14991da177e4SLinus Torvalds if (x->id.spi) 1500658b219eSHerbert Xu goto unlock; 1501658b219eSHerbert Xu 1502658b219eSHerbert Xu err = -ENOENT; 15031da177e4SLinus Torvalds 15041da177e4SLinus Torvalds if (minspi == maxspi) { 15051da177e4SLinus Torvalds x0 = xfrm_state_lookup(&x->id.daddr, minspi, x->id.proto, x->props.family); 15061da177e4SLinus Torvalds if (x0) { 15071da177e4SLinus Torvalds xfrm_state_put(x0); 1508658b219eSHerbert Xu goto unlock; 15091da177e4SLinus Torvalds } 15101da177e4SLinus Torvalds x->id.spi = minspi; 15111da177e4SLinus Torvalds } else { 15121da177e4SLinus Torvalds u32 spi = 0; 151326977b4eSAl Viro for (h=0; h<high-low+1; h++) { 151426977b4eSAl Viro spi = low + net_random()%(high-low+1); 15151da177e4SLinus Torvalds x0 = xfrm_state_lookup(&x->id.daddr, htonl(spi), x->id.proto, x->props.family); 15161da177e4SLinus Torvalds if (x0 == NULL) { 15171da177e4SLinus Torvalds x->id.spi = htonl(spi); 15181da177e4SLinus Torvalds break; 15191da177e4SLinus Torvalds } 15201da177e4SLinus Torvalds xfrm_state_put(x0); 15211da177e4SLinus Torvalds } 15221da177e4SLinus Torvalds } 15231da177e4SLinus Torvalds if (x->id.spi) { 15241da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_lock); 15251da177e4SLinus Torvalds h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, x->props.family); 1526b754a4fdSAlexey Dobriyan hlist_add_head(&x->byspi, init_net.xfrm.state_byspi+h); 15271da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_lock); 1528658b219eSHerbert Xu 1529658b219eSHerbert Xu err = 0; 15301da177e4SLinus Torvalds } 1531658b219eSHerbert Xu 1532658b219eSHerbert Xu unlock: 1533658b219eSHerbert Xu spin_unlock_bh(&x->lock); 1534658b219eSHerbert Xu 1535658b219eSHerbert Xu return err; 15361da177e4SLinus Torvalds } 15371da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_alloc_spi); 15381da177e4SLinus Torvalds 15394c563f76STimo Teras int xfrm_state_walk(struct xfrm_state_walk *walk, 15404c563f76STimo Teras int (*func)(struct xfrm_state *, int, void*), 15411da177e4SLinus Torvalds void *data) 15421da177e4SLinus Torvalds { 154312a169e7SHerbert Xu struct xfrm_state *state; 154412a169e7SHerbert Xu struct xfrm_state_walk *x; 15451da177e4SLinus Torvalds int err = 0; 15461da177e4SLinus Torvalds 154712a169e7SHerbert Xu if (walk->seq != 0 && list_empty(&walk->all)) 15484c563f76STimo Teras return 0; 15494c563f76STimo Teras 15501da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_lock); 155112a169e7SHerbert Xu if (list_empty(&walk->all)) 15529d4139c7SAlexey Dobriyan x = list_first_entry(&init_net.xfrm.state_all, struct xfrm_state_walk, all); 155312a169e7SHerbert Xu else 155412a169e7SHerbert Xu x = list_entry(&walk->all, struct xfrm_state_walk, all); 15559d4139c7SAlexey Dobriyan list_for_each_entry_from(x, &init_net.xfrm.state_all, all) { 155612a169e7SHerbert Xu if (x->state == XFRM_STATE_DEAD) 15574c563f76STimo Teras continue; 155812a169e7SHerbert Xu state = container_of(x, struct xfrm_state, km); 155912a169e7SHerbert Xu if (!xfrm_id_proto_match(state->id.proto, walk->proto)) 156094b9bb54SJamal Hadi Salim continue; 156112a169e7SHerbert Xu err = func(state, walk->seq, data); 15624c563f76STimo Teras if (err) { 156312a169e7SHerbert Xu list_move_tail(&walk->all, &x->all); 156494b9bb54SJamal Hadi Salim goto out; 156594b9bb54SJamal Hadi Salim } 156612a169e7SHerbert Xu walk->seq++; 15674c563f76STimo Teras } 156812a169e7SHerbert Xu if (walk->seq == 0) { 15691da177e4SLinus Torvalds err = -ENOENT; 15701da177e4SLinus Torvalds goto out; 15711da177e4SLinus Torvalds } 157212a169e7SHerbert Xu list_del_init(&walk->all); 15731da177e4SLinus Torvalds out: 15741da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_lock); 15751da177e4SLinus Torvalds return err; 15761da177e4SLinus Torvalds } 15771da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_walk); 15781da177e4SLinus Torvalds 15795c182458SHerbert Xu void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto) 15805c182458SHerbert Xu { 158112a169e7SHerbert Xu INIT_LIST_HEAD(&walk->all); 15825c182458SHerbert Xu walk->proto = proto; 158312a169e7SHerbert Xu walk->state = XFRM_STATE_DEAD; 158412a169e7SHerbert Xu walk->seq = 0; 15855c182458SHerbert Xu } 15865c182458SHerbert Xu EXPORT_SYMBOL(xfrm_state_walk_init); 15875c182458SHerbert Xu 1588abb81c4fSHerbert Xu void xfrm_state_walk_done(struct xfrm_state_walk *walk) 1589abb81c4fSHerbert Xu { 159012a169e7SHerbert Xu if (list_empty(&walk->all)) 15915c182458SHerbert Xu return; 15925c182458SHerbert Xu 159312a169e7SHerbert Xu spin_lock_bh(&xfrm_state_lock); 159412a169e7SHerbert Xu list_del(&walk->all); 159512a169e7SHerbert Xu spin_lock_bh(&xfrm_state_lock); 1596abb81c4fSHerbert Xu } 1597abb81c4fSHerbert Xu EXPORT_SYMBOL(xfrm_state_walk_done); 1598abb81c4fSHerbert Xu 1599f8cd5488SJamal Hadi Salim 1600f8cd5488SJamal Hadi Salim void xfrm_replay_notify(struct xfrm_state *x, int event) 1601f8cd5488SJamal Hadi Salim { 1602f8cd5488SJamal Hadi Salim struct km_event c; 1603f8cd5488SJamal Hadi Salim /* we send notify messages in case 1604f8cd5488SJamal Hadi Salim * 1. we updated on of the sequence numbers, and the seqno difference 1605f8cd5488SJamal Hadi Salim * is at least x->replay_maxdiff, in this case we also update the 1606f8cd5488SJamal Hadi Salim * timeout of our timer function 1607f8cd5488SJamal Hadi Salim * 2. if x->replay_maxage has elapsed since last update, 1608f8cd5488SJamal Hadi Salim * and there were changes 1609f8cd5488SJamal Hadi Salim * 1610f8cd5488SJamal Hadi Salim * The state structure must be locked! 1611f8cd5488SJamal Hadi Salim */ 1612f8cd5488SJamal Hadi Salim 1613f8cd5488SJamal Hadi Salim switch (event) { 1614f8cd5488SJamal Hadi Salim case XFRM_REPLAY_UPDATE: 1615f8cd5488SJamal Hadi Salim if (x->replay_maxdiff && 1616f8cd5488SJamal Hadi Salim (x->replay.seq - x->preplay.seq < x->replay_maxdiff) && 16172717096aSJamal Hadi Salim (x->replay.oseq - x->preplay.oseq < x->replay_maxdiff)) { 16182717096aSJamal Hadi Salim if (x->xflags & XFRM_TIME_DEFER) 16192717096aSJamal Hadi Salim event = XFRM_REPLAY_TIMEOUT; 16202717096aSJamal Hadi Salim else 1621f8cd5488SJamal Hadi Salim return; 16222717096aSJamal Hadi Salim } 1623f8cd5488SJamal Hadi Salim 1624f8cd5488SJamal Hadi Salim break; 1625f8cd5488SJamal Hadi Salim 1626f8cd5488SJamal Hadi Salim case XFRM_REPLAY_TIMEOUT: 1627f8cd5488SJamal Hadi Salim if ((x->replay.seq == x->preplay.seq) && 1628f8cd5488SJamal Hadi Salim (x->replay.bitmap == x->preplay.bitmap) && 16292717096aSJamal Hadi Salim (x->replay.oseq == x->preplay.oseq)) { 16302717096aSJamal Hadi Salim x->xflags |= XFRM_TIME_DEFER; 1631f8cd5488SJamal Hadi Salim return; 16322717096aSJamal Hadi Salim } 1633f8cd5488SJamal Hadi Salim 1634f8cd5488SJamal Hadi Salim break; 1635f8cd5488SJamal Hadi Salim } 1636f8cd5488SJamal Hadi Salim 1637f8cd5488SJamal Hadi Salim memcpy(&x->preplay, &x->replay, sizeof(struct xfrm_replay_state)); 1638f8cd5488SJamal Hadi Salim c.event = XFRM_MSG_NEWAE; 1639f8cd5488SJamal Hadi Salim c.data.aevent = event; 1640f8cd5488SJamal Hadi Salim km_state_notify(x, &c); 1641f8cd5488SJamal Hadi Salim 1642f8cd5488SJamal Hadi Salim if (x->replay_maxage && 1643a47f0ce0SDavid S. Miller !mod_timer(&x->rtimer, jiffies + x->replay_maxage)) 16442717096aSJamal Hadi Salim x->xflags &= ~XFRM_TIME_DEFER; 16452717096aSJamal Hadi Salim } 1646f8cd5488SJamal Hadi Salim 1647f8cd5488SJamal Hadi Salim static void xfrm_replay_timer_handler(unsigned long data) 1648f8cd5488SJamal Hadi Salim { 1649f8cd5488SJamal Hadi Salim struct xfrm_state *x = (struct xfrm_state*)data; 1650f8cd5488SJamal Hadi Salim 1651f8cd5488SJamal Hadi Salim spin_lock(&x->lock); 1652f8cd5488SJamal Hadi Salim 16532717096aSJamal Hadi Salim if (x->km.state == XFRM_STATE_VALID) { 16542717096aSJamal Hadi Salim if (xfrm_aevent_is_on()) 1655f8cd5488SJamal Hadi Salim xfrm_replay_notify(x, XFRM_REPLAY_TIMEOUT); 16562717096aSJamal Hadi Salim else 16572717096aSJamal Hadi Salim x->xflags |= XFRM_TIME_DEFER; 16582717096aSJamal Hadi Salim } 1659f8cd5488SJamal Hadi Salim 1660f8cd5488SJamal Hadi Salim spin_unlock(&x->lock); 1661f8cd5488SJamal Hadi Salim } 1662f8cd5488SJamal Hadi Salim 1663afeb14b4SPaul Moore int xfrm_replay_check(struct xfrm_state *x, 1664afeb14b4SPaul Moore struct sk_buff *skb, __be32 net_seq) 16651da177e4SLinus Torvalds { 16661da177e4SLinus Torvalds u32 diff; 1667a252cc23SAl Viro u32 seq = ntohl(net_seq); 16681da177e4SLinus Torvalds 16691da177e4SLinus Torvalds if (unlikely(seq == 0)) 1670afeb14b4SPaul Moore goto err; 16711da177e4SLinus Torvalds 16721da177e4SLinus Torvalds if (likely(seq > x->replay.seq)) 16731da177e4SLinus Torvalds return 0; 16741da177e4SLinus Torvalds 16751da177e4SLinus Torvalds diff = x->replay.seq - seq; 16764c4d51a7SHerbert Xu if (diff >= min_t(unsigned int, x->props.replay_window, 16774c4d51a7SHerbert Xu sizeof(x->replay.bitmap) * 8)) { 16781da177e4SLinus Torvalds x->stats.replay_window++; 1679afeb14b4SPaul Moore goto err; 16801da177e4SLinus Torvalds } 16811da177e4SLinus Torvalds 16821da177e4SLinus Torvalds if (x->replay.bitmap & (1U << diff)) { 16831da177e4SLinus Torvalds x->stats.replay++; 1684afeb14b4SPaul Moore goto err; 16851da177e4SLinus Torvalds } 16861da177e4SLinus Torvalds return 0; 1687afeb14b4SPaul Moore 1688afeb14b4SPaul Moore err: 1689afeb14b4SPaul Moore xfrm_audit_state_replay(x, skb, net_seq); 1690afeb14b4SPaul Moore return -EINVAL; 16911da177e4SLinus Torvalds } 16921da177e4SLinus Torvalds 169361f4627bSAl Viro void xfrm_replay_advance(struct xfrm_state *x, __be32 net_seq) 16941da177e4SLinus Torvalds { 16951da177e4SLinus Torvalds u32 diff; 169661f4627bSAl Viro u32 seq = ntohl(net_seq); 16971da177e4SLinus Torvalds 16981da177e4SLinus Torvalds if (seq > x->replay.seq) { 16991da177e4SLinus Torvalds diff = seq - x->replay.seq; 17001da177e4SLinus Torvalds if (diff < x->props.replay_window) 17011da177e4SLinus Torvalds x->replay.bitmap = ((x->replay.bitmap) << diff) | 1; 17021da177e4SLinus Torvalds else 17031da177e4SLinus Torvalds x->replay.bitmap = 1; 17041da177e4SLinus Torvalds x->replay.seq = seq; 17051da177e4SLinus Torvalds } else { 17061da177e4SLinus Torvalds diff = x->replay.seq - seq; 17071da177e4SLinus Torvalds x->replay.bitmap |= (1U << diff); 17081da177e4SLinus Torvalds } 1709f8cd5488SJamal Hadi Salim 1710f8cd5488SJamal Hadi Salim if (xfrm_aevent_is_on()) 1711f8cd5488SJamal Hadi Salim xfrm_replay_notify(x, XFRM_REPLAY_UPDATE); 17121da177e4SLinus Torvalds } 17131da177e4SLinus Torvalds 1714df01812eSDenis Cheng static LIST_HEAD(xfrm_km_list); 17151da177e4SLinus Torvalds static DEFINE_RWLOCK(xfrm_km_lock); 17161da177e4SLinus Torvalds 171726b15dadSJamal Hadi Salim void km_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c) 17181da177e4SLinus Torvalds { 17191da177e4SLinus Torvalds struct xfrm_mgr *km; 17201da177e4SLinus Torvalds 172126b15dadSJamal Hadi Salim read_lock(&xfrm_km_lock); 172226b15dadSJamal Hadi Salim list_for_each_entry(km, &xfrm_km_list, list) 172326b15dadSJamal Hadi Salim if (km->notify_policy) 172426b15dadSJamal Hadi Salim km->notify_policy(xp, dir, c); 172526b15dadSJamal Hadi Salim read_unlock(&xfrm_km_lock); 172626b15dadSJamal Hadi Salim } 172726b15dadSJamal Hadi Salim 172826b15dadSJamal Hadi Salim void km_state_notify(struct xfrm_state *x, struct km_event *c) 172926b15dadSJamal Hadi Salim { 173026b15dadSJamal Hadi Salim struct xfrm_mgr *km; 173126b15dadSJamal Hadi Salim read_lock(&xfrm_km_lock); 173226b15dadSJamal Hadi Salim list_for_each_entry(km, &xfrm_km_list, list) 173326b15dadSJamal Hadi Salim if (km->notify) 173426b15dadSJamal Hadi Salim km->notify(x, c); 173526b15dadSJamal Hadi Salim read_unlock(&xfrm_km_lock); 173626b15dadSJamal Hadi Salim } 173726b15dadSJamal Hadi Salim 173826b15dadSJamal Hadi Salim EXPORT_SYMBOL(km_policy_notify); 173926b15dadSJamal Hadi Salim EXPORT_SYMBOL(km_state_notify); 174026b15dadSJamal Hadi Salim 174153bc6b4dSJamal Hadi Salim void km_state_expired(struct xfrm_state *x, int hard, u32 pid) 174226b15dadSJamal Hadi Salim { 174326b15dadSJamal Hadi Salim struct km_event c; 174426b15dadSJamal Hadi Salim 1745bf08867fSHerbert Xu c.data.hard = hard; 174653bc6b4dSJamal Hadi Salim c.pid = pid; 1747f60f6b8fSHerbert Xu c.event = XFRM_MSG_EXPIRE; 174826b15dadSJamal Hadi Salim km_state_notify(x, &c); 17491da177e4SLinus Torvalds 17501da177e4SLinus Torvalds if (hard) 17511da177e4SLinus Torvalds wake_up(&km_waitq); 17521da177e4SLinus Torvalds } 17531da177e4SLinus Torvalds 175453bc6b4dSJamal Hadi Salim EXPORT_SYMBOL(km_state_expired); 175526b15dadSJamal Hadi Salim /* 175626b15dadSJamal Hadi Salim * We send to all registered managers regardless of failure 175726b15dadSJamal Hadi Salim * We are happy with one success 175826b15dadSJamal Hadi Salim */ 1759980ebd25SJamal Hadi Salim int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol) 17601da177e4SLinus Torvalds { 176126b15dadSJamal Hadi Salim int err = -EINVAL, acqret; 17621da177e4SLinus Torvalds struct xfrm_mgr *km; 17631da177e4SLinus Torvalds 17641da177e4SLinus Torvalds read_lock(&xfrm_km_lock); 17651da177e4SLinus Torvalds list_for_each_entry(km, &xfrm_km_list, list) { 176626b15dadSJamal Hadi Salim acqret = km->acquire(x, t, pol, XFRM_POLICY_OUT); 176726b15dadSJamal Hadi Salim if (!acqret) 176826b15dadSJamal Hadi Salim err = acqret; 17691da177e4SLinus Torvalds } 17701da177e4SLinus Torvalds read_unlock(&xfrm_km_lock); 17711da177e4SLinus Torvalds return err; 17721da177e4SLinus Torvalds } 1773980ebd25SJamal Hadi Salim EXPORT_SYMBOL(km_query); 17741da177e4SLinus Torvalds 17755d36b180SAl Viro int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport) 17761da177e4SLinus Torvalds { 17771da177e4SLinus Torvalds int err = -EINVAL; 17781da177e4SLinus Torvalds struct xfrm_mgr *km; 17791da177e4SLinus Torvalds 17801da177e4SLinus Torvalds read_lock(&xfrm_km_lock); 17811da177e4SLinus Torvalds list_for_each_entry(km, &xfrm_km_list, list) { 17821da177e4SLinus Torvalds if (km->new_mapping) 17831da177e4SLinus Torvalds err = km->new_mapping(x, ipaddr, sport); 17841da177e4SLinus Torvalds if (!err) 17851da177e4SLinus Torvalds break; 17861da177e4SLinus Torvalds } 17871da177e4SLinus Torvalds read_unlock(&xfrm_km_lock); 17881da177e4SLinus Torvalds return err; 17891da177e4SLinus Torvalds } 17901da177e4SLinus Torvalds EXPORT_SYMBOL(km_new_mapping); 17911da177e4SLinus Torvalds 17926c5c8ca7SJamal Hadi Salim void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 pid) 17931da177e4SLinus Torvalds { 179426b15dadSJamal Hadi Salim struct km_event c; 17951da177e4SLinus Torvalds 1796bf08867fSHerbert Xu c.data.hard = hard; 17976c5c8ca7SJamal Hadi Salim c.pid = pid; 1798f60f6b8fSHerbert Xu c.event = XFRM_MSG_POLEXPIRE; 179926b15dadSJamal Hadi Salim km_policy_notify(pol, dir, &c); 18001da177e4SLinus Torvalds 18011da177e4SLinus Torvalds if (hard) 18021da177e4SLinus Torvalds wake_up(&km_waitq); 18031da177e4SLinus Torvalds } 1804a70fcb0bSDavid S. Miller EXPORT_SYMBOL(km_policy_expired); 18051da177e4SLinus Torvalds 18062d60abc2SEric Dumazet #ifdef CONFIG_XFRM_MIGRATE 180780c9abaaSShinta Sugimoto int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type, 180813c1d189SArnaud Ebalard struct xfrm_migrate *m, int num_migrate, 180913c1d189SArnaud Ebalard struct xfrm_kmaddress *k) 181080c9abaaSShinta Sugimoto { 181180c9abaaSShinta Sugimoto int err = -EINVAL; 181280c9abaaSShinta Sugimoto int ret; 181380c9abaaSShinta Sugimoto struct xfrm_mgr *km; 181480c9abaaSShinta Sugimoto 181580c9abaaSShinta Sugimoto read_lock(&xfrm_km_lock); 181680c9abaaSShinta Sugimoto list_for_each_entry(km, &xfrm_km_list, list) { 181780c9abaaSShinta Sugimoto if (km->migrate) { 181813c1d189SArnaud Ebalard ret = km->migrate(sel, dir, type, m, num_migrate, k); 181980c9abaaSShinta Sugimoto if (!ret) 182080c9abaaSShinta Sugimoto err = ret; 182180c9abaaSShinta Sugimoto } 182280c9abaaSShinta Sugimoto } 182380c9abaaSShinta Sugimoto read_unlock(&xfrm_km_lock); 182480c9abaaSShinta Sugimoto return err; 182580c9abaaSShinta Sugimoto } 182680c9abaaSShinta Sugimoto EXPORT_SYMBOL(km_migrate); 18272d60abc2SEric Dumazet #endif 182880c9abaaSShinta Sugimoto 182997a64b45SMasahide NAKAMURA int km_report(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr) 183097a64b45SMasahide NAKAMURA { 183197a64b45SMasahide NAKAMURA int err = -EINVAL; 183297a64b45SMasahide NAKAMURA int ret; 183397a64b45SMasahide NAKAMURA struct xfrm_mgr *km; 183497a64b45SMasahide NAKAMURA 183597a64b45SMasahide NAKAMURA read_lock(&xfrm_km_lock); 183697a64b45SMasahide NAKAMURA list_for_each_entry(km, &xfrm_km_list, list) { 183797a64b45SMasahide NAKAMURA if (km->report) { 183897a64b45SMasahide NAKAMURA ret = km->report(proto, sel, addr); 183997a64b45SMasahide NAKAMURA if (!ret) 184097a64b45SMasahide NAKAMURA err = ret; 184197a64b45SMasahide NAKAMURA } 184297a64b45SMasahide NAKAMURA } 184397a64b45SMasahide NAKAMURA read_unlock(&xfrm_km_lock); 184497a64b45SMasahide NAKAMURA return err; 184597a64b45SMasahide NAKAMURA } 184697a64b45SMasahide NAKAMURA EXPORT_SYMBOL(km_report); 184797a64b45SMasahide NAKAMURA 18481da177e4SLinus Torvalds int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen) 18491da177e4SLinus Torvalds { 18501da177e4SLinus Torvalds int err; 18511da177e4SLinus Torvalds u8 *data; 18521da177e4SLinus Torvalds struct xfrm_mgr *km; 18531da177e4SLinus Torvalds struct xfrm_policy *pol = NULL; 18541da177e4SLinus Torvalds 18551da177e4SLinus Torvalds if (optlen <= 0 || optlen > PAGE_SIZE) 18561da177e4SLinus Torvalds return -EMSGSIZE; 18571da177e4SLinus Torvalds 18581da177e4SLinus Torvalds data = kmalloc(optlen, GFP_KERNEL); 18591da177e4SLinus Torvalds if (!data) 18601da177e4SLinus Torvalds return -ENOMEM; 18611da177e4SLinus Torvalds 18621da177e4SLinus Torvalds err = -EFAULT; 18631da177e4SLinus Torvalds if (copy_from_user(data, optval, optlen)) 18641da177e4SLinus Torvalds goto out; 18651da177e4SLinus Torvalds 18661da177e4SLinus Torvalds err = -EINVAL; 18671da177e4SLinus Torvalds read_lock(&xfrm_km_lock); 18681da177e4SLinus Torvalds list_for_each_entry(km, &xfrm_km_list, list) { 1869cb969f07SVenkat Yekkirala pol = km->compile_policy(sk, optname, data, 18701da177e4SLinus Torvalds optlen, &err); 18711da177e4SLinus Torvalds if (err >= 0) 18721da177e4SLinus Torvalds break; 18731da177e4SLinus Torvalds } 18741da177e4SLinus Torvalds read_unlock(&xfrm_km_lock); 18751da177e4SLinus Torvalds 18761da177e4SLinus Torvalds if (err >= 0) { 18771da177e4SLinus Torvalds xfrm_sk_policy_insert(sk, err, pol); 18781da177e4SLinus Torvalds xfrm_pol_put(pol); 18791da177e4SLinus Torvalds err = 0; 18801da177e4SLinus Torvalds } 18811da177e4SLinus Torvalds 18821da177e4SLinus Torvalds out: 18831da177e4SLinus Torvalds kfree(data); 18841da177e4SLinus Torvalds return err; 18851da177e4SLinus Torvalds } 18861da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_user_policy); 18871da177e4SLinus Torvalds 18881da177e4SLinus Torvalds int xfrm_register_km(struct xfrm_mgr *km) 18891da177e4SLinus Torvalds { 18901da177e4SLinus Torvalds write_lock_bh(&xfrm_km_lock); 18911da177e4SLinus Torvalds list_add_tail(&km->list, &xfrm_km_list); 18921da177e4SLinus Torvalds write_unlock_bh(&xfrm_km_lock); 18931da177e4SLinus Torvalds return 0; 18941da177e4SLinus Torvalds } 18951da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_register_km); 18961da177e4SLinus Torvalds 18971da177e4SLinus Torvalds int xfrm_unregister_km(struct xfrm_mgr *km) 18981da177e4SLinus Torvalds { 18991da177e4SLinus Torvalds write_lock_bh(&xfrm_km_lock); 19001da177e4SLinus Torvalds list_del(&km->list); 19011da177e4SLinus Torvalds write_unlock_bh(&xfrm_km_lock); 19021da177e4SLinus Torvalds return 0; 19031da177e4SLinus Torvalds } 19041da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_unregister_km); 19051da177e4SLinus Torvalds 19061da177e4SLinus Torvalds int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo) 19071da177e4SLinus Torvalds { 19081da177e4SLinus Torvalds int err = 0; 19091da177e4SLinus Torvalds if (unlikely(afinfo == NULL)) 19101da177e4SLinus Torvalds return -EINVAL; 19111da177e4SLinus Torvalds if (unlikely(afinfo->family >= NPROTO)) 19121da177e4SLinus Torvalds return -EAFNOSUPPORT; 1913f3111502SIngo Molnar write_lock_bh(&xfrm_state_afinfo_lock); 19141da177e4SLinus Torvalds if (unlikely(xfrm_state_afinfo[afinfo->family] != NULL)) 19151da177e4SLinus Torvalds err = -ENOBUFS; 1916edcd5821SDavid S. Miller else 19171da177e4SLinus Torvalds xfrm_state_afinfo[afinfo->family] = afinfo; 1918f3111502SIngo Molnar write_unlock_bh(&xfrm_state_afinfo_lock); 19191da177e4SLinus Torvalds return err; 19201da177e4SLinus Torvalds } 19211da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_register_afinfo); 19221da177e4SLinus Torvalds 19231da177e4SLinus Torvalds int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo) 19241da177e4SLinus Torvalds { 19251da177e4SLinus Torvalds int err = 0; 19261da177e4SLinus Torvalds if (unlikely(afinfo == NULL)) 19271da177e4SLinus Torvalds return -EINVAL; 19281da177e4SLinus Torvalds if (unlikely(afinfo->family >= NPROTO)) 19291da177e4SLinus Torvalds return -EAFNOSUPPORT; 1930f3111502SIngo Molnar write_lock_bh(&xfrm_state_afinfo_lock); 19311da177e4SLinus Torvalds if (likely(xfrm_state_afinfo[afinfo->family] != NULL)) { 19321da177e4SLinus Torvalds if (unlikely(xfrm_state_afinfo[afinfo->family] != afinfo)) 19331da177e4SLinus Torvalds err = -EINVAL; 1934edcd5821SDavid S. Miller else 19351da177e4SLinus Torvalds xfrm_state_afinfo[afinfo->family] = NULL; 19361da177e4SLinus Torvalds } 1937f3111502SIngo Molnar write_unlock_bh(&xfrm_state_afinfo_lock); 19381da177e4SLinus Torvalds return err; 19391da177e4SLinus Torvalds } 19401da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_unregister_afinfo); 19411da177e4SLinus Torvalds 194217c2a42aSHerbert Xu static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family) 19431da177e4SLinus Torvalds { 19441da177e4SLinus Torvalds struct xfrm_state_afinfo *afinfo; 19451da177e4SLinus Torvalds if (unlikely(family >= NPROTO)) 19461da177e4SLinus Torvalds return NULL; 19471da177e4SLinus Torvalds read_lock(&xfrm_state_afinfo_lock); 19481da177e4SLinus Torvalds afinfo = xfrm_state_afinfo[family]; 1949546be240SHerbert Xu if (unlikely(!afinfo)) 19501da177e4SLinus Torvalds read_unlock(&xfrm_state_afinfo_lock); 19511da177e4SLinus Torvalds return afinfo; 19521da177e4SLinus Torvalds } 19531da177e4SLinus Torvalds 195417c2a42aSHerbert Xu static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo) 19559a429c49SEric Dumazet __releases(xfrm_state_afinfo_lock) 19561da177e4SLinus Torvalds { 1957546be240SHerbert Xu read_unlock(&xfrm_state_afinfo_lock); 19581da177e4SLinus Torvalds } 19591da177e4SLinus Torvalds 19601da177e4SLinus Torvalds /* Temporarily located here until net/xfrm/xfrm_tunnel.c is created */ 19611da177e4SLinus Torvalds void xfrm_state_delete_tunnel(struct xfrm_state *x) 19621da177e4SLinus Torvalds { 19631da177e4SLinus Torvalds if (x->tunnel) { 19641da177e4SLinus Torvalds struct xfrm_state *t = x->tunnel; 19651da177e4SLinus Torvalds 19661da177e4SLinus Torvalds if (atomic_read(&t->tunnel_users) == 2) 19671da177e4SLinus Torvalds xfrm_state_delete(t); 19681da177e4SLinus Torvalds atomic_dec(&t->tunnel_users); 19691da177e4SLinus Torvalds xfrm_state_put(t); 19701da177e4SLinus Torvalds x->tunnel = NULL; 19711da177e4SLinus Torvalds } 19721da177e4SLinus Torvalds } 19731da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_delete_tunnel); 19741da177e4SLinus Torvalds 19751da177e4SLinus Torvalds int xfrm_state_mtu(struct xfrm_state *x, int mtu) 19761da177e4SLinus Torvalds { 1977c5c25238SPatrick McHardy int res; 19781da177e4SLinus Torvalds 19791da177e4SLinus Torvalds spin_lock_bh(&x->lock); 19801da177e4SLinus Torvalds if (x->km.state == XFRM_STATE_VALID && 1981c5c25238SPatrick McHardy x->type && x->type->get_mtu) 1982c5c25238SPatrick McHardy res = x->type->get_mtu(x, mtu); 19831da177e4SLinus Torvalds else 198428121617SPatrick McHardy res = mtu - x->props.header_len; 19851da177e4SLinus Torvalds spin_unlock_bh(&x->lock); 19861da177e4SLinus Torvalds return res; 19871da177e4SLinus Torvalds } 19881da177e4SLinus Torvalds 198972cb6962SHerbert Xu int xfrm_init_state(struct xfrm_state *x) 199072cb6962SHerbert Xu { 1991d094cd83SHerbert Xu struct xfrm_state_afinfo *afinfo; 1992df9dcb45SKazunori MIYAZAWA struct xfrm_mode *inner_mode; 1993d094cd83SHerbert Xu int family = x->props.family; 199472cb6962SHerbert Xu int err; 199572cb6962SHerbert Xu 1996d094cd83SHerbert Xu err = -EAFNOSUPPORT; 1997d094cd83SHerbert Xu afinfo = xfrm_state_get_afinfo(family); 1998d094cd83SHerbert Xu if (!afinfo) 1999d094cd83SHerbert Xu goto error; 2000d094cd83SHerbert Xu 2001d094cd83SHerbert Xu err = 0; 2002d094cd83SHerbert Xu if (afinfo->init_flags) 2003d094cd83SHerbert Xu err = afinfo->init_flags(x); 2004d094cd83SHerbert Xu 2005d094cd83SHerbert Xu xfrm_state_put_afinfo(afinfo); 2006d094cd83SHerbert Xu 2007d094cd83SHerbert Xu if (err) 2008d094cd83SHerbert Xu goto error; 2009d094cd83SHerbert Xu 2010d094cd83SHerbert Xu err = -EPROTONOSUPPORT; 2011df9dcb45SKazunori MIYAZAWA 2012df9dcb45SKazunori MIYAZAWA if (x->sel.family != AF_UNSPEC) { 2013df9dcb45SKazunori MIYAZAWA inner_mode = xfrm_get_mode(x->props.mode, x->sel.family); 2014df9dcb45SKazunori MIYAZAWA if (inner_mode == NULL) 201513996378SHerbert Xu goto error; 201613996378SHerbert Xu 2017df9dcb45SKazunori MIYAZAWA if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL) && 2018df9dcb45SKazunori MIYAZAWA family != x->sel.family) { 2019df9dcb45SKazunori MIYAZAWA xfrm_put_mode(inner_mode); 202013996378SHerbert Xu goto error; 2021df9dcb45SKazunori MIYAZAWA } 2022df9dcb45SKazunori MIYAZAWA 2023df9dcb45SKazunori MIYAZAWA x->inner_mode = inner_mode; 2024df9dcb45SKazunori MIYAZAWA } else { 2025df9dcb45SKazunori MIYAZAWA struct xfrm_mode *inner_mode_iaf; 2026df9dcb45SKazunori MIYAZAWA 2027df9dcb45SKazunori MIYAZAWA inner_mode = xfrm_get_mode(x->props.mode, AF_INET); 2028df9dcb45SKazunori MIYAZAWA if (inner_mode == NULL) 2029df9dcb45SKazunori MIYAZAWA goto error; 2030df9dcb45SKazunori MIYAZAWA 2031df9dcb45SKazunori MIYAZAWA if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL)) { 2032df9dcb45SKazunori MIYAZAWA xfrm_put_mode(inner_mode); 2033df9dcb45SKazunori MIYAZAWA goto error; 2034df9dcb45SKazunori MIYAZAWA } 2035df9dcb45SKazunori MIYAZAWA 2036df9dcb45SKazunori MIYAZAWA inner_mode_iaf = xfrm_get_mode(x->props.mode, AF_INET6); 2037df9dcb45SKazunori MIYAZAWA if (inner_mode_iaf == NULL) 2038df9dcb45SKazunori MIYAZAWA goto error; 2039df9dcb45SKazunori MIYAZAWA 2040df9dcb45SKazunori MIYAZAWA if (!(inner_mode_iaf->flags & XFRM_MODE_FLAG_TUNNEL)) { 2041df9dcb45SKazunori MIYAZAWA xfrm_put_mode(inner_mode_iaf); 2042df9dcb45SKazunori MIYAZAWA goto error; 2043df9dcb45SKazunori MIYAZAWA } 2044df9dcb45SKazunori MIYAZAWA 2045df9dcb45SKazunori MIYAZAWA if (x->props.family == AF_INET) { 2046df9dcb45SKazunori MIYAZAWA x->inner_mode = inner_mode; 2047df9dcb45SKazunori MIYAZAWA x->inner_mode_iaf = inner_mode_iaf; 2048df9dcb45SKazunori MIYAZAWA } else { 2049df9dcb45SKazunori MIYAZAWA x->inner_mode = inner_mode_iaf; 2050df9dcb45SKazunori MIYAZAWA x->inner_mode_iaf = inner_mode; 2051df9dcb45SKazunori MIYAZAWA } 2052df9dcb45SKazunori MIYAZAWA } 205313996378SHerbert Xu 2054d094cd83SHerbert Xu x->type = xfrm_get_type(x->id.proto, family); 205572cb6962SHerbert Xu if (x->type == NULL) 205672cb6962SHerbert Xu goto error; 205772cb6962SHerbert Xu 205872cb6962SHerbert Xu err = x->type->init_state(x); 205972cb6962SHerbert Xu if (err) 206072cb6962SHerbert Xu goto error; 206172cb6962SHerbert Xu 206213996378SHerbert Xu x->outer_mode = xfrm_get_mode(x->props.mode, family); 206313996378SHerbert Xu if (x->outer_mode == NULL) 2064b59f45d0SHerbert Xu goto error; 2065b59f45d0SHerbert Xu 206672cb6962SHerbert Xu x->km.state = XFRM_STATE_VALID; 206772cb6962SHerbert Xu 206872cb6962SHerbert Xu error: 206972cb6962SHerbert Xu return err; 207072cb6962SHerbert Xu } 207172cb6962SHerbert Xu 207272cb6962SHerbert Xu EXPORT_SYMBOL(xfrm_init_state); 20731da177e4SLinus Torvalds 2074d62ddc21SAlexey Dobriyan int __net_init xfrm_state_init(struct net *net) 20751da177e4SLinus Torvalds { 2076f034b5d4SDavid S. Miller unsigned int sz; 20771da177e4SLinus Torvalds 20789d4139c7SAlexey Dobriyan INIT_LIST_HEAD(&net->xfrm.state_all); 20799d4139c7SAlexey Dobriyan 2080f034b5d4SDavid S. Miller sz = sizeof(struct hlist_head) * 8; 2081f034b5d4SDavid S. Miller 208273d189dcSAlexey Dobriyan net->xfrm.state_bydst = xfrm_hash_alloc(sz); 208373d189dcSAlexey Dobriyan if (!net->xfrm.state_bydst) 208473d189dcSAlexey Dobriyan goto out_bydst; 2085d320bbb3SAlexey Dobriyan net->xfrm.state_bysrc = xfrm_hash_alloc(sz); 2086d320bbb3SAlexey Dobriyan if (!net->xfrm.state_bysrc) 2087d320bbb3SAlexey Dobriyan goto out_bysrc; 2088b754a4fdSAlexey Dobriyan net->xfrm.state_byspi = xfrm_hash_alloc(sz); 2089b754a4fdSAlexey Dobriyan if (!net->xfrm.state_byspi) 2090b754a4fdSAlexey Dobriyan goto out_byspi; 2091f034b5d4SDavid S. Miller xfrm_state_hmask = ((sz / sizeof(struct hlist_head)) - 1); 2092f034b5d4SDavid S. Miller 2093c4028958SDavid Howells INIT_WORK(&xfrm_state_gc_work, xfrm_state_gc_task); 2094d62ddc21SAlexey Dobriyan return 0; 209573d189dcSAlexey Dobriyan 2096b754a4fdSAlexey Dobriyan out_byspi: 2097b754a4fdSAlexey Dobriyan xfrm_hash_free(net->xfrm.state_bysrc, sz); 2098d320bbb3SAlexey Dobriyan out_bysrc: 2099d320bbb3SAlexey Dobriyan xfrm_hash_free(net->xfrm.state_bydst, sz); 210073d189dcSAlexey Dobriyan out_bydst: 210173d189dcSAlexey Dobriyan return -ENOMEM; 2102d62ddc21SAlexey Dobriyan } 2103d62ddc21SAlexey Dobriyan 2104d62ddc21SAlexey Dobriyan void xfrm_state_fini(struct net *net) 2105d62ddc21SAlexey Dobriyan { 210673d189dcSAlexey Dobriyan unsigned int sz; 210773d189dcSAlexey Dobriyan 21089d4139c7SAlexey Dobriyan WARN_ON(!list_empty(&net->xfrm.state_all)); 210973d189dcSAlexey Dobriyan 211073d189dcSAlexey Dobriyan sz = (xfrm_state_hmask + 1) * sizeof(struct hlist_head); 2111b754a4fdSAlexey Dobriyan WARN_ON(!hlist_empty(net->xfrm.state_byspi)); 2112b754a4fdSAlexey Dobriyan xfrm_hash_free(net->xfrm.state_byspi, sz); 2113d320bbb3SAlexey Dobriyan WARN_ON(!hlist_empty(net->xfrm.state_bysrc)); 2114d320bbb3SAlexey Dobriyan xfrm_hash_free(net->xfrm.state_bysrc, sz); 211573d189dcSAlexey Dobriyan WARN_ON(!hlist_empty(net->xfrm.state_bydst)); 211673d189dcSAlexey Dobriyan xfrm_hash_free(net->xfrm.state_bydst, sz); 21171da177e4SLinus Torvalds } 21181da177e4SLinus Torvalds 2119ab5f5e8bSJoy Latten #ifdef CONFIG_AUDITSYSCALL 2120cf35f43eSIlpo Järvinen static void xfrm_audit_helper_sainfo(struct xfrm_state *x, 2121ab5f5e8bSJoy Latten struct audit_buffer *audit_buf) 2122ab5f5e8bSJoy Latten { 212368277accSPaul Moore struct xfrm_sec_ctx *ctx = x->security; 212468277accSPaul Moore u32 spi = ntohl(x->id.spi); 212568277accSPaul Moore 212668277accSPaul Moore if (ctx) 2127ab5f5e8bSJoy Latten audit_log_format(audit_buf, " sec_alg=%u sec_doi=%u sec_obj=%s", 212868277accSPaul Moore ctx->ctx_alg, ctx->ctx_doi, ctx->ctx_str); 2129ab5f5e8bSJoy Latten 2130ab5f5e8bSJoy Latten switch(x->props.family) { 2131ab5f5e8bSJoy Latten case AF_INET: 213221454aaaSHarvey Harrison audit_log_format(audit_buf, " src=%pI4 dst=%pI4", 213321454aaaSHarvey Harrison &x->props.saddr.a4, &x->id.daddr.a4); 2134ab5f5e8bSJoy Latten break; 2135ab5f5e8bSJoy Latten case AF_INET6: 21365b095d98SHarvey Harrison audit_log_format(audit_buf, " src=%pI6 dst=%pI6", 2137fdb46ee7SHarvey Harrison x->props.saddr.a6, x->id.daddr.a6); 2138ab5f5e8bSJoy Latten break; 2139ab5f5e8bSJoy Latten } 214068277accSPaul Moore 214168277accSPaul Moore audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi); 2142ab5f5e8bSJoy Latten } 2143ab5f5e8bSJoy Latten 2144cf35f43eSIlpo Järvinen static void xfrm_audit_helper_pktinfo(struct sk_buff *skb, u16 family, 2145afeb14b4SPaul Moore struct audit_buffer *audit_buf) 2146afeb14b4SPaul Moore { 2147afeb14b4SPaul Moore struct iphdr *iph4; 2148afeb14b4SPaul Moore struct ipv6hdr *iph6; 2149afeb14b4SPaul Moore 2150afeb14b4SPaul Moore switch (family) { 2151afeb14b4SPaul Moore case AF_INET: 2152afeb14b4SPaul Moore iph4 = ip_hdr(skb); 215321454aaaSHarvey Harrison audit_log_format(audit_buf, " src=%pI4 dst=%pI4", 215421454aaaSHarvey Harrison &iph4->saddr, &iph4->daddr); 2155afeb14b4SPaul Moore break; 2156afeb14b4SPaul Moore case AF_INET6: 2157afeb14b4SPaul Moore iph6 = ipv6_hdr(skb); 2158afeb14b4SPaul Moore audit_log_format(audit_buf, 21595b095d98SHarvey Harrison " src=%pI6 dst=%pI6 flowlbl=0x%x%02x%02x", 2160fdb46ee7SHarvey Harrison &iph6->saddr,&iph6->daddr, 2161afeb14b4SPaul Moore iph6->flow_lbl[0] & 0x0f, 2162afeb14b4SPaul Moore iph6->flow_lbl[1], 2163afeb14b4SPaul Moore iph6->flow_lbl[2]); 2164afeb14b4SPaul Moore break; 2165afeb14b4SPaul Moore } 2166afeb14b4SPaul Moore } 2167afeb14b4SPaul Moore 216868277accSPaul Moore void xfrm_audit_state_add(struct xfrm_state *x, int result, 21692532386fSEric Paris uid_t auid, u32 sessionid, u32 secid) 2170ab5f5e8bSJoy Latten { 2171ab5f5e8bSJoy Latten struct audit_buffer *audit_buf; 2172ab5f5e8bSJoy Latten 2173afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SAD-add"); 2174ab5f5e8bSJoy Latten if (audit_buf == NULL) 2175ab5f5e8bSJoy Latten return; 21762532386fSEric Paris xfrm_audit_helper_usrinfo(auid, sessionid, secid, audit_buf); 2177afeb14b4SPaul Moore xfrm_audit_helper_sainfo(x, audit_buf); 2178afeb14b4SPaul Moore audit_log_format(audit_buf, " res=%u", result); 2179ab5f5e8bSJoy Latten audit_log_end(audit_buf); 2180ab5f5e8bSJoy Latten } 2181ab5f5e8bSJoy Latten EXPORT_SYMBOL_GPL(xfrm_audit_state_add); 2182ab5f5e8bSJoy Latten 218368277accSPaul Moore void xfrm_audit_state_delete(struct xfrm_state *x, int result, 21842532386fSEric Paris uid_t auid, u32 sessionid, u32 secid) 2185ab5f5e8bSJoy Latten { 2186ab5f5e8bSJoy Latten struct audit_buffer *audit_buf; 2187ab5f5e8bSJoy Latten 2188afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SAD-delete"); 2189ab5f5e8bSJoy Latten if (audit_buf == NULL) 2190ab5f5e8bSJoy Latten return; 21912532386fSEric Paris xfrm_audit_helper_usrinfo(auid, sessionid, secid, audit_buf); 2192afeb14b4SPaul Moore xfrm_audit_helper_sainfo(x, audit_buf); 2193afeb14b4SPaul Moore audit_log_format(audit_buf, " res=%u", result); 2194ab5f5e8bSJoy Latten audit_log_end(audit_buf); 2195ab5f5e8bSJoy Latten } 2196ab5f5e8bSJoy Latten EXPORT_SYMBOL_GPL(xfrm_audit_state_delete); 2197afeb14b4SPaul Moore 2198afeb14b4SPaul Moore void xfrm_audit_state_replay_overflow(struct xfrm_state *x, 2199afeb14b4SPaul Moore struct sk_buff *skb) 2200afeb14b4SPaul Moore { 2201afeb14b4SPaul Moore struct audit_buffer *audit_buf; 2202afeb14b4SPaul Moore u32 spi; 2203afeb14b4SPaul Moore 2204afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SA-replay-overflow"); 2205afeb14b4SPaul Moore if (audit_buf == NULL) 2206afeb14b4SPaul Moore return; 2207afeb14b4SPaul Moore xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf); 2208afeb14b4SPaul Moore /* don't record the sequence number because it's inherent in this kind 2209afeb14b4SPaul Moore * of audit message */ 2210afeb14b4SPaul Moore spi = ntohl(x->id.spi); 2211afeb14b4SPaul Moore audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi); 2212afeb14b4SPaul Moore audit_log_end(audit_buf); 2213afeb14b4SPaul Moore } 2214afeb14b4SPaul Moore EXPORT_SYMBOL_GPL(xfrm_audit_state_replay_overflow); 2215afeb14b4SPaul Moore 2216afeb14b4SPaul Moore static void xfrm_audit_state_replay(struct xfrm_state *x, 2217afeb14b4SPaul Moore struct sk_buff *skb, __be32 net_seq) 2218afeb14b4SPaul Moore { 2219afeb14b4SPaul Moore struct audit_buffer *audit_buf; 2220afeb14b4SPaul Moore u32 spi; 2221afeb14b4SPaul Moore 2222afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SA-replayed-pkt"); 2223afeb14b4SPaul Moore if (audit_buf == NULL) 2224afeb14b4SPaul Moore return; 2225afeb14b4SPaul Moore xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf); 2226afeb14b4SPaul Moore spi = ntohl(x->id.spi); 2227afeb14b4SPaul Moore audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u", 2228afeb14b4SPaul Moore spi, spi, ntohl(net_seq)); 2229afeb14b4SPaul Moore audit_log_end(audit_buf); 2230afeb14b4SPaul Moore } 2231afeb14b4SPaul Moore 2232afeb14b4SPaul Moore void xfrm_audit_state_notfound_simple(struct sk_buff *skb, u16 family) 2233afeb14b4SPaul Moore { 2234afeb14b4SPaul Moore struct audit_buffer *audit_buf; 2235afeb14b4SPaul Moore 2236afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SA-notfound"); 2237afeb14b4SPaul Moore if (audit_buf == NULL) 2238afeb14b4SPaul Moore return; 2239afeb14b4SPaul Moore xfrm_audit_helper_pktinfo(skb, family, audit_buf); 2240afeb14b4SPaul Moore audit_log_end(audit_buf); 2241afeb14b4SPaul Moore } 2242afeb14b4SPaul Moore EXPORT_SYMBOL_GPL(xfrm_audit_state_notfound_simple); 2243afeb14b4SPaul Moore 2244afeb14b4SPaul Moore void xfrm_audit_state_notfound(struct sk_buff *skb, u16 family, 2245afeb14b4SPaul Moore __be32 net_spi, __be32 net_seq) 2246afeb14b4SPaul Moore { 2247afeb14b4SPaul Moore struct audit_buffer *audit_buf; 2248afeb14b4SPaul Moore u32 spi; 2249afeb14b4SPaul Moore 2250afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SA-notfound"); 2251afeb14b4SPaul Moore if (audit_buf == NULL) 2252afeb14b4SPaul Moore return; 2253afeb14b4SPaul Moore xfrm_audit_helper_pktinfo(skb, family, audit_buf); 2254afeb14b4SPaul Moore spi = ntohl(net_spi); 2255afeb14b4SPaul Moore audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u", 2256afeb14b4SPaul Moore spi, spi, ntohl(net_seq)); 2257afeb14b4SPaul Moore audit_log_end(audit_buf); 2258afeb14b4SPaul Moore } 2259afeb14b4SPaul Moore EXPORT_SYMBOL_GPL(xfrm_audit_state_notfound); 2260afeb14b4SPaul Moore 2261afeb14b4SPaul Moore void xfrm_audit_state_icvfail(struct xfrm_state *x, 2262afeb14b4SPaul Moore struct sk_buff *skb, u8 proto) 2263afeb14b4SPaul Moore { 2264afeb14b4SPaul Moore struct audit_buffer *audit_buf; 2265afeb14b4SPaul Moore __be32 net_spi; 2266afeb14b4SPaul Moore __be32 net_seq; 2267afeb14b4SPaul Moore 2268afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SA-icv-failure"); 2269afeb14b4SPaul Moore if (audit_buf == NULL) 2270afeb14b4SPaul Moore return; 2271afeb14b4SPaul Moore xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf); 2272afeb14b4SPaul Moore if (xfrm_parse_spi(skb, proto, &net_spi, &net_seq) == 0) { 2273afeb14b4SPaul Moore u32 spi = ntohl(net_spi); 2274afeb14b4SPaul Moore audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u", 2275afeb14b4SPaul Moore spi, spi, ntohl(net_seq)); 2276afeb14b4SPaul Moore } 2277afeb14b4SPaul Moore audit_log_end(audit_buf); 2278afeb14b4SPaul Moore } 2279afeb14b4SPaul Moore EXPORT_SYMBOL_GPL(xfrm_audit_state_icvfail); 2280ab5f5e8bSJoy Latten #endif /* CONFIG_AUDITSYSCALL */ 2281