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/dev/kttcp.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 /*      $NetBSD: kttcp.c,v 1.16 2005/02/27 00:26:58 perry Exp $ */
    2 
    3 /*
    4  * Copyright (c) 2002 Wasabi Systems, Inc.
    5  * All rights reserved.
    6  *
    7  * Written by Frank van der Linden and Jason R. Thorpe for
    8  * Wasabi Systems, Inc.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  * 3. All advertising materials mentioning features or use of this software
   19  *    must display the following acknowledgement:
   20  *      This product includes software developed for the NetBSD Project by
   21  *      Wasabi Systems, Inc.
   22  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
   23  *    or promote products derived from this software without specific prior
   24  *    written permission.
   25  *
   26  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
   27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
   30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   36  * POSSIBILITY OF SUCH DAMAGE.
   37  */
   38 
   39 /*
   40  * kttcp.c --
   41  *
   42  *      This module provides kernel support for testing network
   43  *      throughput from the perspective of the kernel.  It is
   44  *      similar in spirit to the classic ttcp network benchmark
   45  *      program, the main difference being that with kttcp, the
   46  *      kernel is the source and sink of the data.
   47  *
   48  *      Testing like this is useful for a few reasons:
   49  *
   50  *      1. This allows us to know what kind of performance we can
   51  *         expect from network applications that run in the kernel
   52  *         space, such as the NFS server or the NFS client.  These
   53  *         applications don't have to move the data to/from userspace,
   54  *         and so benchmark programs which run in userspace don't
   55  *         give us an accurate model.
   56  *
   57  *      2. Since data received is just thrown away, the receiver
   58  *         is very fast.  This can provide better exercise for the
   59  *         sender at the other end.
   60  *
   61  *      3. Since the NetBSD kernel currently uses a run-to-completion
   62  *         scheduling model, kttcp provides a benchmark model where
   63  *         preemption of the benchmark program is not an issue.
   64  */
   65 
   66 #include <sys/cdefs.h>
   67 __KERNEL_RCSID(0, "$NetBSD: kttcp.c,v 1.16 2005/02/27 00:26:58 perry Exp $");
   68 
   69 #include <sys/param.h>
   70 #include <sys/types.h>
   71 #include <sys/ioctl.h>
   72 #include <sys/file.h>
   73 #include <sys/filedesc.h>
   74 #include <sys/conf.h>
   75 #include <sys/systm.h>
   76 #include <sys/protosw.h>
   77 #include <sys/proc.h>
   78 #include <sys/resourcevar.h>
   79 #include <sys/signal.h>
   80 #include <sys/socketvar.h>
   81 #include <sys/socket.h>
   82 #include <sys/mbuf.h>
   83 #include <sys/sa.h>
   84 #include <sys/mount.h>
   85 #include <sys/syscallargs.h>
   86 
   87 #include <dev/kttcpio.h>
   88 
   89 static int kttcp_send(struct proc *p, struct kttcp_io_args *);
   90 static int kttcp_recv(struct proc *p, struct kttcp_io_args *);
   91 static int kttcp_sosend(struct socket *, unsigned long long,
   92                         unsigned long long *, struct proc *, int);
   93 static int kttcp_soreceive(struct socket *, unsigned long long,
   94                            unsigned long long *, struct proc *, int *);
   95 
   96 void    kttcpattach(int);
   97 
   98 dev_type_ioctl(kttcpioctl);
   99 
  100 const struct cdevsw kttcp_cdevsw = {
  101         nullopen, nullclose, noread, nowrite, kttcpioctl,
  102         nostop, notty, nopoll, nommap, nokqfilter,
  103 };
  104 
  105 void
  106 kttcpattach(int count)
  107 {
  108         /* Do nothing. */
  109 }
  110 
  111 int
  112 kttcpioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
  113 {
  114         int error;
  115 
  116         if ((flag & FWRITE) == 0)
  117                 return EPERM;
  118 
  119         switch (cmd) {
  120         case KTTCP_IO_SEND:
  121                 error = kttcp_send(p, (struct kttcp_io_args *) data);
  122                 break;
  123 
  124         case KTTCP_IO_RECV:
  125                 error = kttcp_recv(p, (struct kttcp_io_args *) data);
  126                 break;
  127 
  128         default:
  129                 return EINVAL;
  130         }
  131 
  132         return error;
  133 }
  134 
  135 static int
  136 kttcp_send(struct proc *p, struct kttcp_io_args *kio)
  137 {
  138         struct file *fp;
  139         int error;
  140         struct timeval t0, t1;
  141         unsigned long long len, done;
  142 
  143         if (kio->kio_totalsize >= KTTCP_MAX_XMIT)
  144                 return EINVAL;
  145 
  146         fp = fd_getfile(p->p_fd, kio->kio_socket);
  147         if (fp == NULL)
  148                 return EBADF;
  149         FILE_USE(fp);
  150         if (fp->f_type != DTYPE_SOCKET) {
  151                 FILE_UNUSE(fp, p);
  152                 return EFTYPE;
  153         }
  154 
  155         len = kio->kio_totalsize;
  156         microtime(&t0);
  157         do {
  158                 error = kttcp_sosend((struct socket *)fp->f_data, len,
  159                     &done, p, 0);
  160                 len -= done;
  161         } while (error == 0 && len > 0);
  162 
  163         FILE_UNUSE(fp, p);
  164 
  165         microtime(&t1);
  166         if (error != 0)
  167                 return error;
  168         timersub(&t1, &t0, &kio->kio_elapsed);
  169 
  170         kio->kio_bytesdone = kio->kio_totalsize - len;
  171 
  172         return 0;
  173 }
  174 
  175 static int
  176 kttcp_recv(struct proc *p, struct kttcp_io_args *kio)
  177 {
  178         struct file *fp;
  179         int error;
  180         struct timeval t0, t1;
  181         unsigned long long len, done;
  182 
  183         if (kio->kio_totalsize > KTTCP_MAX_XMIT)
  184                 return EINVAL;
  185 
  186         fp = fd_getfile(p->p_fd, kio->kio_socket);
  187         if (fp == NULL)
  188                 return EBADF;
  189         FILE_USE(fp);
  190         if (fp->f_type != DTYPE_SOCKET) {
  191                 FILE_UNUSE(fp, p);
  192                 return EBADF;
  193         }
  194         len = kio->kio_totalsize;
  195         microtime(&t0);
  196         do {
  197                 error = kttcp_soreceive((struct socket *)fp->f_data,
  198                     len, &done, p, NULL);
  199                 len -= done;
  200         } while (error == 0 && len > 0 && done > 0);
  201 
  202         FILE_UNUSE(fp, p);
  203 
  204         microtime(&t1);
  205         if (error == EPIPE)
  206                 error = 0;
  207         if (error != 0)
  208                 return error;
  209         timersub(&t1, &t0, &kio->kio_elapsed);
  210 
  211         kio->kio_bytesdone = kio->kio_totalsize - len;
  212 
  213         return 0;
  214 }
  215 
  216 #define SBLOCKWAIT(f)   (((f) & MSG_DONTWAIT) ? M_NOWAIT : M_WAITOK)
  217 
  218 /*
  219  * Slightly changed version of sosend()
  220  */
  221 static int
  222 kttcp_sosend(struct socket *so, unsigned long long slen,
  223              unsigned long long *done, struct proc *p, int flags)
  224 {
  225         struct mbuf **mp, *m, *top;
  226         long space, len, mlen;
  227         int error, s, dontroute, atomic;
  228         long long resid;
  229 
  230         atomic = sosendallatonce(so);
  231         resid = slen;
  232         top = NULL;
  233         /*
  234          * In theory resid should be unsigned.
  235          * However, space must be signed, as it might be less than 0
  236          * if we over-committed, and we must use a signed comparison
  237          * of space and resid.  On the other hand, a negative resid
  238          * causes us to loop sending 0-length segments to the protocol.
  239          */
  240         if (resid < 0) {
  241                 error = EINVAL;
  242                 goto out;
  243         }
  244         dontroute =
  245             (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 &&
  246             (so->so_proto->pr_flags & PR_ATOMIC);
  247         p->p_stats->p_ru.ru_msgsnd++;
  248 #define snderr(errno)   { error = errno; splx(s); goto release; }
  249 
  250  restart:
  251         if ((error = sblock(&so->so_snd, SBLOCKWAIT(flags))) != 0)
  252                 goto out;
  253         do {
  254                 s = splsoftnet();
  255                 if (so->so_state & SS_CANTSENDMORE)
  256                         snderr(EPIPE);
  257                 if (so->so_error) {
  258                         error = so->so_error;
  259                         so->so_error = 0;
  260                         splx(s);
  261                         goto release;
  262                 }
  263                 if ((so->so_state & SS_ISCONNECTED) == 0) {
  264                         if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
  265                                 if ((so->so_state & SS_ISCONFIRMING) == 0)
  266                                         snderr(ENOTCONN);
  267                         } else
  268                                 snderr(EDESTADDRREQ);
  269                 }
  270                 space = sbspace(&so->so_snd);
  271                 if (flags & MSG_OOB)
  272                         space += 1024;
  273                 if ((atomic && resid > so->so_snd.sb_hiwat))
  274                         snderr(EMSGSIZE);
  275                 if (space < resid && (atomic || space < so->so_snd.sb_lowat)) {
  276                         if (so->so_state & SS_NBIO)
  277                                 snderr(EWOULDBLOCK);
  278                         SBLASTRECORDCHK(&so->so_rcv,
  279                             "kttcp_soreceive sbwait 1");
  280                         SBLASTMBUFCHK(&so->so_rcv,
  281                             "kttcp_soreceive sbwait 1");
  282                         sbunlock(&so->so_snd);
  283                         error = sbwait(&so->so_snd);
  284                         splx(s);
  285                         if (error)
  286                                 goto out;
  287                         goto restart;
  288                 }
  289                 splx(s);
  290                 mp = &top;
  291                 do {
  292                         do {
  293                                 if (top == 0) {
  294                                         m = m_gethdr(M_WAIT, MT_DATA);
  295                                         mlen = MHLEN;
  296                                         m->m_pkthdr.len = 0;
  297                                         m->m_pkthdr.rcvif = NULL;
  298                                 } else {
  299                                         m = m_get(M_WAIT, MT_DATA);
  300                                         mlen = MLEN;
  301                                 }
  302                                 if (resid >= MINCLSIZE && space >= MCLBYTES) {
  303                                         m_clget(m, M_WAIT);
  304                                         if ((m->m_flags & M_EXT) == 0)
  305                                                 goto nopages;
  306                                         mlen = MCLBYTES;
  307 #ifdef  MAPPED_MBUFS
  308                                         len = lmin(MCLBYTES, resid);
  309 #else
  310                                         if (atomic && top == 0) {
  311                                                 len = lmin(MCLBYTES - max_hdr,
  312                                                     resid);
  313                                                 m->m_data += max_hdr;
  314                                         } else
  315                                                 len = lmin(MCLBYTES, resid);
  316 #endif
  317                                         space -= len;
  318                                 } else {
  319 nopages:
  320                                         len = lmin(lmin(mlen, resid), space);
  321                                         space -= len;
  322                                         /*
  323                                          * For datagram protocols, leave room
  324                                          * for protocol headers in first mbuf.
  325                                          */
  326                                         if (atomic && top == 0 && len < mlen)
  327                                                 MH_ALIGN(m, len);
  328                                 }
  329                                 resid -= len;
  330                                 m->m_len = len;
  331                                 *mp = m;
  332                                 top->m_pkthdr.len += len;
  333                                 if (error)
  334                                         goto release;
  335                                 mp = &m->m_next;
  336                                 if (resid <= 0) {
  337                                         if (flags & MSG_EOR)
  338                                                 top->m_flags |= M_EOR;
  339                                         break;
  340                                 }
  341                         } while (space > 0 && atomic);
  342 
  343                         s = splsoftnet();
  344 
  345                         if (so->so_state & SS_CANTSENDMORE)
  346                                 snderr(EPIPE);
  347 
  348                         if (dontroute)
  349                                 so->so_options |= SO_DONTROUTE;
  350                         if (resid > 0)
  351                                 so->so_state |= SS_MORETOCOME;
  352                         error = (*so->so_proto->pr_usrreq)(so,
  353                             (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND,
  354                             top, NULL, NULL, p);
  355                         if (dontroute)
  356                                 so->so_options &= ~SO_DONTROUTE;
  357                         if (resid > 0)
  358                                 so->so_state &= ~SS_MORETOCOME;
  359                         splx(s);
  360 
  361                         top = 0;
  362                         mp = &top;
  363                         if (error)
  364                                 goto release;
  365                 } while (resid && space > 0);
  366         } while (resid);
  367 
  368  release:
  369         sbunlock(&so->so_snd);
  370  out:
  371         if (top)
  372                 m_freem(top);
  373         *done = slen - resid;
  374 #if 0
  375         printf("sosend: error %d slen %llu resid %lld\n", error, slen, resid);
  376 #endif
  377         return (error);
  378 }
  379 
  380 static int
  381 kttcp_soreceive(struct socket *so, unsigned long long slen,
  382                 unsigned long long *done, struct proc *p, int *flagsp)
  383 {
  384         struct mbuf *m, **mp;
  385         int flags, len, error, s, offset, moff, type;
  386         long long orig_resid, resid;
  387         const struct protosw *pr;
  388         struct mbuf *nextrecord;
  389 
  390         pr = so->so_proto;
  391         mp = NULL;
  392         type = 0;
  393         resid = orig_resid = slen;
  394         if (flagsp)
  395                 flags = *flagsp &~ MSG_EOR;
  396         else
  397                 flags = 0;
  398         if (flags & MSG_OOB) {
  399                 m = m_get(M_WAIT, MT_DATA);
  400                 error = (*pr->pr_usrreq)(so, PRU_RCVOOB, m,
  401                     (struct mbuf *)(long)(flags & MSG_PEEK), NULL, NULL);
  402                 if (error)
  403                         goto bad;
  404                 do {
  405                         resid -= min(resid, m->m_len);
  406                         m = m_free(m);
  407                 } while (resid && error == 0 && m);
  408  bad:
  409                 if (m)
  410                         m_freem(m);
  411                 return (error);
  412         }
  413         if (mp)
  414                 *mp = NULL;
  415         if (so->so_state & SS_ISCONFIRMING && resid)
  416                 (*pr->pr_usrreq)(so, PRU_RCVD, NULL, NULL, NULL, NULL);
  417 
  418  restart:
  419         if ((error = sblock(&so->so_rcv, SBLOCKWAIT(flags))) != 0)
  420                 return (error);
  421         s = splsoftnet();
  422 
  423         m = so->so_rcv.sb_mb;
  424         /*
  425          * If we have less data than requested, block awaiting more
  426          * (subject to any timeout) if:
  427          *   1. the current count is less than the low water mark,
  428          *   2. MSG_WAITALL is set, and it is possible to do the entire
  429          *      receive operation at once if we block (resid <= hiwat), or
  430          *   3. MSG_DONTWAIT is not set.
  431          * If MSG_WAITALL is set but resid is larger than the receive buffer,
  432          * we have to do the receive in sections, and thus risk returning
  433          * a short count if a timeout or signal occurs after we start.
  434          */
  435         if (m == NULL || (((flags & MSG_DONTWAIT) == 0 &&
  436             so->so_rcv.sb_cc < resid) &&
  437             (so->so_rcv.sb_cc < so->so_rcv.sb_lowat ||
  438             ((flags & MSG_WAITALL) && resid <= so->so_rcv.sb_hiwat)) &&
  439             m->m_nextpkt == NULL && (pr->pr_flags & PR_ATOMIC) == 0)) {
  440 #ifdef DIAGNOSTIC
  441                 if (m == NULL && so->so_rcv.sb_cc)
  442                         panic("receive 1");
  443 #endif
  444                 if (so->so_error) {
  445                         if (m)
  446                                 goto dontblock;
  447                         error = so->so_error;
  448                         if ((flags & MSG_PEEK) == 0)
  449                                 so->so_error = 0;
  450                         goto release;
  451                 }
  452                 if (so->so_state & SS_CANTRCVMORE) {
  453                         if (m)
  454                                 goto dontblock;
  455                         else
  456                                 goto release;
  457                 }
  458                 for (; m; m = m->m_next)
  459                         if (m->m_type == MT_OOBDATA  || (m->m_flags & M_EOR)) {
  460                                 m = so->so_rcv.sb_mb;
  461                                 goto dontblock;
  462                         }
  463                 if ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) == 0 &&
  464                     (so->so_proto->pr_flags & PR_CONNREQUIRED)) {
  465                         error = ENOTCONN;
  466                         goto release;
  467                 }
  468                 if (resid == 0)
  469                         goto release;
  470                 if ((so->so_state & SS_NBIO) || (flags & MSG_DONTWAIT)) {
  471                         error = EWOULDBLOCK;
  472                         goto release;
  473                 }
  474                 sbunlock(&so->so_rcv);
  475                 error = sbwait(&so->so_rcv);
  476                 splx(s);
  477                 if (error)
  478                         return (error);
  479                 goto restart;
  480         }
  481  dontblock:
  482         /*
  483          * On entry here, m points to the first record of the socket buffer.
  484          * While we process the initial mbufs containing address and control
  485          * info, we save a copy of m->m_nextpkt into nextrecord.
  486          */
  487 #ifdef notyet /* XXXX */
  488         if (uio->uio_procp)
  489                 uio->uio_procp->p_stats->p_ru.ru_msgrcv++;
  490 #endif
  491         KASSERT(m == so->so_rcv.sb_mb);
  492         SBLASTRECORDCHK(&so->so_rcv, "kttcp_soreceive 1");
  493         SBLASTMBUFCHK(&so->so_rcv, "kttcp_soreceive 1");
  494         nextrecord = m->m_nextpkt;
  495         if (pr->pr_flags & PR_ADDR) {
  496 #ifdef DIAGNOSTIC
  497                 if (m->m_type != MT_SONAME)
  498                         panic("receive 1a");
  499 #endif
  500                 orig_resid = 0;
  501                 if (flags & MSG_PEEK) {
  502                         m = m->m_next;
  503                 } else {
  504                         sbfree(&so->so_rcv, m);
  505                         MFREE(m, so->so_rcv.sb_mb);
  506                         m = so->so_rcv.sb_mb;
  507                 }
  508         }
  509         while (m && m->m_type == MT_CONTROL && error == 0) {
  510                 if (flags & MSG_PEEK) {
  511                         m = m->m_next;
  512                 } else {
  513                         sbfree(&so->so_rcv, m);
  514                         MFREE(m, so->so_rcv.sb_mb);
  515                         m = so->so_rcv.sb_mb;
  516                 }
  517         }
  518 
  519         /*
  520          * If m is non-NULL, we have some data to read.  From now on,
  521          * make sure to keep sb_lastrecord consistent when working on
  522          * the last packet on the chain (nextrecord == NULL) and we
  523          * change m->m_nextpkt.
  524          */
  525         if (m) {
  526                 if ((flags & MSG_PEEK) == 0) {
  527                         m->m_nextpkt = nextrecord;
  528                         /*
  529                          * If nextrecord == NULL (this is a single chain),
  530                          * then sb_lastrecord may not be valid here if m
  531                          * was changed earlier.
  532                          */
  533                         if (nextrecord == NULL) {
  534                                 KASSERT(so->so_rcv.sb_mb == m);
  535                                 so->so_rcv.sb_lastrecord = m;
  536                         }
  537                 }
  538                 type = m->m_type;
  539                 if (type == MT_OOBDATA)
  540                         flags |= MSG_OOB;
  541         } else {
  542                 if ((flags & MSG_PEEK) == 0) {
  543                         KASSERT(so->so_rcv.sb_mb == m);
  544                         so->so_rcv.sb_mb = nextrecord;
  545                         SB_EMPTY_FIXUP(&so->so_rcv);
  546                 }
  547         }
  548         SBLASTRECORDCHK(&so->so_rcv, "kttcp_soreceive 2");
  549         SBLASTMBUFCHK(&so->so_rcv, "kttcp_soreceive 2");
  550 
  551         moff = 0;
  552         offset = 0;
  553         while (m && resid > 0 && error == 0) {
  554                 if (m->m_type == MT_OOBDATA) {
  555                         if (type != MT_OOBDATA)
  556                                 break;
  557                 } else if (type == MT_OOBDATA)
  558                         break;
  559 #ifdef DIAGNOSTIC
  560                 else if (m->m_type != MT_DATA && m->m_type != MT_HEADER)
  561                         panic("receive 3");
  562 #endif
  563                 so->so_state &= ~SS_RCVATMARK;
  564                 len = resid;
  565                 if (so->so_oobmark && len > so->so_oobmark - offset)
  566                         len = so->so_oobmark - offset;
  567                 if (len > m->m_len - moff)
  568                         len = m->m_len - moff;
  569                 /*
  570                  * If mp is set, just pass back the mbufs.
  571                  * Otherwise copy them out via the uio, then free.
  572                  * Sockbuf must be consistent here (points to current mbuf,
  573                  * it points to next record) when we drop priority;
  574                  * we must note any additions to the sockbuf when we
  575                  * block interrupts again.
  576                  */
  577                 resid -= len;
  578                 if (len == m->m_len - moff) {
  579                         if (m->m_flags & M_EOR)
  580                                 flags |= MSG_EOR;
  581                         if (flags & MSG_PEEK) {
  582                                 m = m->m_next;
  583                                 moff = 0;
  584                         } else {
  585                                 nextrecord = m->m_nextpkt;
  586                                 sbfree(&so->so_rcv, m);
  587                                 if (mp) {
  588                                         *mp = m;
  589                                         mp = &m->m_next;
  590                                         so->so_rcv.sb_mb = m = m->m_next;
  591                                         *mp = NULL;
  592                                 } else {
  593                                         MFREE(m, so->so_rcv.sb_mb);
  594                                         m = so->so_rcv.sb_mb;
  595                                 }
  596                                 /*
  597                                  * If m != NULL, we also know that
  598                                  * so->so_rcv.sb_mb != NULL.
  599                                  */
  600                                 KASSERT(so->so_rcv.sb_mb == m);
  601                                 if (m) {
  602                                         m->m_nextpkt = nextrecord;
  603                                         if (nextrecord == NULL)
  604                                                 so->so_rcv.sb_lastrecord = m;
  605                                 } else {
  606                                         so->so_rcv.sb_mb = nextrecord;
  607                                         SB_EMPTY_FIXUP(&so->so_rcv);
  608                                 }
  609                                 SBLASTRECORDCHK(&so->so_rcv,
  610                                     "kttcp_soreceive 3");
  611                                 SBLASTMBUFCHK(&so->so_rcv,
  612                                     "kttcp_soreceive 3");
  613                         }
  614                 } else {
  615                         if (flags & MSG_PEEK)
  616                                 moff += len;
  617                         else {
  618                                 if (mp)
  619                                         *mp = m_copym(m, 0, len, M_WAIT);
  620                                 m->m_data += len;
  621                                 m->m_len -= len;
  622                                 so->so_rcv.sb_cc -= len;
  623                         }
  624                 }
  625                 if (so->so_oobmark) {
  626                         if ((flags & MSG_PEEK) == 0) {
  627                                 so->so_oobmark -= len;
  628                                 if (so->so_oobmark == 0) {
  629                                         so->so_state |= SS_RCVATMARK;
  630                                         break;
  631                                 }
  632                         } else {
  633                                 offset += len;
  634                                 if (offset == so->so_oobmark)
  635                                         break;
  636                         }
  637                 }
  638                 if (flags & MSG_EOR)
  639                         break;
  640                 /*
  641                  * If the MSG_WAITALL flag is set (for non-atomic socket),
  642                  * we must not quit until "uio->uio_resid == 0" or an error
  643                  * termination.  If a signal/timeout occurs, return
  644                  * with a short count but without error.
  645                  * Keep sockbuf locked against other readers.
  646                  */
  647                 while (flags & MSG_WAITALL && m == NULL && resid > 0 &&
  648                     !sosendallatonce(so) && !nextrecord) {
  649                         if (so->so_error || so->so_state & SS_CANTRCVMORE)
  650                                 break;
  651                         /*
  652                          * If we are peeking and the socket receive buffer is
  653                          * full, stop since we can't get more data to peek at.
  654                          */
  655                         if ((flags & MSG_PEEK) && sbspace(&so->so_rcv) <= 0)
  656                                 break;
  657                         /*
  658                          * If we've drained the socket buffer, tell the
  659                          * protocol in case it needs to do something to
  660                          * get it filled again.
  661                          */
  662                         if ((pr->pr_flags & PR_WANTRCVD) && so->so_pcb)
  663                                 (*pr->pr_usrreq)(so, PRU_RCVD, NULL,
  664                                     (struct mbuf *)(long)flags, NULL, NULL);
  665                         SBLASTRECORDCHK(&so->so_rcv,
  666                             "kttcp_soreceive sbwait 2");
  667                         SBLASTMBUFCHK(&so->so_rcv,
  668                             "kttcp_soreceive sbwait 2");
  669                         error = sbwait(&so->so_rcv);
  670                         if (error) {
  671                                 sbunlock(&so->so_rcv);
  672                                 splx(s);
  673                                 return (0);
  674                         }
  675                         if ((m = so->so_rcv.sb_mb) != NULL)
  676                                 nextrecord = m->m_nextpkt;
  677                 }
  678         }
  679 
  680         if (m && pr->pr_flags & PR_ATOMIC) {
  681                 flags |= MSG_TRUNC;
  682                 if ((flags & MSG_PEEK) == 0)
  683                         (void) sbdroprecord(&so->so_rcv);
  684         }
  685         if ((flags & MSG_PEEK) == 0) {
  686                 if (m == NULL) {
  687                         /*
  688                          * First part is an SB_EMPTY_FIXUP().  Second part
  689                          * makes sure sb_lastrecord is up-to-date if
  690                          * there is still data in the socket buffer.
  691                          */
  692                         so->so_rcv.sb_mb = nextrecord;
  693                         if (so->so_rcv.sb_mb == NULL) {
  694                                 so->so_rcv.sb_mbtail = NULL;
  695                                 so->so_rcv.sb_lastrecord = NULL;
  696                         } else if (nextrecord->m_nextpkt == NULL)
  697                                 so->so_rcv.sb_lastrecord = nextrecord;
  698                 }
  699                 SBLASTRECORDCHK(&so->so_rcv, "kttcp_soreceive 4");
  700                 SBLASTMBUFCHK(&so->so_rcv, "kttcp_soreceive 4");
  701                 if (pr->pr_flags & PR_WANTRCVD && so->so_pcb)
  702                         (*pr->pr_usrreq)(so, PRU_RCVD, NULL,
  703                             (struct mbuf *)(long)flags, NULL, NULL);
  704         }
  705         if (orig_resid == resid && orig_resid &&
  706             (flags & MSG_EOR) == 0 && (so->so_state & SS_CANTRCVMORE) == 0) {
  707                 sbunlock(&so->so_rcv);
  708                 splx(s);
  709                 goto restart;
  710         }
  711 
  712         if (flagsp)
  713                 *flagsp |= flags;
  714  release:
  715         sbunlock(&so->so_rcv);
  716         splx(s);
  717         *done = slen - resid;
  718 #if 0
  719         printf("soreceive: error %d slen %llu resid %lld\n", error, slen, resid);
  720 #endif
  721         return (error);
  722 }

Cache object: 88eb9756b9b31d92051da30d25ae8af2


[ 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.