Source to bsd/netat/adsp_Open.c
/*
* Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* The contents of this file constitute Original Code as defined in and
* are subject to the Apple Public Source License Version 1.1 (the
* "License"). You may not use this file except in compliance with the
* License. Please obtain a copy of the License at
* http://www.apple.com/publicsource and read it before using this file.
*
* This Original Code and all software distributed under the License are
* distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
* License for the specific language governing rights and limitations
* under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/* adspOpen.c v01.20
*
* From v01.20 08/23/90 Mike Shoemaker for MacOS
* Modified for MP, 1996 by Tuyen Nguyen
* Modified, April 9, 1997 by Tuyen Nguyen for MacOSX.
*/
#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/at_pcb.h>
#include <netat/debug.h>
#include <netat/adsp.h>
#include <netat/adsp_internal.h>
extern atlock_t adspgen_lock;
/*
* NextCID
*
* Create a unique connection ID.
*
* INPUTS:
* none
* OUTPUTS:
* unique connection ID
*/
unsigned short NextCID()
{
int s;
unsigned short num;
register CCB *queue;
while (1) {
ATDISABLE(s, adspgen_lock); /* Disable interrupts */
num = ++adspGlobal.lastCID;
/* qfind_w below is in 68K assembly */
/* point to the first element */
queue = (CCB *)AT_ADSP_STREAMS;
while (queue) {
/* and scan .. */
if (queue->locCID == num)
break;
queue = queue->ccbLink;
}
ATENABLE(s, adspgen_lock);
if (queue == (CCBPtr)NULL)
break;
}
return num;
}
static byte xlateStateTbl[4] = /* The value to be given to the CCB's state. */
{ /* indexed by ocMode */
sOpening, /* ocRequest */
sPassive, /* ocPassive */
sOpening, /* ocAccept */
sOpen /* ocEstablish */
};
static byte xlateOpenTbl[4] = /* Value to use for open state. */
{ /* indexed by ocMode */
O_STATE_OPENWAIT, /* ocRequest */
O_STATE_LISTEN, /* ocPassive */
O_STATE_ESTABLISHED, /* ocAccept */
O_STATE_OPEN /* ocEstablish */
};
/*
* adspOpen
*
* INPUTS:
* --> ccbRefNum refnum of connection end
* --> remoteCID connection id of remote connection end
* --> remoteAddress internet address of remote connection end
* --> filterAddress filter for incoming open connection requests
* --> sendSeq initial send sequence number to use
* --> sendWindow initial size of remote end's receive buffer
* --> recvSeq initial receive sequence number to use
* --> attnSendSeq initial attention send sequence number
* --> attnRecvSeq initial receive sequence number
* --> ocMode connection opening mode
* --> ocMaximum maximum retries of open connection request
*
* OUTPUTS:
* <-- localCID connection identifier of this connection end
* <-- remoteCID connection id of remote connection end
* <-- remoteAddress
* <-- sendSeq
* <-- sendWindow
* <-- attnSendSeq
*
* ERRORS:
* errRefNum bad connection refnum
* errState connection end must be closed
* errOpening open connection attempt failed
* errAborted request aborted by a remove or close call
*/
int adspOpen(sp, pb) /* (DSPPBPtr pb) */
register CCBPtr sp;
register struct adspcmd *pb;
{
extern int adsp_pidM[];
int ocMode;
register gbuf_t *mp;
if (sp == 0) {
pb->ioResult = errRefNum; /* Unknown refnum */
return EINVAL;
}
if ((sp->state != sClosed) ||
(sp->removing)) { /* The CCB must be closed */
pb->ioResult = errState;
return EALREADY;
}
ocMode = pb->u.openParams.ocMode; /* get a local copy of open mode */
if (ocMode == ocRequest)
adsp_pidM[pb->socket] = 0;
/*
* Save parameters. Fill in defaults if zero
*/
if (pb->u.openParams.ocInterval)
sp->openInterval = pb->u.openParams.ocInterval;
else
sp->openInterval = ocIntervalDefault;
if (pb->u.openParams.ocMaximum)
sp->openRetrys = pb->u.openParams.ocMaximum;
else
sp->openRetrys = ocMaximumDefault;
sp->remoteAddress = *((AddrUnionPtr)&pb->u.openParams.remoteAddress);
/* Not used for passive */
/*
* Clear out send/receive buffers.
*/
if (sp->sbuf_mb) { /* clear the send queue */
gbuf_freel(sp->sbuf_mb);
sp->sbuf_mb = 0;
}
if (sp->csbuf_mb) {
gbuf_freem(sp->csbuf_mb);
sp->csbuf_mb = 0;
}
if (sp->rbuf_mb) { /* clear the receive queue */
gbuf_freel(sp->rbuf_mb);
sp->rbuf_mb = 0;
}
if (sp->crbuf_mb) {
gbuf_freem(sp->crbuf_mb);
sp->crbuf_mb = 0;
}
sp->rData = 0; /* Flag both buffers as empty */
sp->sData = 0;
sp->recvQPending = 0; /* No bytes in receive queue */
/*
* Clear all of those pesky flags
*/
sp->userFlags = 0;
sp->sendDataAck = 0;
sp->sendAttnAck = 0;
sp->sendAttnData = 0;
sp->callSend = 0;
sp->removing = 0;
sp->writeFlush = 0;
/*
* Reset round-trip timers
*/
sp->roundTrip = sp->rtmtInterval;
sp->deviation = 0;
/*
* Reset stuff for retransmit advice packet
*/
sp->badSeqCnt = 0;
/*
* Reset flow control variables
*/
sp->pktSendMax = 1; /* Slow start says we should set this to 1 */
sp->pktSendCnt = 0;
sp->rbufFull = 0;
sp->resentData = 0;
sp->noXmitFlow = 0;
sp->waitingAck = 0;
/*
* Copy required information out of parameter block
*/
if (ocMode == ocAccept || ocMode == ocEstablish) {
sp->remCID = pb->u.openParams.remoteCID;
sp->sendSeq = sp->firstRtmtSeq = pb->u.openParams.sendSeq;
sp->sendWdwSeq = sp->sendSeq + pb->u.openParams.sendWindow;
sp->attnSendSeq = pb->u.openParams.attnSendSeq;
} else { /* accept or establish */
sp->remCID = 0;
sp->sendSeq = 0;
sp->sendWdwSeq = 0;
sp->attnSendSeq = 0;
}
if (ocMode == ocEstablish) { /* Only set these if establish mode */
sp->recvSeq = pb->u.openParams.recvSeq;
sp->attnRecvSeq = pb->u.openParams.attnRecvSeq;
UAS_ASSIGN(sp->f.CID, sp->locCID); /* Preset the CID in the ADSP header */
/* This is done elsewhere for all other modes */
InsertTimerElem(&adspGlobal.slowTimers, &sp->ProbeTimer,
sp->probeInterval);
} else { /* establish */
/* All other modes need a CID assigned */
sp->locCID = NextCID();
sp->recvSeq = 0;
sp->attnRecvSeq = 0;
}
/*
* Now set the state variables for this CCB.
*/
sp->openState = xlateOpenTbl[ocMode-ocRequest];
sp->state = xlateStateTbl[ocMode-ocRequest];
if (ocMode == ocEstablish) { /* For establish call, we're done */
pb->ioResult = 0;
adspioc_ack(0, pb->ioc, pb->gref);
return 0;
}
pb->qLink = 0; /* Clear link field before putting on queue */
mp = gbuf_copym(pb->mp); /* Save parameter block to match later */
if (mp == 0) {
pb->ioResult = errDSPQueueSize;
return ENOBUFS;
}
pb->ioResult = 1; /* not open -> not done */
adspioc_ack(0, pb->ioc, pb->gref); /* release user */
sp->opb = (struct adspcmd *)gbuf_rptr(mp);
sp->opb->ioc = 0; /* unlink saved pb from ioctl block */
sp->opb->mp = mp;
/*
* For request & accept, need to send a packet
*/
if ((ocMode == ocRequest) || (ocMode == ocAccept)) {
sp->sendCtl |= (1 << (ocMode == ocRequest ?
ADSP_CTL_OREQ : ADSP_CTL_OREQACK));
CheckSend(sp);
}
return 0;
}
int adspMode(pb)
register struct adspcmd *pb;
{
return pb->u.openParams.ocMode;
}