Annotation of XNU/bsd/netat/adsp_Close.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             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.
        !            11:  * 
        !            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
        !            18:  * under the License.
        !            19:  * 
        !            20:  * @APPLE_LICENSE_HEADER_END@
        !            21:  */
        !            22: /*
        !            23:  *     Copyright (c) 1990, 1995-1998 Apple Computer, Inc.
        !            24:  *     All Rights Reserved.
        !            25:  */
        !            26: 
        !            27: /* dspClose.c 
        !            28:  * From Mike Shoemaker v01.16 06/29/90 mbs
        !            29:  */
        !            30: /*
        !            31:  * Change log:
        !            32:  *   06/29/95 - Modified to handle flow control for writing (Tuyen Nguyen)
        !            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: #include <sys/time.h>
        !            50: 
        !            51: #include <netat/sysglue.h>
        !            52: #include <netat/appletalk.h>
        !            53: #include <netat/ddp.h>
        !            54: #include <netat/at_pcb.h>
        !            55: #include <netat/debug.h>
        !            56: #include <netat/adsp.h>
        !            57: #include <netat/adsp_internal.h>
        !            58: 
        !            59: extern atlock_t adspall_lock;
        !            60: 
        !            61: static void qRemove(CCBPtr, CCBPtr);
        !            62: 
        !            63: 
        !            64: /*
        !            65:  * CheckOkToClose
        !            66:  * 
        !            67:  * Check to see if it is OK to close this connection cleanly.
        !            68:  *
        !            69:  * INPUTS:
        !            70:  *             Stream pointer
        !            71:  * OUTPUTS:
        !            72:  *             True if no outstanding transactions and we can close cleanly
        !            73:  */
        !            74: int CheckOkToClose(sp)         /* (CCBPtr sp) */
        !            75:     CCBPtr sp;
        !            76: {
        !            77:     
        !            78:     if (sp->sData)             /* Outstanding data ? */
        !            79:        return 0;
        !            80: 
        !            81:     if (sp->sapb)              /* Outstanding send attention ? */
        !            82:        return 0;
        !            83: 
        !            84:     if (sp->frpb)              /* Outstanding forward reset ? */
        !            85:        return 0;
        !            86:                
        !            87:     if (sp->sendAttnAck)
        !            88:        return 0;
        !            89:                
        !            90:     if (sp->sendDataAck)
        !            91:        return 0;
        !            92:        
        !            93:     /*
        !            94:      * Must be OK to close
        !            95:      */
        !            96:     sp->sendCtl        |= B_CTL_CLOSE; /* So, need to send close advice */
        !            97:     sp->callSend = 1;
        !            98: 
        !            99:     return 1;                  /* It's OK to close */
        !           100: }
        !           101: 
        !           102: 
        !           103: /*
        !           104:  * CompleteQueue
        !           105:  * 
        !           106:  * Given the address of the head of a queue of DSP parameter blocks, zero 
        !           107:  * the queue, and complete each item on the queue with the given result 
        !           108:  * code.
        !           109:  *
        !           110:  * INPUTS:
        !           111:  *             qhead           Address of ptr to first queue element
        !           112:  *             code            The result code
        !           113:  * OUTPUTS:
        !           114:  *             none
        !           115:  */
        !           116: int  CompleteQueue(qhead, code)        /* (DSPPBPtr FPTR qhead, OSErr code) */
        !           117:     struct adspcmd **qhead;
        !           118:     int code;
        !           119: {
        !           120:     register struct adspcmd *p;
        !           121:     register struct adspcmd *n;
        !           122:     register gref_t *gref;
        !           123:     register int    total = 0;
        !           124:     CCBPtr sp = 0;
        !           125:     int s;
        !           126: 
        !           127:     n = *qhead;                        /* Get first item */
        !           128:     *qhead = 0;                        /* Zero out the queue */
        !           129:     if (n) {
        !           130:        gref = n->gref;
        !           131:        if (gref->info) {
        !           132:            sp = (CCBPtr)gbuf_rptr(((gbuf_t *)gref->info));
        !           133:            atalk_flush(sp->gref);
        !           134:            ATDISABLE(s, sp->lock);
        !           135:            }
        !           136:     }
        !           137: 
        !           138:     while (p = n) {            /* while items left */
        !           139:        n = (struct adspcmd *)(p->qLink); /* Save next guy */
        !           140:        p->ioResult = code;
        !           141:        if (sp) {
        !           142:            completepb(sp, p);  /* complete the copy of the request */
        !           143:            total++;
        !           144:        } else
        !           145:            gbuf_freem(p->mp);
        !           146:     }                          /* while */
        !           147:     if (sp)
        !           148:        ATENABLE(s, sp->lock);
        !           149:     return(total);
        !           150: }
        !           151: 
        !           152: /*
        !           153:  * RemoveCCB
        !           154:  * 
        !           155:  * Called from do close to free up the user's CCB.  So, we remove the 
        !           156:  * CCB from the list of CCB's.
        !           157:  *
        !           158:  * INPUTS:
        !           159:  *             sp      pointer to ccb
        !           160:  *             pb      a remove param block to complete when done
        !           161:  * OUTPUTS:
        !           162:  *             none
        !           163:  */
        !           164: 
        !           165: void RemoveCCB(sp, pb)         /* (CCBPtr sp, DSPPBPtr pb) */
        !           166:     CCBPtr sp;
        !           167:     struct adspcmd *pb;
        !           168: {
        !           169:        gref_t *gref;
        !           170:        
        !           171:        if (sp->gref == 0)
        !           172:                return;
        !           173:     /*
        !           174:      * Unlink CCB from list
        !           175:      */
        !           176:     qRemove(AT_ADSP_STREAMS, sp); /* remove sp from active streams queue */
        !           177: 
        !           178:     if (pb) {
        !           179:        pb->ioResult = 0;
        !           180:        if (pb->ioc)            /* is this a current or queued request */
        !           181:            adspioc_ack(0, pb->ioc, pb->gref);  /* current */
        !           182:        else {
        !           183:            completepb(sp, pb); /* queued */
        !           184:        }
        !           185:        
        !           186:        if (sp->opb && (pb != sp->opb)) { /* if the pb requested is not the */
        !           187:            pb = sp->opb;               /* waiting open pb, complete it too */
        !           188:            sp->opb = 0;
        !           189:            pb->ioResult = 0;
        !           190:            completepb(sp, pb);
        !           191:        } else {
        !           192:            sp->opb = 0;
        !           193:         }
        !           194:     }
        !           195:     gref = sp->gref;
        !           196:     sp->gref = 0;
        !           197:     if (gref->info == (char *)sp->sp_mp) { /* queue head is still valid */
        !           198:            unsigned char skt;
        !           199: 
        !           200:            if ((skt = sp->localSocket) != 0) {
        !           201:              if (adspDeassignSocket(sp) == 0)
        !           202:                  ddp_notify_nbp(skt, sp->pid, DDP_ADSP);
        !           203:            }
        !           204: 
        !           205:          if (gref->info) {
        !           206:            gbuf_freem((gbuf_t *)gref->info);   /* free the CCB */
        !           207:            gref->info = 0;
        !           208:          }
        !           209:     } else
        !           210:        gbuf_freem(sp->sp_mp);  /* our head is already gone, be sure
        !           211:                                 * to release our resources too */
        !           212: }
        !           213: 
        !           214: int  AbortIO(sp, err)
        !           215:     CCBPtr sp;
        !           216:     short err;
        !           217: {
        !           218:     register int    total;
        !           219: 
        !           220:        if (sp->gref == 0)
        !           221:                return 0;
        !           222:     /*
        !           223:      * Complete all outstanding transactions.  
        !           224:      */
        !           225:     total += CompleteQueue(&sp->sapb, err); /* Abort outstanding send attentions */
        !           226:     CompleteQueue(&sp->frpb, err); /* Abort outstanding forward resets */
        !           227: 
        !           228:     if (sp->sbuf_mb) { /* clear the send queue */
        !           229:        gbuf_freel(sp->sbuf_mb);
        !           230:        sp->sbuf_mb = 0;
        !           231:     }
        !           232: 
        !           233:     if (sp->csbuf_mb) {
        !           234:        gbuf_freem(sp->csbuf_mb);
        !           235:        sp->csbuf_mb = 0;
        !           236:     }
        !           237:     sp->sData = 0;
        !           238:     
        !           239:     return(total);
        !           240: }
        !           241: 
        !           242: /*
        !           243:  * DoClose
        !           244:  * 
        !           245:  * Called from several places (probe timeout, recv close advice, 
        !           246:  * dspRemove, etc.) to change state of connection to closed and 
        !           247:  * complete all outstanding I/O.
        !           248:  *
        !           249:  * Will also remove the CCB if there is a dsp remove pending.
        !           250:  *
        !           251:  * INPUTS:
        !           252:  *             sp              An ADSP stream
        !           253:  * OUTPUTS:
        !           254:  *             none
        !           255:  */
        !           256: void DoClose(sp, err, force_abort)     /* (CCBPtr sp, OSErr err) */
        !           257:     register CCBPtr sp;
        !           258:     int err;
        !           259: {
        !           260:     register struct adspcmd *pb, *np;
        !           261:     register gbuf_t *mp;
        !           262:     int      aborted_count;
        !           263:        
        !           264:     dPrintf(D_M_ADSP, D_L_TRACE, ("DoClose: pid=%d,e=%d,a=%d,s=%d,r=%d\n",
        !           265:                sp->pid, err, force_abort, sp->localSocket, sp->removing));
        !           266:     sp->userFlags |= eClosed; /* Set flag */
        !           267:     sp->state = sClosed;
        !           268:     sp->openState = O_STATE_NOTHING;
        !           269: 
        !           270:     /*
        !           271:      * Clean up any timer elements
        !           272:      */
        !           273:     RemoveTimerElem(&adspGlobal.slowTimers, &sp->ProbeTimer);
        !           274:     RemoveTimerElem(&adspGlobal.fastTimers, &sp->FlushTimer);
        !           275:     RemoveTimerElem(&adspGlobal.fastTimers, &sp->RetryTimer);
        !           276:     RemoveTimerElem(&adspGlobal.fastTimers, &sp->AttnTimer);
        !           277:     RemoveTimerElem(&adspGlobal.fastTimers, &sp->ResetTimer);
        !           278: 
        !           279:     aborted_count = AbortIO(sp, err);
        !           280:     np = sp->opb;              /* Get list of close/removes to complete */
        !           281:     sp->opb = 0;               /* set this list null */
        !           282:        
        !           283:     while (pb = np) {          /* Handle all of the close/remove param blks */
        !           284:        np = (struct adspcmd *)pb->qLink; /* Get next guy (if any) */
        !           285:        pb->qLink = 0;
        !           286:        pb->ioResult = err;
        !           287:        completepb(sp, pb);
        !           288:     }
        !           289:     if (sp->removing && (force_abort >= 0)) {        /* Abort outstanding receives */
        !           290:        aborted_count += CompleteQueue(&sp->rpb, err);
        !           291: 
        !           292:        if (sp->deferred_mb) {
        !           293:                gbuf_freel(sp->deferred_mb);
        !           294:                sp->deferred_mb = 0;
        !           295:        }
        !           296:        if (sp->attn_mb) {
        !           297:                gbuf_freem(sp->attn_mb);
        !           298:                sp->attn_mb = 0;
        !           299:        }
        !           300:        if (sp->rbuf_mb) { /* clear the rcv queue */
        !           301:                gbuf_freem(sp->rbuf_mb);
        !           302:                sp->rbuf_mb = 0;
        !           303:        }
        !           304:        if (sp->crbuf_mb) {
        !           305:                gbuf_freem(sp->crbuf_mb);
        !           306:                sp->crbuf_mb = 0;
        !           307:        }
        !           308:        sp->rData = 0;
        !           309: 
        !           310:        /* if our connection has been timed out */
        !           311:        /* and the user wasn't notified of the TearDown */
        !           312:        /* because of pending requests on this socket */
        !           313:        /* then fake a read completion to force the notification */
        !           314: 
        !           315:        if (force_abort && aborted_count == 0) {
        !           316:            if (mp = gbuf_alloc(sizeof(struct adspcmd), PRI_HI)) {
        !           317:                pb = (struct adspcmd *)gbuf_rptr(mp);
        !           318:                gbuf_wset(mp,sizeof(struct adspcmd));
        !           319: 
        !           320:                bzero((caddr_t) pb, sizeof(struct adspcmd));
        !           321:                pb->mp = mp;
        !           322:                pb->csCode = dspRead;
        !           323:                pb->ioResult = errAborted;
        !           324:                completepb(sp, pb);             /* send fake read completion */
        !           325:            }
        !           326:        }
        !           327:        sp->removing = 0;
        !           328:        RemoveCCB(sp, 0); /* Will call completion routine */
        !           329:     }
        !           330:     sp->userFlags &= ~eClosed;
        !           331: }
        !           332: 
        !           333: 
        !           334: /*
        !           335:  * dspClose
        !           336:  * 
        !           337:  * Also called for dspRemove and dspCLRemove.
        !           338:  * Must handle case of multiple close calls being issued (without 
        !           339:  * abort bit set) Can only allow one pending remove though.
        !           340:  *
        !           341:  * INPUTS:
        !           342:  *     -->     ccbRefNum               refnum of connection end
        !           343:  *     -->     abort                   abort the connection
        !           344:  *
        !           345:  * OUTPUTS:
        !           346:  *     none
        !           347:  *
        !           348:  * ERRORS:
        !           349:  *             errRefNum               Bad connection Refnum
        !           350:  */
        !           351: int adspClose(sp, pb)          /* (DSPPBPtr pb) */
        !           352:     register CCBPtr sp;
        !           353:     register struct adspcmd *pb;
        !           354: {
        !           355:     int        s;
        !           356:     register gbuf_t *mp;
        !           357:        
        !           358:     /* Must execute nearly all of this with ints off because user could 
        !           359:      * be issuing a second dspRemove while the first is pending.  Until 
        !           360:      * we can detect this, we must not allow interrupts.
        !           361:      * Also, we can't handle the case where a close was issued earlier, 
        !           362:      * and now this is the remove.  If the write completion for the 
        !           363:      * close advice packet occurs in the middle of this, we might
        !           364:      * foul up.
        !           365:      */
        !           366: 
        !           367:     if (sp == 0) {
        !           368:        pb->ioResult = errRefNum;
        !           369:        return EINVAL;
        !           370:     }
        !           371: 
        !           372:     /*
        !           373:      * Handle dspCLRemove
        !           374:      */
        !           375:     if (pb->csCode == (short)dspCLRemove) { /* Remove connection listener */
        !           376:        if (sp->state != (short)sListening) { /* But it's not a listener! */
        !           377:            pb->ioResult = errState;
        !           378:            return EINVAL;
        !           379:        }
        !           380:        CompleteQueue(&sp->opb, errAborted); /* Complete all dspListens */
        !           381:        RemoveCCB(sp, pb);      /* Will call completion routine */
        !           382:        return 0;
        !           383:     }
        !           384: 
        !           385: 
        !           386:     /*
        !           387:      * Either dspClose or dspRemove
        !           388:      */
        !           389: 
        !           390:     if (sp->removing) {                /* Don't allow dspRemove or dspClose */
        !           391:                                /* after one dspRemove has been issued. */
        !           392:        pb->ioResult = errState;
        !           393:        return EINVAL;
        !           394:     }
        !           395: 
        !           396: 
        !           397:     /*
        !           398:      * The previous Macintosh ADSP allowed you to call close on a 
        !           399:      * connection that was in the process of opening or passively 
        !           400:      * waiting for an open request. It is also legal to close a 
        !           401:      * connection that is already closed.  No error will be generated.
        !           402:      *
        !           403:      * It is also legal to issue a second close call while the first 
        !           404:      * is still pending.
        !           405:      */
        !           406:     if (pb->csCode == (short)dspClose) {
        !           407:        ATDISABLE(s, sp->lock);
        !           408:        if ((sp->state == (short)sPassive) || (sp->state == (short)sOpening)) {
        !           409:            sp->state = sClosed;
        !           410:            ATENABLE(s, sp->lock);
        !           411:            DoClose(sp, errAborted, 0);
        !           412:            pb->ioResult = 0;
        !           413:            adspioc_ack(0, pb->ioc, pb->gref);
        !           414:            return 0;
        !           415:        }
        !           416:                
        !           417:        if (sp->state == (word)sClosed) { /* Ok to close a closed connection */
        !           418:            ATENABLE(s, sp->lock);
        !           419:            pb->ioResult = 0;
        !           420:            adspioc_ack(0, pb->ioc, pb->gref);
        !           421:            return 0;
        !           422:        }
        !           423:        if ((sp->state != (word)sOpen) && (sp->state != (word)sClosing)) {
        !           424:            ATENABLE(s, sp->lock);
        !           425:            pb->ioResult = errState;
        !           426:            return EINVAL;
        !           427:        }
        !           428:                
        !           429:        sp->state = sClosing;   /* No matter what, we're closing */
        !           430:        ATENABLE(s, sp->lock);
        !           431:     }                          /* dspClose */
        !           432:     
        !           433:     else {                     /* dspRemove */
        !           434:        ATDISABLE(s, sp->lock);
        !           435:        sp->removing = 1;       /* Prevent allowing another dspClose. */
        !           436:                                /* Tells completion routine of close */
        !           437:                                /* packet to remove us. */
        !           438: 
        !           439:        if (sp->state == sPassive || sp->state == sClosed || 
        !           440:            sp->state == sOpening) {
        !           441:            sp->state = sClosed;
        !           442:            ATENABLE(s, sp->lock);
        !           443:            DoClose(sp, errAborted, 0); /* Will remove CCB! */
        !           444:            return 0;
        !           445:        } else {                        /* sClosing & sOpen */
        !           446:            sp->state = sClosing;
        !           447:            ATENABLE(s, sp->lock);
        !           448:        }
        !           449:        
        !           450:     }                          /* dspRemove */
        !           451: 
        !           452:     if (pb->u.closeParams.abort || CheckOkToClose(sp)) /* going to close */
        !           453:     {
        !           454:        AbortIO(sp, errAborted);
        !           455:        sp->sendCtl = B_CTL_CLOSE; /* Send close advice */
        !           456:     }
        !           457: 
        !           458:     pb->ioResult = 1;
        !           459:     if ( (mp = gbuf_copym(pb->mp)) ) { /* duplicate user request */
        !           460:            adspioc_ack(0, pb->ioc, pb->gref); /* release user */
        !           461:            pb = (struct adspcmd *)gbuf_rptr(mp); /* get new parameter block */
        !           462:            pb->ioc = 0;
        !           463:            pb->mp = mp;
        !           464:            ATDISABLE(s, sp->lock);
        !           465:            qAddToEnd(&sp->opb, pb);    /* and save it */
        !           466:            ATENABLE(s, sp->lock);
        !           467:     } else {
        !           468:            pb->ioResult = 0;
        !           469:            adspioc_ack(0, pb->ioc, pb->gref); /* release user, and keep no copy
        !           470:                                             * for kernel bookkeeping, yetch!
        !           471:                                             */
        !           472:     }
        !           473:     CheckSend(sp);
        !           474: 
        !           475:     return 0;
        !           476: }
        !           477: 
        !           478: static void qRemove(qptr, elem)
        !           479:     register CCBPtr qptr;
        !           480:     register CCBPtr elem;
        !           481: {
        !           482:        int s;
        !           483: 
        !           484:        ATDISABLE(s, adspall_lock);
        !           485:     while(qptr->ccbLink) {
        !           486:        if ((DSPPBPtr)(qptr->ccbLink) == (DSPPBPtr)elem) {
        !           487:            qptr->ccbLink = elem->ccbLink;
        !           488:            elem->ccbLink = 0;
        !           489:            ATENABLE(s, adspall_lock);
        !           490:            return;
        !           491:        }
        !           492:        qptr = qptr->ccbLink;
        !           493:     }
        !           494:        ATENABLE(s, adspall_lock);
        !           495: }
        !           496: 
        !           497: int RxClose(sp)
        !           498:     register CCBPtr sp;
        !           499: {
        !           500:     register gbuf_t *mp;
        !           501:     register struct adspcmd *pb;
        !           502:        int s, l;
        !           503: 
        !           504:        ATDISABLE(l, sp->lockClose);
        !           505:        ATDISABLE(s, sp->lock);
        !           506:        if ((sp->state == sClosing) || (sp->state == sClosed)) {
        !           507:                ATENABLE(s, sp->lock);
        !           508:                ATENABLE(l, sp->lockClose);
        !           509:                return 0;
        !           510:        }
        !           511:     sp->state = sClosed;
        !           512:        ATENABLE(s, sp->lock);
        !           513:     CheckReadQueue(sp);                /* try to deliver all remaining data */
        !           514: 
        !           515:     if ( (mp = gbuf_alloc(sizeof(struct adspcmd), PRI_HI)) ) {
        !           516:         pb = (struct adspcmd *)gbuf_rptr(mp);
        !           517:        gbuf_wset(mp,sizeof(struct adspcmd));
        !           518:        pb->ioc = 0;
        !           519:        pb->mp = mp;
        !           520: 
        !           521:        pb->csCode = dspClose;
        !           522:        pb->ioResult = 0;
        !           523:        completepb(sp, pb);             /* send close completion */
        !           524:     }
        !           525: 
        !           526: if ((sp->userFlags & eClosed) == 0)
        !           527:     DoClose(sp, errAborted, -1);       /* abort send requests and timers */
        !           528: 
        !           529:        ATENABLE(l, sp->lockClose);
        !           530:     return 0;
        !           531: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.