1/* 2 * Copyright (c) 2000-2007 Apple 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 * 30 * dspRead.c 31 * 32 * From v01.17 08/22/90 mbs 33 * Modified for MP, 1996 by Tuyen Nguyen 34 * Modified, April 9, 1997 by Tuyen Nguyen for MacOSX. 35 */ 36 37#include <sys/errno.h> 38#include <sys/types.h> 39#include <sys/param.h> 40#include <machine/spl.h> 41#include <sys/systm.h> 42#include <sys/kernel.h> 43#include <sys/proc.h> 44#include <sys/filedesc.h> 45#include <sys/fcntl.h> 46#include <sys/mbuf.h> 47#include <sys/socket.h> 48#include <sys/socketvar.h> 49 50#include <netat/sysglue.h> 51#include <netat/appletalk.h> 52#include <netat/at_pcb.h> 53#include <netat/debug.h> 54#include <netat/adsp.h> 55#include <netat/adsp_internal.h> 56 57/* 58 * CheckReadQueue 59 * 60 * Checks to see if there is any data in the receive queue. If there 61 * is data, a pb and the data are queued to the user. 62 * 63 * 64 */ 65extern int adsp_check; 66 67int CheckReadQueue(sp) /* (CCBPtr sp) */ 68 register CCBPtr sp; 69{ 70 register struct adspcmd *pb; 71 unsigned short cnt; 72 char eom = 0; 73 register gbuf_t *mp; 74 register gbuf_t *tmp; 75 gref_t *gref; 76 77 dPrintf(D_M_ADSP, D_L_TRACE, ("CheckReadQueue: sp=0x%x\n", (unsigned)sp)); 78 KERNEL_DEBUG(DBG_ADSP_READ, 0, sp, sp->rbuf_mb, sp->rpb, sp->delay); 79 trace_mbufs(D_M_ADSP_LOW, " bCQR m", sp->rbuf_mb); 80 81 while (sp->rData && (pb = sp->rpb)) { /* have data */ 82 dPrintf(D_M_ADSP, D_L_TRACE, 83 (" pb=0x%p, gref=0x%p, ioc=0x%p, reqCount=%d (have data)\n", 84 pb, pb->gref, pb->ioc, pb->u.ioParams.reqCount)); 85 KERNEL_DEBUG(DBG_ADSP_READ, 1, pb, pb->gref, pb->ioc, pb->u.ioParams.reqCount); 86 if (pb->u.ioParams.reqCount == 0) { 87 pb->ioResult = 0; 88 sp->rpb = pb->qLink; 89 if (pb->ioc) { 90 KERNEL_DEBUG(DBG_ADSP_READ, 2, pb, pb->gref, pb->ioc, 0); 91 adspioc_ack(0, (gbuf_t *)pb->ioc, pb->gref); 92 } else { 93 KERNEL_DEBUG(DBG_ADSP_READ, 3, pb, pb->gref, 0, 0); 94 completepb(sp, pb); 95 } 96 continue; 97 } 98 99 /* take the first packet off of sp->rbuf_mb or sp->crbuf_mb */ 100 if ((mp = sp->rbuf_mb)) { /* Get header for oldest data */ 101 KERNEL_DEBUG(DBG_ADSP_READ, 4, pb, mp, gbuf_msgsize(mp), gbuf_next(mp)); 102 sp->rbuf_mb = gbuf_next(mp); 103 gbuf_next(mp) = 0; 104 eom = 1; 105 } else if ((mp = sp->crbuf_mb)) { 106 KERNEL_DEBUG(DBG_ADSP_READ, 5, pb, mp, gbuf_msgsize(mp), gbuf_next(mp)); 107 sp->crbuf_mb = 0; 108 eom = 0; 109 } 110 111 /* Get the first (reqCount-actCount) bytes and tack them onto 112 the end of pb->mp. If eom is set, put the remainder of the 113 data onto the front of sp->rbuf_mb, otherwise sp->crbuf_mb. */ 114 cnt = gbuf_msgsize(mp); /* # of data bytes in it. */ 115 if (cnt > (unsigned short)(pb->u.ioParams.reqCount - pb->u.ioParams.actCount)) { 116 cnt = pb->u.ioParams.reqCount - pb->u.ioParams.actCount; 117 /* m_split returns the tail */ 118 if (!(tmp = (gbuf_t *)m_split(mp, cnt, M_DONTWAIT))) { 119 cnt = 0; 120 tmp = mp; 121 } 122 if (eom) { 123 gbuf_next(tmp) = sp->rbuf_mb; 124 sp->rbuf_mb = tmp; 125 eom = 0; 126 } else 127 sp->crbuf_mb = tmp; 128 } 129 if (cnt) { 130 pb->u.ioParams.actCount += cnt; 131 gbuf_linkb(pb->mp, mp); 132 } 133 134 pb->u.ioParams.eom = eom; 135 /* 136 * Now clean up receive buffer to remove all of the data 137 * we just copied 138 */ 139 if ((sp->rbuf_mb == 0) && 140 (sp->crbuf_mb == 0)) /* no more data blocks */ 141 sp->rData = 0; 142 /* 143 * If we've filled the parameter block, unlink it from read 144 * queue and complete it. We also need to do this if the connection 145 * is closed && there is no more stuff to read. 146 */ 147 if (eom || (pb->u.ioParams.actCount >= pb->u.ioParams.reqCount) || 148 ((sp->state == sClosed) && (!sp->rData)) ) { 149 /* end of message, message is full, connection 150 * is closed and all data has been delivered, 151 * or we are not to "delay" data delivery. 152 */ 153 pb->ioResult = 0; 154 sp->rpb = pb->qLink; /* dequeue request */ 155 if (pb->ioc) { /* data to be delivered at the time of the */ 156 mp = gbuf_cont(pb->mp); /* ioctl call */ 157 gbuf_cont(pb->mp) = 0; 158 gref = (gref_t *)pb->gref; 159 adspioc_ack(0, (gbuf_t *)pb->ioc, pb->gref); 160 dPrintf(D_M_ADSP, D_L_TRACE, (" (pb->ioc) mp=%p\n", mp)); 161 KERNEL_DEBUG(DBG_ADSP_READ, 0x0A, pb, mp, 162 gbuf_next(mp), gbuf_cont(mp)); 163 SndMsgUp(gref, mp); 164 dPrintf(D_M_ADSP, D_L_TRACE, 165 (" (data) size req=%d\n", pb->u.ioParams.actCount)); 166 KERNEL_DEBUG(DBG_ADSP_READ, 0x0B, pb, pb->ioc, 167 pb->u.ioParams.reqCount, pb->u.ioParams.actCount); 168 } else { /* complete an queued async request */ 169 KERNEL_DEBUG(DBG_ADSP_READ, 0x0C, pb, sp, 170 pb->u.ioParams.actCount, sp->delay); 171 completepb(sp, pb); 172 } 173 } 174 } /* while */ 175 176 if ((pb = sp->rpb)) { /* if there is an outstanding request */ 177 dPrintf(D_M_ADSP, D_L_TRACE, 178 (" pb=0x%p, ioc=0x%p, reqCount=%d (no more data)\n", 179 pb, pb->ioc, pb->u.ioParams.reqCount)); 180 KERNEL_DEBUG(DBG_ADSP_READ, 0x0D, pb, pb->ioc, 181 pb->u.ioParams.reqCount, pb->u.ioParams.actCount); 182 183 if (sp->state == sClosed) { 184 while (pb) { 185 KERNEL_DEBUG(DBG_ADSP_READ, 0x0E, pb, sp, pb->ioc, 0); 186 pb->ioResult = 0; 187 pb->u.ioParams.actCount = 0; 188 pb->u.ioParams.eom = 0; 189 sp->rpb = pb->qLink; 190 if (pb->ioc) { 191 adspioc_ack(0, (gbuf_t *)pb->ioc, pb->gref); 192 } else { 193 completepb(sp, pb); 194 } 195 pb = sp->rpb; 196 } 197 } else if (pb->ioc) { /* if request not complete and this 198 * is an active ioctl, release user */ 199 sp->rpb = pb->qLink; 200 pb->ioResult = 1; 201 tmp = gbuf_cont(pb->mp); /* detatch perhaps delayed data */ 202 gbuf_cont(pb->mp) = 0; 203 if ((mp = gbuf_copym(pb->mp))) { /* otherwise, duplicate user request */ 204 KERNEL_DEBUG(DBG_ADSP_READ, 0x0F, pb, sp, pb->mp, 0); 205 adspioc_ack(0, (gbuf_t *)pb->ioc, pb->gref); /* release user */ 206 pb = (struct adspcmd *)gbuf_rptr(mp); /* get new parameter block */ 207 pb->ioc = 0; 208 pb->mp = mp; 209 gbuf_cont(pb->mp) = tmp; /* reattach data */ 210 pb->qLink = sp->rpb; /* requeue the duplicate at the head */ 211 sp->rpb = pb; 212 } else { /* there is no data left, but no space 213 * to duplicate the parameter block, so 214 * put what must be a non EOM message 215 * back on the current receive queue, and 216 * error out the user 217 */ 218 KERNEL_DEBUG(DBG_ADSP_READ, 0x10, pb, sp, pb->mp, 0); 219 if (tmp) { 220 sp->crbuf_mb = tmp; 221 sp->rData = 1; 222 } 223 pb->ioResult = errDSPQueueSize; 224 adspioc_ack(ENOBUFS, (gbuf_t *)pb->ioc, pb->gref); 225 } 226 } 227 } 228 /* 229 * The receive window has opened. If was previously closed, then we 230 * need to notify the other guy that we now have room to receive more 231 * data. But, in order to cut down on lots of small data packets, 232 * we'll wait until the recieve buffer is /14 empy before telling 233 * him that there's room in our receive buffer. 234 */ 235 if (sp->rbufFull && (CalcRecvWdw(sp) > (sp->rbuflen >> 2))) { 236 sp->rbufFull = 0; 237 sp->sendDataAck = 1; 238 sp->callSend = 1; 239 } 240 241 KERNEL_DEBUG(DBG_ADSP_READ, 0x11, sp, 0, 0, 0); 242 trace_mbufs(D_M_ADSP_LOW, " eCQR m", sp->rbuf_mb); 243 return 0; 244} 245 246/* 247 * CheckAttn 248 * 249 * Checks to see if there is any attention data and passes the data back 250 * in the passed in pb. 251 * 252 * INPUTS: 253 * sp 254 * pb 255 * 256 * OUTPUTS: 257 * 258 */ 259int CheckAttn(CCBPtr, struct adspcmd *); 260 261int CheckAttn(sp, pb) /* (CCBPtr sp) */ 262 register CCBPtr sp; 263 register struct adspcmd *pb; 264{ 265 gbuf_t *mp; 266 gref_t *gref = 0; 267 268 dPrintf(D_M_ADSP, D_L_TRACE, 269 ("CheckAttn: sp=0x%x, pb=0x%x\n", (unsigned)sp, (unsigned)pb)); 270 271 if ((mp = sp->attn_mb)) { 272 273 /* 274 * Deliver the attention data to the user. 275 */ 276 gref = (gref_t *)pb->gref; 277 pb->u.attnParams.attnSize = sp->attnSize; 278 pb->u.attnParams.attnCode = sp->attnCode; 279 if (!sp->attnSize) { 280 gbuf_freem(mp); 281 mp = 0; 282 } 283 sp->userFlags &= ~eAttention; 284 /* 285 * Now clean up receive buffer to remove all of the data 286 * we just copied 287 */ 288 sp->attn_mb = 0; 289 pb->ioResult = 0; 290 } else { 291 /* 292 * No data... 293 */ 294 pb->u.attnParams.attnSize = 0; 295 pb->u.attnParams.attnCode = 0; 296 pb->ioResult = 1; /* not done */ 297 } 298 adspioc_ack(0, (gbuf_t *)pb->ioc, pb->gref); 299 if (mp) { 300 SndMsgUp(gref, mp); 301 } 302 return 0; 303} 304 305/* 306 * adspRead 307 * 308 * INPUTS: 309 * --> sp stream pointer 310 * --> pb user request parameter block 311 * 312 * OUTPUTS: 313 * <-- actCount actual number of bytes read 314 * <-- eom one if end-of-message, zero otherwise 315 * 316 * ERRORS: 317 * errRefNum bad connection refnum 318 * errState 319 * errFwdReset read terminated by forward reset 320 * errAborted request aborted by Remove or Close call 321 */ 322int adspRead(sp, pb) /* (DSPPBPtr pb) */ 323 register CCBPtr sp; 324 register struct adspcmd *pb; 325{ 326 register gbuf_t *mp; 327 328 dPrintf(D_M_ADSP, D_L_TRACE, 329 ("adspRead: sp=0x%x, pb=0x%x\n", (unsigned)sp, (unsigned)pb)); 330 331 KERNEL_DEBUG(DBG_ADSP_READ, 0x12, sp, pb, sp->state, sp->rData); 332 333 if (sp == 0) { 334 pb->ioResult = errRefNum; 335 return EINVAL; 336 } 337 338 /* 339 * It's OK to read on a closed, or closing session 340 */ 341 if (sp->state != sOpen && sp->state != sClosing && sp->state != sClosed) { 342 pb->ioResult = errState; 343 return EINVAL; 344 } 345 if (sp->rData && (sp->rpb == 0)) { /* if data, and no queue of pbs */ 346 qAddToEnd((struct qlink **)&sp->rpb, (struct qlink *)pb); /* deliver data to user directly */ 347 CheckReadQueue(sp); 348 } else if ((pb->u.ioParams.reqCount == 0) && (sp->rpb == 0)) { 349 /* empty read */ 350 pb->ioResult = 0; 351 adspioc_ack(0, (gbuf_t *)pb->ioc, pb->gref); 352 return 0; 353 } else { 354 pb->ioResult = 1; 355 if ((mp = gbuf_copym(pb->mp))) { /* otherwise, duplicate user request */ 356 adspioc_ack(0, (gbuf_t *)pb->ioc, pb->gref); /* release user */ 357 pb = (struct adspcmd *)gbuf_rptr(mp); /* get new parameter block */ 358 pb->ioc = 0; 359 pb->mp = mp; 360 qAddToEnd((struct qlink **)&sp->rpb, (struct qlink *)pb); /* and queue it for later */ 361 } else { 362 pb->ioResult = errDSPQueueSize; 363 return ENOBUFS; 364 } 365 } 366 367 if (sp->callSend) { 368 CheckSend(sp); /* If recv window opened, we might */ 369 /* send an unsolicited ACK. */ 370 } 371 return 0; 372} 373 374/* 375 * dspReadAttention 376 * 377 * INPUTS: 378 * --> sp stream pointer 379 * --> pb user request parameter block 380 * 381 * OUTPUTS: 382 * <-- NONE 383 * 384 * ERRORS: 385 * errRefNum bad connection refnum 386 * errState connection is not in the right state 387 */ 388int adspReadAttention(sp, pb) /* (DSPPBPtr pb) */ 389 register CCBPtr sp; 390 register struct adspcmd *pb; 391{ 392 dPrintf(D_M_ADSP, D_L_TRACE, 393 ("adspReadAttention: sp=0x%x, pb=0x%x\n", (unsigned)sp, (unsigned)pb)); 394 if (sp == 0) { 395 pb->ioResult = errRefNum; 396 return EINVAL; 397 } 398 399 /* 400 * It's OK to read on a closed, or closing session 401 */ 402 if (sp->state != sOpen && sp->state != sClosing && sp->state != sClosed) { 403 pb->ioResult = errState; 404 return EINVAL; 405 } 406 407 CheckAttn(sp, pb); /* Anything in the attention queue */ 408 CheckReadQueue(sp); /* check to see if receive window has opened */ 409 if (sp->callSend) { 410 CheckSend(sp); /* If recv window opened, we might */ 411 /* send an unsolicited ACK. */ 412 } 413 return 0; 414} /* adspReadAttention */ 415