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

1.1     ! misho       1: 
        !             2: /*
        !             3:  * lcp.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 "lcp.h"
        !            16: #include "fsm.h"
        !            17: #include "mp.h"
        !            18: #include "phys.h"
        !            19: #include "link.h"
        !            20: #include "msg.h"
        !            21: #include "util.h"
        !            22: 
        !            23: /*
        !            24:  * DEFINITIONS
        !            25:  */
        !            26: 
        !            27:   #define LCP_ECHO_INTERVAL    5       /* Enable keep alive by default */
        !            28:   #define LCP_ECHO_TIMEOUT     40
        !            29: 
        !            30:   #define LCP_KNOWN_CODES      (   (1 << CODE_CONFIGREQ)       \
        !            31:                                  | (1 << CODE_CONFIGACK)       \
        !            32:                                  | (1 << CODE_CONFIGNAK)       \
        !            33:                                  | (1 << CODE_CONFIGREJ)       \
        !            34:                                  | (1 << CODE_TERMREQ)         \
        !            35:                                  | (1 << CODE_TERMACK)         \
        !            36:                                  | (1 << CODE_CODEREJ)         \
        !            37:                                  | (1 << CODE_PROTOREJ)        \
        !            38:                                  | (1 << CODE_ECHOREQ)         \
        !            39:                                  | (1 << CODE_ECHOREP)         \
        !            40:                                  | (1 << CODE_DISCREQ)         \
        !            41:                                  | (1 << CODE_IDENT)           \
        !            42:                                  | (1 << CODE_TIMEREM)         )
        !            43: 
        !            44:   #define LCP_PEER_REJECTED(p,x)       ((p)->peer_reject & (1<<x))
        !            45:   #define LCP_PEER_REJ(p,x)    do{(p)->peer_reject |= (1<<(x));}while(0)
        !            46:   #define LCP_PEER_UNREJ(p,x)  do{(p)->peer_reject &= ~(1<<(x));}while(0)
        !            47: 
        !            48: /*
        !            49:  * INTERNAL FUNCTIONS
        !            50:  */
        !            51: 
        !            52:   static void  LcpConfigure(Fsm fp);
        !            53:   static void  LcpNewState(Fsm fp, enum fsm_state old, enum fsm_state new);
        !            54:   static void  LcpNewPhase(Link l, enum lcp_phase new);
        !            55: 
        !            56:   static u_char        *LcpBuildConfigReq(Fsm fp, u_char *cp);
        !            57:   static void  LcpDecodeConfig(Fsm fp, FsmOption list, int num, int mode);
        !            58:   static void  LcpLayerDown(Fsm fp);
        !            59:   static void  LcpLayerStart(Fsm fp);
        !            60:   static void  LcpLayerFinish(Fsm fp);
        !            61:   static int   LcpRecvProtoRej(Fsm fp, int proto, Mbuf bp);
        !            62:   static void  LcpFailure(Fsm fp, enum fsmfail reason);
        !            63:   static const struct fsmoption        *LcpAuthProtoNak(ushort proto, u_char alg);
        !            64:   static short         LcpFindAuthProto(ushort proto, u_char alg);
        !            65:   static void  LcpRecvIdent(Fsm fp, Mbuf bp);
        !            66:   static void  LcpStopActivity(Link l);
        !            67: 
        !            68: /*
        !            69:  * INTERNAL VARIABLES
        !            70:  */
        !            71: 
        !            72:   static const struct fsmoptinfo       gLcpConfOpts[] = {
        !            73:     { "VENDOR", TY_VENDOR, 4, 255, TRUE },
        !            74:     { "MRU", TY_MRU, 2, 2, TRUE },
        !            75:     { "ACCMAP", TY_ACCMAP, 4, 4, TRUE },
        !            76:     { "AUTHPROTO", TY_AUTHPROTO, 2, 255, TRUE },
        !            77:     { "QUALPROTO", TY_QUALPROTO, 0, 0, FALSE },
        !            78:     { "MAGICNUM", TY_MAGICNUM, 4, 4, TRUE },
        !            79:     { "RESERVED", TY_RESERVED, 0, 0, FALSE }, /* DEPRECATED */
        !            80:     { "PROTOCOMP", TY_PROTOCOMP, 0, 0, TRUE },
        !            81:     { "ACFCOMP", TY_ACFCOMP, 0, 0, TRUE },
        !            82:     { "FCSALT", TY_FCSALT, 0, 0, FALSE },
        !            83:     { "SDP", TY_SDP, 0, 0, FALSE },
        !            84:     { "NUMMODE", TY_NUMMODE, 0, 0, FALSE },
        !            85:     { "MULTILINK", TY_MULTILINK, 0, 0, FALSE }, /* DEPRECATED */
        !            86:     { "CALLBACK", TY_CALLBACK, 1, 255, TRUE },
        !            87:     { "CONNECTTIME", TY_CONNECTTIME, 0, 0, FALSE }, /* DEPRECATED */
        !            88:     { "COMPFRAME", TY_COMPFRAME, 0, 0, FALSE }, /* DEPRECATED */
        !            89:     { "NDS", TY_NDS, 0, 0, FALSE }, /* DEPRECATED */
        !            90:     { "MP MRRU", TY_MRRU, 2, 2, TRUE },
        !            91:     { "MP SHORTSEQ", TY_SHORTSEQNUM, 0, 0, TRUE },
        !            92:     { "ENDPOINTDISC", TY_ENDPOINTDISC, 1, 255, TRUE },
        !            93:     { "PROPRIETARY", TY_PROPRIETARY, 0, 0, FALSE },
        !            94:     { "DCEIDENTIFIER", TY_DCEIDENTIFIER, 0, 0, FALSE },
        !            95:     { "MULTILINKPLUS", TY_MULTILINKPLUS, 0, 0, FALSE },
        !            96:     { "BACP", TY_BACP, 0, 0, FALSE },
        !            97:     { "LCPAUTHOPT", TY_LCPAUTHOPT, 0, 0, FALSE },
        !            98:     { "COBS", TY_COBS, 0, 0, FALSE },
        !            99:     { "PREFIXELISION", TY_PREFIXELISION, 0, 0, FALSE },
        !           100:     { "MULTILINKHEADERFMT", TY_MULTILINKHEADERFMT, 0, 0, FALSE },
        !           101:     { "INTERNAT", TY_INTERNAT, 0, 0, FALSE },
        !           102:     { "SDATALINKSONET", TY_SDATALINKSONET, 0, 0, FALSE },
        !           103:     { NULL }
        !           104:   };
        !           105: 
        !           106:   static struct fsmtype gLcpFsmType = {
        !           107:     "LCP",                     /* Name of protocol */
        !           108:     PROTO_LCP,                 /* Protocol Number */
        !           109:     LCP_KNOWN_CODES,
        !           110:     TRUE,
        !           111:     LG_LCP, LG_LCP2,
        !           112:     LcpNewState,
        !           113:     NULL,
        !           114:     LcpLayerDown,
        !           115:     LcpLayerStart,
        !           116:     LcpLayerFinish,
        !           117:     LcpBuildConfigReq,
        !           118:     LcpDecodeConfig,
        !           119:     LcpConfigure,
        !           120:     NULL,
        !           121:     NULL,
        !           122:     NULL,
        !           123:     NULL,
        !           124:     LcpRecvProtoRej,
        !           125:     LcpFailure,
        !           126:     NULL,
        !           127:     NULL,
        !           128:     LcpRecvIdent,
        !           129:   };
        !           130: 
        !           131:   /* List of possible Authentication Protocols */
        !           132:   static struct lcpauthproto gLcpAuthProtos[] = {
        !           133:     {
        !           134:       PROTO_PAP,
        !           135:       0,
        !           136:       LINK_CONF_PAP,
        !           137:     },
        !           138:     {
        !           139:       PROTO_CHAP,
        !           140:       CHAP_ALG_MD5,
        !           141:       LINK_CONF_CHAPMD5
        !           142:     },
        !           143:     {
        !           144:       PROTO_CHAP,
        !           145:       CHAP_ALG_MSOFT,
        !           146:       LINK_CONF_CHAPMSv1
        !           147:     },
        !           148:     {
        !           149:       PROTO_CHAP,
        !           150:       CHAP_ALG_MSOFTv2,
        !           151:       LINK_CONF_CHAPMSv2
        !           152:     },
        !           153:     {
        !           154:       PROTO_EAP,
        !           155:       0,
        !           156:       LINK_CONF_EAP
        !           157:     }
        !           158: 
        !           159:   };
        !           160: 
        !           161:   static const char *PhaseNames[] = {
        !           162:     "DEAD",
        !           163:     "ESTABLISH",
        !           164:     "AUTHENTICATE",
        !           165:     "NETWORK",
        !           166:     "TERMINATE",
        !           167:   };
        !           168: 
        !           169: /*
        !           170:  * LcpInit()
        !           171:  */
        !           172: 
        !           173: void
        !           174: LcpInit(Link l)
        !           175: {
        !           176:   LcpState     const lcp = &l->lcp;
        !           177: 
        !           178:   memset(lcp, 0, sizeof(*lcp));
        !           179:   FsmInit(&lcp->fsm, &gLcpFsmType, l);
        !           180:   lcp->fsm.conf.echo_int = LCP_ECHO_INTERVAL;
        !           181:   lcp->fsm.conf.echo_max = LCP_ECHO_TIMEOUT;
        !           182:   lcp->phase = PHASE_DEAD;
        !           183:   
        !           184:   AuthInit(l);
        !           185: }
        !           186: 
        !           187: /*
        !           188:  * LcpInst()
        !           189:  */
        !           190: 
        !           191: void
        !           192: LcpInst(Link l, Link lt)
        !           193: {
        !           194:   LcpState     const lcp = &l->lcp;
        !           195: 
        !           196:   memcpy(lcp, &lt->lcp, sizeof(*lcp));
        !           197:   FsmInst(&lcp->fsm, &lt->lcp.fsm, l);
        !           198:   AuthInst(&lcp->auth, &lt->lcp.auth);
        !           199: }
        !           200: 
        !           201: /*
        !           202:  * LcpShutdown()
        !           203:  */
        !           204: 
        !           205: void
        !           206: LcpShutdown(Link l)
        !           207: {
        !           208:     AuthShutdown(l);
        !           209: }
        !           210: 
        !           211: /*
        !           212:  * LcpConfigure()
        !           213:  */
        !           214: 
        !           215: static void
        !           216: LcpConfigure(Fsm fp)
        !           217: {
        !           218:     Link       l = (Link)fp->arg;
        !           219:     LcpState   const lcp = &l->lcp;
        !           220:     short      i;
        !           221: 
        !           222:     /* FSM stuff */
        !           223:     lcp->fsm.conf.passive = Enabled(&l->conf.options, LINK_CONF_PASSIVE);
        !           224:     lcp->fsm.conf.check_magic =
        !           225:        Enabled(&l->conf.options, LINK_CONF_CHECK_MAGIC);
        !           226:     lcp->peer_reject = 0;
        !           227: 
        !           228:     /* Initialize normal LCP stuff */
        !           229:     lcp->peer_mru = l->conf.mtu;
        !           230:     lcp->want_mru = l->conf.mru;
        !           231:     if (l->type && (lcp->want_mru > l->type->mru))
        !           232:        lcp->want_mru = l->type->mru;
        !           233:     lcp->peer_accmap = 0xffffffff;
        !           234:     lcp->want_accmap = l->conf.accmap;
        !           235:     lcp->peer_acfcomp = FALSE;
        !           236:     lcp->want_acfcomp = Enabled(&l->conf.options, LINK_CONF_ACFCOMP);
        !           237:     lcp->peer_protocomp = FALSE;
        !           238:     lcp->want_protocomp = Enabled(&l->conf.options, LINK_CONF_PROTOCOMP);
        !           239:     lcp->peer_magic = 0;
        !           240:     lcp->want_magic = Enabled(&l->conf.options,
        !           241:        LINK_CONF_MAGICNUM) ? GenerateMagic() : 0;
        !           242:     if (l->originate == LINK_ORIGINATE_LOCAL)
        !           243:        lcp->want_callback = Enabled(&l->conf.options, LINK_CONF_CALLBACK);
        !           244:     else
        !           245:        lcp->want_callback = FALSE;
        !           246: 
        !           247:     /* Authentication stuff */
        !           248:     lcp->peer_auth = 0;
        !           249:     lcp->want_auth = 0;
        !           250:     lcp->peer_alg = 0;
        !           251:     lcp->want_alg = 0;
        !           252:     lcp->peer_ident[0] = 0;
        !           253: 
        !           254:     memset(lcp->want_protos, 0, sizeof(lcp->want_protos));
        !           255:     /* fill my list of possible auth-protos, most to least secure */
        !           256:     /* prefer MS-CHAP to others to get encryption keys */
        !           257:     lcp->want_protos[0] = &gLcpAuthProtos[LINK_CONF_CHAPMSv2];
        !           258:     lcp->want_protos[1] = &gLcpAuthProtos[LINK_CONF_CHAPMSv1];
        !           259:     lcp->want_protos[2] = &gLcpAuthProtos[LINK_CONF_CHAPMD5];
        !           260:     lcp->want_protos[3] = &gLcpAuthProtos[LINK_CONF_PAP];
        !           261:     lcp->want_protos[4] = &gLcpAuthProtos[LINK_CONF_EAP];
        !           262: 
        !           263:     /* Use the same list for the MODE_REQ */
        !           264:     memcpy(lcp->peer_protos, lcp->want_protos, sizeof(lcp->peer_protos));
        !           265: 
        !           266:     for (i = 0; i < LCP_NUM_AUTH_PROTOS; i++) {
        !           267:        if (Enabled(&l->conf.options, lcp->want_protos[i]->conf) && lcp->want_auth == 0) {
        !           268:            lcp->want_auth = lcp->want_protos[i]->proto;
        !           269:            lcp->want_alg = lcp->want_protos[i]->alg;
        !           270:            /* avoid re-requesting this proto, if it was nak'd by the peer */
        !           271:            lcp->want_protos[i] = NULL;
        !           272:        } else if (!Enabled(&l->conf.options, lcp->want_protos[i]->conf)) {
        !           273:            /* don't request disabled Protos */
        !           274:            lcp->want_protos[i] = NULL;
        !           275:        }
        !           276: 
        !           277:        /* remove all denied protos */
        !           278:        if (!Acceptable(&l->conf.options, lcp->peer_protos[i]->conf))
        !           279:            lcp->peer_protos[i] = NULL;
        !           280:     }
        !           281: 
        !           282:     /* Multi-link stuff */
        !           283:     lcp->peer_mrru = 0;
        !           284:     lcp->peer_shortseq = FALSE;
        !           285:     if (Enabled(&l->conf.options, LINK_CONF_MULTILINK)) {
        !           286:        lcp->want_mrru = l->conf.mrru;
        !           287:        lcp->want_shortseq = Enabled(&l->conf.options, LINK_CONF_SHORTSEQ);
        !           288:     } else {
        !           289:        lcp->want_mrru = 0;
        !           290:        lcp->want_shortseq = FALSE;
        !           291:     }
        !           292: 
        !           293:     /* Peer discriminator */
        !           294:     lcp->peer_discrim.class = DISCRIM_CLASS_NULL;
        !           295:     lcp->peer_discrim.len = 0;
        !           296: }
        !           297: 
        !           298: /*
        !           299:  * LcpNewState()
        !           300:  *
        !           301:  * Keep track of phase shifts
        !           302:  */
        !           303: 
        !           304: static void
        !           305: LcpNewState(Fsm fp, enum fsm_state old, enum fsm_state new)
        !           306: {
        !           307:     Link       l = (Link)fp->arg;
        !           308: 
        !           309:   switch (old) {
        !           310:     case ST_INITIAL:                   /* DEAD */
        !           311:     case ST_STARTING:
        !           312:       switch (new) {
        !           313:        case ST_INITIAL:
        !           314:          /* fall through */
        !           315:        case ST_STARTING:
        !           316:          break;
        !           317:        default:
        !           318:          LcpNewPhase(l, PHASE_ESTABLISH);
        !           319:          break;
        !           320:       }
        !           321:       break;
        !           322: 
        !           323:     case ST_CLOSED:                    /* ESTABLISH */
        !           324:     case ST_STOPPED:
        !           325:       switch (new) {
        !           326:        case ST_INITIAL:
        !           327:        case ST_STARTING:
        !           328:          LcpNewPhase(l, PHASE_DEAD);
        !           329:          break;
        !           330:        default:
        !           331:          break;
        !           332:       }
        !           333:       break;
        !           334: 
        !           335:     case ST_CLOSING:                   /* TERMINATE */
        !           336:     case ST_STOPPING:
        !           337:       switch (new) {
        !           338:        case ST_INITIAL:
        !           339:        case ST_STARTING:
        !           340:          LcpNewPhase(l, PHASE_DEAD);
        !           341:          break;
        !           342:        case ST_CLOSED:
        !           343:        case ST_STOPPED:
        !           344:          LcpNewPhase(l, PHASE_ESTABLISH);
        !           345:          break;
        !           346:        default:
        !           347:          break;
        !           348:       }
        !           349:       break;
        !           350: 
        !           351:     case ST_REQSENT:                   /* ESTABLISH */
        !           352:     case ST_ACKRCVD:
        !           353:     case ST_ACKSENT:
        !           354:       switch (new) {
        !           355:        case ST_INITIAL:
        !           356:        case ST_STARTING:
        !           357:          LcpNewPhase(l, PHASE_DEAD);
        !           358:          break;
        !           359:        case ST_CLOSING:
        !           360:        case ST_STOPPING:
        !           361:          LcpNewPhase(l, PHASE_TERMINATE);
        !           362:          break;
        !           363:        case ST_OPENED:
        !           364:          LcpNewPhase(l, PHASE_AUTHENTICATE);
        !           365:          break;
        !           366:        default:
        !           367:          break;
        !           368:       }
        !           369:       break;
        !           370: 
        !           371:     case ST_OPENED:                    /* AUTHENTICATE, NETWORK */
        !           372:       switch (new) {
        !           373:        case ST_STARTING:
        !           374:          LcpNewPhase(l, PHASE_DEAD);
        !           375:          break;
        !           376:        case ST_REQSENT:
        !           377:        case ST_ACKSENT:
        !           378:          LcpNewPhase(l, PHASE_ESTABLISH);
        !           379:          break;
        !           380:        case ST_CLOSING:
        !           381:        case ST_STOPPING:
        !           382:          LcpNewPhase(l, PHASE_TERMINATE);
        !           383:          break;
        !           384:        default:
        !           385:          assert(0);
        !           386:       }
        !           387:       break;
        !           388: 
        !           389:     default:
        !           390:       assert(0);
        !           391:   }
        !           392: 
        !           393:     LinkShutdownCheck(l, new);
        !           394: }
        !           395: 
        !           396: /*
        !           397:  * LcpNewPhase()
        !           398:  */
        !           399: 
        !           400: static void
        !           401: LcpNewPhase(Link l, enum lcp_phase new)
        !           402: {
        !           403:     LcpState   const lcp = &l->lcp;
        !           404:     enum lcp_phase     old = lcp->phase;
        !           405: 
        !           406:     /* Logit */
        !           407:     Log(LG_LCP2, ("[%s] %s: phase shift %s --> %s",
        !           408:        Pref(&lcp->fsm), Fsm(&lcp->fsm), PhaseNames[old], PhaseNames[new]));
        !           409: 
        !           410:     /* Sanity check transition (The picture on RFC 1661 p. 6 is incomplete) */
        !           411:     switch (old) {
        !           412:        case PHASE_DEAD:
        !           413:            assert(new == PHASE_ESTABLISH);
        !           414:            break;
        !           415:     case PHASE_ESTABLISH:
        !           416:         assert(new == PHASE_DEAD
        !           417:          || new == PHASE_TERMINATE
        !           418:          || new == PHASE_AUTHENTICATE);
        !           419:         break;
        !           420:     case PHASE_AUTHENTICATE:
        !           421:         assert(new == PHASE_TERMINATE
        !           422:          || new == PHASE_ESTABLISH
        !           423:          || new == PHASE_NETWORK
        !           424:          || new == PHASE_DEAD);
        !           425:         break;
        !           426:     case PHASE_NETWORK:
        !           427:         assert(new == PHASE_TERMINATE
        !           428:          || new == PHASE_ESTABLISH
        !           429:          || new == PHASE_DEAD);
        !           430:         break;
        !           431:     case PHASE_TERMINATE:
        !           432:         assert(new == PHASE_ESTABLISH
        !           433:          || new == PHASE_DEAD);
        !           434:         break;
        !           435:     default:
        !           436:         assert(0);
        !           437:     }
        !           438: 
        !           439:     /* Change phase now */
        !           440:     lcp->phase = new;
        !           441: 
        !           442:     /* Do whatever for leaving old phase */
        !           443:     switch (old) {
        !           444:     case PHASE_AUTHENTICATE:
        !           445:       if (new != PHASE_NETWORK)
        !           446:        AuthCleanup(l);
        !           447:       break;
        !           448: 
        !           449:     case PHASE_NETWORK:
        !           450:       if (l->joined_bund)
        !           451:        BundLeave(l);
        !           452:       AuthCleanup(l);
        !           453:       break;
        !           454: 
        !           455:     default:
        !           456:       break;
        !           457:     }
        !           458: 
        !           459:     /* Do whatever for entering new phase */
        !           460:     switch (new) {
        !           461:     case PHASE_ESTABLISH:
        !           462:       break;
        !           463: 
        !           464:     case PHASE_AUTHENTICATE:
        !           465:       if (!PhysIsSync(l))
        !           466:         PhysSetAccm(l, lcp->peer_accmap, lcp->want_accmap);
        !           467:       AuthStart(l);
        !           468:       break;
        !           469: 
        !           470:     case PHASE_NETWORK:
        !           471:       /* Send ident string, if configured */
        !           472:       if (l->conf.ident != NULL)
        !           473:        FsmSendIdent(&lcp->fsm, l->conf.ident);
        !           474: 
        !           475:       /* Send Time-Remaining if known */
        !           476:       if (Enabled(&l->conf.options, LINK_CONF_TIMEREMAIN) &&
        !           477:            lcp->auth.params.session_timeout != 0)
        !           478:        FsmSendTimeRemaining(&lcp->fsm, lcp->auth.params.session_timeout);
        !           479: 
        !           480:       /* Join my bundle */
        !           481:       if (!BundJoin(l)) {
        !           482:          Log(LG_LINK|LG_BUND,
        !           483:            ("[%s] link did not validate in bundle",
        !           484:            l->name));
        !           485:          RecordLinkUpDownReason(NULL, l,
        !           486:            0, STR_PROTO_ERR, "%s", STR_MULTI_FAIL);
        !           487:          FsmFailure(&l->lcp.fsm, FAIL_NEGOT_FAILURE);
        !           488:       } else {
        !           489:            /* If link connection complete, reset redial counter */
        !           490:            l->num_redial = 0;
        !           491:       }
        !           492:       break;
        !           493: 
        !           494:     case PHASE_TERMINATE:
        !           495:       break;
        !           496: 
        !           497:     case PHASE_DEAD:
        !           498:         break;
        !           499: 
        !           500:     default:
        !           501:       assert(0);
        !           502:     }
        !           503: }
        !           504: 
        !           505: /*
        !           506:  * LcpAuthResult()
        !           507:  */
        !           508: 
        !           509: void
        !           510: LcpAuthResult(Link l, int success)
        !           511: {
        !           512:   Log(LG_AUTH|LG_LCP, ("[%s] %s: authorization %s",
        !           513:     Pref(&l->lcp.fsm), Fsm(&l->lcp.fsm), success ? "successful" : "failed"));
        !           514:   if (success) {
        !           515:     if (l->lcp.phase != PHASE_NETWORK)
        !           516:       LcpNewPhase(l, PHASE_NETWORK);
        !           517:   } else {
        !           518:     RecordLinkUpDownReason(NULL, l, 0, STR_LOGIN_FAIL,
        !           519:       "%s", STR_PPP_AUTH_FAILURE);
        !           520:     FsmFailure(&l->lcp.fsm, FAIL_NEGOT_FAILURE);
        !           521:   }
        !           522: }
        !           523: 
        !           524: /*
        !           525:  * LcpStat()
        !           526:  */
        !           527: 
        !           528: int
        !           529: LcpStat(Context ctx, int ac, char *av[], void *arg)
        !           530: {
        !           531:     Link       const l = ctx->lnk;
        !           532:     LcpState   const lcp = &l->lcp;
        !           533:     char       buf[64];
        !           534: 
        !           535:     Printf("%s [%s]\r\n", lcp->fsm.type->name, FsmStateName(lcp->fsm.state));
        !           536: 
        !           537:     Printf("Self:\r\n");
        !           538:     Printf(    "\tMRU      : %d bytes\r\n"
        !           539:                "\tMAGIC    : 0x%08x\r\n"
        !           540:                "\tACCMAP   : 0x%08x\r\n"
        !           541:                "\tACFCOMP  : %s\r\n"
        !           542:                "\tPROTOCOMP: %s\r\n"
        !           543:                "\tAUTHTYPE : %s\r\n",
        !           544:        (int) lcp->want_mru,
        !           545:        (int) lcp->want_magic,
        !           546:        (int) lcp->want_accmap,
        !           547:        lcp->want_acfcomp ? "Yes" : "No",
        !           548:        lcp->want_protocomp ? "Yes" : "No",
        !           549:        (lcp->want_auth)?ProtoName(lcp->want_auth):"none");
        !           550: 
        !           551:     if (lcp->want_mrru) {
        !           552:        Printf( "\tMRRU     : %d bytes\r\n", (int) lcp->want_mrru);
        !           553:        Printf( "\tSHORTSEQ : %s\r\n", lcp->want_shortseq ? "Yes" : "No");
        !           554:        Printf( "\tENDPOINTDISC: %s\r\n", MpDiscrimText(&self_discrim, buf, sizeof(buf)));
        !           555:     }
        !           556:     if (l->conf.ident)
        !           557:        Printf( "\tIDENT    : %s\r\n", l->conf.ident);
        !           558: 
        !           559:     Printf("Peer:\r\n");
        !           560:     Printf(    "\tMRU      : %d bytes\r\n"
        !           561:                "\tMAGIC    : 0x%08x\r\n"
        !           562:                "\tACCMAP   : 0x%08x\r\n"
        !           563:                "\tACFCOMP  : %s\r\n"
        !           564:                "\tPROTOCOMP: %s\r\n"
        !           565:                "\tAUTHTYPE : %s\r\n",
        !           566:        (int) lcp->peer_mru,
        !           567:         (int) lcp->peer_magic,
        !           568:        (int) lcp->peer_accmap,
        !           569:         lcp->peer_acfcomp ? "Yes" : "No",
        !           570:         lcp->peer_protocomp ? "Yes" : "No",
        !           571:         (lcp->peer_auth)?ProtoName(lcp->peer_auth):"none");
        !           572: 
        !           573:     if (lcp->peer_mrru) {
        !           574:        Printf( "\tMRRU     : %d bytes\r\n", (int) lcp->peer_mrru);
        !           575:        Printf( "\tSHORTSEQ : %s\r\n", lcp->peer_shortseq ? "Yes" : "No");
        !           576:        Printf( "\tENDPOINTDISC: %s\r\n", MpDiscrimText(&lcp->peer_discrim, buf, sizeof(buf)));
        !           577:     }
        !           578:     if (lcp->peer_ident[0])
        !           579:        Printf( "\tIDENT    : %s\r\n", lcp->peer_ident);
        !           580: 
        !           581:     return(0);
        !           582: }
        !           583: 
        !           584: /*
        !           585:  * LcpBuildConfigReq()
        !           586:  */
        !           587: 
        !           588: static u_char *
        !           589: LcpBuildConfigReq(Fsm fp, u_char *cp)
        !           590: {
        !           591:     Link       l = (Link)fp->arg;
        !           592:     LcpState   const lcp = &l->lcp;
        !           593: 
        !           594:     /* Standard stuff */
        !           595:     if (lcp->want_acfcomp && !LCP_PEER_REJECTED(lcp, TY_ACFCOMP))
        !           596:        cp = FsmConfValue(cp, TY_ACFCOMP, 0, NULL);
        !           597:     if (lcp->want_protocomp && !LCP_PEER_REJECTED(lcp, TY_PROTOCOMP))
        !           598:        cp = FsmConfValue(cp, TY_PROTOCOMP, 0, NULL);
        !           599:     if ((!PhysIsSync(l)) && (!LCP_PEER_REJECTED(lcp, TY_ACCMAP)))
        !           600:        cp = FsmConfValue(cp, TY_ACCMAP, -4, &lcp->want_accmap);
        !           601:     if (!LCP_PEER_REJECTED(lcp, TY_MRU))
        !           602:        cp = FsmConfValue(cp, TY_MRU, -2, &lcp->want_mru);
        !           603:     if (lcp->want_magic && !LCP_PEER_REJECTED(lcp, TY_MAGICNUM))
        !           604:        cp = FsmConfValue(cp, TY_MAGICNUM, -4, &lcp->want_magic);
        !           605:     if (lcp->want_callback && !LCP_PEER_REJECTED(lcp, TY_CALLBACK)) {
        !           606:        struct {
        !           607:            u_char      op;
        !           608:            u_char      data[0];
        !           609:        } s_callback;
        !           610: 
        !           611:        s_callback.op = 0;
        !           612:        cp = FsmConfValue(cp, TY_CALLBACK, 1, &s_callback);
        !           613:     }
        !           614: 
        !           615:     /* Authorization stuff */
        !           616:     switch (lcp->want_auth) {
        !           617:        case PROTO_PAP:
        !           618:        case PROTO_EAP:
        !           619:            cp = FsmConfValue(cp, TY_AUTHPROTO, -2, &lcp->want_auth);
        !           620:            break;
        !           621:        case PROTO_CHAP: {
        !           622:            struct {
        !           623:                u_short want_auth;
        !           624:                u_char  alg;
        !           625:            } s_mdx;
        !           626: 
        !           627:            s_mdx.want_auth = htons(PROTO_CHAP);
        !           628:            s_mdx.alg = lcp->want_alg;
        !           629:            cp = FsmConfValue(cp, TY_AUTHPROTO, 3, &s_mdx);
        !           630:         }
        !           631:         break;
        !           632:     }
        !           633: 
        !           634:     /* Multi-link stuff */
        !           635:     if (Enabled(&l->conf.options, LINK_CONF_MULTILINK)
        !           636:            && !LCP_PEER_REJECTED(lcp, TY_MRRU)) {
        !           637:        cp = FsmConfValue(cp, TY_MRRU, -2, &lcp->want_mrru);
        !           638:        if (lcp->want_shortseq && !LCP_PEER_REJECTED(lcp, TY_SHORTSEQNUM))
        !           639:            cp = FsmConfValue(cp, TY_SHORTSEQNUM, 0, NULL);
        !           640:        if (!LCP_PEER_REJECTED(lcp, TY_ENDPOINTDISC))
        !           641:            cp = FsmConfValue(cp, TY_ENDPOINTDISC, 1 + self_discrim.len, &self_discrim.class);
        !           642:     }
        !           643: 
        !           644:     /* Done */
        !           645:     return(cp);
        !           646: }
        !           647: 
        !           648: static void
        !           649: LcpLayerStart(Fsm fp)
        !           650: {
        !           651:     Link       l = (Link)fp->arg;
        !           652:   
        !           653:     LinkNgInit(l);
        !           654:     if (!TimerStarted(&l->openTimer))
        !           655:        PhysOpen(l);
        !           656: }
        !           657: 
        !           658: static void
        !           659: LcpStopActivity(Link l)
        !           660: {
        !           661:     AuthStop(l);
        !           662: }
        !           663: 
        !           664: static void
        !           665: LcpLayerFinish(Fsm fp)
        !           666: {
        !           667:     Link       l = (Link)fp->arg;
        !           668: 
        !           669:     LcpStopActivity(l);
        !           670:     if (!l->rep) {
        !           671:        PhysClose(l);
        !           672:        LinkNgShutdown(l);
        !           673:     }
        !           674: }
        !           675: 
        !           676: /*
        !           677:  * LcpLayerDown()
        !           678:  */
        !           679: 
        !           680: static void
        !           681: LcpLayerDown(Fsm fp)
        !           682: {
        !           683:     Link       l = (Link)fp->arg;
        !           684:     LcpStopActivity(l);
        !           685: }
        !           686: 
        !           687: void LcpOpen(Link l)
        !           688: {
        !           689:   FsmOpen(&l->lcp.fsm);
        !           690: }
        !           691: 
        !           692: void LcpClose(Link l)
        !           693: {
        !           694:   FsmClose(&l->lcp.fsm);
        !           695: }
        !           696: 
        !           697: void LcpUp(Link l)
        !           698: {
        !           699:   FsmUp(&l->lcp.fsm);
        !           700: }
        !           701: 
        !           702: void LcpDown(Link l)
        !           703: {
        !           704:   FsmDown(&l->lcp.fsm);
        !           705: }
        !           706: 
        !           707: /*
        !           708:  * LcpRecvProtoRej()
        !           709:  */
        !           710: 
        !           711: static int
        !           712: LcpRecvProtoRej(Fsm fp, int proto, Mbuf bp)
        !           713: {
        !           714:     Link       l = (Link)fp->arg;
        !           715:   int  fatal = FALSE;
        !           716:   Fsm  rej = NULL;
        !           717: 
        !           718:   /* Which protocol? */
        !           719:   switch (proto) {
        !           720:     case PROTO_CCP:
        !           721:     case PROTO_COMPD:
        !           722:       rej = l->bund ? &l->bund->ccp.fsm : NULL;
        !           723:       break;
        !           724:     case PROTO_ECP:
        !           725:     case PROTO_CRYPT:
        !           726:       rej = l->bund ? &l->bund->ecp.fsm : NULL;
        !           727:       break;
        !           728:     case PROTO_IPCP:
        !           729:       rej = l->bund ? &l->bund->ipcp.fsm : NULL;
        !           730:       break;
        !           731:     case PROTO_IPV6CP:
        !           732:       rej = l->bund ? &l->bund->ipv6cp.fsm : NULL;
        !           733:       break;
        !           734:     default:
        !           735:       break;
        !           736:   }
        !           737: 
        !           738:   /* Turn off whatever protocol got rejected */
        !           739:   if (rej)
        !           740:     FsmFailure(rej, FAIL_WAS_PROTREJ);
        !           741:   return(fatal);
        !           742: }
        !           743: 
        !           744: /*
        !           745:  * LcpRecvIdent()
        !           746:  */
        !           747: 
        !           748: static void
        !           749: LcpRecvIdent(Fsm fp, Mbuf bp)
        !           750: {
        !           751:     Link       l = (Link)fp->arg;
        !           752:     int                len, clen;
        !           753: 
        !           754:     if (bp == NULL)
        !           755:        return;
        !           756: 
        !           757:     if (l->lcp.peer_ident[0] != 0)
        !           758:        strlcat(l->lcp.peer_ident, " ", sizeof(l->lcp.peer_ident));
        !           759:   
        !           760:     len = strlen(l->lcp.peer_ident);
        !           761:     clen = sizeof(l->lcp.peer_ident) - len - 1;
        !           762:     if (clen > MBLEN(bp))
        !           763:        clen = MBLEN(bp);
        !           764:     memcpy(l->lcp.peer_ident + len, (char *) MBDATAU(bp), clen);
        !           765:     l->lcp.peer_ident[len + clen] = 0;
        !           766: }
        !           767: 
        !           768: /*
        !           769:  * LcpFailure()
        !           770:  */
        !           771: 
        !           772: static void
        !           773: LcpFailure(Fsm fp, enum fsmfail reason)
        !           774: {
        !           775:     Link       l = (Link)fp->arg;
        !           776:   char buf[100];
        !           777: 
        !           778:   snprintf(buf, sizeof(buf), STR_LCP_FAILED, FsmFailureStr(reason));
        !           779:   RecordLinkUpDownReason(NULL, l, 0, reason == FAIL_ECHO_TIMEOUT ?
        !           780:     STR_ECHO_TIMEOUT : STR_PROTO_ERR, "%s", buf);
        !           781: }
        !           782: 
        !           783: /*
        !           784:  * LcpDecodeConfig()
        !           785:  */
        !           786: 
        !           787: static void
        !           788: LcpDecodeConfig(Fsm fp, FsmOption list, int num, int mode)
        !           789: {
        !           790:     Link       l = (Link)fp->arg;
        !           791:     LcpState   const lcp = &l->lcp;
        !           792:     int                k;
        !           793: 
        !           794:     /* If we have got request, forget the previous values */
        !           795:     if (mode == MODE_REQ) {
        !           796:        lcp->peer_mru = l->conf.mtu;
        !           797:        lcp->peer_accmap = 0xffffffff;
        !           798:        lcp->peer_acfcomp = FALSE;
        !           799:        lcp->peer_protocomp = FALSE;
        !           800:        lcp->peer_magic = 0;
        !           801:        lcp->peer_auth = 0;
        !           802:        lcp->peer_alg = 0;
        !           803:        lcp->peer_mrru = 0;
        !           804:        lcp->peer_shortseq = FALSE;
        !           805:     }
        !           806: 
        !           807:   /* Decode each config option */
        !           808:   for (k = 0; k < num; k++) {
        !           809:     FsmOption  const opt = &list[k];
        !           810:     FsmOptInfo const oi = FsmFindOptInfo(gLcpConfOpts, opt->type);
        !           811: 
        !           812:     /* Check option */
        !           813:     if (!oi) {
        !           814:       Log(LG_LCP, ("[%s]   UNKNOWN[%d] len=%d", l->name, opt->type, opt->len));
        !           815:       if (mode == MODE_REQ)
        !           816:        FsmRej(fp, opt);
        !           817:       continue;
        !           818:     }
        !           819:     if (!oi->supported) {
        !           820:       Log(LG_LCP, ("[%s]   %s", l->name, oi->name));
        !           821:       if (mode == MODE_REQ) {
        !           822:        Log(LG_LCP, ("[%s]     Not supported", l->name));
        !           823:        FsmRej(fp, opt);
        !           824:       }
        !           825:       continue;
        !           826:     }
        !           827:     if (opt->len < oi->minLen + 2 || opt->len > oi->maxLen + 2) {
        !           828:       Log(LG_LCP, ("[%s]   %s", l->name, oi->name));
        !           829:       if (mode == MODE_REQ) {
        !           830:        Log(LG_LCP, ("[%s]     Bogus length=%d", l->name, opt->len));
        !           831:        FsmRej(fp, opt);
        !           832:       }
        !           833:       continue;
        !           834:     }
        !           835: 
        !           836:     /* Do whatever */
        !           837:     switch (opt->type) {
        !           838:       case TY_MRU:             /* link MRU */
        !           839:        {
        !           840:          u_int16_t     mru;
        !           841: 
        !           842:          memcpy(&mru, opt->data, 2);
        !           843:          mru = ntohs(mru);
        !           844:          Log(LG_LCP, ("[%s]   %s %d", l->name, oi->name, mru));
        !           845:          switch (mode) {
        !           846:            case MODE_REQ:
        !           847:              if (mru < LCP_MIN_MRU) {
        !           848:                mru = htons(LCP_MIN_MRU);
        !           849:                memcpy(opt->data, &mru, 2);
        !           850:                FsmNak(fp, opt);
        !           851:                break;
        !           852:              }
        !           853:              if (mru < lcp->peer_mru)
        !           854:                lcp->peer_mru = mru;
        !           855:              FsmAck(fp, opt);
        !           856:              break;
        !           857:            case MODE_NAK:
        !           858:              /* Windows 2000 PPPoE bug workaround */
        !           859:              if (mru == lcp->want_mru) {
        !           860:                LCP_PEER_REJ(lcp, opt->type);
        !           861:                break;
        !           862:              }
        !           863:              if (mru >= LCP_MIN_MRU
        !           864:                  && (mru <= l->type->mru || mru < lcp->want_mru))
        !           865:                lcp->want_mru = mru;
        !           866:              break;
        !           867:            case MODE_REJ:
        !           868:              LCP_PEER_REJ(lcp, opt->type);
        !           869:              break;
        !           870:          }
        !           871:        }
        !           872:        break;
        !           873: 
        !           874:       case TY_ACCMAP:          /* async control character escape map */
        !           875:        {
        !           876:          u_int32_t     accm;
        !           877: 
        !           878:          memcpy(&accm, opt->data, 4);
        !           879:          accm = ntohl(accm);
        !           880:          Log(LG_LCP, ("[%s]   %s 0x%08x", l->name, oi->name, accm));
        !           881:          switch (mode) {
        !           882:            case MODE_REQ:
        !           883:              lcp->peer_accmap = accm;
        !           884:              FsmAck(fp, opt);
        !           885:              break;
        !           886:            case MODE_NAK:
        !           887:              lcp->want_accmap = accm;
        !           888:              break;
        !           889:            case MODE_REJ:
        !           890:              LCP_PEER_REJ(lcp, opt->type);
        !           891:              break;
        !           892:          }
        !           893:        }
        !           894:        break;
        !           895: 
        !           896:       case TY_AUTHPROTO:               /* authentication protocol */
        !           897:        {
        !           898:          u_int16_t             proto;
        !           899:          int                   bogus = 0, i, protoPos = -1;
        !           900:          LcpAuthProto          authProto = NULL;
        !           901: 
        !           902:          memcpy(&proto, opt->data, 2);
        !           903:          proto = ntohs(proto);
        !           904: 
        !           905:          /* Display it */
        !           906:          switch (proto) {
        !           907:            case PROTO_CHAP:
        !           908:              if (opt->len >= 5) {
        !           909:                char            buf[20];
        !           910:                const char      *ts;
        !           911: 
        !           912:                switch (opt->data[2]) {
        !           913:                  case CHAP_ALG_MD5:
        !           914:                    ts = "MD5";
        !           915:                    break;
        !           916:                  case CHAP_ALG_MSOFT:
        !           917:                    ts = "MSOFT";
        !           918:                    break;
        !           919:                  case CHAP_ALG_MSOFTv2:
        !           920:                    ts = "MSOFTv2";
        !           921:                    break;
        !           922:                  default:
        !           923:                    snprintf(buf, sizeof(buf), "0x%02x", opt->data[2]);
        !           924:                    ts = buf;
        !           925:                    break;
        !           926:                }
        !           927:                Log(LG_LCP, ("[%s]   %s %s %s", l->name, oi->name, ProtoName(proto), ts));
        !           928:                break;
        !           929:              }
        !           930:              break;
        !           931:            default:
        !           932:              Log(LG_LCP, ("[%s]   %s %s", l->name, oi->name, ProtoName(proto)));
        !           933:              break;
        !           934:          }
        !           935: 
        !           936:          /* Sanity check */
        !           937:          switch (proto) {
        !           938:            case PROTO_PAP:
        !           939:              if (opt->len != 4) {
        !           940:                Log(LG_LCP, ("[%s]     Bad len=%d", l->name, opt->len));
        !           941:                bogus = 1;
        !           942:              }
        !           943:              break;
        !           944:            case PROTO_CHAP:
        !           945:              if (opt->len != 5) {
        !           946:                Log(LG_LCP, ("[%s]     Bad len=%d", l->name, opt->len));
        !           947:                bogus = 1;
        !           948:              }
        !           949:              break;
        !           950:          }
        !           951:          if (!bogus) {
        !           952:            protoPos = LcpFindAuthProto(proto, proto == PROTO_CHAP ? opt->data[2] : 0);
        !           953:            authProto = (protoPos == -1) ? NULL : &gLcpAuthProtos[protoPos];
        !           954:          }
        !           955: 
        !           956:          /* Deal with it */
        !           957:          switch (mode) {
        !           958:            case MODE_REQ:
        !           959: 
        !           960:              /* let us check, whether the requested auth-proto is acceptable */
        !           961:              if ((authProto != NULL) && Acceptable(&l->conf.options, authProto->conf)) {
        !           962:                lcp->peer_auth = proto;
        !           963:                if (proto == PROTO_CHAP)
        !           964:                  lcp->peer_alg = opt->data[2];
        !           965:                FsmAck(fp, opt);
        !           966:                break;
        !           967:              }
        !           968: 
        !           969:              /* search an acceptable proto */
        !           970:              for(i = 0; i < LCP_NUM_AUTH_PROTOS; i++) {
        !           971:                if (lcp->peer_protos[i] != NULL) {
        !           972:                  FsmNak(fp, LcpAuthProtoNak(lcp->peer_protos[i]->proto, lcp->peer_protos[i]->alg));
        !           973:                  break;
        !           974:                }
        !           975:              }
        !           976: 
        !           977:              /* no other acceptable auth-proto found */
        !           978:              if (i == LCP_NUM_AUTH_PROTOS)
        !           979:                FsmRej(fp, opt);
        !           980:              break;
        !           981: 
        !           982:            case MODE_NAK:
        !           983:              /* this should never happen */
        !           984:              if (authProto == NULL)
        !           985:                break;
        !           986: 
        !           987:              /* let us check, whether the requested auth-proto is enabled */
        !           988:              if (Enabled(&l->conf.options, authProto->conf)) {
        !           989:                lcp->want_auth = proto;
        !           990:                if (proto == PROTO_CHAP)
        !           991:                  lcp->want_alg = opt->data[2];
        !           992:                break;
        !           993:              }
        !           994: 
        !           995:              /* Remove the disabled proto from my list */
        !           996:              lcp->want_protos[protoPos] = NULL;
        !           997: 
        !           998:              /* Search the next enabled proto */
        !           999:              for(i = 0; i < LCP_NUM_AUTH_PROTOS; i++) {
        !          1000:                if (lcp->want_protos[i] != NULL) {
        !          1001:                  lcp->want_auth = lcp->want_protos[i]->proto;
        !          1002:                  lcp->want_alg = lcp->want_protos[i]->alg;
        !          1003:                  break;
        !          1004:                }
        !          1005:              }
        !          1006:              break;
        !          1007: 
        !          1008:            case MODE_REJ:
        !          1009:              LCP_PEER_REJ(lcp, opt->type);
        !          1010:              if (l->originate == LINK_ORIGINATE_LOCAL
        !          1011:                  && Enabled(&l->conf.options, LINK_CONF_NO_ORIG_AUTH)) {
        !          1012:                lcp->want_auth = 0;
        !          1013:              }
        !          1014:              break;
        !          1015:          }
        !          1016:        }
        !          1017:        break;
        !          1018: 
        !          1019:       case TY_MRRU:                    /* multi-link MRRU */
        !          1020:        {
        !          1021:          u_int16_t     mrru;
        !          1022: 
        !          1023:          memcpy(&mrru, opt->data, 2);
        !          1024:          mrru = ntohs(mrru);
        !          1025:          Log(LG_LCP, ("[%s]   %s %d", l->name, oi->name, mrru));
        !          1026:          switch (mode) {
        !          1027:            case MODE_REQ:
        !          1028:              if (!Enabled(&l->conf.options, LINK_CONF_MULTILINK)) {
        !          1029:                FsmRej(fp, opt);
        !          1030:                break;
        !          1031:              }
        !          1032:              if (mrru < MP_MIN_MRRU) {
        !          1033:                mrru = htons(MP_MIN_MRRU);
        !          1034:                memcpy(opt->data, &mrru, 2);
        !          1035:                FsmNak(fp, opt);
        !          1036:                break;
        !          1037:              }
        !          1038:              lcp->peer_mrru = mrru;
        !          1039:              FsmAck(fp, opt);
        !          1040:              break;
        !          1041:            case MODE_NAK:
        !          1042:              {
        !          1043:                /* Let the peer to change it's mind. */
        !          1044:                if (LCP_PEER_REJECTED(lcp, opt->type)) {
        !          1045:                    LCP_PEER_UNREJ(lcp, opt->type);
        !          1046:                    if (Enabled(&l->conf.options, LINK_CONF_MULTILINK))
        !          1047:                        lcp->want_mrru = l->conf.mrru;
        !          1048:                }
        !          1049:                /* Make sure we don't violate any rules by changing MRRU now */
        !          1050:                if (mrru > lcp->want_mrru)              /* too big */
        !          1051:                  break;
        !          1052:                if (mrru < MP_MIN_MRRU)                 /* too small; clip */
        !          1053:                  mrru = MP_MIN_MRRU;
        !          1054: 
        !          1055:                /* Update our links */
        !          1056:                lcp->want_mrru = mrru;
        !          1057:              }
        !          1058:              break;
        !          1059:            case MODE_REJ:
        !          1060:              lcp->want_mrru = 0;
        !          1061:              LCP_PEER_REJ(lcp, opt->type);
        !          1062:              break;
        !          1063:          }
        !          1064:        }
        !          1065:        break;
        !          1066: 
        !          1067:       case TY_SHORTSEQNUM:             /* multi-link short sequence numbers */
        !          1068:        Log(LG_LCP, ("[%s]   %s", l->name, oi->name));
        !          1069:        switch (mode) {
        !          1070:          case MODE_REQ:
        !          1071:            if (!Enabled(&l->conf.options, LINK_CONF_MULTILINK) ||
        !          1072:                !Acceptable(&l->conf.options, LINK_CONF_SHORTSEQ)) {
        !          1073:              FsmRej(fp, opt);
        !          1074:              break;
        !          1075:            }
        !          1076:            lcp->peer_shortseq = TRUE;
        !          1077:            FsmAck(fp, opt);
        !          1078:            break;
        !          1079:          case MODE_NAK:
        !          1080:                /* Let the peer to change it's mind. */
        !          1081:                if (LCP_PEER_REJECTED(lcp, opt->type)) {
        !          1082:                    LCP_PEER_UNREJ(lcp, opt->type);
        !          1083:                    if (Enabled(&l->conf.options, LINK_CONF_MULTILINK))
        !          1084:                        lcp->want_shortseq = Enabled(&l->conf.options, LINK_CONF_SHORTSEQ);
        !          1085:                }
        !          1086:                break;
        !          1087:          case MODE_REJ:
        !          1088:              lcp->want_shortseq = FALSE;
        !          1089:              LCP_PEER_REJ(lcp, opt->type);
        !          1090:            break;
        !          1091:        }
        !          1092:        break;
        !          1093: 
        !          1094:       case TY_ENDPOINTDISC:            /* multi-link endpoint discriminator */
        !          1095:        {
        !          1096:          struct discrim        dis;
        !          1097:          char                  buf[64];
        !          1098: 
        !          1099:          if (opt->len < 3 || opt->len > sizeof(dis.bytes)) {
        !          1100:            Log(LG_LCP, ("[%s]   %s bad len=%d", l->name, oi->name, opt->len));
        !          1101:            if (mode == MODE_REQ)
        !          1102:              FsmRej(fp, opt);
        !          1103:            break;
        !          1104:          }
        !          1105:          memcpy(&dis.class, opt->data, opt->len - 2);
        !          1106:          dis.len = opt->len - 3;
        !          1107:          Log(LG_LCP, ("[%s]   %s %s", l->name, oi->name, MpDiscrimText(&dis, buf, sizeof(buf))));
        !          1108:          switch (mode) {
        !          1109:            case MODE_REQ:
        !          1110:              lcp->peer_discrim = dis;
        !          1111:              FsmAck(fp, opt);
        !          1112:              break;
        !          1113:            case MODE_NAK:
        !          1114:                /* Let the peer to change it's mind. */
        !          1115:                LCP_PEER_UNREJ(lcp, opt->type);
        !          1116:                break;
        !          1117:            case MODE_REJ:
        !          1118:              LCP_PEER_REJ(lcp, opt->type);
        !          1119:              break;
        !          1120:          }
        !          1121:        }
        !          1122:        break;
        !          1123: 
        !          1124:       case TY_MAGICNUM:                        /* magic number */
        !          1125:        {
        !          1126:          u_int32_t     magic;
        !          1127: 
        !          1128:          memcpy(&magic, opt->data, 4);
        !          1129:          magic = ntohl(magic);
        !          1130:          Log(LG_LCP, ("[%s]   %s %08x", l->name, oi->name, magic));
        !          1131:          switch (mode) {
        !          1132:            case MODE_REQ:
        !          1133:              if (lcp->want_magic) {
        !          1134:                if (magic == lcp->want_magic) {
        !          1135:                  Log(LG_LCP, ("[%s]     Same magic! Detected loopback condition", l->name));
        !          1136:                  magic = htonl(~magic);
        !          1137:                  memcpy(opt->data, &magic, 4);
        !          1138:                  FsmNak(fp, opt);
        !          1139:                  break;
        !          1140:                }
        !          1141:                lcp->peer_magic = magic;
        !          1142:                FsmAck(fp, opt);
        !          1143:                break;
        !          1144:              }
        !          1145:              FsmRej(fp, opt);
        !          1146:              break;
        !          1147:            case MODE_NAK:
        !          1148:              lcp->want_magic = GenerateMagic();
        !          1149:              break;
        !          1150:            case MODE_REJ:
        !          1151:              lcp->want_magic = 0;
        !          1152:              LCP_PEER_REJ(lcp, opt->type);
        !          1153:              break;
        !          1154:          }
        !          1155:        }
        !          1156:        break;
        !          1157: 
        !          1158:       case TY_PROTOCOMP:               /* Protocol field compression */
        !          1159:        Log(LG_LCP, ("[%s]   %s", l->name, oi->name));
        !          1160:        switch (mode) {
        !          1161:          case MODE_REQ:
        !          1162:            if (Acceptable(&l->conf.options, LINK_CONF_PROTOCOMP)) {
        !          1163:              lcp->peer_protocomp = TRUE;
        !          1164:              FsmAck(fp, opt);
        !          1165:              break;
        !          1166:            }
        !          1167:            FsmRej(fp, opt);
        !          1168:            break;
        !          1169:          case MODE_NAK:        /* a NAK here doesn't make sense */
        !          1170:          case MODE_REJ:
        !          1171:            lcp->want_protocomp = FALSE;
        !          1172:            LCP_PEER_REJ(lcp, opt->type);
        !          1173:            break;
        !          1174:        }
        !          1175:        break;
        !          1176: 
        !          1177:       case TY_ACFCOMP:                 /* Address field compression */
        !          1178:        Log(LG_LCP, ("[%s]   %s", l->name, oi->name));
        !          1179:        switch (mode) {
        !          1180:          case MODE_REQ:
        !          1181:            if (Acceptable(&l->conf.options, LINK_CONF_ACFCOMP)) {
        !          1182:              lcp->peer_acfcomp = TRUE;
        !          1183:              FsmAck(fp, opt);
        !          1184:              break;
        !          1185:            }
        !          1186:            FsmRej(fp, opt);
        !          1187:            break;
        !          1188:          case MODE_NAK:        /* a NAK here doesn't make sense */
        !          1189:          case MODE_REJ:
        !          1190:            lcp->want_acfcomp = FALSE;
        !          1191:            LCP_PEER_REJ(lcp, opt->type);
        !          1192:            break;
        !          1193:        }
        !          1194:        break;
        !          1195: 
        !          1196:       case TY_CALLBACK:                        /* Callback */
        !          1197:        Log(LG_LCP, ("[%s]   %s %d", l->name, oi->name, opt->data[0]));
        !          1198:        switch (mode) {
        !          1199:          case MODE_REQ:        /* we only support peer calling us back */
        !          1200:            FsmRej(fp, opt);
        !          1201:            break;
        !          1202:          case MODE_NAK:        /* we only know one way to do it */
        !          1203:            /* fall through */
        !          1204:          case MODE_REJ:
        !          1205:            lcp->want_callback = FALSE;
        !          1206:            LCP_PEER_REJ(lcp, opt->type);
        !          1207:            break;
        !          1208:        }
        !          1209:        break;
        !          1210: 
        !          1211:       case TY_VENDOR:
        !          1212:        {
        !          1213:          Log(LG_LCP, ("[%s]   %s %02x%02x%02x:%d", l->name, oi->name,
        !          1214:            opt->data[0], opt->data[1], opt->data[2], opt->data[3]));
        !          1215:          switch (mode) {
        !          1216:            case MODE_REQ:
        !          1217:              FsmRej(fp, opt);
        !          1218:              break;
        !          1219:            case MODE_NAK:
        !          1220:              /* fall through */
        !          1221:            case MODE_REJ:
        !          1222:              LCP_PEER_REJ(lcp, opt->type);
        !          1223:              break;
        !          1224:          }
        !          1225:          break;
        !          1226:        }
        !          1227:        break;
        !          1228: 
        !          1229:       default:
        !          1230:        assert(0);
        !          1231:     }
        !          1232:   }
        !          1233: }
        !          1234: 
        !          1235: /*
        !          1236:  * LcpInput()
        !          1237:  */
        !          1238: 
        !          1239: void
        !          1240: LcpInput(Link l, Mbuf bp)
        !          1241: {
        !          1242:   FsmInput(&l->lcp.fsm, bp);
        !          1243: }
        !          1244: 
        !          1245: static const struct fsmoption *
        !          1246: LcpAuthProtoNak(ushort proto, u_char alg)
        !          1247: {
        !          1248:   static const u_char  chapmd5cf[] =
        !          1249:     { PROTO_CHAP >> 8, PROTO_CHAP & 0xff, CHAP_ALG_MD5 };
        !          1250:   static const struct  fsmoption chapmd5Nak =
        !          1251:     { TY_AUTHPROTO, 2 + sizeof(chapmd5cf), (u_char *) chapmd5cf };
        !          1252: 
        !          1253:   static const u_char  chapmsv1cf[] =
        !          1254:     { PROTO_CHAP >> 8, PROTO_CHAP & 0xff, CHAP_ALG_MSOFT };
        !          1255:   static const struct  fsmoption chapmsv1Nak =
        !          1256:     { TY_AUTHPROTO, 2 + sizeof(chapmsv1cf), (u_char *) chapmsv1cf };
        !          1257: 
        !          1258:   static const u_char  chapmsv2cf[] =
        !          1259:     { PROTO_CHAP >> 8, PROTO_CHAP & 0xff, CHAP_ALG_MSOFTv2 };
        !          1260:   static const struct  fsmoption chapmsv2Nak =
        !          1261:     { TY_AUTHPROTO, 2 + sizeof(chapmsv2cf), (u_char *) chapmsv2cf };
        !          1262: 
        !          1263:   static const u_char  papcf[] =
        !          1264:     { PROTO_PAP >> 8, PROTO_PAP & 0xff };
        !          1265:   static const struct  fsmoption papNak =
        !          1266:     { TY_AUTHPROTO, 2 + sizeof(papcf), (u_char *) papcf };
        !          1267: 
        !          1268:   static const u_char  eapcf[] =
        !          1269:     { PROTO_EAP >> 8, PROTO_EAP & 0xff };
        !          1270:   static const struct  fsmoption eapNak =
        !          1271:     { TY_AUTHPROTO, 2 + sizeof(eapcf), (u_char *) eapcf };
        !          1272: 
        !          1273:   if (proto == PROTO_PAP) {
        !          1274:     return &papNak;
        !          1275:   } else if (proto == PROTO_EAP) {
        !          1276:     return &eapNak;
        !          1277:   } else {
        !          1278:     switch (alg) {
        !          1279:       case CHAP_ALG_MSOFTv2:
        !          1280:         return &chapmsv2Nak;
        !          1281: 
        !          1282:       case CHAP_ALG_MSOFT:
        !          1283:         return &chapmsv1Nak;
        !          1284: 
        !          1285:       case CHAP_ALG_MD5:
        !          1286:         return &chapmd5Nak;
        !          1287: 
        !          1288:       default:
        !          1289:         return NULL;
        !          1290:     }
        !          1291:   }
        !          1292: 
        !          1293: }
        !          1294: 
        !          1295: /*
        !          1296:  * LcpFindAuthProto()
        !          1297:  *
        !          1298:  */
        !          1299: static short
        !          1300: LcpFindAuthProto(ushort proto, u_char alg)
        !          1301: {
        !          1302:   int i;
        !          1303: 
        !          1304:   for(i = 0; i < LCP_NUM_AUTH_PROTOS; i++) {
        !          1305:     if (gLcpAuthProtos[i].proto == proto && gLcpAuthProtos[i].alg == alg) {
        !          1306:       return i;
        !          1307:     }
        !          1308:   }
        !          1309: 
        !          1310:   return -1;
        !          1311: 
        !          1312: }

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