Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 21 Sep 2015 12:32:37 +0000 (UTC)
From:      "Bjoern A. Zeeb" <bz@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r288065 - head/sys/netinet6
Message-ID:  <201509211232.t8LCWbmD010440@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: bz
Date: Mon Sep 21 12:32:36 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

Modified:
  head/sys/netinet6/udp6_usrreq.c

Modified: head/sys/netinet6/udp6_usrreq.c
==============================================================================
--- head/sys/netinet6/udp6_usrreq.c	Mon Sep 21 12:23:01 2015	(r288064)
+++ head/sys/netinet6/udp6_usrreq.c	Mon Sep 21 12:32:36 2015	(r288065)
@@ -233,7 +233,7 @@ udp6_input(struct mbuf **mp, int *offp, 
 	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 mb
 			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 mb
 	/*
 	 * 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, 
 		}
 		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, 
 			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));



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201509211232.t8LCWbmD010440>