git: c0fc81e9138b - main - netinet*: remove dead code from TCP, UDP, SCTP control input

From: Gleb Smirnoff <glebius_at_FreeBSD.org>
Date: Tue, 04 Oct 2022 03:57:35 UTC
The branch main has been updated by glebius:

URL: https://cgit.FreeBSD.org/src/commit/?id=c0fc81e9138b4bc636333285087f1c3e1c7bc1e5

commit c0fc81e9138b4bc636333285087f1c3e1c7bc1e5
Author:     Gleb Smirnoff <glebius@FreeBSD.org>
AuthorDate: 2022-10-04 03:53:04 +0000
Commit:     Gleb Smirnoff <glebius@FreeBSD.org>
CommitDate: 2022-10-04 03:53:04 +0000

    netinet*: remove dead code from TCP, UDP, SCTP control input
    
    Now these functions are called only from icmp*_input().  The pointer
    to the ICMP data is never NULL and cmd has a limited set of values.
    
    In the past the functions were demultiplexing control messages from
    ICMP layer, as well as internally generated events.  In the latter
    case the the pointer to IP would be NULL.
    
    Differential revision:  https://reviews.freebsd.org/D36729
---
 sys/netinet/sctp_usrreq.c   | 145 ++++++++++++++++----------------
 sys/netinet/tcp_subr.c      |  95 +++++++--------------
 sys/netinet/udp_usrreq.c    |  65 ++++++---------
 sys/netinet6/sctp6_usrreq.c | 196 +++++++++++++++++++++-----------------------
 sys/netinet6/udp6_usrreq.c  |  88 +++++++-------------
 5 files changed, 242 insertions(+), 347 deletions(-)

diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c
index fdb195d79656..4c70b618bf41 100644
--- a/sys/netinet/sctp_usrreq.c
+++ b/sys/netinet/sctp_usrreq.c
@@ -260,10 +260,9 @@ sctp_notify(struct sctp_inpcb *inp,
 }
 
 void
-sctp_ctlinput(int cmd, struct sockaddr_in *sin, struct ip *ip)
+sctp_ctlinput(int cmd, struct sockaddr_in *sin, struct ip *inner_ip)
 {
 	struct ip *outer_ip;
-	struct ip *inner_ip;
 	struct sctphdr *sh;
 	struct icmp *icmp;
 	struct sctp_inpcb *inp;
@@ -272,91 +271,85 @@ sctp_ctlinput(int cmd, struct sockaddr_in *sin, struct ip *ip)
 	struct sctp_init_chunk *ch;
 	struct sockaddr_in src, dst;
 
-	if (PRC_IS_REDIRECT(cmd)) {
-		ip = NULL;
-	} else if ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0) {
+	if (inetctlerrmap[cmd] == 0)
 		return;
-	}
-	if (ip != NULL) {
-		inner_ip = ip;
-		icmp = (struct icmp *)((caddr_t)inner_ip -
-		    (sizeof(struct icmp) - sizeof(struct ip)));
-		outer_ip = (struct ip *)((caddr_t)icmp - sizeof(struct ip));
-		sh = (struct sctphdr *)((caddr_t)inner_ip + (inner_ip->ip_hl << 2));
-		memset(&src, 0, sizeof(struct sockaddr_in));
-		src.sin_family = AF_INET;
-		src.sin_len = sizeof(struct sockaddr_in);
-		src.sin_port = sh->src_port;
-		src.sin_addr = inner_ip->ip_src;
-		memset(&dst, 0, sizeof(struct sockaddr_in));
-		dst.sin_family = AF_INET;
-		dst.sin_len = sizeof(struct sockaddr_in);
-		dst.sin_port = sh->dest_port;
-		dst.sin_addr = inner_ip->ip_dst;
-		/*
-		 * 'dst' holds the dest of the packet that failed to be
-		 * sent. 'src' holds our local endpoint address. Thus we
-		 * reverse the dst and the src in the lookup.
-		 */
-		inp = NULL;
-		net = NULL;
-		stcb = sctp_findassociation_addr_sa((struct sockaddr *)&dst,
-		    (struct sockaddr *)&src,
-		    &inp, &net, 1,
-		    SCTP_DEFAULT_VRFID);
-		if ((stcb != NULL) &&
-		    (net != NULL) &&
-		    (inp != NULL)) {
-			/* Check the verification tag */
-			if (ntohl(sh->v_tag) != 0) {
+
+	icmp = (struct icmp *)((caddr_t)inner_ip -
+	    (sizeof(struct icmp) - sizeof(struct ip)));
+	outer_ip = (struct ip *)((caddr_t)icmp - sizeof(struct ip));
+	sh = (struct sctphdr *)((caddr_t)inner_ip + (inner_ip->ip_hl << 2));
+	memset(&src, 0, sizeof(struct sockaddr_in));
+	src.sin_family = AF_INET;
+	src.sin_len = sizeof(struct sockaddr_in);
+	src.sin_port = sh->src_port;
+	src.sin_addr = inner_ip->ip_src;
+	memset(&dst, 0, sizeof(struct sockaddr_in));
+	dst.sin_family = AF_INET;
+	dst.sin_len = sizeof(struct sockaddr_in);
+	dst.sin_port = sh->dest_port;
+	dst.sin_addr = inner_ip->ip_dst;
+	/*
+	 * 'dst' holds the dest of the packet that failed to be
+	 * sent. 'src' holds our local endpoint address. Thus we
+	 * reverse the dst and the src in the lookup.
+	 */
+	inp = NULL;
+	net = NULL;
+	stcb = sctp_findassociation_addr_sa((struct sockaddr *)&dst,
+	    (struct sockaddr *)&src,
+	    &inp, &net, 1,
+	    SCTP_DEFAULT_VRFID);
+	if ((stcb != NULL) &&
+	    (net != NULL) &&
+	    (inp != NULL)) {
+		/* Check the verification tag */
+		if (ntohl(sh->v_tag) != 0) {
+			/*
+			 * This must be the verification tag used
+			 * for sending out packets. We don't
+			 * consider packets reflecting the
+			 * verification tag.
+			 */
+			if (ntohl(sh->v_tag) != stcb->asoc.peer_vtag) {
+				SCTP_TCB_UNLOCK(stcb);
+				return;
+			}
+		} else {
+			if (ntohs(outer_ip->ip_len) >=
+			    sizeof(struct ip) +
+			    8 + (inner_ip->ip_hl << 2) + 20) {
 				/*
-				 * This must be the verification tag used
-				 * for sending out packets. We don't
-				 * consider packets reflecting the
-				 * verification tag.
+				 * In this case we can check if we
+				 * got an INIT chunk and if the
+				 * initiate tag matches.
 				 */
-				if (ntohl(sh->v_tag) != stcb->asoc.peer_vtag) {
+				ch = (struct sctp_init_chunk *)(sh + 1);
+				if ((ch->ch.chunk_type != SCTP_INITIATION) ||
+				    (ntohl(ch->init.initiate_tag) != stcb->asoc.my_vtag)) {
 					SCTP_TCB_UNLOCK(stcb);
 					return;
 				}
 			} else {
-				if (ntohs(outer_ip->ip_len) >=
-				    sizeof(struct ip) +
-				    8 + (inner_ip->ip_hl << 2) + 20) {
-					/*
-					 * In this case we can check if we
-					 * got an INIT chunk and if the
-					 * initiate tag matches.
-					 */
-					ch = (struct sctp_init_chunk *)(sh + 1);
-					if ((ch->ch.chunk_type != SCTP_INITIATION) ||
-					    (ntohl(ch->init.initiate_tag) != stcb->asoc.my_vtag)) {
-						SCTP_TCB_UNLOCK(stcb);
-						return;
-					}
-				} else {
-					SCTP_TCB_UNLOCK(stcb);
-					return;
-				}
-			}
-			sctp_notify(inp, stcb, net,
-			    icmp->icmp_type,
-			    icmp->icmp_code,
-			    ntohs(inner_ip->ip_len),
-			    (uint32_t)ntohs(icmp->icmp_nextmtu));
-		} else {
-			if ((stcb == NULL) && (inp != NULL)) {
-				/* reduce ref-count */
-				SCTP_INP_WLOCK(inp);
-				SCTP_INP_DECR_REF(inp);
-				SCTP_INP_WUNLOCK(inp);
-			}
-			if (stcb) {
 				SCTP_TCB_UNLOCK(stcb);
+				return;
 			}
 		}
+		sctp_notify(inp, stcb, net,
+		    icmp->icmp_type,
+		    icmp->icmp_code,
+		    ntohs(inner_ip->ip_len),
+		    (uint32_t)ntohs(icmp->icmp_nextmtu));
+	} else {
+		if ((stcb == NULL) && (inp != NULL)) {
+			/* reduce ref-count */
+			SCTP_INP_WLOCK(inp);
+			SCTP_INP_DECR_REF(inp);
+			SCTP_INP_WUNLOCK(inp);
+		}
+		if (stcb) {
+			SCTP_TCB_UNLOCK(stcb);
+		}
 	}
-	return;
 }
 #endif
 
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c
index e88b3b92b193..7e9fe9e4ff5f 100644
--- a/sys/netinet/tcp_subr.c
+++ b/sys/netinet/tcp_subr.c
@@ -2866,39 +2866,27 @@ tcp_ctlinput_with_port(int cmd, struct sockaddr_in *sin, struct ip *ip,
 	tcp_seq icmp_tcp_seq;
 	int mtu;
 
-	if (cmd == PRC_MSGSIZE)
+	switch (cmd) {
+	case PRC_MSGSIZE:
 		notify = tcp_mtudisc_notify;
-	else if (V_icmp_may_rst && (cmd == PRC_UNREACH_ADMIN_PROHIB ||
-		cmd == PRC_UNREACH_PORT || cmd == PRC_UNREACH_PROTOCOL ||
-		cmd == PRC_TIMXCEED_INTRANS) && ip)
-		notify = tcp_drop_syn_sent;
-
-	/*
-	 * Hostdead is ugly because it goes linearly through all PCBs.
-	 * XXX: We never get this from ICMP, otherwise it makes an
-	 * excellent DoS attack on machines with many connections.
-	 */
-	else if (cmd == PRC_HOSTDEAD)
-		ip = NULL;
-	else if ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0)
-		return;
+		break;
+	case PRC_UNREACH_PORT:
+	case PRC_UNREACH_PROTOCOL:
+	case PRC_TIMXCEED_INTRANS:
+	case PRC_UNREACH_ADMIN_PROHIB:
+		if (V_icmp_may_rst)
+			notify = tcp_drop_syn_sent;
+		break;
+	}
 
-	if (ip == NULL) {
-		in_pcbnotifyall(&V_tcbinfo, sin->sin_addr, inetctlerrmap[cmd],
-		    notify);
+	if (inetctlerrmap[cmd] == 0)
 		return;
-	}
 
 	icp = (struct icmp *)((caddr_t)ip - offsetof(struct icmp, icmp_ip));
 	th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2));
+	icmp_tcp_seq = th->th_seq;
 	inp = in_pcblookup(&V_tcbinfo, sin->sin_addr, th->th_dport, ip->ip_src,
 	    th->th_sport, INPLOOKUP_WLOCKPCB, NULL);
-	if (inp != NULL && PRC_IS_REDIRECT(cmd)) {
-		/* signal EHOSTDOWN, as it flushes the cached route */
-		inp = (*notify)(inp, EHOSTDOWN);
-		goto out;
-	}
-	icmp_tcp_seq = th->th_seq;
 	if (inp != NULL)  {
 		if (!(inp->inp_flags & INP_TIMEWAIT) &&
 		    !(inp->inp_flags & INP_DROPPED) &&
@@ -3029,7 +3017,6 @@ tcp6_ctlinput_with_port(int cmd, struct sockaddr_in6 *sin6,
 	struct inpcb *inp;
 	struct tcpcb *tp;
 	struct icmp6_hdr *icmp6;
-	const struct sockaddr_in6 *sa6_src = NULL;
 	struct in_conninfo inc;
 	struct tcp_ports {
 		uint16_t th_sport;
@@ -3039,44 +3026,27 @@ tcp6_ctlinput_with_port(int cmd, struct sockaddr_in6 *sin6,
 	unsigned int mtu;
 	unsigned int off;
 
-	/* if the parameter is from icmp6, decode it. */
-	if (ip6cp != NULL) {
-		icmp6 = ip6cp->ip6c_icmp6;
-		m = ip6cp->ip6c_m;
-		ip6 = ip6cp->ip6c_ip6;
-		off = ip6cp->ip6c_off;
-		sa6_src = ip6cp->ip6c_src;
-		dst = ip6cp->ip6c_finaldst;
-	} else {
-		m = NULL;
-		ip6 = NULL;
-		off = 0;	/* fool gcc */
-		sa6_src = &sa6_any;
-		dst = NULL;
-	}
+	icmp6 = ip6cp->ip6c_icmp6;
+	m = ip6cp->ip6c_m;
+	ip6 = ip6cp->ip6c_ip6;
+	off = ip6cp->ip6c_off;
+	dst = ip6cp->ip6c_finaldst;
 
-	if (cmd == PRC_MSGSIZE)
+	switch (cmd) {
+	case PRC_MSGSIZE:
 		notify = tcp_mtudisc_notify;
-	else if (V_icmp_may_rst && (cmd == PRC_UNREACH_ADMIN_PROHIB ||
-		cmd == PRC_UNREACH_PORT || cmd == PRC_UNREACH_PROTOCOL ||
-		cmd == PRC_TIMXCEED_INTRANS) && ip6 != NULL)
-		notify = tcp_drop_syn_sent;
-
-	/*
-	 * Hostdead is ugly because it goes linearly through all PCBs.
-	 * XXX: We never get this from ICMP, otherwise it makes an
-	 * excellent DoS attack on machines with many connections.
-	 */
-	else if (cmd == PRC_HOSTDEAD)
-		ip6 = NULL;
-	else if ((unsigned)cmd >= PRC_NCMDS || inet6ctlerrmap[cmd] == 0)
-		return;
+		break;
+	case PRC_UNREACH_ADMIN_PROHIB:
+	case PRC_UNREACH_PORT:
+	case PRC_UNREACH_PROTOCOL:
+	case PRC_TIMXCEED_INTRANS:
+		if (V_icmp_may_rst)
+			notify = tcp_drop_syn_sent;
+		break;
+	}
 
-	if (ip6 == NULL) {
-		in6_pcbnotify(&V_tcbinfo, sin6, 0, sa6_src, 0, cmd, NULL,
-		    notify);
+	if (inet6ctlerrmap[cmd] == 0)
 		return;
-	}
 
 	/* Check if we can safely get the ports from the tcp hdr */
 	if (m == NULL ||
@@ -3088,11 +3058,6 @@ tcp6_ctlinput_with_port(int cmd, struct sockaddr_in6 *sin6,
 	m_copydata(m, off, sizeof(struct tcp_ports), (caddr_t)&t_ports);
 	inp = in6_pcblookup(&V_tcbinfo, &ip6->ip6_dst, t_ports.th_dport,
 	    &ip6->ip6_src, t_ports.th_sport, INPLOOKUP_WLOCKPCB, NULL);
-	if (inp != NULL && PRC_IS_REDIRECT(cmd)) {
-		/* signal EHOSTDOWN, as it flushes the cached route */
-		inp = (*notify)(inp, EHOSTDOWN);
-		goto out;
-	}
 	off += sizeof(struct tcp_ports);
 	if (m->m_pkthdr.len < (int32_t) (off + sizeof(tcp_seq))) {
 		goto out;
diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c
index 372341a0351c..70474fa18f92 100644
--- a/sys/netinet/udp_usrreq.c
+++ b/sys/netinet/udp_usrreq.c
@@ -746,53 +746,34 @@ udp_common_ctlinput(int cmd, struct sockaddr_in *sin, struct ip *ip,
 	struct udphdr *uh;
 	struct inpcb *inp;
 
-	if (PRC_IS_REDIRECT(cmd)) {
-		/* signal EHOSTDOWN, as it flushes the cached route */
-		in_pcbnotifyall(pcbinfo, sin->sin_addr, EHOSTDOWN, udp_notify);
+	if (inetctlerrmap[cmd] == 0)
 		return;
-	}
 
-	/*
-	 * Hostdead is ugly because it goes linearly through all PCBs.
-	 *
-	 * XXX: We never get this from ICMP, otherwise it makes an excellent
-	 * DoS attack on machines with many connections.
-	 */
-	if (cmd == PRC_HOSTDEAD)
-		ip = NULL;
-	else if ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0)
-		return;
-	if (ip != NULL) {
-		uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2));
+	uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2));
+	inp = in_pcblookup(pcbinfo, sin->sin_addr, uh->uh_dport, ip->ip_src,
+	    uh->uh_sport, INPLOOKUP_WLOCKPCB, NULL);
+	if (inp != NULL) {
+		INP_WLOCK_ASSERT(inp);
+		if (inp->inp_socket != NULL)
+			udp_notify(inp, inetctlerrmap[cmd]);
+		INP_WUNLOCK(inp);
+	} else {
 		inp = in_pcblookup(pcbinfo, sin->sin_addr, uh->uh_dport,
-		    ip->ip_src, uh->uh_sport, INPLOOKUP_WLOCKPCB, NULL);
+		    ip->ip_src, uh->uh_sport,
+		    INPLOOKUP_WILDCARD | INPLOOKUP_RLOCKPCB, NULL);
 		if (inp != NULL) {
-			INP_WLOCK_ASSERT(inp);
-			if (inp->inp_socket != NULL) {
-				udp_notify(inp, inetctlerrmap[cmd]);
-			}
-			INP_WUNLOCK(inp);
-		} else {
-			inp = in_pcblookup(pcbinfo, sin->sin_addr, uh->uh_dport,
-					   ip->ip_src, uh->uh_sport,
-					   INPLOOKUP_WILDCARD | INPLOOKUP_RLOCKPCB, NULL);
-			if (inp != NULL) {
-				struct udpcb *up;
-				void *ctx;
-				udp_tun_icmp_t *func;
-
-				up = intoudpcb(inp);
-				ctx = up->u_tun_ctx;
-				func = up->u_icmp_func;
-				INP_RUNLOCK(inp);
-				if (func != NULL)
-					(*func)(cmd, (struct sockaddr *)sin,
-					    ip, ctx);
-			}
+			struct udpcb *up;
+			void *ctx;
+			udp_tun_icmp_t *func;
+
+			up = intoudpcb(inp);
+			ctx = up->u_tun_ctx;
+			func = up->u_icmp_func;
+			INP_RUNLOCK(inp);
+			if (func != NULL)
+				(*func)(cmd, (struct sockaddr *)sin, ip, ctx);
 		}
-	} else
-		in_pcbnotifyall(pcbinfo, sin->sin_addr, inetctlerrmap[cmd],
-		    udp_notify);
+	}
 }
 
 static void
diff --git a/sys/netinet6/sctp6_usrreq.c b/sys/netinet6/sctp6_usrreq.c
index 5a771b19bdb8..1d3a35b2bdef 100644
--- a/sys/netinet6/sctp6_usrreq.c
+++ b/sys/netinet6/sctp6_usrreq.c
@@ -256,124 +256,112 @@ sctp6_ctlinput(int cmd, struct sockaddr_in6 *pktdst, struct ip6ctlparam *ip6cp)
 	struct sctphdr sh;
 	struct sockaddr_in6 src, dst;
 
-	if ((unsigned)cmd >= PRC_NCMDS) {
+	if (inet6ctlerrmap[cmd] == 0)
 		return;
-	}
-	if (PRC_IS_REDIRECT(cmd)) {
-		ip6cp = NULL;
-	} else if (inet6ctlerrmap[cmd] == 0) {
+
+	if (ip6cp->ip6c_m == NULL) {
 		return;
 	}
 
-	if (ip6cp != NULL) {
-		/*
-		 * XXX: We assume that when IPV6 is non NULL, M and OFF are
-		 * valid.
-		 */
-		if (ip6cp->ip6c_m == NULL) {
-			return;
-		}
-
-		/*
-		 * Check if we can safely examine the ports and the
-		 * verification tag of the SCTP common header.
-		 */
-		if (ip6cp->ip6c_m->m_pkthdr.len <
-		    (int32_t)(ip6cp->ip6c_off + offsetof(struct sctphdr, checksum))) {
-			return;
-		}
+	/*
+	 * Check if we can safely examine the ports and the
+	 * verification tag of the SCTP common header.
+	 */
+	if (ip6cp->ip6c_m->m_pkthdr.len <
+	    (int32_t)(ip6cp->ip6c_off + offsetof(struct sctphdr, checksum))) {
+		return;
+	}
 
-		/* Copy out the port numbers and the verification tag. */
-		memset(&sh, 0, sizeof(sh));
-		m_copydata(ip6cp->ip6c_m,
-		    ip6cp->ip6c_off,
-		    sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint32_t),
-		    (caddr_t)&sh);
-		memset(&src, 0, sizeof(struct sockaddr_in6));
-		src.sin6_family = AF_INET6;
-		src.sin6_len = sizeof(struct sockaddr_in6);
-		src.sin6_port = sh.src_port;
-		src.sin6_addr = ip6cp->ip6c_ip6->ip6_src;
-		if (in6_setscope(&src.sin6_addr, ip6cp->ip6c_m->m_pkthdr.rcvif, NULL) != 0) {
-			return;
-		}
-		memset(&dst, 0, sizeof(struct sockaddr_in6));
-		dst.sin6_family = AF_INET6;
-		dst.sin6_len = sizeof(struct sockaddr_in6);
-		dst.sin6_port = sh.dest_port;
-		dst.sin6_addr = ip6cp->ip6c_ip6->ip6_dst;
-		if (in6_setscope(&dst.sin6_addr, ip6cp->ip6c_m->m_pkthdr.rcvif, NULL) != 0) {
-			return;
-		}
-		inp = NULL;
-		net = NULL;
-		stcb = sctp_findassociation_addr_sa((struct sockaddr *)&dst,
-		    (struct sockaddr *)&src,
-		    &inp, &net, 1, SCTP_DEFAULT_VRFID);
-		if ((stcb != NULL) &&
-		    (net != NULL) &&
-		    (inp != NULL)) {
-			/* Check the verification tag */
-			if (ntohl(sh.v_tag) != 0) {
+	/* Copy out the port numbers and the verification tag. */
+	memset(&sh, 0, sizeof(sh));
+	m_copydata(ip6cp->ip6c_m,
+	    ip6cp->ip6c_off,
+	    sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint32_t),
+	    (caddr_t)&sh);
+	memset(&src, 0, sizeof(struct sockaddr_in6));
+	src.sin6_family = AF_INET6;
+	src.sin6_len = sizeof(struct sockaddr_in6);
+	src.sin6_port = sh.src_port;
+	src.sin6_addr = ip6cp->ip6c_ip6->ip6_src;
+	if (in6_setscope(&src.sin6_addr, ip6cp->ip6c_m->m_pkthdr.rcvif, NULL) != 0) {
+		return;
+	}
+	memset(&dst, 0, sizeof(struct sockaddr_in6));
+	dst.sin6_family = AF_INET6;
+	dst.sin6_len = sizeof(struct sockaddr_in6);
+	dst.sin6_port = sh.dest_port;
+	dst.sin6_addr = ip6cp->ip6c_ip6->ip6_dst;
+	if (in6_setscope(&dst.sin6_addr, ip6cp->ip6c_m->m_pkthdr.rcvif, NULL) != 0) {
+		return;
+	}
+	inp = NULL;
+	net = NULL;
+	stcb = sctp_findassociation_addr_sa((struct sockaddr *)&dst,
+	    (struct sockaddr *)&src,
+	    &inp, &net, 1, SCTP_DEFAULT_VRFID);
+	if ((stcb != NULL) &&
+	    (net != NULL) &&
+	    (inp != NULL)) {
+		/* Check the verification tag */
+		if (ntohl(sh.v_tag) != 0) {
+			/*
+			 * This must be the verification tag used
+			 * for sending out packets. We don't
+			 * consider packets reflecting the
+			 * verification tag.
+			 */
+			if (ntohl(sh.v_tag) != stcb->asoc.peer_vtag) {
+				SCTP_TCB_UNLOCK(stcb);
+				return;
+			}
+		} else {
+			if (ip6cp->ip6c_m->m_pkthdr.len >=
+			    ip6cp->ip6c_off + sizeof(struct sctphdr) +
+			    sizeof(struct sctp_chunkhdr) +
+			    offsetof(struct sctp_init, a_rwnd)) {
 				/*
-				 * This must be the verification tag used
-				 * for sending out packets. We don't
-				 * consider packets reflecting the
-				 * verification tag.
+				 * In this case we can check if we
+				 * got an INIT chunk and if the
+				 * initiate tag matches.
 				 */
-				if (ntohl(sh.v_tag) != stcb->asoc.peer_vtag) {
+				uint32_t initiate_tag;
+				uint8_t chunk_type;
+
+				m_copydata(ip6cp->ip6c_m,
+				    ip6cp->ip6c_off +
+				    sizeof(struct sctphdr),
+				    sizeof(uint8_t),
+				    (caddr_t)&chunk_type);
+				m_copydata(ip6cp->ip6c_m,
+				    ip6cp->ip6c_off +
+				    sizeof(struct sctphdr) +
+				    sizeof(struct sctp_chunkhdr),
+				    sizeof(uint32_t),
+				    (caddr_t)&initiate_tag);
+				if ((chunk_type != SCTP_INITIATION) ||
+				    (ntohl(initiate_tag) != stcb->asoc.my_vtag)) {
 					SCTP_TCB_UNLOCK(stcb);
 					return;
 				}
 			} else {
-				if (ip6cp->ip6c_m->m_pkthdr.len >=
-				    ip6cp->ip6c_off + sizeof(struct sctphdr) +
-				    sizeof(struct sctp_chunkhdr) +
-				    offsetof(struct sctp_init, a_rwnd)) {
-					/*
-					 * In this case we can check if we
-					 * got an INIT chunk and if the
-					 * initiate tag matches.
-					 */
-					uint32_t initiate_tag;
-					uint8_t chunk_type;
-
-					m_copydata(ip6cp->ip6c_m,
-					    ip6cp->ip6c_off +
-					    sizeof(struct sctphdr),
-					    sizeof(uint8_t),
-					    (caddr_t)&chunk_type);
-					m_copydata(ip6cp->ip6c_m,
-					    ip6cp->ip6c_off +
-					    sizeof(struct sctphdr) +
-					    sizeof(struct sctp_chunkhdr),
-					    sizeof(uint32_t),
-					    (caddr_t)&initiate_tag);
-					if ((chunk_type != SCTP_INITIATION) ||
-					    (ntohl(initiate_tag) != stcb->asoc.my_vtag)) {
-						SCTP_TCB_UNLOCK(stcb);
-						return;
-					}
-				} else {
-					SCTP_TCB_UNLOCK(stcb);
-					return;
-				}
-			}
-			sctp6_notify(inp, stcb, net,
-			    ip6cp->ip6c_icmp6->icmp6_type,
-			    ip6cp->ip6c_icmp6->icmp6_code,
-			    ntohl(ip6cp->ip6c_icmp6->icmp6_mtu));
-		} else {
-			if ((stcb == NULL) && (inp != NULL)) {
-				/* reduce inp's ref-count */
-				SCTP_INP_WLOCK(inp);
-				SCTP_INP_DECR_REF(inp);
-				SCTP_INP_WUNLOCK(inp);
-			}
-			if (stcb) {
 				SCTP_TCB_UNLOCK(stcb);
+				return;
 			}
 		}
+		sctp6_notify(inp, stcb, net,
+		    ip6cp->ip6c_icmp6->icmp6_type,
+		    ip6cp->ip6c_icmp6->icmp6_code,
+		    ntohl(ip6cp->ip6c_icmp6->icmp6_mtu));
+	} else {
+		if ((stcb == NULL) && (inp != NULL)) {
+			/* reduce inp's ref-count */
+			SCTP_INP_WLOCK(inp);
+			SCTP_INP_DECR_REF(inp);
+			SCTP_INP_WUNLOCK(inp);
+		}
+		if (stcb) {
+			SCTP_TCB_UNLOCK(stcb);
+		}
 	}
 }
 
diff --git a/sys/netinet6/udp6_usrreq.c b/sys/netinet6/udp6_usrreq.c
index f7f737f7e051..f387724ad997 100644
--- a/sys/netinet6/udp6_usrreq.c
+++ b/sys/netinet6/udp6_usrreq.c
@@ -553,8 +553,8 @@ udp6_common_ctlinput(int cmd, struct sockaddr_in6 *sin6,
 	struct udphdr uh;
 	struct ip6_hdr *ip6;
 	struct mbuf *m;
+	struct inpcb *inp;
 	int off = 0;
-	const struct sockaddr_in6 *sa6_src = NULL;
 	void *cmdarg;
 	struct inpcb *(*notify)(struct inpcb *, int) = udp_notify;
 	struct udp_portonly {
@@ -562,70 +562,38 @@ udp6_common_ctlinput(int cmd, struct sockaddr_in6 *sin6,
 		u_int16_t uh_dport;
 	} *uhp;
 
-	if ((unsigned)cmd >= PRC_NCMDS)
+	if (inet6ctlerrmap[cmd] == 0)
 		return;
-	if (PRC_IS_REDIRECT(cmd))
-		notify = in6_rtchange, ip6cp = NULL;
-	else if (cmd == PRC_HOSTDEAD)
-		ip6cp = NULL;
-	else if (inet6ctlerrmap[cmd] == 0)
+
+	m = ip6cp->ip6c_m;
+	ip6 = ip6cp->ip6c_ip6;
+	off = ip6cp->ip6c_off;
+	cmdarg = ip6cp->ip6c_cmdarg;
+
+	/* Check if we can safely examine src and dst ports. */
+	if (m->m_pkthdr.len < off + sizeof(*uhp))
 		return;
 
-	/* if the parameter is from icmp6, decode it. */
-	if (ip6cp != NULL) {
-		m = ip6cp->ip6c_m;
-		ip6 = ip6cp->ip6c_ip6;
-		off = ip6cp->ip6c_off;
-		cmdarg = ip6cp->ip6c_cmdarg;
-		sa6_src = ip6cp->ip6c_src;
-	} else {
-		m = NULL;
-		ip6 = NULL;
-		cmdarg = NULL;
-		sa6_src = &sa6_any;
-	}
+	bzero(&uh, sizeof(uh));
+	m_copydata(m, off, sizeof(*uhp), (caddr_t)&uh);
 
-	if (ip6) {
-		/*
-		 * XXX: We assume that when IPV6 is non NULL,
-		 * M and OFF are valid.
-		 */
+	/* Check to see if its tunneled */
+	inp = in6_pcblookup_mbuf(pcbinfo, &ip6->ip6_dst, uh.uh_dport,
+	    &ip6->ip6_src, uh.uh_sport, INPLOOKUP_WILDCARD | INPLOOKUP_RLOCKPCB,
+	    m->m_pkthdr.rcvif, m);
+	if (inp != NULL) {
+		struct udpcb *up;
+		udp_tun_icmp_t *func;
 
-		/* Check if we can safely examine src and dst ports. */
-		if (m->m_pkthdr.len < off + sizeof(*uhp))
-			return;
-
-		bzero(&uh, sizeof(uh));
-		m_copydata(m, off, sizeof(*uhp), (caddr_t)&uh);
-
-		if (!PRC_IS_REDIRECT(cmd)) {
-			/* Check to see if its tunneled */
-			struct inpcb *inp;
-			inp = in6_pcblookup_mbuf(pcbinfo, &ip6->ip6_dst,
-			    uh.uh_dport, &ip6->ip6_src, uh.uh_sport,
-			    INPLOOKUP_WILDCARD | INPLOOKUP_RLOCKPCB,
-			    m->m_pkthdr.rcvif, m);
-			if (inp != NULL) {
-				struct udpcb *up;
-				
-				up = intoudpcb(inp);
-				if (up->u_icmp_func) {
-					/* Yes it is. */
-					INP_RUNLOCK(inp);
-					(*up->u_icmp_func)(cmd, (struct sockaddr *)ip6cp->ip6c_src,
-					      ip6cp, up->u_tun_ctx);
-					return;
-				} else {
-					/* Can't find it. */
-					INP_RUNLOCK(inp);
-				}
-			}
-		}
-		in6_pcbnotify(pcbinfo, sin6, uh.uh_dport, ip6cp->ip6c_src,
-		    uh.uh_sport, cmd, cmdarg, notify);
-	} else
-		in6_pcbnotify(pcbinfo, sin6, 0, sa6_src, 0, cmd, cmdarg,
-		    notify);
+		up = intoudpcb(inp);
+		func = up->u_icmp_func;
+		INP_RUNLOCK(inp);
+		if (func != NULL)
+			func(cmd, (struct sockaddr *)ip6cp->ip6c_src, ip6cp,
+			    up->u_tun_ctx);
+	}
+	in6_pcbnotify(pcbinfo, sin6, uh.uh_dport, ip6cp->ip6c_src,
+	    uh.uh_sport, cmd, cmdarg, notify);
 }
 
 static void