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 219533cb5b0SEric Dumazet int xfrm_register_type(const struct xfrm_type *type, unsigned short family) 220aa5d62ccSHerbert Xu { 221aa5d62ccSHerbert Xu struct xfrm_state_afinfo *afinfo = xfrm_state_lock_afinfo(family); 222533cb5b0SEric Dumazet const 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 238533cb5b0SEric Dumazet int xfrm_unregister_type(const struct xfrm_type *type, unsigned short family) 239aa5d62ccSHerbert Xu { 240aa5d62ccSHerbert Xu struct xfrm_state_afinfo *afinfo = xfrm_state_lock_afinfo(family); 241533cb5b0SEric Dumazet const 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 257533cb5b0SEric Dumazet static const struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family) 258aa5d62ccSHerbert Xu { 259aa5d62ccSHerbert Xu struct xfrm_state_afinfo *afinfo; 260533cb5b0SEric Dumazet const struct xfrm_type **typemap; 261533cb5b0SEric Dumazet const 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 284533cb5b0SEric Dumazet static void xfrm_put_type(const 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); 391df9dcb45SKazunori MIYAZAWA if (x->inner_mode_iaf) 392df9dcb45SKazunori MIYAZAWA xfrm_put_mode(x->inner_mode_iaf); 39313996378SHerbert Xu if (x->outer_mode) 39413996378SHerbert Xu xfrm_put_mode(x->outer_mode); 3951da177e4SLinus Torvalds if (x->type) { 3961da177e4SLinus Torvalds x->type->destructor(x); 3971da177e4SLinus Torvalds xfrm_put_type(x->type); 3981da177e4SLinus Torvalds } 399df71837dSTrent Jaeger security_xfrm_state_free(x); 4001da177e4SLinus Torvalds kfree(x); 4011da177e4SLinus Torvalds } 4021da177e4SLinus Torvalds 403c4028958SDavid Howells static void xfrm_state_gc_task(struct work_struct *data) 4041da177e4SLinus Torvalds { 4051da177e4SLinus Torvalds struct xfrm_state *x; 4068f126e37SDavid S. Miller struct hlist_node *entry, *tmp; 4078f126e37SDavid S. Miller struct hlist_head gc_list; 4081da177e4SLinus Torvalds 4091da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_gc_lock); 4108f126e37SDavid S. Miller gc_list.first = xfrm_state_gc_list.first; 4118f126e37SDavid S. Miller INIT_HLIST_HEAD(&xfrm_state_gc_list); 4121da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_gc_lock); 4131da177e4SLinus Torvalds 4148f126e37SDavid S. Miller hlist_for_each_entry_safe(x, entry, tmp, &gc_list, bydst) 4151da177e4SLinus Torvalds xfrm_state_gc_destroy(x); 4168f126e37SDavid S. Miller 4171da177e4SLinus Torvalds wake_up(&km_waitq); 4181da177e4SLinus Torvalds } 4191da177e4SLinus Torvalds 4201da177e4SLinus Torvalds static inline unsigned long make_jiffies(long secs) 4211da177e4SLinus Torvalds { 4221da177e4SLinus Torvalds if (secs >= (MAX_SCHEDULE_TIMEOUT-1)/HZ) 4231da177e4SLinus Torvalds return MAX_SCHEDULE_TIMEOUT-1; 4241da177e4SLinus Torvalds else 4251da177e4SLinus Torvalds return secs*HZ; 4261da177e4SLinus Torvalds } 4271da177e4SLinus Torvalds 4281da177e4SLinus Torvalds static void xfrm_timer_handler(unsigned long data) 4291da177e4SLinus Torvalds { 4301da177e4SLinus Torvalds struct xfrm_state *x = (struct xfrm_state*)data; 4319d729f72SJames Morris unsigned long now = get_seconds(); 4321da177e4SLinus Torvalds long next = LONG_MAX; 4331da177e4SLinus Torvalds int warn = 0; 434161a09e7SJoy Latten int err = 0; 4351da177e4SLinus Torvalds 4361da177e4SLinus Torvalds spin_lock(&x->lock); 4371da177e4SLinus Torvalds if (x->km.state == XFRM_STATE_DEAD) 4381da177e4SLinus Torvalds goto out; 4391da177e4SLinus Torvalds if (x->km.state == XFRM_STATE_EXPIRED) 4401da177e4SLinus Torvalds goto expired; 4411da177e4SLinus Torvalds if (x->lft.hard_add_expires_seconds) { 4421da177e4SLinus Torvalds long tmo = x->lft.hard_add_expires_seconds + 4431da177e4SLinus Torvalds x->curlft.add_time - now; 4441da177e4SLinus Torvalds if (tmo <= 0) 4451da177e4SLinus Torvalds goto expired; 4461da177e4SLinus Torvalds if (tmo < next) 4471da177e4SLinus Torvalds next = tmo; 4481da177e4SLinus Torvalds } 4491da177e4SLinus Torvalds if (x->lft.hard_use_expires_seconds) { 4501da177e4SLinus Torvalds long tmo = x->lft.hard_use_expires_seconds + 4511da177e4SLinus Torvalds (x->curlft.use_time ? : now) - now; 4521da177e4SLinus Torvalds if (tmo <= 0) 4531da177e4SLinus Torvalds goto expired; 4541da177e4SLinus Torvalds if (tmo < next) 4551da177e4SLinus Torvalds next = tmo; 4561da177e4SLinus Torvalds } 4571da177e4SLinus Torvalds if (x->km.dying) 4581da177e4SLinus Torvalds goto resched; 4591da177e4SLinus Torvalds if (x->lft.soft_add_expires_seconds) { 4601da177e4SLinus Torvalds long tmo = x->lft.soft_add_expires_seconds + 4611da177e4SLinus Torvalds x->curlft.add_time - now; 4621da177e4SLinus Torvalds if (tmo <= 0) 4631da177e4SLinus Torvalds warn = 1; 4641da177e4SLinus Torvalds else if (tmo < next) 4651da177e4SLinus Torvalds next = tmo; 4661da177e4SLinus Torvalds } 4671da177e4SLinus Torvalds if (x->lft.soft_use_expires_seconds) { 4681da177e4SLinus Torvalds long tmo = x->lft.soft_use_expires_seconds + 4691da177e4SLinus Torvalds (x->curlft.use_time ? : now) - now; 4701da177e4SLinus Torvalds if (tmo <= 0) 4711da177e4SLinus Torvalds warn = 1; 4721da177e4SLinus Torvalds else if (tmo < next) 4731da177e4SLinus Torvalds next = tmo; 4741da177e4SLinus Torvalds } 4751da177e4SLinus Torvalds 4764666faabSHerbert Xu x->km.dying = warn; 4771da177e4SLinus Torvalds if (warn) 47853bc6b4dSJamal Hadi Salim km_state_expired(x, 0, 0); 4791da177e4SLinus Torvalds resched: 480a47f0ce0SDavid S. Miller if (next != LONG_MAX) 481a47f0ce0SDavid S. Miller mod_timer(&x->timer, jiffies + make_jiffies(next)); 482a47f0ce0SDavid S. Miller 4831da177e4SLinus Torvalds goto out; 4841da177e4SLinus Torvalds 4851da177e4SLinus Torvalds expired: 4861da177e4SLinus Torvalds if (x->km.state == XFRM_STATE_ACQ && x->id.spi == 0) { 4871da177e4SLinus Torvalds x->km.state = XFRM_STATE_EXPIRED; 4881da177e4SLinus Torvalds wake_up(&km_waitq); 4891da177e4SLinus Torvalds next = 2; 4901da177e4SLinus Torvalds goto resched; 4911da177e4SLinus Torvalds } 492161a09e7SJoy Latten 493161a09e7SJoy Latten err = __xfrm_state_delete(x); 494161a09e7SJoy Latten if (!err && x->id.spi) 49553bc6b4dSJamal Hadi Salim km_state_expired(x, 1, 0); 4961da177e4SLinus Torvalds 497ab5f5e8bSJoy Latten xfrm_audit_state_delete(x, err ? 0 : 1, 4980c11b942SAl Viro audit_get_loginuid(current), 0); 499161a09e7SJoy Latten 5001da177e4SLinus Torvalds out: 5011da177e4SLinus Torvalds spin_unlock(&x->lock); 5021da177e4SLinus Torvalds } 5031da177e4SLinus Torvalds 5040ac84752SDavid S. Miller static void xfrm_replay_timer_handler(unsigned long data); 5050ac84752SDavid S. Miller 5061da177e4SLinus Torvalds struct xfrm_state *xfrm_state_alloc(void) 5071da177e4SLinus Torvalds { 5081da177e4SLinus Torvalds struct xfrm_state *x; 5091da177e4SLinus Torvalds 5100da974f4SPanagiotis Issaris x = kzalloc(sizeof(struct xfrm_state), GFP_ATOMIC); 5111da177e4SLinus Torvalds 5121da177e4SLinus Torvalds if (x) { 5131da177e4SLinus Torvalds atomic_set(&x->refcnt, 1); 5141da177e4SLinus Torvalds atomic_set(&x->tunnel_users, 0); 5158f126e37SDavid S. Miller INIT_HLIST_NODE(&x->bydst); 5168f126e37SDavid S. Miller INIT_HLIST_NODE(&x->bysrc); 5178f126e37SDavid S. Miller INIT_HLIST_NODE(&x->byspi); 518b24b8a24SPavel Emelyanov setup_timer(&x->timer, xfrm_timer_handler, (unsigned long)x); 519b24b8a24SPavel Emelyanov setup_timer(&x->rtimer, xfrm_replay_timer_handler, 520b24b8a24SPavel Emelyanov (unsigned long)x); 5219d729f72SJames Morris x->curlft.add_time = get_seconds(); 5221da177e4SLinus Torvalds x->lft.soft_byte_limit = XFRM_INF; 5231da177e4SLinus Torvalds x->lft.soft_packet_limit = XFRM_INF; 5241da177e4SLinus Torvalds x->lft.hard_byte_limit = XFRM_INF; 5251da177e4SLinus Torvalds x->lft.hard_packet_limit = XFRM_INF; 526f8cd5488SJamal Hadi Salim x->replay_maxage = 0; 527f8cd5488SJamal Hadi Salim x->replay_maxdiff = 0; 528df9dcb45SKazunori MIYAZAWA x->inner_mode = NULL; 529df9dcb45SKazunori MIYAZAWA x->inner_mode_iaf = NULL; 5301da177e4SLinus Torvalds spin_lock_init(&x->lock); 5311da177e4SLinus Torvalds } 5321da177e4SLinus Torvalds return x; 5331da177e4SLinus Torvalds } 5341da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_alloc); 5351da177e4SLinus Torvalds 5361da177e4SLinus Torvalds void __xfrm_state_destroy(struct xfrm_state *x) 5371da177e4SLinus Torvalds { 5381da177e4SLinus Torvalds BUG_TRAP(x->km.state == XFRM_STATE_DEAD); 5391da177e4SLinus Torvalds 5401da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_gc_lock); 5418f126e37SDavid S. Miller hlist_add_head(&x->bydst, &xfrm_state_gc_list); 5421da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_gc_lock); 5431da177e4SLinus Torvalds schedule_work(&xfrm_state_gc_work); 5441da177e4SLinus Torvalds } 5451da177e4SLinus Torvalds EXPORT_SYMBOL(__xfrm_state_destroy); 5461da177e4SLinus Torvalds 54753bc6b4dSJamal Hadi Salim int __xfrm_state_delete(struct xfrm_state *x) 5481da177e4SLinus Torvalds { 54926b15dadSJamal Hadi Salim int err = -ESRCH; 55026b15dadSJamal Hadi Salim 5511da177e4SLinus Torvalds if (x->km.state != XFRM_STATE_DEAD) { 5521da177e4SLinus Torvalds x->km.state = XFRM_STATE_DEAD; 5531da177e4SLinus Torvalds spin_lock(&xfrm_state_lock); 5548f126e37SDavid S. Miller hlist_del(&x->bydst); 5558f126e37SDavid S. Miller hlist_del(&x->bysrc); 556a47f0ce0SDavid S. Miller if (x->id.spi) 5578f126e37SDavid S. Miller hlist_del(&x->byspi); 558f034b5d4SDavid S. Miller xfrm_state_num--; 5591da177e4SLinus Torvalds spin_unlock(&xfrm_state_lock); 5601da177e4SLinus Torvalds 5611da177e4SLinus Torvalds /* All xfrm_state objects are created by xfrm_state_alloc. 5621da177e4SLinus Torvalds * The xfrm_state_alloc call gives a reference, and that 5631da177e4SLinus Torvalds * is what we are dropping here. 5641da177e4SLinus Torvalds */ 5655dba4797SPatrick McHardy xfrm_state_put(x); 56626b15dadSJamal Hadi Salim err = 0; 5671da177e4SLinus Torvalds } 5681da177e4SLinus Torvalds 56926b15dadSJamal Hadi Salim return err; 57026b15dadSJamal Hadi Salim } 57153bc6b4dSJamal Hadi Salim EXPORT_SYMBOL(__xfrm_state_delete); 57226b15dadSJamal Hadi Salim 57326b15dadSJamal Hadi Salim int xfrm_state_delete(struct xfrm_state *x) 5741da177e4SLinus Torvalds { 57526b15dadSJamal Hadi Salim int err; 57626b15dadSJamal Hadi Salim 5771da177e4SLinus Torvalds spin_lock_bh(&x->lock); 57826b15dadSJamal Hadi Salim err = __xfrm_state_delete(x); 5791da177e4SLinus Torvalds spin_unlock_bh(&x->lock); 58026b15dadSJamal Hadi Salim 58126b15dadSJamal Hadi Salim return err; 5821da177e4SLinus Torvalds } 5831da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_delete); 5841da177e4SLinus Torvalds 5854aa2e62cSJoy Latten #ifdef CONFIG_SECURITY_NETWORK_XFRM 5864aa2e62cSJoy Latten static inline int 5874aa2e62cSJoy Latten xfrm_state_flush_secctx_check(u8 proto, struct xfrm_audit *audit_info) 5881da177e4SLinus Torvalds { 5894aa2e62cSJoy Latten int i, err = 0; 5904aa2e62cSJoy Latten 5914aa2e62cSJoy Latten for (i = 0; i <= xfrm_state_hmask; i++) { 5924aa2e62cSJoy Latten struct hlist_node *entry; 5934aa2e62cSJoy Latten struct xfrm_state *x; 5944aa2e62cSJoy Latten 5954aa2e62cSJoy Latten hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) { 5964aa2e62cSJoy Latten if (xfrm_id_proto_match(x->id.proto, proto) && 5974aa2e62cSJoy Latten (err = security_xfrm_state_delete(x)) != 0) { 598ab5f5e8bSJoy Latten xfrm_audit_state_delete(x, 0, 599ab5f5e8bSJoy Latten audit_info->loginuid, 600ab5f5e8bSJoy Latten audit_info->secid); 6014aa2e62cSJoy Latten return err; 6024aa2e62cSJoy Latten } 6034aa2e62cSJoy Latten } 6044aa2e62cSJoy Latten } 6054aa2e62cSJoy Latten 6064aa2e62cSJoy Latten return err; 6074aa2e62cSJoy Latten } 6084aa2e62cSJoy Latten #else 6094aa2e62cSJoy Latten static inline int 6104aa2e62cSJoy Latten xfrm_state_flush_secctx_check(u8 proto, struct xfrm_audit *audit_info) 6114aa2e62cSJoy Latten { 6124aa2e62cSJoy Latten return 0; 6134aa2e62cSJoy Latten } 6144aa2e62cSJoy Latten #endif 6154aa2e62cSJoy Latten 6164aa2e62cSJoy Latten int xfrm_state_flush(u8 proto, struct xfrm_audit *audit_info) 6174aa2e62cSJoy Latten { 6184aa2e62cSJoy Latten int i, err = 0; 6191da177e4SLinus Torvalds 6201da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_lock); 6214aa2e62cSJoy Latten err = xfrm_state_flush_secctx_check(proto, audit_info); 6224aa2e62cSJoy Latten if (err) 6234aa2e62cSJoy Latten goto out; 6244aa2e62cSJoy Latten 625a9917c06SMasahide NAKAMURA for (i = 0; i <= xfrm_state_hmask; i++) { 6268f126e37SDavid S. Miller struct hlist_node *entry; 6278f126e37SDavid S. Miller struct xfrm_state *x; 6281da177e4SLinus Torvalds restart: 6298f126e37SDavid S. Miller hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) { 6301da177e4SLinus Torvalds if (!xfrm_state_kern(x) && 6315794708fSMasahide NAKAMURA xfrm_id_proto_match(x->id.proto, proto)) { 6321da177e4SLinus Torvalds xfrm_state_hold(x); 6331da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_lock); 6341da177e4SLinus Torvalds 635161a09e7SJoy Latten err = xfrm_state_delete(x); 636ab5f5e8bSJoy Latten xfrm_audit_state_delete(x, err ? 0 : 1, 637ab5f5e8bSJoy Latten audit_info->loginuid, 638ab5f5e8bSJoy Latten audit_info->secid); 6391da177e4SLinus Torvalds xfrm_state_put(x); 6401da177e4SLinus Torvalds 6411da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_lock); 6421da177e4SLinus Torvalds goto restart; 6431da177e4SLinus Torvalds } 6441da177e4SLinus Torvalds } 6451da177e4SLinus Torvalds } 6464aa2e62cSJoy Latten err = 0; 6474aa2e62cSJoy Latten 6484aa2e62cSJoy Latten out: 6491da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_lock); 6501da177e4SLinus Torvalds wake_up(&km_waitq); 6514aa2e62cSJoy Latten return err; 6521da177e4SLinus Torvalds } 6531da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_flush); 6541da177e4SLinus Torvalds 655af11e316SJamal Hadi Salim void xfrm_sad_getinfo(struct xfrmk_sadinfo *si) 65628d8909bSJamal Hadi Salim { 65728d8909bSJamal Hadi Salim spin_lock_bh(&xfrm_state_lock); 65828d8909bSJamal Hadi Salim si->sadcnt = xfrm_state_num; 65928d8909bSJamal Hadi Salim si->sadhcnt = xfrm_state_hmask; 66028d8909bSJamal Hadi Salim si->sadhmcnt = xfrm_state_hashmax; 66128d8909bSJamal Hadi Salim spin_unlock_bh(&xfrm_state_lock); 66228d8909bSJamal Hadi Salim } 66328d8909bSJamal Hadi Salim EXPORT_SYMBOL(xfrm_sad_getinfo); 66428d8909bSJamal Hadi Salim 6651da177e4SLinus Torvalds static int 6661da177e4SLinus Torvalds xfrm_init_tempsel(struct xfrm_state *x, struct flowi *fl, 6671da177e4SLinus Torvalds struct xfrm_tmpl *tmpl, 6681da177e4SLinus Torvalds xfrm_address_t *daddr, xfrm_address_t *saddr, 6691da177e4SLinus Torvalds unsigned short family) 6701da177e4SLinus Torvalds { 6711da177e4SLinus Torvalds struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); 6721da177e4SLinus Torvalds if (!afinfo) 6731da177e4SLinus Torvalds return -1; 6741da177e4SLinus Torvalds afinfo->init_tempsel(x, fl, tmpl, daddr, saddr); 6751da177e4SLinus Torvalds xfrm_state_put_afinfo(afinfo); 6761da177e4SLinus Torvalds return 0; 6771da177e4SLinus Torvalds } 6781da177e4SLinus Torvalds 679a94cfd19SAl Viro static struct xfrm_state *__xfrm_state_lookup(xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family) 680edcd5821SDavid S. Miller { 681edcd5821SDavid S. Miller unsigned int h = xfrm_spi_hash(daddr, spi, proto, family); 682edcd5821SDavid S. Miller struct xfrm_state *x; 6838f126e37SDavid S. Miller struct hlist_node *entry; 684edcd5821SDavid S. Miller 6858f126e37SDavid S. Miller hlist_for_each_entry(x, entry, xfrm_state_byspi+h, byspi) { 686edcd5821SDavid S. Miller if (x->props.family != family || 687edcd5821SDavid S. Miller x->id.spi != spi || 688edcd5821SDavid S. Miller x->id.proto != proto) 689edcd5821SDavid S. Miller continue; 690edcd5821SDavid S. Miller 691edcd5821SDavid S. Miller switch (family) { 692edcd5821SDavid S. Miller case AF_INET: 693edcd5821SDavid S. Miller if (x->id.daddr.a4 != daddr->a4) 694edcd5821SDavid S. Miller continue; 695edcd5821SDavid S. Miller break; 696edcd5821SDavid S. Miller case AF_INET6: 697edcd5821SDavid S. Miller if (!ipv6_addr_equal((struct in6_addr *)daddr, 698edcd5821SDavid S. Miller (struct in6_addr *) 699edcd5821SDavid S. Miller x->id.daddr.a6)) 700edcd5821SDavid S. Miller continue; 701edcd5821SDavid S. Miller break; 7023ff50b79SStephen Hemminger } 703edcd5821SDavid S. Miller 704edcd5821SDavid S. Miller xfrm_state_hold(x); 705edcd5821SDavid S. Miller return x; 706edcd5821SDavid S. Miller } 707edcd5821SDavid S. Miller 708edcd5821SDavid S. Miller return NULL; 709edcd5821SDavid S. Miller } 710edcd5821SDavid S. Miller 711edcd5821SDavid S. Miller static struct xfrm_state *__xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto, unsigned short family) 712edcd5821SDavid S. Miller { 713667bbcb6SMasahide NAKAMURA unsigned int h = xfrm_src_hash(daddr, saddr, family); 714edcd5821SDavid S. Miller struct xfrm_state *x; 7158f126e37SDavid S. Miller struct hlist_node *entry; 716edcd5821SDavid S. Miller 7178f126e37SDavid S. Miller hlist_for_each_entry(x, entry, xfrm_state_bysrc+h, bysrc) { 718edcd5821SDavid S. Miller if (x->props.family != family || 719edcd5821SDavid S. Miller x->id.proto != proto) 720edcd5821SDavid S. Miller continue; 721edcd5821SDavid S. Miller 722edcd5821SDavid S. Miller switch (family) { 723edcd5821SDavid S. Miller case AF_INET: 724edcd5821SDavid S. Miller if (x->id.daddr.a4 != daddr->a4 || 725edcd5821SDavid S. Miller x->props.saddr.a4 != saddr->a4) 726edcd5821SDavid S. Miller continue; 727edcd5821SDavid S. Miller break; 728edcd5821SDavid S. Miller case AF_INET6: 729edcd5821SDavid S. Miller if (!ipv6_addr_equal((struct in6_addr *)daddr, 730edcd5821SDavid S. Miller (struct in6_addr *) 731edcd5821SDavid S. Miller x->id.daddr.a6) || 732edcd5821SDavid S. Miller !ipv6_addr_equal((struct in6_addr *)saddr, 733edcd5821SDavid S. Miller (struct in6_addr *) 734edcd5821SDavid S. Miller x->props.saddr.a6)) 735edcd5821SDavid S. Miller continue; 736edcd5821SDavid S. Miller break; 7373ff50b79SStephen Hemminger } 738edcd5821SDavid S. Miller 739edcd5821SDavid S. Miller xfrm_state_hold(x); 740edcd5821SDavid S. Miller return x; 741edcd5821SDavid S. Miller } 742edcd5821SDavid S. Miller 743edcd5821SDavid S. Miller return NULL; 744edcd5821SDavid S. Miller } 745edcd5821SDavid S. Miller 746edcd5821SDavid S. Miller static inline struct xfrm_state * 747edcd5821SDavid S. Miller __xfrm_state_locate(struct xfrm_state *x, int use_spi, int family) 748edcd5821SDavid S. Miller { 749edcd5821SDavid S. Miller if (use_spi) 750edcd5821SDavid S. Miller return __xfrm_state_lookup(&x->id.daddr, x->id.spi, 751edcd5821SDavid S. Miller x->id.proto, family); 752edcd5821SDavid S. Miller else 753edcd5821SDavid S. Miller return __xfrm_state_lookup_byaddr(&x->id.daddr, 754edcd5821SDavid S. Miller &x->props.saddr, 755edcd5821SDavid S. Miller x->id.proto, family); 756edcd5821SDavid S. Miller } 757edcd5821SDavid S. Miller 7582fab22f2SPatrick McHardy static void xfrm_hash_grow_check(int have_hash_collision) 7592fab22f2SPatrick McHardy { 7602fab22f2SPatrick McHardy if (have_hash_collision && 7612fab22f2SPatrick McHardy (xfrm_state_hmask + 1) < xfrm_state_hashmax && 7622fab22f2SPatrick McHardy xfrm_state_num > xfrm_state_hmask) 7632fab22f2SPatrick McHardy schedule_work(&xfrm_hash_work); 7642fab22f2SPatrick McHardy } 7652fab22f2SPatrick McHardy 7661da177e4SLinus Torvalds struct xfrm_state * 7671da177e4SLinus Torvalds xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, 7681da177e4SLinus Torvalds struct flowi *fl, struct xfrm_tmpl *tmpl, 7691da177e4SLinus Torvalds struct xfrm_policy *pol, int *err, 7701da177e4SLinus Torvalds unsigned short family) 7711da177e4SLinus Torvalds { 7724bda4f25SPavel Emelyanov unsigned int h; 7738f126e37SDavid S. Miller struct hlist_node *entry; 7741da177e4SLinus Torvalds struct xfrm_state *x, *x0; 7751da177e4SLinus Torvalds int acquire_in_progress = 0; 7761da177e4SLinus Torvalds int error = 0; 7771da177e4SLinus Torvalds struct xfrm_state *best = NULL; 7781da177e4SLinus Torvalds 7791da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_lock); 7804bda4f25SPavel Emelyanov h = xfrm_dst_hash(daddr, saddr, tmpl->reqid, family); 7818f126e37SDavid S. Miller hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) { 7821da177e4SLinus Torvalds if (x->props.family == family && 7831da177e4SLinus Torvalds x->props.reqid == tmpl->reqid && 784fbd9a5b4SMasahide NAKAMURA !(x->props.flags & XFRM_STATE_WILDRECV) && 7851da177e4SLinus Torvalds xfrm_state_addr_check(x, daddr, saddr, family) && 7861da177e4SLinus Torvalds tmpl->mode == x->props.mode && 7871da177e4SLinus Torvalds tmpl->id.proto == x->id.proto && 7881da177e4SLinus Torvalds (tmpl->id.spi == x->id.spi || !tmpl->id.spi)) { 7891da177e4SLinus Torvalds /* Resolution logic: 7901da177e4SLinus Torvalds 1. There is a valid state with matching selector. 7911da177e4SLinus Torvalds Done. 7921da177e4SLinus Torvalds 2. Valid state with inappropriate selector. Skip. 7931da177e4SLinus Torvalds 7941da177e4SLinus Torvalds Entering area of "sysdeps". 7951da177e4SLinus Torvalds 7961da177e4SLinus Torvalds 3. If state is not valid, selector is temporary, 7971da177e4SLinus Torvalds it selects only session which triggered 7981da177e4SLinus Torvalds previous resolution. Key manager will do 7991da177e4SLinus Torvalds something to install a state with proper 8001da177e4SLinus Torvalds selector. 8011da177e4SLinus Torvalds */ 8021da177e4SLinus Torvalds if (x->km.state == XFRM_STATE_VALID) { 803df9dcb45SKazunori MIYAZAWA if ((x->sel.family && !xfrm_selector_match(&x->sel, fl, x->sel.family)) || 804e0d1caa7SVenkat Yekkirala !security_xfrm_state_pol_flow_match(x, pol, fl)) 8051da177e4SLinus Torvalds continue; 8061da177e4SLinus Torvalds if (!best || 8071da177e4SLinus Torvalds best->km.dying > x->km.dying || 8081da177e4SLinus Torvalds (best->km.dying == x->km.dying && 8091da177e4SLinus Torvalds best->curlft.add_time < x->curlft.add_time)) 8101da177e4SLinus Torvalds best = x; 8111da177e4SLinus Torvalds } else if (x->km.state == XFRM_STATE_ACQ) { 8121da177e4SLinus Torvalds acquire_in_progress = 1; 8131da177e4SLinus Torvalds } else if (x->km.state == XFRM_STATE_ERROR || 8141da177e4SLinus Torvalds x->km.state == XFRM_STATE_EXPIRED) { 81548b8d783SJoakim Koskela if (xfrm_selector_match(&x->sel, fl, x->sel.family) && 816e0d1caa7SVenkat Yekkirala security_xfrm_state_pol_flow_match(x, pol, fl)) 8171da177e4SLinus Torvalds error = -ESRCH; 8181da177e4SLinus Torvalds } 8191da177e4SLinus Torvalds } 8201da177e4SLinus Torvalds } 8211da177e4SLinus Torvalds 8221da177e4SLinus Torvalds x = best; 8231da177e4SLinus Torvalds if (!x && !error && !acquire_in_progress) { 8245c5d281aSPatrick McHardy if (tmpl->id.spi && 825edcd5821SDavid S. Miller (x0 = __xfrm_state_lookup(daddr, tmpl->id.spi, 826edcd5821SDavid S. Miller tmpl->id.proto, family)) != NULL) { 8271da177e4SLinus Torvalds xfrm_state_put(x0); 8281da177e4SLinus Torvalds error = -EEXIST; 8291da177e4SLinus Torvalds goto out; 8301da177e4SLinus Torvalds } 8311da177e4SLinus Torvalds x = xfrm_state_alloc(); 8321da177e4SLinus Torvalds if (x == NULL) { 8331da177e4SLinus Torvalds error = -ENOMEM; 8341da177e4SLinus Torvalds goto out; 8351da177e4SLinus Torvalds } 8361da177e4SLinus Torvalds /* Initialize temporary selector matching only 8371da177e4SLinus Torvalds * to current session. */ 8381da177e4SLinus Torvalds xfrm_init_tempsel(x, fl, tmpl, daddr, saddr, family); 8391da177e4SLinus Torvalds 840e0d1caa7SVenkat Yekkirala error = security_xfrm_state_alloc_acquire(x, pol->security, fl->secid); 841e0d1caa7SVenkat Yekkirala if (error) { 842e0d1caa7SVenkat Yekkirala x->km.state = XFRM_STATE_DEAD; 843e0d1caa7SVenkat Yekkirala xfrm_state_put(x); 844e0d1caa7SVenkat Yekkirala x = NULL; 845e0d1caa7SVenkat Yekkirala goto out; 846e0d1caa7SVenkat Yekkirala } 847e0d1caa7SVenkat Yekkirala 8481da177e4SLinus Torvalds if (km_query(x, tmpl, pol) == 0) { 8491da177e4SLinus Torvalds x->km.state = XFRM_STATE_ACQ; 8508f126e37SDavid S. Miller hlist_add_head(&x->bydst, xfrm_state_bydst+h); 851667bbcb6SMasahide NAKAMURA h = xfrm_src_hash(daddr, saddr, family); 8528f126e37SDavid S. Miller hlist_add_head(&x->bysrc, xfrm_state_bysrc+h); 8531da177e4SLinus Torvalds if (x->id.spi) { 8541da177e4SLinus Torvalds h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, family); 8558f126e37SDavid S. Miller hlist_add_head(&x->byspi, xfrm_state_byspi+h); 8561da177e4SLinus Torvalds } 85701e67d08SDavid S. Miller x->lft.hard_add_expires_seconds = sysctl_xfrm_acq_expires; 85801e67d08SDavid S. Miller x->timer.expires = jiffies + sysctl_xfrm_acq_expires*HZ; 8591da177e4SLinus Torvalds add_timer(&x->timer); 8602fab22f2SPatrick McHardy xfrm_state_num++; 8612fab22f2SPatrick McHardy xfrm_hash_grow_check(x->bydst.next != NULL); 8621da177e4SLinus Torvalds } else { 8631da177e4SLinus Torvalds x->km.state = XFRM_STATE_DEAD; 8641da177e4SLinus Torvalds xfrm_state_put(x); 8651da177e4SLinus Torvalds x = NULL; 8661da177e4SLinus Torvalds error = -ESRCH; 8671da177e4SLinus Torvalds } 8681da177e4SLinus Torvalds } 8691da177e4SLinus Torvalds out: 8701da177e4SLinus Torvalds if (x) 8711da177e4SLinus Torvalds xfrm_state_hold(x); 8721da177e4SLinus Torvalds else 8731da177e4SLinus Torvalds *err = acquire_in_progress ? -EAGAIN : error; 8741da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_lock); 8751da177e4SLinus Torvalds return x; 8761da177e4SLinus Torvalds } 8771da177e4SLinus Torvalds 878628529b6SJamal Hadi Salim struct xfrm_state * 879628529b6SJamal Hadi Salim xfrm_stateonly_find(xfrm_address_t *daddr, xfrm_address_t *saddr, 880628529b6SJamal Hadi Salim unsigned short family, u8 mode, u8 proto, u32 reqid) 881628529b6SJamal Hadi Salim { 8824bda4f25SPavel Emelyanov unsigned int h; 883628529b6SJamal Hadi Salim struct xfrm_state *rx = NULL, *x = NULL; 884628529b6SJamal Hadi Salim struct hlist_node *entry; 885628529b6SJamal Hadi Salim 886628529b6SJamal Hadi Salim spin_lock(&xfrm_state_lock); 8874bda4f25SPavel Emelyanov h = xfrm_dst_hash(daddr, saddr, reqid, family); 888628529b6SJamal Hadi Salim hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) { 889628529b6SJamal Hadi Salim if (x->props.family == family && 890628529b6SJamal Hadi Salim x->props.reqid == reqid && 891628529b6SJamal Hadi Salim !(x->props.flags & XFRM_STATE_WILDRECV) && 892628529b6SJamal Hadi Salim xfrm_state_addr_check(x, daddr, saddr, family) && 893628529b6SJamal Hadi Salim mode == x->props.mode && 894628529b6SJamal Hadi Salim proto == x->id.proto && 895628529b6SJamal Hadi Salim x->km.state == XFRM_STATE_VALID) { 896628529b6SJamal Hadi Salim rx = x; 897628529b6SJamal Hadi Salim break; 898628529b6SJamal Hadi Salim } 899628529b6SJamal Hadi Salim } 900628529b6SJamal Hadi Salim 901628529b6SJamal Hadi Salim if (rx) 902628529b6SJamal Hadi Salim xfrm_state_hold(rx); 903628529b6SJamal Hadi Salim spin_unlock(&xfrm_state_lock); 904628529b6SJamal Hadi Salim 905628529b6SJamal Hadi Salim 906628529b6SJamal Hadi Salim return rx; 907628529b6SJamal Hadi Salim } 908628529b6SJamal Hadi Salim EXPORT_SYMBOL(xfrm_stateonly_find); 909628529b6SJamal Hadi Salim 9101da177e4SLinus Torvalds static void __xfrm_state_insert(struct xfrm_state *x) 9111da177e4SLinus Torvalds { 912a624c108SDavid S. Miller unsigned int h; 9131da177e4SLinus Torvalds 9149d4a706dSDavid S. Miller x->genid = ++xfrm_state_genid; 9159d4a706dSDavid S. Miller 916c1969f29SDavid S. Miller h = xfrm_dst_hash(&x->id.daddr, &x->props.saddr, 917c1969f29SDavid S. Miller x->props.reqid, x->props.family); 9188f126e37SDavid S. Miller hlist_add_head(&x->bydst, xfrm_state_bydst+h); 9191da177e4SLinus Torvalds 920667bbcb6SMasahide NAKAMURA h = xfrm_src_hash(&x->id.daddr, &x->props.saddr, x->props.family); 9218f126e37SDavid S. Miller hlist_add_head(&x->bysrc, xfrm_state_bysrc+h); 9226c44e6b7SMasahide NAKAMURA 9237b4dc360SMasahide NAKAMURA if (x->id.spi) { 9246c44e6b7SMasahide NAKAMURA h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, 9256c44e6b7SMasahide NAKAMURA x->props.family); 9261da177e4SLinus Torvalds 9278f126e37SDavid S. Miller hlist_add_head(&x->byspi, xfrm_state_byspi+h); 9286c44e6b7SMasahide NAKAMURA } 9291da177e4SLinus Torvalds 930a47f0ce0SDavid S. Miller mod_timer(&x->timer, jiffies + HZ); 931a47f0ce0SDavid S. Miller if (x->replay_maxage) 932a47f0ce0SDavid S. Miller mod_timer(&x->rtimer, jiffies + x->replay_maxage); 933f8cd5488SJamal Hadi Salim 9341da177e4SLinus Torvalds wake_up(&km_waitq); 935f034b5d4SDavid S. Miller 936f034b5d4SDavid S. Miller xfrm_state_num++; 937f034b5d4SDavid S. Miller 938918049f0SDavid S. Miller xfrm_hash_grow_check(x->bydst.next != NULL); 9391da177e4SLinus Torvalds } 9401da177e4SLinus Torvalds 941c7f5ea3aSDavid S. Miller /* xfrm_state_lock is held */ 942c7f5ea3aSDavid S. Miller static void __xfrm_state_bump_genids(struct xfrm_state *xnew) 943c7f5ea3aSDavid S. Miller { 944c7f5ea3aSDavid S. Miller unsigned short family = xnew->props.family; 945c7f5ea3aSDavid S. Miller u32 reqid = xnew->props.reqid; 946c7f5ea3aSDavid S. Miller struct xfrm_state *x; 947c7f5ea3aSDavid S. Miller struct hlist_node *entry; 948c7f5ea3aSDavid S. Miller unsigned int h; 949c7f5ea3aSDavid S. Miller 950c1969f29SDavid S. Miller h = xfrm_dst_hash(&xnew->id.daddr, &xnew->props.saddr, reqid, family); 951c7f5ea3aSDavid S. Miller hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) { 952c7f5ea3aSDavid S. Miller if (x->props.family == family && 953c7f5ea3aSDavid S. Miller x->props.reqid == reqid && 954c1969f29SDavid S. Miller !xfrm_addr_cmp(&x->id.daddr, &xnew->id.daddr, family) && 955c1969f29SDavid S. Miller !xfrm_addr_cmp(&x->props.saddr, &xnew->props.saddr, family)) 956c7f5ea3aSDavid S. Miller x->genid = xfrm_state_genid; 957c7f5ea3aSDavid S. Miller } 958c7f5ea3aSDavid S. Miller } 959c7f5ea3aSDavid S. Miller 9601da177e4SLinus Torvalds void xfrm_state_insert(struct xfrm_state *x) 9611da177e4SLinus Torvalds { 9621da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_lock); 963c7f5ea3aSDavid S. Miller __xfrm_state_bump_genids(x); 9641da177e4SLinus Torvalds __xfrm_state_insert(x); 9651da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_lock); 9661da177e4SLinus Torvalds } 9671da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_insert); 9681da177e4SLinus Torvalds 9692770834cSDavid S. Miller /* xfrm_state_lock is held */ 9702770834cSDavid 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) 9712770834cSDavid S. Miller { 972c1969f29SDavid S. Miller unsigned int h = xfrm_dst_hash(daddr, saddr, reqid, family); 9738f126e37SDavid S. Miller struct hlist_node *entry; 9742770834cSDavid S. Miller struct xfrm_state *x; 9752770834cSDavid S. Miller 9768f126e37SDavid S. Miller hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) { 9772770834cSDavid S. Miller if (x->props.reqid != reqid || 9782770834cSDavid S. Miller x->props.mode != mode || 9792770834cSDavid S. Miller x->props.family != family || 9802770834cSDavid S. Miller x->km.state != XFRM_STATE_ACQ || 98175e252d9SJoy Latten x->id.spi != 0 || 98275e252d9SJoy Latten x->id.proto != proto) 9832770834cSDavid S. Miller continue; 9842770834cSDavid S. Miller 9852770834cSDavid S. Miller switch (family) { 9862770834cSDavid S. Miller case AF_INET: 9872770834cSDavid S. Miller if (x->id.daddr.a4 != daddr->a4 || 9882770834cSDavid S. Miller x->props.saddr.a4 != saddr->a4) 9892770834cSDavid S. Miller continue; 9902770834cSDavid S. Miller break; 9912770834cSDavid S. Miller case AF_INET6: 9922770834cSDavid S. Miller if (!ipv6_addr_equal((struct in6_addr *)x->id.daddr.a6, 9932770834cSDavid S. Miller (struct in6_addr *)daddr) || 9942770834cSDavid S. Miller !ipv6_addr_equal((struct in6_addr *) 9952770834cSDavid S. Miller x->props.saddr.a6, 9962770834cSDavid S. Miller (struct in6_addr *)saddr)) 9972770834cSDavid S. Miller continue; 9982770834cSDavid S. Miller break; 9993ff50b79SStephen Hemminger } 10002770834cSDavid S. Miller 10012770834cSDavid S. Miller xfrm_state_hold(x); 10022770834cSDavid S. Miller return x; 10032770834cSDavid S. Miller } 10042770834cSDavid S. Miller 10052770834cSDavid S. Miller if (!create) 10062770834cSDavid S. Miller return NULL; 10072770834cSDavid S. Miller 10082770834cSDavid S. Miller x = xfrm_state_alloc(); 10092770834cSDavid S. Miller if (likely(x)) { 10102770834cSDavid S. Miller switch (family) { 10112770834cSDavid S. Miller case AF_INET: 10122770834cSDavid S. Miller x->sel.daddr.a4 = daddr->a4; 10132770834cSDavid S. Miller x->sel.saddr.a4 = saddr->a4; 10142770834cSDavid S. Miller x->sel.prefixlen_d = 32; 10152770834cSDavid S. Miller x->sel.prefixlen_s = 32; 10162770834cSDavid S. Miller x->props.saddr.a4 = saddr->a4; 10172770834cSDavid S. Miller x->id.daddr.a4 = daddr->a4; 10182770834cSDavid S. Miller break; 10192770834cSDavid S. Miller 10202770834cSDavid S. Miller case AF_INET6: 10212770834cSDavid S. Miller ipv6_addr_copy((struct in6_addr *)x->sel.daddr.a6, 10222770834cSDavid S. Miller (struct in6_addr *)daddr); 10232770834cSDavid S. Miller ipv6_addr_copy((struct in6_addr *)x->sel.saddr.a6, 10242770834cSDavid S. Miller (struct in6_addr *)saddr); 10252770834cSDavid S. Miller x->sel.prefixlen_d = 128; 10262770834cSDavid S. Miller x->sel.prefixlen_s = 128; 10272770834cSDavid S. Miller ipv6_addr_copy((struct in6_addr *)x->props.saddr.a6, 10282770834cSDavid S. Miller (struct in6_addr *)saddr); 10292770834cSDavid S. Miller ipv6_addr_copy((struct in6_addr *)x->id.daddr.a6, 10302770834cSDavid S. Miller (struct in6_addr *)daddr); 10312770834cSDavid S. Miller break; 10323ff50b79SStephen Hemminger } 10332770834cSDavid S. Miller 10342770834cSDavid S. Miller x->km.state = XFRM_STATE_ACQ; 10352770834cSDavid S. Miller x->id.proto = proto; 10362770834cSDavid S. Miller x->props.family = family; 10372770834cSDavid S. Miller x->props.mode = mode; 10382770834cSDavid S. Miller x->props.reqid = reqid; 103901e67d08SDavid S. Miller x->lft.hard_add_expires_seconds = sysctl_xfrm_acq_expires; 10402770834cSDavid S. Miller xfrm_state_hold(x); 104101e67d08SDavid S. Miller x->timer.expires = jiffies + sysctl_xfrm_acq_expires*HZ; 10422770834cSDavid S. Miller add_timer(&x->timer); 10438f126e37SDavid S. Miller hlist_add_head(&x->bydst, xfrm_state_bydst+h); 1044667bbcb6SMasahide NAKAMURA h = xfrm_src_hash(daddr, saddr, family); 10458f126e37SDavid S. Miller hlist_add_head(&x->bysrc, xfrm_state_bysrc+h); 1046918049f0SDavid S. Miller 1047918049f0SDavid S. Miller xfrm_state_num++; 1048918049f0SDavid S. Miller 1049918049f0SDavid S. Miller xfrm_hash_grow_check(x->bydst.next != NULL); 10502770834cSDavid S. Miller } 10512770834cSDavid S. Miller 10522770834cSDavid S. Miller return x; 10532770834cSDavid S. Miller } 10542770834cSDavid S. Miller 10551da177e4SLinus Torvalds static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq); 10561da177e4SLinus Torvalds 10571da177e4SLinus Torvalds int xfrm_state_add(struct xfrm_state *x) 10581da177e4SLinus Torvalds { 10591da177e4SLinus Torvalds struct xfrm_state *x1; 10601da177e4SLinus Torvalds int family; 10611da177e4SLinus Torvalds int err; 1062eb2971b6SMasahide NAKAMURA int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY); 10631da177e4SLinus Torvalds 10641da177e4SLinus Torvalds family = x->props.family; 10651da177e4SLinus Torvalds 10661da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_lock); 10671da177e4SLinus Torvalds 1068edcd5821SDavid S. Miller x1 = __xfrm_state_locate(x, use_spi, family); 10691da177e4SLinus Torvalds if (x1) { 10701da177e4SLinus Torvalds xfrm_state_put(x1); 10711da177e4SLinus Torvalds x1 = NULL; 10721da177e4SLinus Torvalds err = -EEXIST; 10731da177e4SLinus Torvalds goto out; 10741da177e4SLinus Torvalds } 10751da177e4SLinus Torvalds 1076eb2971b6SMasahide NAKAMURA if (use_spi && x->km.seq) { 10771da177e4SLinus Torvalds x1 = __xfrm_find_acq_byseq(x->km.seq); 107875e252d9SJoy Latten if (x1 && ((x1->id.proto != x->id.proto) || 107975e252d9SJoy Latten xfrm_addr_cmp(&x1->id.daddr, &x->id.daddr, family))) { 10801da177e4SLinus Torvalds xfrm_state_put(x1); 10811da177e4SLinus Torvalds x1 = NULL; 10821da177e4SLinus Torvalds } 10831da177e4SLinus Torvalds } 10841da177e4SLinus Torvalds 1085eb2971b6SMasahide NAKAMURA if (use_spi && !x1) 10862770834cSDavid S. Miller x1 = __find_acq_core(family, x->props.mode, x->props.reqid, 10872770834cSDavid S. Miller x->id.proto, 10881da177e4SLinus Torvalds &x->id.daddr, &x->props.saddr, 0); 10891da177e4SLinus Torvalds 1090c7f5ea3aSDavid S. Miller __xfrm_state_bump_genids(x); 10911da177e4SLinus Torvalds __xfrm_state_insert(x); 10921da177e4SLinus Torvalds err = 0; 10931da177e4SLinus Torvalds 10941da177e4SLinus Torvalds out: 10951da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_lock); 10961da177e4SLinus Torvalds 10971da177e4SLinus Torvalds if (x1) { 10981da177e4SLinus Torvalds xfrm_state_delete(x1); 10991da177e4SLinus Torvalds xfrm_state_put(x1); 11001da177e4SLinus Torvalds } 11011da177e4SLinus Torvalds 11021da177e4SLinus Torvalds return err; 11031da177e4SLinus Torvalds } 11041da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_add); 11051da177e4SLinus Torvalds 110680c9abaaSShinta Sugimoto #ifdef CONFIG_XFRM_MIGRATE 11076666351dSEric Dumazet static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp) 110880c9abaaSShinta Sugimoto { 110980c9abaaSShinta Sugimoto int err = -ENOMEM; 111080c9abaaSShinta Sugimoto struct xfrm_state *x = xfrm_state_alloc(); 111180c9abaaSShinta Sugimoto if (!x) 111280c9abaaSShinta Sugimoto goto error; 111380c9abaaSShinta Sugimoto 111480c9abaaSShinta Sugimoto memcpy(&x->id, &orig->id, sizeof(x->id)); 111580c9abaaSShinta Sugimoto memcpy(&x->sel, &orig->sel, sizeof(x->sel)); 111680c9abaaSShinta Sugimoto memcpy(&x->lft, &orig->lft, sizeof(x->lft)); 111780c9abaaSShinta Sugimoto x->props.mode = orig->props.mode; 111880c9abaaSShinta Sugimoto x->props.replay_window = orig->props.replay_window; 111980c9abaaSShinta Sugimoto x->props.reqid = orig->props.reqid; 112080c9abaaSShinta Sugimoto x->props.family = orig->props.family; 112180c9abaaSShinta Sugimoto x->props.saddr = orig->props.saddr; 112280c9abaaSShinta Sugimoto 112380c9abaaSShinta Sugimoto if (orig->aalg) { 112480c9abaaSShinta Sugimoto x->aalg = xfrm_algo_clone(orig->aalg); 112580c9abaaSShinta Sugimoto if (!x->aalg) 112680c9abaaSShinta Sugimoto goto error; 112780c9abaaSShinta Sugimoto } 112880c9abaaSShinta Sugimoto x->props.aalgo = orig->props.aalgo; 112980c9abaaSShinta Sugimoto 113080c9abaaSShinta Sugimoto if (orig->ealg) { 113180c9abaaSShinta Sugimoto x->ealg = xfrm_algo_clone(orig->ealg); 113280c9abaaSShinta Sugimoto if (!x->ealg) 113380c9abaaSShinta Sugimoto goto error; 113480c9abaaSShinta Sugimoto } 113580c9abaaSShinta Sugimoto x->props.ealgo = orig->props.ealgo; 113680c9abaaSShinta Sugimoto 113780c9abaaSShinta Sugimoto if (orig->calg) { 113880c9abaaSShinta Sugimoto x->calg = xfrm_algo_clone(orig->calg); 113980c9abaaSShinta Sugimoto if (!x->calg) 114080c9abaaSShinta Sugimoto goto error; 114180c9abaaSShinta Sugimoto } 114280c9abaaSShinta Sugimoto x->props.calgo = orig->props.calgo; 114380c9abaaSShinta Sugimoto 114480c9abaaSShinta Sugimoto if (orig->encap) { 114580c9abaaSShinta Sugimoto x->encap = kmemdup(orig->encap, sizeof(*x->encap), GFP_KERNEL); 114680c9abaaSShinta Sugimoto if (!x->encap) 114780c9abaaSShinta Sugimoto goto error; 114880c9abaaSShinta Sugimoto } 114980c9abaaSShinta Sugimoto 115080c9abaaSShinta Sugimoto if (orig->coaddr) { 115180c9abaaSShinta Sugimoto x->coaddr = kmemdup(orig->coaddr, sizeof(*x->coaddr), 115280c9abaaSShinta Sugimoto GFP_KERNEL); 115380c9abaaSShinta Sugimoto if (!x->coaddr) 115480c9abaaSShinta Sugimoto goto error; 115580c9abaaSShinta Sugimoto } 115680c9abaaSShinta Sugimoto 115780c9abaaSShinta Sugimoto err = xfrm_init_state(x); 115880c9abaaSShinta Sugimoto if (err) 115980c9abaaSShinta Sugimoto goto error; 116080c9abaaSShinta Sugimoto 116180c9abaaSShinta Sugimoto x->props.flags = orig->props.flags; 116280c9abaaSShinta Sugimoto 116380c9abaaSShinta Sugimoto x->curlft.add_time = orig->curlft.add_time; 116480c9abaaSShinta Sugimoto x->km.state = orig->km.state; 116580c9abaaSShinta Sugimoto x->km.seq = orig->km.seq; 116680c9abaaSShinta Sugimoto 116780c9abaaSShinta Sugimoto return x; 116880c9abaaSShinta Sugimoto 116980c9abaaSShinta Sugimoto error: 117080c9abaaSShinta Sugimoto if (errp) 117180c9abaaSShinta Sugimoto *errp = err; 117280c9abaaSShinta Sugimoto if (x) { 117380c9abaaSShinta Sugimoto kfree(x->aalg); 117480c9abaaSShinta Sugimoto kfree(x->ealg); 117580c9abaaSShinta Sugimoto kfree(x->calg); 117680c9abaaSShinta Sugimoto kfree(x->encap); 117780c9abaaSShinta Sugimoto kfree(x->coaddr); 117880c9abaaSShinta Sugimoto } 117980c9abaaSShinta Sugimoto kfree(x); 118080c9abaaSShinta Sugimoto return NULL; 118180c9abaaSShinta Sugimoto } 118280c9abaaSShinta Sugimoto 118380c9abaaSShinta Sugimoto /* xfrm_state_lock is held */ 118480c9abaaSShinta Sugimoto struct xfrm_state * xfrm_migrate_state_find(struct xfrm_migrate *m) 118580c9abaaSShinta Sugimoto { 118680c9abaaSShinta Sugimoto unsigned int h; 118780c9abaaSShinta Sugimoto struct xfrm_state *x; 118880c9abaaSShinta Sugimoto struct hlist_node *entry; 118980c9abaaSShinta Sugimoto 119080c9abaaSShinta Sugimoto if (m->reqid) { 119180c9abaaSShinta Sugimoto h = xfrm_dst_hash(&m->old_daddr, &m->old_saddr, 119280c9abaaSShinta Sugimoto m->reqid, m->old_family); 119380c9abaaSShinta Sugimoto hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) { 119480c9abaaSShinta Sugimoto if (x->props.mode != m->mode || 119580c9abaaSShinta Sugimoto x->id.proto != m->proto) 119680c9abaaSShinta Sugimoto continue; 119780c9abaaSShinta Sugimoto if (m->reqid && x->props.reqid != m->reqid) 119880c9abaaSShinta Sugimoto continue; 119980c9abaaSShinta Sugimoto if (xfrm_addr_cmp(&x->id.daddr, &m->old_daddr, 120080c9abaaSShinta Sugimoto m->old_family) || 120180c9abaaSShinta Sugimoto xfrm_addr_cmp(&x->props.saddr, &m->old_saddr, 120280c9abaaSShinta Sugimoto m->old_family)) 120380c9abaaSShinta Sugimoto continue; 120480c9abaaSShinta Sugimoto xfrm_state_hold(x); 120580c9abaaSShinta Sugimoto return x; 120680c9abaaSShinta Sugimoto } 120780c9abaaSShinta Sugimoto } else { 120880c9abaaSShinta Sugimoto h = xfrm_src_hash(&m->old_daddr, &m->old_saddr, 120980c9abaaSShinta Sugimoto m->old_family); 121080c9abaaSShinta Sugimoto hlist_for_each_entry(x, entry, xfrm_state_bysrc+h, bysrc) { 121180c9abaaSShinta Sugimoto if (x->props.mode != m->mode || 121280c9abaaSShinta Sugimoto x->id.proto != m->proto) 121380c9abaaSShinta Sugimoto continue; 121480c9abaaSShinta Sugimoto if (xfrm_addr_cmp(&x->id.daddr, &m->old_daddr, 121580c9abaaSShinta Sugimoto m->old_family) || 121680c9abaaSShinta Sugimoto xfrm_addr_cmp(&x->props.saddr, &m->old_saddr, 121780c9abaaSShinta Sugimoto m->old_family)) 121880c9abaaSShinta Sugimoto continue; 121980c9abaaSShinta Sugimoto xfrm_state_hold(x); 122080c9abaaSShinta Sugimoto return x; 122180c9abaaSShinta Sugimoto } 122280c9abaaSShinta Sugimoto } 122380c9abaaSShinta Sugimoto 122480c9abaaSShinta Sugimoto return NULL; 122580c9abaaSShinta Sugimoto } 122680c9abaaSShinta Sugimoto EXPORT_SYMBOL(xfrm_migrate_state_find); 122780c9abaaSShinta Sugimoto 122880c9abaaSShinta Sugimoto struct xfrm_state * xfrm_state_migrate(struct xfrm_state *x, 122980c9abaaSShinta Sugimoto struct xfrm_migrate *m) 123080c9abaaSShinta Sugimoto { 123180c9abaaSShinta Sugimoto struct xfrm_state *xc; 123280c9abaaSShinta Sugimoto int err; 123380c9abaaSShinta Sugimoto 123480c9abaaSShinta Sugimoto xc = xfrm_state_clone(x, &err); 123580c9abaaSShinta Sugimoto if (!xc) 123680c9abaaSShinta Sugimoto return NULL; 123780c9abaaSShinta Sugimoto 123880c9abaaSShinta Sugimoto memcpy(&xc->id.daddr, &m->new_daddr, sizeof(xc->id.daddr)); 123980c9abaaSShinta Sugimoto memcpy(&xc->props.saddr, &m->new_saddr, sizeof(xc->props.saddr)); 124080c9abaaSShinta Sugimoto 124180c9abaaSShinta Sugimoto /* add state */ 124280c9abaaSShinta Sugimoto if (!xfrm_addr_cmp(&x->id.daddr, &m->new_daddr, m->new_family)) { 124380c9abaaSShinta Sugimoto /* a care is needed when the destination address of the 124480c9abaaSShinta Sugimoto state is to be updated as it is a part of triplet */ 124580c9abaaSShinta Sugimoto xfrm_state_insert(xc); 124680c9abaaSShinta Sugimoto } else { 124780c9abaaSShinta Sugimoto if ((err = xfrm_state_add(xc)) < 0) 124880c9abaaSShinta Sugimoto goto error; 124980c9abaaSShinta Sugimoto } 125080c9abaaSShinta Sugimoto 125180c9abaaSShinta Sugimoto return xc; 125280c9abaaSShinta Sugimoto error: 125380c9abaaSShinta Sugimoto kfree(xc); 125480c9abaaSShinta Sugimoto return NULL; 125580c9abaaSShinta Sugimoto } 125680c9abaaSShinta Sugimoto EXPORT_SYMBOL(xfrm_state_migrate); 125780c9abaaSShinta Sugimoto #endif 125880c9abaaSShinta Sugimoto 12591da177e4SLinus Torvalds int xfrm_state_update(struct xfrm_state *x) 12601da177e4SLinus Torvalds { 12611da177e4SLinus Torvalds struct xfrm_state *x1; 12621da177e4SLinus Torvalds int err; 1263eb2971b6SMasahide NAKAMURA int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY); 12641da177e4SLinus Torvalds 12651da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_lock); 1266edcd5821SDavid S. Miller x1 = __xfrm_state_locate(x, use_spi, x->props.family); 12671da177e4SLinus Torvalds 12681da177e4SLinus Torvalds err = -ESRCH; 12691da177e4SLinus Torvalds if (!x1) 12701da177e4SLinus Torvalds goto out; 12711da177e4SLinus Torvalds 12721da177e4SLinus Torvalds if (xfrm_state_kern(x1)) { 12731da177e4SLinus Torvalds xfrm_state_put(x1); 12741da177e4SLinus Torvalds err = -EEXIST; 12751da177e4SLinus Torvalds goto out; 12761da177e4SLinus Torvalds } 12771da177e4SLinus Torvalds 12781da177e4SLinus Torvalds if (x1->km.state == XFRM_STATE_ACQ) { 12791da177e4SLinus Torvalds __xfrm_state_insert(x); 12801da177e4SLinus Torvalds x = NULL; 12811da177e4SLinus Torvalds } 12821da177e4SLinus Torvalds err = 0; 12831da177e4SLinus Torvalds 12841da177e4SLinus Torvalds out: 12851da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_lock); 12861da177e4SLinus Torvalds 12871da177e4SLinus Torvalds if (err) 12881da177e4SLinus Torvalds return err; 12891da177e4SLinus Torvalds 12901da177e4SLinus Torvalds if (!x) { 12911da177e4SLinus Torvalds xfrm_state_delete(x1); 12921da177e4SLinus Torvalds xfrm_state_put(x1); 12931da177e4SLinus Torvalds return 0; 12941da177e4SLinus Torvalds } 12951da177e4SLinus Torvalds 12961da177e4SLinus Torvalds err = -EINVAL; 12971da177e4SLinus Torvalds spin_lock_bh(&x1->lock); 12981da177e4SLinus Torvalds if (likely(x1->km.state == XFRM_STATE_VALID)) { 12991da177e4SLinus Torvalds if (x->encap && x1->encap) 13001da177e4SLinus Torvalds memcpy(x1->encap, x->encap, sizeof(*x1->encap)); 1301060f02a3SNoriaki TAKAMIYA if (x->coaddr && x1->coaddr) { 1302060f02a3SNoriaki TAKAMIYA memcpy(x1->coaddr, x->coaddr, sizeof(*x1->coaddr)); 1303060f02a3SNoriaki TAKAMIYA } 1304060f02a3SNoriaki TAKAMIYA if (!use_spi && memcmp(&x1->sel, &x->sel, sizeof(x1->sel))) 1305060f02a3SNoriaki TAKAMIYA memcpy(&x1->sel, &x->sel, sizeof(x1->sel)); 13061da177e4SLinus Torvalds memcpy(&x1->lft, &x->lft, sizeof(x1->lft)); 13071da177e4SLinus Torvalds x1->km.dying = 0; 13081da177e4SLinus Torvalds 1309a47f0ce0SDavid S. Miller mod_timer(&x1->timer, jiffies + HZ); 13101da177e4SLinus Torvalds if (x1->curlft.use_time) 13111da177e4SLinus Torvalds xfrm_state_check_expire(x1); 13121da177e4SLinus Torvalds 13131da177e4SLinus Torvalds err = 0; 13141da177e4SLinus Torvalds } 13151da177e4SLinus Torvalds spin_unlock_bh(&x1->lock); 13161da177e4SLinus Torvalds 13171da177e4SLinus Torvalds xfrm_state_put(x1); 13181da177e4SLinus Torvalds 13191da177e4SLinus Torvalds return err; 13201da177e4SLinus Torvalds } 13211da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_update); 13221da177e4SLinus Torvalds 13231da177e4SLinus Torvalds int xfrm_state_check_expire(struct xfrm_state *x) 13241da177e4SLinus Torvalds { 13251da177e4SLinus Torvalds if (!x->curlft.use_time) 13269d729f72SJames Morris x->curlft.use_time = get_seconds(); 13271da177e4SLinus Torvalds 13281da177e4SLinus Torvalds if (x->km.state != XFRM_STATE_VALID) 13291da177e4SLinus Torvalds return -EINVAL; 13301da177e4SLinus Torvalds 13311da177e4SLinus Torvalds if (x->curlft.bytes >= x->lft.hard_byte_limit || 13321da177e4SLinus Torvalds x->curlft.packets >= x->lft.hard_packet_limit) { 13334666faabSHerbert Xu x->km.state = XFRM_STATE_EXPIRED; 1334a47f0ce0SDavid S. Miller mod_timer(&x->timer, jiffies); 13351da177e4SLinus Torvalds return -EINVAL; 13361da177e4SLinus Torvalds } 13371da177e4SLinus Torvalds 13381da177e4SLinus Torvalds if (!x->km.dying && 13391da177e4SLinus Torvalds (x->curlft.bytes >= x->lft.soft_byte_limit || 13404666faabSHerbert Xu x->curlft.packets >= x->lft.soft_packet_limit)) { 13414666faabSHerbert Xu x->km.dying = 1; 134253bc6b4dSJamal Hadi Salim km_state_expired(x, 0, 0); 13434666faabSHerbert Xu } 13441da177e4SLinus Torvalds return 0; 13451da177e4SLinus Torvalds } 13461da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_check_expire); 13471da177e4SLinus Torvalds 13481da177e4SLinus Torvalds struct xfrm_state * 1349a94cfd19SAl Viro xfrm_state_lookup(xfrm_address_t *daddr, __be32 spi, u8 proto, 13501da177e4SLinus Torvalds unsigned short family) 13511da177e4SLinus Torvalds { 13521da177e4SLinus Torvalds struct xfrm_state *x; 13531da177e4SLinus Torvalds 13541da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_lock); 1355edcd5821SDavid S. Miller x = __xfrm_state_lookup(daddr, spi, proto, family); 13561da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_lock); 13571da177e4SLinus Torvalds return x; 13581da177e4SLinus Torvalds } 13591da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_lookup); 13601da177e4SLinus Torvalds 13611da177e4SLinus Torvalds struct xfrm_state * 1362eb2971b6SMasahide NAKAMURA xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr, 1363eb2971b6SMasahide NAKAMURA u8 proto, unsigned short family) 1364eb2971b6SMasahide NAKAMURA { 1365eb2971b6SMasahide NAKAMURA struct xfrm_state *x; 1366eb2971b6SMasahide NAKAMURA 1367eb2971b6SMasahide NAKAMURA spin_lock_bh(&xfrm_state_lock); 1368edcd5821SDavid S. Miller x = __xfrm_state_lookup_byaddr(daddr, saddr, proto, family); 1369eb2971b6SMasahide NAKAMURA spin_unlock_bh(&xfrm_state_lock); 1370eb2971b6SMasahide NAKAMURA return x; 1371eb2971b6SMasahide NAKAMURA } 1372eb2971b6SMasahide NAKAMURA EXPORT_SYMBOL(xfrm_state_lookup_byaddr); 1373eb2971b6SMasahide NAKAMURA 1374eb2971b6SMasahide NAKAMURA struct xfrm_state * 13751da177e4SLinus Torvalds xfrm_find_acq(u8 mode, u32 reqid, u8 proto, 13761da177e4SLinus Torvalds xfrm_address_t *daddr, xfrm_address_t *saddr, 13771da177e4SLinus Torvalds int create, unsigned short family) 13781da177e4SLinus Torvalds { 13791da177e4SLinus Torvalds struct xfrm_state *x; 13801da177e4SLinus Torvalds 13811da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_lock); 13822770834cSDavid S. Miller x = __find_acq_core(family, mode, reqid, proto, daddr, saddr, create); 13831da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_lock); 13842770834cSDavid S. Miller 13851da177e4SLinus Torvalds return x; 13861da177e4SLinus Torvalds } 13871da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_find_acq); 13881da177e4SLinus Torvalds 138941a49cc3SMasahide NAKAMURA #ifdef CONFIG_XFRM_SUB_POLICY 139041a49cc3SMasahide NAKAMURA int 139141a49cc3SMasahide NAKAMURA xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n, 139241a49cc3SMasahide NAKAMURA unsigned short family) 139341a49cc3SMasahide NAKAMURA { 139441a49cc3SMasahide NAKAMURA int err = 0; 139541a49cc3SMasahide NAKAMURA struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); 139641a49cc3SMasahide NAKAMURA if (!afinfo) 139741a49cc3SMasahide NAKAMURA return -EAFNOSUPPORT; 139841a49cc3SMasahide NAKAMURA 139941a49cc3SMasahide NAKAMURA spin_lock_bh(&xfrm_state_lock); 140041a49cc3SMasahide NAKAMURA if (afinfo->tmpl_sort) 140141a49cc3SMasahide NAKAMURA err = afinfo->tmpl_sort(dst, src, n); 140241a49cc3SMasahide NAKAMURA spin_unlock_bh(&xfrm_state_lock); 140341a49cc3SMasahide NAKAMURA xfrm_state_put_afinfo(afinfo); 140441a49cc3SMasahide NAKAMURA return err; 140541a49cc3SMasahide NAKAMURA } 140641a49cc3SMasahide NAKAMURA EXPORT_SYMBOL(xfrm_tmpl_sort); 140741a49cc3SMasahide NAKAMURA 140841a49cc3SMasahide NAKAMURA int 140941a49cc3SMasahide NAKAMURA xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n, 141041a49cc3SMasahide NAKAMURA unsigned short family) 141141a49cc3SMasahide NAKAMURA { 141241a49cc3SMasahide NAKAMURA int err = 0; 141341a49cc3SMasahide NAKAMURA struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); 141441a49cc3SMasahide NAKAMURA if (!afinfo) 141541a49cc3SMasahide NAKAMURA return -EAFNOSUPPORT; 141641a49cc3SMasahide NAKAMURA 141741a49cc3SMasahide NAKAMURA spin_lock_bh(&xfrm_state_lock); 141841a49cc3SMasahide NAKAMURA if (afinfo->state_sort) 141941a49cc3SMasahide NAKAMURA err = afinfo->state_sort(dst, src, n); 142041a49cc3SMasahide NAKAMURA spin_unlock_bh(&xfrm_state_lock); 142141a49cc3SMasahide NAKAMURA xfrm_state_put_afinfo(afinfo); 142241a49cc3SMasahide NAKAMURA return err; 142341a49cc3SMasahide NAKAMURA } 142441a49cc3SMasahide NAKAMURA EXPORT_SYMBOL(xfrm_state_sort); 142541a49cc3SMasahide NAKAMURA #endif 142641a49cc3SMasahide NAKAMURA 14271da177e4SLinus Torvalds /* Silly enough, but I'm lazy to build resolution list */ 14281da177e4SLinus Torvalds 14291da177e4SLinus Torvalds static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq) 14301da177e4SLinus Torvalds { 14311da177e4SLinus Torvalds int i; 14321da177e4SLinus Torvalds 1433f034b5d4SDavid S. Miller for (i = 0; i <= xfrm_state_hmask; i++) { 14348f126e37SDavid S. Miller struct hlist_node *entry; 14358f126e37SDavid S. Miller struct xfrm_state *x; 14368f126e37SDavid S. Miller 14378f126e37SDavid S. Miller hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) { 14388f126e37SDavid S. Miller if (x->km.seq == seq && 14398f126e37SDavid S. Miller x->km.state == XFRM_STATE_ACQ) { 14401da177e4SLinus Torvalds xfrm_state_hold(x); 14411da177e4SLinus Torvalds return x; 14421da177e4SLinus Torvalds } 14431da177e4SLinus Torvalds } 14441da177e4SLinus Torvalds } 14451da177e4SLinus Torvalds return NULL; 14461da177e4SLinus Torvalds } 14471da177e4SLinus Torvalds 14481da177e4SLinus Torvalds struct xfrm_state *xfrm_find_acq_byseq(u32 seq) 14491da177e4SLinus Torvalds { 14501da177e4SLinus Torvalds struct xfrm_state *x; 14511da177e4SLinus Torvalds 14521da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_lock); 14531da177e4SLinus Torvalds x = __xfrm_find_acq_byseq(seq); 14541da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_lock); 14551da177e4SLinus Torvalds return x; 14561da177e4SLinus Torvalds } 14571da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_find_acq_byseq); 14581da177e4SLinus Torvalds 14591da177e4SLinus Torvalds u32 xfrm_get_acqseq(void) 14601da177e4SLinus Torvalds { 14611da177e4SLinus Torvalds u32 res; 14621da177e4SLinus Torvalds static u32 acqseq; 14631da177e4SLinus Torvalds static DEFINE_SPINLOCK(acqseq_lock); 14641da177e4SLinus Torvalds 14651da177e4SLinus Torvalds spin_lock_bh(&acqseq_lock); 14661da177e4SLinus Torvalds res = (++acqseq ? : ++acqseq); 14671da177e4SLinus Torvalds spin_unlock_bh(&acqseq_lock); 14681da177e4SLinus Torvalds return res; 14691da177e4SLinus Torvalds } 14701da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_get_acqseq); 14711da177e4SLinus Torvalds 1472658b219eSHerbert Xu int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high) 14731da177e4SLinus Torvalds { 1474f034b5d4SDavid S. Miller unsigned int h; 14751da177e4SLinus Torvalds struct xfrm_state *x0; 1476658b219eSHerbert Xu int err = -ENOENT; 1477658b219eSHerbert Xu __be32 minspi = htonl(low); 1478658b219eSHerbert Xu __be32 maxspi = htonl(high); 14791da177e4SLinus Torvalds 1480658b219eSHerbert Xu spin_lock_bh(&x->lock); 1481658b219eSHerbert Xu if (x->km.state == XFRM_STATE_DEAD) 1482658b219eSHerbert Xu goto unlock; 1483658b219eSHerbert Xu 1484658b219eSHerbert Xu err = 0; 14851da177e4SLinus Torvalds if (x->id.spi) 1486658b219eSHerbert Xu goto unlock; 1487658b219eSHerbert Xu 1488658b219eSHerbert Xu err = -ENOENT; 14891da177e4SLinus Torvalds 14901da177e4SLinus Torvalds if (minspi == maxspi) { 14911da177e4SLinus Torvalds x0 = xfrm_state_lookup(&x->id.daddr, minspi, x->id.proto, x->props.family); 14921da177e4SLinus Torvalds if (x0) { 14931da177e4SLinus Torvalds xfrm_state_put(x0); 1494658b219eSHerbert Xu goto unlock; 14951da177e4SLinus Torvalds } 14961da177e4SLinus Torvalds x->id.spi = minspi; 14971da177e4SLinus Torvalds } else { 14981da177e4SLinus Torvalds u32 spi = 0; 149926977b4eSAl Viro for (h=0; h<high-low+1; h++) { 150026977b4eSAl Viro spi = low + net_random()%(high-low+1); 15011da177e4SLinus Torvalds x0 = xfrm_state_lookup(&x->id.daddr, htonl(spi), x->id.proto, x->props.family); 15021da177e4SLinus Torvalds if (x0 == NULL) { 15031da177e4SLinus Torvalds x->id.spi = htonl(spi); 15041da177e4SLinus Torvalds break; 15051da177e4SLinus Torvalds } 15061da177e4SLinus Torvalds xfrm_state_put(x0); 15071da177e4SLinus Torvalds } 15081da177e4SLinus Torvalds } 15091da177e4SLinus Torvalds if (x->id.spi) { 15101da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_lock); 15111da177e4SLinus Torvalds h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, x->props.family); 15128f126e37SDavid S. Miller hlist_add_head(&x->byspi, xfrm_state_byspi+h); 15131da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_lock); 1514658b219eSHerbert Xu 1515658b219eSHerbert Xu err = 0; 15161da177e4SLinus Torvalds } 1517658b219eSHerbert Xu 1518658b219eSHerbert Xu unlock: 1519658b219eSHerbert Xu spin_unlock_bh(&x->lock); 1520658b219eSHerbert Xu 1521658b219eSHerbert Xu return err; 15221da177e4SLinus Torvalds } 15231da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_alloc_spi); 15241da177e4SLinus Torvalds 15251da177e4SLinus Torvalds int xfrm_state_walk(u8 proto, int (*func)(struct xfrm_state *, int, void*), 15261da177e4SLinus Torvalds void *data) 15271da177e4SLinus Torvalds { 15281da177e4SLinus Torvalds int i; 152994b9bb54SJamal Hadi Salim struct xfrm_state *x, *last = NULL; 15308f126e37SDavid S. Miller struct hlist_node *entry; 15311da177e4SLinus Torvalds int count = 0; 15321da177e4SLinus Torvalds int err = 0; 15331da177e4SLinus Torvalds 15341da177e4SLinus Torvalds spin_lock_bh(&xfrm_state_lock); 1535f034b5d4SDavid S. Miller for (i = 0; i <= xfrm_state_hmask; i++) { 15368f126e37SDavid S. Miller hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) { 153794b9bb54SJamal Hadi Salim if (!xfrm_id_proto_match(x->id.proto, proto)) 153894b9bb54SJamal Hadi Salim continue; 153994b9bb54SJamal Hadi Salim if (last) { 154094b9bb54SJamal Hadi Salim err = func(last, count, data); 154194b9bb54SJamal Hadi Salim if (err) 154294b9bb54SJamal Hadi Salim goto out; 154394b9bb54SJamal Hadi Salim } 154494b9bb54SJamal Hadi Salim last = x; 15451da177e4SLinus Torvalds count++; 15461da177e4SLinus Torvalds } 15471da177e4SLinus Torvalds } 15481da177e4SLinus Torvalds if (count == 0) { 15491da177e4SLinus Torvalds err = -ENOENT; 15501da177e4SLinus Torvalds goto out; 15511da177e4SLinus Torvalds } 155294b9bb54SJamal Hadi Salim err = func(last, 0, data); 15531da177e4SLinus Torvalds out: 15541da177e4SLinus Torvalds spin_unlock_bh(&xfrm_state_lock); 15551da177e4SLinus Torvalds return err; 15561da177e4SLinus Torvalds } 15571da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_walk); 15581da177e4SLinus Torvalds 1559f8cd5488SJamal Hadi Salim 1560f8cd5488SJamal Hadi Salim void xfrm_replay_notify(struct xfrm_state *x, int event) 1561f8cd5488SJamal Hadi Salim { 1562f8cd5488SJamal Hadi Salim struct km_event c; 1563f8cd5488SJamal Hadi Salim /* we send notify messages in case 1564f8cd5488SJamal Hadi Salim * 1. we updated on of the sequence numbers, and the seqno difference 1565f8cd5488SJamal Hadi Salim * is at least x->replay_maxdiff, in this case we also update the 1566f8cd5488SJamal Hadi Salim * timeout of our timer function 1567f8cd5488SJamal Hadi Salim * 2. if x->replay_maxage has elapsed since last update, 1568f8cd5488SJamal Hadi Salim * and there were changes 1569f8cd5488SJamal Hadi Salim * 1570f8cd5488SJamal Hadi Salim * The state structure must be locked! 1571f8cd5488SJamal Hadi Salim */ 1572f8cd5488SJamal Hadi Salim 1573f8cd5488SJamal Hadi Salim switch (event) { 1574f8cd5488SJamal Hadi Salim case XFRM_REPLAY_UPDATE: 1575f8cd5488SJamal Hadi Salim if (x->replay_maxdiff && 1576f8cd5488SJamal Hadi Salim (x->replay.seq - x->preplay.seq < x->replay_maxdiff) && 15772717096aSJamal Hadi Salim (x->replay.oseq - x->preplay.oseq < x->replay_maxdiff)) { 15782717096aSJamal Hadi Salim if (x->xflags & XFRM_TIME_DEFER) 15792717096aSJamal Hadi Salim event = XFRM_REPLAY_TIMEOUT; 15802717096aSJamal Hadi Salim else 1581f8cd5488SJamal Hadi Salim return; 15822717096aSJamal Hadi Salim } 1583f8cd5488SJamal Hadi Salim 1584f8cd5488SJamal Hadi Salim break; 1585f8cd5488SJamal Hadi Salim 1586f8cd5488SJamal Hadi Salim case XFRM_REPLAY_TIMEOUT: 1587f8cd5488SJamal Hadi Salim if ((x->replay.seq == x->preplay.seq) && 1588f8cd5488SJamal Hadi Salim (x->replay.bitmap == x->preplay.bitmap) && 15892717096aSJamal Hadi Salim (x->replay.oseq == x->preplay.oseq)) { 15902717096aSJamal Hadi Salim x->xflags |= XFRM_TIME_DEFER; 1591f8cd5488SJamal Hadi Salim return; 15922717096aSJamal Hadi Salim } 1593f8cd5488SJamal Hadi Salim 1594f8cd5488SJamal Hadi Salim break; 1595f8cd5488SJamal Hadi Salim } 1596f8cd5488SJamal Hadi Salim 1597f8cd5488SJamal Hadi Salim memcpy(&x->preplay, &x->replay, sizeof(struct xfrm_replay_state)); 1598f8cd5488SJamal Hadi Salim c.event = XFRM_MSG_NEWAE; 1599f8cd5488SJamal Hadi Salim c.data.aevent = event; 1600f8cd5488SJamal Hadi Salim km_state_notify(x, &c); 1601f8cd5488SJamal Hadi Salim 1602f8cd5488SJamal Hadi Salim if (x->replay_maxage && 1603a47f0ce0SDavid S. Miller !mod_timer(&x->rtimer, jiffies + x->replay_maxage)) 16042717096aSJamal Hadi Salim x->xflags &= ~XFRM_TIME_DEFER; 16052717096aSJamal Hadi Salim } 1606f8cd5488SJamal Hadi Salim 1607f8cd5488SJamal Hadi Salim static void xfrm_replay_timer_handler(unsigned long data) 1608f8cd5488SJamal Hadi Salim { 1609f8cd5488SJamal Hadi Salim struct xfrm_state *x = (struct xfrm_state*)data; 1610f8cd5488SJamal Hadi Salim 1611f8cd5488SJamal Hadi Salim spin_lock(&x->lock); 1612f8cd5488SJamal Hadi Salim 16132717096aSJamal Hadi Salim if (x->km.state == XFRM_STATE_VALID) { 16142717096aSJamal Hadi Salim if (xfrm_aevent_is_on()) 1615f8cd5488SJamal Hadi Salim xfrm_replay_notify(x, XFRM_REPLAY_TIMEOUT); 16162717096aSJamal Hadi Salim else 16172717096aSJamal Hadi Salim x->xflags |= XFRM_TIME_DEFER; 16182717096aSJamal Hadi Salim } 1619f8cd5488SJamal Hadi Salim 1620f8cd5488SJamal Hadi Salim spin_unlock(&x->lock); 1621f8cd5488SJamal Hadi Salim } 1622f8cd5488SJamal Hadi Salim 1623afeb14b4SPaul Moore int xfrm_replay_check(struct xfrm_state *x, 1624afeb14b4SPaul Moore struct sk_buff *skb, __be32 net_seq) 16251da177e4SLinus Torvalds { 16261da177e4SLinus Torvalds u32 diff; 1627a252cc23SAl Viro u32 seq = ntohl(net_seq); 16281da177e4SLinus Torvalds 16291da177e4SLinus Torvalds if (unlikely(seq == 0)) 1630afeb14b4SPaul Moore goto err; 16311da177e4SLinus Torvalds 16321da177e4SLinus Torvalds if (likely(seq > x->replay.seq)) 16331da177e4SLinus Torvalds return 0; 16341da177e4SLinus Torvalds 16351da177e4SLinus Torvalds diff = x->replay.seq - seq; 16364c4d51a7SHerbert Xu if (diff >= min_t(unsigned int, x->props.replay_window, 16374c4d51a7SHerbert Xu sizeof(x->replay.bitmap) * 8)) { 16381da177e4SLinus Torvalds x->stats.replay_window++; 1639afeb14b4SPaul Moore goto err; 16401da177e4SLinus Torvalds } 16411da177e4SLinus Torvalds 16421da177e4SLinus Torvalds if (x->replay.bitmap & (1U << diff)) { 16431da177e4SLinus Torvalds x->stats.replay++; 1644afeb14b4SPaul Moore goto err; 16451da177e4SLinus Torvalds } 16461da177e4SLinus Torvalds return 0; 1647afeb14b4SPaul Moore 1648afeb14b4SPaul Moore err: 1649afeb14b4SPaul Moore xfrm_audit_state_replay(x, skb, net_seq); 1650afeb14b4SPaul Moore return -EINVAL; 16511da177e4SLinus Torvalds } 16521da177e4SLinus Torvalds 165361f4627bSAl Viro void xfrm_replay_advance(struct xfrm_state *x, __be32 net_seq) 16541da177e4SLinus Torvalds { 16551da177e4SLinus Torvalds u32 diff; 165661f4627bSAl Viro u32 seq = ntohl(net_seq); 16571da177e4SLinus Torvalds 16581da177e4SLinus Torvalds if (seq > x->replay.seq) { 16591da177e4SLinus Torvalds diff = seq - x->replay.seq; 16601da177e4SLinus Torvalds if (diff < x->props.replay_window) 16611da177e4SLinus Torvalds x->replay.bitmap = ((x->replay.bitmap) << diff) | 1; 16621da177e4SLinus Torvalds else 16631da177e4SLinus Torvalds x->replay.bitmap = 1; 16641da177e4SLinus Torvalds x->replay.seq = seq; 16651da177e4SLinus Torvalds } else { 16661da177e4SLinus Torvalds diff = x->replay.seq - seq; 16671da177e4SLinus Torvalds x->replay.bitmap |= (1U << diff); 16681da177e4SLinus Torvalds } 1669f8cd5488SJamal Hadi Salim 1670f8cd5488SJamal Hadi Salim if (xfrm_aevent_is_on()) 1671f8cd5488SJamal Hadi Salim xfrm_replay_notify(x, XFRM_REPLAY_UPDATE); 16721da177e4SLinus Torvalds } 16731da177e4SLinus Torvalds 1674df01812eSDenis Cheng static LIST_HEAD(xfrm_km_list); 16751da177e4SLinus Torvalds static DEFINE_RWLOCK(xfrm_km_lock); 16761da177e4SLinus Torvalds 167726b15dadSJamal Hadi Salim void km_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c) 16781da177e4SLinus Torvalds { 16791da177e4SLinus Torvalds struct xfrm_mgr *km; 16801da177e4SLinus Torvalds 168126b15dadSJamal Hadi Salim read_lock(&xfrm_km_lock); 168226b15dadSJamal Hadi Salim list_for_each_entry(km, &xfrm_km_list, list) 168326b15dadSJamal Hadi Salim if (km->notify_policy) 168426b15dadSJamal Hadi Salim km->notify_policy(xp, dir, c); 168526b15dadSJamal Hadi Salim read_unlock(&xfrm_km_lock); 168626b15dadSJamal Hadi Salim } 168726b15dadSJamal Hadi Salim 168826b15dadSJamal Hadi Salim void km_state_notify(struct xfrm_state *x, struct km_event *c) 168926b15dadSJamal Hadi Salim { 169026b15dadSJamal Hadi Salim struct xfrm_mgr *km; 169126b15dadSJamal Hadi Salim read_lock(&xfrm_km_lock); 169226b15dadSJamal Hadi Salim list_for_each_entry(km, &xfrm_km_list, list) 169326b15dadSJamal Hadi Salim if (km->notify) 169426b15dadSJamal Hadi Salim km->notify(x, c); 169526b15dadSJamal Hadi Salim read_unlock(&xfrm_km_lock); 169626b15dadSJamal Hadi Salim } 169726b15dadSJamal Hadi Salim 169826b15dadSJamal Hadi Salim EXPORT_SYMBOL(km_policy_notify); 169926b15dadSJamal Hadi Salim EXPORT_SYMBOL(km_state_notify); 170026b15dadSJamal Hadi Salim 170153bc6b4dSJamal Hadi Salim void km_state_expired(struct xfrm_state *x, int hard, u32 pid) 170226b15dadSJamal Hadi Salim { 170326b15dadSJamal Hadi Salim struct km_event c; 170426b15dadSJamal Hadi Salim 1705bf08867fSHerbert Xu c.data.hard = hard; 170653bc6b4dSJamal Hadi Salim c.pid = pid; 1707f60f6b8fSHerbert Xu c.event = XFRM_MSG_EXPIRE; 170826b15dadSJamal Hadi Salim km_state_notify(x, &c); 17091da177e4SLinus Torvalds 17101da177e4SLinus Torvalds if (hard) 17111da177e4SLinus Torvalds wake_up(&km_waitq); 17121da177e4SLinus Torvalds } 17131da177e4SLinus Torvalds 171453bc6b4dSJamal Hadi Salim EXPORT_SYMBOL(km_state_expired); 171526b15dadSJamal Hadi Salim /* 171626b15dadSJamal Hadi Salim * We send to all registered managers regardless of failure 171726b15dadSJamal Hadi Salim * We are happy with one success 171826b15dadSJamal Hadi Salim */ 1719980ebd25SJamal Hadi Salim int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol) 17201da177e4SLinus Torvalds { 172126b15dadSJamal Hadi Salim int err = -EINVAL, acqret; 17221da177e4SLinus Torvalds struct xfrm_mgr *km; 17231da177e4SLinus Torvalds 17241da177e4SLinus Torvalds read_lock(&xfrm_km_lock); 17251da177e4SLinus Torvalds list_for_each_entry(km, &xfrm_km_list, list) { 172626b15dadSJamal Hadi Salim acqret = km->acquire(x, t, pol, XFRM_POLICY_OUT); 172726b15dadSJamal Hadi Salim if (!acqret) 172826b15dadSJamal Hadi Salim err = acqret; 17291da177e4SLinus Torvalds } 17301da177e4SLinus Torvalds read_unlock(&xfrm_km_lock); 17311da177e4SLinus Torvalds return err; 17321da177e4SLinus Torvalds } 1733980ebd25SJamal Hadi Salim EXPORT_SYMBOL(km_query); 17341da177e4SLinus Torvalds 17355d36b180SAl Viro int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport) 17361da177e4SLinus Torvalds { 17371da177e4SLinus Torvalds int err = -EINVAL; 17381da177e4SLinus Torvalds struct xfrm_mgr *km; 17391da177e4SLinus Torvalds 17401da177e4SLinus Torvalds read_lock(&xfrm_km_lock); 17411da177e4SLinus Torvalds list_for_each_entry(km, &xfrm_km_list, list) { 17421da177e4SLinus Torvalds if (km->new_mapping) 17431da177e4SLinus Torvalds err = km->new_mapping(x, ipaddr, sport); 17441da177e4SLinus Torvalds if (!err) 17451da177e4SLinus Torvalds break; 17461da177e4SLinus Torvalds } 17471da177e4SLinus Torvalds read_unlock(&xfrm_km_lock); 17481da177e4SLinus Torvalds return err; 17491da177e4SLinus Torvalds } 17501da177e4SLinus Torvalds EXPORT_SYMBOL(km_new_mapping); 17511da177e4SLinus Torvalds 17526c5c8ca7SJamal Hadi Salim void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 pid) 17531da177e4SLinus Torvalds { 175426b15dadSJamal Hadi Salim struct km_event c; 17551da177e4SLinus Torvalds 1756bf08867fSHerbert Xu c.data.hard = hard; 17576c5c8ca7SJamal Hadi Salim c.pid = pid; 1758f60f6b8fSHerbert Xu c.event = XFRM_MSG_POLEXPIRE; 175926b15dadSJamal Hadi Salim km_policy_notify(pol, dir, &c); 17601da177e4SLinus Torvalds 17611da177e4SLinus Torvalds if (hard) 17621da177e4SLinus Torvalds wake_up(&km_waitq); 17631da177e4SLinus Torvalds } 1764a70fcb0bSDavid S. Miller EXPORT_SYMBOL(km_policy_expired); 17651da177e4SLinus Torvalds 17662d60abc2SEric Dumazet #ifdef CONFIG_XFRM_MIGRATE 176780c9abaaSShinta Sugimoto int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type, 176880c9abaaSShinta Sugimoto struct xfrm_migrate *m, int num_migrate) 176980c9abaaSShinta Sugimoto { 177080c9abaaSShinta Sugimoto int err = -EINVAL; 177180c9abaaSShinta Sugimoto int ret; 177280c9abaaSShinta Sugimoto struct xfrm_mgr *km; 177380c9abaaSShinta Sugimoto 177480c9abaaSShinta Sugimoto read_lock(&xfrm_km_lock); 177580c9abaaSShinta Sugimoto list_for_each_entry(km, &xfrm_km_list, list) { 177680c9abaaSShinta Sugimoto if (km->migrate) { 177780c9abaaSShinta Sugimoto ret = km->migrate(sel, dir, type, m, num_migrate); 177880c9abaaSShinta Sugimoto if (!ret) 177980c9abaaSShinta Sugimoto err = ret; 178080c9abaaSShinta Sugimoto } 178180c9abaaSShinta Sugimoto } 178280c9abaaSShinta Sugimoto read_unlock(&xfrm_km_lock); 178380c9abaaSShinta Sugimoto return err; 178480c9abaaSShinta Sugimoto } 178580c9abaaSShinta Sugimoto EXPORT_SYMBOL(km_migrate); 17862d60abc2SEric Dumazet #endif 178780c9abaaSShinta Sugimoto 178897a64b45SMasahide NAKAMURA int km_report(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr) 178997a64b45SMasahide NAKAMURA { 179097a64b45SMasahide NAKAMURA int err = -EINVAL; 179197a64b45SMasahide NAKAMURA int ret; 179297a64b45SMasahide NAKAMURA struct xfrm_mgr *km; 179397a64b45SMasahide NAKAMURA 179497a64b45SMasahide NAKAMURA read_lock(&xfrm_km_lock); 179597a64b45SMasahide NAKAMURA list_for_each_entry(km, &xfrm_km_list, list) { 179697a64b45SMasahide NAKAMURA if (km->report) { 179797a64b45SMasahide NAKAMURA ret = km->report(proto, sel, addr); 179897a64b45SMasahide NAKAMURA if (!ret) 179997a64b45SMasahide NAKAMURA err = ret; 180097a64b45SMasahide NAKAMURA } 180197a64b45SMasahide NAKAMURA } 180297a64b45SMasahide NAKAMURA read_unlock(&xfrm_km_lock); 180397a64b45SMasahide NAKAMURA return err; 180497a64b45SMasahide NAKAMURA } 180597a64b45SMasahide NAKAMURA EXPORT_SYMBOL(km_report); 180697a64b45SMasahide NAKAMURA 18071da177e4SLinus Torvalds int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen) 18081da177e4SLinus Torvalds { 18091da177e4SLinus Torvalds int err; 18101da177e4SLinus Torvalds u8 *data; 18111da177e4SLinus Torvalds struct xfrm_mgr *km; 18121da177e4SLinus Torvalds struct xfrm_policy *pol = NULL; 18131da177e4SLinus Torvalds 18141da177e4SLinus Torvalds if (optlen <= 0 || optlen > PAGE_SIZE) 18151da177e4SLinus Torvalds return -EMSGSIZE; 18161da177e4SLinus Torvalds 18171da177e4SLinus Torvalds data = kmalloc(optlen, GFP_KERNEL); 18181da177e4SLinus Torvalds if (!data) 18191da177e4SLinus Torvalds return -ENOMEM; 18201da177e4SLinus Torvalds 18211da177e4SLinus Torvalds err = -EFAULT; 18221da177e4SLinus Torvalds if (copy_from_user(data, optval, optlen)) 18231da177e4SLinus Torvalds goto out; 18241da177e4SLinus Torvalds 18251da177e4SLinus Torvalds err = -EINVAL; 18261da177e4SLinus Torvalds read_lock(&xfrm_km_lock); 18271da177e4SLinus Torvalds list_for_each_entry(km, &xfrm_km_list, list) { 1828cb969f07SVenkat Yekkirala pol = km->compile_policy(sk, optname, data, 18291da177e4SLinus Torvalds optlen, &err); 18301da177e4SLinus Torvalds if (err >= 0) 18311da177e4SLinus Torvalds break; 18321da177e4SLinus Torvalds } 18331da177e4SLinus Torvalds read_unlock(&xfrm_km_lock); 18341da177e4SLinus Torvalds 18351da177e4SLinus Torvalds if (err >= 0) { 18361da177e4SLinus Torvalds xfrm_sk_policy_insert(sk, err, pol); 18371da177e4SLinus Torvalds xfrm_pol_put(pol); 18381da177e4SLinus Torvalds err = 0; 18391da177e4SLinus Torvalds } 18401da177e4SLinus Torvalds 18411da177e4SLinus Torvalds out: 18421da177e4SLinus Torvalds kfree(data); 18431da177e4SLinus Torvalds return err; 18441da177e4SLinus Torvalds } 18451da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_user_policy); 18461da177e4SLinus Torvalds 18471da177e4SLinus Torvalds int xfrm_register_km(struct xfrm_mgr *km) 18481da177e4SLinus Torvalds { 18491da177e4SLinus Torvalds write_lock_bh(&xfrm_km_lock); 18501da177e4SLinus Torvalds list_add_tail(&km->list, &xfrm_km_list); 18511da177e4SLinus Torvalds write_unlock_bh(&xfrm_km_lock); 18521da177e4SLinus Torvalds return 0; 18531da177e4SLinus Torvalds } 18541da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_register_km); 18551da177e4SLinus Torvalds 18561da177e4SLinus Torvalds int xfrm_unregister_km(struct xfrm_mgr *km) 18571da177e4SLinus Torvalds { 18581da177e4SLinus Torvalds write_lock_bh(&xfrm_km_lock); 18591da177e4SLinus Torvalds list_del(&km->list); 18601da177e4SLinus Torvalds write_unlock_bh(&xfrm_km_lock); 18611da177e4SLinus Torvalds return 0; 18621da177e4SLinus Torvalds } 18631da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_unregister_km); 18641da177e4SLinus Torvalds 18651da177e4SLinus Torvalds int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo) 18661da177e4SLinus Torvalds { 18671da177e4SLinus Torvalds int err = 0; 18681da177e4SLinus Torvalds if (unlikely(afinfo == NULL)) 18691da177e4SLinus Torvalds return -EINVAL; 18701da177e4SLinus Torvalds if (unlikely(afinfo->family >= NPROTO)) 18711da177e4SLinus Torvalds return -EAFNOSUPPORT; 1872f3111502SIngo Molnar write_lock_bh(&xfrm_state_afinfo_lock); 18731da177e4SLinus Torvalds if (unlikely(xfrm_state_afinfo[afinfo->family] != NULL)) 18741da177e4SLinus Torvalds err = -ENOBUFS; 1875edcd5821SDavid S. Miller else 18761da177e4SLinus Torvalds xfrm_state_afinfo[afinfo->family] = afinfo; 1877f3111502SIngo Molnar write_unlock_bh(&xfrm_state_afinfo_lock); 18781da177e4SLinus Torvalds return err; 18791da177e4SLinus Torvalds } 18801da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_register_afinfo); 18811da177e4SLinus Torvalds 18821da177e4SLinus Torvalds int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo) 18831da177e4SLinus Torvalds { 18841da177e4SLinus Torvalds int err = 0; 18851da177e4SLinus Torvalds if (unlikely(afinfo == NULL)) 18861da177e4SLinus Torvalds return -EINVAL; 18871da177e4SLinus Torvalds if (unlikely(afinfo->family >= NPROTO)) 18881da177e4SLinus Torvalds return -EAFNOSUPPORT; 1889f3111502SIngo Molnar write_lock_bh(&xfrm_state_afinfo_lock); 18901da177e4SLinus Torvalds if (likely(xfrm_state_afinfo[afinfo->family] != NULL)) { 18911da177e4SLinus Torvalds if (unlikely(xfrm_state_afinfo[afinfo->family] != afinfo)) 18921da177e4SLinus Torvalds err = -EINVAL; 1893edcd5821SDavid S. Miller else 18941da177e4SLinus Torvalds xfrm_state_afinfo[afinfo->family] = NULL; 18951da177e4SLinus Torvalds } 1896f3111502SIngo Molnar write_unlock_bh(&xfrm_state_afinfo_lock); 18971da177e4SLinus Torvalds return err; 18981da177e4SLinus Torvalds } 18991da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_unregister_afinfo); 19001da177e4SLinus Torvalds 190117c2a42aSHerbert Xu static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family) 19021da177e4SLinus Torvalds { 19031da177e4SLinus Torvalds struct xfrm_state_afinfo *afinfo; 19041da177e4SLinus Torvalds if (unlikely(family >= NPROTO)) 19051da177e4SLinus Torvalds return NULL; 19061da177e4SLinus Torvalds read_lock(&xfrm_state_afinfo_lock); 19071da177e4SLinus Torvalds afinfo = xfrm_state_afinfo[family]; 1908546be240SHerbert Xu if (unlikely(!afinfo)) 19091da177e4SLinus Torvalds read_unlock(&xfrm_state_afinfo_lock); 19101da177e4SLinus Torvalds return afinfo; 19111da177e4SLinus Torvalds } 19121da177e4SLinus Torvalds 191317c2a42aSHerbert Xu static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo) 19149a429c49SEric Dumazet __releases(xfrm_state_afinfo_lock) 19151da177e4SLinus Torvalds { 1916546be240SHerbert Xu read_unlock(&xfrm_state_afinfo_lock); 19171da177e4SLinus Torvalds } 19181da177e4SLinus Torvalds 19191da177e4SLinus Torvalds /* Temporarily located here until net/xfrm/xfrm_tunnel.c is created */ 19201da177e4SLinus Torvalds void xfrm_state_delete_tunnel(struct xfrm_state *x) 19211da177e4SLinus Torvalds { 19221da177e4SLinus Torvalds if (x->tunnel) { 19231da177e4SLinus Torvalds struct xfrm_state *t = x->tunnel; 19241da177e4SLinus Torvalds 19251da177e4SLinus Torvalds if (atomic_read(&t->tunnel_users) == 2) 19261da177e4SLinus Torvalds xfrm_state_delete(t); 19271da177e4SLinus Torvalds atomic_dec(&t->tunnel_users); 19281da177e4SLinus Torvalds xfrm_state_put(t); 19291da177e4SLinus Torvalds x->tunnel = NULL; 19301da177e4SLinus Torvalds } 19311da177e4SLinus Torvalds } 19321da177e4SLinus Torvalds EXPORT_SYMBOL(xfrm_state_delete_tunnel); 19331da177e4SLinus Torvalds 19341da177e4SLinus Torvalds int xfrm_state_mtu(struct xfrm_state *x, int mtu) 19351da177e4SLinus Torvalds { 1936c5c25238SPatrick McHardy int res; 19371da177e4SLinus Torvalds 19381da177e4SLinus Torvalds spin_lock_bh(&x->lock); 19391da177e4SLinus Torvalds if (x->km.state == XFRM_STATE_VALID && 1940c5c25238SPatrick McHardy x->type && x->type->get_mtu) 1941c5c25238SPatrick McHardy res = x->type->get_mtu(x, mtu); 19421da177e4SLinus Torvalds else 194328121617SPatrick McHardy res = mtu - x->props.header_len; 19441da177e4SLinus Torvalds spin_unlock_bh(&x->lock); 19451da177e4SLinus Torvalds return res; 19461da177e4SLinus Torvalds } 19471da177e4SLinus Torvalds 194872cb6962SHerbert Xu int xfrm_init_state(struct xfrm_state *x) 194972cb6962SHerbert Xu { 1950d094cd83SHerbert Xu struct xfrm_state_afinfo *afinfo; 1951df9dcb45SKazunori MIYAZAWA struct xfrm_mode *inner_mode; 1952d094cd83SHerbert Xu int family = x->props.family; 195372cb6962SHerbert Xu int err; 195472cb6962SHerbert Xu 1955d094cd83SHerbert Xu err = -EAFNOSUPPORT; 1956d094cd83SHerbert Xu afinfo = xfrm_state_get_afinfo(family); 1957d094cd83SHerbert Xu if (!afinfo) 1958d094cd83SHerbert Xu goto error; 1959d094cd83SHerbert Xu 1960d094cd83SHerbert Xu err = 0; 1961d094cd83SHerbert Xu if (afinfo->init_flags) 1962d094cd83SHerbert Xu err = afinfo->init_flags(x); 1963d094cd83SHerbert Xu 1964d094cd83SHerbert Xu xfrm_state_put_afinfo(afinfo); 1965d094cd83SHerbert Xu 1966d094cd83SHerbert Xu if (err) 1967d094cd83SHerbert Xu goto error; 1968d094cd83SHerbert Xu 1969d094cd83SHerbert Xu err = -EPROTONOSUPPORT; 1970df9dcb45SKazunori MIYAZAWA 1971df9dcb45SKazunori MIYAZAWA if (x->sel.family != AF_UNSPEC) { 1972df9dcb45SKazunori MIYAZAWA inner_mode = xfrm_get_mode(x->props.mode, x->sel.family); 1973df9dcb45SKazunori MIYAZAWA if (inner_mode == NULL) 197413996378SHerbert Xu goto error; 197513996378SHerbert Xu 1976df9dcb45SKazunori MIYAZAWA if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL) && 1977df9dcb45SKazunori MIYAZAWA family != x->sel.family) { 1978df9dcb45SKazunori MIYAZAWA xfrm_put_mode(inner_mode); 197913996378SHerbert Xu goto error; 1980df9dcb45SKazunori MIYAZAWA } 1981df9dcb45SKazunori MIYAZAWA 1982df9dcb45SKazunori MIYAZAWA x->inner_mode = inner_mode; 1983df9dcb45SKazunori MIYAZAWA } else { 1984df9dcb45SKazunori MIYAZAWA struct xfrm_mode *inner_mode_iaf; 1985df9dcb45SKazunori MIYAZAWA 1986df9dcb45SKazunori MIYAZAWA inner_mode = xfrm_get_mode(x->props.mode, AF_INET); 1987df9dcb45SKazunori MIYAZAWA if (inner_mode == NULL) 1988df9dcb45SKazunori MIYAZAWA goto error; 1989df9dcb45SKazunori MIYAZAWA 1990df9dcb45SKazunori MIYAZAWA if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL)) { 1991df9dcb45SKazunori MIYAZAWA xfrm_put_mode(inner_mode); 1992df9dcb45SKazunori MIYAZAWA goto error; 1993df9dcb45SKazunori MIYAZAWA } 1994df9dcb45SKazunori MIYAZAWA 1995df9dcb45SKazunori MIYAZAWA inner_mode_iaf = xfrm_get_mode(x->props.mode, AF_INET6); 1996df9dcb45SKazunori MIYAZAWA if (inner_mode_iaf == NULL) 1997df9dcb45SKazunori MIYAZAWA goto error; 1998df9dcb45SKazunori MIYAZAWA 1999df9dcb45SKazunori MIYAZAWA if (!(inner_mode_iaf->flags & XFRM_MODE_FLAG_TUNNEL)) { 2000df9dcb45SKazunori MIYAZAWA xfrm_put_mode(inner_mode_iaf); 2001df9dcb45SKazunori MIYAZAWA goto error; 2002df9dcb45SKazunori MIYAZAWA } 2003df9dcb45SKazunori MIYAZAWA 2004df9dcb45SKazunori MIYAZAWA if (x->props.family == AF_INET) { 2005df9dcb45SKazunori MIYAZAWA x->inner_mode = inner_mode; 2006df9dcb45SKazunori MIYAZAWA x->inner_mode_iaf = inner_mode_iaf; 2007df9dcb45SKazunori MIYAZAWA } else { 2008df9dcb45SKazunori MIYAZAWA x->inner_mode = inner_mode_iaf; 2009df9dcb45SKazunori MIYAZAWA x->inner_mode_iaf = inner_mode; 2010df9dcb45SKazunori MIYAZAWA } 2011df9dcb45SKazunori MIYAZAWA } 201213996378SHerbert Xu 2013d094cd83SHerbert Xu x->type = xfrm_get_type(x->id.proto, family); 201472cb6962SHerbert Xu if (x->type == NULL) 201572cb6962SHerbert Xu goto error; 201672cb6962SHerbert Xu 201772cb6962SHerbert Xu err = x->type->init_state(x); 201872cb6962SHerbert Xu if (err) 201972cb6962SHerbert Xu goto error; 202072cb6962SHerbert Xu 202113996378SHerbert Xu x->outer_mode = xfrm_get_mode(x->props.mode, family); 202213996378SHerbert Xu if (x->outer_mode == NULL) 2023b59f45d0SHerbert Xu goto error; 2024b59f45d0SHerbert Xu 202572cb6962SHerbert Xu x->km.state = XFRM_STATE_VALID; 202672cb6962SHerbert Xu 202772cb6962SHerbert Xu error: 202872cb6962SHerbert Xu return err; 202972cb6962SHerbert Xu } 203072cb6962SHerbert Xu 203172cb6962SHerbert Xu EXPORT_SYMBOL(xfrm_init_state); 20321da177e4SLinus Torvalds 20331da177e4SLinus Torvalds void __init xfrm_state_init(void) 20341da177e4SLinus Torvalds { 2035f034b5d4SDavid S. Miller unsigned int sz; 20361da177e4SLinus Torvalds 2037f034b5d4SDavid S. Miller sz = sizeof(struct hlist_head) * 8; 2038f034b5d4SDavid S. Miller 203944e36b42SDavid S. Miller xfrm_state_bydst = xfrm_hash_alloc(sz); 204044e36b42SDavid S. Miller xfrm_state_bysrc = xfrm_hash_alloc(sz); 204144e36b42SDavid S. Miller xfrm_state_byspi = xfrm_hash_alloc(sz); 2042f034b5d4SDavid S. Miller if (!xfrm_state_bydst || !xfrm_state_bysrc || !xfrm_state_byspi) 2043f034b5d4SDavid S. Miller panic("XFRM: Cannot allocate bydst/bysrc/byspi hashes."); 2044f034b5d4SDavid S. Miller xfrm_state_hmask = ((sz / sizeof(struct hlist_head)) - 1); 2045f034b5d4SDavid S. Miller 2046c4028958SDavid Howells INIT_WORK(&xfrm_state_gc_work, xfrm_state_gc_task); 20471da177e4SLinus Torvalds } 20481da177e4SLinus Torvalds 2049ab5f5e8bSJoy Latten #ifdef CONFIG_AUDITSYSCALL 2050cf35f43eSIlpo Järvinen static void xfrm_audit_helper_sainfo(struct xfrm_state *x, 2051ab5f5e8bSJoy Latten struct audit_buffer *audit_buf) 2052ab5f5e8bSJoy Latten { 205368277accSPaul Moore struct xfrm_sec_ctx *ctx = x->security; 205468277accSPaul Moore u32 spi = ntohl(x->id.spi); 205568277accSPaul Moore 205668277accSPaul Moore if (ctx) 2057ab5f5e8bSJoy Latten audit_log_format(audit_buf, " sec_alg=%u sec_doi=%u sec_obj=%s", 205868277accSPaul Moore ctx->ctx_alg, ctx->ctx_doi, ctx->ctx_str); 2059ab5f5e8bSJoy Latten 2060ab5f5e8bSJoy Latten switch(x->props.family) { 2061ab5f5e8bSJoy Latten case AF_INET: 206268277accSPaul Moore audit_log_format(audit_buf, 206368277accSPaul Moore " src=" NIPQUAD_FMT " dst=" NIPQUAD_FMT, 2064ab5f5e8bSJoy Latten NIPQUAD(x->props.saddr.a4), 2065ab5f5e8bSJoy Latten NIPQUAD(x->id.daddr.a4)); 2066ab5f5e8bSJoy Latten break; 2067ab5f5e8bSJoy Latten case AF_INET6: 2068ab5f5e8bSJoy Latten audit_log_format(audit_buf, 2069ab5f5e8bSJoy Latten " src=" NIP6_FMT " dst=" NIP6_FMT, 207068277accSPaul Moore NIP6(*(struct in6_addr *)x->props.saddr.a6), 207168277accSPaul Moore NIP6(*(struct in6_addr *)x->id.daddr.a6)); 2072ab5f5e8bSJoy Latten break; 2073ab5f5e8bSJoy Latten } 207468277accSPaul Moore 207568277accSPaul Moore audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi); 2076ab5f5e8bSJoy Latten } 2077ab5f5e8bSJoy Latten 2078cf35f43eSIlpo Järvinen static void xfrm_audit_helper_pktinfo(struct sk_buff *skb, u16 family, 2079afeb14b4SPaul Moore struct audit_buffer *audit_buf) 2080afeb14b4SPaul Moore { 2081afeb14b4SPaul Moore struct iphdr *iph4; 2082afeb14b4SPaul Moore struct ipv6hdr *iph6; 2083afeb14b4SPaul Moore 2084afeb14b4SPaul Moore switch (family) { 2085afeb14b4SPaul Moore case AF_INET: 2086afeb14b4SPaul Moore iph4 = ip_hdr(skb); 2087afeb14b4SPaul Moore audit_log_format(audit_buf, 2088afeb14b4SPaul Moore " src=" NIPQUAD_FMT " dst=" NIPQUAD_FMT, 2089afeb14b4SPaul Moore NIPQUAD(iph4->saddr), 2090afeb14b4SPaul Moore NIPQUAD(iph4->daddr)); 2091afeb14b4SPaul Moore break; 2092afeb14b4SPaul Moore case AF_INET6: 2093afeb14b4SPaul Moore iph6 = ipv6_hdr(skb); 2094afeb14b4SPaul Moore audit_log_format(audit_buf, 2095afeb14b4SPaul Moore " src=" NIP6_FMT " dst=" NIP6_FMT 2096afeb14b4SPaul Moore " flowlbl=0x%x%x%x", 2097afeb14b4SPaul Moore NIP6(iph6->saddr), 2098afeb14b4SPaul Moore NIP6(iph6->daddr), 2099afeb14b4SPaul Moore iph6->flow_lbl[0] & 0x0f, 2100afeb14b4SPaul Moore iph6->flow_lbl[1], 2101afeb14b4SPaul Moore iph6->flow_lbl[2]); 2102afeb14b4SPaul Moore break; 2103afeb14b4SPaul Moore } 2104afeb14b4SPaul Moore } 2105afeb14b4SPaul Moore 210668277accSPaul Moore void xfrm_audit_state_add(struct xfrm_state *x, int result, 210768277accSPaul Moore u32 auid, u32 secid) 2108ab5f5e8bSJoy Latten { 2109ab5f5e8bSJoy Latten struct audit_buffer *audit_buf; 2110ab5f5e8bSJoy Latten 2111afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SAD-add"); 2112ab5f5e8bSJoy Latten if (audit_buf == NULL) 2113ab5f5e8bSJoy Latten return; 2114afeb14b4SPaul Moore xfrm_audit_helper_usrinfo(auid, secid, audit_buf); 2115afeb14b4SPaul Moore xfrm_audit_helper_sainfo(x, audit_buf); 2116afeb14b4SPaul Moore audit_log_format(audit_buf, " res=%u", result); 2117ab5f5e8bSJoy Latten audit_log_end(audit_buf); 2118ab5f5e8bSJoy Latten } 2119ab5f5e8bSJoy Latten EXPORT_SYMBOL_GPL(xfrm_audit_state_add); 2120ab5f5e8bSJoy Latten 212168277accSPaul Moore void xfrm_audit_state_delete(struct xfrm_state *x, int result, 212268277accSPaul Moore u32 auid, u32 secid) 2123ab5f5e8bSJoy Latten { 2124ab5f5e8bSJoy Latten struct audit_buffer *audit_buf; 2125ab5f5e8bSJoy Latten 2126afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SAD-delete"); 2127ab5f5e8bSJoy Latten if (audit_buf == NULL) 2128ab5f5e8bSJoy Latten return; 2129afeb14b4SPaul Moore xfrm_audit_helper_usrinfo(auid, secid, audit_buf); 2130afeb14b4SPaul Moore xfrm_audit_helper_sainfo(x, audit_buf); 2131afeb14b4SPaul Moore audit_log_format(audit_buf, " res=%u", result); 2132ab5f5e8bSJoy Latten audit_log_end(audit_buf); 2133ab5f5e8bSJoy Latten } 2134ab5f5e8bSJoy Latten EXPORT_SYMBOL_GPL(xfrm_audit_state_delete); 2135afeb14b4SPaul Moore 2136afeb14b4SPaul Moore void xfrm_audit_state_replay_overflow(struct xfrm_state *x, 2137afeb14b4SPaul Moore struct sk_buff *skb) 2138afeb14b4SPaul Moore { 2139afeb14b4SPaul Moore struct audit_buffer *audit_buf; 2140afeb14b4SPaul Moore u32 spi; 2141afeb14b4SPaul Moore 2142afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SA-replay-overflow"); 2143afeb14b4SPaul Moore if (audit_buf == NULL) 2144afeb14b4SPaul Moore return; 2145afeb14b4SPaul Moore xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf); 2146afeb14b4SPaul Moore /* don't record the sequence number because it's inherent in this kind 2147afeb14b4SPaul Moore * of audit message */ 2148afeb14b4SPaul Moore spi = ntohl(x->id.spi); 2149afeb14b4SPaul Moore audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi); 2150afeb14b4SPaul Moore audit_log_end(audit_buf); 2151afeb14b4SPaul Moore } 2152afeb14b4SPaul Moore EXPORT_SYMBOL_GPL(xfrm_audit_state_replay_overflow); 2153afeb14b4SPaul Moore 2154afeb14b4SPaul Moore static void xfrm_audit_state_replay(struct xfrm_state *x, 2155afeb14b4SPaul Moore struct sk_buff *skb, __be32 net_seq) 2156afeb14b4SPaul Moore { 2157afeb14b4SPaul Moore struct audit_buffer *audit_buf; 2158afeb14b4SPaul Moore u32 spi; 2159afeb14b4SPaul Moore 2160afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SA-replayed-pkt"); 2161afeb14b4SPaul Moore if (audit_buf == NULL) 2162afeb14b4SPaul Moore return; 2163afeb14b4SPaul Moore xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf); 2164afeb14b4SPaul Moore spi = ntohl(x->id.spi); 2165afeb14b4SPaul Moore audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u", 2166afeb14b4SPaul Moore spi, spi, ntohl(net_seq)); 2167afeb14b4SPaul Moore audit_log_end(audit_buf); 2168afeb14b4SPaul Moore } 2169afeb14b4SPaul Moore 2170afeb14b4SPaul Moore void xfrm_audit_state_notfound_simple(struct sk_buff *skb, u16 family) 2171afeb14b4SPaul Moore { 2172afeb14b4SPaul Moore struct audit_buffer *audit_buf; 2173afeb14b4SPaul Moore 2174afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SA-notfound"); 2175afeb14b4SPaul Moore if (audit_buf == NULL) 2176afeb14b4SPaul Moore return; 2177afeb14b4SPaul Moore xfrm_audit_helper_pktinfo(skb, family, audit_buf); 2178afeb14b4SPaul Moore audit_log_end(audit_buf); 2179afeb14b4SPaul Moore } 2180afeb14b4SPaul Moore EXPORT_SYMBOL_GPL(xfrm_audit_state_notfound_simple); 2181afeb14b4SPaul Moore 2182afeb14b4SPaul Moore void xfrm_audit_state_notfound(struct sk_buff *skb, u16 family, 2183afeb14b4SPaul Moore __be32 net_spi, __be32 net_seq) 2184afeb14b4SPaul Moore { 2185afeb14b4SPaul Moore struct audit_buffer *audit_buf; 2186afeb14b4SPaul Moore u32 spi; 2187afeb14b4SPaul Moore 2188afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SA-notfound"); 2189afeb14b4SPaul Moore if (audit_buf == NULL) 2190afeb14b4SPaul Moore return; 2191afeb14b4SPaul Moore xfrm_audit_helper_pktinfo(skb, family, audit_buf); 2192afeb14b4SPaul Moore spi = ntohl(net_spi); 2193afeb14b4SPaul Moore audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u", 2194afeb14b4SPaul Moore spi, spi, ntohl(net_seq)); 2195afeb14b4SPaul Moore audit_log_end(audit_buf); 2196afeb14b4SPaul Moore } 2197afeb14b4SPaul Moore EXPORT_SYMBOL_GPL(xfrm_audit_state_notfound); 2198afeb14b4SPaul Moore 2199afeb14b4SPaul Moore void xfrm_audit_state_icvfail(struct xfrm_state *x, 2200afeb14b4SPaul Moore struct sk_buff *skb, u8 proto) 2201afeb14b4SPaul Moore { 2202afeb14b4SPaul Moore struct audit_buffer *audit_buf; 2203afeb14b4SPaul Moore __be32 net_spi; 2204afeb14b4SPaul Moore __be32 net_seq; 2205afeb14b4SPaul Moore 2206afeb14b4SPaul Moore audit_buf = xfrm_audit_start("SA-icv-failure"); 2207afeb14b4SPaul Moore if (audit_buf == NULL) 2208afeb14b4SPaul Moore return; 2209afeb14b4SPaul Moore xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf); 2210afeb14b4SPaul Moore if (xfrm_parse_spi(skb, proto, &net_spi, &net_seq) == 0) { 2211afeb14b4SPaul Moore u32 spi = ntohl(net_spi); 2212afeb14b4SPaul Moore audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u", 2213afeb14b4SPaul Moore spi, spi, ntohl(net_seq)); 2214afeb14b4SPaul Moore } 2215afeb14b4SPaul Moore audit_log_end(audit_buf); 2216afeb14b4SPaul Moore } 2217afeb14b4SPaul Moore EXPORT_SYMBOL_GPL(xfrm_audit_state_icvfail); 2218ab5f5e8bSJoy Latten #endif /* CONFIG_AUDITSYSCALL */ 2219