summaryrefslogtreecommitdiff
path: root/sys/net/if_mpe.c
diff options
context:
space:
mode:
authorDavid Gwynne <dlg@cvs.openbsd.org>2019-01-27 04:54:07 +0000
committerDavid Gwynne <dlg@cvs.openbsd.org>2019-01-27 04:54:07 +0000
commit84e533500e78fbc72989b21205c01ed0ef5ccbdb (patch)
tree3287ff3708d9b5b119fe8f283a33118bdd2f0adf /sys/net/if_mpe.c
parent69150e97f044d4b63031c49d64c7a43a0cd70102 (diff)
rework mpe_input so it patches ipv4 cksum, and handles ipv6 too.
rather than check and recalculate the ipv4 checksum, we can update the cksum incrementally. this is a bit faster, and means we'll see more things on bpf. also, peek at the first nibble so we can tell ipv6 from ipv4. i consider them the same FEC, so either can be received now.
Diffstat (limited to 'sys/net/if_mpe.c')
-rw-r--r--sys/net/if_mpe.c93
1 files changed, 58 insertions, 35 deletions
diff --git a/sys/net/if_mpe.c b/sys/net/if_mpe.c
index eadc0794919..1e556d96401 100644
--- a/sys/net/if_mpe.c
+++ b/sys/net/if_mpe.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_mpe.c,v 1.68 2019/01/27 04:20:59 dlg Exp $ */
+/* $OpenBSD: if_mpe.c,v 1.69 2019/01/27 04:54:06 dlg Exp $ */
/*
* Copyright (c) 2008 Pierre-Yves Ritschard <pyr@spootnik.org>
@@ -387,48 +387,66 @@ void
mpe_input(struct ifnet *ifp, struct mbuf *m)
{
struct shim_hdr *shim;
- struct ip *ip;
- int hlen;
+ struct mbuf *n;
uint8_t ttl;
+ void (*input)(struct ifnet *, struct mbuf *);
shim = mtod(m, struct shim_hdr *);
- if (!MPLS_BOS_ISSET(shim->shim_label)) {
- m_freem(m);
- return;
- }
+ if (!MPLS_BOS_ISSET(shim->shim_label))
+ goto drop;
+
ttl = ntohl(shim->shim_label & MPLS_TTL_MASK);
m_adj(m, sizeof(*shim));
- if (m->m_len < sizeof(*ip)) {
- m = m_pullup(m, sizeof(*ip));
- if (m == NULL)
- return;
- }
- ip = mtod(m, struct ip *);
- if (ip->ip_v != IPVERSION) {
- m_freem(m);
- return;
+ n = m;
+ while (n->m_len == 0) {
+ n = n->m_next;
+ if (n == NULL)
+ goto drop;
}
- if (mpls_mapttl_ip) {
- hlen = ip->ip_hl << 2;
- if (m->m_len < hlen) {
- if ((m = m_pullup(m, hlen)) == NULL)
- return;
- ip = mtod(m, struct ip *);
- }
+ switch (*mtod(n, uint8_t *) >> 4) {
+ case 4:
+ if (mpls_mapttl_ip) {
+ struct ip *ip;
+ uint16_t old, new, x;
- if (in_cksum(m, hlen) != 0) {
- m_freem(m);
- return;
- }
+ if (m->m_len < sizeof(*ip)) {
+ m = m_pullup(m, sizeof(*ip));
+ if (m == NULL)
+ return;
+ }
+ ip = mtod(m, struct ip *);
- /* set IP ttl from MPLS ttl */
- ip->ip_ttl = ttl;
+ old = htons(ip->ip_ttl << 8);
+ new = htons(ttl << 8);
+ x = ip->ip_sum + old - new;
- /* recalculate checksum */
- ip->ip_sum = 0;
- ip->ip_sum = in_cksum(m, hlen);
+ ip->ip_ttl = ttl;
+ ip->ip_sum = (x) + (x >> 16);
+ }
+ input = ipv4_input;
+ m->m_pkthdr.ph_family = AF_INET;
+ break;
+#ifdef INET6
+ case 6:
+ if (mpls_mapttl_ip6) {
+ struct ip6_hdr *ip6;
+
+ if (m->m_len < sizeof(*ip6)) {
+ m = m_pullup(m, sizeof(*ip6));
+ if (m == NULL)
+ return;
+ }
+ ip6 = mtod(m, struct ip6_hdr *);
+ ip6->ip6_hlim = ttl;
+ }
+ input = ipv6_input;
+ m->m_pkthdr.ph_family = AF_INET6;
+ break;
+#endif /* INET6 */
+ default:
+ goto drop;
}
/* new receive if and move into correct rtable */
@@ -436,9 +454,14 @@ mpe_input(struct ifnet *ifp, struct mbuf *m)
m->m_pkthdr.ph_rtableid = ifp->if_rdomain;
#if NBPFILTER > 0
- if (ifp->if_bpf)
- bpf_mtap_af(ifp->if_bpf, AF_INET, m, BPF_DIRECTION_IN);
+ if (ifp->if_bpf) {
+ bpf_mtap_af(ifp->if_bpf, m->m_pkthdr.ph_family,
+ m, BPF_DIRECTION_IN);
+ }
#endif
- ipv4_input(ifp, m);
+ (*input)(ifp, m);
+ return;
+drop:
+ m_freem(m);
}