lcp.c revision 29744
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.33 1997/09/22 23:59:14 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++ = 5; /* 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) { 514 LcpInfo.his_auth = proto; 515 bcopy(cp, ackp, length); 516 ackp += length; 517 } else if (Acceptable(ConfPap)) { 518 *nakp++ = *cp; 519 *nakp++ = 4; 520 *nakp++ = (unsigned char) (PROTO_PAP >> 8); 521 *nakp++ = (unsigned char) PROTO_PAP; 522 } else 523 goto reqreject; 524 break; 525 default: 526 LogPrintf(LogLCP, " %s not implemented, NAK.\n", request); 527 bcopy(cp, nakp, length); 528 nakp += length; 529 break; 530 } 531 break; 532 case MODE_NAK: 533 break; 534 case MODE_REJ: 535 LcpInfo.his_reject |= (1 << type); 536 break; 537 } 538 break; 539 case TY_QUALPROTO: 540 req = (struct lqrreq *) cp; 541 LogPrintf(LogLCP, " %s proto: %x, interval: %dms\n", 542 request, ntohs(req->proto), ntohl(req->period) * 10); 543 switch (mode) { 544 case MODE_REQ: 545 if (ntohs(req->proto) != PROTO_LQR || !Acceptable(ConfLqr)) 546 goto reqreject; 547 else { 548 LcpInfo.his_lqrperiod = ntohl(req->period); 549 if (LcpInfo.his_lqrperiod < 500) 550 LcpInfo.his_lqrperiod = 500; 551 req->period = htonl(LcpInfo.his_lqrperiod); 552 bcopy(cp, ackp, length); 553 ackp += length; 554 } 555 break; 556 case MODE_NAK: 557 break; 558 case MODE_REJ: 559 LcpInfo.his_reject |= (1 << type); 560 break; 561 } 562 break; 563 case TY_MAGICNUM: 564 lp = (u_long *) (cp + 2); 565 magic = ntohl(*lp); 566 LogPrintf(LogLCP, " %s %08x\n", request, magic); 567 568 switch (mode) { 569 case MODE_REQ: 570 if (LcpInfo.want_magic) { 571 /* Validate magic number */ 572 if (magic == LcpInfo.want_magic) { 573 LogPrintf(LogLCP, "Magic is same (%08x) - %d times\n", 574 magic, ++LcpFailedMagic); 575 LcpInfo.want_magic = GenerateMagic(); 576 bcopy(cp, nakp, 6); 577 nakp += 6; 578 ualarm(TICKUNIT * (4 + 4 * LcpFailedMagic), 0); 579 sigpause(0); 580 } else { 581 LcpInfo.his_magic = magic; 582 bcopy(cp, ackp, length); 583 ackp += length; 584 LcpFailedMagic = 0; 585 } 586 } else { 587 LcpInfo.my_reject |= (1 << type); 588 goto reqreject; 589 } 590 break; 591 case MODE_NAK: 592 LogPrintf(LogLCP, " %s magic %08x has NAKed\n", request, magic); 593 LcpInfo.want_magic = GenerateMagic(); 594 break; 595 case MODE_REJ: 596 LogPrintf(LogLCP, " %s magic has REJected\n", request); 597 LcpInfo.want_magic = 0; 598 LcpInfo.his_reject |= (1 << type); 599 break; 600 } 601 break; 602 case TY_PROTOCOMP: 603 LogPrintf(LogLCP, " %s\n", request); 604 605 switch (mode) { 606 case MODE_REQ: 607 if (Acceptable(ConfProtocomp)) { 608 LcpInfo.his_protocomp = 1; 609 bcopy(cp, ackp, 2); 610 ackp += 2; 611 } else { 612#ifdef OLDMST 613 614 /* 615 * MorningStar before v1.3 needs NAK 616 */ 617 bcopy(cp, nakp, 2); 618 nakp += 2; 619#else 620 bcopy(cp, rejp, 2); 621 rejp += 2; 622 LcpInfo.my_reject |= (1 << type); 623#endif 624 } 625 break; 626 case MODE_NAK: 627 case MODE_REJ: 628 LcpInfo.want_protocomp = 0; 629 LcpInfo.his_reject |= (1 << type); 630 break; 631 } 632 break; 633 case TY_ACFCOMP: 634 LogPrintf(LogLCP, " %s\n", request); 635 switch (mode) { 636 case MODE_REQ: 637 if (Acceptable(ConfAcfcomp)) { 638 LcpInfo.his_acfcomp = 1; 639 bcopy(cp, ackp, 2); 640 ackp += 2; 641 } else { 642#ifdef OLDMST 643 644 /* 645 * MorningStar before v1.3 needs NAK 646 */ 647 bcopy(cp, nakp, 2); 648 nakp += 2; 649#else 650 bcopy(cp, rejp, 2); 651 rejp += 2; 652 LcpInfo.my_reject |= (1 << type); 653#endif 654 } 655 break; 656 case MODE_NAK: 657 case MODE_REJ: 658 LcpInfo.want_acfcomp = 0; 659 LcpInfo.his_reject |= (1 << type); 660 break; 661 } 662 break; 663 case TY_SDP: 664 LogPrintf(LogLCP, " %s\n", request); 665 switch (mode) { 666 case MODE_REQ: 667 case MODE_NAK: 668 case MODE_REJ: 669 break; 670 } 671 break; 672 default: 673 LogPrintf(LogLCP, " ???[%02x]\n", type); 674 if (mode == MODE_REQ) { 675 reqreject: 676 bcopy(cp, rejp, length); 677 rejp += length; 678 LcpInfo.my_reject |= (1 << type); 679 } 680 break; 681 } 682 /* to avoid inf. loop */ 683 if (length == 0) { 684 LogPrintf(LogLCP, "LCP size zero\n"); 685 break; 686 } 687 plen -= length; 688 cp += length; 689 } 690} 691 692void 693LcpInput(struct mbuf * bp) 694{ 695 FsmInput(&LcpFsm, bp); 696} 697