+ udpstat.udps_snd_swcsum++;
+ udpstat.udps_snd_swcsum_bytes += len;
+}
+
+#if INET6
+void
+udp_in6_cksum_stats(u_int32_t len)
+{
+ udpstat.udps_rcv6_swcsum++;
+ udpstat.udps_rcv6_swcsum_bytes += len;
+}
+
+void
+udp_out6_cksum_stats(u_int32_t len)
+{
+ udpstat.udps_snd6_swcsum++;
+ udpstat.udps_snd6_swcsum_bytes += len;
+}
+#endif /* INET6 */
+
+/*
+ * Checksum extended UDP header and data.
+ */
+static int
+udp_input_checksum(struct mbuf *m, struct udphdr *uh, int off, int ulen)
+{
+ struct ifnet *ifp = m->m_pkthdr.rcvif;
+ struct ip *ip = mtod(m, struct ip *);
+ struct ipovly *ipov = (struct ipovly *)ip;
+
+ if (uh->uh_sum == 0) {
+ udpstat.udps_nosum++;
+ return (0);
+ }
+
+ if ((hwcksum_rx || (ifp->if_flags & IFF_LOOPBACK) ||
+ (m->m_pkthdr.pkt_flags & PKTF_LOOP)) &&
+ (m->m_pkthdr.csum_flags & CSUM_DATA_VALID)) {
+ if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR) {
+ uh->uh_sum = m->m_pkthdr.csum_rx_val;
+ } else {
+ uint16_t sum = m->m_pkthdr.csum_rx_val;
+ uint16_t start = m->m_pkthdr.csum_rx_start;
+
+ /*
+ * Perform 1's complement adjustment of octets
+ * that got included/excluded in the hardware-
+ * calculated checksum value. Ignore cases
+ * where the value includes or excludes the
+ * IP header span, as the sum for those octets
+ * would already be 0xffff and thus no-op.
+ */
+ if ((m->m_pkthdr.csum_flags & CSUM_PARTIAL) &&
+ start != 0 && (off - start) != off) {
+#if BYTE_ORDER != BIG_ENDIAN
+ if (start < off) {
+ HTONS(ip->ip_len);
+ HTONS(ip->ip_off);
+ }
+#endif /* BYTE_ORDER != BIG_ENDIAN */
+ /* callee folds in sum */
+ sum = m_adj_sum16(m, start, off, sum);
+#if BYTE_ORDER != BIG_ENDIAN
+ if (start < off) {
+ NTOHS(ip->ip_off);
+ NTOHS(ip->ip_len);
+ }
+#endif /* BYTE_ORDER != BIG_ENDIAN */
+ }
+
+ /* callee folds in sum */
+ uh->uh_sum = in_pseudo(ip->ip_src.s_addr,
+ ip->ip_dst.s_addr, sum + htonl(ulen + IPPROTO_UDP));
+ }
+ uh->uh_sum ^= 0xffff;
+ } else {
+ uint16_t ip_sum;
+ char b[9];
+
+ bcopy(ipov->ih_x1, b, sizeof (ipov->ih_x1));
+ bzero(ipov->ih_x1, sizeof (ipov->ih_x1));
+ ip_sum = ipov->ih_len;
+ ipov->ih_len = uh->uh_ulen;
+ uh->uh_sum = in_cksum(m, ulen + sizeof (struct ip));
+ bcopy(b, ipov->ih_x1, sizeof (ipov->ih_x1));
+ ipov->ih_len = ip_sum;
+
+ udp_in_cksum_stats(ulen);
+ }
+
+ if (uh->uh_sum != 0) {
+ udpstat.udps_badsum++;
+ IF_UDP_STATINC(ifp, badchksum);
+ return (-1);
+ }
+
+ return (0);