diff options
author | David Gwynne <dlg@cvs.openbsd.org> | 2022-02-28 00:12:12 +0000 |
---|---|---|
committer | David Gwynne <dlg@cvs.openbsd.org> | 2022-02-28 00:12:12 +0000 |
commit | 90f30bf40b79e96714aa2b692f33d55f05a37f25 (patch) | |
tree | 231300d94f1dee52f5192716f28b16393ef972d0 /sys/net/if_etherip.c | |
parent | d08a3a5b49bc8892e2c0a96ce10d88d86d25a983 (diff) |
add the mbuf tags that prevent output loops.
mostly copied from vxlan where the tag is checked in output and
set in encap. etherip appears to be one of the first drivers i
reworked, so it's a bit crufty. the ipv4 vs ipv6 handling could
be done better.
Diffstat (limited to 'sys/net/if_etherip.c')
-rw-r--r-- | sys/net/if_etherip.c | 42 |
1 files changed, 41 insertions, 1 deletions
diff --git a/sys/net/if_etherip.c b/sys/net/if_etherip.c index 57eb95a6242..3abc9d4b5aa 100644 --- a/sys/net/if_etherip.c +++ b/sys/net/if_etherip.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_etherip.c,v 1.49 2021/05/16 15:10:20 deraadt Exp $ */ +/* $OpenBSD: if_etherip.c,v 1.50 2022/02/28 00:12:11 dlg Exp $ */ /* * Copyright (c) 2015 Kazuya GODA <goda@openbsd.org> * @@ -104,6 +104,8 @@ void etheripattach(int); int etherip_clone_create(struct if_clone *, int); int etherip_clone_destroy(struct ifnet *); int etherip_ioctl(struct ifnet *, u_long, caddr_t); +int etherip_output(struct ifnet *, struct mbuf *, struct sockaddr *, + struct rtentry *); void etherip_start(struct ifnet *); int etherip_media_change(struct ifnet *); void etherip_media_status(struct ifnet *, struct ifmediareq *); @@ -147,6 +149,7 @@ etherip_clone_create(struct if_clone *ifc, int unit) ifp->if_softc = sc; ifp->if_hardmtu = ETHER_MAX_HARDMTU_LEN; ifp->if_ioctl = etherip_ioctl; + ifp->if_output = etherip_output; ifp->if_start = etherip_start; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; ifp->if_xflags = IFXF_CLONED; @@ -203,6 +206,23 @@ etherip_media_status(struct ifnet *ifp, struct ifmediareq *imr) imr->ifm_status = IFM_AVALID | IFM_ACTIVE; } +int +etherip_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, + struct rtentry *rt) +{ + struct m_tag *mtag; + + mtag = NULL; + while ((mtag = m_tag_find(m, PACKET_TAG_GRE, mtag)) != NULL) { + if (*(int *)(mtag + 1) == ifp->if_index) { + m_freem(m); + return (EIO); + } + } + + return (ether_output(ifp, m, dst, rt)); +} + void etherip_start(struct ifnet *ifp) { @@ -509,6 +529,7 @@ int ip_etherip_output(struct ifnet *ifp, struct mbuf *m) { struct etherip_softc *sc = (struct etherip_softc *)ifp->if_softc; + struct m_tag *mtag; struct etherip_header *eip; struct ip *ip; @@ -538,6 +559,15 @@ ip_etherip_output(struct ifnet *ifp, struct mbuf *m) eip->eip_res = 0; eip->eip_pad = 0; + mtag = m_tag_get(PACKET_TAG_GRE, sizeof(ifp->if_index), M_NOWAIT); + if (mtag == NULL) { + m_freem(m); + return (ENOMEM); + } + + *(int *)(mtag + 1) = ifp->if_index; + m_tag_prepend(m, mtag); + m->m_flags &= ~(M_BCAST|M_MCAST); m->m_pkthdr.ph_rtableid = sc->sc_tunnel.t_rtableid; @@ -669,6 +699,7 @@ int ip6_etherip_output(struct ifnet *ifp, struct mbuf *m) { struct etherip_softc *sc = ifp->if_softc; + struct m_tag *mtag; struct ip6_hdr *ip6; struct etherip_header *eip; uint16_t len; @@ -704,6 +735,15 @@ ip6_etherip_output(struct ifnet *ifp, struct mbuf *m) eip->eip_res = 0; eip->eip_pad = 0; + mtag = m_tag_get(PACKET_TAG_GRE, sizeof(ifp->if_index), M_NOWAIT); + if (mtag == NULL) { + m_freem(m); + return (ENOMEM); + } + + *(int *)(mtag + 1) = ifp->if_index; + m_tag_prepend(m, mtag); + if (sc->sc_df) SET(m->m_pkthdr.csum_flags, M_IPV6_DF_OUT); |