]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/kern/kpi_socket.c
xnu-3789.70.16.tar.gz
[apple/xnu.git] / bsd / kern / kpi_socket.c
index 1db81b353be1396878f06244619dd3d3c5db398e..2f1b1d96a8af12006babef4a89d17f69d654b35c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003-2012 Apple Inc. All rights reserved.
+ * Copyright (c) 2003-2016 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  *
 #include <sys/protosw.h>
 #include <sys/domain.h>
 #include <sys/mbuf.h>
+#include <sys/mcache.h>
 #include <sys/fcntl.h>
 #include <sys/filio.h>
 #include <sys/uio_internal.h>
-#include <kern/lock.h>
+#include <kern/locks.h>
 #include <netinet/in.h>
 #include <libkern/OSAtomic.h>
 
@@ -73,6 +74,7 @@ sock_accept(socket_t sock, struct sockaddr *from, int fromlen, int flags,
                socket_unlock(sock, 1);
                return (ENOTSUP);
        }
+check_again:
        if (((flags & MSG_DONTWAIT) != 0 || (sock->so_state & SS_NBIO) != 0) &&
            sock->so_comp.tqh_first == NULL) {
                socket_unlock(sock, 1);
@@ -106,10 +108,19 @@ sock_accept(socket_t sock, struct sockaddr *from, int fromlen, int flags,
                return (error);
        }
 
+       so_acquire_accept_list(sock, NULL);
+       if (TAILQ_EMPTY(&sock->so_comp)) {
+               so_release_accept_list(sock);
+               goto check_again;
+       }
        new_so = TAILQ_FIRST(&sock->so_comp);
        TAILQ_REMOVE(&sock->so_comp, new_so, so_list);
+       new_so->so_state &= ~SS_COMP;
+       new_so->so_head = NULL;
        sock->so_qlen--;
 
+       so_release_accept_list(sock);
+
        /*
         * Pass the pre-accepted socket to any interested socket filter(s).
         * Upon failure, the socket would have been closed by the callee.
@@ -122,7 +133,7 @@ sock_accept(socket_t sock, struct sockaddr *from, int fromlen, int flags,
                 * again once we're done with the filter(s).
                 */
                socket_unlock(sock, 0);
-               if ((error = soacceptfilter(new_so)) != 0) {
+               if ((error = soacceptfilter(new_so, sock)) != 0) {
                        /* Drop reference on listening socket */
                        sodereference(sock);
                        return (error);
@@ -136,8 +147,6 @@ sock_accept(socket_t sock, struct sockaddr *from, int fromlen, int flags,
                socket_lock(new_so, 1);
        }
 
-       new_so->so_state &= ~SS_COMP;
-       new_so->so_head = NULL;
        (void) soacceptlock(new_so, &sa, 0);
 
        socket_unlock(sock, 1); /* release the head */
@@ -495,7 +504,7 @@ so_tc_from_dscp(u_int8_t dscp)
        else if (dscp >= 0x20 && dscp <= 0x2f)
                tc = SO_TC_VI;
        else if (dscp >= 0x08 && dscp <= 0x17)
-               tc = SO_TC_BK;
+               tc = SO_TC_BK_SYS;
        else
                tc = SO_TC_BE;
 
@@ -950,11 +959,18 @@ sock_release(socket_t sock)
                    __func__, sock->so_retaincnt, sock);
                /* NOTREACHED */
        }
-       if ((sock->so_retaincnt == 0) && (sock->so_usecount == 2)) {
+       /*
+        * Check SS_NOFDREF in case a close happened as sock_retain()
+        * was grabbing the lock
+        */
+       if ((sock->so_retaincnt == 0) && (sock->so_usecount == 2) &&
+           (!(sock->so_state & SS_NOFDREF) ||
+           (sock->so_flags & SOF_MP_SUBFLOW))) {
                /* close socket only if the FD is not holding it */
                soclose_locked(sock);
        } else {
                /* remove extra reference holding the socket */
+               VERIFY(sock->so_usecount > 1);
                sock->so_usecount--;
        }
        socket_unlock(sock, 1);
@@ -1038,14 +1054,22 @@ sock_set_tcp_stream_priority(socket_t sock)
  * Caller must have ensured socket is valid and won't be going away.
  */
 void
-socket_set_traffic_mgt_flags_locked(socket_t sock, u_int32_t flags)
+socket_set_traffic_mgt_flags_locked(socket_t sock, u_int8_t flags)
 {
-       (void) OSBitOrAtomic(flags, &sock->so_traffic_mgt_flags);
+       u_int32_t soflags1 = 0;
+       
+       if ((flags & TRAFFIC_MGT_SO_BACKGROUND))
+               soflags1 |= SOF1_TRAFFIC_MGT_SO_BACKGROUND;
+       if ((flags & TRAFFIC_MGT_TCP_RECVBG))
+               soflags1 |= SOF1_TRAFFIC_MGT_TCP_RECVBG;
+       
+       (void) OSBitOrAtomic(soflags1, &sock->so_flags1);
+
        sock_set_tcp_stream_priority(sock);
 }
 
 void
-socket_set_traffic_mgt_flags(socket_t sock, u_int32_t flags)
+socket_set_traffic_mgt_flags(socket_t sock, u_int8_t flags)
 {
        socket_lock(sock, 1);
        socket_set_traffic_mgt_flags_locked(sock, flags);
@@ -1056,14 +1080,22 @@ socket_set_traffic_mgt_flags(socket_t sock, u_int32_t flags)
  * Caller must have ensured socket is valid and won't be going away.
  */
 void
-socket_clear_traffic_mgt_flags_locked(socket_t sock, u_int32_t flags)
+socket_clear_traffic_mgt_flags_locked(socket_t sock, u_int8_t flags)
 {
-       (void) OSBitAndAtomic(~flags, &sock->so_traffic_mgt_flags);
+       u_int32_t soflags1 = 0;
+
+       if ((flags & TRAFFIC_MGT_SO_BACKGROUND))
+               soflags1 |= SOF1_TRAFFIC_MGT_SO_BACKGROUND;
+       if ((flags & TRAFFIC_MGT_TCP_RECVBG))
+               soflags1 |= SOF1_TRAFFIC_MGT_TCP_RECVBG;
+       
+       (void) OSBitAndAtomic(~soflags1, &sock->so_flags1);
+
        sock_set_tcp_stream_priority(sock);
 }
 
 void
-socket_clear_traffic_mgt_flags(socket_t sock, u_int32_t flags)
+socket_clear_traffic_mgt_flags(socket_t sock, u_int8_t flags)
 {
        socket_lock(sock, 1);
        socket_clear_traffic_mgt_flags_locked(sock, flags);
@@ -1183,7 +1215,7 @@ sock_catchevents(socket_t sock, sock_evupcall ecallback, void *econtext,
                sock->so_eventarg = econtext;
                sock->so_eventmask = emask;
        } else {
-               sock->so_event = NULL;
+               sock->so_event = sonullevent;
                sock->so_eventarg = NULL;
                sock->so_eventmask = 0;
        }
@@ -1191,3 +1223,12 @@ sock_catchevents(socket_t sock, sock_evupcall ecallback, void *econtext,
 
        return (0);
 }
+
+/*
+ * Returns true whether or not a socket belongs to the kernel.
+ */
+int
+sock_iskernel(socket_t so)
+{
+       return (so && so->last_pid == 0);
+}