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 61gbuf_t *releaseData(gbuf_t *, int); 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{ 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 243noack: 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 */ 271int 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 */ 393