The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/bsd/kern/kpi_socket.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (c) 2003-2011 Apple Inc. All rights reserved.
    3  *
    4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
    5  * 
    6  * This file contains Original Code and/or Modifications of Original Code
    7  * as defined in and that are subject to the Apple Public Source License
    8  * Version 2.0 (the 'License'). You may not use this file except in
    9  * compliance with the License. The rights granted to you under the License
   10  * may not be used to create, or enable the creation or redistribution of,
   11  * unlawful or unlicensed copies of an Apple operating system, or to
   12  * circumvent, violate, or enable the circumvention or violation of, any
   13  * terms of an Apple operating system software license agreement.
   14  * 
   15  * Please obtain a copy of the License at
   16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
   17  * 
   18  * The Original Code and all software distributed under the License are
   19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
   20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
   21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
   22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
   23  * Please see the License for the specific language governing rights and
   24  * limitations under the License.
   25  * 
   26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
   27  */
   28 
   29 #define __KPI__
   30 #include <sys/systm.h>
   31 #include <sys/kernel.h>
   32 #include <sys/types.h>
   33 #include <sys/socket.h>
   34 #include <sys/socketvar.h>
   35 #include <sys/param.h>
   36 #include <sys/proc.h>
   37 #include <sys/errno.h>
   38 #include <sys/malloc.h>
   39 #include <sys/protosw.h>
   40 #include <sys/domain.h>
   41 #include <sys/mbuf.h>
   42 #include <sys/fcntl.h>
   43 #include <sys/filio.h>
   44 #include <sys/uio_internal.h>
   45 #include <kern/lock.h>
   46 #include <netinet/in.h>
   47 #include <libkern/OSAtomic.h>
   48 
   49 extern int soclose_locked(struct socket *so);
   50 extern void soclose_wait_locked(struct socket *so);
   51 extern int so_isdstlocal(struct socket *so);
   52 
   53 errno_t sock_send_internal(
   54         socket_t                        sock,
   55         const struct msghdr     *msg,
   56         mbuf_t                          data,
   57         int                                     flags,
   58         size_t                          *sentlen);
   59 
   60 typedef void    (*so_upcall)(struct socket *, caddr_t , int );
   61 
   62 
   63 errno_t
   64 sock_accept(
   65         socket_t                sock,
   66         struct sockaddr *from,
   67         int                             fromlen,
   68         int                             flags,
   69         sock_upcall             callback,
   70         void*                   cookie,
   71         socket_t                *new_sock)
   72 {
   73         struct sockaddr *sa;
   74         struct socket *new_so;
   75         lck_mtx_t *mutex_held;
   76         int     dosocklock;
   77         errno_t error = 0;
   78         
   79         if (sock == NULL || new_sock == NULL) return EINVAL;
   80         socket_lock(sock, 1);
   81         if ((sock->so_options & SO_ACCEPTCONN) == 0) {
   82                 socket_unlock(sock, 1);
   83                 return EINVAL;
   84         }
   85         if ((flags & ~(MSG_DONTWAIT)) != 0) {
   86                 socket_unlock(sock, 1);
   87                 return ENOTSUP;
   88         }
   89         if (((flags & MSG_DONTWAIT) != 0 || (sock->so_state & SS_NBIO) != 0) &&
   90                 sock->so_comp.tqh_first == NULL) {
   91                 socket_unlock(sock, 1);
   92                 return EWOULDBLOCK;
   93         }
   94 
   95         if (sock->so_proto->pr_getlock != NULL)  {
   96                 mutex_held = (*sock->so_proto->pr_getlock)(sock, 0);
   97                 dosocklock = 1;
   98         }
   99         else {
  100                 mutex_held = sock->so_proto->pr_domain->dom_mtx;
  101                 dosocklock = 0;
  102         }
  103         
  104         while (TAILQ_EMPTY(&sock->so_comp) && sock->so_error == 0) {
  105                 if (sock->so_state & SS_CANTRCVMORE) {
  106                         sock->so_error = ECONNABORTED;
  107                         break;
  108                 }
  109                 error = msleep((caddr_t)&sock->so_timeo, mutex_held, PSOCK | PCATCH, "sock_accept", NULL);
  110                 if (error) {
  111                         socket_unlock(sock, 1);
  112                         return (error);
  113                 }
  114         }
  115         if (sock->so_error) {
  116                 error = sock->so_error;
  117                 sock->so_error = 0;
  118                 socket_unlock(sock, 1);
  119                 return (error);
  120         }
  121         
  122         new_so = TAILQ_FIRST(&sock->so_comp);
  123         TAILQ_REMOVE(&sock->so_comp, new_so, so_list);
  124         sock->so_qlen--;
  125 
  126         /*
  127          * Pass the pre-accepted socket to any interested socket filter(s).
  128          * Upon failure, the socket would have been closed by the callee.
  129          */
  130         if (new_so->so_filt != NULL) {
  131                 /*
  132                  * Temporarily drop the listening socket's lock before we
  133                  * hand off control over to the socket filter(s), but keep
  134                  * a reference so that it won't go away.  We'll grab it
  135                  * again once we're done with the filter(s).
  136                  */
  137                 socket_unlock(sock, 0);
  138                 if ((error = soacceptfilter(new_so)) != 0) {
  139                         /* Drop reference on listening socket */
  140                         sodereference(sock);
  141                         return (error);
  142                 }
  143                 socket_lock(sock, 0);
  144         }
  145 
  146         if (dosocklock) {
  147                 lck_mtx_assert(new_so->so_proto->pr_getlock(new_so, 0),
  148                                            LCK_MTX_ASSERT_NOTOWNED);
  149                 socket_lock(new_so, 1);
  150         }
  151         
  152         new_so->so_state &= ~SS_COMP;
  153         new_so->so_head = NULL;
  154         (void) soacceptlock(new_so, &sa, 0);
  155         
  156         socket_unlock(sock, 1); /* release the head */
  157 
  158         if (callback) {
  159                 new_so->so_upcall = (so_upcall) callback;
  160                 new_so->so_upcallarg = cookie;
  161                 new_so->so_rcv.sb_flags |= SB_UPCALL;
  162 #if CONFIG_SOWUPCALL
  163                 new_so->so_snd.sb_flags |= SB_UPCALL;
  164 #endif
  165         }
  166         
  167         if (sa && from)
  168         {
  169                 if (fromlen > sa->sa_len) fromlen = sa->sa_len;
  170                 memcpy(from, sa, fromlen);
  171         }
  172         if (sa) FREE(sa, M_SONAME);
  173 
  174         /*
  175          * If the socket has been marked as inactive by sosetdefunct(),
  176          * disallow further operations on it.
  177          */
  178         if (new_so->so_flags & SOF_DEFUNCT) {
  179                 (void) sodefunct(current_proc(), new_so,
  180                     SHUTDOWN_SOCKET_LEVEL_DISCONNECT_INTERNAL);
  181         }
  182         *new_sock = new_so;
  183         if (dosocklock) 
  184                 socket_unlock(new_so, 1);
  185         return error;
  186 }
  187 
  188 errno_t
  189 sock_bind(
  190         socket_t                                sock,
  191         const struct sockaddr   *to)
  192 {
  193         int     error = 0;
  194         struct sockaddr *sa = NULL;
  195         struct sockaddr_storage ss;
  196         boolean_t want_free = TRUE;
  197 
  198         if (sock == NULL || to == NULL) 
  199                 return EINVAL;
  200         
  201         if (to->sa_len > sizeof(ss)) {
  202                 MALLOC(sa, struct sockaddr *, to->sa_len, M_SONAME, M_WAITOK);
  203                 if (sa == NULL)
  204                         return ENOBUFS;
  205         } else {
  206                 sa = (struct sockaddr *)&ss;
  207                 want_free = FALSE;
  208         }
  209         memcpy(sa, to, to->sa_len);
  210 
  211         error = sobind(sock, sa);
  212         
  213         if (sa != NULL && want_free == TRUE)
  214                 FREE(sa, M_SONAME);     
  215 
  216         return error;
  217 }
  218 
  219 errno_t
  220 sock_connect(
  221         socket_t                                sock,
  222         const struct sockaddr   *to,
  223         int                                             flags)
  224 {
  225         int     error = 0;
  226         lck_mtx_t *mutex_held;
  227         struct sockaddr *sa = NULL;
  228         struct sockaddr_storage ss;
  229         boolean_t want_free = TRUE;
  230         
  231         if (sock == NULL || to == NULL) return EINVAL;
  232         
  233         if (to->sa_len > sizeof(ss)) {
  234                 MALLOC(sa, struct sockaddr *, to->sa_len, M_SONAME,
  235                         (flags & MSG_DONTWAIT) ? M_NOWAIT : M_WAITOK);
  236                 if (sa == NULL)
  237                         return ENOBUFS;
  238         } else {
  239                 sa = (struct sockaddr *)&ss;
  240                 want_free = FALSE;
  241         }
  242         memcpy(sa, to, to->sa_len);
  243 
  244         socket_lock(sock, 1);
  245 
  246         if ((sock->so_state & SS_ISCONNECTING) &&
  247                 ((sock->so_state & SS_NBIO) != 0 ||
  248                  (flags & MSG_DONTWAIT) != 0)) {
  249                 error = EALREADY;
  250                 goto out;
  251         }
  252         error = soconnectlock(sock, sa, 0);
  253         if (!error) {
  254                 if ((sock->so_state & SS_ISCONNECTING) &&
  255                         ((sock->so_state & SS_NBIO) != 0 || (flags & MSG_DONTWAIT) != 0)) {
  256                         error = EINPROGRESS;
  257                         goto out;
  258                 }
  259                 
  260                 if (sock->so_proto->pr_getlock != NULL)  
  261                         mutex_held = (*sock->so_proto->pr_getlock)(sock, 0);
  262                 else 
  263                         mutex_held = sock->so_proto->pr_domain->dom_mtx;
  264 
  265                 while ((sock->so_state & SS_ISCONNECTING) && sock->so_error == 0) {
  266                         error = msleep((caddr_t)&sock->so_timeo, mutex_held, PSOCK | PCATCH,
  267                                 "sock_connect", NULL);
  268                         if (error)
  269                                 break;
  270                 }
  271                 
  272                 if (error == 0) {
  273                         error = sock->so_error;
  274                         sock->so_error = 0;
  275                 }
  276         }
  277         else {
  278                 sock->so_state &= ~SS_ISCONNECTING;
  279         }
  280 out:
  281         socket_unlock(sock, 1);
  282 
  283         if (sa != NULL && want_free == TRUE)
  284                 FREE(sa, M_SONAME);
  285                 
  286         return error;
  287 }
  288 
  289 errno_t
  290 sock_connectwait(
  291         socket_t                                sock,
  292         const struct timeval    *tv)
  293 {
  294         lck_mtx_t * mutex_held;
  295         errno_t retval = 0;
  296         struct timespec ts;
  297         
  298         socket_lock(sock, 1);
  299         
  300         // Check if we're already connected or if we've already errored out
  301         if ((sock->so_state & SS_ISCONNECTING) == 0 || sock->so_error) {
  302                 if (sock->so_error) {
  303                         retval = sock->so_error;
  304                         sock->so_error = 0;
  305                 }
  306                 else {
  307                         if ((sock->so_state & SS_ISCONNECTED) != 0)
  308                                 retval = 0;
  309                         else
  310                                 retval = EINVAL;
  311                 }
  312                 goto done;
  313         }
  314         
  315         // copied translation from timeval to hertz from SO_RCVTIMEO handling
  316         if (tv->tv_sec < 0 || tv->tv_sec > SHRT_MAX / hz ||
  317                 tv->tv_usec < 0 || tv->tv_usec >= 1000000) {
  318                 retval = EDOM;
  319                 goto done;
  320         }
  321         
  322         ts.tv_sec = tv->tv_sec;
  323         ts.tv_nsec = (tv->tv_usec * NSEC_PER_USEC);
  324         if ( (ts.tv_sec + (ts.tv_nsec/NSEC_PER_SEC))/100  >  SHRT_MAX)  {
  325                 retval = EDOM;
  326                 goto done;
  327         }
  328         
  329         if (sock->so_proto->pr_getlock != NULL)  
  330                 mutex_held = (*sock->so_proto->pr_getlock)(sock, 0);
  331         else 
  332                 mutex_held = sock->so_proto->pr_domain->dom_mtx;
  333 
  334         msleep((caddr_t)&sock->so_timeo, mutex_held, PSOCK, "sock_connectwait", &ts);
  335         
  336         // Check if we're still waiting to connect
  337         if ((sock->so_state & SS_ISCONNECTING) && sock->so_error == 0) {
  338                 retval = EINPROGRESS;
  339                 goto done;
  340         }
  341         
  342         if (sock->so_error) {
  343                 retval = sock->so_error;
  344                 sock->so_error = 0;
  345         }
  346         
  347 done:
  348         socket_unlock(sock, 1);
  349         return retval;
  350 }
  351 
  352 errno_t
  353 sock_nointerrupt(
  354         socket_t        sock,
  355         int                     on)
  356 {
  357         socket_lock(sock, 1);
  358 
  359         if (on) {
  360                 sock->so_rcv.sb_flags |= SB_NOINTR; // This isn't safe
  361                 sock->so_snd.sb_flags |= SB_NOINTR; // This isn't safe
  362         }
  363         else {
  364                 sock->so_rcv.sb_flags &= ~SB_NOINTR; // This isn't safe
  365                 sock->so_snd.sb_flags &= ~SB_NOINTR; // This isn't safe
  366         }
  367 
  368         socket_unlock(sock, 1);
  369 
  370         return 0;
  371 }
  372 
  373 errno_t
  374 sock_getpeername(socket_t sock, struct sockaddr *peername, int peernamelen)
  375 {
  376         int error;
  377         struct sockaddr *sa = NULL;
  378 
  379         if (sock == NULL || peername == NULL || peernamelen < 0)
  380                 return (EINVAL);
  381 
  382         socket_lock(sock, 1);
  383         if (!(sock->so_state & (SS_ISCONNECTED|SS_ISCONFIRMING))) {
  384                 socket_unlock(sock, 1);
  385                 return (ENOTCONN);
  386         }
  387         error = sogetaddr_locked(sock, &sa, 1);
  388         socket_unlock(sock, 1);
  389         if (error == 0) {
  390                 if (peernamelen > sa->sa_len)
  391                         peernamelen = sa->sa_len;
  392                 memcpy(peername, sa, peernamelen);
  393                 FREE(sa, M_SONAME);
  394         }
  395         return (error);
  396 }
  397 
  398 errno_t
  399 sock_getsockname(socket_t sock, struct sockaddr *sockname, int socknamelen)
  400 {
  401         int error;
  402         struct sockaddr *sa = NULL;
  403 
  404         if (sock == NULL || sockname == NULL || socknamelen < 0)
  405                 return (EINVAL);
  406 
  407         socket_lock(sock, 1);
  408         error = sogetaddr_locked(sock, &sa, 0);
  409         socket_unlock(sock, 1);
  410         if (error == 0) {
  411                 if (socknamelen > sa->sa_len)
  412                         socknamelen = sa->sa_len;
  413                 memcpy(sockname, sa, socknamelen);
  414                 FREE(sa, M_SONAME);
  415         }
  416         return (error);
  417 }
  418 
  419 __private_extern__ int
  420 sogetaddr_locked(struct socket *so, struct sockaddr **psa, int peer)
  421 {
  422         int error;
  423 
  424         if (so == NULL || psa == NULL)
  425                 return (EINVAL);
  426 
  427         *psa = NULL;
  428         error = peer ? so->so_proto->pr_usrreqs->pru_peeraddr(so, psa) :
  429             so->so_proto->pr_usrreqs->pru_sockaddr(so, psa);
  430 
  431         if (error == 0 && *psa == NULL) {
  432                 error = ENOMEM;
  433         } else if (error != 0 && *psa != NULL) {
  434                 FREE(*psa, M_SONAME);
  435                 *psa = NULL;
  436         }
  437         return (error);
  438 }
  439 
  440 errno_t
  441 sock_getaddr(socket_t sock, struct sockaddr **psa, int peer)
  442 {
  443         int error;
  444 
  445         if (sock == NULL || psa == NULL)
  446                 return (EINVAL);
  447 
  448         socket_lock(sock, 1);
  449         error = sogetaddr_locked(sock, psa, peer);
  450         socket_unlock(sock, 1);
  451         
  452         return (error);
  453 }
  454 
  455 void
  456 sock_freeaddr(struct sockaddr *sa)
  457 {
  458         if (sa != NULL)
  459                 FREE(sa, M_SONAME);
  460 }
  461 
  462 errno_t
  463 sock_getsockopt(
  464         socket_t        sock,
  465         int                     level,
  466         int                     optname,
  467         void            *optval,
  468         int                     *optlen)
  469 {
  470         int                             error = 0;
  471         struct sockopt  sopt;
  472         
  473         if (sock == NULL || optval == NULL || optlen == NULL) return EINVAL;
  474         sopt.sopt_dir = SOPT_GET;
  475         sopt.sopt_level = level;
  476         sopt.sopt_name = optname;
  477         sopt.sopt_val = CAST_USER_ADDR_T(optval); 
  478         sopt.sopt_valsize = *optlen;
  479         sopt.sopt_p = kernproc;
  480         error = sogetopt(sock, &sopt); /* will lock socket */
  481         if (error == 0) *optlen = sopt.sopt_valsize;
  482         return error;
  483 }
  484 
  485 errno_t
  486 sock_ioctl(
  487         socket_t        sock,
  488         unsigned long request,
  489         void *argp)
  490 {
  491         return soioctl(sock, request, argp, kernproc); /* will lock socket */
  492 }
  493 
  494 errno_t
  495 sock_setsockopt(
  496         socket_t        sock,
  497         int                     level,
  498         int                     optname,
  499         const void      *optval,
  500         int                     optlen)
  501 {
  502         struct sockopt  sopt;
  503         
  504         if (sock == NULL || optval == NULL) return EINVAL;
  505         sopt.sopt_dir = SOPT_SET;
  506         sopt.sopt_level = level;
  507         sopt.sopt_name = optname;
  508         sopt.sopt_val = CAST_USER_ADDR_T(optval);
  509         sopt.sopt_valsize = optlen;
  510         sopt.sopt_p = kernproc;
  511         return sosetopt(sock, &sopt); /* will lock socket */
  512 }
  513 
  514 /*
  515  * This follows the recommended mappings between DSCP code points and WMM access classes
  516  */
  517 static u_int8_t so_tc_from_dscp(u_int8_t dscp);
  518 static u_int8_t
  519 so_tc_from_dscp(u_int8_t dscp)
  520 {
  521         u_int8_t tc;
  522 
  523         if (dscp >= 0x30 && dscp <= 0x3f)
  524                 tc = SO_TC_VO;
  525         else if (dscp >= 0x20 && dscp <= 0x2f)
  526                 tc = SO_TC_VI;
  527         else if (dscp >= 0x08 && dscp <= 0x17)
  528                 tc = SO_TC_BK;
  529         else
  530                 tc = SO_TC_BE;
  531 
  532         return tc;
  533 }
  534 
  535 errno_t
  536 sock_settclassopt(
  537         socket_t        sock,
  538         const void      *optval,
  539         size_t          optlen) {
  540 
  541         errno_t error = 0;
  542         struct sockopt sopt;
  543         int sotc;
  544 
  545         if (sock == NULL || optval == NULL || optlen != sizeof(int)) return EINVAL;
  546 
  547         socket_lock(sock, 1);
  548         if (!(sock->so_state & SS_ISCONNECTED)) {
  549                 /* If the socket is not connected then we don't know 
  550                  * if the destination is on LAN  or not. Skip
  551                  * setting traffic class in this case
  552                  */
  553                 error = ENOTCONN;
  554                 goto out;
  555         }
  556 
  557         if (sock->so_proto == NULL || sock->so_proto->pr_domain == NULL || sock->so_pcb == NULL) {
  558                 error = EINVAL;
  559                 goto out;
  560         }
  561 
  562         /*
  563          * Set the socket traffic class based on the passed DSCP code point
  564          * regardless of the scope of the destination
  565          */
  566         sotc = so_tc_from_dscp((*(const int *)optval) >> 2);
  567 
  568         sopt.sopt_dir = SOPT_SET;
  569         sopt.sopt_val = CAST_USER_ADDR_T(&sotc);
  570         sopt.sopt_valsize = sizeof(sotc);
  571         sopt.sopt_p = kernproc;
  572         sopt.sopt_level = SOL_SOCKET;
  573         sopt.sopt_name = SO_TRAFFIC_CLASS;
  574 
  575         socket_unlock(sock, 0);
  576         error = sosetopt(sock, &sopt);
  577         socket_lock(sock, 0);
  578 
  579         if (error != 0) {
  580                 printf("sock_settclassopt: sosetopt SO_TRAFFIC_CLASS failed %d\n", error);
  581                 goto out;
  582         }
  583 
  584         /* Check if the destination address is LAN or link local address.
  585          * We do not want to set traffic class bits if the destination
  586          * is not local 
  587          */ 
  588         if (!so_isdstlocal(sock)) {
  589                 goto out;
  590         }
  591 
  592         sopt.sopt_dir = SOPT_SET;
  593         sopt.sopt_val = CAST_USER_ADDR_T(optval);
  594         sopt.sopt_valsize = optlen;
  595         sopt.sopt_p = kernproc;
  596 
  597         switch (sock->so_proto->pr_domain->dom_family) {
  598         case AF_INET:
  599                 sopt.sopt_level = IPPROTO_IP;
  600                 sopt.sopt_name = IP_TOS;
  601                 break;
  602         case AF_INET6:
  603                 sopt.sopt_level = IPPROTO_IPV6;
  604                 sopt.sopt_name = IPV6_TCLASS;
  605                 break;
  606         default:
  607                 error = EINVAL;
  608                 goto out;
  609         }
  610         
  611         socket_unlock(sock, 1);
  612         return sosetopt(sock, &sopt);
  613 out:
  614         socket_unlock(sock, 1);
  615         return error;
  616 }
  617 
  618 errno_t
  619 sock_gettclassopt(
  620         socket_t        sock,
  621         void            *optval,
  622         size_t          *optlen) {
  623 
  624         errno_t         error = 0;
  625         struct sockopt  sopt;
  626         
  627         if (sock == NULL || optval == NULL || optlen == NULL) return EINVAL;
  628 
  629         sopt.sopt_dir = SOPT_GET;
  630         sopt.sopt_val = CAST_USER_ADDR_T(optval); 
  631         sopt.sopt_valsize = *optlen;
  632         sopt.sopt_p = kernproc;
  633 
  634         socket_lock(sock, 1);
  635         if (sock->so_proto == NULL || sock->so_proto->pr_domain == NULL) {
  636                 socket_unlock(sock, 1);
  637                 return EINVAL;
  638         }
  639 
  640         switch (sock->so_proto->pr_domain->dom_family) {
  641         case AF_INET:
  642                 sopt.sopt_level = IPPROTO_IP;
  643                 sopt.sopt_name = IP_TOS;
  644                 break;
  645         case AF_INET6:
  646                 sopt.sopt_level = IPPROTO_IPV6;
  647                 sopt.sopt_name = IPV6_TCLASS;
  648                 break;
  649         default:
  650                 socket_unlock(sock, 1);
  651                 return EINVAL;
  652 
  653         }
  654         socket_unlock(sock, 1);
  655         error = sogetopt(sock, &sopt); /* will lock socket */
  656         if (error == 0) *optlen = sopt.sopt_valsize;
  657         return error;
  658 }
  659 
  660 errno_t
  661 sock_listen(
  662         socket_t        sock,
  663         int                     backlog)
  664 {
  665         if (sock == NULL) return EINVAL;
  666         return solisten(sock, backlog); /* will lock socket */
  667 }
  668 
  669 static errno_t
  670 sock_receive_internal(
  671         socket_t                sock,
  672         struct msghdr           *msg,
  673         mbuf_t                  *data,
  674         int                     flags,
  675         size_t                  *recvdlen)
  676 {
  677         uio_t           auio;
  678         struct mbuf     *control = NULL;
  679         int                     error = 0;
  680         int                     length = 0;
  681         struct sockaddr *fromsa;
  682         char            uio_buf[ UIO_SIZEOF((msg != NULL) ? msg->msg_iovlen : 0) ];
  683         
  684         if (sock == NULL) return EINVAL;
  685         
  686         auio = uio_createwithbuffer(((msg != NULL) ? msg->msg_iovlen : 0), 
  687                                                                   0, UIO_SYSSPACE, UIO_READ, 
  688                                                                   &uio_buf[0], sizeof(uio_buf));
  689         if (msg && data == NULL) {
  690                 int i;
  691                 struct iovec *tempp = msg->msg_iov;
  692                 
  693                 for (i = 0; i < msg->msg_iovlen; i++) {
  694                         uio_addiov(auio, CAST_USER_ADDR_T((tempp + i)->iov_base), (tempp + i)->iov_len);
  695                 }
  696                 if (uio_resid(auio) < 0) return EINVAL;
  697         }
  698         else {
  699                 uio_setresid(auio, (uio_resid(auio) + *recvdlen));
  700         }
  701         length = uio_resid(auio);
  702         
  703         if (recvdlen)
  704                 *recvdlen = 0;
  705 
  706         /* let pru_soreceive handle the socket locking */       
  707         error = sock->so_proto->pr_usrreqs->pru_soreceive(sock, &fromsa, auio,
  708             data, (msg && msg->msg_control) ? &control : NULL, &flags);
  709         if (error) goto cleanup;
  710         
  711         if (recvdlen)
  712                 *recvdlen = length - uio_resid(auio);
  713         if (msg) {
  714                 msg->msg_flags = flags;
  715                 
  716                 if (msg->msg_name)
  717                 {
  718                         int salen;
  719                         salen = msg->msg_namelen;
  720                         if (msg->msg_namelen > 0 && fromsa != 0)
  721                         {
  722                                 salen = MIN(salen, fromsa->sa_len);
  723                                 memcpy(msg->msg_name, fromsa,
  724                                         msg->msg_namelen > fromsa->sa_len ? fromsa->sa_len :  msg->msg_namelen);
  725                         }
  726                 }
  727                 
  728                 if (msg->msg_control)
  729                 {
  730                         struct mbuf*    m = control;
  731                         u_char*                 ctlbuf = msg->msg_control;
  732                         int                             clen = msg->msg_controllen;
  733                         msg->msg_controllen = 0;
  734                         
  735                         while (m && clen > 0)
  736                         {
  737                                 unsigned int tocopy;
  738                                 if (clen >= m->m_len)
  739                                 {
  740                                         tocopy = m->m_len;
  741                                 }
  742                                 else
  743                                 {
  744                                         msg->msg_flags |= MSG_CTRUNC;
  745                                         tocopy = clen;
  746                                 }
  747                                 memcpy(ctlbuf, mtod(m, caddr_t), tocopy);
  748                                 ctlbuf += tocopy;
  749                                 clen -= tocopy;
  750                                 m = m->m_next;
  751                         }
  752                         msg->msg_controllen = (uintptr_t)ctlbuf - (uintptr_t)msg->msg_control;
  753                 }
  754         }
  755 
  756 cleanup:
  757         if (control) m_freem(control);
  758         if (fromsa) FREE(fromsa, M_SONAME);
  759         return error;
  760 }
  761 
  762 errno_t
  763 sock_receive(
  764         socket_t                sock,
  765         struct msghdr   *msg,
  766         int                             flags,
  767         size_t                  *recvdlen)
  768 {
  769         if ((msg == NULL) ||
  770                 (msg->msg_iovlen < 1) ||
  771                 (msg->msg_iov[0].iov_len == 0) ||
  772                 (msg->msg_iov[0].iov_base == NULL))
  773                 return EINVAL;
  774         return sock_receive_internal(sock, msg, NULL, flags, recvdlen);
  775 }
  776 
  777 errno_t
  778 sock_receivembuf(
  779         socket_t                sock,
  780         struct msghdr   *msg,
  781         mbuf_t                  *data,
  782         int                             flags,
  783         size_t                  *recvlen)
  784 {
  785         if (data == NULL || recvlen == 0 || *recvlen <= 0 || (msg &&
  786                 (msg->msg_iov != NULL || msg->msg_iovlen != 0)))
  787                 return EINVAL;
  788         return sock_receive_internal(sock, msg, data, flags, recvlen);
  789 }
  790 
  791 errno_t
  792 sock_send_internal(
  793         socket_t                        sock,
  794         const struct msghdr     *msg,
  795         mbuf_t                          data,
  796         int                                     flags,
  797         size_t                          *sentlen)
  798 {
  799         uio_t                   auio = NULL;
  800         struct mbuf             *control = NULL;
  801         int                             error = 0;
  802         int                             datalen = 0;
  803         char                    uio_buf[ UIO_SIZEOF((msg != NULL ? msg->msg_iovlen : 1)) ];
  804         
  805         if (sock == NULL) {
  806                 error = EINVAL;
  807                 goto errorout;
  808         }
  809         
  810         if (data == 0 && msg != NULL) {
  811                 struct iovec *tempp = msg->msg_iov;
  812 
  813                 auio = uio_createwithbuffer(msg->msg_iovlen, 0, UIO_SYSSPACE, UIO_WRITE, 
  814                                                                   &uio_buf[0], sizeof(uio_buf));
  815                 if (tempp != NULL)
  816                 {
  817                         int i;
  818                         
  819                         for (i = 0; i < msg->msg_iovlen; i++) {
  820                                 uio_addiov(auio, CAST_USER_ADDR_T((tempp + i)->iov_base), (tempp + i)->iov_len);
  821                         }
  822                         
  823                         if (uio_resid(auio) < 0) {
  824                                 error = EINVAL;
  825                                 goto errorout;
  826                         }
  827                 }
  828         }
  829         
  830         if (sentlen)
  831                 *sentlen = 0;
  832         
  833         if (auio)
  834                 datalen = uio_resid(auio);
  835         else
  836                 datalen = data->m_pkthdr.len;
  837         
  838         if (msg && msg->msg_control)
  839         {
  840                 if ((size_t)msg->msg_controllen < sizeof(struct cmsghdr)) return EINVAL;
  841                 if ((size_t)msg->msg_controllen > MLEN) return EINVAL;
  842                 control = m_get(M_NOWAIT, MT_CONTROL);
  843                 if (control == NULL) {
  844                         error = ENOMEM;
  845                         goto errorout;
  846                 }
  847                 memcpy(mtod(control, caddr_t), msg->msg_control, msg->msg_controllen);
  848                 control->m_len = msg->msg_controllen;
  849         }
  850         
  851         error = sock->so_proto->pr_usrreqs->pru_sosend(sock, msg != NULL ?
  852             (struct sockaddr*)msg->msg_name : NULL, auio, data, control, flags);
  853 
  854         /*
  855          * Residual data is possible in the case of IO vectors but not
  856          * in the mbuf case since the latter is treated as atomic send.
  857          * If pru_sosend() consumed a portion of the iovecs data and
  858          * the error returned is transient, treat it as success; this
  859          * is consistent with sendit() behavior.
  860          */
  861         if (auio != NULL && uio_resid(auio) != datalen &&
  862             (error == ERESTART || error == EINTR || error == EWOULDBLOCK))
  863                 error = 0;
  864 
  865         if (error == 0 && sentlen != NULL) {
  866                 if (auio != NULL)
  867                         *sentlen = datalen - uio_resid(auio);
  868                 else
  869                         *sentlen = datalen;
  870         }
  871         
  872         return error;
  873 
  874 /*
  875  * In cases where we detect an error before returning, we need to
  876  * free the mbuf chain if there is one. sosend (and pru_sosend) will
  877  * free the mbuf chain if they encounter an error.
  878  */
  879 errorout:
  880         if (control)
  881                 m_freem(control);
  882         if (data)
  883                 m_freem(data);
  884         if (sentlen)
  885                 *sentlen = 0;
  886         return error;
  887 }
  888 
  889 errno_t
  890 sock_send(
  891         socket_t                        sock,
  892         const struct msghdr     *msg,
  893         int                                     flags,
  894         size_t                          *sentlen)
  895 {
  896         if (msg == NULL || msg->msg_iov == NULL || msg->msg_iovlen < 1)
  897                 return EINVAL;
  898         return sock_send_internal(sock, msg, NULL, flags, sentlen);
  899 }
  900 
  901 errno_t
  902 sock_sendmbuf(
  903         socket_t                        sock,
  904         const struct msghdr     *msg,
  905         mbuf_t                          data,
  906         int                                     flags,
  907         size_t                          *sentlen)
  908 {
  909         if (data == NULL || (msg &&
  910                 (msg->msg_iov != NULL || msg->msg_iovlen != 0))) {
  911                 if (data)
  912                         m_freem(data);
  913                 return EINVAL;
  914         }
  915         return sock_send_internal(sock, msg, data, flags, sentlen);
  916 }
  917 
  918 errno_t
  919 sock_shutdown(
  920         socket_t        sock,
  921         int                     how)
  922 {
  923         if (sock == NULL) return EINVAL;
  924         return soshutdown(sock, how);
  925 }
  926 
  927 
  928 errno_t
  929 sock_socket(
  930         int                             domain,
  931         int                             type,
  932         int                             protocol,
  933         sock_upcall             callback,
  934         void*                   context,
  935         socket_t                *new_so)
  936 {
  937         int     error = 0;
  938         if (new_so == NULL) return EINVAL;
  939         /* socreate will create an initial so_count */
  940         error = socreate(domain, new_so, type, protocol);
  941         if (error == 0 && callback)
  942         {
  943                 (*new_so)->so_rcv.sb_flags |= SB_UPCALL;
  944 #if CONFIG_SOWUPCALL
  945                 (*new_so)->so_snd.sb_flags |= SB_UPCALL;
  946 #endif
  947                 (*new_so)->so_upcall = (so_upcall)callback;
  948                 (*new_so)->so_upcallarg = context;
  949         }
  950         return error;
  951 }
  952 
  953 void
  954 sock_close(
  955         socket_t        sock)
  956 {
  957         if (sock == NULL) return;
  958         soclose(sock);
  959 }
  960 
  961 /* Do we want this to be APPLE_PRIVATE API?: YES (LD 12/23/04)*/
  962 void
  963 sock_retain(
  964         socket_t        sock)
  965 {
  966         if (sock == NULL) return;
  967         socket_lock(sock, 1);
  968         sock->so_retaincnt++;
  969         sock->so_usecount++;    /* add extra reference for holding the socket */
  970         socket_unlock(sock, 1);
  971 }
  972 
  973 /* Do we want this to be APPLE_PRIVATE API? */
  974 void
  975 sock_release(socket_t sock)
  976 {
  977         if (sock == NULL)
  978                 return;
  979         socket_lock(sock, 1);
  980 
  981         if (sock->so_flags & SOF_UPCALLINUSE)
  982                 soclose_wait_locked(sock);
  983 
  984         sock->so_retaincnt--;
  985         if (sock->so_retaincnt < 0)
  986                 panic("sock_release: negative retain count for sock=%p "
  987                     "cnt=%x\n", sock, sock->so_retaincnt);
  988         if ((sock->so_retaincnt == 0) && (sock->so_usecount == 2)) {
  989                 /* close socket only if the FD is not holding it */
  990                 soclose_locked(sock);
  991         } else {
  992                 /* remove extra reference holding the socket */
  993                 sock->so_usecount--;
  994         }
  995         socket_unlock(sock, 1);
  996 }
  997 
  998 errno_t
  999 sock_setpriv(
 1000         socket_t        sock,
 1001         int                     on)
 1002 {
 1003         if (sock == NULL) return EINVAL;
 1004         socket_lock(sock, 1);
 1005         if (on)
 1006         {
 1007                 sock->so_state |= SS_PRIV;
 1008         }
 1009         else
 1010         {
 1011                 sock->so_state &= ~SS_PRIV;
 1012         }
 1013         socket_unlock(sock, 1);
 1014         return 0;
 1015 }
 1016 
 1017 int
 1018 sock_isconnected(
 1019         socket_t sock)
 1020 {
 1021         int retval;
 1022         socket_lock(sock, 1);
 1023         retval = (sock->so_state & SS_ISCONNECTED) != 0;
 1024         socket_unlock(sock, 1);
 1025         return (retval);
 1026 }
 1027 
 1028 int
 1029 sock_isnonblocking(
 1030         socket_t sock)
 1031 {
 1032         int retval;
 1033         socket_lock(sock, 1);
 1034         retval = (sock->so_state & SS_NBIO) != 0;
 1035         socket_unlock(sock, 1);
 1036         return (retval);
 1037 }
 1038 
 1039 errno_t
 1040 sock_gettype(
 1041         socket_t        sock,
 1042         int                     *outDomain,
 1043         int                     *outType,
 1044         int                     *outProtocol)
 1045 {
 1046         socket_lock(sock, 1);
 1047         if (outDomain)
 1048                 *outDomain = sock->so_proto->pr_domain->dom_family;
 1049         if (outType)
 1050                 *outType = sock->so_type;
 1051         if (outProtocol)
 1052                 *outProtocol = sock->so_proto->pr_protocol;
 1053         socket_unlock(sock, 1);
 1054         return 0;
 1055 }
 1056 
 1057 /*
 1058  * Return the listening socket of a pre-accepted socket.  It returns the
 1059  * listener (so_head) value of a given socket.  This is intended to be
 1060  * called by a socket filter during a filter attach (sf_attach) callback.
 1061  * The value returned by this routine is safe to be used only in the
 1062  * context of that callback, because we hold the listener's lock across
 1063  * the sflt_initsock() call.
 1064  */
 1065 socket_t
 1066 sock_getlistener(socket_t sock)
 1067 {
 1068         return (sock->so_head);
 1069 }
 1070 
 1071 static inline void
 1072 sock_set_tcp_stream_priority(socket_t sock)
 1073 {
 1074         if ((sock->so_proto->pr_domain->dom_family == AF_INET || 
 1075                 sock->so_proto->pr_domain->dom_family == AF_INET6) &&
 1076                 sock->so_proto->pr_type == SOCK_STREAM) {
 1077 
 1078                 set_tcp_stream_priority(sock);
 1079 
 1080         }
 1081 }
 1082 
 1083 /*
 1084  * Caller must have ensured socket is valid and won't be going away.
 1085  */
 1086 void
 1087 socket_set_traffic_mgt_flags_locked(socket_t sock, u_int32_t flags)
 1088 {
 1089         (void) OSBitOrAtomic(flags, &sock->so_traffic_mgt_flags);
 1090         sock_set_tcp_stream_priority(sock);
 1091 }
 1092 
 1093 void
 1094 socket_set_traffic_mgt_flags(socket_t sock, u_int32_t flags)
 1095 {
 1096         socket_lock(sock, 1);
 1097         socket_set_traffic_mgt_flags_locked(sock, flags);
 1098         socket_unlock(sock, 1);
 1099 }
 1100 
 1101 /*
 1102  * Caller must have ensured socket is valid and won't be going away.
 1103  */
 1104 void
 1105 socket_clear_traffic_mgt_flags_locked(socket_t sock, u_int32_t flags)
 1106 {
 1107         (void) OSBitAndAtomic(~flags, &sock->so_traffic_mgt_flags);
 1108         sock_set_tcp_stream_priority(sock);
 1109 }
 1110 
 1111 void
 1112 socket_clear_traffic_mgt_flags(socket_t sock, u_int32_t flags)
 1113 {
 1114         socket_lock(sock, 1);
 1115         socket_clear_traffic_mgt_flags_locked(sock, flags);
 1116         socket_unlock(sock, 1);
 1117 }
 1118 
 1119 
 1120 /*
 1121  * Caller must have ensured socket is valid and won't be going away.
 1122  */
 1123 errno_t
 1124 socket_defunct(struct proc *p, socket_t so, int level)
 1125 {
 1126         errno_t retval;
 1127 
 1128         if (level != SHUTDOWN_SOCKET_LEVEL_DISCONNECT_SVC &&
 1129             level != SHUTDOWN_SOCKET_LEVEL_DISCONNECT_ALL)
 1130                 return (EINVAL);
 1131 
 1132         socket_lock(so, 1);
 1133         /*
 1134          * SHUTDOWN_SOCKET_LEVEL_DISCONNECT_SVC level is meant to tear down
 1135          * all of mDNSResponder IPC sockets, currently those of AF_UNIX; note
 1136          * that this is an implementation artifact of mDNSResponder.  We do
 1137          * a quick test against the socket buffers for SB_UNIX, since that
 1138          * would have been set by unp_attach() at socket creation time.
 1139          */
 1140         if (level == SHUTDOWN_SOCKET_LEVEL_DISCONNECT_SVC &&
 1141             (so->so_rcv.sb_flags & so->so_snd.sb_flags & SB_UNIX) != SB_UNIX) {
 1142                 socket_unlock(so, 1);
 1143                 return (EOPNOTSUPP);
 1144         }
 1145         retval = sosetdefunct(p, so, level, TRUE);
 1146         if (retval == 0)
 1147                 retval = sodefunct(p, so, level);
 1148         socket_unlock(so, 1);
 1149         return (retval);
 1150 }
 1151 
 1152 errno_t
 1153 sock_setupcall(socket_t sock, sock_upcall callback, void* context)
 1154 {
 1155         if (sock == NULL)
 1156                 return EINVAL;
 1157 
 1158         /*
 1159          * Note that we don't wait for any in progress upcall to complete.
 1160          */
 1161         socket_lock(sock, 1);
 1162 
 1163         sock->so_upcall = (so_upcall) callback;
 1164         sock->so_upcallarg = context;
 1165         if (callback) {
 1166                 sock->so_rcv.sb_flags |= SB_UPCALL;
 1167 #if CONFIG_SOWUPCALL
 1168                 sock->so_snd.sb_flags |= SB_UPCALL;
 1169 #endif /* CONFIG_SOWUPCALL */
 1170         } else {
 1171                 sock->so_rcv.sb_flags &= ~SB_UPCALL;
 1172 #if CONFIG_SOWUPCALL
 1173                 sock->so_snd.sb_flags &= ~SB_UPCALL;
 1174 #endif /* CONFIG_SOWUPCALL */
 1175         }
 1176         
 1177         socket_unlock(sock, 1);
 1178 
 1179         return 0;
 1180 }
 1181 

Cache object: 3172addb60ece87eb2583225702154dd


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.