diff options
Diffstat (limited to 'net/xfrm/xfrm_state.c')
-rw-r--r-- | net/xfrm/xfrm_state.c | 94 |
1 files changed, 84 insertions, 10 deletions
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 9955ff4da0a2..e070c3f938fb 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -21,18 +21,21 @@ #include <linux/cache.h> #include <asm/uaccess.h> #include <linux/audit.h> +#include <linux/cache.h> #include "xfrm_hash.h" struct sock *xfrm_nl; EXPORT_SYMBOL(xfrm_nl); -u32 sysctl_xfrm_aevent_etime = XFRM_AE_ETIME; +u32 sysctl_xfrm_aevent_etime __read_mostly = XFRM_AE_ETIME; EXPORT_SYMBOL(sysctl_xfrm_aevent_etime); -u32 sysctl_xfrm_aevent_rseqth = XFRM_AE_SEQT_SIZE; +u32 sysctl_xfrm_aevent_rseqth __read_mostly = XFRM_AE_SEQT_SIZE; EXPORT_SYMBOL(sysctl_xfrm_aevent_rseqth); +u32 sysctl_xfrm_acq_expires __read_mostly = 30; + /* Each xfrm_state may be linked to two tables: 1. Hash table by (spi,daddr,ah/esp) to find SA by SPI. (input,ctl) @@ -388,12 +391,48 @@ int xfrm_state_delete(struct xfrm_state *x) } EXPORT_SYMBOL(xfrm_state_delete); -void xfrm_state_flush(u8 proto, struct xfrm_audit *audit_info) +#ifdef CONFIG_SECURITY_NETWORK_XFRM +static inline int +xfrm_state_flush_secctx_check(u8 proto, struct xfrm_audit *audit_info) { - int i; - int err = 0; + int i, err = 0; + + 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 (xfrm_id_proto_match(x->id.proto, proto) && + (err = security_xfrm_state_delete(x)) != 0) { + xfrm_audit_log(audit_info->loginuid, + audit_info->secid, + AUDIT_MAC_IPSEC_DELSA, + 0, NULL, x); + + return err; + } + } + } + + return err; +} +#else +static inline int +xfrm_state_flush_secctx_check(u8 proto, struct xfrm_audit *audit_info) +{ + return 0; +} +#endif + +int xfrm_state_flush(u8 proto, struct xfrm_audit *audit_info) +{ + int i, err = 0; spin_lock_bh(&xfrm_state_lock); + err = xfrm_state_flush_secctx_check(proto, audit_info); + if (err) + goto out; + for (i = 0; i <= xfrm_state_hmask; i++) { struct hlist_node *entry; struct xfrm_state *x; @@ -416,8 +455,12 @@ restart: } } } + err = 0; + +out: spin_unlock_bh(&xfrm_state_lock); wake_up(&km_waitq); + return err; } EXPORT_SYMBOL(xfrm_state_flush); @@ -622,8 +665,8 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, family); hlist_add_head(&x->byspi, xfrm_state_byspi+h); } - x->lft.hard_add_expires_seconds = XFRM_ACQ_EXPIRES; - x->timer.expires = jiffies + XFRM_ACQ_EXPIRES*HZ; + x->lft.hard_add_expires_seconds = sysctl_xfrm_acq_expires; + x->timer.expires = jiffies + sysctl_xfrm_acq_expires*HZ; add_timer(&x->timer); xfrm_state_num++; xfrm_hash_grow_check(x->bydst.next != NULL); @@ -643,6 +686,37 @@ out: return x; } +struct xfrm_state * +xfrm_stateonly_find(xfrm_address_t *daddr, xfrm_address_t *saddr, + unsigned short family, u8 mode, u8 proto, u32 reqid) +{ + unsigned int h = xfrm_dst_hash(daddr, saddr, reqid, family); + struct xfrm_state *rx = NULL, *x = NULL; + struct hlist_node *entry; + + spin_lock(&xfrm_state_lock); + hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) { + if (x->props.family == family && + x->props.reqid == reqid && + !(x->props.flags & XFRM_STATE_WILDRECV) && + xfrm_state_addr_check(x, daddr, saddr, family) && + mode == x->props.mode && + proto == x->id.proto && + x->km.state == XFRM_STATE_VALID) { + rx = x; + break; + } + } + + if (rx) + xfrm_state_hold(rx); + spin_unlock(&xfrm_state_lock); + + + return rx; +} +EXPORT_SYMBOL(xfrm_stateonly_find); + static void __xfrm_state_insert(struct xfrm_state *x) { unsigned int h; @@ -772,9 +846,9 @@ static struct xfrm_state *__find_acq_core(unsigned short family, u8 mode, u32 re x->props.family = family; x->props.mode = mode; x->props.reqid = reqid; - x->lft.hard_add_expires_seconds = XFRM_ACQ_EXPIRES; + x->lft.hard_add_expires_seconds = sysctl_xfrm_acq_expires; xfrm_state_hold(x); - x->timer.expires = jiffies + XFRM_ACQ_EXPIRES*HZ; + x->timer.expires = jiffies + sysctl_xfrm_acq_expires*HZ; add_timer(&x->timer); hlist_add_head(&x->bydst, xfrm_state_bydst+h); h = xfrm_src_hash(daddr, saddr, family); @@ -1686,7 +1760,7 @@ int xfrm_state_mtu(struct xfrm_state *x, int mtu) x->type && x->type->get_mtu) res = x->type->get_mtu(x, mtu); else - res = mtu; + res = mtu - x->props.header_len; spin_unlock_bh(&x->lock); return res; } |