#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/socket.h>
#include <sys/socketvar.h>
#include <sys/time.h>
#include <netat/sysglue.h>
#include <netat/appletalk.h>
#include <netat/ddp.h>
#include <netat/at_pcb.h>
#include <netat/debug.h>
#include <netat/adsp.h>
#include <netat/adsp_internal.h>
static void qRemove(CCBPtr, CCBPtr);
int CheckOkToClose(sp)
CCBPtr sp;
{
if (sp->sData)
return 0;
if (sp->sapb)
return 0;
if (sp->frpb)
return 0;
if (sp->sendAttnAck)
return 0;
if (sp->sendDataAck)
return 0;
sp->sendCtl |= B_CTL_CLOSE;
sp->callSend = 1;
return 1;
}
int CompleteQueue(qhead, code)
struct adspcmd **qhead;
int code;
{
register struct adspcmd *p;
register struct adspcmd *n;
register gref_t *gref;
register int _total = 0;
CCBPtr sp = 0;
n = *qhead;
*qhead = 0;
if (n) {
gref = n->gref;
if (gref->info) {
sp = (CCBPtr)gbuf_rptr(((gbuf_t *)gref->info));
atalk_flush(sp->gref);
}
}
while ((p = n)) {
n = (struct adspcmd *)(p->qLink);
p->ioResult = code;
if (sp) {
completepb(sp, p);
_total++;
} else
gbuf_freem(p->mp);
}
return(_total);
}
void RemoveCCB(CCBPtr, struct adspcmd *);
void RemoveCCB(sp, pb)
CCBPtr sp;
struct adspcmd *pb;
{
gref_t *gref;
if (sp->gref == 0)
return;
qRemove((CCB *)AT_ADSP_STREAMS, sp);
if (pb) {
pb->ioResult = 0;
if (pb->ioc)
adspioc_ack(0, (gbuf_t *)pb->ioc, pb->gref);
else {
completepb(sp, pb);
}
if (sp->opb && (pb != sp->opb)) {
pb = sp->opb;
sp->opb = 0;
pb->ioResult = 0;
completepb(sp, pb);
} else {
sp->opb = 0;
}
}
gref = sp->gref;
sp->gref = 0;
if (gref->info == (char *)sp->sp_mp) {
unsigned char skt;
if ((skt = sp->localSocket) != 0) {
if (adspDeassignSocket(sp) == 0)
ddp_notify_nbp(skt, sp->pid, DDP_ADSP);
}
if (gref->info) {
gbuf_freem((gbuf_t *)gref->info);
gref->info = 0;
}
} else
gbuf_freem(sp->sp_mp);
}
int AbortIO(CCBPtr, short);
int AbortIO(sp, err)
CCBPtr sp;
short err;
{
register int _total;
if (sp->gref == 0)
return 0;
_total = CompleteQueue(&sp->sapb, err);
CompleteQueue(&sp->frpb, err);
if (sp->sbuf_mb) {
gbuf_freel(sp->sbuf_mb);
sp->sbuf_mb = 0;
}
if (sp->csbuf_mb) {
gbuf_freem(sp->csbuf_mb);
sp->csbuf_mb = 0;
}
sp->sData = 0;
return(_total);
}
void DoClose(sp, err, force_abort)
register CCBPtr sp;
int err;
int force_abort;
{
register struct adspcmd *pb, *np;
register gbuf_t *mp;
int aborted_count;
dPrintf(D_M_ADSP, D_L_TRACE, ("DoClose: pid=%d,e=%d,a=%d,s=%d,r=%d\n",
sp->pid, err, force_abort, sp->localSocket, sp->removing));
sp->userFlags |= eClosed;
sp->state = sClosed;
sp->openState = O_STATE_NOTHING;
RemoveTimerElem(&adspGlobal.slowTimers, &sp->ProbeTimer);
RemoveTimerElem(&adspGlobal.fastTimers, &sp->FlushTimer);
RemoveTimerElem(&adspGlobal.fastTimers, &sp->RetryTimer);
RemoveTimerElem(&adspGlobal.fastTimers, &sp->AttnTimer);
RemoveTimerElem(&adspGlobal.fastTimers, &sp->ResetTimer);
aborted_count = AbortIO(sp, err);
np = sp->opb;
sp->opb = 0;
while ((pb = np)) {
np = (struct adspcmd *)pb->qLink;
pb->qLink = 0;
pb->ioResult = err;
completepb(sp, pb);
}
if (sp->removing && (force_abort >= 0)) {
aborted_count += CompleteQueue(&sp->rpb, err);
if (sp->deferred_mb) {
gbuf_freel(sp->deferred_mb);
sp->deferred_mb = 0;
}
if (sp->attn_mb) {
gbuf_freem(sp->attn_mb);
sp->attn_mb = 0;
}
if (sp->rbuf_mb) {
gbuf_freem(sp->rbuf_mb);
sp->rbuf_mb = 0;
}
if (sp->crbuf_mb) {
gbuf_freem(sp->crbuf_mb);
sp->crbuf_mb = 0;
}
sp->rData = 0;
if (force_abort && aborted_count == 0) {
if ((mp = gbuf_alloc(sizeof(struct adspcmd), PRI_HI))) {
pb = (struct adspcmd *)gbuf_rptr(mp);
gbuf_wset(mp,sizeof(struct adspcmd));
bzero((caddr_t) pb, sizeof(struct adspcmd));
pb->mp = mp;
pb->csCode = dspRead;
pb->ioResult = errAborted;
completepb(sp, pb);
}
}
sp->removing = 0;
RemoveCCB(sp, 0);
}
sp->userFlags &= ~eClosed;
}
int adspClose(sp, pb)
register CCBPtr sp;
register struct adspcmd *pb;
{
register gbuf_t *mp;
if (sp == 0) {
pb->ioResult = errRefNum;
return EINVAL;
}
if (pb->csCode == (short)dspCLRemove) {
if (sp->state != (short)sListening) {
pb->ioResult = errState;
return EINVAL;
}
CompleteQueue(&sp->opb, errAborted);
RemoveCCB(sp, pb);
return 0;
}
if (sp->removing) {
pb->ioResult = errState;
return EINVAL;
}
if (pb->csCode == (short)dspClose) {
if ((sp->state == (short)sPassive) || (sp->state == (short)sOpening)) {
sp->state = sClosed;
DoClose(sp, errAborted, 0);
pb->ioResult = 0;
adspioc_ack(0, (gbuf_t *)pb->ioc, pb->gref);
return 0;
}
if (sp->state == (word)sClosed) {
pb->ioResult = 0;
adspioc_ack(0, (gbuf_t *)pb->ioc, pb->gref);
return 0;
}
if ((sp->state != (word)sOpen) && (sp->state != (word)sClosing)) {
pb->ioResult = errState;
return EINVAL;
}
sp->state = sClosing;
}
else {
sp->removing = 1;
if (sp->state == sPassive || sp->state == sClosed ||
sp->state == sOpening) {
sp->state = sClosed;
DoClose(sp, errAborted, 0);
return 0;
} else
sp->state = sClosing;
}
if (pb->u.closeParams.abort || CheckOkToClose(sp))
{
AbortIO(sp, errAborted);
sp->sendCtl = B_CTL_CLOSE;
}
pb->ioResult = 1;
if ( (mp = gbuf_copym(pb->mp)) ) {
adspioc_ack(0, (gbuf_t *)pb->ioc, pb->gref);
pb = (struct adspcmd *)gbuf_rptr(mp);
pb->ioc = 0;
pb->mp = mp;
qAddToEnd((struct qlink **)&sp->opb, (struct qlink *)pb);
} else {
pb->ioResult = 0;
adspioc_ack(0, (gbuf_t *)pb->ioc, pb->gref);
}
CheckSend(sp);
return 0;
}
static void qRemove(qptr, elem)
register CCBPtr qptr;
register CCBPtr elem;
{
while(qptr->ccbLink) {
if ((DSPPBPtr)(qptr->ccbLink) == (DSPPBPtr)elem) {
qptr->ccbLink = elem->ccbLink;
elem->ccbLink = 0;
return;
}
qptr = qptr->ccbLink;
}
}
int RxClose(sp)
register CCBPtr sp;
{
register gbuf_t *mp;
register struct adspcmd *pb;
if ((sp->state == sClosing) || (sp->state == sClosed))
return 0;
sp->state = sClosed;
CheckReadQueue(sp);
if ( (mp = gbuf_alloc(sizeof(struct adspcmd), PRI_HI)) ) {
pb = (struct adspcmd *)gbuf_rptr(mp);
gbuf_wset(mp,sizeof(struct adspcmd));
pb->ioc = 0;
pb->mp = mp;
pb->csCode = dspClose;
pb->ioResult = 0;
completepb(sp, pb);
}
if ((sp->userFlags & eClosed) == 0)
DoClose(sp, errAborted, -1);
return 0;
}