Index: net/pf.c
===================================================================
RCS file: /cvs/src/sys/net/pf.c,v
retrieving revision 1.395
diff -u -r1.395 pf.c
--- net/pf.c	25 Oct 2003 20:27:07 -0000	1.395
+++ net/pf.c	28 Oct 2003 20:41:07 -0000
@@ -2003,8 +2003,7 @@
 	case AF_INET:
 		inp = in_pcbhashlookup(tb, saddr->v4, sport, daddr->v4, dport);
 		if (inp == NULL) {
-			inp = in_pcblookup(tb, &saddr->v4, sport, &daddr->v4,
-			    dport, INPLOOKUP_WILDCARD);
+			inp = in_pcblookup_listen(tb, daddr->v4, dport);
 			if (inp == NULL)
 				return (0);
 		}
@@ -2014,8 +2013,7 @@
 		inp = in6_pcbhashlookup(tb, &saddr->v6, sport, &daddr->v6,
 		    dport);
 		if (inp == NULL) {
-			inp = in_pcblookup(tb, &saddr->v6, sport, &daddr->v6,
-			    dport, INPLOOKUP_WILDCARD | INPLOOKUP_IPV6);
+			inp = in6_pcblookup_listen(tb, &daddr->v6, dport);
 			if (inp == NULL)
 				return (0);
 		}
Index: netinet/tcp_input.c
===================================================================
RCS file: /cvs/src/sys/netinet/tcp_input.c,v
retrieving revision 1.133
diff -u -r1.133 tcp_input.c
--- netinet/tcp_input.c	1 Oct 2003 21:41:05 -0000	1.133
+++ netinet/tcp_input.c	28 Oct 2003 20:50:11 -0000
@@ -670,14 +670,13 @@
 		switch (af) {
 #ifdef INET6
 		case AF_INET6:
-			inp = in_pcblookup(&tcbtable, &ip6->ip6_src,
-			    th->th_sport, &ip6->ip6_dst, th->th_dport,
-			    INPLOOKUP_WILDCARD | INPLOOKUP_IPV6);
+			inp = in6_pcblookup_listen(&tcbtable,
+			    &ip6->ip6_dst, th->th_dport);
 			break;
 #endif /* INET6 */
 		case AF_INET:
-			inp = in_pcblookup(&tcbtable, &ip->ip_src, th->th_sport,
-			    &ip->ip_dst, th->th_dport, INPLOOKUP_WILDCARD);
+			inp = in_pcblookup_listen(&tcbtable,
+			    ip->ip_dst, th->th_dport);
 			break;
 		}
 		/*
Index: netinet/tcp_subr.c
===================================================================
RCS file: /cvs/src/sys/netinet/tcp_subr.c,v
retrieving revision 1.69
diff -u -r1.69 tcp_subr.c
--- netinet/tcp_subr.c	1 Oct 2003 21:41:05 -0000	1.69
+++ netinet/tcp_subr.c	28 Oct 2003 20:41:07 -0000
@@ -839,10 +839,6 @@
 			    th.th_dport, (struct in6_addr *)&sa6_src->sin6_addr,
 			    th.th_sport))
 				valid++;
-			else if (in_pcblookup(&tcbtable, &sa6->sin6_addr,
-			    th.th_dport, (struct in6_addr *)&sa6_src->sin6_addr,
-			    th.th_sport, INPLOOKUP_IPV6))
-				valid++;
 
 			/*
 			 * Depending on the value of "valid" and routing table
@@ -893,10 +889,12 @@
 		 * Verify that the packet in the icmp payload refers
 		 * to an existing TCP connection.
 		 */
-		if (in_pcblookup(&tcbtable,
-				 &ip->ip_dst, th->th_dport,
-				 &ip->ip_src, th->th_sport,
-				 INPLOOKUP_WILDCARD)) {
+		/*
+		 * XXX is it possible to get a valid PRC_MSGSIZE error for
+		 * a non-established connection?
+		 */
+		if (in_pcbhashlookup(&tcbtable,
+		    ip->ip_dst, th->th_dport, ip->ip_src, th->th_sport)) {
 			struct icmp *icp;
 			icp = (struct icmp *)((caddr_t)ip -
 					      offsetof(struct icmp, icmp_ip));
Index: netinet/tcp_usrreq.c
===================================================================
RCS file: /cvs/src/sys/netinet/tcp_usrreq.c,v
retrieving revision 1.71
diff -u -r1.71 tcp_usrreq.c
--- netinet/tcp_usrreq.c	9 Jun 2003 07:40:25 -0000	1.71
+++ netinet/tcp_usrreq.c	28 Oct 2003 20:41:07 -0000
@@ -834,15 +834,13 @@
 		switch (tir.faddr.ss_family) {
 #ifdef INET6
 		case AF_INET6:
-			inp = in_pcblookup(&tcbtable, &f6,
-			    fin6->sin6_port, &l6, lin6->sin6_port,
-			    INPLOOKUP_WILDCARD | INPLOOKUP_IPV6);
+			inp = in6_pcblookup_listen(&tcbtable,
+			    &l6, lin6->sin6_port);
 			break;
 #endif
 		case AF_INET:
-			inp = in_pcblookup(&tcbtable, &fin->sin_addr,
-			    fin->sin_port, &lin->sin_addr, lin->sin_port,
-			    INPLOOKUP_WILDCARD);
+			inp = in_pcblookup_listen(&tcbtable, 
+			    lin->sin_addr, lin->sin_port);
 			break;
 		}
 	}
Index: netinet/udp_usrreq.c
===================================================================
RCS file: /cvs/src/sys/netinet/udp_usrreq.c,v
retrieving revision 1.91
diff -u -r1.91 udp_usrreq.c
--- netinet/udp_usrreq.c	9 Jul 2003 22:03:16 -0000	1.91
+++ netinet/udp_usrreq.c	28 Oct 2003 20:54:33 -0000
@@ -483,14 +483,12 @@
 		++udpstat.udps_pcbhashmiss;
 #ifdef INET6
 		if (ip6) {
-			inp = in_pcblookup(&udbtable,
-			    (struct in_addr *)&(ip6->ip6_src),
-			    uh->uh_sport, (struct in_addr *)&(ip6->ip6_dst),
-			    uh->uh_dport, INPLOOKUP_WILDCARD | INPLOOKUP_IPV6);
+			inp = in6_pcblookup_listen(&udbtable,
+			    &ip6->ip6_dst, uh->uh_dport);
 		} else
 #endif /* INET6 */
-		inp = in_pcblookup(&udbtable, &ip->ip_src, uh->uh_sport,
-		    &ip->ip_dst, uh->uh_dport, INPLOOKUP_WILDCARD);
+		inp = in_pcblookup_listen(&udbtable,
+		    ip->ip_dst, uh->uh_dport);
 		if (inp == 0) {
 			udpstat.udps_noport++;
 			if (m->m_flags & (M_BCAST | M_MCAST)) {
@@ -665,7 +663,6 @@
 	int off;
 	void *cmdarg;
 	struct ip6ctlparam *ip6cp = NULL;
-	struct in6_addr finaldst;
 	struct udp_portonly {
 		u_int16_t uh_sport;
 		u_int16_t uh_dport;
@@ -770,13 +767,9 @@
 			 * corresponding to the address in the ICMPv6 message
 			 * payload.
 			 */
-			if (in6_pcbhashlookup(&udbtable, &finaldst,
+			if (in6_pcbhashlookup(&udbtable, &sa6.sin6_addr,
 			    uh.uh_dport, &sa6_src.sin6_addr, uh.uh_sport))
 				valid = 1;
-			else if (in_pcblookup(&udbtable, &sa6.sin6_addr,
-			    uh.uh_dport, &sa6_src.sin6_addr, uh.uh_sport,
-			    INPLOOKUP_IPV6))
-				valid = 1;
 #if 0
 			/*
 			 * As the use of sendto(2) is fairly popular,
@@ -785,9 +778,8 @@
 			 * We should at least check if the local address (= s)
 			 * is really ours.
 			 */
-			else if (in_pcblookup(&udbtable, &sa6.sin6_addr,
-			    uh.uh_dport, &sa6_src.sin6_addr, uh.uh_sport,
-			    INPLOOKUP_WILDCARD | INPLOOKUP_IPV6))
+			else if (in6_pcblookup_listen(&udbtable,
+			    &sa6_src.sin6_addr, uh.uh_sport))
 				valid = 1;
 #endif
 
Index: netinet/in_pcb.c
===================================================================
RCS file: /cvs/src/sys/netinet/in_pcb.c,v
retrieving revision 1.68
diff -u -r1.68 in_pcb.c
--- netinet/in_pcb.c	25 Oct 2003 12:15:24 -0000	1.68
+++ netinet/in_pcb.c	28 Oct 2003 20:56:20 -0000
@@ -955,6 +955,15 @@
 int	in_pcbnotifymiss = 0;
 #endif
 
+/*
+ * The in(6)_pcbhashlookup functions are used to locate connected sockets
+ * quickly:
+ * 		faddr.fport <-> laddr.lport
+ * No wildcard matching is done so that listening sockets are not found.
+ * If the functions return NULL in(6)_pcblookup_listen can be used to
+ * find a listening/bound socket that may accept the connection.
+ * After those two lookups no other are necessary.
+ */
 struct inpcb *
 in_pcbhashlookup(table, faddr, fport_arg, laddr, lport_arg)
 	struct inpcbtable *table;
@@ -1029,7 +1038,7 @@
 	}
 #ifdef DIAGNOSTIC
 	if (inp == NULL && in_pcbnotifymiss) {
-		printf("in6_pcblookup_connect: faddr=");
+		printf("in6_pcbhashlookup: faddr=");
 		printf(" fport=%d laddr=", ntohs(fport));
 		printf(" lport=%d\n", ntohs(lport));
 	}
@@ -1038,4 +1047,112 @@
 }
 #endif /* INET6 */
 
+/*
+ * The in(6)_pcblookup_listen functions are used to locate listening
+ * sockets quickly.  This are sockets with unspecified foreign address
+ * and port:
+ *		*.*     <-> laddr.lport
+ *		*.*     <->     *.lport
+ */
+struct inpcb *
+in_pcblookup_listen(table, laddr, lport_arg)
+	struct inpcbtable *table;
+	struct in_addr laddr;
+	u_int lport_arg;
+{
+	struct inpcbhead *head;
+	register struct inpcb *inp;
+	u_int16_t lport = lport_arg;
 
+	head = INPCBHASH(table, &zeroin_addr, 0, &laddr, lport);
+	LIST_FOREACH(inp, head, inp_hash) {
+#ifdef INET6
+		if (inp->inp_flags & INP_IPV6)
+			continue;	/*XXX*/
+#endif
+		if (inp->inp_lport == lport && inp->inp_fport == 0 &&
+		    inp->inp_laddr.s_addr == laddr.s_addr &&
+		    inp->inp_faddr.s_addr == INADDR_ANY)
+			break;
+	}
+	if (inp == NULL && laddr.s_addr != INADDR_ANY) {
+		head = INPCBHASH(table, &zeroin_addr, 0, &zeroin_addr, lport);
+		LIST_FOREACH(inp, head, inp_hash) {
+#ifdef INET6
+			if (inp->inp_flags & INP_IPV6)
+				continue;	/*XXX*/
+#endif
+			if (inp->inp_lport == lport && inp->inp_fport == 0 &&
+			    inp->inp_laddr.s_addr == INADDR_ANY &&
+			    inp->inp_faddr.s_addr == INADDR_ANY)
+				break;
+		}
+	}
+#ifdef DIAGNOSTIC
+	if (inp == NULL && in_pcbnotifymiss) {
+		printf("in_pcblookup_listen: laddr=%08x lport=%d\n",
+		    ntohl(laddr.s_addr), ntohs(lport));
+	}
+#endif
+	/*
+	 * Move this PCB to the head of hash chain so that
+	 * repeated accesses are quicker.  This is analogous to
+	 * the historic single-entry PCB cache.
+	 */
+	if (inp != NULL && inp != head->lh_first) {
+		LIST_REMOVE(inp, inp_hash);
+		LIST_INSERT_HEAD(head, inp, inp_hash);
+	}
+	return (inp);
+}
+
+#ifdef INET6
+struct inpcb *
+in6_pcblookup_listen(table, laddr, lport_arg)
+	struct inpcbtable *table;
+	struct in6_addr *laddr;
+	u_int lport_arg;
+{
+	struct inpcbhead *head;
+	register struct inpcb *inp;
+	u_int16_t lport = lport_arg;
+
+	head = IN6PCBHASH(table, &zeroin6_addr, 0, laddr, lport);
+	LIST_FOREACH(inp, head, inp_hash) {
+		if (!(inp->inp_flags & INP_IPV6))
+			continue;
+		if (inp->inp_lport == lport && inp->inp_fport == 0 &&
+		    IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6, laddr) &&
+		    IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6))
+			break;
+	}
+	if (inp == NULL && !IN6_IS_ADDR_UNSPECIFIED(laddr)) {
+		head = IN6PCBHASH(table, &zeroin6_addr, 0,
+		    &zeroin6_addr, lport);
+		LIST_FOREACH(inp, head, inp_hash) {
+			if (!(inp->inp_flags & INP_IPV6))
+				continue;
+			if (inp->inp_lport == lport && inp->inp_fport == 0 &&
+			    IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6) &&
+			    IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6))
+				break;
+		}
+	}
+#ifdef DIAGNOSTIC
+	if (inp == NULL && in_pcbnotifymiss) {
+		printf("in6_pcblookup_listen: laddr= lport=%d\n",
+		    ntohs(lport));
+	}
+#endif
+	/*
+	 * Move this PCB to the head of hash chain so that
+	 * repeated accesses are quicker.  This is analogous to
+	 * the historic single-entry PCB cache.
+	 */
+	if (inp != NULL && inp != head->lh_first) {
+		LIST_REMOVE(inp, inp_hash);
+		LIST_INSERT_HEAD(head, inp, inp_hash);
+	}
+	return (inp);
+}
+#endif /* INET6 */
Index: netinet/in_pcb.h
===================================================================
RCS file: /cvs/src/sys/netinet/in_pcb.h,v
retrieving revision 1.46
diff -u -r1.46 in_pcb.h
--- netinet/in_pcb.h	25 Oct 2003 12:15:24 -0000	1.46
+++ netinet/in_pcb.h	28 Oct 2003 20:57:14 -0000
@@ -238,10 +238,15 @@
 struct inpcb *
 	 in_pcbhashlookup(struct inpcbtable *, struct in_addr,
 			       u_int, struct in_addr, u_int);
+struct inpcb *
+	 in_pcblookup_listen(struct inpcbtable *, struct in_addr, u_int);
 #ifdef INET6
 struct inpcb *
 	 in6_pcbhashlookup(struct inpcbtable *, struct in6_addr *,
 			       u_int, struct in6_addr *, u_int);
+struct inpcb *
+	 in6_pcblookup_listen(struct inpcbtable *,
+			       struct in6_addr *, u_int);
 int	 in6_pcbbind(struct inpcb *, struct mbuf *);
 int	 in6_pcbconnect(struct inpcb *, struct mbuf *);
 int	 in6_setsockaddr(struct inpcb *, struct mbuf *);
