summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--share/man/man4/Makefile6
-rw-r--r--share/man/man4/gre.437
-rw-r--r--share/man/man4/mobileip.4139
-rw-r--r--sys/conf/GENERIC4
-rw-r--r--sys/conf/files4
-rw-r--r--sys/net/if_mobileip.c637
-rw-r--r--sys/net/if_mobileip.h41
-rw-r--r--sys/netinet/in_proto.c15
-rw-r--r--sys/netinet/ip_gre.c112
9 files changed, 844 insertions, 151 deletions
diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile
index 20b409df996..3568370ab8e 100644
--- a/share/man/man4/Makefile
+++ b/share/man/man4/Makefile
@@ -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 \
diff --git a/share/man/man4/gre.4 b/share/man/man4/gre.4
index ad8dbf749b7..ffa4a017dcf 100644
--- a/share/man/man4/gre.4
+++ b/share/man/man4/gre.4
@@ -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.
@@ -28,25 +28,23 @@
.\" 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
index 00000000000..386dd038930
--- /dev/null
+++ b/share/man/man4/mobileip.4
@@ -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 .
diff --git a/sys/conf/GENERIC b/sys/conf/GENERIC
index ff356c01069..9945a24c9e1 100644
--- a/sys/conf/GENERIC
+++ b/sys/conf/GENERIC
@@ -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
diff --git a/sys/conf/files b/sys/conf/files
index f623c4101e3..d8cc6a02a6b 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -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
index 00000000000..80a111adc05
--- /dev/null
+++ b/sys/net/if_mobileip.c
@@ -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
index 00000000000..1055f36a254
--- /dev/null
+++ b/sys/net/if_mobileip.h
@@ -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_ */
diff --git a/sys/netinet/in_proto.c b/sys/netinet/in_proto.c
index 697b95c66e4..54ad512571d 100644
--- a/sys/netinet/in_proto.c
+++ b/sys/netinet/in_proto.c
@@ -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 $ */
/*
@@ -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,
diff --git a/sys/netinet/ip_gre.c b/sys/netinet/ip_gre.c
index 0dba2339b21..5dad1d88d38 100644
--- a/sys/netinet/ip_gre.c
+++ b/sys/netinet/ip_gre.c
@@ -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 $ */
/*
@@ -261,93 +261,6 @@ gre_input(struct mbuf **mp, int *offp, int proto, int af)
}
/*
- * 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 *
@@ -398,29 +311,6 @@ gre_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
}
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)
{