1
0
Files
irix-657m-src/stand/arcs/symmon/netprotocol.c
2022-09-29 17:59:04 +03:00

361 lines
8.5 KiB
C

#ifdef NETDBX
/*
* protocol.c -- udp protocol
*/
#ident "$Revision: 1.1 $"
#include <arcs/types.h>
#include "protocol.h"
#include "protoio.h"
#include "dbgmon.h" /* for prototypes */
#include <setjmp.h>
#include <saioctl.h>
#include <libsc.h>
#include <libsk.h>
#include <arcs/types.h>
#include <arcs/signal.h>
#include <errno.h>
#ifndef NULL
#define NULL 0
#endif
#define CONTROL(x) (x&0x1f)
char *str_buf(char *, int);
int protocol_debug = 0;
int bad_msg_debug = 1;
#define bprintf(x) if (bad_msg_debug) printf("R");
#define DEBUG
#ifdef DEBUG
#define dprintf(x) if (protocol_debug) printf x
#else
#define dprintf(x)
#endif
/*
* UDP protocol description:
* This protocol is a ack/nack, byte-stuffing, half-duplex protocol.
* The protocol may be used for bidirectional communication, but the
* hand-shaking necessary to turn the line around is the responsibility
* of the user of the protocol.
*
* SYN characters are used purely to synchonize the protocol and
* always resync the protocol when received.
*
* serial line protocol format:
* <SYN><len><seq><data0>...<data_len>
*
* <SYN> ::= Ascii sync character
*
* <type_len0> ::= Packet type and high order bits of data length
* Length is data length.
* Bit 6 is set to 1 to avoid inadvertent SYN character
* Bit 5 == 1 => Data packet (DATA_PKTTYPE)
* Bit 5 == 0 => Acknowledgment packet (ACK_PKTTYPE)
* Bits 4 -- 0 => Bits 10 -- 6 of data length
*
* <len1> ::= Low order data length bits.
* Bit 6 is set to 1 to avoid inadvertent SYN character
* Bits 5 -- 0 => Bits 5 -- 0 of data length
*
* <seq> ::= 6 bit sequence number, encoded as
* low 6 bits of 1 character.
* Character is OR'ed with 0x40 to
* avoid conflict with SYN character.
* ACK_PKTTYPE packets carry sequence number
* of NEXT expected DATA_PKTTYPE packet.
*
* <dataN> ::= Body of message
*
*
*/
static unsigned next_getseq; /* next expected receive seq number */
static unsigned current_putseq; /* seq number for current xmit packet */
static unsigned acked_putseq; /* last acknowledged xmit packet seq */
static int n_acked; /* number of ACK pkts received */
static int n_xmited; /* number of transmitted pkts */
#ifdef DEBUG
char *
str_buf(char *buf, int len)
{
static char tmpbuf[64];
int i;
if (len == 0)
strcpy(tmpbuf, "\"\"");
else {
tmpbuf[0] = '"';
for (i = 0; i < len && i < 20; i++)
tmpbuf[i+1] = buf[i];
tmpbuf[++i] = '"';
tmpbuf[++i] = 0;
}
return(tmpbuf);
}
#endif
/*
* netinit_proto -- reset protocol state info
*/
/* ARGSUSED */
void
netinit_proto(ULONG fd)
{
PINIT(fd);
next_getseq = current_putseq = 0;
acked_putseq = (unsigned int) -1;
n_acked = n_xmited = 0;
}
static jmp_buf resync_buf;
static char putbuftmp[MAXPACKET];
static char getbuftmp[MAXPACKET];
/*
* netgetpkt -- unwrap incoming packet, check sequence number and checksum
* and send appropriate acknowledgment.
* Returns data length.
*
* fd - device to receive from
* buf - buf for received packet
* cnt - max data len
* pkt_typep - in: pointer to desired packet type
* out: pointer to received packet type
*/
int
netgetpkt(ULONG fd, char *buf, ULONG cnt, int *pkt_typep)
{
register char *cp;
register int i;
unsigned seq;
int pkt_type;
int new_packet, type_len, len;
unsigned nseq;
extern int Debug;
char *ip;
char *ibuf = &getbuftmp[0];
if (*pkt_typep != DATA_PKTTYPE && *pkt_typep != ACK_PKTTYPE &&
*pkt_typep != ANY_PKTTYPE) {
printf("*** netgetpkt: BAD PKTTYPE\n");
return(0);
}
new_packet = 0;
while (!new_packet)
{
dprintf(("netgetpkt: waiting on read\n"));
Read(fd, ibuf, MAXPACKET, &cnt);
dprintf(("netgetpkt: read %d bytes\n", cnt));
if (ibuf[0] != SYN) {
printf("netgetpkt: Warning! no SYN at start of msg. (0x%x), discard %d bytes\n", ibuf[0], cnt);
continue;
}
if (cnt < 4) {
printf("netgetpkt: Warning! Expected 4, got %d bytes; discarding\n", cnt);
continue;
}
setjmp(resync_buf); /* longjmp here on SYN */
type_len = ibuf[1];
pkt_type = type_len & MASK_PKTTYPE;
if (pkt_type != *pkt_typep && *pkt_typep != ANY_PKTTYPE) {
bprintf(("bad type, got %s, seq: got %d, expect = %d\n",
(long)(pkt_type == DATA_PKTTYPE ? "data" : "ack"),
(ibuf[3] & 0x3f), (pkt_type == DATA_PKTTYPE) ?
next_getseq : (current_putseq + 1) & 0x3f));
goto sendack;
}
len = (type_len & 0x1f) << 6;
len |= ibuf[2] & 0x3f;
if (len > cnt) { /* don't accept long packets */
printf("bad len\n",0,0);
goto sendack;
}
seq = (pkt_type == DATA_PKTTYPE)
? next_getseq /* next expected data seq */
: (current_putseq + 1) & 0x3f; /* next expected ack seq */
if ((nseq = (ibuf[3] & 0x3f)) != seq) {
bprintf(("bad seq, got 0x%x wanted 0x%x type = %s\n",
nseq, seq,
(long)(pkt_type == DATA_PKTTYPE ? "data" : "ack")));
goto sendack;
}
cp = buf;
i = len;
ip = &ibuf[4];
if (len != (cnt - 4)) {
printf("netgetpkt: Warning! Expected %d, got %d bytes; discarding\n", len, cnt);
continue;
}
while (i-- > 0)
*cp++ = *ip++;
new_packet = 1; /* got a good packet */
if (pkt_type == DATA_PKTTYPE)
next_getseq = (next_getseq + 1) & 0x3f;
else
acked_putseq = current_putseq;
sendack:
dprintf(("netgetpkt len=%d seq=0x%x type %s\r\n",
len, nseq, pkt_type == ACK_PKTTYPE ? "ACK" : "DATA"));
dprintf(("netgetpkt, buf = %s\n", str_buf(buf, len)));
/*
* Don't send ACKs to ACKs
*/
if (pkt_type != ACK_PKTTYPE)
netputpkt(fd, NULL, 0, ACK_PKTTYPE);
}
*pkt_typep = pkt_type;
return(len);
}
jmp_buf rexmit_buf;
static void
rexmit_handler(void)
{
longjmp (rexmit_buf, 1);
}
/*
* netputpkt -- wrap data in packet and transmit.
* Waits for acknowledgment and retransmits as necessary
*/
void
netputpkt(ULONG fd, char *buf, int cnt, int pkt_type)
{
register char *cp;
register int i, cc;
ULONG wcc;
int ack_type;
unsigned seq;
char type_len;
extern int Debug;
char *obuf = &putbuftmp[0];
SIGNALHANDLER old_handler;
ULONG err;
int old_alarm;
if (pkt_type != DATA_PKTTYPE && pkt_type != ACK_PKTTYPE) {
printf("*** netputpkt: ILLEGAL PACKET TYPE\n");
return;
}
if (cnt > MAXPACKET) {
printf("*** netputpkt: ILLEGAL PACKET SIZE\n");
buf[MAXPACKET-1] = NULL;
printf("SIZE = %d, PKT = <<%s>>\n", cnt, buf);
return;
}
/* restart here if timeout */
if (pkt_type != ACK_PKTTYPE) {
dprintf(("Putpkt (cpu %d): about to setjmp buf (0x%x)\n",
cpuid(), &rexmit_buf[0]));
dprintf(("Putpkt (cpu %d): accessing rexmitbuf\n", cpuid()));
rexmit_buf[0] = 0x5; /* jfk */
dprintf(("Putpkt (cpu %d): rexmitbuf accessed\n", cpuid()));
/* we dont wait for ack to ack, hence not necessary */
if (setjmp(rexmit_buf)) {
bprintf(("(cpu %d), retransmitting packet len=%d buf=%s seq=0x%x type %s\r\n",
cpuid(), cnt, str_buf(buf, cnt), pkt_type == ACK_PKTTYPE ?
current_putseq: next_getseq,
pkt_type == ACK_PKTTYPE ? "ACK" : "DATA"));
if (pkt_type == ACK_PKTTYPE) {
printf("ACK packet not retransmitted\n");
return;
}
}
}
dprintf(("Putpkt (cpu %d): jmp buf set\n", cpuid()));
while (current_putseq != acked_putseq) {
cc = 0; /* Index into buf */
obuf[cc++] = SYN;
dprintf(("Putpkt (cpu %d): Set SYN\n", cpuid()));
type_len = pkt_type | ((cnt >> 6) & 0x1f) | 0x40;
obuf[cc++] = type_len; /* TYPE_LEN */
dprintf(("Putpkt (cpu %d): Set typelen\n", cpuid()));
obuf[cc++] = (cnt & 0x3f) | 0x40; /* LEN1 */
seq = (pkt_type == DATA_PKTTYPE)
? current_putseq /* sequence for data packets */
: next_getseq; /* sequence for ack packets */
obuf[cc++] = seq | 0x40; /* SEQ */
dprintf(("Putpkt (cpu %d): Set seq\n", cpuid()));
cp = buf;
for (i = cnt; i > 0; i--) /* DATA */
obuf[cc++] = *cp++;
dprintf(("netputpkt: about to write (obuf = 0x%x, cc = %d\n",
obuf, cc));
if ((err = Write(fd, obuf, cc, &wcc)) != ESUCCESS) {
printf("Error in writing file (err = %d)\n", err);
return;
}
dprintf(("netputpkt len=%d buf=%s seq=0x%x type %s\r\n",
cnt, str_buf(buf, cnt), seq,
pkt_type == ACK_PKTTYPE ? "ACK" : "DATA"));
if (pkt_type == ACK_PKTTYPE) /* don't send ACKs to ACKs */
return;
dprintf(("netputpkt still here!\n"));
n_xmited++;
old_handler = Signal (SIGALRM, rexmit_handler);
old_alarm = alarm(REXMIT_TIME);
ack_type = ACK_PKTTYPE;
dprintf(("netputpkt calling netgetpkt!\n"));
netgetpkt(fd, NULL, 0, &ack_type);
Signal (SIGALRM, old_handler);
alarm(old_alarm);
}
if (pkt_type == DATA_PKTTYPE) {
current_putseq = (current_putseq + 1) & 0x3f;
n_acked++;
}
}
#endif /* NETDBX */