]>
git.saurik.com Git - apple/xnu.git/blob - bsd/netat/adsp_RxData.c
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
25 * From v01.28 Handle an incoming Data Packet 06/21/90 mbs
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.
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>
41 #include <sys/filedesc.h>
42 #include <sys/fcntl.h>
44 #include <sys/socket.h>
45 #include <sys/socketvar.h>
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>
55 gbuf_t
*releaseData(mp
, len
)
63 dPrintf(D_M_ADSP
, D_L_TRACE
,
64 ("releaseData: mbuf=0x%x, len=%d\n", (unsigned)mp
, len
));
66 KERNEL_DEBUG(DBG_ADSP_RCV
, 0, mp
, len
, 0, 0);
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 */
81 return tmp
; /* if we don't use the whole block */
82 /* pass back the partial gbuf_t pointer */
90 * We just got a non-attention packet. Check the pktNextRecvSeq field
91 * to see if it acknowledges any of our sent data.
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
97 * Always called as the result of receiving a packet. Interrupts
98 * are completely masked when this routine is called.
102 * f pointer to ASDP header
106 void CheckRecvSeq(sp
, f
) /* (CCBPtr sp, ADSP_FRAMEPtr f) */
108 register ADSP_FRAMEPtr f
;
117 ATDISABLE(s
, sp
->lock
);
118 if (f
->descriptor
& ADSP_ACK_REQ_BIT
) { /* He wants an Ack */
123 pktNextRecvSeq
= netdw(UAL_VALUE(f
->pktNextRecvSeq
)); /* Local copy */
126 * Make sure the sequence number corresponds to reality -- i.e. for
127 * unacknowledged data that we have sent
130 if (GT(pktNextRecvSeq
, sp
->maxSendSeq
)) /* We've never sent this seq #! */
133 if (GTE(pktNextRecvSeq
, sp
->timerSeq
) && sp
->waitingAck
) {
134 /* This acks our Ack Request */
135 sp
->waitingAck
= 0; /* Allow sending more */
136 sp
->pktSendCnt
= 0; /* Reset packet count */
137 /* Remove retry timer */
138 RemoveTimerElem(&adspGlobal
.fastTimers
, &sp
->RetryTimer
);
140 if (!sp
->resentData
) { /* Data sent without retries */
141 short diff
; /* Signed!! */
142 /* All timings done in 6th second base */
143 /* The contortions here are to prevent C from promoting
144 * everything to longs and then using a library routine
145 * to do the division. As 16-bit words, a DIVU instruction
149 diff
= (((word
)(SysTicks() - sp
->sendStamp
)) / (word
)10) -
152 sp
->roundTrip
+= diff
>> 3; /* Update average */
154 if (diff
< 0) /* Take absolute value */
156 sp
->deviation
+= (diff
- sp
->deviation
) >> 2; /* Update deviation*/
158 sp
->rtmtInterval
= sp
->roundTrip
+
159 ((short)2 * (short)sp
->deviation
);
161 if (!sp
->noXmitFlow
&&
162 sp
->pktSendMax
< 50) /* Bump # of sequential */
163 sp
->pktSendMax
++; /* Packets we'll send */
170 } /* Acked our data */
172 if (LTE(pktNextRecvSeq
,
173 sp
->firstRtmtSeq
)) /* Was duplicate ack, so ignore */
176 if (!sp
->sData
) /* If nothing in send queue, ignore */
180 do { /* This acks bytes in our buffer */
181 if (mp
= sp
->sbuf_mb
) { /* Get ptr to oldest data header */
182 sp
->sbuf_mb
= gbuf_next(mp
); /* unlink it from send queue */
190 if (mp
== 0) { /* shouldn't happen! */
195 * Does this ack the entire data block we're now pointing at?
197 if (LTE((sp
->firstRtmtSeq
+ eom
+ (hlen
= gbuf_msgsize(mp
))),
202 /* Update seq # of oldest byte in bfr */
203 sp
->firstRtmtSeq
+= eom
+ hlen
;
205 if ((sp
->sbuf_mb
== 0) && (sp
->csbuf_mb
== 0)) {
206 /* If this was only block, then ... */
207 sp
->sData
= 0; /* ... no data in queue */
209 if (sp
->state
== sClosing
) /* this may allow us to close... */
211 atalk_enablew(sp
->gref
);
214 } /* whole data block acked */
215 else /* Only some of the data was acked */
219 acked
= (pktNextRecvSeq
- sp
->firstRtmtSeq
);
220 mp
= releaseData(mp
, acked
);
223 gbuf_next(mp
) = sp
->sbuf_mb
;
229 sp
->firstRtmtSeq
= pktNextRecvSeq
; /* Update seq # oldest byte */
232 } while (LT(sp
->firstRtmtSeq
, pktNextRecvSeq
));
234 if (sp
->sData
) /* We've got stuff to send */
238 sendWdwSeq
= netw(UAS_VALUE(f
->pktRecvWdw
)) - 1 + pktNextRecvSeq
;
240 if (GT(sendWdwSeq
, sp
->sendWdwSeq
)) /* Don't make send window smaller */
242 sp
->callSend
= 1; /* His recv wdw opened, so see */
243 /* if we can send more data */
244 sp
->sendWdwSeq
= sendWdwSeq
;
246 ATENABLE(s
, sp
->lock
);
252 * We just got a Data Packet
253 * See if it came from anybody we know.
255 * Called from ADSP Packet with interrupts masked completely OFF
256 * *** In MacOSX interrupts do not seem to be off! ***
261 * Pointer to ADSP header, (part of the mblk pointer to by mp)
262 * Length of header plus data
264 * Returns 1 if packet was ignored
266 int RXData(sp
, mp
, f
, len
) /* (CCBPtr sp, ADSP_FRAMEPtr f, word len) */
277 len
-= ADSP_FRAME_LEN
;
279 /* Does packet have eom bit set? */
280 eom
= (f
->descriptor
& ADSP_EOM_BIT
) ? 1 : 0;
282 dPrintf(D_M_ADSP
, D_L_TRACE
,
283 ("RXData: sp=0x%x, mbuf=0x%x, f=0x%x, len=%d, eom=%d\n",
284 (unsigned)sp
, (unsigned)mp
, (unsigned)f
, len
, eom
));
286 KERNEL_DEBUG(DBG_ADSP_RCV
, 1, sp
, mp
, len
, eom
);
288 trace_mbufs(D_M_ADSP
, " mp", mp
);
290 PktFirstByteSeq
= netdw(UAL_VALUE(f
->pktFirstByteSeq
)); /* Local copy */
292 ATDISABLE(s
, sp
->lock
);
293 if (GT(PktFirstByteSeq
, sp
->recvSeq
)) /* missed a packet (out of order) */
295 if (sp
->badSeqCnt
++ > sp
->badSeqCnt
) /* Need to send rexmit advice */
296 sp
->sendCtl
|= B_CTL_RETRANSMIT
;
297 ATENABLE(s
, sp
->lock
);
298 CheckRecvSeq(sp
, f
); /* Will set send ACK flag if requested */
302 KERNEL_DEBUG(DBG_ADSP_RCV
, 2, sp
, 0, 0, 0);
303 trace_mbufs(D_M_ADSP
, " exRXD m", sp
->rbuf_mb
);
304 dPrintf(D_M_ADSP
, D_L_TRACE
, (" End RXData - missed a packet\n"));
309 if (LTE(PktFirstByteSeq
+ len
+ eom
, sp
->recvSeq
)) { /* duplicate data? */
310 ATENABLE(s
, sp
->lock
);
311 CheckRecvSeq(sp
, f
); /* Will set send ACK flag if requested */
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"));
322 sp
->badSeqCnt
= 0; /* reset out of sequence pckt counter */
324 cnt
= sp
->recvSeq
- PktFirstByteSeq
; /* # bytes we've seen already */
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) */
330 len
-= cnt
; /* # of new data bytes */
332 cnt
= len
; /* # bytes left to deal with */
334 if (!sp
->rData
) /* Recv bfr is empty */
336 sp
->rData
= 1; /* Not empty any more */
338 if ((sp
->rpb
)->ioc
== mp
) {
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);
347 } /* Recv queue is empty */
350 * Else, there's already stored data.
355 * Is this a new "message?"
359 gbuf_linkb(sp
->crbuf_mb
, mp
);
363 if (rmp
= sp
->rbuf_mb
) {
367 while(gbuf_next(rmp
))
368 rmp
= gbuf_next(rmp
);
372 } else if (sp
->crbuf_mb
)
373 gbuf_linkb(sp
->crbuf_mb
, mp
);
377 sp
->recvSeq
+= (cnt
+ eom
); /* We've got these bytes */
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
385 ATENABLE(s
, sp
->lock
);
386 CheckRecvSeq(sp
, f
); /* Will set send ACK flag if requested */
388 KERNEL_DEBUG(DBG_ADSP_RCV
, 5, sp
, sp
->rbuf_mb
, 0, 0);
389 trace_mbufs(D_M_ADSP
, " eRXD m", sp
->rbuf_mb
);