i have plans for the gre code, but the mobileip code complicates
it. this splits mobileip out into its own driver. this makes it
easier to disable to remove in the future.

im pretty sure the current mobileip is broken too, so if you want
to test you should install it on both sides of the tunnel.

ok?

Index: share/man/man4/Makefile
===================================================================
RCS file: /cvs/src/share/man/man4/Makefile,v
retrieving revision 1.663
diff -u -p -r1.663 Makefile
--- share/man/man4/Makefile     2 Jan 2018 22:56:01 -0000       1.663
+++ share/man/man4/Makefile     30 Jan 2018 07:07:32 -0000
@@ -38,8 +38,8 @@ MAN=  aac.4 ac97.4 acphy.4 acrtc.4 \
        lmenv.4 lmn.4 lmtemp.4 lo.4 lpt.4 lxtphy.4 luphy.4 \
        maestro.4 mainbus.4 malo.4 maxds.4 maxrtc.4 maxtmp.4 mbg.4 midi.4 \
        mii.4 mfi.4 \
-       mfii.4 mlphy.4 moscom.4 mos.4 mpe.4 mpath.4 mpi.4 mpii.4 mpu.4 msk.4 \
-       mpw.4 msts.4 mtd.4 mtdphy.4 multicast.4 mtio.4 myx.4 \
+       mfii.4 mlphy.4 mobileip.4 moscom.4 mos.4 mpe.4 mpath.4 mpi.4 mpii.4 \
+       mpu.4 msk.4 mpw.4 msts.4 mtd.4 mtdphy.4 multicast.4 mtio.4 myx.4 \
        ne.4 neo.4 nep.4 netintro.4 nfe.4 nge.4 nmea.4 \
        nsclpcsio.4 nsgphy.4 nsphy.4 nsphyter.4 null.4 nviic.4 nvme.4 nvt.4 \
        oce.4 ohci.4 options.4 onewire.4 oosiop.4 osiop.4 otus.4 \
Index: share/man/man4/gre.4
===================================================================
RCS file: /cvs/src/share/man/man4/gre.4,v
retrieving revision 1.49
diff -u -p -r1.49 gre.4
--- share/man/man4/gre.4        12 Jan 2018 04:36:44 -0000      1.49
+++ share/man/man4/gre.4        30 Jan 2018 07:07:32 -0000
@@ -32,21 +32,19 @@
 .Dt GRE 4
 .Os
 .Sh NAME
-.Nm gre ,
-.Nm mobileip
+.Nm gre
 .Nd encapsulating network device
 .Sh SYNOPSIS
 .Cd "pseudo-device gre"
 .Sh DESCRIPTION
 The
 .Nm
-driver allows tunnel construction using the Cisco GRE or
-the Mobile IP (RFC 2004) encapsulation protocols.
+driver allows tunnel construction using the GRE (RFC 1701)
+encapsulation protocol.
 .Pp
-.Tn GRE ,
-.Tn WCCPv1 ,
+.Tn GRE
 and
-.Tn Mobile IP
+.Tn WCCPv1
 are enabled with the following
 .Xr sysctl 2
 variables respectively in
@@ -64,13 +62,8 @@ to do anything useful with these packets
 This sysctl requires
 .Va gre.allow
 to be set.
-.It Va net.inet.mobileip.allow
-Allow Mobile IP packets in and out of the system.
 .El
 .Pp
-This driver currently supports the following modes of operation:
-.Bl -tag -width mobileipXXX
-.It Nm gre
 GRE datagrams (IP protocol number 47)
 are prepended by an outer datagram and a GRE header.
 The GRE header specifies the type of the encapsulated datagram
@@ -80,18 +73,9 @@ GRE mode is the default tunnel mode on C
 This is also the default mode of operation of the
 .Nm
 interfaces.
-.It Nm mobileip
-MOBILE datagrams (IP protocol number 55)
-are encapsulated into IP, but with a much smaller
-encapsulation header.
-This protocol only supports IP in IP encapsulation, and is intended
-for use with Mobile IP.
-.El
 .Pp
 A
 .Nm gre
-or
-.Nm mobileip
 interface can be created at runtime using the
 .Ic ifconfig gre Ns Ar N Ic create
 command or by setting up a
@@ -225,13 +209,6 @@ pass quick on gre proto gre no state
 .%D October 1994
 .%R RFC 1702
 .%T Generic Routing Encapsulation over IPv4 networks
-.Re
-.Pp
-.Rs
-.%A C. Perkins
-.%D October 1996
-.%R RFC 2004
-.%T Minimal Encapsulation within IP
 .Re
 .Pp
 .Rs
Index: share/man/man4/mobileip.4
===================================================================
RCS file: share/man/man4/mobileip.4
diff -N share/man/man4/mobileip.4
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ share/man/man4/mobileip.4   30 Jan 2018 07:07:32 -0000
@@ -0,0 +1,139 @@
+.\"    $OpenBSD$
+.\"
+.\" Copyright (c) 2018 David Gwynne <[email protected]>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd $Mdocdate$
+.Dt MOBILEIP 4
+.Sh NAME
+.Nm mobileip
+.Nd MobileIP encapsulating network device
+.Sh SYNOPSIS
+.Cd "pseudo-device mobileip"
+.Sh DESCRIPTION
+The
+.Nm
+driver provides IP tunnel construction using
+the Mobile IP (RFC 2004) encapsulation protocol
+.Pp
+.Nm
+datagrams (IP protocol number 55)
+are encapsulated into IP using a small encapsulation header.
+This protocol according to the RFC only supports encapsulating IPv4,
+and is intended for use with Mobile IP.
+.Pp
+A
+.Nm
+interface can be created at runtime using the
+.Ic ifconfig Nm Ns Ar N Ic create
+command or by setting up a
+.Xr hostname.if 5
+configuration file for
+.Xr netstart 8 .
+.Pp
+The MTU is set to 1488 by default.
+This may not be an optimal value
+depending on the link between the two tunnel endpoints,
+but it can be adjusted via
+.Xr ifconfig 8 .
+.Pp
+For correct operation, the route to the tunnel destination must not
+go over the interface itself.
+This can be implemented by adding a distinct or a more specific
+route to the tunnel destination than the hosts or networks routed
+via the tunnel interface.
+Alternatively, the tunnel traffic may be configured in a separate
+routing table to the encapsulated traffic.
+.Pp
+.Nm
+interfaces support the following
+.Xr ioctl 2 Ns s
+for configuring tunnel options:
+.Bl -tag -width indent -offset 3n
+.It Dv SIOCSLIFPHYADDR Fa "struct if_laddrreq *"
+Set the addresses of the outer IP header.
+The addresses may only be configured while the interface is down.
+.It Dv SIOCGLIFPHYADDR Fa "struct if_laddrreq *"
+Get the addresses of the outer IP header.
+.It Dv SIOCDIFPHYADDR
+Clear the outer IP header addresses.
+The addresses may only be cleared while the interface is down.
+.It Dv SIOCSLIFPHYRTABLE Fa "struct ifreq *"
+Set the routing table the encapsulated IP packets operate within.
+The routing table may only be configured while the interface is down.
+.It Dv SIOCGLIFPHYRTABLE Fa "struct ifreq *"
+Get the routing table the encapsulated IP packets operate within.
+.El
+.Sh EXAMPLES
+Configuration example:
+.Bd -literal
+Host X --- Host A ----------- MobileIP ------------ Host D --- Host E
+              \e                                      /
+               \e                                    /
+                +------ Host B ------ Host C ------+
+.Ed
+.Pp
+On Host A
+.Pq Ox :
+.Bd -literal -offset indent
+# route add default B
+# ifconfig mobileipN create
+# ifconfig mobileipN tunnel A D
+# ifconfig mobileipN A D netmask 255.255.255.255
+# route add E D
+.Ed
+.Pp
+On Host D
+.Pq Ox :
+.Bd -literal -offset indent
+# route add default C
+# ifconfig mobileipN create
+# ifconfig mobileipN tunnel D A
+# ifconfig mobileipN D A netmask 255.255.255.255
+# route add D E
+.Ed
+.Pp
+The route domain used for the encapsulated traffic may be set using
+.Xr ifconfig 8
+and the tunneldomain argument:
+.Bd -literal -offset indent
+# ifconfig mobileipN tunneldomain 1
+.Ed
+.Sh SEE ALSO
+.Xr inet 4 ,
+.Xr ip 4 ,
+.Xr netintro 4 ,
+.Xr options 4 ,
+.Xr hostname.if 5 ,
+.Xr protocols 5 ,
+.Xr ifconfig 8 ,
+.Xr netstart 8
+.Sh STANDARDS
+.Rs
+.Re
+The C. Perkins
+.%D October 1996
+.%R RFC 2004
+.%T Minimal Encapsulation within IP
+.Re
+.Sh HISTORY
+Support for the MobileIP protocol was originally implemented as part of the
+.Xr gre 4
+driver.
+The
+.Nm
+driver was split off from
+.Xr gre 4
+in
+.Ox 6.3 .
Index: sys/net/if_mobileip.c
===================================================================
RCS file: sys/net/if_mobileip.c
diff -N sys/net/if_mobileip.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ sys/net/if_mobileip.c       30 Jan 2018 07:07:32 -0000
@@ -0,0 +1,637 @@
+/*     $OpenBSD$ */
+
+/*
+ * Copyright (c) 2016 David Gwynne <[email protected]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "mobileip.h"
+
+#include "bpfilter.h"
+#include "pf.h"
+
+#include <sys/param.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/timeout.h>
+#include <sys/tree.h>
+
+#include <net/if.h>
+#include <net/if_types.h>
+#include <net/if_var.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#endif
+
+#if NPF > 0
+#include <net/pfvar.h>
+#endif
+
+#include <net/if_mobileip.h>
+
+struct mobileip_softc {
+       struct ifnet            sc_if;
+
+       RBT_ENTRY(mobileip_softc)
+                               sc_entry;
+
+       unsigned int            sc_rtableid;
+       uint32_t                sc_src;
+       uint32_t                sc_dst;
+};
+
+static int     mobileip_clone_create(struct if_clone *, int);
+static int     mobileip_clone_destroy(struct ifnet *);
+
+static struct if_clone mobileip_cloner = IF_CLONE_INITIALIZER("mobileip",
+    mobileip_clone_create, mobileip_clone_destroy);
+
+RBT_HEAD(mobileip_tree, mobileip_softc);
+
+static inline int
+               mobileip_cmp(const struct mobileip_softc *,
+                   const struct mobileip_softc *);
+
+RBT_PROTOTYPE(mobileip_tree, mobileip_softc, sc_entry, mobileip_cmp);
+
+struct mobileip_tree mobileip_softcs = RBT_INITIALIZER();
+
+#define MOBILEIPMTU    (1500 - (sizeof(struct mobileip_header) +       \
+                           sizeof(struct mobileip_h_src)))             \
+
+static int     mobileip_ioctl(struct ifnet *, u_long, caddr_t);
+static int     mobileip_up(struct mobileip_softc *);
+static int     mobileip_down(struct mobileip_softc *);
+static int     mobileip_set_tunnel(struct mobileip_softc *,
+                   struct if_laddrreq *);
+static int     mobileip_get_tunnel(struct mobileip_softc *,
+                   struct if_laddrreq *);
+static int     mobileip_del_tunnel(struct mobileip_softc *);
+
+static int     mobileip_output(struct ifnet *, struct mbuf *,
+                   struct sockaddr *, struct rtentry *);
+static void    mobileip_start(struct ifnet *);
+static int     mobileip_encap(struct mobileip_softc *, struct mbuf *);
+
+/*
+ * let's begin
+ */
+
+int    mobileip_allow = 0;
+
+void
+mobileipattach(int n)
+{
+       if_clone_attach(&mobileip_cloner);
+}
+
+int
+mobileip_clone_create(struct if_clone *ifc, int unit)
+{
+       struct mobileip_softc *sc;
+
+       sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT|M_ZERO);
+       if (!sc)
+               return (ENOMEM);
+
+       sc->sc_rtableid = 0;
+       sc->sc_src = INADDR_ANY;
+       sc->sc_dst = INADDR_ANY;
+
+       snprintf(sc->sc_if.if_xname, sizeof sc->sc_if.if_xname, "%s%d",
+           ifc->ifc_name, unit);
+       sc->sc_if.if_softc = sc;
+       sc->sc_if.if_type = IFT_TUNNEL;
+       sc->sc_if.if_addrlen = 0;
+       sc->sc_if.if_mtu = MOBILEIPMTU;
+       sc->sc_if.if_flags = IFF_POINTOPOINT|IFF_MULTICAST;
+       sc->sc_if.if_output = mobileip_output;
+       sc->sc_if.if_start = mobileip_start;
+       sc->sc_if.if_ioctl = mobileip_ioctl;
+       sc->sc_if.if_rtrequest = p2p_rtrequest;
+
+       if_attach(&sc->sc_if);
+       if_alloc_sadl(&sc->sc_if);
+
+#if NBPFILTER > 0
+       bpfattach(&sc->sc_if.if_bpf, &sc->sc_if, DLT_LOOP, sizeof(uint32_t));
+#endif
+
+       return (0);
+}
+
+int
+mobileip_clone_destroy(struct ifnet *ifp)
+{
+       struct mobileip_softc *sc = ifp->if_softc;
+
+       if_detach(ifp);
+
+       free(sc, M_DEVBUF, sizeof(*sc));
+
+       return (0);
+}
+
+/*
+ * do a checksum of a header.
+ *
+ * assumes len is aligned correctly, and not an odd number of bytes.
+ */
+static inline uint16_t
+mobileip_cksum(const void *buf, size_t len)
+{
+       const uint16_t *p = buf;
+       uint32_t sum = 0;
+
+       do {
+               sum += bemtoh16(p++);
+       } while (len -= 2);
+
+       /* end-around-carry */
+       sum = (sum >> 16) + (sum & 0xffff);
+       sum += (sum >> 16);
+       return (~sum);
+}
+
+static inline int
+mobileip_cmp(const struct mobileip_softc *a, const struct mobileip_softc *b)
+{
+       if (a->sc_src > b->sc_src)
+               return (1);
+       if (a->sc_src < b->sc_src)
+               return (-1);
+
+       if (a->sc_dst > b->sc_dst)
+               return (1);
+       if (a->sc_dst < b->sc_dst)
+               return (-1);
+
+       if (a->sc_rtableid > b->sc_rtableid)
+               return (1);
+       if (a->sc_rtableid < b->sc_rtableid)
+               return (-1);
+
+       return (0);
+}
+
+static int
+mobileip_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
+    struct rtentry *rt)
+{
+       struct m_tag *mtag;
+       int error = 0;
+
+       if (!mobileip_allow) {
+               m_freem(m);
+               error = EACCES;
+               goto end;
+       }
+
+       if (!ISSET(ifp->if_flags, IFF_RUNNING)) {
+               m_freem(m);
+               error = ENETDOWN;
+               goto end;
+       }
+
+       if (dst->sa_family != AF_INET) {
+               m_freem(m);
+               error = EAFNOSUPPORT;
+               goto end;
+       }
+
+       /* Try to limit infinite recursion through misconfiguration. */
+       for (mtag = m_tag_find(m, PACKET_TAG_GRE, NULL); mtag;
+            mtag = m_tag_find(m, PACKET_TAG_GRE, mtag)) {
+               if (memcmp(mtag + 1, &ifp->if_index,
+                   sizeof(ifp->if_index)) == 0) {
+                       m_freem(m);
+                       error = EIO;
+                       goto end;
+               }
+       }
+
+       mtag = m_tag_get(PACKET_TAG_GRE, sizeof(ifp->if_index), M_NOWAIT);
+       if (mtag == NULL) {
+               m_freem(m);
+               error = ENOBUFS;
+               goto end;
+       }
+       memcpy(mtag + 1, &ifp->if_index, sizeof(ifp->if_index));
+       m_tag_prepend(m, mtag);
+
+       error = if_enqueue(ifp, m);
+  end:
+       if (error)
+               ifp->if_oerrors++;
+       return (error);
+}
+
+static void
+mobileip_start(struct ifnet *ifp)
+{
+       struct mobileip_softc *sc = ifp->if_softc;
+       struct mbuf *m;
+
+       while ((m = ifq_dequeue(&ifp->if_snd)) != NULL) {
+#if NBPFILTER > 0
+               if (ifp->if_bpf)
+                       bpf_mtap_af(ifp->if_bpf, AF_INET, m, BPF_DIRECTION_OUT);
+#endif
+
+               if (mobileip_encap(sc, m) != 0)
+                       ifp->if_oerrors++;
+       }
+}
+
+static int
+mobileip_encap(struct mobileip_softc *sc, struct mbuf *m)
+{
+       struct ip *ip;
+       struct mobileip_header *mh;
+       struct mobileip_h_src *msh;
+       caddr_t hdr;
+       int iphlen, hlen;
+
+       /* look at the current IP header */
+       m = m_pullup(m, sizeof(*ip));
+       if (m == NULL)
+               return (ENOBUFS);
+
+       /* figure out how long it is */
+       ip = mtod(m, struct ip *);
+       iphlen = ip->ip_hl << 2;
+
+       /* figure out how much extra space we'll need */
+       hlen = sizeof(*mh);
+       if (ip->ip_src.s_addr != sc->sc_src)
+               hlen += sizeof(*msh);
+
+       /* add the space */
+       m = m_prepend(m, hlen, M_DONTWAIT);
+       if (m == NULL)
+               return (ENOBUFS);
+
+       /* make the IP and mobileip headers contig */
+       m = m_pullup(m, iphlen + hlen);
+       if (m == NULL)
+               return (ENOBUFS);
+
+       /* move the IP header to the front */
+       hdr = mtod(m, caddr_t);
+       memmove(hdr, hdr + hlen, iphlen);
+
+       /* fill in the headers */
+       ip = (struct ip *)hdr;
+       mh = (struct mobileip_header *)(hdr + iphlen);
+       mh->mip_proto = ip->ip_p;
+       mh->mip_flags = 0;
+       mh->mip_hcrc = 0;
+       mh->mip_dst = ip->ip_dst.s_addr;
+
+       if (ip->ip_src.s_addr != sc->sc_src) {
+               mh->mip_flags |= MOBILEIP_SP;
+
+               msh = (struct mobileip_h_src *)(mh + 1);
+               msh->mip_src = ip->ip_src.s_addr;
+
+               ip->ip_src.s_addr = sc->sc_src;
+       }
+
+       htobem16(&mh->mip_hcrc, mobileip_cksum(mh, hlen));
+
+       ip->ip_p = IPPROTO_MOBILE;
+       htobem16(&ip->ip_len, bemtoh16(&ip->ip_len) + hlen);
+       ip->ip_dst.s_addr = sc->sc_dst;
+
+       m->m_flags &= ~(M_BCAST|M_MCAST);
+       m->m_pkthdr.ph_rtableid = sc->sc_rtableid;
+
+#if NPF > 0
+       pf_pkt_addr_changed(m);
+#endif
+
+       ip_send(m);
+
+       return (0);
+}
+
+int
+mobileip_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
+{
+       struct mobileip_softc *sc = ifp->if_softc;
+       struct ifreq *ifr = (struct ifreq *)data;
+       int error = 0;
+
+       switch(cmd) {
+       case SIOCSIFADDR:
+               /* XXX restrict to AF_INET */
+               ifp->if_flags |= IFF_UP;
+               /* FALLTHROUGH */
+       case SIOCSIFFLAGS:
+               if (ISSET(ifp->if_flags, IFF_UP)) {
+                       if (!ISSET(ifp->if_flags, IFF_RUNNING))
+                               error = mobileip_up(sc);
+                       else
+                               error = ENETRESET;
+               } else {
+                       if (ISSET(ifp->if_flags, IFF_RUNNING))
+                               error = mobileip_down(sc);
+               }
+               break;
+       case SIOCSIFDSTADDR:
+               break;
+       case SIOCSIFMTU:
+               if (ifr->ifr_mtu < 576) {
+                       error = EINVAL;
+                       break;
+               }
+               ifp->if_mtu = ifr->ifr_mtu;
+               break;
+       case SIOCGIFMTU:
+               ifr->ifr_mtu = sc->sc_if.if_mtu;
+               break;
+       case SIOCADDMULTI:
+       case SIOCDELMULTI:
+               break;
+
+       case SIOCSLIFPHYADDR:
+               error = mobileip_set_tunnel(sc, (struct if_laddrreq *)data);
+               break;
+       case SIOCGLIFPHYADDR:
+               error = mobileip_get_tunnel(sc, (struct if_laddrreq *)data);
+               break;
+       case SIOCDIFPHYADDR:
+               error = mobileip_del_tunnel(sc);
+               break;
+
+       case SIOCSLIFPHYRTABLE:
+               if (ISSET(ifp->if_flags, IFF_RUNNING)) {
+                       error = EBUSY;
+                       break;
+               }
+
+               if (ifr->ifr_rdomainid < 0 ||
+                   ifr->ifr_rdomainid > RT_TABLEID_MAX ||
+                   !rtable_exists(ifr->ifr_rdomainid)) {
+                       error = EINVAL;
+                       break;
+               }
+               sc->sc_rtableid = ifr->ifr_rdomainid;
+               break;
+       case SIOCGLIFPHYRTABLE:
+               ifr->ifr_rdomainid = sc->sc_rtableid;
+               break;
+
+       default:
+               error = ENOTTY;
+               break;
+       }
+
+       return (error);
+}
+
+static int
+mobileip_up(struct mobileip_softc *sc)
+{
+       struct mobileip_softc *osc;
+
+       if (sc->sc_dst == INADDR_ANY)
+               return (EDESTADDRREQ);
+
+       NET_ASSERT_LOCKED();
+       osc = RBT_INSERT(mobileip_tree, &mobileip_softcs, sc);
+       if (osc != NULL)
+               return (EADDRINUSE);
+
+       SET(sc->sc_if.if_flags, IFF_RUNNING);
+
+       return (0);
+}
+
+static int
+mobileip_down(struct mobileip_softc *sc)
+{
+       NET_ASSERT_LOCKED();
+       RBT_REMOVE(mobileip_tree, &mobileip_softcs, sc);
+
+       CLR(sc->sc_if.if_flags, IFF_RUNNING);
+
+       ifq_barrier(&sc->sc_if.if_snd);
+
+       return (0);
+}
+
+static int
+mobileip_set_tunnel(struct mobileip_softc *sc, struct if_laddrreq *req)
+{
+       struct sockaddr_in *src = (struct sockaddr_in *)&req->addr;
+       struct sockaddr_in *dst = (struct sockaddr_in *)&req->dstaddr;
+
+       if (ISSET(sc->sc_if.if_flags, IFF_RUNNING))
+               return (EBUSY);
+
+       /* sa_family and sa_len must be equal */
+       if (src->sin_family != dst->sin_family || src->sin_len != dst->sin_len)
+               return (EINVAL);
+
+       if (dst->sin_family != AF_INET)
+               return (EAFNOSUPPORT);
+       if (dst->sin_len != sizeof(*dst))
+               return (EINVAL);
+
+       if (in_nullhost(src->sin_addr) ||
+           IN_MULTICAST(src->sin_addr.s_addr) ||
+           in_nullhost(dst->sin_addr) ||
+           IN_MULTICAST(dst->sin_addr.s_addr))
+               return (EINVAL);
+
+       /* commit */
+       sc->sc_src = src->sin_addr.s_addr;
+       sc->sc_dst = dst->sin_addr.s_addr;
+
+       return (0);
+}
+
+static int
+mobileip_get_tunnel(struct mobileip_softc *sc, struct if_laddrreq *req)
+{
+       struct sockaddr_in *src = (struct sockaddr_in *)&req->addr;
+       struct sockaddr_in *dst = (struct sockaddr_in *)&req->dstaddr;
+
+       if (sc->sc_dst == INADDR_ANY)
+               return (EADDRNOTAVAIL);
+
+       memset(src, 0, sizeof(*src));
+       src->sin_family = AF_INET;
+       src->sin_len = sizeof(*src);
+       src->sin_addr.s_addr = sc->sc_src;
+
+       memset(dst, 0, sizeof(*dst));
+       dst->sin_family = AF_INET;
+       dst->sin_len = sizeof(*dst);
+       dst->sin_addr.s_addr = sc->sc_dst;
+
+       return (0);
+}
+
+static int
+mobileip_del_tunnel(struct mobileip_softc *sc)
+{
+       if (ISSET(sc->sc_if.if_flags, IFF_RUNNING))
+               return (EBUSY);
+
+       /* commit */
+       sc->sc_src = INADDR_ANY;
+       sc->sc_dst = INADDR_ANY;
+
+       return (0);
+}
+
+int
+mobileip_input(struct mbuf **mp, int *offp, int type, int af)
+{
+       struct mobileip_softc key;
+       struct mbuf *m = *mp;
+       struct ifnet *ifp;
+       struct mobileip_softc *sc;
+       caddr_t hdr;
+       struct ip *ip;
+       struct mobileip_header *mh;
+       struct mobileip_h_src *msh;
+       int iphlen = 0;
+       int hlen;
+
+       if (!mobileip_allow)
+               goto drop;
+
+       ip = mtod(m, struct ip *);
+
+       key.sc_rtableid = m->m_pkthdr.ph_rtableid;
+       key.sc_src = ip->ip_dst.s_addr;
+       key.sc_dst = ip->ip_src.s_addr;
+
+       /* NET_ASSERT_READ_LOCKED() */
+       sc = RBT_FIND(mobileip_tree, &mobileip_softcs, &key);
+       if (sc == NULL)
+               goto drop;
+
+       /* it's ours now, we can do what we want */
+
+       iphlen = ip->ip_hl << 2;
+       hlen = sizeof(*mh);
+       m = m_pullup(m, iphlen + hlen);
+       if (m == NULL)
+               return (IPPROTO_DONE);
+
+       hdr = mtod(m, caddr_t);
+       ip = (struct ip *)hdr;
+       mh = (struct mobileip_header *)(hdr + iphlen);
+
+       if (mh->mip_flags & ~MOBILEIP_SP)
+               goto drop;
+
+       if (ISSET(mh->mip_flags, MOBILEIP_SP)) {
+               hlen += sizeof(*msh);
+               m = m_pullup(m, iphlen + hlen);
+               if (m == NULL)
+                       return (IPPROTO_DONE);
+
+               hdr = mtod(m, caddr_t);
+               ip = (struct ip *)hdr;
+               mh = (struct mobileip_header *)(hdr + iphlen);
+               msh = (struct mobileip_h_src *)(mh + 1);
+
+               ip->ip_src.s_addr = msh->mip_src;
+       }
+
+       if (mobileip_cksum(mh, hlen) != 0)
+               goto drop;
+
+       ip->ip_p = mh->mip_proto;
+       htobem16(&ip->ip_len, bemtoh16(&ip->ip_len) - hlen);
+       ip->ip_dst.s_addr = mh->mip_dst;
+
+       memmove(hdr + hlen, hdr, iphlen);
+       m_adj(m, hlen);
+
+       ifp = &sc->sc_if;
+
+       CLR(m->m_flags, M_MCAST|M_BCAST);
+       SET(m->m_pkthdr.csum_flags, M_IPV4_CSUM_IN_OK);
+       m->m_pkthdr.ph_ifidx = ifp->if_index;
+       m->m_pkthdr.ph_rtableid = ifp->if_rdomain;
+
+#if NPF > 0
+       pf_pkt_addr_changed(m);
+#endif
+
+       ifp->if_ipackets++;
+       ifp->if_ibytes += m->m_pkthdr.len;
+
+#if NBPFILTER > 0
+       if (ifp->if_bpf)
+               bpf_mtap_af(ifp->if_bpf, AF_INET, m, BPF_DIRECTION_IN);
+#endif
+
+       ipv4_input(ifp, m);
+
+       return (IPPROTO_DONE);
+
+drop:
+       m_freem(m);
+       return (IPPROTO_DONE);
+}
+
+#include <sys/sysctl.h>
+#include <netinet/ip_gre.h>
+
+int
+mobileip_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
+    void *newp, size_t newlen)
+{
+       int allow;
+       int error;
+
+       /* All sysctl names at this level are terminal. */
+       if (namelen != 1)
+               return (ENOTDIR);
+
+       switch (name[0]) {
+       case MOBILEIPCTL_ALLOW:
+               allow = mobileip_allow;
+
+               error = sysctl_int(oldp, oldlenp, newp, newlen,
+                   &allow);
+               if (error != 0)
+                       return (error);
+
+               mobileip_allow = allow;
+               break;
+       default:
+               return (ENOPROTOOPT);
+       }
+
+       return (0);
+}
+
+RBT_GENERATE(mobileip_tree, mobileip_softc, sc_entry, mobileip_cmp);
Index: sys/net/if_mobileip.h
===================================================================
RCS file: sys/net/if_mobileip.h
diff -N sys/net/if_mobileip.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ sys/net/if_mobileip.h       30 Jan 2018 07:07:32 -0000
@@ -0,0 +1,41 @@
+/*      $OpenBSD$ */
+
+/*
+ * Copyright (c) 2016 David Gwynne <[email protected]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _NET_IF_MOBILEIP_H
+#define _NET_IF_MOBILEIP_H
+
+struct mobileip_header {
+       uint8_t                 mip_proto;      /* original protocol */
+       uint8_t                 mip_flags;
+#define MOBILEIP_SP                    0x80    /* src address is present */
+       uint16_t                mip_hcrc;       /* header checksum */
+       uint32_t                mip_dst;        /* original dst address */
+} __packed __aligned(4);
+
+struct mobileip_h_src {
+       uint32_t                mip_src;        /* original src address */
+} __packed __aligned(4);
+
+#ifdef _KERNEL
+void            mobileipattach(int);
+int             mobileip_input(struct mbuf **, int *, int, int);
+int             mobileip_sysctl(int *, u_int, void *, size_t *,
+                    void *, size_t);
+#endif /* _KERNEL */
+
+#endif /* _NET_IF_MOBILEIP_H_ */
Index: sys/netinet/in_proto.c
===================================================================
RCS file: /cvs/src/sys/netinet/in_proto.c,v
retrieving revision 1.88
diff -u -p -r1.88 in_proto.c
--- sys/netinet/in_proto.c      23 Nov 2017 13:45:46 -0000      1.88
+++ sys/netinet/in_proto.c      30 Jan 2018 07:07:32 -0000
@@ -172,6 +172,11 @@
 #include <net/if_etherip.h>
 #endif
 
+#include "mobileip.h"
+#if NMOBILEIP > 0
+#include <net/if_mobileip.h>
+#endif
+
 u_char ip_protox[IPPROTO_MAX];
 
 const struct protosw inetsw[] = {
@@ -348,19 +353,21 @@ const struct protosw inetsw[] = {
   .pr_detach   = rip_detach,
   .pr_sysctl   = gre_sysctl
 },
+#endif /* NGRE > 0 */
+#if NMOBILEIP > 0
 {
   .pr_type     = SOCK_RAW,
   .pr_domain   = &inetdomain,
   .pr_protocol = IPPROTO_MOBILE,
   .pr_flags    = PR_ATOMIC|PR_ADDR,
-  .pr_input    = gre_mobile_input,
+  .pr_input    = mobileip_input,
   .pr_ctloutput        = rip_ctloutput,
   .pr_usrreq   = rip_usrreq,
   .pr_attach   = rip_attach,
   .pr_detach   = rip_detach,
-  .pr_sysctl   = ipmobile_sysctl
+  .pr_sysctl   = mobileip_sysctl
 },
-#endif /* NGRE > 0 */
+#endif /* NMOBILEIP > 0 */
 #if NCARP > 0
 {
   .pr_type     = SOCK_RAW,
Index: sys/netinet/ip_gre.c
===================================================================
RCS file: /cvs/src/sys/netinet/ip_gre.c,v
retrieving revision 1.69
diff -u -p -r1.69 ip_gre.c
--- sys/netinet/ip_gre.c        9 Jan 2018 06:24:15 -0000       1.69
+++ sys/netinet/ip_gre.c        30 Jan 2018 07:07:32 -0000
@@ -261,93 +261,6 @@ gre_input(struct mbuf **mp, int *offp, i
 }
 
 /*
- * Input routine for IPPROTO_MOBILE.
- * This is a little bit different from the other modes, as the
- * encapsulating header was not prepended, but instead inserted
- * between IP header and payload.
- */
-
-int
-gre_mobile_input(struct mbuf **mp, int *offp, int proto, int af)
-{
-       struct mbuf *m = *mp;
-       struct ip *ip;
-       struct mobip_h *mip;
-       struct gre_softc *sc;
-       u_char osrc = 0;
-       int msiz;
-
-       if (!ip_mobile_allow) {
-               m_freem(m);
-               return IPPROTO_DONE;
-       }
-
-       if ((sc = gre_lookup(m, proto)) == NULL) {
-               /* No matching tunnel or tunnel is down. */
-               m_freem(m);
-               return IPPROTO_DONE;
-       }
-
-       if (m->m_len < sizeof(*mip)) {
-               m = *mp = m_pullup(m, sizeof(*mip));
-               if (m == NULL)
-                       return IPPROTO_DONE;
-       }
-       ip = mtod(m, struct ip *);
-       mip = mtod(m, struct mobip_h *);
-
-       m->m_pkthdr.ph_ifidx = sc->sc_if.if_index;
-
-       sc->sc_if.if_ipackets++;
-       sc->sc_if.if_ibytes += m->m_pkthdr.len;
-
-       if (ntohs(mip->mh.proto) & MOB_H_SBIT) {
-               osrc = 1;
-               msiz = MOB_H_SIZ_L;
-               mip->mi.ip_src.s_addr = mip->mh.osrc;
-       } else
-               msiz = MOB_H_SIZ_S;
-
-       if (m->m_len < (ip->ip_hl << 2) + msiz) {
-               m = *mp = m_pullup(m, (ip->ip_hl << 2) + msiz);
-               if (m == NULL)
-                       return IPPROTO_DONE;
-               ip = mtod(m, struct ip *);
-               mip = mtod(m, struct mobip_h *);
-       }
-
-       mip->mi.ip_dst.s_addr = mip->mh.odst;
-       mip->mi.ip_p = (ntohs(mip->mh.proto) >> 8);
-
-       if (gre_in_cksum((u_short *) &mip->mh, msiz) != 0) {
-               m_freem(m);
-               return IPPROTO_DONE;
-       }
-
-       memmove(ip + (ip->ip_hl << 2), ip + (ip->ip_hl << 2) + msiz, 
-             m->m_len - msiz - (ip->ip_hl << 2));
-
-       m->m_len -= msiz;
-       ip->ip_len = htons(ntohs(ip->ip_len) - msiz);
-       m->m_pkthdr.len -= msiz;
-
-       ip->ip_sum = 0;
-       ip->ip_sum = in_cksum(m,(ip->ip_hl << 2));
-
-#if NBPFILTER > 0
-        if (sc->sc_if.if_bpf)
-               bpf_mtap_af(sc->sc_if.if_bpf, AF_INET, m, BPF_DIRECTION_IN);
-#endif
-
-#if NPF > 0
-       pf_pkt_addr_changed(m);
-#endif
-
-       ipv4_input(&sc->sc_if, m);
-       return IPPROTO_DONE;
-}
-
-/*
  * Find the gre interface associated with our src/dst/proto set.
  */
 struct gre_softc *
@@ -389,29 +302,6 @@ gre_sysctl(int *name, u_int namelen, voi
         case GRECTL_WCCP:
                NET_LOCK();
                error = sysctl_int(oldp, oldlenp, newp, newlen, &gre_wccp);
-               NET_UNLOCK();
-               return (error);
-        default:
-                return (ENOPROTOOPT);
-        }
-        /* NOTREACHED */
-}
-
-int
-ipmobile_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
-    void *newp, size_t newlen)
-{
-       int error;
-
-        /* All sysctl names at this level are terminal. */
-        if (namelen != 1)
-                return (ENOTDIR);
-
-        switch (name[0]) {
-        case MOBILEIPCTL_ALLOW:
-               NET_LOCK();
-               error = sysctl_int(oldp, oldlenp, newp, newlen,
-                   &ip_mobile_allow);
                NET_UNLOCK();
                return (error);
         default:
Index: sys/conf/GENERIC
===================================================================
RCS file: /cvs/src/sys/conf/GENERIC,v
retrieving revision 1.250
diff -u -p -r1.250 GENERIC
--- sys/conf/GENERIC    25 Oct 2017 12:38:21 -0000      1.250
+++ sys/conf/GENERIC    30 Jan 2018 07:07:32 -0000
@@ -17,7 +17,6 @@ option                PTRACE          # ptrace(2) system call
 #option                WITNESS         # witness(4) lock checker
 
 #option                KVA_GUARDPAGES  # slow virtual address recycling (+ 
guarding)
-option         POOL_DEBUG      # pool corruption detection
 #option                VFSLCKDEBUG     # VFS locking checks
 
 option         CRYPTO          # Cryptographic framework
@@ -90,6 +89,7 @@ pseudo-device carp            # CARP protocol supp
 pseudo-device  etherip         # EtherIP (RFC 3378)
 pseudo-device  gif             # IPv[46] over IPv[46] tunnel (RFC1933)
 pseudo-device  gre             # GRE encapsulation interface
+pseudo-device  mobileip        # MobileIP encapsulation interface
 pseudo-device  loop            # network loopback
 pseudo-device  mpe             # MPLS PE interface
 pseudo-device  mpw             # MPLS pseudowire support
Index: sys/conf/files
===================================================================
RCS file: /cvs/src/sys/conf/files,v
retrieving revision 1.656
diff -u -p -r1.656 files
--- sys/conf/files      16 Nov 2017 18:12:27 -0000      1.656
+++ sys/conf/files      30 Jan 2018 07:07:32 -0000
@@ -551,6 +551,7 @@ pseudo-device carp: ifnet, ether
 pseudo-device sppp: ifnet
 pseudo-device gif: ifnet
 pseudo-device gre: ifnet
+pseudo-device mobileip: ifnet
 pseudo-device crypto: ifnet
 pseudo-device trunk: ifnet, ether, ifmedia
 pseudo-device mpe: ifnet, ether
@@ -798,6 +799,7 @@ file net/rtsock.c
 file net/slcompress.c                  ppp
 file net/if_enc.c                      enc                     needs-count
 file net/if_gre.c                      gre                     needs-count
+file net/if_mobileip.c                 mobileip                needs-count
 file net/if_trunk.c                    trunk                   needs-count
 file net/trunklacp.c                   trunk
 file net/if_mpe.c                      mpe                     needs-count

Reply via email to