Annotation of embedaddon/mpd/src/fsm.c, revision 1.1

1.1     ! misho       1: 
        !             2: /*
        !             3:  * fsm.c
        !             4:  *
        !             5:  * Written by Toshiharu OHNO <tony-o@iij.ad.jp>
        !             6:  * Copyright (c) 1993, Internet Initiative Japan, Inc. All rights reserved.
        !             7:  * See ``COPYRIGHT.iij''
        !             8:  * 
        !             9:  * Rewritten by Archie Cobbs <archie@freebsd.org>
        !            10:  * Copyright (c) 1995-1999 Whistle Communications, Inc. All rights reserved.
        !            11:  * See ``COPYRIGHT.whistle''
        !            12:  */
        !            13: 
        !            14: #include "ppp.h"
        !            15: #include "fsm.h"
        !            16: #include "ngfunc.h"
        !            17: #include "util.h"
        !            18: 
        !            19: /*
        !            20:  * DEFINITIONS
        !            21:  */
        !            22: 
        !            23:   #define FSM_MAXCONFIG                10
        !            24:   #define FSM_MAXNAK           10
        !            25:   #define FSM_MAX_OPTS         100
        !            26:   #define FSM_MAXTERMINATE     2
        !            27:   #define FSM_MAXFAILURE       5
        !            28: 
        !            29: /* FSM restart options */
        !            30: 
        !            31:   /* #define RESTART_OPENED */
        !            32:   /* #define RESTART_CLOSING */
        !            33:   /* #define RESTART_STOPPED */
        !            34: 
        !            35:   struct fsmcodedesc {
        !            36:     void       (*action)(Fsm fp, FsmHeader hdr, Mbuf bp);
        !            37:     const char *name;
        !            38:   };
        !            39: 
        !            40: /* Size of REQ, ACK, NAK, and REJ buffers */
        !            41: 
        !            42:   #define REQ_BUFFER_SIZE      256
        !            43:   #define REJ_BUFFER_SIZE      256
        !            44:   #define ACK_BUFFER_SIZE      256
        !            45:   #define NAK_BUFFER_SIZE      256
        !            46: 
        !            47: /*
        !            48:  * INTERNAL FUNCTIONS
        !            49:  */
        !            50: 
        !            51:   static void  FsmNewState(Fsm f, enum fsm_state state);
        !            52: 
        !            53:   static void  FsmSendConfigReq(Fsm fp);
        !            54:   static void  FsmSendTerminateReq(Fsm fp);
        !            55:   static void  FsmSendTerminateAck(Fsm fp);
        !            56:   static void  FsmInitRestartCounter(Fsm fp, int value);
        !            57:   static void  FsmInitMaxFailure(Fsm fp, int value);
        !            58:   static void  FsmInitMaxConfig(Fsm fp, int value);
        !            59:   static void  FsmTimeout(void *arg);
        !            60: 
        !            61:   static void  FsmRecvConfigReq(Fsm fp, FsmHeader lhp, Mbuf bp);
        !            62:   static void  FsmRecvConfigAck(Fsm fp, FsmHeader lhp, Mbuf bp);
        !            63:   static void  FsmRecvConfigNak(Fsm fp, FsmHeader lhp, Mbuf bp);
        !            64:   static void  FsmRecvTermReq(Fsm fp, FsmHeader lhp, Mbuf bp);
        !            65:   static void  FsmRecvTermAck(Fsm fp, FsmHeader lhp, Mbuf bp);
        !            66:   static void  FsmRecvConfigRej(Fsm fp, FsmHeader lhp, Mbuf bp);
        !            67:   static void  FsmRecvCodeRej(Fsm fp, FsmHeader lhp, Mbuf bp);
        !            68:   static void  FsmRecvProtoRej(Fsm fp, FsmHeader lhp, Mbuf bp);
        !            69:   static void  FsmRecvEchoReq(Fsm fp, FsmHeader lhp, Mbuf bp);
        !            70:   static void  FsmRecvEchoRep(Fsm fp, FsmHeader lhp, Mbuf bp);
        !            71:   static void  FsmRecvDiscReq(Fsm fp, FsmHeader lhp, Mbuf bp);
        !            72:   static void  FsmRecvIdent(Fsm fp, FsmHeader lhp, Mbuf bp);
        !            73:   static void  FsmRecvTimeRemain(Fsm fp, FsmHeader lhp, Mbuf bp);
        !            74:   static void  FsmRecvResetReq(Fsm fp, FsmHeader lhp, Mbuf bp);
        !            75:   static void  FsmRecvResetAck(Fsm fp, FsmHeader lhp, Mbuf bp);
        !            76:   static void  FsmRecvVendor(Fsm fp, FsmHeader lhp, Mbuf bp);
        !            77:   static void  FsmRecvRxjPlus(Fsm fp);
        !            78: 
        !            79:   static void  FsmLayerUp(Fsm fp);
        !            80:   static void  FsmLayerDown(Fsm fp);
        !            81:   static void  FsmLayerStart(Fsm fp);
        !            82:   static void  FsmLayerFinish(Fsm fp);
        !            83: 
        !            84:   static Mbuf  FsmCheckMagic(Fsm fp, Mbuf bp);
        !            85:   static void  FsmEchoTimeout(void *arg);
        !            86:   static void  FsmDecodeBuffer(Fsm fp, u_char *buf, int size, int mode);
        !            87:   static int   FsmExtractOptions(Fsm fp, u_char *data,
        !            88:                  int dlen, FsmOption opts, int max);
        !            89: 
        !            90: /*
        !            91:  * GLOBAL VARIABLES
        !            92:  */
        !            93: 
        !            94:   u_int                gAckSize, gNakSize, gRejSize;
        !            95: 
        !            96: /*
        !            97:  * INTERNAL VARIABLES
        !            98:  */
        !            99: 
        !           100: /*
        !           101:  * It's OK for these to be statically allocated, because we always
        !           102:  * do our work with them all in one whole step without stopping.
        !           103:  */
        !           104: 
        !           105:   static u_char        gRejBuf[REJ_BUFFER_SIZE];
        !           106:   static u_char        gAckBuf[ACK_BUFFER_SIZE];
        !           107:   static u_char        gNakBuf[NAK_BUFFER_SIZE];
        !           108: 
        !           109:   static const struct fsmcodedesc FsmCodes[] = {
        !           110:    { FsmRecvVendor,    "Vendor Packet" },
        !           111:    { FsmRecvConfigReq,  "Configure Request" },
        !           112:    { FsmRecvConfigAck,  "Configure Ack" },
        !           113:    { FsmRecvConfigNak,  "Configure Nak" },
        !           114:    { FsmRecvConfigRej,  "Configure Reject" },
        !           115:    { FsmRecvTermReq,    "Terminate Request" },
        !           116:    { FsmRecvTermAck,    "Terminate Ack" },
        !           117:    { FsmRecvCodeRej,    "Code Reject" },
        !           118:    { FsmRecvProtoRej,   "Protocol Reject" },
        !           119:    { FsmRecvEchoReq,    "Echo Request" },
        !           120:    { FsmRecvEchoRep,    "Echo Reply" },
        !           121:    { FsmRecvDiscReq,    "Discard Request" },
        !           122:    { FsmRecvIdent,      "Ident" },
        !           123:    { FsmRecvTimeRemain, "Time Remain" },
        !           124:    { FsmRecvResetReq,   "Reset Request" },
        !           125:    { FsmRecvResetAck,   "Reset Ack" },
        !           126:   };
        !           127: 
        !           128:   #define NUM_FSM_CODES        (sizeof(FsmCodes) / sizeof(*FsmCodes))
        !           129: 
        !           130: /*
        !           131:  * FsmInit()
        !           132:  *
        !           133:  * Initialize FSM structure and install some default values
        !           134:  */
        !           135: 
        !           136: void
        !           137: FsmInit(Fsm fp, FsmType type, void *arg)
        !           138: {
        !           139:   memset(fp, 0, sizeof(*fp));
        !           140:   fp->type = type;
        !           141:   fp->arg = arg;
        !           142:   fp->log = LG_FSM | type->log;
        !           143:   fp->log2 = LG_FSM | type->log2;
        !           144:   fp->conf.maxconfig = FSM_MAXCONFIG;
        !           145:   fp->conf.maxterminate = FSM_MAXTERMINATE;
        !           146:   fp->conf.maxfailure = FSM_MAXFAILURE;
        !           147:   fp->conf.check_magic = FALSE;
        !           148:   fp->conf.passive = FALSE;
        !           149:   fp->state = ST_INITIAL;
        !           150:   fp->reqid = 1;
        !           151:   fp->rejid = 1;
        !           152:   fp->echoid = 1;
        !           153: }
        !           154: 
        !           155: /*
        !           156:  * FsmInst()
        !           157:  *
        !           158:  * Instantiate FSM structure from template
        !           159:  */
        !           160: 
        !           161: void
        !           162: FsmInst(Fsm fp, Fsm fpt, void *arg)
        !           163: {
        !           164:     memcpy(fp, fpt, sizeof(*fp));
        !           165:     fp->arg = arg;
        !           166: }
        !           167: 
        !           168: /*
        !           169:  * FsmNewState()
        !           170:  *
        !           171:  * Change state of a FSM. Also, call the configuration routine
        !           172:  * if this is an appropriate time.
        !           173:  */
        !           174: 
        !           175: void
        !           176: FsmNewState(Fsm fp, enum fsm_state new)
        !           177: {
        !           178:   enum fsm_state       old;
        !           179: 
        !           180:   /* Log it */
        !           181:   Log(fp->log2, ("[%s] %s: state change %s --> %s",
        !           182:     Pref(fp), Fsm(fp), FsmStateName(fp->state), FsmStateName(new)));
        !           183: 
        !           184:   /* Change state and call protocol's own handler, if any */
        !           185:   old = fp->state;
        !           186:   if (fp->type->NewState)
        !           187:     (*fp->type->NewState)(fp, old, new);
        !           188:   fp->state = new;
        !           189:   if ((new >= ST_INITIAL && new <= ST_STOPPED) || (new == ST_OPENED))
        !           190:     TimerStop(&fp->timer);
        !           191: 
        !           192:   /* Turn on/off keep-alive echo packets (if so configured) */
        !           193:   if (old == ST_OPENED)
        !           194:     TimerStop(&fp->echoTimer);
        !           195:   if (new == ST_OPENED && fp->conf.echo_int != 0) {
        !           196:     fp->quietCount = 0;
        !           197:     memset(&fp->idleStats, 0, sizeof(fp->idleStats));
        !           198:     TimerInit(&fp->echoTimer, "FsmKeepAlive",
        !           199:       fp->conf.echo_int * SECONDS, FsmEchoTimeout, fp);
        !           200:     TimerStartRecurring(&fp->echoTimer);
        !           201:   }
        !           202: }
        !           203: 
        !           204: /*
        !           205:  * FsmOutputMbuf()
        !           206:  *
        !           207:  * Send out a control packet with specified contents. Consumes the mbuf.
        !           208:  */
        !           209: 
        !           210: void
        !           211: FsmOutputMbuf(Fsm fp, u_int code, u_int id, Mbuf payload)
        !           212: {
        !           213:     Bund               b;
        !           214:     Mbuf               bp;
        !           215:     struct fsmheader   hdr;
        !           216: 
        !           217:     if (fp->type->link_layer)
        !           218:        b = ((Link)fp->arg)->bund;
        !           219:     else
        !           220:        b = (Bund)fp->arg;
        !           221: 
        !           222:     /* Build header */
        !           223:     hdr.id = id;
        !           224:     hdr.code = code;
        !           225:     hdr.length = htons(sizeof(hdr) + MBLEN(payload));
        !           226: 
        !           227:     /* Prepend to payload */
        !           228:     bp = mbcopyback(payload, -(int)sizeof(hdr), &hdr, sizeof(hdr));
        !           229: 
        !           230:     /* Send it out */
        !           231:     if (fp->type->link_layer) {
        !           232:        NgFuncWritePppFrameLink((Link)fp->arg, fp->type->proto, bp);
        !           233:     } else {
        !           234:        NgFuncWritePppFrame(b, NG_PPP_BUNDLE_LINKNUM, fp->type->proto, bp);
        !           235:     }
        !           236: }
        !           237: 
        !           238: /*
        !           239:  * FsmOutput()
        !           240:  *
        !           241:  * Send out a control packet with specified contents
        !           242:  */
        !           243: 
        !           244: void
        !           245: FsmOutput(Fsm fp, u_int code, u_int id, u_char *ptr, int len)
        !           246: {
        !           247:   Mbuf bp;
        !           248: 
        !           249:   bp = (len > 0) ? mbcopyback(NULL, 0, ptr, len) : NULL;
        !           250:   FsmOutputMbuf(fp, code, id, bp);
        !           251: }
        !           252: 
        !           253: /*
        !           254:  * FsmOpen()
        !           255:  *
        !           256:  * XXX The use of the restart option should probably be
        !           257:  * XXX configured per FSM via the initialization structure.
        !           258:  * XXX For now, we just make it mandatory via #ifdef's.
        !           259:  */
        !           260: 
        !           261: void
        !           262: FsmOpen(Fsm fp)
        !           263: {
        !           264:   Log(fp->log2, ("[%s] %s: Open event", Pref(fp), Fsm(fp)));
        !           265:   switch (fp->state) {
        !           266:     case ST_INITIAL:
        !           267:       FsmNewState(fp, ST_STARTING);
        !           268:       FsmLayerStart(fp);
        !           269:       break;
        !           270:     case ST_STARTING:
        !           271:       break;
        !           272:     case ST_CLOSED:
        !           273:       if (fp->type->Configure)
        !           274:        (*fp->type->Configure)(fp);
        !           275:       FsmNewState(fp, ST_REQSENT);
        !           276:       FsmLayerStart(fp);               /* Missing in RFC 1661 */
        !           277:       FsmInitRestartCounter(fp, fp->conf.maxconfig);
        !           278:       FsmInitMaxFailure(fp, fp->conf.maxfailure);
        !           279:       FsmInitMaxConfig(fp, fp->conf.maxconfig);
        !           280:       FsmSendConfigReq(fp);
        !           281:       break;
        !           282:     case ST_REQSENT:
        !           283:     case ST_ACKRCVD:
        !           284:     case ST_ACKSENT:
        !           285:       break;
        !           286: 
        !           287:     case ST_OPENED:
        !           288: #ifdef RESTART_OPENED
        !           289:       FsmDown(fp);
        !           290:       FsmUp(fp);
        !           291: #endif
        !           292:       break;
        !           293: 
        !           294:     case ST_CLOSING:
        !           295:       FsmNewState(fp, ST_STOPPING);
        !           296:     case ST_STOPPING:
        !           297: #ifdef RESTART_CLOSING
        !           298:       FsmDown(fp);
        !           299:       FsmUp(fp);
        !           300: #endif
        !           301:       break;
        !           302: 
        !           303:     case ST_STOPPED:
        !           304: #ifdef RESTART_STOPPED
        !           305:       FsmDown(fp);
        !           306:       FsmUp(fp);
        !           307: #endif
        !           308:       break;
        !           309:   }
        !           310: }
        !           311: 
        !           312: void
        !           313: FsmUp(Fsm fp)
        !           314: {
        !           315:   Log(fp->log2, ("[%s] %s: Up event", Pref(fp), Fsm(fp)));
        !           316:   switch (fp->state) {
        !           317:     case ST_INITIAL:
        !           318:       FsmNewState(fp, ST_CLOSED);
        !           319:       break;
        !           320:     case ST_STARTING:
        !           321:       if (fp->type->Configure)
        !           322:        (*fp->type->Configure)(fp);
        !           323:       FsmNewState(fp, ST_REQSENT);
        !           324:       FsmInitRestartCounter(fp, fp->conf.maxconfig);
        !           325:       FsmInitMaxFailure(fp, fp->conf.maxfailure);
        !           326:       FsmInitMaxConfig(fp, fp->conf.maxconfig);
        !           327:       FsmSendConfigReq(fp);
        !           328:       break;
        !           329:     default:
        !           330:       Log(fp->log2, ("[%s] %s: Oops, UP at %s",
        !           331:        Pref(fp), Fsm(fp), FsmStateName(fp->state)));
        !           332:       break;
        !           333:   }
        !           334: }
        !           335: 
        !           336: void
        !           337: FsmDown(Fsm fp)
        !           338: {
        !           339:   Log(fp->log2, ("[%s] %s: Down event", Pref(fp), Fsm(fp)));
        !           340:   switch (fp->state) {
        !           341:     case ST_CLOSING:
        !           342:       FsmLayerFinish(fp);              /* Missing in RFC 1661 */
        !           343:       /* fall through */
        !           344:     case ST_CLOSED:
        !           345:       FsmNewState(fp, ST_INITIAL);
        !           346:       break;
        !           347:     case ST_STOPPED:
        !           348:       FsmNewState(fp, ST_STARTING);
        !           349:       FsmLayerStart(fp);
        !           350:       break;
        !           351:     case ST_STOPPING:
        !           352:     case ST_REQSENT:
        !           353:     case ST_ACKRCVD:
        !           354:     case ST_ACKSENT:
        !           355:       FsmNewState(fp, ST_STARTING);
        !           356:       if (fp->type->UnConfigure)
        !           357:        (*fp->type->UnConfigure)(fp);
        !           358:       break;
        !           359:     case ST_OPENED:
        !           360:       FsmNewState(fp, ST_STARTING);
        !           361:       FsmLayerDown(fp);
        !           362:       if (fp->type->UnConfigure)
        !           363:        (*fp->type->UnConfigure)(fp);
        !           364:       break;
        !           365:     default:
        !           366:       break;
        !           367:   }
        !           368: }
        !           369: 
        !           370: void
        !           371: FsmClose(Fsm fp)
        !           372: {
        !           373:   Log(fp->log2, ("[%s] %s: Close event", Pref(fp), Fsm(fp)));
        !           374:   switch (fp->state) {
        !           375:     case ST_STARTING:
        !           376:       FsmNewState(fp, ST_INITIAL);
        !           377:       FsmLayerFinish(fp);
        !           378:       break;
        !           379:     case ST_STOPPED:
        !           380:       FsmNewState(fp, ST_CLOSED);
        !           381:       break;
        !           382:     case ST_STOPPING:
        !           383:       FsmNewState(fp, ST_CLOSING);
        !           384:       break;
        !           385:     case ST_OPENED:
        !           386:       FsmNewState(fp, ST_CLOSING);
        !           387:       FsmInitRestartCounter(fp, fp->conf.maxterminate);
        !           388:       FsmSendTerminateReq(fp);
        !           389:       FsmLayerDown(fp);
        !           390:       if (fp->type->UnConfigure)
        !           391:        (*fp->type->UnConfigure)(fp);
        !           392:       break;
        !           393:     case ST_REQSENT:
        !           394:     case ST_ACKRCVD:
        !           395:     case ST_ACKSENT:
        !           396:       FsmNewState(fp, ST_CLOSING);
        !           397:       FsmInitRestartCounter(fp, fp->conf.maxterminate);
        !           398:       FsmSendTerminateReq(fp);
        !           399:       if (fp->type->UnConfigure)
        !           400:        (*fp->type->UnConfigure)(fp);
        !           401:       break;
        !           402:     default:
        !           403:       break;
        !           404:   }
        !           405: }
        !           406: 
        !           407: /*
        !           408:  * Send functions
        !           409:  */
        !           410: 
        !           411: static void
        !           412: FsmSendConfigReq(Fsm fp)
        !           413: {
        !           414:   u_char       reqBuf[REQ_BUFFER_SIZE];
        !           415:   u_char       *cp;
        !           416: 
        !           417:   /* Build and display config request */
        !           418:   Log(fp->log, ("[%s] %s: SendConfigReq #%d", Pref(fp), Fsm(fp), fp->reqid));
        !           419:   cp = (*fp->type->BuildConfigReq)(fp, reqBuf);
        !           420:   FsmDecodeBuffer(fp, reqBuf, cp - reqBuf, MODE_NOP);
        !           421: 
        !           422:   /* Send it */
        !           423:   FsmOutput(fp, CODE_CONFIGREQ, fp->reqid++, reqBuf, cp - reqBuf);
        !           424: 
        !           425:   /* Restart restart timer and decrement restart counter */
        !           426:   TimerStart(&fp->timer);
        !           427:   fp->restart--;
        !           428:   fp->config--;
        !           429: }
        !           430: 
        !           431: static void
        !           432: FsmSendTerminateReq(Fsm fp)
        !           433: {
        !           434:   Log(fp->log, ("[%s] %s: SendTerminateReq #%d", Pref(fp), Fsm(fp), fp->reqid));
        !           435:   FsmOutput(fp, CODE_TERMREQ, fp->reqid++, NULL, 0);
        !           436:   if (fp->type->SendTerminateReq)
        !           437:     (*fp->type->SendTerminateReq)(fp);
        !           438:   TimerStart(&fp->timer);      /* Restart restart timer */
        !           439:   fp->restart--;               /* Decrement restart counter */
        !           440: }
        !           441: 
        !           442: static void
        !           443: FsmSendTerminateAck(Fsm fp)
        !           444: {
        !           445:   Log(fp->log, ("[%s] %s: SendTerminateAck #%d", Pref(fp), Fsm(fp), fp->reqid));
        !           446:   FsmOutput(fp, CODE_TERMACK, fp->reqid++, NULL, 0);
        !           447:   if (fp->type->SendTerminateAck)
        !           448:     (*fp->type->SendTerminateAck)(fp);
        !           449: }
        !           450: 
        !           451: static void
        !           452: FsmSendConfigAck(Fsm fp, FsmHeader lhp, u_char *option, int count)
        !           453: {
        !           454:   Log(fp->log, ("[%s] %s: SendConfigAck #%d", Pref(fp), Fsm(fp), lhp->id));
        !           455:   FsmDecodeBuffer(fp, option, count, MODE_NOP);
        !           456:   FsmOutput(fp, CODE_CONFIGACK, lhp->id, option, count);
        !           457: }
        !           458: 
        !           459: static void
        !           460: FsmSendConfigRej(Fsm fp, FsmHeader lhp, u_char *option, int count)
        !           461: {
        !           462:   Log(fp->log, ("[%s] %s: SendConfigRej #%d", Pref(fp), Fsm(fp), lhp->id));
        !           463:   FsmDecodeBuffer(fp, option, count, MODE_NOP);
        !           464:   FsmOutput(fp, CODE_CONFIGREJ, lhp->id, option, count);
        !           465:   fp->failure--;
        !           466: }
        !           467: 
        !           468: static void
        !           469: FsmSendConfigNak(Fsm fp, FsmHeader lhp, u_char *option, int count)
        !           470: {
        !           471:   Log(fp->log, ("[%s] %s: SendConfigNak #%d", Pref(fp), Fsm(fp), lhp->id));
        !           472:   FsmDecodeBuffer(fp, option, count, MODE_NOP);
        !           473:   FsmOutput(fp, CODE_CONFIGNAK, lhp->id, option, count);
        !           474:   fp->failure--;
        !           475: }
        !           476: 
        !           477: /*
        !           478:  * Timeout actions
        !           479:  */
        !           480: 
        !           481: static void
        !           482: FsmTimeout(void *arg)
        !           483: {
        !           484:   Fsm  fp = (Fsm) arg;
        !           485: 
        !           486:   if (fp->restart > 0) {       /* TO+ */
        !           487:     switch (fp->state) {
        !           488:       case ST_CLOSING:
        !           489:       case ST_STOPPING:
        !           490:        FsmSendTerminateReq(fp);
        !           491:        break;
        !           492:       case ST_REQSENT:
        !           493:       case ST_ACKSENT:
        !           494:        FsmSendConfigReq(fp);
        !           495:        break;
        !           496:       case ST_ACKRCVD:
        !           497:        FsmNewState(fp, ST_REQSENT);
        !           498:        FsmSendConfigReq(fp);
        !           499:        break;
        !           500:       default:
        !           501:        break;
        !           502:     }
        !           503:   } else {                             /* TO- */
        !           504:     switch (fp->state) {
        !           505:       case ST_CLOSING:
        !           506:        FsmNewState(fp, ST_CLOSED);
        !           507:        FsmLayerFinish(fp);
        !           508:        break;
        !           509:       case ST_STOPPING:
        !           510:        FsmNewState(fp, ST_STOPPED);
        !           511:        FsmLayerFinish(fp);
        !           512:        break;
        !           513:       case ST_REQSENT:
        !           514:       case ST_ACKSENT:
        !           515:       case ST_ACKRCVD:
        !           516:        FsmFailure(fp, FAIL_NEGOT_FAILURE);
        !           517:        break;
        !           518:       default:
        !           519:         break;
        !           520:     }
        !           521:   }
        !           522: }
        !           523: 
        !           524: void
        !           525: FsmInitRestartCounter(Fsm fp, int value)
        !           526: {
        !           527:   const int    retry = fp->type->link_layer ?
        !           528:                        ((Link)(fp->arg))->conf.retry_timeout : 
        !           529:                        ((Bund)(fp->arg))->conf.retry_timeout;
        !           530: 
        !           531:   TimerStop(&fp->timer);
        !           532:   TimerInit(&fp->timer,
        !           533:     fp->type->name, retry * SECONDS, FsmTimeout, (void *) fp);
        !           534:   fp->restart = value;
        !           535: }
        !           536: 
        !           537: void
        !           538: FsmInitMaxFailure(Fsm fp, int value)
        !           539: {
        !           540:   fp->failure = value;
        !           541: }
        !           542: 
        !           543: void
        !           544: FsmInitMaxConfig(Fsm fp, int value)
        !           545: {
        !           546:   fp->config = value;
        !           547: }
        !           548: 
        !           549: /*
        !           550:  * Actions that happen when we receive packets
        !           551:  */
        !           552: 
        !           553: /* RCR */
        !           554: 
        !           555: static void
        !           556: FsmRecvConfigReq(Fsm fp, FsmHeader lhp, Mbuf bp)
        !           557: {
        !           558:   int  fullyAcked;
        !           559: 
        !           560:   /* Check and process easy cases */
        !           561:   switch (fp->state) {
        !           562:     case ST_INITIAL:
        !           563:     case ST_STARTING:
        !           564:       Log(fp->log2, ("[%s] %s: Oops, RCR in %s", Pref(fp), Fsm(fp), FsmStateName(fp->state)));
        !           565:       mbfree(bp);
        !           566:       return;
        !           567:     case ST_CLOSED:
        !           568:       FsmSendTerminateAck(fp);
        !           569:       mbfree(bp);
        !           570:       return;
        !           571:     case ST_STOPPED:
        !           572:       if (fp->type->Configure)
        !           573:        (*fp->type->Configure)(fp);
        !           574:       break;
        !           575:     case ST_CLOSING:
        !           576:     case ST_STOPPING:
        !           577:       mbfree(bp);
        !           578:       return;
        !           579:     default:
        !           580:       break;
        !           581:   }
        !           582: 
        !           583:   /* Decode packet */
        !           584:   FsmDecodeBuffer(fp, MBDATA(bp), MBLEN(bp), MODE_REQ);
        !           585: 
        !           586:   /* State specific actions */
        !           587:   switch (fp->state) {
        !           588:     case ST_OPENED:
        !           589:       FsmLayerDown(fp);
        !           590:       FsmSendConfigReq(fp);
        !           591:       break;
        !           592:     case ST_STOPPED:
        !           593:       FsmLayerStart(fp);               /* Missing in RFC 1661 */
        !           594:       FsmInitRestartCounter(fp, fp->conf.maxconfig);
        !           595:       FsmInitMaxFailure(fp, fp->conf.maxfailure);
        !           596:       FsmInitMaxConfig(fp, fp->conf.maxconfig);
        !           597:       FsmSendConfigReq(fp);
        !           598:       break;
        !           599:     default:
        !           600:       break;
        !           601:   }
        !           602: 
        !           603:   /* What did we think of packet? */
        !           604:   fullyAcked = (gNakSize == 0 && gRejSize == 0);
        !           605:   if (fullyAcked)
        !           606:     FsmSendConfigAck(fp, lhp, gAckBuf, gAckSize);
        !           607:   else {
        !           608:     if (fp->failure <= 0) {
        !           609:       Log(fp->log, ("[%s] %s: not converging", Pref(fp), Fsm(fp)));
        !           610:       FsmFailure(fp, FAIL_NEGOT_FAILURE);
        !           611:       mbfree(bp);
        !           612:       return;
        !           613:     } else {
        !           614:       if (gRejSize)
        !           615:        FsmSendConfigRej(fp, lhp, gRejBuf, gRejSize);
        !           616:       else if (gNakSize)
        !           617:        FsmSendConfigNak(fp, lhp, gNakBuf, gNakSize);
        !           618:     }
        !           619:   }
        !           620: 
        !           621:   /* Continue with state transition */
        !           622:   switch (fp->state) {
        !           623:     case ST_STOPPED:
        !           624:     case ST_OPENED:
        !           625:       if (fullyAcked)
        !           626:        FsmNewState(fp, ST_ACKSENT);
        !           627:       else
        !           628:        FsmNewState(fp, ST_REQSENT);
        !           629:       break;
        !           630:     case ST_REQSENT:
        !           631:       if (fullyAcked)
        !           632:        FsmNewState(fp, ST_ACKSENT);
        !           633:       break;
        !           634:     case ST_ACKRCVD:
        !           635:       if (fullyAcked)
        !           636:       {
        !           637:        FsmNewState(fp, ST_OPENED);
        !           638:        FsmLayerUp(fp);
        !           639:       }
        !           640:       break;
        !           641:     case ST_ACKSENT:
        !           642:       if (!fullyAcked)
        !           643:        FsmNewState(fp, ST_REQSENT);
        !           644:       break;
        !           645:     default:
        !           646:       break;
        !           647:   }
        !           648:   mbfree(bp);
        !           649: }
        !           650: 
        !           651: /* RCA */
        !           652: 
        !           653: static void
        !           654: FsmRecvConfigAck(Fsm fp, FsmHeader lhp, Mbuf bp)
        !           655: {
        !           656: 
        !           657:   /* Check sequence number */
        !           658:   if (lhp->id != (u_char) (fp->reqid - 1)) {
        !           659:     Log(fp->log, ("[%s]   Wrong id#, expecting %d", Pref(fp), (u_char) (fp->reqid - 1)));
        !           660:     mbfree(bp);
        !           661:     return;
        !           662:   }
        !           663: 
        !           664:   /* XXX We should verify the contents are equal to our last sent config-req */
        !           665: 
        !           666:   /* Decode packet */
        !           667:   FsmDecodeBuffer(fp, MBDATA(bp), MBLEN(bp), MODE_NOP);
        !           668: 
        !           669:   /* Do whatever */
        !           670:   switch (fp->state) {
        !           671:     case ST_CLOSED:
        !           672:     case ST_STOPPED:
        !           673:       FsmSendTerminateAck(fp);
        !           674:       break;
        !           675:     case ST_CLOSING:
        !           676:     case ST_STOPPING:
        !           677:       break;
        !           678:     case ST_REQSENT:
        !           679:       FsmNewState(fp, ST_ACKRCVD);
        !           680:       FsmInitRestartCounter(fp, fp->conf.maxconfig);
        !           681:       FsmInitMaxFailure(fp, fp->conf.maxfailure);
        !           682:       FsmInitMaxConfig(fp, fp->conf.maxconfig);
        !           683:       TimerStart(&fp->timer);          /* Start restart timer */
        !           684:       break;
        !           685:     case ST_ACKRCVD:
        !           686:       FsmNewState(fp, ST_REQSENT);
        !           687:       FsmSendConfigReq(fp);
        !           688:       break;
        !           689:     case ST_ACKSENT:
        !           690:       FsmNewState(fp, ST_OPENED);
        !           691:       FsmInitRestartCounter(fp, fp->conf.maxconfig);
        !           692:       FsmInitMaxFailure(fp, fp->conf.maxfailure);
        !           693:       FsmInitMaxConfig(fp, fp->conf.maxconfig);
        !           694:       FsmLayerUp(fp);
        !           695:       break;
        !           696:     case ST_OPENED:
        !           697:       FsmNewState(fp, ST_REQSENT);
        !           698:       FsmLayerDown(fp);
        !           699:       FsmSendConfigReq(fp);
        !           700:       break;
        !           701:     default:
        !           702:       break;
        !           703:   }
        !           704:   mbfree(bp);
        !           705: }
        !           706: 
        !           707: /* RCN */
        !           708: 
        !           709: static void
        !           710: FsmRecvConfigNak(Fsm fp, FsmHeader lhp, Mbuf bp)
        !           711: {
        !           712: 
        !           713:   /* Check sequence number */
        !           714:   if (lhp->id != (u_char) (fp->reqid - 1)) {
        !           715:     Log(fp->log, ("[%s]   Wrong id#, expecting %d", Pref(fp), (u_char) (fp->reqid - 1)));
        !           716:     mbfree(bp);
        !           717:     return;
        !           718:   }
        !           719: 
        !           720:   /* Check and process easy cases */
        !           721:   switch (fp->state) {
        !           722:     case ST_INITIAL:
        !           723:     case ST_STARTING:
        !           724:       Log(fp->log, ("[%s] %s: Oops, RCN in %s", Pref(fp), Fsm(fp), FsmStateName(fp->state)));
        !           725:       mbfree(bp);
        !           726:       return;
        !           727:     case ST_CLOSED:
        !           728:     case ST_STOPPED:
        !           729:       FsmSendTerminateAck(fp);
        !           730:       mbfree(bp);
        !           731:       return;
        !           732:     case ST_CLOSING:
        !           733:     case ST_STOPPING:
        !           734:       mbfree(bp);
        !           735:       return;
        !           736:     default:
        !           737:       break;
        !           738:   }
        !           739: 
        !           740:   /* Decode packet */
        !           741:   FsmDecodeBuffer(fp, MBDATA(bp), MBLEN(bp), MODE_NAK);
        !           742: 
        !           743:   /* Not converging? */
        !           744:   if (fp->config <= 0) {
        !           745:     Log(fp->log, ("[%s] %s: not converging", Pref(fp), Fsm(fp)));
        !           746:     FsmFailure(fp, FAIL_NEGOT_FAILURE);
        !           747:     mbfree(bp);
        !           748:     return;
        !           749:   }
        !           750: 
        !           751:   /* Do whatever */
        !           752:   switch (fp->state) {
        !           753:     case ST_REQSENT:
        !           754:     case ST_ACKSENT:
        !           755:       FsmInitRestartCounter(fp, fp->conf.maxconfig);
        !           756:       FsmSendConfigReq(fp);
        !           757:       break;
        !           758:     case ST_OPENED:
        !           759:       FsmLayerDown(fp);
        !           760:       /* fall through */
        !           761:     case ST_ACKRCVD:
        !           762:       FsmNewState(fp, ST_REQSENT);
        !           763:       FsmSendConfigReq(fp);
        !           764:       break;
        !           765:     default:
        !           766:       break;
        !           767:   }
        !           768:   mbfree(bp);
        !           769: }
        !           770: 
        !           771: /* RCJ */
        !           772: 
        !           773: static void
        !           774: FsmRecvConfigRej(Fsm fp, FsmHeader lhp, Mbuf bp)
        !           775: {
        !           776: 
        !           777:   /* Check sequence number */
        !           778:   if (lhp->id != (u_char) (fp->reqid - 1)) {
        !           779:     Log(fp->log, ("[%s]   Wrong id#, expecting %d", Pref(fp), (u_char) (fp->reqid - 1)));
        !           780:     mbfree(bp);
        !           781:     return;
        !           782:   }
        !           783: 
        !           784:   /* XXX should verify contents are a subset of previously sent config-req */
        !           785: 
        !           786:   /* Check and process easy cases */
        !           787:   switch (fp->state) {
        !           788:     case ST_INITIAL:
        !           789:     case ST_STARTING:
        !           790:       Log(fp->log, ("[%s] %s: Oops, RCJ in %s", Pref(fp), Fsm(fp), FsmStateName(fp->state)));
        !           791:       mbfree(bp);
        !           792:       return;
        !           793:     case ST_CLOSED:
        !           794:     case ST_STOPPED:
        !           795:       FsmSendTerminateAck(fp);
        !           796:       mbfree(bp);
        !           797:       return;
        !           798:     case ST_CLOSING:
        !           799:     case ST_STOPPING:
        !           800:       mbfree(bp);
        !           801:       return;
        !           802:     default:
        !           803:       break;
        !           804:   }
        !           805: 
        !           806:   /* Decode packet */
        !           807:   FsmDecodeBuffer(fp, MBDATA(bp), MBLEN(bp), MODE_REJ);
        !           808: 
        !           809:   /* Not converging? */
        !           810:   if (fp->config <= 0) {
        !           811:     Log(fp->log, ("[%s] %s: not converging", Pref(fp), Fsm(fp)));
        !           812:     FsmFailure(fp, FAIL_NEGOT_FAILURE);
        !           813:     mbfree(bp);
        !           814:     return;
        !           815:   }
        !           816: 
        !           817:   /* Do whatever */
        !           818:   switch (fp->state) {
        !           819:     case ST_REQSENT:
        !           820:     case ST_ACKSENT:
        !           821:       FsmInitRestartCounter(fp, fp->conf.maxconfig);
        !           822:       FsmSendConfigReq(fp);
        !           823:       break;
        !           824:     case ST_OPENED:
        !           825:       FsmNewState(fp, ST_REQSENT);
        !           826:       FsmLayerDown(fp);
        !           827:       FsmSendConfigReq(fp);
        !           828:       break;
        !           829:     case ST_ACKRCVD:
        !           830:       FsmNewState(fp, ST_REQSENT);
        !           831:       FsmSendConfigReq(fp);
        !           832:       break;
        !           833:     default:
        !           834:       break;
        !           835:   }
        !           836:   mbfree(bp);
        !           837: }
        !           838: 
        !           839: /* RTR */
        !           840: 
        !           841: static void
        !           842: FsmRecvTermReq(Fsm fp, FsmHeader lhp, Mbuf bp)
        !           843: {
        !           844:   if (fp->type->link_layer) {
        !           845:     RecordLinkUpDownReason(NULL, (Link)(fp->arg), 0, STR_PEER_DISC, NULL);
        !           846:   }
        !           847:   switch (fp->state) {
        !           848:     case ST_INITIAL:
        !           849:     case ST_STARTING:
        !           850:       Log(fp->log, ("[%s] %s: Oops, RTR in %s", Pref(fp), Fsm(fp), FsmStateName(fp->state)));
        !           851:       break;
        !           852:     case ST_CLOSED:
        !           853:     case ST_STOPPED:
        !           854:     case ST_CLOSING:
        !           855:     case ST_STOPPING:
        !           856:     case ST_REQSENT:
        !           857:       FsmSendTerminateAck(fp);
        !           858:       break;
        !           859:     case ST_ACKRCVD:
        !           860:     case ST_ACKSENT:
        !           861:       FsmNewState(fp, ST_REQSENT);
        !           862:       FsmSendTerminateAck(fp);
        !           863:       break;
        !           864:     case ST_OPENED:
        !           865:       FsmNewState(fp, ST_STOPPING);
        !           866:       FsmSendTerminateAck(fp);
        !           867:       FsmLayerDown(fp);
        !           868:       FsmInitRestartCounter(fp, 0);    /* Zero restart counter */
        !           869:       TimerStart(&fp->timer);          /* Start restart timer */
        !           870:       if (fp->type->UnConfigure)
        !           871:        (*fp->type->UnConfigure)(fp);
        !           872:       break;
        !           873:   }
        !           874:   mbfree(bp);
        !           875: }
        !           876: 
        !           877: /* RTA */
        !           878: 
        !           879: static void
        !           880: FsmRecvTermAck(Fsm fp, FsmHeader lhp, Mbuf bp)
        !           881: {
        !           882:   switch (fp->state) {
        !           883:     case ST_CLOSING:
        !           884:       FsmNewState(fp, ST_CLOSED);
        !           885:       FsmLayerFinish(fp);
        !           886:       break;
        !           887:     case ST_STOPPING:
        !           888:       FsmNewState(fp, ST_STOPPED);
        !           889:       FsmLayerFinish(fp);
        !           890:       break;
        !           891:     case ST_ACKRCVD:
        !           892:       FsmNewState(fp, ST_REQSENT);
        !           893:       break;
        !           894:     case ST_OPENED:
        !           895:       FsmNewState(fp, ST_REQSENT);
        !           896:       FsmLayerDown(fp);
        !           897:       FsmSendConfigReq(fp);
        !           898:       break;
        !           899:     default:
        !           900:       break;
        !           901:   }
        !           902:   mbfree(bp);
        !           903: }
        !           904: 
        !           905: /*
        !           906:  * FsmRecvCodeRej()
        !           907:  *
        !           908:  * By default, this is fatal for most codes
        !           909:  */
        !           910: 
        !           911: static void
        !           912: FsmRecvCodeRej(Fsm fp, FsmHeader lhp, Mbuf bp)
        !           913: {
        !           914:   u_char       code = 0;
        !           915:   int          fatal;
        !           916: 
        !           917:   /* Get code and log it */
        !           918:   bp = mbread(bp, &code, sizeof(code));
        !           919:   Log(fp->log, ("[%s] %s: code %s was rejected", Pref(fp), Fsm(fp), FsmCodeName(code)));
        !           920: 
        !           921:   /* Determine fatalness */
        !           922:   if (fp->type->RecvCodeRej)
        !           923:     fatal = (*fp->type->RecvCodeRej)(fp, code, bp);
        !           924:   else {
        !           925:     switch (code) {
        !           926:       case CODE_CONFIGREQ:
        !           927:       case CODE_CONFIGACK:
        !           928:       case CODE_CONFIGNAK:
        !           929:       case CODE_CONFIGREJ:
        !           930:       case CODE_TERMREQ:
        !           931:       case CODE_TERMACK:
        !           932:       case CODE_CODEREJ:
        !           933:       case CODE_PROTOREJ:
        !           934:       case CODE_ECHOREQ:
        !           935:       case CODE_ECHOREP:
        !           936:       case CODE_RESETREQ:
        !           937:       case CODE_RESETACK:
        !           938:        fatal = TRUE;
        !           939:        break;
        !           940:       case CODE_VENDOR:
        !           941:       case CODE_DISCREQ:
        !           942:       case CODE_IDENT:
        !           943:       case CODE_TIMEREM:
        !           944:       default:         /* if we don't know it, that makes two of us */
        !           945:        fatal = FALSE;
        !           946:        break;
        !           947:     }
        !           948:   }
        !           949: 
        !           950:   /* Possibly shut down as a result */
        !           951:   if (fatal)
        !           952:     FsmFailure(fp, FAIL_RECD_CODEREJ);         /* RXJ- */
        !           953:   else
        !           954:     FsmRecvRxjPlus(fp);
        !           955:   mbfree(bp);
        !           956: }
        !           957: 
        !           958: /*
        !           959:  * FsmRecvProtoRej()
        !           960:  *
        !           961:  * By default, this is non-fatal
        !           962:  */
        !           963: 
        !           964: static void
        !           965: FsmRecvProtoRej(Fsm fp, FsmHeader lhp, Mbuf bp)
        !           966: {
        !           967:   u_short      proto = 0;
        !           968:   int          fatal = FALSE;
        !           969: 
        !           970:   bp = mbread(bp, &proto, sizeof(proto));
        !           971:   proto = ntohs(proto);
        !           972:   Log(fp->log, ("[%s] %s: protocol %s was rejected", Pref(fp), Fsm(fp), ProtoName(proto)));
        !           973:   if (fp->state == ST_OPENED && fp->type->RecvProtoRej)
        !           974:     fatal = (*fp->type->RecvProtoRej)(fp, proto, bp);
        !           975:   if (fatal)
        !           976:     FsmFailure(fp, FAIL_RECD_PROTREJ);         /* RXJ- */
        !           977:   else
        !           978:     FsmRecvRxjPlus(fp);
        !           979:   mbfree(bp);
        !           980: }
        !           981: 
        !           982: /*
        !           983:  * FsmRecvRxjPlus()
        !           984:  */
        !           985: 
        !           986: static void
        !           987: FsmRecvRxjPlus(Fsm fp)                         /* RXJ+ */
        !           988: {
        !           989:   switch (fp->state) {
        !           990:     case ST_ACKRCVD:
        !           991:       FsmNewState(fp, ST_REQSENT);
        !           992:       break;
        !           993:     default:
        !           994:       break;
        !           995:   }
        !           996: }
        !           997: 
        !           998: /*
        !           999:  * FsmFailure()
        !          1000:  *
        !          1001:  * Call this at any point if something fatal happens that is inherent
        !          1002:  * to the FSM itself, like a RXJ- event or negotiation failed to converge.
        !          1003:  * The action taken is like the RXJ- event.
        !          1004:  */
        !          1005: 
        !          1006: void
        !          1007: FsmFailure(Fsm fp, enum fsmfail reason)
        !          1008: {
        !          1009:   Log(fp->log, ("[%s] %s: %s", Pref(fp), Fsm(fp), FsmFailureStr(reason)));
        !          1010: 
        !          1011:   /* Let layer do any special handling of error code */
        !          1012:   if (fp->type->Failure)
        !          1013:     (*fp->type->Failure)(fp, reason);
        !          1014: 
        !          1015:   /* Shut this state machine down */
        !          1016:   switch (fp->state) {
        !          1017:     case ST_CLOSING:
        !          1018:       FsmNewState(fp, ST_CLOSED);
        !          1019:       /* fall through */
        !          1020:     case ST_CLOSED:
        !          1021:       FsmLayerFinish(fp);
        !          1022:       break;
        !          1023:     case ST_STOPPING:
        !          1024:       FsmNewState(fp, ST_STOPPED);
        !          1025:       FsmLayerFinish(fp);
        !          1026:       break;
        !          1027:     case ST_ACKRCVD:
        !          1028:     case ST_ACKSENT:
        !          1029:     case ST_REQSENT:
        !          1030:       FsmNewState(fp, ST_STOPPED);
        !          1031:       if (!fp->conf.passive)
        !          1032:        FsmLayerFinish(fp);
        !          1033:       if (fp->type->UnConfigure)
        !          1034:        (*fp->type->UnConfigure)(fp);
        !          1035:       break;
        !          1036: 
        !          1037:     /*
        !          1038:      * In the opened state, the peer FSM has somehow died or did something
        !          1039:      * horribly wrong to us. So the common sense action in this case is to 
        !          1040:      * bring the whole link down, rather than restarting just the FSM.
        !          1041:      * We do this by telling the lower layer to restart using tlf and tls
        !          1042:      * while also pretending that we got a DOWN event.
        !          1043:      */
        !          1044:     case ST_OPENED:
        !          1045:       FsmNewState(fp, ST_STOPPING);
        !          1046:       FsmInitRestartCounter(fp, fp->conf.maxterminate);
        !          1047:       FsmSendTerminateReq(fp);
        !          1048:       FsmLayerDown(fp);
        !          1049:       if (fp->type->UnConfigure)
        !          1050:        (*fp->type->UnConfigure)(fp);
        !          1051:       break;
        !          1052: 
        !          1053:     /*
        !          1054:      * In the STOPPED state, then most likely the negotiation timed out
        !          1055:      * or didn't converge. Just wait for the DOWN event from the previously
        !          1056:      * issued tlf action.
        !          1057:      */
        !          1058:     case ST_STOPPED:
        !          1059:       if (!fp->conf.passive)
        !          1060:        FsmLayerFinish(fp);
        !          1061:       break;
        !          1062:     default:
        !          1063:       break;
        !          1064:   }
        !          1065: }
        !          1066: 
        !          1067: /*
        !          1068:  * FsmFailureStr()
        !          1069:  */
        !          1070: 
        !          1071: const char *
        !          1072: FsmFailureStr(enum fsmfail reason)
        !          1073: {
        !          1074:   const char   *string = NULL;
        !          1075: 
        !          1076:   switch (reason) {
        !          1077:     case FAIL_NEGOT_FAILURE:
        !          1078:       string = STR_FAIL_NEGOT_FAILURE;
        !          1079:       break;
        !          1080:     case FAIL_RECD_BADMAGIC:
        !          1081:       string = STR_FAIL_RECD_BADMAGIC;
        !          1082:       break;
        !          1083:     case FAIL_RECD_CODEREJ:
        !          1084:       string = STR_FAIL_RECD_CODEREJ;
        !          1085:       break;
        !          1086:     case FAIL_RECD_PROTREJ:
        !          1087:       string = STR_FAIL_RECD_PROTREJ;
        !          1088:       break;
        !          1089:     case FAIL_WAS_PROTREJ:
        !          1090:       string = STR_FAIL_WAS_PROTREJ;
        !          1091:       break;
        !          1092:     case FAIL_ECHO_TIMEOUT:
        !          1093:       string = STR_FAIL_ECHO_TIMEOUT;
        !          1094:       break;
        !          1095:     case FAIL_CANT_ENCRYPT:
        !          1096:       string = STR_FAIL_CANT_ENCRYPT;
        !          1097:       break;
        !          1098:     default:
        !          1099:       assert(0);
        !          1100:   }
        !          1101:   return(string);
        !          1102: }
        !          1103: 
        !          1104: /*
        !          1105:  * FsmSendEchoReq()
        !          1106:  *
        !          1107:  * Send an echo request containing the supplied payload data.
        !          1108:  * Consumes the mbuf.
        !          1109:  */
        !          1110: 
        !          1111: void
        !          1112: FsmSendEchoReq(Fsm fp, Mbuf payload)
        !          1113: {
        !          1114:   u_int32_t    const self_magic = htonl(((Link)(fp->arg))->lcp.want_magic);
        !          1115:   Mbuf         bp;
        !          1116: 
        !          1117:   if (fp->state != ST_OPENED)
        !          1118:     return;
        !          1119: 
        !          1120:   /* Prepend my magic number */
        !          1121:   bp = mbcopyback(payload, -(int)sizeof(self_magic), &self_magic, sizeof(self_magic));
        !          1122: 
        !          1123:   /* Send it */
        !          1124:   Log(LG_ECHO, ("[%s] %s: SendEchoReq #%d", Pref(fp), Fsm(fp), fp->echoid));
        !          1125:   FsmOutputMbuf(fp, CODE_ECHOREQ, fp->echoid++, bp);
        !          1126: }
        !          1127: 
        !          1128: /*
        !          1129:  * FsmSendIdent()
        !          1130:  *
        !          1131:  * Send an LCP ident packet.
        !          1132:  */
        !          1133: 
        !          1134: void
        !          1135: FsmSendIdent(Fsm fp, const char *ident)
        !          1136: {
        !          1137:   u_int32_t    self_magic = htonl(((Link)(fp->arg))->lcp.want_magic);
        !          1138:   const int    len = strlen(ident) + 1;        /* include NUL to be nice */
        !          1139:   Mbuf         bp;
        !          1140: 
        !          1141:   /* Leave magic zero unless fully opened, as IDENT can be sent anytime */
        !          1142:   if (fp->state != ST_OPENED)
        !          1143:     self_magic = 0;
        !          1144: 
        !          1145:   /* Prepend my magic number */
        !          1146:   bp = mbcopyback(NULL, 0, (u_char *) &self_magic, sizeof(self_magic));
        !          1147:   bp = mbcopyback(bp, sizeof(self_magic), ident, len);
        !          1148: 
        !          1149:   /* Send it */
        !          1150:   Log(LG_FSM, ("[%s] %s: SendIdent #%d", Pref(fp), Fsm(fp), fp->echoid));
        !          1151:   ShowMesg(LG_FSM, Pref(fp), ident, len);
        !          1152:   FsmOutputMbuf(fp, CODE_IDENT, fp->echoid++, bp);
        !          1153: }
        !          1154: 
        !          1155: /*
        !          1156:  * FsmSendTimeRemaining()
        !          1157:  *
        !          1158:  * Send an LCP Time-Remaining packet.
        !          1159:  */
        !          1160: 
        !          1161: void
        !          1162: FsmSendTimeRemaining(Fsm fp, u_int seconds)
        !          1163: {
        !          1164:   u_int32_t    self_magic = htonl(((Link)(fp->arg))->lcp.want_magic);
        !          1165:   u_int32_t    data = htonl(seconds);
        !          1166:   Mbuf         bp;
        !          1167: 
        !          1168:   /* Leave magic zero unless fully opened, as IDENT can be sent anytime */
        !          1169:   if (fp->state != ST_OPENED)
        !          1170:     self_magic = 0;
        !          1171: 
        !          1172:   /* Prepend my magic number */
        !          1173:   bp = mbcopyback(NULL, 0, (u_char *) &self_magic, sizeof(self_magic));
        !          1174:   bp = mbcopyback(bp, sizeof(self_magic), &data, 4);
        !          1175: 
        !          1176:   /* Send it */
        !          1177:   Log(LG_FSM, ("[%s] %s: SendTimeRemaining #%d", Pref(fp), Fsm(fp), fp->echoid));
        !          1178:   Log(LG_FSM, ("[%s]   %u seconds remain", Pref(fp), seconds));
        !          1179:   FsmOutputMbuf(fp, CODE_TIMEREM, fp->echoid++, bp);
        !          1180: }
        !          1181: 
        !          1182: /*
        !          1183:  * FsmRecvEchoReq()
        !          1184:  */
        !          1185: 
        !          1186: static void
        !          1187: FsmRecvEchoReq(Fsm fp, FsmHeader lhp, Mbuf bp)
        !          1188: {
        !          1189:   u_int32_t    self_magic;
        !          1190: 
        !          1191:   /* Validate magic number */
        !          1192:   bp = FsmCheckMagic(fp, bp);
        !          1193: 
        !          1194:   /* If not opened, do nothing */
        !          1195:   if (fp->state != ST_OPENED) {
        !          1196:     mbfree(bp);
        !          1197:     return;
        !          1198:   }
        !          1199: 
        !          1200:   /* Stick my magic number in there instead */
        !          1201:   self_magic = htonl(((Link)(fp->arg))->lcp.want_magic);
        !          1202:   bp = mbcopyback(bp, -(int)sizeof(self_magic), &self_magic, sizeof(self_magic));
        !          1203: 
        !          1204:   /* Send it back, preserving everything else */
        !          1205:   Log(LG_ECHO, ("[%s] %s: SendEchoRep #%d", Pref(fp), Fsm(fp), lhp->id));
        !          1206:   FsmOutputMbuf(fp, CODE_ECHOREP, lhp->id, bp);
        !          1207: }
        !          1208: 
        !          1209: /*
        !          1210:  * FsmRecvEchoRep()
        !          1211:  */
        !          1212: 
        !          1213: static void
        !          1214: FsmRecvEchoRep(Fsm fp, FsmHeader lhp, Mbuf bp)
        !          1215: {
        !          1216:   bp = FsmCheckMagic(fp, bp);
        !          1217:   mbfree(bp);
        !          1218: }
        !          1219: 
        !          1220: /*
        !          1221:  * FsmRecvDiscReq()
        !          1222:  */
        !          1223: 
        !          1224: static void
        !          1225: FsmRecvDiscReq(Fsm fp, FsmHeader lhp, Mbuf bp)
        !          1226: {
        !          1227:   bp = FsmCheckMagic(fp, bp);
        !          1228:   if (fp->type->RecvDiscReq)
        !          1229:     (*fp->type->RecvDiscReq)(fp, bp);
        !          1230:   mbfree(bp);
        !          1231: }
        !          1232: 
        !          1233: /*
        !          1234:  * FsmRecvIdent()
        !          1235:  */
        !          1236: 
        !          1237: static void
        !          1238: FsmRecvIdent(Fsm fp, FsmHeader lhp, Mbuf bp)
        !          1239: {
        !          1240:     bp = FsmCheckMagic(fp, bp);
        !          1241:     if (bp)
        !          1242:         ShowMesg(fp->log, Pref(fp), (char *) MBDATA(bp), MBLEN(bp));
        !          1243:     if (fp->type->RecvIdent)
        !          1244:        (*fp->type->RecvIdent)(fp, bp);
        !          1245:     mbfree(bp);
        !          1246: }
        !          1247: 
        !          1248: /*
        !          1249:  * FsmRecvVendor()
        !          1250:  */
        !          1251: 
        !          1252: static void
        !          1253: FsmRecvVendor(Fsm fp, FsmHeader lhp, Mbuf bp)
        !          1254: {
        !          1255:     bp = FsmCheckMagic(fp, bp);
        !          1256:     if (fp->type->RecvVendor)
        !          1257:        (*fp->type->RecvVendor)(fp, bp);
        !          1258:     mbfree(bp);
        !          1259: }
        !          1260: 
        !          1261: /*
        !          1262:  * FsmRecvTimeRemain()
        !          1263:  */
        !          1264: 
        !          1265: static void
        !          1266: FsmRecvTimeRemain(Fsm fp, FsmHeader lhp, Mbuf bp)
        !          1267: {
        !          1268:     bp = FsmCheckMagic(fp, bp);
        !          1269:     if (bp) {
        !          1270:        u_int32_t       remain = 0;
        !          1271:        mbcopy(bp, 0, &remain, sizeof(remain));
        !          1272:        remain = ntohl(remain);
        !          1273:        Log(fp->log, ("[%s]   %u seconds remain", Pref(fp), remain));
        !          1274:     }
        !          1275:     if (fp->type->RecvTimeRemain)
        !          1276:        (*fp->type->RecvTimeRemain)(fp, bp);
        !          1277:     mbfree(bp);
        !          1278: }
        !          1279: 
        !          1280: /*
        !          1281:  * FsmRecvResetReq()
        !          1282:  */
        !          1283: 
        !          1284: static void
        !          1285: FsmRecvResetReq(Fsm fp, FsmHeader lhp, Mbuf bp)
        !          1286: {
        !          1287:   if (fp->type->RecvResetReq)
        !          1288:     (*fp->type->RecvResetReq)(fp, lhp->id, bp);
        !          1289:   mbfree(bp);
        !          1290: }
        !          1291: 
        !          1292: /*
        !          1293:  * FsmRecvResetAck()
        !          1294:  */
        !          1295: 
        !          1296: static void
        !          1297: FsmRecvResetAck(Fsm fp, FsmHeader lhp, Mbuf bp)
        !          1298: {
        !          1299:   if (fp->type->RecvResetAck)
        !          1300:     (*fp->type->RecvResetAck)(fp, lhp->id, bp);
        !          1301:   mbfree(bp);
        !          1302: }
        !          1303: 
        !          1304: /*
        !          1305:  * FsmLayerUp()
        !          1306:  */
        !          1307: 
        !          1308: static void
        !          1309: FsmLayerUp(Fsm fp)
        !          1310: {
        !          1311:   Log(fp->log2, ("[%s] %s: LayerUp", Pref(fp), Fsm(fp)));
        !          1312:   if (fp->type->LayerUp)
        !          1313:     (*fp->type->LayerUp)(fp);
        !          1314: }
        !          1315: 
        !          1316: /*
        !          1317:  * FsmLayerDown()
        !          1318:  */
        !          1319: 
        !          1320: static void
        !          1321: FsmLayerDown(Fsm fp)
        !          1322: {
        !          1323:   Log(fp->log2, ("[%s] %s: LayerDown", Pref(fp), Fsm(fp)));
        !          1324:   if (fp->type->LayerDown)
        !          1325:     (*fp->type->LayerDown)(fp);
        !          1326: }
        !          1327: 
        !          1328: /*
        !          1329:  * FsmLayerStart()
        !          1330:  */
        !          1331: 
        !          1332: static void
        !          1333: FsmLayerStart(Fsm fp)
        !          1334: {
        !          1335:   Log(fp->log2, ("[%s] %s: LayerStart", Pref(fp), Fsm(fp)));
        !          1336:   if (fp->type->LayerStart)
        !          1337:     (*fp->type->LayerStart)(fp);
        !          1338: }
        !          1339: 
        !          1340: /*
        !          1341:  * FsmLayerFinish()
        !          1342:  */
        !          1343: 
        !          1344: static void
        !          1345: FsmLayerFinish(Fsm fp)
        !          1346: {
        !          1347:   Log(fp->log2, ("[%s] %s: LayerFinish", Pref(fp), Fsm(fp)));
        !          1348:   if (fp->type->LayerFinish)
        !          1349:     (*fp->type->LayerFinish)(fp);
        !          1350: }
        !          1351: 
        !          1352: /*
        !          1353:  * FsmCheckMagic()
        !          1354:  */
        !          1355: 
        !          1356: static Mbuf
        !          1357: FsmCheckMagic(Fsm fp, Mbuf bp)
        !          1358: {
        !          1359:   u_int32_t    peer_magic;
        !          1360:   u_int32_t    peer_magic_ought;
        !          1361: 
        !          1362:   /* Read magic number */
        !          1363:   bp = mbread(bp, &peer_magic, sizeof(peer_magic));
        !          1364:   peer_magic = ntohl(peer_magic);
        !          1365: 
        !          1366:   /* What should magic number be? */
        !          1367:   if (PROT_LINK_LAYER(fp->type->proto))
        !          1368:     peer_magic_ought = ((Link)(fp->arg))->lcp.peer_magic;
        !          1369:   else
        !          1370:     peer_magic_ought = 0;
        !          1371: 
        !          1372:   /* Verify */
        !          1373:   if (fp->conf.check_magic && peer_magic != 0
        !          1374:      && peer_magic != peer_magic_ought) {
        !          1375:     Log(fp->log, ("[%s] %s: magic number is wrong: 0x%08x != 0x%08x",
        !          1376:       Pref(fp), Fsm(fp), peer_magic, peer_magic_ought));
        !          1377:     FsmFailure(fp, FAIL_RECD_BADMAGIC);
        !          1378:   }
        !          1379:   return(bp);
        !          1380: }
        !          1381: 
        !          1382: /*
        !          1383:  * FsmEchoTimeout()
        !          1384:  */
        !          1385: 
        !          1386: static void
        !          1387: FsmEchoTimeout(void *arg)
        !          1388: {
        !          1389:     Fsm                        const fp = (Fsm) arg;
        !          1390:     Bund               b;
        !          1391:     Link               l;
        !          1392:     struct ng_ppp_link_stat    oldStats;
        !          1393: 
        !          1394:     if (fp->type->link_layer) {
        !          1395:        l = (Link)fp->arg;
        !          1396:        b = l->bund;
        !          1397:     } else {
        !          1398:        b = (Bund)fp->arg;
        !          1399:        l = NULL;
        !          1400:     }
        !          1401:     
        !          1402:     if (!b) {
        !          1403:        /* We can't get link stat without bundle present */
        !          1404:        return;
        !          1405:     }
        !          1406: 
        !          1407:     /* See if there was any traffic since last time */
        !          1408:     oldStats = fp->idleStats;
        !          1409:     NgFuncGetStats(b, l ?
        !          1410:        l->bundleIndex : NG_PPP_BUNDLE_LINKNUM, &fp->idleStats);
        !          1411:     if (fp->idleStats.recvFrames > oldStats.recvFrames)
        !          1412:        fp->quietCount = 0;
        !          1413:     else
        !          1414:        fp->quietCount++;
        !          1415: 
        !          1416:     /* See if peer hasn't responded for too many requests */
        !          1417:     switch (fp->quietCount) {
        !          1418: 
        !          1419:     /* Peer failed to reply to previous echo request */
        !          1420:     default:
        !          1421:         Log(LG_ECHO|fp->log,
        !          1422:            ("[%s] %s: no reply to %d echo request(s)",
        !          1423:            Pref(fp), Fsm(fp), fp->quietCount - 1));
        !          1424: 
        !          1425:         /* Has peer failed to reply for maximum allowable interval? */
        !          1426:         if (fp->quietCount * fp->conf.echo_int >= fp->conf.echo_max) {
        !          1427:            TimerStop(&fp->echoTimer);
        !          1428:            FsmFailure(fp, FAIL_ECHO_TIMEOUT);
        !          1429:            break;
        !          1430:         }
        !          1431:         /* fall through */
        !          1432:     case 1:    /* one interval of silence elapsed; send first echo request */
        !          1433:         FsmSendEchoReq(fp, NULL);
        !          1434:         /* fall through */
        !          1435:     case 0:
        !          1436:         break;
        !          1437:     }
        !          1438: }
        !          1439: 
        !          1440: /*
        !          1441:  * FsmInput()
        !          1442:  *
        !          1443:  * Deal with an incoming packet for FSM pointed to by "fp"
        !          1444:  */
        !          1445: 
        !          1446: void
        !          1447: FsmInput(Fsm fp, Mbuf bp)
        !          1448: {
        !          1449:     int                        log, recd_len, length;
        !          1450:     struct fsmheader   hdr;
        !          1451: 
        !          1452:     /* Check for runt frames; discard them */
        !          1453:     if ((recd_len = MBLEN(bp)) < sizeof(hdr)) {
        !          1454:        Log(fp->log, ("[%s] %s: runt packet: %d bytes", Pref(fp), Fsm(fp), recd_len));
        !          1455:        mbfree(bp);
        !          1456:        return;
        !          1457:     }
        !          1458: 
        !          1459:     /* Read in the header */
        !          1460:     bp = mbread(bp, &hdr, sizeof(hdr));
        !          1461:     length = ntohs(hdr.length);
        !          1462: 
        !          1463:     /* Make sure length is sensible; discard otherwise */
        !          1464:     if (length < sizeof(hdr) || length > recd_len) {
        !          1465:        Log(fp->log, ("[%s] %s: bad length: says %d, rec'd %d",
        !          1466:            Pref(fp), Fsm(fp), length, recd_len));
        !          1467:        mbfree(bp);
        !          1468:        return;
        !          1469:     }
        !          1470: 
        !          1471:     /* Truncate off any padding bytes */
        !          1472:     if (length < recd_len)
        !          1473:        bp = mbtrunc(bp, length - sizeof(hdr));
        !          1474: 
        !          1475:     /* Check for a valid code byte -- if not, send code-reject */
        !          1476:     if ((hdr.code >= NUM_FSM_CODES) ||
        !          1477:            (((1 << hdr.code) & fp->type->known_codes) == 0)) { /* RUC */
        !          1478:        Log(fp->log, ("[%s] %s: unknown code %d", Pref(fp), Fsm(fp), hdr.code));
        !          1479:        FsmOutputMbuf(fp, CODE_CODEREJ, fp->rejid++, bp);
        !          1480:        return;
        !          1481:     }
        !          1482: 
        !          1483:     /* Log it */
        !          1484:     if (hdr.code == CODE_ECHOREQ || hdr.code == CODE_ECHOREP)
        !          1485:        log = LG_ECHO;
        !          1486:     else if (hdr.code == CODE_RESETREQ || hdr.code == CODE_RESETACK)
        !          1487:        log = fp->log2;
        !          1488:     else
        !          1489:        log = fp->log;
        !          1490:     Log(log, ("[%s] %s: rec'd %s #%d (%s)",
        !          1491:        Pref(fp), Fsm(fp), FsmCodeName(hdr.code), (int) hdr.id,
        !          1492:        FsmStateName(fp->state)));
        !          1493: 
        !          1494:     /* Do whatever */
        !          1495:     (*FsmCodes[hdr.code].action)(fp, &hdr, bp);
        !          1496: }
        !          1497: 
        !          1498: /*
        !          1499:  * FsmConfValue()
        !          1500:  *
        !          1501:  * Write in a configuration item with "len" bytes of information.
        !          1502:  * Special cases: length -2 or -4 means convert to network byte order.
        !          1503:  */
        !          1504: 
        !          1505: u_char *
        !          1506: FsmConfValue(u_char *cp, int type, int len, const void *data)
        !          1507: {
        !          1508:   u_char       *bytes = (u_char *) data;
        !          1509:   u_int16_t    sv;
        !          1510:   u_int32_t    lv;
        !          1511: 
        !          1512:   /* Special cases */
        !          1513:   switch (len) {
        !          1514:     case -2:
        !          1515:       len = 2;
        !          1516:       sv = htons(*((u_int16_t *) data));
        !          1517:       bytes = (u_char *) &sv;
        !          1518:       break;
        !          1519:     case -4:
        !          1520:       len = 4;
        !          1521:       lv = htonl(*((u_int32_t *) data));
        !          1522:       bytes = (u_char *) &lv;
        !          1523:       break;
        !          1524:     default:
        !          1525:       break;
        !          1526:   }
        !          1527: 
        !          1528:   /* Add header and data */
        !          1529:   *cp++ = type;
        !          1530:   *cp++ = len + 2;
        !          1531:   while (len-- > 0)
        !          1532:     *cp++ = *bytes++;
        !          1533: 
        !          1534:   /* Done */
        !          1535:   return(cp);
        !          1536: }
        !          1537: 
        !          1538: /*
        !          1539:  * FsmExtractOptions()
        !          1540:  *
        !          1541:  * Extract options from a config packet
        !          1542:  */
        !          1543: 
        !          1544: static int
        !          1545: FsmExtractOptions(Fsm fp, u_char *data, int dlen, FsmOption opts, int max)
        !          1546: {
        !          1547:   int  num;
        !          1548: 
        !          1549:   for (num = 0; dlen >= 2 && num < max; num++) {
        !          1550:     FsmOption  const opt = &opts[num];
        !          1551: 
        !          1552:     opt->type = data[0];
        !          1553:     opt->len = data[1];
        !          1554:     opt->data = &data[2];
        !          1555:     if (opt->len < 2 || opt->len > dlen)
        !          1556:       break;
        !          1557:     data += opt->len;
        !          1558:     dlen -= opt->len;
        !          1559:   }
        !          1560:   if (dlen != 0)
        !          1561:     LogDumpBuf(LG_ERR, data, dlen,
        !          1562:       "[%s] %s: %d extra garbage bytes in config packet", Pref(fp), Fsm(fp), dlen);
        !          1563:   return(num);
        !          1564: }
        !          1565: 
        !          1566: /*
        !          1567:  * FsmFindOption()
        !          1568:  */
        !          1569: 
        !          1570: FsmOptInfo
        !          1571: FsmFindOptInfo(FsmOptInfo list, u_char type)
        !          1572: {
        !          1573:   for (; list->name; list++)
        !          1574:     if (list->type == type)
        !          1575:       return(list);
        !          1576:   return(NULL);
        !          1577: }
        !          1578: 
        !          1579: /*
        !          1580:  * FsmDecodeBuffer()
        !          1581:  */
        !          1582: 
        !          1583: static void
        !          1584: FsmDecodeBuffer(Fsm fp, u_char *buf, int size, int mode)
        !          1585: {
        !          1586:   struct fsmoption     opts[FSM_MAX_OPTS];
        !          1587:   int                  num;
        !          1588: 
        !          1589:   if (mode == MODE_REQ)
        !          1590:     gAckSize = gNakSize = gRejSize = 0;
        !          1591:   num = FsmExtractOptions(fp, buf, size, opts, FSM_MAX_OPTS);
        !          1592:   (*fp->type->DecodeConfig)(fp, opts, num, mode);
        !          1593: }
        !          1594: 
        !          1595: /*
        !          1596:  * FsmAck()
        !          1597:  */
        !          1598: 
        !          1599: void
        !          1600: FsmAck(Fsm fp, const struct fsmoption *opt)
        !          1601: {
        !          1602:   if (gAckSize + opt->len > sizeof(gAckBuf)) {
        !          1603:     Log(LG_ERR, ("[%s] %s: %s buffer full", Pref(fp), Fsm(fp), "ack"));
        !          1604:     return;
        !          1605:   }
        !          1606:   memcpy(&gAckBuf[gAckSize], opt, 2);
        !          1607:   memcpy(&gAckBuf[gAckSize + 2], opt->data, opt->len - 2);
        !          1608:   gAckSize += opt->len;
        !          1609: }
        !          1610: 
        !          1611: /*
        !          1612:  * FsmNak()
        !          1613:  */
        !          1614: 
        !          1615: void
        !          1616: FsmNak(Fsm fp, const struct fsmoption *opt)
        !          1617: {
        !          1618:   if (gNakSize + opt->len > sizeof(gNakBuf)) {
        !          1619:     Log(LG_ERR, ("[%s] %s: %s buffer full", Pref(fp), Fsm(fp), "nak"));
        !          1620:     return;
        !          1621:   }
        !          1622:   memcpy(&gNakBuf[gNakSize], opt, 2);
        !          1623:   memcpy(&gNakBuf[gNakSize + 2], opt->data, opt->len - 2);
        !          1624:   gNakSize += opt->len;
        !          1625: }
        !          1626: 
        !          1627: /*
        !          1628:  * FsmRej()
        !          1629:  */
        !          1630: 
        !          1631: void
        !          1632: FsmRej(Fsm fp, const struct fsmoption *opt)
        !          1633: {
        !          1634:   if (gRejSize + opt->len > sizeof(gRejBuf)) {
        !          1635:     Log(LG_ERR, ("[%s] %s: %s buffer full", Pref(fp), Fsm(fp), "rej"));
        !          1636:     return;
        !          1637:   }
        !          1638:   memcpy(&gRejBuf[gRejSize], opt, 2);
        !          1639:   memcpy(&gRejBuf[gRejSize + 2], opt->data, opt->len - 2);
        !          1640:   gRejSize += opt->len;
        !          1641: }
        !          1642: 
        !          1643: /*
        !          1644:  * FsmCodeName()
        !          1645:  */
        !          1646: 
        !          1647: const char *
        !          1648: FsmCodeName(int code)
        !          1649: {
        !          1650:   if (code >= 0 && code < NUM_FSM_CODES)
        !          1651:     return (FsmCodes[code].name);
        !          1652:   return ("UNKNOWN");
        !          1653: }
        !          1654: 
        !          1655: /*
        !          1656:  * FsmStateName()
        !          1657:  */
        !          1658: 
        !          1659: const char *
        !          1660: FsmStateName(enum fsm_state state)
        !          1661: {
        !          1662:   switch (state) {
        !          1663:     case ST_INITIAL:   return "Initial";
        !          1664:     case ST_STARTING:  return "Starting";
        !          1665:     case ST_CLOSED:    return "Closed";
        !          1666:     case ST_STOPPED:   return "Stopped";
        !          1667:     case ST_CLOSING:   return "Closing";
        !          1668:     case ST_STOPPING:  return "Stopping";
        !          1669:     case ST_REQSENT:   return "Req-Sent";
        !          1670:     case ST_ACKRCVD:   return "Ack-Rcvd";
        !          1671:     case ST_ACKSENT:   return "Ack-Sent";
        !          1672:     case ST_OPENED:    return "Opened";
        !          1673:   }
        !          1674:   return "???";
        !          1675: }
        !          1676: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>