* Main use is finding SA after policy selected tunnel or transport mode.
* Also, it can be used by ah/esp icmp error handler to find offending SA.
*/
+static LIST_HEAD(xfrm_state_all);
static struct hlist_head *xfrm_state_bydst __read_mostly;
static struct hlist_head *xfrm_state_bysrc __read_mostly;
static struct hlist_head *xfrm_state_byspi __read_mostly;
km_state_expired(x, 1, 0);
xfrm_audit_state_delete(x, err ? 0 : 1,
- audit_get_loginuid(current), 0);
+ audit_get_loginuid(current),
+ audit_get_sessionid(current), 0);
out:
spin_unlock(&x->lock);
if (x) {
atomic_set(&x->refcnt, 1);
atomic_set(&x->tunnel_users, 0);
+ INIT_LIST_HEAD(&x->all);
INIT_HLIST_NODE(&x->bydst);
INIT_HLIST_NODE(&x->bysrc);
INIT_HLIST_NODE(&x->byspi);
void __xfrm_state_destroy(struct xfrm_state *x)
{
- BUG_TRAP(x->km.state == XFRM_STATE_DEAD);
+ WARN_ON(x->km.state != XFRM_STATE_DEAD);
+
+ spin_lock_bh(&xfrm_state_lock);
+ list_del(&x->all);
+ spin_unlock_bh(&xfrm_state_lock);
spin_lock_bh(&xfrm_state_gc_lock);
hlist_add_head(&x->bydst, &xfrm_state_gc_list);
(err = security_xfrm_state_delete(x)) != 0) {
xfrm_audit_state_delete(x, 0,
audit_info->loginuid,
+ audit_info->sessionid,
audit_info->secid);
return err;
}
err = xfrm_state_delete(x);
xfrm_audit_state_delete(x, err ? 0 : 1,
audit_info->loginuid,
+ audit_info->sessionid,
audit_info->secid);
xfrm_state_put(x);
{
unsigned int h;
struct hlist_node *entry;
- struct xfrm_state *x, *x0;
+ struct xfrm_state *x, *x0, *to_put;
int acquire_in_progress = 0;
int error = 0;
struct xfrm_state *best = NULL;
+ to_put = NULL;
+
spin_lock_bh(&xfrm_state_lock);
h = xfrm_dst_hash(daddr, saddr, tmpl->reqid, family);
hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) {
if (tmpl->id.spi &&
(x0 = __xfrm_state_lookup(daddr, tmpl->id.spi,
tmpl->id.proto, family)) != NULL) {
- xfrm_state_put(x0);
+ to_put = x0;
error = -EEXIST;
goto out;
}
error = security_xfrm_state_alloc_acquire(x, pol->security, fl->secid);
if (error) {
x->km.state = XFRM_STATE_DEAD;
- xfrm_state_put(x);
+ to_put = x;
x = NULL;
goto out;
}
if (km_query(x, tmpl, pol) == 0) {
x->km.state = XFRM_STATE_ACQ;
+ list_add_tail(&x->all, &xfrm_state_all);
hlist_add_head(&x->bydst, xfrm_state_bydst+h);
h = xfrm_src_hash(daddr, saddr, family);
hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
xfrm_hash_grow_check(x->bydst.next != NULL);
} else {
x->km.state = XFRM_STATE_DEAD;
- xfrm_state_put(x);
+ to_put = x;
x = NULL;
error = -ESRCH;
}
else
*err = acquire_in_progress ? -EAGAIN : error;
spin_unlock_bh(&xfrm_state_lock);
+ if (to_put)
+ xfrm_state_put(to_put);
return x;
}
x->genid = ++xfrm_state_genid;
+ list_add_tail(&x->all, &xfrm_state_all);
+
h = xfrm_dst_hash(&x->id.daddr, &x->props.saddr,
x->props.reqid, x->props.family);
hlist_add_head(&x->bydst, xfrm_state_bydst+h);
xfrm_state_hold(x);
x->timer.expires = jiffies + sysctl_xfrm_acq_expires*HZ;
add_timer(&x->timer);
+ list_add_tail(&x->all, &xfrm_state_all);
hlist_add_head(&x->bydst, xfrm_state_bydst+h);
h = xfrm_src_hash(daddr, saddr, family);
hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
int xfrm_state_add(struct xfrm_state *x)
{
- struct xfrm_state *x1;
+ struct xfrm_state *x1, *to_put;
int family;
int err;
int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY);
family = x->props.family;
+ to_put = NULL;
+
spin_lock_bh(&xfrm_state_lock);
x1 = __xfrm_state_locate(x, use_spi, family);
if (x1) {
- xfrm_state_put(x1);
+ to_put = x1;
x1 = NULL;
err = -EEXIST;
goto out;
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);
+ to_put = x1;
x1 = NULL;
}
}
xfrm_state_put(x1);
}
+ if (to_put)
+ xfrm_state_put(to_put);
+
return err;
}
EXPORT_SYMBOL(xfrm_state_add);
int xfrm_state_update(struct xfrm_state *x)
{
- struct xfrm_state *x1;
+ struct xfrm_state *x1, *to_put;
int err;
int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY);
+ to_put = NULL;
+
spin_lock_bh(&xfrm_state_lock);
x1 = __xfrm_state_locate(x, use_spi, x->props.family);
goto out;
if (xfrm_state_kern(x1)) {
- xfrm_state_put(x1);
+ to_put = x1;
err = -EEXIST;
goto out;
}
out:
spin_unlock_bh(&xfrm_state_lock);
+ if (to_put)
+ xfrm_state_put(to_put);
+
if (err)
return err;
}
EXPORT_SYMBOL(xfrm_alloc_spi);
-int xfrm_state_walk(u8 proto, int (*func)(struct xfrm_state *, int, void*),
+int xfrm_state_walk(struct xfrm_state_walk *walk,
+ int (*func)(struct xfrm_state *, int, void*),
void *data)
{
- int i;
- struct xfrm_state *x, *last = NULL;
- struct hlist_node *entry;
- int count = 0;
+ struct xfrm_state *old, *x, *last = NULL;
int err = 0;
+ if (walk->state == NULL && walk->count != 0)
+ return 0;
+
+ old = x = walk->state;
+ walk->state = NULL;
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;
+ if (x == NULL)
+ x = list_first_entry(&xfrm_state_all, struct xfrm_state, all);
+ list_for_each_entry_from(x, &xfrm_state_all, all) {
+ if (x->km.state == XFRM_STATE_DEAD)
+ continue;
+ if (!xfrm_id_proto_match(x->id.proto, walk->proto))
+ continue;
+ if (last) {
+ err = func(last, walk->count, data);
+ if (err) {
+ xfrm_state_hold(last);
+ walk->state = last;
+ goto out;
}
- last = x;
- count++;
}
+ last = x;
+ walk->count++;
}
- if (count == 0) {
+ if (walk->count == 0) {
err = -ENOENT;
goto out;
}
- err = func(last, 0, data);
+ if (last)
+ err = func(last, 0, data);
out:
spin_unlock_bh(&xfrm_state_lock);
+ if (old != NULL)
+ xfrm_state_put(old);
return err;
}
EXPORT_SYMBOL(xfrm_state_walk);
iph6 = ipv6_hdr(skb);
audit_log_format(audit_buf,
" src=" NIP6_FMT " dst=" NIP6_FMT
- " flowlbl=0x%x%x%x",
+ " flowlbl=0x%x%02x%02x",
NIP6(iph6->saddr),
NIP6(iph6->daddr),
iph6->flow_lbl[0] & 0x0f,
}
void xfrm_audit_state_add(struct xfrm_state *x, int result,
- u32 auid, u32 secid)
+ uid_t auid, u32 sessionid, u32 secid)
{
struct audit_buffer *audit_buf;
audit_buf = xfrm_audit_start("SAD-add");
if (audit_buf == NULL)
return;
- xfrm_audit_helper_usrinfo(auid, secid, audit_buf);
+ xfrm_audit_helper_usrinfo(auid, sessionid, secid, audit_buf);
xfrm_audit_helper_sainfo(x, audit_buf);
audit_log_format(audit_buf, " res=%u", result);
audit_log_end(audit_buf);
EXPORT_SYMBOL_GPL(xfrm_audit_state_add);
void xfrm_audit_state_delete(struct xfrm_state *x, int result,
- u32 auid, u32 secid)
+ uid_t auid, u32 sessionid, u32 secid)
{
struct audit_buffer *audit_buf;
audit_buf = xfrm_audit_start("SAD-delete");
if (audit_buf == NULL)
return;
- xfrm_audit_helper_usrinfo(auid, secid, audit_buf);
+ xfrm_audit_helper_usrinfo(auid, sessionid, secid, audit_buf);
xfrm_audit_helper_sainfo(x, audit_buf);
audit_log_format(audit_buf, " res=%u", result);
audit_log_end(audit_buf);