diff --git a/sys/arch/xen/xen/if_xennet_xenbus.c b/sys/arch/xen/xen/if_xennet_xenbus.c index 1062d8c26db0..867811afbb50 100644 --- a/sys/arch/xen/xen/if_xennet_xenbus.c +++ b/sys/arch/xen/xen/if_xennet_xenbus.c @@ -1,4 +1,4 @@ -/* $NetBSD: if_xennet_xenbus.c,v 1.92 2020/03/19 10:53:43 jdolecek Exp $ */ +/* $NetBSD: if_xennet_xenbus.c,v 1.93 2020/03/22 00:11:02 jdolecek Exp $ */ /* * Copyright (c) 2006 Manuel Bouyer. @@ -84,7 +84,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: if_xennet_xenbus.c,v 1.92 2020/03/19 10:53:43 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_xennet_xenbus.c,v 1.93 2020/03/22 00:11:02 jdolecek Exp $"); #include "opt_xen.h" #include "opt_nfs_boot.h" @@ -389,7 +389,14 @@ xennet_xenbus_attach(device_t parent, device_t self, void *aux) ifp->if_capabilities = IFCAP_CSUM_IPv4_Rx | IFCAP_CSUM_IPv4_Tx | IFCAP_CSUM_UDPv4_Rx | IFCAP_CSUM_UDPv4_Tx - | IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_TCPv4_Tx; + | IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_TCPv4_Tx + | IFCAP_CSUM_UDPv6_Rx | IFCAP_CSUM_UDPv6_Tx + | IFCAP_CSUM_TCPv6_Rx | IFCAP_CSUM_TCPv6_Tx; +#define XN_M_CSUM_SUPPORTED ( \ + M_CSUM_TCPv4 | M_CSUM_UDPv4 | M_CSUM_IPv4 \ + | M_CSUM_TCPv6 | M_CSUM_UDPv6 \ + ) + IFQ_SET_READY(&ifp->if_snd); if_attach(ifp); ether_ifattach(ifp, sc->sc_enaddr); @@ -1229,8 +1236,7 @@ xennet_softstart(void *arg) break; } - if ((m->m_pkthdr.csum_flags & - (M_CSUM_TCPv4 | M_CSUM_UDPv4 | M_CSUM_IPv4)) != 0) { + if ((m->m_pkthdr.csum_flags & XN_M_CSUM_SUPPORTED) != 0) { txflags = NETTXF_csum_blank; } else { txflags = NETTXF_data_validated; diff --git a/sys/arch/xen/xen/xennet_checksum.c b/sys/arch/xen/xen/xennet_checksum.c index 817cb3eb6214..597f325ad2f7 100644 --- a/sys/arch/xen/xen/xennet_checksum.c +++ b/sys/arch/xen/xen/xennet_checksum.c @@ -1,4 +1,4 @@ -/* $NetBSD: xennet_checksum.c,v 1.8 2020/03/19 10:53:43 jdolecek Exp $ */ +/* $NetBSD: xennet_checksum.c,v 1.9 2020/03/22 00:11:02 jdolecek Exp $ */ /*- * Copyright (c)2006 YAMAMOTO Takashi, @@ -27,7 +27,11 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: xennet_checksum.c,v 1.8 2020/03/19 10:53:43 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: xennet_checksum.c,v 1.9 2020/03/22 00:11:02 jdolecek Exp $"); + +#ifdef _KERNEL_OPT +#include "opt_inet.h" +#endif #include #include @@ -43,6 +47,8 @@ __KERNEL_RCSID(0, "$NetBSD: xennet_checksum.c,v 1.8 2020/03/19 10:53:43 jdolecek #include #include #include +#include +#include #include @@ -57,16 +63,15 @@ EVCNT_ATTACH_STATIC(xn_cksum_defer); EVCNT_ATTACH_STATIC(xn_cksum_undefer); EVCNT_ATTACH_STATIC(xn_cksum_valid); +#ifdef XENNET_DEBUG /* ratecheck(9) for checksum validation failures */ static const struct timeval xn_cksum_errintvl = { 600, 0 }; /* 10 min, each */ +#endif static void * m_extract(struct mbuf *m, int off, int len) { - KASSERT(m->m_pkthdr.len >= off + len); - KASSERT(m->m_len >= off + len); - - if (m->m_pkthdr.len >= off + len) + if (m->m_len >= off + len) return mtod(m, char *) + off; else return NULL; @@ -80,7 +85,10 @@ int xennet_checksum_fill(struct ifnet *ifp, struct mbuf *m, bool data_validated) { const struct ether_header *eh; - struct ip *iph; + struct ip *iph = NULL; +#ifdef INET6 + struct ip6_hdr *ip6h = NULL; +#endif int ehlen; int iphlen; int iplen; @@ -98,27 +106,49 @@ xennet_checksum_fill(struct ifnet *ifp, struct mbuf *m, bool data_validated) return EINVAL; } etype = eh->ether_type; - if (etype == htobe16(ETHERTYPE_VLAN)) { - ehlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; - } else if (etype == htobe16(ETHERTYPE_IP)) { - ehlen = ETHER_HDR_LEN; - } else { - static struct timeval lasttime; - if (ratecheck(&lasttime, &xn_cksum_errintvl)) - printf("%s: unknown etype %#x passed%s\n", - ifp->if_xname, ntohs(etype), - data_validated ? "" : " no checksum"); - return EINVAL; + ehlen = ETHER_HDR_LEN; + if (__predict_false(etype == htons(ETHERTYPE_VLAN))) { + struct ether_vlan_header *evl = m_extract(m, 0, sizeof(*evl)); + if (evl == NULL) { + /* Too short, packet will be dropped by upper layer */ + return EINVAL; + } + ehlen += ETHER_VLAN_ENCAP_LEN; + etype = ntohs(evl->evl_proto); } - iph = m_extract(m, ehlen, sizeof(*iph)); - if (iph == NULL) { - /* Too short, packet will be dropped by upper layer */ - return EINVAL; + switch (etype) { + case htons(ETHERTYPE_IP): + iph = m_extract(m, ehlen, sizeof(*iph)); + if (iph == NULL) { + /* Too short, packet will be dropped by upper layer */ + return EINVAL; + } + nxt = iph->ip_p; + iphlen = iph->ip_hl << 2; + iplen = ntohs(iph->ip_len); + break; +#ifdef INET6 + case htons(ETHERTYPE_IPV6): + ip6h = m_extract(m, ehlen, sizeof(*ip6h)); + if (ip6h == NULL) { + /* Too short, packet will be dropped by upper layer */ + return EINVAL; + } + if ((ip6h->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) { + /* Bad version */ + return EINVAL; + } + nxt = ip6h->ip6_nxt; + iphlen = sizeof(*ip6h); + iplen = ntohs(ip6h->ip6_plen); + break; +#endif + default: + /* Not supported ethernet type */ + return EOPNOTSUPP; } - nxt = iph->ip_p; - iphlen = iph->ip_hl << 2; - iplen = ntohs(iph->ip_len); + if (ehlen + iplen > m->m_pkthdr.len) { /* Too short, packet will be dropped by upper layer */ return EINVAL; @@ -126,27 +156,47 @@ xennet_checksum_fill(struct ifnet *ifp, struct mbuf *m, bool data_validated) switch (nxt) { case IPPROTO_UDP: - m->m_pkthdr.csum_flags = M_CSUM_UDPv4 | M_CSUM_IPv4; + if (iph) + m->m_pkthdr.csum_flags = M_CSUM_UDPv4 | M_CSUM_IPv4; +#ifdef INET6 + else + m->m_pkthdr.csum_flags = M_CSUM_UDPv6; +#endif m->m_pkthdr.csum_data = offsetof(struct udphdr, uh_sum); m->m_pkthdr.csum_data |= iphlen << 16; break; case IPPROTO_TCP: - m->m_pkthdr.csum_flags = M_CSUM_TCPv4 | M_CSUM_IPv4; + if (iph) + m->m_pkthdr.csum_flags = M_CSUM_TCPv4 | M_CSUM_IPv4; +#ifdef INET6 + else + m->m_pkthdr.csum_flags = M_CSUM_TCPv6; +#endif m->m_pkthdr.csum_data = offsetof(struct tcphdr, th_sum); m->m_pkthdr.csum_data |= iphlen << 16; break; case IPPROTO_ICMP: case IPPROTO_IGMP: - m->m_pkthdr.csum_flags = M_CSUM_IPv4; + if (iph) + m->m_pkthdr.csum_flags = M_CSUM_IPv4; m->m_pkthdr.csum_data = iphlen << 16; break; + case IPPROTO_HOPOPTS: + case IPPROTO_ICMPV6: + case IPPROTO_FRAGMENT: + /* nothing to do */ + error = 0; + goto out; + /* NOTREACHED */ default: { +#ifdef XENNET_DEBUG static struct timeval lasttime; if (ratecheck(&lasttime, &xn_cksum_errintvl)) printf("%s: unknown proto %d passed%s\n", ifp->if_xname, nxt, data_validated ? "" : " no checksum"); +#endif /* XENNET_DEBUG */ error = EINVAL; goto out; } @@ -163,7 +213,7 @@ xennet_checksum_fill(struct ifnet *ifp, struct mbuf *m, bool data_validated) * checksumming requires this. in_undefer_cksum() * also needs it to be zero. */ - if (m->m_pkthdr.csum_flags & M_CSUM_IPv4) + if (iph != NULL && (m->m_pkthdr.csum_flags & M_CSUM_IPv4)) iph->ip_sum = 0; if (sw_csum & (M_CSUM_IPv4|M_CSUM_UDPv4|M_CSUM_TCPv4)) { @@ -171,6 +221,13 @@ xennet_checksum_fill(struct ifnet *ifp, struct mbuf *m, bool data_validated) sw_csum & (M_CSUM_IPv4|M_CSUM_UDPv4|M_CSUM_TCPv4)); } +#ifdef INET6 + if (sw_csum & (M_CSUM_UDPv6|M_CSUM_TCPv6)) { + in6_undefer_cksum(m, ehlen, + sw_csum & (M_CSUM_UDPv6|M_CSUM_TCPv6)); + } +#endif + if (m->m_pkthdr.csum_flags != 0) { xn_cksum_defer.ev_count++; #ifdef M_CSUM_BLANK diff --git a/sys/arch/xen/xen/xennetback_xenbus.c b/sys/arch/xen/xen/xennetback_xenbus.c index 2679436ab369..45dd26277345 100644 --- a/sys/arch/xen/xen/xennetback_xenbus.c +++ b/sys/arch/xen/xen/xennetback_xenbus.c @@ -1,4 +1,4 @@ -/* $NetBSD: xennetback_xenbus.c,v 1.83 2020/03/21 23:25:53 jdolecek Exp $ */ +/* $NetBSD: xennetback_xenbus.c,v 1.84 2020/03/22 00:11:02 jdolecek Exp $ */ /* * Copyright (c) 2006 Manuel Bouyer. @@ -25,7 +25,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: xennetback_xenbus.c,v 1.83 2020/03/21 23:25:53 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: xennetback_xenbus.c,v 1.84 2020/03/22 00:11:02 jdolecek Exp $"); #include "opt_xen.h" @@ -306,7 +306,13 @@ xennetback_xenbus_create(struct xenbus_device *xbusd) ifp->if_capabilities = IFCAP_CSUM_IPv4_Tx | IFCAP_CSUM_UDPv4_Tx - | IFCAP_CSUM_TCPv4_Tx; + | IFCAP_CSUM_TCPv4_Tx + | IFCAP_CSUM_UDPv6_Tx + | IFCAP_CSUM_TCPv6_Tx; +#define XN_M_CSUM_SUPPORTED ( \ + M_CSUM_TCPv4 | M_CSUM_UDPv4 | M_CSUM_IPv4 \ + | M_CSUM_TCPv6 | M_CSUM_UDPv6 \ + ) ifp->if_ioctl = xennetback_ifioctl; ifp->if_start = xennetback_ifstart; ifp->if_watchdog = xennetback_ifwatchdog; @@ -1050,7 +1056,7 @@ xennetback_ifsoftstart_transfer(void *arg) rxresp->offset = offset; rxresp->status = m->m_pkthdr.len; if ((m->m_pkthdr.csum_flags & - (M_CSUM_TCPv4 | M_CSUM_UDPv4 | M_CSUM_IPv4)) != 0) { + XN_M_CSUM_SUPPORTED) != 0) { rxresp->flags = NETRXF_csum_blank; } else { rxresp->flags = NETRXF_data_validated; @@ -1366,7 +1372,7 @@ xennetback_ifsoftstart_copy(void *arg) rxresp->offset = 0; rxresp->status = m->m_pkthdr.len; if ((m->m_pkthdr.csum_flags & - (M_CSUM_TCPv4 | M_CSUM_UDPv4 | M_CSUM_IPv4)) != 0) { + XN_M_CSUM_SUPPORTED) != 0) { rxresp->flags = NETRXF_csum_blank; } else { rxresp->flags = NETRXF_data_validated;