summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbz <bz@FreeBSD.org>2015-09-21 12:32:36 +0000
committerbz <bz@FreeBSD.org>2015-09-21 12:32:36 +0000
commit3e1ba7cafdfe86d0cb2fc084b9f3bc17af83a65e (patch)
tree1194469741f0415442c5444a9b4f8da5080ad967
parent4d617ecf9d312e2d4fb81973da036c667d7c99ba (diff)
downloadFreeBSD-src-3e1ba7cafdfe86d0cb2fc084b9f3bc17af83a65e.zip
FreeBSD-src-3e1ba7cafdfe86d0cb2fc084b9f3bc17af83a65e.tar.gz
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
-rw-r--r--sys/netinet6/udp6_usrreq.c38
1 files changed, 26 insertions, 12 deletions
diff --git a/sys/netinet6/udp6_usrreq.c b/sys/netinet6/udp6_usrreq.c
index 98790a8..e39db6c 100644
--- a/sys/netinet6/udp6_usrreq.c
+++ b/sys/netinet6/udp6_usrreq.c
@@ -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));
OpenPOWER on IntegriCloud