#include <sys/errno.h>
#include <sys/types.h>
#include <sys/param.h>
#include <machine/spl.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/proc.h>
#include <sys/filedesc.h>
#include <sys/fcntl.h>
#include <sys/mbuf.h>
#include <sys/ioctl.h>
#include <sys/malloc.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/time.h>
#include <net/if.h>
#include <netat/sysglue.h>
#include <netat/appletalk.h>
#include <netat/at_pcb.h>
#include <netat/ddp.h>
#include <netat/at_var.h>
#include <netat/adsp.h>
#include <netat/adsp_internal.h>
extern at_ifaddr_t *ifID_home;
static void GleanSession(sp)
CCBPtr sp;
{
if (sp->openState == O_STATE_OPEN) {
RemoveTimerElem(&adspGlobal.slowTimers, &sp->ProbeTimer);
InsertTimerElem(&adspGlobal.slowTimers, &sp->ProbeTimer,
sp->probeInterval);
sp->probeCntr = 4;
}
}
typedef struct {
u_char match;
char action;
char send;
char openState;
char state;
char pad;
} TBL, *TBLPtr;
#define M_LSOC 0x01
#define M_ADDR 0x02
#define M_DCID 0x04
#define M_SCID 0x08
#define M_DCIDZERO 0x10
#define M_SCIDZERO 0x20
#define M_FILTER 0x40
#define M_IGNORE 0x80
#define A_COMPLETE 0x01
#define A_SAVEPARMS 0x02
#define A_OREQACKOPEN 0x04
#define A_GLEAN 0x08
#define A_DENY 0x10
static TBL tbl[16] = {
{ M_LSOC + M_DCIDZERO + M_FILTER,
A_SAVEPARMS + A_GLEAN,
B_CTL_OREQACK,
O_STATE_ESTABLISHED,
sOpening,
0
},
{ M_LSOC + M_ADDR + M_DCIDZERO,
A_SAVEPARMS + A_GLEAN,
B_CTL_OACK,
O_STATE_ESTABLISHED,
sOpening,
0
},
{ M_ADDR + M_SCID + M_DCIDZERO,
A_GLEAN,
B_CTL_OACK,
O_STATE_ESTABLISHED,
sOpening,
0
},
{ M_IGNORE,
0,
0,
0,
0,
0
},
{ M_IGNORE,
0,
0,
0,
0,
0
},
{ M_IGNORE,
0,
0,
0,
0,
0
},
{ M_ADDR + M_DCID + M_SCID + M_LSOC,
A_COMPLETE + A_GLEAN,
0,
O_STATE_OPEN,
sOpen,
0
},
{ M_IGNORE,
0,
0,
0,
0,
0
},
{ M_IGNORE,
0,
0,
0,
0,
0
},
{ M_DCID + M_LSOC,
A_COMPLETE + A_SAVEPARMS + A_GLEAN,
B_CTL_OACK,
O_STATE_OPEN,
sOpen,
0
},
{ M_IGNORE,
0,
0,
0,
0,
0
},
{ M_ADDR + M_DCID + M_SCID + M_LSOC,
A_OREQACKOPEN + A_GLEAN,
B_CTL_OACK,
O_STATE_OPEN,
sOpen,
0
},
{ M_IGNORE,
0,
0,
0,
0,
0
},
{ M_SCIDZERO + M_DCID + M_ADDR,
A_DENY,
0,
O_STATE_NOTHING,
sClosed,
0
},
{ M_IGNORE,
0,
0,
0,
0,
0
},
{ M_IGNORE,
0,
0,
0,
0,
0
}
};
extern at_ifaddr_t *ifID_table[];
typedef struct {
AddrUnion addr;
word dstCID;
word srcCID;
byte socket;
byte descriptor;
byte idx;
TBLPtr t;
} MATCH, *MATCHPtr;
static boolean
MatchStream(sp, m)
CCBPtr sp;
MATCHPtr m;
{
unsigned char match;
struct adspcmd *opb;
if (sp->openState < O_STATE_LISTEN ||
sp->openState > O_STATE_OPEN)
return 0;
m->t = &tbl[sp->openState - O_STATE_LISTEN + m->idx];
match = m->t->match;
if (match & M_IGNORE)
return 0;
if (match & M_LSOC) {
if (sp->localSocket != m->socket)
return 0;
}
if (match & M_ADDR) {
AddrUnion addr;
addr = m->addr;
if (sp->remoteAddress.a.node != addr.a.node)
return 0;
if (sp->remoteAddress.a.socket != addr.a.socket)
return 0;
if (sp->remoteAddress.a.net && addr.a.net &&
(sp->remoteAddress.a.net != addr.a.net))
return 0;
if ((m->srcCID == sp->locCID) &&
(addr.a.node == ifID_home->ifThisNode.s_node) &&
((addr.a.net == 0) ||
(ifID_home->ifThisNode.s_net == 0) ||
(ifID_home->ifThisNode.s_net == addr.a.net)) )
return 0;
}
if (match & M_DCID) {
if (sp->locCID != m->dstCID)
return 0;
}
if (match & M_SCID) {
if (sp->remCID != m->srcCID)
return 0;
}
if (match & M_DCIDZERO) {
if (m->dstCID != 0)
return 0;
}
if (match & M_SCIDZERO)
{
if (m->srcCID != 0)
return 0;
}
if (match & M_FILTER) {
if ((opb = sp->opb))
{
AddrUnion addr;
addr = m->addr;
if ((opb->u.openParams.filterAddress.net &&
addr.a.net &&
opb->u.openParams.filterAddress.net != addr.a.net) ||
(opb->u.openParams.filterAddress.node != 0 &&
opb->u.openParams.filterAddress.node != addr.a.node)||
(opb->u.openParams.filterAddress.socket != 0 &&
opb->u.openParams.filterAddress.socket != addr.a.socket))
return 0;
}
}
return 1;
}
static boolean MatchListener(sp, m)
CCBPtr sp;
MATCHPtr m;
{
if ((sp->state == (word)sListening) &&
(sp->localSocket == m->socket))
return 1;
return 0;
}
static int RXConnection(gref, spPtr, f, len, addr, dsoc)
gref_t *gref;
CCBPtr *spPtr;
ADSP_FRAMEPtr f;
int len;
AddrUnion addr;
unsigned char dsoc;
{
CCBPtr sp;
ADSP_OPEN_DATAPtr op;
struct adspcmd *pb;
MATCH m;
gbuf_t *mp;
ADSP_FRAMEPtr adspp;
ADSP_OPEN_DATAPtr adspop;
int s;
op = (ADSP_OPEN_DATAPtr)&f->data[0];
len -= ADSP_FRAME_LEN;
if (len < (sizeof(ADSP_OPEN_DATA)))
return 1;
if (UAS_VALUE(op->version) != netw(0x0100)) {
mp = gbuf_alloc(AT_WR_OFFSET + DDPL_FRAME_LEN + ADSP_FRAME_LEN + ADSP_OPEN_FRAME_LEN,
PRI_LO);
gbuf_rinc(mp,AT_WR_OFFSET);
gbuf_wset(mp,DDPL_FRAME_LEN);
adspp = (ADSP_FRAMEPtr)gbuf_wptr(mp);
gbuf_winc(mp,ADSP_FRAME_LEN);
bzero((caddr_t) gbuf_rptr(mp),DDPL_FRAME_LEN + ADSP_FRAME_LEN +
ADSP_OPEN_FRAME_LEN);
adspp->descriptor = ADSP_CONTROL_BIT | ADSP_CTL_ODENY;
adspop = (ADSP_OPEN_DATAPtr)gbuf_wptr(mp);
gbuf_winc(mp,ADSP_OPEN_FRAME_LEN);
UAS_UAS(adspop->dstCID, f->CID);
UAS_ASSIGN(adspop->version, 0x100);
adsp_sendddp(0, mp, DDPL_FRAME_LEN + ADSP_FRAME_LEN +
ADSP_OPEN_FRAME_LEN, &addr, DDP_ADSP);
return 0;
}
m.addr = addr;
m.socket = dsoc;
m.descriptor = f->descriptor;
m.srcCID = UAS_VALUE(f->CID);
m.dstCID = UAS_VALUE(op->dstCID);
m.idx = ((f->descriptor & ADSP_CONTROL_MASK) - 1) * 4;
if ((sp = (CCBPtr)qfind_m(AT_ADSP_STREAMS, &m, (ProcPtr)MatchStream)) == 0)
{
struct adspcmd *p;
struct adspcmd *n;
if ((f->descriptor & ADSP_CONTROL_MASK) != (byte)ADSP_CTL_OREQ)
return 1;
if ((sp = (CCBPtr)qfind_m(AT_ADSP_STREAMS, &m,
(ProcPtr)MatchListener)) == 0)
return 1;
ATDISABLE(s, sp->lock);
p = (struct adspcmd *)&sp->opb;
while (n = (struct adspcmd *)p->qLink)
{
if (((n->u.openParams.filterAddress.net == 0) ||
(addr.a.net == 0) ||
(n->u.openParams.filterAddress.net == addr.a.net)) &&
((n->u.openParams.filterAddress.node == 0) ||
(n->u.openParams.filterAddress.node == addr.a.node)) &&
((n->u.openParams.filterAddress.socket == 0) ||
(n->u.openParams.filterAddress.socket == addr.a.socket))) {
p->qLink = n->qLink;
n->u.openParams.remoteCID = m.srcCID;
*((AddrUnionPtr)&n->u.openParams.remoteAddress) = addr;
n->u.openParams.sendSeq = netdw(UAL_VALUE(f->pktNextRecvSeq));
n->u.openParams.sendWindow = netw(UAS_VALUE(f->pktRecvWdw));
n->u.openParams.attnSendSeq = netdw(UAL_VALUE(op->pktAttnRecvSeq));
n->ioResult = 0;
ATENABLE(s, sp->lock);
completepb(sp, n);
return 0;
}
p = n;
}
ATENABLE(s, sp->lock);
return 1;
}
*spPtr = sp;
ATDISABLE(s, sp->lock);
sp->openState = m.t->openState;
sp->state = m.t->state;
if (m.t->action & A_SAVEPARMS) {
sp->firstRtmtSeq = sp->sendSeq = netdw(UAL_VALUE(f->pktNextRecvSeq));
sp->sendWdwSeq = netdw(UAL_VALUE(f->pktNextRecvSeq)) + netw(UAS_VALUE(f->pktRecvWdw)) - 1;
sp->attnSendSeq = netdw(UAL_VALUE(op->pktAttnRecvSeq));
sp->remCID = UAS_VALUE(f->CID);
UAS_UAS(sp->of.dstCID, f->CID);
sp->remoteAddress = addr;
}
ATENABLE(s, sp->lock);
if (m.t->action & A_DENY) {
DoClose(sp, errOpenDenied, -1);
}
if (m.t->action & A_OREQACKOPEN) {
RemoveTimerElem(&adspGlobal.fastTimers, &sp->RetryTimer);
sp->sendSeq = sp->firstRtmtSeq;
sp->pktSendCnt = 0;
sp->waitingAck = 0;
sp->callSend = 1;
}
if (m.t->send) {
sp->sendCtl |= m.t->send;
sp->callSend = 1;
}
if (m.t->action & A_COMPLETE) {
RemoveTimerElem(&adspGlobal.slowTimers, &sp->ProbeTimer);
if (pb = sp->opb) {
sp->opb = 0;
pb->u.openParams.localCID = sp->locCID;
pb->u.openParams.remoteCID = sp->remCID;
pb->u.openParams.remoteAddress =
*((at_inet_t *)&sp->remoteAddress);
pb->u.openParams.sendSeq = sp->sendSeq;
pb->u.openParams.sendWindow = sp->sendWdwSeq - sp->sendSeq;
pb->u.openParams.attnSendSeq = sp->attnSendSeq;
pb->ioResult = 0;
completepb(sp, pb);
return 0;
}
InsertTimerElem(&adspGlobal.slowTimers, &sp->ProbeTimer,
sp->probeInterval);
}
return 0;
}
int adspPacket(gref, mp)
gref_t *gref;
gbuf_t *mp;
{
unsigned char *bp;
int len;
AddrUnion a;
int dsoc;
int s;
register DDPX_FRAME *ddp;
register ADSP_FRAMEPtr f;
CCBPtr sp;
sp = 0;
bp = (unsigned char *)gbuf_rptr(mp);
ddp = (DDPX_FRAME *)bp;
if (ddp->ddpx_type != DDP_ADSP)
return -1;
f = (ADSP_FRAMEPtr)(bp + DDPL_FRAME_LEN);
len = UAS_VALUE(ddp->ddpx_length) & 0x3ff;
len -= DDPL_FRAME_LEN;
if (len < (sizeof(ADSP_FRAME) - 1))
return -1;
a.a.net = NET_VALUE(ddp->ddpx_snet);
a.a.node = ddp->ddpx_snode;
a.a.socket = ddp->ddpx_source;
dsoc = ddp->ddpx_dest;
if (sp = (CCBPtr)FindSender(f, a))
GleanSession(sp);
if (f->descriptor & ADSP_ATTENTION_BIT) {
if (sp && RXAttention(sp, mp, f, len))
goto ignore;
else
mp = 0;
}
else if (f->descriptor & ADSP_CONTROL_BIT) {
switch (f->descriptor & ADSP_CONTROL_MASK) {
case ADSP_CTL_PROBE:
if (sp)
CheckRecvSeq(sp, f);
break;
case ADSP_CTL_OREQ:
case ADSP_CTL_OREQACK:
case ADSP_CTL_OACK:
case ADSP_CTL_ODENY:
if (RXConnection(gref, &sp, f, len, a, dsoc))
goto ignore;
break;
case ADSP_CTL_CLOSE:
if (sp) {
CheckRecvSeq(sp, f);
RxClose(sp);
sp = 0;
} else
goto ignore;
break;
case ADSP_CTL_FRESET:
if (sp && (CheckRecvSeq(sp, f), RXFReset(sp, f)))
goto ignore;
break;
case ADSP_CTL_FRESET_ACK:
if (sp && (CheckRecvSeq(sp, f), RXFResetAck(sp, f)))
goto ignore;
break;
case ADSP_CTL_RETRANSMIT:
if (sp) {
CheckRecvSeq(sp, f);
RemoveTimerElem(&adspGlobal.fastTimers, &sp->RetryTimer);
ATDISABLE(s, sp->lock);
sp->sendSeq = sp->firstRtmtSeq;
sp->pktSendCnt = 0;
sp->waitingAck = 0;
sp->callSend = 1;
ATENABLE(s, sp->lock);
} else
goto ignore;
break;
default:
goto ignore;
}
}
else {
if ((sp == 0) || RXData(sp, mp, f, len))
goto ignore;
else
mp = 0;
}
if (mp)
gbuf_freem(mp);
checksend:
if (sp && sp->callSend)
CheckSend(sp);
return 0;
ignore:
gbuf_freem(mp);
return 0;
}