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