/*
- * Copyright (c) 1998-2007 Apple Inc. All rights reserved.
+ * Copyright (c) 1998-2010 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
static int soqlimitcompat = 1;
static int soqlencomp = 0;
-u_long sb_max = SB_MAX; /* XXX should be static */
+/* Based on the number of mbuf clusters configured, high_sb_max and sb_max can get
+ * scaled up or down to suit that memory configuration. high_sb_max is a higher
+ * limit on sb_max that is checked when sb_max gets set through sysctl.
+ */
+
+u_int32_t sb_max = SB_MAX; /* XXX should be static */
+u_int32_t high_sb_max = SB_MAX;
-static u_long sb_efficiency = 8; /* parameter for sbreserve() */
+static u_int32_t sb_efficiency = 8; /* parameter for sbreserve() */
__private_extern__ unsigned int total_mb_cnt = 0;
__private_extern__ unsigned int total_cl_cnt = 0;
__private_extern__ int sbspace_factor = 8;
if (so_qlen >=
(soqlimitcompat ? head->so_qlimit : (3 * head->so_qlimit / 2)))
return ((struct socket *)0);
- so = soalloc(M_NOWAIT, head->so_proto->pr_domain->dom_family,
+ so = soalloc(1, head->so_proto->pr_domain->dom_family,
head->so_type);
if (so == NULL)
return ((struct socket *)0);
so->so_timeo = head->so_timeo;
so->so_pgid = head->so_pgid;
so->so_uid = head->so_uid;
- so->so_flags = head->so_flags & (SOF_REUSESHAREUID|SOF_NOTIFYCONFLICT); /* inherit SO_REUSESHAREUID and SO_NOTIFYCONFLICT ocket options */
+ /* inherit socket options stored in so_flags */
+ so->so_flags = head->so_flags & (SOF_NOSIGPIPE |
+ SOF_NOADDRAVAIL |
+ SOF_REUSESHAREUID |
+ SOF_NOTIFYCONFLICT |
+ SOF_BINDRANDOMPORT |
+ SOF_NPX_SETOPTSHUT);
so->so_usecount = 1;
so->next_lock_lr = 0;
so->next_unlock_lr = 0;
mac_socket_label_associate_accept(head, so);
#endif
+ /* inherit traffic management properties of listener */
+ so->so_traffic_mgt_flags = head->so_traffic_mgt_flags &
+ (TRAFFIC_MGT_SO_BACKGROUND | TRAFFIC_MGT_SO_BG_REGULATE);
+ so->so_background_thread = head->so_background_thread;
+#if PKT_PRIORITY
+ so->so_traffic_class = head->so_traffic_class;
+#endif /* PKT_PRIORITY */
+
if (soreserve(so, head->so_snd.sb_hiwat, head->so_rcv.sb_hiwat)) {
sflt_termsock(so);
sodealloc(so);
int
sbwait(struct sockbuf *sb)
{
- int error = 0, lr_saved;
+ int error = 0;
+ uintptr_t lr_saved;
struct socket *so = sb->sb_so;
lck_mtx_t *mutex_held;
struct timespec ts;
- lr_saved = (unsigned int) __builtin_return_address(0);
+ lr_saved = (uintptr_t) __builtin_return_address(0);
if (so->so_proto->pr_getlock != NULL)
mutex_held = (*so->so_proto->pr_getlock)(so, 0);
* ENOBUFS
*/
int
-soreserve(struct socket *so, u_long sndcc, u_long rcvcc)
+soreserve(struct socket *so, u_int32_t sndcc, u_int32_t rcvcc)
{
if (sbreserve(&so->so_snd, sndcc) == 0)
* if buffering efficiency is near the normal case.
*/
int
-sbreserve(struct sockbuf *sb, u_long cc)
+sbreserve(struct sockbuf *sb, u_int32_t cc)
{
if ((u_quad_t)cc > (u_quad_t)sb_max * MCLBYTES / (MSIZE + MCLBYTES))
return (0);
{
struct mbuf *m;
struct mbuf *n = 0;
- u_long len = 0, mbcnt = 0;
+ u_int32_t len = 0, mbcnt = 0;
lck_mtx_t *mutex_held;
if (sb->sb_so->so_proto->pr_getlock != NULL)
{
if (!(sb->sb_cc == 0 && sb->sb_mb == NULL && sb->sb_mbcnt == 0 &&
sb->sb_mbtail == NULL && sb->sb_lastrecord == NULL)) {
- panic("%s: sb %p so %p cc %ld mbcnt %ld mb %p mbtail %p "
+ panic("%s: sb %p so %p cc %d mbcnt %d mb %p mbtail %p "
"lastrecord %p\n", where, sb, sb->sb_so, sb->sb_cc,
sb->sb_mbcnt, sb->sb_mb, sb->sb_mbtail, sb->sb_lastrecord);
/* NOTREACHED */
}
int
-pru_control_notsupp(__unused struct socket *so, __unused u_long cmd,
+pru_control_notsupp(__unused struct socket *so, __unused u_long cmd,
__unused caddr_t data, __unused struct ifnet *ifp, __unused struct proc *p)
{
return (EOPNOTSUPP);
* How much space is there in a socket buffer (so->so_snd or so->so_rcv)?
* This is problematical if the fields are unsigned, as the space might
* still be negative (cc > hiwat or mbcnt > mbmax). Should detect
- * overflow and return 0. Should use "lmin" but it doesn't exist now.
+ * overflow and return 0.
*/
-long
+int
sbspace(struct sockbuf *sb)
{
- return ((long)imin((int)(sb->sb_hiwat - sb->sb_cc),
- (int)(sb->sb_mbmax - sb->sb_mbcnt)));
+ int space =
+ imin((int)(sb->sb_hiwat - sb->sb_cc),
+ (int)(sb->sb_mbmax - sb->sb_mbcnt));
+ if (space < 0)
+ space = 0;
+
+ return space;
}
/* do we have to send all at once on a socket? */
int
sowriteable(struct socket *so)
{
- return ((sbspace(&(so)->so_snd) >= (long)(so)->so_snd.sb_lowat &&
+ return ((sbspace(&(so)->so_snd) >= (so)->so_snd.sb_lowat &&
((so->so_state&SS_ISCONNECTED) ||
(so->so_proto->pr_flags&PR_CONNREQUIRED) == 0)) ||
(so->so_state & SS_CANTSENDMORE) ||
sb->sb_mbcnt += m->m_ext.ext_size;
cnt += m->m_ext.ext_size / MSIZE ;
}
- OSAddAtomic(cnt, (SInt32*)&total_mb_cnt);
+ OSAddAtomic(cnt, &total_mb_cnt);
}
/* adjust counters in sb reflecting freeing of m */
sb->sb_mbcnt -= m->m_ext.ext_size;
cnt -= m->m_ext.ext_size / MSIZE ;
}
- OSAddAtomic(cnt, (SInt32*)&total_mb_cnt);
+ OSAddAtomic(cnt, &total_mb_cnt);
}
/*
sbunlock(struct sockbuf *sb, int keeplocked)
{
struct socket *so = sb->sb_so;
- int lr_saved;
+ void *lr_saved;
lck_mtx_t *mutex_held;
- lr_saved = (unsigned int) __builtin_return_address(0);
+ lr_saved = __builtin_return_address(0);
sb->sb_flags &= ~SB_LOCK;
if (sb->sb_flags & SB_WANT) {
sb->sb_flags &= ~SB_WANT;
- if (so->so_usecount < 0)
- panic("sbunlock: b4 wakeup so=%p ref=%d lr=%x "
- "sb_flags=%x\n", sb->sb_so, so->so_usecount,
- lr_saved, sb->sb_flags);
-
+ if (so->so_usecount < 0) {
+ panic("sbunlock: b4 wakeup so=%p ref=%d lr=%p "
+ "sb_flags=%x lrh= %s\n", sb->sb_so, so->so_usecount,
+ lr_saved, sb->sb_flags, solockhistory_nr(so));
+ /* NOTREACHED */
+ }
wakeup((caddr_t)&(sb)->sb_flags);
}
if (keeplocked == 0) { /* unlock on exit */
- if (so->so_proto->pr_getlock != NULL)
+ if (so->so_proto->pr_getlock != NULL)
mutex_held = (*so->so_proto->pr_getlock)(so, 0);
- else
+ else
mutex_held = so->so_proto->pr_domain->dom_mtx;
-
+
lck_mtx_assert(mutex_held, LCK_MTX_ASSERT_OWNED);
so->so_usecount--;
if (so->so_usecount < 0)
- panic("sbunlock: unlock on exit so=%p ref=%d lr=%x "
- "sb_flags=%x\n", so, so->so_usecount, lr_saved,
- sb->sb_flags);
- so->unlock_lr[so->next_unlock_lr] = (u_int32_t)lr_saved;
+ panic("sbunlock: unlock on exit so=%p ref=%d lr=%p "
+ "sb_flags=%x lrh= %s\n", so, so->so_usecount, lr_saved,
+ sb->sb_flags, solockhistory_nr(so));
+ so->unlock_lr[so->next_unlock_lr] = lr_saved;
so->next_unlock_lr = (so->next_unlock_lr+1) % SO_LCKDBG_MAX;
lck_mtx_unlock(mutex_held);
}
sotoxsocket(struct socket *so, struct xsocket *xso)
{
xso->xso_len = sizeof (*xso);
- xso->xso_so = so;
+ xso->xso_so = (_XSOCKET_PTR(struct socket *))(uintptr_t)so;
xso->so_type = so->so_type;
xso->so_options = so->so_options;
xso->so_linger = so->so_linger;
xso->so_state = so->so_state;
- xso->so_pcb = so->so_pcb;
+ xso->so_pcb = (_XSOCKET_PTR(caddr_t))(uintptr_t)so->so_pcb;
if (so->so_proto) {
xso->xso_protocol = so->so_proto->pr_protocol;
xso->xso_family = so->so_proto->pr_domain->dom_family;
xso->so_uid = so->so_uid;
}
+
+#if !CONFIG_EMBEDDED
+
+void
+sotoxsocket64(struct socket *so, struct xsocket64 *xso)
+{
+ xso->xso_len = sizeof (*xso);
+ xso->xso_so = (u_int64_t)(uintptr_t)so;
+ xso->so_type = so->so_type;
+ xso->so_options = so->so_options;
+ xso->so_linger = so->so_linger;
+ xso->so_state = so->so_state;
+ xso->so_pcb = (u_int64_t)(uintptr_t)so->so_pcb;
+ if (so->so_proto) {
+ xso->xso_protocol = so->so_proto->pr_protocol;
+ xso->xso_family = so->so_proto->pr_domain->dom_family;
+ } else {
+ xso->xso_protocol = xso->xso_family = 0;
+ }
+ xso->so_qlen = so->so_qlen;
+ xso->so_incqlen = so->so_incqlen;
+ xso->so_qlimit = so->so_qlimit;
+ xso->so_timeo = so->so_timeo;
+ xso->so_error = so->so_error;
+ xso->so_pgid = so->so_pgid;
+ xso->so_oobmark = so->so_oobmark;
+ sbtoxsockbuf(&so->so_snd, &xso->so_snd);
+ sbtoxsockbuf(&so->so_rcv, &xso->so_rcv);
+ xso->so_uid = so->so_uid;
+}
+
+#endif /* !CONFIG_EMBEDDED */
+
/*
* This does the same for sockbufs. Note that the xsockbuf structure,
* since it is always embedded in a socket, does not include a self
xsb->sb_mbmax = sb->sb_mbmax;
xsb->sb_lowat = sb->sb_lowat;
xsb->sb_flags = sb->sb_flags;
- xsb->sb_timeo = (u_long)
+ xsb->sb_timeo = (short)
(sb->sb_timeo.tv_sec * hz) + sb->sb_timeo.tv_usec / tick;
if (xsb->sb_timeo == 0 && sb->sb_timeo.tv_usec != 0)
xsb->sb_timeo = 1;
}
+int
+soisbackground(struct socket *so)
+{
+ return (so->so_traffic_mgt_flags & TRAFFIC_MGT_SO_BACKGROUND);
+}
+
+#if PKT_PRIORITY
+#define _MIN_NXT_CMSGHDR_PTR(cmsg) \
+ ((char *)(cmsg) + \
+ __DARWIN_ALIGN32((__uint32_t)(cmsg)->cmsg_len) + \
+ __DARWIN_ALIGN32(sizeof(struct cmsghdr)))
+
+#define M_FIRST_CMSGHDR(m) \
+ ((char *)(m) != (char *)0L && (size_t)(m)->m_len >= sizeof(struct cmsghdr) && \
+ (socklen_t)(m)->m_len >= __DARWIN_ALIGN32(((struct cmsghdr *)(m)->m_data)->cmsg_len) ?\
+ (struct cmsghdr *)(m)->m_data : \
+ (struct cmsghdr *)0L)
+
+#define M_NXT_CMSGHDR(m, cmsg) \
+ ((char *)(cmsg) == (char *)0L ? M_FIRST_CMSGHDR(m) : \
+ _MIN_NXT_CMSGHDR_PTR(cmsg) > ((char *)(m)->m_data) + (m)->m_len || \
+ _MIN_NXT_CMSGHDR_PTR(cmsg) < (char *)(m)->m_data ? \
+ (struct cmsghdr *)0L /* NULL */ : \
+ (struct cmsghdr *)((unsigned char *)(cmsg) + \
+ __DARWIN_ALIGN32((__uint32_t)(cmsg)->cmsg_len)))
+#endif /* PKT_PRIORITY */
+
+__private_extern__ int
+mbuf_traffic_class_from_control(struct mbuf *control)
+{
+#if !PKT_PRIORITY
+#pragma unused(control)
+ return MBUF_TC_NONE;
+#else /* PKT_PRIORITY */
+ struct cmsghdr *cm;
+
+ for (cm = M_FIRST_CMSGHDR(control); cm; cm = M_NXT_CMSGHDR(control, cm)) {
+ int tc;
+
+ if (cm->cmsg_len < sizeof(struct cmsghdr))
+ break;
+
+ if (cm->cmsg_level != SOL_SOCKET || cm->cmsg_type != SO_TRAFFIC_CLASS)
+ continue;
+ if (cm->cmsg_len != CMSG_LEN(sizeof(int)))
+ continue;
+
+ tc = *(int *)CMSG_DATA(cm);
+
+ switch (tc) {
+ case SO_TC_BE:
+ return MBUF_TC_BE;
+ case SO_TC_BK:
+ return MBUF_TC_BK;
+ case SO_TC_VI:
+ return MBUF_TC_VI;
+ case SO_TC_VO:
+ return MBUF_TC_VO;
+ default:
+ break;
+ }
+ }
+
+ return MBUF_TC_NONE;
+#endif /* PKT_PRIORITY */
+}
+
/*
* Here is the definition of some of the basic objects in the kern.ipc
* branch of the MIB.
*/
SYSCTL_NODE(_kern, KERN_IPC, ipc, CTLFLAG_RW|CTLFLAG_LOCKED, 0, "IPC");
-/* This takes the place of kern.maxsockbuf, which moved to kern.ipc. */
-static int dummy;
-SYSCTL_INT(_kern, KERN_DUMMY, dummy, CTLFLAG_RW, &dummy, 0, "");
+/* Check that the maximum socket buffer size is within a range */
+
+static int
+sysctl_sb_max(__unused struct sysctl_oid *oidp, __unused void *arg1,
+ __unused int arg2, struct sysctl_req *req)
+{
+ u_int32_t new_value;
+ int changed = 0;
+ int error = sysctl_io_number(req, sb_max, sizeof(u_int32_t), &new_value,
+ &changed);
+ if (!error && changed) {
+ if (new_value > LOW_SB_MAX &&
+ new_value <= high_sb_max ) {
+ sb_max = new_value;
+ } else {
+ error = ERANGE;
+ }
+ }
+ return error;
+}
+
+SYSCTL_PROC(_kern_ipc, KIPC_MAXSOCKBUF, maxsockbuf, CTLTYPE_INT | CTLFLAG_RW,
+ &sb_max, 0, &sysctl_sb_max, "IU", "Maximum socket buffer size");
-SYSCTL_INT(_kern_ipc, KIPC_MAXSOCKBUF, maxsockbuf, CTLFLAG_RW,
- &sb_max, 0, "Maximum socket buffer size");
SYSCTL_INT(_kern_ipc, OID_AUTO, maxsockets, CTLFLAG_RD,
&maxsockets, 0, "Maximum number of sockets avaliable");
SYSCTL_INT(_kern_ipc, KIPC_SOCKBUF_WASTE, sockbuf_waste_factor, CTLFLAG_RW,