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.3 1995/03/11 15:18:45 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 OsLinkdown(); 376 NewPhase(PHASE_TERMINATE); 377 } 378 379 void 380 LcpUp() 381 { 382 FsmUp(&LcpFsm); 383 } 384 385 void 386 LcpDown() /* Sudden death */ 387 { 388 NewPhase(PHASE_DEAD); 389 StopAllTimers(); 390 FsmDown(&LcpFsm); 391 } 392 393 void 394 LcpOpen(mode) 395 int mode; 396 { 397 LcpFsm.open_mode = mode; 398 FsmOpen(&LcpFsm); 399 } 400 401 void 402 LcpClose() 403 { 404 FsmClose(&LcpFsm); 405 } 406 407 /* 408 * XXX: Should validate option length 409 */ 410 static void 411 LcpDecodeConfig(cp, plen, mode) 412 u_char *cp; 413 int plen; 414 int mode; 415 { 416 char *request; 417 int type, length, mru; 418 u_long *lp, magic, accmap; 419 u_short *sp, proto; 420 struct lqrreq *req; 421 422 ackp = AckBuff; 423 nakp = NakBuff; 424 rejp = RejBuff; 425 426 while (plen >= sizeof(struct fsmconfig)) { 427 type = *cp; 428 length = cp[1]; 429 if (type <= TY_ACFCOMP) 430 request = cftypes[type]; 431 else 432 request = "???"; 433 434 switch (type) { 435 case TY_MRU: 436 sp = (u_short *)(cp + 2); 437 mru = htons(*sp); 438 LogPrintf(LOG_LCP, " %s %d\n", request, mru); 439 440 switch (mode) { 441 case MODE_REQ: 442 if (mru > MAX_MRU) { 443 *sp = htons(MAX_MRU); 444 bcopy(cp, nakp, 4); nakp += 4; 445 } else if (mru < MIN_MRU) { 446 *sp = htons(MIN_MRU); 447 bcopy(cp, nakp, 4); nakp += 4; 448 } else { 449 LcpInfo.his_mru = mru; 450 bcopy(cp, ackp, 4); ackp += 4; 451 } 452 break; 453 case MODE_NAK: 454 if (mru >= MIN_MRU || mru <= MAX_MRU) 455 LcpInfo.want_mru = mru; 456 break; 457 case MODE_REJ: 458 LcpInfo.his_reject |= (1 << type); 459 break; 460 } 461 break; 462 case TY_ACCMAP: 463 lp = (u_long *)(cp + 2); 464 accmap = htonl(*lp); 465 LogPrintf(LOG_LCP, " %s %08x\n", request, accmap); 466 467 switch (mode) { 468 case MODE_REQ: 469 LcpInfo.his_accmap = accmap; 470 bcopy(cp, ackp, 6); ackp += 6; 471 break; 472 case MODE_NAK: 473 LcpInfo.want_accmap = accmap; 474 break; 475 case MODE_REJ: 476 LcpInfo.his_reject |= (1 << type); 477 break; 478 } 479 break; 480 case TY_AUTHPROTO: 481 sp = (u_short *)(cp + 2); 482 proto = ntohs(*sp); 483 LogPrintf(LOG_LCP, " %s proto = %04x\n", request, proto); 484 485 switch (mode) { 486 case MODE_REQ: 487 switch (proto) { 488 case PROTO_PAP: 489 if (length != 4) { 490 LogPrintf(LOG_LCP, " %s bad length (%d)\n", request, length); 491 goto reqreject; 492 } 493 if (Acceptable(ConfPap)) { 494 LcpInfo.his_auth = proto; 495 bcopy(cp, ackp, length); ackp += length; 496 } else if (Acceptable(ConfChap)) { 497 *nakp++ = *cp; *nakp++ = 5; 498 *nakp++ = (unsigned char)(PROTO_CHAP >> 8); 499 *nakp++ = (unsigned char)PROTO_CHAP; 500 *nakp++ = 5; 501 } else 502 goto reqreject; 503 break; 504 case PROTO_CHAP: 505 if (length < 5) { 506 LogPrintf(LOG_LCP, " %s bad length (%d)\n", request, length); 507 goto reqreject; 508 } 509 if (Acceptable(ConfChap) && cp[4] == 5) { 510 LcpInfo.his_auth = proto; 511 bcopy(cp, ackp, length); ackp += length; 512 } else if (Acceptable(ConfPap)) { 513 *nakp++ = *cp; *nakp++ = 4; 514 *nakp++ = (unsigned char)(PROTO_PAP >> 8); 515 *nakp++ = (unsigned char)PROTO_PAP; 516 } else 517 goto reqreject; 518 break; 519 default: 520 LogPrintf(LOG_LCP, " %s not implemented.\n", request); 521 goto reqreject; 522 } 523 break; 524 case MODE_NAK: 525 break; 526 case MODE_REJ: 527 LcpInfo.his_reject |= (1 << type); 528 break; 529 } 530 break; 531 case TY_QUALPROTO: 532 req = (struct lqrreq *)cp; 533 LogPrintf(LOG_LCP, " %s proto: %x, interval: %dms\n", 534 request, ntohs(req->proto), ntohl(req->period)*10); 535 switch (mode) { 536 case MODE_REQ: 537 if (ntohs(req->proto) != PROTO_LQR || !Acceptable(ConfLqr)) 538 goto reqreject; 539 else { 540 LcpInfo.his_lqrperiod = ntohl(req->period); 541 if (LcpInfo.his_lqrperiod < 500) 542 LcpInfo.his_lqrperiod = 500; 543 req->period = htonl(LcpInfo.his_lqrperiod); 544 bcopy(cp, ackp, length); ackp += length; 545 } 546 break; 547 case MODE_NAK: 548 break; 549 case MODE_REJ: 550 LcpInfo.his_reject |= (1 << type); 551 break; 552 } 553 break; 554 case TY_MAGICNUM: 555 lp = (u_long *)(cp + 2); 556 magic = ntohl(*lp); 557 LogPrintf(LOG_LCP, " %s %08x\n", request, magic); 558 559 switch (mode) { 560 case MODE_REQ: 561 if (LcpInfo.want_magic) { 562 /* XXX: Shoud validate magic number */ 563 if (magic == LcpInfo.want_magic) 564 logprintf("magic is same!! %x, %x, %x\n", 565 magic, LcpInfo.want_magic, LcpInfo.his_magic); 566 LcpInfo.his_magic = magic; 567 bcopy(cp, ackp, length); ackp += length; 568 } else { 569 LcpInfo.my_reject |= (1 << type); 570 goto reqreject; 571 } 572 break; 573 case MODE_NAK: 574 LogPrintf(LOG_LCP, " %s magic %08x has NAKed\n", request, magic); 575 LcpInfo.want_magic = GenerateMagic(); 576 break; 577 case MODE_REJ: 578 LogPrintf(LOG_LCP, " %s magic has REJected\n", request); 579 LcpInfo.want_magic = 0; 580 LcpInfo.his_reject |= (1 << type); 581 break; 582 } 583 break; 584 case TY_PROTOCOMP: 585 LogPrintf(LOG_LCP, " %s\n", request); 586 587 switch (mode) { 588 case MODE_REQ: 589 if (Acceptable(ConfProtocomp)) { 590 LcpInfo.his_protocomp = 1; 591 bcopy(cp, ackp, 2); ackp += 2; 592 } else { 593 #ifdef OLDMST 594 /* 595 * MorningStar before v1.3 needs NAK 596 */ 597 bcopy(cp, nakp, 2); nakp += 2; 598 #else 599 bcopy(cp, rejp, 2); rejp += 2; 600 LcpInfo.my_reject |= (1 << type); 601 #endif 602 } 603 break; 604 case MODE_NAK: 605 case MODE_REJ: 606 LcpInfo.want_protocomp = 0; 607 LcpInfo.his_reject |= (1 << type); 608 break; 609 } 610 break; 611 case TY_ACFCOMP: 612 LogPrintf(LOG_LCP, " %s\n", request); 613 switch (mode) { 614 case MODE_REQ: 615 if (Acceptable(ConfAcfcomp)) { 616 LcpInfo.his_acfcomp = 1; 617 bcopy(cp, ackp, 2); 618 ackp += 2; 619 } else { 620 #ifdef OLDMST 621 /* 622 * MorningStar before v1.3 needs NAK 623 */ 624 bcopy(cp, nakp, 2); 625 nakp += 2; 626 #else 627 bcopy(cp, rejp, 2); 628 rejp += 2; 629 LcpInfo.my_reject |= (1 << type); 630 #endif 631 } 632 break; 633 case MODE_NAK: 634 case MODE_REJ: 635 LcpInfo.want_acfcomp = 0; 636 LcpInfo.his_reject |= (1 << type); 637 break; 638 } 639 break; 640 case TY_SDP: 641 LogPrintf(LOG_LCP, " %s\n", request); 642 switch (mode) { 643 case MODE_REQ: 644 case MODE_NAK: 645 case MODE_REJ: 646 break; 647 } 648 break; 649 default: 650 LogPrintf(LOG_LCP, " ???[%02x]\n", type); 651 if (mode == MODE_REQ) { 652 reqreject: 653 bcopy(cp, rejp, length); 654 rejp += length; 655 LcpInfo.my_reject |= (1 << type); 656 } 657 break; 658 } 659 plen -= length; 660 cp += length; 661 } 662 } 663 664 void 665 LcpInput(struct mbuf *bp) 666 { 667 FsmInput(&LcpFsm, bp); 668 } 669