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