Module Name:    src
Committed By:   rmind
Date:           Mon Sep 23 00:57:53 UTC 2013

Modified Files:
        src/sys/dist/pf/net [rmind-smpnet]: pf.c
        src/sys/kern [rmind-smpnet]: uipc_socket2.c
        src/sys/netinet [rmind-smpnet]: in_pcb.c in_pcb.h portalgo.c raw_ip.c
            tcp_input.c tcp_subr.c tcp_usrreq.c tcp_vtw.c udp_usrreq.c
            udp_var.h
        src/sys/netinet6 [rmind-smpnet]: in6_pcb.c

Log Message:
- Add some initial locking to the IPv4 PCB.
- Rename inpcb_lookup_*() routines to be more accurate and add comments.
- Add some comments about connection life-cycle WRT socket layer.


To generate a diff of this commit:
cvs rdiff -u -r1.69.4.1 -r1.69.4.2 src/sys/dist/pf/net/pf.c
cvs rdiff -u -r1.112.2.1 -r1.112.2.2 src/sys/kern/uipc_socket2.c
cvs rdiff -u -r1.145.2.2 -r1.145.2.3 src/sys/netinet/in_pcb.c
cvs rdiff -u -r1.51.2.1 -r1.51.2.2 src/sys/netinet/in_pcb.h
cvs rdiff -u -r1.5.2.1 -r1.5.2.2 src/sys/netinet/portalgo.c
cvs rdiff -u -r1.116.2.2 -r1.116.2.3 src/sys/netinet/raw_ip.c
cvs rdiff -u -r1.327.2.1 -r1.327.2.2 src/sys/netinet/tcp_input.c
cvs rdiff -u -r1.250.2.1 -r1.250.2.2 src/sys/netinet/tcp_subr.c
cvs rdiff -u -r1.166.4.2 -r1.166.4.3 src/sys/netinet/tcp_usrreq.c
cvs rdiff -u -r1.9.4.1 -r1.9.4.2 src/sys/netinet/tcp_vtw.c
cvs rdiff -u -r1.190.2.2 -r1.190.2.3 src/sys/netinet/udp_usrreq.c
cvs rdiff -u -r1.38.4.2 -r1.38.4.3 src/sys/netinet/udp_var.h
cvs rdiff -u -r1.123.2.1 -r1.123.2.2 src/sys/netinet6/in6_pcb.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dist/pf/net/pf.c
diff -u src/sys/dist/pf/net/pf.c:1.69.4.1 src/sys/dist/pf/net/pf.c:1.69.4.2
--- src/sys/dist/pf/net/pf.c:1.69.4.1	Wed Jul 17 03:16:31 2013
+++ src/sys/dist/pf/net/pf.c	Mon Sep 23 00:57:53 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: pf.c,v 1.69.4.1 2013/07/17 03:16:31 rmind Exp $	*/
+/*	$NetBSD: pf.c,v 1.69.4.2 2013/09/23 00:57:53 rmind Exp $	*/
 /*	$OpenBSD: pf.c,v 1.552.2.1 2007/11/27 16:37:57 henning Exp $ */
 
 /*
@@ -37,7 +37,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pf.c,v 1.69.4.1 2013/07/17 03:16:31 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pf.c,v 1.69.4.2 2013/09/23 00:57:53 rmind Exp $");
 
 #include "pflog.h"
 
@@ -2799,11 +2799,11 @@ pf_socket_lookup(int direction, struct p
 
 #ifdef __NetBSD__
 #define in_pcbhashlookup(tbl, saddr, sport, daddr, dport) \
-    inpcb_lookup_connect(tbl, saddr, sport, daddr, dport, NULL)
+    inpcb_lookup(tbl, saddr, sport, daddr, dport, NULL)
 #define in6_pcbhashlookup(tbl, saddr, sport, daddr, dport) \
     in6_pcblookup_connect(tbl, saddr, sport, daddr, dport, 0, NULL)
 #define inpcb_lookup_listen(tbl, addr, port, zero) \
-    inpcb_lookup_bind(tbl, addr, port)
+    inpcb_lookup_bound(tbl, addr, port)
 #define in6_pcblookup_listen(tbl, addr, port, zero) \
     in6_pcblookup_bind(tbl, addr, port, zero)
 #endif

Index: src/sys/kern/uipc_socket2.c
diff -u src/sys/kern/uipc_socket2.c:1.112.2.1 src/sys/kern/uipc_socket2.c:1.112.2.2
--- src/sys/kern/uipc_socket2.c:1.112.2.1	Wed Aug 28 15:21:48 2013
+++ src/sys/kern/uipc_socket2.c	Mon Sep 23 00:57:53 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: uipc_socket2.c,v 1.112.2.1 2013/08/28 15:21:48 rmind Exp $	*/
+/*	$NetBSD: uipc_socket2.c,v 1.112.2.2 2013/09/23 00:57:53 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2008 The NetBSD Foundation, Inc.
@@ -58,7 +58,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uipc_socket2.c,v 1.112.2.1 2013/08/28 15:21:48 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uipc_socket2.c,v 1.112.2.2 2013/09/23 00:57:53 rmind Exp $");
 
 #include "opt_mbuftrace.h"
 #include "opt_sb_max.h"
@@ -82,6 +82,37 @@ __KERNEL_RCSID(0, "$NetBSD: uipc_socket2
 /*
  * Primitive routines for operating on sockets and socket buffers.
  *
+ * Connection life-cycle:
+ *
+ *	Normal sequence from the active (originating) side:
+ *
+ *	- soisconnecting() is called during processing of connect() call,
+ *	- resulting in an eventual call to soisconnected() if/when the
+ *	  connection is established.
+ *
+ *	When the connection is torn down during processing of disconnect():
+ *
+ *	- soisdisconnecting() is called and,
+ *	- soisdisconnected() is called when the connection to the peer
+ *	  is totally severed.
+ *
+ *	The semantics of these routines are such that connectionless protocols
+ *	can call soisconnected() and soisdisconnected() only, bypassing the
+ *	in-progress calls when setting up a ``connection'' takes no time.
+ *
+ *	From the passive side, a socket is created with two queues of sockets:
+ *
+ *	- so_q0 (0) for partial connections (i.e. connections in progress)
+ *	- so_q (1) for connections already made and awaiting user acceptance.
+ *
+ *	As a protocol is preparing incoming connections, it creates a socket
+ *	structure queued on so_q0 by calling sonewconn().  When the connection
+ *	is established, soisconnected() is called, and transfers the
+ *	socket structure to so_q, making it available to accept().
+ *
+ *	If a socket is closed with sockets on either so_q0 or so_q, these
+ *	sockets are dropped.
+ *
  * Locking rules and assumptions:
  *
  * o socket::so_lock can change on the fly.  The low level routines used
@@ -120,40 +151,9 @@ __KERNEL_RCSID(0, "$NetBSD: uipc_socket2
  *   domains.
  */
 
-static pool_cache_t socket_cache;
-
-u_long	sb_max = SB_MAX;	/* maximum socket buffer size */
-static u_long sb_max_adj;	/* adjusted sb_max */
-
-/*
- * Procedures to manipulate state flags of socket
- * and do appropriate wakeups.  Normal sequence from the
- * active (originating) side is that soisconnecting() is
- * called during processing of connect() call,
- * resulting in an eventual call to soisconnected() if/when the
- * connection is established.  When the connection is torn down
- * soisdisconnecting() is called during processing of disconnect() call,
- * and soisdisconnected() is called when the connection to the peer
- * is totally severed.  The semantics of these routines are such that
- * connectionless protocols can call soisconnected() and soisdisconnected()
- * only, bypassing the in-progress calls when setting up a ``connection''
- * takes no time.
- *
- * From the passive side, a socket is created with
- * two queues of sockets: so_q0 for connections in progress
- * and so_q for connections already made and awaiting user acceptance.
- * As a protocol is preparing incoming connections, it creates a socket
- * structure queued on so_q0 by calling sonewconn().  When the connection
- * is established, soisconnected() is called, and transfers the
- * socket structure to so_q, making it available to accept().
- *
- * If a socket is closed with sockets on either
- * so_q0 or so_q, these sockets are dropped.
- *
- * If higher level protocols are implemented in
- * the kernel, the wakeups done here will sometimes
- * cause software-interrupt process scheduling.
- */
+static pool_cache_t	socket_cache;
+u_long			sb_max = SB_MAX;/* maximum socket buffer size */
+static u_long		sb_max_adj;	/* adjusted sb_max */
 
 void
 soisconnecting(struct socket *so)
@@ -179,6 +179,10 @@ soisconnected(struct socket *so)
 	so->so_state |= SS_ISCONNECTED;
 	if (head && so->so_onq == &head->so_q0) {
 		if ((so->so_options & SO_ACCEPTFILTER) == 0) {
+			/*
+			 * Re-enqueue and wake up any waiters, e.g.
+			 * processes blocking on accept().
+			 */
 			soqremque(so, 0);
 			soqinsque(head, so, 1);
 			sorwakeup(head);
@@ -242,6 +246,7 @@ soinit2(void)
  * properly linked into the data structure of the original socket.
  *
  * => Connection status may be 0, SS_ISCONFIRMING, or SS_ISCONNECTED.
+ * => May be called from soft-interrupt context.
  * => Listening socket should be locked.
  * => Returns the new socket locked.
  */
@@ -269,7 +274,7 @@ sonewconn(struct socket *head, int conns
 		return NULL;
 	}
 	so->so_type = head->so_type;
-	so->so_options = head->so_options &~ SO_ACCEPTCONN;
+	so->so_options = head->so_options & ~SO_ACCEPTCONN;
 	so->so_linger = head->so_linger;
 	so->so_state = head->so_state | SS_NOFDREF;
 	so->so_proto = head->so_proto;
@@ -430,29 +435,29 @@ soqremque(struct socket *so, int q)
 }
 
 /*
- * Socantsendmore indicates that no more data will be sent on the
+ * socantsendmore(): indicates that no more data will be sent on the
  * socket; it would normally be applied to a socket when the user
  * informs the system that no more data is to be sent, by the protocol
- * code (in case PRU_SHUTDOWN).  Socantrcvmore indicates that no more data
- * will be received, and will normally be applied to the socket by a
- * protocol when it detects that the peer will send no more data.
- * Data queued for reading in the socket may yet be read.
+ * code (in case PRU_SHUTDOWN).
  */
-
 void
 socantsendmore(struct socket *so)
 {
-
 	KASSERT(solocked(so));
 
 	so->so_state |= SS_CANTSENDMORE;
 	sowwakeup(so);
 }
 
+/*
+ * socantrcvmore(): indicates that no more data will be received and
+ * will normally be applied to the socket by a protocol when it detects
+ * that the peer will send no more data.  Data queued for reading in
+ * the socket may yet be read.
+ */
 void
 socantrcvmore(struct socket *so)
 {
-
 	KASSERT(solocked(so));
 
 	so->so_state |= SS_CANTRCVMORE;

Index: src/sys/netinet/in_pcb.c
diff -u src/sys/netinet/in_pcb.c:1.145.2.2 src/sys/netinet/in_pcb.c:1.145.2.3
--- src/sys/netinet/in_pcb.c:1.145.2.2	Wed Aug 28 15:21:48 2013
+++ src/sys/netinet/in_pcb.c	Mon Sep 23 00:57:53 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: in_pcb.c,v 1.145.2.2 2013/08/28 15:21:48 rmind Exp $	*/
+/*	$NetBSD: in_pcb.c,v 1.145.2.3 2013/09/23 00:57:53 rmind Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -96,32 +96,33 @@
  * Internet Protocol Control Block (PCB) module.
  *
  *	Each PCB (inpcb_t) is associated with a socket during PCB creation.
- *	Its members are protected by the socket lock.  Creation is done on
- *	PRU_ATTACH protocol command and destruction on PRU_DETACH.
+ *	Its members are protected by the socket lock.  Creation is done at
+ *	pr_attach protocol method and destruction at pr_detach.
  *
  * Synchronisation
  *
  *	PCBs are inserted into a PCB table (inpcbtable_t).  The hash and
  *	the lists of the table are protected by the inpcbtable_t::inpt_lock.
  *	There are two main PCB lookup points, which can occur either from
- *	the top or the bottom of the stack:
+ *	the top or the bottom of the network stack:
  *
  *	- Process performs a protocol operation (e.g. PRU_SEND) and gets
  *	  PCB from the socket, i.e. sotoinpcb(9).
  *	- When a packet arrives (e.g. UDP datagram), the protocol layer
- *	  performs 4-tuple a PCB lookup to find an associated socket.
+ *	  performs a PCB lookup to find an associated socket.
  *
  *	In addition to this, there are cases when multiple PCBs are matched
  *	and processed (e.g. raw IP or UDP multicast).
  *
- * Lock order, XXXrmind: NOT YET
+ * Lock order
  *
- *	inpcbtable_t::inpt_lock ->
- *		struct socket::so_lock
+ *	softnet_lock ->
+ *		struct socket::so_lock ->
+ *			inpcbtable_t::inpt_lock ->
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: in_pcb.c,v 1.145.2.2 2013/08/28 15:21:48 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: in_pcb.c,v 1.145.2.3 2013/09/23 00:57:53 rmind Exp $");
 
 #include "opt_inet.h"
 #include "opt_ipsec.h"
@@ -175,6 +176,8 @@ int	anonportmax = IPPORT_ANONMAX;
 int	lowportmin  = IPPORT_RESERVEDMIN;
 int	lowportmax  = IPPORT_RESERVEDMAX;
 
+static void		inpcb_set_state1(inpcb_t *, int);
+
 #define	INPCBHASH_PORT(table, lport) \
 	&(table)->inpt_porthashtbl[ntohs(lport) & (table)->inpt_porthash]
 #define	INPCBHASH_BIND(table, laddr, lport) \
@@ -231,7 +234,7 @@ inpcb_create(struct socket *so, inpcbtab
 
 	inp = pool_cache_get(inpcb_cache, PR_NOWAIT);
 	if (inp == NULL) {
-		return ENOBUFS;
+		return ENOMEM;
 	}
 	memset(inp, 0, sizeof(*inp));
 
@@ -249,11 +252,13 @@ inpcb_create(struct socket *so, inpcbtab
 	}
 #endif
 	so->so_pcb = inp;
-	inpcb_set_state(inp, INP_ATTACHED);
-
 	head = INPCBHASH_PORT(inpt, inp->inp_lport);
+
+	mutex_enter(&inpt->inpt_lock);
+	inpcb_set_state1(inp, INP_ATTACHED);
 	CIRCLEQ_INSERT_HEAD(&inpt->inpt_queue, &inp->inp_head, inph_queue);
 	LIST_INSERT_HEAD(head, &inp->inp_head, inph_lhash);
+	mutex_exit(&inpt->inpt_lock);
 
 	return 0;
 }
@@ -393,7 +398,8 @@ inpcb_bind_port(inpcb_t *inp, struct soc
 
 		/* XXX-kauth */
 		if (so->so_uidinfo->ui_uid && !IN_MULTICAST(sin->sin_addr.s_addr)) {
-			t = inpcb_lookup_port(inpt, sin->sin_addr, sin->sin_port, 1, &vestige);
+			t = inpcb_lookup_local(inpt, sin->sin_addr,
+			    sin->sin_port, 1, &vestige);
 			/*
 			 * XXX:	investigate ramifications of loosening this
 			 *	restriction so that as long as both ports have
@@ -415,7 +421,8 @@ inpcb_bind_port(inpcb_t *inp, struct soc
 				}
 			}
 		}
-		t = inpcb_lookup_port(inpt, sin->sin_addr, sin->sin_port, wild, &vestige);
+		t = inpcb_lookup_local(inpt, sin->sin_addr, sin->sin_port,
+		    wild, &vestige);
 		if (t && (reuseport & t->inp_socket->so_options) == 0)
 			return (EADDRINUSE);
 		if (!t
@@ -426,10 +433,12 @@ inpcb_bind_port(inpcb_t *inp, struct soc
 		inp->inp_lport = sin->sin_port;
 	}
 
-	inpcb_set_state(inp, INP_BOUND);
+	mutex_enter(&inpt->inpt_lock);
+	inpcb_set_state1(inp, INP_BOUND);
 	LIST_REMOVE(&inp->inp_head, inph_lhash);
 	LIST_INSERT_HEAD(INPCBHASH_PORT(inpt, inp->inp_lport), &inp->inp_head,
 	    inph_lhash);
+	mutex_exit(&inpt->inpt_lock);
 
 	return 0;
 }
@@ -441,6 +450,8 @@ inpcb_bind_port(inpcb_t *inp, struct soc
  * local interface.  If a port is specified and it is privileged, then
  * check the permission.  Check whether the address or port is in use,
  * and if so, whether we can re-use them.
+ *
+ * => Associated socket must be locked.
  */
 int
 inpcb_bind(inpcb_t *inp, struct mbuf *nam, struct lwp *l)
@@ -449,8 +460,10 @@ inpcb_bind(inpcb_t *inp, struct mbuf *na
 	struct sockaddr_in lsin;
 	int error;
 
-	if (inp->inp_af != AF_INET)
+	if (inp->inp_af != AF_INET) {
 		return EINVAL;
+	}
+	KASSERT(solocked(inp->inp_socket));
 
 	if (TAILQ_EMPTY(&in_ifaddrhead))
 		return EADDRNOTAVAIL;
@@ -462,8 +475,10 @@ inpcb_bind(inpcb_t *inp, struct mbuf *na
 		if (nam->m_len != sizeof (*sin))
 			return EINVAL;
 	} else {
-		lsin = *((const struct sockaddr_in *)
-		    inp->inp_socket->so_proto->pr_domain->dom_sa_any);
+		struct socket *so = inp->inp_socket;
+
+		memcpy(&lsin, &so->so_proto->pr_domain->dom_sa_any,
+		    sizeof(struct sockaddr_in));
 		sin = &lsin;
 	}
 
@@ -488,10 +503,13 @@ inpcb_bind(inpcb_t *inp, struct mbuf *na
  *
  * Both address and port must be specified in the name argument.
  * If there is no local address for this socket yet, then pick one.
+ *
+ * => Associated socket must be locked.
  */
 int
 inpcb_connect(inpcb_t *inp, struct mbuf *nam, struct lwp *l)
 {
+	inpcbtable_t *inpt = inp->inp_table;
 	struct in_ifaddr *ia = NULL;
 	struct sockaddr_in *ifaddr = NULL;
 	struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
@@ -499,6 +517,11 @@ inpcb_connect(inpcb_t *inp, struct mbuf 
 	vestigial_inpcb_t vestige;
 	int error = 0;
 
+	if (inp->inp_af != AF_INET) {
+		return EINVAL;
+	}
+	KASSERT(solocked(so));
+
 	if (nam->m_len != sizeof(*sin))
 		return EINVAL;
 
@@ -508,14 +531,8 @@ inpcb_connect(inpcb_t *inp, struct mbuf 
 	if (sin->sin_port == 0)
 		return EADDRNOTAVAIL;
 
-	if (inp->inp_af != AF_INET) {
-		error = EINVAL;
-		goto out;
-	}
-
 	if (IN_MULTICAST(sin->sin_addr.s_addr) && so->so_type == SOCK_STREAM) {
-		error = EADDRNOTAVAIL;
-		goto out;
+		return EADDRNOTAVAIL;
 	}
 
 	if (!TAILQ_EMPTY(&in_ifaddrhead)) {
@@ -564,7 +581,7 @@ inpcb_connect(inpcb_t *inp, struct mbuf 
 		if (ia == NULL)
 			return (EADDRNOTAVAIL);
 	}
-	if (inpcb_lookup_connect(inp->inp_table, sin->sin_addr, sin->sin_port,
+	if (inpcb_lookup(inp->inp_table, sin->sin_addr, sin->sin_port,
 	    !in_nullhost(inp->inp_laddr) ? inp->inp_laddr : ifaddr->sin_addr,
 	    inp->inp_lport, &vestige) != 0 || vestige.valid)
 		return (EADDRINUSE);
@@ -586,8 +603,10 @@ inpcb_connect(inpcb_t *inp, struct mbuf 
 
 	/* Late bind, if needed. */
 	if (inp->inp_bindportonsend) {
-		struct sockaddr_in lsin = *((const struct sockaddr_in *)
-		    so->so_proto->pr_domain->dom_sa_any);
+		struct sockaddr_in lsin;
+
+		memcpy(&lsin, &so->so_proto->pr_domain->dom_sa_any,
+		    sizeof(struct sockaddr_in));
 		lsin.sin_addr = inp->inp_laddr;
 		lsin.sin_port = 0;
 
@@ -595,29 +614,39 @@ inpcb_connect(inpcb_t *inp, struct mbuf 
 			return error;
 	}
 
-	inpcb_set_state(inp, INP_CONNECTED);
+	mutex_enter(&inpt->inpt_lock);
+	inpcb_set_state1(inp, INP_CONNECTED);
+	mutex_exit(&inpt->inpt_lock);
+
 #if defined(IPSEC)
 	if (so->so_type == SOCK_STREAM)
 		ipsec_pcbconn(inp->inp_sp);
 #endif
-out:
 	return error;
 }
 
 /*
  * inpcb_disconnect: remove any foreign IP/port association.
- *
  * Note: destroys the PCB if socket was closed.
+ *
+ * => Associated socket must be locked.
  */
 void
 inpcb_disconnect(inpcb_t *inp)
 {
-	if (inp->inp_af != AF_INET)
+	inpcbtable_t *inpt = inp->inp_table;
+
+	if (inp->inp_af != AF_INET) {
 		return;
+	}
+	KASSERT(solocked(inp->inp_socket));
 
 	inp->inp_faddr = zeroin_addr;
 	inp->inp_fport = 0;
-	inpcb_set_state(inp, INP_BOUND);
+
+	mutex_enter(&inpt->inpt_lock);
+	inpcb_set_state1(inp, INP_BOUND);
+	mutex_exit(&inpt->inpt_lock);
 
 #if defined(IPSEC)
 	ipsec_pcbdisconn(inp->inp_sp);
@@ -628,6 +657,8 @@ inpcb_disconnect(inpcb_t *inp)
 
 /*
  * inpcb_destroy: destroy PCB as well as the associated socket.
+ *
+ * => Associated socket must be locked.
  */
 void
 inpcb_destroy(inpcb_t *inp)
@@ -635,12 +666,17 @@ inpcb_destroy(inpcb_t *inp)
 	struct socket *so = inp->inp_socket;
 	inpcbtable_t *inpt = inp->inp_table;
 
-	if (inp->inp_af != AF_INET)
+	if (inp->inp_af != AF_INET) {
 		return;
+	}
+	KASSERT(solocked(so));
 
-	inpcb_set_state(inp, INP_ATTACHED);
+	/* Acquire the lock and remove PCB entry from the lists. */
+	mutex_enter(&inpt->inpt_lock);
+	inpcb_set_state1(inp, INP_ATTACHED);
 	LIST_REMOVE(&inp->inp_head, inph_lhash);
 	CIRCLEQ_REMOVE(&inpt->inpt_queue, &inp->inp_head, inph_queue);
+	mutex_exit(&inpt->inpt_lock);
 
 #if defined(IPSEC)
 	ipsec4_delete_pcbpolicy(inp);
@@ -670,8 +706,10 @@ inpcb_fetch_sockaddr(inpcb_t *inp, struc
 {
 	struct sockaddr_in *sin;
 
-	if (inp->inp_af != AF_INET)
+	if (inp->inp_af != AF_INET) {
 		return;
+	}
+	KASSERT(solocked(inp->inp_socket));
 
 	sin = mtod(nam, struct sockaddr_in *);
 	sockaddr_in_init(sin, &inp->inp_laddr, inp->inp_lport);
@@ -686,8 +724,10 @@ inpcb_fetch_peeraddr(inpcb_t *inp, struc
 {
 	struct sockaddr_in *sin;
 
-	if (inp->inp_af != AF_INET)
+	if (inp->inp_af != AF_INET) {
 		return;
+	}
+	KASSERT(solocked(inp->inp_socket));
 
 	sin = mtod(nam, struct sockaddr_in *);
 	sockaddr_in_init(sin, &inp->inp_faddr, inp->inp_fport);
@@ -718,6 +758,8 @@ inpcb_notify(inpcbtable_t *inpt, struct 
 		return 0;
 
 	nmatch = 0;
+
+	mutex_enter(&inpt->inpt_lock);
 	head = INPCBHASH_CONNECT(inpt, faddr, fport, laddr, lport);
 	LIST_FOREACH(inph, head, inph_hash) {
 		inpcb_t *inp = (inpcb_t *)inph;
@@ -733,6 +775,7 @@ inpcb_notify(inpcbtable_t *inpt, struct 
 			nmatch++;
 		}
 	}
+	mutex_exit(&inpt->inpt_lock);
 	return nmatch;
 }
 
@@ -745,6 +788,7 @@ inpcb_notifyall(inpcbtable_t *inpt, stru
 	if (in_nullhost(faddr) || notify == NULL)
 		return;
 
+	mutex_enter(&inpt->inpt_lock);
 	CIRCLEQ_FOREACH(inph, &inpt->inpt_queue, inph_queue) {
 		inpcb_t *inp = (inpcb_t *)inph;
 
@@ -753,6 +797,7 @@ inpcb_notifyall(inpcbtable_t *inpt, stru
 		if (in_hosteq(inp->inp_faddr, faddr))
 			(*notify)(inp, errno);
 	}
+	mutex_exit(&inpt->inpt_lock);
 }
 
 void
@@ -760,6 +805,7 @@ inpcb_purgeif0(inpcbtable_t *inpt, ifnet
 {
 	struct inpcb_hdr *inph;
 
+	mutex_enter(&inpt->inpt_lock);
 	CIRCLEQ_FOREACH(inph, &inpt->inpt_queue, inph_queue) {
 		inpcb_t *inp = (inpcb_t *)inph;
 		struct ip_moptions *imo;
@@ -790,6 +836,7 @@ inpcb_purgeif0(inpcbtable_t *inpt, ifnet
 		}
 		imo->imo_num_memberships -= gap;
 	}
+	mutex_exit(&inpt->inpt_lock);
 }
 
 void
@@ -797,6 +844,7 @@ inpcb_purgeif(inpcbtable_t *inpt, ifnet_
 {
 	struct inpcb_hdr *inph;
 
+	mutex_enter(&inpt->inpt_lock);
 	CIRCLEQ_FOREACH(inph, &inpt->inpt_queue, inph_queue) {
 		inpcb_t *inp = (inpcb_t *)inph;
 		struct rtentry *rt;
@@ -808,6 +856,7 @@ inpcb_purgeif(inpcbtable_t *inpt, ifnet_
 			inpcb_rtchange(inp, 0);
 		}
 	}
+	mutex_exit(&inpt->inpt_lock);
 }
 
 int
@@ -818,6 +867,7 @@ inpcb_foreach(inpcbtable_t *inpt, int af
 
 	KASSERT(func != NULL);
 
+	mutex_enter(&inpt->inpt_lock);
 	CIRCLEQ_FOREACH(inph, &inpt->inpt_queue, inph_queue) {
 		inpcb_t *inp = (inpcb_t *)inph;
 
@@ -826,6 +876,8 @@ inpcb_foreach(inpcbtable_t *inpt, int af
 		if ((error = func(inp, arg)) != 0)
 			break;
 	}
+	mutex_exit(&inpt->inpt_lock);
+
 	return error;
 }
 
@@ -876,20 +928,25 @@ inpcb_rtchange(inpcb_t *inp, int errno)
 	/* XXX SHOULD NOTIFY HIGHER-LEVEL PROTOCOLS */
 }
 
+/*
+ * inpcb_lookup_local: find a PCB by looking at the local port and matching
+ * the local address or resolving the wildcards.  Primarily used to detect
+ * when the local address is already in use.
+ */
 inpcb_t *
-inpcb_lookup_port(inpcbtable_t *inpt, struct in_addr laddr,
-    u_int lport_arg, int lookup_wildcard, vestigial_inpcb_t *vp)
+inpcb_lookup_local(inpcbtable_t *inpt, struct in_addr laddr,
+    in_port_t lport, int lookup_wildcard, vestigial_inpcb_t *vp)
 {
 	inpcbhead_t *head;
 	struct inpcb_hdr *inph;
 	inpcb_t *match = NULL;
 	struct vestigial_hooks *vestige;
-	in_port_t lport = lport_arg;
 	int wildcard, matchwild = 3;
 
 	if (vp)
 		vp->valid = 0;
 
+	mutex_enter(&inpt->inpt_lock);
 	head = INPCBHASH_PORT(inpt, lport);
 	LIST_FOREACH(inph, head, inph_lhash) {
 		inpcb_t * const inp = (inpcb_t *)inph;
@@ -935,16 +992,17 @@ inpcb_lookup_port(inpcbtable_t *inpt, st
 				break;
 		}
 	}
-	if (match && matchwild == 0)
+	if (match && matchwild == 0) {
+		mutex_exit(&inpt->inpt_lock);
 		return match;
+	}
 
 	if (vp && (vestige = inpt->inpt_vestige) != NULL) {
-		void *state = (*vestige->init_ports4)(laddr, lport_arg,
+		void *state = (*vestige->init_ports4)(laddr, lport,
 		    lookup_wildcard);
 		vestigial_inpcb_t better;
 
 		while ((*vestige->next_port4)(state, vp)) {
-
 			if (vp->lport != lport)
 				continue;
 			wildcard = 0;
@@ -973,38 +1031,32 @@ inpcb_lookup_port(inpcbtable_t *inpt, st
 			}
 		}
 
-		if (match) {
-			if (match != (void*)&better)
-				return match;
-			else {
-				*vp = better;
-				return 0;
-			}
+		if (match && match == (void*)&better) {
+			*vp = better;
+			match = 0;
 		}
 	}
+	mutex_exit(&inpt->inpt_lock);
 
 	return match;
 }
 
-#ifdef DIAGNOSTIC
-int	inpcb_notifymiss = 0;
-#endif
-
+/*
+ * inpcb_lookup: perform a full 4-tuple PCB lookup.
+ */
 inpcb_t *
-inpcb_lookup_connect(inpcbtable_t *inpt,
-    struct in_addr faddr, u_int fport_arg,
-    struct in_addr laddr, u_int lport_arg,
-    vestigial_inpcb_t *vp)
+inpcb_lookup(inpcbtable_t *inpt, struct in_addr faddr, in_port_t fport,
+    struct in_addr laddr, in_port_t lport, vestigial_inpcb_t *vp)
 {
 	inpcbhead_t *head;
 	struct inpcb_hdr *inph;
 	inpcb_t *inp;
-	in_port_t fport = fport_arg, lport = lport_arg;
 	struct vestigial_hooks *vestige;
 
 	if (vp)
 		vp->valid = 0;
 
+	mutex_enter(&inpt->inpt_lock);
 	head = INPCBHASH_CONNECT(inpt, faddr, fport, laddr, lport);
 	LIST_FOREACH(inph, head, inph_hash) {
 		inp = (inpcb_t *)inph;
@@ -1018,19 +1070,11 @@ inpcb_lookup_connect(inpcbtable_t *inpt,
 			goto out;
 	}
 	if (vp && (vestige = inpt->inpt_vestige) != NULL) {
-		if ((*vestige->lookup4)(faddr, fport_arg, laddr, lport_arg, vp))
-			return 0;
+		(void)(*vestige->lookup4)(faddr, fport, laddr, lport, vp);
 	}
+	mutex_exit(&inpt->inpt_lock);
 
-#ifdef DIAGNOSTIC
-	if (inpcb_notifymiss) {
-		printf("inpcb_lookup_connect: faddr=%08x fport=%d laddr=%08x lport=%d\n",
-		    ntohl(faddr.s_addr), ntohs(fport),
-		    ntohl(laddr.s_addr), ntohs(lport));
-	}
-#endif
-	return 0;
-
+	return NULL;
 out:
 	/* Move this PCB to the head of hash chain. */
 	inph = &inp->inp_head;
@@ -1038,17 +1082,23 @@ out:
 		LIST_REMOVE(inph, inph_hash);
 		LIST_INSERT_HEAD(head, inph, inph_hash);
 	}
+	mutex_exit(&inpt->inpt_lock);
+
 	return inp;
 }
 
+/*
+ * inpcb_lookup_bound: find a PCB by looking at the local address and port.
+ * Primarily used to find the listening (i.e. already bound) socket.
+ */
 inpcb_t *
-inpcb_lookup_bind(inpcbtable_t *inpt, struct in_addr laddr, u_int lport_arg)
+inpcb_lookup_bound(inpcbtable_t *inpt, struct in_addr laddr, in_port_t lport)
 {
 	inpcbhead_t *head;
 	struct inpcb_hdr *inph;
 	inpcb_t *inp;
-	in_port_t lport = lport_arg;
 
+	mutex_enter(&inpt->inpt_lock);
 	head = INPCBHASH_BIND(inpt, laddr, lport);
 	LIST_FOREACH(inph, head, inph_hash) {
 		inp = (inpcb_t *)inph;
@@ -1069,14 +1119,9 @@ inpcb_lookup_bind(inpcbtable_t *inpt, st
 		    in_hosteq(inp->inp_laddr, zeroin_addr))
 			goto out;
 	}
-#ifdef DIAGNOSTIC
-	if (inpcb_notifymiss) {
-		printf("inpcb_lookup_bind: laddr=%08x lport=%d\n",
-		    ntohl(laddr.s_addr), ntohs(lport));
-	}
-#endif
-	return 0;
+	mutex_exit(&inpt->inpt_lock);
 
+	return NULL;
 out:
 	/* Move this PCB to the head of hash chain. */
 	inph = &inp->inp_head;
@@ -1084,15 +1129,19 @@ out:
 		LIST_REMOVE(inph, inph_hash);
 		LIST_INSERT_HEAD(head, inph, inph_hash);
 	}
+	mutex_exit(&inpt->inpt_lock);
+
 	return inp;
 }
 
-void
-inpcb_set_state(inpcb_t *inp, int state)
+static void
+inpcb_set_state1(inpcb_t *inp, int state)
 {
+	KASSERT(mutex_owned(&inp->inp_table->inpt_lock));
 
-	if (inp->inp_af != AF_INET)
+	if (inp->inp_af != AF_INET) {
 		return;
+	}
 
 	if (inp->inp_state > INP_ATTACHED) {
 		LIST_REMOVE(&inp->inp_head, inph_hash);
@@ -1113,6 +1162,16 @@ inpcb_set_state(inpcb_t *inp, int state)
 	inp->inp_state = state;
 }
 
+void
+inpcb_set_state(inpcb_t *inp, int state)
+{
+	inpcbtable_t *inpt = inp->inp_table;
+
+	mutex_enter(&inpt->inpt_lock);
+	inpcb_set_state1(inp, state);
+	mutex_exit(&inpt->inpt_lock);
+}
+
 struct rtentry *
 inpcb_rtentry(inpcb_t *inp)
 {

Index: src/sys/netinet/in_pcb.h
diff -u src/sys/netinet/in_pcb.h:1.51.2.1 src/sys/netinet/in_pcb.h:1.51.2.2
--- src/sys/netinet/in_pcb.h:1.51.2.1	Wed Jul 17 03:16:31 2013
+++ src/sys/netinet/in_pcb.h	Mon Sep 23 00:57:53 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: in_pcb.h,v 1.51.2.1 2013/07/17 03:16:31 rmind Exp $	*/
+/*	$NetBSD: in_pcb.h,v 1.51.2.2 2013/09/23 00:57:53 rmind Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -196,11 +196,11 @@ int	inpcb_bind(inpcb_t *, struct mbuf *,
 int	inpcb_connect(inpcb_t *, struct mbuf *, struct lwp *);
 void	inpcb_destroy(inpcb_t *);
 void	inpcb_disconnect(inpcb_t *);
-inpcb_t *inpcb_lookup_port(inpcbtable_t *, struct in_addr, u_int, int,
+inpcb_t *inpcb_lookup_local(inpcbtable_t *, struct in_addr, in_port_t, int,
     struct vestigial_inpcb *);
-inpcb_t *inpcb_lookup_bind(inpcbtable_t *, struct in_addr, u_int);
-inpcb_t *inpcb_lookup_connect(inpcbtable_t *, struct in_addr, u_int,
-    struct in_addr, u_int, struct vestigial_inpcb *);
+inpcb_t *inpcb_lookup_bound(inpcbtable_t *, struct in_addr, in_port_t);
+inpcb_t *inpcb_lookup(inpcbtable_t *, struct in_addr, in_port_t,
+    struct in_addr, in_port_t, struct vestigial_inpcb *);
 int	inpcb_notify(inpcbtable_t *, struct in_addr, u_int,
 	    struct in_addr, u_int, int, void (*)(inpcb_t *, int));
 void	inpcb_notifyall(inpcbtable_t *, struct in_addr, int,

Index: src/sys/netinet/portalgo.c
diff -u src/sys/netinet/portalgo.c:1.5.2.1 src/sys/netinet/portalgo.c:1.5.2.2
--- src/sys/netinet/portalgo.c:1.5.2.1	Wed Jul 17 03:16:31 2013
+++ src/sys/netinet/portalgo.c	Mon Sep 23 00:57:53 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: portalgo.c,v 1.5.2.1 2013/07/17 03:16:31 rmind Exp $	*/
+/*	$NetBSD: portalgo.c,v 1.5.2.2 2013/09/23 00:57:53 rmind Exp $	*/
 
 /*
  * Copyright 2011 Vlad Balan
@@ -34,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: portalgo.c,v 1.5.2.1 2013/07/17 03:16:31 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: portalgo.c,v 1.5.2.2 2013/09/23 00:57:53 rmind Exp $");
 
 #include "opt_inet.h"
 
@@ -266,13 +266,8 @@ check_suitable_port(uint16_t port, struc
 			return false;
 
 		sin.sin_addr = inp->inp_laddr;
-		pcb = inpcb_lookup_port(table, sin.sin_addr, htons(port), 1,
+		pcb = inpcb_lookup_local(table, sin.sin_addr, htons(port), 1,
 		    &vestigial);
-
-		DPRINTF("%s inpcb_lookup_port returned %p and "
-		    "vestigial.valid %d\n",
-		    __func__, pcb, vestigial.valid);
-
 		if ((!pcb) && (!vestigial.valid)) {
 			enum kauth_network_req req;
 
@@ -321,12 +316,10 @@ check_suitable_port(uint16_t port, struc
 
 #ifdef INET
 		if (IN6_IS_ADDR_V4MAPPED(&sin6.sin6_addr)) {
-			t = inpcb_lookup_port(table,
+			t = inpcb_lookup_local(table,
 			    *(struct in_addr *)&sin6.sin6_addr.s6_addr32[3],
 			    htons(port), wild, &vestigial);
 			if (!t && vestigial.valid) {
-				DPRINTF("%s inpcb_lookup_port returned "
-				    "a result\n", __func__);
 				return false;
 			}
 		} else

Index: src/sys/netinet/raw_ip.c
diff -u src/sys/netinet/raw_ip.c:1.116.2.2 src/sys/netinet/raw_ip.c:1.116.2.3
--- src/sys/netinet/raw_ip.c:1.116.2.2	Wed Aug 28 15:21:48 2013
+++ src/sys/netinet/raw_ip.c	Mon Sep 23 00:57:53 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: raw_ip.c,v 1.116.2.2 2013/08/28 15:21:48 rmind Exp $	*/
+/*	$NetBSD: raw_ip.c,v 1.116.2.3 2013/09/23 00:57:53 rmind Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -65,7 +65,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: raw_ip.c,v 1.116.2.2 2013/08/28 15:21:48 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: raw_ip.c,v 1.116.2.3 2013/09/23 00:57:53 rmind Exp $");
 
 #include "opt_inet.h"
 #include "opt_compat_netbsd.h"
@@ -573,6 +573,7 @@ rip_attach(struct socket *so, int proto)
 
 	return 0;
 }
+
 static void
 rip_detach(struct socket *so)
 {

Index: src/sys/netinet/tcp_input.c
diff -u src/sys/netinet/tcp_input.c:1.327.2.1 src/sys/netinet/tcp_input.c:1.327.2.2
--- src/sys/netinet/tcp_input.c:1.327.2.1	Wed Jul 17 03:16:31 2013
+++ src/sys/netinet/tcp_input.c	Mon Sep 23 00:57:53 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: tcp_input.c,v 1.327.2.1 2013/07/17 03:16:31 rmind Exp $	*/
+/*	$NetBSD: tcp_input.c,v 1.327.2.2 2013/09/23 00:57:53 rmind Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -148,7 +148,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tcp_input.c,v 1.327.2.1 2013/07/17 03:16:31 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tcp_input.c,v 1.327.2.2 2013/09/23 00:57:53 rmind Exp $");
 
 #include "opt_inet.h"
 #include "opt_ipsec.h"
@@ -1407,11 +1407,11 @@ findpcb:
 	switch (af) {
 #ifdef INET
 	case AF_INET:
-		inp = inpcb_lookup_connect(tcbtable, ip->ip_src, th->th_sport,
+		inp = inpcb_lookup(tcbtable, ip->ip_src, th->th_sport,
 		    ip->ip_dst, th->th_dport, &vestige);
 		if (inp == NULL && !vestige.valid) {
 			TCP_STATINC(TCP_STAT_PCBHASHMISS);
-			inp = inpcb_lookup_bind(tcbtable, ip->ip_dst, th->th_dport);
+			inp = inpcb_lookup_bound(tcbtable, ip->ip_dst, th->th_dport);
 		}
 #ifdef INET6
 		if (inp == NULL && !vestige.valid) {

Index: src/sys/netinet/tcp_subr.c
diff -u src/sys/netinet/tcp_subr.c:1.250.2.1 src/sys/netinet/tcp_subr.c:1.250.2.2
--- src/sys/netinet/tcp_subr.c:1.250.2.1	Wed Jul 17 03:16:31 2013
+++ src/sys/netinet/tcp_subr.c	Mon Sep 23 00:57:53 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: tcp_subr.c,v 1.250.2.1 2013/07/17 03:16:31 rmind Exp $	*/
+/*	$NetBSD: tcp_subr.c,v 1.250.2.2 2013/09/23 00:57:53 rmind Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -91,7 +91,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tcp_subr.c,v 1.250.2.1 2013/07/17 03:16:31 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tcp_subr.c,v 1.250.2.2 2013/09/23 00:57:53 rmind Exp $");
 
 #include "opt_inet.h"
 #include "opt_ipsec.h"
@@ -1610,8 +1610,8 @@ tcp_ctlinput(int cmd, const struct socka
 		memcpy(&src6.s6_addr32[3], &ip->ip_src, sizeof(struct in_addr));
 		memcpy(&dst6.s6_addr32[3], &ip->ip_dst, sizeof(struct in_addr));
 #endif
-		if ((inp = inpcb_lookup_connect(tcbtable, ip->ip_dst,
-		    th->th_dport, ip->ip_src, th->th_sport, 0)) != NULL)
+		if ((inp = inpcb_lookup(tcbtable, ip->ip_dst,
+		    th->th_dport, ip->ip_src, th->th_sport, NULL)) != NULL)
 #ifdef INET6
 			in6p = NULL;
 #else

Index: src/sys/netinet/tcp_usrreq.c
diff -u src/sys/netinet/tcp_usrreq.c:1.166.4.2 src/sys/netinet/tcp_usrreq.c:1.166.4.3
--- src/sys/netinet/tcp_usrreq.c:1.166.4.2	Wed Aug 28 15:21:48 2013
+++ src/sys/netinet/tcp_usrreq.c	Mon Sep 23 00:57:53 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: tcp_usrreq.c,v 1.166.4.2 2013/08/28 15:21:48 rmind Exp $	*/
+/*	$NetBSD: tcp_usrreq.c,v 1.166.4.3 2013/09/23 00:57:53 rmind Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -95,7 +95,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tcp_usrreq.c,v 1.166.4.2 2013/08/28 15:21:48 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tcp_usrreq.c,v 1.166.4.3 2013/09/23 00:57:53 rmind Exp $");
 
 #include "opt_inet.h"
 #include "opt_ipsec.h"
@@ -1235,7 +1235,7 @@ inet4_ident_core(struct in_addr raddr, u
 	inpcb_t *inp;
 	struct socket *so;
 
-	inp = inpcb_lookup_connect(tcbtable, raddr, rport, laddr, lport, 0);
+	inp = inpcb_lookup(tcbtable, raddr, rport, laddr, lport, NULL);
 	if (inp == NULL || (so = inpcb_get_socket(inp)) == NULL)
 		return ESRCH;
 

Index: src/sys/netinet/tcp_vtw.c
diff -u src/sys/netinet/tcp_vtw.c:1.9.4.1 src/sys/netinet/tcp_vtw.c:1.9.4.2
--- src/sys/netinet/tcp_vtw.c:1.9.4.1	Wed Jul 17 03:16:31 2013
+++ src/sys/netinet/tcp_vtw.c	Mon Sep 23 00:57:53 2013
@@ -124,7 +124,7 @@
 
 #include <netinet/tcp_vtw.h>
 
-__KERNEL_RCSID(0, "$NetBSD: tcp_vtw.c,v 1.9.4.1 2013/07/17 03:16:31 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tcp_vtw.c,v 1.9.4.2 2013/09/23 00:57:53 rmind Exp $");
 
 #define db_trace(__a, __b)	do { } while (/*CONSTCOND*/0)
 
@@ -1570,7 +1570,7 @@ vtw_tick(void *arg)
 	mutex_exit(softnet_lock);
 }
 
-/* inpcb_lookup_ports assist for handling vestigial entries.
+/* inpcb_lookup_local() assist for handling vestigial entries.
  */
 static void *
 tcp_init_ports_v4(struct in_addr addr, u_int port, int wild)
@@ -1669,7 +1669,7 @@ tcp_lookup_v4(struct in_addr faddr, uint
 	return vtw_export_v4(ctl, vtw, res);
 }
 
-/* inpcb_lookup_ports assist for handling vestigial entries.
+/* inpcb_lookup_local() assist for handling vestigial entries.
  */
 static void *
 tcp_init_ports_v6(const struct in6_addr *addr, u_int port, int wild)

Index: src/sys/netinet/udp_usrreq.c
diff -u src/sys/netinet/udp_usrreq.c:1.190.2.2 src/sys/netinet/udp_usrreq.c:1.190.2.3
--- src/sys/netinet/udp_usrreq.c:1.190.2.2	Wed Aug 28 15:21:48 2013
+++ src/sys/netinet/udp_usrreq.c	Mon Sep 23 00:57:53 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: udp_usrreq.c,v 1.190.2.2 2013/08/28 15:21:48 rmind Exp $	*/
+/*	$NetBSD: udp_usrreq.c,v 1.190.2.3 2013/09/23 00:57:53 rmind Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -66,7 +66,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: udp_usrreq.c,v 1.190.2.2 2013/08/28 15:21:48 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: udp_usrreq.c,v 1.190.2.3 2013/09/23 00:57:53 rmind Exp $");
 
 #include "opt_inet.h"
 #include "opt_compat_netbsd.h"
@@ -575,11 +575,10 @@ udp4_realinput(struct sockaddr_in *src, 
 		 */
 		struct socket *so;
 
-		inp = inpcb_lookup_connect(udbtable, *src4, *sport, *dst4,
-		    *dport, 0);
+		inp = inpcb_lookup(udbtable, *src4, *sport, *dst4, *dport, NULL);
 		if (inp == NULL) {
 			UDP_STATINC(UDP_STAT_PCBHASHMISS);
-			inp = inpcb_lookup_bind(udbtable, *dst4, *dport);
+			inp = inpcb_lookup_bound(udbtable, *dst4, *dport);
 			if (inp == NULL)
 				return rcvcnt;
 		}
@@ -753,32 +752,24 @@ end:
 	return error;
 }
 
-
-int
-udp_output(struct mbuf *m, ...)
+static int
+udp_output(struct mbuf *m, inpcb_t *inp)
 {
-	inpcb_t *inp;
 	struct socket *so;
 	struct udpiphdr *ui;
 	struct route *ro;
 	int len = m->m_pkthdr.len;
 	int error = 0;
-	va_list ap;
 
 	MCLAIM(m, &udp_tx_mowner);
-	va_start(ap, m);
-	inp = va_arg(ap, inpcb_t *);
-	va_end(ap);
-
 	so = inpcb_get_socket(inp);
 	KASSERT(solocked(so));
 
 	/*
-	 * Calculate data length and get a mbuf
-	 * for UDP and IP headers.
+	 * Calculate data length and get a mbuf for UDP and IP headers.
 	 */
 	M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT);
-	if (m == 0) {
+	if (m == NULL) {
 		error = ENOBUFS;
 		goto release;
 	}
@@ -793,15 +784,13 @@ udp_output(struct mbuf *m, ...)
 	}
 
 	/*
-	 * Fill in mbuf with extended UDP header
-	 * and addresses and length put into network format.
+	 * Fill in mbuf with extended UDP header.
 	 */
 	ui = mtod(m, struct udpiphdr *);
 	ui->ui_pr = IPPROTO_UDP;
-
 	inpcb_get_addrs(inp, &ui->ui_src, &ui->ui_dst);
 	inpcb_get_ports(inp, &ui->ui_sport, &ui->ui_dport);
-	ui->ui_ulen = htons((u_int16_t)len + sizeof(struct udphdr));
+	ui->ui_ulen = htons((uint16_t)len + sizeof(struct udphdr));
 
 	ro = inpcb_get_route(inp);
 
@@ -821,11 +810,12 @@ udp_output(struct mbuf *m, ...)
 	} else
 		ui->ui_sum = 0;
 
-	((struct ip *)ui)->ip_len = htons(sizeof (struct udpiphdr) + len);
+	struct ip *ui_ip = (struct ip *)ui;
+	ui_ip->ip_len = htons(sizeof (struct udpiphdr) + len);
 
 	struct ip *inp_ip = in_getiphdr(inp);
-	((struct ip *)ui)->ip_ttl = inp_ip->ip_ttl;	/* XXX */
-	((struct ip *)ui)->ip_tos = inp_ip->ip_tos;	/* XXX */
+	ui_ip->ip_ttl = inp_ip->ip_ttl;	/* XXX */
+	ui_ip->ip_tos = inp_ip->ip_tos;	/* XXX */
 	UDP_STATINC(UDP_STAT_OPACKETS);
 
 	return (ip_output(m, inpcb_get_options(inp), ro,
@@ -889,6 +879,49 @@ udp_detach(struct socket *so)
 }
 
 static int
+udp_send(struct socket *so, struct mbuf *m, struct mbuf *nam,
+    struct mbuf *control)
+{
+	inpcb_t *inp;
+	struct in_addr laddr;
+	int error;
+
+	KASSERT(solocked(so));
+	inp = sotoinpcb(so);
+
+	if (control && control->m_len) {
+		m_freem(control);
+		m_freem(m);
+		return EINVAL;
+	}
+
+	if ((so->so_state & SS_ISCONNECTED) != 0) {
+		m_freem(m);
+		return nam ? EISCONN : ENOTCONN;
+	}
+
+	if (nam) {
+		/*
+		 * XXX: sendto() case - temporarily connect the socket
+		 * to the destination, send and then disconnect.  Also,
+		 * preserve the local address as it may be changed.
+		 */
+		inpcb_get_addrs(inp, &laddr, NULL);
+		if ((error = inpcb_connect(inp, nam, curlwp)) != 0) {
+			m_freem(m);
+			return error;
+		}
+	}
+	error = udp_output(m, inp);
+	if (nam) {
+		inpcb_disconnect(inp);
+		inpcb_set_addrs(inp, &laddr, NULL);
+		inpcb_set_state(inp, INP_BOUND);
+	}
+	return error;
+}
+
+static int
 udp_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam,
     struct mbuf *control, struct lwp *l)
 {
@@ -921,10 +954,6 @@ udp_usrreq(struct socket *so, int req, s
 		goto release;
 	}
 
-	/*
-	 * Note: need to block udp_input while changing
-	 * the udp pcb queue and/or pcb addresses.
-	 */
 	switch (req) {
 	case PRU_BIND:
 		error = inpcb_bind(inp, nam, l);
@@ -949,8 +978,6 @@ udp_usrreq(struct socket *so, int req, s
 		/*soisdisconnected(so);*/
 		so->so_state &= ~SS_ISCONNECTED;		/* XXX */
 		inpcb_disconnect(inp);
-		inpcb_set_addrs(inp, &zeroin_addr, NULL);	/* XXX */
-		inpcb_set_state(inp, INP_BOUND);		/* XXX */
 		break;
 
 	case PRU_SHUTDOWN:
@@ -962,47 +989,7 @@ udp_usrreq(struct socket *so, int req, s
 		break;
 
 	case PRU_SEND:
-		if (control && control->m_len) {
-			m_freem(control);
-			m_freem(m);
-			error = EINVAL;
-			break;
-		}
-	{
-		/*
-		 * Note: sendto case - temporarily connect the socket
-		 * to the destination, send and then disconnect.
-		 * XXX: save the local address, restore after.
-		 */
-		struct in_addr laddr;
-
-		memset(&laddr, 0, sizeof laddr);
-		if (nam) {
-			inpcb_get_addrs(inp, &laddr, NULL);
-			if ((so->so_state & SS_ISCONNECTED) != 0) {
-				error = EISCONN;
-				goto die;
-			}
-			error = inpcb_connect(inp, nam, l);
-			if (error)
-				goto die;
-		} else {
-			if ((so->so_state & SS_ISCONNECTED) == 0) {
-				error = ENOTCONN;
-				goto die;
-			}
-		}
-		error = udp_output(m, inp);
-		m = NULL;
-		if (nam) {
-			inpcb_disconnect(inp);
-			inpcb_set_addrs(inp, &laddr, NULL);
-			inpcb_set_state(inp, INP_BOUND);
-		}
-die:
-		if (m)
-			m_freem(m);
-	}
+		error = udp_send(so, m, nam, control);
 		break;
 
 	case PRU_SENSE:

Index: src/sys/netinet/udp_var.h
diff -u src/sys/netinet/udp_var.h:1.38.4.2 src/sys/netinet/udp_var.h:1.38.4.3
--- src/sys/netinet/udp_var.h:1.38.4.2	Wed Aug 28 15:21:48 2013
+++ src/sys/netinet/udp_var.h	Mon Sep 23 00:57:53 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: udp_var.h,v 1.38.4.2 2013/08/28 15:21:48 rmind Exp $	*/
+/*	$NetBSD: udp_var.h,v 1.38.4.3 2013/09/23 00:57:53 rmind Exp $	*/
 
 /*
  * Copyright (c) 1982, 1986, 1989, 1993
@@ -95,7 +95,6 @@ void	 *udp_ctlinput(int, const struct so
 int	 udp_ctloutput(int, struct socket *, struct sockopt *);
 void	 udp_init(void);
 void	 udp_input(struct mbuf *, ...);
-int	 udp_output(struct mbuf *, ...);
 int	 udp_sysctl(int *, u_int, void *, size_t *, void *, size_t);
 
 int	udp_input_checksum(int af, struct mbuf *, const struct udphdr *, int,

Index: src/sys/netinet6/in6_pcb.c
diff -u src/sys/netinet6/in6_pcb.c:1.123.2.1 src/sys/netinet6/in6_pcb.c:1.123.2.2
--- src/sys/netinet6/in6_pcb.c:1.123.2.1	Wed Jul 17 03:16:31 2013
+++ src/sys/netinet6/in6_pcb.c	Mon Sep 23 00:57:53 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: in6_pcb.c,v 1.123.2.1 2013/07/17 03:16:31 rmind Exp $	*/
+/*	$NetBSD: in6_pcb.c,v 1.123.2.2 2013/09/23 00:57:53 rmind Exp $	*/
 /*	$KAME: in6_pcb.c,v 1.84 2001/02/08 18:02:08 itojun Exp $	*/
 
 /*
@@ -62,7 +62,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: in6_pcb.c,v 1.123.2.1 2013/07/17 03:16:31 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: in6_pcb.c,v 1.123.2.2 2013/09/23 00:57:53 rmind Exp $");
 
 #include "opt_inet.h"
 #include "opt_ipsec.h"
@@ -317,7 +317,7 @@ in6_pcbbind_port(struct in6pcb *in6p, st
 			struct inpcb *t;
 			struct vestigial_inpcb vestige;
 
-			t = inpcb_lookup_port(table,
+			t = inpcb_lookup_local(table,
 			    *(struct in_addr *)&sin6->sin6_addr.s6_addr32[3],
 			    sin6->sin6_port, wild, &vestige);
 			if (t && (reuseport & t->inp_socket->so_options) == 0)

Reply via email to