13006ec67SBrian Somers /*- 23006ec67SBrian Somers * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org> 33006ec67SBrian Somers * All rights reserved. 43006ec67SBrian Somers * 53006ec67SBrian Somers * Redistribution and use in source and binary forms, with or without 63006ec67SBrian Somers * modification, are permitted provided that the following conditions 73006ec67SBrian Somers * are met: 83006ec67SBrian Somers * 1. Redistributions of source code must retain the above copyright 93006ec67SBrian Somers * notice, this list of conditions and the following disclaimer. 103006ec67SBrian Somers * 2. Redistributions in binary form must reproduce the above copyright 113006ec67SBrian Somers * notice, this list of conditions and the following disclaimer in the 123006ec67SBrian Somers * documentation and/or other materials provided with the distribution. 133006ec67SBrian Somers * 143006ec67SBrian Somers * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 153006ec67SBrian Somers * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 163006ec67SBrian Somers * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 173006ec67SBrian Somers * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 183006ec67SBrian Somers * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 193006ec67SBrian Somers * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 203006ec67SBrian Somers * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 213006ec67SBrian Somers * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 223006ec67SBrian Somers * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 233006ec67SBrian Somers * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 243006ec67SBrian Somers * SUCH DAMAGE. 253006ec67SBrian Somers * 26643f4904SBrian Somers * $Id: datalink.c,v 1.1.2.45 1998/04/23 18:56:09 brian Exp $ 273006ec67SBrian Somers */ 283006ec67SBrian Somers 292764b86aSBrian Somers #include <sys/types.h> 303006ec67SBrian Somers #include <netinet/in.h> 31eaa4df37SBrian Somers #include <netinet/in_systm.h> 32eaa4df37SBrian Somers #include <netinet/ip.h> 333006ec67SBrian Somers 34c7cc5030SBrian Somers #include <stdio.h> 353006ec67SBrian Somers #include <stdlib.h> 363006ec67SBrian Somers #include <string.h> 373006ec67SBrian Somers #include <termios.h> 383006ec67SBrian Somers 393006ec67SBrian Somers #include "mbuf.h" 403006ec67SBrian Somers #include "log.h" 413006ec67SBrian Somers #include "defs.h" 423006ec67SBrian Somers #include "timer.h" 433006ec67SBrian Somers #include "fsm.h" 443006ec67SBrian Somers #include "lcp.h" 453006ec67SBrian Somers #include "descriptor.h" 46879ed6faSBrian Somers #include "lqr.h" 473006ec67SBrian Somers #include "hdlc.h" 483006ec67SBrian Somers #include "async.h" 493006ec67SBrian Somers #include "throughput.h" 503b0f8d2eSBrian Somers #include "ccp.h" 513006ec67SBrian Somers #include "link.h" 523006ec67SBrian Somers #include "physical.h" 535828db6dSBrian Somers #include "iplist.h" 54eaa4df37SBrian Somers #include "slcompress.h" 555828db6dSBrian Somers #include "ipcp.h" 565ca5389aSBrian Somers #include "filter.h" 573b0f8d2eSBrian Somers #include "mp.h" 583006ec67SBrian Somers #include "bundle.h" 593006ec67SBrian Somers #include "chat.h" 60e2ebb036SBrian Somers #include "auth.h" 613006ec67SBrian Somers #include "modem.h" 62c7cc5030SBrian Somers #include "prompt.h" 63e2ebb036SBrian Somers #include "lcpproto.h" 64e2ebb036SBrian Somers #include "pap.h" 65e2ebb036SBrian Somers #include "chap.h" 66565e35e5SBrian Somers #include "command.h" 67e2ebb036SBrian Somers #include "datalink.h" 68c7cc5030SBrian Somers 69030e4ebbSBrian Somers static void datalink_LoginDone(struct datalink *); 703006ec67SBrian Somers 713006ec67SBrian Somers static void 723006ec67SBrian Somers datalink_OpenTimeout(void *v) 733006ec67SBrian Somers { 743006ec67SBrian Somers struct datalink *dl = (struct datalink *)v; 753006ec67SBrian Somers 763006ec67SBrian Somers StopTimer(&dl->dial_timer); 773006ec67SBrian Somers if (dl->state == DATALINK_OPENING) 783006ec67SBrian Somers LogPrintf(LogPHASE, "%s: Redial timer expired.\n", dl->name); 793006ec67SBrian Somers } 803006ec67SBrian Somers 813006ec67SBrian Somers static void 823006ec67SBrian Somers datalink_StartDialTimer(struct datalink *dl, int Timeout) 833006ec67SBrian Somers { 843006ec67SBrian Somers StopTimer(&dl->dial_timer); 853006ec67SBrian Somers 863006ec67SBrian Somers if (Timeout) { 873006ec67SBrian Somers if (Timeout > 0) 883006ec67SBrian Somers dl->dial_timer.load = Timeout * SECTICKS; 893006ec67SBrian Somers else 90e718d1d7SBrian Somers dl->dial_timer.load = (random() % DIAL_TIMEOUT) * SECTICKS; 913006ec67SBrian Somers dl->dial_timer.func = datalink_OpenTimeout; 923b0f8d2eSBrian Somers dl->dial_timer.name = "dial"; 933006ec67SBrian Somers dl->dial_timer.arg = dl; 943006ec67SBrian Somers StartTimer(&dl->dial_timer); 953006ec67SBrian Somers if (dl->state == DATALINK_OPENING) 963006ec67SBrian Somers LogPrintf(LogPHASE, "%s: Enter pause (%d) for redialing.\n", 973006ec67SBrian Somers dl->name, Timeout); 983006ec67SBrian Somers } 993006ec67SBrian Somers } 1003006ec67SBrian Somers 1013006ec67SBrian Somers static void 1023006ec67SBrian Somers datalink_HangupDone(struct datalink *dl) 1033006ec67SBrian Somers { 104030e4ebbSBrian Somers if (dl->physical->type == PHYS_DEDICATED && !dl->bundle->CleaningUp && 105030e4ebbSBrian Somers Physical_GetFD(dl->physical) != -1) { 106030e4ebbSBrian Somers /* Don't close our modem if the link is dedicated */ 107030e4ebbSBrian Somers datalink_LoginDone(dl); 108030e4ebbSBrian Somers return; 109030e4ebbSBrian Somers } 110030e4ebbSBrian Somers 1113006ec67SBrian Somers modem_Close(dl->physical); 112565e35e5SBrian Somers dl->phone.chosen = "N/A"; 1133006ec67SBrian Somers 1143b0f8d2eSBrian Somers if (dl->bundle->CleaningUp || 115565e35e5SBrian Somers (dl->physical->type == PHYS_STDIN) || 1163b0f8d2eSBrian Somers ((!dl->dial_tries || (dl->dial_tries < 0 && !dl->reconnect_tries)) && 117565e35e5SBrian Somers !(dl->physical->type & (PHYS_PERM|PHYS_DEDICATED)))) { 1183006ec67SBrian Somers LogPrintf(LogPHASE, "%s: Entering CLOSED state\n", dl->name); 1193006ec67SBrian Somers dl->state = DATALINK_CLOSED; 1203006ec67SBrian Somers dl->dial_tries = -1; 1213006ec67SBrian Somers dl->reconnect_tries = 0; 1223006ec67SBrian Somers bundle_LinkClosed(dl->bundle, dl); 1233b0f8d2eSBrian Somers if (!dl->bundle->CleaningUp) 124565e35e5SBrian Somers datalink_StartDialTimer(dl, dl->cfg.dial.timeout); 1253006ec67SBrian Somers } else { 126aef795ccSBrian Somers LogPrintf(LogPHASE, "%s: Re-entering OPENING state\n", dl->name); 1273006ec67SBrian Somers dl->state = DATALINK_OPENING; 128abff9baeSBrian Somers if (dl->dial_tries < 0) { 129565e35e5SBrian Somers datalink_StartDialTimer(dl, dl->cfg.reconnect.timeout); 130565e35e5SBrian Somers dl->dial_tries = dl->cfg.dial.max; 131abff9baeSBrian Somers dl->reconnect_tries--; 132abff9baeSBrian Somers } else { 133f9545805SBrian Somers if (dl->phone.next == NULL) 134565e35e5SBrian Somers datalink_StartDialTimer(dl, dl->cfg.dial.timeout); 1353006ec67SBrian Somers else 136565e35e5SBrian Somers datalink_StartDialTimer(dl, dl->cfg.dial.next_timeout); 1373006ec67SBrian Somers } 138abff9baeSBrian Somers } 139abff9baeSBrian Somers } 1403006ec67SBrian Somers 141f9545805SBrian Somers static const char * 142f9545805SBrian Somers datalink_ChoosePhoneNumber(struct datalink *dl) 143f9545805SBrian Somers { 144f9545805SBrian Somers char *phone; 145f9545805SBrian Somers 146f9545805SBrian Somers if (dl->phone.alt == NULL) { 147f9545805SBrian Somers if (dl->phone.next == NULL) { 148f9545805SBrian Somers strncpy(dl->phone.list, dl->cfg.phone.list, sizeof dl->phone.list - 1); 149f9545805SBrian Somers dl->phone.list[sizeof dl->phone.list - 1] = '\0'; 150f9545805SBrian Somers dl->phone.next = dl->phone.list; 151f9545805SBrian Somers } 152f9545805SBrian Somers dl->phone.alt = strsep(&dl->phone.next, ":"); 153f9545805SBrian Somers } 154f9545805SBrian Somers phone = strsep(&dl->phone.alt, "|"); 155f9545805SBrian Somers dl->phone.chosen = *phone ? phone : "[NONE]"; 156f9545805SBrian Somers if (*phone) 157f9545805SBrian Somers LogPrintf(LogPHASE, "Phone: %s\n", phone); 158f9545805SBrian Somers return phone; 159f9545805SBrian Somers } 160f9545805SBrian Somers 161c5a5a6caSBrian Somers static void 162c5a5a6caSBrian Somers datalink_LoginDone(struct datalink *dl) 163c5a5a6caSBrian Somers { 164d345321bSBrian Somers if (!dl->script.packetmode) { 165d345321bSBrian Somers dl->dial_tries = -1; 166d345321bSBrian Somers LogPrintf(LogPHASE, "%s: Entering READY state\n", dl->name); 167d345321bSBrian Somers dl->state = DATALINK_READY; 168d345321bSBrian Somers } else if (modem_Raw(dl->physical, dl->bundle) < 0) { 169c5a5a6caSBrian Somers dl->dial_tries = 0; 170c5a5a6caSBrian Somers LogPrintf(LogWARN, "datalink_LoginDone: Not connected.\n"); 171c5a5a6caSBrian Somers if (dl->script.run) { 172c5a5a6caSBrian Somers LogPrintf(LogPHASE, "%s: Entering HANGUP state\n", dl->name); 173c5a5a6caSBrian Somers dl->state = DATALINK_HANGUP; 174c5a5a6caSBrian Somers modem_Offline(dl->physical); 175f9545805SBrian Somers chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL); 176030e4ebbSBrian Somers } else { 177030e4ebbSBrian Somers if (dl->physical->type == PHYS_DEDICATED) 178030e4ebbSBrian Somers /* force a redial timeout */ 179030e4ebbSBrian Somers modem_Close(dl->physical); 180c5a5a6caSBrian Somers datalink_HangupDone(dl); 181030e4ebbSBrian Somers } 182c5a5a6caSBrian Somers } else { 183c7cc5030SBrian Somers dl->dial_tries = -1; 184c7cc5030SBrian Somers 185643f4904SBrian Somers hdlc_Init(&dl->physical->hdlc, &dl->physical->link.lcp); 1863b0f8d2eSBrian Somers async_Init(&dl->physical->async); 1873b0f8d2eSBrian Somers 188cd9647a1SBrian Somers lcp_Setup(&dl->physical->link.lcp, dl->state == DATALINK_READY ? 189cd9647a1SBrian Somers 0 : dl->physical->link.lcp.cfg.openmode); 1903b0f8d2eSBrian Somers ccp_Setup(&dl->physical->link.ccp); 191503a7782SBrian Somers 192e2ebb036SBrian Somers LogPrintf(LogPHASE, "%s: Entering LCP state\n", dl->name); 193e2ebb036SBrian Somers dl->state = DATALINK_LCP; 1943b0f8d2eSBrian Somers FsmUp(&dl->physical->link.lcp.fsm); 1953b0f8d2eSBrian Somers FsmOpen(&dl->physical->link.lcp.fsm); 196c5a5a6caSBrian Somers } 197c5a5a6caSBrian Somers } 198c5a5a6caSBrian Somers 1993006ec67SBrian Somers static int 2003006ec67SBrian Somers datalink_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e, 2013006ec67SBrian Somers int *n) 2023006ec67SBrian Somers { 2033006ec67SBrian Somers struct datalink *dl = descriptor2datalink(d); 2043006ec67SBrian Somers int result; 2053006ec67SBrian Somers 206310c3babSBrian Somers result = 0; 2073006ec67SBrian Somers switch (dl->state) { 2083006ec67SBrian Somers case DATALINK_CLOSED: 209565e35e5SBrian Somers if ((dl->physical->type & (PHYS_STDIN|PHYS_DEDICATED|PHYS_1OFF)) && 210565e35e5SBrian Somers !bundle_IsDead(dl->bundle)) 211565e35e5SBrian Somers /* 212565e35e5SBrian Somers * Our first time in - DEDICATED never comes down, and STDIN & 1OFF 213565e35e5SBrian Somers * get deleted when they enter DATALINK_CLOSED. Go to 214565e35e5SBrian Somers * DATALINK_OPENING via datalink_Up() and fall through. 215565e35e5SBrian Somers */ 216565e35e5SBrian Somers datalink_Up(dl, 1, 1); 217565e35e5SBrian Somers else 218310c3babSBrian Somers break; 219565e35e5SBrian Somers /* fall through */ 2203006ec67SBrian Somers 2213006ec67SBrian Somers case DATALINK_OPENING: 2223006ec67SBrian Somers if (dl->dial_timer.state != TIMER_RUNNING) { 2233006ec67SBrian Somers if (--dl->dial_tries < 0) 2243006ec67SBrian Somers dl->dial_tries = 0; 2253006ec67SBrian Somers if (modem_Open(dl->physical, dl->bundle) >= 0) { 226c5a5a6caSBrian Somers if (dl->script.run) { 2273006ec67SBrian Somers LogPrintf(LogPHASE, "%s: Entering DIAL state\n", dl->name); 2283006ec67SBrian Somers dl->state = DATALINK_DIAL; 229f9545805SBrian Somers chat_Init(&dl->chat, dl->physical, dl->cfg.script.dial, 1, 230f9545805SBrian Somers datalink_ChoosePhoneNumber(dl)); 231565e35e5SBrian Somers if (!(dl->physical->type & (PHYS_PERM|PHYS_DEDICATED)) && 232565e35e5SBrian Somers dl->cfg.dial.max) 2333006ec67SBrian Somers LogPrintf(LogCHAT, "%s: Dial attempt %u of %d\n", 234565e35e5SBrian Somers dl->name, dl->cfg.dial.max - dl->dial_tries, 235565e35e5SBrian Somers dl->cfg.dial.max); 2361342caedSBrian Somers return datalink_UpdateSet(d, r, w, e, n); 237c5a5a6caSBrian Somers } else 238c5a5a6caSBrian Somers datalink_LoginDone(dl); 2393006ec67SBrian Somers } else { 240565e35e5SBrian Somers if (!(dl->physical->type & (PHYS_PERM|PHYS_DEDICATED)) && 241565e35e5SBrian Somers dl->cfg.dial.max) 2423006ec67SBrian Somers LogPrintf(LogCHAT, "Failed to open modem (attempt %u of %d)\n", 243565e35e5SBrian Somers dl->cfg.dial.max - dl->dial_tries, dl->cfg.dial.max); 2443006ec67SBrian Somers else 2453006ec67SBrian Somers LogPrintf(LogCHAT, "Failed to open modem\n"); 2463006ec67SBrian Somers 2473b0f8d2eSBrian Somers if (dl->bundle->CleaningUp || 248565e35e5SBrian Somers (!(dl->physical->type & (PHYS_PERM|PHYS_DEDICATED)) && 249565e35e5SBrian Somers dl->cfg.dial.max && dl->dial_tries == 0)) { 2503006ec67SBrian Somers LogPrintf(LogPHASE, "%s: Entering CLOSED state\n", dl->name); 2513006ec67SBrian Somers dl->state = DATALINK_CLOSED; 2523006ec67SBrian Somers dl->reconnect_tries = 0; 2533006ec67SBrian Somers dl->dial_tries = -1; 2545b8b8060SBrian Somers bundle_LinkClosed(dl->bundle, dl); 255c5a5a6caSBrian Somers } 2563b0f8d2eSBrian Somers if (!dl->bundle->CleaningUp) 257565e35e5SBrian Somers datalink_StartDialTimer(dl, dl->cfg.dial.timeout); 2583006ec67SBrian Somers } 2593006ec67SBrian Somers } 260310c3babSBrian Somers break; 2613006ec67SBrian Somers 2623006ec67SBrian Somers case DATALINK_HANGUP: 2633006ec67SBrian Somers case DATALINK_DIAL: 2643006ec67SBrian Somers case DATALINK_LOGIN: 2653006ec67SBrian Somers result = descriptor_UpdateSet(&dl->chat.desc, r, w, e, n); 2663006ec67SBrian Somers switch (dl->chat.state) { 2673006ec67SBrian Somers case CHAT_DONE: 2683006ec67SBrian Somers /* script succeeded */ 26939d94652SBrian Somers chat_Destroy(&dl->chat); 2703006ec67SBrian Somers switch(dl->state) { 2713006ec67SBrian Somers case DATALINK_HANGUP: 2723006ec67SBrian Somers datalink_HangupDone(dl); 2733006ec67SBrian Somers break; 2743006ec67SBrian Somers case DATALINK_DIAL: 2753006ec67SBrian Somers LogPrintf(LogPHASE, "%s: Entering LOGIN state\n", dl->name); 2763006ec67SBrian Somers dl->state = DATALINK_LOGIN; 277f9545805SBrian Somers chat_Init(&dl->chat, dl->physical, dl->cfg.script.login, 0, NULL); 2781342caedSBrian Somers return datalink_UpdateSet(d, r, w, e, n); 2793006ec67SBrian Somers case DATALINK_LOGIN: 280c5a5a6caSBrian Somers datalink_LoginDone(dl); 2813006ec67SBrian Somers break; 2823006ec67SBrian Somers } 2833006ec67SBrian Somers break; 2843006ec67SBrian Somers case CHAT_FAILED: 2853006ec67SBrian Somers /* Going down - script failed */ 2863006ec67SBrian Somers LogPrintf(LogWARN, "Chat script failed\n"); 28739d94652SBrian Somers chat_Destroy(&dl->chat); 2883006ec67SBrian Somers switch(dl->state) { 2893006ec67SBrian Somers case DATALINK_HANGUP: 2903006ec67SBrian Somers datalink_HangupDone(dl); 2913006ec67SBrian Somers break; 2923006ec67SBrian Somers case DATALINK_DIAL: 2933006ec67SBrian Somers case DATALINK_LOGIN: 2943006ec67SBrian Somers LogPrintf(LogPHASE, "%s: Entering HANGUP state\n", dl->name); 2953006ec67SBrian Somers dl->state = DATALINK_HANGUP; 2963006ec67SBrian Somers modem_Offline(dl->physical); 297f9545805SBrian Somers chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL); 2981342caedSBrian Somers return datalink_UpdateSet(d, r, w, e, n); 2993006ec67SBrian Somers } 3003006ec67SBrian Somers break; 3013006ec67SBrian Somers } 3023006ec67SBrian Somers break; 303c7cc5030SBrian Somers 304c7cc5030SBrian Somers case DATALINK_READY: 305e2ebb036SBrian Somers case DATALINK_LCP: 306e2ebb036SBrian Somers case DATALINK_AUTH: 3073006ec67SBrian Somers case DATALINK_OPEN: 3083006ec67SBrian Somers result = descriptor_UpdateSet(&dl->physical->desc, r, w, e, n); 3093006ec67SBrian Somers break; 3103006ec67SBrian Somers } 3113006ec67SBrian Somers return result; 3123006ec67SBrian Somers } 3133006ec67SBrian Somers 3143006ec67SBrian Somers static int 3152f786681SBrian Somers datalink_IsSet(struct descriptor *d, const fd_set *fdset) 3163006ec67SBrian Somers { 3173006ec67SBrian Somers struct datalink *dl = descriptor2datalink(d); 3183006ec67SBrian Somers 3193006ec67SBrian Somers switch (dl->state) { 3203006ec67SBrian Somers case DATALINK_CLOSED: 321c7cc5030SBrian Somers case DATALINK_OPENING: 3223006ec67SBrian Somers break; 323c7cc5030SBrian Somers 3243006ec67SBrian Somers case DATALINK_HANGUP: 3253006ec67SBrian Somers case DATALINK_DIAL: 3263006ec67SBrian Somers case DATALINK_LOGIN: 3273006ec67SBrian Somers return descriptor_IsSet(&dl->chat.desc, fdset); 328c7cc5030SBrian Somers 329c7cc5030SBrian Somers case DATALINK_READY: 330e2ebb036SBrian Somers case DATALINK_LCP: 331e2ebb036SBrian Somers case DATALINK_AUTH: 3323006ec67SBrian Somers case DATALINK_OPEN: 3333006ec67SBrian Somers return descriptor_IsSet(&dl->physical->desc, fdset); 3343006ec67SBrian Somers } 3353006ec67SBrian Somers return 0; 3363006ec67SBrian Somers } 3373006ec67SBrian Somers 3383006ec67SBrian Somers static void 3393006ec67SBrian Somers datalink_Read(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) 3403006ec67SBrian Somers { 3413006ec67SBrian Somers struct datalink *dl = descriptor2datalink(d); 3423006ec67SBrian Somers 3433006ec67SBrian Somers switch (dl->state) { 3443006ec67SBrian Somers case DATALINK_CLOSED: 345c7cc5030SBrian Somers case DATALINK_OPENING: 3463006ec67SBrian Somers break; 347c7cc5030SBrian Somers 3483006ec67SBrian Somers case DATALINK_HANGUP: 3493006ec67SBrian Somers case DATALINK_DIAL: 3503006ec67SBrian Somers case DATALINK_LOGIN: 3513006ec67SBrian Somers descriptor_Read(&dl->chat.desc, bundle, fdset); 3523006ec67SBrian Somers break; 353c7cc5030SBrian Somers 354c7cc5030SBrian Somers case DATALINK_READY: 355e2ebb036SBrian Somers case DATALINK_LCP: 356e2ebb036SBrian Somers case DATALINK_AUTH: 3573006ec67SBrian Somers case DATALINK_OPEN: 3583006ec67SBrian Somers descriptor_Read(&dl->physical->desc, bundle, fdset); 3593006ec67SBrian Somers break; 3603006ec67SBrian Somers } 3613006ec67SBrian Somers } 3623006ec67SBrian Somers 3633006ec67SBrian Somers static void 364f4768038SBrian Somers datalink_Write(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) 3653006ec67SBrian Somers { 3663006ec67SBrian Somers struct datalink *dl = descriptor2datalink(d); 3673006ec67SBrian Somers 3683006ec67SBrian Somers switch (dl->state) { 3693006ec67SBrian Somers case DATALINK_CLOSED: 370c7cc5030SBrian Somers case DATALINK_OPENING: 3713006ec67SBrian Somers break; 372c7cc5030SBrian Somers 3733006ec67SBrian Somers case DATALINK_HANGUP: 3743006ec67SBrian Somers case DATALINK_DIAL: 3753006ec67SBrian Somers case DATALINK_LOGIN: 376f4768038SBrian Somers descriptor_Write(&dl->chat.desc, bundle, fdset); 3773006ec67SBrian Somers break; 378c7cc5030SBrian Somers 379c7cc5030SBrian Somers case DATALINK_READY: 380e2ebb036SBrian Somers case DATALINK_LCP: 381e2ebb036SBrian Somers case DATALINK_AUTH: 3823006ec67SBrian Somers case DATALINK_OPEN: 383f4768038SBrian Somers descriptor_Write(&dl->physical->desc, bundle, fdset); 3843006ec67SBrian Somers break; 3853006ec67SBrian Somers } 3863006ec67SBrian Somers } 3873006ec67SBrian Somers 3886d666775SBrian Somers static void 389e2ebb036SBrian Somers datalink_ComeDown(struct datalink *dl, int stay) 390e2ebb036SBrian Somers { 391e2ebb036SBrian Somers if (stay) { 392e2ebb036SBrian Somers dl->dial_tries = -1; 393e2ebb036SBrian Somers dl->reconnect_tries = 0; 394e2ebb036SBrian Somers } 395e2ebb036SBrian Somers 396e2ebb036SBrian Somers if (dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP) { 397e2ebb036SBrian Somers modem_Offline(dl->physical); 398e2ebb036SBrian Somers if (dl->script.run && dl->state != DATALINK_OPENING) { 399e2ebb036SBrian Somers LogPrintf(LogPHASE, "%s: Entering HANGUP state\n", dl->name); 400e2ebb036SBrian Somers dl->state = DATALINK_HANGUP; 401f9545805SBrian Somers chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL); 402e2ebb036SBrian Somers } else 403e2ebb036SBrian Somers datalink_HangupDone(dl); 404e2ebb036SBrian Somers } 405e2ebb036SBrian Somers } 406e2ebb036SBrian Somers 407e2ebb036SBrian Somers static void 4086d666775SBrian Somers datalink_LayerStart(void *v, struct fsm *fp) 4096d666775SBrian Somers { 4106d666775SBrian Somers /* The given FSM is about to start up ! */ 4116d666775SBrian Somers struct datalink *dl = (struct datalink *)v; 412a611cad6SBrian Somers 41392e872e7SBrian Somers if (fp->proto == PROTO_LCP) 414e2ebb036SBrian Somers (*dl->parent->LayerStart)(dl->parent->object, fp); 415e2ebb036SBrian Somers } 4166d666775SBrian Somers 4176d666775SBrian Somers static void 4186d666775SBrian Somers datalink_LayerUp(void *v, struct fsm *fp) 4196d666775SBrian Somers { 4206d666775SBrian Somers /* The given fsm is now up */ 4216d666775SBrian Somers struct datalink *dl = (struct datalink *)v; 4226d666775SBrian Somers 42392e872e7SBrian Somers if (fp->proto == PROTO_LCP) { 424643f4904SBrian Somers datalink_GotAuthname(dl, "", 0); 4253b0f8d2eSBrian Somers dl->physical->link.lcp.auth_ineed = dl->physical->link.lcp.want_auth; 4263b0f8d2eSBrian Somers dl->physical->link.lcp.auth_iwait = dl->physical->link.lcp.his_auth; 4273b0f8d2eSBrian Somers if (dl->physical->link.lcp.his_auth || dl->physical->link.lcp.want_auth) { 4283b0f8d2eSBrian Somers if (bundle_Phase(dl->bundle) == PHASE_ESTABLISH) 4295563ebdeSBrian Somers bundle_NewPhase(dl->bundle, PHASE_AUTHENTICATE); 430e2ebb036SBrian Somers LogPrintf(LogPHASE, "%s: his = %s, mine = %s\n", dl->name, 4313b0f8d2eSBrian Somers Auth2Nam(dl->physical->link.lcp.his_auth), 4323b0f8d2eSBrian Somers Auth2Nam(dl->physical->link.lcp.want_auth)); 4333b0f8d2eSBrian Somers if (dl->physical->link.lcp.his_auth == PROTO_PAP) 434e2ebb036SBrian Somers StartAuthChallenge(&dl->pap, dl->physical, SendPapChallenge); 4353b0f8d2eSBrian Somers if (dl->physical->link.lcp.want_auth == PROTO_CHAP) 436e2ebb036SBrian Somers StartAuthChallenge(&dl->chap.auth, dl->physical, SendChapChallenge); 437e2ebb036SBrian Somers } else 438e2ebb036SBrian Somers datalink_AuthOk(dl); 439e2ebb036SBrian Somers } 440e2ebb036SBrian Somers } 441e2ebb036SBrian Somers 442e2ebb036SBrian Somers void 443643f4904SBrian Somers datalink_GotAuthname(struct datalink *dl, const char *name, int len) 444643f4904SBrian Somers { 445643f4904SBrian Somers if (len >= sizeof dl->peer.authname) 446643f4904SBrian Somers len = sizeof dl->peer.authname - 1; 447643f4904SBrian Somers strncpy(dl->peer.authname, name, len); 448643f4904SBrian Somers dl->peer.authname[len] = '\0'; 449643f4904SBrian Somers } 450643f4904SBrian Somers 451643f4904SBrian Somers void 452e2ebb036SBrian Somers datalink_AuthOk(struct datalink *dl) 453e2ebb036SBrian Somers { 4543b0f8d2eSBrian Somers /* XXX: Connect to another ppp instance HERE */ 4553b0f8d2eSBrian Somers 456dbf60d74SBrian Somers if (dl->physical->link.lcp.want_mrru && dl->physical->link.lcp.his_mrru) { 457643f4904SBrian Somers if (!mp_Up(&dl->bundle->ncp.mp, &dl->peer, 45849052c95SBrian Somers dl->physical->link.lcp.want_mrru, 45949052c95SBrian Somers dl->physical->link.lcp.his_mrru, 46049052c95SBrian Somers dl->physical->link.lcp.want_shortseq, 46149052c95SBrian Somers dl->physical->link.lcp.his_shortseq)) { 46249052c95SBrian Somers datalink_AuthNotOk(dl); 46349052c95SBrian Somers return; 46449052c95SBrian Somers } 46549052c95SBrian Somers } else if (bundle_Phase(dl->bundle) == PHASE_NETWORK) { 46649052c95SBrian Somers LogPrintf(LogPHASE, "%s: Already in NETWORK phase\n", dl->name); 46749052c95SBrian Somers datalink_AuthNotOk(dl); 46849052c95SBrian Somers return; 469ce828a6eSBrian Somers } else 470ce828a6eSBrian Somers ipcp_SetLink(&dl->bundle->ncp.ipcp, &dl->physical->link); 47149052c95SBrian Somers 472643f4904SBrian Somers AuthSelect(dl->bundle, dl->peer.authname, dl->physical); 4733b0f8d2eSBrian Somers FsmUp(&dl->physical->link.ccp.fsm); 4743b0f8d2eSBrian Somers FsmOpen(&dl->physical->link.ccp.fsm); 475e2ebb036SBrian Somers dl->state = DATALINK_OPEN; 4763b0f8d2eSBrian Somers bundle_NewPhase(dl->bundle, PHASE_NETWORK); 4773b0f8d2eSBrian Somers (*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.lcp.fsm); 4786d666775SBrian Somers } 479e2ebb036SBrian Somers 480e2ebb036SBrian Somers void 481e2ebb036SBrian Somers datalink_AuthNotOk(struct datalink *dl) 482e2ebb036SBrian Somers { 483e2ebb036SBrian Somers dl->state = DATALINK_LCP; 4843b0f8d2eSBrian Somers FsmClose(&dl->physical->link.lcp.fsm); 4856d666775SBrian Somers } 4866d666775SBrian Somers 4876d666775SBrian Somers static void 4886d666775SBrian Somers datalink_LayerDown(void *v, struct fsm *fp) 4896d666775SBrian Somers { 4906d666775SBrian Somers /* The given FSM has been told to come down */ 4916d666775SBrian Somers struct datalink *dl = (struct datalink *)v; 492a611cad6SBrian Somers 49392e872e7SBrian Somers if (fp->proto == PROTO_LCP) { 494e2ebb036SBrian Somers switch (dl->state) { 495e2ebb036SBrian Somers case DATALINK_OPEN: 496643f4904SBrian Somers peerid_Init(&dl->peer); 4973b0f8d2eSBrian Somers FsmDown(&dl->physical->link.ccp.fsm); 4983b0f8d2eSBrian Somers FsmClose(&dl->physical->link.ccp.fsm); 499e2ebb036SBrian Somers (*dl->parent->LayerDown)(dl->parent->object, fp); 500e2ebb036SBrian Somers /* fall through */ 501e2ebb036SBrian Somers 502e2ebb036SBrian Somers case DATALINK_AUTH: 503e2ebb036SBrian Somers StopTimer(&dl->pap.authtimer); 504e2ebb036SBrian Somers StopTimer(&dl->chap.auth.authtimer); 5056d666775SBrian Somers } 506e2ebb036SBrian Somers dl->state = DATALINK_LCP; 507e2ebb036SBrian Somers } 5086d666775SBrian Somers } 5096d666775SBrian Somers 5106d666775SBrian Somers static void 5116d666775SBrian Somers datalink_LayerFinish(void *v, struct fsm *fp) 5126d666775SBrian Somers { 5136d666775SBrian Somers /* The given fsm is now down */ 5146d666775SBrian Somers struct datalink *dl = (struct datalink *)v; 5156d666775SBrian Somers 51692e872e7SBrian Somers if (fp->proto == PROTO_LCP) { 51792e872e7SBrian Somers FsmDown(fp); /* Bring us to INITIAL or STARTING */ 5186d666775SBrian Somers (*dl->parent->LayerFinish)(dl->parent->object, fp); 519e2ebb036SBrian Somers datalink_ComeDown(dl, 0); 5206d666775SBrian Somers } 5216d666775SBrian Somers } 5226d666775SBrian Somers 5233006ec67SBrian Somers struct datalink * 5246d666775SBrian Somers datalink_Create(const char *name, struct bundle *bundle, 525565e35e5SBrian Somers const struct fsm_parent *parent, int type) 5263006ec67SBrian Somers { 5273006ec67SBrian Somers struct datalink *dl; 5283006ec67SBrian Somers 5293006ec67SBrian Somers dl = (struct datalink *)malloc(sizeof(struct datalink)); 5303006ec67SBrian Somers if (dl == NULL) 5313006ec67SBrian Somers return dl; 5323006ec67SBrian Somers 5333006ec67SBrian Somers dl->desc.type = DATALINK_DESCRIPTOR; 5343006ec67SBrian Somers dl->desc.next = NULL; 5353006ec67SBrian Somers dl->desc.UpdateSet = datalink_UpdateSet; 5363006ec67SBrian Somers dl->desc.IsSet = datalink_IsSet; 5373006ec67SBrian Somers dl->desc.Read = datalink_Read; 5383006ec67SBrian Somers dl->desc.Write = datalink_Write; 5395b8b8060SBrian Somers 540e718d1d7SBrian Somers dl->state = DATALINK_CLOSED; 541e718d1d7SBrian Somers 54273a13b5cSBrian Somers *dl->cfg.script.dial = '\0'; 54373a13b5cSBrian Somers *dl->cfg.script.login = '\0'; 54473a13b5cSBrian Somers *dl->cfg.script.hangup = '\0'; 545f9545805SBrian Somers *dl->cfg.phone.list = '\0'; 546f9545805SBrian Somers *dl->phone.list = '\0'; 547f9545805SBrian Somers dl->phone.next = NULL; 548f9545805SBrian Somers dl->phone.alt = NULL; 549f9545805SBrian Somers dl->phone.chosen = "N/A"; 550c7cc5030SBrian Somers dl->script.run = 1; 551c7cc5030SBrian Somers dl->script.packetmode = 1; 5523b0f8d2eSBrian Somers mp_linkInit(&dl->mp); 5535b8b8060SBrian Somers 5543006ec67SBrian Somers dl->bundle = bundle; 5553006ec67SBrian Somers dl->next = NULL; 556e718d1d7SBrian Somers 5573006ec67SBrian Somers memset(&dl->dial_timer, '\0', sizeof dl->dial_timer); 558e718d1d7SBrian Somers 5593006ec67SBrian Somers dl->dial_tries = 0; 560565e35e5SBrian Somers dl->cfg.dial.max = 1; 561565e35e5SBrian Somers dl->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT; 562565e35e5SBrian Somers dl->cfg.dial.timeout = DIAL_TIMEOUT; 563e718d1d7SBrian Somers 564abff9baeSBrian Somers dl->reconnect_tries = 0; 565565e35e5SBrian Somers dl->cfg.reconnect.max = 0; 566565e35e5SBrian Somers dl->cfg.reconnect.timeout = RECONNECT_TIMEOUT; 567abff9baeSBrian Somers 5683006ec67SBrian Somers dl->name = strdup(name); 569643f4904SBrian Somers peerid_Init(&dl->peer); 5703b0f8d2eSBrian Somers dl->parent = parent; 5713b0f8d2eSBrian Somers dl->fsmp.LayerStart = datalink_LayerStart; 5723b0f8d2eSBrian Somers dl->fsmp.LayerUp = datalink_LayerUp; 5733b0f8d2eSBrian Somers dl->fsmp.LayerDown = datalink_LayerDown; 5743b0f8d2eSBrian Somers dl->fsmp.LayerFinish = datalink_LayerFinish; 5753b0f8d2eSBrian Somers dl->fsmp.object = dl; 5763b0f8d2eSBrian Somers 5773b0f8d2eSBrian Somers authinfo_Init(&dl->pap); 5783b0f8d2eSBrian Somers authinfo_Init(&dl->chap.auth); 5793b0f8d2eSBrian Somers 580565e35e5SBrian Somers if ((dl->physical = modem_Create(dl, type)) == NULL) { 5813006ec67SBrian Somers free(dl->name); 5823006ec67SBrian Somers free(dl); 5833006ec67SBrian Somers return NULL; 5843006ec67SBrian Somers } 585f9545805SBrian Somers chat_Init(&dl->chat, dl->physical, NULL, 1, NULL); 5863006ec67SBrian Somers 587c7cc5030SBrian Somers LogPrintf(LogPHASE, "%s: Created in CLOSED state\n", dl->name); 5883006ec67SBrian Somers 5893006ec67SBrian Somers return dl; 5903006ec67SBrian Somers } 5913006ec67SBrian Somers 5923006ec67SBrian Somers struct datalink * 593cd7bd93aSBrian Somers datalink_Clone(struct datalink *odl, const char *name) 594cd7bd93aSBrian Somers { 595cd7bd93aSBrian Somers struct datalink *dl; 596cd7bd93aSBrian Somers 597cd7bd93aSBrian Somers dl = (struct datalink *)malloc(sizeof(struct datalink)); 598cd7bd93aSBrian Somers if (dl == NULL) 599cd7bd93aSBrian Somers return dl; 600cd7bd93aSBrian Somers 601cd7bd93aSBrian Somers dl->desc.type = DATALINK_DESCRIPTOR; 602cd7bd93aSBrian Somers dl->desc.next = NULL; 603cd7bd93aSBrian Somers dl->desc.UpdateSet = datalink_UpdateSet; 604cd7bd93aSBrian Somers dl->desc.IsSet = datalink_IsSet; 605cd7bd93aSBrian Somers dl->desc.Read = datalink_Read; 606cd7bd93aSBrian Somers dl->desc.Write = datalink_Write; 607cd7bd93aSBrian Somers 608cd7bd93aSBrian Somers dl->state = DATALINK_CLOSED; 609cd7bd93aSBrian Somers 610cd7bd93aSBrian Somers memcpy(&dl->cfg, &odl->cfg, sizeof dl->cfg); 611cd7bd93aSBrian Somers mp_linkInit(&dl->mp); 612cd7bd93aSBrian Somers *dl->phone.list = '\0'; 613643f4904SBrian Somers dl->phone.next = NULL; 614643f4904SBrian Somers dl->phone.alt = NULL; 615643f4904SBrian Somers dl->phone.chosen = "N/A"; 616cd7bd93aSBrian Somers dl->bundle = odl->bundle; 617cd7bd93aSBrian Somers dl->next = NULL; 618cd7bd93aSBrian Somers memset(&dl->dial_timer, '\0', sizeof dl->dial_timer); 619cd7bd93aSBrian Somers dl->dial_tries = 0; 620cd7bd93aSBrian Somers dl->reconnect_tries = 0; 621cd7bd93aSBrian Somers dl->name = strdup(name); 622643f4904SBrian Somers peerid_Init(&dl->peer); 623cd7bd93aSBrian Somers dl->parent = odl->parent; 624cd7bd93aSBrian Somers memcpy(&dl->fsmp, &odl->fsmp, sizeof dl->fsmp); 625643f4904SBrian Somers dl->fsmp.object = dl; 626cd7bd93aSBrian Somers authinfo_Init(&dl->pap); 627cd7bd93aSBrian Somers dl->pap.cfg.fsmretry = odl->pap.cfg.fsmretry; 628cd7bd93aSBrian Somers 629cd7bd93aSBrian Somers authinfo_Init(&dl->chap.auth); 630cd7bd93aSBrian Somers dl->chap.auth.cfg.fsmretry = odl->chap.auth.cfg.fsmretry; 631cd7bd93aSBrian Somers 632565e35e5SBrian Somers if ((dl->physical = modem_Create(dl, PHYS_MANUAL)) == NULL) { 633cd7bd93aSBrian Somers free(dl->name); 634cd7bd93aSBrian Somers free(dl); 635cd7bd93aSBrian Somers return NULL; 636cd7bd93aSBrian Somers } 637cd7bd93aSBrian Somers memcpy(&dl->physical->cfg, &odl->physical->cfg, sizeof dl->physical->cfg); 638cd7bd93aSBrian Somers memcpy(&dl->physical->link.lcp.cfg, &odl->physical->link.lcp.cfg, 639cd7bd93aSBrian Somers sizeof dl->physical->link.lcp.cfg); 640cd7bd93aSBrian Somers memcpy(&dl->physical->link.ccp.cfg, &odl->physical->link.ccp.cfg, 641cd7bd93aSBrian Somers sizeof dl->physical->link.ccp.cfg); 642cd7bd93aSBrian Somers memcpy(&dl->physical->async.cfg, &odl->physical->async.cfg, 643cd7bd93aSBrian Somers sizeof dl->physical->async.cfg); 644cd7bd93aSBrian Somers 645cd7bd93aSBrian Somers chat_Init(&dl->chat, dl->physical, NULL, 1, NULL); 646cd7bd93aSBrian Somers 647cd7bd93aSBrian Somers LogPrintf(LogPHASE, "%s: Created in CLOSED state\n", dl->name); 648cd7bd93aSBrian Somers 649cd7bd93aSBrian Somers return dl; 650cd7bd93aSBrian Somers } 651cd7bd93aSBrian Somers 652cd7bd93aSBrian Somers struct datalink * 6533006ec67SBrian Somers datalink_Destroy(struct datalink *dl) 6543006ec67SBrian Somers { 6553006ec67SBrian Somers struct datalink *result; 6563006ec67SBrian Somers 65739d94652SBrian Somers if (dl->state != DATALINK_CLOSED) { 658c7cc5030SBrian Somers LogPrintf(LogERROR, "Oops, destroying a datalink in state %s\n", 659c7cc5030SBrian Somers datalink_State(dl)); 66039d94652SBrian Somers switch (dl->state) { 66139d94652SBrian Somers case DATALINK_HANGUP: 66239d94652SBrian Somers case DATALINK_DIAL: 66339d94652SBrian Somers case DATALINK_LOGIN: 66439d94652SBrian Somers chat_Destroy(&dl->chat); /* Gotta blat the timers ! */ 66539d94652SBrian Somers break; 66639d94652SBrian Somers } 66739d94652SBrian Somers } 6683006ec67SBrian Somers 6693006ec67SBrian Somers result = dl->next; 6703b0f8d2eSBrian Somers modem_Destroy(dl->physical); 6713006ec67SBrian Somers free(dl->name); 6723006ec67SBrian Somers free(dl); 6733006ec67SBrian Somers 6743006ec67SBrian Somers return result; 6753006ec67SBrian Somers } 6763006ec67SBrian Somers 6773006ec67SBrian Somers void 678c5a5a6caSBrian Somers datalink_Up(struct datalink *dl, int runscripts, int packetmode) 6793006ec67SBrian Somers { 680565e35e5SBrian Somers if (dl->physical->type & (PHYS_STDIN|PHYS_DEDICATED)) 681565e35e5SBrian Somers /* Ignore scripts */ 682565e35e5SBrian Somers runscripts = 0; 683565e35e5SBrian Somers 684c7cc5030SBrian Somers switch (dl->state) { 685c7cc5030SBrian Somers case DATALINK_CLOSED: 6863006ec67SBrian Somers LogPrintf(LogPHASE, "%s: Entering OPENING state\n", dl->name); 6873b0f8d2eSBrian Somers if (bundle_Phase(dl->bundle) == PHASE_DEAD || 6883b0f8d2eSBrian Somers bundle_Phase(dl->bundle) == PHASE_TERMINATE) 6893b0f8d2eSBrian Somers bundle_NewPhase(dl->bundle, PHASE_ESTABLISH); 6903006ec67SBrian Somers dl->state = DATALINK_OPENING; 691565e35e5SBrian Somers dl->reconnect_tries = 692565e35e5SBrian Somers dl->physical->type == PHYS_STDIN ? 0 : dl->cfg.reconnect.max; 693565e35e5SBrian Somers dl->dial_tries = dl->cfg.dial.max; 694c5a5a6caSBrian Somers dl->script.run = runscripts; 695c5a5a6caSBrian Somers dl->script.packetmode = packetmode; 696c7cc5030SBrian Somers break; 697c7cc5030SBrian Somers 698c7cc5030SBrian Somers case DATALINK_OPENING: 699c7cc5030SBrian Somers if (!dl->script.run && runscripts) 700c7cc5030SBrian Somers dl->script.run = 1; 701c7cc5030SBrian Somers /* fall through */ 702c7cc5030SBrian Somers 703c7cc5030SBrian Somers case DATALINK_DIAL: 704c7cc5030SBrian Somers case DATALINK_LOGIN: 705c7cc5030SBrian Somers case DATALINK_READY: 706c7cc5030SBrian Somers if (!dl->script.packetmode && packetmode) { 707c7cc5030SBrian Somers dl->script.packetmode = 1; 708c7cc5030SBrian Somers if (dl->state == DATALINK_READY) 709c7cc5030SBrian Somers datalink_LoginDone(dl); 710c7cc5030SBrian Somers } 711c7cc5030SBrian Somers break; 7123006ec67SBrian Somers } 7133006ec67SBrian Somers } 7143006ec67SBrian Somers 7153006ec67SBrian Somers void 716c7cc5030SBrian Somers datalink_Close(struct datalink *dl, int stay) 717c7cc5030SBrian Somers { 718c7cc5030SBrian Somers /* Please close */ 719e2ebb036SBrian Somers switch (dl->state) { 720e2ebb036SBrian Somers case DATALINK_OPEN: 721643f4904SBrian Somers peerid_Init(&dl->peer); 7223b0f8d2eSBrian Somers FsmDown(&dl->physical->link.ccp.fsm); 7233b0f8d2eSBrian Somers FsmClose(&dl->physical->link.ccp.fsm); 724e2ebb036SBrian Somers /* fall through */ 725e2ebb036SBrian Somers 726e2ebb036SBrian Somers case DATALINK_AUTH: 727e2ebb036SBrian Somers case DATALINK_LCP: 7283b0f8d2eSBrian Somers FsmClose(&dl->physical->link.lcp.fsm); 729c7cc5030SBrian Somers if (stay) { 730c7cc5030SBrian Somers dl->dial_tries = -1; 731c7cc5030SBrian Somers dl->reconnect_tries = 0; 732c7cc5030SBrian Somers } 733e2ebb036SBrian Somers break; 734e2ebb036SBrian Somers 735e2ebb036SBrian Somers default: 736c7cc5030SBrian Somers datalink_ComeDown(dl, stay); 737c7cc5030SBrian Somers } 738e2ebb036SBrian Somers } 739c7cc5030SBrian Somers 740c7cc5030SBrian Somers void 741c7cc5030SBrian Somers datalink_Down(struct datalink *dl, int stay) 742c7cc5030SBrian Somers { 743c7cc5030SBrian Somers /* Carrier is lost */ 744e2ebb036SBrian Somers switch (dl->state) { 745e2ebb036SBrian Somers case DATALINK_OPEN: 746643f4904SBrian Somers peerid_Init(&dl->peer); 7473b0f8d2eSBrian Somers FsmDown(&dl->physical->link.ccp.fsm); 7483b0f8d2eSBrian Somers FsmClose(&dl->physical->link.ccp.fsm); 749e2ebb036SBrian Somers /* fall through */ 750e2ebb036SBrian Somers 751e2ebb036SBrian Somers case DATALINK_AUTH: 752e2ebb036SBrian Somers case DATALINK_LCP: 7533b0f8d2eSBrian Somers FsmDown(&dl->physical->link.lcp.fsm); 754c7cc5030SBrian Somers if (stay) 7553b0f8d2eSBrian Somers FsmClose(&dl->physical->link.lcp.fsm); 756c7cc5030SBrian Somers else 7573b0f8d2eSBrian Somers FsmOpen(&dl->physical->link.ccp.fsm); 758e2ebb036SBrian Somers /* fall through */ 759c7cc5030SBrian Somers 760e2ebb036SBrian Somers default: 761c7cc5030SBrian Somers datalink_ComeDown(dl, stay); 762c7cc5030SBrian Somers } 763e2ebb036SBrian Somers } 764c7cc5030SBrian Somers 765c7cc5030SBrian Somers void 7663006ec67SBrian Somers datalink_StayDown(struct datalink *dl) 7673006ec67SBrian Somers { 7683006ec67SBrian Somers dl->reconnect_tries = 0; 7693006ec67SBrian Somers } 770c7cc5030SBrian Somers 771643f4904SBrian Somers int 772643f4904SBrian Somers datalink_Show(struct cmdargs const *arg) 773c7cc5030SBrian Somers { 774643f4904SBrian Somers prompt_Printf(arg->prompt, "Name: %s\n", arg->cx->name); 775643f4904SBrian Somers prompt_Printf(arg->prompt, " State: %s\n", 776643f4904SBrian Somers datalink_State(arg->cx)); 777643f4904SBrian Somers prompt_Printf(arg->prompt, " CHAP Encryption: %s\n", 778643f4904SBrian Somers arg->cx->chap.using_MSChap ? "MSChap" : "MD5" ); 779643f4904SBrian Somers prompt_Printf(arg->prompt, " Peer name: "); 780643f4904SBrian Somers if (*arg->cx->peer.authname) 781643f4904SBrian Somers prompt_Printf(arg->prompt, "%s\n", arg->cx->peer.authname); 782643f4904SBrian Somers else if (arg->cx->state == DATALINK_OPEN) 783643f4904SBrian Somers prompt_Printf(arg->prompt, "None requested\n"); 784565e35e5SBrian Somers else 785643f4904SBrian Somers prompt_Printf(arg->prompt, "N/A\n"); 786643f4904SBrian Somers prompt_Printf(arg->prompt, " Discriminator: %s\n", 787643f4904SBrian Somers mp_Enddisc(arg->cx->peer.enddisc.class, 788643f4904SBrian Somers arg->cx->peer.enddisc.address, 789643f4904SBrian Somers arg->cx->peer.enddisc.len)); 790643f4904SBrian Somers 791643f4904SBrian Somers prompt_Printf(arg->prompt, "\nDefaults:\n"); 792643f4904SBrian Somers prompt_Printf(arg->prompt, " Phone List: %s\n", 793643f4904SBrian Somers arg->cx->cfg.phone.list); 794643f4904SBrian Somers if (arg->cx->cfg.dial.max) 795643f4904SBrian Somers prompt_Printf(arg->prompt, " Dial tries: %d, delay ", 796643f4904SBrian Somers arg->cx->cfg.dial.max); 797565e35e5SBrian Somers else 798643f4904SBrian Somers prompt_Printf(arg->prompt, " Dial tries: infinite, delay "); 799643f4904SBrian Somers if (arg->cx->cfg.dial.next_timeout > 0) 800643f4904SBrian Somers prompt_Printf(arg->prompt, "%ds/", arg->cx->cfg.dial.next_timeout); 801565e35e5SBrian Somers else 802643f4904SBrian Somers prompt_Printf(arg->prompt, "random/"); 803643f4904SBrian Somers if (arg->cx->cfg.dial.timeout > 0) 804643f4904SBrian Somers prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.dial.timeout); 805565e35e5SBrian Somers else 806643f4904SBrian Somers prompt_Printf(arg->prompt, "random\n"); 807643f4904SBrian Somers prompt_Printf(arg->prompt, " Reconnect tries: %d, delay ", 808643f4904SBrian Somers arg->cx->cfg.reconnect.max); 809643f4904SBrian Somers if (arg->cx->cfg.reconnect.timeout > 0) 810643f4904SBrian Somers prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.reconnect.timeout); 811643f4904SBrian Somers else 812643f4904SBrian Somers prompt_Printf(arg->prompt, "random\n"); 813643f4904SBrian Somers prompt_Printf(arg->prompt, " Dial Script: %s\n", 814643f4904SBrian Somers arg->cx->cfg.script.dial); 815643f4904SBrian Somers prompt_Printf(arg->prompt, " Login Script: %s\n", 816643f4904SBrian Somers arg->cx->cfg.script.login); 817643f4904SBrian Somers prompt_Printf(arg->prompt, " Hangup Script: %s\n", 818643f4904SBrian Somers arg->cx->cfg.script.hangup); 819643f4904SBrian Somers return 0; 820565e35e5SBrian Somers } 821565e35e5SBrian Somers 822565e35e5SBrian Somers int 823565e35e5SBrian Somers datalink_SetReconnect(struct cmdargs const *arg) 824565e35e5SBrian Somers { 82525092092SBrian Somers if (arg->argc == arg->argn+2) { 82625092092SBrian Somers arg->cx->cfg.reconnect.timeout = atoi(arg->argv[arg->argn]); 82725092092SBrian Somers arg->cx->cfg.reconnect.max = atoi(arg->argv[arg->argn+1]); 828565e35e5SBrian Somers return 0; 829565e35e5SBrian Somers } 830565e35e5SBrian Somers return -1; 831565e35e5SBrian Somers } 832565e35e5SBrian Somers 833565e35e5SBrian Somers int 834565e35e5SBrian Somers datalink_SetRedial(struct cmdargs const *arg) 835565e35e5SBrian Somers { 836565e35e5SBrian Somers int timeout; 837565e35e5SBrian Somers int tries; 838565e35e5SBrian Somers char *dot; 839565e35e5SBrian Somers 84025092092SBrian Somers if (arg->argc == arg->argn+1 || arg->argc == arg->argn+2) { 84125092092SBrian Somers if (strncasecmp(arg->argv[arg->argn], "random", 6) == 0 && 84225092092SBrian Somers (arg->argv[arg->argn][6] == '\0' || arg->argv[arg->argn][6] == '.')) { 843565e35e5SBrian Somers arg->cx->cfg.dial.timeout = -1; 844565e35e5SBrian Somers randinit(); 845565e35e5SBrian Somers } else { 84625092092SBrian Somers timeout = atoi(arg->argv[arg->argn]); 847565e35e5SBrian Somers 848565e35e5SBrian Somers if (timeout >= 0) 849565e35e5SBrian Somers arg->cx->cfg.dial.timeout = timeout; 850565e35e5SBrian Somers else { 851565e35e5SBrian Somers LogPrintf(LogWARN, "Invalid redial timeout\n"); 852565e35e5SBrian Somers return -1; 853565e35e5SBrian Somers } 854565e35e5SBrian Somers } 855565e35e5SBrian Somers 85625092092SBrian Somers dot = strchr(arg->argv[arg->argn], '.'); 857565e35e5SBrian Somers if (dot) { 858565e35e5SBrian Somers if (strcasecmp(++dot, "random") == 0) { 859565e35e5SBrian Somers arg->cx->cfg.dial.next_timeout = -1; 860565e35e5SBrian Somers randinit(); 861565e35e5SBrian Somers } else { 862565e35e5SBrian Somers timeout = atoi(dot); 863565e35e5SBrian Somers if (timeout >= 0) 864565e35e5SBrian Somers arg->cx->cfg.dial.next_timeout = timeout; 865565e35e5SBrian Somers else { 866565e35e5SBrian Somers LogPrintf(LogWARN, "Invalid next redial timeout\n"); 867565e35e5SBrian Somers return -1; 868565e35e5SBrian Somers } 869565e35e5SBrian Somers } 870565e35e5SBrian Somers } else 871565e35e5SBrian Somers /* Default next timeout */ 872565e35e5SBrian Somers arg->cx->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT; 873565e35e5SBrian Somers 87425092092SBrian Somers if (arg->argc == arg->argn+2) { 87525092092SBrian Somers tries = atoi(arg->argv[arg->argn+1]); 876565e35e5SBrian Somers 877565e35e5SBrian Somers if (tries >= 0) { 878565e35e5SBrian Somers arg->cx->cfg.dial.max = tries; 879565e35e5SBrian Somers } else { 880565e35e5SBrian Somers LogPrintf(LogWARN, "Invalid retry value\n"); 881565e35e5SBrian Somers return 1; 882565e35e5SBrian Somers } 883565e35e5SBrian Somers } 884565e35e5SBrian Somers return 0; 885565e35e5SBrian Somers } 886565e35e5SBrian Somers return -1; 887c7cc5030SBrian Somers } 888c7cc5030SBrian Somers 889cdbbb6b5SBrian Somers static const char *states[] = { 890565e35e5SBrian Somers "closed", 891565e35e5SBrian Somers "opening", 892565e35e5SBrian Somers "hangup", 893565e35e5SBrian Somers "dial", 894565e35e5SBrian Somers "login", 895565e35e5SBrian Somers "ready", 896565e35e5SBrian Somers "lcp", 897565e35e5SBrian Somers "auth", 898565e35e5SBrian Somers "open" 899c7cc5030SBrian Somers }; 900c7cc5030SBrian Somers 901643f4904SBrian Somers const char * 902c7cc5030SBrian Somers datalink_State(struct datalink *dl) 903c7cc5030SBrian Somers { 904c7cc5030SBrian Somers if (dl->state < 0 || dl->state >= sizeof states / sizeof states[0]) 905c7cc5030SBrian Somers return "unknown"; 906c7cc5030SBrian Somers return states[dl->state]; 907c7cc5030SBrian Somers } 908