+static struct xfrm_tunnel *ipip_handler;
+static DECLARE_MUTEX(xfrm4_tunnel_sem);
+
+int xfrm4_tunnel_register(struct xfrm_tunnel *handler)
+{
+ int ret;
+
+ down(&xfrm4_tunnel_sem);
+ ret = 0;
+ if (ipip_handler != NULL)
+ ret = -EINVAL;
+ if (!ret)
+ ipip_handler = handler;
+ up(&xfrm4_tunnel_sem);
+
+ return ret;
+}
+
+EXPORT_SYMBOL(xfrm4_tunnel_register);
+
+int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler)
+{
+ int ret;
+
+ down(&xfrm4_tunnel_sem);
+ ret = 0;
+ if (ipip_handler != handler)
+ ret = -EINVAL;
+ if (!ret)
+ ipip_handler = NULL;
+ up(&xfrm4_tunnel_sem);
+
+ synchronize_net();
+
+ return ret;
+}
+
+EXPORT_SYMBOL(xfrm4_tunnel_deregister);
+
+static int ipip_rcv(struct sk_buff *skb)
+{
+ struct xfrm_tunnel *handler = ipip_handler;
+
+ /* Tunnel devices take precedence. */
+ if (handler && handler->handler(skb) == 0)
+ return 0;
+
+ return xfrm4_rcv(skb);
+}
+
+static void ipip_err(struct sk_buff *skb, u32 info)
+{
+ struct xfrm_tunnel *handler = ipip_handler;
+
+ if (handler)
+ handler->err_handler(skb, info);
+}
+