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