lcp.c revision 44305
11573Srgrimes/* 21573Srgrimes * PPP Link Control Protocol (LCP) Module 31573Srgrimes * 41573Srgrimes * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 51573Srgrimes * 61573Srgrimes * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 71573Srgrimes * 81573Srgrimes * Redistribution and use in source and binary forms are permitted 91573Srgrimes * provided that the above copyright notice and this paragraph are 101573Srgrimes * duplicated in all such forms and that any documentation, 111573Srgrimes * advertising materials, and other materials related to such 121573Srgrimes * distribution and use acknowledge that the software was developed 131573Srgrimes * by the Internet Initiative Japan, Inc. The name of the 141573Srgrimes * IIJ may not be used to endorse or promote products derived 151573Srgrimes * from this software without specific prior written permission. 161573Srgrimes * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 171573Srgrimes * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 181573Srgrimes * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 191573Srgrimes * 201573Srgrimes * $Id: lcp.c,v 1.68 1999/02/18 00:52:14 brian Exp $ 211573Srgrimes * 221573Srgrimes * TODO: 231573Srgrimes * o Limit data field length by MRU 241573Srgrimes */ 251573Srgrimes 261573Srgrimes#include <sys/param.h> 271573Srgrimes#include <netinet/in.h> 281573Srgrimes#include <netinet/in_systm.h> 291573Srgrimes#include <netinet/ip.h> 301573Srgrimes#include <sys/un.h> 311573Srgrimes 321573Srgrimes#include <signal.h> 331573Srgrimes#include <stdio.h> 341573Srgrimes#include <stdlib.h> 351573Srgrimes#include <string.h> 3692986Sobrien#include <termios.h> 3792986Sobrien#include <unistd.h> 381573Srgrimes 3971579Sdeischen#include "ua.h" 401573Srgrimes#include "defs.h" 411573Srgrimes#include "command.h" 4271579Sdeischen#include "mbuf.h" 4371579Sdeischen#include "log.h" 441573Srgrimes#include "timer.h" 451573Srgrimes#include "fsm.h" 4672373Sdeischen#include "iplist.h" 4772373Sdeischen#include "lcp.h" 4871579Sdeischen#include "throughput.h" 4971579Sdeischen#include "lcpproto.h" 5071579Sdeischen#include "descriptor.h" 5171579Sdeischen#include "lqr.h" 5213545Sjulian#include "hdlc.h" 5371579Sdeischen#include "ccp.h" 541573Srgrimes#include "async.h" 5513545Sjulian#include "link.h" 561573Srgrimes#include "physical.h" 571573Srgrimes#include "prompt.h" 5872373Sdeischen#include "slcompress.h" 5935129Sjb#include "ipcp.h" 60131592Scperciva#include "filter.h" 61131592Scperciva#include "mp.h" 62131592Scperciva#include "chat.h" 63131592Scperciva#include "auth.h" 64131592Scperciva#include "chap.h" 65131592Scperciva#include "cbcp.h" 66131592Scperciva#include "datalink.h" 67131592Scperciva#ifndef NORADIUS 68131592Scperciva#include "radius.h" 69131592Scperciva#endif 70131592Scperciva#include "bundle.h" 71131592Scperciva 721573Srgrimes/* for received LQRs */ 731573Srgrimesstruct lqrreq { 7413545Sjulian u_char type; 7571579Sdeischen u_char length; 7613545Sjulian u_short proto; /* Quality protocol */ 7735129Sjb u_int32_t period; /* Reporting interval */ 7813545Sjulian}; 791573Srgrimes 801573Srgrimesstatic int LcpLayerUp(struct fsm *); 8171579Sdeischenstatic void LcpLayerDown(struct fsm *); 8271579Sdeischenstatic void LcpLayerStart(struct fsm *); 8371579Sdeischenstatic void LcpLayerFinish(struct fsm *); 8471579Sdeischenstatic void LcpInitRestartCounter(struct fsm *, int); 8513545Sjulianstatic void LcpSendConfigReq(struct fsm *); 8671579Sdeischenstatic void LcpSentTerminateReq(struct fsm *); 871573Srgrimesstatic void LcpSendTerminateAck(struct fsm *, u_char); 8871579Sdeischenstatic void LcpDecodeConfig(struct fsm *, u_char *, int, int, 891573Srgrimes struct fsm_decode *); 9071579Sdeischen 9172373Sdeischenstatic struct fsm_callbacks lcp_Callbacks = { 9271579Sdeischen LcpLayerUp, 9371579Sdeischen LcpLayerDown, 9471579Sdeischen LcpLayerStart, 9571579Sdeischen LcpLayerFinish, 9671579Sdeischen LcpInitRestartCounter, 9771579Sdeischen LcpSendConfigReq, 9871579Sdeischen LcpSentTerminateReq, 9971579Sdeischen LcpSendTerminateAck, 10071579Sdeischen LcpDecodeConfig, 10171579Sdeischen fsm_NullRecvResetReq, 10271579Sdeischen fsm_NullRecvResetAck 10371579Sdeischen}; 10471579Sdeischen 10571579Sdeischenstatic const char *lcp_TimerNames[] = 1061573Srgrimes {"LCP restart", "LCP openmode", "LCP stopped"}; 1071573Srgrimes 1081573Srgrimesstatic const char *cftypes[] = { 1091573Srgrimes /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */ 1101573Srgrimes "???", 1111573Srgrimes "MRU", /* 1: Maximum-Receive-Unit */ 1121573Srgrimes "ACCMAP", /* 2: Async-Control-Character-Map */ 1131573Srgrimes "AUTHPROTO", /* 3: Authentication-Protocol */ 1141573Srgrimes "QUALPROTO", /* 4: Quality-Protocol */ 1151573Srgrimes "MAGICNUM", /* 5: Magic-Number */ 1161573Srgrimes "RESERVED", /* 6: RESERVED */ 1171573Srgrimes "PROTOCOMP", /* 7: Protocol-Field-Compression */ 1181573Srgrimes "ACFCOMP", /* 8: Address-and-Control-Field-Compression */ 1191573Srgrimes "FCSALT", /* 9: FCS-Alternatives */ 1201573Srgrimes "SDP", /* 10: Self-Describing-Pad */ 1211573Srgrimes "NUMMODE", /* 11: Numbered-Mode */ 1221573Srgrimes "MULTIPROC", /* 12: Multi-Link-Procedure */ 12382838Sache "CALLBACK", /* 13: Callback */ 1241573Srgrimes "CONTIME", /* 14: Connect-Time */ 1251573Srgrimes "COMPFRAME", /* 15: Compound-Frames */ 1261573Srgrimes "NDE", /* 16: Nominal-Data-Encapsulation */ 1271573Srgrimes "MRRU", /* 17: Multilink-MRRU */ 1281573Srgrimes "SHORTSEQ", /* 18: Multilink-Short-Sequence-Number-Header */ 1291573Srgrimes "ENDDISC", /* 19: Multilink-Endpoint-Discriminator */ 1301573Srgrimes "PROPRIETRY", /* 20: Proprietary */ 13172373Sdeischen "DCEID", /* 21: DCE-Identifier */ 13272373Sdeischen "MULTIPP", /* 22: Multi-Link-Plus-Procedure */ 13372373Sdeischen "LDBACP", /* 23: Link Discriminator for BACP */ 13472373Sdeischen}; 13572373Sdeischen 13672373Sdeischen#define NCFTYPES (sizeof cftypes/sizeof cftypes[0]) 13772373Sdeischen 13872373Sdeischenint 13972373Sdeischenlcp_ReportStatus(struct cmdargs const *arg) 14072373Sdeischen{ 14172373Sdeischen struct link *l; 142 struct lcp *lcp; 143 144 l = command_ChooseLink(arg); 145 lcp = &l->lcp; 146 147 prompt_Printf(arg->prompt, "%s: %s [%s]\n", l->name, lcp->fsm.name, 148 State2Nam(lcp->fsm.state)); 149 prompt_Printf(arg->prompt, 150 " his side: MRU %d, ACCMAP %08lx, PROTOCOMP %s, ACFCOMP %s,\n" 151 " MAGIC %08lx, MRRU %u, SHORTSEQ %s, REJECT %04x\n", 152 lcp->his_mru, (u_long)lcp->his_accmap, 153 lcp->his_protocomp ? "on" : "off", 154 lcp->his_acfcomp ? "on" : "off", 155 (u_long)lcp->his_magic, lcp->his_mrru, 156 lcp->his_shortseq ? "on" : "off", lcp->his_reject); 157 prompt_Printf(arg->prompt, 158 " my side: MRU %d, ACCMAP %08lx, PROTOCOMP %s, ACFCOMP %s,\n" 159 " MAGIC %08lx, MRRU %u, SHORTSEQ %s, REJECT %04x\n", 160 lcp->want_mru, (u_long)lcp->want_accmap, 161 lcp->want_protocomp ? "on" : "off", 162 lcp->want_acfcomp ? "on" : "off", 163 (u_long)lcp->want_magic, lcp->want_mrru, 164 lcp->want_shortseq ? "on" : "off", lcp->my_reject); 165 166 prompt_Printf(arg->prompt, "\n Defaults: MRU = %d, ", lcp->cfg.mru); 167 prompt_Printf(arg->prompt, "ACCMAP = %08lx\n", (u_long)lcp->cfg.accmap); 168 prompt_Printf(arg->prompt, " LQR period = %us, ", 169 lcp->cfg.lqrperiod); 170 prompt_Printf(arg->prompt, "Open Mode = %s", 171 lcp->cfg.openmode == OPEN_PASSIVE ? "passive" : "active"); 172 if (lcp->cfg.openmode > 0) 173 prompt_Printf(arg->prompt, " (delay %ds)", lcp->cfg.openmode); 174 prompt_Printf(arg->prompt, "\n FSM retry = %us, max %u Config" 175 " REQ%s, %u Term REQ%s\n", lcp->cfg.fsm.timeout, 176 lcp->cfg.fsm.maxreq, lcp->cfg.fsm.maxreq == 1 ? "" : "s", 177 lcp->cfg.fsm.maxtrm, lcp->cfg.fsm.maxtrm == 1 ? "" : "s"); 178 prompt_Printf(arg->prompt, "\n Negotiation:\n"); 179 prompt_Printf(arg->prompt, " ACFCOMP = %s\n", 180 command_ShowNegval(lcp->cfg.acfcomp)); 181 prompt_Printf(arg->prompt, " CHAP = %s\n", 182 command_ShowNegval(lcp->cfg.chap05)); 183#ifdef HAVE_DES 184 prompt_Printf(arg->prompt, " MSCHAP = %s\n", 185 command_ShowNegval(lcp->cfg.chap80nt)); 186 prompt_Printf(arg->prompt, " LANMan = %s\n", 187 command_ShowNegval(lcp->cfg.chap80lm)); 188#endif 189 prompt_Printf(arg->prompt, " LQR = %s\n", 190 command_ShowNegval(lcp->cfg.lqr)); 191 prompt_Printf(arg->prompt, " PAP = %s\n", 192 command_ShowNegval(lcp->cfg.pap)); 193 prompt_Printf(arg->prompt, " PROTOCOMP = %s\n", 194 command_ShowNegval(lcp->cfg.protocomp)); 195 196 return 0; 197} 198 199static u_int32_t 200GenerateMagic(void) 201{ 202 /* Generate random number which will be used as magic number */ 203 randinit(); 204 return random(); 205} 206 207void 208lcp_SetupCallbacks(struct lcp *lcp) 209{ 210 lcp->fsm.fn = &lcp_Callbacks; 211 lcp->fsm.FsmTimer.name = lcp_TimerNames[0]; 212 lcp->fsm.OpenTimer.name = lcp_TimerNames[1]; 213 lcp->fsm.StoppedTimer.name = lcp_TimerNames[2]; 214} 215 216void 217lcp_Init(struct lcp *lcp, struct bundle *bundle, struct link *l, 218 const struct fsm_parent *parent) 219{ 220 /* Initialise ourselves */ 221 int mincode = parent ? 1 : LCP_MINMPCODE; 222 223 fsm_Init(&lcp->fsm, "LCP", PROTO_LCP, mincode, LCP_MAXCODE, LogLCP, 224 bundle, l, parent, &lcp_Callbacks, lcp_TimerNames); 225 226 lcp->cfg.mru = DEF_MRU; 227 lcp->cfg.accmap = 0; 228 lcp->cfg.openmode = 1; 229 lcp->cfg.lqrperiod = DEF_LQRPERIOD; 230 lcp->cfg.fsm.timeout = DEF_FSMRETRY; 231 lcp->cfg.fsm.maxreq = DEF_FSMTRIES; 232 lcp->cfg.fsm.maxtrm = DEF_FSMTRIES; 233 234 lcp->cfg.acfcomp = NEG_ENABLED|NEG_ACCEPTED; 235 lcp->cfg.chap05 = NEG_ACCEPTED; 236#ifdef HAVE_DES 237 lcp->cfg.chap80nt = NEG_ACCEPTED; 238 lcp->cfg.chap80lm = NEG_ACCEPTED; 239#endif 240 lcp->cfg.lqr = NEG_ACCEPTED; 241 lcp->cfg.pap = NEG_ACCEPTED; 242 lcp->cfg.protocomp = NEG_ENABLED|NEG_ACCEPTED; 243 244 lcp_Setup(lcp, lcp->cfg.openmode); 245} 246 247void 248lcp_Setup(struct lcp *lcp, int openmode) 249{ 250 lcp->fsm.open_mode = openmode; 251 252 lcp->his_mru = lcp->fsm.bundle->cfg.mtu; 253 if (!lcp->his_mru || lcp->his_mru > DEF_MRU) 254 lcp->his_mru = DEF_MRU; 255 lcp->his_mrru = 0; 256 lcp->his_magic = 0; 257 lcp->his_lqrperiod = 0; 258 lcp->his_acfcomp = 0; 259 lcp->his_auth = 0; 260 lcp->his_authtype = 0; 261 lcp->his_callback.opmask = 0; 262 lcp->his_shortseq = 0; 263 264 lcp->want_mru = lcp->cfg.mru; 265 lcp->want_mrru = lcp->fsm.bundle->ncp.mp.cfg.mrru; 266 lcp->want_shortseq = IsEnabled(lcp->fsm.bundle->ncp.mp.cfg.shortseq) ? 1 : 0; 267 lcp->want_acfcomp = IsEnabled(lcp->cfg.acfcomp) ? 1 : 0; 268 269 if (lcp->fsm.parent) { 270 struct physical *p = link2physical(lcp->fsm.link); 271 272 lcp->his_accmap = 0xffffffff; 273 lcp->want_accmap = lcp->cfg.accmap; 274 lcp->his_protocomp = 0; 275 lcp->want_protocomp = IsEnabled(lcp->cfg.protocomp) ? 1 : 0; 276 lcp->want_magic = GenerateMagic(); 277 278 if (IsEnabled(lcp->cfg.chap05)) { 279 lcp->want_auth = PROTO_CHAP; 280 lcp->want_authtype = 0x05; 281#ifdef HAVE_DES 282 } else if (IsEnabled(lcp->cfg.chap80nt) || 283 IsEnabled(lcp->cfg.chap80lm)) { 284 lcp->want_auth = PROTO_CHAP; 285 lcp->want_authtype = 0x80; 286#endif 287 } else if (IsEnabled(lcp->cfg.pap)) { 288 lcp->want_auth = PROTO_PAP; 289 lcp->want_authtype = 0; 290 } else { 291 lcp->want_auth = 0; 292 lcp->want_authtype = 0; 293 } 294 295 if (p->type != PHYS_DIRECT) 296 memcpy(&lcp->want_callback, &p->dl->cfg.callback, sizeof(struct callback)); 297 else 298 lcp->want_callback.opmask = 0; 299 lcp->want_lqrperiod = IsEnabled(lcp->cfg.lqr) ? 300 lcp->cfg.lqrperiod * 100 : 0; 301 } else { 302 lcp->his_accmap = lcp->want_accmap = 0; 303 lcp->his_protocomp = lcp->want_protocomp = 1; 304 lcp->want_magic = 0; 305 lcp->want_auth = 0; 306 lcp->want_authtype = 0; 307 lcp->want_callback.opmask = 0; 308 lcp->want_lqrperiod = 0; 309 } 310 311 lcp->his_reject = lcp->my_reject = 0; 312 lcp->auth_iwait = lcp->auth_ineed = 0; 313 lcp->LcpFailedMagic = 0; 314} 315 316static void 317LcpInitRestartCounter(struct fsm *fp, int what) 318{ 319 /* Set fsm timer load */ 320 struct lcp *lcp = fsm2lcp(fp); 321 322 fp->FsmTimer.load = lcp->cfg.fsm.timeout * SECTICKS; 323 switch (what) { 324 case FSM_REQ_TIMER: 325 fp->restart = lcp->cfg.fsm.maxreq; 326 break; 327 case FSM_TRM_TIMER: 328 fp->restart = lcp->cfg.fsm.maxtrm; 329 break; 330 default: 331 fp->restart = 1; 332 break; 333 } 334} 335 336static void 337LcpSendConfigReq(struct fsm *fp) 338{ 339 /* Send config REQ please */ 340 struct physical *p = link2physical(fp->link); 341 struct lcp *lcp = fsm2lcp(fp); 342 u_char buff[200]; 343 struct lcp_opt *o; 344 struct mp *mp; 345 u_int16_t proto; 346 347 if (!p) { 348 log_Printf(LogERROR, "%s: LcpSendConfigReq: Not a physical link !\n", 349 fp->link->name); 350 return; 351 } 352 353 o = (struct lcp_opt *)buff; 354 if (!physical_IsSync(p)) { 355 if (lcp->want_acfcomp && !REJECTED(lcp, TY_ACFCOMP)) 356 INC_LCP_OPT(TY_ACFCOMP, 2, o); 357 358 if (lcp->want_protocomp && !REJECTED(lcp, TY_PROTOCOMP)) 359 INC_LCP_OPT(TY_PROTOCOMP, 2, o); 360 361 if (!REJECTED(lcp, TY_ACCMAP)) { 362 ua_htonl(&lcp->want_accmap, o->data); 363 INC_LCP_OPT(TY_ACCMAP, 6, o); 364 } 365 } 366 367 if (!REJECTED(lcp, TY_MRU)) { 368 ua_htons(&lcp->want_mru, o->data); 369 INC_LCP_OPT(TY_MRU, 4, o); 370 } 371 372 if (lcp->want_magic && !REJECTED(lcp, TY_MAGICNUM)) { 373 ua_htonl(&lcp->want_magic, o->data); 374 INC_LCP_OPT(TY_MAGICNUM, 6, o); 375 } 376 377 if (lcp->want_lqrperiod && !REJECTED(lcp, TY_QUALPROTO)) { 378 proto = PROTO_LQR; 379 ua_htons(&proto, o->data); 380 ua_htonl(&lcp->want_lqrperiod, o->data + 2); 381 INC_LCP_OPT(TY_QUALPROTO, 8, o); 382 } 383 384 switch (lcp->want_auth) { 385 case PROTO_PAP: 386 proto = PROTO_PAP; 387 ua_htons(&proto, o->data); 388 INC_LCP_OPT(TY_AUTHPROTO, 4, o); 389 break; 390 391 case PROTO_CHAP: 392 proto = PROTO_CHAP; 393 ua_htons(&proto, o->data); 394 o->data[2] = lcp->want_authtype; 395 INC_LCP_OPT(TY_AUTHPROTO, 5, o); 396 break; 397 } 398 399 if (!REJECTED(lcp, TY_CALLBACK)) { 400 if (lcp->want_callback.opmask & CALLBACK_BIT(CALLBACK_AUTH)) { 401 *o->data = CALLBACK_AUTH; 402 INC_LCP_OPT(TY_CALLBACK, 3, o); 403 } else if (lcp->want_callback.opmask & CALLBACK_BIT(CALLBACK_CBCP)) { 404 *o->data = CALLBACK_CBCP; 405 INC_LCP_OPT(TY_CALLBACK, 3, o); 406 } else if (lcp->want_callback.opmask & CALLBACK_BIT(CALLBACK_E164)) { 407 int sz = strlen(lcp->want_callback.msg); 408 409 if (sz > sizeof o->data - 1) { 410 sz = sizeof o->data - 1; 411 log_Printf(LogWARN, "Truncating E164 data to %d octets (oops!)\n", sz); 412 } 413 *o->data = CALLBACK_E164; 414 memcpy(o->data + 1, lcp->want_callback.msg, sz); 415 INC_LCP_OPT(TY_CALLBACK, sz + 3, o); 416 } 417 } 418 419 if (lcp->want_mrru && !REJECTED(lcp, TY_MRRU)) { 420 ua_htons(&lcp->want_mrru, o->data); 421 INC_LCP_OPT(TY_MRRU, 4, o); 422 423 if (lcp->want_shortseq && !REJECTED(lcp, TY_SHORTSEQ)) 424 INC_LCP_OPT(TY_SHORTSEQ, 2, o); 425 } 426 427 mp = &lcp->fsm.bundle->ncp.mp; 428 if (mp->cfg.enddisc.class != 0 && !REJECTED(lcp, TY_ENDDISC)) { 429 *o->data = mp->cfg.enddisc.class; 430 memcpy(o->data+1, mp->cfg.enddisc.address, mp->cfg.enddisc.len); 431 INC_LCP_OPT(TY_ENDDISC, mp->cfg.enddisc.len + 3, o); 432 } 433 434 fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, (u_char *)o - buff); 435} 436 437void 438lcp_SendProtoRej(struct lcp *lcp, u_char *option, int count) 439{ 440 /* Don't understand `option' */ 441 fsm_Output(&lcp->fsm, CODE_PROTOREJ, lcp->fsm.reqid, option, count); 442} 443 444static void 445LcpSentTerminateReq(struct fsm *fp) 446{ 447 /* Term REQ just sent by FSM */ 448} 449 450static void 451LcpSendTerminateAck(struct fsm *fp, u_char id) 452{ 453 /* Send Term ACK please */ 454 struct physical *p = link2physical(fp->link); 455 456 if (p && p->dl->state == DATALINK_CBCP) 457 cbcp_ReceiveTerminateReq(p); 458 459 fsm_Output(fp, CODE_TERMACK, id, NULL, 0); 460} 461 462static void 463LcpLayerStart(struct fsm *fp) 464{ 465 /* We're about to start up ! */ 466 struct lcp *lcp = fsm2lcp(fp); 467 468 log_Printf(LogLCP, "%s: LayerStart\n", fp->link->name); 469 lcp->LcpFailedMagic = 0; 470 fp->more.reqs = fp->more.naks = fp->more.rejs = lcp->cfg.fsm.maxreq * 3; 471} 472 473static void 474LcpLayerFinish(struct fsm *fp) 475{ 476 /* We're now down */ 477 log_Printf(LogLCP, "%s: LayerFinish\n", fp->link->name); 478} 479 480static int 481LcpLayerUp(struct fsm *fp) 482{ 483 /* We're now up */ 484 struct physical *p = link2physical(fp->link); 485 struct lcp *lcp = fsm2lcp(fp); 486 487 log_Printf(LogLCP, "%s: LayerUp\n", fp->link->name); 488 async_SetLinkParams(&p->async, lcp); 489 lqr_Start(lcp); 490 hdlc_StartTimer(&p->hdlc); 491 fp->more.reqs = fp->more.naks = fp->more.rejs = lcp->cfg.fsm.maxreq * 3; 492 493 return 1; 494} 495 496static void 497LcpLayerDown(struct fsm *fp) 498{ 499 /* About to come down */ 500 struct physical *p = link2physical(fp->link); 501 502 log_Printf(LogLCP, "%s: LayerDown\n", fp->link->name); 503 hdlc_StopTimer(&p->hdlc); 504 lqr_StopTimer(p); 505 lcp_Setup(fsm2lcp(fp), 0); 506} 507 508static int 509E164ok(struct callback *cb, char *req, int sz) 510{ 511 char list[sizeof cb->msg], *next; 512 int len; 513 514 if (!strcmp(cb->msg, "*")) 515 return 1; 516 517 strncpy(list, cb->msg, sizeof list - 1); 518 list[sizeof list - 1] = '\0'; 519 for (next = strtok(list, ","); next; next = strtok(NULL, ",")) { 520 len = strlen(next); 521 if (sz == len && !memcmp(list, req, sz)) 522 return 1; 523 } 524 return 0; 525} 526 527static void 528LcpDecodeConfig(struct fsm *fp, u_char *cp, int plen, int mode_type, 529 struct fsm_decode *dec) 530{ 531 /* Deal with incoming PROTO_LCP */ 532 struct lcp *lcp = fsm2lcp(fp); 533 int type, length, sz, pos, op, callback_req; 534 u_int32_t magic, accmap; 535 u_short mtu, mru, proto; 536 struct lqrreq *req; 537 char request[20], desc[22]; 538 struct mp *mp; 539 struct physical *p = link2physical(fp->link); 540 541 callback_req = 0; 542 543 while (plen >= sizeof(struct fsmconfig)) { 544 type = *cp; 545 length = cp[1]; 546 547 if (type < 0 || type >= NCFTYPES) 548 snprintf(request, sizeof request, " <%d>[%d]", type, length); 549 else 550 snprintf(request, sizeof request, " %s[%d]", cftypes[type], length); 551 552 if (length < 2) { 553 log_Printf(LogLCP, "%s:%s: Bad LCP length\n", fp->link->name, request); 554 break; 555 } 556 557 switch (type) { 558 case TY_MRRU: 559 mp = &lcp->fsm.bundle->ncp.mp; 560 ua_ntohs(cp + 2, &mru); 561 log_Printf(LogLCP, "%s %u\n", request, mru); 562 563 switch (mode_type) { 564 case MODE_REQ: 565 if (mp->cfg.mrru) { 566 if (REJECTED(lcp, TY_MRRU)) 567 /* Ignore his previous reject so that we REQ next time */ 568 lcp->his_reject &= ~(1 << type); 569 570 mtu = lcp->fsm.bundle->cfg.mtu; 571 if (mru < MIN_MRU || mru < mtu) { 572 /* Push him up to MTU or MIN_MRU */ 573 lcp->his_mrru = mru < mtu ? mtu : MIN_MRU; 574 memcpy(dec->nakend, cp, 2); 575 ua_htons(&lcp->his_mrru, dec->nakend + 2); 576 dec->nakend += 4; 577 } else { 578 lcp->his_mrru = mtu ? mtu : mru; 579 memcpy(dec->ackend, cp, 4); 580 dec->ackend += 4; 581 } 582 break; 583 } else 584 goto reqreject; 585 break; 586 case MODE_NAK: 587 if (mp->cfg.mrru) { 588 if (REJECTED(lcp, TY_MRRU)) 589 /* Must have changed his mind ! */ 590 lcp->his_reject &= ~(1 << type); 591 592 if (mru > MAX_MRU) 593 lcp->want_mrru = MAX_MRU; 594 else if (mru < MIN_MRU) 595 lcp->want_mrru = MIN_MRU; 596 else 597 lcp->want_mrru = mru; 598 } 599 /* else we honour our config and don't send the suggested REQ */ 600 break; 601 case MODE_REJ: 602 lcp->his_reject |= (1 << type); 603 lcp->want_mrru = 0; /* Ah well, no multilink :-( */ 604 break; 605 } 606 break; 607 608 case TY_MRU: 609 ua_ntohs(cp + 2, &mru); 610 log_Printf(LogLCP, "%s %d\n", request, mru); 611 612 switch (mode_type) { 613 case MODE_REQ: 614 mtu = lcp->fsm.bundle->cfg.mtu; 615 if (mru < MIN_MRU || (!lcp->want_mrru && mru < mtu)) { 616 /* Push him up to MTU or MIN_MRU */ 617 lcp->his_mru = mru < mtu ? mtu : MIN_MRU; 618 memcpy(dec->nakend, cp, 2); 619 ua_htons(&lcp->his_mru, dec->nakend + 2); 620 dec->nakend += 4; 621 } else { 622 lcp->his_mru = mtu ? mtu : mru; 623 memcpy(dec->ackend, cp, 4); 624 dec->ackend += 4; 625 } 626 break; 627 case MODE_NAK: 628 if (mru > MAX_MRU) 629 lcp->want_mru = MAX_MRU; 630 else if (mru < MIN_MRU) 631 lcp->want_mru = MIN_MRU; 632 else 633 lcp->want_mru = mru; 634 break; 635 case MODE_REJ: 636 lcp->his_reject |= (1 << type); 637 break; 638 } 639 break; 640 641 case TY_ACCMAP: 642 ua_ntohl(cp + 2, &accmap); 643 log_Printf(LogLCP, "%s 0x%08lx\n", request, (u_long)accmap); 644 645 switch (mode_type) { 646 case MODE_REQ: 647 lcp->his_accmap = accmap; 648 memcpy(dec->ackend, cp, 6); 649 dec->ackend += 6; 650 break; 651 case MODE_NAK: 652 lcp->want_accmap = accmap; 653 break; 654 case MODE_REJ: 655 lcp->his_reject |= (1 << type); 656 break; 657 } 658 break; 659 660 case TY_AUTHPROTO: 661 ua_ntohs(cp + 2, &proto); 662 log_Printf(LogLCP, "%s 0x%04x (%s)\n", request, proto, 663 Auth2Nam(proto, length > 4 ? cp[4] : 0)); 664 665 switch (mode_type) { 666 case MODE_REQ: 667 switch (proto) { 668 case PROTO_PAP: 669 if (length != 4) { 670 log_Printf(LogLCP, " Bad length!\n"); 671 goto reqreject; 672 } 673 if (IsAccepted(lcp->cfg.pap)) { 674 lcp->his_auth = proto; 675 lcp->his_authtype = 0; 676 memcpy(dec->ackend, cp, length); 677 dec->ackend += length; 678 } else if (IsAccepted(lcp->cfg.chap05)) { 679 *dec->nakend++ = *cp; 680 *dec->nakend++ = 5; 681 *dec->nakend++ = (unsigned char) (PROTO_CHAP >> 8); 682 *dec->nakend++ = (unsigned char) PROTO_CHAP; 683 *dec->nakend++ = 0x05; 684#ifdef HAVE_DES 685 } else if (IsAccepted(lcp->cfg.chap80nt) || 686 IsAccepted(lcp->cfg.chap80lm)) { 687 *dec->nakend++ = *cp; 688 *dec->nakend++ = 5; 689 *dec->nakend++ = (unsigned char) (PROTO_CHAP >> 8); 690 *dec->nakend++ = (unsigned char) PROTO_CHAP; 691 *dec->nakend++ = 0x80; 692#endif 693 } else 694 goto reqreject; 695 break; 696 697 case PROTO_CHAP: 698 if (length != 5) { 699 log_Printf(LogLCP, " Bad length!\n"); 700 goto reqreject; 701 } 702 if ((cp[4] == 0x05 && IsAccepted(lcp->cfg.chap05)) 703#ifdef HAVE_DES 704 || (cp[4] == 0x80 && (IsAccepted(lcp->cfg.chap80nt) || 705 (IsAccepted(lcp->cfg.chap80lm)))) 706#endif 707 ) { 708 lcp->his_auth = proto; 709 lcp->his_authtype = cp[4]; 710 memcpy(dec->ackend, cp, length); 711 dec->ackend += length; 712 } else { 713#ifndef HAVE_DES 714 if (cp[4] == 0x80) 715 log_Printf(LogWARN, "CHAP 0x80 not available without DES\n"); 716 else 717#endif 718 if (cp[4] != 0x05) 719 log_Printf(LogWARN, "%s not supported\n", 720 Auth2Nam(PROTO_CHAP, cp[4])); 721 722 if (IsAccepted(lcp->cfg.chap05)) { 723 *dec->nakend++ = *cp; 724 *dec->nakend++ = 5; 725 *dec->nakend++ = (unsigned char) (PROTO_CHAP >> 8); 726 *dec->nakend++ = (unsigned char) PROTO_CHAP; 727 *dec->nakend++ = 0x05; 728#ifdef HAVE_DES 729 } else if (IsAccepted(lcp->cfg.chap80nt) || 730 IsAccepted(lcp->cfg.chap80lm)) { 731 *dec->nakend++ = *cp; 732 *dec->nakend++ = 5; 733 *dec->nakend++ = (unsigned char) (PROTO_CHAP >> 8); 734 *dec->nakend++ = (unsigned char) PROTO_CHAP; 735 *dec->nakend++ = 0x80; 736#endif 737 } else if (IsAccepted(lcp->cfg.pap)) { 738 *dec->nakend++ = *cp; 739 *dec->nakend++ = 4; 740 *dec->nakend++ = (unsigned char) (PROTO_PAP >> 8); 741 *dec->nakend++ = (unsigned char) PROTO_PAP; 742 } else 743 goto reqreject; 744 } 745 break; 746 747 default: 748 log_Printf(LogLCP, "%s 0x%04x - not recognised, NAK\n", 749 request, proto); 750 memcpy(dec->nakend, cp, length); 751 dec->nakend += length; 752 break; 753 } 754 break; 755 case MODE_NAK: 756 switch (proto) { 757 case PROTO_PAP: 758 if (IsEnabled(lcp->cfg.pap)) { 759 lcp->want_auth = PROTO_PAP; 760 lcp->want_authtype = 0; 761 } else { 762 log_Printf(LogLCP, "Peer will only send PAP (not enabled)\n"); 763 lcp->his_reject |= (1 << type); 764 } 765 break; 766 case PROTO_CHAP: 767 if (cp[4] == 0x05 && IsEnabled(lcp->cfg.chap05)) { 768 lcp->want_auth = PROTO_CHAP; 769 lcp->want_authtype = 0x05; 770#ifdef HAVE_DES 771 } else if (cp[4] == 0x80 && (IsEnabled(lcp->cfg.chap80nt) || 772 IsEnabled(lcp->cfg.chap80lm))) { 773 lcp->want_auth = PROTO_CHAP; 774 lcp->want_authtype = 0x80; 775#endif 776 } else { 777#ifndef HAVE_DES 778 if (cp[4] == 0x80) 779 log_Printf(LogLCP, "Peer will only send MSCHAP (not available" 780 " without DES)\n"); 781 else 782#endif 783 log_Printf(LogLCP, "Peer will only send %s (not %s)\n", 784 Auth2Nam(PROTO_CHAP, cp[4]), 785#ifdef HAVE_DES 786 cp[4] == 0x80 ? "configured" : 787#endif 788 "supported"); 789 lcp->his_reject |= (1 << type); 790 } 791 break; 792 default: 793 /* We've been NAK'd with something we don't understand :-( */ 794 lcp->his_reject |= (1 << type); 795 break; 796 } 797 break; 798 case MODE_REJ: 799 lcp->his_reject |= (1 << type); 800 break; 801 } 802 break; 803 804 case TY_QUALPROTO: 805 req = (struct lqrreq *)cp; 806 log_Printf(LogLCP, "%s proto %x, interval %lums\n", 807 request, ntohs(req->proto), (u_long)ntohl(req->period) * 10); 808 switch (mode_type) { 809 case MODE_REQ: 810 if (ntohs(req->proto) != PROTO_LQR || !IsAccepted(lcp->cfg.lqr)) 811 goto reqreject; 812 else { 813 lcp->his_lqrperiod = ntohl(req->period); 814 if (lcp->his_lqrperiod < MIN_LQRPERIOD * 100) 815 lcp->his_lqrperiod = MIN_LQRPERIOD * 100; 816 req->period = htonl(lcp->his_lqrperiod); 817 memcpy(dec->ackend, cp, length); 818 dec->ackend += length; 819 } 820 break; 821 case MODE_NAK: 822 break; 823 case MODE_REJ: 824 lcp->his_reject |= (1 << type); 825 break; 826 } 827 break; 828 829 case TY_MAGICNUM: 830 ua_ntohl(cp + 2, &magic); 831 log_Printf(LogLCP, "%s 0x%08lx\n", request, (u_long)magic); 832 833 switch (mode_type) { 834 case MODE_REQ: 835 if (lcp->want_magic) { 836 /* Validate magic number */ 837 if (magic == lcp->want_magic) { 838 log_Printf(LogLCP, "Magic is same (%08lx) - %d times\n", 839 (u_long)magic, ++lcp->LcpFailedMagic); 840 lcp->want_magic = GenerateMagic(); 841 memcpy(dec->nakend, cp, 6); 842 dec->nakend += 6; 843 ualarm(TICKUNIT * (4 + 4 * lcp->LcpFailedMagic), 0); 844 sigpause(0); 845 } else { 846 lcp->his_magic = magic; 847 memcpy(dec->ackend, cp, length); 848 dec->ackend += length; 849 lcp->LcpFailedMagic = 0; 850 } 851 } else { 852 goto reqreject; 853 } 854 break; 855 case MODE_NAK: 856 log_Printf(LogLCP, " Magic 0x%08lx is NAKed!\n", (u_long)magic); 857 lcp->want_magic = GenerateMagic(); 858 break; 859 case MODE_REJ: 860 log_Printf(LogLCP, " Magic 0x%08x is REJected!\n", magic); 861 lcp->want_magic = 0; 862 lcp->his_reject |= (1 << type); 863 break; 864 } 865 break; 866 867 case TY_PROTOCOMP: 868 log_Printf(LogLCP, "%s\n", request); 869 870 switch (mode_type) { 871 case MODE_REQ: 872 if (IsAccepted(lcp->cfg.protocomp)) { 873 lcp->his_protocomp = 1; 874 memcpy(dec->ackend, cp, 2); 875 dec->ackend += 2; 876 } else { 877#ifdef OLDMST 878 /* 879 * MorningStar before v1.3 needs NAK 880 */ 881 memcpy(dec->nakend, cp, 2); 882 dec->nakend += 2; 883#else 884 goto reqreject; 885#endif 886 } 887 break; 888 case MODE_NAK: 889 case MODE_REJ: 890 lcp->want_protocomp = 0; 891 lcp->his_reject |= (1 << type); 892 break; 893 } 894 break; 895 896 case TY_ACFCOMP: 897 log_Printf(LogLCP, "%s\n", request); 898 switch (mode_type) { 899 case MODE_REQ: 900 if (IsAccepted(lcp->cfg.acfcomp)) { 901 lcp->his_acfcomp = 1; 902 memcpy(dec->ackend, cp, 2); 903 dec->ackend += 2; 904 } else { 905#ifdef OLDMST 906 /* 907 * MorningStar before v1.3 needs NAK 908 */ 909 memcpy(dec->nakend, cp, 2); 910 dec->nakend += 2; 911#else 912 goto reqreject; 913#endif 914 } 915 break; 916 case MODE_NAK: 917 case MODE_REJ: 918 lcp->want_acfcomp = 0; 919 lcp->his_reject |= (1 << type); 920 break; 921 } 922 break; 923 924 case TY_SDP: 925 log_Printf(LogLCP, "%s\n", request); 926 switch (mode_type) { 927 case MODE_REQ: 928 case MODE_NAK: 929 case MODE_REJ: 930 break; 931 } 932 break; 933 934 case TY_CALLBACK: 935 if (length == 2) 936 op = CALLBACK_NONE; 937 else 938 op = (int)cp[2]; 939 sz = length - 3; 940 switch (op) { 941 case CALLBACK_AUTH: 942 log_Printf(LogLCP, "%s Auth\n", request); 943 break; 944 case CALLBACK_DIALSTRING: 945 log_Printf(LogLCP, "%s Dialstring %.*s\n", request, sz, cp + 3); 946 break; 947 case CALLBACK_LOCATION: 948 log_Printf(LogLCP, "%s Location %.*s\n", request, sz, cp + 3); 949 break; 950 case CALLBACK_E164: 951 log_Printf(LogLCP, "%s E.164 (%.*s)\n", request, sz, cp + 3); 952 break; 953 case CALLBACK_NAME: 954 log_Printf(LogLCP, "%s Name %.*s\n", request, sz, cp + 3); 955 break; 956 case CALLBACK_CBCP: 957 log_Printf(LogLCP, "%s CBCP\n", request); 958 break; 959 default: 960 log_Printf(LogLCP, "%s ???\n", request); 961 break; 962 } 963 964 switch (mode_type) { 965 case MODE_REQ: 966 callback_req = 1; 967 if (p->type != PHYS_DIRECT) 968 goto reqreject; 969 if ((p->dl->cfg.callback.opmask & CALLBACK_BIT(op)) && 970 (op != CALLBACK_AUTH || p->link.lcp.auth_ineed) && 971 (op != CALLBACK_E164 || 972 E164ok(&p->dl->cfg.callback, cp + 3, sz))) { 973 lcp->his_callback.opmask = CALLBACK_BIT(op); 974 if (sz > sizeof lcp->his_callback.msg - 1) { 975 sz = sizeof lcp->his_callback.msg - 1; 976 log_Printf(LogWARN, "Truncating option arg to %d octets\n", sz); 977 } 978 memcpy(lcp->his_callback.msg, cp + 3, sz); 979 lcp->his_callback.msg[sz] = '\0'; 980 memcpy(dec->ackend, cp, sz + 3); 981 dec->ackend += sz + 3; 982 } else if ((p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_AUTH)) && 983 p->link.lcp.auth_ineed) { 984 *dec->nakend++ = *cp; 985 *dec->nakend++ = 3; 986 *dec->nakend++ = CALLBACK_AUTH; 987 } else if (p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_CBCP)) { 988 *dec->nakend++ = *cp; 989 *dec->nakend++ = 3; 990 *dec->nakend++ = CALLBACK_CBCP; 991 } else if (p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_E164)) { 992 *dec->nakend++ = *cp; 993 *dec->nakend++ = 3; 994 *dec->nakend++ = CALLBACK_E164; 995 } else if (p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_AUTH)) { 996 log_Printf(LogWARN, "Cannot insist on auth callback without" 997 " PAP or CHAP enabled !\n"); 998 *dec->nakend++ = *cp; 999 *dec->nakend++ = 2; 1000 } else 1001 goto reqreject; 1002 break; 1003 case MODE_NAK: 1004 /* We don't do what he NAKs with, we do things in our preferred order */ 1005 if (lcp->want_callback.opmask & CALLBACK_BIT(CALLBACK_AUTH)) 1006 lcp->want_callback.opmask &= ~CALLBACK_BIT(CALLBACK_AUTH); 1007 else if (lcp->want_callback.opmask & CALLBACK_BIT(CALLBACK_CBCP)) 1008 lcp->want_callback.opmask &= ~CALLBACK_BIT(CALLBACK_CBCP); 1009 else if (lcp->want_callback.opmask & CALLBACK_BIT(CALLBACK_E164)) 1010 lcp->want_callback.opmask &= ~CALLBACK_BIT(CALLBACK_E164); 1011 if (lcp->want_callback.opmask == CALLBACK_BIT(CALLBACK_NONE)) { 1012 log_Printf(LogPHASE, "Peer NAKd all callbacks, trying none\n"); 1013 lcp->want_callback.opmask = 0; 1014 } else if (!lcp->want_callback.opmask) { 1015 log_Printf(LogPHASE, "Peer NAKd last configured callback\n"); 1016 fsm_Close(&lcp->fsm); 1017 } 1018 break; 1019 case MODE_REJ: 1020 if (lcp->want_callback.opmask & CALLBACK_BIT(CALLBACK_NONE)) { 1021 lcp->his_reject |= (1 << type); 1022 lcp->want_callback.opmask = 0; 1023 } else { 1024 log_Printf(LogPHASE, "Peer rejected *required* callback\n"); 1025 fsm_Close(&lcp->fsm); 1026 } 1027 break; 1028 } 1029 break; 1030 1031 case TY_SHORTSEQ: 1032 mp = &lcp->fsm.bundle->ncp.mp; 1033 log_Printf(LogLCP, "%s\n", request); 1034 1035 switch (mode_type) { 1036 case MODE_REQ: 1037 if (lcp->want_mrru && IsAccepted(mp->cfg.shortseq)) { 1038 lcp->his_shortseq = 1; 1039 memcpy(dec->ackend, cp, length); 1040 dec->ackend += length; 1041 } else 1042 goto reqreject; 1043 break; 1044 case MODE_NAK: 1045 /* 1046 * He's trying to get us to ask for short sequence numbers. 1047 * We ignore the NAK and honour our configuration file instead. 1048 */ 1049 break; 1050 case MODE_REJ: 1051 lcp->his_reject |= (1 << type); 1052 lcp->want_shortseq = 0; /* For when we hit MP */ 1053 break; 1054 } 1055 break; 1056 1057 case TY_ENDDISC: 1058 log_Printf(LogLCP, "%s %s\n", request, 1059 mp_Enddisc(cp[2], cp + 3, length - 3)); 1060 switch (mode_type) { 1061 case MODE_REQ: 1062 if (!p) { 1063 log_Printf(LogLCP, " ENDDISC rejected - not a physical link\n"); 1064 goto reqreject; 1065 } else if (length-3 < sizeof p->dl->peer.enddisc.address && 1066 cp[2] <= MAX_ENDDISC_CLASS) { 1067 p->dl->peer.enddisc.class = cp[2]; 1068 p->dl->peer.enddisc.len = length-3; 1069 memcpy(p->dl->peer.enddisc.address, cp + 3, length - 3); 1070 p->dl->peer.enddisc.address[length - 3] = '\0'; 1071 /* XXX: If mp->active, compare and NAK with mp->peer ? */ 1072 memcpy(dec->ackend, cp, length); 1073 dec->ackend += length; 1074 } else { 1075 if (cp[2] > MAX_ENDDISC_CLASS) 1076 log_Printf(LogLCP, " ENDDISC rejected - unrecognised class %d\n", 1077 cp[2]); 1078 else 1079 log_Printf(LogLCP, " ENDDISC rejected - local max length is %ld\n", 1080 (long)(sizeof p->dl->peer.enddisc.address - 1)); 1081 goto reqreject; 1082 } 1083 break; 1084 1085 case MODE_NAK: /* Treat this as a REJ, we don't vary our disc */ 1086 case MODE_REJ: 1087 lcp->his_reject |= (1 << type); 1088 break; 1089 } 1090 break; 1091 1092 default: 1093 sz = (sizeof desc - 2) / 2; 1094 if (sz > length - 2) 1095 sz = length - 2; 1096 pos = 0; 1097 desc[0] = sz ? ' ' : '\0'; 1098 for (pos = 0; sz--; pos++) 1099 sprintf(desc+(pos<<1)+1, "%02x", cp[pos+2]); 1100 1101 log_Printf(LogLCP, "%s%s\n", request, desc); 1102 1103 if (mode_type == MODE_REQ) { 1104reqreject: 1105 if (length > sizeof dec->rej - (dec->rejend - dec->rej)) { 1106 length = sizeof dec->rej - (dec->rejend - dec->rej); 1107 log_Printf(LogLCP, "Can't REJ length %d - trunating to %d\n", 1108 cp[1], length); 1109 } 1110 memcpy(dec->rejend, cp, length); 1111 dec->rejend += length; 1112 lcp->my_reject |= (1 << type); 1113 if (length != cp[1]) 1114 length = 0; /* force our way out of the loop */ 1115 } 1116 break; 1117 } 1118 plen -= length; 1119 cp += length; 1120 } 1121 1122 if (mode_type != MODE_NOP) { 1123 if (mode_type == MODE_REQ && p && p->type == PHYS_DIRECT && 1124 p->dl->cfg.callback.opmask && !callback_req && 1125 !(p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_NONE))) { 1126 /* We *REQUIRE* that the peer requests callback */ 1127 *dec->nakend++ = TY_CALLBACK; 1128 *dec->nakend++ = 3; 1129 if ((p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_AUTH)) && 1130 p->link.lcp.auth_ineed) 1131 *dec->nakend++ = CALLBACK_AUTH; 1132 else if (p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_CBCP)) 1133 *dec->nakend++ = CALLBACK_CBCP; 1134 else if (p->dl->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_E164)) 1135 *dec->nakend++ = CALLBACK_E164; 1136 else { 1137 log_Printf(LogWARN, "Cannot insist on auth callback without" 1138 " PAP or CHAP enabled !\n"); 1139 dec->nakend[-1] = 2; /* XXX: Silly ! */ 1140 } 1141 } 1142 if (dec->rejend != dec->rej) { 1143 /* rejects are preferred */ 1144 dec->ackend = dec->ack; 1145 dec->nakend = dec->nak; 1146 } else if (dec->nakend != dec->nak) 1147 /* then NAKs */ 1148 dec->ackend = dec->ack; 1149 } 1150} 1151 1152void 1153lcp_Input(struct lcp *lcp, struct mbuf *bp) 1154{ 1155 /* Got PROTO_LCP from link */ 1156 fsm_Input(&lcp->fsm, bp); 1157} 1158