diff options
-rw-r--r-- | share/man/man4/Makefile | 6 | ||||
-rw-r--r-- | share/man/man4/gre.4 | 37 | ||||
-rw-r--r-- | share/man/man4/mobileip.4 | 139 | ||||
-rw-r--r-- | sys/conf/GENERIC | 4 | ||||
-rw-r--r-- | sys/conf/files | 4 | ||||
-rw-r--r-- | sys/net/if_mobileip.c | 637 | ||||
-rw-r--r-- | sys/net/if_mobileip.h | 41 | ||||
-rw-r--r-- | sys/netinet/in_proto.c | 15 | ||||
-rw-r--r-- | sys/netinet/ip_gre.c | 112 |
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) { |