]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/kern/uipc_socket2.c
xnu-1504.15.3.tar.gz
[apple/xnu.git] / bsd / kern / uipc_socket2.c
index 41a606ca39fa35818172d8411a845b334cbd7452..a6b2af000456afd60dc3d12b380c2138dbd7b813 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998-2007 Apple Inc. All rights reserved.
+ * Copyright (c) 1998-2010 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  * 
@@ -113,9 +113,15 @@ static int sbappendcontrol_internal(struct sockbuf *, struct mbuf *,
 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;
@@ -260,7 +266,7 @@ sonewconn_internal(struct socket *head, int connstatus)
        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);
@@ -279,7 +285,13 @@ sonewconn_internal(struct socket *head, int connstatus)
        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;
@@ -294,6 +306,14 @@ sonewconn_internal(struct socket *head, int connstatus)
        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);
@@ -411,12 +431,13 @@ socantrcvmore(struct socket *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);
@@ -564,7 +585,7 @@ sowakeup(struct socket *so, struct sockbuf *sb)
  *             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)
@@ -593,7 +614,7 @@ bad:
  * 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);
@@ -724,7 +745,7 @@ sbcheck(struct sockbuf *sb)
 {
        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)
@@ -1215,7 +1236,7 @@ sb_empty_assert(struct sockbuf *sb, const char *where)
 {
        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 */
@@ -1436,7 +1457,7 @@ pru_connect2_notsupp(__unused struct socket *so1, __unused struct socket *so2)
 }
 
 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);
@@ -1570,13 +1591,18 @@ sb_notify(struct sockbuf *sb)
  * 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? */
@@ -1600,7 +1626,7 @@ soreadable(struct socket *so)
 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) ||
@@ -1623,7 +1649,7 @@ sballoc(struct sockbuf *sb, struct mbuf *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);
 }
 
 /* adjust counters in sb reflecting freeing of m */
@@ -1640,7 +1666,7 @@ sbfree(struct sockbuf *sb, struct mbuf *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);
 }
 
 /*
@@ -1670,36 +1696,37 @@ void
 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);
        }
@@ -1747,12 +1774,12 @@ void
 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;
@@ -1771,6 +1798,39 @@ sotoxsocket(struct socket *so, struct xsocket *xso)
        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
@@ -1786,24 +1846,109 @@ sbtoxsockbuf(struct sockbuf *sb, struct xsockbuf *xsb)
        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,