661 lines
17 KiB
C
661 lines
17 KiB
C
/* 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
|
||
const char proty_id[] = "$Id: proty.c,v 1.1 1995/08/24 05:23:00 jtc Exp $";
|
||
#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;
|
||
}
|