The 'proto' parameter should be used to get the protocol number (UDP or UDPLITE), instead of ip6->ip6_nxt in udp6_input(). Because ip6->ip6_nxt may be the protocol number of extension header, such as: If a UDP packet is an "atomic" fragment, frag6_input() will return directly, and ip6->ip6_nxt will be IPPROTO_FRAGMENT (if the first extension header is the fragment header) instead of IPPROTO_UDP or IPPROTO_UDPLITE: int frag6_input(struct mbuf **mp, int *offp, int proto) { ...... /* * RFC 6946: Handle "atomic" fragments (offset and m bit set to 0) * upfront, unrelated to any reassembly. Just skip the fragment header. */ if ((ip6f->ip6f_offlg & ~IP6F_RESERVED_MASK) == 0) { /* XXX-BZ we want dedicated counters for this. */ IP6STAT_INC(ip6s_reassembled); in6_ifstat_inc(dstifp, ifs6_reass_ok); *offp = offset; return (ip6f->ip6f_nxt); } And this is the patch to fix this bug: diff --git a/sys/netinet6/udp6_usrreq.c b/sys/netinet6/udp6_usrreq.c index 98790a8..da72f00 100644 --- a/sys/netinet6/udp6_usrreq.c +++ b/sys/netinet6/udp6_usrreq.c @@ -207,7 +207,7 @@ udp6_input(struct mbuf **mp, int *offp, int proto) struct sockaddr_in6 fromsa; struct m_tag *fwd_tag; uint16_t uh_sum; - uint8_t nxt; + uint8_t nxt = proto; ifp = m->m_pkthdr.rcvif; ip6 = mtod(m, struct ip6_hdr *); @@ -233,7 +233,6 @@ udp6_input(struct mbuf **mp, int *offp, int proto) plen = ntohs(ip6->ip6_plen) - off + sizeof(*ip6); ulen = ntohs((u_short)uh->uh_ulen); - nxt = ip6->ip6_nxt; cscov_partial = (nxt == IPPROTO_UDPLITE) ? 1 : 0; if (nxt == IPPROTO_UDPLITE) { /* Zero means checksum over the complete packet. */
Sorry, did not forget. This is yours (shortened) and two more extra UDP-Lite "nxt" fixes. I'll put them up for review. Index: sys/netinet6/udp6_usrreq.c =================================================================== --- sys/netinet6/udp6_usrreq.c (revision 287907) +++ sys/netinet6/udp6_usrreq.c (working copy) @@ -233,7 +233,7 @@ udp6_input(struct mbuf **mp, int *offp, int proto) plen = ntohs(ip6->ip6_plen) - off + sizeof(*ip6); ulen = ntohs((u_short)uh->uh_ulen); - nxt = ip6->ip6_nxt; + nxt = proto; cscov_partial = (nxt == IPPROTO_UDPLITE) ? 1 : 0; if (nxt == IPPROTO_UDPLITE) { /* Zero means checksum over the complete packet. */ @@ -668,9 +668,11 @@ udp6_output(struct inpcb *inp, struct mbuf *m, str return (error); } + nxt = (inp->inp_socket->so_proto->pr_protocol == IPPROTO_UDP) ? + IPPROTO_UDP : IPPROTO_UDPLITE; if (control) { if ((error = ip6_setpktopts(control, &opt, - inp->in6p_outputopts, td->td_ucred, IPPROTO_UDP)) != 0) + inp->in6p_outputopts, td->td_ucred, nxt)) != 0) goto release; optp = &opt; } else @@ -794,8 +796,6 @@ udp6_output(struct inpcb *inp, struct mbuf *m, str /* * Stuff checksum and output datagram. */ - nxt = (inp->inp_socket->so_proto->pr_protocol == IPPROTO_UDP) ? - IPPROTO_UDP : IPPROTO_UDPLITE; udp6 = (struct udphdr *)(mtod(m, caddr_t) + hlen); udp6->uh_sport = inp->inp_lport; /* lport is always set in the PCB */ udp6->uh_dport = fport; @@ -1218,7 +1218,10 @@ udp6_send(struct socket *so, int flags, struct mbu } if (hasv4addr) { struct pr_usrreqs *pru; + uint8_t nxt; + nxt = (inp->inp_socket->so_proto->pr_protocol == + IPPROTO_UDP) ? IPPROTO_UDP : IPPROTO_UDPLITE; /* * XXXRW: We release UDP-layer locks before calling * udp_send() in order to avoid recursion. However, @@ -1230,7 +1233,7 @@ udp6_send(struct socket *so, int flags, struct mbu INP_WUNLOCK(inp); if (sin6) in6_sin6_2_sin_in_sock(addr); - pru = inetsw[ip_protox[IPPROTO_UDP]].pr_usrreqs; + pru = inetsw[ip_protox[nxt]].pr_usrreqs; /* addr will just be freed in sendit(). */ return ((*pru->pru_send)(so, flags, m, addr, control, td));
https://reviews.freebsd.org/D3686
(In reply to Bjoern A. Zeeb from comment #1) Never mind! Thank you very much! ^_^
A commit references this bug: Author: bz Date: Mon Sep 21 12:32:37 UTC 2015 New revision: 288065 URL: https://svnweb.freebsd.org/changeset/base/288065 Log: In the UDP over IPv6 implementation several cases are using the wrong protocol, e.g., based on wrong "next header" assumptions (which does not have to point to the upper layer protocol), or using hard-coded UDP instead of UDP or UDP-Lite possibly switching protocols. Fix those cases for UDP-Lite to work correctly. PR: 202788 Submitted by: Tiwei Bie (btw mail.ustc.edu.cn) [parts] Reviewed by: gnn, Tiwei Bie (btw mail.ustc.edu.cn), kevlo (earlier version) MFC after: 2 weeks Differential Revision: https://reviews.freebsd.org/D3686 Changes: head/sys/netinet6/udp6_usrreq.c