inpcb: move local address assignment out of in_pcbdisconnect()
The logic of clearing local address at the protocol level makes sense. It
is feature of UDP, not of any protocol, that local address is cleared on
disconnect. This code can be tracked down to pre-FreeBSD times.
For example, for TCP we want a disconnected socket to return previously
used local address with getsockname(2). The TCP has successfully evaded
that by not calling in_pcbdisconnect() and calling in_pcbdetach() in the
very old code and in_pcbdrop() later. After D55661 TCP again has this
potential bug masked. Better make it right than rely on such
unintentional evasions.
The raw IP sockets don't use in_pcbdisconnect(), but they are going to in
the near future. If in_pcbdisconnect() clears local address for them,
that would be a larger bug than just getsockname(). A raw socket may be
bound with bind(2) and then connect(2)ed, and then disconnected, e.g.
connect(INADDR_ANY). And when we run raw IP socket through
in_pcbdisconnect() we don't want to lose local address.
This reverts D38362.
This reverts commit 2589ec0f36.
Reviewed by: rrs, markj
Differential Revision: https://reviews.freebsd.org/D56170
This commit is contained in:
@@ -1465,7 +1465,6 @@ in_pcbdisconnect(struct inpcb *inp)
|
||||
if ((inp->inp_socket->so_proto->pr_flags & PR_CONNREQUIRED) == 0) {
|
||||
/* See the comment in in_pcbinshash(). */
|
||||
inp->inp_smr = smr_advance(inp->inp_pcbinfo->ipi_smr);
|
||||
inp->inp_laddr.s_addr = INADDR_ANY;
|
||||
inp->inp_faddr.s_addr = INADDR_ANY;
|
||||
inp->inp_fport = 0;
|
||||
}
|
||||
|
||||
@@ -1528,6 +1528,7 @@ udp_abort(struct socket *so)
|
||||
INP_WLOCK(inp);
|
||||
if (inp->inp_faddr.s_addr != INADDR_ANY) {
|
||||
in_pcbdisconnect(inp);
|
||||
inp->inp_laddr.s_addr = INADDR_ANY;
|
||||
soisdisconnected(so);
|
||||
}
|
||||
INP_WUNLOCK(inp);
|
||||
@@ -1630,6 +1631,7 @@ udp_close(struct socket *so)
|
||||
INP_WLOCK(inp);
|
||||
if (inp->inp_faddr.s_addr != INADDR_ANY) {
|
||||
in_pcbdisconnect(inp);
|
||||
inp->inp_laddr.s_addr = INADDR_ANY;
|
||||
soisdisconnected(so);
|
||||
}
|
||||
INP_WUNLOCK(inp);
|
||||
@@ -1697,6 +1699,7 @@ udp_disconnect(struct socket *so)
|
||||
return (ENOTCONN);
|
||||
}
|
||||
in_pcbdisconnect(inp);
|
||||
inp->inp_laddr.s_addr = INADDR_ANY;
|
||||
SOCK_LOCK(so);
|
||||
so->so_state &= ~SS_ISCONNECTED; /* XXX */
|
||||
SOCK_UNLOCK(so);
|
||||
|
||||
@@ -542,7 +542,6 @@ in6_pcbdisconnect(struct inpcb *inp)
|
||||
/* See the comment in in_pcbinshash(). */
|
||||
inp->inp_smr = smr_advance(inp->inp_pcbinfo->ipi_smr);
|
||||
/* XXX-MJ torn writes are visible to SMR lookup */
|
||||
memset(&inp->in6p_laddr, 0, sizeof(inp->in6p_laddr));
|
||||
memset(&inp->in6p_faddr, 0, sizeof(inp->in6p_faddr));
|
||||
inp->inp_fport = 0;
|
||||
}
|
||||
|
||||
@@ -996,6 +996,7 @@ udp6_abort(struct socket *so)
|
||||
|
||||
if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) {
|
||||
in6_pcbdisconnect(inp);
|
||||
memset(&inp->in6p_laddr, 0, sizeof(inp->in6p_laddr));
|
||||
soisdisconnected(so);
|
||||
}
|
||||
INP_WUNLOCK(inp);
|
||||
@@ -1105,6 +1106,7 @@ udp6_close(struct socket *so)
|
||||
#endif
|
||||
if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) {
|
||||
in6_pcbdisconnect(inp);
|
||||
memset(&inp->in6p_laddr, 0, sizeof(inp->in6p_laddr));
|
||||
soisdisconnected(so);
|
||||
}
|
||||
INP_WUNLOCK(inp);
|
||||
@@ -1239,6 +1241,7 @@ udp6_disconnect(struct socket *so)
|
||||
}
|
||||
|
||||
in6_pcbdisconnect(inp);
|
||||
memset(&inp->in6p_laddr, 0, sizeof(inp->in6p_laddr));
|
||||
SOCK_LOCK(so);
|
||||
so->so_state &= ~SS_ISCONNECTED; /* XXX */
|
||||
SOCK_UNLOCK(so);
|
||||
|
||||
Reference in New Issue
Block a user