lcp.c revision 26516
1/* 2 * PPP Link Control Protocol (LCP) Module 3 * 4 * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 5 * 6 * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 7 * 8 * Redistribution and use in source and binary forms are permitted 9 * provided that the above copyright notice and this paragraph are 10 * duplicated in all such forms and that any documentation, 11 * advertising materials, and other materials related to such 12 * distribution and use acknowledge that the software was developed 13 * by the Internet Initiative Japan, Inc. The name of the 14 * IIJ may not be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19 * 20 * $Id: lcp.c,v 1.22 1997/06/01 03:43:22 brian Exp $ 21 * 22 * TODO: 23 * o Validate magic number received from peer. 24 * o Limit data field length by MRU 25 */ 26#include <sys/time.h> 27#include "fsm.h" 28#include "lcp.h" 29#include "ipcp.h" 30#include "lcpproto.h" 31#include "os.h" 32#include "hdlc.h" 33#include "ccp.h" 34#include "lqr.h" 35#include "phase.h" 36#include "loadalias.h" 37#include "vars.h" 38#include "auth.h" 39#include <arpa/inet.h> 40 41extern void IpcpUp(); 42extern void IpcpOpen(); 43extern void StartPapChallenge(); 44extern void StartChapChallenge(); 45extern void SetLinkParams(struct lcpstate *); 46extern void Prompt(); 47extern void StopIdleTimer(); 48extern void OsLinkdown(); 49extern void Cleanup(); 50extern struct pppTimer IpcpReportTimer; 51extern int randinit; 52 53struct lcpstate LcpInfo; 54 55static void LcpSendConfigReq(struct fsm *); 56static void LcpSendTerminateReq(struct fsm *fp); 57static void LcpSendTerminateAck(struct fsm *fp); 58static void LcpDecodeConfig(u_char *cp, int flen,int mode); 59static void LcpInitRestartCounter(struct fsm *); 60static void LcpLayerUp(struct fsm *); 61static void LcpLayerDown(struct fsm *); 62static void LcpLayerStart(struct fsm *); 63static void LcpLayerFinish(struct fsm *); 64 65extern int ModemSpeed(); 66 67#define REJECTED(p, x) (p->his_reject & (1<<x)) 68 69static char *cftypes[] = { 70 "???", "MRU", "ACCMAP", "AUTHPROTO", "QUALPROTO", "MAGICNUM", 71 "RESERVED", "PROTOCOMP", "ACFCOMP", "FCSALT", "SDP", 72}; 73 74struct fsm LcpFsm = { 75 "LCP", /* Name of protocol */ 76 PROTO_LCP, /* Protocol Number */ 77 LCP_MAXCODE, 78 OPEN_ACTIVE, 79 ST_INITIAL, /* State of machine */ 80 0, 0, 0, 81 82 0, 83 { 0, 0, 0, NULL, NULL, NULL }, 84 85 LcpLayerUp, 86 LcpLayerDown, 87 LcpLayerStart, 88 LcpLayerFinish, 89 LcpInitRestartCounter, 90 LcpSendConfigReq, 91 LcpSendTerminateReq, 92 LcpSendTerminateAck, 93 LcpDecodeConfig, 94}; 95 96static struct pppTimer LcpReportTimer; 97 98char *PhaseNames[] = { 99 "Dead", "Establish", "Authenticate", "Network", "Terminate" 100}; 101 102void 103NewPhase(new) 104int new; 105{ 106 struct lcpstate *lcp = &LcpInfo; 107 108 phase = new; 109 LogPrintf(LogPHASE, "NewPhase: %s\n", PhaseNames[phase]); 110 switch (phase) { 111 case PHASE_AUTHENTICATE: 112 lcp->auth_ineed = lcp->want_auth; 113 lcp->auth_iwait = lcp->his_auth; 114 if (lcp->his_auth || lcp->want_auth) { 115 LogPrintf(LogPHASE, " his = %x, mine = %x\n", lcp->his_auth, lcp->want_auth); 116 if (lcp->his_auth == PROTO_PAP) 117 StartAuthChallenge(&AuthPapInfo); 118 if (lcp->want_auth == PROTO_CHAP) 119 StartAuthChallenge(&AuthChapInfo); 120 } else 121 NewPhase(PHASE_NETWORK); 122 break; 123 case PHASE_NETWORK: 124 IpcpUp(); 125 IpcpOpen(); 126 CcpUp(); 127 CcpOpen(); 128 break; 129 case PHASE_DEAD: 130 if (mode & MODE_DIRECT) 131 Cleanup(EX_DEAD); 132 if (mode & MODE_BACKGROUND && reconnectState != RECON_TRUE) 133 Cleanup(EX_DEAD); 134 break; 135 } 136} 137 138static void 139LcpReportTime() 140{ 141 if (LogIsKept(LogDEBUG)) { 142 time_t t; 143 144 time(&t); 145 LogPrintf(LogDEBUG, "LcpReportTime: %s", ctime(&t)); 146 } 147 StopTimer(&LcpReportTimer); 148 LcpReportTimer.state = TIMER_STOPPED; 149 StartTimer(&LcpReportTimer); 150 HdlcErrorCheck(); 151} 152 153int 154ReportLcpStatus() 155{ 156 struct lcpstate *lcp = &LcpInfo; 157 struct fsm *fp = &LcpFsm; 158 159 if (!VarTerm) 160 return 1; 161 162 fprintf(VarTerm, "%s [%s]\n", fp->name, StateNames[fp->state]); 163 fprintf(VarTerm, 164 " his side: MRU %ld, ACCMAP %08lx, PROTOCOMP %d, ACFCOMP %d, MAGIC %08lx,\n" 165 " REJECT %04lx\n", 166 lcp->his_mru, lcp->his_accmap, lcp->his_protocomp, lcp->his_acfcomp, 167 lcp->his_magic, lcp->his_reject); 168 fprintf(VarTerm, 169 " my side: MRU %ld, ACCMAP %08lx, PROTOCOMP %d, ACFCOMP %d, MAGIC %08lx,\n" 170 " REJECT %04lx\n", 171 lcp->want_mru, lcp->want_accmap, lcp->want_protocomp, lcp->want_acfcomp, 172 lcp->want_magic, lcp->my_reject); 173 fprintf(VarTerm, "\nDefaults: MRU = %ld, ACCMAP = %08x\t", VarMRU, VarAccmap); 174 fprintf(VarTerm, "Open Mode: %s\n", (VarOpenMode == OPEN_ACTIVE)? "active" : "passive"); 175 return 0; 176} 177 178/* 179 * Generate random number which will be used as magic number. 180 */ 181u_long 182GenerateMagic() 183{ 184 if (!randinit) { 185 randinit = 1; 186 if (srandomdev() < 0) 187 srandom((unsigned long)(time(NULL) ^ getpid())); 188 } 189 190 return (random()); 191} 192 193void 194LcpInit() 195{ 196 struct lcpstate *lcp = &LcpInfo; 197 198 FsmInit(&LcpFsm); 199 HdlcInit(); 200 201 bzero(lcp, sizeof(struct lcpstate)); 202 lcp->want_mru = VarMRU; 203 lcp->his_mru = DEF_MRU; 204 lcp->his_accmap = 0xffffffff; 205 lcp->want_accmap = VarAccmap; 206 lcp->want_magic = GenerateMagic(); 207 lcp->want_auth = lcp->his_auth = 0; 208 if (Enabled(ConfChap)) 209 lcp->want_auth = PROTO_CHAP; 210 else if (Enabled(ConfPap)) 211 lcp->want_auth = PROTO_PAP; 212 if (Enabled(ConfLqr)) lcp->want_lqrperiod = VarLqrTimeout * 100; 213 if (Enabled(ConfAcfcomp)) lcp->want_acfcomp = 1; 214 if (Enabled(ConfProtocomp)) lcp->want_protocomp = 1; 215 LcpFsm.maxconfig = 10; 216} 217 218static void 219LcpInitRestartCounter(fp) 220struct fsm *fp; 221{ 222 fp->FsmTimer.load = VarRetryTimeout * SECTICKS; 223 fp->restart = 5; 224} 225 226void 227PutConfValue(cpp, types, type, len, val) 228u_char **cpp; 229char **types; 230u_char type; 231int len; 232u_long val; 233{ 234 u_char *cp; 235 struct in_addr ina; 236 237 cp = *cpp; 238 *cp++ = type; *cp++ = len; 239 if (len == 6) { 240 if (type == TY_IPADDR) { 241 ina.s_addr = htonl(val); 242 LogPrintf(LogLCP, " %s [%d] %s\n", 243 types[type], len, inet_ntoa(ina)); 244 } else { 245 LogPrintf(LogLCP, " %s [%d] %08x\n", types[type], len, val); 246 } 247 *cp++ = (val >> 24) & 0377; 248 *cp++ = (val >> 16) & 0377; 249 } else 250 LogPrintf(LogLCP, " %s [%d] %d\n", types[type], len, val); 251 *cp++ = (val >> 8) & 0377; 252 *cp++ = val & 0377; 253 *cpp = cp; 254} 255 256static void 257LcpSendConfigReq(fp) 258struct fsm *fp; 259{ 260 u_char *cp; 261 struct lcpstate *lcp = &LcpInfo; 262 struct lqrreq *req; 263 264 LogPrintf(LogLCP, "LcpSendConfigReq\n"); 265 cp = ReqBuff; 266 if (!DEV_IS_SYNC) { 267 if (lcp->want_acfcomp && !REJECTED(lcp, TY_ACFCOMP)) { 268 *cp++ = TY_ACFCOMP; *cp++ = 2; 269 LogPrintf(LogLCP, " %s\n", cftypes[TY_ACFCOMP]); 270 } 271 if (lcp->want_protocomp && !REJECTED(lcp, TY_PROTOCOMP)) { 272 *cp++ = TY_PROTOCOMP; *cp++ = 2; 273 LogPrintf(LogLCP, " %s\n", cftypes[TY_PROTOCOMP]); 274 } 275 if (!REJECTED(lcp, TY_ACCMAP)) 276 PutConfValue(&cp, cftypes, TY_ACCMAP, 6, lcp->want_accmap); 277 } 278 if (!REJECTED(lcp, TY_MRU)) 279 PutConfValue(&cp, cftypes, TY_MRU, 4, lcp->want_mru); 280 if (lcp->want_magic && !REJECTED(lcp, TY_MAGICNUM)) 281 PutConfValue(&cp, cftypes, TY_MAGICNUM, 6, lcp->want_magic); 282 if (lcp->want_lqrperiod && !REJECTED(lcp, TY_QUALPROTO)) { 283 req = (struct lqrreq *)cp; 284 req->type = TY_QUALPROTO; req->length = sizeof(struct lqrreq); 285 req->proto = htons(PROTO_LQR); 286 req->period = htonl(lcp->want_lqrperiod); 287 cp += sizeof(struct lqrreq); 288 LogPrintf(LogLCP, " %s (%d)\n", cftypes[TY_QUALPROTO], lcp->want_lqrperiod); 289 } 290 switch (lcp->want_auth) { 291 case PROTO_PAP: 292 PutConfValue(&cp, cftypes, TY_AUTHPROTO, 4, lcp->want_auth); 293 break; 294 case PROTO_CHAP: 295 PutConfValue(&cp, cftypes, TY_AUTHPROTO, 5, lcp->want_auth); 296 *cp++ = 5; /* Use MD5 */ 297 break; 298 } 299 FsmOutput(fp, CODE_CONFIGREQ, fp->reqid++, ReqBuff, cp - ReqBuff); 300} 301 302void 303LcpSendProtoRej(option, count) 304u_char *option; 305int count; 306{ 307 struct fsm *fp = &LcpFsm; 308 309 LogPrintf(LogLCP, "LcpSendProtoRej\n"); 310 FsmOutput(fp, CODE_PROTOREJ, fp->reqid, option, count); 311} 312 313static void 314LcpSendTerminateReq(fp) 315struct fsm *fp; 316{ 317 /* Most thins are done in fsm layer. Nothing to to. */ 318} 319 320static void 321LcpSendTerminateAck(fp) 322struct fsm *fp; 323{ 324 LogPrintf(LogLCP, "LcpSendTerminateAck.\n"); 325 FsmOutput(fp, CODE_TERMACK, fp->reqid++, NULL, 0); 326} 327 328static void 329LcpLayerStart(fp) 330struct fsm *fp; 331{ 332 LogPrintf(LogLCP, "LcpLayerStart\n"); 333 NewPhase(PHASE_ESTABLISH); 334} 335 336static void 337StopAllTimers() 338{ 339 StopTimer(&LcpReportTimer); 340 StopTimer(&IpcpReportTimer); 341 StopIdleTimer(); 342 StopTimer(&AuthPapInfo.authtimer); 343 StopTimer(&AuthChapInfo.authtimer); 344 StopLqrTimer(); 345} 346 347static void 348LcpLayerFinish(fp) 349struct fsm *fp; 350{ 351 LogPrintf(LogLCP, "LcpLayerFinish\n"); 352 OsCloseLink(1); 353 NewPhase(PHASE_DEAD); 354 StopAllTimers(); 355 (void)OsInterfaceDown(0); 356 Prompt(); 357} 358 359static void 360LcpLayerUp(fp) 361struct fsm *fp; 362{ 363 LogPrintf(LogLCP, "LcpLayerUp\n"); 364 OsSetInterfaceParams(23, LcpInfo.his_mru, ModemSpeed()); 365 SetLinkParams(&LcpInfo); 366 367 NewPhase(PHASE_AUTHENTICATE); 368 369 StartLqm(); 370 StopTimer(&LcpReportTimer); 371 LcpReportTimer.state = TIMER_STOPPED; 372 LcpReportTimer.load = 60 * SECTICKS; 373 LcpReportTimer.func = LcpReportTime; 374 StartTimer(&LcpReportTimer); 375} 376 377static void 378LcpLayerDown(fp) 379struct fsm *fp; 380{ 381 LogPrintf(LogLCP, "LcpLayerDown\n"); 382 StopAllTimers(); 383 OsLinkdown(); 384 NewPhase(PHASE_TERMINATE); 385} 386 387void 388LcpUp() 389{ 390 FsmUp(&LcpFsm); 391} 392 393void 394LcpDown() /* Sudden death */ 395{ 396 NewPhase(PHASE_DEAD); 397 StopAllTimers(); 398 FsmDown(&LcpFsm); 399} 400 401void 402LcpOpen(mode) 403int mode; 404{ 405 LcpFsm.open_mode = mode; 406 FsmOpen(&LcpFsm); 407} 408 409void 410LcpClose() 411{ 412 FsmClose(&LcpFsm); 413} 414 415/* 416 * XXX: Should validate option length 417 */ 418static void 419LcpDecodeConfig(cp, plen, mode) 420u_char *cp; 421int plen; 422int mode; 423{ 424 char *request; 425 int type, length, mru; 426 u_long *lp, magic, accmap; 427 u_short *sp, proto; 428 struct lqrreq *req; 429 430 ackp = AckBuff; 431 nakp = NakBuff; 432 rejp = RejBuff; 433 434 while (plen >= sizeof(struct fsmconfig)) { 435 type = *cp; 436 length = cp[1]; 437 if (type <= TY_ACFCOMP) 438 request = cftypes[type]; 439 else 440 request = "???"; 441 442 switch (type) { 443 case TY_MRU: 444 sp = (u_short *)(cp + 2); 445 mru = htons(*sp); 446 LogPrintf(LogLCP, " %s %d\n", request, mru); 447 448 switch (mode) { 449 case MODE_REQ: 450 if (mru > MAX_MRU) { 451 *sp = htons(MAX_MRU); 452 bcopy(cp, nakp, 4); nakp += 4; 453 } else if (mru < MIN_MRU) { 454 *sp = htons(MIN_MRU); 455 bcopy(cp, nakp, 4); nakp += 4; 456 } else { 457 LcpInfo.his_mru = mru; 458 bcopy(cp, ackp, 4); ackp += 4; 459 } 460 break; 461 case MODE_NAK: 462 if (mru >= MIN_MRU || mru <= MAX_MRU) 463 LcpInfo.want_mru = mru; 464 break; 465 case MODE_REJ: 466 LcpInfo.his_reject |= (1 << type); 467 break; 468 } 469 break; 470 case TY_ACCMAP: 471 lp = (u_long *)(cp + 2); 472 accmap = htonl(*lp); 473 LogPrintf(LogLCP, " %s %08x\n", request, accmap); 474 475 switch (mode) { 476 case MODE_REQ: 477 LcpInfo.his_accmap = accmap; 478 bcopy(cp, ackp, 6); ackp += 6; 479 break; 480 case MODE_NAK: 481 LcpInfo.want_accmap = accmap; 482 break; 483 case MODE_REJ: 484 LcpInfo.his_reject |= (1 << type); 485 break; 486 } 487 break; 488 case TY_AUTHPROTO: 489 sp = (u_short *)(cp + 2); 490 proto = ntohs(*sp); 491 LogPrintf(LogLCP, " %s proto = %04x\n", request, proto); 492 493 switch (mode) { 494 case MODE_REQ: 495 switch (proto) { 496 case PROTO_PAP: 497 if (length != 4) { 498 LogPrintf(LogLCP, " %s bad length (%d)\n", request, length); 499 goto reqreject; 500 } 501 if (Acceptable(ConfPap)) { 502 LcpInfo.his_auth = proto; 503 bcopy(cp, ackp, length); ackp += length; 504 } else if (Acceptable(ConfChap)) { 505 *nakp++ = *cp; *nakp++ = 5; 506 *nakp++ = (unsigned char)(PROTO_CHAP >> 8); 507 *nakp++ = (unsigned char)PROTO_CHAP; 508 *nakp++ = 5; 509 } else 510 goto reqreject; 511 break; 512 case PROTO_CHAP: 513 if (length < 5) { 514 LogPrintf(LogLCP, " %s bad length (%d)\n", request, length); 515 goto reqreject; 516 } 517 if (Acceptable(ConfChap) && cp[4] == 5) { 518 LcpInfo.his_auth = proto; 519 bcopy(cp, ackp, length); ackp += length; 520 } else if (Acceptable(ConfPap)) { 521 *nakp++ = *cp; *nakp++ = 4; 522 *nakp++ = (unsigned char)(PROTO_PAP >> 8); 523 *nakp++ = (unsigned char)PROTO_PAP; 524 } else 525 goto reqreject; 526 break; 527 default: 528 LogPrintf(LogLCP, " %s not implemented, NAK.\n", request); 529 bcopy(cp, nakp, length); 530 nakp += length; 531 break; 532 } 533 break; 534 case MODE_NAK: 535 break; 536 case MODE_REJ: 537 LcpInfo.his_reject |= (1 << type); 538 break; 539 } 540 break; 541 case TY_QUALPROTO: 542 req = (struct lqrreq *)cp; 543 LogPrintf(LogLCP, " %s proto: %x, interval: %dms\n", 544 request, ntohs(req->proto), ntohl(req->period)*10); 545 switch (mode) { 546 case MODE_REQ: 547 if (ntohs(req->proto) != PROTO_LQR || !Acceptable(ConfLqr)) 548 goto reqreject; 549 else { 550 LcpInfo.his_lqrperiod = ntohl(req->period); 551 if (LcpInfo.his_lqrperiod < 500) 552 LcpInfo.his_lqrperiod = 500; 553 req->period = htonl(LcpInfo.his_lqrperiod); 554 bcopy(cp, ackp, length); ackp += length; 555 } 556 break; 557 case MODE_NAK: 558 break; 559 case MODE_REJ: 560 LcpInfo.his_reject |= (1 << type); 561 break; 562 } 563 break; 564 case TY_MAGICNUM: 565 lp = (u_long *)(cp + 2); 566 magic = ntohl(*lp); 567 LogPrintf(LogLCP, " %s %08x\n", request, magic); 568 569 switch (mode) { 570 case MODE_REQ: 571 if (LcpInfo.want_magic) { 572 /* Validate magic number */ 573 if (magic == LcpInfo.want_magic) { 574 LogPrintf(LogLCP, "Magic is same (%08x)\n", magic); 575 LcpInfo.want_magic = GenerateMagic(); 576 bcopy(cp, nakp, 6); 577 nakp += 6; 578 } else { 579 LcpInfo.his_magic = magic; 580 bcopy(cp, ackp, length); ackp += length; 581 } 582 } else { 583 LcpInfo.my_reject |= (1 << type); 584 goto reqreject; 585 } 586 break; 587 case MODE_NAK: 588 LogPrintf(LogLCP, " %s magic %08x has NAKed\n", request, magic); 589 LcpInfo.want_magic = GenerateMagic(); 590 break; 591 case MODE_REJ: 592 LogPrintf(LogLCP, " %s magic has REJected\n", request); 593 LcpInfo.want_magic = 0; 594 LcpInfo.his_reject |= (1 << type); 595 break; 596 } 597 break; 598 case TY_PROTOCOMP: 599 LogPrintf(LogLCP, " %s\n", request); 600 601 switch (mode) { 602 case MODE_REQ: 603 if (Acceptable(ConfProtocomp)) { 604 LcpInfo.his_protocomp = 1; 605 bcopy(cp, ackp, 2); ackp += 2; 606 } else { 607#ifdef OLDMST 608 /* 609 * MorningStar before v1.3 needs NAK 610 */ 611 bcopy(cp, nakp, 2); nakp += 2; 612#else 613 bcopy(cp, rejp, 2); rejp += 2; 614 LcpInfo.my_reject |= (1 << type); 615#endif 616 } 617 break; 618 case MODE_NAK: 619 case MODE_REJ: 620 LcpInfo.want_protocomp = 0; 621 LcpInfo.his_reject |= (1 << type); 622 break; 623 } 624 break; 625 case TY_ACFCOMP: 626 LogPrintf(LogLCP, " %s\n", request); 627 switch (mode) { 628 case MODE_REQ: 629 if (Acceptable(ConfAcfcomp)) { 630 LcpInfo.his_acfcomp = 1; 631 bcopy(cp, ackp, 2); 632 ackp += 2; 633 } else { 634#ifdef OLDMST 635 /* 636 * MorningStar before v1.3 needs NAK 637 */ 638 bcopy(cp, nakp, 2); 639 nakp += 2; 640#else 641 bcopy(cp, rejp, 2); 642 rejp += 2; 643 LcpInfo.my_reject |= (1 << type); 644#endif 645 } 646 break; 647 case MODE_NAK: 648 case MODE_REJ: 649 LcpInfo.want_acfcomp = 0; 650 LcpInfo.his_reject |= (1 << type); 651 break; 652 } 653 break; 654 case TY_SDP: 655 LogPrintf(LogLCP, " %s\n", request); 656 switch (mode) { 657 case MODE_REQ: 658 case MODE_NAK: 659 case MODE_REJ: 660 break; 661 } 662 break; 663 default: 664 LogPrintf(LogLCP, " ???[%02x]\n", type); 665 if (mode == MODE_REQ) { 666reqreject: 667 bcopy(cp, rejp, length); 668 rejp += length; 669 LcpInfo.my_reject |= (1 << type); 670 } 671 break; 672 } 673 /* to avoid inf. loop */ 674 if (length == 0) { 675 LogPrintf(LogLCP, "LCP size zero\n"); 676 break; 677 } 678 679 plen -= length; 680 cp += length; 681 } 682} 683 684void 685LcpInput(struct mbuf *bp) 686{ 687 FsmInput(&LcpFsm, bp); 688} 689