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