lcp.c revision 29729
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.32 1997/09/22 02:51:24 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 <netinet/in.h> 28#include <arpa/inet.h> 29#include <signal.h> 30#include "fsm.h" 31#include "lcp.h" 32#include "ipcp.h" 33#include "lcpproto.h" 34#include "os.h" 35#include "hdlc.h" 36#include "ccp.h" 37#include "lqr.h" 38#include "phase.h" 39#include "loadalias.h" 40#include "vars.h" 41#include "auth.h" 42#include "timeout.h" 43 44extern void IpcpUp(); 45extern void IpcpOpen(); 46extern void SetLinkParams(struct lcpstate *); 47extern void Prompt(); 48extern void Cleanup(); 49extern struct pppTimer IpcpReportTimer; 50extern int randinit; 51 52struct lcpstate LcpInfo; 53 54static void LcpSendConfigReq(struct fsm *); 55static void LcpSendTerminateReq(struct fsm * fp); 56static void LcpSendTerminateAck(struct fsm * fp); 57static void LcpDecodeConfig(u_char * cp, int flen, int mode); 58static void LcpInitRestartCounter(struct fsm *); 59static void LcpLayerUp(struct fsm *); 60static void LcpLayerDown(struct fsm *); 61static void LcpLayerStart(struct fsm *); 62static void LcpLayerFinish(struct fsm *); 63 64extern int ModemSpeed(); 65 66#define REJECTED(p, x) (p->his_reject & (1<<x)) 67 68static char *cftypes[] = { 69 "???", "MRU", "ACCMAP", "AUTHPROTO", "QUALPROTO", "MAGICNUM", 70 "RESERVED", "PROTOCOMP", "ACFCOMP", "FCSALT", "SDP", 71}; 72 73struct fsm LcpFsm = { 74 "LCP", /* Name of protocol */ 75 PROTO_LCP, /* Protocol Number */ 76 LCP_MAXCODE, 77 OPEN_ACTIVE, 78 ST_INITIAL, /* State of machine */ 79 0, 0, 0, 80 0, 81 {0, 0, 0, NULL, NULL, NULL}, 82 {0, 0, 0, NULL, NULL, NULL}, 83 LogLCP, 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; 97static int LcpFailedMagic; 98 99char *PhaseNames[] = { 100 "Dead", "Establish", "Authenticate", "Network", "Terminate" 101}; 102 103void 104NewPhase(int 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\n", 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 srandomdev(); 187 } 188 return (random()); 189} 190 191void 192LcpInit() 193{ 194 struct lcpstate *lcp = &LcpInfo; 195 196 FsmInit(&LcpFsm); 197 HdlcInit(); 198 199 bzero(lcp, sizeof(struct lcpstate)); 200 lcp->want_mru = VarMRU; 201 lcp->his_mru = DEF_MRU; 202 lcp->his_accmap = 0xffffffff; 203 lcp->want_accmap = VarAccmap; 204 lcp->want_magic = GenerateMagic(); 205 lcp->want_auth = lcp->his_auth = 0; 206 if (Enabled(ConfChap)) 207 lcp->want_auth = PROTO_CHAP; 208 else if (Enabled(ConfPap)) 209 lcp->want_auth = PROTO_PAP; 210 if (Enabled(ConfLqr)) 211 lcp->want_lqrperiod = VarLqrTimeout * 100; 212 if (Enabled(ConfAcfcomp)) 213 lcp->want_acfcomp = 1; 214 if (Enabled(ConfProtocomp)) 215 lcp->want_protocomp = 1; 216 LcpFsm.maxconfig = 10; 217} 218 219static void 220LcpInitRestartCounter(struct fsm * fp) 221{ 222 fp->FsmTimer.load = VarRetryTimeout * SECTICKS; 223 fp->restart = 5; 224} 225 226void 227PutConfValue(u_char ** cpp, char **types, u_char type, int len, u_long val) 228{ 229 u_char *cp; 230 struct in_addr ina; 231 232 cp = *cpp; 233 *cp++ = type; 234 *cp++ = len; 235 if (len == 6) { 236 if (type == TY_IPADDR) { 237 ina.s_addr = htonl(val); 238 LogPrintf(LogLCP, " %s [%d] %s\n", 239 types[type], len, inet_ntoa(ina)); 240 } else { 241 LogPrintf(LogLCP, " %s [%d] %08x\n", types[type], len, val); 242 } 243 *cp++ = (val >> 24) & 0377; 244 *cp++ = (val >> 16) & 0377; 245 } else 246 LogPrintf(LogLCP, " %s [%d] %d\n", types[type], len, val); 247 *cp++ = (val >> 8) & 0377; 248 *cp++ = val & 0377; 249 *cpp = cp; 250} 251 252static void 253LcpSendConfigReq(struct fsm * fp) 254{ 255 u_char *cp; 256 struct lcpstate *lcp = &LcpInfo; 257 struct lqrreq *req; 258 259 LogPrintf(LogLCP, "LcpSendConfigReq\n"); 260 cp = ReqBuff; 261 if (!DEV_IS_SYNC) { 262 if (lcp->want_acfcomp && !REJECTED(lcp, TY_ACFCOMP)) { 263 *cp++ = TY_ACFCOMP; 264 *cp++ = 2; 265 LogPrintf(LogLCP, " %s\n", cftypes[TY_ACFCOMP]); 266 } 267 if (lcp->want_protocomp && !REJECTED(lcp, TY_PROTOCOMP)) { 268 *cp++ = TY_PROTOCOMP; 269 *cp++ = 2; 270 LogPrintf(LogLCP, " %s\n", cftypes[TY_PROTOCOMP]); 271 } 272 if (!REJECTED(lcp, TY_ACCMAP)) 273 PutConfValue(&cp, cftypes, TY_ACCMAP, 6, lcp->want_accmap); 274 } 275 if (!REJECTED(lcp, TY_MRU)) 276 PutConfValue(&cp, cftypes, TY_MRU, 4, lcp->want_mru); 277 if (lcp->want_magic && !REJECTED(lcp, TY_MAGICNUM)) 278 PutConfValue(&cp, cftypes, TY_MAGICNUM, 6, lcp->want_magic); 279 if (lcp->want_lqrperiod && !REJECTED(lcp, TY_QUALPROTO)) { 280 req = (struct lqrreq *) cp; 281 req->type = TY_QUALPROTO; 282 req->length = sizeof(struct lqrreq); 283 req->proto = htons(PROTO_LQR); 284 req->period = htonl(lcp->want_lqrperiod); 285 cp += sizeof(struct lqrreq); 286 LogPrintf(LogLCP, " %s (%d)\n", cftypes[TY_QUALPROTO], lcp->want_lqrperiod); 287 } 288 switch (lcp->want_auth) { 289 case PROTO_PAP: 290 PutConfValue(&cp, cftypes, TY_AUTHPROTO, 4, lcp->want_auth); 291 break; 292 case PROTO_CHAP: 293 PutConfValue(&cp, cftypes, TY_AUTHPROTO, 5, lcp->want_auth); 294 *cp++ = VarEncMD4 ? 0x80 : 0x05; /* Use MD4/MD5 */ 295 break; 296 } 297 FsmOutput(fp, CODE_CONFIGREQ, fp->reqid++, ReqBuff, cp - ReqBuff); 298} 299 300void 301LcpSendProtoRej(u_char * option, int count) 302{ 303 struct fsm *fp = &LcpFsm; 304 305 LogPrintf(LogLCP, "LcpSendProtoRej\n"); 306 FsmOutput(fp, CODE_PROTOREJ, fp->reqid, option, count); 307} 308 309static void 310LcpSendTerminateReq(struct fsm * fp) 311{ 312 /* Most thins are done in fsm layer. Nothing to to. */ 313} 314 315static void 316LcpSendTerminateAck(struct fsm * fp) 317{ 318 LogPrintf(LogLCP, "LcpSendTerminateAck.\n"); 319 FsmOutput(fp, CODE_TERMACK, fp->reqid++, NULL, 0); 320} 321 322static void 323LcpLayerStart(struct fsm * fp) 324{ 325 LogPrintf(LogLCP, "LcpLayerStart\n"); 326 NewPhase(PHASE_ESTABLISH); 327} 328 329static void 330StopAllTimers() 331{ 332 StopTimer(&LcpReportTimer); 333 StopTimer(&IpcpReportTimer); 334 StopIdleTimer(); 335 StopTimer(&AuthPapInfo.authtimer); 336 StopTimer(&AuthChapInfo.authtimer); 337 StopLqrTimer(); 338} 339 340static void 341LcpLayerFinish(struct fsm * fp) 342{ 343 LogPrintf(LogLCP, "LcpLayerFinish\n"); 344 OsCloseLink(1); 345 NewPhase(PHASE_DEAD); 346 StopAllTimers(); 347 (void) OsInterfaceDown(0); 348 Prompt(); 349} 350 351static void 352LcpLayerUp(struct fsm * fp) 353{ 354 LogPrintf(LogLCP, "LcpLayerUp\n"); 355 OsSetInterfaceParams(23, LcpInfo.his_mru, ModemSpeed()); 356 SetLinkParams(&LcpInfo); 357 358 NewPhase(PHASE_AUTHENTICATE); 359 360 StartLqm(); 361 StopTimer(&LcpReportTimer); 362 LcpReportTimer.state = TIMER_STOPPED; 363 LcpReportTimer.load = 60 * SECTICKS; 364 LcpReportTimer.func = LcpReportTime; 365 StartTimer(&LcpReportTimer); 366} 367 368static void 369LcpLayerDown(struct fsm * fp) 370{ 371 StopAllTimers(); 372 OsLinkdown(); 373 LogPrintf(LogLCP, "LcpLayerDown\n"); 374 NewPhase(PHASE_TERMINATE); 375} 376 377void 378LcpUp() 379{ 380 FsmUp(&LcpFsm); 381 LcpFailedMagic = 0; 382} 383 384void 385LcpDown() 386{ /* Sudden death */ 387 LcpFailedMagic = 0; 388 NewPhase(PHASE_DEAD); 389 StopAllTimers(); 390 FsmDown(&LcpFsm); 391} 392 393void 394LcpOpen(int mode) 395{ 396 LcpFsm.open_mode = mode; 397 LcpFailedMagic = 0; 398 FsmOpen(&LcpFsm); 399} 400 401void 402LcpClose() 403{ 404 FsmClose(&LcpFsm); 405 LcpFailedMagic = 0; 406} 407 408/* 409 * XXX: Should validate option length 410 */ 411static void 412LcpDecodeConfig(u_char * cp, int plen, int mode) 413{ 414 char *request; 415 int type, length, mru; 416 u_long *lp, magic, accmap; 417 u_short *sp, proto; 418 struct lqrreq *req; 419 420 ackp = AckBuff; 421 nakp = NakBuff; 422 rejp = RejBuff; 423 424 while (plen >= sizeof(struct fsmconfig)) { 425 type = *cp; 426 length = cp[1]; 427 if (type <= TY_ACFCOMP) 428 request = cftypes[type]; 429 else 430 request = "???"; 431 432 switch (type) { 433 case TY_MRU: 434 sp = (u_short *) (cp + 2); 435 mru = htons(*sp); 436 LogPrintf(LogLCP, " %s %d\n", request, mru); 437 438 switch (mode) { 439 case MODE_REQ: 440 if (mru > MAX_MRU) { 441 *sp = htons(MAX_MRU); 442 bcopy(cp, nakp, 4); 443 nakp += 4; 444 } else if (mru < MIN_MRU) { 445 *sp = htons(MIN_MRU); 446 bcopy(cp, nakp, 4); 447 nakp += 4; 448 } else { 449 LcpInfo.his_mru = mru; 450 bcopy(cp, ackp, 4); 451 ackp += 4; 452 } 453 break; 454 case MODE_NAK: 455 if (mru >= MIN_MRU || mru <= MAX_MRU) 456 LcpInfo.want_mru = mru; 457 break; 458 case MODE_REJ: 459 LcpInfo.his_reject |= (1 << type); 460 break; 461 } 462 break; 463 case TY_ACCMAP: 464 lp = (u_long *) (cp + 2); 465 accmap = htonl(*lp); 466 LogPrintf(LogLCP, " %s %08x\n", request, accmap); 467 468 switch (mode) { 469 case MODE_REQ: 470 LcpInfo.his_accmap = accmap; 471 bcopy(cp, ackp, 6); 472 ackp += 6; 473 break; 474 case MODE_NAK: 475 LcpInfo.want_accmap = accmap; 476 break; 477 case MODE_REJ: 478 LcpInfo.his_reject |= (1 << type); 479 break; 480 } 481 break; 482 case TY_AUTHPROTO: 483 sp = (u_short *) (cp + 2); 484 proto = ntohs(*sp); 485 LogPrintf(LogLCP, " %s proto = %04x\n", request, proto); 486 487 switch (mode) { 488 case MODE_REQ: 489 switch (proto) { 490 case PROTO_PAP: 491 if (length != 4) { 492 LogPrintf(LogLCP, " %s bad length (%d)\n", request, length); 493 goto reqreject; 494 } 495 if (Acceptable(ConfPap)) { 496 LcpInfo.his_auth = proto; 497 bcopy(cp, ackp, length); 498 ackp += length; 499 } else if (Acceptable(ConfChap)) { 500 *nakp++ = *cp; 501 *nakp++ = 5; 502 *nakp++ = (unsigned char) (PROTO_CHAP >> 8); 503 *nakp++ = (unsigned char) PROTO_CHAP; 504 *nakp++ = 5; 505 } else 506 goto reqreject; 507 break; 508 case PROTO_CHAP: 509 if (length < 5) { 510 LogPrintf(LogLCP, " %s bad length (%d)\n", request, length); 511 goto reqreject; 512 } 513 if (Acceptable(ConfChap) && (cp[4] == 5 || cp[4] == 0x80)) { 514 LcpInfo.his_auth = proto; 515 bcopy(cp, ackp, length); 516 ackp += length; 517 VarEncMD4 = cp[4] == 0x80; 518 } else if (Acceptable(ConfPap)) { 519 *nakp++ = *cp; 520 *nakp++ = 4; 521 *nakp++ = (unsigned char) (PROTO_PAP >> 8); 522 *nakp++ = (unsigned char) PROTO_PAP; 523 } else 524 goto reqreject; 525 break; 526 default: 527 LogPrintf(LogLCP, " %s not implemented, NAK.\n", request); 528 bcopy(cp, nakp, length); 529 nakp += length; 530 break; 531 } 532 break; 533 case MODE_NAK: 534 break; 535 case MODE_REJ: 536 LcpInfo.his_reject |= (1 << type); 537 break; 538 } 539 break; 540 case TY_QUALPROTO: 541 req = (struct lqrreq *) cp; 542 LogPrintf(LogLCP, " %s proto: %x, interval: %dms\n", 543 request, ntohs(req->proto), ntohl(req->period) * 10); 544 switch (mode) { 545 case MODE_REQ: 546 if (ntohs(req->proto) != PROTO_LQR || !Acceptable(ConfLqr)) 547 goto reqreject; 548 else { 549 LcpInfo.his_lqrperiod = ntohl(req->period); 550 if (LcpInfo.his_lqrperiod < 500) 551 LcpInfo.his_lqrperiod = 500; 552 req->period = htonl(LcpInfo.his_lqrperiod); 553 bcopy(cp, ackp, length); 554 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) - %d times\n", 575 magic, ++LcpFailedMagic); 576 LcpInfo.want_magic = GenerateMagic(); 577 bcopy(cp, nakp, 6); 578 nakp += 6; 579 ualarm(TICKUNIT * (4 + 4 * LcpFailedMagic), 0); 580 sigpause(0); 581 } else { 582 LcpInfo.his_magic = magic; 583 bcopy(cp, ackp, length); 584 ackp += length; 585 LcpFailedMagic = 0; 586 } 587 } else { 588 LcpInfo.my_reject |= (1 << type); 589 goto reqreject; 590 } 591 break; 592 case MODE_NAK: 593 LogPrintf(LogLCP, " %s magic %08x has NAKed\n", request, magic); 594 LcpInfo.want_magic = GenerateMagic(); 595 break; 596 case MODE_REJ: 597 LogPrintf(LogLCP, " %s magic has REJected\n", request); 598 LcpInfo.want_magic = 0; 599 LcpInfo.his_reject |= (1 << type); 600 break; 601 } 602 break; 603 case TY_PROTOCOMP: 604 LogPrintf(LogLCP, " %s\n", request); 605 606 switch (mode) { 607 case MODE_REQ: 608 if (Acceptable(ConfProtocomp)) { 609 LcpInfo.his_protocomp = 1; 610 bcopy(cp, ackp, 2); 611 ackp += 2; 612 } else { 613#ifdef OLDMST 614 615 /* 616 * MorningStar before v1.3 needs NAK 617 */ 618 bcopy(cp, nakp, 2); 619 nakp += 2; 620#else 621 bcopy(cp, rejp, 2); 622 rejp += 2; 623 LcpInfo.my_reject |= (1 << type); 624#endif 625 } 626 break; 627 case MODE_NAK: 628 case MODE_REJ: 629 LcpInfo.want_protocomp = 0; 630 LcpInfo.his_reject |= (1 << type); 631 break; 632 } 633 break; 634 case TY_ACFCOMP: 635 LogPrintf(LogLCP, " %s\n", request); 636 switch (mode) { 637 case MODE_REQ: 638 if (Acceptable(ConfAcfcomp)) { 639 LcpInfo.his_acfcomp = 1; 640 bcopy(cp, ackp, 2); 641 ackp += 2; 642 } else { 643#ifdef OLDMST 644 645 /* 646 * MorningStar before v1.3 needs NAK 647 */ 648 bcopy(cp, nakp, 2); 649 nakp += 2; 650#else 651 bcopy(cp, rejp, 2); 652 rejp += 2; 653 LcpInfo.my_reject |= (1 << type); 654#endif 655 } 656 break; 657 case MODE_NAK: 658 case MODE_REJ: 659 LcpInfo.want_acfcomp = 0; 660 LcpInfo.his_reject |= (1 << type); 661 break; 662 } 663 break; 664 case TY_SDP: 665 LogPrintf(LogLCP, " %s\n", request); 666 switch (mode) { 667 case MODE_REQ: 668 case MODE_NAK: 669 case MODE_REJ: 670 break; 671 } 672 break; 673 default: 674 LogPrintf(LogLCP, " ???[%02x]\n", type); 675 if (mode == MODE_REQ) { 676 reqreject: 677 bcopy(cp, rejp, length); 678 rejp += length; 679 LcpInfo.my_reject |= (1 << type); 680 } 681 break; 682 } 683 /* to avoid inf. loop */ 684 if (length == 0) { 685 LogPrintf(LogLCP, "LCP size zero\n"); 686 break; 687 } 688 plen -= length; 689 cp += length; 690 } 691} 692 693void 694LcpInput(struct mbuf * bp) 695{ 696 FsmInput(&LcpFsm, bp); 697} 698