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