]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blobdiff - net/xfrm/xfrm_input.c
Merge branch 'for-3.15' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup
[mirror_ubuntu-zesty-kernel.git] / net / xfrm / xfrm_input.c
index 4218164f4f5e488eca0242210e5bdc270c21a433..85d1d476461257b3e248bd870cd9f7217fa21657 100644 (file)
 
 static struct kmem_cache *secpath_cachep __read_mostly;
 
+static DEFINE_SPINLOCK(xfrm_input_afinfo_lock);
+static struct xfrm_input_afinfo __rcu *xfrm_input_afinfo[NPROTO];
+
+int xfrm_input_register_afinfo(struct xfrm_input_afinfo *afinfo)
+{
+       int err = 0;
+
+       if (unlikely(afinfo == NULL))
+               return -EINVAL;
+       if (unlikely(afinfo->family >= NPROTO))
+               return -EAFNOSUPPORT;
+       spin_lock_bh(&xfrm_input_afinfo_lock);
+       if (unlikely(xfrm_input_afinfo[afinfo->family] != NULL))
+               err = -ENOBUFS;
+       else
+               rcu_assign_pointer(xfrm_input_afinfo[afinfo->family], afinfo);
+       spin_unlock_bh(&xfrm_input_afinfo_lock);
+       return err;
+}
+EXPORT_SYMBOL(xfrm_input_register_afinfo);
+
+int xfrm_input_unregister_afinfo(struct xfrm_input_afinfo *afinfo)
+{
+       int err = 0;
+
+       if (unlikely(afinfo == NULL))
+               return -EINVAL;
+       if (unlikely(afinfo->family >= NPROTO))
+               return -EAFNOSUPPORT;
+       spin_lock_bh(&xfrm_input_afinfo_lock);
+       if (likely(xfrm_input_afinfo[afinfo->family] != NULL)) {
+               if (unlikely(xfrm_input_afinfo[afinfo->family] != afinfo))
+                       err = -EINVAL;
+               else
+                       RCU_INIT_POINTER(xfrm_input_afinfo[afinfo->family], NULL);
+       }
+       spin_unlock_bh(&xfrm_input_afinfo_lock);
+       synchronize_rcu();
+       return err;
+}
+EXPORT_SYMBOL(xfrm_input_unregister_afinfo);
+
+static struct xfrm_input_afinfo *xfrm_input_get_afinfo(unsigned int family)
+{
+       struct xfrm_input_afinfo *afinfo;
+
+       if (unlikely(family >= NPROTO))
+               return NULL;
+       rcu_read_lock();
+       afinfo = rcu_dereference(xfrm_input_afinfo[family]);
+       if (unlikely(!afinfo))
+               rcu_read_unlock();
+       return afinfo;
+}
+
+static void xfrm_input_put_afinfo(struct xfrm_input_afinfo *afinfo)
+{
+       rcu_read_unlock();
+}
+
+static int xfrm_rcv_cb(struct sk_buff *skb, unsigned int family, u8 protocol,
+                      int err)
+{
+       int ret;
+       struct xfrm_input_afinfo *afinfo = xfrm_input_get_afinfo(family);
+
+       if (!afinfo)
+               return -EAFNOSUPPORT;
+
+       ret = afinfo->callback(skb, protocol, err);
+       xfrm_input_put_afinfo(afinfo);
+
+       return ret;
+}
+
 void __secpath_destroy(struct sec_path *sp)
 {
        int i;