/* etherload.c
L. Stewart September 10, 1982 11:12 AM
L. Stewart December 3, 1982 2:19 PM, changed to poll style
*/
/* in cmon.c */
extern char mstate[26];
extern startm();
/* in cmruntimeml.dsm */
extern swab();
extern blt();
/* in cmslcml.dsm */
extern slcinit();
extern waitccb();
extern sltstart();
extern slrstart();
struct ccb {
char cmda;
char *addra;
char counta;
char stata;
};
struct port {
char net, host;
int soc1, soc2;
};
struct pup {
int eaddr;
int etype;
int len;
char tpc, type;
int id1, id2;
struct port dport, sport;
char data[1];
};
struct core {
int addrlo, addrhi, count;
char data[1];
};
struct ccb minccb, inccb, outccb;
/* really want length to be unsigned, but *char
is ok too. The problem is to avoid sign extension
when assigning from inccb.counta to length */
static char *cdata;
static char *caddr;
static char *length;
static int ccount;
static struct pup *rpup;
static struct pup *tpup;
static struct core *tcore;
static int lastid1;
static int lastid2;
static int tplen;
static int rv;
static int valid;
static int rbuf[130];
static int buf[130];
static int lhost;
/* Pup download server */
StartEL()
{
lhost = GetPIO(1);
slcinit(lhost);
minccb.cmda = 0x00;
minccb.addra = rbuf;
minccb.counta = 0;
minccb.stata = 0;
tpup = (struct pup *) buf;
tcore = (struct core *) tpup->data;
cdata = tcore->data;
rpup = (struct pup *) rbuf;
startrx();
};
CheckEL()
{
if (!(inccb.stata & 0x80)) return;
if (inccb.stata != 0x88) StartEL();
if (inccb.counta == 0) length = 256;
else length = inccb.counta;
echo(length);
StartEL();
};
static echo(leng)
int leng;
{
int plen;
if ((!(rpup->eaddr & 0xff)) || (leng&01) || (leng<26)) goto quitel;
/* unswabbed etype should be 2 */
if (rpup->etype != 2) goto quitel;
/* check lengths */
plen = (swab(rpup->len)+5) & 0xfffe;
if (plen != leng) goto quitel;
/* check pup destintion */
if (rpup->dport.host != lhost) goto quitel;
if ((rpup->dport.soc1) || (rpup->dport.soc2 != 0x3000)) goto quitel;
if ((rpup->type != 0xc0) && (rpup->type != 0xc2)) {
if ((rpup->type != 0xc4) && (rpup->type != 0xc6)) goto quitel;
};
if ((rpup->id1 == lastid1) && (rpup->id2 == lastid2)) {
if (valid) sendpkt();
goto quitel;
};
/* copy packet accross */
blt(rbuf, buf, 260);
valid = 0;
rv = 0;
caddr = swab(tcore->addrlo);
ccount = swab(tcore->count);
if (tcore->addrhi) goto quitel;
/* check puptype */
if (tpup->type == 0xc0) { /* core store */
blt(cdata, caddr, ccount);
blt(caddr, cdata, ccount);
comtc();
tplen = leng;
};
if (tpup->type == 0xc2) { /* core fetch */
mcomc();
};
if (tpup->type == 0xc6) { /* state fetch */
if (((int) caddr != 1) || (ccount != 28)) goto quitel;
caddr = mstate;
mcomc();
};
if (tpup->type == 0xc4) { /* state store */
if (((int) caddr != 1) || (ccount != 28)) goto quitel;
caddr = mstate;
blt(cdata, caddr, ccount);
mcomc();
setuppkt();
sendpkt();
startm();
};
if (!rv) goto quitel;
setuppkt();
sendpkt();
quitel:
};
static mcomc()
{
blt(caddr, cdata, ccount);
tplen = (33+ccount) & 0xfffe;
tpup->len = swab(tplen - 4);
comtc();
};
static sendpkt()
{
outccb.cmda = 0x50;
outccb.addra = buf;
outccb.counta = tplen;
outccb.stata = 0;
sltstart(&outccb);
/* wait for transmit done */
waitccb(&outccb);
};
static setuppkt()
{
/* swap src and destination */
ssd(buf);
/* fill in no-checksum */
buf[(tplen/2)-1] = 0xffff;
/* swap ether source and destination */
tpup->eaddr = swab(tpup->eaddr);
/* zero transport control */
tpup->tpc = 0;
/* set puptype */
/* tpup->type += 1; doesn't work */
tpup->type = tpup->type+1;
};
static comtc()
{
rv = 1;
valid = 1;
lastid1 = tpup->id1;
lastid2 = tpup->id2;
};
static ssd(p)
char *p;
{
char temp[6];
blt(&p[12],temp, 6);
blt(&p[18],&p[12], 6);
blt(temp,&p[18], 6);
};
static startrx()
{
if (slrstat() & 0x000c) slrinit();
blt(&minccb, &inccb, 5);
slrstart(&inccb);
};