Annotation of XNU/bsd/netat/adsp_Close.c, revision 1.1.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.