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