diff options
author | truckman <truckman@FreeBSD.org> | 2002-08-21 11:57:12 +0000 |
---|---|---|
committer | truckman <truckman@FreeBSD.org> | 2002-08-21 11:57:12 +0000 |
commit | 7199888e8f06576febc8146d51d09b781470e8ce (patch) | |
tree | 20c70efb8a65a6f9c615daec57afaba3656fe3cc /sys/netinet/tcp_usrreq.c | |
parent | 2d2341a634a0d5c812cce6d8552614bd05f799c4 (diff) | |
download | FreeBSD-src-7199888e8f06576febc8146d51d09b781470e8ce.zip FreeBSD-src-7199888e8f06576febc8146d51d09b781470e8ce.tar.gz |
Create new functions in_sockaddr(), in6_sockaddr(), and
in6_v4mapsin6_sockaddr() which allocate the appropriate sockaddr_in*
structure and initialize it with the address and port information passed
as arguments. Use calls to these new functions to replace code that is
replicated multiple times in in_setsockaddr(), in_setpeeraddr(),
in6_setsockaddr(), in6_setpeeraddr(), in6_mapped_sockaddr(), and
in6_mapped_peeraddr(). Inline COMMON_END in tcp_usr_accept() so that
we can call in_sockaddr() with temporary copies of the address and port
after the PCB is unlocked.
Fix the lock violation in tcp6_usr_accept() (caused by calling MALLOC()
inside in6_mapped_peeraddr() while the PCB is locked) by changing
the implementation of tcp6_usr_accept() to match tcp_usr_accept().
Reviewed by: suz
Diffstat (limited to 'sys/netinet/tcp_usrreq.c')
-rw-r--r-- | sys/netinet/tcp_usrreq.c | 63 |
1 files changed, 43 insertions, 20 deletions
diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c index 767fb7d..2b8e3fd 100644 --- a/sys/netinet/tcp_usrreq.c +++ b/sys/netinet/tcp_usrreq.c @@ -467,8 +467,8 @@ tcp_usr_accept(struct socket *so, struct sockaddr **nam) int error = 0; struct inpcb *inp = NULL; struct tcpcb *tp = NULL; - struct sockaddr_in *sin; - const int inirw = INI_READ; + struct in_addr addr; + in_port_t port = 0; TCPDEBUG0; if (so->so_state & SS_ISDISCONNECTED) { @@ -476,21 +476,12 @@ tcp_usr_accept(struct socket *so, struct sockaddr **nam) goto out; } - /* - * Do the malloc first in case it blocks. - */ - MALLOC(sin, struct sockaddr_in *, sizeof *sin, M_SONAME, - M_WAITOK | M_ZERO); - sin->sin_family = AF_INET; - sin->sin_len = sizeof(*sin); - s = splnet(); INP_INFO_RLOCK(&tcbinfo); inp = sotoinpcb(so); if (!inp) { INP_INFO_RUNLOCK(&tcbinfo); splx(s); - free(sin, M_SONAME); return (EINVAL); } INP_LOCK(inp); @@ -499,14 +490,20 @@ tcp_usr_accept(struct socket *so, struct sockaddr **nam) TCPDEBUG1(); /* - * We inline in_setpeeraddr here, because we have already done - * the locking and the malloc. + * We inline in_setpeeraddr and COMMON_END here, so that we can + * copy the data of interest and defer the malloc until after we + * release the lock. */ - sin->sin_port = inp->inp_fport; - sin->sin_addr = inp->inp_faddr; - *nam = (struct sockaddr *)sin; + port = inp->inp_fport; + addr = inp->inp_faddr; - COMMON_END(PRU_ACCEPT); +out: TCPDEBUG2(PRU_ACCEPT); + if (tp) + INP_UNLOCK(inp); + splx(s); + if (error == 0) + *nam = in_sockaddr(port, &addr); + return error; } #ifdef INET6 @@ -517,7 +514,10 @@ tcp6_usr_accept(struct socket *so, struct sockaddr **nam) struct inpcb *inp = NULL; int error = 0; struct tcpcb *tp = NULL; - const int inirw = INI_READ; + struct in_addr addr; + struct in6_addr addr6; + in_port_t port = 0; + int v4 = 0; TCPDEBUG0; if (so->so_state & SS_ISDISCONNECTED) { @@ -537,8 +537,31 @@ tcp6_usr_accept(struct socket *so, struct sockaddr **nam) INP_INFO_RUNLOCK(&tcbinfo); tp = intotcpcb(inp); TCPDEBUG1(); - in6_mapped_peeraddr(so, nam); - COMMON_END(PRU_ACCEPT); + /* + * We inline in6_mapped_peeraddr and COMMON_END here, so that we can + * copy the data of interest and defer the malloc until after we + * release the lock. + */ + if (inp->inp_vflag & INP_IPV4) { + v4 = 1; + port = inp->inp_fport; + addr = inp->inp_faddr; + } else { + port = inp->inp_fport; + addr6 = inp->in6p_faddr; + } + +out: TCPDEBUG2(PRU_ACCEPT); + if (tp) + INP_UNLOCK(inp); + splx(s); + if (error == 0) { + if (v4) + *nam = in6_v4mapsin6_sockaddr(port, &addr); + else + *nam = in6_sockaddr(port, &addr6); + } + return error; } #endif /* INET6 */ |