Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/uipc_socket.c
Show First 20 Lines • Show All 101 Lines • ▼ Show 20 Lines | |||||
* sopoll() currently does not need a VNET context to be set. | * sopoll() currently does not need a VNET context to be set. | ||||
*/ | */ | ||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include "opt_inet.h" | #include "opt_inet.h" | ||||
#include "opt_inet6.h" | #include "opt_inet6.h" | ||||
#include "opt_kern_tls.h" | |||||
#include "opt_sctp.h" | #include "opt_sctp.h" | ||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/systm.h> | #include <sys/systm.h> | ||||
#include <sys/fcntl.h> | #include <sys/fcntl.h> | ||||
#include <sys/limits.h> | #include <sys/limits.h> | ||||
#include <sys/lock.h> | #include <sys/lock.h> | ||||
#include <sys/mac.h> | #include <sys/mac.h> | ||||
#include <sys/malloc.h> | #include <sys/malloc.h> | ||||
#include <sys/mbuf.h> | #include <sys/mbuf.h> | ||||
#include <sys/mutex.h> | #include <sys/mutex.h> | ||||
#include <sys/domain.h> | #include <sys/domain.h> | ||||
#include <sys/file.h> /* for struct knote */ | #include <sys/file.h> /* for struct knote */ | ||||
#include <sys/hhook.h> | #include <sys/hhook.h> | ||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/khelp.h> | #include <sys/khelp.h> | ||||
#include <sys/ktls.h> | |||||
#include <sys/event.h> | #include <sys/event.h> | ||||
#include <sys/eventhandler.h> | #include <sys/eventhandler.h> | ||||
#include <sys/poll.h> | #include <sys/poll.h> | ||||
#include <sys/proc.h> | #include <sys/proc.h> | ||||
#include <sys/protosw.h> | #include <sys/protosw.h> | ||||
#include <sys/socket.h> | #include <sys/socket.h> | ||||
#include <sys/socketvar.h> | #include <sys/socketvar.h> | ||||
#include <sys/resourcevar.h> | #include <sys/resourcevar.h> | ||||
#include <net/route.h> | #include <net/route.h> | ||||
#include <sys/signalvar.h> | #include <sys/signalvar.h> | ||||
#include <sys/stat.h> | #include <sys/stat.h> | ||||
#include <sys/sx.h> | #include <sys/sx.h> | ||||
#include <sys/sysctl.h> | #include <sys/sysctl.h> | ||||
#include <sys/taskqueue.h> | #include <sys/taskqueue.h> | ||||
#include <sys/uio.h> | #include <sys/uio.h> | ||||
#include <sys/jail.h> | #include <sys/jail.h> | ||||
#include <sys/syslog.h> | #include <sys/syslog.h> | ||||
#include <netinet/in.h> | #include <netinet/in.h> | ||||
#include <netinet/tcp.h> | |||||
#include <net/vnet.h> | #include <net/vnet.h> | ||||
#include <security/mac/mac_framework.h> | #include <security/mac/mac_framework.h> | ||||
#include <vm/uma.h> | #include <vm/uma.h> | ||||
#ifdef COMPAT_FREEBSD32 | #ifdef COMPAT_FREEBSD32 | ||||
▲ Show 20 Lines • Show All 1,285 Lines • ▼ Show 20 Lines | |||||
int | int | ||||
sosend_generic(struct socket *so, struct sockaddr *addr, struct uio *uio, | sosend_generic(struct socket *so, struct sockaddr *addr, struct uio *uio, | ||||
struct mbuf *top, struct mbuf *control, int flags, struct thread *td) | struct mbuf *top, struct mbuf *control, int flags, struct thread *td) | ||||
{ | { | ||||
long space; | long space; | ||||
ssize_t resid; | ssize_t resid; | ||||
int clen = 0, error, dontroute; | int clen = 0, error, dontroute; | ||||
int atomic = sosendallatonce(so) || top; | int atomic = sosendallatonce(so) || top; | ||||
int pru_flag; | |||||
#ifdef KERN_TLS | |||||
struct ktls_session *tls; | |||||
int tls_enq_cnt, tls_pruflag; | |||||
uint8_t tls_rtype; | |||||
tls = NULL; | |||||
tls_rtype = TLS_RLTYPE_APP; | |||||
#endif | |||||
if (uio != NULL) | if (uio != NULL) | ||||
resid = uio->uio_resid; | resid = uio->uio_resid; | ||||
else | else | ||||
resid = top->m_pkthdr.len; | resid = top->m_pkthdr.len; | ||||
/* | /* | ||||
* In theory resid should be unsigned. However, space must be | * In theory resid should be unsigned. However, space must be | ||||
* signed, as it might be less than 0 if we over-committed, and we | * signed, as it might be less than 0 if we over-committed, and we | ||||
* must use a signed comparison of space and resid. On the other | * must use a signed comparison of space and resid. On the other | ||||
Show All 15 Lines | if (td != NULL) | ||||
td->td_ru.ru_msgsnd++; | td->td_ru.ru_msgsnd++; | ||||
if (control != NULL) | if (control != NULL) | ||||
clen = control->m_len; | clen = control->m_len; | ||||
error = sblock(&so->so_snd, SBLOCKWAIT(flags)); | error = sblock(&so->so_snd, SBLOCKWAIT(flags)); | ||||
if (error) | if (error) | ||||
goto out; | goto out; | ||||
#ifdef KERN_TLS | |||||
tls_pruflag = 0; | |||||
tls = ktls_hold(so->so_snd.sb_tls_info); | |||||
if (tls != NULL) { | |||||
if (tls->sw_encrypt != NULL) | |||||
tls_pruflag = PRUS_NOTREADY; | |||||
if (control != NULL) { | |||||
struct cmsghdr *cm = mtod(control, struct cmsghdr *); | |||||
if (clen >= sizeof(*cm) && | |||||
cm->cmsg_type == TLS_SET_RECORD_TYPE) { | |||||
tls_rtype = *((uint8_t *)CMSG_DATA(cm)); | |||||
clen = 0; | |||||
m_freem(control); | |||||
control = NULL; | |||||
atomic = 1; | |||||
} | |||||
} | |||||
} | |||||
#endif | |||||
restart: | restart: | ||||
do { | do { | ||||
SOCKBUF_LOCK(&so->so_snd); | SOCKBUF_LOCK(&so->so_snd); | ||||
if (so->so_snd.sb_state & SBS_CANTSENDMORE) { | if (so->so_snd.sb_state & SBS_CANTSENDMORE) { | ||||
SOCKBUF_UNLOCK(&so->so_snd); | SOCKBUF_UNLOCK(&so->so_snd); | ||||
error = EPIPE; | error = EPIPE; | ||||
goto release; | goto release; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 61 Lines • ▼ Show 20 Lines | do { | ||||
/* | /* | ||||
* Copy the data from userland into a mbuf | * Copy the data from userland into a mbuf | ||||
* chain. If resid is 0, which can happen | * chain. If resid is 0, which can happen | ||||
* only if we have control to send, then | * only if we have control to send, then | ||||
* a single empty mbuf is returned. This | * a single empty mbuf is returned. This | ||||
* is a workaround to prevent protocol send | * is a workaround to prevent protocol send | ||||
* methods to panic. | * methods to panic. | ||||
*/ | */ | ||||
#ifdef KERN_TLS | |||||
if (tls != NULL) { | |||||
top = m_uiotombuf(uio, M_WAITOK, space, | top = m_uiotombuf(uio, M_WAITOK, space, | ||||
tls->params.max_frame_len, | |||||
M_NOMAP | | |||||
((flags & MSG_EOR) ? M_EOR : 0)); | |||||
if (top != NULL) { | |||||
error = ktls_frame(top, tls, | |||||
&tls_enq_cnt, tls_rtype); | |||||
if (error) { | |||||
m_freem(top); | |||||
goto release; | |||||
} | |||||
} | |||||
tls_rtype = TLS_RLTYPE_APP; | |||||
} else | |||||
#endif | |||||
top = m_uiotombuf(uio, M_WAITOK, space, | |||||
(atomic ? max_hdr : 0), | (atomic ? max_hdr : 0), | ||||
(atomic ? M_PKTHDR : 0) | | (atomic ? M_PKTHDR : 0) | | ||||
((flags & MSG_EOR) ? M_EOR : 0)); | ((flags & MSG_EOR) ? M_EOR : 0)); | ||||
if (top == NULL) { | if (top == NULL) { | ||||
error = EFAULT; /* only possible error */ | error = EFAULT; /* only possible error */ | ||||
goto release; | goto release; | ||||
} | } | ||||
space -= resid - uio->uio_resid; | space -= resid - uio->uio_resid; | ||||
resid = uio->uio_resid; | resid = uio->uio_resid; | ||||
} | } | ||||
if (dontroute) { | if (dontroute) { | ||||
SOCK_LOCK(so); | SOCK_LOCK(so); | ||||
so->so_options |= SO_DONTROUTE; | so->so_options |= SO_DONTROUTE; | ||||
SOCK_UNLOCK(so); | SOCK_UNLOCK(so); | ||||
} | } | ||||
/* | /* | ||||
* XXX all the SBS_CANTSENDMORE checks previously | * XXX all the SBS_CANTSENDMORE checks previously | ||||
* done could be out of date. We could have received | * done could be out of date. We could have received | ||||
* a reset packet in an interrupt or maybe we slept | * a reset packet in an interrupt or maybe we slept | ||||
* while doing page faults in uiomove() etc. We | * while doing page faults in uiomove() etc. We | ||||
* could probably recheck again inside the locking | * could probably recheck again inside the locking | ||||
* protection here, but there are probably other | * protection here, but there are probably other | ||||
* places that this also happens. We must rethink | * places that this also happens. We must rethink | ||||
* this. | * this. | ||||
*/ | */ | ||||
VNET_SO_ASSERT(so); | VNET_SO_ASSERT(so); | ||||
error = (*so->so_proto->pr_usrreqs->pru_send)(so, | |||||
(flags & MSG_OOB) ? PRUS_OOB : | pru_flag = (flags & MSG_OOB) ? PRUS_OOB : | ||||
/* | /* | ||||
* If the user set MSG_EOF, the protocol understands | * If the user set MSG_EOF, the protocol understands | ||||
* this flag and nothing left to send then use | * this flag and nothing left to send then use | ||||
* PRU_SEND_EOF instead of PRU_SEND. | * PRU_SEND_EOF instead of PRU_SEND. | ||||
*/ | */ | ||||
((flags & MSG_EOF) && | ((flags & MSG_EOF) && | ||||
(so->so_proto->pr_flags & PR_IMPLOPCL) && | (so->so_proto->pr_flags & PR_IMPLOPCL) && | ||||
(resid <= 0)) ? | (resid <= 0)) ? | ||||
PRUS_EOF : | PRUS_EOF : | ||||
/* If there is more to send set PRUS_MORETOCOME. */ | /* If there is more to send set PRUS_MORETOCOME. */ | ||||
(flags & MSG_MORETOCOME) || | (flags & MSG_MORETOCOME) || | ||||
(resid > 0 && space > 0) ? PRUS_MORETOCOME : 0, | (resid > 0 && space > 0) ? PRUS_MORETOCOME : 0; | ||||
top, addr, control, td); | |||||
#ifdef KERN_TLS | |||||
pru_flag |= tls_pruflag; | |||||
#endif | |||||
error = (*so->so_proto->pr_usrreqs->pru_send)(so, | |||||
pru_flag, top, addr, control, td); | |||||
if (dontroute) { | if (dontroute) { | ||||
SOCK_LOCK(so); | SOCK_LOCK(so); | ||||
so->so_options &= ~SO_DONTROUTE; | so->so_options &= ~SO_DONTROUTE; | ||||
SOCK_UNLOCK(so); | SOCK_UNLOCK(so); | ||||
} | } | ||||
#ifdef KERN_TLS | |||||
if (tls != NULL && tls->sw_encrypt != NULL) { | |||||
/* | |||||
* Note that error is intentionally | |||||
* ignored. | |||||
* | |||||
* Like sendfile(), we rely on the | |||||
* completion routine (pru_ready()) | |||||
* to free the mbufs in the event that | |||||
* pru_send() encountered an error and | |||||
* did not append them to the sockbuf. | |||||
*/ | |||||
soref(so); | |||||
ktls_enqueue(top, so, tls_enq_cnt); | |||||
} | |||||
#endif | |||||
clen = 0; | clen = 0; | ||||
control = NULL; | control = NULL; | ||||
top = NULL; | top = NULL; | ||||
if (error) | if (error) | ||||
goto release; | goto release; | ||||
} while (resid && space > 0); | } while (resid && space > 0); | ||||
} while (resid); | } while (resid); | ||||
release: | release: | ||||
sbunlock(&so->so_snd); | sbunlock(&so->so_snd); | ||||
out: | out: | ||||
#ifdef KERN_TLS | |||||
if (tls != NULL) | |||||
ktls_free(tls); | |||||
#endif | |||||
if (top != NULL) | if (top != NULL) | ||||
m_freem(top); | m_freem(top); | ||||
if (control != NULL) | if (control != NULL) | ||||
m_freem(control); | m_freem(control); | ||||
return (error); | return (error); | ||||
} | } | ||||
int | int | ||||
▲ Show 20 Lines • Show All 2,547 Lines • Show Last 20 Lines |