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
This commit is contained in:
Bjoern A. Zeeb 2015-09-21 12:32:36 +00:00
parent e88445a48b
commit b1ce89f2bc
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=288065

View File

@ -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, struct sockaddr *addr6,
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, struct sockaddr *addr6,
/*
* 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;
@ -912,17 +912,21 @@ udp6_abort(struct socket *so)
inp = sotoinpcb(so);
KASSERT(inp != NULL, ("udp6_abort: inp == NULL"));
INP_WLOCK(inp);
#ifdef INET
if (inp->inp_vflag & INP_IPV4) {
struct pr_usrreqs *pru;
uint8_t nxt;
pru = inetsw[ip_protox[IPPROTO_UDP]].pr_usrreqs;
nxt = (inp->inp_socket->so_proto->pr_protocol == IPPROTO_UDP) ?
IPPROTO_UDP : IPPROTO_UDPLITE;
INP_WUNLOCK(inp);
pru = inetsw[ip_protox[nxt]].pr_usrreqs;
(*pru->pru_abort)(so);
return;
}
#endif
INP_WLOCK(inp);
if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) {
INP_HASH_WLOCK(pcbinfo);
in6_pcbdisconnect(inp);
@ -1036,16 +1040,20 @@ udp6_close(struct socket *so)
inp = sotoinpcb(so);
KASSERT(inp != NULL, ("udp6_close: inp == NULL"));
INP_WLOCK(inp);
#ifdef INET
if (inp->inp_vflag & INP_IPV4) {
struct pr_usrreqs *pru;
uint8_t nxt;
pru = inetsw[ip_protox[IPPROTO_UDP]].pr_usrreqs;
nxt = (inp->inp_socket->so_proto->pr_protocol == IPPROTO_UDP) ?
IPPROTO_UDP : IPPROTO_UDPLITE;
INP_WUNLOCK(inp);
pru = inetsw[ip_protox[nxt]].pr_usrreqs;
(*pru->pru_disconnect)(so);
return;
}
#endif
INP_WLOCK(inp);
if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) {
INP_HASH_WLOCK(pcbinfo);
in6_pcbdisconnect(inp);
@ -1151,18 +1159,21 @@ udp6_disconnect(struct socket *so)
inp = sotoinpcb(so);
KASSERT(inp != NULL, ("udp6_disconnect: inp == NULL"));
INP_WLOCK(inp);
#ifdef INET
if (inp->inp_vflag & INP_IPV4) {
struct pr_usrreqs *pru;
uint8_t nxt;
pru = inetsw[ip_protox[IPPROTO_UDP]].pr_usrreqs;
nxt = (inp->inp_socket->so_proto->pr_protocol == IPPROTO_UDP) ?
IPPROTO_UDP : IPPROTO_UDPLITE;
INP_WUNLOCK(inp);
pru = inetsw[ip_protox[nxt]].pr_usrreqs;
(void)(*pru->pru_disconnect)(so);
return (0);
}
#endif
INP_WLOCK(inp);
if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) {
error = ENOTCONN;
goto out;
@ -1218,7 +1229,10 @@ udp6_send(struct socket *so, int flags, struct mbuf *m,
}
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 +1244,7 @@ udp6_send(struct socket *so, int flags, struct mbuf *m,
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));