32 #include <sys/cdefs.h>
35 #include "opt_param.h"
37 #include <sys/param.h>
39 #include <sys/kernel.h>
42 #include <sys/mutex.h>
44 #include <sys/protosw.h>
45 #include <sys/resourcevar.h>
46 #include <sys/signalvar.h>
47 #include <sys/socket.h>
48 #include <sys/socketvar.h>
50 #include <sys/sysctl.h>
56 void (*
aio_swake)(
struct socket *,
struct sockbuf *);
64 (quad_t)SB_MAX * MCLBYTES / (MSIZE + MCLBYTES);
84 SOCKBUF_LOCK_ASSERT(&so->so_snd);
86 so->so_snd.sb_state |= SBS_CANTSENDMORE;
88 mtx_assert(SOCKBUF_MTX(&so->so_snd), MA_NOTOWNED);
95 SOCKBUF_LOCK(&so->so_snd);
97 mtx_assert(SOCKBUF_MTX(&so->so_snd), MA_NOTOWNED);
104 SOCKBUF_LOCK_ASSERT(&so->so_rcv);
106 so->so_rcv.sb_state |= SBS_CANTRCVMORE;
107 sorwakeup_locked(so);
108 mtx_assert(SOCKBUF_MTX(&so->so_rcv), MA_NOTOWNED);
115 SOCKBUF_LOCK(&so->so_rcv);
117 mtx_assert(SOCKBUF_MTX(&so->so_rcv), MA_NOTOWNED);
127 SOCKBUF_LOCK_ASSERT(sb);
129 sb->sb_flags |= SB_WAIT;
130 return (msleep(&sb->sb_cc, &sb->sb_mtx,
131 (sb->sb_flags & SB_NOINTR) ? PSOCK : PSOCK | PCATCH,
"sbwait",
139 KASSERT((flags & SBL_VALID) == flags,
140 (
"sblock: flags invalid (0x%x)", flags));
142 if (flags & SBL_WAIT) {
143 if ((sb->sb_flags & SB_NOINTR) ||
144 (flags & SBL_NOINTR)) {
145 sx_xlock(&sb->sb_sx);
148 return (sx_xlock_sig(&sb->sb_sx));
150 if (sx_try_xlock(&sb->sb_sx) == 0)
151 return (EWOULDBLOCK);
160 sx_xunlock(&sb->sb_sx);
180 SOCKBUF_LOCK_ASSERT(sb);
183 if (!SEL_WAITING(&sb->sb_sel))
184 sb->sb_flags &= ~SB_SEL;
185 if (sb->sb_flags & SB_WAIT) {
186 sb->sb_flags &= ~SB_WAIT;
189 KNOTE_LOCKED(&sb->sb_sel.si_note, 0);
190 if (sb->sb_upcall != NULL) {
191 ret = sb->sb_upcall(so, sb->sb_upcallarg, M_DONTWAIT);
192 if (ret == SU_ISCONNECTED) {
193 KASSERT(sb == &so->so_rcv,
194 (
"SO_SND upcall returned SU_ISCONNECTED"));
199 if (sb->sb_flags & SB_AIO)
202 if (ret == SU_ISCONNECTED)
204 if ((so->so_state & SS_ASYNC) && so->so_sigio != NULL)
205 pgsigio(&so->so_sigio, SIGIO, 0);
206 mtx_assert(SOCKBUF_MTX(sb), MA_NOTOWNED);
241 soreserve(
struct socket *so, u_long sndcc, u_long rcvcc)
243 struct thread *td = curthread;
245 SOCKBUF_LOCK(&so->so_snd);
246 SOCKBUF_LOCK(&so->so_rcv);
251 if (so->so_rcv.sb_lowat == 0)
252 so->so_rcv.sb_lowat = 1;
253 if (so->so_snd.sb_lowat == 0)
254 so->so_snd.sb_lowat = MCLBYTES;
255 if (so->so_snd.sb_lowat > so->so_snd.sb_hiwat)
256 so->so_snd.sb_lowat = so->so_snd.sb_hiwat;
257 SOCKBUF_UNLOCK(&so->so_rcv);
258 SOCKBUF_UNLOCK(&so->so_snd);
263 SOCKBUF_UNLOCK(&so->so_rcv);
264 SOCKBUF_UNLOCK(&so->so_snd);
272 u_long tmp_sb_max =
sb_max;
275 if (error || !req->newptr)
277 if (tmp_sb_max < MSIZE + MCLBYTES)
294 SOCKBUF_LOCK_ASSERT(sb);
306 PROC_LOCK(td->td_proc);
307 sbsize_limit =
lim_cur(td->td_proc, RLIMIT_SBSIZE);
308 PROC_UNLOCK(td->td_proc);
310 sbsize_limit = RLIM_INFINITY;
311 if (!
chgsbsize(so->so_cred->cr_uidinfo, &sb->sb_hiwat, cc,
314 sb->sb_mbmax = min(cc * sb_efficiency,
sb_max);
315 if (sb->sb_lowat > sb->sb_hiwat)
316 sb->sb_lowat = sb->sb_hiwat;
321 sbreserve(
struct sockbuf *sb, u_long cc,
struct socket *so,
340 (void)
chgsbsize(so->so_cred->cr_uidinfo, &sb->sb_hiwat, 0,
349 SOCKBUF_LOCK_ASSERT(sb);
394 sblastrecordchk(
struct sockbuf *sb,
const char *file,
int line)
396 struct mbuf *m = sb->sb_mb;
398 SOCKBUF_LOCK_ASSERT(sb);
400 while (m && m->m_nextpkt)
403 if (m != sb->sb_lastrecord) {
404 printf(
"%s: sb_mb %p sb_lastrecord %p last %p\n",
405 __func__, sb->sb_mb, sb->sb_lastrecord, m);
406 printf(
"packet chain:\n");
407 for (m = sb->sb_mb; m != NULL; m = m->m_nextpkt)
409 panic(
"%s from %s:%u", __func__, file, line);
414 sblastmbufchk(
struct sockbuf *sb,
const char *file,
int line)
416 struct mbuf *m = sb->sb_mb;
419 SOCKBUF_LOCK_ASSERT(sb);
421 while (m && m->m_nextpkt)
424 while (m && m->m_next)
427 if (m != sb->sb_mbtail) {
428 printf(
"%s: sb_mb %p sb_mbtail %p last %p\n",
429 __func__, sb->sb_mb, sb->sb_mbtail, m);
431 for (m = sb->sb_mb; m != NULL; m = m->m_nextpkt) {
433 for (n = m; n != NULL; n = n->m_next)
437 panic(
"%s from %s:%u", __func__, file, line);
442 #define SBLINKRECORD(sb, m0) do { \
443 SOCKBUF_LOCK_ASSERT(sb); \
444 if ((sb)->sb_lastrecord != NULL) \
445 (sb)->sb_lastrecord->m_nextpkt = (m0); \
447 (sb)->sb_mb = (m0); \
448 (sb)->sb_lastrecord = (m0); \
461 SOCKBUF_LOCK_ASSERT(sb);
472 if (n->m_flags & M_EOR) {
476 }
while (n->m_next && (n = n->m_next));
483 if ((n = sb->sb_lastrecord) != NULL) {
485 if (n->m_flags & M_EOR) {
489 }
while (n->m_next && (n = n->m_next));
495 sb->sb_lastrecord = m;
524 SOCKBUF_LOCK_ASSERT(sb);
526 KASSERT(m->m_nextpkt == NULL,(
"sbappendstream 0"));
527 KASSERT(sb->sb_mb == sb->sb_lastrecord,(
"sbappendstream 1"));
533 sb->sb_lastrecord = sb->sb_mb;
553 sbcheck(
struct sockbuf *sb)
557 u_long len = 0, mbcnt = 0;
559 SOCKBUF_LOCK_ASSERT(sb);
561 for (m = sb->sb_mb; m; m = n) {
563 for (; m; m = m->m_next) {
566 if (m->m_flags & M_EXT)
567 mbcnt += m->m_ext.ext_size;
570 if (len != sb->sb_cc || mbcnt != sb->sb_mbcnt) {
571 printf(
"cc %ld != %u || mbcnt %ld != %u\n", len, sb->sb_cc,
572 mbcnt, sb->sb_mbcnt);
586 SOCKBUF_LOCK_ASSERT(sb);
600 if (m && (m0->m_flags & M_EOR)) {
601 m0->m_flags &= ~M_EOR;
623 struct mbuf *m0,
struct mbuf *control,
struct mbuf *ctrl_last)
625 struct mbuf *m, *n, *nlast;
627 if (asa->sa_len > MLEN)
630 MGET(m, M_DONTWAIT, MT_SONAME);
633 m->m_len = asa->sa_len;
634 bcopy(asa, mtod(m, caddr_t), asa->sa_len);
636 ctrl_last->m_next = m0;
640 for (n = m; n->m_next != NULL; n = n->m_next)
646 sb->sb_mbtail = nlast;
661 struct mbuf *m0,
struct mbuf *control)
663 struct mbuf *ctrl_last;
664 int space = asa->sa_len;
666 SOCKBUF_LOCK_ASSERT(sb);
668 if (m0 && (m0->m_flags & M_PKTHDR) == 0)
669 panic(
"sbappendaddr_locked");
671 space += m0->m_pkthdr.len;
672 space +=
m_length(control, &ctrl_last);
674 if (space > sbspace(sb))
687 struct mbuf *m0,
struct mbuf *control)
689 struct mbuf *ctrl_last;
691 SOCKBUF_LOCK_ASSERT(sb);
693 ctrl_last = (control == NULL) ? NULL : m_last(control);
705 struct mbuf *m0,
struct mbuf *control)
717 struct mbuf *control)
719 struct mbuf *m, *n, *mlast;
722 SOCKBUF_LOCK_ASSERT(sb);
725 panic(
"sbappendcontrol_locked");
728 if (space > sbspace(sb))
734 for (m = control; m->m_next; m = m->m_next)
740 sb->sb_mbtail = mlast;
779 sbcompress(
struct sockbuf *sb,
struct mbuf *m,
struct mbuf *n)
784 SOCKBUF_LOCK_ASSERT(sb);
787 eor |= m->m_flags & M_EOR;
790 (((o = m->m_next) || (o = n)) &&
791 o->m_type == m->m_type))) {
792 if (sb->sb_lastrecord == m)
793 sb->sb_lastrecord = m->m_next;
797 if (n && (n->m_flags & M_EOR) == 0 &&
799 ((sb->sb_flags & SB_NOCOALESCE) == 0) &&
800 m->m_len <= MCLBYTES / 4 &&
801 m->m_len <= M_TRAILINGSPACE(n) &&
802 n->m_type == m->m_type) {
803 bcopy(mtod(m, caddr_t), mtod(n, caddr_t) + n->m_len,
805 n->m_len += m->m_len;
806 sb->sb_cc += m->m_len;
807 if (m->m_type != MT_DATA && m->m_type != MT_OOBDATA)
809 sb->sb_ctl += m->m_len;
820 m->m_flags &= ~M_EOR;
825 KASSERT(n != NULL, (
"sbcompress: eor && n == NULL"));
838 while (sb->sb_mbcnt) {
843 if (!sb->sb_cc && (sb->sb_mb == NULL || sb->sb_mb->m_len))
847 if (sb->sb_cc || sb->sb_mb || sb->sb_mbcnt)
848 panic(
"sbflush_internal: cc %u || mb %p || mbcnt %u",
849 sb->sb_cc, (
void *)sb->sb_mb, sb->sb_mbcnt);
856 SOCKBUF_LOCK_ASSERT(sb);
878 next = (m = sb->sb_mb) ? m->m_nextpkt : 0;
887 if (m->m_len > len) {
891 if (sb->sb_sndptroff != 0)
892 sb->sb_sndptroff -= len;
893 if (m->m_type != MT_DATA && m->m_type != MT_OOBDATA)
901 while (m && m->m_len == 0) {
916 sb->sb_mbtail = NULL;
917 sb->sb_lastrecord = NULL;
918 }
else if (m->m_nextpkt == NULL) {
919 sb->sb_lastrecord = m;
930 SOCKBUF_LOCK_ASSERT(sb);
949 sbsndptr(
struct sockbuf *sb, u_int off, u_int len, u_int *moff)
951 struct mbuf *m, *ret;
953 KASSERT(sb->sb_mb != NULL, (
"%s: sb_mb is NULL", __func__));
954 KASSERT(off + len <= sb->sb_cc, (
"%s: beyond sb", __func__));
955 KASSERT(sb->sb_sndptroff <= sb->sb_cc, (
"%s: sndptroff broken", __func__));
961 if (sb->sb_sndptroff > off) {
967 *moff = off - sb->sb_sndptroff;
968 m = ret = sb->sb_sndptr ? sb->sb_sndptr : sb->sb_mb;
969 if (*moff == m->m_len) {
971 sb->sb_sndptroff += m->m_len;
973 KASSERT(ret->m_len > 0,
974 (
"mbuf %p in sockbuf %p chain has no valid data", ret, sb));
978 for (off = off - sb->sb_sndptroff + len - 1;
979 off > 0 && m != NULL && off >= m->m_len;
981 sb->sb_sndptroff += m->m_len;
984 if (off > 0 && m == NULL)
985 panic(
"%s: sockbuf %p and mbuf %p clashing", __func__, sb, ret);
1000 KASSERT(sb->sb_mb != NULL, (
"%s: sb_mb is NULL", __func__));
1006 if (sb->sb_sndptr == NULL || sb->sb_sndptroff > off) {
1010 off -= sb->sb_sndptroff;
1012 while (off > 0 && m != NULL) {
1031 SOCKBUF_LOCK_ASSERT(sb);
1035 sb->sb_mb = m->m_nextpkt;
1067 if (CMSG_SPACE((u_int)size) > MCLBYTES)
1068 return ((
struct mbuf *) NULL);
1069 if (CMSG_SPACE((u_int)size) > MLEN)
1070 m = m_getcl(M_DONTWAIT, MT_CONTROL, 0);
1072 m = m_get(M_DONTWAIT, MT_CONTROL);
1074 return ((
struct mbuf *) NULL);
1075 cp = mtod(m,
struct cmsghdr *);
1077 KASSERT(CMSG_SPACE((u_int)size) <= M_TRAILINGSPACE(m),
1078 (
"sbcreatecontrol: short mbuf"));
1083 bzero(cp, CMSG_SPACE((u_int)size));
1085 (void)memcpy(CMSG_DATA(cp), p, size);
1086 m->m_len = CMSG_SPACE(size);
1087 cp->cmsg_len = CMSG_LEN(size);
1088 cp->cmsg_level =
level;
1089 cp->cmsg_type =
type;
1104 xsb->sb_cc = sb->sb_cc;
1105 xsb->sb_hiwat = sb->sb_hiwat;
1106 xsb->sb_mbcnt = sb->sb_mbcnt;
1107 xsb->sb_mcnt = sb->sb_mcnt;
1108 xsb->sb_ccnt = sb->sb_ccnt;
1109 xsb->sb_mbmax = sb->sb_mbmax;
1110 xsb->sb_lowat = sb->sb_lowat;
1111 xsb->sb_flags = sb->sb_flags;
1112 xsb->sb_timeo = sb->sb_timeo;
1117 SYSCTL_INT(_kern, KERN_DUMMY, dummy, CTLFLAG_RW, &dummy, 0,
"");
1118 SYSCTL_OID(_kern_ipc, KIPC_MAXSOCKBUF, maxsockbuf, CTLTYPE_ULONG|CTLFLAG_RW,
1120 SYSCTL_ULONG(_kern_ipc, KIPC_SOCKBUF_WASTE, sockbuf_waste_factor, CTLFLAG_RW,
1121 &sb_efficiency, 0,
"");
int sbreserve(struct sockbuf *sb, u_long cc, struct socket *so, struct thread *td)
void soisconnected(struct socket *so)
void(* aio_swake)(struct socket *, struct sockbuf *)
int chgsbsize(struct uidinfo *uip, u_int *hiwat, u_int to, rlim_t max)
void socantsendmore_locked(struct socket *so)
void soupcall_clear(struct socket *so, int which)
rlim_t lim_cur(struct proc *p, int which)
void sowakeup(struct socket *so, struct sockbuf *sb)
void sbappendrecord_locked(struct sockbuf *sb, struct mbuf *m0)
void sbunlock(struct sockbuf *sb)
int sbwait(struct sockbuf *sb)
void sbappend_locked(struct sockbuf *sb, struct mbuf *m)
void panic(const char *fmt,...)
void sbflush_locked(struct sockbuf *sb)
int sbreserve_locked(struct sockbuf *sb, u_long cc, struct socket *so, struct thread *td)
void selwakeuppri(struct selinfo *sip, int pri)
struct mbuf * sbsndmbuf(struct sockbuf *sb, u_int off, u_int *moff)
static u_long sb_efficiency
void socantrcvmore(struct socket *so)
static int sysctl_handle_sb_max(SYSCTL_HANDLER_ARGS)
void sbdrop(struct sockbuf *sb, int len)
static void sbdrop_internal(struct sockbuf *sb, int len)
void sbrelease_internal(struct sockbuf *sb, struct socket *so)
void sbdrop_locked(struct sockbuf *sb, int len)
void sbrelease(struct sockbuf *sb, struct socket *so)
void sbdroprecord(struct sockbuf *sb)
int sblock(struct sockbuf *sb, int flags)
SYSCTL_INT(_kern, KERN_DUMMY, dummy, CTLFLAG_RW,&dummy, 0,"")
void socantrcvmore_locked(struct socket *so)
void socantsendmore(struct socket *so)
void sbappend(struct sockbuf *sb, struct mbuf *m)
void sbcompress(struct sockbuf *sb, struct mbuf *m, struct mbuf *n)
int sbappendcontrol(struct sockbuf *sb, struct mbuf *m0, struct mbuf *control)
int sbappendaddr_nospacecheck_locked(struct sockbuf *sb, const struct sockaddr *asa, struct mbuf *m0, struct mbuf *control)
void sbappendstream_locked(struct sockbuf *sb, struct mbuf *m)
void sbdestroy(struct sockbuf *sb, struct socket *so)
static void sbflush_internal(struct sockbuf *sb)
SYSCTL_ULONG(_kern_ipc, KIPC_SOCKBUF_WASTE, sockbuf_waste_factor, CTLFLAG_RW,&sb_efficiency, 0,"")
int sbappendaddr(struct sockbuf *sb, const struct sockaddr *asa, struct mbuf *m0, struct mbuf *control)
void sbtoxsockbuf(struct sockbuf *sb, struct xsockbuf *xsb)
struct mbuf * sbcreatecontrol(caddr_t p, int size, int type, int level)
int printf(const char *fmt,...)
#define SBLINKRECORD(sb, m0)
static int sbappendaddr_locked_internal(struct sockbuf *sb, const struct sockaddr *asa, struct mbuf *m0, struct mbuf *control, struct mbuf *ctrl_last)
int soreserve(struct socket *so, u_long sndcc, u_long rcvcc)
SYSCTL_OID(_kern_ipc, KIPC_MAXSOCKBUF, maxsockbuf, CTLTYPE_ULONG|CTLFLAG_RW,&sb_max, 0, sysctl_handle_sb_max,"LU","Maximum socket buffer size")
u_int m_length(struct mbuf *m0, struct mbuf **last)
void sbappendrecord(struct sockbuf *sb, struct mbuf *m0)
int sbappendaddr_locked(struct sockbuf *sb, const struct sockaddr *asa, struct mbuf *m0, struct mbuf *control)
void sbdroprecord_locked(struct sockbuf *sb)
int sysctl_handle_long(SYSCTL_HANDLER_ARGS)
void sbrelease_locked(struct sockbuf *sb, struct socket *so)
struct mbuf * sbsndptr(struct sockbuf *sb, u_int off, u_int len, u_int *moff)
void sbflush(struct sockbuf *sb)
int sbappendcontrol_locked(struct sockbuf *sb, struct mbuf *m0, struct mbuf *control)
void pgsigio(struct sigio **sigiop, int sig, int checkctty)
const struct cf_level * level
void sbappendstream(struct sockbuf *sb, struct mbuf *m)