]> git.saurik.com Git - apple/xnu.git/blame - bsd/netat/adsp_RxData.c
xnu-792.22.5.tar.gz
[apple/xnu.git] / bsd / netat / adsp_RxData.c
CommitLineData
1c79356b 1/*
5d5c5d0d
A
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
8f6c56a5 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
8f6c56a5
A
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
8ad349bb 24 * limitations under the License.
8f6c56a5
A
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
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(mp, len)
62 gbuf_t *mp;
63 int len;
64{
65 register gbuf_t *tmp;
66 register int cnt;
67 int freeit;
68
69 dPrintf(D_M_ADSP, D_L_TRACE,
70 ("releaseData: mbuf=0x%x, len=%d\n", (unsigned)mp, len));
71
72 KERNEL_DEBUG(DBG_ADSP_RCV, 0, mp, len, 0, 0);
73
74 do {
75 freeit = 1; /* assume we use the whole mblk */
76 if ((cnt = gbuf_len(mp)) > len) {
77 freeit = 0; /* using only part of the mblk */
78 cnt = len;
79 }
80 gbuf_rinc(mp,cnt);
81 len -= cnt;
82 tmp = mp;
83 mp = gbuf_cont(mp);
84 if (freeit) {
85 gbuf_freeb(tmp);
86 } else
87 return tmp; /* if we don't use the whole block */
88 /* pass back the partial gbuf_t pointer */
89 } while (len && mp);
90 return mp;
91}
92
93/*
94 * CheckRecvSeq
95 *
96 * We just got a non-attention packet. Check the pktNextRecvSeq field
97 * to see if it acknowledges any of our sent data.
98 *
99 * If any data was acked, check to see if we have anything to fill the
100 * newly opened up remote receive window. Otherwise, if the ACK request
101 * bit was set, we need to send an Ack Packet
102 *
103 * Always called as the result of receiving a packet. Interrupts
104 * are completely masked when this routine is called.
105 *
106 * INPUTS:
107 * sp stream
108 * f pointer to ASDP header
109 * OUTPUTS:
110 * none
111 */
112void CheckRecvSeq(sp, f) /* (CCBPtr sp, ADSP_FRAMEPtr f) */
113 register CCBPtr sp;
114 register ADSP_FRAMEPtr f;
115{
1c79356b
A
116 int pktNextRecvSeq;
117 int sendWdwSeq;
118 int eom;
119 int hlen;
120 register gbuf_t *mp;
121
1c79356b
A
122 if (f->descriptor & ADSP_ACK_REQ_BIT) { /* He wants an Ack */
123 sp->sendDataAck = 1;
124 sp->callSend = 1;
125 }
126
4452a7af 127 pktNextRecvSeq = UAL_VALUE_NTOH(f->pktNextRecvSeq); /* Local copy */
1c79356b
A
128
129 /*
130 * Make sure the sequence number corresponds to reality -- i.e. for
131 * unacknowledged data that we have sent
132 */
133
134 if (GT(pktNextRecvSeq, sp->maxSendSeq)) /* We've never sent this seq #! */
135 goto noack;
136
137 if (GTE(pktNextRecvSeq, sp->timerSeq) && sp->waitingAck) {
138 /* This acks our Ack Request */
139 sp->waitingAck = 0; /* Allow sending more */
140 sp->pktSendCnt = 0; /* Reset packet count */
141 /* Remove retry timer */
142 RemoveTimerElem(&adspGlobal.fastTimers, &sp->RetryTimer);
143
144 if (!sp->resentData) { /* Data sent without retries */
145 short diff; /* Signed!! */
146 /* All timings done in 6th second base */
147 /* The contortions here are to prevent C from promoting
148 * everything to longs and then using a library routine
149 * to do the division. As 16-bit words, a DIVU instruction
150 * is used.
151 */
152
153 diff = (((word)(SysTicks() - sp->sendStamp)) / (word)10) -
154 sp->roundTrip + 1;
155
156 sp->roundTrip += diff >> 3; /* Update average */
157
158 if (diff < 0) /* Take absolute value */
159 diff = -diff;
160 sp->deviation += (diff - sp->deviation) >> 2; /* Update deviation*/
161
162 sp->rtmtInterval = sp->roundTrip +
163 ((short)2 * (short)sp->deviation);
164
165 if (!sp->noXmitFlow &&
166 sp->pktSendMax < 50) /* Bump # of sequential */
167 sp->pktSendMax++; /* Packets we'll send */
168
169 sp->noXmitFlow = 0;
170 }
171 else
172 sp->resentData = 0;
173
174 } /* Acked our data */
175
176 if (LTE(pktNextRecvSeq,
177 sp->firstRtmtSeq)) /* Was duplicate ack, so ignore */
178 goto noack;
179
180 if (!sp->sData) /* If nothing in send queue, ignore */
181 goto noack;
182
183
184 do { /* This acks bytes in our buffer */
185 if (mp = sp->sbuf_mb) { /* Get ptr to oldest data header */
186 sp->sbuf_mb = gbuf_next(mp); /* unlink it from send queue */
187 eom = 1;
188 } else {
189 mp = sp->csbuf_mb;
190 sp->csbuf_mb = 0;
191 eom = 0;
192 }
193
194 if (mp == 0) { /* shouldn't happen! */
195 sp->sData = 0;
196 goto noack;
197 }
198 /*
199 * Does this ack the entire data block we're now pointing at?
200 */
201 if (LTE((sp->firstRtmtSeq + eom + (hlen = gbuf_msgsize(mp))),
202 pktNextRecvSeq)) {
203
204 gbuf_freem(mp);
205
206 /* Update seq # of oldest byte in bfr */
207 sp->firstRtmtSeq += eom + hlen;
208
209 if ((sp->sbuf_mb == 0) && (sp->csbuf_mb == 0)) {
210 /* If this was only block, then ... */
211 sp->sData = 0; /* ... no data in queue */
212 sp->writeFlush = 0;
213 if (sp->state == sClosing) /* this may allow us to close... */
214 CheckOkToClose(sp);
215 atalk_enablew(sp->gref);
216 break;
217 }
218 } /* whole data block acked */
219 else /* Only some of the data was acked */
220 {
221 short acked;
222
223 acked = (pktNextRecvSeq - sp->firstRtmtSeq);
224 mp = releaseData(mp, acked);
225 if (eom) {
226 if (mp) {
227 gbuf_next(mp) = sp->sbuf_mb;
228 sp->sbuf_mb = mp;
229 }
230 } else
231 sp->csbuf_mb = mp;
232
233 sp->firstRtmtSeq = pktNextRecvSeq; /* Update seq # oldest byte */
234 break;
235 }
236 } while (LT(sp->firstRtmtSeq, pktNextRecvSeq));
237
238 if (sp->sData) /* We've got stuff to send */
239 sp->callSend = 1;
240
241noack:
4452a7af 242 sendWdwSeq = UAS_VALUE_NTOH(f->pktRecvWdw) - 1 + pktNextRecvSeq;
1c79356b
A
243
244 if (GT(sendWdwSeq, sp->sendWdwSeq)) /* Don't make send window smaller */
245 {
246 sp->callSend = 1; /* His recv wdw opened, so see */
247 /* if we can send more data */
248 sp->sendWdwSeq = sendWdwSeq;
249 }
1c79356b
A
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{
4452a7af 275 int offset;
1c79356b
A
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
4452a7af 293 PktFirstByteSeq = UAL_VALUE_NTOH(f->pktFirstByteSeq); /* Local copy */
1c79356b 294
1c79356b
A
295 if (GT(PktFirstByteSeq, sp->recvSeq)) /* missed a packet (out of order) */
296 {
297 if (sp->badSeqCnt++ > sp->badSeqCnt) /* Need to send rexmit advice */
298 sp->sendCtl |= B_CTL_RETRANSMIT;
1c79356b
A
299 CheckRecvSeq(sp, f); /* Will set send ACK flag if requested */
300 CheckReadQueue(sp);
301 gbuf_freem(mp);
302
303 KERNEL_DEBUG(DBG_ADSP_RCV, 2, sp, 0, 0, 0);
304 trace_mbufs(D_M_ADSP, " exRXD m", sp->rbuf_mb);
305 dPrintf(D_M_ADSP, D_L_TRACE, (" End RXData - missed a packet\n"));
306
307 return 0;
308 }
309
310 if (LTE(PktFirstByteSeq + len + eom, sp->recvSeq)) { /* duplicate data? */
1c79356b
A
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
55e303ae 338 if ((sp->rpb)->ioc == (caddr_t)mp) {
1c79356b
A
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
1c79356b
A
385 CheckRecvSeq(sp, f); /* Will set send ACK flag if requested */
386 CheckReadQueue(sp);
387 KERNEL_DEBUG(DBG_ADSP_RCV, 5, sp, sp->rbuf_mb, 0, 0);
388 trace_mbufs(D_M_ADSP, " eRXD m", sp->rbuf_mb);
389 return 0;
390} /* RXData */