From c89c8a1029860182eece5d51ec09119b9500e5a1 Mon Sep 17 00:00:00 2001 From: Marius Strobl Date: Sat, 7 Mar 2009 19:08:58 +0000 Subject: [PATCH] On architectures with strict alignment requirements compensate the misalignment of the IP header that prepending the EtherIP header might have caused. PR: 131921 MFC after: 1 week --- sys/net/if_gif.h | 2 ++ sys/netinet/in_gif.c | 22 ++++++++++++++++++---- sys/netinet6/in6_gif.c | 22 ++++++++++++++++++---- 3 files changed, 38 insertions(+), 8 deletions(-) diff --git a/sys/net/if_gif.h b/sys/net/if_gif.h index 2ba7bd399a1a..0fe45b31a88c 100644 --- a/sys/net/if_gif.h +++ b/sys/net/if_gif.h @@ -100,6 +100,8 @@ struct etherip_header { #define ETHERIP_VER_VERS_MASK 0x0f #define ETHERIP_VER_RSVD_MASK 0xf0 #define ETHERIP_VERSION 0x03 +/* mbuf adjust factor to force 32-bit alignment of IP header */ +#define ETHERIP_ALIGN 2 /* Prototypes */ void gif_input(struct mbuf *, int, struct ifnet *); diff --git a/sys/netinet/in_gif.c b/sys/netinet/in_gif.c index 9bcb09e1c068..a05c04bc295e 100644 --- a/sys/netinet/in_gif.c +++ b/sys/netinet/in_gif.c @@ -102,7 +102,7 @@ in_gif_output(struct ifnet *ifp, int family, struct mbuf *m) struct sockaddr_in *sin_dst = (struct sockaddr_in *)sc->gif_pdst; struct ip iphdr; /* capsule IP header, host byte ordered */ struct etherip_header eiphdr; - int proto, error; + int error, len, proto; u_int8_t tos; GIF_LOCK_ASSERT(sc); @@ -186,13 +186,27 @@ in_gif_output(struct ifnet *ifp, int family, struct mbuf *m) &iphdr.ip_tos, &tos); /* prepend new IP header */ - M_PREPEND(m, sizeof(struct ip), M_DONTWAIT); - if (m && m->m_len < sizeof(struct ip)) - m = m_pullup(m, sizeof(struct ip)); + len = sizeof(struct ip); +#ifndef __NO_STRICT_ALIGNMENT + if (family == AF_LINK) + len += ETHERIP_ALIGN; +#endif + M_PREPEND(m, len, M_DONTWAIT); + if (m != NULL && m->m_len < len) + m = m_pullup(m, len); if (m == NULL) { printf("ENOBUFS in in_gif_output %d\n", __LINE__); return ENOBUFS; } +#ifndef __NO_STRICT_ALIGNMENT + if (family == AF_LINK) { + len = mtod(m, vm_offset_t) & 3; + KASSERT(len == 0 || len == ETHERIP_ALIGN, + ("in_gif_output: unexpected misalignment")); + m->m_data += len; + m->m_len -= ETHERIP_ALIGN; + } +#endif bcopy(&iphdr, mtod(m, struct ip *), sizeof(struct ip)); M_SETFIB(m, sc->gif_fibnum); diff --git a/sys/netinet6/in6_gif.c b/sys/netinet6/in6_gif.c index bba348f83cb6..7041841e2619 100644 --- a/sys/netinet6/in6_gif.c +++ b/sys/netinet6/in6_gif.c @@ -98,7 +98,7 @@ in6_gif_output(struct ifnet *ifp, struct sockaddr_in6 *sin6_dst = (struct sockaddr_in6 *)sc->gif_pdst; struct ip6_hdr *ip6; struct etherip_header eiphdr; - int proto, error; + int error, len, proto; u_int8_t itos, otos; GIF_LOCK_ASSERT(sc); @@ -166,13 +166,27 @@ in6_gif_output(struct ifnet *ifp, } /* prepend new IP header */ - M_PREPEND(m, sizeof(struct ip6_hdr), M_DONTWAIT); - if (m && m->m_len < sizeof(struct ip6_hdr)) - m = m_pullup(m, sizeof(struct ip6_hdr)); + len = sizeof(struct ip6_hdr); +#ifndef __NO_STRICT_ALIGNMENT + if (family == AF_LINK) + len += ETHERIP_ALIGN; +#endif + M_PREPEND(m, len, M_DONTWAIT); + if (m != NULL && m->m_len < len) + m = m_pullup(m, len); if (m == NULL) { printf("ENOBUFS in in6_gif_output %d\n", __LINE__); return ENOBUFS; } +#ifndef __NO_STRICT_ALIGNMENT + if (family == AF_LINK) { + len = mtod(m, vm_offset_t) & 3; + KASSERT(len == 0 || len == ETHERIP_ALIGN, + ("in6_gif_output: unexpected misalignment")); + m->m_data += len; + m->m_len -= ETHERIP_ALIGN; + } +#endif ip6 = mtod(m, struct ip6_hdr *); ip6->ip6_flow = 0;