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/*
29 *	Copyright (c) 1990, 1995-1998 Apple Computer, Inc.
30 *	All Rights Reserved.
31 */
32
33/* Control.c
34 * From Mike Shoemaker v01.25 07/02/90 for MacOS
35 * 09/07/95 - Modified for performance (Tuyen Nguyen)
36 *    Modified for MP, 1996 by Tuyen Nguyen
37 *   Modified, April 9, 1997 by Tuyen Nguyen for MacOSX.
38 */
39
40#include <sys/errno.h>
41#include <sys/types.h>
42#include <sys/param.h>
43#include <machine/spl.h>
44#include <sys/systm.h>
45#include <sys/kernel.h>
46#include <sys/proc.h>
47#include <sys/filedesc.h>
48#include <sys/fcntl.h>
49#include <sys/mbuf.h>
50#include <sys/time.h>
51#include <sys/socket.h>
52
53#include <netat/sysglue.h>
54#include <netat/appletalk.h>
55#include <netat/ddp.h>
56#include <netat/at_pcb.h>
57#include <netat/debug.h>
58#include <netat/adsp.h>
59#include <netat/adsp_internal.h>
60
61/* # of additional ticks to add to any timer that we're queuing up.  For
62 * very short delays (1 and 2), the timer fires before the transmit
63 * even takes place */
64#define TX_DLY	2
65
66int adsp_window = 1;
67
68int attachData(CCBPtr, gbuf_t *mp);
69
70/*
71 * CalcRecvWdw
72 *
73 * INPUTS:
74 *		sp		ADSP Stream
75 * OUTPUTS:
76 *		# of bytes in avail in local receive queue
77 */
78int CalcRecvWdw(sp)		/* (CCBPtr sp) */
79    CCBPtr sp;
80{
81    int bytes;
82
83    bytes = calcRecvQ(sp);
84    bytes = sp->rbuflen - bytes; /* get what is left */
85
86    if ((bytes <= 16)) {		/* %%% this should be zero */
87	sp->rbufFull = 1;	/* Save flag that our recv buf is full */
88	return 0;
89    }
90    else
91	return ((bytes+bytes+bytes) >> 2) + 1; /* %%% */
92}
93
94int
95calcRecvQ(sp)
96    CCBPtr sp;
97{
98    int bytes = 0;
99#ifdef AT_Socket
100    register struct mbuf *m, *p;
101
102    if (((sp->gref)->so)->so_rcv.sb_mb)
103      for (p = ((sp->gref)->so)->so_rcv.sb_mb; p; p = p->m_nextpkt)
104	for (m = p; m; m = m->m_next)
105	  bytes += m->m_len;
106#else
107    register gbuf_t *mb;
108
109    if (sp->rData) {		/* There is data in buffer */
110	if ((mb = sp->rbuf_mb)) {
111	    do {
112		bytes += gbuf_msgsize(mb);
113		mb = gbuf_next(mb);
114	    } while (mb);
115	}
116	if ((mb = sp->crbuf_mb))
117	    bytes += gbuf_msgsize(mb);
118    }
119#endif
120    return bytes;
121}
122
123/*
124 * CheckSend
125 *
126 * Check to see if the transmit PB is available and if there is anything
127 * to transmit. Start off any pending transmit.
128 *
129 * Normally called from the write completion routine
130 *
131 * INPUTS:
132 * 		sp		Connection control block
133 * OUTPUTS:
134 * 		true if sent a packet
135 */
136void CheckSend(sp)		/* (CCBPtr sp) */
137    register CCBPtr sp;
138{
139    int i;
140    int	attnMsg;		/* True if attention message */
141    register gbuf_t *mp;	/* send message block */
142#ifdef notdef
143    register gbuf_t *tmp;
144    u_char current;
145#endif
146    char *dp;			/* a data pointer */
147    int use_attention_code;
148    int len;			/* length used in allocd mblk */
149    int datalen;		/* amount of data attached to mblk */
150    gbuf_t *mprev = 0, *mlist = 0;
151
152top:
153
154    if (sp->state == sClosed)
155	return;
156
157				/* get a message block to hold DDP and
158				 * ADSP headers + 2 bytes of attention
159				 * code if necessary */
160    if ((mp = gbuf_alloc(AT_WR_OFFSET + DDPL_FRAME_LEN + ADSP_FRAME_LEN + ADSP_OPEN_FRAME_LEN + 2,
161		     PRI_LO)) == 0) {
162	if (mlist)
163		gbuf_freel(mlist);
164	return;		/* can't get buffers... do nothing! */
165    }
166    sp->callSend = 0;		/* Clear flag */
167    use_attention_code = 0;
168    len = 0;
169    datalen = 0;
170
171    gbuf_rinc(mp,AT_WR_OFFSET);
172    gbuf_wset(mp,DDPL_FRAME_LEN); /* leave room for DDP header */
173
174    if (sp->sendCtl) {
175	short mask = 0;
176
177	i = sp->sendCtl;	/* get local copy bitmap of */
178				/* which ctl packets to send. */
179	attnMsg = 0;
180
181	if (i & 0x1E)		/* One of the open ctrl packets */
182	{
183
184	    /* point past ADSP header (no attention) */
185	    dp = ((char *) gbuf_wptr(mp)) + ADSP_FRAME_LEN;
186	    UAL_ASSIGN_HTON(sp->f.pktFirstByteSeq, sp->firstRtmtSeq);
187
188	    UAS_ASSIGN_HTON(sp->of.version, netw(0x0100)); /* Fill in open connection parms */
189	    UAS_ASSIGN_HTON(sp->of.dstCID, sp->remCID);	/* Destination CID */
190	    UAL_ASSIGN_HTON(sp->of.pktAttnRecvSeq, sp->attnRecvSeq);
191	    bcopy((caddr_t) &sp->of, (caddr_t) dp, ADSP_OPEN_FRAME_LEN);
192	    len += ADSP_OPEN_FRAME_LEN;
193
194	    if (i & B_CTL_OREQ) {
195		UAS_ASSIGN_HTON(sp->f.CID, sp->locCID);
196		mask = B_CTL_OREQ;
197		sp->f.descriptor = ADSP_CONTROL_BIT | ADSP_CTL_OREQ;
198	    } else if (i & B_CTL_OACK) {
199		UAS_ASSIGN_HTON(sp->f.CID, sp->locCID);
200		mask = B_CTL_OACK;
201		sp->f.descriptor = ADSP_CONTROL_BIT | ADSP_CTL_OACK;
202	    } else if (i & B_CTL_OREQACK) {
203		UAS_ASSIGN_HTON(sp->f.CID, sp->locCID);
204		mask = B_CTL_OREQACK;
205		sp->f.descriptor = ADSP_CONTROL_BIT | ADSP_CTL_OREQACK;
206	    } else 		/* Deny */
207	    {
208		UAS_ASSIGN(sp->f.CID, 0);
209		mask = B_CTL_ODENY;
210		sp->f.descriptor = ADSP_CONTROL_BIT | ADSP_CTL_ODENY;
211		UAL_ASSIGN(sp->f.pktFirstByteSeq, 0);
212	    }
213
214	    if (i & (B_CTL_OREQ | B_CTL_OREQACK))
215		/* Need to start up a timer for it */
216	    {
217		/* It's possible that we've received a duplicate
218		 * open request.  In this case, there will already be
219		 * a timer queued up for the request+ack
220		 *  packet we sent the first time.  So remove the timer
221		 * and start another.
222		 */
223	        RemoveTimerElem(&adspGlobal.slowTimers, &sp->ProbeTimer);
224		InsertTimerElem(&adspGlobal.slowTimers, &sp->ProbeTimer,
225				sp->openInterval+1);
226	    }
227	} else {
228	    /* seq # of next byte to send */
229	    UAL_ASSIGN_HTON(sp->f.pktFirstByteSeq, sp->sendSeq);
230
231	    if (i & B_CTL_CLOSE) {
232		sp->state = sClosed; /* Now we're closed */
233		mask = B_CTL_CLOSE;
234		sp->f.descriptor = ADSP_CONTROL_BIT | ADSP_CTL_CLOSE;
235	    } else if (i & B_CTL_PROBE) {
236		mask = B_CTL_PROBE;
237		sp->f.descriptor =
238		    ADSP_CONTROL_BIT | ADSP_CTL_PROBE | ADSP_ACK_REQ_BIT;
239	    } else if (i & B_CTL_FRESET) {
240		mask = B_CTL_FRESET;
241		sp->f.descriptor = ADSP_CONTROL_BIT | ADSP_CTL_FRESET;
242		InsertTimerElem(&adspGlobal.fastTimers,
243				&sp->ResetTimer, sp->rtmtInterval+TX_DLY);
244	    } else if (i & B_CTL_FRESETACK) {
245		mask = B_CTL_FRESETACK;
246		sp->f.descriptor = ADSP_CONTROL_BIT | ADSP_CTL_FRESET_ACK;
247	    }
248	    else if (i & B_CTL_RETRANSMIT) {
249		mask = B_CTL_RETRANSMIT;
250		sp->f.descriptor = ADSP_CONTROL_BIT | ADSP_CTL_RETRANSMIT;
251	    }
252	    else {
253		dPrintf(D_M_ADSP, D_L_ERROR, ("CheckSend: Control bit error\n"));
254	   }
255	}			/* non open control packet */
256
257	sp->sendCtl &= ~mask;
258	goto sendit;
259    }				/* send control packet */
260
261    if (sp->sendAttnData)	/* Send attn ready to go? */
262    {
263	sp->sendAttnData = 0;	/* Clear Flags */
264	if (sp->sapb) {
265	    sp->sendAttnAck  = 0; /* This will also do an Attn Ack */
266
267	    attnMsg = 1;
268	    sp->f.descriptor = ADSP_ATTENTION_BIT | ADSP_ACK_REQ_BIT;
269	    if (gbuf_cont(sp->sapb->mp)) {
270		gbuf_cont(mp) = gbuf_dupm(gbuf_cont(sp->sapb->mp));
271		/* Major hack here.  The ADSP Attn code is butted up against
272		 * the end of the adsp packet header, and the length is
273		 * increased by 2.  (There is a pad field behind the adsp
274		 * header in the CCB just for this purpose.)
275		 */
276	    }
277	    use_attention_code++;
278
279	    sp->f.data[0] = high(sp->sapb->u.attnParams.attnCode);
280	    sp->f.data[1] = low(sp->sapb->u.attnParams.attnCode);
281	    InsertTimerElem(&adspGlobal.fastTimers, &sp->AttnTimer,
282			                             sp->rtmtInterval+TX_DLY);
283	    goto sendit;
284	}
285    }				/* attn data */
286
287    if (sp->sendAttnAck)	/* Send attn ack ready to go? */
288    {
289	attnMsg = 1;
290	sp->f.descriptor = ADSP_CONTROL_BIT | ADSP_ATTENTION_BIT;
291	sp->sendAttnAck = 0;
292	goto sendit;
293    }				/* attn ack */
294
295    if ((sp->state == sOpen || sp->state == sClosing) && /* Correct state */
296	(!sp->waitingAck) &&	/* not waiting for an ACK */
297	(sp->sData) &&		/* have data to send */
298	(GTE(sp->sendWdwSeq,sp->sendSeq)) && /* they have room to accept it */
299	(sp->pktSendCnt < sp->pktSendMax)) /* haven't sent too many pkts
300					    * in a row. */
301    {
302	attnMsg = 0;
303	if ((datalen = attachData(sp, mp))) /* attach data to mp */
304	    goto sendit;	/* if successful, sendit */
305    }
306
307    if (sp->sendDataAck) {
308	UAL_ASSIGN_HTON(sp->f.pktFirstByteSeq, sp->sendSeq); /* seq # of next byte */
309	attnMsg = 0;
310	sp->f.descriptor = ADSP_CONTROL_BIT;
311	goto sendit;
312    }
313
314    /*
315     * Nothing left to do...
316     */
317    if (mp)
318	gbuf_freem(mp);
319    if (mlist)
320	adsp_sendddp(sp, mlist, 0, &sp->remoteAddress, DDP_ADSP);
321    return;
322
323sendit:
324
325    if (attnMsg) {
326	UAL_ASSIGN_HTON(sp->f.pktFirstByteSeq, sp->attnSendSeq);
327	UAL_ASSIGN_HTON(sp->f.pktNextRecvSeq, sp->attnRecvSeq);
328	UAS_ASSIGN(sp->f.pktRecvWdw, 0);	/* Always zero in attn pkt */
329    } else {
330	sp->sendDataAck = 0;
331	UAL_ASSIGN_HTON(sp->f.pktNextRecvSeq, sp->recvSeq);
332	UAS_ASSIGN_HTON(sp->f.pktRecvWdw, CalcRecvWdw(sp));
333    }
334    if (use_attention_code) {
335	bcopy((caddr_t) &sp->f, (caddr_t) gbuf_wptr(mp), ADSP_FRAME_LEN + 2);
336	len += ADSP_FRAME_LEN + 2;
337    } else {
338	bcopy((caddr_t) &sp->f, (caddr_t) gbuf_wptr(mp), ADSP_FRAME_LEN);
339	len += ADSP_FRAME_LEN;
340    }
341    gbuf_winc(mp,len);		/* update mblk length  */
342    if (mlist)
343	gbuf_next(mprev) = mp;
344    else
345	mlist = mp;
346    mprev = mp;
347
348    if (sp->state == sClosed) {	/* must have sent a close advice */
349				/* send header + data */
350	adsp_sendddp(sp, mlist, 0, &sp->remoteAddress, DDP_ADSP);
351	DoClose(sp, 0, -1);	/* complete close! */
352	return;
353    }
354    if (sp->state == sClosing) /* See if we were waiting on this write */
355	CheckOkToClose(sp);
356    goto top;
357}
358
359/*
360 * completepb delivers a paramater block with all its appropriate fields
361 * set back to the user.
362 *
363 * The assumptions here are that the PB is not linked to any queue,
364 * that the fields including ioResult are set, and that the
365 * kernel is no longer interested in the mblks that may or
366 * maynot be linked to this pb.
367 */
368void completepb(sp, pb)
369    register CCBPtr sp;
370    register struct adspcmd *pb;
371{
372    if (sp->gref && (sp->gref->info == (caddr_t)sp->sp_mp)) {
373	if (gbuf_len(pb->mp) > sizeof(struct adspcmd))
374		gbuf_wset(pb->mp,sizeof(struct adspcmd));
375	SndMsgUp(sp->gref, pb->mp);
376	NotifyUser(sp);
377    } else
378	gbuf_freem(pb->mp);
379}
380
381
382int
383attachData(sp, mp)
384    register CCBPtr sp;
385    register gbuf_t *mp;
386{
387    int	seq;
388    int cnt;
389    char eom = 0;
390    int bsize;
391    int diff;
392    char sendAckReq;
393    int partial = 0;		/* flag for a partial send */
394    int tcnt = 0;
395    register gbuf_t *smp;	/* send data message block */
396    register gbuf_t *psmp;	/* previous message block */
397
398    sendAckReq = 0;
399
400    if (LT(sp->sendSeq, sp->firstRtmtSeq)) /* Sanity check on send seq */
401	sp->sendSeq = sp->firstRtmtSeq; /* seq must be oldest in buffer. */
402
403    /* This test and assignment was necessary because the retry VBL could
404     * have fired and reset send Seq to first Rtmt Seq, and then an
405     * expected ACK comes in that bumps first Rtmt Seq up.  Then we
406     * have the problem that send Seq is less than first Rtmt Seq.
407     * The easiest fix to this timing dilemma seems to be to reset
408     * sendSeq to first Rtmt Seq if we're sending the first packet.
409     */
410    UAL_ASSIGN_HTON(sp->f.pktFirstByteSeq, sp->sendSeq);
411
412    if ((smp = sp->sbuf_mb)) /* Get oldest header */
413	eom = 1;
414    else if ((smp = sp->csbuf_mb))
415	eom = 0;
416
417    if (smp == 0) {		/* this shouldn't happen... */
418	    sp->sData = 0;
419	    return 0;
420    }
421    /*
422     * Must find next byte to transmit
423     */
424    seq = sp->firstRtmtSeq;	/* Seq # of oldest in buffer */
425    while ((diff = (sp->sendSeq - seq)) >= ((bsize = gbuf_msgsize(smp)) + eom)) {
426	seq += bsize + eom;	/* update sequence # */
427	if (gbuf_next(smp)) { /* if another send buffer */
428	    smp = gbuf_next(smp);
429	    eom = 1;
430	} else if (smp == sp->csbuf_mb) { /* seen the current one? */
431	    smp = 0;
432	    break;
433	} else if (sp->csbuf_mb) { /* look at it */
434	    smp = sp->csbuf_mb;
435	    eom = 0;
436	} else {		/* no more buffers */
437	    smp = 0;
438	    break;
439	}
440    }			/* while */
441
442    if (smp) {
443	if (gbuf_next(smp) == 0)	/* last block */
444	    sendAckReq = 1;
445	cnt = bsize - diff;	/* # of bytes in this block */
446    } else
447	cnt = 0;
448
449    /*
450     * Check to see if the number of bytes is less than the 'send
451     * Blocking' setting. If so, then we won't send this data unless
452     * we're flushing.  So we set up a timer to force a flush later.
453     */
454    if ((cnt < sp->sendBlocking) && !sp->writeFlush) {
455        InsertTimerElem(&adspGlobal.fastTimers, &sp->FlushTimer,
456			                         sp->sendInterval);
457	return 0;		/* no data to send */
458    }
459
460    if (cnt > ADSP_MAX_DATA_LEN) { /* truncate to one packet */
461	cnt = ADSP_MAX_DATA_LEN;
462	eom = 0;
463	sendAckReq = 0;	/* Won't send ack because end of data */
464	partial++;
465    }
466
467    if (smp) {
468	/* trim extra bytes off the beginning of the "block" before the copy */
469	while (diff) {
470	    if (gbuf_len(smp) > diff)
471		break;
472	    else
473		diff -= gbuf_len(smp);
474	    smp = gbuf_cont(smp);
475        }
476	if((gbuf_cont(mp) = gbuf_dupm(smp)) == 0) /* copy the data */
477	    return 0;
478	smp = gbuf_cont(mp);	/* use the new message blocks */
479        gbuf_rinc(smp,diff);	/* and get to the first byte of data to send */
480    }
481    /*
482     * Check to see if this many bytes will close the other end's
483     * receive window. If so, we need to send an ack request along
484     * with this.  sendWdwSeq is the seq # of the last byte that
485     * the remote has room for
486     */
487    if ((diff = sp->sendWdwSeq + 1 - sp->sendSeq) <= cnt) {
488	if (diff < cnt) { /* Won't fit exactly */
489	    eom = 0;	/* so can't send EOM */
490	    cnt = diff;
491	    partial++;
492	}
493	sendAckReq = 1;		/* Make him tell us new recv. window */
494	sp->noXmitFlow = 1;	/* Don't do flow control calc. */
495    }
496
497    /* trim extra bytes off the tail of the "block" after the copy */
498    if (partial && smp) {
499	psmp = smp;
500	tcnt = cnt;
501	while (tcnt && smp) { /* while there are message blocks and data */
502	    if (tcnt >= gbuf_len(smp)) {
503		tcnt -= gbuf_len(smp);
504		if (tcnt) {
505		    psmp = smp;
506		    smp = gbuf_cont(smp);
507		} else {
508		    if (psmp != smp) { /* not the first item on the list */
509			gbuf_cont(psmp) = 0;
510			gbuf_freem(smp);
511			smp = psmp;
512		    } else {
513			gbuf_freem(gbuf_cont(smp));
514			gbuf_cont(smp) = 0;
515		    }
516		    break;
517		}
518	    } else {
519		gbuf_wset(smp,tcnt);
520		if (gbuf_cont(smp)) {
521		    gbuf_freem(gbuf_cont(smp));
522		    gbuf_cont(smp) = 0;
523		}
524		break;
525	    }
526	}
527    }
528
529    sp->sendSeq += cnt + eom;	/* Update sendSeq field */
530
531    if (GT(sp->sendSeq, sp->maxSendSeq)) /* Keep track of >st ever sent */
532	sp->maxSendSeq = sp->sendSeq;
533
534    if (eom)
535	sp->f.descriptor = ADSP_EOM_BIT;
536    else
537	sp->f.descriptor = 0;
538
539    if (sendAckReq || (++sp->pktSendCnt >= sp->pktSendMax)) {
540	/* Last packet in a series */
541	sp->f.descriptor |= ADSP_ACK_REQ_BIT; /* We want an ack to this */
542	sp->waitingAck = 1;	/* Flag that we're waiting */
543	sp->sendStamp = SysTicks(); /* Save time we sent request */
544	sp->timerSeq = sp->sendSeq; /* Save seq # we want acked */
545	InsertTimerElem(&adspGlobal.fastTimers, &sp->RetryTimer,
546			sp->rtmtInterval+TX_DLY);
547    }
548    return cnt + eom;
549}
550
551
552
553