Merge branch 'linus' into core/generic-dma-coherent
[pandora-kernel.git] / net / xfrm / xfrm_state.c
index 58f1f93..4c6914e 100644 (file)
@@ -50,6 +50,7 @@ static DEFINE_SPINLOCK(xfrm_state_lock);
  * 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;
@@ -495,7 +496,8 @@ expired:
                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);
@@ -512,6 +514,7 @@ struct xfrm_state *xfrm_state_alloc(void)
        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);
@@ -535,7 +538,11 @@ EXPORT_SYMBOL(xfrm_state_alloc);
 
 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);
@@ -597,6 +604,7 @@ xfrm_state_flush_secctx_check(u8 proto, struct xfrm_audit *audit_info)
                           (err = security_xfrm_state_delete(x)) != 0) {
                                xfrm_audit_state_delete(x, 0,
                                                        audit_info->loginuid,
+                                                       audit_info->sessionid,
                                                        audit_info->secid);
                                return err;
                        }
@@ -635,6 +643,7 @@ restart:
                                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);
 
@@ -913,6 +922,8 @@ static void __xfrm_state_insert(struct xfrm_state *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);
@@ -1522,36 +1533,47 @@ unlock:
 }
 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);
@@ -2093,7 +2115,7 @@ static void xfrm_audit_helper_pktinfo(struct sk_buff *skb, u16 family,
                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,
@@ -2104,14 +2126,14 @@ static void xfrm_audit_helper_pktinfo(struct sk_buff *skb, u16 family,
 }
 
 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);
@@ -2119,14 +2141,14 @@ void xfrm_audit_state_add(struct xfrm_state *x, int result,
 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);