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