-struct pr_usrreqs udp6_usrreqs = {
- udp6_abort, pru_accept_notsupp, udp6_attach, udp6_bind, udp6_connect,
- pru_connect2_notsupp, in6_control, udp6_detach, udp6_disconnect,
- pru_listen_notsupp, in6_mapped_peeraddr, pru_rcvd_notsupp,
- pru_rcvoob_notsupp, udp6_send, pru_sense_null, udp_shutdown,
- in6_mapped_sockaddr, sosend, soreceive, pru_sopoll_notsupp
-};
+/*
+ * Checksum extended UDP header and data.
+ */
+static int
+udp6_input_checksum(struct mbuf *m, struct udphdr *uh, int off, int ulen)
+{
+ struct ifnet *ifp = m->m_pkthdr.rcvif;
+ struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
+
+ if (!(m->m_pkthdr.csum_flags & CSUM_DATA_VALID) &&
+ uh->uh_sum == 0) {
+ /* UDP/IPv6 checksum is mandatory (RFC2460) */
+
+ /*
+ * If checksum was already validated, ignore this check.
+ * This is necessary for transport-mode ESP, which may be
+ * getting UDP payloads without checksums when the network
+ * has a NAT64.
+ */
+ udpstat.udps_nosum++;
+ goto badsum;
+ }
+
+ 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 {
+ uint32_t sum = m->m_pkthdr.csum_rx_val;
+ uint32_t start = m->m_pkthdr.csum_rx_start;
+ int32_t trailer = (m_pktlen(m) - (off + ulen));
+
+ /*
+ * Perform 1's complement adjustment of octets
+ * that got included/excluded in the hardware-
+ * calculated checksum value. Also take care
+ * of any trailing bytes and subtract out
+ * their partial sum.
+ */
+ ASSERT(trailer >= 0);
+ if ((m->m_pkthdr.csum_flags & CSUM_PARTIAL) &&
+ (start != off || trailer != 0)) {
+ uint32_t swbytes = (uint32_t)trailer;
+ uint16_t s = 0, d = 0;
+
+ if (IN6_IS_SCOPE_EMBED(&ip6->ip6_src)) {
+ s = ip6->ip6_src.s6_addr16[1];
+ ip6->ip6_src.s6_addr16[1] = 0;
+ }
+ if (IN6_IS_SCOPE_EMBED(&ip6->ip6_dst)) {
+ d = ip6->ip6_dst.s6_addr16[1];
+ ip6->ip6_dst.s6_addr16[1] = 0;
+ }
+
+ /* callee folds in sum */
+ sum = m_adj_sum16(m, start, off, ulen, sum);
+ if (off > start) {
+ swbytes += (off - start);
+ } else {
+ swbytes += (start - off);
+ }
+
+ if (IN6_IS_SCOPE_EMBED(&ip6->ip6_src)) {
+ ip6->ip6_src.s6_addr16[1] = s;
+ }
+ if (IN6_IS_SCOPE_EMBED(&ip6->ip6_dst)) {
+ ip6->ip6_dst.s6_addr16[1] = d;
+ }
+
+ if (swbytes != 0) {
+ udp_in_cksum_stats(swbytes);
+ }
+ if (trailer != 0) {
+ m_adj(m, -trailer);
+ }
+ }
+
+ uh->uh_sum = in6_pseudo(&ip6->ip6_src, &ip6->ip6_dst,
+ sum + htonl(ulen + IPPROTO_UDP));
+ }
+ uh->uh_sum ^= 0xffff;
+ } else {
+ udp_in6_cksum_stats(ulen);
+ uh->uh_sum = in6_cksum(m, IPPROTO_UDP, off, ulen);
+ }
+
+ if (uh->uh_sum != 0) {
+badsum:
+ udpstat.udps_badsum++;
+ IF_UDP_STATINC(ifp, badchksum);
+ return -1;
+ }
+
+ return 0;
+}