📄 xfrm_state.c
字号:
xfrm_hash_grow_check(x->bydst.next != NULL); } return x;}static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq);int xfrm_state_add(struct xfrm_state *x){ struct xfrm_state *x1; int family; int err; int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY); family = x->props.family; spin_lock_bh(&xfrm_state_lock); x1 = __xfrm_state_locate(x, use_spi, family); if (x1) { xfrm_state_put(x1); x1 = NULL; err = -EEXIST; goto out; } if (use_spi && x->km.seq) { x1 = __xfrm_find_acq_byseq(x->km.seq); if (x1 && ((x1->id.proto != x->id.proto) || xfrm_addr_cmp(&x1->id.daddr, &x->id.daddr, family))) { xfrm_state_put(x1); x1 = NULL; } } if (use_spi && !x1) x1 = __find_acq_core(family, x->props.mode, x->props.reqid, x->id.proto, &x->id.daddr, &x->props.saddr, 0); __xfrm_state_bump_genids(x); __xfrm_state_insert(x); err = 0;out: spin_unlock_bh(&xfrm_state_lock); if (x1) { xfrm_state_delete(x1); xfrm_state_put(x1); } return err;}EXPORT_SYMBOL(xfrm_state_add);#ifdef CONFIG_XFRM_MIGRATEstruct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp){ int err = -ENOMEM; struct xfrm_state *x = xfrm_state_alloc(); if (!x) goto error; memcpy(&x->id, &orig->id, sizeof(x->id)); memcpy(&x->sel, &orig->sel, sizeof(x->sel)); memcpy(&x->lft, &orig->lft, sizeof(x->lft)); x->props.mode = orig->props.mode; x->props.replay_window = orig->props.replay_window; x->props.reqid = orig->props.reqid; x->props.family = orig->props.family; x->props.saddr = orig->props.saddr; if (orig->aalg) { x->aalg = xfrm_algo_clone(orig->aalg); if (!x->aalg) goto error; } x->props.aalgo = orig->props.aalgo; if (orig->ealg) { x->ealg = xfrm_algo_clone(orig->ealg); if (!x->ealg) goto error; } x->props.ealgo = orig->props.ealgo; if (orig->calg) { x->calg = xfrm_algo_clone(orig->calg); if (!x->calg) goto error; } x->props.calgo = orig->props.calgo; if (orig->encap) { x->encap = kmemdup(orig->encap, sizeof(*x->encap), GFP_KERNEL); if (!x->encap) goto error; } if (orig->coaddr) { x->coaddr = kmemdup(orig->coaddr, sizeof(*x->coaddr), GFP_KERNEL); if (!x->coaddr) goto error; } err = xfrm_init_state(x); if (err) goto error; x->props.flags = orig->props.flags; x->curlft.add_time = orig->curlft.add_time; x->km.state = orig->km.state; x->km.seq = orig->km.seq; return x; error: if (errp) *errp = err; if (x) { kfree(x->aalg); kfree(x->ealg); kfree(x->calg); kfree(x->encap); kfree(x->coaddr); } kfree(x); return NULL;}EXPORT_SYMBOL(xfrm_state_clone);/* xfrm_state_lock is held */struct xfrm_state * xfrm_migrate_state_find(struct xfrm_migrate *m){ unsigned int h; struct xfrm_state *x; struct hlist_node *entry; if (m->reqid) { h = xfrm_dst_hash(&m->old_daddr, &m->old_saddr, m->reqid, m->old_family); hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) { if (x->props.mode != m->mode || x->id.proto != m->proto) continue; if (m->reqid && x->props.reqid != m->reqid) continue; if (xfrm_addr_cmp(&x->id.daddr, &m->old_daddr, m->old_family) || xfrm_addr_cmp(&x->props.saddr, &m->old_saddr, m->old_family)) continue; xfrm_state_hold(x); return x; } } else { h = xfrm_src_hash(&m->old_daddr, &m->old_saddr, m->old_family); hlist_for_each_entry(x, entry, xfrm_state_bysrc+h, bysrc) { if (x->props.mode != m->mode || x->id.proto != m->proto) continue; if (xfrm_addr_cmp(&x->id.daddr, &m->old_daddr, m->old_family) || xfrm_addr_cmp(&x->props.saddr, &m->old_saddr, m->old_family)) continue; xfrm_state_hold(x); return x; } } return NULL;}EXPORT_SYMBOL(xfrm_migrate_state_find);struct xfrm_state * xfrm_state_migrate(struct xfrm_state *x, struct xfrm_migrate *m){ struct xfrm_state *xc; int err; xc = xfrm_state_clone(x, &err); if (!xc) return NULL; memcpy(&xc->id.daddr, &m->new_daddr, sizeof(xc->id.daddr)); memcpy(&xc->props.saddr, &m->new_saddr, sizeof(xc->props.saddr)); /* add state */ if (!xfrm_addr_cmp(&x->id.daddr, &m->new_daddr, m->new_family)) { /* a care is needed when the destination address of the state is to be updated as it is a part of triplet */ xfrm_state_insert(xc); } else { if ((err = xfrm_state_add(xc)) < 0) goto error; } return xc;error: kfree(xc); return NULL;}EXPORT_SYMBOL(xfrm_state_migrate);#endifint xfrm_state_update(struct xfrm_state *x){ struct xfrm_state *x1; int err; int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY); spin_lock_bh(&xfrm_state_lock); x1 = __xfrm_state_locate(x, use_spi, x->props.family); err = -ESRCH; if (!x1) goto out; if (xfrm_state_kern(x1)) { xfrm_state_put(x1); err = -EEXIST; goto out; } if (x1->km.state == XFRM_STATE_ACQ) { __xfrm_state_insert(x); x = NULL; } err = 0;out: spin_unlock_bh(&xfrm_state_lock); if (err) return err; if (!x) { xfrm_state_delete(x1); xfrm_state_put(x1); return 0; } err = -EINVAL; spin_lock_bh(&x1->lock); if (likely(x1->km.state == XFRM_STATE_VALID)) { if (x->encap && x1->encap) memcpy(x1->encap, x->encap, sizeof(*x1->encap)); if (x->coaddr && x1->coaddr) { memcpy(x1->coaddr, x->coaddr, sizeof(*x1->coaddr)); } if (!use_spi && memcmp(&x1->sel, &x->sel, sizeof(x1->sel))) memcpy(&x1->sel, &x->sel, sizeof(x1->sel)); memcpy(&x1->lft, &x->lft, sizeof(x1->lft)); x1->km.dying = 0; mod_timer(&x1->timer, jiffies + HZ); if (x1->curlft.use_time) xfrm_state_check_expire(x1); err = 0; } spin_unlock_bh(&x1->lock); xfrm_state_put(x1); return err;}EXPORT_SYMBOL(xfrm_state_update);int xfrm_state_check_expire(struct xfrm_state *x){ if (!x->curlft.use_time) x->curlft.use_time = get_seconds(); if (x->km.state != XFRM_STATE_VALID) return -EINVAL; if (x->curlft.bytes >= x->lft.hard_byte_limit || x->curlft.packets >= x->lft.hard_packet_limit) { x->km.state = XFRM_STATE_EXPIRED; mod_timer(&x->timer, jiffies); return -EINVAL; } if (!x->km.dying && (x->curlft.bytes >= x->lft.soft_byte_limit || x->curlft.packets >= x->lft.soft_packet_limit)) { x->km.dying = 1; km_state_expired(x, 0, 0); } return 0;}EXPORT_SYMBOL(xfrm_state_check_expire);struct xfrm_state *xfrm_state_lookup(xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family){ struct xfrm_state *x; spin_lock_bh(&xfrm_state_lock); x = __xfrm_state_lookup(daddr, spi, proto, family); spin_unlock_bh(&xfrm_state_lock); return x;}EXPORT_SYMBOL(xfrm_state_lookup);struct xfrm_state *xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto, unsigned short family){ struct xfrm_state *x; spin_lock_bh(&xfrm_state_lock); x = __xfrm_state_lookup_byaddr(daddr, saddr, proto, family); spin_unlock_bh(&xfrm_state_lock); return x;}EXPORT_SYMBOL(xfrm_state_lookup_byaddr);struct xfrm_state *xfrm_find_acq(u8 mode, u32 reqid, u8 proto, xfrm_address_t *daddr, xfrm_address_t *saddr, int create, unsigned short family){ struct xfrm_state *x; spin_lock_bh(&xfrm_state_lock); x = __find_acq_core(family, mode, reqid, proto, daddr, saddr, create); spin_unlock_bh(&xfrm_state_lock); return x;}EXPORT_SYMBOL(xfrm_find_acq);#ifdef CONFIG_XFRM_SUB_POLICYintxfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n, unsigned short family){ int err = 0; struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); if (!afinfo) return -EAFNOSUPPORT; spin_lock_bh(&xfrm_state_lock); if (afinfo->tmpl_sort) err = afinfo->tmpl_sort(dst, src, n); spin_unlock_bh(&xfrm_state_lock); xfrm_state_put_afinfo(afinfo); return err;}EXPORT_SYMBOL(xfrm_tmpl_sort);intxfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n, unsigned short family){ int err = 0; struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); if (!afinfo) return -EAFNOSUPPORT; spin_lock_bh(&xfrm_state_lock); if (afinfo->state_sort) err = afinfo->state_sort(dst, src, n); spin_unlock_bh(&xfrm_state_lock); xfrm_state_put_afinfo(afinfo); return err;}EXPORT_SYMBOL(xfrm_state_sort);#endif/* Silly enough, but I'm lazy to build resolution list */static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq){ int i; for (i = 0; i <= xfrm_state_hmask; i++) { struct hlist_node *entry; struct xfrm_state *x; hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) { if (x->km.seq == seq && x->km.state == XFRM_STATE_ACQ) { xfrm_state_hold(x); return x; } } } return NULL;}struct xfrm_state *xfrm_find_acq_byseq(u32 seq){ struct xfrm_state *x; spin_lock_bh(&xfrm_state_lock); x = __xfrm_find_acq_byseq(seq); spin_unlock_bh(&xfrm_state_lock); return x;}EXPORT_SYMBOL(xfrm_find_acq_byseq);u32 xfrm_get_acqseq(void){ u32 res; static u32 acqseq; static DEFINE_SPINLOCK(acqseq_lock); spin_lock_bh(&acqseq_lock); res = (++acqseq ? : ++acqseq); spin_unlock_bh(&acqseq_lock); return res;}EXPORT_SYMBOL(xfrm_get_acqseq);int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high){ unsigned int h; struct xfrm_state *x0; int err = -ENOENT; __be32 minspi = htonl(low); __be32 maxspi = htonl(high); spin_lock_bh(&x->lock); if (x->km.state == XFRM_STATE_DEAD) goto unlock; err = 0; if (x->id.spi) goto unlock; err = -ENOENT; if (minspi == maxspi) { x0 = xfrm_state_lookup(&x->id.daddr, minspi, x->id.proto, x->props.family); if (x0) { xfrm_state_put(x0); goto unlock; } x->id.spi = minspi; } else { u32 spi = 0; for (h=0; h<high-low+1; h++) { spi = low + net_random()%(high-low+1); x0 = xfrm_state_lookup(&x->id.daddr, htonl(spi), x->id.proto, x->props.family); if (x0 == NULL) { x->id.spi = htonl(spi); break; } xfrm_state_put(x0); } } if (x->id.spi) { spin_lock_bh(&xfrm_state_lock); h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, x->props.family); hlist_add_head(&x->byspi, xfrm_state_byspi+h); spin_unlock_bh(&xfrm_state_lock); err = 0; }unlock: spin_unlock_bh(&x->lock); return err;}EXPORT_SYMBOL(xfrm_alloc_spi);int xfrm_state_walk(u8 proto, int (*func)(struct xfrm_state *, int, void*), void *data){ int i; struct xfrm_state *x, *last = NULL; struct hlist_node *entry; int count = 0; int err = 0; spin_lock_bh(&xfrm_state_lock); for (i = 0; i <= xfrm_state_hmask; i++) { hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) { if (!xfrm_id_proto_match(x->id.proto, proto)) continue; if (last) { err = func(last, count, data); if (err) goto out; } last = x; count++; } } if (count == 0) { err = -ENOENT; goto out; } err = func(last, 0, data);out: spin_unlock_bh(&xfrm_state_lock); return err;}EXPORT_SYMBOL(xfrm_state_walk);void xfrm_replay_notify(struct xfrm_state *x, int event){ struct km_event c; /* we send notify messages in case * 1. we updated on of the sequence numbers, and the seqno difference * is at least x->replay_maxdiff, in this case we also update the
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -