home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / TELECOM / UUCPbb_2_1_src.lzh / UUCPBB21 / gproto.c < prev    next >
Text File  |  1994-09-25  |  25KB  |  1,008 lines

  1. /*  gproto.c   These are the g protocol routines for UUCPbb package.
  2.     Copyright (C) 1990, 1993  Rick Adams and Bob Billson
  3.  
  4.     This file is part of the OS-9 UUCP package, UUCPbb.
  5.  
  6.     This program is free software; you can redistribute it and/or modify
  7.     it under the terms of the GNU General Public License as published by
  8.     the Free Software Foundation; either version 2 of the License, or
  9.     (at your option) any later version.
  10.  
  11.     This program is distributed in the hope that it will be useful,
  12.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.     GNU General Public License for more details.
  15.  
  16.     You should have received a copy of the GNU General Public License
  17.     along with this program; if not, write to the Free Software
  18.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  
  20.     The author of UUCPbb, Bob Billson, can be contacted at:
  21.     bob@kc2wz.bubble.org  or  uunet!kc2wz!bob  or  by snail mail:
  22.     21 Bates Way, Westfield, NJ 07090
  23. */
  24.  
  25. #include "uucp.h"
  26. #include "uucico.h"
  27.  
  28. #define CLOSE2    9                                 /* Added --BGP */
  29.  
  30. #ifdef DEBUG
  31. #define debuglvl ((int)0x62726164)
  32. #endif
  33.  
  34.  
  35. /* used for a quick calculation of packet sizes, only in this file */
  36. static uucpbufsiz[9] = {0, 32, 64, 128, 256, 512, 1024, 2048, 4096};
  37.  
  38. /* This variable tells swin_flush() to accept a LDATA(HY) in response to
  39.    a LDATA(HY) sent by us.  Normally, only an RR or RJ are accepted -- BAS */
  40.  
  41. static QQ flag eat_HY = FALSE;                             /* BAS */
  42. static char msg[200];
  43.  
  44.  
  45. int gproto()
  46. {
  47.      register flag state;
  48.      short length, i;
  49.      int qq = 0;
  50.  
  51.      /* sseq needs to be initialized for wtcontrol */
  52.      sseq = 0;
  53.  
  54.      /* Tell remote the window size we can handle */
  55.      wtcontrol (INITA | rec_window);
  56.  
  57.      if (rdpacket (msg, &length) != INITA)
  58.        {
  59.           logerror ("bad response to INITA");
  60.           return (ABORT);
  61.        }
  62.  
  63.      /* get the size the remote can handle */
  64.      winsiz = inpacket.C & 0x07;
  65.  
  66.      /* Use the window size the remote sent us or our size, whichever is
  67.         smaller. */
  68.  
  69.      winsiz = min (rec_window, winsiz);
  70.  
  71.      /* Set data packet size */
  72.      if (debuglvl > 4)
  73.           fprintf (log, "Sent: INITB %d\n", rec_segment);
  74.  
  75.      wtcontrol (INITB | rec_segment-1);
  76.  
  77.      if (rdpacket (msg, &length) != INITB)
  78.        {
  79.           logerror ("bad response to INITB");
  80.           return (ABORT);
  81.        }
  82.  
  83.      /* Get the data segment size the remote wants to use. */
  84.      segsiz = inpacket.C & 0x07;
  85.  
  86.      /* Tell the remote the window we will use. */
  87.      wtcontrol (INITC | winsiz);
  88.  
  89.      for (i = 0; i < 4; ++i)
  90.           if (rdpacket (msg, &length) != INITC)
  91.                logerror ("bad response to INITC");
  92.           else
  93.                break;
  94.  
  95.      winsiz = inpacket.C & 0x07;
  96.  
  97.      if (debuglvl > 0)
  98.           fprintf (log,
  99.                    "%s %s %s DEBUG--gproto: protocol started; segsize = %d, winsize = %d\n",
  100.                    sender, sysname, gtime(), segsiz, winsiz);
  101.  
  102.      for (rseq = sseq = 0, state = role;;)
  103.           switch (state)
  104.             {
  105.                case MASTER:
  106.                     state = master();
  107.                     break;
  108.  
  109.                case SLAVE:
  110.                     state = slave();
  111.                     break;
  112.  
  113.                /* The close sequence can be started from either side. This
  114.                   is the case when we have not been sent a CLOSE yet. -BAS
  115.  
  116.                   That is:
  117.                       US          THEM
  118.  
  119.                       CLOSE  ->
  120.                              <-   CLOSE */
  121.  
  122.                case CLOSE:
  123.                     /* close up shop */
  124.                     for (i = 0; i < 3; i++)
  125.                       {
  126.                          wtcontrol (CLOSE);
  127.  
  128.                          if (rdpacket (msg, &length) == CLOSE)
  129.                               return (_END);
  130.                       }
  131.                     break;
  132.  
  133.                /* This case should handle that case where we have been sent a
  134.                   CLOSE. The CLOSE itself is read by master() and slave() -BAS
  135.  
  136.                   That is:
  137.                      US        THEM
  138.                            <-   CLOSE [read at master() or slave()]
  139.                      CLOSE ->  */
  140.  
  141.                case CLOSE2:
  142.                     wtcontrol (CLOSE);
  143.                     return (_END);
  144.                     break;
  145.             }
  146. }
  147.  
  148.  
  149.  
  150. /* This should ONLY be executed when the role is MASTER otherwise, things
  151.    will get confused --BAS */
  152.  
  153.  
  154. int master()
  155. {
  156.      register int type;
  157.      int len;
  158.  
  159.      /* find and perform all queued work as master */
  160.      findwork();
  161.      
  162. #ifndef DEBUG
  163.      if (debuglvl > 1)
  164.           fputs ("master: asking remote if it has work for us\n", log);
  165. else      
  166.      if (debuglvl > 1)
  167.           fputs ("master: sending H to Slave to see if it has work for us\n",
  168.                  log);
  169. #endif
  170.  
  171.      /* does other system have queued work for us? */
  172.      wtmsg ("H");
  173.  
  174. #ifdef DEBUG
  175.      fputs("master: Sent H to slave\n",log);
  176. #endif
  177.  
  178.      /* The only valid responses from H should be HY or HN.  An HN means that
  179.         the slave has work to do and roles should be switched.  HY means it's
  180.         ok to begin to shut the protocol down --BAS */
  181.  
  182. #ifdef DEBUG
  183.      fputs("master: About to read an HY or HN from slave\n",log);
  184. #endif
  185.  
  186.      rdmsg (msg);
  187.  
  188. #ifdef DEBUG
  189.      fputs("master: Read an HY or HN from slave\n",log);
  190. #endif
  191.  
  192.      if (strncmp (msg, "HN", 2) == 0)
  193.        {
  194.           if (debuglvl > 1)
  195.                fputs ("master: Slave wants to reverse roles\n", log);
  196.  
  197.           role = SLAVE;
  198.           return (SLAVE);
  199.        }
  200.  
  201.      /* We should probably check to make sure that message was an HY --BAS */
  202.  
  203. #ifndef DEBUG
  204.      if (debuglvl > 1)
  205.           fputs ("master: remote says no, hang up\n", log);
  206. #else
  207.      if (debuglvl > 1)
  208.           fputs ("master: slave must want to quit\n", log);
  209.  
  210.      fputs ("master: About to send final HY to slave\n", log);
  211. #endif
  212.  
  213.      /* We need to munch an LDATA(HY) when we run Taylor UUCP  -- BAS */
  214.      eat_HY = TRUE;
  215.      swin_send (LDATA,"HY",2);
  216.      eat_HY = FALSE;
  217.  
  218. #ifdef DEBUG
  219.      fputs ("master: Sent final HY to slave\n", log);
  220. #endif
  221.  
  222.      if (debuglvl > 3)
  223.        fputs ("master: About to read last message from slave\n", log);
  224.  
  225.      type = getpacket (msg, &len);
  226.  
  227. #ifdef DEBUG
  228.      fputs ("master: Got last message from slave\n", log);
  229. #endif
  230.  
  231.      switch (type)
  232.        {
  233.           /* This case takes care of any LDATA or SDATA packets at the end
  234.              Apparently Ultrix uucico sends this -- BAS */
  235.  
  236.           case LDATA:
  237.           case SDATA:
  238.                if (debuglvl > 3)
  239.                     fputs ("master: slave sent us a LDATA or SDATA, RR it and send a CLOSE.\n",
  240.                            log);
  241.  
  242.                rseq = (++rseq & 0x07);
  243.                wtcontrol (RR | rseq);
  244.                break;
  245.  
  246.           /* This is the usual case for Sun uucico [really System V, I think]
  247.               and whatever UUNET Tech. uses. -- BAS */
  248.  
  249.           case RR:
  250.                if (debuglvl > 3)
  251.                     fputs ("master: slave sent us an RR, send them CLOSE.\n",
  252.                            log);
  253.  
  254.               return (CLOSE);
  255.               break;
  256.  
  257.           /* This seems to be the usual case for Taylor UUCP. -- BAS */
  258.           case CLOSE:
  259.                if (debuglvl > 3)
  260.                     fputs ("master: slave sent us an CLOSE, send them one.\n",
  261.                            log);
  262.  
  263.                return (CLOSE2);
  264.                break;
  265.  
  266.           /* This may handle everything else, maybe not???  Who knows....
  267.              -- BAS */
  268.  
  269.           default:
  270.                if (debuglvl > 1)
  271.                  {
  272.                     fprintf (log,
  273.                              "master: slave sent us something--> %d\n",
  274.                              type);
  275.                     fputs ("          send them a CLOSE.\n", log);
  276.                  }
  277.                break;
  278.        }
  279.      return (CLOSE);
  280. }
  281.  
  282.  
  283.  
  284. /* This should ONLY be executed when role is SLAVE, otherwise things will get
  285.    confused.  --BAS */
  286.  
  287. int slave()
  288. {
  289.      register int type;
  290.      int len;
  291.  
  292.      /* do all the queued work for us */
  293.      for (rdmsg (msg);  strcmp (msg, "H") != 0;  rdmsg (msg))
  294.        {
  295.           if (debuglvl > 1)                                        /* DEBUG */
  296.                fprintf (log, "DEBUG--slave: cline=%s:\n", msg);
  297.  
  298.           slavework (msg);
  299.        }
  300.  
  301.      /* We need to check to see if we have any work to send --BAS */
  302.      if (anywork() == 1)
  303.        {
  304.           if (debuglvl > 3)
  305.                fputs ("slave: switch roles, send HN to master\n", log);
  306.  
  307.           wtmsg ("HN");
  308.  
  309. #ifdef DEBUG
  310.           fputs ("slave: Sent an HN to master\n", log);
  311. #endif
  312.           role = MASTER;
  313.           return (MASTER);
  314.        }
  315.  
  316.      if (debuglvl > 3)
  317.           fputs ("slave: slave has no work to do, send last HY to master\n",
  318.                  log);
  319.  
  320.      wtmsg ("HY");
  321.  
  322. #ifdef DEBUG
  323.      fputs ("slave: Sent last HY to master\n", log);
  324. #endif
  325.  
  326.      if (debuglvl > 3)
  327.           fputs ("slave: read last message from master\n", log);
  328.  
  329.      /* According to the spec. on the 'g' protocol, the only thing that should
  330.         be sent from the master is a LDATA(HY), however, at least Ultrix
  331.         uucico will send a CLOSE.  Nice huh?... --BAS */
  332.  
  333.      type = getpacket (msg, &len);
  334.  
  335. #ifdef DEBUG
  336.      fputs ("slave: Got last message from master\n", log);
  337. #endif
  338.  
  339.      switch (type)
  340.        {
  341.           /* This seems to be the usual case for Sun and Taylor, most uucicos,
  342.              I think -- BAS */
  343.  
  344.           case LDATA:
  345.           case SDATA:
  346.                if (debuglvl > 3)
  347.                     fputs ("slave: master sent us a LDATA or SDATA, RR it and send a CLOSE.\n",
  348.                            log);
  349.  
  350.                rseq = (++rseq & 0x07);
  351.                wtcontrol (RR | rseq);
  352.                break;
  353.  
  354.           /* Never seen this one actually execute.  -- BAS */
  355.           case RR:
  356.                if (debuglvl > 3)
  357.                     fputs ("slave: master sent us an RR, send them CLOSE.\n",
  358.                            log);
  359.  
  360.                return (CLOSE);
  361.                break;
  362.  
  363.           /* Ultrix apparently sends this.  -- BAS */
  364.           case CLOSE:
  365.                if (debuglvl > 3)
  366.                     fputs ("slave: master sent us an CLOSE, send them one.\n",
  367.                            log);
  368.  
  369.                return (CLOSE2);
  370.                break;
  371.  
  372.           /* Don't know what this could be, really.... -- BAS */
  373.           default:
  374.                if (debuglvl > 1)
  375.                  {
  376.                     fprintf (log,
  377.                              "slave: master sent us something--> %d\n", type);
  378.                     fputs ("          send them a CLOSE.\n", log);
  379.                  }
  380.                break;
  381.        }
  382.      return (CLOSE);
  383. }
  384.  
  385.  
  386.  
  387. /* swin_init   initialize sending window */
  388.  
  389. int swin_init()
  390. {
  391.      swin = sseq;
  392. }
  393.  
  394.  
  395.  
  396. /* swin_send   Send one packet, update window if reply is ready return only if
  397.                window is not fully extended. */
  398.  
  399. int swin_send (type, data, length)
  400. char type, *data;
  401. int length;
  402. {
  403.      /* send current packet */
  404.      sseq = (++sseq & 7);
  405.      wtdata (type, data, length);
  406.      swin_flush (FALSE);
  407. }
  408.  
  409.  
  410.  
  411. /* swin_flush  wait for sending window to be emptied
  412.       if sw_flag == TRUE, return when swin == sseq
  413.       if sw_flag != TRUE, return when window is not fully extended */
  414.  
  415. int swin_flush (sw_flag)
  416. int sw_flag;
  417. {
  418.      char tseq = sseq;
  419.      register int type;
  420.      int length, size;
  421.      flag ready = TRUE;
  422.      struct pk *outp;
  423. #ifndef _OSK
  424.      unsigned cksum;
  425. #else
  426.      unsigned short cksum;
  427. #endif
  428.  
  429.      /* read response if one is ready
  430.         on error, retransmit all packets up to sseq
  431.         return only when it's safe to send another packet
  432.            ie: if window is full, wait for response from remote.
  433.  
  434.         Eddie Kuns fixed a bug in the original routine where retransmitting
  435.         a block required that some values be updated first.  Eddie's fix is
  436.         included here. */
  437.  
  438.      do
  439.        {
  440.           /* If we have to retransmit a packet, do so */
  441.           if (tseq != sseq)
  442.             {
  443.                tseq = (++tseq & 7);
  444.                outp = &(outpacket[tseq]);
  445.  
  446.                size = uucpbufsiz[outp->K];
  447.  
  448.                /* get old data checksum so we can update it later */
  449.                cksum = MAGIC - ((outp->C0 & 0xff) | (outp->C1 << 8));
  450.                cksum ^= (outp->C & 0xFF);
  451.  
  452.                /* first update "last packet read" counter */
  453.                outp->C &= 0xf8;
  454.                outp->C |= rseq & 0x7;
  455.  
  456.                /* now update checksums */
  457.                cksum = MAGIC - (cksum ^ (outp->C & 0xFF));
  458.                outp->C0 = cksum & 0xFF;
  459.                outp->C1 = (cksum >> 8) & 0xFF;
  460.  
  461.                outp->X = outp->K ^ outp->C0 ^ outp->C1 ^ outp->C;
  462.  
  463.                write(port, outp, size + 6);
  464.  
  465.                if (debuglvl > 4)
  466.                     dumpcode("R> ", outp);
  467.  
  468.                if (debuglvl > 8)
  469.                 {
  470.                     fputs ("        ", log);
  471.                     strdump (outp->data);
  472.                 }
  473.             }
  474.  
  475.           /* read reply if one is waiting
  476.              if we cannot exit yet, force reading a packet
  477.              if retransmitting packets, do not force reading a packet.
  478.  
  479.              _gs_rdy() is necessary, sliding windows are disabled otherwise */
  480.  
  481.           if (_gs_rdy (port) > 0  ||  (!ready && tseq == sseq))
  482.             {
  483.                type = getpacket (msg, &length);
  484.  
  485.                /* This is a bit of a hack to keep master() clean.  Taylor
  486.                   UUCP, and perhaps others, like to send strange things at the
  487.                   shutdown of the protocol --BAS */
  488.  
  489.                if (eat_HY  &&  type == LDATA)
  490.                     if (strncmp (msg, "HY", 2) == 0)
  491.                       {
  492.                          if (debuglvl > 3)
  493.                               fputs ("swin_flush: eating an LDATA(HY) and sending RR\n",
  494.                                      log);
  495.  
  496.                          /* Tell a bit of a lie to the switch statement that
  497.                             follows... -- BAS */
  498.                          type = RR;
  499.                          rseq = (++rseq & 0x07);
  500.                          wtcontrol (RR | rseq);
  501.                       }
  502.  
  503.                switch (type)
  504.                  {
  505.                     /* All is OK! */
  506.                     case RR:
  507.                          swin = inpacket.C & 7;        /* slide window here */
  508.                          break;
  509.  
  510.                     /* Error detected */
  511.                     case RJ:
  512.                          swin = inpacket.C & 7;         /* last good packet */
  513.                          tseq = swin;          /* retransmit at next packet */
  514.                          break;
  515.  
  516.                     /* Huh?  Unexpected packet type!  Log error. --REB */
  517.                     default:
  518.                          if (debuglvl > 0)
  519.                               fprintf (log,
  520.                                        "\n%s %s %s Unexpected packet type: $%X msg = %s\n",
  521.                                        sender, sysname, gtime(), type, msg);
  522.                  }
  523.             }
  524.  
  525.           /* set value of "ready"
  526.              TRICK: open window = ((sseq + 7) - swin) & 7
  527.                                 = (sseq - swin) & 7
  528.                     even when sseq < swin! */
  529.  
  530.           if (sw_flag)
  531.                ready = (swin == sseq);
  532.           else
  533.                ready = (((sseq - swin) & 7) < winsiz);
  534.        }
  535.      while (tseq != sseq || !ready);
  536. }
  537.  
  538.  
  539.  
  540. /* wtdata  --packetize data + send.  Don't wait for response */
  541.  
  542. int wtdata (type, data, length)
  543. char type, *data;
  544. int length;
  545. {
  546.      register struct pk *outp;
  547. #ifdef _OSK
  548.      short cksum;
  549. #else
  550.      unsigned cksum;
  551. #endif
  552.      int size, diff, i;
  553.      char *p;
  554.  
  555.      outp = &(outpacket[sseq]);
  556.  
  557.      for (i = 0; i < 64; i++)
  558.           outp->data[i] = 0;
  559.  
  560.      outp->DLE = 0x10;
  561.      p = outp->data;
  562.      outp->C = type;
  563.  
  564.      if (type == (char) SDATA)
  565.        {
  566.           size = 64;
  567.           outp->K = K64;
  568.           diff = size - length;
  569.  
  570.           if ((diff & 0x80) == 0)
  571.                *p++ = (diff & 0xFF);
  572.           else
  573.             {
  574.                *p++ = (diff & 0xFF) | 0x80;
  575.                *p++ = diff >> 7;
  576.             }
  577.        }
  578.      else
  579.        {
  580.           size = 64;          /* our packet size */
  581.           outp->K = K64;
  582.        }
  583.  
  584.      outp->C |= (sseq & 0x7) << 3;
  585.      outp->C |= rseq & 0x7;
  586.  
  587.      /* Move data into outgoing packet */
  588.      memcpy (p, data, length < size ? length : size);
  589.  
  590.      cksum = MAGIC - (g_chksum (outp->data, size) ^ (outp->C & 0xFF));
  591.      outp->C0 = cksum & 0xFF;
  592.      outp->C1 = (cksum >> 8) & 0xFF;
  593.  
  594.      outp->X = outp->K ^ outp->C0 ^ outp->C1 ^ outp->C;
  595.  
  596.      if (debuglvl > 7)
  597.          dumpcode (">> ", outp);
  598.  
  599.      write (port, outp, size + 6);
  600. }
  601.  
  602.  
  603.  
  604. /* wtmsg   --write g-proto message, wait for RR */
  605.  
  606. int wtmsg (message)
  607. char *message;
  608. {
  609.      register char *p;
  610.  
  611.      if (debuglvl >= 5)
  612.           fprintf (log, ">> %s\n", message);
  613.  
  614.      p = message;
  615.  
  616.      /* initialize sliding windows */
  617.      swin_init();
  618.  
  619.      /* send message; swin_send updates sseq */
  620.      do
  621.        {
  622.           int lenp = strlen (p);
  623.  
  624.           /* write data packet containing message */
  625.           swin_send (LDATA, p, lenp);
  626.           p += lenp < 64  ? lenp : 64;
  627.        }
  628.      while (*p);
  629.  
  630.      /* make sure all packets are sent */
  631.      swin_flush (TRUE);
  632. }
  633.  
  634.  
  635.  
  636. /* wtcontrol  --write control packet, don't wait for response */
  637.  
  638. int wtcontrol (code)
  639. register int code;
  640. {
  641.      static struct pk outp;
  642. #ifdef _OSK
  643.      short cksum;
  644. #else
  645.      int cksum;
  646. #endif
  647.  
  648.      code &= 0xFF;
  649.      outp.DLE = 0x10;
  650.      outp.K = KCONTROL;
  651.      outp.C = code;
  652.      cksum = MAGIC - code;
  653.      outp.C0 = cksum & 0xFF;
  654.      outp.C1 = (cksum >> 8) & 0xFF;
  655.      outp.X = outp.K ^ outp.C0 ^ outp.C1 ^ code;
  656.  
  657.      if (debuglvl > 7)
  658.           dumpcode (">> ", &outp);
  659.  
  660.      write (port, &outp, 6);
  661. }
  662.  
  663.  
  664.  
  665. /* rdpacket  --read a packet
  666.  
  667.          Return:
  668.              data
  669.              length of data (zero if no data)
  670.              type of packet (CLOSE, LDATA, SDATA, RR, INITA, etc) */
  671.  
  672. int rdpacket (data, length)
  673. char *data;
  674. int  *length;
  675. {
  676.      char c, *p;
  677. #ifdef _OSK
  678.      short cksum;
  679. #else
  680.      unsigned cksum;
  681. #endif
  682.      int diff = 0, type;
  683.  
  684.      *length = 0;
  685.      *data = '\0';
  686.  
  687.      /* scan for leading DLE */
  688.      do
  689.        {
  690.           if (readport (&c, PKTTIME, GET_TRY) == TIMEDOUT)
  691.                longjmp (env, FATAL);
  692.        }
  693.      while (c != 0x10);
  694.  
  695.      inpacket.DLE = c;
  696.  
  697.      /* read packet header */
  698.      if (readport (&inpacket.K, PKTTIME, MAXTRY) == TIMEDOUT)
  699.           longjmp (env, FATAL);
  700.  
  701.      if (readport (&inpacket.C0, PKTTIME, MAXTRY) == TIMEDOUT)
  702.           longjmp (env, FATAL);
  703.  
  704.      if (readport (&inpacket.C1, PKTTIME, MAXTRY) == TIMEDOUT)
  705.           longjmp (env, FATAL);
  706.  
  707.      if (readport (&inpacket.C, PKTTIME, MAXTRY) == TIMEDOUT)
  708.           longjmp (env, FATAL);
  709.  
  710.      if (readport (&inpacket.X, PKTTIME, MAXTRY) == TIMEDOUT)
  711.           longjmp (env, FATAL);
  712.  
  713.      /* return type of packet */
  714.      if ((inpacket.C & 0xC0) == 0)
  715.           type = inpacket.C & 0x38;
  716.      else
  717.           type = inpacket.C & 0xC0;
  718.  
  719.      /* check XOR checksum of packet */
  720.      if ((inpacket.K ^ inpacket.C0 ^ inpacket.C1 ^ inpacket.C) != inpacket.X)
  721.           return (FALSE);
  722.  
  723.      if (debuglvl > 7)
  724.           dumpcode ("<< ", &inpacket);
  725.  
  726.      /* control packet? */
  727.      if (inpacket.K == KCONTROL)
  728.           return (type);
  729.  
  730.      /* if not control packet, read data */
  731.      if (inpacket.K != KCONTROL)
  732.        {
  733.           if (inpacket.K == 0)
  734.                *length = 0;
  735.           else
  736.             {
  737.                *length = uucpbufsiz[inpacket.K];
  738.  
  739.                /* If we don't get a whole packet, return error */
  740.                if (readfill (inpacket.data, *length) != *length)
  741.                     return (FALSE);
  742.             }
  743.         }
  744.  
  745.      cksum = MAGIC - (g_chksum (inpacket.data, *length)
  746.               ^(inpacket.C & 0xFF));
  747.  
  748.      /* short data packet, or long data packet? */
  749.      if ((inpacket.C & 0xC0) == SDATA)
  750.        {
  751.           /* short data packet */
  752.           diff = inpacket.data[0] & 0xFF;
  753.           p = inpacket.data;
  754.  
  755.           if ((diff & 0x80) == 0)
  756.             {
  757.                *length -= diff;
  758.                p++;
  759.             }
  760.           else
  761.             {
  762.                diff &= 0x7F;
  763.                diff |= ((inpacket.data[1] & 0xFF) << 7);
  764.                *length -= diff;
  765.                p += 2;
  766.             }
  767.        }
  768.      else
  769.        {
  770.           /* long data packet */
  771.           p = inpacket.data;
  772.        }
  773.  
  774.      /* check checksum of data portion */
  775.      if (cksum != ((inpacket.C1 << 8) | (inpacket.C0 & 0xFF)))
  776.           return (FALSE);
  777.      else
  778.        {
  779.           if (*length)
  780.                memcpy (data, p, *length);
  781.  
  782.           return (type);
  783.        }
  784. }
  785.  
  786.  
  787.  
  788. /* rdmsg  --read g-proto message */
  789.  
  790. int rdmsg (message)
  791. char *message;
  792. {
  793.      register int i;
  794.      int msglen, length, type;
  795.      char *p;
  796.  
  797.      p = message;
  798.  
  799.      do
  800.        {
  801.           for (i = 0; i < GET_TRY; i++)
  802.                if ((type = getpacket (p, &length)) == LDATA || type == SDATA)
  803.                  {
  804.                     rseq = (++rseq & 0x7);
  805.                     wtcontrol (RR | rseq);
  806.                     break;
  807.                  }
  808.  
  809.           /* fatal error abort back to uucico() */
  810.           if (i == GET_TRY)
  811.             {
  812.                logerror ("rdmsg: didn't get message");
  813.                longjmp (env, FATAL);
  814.             }
  815.  
  816.           msglen = strlen (inpacket.data);
  817.           p += msglen;
  818.  
  819.        }
  820.      while (type == LDATA && length == msglen);
  821.  
  822.      if (debuglvl > 4)
  823.           fprintf (log, "<< %s\n", message);
  824. }
  825.  
  826.  
  827.  
  828. /* getpacket   --get data packet */
  829.  
  830. int getpacket (data, length)
  831. char *data;
  832. int *length;
  833. {
  834.      int status;
  835.      register int tries;
  836.  
  837.      for (tries = 0; tries < GET_TRY; tries++)
  838.        {
  839.           status = rdpacket (data, length);
  840.  
  841.           if (!status)
  842.                wtcontrol (RJ | rseq);
  843.           else
  844.                return (status);
  845.        }
  846.  
  847.      /* If we get too many errors, abort to highest level and exit. */
  848.      putc ('\n', log);
  849.      logerror ("getpacket: too many checksum errors in received packets");
  850.      fputs ("                       *** TRANSFER ABORTED ***\n", log);
  851.      longjmp (env, FATAL);
  852. }
  853.  
  854.  
  855.  
  856. /*========== Calculate checksum routines for 6809, 6309 and OSK ==========*/
  857.  
  858. #ifdef _OSK
  859. /* g_chksum for OSK borrowed from Taylor UUCP */
  860.  
  861. int g_chksum (z, c)
  862. register char *z;
  863. register int c;
  864. {
  865.      register unsigned int ichk1, ichk2;
  866.  
  867.      ichk1 = 0xffff;
  868.      ichk2 = 0;
  869.  
  870.      do
  871.        {
  872.           register unsigned int b;
  873.  
  874.           /* rotate ichk1 left */
  875.           if ((ichk1 & 0x8000) == 0)
  876.                ichk1 <<= 1;
  877.           else
  878.             {
  879.                ichk1 <<= 1;
  880.                ++ichk1;
  881.             }
  882.  
  883.           /* add next character to ichk1 */
  884.           b = *z++ & 0xff;
  885.           ichk1 += b;
  886.  
  887.           /* add ichk1 xor the checksum position in the buffer counting
  888.              from the back to ichk2. */
  889.           ichk2 += ichk1 ^ c;
  890.  
  891.           /* if the character was zero, or adding it to ichk1 causes
  892.              an overflow, xor ichk2 to ichk1 */
  893.           if (b == 0  ||  (ichk1 & 0xffff)  < b)
  894.                ichk1 ^= ichk2;
  895.        }
  896.      while (--c > 0);
  897.  
  898.      return (ichk1 & 0xffff);
  899. }
  900.  
  901. #else
  902.  
  903. #  ifndef m6309
  904. #  asm        assembler routine for OS9/6809 using 6809
  905.  
  906. *        Remember below that C identifiers are 8 characters long
  907.  
  908.  vsect dp
  909. ChkSum rmb 2
  910. X      rmb 2
  911.  endsect
  912.  
  913. g_chksum:
  914.  ldd #0
  915.  std  <X
  916.  deca
  917.  decb
  918.  std  <ChkSum
  919.  
  920.  pshs u,y
  921.  ldu  6,s       Get pointer into U.
  922.  ldy  8,s       Get count into Y
  923.  beq  Fin_CRC   In case the count = 0
  924. Upd_CRC1
  925.  ldd  <ChkSum
  926.  aslb           ChkSum <<= 1  (and += 1 if negative)
  927.  rola
  928.  adcb #0
  929.  std  <ChkSum
  930.  pshs d         t = chksum
  931.  clra           chksum += *(s++)
  932.  ldb  ,u+
  933.  addd ,s
  934.  std  <ChkSum
  935.  pshs y         X += chksum ^ n
  936.  eora ,s+
  937.  eorb ,s+
  938.  addd <X
  939.  std  <X
  940.  ldd  <ChkSum   if ( (unsigned) chksum <= t)
  941.  cmpd ,s++
  942.  bhi  Next
  943.  eora <X                 chksum ^= x;
  944.  eorb <X+1
  945.  std  <ChkSum
  946. Next
  947.  leay -1,y
  948.  bne  Upd_CRC1
  949. Fin_CRC
  950.  puls u,y,pc
  951.  
  952. #  endasm
  953.  
  954. #  else
  955. #  asm        assembler routine for OS9/6809 using 6309
  956.  
  957. *             This routine uses the W register.  It assumes OS-9's kernel is
  958. *             patched so it does not destroy the contents of W during
  959. *             interrupts.  Burke & Burke's PowerBoost is an example of such
  960. *             a patch.
  961.  
  962. *        Remember below that C identifiers are 8 characters long
  963.  
  964.  vsect dp
  965. ChkSum rmb 2
  966. X      rmb 2
  967.  endsect
  968.  
  969. g_chksum:
  970.  fdb  $104f    clrd
  971.  std  <X
  972.  fdb  $104a    decd
  973.  std  <ChkSum
  974.  pshs u,y
  975.  ldu  6,s       Get pointer into U.
  976.  ldy  8,s       Get count into Y
  977.  beq  Fin_CRC   In case the count = 0
  978.  
  979. Upd_CRC1
  980.  ldd  <ChkSum
  981.  fdb  $1048        asld      ChkSum <<= 1  (and += 1 if negative)
  982.  adcb #0
  983.  std  <ChkSum
  984.  fdb $1f06         tfr d,w    t = chksum
  985.  clra                         chksum += *(s++)
  986.  ldb  ,u+
  987.  fcb $10,$30,$60   addr w,d
  988.  std  <ChkSum
  989.  fcb $10,$36,$20   eorr y,d   X += chksum ^ n
  990.  addd <X
  991.  std  <X
  992.  ldd  <ChkSum                 if ( (unsigned) chksum <= t)
  993.  fcb $10,$37,$60   cmpr w,d
  994.  bhi  Next
  995.  eora <X                      chksum ^= x;
  996.  eorb <X+1
  997.  std  <ChkSum
  998.  
  999. Next
  1000.  leay -1,y
  1001.  bne  Upd_CRC1
  1002.  
  1003. Fin_CRC
  1004.  puls u,y,pc
  1005. #  endasm
  1006. #  endif
  1007. #endif
  1008.