diff options
Diffstat (limited to 'net/ipv4/xfrm4_state.c')
-rw-r--r-- | net/ipv4/xfrm4_state.c | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/net/ipv4/xfrm4_state.c b/net/ipv4/xfrm4_state.c new file mode 100644 index 000000000000..223a2e83853f --- /dev/null +++ b/net/ipv4/xfrm4_state.c @@ -0,0 +1,126 @@ +/* + * xfrm4_state.c + * + * Changes: + * YOSHIFUJI Hideaki @USAGI + * Split up af-specific portion + * + */ + +#include <net/xfrm.h> +#include <linux/pfkeyv2.h> +#include <linux/ipsec.h> + +static struct xfrm_state_afinfo xfrm4_state_afinfo; + +static void +__xfrm4_init_tempsel(struct xfrm_state *x, struct flowi *fl, + struct xfrm_tmpl *tmpl, + xfrm_address_t *daddr, xfrm_address_t *saddr) +{ + x->sel.daddr.a4 = fl->fl4_dst; + x->sel.saddr.a4 = fl->fl4_src; + x->sel.dport = xfrm_flowi_dport(fl); + x->sel.dport_mask = ~0; + x->sel.sport = xfrm_flowi_sport(fl); + x->sel.sport_mask = ~0; + x->sel.prefixlen_d = 32; + x->sel.prefixlen_s = 32; + x->sel.proto = fl->proto; + x->sel.ifindex = fl->oif; + x->id = tmpl->id; + if (x->id.daddr.a4 == 0) + x->id.daddr.a4 = daddr->a4; + x->props.saddr = tmpl->saddr; + if (x->props.saddr.a4 == 0) + x->props.saddr.a4 = saddr->a4; + x->props.mode = tmpl->mode; + x->props.reqid = tmpl->reqid; + x->props.family = AF_INET; +} + +static struct xfrm_state * +__xfrm4_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto) +{ + unsigned h = __xfrm4_spi_hash(daddr, spi, proto); + struct xfrm_state *x; + + list_for_each_entry(x, xfrm4_state_afinfo.state_byspi+h, byspi) { + if (x->props.family == AF_INET && + spi == x->id.spi && + daddr->a4 == x->id.daddr.a4 && + proto == x->id.proto) { + xfrm_state_hold(x); + return x; + } + } + return NULL; +} + +static struct xfrm_state * +__xfrm4_find_acq(u8 mode, u32 reqid, u8 proto, + xfrm_address_t *daddr, xfrm_address_t *saddr, + int create) +{ + struct xfrm_state *x, *x0; + unsigned h = __xfrm4_dst_hash(daddr); + + x0 = NULL; + + list_for_each_entry(x, xfrm4_state_afinfo.state_bydst+h, bydst) { + if (x->props.family == AF_INET && + daddr->a4 == x->id.daddr.a4 && + mode == x->props.mode && + proto == x->id.proto && + saddr->a4 == x->props.saddr.a4 && + reqid == x->props.reqid && + x->km.state == XFRM_STATE_ACQ && + !x->id.spi) { + x0 = x; + break; + } + } + if (!x0 && create && (x0 = xfrm_state_alloc()) != NULL) { + x0->sel.daddr.a4 = daddr->a4; + x0->sel.saddr.a4 = saddr->a4; + x0->sel.prefixlen_d = 32; + x0->sel.prefixlen_s = 32; + x0->props.saddr.a4 = saddr->a4; + x0->km.state = XFRM_STATE_ACQ; + x0->id.daddr.a4 = daddr->a4; + x0->id.proto = proto; + x0->props.family = AF_INET; + x0->props.mode = mode; + x0->props.reqid = reqid; + x0->props.family = AF_INET; + x0->lft.hard_add_expires_seconds = XFRM_ACQ_EXPIRES; + xfrm_state_hold(x0); + x0->timer.expires = jiffies + XFRM_ACQ_EXPIRES*HZ; + add_timer(&x0->timer); + xfrm_state_hold(x0); + list_add_tail(&x0->bydst, xfrm4_state_afinfo.state_bydst+h); + wake_up(&km_waitq); + } + if (x0) + xfrm_state_hold(x0); + return x0; +} + +static struct xfrm_state_afinfo xfrm4_state_afinfo = { + .family = AF_INET, + .lock = RW_LOCK_UNLOCKED, + .init_tempsel = __xfrm4_init_tempsel, + .state_lookup = __xfrm4_state_lookup, + .find_acq = __xfrm4_find_acq, +}; + +void __init xfrm4_state_init(void) +{ + xfrm_state_register_afinfo(&xfrm4_state_afinfo); +} + +void __exit xfrm4_state_fini(void) +{ + xfrm_state_unregister_afinfo(&xfrm4_state_afinfo); +} + |