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_usrreq.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/9.0/sys/netipx/spx_usrreq.c 194561 2009-06-20 23:38:21Z rwatson $");
   67 
   68 #include <sys/param.h>
   69 #include <sys/lock.h>
   70 #include <sys/malloc.h>
   71 #include <sys/mbuf.h>
   72 #include <sys/mutex.h>
   73 #include <sys/proc.h>
   74 #include <sys/protosw.h>
   75 #include <sys/signalvar.h>
   76 #include <sys/socket.h>
   77 #include <sys/socketvar.h>
   78 #include <sys/sx.h>
   79 #include <sys/systm.h>
   80 
   81 #include <net/route.h>
   82 #include <netinet/tcp_fsm.h>
   83 
   84 #include <netipx/ipx.h>
   85 #include <netipx/ipx_pcb.h>
   86 #include <netipx/ipx_var.h>
   87 #include <netipx/spx.h>
   88 #include <netipx/spx_debug.h>
   89 #include <netipx/spx_timer.h>
   90 #include <netipx/spx_var.h>
   91 
   92 #include <security/mac/mac_framework.h>
   93 
   94 /*
   95  * SPX protocol implementation.
   96  */
   97 static struct   mtx spx_mtx;                    /* Protects only spx_iss. */
   98 static u_short  spx_iss;
   99 u_short         spx_newchecks[50];
  100 static int      spx_hardnosed;
  101 static int      traceallspxs = 0;
  102 struct  spx_istat spx_istat;
  103 
  104 #define SPX_LOCK_INIT() mtx_init(&spx_mtx, "spx_mtx", NULL, MTX_DEF)
  105 #define SPX_LOCK()      mtx_lock(&spx_mtx)
  106 #define SPX_UNLOCK()    mtx_unlock(&spx_mtx)
  107 
  108 static const int spx_backoff[SPX_MAXRXTSHIFT+1] =
  109     { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 };
  110 
  111 static  void spx_close(struct spxpcb *cb);
  112 static  void spx_disconnect(struct spxpcb *cb);
  113 static  void spx_drop(struct spxpcb *cb, int errno);
  114 static  void spx_setpersist(struct spxpcb *cb);
  115 static  void spx_template(struct spxpcb *cb);
  116 static  void spx_timers(struct spxpcb *cb, int timer);
  117 static  void spx_usrclosed(struct spxpcb *cb);
  118 
  119 static  void spx_usr_abort(struct socket *so);
  120 static  int spx_accept(struct socket *so, struct sockaddr **nam);
  121 static  int spx_attach(struct socket *so, int proto, struct thread *td);
  122 static  int spx_bind(struct socket *so, struct sockaddr *nam, struct thread *td);
  123 static  void spx_usr_close(struct socket *so);
  124 static  int spx_connect(struct socket *so, struct sockaddr *nam,
  125                         struct thread *td);
  126 static  void spx_detach(struct socket *so);
  127 static  void spx_pcbdetach(struct ipxpcb *ipxp);
  128 static  int spx_usr_disconnect(struct socket *so);
  129 static  int spx_listen(struct socket *so, int backlog, struct thread *td);
  130 static  int spx_rcvd(struct socket *so, int flags);
  131 static  int spx_rcvoob(struct socket *so, struct mbuf *m, int flags);
  132 static  int spx_send(struct socket *so, int flags, struct mbuf *m,
  133                      struct sockaddr *addr, struct mbuf *control,
  134                      struct thread *td);
  135 static  int spx_shutdown(struct socket *so);
  136 static  int spx_sp_attach(struct socket *so, int proto, struct thread *td);
  137 
  138 struct  pr_usrreqs spx_usrreqs = {
  139         .pru_abort =            spx_usr_abort,
  140         .pru_accept =           spx_accept,
  141         .pru_attach =           spx_attach,
  142         .pru_bind =             spx_bind,
  143         .pru_connect =          spx_connect,
  144         .pru_control =          ipx_control,
  145         .pru_detach =           spx_detach,
  146         .pru_disconnect =       spx_usr_disconnect,
  147         .pru_listen =           spx_listen,
  148         .pru_peeraddr =         ipx_peeraddr,
  149         .pru_rcvd =             spx_rcvd,
  150         .pru_rcvoob =           spx_rcvoob,
  151         .pru_send =             spx_send,
  152         .pru_shutdown =         spx_shutdown,
  153         .pru_sockaddr =         ipx_sockaddr,
  154         .pru_close =            spx_usr_close,
  155 };
  156 
  157 struct  pr_usrreqs spx_usrreq_sps = {
  158         .pru_abort =            spx_usr_abort,
  159         .pru_accept =           spx_accept,
  160         .pru_attach =           spx_sp_attach,
  161         .pru_bind =             spx_bind,
  162         .pru_connect =          spx_connect,
  163         .pru_control =          ipx_control,
  164         .pru_detach =           spx_detach,
  165         .pru_disconnect =       spx_usr_disconnect,
  166         .pru_listen =           spx_listen,
  167         .pru_peeraddr =         ipx_peeraddr,
  168         .pru_rcvd =             spx_rcvd,
  169         .pru_rcvoob =           spx_rcvoob,
  170         .pru_send =             spx_send,
  171         .pru_shutdown =         spx_shutdown,
  172         .pru_sockaddr =         ipx_sockaddr,
  173         .pru_close =            spx_usr_close,
  174 };
  175 
  176 void
  177 spx_init(void)
  178 {
  179 
  180         SPX_LOCK_INIT();
  181         spx_iss = 1; /* WRONG !! should fish it out of TODR */
  182 }
  183 
  184 void
  185 spx_input(struct mbuf *m, struct ipxpcb *ipxp)
  186 {
  187         struct spxpcb *cb;
  188         struct spx *si = mtod(m, struct spx *);
  189         struct socket *so;
  190         struct spx spx_savesi;
  191         int dropsocket = 0;
  192         short ostate = 0;
  193 
  194         spxstat.spxs_rcvtotal++;
  195         KASSERT(ipxp != NULL, ("spx_input: ipxpcb == NULL"));
  196 
  197         /*
  198          * spx_input() assumes that the caller will hold both the pcb list
  199          * lock and also the ipxp lock.  spx_input() will release both before
  200          * returning, and may in fact trade in the ipxp lock for another pcb
  201          * lock following sonewconn().
  202          */
  203         IPX_LIST_LOCK_ASSERT();
  204         IPX_LOCK_ASSERT(ipxp);
  205 
  206         cb = ipxtospxpcb(ipxp);
  207         KASSERT(cb != NULL, ("spx_input: cb == NULL"));
  208 
  209         if (ipxp->ipxp_flags & IPXP_DROPPED)
  210                 goto drop;
  211 
  212         if (m->m_len < sizeof(*si)) {
  213                 if ((m = m_pullup(m, sizeof(*si))) == NULL) {
  214                         IPX_UNLOCK(ipxp);
  215                         IPX_LIST_UNLOCK();
  216                         spxstat.spxs_rcvshort++;
  217                         return;
  218                 }
  219                 si = mtod(m, struct spx *);
  220         }
  221         si->si_seq = ntohs(si->si_seq);
  222         si->si_ack = ntohs(si->si_ack);
  223         si->si_alo = ntohs(si->si_alo);
  224 
  225         so = ipxp->ipxp_socket;
  226         KASSERT(so != NULL, ("spx_input: so == NULL"));
  227 
  228 #ifdef MAC
  229         if (mac_socket_check_deliver(so, m) != 0)
  230                 goto drop;
  231 #endif
  232 
  233         if (so->so_options & SO_DEBUG || traceallspxs) {
  234                 ostate = cb->s_state;
  235                 spx_savesi = *si;
  236         }
  237         if (so->so_options & SO_ACCEPTCONN) {
  238                 struct spxpcb *ocb = cb;
  239 
  240                 so = sonewconn(so, 0);
  241                 if (so == NULL)
  242                         goto drop;
  243 
  244                 /*
  245                  * This is ugly, but ....
  246                  *
  247                  * Mark socket as temporary until we're committed to keeping
  248                  * it.  The code at ``drop'' and ``dropwithreset'' check the
  249                  * flag dropsocket to see if the temporary socket created
  250                  * here should be discarded.  We mark the socket as
  251                  * discardable until we're committed to it below in
  252                  * TCPS_LISTEN.
  253                  *
  254                  * XXXRW: In the new world order of real kernel parallelism,
  255                  * temporarily allocating the socket when we're "not sure"
  256                  * seems like a bad idea, as we might race to remove it if
  257                  * the listen socket is closed...?
  258                  *
  259                  * We drop the lock of the listen socket ipxp, and acquire
  260                  * the lock of the new socket ippx.
  261                  */
  262                 dropsocket++;
  263                 IPX_UNLOCK(ipxp);
  264                 ipxp = (struct ipxpcb *)so->so_pcb;
  265                 IPX_LOCK(ipxp);
  266                 ipxp->ipxp_laddr = si->si_dna;
  267                 cb = ipxtospxpcb(ipxp);
  268                 cb->s_mtu = ocb->s_mtu;         /* preserve sockopts */
  269                 cb->s_flags = ocb->s_flags;     /* preserve sockopts */
  270                 cb->s_flags2 = ocb->s_flags2;   /* preserve sockopts */
  271                 cb->s_state = TCPS_LISTEN;
  272         }
  273         IPX_LOCK_ASSERT(ipxp);
  274 
  275         /*
  276          * Packet received on connection.  Reset idle time and keep-alive
  277          * timer.
  278          */
  279         cb->s_idle = 0;
  280         cb->s_timer[SPXT_KEEP] = SPXTV_KEEP;
  281 
  282         switch (cb->s_state) {
  283         case TCPS_LISTEN:{
  284                 struct sockaddr_ipx *sipx, ssipx;
  285                 struct ipx_addr laddr;
  286 
  287                 /*
  288                  * If somebody here was carying on a conversation and went
  289                  * away, and his pen pal thinks he can still talk, we get the
  290                  * misdirected packet.
  291                  */
  292                 if (spx_hardnosed && (si->si_did != 0 || si->si_seq != 0)) {
  293                         spx_istat.gonawy++;
  294                         goto dropwithreset;
  295                 }
  296                 sipx = &ssipx;
  297                 bzero(sipx, sizeof *sipx);
  298                 sipx->sipx_len = sizeof(*sipx);
  299                 sipx->sipx_family = AF_IPX;
  300                 sipx->sipx_addr = si->si_sna;
  301                 laddr = ipxp->ipxp_laddr;
  302                 if (ipx_nullhost(laddr))
  303                         ipxp->ipxp_laddr = si->si_dna;
  304                 if (ipx_pcbconnect(ipxp, (struct sockaddr *)sipx, &thread0)) {
  305                         ipxp->ipxp_laddr = laddr;
  306                         spx_istat.noconn++;
  307                         goto drop;
  308                 }
  309                 spx_template(cb);
  310                 dropsocket = 0;         /* committed to socket */
  311                 cb->s_did = si->si_sid;
  312                 cb->s_rack = si->si_ack;
  313                 cb->s_ralo = si->si_alo;
  314 #define THREEWAYSHAKE
  315 #ifdef THREEWAYSHAKE
  316                 cb->s_state = TCPS_SYN_RECEIVED;
  317                 cb->s_force = 1 + SPXT_KEEP;
  318                 spxstat.spxs_accepts++;
  319                 cb->s_timer[SPXT_KEEP] = SPXTV_KEEP;
  320                 }
  321                 break;
  322 
  323          case TCPS_SYN_RECEIVED: {
  324                 /*
  325                  * This state means that we have heard a response to our
  326                  * acceptance of their connection.  It is probably logically
  327                  * unnecessary in this implementation.
  328                  */
  329                 if (si->si_did != cb->s_sid) {
  330                         spx_istat.wrncon++;
  331                         goto drop;
  332                 }
  333 #endif
  334                 ipxp->ipxp_fport =  si->si_sport;
  335                 cb->s_timer[SPXT_REXMT] = 0;
  336                 cb->s_timer[SPXT_KEEP] = SPXTV_KEEP;
  337                 soisconnected(so);
  338                 cb->s_state = TCPS_ESTABLISHED;
  339                 spxstat.spxs_accepts++;
  340                 }
  341                 break;
  342 
  343         case TCPS_SYN_SENT:
  344                 /*
  345                  * This state means that we have gotten a response to our
  346                  * attempt to establish a connection.  We fill in the data
  347                  * from the other side, telling us which port to respond to,
  348                  * instead of the well-known one we might have sent to in the
  349                  * first place.  We also require that this is a response to
  350                  * our connection id.
  351                  */
  352                 if (si->si_did != cb->s_sid) {
  353                         spx_istat.notme++;
  354                         goto drop;
  355                 }
  356                 spxstat.spxs_connects++;
  357                 cb->s_did = si->si_sid;
  358                 cb->s_rack = si->si_ack;
  359                 cb->s_ralo = si->si_alo;
  360                 cb->s_dport = ipxp->ipxp_fport =  si->si_sport;
  361                 cb->s_timer[SPXT_REXMT] = 0;
  362                 cb->s_flags |= SF_ACKNOW;
  363                 soisconnected(so);
  364                 cb->s_state = TCPS_ESTABLISHED;
  365 
  366                 /*
  367                  * Use roundtrip time of connection request for initial rtt.
  368                  */
  369                 if (cb->s_rtt) {
  370                         cb->s_srtt = cb->s_rtt << 3;
  371                         cb->s_rttvar = cb->s_rtt << 1;
  372                         SPXT_RANGESET(cb->s_rxtcur,
  373                             ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1,
  374                             SPXTV_MIN, SPXTV_REXMTMAX);
  375                             cb->s_rtt = 0;
  376                 }
  377         }
  378 
  379         if (so->so_options & SO_DEBUG || traceallspxs)
  380                 spx_trace(SA_INPUT, (u_char)ostate, cb, &spx_savesi, 0);
  381 
  382         m->m_len -= sizeof(struct ipx);
  383         m->m_pkthdr.len -= sizeof(struct ipx);
  384         m->m_data += sizeof(struct ipx);
  385 
  386         if (spx_reass(cb, m, si))
  387                 m_freem(m);
  388         if (cb->s_force || (cb->s_flags & (SF_ACKNOW|SF_WIN|SF_RXT)))
  389                 spx_output(cb, NULL);
  390         cb->s_flags &= ~(SF_WIN|SF_RXT);
  391         IPX_UNLOCK(ipxp);
  392         IPX_LIST_UNLOCK();
  393         return;
  394 
  395 dropwithreset:
  396         IPX_LOCK_ASSERT(ipxp);
  397         if (cb == NULL || (cb->s_ipxpcb->ipxp_socket->so_options & SO_DEBUG ||
  398             traceallspxs))
  399                 spx_trace(SA_DROP, (u_char)ostate, cb, &spx_savesi, 0);
  400         IPX_UNLOCK(ipxp);
  401         if (dropsocket) {
  402                 struct socket *head;
  403                 ACCEPT_LOCK();
  404                 KASSERT((so->so_qstate & SQ_INCOMP) != 0,
  405                     ("spx_input: nascent socket not SQ_INCOMP on soabort()"));
  406                 head = so->so_head;
  407                 TAILQ_REMOVE(&head->so_incomp, so, so_list);
  408                 head->so_incqlen--;
  409                 so->so_qstate &= ~SQ_INCOMP;
  410                 so->so_head = NULL;
  411                 ACCEPT_UNLOCK();
  412                 soabort(so);
  413         }
  414         IPX_LIST_UNLOCK();
  415         m_freem(m);
  416         return;
  417 
  418 drop:
  419         IPX_LOCK_ASSERT(ipxp);
  420         if (cb->s_ipxpcb->ipxp_socket->so_options & SO_DEBUG || traceallspxs)
  421                 spx_trace(SA_DROP, (u_char)ostate, cb, &spx_savesi, 0);
  422         IPX_UNLOCK(ipxp);
  423         IPX_LIST_UNLOCK();
  424         m_freem(m);
  425 }
  426 
  427 void
  428 spx_ctlinput(int cmd, struct sockaddr *arg_as_sa, void *dummy)
  429 {
  430 
  431         /* Currently, nothing. */
  432 }
  433 
  434 int
  435 spx_output(struct spxpcb *cb, struct mbuf *m0)
  436 {
  437         struct socket *so = cb->s_ipxpcb->ipxp_socket;
  438         struct mbuf *m = NULL;
  439         struct spx *si = NULL;
  440         struct sockbuf *sb = &so->so_snd;
  441         int len = 0, win, rcv_win;
  442         short span, off, recordp = 0;
  443         u_short alo;
  444         int error = 0, sendalot;
  445 #ifdef notdef
  446         int idle;
  447 #endif
  448         struct mbuf *mprev;
  449 
  450         IPX_LOCK_ASSERT(cb->s_ipxpcb);
  451 
  452         if (m0 != NULL) {
  453                 int mtu = cb->s_mtu;
  454                 int datalen;
  455 
  456                 /*
  457                  * Make sure that packet isn't too big.
  458                  */
  459                 for (m = m0; m != NULL; m = m->m_next) {
  460                         mprev = m;
  461                         len += m->m_len;
  462                         if (m->m_flags & M_EOR)
  463                                 recordp = 1;
  464                 }
  465                 datalen = (cb->s_flags & SF_HO) ?
  466                                 len - sizeof(struct spxhdr) : len;
  467                 if (datalen > mtu) {
  468                         if (cb->s_flags & SF_PI) {
  469                                 m_freem(m0);
  470                                 return (EMSGSIZE);
  471                         } else {
  472                                 int oldEM = cb->s_cc & SPX_EM;
  473 
  474                                 cb->s_cc &= ~SPX_EM;
  475                                 while (len > mtu) {
  476                                         m = m_copym(m0, 0, mtu, M_DONTWAIT);
  477                                         if (m == NULL) {
  478                                             cb->s_cc |= oldEM;
  479                                             m_freem(m0);
  480                                             return (ENOBUFS);
  481                                         }
  482                                         if (cb->s_flags & SF_NEWCALL) {
  483                                             struct mbuf *mm = m;
  484                                             spx_newchecks[7]++;
  485                                             while (mm != NULL) {
  486                                                 mm->m_flags &= ~M_EOR;
  487                                                 mm = mm->m_next;
  488                                             }
  489                                         }
  490                                         error = spx_output(cb, m);
  491                                         if (error) {
  492                                                 cb->s_cc |= oldEM;
  493                                                 m_freem(m0);
  494                                                 return (error);
  495                                         }
  496                                         m_adj(m0, mtu);
  497                                         len -= mtu;
  498                                 }
  499                                 cb->s_cc |= oldEM;
  500                         }
  501                 }
  502 
  503                 /*
  504                  * Force length even, by adding a "garbage byte" if
  505                  * necessary.
  506                  */
  507                 if (len & 1) {
  508                         m = mprev;
  509                         if (M_TRAILINGSPACE(m) >= 1)
  510                                 m->m_len++;
  511                         else {
  512                                 struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA);
  513 
  514                                 if (m1 == NULL) {
  515                                         m_freem(m0);
  516                                         return (ENOBUFS);
  517                                 }
  518                                 m1->m_len = 1;
  519                                 *(mtod(m1, u_char *)) = 0;
  520                                 m->m_next = m1;
  521                         }
  522                 }
  523                 m = m_gethdr(M_DONTWAIT, MT_DATA);
  524                 if (m == NULL) {
  525                         m_freem(m0);
  526                         return (ENOBUFS);
  527                 }
  528 
  529                 /*
  530                  * Fill in mbuf with extended SP header and addresses and
  531                  * length put into network format.
  532                  */
  533                 MH_ALIGN(m, sizeof(struct spx));
  534                 m->m_len = sizeof(struct spx);
  535                 m->m_next = m0;
  536                 si = mtod(m, struct spx *);
  537                 si->si_i = cb->s_ipx;
  538                 si->si_s = cb->s_shdr;
  539                 if ((cb->s_flags & SF_PI) && (cb->s_flags & SF_HO)) {
  540                         struct spxhdr *sh;
  541                         if (m0->m_len < sizeof(*sh)) {
  542                                 if((m0 = m_pullup(m0, sizeof(*sh))) == NULL) {
  543                                         m_free(m);
  544                                         m_freem(m0);
  545                                         return (EINVAL);
  546                                 }
  547                                 m->m_next = m0;
  548                         }
  549                         sh = mtod(m0, struct spxhdr *);
  550                         si->si_dt = sh->spx_dt;
  551                         si->si_cc |= sh->spx_cc & SPX_EM;
  552                         m0->m_len -= sizeof(*sh);
  553                         m0->m_data += sizeof(*sh);
  554                         len -= sizeof(*sh);
  555                 }
  556                 len += sizeof(*si);
  557                 if ((cb->s_flags2 & SF_NEWCALL) && recordp) {
  558                         si->si_cc |= SPX_EM;
  559                         spx_newchecks[8]++;
  560                 }
  561                 if (cb->s_oobflags & SF_SOOB) {
  562                         /*
  563                          * Per jqj@cornell: Make sure OB packets convey
  564                          * exactly 1 byte.  If the packet is 1 byte or
  565                          * larger, we have already guaranted there to be at
  566                          * least one garbage byte for the checksum, and extra
  567                          * bytes shouldn't hurt!
  568                          */
  569                         if (len > sizeof(*si)) {
  570                                 si->si_cc |= SPX_OB;
  571                                 len = (1 + sizeof(*si));
  572                         }
  573                 }
  574                 si->si_len = htons((u_short)len);
  575                 m->m_pkthdr.len = ((len - 1) | 1) + 1;
  576 
  577                 /*
  578                  * Queue stuff up for output.
  579                  */
  580                 sbappendrecord(sb, m);
  581                 cb->s_seq++;
  582         }
  583 #ifdef notdef
  584         idle = (cb->s_smax == (cb->s_rack - 1));
  585 #endif
  586 again:
  587         sendalot = 0;
  588         off = cb->s_snxt - cb->s_rack;
  589         win = min(cb->s_swnd, (cb->s_cwnd / CUNIT));
  590 
  591         /*
  592          * If in persist timeout with window of 0, send a probe.  Otherwise,
  593          * if window is small but non-zero and timer expired, send what we
  594          * can and go into transmit state.
  595          */
  596         if (cb->s_force == 1 + SPXT_PERSIST) {
  597                 if (win != 0) {
  598                         cb->s_timer[SPXT_PERSIST] = 0;
  599                         cb->s_rxtshift = 0;
  600                 }
  601         }
  602         span = cb->s_seq - cb->s_rack;
  603         len = min(span, win) - off;
  604 
  605         if (len < 0) {
  606                 /*
  607                  * Window shrank after we went into it.  If window shrank to
  608                  * 0, cancel pending restransmission and pull s_snxt back to
  609                  * (closed) window.  We will enter persist state below.  If
  610                  * the widndow didn't close completely, just wait for an ACK.
  611                  */
  612                 len = 0;
  613                 if (win == 0) {
  614                         cb->s_timer[SPXT_REXMT] = 0;
  615                         cb->s_snxt = cb->s_rack;
  616                 }
  617         }
  618         if (len > 1)
  619                 sendalot = 1;
  620         rcv_win = sbspace(&so->so_rcv);
  621 
  622         /*
  623          * Send if we owe peer an ACK.
  624          */
  625         if (cb->s_oobflags & SF_SOOB) {
  626                 /*
  627                  * Must transmit this out of band packet.
  628                  */
  629                 cb->s_oobflags &= ~ SF_SOOB;
  630                 sendalot = 1;
  631                 spxstat.spxs_sndurg++;
  632                 goto found;
  633         }
  634         if (cb->s_flags & SF_ACKNOW)
  635                 goto send;
  636         if (cb->s_state < TCPS_ESTABLISHED)
  637                 goto send;
  638 
  639         /*
  640          * Silly window can't happen in spx.  Code from TCP deleted.
  641          */
  642         if (len)
  643                 goto send;
  644 
  645         /*
  646          * Compare available window to amount of window known to peer (as
  647          * advertised window less next expected input.)  If the difference is
  648          * at least two packets or at least 35% of the mximum possible
  649          * window, then want to send a window update to peer.
  650          */
  651         if (rcv_win > 0) {
  652                 u_short delta =  1 + cb->s_alo - cb->s_ack;
  653                 int adv = rcv_win - (delta * cb->s_mtu);
  654 
  655                 if ((so->so_rcv.sb_cc == 0 && adv >= (2 * cb->s_mtu)) ||
  656                     (100 * adv / so->so_rcv.sb_hiwat >= 35)) {
  657                         spxstat.spxs_sndwinup++;
  658                         cb->s_flags |= SF_ACKNOW;
  659                         goto send;
  660                 }
  661 
  662         }
  663 
  664         /*
  665          * Many comments from tcp_output.c are appropriate here including ...
  666          * If send window is too small, there is data to transmit, and no
  667          * retransmit or persist is pending, then go to persist state.  If
  668          * nothing happens soon, send when timer expires: if window is
  669          * non-zero, transmit what we can, otherwise send a probe.
  670          */
  671         if (so->so_snd.sb_cc && cb->s_timer[SPXT_REXMT] == 0 &&
  672             cb->s_timer[SPXT_PERSIST] == 0) {
  673                 cb->s_rxtshift = 0;
  674                 spx_setpersist(cb);
  675         }
  676 
  677         /*
  678          * No reason to send a packet, just return.
  679          */
  680         cb->s_outx = 1;
  681         return (0);
  682 
  683 send:
  684         /*
  685          * Find requested packet.
  686          */
  687         si = NULL;
  688         m = NULL;
  689         if (len > 0) {
  690                 cb->s_want = cb->s_snxt;
  691                 for (m = sb->sb_mb; m != NULL; m = m->m_nextpkt) {
  692                         si = mtod(m, struct spx *);
  693                         if (SSEQ_LEQ(cb->s_snxt, si->si_seq))
  694                                 break;
  695                 }
  696         found:
  697                 if (si != NULL) {
  698                         if (si->si_seq != cb->s_snxt) {
  699                                 spxstat.spxs_sndvoid++;
  700                                 si = NULL;
  701                                 m = NULL;
  702                         } else
  703                                 cb->s_snxt++;
  704                 }
  705         }
  706 
  707         /*
  708          * Update window.
  709          */
  710         if (rcv_win < 0)
  711                 rcv_win = 0;
  712         alo = cb->s_ack - 1 + (rcv_win / ((short)cb->s_mtu));
  713         if (SSEQ_LT(alo, cb->s_alo))
  714                 alo = cb->s_alo;
  715 
  716         if (m != NULL) {
  717                 /*
  718                  * Must make a copy of this packet for ipx_output to monkey
  719                  * with.
  720                  */
  721                 m = m_copy(m, 0, M_COPYALL);
  722                 if (m == NULL)
  723                         return (ENOBUFS);
  724                 si = mtod(m, struct spx *);
  725                 if (SSEQ_LT(si->si_seq, cb->s_smax))
  726                         spxstat.spxs_sndrexmitpack++;
  727                 else
  728                         spxstat.spxs_sndpack++;
  729         } else if (cb->s_force || cb->s_flags & SF_ACKNOW) {
  730                 /*
  731                  * Must send an acknowledgement or a probe.
  732                  */
  733                 if (cb->s_force)
  734                         spxstat.spxs_sndprobe++;
  735                 if (cb->s_flags & SF_ACKNOW)
  736                         spxstat.spxs_sndacks++;
  737                 m = m_gethdr(M_DONTWAIT, MT_DATA);
  738                 if (m == NULL)
  739                         return (ENOBUFS);
  740 
  741                 /*
  742                  * Fill in mbuf with extended SP header and addresses and
  743                  * length put into network format.
  744                  */
  745                 MH_ALIGN(m, sizeof(struct spx));
  746                 m->m_len = sizeof(*si);
  747                 m->m_pkthdr.len = sizeof(*si);
  748                 si = mtod(m, struct spx *);
  749                 si->si_i = cb->s_ipx;
  750                 si->si_s = cb->s_shdr;
  751                 si->si_seq = cb->s_smax + 1;
  752                 si->si_len = htons(sizeof(*si));
  753                 si->si_cc |= SPX_SP;
  754         } else {
  755                 cb->s_outx = 3;
  756                 if (so->so_options & SO_DEBUG || traceallspxs)
  757                         spx_trace(SA_OUTPUT, cb->s_state, cb, si, 0);
  758                 return (0);
  759         }
  760 
  761         /*
  762          * Stuff checksum and output datagram.
  763          */
  764         if ((si->si_cc & SPX_SP) == 0) {
  765                 if (cb->s_force != (1 + SPXT_PERSIST) ||
  766                     cb->s_timer[SPXT_PERSIST] == 0) {
  767                         /*
  768                          * If this is a new packet and we are not currently
  769                          * timing anything, time this one.
  770                          */
  771                         if (SSEQ_LT(cb->s_smax, si->si_seq)) {
  772                                 cb->s_smax = si->si_seq;
  773                                 if (cb->s_rtt == 0) {
  774                                         spxstat.spxs_segstimed++;
  775                                         cb->s_rtseq = si->si_seq;
  776                                         cb->s_rtt = 1;
  777                                 }
  778                         }
  779 
  780                         /*
  781                          * Set rexmt timer if not currently set, initial
  782                          * value for retransmit timer is smoothed round-trip
  783                          * time + 2 * round-trip time variance.  Initialize
  784                          * shift counter which is used for backoff of
  785                          * retransmit time.
  786                          */
  787                         if (cb->s_timer[SPXT_REXMT] == 0 &&
  788                             cb->s_snxt != cb->s_rack) {
  789                                 cb->s_timer[SPXT_REXMT] = cb->s_rxtcur;
  790                                 if (cb->s_timer[SPXT_PERSIST]) {
  791                                         cb->s_timer[SPXT_PERSIST] = 0;
  792                                         cb->s_rxtshift = 0;
  793                                 }
  794                         }
  795                 } else if (SSEQ_LT(cb->s_smax, si->si_seq))
  796                         cb->s_smax = si->si_seq;
  797         } else if (cb->s_state < TCPS_ESTABLISHED) {
  798                 if (cb->s_rtt == 0)
  799                         cb->s_rtt = 1; /* Time initial handshake */
  800                 if (cb->s_timer[SPXT_REXMT] == 0)
  801                         cb->s_timer[SPXT_REXMT] = cb->s_rxtcur;
  802         }
  803 
  804         /*
  805          * Do not request acks when we ack their data packets or when we do a
  806          * gratuitous window update.
  807          */
  808         if (((si->si_cc & SPX_SP) == 0) || cb->s_force)
  809                 si->si_cc |= SPX_SA;
  810         si->si_seq = htons(si->si_seq);
  811         si->si_alo = htons(alo);
  812         si->si_ack = htons(cb->s_ack);
  813 
  814         if (ipxcksum)
  815                 si->si_sum = ipx_cksum(m, ntohs(si->si_len));
  816         else
  817                 si->si_sum = 0xffff;
  818 
  819         cb->s_outx = 4;
  820         if (so->so_options & SO_DEBUG || traceallspxs)
  821                 spx_trace(SA_OUTPUT, cb->s_state, cb, si, 0);
  822 
  823 #ifdef MAC
  824         mac_socket_create_mbuf(so, m);
  825 #endif
  826 
  827         if (so->so_options & SO_DONTROUTE)
  828                 error = ipx_outputfl(m, NULL, IPX_ROUTETOIF);
  829         else
  830                 error = ipx_outputfl(m, &cb->s_ipxpcb->ipxp_route, 0);
  831         if (error)
  832                 return (error);
  833         spxstat.spxs_sndtotal++;
  834 
  835         /*
  836          * Data sent (as far as we can tell).  If this advertises a larger
  837          * window than any other segment, then remember the size of the
  838          * advertized window.  Any pending ACK has now been sent.
  839          */
  840         cb->s_force = 0;
  841         cb->s_flags &= ~(SF_ACKNOW|SF_DELACK);
  842         if (SSEQ_GT(alo, cb->s_alo))
  843                 cb->s_alo = alo;
  844         if (sendalot)
  845                 goto again;
  846         cb->s_outx = 5;
  847         return (0);
  848 }
  849 
  850 static int spx_do_persist_panics = 0;
  851 
  852 static void
  853 spx_setpersist(struct spxpcb *cb)
  854 {
  855         int t = ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1;
  856 
  857         IPX_LOCK_ASSERT(cb->s_ipxpcb);
  858 
  859         if (cb->s_timer[SPXT_REXMT] && spx_do_persist_panics)
  860                 panic("spx_output REXMT");
  861 
  862         /*
  863          * Start/restart persistance timer.
  864          */
  865         SPXT_RANGESET(cb->s_timer[SPXT_PERSIST],
  866             t*spx_backoff[cb->s_rxtshift],
  867             SPXTV_PERSMIN, SPXTV_PERSMAX);
  868         if (cb->s_rxtshift < SPX_MAXRXTSHIFT)
  869                 cb->s_rxtshift++;
  870 }
  871 
  872 int
  873 spx_ctloutput(struct socket *so, struct sockopt *sopt)
  874 {
  875         struct spxhdr spxhdr;
  876         struct ipxpcb *ipxp;
  877         struct spxpcb *cb;
  878         int mask, error;
  879         short soptval;
  880         u_short usoptval;
  881         int optval;
  882 
  883         ipxp = sotoipxpcb(so);
  884         KASSERT(ipxp != NULL, ("spx_ctloutput: ipxp == NULL"));
  885 
  886         /*
  887          * This will have to be changed when we do more general stacking of
  888          * protocols.
  889          */
  890         if (sopt->sopt_level != IPXPROTO_SPX)
  891                 return (ipx_ctloutput(so, sopt));
  892 
  893         IPX_LOCK(ipxp);
  894         if (ipxp->ipxp_flags & IPXP_DROPPED) {
  895                 IPX_UNLOCK(ipxp);
  896                 return (ECONNRESET);
  897         }
  898 
  899         IPX_LOCK(ipxp);
  900         cb = ipxtospxpcb(ipxp);
  901         KASSERT(cb != NULL, ("spx_ctloutput: cb == NULL"));
  902 
  903         error = 0;
  904         switch (sopt->sopt_dir) {
  905         case SOPT_GET:
  906                 switch (sopt->sopt_name) {
  907                 case SO_HEADERS_ON_INPUT:
  908                         mask = SF_HI;
  909                         goto get_flags;
  910 
  911                 case SO_HEADERS_ON_OUTPUT:
  912                         mask = SF_HO;
  913                 get_flags:
  914                         soptval = cb->s_flags & mask;
  915                         IPX_UNLOCK(ipxp);
  916                         error = sooptcopyout(sopt, &soptval,
  917                             sizeof(soptval));
  918                         break;
  919 
  920                 case SO_MTU:
  921                         usoptval = cb->s_mtu;
  922                         IPX_UNLOCK(ipxp);
  923                         error = sooptcopyout(sopt, &usoptval,
  924                             sizeof(usoptval));
  925                         break;
  926 
  927                 case SO_LAST_HEADER:
  928                         spxhdr = cb->s_rhdr;
  929                         IPX_UNLOCK(ipxp);
  930                         error = sooptcopyout(sopt, &spxhdr, sizeof(spxhdr));
  931                         break;
  932 
  933                 case SO_DEFAULT_HEADERS:
  934                         spxhdr = cb->s_shdr;
  935                         IPX_UNLOCK(ipxp);
  936                         error = sooptcopyout(sopt, &spxhdr, sizeof(spxhdr));
  937                         break;
  938 
  939                 default:
  940                         IPX_UNLOCK(ipxp);
  941                         error = ENOPROTOOPT;
  942                 }
  943                 break;
  944 
  945         case SOPT_SET:
  946                 /*
  947                  * XXX Why are these shorts on get and ints on set?  That
  948                  * doesn't make any sense...
  949                  *
  950                  * XXXRW: Note, when we re-acquire the ipxp lock, we should
  951                  * re-check that it's not dropped.
  952                  */
  953                 IPX_UNLOCK(ipxp);
  954                 switch (sopt->sopt_name) {
  955                 case SO_HEADERS_ON_INPUT:
  956                         mask = SF_HI;
  957                         goto set_head;
  958 
  959                 case SO_HEADERS_ON_OUTPUT:
  960                         mask = SF_HO;
  961                 set_head:
  962                         error = sooptcopyin(sopt, &optval, sizeof optval,
  963                                             sizeof optval);
  964                         if (error)
  965                                 break;
  966 
  967                         IPX_LOCK(ipxp);
  968                         if (cb->s_flags & SF_PI) {
  969                                 if (optval)
  970                                         cb->s_flags |= mask;
  971                                 else
  972                                         cb->s_flags &= ~mask;
  973                         } else error = EINVAL;
  974                         IPX_UNLOCK(ipxp);
  975                         break;
  976 
  977                 case SO_MTU:
  978                         error = sooptcopyin(sopt, &usoptval, sizeof usoptval,
  979                                             sizeof usoptval);
  980                         if (error)
  981                                 break;
  982                         /* Unlocked write. */
  983                         cb->s_mtu = usoptval;
  984                         break;
  985 
  986 #ifdef SF_NEWCALL
  987                 case SO_NEWCALL:
  988                         error = sooptcopyin(sopt, &optval, sizeof optval,
  989                                             sizeof optval);
  990                         if (error)
  991                                 break;
  992                         IPX_LOCK(ipxp);
  993                         if (optval) {
  994                                 cb->s_flags2 |= SF_NEWCALL;
  995                                 spx_newchecks[5]++;
  996                         } else {
  997                                 cb->s_flags2 &= ~SF_NEWCALL;
  998                                 spx_newchecks[6]++;
  999                         }
 1000                         IPX_UNLOCK(ipxp);
 1001                         break;
 1002 #endif
 1003 
 1004                 case SO_DEFAULT_HEADERS:
 1005                         {
 1006                                 struct spxhdr sp;
 1007 
 1008                                 error = sooptcopyin(sopt, &sp, sizeof sp,
 1009                                                     sizeof sp);
 1010                                 if (error)
 1011                                         break;
 1012                                 IPX_LOCK(ipxp);
 1013                                 cb->s_dt = sp.spx_dt;
 1014                                 cb->s_cc = sp.spx_cc & SPX_EM;
 1015                                 IPX_UNLOCK(ipxp);
 1016                         }
 1017                         break;
 1018 
 1019                 default:
 1020                         error = ENOPROTOOPT;
 1021                 }
 1022                 break;
 1023 
 1024         default:
 1025                 panic("spx_ctloutput: bad socket option direction");
 1026         }
 1027         return (error);
 1028 }
 1029 
 1030 static void
 1031 spx_usr_abort(struct socket *so)
 1032 {
 1033         struct ipxpcb *ipxp;
 1034         struct spxpcb *cb;
 1035 
 1036         ipxp = sotoipxpcb(so);
 1037         KASSERT(ipxp != NULL, ("spx_usr_abort: ipxp == NULL"));
 1038 
 1039         cb = ipxtospxpcb(ipxp);
 1040         KASSERT(cb != NULL, ("spx_usr_abort: cb == NULL"));
 1041 
 1042         IPX_LIST_LOCK();
 1043         IPX_LOCK(ipxp);
 1044         spx_drop(cb, ECONNABORTED);
 1045         IPX_UNLOCK(ipxp);
 1046         IPX_LIST_UNLOCK();
 1047 }
 1048 
 1049 /*
 1050  * Accept a connection.  Essentially all the work is done at higher levels;
 1051  * just return the address of the peer, storing through addr.
 1052  */
 1053 static int
 1054 spx_accept(struct socket *so, struct sockaddr **nam)
 1055 {
 1056         struct ipxpcb *ipxp;
 1057         struct sockaddr_ipx *sipx, ssipx;
 1058 
 1059         ipxp = sotoipxpcb(so);
 1060         KASSERT(ipxp != NULL, ("spx_accept: ipxp == NULL"));
 1061 
 1062         sipx = &ssipx;
 1063         bzero(sipx, sizeof *sipx);
 1064         sipx->sipx_len = sizeof *sipx;
 1065         sipx->sipx_family = AF_IPX;
 1066         IPX_LOCK(ipxp);
 1067         sipx->sipx_addr = ipxp->ipxp_faddr;
 1068         IPX_UNLOCK(ipxp);
 1069         *nam = sodupsockaddr((struct sockaddr *)sipx, M_WAITOK);
 1070         return (0);
 1071 }
 1072 
 1073 static int
 1074 spx_attach(struct socket *so, int proto, struct thread *td)
 1075 {
 1076         struct ipxpcb *ipxp;
 1077         struct spxpcb *cb;
 1078         struct mbuf *mm;
 1079         struct sockbuf *sb;
 1080         int error;
 1081 
 1082         ipxp = sotoipxpcb(so);
 1083         KASSERT(ipxp == NULL, ("spx_attach: ipxp != NULL"));
 1084 
 1085         if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
 1086                 error = soreserve(so, (u_long) 3072, (u_long) 3072);
 1087                 if (error)
 1088                         return (error);
 1089         }
 1090 
 1091         cb = malloc(sizeof *cb, M_PCB, M_NOWAIT | M_ZERO);
 1092         if (cb == NULL)
 1093                 return (ENOBUFS);
 1094         mm = m_getclr(M_DONTWAIT, MT_DATA);
 1095         if (mm == NULL) {
 1096                 free(cb, M_PCB);
 1097                 return (ENOBUFS);
 1098         }
 1099 
 1100         IPX_LIST_LOCK();
 1101         error = ipx_pcballoc(so, &ipxpcb_list, td);
 1102         if (error) {
 1103                 IPX_LIST_UNLOCK();
 1104                 m_free(mm);
 1105                 free(cb, M_PCB);
 1106                 return (error);
 1107         }
 1108         ipxp = sotoipxpcb(so);
 1109         ipxp->ipxp_flags |= IPXP_SPX;
 1110 
 1111         cb->s_state = TCPS_LISTEN;
 1112         cb->s_smax = -1;
 1113         cb->s_swl1 = -1;
 1114         spx_reass_init(cb);
 1115         cb->s_ipxpcb = ipxp;
 1116         cb->s_mtu = 576 - sizeof(struct spx);
 1117         sb = &so->so_snd;
 1118         cb->s_cwnd = sbspace(sb) * CUNIT / cb->s_mtu;
 1119         cb->s_ssthresh = cb->s_cwnd;
 1120         cb->s_cwmx = sbspace(sb) * CUNIT / (2 * sizeof(struct spx));
 1121 
 1122         /*
 1123          * Above is recomputed when connecting to account for changed
 1124          * buffering or mtu's.
 1125          */
 1126         cb->s_rtt = SPXTV_SRTTBASE;
 1127         cb->s_rttvar = SPXTV_SRTTDFLT << 2;
 1128         SPXT_RANGESET(cb->s_rxtcur,
 1129             ((SPXTV_SRTTBASE >> 2) + (SPXTV_SRTTDFLT << 2)) >> 1,
 1130             SPXTV_MIN, SPXTV_REXMTMAX);
 1131         ipxp->ipxp_pcb = (caddr_t)cb;
 1132         IPX_LIST_UNLOCK();
 1133         return (0);
 1134 }
 1135 
 1136 static void
 1137 spx_pcbdetach(struct ipxpcb *ipxp)
 1138 {
 1139         struct spxpcb *cb;
 1140 
 1141         IPX_LOCK_ASSERT(ipxp);
 1142 
 1143         cb = ipxtospxpcb(ipxp);
 1144         KASSERT(cb != NULL, ("spx_pcbdetach: cb == NULL"));
 1145 
 1146         spx_reass_flush(cb);
 1147         free(cb, M_PCB);
 1148         ipxp->ipxp_pcb = NULL;
 1149 }
 1150 
 1151 static int
 1152 spx_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
 1153 {
 1154         struct ipxpcb *ipxp;
 1155         int error;
 1156 
 1157         ipxp = sotoipxpcb(so);
 1158         KASSERT(ipxp != NULL, ("spx_bind: ipxp == NULL"));
 1159 
 1160         IPX_LIST_LOCK();
 1161         IPX_LOCK(ipxp);
 1162         if (ipxp->ipxp_flags & IPXP_DROPPED) {
 1163                 error = EINVAL;
 1164                 goto out;
 1165         }
 1166         error = ipx_pcbbind(ipxp, nam, td);
 1167 out:
 1168         IPX_UNLOCK(ipxp);
 1169         IPX_LIST_UNLOCK();
 1170         return (error);
 1171 }
 1172 
 1173 static void
 1174 spx_usr_close(struct socket *so)
 1175 {
 1176         struct ipxpcb *ipxp;
 1177         struct spxpcb *cb;
 1178 
 1179         ipxp = sotoipxpcb(so);
 1180         KASSERT(ipxp != NULL, ("spx_usr_close: ipxp == NULL"));
 1181 
 1182         cb = ipxtospxpcb(ipxp);
 1183         KASSERT(cb != NULL, ("spx_usr_close: cb == NULL"));
 1184 
 1185         IPX_LIST_LOCK();
 1186         IPX_LOCK(ipxp);
 1187         if (cb->s_state > TCPS_LISTEN)
 1188                 spx_disconnect(cb);
 1189         else
 1190                 spx_close(cb);
 1191         IPX_UNLOCK(ipxp);
 1192         IPX_LIST_UNLOCK();
 1193 }
 1194 
 1195 /*
 1196  * Initiate connection to peer.  Enter SYN_SENT state, and mark socket as
 1197  * connecting.  Start keep-alive timer, setup prototype header, send initial
 1198  * system packet requesting connection.
 1199  */
 1200 static int
 1201 spx_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
 1202 {
 1203         struct ipxpcb *ipxp;
 1204         struct spxpcb *cb;
 1205         int error;
 1206 
 1207         ipxp = sotoipxpcb(so);
 1208         KASSERT(ipxp != NULL, ("spx_connect: ipxp == NULL"));
 1209 
 1210         cb = ipxtospxpcb(ipxp);
 1211         KASSERT(cb != NULL, ("spx_connect: cb == NULL"));
 1212 
 1213         IPX_LIST_LOCK();
 1214         IPX_LOCK(ipxp);
 1215         if (ipxp->ipxp_flags & IPXP_DROPPED) {
 1216                 error = EINVAL;
 1217                 goto spx_connect_end;
 1218         }
 1219         if (ipxp->ipxp_lport == 0) {
 1220                 error = ipx_pcbbind(ipxp, NULL, td);
 1221                 if (error)
 1222                         goto spx_connect_end;
 1223         }
 1224         error = ipx_pcbconnect(ipxp, nam, td);
 1225         if (error)
 1226                 goto spx_connect_end;
 1227         soisconnecting(so);
 1228         spxstat.spxs_connattempt++;
 1229         cb->s_state = TCPS_SYN_SENT;
 1230         cb->s_did = 0;
 1231         spx_template(cb);
 1232         cb->s_timer[SPXT_KEEP] = SPXTV_KEEP;
 1233         cb->s_force = 1 + SPXTV_KEEP;
 1234 
 1235         /*
 1236          * Other party is required to respond to the port I send from, but he
 1237          * is not required to answer from where I am sending to, so allow
 1238          * wildcarding.  Original port I am sending to is still saved in
 1239          * cb->s_dport.
 1240          */
 1241         ipxp->ipxp_fport = 0;
 1242         error = spx_output(cb, NULL);
 1243 spx_connect_end:
 1244         IPX_UNLOCK(ipxp);
 1245         IPX_LIST_UNLOCK();
 1246         return (error);
 1247 }
 1248 
 1249 static void
 1250 spx_detach(struct socket *so)
 1251 {
 1252         struct ipxpcb *ipxp;
 1253         struct spxpcb *cb;
 1254 
 1255         /*
 1256          * XXXRW: Should assert appropriately detached.
 1257          */
 1258         ipxp = sotoipxpcb(so);
 1259         KASSERT(ipxp != NULL, ("spx_detach: ipxp == NULL"));
 1260 
 1261         cb = ipxtospxpcb(ipxp);
 1262         KASSERT(cb != NULL, ("spx_detach: cb == NULL"));
 1263 
 1264         IPX_LIST_LOCK();
 1265         IPX_LOCK(ipxp);
 1266         spx_pcbdetach(ipxp);
 1267         ipx_pcbdetach(ipxp);
 1268         ipx_pcbfree(ipxp);
 1269         IPX_LIST_UNLOCK();
 1270 }
 1271 
 1272 /*
 1273  * We may decide later to implement connection closing handshaking at the spx
 1274  * level optionally.  Here is the hook to do it:
 1275  */
 1276 static int
 1277 spx_usr_disconnect(struct socket *so)
 1278 {
 1279         struct ipxpcb *ipxp;
 1280         struct spxpcb *cb;
 1281         int error;
 1282 
 1283         ipxp = sotoipxpcb(so);
 1284         KASSERT(ipxp != NULL, ("spx_usr_disconnect: ipxp == NULL"));
 1285 
 1286         cb = ipxtospxpcb(ipxp);
 1287         KASSERT(cb != NULL, ("spx_usr_disconnect: cb == NULL"));
 1288 
 1289         IPX_LIST_LOCK();
 1290         IPX_LOCK(ipxp);
 1291         if (ipxp->ipxp_flags & IPXP_DROPPED) {
 1292                 error = EINVAL;
 1293                 goto out;
 1294         }
 1295         spx_disconnect(cb);
 1296         error = 0;
 1297 out:
 1298         IPX_UNLOCK(ipxp);
 1299         IPX_LIST_UNLOCK();
 1300         return (error);
 1301 }
 1302 
 1303 static int
 1304 spx_listen(struct socket *so, int backlog, struct thread *td)
 1305 {
 1306         int error;
 1307         struct ipxpcb *ipxp;
 1308         struct spxpcb *cb;
 1309 
 1310         error = 0;
 1311         ipxp = sotoipxpcb(so);
 1312         KASSERT(ipxp != NULL, ("spx_listen: ipxp == NULL"));
 1313 
 1314         cb = ipxtospxpcb(ipxp);
 1315         KASSERT(cb != NULL, ("spx_listen: cb == NULL"));
 1316 
 1317         IPX_LIST_LOCK();
 1318         IPX_LOCK(ipxp);
 1319         if (ipxp->ipxp_flags & IPXP_DROPPED) {
 1320                 error = EINVAL;
 1321                 goto out;
 1322         }
 1323         SOCK_LOCK(so);
 1324         error = solisten_proto_check(so);
 1325         if (error == 0 && ipxp->ipxp_lport == 0)
 1326                 error = ipx_pcbbind(ipxp, NULL, td);
 1327         if (error == 0) {
 1328                 cb->s_state = TCPS_LISTEN;
 1329                 solisten_proto(so, backlog);
 1330         }
 1331         SOCK_UNLOCK(so);
 1332 out:
 1333         IPX_UNLOCK(ipxp);
 1334         IPX_LIST_UNLOCK();
 1335         return (error);
 1336 }
 1337 
 1338 /*
 1339  * After a receive, possibly send acknowledgment updating allocation.
 1340  */
 1341 static int
 1342 spx_rcvd(struct socket *so, int flags)
 1343 {
 1344         struct ipxpcb *ipxp;
 1345         struct spxpcb *cb;
 1346         int error;
 1347 
 1348         ipxp = sotoipxpcb(so);
 1349         KASSERT(ipxp != NULL, ("spx_rcvd: ipxp == NULL"));
 1350 
 1351         cb = ipxtospxpcb(ipxp);
 1352         KASSERT(cb != NULL, ("spx_rcvd: cb == NULL"));
 1353 
 1354         IPX_LOCK(ipxp);
 1355         if (ipxp->ipxp_flags & IPXP_DROPPED) {
 1356                 error = EINVAL;
 1357                 goto out;
 1358         }
 1359         cb->s_flags |= SF_RVD;
 1360         spx_output(cb, NULL);
 1361         cb->s_flags &= ~SF_RVD;
 1362         error = 0;
 1363 out:
 1364         IPX_UNLOCK(ipxp);
 1365         return (error);
 1366 }
 1367 
 1368 static int
 1369 spx_rcvoob(struct socket *so, struct mbuf *m, int flags)
 1370 {
 1371         struct ipxpcb *ipxp;
 1372         struct spxpcb *cb;
 1373         int error;
 1374 
 1375         ipxp = sotoipxpcb(so);
 1376         KASSERT(ipxp != NULL, ("spx_rcvoob: ipxp == NULL"));
 1377 
 1378         cb = ipxtospxpcb(ipxp);
 1379         KASSERT(cb != NULL, ("spx_rcvoob: cb == NULL"));
 1380 
 1381         IPX_LOCK(ipxp);
 1382         if (ipxp->ipxp_flags & IPXP_DROPPED) {
 1383                 error = EINVAL;
 1384                 goto out;
 1385         }
 1386         SOCKBUF_LOCK(&so->so_rcv);
 1387         if ((cb->s_oobflags & SF_IOOB) || so->so_oobmark ||
 1388             (so->so_rcv.sb_state & SBS_RCVATMARK)) {
 1389                 SOCKBUF_UNLOCK(&so->so_rcv);
 1390                 m->m_len = 1;
 1391                 *mtod(m, caddr_t) = cb->s_iobc;
 1392                 error = 0;
 1393                 goto out;
 1394         }
 1395         SOCKBUF_UNLOCK(&so->so_rcv);
 1396         error = EINVAL;
 1397 out:
 1398         IPX_UNLOCK(ipxp);
 1399         return (error);
 1400 }
 1401 
 1402 static int
 1403 spx_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
 1404     struct mbuf *controlp, struct thread *td)
 1405 {
 1406         struct ipxpcb *ipxp;
 1407         struct spxpcb *cb;
 1408         int error;
 1409 
 1410         ipxp = sotoipxpcb(so);
 1411         KASSERT(ipxp != NULL, ("spx_send: ipxp == NULL"));
 1412 
 1413         cb = ipxtospxpcb(ipxp);
 1414         KASSERT(cb != NULL, ("spx_send: cb == NULL"));
 1415 
 1416         error = 0;
 1417         IPX_LOCK(ipxp);
 1418         if (ipxp->ipxp_flags & IPXP_DROPPED) {
 1419                 error = ECONNRESET;
 1420                 goto spx_send_end;
 1421         }
 1422         if (flags & PRUS_OOB) {
 1423                 if (sbspace(&so->so_snd) < -512) {
 1424                         error = ENOBUFS;
 1425                         goto spx_send_end;
 1426                 }
 1427                 cb->s_oobflags |= SF_SOOB;
 1428         }
 1429         if (controlp != NULL) {
 1430                 u_short *p = mtod(controlp, u_short *);
 1431                 spx_newchecks[2]++;
 1432                 if ((p[0] == 5) && (p[1] == 1)) { /* XXXX, for testing */
 1433                         cb->s_shdr.spx_dt = *(u_char *)(&p[2]);
 1434                         spx_newchecks[3]++;
 1435                 }
 1436                 m_freem(controlp);
 1437         }
 1438         controlp = NULL;
 1439         error = spx_output(cb, m);
 1440         m = NULL;
 1441 spx_send_end:
 1442         IPX_UNLOCK(ipxp);
 1443         if (controlp != NULL)
 1444                 m_freem(controlp);
 1445         if (m != NULL)
 1446                 m_freem(m);
 1447         return (error);
 1448 }
 1449 
 1450 static int
 1451 spx_shutdown(struct socket *so)
 1452 {
 1453         struct ipxpcb *ipxp;
 1454         struct spxpcb *cb;
 1455         int error;
 1456 
 1457         ipxp = sotoipxpcb(so);
 1458         KASSERT(ipxp != NULL, ("spx_shutdown: ipxp == NULL"));
 1459 
 1460         cb = ipxtospxpcb(ipxp);
 1461         KASSERT(cb != NULL, ("spx_shutdown: cb == NULL"));
 1462 
 1463         socantsendmore(so);
 1464         IPX_LIST_LOCK();
 1465         IPX_LOCK(ipxp);
 1466         if (ipxp->ipxp_flags & IPXP_DROPPED) {
 1467                 error = EINVAL;
 1468                 goto out;
 1469         }
 1470         spx_usrclosed(cb);
 1471         error = 0;
 1472 out:
 1473         IPX_UNLOCK(ipxp);
 1474         IPX_LIST_UNLOCK();
 1475         return (error);
 1476 }
 1477 
 1478 static int
 1479 spx_sp_attach(struct socket *so, int proto, struct thread *td)
 1480 {
 1481         struct ipxpcb *ipxp;
 1482         struct spxpcb *cb;
 1483         int error;
 1484 
 1485         KASSERT(so->so_pcb == NULL, ("spx_sp_attach: so_pcb != NULL"));
 1486 
 1487         error = spx_attach(so, proto, td);
 1488         if (error)
 1489                 return (error);
 1490 
 1491         ipxp = sotoipxpcb(so);
 1492         KASSERT(ipxp != NULL, ("spx_sp_attach: ipxp == NULL"));
 1493 
 1494         cb = ipxtospxpcb(ipxp);
 1495         KASSERT(cb != NULL, ("spx_sp_attach: cb == NULL"));
 1496 
 1497         IPX_LOCK(ipxp);
 1498         cb->s_flags |= (SF_HI | SF_HO | SF_PI);
 1499         IPX_UNLOCK(ipxp);
 1500         return (0);
 1501 }
 1502 
 1503 /*
 1504  * Create template to be used to send spx packets on a connection.  Called
 1505  * after host entry created, fills in a skeletal spx header (choosing
 1506  * connection id), minimizing the amount of work necessary when the
 1507  * connection is used.
 1508  */
 1509 static void
 1510 spx_template(struct spxpcb *cb)
 1511 {
 1512         struct ipxpcb *ipxp = cb->s_ipxpcb;
 1513         struct sockbuf *sb = &(ipxp->ipxp_socket->so_snd);
 1514 
 1515         IPX_LOCK_ASSERT(ipxp);
 1516 
 1517         cb->s_ipx.ipx_pt = IPXPROTO_SPX;
 1518         cb->s_ipx.ipx_sna = ipxp->ipxp_laddr;
 1519         cb->s_ipx.ipx_dna = ipxp->ipxp_faddr;
 1520         SPX_LOCK();
 1521         cb->s_sid = htons(spx_iss);
 1522         spx_iss += SPX_ISSINCR/2;
 1523         SPX_UNLOCK();
 1524         cb->s_alo = 1;
 1525         cb->s_cwnd = (sbspace(sb) * CUNIT) / cb->s_mtu;
 1526 
 1527         /*
 1528          * Try to expand fast to full complement of large packets.
 1529          */
 1530         cb->s_ssthresh = cb->s_cwnd;
 1531         cb->s_cwmx = (sbspace(sb) * CUNIT) / (2 * sizeof(struct spx));
 1532 
 1533         /*
 1534          * But allow for lots of little packets as well.
 1535          */
 1536         cb->s_cwmx = max(cb->s_cwmx, cb->s_cwnd);
 1537 }
 1538 
 1539 /*
 1540  * Close a SPIP control block.  Wake up any sleepers.  We used to free any
 1541  * queued packets, but now we defer that until the pcb is discarded.
 1542  */
 1543 void
 1544 spx_close(struct spxpcb *cb)
 1545 {
 1546         struct ipxpcb *ipxp = cb->s_ipxpcb;
 1547         struct socket *so = ipxp->ipxp_socket;
 1548 
 1549         KASSERT(ipxp != NULL, ("spx_close: ipxp == NULL"));
 1550         IPX_LIST_LOCK_ASSERT();
 1551         IPX_LOCK_ASSERT(ipxp);
 1552 
 1553         ipxp->ipxp_flags |= IPXP_DROPPED;
 1554         soisdisconnected(so);
 1555         spxstat.spxs_closed++;
 1556 }
 1557 
 1558 /*
 1559  * Someday we may do level 3 handshaking to close a connection or send a
 1560  * xerox style error.  For now, just close.  cb will always be invalid after
 1561  * this call.
 1562  */
 1563 static void
 1564 spx_usrclosed(struct spxpcb *cb)
 1565 {
 1566 
 1567         IPX_LIST_LOCK_ASSERT();
 1568         IPX_LOCK_ASSERT(cb->s_ipxpcb);
 1569 
 1570         spx_close(cb);
 1571 }
 1572 
 1573 /*
 1574  * cb will always be invalid after this call.
 1575  */
 1576 static void
 1577 spx_disconnect(struct spxpcb *cb)
 1578 {
 1579 
 1580         IPX_LIST_LOCK_ASSERT();
 1581         IPX_LOCK_ASSERT(cb->s_ipxpcb);
 1582 
 1583         spx_close(cb);
 1584 }
 1585 
 1586 /*
 1587  * Drop connection, reporting the specified error.  cb will always be invalid
 1588  * after this call.
 1589  */
 1590 static void
 1591 spx_drop(struct spxpcb *cb, int errno)
 1592 {
 1593         struct socket *so = cb->s_ipxpcb->ipxp_socket;
 1594 
 1595         IPX_LIST_LOCK_ASSERT();
 1596         IPX_LOCK_ASSERT(cb->s_ipxpcb);
 1597 
 1598         /*
 1599          * Someday, in the xerox world we will generate error protocol
 1600          * packets announcing that the socket has gone away.
 1601          */
 1602         if (TCPS_HAVERCVDSYN(cb->s_state)) {
 1603                 spxstat.spxs_drops++;
 1604                 cb->s_state = TCPS_CLOSED;
 1605                 /*tcp_output(cb);*/
 1606         } else
 1607                 spxstat.spxs_conndrops++;
 1608         so->so_error = errno;
 1609         spx_close(cb);
 1610 }
 1611 
 1612 /*
 1613  * Fast timeout routine for processing delayed acks.
 1614  */
 1615 void
 1616 spx_fasttimo(void)
 1617 {
 1618         struct ipxpcb *ipxp;
 1619         struct spxpcb *cb;
 1620 
 1621         IPX_LIST_LOCK();
 1622         LIST_FOREACH(ipxp, &ipxpcb_list, ipxp_list) {
 1623                 IPX_LOCK(ipxp);
 1624                 if (!(ipxp->ipxp_flags & IPXP_SPX) ||
 1625                     (ipxp->ipxp_flags & IPXP_DROPPED)) {
 1626                         IPX_UNLOCK(ipxp);
 1627                         continue;
 1628                 }
 1629                 cb = ipxtospxpcb(ipxp);
 1630                 if (cb->s_flags & SF_DELACK) {
 1631                         cb->s_flags &= ~SF_DELACK;
 1632                         cb->s_flags |= SF_ACKNOW;
 1633                         spxstat.spxs_delack++;
 1634                         spx_output(cb, NULL);
 1635                 }
 1636                 IPX_UNLOCK(ipxp);
 1637         }
 1638         IPX_LIST_UNLOCK();
 1639 }
 1640 
 1641 /*
 1642  * spx protocol timeout routine called every 500 ms.  Updates the timers in
 1643  * all active pcb's and causes finite state machine actions if timers expire.
 1644  */
 1645 void
 1646 spx_slowtimo(void)
 1647 {
 1648         struct ipxpcb *ipxp;
 1649         struct spxpcb *cb;
 1650         int i;
 1651 
 1652         /*
 1653          * Search through tcb's and update active timers.  Once, timers could
 1654          * free ipxp's, but now we do that only when detaching a socket.
 1655          */
 1656         IPX_LIST_LOCK();
 1657         LIST_FOREACH(ipxp, &ipxpcb_list, ipxp_list) {
 1658                 IPX_LOCK(ipxp);
 1659                 if (!(ipxp->ipxp_flags & IPXP_SPX) ||
 1660                     (ipxp->ipxp_flags & IPXP_DROPPED)) {
 1661                         IPX_UNLOCK(ipxp);
 1662                         continue;
 1663                 }
 1664 
 1665                 cb = (struct spxpcb *)ipxp->ipxp_pcb;
 1666                 KASSERT(cb != NULL, ("spx_slowtimo: cb == NULL"));
 1667                 for (i = 0; i < SPXT_NTIMERS; i++) {
 1668                         if (cb->s_timer[i] && --cb->s_timer[i] == 0) {
 1669                                 spx_timers(cb, i);
 1670                                 if (ipxp->ipxp_flags & IPXP_DROPPED)
 1671                                         break;
 1672                         }
 1673                 }
 1674                 if (!(ipxp->ipxp_flags & IPXP_DROPPED)) {
 1675                         cb->s_idle++;
 1676                         if (cb->s_rtt)
 1677                                 cb->s_rtt++;
 1678                 }
 1679                 IPX_UNLOCK(ipxp);
 1680         }
 1681         IPX_LIST_UNLOCK();
 1682         SPX_LOCK();
 1683         spx_iss += SPX_ISSINCR/PR_SLOWHZ;               /* increment iss */
 1684         SPX_UNLOCK();
 1685 }
 1686 
 1687 /*
 1688  * SPX timer processing.
 1689  */
 1690 static void
 1691 spx_timers(struct spxpcb *cb, int timer)
 1692 {
 1693         long rexmt;
 1694         int win;
 1695 
 1696         IPX_LIST_LOCK_ASSERT();
 1697         IPX_LOCK_ASSERT(cb->s_ipxpcb);
 1698 
 1699         cb->s_force = 1 + timer;
 1700         switch (timer) {
 1701         case SPXT_2MSL:
 1702                 /*
 1703                  * 2 MSL timeout in shutdown went off.  TCP deletes
 1704                  * connection control block.
 1705                  */
 1706                 printf("spx: SPXT_2MSL went off for no reason\n");
 1707                 cb->s_timer[timer] = 0;
 1708                 break;
 1709 
 1710         case SPXT_REXMT:
 1711                 /*
 1712                  * Retransmission timer went off.  Message has not been acked
 1713                  * within retransmit interval.  Back off to a longer
 1714                  * retransmit interval and retransmit one packet.
 1715                  */
 1716                 if (++cb->s_rxtshift > SPX_MAXRXTSHIFT) {
 1717                         cb->s_rxtshift = SPX_MAXRXTSHIFT;
 1718                         spxstat.spxs_timeoutdrop++;
 1719                         spx_drop(cb, ETIMEDOUT);
 1720                         break;
 1721                 }
 1722                 spxstat.spxs_rexmttimeo++;
 1723                 rexmt = ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1;
 1724                 rexmt *= spx_backoff[cb->s_rxtshift];
 1725                 SPXT_RANGESET(cb->s_rxtcur, rexmt, SPXTV_MIN, SPXTV_REXMTMAX);
 1726                 cb->s_timer[SPXT_REXMT] = cb->s_rxtcur;
 1727 
 1728                 /*
 1729                  * If we have backed off fairly far, our srtt estimate is
 1730                  * probably bogus.  Clobber it so we'll take the next rtt
 1731                  * measurement as our srtt; move the current srtt into rttvar
 1732                  * to keep the current retransmit times until then.
 1733                  */
 1734                 if (cb->s_rxtshift > SPX_MAXRXTSHIFT / 4 ) {
 1735                         cb->s_rttvar += (cb->s_srtt >> 2);
 1736                         cb->s_srtt = 0;
 1737                 }
 1738                 cb->s_snxt = cb->s_rack;
 1739 
 1740                 /*
 1741                  * If timing a packet, stop the timer.
 1742                  */
 1743                 cb->s_rtt = 0;
 1744 
 1745                 /*
 1746                  * See very long discussion in tcp_timer.c about congestion
 1747                  * window and sstrhesh.
 1748                  */
 1749                 win = min(cb->s_swnd, (cb->s_cwnd/CUNIT)) / 2;
 1750                 if (win < 2)
 1751                         win = 2;
 1752                 cb->s_cwnd = CUNIT;
 1753                 cb->s_ssthresh = win * CUNIT;
 1754                 spx_output(cb, NULL);
 1755                 break;
 1756 
 1757         case SPXT_PERSIST:
 1758                 /*
 1759                  * Persistance timer into zero window.  Force a probe to be
 1760                  * sent.
 1761                  */
 1762                 spxstat.spxs_persisttimeo++;
 1763                 spx_setpersist(cb);
 1764                 spx_output(cb, NULL);
 1765                 break;
 1766 
 1767         case SPXT_KEEP:
 1768                 /*
 1769                  * Keep-alive timer went off; send something or drop
 1770                  * connection if idle for too long.
 1771                  */
 1772                 spxstat.spxs_keeptimeo++;
 1773                 if (cb->s_state < TCPS_ESTABLISHED)
 1774                         goto dropit;
 1775                 if (cb->s_ipxpcb->ipxp_socket->so_options & SO_KEEPALIVE) {
 1776                         if (cb->s_idle >= SPXTV_MAXIDLE)
 1777                                 goto dropit;
 1778                         spxstat.spxs_keepprobe++;
 1779                         spx_output(cb, NULL);
 1780                 } else
 1781                         cb->s_idle = 0;
 1782                 cb->s_timer[SPXT_KEEP] = SPXTV_KEEP;
 1783                 break;
 1784 
 1785         dropit:
 1786                 spxstat.spxs_keepdrops++;
 1787                 spx_drop(cb, ETIMEDOUT);
 1788                 break;
 1789 
 1790         default:
 1791                 panic("spx_timers: unknown timer %d", timer);
 1792         }
 1793 }

Cache object: e8bcc6990954958d00f5f1b6470dec57


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