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 471da177e4SLinus Torvalds /* Hash table to find appropriate SA towards given target (endpoint 481da177e4SLinus Torvalds * of tunnel or destination of transport mode) allowed by selector. 491da177e4SLinus Torvalds * 501da177e4SLinus Torvalds * Main use is finding SA after policy selected tunnel or transport mode. 511da177e4SLinus Torvalds * Also, it can be used by ah/esp icmp error handler to find offending SA. 521da177e4SLinus Torvalds */ 53*4c563f76STimo Teras static LIST_HEAD(xfrm_state_all); 54f034b5d4SDavid S. Miller static struct hlist_head *xfrm_state_bydst __read_mostly; 55f034b5d4SDavid S. Miller static struct hlist_head *xfrm_state_bysrc __read_mostly; 56f034b5d4SDavid S. Miller static struct hlist_head *xfrm_state_byspi __read_mostly; 57f034b5d4SDavid S. Miller static unsigned int xfrm_state_hmask __read_mostly; 58f034b5d4SDavid S. Miller static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024; 59f034b5d4SDavid S. Miller static unsigned int xfrm_state_num; 609d4a706dSDavid S. Miller static unsigned int xfrm_state_genid; 611da177e4SLinus Torvalds 6217c2a42aSHerbert Xu static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family); 6317c2a42aSHerbert Xu static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo); 6417c2a42aSHerbert Xu 65afeb14b4SPaul Moore #ifdef CONFIG_AUDITSYSCALL 66afeb14b4SPaul Moore static void xfrm_audit_state_replay(struct xfrm_state *x, 67afeb14b4SPaul Moore struct sk_buff *skb, __be32 net_seq); 68afeb14b4SPaul Moore #else 69afeb14b4SPaul Moore #define xfrm_audit_state_replay(x, s, sq) do { ; } while (0) 70afeb14b4SPaul Moore #endif /* CONFIG_AUDITSYSCALL */ 71afeb14b4SPaul Moore 72c1969f29SDavid S. Miller static inline unsigned int xfrm_dst_hash(xfrm_address_t *daddr, 73c1969f29SDavid S. Miller xfrm_address_t *saddr, 74c1969f29SDavid S. Miller u32 reqid, 75a624c108SDavid S. Miller unsigned short family) 76a624c108SDavid S. Miller { 77c1969f29SDavid S. Miller return __xfrm_dst_hash(daddr, saddr, reqid, family, xfrm_state_hmask); 78a624c108SDavid S. Miller } 79a624c108SDavid S. Miller 80667bbcb6SMasahide NAKAMURA static inline unsigned int xfrm_src_hash(xfrm_address_t *daddr, 81667bbcb6SMasahide NAKAMURA xfrm_address_t *saddr, 8244e36b42SDavid S. Miller unsigned short family) 83f034b5d4SDavid S. Miller { 84667bbcb6SMasahide NAKAMURA return __xfrm_src_hash(daddr, saddr, family, xfrm_state_hmask); 85f034b5d4SDavid S. Miller } 86f034b5d4SDavid S. Miller 872575b654SDavid S. Miller static inline unsigned int 888122adf0SAl Viro xfrm_spi_hash(xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family) 89f034b5d4SDavid S. Miller { 90c1969f29SDavid S. Miller return __xfrm_spi_hash(daddr, spi, proto, family, xfrm_state_hmask); 91f034b5d4SDavid S. Miller } 92f034b5d4SDavid S. Miller 93f034b5d4SDavid S. Miller static void xfrm_hash_transfer(struct hlist_head *list, 94f034b5d4SDavid S. Miller struct hlist_head *ndsttable, 95f034b5d4SDavid S. Miller struct hlist_head *nsrctable, 96f034b5d4SDavid S. Miller struct hlist_head *nspitable, 97f034b5d4SDavid S. Miller unsigned int nhashmask) 98f034b5d4SDavid S. Miller { 99f034b5d4SDavid S. Miller struct hlist_node *entry, *tmp; 100f034b5d4SDavid S. Miller struct xfrm_state *x; 101f034b5d4SDavid S. Miller 102f034b5d4SDavid S. Miller hlist_for_each_entry_safe(x, entry, tmp, list, bydst) { 103f034b5d4SDavid S. Miller unsigned int h; 104f034b5d4SDavid S. Miller 105c1969f29SDavid S. Miller h = __xfrm_dst_hash(&x->id.daddr, &x->props.saddr, 106c1969f29SDavid S. Miller x->props.reqid, x->props.family, 107c1969f29SDavid S. Miller nhashmask); 108f034b5d4SDavid S. Miller hlist_add_head(&x->bydst, ndsttable+h); 109f034b5d4SDavid S. Miller 110667bbcb6SMasahide NAKAMURA h = __xfrm_src_hash(&x->id.daddr, &x->props.saddr, 111667bbcb6SMasahide NAKAMURA x->props.family, 112f034b5d4SDavid S. Miller nhashmask); 113f034b5d4SDavid S. Miller hlist_add_head(&x->bysrc, nsrctable+h); 114f034b5d4SDavid S. Miller 1157b4dc360SMasahide NAKAMURA if (x->id.spi) { 1167b4dc360SMasahide NAKAMURA h = __xfrm_spi_hash(&x->id.daddr, x->id.spi, 1177b4dc360SMasahide NAKAMURA x->id.proto, x->props.family, 1187b4dc360SMasahide NAKAMURA nhashmask); 119f034b5d4SDavid S. Miller hlist_add_head(&x->byspi, nspitable+h); 120f034b5d4SDavid S. Miller } 121f034b5d4SDavid S. Miller } 1227b4dc360SMasahide NAKAMURA } 123f034b5d4SDavid S. Miller 124f034b5d4SDavid S. Miller static unsigned long xfrm_hash_new_size(void) 125f034b5d4SDavid S. Miller { 126f034b5d4SDavid S. Miller return ((xfrm_state_hmask + 1) << 1) * 127f034b5d4SDavid S. Miller sizeof(struct hlist_head); 128f034b5d4SDavid S. Miller } 129f034b5d4SDavid S. Miller 130f034b5d4SDavid S. Miller static DEFINE_MUTEX(hash_resize_mutex); 131f034b5d4SDavid S. Miller 132c4028958SDavid Howells static void xfrm_hash_resize(struct work_struct *__unused) 133f034b5d4SDavid S. Miller { 134f034b5d4SDavid S. Miller struct hlist_head *ndst, *nsrc, *nspi, *odst, *osrc, *ospi; 135f034b5d4SDavid S. Miller unsigned long nsize, osize; 136f034b5d4SDavid S. Miller unsigned int nhashmask, ohashmask; 137f034b5d4SDavid S. Miller int i; 138f034b5d4SDavid S. Miller 139f034b5d4SDavid S. Miller mutex_lock(&hash_resize_mutex); 140f034b5d4SDavid S. Miller 141f034b5d4SDavid S. Miller nsize = xfrm_hash_new_size(); 14244e36b42SDavid S. Miller ndst = xfrm_hash_alloc(nsize); 143f034b5d4SDavid S. Miller if (!ndst) 144f034b5d4SDavid S. Miller goto out_unlock; 14544e36b42SDavid S. Miller nsrc = xfrm_hash_alloc(nsize); 146f034b5d4SDavid S. Miller if (!nsrc) { 14744e36b42SDavid S. Miller xfrm_hash_free(ndst, nsize); 148f034b5d4SDavid S. Miller goto out_unlock; 149f034b5d4SDavid S. Miller } 15044e36b42SDavid S. Miller nspi = xfrm_hash_alloc(nsize); 151f034b5d4SDavid S. Miller if (!nspi) { 15244e36b42SDavid S. Miller xfrm_hash_free(ndst, nsize); 15344e36b42SDavid S. Miller xfrm_hash_free(nsrc, nsize); 154f034b5d4SDavid S. Miller goto out_unlock; 155f034b5d4SDavid S. Miller } 156f034b5d4SDavid S. Miller 157f034b5d4SDavid S. Miller spin_lock_bh(&xfrm_state_lock); 158f034b5d4SDavid S. Miller 159f034b5d4SDavid S. Miller nhashmask = (nsize / sizeof(struct hlist_head)) - 1U; 160f034b5d4SDavid S. Miller for (i = xfrm_state_hmask; i >= 0; i--) 161f034b5d4SDavid S. Miller xfrm_hash_transfer(xfrm_state_bydst+i, ndst, nsrc, nspi, 162f034b5d4SDavid S. Miller nhashmask); 163f034b5d4SDavid S. Miller 164f034b5d4SDavid S. Miller odst = xfrm_state_bydst; 165f034b5d4SDavid S. Miller osrc = xfrm_state_bysrc; 166f034b5d4SDavid S. Miller ospi = xfrm_state_byspi; 167f034b5d4SDavid S. Miller ohashmask = xfrm_state_hmask; 168f034b5d4SDavid S. Miller 169f034b5d4SDavid S. Miller xfrm_state_bydst = ndst; 170f034b5d4SDavid S. Miller xfrm_state_bysrc = nsrc; 171f034b5d4SDavid S. Miller xfrm_state_byspi = nspi; 172f034b5d4SDavid S. Miller xfrm_state_hmask = nhashmask; 173f034b5d4SDavid S. Miller 174f034b5d4SDavid S. Miller spin_unlock_bh(&xfrm_state_lock); 175f034b5d4SDavid S. Miller 176f034b5d4SDavid S. Miller osize = (ohashmask + 1) * sizeof(struct hlist_head); 17744e36b42SDavid S. Miller xfrm_hash_free(odst, osize); 17844e36b42SDavid S. Miller xfrm_hash_free(osrc, osize); 17944e36b42SDavid S. Miller xfrm_hash_free(ospi, osize); 180f034b5d4SDavid S. Miller 181f034b5d4SDavid S. Miller out_unlock: 182f034b5d4SDavid S. Miller mutex_unlock(&hash_resize_mutex); 183f034b5d4SDavid S. Miller } 184f034b5d4SDavid S. Miller 185c4028958SDavid Howells static DECLARE_WORK(xfrm_hash_work, xfrm_hash_resize); 186f034b5d4SDavid S. Miller 1871da177e4SLinus Torvalds DECLARE_WAIT_QUEUE_HEAD(km_waitq); 1881da177e4SLinus Torvalds EXPORT_SYMBOL(km_waitq); 1891da177e4SLinus Torvalds 1901da177e4SLinus Torvalds static DEFINE_RWLOCK(xfrm_state_afinfo_lock); 1911da177e4SLinus Torvalds static struct xfrm_state_afinfo *xfrm_state_afinfo[NPROTO]; 1921da177e4SLinus Torvalds 1931da177e4SLinus Torvalds static struct work_struct xfrm_state_gc_work; 1948f126e37SDavid S. Miller static HLIST_HEAD(xfrm_state_gc_list); 1951da177e4SLinus Torvalds static DEFINE_SPINLOCK(xfrm_state_gc_lock); 1961da177e4SLinus Torvalds 19753bc6b4dSJamal Hadi Salim int __xfrm_state_delete(struct xfrm_state *x); 1981da177e4SLinus Torvalds 199980ebd25SJamal Hadi Salim int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol); 20053bc6b4dSJamal Hadi Salim void km_state_expired(struct xfrm_state *x, int hard, u32 pid); 2011da177e4SLinus Torvalds 202aa5d62ccSHerbert Xu static struct xfrm_state_afinfo *xfrm_state_lock_afinfo(unsigned int family) 203aa5d62ccSHerbert Xu { 204aa5d62ccSHerbert Xu struct xfrm_state_afinfo *afinfo; 205aa5d62ccSHerbert Xu if (unlikely(family >= NPROTO)) 206aa5d62ccSHerbert Xu return NULL; 207aa5d62ccSHerbert Xu write_lock_bh(&xfrm_state_afinfo_lock); 208aa5d62ccSHerbert Xu afinfo = xfrm_state_afinfo[family]; 209aa5d62ccSHerbert Xu if (unlikely(!afinfo)) 210aa5d62ccSHerbert Xu write_unlock_bh(&xfrm_state_afinfo_lock); 211aa5d62ccSHerbert Xu return afinfo; 212aa5d62ccSHerbert Xu } 213aa5d62ccSHerbert Xu 214aa5d62ccSHerbert Xu static void xfrm_state_unlock_afinfo(struct xfrm_state_afinfo *afinfo) 2159a429c49SEric Dumazet __releases(xfrm_state_afinfo_lock) 216aa5d62ccSHerbert Xu { 217aa5d62ccSHerbert Xu write_unlock_bh(&xfrm_state_afinfo_lock); 218aa5d62ccSHerbert Xu } 219aa5d62ccSHerbert Xu 220533cb5b0SEric Dumazet int xfrm_register_type(const struct xfrm_type *type, unsigned short family) 221aa5d62ccSHerbert Xu { 222aa5d62ccSHerbert Xu struct xfrm_state_afinfo *afinfo = xfrm_state_lock_afinfo(family); 223533cb5b0SEric Dumazet const struct xfrm_type **typemap; 224aa5d62ccSHerbert Xu int err = 0; 225aa5d62ccSHerbert Xu 226aa5d62ccSHerbert Xu if (unlikely(afinfo == NULL)) 227aa5d62ccSHerbert Xu return -EAFNOSUPPORT; 228aa5d62ccSHerbert Xu typemap = afinfo->type_map; 229aa5d62ccSHerbert Xu 230aa5d62ccSHerbert Xu if (likely(typemap[type->proto] == NULL)) 231aa5d62ccSHerbert Xu typemap[type->proto] = type; 232aa5d62ccSHerbert Xu else 233aa5d62ccSHerbert Xu err = -EEXIST; 234aa5d62ccSHerbert Xu xfrm_state_unlock_afinfo(afinfo); 235aa5d62ccSHerbert Xu return err; 236aa5d62ccSHerbert Xu } 237aa5d62ccSHerbert Xu EXPORT_SYMBOL(xfrm_register_type); 238aa5d62ccSHerbert Xu 239533cb5b0SEric Dumazet int xfrm_unregister_type(const struct xfrm_type *type, unsigned short family) 240aa5d62ccSHerbert Xu { 241aa5d62ccSHerbert Xu struct xfrm_state_afinfo *afinfo = xfrm_state_lock_afinfo(family); 242533cb5b0SEric Dumazet const struct xfrm_type **typemap; 243aa5d62ccSHerbert Xu int err = 0; 244aa5d62ccSHerbert Xu 245aa5d62ccSHerbert Xu if (unlikely(afinfo == NULL)) 246aa5d62ccSHerbert Xu return -EAFNOSUPPORT; 247aa5d62ccSHerbert Xu typemap = afinfo->type_map; 248aa5d62ccSHerbert Xu 249aa5d62ccSHerbert Xu if (unlikely(typemap[type->proto] != type)) 250aa5d62ccSHerbert Xu err = -ENOENT; 251aa5d62ccSHerbert Xu else 252aa5d62ccSHerbert Xu typemap[type->proto] = NULL; 253aa5d62ccSHerbert Xu xfrm_state_unlock_afinfo(afinfo); 254aa5d62ccSHerbert Xu return err; 255aa5d62ccSHerbert Xu } 256aa5d62ccSHerbert Xu EXPORT_SYMBOL(xfrm_unregister_type); 257aa5d62ccSHerbert Xu 258533cb5b0SEric Dumazet static const struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family) 259aa5d62ccSHerbert Xu { 260aa5d62ccSHerbert Xu struct xfrm_state_afinfo *afinfo; 261533cb5b0SEric Dumazet const struct xfrm_type **typemap; 262533cb5b0SEric Dumazet const struct xfrm_type *type; 263aa5d62ccSHerbert Xu int modload_attempted = 0; 264aa5d62ccSHerbert Xu 265aa5d62ccSHerbert Xu retry: 266aa5d62ccSHerbert Xu afinfo = xfrm_state_get_afinfo(family); 267aa5d62ccSHerbert Xu if (unlikely(afinfo == NULL)) 268aa5d62ccSHerbert Xu return NULL; 269aa5d62ccSHerbert Xu typemap = afinfo->type_map; 270aa5d62ccSHerbert Xu 271aa5d62ccSHerbert Xu type = typemap[proto]; 272aa5d62ccSHerbert Xu if (unlikely(type && !try_module_get(type->owner))) 273aa5d62ccSHerbert Xu type = NULL; 274aa5d62ccSHerbert Xu if (!type && !modload_attempted) { 275aa5d62ccSHerbert Xu xfrm_state_put_afinfo(afinfo); 276aa5d62ccSHerbert Xu request_module("xfrm-type-%d-%d", family, proto); 277aa5d62ccSHerbert Xu modload_attempted = 1; 278aa5d62ccSHerbert Xu goto retry; 279aa5d62ccSHerbert Xu } 280aa5d62ccSHerbert Xu 281aa5d62ccSHerbert Xu xfrm_state_put_afinfo(afinfo); 282aa5d62ccSHerbert Xu return type; 283aa5d62ccSHerbert Xu } 284aa5d62ccSHerbert Xu 285533cb5b0SEric Dumazet static void xfrm_put_type(const struct xfrm_type *type) 286aa5d62ccSHerbert Xu { 287aa5d62ccSHerbert Xu module_put(type->owner); 288aa5d62ccSHerbert Xu } 289aa5d62ccSHerbert Xu 290aa5d62ccSHerbert Xu int xfrm_register_mode(struct xfrm_mode *mode, int family) 291aa5d62ccSHerbert Xu { 292aa5d62ccSHerbert Xu struct xfrm_state_afinfo *afinfo; 293aa5d62ccSHerbert Xu struct xfrm_mode **modemap; 294aa5d62ccSHerbert Xu int err; 295aa5d62ccSHerbert Xu 296aa5d62ccSHerbert Xu if (unlikely(mode->encap >= XFRM_MODE_MAX)) 297aa5d62ccSHerbert Xu return -EINVAL; 298aa5d62ccSHerbert Xu 299aa5d62ccSHerbert Xu afinfo = xfrm_state_lock_afinfo(family); 300aa5d62ccSHerbert Xu if (unlikely(afinfo == NULL)) 301aa5d62ccSHerbert Xu return -EAFNOSUPPORT; 302aa5d62ccSHerbert Xu 303aa5d62ccSHerbert Xu err = -EEXIST; 304aa5d62ccSHerbert Xu modemap = afinfo->mode_map; 30517c2a42aSHerbert Xu if (modemap[mode->encap]) 30617c2a42aSHerbert Xu goto out; 30717c2a42aSHerbert Xu 30817c2a42aSHerbert Xu err = -ENOENT; 30917c2a42aSHerbert Xu if (!try_module_get(afinfo->owner)) 31017c2a42aSHerbert Xu goto out; 31117c2a42aSHerbert Xu 31217c2a42aSHerbert Xu mode->afinfo = afinfo; 313aa5d62ccSHerbert Xu modemap[mode->encap] = mode; 314aa5d62ccSHerbert Xu err = 0; 315aa5d62ccSHerbert Xu 31617c2a42aSHerbert Xu out: 317aa5d62ccSHerbert Xu xfrm_state_unlock_afinfo(afinfo); 318aa5d62ccSHerbert Xu return err; 319aa5d62ccSHerbert Xu } 320aa5d62ccSHerbert Xu EXPORT_SYMBOL(xfrm_register_mode); 321aa5d62ccSHerbert Xu 322aa5d62ccSHerbert Xu int xfrm_unregister_mode(struct xfrm_mode *mode, int family) 323aa5d62ccSHerbert Xu { 324aa5d62ccSHerbert Xu struct xfrm_state_afinfo *afinfo; 325aa5d62ccSHerbert Xu struct xfrm_mode **modemap; 326aa5d62ccSHerbert Xu int err; 327aa5d62ccSHerbert Xu 328aa5d62ccSHerbert Xu if (unlikely(mode->encap >= XFRM_MODE_MAX)) 329aa5d62ccSHerbert Xu return -EINVAL; 330aa5d62ccSHerbert Xu 331aa5d62ccSHerbert Xu afinfo = xfrm_state_lock_afinfo(family); 332aa5d62ccSHerbert Xu if (unlikely(afinfo == NULL)) 333aa5d62ccSHerbert Xu return -EAFNOSUPPORT; 334aa5d62ccSHerbert Xu 335aa5d62ccSHerbert Xu err = -ENOENT; 336aa5d62ccSHerbert Xu modemap = afinfo->mode_map; 337aa5d62ccSHerbert Xu if (likely(modemap[mode->encap] == mode)) { 338aa5d62ccSHerbert Xu modemap[mode->encap] = NULL; 33917c2a42aSHerbert Xu module_put(mode->afinfo->owner); 340aa5d62ccSHerbert Xu err = 0; 341aa5d62ccSHerbert Xu } 342aa5d62ccSHerbert Xu 343aa5d62ccSHerbert Xu xfrm_state_unlock_afinfo(afinfo); 344aa5d62ccSHerbert Xu return err; 345aa5d62ccSHerbert Xu } 346aa5d62ccSHerbert Xu EXPORT_SYMBOL(xfrm_unregister_mode); 347aa5d62ccSHerbert Xu 348aa5d62ccSHerbert Xu static struct xfrm_mode *xfrm_get_mode(unsigned int encap, int family) 349aa5d62ccSHerbert Xu { 350aa5d62ccSHerbert Xu struct xfrm_state_afinfo *afinfo; 351aa5d62ccSHerbert Xu struct xfrm_mode *mode; 352aa5d62ccSHerbert Xu int modload_attempted = 0; 353aa5d62ccSHerbert Xu 354aa5d62ccSHerbert Xu if (unlikely(encap >= XFRM_MODE_MAX)) 355aa5d62ccSHerbert Xu return NULL; 356aa5d62ccSHerbert Xu 357aa5d62ccSHerbert Xu retry: 358aa5d62ccSHerbert Xu afinfo = xfrm_state_get_afinfo(family); 359aa5d62ccSHerbert Xu if (unlikely(afinfo == NULL)) 360aa5d62ccSHerbert Xu return NULL; 361aa5d62ccSHerbert Xu 362aa5d62ccSHerbert Xu mode = afinfo->mode_map[encap]; 363aa5d62ccSHerbert Xu if (unlikely(mode && !try_module_get(mode->owner))) 364aa5d62ccSHerbert Xu mode = NULL; 365aa5d62ccSHerbert Xu if (!mode && !modload_attempted) { 366aa5d62ccSHerbert Xu xfrm_state_put_afinfo(afinfo); 367aa5d62ccSHerbert Xu request_module("xfrm-mode-%d-%d", family, encap); 368aa5d62ccSHerbert Xu modload_attempted = 1; 369aa5d62ccSHerbert Xu goto retry; 370aa5d62ccSHerbert Xu } 371aa5d62ccSHerbert Xu 372aa5d62ccSHerbert Xu xfrm_state_put_afinfo(afinfo); 373aa5d62ccSHerbert Xu return mode; 374aa5d62ccSHerbert Xu } 375aa5d62ccSHerbert Xu 376aa5d62ccSHerbert Xu static void xfrm_put_mode(struct xfrm_mode *mode) 377aa5d62ccSHerbert Xu { 378aa5d62ccSHerbert Xu module_put(mode->owner); 379aa5d62ccSHerbert Xu } 380aa5d62ccSHerbert Xu 3811da177e4SLinus Torvalds static void xfrm_state_gc_destroy(struct xfrm_state *x) 3821da177e4SLinus Torvalds { 383a47f0ce0SDavid S. Miller del_timer_sync(&x->timer); 384a47f0ce0SDavid S. Miller del_timer_sync(&x->rtimer); 3851da177e4SLinus Torvalds kfree(x->aalg); 3861da177e4SLinus Torvalds kfree(x->ealg); 3871da177e4SLinus Torvalds kfree(x->calg); 3881da177e4SLinus Torvalds kfree(x->encap); 389060f02a3SNoriaki TAKAMIYA kfree(x->coaddr); 39013996378SHerbert Xu if (x->inner_mode) 39113996378SHerbert Xu xfrm_put_mode(x->inner_mode); 39213996378SHerbert Xu if (x->outer_mode) 39313996378SHerbert Xu xfrm_put_mode(x->outer_mode); 3941da177e4SLinus Torvalds if (x->type) { 3951da177e4SLinus Torvalds x->type->destructor(x); 3961da177e4SLinus Torvalds xfrm_put_type(x->type); 3971da177e4SLinus Torvalds } 398df71837dSTrent Jaeger security_xfrm_state_free(x); 3991da177e4SLinus Torvalds kfree(x); 4001da177e4SLinus Torvalds } 4011da177e4SLinus Torvalds 402c4028958SDavid Howells static void xfrm_state_gc_task(struct work_struct *data) 4031da177e4SLinus Torvalds { 4041da177e4SLinus Torvalds struct xfrm_state *x; 4058f126e37SDavid S. Miller struct hlist_node *entry, *tmp; 4068f126e37SDavid S. Miller struct hlist_head gc_list; 4071da177e4SLinus Torvalds 4081da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_gc_lock); 4098f126e37SDavid S. Miller gc_list.first = xfrm_state_gc_list.first; 4108f126e37SDavid S. Miller INIT_HLIST_HEAD(&xfrm_state_gc_list); 4111da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_gc_lock); 4121da177e4SLinus Torvalds 4138f126e37SDavid S. Miller hlist_for_each_entry_safe(x, entry, tmp, &gc_list, bydst) 4141da177e4SLinus Torvalds xfrm_state_gc_destroy(x); 4158f126e37SDavid S. Miller 4161da177e4SLinus Torvalds wake_up(&km_waitq); 4171da177e4SLinus Torvalds } 4181da177e4SLinus Torvalds 4191da177e4SLinus Torvalds static inline unsigned long make_jiffies(long secs) 4201da177e4SLinus Torvalds { 4211da177e4SLinus Torvalds if (secs >= (MAX_SCHEDULE_TIMEOUT-1)/HZ) 4221da177e4SLinus Torvalds return MAX_SCHEDULE_TIMEOUT-1; 4231da177e4SLinus Torvalds else 4241da177e4SLinus Torvalds return secs*HZ; 4251da177e4SLinus Torvalds } 4261da177e4SLinus Torvalds 4271da177e4SLinus Torvalds static void xfrm_timer_handler(unsigned long data) 4281da177e4SLinus Torvalds { 4291da177e4SLinus Torvalds struct xfrm_state *x = (struct xfrm_state*)data; 4309d729f72SJames Morris unsigned long now = get_seconds(); 4311da177e4SLinus Torvalds long next = LONG_MAX; 4321da177e4SLinus Torvalds int warn = 0; 433161a09e7SJoy Latten int err = 0; 4341da177e4SLinus Torvalds 4351da177e4SLinus Torvalds spin_lock(&x->lock); 4361da177e4SLinus Torvalds if (x->km.state == XFRM_STATE_DEAD) 4371da177e4SLinus Torvalds goto out; 4381da177e4SLinus Torvalds if (x->km.state == XFRM_STATE_EXPIRED) 4391da177e4SLinus Torvalds goto expired; 4401da177e4SLinus Torvalds if (x->lft.hard_add_expires_seconds) { 4411da177e4SLinus Torvalds long tmo = x->lft.hard_add_expires_seconds + 4421da177e4SLinus Torvalds x->curlft.add_time - now; 4431da177e4SLinus Torvalds if (tmo <= 0) 4441da177e4SLinus Torvalds goto expired; 4451da177e4SLinus Torvalds if (tmo < next) 4461da177e4SLinus Torvalds next = tmo; 4471da177e4SLinus Torvalds } 4481da177e4SLinus Torvalds if (x->lft.hard_use_expires_seconds) { 4491da177e4SLinus Torvalds long tmo = x->lft.hard_use_expires_seconds + 4501da177e4SLinus Torvalds (x->curlft.use_time ? : now) - now; 4511da177e4SLinus Torvalds if (tmo <= 0) 4521da177e4SLinus Torvalds goto expired; 4531da177e4SLinus Torvalds if (tmo < next) 4541da177e4SLinus Torvalds next = tmo; 4551da177e4SLinus Torvalds } 4561da177e4SLinus Torvalds if (x->km.dying) 4571da177e4SLinus Torvalds goto resched; 4581da177e4SLinus Torvalds if (x->lft.soft_add_expires_seconds) { 4591da177e4SLinus Torvalds long tmo = x->lft.soft_add_expires_seconds + 4601da177e4SLinus Torvalds x->curlft.add_time - now; 4611da177e4SLinus Torvalds if (tmo <= 0) 4621da177e4SLinus Torvalds warn = 1; 4631da177e4SLinus Torvalds else if (tmo < next) 4641da177e4SLinus Torvalds next = tmo; 4651da177e4SLinus Torvalds } 4661da177e4SLinus Torvalds if (x->lft.soft_use_expires_seconds) { 4671da177e4SLinus Torvalds long tmo = x->lft.soft_use_expires_seconds + 4681da177e4SLinus Torvalds (x->curlft.use_time ? : now) - now; 4691da177e4SLinus Torvalds if (tmo <= 0) 4701da177e4SLinus Torvalds warn = 1; 4711da177e4SLinus Torvalds else if (tmo < next) 4721da177e4SLinus Torvalds next = tmo; 4731da177e4SLinus Torvalds } 4741da177e4SLinus Torvalds 4754666faabSHerbert Xu x->km.dying = warn; 4761da177e4SLinus Torvalds if (warn) 47753bc6b4dSJamal Hadi Salim km_state_expired(x, 0, 0); 4781da177e4SLinus Torvalds resched: 479a47f0ce0SDavid S. Miller if (next != LONG_MAX) 480a47f0ce0SDavid S. Miller mod_timer(&x->timer, jiffies + make_jiffies(next)); 481a47f0ce0SDavid S. Miller 4821da177e4SLinus Torvalds goto out; 4831da177e4SLinus Torvalds 4841da177e4SLinus Torvalds expired: 4851da177e4SLinus Torvalds if (x->km.state == XFRM_STATE_ACQ && x->id.spi == 0) { 4861da177e4SLinus Torvalds x->km.state = XFRM_STATE_EXPIRED; 4871da177e4SLinus Torvalds wake_up(&km_waitq); 4881da177e4SLinus Torvalds next = 2; 4891da177e4SLinus Torvalds goto resched; 4901da177e4SLinus Torvalds } 491161a09e7SJoy Latten 492161a09e7SJoy Latten err = __xfrm_state_delete(x); 493161a09e7SJoy Latten if (!err && x->id.spi) 49453bc6b4dSJamal Hadi Salim km_state_expired(x, 1, 0); 4951da177e4SLinus Torvalds 496ab5f5e8bSJoy Latten xfrm_audit_state_delete(x, err ? 0 : 1, 4970c11b942SAl Viro audit_get_loginuid(current), 0); 498161a09e7SJoy Latten 4991da177e4SLinus Torvalds out: 5001da177e4SLinus Torvalds spin_unlock(&x->lock); 5011da177e4SLinus Torvalds } 5021da177e4SLinus Torvalds 5030ac84752SDavid S. Miller static void xfrm_replay_timer_handler(unsigned long data); 5040ac84752SDavid S. Miller 5051da177e4SLinus Torvalds struct xfrm_state *xfrm_state_alloc(void) 5061da177e4SLinus Torvalds { 5071da177e4SLinus Torvalds struct xfrm_state *x; 5081da177e4SLinus Torvalds 5090da974f4SPanagiotis Issaris x = kzalloc(sizeof(struct xfrm_state), GFP_ATOMIC); 5101da177e4SLinus Torvalds 5111da177e4SLinus Torvalds if (x) { 5121da177e4SLinus Torvalds atomic_set(&x->refcnt, 1); 5131da177e4SLinus Torvalds atomic_set(&x->tunnel_users, 0); 514*4c563f76STimo Teras INIT_LIST_HEAD(&x->all); 5158f126e37SDavid S. Miller INIT_HLIST_NODE(&x->bydst); 5168f126e37SDavid S. Miller INIT_HLIST_NODE(&x->bysrc); 5178f126e37SDavid S. Miller INIT_HLIST_NODE(&x->byspi); 518b24b8a24SPavel Emelyanov setup_timer(&x->timer, xfrm_timer_handler, (unsigned long)x); 519b24b8a24SPavel Emelyanov setup_timer(&x->rtimer, xfrm_replay_timer_handler, 520b24b8a24SPavel Emelyanov (unsigned long)x); 5219d729f72SJames Morris x->curlft.add_time = get_seconds(); 5221da177e4SLinus Torvalds x->lft.soft_byte_limit = XFRM_INF; 5231da177e4SLinus Torvalds x->lft.soft_packet_limit = XFRM_INF; 5241da177e4SLinus Torvalds x->lft.hard_byte_limit = XFRM_INF; 5251da177e4SLinus Torvalds x->lft.hard_packet_limit = XFRM_INF; 526f8cd5488SJamal Hadi Salim x->replay_maxage = 0; 527f8cd5488SJamal Hadi Salim x->replay_maxdiff = 0; 5281da177e4SLinus Torvalds spin_lock_init(&x->lock); 5291da177e4SLinus Torvalds } 5301da177e4SLinus Torvalds return x; 5311da177e4SLinus Torvalds } 5321da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_alloc); 5331da177e4SLinus Torvalds 5341da177e4SLinus Torvalds void __xfrm_state_destroy(struct xfrm_state *x) 5351da177e4SLinus Torvalds { 5361da177e4SLinus Torvalds BUG_TRAP(x->km.state == XFRM_STATE_DEAD); 5371da177e4SLinus Torvalds 538*4c563f76STimo Teras spin_lock_bh(&xfrm_state_lock); 539*4c563f76STimo Teras list_del(&x->all); 540*4c563f76STimo Teras spin_unlock_bh(&xfrm_state_lock); 541*4c563f76STimo Teras 5421da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_gc_lock); 5438f126e37SDavid S. Miller hlist_add_head(&x->bydst, &xfrm_state_gc_list); 5441da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_gc_lock); 5451da177e4SLinus Torvalds schedule_work(&xfrm_state_gc_work); 5461da177e4SLinus Torvalds } 5471da177e4SLinus Torvalds EXPORT_SYMBOL(__xfrm_state_destroy); 5481da177e4SLinus Torvalds 54953bc6b4dSJamal Hadi Salim int __xfrm_state_delete(struct xfrm_state *x) 5501da177e4SLinus Torvalds { 55126b15dadSJamal Hadi Salim int err = -ESRCH; 55226b15dadSJamal Hadi Salim 5531da177e4SLinus Torvalds if (x->km.state != XFRM_STATE_DEAD) { 5541da177e4SLinus Torvalds x->km.state = XFRM_STATE_DEAD; 5551da177e4SLinus Torvalds spin_lock(&xfrm_state_lock); 5568f126e37SDavid S. Miller hlist_del(&x->bydst); 5578f126e37SDavid S. Miller hlist_del(&x->bysrc); 558a47f0ce0SDavid S. Miller if (x->id.spi) 5598f126e37SDavid S. Miller hlist_del(&x->byspi); 560f034b5d4SDavid S. Miller xfrm_state_num--; 5611da177e4SLinus Torvalds spin_unlock(&xfrm_state_lock); 5621da177e4SLinus Torvalds 5631da177e4SLinus Torvalds /* All xfrm_state objects are created by xfrm_state_alloc. 5641da177e4SLinus Torvalds * The xfrm_state_alloc call gives a reference, and that 5651da177e4SLinus Torvalds * is what we are dropping here. 5661da177e4SLinus Torvalds */ 5675dba4797SPatrick McHardy xfrm_state_put(x); 56826b15dadSJamal Hadi Salim err = 0; 5691da177e4SLinus Torvalds } 5701da177e4SLinus Torvalds 57126b15dadSJamal Hadi Salim return err; 57226b15dadSJamal Hadi Salim } 57353bc6b4dSJamal Hadi Salim EXPORT_SYMBOL(__xfrm_state_delete); 57426b15dadSJamal Hadi Salim 57526b15dadSJamal Hadi Salim int xfrm_state_delete(struct xfrm_state *x) 5761da177e4SLinus Torvalds { 57726b15dadSJamal Hadi Salim int err; 57826b15dadSJamal Hadi Salim 5791da177e4SLinus Torvalds spin_lock_bh(&x->lock); 58026b15dadSJamal Hadi Salim err = __xfrm_state_delete(x); 5811da177e4SLinus Torvalds spin_unlock_bh(&x->lock); 58226b15dadSJamal Hadi Salim 58326b15dadSJamal Hadi Salim return err; 5841da177e4SLinus Torvalds } 5851da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_delete); 5861da177e4SLinus Torvalds 5874aa2e62cSJoy Latten #ifdef CONFIG_SECURITY_NETWORK_XFRM 5884aa2e62cSJoy Latten static inline int 5894aa2e62cSJoy Latten xfrm_state_flush_secctx_check(u8 proto, struct xfrm_audit *audit_info) 5901da177e4SLinus Torvalds { 5914aa2e62cSJoy Latten int i, err = 0; 5924aa2e62cSJoy Latten 5934aa2e62cSJoy Latten for (i = 0; i <= xfrm_state_hmask; i++) { 5944aa2e62cSJoy Latten struct hlist_node *entry; 5954aa2e62cSJoy Latten struct xfrm_state *x; 5964aa2e62cSJoy Latten 5974aa2e62cSJoy Latten hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) { 5984aa2e62cSJoy Latten if (xfrm_id_proto_match(x->id.proto, proto) && 5994aa2e62cSJoy Latten (err = security_xfrm_state_delete(x)) != 0) { 600ab5f5e8bSJoy Latten xfrm_audit_state_delete(x, 0, 601ab5f5e8bSJoy Latten audit_info->loginuid, 602ab5f5e8bSJoy Latten audit_info->secid); 6034aa2e62cSJoy Latten return err; 6044aa2e62cSJoy Latten } 6054aa2e62cSJoy Latten } 6064aa2e62cSJoy Latten } 6074aa2e62cSJoy Latten 6084aa2e62cSJoy Latten return err; 6094aa2e62cSJoy Latten } 6104aa2e62cSJoy Latten #else 6114aa2e62cSJoy Latten static inline int 6124aa2e62cSJoy Latten xfrm_state_flush_secctx_check(u8 proto, struct xfrm_audit *audit_info) 6134aa2e62cSJoy Latten { 6144aa2e62cSJoy Latten return 0; 6154aa2e62cSJoy Latten } 6164aa2e62cSJoy Latten #endif 6174aa2e62cSJoy Latten 6184aa2e62cSJoy Latten int xfrm_state_flush(u8 proto, struct xfrm_audit *audit_info) 6194aa2e62cSJoy Latten { 6204aa2e62cSJoy Latten int i, err = 0; 6211da177e4SLinus Torvalds 6221da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_lock); 6234aa2e62cSJoy Latten err = xfrm_state_flush_secctx_check(proto, audit_info); 6244aa2e62cSJoy Latten if (err) 6254aa2e62cSJoy Latten goto out; 6264aa2e62cSJoy Latten 627a9917c06SMasahide NAKAMURA for (i = 0; i <= xfrm_state_hmask; i++) { 6288f126e37SDavid S. Miller struct hlist_node *entry; 6298f126e37SDavid S. Miller struct xfrm_state *x; 6301da177e4SLinus Torvalds restart: 6318f126e37SDavid S. Miller hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) { 6321da177e4SLinus Torvalds if (!xfrm_state_kern(x) && 6335794708fSMasahide NAKAMURA xfrm_id_proto_match(x->id.proto, proto)) { 6341da177e4SLinus Torvalds xfrm_state_hold(x); 6351da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_lock); 6361da177e4SLinus Torvalds 637161a09e7SJoy Latten err = xfrm_state_delete(x); 638ab5f5e8bSJoy Latten xfrm_audit_state_delete(x, err ? 0 : 1, 639ab5f5e8bSJoy Latten audit_info->loginuid, 640ab5f5e8bSJoy Latten audit_info->secid); 6411da177e4SLinus Torvalds xfrm_state_put(x); 6421da177e4SLinus Torvalds 6431da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_lock); 6441da177e4SLinus Torvalds goto restart; 6451da177e4SLinus Torvalds } 6461da177e4SLinus Torvalds } 6471da177e4SLinus Torvalds } 6484aa2e62cSJoy Latten err = 0; 6494aa2e62cSJoy Latten 6504aa2e62cSJoy Latten out: 6511da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_lock); 6521da177e4SLinus Torvalds wake_up(&km_waitq); 6534aa2e62cSJoy Latten return err; 6541da177e4SLinus Torvalds } 6551da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_flush); 6561da177e4SLinus Torvalds 657af11e316SJamal Hadi Salim void xfrm_sad_getinfo(struct xfrmk_sadinfo *si) 65828d8909bSJamal Hadi Salim { 65928d8909bSJamal Hadi Salim spin_lock_bh(&xfrm_state_lock); 66028d8909bSJamal Hadi Salim si->sadcnt = xfrm_state_num; 66128d8909bSJamal Hadi Salim si->sadhcnt = xfrm_state_hmask; 66228d8909bSJamal Hadi Salim si->sadhmcnt = xfrm_state_hashmax; 66328d8909bSJamal Hadi Salim spin_unlock_bh(&xfrm_state_lock); 66428d8909bSJamal Hadi Salim } 66528d8909bSJamal Hadi Salim EXPORT_SYMBOL(xfrm_sad_getinfo); 66628d8909bSJamal Hadi Salim 6671da177e4SLinus Torvalds static int 6681da177e4SLinus Torvalds xfrm_init_tempsel(struct xfrm_state *x, struct flowi *fl, 6691da177e4SLinus Torvalds struct xfrm_tmpl *tmpl, 6701da177e4SLinus Torvalds xfrm_address_t *daddr, xfrm_address_t *saddr, 6711da177e4SLinus Torvalds unsigned short family) 6721da177e4SLinus Torvalds { 6731da177e4SLinus Torvalds struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); 6741da177e4SLinus Torvalds if (!afinfo) 6751da177e4SLinus Torvalds return -1; 6761da177e4SLinus Torvalds afinfo->init_tempsel(x, fl, tmpl, daddr, saddr); 6771da177e4SLinus Torvalds xfrm_state_put_afinfo(afinfo); 6781da177e4SLinus Torvalds return 0; 6791da177e4SLinus Torvalds } 6801da177e4SLinus Torvalds 681a94cfd19SAl Viro static struct xfrm_state *__xfrm_state_lookup(xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family) 682edcd5821SDavid S. Miller { 683edcd5821SDavid S. Miller unsigned int h = xfrm_spi_hash(daddr, spi, proto, family); 684edcd5821SDavid S. Miller struct xfrm_state *x; 6858f126e37SDavid S. Miller struct hlist_node *entry; 686edcd5821SDavid S. Miller 6878f126e37SDavid S. Miller hlist_for_each_entry(x, entry, xfrm_state_byspi+h, byspi) { 688edcd5821SDavid S. Miller if (x->props.family != family || 689edcd5821SDavid S. Miller x->id.spi != spi || 690edcd5821SDavid S. Miller x->id.proto != proto) 691edcd5821SDavid S. Miller continue; 692edcd5821SDavid S. Miller 693edcd5821SDavid S. Miller switch (family) { 694edcd5821SDavid S. Miller case AF_INET: 695edcd5821SDavid S. Miller if (x->id.daddr.a4 != daddr->a4) 696edcd5821SDavid S. Miller continue; 697edcd5821SDavid S. Miller break; 698edcd5821SDavid S. Miller case AF_INET6: 699edcd5821SDavid S. Miller if (!ipv6_addr_equal((struct in6_addr *)daddr, 700edcd5821SDavid S. Miller (struct in6_addr *) 701edcd5821SDavid S. Miller x->id.daddr.a6)) 702edcd5821SDavid S. Miller continue; 703edcd5821SDavid S. Miller break; 7043ff50b79SStephen Hemminger } 705edcd5821SDavid S. Miller 706edcd5821SDavid S. Miller xfrm_state_hold(x); 707edcd5821SDavid S. Miller return x; 708edcd5821SDavid S. Miller } 709edcd5821SDavid S. Miller 710edcd5821SDavid S. Miller return NULL; 711edcd5821SDavid S. Miller } 712edcd5821SDavid S. Miller 713edcd5821SDavid S. Miller static struct xfrm_state *__xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto, unsigned short family) 714edcd5821SDavid S. Miller { 715667bbcb6SMasahide NAKAMURA unsigned int h = xfrm_src_hash(daddr, saddr, family); 716edcd5821SDavid S. Miller struct xfrm_state *x; 7178f126e37SDavid S. Miller struct hlist_node *entry; 718edcd5821SDavid S. Miller 7198f126e37SDavid S. Miller hlist_for_each_entry(x, entry, xfrm_state_bysrc+h, bysrc) { 720edcd5821SDavid S. Miller if (x->props.family != family || 721edcd5821SDavid S. Miller x->id.proto != proto) 722edcd5821SDavid S. Miller continue; 723edcd5821SDavid S. Miller 724edcd5821SDavid S. Miller switch (family) { 725edcd5821SDavid S. Miller case AF_INET: 726edcd5821SDavid S. Miller if (x->id.daddr.a4 != daddr->a4 || 727edcd5821SDavid S. Miller x->props.saddr.a4 != saddr->a4) 728edcd5821SDavid S. Miller continue; 729edcd5821SDavid S. Miller break; 730edcd5821SDavid S. Miller case AF_INET6: 731edcd5821SDavid S. Miller if (!ipv6_addr_equal((struct in6_addr *)daddr, 732edcd5821SDavid S. Miller (struct in6_addr *) 733edcd5821SDavid S. Miller x->id.daddr.a6) || 734edcd5821SDavid S. Miller !ipv6_addr_equal((struct in6_addr *)saddr, 735edcd5821SDavid S. Miller (struct in6_addr *) 736edcd5821SDavid S. Miller x->props.saddr.a6)) 737edcd5821SDavid S. Miller continue; 738edcd5821SDavid S. Miller break; 7393ff50b79SStephen Hemminger } 740edcd5821SDavid S. Miller 741edcd5821SDavid S. Miller xfrm_state_hold(x); 742edcd5821SDavid S. Miller return x; 743edcd5821SDavid S. Miller } 744edcd5821SDavid S. Miller 745edcd5821SDavid S. Miller return NULL; 746edcd5821SDavid S. Miller } 747edcd5821SDavid S. Miller 748edcd5821SDavid S. Miller static inline struct xfrm_state * 749edcd5821SDavid S. Miller __xfrm_state_locate(struct xfrm_state *x, int use_spi, int family) 750edcd5821SDavid S. Miller { 751edcd5821SDavid S. Miller if (use_spi) 752edcd5821SDavid S. Miller return __xfrm_state_lookup(&x->id.daddr, x->id.spi, 753edcd5821SDavid S. Miller x->id.proto, family); 754edcd5821SDavid S. Miller else 755edcd5821SDavid S. Miller return __xfrm_state_lookup_byaddr(&x->id.daddr, 756edcd5821SDavid S. Miller &x->props.saddr, 757edcd5821SDavid S. Miller x->id.proto, family); 758edcd5821SDavid S. Miller } 759edcd5821SDavid S. Miller 7602fab22f2SPatrick McHardy static void xfrm_hash_grow_check(int have_hash_collision) 7612fab22f2SPatrick McHardy { 7622fab22f2SPatrick McHardy if (have_hash_collision && 7632fab22f2SPatrick McHardy (xfrm_state_hmask + 1) < xfrm_state_hashmax && 7642fab22f2SPatrick McHardy xfrm_state_num > xfrm_state_hmask) 7652fab22f2SPatrick McHardy schedule_work(&xfrm_hash_work); 7662fab22f2SPatrick McHardy } 7672fab22f2SPatrick McHardy 7681da177e4SLinus Torvalds struct xfrm_state * 7691da177e4SLinus Torvalds xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, 7701da177e4SLinus Torvalds struct flowi *fl, struct xfrm_tmpl *tmpl, 7711da177e4SLinus Torvalds struct xfrm_policy *pol, int *err, 7721da177e4SLinus Torvalds unsigned short family) 7731da177e4SLinus Torvalds { 7744bda4f25SPavel Emelyanov unsigned int h; 7758f126e37SDavid S. Miller struct hlist_node *entry; 7761da177e4SLinus Torvalds struct xfrm_state *x, *x0; 7771da177e4SLinus Torvalds int acquire_in_progress = 0; 7781da177e4SLinus Torvalds int error = 0; 7791da177e4SLinus Torvalds struct xfrm_state *best = NULL; 7801da177e4SLinus Torvalds 7811da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_lock); 7824bda4f25SPavel Emelyanov h = xfrm_dst_hash(daddr, saddr, tmpl->reqid, family); 7838f126e37SDavid S. Miller hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) { 7841da177e4SLinus Torvalds if (x->props.family == family && 7851da177e4SLinus Torvalds x->props.reqid == tmpl->reqid && 786fbd9a5b4SMasahide NAKAMURA !(x->props.flags & XFRM_STATE_WILDRECV) && 7871da177e4SLinus Torvalds xfrm_state_addr_check(x, daddr, saddr, family) && 7881da177e4SLinus Torvalds tmpl->mode == x->props.mode && 7891da177e4SLinus Torvalds tmpl->id.proto == x->id.proto && 7901da177e4SLinus Torvalds (tmpl->id.spi == x->id.spi || !tmpl->id.spi)) { 7911da177e4SLinus Torvalds /* Resolution logic: 7921da177e4SLinus Torvalds 1. There is a valid state with matching selector. 7931da177e4SLinus Torvalds Done. 7941da177e4SLinus Torvalds 2. Valid state with inappropriate selector. Skip. 7951da177e4SLinus Torvalds 7961da177e4SLinus Torvalds Entering area of "sysdeps". 7971da177e4SLinus Torvalds 7981da177e4SLinus Torvalds 3. If state is not valid, selector is temporary, 7991da177e4SLinus Torvalds it selects only session which triggered 8001da177e4SLinus Torvalds previous resolution. Key manager will do 8011da177e4SLinus Torvalds something to install a state with proper 8021da177e4SLinus Torvalds selector. 8031da177e4SLinus Torvalds */ 8041da177e4SLinus Torvalds if (x->km.state == XFRM_STATE_VALID) { 80548b8d783SJoakim Koskela if (!xfrm_selector_match(&x->sel, fl, x->sel.family) || 806e0d1caa7SVenkat Yekkirala !security_xfrm_state_pol_flow_match(x, pol, fl)) 8071da177e4SLinus Torvalds continue; 8081da177e4SLinus Torvalds if (!best || 8091da177e4SLinus Torvalds best->km.dying > x->km.dying || 8101da177e4SLinus Torvalds (best->km.dying == x->km.dying && 8111da177e4SLinus Torvalds best->curlft.add_time < x->curlft.add_time)) 8121da177e4SLinus Torvalds best = x; 8131da177e4SLinus Torvalds } else if (x->km.state == XFRM_STATE_ACQ) { 8141da177e4SLinus Torvalds acquire_in_progress = 1; 8151da177e4SLinus Torvalds } else if (x->km.state == XFRM_STATE_ERROR || 8161da177e4SLinus Torvalds x->km.state == XFRM_STATE_EXPIRED) { 81748b8d783SJoakim Koskela if (xfrm_selector_match(&x->sel, fl, x->sel.family) && 818e0d1caa7SVenkat Yekkirala security_xfrm_state_pol_flow_match(x, pol, fl)) 8191da177e4SLinus Torvalds error = -ESRCH; 8201da177e4SLinus Torvalds } 8211da177e4SLinus Torvalds } 8221da177e4SLinus Torvalds } 8231da177e4SLinus Torvalds 8241da177e4SLinus Torvalds x = best; 8251da177e4SLinus Torvalds if (!x && !error && !acquire_in_progress) { 8265c5d281aSPatrick McHardy if (tmpl->id.spi && 827edcd5821SDavid S. Miller (x0 = __xfrm_state_lookup(daddr, tmpl->id.spi, 828edcd5821SDavid S. Miller tmpl->id.proto, family)) != NULL) { 8291da177e4SLinus Torvalds xfrm_state_put(x0); 8301da177e4SLinus Torvalds error = -EEXIST; 8311da177e4SLinus Torvalds goto out; 8321da177e4SLinus Torvalds } 8331da177e4SLinus Torvalds x = xfrm_state_alloc(); 8341da177e4SLinus Torvalds if (x == NULL) { 8351da177e4SLinus Torvalds error = -ENOMEM; 8361da177e4SLinus Torvalds goto out; 8371da177e4SLinus Torvalds } 8381da177e4SLinus Torvalds /* Initialize temporary selector matching only 8391da177e4SLinus Torvalds * to current session. */ 8401da177e4SLinus Torvalds xfrm_init_tempsel(x, fl, tmpl, daddr, saddr, family); 8411da177e4SLinus Torvalds 842e0d1caa7SVenkat Yekkirala error = security_xfrm_state_alloc_acquire(x, pol->security, fl->secid); 843e0d1caa7SVenkat Yekkirala if (error) { 844e0d1caa7SVenkat Yekkirala x->km.state = XFRM_STATE_DEAD; 845e0d1caa7SVenkat Yekkirala xfrm_state_put(x); 846e0d1caa7SVenkat Yekkirala x = NULL; 847e0d1caa7SVenkat Yekkirala goto out; 848e0d1caa7SVenkat Yekkirala } 849e0d1caa7SVenkat Yekkirala 8501da177e4SLinus Torvalds if (km_query(x, tmpl, pol) == 0) { 8511da177e4SLinus Torvalds x->km.state = XFRM_STATE_ACQ; 8528f126e37SDavid S. Miller hlist_add_head(&x->bydst, xfrm_state_bydst+h); 853667bbcb6SMasahide NAKAMURA h = xfrm_src_hash(daddr, saddr, family); 8548f126e37SDavid S. Miller hlist_add_head(&x->bysrc, xfrm_state_bysrc+h); 8551da177e4SLinus Torvalds if (x->id.spi) { 8561da177e4SLinus Torvalds h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, family); 8578f126e37SDavid S. Miller hlist_add_head(&x->byspi, xfrm_state_byspi+h); 8581da177e4SLinus Torvalds } 85901e67d08SDavid S. Miller x->lft.hard_add_expires_seconds = sysctl_xfrm_acq_expires; 86001e67d08SDavid S. Miller x->timer.expires = jiffies + sysctl_xfrm_acq_expires*HZ; 8611da177e4SLinus Torvalds add_timer(&x->timer); 8622fab22f2SPatrick McHardy xfrm_state_num++; 8632fab22f2SPatrick McHardy xfrm_hash_grow_check(x->bydst.next != NULL); 8641da177e4SLinus Torvalds } else { 8651da177e4SLinus Torvalds x->km.state = XFRM_STATE_DEAD; 8661da177e4SLinus Torvalds xfrm_state_put(x); 8671da177e4SLinus Torvalds x = NULL; 8681da177e4SLinus Torvalds error = -ESRCH; 8691da177e4SLinus Torvalds } 8701da177e4SLinus Torvalds } 8711da177e4SLinus Torvalds out: 8721da177e4SLinus Torvalds if (x) 8731da177e4SLinus Torvalds xfrm_state_hold(x); 8741da177e4SLinus Torvalds else 8751da177e4SLinus Torvalds *err = acquire_in_progress ? -EAGAIN : error; 8761da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_lock); 8771da177e4SLinus Torvalds return x; 8781da177e4SLinus Torvalds } 8791da177e4SLinus Torvalds 880628529b6SJamal Hadi Salim struct xfrm_state * 881628529b6SJamal Hadi Salim xfrm_stateonly_find(xfrm_address_t *daddr, xfrm_address_t *saddr, 882628529b6SJamal Hadi Salim unsigned short family, u8 mode, u8 proto, u32 reqid) 883628529b6SJamal Hadi Salim { 8844bda4f25SPavel Emelyanov unsigned int h; 885628529b6SJamal Hadi Salim struct xfrm_state *rx = NULL, *x = NULL; 886628529b6SJamal Hadi Salim struct hlist_node *entry; 887628529b6SJamal Hadi Salim 888628529b6SJamal Hadi Salim spin_lock(&xfrm_state_lock); 8894bda4f25SPavel Emelyanov h = xfrm_dst_hash(daddr, saddr, reqid, family); 890628529b6SJamal Hadi Salim hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) { 891628529b6SJamal Hadi Salim if (x->props.family == family && 892628529b6SJamal Hadi Salim x->props.reqid == reqid && 893628529b6SJamal Hadi Salim !(x->props.flags & XFRM_STATE_WILDRECV) && 894628529b6SJamal Hadi Salim xfrm_state_addr_check(x, daddr, saddr, family) && 895628529b6SJamal Hadi Salim mode == x->props.mode && 896628529b6SJamal Hadi Salim proto == x->id.proto && 897628529b6SJamal Hadi Salim x->km.state == XFRM_STATE_VALID) { 898628529b6SJamal Hadi Salim rx = x; 899628529b6SJamal Hadi Salim break; 900628529b6SJamal Hadi Salim } 901628529b6SJamal Hadi Salim } 902628529b6SJamal Hadi Salim 903628529b6SJamal Hadi Salim if (rx) 904628529b6SJamal Hadi Salim xfrm_state_hold(rx); 905628529b6SJamal Hadi Salim spin_unlock(&xfrm_state_lock); 906628529b6SJamal Hadi Salim 907628529b6SJamal Hadi Salim 908628529b6SJamal Hadi Salim return rx; 909628529b6SJamal Hadi Salim } 910628529b6SJamal Hadi Salim EXPORT_SYMBOL(xfrm_stateonly_find); 911628529b6SJamal Hadi Salim 9121da177e4SLinus Torvalds static void __xfrm_state_insert(struct xfrm_state *x) 9131da177e4SLinus Torvalds { 914a624c108SDavid S. Miller unsigned int h; 9151da177e4SLinus Torvalds 9169d4a706dSDavid S. Miller x->genid = ++xfrm_state_genid; 9179d4a706dSDavid S. Miller 918*4c563f76STimo Teras list_add_tail(&x->all, &xfrm_state_all); 919*4c563f76STimo Teras 920c1969f29SDavid S. Miller h = xfrm_dst_hash(&x->id.daddr, &x->props.saddr, 921c1969f29SDavid S. Miller x->props.reqid, x->props.family); 9228f126e37SDavid S. Miller hlist_add_head(&x->bydst, xfrm_state_bydst+h); 9231da177e4SLinus Torvalds 924667bbcb6SMasahide NAKAMURA h = xfrm_src_hash(&x->id.daddr, &x->props.saddr, x->props.family); 9258f126e37SDavid S. Miller hlist_add_head(&x->bysrc, xfrm_state_bysrc+h); 9266c44e6b7SMasahide NAKAMURA 9277b4dc360SMasahide NAKAMURA if (x->id.spi) { 9286c44e6b7SMasahide NAKAMURA h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, 9296c44e6b7SMasahide NAKAMURA x->props.family); 9301da177e4SLinus Torvalds 9318f126e37SDavid S. Miller hlist_add_head(&x->byspi, xfrm_state_byspi+h); 9326c44e6b7SMasahide NAKAMURA } 9331da177e4SLinus Torvalds 934a47f0ce0SDavid S. Miller mod_timer(&x->timer, jiffies + HZ); 935a47f0ce0SDavid S. Miller if (x->replay_maxage) 936a47f0ce0SDavid S. Miller mod_timer(&x->rtimer, jiffies + x->replay_maxage); 937f8cd5488SJamal Hadi Salim 9381da177e4SLinus Torvalds wake_up(&km_waitq); 939f034b5d4SDavid S. Miller 940f034b5d4SDavid S. Miller xfrm_state_num++; 941f034b5d4SDavid S. Miller 942918049f0SDavid S. Miller xfrm_hash_grow_check(x->bydst.next != NULL); 9431da177e4SLinus Torvalds } 9441da177e4SLinus Torvalds 945c7f5ea3aSDavid S. Miller /* xfrm_state_lock is held */ 946c7f5ea3aSDavid S. Miller static void __xfrm_state_bump_genids(struct xfrm_state *xnew) 947c7f5ea3aSDavid S. Miller { 948c7f5ea3aSDavid S. Miller unsigned short family = xnew->props.family; 949c7f5ea3aSDavid S. Miller u32 reqid = xnew->props.reqid; 950c7f5ea3aSDavid S. Miller struct xfrm_state *x; 951c7f5ea3aSDavid S. Miller struct hlist_node *entry; 952c7f5ea3aSDavid S. Miller unsigned int h; 953c7f5ea3aSDavid S. Miller 954c1969f29SDavid S. Miller h = xfrm_dst_hash(&xnew->id.daddr, &xnew->props.saddr, reqid, family); 955c7f5ea3aSDavid S. Miller hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) { 956c7f5ea3aSDavid S. Miller if (x->props.family == family && 957c7f5ea3aSDavid S. Miller x->props.reqid == reqid && 958c1969f29SDavid S. Miller !xfrm_addr_cmp(&x->id.daddr, &xnew->id.daddr, family) && 959c1969f29SDavid S. Miller !xfrm_addr_cmp(&x->props.saddr, &xnew->props.saddr, family)) 960c7f5ea3aSDavid S. Miller x->genid = xfrm_state_genid; 961c7f5ea3aSDavid S. Miller } 962c7f5ea3aSDavid S. Miller } 963c7f5ea3aSDavid S. Miller 9641da177e4SLinus Torvalds void xfrm_state_insert(struct xfrm_state *x) 9651da177e4SLinus Torvalds { 9661da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_lock); 967c7f5ea3aSDavid S. Miller __xfrm_state_bump_genids(x); 9681da177e4SLinus Torvalds __xfrm_state_insert(x); 9691da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_lock); 9701da177e4SLinus Torvalds } 9711da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_insert); 9721da177e4SLinus Torvalds 9732770834cSDavid S. Miller /* xfrm_state_lock is held */ 9742770834cSDavid 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) 9752770834cSDavid S. Miller { 976c1969f29SDavid S. Miller unsigned int h = xfrm_dst_hash(daddr, saddr, reqid, family); 9778f126e37SDavid S. Miller struct hlist_node *entry; 9782770834cSDavid S. Miller struct xfrm_state *x; 9792770834cSDavid S. Miller 9808f126e37SDavid S. Miller hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) { 9812770834cSDavid S. Miller if (x->props.reqid != reqid || 9822770834cSDavid S. Miller x->props.mode != mode || 9832770834cSDavid S. Miller x->props.family != family || 9842770834cSDavid S. Miller x->km.state != XFRM_STATE_ACQ || 98575e252d9SJoy Latten x->id.spi != 0 || 98675e252d9SJoy Latten x->id.proto != proto) 9872770834cSDavid S. Miller continue; 9882770834cSDavid S. Miller 9892770834cSDavid S. Miller switch (family) { 9902770834cSDavid S. Miller case AF_INET: 9912770834cSDavid S. Miller if (x->id.daddr.a4 != daddr->a4 || 9922770834cSDavid S. Miller x->props.saddr.a4 != saddr->a4) 9932770834cSDavid S. Miller continue; 9942770834cSDavid S. Miller break; 9952770834cSDavid S. Miller case AF_INET6: 9962770834cSDavid S. Miller if (!ipv6_addr_equal((struct in6_addr *)x->id.daddr.a6, 9972770834cSDavid S. Miller (struct in6_addr *)daddr) || 9982770834cSDavid S. Miller !ipv6_addr_equal((struct in6_addr *) 9992770834cSDavid S. Miller x->props.saddr.a6, 10002770834cSDavid S. Miller (struct in6_addr *)saddr)) 10012770834cSDavid S. Miller continue; 10022770834cSDavid S. Miller break; 10033ff50b79SStephen Hemminger } 10042770834cSDavid S. Miller 10052770834cSDavid S. Miller xfrm_state_hold(x); 10062770834cSDavid S. Miller return x; 10072770834cSDavid S. Miller } 10082770834cSDavid S. Miller 10092770834cSDavid S. Miller if (!create) 10102770834cSDavid S. Miller return NULL; 10112770834cSDavid S. Miller 10122770834cSDavid S. Miller x = xfrm_state_alloc(); 10132770834cSDavid S. Miller if (likely(x)) { 10142770834cSDavid S. Miller switch (family) { 10152770834cSDavid S. Miller case AF_INET: 10162770834cSDavid S. Miller x->sel.daddr.a4 = daddr->a4; 10172770834cSDavid S. Miller x->sel.saddr.a4 = saddr->a4; 10182770834cSDavid S. Miller x->sel.prefixlen_d = 32; 10192770834cSDavid S. Miller x->sel.prefixlen_s = 32; 10202770834cSDavid S. Miller x->props.saddr.a4 = saddr->a4; 10212770834cSDavid S. Miller x->id.daddr.a4 = daddr->a4; 10222770834cSDavid S. Miller break; 10232770834cSDavid S. Miller 10242770834cSDavid S. Miller case AF_INET6: 10252770834cSDavid S. Miller ipv6_addr_copy((struct in6_addr *)x->sel.daddr.a6, 10262770834cSDavid S. Miller (struct in6_addr *)daddr); 10272770834cSDavid S. Miller ipv6_addr_copy((struct in6_addr *)x->sel.saddr.a6, 10282770834cSDavid S. Miller (struct in6_addr *)saddr); 10292770834cSDavid S. Miller x->sel.prefixlen_d = 128; 10302770834cSDavid S. Miller x->sel.prefixlen_s = 128; 10312770834cSDavid S. Miller ipv6_addr_copy((struct in6_addr *)x->props.saddr.a6, 10322770834cSDavid S. Miller (struct in6_addr *)saddr); 10332770834cSDavid S. Miller ipv6_addr_copy((struct in6_addr *)x->id.daddr.a6, 10342770834cSDavid S. Miller (struct in6_addr *)daddr); 10352770834cSDavid S. Miller break; 10363ff50b79SStephen Hemminger } 10372770834cSDavid S. Miller 10382770834cSDavid S. Miller x->km.state = XFRM_STATE_ACQ; 10392770834cSDavid S. Miller x->id.proto = proto; 10402770834cSDavid S. Miller x->props.family = family; 10412770834cSDavid S. Miller x->props.mode = mode; 10422770834cSDavid S. Miller x->props.reqid = reqid; 104301e67d08SDavid S. Miller x->lft.hard_add_expires_seconds = sysctl_xfrm_acq_expires; 10442770834cSDavid S. Miller xfrm_state_hold(x); 104501e67d08SDavid S. Miller x->timer.expires = jiffies + sysctl_xfrm_acq_expires*HZ; 10462770834cSDavid S. Miller add_timer(&x->timer); 10478f126e37SDavid S. Miller hlist_add_head(&x->bydst, xfrm_state_bydst+h); 1048667bbcb6SMasahide NAKAMURA h = xfrm_src_hash(daddr, saddr, family); 10498f126e37SDavid S. Miller hlist_add_head(&x->bysrc, 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 { 10631da177e4SLinus Torvalds struct xfrm_state *x1; 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 10701da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_lock); 10711da177e4SLinus Torvalds 1072edcd5821SDavid S. Miller x1 = __xfrm_state_locate(x, use_spi, family); 10731da177e4SLinus Torvalds if (x1) { 10741da177e4SLinus Torvalds xfrm_state_put(x1); 10751da177e4SLinus Torvalds x1 = NULL; 10761da177e4SLinus Torvalds err = -EEXIST; 10771da177e4SLinus Torvalds goto out; 10781da177e4SLinus Torvalds } 10791da177e4SLinus Torvalds 1080eb2971b6SMasahide NAKAMURA if (use_spi && x->km.seq) { 10811da177e4SLinus Torvalds x1 = __xfrm_find_acq_byseq(x->km.seq); 108275e252d9SJoy Latten if (x1 && ((x1->id.proto != x->id.proto) || 108375e252d9SJoy Latten xfrm_addr_cmp(&x1->id.daddr, &x->id.daddr, family))) { 10841da177e4SLinus Torvalds xfrm_state_put(x1); 10851da177e4SLinus Torvalds x1 = NULL; 10861da177e4SLinus Torvalds } 10871da177e4SLinus Torvalds } 10881da177e4SLinus Torvalds 1089eb2971b6SMasahide NAKAMURA if (use_spi && !x1) 10902770834cSDavid S. Miller x1 = __find_acq_core(family, x->props.mode, x->props.reqid, 10912770834cSDavid S. Miller x->id.proto, 10921da177e4SLinus Torvalds &x->id.daddr, &x->props.saddr, 0); 10931da177e4SLinus Torvalds 1094c7f5ea3aSDavid S. Miller __xfrm_state_bump_genids(x); 10951da177e4SLinus Torvalds __xfrm_state_insert(x); 10961da177e4SLinus Torvalds err = 0; 10971da177e4SLinus Torvalds 10981da177e4SLinus Torvalds out: 10991da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_lock); 11001da177e4SLinus Torvalds 11011da177e4SLinus Torvalds if (x1) { 11021da177e4SLinus Torvalds xfrm_state_delete(x1); 11031da177e4SLinus Torvalds xfrm_state_put(x1); 11041da177e4SLinus Torvalds } 11051da177e4SLinus Torvalds 11061da177e4SLinus Torvalds return err; 11071da177e4SLinus Torvalds } 11081da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_add); 11091da177e4SLinus Torvalds 111080c9abaaSShinta Sugimoto #ifdef CONFIG_XFRM_MIGRATE 11116666351dSEric Dumazet static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp) 111280c9abaaSShinta Sugimoto { 111380c9abaaSShinta Sugimoto int err = -ENOMEM; 111480c9abaaSShinta Sugimoto struct xfrm_state *x = xfrm_state_alloc(); 111580c9abaaSShinta Sugimoto if (!x) 111680c9abaaSShinta Sugimoto goto error; 111780c9abaaSShinta Sugimoto 111880c9abaaSShinta Sugimoto memcpy(&x->id, &orig->id, sizeof(x->id)); 111980c9abaaSShinta Sugimoto memcpy(&x->sel, &orig->sel, sizeof(x->sel)); 112080c9abaaSShinta Sugimoto memcpy(&x->lft, &orig->lft, sizeof(x->lft)); 112180c9abaaSShinta Sugimoto x->props.mode = orig->props.mode; 112280c9abaaSShinta Sugimoto x->props.replay_window = orig->props.replay_window; 112380c9abaaSShinta Sugimoto x->props.reqid = orig->props.reqid; 112480c9abaaSShinta Sugimoto x->props.family = orig->props.family; 112580c9abaaSShinta Sugimoto x->props.saddr = orig->props.saddr; 112680c9abaaSShinta Sugimoto 112780c9abaaSShinta Sugimoto if (orig->aalg) { 112880c9abaaSShinta Sugimoto x->aalg = xfrm_algo_clone(orig->aalg); 112980c9abaaSShinta Sugimoto if (!x->aalg) 113080c9abaaSShinta Sugimoto goto error; 113180c9abaaSShinta Sugimoto } 113280c9abaaSShinta Sugimoto x->props.aalgo = orig->props.aalgo; 113380c9abaaSShinta Sugimoto 113480c9abaaSShinta Sugimoto if (orig->ealg) { 113580c9abaaSShinta Sugimoto x->ealg = xfrm_algo_clone(orig->ealg); 113680c9abaaSShinta Sugimoto if (!x->ealg) 113780c9abaaSShinta Sugimoto goto error; 113880c9abaaSShinta Sugimoto } 113980c9abaaSShinta Sugimoto x->props.ealgo = orig->props.ealgo; 114080c9abaaSShinta Sugimoto 114180c9abaaSShinta Sugimoto if (orig->calg) { 114280c9abaaSShinta Sugimoto x->calg = xfrm_algo_clone(orig->calg); 114380c9abaaSShinta Sugimoto if (!x->calg) 114480c9abaaSShinta Sugimoto goto error; 114580c9abaaSShinta Sugimoto } 114680c9abaaSShinta Sugimoto x->props.calgo = orig->props.calgo; 114780c9abaaSShinta Sugimoto 114880c9abaaSShinta Sugimoto if (orig->encap) { 114980c9abaaSShinta Sugimoto x->encap = kmemdup(orig->encap, sizeof(*x->encap), GFP_KERNEL); 115080c9abaaSShinta Sugimoto if (!x->encap) 115180c9abaaSShinta Sugimoto goto error; 115280c9abaaSShinta Sugimoto } 115380c9abaaSShinta Sugimoto 115480c9abaaSShinta Sugimoto if (orig->coaddr) { 115580c9abaaSShinta Sugimoto x->coaddr = kmemdup(orig->coaddr, sizeof(*x->coaddr), 115680c9abaaSShinta Sugimoto GFP_KERNEL); 115780c9abaaSShinta Sugimoto if (!x->coaddr) 115880c9abaaSShinta Sugimoto goto error; 115980c9abaaSShinta Sugimoto } 116080c9abaaSShinta Sugimoto 116180c9abaaSShinta Sugimoto err = xfrm_init_state(x); 116280c9abaaSShinta Sugimoto if (err) 116380c9abaaSShinta Sugimoto goto error; 116480c9abaaSShinta Sugimoto 116580c9abaaSShinta Sugimoto x->props.flags = orig->props.flags; 116680c9abaaSShinta Sugimoto 116780c9abaaSShinta Sugimoto x->curlft.add_time = orig->curlft.add_time; 116880c9abaaSShinta Sugimoto x->km.state = orig->km.state; 116980c9abaaSShinta Sugimoto x->km.seq = orig->km.seq; 117080c9abaaSShinta Sugimoto 117180c9abaaSShinta Sugimoto return x; 117280c9abaaSShinta Sugimoto 117380c9abaaSShinta Sugimoto error: 117480c9abaaSShinta Sugimoto if (errp) 117580c9abaaSShinta Sugimoto *errp = err; 117680c9abaaSShinta Sugimoto if (x) { 117780c9abaaSShinta Sugimoto kfree(x->aalg); 117880c9abaaSShinta Sugimoto kfree(x->ealg); 117980c9abaaSShinta Sugimoto kfree(x->calg); 118080c9abaaSShinta Sugimoto kfree(x->encap); 118180c9abaaSShinta Sugimoto kfree(x->coaddr); 118280c9abaaSShinta Sugimoto } 118380c9abaaSShinta Sugimoto kfree(x); 118480c9abaaSShinta Sugimoto return NULL; 118580c9abaaSShinta Sugimoto } 118680c9abaaSShinta Sugimoto 118780c9abaaSShinta Sugimoto /* xfrm_state_lock is held */ 118880c9abaaSShinta Sugimoto struct xfrm_state * xfrm_migrate_state_find(struct xfrm_migrate *m) 118980c9abaaSShinta Sugimoto { 119080c9abaaSShinta Sugimoto unsigned int h; 119180c9abaaSShinta Sugimoto struct xfrm_state *x; 119280c9abaaSShinta Sugimoto struct hlist_node *entry; 119380c9abaaSShinta Sugimoto 119480c9abaaSShinta Sugimoto if (m->reqid) { 119580c9abaaSShinta Sugimoto h = xfrm_dst_hash(&m->old_daddr, &m->old_saddr, 119680c9abaaSShinta Sugimoto m->reqid, m->old_family); 119780c9abaaSShinta Sugimoto hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) { 119880c9abaaSShinta Sugimoto if (x->props.mode != m->mode || 119980c9abaaSShinta Sugimoto x->id.proto != m->proto) 120080c9abaaSShinta Sugimoto continue; 120180c9abaaSShinta Sugimoto if (m->reqid && x->props.reqid != m->reqid) 120280c9abaaSShinta Sugimoto continue; 120380c9abaaSShinta Sugimoto if (xfrm_addr_cmp(&x->id.daddr, &m->old_daddr, 120480c9abaaSShinta Sugimoto m->old_family) || 120580c9abaaSShinta Sugimoto xfrm_addr_cmp(&x->props.saddr, &m->old_saddr, 120680c9abaaSShinta Sugimoto m->old_family)) 120780c9abaaSShinta Sugimoto continue; 120880c9abaaSShinta Sugimoto xfrm_state_hold(x); 120980c9abaaSShinta Sugimoto return x; 121080c9abaaSShinta Sugimoto } 121180c9abaaSShinta Sugimoto } else { 121280c9abaaSShinta Sugimoto h = xfrm_src_hash(&m->old_daddr, &m->old_saddr, 121380c9abaaSShinta Sugimoto m->old_family); 121480c9abaaSShinta Sugimoto hlist_for_each_entry(x, entry, xfrm_state_bysrc+h, bysrc) { 121580c9abaaSShinta Sugimoto if (x->props.mode != m->mode || 121680c9abaaSShinta Sugimoto x->id.proto != m->proto) 121780c9abaaSShinta Sugimoto continue; 121880c9abaaSShinta Sugimoto if (xfrm_addr_cmp(&x->id.daddr, &m->old_daddr, 121980c9abaaSShinta Sugimoto m->old_family) || 122080c9abaaSShinta Sugimoto xfrm_addr_cmp(&x->props.saddr, &m->old_saddr, 122180c9abaaSShinta Sugimoto m->old_family)) 122280c9abaaSShinta Sugimoto continue; 122380c9abaaSShinta Sugimoto xfrm_state_hold(x); 122480c9abaaSShinta Sugimoto return x; 122580c9abaaSShinta Sugimoto } 122680c9abaaSShinta Sugimoto } 122780c9abaaSShinta Sugimoto 122880c9abaaSShinta Sugimoto return NULL; 122980c9abaaSShinta Sugimoto } 123080c9abaaSShinta Sugimoto EXPORT_SYMBOL(xfrm_migrate_state_find); 123180c9abaaSShinta Sugimoto 123280c9abaaSShinta Sugimoto struct xfrm_state * xfrm_state_migrate(struct xfrm_state *x, 123380c9abaaSShinta Sugimoto struct xfrm_migrate *m) 123480c9abaaSShinta Sugimoto { 123580c9abaaSShinta Sugimoto struct xfrm_state *xc; 123680c9abaaSShinta Sugimoto int err; 123780c9abaaSShinta Sugimoto 123880c9abaaSShinta Sugimoto xc = xfrm_state_clone(x, &err); 123980c9abaaSShinta Sugimoto if (!xc) 124080c9abaaSShinta Sugimoto return NULL; 124180c9abaaSShinta Sugimoto 124280c9abaaSShinta Sugimoto memcpy(&xc->id.daddr, &m->new_daddr, sizeof(xc->id.daddr)); 124380c9abaaSShinta Sugimoto memcpy(&xc->props.saddr, &m->new_saddr, sizeof(xc->props.saddr)); 124480c9abaaSShinta Sugimoto 124580c9abaaSShinta Sugimoto /* add state */ 124680c9abaaSShinta Sugimoto if (!xfrm_addr_cmp(&x->id.daddr, &m->new_daddr, m->new_family)) { 124780c9abaaSShinta Sugimoto /* a care is needed when the destination address of the 124880c9abaaSShinta Sugimoto state is to be updated as it is a part of triplet */ 124980c9abaaSShinta Sugimoto xfrm_state_insert(xc); 125080c9abaaSShinta Sugimoto } else { 125180c9abaaSShinta Sugimoto if ((err = xfrm_state_add(xc)) < 0) 125280c9abaaSShinta Sugimoto goto error; 125380c9abaaSShinta Sugimoto } 125480c9abaaSShinta Sugimoto 125580c9abaaSShinta Sugimoto return xc; 125680c9abaaSShinta Sugimoto error: 125780c9abaaSShinta Sugimoto kfree(xc); 125880c9abaaSShinta Sugimoto return NULL; 125980c9abaaSShinta Sugimoto } 126080c9abaaSShinta Sugimoto EXPORT_SYMBOL(xfrm_state_migrate); 126180c9abaaSShinta Sugimoto #endif 126280c9abaaSShinta Sugimoto 12631da177e4SLinus Torvalds int xfrm_state_update(struct xfrm_state *x) 12641da177e4SLinus Torvalds { 12651da177e4SLinus Torvalds struct xfrm_state *x1; 12661da177e4SLinus Torvalds int err; 1267eb2971b6SMasahide NAKAMURA int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY); 12681da177e4SLinus Torvalds 12691da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_lock); 1270edcd5821SDavid S. Miller x1 = __xfrm_state_locate(x, use_spi, x->props.family); 12711da177e4SLinus Torvalds 12721da177e4SLinus Torvalds err = -ESRCH; 12731da177e4SLinus Torvalds if (!x1) 12741da177e4SLinus Torvalds goto out; 12751da177e4SLinus Torvalds 12761da177e4SLinus Torvalds if (xfrm_state_kern(x1)) { 12771da177e4SLinus Torvalds xfrm_state_put(x1); 12781da177e4SLinus Torvalds err = -EEXIST; 12791da177e4SLinus Torvalds goto out; 12801da177e4SLinus Torvalds } 12811da177e4SLinus Torvalds 12821da177e4SLinus Torvalds if (x1->km.state == XFRM_STATE_ACQ) { 12831da177e4SLinus Torvalds __xfrm_state_insert(x); 12841da177e4SLinus Torvalds x = NULL; 12851da177e4SLinus Torvalds } 12861da177e4SLinus Torvalds err = 0; 12871da177e4SLinus Torvalds 12881da177e4SLinus Torvalds out: 12891da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_lock); 12901da177e4SLinus Torvalds 12911da177e4SLinus Torvalds if (err) 12921da177e4SLinus Torvalds return err; 12931da177e4SLinus Torvalds 12941da177e4SLinus Torvalds if (!x) { 12951da177e4SLinus Torvalds xfrm_state_delete(x1); 12961da177e4SLinus Torvalds xfrm_state_put(x1); 12971da177e4SLinus Torvalds return 0; 12981da177e4SLinus Torvalds } 12991da177e4SLinus Torvalds 13001da177e4SLinus Torvalds err = -EINVAL; 13011da177e4SLinus Torvalds spin_lock_bh(&x1->lock); 13021da177e4SLinus Torvalds if (likely(x1->km.state == XFRM_STATE_VALID)) { 13031da177e4SLinus Torvalds if (x->encap && x1->encap) 13041da177e4SLinus Torvalds memcpy(x1->encap, x->encap, sizeof(*x1->encap)); 1305060f02a3SNoriaki TAKAMIYA if (x->coaddr && x1->coaddr) { 1306060f02a3SNoriaki TAKAMIYA memcpy(x1->coaddr, x->coaddr, sizeof(*x1->coaddr)); 1307060f02a3SNoriaki TAKAMIYA } 1308060f02a3SNoriaki TAKAMIYA if (!use_spi && memcmp(&x1->sel, &x->sel, sizeof(x1->sel))) 1309060f02a3SNoriaki TAKAMIYA memcpy(&x1->sel, &x->sel, sizeof(x1->sel)); 13101da177e4SLinus Torvalds memcpy(&x1->lft, &x->lft, sizeof(x1->lft)); 13111da177e4SLinus Torvalds x1->km.dying = 0; 13121da177e4SLinus Torvalds 1313a47f0ce0SDavid S. Miller mod_timer(&x1->timer, jiffies + HZ); 13141da177e4SLinus Torvalds if (x1->curlft.use_time) 13151da177e4SLinus Torvalds xfrm_state_check_expire(x1); 13161da177e4SLinus Torvalds 13171da177e4SLinus Torvalds err = 0; 13181da177e4SLinus Torvalds } 13191da177e4SLinus Torvalds spin_unlock_bh(&x1->lock); 13201da177e4SLinus Torvalds 13211da177e4SLinus Torvalds xfrm_state_put(x1); 13221da177e4SLinus Torvalds 13231da177e4SLinus Torvalds return err; 13241da177e4SLinus Torvalds } 13251da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_update); 13261da177e4SLinus Torvalds 13271da177e4SLinus Torvalds int xfrm_state_check_expire(struct xfrm_state *x) 13281da177e4SLinus Torvalds { 13291da177e4SLinus Torvalds if (!x->curlft.use_time) 13309d729f72SJames Morris x->curlft.use_time = get_seconds(); 13311da177e4SLinus Torvalds 13321da177e4SLinus Torvalds if (x->km.state != XFRM_STATE_VALID) 13331da177e4SLinus Torvalds return -EINVAL; 13341da177e4SLinus Torvalds 13351da177e4SLinus Torvalds if (x->curlft.bytes >= x->lft.hard_byte_limit || 13361da177e4SLinus Torvalds x->curlft.packets >= x->lft.hard_packet_limit) { 13374666faabSHerbert Xu x->km.state = XFRM_STATE_EXPIRED; 1338a47f0ce0SDavid S. Miller mod_timer(&x->timer, jiffies); 13391da177e4SLinus Torvalds return -EINVAL; 13401da177e4SLinus Torvalds } 13411da177e4SLinus Torvalds 13421da177e4SLinus Torvalds if (!x->km.dying && 13431da177e4SLinus Torvalds (x->curlft.bytes >= x->lft.soft_byte_limit || 13444666faabSHerbert Xu x->curlft.packets >= x->lft.soft_packet_limit)) { 13454666faabSHerbert Xu x->km.dying = 1; 134653bc6b4dSJamal Hadi Salim km_state_expired(x, 0, 0); 13474666faabSHerbert Xu } 13481da177e4SLinus Torvalds return 0; 13491da177e4SLinus Torvalds } 13501da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_check_expire); 13511da177e4SLinus Torvalds 13521da177e4SLinus Torvalds struct xfrm_state * 1353a94cfd19SAl Viro xfrm_state_lookup(xfrm_address_t *daddr, __be32 spi, u8 proto, 13541da177e4SLinus Torvalds unsigned short family) 13551da177e4SLinus Torvalds { 13561da177e4SLinus Torvalds struct xfrm_state *x; 13571da177e4SLinus Torvalds 13581da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_lock); 1359edcd5821SDavid S. Miller x = __xfrm_state_lookup(daddr, spi, proto, family); 13601da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_lock); 13611da177e4SLinus Torvalds return x; 13621da177e4SLinus Torvalds } 13631da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_lookup); 13641da177e4SLinus Torvalds 13651da177e4SLinus Torvalds struct xfrm_state * 1366eb2971b6SMasahide NAKAMURA xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr, 1367eb2971b6SMasahide NAKAMURA u8 proto, unsigned short family) 1368eb2971b6SMasahide NAKAMURA { 1369eb2971b6SMasahide NAKAMURA struct xfrm_state *x; 1370eb2971b6SMasahide NAKAMURA 1371eb2971b6SMasahide NAKAMURA spin_lock_bh(&xfrm_state_lock); 1372edcd5821SDavid S. Miller x = __xfrm_state_lookup_byaddr(daddr, saddr, proto, family); 1373eb2971b6SMasahide NAKAMURA spin_unlock_bh(&xfrm_state_lock); 1374eb2971b6SMasahide NAKAMURA return x; 1375eb2971b6SMasahide NAKAMURA } 1376eb2971b6SMasahide NAKAMURA EXPORT_SYMBOL(xfrm_state_lookup_byaddr); 1377eb2971b6SMasahide NAKAMURA 1378eb2971b6SMasahide NAKAMURA struct xfrm_state * 13791da177e4SLinus Torvalds xfrm_find_acq(u8 mode, u32 reqid, u8 proto, 13801da177e4SLinus Torvalds xfrm_address_t *daddr, xfrm_address_t *saddr, 13811da177e4SLinus Torvalds int create, unsigned short family) 13821da177e4SLinus Torvalds { 13831da177e4SLinus Torvalds struct xfrm_state *x; 13841da177e4SLinus Torvalds 13851da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_lock); 13862770834cSDavid S. Miller x = __find_acq_core(family, mode, reqid, proto, daddr, saddr, create); 13871da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_lock); 13882770834cSDavid S. Miller 13891da177e4SLinus Torvalds return x; 13901da177e4SLinus Torvalds } 13911da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_find_acq); 13921da177e4SLinus Torvalds 139341a49cc3SMasahide NAKAMURA #ifdef CONFIG_XFRM_SUB_POLICY 139441a49cc3SMasahide NAKAMURA int 139541a49cc3SMasahide NAKAMURA xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n, 139641a49cc3SMasahide NAKAMURA unsigned short family) 139741a49cc3SMasahide NAKAMURA { 139841a49cc3SMasahide NAKAMURA int err = 0; 139941a49cc3SMasahide NAKAMURA struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); 140041a49cc3SMasahide NAKAMURA if (!afinfo) 140141a49cc3SMasahide NAKAMURA return -EAFNOSUPPORT; 140241a49cc3SMasahide NAKAMURA 140341a49cc3SMasahide NAKAMURA spin_lock_bh(&xfrm_state_lock); 140441a49cc3SMasahide NAKAMURA if (afinfo->tmpl_sort) 140541a49cc3SMasahide NAKAMURA err = afinfo->tmpl_sort(dst, src, n); 140641a49cc3SMasahide NAKAMURA spin_unlock_bh(&xfrm_state_lock); 140741a49cc3SMasahide NAKAMURA xfrm_state_put_afinfo(afinfo); 140841a49cc3SMasahide NAKAMURA return err; 140941a49cc3SMasahide NAKAMURA } 141041a49cc3SMasahide NAKAMURA EXPORT_SYMBOL(xfrm_tmpl_sort); 141141a49cc3SMasahide NAKAMURA 141241a49cc3SMasahide NAKAMURA int 141341a49cc3SMasahide NAKAMURA xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n, 141441a49cc3SMasahide NAKAMURA unsigned short family) 141541a49cc3SMasahide NAKAMURA { 141641a49cc3SMasahide NAKAMURA int err = 0; 141741a49cc3SMasahide NAKAMURA struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); 141841a49cc3SMasahide NAKAMURA if (!afinfo) 141941a49cc3SMasahide NAKAMURA return -EAFNOSUPPORT; 142041a49cc3SMasahide NAKAMURA 142141a49cc3SMasahide NAKAMURA spin_lock_bh(&xfrm_state_lock); 142241a49cc3SMasahide NAKAMURA if (afinfo->state_sort) 142341a49cc3SMasahide NAKAMURA err = afinfo->state_sort(dst, src, n); 142441a49cc3SMasahide NAKAMURA spin_unlock_bh(&xfrm_state_lock); 142541a49cc3SMasahide NAKAMURA xfrm_state_put_afinfo(afinfo); 142641a49cc3SMasahide NAKAMURA return err; 142741a49cc3SMasahide NAKAMURA } 142841a49cc3SMasahide NAKAMURA EXPORT_SYMBOL(xfrm_state_sort); 142941a49cc3SMasahide NAKAMURA #endif 143041a49cc3SMasahide NAKAMURA 14311da177e4SLinus Torvalds /* Silly enough, but I'm lazy to build resolution list */ 14321da177e4SLinus Torvalds 14331da177e4SLinus Torvalds static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq) 14341da177e4SLinus Torvalds { 14351da177e4SLinus Torvalds int i; 14361da177e4SLinus Torvalds 1437f034b5d4SDavid S. Miller for (i = 0; i <= xfrm_state_hmask; i++) { 14388f126e37SDavid S. Miller struct hlist_node *entry; 14398f126e37SDavid S. Miller struct xfrm_state *x; 14408f126e37SDavid S. Miller 14418f126e37SDavid S. Miller hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) { 14428f126e37SDavid S. Miller if (x->km.seq == seq && 14438f126e37SDavid S. Miller x->km.state == XFRM_STATE_ACQ) { 14441da177e4SLinus Torvalds xfrm_state_hold(x); 14451da177e4SLinus Torvalds return x; 14461da177e4SLinus Torvalds } 14471da177e4SLinus Torvalds } 14481da177e4SLinus Torvalds } 14491da177e4SLinus Torvalds return NULL; 14501da177e4SLinus Torvalds } 14511da177e4SLinus Torvalds 14521da177e4SLinus Torvalds struct xfrm_state *xfrm_find_acq_byseq(u32 seq) 14531da177e4SLinus Torvalds { 14541da177e4SLinus Torvalds struct xfrm_state *x; 14551da177e4SLinus Torvalds 14561da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_lock); 14571da177e4SLinus Torvalds x = __xfrm_find_acq_byseq(seq); 14581da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_lock); 14591da177e4SLinus Torvalds return x; 14601da177e4SLinus Torvalds } 14611da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_find_acq_byseq); 14621da177e4SLinus Torvalds 14631da177e4SLinus Torvalds u32 xfrm_get_acqseq(void) 14641da177e4SLinus Torvalds { 14651da177e4SLinus Torvalds u32 res; 14661da177e4SLinus Torvalds static u32 acqseq; 14671da177e4SLinus Torvalds static DEFINE_SPINLOCK(acqseq_lock); 14681da177e4SLinus Torvalds 14691da177e4SLinus Torvalds spin_lock_bh(&acqseq_lock); 14701da177e4SLinus Torvalds res = (++acqseq ? : ++acqseq); 14711da177e4SLinus Torvalds spin_unlock_bh(&acqseq_lock); 14721da177e4SLinus Torvalds return res; 14731da177e4SLinus Torvalds } 14741da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_get_acqseq); 14751da177e4SLinus Torvalds 1476658b219eSHerbert Xu int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high) 14771da177e4SLinus Torvalds { 1478f034b5d4SDavid S. Miller unsigned int h; 14791da177e4SLinus Torvalds struct xfrm_state *x0; 1480658b219eSHerbert Xu int err = -ENOENT; 1481658b219eSHerbert Xu __be32 minspi = htonl(low); 1482658b219eSHerbert Xu __be32 maxspi = htonl(high); 14831da177e4SLinus Torvalds 1484658b219eSHerbert Xu spin_lock_bh(&x->lock); 1485658b219eSHerbert Xu if (x->km.state == XFRM_STATE_DEAD) 1486658b219eSHerbert Xu goto unlock; 1487658b219eSHerbert Xu 1488658b219eSHerbert Xu err = 0; 14891da177e4SLinus Torvalds if (x->id.spi) 1490658b219eSHerbert Xu goto unlock; 1491658b219eSHerbert Xu 1492658b219eSHerbert Xu err = -ENOENT; 14931da177e4SLinus Torvalds 14941da177e4SLinus Torvalds if (minspi == maxspi) { 14951da177e4SLinus Torvalds x0 = xfrm_state_lookup(&x->id.daddr, minspi, x->id.proto, x->props.family); 14961da177e4SLinus Torvalds if (x0) { 14971da177e4SLinus Torvalds xfrm_state_put(x0); 1498658b219eSHerbert Xu goto unlock; 14991da177e4SLinus Torvalds } 15001da177e4SLinus Torvalds x->id.spi = minspi; 15011da177e4SLinus Torvalds } else { 15021da177e4SLinus Torvalds u32 spi = 0; 150326977b4eSAl Viro for (h=0; h<high-low+1; h++) { 150426977b4eSAl Viro spi = low + net_random()%(high-low+1); 15051da177e4SLinus Torvalds x0 = xfrm_state_lookup(&x->id.daddr, htonl(spi), x->id.proto, x->props.family); 15061da177e4SLinus Torvalds if (x0 == NULL) { 15071da177e4SLinus Torvalds x->id.spi = htonl(spi); 15081da177e4SLinus Torvalds break; 15091da177e4SLinus Torvalds } 15101da177e4SLinus Torvalds xfrm_state_put(x0); 15111da177e4SLinus Torvalds } 15121da177e4SLinus Torvalds } 15131da177e4SLinus Torvalds if (x->id.spi) { 15141da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_lock); 15151da177e4SLinus Torvalds h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, x->props.family); 15168f126e37SDavid S. Miller hlist_add_head(&x->byspi, xfrm_state_byspi+h); 15171da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_lock); 1518658b219eSHerbert Xu 1519658b219eSHerbert Xu err = 0; 15201da177e4SLinus Torvalds } 1521658b219eSHerbert Xu 1522658b219eSHerbert Xu unlock: 1523658b219eSHerbert Xu spin_unlock_bh(&x->lock); 1524658b219eSHerbert Xu 1525658b219eSHerbert Xu return err; 15261da177e4SLinus Torvalds } 15271da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_alloc_spi); 15281da177e4SLinus Torvalds 1529*4c563f76STimo Teras int xfrm_state_walk(struct xfrm_state_walk *walk, 1530*4c563f76STimo Teras int (*func)(struct xfrm_state *, int, void*), 15311da177e4SLinus Torvalds void *data) 15321da177e4SLinus Torvalds { 1533*4c563f76STimo Teras struct xfrm_state *old, *x, *last = NULL; 15341da177e4SLinus Torvalds int err = 0; 15351da177e4SLinus Torvalds 1536*4c563f76STimo Teras if (walk->state == NULL && walk->count != 0) 1537*4c563f76STimo Teras return 0; 1538*4c563f76STimo Teras 1539*4c563f76STimo Teras old = x = walk->state; 1540*4c563f76STimo Teras walk->state = NULL; 15411da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_lock); 1542*4c563f76STimo Teras if (x == NULL) 1543*4c563f76STimo Teras x = list_first_entry(&xfrm_state_all, struct xfrm_state, all); 1544*4c563f76STimo Teras list_for_each_entry_from(x, &xfrm_state_all, all) { 1545*4c563f76STimo Teras if (x->km.state == XFRM_STATE_DEAD) 1546*4c563f76STimo Teras continue; 1547*4c563f76STimo Teras if (!xfrm_id_proto_match(x->id.proto, walk->proto)) 154894b9bb54SJamal Hadi Salim continue; 154994b9bb54SJamal Hadi Salim if (last) { 1550*4c563f76STimo Teras err = func(last, walk->count, data); 1551*4c563f76STimo Teras if (err) { 1552*4c563f76STimo Teras xfrm_state_hold(last); 1553*4c563f76STimo Teras walk->state = last; 155494b9bb54SJamal Hadi Salim goto out; 155594b9bb54SJamal Hadi Salim } 1556*4c563f76STimo Teras } 155794b9bb54SJamal Hadi Salim last = x; 1558*4c563f76STimo Teras walk->count++; 15591da177e4SLinus Torvalds } 1560*4c563f76STimo Teras if (walk->count == 0) { 15611da177e4SLinus Torvalds err = -ENOENT; 15621da177e4SLinus Torvalds goto out; 15631da177e4SLinus Torvalds } 1564*4c563f76STimo Teras if (last) 156594b9bb54SJamal Hadi Salim err = func(last, 0, data); 15661da177e4SLinus Torvalds out: 15671da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_lock); 1568*4c563f76STimo Teras if (old != NULL) 1569*4c563f76STimo Teras xfrm_state_put(old); 15701da177e4SLinus Torvalds return err; 15711da177e4SLinus Torvalds } 15721da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_walk); 15731da177e4SLinus Torvalds 1574f8cd5488SJamal Hadi Salim 1575f8cd5488SJamal Hadi Salim void xfrm_replay_notify(struct xfrm_state *x, int event) 1576f8cd5488SJamal Hadi Salim { 1577f8cd5488SJamal Hadi Salim struct km_event c; 1578f8cd5488SJamal Hadi Salim /* we send notify messages in case 1579f8cd5488SJamal Hadi Salim * 1. we updated on of the sequence numbers, and the seqno difference 1580f8cd5488SJamal Hadi Salim * is at least x->replay_maxdiff, in this case we also update the 1581f8cd5488SJamal Hadi Salim * timeout of our timer function 1582f8cd5488SJamal Hadi Salim * 2. if x->replay_maxage has elapsed since last update, 1583f8cd5488SJamal Hadi Salim * and there were changes 1584f8cd5488SJamal Hadi Salim * 1585f8cd5488SJamal Hadi Salim * The state structure must be locked! 1586f8cd5488SJamal Hadi Salim */ 1587f8cd5488SJamal Hadi Salim 1588f8cd5488SJamal Hadi Salim switch (event) { 1589f8cd5488SJamal Hadi Salim case XFRM_REPLAY_UPDATE: 1590f8cd5488SJamal Hadi Salim if (x->replay_maxdiff && 1591f8cd5488SJamal Hadi Salim (x->replay.seq - x->preplay.seq < x->replay_maxdiff) && 15922717096aSJamal Hadi Salim (x->replay.oseq - x->preplay.oseq < x->replay_maxdiff)) { 15932717096aSJamal Hadi Salim if (x->xflags & XFRM_TIME_DEFER) 15942717096aSJamal Hadi Salim event = XFRM_REPLAY_TIMEOUT; 15952717096aSJamal Hadi Salim else 1596f8cd5488SJamal Hadi Salim return; 15972717096aSJamal Hadi Salim } 1598f8cd5488SJamal Hadi Salim 1599f8cd5488SJamal Hadi Salim break; 1600f8cd5488SJamal Hadi Salim 1601f8cd5488SJamal Hadi Salim case XFRM_REPLAY_TIMEOUT: 1602f8cd5488SJamal Hadi Salim if ((x->replay.seq == x->preplay.seq) && 1603f8cd5488SJamal Hadi Salim (x->replay.bitmap == x->preplay.bitmap) && 16042717096aSJamal Hadi Salim (x->replay.oseq == x->preplay.oseq)) { 16052717096aSJamal Hadi Salim x->xflags |= XFRM_TIME_DEFER; 1606f8cd5488SJamal Hadi Salim return; 16072717096aSJamal Hadi Salim } 1608f8cd5488SJamal Hadi Salim 1609f8cd5488SJamal Hadi Salim break; 1610f8cd5488SJamal Hadi Salim } 1611f8cd5488SJamal Hadi Salim 1612f8cd5488SJamal Hadi Salim memcpy(&x->preplay, &x->replay, sizeof(struct xfrm_replay_state)); 1613f8cd5488SJamal Hadi Salim c.event = XFRM_MSG_NEWAE; 1614f8cd5488SJamal Hadi Salim c.data.aevent = event; 1615f8cd5488SJamal Hadi Salim km_state_notify(x, &c); 1616f8cd5488SJamal Hadi Salim 1617f8cd5488SJamal Hadi Salim if (x->replay_maxage && 1618a47f0ce0SDavid S. Miller !mod_timer(&x->rtimer, jiffies + x->replay_maxage)) 16192717096aSJamal Hadi Salim x->xflags &= ~XFRM_TIME_DEFER; 16202717096aSJamal Hadi Salim } 1621f8cd5488SJamal Hadi Salim 1622f8cd5488SJamal Hadi Salim static void xfrm_replay_timer_handler(unsigned long data) 1623f8cd5488SJamal Hadi Salim { 1624f8cd5488SJamal Hadi Salim struct xfrm_state *x = (struct xfrm_state*)data; 1625f8cd5488SJamal Hadi Salim 1626f8cd5488SJamal Hadi Salim spin_lock(&x->lock); 1627f8cd5488SJamal Hadi Salim 16282717096aSJamal Hadi Salim if (x->km.state == XFRM_STATE_VALID) { 16292717096aSJamal Hadi Salim if (xfrm_aevent_is_on()) 1630f8cd5488SJamal Hadi Salim xfrm_replay_notify(x, XFRM_REPLAY_TIMEOUT); 16312717096aSJamal Hadi Salim else 16322717096aSJamal Hadi Salim x->xflags |= XFRM_TIME_DEFER; 16332717096aSJamal Hadi Salim } 1634f8cd5488SJamal Hadi Salim 1635f8cd5488SJamal Hadi Salim spin_unlock(&x->lock); 1636f8cd5488SJamal Hadi Salim } 1637f8cd5488SJamal Hadi Salim 1638afeb14b4SPaul Moore int xfrm_replay_check(struct xfrm_state *x, 1639afeb14b4SPaul Moore struct sk_buff *skb, __be32 net_seq) 16401da177e4SLinus Torvalds { 16411da177e4SLinus Torvalds u32 diff; 1642a252cc23SAl Viro u32 seq = ntohl(net_seq); 16431da177e4SLinus Torvalds 16441da177e4SLinus Torvalds if (unlikely(seq == 0)) 1645afeb14b4SPaul Moore goto err; 16461da177e4SLinus Torvalds 16471da177e4SLinus Torvalds if (likely(seq > x->replay.seq)) 16481da177e4SLinus Torvalds return 0; 16491da177e4SLinus Torvalds 16501da177e4SLinus Torvalds diff = x->replay.seq - seq; 16514c4d51a7SHerbert Xu if (diff >= min_t(unsigned int, x->props.replay_window, 16524c4d51a7SHerbert Xu sizeof(x->replay.bitmap) * 8)) { 16531da177e4SLinus Torvalds x->stats.replay_window++; 1654afeb14b4SPaul Moore goto err; 16551da177e4SLinus Torvalds } 16561da177e4SLinus Torvalds 16571da177e4SLinus Torvalds if (x->replay.bitmap & (1U << diff)) { 16581da177e4SLinus Torvalds x->stats.replay++; 1659afeb14b4SPaul Moore goto err; 16601da177e4SLinus Torvalds } 16611da177e4SLinus Torvalds return 0; 1662afeb14b4SPaul Moore 1663afeb14b4SPaul Moore err: 1664afeb14b4SPaul Moore xfrm_audit_state_replay(x, skb, net_seq); 1665afeb14b4SPaul Moore return -EINVAL; 16661da177e4SLinus Torvalds } 16671da177e4SLinus Torvalds 166861f4627bSAl Viro void xfrm_replay_advance(struct xfrm_state *x, __be32 net_seq) 16691da177e4SLinus Torvalds { 16701da177e4SLinus Torvalds u32 diff; 167161f4627bSAl Viro u32 seq = ntohl(net_seq); 16721da177e4SLinus Torvalds 16731da177e4SLinus Torvalds if (seq > x->replay.seq) { 16741da177e4SLinus Torvalds diff = seq - x->replay.seq; 16751da177e4SLinus Torvalds if (diff < x->props.replay_window) 16761da177e4SLinus Torvalds x->replay.bitmap = ((x->replay.bitmap) << diff) | 1; 16771da177e4SLinus Torvalds else 16781da177e4SLinus Torvalds x->replay.bitmap = 1; 16791da177e4SLinus Torvalds x->replay.seq = seq; 16801da177e4SLinus Torvalds } else { 16811da177e4SLinus Torvalds diff = x->replay.seq - seq; 16821da177e4SLinus Torvalds x->replay.bitmap |= (1U << diff); 16831da177e4SLinus Torvalds } 1684f8cd5488SJamal Hadi Salim 1685f8cd5488SJamal Hadi Salim if (xfrm_aevent_is_on()) 1686f8cd5488SJamal Hadi Salim xfrm_replay_notify(x, XFRM_REPLAY_UPDATE); 16871da177e4SLinus Torvalds } 16881da177e4SLinus Torvalds 1689df01812eSDenis Cheng static LIST_HEAD(xfrm_km_list); 16901da177e4SLinus Torvalds static DEFINE_RWLOCK(xfrm_km_lock); 16911da177e4SLinus Torvalds 169226b15dadSJamal Hadi Salim void km_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c) 16931da177e4SLinus Torvalds { 16941da177e4SLinus Torvalds struct xfrm_mgr *km; 16951da177e4SLinus Torvalds 169626b15dadSJamal Hadi Salim read_lock(&xfrm_km_lock); 169726b15dadSJamal Hadi Salim list_for_each_entry(km, &xfrm_km_list, list) 169826b15dadSJamal Hadi Salim if (km->notify_policy) 169926b15dadSJamal Hadi Salim km->notify_policy(xp, dir, c); 170026b15dadSJamal Hadi Salim read_unlock(&xfrm_km_lock); 170126b15dadSJamal Hadi Salim } 170226b15dadSJamal Hadi Salim 170326b15dadSJamal Hadi Salim void km_state_notify(struct xfrm_state *x, struct km_event *c) 170426b15dadSJamal Hadi Salim { 170526b15dadSJamal Hadi Salim struct xfrm_mgr *km; 170626b15dadSJamal Hadi Salim read_lock(&xfrm_km_lock); 170726b15dadSJamal Hadi Salim list_for_each_entry(km, &xfrm_km_list, list) 170826b15dadSJamal Hadi Salim if (km->notify) 170926b15dadSJamal Hadi Salim km->notify(x, c); 171026b15dadSJamal Hadi Salim read_unlock(&xfrm_km_lock); 171126b15dadSJamal Hadi Salim } 171226b15dadSJamal Hadi Salim 171326b15dadSJamal Hadi Salim EXPORT_SYMBOL(km_policy_notify); 171426b15dadSJamal Hadi Salim EXPORT_SYMBOL(km_state_notify); 171526b15dadSJamal Hadi Salim 171653bc6b4dSJamal Hadi Salim void km_state_expired(struct xfrm_state *x, int hard, u32 pid) 171726b15dadSJamal Hadi Salim { 171826b15dadSJamal Hadi Salim struct km_event c; 171926b15dadSJamal Hadi Salim 1720bf08867fSHerbert Xu c.data.hard = hard; 172153bc6b4dSJamal Hadi Salim c.pid = pid; 1722f60f6b8fSHerbert Xu c.event = XFRM_MSG_EXPIRE; 172326b15dadSJamal Hadi Salim km_state_notify(x, &c); 17241da177e4SLinus Torvalds 17251da177e4SLinus Torvalds if (hard) 17261da177e4SLinus Torvalds wake_up(&km_waitq); 17271da177e4SLinus Torvalds } 17281da177e4SLinus Torvalds 172953bc6b4dSJamal Hadi Salim EXPORT_SYMBOL(km_state_expired); 173026b15dadSJamal Hadi Salim /* 173126b15dadSJamal Hadi Salim * We send to all registered managers regardless of failure 173226b15dadSJamal Hadi Salim * We are happy with one success 173326b15dadSJamal Hadi Salim */ 1734980ebd25SJamal Hadi Salim int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol) 17351da177e4SLinus Torvalds { 173626b15dadSJamal Hadi Salim int err = -EINVAL, acqret; 17371da177e4SLinus Torvalds struct xfrm_mgr *km; 17381da177e4SLinus Torvalds 17391da177e4SLinus Torvalds read_lock(&xfrm_km_lock); 17401da177e4SLinus Torvalds list_for_each_entry(km, &xfrm_km_list, list) { 174126b15dadSJamal Hadi Salim acqret = km->acquire(x, t, pol, XFRM_POLICY_OUT); 174226b15dadSJamal Hadi Salim if (!acqret) 174326b15dadSJamal Hadi Salim err = acqret; 17441da177e4SLinus Torvalds } 17451da177e4SLinus Torvalds read_unlock(&xfrm_km_lock); 17461da177e4SLinus Torvalds return err; 17471da177e4SLinus Torvalds } 1748980ebd25SJamal Hadi Salim EXPORT_SYMBOL(km_query); 17491da177e4SLinus Torvalds 17505d36b180SAl Viro int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport) 17511da177e4SLinus Torvalds { 17521da177e4SLinus Torvalds int err = -EINVAL; 17531da177e4SLinus Torvalds struct xfrm_mgr *km; 17541da177e4SLinus Torvalds 17551da177e4SLinus Torvalds read_lock(&xfrm_km_lock); 17561da177e4SLinus Torvalds list_for_each_entry(km, &xfrm_km_list, list) { 17571da177e4SLinus Torvalds if (km->new_mapping) 17581da177e4SLinus Torvalds err = km->new_mapping(x, ipaddr, sport); 17591da177e4SLinus Torvalds if (!err) 17601da177e4SLinus Torvalds break; 17611da177e4SLinus Torvalds } 17621da177e4SLinus Torvalds read_unlock(&xfrm_km_lock); 17631da177e4SLinus Torvalds return err; 17641da177e4SLinus Torvalds } 17651da177e4SLinus Torvalds EXPORT_SYMBOL(km_new_mapping); 17661da177e4SLinus Torvalds 17676c5c8ca7SJamal Hadi Salim void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 pid) 17681da177e4SLinus Torvalds { 176926b15dadSJamal Hadi Salim struct km_event c; 17701da177e4SLinus Torvalds 1771bf08867fSHerbert Xu c.data.hard = hard; 17726c5c8ca7SJamal Hadi Salim c.pid = pid; 1773f60f6b8fSHerbert Xu c.event = XFRM_MSG_POLEXPIRE; 177426b15dadSJamal Hadi Salim km_policy_notify(pol, dir, &c); 17751da177e4SLinus Torvalds 17761da177e4SLinus Torvalds if (hard) 17771da177e4SLinus Torvalds wake_up(&km_waitq); 17781da177e4SLinus Torvalds } 1779a70fcb0bSDavid S. Miller EXPORT_SYMBOL(km_policy_expired); 17801da177e4SLinus Torvalds 17812d60abc2SEric Dumazet #ifdef CONFIG_XFRM_MIGRATE 178280c9abaaSShinta Sugimoto int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type, 178380c9abaaSShinta Sugimoto struct xfrm_migrate *m, int num_migrate) 178480c9abaaSShinta Sugimoto { 178580c9abaaSShinta Sugimoto int err = -EINVAL; 178680c9abaaSShinta Sugimoto int ret; 178780c9abaaSShinta Sugimoto struct xfrm_mgr *km; 178880c9abaaSShinta Sugimoto 178980c9abaaSShinta Sugimoto read_lock(&xfrm_km_lock); 179080c9abaaSShinta Sugimoto list_for_each_entry(km, &xfrm_km_list, list) { 179180c9abaaSShinta Sugimoto if (km->migrate) { 179280c9abaaSShinta Sugimoto ret = km->migrate(sel, dir, type, m, num_migrate); 179380c9abaaSShinta Sugimoto if (!ret) 179480c9abaaSShinta Sugimoto err = ret; 179580c9abaaSShinta Sugimoto } 179680c9abaaSShinta Sugimoto } 179780c9abaaSShinta Sugimoto read_unlock(&xfrm_km_lock); 179880c9abaaSShinta Sugimoto return err; 179980c9abaaSShinta Sugimoto } 180080c9abaaSShinta Sugimoto EXPORT_SYMBOL(km_migrate); 18012d60abc2SEric Dumazet #endif 180280c9abaaSShinta Sugimoto 180397a64b45SMasahide NAKAMURA int km_report(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr) 180497a64b45SMasahide NAKAMURA { 180597a64b45SMasahide NAKAMURA int err = -EINVAL; 180697a64b45SMasahide NAKAMURA int ret; 180797a64b45SMasahide NAKAMURA struct xfrm_mgr *km; 180897a64b45SMasahide NAKAMURA 180997a64b45SMasahide NAKAMURA read_lock(&xfrm_km_lock); 181097a64b45SMasahide NAKAMURA list_for_each_entry(km, &xfrm_km_list, list) { 181197a64b45SMasahide NAKAMURA if (km->report) { 181297a64b45SMasahide NAKAMURA ret = km->report(proto, sel, addr); 181397a64b45SMasahide NAKAMURA if (!ret) 181497a64b45SMasahide NAKAMURA err = ret; 181597a64b45SMasahide NAKAMURA } 181697a64b45SMasahide NAKAMURA } 181797a64b45SMasahide NAKAMURA read_unlock(&xfrm_km_lock); 181897a64b45SMasahide NAKAMURA return err; 181997a64b45SMasahide NAKAMURA } 182097a64b45SMasahide NAKAMURA EXPORT_SYMBOL(km_report); 182197a64b45SMasahide NAKAMURA 18221da177e4SLinus Torvalds int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen) 18231da177e4SLinus Torvalds { 18241da177e4SLinus Torvalds int err; 18251da177e4SLinus Torvalds u8 *data; 18261da177e4SLinus Torvalds struct xfrm_mgr *km; 18271da177e4SLinus Torvalds struct xfrm_policy *pol = NULL; 18281da177e4SLinus Torvalds 18291da177e4SLinus Torvalds if (optlen <= 0 || optlen > PAGE_SIZE) 18301da177e4SLinus Torvalds return -EMSGSIZE; 18311da177e4SLinus Torvalds 18321da177e4SLinus Torvalds data = kmalloc(optlen, GFP_KERNEL); 18331da177e4SLinus Torvalds if (!data) 18341da177e4SLinus Torvalds return -ENOMEM; 18351da177e4SLinus Torvalds 18361da177e4SLinus Torvalds err = -EFAULT; 18371da177e4SLinus Torvalds if (copy_from_user(data, optval, optlen)) 18381da177e4SLinus Torvalds goto out; 18391da177e4SLinus Torvalds 18401da177e4SLinus Torvalds err = -EINVAL; 18411da177e4SLinus Torvalds read_lock(&xfrm_km_lock); 18421da177e4SLinus Torvalds list_for_each_entry(km, &xfrm_km_list, list) { 1843cb969f07SVenkat Yekkirala pol = km->compile_policy(sk, optname, data, 18441da177e4SLinus Torvalds optlen, &err); 18451da177e4SLinus Torvalds if (err >= 0) 18461da177e4SLinus Torvalds break; 18471da177e4SLinus Torvalds } 18481da177e4SLinus Torvalds read_unlock(&xfrm_km_lock); 18491da177e4SLinus Torvalds 18501da177e4SLinus Torvalds if (err >= 0) { 18511da177e4SLinus Torvalds xfrm_sk_policy_insert(sk, err, pol); 18521da177e4SLinus Torvalds xfrm_pol_put(pol); 18531da177e4SLinus Torvalds err = 0; 18541da177e4SLinus Torvalds } 18551da177e4SLinus Torvalds 18561da177e4SLinus Torvalds out: 18571da177e4SLinus Torvalds kfree(data); 18581da177e4SLinus Torvalds return err; 18591da177e4SLinus Torvalds } 18601da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_user_policy); 18611da177e4SLinus Torvalds 18621da177e4SLinus Torvalds int xfrm_register_km(struct xfrm_mgr *km) 18631da177e4SLinus Torvalds { 18641da177e4SLinus Torvalds write_lock_bh(&xfrm_km_lock); 18651da177e4SLinus Torvalds list_add_tail(&km->list, &xfrm_km_list); 18661da177e4SLinus Torvalds write_unlock_bh(&xfrm_km_lock); 18671da177e4SLinus Torvalds return 0; 18681da177e4SLinus Torvalds } 18691da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_register_km); 18701da177e4SLinus Torvalds 18711da177e4SLinus Torvalds int xfrm_unregister_km(struct xfrm_mgr *km) 18721da177e4SLinus Torvalds { 18731da177e4SLinus Torvalds write_lock_bh(&xfrm_km_lock); 18741da177e4SLinus Torvalds list_del(&km->list); 18751da177e4SLinus Torvalds write_unlock_bh(&xfrm_km_lock); 18761da177e4SLinus Torvalds return 0; 18771da177e4SLinus Torvalds } 18781da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_unregister_km); 18791da177e4SLinus Torvalds 18801da177e4SLinus Torvalds int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo) 18811da177e4SLinus Torvalds { 18821da177e4SLinus Torvalds int err = 0; 18831da177e4SLinus Torvalds if (unlikely(afinfo == NULL)) 18841da177e4SLinus Torvalds return -EINVAL; 18851da177e4SLinus Torvalds if (unlikely(afinfo->family >= NPROTO)) 18861da177e4SLinus Torvalds return -EAFNOSUPPORT; 1887f3111502SIngo Molnar write_lock_bh(&xfrm_state_afinfo_lock); 18881da177e4SLinus Torvalds if (unlikely(xfrm_state_afinfo[afinfo->family] != NULL)) 18891da177e4SLinus Torvalds err = -ENOBUFS; 1890edcd5821SDavid S. Miller else 18911da177e4SLinus Torvalds xfrm_state_afinfo[afinfo->family] = afinfo; 1892f3111502SIngo Molnar write_unlock_bh(&xfrm_state_afinfo_lock); 18931da177e4SLinus Torvalds return err; 18941da177e4SLinus Torvalds } 18951da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_register_afinfo); 18961da177e4SLinus Torvalds 18971da177e4SLinus Torvalds int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo) 18981da177e4SLinus Torvalds { 18991da177e4SLinus Torvalds int err = 0; 19001da177e4SLinus Torvalds if (unlikely(afinfo == NULL)) 19011da177e4SLinus Torvalds return -EINVAL; 19021da177e4SLinus Torvalds if (unlikely(afinfo->family >= NPROTO)) 19031da177e4SLinus Torvalds return -EAFNOSUPPORT; 1904f3111502SIngo Molnar write_lock_bh(&xfrm_state_afinfo_lock); 19051da177e4SLinus Torvalds if (likely(xfrm_state_afinfo[afinfo->family] != NULL)) { 19061da177e4SLinus Torvalds if (unlikely(xfrm_state_afinfo[afinfo->family] != afinfo)) 19071da177e4SLinus Torvalds err = -EINVAL; 1908edcd5821SDavid S. Miller else 19091da177e4SLinus Torvalds xfrm_state_afinfo[afinfo->family] = NULL; 19101da177e4SLinus Torvalds } 1911f3111502SIngo Molnar write_unlock_bh(&xfrm_state_afinfo_lock); 19121da177e4SLinus Torvalds return err; 19131da177e4SLinus Torvalds } 19141da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_unregister_afinfo); 19151da177e4SLinus Torvalds 191617c2a42aSHerbert Xu static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family) 19171da177e4SLinus Torvalds { 19181da177e4SLinus Torvalds struct xfrm_state_afinfo *afinfo; 19191da177e4SLinus Torvalds if (unlikely(family >= NPROTO)) 19201da177e4SLinus Torvalds return NULL; 19211da177e4SLinus Torvalds read_lock(&xfrm_state_afinfo_lock); 19221da177e4SLinus Torvalds afinfo = xfrm_state_afinfo[family]; 1923546be240SHerbert Xu if (unlikely(!afinfo)) 19241da177e4SLinus Torvalds read_unlock(&xfrm_state_afinfo_lock); 19251da177e4SLinus Torvalds return afinfo; 19261da177e4SLinus Torvalds } 19271da177e4SLinus Torvalds 192817c2a42aSHerbert Xu static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo) 19299a429c49SEric Dumazet __releases(xfrm_state_afinfo_lock) 19301da177e4SLinus Torvalds { 1931546be240SHerbert Xu read_unlock(&xfrm_state_afinfo_lock); 19321da177e4SLinus Torvalds } 19331da177e4SLinus Torvalds 19341da177e4SLinus Torvalds /* Temporarily located here until net/xfrm/xfrm_tunnel.c is created */ 19351da177e4SLinus Torvalds void xfrm_state_delete_tunnel(struct xfrm_state *x) 19361da177e4SLinus Torvalds { 19371da177e4SLinus Torvalds if (x->tunnel) { 19381da177e4SLinus Torvalds struct xfrm_state *t = x->tunnel; 19391da177e4SLinus Torvalds 19401da177e4SLinus Torvalds if (atomic_read(&t->tunnel_users) == 2) 19411da177e4SLinus Torvalds xfrm_state_delete(t); 19421da177e4SLinus Torvalds atomic_dec(&t->tunnel_users); 19431da177e4SLinus Torvalds xfrm_state_put(t); 19441da177e4SLinus Torvalds x->tunnel = NULL; 19451da177e4SLinus Torvalds } 19461da177e4SLinus Torvalds } 19471da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_delete_tunnel); 19481da177e4SLinus Torvalds 19491da177e4SLinus Torvalds int xfrm_state_mtu(struct xfrm_state *x, int mtu) 19501da177e4SLinus Torvalds { 1951c5c25238SPatrick McHardy int res; 19521da177e4SLinus Torvalds 19531da177e4SLinus Torvalds spin_lock_bh(&x->lock); 19541da177e4SLinus Torvalds if (x->km.state == XFRM_STATE_VALID && 1955c5c25238SPatrick McHardy x->type && x->type->get_mtu) 1956c5c25238SPatrick McHardy res = x->type->get_mtu(x, mtu); 19571da177e4SLinus Torvalds else 195828121617SPatrick McHardy res = mtu - x->props.header_len; 19591da177e4SLinus Torvalds spin_unlock_bh(&x->lock); 19601da177e4SLinus Torvalds return res; 19611da177e4SLinus Torvalds } 19621da177e4SLinus Torvalds 196372cb6962SHerbert Xu int xfrm_init_state(struct xfrm_state *x) 196472cb6962SHerbert Xu { 1965d094cd83SHerbert Xu struct xfrm_state_afinfo *afinfo; 1966d094cd83SHerbert Xu int family = x->props.family; 196772cb6962SHerbert Xu int err; 196872cb6962SHerbert Xu 1969d094cd83SHerbert Xu err = -EAFNOSUPPORT; 1970d094cd83SHerbert Xu afinfo = xfrm_state_get_afinfo(family); 1971d094cd83SHerbert Xu if (!afinfo) 1972d094cd83SHerbert Xu goto error; 1973d094cd83SHerbert Xu 1974d094cd83SHerbert Xu err = 0; 1975d094cd83SHerbert Xu if (afinfo->init_flags) 1976d094cd83SHerbert Xu err = afinfo->init_flags(x); 1977d094cd83SHerbert Xu 1978d094cd83SHerbert Xu xfrm_state_put_afinfo(afinfo); 1979d094cd83SHerbert Xu 1980d094cd83SHerbert Xu if (err) 1981d094cd83SHerbert Xu goto error; 1982d094cd83SHerbert Xu 1983d094cd83SHerbert Xu err = -EPROTONOSUPPORT; 198413996378SHerbert Xu x->inner_mode = xfrm_get_mode(x->props.mode, x->sel.family); 198513996378SHerbert Xu if (x->inner_mode == NULL) 198613996378SHerbert Xu goto error; 198713996378SHerbert Xu 198813996378SHerbert Xu if (!(x->inner_mode->flags & XFRM_MODE_FLAG_TUNNEL) && 198913996378SHerbert Xu family != x->sel.family) 199013996378SHerbert Xu goto error; 199113996378SHerbert Xu 1992d094cd83SHerbert Xu x->type = xfrm_get_type(x->id.proto, family); 199372cb6962SHerbert Xu if (x->type == NULL) 199472cb6962SHerbert Xu goto error; 199572cb6962SHerbert Xu 199672cb6962SHerbert Xu err = x->type->init_state(x); 199772cb6962SHerbert Xu if (err) 199872cb6962SHerbert Xu goto error; 199972cb6962SHerbert Xu 200013996378SHerbert Xu x->outer_mode = xfrm_get_mode(x->props.mode, family); 200113996378SHerbert Xu if (x->outer_mode == NULL) 2002b59f45d0SHerbert Xu goto error; 2003b59f45d0SHerbert Xu 200472cb6962SHerbert Xu x->km.state = XFRM_STATE_VALID; 200572cb6962SHerbert Xu 200672cb6962SHerbert Xu error: 200772cb6962SHerbert Xu return err; 200872cb6962SHerbert Xu } 200972cb6962SHerbert Xu 201072cb6962SHerbert Xu EXPORT_SYMBOL(xfrm_init_state); 20111da177e4SLinus Torvalds 20121da177e4SLinus Torvalds void __init xfrm_state_init(void) 20131da177e4SLinus Torvalds { 2014f034b5d4SDavid S. Miller unsigned int sz; 20151da177e4SLinus Torvalds 2016f034b5d4SDavid S. Miller sz = sizeof(struct hlist_head) * 8; 2017f034b5d4SDavid S. Miller 201844e36b42SDavid S. Miller xfrm_state_bydst = xfrm_hash_alloc(sz); 201944e36b42SDavid S. Miller xfrm_state_bysrc = xfrm_hash_alloc(sz); 202044e36b42SDavid S. Miller xfrm_state_byspi = xfrm_hash_alloc(sz); 2021f034b5d4SDavid S. Miller if (!xfrm_state_bydst || !xfrm_state_bysrc || !xfrm_state_byspi) 2022f034b5d4SDavid S. Miller panic("XFRM: Cannot allocate bydst/bysrc/byspi hashes."); 2023f034b5d4SDavid S. Miller xfrm_state_hmask = ((sz / sizeof(struct hlist_head)) - 1); 2024f034b5d4SDavid S. Miller 2025c4028958SDavid Howells INIT_WORK(&xfrm_state_gc_work, xfrm_state_gc_task); 20261da177e4SLinus Torvalds } 20271da177e4SLinus Torvalds 2028ab5f5e8bSJoy Latten #ifdef CONFIG_AUDITSYSCALL 2029cf35f43eSIlpo Järvinen static void xfrm_audit_helper_sainfo(struct xfrm_state *x, 2030ab5f5e8bSJoy Latten struct audit_buffer *audit_buf) 2031ab5f5e8bSJoy Latten { 203268277accSPaul Moore struct xfrm_sec_ctx *ctx = x->security; 203368277accSPaul Moore u32 spi = ntohl(x->id.spi); 203468277accSPaul Moore 203568277accSPaul Moore if (ctx) 2036ab5f5e8bSJoy Latten audit_log_format(audit_buf, " sec_alg=%u sec_doi=%u sec_obj=%s", 203768277accSPaul Moore ctx->ctx_alg, ctx->ctx_doi, ctx->ctx_str); 2038ab5f5e8bSJoy Latten 2039ab5f5e8bSJoy Latten switch(x->props.family) { 2040ab5f5e8bSJoy Latten case AF_INET: 204168277accSPaul Moore audit_log_format(audit_buf, 204268277accSPaul Moore " src=" NIPQUAD_FMT " dst=" NIPQUAD_FMT, 2043ab5f5e8bSJoy Latten NIPQUAD(x->props.saddr.a4), 2044ab5f5e8bSJoy Latten NIPQUAD(x->id.daddr.a4)); 2045ab5f5e8bSJoy Latten break; 2046ab5f5e8bSJoy Latten case AF_INET6: 2047ab5f5e8bSJoy Latten audit_log_format(audit_buf, 2048ab5f5e8bSJoy Latten " src=" NIP6_FMT " dst=" NIP6_FMT, 204968277accSPaul Moore NIP6(*(struct in6_addr *)x->props.saddr.a6), 205068277accSPaul Moore NIP6(*(struct in6_addr *)x->id.daddr.a6)); 2051ab5f5e8bSJoy Latten break; 2052ab5f5e8bSJoy Latten } 205368277accSPaul Moore 205468277accSPaul Moore audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi); 2055ab5f5e8bSJoy Latten } 2056ab5f5e8bSJoy Latten 2057cf35f43eSIlpo Järvinen static void xfrm_audit_helper_pktinfo(struct sk_buff *skb, u16 family, 2058afeb14b4SPaul Moore struct audit_buffer *audit_buf) 2059afeb14b4SPaul Moore { 2060afeb14b4SPaul Moore struct iphdr *iph4; 2061afeb14b4SPaul Moore struct ipv6hdr *iph6; 2062afeb14b4SPaul Moore 2063afeb14b4SPaul Moore switch (family) { 2064afeb14b4SPaul Moore case AF_INET: 2065afeb14b4SPaul Moore iph4 = ip_hdr(skb); 2066afeb14b4SPaul Moore audit_log_format(audit_buf, 2067afeb14b4SPaul Moore " src=" NIPQUAD_FMT " dst=" NIPQUAD_FMT, 2068afeb14b4SPaul Moore NIPQUAD(iph4->saddr), 2069afeb14b4SPaul Moore NIPQUAD(iph4->daddr)); 2070afeb14b4SPaul Moore break; 2071afeb14b4SPaul Moore case AF_INET6: 2072afeb14b4SPaul Moore iph6 = ipv6_hdr(skb); 2073afeb14b4SPaul Moore audit_log_format(audit_buf, 2074afeb14b4SPaul Moore " src=" NIP6_FMT " dst=" NIP6_FMT 2075afeb14b4SPaul Moore " flowlbl=0x%x%x%x", 2076afeb14b4SPaul Moore NIP6(iph6->saddr), 2077afeb14b4SPaul Moore NIP6(iph6->daddr), 2078afeb14b4SPaul Moore iph6->flow_lbl[0] & 0x0f, 2079afeb14b4SPaul Moore iph6->flow_lbl[1], 2080afeb14b4SPaul Moore iph6->flow_lbl[2]); 2081afeb14b4SPaul Moore break; 2082afeb14b4SPaul Moore } 2083afeb14b4SPaul Moore } 2084afeb14b4SPaul Moore 208568277accSPaul Moore void xfrm_audit_state_add(struct xfrm_state *x, int result, 208668277accSPaul Moore u32 auid, u32 secid) 2087ab5f5e8bSJoy Latten { 2088ab5f5e8bSJoy Latten struct audit_buffer *audit_buf; 2089ab5f5e8bSJoy Latten 2090afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SAD-add"); 2091ab5f5e8bSJoy Latten if (audit_buf == NULL) 2092ab5f5e8bSJoy Latten return; 2093afeb14b4SPaul Moore xfrm_audit_helper_usrinfo(auid, secid, audit_buf); 2094afeb14b4SPaul Moore xfrm_audit_helper_sainfo(x, audit_buf); 2095afeb14b4SPaul Moore audit_log_format(audit_buf, " res=%u", result); 2096ab5f5e8bSJoy Latten audit_log_end(audit_buf); 2097ab5f5e8bSJoy Latten } 2098ab5f5e8bSJoy Latten EXPORT_SYMBOL_GPL(xfrm_audit_state_add); 2099ab5f5e8bSJoy Latten 210068277accSPaul Moore void xfrm_audit_state_delete(struct xfrm_state *x, int result, 210168277accSPaul Moore u32 auid, u32 secid) 2102ab5f5e8bSJoy Latten { 2103ab5f5e8bSJoy Latten struct audit_buffer *audit_buf; 2104ab5f5e8bSJoy Latten 2105afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SAD-delete"); 2106ab5f5e8bSJoy Latten if (audit_buf == NULL) 2107ab5f5e8bSJoy Latten return; 2108afeb14b4SPaul Moore xfrm_audit_helper_usrinfo(auid, secid, audit_buf); 2109afeb14b4SPaul Moore xfrm_audit_helper_sainfo(x, audit_buf); 2110afeb14b4SPaul Moore audit_log_format(audit_buf, " res=%u", result); 2111ab5f5e8bSJoy Latten audit_log_end(audit_buf); 2112ab5f5e8bSJoy Latten } 2113ab5f5e8bSJoy Latten EXPORT_SYMBOL_GPL(xfrm_audit_state_delete); 2114afeb14b4SPaul Moore 2115afeb14b4SPaul Moore void xfrm_audit_state_replay_overflow(struct xfrm_state *x, 2116afeb14b4SPaul Moore struct sk_buff *skb) 2117afeb14b4SPaul Moore { 2118afeb14b4SPaul Moore struct audit_buffer *audit_buf; 2119afeb14b4SPaul Moore u32 spi; 2120afeb14b4SPaul Moore 2121afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SA-replay-overflow"); 2122afeb14b4SPaul Moore if (audit_buf == NULL) 2123afeb14b4SPaul Moore return; 2124afeb14b4SPaul Moore xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf); 2125afeb14b4SPaul Moore /* don't record the sequence number because it's inherent in this kind 2126afeb14b4SPaul Moore * of audit message */ 2127afeb14b4SPaul Moore spi = ntohl(x->id.spi); 2128afeb14b4SPaul Moore audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi); 2129afeb14b4SPaul Moore audit_log_end(audit_buf); 2130afeb14b4SPaul Moore } 2131afeb14b4SPaul Moore EXPORT_SYMBOL_GPL(xfrm_audit_state_replay_overflow); 2132afeb14b4SPaul Moore 2133afeb14b4SPaul Moore static void xfrm_audit_state_replay(struct xfrm_state *x, 2134afeb14b4SPaul Moore struct sk_buff *skb, __be32 net_seq) 2135afeb14b4SPaul Moore { 2136afeb14b4SPaul Moore struct audit_buffer *audit_buf; 2137afeb14b4SPaul Moore u32 spi; 2138afeb14b4SPaul Moore 2139afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SA-replayed-pkt"); 2140afeb14b4SPaul Moore if (audit_buf == NULL) 2141afeb14b4SPaul Moore return; 2142afeb14b4SPaul Moore xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf); 2143afeb14b4SPaul Moore spi = ntohl(x->id.spi); 2144afeb14b4SPaul Moore audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u", 2145afeb14b4SPaul Moore spi, spi, ntohl(net_seq)); 2146afeb14b4SPaul Moore audit_log_end(audit_buf); 2147afeb14b4SPaul Moore } 2148afeb14b4SPaul Moore 2149afeb14b4SPaul Moore void xfrm_audit_state_notfound_simple(struct sk_buff *skb, u16 family) 2150afeb14b4SPaul Moore { 2151afeb14b4SPaul Moore struct audit_buffer *audit_buf; 2152afeb14b4SPaul Moore 2153afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SA-notfound"); 2154afeb14b4SPaul Moore if (audit_buf == NULL) 2155afeb14b4SPaul Moore return; 2156afeb14b4SPaul Moore xfrm_audit_helper_pktinfo(skb, family, audit_buf); 2157afeb14b4SPaul Moore audit_log_end(audit_buf); 2158afeb14b4SPaul Moore } 2159afeb14b4SPaul Moore EXPORT_SYMBOL_GPL(xfrm_audit_state_notfound_simple); 2160afeb14b4SPaul Moore 2161afeb14b4SPaul Moore void xfrm_audit_state_notfound(struct sk_buff *skb, u16 family, 2162afeb14b4SPaul Moore __be32 net_spi, __be32 net_seq) 2163afeb14b4SPaul Moore { 2164afeb14b4SPaul Moore struct audit_buffer *audit_buf; 2165afeb14b4SPaul Moore u32 spi; 2166afeb14b4SPaul Moore 2167afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SA-notfound"); 2168afeb14b4SPaul Moore if (audit_buf == NULL) 2169afeb14b4SPaul Moore return; 2170afeb14b4SPaul Moore xfrm_audit_helper_pktinfo(skb, family, audit_buf); 2171afeb14b4SPaul Moore spi = ntohl(net_spi); 2172afeb14b4SPaul Moore audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u", 2173afeb14b4SPaul Moore spi, spi, ntohl(net_seq)); 2174afeb14b4SPaul Moore audit_log_end(audit_buf); 2175afeb14b4SPaul Moore } 2176afeb14b4SPaul Moore EXPORT_SYMBOL_GPL(xfrm_audit_state_notfound); 2177afeb14b4SPaul Moore 2178afeb14b4SPaul Moore void xfrm_audit_state_icvfail(struct xfrm_state *x, 2179afeb14b4SPaul Moore struct sk_buff *skb, u8 proto) 2180afeb14b4SPaul Moore { 2181afeb14b4SPaul Moore struct audit_buffer *audit_buf; 2182afeb14b4SPaul Moore __be32 net_spi; 2183afeb14b4SPaul Moore __be32 net_seq; 2184afeb14b4SPaul Moore 2185afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SA-icv-failure"); 2186afeb14b4SPaul Moore if (audit_buf == NULL) 2187afeb14b4SPaul Moore return; 2188afeb14b4SPaul Moore xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf); 2189afeb14b4SPaul Moore if (xfrm_parse_spi(skb, proto, &net_spi, &net_seq) == 0) { 2190afeb14b4SPaul Moore u32 spi = ntohl(net_spi); 2191afeb14b4SPaul Moore audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u", 2192afeb14b4SPaul Moore spi, spi, ntohl(net_seq)); 2193afeb14b4SPaul Moore } 2194afeb14b4SPaul Moore audit_log_end(audit_buf); 2195afeb14b4SPaul Moore } 2196afeb14b4SPaul Moore EXPORT_SYMBOL_GPL(xfrm_audit_state_icvfail); 2197ab5f5e8bSJoy Latten #endif /* CONFIG_AUDITSYSCALL */ 2198