diff options
Diffstat (limited to 'sys/netinet')
| -rw-r--r-- | sys/netinet/in_pcb.c | 53 | ||||
| -rw-r--r-- | sys/netinet/in_pcb.h | 2 | ||||
| -rw-r--r-- | sys/netinet/tcp_usrreq.c | 63 |
3 files changed, 72 insertions, 46 deletions
diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c index 8284031a200e..9ad3607cf6e0 100644 --- a/sys/netinet/in_pcb.c +++ b/sys/netinet/in_pcb.c @@ -577,6 +577,23 @@ in_pcbdetach(inp) uma_zfree(ipi->ipi_zone, inp); } +struct sockaddr * +in_sockaddr(port, addr_p) + in_port_t port; + struct in_addr *addr_p; +{ + struct sockaddr_in *sin; + + MALLOC(sin, struct sockaddr_in *, sizeof *sin, M_SONAME, + M_WAITOK | M_ZERO); + sin->sin_family = AF_INET; + sin->sin_len = sizeof(*sin); + sin->sin_addr = *addr_p; + sin->sin_port = port; + + return (struct sockaddr *)sin; +} + /* * The wrapper function will pass down the pcbinfo for this function to lock. * The socket must have a valid @@ -593,15 +610,8 @@ in_setsockaddr(so, nam, pcbinfo) { int s; register struct inpcb *inp; - register struct sockaddr_in *sin; - - /* - * 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); + struct in_addr addr; + in_port_t port; s = splnet(); INP_INFO_RLOCK(pcbinfo); @@ -609,17 +619,16 @@ in_setsockaddr(so, nam, pcbinfo) if (!inp) { INP_INFO_RUNLOCK(pcbinfo); splx(s); - free(sin, M_SONAME); return ECONNRESET; } INP_LOCK(inp); - sin->sin_port = inp->inp_lport; - sin->sin_addr = inp->inp_laddr; + port = inp->inp_lport; + addr = inp->inp_laddr; INP_UNLOCK(inp); INP_INFO_RUNLOCK(pcbinfo); splx(s); - *nam = (struct sockaddr *)sin; + *nam = in_sockaddr(port, &addr); return 0; } @@ -634,15 +643,8 @@ in_setpeeraddr(so, nam, pcbinfo) { int s; register struct inpcb *inp; - register struct sockaddr_in *sin; - - /* - * 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); + struct in_addr addr; + in_port_t port; s = splnet(); INP_INFO_RLOCK(pcbinfo); @@ -650,17 +652,16 @@ in_setpeeraddr(so, nam, pcbinfo) if (!inp) { INP_INFO_RUNLOCK(pcbinfo); splx(s); - free(sin, M_SONAME); return ECONNRESET; } INP_LOCK(inp); - sin->sin_port = inp->inp_fport; - sin->sin_addr = inp->inp_faddr; + port = inp->inp_fport; + addr = inp->inp_faddr; INP_UNLOCK(inp); INP_INFO_RUNLOCK(pcbinfo); splx(s); - *nam = (struct sockaddr *)sin; + *nam = in_sockaddr(port, &addr); return 0; } diff --git a/sys/netinet/in_pcb.h b/sys/netinet/in_pcb.h index d4d049cea74a..1654eb99e93b 100644 --- a/sys/netinet/in_pcb.h +++ b/sys/netinet/in_pcb.h @@ -344,6 +344,8 @@ void in_pcbnotifyall(struct inpcbinfo *pcbinfo, struct in_addr, void in_pcbrehash(struct inpcb *); int in_setpeeraddr(struct socket *so, struct sockaddr **nam, struct inpcbinfo *pcbinfo); int in_setsockaddr(struct socket *so, struct sockaddr **nam, struct inpcbinfo *pcbinfo);; +struct sockaddr * + in_sockaddr(in_port_t port, struct in_addr *addr); void in_pcbremlists(struct inpcb *inp); int prison_xinpcb(struct thread *td, struct inpcb *inp); #endif /* _KERNEL */ diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c index 767fb7d29323..2b8e3fd1a8b9 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 */ |
