-/* $OpenBSD: if_gre.c,v 1.95 2018/02/08 22:11:06 dlg Exp $ */
+/* $OpenBSD: if_gre.c,v 1.96 2018/02/08 23:53:20 dlg Exp $ */
/* $NetBSD: if_gre.c,v 1.9 1999/10/25 19:18:11 drochner Exp $ */
/*
u_int t_rtableid;
uint32_t t_src[4];
uint32_t t_dst[4];
+ int t_ttl;
sa_family_t t_af;
- uint8_t t_ttl;
};
RBT_HEAD(gre_tree, gre_tunnel);
static struct mbuf *
gre_ip_encap(const struct gre_tunnel *, struct mbuf *,
- uint8_t);
+ uint8_t, uint8_t);
static int
gre_ip_output(const struct gre_tunnel *, struct mbuf *,
- uint8_t);
+ uint8_t, uint8_t);
static int gre_tunnel_ioctl(struct ifnet *, struct gre_tunnel *,
u_long, void *);
ip = mtod(m, struct ip *);
key.t_af = AF_INET;
+ key.t_ttl = ip->ip_ttl;
key.t_src[0] = ip->ip_dst.s_addr;
key.t_dst[0] = ip->ip_src.s_addr;
ip6 = mtod(m, struct ip6_hdr *);
key.t_af = AF_INET6;
+ key.t_ttl = ip6->ip6_hlim;
memcpy(key.t_src, &ip6->ip6_dst, sizeof(key.t_src));
memcpy(key.t_dst, &ip6->ip6_src, sizeof(key.t_dst));
void (*input)(struct ifnet *, struct mbuf *);
int bpf_af = AF_UNSPEC; /* bpf */
int mcast = 0;
+ int ttloff;
if (!gre_allow)
goto decline;
#if NBPFILTER > 0
bpf_af = AF_INET;
#endif
+ ttloff = offsetof(struct ip, ip_ttl);
input = ipv4_input;
break;
#ifdef INET6
#if NBPFILTER > 0
bpf_af = AF_INET6;
#endif
+ ttloff = offsetof(struct ip6_hdr, ip6_hlim);
input = ipv6_input;
break;
#endif
#if NBPFILTER > 0
bpf_af = AF_MPLS;
#endif
+ ttloff = 3; /* XXX */
input = mpls_input;
break;
#endif
m_adj(m, hlen);
+ if (sc->sc_tunnel.t_ttl == -1) {
+ m = m_pullup(m, ttloff + 1);
+ if (m == NULL)
+ return (IPPROTO_DONE);
+
+ *(m->m_data + ttloff) = key->t_ttl;
+ }
+
m->m_flags &= ~(M_MCAST|M_BCAST);
m->m_flags |= mcast;
m->m_pkthdr.ph_ifidx = ifp->if_index;
{
struct gre_softc *sc = ifp->if_softc;
struct mbuf *m;
- uint8_t tos;
+ uint8_t ttl, tos;
+ int tttl;
uint16_t proto;
#if NBPFILTER > 0
caddr_t if_bpf;
#endif
+ int ttloff;
+
+ tttl = sc->sc_tunnel.t_ttl;
while ((m = ifq_dequeue(&ifp->if_snd)) != NULL) {
#if NBPFILTER > 0
switch (m->m_pkthdr.ph_family) {
case AF_INET: {
- struct ip *ip = mtod(m, struct ip *);
+ struct ip *ip;
+
+ m = m_pullup(m, sizeof(*ip));
+ if (m == NULL)
+ continue;
+
+ ip = mtod(m, struct ip *);
tos = ip->ip_tos;
+ ttloff = offsetof(struct ip, ip_ttl);
proto = htons(ETHERTYPE_IP);
break;
}
#ifdef INET6
case AF_INET6:
+ tos = 0;
+ ttloff = offsetof(struct ip6_hdr, ip6_hlim);
proto = htons(ETHERTYPE_IPV6);
break;
#endif
#ifdef MPLS
case AF_MPLS:
+ ttloff = 3;
+ tos = 0;
+
if (m->m_flags & (M_BCAST | M_MCAST))
proto = htons(ETHERTYPE_MPLS_MCAST);
else
- proto = htons(ETHERTYPE_MPLS);
+ proto = htons(ETHERTYPE_MPLS);
break;
#endif
default:
unhandled_af(m->m_pkthdr.ph_family);
}
+ if (tttl == -1) {
+ m = m_pullup(m, ttloff + 1);
+ if (m == NULL)
+ continue;
+
+ ttl = *(m->m_data + ttloff);
+ } else
+ ttl = tttl;
+
m = gre_encap(&sc->sc_tunnel, m, proto);
- if (m == NULL || gre_ip_output(&sc->sc_tunnel, m, tos) != 0) {
+ if (m == NULL ||
+ gre_ip_output(&sc->sc_tunnel, m, ttl, tos) != 0) {
ifp->if_oerrors++;
continue;
}
#endif
m = gre_encap(&sc->sc_tunnel, m, htons(ETHERTYPE_TRANSETHER));
- if (m == NULL || gre_ip_output(&sc->sc_tunnel, m, 0) != 0) {
+ if (m == NULL || gre_ip_output(&sc->sc_tunnel, m,
+ sc->sc_tunnel.t_ttl, 0) != 0) {
ifp->if_oerrors++;
continue;
}
}
static int
-gre_ip_output(const struct gre_tunnel *tunnel, struct mbuf *m, uint8_t tos)
+gre_ip_output(const struct gre_tunnel *tunnel, struct mbuf *m,
+ uint8_t ttl, uint8_t tos)
{
- m = gre_ip_encap(tunnel, m, tos);
+ m = gre_ip_encap(tunnel, m, ttl, tos);
if (m == NULL)
return (-1);
}
static struct mbuf *
-gre_ip_encap(const struct gre_tunnel *tunnel, struct mbuf *m, uint8_t tos)
+gre_ip_encap(const struct gre_tunnel *tunnel, struct mbuf *m,
+ uint8_t ttl, uint8_t tos)
{
m->m_flags &= ~(M_BCAST|M_MCAST);
m->m_pkthdr.ph_rtableid = tunnel->t_rtableid;
ip->ip_off = 0; /* DF ? */
ip->ip_tos = tos;
ip->ip_len = htons(m->m_pkthdr.len);
- ip->ip_ttl = tunnel->t_ttl;
+ ip->ip_ttl = ttl;
ip->ip_p = IPPROTO_GRE;
ip->ip_src.s_addr = tunnel->t_src[0];
ip->ip_dst.s_addr = tunnel->t_dst[0];
ip6->ip6_vfc |= IPV6_VERSION;
ip6->ip6_plen = htons(len);
ip6->ip6_nxt = IPPROTO_GRE;
- ip6->ip6_hlim = tunnel->t_ttl;
+ ip6->ip6_hlim = ttl;
memcpy(&ip6->ip6_src, tunnel->t_src, sizeof(ip6->ip6_src));
memcpy(&ip6->ip6_dst, tunnel->t_dst, sizeof(ip6->ip6_dst));
break;
ifr->ifr_rdomainid = tunnel->t_rtableid;
break;
- case SIOCSLIFPHYTTL:
- if (ifr->ifr_ttl < 1 || ifr->ifr_ttl > 0xff) {
- error = EINVAL;
- break;
- }
-
- /* commit */
- tunnel->t_ttl = (uint8_t)ifr->ifr_ttl;
- break;
-
- case SIOCGLIFPHYTTL:
- ifr->ifr_ttl = (int)tunnel->t_ttl;
- break;
-
default:
error = ENOTTY;
break;
gre_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
{
struct gre_softc *sc = ifp->if_softc;
+ struct ifreq *ifr = (struct ifreq *)data;
struct ifkalivereq *ikar = (struct ifkalivereq *)data;
int error = 0;
ikar->ikar_timeo = sc->sc_ka_timeo;
break;
+ case SIOCSLIFPHYTTL:
+ if (ifr->ifr_ttl != -1 &&
+ (ifr->ifr_ttl < 1 || ifr->ifr_ttl > 0xff)) {
+ error = EINVAL;
+ break;
+ }
+
+ /* commit */
+ sc->sc_tunnel.t_ttl = ifr->ifr_ttl;
+ break;
+
+ case SIOCGLIFPHYTTL:
+ ifr->ifr_ttl = sc->sc_tunnel.t_ttl;
+ break;
+
default:
error = gre_tunnel_ioctl(ifp, &sc->sc_tunnel, cmd, data);
break;
egre_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
{
struct egre_softc *sc = ifp->if_softc;
+ struct ifreq *ifr = (struct ifreq *)data;
int error = 0;
switch(cmd) {
}
break;
+ case SIOCSLIFPHYTTL:
+ if (ifr->ifr_ttl < 1 || ifr->ifr_ttl > 0xff) {
+ error = EINVAL;
+ break;
+ }
+
+ /* commit */
+ sc->sc_tunnel.t_ttl = (uint8_t)ifr->ifr_ttl;
+ break;
+
+ case SIOCGLIFPHYTTL:
+ ifr->ifr_ttl = (int)sc->sc_tunnel.t_ttl;
+ break;
+
default:
error = gre_tunnel_ioctl(ifp, &sc->sc_tunnel, cmd, data);
if (error == ENOTTY)
SIPHASH_CTX ctx;
int linkhdr, len;
uint16_t proto;
+ uint8_t ttl;
if (!ISSET(sc->sc_if.if_flags, IFF_RUNNING) ||
sc->sc_ka_state == GRE_KA_NONE)
if (m == NULL)
return;
+ ttl = sc->sc_tunnel.t_ttl == -1 ? ip_defttl : sc->sc_tunnel.t_ttl;
+
t.t_af = sc->sc_tunnel.t_af;
- t.t_ttl = sc->sc_tunnel.t_ttl;
memcpy(t.t_src, sc->sc_tunnel.t_dst, sizeof(t.t_src));
memcpy(t.t_dst, sc->sc_tunnel.t_src, sizeof(t.t_dst));
- m = gre_ip_encap(&t, m, 0);
+ m = gre_ip_encap(&t, m, ttl, 0);
if (m == NULL)
return;
m->m_pkthdr.ph_ifidx = sc->sc_if.if_index;
m->m_pkthdr.ph_rtableid = sc->sc_if.if_rdomain;
- gre_ip_output(&sc->sc_tunnel, m, 0);
+ gre_ip_output(&sc->sc_tunnel, m, ttl, 0);
timeout_add_sec(&sc->sc_ka_send, sc->sc_ka_timeo);
}