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)