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