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/netipx/spx_reass.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) 1984, 1985, 1986, 1987, 1993
    3  *      The Regents of the University of California.
    4  * Copyright (c) 2004-2009 Robert N. M. Watson
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 4. Neither the name of the University nor the names of its contributors
   16  *    may be used to endorse or promote products derived from this software
   17  *    without specific prior written permission.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   29  * SUCH DAMAGE.
   30  *
   31  * Copyright (c) 1995, Mike Mitchell
   32  * All rights reserved.
   33  *
   34  * Redistribution and use in source and binary forms, with or without
   35  * modification, are permitted provided that the following conditions
   36  * are met:
   37  * 1. Redistributions of source code must retain the above copyright
   38  *    notice, this list of conditions and the following disclaimer.
   39  * 2. Redistributions in binary form must reproduce the above copyright
   40  *    notice, this list of conditions and the following disclaimer in the
   41  *    documentation and/or other materials provided with the distribution.
   42  * 3. All advertising materials mentioning features or use of this software
   43  *    must display the following acknowledgement:
   44  *      This product includes software developed by the University of
   45  *      California, Berkeley and its contributors.
   46  * 4. Neither the name of the University nor the names of its contributors
   47  *    may be used to endorse or promote products derived from this software
   48  *    without specific prior written permission.
   49  *
   50  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   51  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   52  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   53  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   54  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   55  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   56  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   57  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   58  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   59  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   60  * SUCH DAMAGE.
   61  *
   62  *      @(#)spx_usrreq.h
   63  */
   64 
   65 #include <sys/cdefs.h>
   66 __FBSDID("$FreeBSD: releng/8.3/sys/netipx/spx_reass.c 199583 2009-11-20 15:27:52Z jhb $");
   67 
   68 #include <sys/param.h>
   69 #include <sys/lock.h>
   70 #include <sys/kernel.h>
   71 #include <sys/malloc.h>
   72 #include <sys/mbuf.h>
   73 #include <sys/mutex.h>
   74 #include <sys/proc.h>
   75 #include <sys/protosw.h>
   76 #include <sys/signalvar.h>
   77 #include <sys/socket.h>
   78 #include <sys/socketvar.h>
   79 #include <sys/sx.h>
   80 #include <sys/systm.h>
   81 
   82 #include <net/route.h>
   83 #include <netinet/tcp_fsm.h>
   84 
   85 #include <netipx/ipx.h>
   86 #include <netipx/ipx_pcb.h>
   87 #include <netipx/ipx_var.h>
   88 #include <netipx/spx.h>
   89 #include <netipx/spx_debug.h>
   90 #include <netipx/spx_timer.h>
   91 #include <netipx/spx_var.h>
   92 
   93 static int      spx_use_delack = 0;
   94 static int      spxrexmtthresh = 3;
   95 
   96 MALLOC_DEFINE(M_SPXREASSQ, "spxreassq", "SPX reassembly queue entry");
   97 
   98 /*
   99  * Flesh pending queued segments on SPX close.
  100  */
  101 void
  102 spx_reass_flush(struct spxpcb *cb)
  103 {
  104         struct spx_q *q;
  105 
  106         while ((q = LIST_FIRST(&cb->s_q)) != NULL) {
  107                 LIST_REMOVE(q, sq_entry);
  108                 m_freem(q->sq_msi);
  109                 free(q, M_SPXREASSQ);
  110         }
  111 }
  112 
  113 /*
  114  * Initialize SPX segment reassembly queue on SPX socket open.
  115  */
  116 void
  117 spx_reass_init(struct spxpcb *cb)
  118 {
  119 
  120         LIST_INIT(&cb->s_q);
  121 }
  122 
  123 /*
  124  * This is structurally similar to the tcp reassembly routine but its
  125  * function is somewhat different: it merely queues packets up, and
  126  * suppresses duplicates.
  127  */
  128 int
  129 spx_reass(struct spxpcb *cb, struct mbuf *msi, struct spx *si)
  130 {
  131         struct spx_q *q, *q_new, *q_temp;
  132         struct mbuf *m;
  133         struct socket *so = cb->s_ipxpcb->ipxp_socket;
  134         char packetp = cb->s_flags & SF_HI;
  135         int incr;
  136         char wakeup = 0;
  137 
  138         IPX_LOCK_ASSERT(cb->s_ipxpcb);
  139 
  140         if (si == SI(0))
  141                 goto present;
  142 
  143         /*
  144          * Update our news from them.
  145          */
  146         if (si->si_cc & SPX_SA)
  147                 cb->s_flags |= (spx_use_delack ? SF_DELACK : SF_ACKNOW);
  148         if (SSEQ_GT(si->si_alo, cb->s_ralo))
  149                 cb->s_flags |= SF_WIN;
  150         if (SSEQ_LEQ(si->si_ack, cb->s_rack)) {
  151                 if ((si->si_cc & SPX_SP) && cb->s_rack != (cb->s_smax + 1)) {
  152                         spxstat.spxs_rcvdupack++;
  153 
  154                         /*
  155                          * If this is a completely duplicate ack and other
  156                          * conditions hold, we assume a packet has been
  157                          * dropped and retransmit it exactly as in
  158                          * tcp_input().
  159                          */
  160                         if (si->si_ack != cb->s_rack ||
  161                             si->si_alo != cb->s_ralo)
  162                                 cb->s_dupacks = 0;
  163                         else if (++cb->s_dupacks == spxrexmtthresh) {
  164                                 u_short onxt = cb->s_snxt;
  165                                 int cwnd = cb->s_cwnd;
  166 
  167                                 cb->s_snxt = si->si_ack;
  168                                 cb->s_cwnd = CUNIT;
  169                                 cb->s_force = 1 + SPXT_REXMT;
  170                                 spx_output(cb, NULL);
  171                                 cb->s_timer[SPXT_REXMT] = cb->s_rxtcur;
  172                                 cb->s_rtt = 0;
  173                                 if (cwnd >= 4 * CUNIT)
  174                                         cb->s_cwnd = cwnd / 2;
  175                                 if (SSEQ_GT(onxt, cb->s_snxt))
  176                                         cb->s_snxt = onxt;
  177                                 return (1);
  178                         }
  179                 } else
  180                         cb->s_dupacks = 0;
  181                 goto update_window;
  182         }
  183         cb->s_dupacks = 0;
  184 
  185         /*
  186          * If our correspondent acknowledges data we haven't sent TCP would
  187          * drop the packet after acking.  We'll be a little more permissive.
  188          */
  189         if (SSEQ_GT(si->si_ack, (cb->s_smax + 1))) {
  190                 spxstat.spxs_rcvacktoomuch++;
  191                 si->si_ack = cb->s_smax + 1;
  192         }
  193         spxstat.spxs_rcvackpack++;
  194 
  195         /*
  196          * If transmit timer is running and timed sequence number was acked,
  197          * update smoothed round trip time.  See discussion of algorithm in
  198          * tcp_input.c
  199          */
  200         if (cb->s_rtt && SSEQ_GT(si->si_ack, cb->s_rtseq)) {
  201                 spxstat.spxs_rttupdated++;
  202                 if (cb->s_srtt != 0) {
  203                         short delta;
  204                         delta = cb->s_rtt - (cb->s_srtt >> 3);
  205                         if ((cb->s_srtt += delta) <= 0)
  206                                 cb->s_srtt = 1;
  207                         if (delta < 0)
  208                                 delta = -delta;
  209                         delta -= (cb->s_rttvar >> 2);
  210                         if ((cb->s_rttvar += delta) <= 0)
  211                                 cb->s_rttvar = 1;
  212                 } else {
  213                         /*
  214                          * No rtt measurement yet.
  215                          */
  216                         cb->s_srtt = cb->s_rtt << 3;
  217                         cb->s_rttvar = cb->s_rtt << 1;
  218                 }
  219                 cb->s_rtt = 0;
  220                 cb->s_rxtshift = 0;
  221                 SPXT_RANGESET(cb->s_rxtcur,
  222                         ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1,
  223                         SPXTV_MIN, SPXTV_REXMTMAX);
  224         }
  225 
  226         /*
  227          * If all outstanding data is acked, stop retransmit timer and
  228          * remember to restart (more output or persist).  If there is more
  229          * data to be acked, restart retransmit timer, using current
  230          * (possibly backed-off) value;
  231          */
  232         if (si->si_ack == cb->s_smax + 1) {
  233                 cb->s_timer[SPXT_REXMT] = 0;
  234                 cb->s_flags |= SF_RXT;
  235         } else if (cb->s_timer[SPXT_PERSIST] == 0)
  236                 cb->s_timer[SPXT_REXMT] = cb->s_rxtcur;
  237 
  238         /*
  239          * When new data is acked, open the congestion window.  If the window
  240          * gives us less than ssthresh packets in flight, open exponentially
  241          * (maxseg at a time).  Otherwise open linearly (maxseg^2 / cwnd at a
  242          * time).
  243          */
  244         incr = CUNIT;
  245         if (cb->s_cwnd > cb->s_ssthresh)
  246                 incr = max(incr * incr / cb->s_cwnd, 1);
  247         cb->s_cwnd = min(cb->s_cwnd + incr, cb->s_cwmx);
  248 
  249         /*
  250          * Trim Acked data from output queue.
  251          */
  252         SOCKBUF_LOCK(&so->so_snd);
  253         while ((m = so->so_snd.sb_mb) != NULL) {
  254                 if (SSEQ_LT((mtod(m, struct spx *))->si_seq, si->si_ack))
  255                         sbdroprecord_locked(&so->so_snd);
  256                 else
  257                         break;
  258         }
  259         sowwakeup_locked(so);
  260         cb->s_rack = si->si_ack;
  261 update_window:
  262         if (SSEQ_LT(cb->s_snxt, cb->s_rack))
  263                 cb->s_snxt = cb->s_rack;
  264         if (SSEQ_LT(cb->s_swl1, si->si_seq) || ((cb->s_swl1 == si->si_seq &&
  265             (SSEQ_LT(cb->s_swl2, si->si_ack))) ||
  266              (cb->s_swl2 == si->si_ack && SSEQ_LT(cb->s_ralo, si->si_alo)))) {
  267                 /* keep track of pure window updates */
  268                 if ((si->si_cc & SPX_SP) && cb->s_swl2 == si->si_ack
  269                     && SSEQ_LT(cb->s_ralo, si->si_alo)) {
  270                         spxstat.spxs_rcvwinupd++;
  271                         spxstat.spxs_rcvdupack--;
  272                 }
  273                 cb->s_ralo = si->si_alo;
  274                 cb->s_swl1 = si->si_seq;
  275                 cb->s_swl2 = si->si_ack;
  276                 cb->s_swnd = (1 + si->si_alo - si->si_ack);
  277                 if (cb->s_swnd > cb->s_smxw)
  278                         cb->s_smxw = cb->s_swnd;
  279                 cb->s_flags |= SF_WIN;
  280         }
  281 
  282         /*
  283          * If this packet number is higher than that which we have allocated
  284          * refuse it, unless urgent.
  285          */
  286         if (SSEQ_GT(si->si_seq, cb->s_alo)) {
  287                 if (si->si_cc & SPX_SP) {
  288                         spxstat.spxs_rcvwinprobe++;
  289                         return (1);
  290                 } else
  291                         spxstat.spxs_rcvpackafterwin++;
  292                 if (si->si_cc & SPX_OB) {
  293                         if (SSEQ_GT(si->si_seq, cb->s_alo + 60))
  294                                 return (1); /* else queue this packet; */
  295                 } else {
  296 #ifdef BROKEN
  297                         /*
  298                          * XXXRW: This is broken on at least one count:
  299                          * spx_close() will free the ipxp and related parts,
  300                          * which are then touched by spx_input() after the
  301                          * return from spx_reass().
  302                          */
  303                         /*struct socket *so = cb->s_ipxpcb->ipxp_socket;
  304                         if (so->so_state && SS_NOFDREF) {
  305                                 spx_close(cb);
  306                         } else
  307                                        would crash system*/
  308 #endif
  309                         spx_istat.notyet++;
  310                         return (1);
  311                 }
  312         }
  313 
  314         /*
  315          * If this is a system packet, we don't need to queue it up, and
  316          * won't update acknowledge #.
  317          */
  318         if (si->si_cc & SPX_SP)
  319                 return (1);
  320 
  321         /*
  322          * We have already seen this packet, so drop.
  323          */
  324         if (SSEQ_LT(si->si_seq, cb->s_ack)) {
  325                 spx_istat.bdreas++;
  326                 spxstat.spxs_rcvduppack++;
  327                 if (si->si_seq == cb->s_ack - 1)
  328                         spx_istat.lstdup++;
  329                 return (1);
  330         }
  331 
  332         /*
  333          * Loop through all packets queued up to insert in appropriate
  334          * sequence.
  335          */
  336         q_new = malloc(sizeof(*q_new), M_SPXREASSQ, M_NOWAIT | M_ZERO);
  337         if (q_new == NULL)
  338                 return (1);
  339         q_new->sq_si = si;
  340         q_new->sq_msi = msi;
  341         LIST_FOREACH(q, &cb->s_q, sq_entry) {
  342                 if (si->si_seq == q->sq_si->si_seq) {
  343                         free(q_new, M_SPXREASSQ);
  344                         spxstat.spxs_rcvduppack++;
  345                         return (1);
  346                 }
  347                 if (SSEQ_LT(si->si_seq, q->sq_si->si_seq)) {
  348                         spxstat.spxs_rcvoopack++;
  349                         break;
  350                 }
  351         }
  352         if (q != NULL)
  353                 LIST_INSERT_BEFORE(q, q_new, sq_entry);
  354         else
  355                 LIST_INSERT_HEAD(&cb->s_q, q_new, sq_entry);
  356 
  357         /*
  358          * If this packet is urgent, inform process
  359          */
  360         if (si->si_cc & SPX_OB) {
  361                 cb->s_iobc = ((char *)si)[1 + sizeof(*si)];
  362                 sohasoutofband(so);
  363                 cb->s_oobflags |= SF_IOOB;
  364         }
  365 present:
  366 #define SPINC sizeof(struct spxhdr)
  367         SOCKBUF_LOCK(&so->so_rcv);
  368 
  369         /*
  370          * Loop through all packets queued up to update acknowledge number,
  371          * and present all acknowledged data to user; if in packet interface
  372          * mode, show packet headers.
  373          */
  374         LIST_FOREACH_SAFE(q, &cb->s_q, sq_entry, q_temp) {
  375                 struct spx *qsi;
  376                 struct mbuf *mqsi;
  377 
  378                 qsi = q->sq_si;
  379                 mqsi = q->sq_msi;
  380                 if (qsi->si_seq == cb->s_ack) {
  381                         cb->s_ack++;
  382                         if (qsi->si_cc & SPX_OB) {
  383                                 cb->s_oobflags &= ~SF_IOOB;
  384                                 if (so->so_rcv.sb_cc)
  385                                         so->so_oobmark = so->so_rcv.sb_cc;
  386                                 else
  387                                         so->so_rcv.sb_state |= SBS_RCVATMARK;
  388                         }
  389                         LIST_REMOVE(q, sq_entry);
  390                         free(q, M_SPXREASSQ);
  391                         wakeup = 1;
  392                         spxstat.spxs_rcvpack++;
  393 #ifdef SF_NEWCALL
  394                         if (cb->s_flags2 & SF_NEWCALL) {
  395                                 struct spxhdr *sp =
  396                                     mtod(mqsi, struct spxhdr *);
  397                                 u_char dt = sp->spx_dt;
  398 
  399                                 spx_newchecks[4]++;
  400                                 if (dt != cb->s_rhdr.spx_dt) {
  401                                         struct mbuf *mm =
  402                                            m_getclr(M_DONTWAIT, MT_CONTROL);
  403                                         spx_newchecks[0]++;
  404                                         if (mm != NULL) {
  405                                                 u_short *s =
  406                                                         mtod(mm, u_short *);
  407                                                 cb->s_rhdr.spx_dt = dt;
  408                                                 mm->m_len = 5; /*XXX*/
  409                                                 s[0] = 5;
  410                                                 s[1] = 1;
  411                                                 *(u_char *)(&s[2]) = dt;
  412                                                 sbappend_locked(&so->so_rcv, mm);
  413                                         }
  414                                 }
  415                                 if (sp->spx_cc & SPX_OB) {
  416                                         MCHTYPE(mqsi, MT_OOBDATA);
  417                                         spx_newchecks[1]++;
  418                                         so->so_oobmark = 0;
  419                                         so->so_rcv.sb_state &= ~SBS_RCVATMARK;
  420                                 }
  421                                 if (packetp == 0) {
  422                                         mqsi->m_data += SPINC;
  423                                         mqsi->m_len -= SPINC;
  424                                         mqsi->m_pkthdr.len -= SPINC;
  425                                 }
  426                                 if ((sp->spx_cc & SPX_EM) || packetp) {
  427                                         sbappendrecord_locked(&so->so_rcv,
  428                                             mqsi);
  429                                         spx_newchecks[9]++;
  430                                 } else
  431                                         sbappend_locked(&so->so_rcv, mqsi);
  432                         } else
  433 #endif
  434                         if (packetp)
  435                                 sbappendrecord_locked(&so->so_rcv, mqsi);
  436                         else {
  437                                 cb->s_rhdr = *mtod(mqsi, struct spxhdr *);
  438                                 mqsi->m_data += SPINC;
  439                                 mqsi->m_len -= SPINC;
  440                                 mqsi->m_pkthdr.len -= SPINC;
  441                                 sbappend_locked(&so->so_rcv, mqsi);
  442                         }
  443                   } else
  444                         break;
  445         }
  446         if (wakeup)
  447                 sorwakeup_locked(so);
  448         else
  449                 SOCKBUF_UNLOCK(&so->so_rcv);
  450         return (0);
  451 }

Cache object: ae1024bad3d292f3fa12fedeec9306fa


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