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 * RxData.c
30 *
31 * From v01.28   Handle an incoming Data Packet       06/21/90 mbs
32 */
33/*
34 * Change log:
35 *   06/29/95 - Modified to handle flow control for writing (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/socket.h>
51#include <sys/socketvar.h>
52#include <sys/time.h>
53
54#include <netat/sysglue.h>
55#include <netat/appletalk.h>
56#include <netat/at_pcb.h>
57#include <netat/debug.h>
58#include <netat/adsp.h>
59#include <netat/adsp_internal.h>
60
61gbuf_t *releaseData(gbuf_t *, int);
62
63gbuf_t *releaseData(mp, len)
64    gbuf_t *mp;
65    int len;
66{
67    register gbuf_t *tmp;
68    register int cnt;
69    int freeit;
70
71    dPrintf(D_M_ADSP, D_L_TRACE,
72	    ("releaseData: mbuf=0x%x, len=%d\n", (unsigned)mp, len));
73
74    KERNEL_DEBUG(DBG_ADSP_RCV, 0, mp, len, 0, 0);
75
76    do {
77	freeit = 1;		/* assume we use the whole mblk */
78	if ((cnt = gbuf_len(mp)) > len) {
79	    freeit = 0;		/* using only part of the mblk */
80	    cnt = len;
81	}
82	gbuf_rinc(mp,cnt);
83	len -= cnt;
84	tmp = mp;
85	mp = gbuf_cont(mp);
86	if (freeit) {
87	    gbuf_freeb(tmp);
88	} else
89	    return tmp;		/* if we don't use the whole block */
90				/* pass back the partial gbuf_t pointer */
91    } while (len && mp);
92    return mp;
93}
94
95/*
96 * CheckRecvSeq
97 *
98 * We just got a non-attention packet.  Check the pktNextRecvSeq field
99 * to see if it acknowledges any of our sent data.
100 *
101 * If any data was acked, check to see if we have anything to fill the
102 * newly opened up remote receive window. Otherwise, if the ACK request
103 * bit was set, we need to send an Ack Packet
104 *
105 * Always called as the result of receiving a packet.  Interrupts
106 * are completely masked when this routine is called.
107 *
108 * INPUTS:
109 *    sp stream
110 *    f  pointer to ASDP header
111 * OUTPUTS:
112 *    none
113 */
114void CheckRecvSeq(sp, f)	/* (CCBPtr sp, ADSP_FRAMEPtr f) */
115    register CCBPtr sp;
116    register ADSP_FRAMEPtr f;
117{
118    int pktNextRecvSeq;
119    int sendWdwSeq;
120    int eom;
121    int hlen;
122    register gbuf_t *mp;
123
124    if (f->descriptor & ADSP_ACK_REQ_BIT) { /* He wants an Ack */
125	sp->sendDataAck = 1;
126	sp->callSend = 1;
127    }
128
129    pktNextRecvSeq = UAL_VALUE_NTOH(f->pktNextRecvSeq); /* Local copy */
130
131    /*
132     * Make sure the sequence number corresponds to reality -- i.e. for
133     * unacknowledged data that we have sent
134     */
135
136    if (GT(pktNextRecvSeq, sp->maxSendSeq)) /* We've never sent this seq #! */
137	goto noack;
138
139    if (GTE(pktNextRecvSeq, sp->timerSeq) && sp->waitingAck) {
140	/* This acks our Ack Request */
141	sp->waitingAck = 0;	/* Allow sending more */
142	sp->pktSendCnt = 0;	/* Reset packet count */
143	/* Remove retry timer */
144	RemoveTimerElem(&adspGlobal.fastTimers, &sp->RetryTimer);
145
146	if (!sp->resentData) {	/* Data sent without retries */
147	    short diff;		/* Signed!! */
148	    /* All timings done in 6th second base */
149	    /* The contortions here are to prevent C from promoting
150	     * everything to longs and then using a library routine
151	     * to do the division. As 16-bit words, a DIVU instruction
152	     * is used.
153	     */
154
155	    diff = (((word)(SysTicks() - sp->sendStamp)) / (word)10) -
156		sp->roundTrip + 1;
157
158	    sp->roundTrip += diff >> 3;	/* Update average */
159
160	    if (diff < 0)	/* Take absolute value */
161		diff = -diff;
162	    sp->deviation += (diff - sp->deviation) >> 2; /* Update deviation*/
163
164	    sp->rtmtInterval = sp->roundTrip +
165		((short)2 * (short)sp->deviation);
166
167	    if (!sp->noXmitFlow &&
168		sp->pktSendMax < 50) /* Bump # of sequential */
169		sp->pktSendMax++; /* Packets we'll send */
170
171	    sp->noXmitFlow = 0;
172	}
173	else
174	    sp->resentData = 0;
175
176    }				/* Acked our data */
177
178    if (LTE(pktNextRecvSeq,
179	    sp->firstRtmtSeq)) /* Was duplicate ack, so ignore */
180	goto noack;
181
182    if (!sp->sData)		/* If nothing in send queue, ignore */
183	goto noack;
184
185
186    do {			/* This acks bytes in our buffer */
187	if ((mp = sp->sbuf_mb)) {	/* Get ptr to oldest data header */
188	    sp->sbuf_mb = gbuf_next(mp); /* unlink it from send queue */
189	    eom = 1;
190	} else {
191	    mp = sp->csbuf_mb;
192	    sp->csbuf_mb = 0;
193	    eom = 0;
194	}
195
196	if (mp == 0) {		/* shouldn't happen! */
197	    sp->sData = 0;
198	    goto noack;
199	}
200	/*
201	 * Does this ack the entire data block we're now pointing at?
202	 */
203	if (LTE((sp->firstRtmtSeq + eom + (hlen = gbuf_msgsize(mp))),
204		 pktNextRecvSeq)) {
205
206	    gbuf_freem(mp);
207
208	    /* Update seq # of oldest byte in bfr */
209	    sp->firstRtmtSeq += eom + hlen;
210
211	    if ((sp->sbuf_mb == 0) && (sp->csbuf_mb == 0)) {
212		/* If this was only block, then ... */
213		sp->sData = 0;	/* ... no data in queue */
214		sp->writeFlush = 0;
215		if (sp->state == sClosing) /* this may allow us to close... */
216		    CheckOkToClose(sp);
217		atalk_enablew(sp->gref);
218		break;
219	    }
220	}			/* whole data block acked */
221	else			/* Only some of the data was acked */
222	{
223	    short acked;
224
225	    acked = (pktNextRecvSeq - sp->firstRtmtSeq);
226	    mp = releaseData(mp, acked);
227	    if (eom) {
228		if (mp) {
229			gbuf_next(mp) = sp->sbuf_mb;
230			sp->sbuf_mb = mp;
231		}
232	    } else
233		sp->csbuf_mb = mp;
234
235	    sp->firstRtmtSeq = pktNextRecvSeq; /* Update seq # oldest byte */
236	    break;
237	}
238    } while (LT(sp->firstRtmtSeq, pktNextRecvSeq));
239
240    if (sp->sData)		/* We've got stuff to send */
241	sp->callSend = 1;
242
243noack:
244    sendWdwSeq = UAS_VALUE_NTOH(f->pktRecvWdw) - 1 + pktNextRecvSeq;
245
246    if (GT(sendWdwSeq, sp->sendWdwSeq))	/* Don't make send window smaller */
247    {
248	sp->callSend = 1;	/* His recv wdw opened, so see */
249				/* if we can send more data */
250	sp->sendWdwSeq	= sendWdwSeq;
251    }
252}
253
254/*
255 * RXData
256 *
257 * We just got a Data Packet
258 * See if it came from anybody we know.
259 *
260 * Called from ADSP Packet with interrupts masked completely OFF
261 *  *** In MacOSX interrupts do not seem to be off! ***
262 *
263 * INPUTS:
264 *    Stream pointer
265 *    gbuf_t pointer
266 *    Pointer to ADSP header, (part of the mblk pointer to by mp)
267 *    Length of header plus data
268 * OUTPUTS:
269 *    Returns 1 if packet was ignored
270 */
271int RXData(sp, mp, f, len)	/* (CCBPtr sp, ADSP_FRAMEPtr f, word len) */
272    CCBPtr sp;
273    register gbuf_t *mp;
274    ADSP_FRAMEPtr f;
275    int len;
276{
277    int offset;
278    int PktFirstByteSeq;
279    short cnt;
280    char eom;
281
282    len	-= ADSP_FRAME_LEN;
283
284    /* Does packet have eom bit set? */
285    eom = (f->descriptor & ADSP_EOM_BIT) ? 1 : 0;
286
287    dPrintf(D_M_ADSP, D_L_TRACE,
288	    ("RXData: sp=0x%x, mbuf=0x%x, f=0x%x, len=%d, eom=%d\n",
289	     (unsigned)sp, (unsigned)mp, (unsigned)f, len, eom));
290
291    KERNEL_DEBUG(DBG_ADSP_RCV, 1, sp, mp, len, eom);
292
293    trace_mbufs(D_M_ADSP, "  mp", mp);
294
295    PktFirstByteSeq = UAL_VALUE_NTOH(f->pktFirstByteSeq); /* Local copy */
296
297    if (GT(PktFirstByteSeq, sp->recvSeq)) /* missed a packet (out of order) */
298    {
299	if (sp->badSeqCnt++ > sp->badSeqCnt) /* Need to send rexmit advice */
300	    sp->sendCtl |= B_CTL_RETRANSMIT;
301	CheckRecvSeq(sp, f);	/* Will set send ACK flag if requested */
302	CheckReadQueue(sp);
303	gbuf_freem(mp);
304
305    	KERNEL_DEBUG(DBG_ADSP_RCV, 2, sp, 0, 0, 0);
306	trace_mbufs(D_M_ADSP, "  exRXD m", sp->rbuf_mb);
307	dPrintf(D_M_ADSP, D_L_TRACE, ("    End RXData - missed a packet\n"));
308
309	return 0;
310    }
311
312    if (LTE(PktFirstByteSeq + len + eom, sp->recvSeq)) { /* duplicate data? */
313	CheckRecvSeq(sp, f);	/* Will set send ACK flag if requested */
314	CheckReadQueue(sp);
315	gbuf_freem(mp);
316
317    	KERNEL_DEBUG(DBG_ADSP_RCV, 3, sp, 0, 0, 0);
318	trace_mbufs(D_M_ADSP, "  exRXD m", sp->rbuf_mb);
319	dPrintf(D_M_ADSP, D_L_TRACE, ("    End RXData - duplicate data\n"));
320
321	return 0;
322    }
323
324    sp->badSeqCnt = 0;		/* reset out of sequence pckt counter */
325
326    cnt = sp->recvSeq - PktFirstByteSeq; /* # bytes we've seen already */
327
328    offset = ((unsigned char *)&f->data[cnt]) - (unsigned char *)gbuf_rptr(mp);
329    gbuf_rinc(mp,offset);
330				/* point recv mblk to data (past headers) */
331
332    len -= cnt;			/* # of new data bytes */
333
334    cnt = len;			/* # bytes left to deal with */
335
336    if (!sp->rData)		/* Recv bfr is empty */
337    {
338	sp->rData = 1;		/* Not empty any more */
339
340	if ((sp->rpb)->ioc == (caddr_t)mp) {
341	   dPrintf(D_M_ADSP, D_L_TRACE,
342		   ("RXData: (pb->ioc == mp) no stored data\n"));
343    	   KERNEL_DEBUG(DBG_ADSP_RCV, 4, sp, sp->rpb, 0, 0);
344	}
345	if (eom)
346	    sp->rbuf_mb = mp;
347	else
348	    sp->crbuf_mb = mp;
349    }				/* Recv queue is empty */
350
351    /*
352     * Else, there's already stored data.
353     */
354    else {
355        gbuf_t *rmp;
356	/*
357	 * Is this a new "message?"
358	 */
359	if (eom) {
360	    if (sp->crbuf_mb) {
361		gbuf_linkb(sp->crbuf_mb, mp);
362		mp = sp->crbuf_mb;
363		sp->crbuf_mb = 0;
364	    }
365	    if ((rmp = sp->rbuf_mb)) {
366		/*
367		 * Add it to the end
368		 */
369		while(gbuf_next(rmp))
370		    rmp = gbuf_next(rmp);
371		gbuf_next(rmp) = mp;
372	    } else
373		sp->rbuf_mb = mp;
374	} else if (sp->crbuf_mb)
375	    gbuf_linkb(sp->crbuf_mb, mp);
376	else
377	    sp->crbuf_mb = mp;
378    }
379    sp->recvSeq += (cnt + eom);	/* We've got these bytes */
380
381    /* %%% We really should call check recv seq first, but let's
382     * continue to do it down here.  We really want to service the
383     * received packet first, and maybe reenable scc ints before
384     * doing anything that might take a long while
385     */
386
387    CheckRecvSeq(sp, f);	/* Will set send ACK flag if requested */
388    CheckReadQueue(sp);
389    KERNEL_DEBUG(DBG_ADSP_RCV, 5, sp, sp->rbuf_mb, 0, 0);
390    trace_mbufs(D_M_ADSP, "  eRXD m", sp->rbuf_mb);
391    return 0;
392} /* RXData */
393