|
@@ -16,6 +16,81 @@
|
|
|
|
|
|
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;
|