Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/uipc_usrreq.c
Show First 20 Lines • Show All 1,246 Lines • ▼ Show 20 Lines | out: | ||||||||||
if (c) | if (c) | ||||||||||
m_freem(c); | m_freem(c); | ||||||||||
if (m) | if (m) | ||||||||||
m_freem(m); | m_freem(m); | ||||||||||
return (error); | return (error); | ||||||||||
} | } | ||||||||||
/* | |||||||||||
* PF_UNIX/SOCK_DGRAM receive with MSG_PEEK | |||||||||||
*/ | |||||||||||
static int | |||||||||||
uipc_peek_dgram(struct socket *so, struct sockaddr **psa, struct uio *uio, | |||||||||||
struct mbuf **controlp, int *flagsp) | |||||||||||
{ | |||||||||||
struct mbuf *m; | |||||||||||
ssize_t len; | |||||||||||
int error; | |||||||||||
SOCKBUF_UNLOCK(&so->so_rcv); | |||||||||||
m = so->so_rcv.sb_mb; | |||||||||||
KASSERT(m->m_type == MT_SONAME, ("m->m_type == %d", m->m_type)); | |||||||||||
if (psa != NULL) | |||||||||||
*psa = sodupsockaddr(mtod(m, struct sockaddr *), M_WAITOK); | |||||||||||
if ((m = m->m_next) == NULL) { | |||||||||||
/* XXXRW: Can this happen? */ | |||||||||||
SOCK_IO_RECV_UNLOCK(so); | |||||||||||
return (0); | |||||||||||
} | |||||||||||
/* | |||||||||||
* With MSG_PEEK the control isn't executed, just copied. | |||||||||||
*/ | |||||||||||
while (m != NULL && m->m_type == MT_CONTROL) { | |||||||||||
if (controlp != NULL) { | |||||||||||
*controlp = m_copym(m, 0, m->m_len, M_WAITOK); | |||||||||||
controlp = &(*controlp)->m_next; | |||||||||||
} | |||||||||||
markj: Doesn't this copy internalized control messages? | |||||||||||
Done Inline ActionsYes, and this is the intent. Before we did the same in soreceive_generic() uipc_socket.c:2159 glebius: Yes, and this is the intent. Before we did the same in soreceive_generic() uipc_socket.c:2159 | |||||||||||
m = m->m_next; | |||||||||||
} | |||||||||||
KASSERT(m == NULL || m->m_type == MT_DATA, | |||||||||||
("%s: not MT_DATA mbuf %p", __func__, m)); | |||||||||||
while (m != NULL && uio->uio_resid > 0) { | |||||||||||
len = uio->uio_resid; | |||||||||||
if (len > m->m_len) | |||||||||||
len = m->m_len; | |||||||||||
error = uiomove(mtod(m, char *), (int)len, uio); | |||||||||||
if (error) { | |||||||||||
SOCK_IO_RECV_UNLOCK(so); | |||||||||||
return (error); | |||||||||||
} | |||||||||||
if (len == m->m_len) | |||||||||||
m = m->m_next; | |||||||||||
} | |||||||||||
SOCK_IO_RECV_UNLOCK(so); | |||||||||||
if (m != NULL && flagsp != NULL) | |||||||||||
*flagsp |= MSG_TRUNC; | |||||||||||
return (0); | |||||||||||
} | |||||||||||
/* | |||||||||||
* PF_UNIX/SOCK_DGRAM receive | |||||||||||
*/ | |||||||||||
static int | |||||||||||
uipc_soreceive_dgram(struct socket *so, struct sockaddr **psa, struct uio *uio, | |||||||||||
struct mbuf **mp0, struct mbuf **controlp, int *flagsp) | |||||||||||
{ | |||||||||||
struct mbuf *m, *m2; | |||||||||||
int flags, error; | |||||||||||
ssize_t len; | |||||||||||
bool nonblock; | |||||||||||
MPASS(mp0 == NULL); | |||||||||||
if (psa != NULL) | |||||||||||
*psa = NULL; | |||||||||||
if (controlp != NULL) | |||||||||||
*controlp = NULL; | |||||||||||
flags = flagsp != NULL ? *flagsp : 0; | |||||||||||
nonblock = (so->so_state & SS_NBIO) || | |||||||||||
(flags & (MSG_DONTWAIT | MSG_NBIO)); | |||||||||||
Done Inline Actions
markj: | |||||||||||
SOCK_IO_RECV_LOCK(so, SBLOCKWAIT(flags)); | |||||||||||
SOCKBUF_LOCK(&so->so_rcv); | |||||||||||
/* | |||||||||||
* Loop blocking while waiting for a datagram. | |||||||||||
*/ | |||||||||||
while ((m = so->so_rcv.sb_mb) == NULL) { | |||||||||||
KASSERT(sbavail(&so->so_rcv) == 0, | |||||||||||
("soreceive_dgram: sb_mb NULL but sbavail %u", | |||||||||||
sbavail(&so->so_rcv))); | |||||||||||
if (so->so_error) { | |||||||||||
error = so->so_error; | |||||||||||
so->so_error = 0; | |||||||||||
SOCKBUF_UNLOCK(&so->so_rcv); | |||||||||||
SOCK_IO_RECV_UNLOCK(so); | |||||||||||
return (error); | |||||||||||
} | |||||||||||
if (so->so_rcv.sb_state & SBS_CANTRCVMORE || | |||||||||||
uio->uio_resid == 0) { | |||||||||||
SOCKBUF_UNLOCK(&so->so_rcv); | |||||||||||
SOCK_IO_RECV_UNLOCK(so); | |||||||||||
return (0); | |||||||||||
} | |||||||||||
if (nonblock) { | |||||||||||
SOCKBUF_UNLOCK(&so->so_rcv); | |||||||||||
SOCK_IO_RECV_UNLOCK(so); | |||||||||||
return (EWOULDBLOCK); | |||||||||||
} | |||||||||||
SBLASTRECORDCHK(&so->so_rcv); | |||||||||||
SBLASTMBUFCHK(&so->so_rcv); | |||||||||||
error = sbwait(so, SO_RCV); | |||||||||||
if (error) { | |||||||||||
SOCKBUF_UNLOCK(&so->so_rcv); | |||||||||||
SOCK_IO_RECV_UNLOCK(so); | |||||||||||
return (error); | |||||||||||
} | |||||||||||
} | |||||||||||
SOCKBUF_LOCK_ASSERT(&so->so_rcv); | |||||||||||
if (uio->uio_td) | |||||||||||
uio->uio_td->td_ru.ru_msgrcv++; | |||||||||||
SBLASTRECORDCHK(&so->so_rcv); | |||||||||||
SBLASTMBUFCHK(&so->so_rcv); | |||||||||||
if (__predict_false(flags & MSG_PEEK)) | |||||||||||
return (uipc_peek_dgram(so, psa, uio, controlp, flagsp)); | |||||||||||
/* | |||||||||||
* Advance the sb_mb, update sb_lastrecord if necessary. | |||||||||||
*/ | |||||||||||
so->so_rcv.sb_mb = m->m_nextpkt; | |||||||||||
if (so->so_rcv.sb_mb == NULL) { | |||||||||||
KASSERT(so->so_rcv.sb_lastrecord == m, | |||||||||||
("%s: lastrecord != m", __func__)); | |||||||||||
so->so_rcv.sb_lastrecord = NULL; | |||||||||||
so->so_rcv.sb_mbtail = NULL; | |||||||||||
} else if (so->so_rcv.sb_mb->m_nextpkt == NULL) | |||||||||||
so->so_rcv.sb_lastrecord = so->so_rcv.sb_mb; | |||||||||||
/* | |||||||||||
* Walk 'm's chain and free that many bytes from the socket buffer. | |||||||||||
*/ | |||||||||||
for (m2 = m; m2 != NULL; m2 = m2->m_next) | |||||||||||
sbfree(&so->so_rcv, m2); | |||||||||||
/* | |||||||||||
* Do a few last checks before we let go of the lock. | |||||||||||
*/ | |||||||||||
SBLASTRECORDCHK(&so->so_rcv); | |||||||||||
SBLASTMBUFCHK(&so->so_rcv); | |||||||||||
SOCKBUF_UNLOCK(&so->so_rcv); | |||||||||||
KASSERT(m->m_type == MT_SONAME, ("m->m_type == %d", m->m_type)); | |||||||||||
if (psa != NULL) | |||||||||||
*psa = sodupsockaddr(mtod(m, struct sockaddr *), M_WAITOK); | |||||||||||
m = m_free(m); | |||||||||||
if (m == NULL) { | |||||||||||
/* XXXRW: Can this happen? */ | |||||||||||
SOCK_IO_RECV_UNLOCK(so); | |||||||||||
return (0); | |||||||||||
} | |||||||||||
/* | |||||||||||
* Packet to copyout() is now in 'm' and it is disconnected from the | |||||||||||
* queue. | |||||||||||
* | |||||||||||
* Process one or more MT_CONTROL mbufs present before any data mbufs | |||||||||||
* in the first mbuf chain on the socket buffer. We call into the | |||||||||||
* unp_externalize() to perform externalization (or freeing if | |||||||||||
* controlp == NULL). In some cases there can be only MT_CONTROL mbufs | |||||||||||
* without MT_DATA mbufs. | |||||||||||
*/ | |||||||||||
while (m != NULL && m->m_type == MT_CONTROL) { | |||||||||||
struct mbuf *cm; | |||||||||||
/* XXXGL: unp_externalize() is also dom_externalize() KBI and | |||||||||||
markjUnsubmitted Not Done Inline Actions
markj: | |||||||||||
* it frees whole chain, so we must disconnect the mbuf. | |||||||||||
markjUnsubmitted Not Done Inline ActionsRelated, unp_scan() will visit m->m_nextpkt, since it was intended to operate on the entire socket buffer. I can't find any problems caused by that, but it seems rather subtle. Might be worth asserting m->m_nextpkt == NULL before calling unp_scan() below and elsewhere in your patch set. Or improve the KPI to remove such footguns. markj: Related, unp_scan() will visit `m->m_nextpkt`, since it was intended to operate on the entire… | |||||||||||
*/ | |||||||||||
cm = m; m = m->m_next; cm->m_next = NULL; | |||||||||||
error = unp_externalize(cm, controlp, flags); | |||||||||||
if (error != 0) { | |||||||||||
SOCK_IO_RECV_UNLOCK(so); | |||||||||||
unp_scan(m, unp_freerights); | |||||||||||
m_freem(m); | |||||||||||
return (error); | |||||||||||
} | |||||||||||
if (controlp != NULL) { | |||||||||||
Done Inline ActionsLooks like this error is lost? markj: Looks like this error is lost? | |||||||||||
Done Inline ActionsGood catch! In the soreceive_generic() we catch the error much later and my code doesn't have it. I'm looking in making unp_externalize() to never fail, at least for SOCK_DGRAM. glebius: Good catch! In the soreceive_generic() we catch the error much later and my code doesn't have… | |||||||||||
while (*controlp != NULL) | |||||||||||
controlp = &(*controlp)->m_next; | |||||||||||
} | |||||||||||
} | |||||||||||
KASSERT(m == NULL || m->m_type == MT_DATA, | |||||||||||
("%s: not MT_DATA mbuf %p", __func__, m)); | |||||||||||
while (m != NULL && uio->uio_resid > 0) { | |||||||||||
len = uio->uio_resid; | |||||||||||
if (len > m->m_len) | |||||||||||
len = m->m_len; | |||||||||||
error = uiomove(mtod(m, char *), (int)len, uio); | |||||||||||
if (error) { | |||||||||||
SOCK_IO_RECV_UNLOCK(so); | |||||||||||
m_freem(m); | |||||||||||
return (error); | |||||||||||
} | |||||||||||
if (len == m->m_len) | |||||||||||
m = m_free(m); | |||||||||||
else { | |||||||||||
m->m_data += len; | |||||||||||
m->m_len -= len; | |||||||||||
} | |||||||||||
} | |||||||||||
SOCK_IO_RECV_UNLOCK(so); | |||||||||||
if (m != NULL) { | |||||||||||
flags |= MSG_TRUNC; | |||||||||||
m_freem(m); | |||||||||||
} | |||||||||||
if (flagsp != NULL) | |||||||||||
*flagsp |= flags; | |||||||||||
return (0); | |||||||||||
} | |||||||||||
static bool | static bool | ||||||||||
uipc_ready_scan(struct socket *so, struct mbuf *m, int count, int *errorp) | uipc_ready_scan(struct socket *so, struct mbuf *m, int count, int *errorp) | ||||||||||
{ | { | ||||||||||
struct mbuf *mb, *n; | struct mbuf *mb, *n; | ||||||||||
struct sockbuf *sb; | struct sockbuf *sb; | ||||||||||
SOCK_LOCK(so); | SOCK_LOCK(so); | ||||||||||
if (SOLISTENING(so)) { | if (SOLISTENING(so)) { | ||||||||||
▲ Show 20 Lines • Show All 129 Lines • ▼ Show 20 Lines | static struct pr_usrreqs uipc_usrreqs_dgram = { | ||||||||||
.pru_connect2 = uipc_connect2, | .pru_connect2 = uipc_connect2, | ||||||||||
.pru_detach = uipc_detach, | .pru_detach = uipc_detach, | ||||||||||
.pru_disconnect = uipc_disconnect, | .pru_disconnect = uipc_disconnect, | ||||||||||
.pru_peeraddr = uipc_peeraddr, | .pru_peeraddr = uipc_peeraddr, | ||||||||||
.pru_sosend = uipc_sosend_dgram, | .pru_sosend = uipc_sosend_dgram, | ||||||||||
.pru_sense = uipc_sense, | .pru_sense = uipc_sense, | ||||||||||
.pru_shutdown = uipc_shutdown, | .pru_shutdown = uipc_shutdown, | ||||||||||
.pru_sockaddr = uipc_sockaddr, | .pru_sockaddr = uipc_sockaddr, | ||||||||||
.pru_soreceive = soreceive_dgram, | .pru_soreceive = uipc_soreceive_dgram, | ||||||||||
.pru_close = uipc_close, | .pru_close = uipc_close, | ||||||||||
}; | }; | ||||||||||
static struct pr_usrreqs uipc_usrreqs_seqpacket = { | static struct pr_usrreqs uipc_usrreqs_seqpacket = { | ||||||||||
.pru_abort = uipc_abort, | .pru_abort = uipc_abort, | ||||||||||
.pru_accept = uipc_accept, | .pru_accept = uipc_accept, | ||||||||||
.pru_attach = uipc_attach, | .pru_attach = uipc_attach, | ||||||||||
.pru_bind = uipc_bind, | .pru_bind = uipc_bind, | ||||||||||
▲ Show 20 Lines • Show All 1,645 Lines • Show Last 20 Lines |
Doesn't this copy internalized control messages?