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 */ 53f034b5d4SDavid S. Miller static struct hlist_head *xfrm_state_bydst __read_mostly; 54f034b5d4SDavid S. Miller static struct hlist_head *xfrm_state_bysrc __read_mostly; 55f034b5d4SDavid S. Miller static struct hlist_head *xfrm_state_byspi __read_mostly; 56f034b5d4SDavid S. Miller static unsigned int xfrm_state_hmask __read_mostly; 57f034b5d4SDavid S. Miller static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024; 58f034b5d4SDavid S. Miller static unsigned int xfrm_state_num; 599d4a706dSDavid S. Miller static unsigned int xfrm_state_genid; 601da177e4SLinus Torvalds 6117c2a42aSHerbert Xu static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family); 6217c2a42aSHerbert Xu static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo); 6317c2a42aSHerbert Xu 64afeb14b4SPaul Moore #ifdef CONFIG_AUDITSYSCALL 65afeb14b4SPaul Moore static void xfrm_audit_state_replay(struct xfrm_state *x, 66afeb14b4SPaul Moore struct sk_buff *skb, __be32 net_seq); 67afeb14b4SPaul Moore #else 68afeb14b4SPaul Moore #define xfrm_audit_state_replay(x, s, sq) do { ; } while (0) 69afeb14b4SPaul Moore #endif /* CONFIG_AUDITSYSCALL */ 70afeb14b4SPaul Moore 71c1969f29SDavid S. Miller static inline unsigned int xfrm_dst_hash(xfrm_address_t *daddr, 72c1969f29SDavid S. Miller xfrm_address_t *saddr, 73c1969f29SDavid S. Miller u32 reqid, 74a624c108SDavid S. Miller unsigned short family) 75a624c108SDavid S. Miller { 76c1969f29SDavid S. Miller return __xfrm_dst_hash(daddr, saddr, reqid, family, xfrm_state_hmask); 77a624c108SDavid S. Miller } 78a624c108SDavid S. Miller 79667bbcb6SMasahide NAKAMURA static inline unsigned int xfrm_src_hash(xfrm_address_t *daddr, 80667bbcb6SMasahide NAKAMURA xfrm_address_t *saddr, 8144e36b42SDavid S. Miller unsigned short family) 82f034b5d4SDavid S. Miller { 83667bbcb6SMasahide NAKAMURA return __xfrm_src_hash(daddr, saddr, family, xfrm_state_hmask); 84f034b5d4SDavid S. Miller } 85f034b5d4SDavid S. Miller 862575b654SDavid S. Miller static inline unsigned int 878122adf0SAl Viro xfrm_spi_hash(xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family) 88f034b5d4SDavid S. Miller { 89c1969f29SDavid S. Miller return __xfrm_spi_hash(daddr, spi, proto, family, xfrm_state_hmask); 90f034b5d4SDavid S. Miller } 91f034b5d4SDavid S. Miller 92f034b5d4SDavid S. Miller static void xfrm_hash_transfer(struct hlist_head *list, 93f034b5d4SDavid S. Miller struct hlist_head *ndsttable, 94f034b5d4SDavid S. Miller struct hlist_head *nsrctable, 95f034b5d4SDavid S. Miller struct hlist_head *nspitable, 96f034b5d4SDavid S. Miller unsigned int nhashmask) 97f034b5d4SDavid S. Miller { 98f034b5d4SDavid S. Miller struct hlist_node *entry, *tmp; 99f034b5d4SDavid S. Miller struct xfrm_state *x; 100f034b5d4SDavid S. Miller 101f034b5d4SDavid S. Miller hlist_for_each_entry_safe(x, entry, tmp, list, bydst) { 102f034b5d4SDavid S. Miller unsigned int h; 103f034b5d4SDavid S. Miller 104c1969f29SDavid S. Miller h = __xfrm_dst_hash(&x->id.daddr, &x->props.saddr, 105c1969f29SDavid S. Miller x->props.reqid, x->props.family, 106c1969f29SDavid S. Miller nhashmask); 107f034b5d4SDavid S. Miller hlist_add_head(&x->bydst, ndsttable+h); 108f034b5d4SDavid S. Miller 109667bbcb6SMasahide NAKAMURA h = __xfrm_src_hash(&x->id.daddr, &x->props.saddr, 110667bbcb6SMasahide NAKAMURA x->props.family, 111f034b5d4SDavid S. Miller nhashmask); 112f034b5d4SDavid S. Miller hlist_add_head(&x->bysrc, nsrctable+h); 113f034b5d4SDavid S. Miller 1147b4dc360SMasahide NAKAMURA if (x->id.spi) { 1157b4dc360SMasahide NAKAMURA h = __xfrm_spi_hash(&x->id.daddr, x->id.spi, 1167b4dc360SMasahide NAKAMURA x->id.proto, x->props.family, 1177b4dc360SMasahide NAKAMURA nhashmask); 118f034b5d4SDavid S. Miller hlist_add_head(&x->byspi, nspitable+h); 119f034b5d4SDavid S. Miller } 120f034b5d4SDavid S. Miller } 1217b4dc360SMasahide NAKAMURA } 122f034b5d4SDavid S. Miller 123f034b5d4SDavid S. Miller static unsigned long xfrm_hash_new_size(void) 124f034b5d4SDavid S. Miller { 125f034b5d4SDavid S. Miller return ((xfrm_state_hmask + 1) << 1) * 126f034b5d4SDavid S. Miller sizeof(struct hlist_head); 127f034b5d4SDavid S. Miller } 128f034b5d4SDavid S. Miller 129f034b5d4SDavid S. Miller static DEFINE_MUTEX(hash_resize_mutex); 130f034b5d4SDavid S. Miller 131c4028958SDavid Howells static void xfrm_hash_resize(struct work_struct *__unused) 132f034b5d4SDavid S. Miller { 133f034b5d4SDavid S. Miller struct hlist_head *ndst, *nsrc, *nspi, *odst, *osrc, *ospi; 134f034b5d4SDavid S. Miller unsigned long nsize, osize; 135f034b5d4SDavid S. Miller unsigned int nhashmask, ohashmask; 136f034b5d4SDavid S. Miller int i; 137f034b5d4SDavid S. Miller 138f034b5d4SDavid S. Miller mutex_lock(&hash_resize_mutex); 139f034b5d4SDavid S. Miller 140f034b5d4SDavid S. Miller nsize = xfrm_hash_new_size(); 14144e36b42SDavid S. Miller ndst = xfrm_hash_alloc(nsize); 142f034b5d4SDavid S. Miller if (!ndst) 143f034b5d4SDavid S. Miller goto out_unlock; 14444e36b42SDavid S. Miller nsrc = xfrm_hash_alloc(nsize); 145f034b5d4SDavid S. Miller if (!nsrc) { 14644e36b42SDavid S. Miller xfrm_hash_free(ndst, nsize); 147f034b5d4SDavid S. Miller goto out_unlock; 148f034b5d4SDavid S. Miller } 14944e36b42SDavid S. Miller nspi = xfrm_hash_alloc(nsize); 150f034b5d4SDavid S. Miller if (!nspi) { 15144e36b42SDavid S. Miller xfrm_hash_free(ndst, nsize); 15244e36b42SDavid S. Miller xfrm_hash_free(nsrc, nsize); 153f034b5d4SDavid S. Miller goto out_unlock; 154f034b5d4SDavid S. Miller } 155f034b5d4SDavid S. Miller 156f034b5d4SDavid S. Miller spin_lock_bh(&xfrm_state_lock); 157f034b5d4SDavid S. Miller 158f034b5d4SDavid S. Miller nhashmask = (nsize / sizeof(struct hlist_head)) - 1U; 159f034b5d4SDavid S. Miller for (i = xfrm_state_hmask; i >= 0; i--) 160f034b5d4SDavid S. Miller xfrm_hash_transfer(xfrm_state_bydst+i, ndst, nsrc, nspi, 161f034b5d4SDavid S. Miller nhashmask); 162f034b5d4SDavid S. Miller 163f034b5d4SDavid S. Miller odst = xfrm_state_bydst; 164f034b5d4SDavid S. Miller osrc = xfrm_state_bysrc; 165f034b5d4SDavid S. Miller ospi = xfrm_state_byspi; 166f034b5d4SDavid S. Miller ohashmask = xfrm_state_hmask; 167f034b5d4SDavid S. Miller 168f034b5d4SDavid S. Miller xfrm_state_bydst = ndst; 169f034b5d4SDavid S. Miller xfrm_state_bysrc = nsrc; 170f034b5d4SDavid S. Miller xfrm_state_byspi = nspi; 171f034b5d4SDavid S. Miller xfrm_state_hmask = nhashmask; 172f034b5d4SDavid S. Miller 173f034b5d4SDavid S. Miller spin_unlock_bh(&xfrm_state_lock); 174f034b5d4SDavid S. Miller 175f034b5d4SDavid S. Miller osize = (ohashmask + 1) * sizeof(struct hlist_head); 17644e36b42SDavid S. Miller xfrm_hash_free(odst, osize); 17744e36b42SDavid S. Miller xfrm_hash_free(osrc, osize); 17844e36b42SDavid S. Miller xfrm_hash_free(ospi, osize); 179f034b5d4SDavid S. Miller 180f034b5d4SDavid S. Miller out_unlock: 181f034b5d4SDavid S. Miller mutex_unlock(&hash_resize_mutex); 182f034b5d4SDavid S. Miller } 183f034b5d4SDavid S. Miller 184c4028958SDavid Howells static DECLARE_WORK(xfrm_hash_work, xfrm_hash_resize); 185f034b5d4SDavid S. Miller 1861da177e4SLinus Torvalds DECLARE_WAIT_QUEUE_HEAD(km_waitq); 1871da177e4SLinus Torvalds EXPORT_SYMBOL(km_waitq); 1881da177e4SLinus Torvalds 1891da177e4SLinus Torvalds static DEFINE_RWLOCK(xfrm_state_afinfo_lock); 1901da177e4SLinus Torvalds static struct xfrm_state_afinfo *xfrm_state_afinfo[NPROTO]; 1911da177e4SLinus Torvalds 1921da177e4SLinus Torvalds static struct work_struct xfrm_state_gc_work; 1938f126e37SDavid S. Miller static HLIST_HEAD(xfrm_state_gc_list); 1941da177e4SLinus Torvalds static DEFINE_SPINLOCK(xfrm_state_gc_lock); 1951da177e4SLinus Torvalds 19653bc6b4dSJamal Hadi Salim int __xfrm_state_delete(struct xfrm_state *x); 1971da177e4SLinus Torvalds 198980ebd25SJamal Hadi Salim int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol); 19953bc6b4dSJamal Hadi Salim void km_state_expired(struct xfrm_state *x, int hard, u32 pid); 2001da177e4SLinus Torvalds 201aa5d62ccSHerbert Xu static struct xfrm_state_afinfo *xfrm_state_lock_afinfo(unsigned int family) 202aa5d62ccSHerbert Xu { 203aa5d62ccSHerbert Xu struct xfrm_state_afinfo *afinfo; 204aa5d62ccSHerbert Xu if (unlikely(family >= NPROTO)) 205aa5d62ccSHerbert Xu return NULL; 206aa5d62ccSHerbert Xu write_lock_bh(&xfrm_state_afinfo_lock); 207aa5d62ccSHerbert Xu afinfo = xfrm_state_afinfo[family]; 208aa5d62ccSHerbert Xu if (unlikely(!afinfo)) 209aa5d62ccSHerbert Xu write_unlock_bh(&xfrm_state_afinfo_lock); 210aa5d62ccSHerbert Xu return afinfo; 211aa5d62ccSHerbert Xu } 212aa5d62ccSHerbert Xu 213aa5d62ccSHerbert Xu static void xfrm_state_unlock_afinfo(struct xfrm_state_afinfo *afinfo) 2149a429c49SEric Dumazet __releases(xfrm_state_afinfo_lock) 215aa5d62ccSHerbert Xu { 216aa5d62ccSHerbert Xu write_unlock_bh(&xfrm_state_afinfo_lock); 217aa5d62ccSHerbert Xu } 218aa5d62ccSHerbert Xu 219aa5d62ccSHerbert Xu int xfrm_register_type(struct xfrm_type *type, unsigned short family) 220aa5d62ccSHerbert Xu { 221aa5d62ccSHerbert Xu struct xfrm_state_afinfo *afinfo = xfrm_state_lock_afinfo(family); 222aa5d62ccSHerbert Xu struct xfrm_type **typemap; 223aa5d62ccSHerbert Xu int err = 0; 224aa5d62ccSHerbert Xu 225aa5d62ccSHerbert Xu if (unlikely(afinfo == NULL)) 226aa5d62ccSHerbert Xu return -EAFNOSUPPORT; 227aa5d62ccSHerbert Xu typemap = afinfo->type_map; 228aa5d62ccSHerbert Xu 229aa5d62ccSHerbert Xu if (likely(typemap[type->proto] == NULL)) 230aa5d62ccSHerbert Xu typemap[type->proto] = type; 231aa5d62ccSHerbert Xu else 232aa5d62ccSHerbert Xu err = -EEXIST; 233aa5d62ccSHerbert Xu xfrm_state_unlock_afinfo(afinfo); 234aa5d62ccSHerbert Xu return err; 235aa5d62ccSHerbert Xu } 236aa5d62ccSHerbert Xu EXPORT_SYMBOL(xfrm_register_type); 237aa5d62ccSHerbert Xu 238aa5d62ccSHerbert Xu int xfrm_unregister_type(struct xfrm_type *type, unsigned short family) 239aa5d62ccSHerbert Xu { 240aa5d62ccSHerbert Xu struct xfrm_state_afinfo *afinfo = xfrm_state_lock_afinfo(family); 241aa5d62ccSHerbert Xu struct xfrm_type **typemap; 242aa5d62ccSHerbert Xu int err = 0; 243aa5d62ccSHerbert Xu 244aa5d62ccSHerbert Xu if (unlikely(afinfo == NULL)) 245aa5d62ccSHerbert Xu return -EAFNOSUPPORT; 246aa5d62ccSHerbert Xu typemap = afinfo->type_map; 247aa5d62ccSHerbert Xu 248aa5d62ccSHerbert Xu if (unlikely(typemap[type->proto] != type)) 249aa5d62ccSHerbert Xu err = -ENOENT; 250aa5d62ccSHerbert Xu else 251aa5d62ccSHerbert Xu typemap[type->proto] = NULL; 252aa5d62ccSHerbert Xu xfrm_state_unlock_afinfo(afinfo); 253aa5d62ccSHerbert Xu return err; 254aa5d62ccSHerbert Xu } 255aa5d62ccSHerbert Xu EXPORT_SYMBOL(xfrm_unregister_type); 256aa5d62ccSHerbert Xu 257aa5d62ccSHerbert Xu static struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family) 258aa5d62ccSHerbert Xu { 259aa5d62ccSHerbert Xu struct xfrm_state_afinfo *afinfo; 260aa5d62ccSHerbert Xu struct xfrm_type **typemap; 261aa5d62ccSHerbert Xu struct xfrm_type *type; 262aa5d62ccSHerbert Xu int modload_attempted = 0; 263aa5d62ccSHerbert Xu 264aa5d62ccSHerbert Xu retry: 265aa5d62ccSHerbert Xu afinfo = xfrm_state_get_afinfo(family); 266aa5d62ccSHerbert Xu if (unlikely(afinfo == NULL)) 267aa5d62ccSHerbert Xu return NULL; 268aa5d62ccSHerbert Xu typemap = afinfo->type_map; 269aa5d62ccSHerbert Xu 270aa5d62ccSHerbert Xu type = typemap[proto]; 271aa5d62ccSHerbert Xu if (unlikely(type && !try_module_get(type->owner))) 272aa5d62ccSHerbert Xu type = NULL; 273aa5d62ccSHerbert Xu if (!type && !modload_attempted) { 274aa5d62ccSHerbert Xu xfrm_state_put_afinfo(afinfo); 275aa5d62ccSHerbert Xu request_module("xfrm-type-%d-%d", family, proto); 276aa5d62ccSHerbert Xu modload_attempted = 1; 277aa5d62ccSHerbert Xu goto retry; 278aa5d62ccSHerbert Xu } 279aa5d62ccSHerbert Xu 280aa5d62ccSHerbert Xu xfrm_state_put_afinfo(afinfo); 281aa5d62ccSHerbert Xu return type; 282aa5d62ccSHerbert Xu } 283aa5d62ccSHerbert Xu 284aa5d62ccSHerbert Xu static void xfrm_put_type(struct xfrm_type *type) 285aa5d62ccSHerbert Xu { 286aa5d62ccSHerbert Xu module_put(type->owner); 287aa5d62ccSHerbert Xu } 288aa5d62ccSHerbert Xu 289aa5d62ccSHerbert Xu int xfrm_register_mode(struct xfrm_mode *mode, int family) 290aa5d62ccSHerbert Xu { 291aa5d62ccSHerbert Xu struct xfrm_state_afinfo *afinfo; 292aa5d62ccSHerbert Xu struct xfrm_mode **modemap; 293aa5d62ccSHerbert Xu int err; 294aa5d62ccSHerbert Xu 295aa5d62ccSHerbert Xu if (unlikely(mode->encap >= XFRM_MODE_MAX)) 296aa5d62ccSHerbert Xu return -EINVAL; 297aa5d62ccSHerbert Xu 298aa5d62ccSHerbert Xu afinfo = xfrm_state_lock_afinfo(family); 299aa5d62ccSHerbert Xu if (unlikely(afinfo == NULL)) 300aa5d62ccSHerbert Xu return -EAFNOSUPPORT; 301aa5d62ccSHerbert Xu 302aa5d62ccSHerbert Xu err = -EEXIST; 303aa5d62ccSHerbert Xu modemap = afinfo->mode_map; 30417c2a42aSHerbert Xu if (modemap[mode->encap]) 30517c2a42aSHerbert Xu goto out; 30617c2a42aSHerbert Xu 30717c2a42aSHerbert Xu err = -ENOENT; 30817c2a42aSHerbert Xu if (!try_module_get(afinfo->owner)) 30917c2a42aSHerbert Xu goto out; 31017c2a42aSHerbert Xu 31117c2a42aSHerbert Xu mode->afinfo = afinfo; 312aa5d62ccSHerbert Xu modemap[mode->encap] = mode; 313aa5d62ccSHerbert Xu err = 0; 314aa5d62ccSHerbert Xu 31517c2a42aSHerbert Xu out: 316aa5d62ccSHerbert Xu xfrm_state_unlock_afinfo(afinfo); 317aa5d62ccSHerbert Xu return err; 318aa5d62ccSHerbert Xu } 319aa5d62ccSHerbert Xu EXPORT_SYMBOL(xfrm_register_mode); 320aa5d62ccSHerbert Xu 321aa5d62ccSHerbert Xu int xfrm_unregister_mode(struct xfrm_mode *mode, int family) 322aa5d62ccSHerbert Xu { 323aa5d62ccSHerbert Xu struct xfrm_state_afinfo *afinfo; 324aa5d62ccSHerbert Xu struct xfrm_mode **modemap; 325aa5d62ccSHerbert Xu int err; 326aa5d62ccSHerbert Xu 327aa5d62ccSHerbert Xu if (unlikely(mode->encap >= XFRM_MODE_MAX)) 328aa5d62ccSHerbert Xu return -EINVAL; 329aa5d62ccSHerbert Xu 330aa5d62ccSHerbert Xu afinfo = xfrm_state_lock_afinfo(family); 331aa5d62ccSHerbert Xu if (unlikely(afinfo == NULL)) 332aa5d62ccSHerbert Xu return -EAFNOSUPPORT; 333aa5d62ccSHerbert Xu 334aa5d62ccSHerbert Xu err = -ENOENT; 335aa5d62ccSHerbert Xu modemap = afinfo->mode_map; 336aa5d62ccSHerbert Xu if (likely(modemap[mode->encap] == mode)) { 337aa5d62ccSHerbert Xu modemap[mode->encap] = NULL; 33817c2a42aSHerbert Xu module_put(mode->afinfo->owner); 339aa5d62ccSHerbert Xu err = 0; 340aa5d62ccSHerbert Xu } 341aa5d62ccSHerbert Xu 342aa5d62ccSHerbert Xu xfrm_state_unlock_afinfo(afinfo); 343aa5d62ccSHerbert Xu return err; 344aa5d62ccSHerbert Xu } 345aa5d62ccSHerbert Xu EXPORT_SYMBOL(xfrm_unregister_mode); 346aa5d62ccSHerbert Xu 347aa5d62ccSHerbert Xu static struct xfrm_mode *xfrm_get_mode(unsigned int encap, int family) 348aa5d62ccSHerbert Xu { 349aa5d62ccSHerbert Xu struct xfrm_state_afinfo *afinfo; 350aa5d62ccSHerbert Xu struct xfrm_mode *mode; 351aa5d62ccSHerbert Xu int modload_attempted = 0; 352aa5d62ccSHerbert Xu 353aa5d62ccSHerbert Xu if (unlikely(encap >= XFRM_MODE_MAX)) 354aa5d62ccSHerbert Xu return NULL; 355aa5d62ccSHerbert Xu 356aa5d62ccSHerbert Xu retry: 357aa5d62ccSHerbert Xu afinfo = xfrm_state_get_afinfo(family); 358aa5d62ccSHerbert Xu if (unlikely(afinfo == NULL)) 359aa5d62ccSHerbert Xu return NULL; 360aa5d62ccSHerbert Xu 361aa5d62ccSHerbert Xu mode = afinfo->mode_map[encap]; 362aa5d62ccSHerbert Xu if (unlikely(mode && !try_module_get(mode->owner))) 363aa5d62ccSHerbert Xu mode = NULL; 364aa5d62ccSHerbert Xu if (!mode && !modload_attempted) { 365aa5d62ccSHerbert Xu xfrm_state_put_afinfo(afinfo); 366aa5d62ccSHerbert Xu request_module("xfrm-mode-%d-%d", family, encap); 367aa5d62ccSHerbert Xu modload_attempted = 1; 368aa5d62ccSHerbert Xu goto retry; 369aa5d62ccSHerbert Xu } 370aa5d62ccSHerbert Xu 371aa5d62ccSHerbert Xu xfrm_state_put_afinfo(afinfo); 372aa5d62ccSHerbert Xu return mode; 373aa5d62ccSHerbert Xu } 374aa5d62ccSHerbert Xu 375aa5d62ccSHerbert Xu static void xfrm_put_mode(struct xfrm_mode *mode) 376aa5d62ccSHerbert Xu { 377aa5d62ccSHerbert Xu module_put(mode->owner); 378aa5d62ccSHerbert Xu } 379aa5d62ccSHerbert Xu 3801da177e4SLinus Torvalds static void xfrm_state_gc_destroy(struct xfrm_state *x) 3811da177e4SLinus Torvalds { 382a47f0ce0SDavid S. Miller del_timer_sync(&x->timer); 383a47f0ce0SDavid S. Miller del_timer_sync(&x->rtimer); 3841da177e4SLinus Torvalds kfree(x->aalg); 3851da177e4SLinus Torvalds kfree(x->ealg); 3861da177e4SLinus Torvalds kfree(x->calg); 3871da177e4SLinus Torvalds kfree(x->encap); 388060f02a3SNoriaki TAKAMIYA kfree(x->coaddr); 38913996378SHerbert Xu if (x->inner_mode) 39013996378SHerbert Xu xfrm_put_mode(x->inner_mode); 39113996378SHerbert Xu if (x->outer_mode) 39213996378SHerbert Xu xfrm_put_mode(x->outer_mode); 3931da177e4SLinus Torvalds if (x->type) { 3941da177e4SLinus Torvalds x->type->destructor(x); 3951da177e4SLinus Torvalds xfrm_put_type(x->type); 3961da177e4SLinus Torvalds } 397df71837dSTrent Jaeger security_xfrm_state_free(x); 3981da177e4SLinus Torvalds kfree(x); 3991da177e4SLinus Torvalds } 4001da177e4SLinus Torvalds 401c4028958SDavid Howells static void xfrm_state_gc_task(struct work_struct *data) 4021da177e4SLinus Torvalds { 4031da177e4SLinus Torvalds struct xfrm_state *x; 4048f126e37SDavid S. Miller struct hlist_node *entry, *tmp; 4058f126e37SDavid S. Miller struct hlist_head gc_list; 4061da177e4SLinus Torvalds 4071da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_gc_lock); 4088f126e37SDavid S. Miller gc_list.first = xfrm_state_gc_list.first; 4098f126e37SDavid S. Miller INIT_HLIST_HEAD(&xfrm_state_gc_list); 4101da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_gc_lock); 4111da177e4SLinus Torvalds 4128f126e37SDavid S. Miller hlist_for_each_entry_safe(x, entry, tmp, &gc_list, bydst) 4131da177e4SLinus Torvalds xfrm_state_gc_destroy(x); 4148f126e37SDavid S. Miller 4151da177e4SLinus Torvalds wake_up(&km_waitq); 4161da177e4SLinus Torvalds } 4171da177e4SLinus Torvalds 4181da177e4SLinus Torvalds static inline unsigned long make_jiffies(long secs) 4191da177e4SLinus Torvalds { 4201da177e4SLinus Torvalds if (secs >= (MAX_SCHEDULE_TIMEOUT-1)/HZ) 4211da177e4SLinus Torvalds return MAX_SCHEDULE_TIMEOUT-1; 4221da177e4SLinus Torvalds else 4231da177e4SLinus Torvalds return secs*HZ; 4241da177e4SLinus Torvalds } 4251da177e4SLinus Torvalds 4261da177e4SLinus Torvalds static void xfrm_timer_handler(unsigned long data) 4271da177e4SLinus Torvalds { 4281da177e4SLinus Torvalds struct xfrm_state *x = (struct xfrm_state*)data; 4299d729f72SJames Morris unsigned long now = get_seconds(); 4301da177e4SLinus Torvalds long next = LONG_MAX; 4311da177e4SLinus Torvalds int warn = 0; 432161a09e7SJoy Latten int err = 0; 4331da177e4SLinus Torvalds 4341da177e4SLinus Torvalds spin_lock(&x->lock); 4351da177e4SLinus Torvalds if (x->km.state == XFRM_STATE_DEAD) 4361da177e4SLinus Torvalds goto out; 4371da177e4SLinus Torvalds if (x->km.state == XFRM_STATE_EXPIRED) 4381da177e4SLinus Torvalds goto expired; 4391da177e4SLinus Torvalds if (x->lft.hard_add_expires_seconds) { 4401da177e4SLinus Torvalds long tmo = x->lft.hard_add_expires_seconds + 4411da177e4SLinus Torvalds x->curlft.add_time - now; 4421da177e4SLinus Torvalds if (tmo <= 0) 4431da177e4SLinus Torvalds goto expired; 4441da177e4SLinus Torvalds if (tmo < next) 4451da177e4SLinus Torvalds next = tmo; 4461da177e4SLinus Torvalds } 4471da177e4SLinus Torvalds if (x->lft.hard_use_expires_seconds) { 4481da177e4SLinus Torvalds long tmo = x->lft.hard_use_expires_seconds + 4491da177e4SLinus Torvalds (x->curlft.use_time ? : now) - now; 4501da177e4SLinus Torvalds if (tmo <= 0) 4511da177e4SLinus Torvalds goto expired; 4521da177e4SLinus Torvalds if (tmo < next) 4531da177e4SLinus Torvalds next = tmo; 4541da177e4SLinus Torvalds } 4551da177e4SLinus Torvalds if (x->km.dying) 4561da177e4SLinus Torvalds goto resched; 4571da177e4SLinus Torvalds if (x->lft.soft_add_expires_seconds) { 4581da177e4SLinus Torvalds long tmo = x->lft.soft_add_expires_seconds + 4591da177e4SLinus Torvalds x->curlft.add_time - now; 4601da177e4SLinus Torvalds if (tmo <= 0) 4611da177e4SLinus Torvalds warn = 1; 4621da177e4SLinus Torvalds else if (tmo < next) 4631da177e4SLinus Torvalds next = tmo; 4641da177e4SLinus Torvalds } 4651da177e4SLinus Torvalds if (x->lft.soft_use_expires_seconds) { 4661da177e4SLinus Torvalds long tmo = x->lft.soft_use_expires_seconds + 4671da177e4SLinus Torvalds (x->curlft.use_time ? : now) - now; 4681da177e4SLinus Torvalds if (tmo <= 0) 4691da177e4SLinus Torvalds warn = 1; 4701da177e4SLinus Torvalds else if (tmo < next) 4711da177e4SLinus Torvalds next = tmo; 4721da177e4SLinus Torvalds } 4731da177e4SLinus Torvalds 4744666faabSHerbert Xu x->km.dying = warn; 4751da177e4SLinus Torvalds if (warn) 47653bc6b4dSJamal Hadi Salim km_state_expired(x, 0, 0); 4771da177e4SLinus Torvalds resched: 478a47f0ce0SDavid S. Miller if (next != LONG_MAX) 479a47f0ce0SDavid S. Miller mod_timer(&x->timer, jiffies + make_jiffies(next)); 480a47f0ce0SDavid S. Miller 4811da177e4SLinus Torvalds goto out; 4821da177e4SLinus Torvalds 4831da177e4SLinus Torvalds expired: 4841da177e4SLinus Torvalds if (x->km.state == XFRM_STATE_ACQ && x->id.spi == 0) { 4851da177e4SLinus Torvalds x->km.state = XFRM_STATE_EXPIRED; 4861da177e4SLinus Torvalds wake_up(&km_waitq); 4871da177e4SLinus Torvalds next = 2; 4881da177e4SLinus Torvalds goto resched; 4891da177e4SLinus Torvalds } 490161a09e7SJoy Latten 491161a09e7SJoy Latten err = __xfrm_state_delete(x); 492161a09e7SJoy Latten if (!err && x->id.spi) 49353bc6b4dSJamal Hadi Salim km_state_expired(x, 1, 0); 4941da177e4SLinus Torvalds 495ab5f5e8bSJoy Latten xfrm_audit_state_delete(x, err ? 0 : 1, 496ab5f5e8bSJoy Latten audit_get_loginuid(current->audit_context), 0); 497161a09e7SJoy Latten 4981da177e4SLinus Torvalds out: 4991da177e4SLinus Torvalds spin_unlock(&x->lock); 5001da177e4SLinus Torvalds } 5011da177e4SLinus Torvalds 5020ac84752SDavid S. Miller static void xfrm_replay_timer_handler(unsigned long data); 5030ac84752SDavid S. Miller 5041da177e4SLinus Torvalds struct xfrm_state *xfrm_state_alloc(void) 5051da177e4SLinus Torvalds { 5061da177e4SLinus Torvalds struct xfrm_state *x; 5071da177e4SLinus Torvalds 5080da974f4SPanagiotis Issaris x = kzalloc(sizeof(struct xfrm_state), GFP_ATOMIC); 5091da177e4SLinus Torvalds 5101da177e4SLinus Torvalds if (x) { 5111da177e4SLinus Torvalds atomic_set(&x->refcnt, 1); 5121da177e4SLinus Torvalds atomic_set(&x->tunnel_users, 0); 5138f126e37SDavid S. Miller INIT_HLIST_NODE(&x->bydst); 5148f126e37SDavid S. Miller INIT_HLIST_NODE(&x->bysrc); 5158f126e37SDavid S. Miller INIT_HLIST_NODE(&x->byspi); 516b24b8a24SPavel Emelyanov setup_timer(&x->timer, xfrm_timer_handler, (unsigned long)x); 517b24b8a24SPavel Emelyanov setup_timer(&x->rtimer, xfrm_replay_timer_handler, 518b24b8a24SPavel Emelyanov (unsigned long)x); 5199d729f72SJames Morris x->curlft.add_time = get_seconds(); 5201da177e4SLinus Torvalds x->lft.soft_byte_limit = XFRM_INF; 5211da177e4SLinus Torvalds x->lft.soft_packet_limit = XFRM_INF; 5221da177e4SLinus Torvalds x->lft.hard_byte_limit = XFRM_INF; 5231da177e4SLinus Torvalds x->lft.hard_packet_limit = XFRM_INF; 524f8cd5488SJamal Hadi Salim x->replay_maxage = 0; 525f8cd5488SJamal Hadi Salim x->replay_maxdiff = 0; 5261da177e4SLinus Torvalds spin_lock_init(&x->lock); 5271da177e4SLinus Torvalds } 5281da177e4SLinus Torvalds return x; 5291da177e4SLinus Torvalds } 5301da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_alloc); 5311da177e4SLinus Torvalds 5321da177e4SLinus Torvalds void __xfrm_state_destroy(struct xfrm_state *x) 5331da177e4SLinus Torvalds { 5341da177e4SLinus Torvalds BUG_TRAP(x->km.state == XFRM_STATE_DEAD); 5351da177e4SLinus Torvalds 5361da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_gc_lock); 5378f126e37SDavid S. Miller hlist_add_head(&x->bydst, &xfrm_state_gc_list); 5381da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_gc_lock); 5391da177e4SLinus Torvalds schedule_work(&xfrm_state_gc_work); 5401da177e4SLinus Torvalds } 5411da177e4SLinus Torvalds EXPORT_SYMBOL(__xfrm_state_destroy); 5421da177e4SLinus Torvalds 54353bc6b4dSJamal Hadi Salim int __xfrm_state_delete(struct xfrm_state *x) 5441da177e4SLinus Torvalds { 54526b15dadSJamal Hadi Salim int err = -ESRCH; 54626b15dadSJamal Hadi Salim 5471da177e4SLinus Torvalds if (x->km.state != XFRM_STATE_DEAD) { 5481da177e4SLinus Torvalds x->km.state = XFRM_STATE_DEAD; 5491da177e4SLinus Torvalds spin_lock(&xfrm_state_lock); 5508f126e37SDavid S. Miller hlist_del(&x->bydst); 5518f126e37SDavid S. Miller hlist_del(&x->bysrc); 552a47f0ce0SDavid S. Miller if (x->id.spi) 5538f126e37SDavid S. Miller hlist_del(&x->byspi); 554f034b5d4SDavid S. Miller xfrm_state_num--; 5551da177e4SLinus Torvalds spin_unlock(&xfrm_state_lock); 5561da177e4SLinus Torvalds 5571da177e4SLinus Torvalds /* All xfrm_state objects are created by xfrm_state_alloc. 5581da177e4SLinus Torvalds * The xfrm_state_alloc call gives a reference, and that 5591da177e4SLinus Torvalds * is what we are dropping here. 5601da177e4SLinus Torvalds */ 5615dba4797SPatrick McHardy xfrm_state_put(x); 56226b15dadSJamal Hadi Salim err = 0; 5631da177e4SLinus Torvalds } 5641da177e4SLinus Torvalds 56526b15dadSJamal Hadi Salim return err; 56626b15dadSJamal Hadi Salim } 56753bc6b4dSJamal Hadi Salim EXPORT_SYMBOL(__xfrm_state_delete); 56826b15dadSJamal Hadi Salim 56926b15dadSJamal Hadi Salim int xfrm_state_delete(struct xfrm_state *x) 5701da177e4SLinus Torvalds { 57126b15dadSJamal Hadi Salim int err; 57226b15dadSJamal Hadi Salim 5731da177e4SLinus Torvalds spin_lock_bh(&x->lock); 57426b15dadSJamal Hadi Salim err = __xfrm_state_delete(x); 5751da177e4SLinus Torvalds spin_unlock_bh(&x->lock); 57626b15dadSJamal Hadi Salim 57726b15dadSJamal Hadi Salim return err; 5781da177e4SLinus Torvalds } 5791da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_delete); 5801da177e4SLinus Torvalds 5814aa2e62cSJoy Latten #ifdef CONFIG_SECURITY_NETWORK_XFRM 5824aa2e62cSJoy Latten static inline int 5834aa2e62cSJoy Latten xfrm_state_flush_secctx_check(u8 proto, struct xfrm_audit *audit_info) 5841da177e4SLinus Torvalds { 5854aa2e62cSJoy Latten int i, err = 0; 5864aa2e62cSJoy Latten 5874aa2e62cSJoy Latten for (i = 0; i <= xfrm_state_hmask; i++) { 5884aa2e62cSJoy Latten struct hlist_node *entry; 5894aa2e62cSJoy Latten struct xfrm_state *x; 5904aa2e62cSJoy Latten 5914aa2e62cSJoy Latten hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) { 5924aa2e62cSJoy Latten if (xfrm_id_proto_match(x->id.proto, proto) && 5934aa2e62cSJoy Latten (err = security_xfrm_state_delete(x)) != 0) { 594ab5f5e8bSJoy Latten xfrm_audit_state_delete(x, 0, 595ab5f5e8bSJoy Latten audit_info->loginuid, 596ab5f5e8bSJoy Latten audit_info->secid); 5974aa2e62cSJoy Latten return err; 5984aa2e62cSJoy Latten } 5994aa2e62cSJoy Latten } 6004aa2e62cSJoy Latten } 6014aa2e62cSJoy Latten 6024aa2e62cSJoy Latten return err; 6034aa2e62cSJoy Latten } 6044aa2e62cSJoy Latten #else 6054aa2e62cSJoy Latten static inline int 6064aa2e62cSJoy Latten xfrm_state_flush_secctx_check(u8 proto, struct xfrm_audit *audit_info) 6074aa2e62cSJoy Latten { 6084aa2e62cSJoy Latten return 0; 6094aa2e62cSJoy Latten } 6104aa2e62cSJoy Latten #endif 6114aa2e62cSJoy Latten 6124aa2e62cSJoy Latten int xfrm_state_flush(u8 proto, struct xfrm_audit *audit_info) 6134aa2e62cSJoy Latten { 6144aa2e62cSJoy Latten int i, err = 0; 6151da177e4SLinus Torvalds 6161da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_lock); 6174aa2e62cSJoy Latten err = xfrm_state_flush_secctx_check(proto, audit_info); 6184aa2e62cSJoy Latten if (err) 6194aa2e62cSJoy Latten goto out; 6204aa2e62cSJoy Latten 621a9917c06SMasahide NAKAMURA for (i = 0; i <= xfrm_state_hmask; i++) { 6228f126e37SDavid S. Miller struct hlist_node *entry; 6238f126e37SDavid S. Miller struct xfrm_state *x; 6241da177e4SLinus Torvalds restart: 6258f126e37SDavid S. Miller hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) { 6261da177e4SLinus Torvalds if (!xfrm_state_kern(x) && 6275794708fSMasahide NAKAMURA xfrm_id_proto_match(x->id.proto, proto)) { 6281da177e4SLinus Torvalds xfrm_state_hold(x); 6291da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_lock); 6301da177e4SLinus Torvalds 631161a09e7SJoy Latten err = xfrm_state_delete(x); 632ab5f5e8bSJoy Latten xfrm_audit_state_delete(x, err ? 0 : 1, 633ab5f5e8bSJoy Latten audit_info->loginuid, 634ab5f5e8bSJoy Latten audit_info->secid); 6351da177e4SLinus Torvalds xfrm_state_put(x); 6361da177e4SLinus Torvalds 6371da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_lock); 6381da177e4SLinus Torvalds goto restart; 6391da177e4SLinus Torvalds } 6401da177e4SLinus Torvalds } 6411da177e4SLinus Torvalds } 6424aa2e62cSJoy Latten err = 0; 6434aa2e62cSJoy Latten 6444aa2e62cSJoy Latten out: 6451da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_lock); 6461da177e4SLinus Torvalds wake_up(&km_waitq); 6474aa2e62cSJoy Latten return err; 6481da177e4SLinus Torvalds } 6491da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_flush); 6501da177e4SLinus Torvalds 651af11e316SJamal Hadi Salim void xfrm_sad_getinfo(struct xfrmk_sadinfo *si) 65228d8909bSJamal Hadi Salim { 65328d8909bSJamal Hadi Salim spin_lock_bh(&xfrm_state_lock); 65428d8909bSJamal Hadi Salim si->sadcnt = xfrm_state_num; 65528d8909bSJamal Hadi Salim si->sadhcnt = xfrm_state_hmask; 65628d8909bSJamal Hadi Salim si->sadhmcnt = xfrm_state_hashmax; 65728d8909bSJamal Hadi Salim spin_unlock_bh(&xfrm_state_lock); 65828d8909bSJamal Hadi Salim } 65928d8909bSJamal Hadi Salim EXPORT_SYMBOL(xfrm_sad_getinfo); 66028d8909bSJamal Hadi Salim 6611da177e4SLinus Torvalds static int 6621da177e4SLinus Torvalds xfrm_init_tempsel(struct xfrm_state *x, struct flowi *fl, 6631da177e4SLinus Torvalds struct xfrm_tmpl *tmpl, 6641da177e4SLinus Torvalds xfrm_address_t *daddr, xfrm_address_t *saddr, 6651da177e4SLinus Torvalds unsigned short family) 6661da177e4SLinus Torvalds { 6671da177e4SLinus Torvalds struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); 6681da177e4SLinus Torvalds if (!afinfo) 6691da177e4SLinus Torvalds return -1; 6701da177e4SLinus Torvalds afinfo->init_tempsel(x, fl, tmpl, daddr, saddr); 6711da177e4SLinus Torvalds xfrm_state_put_afinfo(afinfo); 6721da177e4SLinus Torvalds return 0; 6731da177e4SLinus Torvalds } 6741da177e4SLinus Torvalds 675a94cfd19SAl Viro static struct xfrm_state *__xfrm_state_lookup(xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family) 676edcd5821SDavid S. Miller { 677edcd5821SDavid S. Miller unsigned int h = xfrm_spi_hash(daddr, spi, proto, family); 678edcd5821SDavid S. Miller struct xfrm_state *x; 6798f126e37SDavid S. Miller struct hlist_node *entry; 680edcd5821SDavid S. Miller 6818f126e37SDavid S. Miller hlist_for_each_entry(x, entry, xfrm_state_byspi+h, byspi) { 682edcd5821SDavid S. Miller if (x->props.family != family || 683edcd5821SDavid S. Miller x->id.spi != spi || 684edcd5821SDavid S. Miller x->id.proto != proto) 685edcd5821SDavid S. Miller continue; 686edcd5821SDavid S. Miller 687edcd5821SDavid S. Miller switch (family) { 688edcd5821SDavid S. Miller case AF_INET: 689edcd5821SDavid S. Miller if (x->id.daddr.a4 != daddr->a4) 690edcd5821SDavid S. Miller continue; 691edcd5821SDavid S. Miller break; 692edcd5821SDavid S. Miller case AF_INET6: 693edcd5821SDavid S. Miller if (!ipv6_addr_equal((struct in6_addr *)daddr, 694edcd5821SDavid S. Miller (struct in6_addr *) 695edcd5821SDavid S. Miller x->id.daddr.a6)) 696edcd5821SDavid S. Miller continue; 697edcd5821SDavid S. Miller break; 6983ff50b79SStephen Hemminger } 699edcd5821SDavid S. Miller 700edcd5821SDavid S. Miller xfrm_state_hold(x); 701edcd5821SDavid S. Miller return x; 702edcd5821SDavid S. Miller } 703edcd5821SDavid S. Miller 704edcd5821SDavid S. Miller return NULL; 705edcd5821SDavid S. Miller } 706edcd5821SDavid S. Miller 707edcd5821SDavid S. Miller static struct xfrm_state *__xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto, unsigned short family) 708edcd5821SDavid S. Miller { 709667bbcb6SMasahide NAKAMURA unsigned int h = xfrm_src_hash(daddr, saddr, family); 710edcd5821SDavid S. Miller struct xfrm_state *x; 7118f126e37SDavid S. Miller struct hlist_node *entry; 712edcd5821SDavid S. Miller 7138f126e37SDavid S. Miller hlist_for_each_entry(x, entry, xfrm_state_bysrc+h, bysrc) { 714edcd5821SDavid S. Miller if (x->props.family != family || 715edcd5821SDavid S. Miller x->id.proto != proto) 716edcd5821SDavid S. Miller continue; 717edcd5821SDavid S. Miller 718edcd5821SDavid S. Miller switch (family) { 719edcd5821SDavid S. Miller case AF_INET: 720edcd5821SDavid S. Miller if (x->id.daddr.a4 != daddr->a4 || 721edcd5821SDavid S. Miller x->props.saddr.a4 != saddr->a4) 722edcd5821SDavid S. Miller continue; 723edcd5821SDavid S. Miller break; 724edcd5821SDavid S. Miller case AF_INET6: 725edcd5821SDavid S. Miller if (!ipv6_addr_equal((struct in6_addr *)daddr, 726edcd5821SDavid S. Miller (struct in6_addr *) 727edcd5821SDavid S. Miller x->id.daddr.a6) || 728edcd5821SDavid S. Miller !ipv6_addr_equal((struct in6_addr *)saddr, 729edcd5821SDavid S. Miller (struct in6_addr *) 730edcd5821SDavid S. Miller x->props.saddr.a6)) 731edcd5821SDavid S. Miller continue; 732edcd5821SDavid S. Miller break; 7333ff50b79SStephen Hemminger } 734edcd5821SDavid S. Miller 735edcd5821SDavid S. Miller xfrm_state_hold(x); 736edcd5821SDavid S. Miller return x; 737edcd5821SDavid S. Miller } 738edcd5821SDavid S. Miller 739edcd5821SDavid S. Miller return NULL; 740edcd5821SDavid S. Miller } 741edcd5821SDavid S. Miller 742edcd5821SDavid S. Miller static inline struct xfrm_state * 743edcd5821SDavid S. Miller __xfrm_state_locate(struct xfrm_state *x, int use_spi, int family) 744edcd5821SDavid S. Miller { 745edcd5821SDavid S. Miller if (use_spi) 746edcd5821SDavid S. Miller return __xfrm_state_lookup(&x->id.daddr, x->id.spi, 747edcd5821SDavid S. Miller x->id.proto, family); 748edcd5821SDavid S. Miller else 749edcd5821SDavid S. Miller return __xfrm_state_lookup_byaddr(&x->id.daddr, 750edcd5821SDavid S. Miller &x->props.saddr, 751edcd5821SDavid S. Miller x->id.proto, family); 752edcd5821SDavid S. Miller } 753edcd5821SDavid S. Miller 7542fab22f2SPatrick McHardy static void xfrm_hash_grow_check(int have_hash_collision) 7552fab22f2SPatrick McHardy { 7562fab22f2SPatrick McHardy if (have_hash_collision && 7572fab22f2SPatrick McHardy (xfrm_state_hmask + 1) < xfrm_state_hashmax && 7582fab22f2SPatrick McHardy xfrm_state_num > xfrm_state_hmask) 7592fab22f2SPatrick McHardy schedule_work(&xfrm_hash_work); 7602fab22f2SPatrick McHardy } 7612fab22f2SPatrick McHardy 7621da177e4SLinus Torvalds struct xfrm_state * 7631da177e4SLinus Torvalds xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, 7641da177e4SLinus Torvalds struct flowi *fl, struct xfrm_tmpl *tmpl, 7651da177e4SLinus Torvalds struct xfrm_policy *pol, int *err, 7661da177e4SLinus Torvalds unsigned short family) 7671da177e4SLinus Torvalds { 7684bda4f25SPavel Emelyanov unsigned int h; 7698f126e37SDavid S. Miller struct hlist_node *entry; 7701da177e4SLinus Torvalds struct xfrm_state *x, *x0; 7711da177e4SLinus Torvalds int acquire_in_progress = 0; 7721da177e4SLinus Torvalds int error = 0; 7731da177e4SLinus Torvalds struct xfrm_state *best = NULL; 7741da177e4SLinus Torvalds 7751da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_lock); 7764bda4f25SPavel Emelyanov h = xfrm_dst_hash(daddr, saddr, tmpl->reqid, family); 7778f126e37SDavid S. Miller hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) { 7781da177e4SLinus Torvalds if (x->props.family == family && 7791da177e4SLinus Torvalds x->props.reqid == tmpl->reqid && 780fbd9a5b4SMasahide NAKAMURA !(x->props.flags & XFRM_STATE_WILDRECV) && 7811da177e4SLinus Torvalds xfrm_state_addr_check(x, daddr, saddr, family) && 7821da177e4SLinus Torvalds tmpl->mode == x->props.mode && 7831da177e4SLinus Torvalds tmpl->id.proto == x->id.proto && 7841da177e4SLinus Torvalds (tmpl->id.spi == x->id.spi || !tmpl->id.spi)) { 7851da177e4SLinus Torvalds /* Resolution logic: 7861da177e4SLinus Torvalds 1. There is a valid state with matching selector. 7871da177e4SLinus Torvalds Done. 7881da177e4SLinus Torvalds 2. Valid state with inappropriate selector. Skip. 7891da177e4SLinus Torvalds 7901da177e4SLinus Torvalds Entering area of "sysdeps". 7911da177e4SLinus Torvalds 7921da177e4SLinus Torvalds 3. If state is not valid, selector is temporary, 7931da177e4SLinus Torvalds it selects only session which triggered 7941da177e4SLinus Torvalds previous resolution. Key manager will do 7951da177e4SLinus Torvalds something to install a state with proper 7961da177e4SLinus Torvalds selector. 7971da177e4SLinus Torvalds */ 7981da177e4SLinus Torvalds if (x->km.state == XFRM_STATE_VALID) { 79948b8d783SJoakim Koskela if (!xfrm_selector_match(&x->sel, fl, x->sel.family) || 800e0d1caa7SVenkat Yekkirala !security_xfrm_state_pol_flow_match(x, pol, fl)) 8011da177e4SLinus Torvalds continue; 8021da177e4SLinus Torvalds if (!best || 8031da177e4SLinus Torvalds best->km.dying > x->km.dying || 8041da177e4SLinus Torvalds (best->km.dying == x->km.dying && 8051da177e4SLinus Torvalds best->curlft.add_time < x->curlft.add_time)) 8061da177e4SLinus Torvalds best = x; 8071da177e4SLinus Torvalds } else if (x->km.state == XFRM_STATE_ACQ) { 8081da177e4SLinus Torvalds acquire_in_progress = 1; 8091da177e4SLinus Torvalds } else if (x->km.state == XFRM_STATE_ERROR || 8101da177e4SLinus Torvalds x->km.state == XFRM_STATE_EXPIRED) { 81148b8d783SJoakim Koskela if (xfrm_selector_match(&x->sel, fl, x->sel.family) && 812e0d1caa7SVenkat Yekkirala security_xfrm_state_pol_flow_match(x, pol, fl)) 8131da177e4SLinus Torvalds error = -ESRCH; 8141da177e4SLinus Torvalds } 8151da177e4SLinus Torvalds } 8161da177e4SLinus Torvalds } 8171da177e4SLinus Torvalds 8181da177e4SLinus Torvalds x = best; 8191da177e4SLinus Torvalds if (!x && !error && !acquire_in_progress) { 8205c5d281aSPatrick McHardy if (tmpl->id.spi && 821edcd5821SDavid S. Miller (x0 = __xfrm_state_lookup(daddr, tmpl->id.spi, 822edcd5821SDavid S. Miller tmpl->id.proto, family)) != NULL) { 8231da177e4SLinus Torvalds xfrm_state_put(x0); 8241da177e4SLinus Torvalds error = -EEXIST; 8251da177e4SLinus Torvalds goto out; 8261da177e4SLinus Torvalds } 8271da177e4SLinus Torvalds x = xfrm_state_alloc(); 8281da177e4SLinus Torvalds if (x == NULL) { 8291da177e4SLinus Torvalds error = -ENOMEM; 8301da177e4SLinus Torvalds goto out; 8311da177e4SLinus Torvalds } 8321da177e4SLinus Torvalds /* Initialize temporary selector matching only 8331da177e4SLinus Torvalds * to current session. */ 8341da177e4SLinus Torvalds xfrm_init_tempsel(x, fl, tmpl, daddr, saddr, family); 8351da177e4SLinus Torvalds 836e0d1caa7SVenkat Yekkirala error = security_xfrm_state_alloc_acquire(x, pol->security, fl->secid); 837e0d1caa7SVenkat Yekkirala if (error) { 838e0d1caa7SVenkat Yekkirala x->km.state = XFRM_STATE_DEAD; 839e0d1caa7SVenkat Yekkirala xfrm_state_put(x); 840e0d1caa7SVenkat Yekkirala x = NULL; 841e0d1caa7SVenkat Yekkirala goto out; 842e0d1caa7SVenkat Yekkirala } 843e0d1caa7SVenkat Yekkirala 8441da177e4SLinus Torvalds if (km_query(x, tmpl, pol) == 0) { 8451da177e4SLinus Torvalds x->km.state = XFRM_STATE_ACQ; 8468f126e37SDavid S. Miller hlist_add_head(&x->bydst, xfrm_state_bydst+h); 847667bbcb6SMasahide NAKAMURA h = xfrm_src_hash(daddr, saddr, family); 8488f126e37SDavid S. Miller hlist_add_head(&x->bysrc, xfrm_state_bysrc+h); 8491da177e4SLinus Torvalds if (x->id.spi) { 8501da177e4SLinus Torvalds h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, family); 8518f126e37SDavid S. Miller hlist_add_head(&x->byspi, xfrm_state_byspi+h); 8521da177e4SLinus Torvalds } 85301e67d08SDavid S. Miller x->lft.hard_add_expires_seconds = sysctl_xfrm_acq_expires; 85401e67d08SDavid S. Miller x->timer.expires = jiffies + sysctl_xfrm_acq_expires*HZ; 8551da177e4SLinus Torvalds add_timer(&x->timer); 8562fab22f2SPatrick McHardy xfrm_state_num++; 8572fab22f2SPatrick McHardy xfrm_hash_grow_check(x->bydst.next != NULL); 8581da177e4SLinus Torvalds } else { 8591da177e4SLinus Torvalds x->km.state = XFRM_STATE_DEAD; 8601da177e4SLinus Torvalds xfrm_state_put(x); 8611da177e4SLinus Torvalds x = NULL; 8621da177e4SLinus Torvalds error = -ESRCH; 8631da177e4SLinus Torvalds } 8641da177e4SLinus Torvalds } 8651da177e4SLinus Torvalds out: 8661da177e4SLinus Torvalds if (x) 8671da177e4SLinus Torvalds xfrm_state_hold(x); 8681da177e4SLinus Torvalds else 8691da177e4SLinus Torvalds *err = acquire_in_progress ? -EAGAIN : error; 8701da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_lock); 8711da177e4SLinus Torvalds return x; 8721da177e4SLinus Torvalds } 8731da177e4SLinus Torvalds 874628529b6SJamal Hadi Salim struct xfrm_state * 875628529b6SJamal Hadi Salim xfrm_stateonly_find(xfrm_address_t *daddr, xfrm_address_t *saddr, 876628529b6SJamal Hadi Salim unsigned short family, u8 mode, u8 proto, u32 reqid) 877628529b6SJamal Hadi Salim { 8784bda4f25SPavel Emelyanov unsigned int h; 879628529b6SJamal Hadi Salim struct xfrm_state *rx = NULL, *x = NULL; 880628529b6SJamal Hadi Salim struct hlist_node *entry; 881628529b6SJamal Hadi Salim 882628529b6SJamal Hadi Salim spin_lock(&xfrm_state_lock); 8834bda4f25SPavel Emelyanov h = xfrm_dst_hash(daddr, saddr, reqid, family); 884628529b6SJamal Hadi Salim hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) { 885628529b6SJamal Hadi Salim if (x->props.family == family && 886628529b6SJamal Hadi Salim x->props.reqid == reqid && 887628529b6SJamal Hadi Salim !(x->props.flags & XFRM_STATE_WILDRECV) && 888628529b6SJamal Hadi Salim xfrm_state_addr_check(x, daddr, saddr, family) && 889628529b6SJamal Hadi Salim mode == x->props.mode && 890628529b6SJamal Hadi Salim proto == x->id.proto && 891628529b6SJamal Hadi Salim x->km.state == XFRM_STATE_VALID) { 892628529b6SJamal Hadi Salim rx = x; 893628529b6SJamal Hadi Salim break; 894628529b6SJamal Hadi Salim } 895628529b6SJamal Hadi Salim } 896628529b6SJamal Hadi Salim 897628529b6SJamal Hadi Salim if (rx) 898628529b6SJamal Hadi Salim xfrm_state_hold(rx); 899628529b6SJamal Hadi Salim spin_unlock(&xfrm_state_lock); 900628529b6SJamal Hadi Salim 901628529b6SJamal Hadi Salim 902628529b6SJamal Hadi Salim return rx; 903628529b6SJamal Hadi Salim } 904628529b6SJamal Hadi Salim EXPORT_SYMBOL(xfrm_stateonly_find); 905628529b6SJamal Hadi Salim 9061da177e4SLinus Torvalds static void __xfrm_state_insert(struct xfrm_state *x) 9071da177e4SLinus Torvalds { 908a624c108SDavid S. Miller unsigned int h; 9091da177e4SLinus Torvalds 9109d4a706dSDavid S. Miller x->genid = ++xfrm_state_genid; 9119d4a706dSDavid S. Miller 912c1969f29SDavid S. Miller h = xfrm_dst_hash(&x->id.daddr, &x->props.saddr, 913c1969f29SDavid S. Miller x->props.reqid, x->props.family); 9148f126e37SDavid S. Miller hlist_add_head(&x->bydst, xfrm_state_bydst+h); 9151da177e4SLinus Torvalds 916667bbcb6SMasahide NAKAMURA h = xfrm_src_hash(&x->id.daddr, &x->props.saddr, x->props.family); 9178f126e37SDavid S. Miller hlist_add_head(&x->bysrc, xfrm_state_bysrc+h); 9186c44e6b7SMasahide NAKAMURA 9197b4dc360SMasahide NAKAMURA if (x->id.spi) { 9206c44e6b7SMasahide NAKAMURA h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, 9216c44e6b7SMasahide NAKAMURA x->props.family); 9221da177e4SLinus Torvalds 9238f126e37SDavid S. Miller hlist_add_head(&x->byspi, xfrm_state_byspi+h); 9246c44e6b7SMasahide NAKAMURA } 9251da177e4SLinus Torvalds 926a47f0ce0SDavid S. Miller mod_timer(&x->timer, jiffies + HZ); 927a47f0ce0SDavid S. Miller if (x->replay_maxage) 928a47f0ce0SDavid S. Miller mod_timer(&x->rtimer, jiffies + x->replay_maxage); 929f8cd5488SJamal Hadi Salim 9301da177e4SLinus Torvalds wake_up(&km_waitq); 931f034b5d4SDavid S. Miller 932f034b5d4SDavid S. Miller xfrm_state_num++; 933f034b5d4SDavid S. Miller 934918049f0SDavid S. Miller xfrm_hash_grow_check(x->bydst.next != NULL); 9351da177e4SLinus Torvalds } 9361da177e4SLinus Torvalds 937c7f5ea3aSDavid S. Miller /* xfrm_state_lock is held */ 938c7f5ea3aSDavid S. Miller static void __xfrm_state_bump_genids(struct xfrm_state *xnew) 939c7f5ea3aSDavid S. Miller { 940c7f5ea3aSDavid S. Miller unsigned short family = xnew->props.family; 941c7f5ea3aSDavid S. Miller u32 reqid = xnew->props.reqid; 942c7f5ea3aSDavid S. Miller struct xfrm_state *x; 943c7f5ea3aSDavid S. Miller struct hlist_node *entry; 944c7f5ea3aSDavid S. Miller unsigned int h; 945c7f5ea3aSDavid S. Miller 946c1969f29SDavid S. Miller h = xfrm_dst_hash(&xnew->id.daddr, &xnew->props.saddr, reqid, family); 947c7f5ea3aSDavid S. Miller hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) { 948c7f5ea3aSDavid S. Miller if (x->props.family == family && 949c7f5ea3aSDavid S. Miller x->props.reqid == reqid && 950c1969f29SDavid S. Miller !xfrm_addr_cmp(&x->id.daddr, &xnew->id.daddr, family) && 951c1969f29SDavid S. Miller !xfrm_addr_cmp(&x->props.saddr, &xnew->props.saddr, family)) 952c7f5ea3aSDavid S. Miller x->genid = xfrm_state_genid; 953c7f5ea3aSDavid S. Miller } 954c7f5ea3aSDavid S. Miller } 955c7f5ea3aSDavid S. Miller 9561da177e4SLinus Torvalds void xfrm_state_insert(struct xfrm_state *x) 9571da177e4SLinus Torvalds { 9581da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_lock); 959c7f5ea3aSDavid S. Miller __xfrm_state_bump_genids(x); 9601da177e4SLinus Torvalds __xfrm_state_insert(x); 9611da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_lock); 9621da177e4SLinus Torvalds } 9631da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_insert); 9641da177e4SLinus Torvalds 9652770834cSDavid S. Miller /* xfrm_state_lock is held */ 9662770834cSDavid 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) 9672770834cSDavid S. Miller { 968c1969f29SDavid S. Miller unsigned int h = xfrm_dst_hash(daddr, saddr, reqid, family); 9698f126e37SDavid S. Miller struct hlist_node *entry; 9702770834cSDavid S. Miller struct xfrm_state *x; 9712770834cSDavid S. Miller 9728f126e37SDavid S. Miller hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) { 9732770834cSDavid S. Miller if (x->props.reqid != reqid || 9742770834cSDavid S. Miller x->props.mode != mode || 9752770834cSDavid S. Miller x->props.family != family || 9762770834cSDavid S. Miller x->km.state != XFRM_STATE_ACQ || 97775e252d9SJoy Latten x->id.spi != 0 || 97875e252d9SJoy Latten x->id.proto != proto) 9792770834cSDavid S. Miller continue; 9802770834cSDavid S. Miller 9812770834cSDavid S. Miller switch (family) { 9822770834cSDavid S. Miller case AF_INET: 9832770834cSDavid S. Miller if (x->id.daddr.a4 != daddr->a4 || 9842770834cSDavid S. Miller x->props.saddr.a4 != saddr->a4) 9852770834cSDavid S. Miller continue; 9862770834cSDavid S. Miller break; 9872770834cSDavid S. Miller case AF_INET6: 9882770834cSDavid S. Miller if (!ipv6_addr_equal((struct in6_addr *)x->id.daddr.a6, 9892770834cSDavid S. Miller (struct in6_addr *)daddr) || 9902770834cSDavid S. Miller !ipv6_addr_equal((struct in6_addr *) 9912770834cSDavid S. Miller x->props.saddr.a6, 9922770834cSDavid S. Miller (struct in6_addr *)saddr)) 9932770834cSDavid S. Miller continue; 9942770834cSDavid S. Miller break; 9953ff50b79SStephen Hemminger } 9962770834cSDavid S. Miller 9972770834cSDavid S. Miller xfrm_state_hold(x); 9982770834cSDavid S. Miller return x; 9992770834cSDavid S. Miller } 10002770834cSDavid S. Miller 10012770834cSDavid S. Miller if (!create) 10022770834cSDavid S. Miller return NULL; 10032770834cSDavid S. Miller 10042770834cSDavid S. Miller x = xfrm_state_alloc(); 10052770834cSDavid S. Miller if (likely(x)) { 10062770834cSDavid S. Miller switch (family) { 10072770834cSDavid S. Miller case AF_INET: 10082770834cSDavid S. Miller x->sel.daddr.a4 = daddr->a4; 10092770834cSDavid S. Miller x->sel.saddr.a4 = saddr->a4; 10102770834cSDavid S. Miller x->sel.prefixlen_d = 32; 10112770834cSDavid S. Miller x->sel.prefixlen_s = 32; 10122770834cSDavid S. Miller x->props.saddr.a4 = saddr->a4; 10132770834cSDavid S. Miller x->id.daddr.a4 = daddr->a4; 10142770834cSDavid S. Miller break; 10152770834cSDavid S. Miller 10162770834cSDavid S. Miller case AF_INET6: 10172770834cSDavid S. Miller ipv6_addr_copy((struct in6_addr *)x->sel.daddr.a6, 10182770834cSDavid S. Miller (struct in6_addr *)daddr); 10192770834cSDavid S. Miller ipv6_addr_copy((struct in6_addr *)x->sel.saddr.a6, 10202770834cSDavid S. Miller (struct in6_addr *)saddr); 10212770834cSDavid S. Miller x->sel.prefixlen_d = 128; 10222770834cSDavid S. Miller x->sel.prefixlen_s = 128; 10232770834cSDavid S. Miller ipv6_addr_copy((struct in6_addr *)x->props.saddr.a6, 10242770834cSDavid S. Miller (struct in6_addr *)saddr); 10252770834cSDavid S. Miller ipv6_addr_copy((struct in6_addr *)x->id.daddr.a6, 10262770834cSDavid S. Miller (struct in6_addr *)daddr); 10272770834cSDavid S. Miller break; 10283ff50b79SStephen Hemminger } 10292770834cSDavid S. Miller 10302770834cSDavid S. Miller x->km.state = XFRM_STATE_ACQ; 10312770834cSDavid S. Miller x->id.proto = proto; 10322770834cSDavid S. Miller x->props.family = family; 10332770834cSDavid S. Miller x->props.mode = mode; 10342770834cSDavid S. Miller x->props.reqid = reqid; 103501e67d08SDavid S. Miller x->lft.hard_add_expires_seconds = sysctl_xfrm_acq_expires; 10362770834cSDavid S. Miller xfrm_state_hold(x); 103701e67d08SDavid S. Miller x->timer.expires = jiffies + sysctl_xfrm_acq_expires*HZ; 10382770834cSDavid S. Miller add_timer(&x->timer); 10398f126e37SDavid S. Miller hlist_add_head(&x->bydst, xfrm_state_bydst+h); 1040667bbcb6SMasahide NAKAMURA h = xfrm_src_hash(daddr, saddr, family); 10418f126e37SDavid S. Miller hlist_add_head(&x->bysrc, xfrm_state_bysrc+h); 1042918049f0SDavid S. Miller 1043918049f0SDavid S. Miller xfrm_state_num++; 1044918049f0SDavid S. Miller 1045918049f0SDavid S. Miller xfrm_hash_grow_check(x->bydst.next != NULL); 10462770834cSDavid S. Miller } 10472770834cSDavid S. Miller 10482770834cSDavid S. Miller return x; 10492770834cSDavid S. Miller } 10502770834cSDavid S. Miller 10511da177e4SLinus Torvalds static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq); 10521da177e4SLinus Torvalds 10531da177e4SLinus Torvalds int xfrm_state_add(struct xfrm_state *x) 10541da177e4SLinus Torvalds { 10551da177e4SLinus Torvalds struct xfrm_state *x1; 10561da177e4SLinus Torvalds int family; 10571da177e4SLinus Torvalds int err; 1058eb2971b6SMasahide NAKAMURA int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY); 10591da177e4SLinus Torvalds 10601da177e4SLinus Torvalds family = x->props.family; 10611da177e4SLinus Torvalds 10621da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_lock); 10631da177e4SLinus Torvalds 1064edcd5821SDavid S. Miller x1 = __xfrm_state_locate(x, use_spi, family); 10651da177e4SLinus Torvalds if (x1) { 10661da177e4SLinus Torvalds xfrm_state_put(x1); 10671da177e4SLinus Torvalds x1 = NULL; 10681da177e4SLinus Torvalds err = -EEXIST; 10691da177e4SLinus Torvalds goto out; 10701da177e4SLinus Torvalds } 10711da177e4SLinus Torvalds 1072eb2971b6SMasahide NAKAMURA if (use_spi && x->km.seq) { 10731da177e4SLinus Torvalds x1 = __xfrm_find_acq_byseq(x->km.seq); 107475e252d9SJoy Latten if (x1 && ((x1->id.proto != x->id.proto) || 107575e252d9SJoy Latten xfrm_addr_cmp(&x1->id.daddr, &x->id.daddr, family))) { 10761da177e4SLinus Torvalds xfrm_state_put(x1); 10771da177e4SLinus Torvalds x1 = NULL; 10781da177e4SLinus Torvalds } 10791da177e4SLinus Torvalds } 10801da177e4SLinus Torvalds 1081eb2971b6SMasahide NAKAMURA if (use_spi && !x1) 10822770834cSDavid S. Miller x1 = __find_acq_core(family, x->props.mode, x->props.reqid, 10832770834cSDavid S. Miller x->id.proto, 10841da177e4SLinus Torvalds &x->id.daddr, &x->props.saddr, 0); 10851da177e4SLinus Torvalds 1086c7f5ea3aSDavid S. Miller __xfrm_state_bump_genids(x); 10871da177e4SLinus Torvalds __xfrm_state_insert(x); 10881da177e4SLinus Torvalds err = 0; 10891da177e4SLinus Torvalds 10901da177e4SLinus Torvalds out: 10911da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_lock); 10921da177e4SLinus Torvalds 10931da177e4SLinus Torvalds if (x1) { 10941da177e4SLinus Torvalds xfrm_state_delete(x1); 10951da177e4SLinus Torvalds xfrm_state_put(x1); 10961da177e4SLinus Torvalds } 10971da177e4SLinus Torvalds 10981da177e4SLinus Torvalds return err; 10991da177e4SLinus Torvalds } 11001da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_add); 11011da177e4SLinus Torvalds 110280c9abaaSShinta Sugimoto #ifdef CONFIG_XFRM_MIGRATE 110380c9abaaSShinta Sugimoto struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp) 110480c9abaaSShinta Sugimoto { 110580c9abaaSShinta Sugimoto int err = -ENOMEM; 110680c9abaaSShinta Sugimoto struct xfrm_state *x = xfrm_state_alloc(); 110780c9abaaSShinta Sugimoto if (!x) 110880c9abaaSShinta Sugimoto goto error; 110980c9abaaSShinta Sugimoto 111080c9abaaSShinta Sugimoto memcpy(&x->id, &orig->id, sizeof(x->id)); 111180c9abaaSShinta Sugimoto memcpy(&x->sel, &orig->sel, sizeof(x->sel)); 111280c9abaaSShinta Sugimoto memcpy(&x->lft, &orig->lft, sizeof(x->lft)); 111380c9abaaSShinta Sugimoto x->props.mode = orig->props.mode; 111480c9abaaSShinta Sugimoto x->props.replay_window = orig->props.replay_window; 111580c9abaaSShinta Sugimoto x->props.reqid = orig->props.reqid; 111680c9abaaSShinta Sugimoto x->props.family = orig->props.family; 111780c9abaaSShinta Sugimoto x->props.saddr = orig->props.saddr; 111880c9abaaSShinta Sugimoto 111980c9abaaSShinta Sugimoto if (orig->aalg) { 112080c9abaaSShinta Sugimoto x->aalg = xfrm_algo_clone(orig->aalg); 112180c9abaaSShinta Sugimoto if (!x->aalg) 112280c9abaaSShinta Sugimoto goto error; 112380c9abaaSShinta Sugimoto } 112480c9abaaSShinta Sugimoto x->props.aalgo = orig->props.aalgo; 112580c9abaaSShinta Sugimoto 112680c9abaaSShinta Sugimoto if (orig->ealg) { 112780c9abaaSShinta Sugimoto x->ealg = xfrm_algo_clone(orig->ealg); 112880c9abaaSShinta Sugimoto if (!x->ealg) 112980c9abaaSShinta Sugimoto goto error; 113080c9abaaSShinta Sugimoto } 113180c9abaaSShinta Sugimoto x->props.ealgo = orig->props.ealgo; 113280c9abaaSShinta Sugimoto 113380c9abaaSShinta Sugimoto if (orig->calg) { 113480c9abaaSShinta Sugimoto x->calg = xfrm_algo_clone(orig->calg); 113580c9abaaSShinta Sugimoto if (!x->calg) 113680c9abaaSShinta Sugimoto goto error; 113780c9abaaSShinta Sugimoto } 113880c9abaaSShinta Sugimoto x->props.calgo = orig->props.calgo; 113980c9abaaSShinta Sugimoto 114080c9abaaSShinta Sugimoto if (orig->encap) { 114180c9abaaSShinta Sugimoto x->encap = kmemdup(orig->encap, sizeof(*x->encap), GFP_KERNEL); 114280c9abaaSShinta Sugimoto if (!x->encap) 114380c9abaaSShinta Sugimoto goto error; 114480c9abaaSShinta Sugimoto } 114580c9abaaSShinta Sugimoto 114680c9abaaSShinta Sugimoto if (orig->coaddr) { 114780c9abaaSShinta Sugimoto x->coaddr = kmemdup(orig->coaddr, sizeof(*x->coaddr), 114880c9abaaSShinta Sugimoto GFP_KERNEL); 114980c9abaaSShinta Sugimoto if (!x->coaddr) 115080c9abaaSShinta Sugimoto goto error; 115180c9abaaSShinta Sugimoto } 115280c9abaaSShinta Sugimoto 115380c9abaaSShinta Sugimoto err = xfrm_init_state(x); 115480c9abaaSShinta Sugimoto if (err) 115580c9abaaSShinta Sugimoto goto error; 115680c9abaaSShinta Sugimoto 115780c9abaaSShinta Sugimoto x->props.flags = orig->props.flags; 115880c9abaaSShinta Sugimoto 115980c9abaaSShinta Sugimoto x->curlft.add_time = orig->curlft.add_time; 116080c9abaaSShinta Sugimoto x->km.state = orig->km.state; 116180c9abaaSShinta Sugimoto x->km.seq = orig->km.seq; 116280c9abaaSShinta Sugimoto 116380c9abaaSShinta Sugimoto return x; 116480c9abaaSShinta Sugimoto 116580c9abaaSShinta Sugimoto error: 116680c9abaaSShinta Sugimoto if (errp) 116780c9abaaSShinta Sugimoto *errp = err; 116880c9abaaSShinta Sugimoto if (x) { 116980c9abaaSShinta Sugimoto kfree(x->aalg); 117080c9abaaSShinta Sugimoto kfree(x->ealg); 117180c9abaaSShinta Sugimoto kfree(x->calg); 117280c9abaaSShinta Sugimoto kfree(x->encap); 117380c9abaaSShinta Sugimoto kfree(x->coaddr); 117480c9abaaSShinta Sugimoto } 117580c9abaaSShinta Sugimoto kfree(x); 117680c9abaaSShinta Sugimoto return NULL; 117780c9abaaSShinta Sugimoto } 117880c9abaaSShinta Sugimoto EXPORT_SYMBOL(xfrm_state_clone); 117980c9abaaSShinta Sugimoto 118080c9abaaSShinta Sugimoto /* xfrm_state_lock is held */ 118180c9abaaSShinta Sugimoto struct xfrm_state * xfrm_migrate_state_find(struct xfrm_migrate *m) 118280c9abaaSShinta Sugimoto { 118380c9abaaSShinta Sugimoto unsigned int h; 118480c9abaaSShinta Sugimoto struct xfrm_state *x; 118580c9abaaSShinta Sugimoto struct hlist_node *entry; 118680c9abaaSShinta Sugimoto 118780c9abaaSShinta Sugimoto if (m->reqid) { 118880c9abaaSShinta Sugimoto h = xfrm_dst_hash(&m->old_daddr, &m->old_saddr, 118980c9abaaSShinta Sugimoto m->reqid, m->old_family); 119080c9abaaSShinta Sugimoto hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) { 119180c9abaaSShinta Sugimoto if (x->props.mode != m->mode || 119280c9abaaSShinta Sugimoto x->id.proto != m->proto) 119380c9abaaSShinta Sugimoto continue; 119480c9abaaSShinta Sugimoto if (m->reqid && x->props.reqid != m->reqid) 119580c9abaaSShinta Sugimoto continue; 119680c9abaaSShinta Sugimoto if (xfrm_addr_cmp(&x->id.daddr, &m->old_daddr, 119780c9abaaSShinta Sugimoto m->old_family) || 119880c9abaaSShinta Sugimoto xfrm_addr_cmp(&x->props.saddr, &m->old_saddr, 119980c9abaaSShinta Sugimoto m->old_family)) 120080c9abaaSShinta Sugimoto continue; 120180c9abaaSShinta Sugimoto xfrm_state_hold(x); 120280c9abaaSShinta Sugimoto return x; 120380c9abaaSShinta Sugimoto } 120480c9abaaSShinta Sugimoto } else { 120580c9abaaSShinta Sugimoto h = xfrm_src_hash(&m->old_daddr, &m->old_saddr, 120680c9abaaSShinta Sugimoto m->old_family); 120780c9abaaSShinta Sugimoto hlist_for_each_entry(x, entry, xfrm_state_bysrc+h, bysrc) { 120880c9abaaSShinta Sugimoto if (x->props.mode != m->mode || 120980c9abaaSShinta Sugimoto x->id.proto != m->proto) 121080c9abaaSShinta Sugimoto continue; 121180c9abaaSShinta Sugimoto if (xfrm_addr_cmp(&x->id.daddr, &m->old_daddr, 121280c9abaaSShinta Sugimoto m->old_family) || 121380c9abaaSShinta Sugimoto xfrm_addr_cmp(&x->props.saddr, &m->old_saddr, 121480c9abaaSShinta Sugimoto m->old_family)) 121580c9abaaSShinta Sugimoto continue; 121680c9abaaSShinta Sugimoto xfrm_state_hold(x); 121780c9abaaSShinta Sugimoto return x; 121880c9abaaSShinta Sugimoto } 121980c9abaaSShinta Sugimoto } 122080c9abaaSShinta Sugimoto 122180c9abaaSShinta Sugimoto return NULL; 122280c9abaaSShinta Sugimoto } 122380c9abaaSShinta Sugimoto EXPORT_SYMBOL(xfrm_migrate_state_find); 122480c9abaaSShinta Sugimoto 122580c9abaaSShinta Sugimoto struct xfrm_state * xfrm_state_migrate(struct xfrm_state *x, 122680c9abaaSShinta Sugimoto struct xfrm_migrate *m) 122780c9abaaSShinta Sugimoto { 122880c9abaaSShinta Sugimoto struct xfrm_state *xc; 122980c9abaaSShinta Sugimoto int err; 123080c9abaaSShinta Sugimoto 123180c9abaaSShinta Sugimoto xc = xfrm_state_clone(x, &err); 123280c9abaaSShinta Sugimoto if (!xc) 123380c9abaaSShinta Sugimoto return NULL; 123480c9abaaSShinta Sugimoto 123580c9abaaSShinta Sugimoto memcpy(&xc->id.daddr, &m->new_daddr, sizeof(xc->id.daddr)); 123680c9abaaSShinta Sugimoto memcpy(&xc->props.saddr, &m->new_saddr, sizeof(xc->props.saddr)); 123780c9abaaSShinta Sugimoto 123880c9abaaSShinta Sugimoto /* add state */ 123980c9abaaSShinta Sugimoto if (!xfrm_addr_cmp(&x->id.daddr, &m->new_daddr, m->new_family)) { 124080c9abaaSShinta Sugimoto /* a care is needed when the destination address of the 124180c9abaaSShinta Sugimoto state is to be updated as it is a part of triplet */ 124280c9abaaSShinta Sugimoto xfrm_state_insert(xc); 124380c9abaaSShinta Sugimoto } else { 124480c9abaaSShinta Sugimoto if ((err = xfrm_state_add(xc)) < 0) 124580c9abaaSShinta Sugimoto goto error; 124680c9abaaSShinta Sugimoto } 124780c9abaaSShinta Sugimoto 124880c9abaaSShinta Sugimoto return xc; 124980c9abaaSShinta Sugimoto error: 125080c9abaaSShinta Sugimoto kfree(xc); 125180c9abaaSShinta Sugimoto return NULL; 125280c9abaaSShinta Sugimoto } 125380c9abaaSShinta Sugimoto EXPORT_SYMBOL(xfrm_state_migrate); 125480c9abaaSShinta Sugimoto #endif 125580c9abaaSShinta Sugimoto 12561da177e4SLinus Torvalds int xfrm_state_update(struct xfrm_state *x) 12571da177e4SLinus Torvalds { 12581da177e4SLinus Torvalds struct xfrm_state *x1; 12591da177e4SLinus Torvalds int err; 1260eb2971b6SMasahide NAKAMURA int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY); 12611da177e4SLinus Torvalds 12621da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_lock); 1263edcd5821SDavid S. Miller x1 = __xfrm_state_locate(x, use_spi, x->props.family); 12641da177e4SLinus Torvalds 12651da177e4SLinus Torvalds err = -ESRCH; 12661da177e4SLinus Torvalds if (!x1) 12671da177e4SLinus Torvalds goto out; 12681da177e4SLinus Torvalds 12691da177e4SLinus Torvalds if (xfrm_state_kern(x1)) { 12701da177e4SLinus Torvalds xfrm_state_put(x1); 12711da177e4SLinus Torvalds err = -EEXIST; 12721da177e4SLinus Torvalds goto out; 12731da177e4SLinus Torvalds } 12741da177e4SLinus Torvalds 12751da177e4SLinus Torvalds if (x1->km.state == XFRM_STATE_ACQ) { 12761da177e4SLinus Torvalds __xfrm_state_insert(x); 12771da177e4SLinus Torvalds x = NULL; 12781da177e4SLinus Torvalds } 12791da177e4SLinus Torvalds err = 0; 12801da177e4SLinus Torvalds 12811da177e4SLinus Torvalds out: 12821da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_lock); 12831da177e4SLinus Torvalds 12841da177e4SLinus Torvalds if (err) 12851da177e4SLinus Torvalds return err; 12861da177e4SLinus Torvalds 12871da177e4SLinus Torvalds if (!x) { 12881da177e4SLinus Torvalds xfrm_state_delete(x1); 12891da177e4SLinus Torvalds xfrm_state_put(x1); 12901da177e4SLinus Torvalds return 0; 12911da177e4SLinus Torvalds } 12921da177e4SLinus Torvalds 12931da177e4SLinus Torvalds err = -EINVAL; 12941da177e4SLinus Torvalds spin_lock_bh(&x1->lock); 12951da177e4SLinus Torvalds if (likely(x1->km.state == XFRM_STATE_VALID)) { 12961da177e4SLinus Torvalds if (x->encap && x1->encap) 12971da177e4SLinus Torvalds memcpy(x1->encap, x->encap, sizeof(*x1->encap)); 1298060f02a3SNoriaki TAKAMIYA if (x->coaddr && x1->coaddr) { 1299060f02a3SNoriaki TAKAMIYA memcpy(x1->coaddr, x->coaddr, sizeof(*x1->coaddr)); 1300060f02a3SNoriaki TAKAMIYA } 1301060f02a3SNoriaki TAKAMIYA if (!use_spi && memcmp(&x1->sel, &x->sel, sizeof(x1->sel))) 1302060f02a3SNoriaki TAKAMIYA memcpy(&x1->sel, &x->sel, sizeof(x1->sel)); 13031da177e4SLinus Torvalds memcpy(&x1->lft, &x->lft, sizeof(x1->lft)); 13041da177e4SLinus Torvalds x1->km.dying = 0; 13051da177e4SLinus Torvalds 1306a47f0ce0SDavid S. Miller mod_timer(&x1->timer, jiffies + HZ); 13071da177e4SLinus Torvalds if (x1->curlft.use_time) 13081da177e4SLinus Torvalds xfrm_state_check_expire(x1); 13091da177e4SLinus Torvalds 13101da177e4SLinus Torvalds err = 0; 13111da177e4SLinus Torvalds } 13121da177e4SLinus Torvalds spin_unlock_bh(&x1->lock); 13131da177e4SLinus Torvalds 13141da177e4SLinus Torvalds xfrm_state_put(x1); 13151da177e4SLinus Torvalds 13161da177e4SLinus Torvalds return err; 13171da177e4SLinus Torvalds } 13181da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_update); 13191da177e4SLinus Torvalds 13201da177e4SLinus Torvalds int xfrm_state_check_expire(struct xfrm_state *x) 13211da177e4SLinus Torvalds { 13221da177e4SLinus Torvalds if (!x->curlft.use_time) 13239d729f72SJames Morris x->curlft.use_time = get_seconds(); 13241da177e4SLinus Torvalds 13251da177e4SLinus Torvalds if (x->km.state != XFRM_STATE_VALID) 13261da177e4SLinus Torvalds return -EINVAL; 13271da177e4SLinus Torvalds 13281da177e4SLinus Torvalds if (x->curlft.bytes >= x->lft.hard_byte_limit || 13291da177e4SLinus Torvalds x->curlft.packets >= x->lft.hard_packet_limit) { 13304666faabSHerbert Xu x->km.state = XFRM_STATE_EXPIRED; 1331a47f0ce0SDavid S. Miller mod_timer(&x->timer, jiffies); 13321da177e4SLinus Torvalds return -EINVAL; 13331da177e4SLinus Torvalds } 13341da177e4SLinus Torvalds 13351da177e4SLinus Torvalds if (!x->km.dying && 13361da177e4SLinus Torvalds (x->curlft.bytes >= x->lft.soft_byte_limit || 13374666faabSHerbert Xu x->curlft.packets >= x->lft.soft_packet_limit)) { 13384666faabSHerbert Xu x->km.dying = 1; 133953bc6b4dSJamal Hadi Salim km_state_expired(x, 0, 0); 13404666faabSHerbert Xu } 13411da177e4SLinus Torvalds return 0; 13421da177e4SLinus Torvalds } 13431da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_check_expire); 13441da177e4SLinus Torvalds 13451da177e4SLinus Torvalds struct xfrm_state * 1346a94cfd19SAl Viro xfrm_state_lookup(xfrm_address_t *daddr, __be32 spi, u8 proto, 13471da177e4SLinus Torvalds unsigned short family) 13481da177e4SLinus Torvalds { 13491da177e4SLinus Torvalds struct xfrm_state *x; 13501da177e4SLinus Torvalds 13511da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_lock); 1352edcd5821SDavid S. Miller x = __xfrm_state_lookup(daddr, spi, proto, family); 13531da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_lock); 13541da177e4SLinus Torvalds return x; 13551da177e4SLinus Torvalds } 13561da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_lookup); 13571da177e4SLinus Torvalds 13581da177e4SLinus Torvalds struct xfrm_state * 1359eb2971b6SMasahide NAKAMURA xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr, 1360eb2971b6SMasahide NAKAMURA u8 proto, unsigned short family) 1361eb2971b6SMasahide NAKAMURA { 1362eb2971b6SMasahide NAKAMURA struct xfrm_state *x; 1363eb2971b6SMasahide NAKAMURA 1364eb2971b6SMasahide NAKAMURA spin_lock_bh(&xfrm_state_lock); 1365edcd5821SDavid S. Miller x = __xfrm_state_lookup_byaddr(daddr, saddr, proto, family); 1366eb2971b6SMasahide NAKAMURA spin_unlock_bh(&xfrm_state_lock); 1367eb2971b6SMasahide NAKAMURA return x; 1368eb2971b6SMasahide NAKAMURA } 1369eb2971b6SMasahide NAKAMURA EXPORT_SYMBOL(xfrm_state_lookup_byaddr); 1370eb2971b6SMasahide NAKAMURA 1371eb2971b6SMasahide NAKAMURA struct xfrm_state * 13721da177e4SLinus Torvalds xfrm_find_acq(u8 mode, u32 reqid, u8 proto, 13731da177e4SLinus Torvalds xfrm_address_t *daddr, xfrm_address_t *saddr, 13741da177e4SLinus Torvalds int create, unsigned short family) 13751da177e4SLinus Torvalds { 13761da177e4SLinus Torvalds struct xfrm_state *x; 13771da177e4SLinus Torvalds 13781da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_lock); 13792770834cSDavid S. Miller x = __find_acq_core(family, mode, reqid, proto, daddr, saddr, create); 13801da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_lock); 13812770834cSDavid S. Miller 13821da177e4SLinus Torvalds return x; 13831da177e4SLinus Torvalds } 13841da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_find_acq); 13851da177e4SLinus Torvalds 138641a49cc3SMasahide NAKAMURA #ifdef CONFIG_XFRM_SUB_POLICY 138741a49cc3SMasahide NAKAMURA int 138841a49cc3SMasahide NAKAMURA xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n, 138941a49cc3SMasahide NAKAMURA unsigned short family) 139041a49cc3SMasahide NAKAMURA { 139141a49cc3SMasahide NAKAMURA int err = 0; 139241a49cc3SMasahide NAKAMURA struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); 139341a49cc3SMasahide NAKAMURA if (!afinfo) 139441a49cc3SMasahide NAKAMURA return -EAFNOSUPPORT; 139541a49cc3SMasahide NAKAMURA 139641a49cc3SMasahide NAKAMURA spin_lock_bh(&xfrm_state_lock); 139741a49cc3SMasahide NAKAMURA if (afinfo->tmpl_sort) 139841a49cc3SMasahide NAKAMURA err = afinfo->tmpl_sort(dst, src, n); 139941a49cc3SMasahide NAKAMURA spin_unlock_bh(&xfrm_state_lock); 140041a49cc3SMasahide NAKAMURA xfrm_state_put_afinfo(afinfo); 140141a49cc3SMasahide NAKAMURA return err; 140241a49cc3SMasahide NAKAMURA } 140341a49cc3SMasahide NAKAMURA EXPORT_SYMBOL(xfrm_tmpl_sort); 140441a49cc3SMasahide NAKAMURA 140541a49cc3SMasahide NAKAMURA int 140641a49cc3SMasahide NAKAMURA xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n, 140741a49cc3SMasahide NAKAMURA unsigned short family) 140841a49cc3SMasahide NAKAMURA { 140941a49cc3SMasahide NAKAMURA int err = 0; 141041a49cc3SMasahide NAKAMURA struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); 141141a49cc3SMasahide NAKAMURA if (!afinfo) 141241a49cc3SMasahide NAKAMURA return -EAFNOSUPPORT; 141341a49cc3SMasahide NAKAMURA 141441a49cc3SMasahide NAKAMURA spin_lock_bh(&xfrm_state_lock); 141541a49cc3SMasahide NAKAMURA if (afinfo->state_sort) 141641a49cc3SMasahide NAKAMURA err = afinfo->state_sort(dst, src, n); 141741a49cc3SMasahide NAKAMURA spin_unlock_bh(&xfrm_state_lock); 141841a49cc3SMasahide NAKAMURA xfrm_state_put_afinfo(afinfo); 141941a49cc3SMasahide NAKAMURA return err; 142041a49cc3SMasahide NAKAMURA } 142141a49cc3SMasahide NAKAMURA EXPORT_SYMBOL(xfrm_state_sort); 142241a49cc3SMasahide NAKAMURA #endif 142341a49cc3SMasahide NAKAMURA 14241da177e4SLinus Torvalds /* Silly enough, but I'm lazy to build resolution list */ 14251da177e4SLinus Torvalds 14261da177e4SLinus Torvalds static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq) 14271da177e4SLinus Torvalds { 14281da177e4SLinus Torvalds int i; 14291da177e4SLinus Torvalds 1430f034b5d4SDavid S. Miller for (i = 0; i <= xfrm_state_hmask; i++) { 14318f126e37SDavid S. Miller struct hlist_node *entry; 14328f126e37SDavid S. Miller struct xfrm_state *x; 14338f126e37SDavid S. Miller 14348f126e37SDavid S. Miller hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) { 14358f126e37SDavid S. Miller if (x->km.seq == seq && 14368f126e37SDavid S. Miller x->km.state == XFRM_STATE_ACQ) { 14371da177e4SLinus Torvalds xfrm_state_hold(x); 14381da177e4SLinus Torvalds return x; 14391da177e4SLinus Torvalds } 14401da177e4SLinus Torvalds } 14411da177e4SLinus Torvalds } 14421da177e4SLinus Torvalds return NULL; 14431da177e4SLinus Torvalds } 14441da177e4SLinus Torvalds 14451da177e4SLinus Torvalds struct xfrm_state *xfrm_find_acq_byseq(u32 seq) 14461da177e4SLinus Torvalds { 14471da177e4SLinus Torvalds struct xfrm_state *x; 14481da177e4SLinus Torvalds 14491da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_lock); 14501da177e4SLinus Torvalds x = __xfrm_find_acq_byseq(seq); 14511da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_lock); 14521da177e4SLinus Torvalds return x; 14531da177e4SLinus Torvalds } 14541da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_find_acq_byseq); 14551da177e4SLinus Torvalds 14561da177e4SLinus Torvalds u32 xfrm_get_acqseq(void) 14571da177e4SLinus Torvalds { 14581da177e4SLinus Torvalds u32 res; 14591da177e4SLinus Torvalds static u32 acqseq; 14601da177e4SLinus Torvalds static DEFINE_SPINLOCK(acqseq_lock); 14611da177e4SLinus Torvalds 14621da177e4SLinus Torvalds spin_lock_bh(&acqseq_lock); 14631da177e4SLinus Torvalds res = (++acqseq ? : ++acqseq); 14641da177e4SLinus Torvalds spin_unlock_bh(&acqseq_lock); 14651da177e4SLinus Torvalds return res; 14661da177e4SLinus Torvalds } 14671da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_get_acqseq); 14681da177e4SLinus Torvalds 1469658b219eSHerbert Xu int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high) 14701da177e4SLinus Torvalds { 1471f034b5d4SDavid S. Miller unsigned int h; 14721da177e4SLinus Torvalds struct xfrm_state *x0; 1473658b219eSHerbert Xu int err = -ENOENT; 1474658b219eSHerbert Xu __be32 minspi = htonl(low); 1475658b219eSHerbert Xu __be32 maxspi = htonl(high); 14761da177e4SLinus Torvalds 1477658b219eSHerbert Xu spin_lock_bh(&x->lock); 1478658b219eSHerbert Xu if (x->km.state == XFRM_STATE_DEAD) 1479658b219eSHerbert Xu goto unlock; 1480658b219eSHerbert Xu 1481658b219eSHerbert Xu err = 0; 14821da177e4SLinus Torvalds if (x->id.spi) 1483658b219eSHerbert Xu goto unlock; 1484658b219eSHerbert Xu 1485658b219eSHerbert Xu err = -ENOENT; 14861da177e4SLinus Torvalds 14871da177e4SLinus Torvalds if (minspi == maxspi) { 14881da177e4SLinus Torvalds x0 = xfrm_state_lookup(&x->id.daddr, minspi, x->id.proto, x->props.family); 14891da177e4SLinus Torvalds if (x0) { 14901da177e4SLinus Torvalds xfrm_state_put(x0); 1491658b219eSHerbert Xu goto unlock; 14921da177e4SLinus Torvalds } 14931da177e4SLinus Torvalds x->id.spi = minspi; 14941da177e4SLinus Torvalds } else { 14951da177e4SLinus Torvalds u32 spi = 0; 149626977b4eSAl Viro for (h=0; h<high-low+1; h++) { 149726977b4eSAl Viro spi = low + net_random()%(high-low+1); 14981da177e4SLinus Torvalds x0 = xfrm_state_lookup(&x->id.daddr, htonl(spi), x->id.proto, x->props.family); 14991da177e4SLinus Torvalds if (x0 == NULL) { 15001da177e4SLinus Torvalds x->id.spi = htonl(spi); 15011da177e4SLinus Torvalds break; 15021da177e4SLinus Torvalds } 15031da177e4SLinus Torvalds xfrm_state_put(x0); 15041da177e4SLinus Torvalds } 15051da177e4SLinus Torvalds } 15061da177e4SLinus Torvalds if (x->id.spi) { 15071da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_lock); 15081da177e4SLinus Torvalds h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, x->props.family); 15098f126e37SDavid S. Miller hlist_add_head(&x->byspi, xfrm_state_byspi+h); 15101da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_lock); 1511658b219eSHerbert Xu 1512658b219eSHerbert Xu err = 0; 15131da177e4SLinus Torvalds } 1514658b219eSHerbert Xu 1515658b219eSHerbert Xu unlock: 1516658b219eSHerbert Xu spin_unlock_bh(&x->lock); 1517658b219eSHerbert Xu 1518658b219eSHerbert Xu return err; 15191da177e4SLinus Torvalds } 15201da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_alloc_spi); 15211da177e4SLinus Torvalds 15221da177e4SLinus Torvalds int xfrm_state_walk(u8 proto, int (*func)(struct xfrm_state *, int, void*), 15231da177e4SLinus Torvalds void *data) 15241da177e4SLinus Torvalds { 15251da177e4SLinus Torvalds int i; 152694b9bb54SJamal Hadi Salim struct xfrm_state *x, *last = NULL; 15278f126e37SDavid S. Miller struct hlist_node *entry; 15281da177e4SLinus Torvalds int count = 0; 15291da177e4SLinus Torvalds int err = 0; 15301da177e4SLinus Torvalds 15311da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_lock); 1532f034b5d4SDavid S. Miller for (i = 0; i <= xfrm_state_hmask; i++) { 15338f126e37SDavid S. Miller hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) { 153494b9bb54SJamal Hadi Salim if (!xfrm_id_proto_match(x->id.proto, proto)) 153594b9bb54SJamal Hadi Salim continue; 153694b9bb54SJamal Hadi Salim if (last) { 153794b9bb54SJamal Hadi Salim err = func(last, count, data); 153894b9bb54SJamal Hadi Salim if (err) 153994b9bb54SJamal Hadi Salim goto out; 154094b9bb54SJamal Hadi Salim } 154194b9bb54SJamal Hadi Salim last = x; 15421da177e4SLinus Torvalds count++; 15431da177e4SLinus Torvalds } 15441da177e4SLinus Torvalds } 15451da177e4SLinus Torvalds if (count == 0) { 15461da177e4SLinus Torvalds err = -ENOENT; 15471da177e4SLinus Torvalds goto out; 15481da177e4SLinus Torvalds } 154994b9bb54SJamal Hadi Salim err = func(last, 0, data); 15501da177e4SLinus Torvalds out: 15511da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_lock); 15521da177e4SLinus Torvalds return err; 15531da177e4SLinus Torvalds } 15541da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_walk); 15551da177e4SLinus Torvalds 1556f8cd5488SJamal Hadi Salim 1557f8cd5488SJamal Hadi Salim void xfrm_replay_notify(struct xfrm_state *x, int event) 1558f8cd5488SJamal Hadi Salim { 1559f8cd5488SJamal Hadi Salim struct km_event c; 1560f8cd5488SJamal Hadi Salim /* we send notify messages in case 1561f8cd5488SJamal Hadi Salim * 1. we updated on of the sequence numbers, and the seqno difference 1562f8cd5488SJamal Hadi Salim * is at least x->replay_maxdiff, in this case we also update the 1563f8cd5488SJamal Hadi Salim * timeout of our timer function 1564f8cd5488SJamal Hadi Salim * 2. if x->replay_maxage has elapsed since last update, 1565f8cd5488SJamal Hadi Salim * and there were changes 1566f8cd5488SJamal Hadi Salim * 1567f8cd5488SJamal Hadi Salim * The state structure must be locked! 1568f8cd5488SJamal Hadi Salim */ 1569f8cd5488SJamal Hadi Salim 1570f8cd5488SJamal Hadi Salim switch (event) { 1571f8cd5488SJamal Hadi Salim case XFRM_REPLAY_UPDATE: 1572f8cd5488SJamal Hadi Salim if (x->replay_maxdiff && 1573f8cd5488SJamal Hadi Salim (x->replay.seq - x->preplay.seq < x->replay_maxdiff) && 15742717096aSJamal Hadi Salim (x->replay.oseq - x->preplay.oseq < x->replay_maxdiff)) { 15752717096aSJamal Hadi Salim if (x->xflags & XFRM_TIME_DEFER) 15762717096aSJamal Hadi Salim event = XFRM_REPLAY_TIMEOUT; 15772717096aSJamal Hadi Salim else 1578f8cd5488SJamal Hadi Salim return; 15792717096aSJamal Hadi Salim } 1580f8cd5488SJamal Hadi Salim 1581f8cd5488SJamal Hadi Salim break; 1582f8cd5488SJamal Hadi Salim 1583f8cd5488SJamal Hadi Salim case XFRM_REPLAY_TIMEOUT: 1584f8cd5488SJamal Hadi Salim if ((x->replay.seq == x->preplay.seq) && 1585f8cd5488SJamal Hadi Salim (x->replay.bitmap == x->preplay.bitmap) && 15862717096aSJamal Hadi Salim (x->replay.oseq == x->preplay.oseq)) { 15872717096aSJamal Hadi Salim x->xflags |= XFRM_TIME_DEFER; 1588f8cd5488SJamal Hadi Salim return; 15892717096aSJamal Hadi Salim } 1590f8cd5488SJamal Hadi Salim 1591f8cd5488SJamal Hadi Salim break; 1592f8cd5488SJamal Hadi Salim } 1593f8cd5488SJamal Hadi Salim 1594f8cd5488SJamal Hadi Salim memcpy(&x->preplay, &x->replay, sizeof(struct xfrm_replay_state)); 1595f8cd5488SJamal Hadi Salim c.event = XFRM_MSG_NEWAE; 1596f8cd5488SJamal Hadi Salim c.data.aevent = event; 1597f8cd5488SJamal Hadi Salim km_state_notify(x, &c); 1598f8cd5488SJamal Hadi Salim 1599f8cd5488SJamal Hadi Salim if (x->replay_maxage && 1600a47f0ce0SDavid S. Miller !mod_timer(&x->rtimer, jiffies + x->replay_maxage)) 16012717096aSJamal Hadi Salim x->xflags &= ~XFRM_TIME_DEFER; 16022717096aSJamal Hadi Salim } 1603f8cd5488SJamal Hadi Salim 1604f8cd5488SJamal Hadi Salim static void xfrm_replay_timer_handler(unsigned long data) 1605f8cd5488SJamal Hadi Salim { 1606f8cd5488SJamal Hadi Salim struct xfrm_state *x = (struct xfrm_state*)data; 1607f8cd5488SJamal Hadi Salim 1608f8cd5488SJamal Hadi Salim spin_lock(&x->lock); 1609f8cd5488SJamal Hadi Salim 16102717096aSJamal Hadi Salim if (x->km.state == XFRM_STATE_VALID) { 16112717096aSJamal Hadi Salim if (xfrm_aevent_is_on()) 1612f8cd5488SJamal Hadi Salim xfrm_replay_notify(x, XFRM_REPLAY_TIMEOUT); 16132717096aSJamal Hadi Salim else 16142717096aSJamal Hadi Salim x->xflags |= XFRM_TIME_DEFER; 16152717096aSJamal Hadi Salim } 1616f8cd5488SJamal Hadi Salim 1617f8cd5488SJamal Hadi Salim spin_unlock(&x->lock); 1618f8cd5488SJamal Hadi Salim } 1619f8cd5488SJamal Hadi Salim 1620afeb14b4SPaul Moore int xfrm_replay_check(struct xfrm_state *x, 1621afeb14b4SPaul Moore struct sk_buff *skb, __be32 net_seq) 16221da177e4SLinus Torvalds { 16231da177e4SLinus Torvalds u32 diff; 1624a252cc23SAl Viro u32 seq = ntohl(net_seq); 16251da177e4SLinus Torvalds 16261da177e4SLinus Torvalds if (unlikely(seq == 0)) 1627afeb14b4SPaul Moore goto err; 16281da177e4SLinus Torvalds 16291da177e4SLinus Torvalds if (likely(seq > x->replay.seq)) 16301da177e4SLinus Torvalds return 0; 16311da177e4SLinus Torvalds 16321da177e4SLinus Torvalds diff = x->replay.seq - seq; 16334c4d51a7SHerbert Xu if (diff >= min_t(unsigned int, x->props.replay_window, 16344c4d51a7SHerbert Xu sizeof(x->replay.bitmap) * 8)) { 16351da177e4SLinus Torvalds x->stats.replay_window++; 1636afeb14b4SPaul Moore goto err; 16371da177e4SLinus Torvalds } 16381da177e4SLinus Torvalds 16391da177e4SLinus Torvalds if (x->replay.bitmap & (1U << diff)) { 16401da177e4SLinus Torvalds x->stats.replay++; 1641afeb14b4SPaul Moore goto err; 16421da177e4SLinus Torvalds } 16431da177e4SLinus Torvalds return 0; 1644afeb14b4SPaul Moore 1645afeb14b4SPaul Moore err: 1646afeb14b4SPaul Moore xfrm_audit_state_replay(x, skb, net_seq); 1647afeb14b4SPaul Moore return -EINVAL; 16481da177e4SLinus Torvalds } 16491da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_replay_check); 16501da177e4SLinus Torvalds 165161f4627bSAl Viro void xfrm_replay_advance(struct xfrm_state *x, __be32 net_seq) 16521da177e4SLinus Torvalds { 16531da177e4SLinus Torvalds u32 diff; 165461f4627bSAl Viro u32 seq = ntohl(net_seq); 16551da177e4SLinus Torvalds 16561da177e4SLinus Torvalds if (seq > x->replay.seq) { 16571da177e4SLinus Torvalds diff = seq - x->replay.seq; 16581da177e4SLinus Torvalds if (diff < x->props.replay_window) 16591da177e4SLinus Torvalds x->replay.bitmap = ((x->replay.bitmap) << diff) | 1; 16601da177e4SLinus Torvalds else 16611da177e4SLinus Torvalds x->replay.bitmap = 1; 16621da177e4SLinus Torvalds x->replay.seq = seq; 16631da177e4SLinus Torvalds } else { 16641da177e4SLinus Torvalds diff = x->replay.seq - seq; 16651da177e4SLinus Torvalds x->replay.bitmap |= (1U << diff); 16661da177e4SLinus Torvalds } 1667f8cd5488SJamal Hadi Salim 1668f8cd5488SJamal Hadi Salim if (xfrm_aevent_is_on()) 1669f8cd5488SJamal Hadi Salim xfrm_replay_notify(x, XFRM_REPLAY_UPDATE); 16701da177e4SLinus Torvalds } 16711da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_replay_advance); 16721da177e4SLinus Torvalds 1673df01812eSDenis Cheng static LIST_HEAD(xfrm_km_list); 16741da177e4SLinus Torvalds static DEFINE_RWLOCK(xfrm_km_lock); 16751da177e4SLinus Torvalds 167626b15dadSJamal Hadi Salim void km_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c) 16771da177e4SLinus Torvalds { 16781da177e4SLinus Torvalds struct xfrm_mgr *km; 16791da177e4SLinus Torvalds 168026b15dadSJamal Hadi Salim read_lock(&xfrm_km_lock); 168126b15dadSJamal Hadi Salim list_for_each_entry(km, &xfrm_km_list, list) 168226b15dadSJamal Hadi Salim if (km->notify_policy) 168326b15dadSJamal Hadi Salim km->notify_policy(xp, dir, c); 168426b15dadSJamal Hadi Salim read_unlock(&xfrm_km_lock); 168526b15dadSJamal Hadi Salim } 168626b15dadSJamal Hadi Salim 168726b15dadSJamal Hadi Salim void km_state_notify(struct xfrm_state *x, struct km_event *c) 168826b15dadSJamal Hadi Salim { 168926b15dadSJamal Hadi Salim struct xfrm_mgr *km; 169026b15dadSJamal Hadi Salim read_lock(&xfrm_km_lock); 169126b15dadSJamal Hadi Salim list_for_each_entry(km, &xfrm_km_list, list) 169226b15dadSJamal Hadi Salim if (km->notify) 169326b15dadSJamal Hadi Salim km->notify(x, c); 169426b15dadSJamal Hadi Salim read_unlock(&xfrm_km_lock); 169526b15dadSJamal Hadi Salim } 169626b15dadSJamal Hadi Salim 169726b15dadSJamal Hadi Salim EXPORT_SYMBOL(km_policy_notify); 169826b15dadSJamal Hadi Salim EXPORT_SYMBOL(km_state_notify); 169926b15dadSJamal Hadi Salim 170053bc6b4dSJamal Hadi Salim void km_state_expired(struct xfrm_state *x, int hard, u32 pid) 170126b15dadSJamal Hadi Salim { 170226b15dadSJamal Hadi Salim struct km_event c; 170326b15dadSJamal Hadi Salim 1704bf08867fSHerbert Xu c.data.hard = hard; 170553bc6b4dSJamal Hadi Salim c.pid = pid; 1706f60f6b8fSHerbert Xu c.event = XFRM_MSG_EXPIRE; 170726b15dadSJamal Hadi Salim km_state_notify(x, &c); 17081da177e4SLinus Torvalds 17091da177e4SLinus Torvalds if (hard) 17101da177e4SLinus Torvalds wake_up(&km_waitq); 17111da177e4SLinus Torvalds } 17121da177e4SLinus Torvalds 171353bc6b4dSJamal Hadi Salim EXPORT_SYMBOL(km_state_expired); 171426b15dadSJamal Hadi Salim /* 171526b15dadSJamal Hadi Salim * We send to all registered managers regardless of failure 171626b15dadSJamal Hadi Salim * We are happy with one success 171726b15dadSJamal Hadi Salim */ 1718980ebd25SJamal Hadi Salim int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol) 17191da177e4SLinus Torvalds { 172026b15dadSJamal Hadi Salim int err = -EINVAL, acqret; 17211da177e4SLinus Torvalds struct xfrm_mgr *km; 17221da177e4SLinus Torvalds 17231da177e4SLinus Torvalds read_lock(&xfrm_km_lock); 17241da177e4SLinus Torvalds list_for_each_entry(km, &xfrm_km_list, list) { 172526b15dadSJamal Hadi Salim acqret = km->acquire(x, t, pol, XFRM_POLICY_OUT); 172626b15dadSJamal Hadi Salim if (!acqret) 172726b15dadSJamal Hadi Salim err = acqret; 17281da177e4SLinus Torvalds } 17291da177e4SLinus Torvalds read_unlock(&xfrm_km_lock); 17301da177e4SLinus Torvalds return err; 17311da177e4SLinus Torvalds } 1732980ebd25SJamal Hadi Salim EXPORT_SYMBOL(km_query); 17331da177e4SLinus Torvalds 17345d36b180SAl Viro int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport) 17351da177e4SLinus Torvalds { 17361da177e4SLinus Torvalds int err = -EINVAL; 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) { 17411da177e4SLinus Torvalds if (km->new_mapping) 17421da177e4SLinus Torvalds err = km->new_mapping(x, ipaddr, sport); 17431da177e4SLinus Torvalds if (!err) 17441da177e4SLinus Torvalds break; 17451da177e4SLinus Torvalds } 17461da177e4SLinus Torvalds read_unlock(&xfrm_km_lock); 17471da177e4SLinus Torvalds return err; 17481da177e4SLinus Torvalds } 17491da177e4SLinus Torvalds EXPORT_SYMBOL(km_new_mapping); 17501da177e4SLinus Torvalds 17516c5c8ca7SJamal Hadi Salim void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 pid) 17521da177e4SLinus Torvalds { 175326b15dadSJamal Hadi Salim struct km_event c; 17541da177e4SLinus Torvalds 1755bf08867fSHerbert Xu c.data.hard = hard; 17566c5c8ca7SJamal Hadi Salim c.pid = pid; 1757f60f6b8fSHerbert Xu c.event = XFRM_MSG_POLEXPIRE; 175826b15dadSJamal Hadi Salim km_policy_notify(pol, dir, &c); 17591da177e4SLinus Torvalds 17601da177e4SLinus Torvalds if (hard) 17611da177e4SLinus Torvalds wake_up(&km_waitq); 17621da177e4SLinus Torvalds } 1763a70fcb0bSDavid S. Miller EXPORT_SYMBOL(km_policy_expired); 17641da177e4SLinus Torvalds 17652d60abc2SEric Dumazet #ifdef CONFIG_XFRM_MIGRATE 176680c9abaaSShinta Sugimoto int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type, 176780c9abaaSShinta Sugimoto struct xfrm_migrate *m, int num_migrate) 176880c9abaaSShinta Sugimoto { 176980c9abaaSShinta Sugimoto int err = -EINVAL; 177080c9abaaSShinta Sugimoto int ret; 177180c9abaaSShinta Sugimoto struct xfrm_mgr *km; 177280c9abaaSShinta Sugimoto 177380c9abaaSShinta Sugimoto read_lock(&xfrm_km_lock); 177480c9abaaSShinta Sugimoto list_for_each_entry(km, &xfrm_km_list, list) { 177580c9abaaSShinta Sugimoto if (km->migrate) { 177680c9abaaSShinta Sugimoto ret = km->migrate(sel, dir, type, m, num_migrate); 177780c9abaaSShinta Sugimoto if (!ret) 177880c9abaaSShinta Sugimoto err = ret; 177980c9abaaSShinta Sugimoto } 178080c9abaaSShinta Sugimoto } 178180c9abaaSShinta Sugimoto read_unlock(&xfrm_km_lock); 178280c9abaaSShinta Sugimoto return err; 178380c9abaaSShinta Sugimoto } 178480c9abaaSShinta Sugimoto EXPORT_SYMBOL(km_migrate); 17852d60abc2SEric Dumazet #endif 178680c9abaaSShinta Sugimoto 178797a64b45SMasahide NAKAMURA int km_report(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr) 178897a64b45SMasahide NAKAMURA { 178997a64b45SMasahide NAKAMURA int err = -EINVAL; 179097a64b45SMasahide NAKAMURA int ret; 179197a64b45SMasahide NAKAMURA struct xfrm_mgr *km; 179297a64b45SMasahide NAKAMURA 179397a64b45SMasahide NAKAMURA read_lock(&xfrm_km_lock); 179497a64b45SMasahide NAKAMURA list_for_each_entry(km, &xfrm_km_list, list) { 179597a64b45SMasahide NAKAMURA if (km->report) { 179697a64b45SMasahide NAKAMURA ret = km->report(proto, sel, addr); 179797a64b45SMasahide NAKAMURA if (!ret) 179897a64b45SMasahide NAKAMURA err = ret; 179997a64b45SMasahide NAKAMURA } 180097a64b45SMasahide NAKAMURA } 180197a64b45SMasahide NAKAMURA read_unlock(&xfrm_km_lock); 180297a64b45SMasahide NAKAMURA return err; 180397a64b45SMasahide NAKAMURA } 180497a64b45SMasahide NAKAMURA EXPORT_SYMBOL(km_report); 180597a64b45SMasahide NAKAMURA 18061da177e4SLinus Torvalds int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen) 18071da177e4SLinus Torvalds { 18081da177e4SLinus Torvalds int err; 18091da177e4SLinus Torvalds u8 *data; 18101da177e4SLinus Torvalds struct xfrm_mgr *km; 18111da177e4SLinus Torvalds struct xfrm_policy *pol = NULL; 18121da177e4SLinus Torvalds 18131da177e4SLinus Torvalds if (optlen <= 0 || optlen > PAGE_SIZE) 18141da177e4SLinus Torvalds return -EMSGSIZE; 18151da177e4SLinus Torvalds 18161da177e4SLinus Torvalds data = kmalloc(optlen, GFP_KERNEL); 18171da177e4SLinus Torvalds if (!data) 18181da177e4SLinus Torvalds return -ENOMEM; 18191da177e4SLinus Torvalds 18201da177e4SLinus Torvalds err = -EFAULT; 18211da177e4SLinus Torvalds if (copy_from_user(data, optval, optlen)) 18221da177e4SLinus Torvalds goto out; 18231da177e4SLinus Torvalds 18241da177e4SLinus Torvalds err = -EINVAL; 18251da177e4SLinus Torvalds read_lock(&xfrm_km_lock); 18261da177e4SLinus Torvalds list_for_each_entry(km, &xfrm_km_list, list) { 1827cb969f07SVenkat Yekkirala pol = km->compile_policy(sk, optname, data, 18281da177e4SLinus Torvalds optlen, &err); 18291da177e4SLinus Torvalds if (err >= 0) 18301da177e4SLinus Torvalds break; 18311da177e4SLinus Torvalds } 18321da177e4SLinus Torvalds read_unlock(&xfrm_km_lock); 18331da177e4SLinus Torvalds 18341da177e4SLinus Torvalds if (err >= 0) { 18351da177e4SLinus Torvalds xfrm_sk_policy_insert(sk, err, pol); 18361da177e4SLinus Torvalds xfrm_pol_put(pol); 18371da177e4SLinus Torvalds err = 0; 18381da177e4SLinus Torvalds } 18391da177e4SLinus Torvalds 18401da177e4SLinus Torvalds out: 18411da177e4SLinus Torvalds kfree(data); 18421da177e4SLinus Torvalds return err; 18431da177e4SLinus Torvalds } 18441da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_user_policy); 18451da177e4SLinus Torvalds 18461da177e4SLinus Torvalds int xfrm_register_km(struct xfrm_mgr *km) 18471da177e4SLinus Torvalds { 18481da177e4SLinus Torvalds write_lock_bh(&xfrm_km_lock); 18491da177e4SLinus Torvalds list_add_tail(&km->list, &xfrm_km_list); 18501da177e4SLinus Torvalds write_unlock_bh(&xfrm_km_lock); 18511da177e4SLinus Torvalds return 0; 18521da177e4SLinus Torvalds } 18531da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_register_km); 18541da177e4SLinus Torvalds 18551da177e4SLinus Torvalds int xfrm_unregister_km(struct xfrm_mgr *km) 18561da177e4SLinus Torvalds { 18571da177e4SLinus Torvalds write_lock_bh(&xfrm_km_lock); 18581da177e4SLinus Torvalds list_del(&km->list); 18591da177e4SLinus Torvalds write_unlock_bh(&xfrm_km_lock); 18601da177e4SLinus Torvalds return 0; 18611da177e4SLinus Torvalds } 18621da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_unregister_km); 18631da177e4SLinus Torvalds 18641da177e4SLinus Torvalds int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo) 18651da177e4SLinus Torvalds { 18661da177e4SLinus Torvalds int err = 0; 18671da177e4SLinus Torvalds if (unlikely(afinfo == NULL)) 18681da177e4SLinus Torvalds return -EINVAL; 18691da177e4SLinus Torvalds if (unlikely(afinfo->family >= NPROTO)) 18701da177e4SLinus Torvalds return -EAFNOSUPPORT; 1871f3111502SIngo Molnar write_lock_bh(&xfrm_state_afinfo_lock); 18721da177e4SLinus Torvalds if (unlikely(xfrm_state_afinfo[afinfo->family] != NULL)) 18731da177e4SLinus Torvalds err = -ENOBUFS; 1874edcd5821SDavid S. Miller else 18751da177e4SLinus Torvalds xfrm_state_afinfo[afinfo->family] = afinfo; 1876f3111502SIngo Molnar write_unlock_bh(&xfrm_state_afinfo_lock); 18771da177e4SLinus Torvalds return err; 18781da177e4SLinus Torvalds } 18791da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_register_afinfo); 18801da177e4SLinus Torvalds 18811da177e4SLinus Torvalds int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo) 18821da177e4SLinus Torvalds { 18831da177e4SLinus Torvalds int err = 0; 18841da177e4SLinus Torvalds if (unlikely(afinfo == NULL)) 18851da177e4SLinus Torvalds return -EINVAL; 18861da177e4SLinus Torvalds if (unlikely(afinfo->family >= NPROTO)) 18871da177e4SLinus Torvalds return -EAFNOSUPPORT; 1888f3111502SIngo Molnar write_lock_bh(&xfrm_state_afinfo_lock); 18891da177e4SLinus Torvalds if (likely(xfrm_state_afinfo[afinfo->family] != NULL)) { 18901da177e4SLinus Torvalds if (unlikely(xfrm_state_afinfo[afinfo->family] != afinfo)) 18911da177e4SLinus Torvalds err = -EINVAL; 1892edcd5821SDavid S. Miller else 18931da177e4SLinus Torvalds xfrm_state_afinfo[afinfo->family] = NULL; 18941da177e4SLinus Torvalds } 1895f3111502SIngo Molnar write_unlock_bh(&xfrm_state_afinfo_lock); 18961da177e4SLinus Torvalds return err; 18971da177e4SLinus Torvalds } 18981da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_unregister_afinfo); 18991da177e4SLinus Torvalds 190017c2a42aSHerbert Xu static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family) 19011da177e4SLinus Torvalds { 19021da177e4SLinus Torvalds struct xfrm_state_afinfo *afinfo; 19031da177e4SLinus Torvalds if (unlikely(family >= NPROTO)) 19041da177e4SLinus Torvalds return NULL; 19051da177e4SLinus Torvalds read_lock(&xfrm_state_afinfo_lock); 19061da177e4SLinus Torvalds afinfo = xfrm_state_afinfo[family]; 1907546be240SHerbert Xu if (unlikely(!afinfo)) 19081da177e4SLinus Torvalds read_unlock(&xfrm_state_afinfo_lock); 19091da177e4SLinus Torvalds return afinfo; 19101da177e4SLinus Torvalds } 19111da177e4SLinus Torvalds 191217c2a42aSHerbert Xu static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo) 19139a429c49SEric Dumazet __releases(xfrm_state_afinfo_lock) 19141da177e4SLinus Torvalds { 1915546be240SHerbert Xu read_unlock(&xfrm_state_afinfo_lock); 19161da177e4SLinus Torvalds } 19171da177e4SLinus Torvalds 19181da177e4SLinus Torvalds /* Temporarily located here until net/xfrm/xfrm_tunnel.c is created */ 19191da177e4SLinus Torvalds void xfrm_state_delete_tunnel(struct xfrm_state *x) 19201da177e4SLinus Torvalds { 19211da177e4SLinus Torvalds if (x->tunnel) { 19221da177e4SLinus Torvalds struct xfrm_state *t = x->tunnel; 19231da177e4SLinus Torvalds 19241da177e4SLinus Torvalds if (atomic_read(&t->tunnel_users) == 2) 19251da177e4SLinus Torvalds xfrm_state_delete(t); 19261da177e4SLinus Torvalds atomic_dec(&t->tunnel_users); 19271da177e4SLinus Torvalds xfrm_state_put(t); 19281da177e4SLinus Torvalds x->tunnel = NULL; 19291da177e4SLinus Torvalds } 19301da177e4SLinus Torvalds } 19311da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_delete_tunnel); 19321da177e4SLinus Torvalds 19331da177e4SLinus Torvalds int xfrm_state_mtu(struct xfrm_state *x, int mtu) 19341da177e4SLinus Torvalds { 1935c5c25238SPatrick McHardy int res; 19361da177e4SLinus Torvalds 19371da177e4SLinus Torvalds spin_lock_bh(&x->lock); 19381da177e4SLinus Torvalds if (x->km.state == XFRM_STATE_VALID && 1939c5c25238SPatrick McHardy x->type && x->type->get_mtu) 1940c5c25238SPatrick McHardy res = x->type->get_mtu(x, mtu); 19411da177e4SLinus Torvalds else 194228121617SPatrick McHardy res = mtu - x->props.header_len; 19431da177e4SLinus Torvalds spin_unlock_bh(&x->lock); 19441da177e4SLinus Torvalds return res; 19451da177e4SLinus Torvalds } 19461da177e4SLinus Torvalds 194772cb6962SHerbert Xu int xfrm_init_state(struct xfrm_state *x) 194872cb6962SHerbert Xu { 1949d094cd83SHerbert Xu struct xfrm_state_afinfo *afinfo; 1950d094cd83SHerbert Xu int family = x->props.family; 195172cb6962SHerbert Xu int err; 195272cb6962SHerbert Xu 1953d094cd83SHerbert Xu err = -EAFNOSUPPORT; 1954d094cd83SHerbert Xu afinfo = xfrm_state_get_afinfo(family); 1955d094cd83SHerbert Xu if (!afinfo) 1956d094cd83SHerbert Xu goto error; 1957d094cd83SHerbert Xu 1958d094cd83SHerbert Xu err = 0; 1959d094cd83SHerbert Xu if (afinfo->init_flags) 1960d094cd83SHerbert Xu err = afinfo->init_flags(x); 1961d094cd83SHerbert Xu 1962d094cd83SHerbert Xu xfrm_state_put_afinfo(afinfo); 1963d094cd83SHerbert Xu 1964d094cd83SHerbert Xu if (err) 1965d094cd83SHerbert Xu goto error; 1966d094cd83SHerbert Xu 1967d094cd83SHerbert Xu err = -EPROTONOSUPPORT; 196813996378SHerbert Xu x->inner_mode = xfrm_get_mode(x->props.mode, x->sel.family); 196913996378SHerbert Xu if (x->inner_mode == NULL) 197013996378SHerbert Xu goto error; 197113996378SHerbert Xu 197213996378SHerbert Xu if (!(x->inner_mode->flags & XFRM_MODE_FLAG_TUNNEL) && 197313996378SHerbert Xu family != x->sel.family) 197413996378SHerbert Xu goto error; 197513996378SHerbert Xu 1976d094cd83SHerbert Xu x->type = xfrm_get_type(x->id.proto, family); 197772cb6962SHerbert Xu if (x->type == NULL) 197872cb6962SHerbert Xu goto error; 197972cb6962SHerbert Xu 198072cb6962SHerbert Xu err = x->type->init_state(x); 198172cb6962SHerbert Xu if (err) 198272cb6962SHerbert Xu goto error; 198372cb6962SHerbert Xu 198413996378SHerbert Xu x->outer_mode = xfrm_get_mode(x->props.mode, family); 198513996378SHerbert Xu if (x->outer_mode == NULL) 1986b59f45d0SHerbert Xu goto error; 1987b59f45d0SHerbert Xu 198872cb6962SHerbert Xu x->km.state = XFRM_STATE_VALID; 198972cb6962SHerbert Xu 199072cb6962SHerbert Xu error: 199172cb6962SHerbert Xu return err; 199272cb6962SHerbert Xu } 199372cb6962SHerbert Xu 199472cb6962SHerbert Xu EXPORT_SYMBOL(xfrm_init_state); 19951da177e4SLinus Torvalds 19961da177e4SLinus Torvalds void __init xfrm_state_init(void) 19971da177e4SLinus Torvalds { 1998f034b5d4SDavid S. Miller unsigned int sz; 19991da177e4SLinus Torvalds 2000f034b5d4SDavid S. Miller sz = sizeof(struct hlist_head) * 8; 2001f034b5d4SDavid S. Miller 200244e36b42SDavid S. Miller xfrm_state_bydst = xfrm_hash_alloc(sz); 200344e36b42SDavid S. Miller xfrm_state_bysrc = xfrm_hash_alloc(sz); 200444e36b42SDavid S. Miller xfrm_state_byspi = xfrm_hash_alloc(sz); 2005f034b5d4SDavid S. Miller if (!xfrm_state_bydst || !xfrm_state_bysrc || !xfrm_state_byspi) 2006f034b5d4SDavid S. Miller panic("XFRM: Cannot allocate bydst/bysrc/byspi hashes."); 2007f034b5d4SDavid S. Miller xfrm_state_hmask = ((sz / sizeof(struct hlist_head)) - 1); 2008f034b5d4SDavid S. Miller 2009c4028958SDavid Howells INIT_WORK(&xfrm_state_gc_work, xfrm_state_gc_task); 20101da177e4SLinus Torvalds } 20111da177e4SLinus Torvalds 2012ab5f5e8bSJoy Latten #ifdef CONFIG_AUDITSYSCALL 2013*cf35f43eSIlpo Järvinen static void xfrm_audit_helper_sainfo(struct xfrm_state *x, 2014ab5f5e8bSJoy Latten struct audit_buffer *audit_buf) 2015ab5f5e8bSJoy Latten { 201668277accSPaul Moore struct xfrm_sec_ctx *ctx = x->security; 201768277accSPaul Moore u32 spi = ntohl(x->id.spi); 201868277accSPaul Moore 201968277accSPaul Moore if (ctx) 2020ab5f5e8bSJoy Latten audit_log_format(audit_buf, " sec_alg=%u sec_doi=%u sec_obj=%s", 202168277accSPaul Moore ctx->ctx_alg, ctx->ctx_doi, ctx->ctx_str); 2022ab5f5e8bSJoy Latten 2023ab5f5e8bSJoy Latten switch(x->props.family) { 2024ab5f5e8bSJoy Latten case AF_INET: 202568277accSPaul Moore audit_log_format(audit_buf, 202668277accSPaul Moore " src=" NIPQUAD_FMT " dst=" NIPQUAD_FMT, 2027ab5f5e8bSJoy Latten NIPQUAD(x->props.saddr.a4), 2028ab5f5e8bSJoy Latten NIPQUAD(x->id.daddr.a4)); 2029ab5f5e8bSJoy Latten break; 2030ab5f5e8bSJoy Latten case AF_INET6: 2031ab5f5e8bSJoy Latten audit_log_format(audit_buf, 2032ab5f5e8bSJoy Latten " src=" NIP6_FMT " dst=" NIP6_FMT, 203368277accSPaul Moore NIP6(*(struct in6_addr *)x->props.saddr.a6), 203468277accSPaul Moore NIP6(*(struct in6_addr *)x->id.daddr.a6)); 2035ab5f5e8bSJoy Latten break; 2036ab5f5e8bSJoy Latten } 203768277accSPaul Moore 203868277accSPaul Moore audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi); 2039ab5f5e8bSJoy Latten } 2040ab5f5e8bSJoy Latten 2041*cf35f43eSIlpo Järvinen static void xfrm_audit_helper_pktinfo(struct sk_buff *skb, u16 family, 2042afeb14b4SPaul Moore struct audit_buffer *audit_buf) 2043afeb14b4SPaul Moore { 2044afeb14b4SPaul Moore struct iphdr *iph4; 2045afeb14b4SPaul Moore struct ipv6hdr *iph6; 2046afeb14b4SPaul Moore 2047afeb14b4SPaul Moore switch (family) { 2048afeb14b4SPaul Moore case AF_INET: 2049afeb14b4SPaul Moore iph4 = ip_hdr(skb); 2050afeb14b4SPaul Moore audit_log_format(audit_buf, 2051afeb14b4SPaul Moore " src=" NIPQUAD_FMT " dst=" NIPQUAD_FMT, 2052afeb14b4SPaul Moore NIPQUAD(iph4->saddr), 2053afeb14b4SPaul Moore NIPQUAD(iph4->daddr)); 2054afeb14b4SPaul Moore break; 2055afeb14b4SPaul Moore case AF_INET6: 2056afeb14b4SPaul Moore iph6 = ipv6_hdr(skb); 2057afeb14b4SPaul Moore audit_log_format(audit_buf, 2058afeb14b4SPaul Moore " src=" NIP6_FMT " dst=" NIP6_FMT 2059afeb14b4SPaul Moore " flowlbl=0x%x%x%x", 2060afeb14b4SPaul Moore NIP6(iph6->saddr), 2061afeb14b4SPaul Moore NIP6(iph6->daddr), 2062afeb14b4SPaul Moore iph6->flow_lbl[0] & 0x0f, 2063afeb14b4SPaul Moore iph6->flow_lbl[1], 2064afeb14b4SPaul Moore iph6->flow_lbl[2]); 2065afeb14b4SPaul Moore break; 2066afeb14b4SPaul Moore } 2067afeb14b4SPaul Moore } 2068afeb14b4SPaul Moore 206968277accSPaul Moore void xfrm_audit_state_add(struct xfrm_state *x, int result, 207068277accSPaul Moore u32 auid, u32 secid) 2071ab5f5e8bSJoy Latten { 2072ab5f5e8bSJoy Latten struct audit_buffer *audit_buf; 2073ab5f5e8bSJoy Latten 2074afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SAD-add"); 2075ab5f5e8bSJoy Latten if (audit_buf == NULL) 2076ab5f5e8bSJoy Latten return; 2077afeb14b4SPaul Moore xfrm_audit_helper_usrinfo(auid, secid, audit_buf); 2078afeb14b4SPaul Moore xfrm_audit_helper_sainfo(x, audit_buf); 2079afeb14b4SPaul Moore audit_log_format(audit_buf, " res=%u", result); 2080ab5f5e8bSJoy Latten audit_log_end(audit_buf); 2081ab5f5e8bSJoy Latten } 2082ab5f5e8bSJoy Latten EXPORT_SYMBOL_GPL(xfrm_audit_state_add); 2083ab5f5e8bSJoy Latten 208468277accSPaul Moore void xfrm_audit_state_delete(struct xfrm_state *x, int result, 208568277accSPaul Moore u32 auid, u32 secid) 2086ab5f5e8bSJoy Latten { 2087ab5f5e8bSJoy Latten struct audit_buffer *audit_buf; 2088ab5f5e8bSJoy Latten 2089afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SAD-delete"); 2090ab5f5e8bSJoy Latten if (audit_buf == NULL) 2091ab5f5e8bSJoy Latten return; 2092afeb14b4SPaul Moore xfrm_audit_helper_usrinfo(auid, secid, audit_buf); 2093afeb14b4SPaul Moore xfrm_audit_helper_sainfo(x, audit_buf); 2094afeb14b4SPaul Moore audit_log_format(audit_buf, " res=%u", result); 2095ab5f5e8bSJoy Latten audit_log_end(audit_buf); 2096ab5f5e8bSJoy Latten } 2097ab5f5e8bSJoy Latten EXPORT_SYMBOL_GPL(xfrm_audit_state_delete); 2098afeb14b4SPaul Moore 2099afeb14b4SPaul Moore void xfrm_audit_state_replay_overflow(struct xfrm_state *x, 2100afeb14b4SPaul Moore struct sk_buff *skb) 2101afeb14b4SPaul Moore { 2102afeb14b4SPaul Moore struct audit_buffer *audit_buf; 2103afeb14b4SPaul Moore u32 spi; 2104afeb14b4SPaul Moore 2105afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SA-replay-overflow"); 2106afeb14b4SPaul Moore if (audit_buf == NULL) 2107afeb14b4SPaul Moore return; 2108afeb14b4SPaul Moore xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf); 2109afeb14b4SPaul Moore /* don't record the sequence number because it's inherent in this kind 2110afeb14b4SPaul Moore * of audit message */ 2111afeb14b4SPaul Moore spi = ntohl(x->id.spi); 2112afeb14b4SPaul Moore audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi); 2113afeb14b4SPaul Moore audit_log_end(audit_buf); 2114afeb14b4SPaul Moore } 2115afeb14b4SPaul Moore EXPORT_SYMBOL_GPL(xfrm_audit_state_replay_overflow); 2116afeb14b4SPaul Moore 2117afeb14b4SPaul Moore static void xfrm_audit_state_replay(struct xfrm_state *x, 2118afeb14b4SPaul Moore struct sk_buff *skb, __be32 net_seq) 2119afeb14b4SPaul Moore { 2120afeb14b4SPaul Moore struct audit_buffer *audit_buf; 2121afeb14b4SPaul Moore u32 spi; 2122afeb14b4SPaul Moore 2123afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SA-replayed-pkt"); 2124afeb14b4SPaul Moore if (audit_buf == NULL) 2125afeb14b4SPaul Moore return; 2126afeb14b4SPaul Moore xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf); 2127afeb14b4SPaul Moore spi = ntohl(x->id.spi); 2128afeb14b4SPaul Moore audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u", 2129afeb14b4SPaul Moore spi, spi, ntohl(net_seq)); 2130afeb14b4SPaul Moore audit_log_end(audit_buf); 2131afeb14b4SPaul Moore } 2132afeb14b4SPaul Moore 2133afeb14b4SPaul Moore void xfrm_audit_state_notfound_simple(struct sk_buff *skb, u16 family) 2134afeb14b4SPaul Moore { 2135afeb14b4SPaul Moore struct audit_buffer *audit_buf; 2136afeb14b4SPaul Moore 2137afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SA-notfound"); 2138afeb14b4SPaul Moore if (audit_buf == NULL) 2139afeb14b4SPaul Moore return; 2140afeb14b4SPaul Moore xfrm_audit_helper_pktinfo(skb, family, audit_buf); 2141afeb14b4SPaul Moore audit_log_end(audit_buf); 2142afeb14b4SPaul Moore } 2143afeb14b4SPaul Moore EXPORT_SYMBOL_GPL(xfrm_audit_state_notfound_simple); 2144afeb14b4SPaul Moore 2145afeb14b4SPaul Moore void xfrm_audit_state_notfound(struct sk_buff *skb, u16 family, 2146afeb14b4SPaul Moore __be32 net_spi, __be32 net_seq) 2147afeb14b4SPaul Moore { 2148afeb14b4SPaul Moore struct audit_buffer *audit_buf; 2149afeb14b4SPaul Moore u32 spi; 2150afeb14b4SPaul Moore 2151afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SA-notfound"); 2152afeb14b4SPaul Moore if (audit_buf == NULL) 2153afeb14b4SPaul Moore return; 2154afeb14b4SPaul Moore xfrm_audit_helper_pktinfo(skb, family, audit_buf); 2155afeb14b4SPaul Moore spi = ntohl(net_spi); 2156afeb14b4SPaul Moore audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u", 2157afeb14b4SPaul Moore spi, spi, ntohl(net_seq)); 2158afeb14b4SPaul Moore audit_log_end(audit_buf); 2159afeb14b4SPaul Moore } 2160afeb14b4SPaul Moore EXPORT_SYMBOL_GPL(xfrm_audit_state_notfound); 2161afeb14b4SPaul Moore 2162afeb14b4SPaul Moore void xfrm_audit_state_icvfail(struct xfrm_state *x, 2163afeb14b4SPaul Moore struct sk_buff *skb, u8 proto) 2164afeb14b4SPaul Moore { 2165afeb14b4SPaul Moore struct audit_buffer *audit_buf; 2166afeb14b4SPaul Moore __be32 net_spi; 2167afeb14b4SPaul Moore __be32 net_seq; 2168afeb14b4SPaul Moore 2169afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SA-icv-failure"); 2170afeb14b4SPaul Moore if (audit_buf == NULL) 2171afeb14b4SPaul Moore return; 2172afeb14b4SPaul Moore xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf); 2173afeb14b4SPaul Moore if (xfrm_parse_spi(skb, proto, &net_spi, &net_seq) == 0) { 2174afeb14b4SPaul Moore u32 spi = ntohl(net_spi); 2175afeb14b4SPaul Moore audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u", 2176afeb14b4SPaul Moore spi, spi, ntohl(net_seq)); 2177afeb14b4SPaul Moore } 2178afeb14b4SPaul Moore audit_log_end(audit_buf); 2179afeb14b4SPaul Moore } 2180afeb14b4SPaul Moore EXPORT_SYMBOL_GPL(xfrm_audit_state_icvfail); 2181ab5f5e8bSJoy Latten #endif /* CONFIG_AUDITSYSCALL */ 2182