lcp.c revision 29990
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.36 1997/09/27 19:41:40 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, mtu; 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 mtu = VarPrefMTU; 446 if (mtu == 0) 447 mtu = MAX_MTU; 448 if (mru > mtu) { 449 *sp = htons(mtu); 450 bcopy(cp, nakp, 4); 451 nakp += 4; 452 } else if (mru < MIN_MRU) { 453 *sp = htons(MIN_MRU); 454 bcopy(cp, nakp, 4); 455 nakp += 4; 456 } else { 457 LcpInfo.his_mru = mru; 458 bcopy(cp, ackp, 4); 459 ackp += 4; 460 } 461 break; 462 case MODE_NAK: 463 if (mru >= MIN_MRU || mru <= MAX_MRU) 464 LcpInfo.want_mru = mru; 465 break; 466 case MODE_REJ: 467 LcpInfo.his_reject |= (1 << type); 468 break; 469 } 470 break; 471 case TY_ACCMAP: 472 lp = (u_long *) (cp + 2); 473 accmap = htonl(*lp); 474 LogPrintf(LogLCP, " %s %08x\n", request, accmap); 475 476 switch (mode) { 477 case MODE_REQ: 478 LcpInfo.his_accmap = accmap; 479 bcopy(cp, ackp, 6); 480 ackp += 6; 481 break; 482 case MODE_NAK: 483 LcpInfo.want_accmap = accmap; 484 break; 485 case MODE_REJ: 486 LcpInfo.his_reject |= (1 << type); 487 break; 488 } 489 break; 490 case TY_AUTHPROTO: 491 sp = (u_short *) (cp + 2); 492 proto = ntohs(*sp); 493 LogPrintf(LogLCP, " %s proto = %04x\n", request, proto); 494 495 switch (mode) { 496 case MODE_REQ: 497 switch (proto) { 498 case PROTO_PAP: 499 if (length != 4) { 500 LogPrintf(LogLCP, " %s bad length (%d)\n", request, length); 501 goto reqreject; 502 } 503 if (Acceptable(ConfPap)) { 504 LcpInfo.his_auth = proto; 505 bcopy(cp, ackp, length); 506 ackp += length; 507 } else if (Acceptable(ConfChap)) { 508 *nakp++ = *cp; 509 *nakp++ = 5; 510 *nakp++ = (unsigned char) (PROTO_CHAP >> 8); 511 *nakp++ = (unsigned char) PROTO_CHAP; 512 *nakp++ = 5; 513 } else 514 goto reqreject; 515 break; 516 case PROTO_CHAP: 517 if (length < 5) { 518 LogPrintf(LogLCP, " %s bad length (%d)\n", request, length); 519 goto reqreject; 520 } 521#ifdef HAVE_DES 522 if (Acceptable(ConfChap) && (cp[4] == 5 || cp[4] == 0x80)) 523#else 524 if (Acceptable(ConfChap) && cp[4] == 5) 525#endif 526 { 527 LcpInfo.his_auth = proto; 528 bcopy(cp, ackp, length); 529 ackp += length; 530#ifdef HAVE_DES 531 VarMSChap = cp[4] = 0x80; 532#endif 533 } else if (Acceptable(ConfPap)) { 534 *nakp++ = *cp; 535 *nakp++ = 4; 536 *nakp++ = (unsigned char) (PROTO_PAP >> 8); 537 *nakp++ = (unsigned char) PROTO_PAP; 538 } else 539 goto reqreject; 540 break; 541 default: 542 LogPrintf(LogLCP, " %s not implemented, NAK.\n", request); 543 bcopy(cp, nakp, length); 544 nakp += length; 545 break; 546 } 547 break; 548 case MODE_NAK: 549 break; 550 case MODE_REJ: 551 LcpInfo.his_reject |= (1 << type); 552 break; 553 } 554 break; 555 case TY_QUALPROTO: 556 req = (struct lqrreq *) cp; 557 LogPrintf(LogLCP, " %s proto: %x, interval: %dms\n", 558 request, ntohs(req->proto), ntohl(req->period) * 10); 559 switch (mode) { 560 case MODE_REQ: 561 if (ntohs(req->proto) != PROTO_LQR || !Acceptable(ConfLqr)) 562 goto reqreject; 563 else { 564 LcpInfo.his_lqrperiod = ntohl(req->period); 565 if (LcpInfo.his_lqrperiod < 500) 566 LcpInfo.his_lqrperiod = 500; 567 req->period = htonl(LcpInfo.his_lqrperiod); 568 bcopy(cp, ackp, length); 569 ackp += length; 570 } 571 break; 572 case MODE_NAK: 573 break; 574 case MODE_REJ: 575 LcpInfo.his_reject |= (1 << type); 576 break; 577 } 578 break; 579 case TY_MAGICNUM: 580 lp = (u_long *) (cp + 2); 581 magic = ntohl(*lp); 582 LogPrintf(LogLCP, " %s %08x\n", request, magic); 583 584 switch (mode) { 585 case MODE_REQ: 586 if (LcpInfo.want_magic) { 587 /* Validate magic number */ 588 if (magic == LcpInfo.want_magic) { 589 LogPrintf(LogLCP, "Magic is same (%08x) - %d times\n", 590 magic, ++LcpFailedMagic); 591 LcpInfo.want_magic = GenerateMagic(); 592 bcopy(cp, nakp, 6); 593 nakp += 6; 594 ualarm(TICKUNIT * (4 + 4 * LcpFailedMagic), 0); 595 sigpause(0); 596 } else { 597 LcpInfo.his_magic = magic; 598 bcopy(cp, ackp, length); 599 ackp += length; 600 LcpFailedMagic = 0; 601 } 602 } else { 603 LcpInfo.my_reject |= (1 << type); 604 goto reqreject; 605 } 606 break; 607 case MODE_NAK: 608 LogPrintf(LogLCP, " %s magic %08x has NAKed\n", request, magic); 609 LcpInfo.want_magic = GenerateMagic(); 610 break; 611 case MODE_REJ: 612 LogPrintf(LogLCP, " %s magic has REJected\n", request); 613 LcpInfo.want_magic = 0; 614 LcpInfo.his_reject |= (1 << type); 615 break; 616 } 617 break; 618 case TY_PROTOCOMP: 619 LogPrintf(LogLCP, " %s\n", request); 620 621 switch (mode) { 622 case MODE_REQ: 623 if (Acceptable(ConfProtocomp)) { 624 LcpInfo.his_protocomp = 1; 625 bcopy(cp, ackp, 2); 626 ackp += 2; 627 } else { 628#ifdef OLDMST 629 630 /* 631 * MorningStar before v1.3 needs NAK 632 */ 633 bcopy(cp, nakp, 2); 634 nakp += 2; 635#else 636 bcopy(cp, rejp, 2); 637 rejp += 2; 638 LcpInfo.my_reject |= (1 << type); 639#endif 640 } 641 break; 642 case MODE_NAK: 643 case MODE_REJ: 644 LcpInfo.want_protocomp = 0; 645 LcpInfo.his_reject |= (1 << type); 646 break; 647 } 648 break; 649 case TY_ACFCOMP: 650 LogPrintf(LogLCP, " %s\n", request); 651 switch (mode) { 652 case MODE_REQ: 653 if (Acceptable(ConfAcfcomp)) { 654 LcpInfo.his_acfcomp = 1; 655 bcopy(cp, ackp, 2); 656 ackp += 2; 657 } else { 658#ifdef OLDMST 659 660 /* 661 * MorningStar before v1.3 needs NAK 662 */ 663 bcopy(cp, nakp, 2); 664 nakp += 2; 665#else 666 bcopy(cp, rejp, 2); 667 rejp += 2; 668 LcpInfo.my_reject |= (1 << type); 669#endif 670 } 671 break; 672 case MODE_NAK: 673 case MODE_REJ: 674 LcpInfo.want_acfcomp = 0; 675 LcpInfo.his_reject |= (1 << type); 676 break; 677 } 678 break; 679 case TY_SDP: 680 LogPrintf(LogLCP, " %s\n", request); 681 switch (mode) { 682 case MODE_REQ: 683 case MODE_NAK: 684 case MODE_REJ: 685 break; 686 } 687 break; 688 default: 689 LogPrintf(LogLCP, " ???[%02x]\n", type); 690 if (mode == MODE_REQ) { 691 reqreject: 692 bcopy(cp, rejp, length); 693 rejp += length; 694 LcpInfo.my_reject |= (1 << type); 695 } 696 break; 697 } 698 /* to avoid inf. loop */ 699 if (length == 0) { 700 LogPrintf(LogLCP, "LCP size zero\n"); 701 break; 702 } 703 plen -= length; 704 cp += length; 705 } 706} 707 708void 709LcpInput(struct mbuf * bp) 710{ 711 FsmInput(&LcpFsm, bp); 712} 713