File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / mpd / src / lcp.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Nov 1 09:56:12 2016 UTC (7 years, 8 months ago) by misho
Branches: mpd, MAIN
CVS tags: v5_8p7, v5_8p1_cross, v5_8p1, v5_8, HEAD
mpd 5.8

    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 = PhysGetMtu(l, 1);
  230:     lcp->want_mru = PhysGetMru(l, 1);
  231:     if (l->type && (lcp->want_mru > PhysGetMru(l, 0)))
  232: 	lcp->want_mru = PhysGetMru(l, 0);
  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 = PhysGetMtu(l, 1);
  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 0x%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>