1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28/* adspOpen.c v01.20
29 *
30 * From v01.20 08/23/90 Mike Shoemaker for MacOS
31 *    Modified for MP, 1996 by Tuyen Nguyen
32 *   Modified, April 9, 1997 by Tuyen Nguyen for MacOSX.
33 */
34
35#include <sys/errno.h>
36#include <sys/types.h>
37#include <sys/param.h>
38#include <machine/spl.h>
39#include <sys/systm.h>
40#include <sys/kernel.h>
41#include <sys/proc.h>
42#include <sys/filedesc.h>
43#include <sys/fcntl.h>
44#include <sys/mbuf.h>
45#include <sys/socket.h>
46#include <sys/socketvar.h>
47#include <sys/time.h>
48
49#include <netat/sysglue.h>
50#include <netat/appletalk.h>
51#include <netat/at_pcb.h>
52#include <netat/debug.h>
53#include <netat/adsp.h>
54#include <netat/adsp_internal.h>
55
56extern int *adsp_pidM;
57
58
59/*
60 * NextCID
61 *
62 * Create a unique connection ID.
63 *
64 * INPUTS:
65 * 		none
66 * OUTPUTS:
67 * 		unique connection ID
68 */
69
70unsigned short NextCID(void)
71{
72	unsigned short num;
73	register CCB *queue;
74
75	while (1) {
76	    num = ++adspGlobal.lastCID;
77	    /* qfind_w below is in 68K assembly */
78	    /* point to the first element */
79	    queue = (CCB *)AT_ADSP_STREAMS;
80	    while (queue) {
81		    /* and scan .. */
82		    if (queue->locCID == num)
83			break;
84		    queue = queue->ccbLink;
85	    }
86	    if (queue == (CCBPtr)NULL)
87		break;
88	}
89	return num;
90}
91
92static	byte xlateStateTbl[4] =	/* The value to be given to the CCB's state. */
93{				/* indexed by ocMode */
94	sOpening,		/* ocRequest */
95	sPassive,		/* ocPassive */
96	sOpening,		/* ocAccept */
97	sOpen			/* ocEstablish */
98};
99static	byte xlateOpenTbl[4] =	/* Value to use for open state. */
100{				/* indexed by ocMode */
101	O_STATE_OPENWAIT,	/* ocRequest */
102	O_STATE_LISTEN,		/* ocPassive */
103	O_STATE_ESTABLISHED,	/* ocAccept */
104	O_STATE_OPEN		/* ocEstablish */
105};
106
107/*
108 * adspOpen
109 *
110 * INPUTS:
111 * 	-->	ccbRefNum	refnum of connection end
112 *	-->	remoteCID	connection id of remote connection end
113 *	-->	remoteAddress	internet address of remote connection end
114 *	-->	filterAddress	filter for incoming open connection requests
115 *	-->	sendSeq		initial send sequence number to use
116 *	-->	sendWindow	initial size of remote end's receive buffer
117 *	--> 	recvSeq		initial receive sequence number to use
118 *	--> 	attnSendSeq	initial attention send sequence number
119 *	-->	attnRecvSeq	initial receive sequence number
120 *	-->	ocMode		connection opening mode
121 *	-->	ocMaximum	maximum retries of open connection request
122 *
123 * OUTPUTS:
124 *	<--	localCID	connection identifier of this connection end
125 *	<--	remoteCID	connection id of remote connection end
126 *	<--	remoteAddress
127 *	<--	sendSeq
128 *	<-- 	sendWindow
129 *	<--	attnSendSeq
130 *
131 * ERRORS:
132 *		errRefNum	bad connection refnum
133 *		errState	connection end must be closed
134 *		errOpening	open connection attempt failed
135 *		errAborted	request aborted by a remove or close call
136 */
137int adspOpen(sp, pb)		/* (DSPPBPtr pb) */
138    register CCBPtr sp;
139    register struct adspcmd *pb;
140{
141    int ocMode;
142    register gbuf_t *mp;
143
144    if (sp == 0) {
145	pb->ioResult = errRefNum; /* Unknown refnum */
146	return EINVAL;
147    }
148
149    if ((sp->state != sClosed) ||
150	(sp->removing)) { /* The CCB must be closed */
151	pb->ioResult = errState;
152	return EALREADY;
153    }
154
155    ocMode = pb->u.openParams.ocMode; /* get a local copy of open mode */
156	if (ocMode == ocRequest)
157		adsp_pidM[pb->socket] = 0;
158
159    /*
160     * Save parameters.  Fill in defaults if zero
161     */
162    if (pb->u.openParams.ocInterval)
163	sp->openInterval = pb->u.openParams.ocInterval;
164    else
165	sp->openInterval = ocIntervalDefault;
166
167    if (pb->u.openParams.ocMaximum)
168	sp->openRetrys = pb->u.openParams.ocMaximum;
169    else
170	sp->openRetrys = ocMaximumDefault;
171
172    sp->remoteAddress = *((AddrUnionPtr)&pb->u.openParams.remoteAddress);
173    /* Not used for passive */
174    /*
175     * Clear out send/receive buffers.
176     */
177    if (sp->sbuf_mb) { /* clear the send queue */
178	gbuf_freel(sp->sbuf_mb);
179	sp->sbuf_mb = 0;
180    }
181    if (sp->csbuf_mb) {
182	gbuf_freem(sp->csbuf_mb);
183	sp->csbuf_mb = 0;
184    }
185    if (sp->rbuf_mb) { /* clear the receive queue */
186	gbuf_freel(sp->rbuf_mb);
187	sp->rbuf_mb = 0;
188    }
189    if (sp->crbuf_mb) {
190	gbuf_freem(sp->crbuf_mb);
191	sp->crbuf_mb = 0;
192    }
193
194    sp->rData = 0;		/* Flag both buffers as empty */
195    sp->sData = 0;
196    sp->recvQPending = 0;	/* No bytes in receive queue */
197
198    /*
199     * Clear all of those pesky flags
200     */
201    sp->userFlags = 0;
202    sp->sendDataAck = 0;
203    sp->sendAttnAck = 0;
204    sp->sendAttnData = 0;
205    sp->callSend = 0;
206    sp->removing = 0;
207    sp->writeFlush = 0;
208
209    /*
210     * Reset round-trip timers
211     */
212    sp->roundTrip = sp->rtmtInterval;
213    sp->deviation = 0;
214
215    /*
216     * Reset stuff for retransmit advice packet
217     */
218    sp->badSeqCnt = 0;
219    /*
220     * Reset flow control variables
221     */
222    sp->pktSendMax = 1;	/* Slow start says we should set this to 1 */
223    sp->pktSendCnt = 0;
224    sp->rbufFull = 0;
225    sp->resentData = 0;
226    sp->noXmitFlow = 0;
227    sp->waitingAck = 0;
228
229    /*
230     * Copy required information out of parameter block
231     */
232    if (ocMode == ocAccept || ocMode == ocEstablish) {
233	sp->remCID = pb->u.openParams.remoteCID;
234	sp->sendSeq = sp->firstRtmtSeq = pb->u.openParams.sendSeq;
235	sp->sendWdwSeq = sp->sendSeq + pb->u.openParams.sendWindow;
236	sp->attnSendSeq = pb->u.openParams.attnSendSeq;
237    } else {			/* accept or establish */
238	sp->remCID = 0;
239	sp->sendSeq = 0;
240	sp->sendWdwSeq = 0;
241	sp->attnSendSeq = 0;
242    }
243
244    if (ocMode == ocEstablish) { /* Only set these if establish mode */
245	sp->recvSeq = pb->u.openParams.recvSeq;
246	sp->attnRecvSeq = pb->u.openParams.attnRecvSeq;
247	UAS_ASSIGN_HTON(sp->f.CID, sp->locCID); /* Preset the CID in the ADSP header */
248	/* This is done elsewhere for all other modes */
249	InsertTimerElem(&adspGlobal.slowTimers, &sp->ProbeTimer,
250			sp->probeInterval);
251    } else {			/* establish */
252	/* All other modes need a CID assigned */
253	sp->locCID = NextCID();
254	sp->recvSeq = 0;
255	sp->attnRecvSeq = 0;
256    }
257
258    /*
259     * Now set the state variables for this CCB.
260     */
261
262    sp->openState = xlateOpenTbl[ocMode-ocRequest];
263    sp->state = xlateStateTbl[ocMode-ocRequest];
264
265    if (ocMode == ocEstablish) { /* For establish call, we're done */
266	pb->ioResult = 0;
267	adspioc_ack(0, (gbuf_t *)pb->ioc, pb->gref);
268	return 0;
269    }
270
271    pb->qLink = 0;		/* Clear link field before putting on queue */
272    mp = gbuf_copym(pb->mp);	/* Save parameter block to match later */
273
274    if (mp == 0) {
275	    pb->ioResult = errDSPQueueSize;
276	    return ENOBUFS;
277    }
278    pb->ioResult = 1;	/* not open -> not done */
279    adspioc_ack(0, (gbuf_t *)pb->ioc, pb->gref); /* release user */
280    sp->opb = (struct adspcmd *)gbuf_rptr(mp);
281    sp->opb->ioc = 0;		/* unlink saved pb from ioctl block */
282    sp->opb->mp = mp;
283
284    /*
285     * For request & accept, need to send a packet
286     */
287    if ((ocMode == ocRequest) || (ocMode == ocAccept)) {
288	sp->sendCtl |= (1 << (ocMode == ocRequest ?
289			      ADSP_CTL_OREQ : ADSP_CTL_OREQACK));
290	CheckSend(sp);
291    }
292    return 0;
293}
294
295int adspMode(pb)
296    register struct adspcmd *pb;
297{
298    return pb->u.openParams.ocMode;
299}
300