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