1 /*- 2 * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $Id: datalink.c,v 1.1.2.34 1998/04/06 09:12:26 brian Exp $ 27 */ 28 29 #include <sys/types.h> 30 #include <netinet/in.h> 31 #include <netinet/in_systm.h> 32 #include <netinet/ip.h> 33 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #include <termios.h> 38 39 #include "mbuf.h" 40 #include "log.h" 41 #include "defs.h" 42 #include "timer.h" 43 #include "fsm.h" 44 #include "lcp.h" 45 #include "descriptor.h" 46 #include "lqr.h" 47 #include "hdlc.h" 48 #include "async.h" 49 #include "throughput.h" 50 #include "ccp.h" 51 #include "link.h" 52 #include "physical.h" 53 #include "iplist.h" 54 #include "slcompress.h" 55 #include "ipcp.h" 56 #include "filter.h" 57 #include "mp.h" 58 #include "bundle.h" 59 #include "chat.h" 60 #include "auth.h" 61 #include "modem.h" 62 #include "prompt.h" 63 #include "lcpproto.h" 64 #include "pap.h" 65 #include "chap.h" 66 #include "datalink.h" 67 68 static const char *datalink_State(struct datalink *); 69 70 static void 71 datalink_OpenTimeout(void *v) 72 { 73 struct datalink *dl = (struct datalink *)v; 74 75 StopTimer(&dl->dial_timer); 76 if (dl->state == DATALINK_OPENING) 77 LogPrintf(LogPHASE, "%s: Redial timer expired.\n", dl->name); 78 } 79 80 static void 81 datalink_StartDialTimer(struct datalink *dl, int Timeout) 82 { 83 StopTimer(&dl->dial_timer); 84 85 if (Timeout) { 86 dl->dial_timer.state = TIMER_STOPPED; 87 if (Timeout > 0) 88 dl->dial_timer.load = Timeout * SECTICKS; 89 else 90 dl->dial_timer.load = (random() % DIAL_TIMEOUT) * SECTICKS; 91 dl->dial_timer.func = datalink_OpenTimeout; 92 dl->dial_timer.name = "dial"; 93 dl->dial_timer.arg = dl; 94 StartTimer(&dl->dial_timer); 95 if (dl->state == DATALINK_OPENING) 96 LogPrintf(LogPHASE, "%s: Enter pause (%d) for redialing.\n", 97 dl->name, Timeout); 98 } 99 } 100 101 static void 102 datalink_HangupDone(struct datalink *dl) 103 { 104 modem_Close(dl->physical); 105 dl->phone.chosen = "[N/A]"; 106 107 if (dl->bundle->CleaningUp || 108 (mode & MODE_DIRECT) || 109 ((!dl->dial_tries || (dl->dial_tries < 0 && !dl->reconnect_tries)) && 110 !(mode & (MODE_DDIAL|MODE_DEDICATED)))) { 111 LogPrintf(LogPHASE, "%s: Entering CLOSED state\n", dl->name); 112 dl->state = DATALINK_CLOSED; 113 dl->dial_tries = -1; 114 dl->reconnect_tries = 0; 115 bundle_LinkClosed(dl->bundle, dl); 116 if (!dl->bundle->CleaningUp) 117 datalink_StartDialTimer(dl, dl->cfg.dial_timeout); 118 } else { 119 LogPrintf(LogPHASE, "%s: Re-entering OPENING state\n", dl->name); 120 dl->state = DATALINK_OPENING; 121 if (dl->dial_tries < 0) { 122 datalink_StartDialTimer(dl, dl->cfg.reconnect_timeout); 123 dl->dial_tries = dl->cfg.max_dial; 124 dl->reconnect_tries--; 125 } else { 126 if (dl->phone.next == NULL) 127 datalink_StartDialTimer(dl, dl->cfg.dial_timeout); 128 else 129 datalink_StartDialTimer(dl, dl->cfg.dial_next_timeout); 130 } 131 } 132 } 133 134 static const char * 135 datalink_ChoosePhoneNumber(struct datalink *dl) 136 { 137 char *phone; 138 139 if (dl->phone.alt == NULL) { 140 if (dl->phone.next == NULL) { 141 strncpy(dl->phone.list, dl->cfg.phone.list, sizeof dl->phone.list - 1); 142 dl->phone.list[sizeof dl->phone.list - 1] = '\0'; 143 dl->phone.next = dl->phone.list; 144 } 145 dl->phone.alt = strsep(&dl->phone.next, ":"); 146 } 147 phone = strsep(&dl->phone.alt, "|"); 148 dl->phone.chosen = *phone ? phone : "[NONE]"; 149 if (*phone) 150 LogPrintf(LogPHASE, "Phone: %s\n", phone); 151 return phone; 152 } 153 154 static void 155 datalink_LoginDone(struct datalink *dl) 156 { 157 if (!dl->script.packetmode) { 158 dl->dial_tries = -1; 159 LogPrintf(LogPHASE, "%s: Entering READY state\n", dl->name); 160 dl->state = DATALINK_READY; 161 } else if (modem_Raw(dl->physical, dl->bundle) < 0) { 162 dl->dial_tries = 0; 163 LogPrintf(LogWARN, "datalink_LoginDone: Not connected.\n"); 164 if (dl->script.run) { 165 LogPrintf(LogPHASE, "%s: Entering HANGUP state\n", dl->name); 166 dl->state = DATALINK_HANGUP; 167 modem_Offline(dl->physical); 168 chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL); 169 } else 170 datalink_HangupDone(dl); 171 } else { 172 dl->dial_tries = -1; 173 174 hdlc_Init(&dl->physical->hdlc); 175 async_Init(&dl->physical->async); 176 177 lcp_Setup(&dl->physical->link.lcp, dl->state == DATALINK_READY ? 178 0 : dl->physical->link.lcp.cfg.openmode); 179 ccp_Setup(&dl->physical->link.ccp); 180 181 LogPrintf(LogPHASE, "%s: Entering LCP state\n", dl->name); 182 dl->state = DATALINK_LCP; 183 FsmUp(&dl->physical->link.lcp.fsm); 184 FsmOpen(&dl->physical->link.lcp.fsm); 185 } 186 } 187 188 static int 189 datalink_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e, 190 int *n) 191 { 192 struct datalink *dl = descriptor2datalink(d); 193 int result; 194 195 result = 0; 196 switch (dl->state) { 197 case DATALINK_CLOSED: 198 break; 199 200 case DATALINK_OPENING: 201 if (dl->dial_timer.state != TIMER_RUNNING) { 202 if (--dl->dial_tries < 0) 203 dl->dial_tries = 0; 204 if (modem_Open(dl->physical, dl->bundle) >= 0) { 205 if (dl->script.run) { 206 LogPrintf(LogPHASE, "%s: Entering DIAL state\n", dl->name); 207 dl->state = DATALINK_DIAL; 208 chat_Init(&dl->chat, dl->physical, dl->cfg.script.dial, 1, 209 datalink_ChoosePhoneNumber(dl)); 210 if (!(mode & MODE_DDIAL) && dl->cfg.max_dial) 211 LogPrintf(LogCHAT, "%s: Dial attempt %u of %d\n", 212 dl->name, dl->cfg.max_dial - dl->dial_tries, 213 dl->cfg.max_dial); 214 } else 215 datalink_LoginDone(dl); 216 } else { 217 if (!(mode & MODE_DDIAL) && dl->cfg.max_dial) 218 LogPrintf(LogCHAT, "Failed to open modem (attempt %u of %d)\n", 219 dl->cfg.max_dial - dl->dial_tries, dl->cfg.max_dial); 220 else 221 LogPrintf(LogCHAT, "Failed to open modem\n"); 222 223 if (dl->bundle->CleaningUp || 224 (!(mode & (MODE_DDIAL|MODE_DEDICATED)) && 225 dl->cfg.max_dial && dl->dial_tries == 0)) { 226 LogPrintf(LogPHASE, "%s: Entering CLOSED state\n", dl->name); 227 dl->state = DATALINK_CLOSED; 228 dl->reconnect_tries = 0; 229 dl->dial_tries = -1; 230 bundle_LinkClosed(dl->bundle, dl); 231 } 232 if (!dl->bundle->CleaningUp) 233 datalink_StartDialTimer(dl, dl->cfg.dial_timeout); 234 } 235 } 236 break; 237 238 case DATALINK_HANGUP: 239 case DATALINK_DIAL: 240 case DATALINK_LOGIN: 241 result = descriptor_UpdateSet(&dl->chat.desc, r, w, e, n); 242 switch (dl->chat.state) { 243 case CHAT_DONE: 244 /* script succeeded */ 245 switch(dl->state) { 246 case DATALINK_HANGUP: 247 datalink_HangupDone(dl); 248 break; 249 case DATALINK_DIAL: 250 LogPrintf(LogPHASE, "%s: Entering LOGIN state\n", dl->name); 251 dl->state = DATALINK_LOGIN; 252 chat_Init(&dl->chat, dl->physical, dl->cfg.script.login, 0, NULL); 253 break; 254 case DATALINK_LOGIN: 255 datalink_LoginDone(dl); 256 break; 257 } 258 break; 259 case CHAT_FAILED: 260 /* Going down - script failed */ 261 LogPrintf(LogWARN, "Chat script failed\n"); 262 switch(dl->state) { 263 case DATALINK_HANGUP: 264 datalink_HangupDone(dl); 265 break; 266 case DATALINK_DIAL: 267 case DATALINK_LOGIN: 268 LogPrintf(LogPHASE, "%s: Entering HANGUP state\n", dl->name); 269 dl->state = DATALINK_HANGUP; 270 modem_Offline(dl->physical); 271 chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL); 272 break; 273 } 274 break; 275 } 276 break; 277 278 case DATALINK_READY: 279 case DATALINK_LCP: 280 case DATALINK_AUTH: 281 case DATALINK_OPEN: 282 result = descriptor_UpdateSet(&dl->physical->desc, r, w, e, n); 283 break; 284 } 285 return result; 286 } 287 288 static int 289 datalink_IsSet(struct descriptor *d, const fd_set *fdset) 290 { 291 struct datalink *dl = descriptor2datalink(d); 292 293 switch (dl->state) { 294 case DATALINK_CLOSED: 295 case DATALINK_OPENING: 296 break; 297 298 case DATALINK_HANGUP: 299 case DATALINK_DIAL: 300 case DATALINK_LOGIN: 301 return descriptor_IsSet(&dl->chat.desc, fdset); 302 303 case DATALINK_READY: 304 case DATALINK_LCP: 305 case DATALINK_AUTH: 306 case DATALINK_OPEN: 307 return descriptor_IsSet(&dl->physical->desc, fdset); 308 } 309 return 0; 310 } 311 312 static void 313 datalink_Read(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) 314 { 315 struct datalink *dl = descriptor2datalink(d); 316 317 switch (dl->state) { 318 case DATALINK_CLOSED: 319 case DATALINK_OPENING: 320 break; 321 322 case DATALINK_HANGUP: 323 case DATALINK_DIAL: 324 case DATALINK_LOGIN: 325 descriptor_Read(&dl->chat.desc, bundle, fdset); 326 break; 327 328 case DATALINK_READY: 329 case DATALINK_LCP: 330 case DATALINK_AUTH: 331 case DATALINK_OPEN: 332 descriptor_Read(&dl->physical->desc, bundle, fdset); 333 break; 334 } 335 } 336 337 static void 338 datalink_Write(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) 339 { 340 struct datalink *dl = descriptor2datalink(d); 341 342 switch (dl->state) { 343 case DATALINK_CLOSED: 344 case DATALINK_OPENING: 345 break; 346 347 case DATALINK_HANGUP: 348 case DATALINK_DIAL: 349 case DATALINK_LOGIN: 350 descriptor_Write(&dl->chat.desc, bundle, fdset); 351 break; 352 353 case DATALINK_READY: 354 case DATALINK_LCP: 355 case DATALINK_AUTH: 356 case DATALINK_OPEN: 357 descriptor_Write(&dl->physical->desc, bundle, fdset); 358 break; 359 } 360 } 361 362 static void 363 datalink_ComeDown(struct datalink *dl, int stay) 364 { 365 if (stay) { 366 dl->dial_tries = -1; 367 dl->reconnect_tries = 0; 368 } 369 370 if (dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP) { 371 modem_Offline(dl->physical); 372 if (dl->script.run && dl->state != DATALINK_OPENING) { 373 LogPrintf(LogPHASE, "%s: Entering HANGUP state\n", dl->name); 374 dl->state = DATALINK_HANGUP; 375 chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL); 376 } else 377 datalink_HangupDone(dl); 378 } 379 } 380 381 static void 382 datalink_LayerStart(void *v, struct fsm *fp) 383 { 384 /* The given FSM is about to start up ! */ 385 struct datalink *dl = (struct datalink *)v; 386 387 if (fp->proto == PROTO_LCP) 388 (*dl->parent->LayerStart)(dl->parent->object, fp); 389 } 390 391 static void 392 datalink_LayerUp(void *v, struct fsm *fp) 393 { 394 /* The given fsm is now up */ 395 struct datalink *dl = (struct datalink *)v; 396 397 if (fp->proto == PROTO_LCP) { 398 dl->physical->link.lcp.auth_ineed = dl->physical->link.lcp.want_auth; 399 dl->physical->link.lcp.auth_iwait = dl->physical->link.lcp.his_auth; 400 if (dl->physical->link.lcp.his_auth || dl->physical->link.lcp.want_auth) { 401 if (bundle_Phase(dl->bundle) == PHASE_ESTABLISH) 402 bundle_NewPhase(dl->bundle, PHASE_AUTHENTICATE); 403 LogPrintf(LogPHASE, "%s: his = %s, mine = %s\n", dl->name, 404 Auth2Nam(dl->physical->link.lcp.his_auth), 405 Auth2Nam(dl->physical->link.lcp.want_auth)); 406 if (dl->physical->link.lcp.his_auth == PROTO_PAP) 407 StartAuthChallenge(&dl->pap, dl->physical, SendPapChallenge); 408 if (dl->physical->link.lcp.want_auth == PROTO_CHAP) 409 StartAuthChallenge(&dl->chap.auth, dl->physical, SendChapChallenge); 410 } else 411 datalink_AuthOk(dl); 412 } 413 } 414 415 void 416 datalink_AuthOk(struct datalink *dl) 417 { 418 /* XXX: Connect to another ppp instance HERE */ 419 420 FsmUp(&dl->physical->link.ccp.fsm); 421 FsmOpen(&dl->physical->link.ccp.fsm); 422 dl->state = DATALINK_OPEN; 423 bundle_NewPhase(dl->bundle, PHASE_NETWORK); 424 (*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.lcp.fsm); 425 } 426 427 void 428 datalink_AuthNotOk(struct datalink *dl) 429 { 430 dl->state = DATALINK_LCP; 431 FsmClose(&dl->physical->link.lcp.fsm); 432 } 433 434 static void 435 datalink_LayerDown(void *v, struct fsm *fp) 436 { 437 /* The given FSM has been told to come down */ 438 struct datalink *dl = (struct datalink *)v; 439 440 if (fp->proto == PROTO_LCP) { 441 switch (dl->state) { 442 case DATALINK_OPEN: 443 FsmDown(&dl->physical->link.ccp.fsm); 444 FsmClose(&dl->physical->link.ccp.fsm); 445 (*dl->parent->LayerDown)(dl->parent->object, fp); 446 /* fall through */ 447 448 case DATALINK_AUTH: 449 StopTimer(&dl->pap.authtimer); 450 StopTimer(&dl->chap.auth.authtimer); 451 } 452 dl->state = DATALINK_LCP; 453 } 454 } 455 456 static void 457 datalink_LayerFinish(void *v, struct fsm *fp) 458 { 459 /* The given fsm is now down */ 460 struct datalink *dl = (struct datalink *)v; 461 462 if (fp->proto == PROTO_LCP) { 463 FsmDown(fp); /* Bring us to INITIAL or STARTING */ 464 (*dl->parent->LayerFinish)(dl->parent->object, fp); 465 datalink_ComeDown(dl, 0); 466 } 467 } 468 469 struct datalink * 470 datalink_Create(const char *name, struct bundle *bundle, 471 const struct fsm_parent *parent) 472 { 473 struct datalink *dl; 474 475 dl = (struct datalink *)malloc(sizeof(struct datalink)); 476 if (dl == NULL) 477 return dl; 478 479 dl->desc.type = DATALINK_DESCRIPTOR; 480 dl->desc.next = NULL; 481 dl->desc.UpdateSet = datalink_UpdateSet; 482 dl->desc.IsSet = datalink_IsSet; 483 dl->desc.Read = datalink_Read; 484 dl->desc.Write = datalink_Write; 485 486 dl->state = DATALINK_CLOSED; 487 488 *dl->cfg.script.dial = '\0'; 489 *dl->cfg.script.login = '\0'; 490 *dl->cfg.script.hangup = '\0'; 491 *dl->cfg.phone.list = '\0'; 492 *dl->phone.list = '\0'; 493 dl->phone.next = NULL; 494 dl->phone.alt = NULL; 495 dl->phone.chosen = "N/A"; 496 dl->script.run = 1; 497 dl->script.packetmode = 1; 498 mp_linkInit(&dl->mp); 499 500 dl->bundle = bundle; 501 dl->next = NULL; 502 503 memset(&dl->dial_timer, '\0', sizeof dl->dial_timer); 504 505 dl->dial_tries = 0; 506 dl->cfg.max_dial = 1; 507 dl->cfg.dial_timeout = DIAL_TIMEOUT; 508 dl->cfg.dial_next_timeout = DIAL_NEXT_TIMEOUT; 509 510 dl->reconnect_tries = 0; 511 dl->cfg.max_reconnect = 0; 512 dl->cfg.reconnect_timeout = RECONNECT_TIMEOUT; 513 514 dl->name = strdup(name); 515 dl->parent = parent; 516 dl->fsmp.LayerStart = datalink_LayerStart; 517 dl->fsmp.LayerUp = datalink_LayerUp; 518 dl->fsmp.LayerDown = datalink_LayerDown; 519 dl->fsmp.LayerFinish = datalink_LayerFinish; 520 dl->fsmp.object = dl; 521 522 authinfo_Init(&dl->pap); 523 authinfo_Init(&dl->chap.auth); 524 525 if ((dl->physical = modem_Create(dl)) == NULL) { 526 free(dl->name); 527 free(dl); 528 return NULL; 529 } 530 chat_Init(&dl->chat, dl->physical, NULL, 1, NULL); 531 532 LogPrintf(LogPHASE, "%s: Created in CLOSED state\n", dl->name); 533 534 return dl; 535 } 536 537 struct datalink * 538 datalink_Clone(struct datalink *odl, const char *name) 539 { 540 struct datalink *dl; 541 542 dl = (struct datalink *)malloc(sizeof(struct datalink)); 543 if (dl == NULL) 544 return dl; 545 546 dl->desc.type = DATALINK_DESCRIPTOR; 547 dl->desc.next = NULL; 548 dl->desc.UpdateSet = datalink_UpdateSet; 549 dl->desc.IsSet = datalink_IsSet; 550 dl->desc.Read = datalink_Read; 551 dl->desc.Write = datalink_Write; 552 553 dl->state = DATALINK_CLOSED; 554 555 memcpy(&dl->cfg, &odl->cfg, sizeof dl->cfg); 556 mp_linkInit(&dl->mp); 557 *dl->phone.list = '\0'; 558 dl->bundle = odl->bundle; 559 dl->next = NULL; 560 memset(&dl->dial_timer, '\0', sizeof dl->dial_timer); 561 dl->dial_tries = 0; 562 dl->reconnect_tries = 0; 563 dl->name = strdup(name); 564 dl->parent = odl->parent; 565 memcpy(&dl->fsmp, &odl->fsmp, sizeof dl->fsmp); 566 authinfo_Init(&dl->pap); 567 dl->pap.cfg.fsmretry = odl->pap.cfg.fsmretry; 568 569 authinfo_Init(&dl->chap.auth); 570 dl->chap.auth.cfg.fsmretry = odl->chap.auth.cfg.fsmretry; 571 572 if ((dl->physical = modem_Create(dl)) == NULL) { 573 free(dl->name); 574 free(dl); 575 return NULL; 576 } 577 memcpy(&dl->physical->cfg, &odl->physical->cfg, sizeof dl->physical->cfg); 578 memcpy(&dl->physical->link.lcp.cfg, &odl->physical->link.lcp.cfg, 579 sizeof dl->physical->link.lcp.cfg); 580 memcpy(&dl->physical->link.ccp.cfg, &odl->physical->link.ccp.cfg, 581 sizeof dl->physical->link.ccp.cfg); 582 memcpy(&dl->physical->async.cfg, &odl->physical->async.cfg, 583 sizeof dl->physical->async.cfg); 584 585 chat_Init(&dl->chat, dl->physical, NULL, 1, NULL); 586 587 LogPrintf(LogPHASE, "%s: Created in CLOSED state\n", dl->name); 588 589 return dl; 590 } 591 592 struct datalink * 593 datalink_Destroy(struct datalink *dl) 594 { 595 struct datalink *result; 596 597 if (dl->state != DATALINK_CLOSED) 598 LogPrintf(LogERROR, "Oops, destroying a datalink in state %s\n", 599 datalink_State(dl)); 600 601 result = dl->next; 602 chat_Destroy(&dl->chat); 603 modem_Destroy(dl->physical); 604 free(dl->name); 605 free(dl); 606 607 return result; 608 } 609 610 void 611 datalink_Up(struct datalink *dl, int runscripts, int packetmode) 612 { 613 switch (dl->state) { 614 case DATALINK_CLOSED: 615 LogPrintf(LogPHASE, "%s: Entering OPENING state\n", dl->name); 616 if (bundle_Phase(dl->bundle) == PHASE_DEAD || 617 bundle_Phase(dl->bundle) == PHASE_TERMINATE) 618 bundle_NewPhase(dl->bundle, PHASE_ESTABLISH); 619 dl->state = DATALINK_OPENING; 620 dl->reconnect_tries = dl->cfg.max_reconnect; 621 dl->dial_tries = dl->cfg.max_dial; 622 dl->script.run = runscripts; 623 dl->script.packetmode = packetmode; 624 break; 625 626 case DATALINK_OPENING: 627 if (!dl->script.run && runscripts) 628 dl->script.run = 1; 629 /* fall through */ 630 631 case DATALINK_DIAL: 632 case DATALINK_LOGIN: 633 case DATALINK_READY: 634 if (!dl->script.packetmode && packetmode) { 635 dl->script.packetmode = 1; 636 if (dl->state == DATALINK_READY) 637 datalink_LoginDone(dl); 638 } 639 break; 640 } 641 } 642 643 void 644 datalink_Close(struct datalink *dl, int stay) 645 { 646 /* Please close */ 647 switch (dl->state) { 648 case DATALINK_OPEN: 649 FsmDown(&dl->physical->link.ccp.fsm); 650 FsmClose(&dl->physical->link.ccp.fsm); 651 /* fall through */ 652 653 case DATALINK_AUTH: 654 case DATALINK_LCP: 655 FsmClose(&dl->physical->link.lcp.fsm); 656 if (stay) { 657 dl->dial_tries = -1; 658 dl->reconnect_tries = 0; 659 } 660 break; 661 662 default: 663 datalink_ComeDown(dl, stay); 664 } 665 } 666 667 void 668 datalink_Down(struct datalink *dl, int stay) 669 { 670 /* Carrier is lost */ 671 switch (dl->state) { 672 case DATALINK_OPEN: 673 FsmDown(&dl->physical->link.ccp.fsm); 674 FsmClose(&dl->physical->link.ccp.fsm); 675 /* fall through */ 676 677 case DATALINK_AUTH: 678 case DATALINK_LCP: 679 FsmDown(&dl->physical->link.lcp.fsm); 680 if (stay) 681 FsmClose(&dl->physical->link.lcp.fsm); 682 else 683 FsmOpen(&dl->physical->link.ccp.fsm); 684 /* fall through */ 685 686 default: 687 datalink_ComeDown(dl, stay); 688 } 689 } 690 691 void 692 datalink_StayDown(struct datalink *dl) 693 { 694 dl->reconnect_tries = 0; 695 } 696 697 void 698 datalink_Show(struct datalink *dl, struct prompt *prompt) 699 { 700 prompt_Printf(prompt, "Link %s: State %s\n", dl->name, datalink_State(dl)); 701 #ifdef HAVE_DES 702 prompt_Printf(arg->prompt, " Encryption = %s\n", 703 dl->chap.using_MSChap ? "MSChap" : "MD5" ); 704 #endif 705 } 706 707 static char *states[] = { 708 "CLOSED", 709 "OPENING", 710 "HANGUP", 711 "DIAL", 712 "LOGIN", 713 "READY", 714 "LCP" 715 "AUTH" 716 "OPEN" 717 }; 718 719 static const char * 720 datalink_State(struct datalink *dl) 721 { 722 if (dl->state < 0 || dl->state >= sizeof states / sizeof states[0]) 723 return "unknown"; 724 return states[dl->state]; 725 } 726