/* etherload.c April 22, 1982 4:38 PM */
extern char mstate[26];
extern slcinit();
extern waitccb();
extern swab();
extern blt();
extern startm();
extern sltstart();
extern slrstart();
extern chav();
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 */
char *cdata, *caddr, *length;
int ccount;
struct pup *rpup, *tpup;
struct core *tcore;
int lastid1, lastid2, tplen, rv, valid;
int rbuf[130], buf[130];
/* Pup download server */
etherload(host)
int host;
{
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;
slcinit(host);
for (;;) {
startrx();
while (!(inccb.stata & 0x80)) if (chav()) return;
if (inccb.stata != 0x88) continue;
if (inccb.counta == 0) length = 256;
else length = inccb.counta;
echo(length);
};
};
echo(leng)
int leng;
{
int plen;
if (!(rpup->eaddr & 0xff)) return;
if (leng&01) return;
if (leng<26) return;
/* generate a delay */
plen = 3000;
while (--plen);
/* unswabbed etype should be 2 */
if (rpup->etype != 2) return;
/* check lengths */
plen = (swab(rpup->len)+5) & 0xfffe;
if (plen != leng) return;
/* check pup destintion */
if (rpup->dport.host != 0x55) return;
if ((rpup->dport.soc1) || (rpup->dport.soc2 != 0x3000)) return;
if ((rpup->type != 0xc0) && (rpup->type != 0xc2)) {
if ((rpup->type != 0xc4) && (rpup->type != 0xc6)) return;
};
if ((rpup->id1 == lastid1) && (rpup->id2 == lastid2)) {
if (valid) sendpkt();
return;
};
/* copy packet accross */
blt(rbuf, buf, 260);
valid = 0;
rv = 0;
caddr = swab(tcore->addrlo);
ccount = swab(tcore->count);
if (tcore->addrhi) return;
/* 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)) return;
caddr = mstate;
mcomc();
};
if (tpup->type == 0xc4) { /* state store */
if (((int) caddr != 1) || (ccount != 28)) return;
caddr = mstate;
blt(cdata, caddr, ccount);
mcomc();
setuppkt();
sendpkt();
startm();
};
if (!rv) return(0);
setuppkt();
sendpkt();
};
mcomc()
{
blt(caddr, cdata, ccount);
tplen = (33+ccount) & 0xfffe;
tpup->len = swab(tplen - 4);
comtc();
};
sendpkt()
{
outccb.cmda = 0x50;
outccb.addra = buf;
outccb.counta = tplen;
outccb.stata = 0;
sltstart(&outccb);
/* wait for transmit done */
waitccb(&outccb);
};
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;
};
comtc()
{
rv = 1;
valid = 1;
lastid1 = tpup->id1;
lastid2 = tpup->id2;
};
ssd(p)
char *p;
{
char temp[6];
blt(&p[12],temp, 6);
blt(&p[18],&p[12], 6);
blt(temp,&p[18], 6);
};
startrx()
{
if (slrstat() & 0x000c) slrinit();
blt(&minccb, &inccb, 5);
slrstart(&inccb);
};