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