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