summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/netinet/in_pcb.c53
-rw-r--r--sys/netinet/in_pcb.h2
-rw-r--r--sys/netinet/tcp_usrreq.c63
-rw-r--r--sys/netinet6/in6_pcb.c92
-rw-r--r--sys/netinet6/in6_pcb.h4
5 files changed, 130 insertions, 84 deletions
diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c
index 8284031..9ad3607 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 d4d049c..1654eb9 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 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 */
diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c
index 083ed03..2d7baab 100644
--- a/sys/netinet6/in6_pcb.c
+++ b/sys/netinet6/in6_pcb.c
@@ -626,6 +626,50 @@ in6_pcbdetach(inp)
uma_zfree(ipi->ipi_zone, inp);
}
+struct sockaddr *
+in6_sockaddr(port, addr_p)
+ in_port_t port;
+ struct in6_addr *addr_p;
+{
+ struct sockaddr_in6 *sin6;
+
+ MALLOC(sin6, struct sockaddr_in6 *, sizeof *sin6, M_SONAME, M_WAITOK);
+ bzero(sin6, sizeof *sin6);
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_len = sizeof(*sin6);
+ sin6->sin6_port = port;
+ sin6->sin6_addr = *addr_p;
+ if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr))
+ sin6->sin6_scope_id = ntohs(sin6->sin6_addr.s6_addr16[1]);
+ else
+ sin6->sin6_scope_id = 0; /*XXX*/
+ if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr))
+ sin6->sin6_addr.s6_addr16[1] = 0;
+
+ return (struct sockaddr *)sin6;
+}
+
+struct sockaddr *
+in6_v4mapsin6_sockaddr(port, addr_p)
+ in_port_t port;
+ struct in_addr *addr_p;
+{
+ struct sockaddr_in sin;
+ struct sockaddr_in6 *sin6_p;
+
+ bzero(&sin, sizeof sin);
+ sin.sin_family = AF_INET;
+ sin.sin_len = sizeof(sin);
+ sin.sin_port = port;
+ sin.sin_addr = *addr_p;
+
+ MALLOC(sin6_p, struct sockaddr_in6 *, sizeof *sin6_p, M_SONAME,
+ M_WAITOK);
+ in6_sin_2_v4mapsin6(&sin, sin6_p);
+
+ return (struct sockaddr *)sin6_p;
+}
+
/*
* The calling convention of in6_setsockaddr() and in6_setpeeraddr() was
* modified to match the pru_sockaddr() and pru_peeraddr() entry points
@@ -643,34 +687,20 @@ in6_setsockaddr(so, nam)
{
int s;
register struct inpcb *inp;
- register struct sockaddr_in6 *sin6;
-
- /*
- * Do the malloc first in case it blocks.
- */
- MALLOC(sin6, struct sockaddr_in6 *, sizeof *sin6, M_SONAME, M_WAITOK);
- bzero(sin6, sizeof *sin6);
- sin6->sin6_family = AF_INET6;
- sin6->sin6_len = sizeof(*sin6);
+ struct in6_addr addr;
+ in_port_t port;
s = splnet();
inp = sotoinpcb(so);
if (!inp) {
splx(s);
- free(sin6, M_SONAME);
return EINVAL;
}
- sin6->sin6_port = inp->inp_lport;
- sin6->sin6_addr = inp->in6p_laddr;
+ port = inp->inp_lport;
+ addr = inp->in6p_laddr;
splx(s);
- if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr))
- sin6->sin6_scope_id = ntohs(sin6->sin6_addr.s6_addr16[1]);
- else
- sin6->sin6_scope_id = 0; /*XXX*/
- if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr))
- sin6->sin6_addr.s6_addr16[1] = 0;
- *nam = (struct sockaddr *)sin6;
+ *nam = in6_sockaddr(port, &addr);
return 0;
}
@@ -681,34 +711,20 @@ in6_setpeeraddr(so, nam)
{
int s;
struct inpcb *inp;
- register struct sockaddr_in6 *sin6;
-
- /*
- * Do the malloc first in case it blocks.
- */
- MALLOC(sin6, struct sockaddr_in6 *, sizeof(*sin6), M_SONAME, M_WAITOK);
- bzero((caddr_t)sin6, sizeof (*sin6));
- sin6->sin6_family = AF_INET6;
- sin6->sin6_len = sizeof(struct sockaddr_in6);
+ struct in6_addr addr;
+ in_port_t port;
s = splnet();
inp = sotoinpcb(so);
if (!inp) {
splx(s);
- free(sin6, M_SONAME);
return EINVAL;
}
- sin6->sin6_port = inp->inp_fport;
- sin6->sin6_addr = inp->in6p_faddr;
+ port = inp->inp_fport;
+ addr = inp->in6p_faddr;
splx(s);
- if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr))
- sin6->sin6_scope_id = ntohs(sin6->sin6_addr.s6_addr16[1]);
- else
- sin6->sin6_scope_id = 0; /*XXX*/
- if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr))
- sin6->sin6_addr.s6_addr16[1] = 0;
- *nam = (struct sockaddr *)sin6;
+ *nam = in6_sockaddr(port, &addr);
return 0;
}
diff --git a/sys/netinet6/in6_pcb.h b/sys/netinet6/in6_pcb.h
index 5098a12..6d5c609 100644
--- a/sys/netinet6/in6_pcb.h
+++ b/sys/netinet6/in6_pcb.h
@@ -95,6 +95,10 @@ void in6_pcbnotify __P((struct inpcbhead *, struct sockaddr *,
struct inpcb *(*)(struct inpcb *, int)));
struct inpcb *
in6_rtchange __P((struct inpcb *, int));
+struct sockaddr *
+ in6_sockaddr __P((in_port_t port, struct in6_addr *addr_p));
+struct sockaddr *
+ in6_v4mapsin6_sockaddr __P((in_port_t port, struct in_addr *addr_p));
int in6_setpeeraddr __P((struct socket *so, struct sockaddr **nam));
int in6_setsockaddr __P((struct socket *so, struct sockaddr **nam));
int in6_mapped_sockaddr __P((struct socket *so, struct sockaddr **nam));
OpenPOWER on IntegriCloud