1995-08-19 21:30:30 +00:00
|
|
|
|
/* proty.c
|
|
|
|
|
The 'y' protocol.
|
|
|
|
|
|
|
|
|
|
Copyright (C) 1994, 1995 Jorge Cwik and Ian Lance Taylor
|
|
|
|
|
|
|
|
|
|
This file is part of the Taylor UUCP package.
|
|
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
|
|
|
modify it under the terms of the GNU General Public License as
|
|
|
|
|
published by the Free Software Foundation; either version 2 of the
|
|
|
|
|
License, or (at your option) any later version.
|
|
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful, but
|
|
|
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
General Public License for more details.
|
|
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "uucp.h"
|
|
|
|
|
|
|
|
|
|
#if USE_RCS_ID
|
1997-02-22 15:28:58 +00:00
|
|
|
|
const char proty_id[] = "$Id$";
|
1995-08-19 21:30:30 +00:00
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#include "uudefs.h"
|
|
|
|
|
#include "uuconf.h"
|
|
|
|
|
#include "conn.h"
|
|
|
|
|
#include "trans.h"
|
|
|
|
|
#include "system.h"
|
|
|
|
|
#include "prot.h"
|
|
|
|
|
|
|
|
|
|
/* The 'y' protocol, and this implementation, was written and designed
|
|
|
|
|
by Jorge Cwik <jorge@satlink.net>. Some of the routines, and the
|
|
|
|
|
coding style in general, were taken verbatim or adapted from other
|
|
|
|
|
Taylor UUCP modules. Mark Delany made the initial testings and
|
|
|
|
|
helped in portability issues.
|
|
|
|
|
|
|
|
|
|
This protocol does not perform any kind of error correction or flow
|
|
|
|
|
control. It does do error checking. It does not require an end to
|
|
|
|
|
end reliable link. It is recommended for error-free (also called
|
|
|
|
|
semi-reliable) connections as provided by error correcting modems.
|
|
|
|
|
It needs an eight bit clean channel and some kind of flow control
|
|
|
|
|
at the lower layers, typically RTS/CTS hardware flow control.
|
|
|
|
|
|
|
|
|
|
The flow of the file transmission is completely unidirectional.
|
|
|
|
|
There are no ACKs or NAKs outside file boundaries. This makes it
|
|
|
|
|
very suitable for half duplex modulations (like PEP) and
|
|
|
|
|
connections with very long delays, like multihop satellite links. */
|
|
|
|
|
|
|
|
|
|
/* This protocol uses 16 bit little-endian ints in the packet header. */
|
|
|
|
|
#define FROMLITTLE(p) (((p)[0] & 0xff) + (((p)[1] & 0xff) << 8))
|
|
|
|
|
#define TOLITTLE(p, i) ((p)[0] = (i) & 0xff, (p)[1] = ((i) >> 8) & 0xff)
|
|
|
|
|
|
|
|
|
|
/* The buffer and packet size we use. */
|
|
|
|
|
#define CYBUFSIZE (1024)
|
|
|
|
|
#define IYPACKSIZE (1024)
|
|
|
|
|
|
|
|
|
|
/* The offset in the buffer to the data. */
|
|
|
|
|
#define CYFRAMELEN (6)
|
|
|
|
|
|
|
|
|
|
/* Offsets in a packet header. */
|
|
|
|
|
#define YFRAME_SEQ_OFF (0)
|
|
|
|
|
#define YFRAME_LEN_OFF (2)
|
|
|
|
|
#define YFRAME_CTL_OFF (2)
|
|
|
|
|
#define YFRAME_CHK_OFF (4)
|
|
|
|
|
|
|
|
|
|
/* Offsets in a packet header viewed as an array of shorts. */
|
|
|
|
|
#define YFRAME_SEQ (0)
|
|
|
|
|
#define YFRAME_LEN (1)
|
|
|
|
|
#define YFRAME_CTL (1)
|
|
|
|
|
#define YFRAME_CHK (2)
|
|
|
|
|
|
|
|
|
|
/* The default timeout. */
|
|
|
|
|
#define CYTIMEOUT (60)
|
|
|
|
|
|
|
|
|
|
/* Control packet types. */
|
|
|
|
|
#define YPKT_ACK (0xFFFE)
|
|
|
|
|
#define YPKT_ERR (0xFFFD)
|
|
|
|
|
#define YPKT_BAD (0xFFFC)
|
|
|
|
|
|
|
|
|
|
/* The protocol version number. */
|
|
|
|
|
#define Y_VERSION (1)
|
|
|
|
|
|
|
|
|
|
/* When the protocol starts up, it transmit the following information:
|
|
|
|
|
1 byte version
|
|
|
|
|
1 byte packet size
|
|
|
|
|
2 byte flags (none currently defined)
|
|
|
|
|
Future revision may expand the structure as long as these members
|
|
|
|
|
keep their current offset. */
|
|
|
|
|
#define Y_INIT_HDR_LEN (4)
|
|
|
|
|
#define Y_INIT_HDR_VERSION_OFF (0)
|
|
|
|
|
#define Y_INIT_HDR_PKTSIZE_OFF (1)
|
|
|
|
|
#define Y_INIT_HDR_FLAGS_OFF (2)
|
|
|
|
|
|
|
|
|
|
/* The initialization length of the lowest accepted version. */
|
|
|
|
|
#define MIN_Y_SYNC (4)
|
|
|
|
|
|
|
|
|
|
/* Not strictly needed, but I would not want to accept a 32k sync pkt. */
|
|
|
|
|
#define MAX_Y_SYNC IYPACKSIZE
|
|
|
|
|
|
|
|
|
|
/* Local and remote packet sizes (we actually use the same value for
|
|
|
|
|
both). */
|
|
|
|
|
static size_t iYlocal_packsize = IYPACKSIZE;
|
|
|
|
|
static size_t iYremote_packsize = IYPACKSIZE;
|
|
|
|
|
|
|
|
|
|
/* Local and remote packet sequence numbers. */
|
|
|
|
|
static unsigned short iYlocal_pktnum;
|
|
|
|
|
static unsigned short iYremote_pktnum;
|
|
|
|
|
|
|
|
|
|
/* The timeout. */
|
|
|
|
|
static int cYtimeout = CYTIMEOUT;
|
|
|
|
|
|
|
|
|
|
/* Transmitter buffer. */
|
|
|
|
|
static char *zYbuf;
|
|
|
|
|
|
|
|
|
|
/* Protocol parameters. */
|
|
|
|
|
|
|
|
|
|
struct uuconf_cmdtab asYproto_params[] =
|
|
|
|
|
{
|
|
|
|
|
{ "timeout", UUCONF_CMDTABTYPE_INT, (pointer) &cYtimeout, NULL },
|
|
|
|
|
{ "packet-size", UUCONF_CMDTABTYPE_INT, (pointer) &iYlocal_packsize, NULL },
|
|
|
|
|
{ NULL, 0, NULL, NULL }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* Local functions. */
|
|
|
|
|
|
|
|
|
|
static boolean fywait_for_packet P((struct sdaemon *qdaemon,
|
|
|
|
|
boolean *pfexit));
|
|
|
|
|
static unsigned short iychecksum P((const char *z, size_t c));
|
|
|
|
|
static unsigned short iychecksum2 P((const char *zfirst, size_t cfirst,
|
|
|
|
|
const char *zsecond, size_t csecond));
|
|
|
|
|
static boolean fywait_for_header P((struct sdaemon *qdaemon,
|
|
|
|
|
unsigned short header[3], int timeout));
|
|
|
|
|
static boolean fysend_pkt P((struct sdaemon *qdaemon,
|
|
|
|
|
const void *zdata, size_t cdata));
|
|
|
|
|
static boolean fysend_control P((struct sdaemon *qdaemon,
|
|
|
|
|
int itype));
|
|
|
|
|
static boolean fyread_data P((struct sdaemon *qdaemon, size_t clen,
|
|
|
|
|
int timeout));
|
|
|
|
|
|
|
|
|
|
/* Exchange sync packets at protocol startup. */
|
|
|
|
|
|
|
|
|
|
static boolean
|
|
|
|
|
fyxchg_syncs (qdaemon)
|
|
|
|
|
struct sdaemon *qdaemon;
|
|
|
|
|
{
|
|
|
|
|
char inithdr[Y_INIT_HDR_LEN];
|
|
|
|
|
unsigned short header[3];
|
|
|
|
|
unsigned short ichk;
|
|
|
|
|
size_t clen, cfirst;
|
|
|
|
|
int rpktsize;
|
|
|
|
|
|
|
|
|
|
/* Send our configuration. We could use only one array (for local
|
|
|
|
|
and remote). But this is safer in case the code changes and
|
|
|
|
|
depend on separate ones. */
|
|
|
|
|
|
|
|
|
|
inithdr[Y_INIT_HDR_VERSION_OFF] = Y_VERSION;
|
|
|
|
|
inithdr[Y_INIT_HDR_PKTSIZE_OFF] = iYlocal_packsize >> 8;
|
|
|
|
|
TOLITTLE (inithdr + Y_INIT_HDR_FLAGS_OFF, 0);
|
|
|
|
|
|
|
|
|
|
if (! fysend_pkt (qdaemon, inithdr, Y_INIT_HDR_LEN))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
if (! fywait_for_header (qdaemon, header, cYtimeout))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
DEBUG_MESSAGE0 (DEBUG_UUCP_PROTO, "fyxchg_syncs: Got sync header");
|
|
|
|
|
clen = header[YFRAME_LEN];
|
|
|
|
|
|
|
|
|
|
if (clen < MIN_Y_SYNC || clen > MAX_Y_SYNC)
|
|
|
|
|
{
|
|
|
|
|
ulog (LOG_ERROR, "Bad 'y' protocol sync packet length");
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* It may be better to integrate this code with fywait_for_packet. */
|
|
|
|
|
if (! fyread_data (qdaemon, clen, cYtimeout))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
cfirst = CRECBUFLEN - iPrecstart;
|
|
|
|
|
ichk = iychecksum2 (abPrecbuf + iPrecstart, cfirst,
|
|
|
|
|
abPrecbuf, clen - cfirst);
|
|
|
|
|
|
|
|
|
|
rpktsize = BUCHAR (abPrecbuf[(iPrecstart + 1) % CRECBUFLEN]);
|
|
|
|
|
|
|
|
|
|
/* Future versions of the protocol may need to check and react
|
|
|
|
|
according to the version number. */
|
|
|
|
|
|
|
|
|
|
if (rpktsize == 0 || header[YFRAME_CHK] != ichk)
|
|
|
|
|
{
|
|
|
|
|
ulog (LOG_ERROR, "Bad 'y' protocol sync packet");
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
iYremote_packsize = rpktsize << 8;
|
|
|
|
|
|
|
|
|
|
/* Some may want to do this different and in effect the protocol
|
|
|
|
|
support this. But I like the idea that the packet size would be
|
|
|
|
|
the same in both directions. This allows the caller to select
|
|
|
|
|
both packet sizes without changing the configuration at the
|
|
|
|
|
server. */
|
|
|
|
|
if (iYremote_packsize > iYlocal_packsize)
|
|
|
|
|
iYremote_packsize = iYlocal_packsize;
|
|
|
|
|
|
|
|
|
|
iPrecstart = (iPrecstart + clen) % CRECBUFLEN;
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Start the protocol. */
|
|
|
|
|
|
|
|
|
|
boolean
|
|
|
|
|
fystart (qdaemon, pzlog)
|
|
|
|
|
struct sdaemon *qdaemon;
|
|
|
|
|
char **pzlog;
|
|
|
|
|
{
|
|
|
|
|
*pzlog = NULL;
|
|
|
|
|
|
|
|
|
|
/* This should force, or at least enable if available, RTS/CTS
|
|
|
|
|
hardware flow control !! */
|
|
|
|
|
|
|
|
|
|
/* The 'y' protocol requires an eight bit clean link */
|
|
|
|
|
if (! fconn_set (qdaemon->qconn, PARITYSETTING_NONE,
|
|
|
|
|
STRIPSETTING_EIGHTBITS, XONXOFF_OFF))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
iYlocal_pktnum = iYremote_pktnum = 0;
|
|
|
|
|
|
|
|
|
|
/* Only multiple of 256 sizes are allowed */
|
|
|
|
|
iYlocal_packsize &= ~0xff;
|
|
|
|
|
if (iYlocal_packsize < 256 || iYlocal_packsize > (16*1024))
|
|
|
|
|
iYlocal_packsize = IYPACKSIZE;
|
|
|
|
|
|
|
|
|
|
/* Exhange SYNC packets */
|
|
|
|
|
if (! fyxchg_syncs (qdaemon))
|
|
|
|
|
{
|
|
|
|
|
/* Restore defaults */
|
|
|
|
|
cYtimeout = CYTIMEOUT;
|
|
|
|
|
iYlocal_packsize = IYPACKSIZE;
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
zYbuf = (char *) xmalloc (CYBUFSIZE + CYFRAMELEN);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Shutdown the protocol. */
|
|
|
|
|
|
|
|
|
|
boolean
|
|
|
|
|
fyshutdown (qdaemon)
|
|
|
|
|
struct sdaemon *qdaemon;
|
|
|
|
|
{
|
|
|
|
|
xfree ((pointer) zYbuf);
|
|
|
|
|
zYbuf = NULL;
|
|
|
|
|
cYtimeout = CYTIMEOUT;
|
|
|
|
|
iYlocal_packsize = IYPACKSIZE;
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Send a command string. We send packets containing the string until
|
|
|
|
|
the entire string has been sent, including the zero terminator. */
|
|
|
|
|
|
|
|
|
|
/*ARGSUSED*/
|
|
|
|
|
boolean
|
|
|
|
|
fysendcmd (qdaemon, z, ilocal, iremote)
|
|
|
|
|
struct sdaemon *qdaemon;
|
|
|
|
|
const char *z;
|
|
|
|
|
int ilocal;
|
|
|
|
|
int iremote;
|
|
|
|
|
{
|
|
|
|
|
size_t clen;
|
|
|
|
|
|
|
|
|
|
DEBUG_MESSAGE1 (DEBUG_UUCP_PROTO, "fysendcmd: Sending command \"%s\"", z);
|
|
|
|
|
|
|
|
|
|
clen = strlen (z) + 1;
|
|
|
|
|
|
|
|
|
|
while (clen > 0)
|
|
|
|
|
{
|
|
|
|
|
size_t csize;
|
|
|
|
|
|
|
|
|
|
csize = clen;
|
|
|
|
|
if (csize > iYremote_packsize)
|
|
|
|
|
csize = iYremote_packsize;
|
|
|
|
|
|
|
|
|
|
if (! fysend_pkt (qdaemon, z, csize))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
z += csize;
|
|
|
|
|
clen -= csize;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Get space to be filled with data. We always use zYbuf, which was
|
|
|
|
|
allocated from the heap. */
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
|
zygetspace (qdaemon, pclen)
|
|
|
|
|
struct sdaemon *qdaemon;
|
|
|
|
|
size_t *pclen;
|
|
|
|
|
{
|
|
|
|
|
*pclen = iYremote_packsize;
|
|
|
|
|
return zYbuf + CYFRAMELEN;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Send out a data packet. */
|
|
|
|
|
|
|
|
|
|
boolean
|
|
|
|
|
fysenddata (qdaemon, zdata, cdata, ilocal, iremote, ipos)
|
|
|
|
|
struct sdaemon *qdaemon;
|
|
|
|
|
char *zdata;
|
|
|
|
|
size_t cdata;
|
|
|
|
|
int ilocal;
|
|
|
|
|
int iremote;
|
|
|
|
|
long ipos;
|
|
|
|
|
{
|
|
|
|
|
#if DEBUG > 0
|
|
|
|
|
if (cdata > iYremote_packsize)
|
|
|
|
|
ulog (LOG_FATAL, "fysend_packet: Packet size too large");
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
TOLITTLE (zYbuf + YFRAME_SEQ_OFF, iYlocal_pktnum);
|
|
|
|
|
++iYlocal_pktnum;
|
|
|
|
|
TOLITTLE (zYbuf + YFRAME_LEN_OFF, cdata);
|
|
|
|
|
TOLITTLE (zYbuf + YFRAME_CHK_OFF, iychecksum (zdata, cdata));
|
|
|
|
|
|
|
|
|
|
/* We pass FALSE to fsend_data since we don't expect the other side
|
|
|
|
|
to be sending us anything just now. */
|
|
|
|
|
return fsend_data (qdaemon->qconn, zYbuf, cdata + CYFRAMELEN, FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Wait for data to come in and process it until we've finished a
|
|
|
|
|
command or a file. */
|
|
|
|
|
|
|
|
|
|
boolean
|
|
|
|
|
fywait (qdaemon)
|
|
|
|
|
struct sdaemon *qdaemon;
|
|
|
|
|
{
|
|
|
|
|
boolean fexit = FALSE;
|
|
|
|
|
|
|
|
|
|
while (! fexit)
|
|
|
|
|
{
|
|
|
|
|
if (! fywait_for_packet (qdaemon, &fexit))
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* File level routines
|
|
|
|
|
We could handle this inside the other public routines,
|
|
|
|
|
but this is cleaner and better for future expansions */
|
|
|
|
|
|
|
|
|
|
boolean
|
|
|
|
|
fyfile (qdaemon, qtrans, fstart, fsend, cbytes, pfhandled)
|
|
|
|
|
struct sdaemon *qdaemon;
|
|
|
|
|
struct stransfer *qtrans;
|
|
|
|
|
boolean fstart;
|
|
|
|
|
boolean fsend;
|
|
|
|
|
long cbytes;
|
|
|
|
|
boolean *pfhandled;
|
|
|
|
|
{
|
|
|
|
|
unsigned short header[3];
|
|
|
|
|
|
|
|
|
|
*pfhandled = FALSE;
|
|
|
|
|
|
|
|
|
|
if (! fstart)
|
|
|
|
|
{
|
|
|
|
|
if (fsend)
|
|
|
|
|
{
|
|
|
|
|
/* It is critical that the timeout here would be long
|
|
|
|
|
enough. We have just sent a full file without any kind
|
|
|
|
|
of flow control at the protocol level. The traffic may
|
|
|
|
|
be buffered in many places of the link, and the remote
|
|
|
|
|
may take a while until cathing up. */
|
|
|
|
|
if (! fywait_for_header (qdaemon, header, cYtimeout * 2))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
if (header[YFRAME_CTL] != (unsigned short) YPKT_ACK)
|
|
|
|
|
{
|
|
|
|
|
DEBUG_MESSAGE1 (DEBUG_PROTO | DEBUG_ABNORMAL,
|
|
|
|
|
"fyfile: Error from remote: 0x%04X", header[1]);
|
|
|
|
|
ulog (LOG_ERROR, "Received 'y' protocol error from remote");
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* This is technically not requireed. But I've put this in
|
|
|
|
|
the protocol to allow easier expansions. */
|
|
|
|
|
return fysend_control (qdaemon, YPKT_ACK);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Send a control packet, not used during the normal file
|
|
|
|
|
transmission. */
|
|
|
|
|
|
|
|
|
|
static boolean
|
|
|
|
|
fysend_control (qdaemon, itype)
|
|
|
|
|
struct sdaemon *qdaemon;
|
|
|
|
|
int itype;
|
|
|
|
|
{
|
|
|
|
|
char header[CYFRAMELEN];
|
|
|
|
|
|
|
|
|
|
TOLITTLE (header + YFRAME_SEQ_OFF, iYlocal_pktnum);
|
|
|
|
|
iYlocal_pktnum++;
|
|
|
|
|
TOLITTLE (header + YFRAME_CTL_OFF, itype);
|
|
|
|
|
TOLITTLE (header + YFRAME_CHK_OFF, 0);
|
|
|
|
|
|
|
|
|
|
return fsend_data (qdaemon->qconn, header, CYFRAMELEN, FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Private function to send a packet. This one doesn't need the data
|
|
|
|
|
to be in the buffer provided by zygetspace. I've found it worth
|
|
|
|
|
for avoiding memory copies. Somebody may want to do it otherwise */
|
|
|
|
|
|
|
|
|
|
static boolean
|
|
|
|
|
fysend_pkt (qdaemon, zdata, cdata)
|
|
|
|
|
struct sdaemon *qdaemon;
|
|
|
|
|
const void *zdata;
|
|
|
|
|
size_t cdata;
|
|
|
|
|
{
|
|
|
|
|
char header[CYFRAMELEN];
|
|
|
|
|
|
|
|
|
|
TOLITTLE (header + YFRAME_SEQ_OFF, iYlocal_pktnum);
|
|
|
|
|
iYlocal_pktnum++;
|
|
|
|
|
TOLITTLE (header + YFRAME_LEN_OFF, cdata);
|
|
|
|
|
TOLITTLE (header + YFRAME_CHK_OFF, iychecksum (zdata, cdata));
|
|
|
|
|
|
|
|
|
|
if (! fsend_data (qdaemon->qconn, header, CYFRAMELEN, FALSE))
|
|
|
|
|
return FALSE;
|
|
|
|
|
return fsend_data (qdaemon->qconn, zdata, cdata, FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Wait until enough data arrived from the comm line. This protocol
|
|
|
|
|
doesn't need to perform any kind of action while waiting. */
|
|
|
|
|
|
|
|
|
|
static boolean
|
|
|
|
|
fyread_data (qdaemon, clen, timeout)
|
|
|
|
|
struct sdaemon *qdaemon;
|
|
|
|
|
size_t clen;
|
|
|
|
|
int timeout;
|
|
|
|
|
{
|
|
|
|
|
int cinbuf;
|
|
|
|
|
size_t crec;
|
|
|
|
|
|
|
|
|
|
cinbuf = iPrecend - iPrecstart;
|
|
|
|
|
if (cinbuf < 0)
|
|
|
|
|
cinbuf += CRECBUFLEN;
|
|
|
|
|
|
|
|
|
|
if (cinbuf < clen)
|
|
|
|
|
{
|
|
|
|
|
if (! freceive_data (qdaemon->qconn, clen - cinbuf, &crec,
|
|
|
|
|
timeout, TRUE))
|
|
|
|
|
return FALSE;
|
|
|
|
|
cinbuf += crec;
|
|
|
|
|
if (cinbuf < clen)
|
|
|
|
|
{
|
|
|
|
|
if (! freceive_data (qdaemon->qconn, clen - cinbuf, &crec,
|
|
|
|
|
timeout, TRUE))
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
cinbuf += crec;
|
|
|
|
|
if (cinbuf < clen)
|
|
|
|
|
{
|
|
|
|
|
ulog (LOG_ERROR, "Timed out waiting for data");
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Receive a remote packet header, check for correct sequence number. */
|
|
|
|
|
|
|
|
|
|
static boolean
|
|
|
|
|
fywait_for_header (qdaemon, header, timeout)
|
|
|
|
|
struct sdaemon *qdaemon;
|
|
|
|
|
unsigned short header[3];
|
|
|
|
|
int timeout;
|
|
|
|
|
{
|
|
|
|
|
if (! fyread_data (qdaemon, CYFRAMELEN, timeout))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
/* Somebody may want to optimize this in a portable way. I'm not
|
|
|
|
|
sure it's worth, but the output by gcc for the portable construct
|
|
|
|
|
is so bad (even with optimization), that I couldn't resist. */
|
|
|
|
|
|
|
|
|
|
if (iPrecstart <= (CRECBUFLEN - CYFRAMELEN))
|
|
|
|
|
{
|
|
|
|
|
header[0] = FROMLITTLE (abPrecbuf + iPrecstart);
|
|
|
|
|
header[1] = FROMLITTLE (abPrecbuf + iPrecstart + 2);
|
|
|
|
|
header[2] = FROMLITTLE (abPrecbuf + iPrecstart + 4);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
register int i, j;
|
|
|
|
|
|
|
|
|
|
for (i = j = 0; j < CYFRAMELEN; i++, j += 2)
|
|
|
|
|
{
|
|
|
|
|
header[i] =
|
|
|
|
|
(((abPrecbuf[(iPrecstart + j + 1) % CRECBUFLEN] & 0xff) << 8)
|
|
|
|
|
+ (abPrecbuf[(iPrecstart + j) % CRECBUFLEN] & 0xff));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
iPrecstart = (iPrecstart + CYFRAMELEN) % CRECBUFLEN;
|
|
|
|
|
|
|
|
|
|
DEBUG_MESSAGE3 (DEBUG_UUCP_PROTO,
|
|
|
|
|
"fywait_for_header: Got header: 0x%04X, 0x%04X, 0x%04X",
|
|
|
|
|
header[0], header[1], header[2]);
|
|
|
|
|
|
|
|
|
|
if (header[YFRAME_SEQ] != iYremote_pktnum++)
|
|
|
|
|
{
|
|
|
|
|
ulog (LOG_ERROR, "Incorrect 'y' packet sequence");
|
|
|
|
|
fysend_control (qdaemon, YPKT_BAD);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Receive a remote data packet */
|
|
|
|
|
|
|
|
|
|
static boolean
|
|
|
|
|
fywait_for_packet (qdaemon, pfexit)
|
|
|
|
|
struct sdaemon *qdaemon;
|
|
|
|
|
boolean *pfexit;
|
|
|
|
|
{
|
|
|
|
|
unsigned short header[3], ichk;
|
|
|
|
|
size_t clen, cfirst;
|
|
|
|
|
|
|
|
|
|
if (! fywait_for_header (qdaemon, header, cYtimeout))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
clen = header[YFRAME_LEN];
|
|
|
|
|
if (clen == 0 && pfexit != NULL)
|
|
|
|
|
{
|
|
|
|
|
/* I Suppose the pointers could be NULL ??? */
|
|
|
|
|
return fgot_data (qdaemon, abPrecbuf, 0, abPrecbuf, 0,
|
|
|
|
|
-1, -1, (long) -1, TRUE, pfexit);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (clen & 0x8000)
|
|
|
|
|
{
|
|
|
|
|
DEBUG_MESSAGE1 (DEBUG_PROTO | DEBUG_ABNORMAL,
|
|
|
|
|
"fywait_for_packet: Error from remote: 0x%04X",
|
|
|
|
|
header[YFRAME_CTL]);
|
|
|
|
|
ulog (LOG_ERROR, "Remote error packet");
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* This is really not neccessary. But if this check is removed,
|
|
|
|
|
take in mind that the packet may be up to 32k long. */
|
|
|
|
|
if (clen > iYlocal_packsize)
|
|
|
|
|
{
|
|
|
|
|
ulog (LOG_ERROR, "Packet too large");
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (! fyread_data (qdaemon, clen, cYtimeout))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
cfirst = CRECBUFLEN - iPrecstart;
|
|
|
|
|
if (cfirst > clen)
|
|
|
|
|
cfirst = clen;
|
|
|
|
|
|
|
|
|
|
if (cfirst == clen)
|
|
|
|
|
ichk = iychecksum (abPrecbuf + iPrecstart, clen);
|
|
|
|
|
else
|
|
|
|
|
ichk = iychecksum2 (abPrecbuf + iPrecstart, cfirst,
|
|
|
|
|
abPrecbuf, clen - cfirst);
|
|
|
|
|
if (header[YFRAME_CHK] != ichk)
|
|
|
|
|
{
|
|
|
|
|
DEBUG_MESSAGE2 (DEBUG_PROTO | DEBUG_ABNORMAL,
|
|
|
|
|
"fywait_for_packet: Bad checksum 0x%x != 0x%x",
|
|
|
|
|
header[YFRAME_CHK], ichk);
|
|
|
|
|
fysend_control (qdaemon, YPKT_ERR);
|
|
|
|
|
ulog (LOG_ERROR, "Checksum error");
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pfexit != NULL
|
|
|
|
|
&& ! fgot_data (qdaemon, abPrecbuf + iPrecstart, cfirst,
|
|
|
|
|
abPrecbuf, clen - cfirst,
|
|
|
|
|
-1, -1, (long) -1, TRUE, pfexit))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
iPrecstart = (iPrecstart + clen) % CRECBUFLEN;
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Compute 16 bit checksum */
|
|
|
|
|
|
|
|
|
|
#ifdef __GNUC__
|
|
|
|
|
#ifdef __i386__
|
|
|
|
|
#define I386_ASM
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef I386_ASM
|
|
|
|
|
#define ROTATE(i) \
|
|
|
|
|
asm ("rolw $1,%0" : "=g" (i) : "g" (i))
|
|
|
|
|
#else
|
|
|
|
|
#define ROTATE(i) i += i + ((i & 0x8000) >> 15)
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
static unsigned short
|
|
|
|
|
iychecksum (z, c)
|
|
|
|
|
register const char *z;
|
|
|
|
|
register size_t c;
|
|
|
|
|
{
|
|
|
|
|
register unsigned short ichk;
|
|
|
|
|
|
|
|
|
|
ichk = 0xffff;
|
|
|
|
|
|
|
|
|
|
while (c-- > 0)
|
|
|
|
|
{
|
|
|
|
|
ROTATE (ichk);
|
|
|
|
|
ichk += BUCHAR (*z++);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ichk;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static unsigned short
|
|
|
|
|
iychecksum2 (zfirst, cfirst, zsecond, csecond)
|
|
|
|
|
const char *zfirst;
|
|
|
|
|
size_t cfirst;
|
|
|
|
|
const char *zsecond;
|
|
|
|
|
size_t csecond;
|
|
|
|
|
{
|
|
|
|
|
register unsigned short ichk;
|
|
|
|
|
register const char *z;
|
|
|
|
|
register size_t c;
|
|
|
|
|
|
|
|
|
|
z = zfirst;
|
|
|
|
|
c = cfirst + csecond;
|
|
|
|
|
|
|
|
|
|
ichk = 0xffff;
|
|
|
|
|
|
|
|
|
|
while (c-- > 0)
|
|
|
|
|
{
|
|
|
|
|
ROTATE (ichk);
|
|
|
|
|
ichk += BUCHAR (*z++);
|
|
|
|
|
|
|
|
|
|
/* If the first buffer has been finished, switch to the second. */
|
|
|
|
|
if (--cfirst == 0)
|
|
|
|
|
z = zsecond;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ichk;
|
|
|
|
|
}
|