split mobileip(4) out from the gre(4) driver.
authordlg <dlg@openbsd.org>
Wed, 7 Feb 2018 01:09:57 +0000 (01:09 +0000)
committerdlg <dlg@openbsd.org>
Wed, 7 Feb 2018 01:09:57 +0000 (01:09 +0000)
having mobileip in gre makes it hard to cut gre up. the current mobileip
code is also broken, so this is def and improvement. it also makes it
easy to disable and remove mobileip in the future.

ok claudio@ henning@

share/man/man4/Makefile
share/man/man4/gre.4
share/man/man4/mobileip.4 [new file with mode: 0644]
sys/conf/GENERIC
sys/conf/files
sys/net/if_mobileip.c [new file with mode: 0644]
sys/net/if_mobileip.h [new file with mode: 0644]
sys/netinet/in_proto.c
sys/netinet/ip_gre.c

index 20b409d..3568370 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: Makefile,v 1.663 2018/01/02 22:56:01 kettenis Exp $
+#      $OpenBSD: Makefile,v 1.664 2018/02/07 01:09:57 dlg Exp $
 
 MAN=   aac.4 ac97.4 acphy.4 acrtc.4 \
        acpi.4 acpiac.4 acpials.4 acpiasus.4 acpibat.4 \
@@ -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 ad8dbf7..ffa4a01 100644 (file)
@@ -1,4 +1,4 @@
-.\" $OpenBSD: gre.4,v 1.49 2018/01/12 04:36:44 deraadt Exp $
+.\" $OpenBSD: gre.4,v 1.50 2018/02/07 01:09:57 dlg Exp $
 .\" $NetBSD: gre.4,v 1.10 1999/12/22 14:55:49 kleink Exp $
 .\"
 .\" Copyright 1998 (c) The NetBSD Foundation, Inc.
 .\" ARISING IN ANY WAY  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 .\" POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd $Mdocdate: January 12 2018 $
+.Dd $Mdocdate: February 7 2018 $
 .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 Cisco routers.
 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
@@ -228,13 +212,6 @@ pass quick on gre proto gre no state
 .Re
 .Pp
 .Rs
-.%A C. Perkins
-.%D October 1996
-.%R RFC 2004
-.%T Minimal Encapsulation within IP
-.Re
-.Pp
-.Rs
 .%U https://tools.ietf.org/html/draft-ietf-wrec-web-pro-00.txt
 .%T Web Cache Coordination Protocol V1.0
 .Re
diff --git a/share/man/man4/mobileip.4 b/share/man/man4/mobileip.4
new file mode 100644 (file)
index 0000000..386dd03
--- /dev/null
@@ -0,0 +1,139 @@
+.\"    $OpenBSD: mobileip.4,v 1.1 2018/02/07 01:09:57 dlg Exp $
+.\"
+.\" Copyright (c) 2018 David Gwynne <dlg@openbsd.org>
+.\"
+.\" 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: February 7 2018 $
+.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 ff356c0..9945a24 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: GENERIC,v 1.250 2017/10/25 12:38:21 job Exp $
+#      $OpenBSD: GENERIC,v 1.251 2018/02/07 01:09:57 dlg Exp $
 #
 #      Machine-independent option; used by all architectures for their
 #      GENERIC kernel
@@ -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 support
 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 f623c41..d8cc6a0 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: files,v 1.657 2018/02/06 23:44:48 henning Exp $
+#      $OpenBSD: files,v 1.658 2018/02/07 01:09:57 dlg Exp $
 #      $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $
 
 #      @(#)files.newconf       7.5 (Berkeley) 5/10/93
@@ -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
@@ -799,6 +800,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
diff --git a/sys/net/if_mobileip.c b/sys/net/if_mobileip.c
new file mode 100644 (file)
index 0000000..80a111a
--- /dev/null
@@ -0,0 +1,637 @@
+/*     $OpenBSD: if_mobileip.c,v 1.1 2018/02/07 01:09:57 dlg Exp $ */
+
+/*
+ * Copyright (c) 2016 David Gwynne <dlg@openbsd.org>
+ *
+ * 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);
diff --git a/sys/net/if_mobileip.h b/sys/net/if_mobileip.h
new file mode 100644 (file)
index 0000000..1055f36
--- /dev/null
@@ -0,0 +1,41 @@
+/*      $OpenBSD: if_mobileip.h,v 1.1 2018/02/07 01:09:57 dlg Exp $ */
+
+/*
+ * Copyright (c) 2016 David Gwynne <dlg@openbsd.org>
+ *
+ * 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 697b95c..54ad512 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: in_proto.c,v 1.88 2017/11/23 13:45:46 mpi Exp $       */
+/*     $OpenBSD: in_proto.c,v 1.89 2018/02/07 01:09:57 dlg Exp $       */
 /*     $NetBSD: in_proto.c,v 1.14 1996/02/18 18:58:32 christos Exp $   */
 
 /*
 #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 0dba233..5dad1d8 100644 (file)
@@ -1,4 +1,4 @@
-/*      $OpenBSD: ip_gre.c,v 1.69 2018/01/09 06:24:15 dlg Exp $ */
+/*      $OpenBSD: ip_gre.c,v 1.70 2018/02/07 01:09:57 dlg Exp $ */
 /*     $NetBSD: ip_gre.c,v 1.9 1999/10/25 19:18:11 drochner Exp $ */
 
 /*
@@ -260,93 +260,6 @@ gre_input(struct mbuf **mp, int *offp, int proto, int af)
        return IPPROTO_DONE;
 }
 
-/*
- * 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.
  */
@@ -397,29 +310,6 @@ gre_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
         /* 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:
-                return (ENOPROTOOPT);
-        }
-        /* NOTREACHED */
-}
-
 int
 gre_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam,
     struct mbuf *control, struct proc *p)