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 * 269ae58882SBrian Somers * $Id: datalink.c,v 1.1.2.57 1998/05/08 01:15:05 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> 331fa665f5SBrian Somers #include <sys/un.h> 343006ec67SBrian Somers 356f384573SBrian Somers #include <ctype.h> 36c7cc5030SBrian Somers #include <stdio.h> 373006ec67SBrian Somers #include <stdlib.h> 383006ec67SBrian Somers #include <string.h> 3996c9bb21SBrian Somers #include <sys/uio.h> 403006ec67SBrian Somers #include <termios.h> 416f384573SBrian Somers #include <unistd.h> 423006ec67SBrian Somers 433006ec67SBrian Somers #include "mbuf.h" 443006ec67SBrian Somers #include "log.h" 453006ec67SBrian Somers #include "defs.h" 463006ec67SBrian Somers #include "timer.h" 473006ec67SBrian Somers #include "fsm.h" 483006ec67SBrian Somers #include "lcp.h" 493006ec67SBrian Somers #include "descriptor.h" 50879ed6faSBrian Somers #include "lqr.h" 513006ec67SBrian Somers #include "hdlc.h" 523006ec67SBrian Somers #include "async.h" 533006ec67SBrian Somers #include "throughput.h" 543b0f8d2eSBrian Somers #include "ccp.h" 553006ec67SBrian Somers #include "link.h" 563006ec67SBrian Somers #include "physical.h" 575828db6dSBrian Somers #include "iplist.h" 58eaa4df37SBrian Somers #include "slcompress.h" 595828db6dSBrian Somers #include "ipcp.h" 605ca5389aSBrian Somers #include "filter.h" 613b0f8d2eSBrian Somers #include "mp.h" 623006ec67SBrian Somers #include "bundle.h" 633006ec67SBrian Somers #include "chat.h" 64e2ebb036SBrian Somers #include "auth.h" 653006ec67SBrian Somers #include "modem.h" 66c7cc5030SBrian Somers #include "prompt.h" 67e2ebb036SBrian Somers #include "lcpproto.h" 68e2ebb036SBrian Somers #include "pap.h" 69e2ebb036SBrian Somers #include "chap.h" 70565e35e5SBrian Somers #include "command.h" 71e2ebb036SBrian Somers #include "datalink.h" 72c7cc5030SBrian Somers 73030e4ebbSBrian Somers static void datalink_LoginDone(struct datalink *); 749ae58882SBrian Somers static void datalink_NewState(struct datalink *, int); 753006ec67SBrian Somers 763006ec67SBrian Somers static void 773006ec67SBrian Somers datalink_OpenTimeout(void *v) 783006ec67SBrian Somers { 793006ec67SBrian Somers struct datalink *dl = (struct datalink *)v; 803006ec67SBrian Somers 81dd7e2610SBrian Somers timer_Stop(&dl->dial_timer); 823006ec67SBrian Somers if (dl->state == DATALINK_OPENING) 83dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: Redial timer expired.\n", dl->name); 843006ec67SBrian Somers } 853006ec67SBrian Somers 863006ec67SBrian Somers static void 873006ec67SBrian Somers datalink_StartDialTimer(struct datalink *dl, int Timeout) 883006ec67SBrian Somers { 89dd7e2610SBrian Somers timer_Stop(&dl->dial_timer); 903006ec67SBrian Somers 913006ec67SBrian Somers if (Timeout) { 923006ec67SBrian Somers if (Timeout > 0) 933006ec67SBrian Somers dl->dial_timer.load = Timeout * SECTICKS; 943006ec67SBrian Somers else 95e718d1d7SBrian Somers dl->dial_timer.load = (random() % DIAL_TIMEOUT) * SECTICKS; 963006ec67SBrian Somers dl->dial_timer.func = datalink_OpenTimeout; 973b0f8d2eSBrian Somers dl->dial_timer.name = "dial"; 983006ec67SBrian Somers dl->dial_timer.arg = dl; 99dd7e2610SBrian Somers timer_Start(&dl->dial_timer); 1003006ec67SBrian Somers if (dl->state == DATALINK_OPENING) 101dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: Enter pause (%d) for redialing.\n", 1023006ec67SBrian Somers dl->name, Timeout); 1033006ec67SBrian Somers } 1043006ec67SBrian Somers } 1053006ec67SBrian Somers 1063006ec67SBrian Somers static void 1073006ec67SBrian Somers datalink_HangupDone(struct datalink *dl) 1083006ec67SBrian Somers { 109030e4ebbSBrian Somers if (dl->physical->type == PHYS_DEDICATED && !dl->bundle->CleaningUp && 110dd7e2610SBrian Somers physical_GetFD(dl->physical) != -1) { 111030e4ebbSBrian Somers /* Don't close our modem if the link is dedicated */ 112030e4ebbSBrian Somers datalink_LoginDone(dl); 113030e4ebbSBrian Somers return; 114030e4ebbSBrian Somers } 115030e4ebbSBrian Somers 1163006ec67SBrian Somers modem_Close(dl->physical); 117565e35e5SBrian Somers dl->phone.chosen = "N/A"; 1183006ec67SBrian Somers 1193b0f8d2eSBrian Somers if (dl->bundle->CleaningUp || 1206f384573SBrian Somers (dl->physical->type == PHYS_DIRECT) || 1213b0f8d2eSBrian Somers ((!dl->dial_tries || (dl->dial_tries < 0 && !dl->reconnect_tries)) && 122565e35e5SBrian Somers !(dl->physical->type & (PHYS_PERM|PHYS_DEDICATED)))) { 1239ae58882SBrian Somers datalink_NewState(dl, DATALINK_CLOSED); 1243006ec67SBrian Somers dl->dial_tries = -1; 1253006ec67SBrian Somers dl->reconnect_tries = 0; 1263006ec67SBrian Somers bundle_LinkClosed(dl->bundle, dl); 1273b0f8d2eSBrian Somers if (!dl->bundle->CleaningUp) 128565e35e5SBrian Somers datalink_StartDialTimer(dl, dl->cfg.dial.timeout); 1293006ec67SBrian Somers } else { 1309ae58882SBrian Somers datalink_NewState(dl, DATALINK_OPENING); 131abff9baeSBrian Somers if (dl->dial_tries < 0) { 132565e35e5SBrian Somers datalink_StartDialTimer(dl, dl->cfg.reconnect.timeout); 133565e35e5SBrian Somers dl->dial_tries = dl->cfg.dial.max; 134abff9baeSBrian Somers dl->reconnect_tries--; 135abff9baeSBrian Somers } else { 136f9545805SBrian Somers if (dl->phone.next == NULL) 137565e35e5SBrian Somers datalink_StartDialTimer(dl, dl->cfg.dial.timeout); 1383006ec67SBrian Somers else 139565e35e5SBrian Somers datalink_StartDialTimer(dl, dl->cfg.dial.next_timeout); 1403006ec67SBrian Somers } 141abff9baeSBrian Somers } 142abff9baeSBrian Somers } 1433006ec67SBrian Somers 144f9545805SBrian Somers static const char * 145f9545805SBrian Somers datalink_ChoosePhoneNumber(struct datalink *dl) 146f9545805SBrian Somers { 147f9545805SBrian Somers char *phone; 148f9545805SBrian Somers 149f9545805SBrian Somers if (dl->phone.alt == NULL) { 150f9545805SBrian Somers if (dl->phone.next == NULL) { 151f9545805SBrian Somers strncpy(dl->phone.list, dl->cfg.phone.list, sizeof dl->phone.list - 1); 152f9545805SBrian Somers dl->phone.list[sizeof dl->phone.list - 1] = '\0'; 153f9545805SBrian Somers dl->phone.next = dl->phone.list; 154f9545805SBrian Somers } 155f9545805SBrian Somers dl->phone.alt = strsep(&dl->phone.next, ":"); 156f9545805SBrian Somers } 157f9545805SBrian Somers phone = strsep(&dl->phone.alt, "|"); 158f9545805SBrian Somers dl->phone.chosen = *phone ? phone : "[NONE]"; 159f9545805SBrian Somers if (*phone) 160dd7e2610SBrian Somers log_Printf(LogPHASE, "Phone: %s\n", phone); 161f9545805SBrian Somers return phone; 162f9545805SBrian Somers } 163f9545805SBrian Somers 164c5a5a6caSBrian Somers static void 165c5a5a6caSBrian Somers datalink_LoginDone(struct datalink *dl) 166c5a5a6caSBrian Somers { 167d345321bSBrian Somers if (!dl->script.packetmode) { 168d345321bSBrian Somers dl->dial_tries = -1; 1699ae58882SBrian Somers datalink_NewState(dl, DATALINK_READY); 170d345321bSBrian Somers } else if (modem_Raw(dl->physical, dl->bundle) < 0) { 171c5a5a6caSBrian Somers dl->dial_tries = 0; 172dd7e2610SBrian Somers log_Printf(LogWARN, "datalink_LoginDone: Not connected.\n"); 173c5a5a6caSBrian Somers if (dl->script.run) { 1749ae58882SBrian Somers datalink_NewState(dl, DATALINK_HANGUP); 175c5a5a6caSBrian Somers modem_Offline(dl->physical); 176f9545805SBrian Somers chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL); 177030e4ebbSBrian Somers } else { 178030e4ebbSBrian Somers if (dl->physical->type == PHYS_DEDICATED) 179030e4ebbSBrian Somers /* force a redial timeout */ 180030e4ebbSBrian Somers modem_Close(dl->physical); 181c5a5a6caSBrian Somers datalink_HangupDone(dl); 182030e4ebbSBrian Somers } 183c5a5a6caSBrian Somers } else { 184c7cc5030SBrian Somers dl->dial_tries = -1; 185c7cc5030SBrian Somers 186643f4904SBrian Somers hdlc_Init(&dl->physical->hdlc, &dl->physical->link.lcp); 1873b0f8d2eSBrian Somers async_Init(&dl->physical->async); 1883b0f8d2eSBrian Somers 189cd9647a1SBrian Somers lcp_Setup(&dl->physical->link.lcp, dl->state == DATALINK_READY ? 190cd9647a1SBrian Somers 0 : dl->physical->link.lcp.cfg.openmode); 1913b0f8d2eSBrian Somers ccp_Setup(&dl->physical->link.ccp); 192503a7782SBrian Somers 1939ae58882SBrian Somers datalink_NewState(dl, DATALINK_LCP); 194dd7e2610SBrian Somers fsm_Up(&dl->physical->link.lcp.fsm); 195dd7e2610SBrian Somers fsm_Open(&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: 2096f384573SBrian Somers if ((dl->physical->type & (PHYS_DIRECT|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) { 2279ae58882SBrian Somers datalink_NewState(dl, DATALINK_DIAL); 228f9545805SBrian Somers chat_Init(&dl->chat, dl->physical, dl->cfg.script.dial, 1, 229f9545805SBrian Somers datalink_ChoosePhoneNumber(dl)); 230565e35e5SBrian Somers if (!(dl->physical->type & (PHYS_PERM|PHYS_DEDICATED)) && 231565e35e5SBrian Somers dl->cfg.dial.max) 232dd7e2610SBrian Somers log_Printf(LogCHAT, "%s: Dial attempt %u of %d\n", 233565e35e5SBrian Somers dl->name, dl->cfg.dial.max - dl->dial_tries, 234565e35e5SBrian Somers dl->cfg.dial.max); 2351342caedSBrian Somers return datalink_UpdateSet(d, r, w, e, n); 236c5a5a6caSBrian Somers } else 237c5a5a6caSBrian Somers datalink_LoginDone(dl); 2383006ec67SBrian Somers } else { 239565e35e5SBrian Somers if (!(dl->physical->type & (PHYS_PERM|PHYS_DEDICATED)) && 240565e35e5SBrian Somers dl->cfg.dial.max) 241dd7e2610SBrian Somers log_Printf(LogCHAT, "Failed to open modem (attempt %u of %d)\n", 242565e35e5SBrian Somers dl->cfg.dial.max - dl->dial_tries, dl->cfg.dial.max); 2433006ec67SBrian Somers else 244dd7e2610SBrian Somers log_Printf(LogCHAT, "Failed to open modem\n"); 2453006ec67SBrian Somers 2463b0f8d2eSBrian Somers if (dl->bundle->CleaningUp || 247565e35e5SBrian Somers (!(dl->physical->type & (PHYS_PERM|PHYS_DEDICATED)) && 248565e35e5SBrian Somers dl->cfg.dial.max && dl->dial_tries == 0)) { 2499ae58882SBrian Somers datalink_NewState(dl, DATALINK_CLOSED); 2503006ec67SBrian Somers dl->reconnect_tries = 0; 2513006ec67SBrian Somers dl->dial_tries = -1; 2525b8b8060SBrian Somers bundle_LinkClosed(dl->bundle, dl); 253c5a5a6caSBrian Somers } 2543b0f8d2eSBrian Somers if (!dl->bundle->CleaningUp) 255565e35e5SBrian Somers datalink_StartDialTimer(dl, dl->cfg.dial.timeout); 2563006ec67SBrian Somers } 2573006ec67SBrian Somers } 258310c3babSBrian Somers break; 2593006ec67SBrian Somers 2603006ec67SBrian Somers case DATALINK_HANGUP: 2613006ec67SBrian Somers case DATALINK_DIAL: 2623006ec67SBrian Somers case DATALINK_LOGIN: 2633006ec67SBrian Somers result = descriptor_UpdateSet(&dl->chat.desc, r, w, e, n); 2643006ec67SBrian Somers switch (dl->chat.state) { 2653006ec67SBrian Somers case CHAT_DONE: 2663006ec67SBrian Somers /* script succeeded */ 26739d94652SBrian Somers chat_Destroy(&dl->chat); 2683006ec67SBrian Somers switch(dl->state) { 2693006ec67SBrian Somers case DATALINK_HANGUP: 2703006ec67SBrian Somers datalink_HangupDone(dl); 2713006ec67SBrian Somers break; 2723006ec67SBrian Somers case DATALINK_DIAL: 2739ae58882SBrian Somers datalink_NewState(dl, DATALINK_LOGIN); 274f9545805SBrian Somers chat_Init(&dl->chat, dl->physical, dl->cfg.script.login, 0, NULL); 2751342caedSBrian Somers return datalink_UpdateSet(d, r, w, e, n); 2763006ec67SBrian Somers case DATALINK_LOGIN: 277c5a5a6caSBrian Somers datalink_LoginDone(dl); 2783006ec67SBrian Somers break; 2793006ec67SBrian Somers } 2803006ec67SBrian Somers break; 2813006ec67SBrian Somers case CHAT_FAILED: 2823006ec67SBrian Somers /* Going down - script failed */ 283dd7e2610SBrian Somers log_Printf(LogWARN, "Chat script failed\n"); 28439d94652SBrian Somers chat_Destroy(&dl->chat); 2853006ec67SBrian Somers switch(dl->state) { 2863006ec67SBrian Somers case DATALINK_HANGUP: 2873006ec67SBrian Somers datalink_HangupDone(dl); 2883006ec67SBrian Somers break; 2893006ec67SBrian Somers case DATALINK_DIAL: 2903006ec67SBrian Somers case DATALINK_LOGIN: 2919ae58882SBrian Somers datalink_NewState(dl, DATALINK_HANGUP); 2923006ec67SBrian Somers modem_Offline(dl->physical); 293f9545805SBrian Somers chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL); 2941342caedSBrian Somers return datalink_UpdateSet(d, r, w, e, n); 2953006ec67SBrian Somers } 2963006ec67SBrian Somers break; 2973006ec67SBrian Somers } 2983006ec67SBrian Somers break; 299c7cc5030SBrian Somers 300c7cc5030SBrian Somers case DATALINK_READY: 301e2ebb036SBrian Somers case DATALINK_LCP: 302e2ebb036SBrian Somers case DATALINK_AUTH: 3033006ec67SBrian Somers case DATALINK_OPEN: 3049ae58882SBrian Somers if (dl == dl->bundle->ncp.mp.server.send.dl) 3059ae58882SBrian Somers /* Never read our descriptor if we're scheduled for transfer */ 3069ae58882SBrian Somers r = NULL; 3073006ec67SBrian Somers result = descriptor_UpdateSet(&dl->physical->desc, r, w, e, n); 3083006ec67SBrian Somers break; 3093006ec67SBrian Somers } 3103006ec67SBrian Somers return result; 3113006ec67SBrian Somers } 3123006ec67SBrian Somers 3133006ec67SBrian Somers static int 3142f786681SBrian Somers datalink_IsSet(struct descriptor *d, const fd_set *fdset) 3153006ec67SBrian Somers { 3163006ec67SBrian Somers struct datalink *dl = descriptor2datalink(d); 3173006ec67SBrian Somers 3183006ec67SBrian Somers switch (dl->state) { 3193006ec67SBrian Somers case DATALINK_CLOSED: 320c7cc5030SBrian Somers case DATALINK_OPENING: 3213006ec67SBrian Somers break; 322c7cc5030SBrian Somers 3233006ec67SBrian Somers case DATALINK_HANGUP: 3243006ec67SBrian Somers case DATALINK_DIAL: 3253006ec67SBrian Somers case DATALINK_LOGIN: 3263006ec67SBrian Somers return descriptor_IsSet(&dl->chat.desc, fdset); 327c7cc5030SBrian Somers 328c7cc5030SBrian Somers case DATALINK_READY: 329e2ebb036SBrian Somers case DATALINK_LCP: 330e2ebb036SBrian Somers case DATALINK_AUTH: 3313006ec67SBrian Somers case DATALINK_OPEN: 3323006ec67SBrian Somers return descriptor_IsSet(&dl->physical->desc, fdset); 3333006ec67SBrian Somers } 3343006ec67SBrian Somers return 0; 3353006ec67SBrian Somers } 3363006ec67SBrian Somers 3373006ec67SBrian Somers static void 3383006ec67SBrian Somers datalink_Read(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) 3393006ec67SBrian Somers { 3403006ec67SBrian Somers struct datalink *dl = descriptor2datalink(d); 3413006ec67SBrian Somers 3423006ec67SBrian Somers switch (dl->state) { 3433006ec67SBrian Somers case DATALINK_CLOSED: 344c7cc5030SBrian Somers case DATALINK_OPENING: 3453006ec67SBrian Somers break; 346c7cc5030SBrian Somers 3473006ec67SBrian Somers case DATALINK_HANGUP: 3483006ec67SBrian Somers case DATALINK_DIAL: 3493006ec67SBrian Somers case DATALINK_LOGIN: 3503006ec67SBrian Somers descriptor_Read(&dl->chat.desc, bundle, fdset); 3513006ec67SBrian Somers break; 352c7cc5030SBrian Somers 353c7cc5030SBrian Somers case DATALINK_READY: 354e2ebb036SBrian Somers case DATALINK_LCP: 355e2ebb036SBrian Somers case DATALINK_AUTH: 3563006ec67SBrian Somers case DATALINK_OPEN: 3573006ec67SBrian Somers descriptor_Read(&dl->physical->desc, bundle, fdset); 3583006ec67SBrian Somers break; 3593006ec67SBrian Somers } 3603006ec67SBrian Somers } 3613006ec67SBrian Somers 3623006ec67SBrian Somers static void 363f4768038SBrian Somers datalink_Write(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) 3643006ec67SBrian Somers { 3653006ec67SBrian Somers struct datalink *dl = descriptor2datalink(d); 3663006ec67SBrian Somers 3673006ec67SBrian Somers switch (dl->state) { 3683006ec67SBrian Somers case DATALINK_CLOSED: 369c7cc5030SBrian Somers case DATALINK_OPENING: 3703006ec67SBrian Somers break; 371c7cc5030SBrian Somers 3723006ec67SBrian Somers case DATALINK_HANGUP: 3733006ec67SBrian Somers case DATALINK_DIAL: 3743006ec67SBrian Somers case DATALINK_LOGIN: 375f4768038SBrian Somers descriptor_Write(&dl->chat.desc, bundle, fdset); 3763006ec67SBrian Somers break; 377c7cc5030SBrian Somers 378c7cc5030SBrian Somers case DATALINK_READY: 379e2ebb036SBrian Somers case DATALINK_LCP: 380e2ebb036SBrian Somers case DATALINK_AUTH: 3813006ec67SBrian Somers case DATALINK_OPEN: 382f4768038SBrian Somers descriptor_Write(&dl->physical->desc, bundle, fdset); 3833006ec67SBrian Somers break; 3843006ec67SBrian Somers } 3853006ec67SBrian Somers } 3863006ec67SBrian Somers 3876d666775SBrian Somers static void 388e2ebb036SBrian Somers datalink_ComeDown(struct datalink *dl, int stay) 389e2ebb036SBrian Somers { 390e2ebb036SBrian Somers if (stay) { 391e2ebb036SBrian Somers dl->dial_tries = -1; 392e2ebb036SBrian Somers dl->reconnect_tries = 0; 393e2ebb036SBrian Somers } 394e2ebb036SBrian Somers 395e2ebb036SBrian Somers if (dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP) { 396e2ebb036SBrian Somers modem_Offline(dl->physical); 397e2ebb036SBrian Somers if (dl->script.run && dl->state != DATALINK_OPENING) { 3989ae58882SBrian Somers datalink_NewState(dl, DATALINK_HANGUP); 399f9545805SBrian Somers chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL); 400e2ebb036SBrian Somers } else 401e2ebb036SBrian Somers datalink_HangupDone(dl); 402e2ebb036SBrian Somers } 403e2ebb036SBrian Somers } 404e2ebb036SBrian Somers 405e2ebb036SBrian Somers static void 4066d666775SBrian Somers datalink_LayerStart(void *v, struct fsm *fp) 4076d666775SBrian Somers { 4086d666775SBrian Somers /* The given FSM is about to start up ! */ 4096d666775SBrian Somers struct datalink *dl = (struct datalink *)v; 410a611cad6SBrian Somers 41192e872e7SBrian Somers if (fp->proto == PROTO_LCP) 412e2ebb036SBrian Somers (*dl->parent->LayerStart)(dl->parent->object, fp); 413e2ebb036SBrian Somers } 4146d666775SBrian Somers 4156d666775SBrian Somers static void 4166d666775SBrian Somers datalink_LayerUp(void *v, struct fsm *fp) 4176d666775SBrian Somers { 4186d666775SBrian Somers /* The given fsm is now up */ 4196d666775SBrian Somers struct datalink *dl = (struct datalink *)v; 4206d666775SBrian Somers 42192e872e7SBrian Somers if (fp->proto == PROTO_LCP) { 422643f4904SBrian Somers datalink_GotAuthname(dl, "", 0); 4233b0f8d2eSBrian Somers dl->physical->link.lcp.auth_ineed = dl->physical->link.lcp.want_auth; 4243b0f8d2eSBrian Somers dl->physical->link.lcp.auth_iwait = dl->physical->link.lcp.his_auth; 4253b0f8d2eSBrian Somers if (dl->physical->link.lcp.his_auth || dl->physical->link.lcp.want_auth) { 4263b0f8d2eSBrian Somers if (bundle_Phase(dl->bundle) == PHASE_ESTABLISH) 4275563ebdeSBrian Somers bundle_NewPhase(dl->bundle, PHASE_AUTHENTICATE); 428dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: his = %s, mine = %s\n", dl->name, 4293b0f8d2eSBrian Somers Auth2Nam(dl->physical->link.lcp.his_auth), 4303b0f8d2eSBrian Somers Auth2Nam(dl->physical->link.lcp.want_auth)); 4313b0f8d2eSBrian Somers if (dl->physical->link.lcp.his_auth == PROTO_PAP) 432dd7e2610SBrian Somers auth_StartChallenge(&dl->pap, dl->physical, pap_SendChallenge); 4333b0f8d2eSBrian Somers if (dl->physical->link.lcp.want_auth == PROTO_CHAP) 434dd7e2610SBrian Somers auth_StartChallenge(&dl->chap.auth, dl->physical, chap_SendChallenge); 435e2ebb036SBrian Somers } else 436e2ebb036SBrian Somers datalink_AuthOk(dl); 437e2ebb036SBrian Somers } 438e2ebb036SBrian Somers } 439e2ebb036SBrian Somers 440e2ebb036SBrian Somers void 441643f4904SBrian Somers datalink_GotAuthname(struct datalink *dl, const char *name, int len) 442643f4904SBrian Somers { 443643f4904SBrian Somers if (len >= sizeof dl->peer.authname) 444643f4904SBrian Somers len = sizeof dl->peer.authname - 1; 445643f4904SBrian Somers strncpy(dl->peer.authname, name, len); 446643f4904SBrian Somers dl->peer.authname[len] = '\0'; 447643f4904SBrian Somers } 448643f4904SBrian Somers 449643f4904SBrian Somers void 450e2ebb036SBrian Somers datalink_AuthOk(struct datalink *dl) 451e2ebb036SBrian Somers { 452dbf60d74SBrian Somers if (dl->physical->link.lcp.want_mrru && dl->physical->link.lcp.his_mrru) { 4531fa665f5SBrian Somers /* we've authenticated in multilink mode ! */ 4541fa665f5SBrian Somers switch (mp_Up(&dl->bundle->ncp.mp, dl)) { 4551fa665f5SBrian Somers case MP_LINKSENT: 4561fa665f5SBrian Somers /* We've handed the link off to another ppp ! */ 4571fa665f5SBrian Somers return; 4581fa665f5SBrian Somers case MP_UP: 459dd7e2610SBrian Somers auth_Select(dl->bundle, dl->peer.authname, dl->physical); 460078c562eSBrian Somers break; 4611fa665f5SBrian Somers case MP_ADDED: 462078c562eSBrian Somers /* We were already in multilink mode ! */ 4631fa665f5SBrian Somers break; 4641fa665f5SBrian Somers case MP_FAILED: 46549052c95SBrian Somers datalink_AuthNotOk(dl); 46649052c95SBrian Somers return; 46749052c95SBrian Somers } 46849052c95SBrian Somers } else if (bundle_Phase(dl->bundle) == PHASE_NETWORK) { 469dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: Already in NETWORK phase\n", dl->name); 47049052c95SBrian Somers datalink_AuthNotOk(dl); 47149052c95SBrian Somers return; 47250abd4c8SBrian Somers } else { 47350abd4c8SBrian Somers dl->bundle->ncp.mp.peer = dl->peer; 474ce828a6eSBrian Somers ipcp_SetLink(&dl->bundle->ncp.ipcp, &dl->physical->link); 475dd7e2610SBrian Somers auth_Select(dl->bundle, dl->peer.authname, dl->physical); 47650abd4c8SBrian Somers } 47749052c95SBrian Somers 478dd7e2610SBrian Somers fsm_Up(&dl->physical->link.ccp.fsm); 479dd7e2610SBrian Somers fsm_Open(&dl->physical->link.ccp.fsm); 4809ae58882SBrian Somers datalink_NewState(dl, DATALINK_OPEN); 4813b0f8d2eSBrian Somers bundle_NewPhase(dl->bundle, PHASE_NETWORK); 4823b0f8d2eSBrian Somers (*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.lcp.fsm); 4836d666775SBrian Somers } 484e2ebb036SBrian Somers 485e2ebb036SBrian Somers void 486e2ebb036SBrian Somers datalink_AuthNotOk(struct datalink *dl) 487e2ebb036SBrian Somers { 4889ae58882SBrian Somers datalink_NewState(dl, DATALINK_LCP); 489dd7e2610SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 4906d666775SBrian Somers } 4916d666775SBrian Somers 4926d666775SBrian Somers static void 4936d666775SBrian Somers datalink_LayerDown(void *v, struct fsm *fp) 4946d666775SBrian Somers { 4956d666775SBrian Somers /* The given FSM has been told to come down */ 4966d666775SBrian Somers struct datalink *dl = (struct datalink *)v; 497a611cad6SBrian Somers 49892e872e7SBrian Somers if (fp->proto == PROTO_LCP) { 499e2ebb036SBrian Somers switch (dl->state) { 500e2ebb036SBrian Somers case DATALINK_OPEN: 501643f4904SBrian Somers peerid_Init(&dl->peer); 502dd7e2610SBrian Somers fsm_Down(&dl->physical->link.ccp.fsm); 503dd7e2610SBrian Somers fsm_Close(&dl->physical->link.ccp.fsm); 504e2ebb036SBrian Somers (*dl->parent->LayerDown)(dl->parent->object, fp); 505e2ebb036SBrian Somers /* fall through */ 506e2ebb036SBrian Somers 507e2ebb036SBrian Somers case DATALINK_AUTH: 508dd7e2610SBrian Somers timer_Stop(&dl->pap.authtimer); 509dd7e2610SBrian Somers timer_Stop(&dl->chap.auth.authtimer); 5106d666775SBrian Somers } 5119ae58882SBrian Somers datalink_NewState(dl, DATALINK_LCP); 512e2ebb036SBrian Somers } 5136d666775SBrian Somers } 5146d666775SBrian Somers 5156d666775SBrian Somers static void 5166d666775SBrian Somers datalink_LayerFinish(void *v, struct fsm *fp) 5176d666775SBrian Somers { 5186d666775SBrian Somers /* The given fsm is now down */ 5196d666775SBrian Somers struct datalink *dl = (struct datalink *)v; 5206d666775SBrian Somers 52192e872e7SBrian Somers if (fp->proto == PROTO_LCP) { 522dd7e2610SBrian Somers fsm_Down(fp); /* Bring us to INITIAL or STARTING */ 5236d666775SBrian Somers (*dl->parent->LayerFinish)(dl->parent->object, fp); 524e2ebb036SBrian Somers datalink_ComeDown(dl, 0); 5256d666775SBrian Somers } 5266d666775SBrian Somers } 5276d666775SBrian Somers 5283006ec67SBrian Somers struct datalink * 5296f384573SBrian Somers datalink_Create(const char *name, struct bundle *bundle, int type) 5303006ec67SBrian Somers { 5313006ec67SBrian Somers struct datalink *dl; 5323006ec67SBrian Somers 5333006ec67SBrian Somers dl = (struct datalink *)malloc(sizeof(struct datalink)); 5343006ec67SBrian Somers if (dl == NULL) 5353006ec67SBrian Somers return dl; 5363006ec67SBrian Somers 5373006ec67SBrian Somers dl->desc.type = DATALINK_DESCRIPTOR; 5383006ec67SBrian Somers dl->desc.next = NULL; 5393006ec67SBrian Somers dl->desc.UpdateSet = datalink_UpdateSet; 5403006ec67SBrian Somers dl->desc.IsSet = datalink_IsSet; 5413006ec67SBrian Somers dl->desc.Read = datalink_Read; 5423006ec67SBrian Somers dl->desc.Write = datalink_Write; 5435b8b8060SBrian Somers 544e718d1d7SBrian Somers dl->state = DATALINK_CLOSED; 545e718d1d7SBrian Somers 54673a13b5cSBrian Somers *dl->cfg.script.dial = '\0'; 54773a13b5cSBrian Somers *dl->cfg.script.login = '\0'; 54873a13b5cSBrian Somers *dl->cfg.script.hangup = '\0'; 549f9545805SBrian Somers *dl->cfg.phone.list = '\0'; 550f9545805SBrian Somers *dl->phone.list = '\0'; 551f9545805SBrian Somers dl->phone.next = NULL; 552f9545805SBrian Somers dl->phone.alt = NULL; 553f9545805SBrian Somers dl->phone.chosen = "N/A"; 554c7cc5030SBrian Somers dl->script.run = 1; 555c7cc5030SBrian Somers dl->script.packetmode = 1; 5563b0f8d2eSBrian Somers mp_linkInit(&dl->mp); 5575b8b8060SBrian Somers 5583006ec67SBrian Somers dl->bundle = bundle; 5593006ec67SBrian Somers dl->next = NULL; 560e718d1d7SBrian Somers 5613006ec67SBrian Somers memset(&dl->dial_timer, '\0', sizeof dl->dial_timer); 562e718d1d7SBrian Somers 5633006ec67SBrian Somers dl->dial_tries = 0; 564565e35e5SBrian Somers dl->cfg.dial.max = 1; 565565e35e5SBrian Somers dl->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT; 566565e35e5SBrian Somers dl->cfg.dial.timeout = DIAL_TIMEOUT; 567e718d1d7SBrian Somers 568abff9baeSBrian Somers dl->reconnect_tries = 0; 569565e35e5SBrian Somers dl->cfg.reconnect.max = 0; 570565e35e5SBrian Somers dl->cfg.reconnect.timeout = RECONNECT_TIMEOUT; 571abff9baeSBrian Somers 5723006ec67SBrian Somers dl->name = strdup(name); 573643f4904SBrian Somers peerid_Init(&dl->peer); 5746f384573SBrian Somers dl->parent = &bundle->fsm; 5753b0f8d2eSBrian Somers dl->fsmp.LayerStart = datalink_LayerStart; 5763b0f8d2eSBrian Somers dl->fsmp.LayerUp = datalink_LayerUp; 5773b0f8d2eSBrian Somers dl->fsmp.LayerDown = datalink_LayerDown; 5783b0f8d2eSBrian Somers dl->fsmp.LayerFinish = datalink_LayerFinish; 5793b0f8d2eSBrian Somers dl->fsmp.object = dl; 5803b0f8d2eSBrian Somers 581dd7e2610SBrian Somers auth_Init(&dl->pap); 582dd7e2610SBrian Somers auth_Init(&dl->chap.auth); 5833b0f8d2eSBrian Somers 584565e35e5SBrian Somers if ((dl->physical = modem_Create(dl, type)) == NULL) { 5853006ec67SBrian Somers free(dl->name); 5863006ec67SBrian Somers free(dl); 5873006ec67SBrian Somers return NULL; 5883006ec67SBrian Somers } 589f9545805SBrian Somers chat_Init(&dl->chat, dl->physical, NULL, 1, NULL); 5903006ec67SBrian Somers 5919ae58882SBrian Somers log_Printf(LogPHASE, "%s: Created in %s state\n", 5929ae58882SBrian Somers dl->name, datalink_State(dl)); 5933006ec67SBrian Somers 5943006ec67SBrian Somers return dl; 5953006ec67SBrian Somers } 5963006ec67SBrian Somers 5973006ec67SBrian Somers struct datalink * 598cd7bd93aSBrian Somers datalink_Clone(struct datalink *odl, const char *name) 599cd7bd93aSBrian Somers { 600cd7bd93aSBrian Somers struct datalink *dl; 601cd7bd93aSBrian Somers 602cd7bd93aSBrian Somers dl = (struct datalink *)malloc(sizeof(struct datalink)); 603cd7bd93aSBrian Somers if (dl == NULL) 604cd7bd93aSBrian Somers return dl; 605cd7bd93aSBrian Somers 606cd7bd93aSBrian Somers dl->desc.type = DATALINK_DESCRIPTOR; 607cd7bd93aSBrian Somers dl->desc.next = NULL; 608cd7bd93aSBrian Somers dl->desc.UpdateSet = datalink_UpdateSet; 609cd7bd93aSBrian Somers dl->desc.IsSet = datalink_IsSet; 610cd7bd93aSBrian Somers dl->desc.Read = datalink_Read; 611cd7bd93aSBrian Somers dl->desc.Write = datalink_Write; 612cd7bd93aSBrian Somers 613cd7bd93aSBrian Somers dl->state = DATALINK_CLOSED; 614cd7bd93aSBrian Somers 615cd7bd93aSBrian Somers memcpy(&dl->cfg, &odl->cfg, sizeof dl->cfg); 616cd7bd93aSBrian Somers mp_linkInit(&dl->mp); 617cd7bd93aSBrian Somers *dl->phone.list = '\0'; 618643f4904SBrian Somers dl->phone.next = NULL; 619643f4904SBrian Somers dl->phone.alt = NULL; 620643f4904SBrian Somers dl->phone.chosen = "N/A"; 621cd7bd93aSBrian Somers dl->bundle = odl->bundle; 622cd7bd93aSBrian Somers dl->next = NULL; 623cd7bd93aSBrian Somers memset(&dl->dial_timer, '\0', sizeof dl->dial_timer); 624cd7bd93aSBrian Somers dl->dial_tries = 0; 625cd7bd93aSBrian Somers dl->reconnect_tries = 0; 626cd7bd93aSBrian Somers dl->name = strdup(name); 627643f4904SBrian Somers peerid_Init(&dl->peer); 628cd7bd93aSBrian Somers dl->parent = odl->parent; 629cd7bd93aSBrian Somers memcpy(&dl->fsmp, &odl->fsmp, sizeof dl->fsmp); 630643f4904SBrian Somers dl->fsmp.object = dl; 631dd7e2610SBrian Somers auth_Init(&dl->pap); 632cd7bd93aSBrian Somers dl->pap.cfg.fsmretry = odl->pap.cfg.fsmretry; 633cd7bd93aSBrian Somers 634dd7e2610SBrian Somers auth_Init(&dl->chap.auth); 635cd7bd93aSBrian Somers dl->chap.auth.cfg.fsmretry = odl->chap.auth.cfg.fsmretry; 636cd7bd93aSBrian Somers 637565e35e5SBrian Somers if ((dl->physical = modem_Create(dl, PHYS_MANUAL)) == NULL) { 638cd7bd93aSBrian Somers free(dl->name); 639cd7bd93aSBrian Somers free(dl); 640cd7bd93aSBrian Somers return NULL; 641cd7bd93aSBrian Somers } 642cd7bd93aSBrian Somers memcpy(&dl->physical->cfg, &odl->physical->cfg, sizeof dl->physical->cfg); 643cd7bd93aSBrian Somers memcpy(&dl->physical->link.lcp.cfg, &odl->physical->link.lcp.cfg, 644cd7bd93aSBrian Somers sizeof dl->physical->link.lcp.cfg); 645cd7bd93aSBrian Somers memcpy(&dl->physical->link.ccp.cfg, &odl->physical->link.ccp.cfg, 646cd7bd93aSBrian Somers sizeof dl->physical->link.ccp.cfg); 647cd7bd93aSBrian Somers memcpy(&dl->physical->async.cfg, &odl->physical->async.cfg, 648cd7bd93aSBrian Somers sizeof dl->physical->async.cfg); 649cd7bd93aSBrian Somers 650cd7bd93aSBrian Somers chat_Init(&dl->chat, dl->physical, NULL, 1, NULL); 651cd7bd93aSBrian Somers 6529ae58882SBrian Somers log_Printf(LogPHASE, "%s: Cloned in %s state\n", 6539ae58882SBrian Somers dl->name, datalink_State(dl)); 654cd7bd93aSBrian Somers 655cd7bd93aSBrian Somers return dl; 656cd7bd93aSBrian Somers } 657cd7bd93aSBrian Somers 658cd7bd93aSBrian Somers struct datalink * 6593006ec67SBrian Somers datalink_Destroy(struct datalink *dl) 6603006ec67SBrian Somers { 6613006ec67SBrian Somers struct datalink *result; 6623006ec67SBrian Somers 66339d94652SBrian Somers if (dl->state != DATALINK_CLOSED) { 664dd7e2610SBrian Somers log_Printf(LogERROR, "Oops, destroying a datalink in state %s\n", 665c7cc5030SBrian Somers datalink_State(dl)); 66639d94652SBrian Somers switch (dl->state) { 66739d94652SBrian Somers case DATALINK_HANGUP: 66839d94652SBrian Somers case DATALINK_DIAL: 66939d94652SBrian Somers case DATALINK_LOGIN: 67039d94652SBrian Somers chat_Destroy(&dl->chat); /* Gotta blat the timers ! */ 67139d94652SBrian Somers break; 67239d94652SBrian Somers } 67339d94652SBrian Somers } 6743006ec67SBrian Somers 6753006ec67SBrian Somers result = dl->next; 6763b0f8d2eSBrian Somers modem_Destroy(dl->physical); 6773006ec67SBrian Somers free(dl->name); 6783006ec67SBrian Somers free(dl); 6793006ec67SBrian Somers 6803006ec67SBrian Somers return result; 6813006ec67SBrian Somers } 6823006ec67SBrian Somers 6833006ec67SBrian Somers void 684c5a5a6caSBrian Somers datalink_Up(struct datalink *dl, int runscripts, int packetmode) 6853006ec67SBrian Somers { 6866f384573SBrian Somers if (dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED)) 687565e35e5SBrian Somers /* Ignore scripts */ 688565e35e5SBrian Somers runscripts = 0; 689565e35e5SBrian Somers 690c7cc5030SBrian Somers switch (dl->state) { 691c7cc5030SBrian Somers case DATALINK_CLOSED: 6923b0f8d2eSBrian Somers if (bundle_Phase(dl->bundle) == PHASE_DEAD || 6933b0f8d2eSBrian Somers bundle_Phase(dl->bundle) == PHASE_TERMINATE) 6943b0f8d2eSBrian Somers bundle_NewPhase(dl->bundle, PHASE_ESTABLISH); 6959ae58882SBrian Somers datalink_NewState(dl, DATALINK_OPENING); 696565e35e5SBrian Somers dl->reconnect_tries = 6976f384573SBrian Somers dl->physical->type == PHYS_DIRECT ? 0 : dl->cfg.reconnect.max; 698565e35e5SBrian Somers dl->dial_tries = dl->cfg.dial.max; 699c5a5a6caSBrian Somers dl->script.run = runscripts; 700c5a5a6caSBrian Somers dl->script.packetmode = packetmode; 701c7cc5030SBrian Somers break; 702c7cc5030SBrian Somers 703c7cc5030SBrian Somers case DATALINK_OPENING: 704c7cc5030SBrian Somers if (!dl->script.run && runscripts) 705c7cc5030SBrian Somers dl->script.run = 1; 706c7cc5030SBrian Somers /* fall through */ 707c7cc5030SBrian Somers 708c7cc5030SBrian Somers case DATALINK_DIAL: 709c7cc5030SBrian Somers case DATALINK_LOGIN: 710c7cc5030SBrian Somers case DATALINK_READY: 711c7cc5030SBrian Somers if (!dl->script.packetmode && packetmode) { 712c7cc5030SBrian Somers dl->script.packetmode = 1; 713c7cc5030SBrian Somers if (dl->state == DATALINK_READY) 714c7cc5030SBrian Somers datalink_LoginDone(dl); 715c7cc5030SBrian Somers } 716c7cc5030SBrian Somers break; 7173006ec67SBrian Somers } 7183006ec67SBrian Somers } 7193006ec67SBrian Somers 7203006ec67SBrian Somers void 721c7cc5030SBrian Somers datalink_Close(struct datalink *dl, int stay) 722c7cc5030SBrian Somers { 723c7cc5030SBrian Somers /* Please close */ 724e2ebb036SBrian Somers switch (dl->state) { 725e2ebb036SBrian Somers case DATALINK_OPEN: 726643f4904SBrian Somers peerid_Init(&dl->peer); 727dd7e2610SBrian Somers fsm_Down(&dl->physical->link.ccp.fsm); 728dd7e2610SBrian Somers fsm_Close(&dl->physical->link.ccp.fsm); 729e2ebb036SBrian Somers /* fall through */ 730e2ebb036SBrian Somers 731e2ebb036SBrian Somers case DATALINK_AUTH: 732e2ebb036SBrian Somers case DATALINK_LCP: 733dd7e2610SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 734c7cc5030SBrian Somers if (stay) { 735c7cc5030SBrian Somers dl->dial_tries = -1; 736c7cc5030SBrian Somers dl->reconnect_tries = 0; 737c7cc5030SBrian Somers } 738e2ebb036SBrian Somers break; 739e2ebb036SBrian Somers 740e2ebb036SBrian Somers default: 741c7cc5030SBrian Somers datalink_ComeDown(dl, stay); 742c7cc5030SBrian Somers } 743e2ebb036SBrian Somers } 744c7cc5030SBrian Somers 745c7cc5030SBrian Somers void 746c7cc5030SBrian Somers datalink_Down(struct datalink *dl, int stay) 747c7cc5030SBrian Somers { 748c7cc5030SBrian Somers /* Carrier is lost */ 749e2ebb036SBrian Somers switch (dl->state) { 750e2ebb036SBrian Somers case DATALINK_OPEN: 751643f4904SBrian Somers peerid_Init(&dl->peer); 752dd7e2610SBrian Somers fsm_Down(&dl->physical->link.ccp.fsm); 753dd7e2610SBrian Somers fsm_Close(&dl->physical->link.ccp.fsm); 754e2ebb036SBrian Somers /* fall through */ 755e2ebb036SBrian Somers 756e2ebb036SBrian Somers case DATALINK_AUTH: 757e2ebb036SBrian Somers case DATALINK_LCP: 758dd7e2610SBrian Somers fsm_Down(&dl->physical->link.lcp.fsm); 759c7cc5030SBrian Somers if (stay) 760dd7e2610SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 761c7cc5030SBrian Somers else 762dd7e2610SBrian Somers fsm_Open(&dl->physical->link.ccp.fsm); 763e2ebb036SBrian Somers /* fall through */ 764c7cc5030SBrian Somers 765e2ebb036SBrian Somers default: 766c7cc5030SBrian Somers datalink_ComeDown(dl, stay); 767c7cc5030SBrian Somers } 768e2ebb036SBrian Somers } 769c7cc5030SBrian Somers 770c7cc5030SBrian Somers void 7713006ec67SBrian Somers datalink_StayDown(struct datalink *dl) 7723006ec67SBrian Somers { 7733006ec67SBrian Somers dl->reconnect_tries = 0; 7743006ec67SBrian Somers } 775c7cc5030SBrian Somers 776643f4904SBrian Somers int 777643f4904SBrian Somers datalink_Show(struct cmdargs const *arg) 778c7cc5030SBrian Somers { 779643f4904SBrian Somers prompt_Printf(arg->prompt, "Name: %s\n", arg->cx->name); 780643f4904SBrian Somers prompt_Printf(arg->prompt, " State: %s\n", 781643f4904SBrian Somers datalink_State(arg->cx)); 782643f4904SBrian Somers prompt_Printf(arg->prompt, " CHAP Encryption: %s\n", 783643f4904SBrian Somers arg->cx->chap.using_MSChap ? "MSChap" : "MD5" ); 784643f4904SBrian Somers prompt_Printf(arg->prompt, " Peer name: "); 785643f4904SBrian Somers if (*arg->cx->peer.authname) 786643f4904SBrian Somers prompt_Printf(arg->prompt, "%s\n", arg->cx->peer.authname); 787643f4904SBrian Somers else if (arg->cx->state == DATALINK_OPEN) 788643f4904SBrian Somers prompt_Printf(arg->prompt, "None requested\n"); 789565e35e5SBrian Somers else 790643f4904SBrian Somers prompt_Printf(arg->prompt, "N/A\n"); 791643f4904SBrian Somers prompt_Printf(arg->prompt, " Discriminator: %s\n", 792643f4904SBrian Somers mp_Enddisc(arg->cx->peer.enddisc.class, 793643f4904SBrian Somers arg->cx->peer.enddisc.address, 794643f4904SBrian Somers arg->cx->peer.enddisc.len)); 795643f4904SBrian Somers 796643f4904SBrian Somers prompt_Printf(arg->prompt, "\nDefaults:\n"); 797643f4904SBrian Somers prompt_Printf(arg->prompt, " Phone List: %s\n", 798643f4904SBrian Somers arg->cx->cfg.phone.list); 799643f4904SBrian Somers if (arg->cx->cfg.dial.max) 800643f4904SBrian Somers prompt_Printf(arg->prompt, " Dial tries: %d, delay ", 801643f4904SBrian Somers arg->cx->cfg.dial.max); 802565e35e5SBrian Somers else 803643f4904SBrian Somers prompt_Printf(arg->prompt, " Dial tries: infinite, delay "); 804643f4904SBrian Somers if (arg->cx->cfg.dial.next_timeout > 0) 805643f4904SBrian Somers prompt_Printf(arg->prompt, "%ds/", arg->cx->cfg.dial.next_timeout); 806565e35e5SBrian Somers else 807643f4904SBrian Somers prompt_Printf(arg->prompt, "random/"); 808643f4904SBrian Somers if (arg->cx->cfg.dial.timeout > 0) 809643f4904SBrian Somers prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.dial.timeout); 810565e35e5SBrian Somers else 811643f4904SBrian Somers prompt_Printf(arg->prompt, "random\n"); 812643f4904SBrian Somers prompt_Printf(arg->prompt, " Reconnect tries: %d, delay ", 813643f4904SBrian Somers arg->cx->cfg.reconnect.max); 814643f4904SBrian Somers if (arg->cx->cfg.reconnect.timeout > 0) 815643f4904SBrian Somers prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.reconnect.timeout); 816643f4904SBrian Somers else 817643f4904SBrian Somers prompt_Printf(arg->prompt, "random\n"); 818643f4904SBrian Somers prompt_Printf(arg->prompt, " Dial Script: %s\n", 819643f4904SBrian Somers arg->cx->cfg.script.dial); 820643f4904SBrian Somers prompt_Printf(arg->prompt, " Login Script: %s\n", 821643f4904SBrian Somers arg->cx->cfg.script.login); 822643f4904SBrian Somers prompt_Printf(arg->prompt, " Hangup Script: %s\n", 823643f4904SBrian Somers arg->cx->cfg.script.hangup); 824643f4904SBrian Somers return 0; 825565e35e5SBrian Somers } 826565e35e5SBrian Somers 827565e35e5SBrian Somers int 828565e35e5SBrian Somers datalink_SetReconnect(struct cmdargs const *arg) 829565e35e5SBrian Somers { 83025092092SBrian Somers if (arg->argc == arg->argn+2) { 83125092092SBrian Somers arg->cx->cfg.reconnect.timeout = atoi(arg->argv[arg->argn]); 83225092092SBrian Somers arg->cx->cfg.reconnect.max = atoi(arg->argv[arg->argn+1]); 833565e35e5SBrian Somers return 0; 834565e35e5SBrian Somers } 835565e35e5SBrian Somers return -1; 836565e35e5SBrian Somers } 837565e35e5SBrian Somers 838565e35e5SBrian Somers int 839565e35e5SBrian Somers datalink_SetRedial(struct cmdargs const *arg) 840565e35e5SBrian Somers { 841565e35e5SBrian Somers int timeout; 842565e35e5SBrian Somers int tries; 843565e35e5SBrian Somers char *dot; 844565e35e5SBrian Somers 84525092092SBrian Somers if (arg->argc == arg->argn+1 || arg->argc == arg->argn+2) { 84625092092SBrian Somers if (strncasecmp(arg->argv[arg->argn], "random", 6) == 0 && 84725092092SBrian Somers (arg->argv[arg->argn][6] == '\0' || arg->argv[arg->argn][6] == '.')) { 848565e35e5SBrian Somers arg->cx->cfg.dial.timeout = -1; 849565e35e5SBrian Somers randinit(); 850565e35e5SBrian Somers } else { 85125092092SBrian Somers timeout = atoi(arg->argv[arg->argn]); 852565e35e5SBrian Somers 853565e35e5SBrian Somers if (timeout >= 0) 854565e35e5SBrian Somers arg->cx->cfg.dial.timeout = timeout; 855565e35e5SBrian Somers else { 856dd7e2610SBrian Somers log_Printf(LogWARN, "Invalid redial timeout\n"); 857565e35e5SBrian Somers return -1; 858565e35e5SBrian Somers } 859565e35e5SBrian Somers } 860565e35e5SBrian Somers 86125092092SBrian Somers dot = strchr(arg->argv[arg->argn], '.'); 862565e35e5SBrian Somers if (dot) { 863565e35e5SBrian Somers if (strcasecmp(++dot, "random") == 0) { 864565e35e5SBrian Somers arg->cx->cfg.dial.next_timeout = -1; 865565e35e5SBrian Somers randinit(); 866565e35e5SBrian Somers } else { 867565e35e5SBrian Somers timeout = atoi(dot); 868565e35e5SBrian Somers if (timeout >= 0) 869565e35e5SBrian Somers arg->cx->cfg.dial.next_timeout = timeout; 870565e35e5SBrian Somers else { 871dd7e2610SBrian Somers log_Printf(LogWARN, "Invalid next redial timeout\n"); 872565e35e5SBrian Somers return -1; 873565e35e5SBrian Somers } 874565e35e5SBrian Somers } 875565e35e5SBrian Somers } else 876565e35e5SBrian Somers /* Default next timeout */ 877565e35e5SBrian Somers arg->cx->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT; 878565e35e5SBrian Somers 87925092092SBrian Somers if (arg->argc == arg->argn+2) { 88025092092SBrian Somers tries = atoi(arg->argv[arg->argn+1]); 881565e35e5SBrian Somers 882565e35e5SBrian Somers if (tries >= 0) { 883565e35e5SBrian Somers arg->cx->cfg.dial.max = tries; 884565e35e5SBrian Somers } else { 885dd7e2610SBrian Somers log_Printf(LogWARN, "Invalid retry value\n"); 886565e35e5SBrian Somers return 1; 887565e35e5SBrian Somers } 888565e35e5SBrian Somers } 889565e35e5SBrian Somers return 0; 890565e35e5SBrian Somers } 891565e35e5SBrian Somers return -1; 892c7cc5030SBrian Somers } 893c7cc5030SBrian Somers 894cdbbb6b5SBrian Somers static const char *states[] = { 895565e35e5SBrian Somers "closed", 896565e35e5SBrian Somers "opening", 897565e35e5SBrian Somers "hangup", 898565e35e5SBrian Somers "dial", 899565e35e5SBrian Somers "login", 900565e35e5SBrian Somers "ready", 901565e35e5SBrian Somers "lcp", 902565e35e5SBrian Somers "auth", 903565e35e5SBrian Somers "open" 904c7cc5030SBrian Somers }; 905c7cc5030SBrian Somers 906643f4904SBrian Somers const char * 907c7cc5030SBrian Somers datalink_State(struct datalink *dl) 908c7cc5030SBrian Somers { 909c7cc5030SBrian Somers if (dl->state < 0 || dl->state >= sizeof states / sizeof states[0]) 910c7cc5030SBrian Somers return "unknown"; 911c7cc5030SBrian Somers return states[dl->state]; 912c7cc5030SBrian Somers } 9136f384573SBrian Somers 9149ae58882SBrian Somers static void 9159ae58882SBrian Somers datalink_NewState(struct datalink *dl, int state) 9169ae58882SBrian Somers { 9179ae58882SBrian Somers if (state != dl->state) { 9189ae58882SBrian Somers if (state >= 0 && state < sizeof states / sizeof states[0]) { 9199ae58882SBrian Somers log_Printf(LogPHASE, "%s: %s -> %s\n", dl->name, datalink_State(dl), 9209ae58882SBrian Somers states[state]); 9219ae58882SBrian Somers dl->state = state; 9229ae58882SBrian Somers } else 9239ae58882SBrian Somers log_Printf(LogERROR, "%s: Can't enter state %d !\n", dl->name, state); 9249ae58882SBrian Somers } 9259ae58882SBrian Somers } 9269ae58882SBrian Somers 9276f384573SBrian Somers struct datalink * 92896c9bb21SBrian Somers iov2datalink(struct bundle *bundle, struct iovec *iov, int *niov, int maxiov, 92996c9bb21SBrian Somers int fd) 9306f384573SBrian Somers { 931b7c5748eSBrian Somers struct datalink *dl, *cdl; 9326f384573SBrian Somers u_int retry; 933b7c5748eSBrian Somers char *oname; 9346f384573SBrian Somers 93596c9bb21SBrian Somers dl = (struct datalink *)iov[(*niov)++].iov_base; 93696c9bb21SBrian Somers dl->name = iov[*niov].iov_base; 9376f384573SBrian Somers 93896c9bb21SBrian Somers if (dl->name[DATALINK_MAXNAME-1]) { 93996c9bb21SBrian Somers dl->name[DATALINK_MAXNAME-1] = '\0'; 94096c9bb21SBrian Somers if (strlen(dl->name) == DATALINK_MAXNAME - 1) 94196c9bb21SBrian Somers log_Printf(LogWARN, "Datalink name truncated to \"%s\"\n", dl->name); 9426f384573SBrian Somers } 943b7c5748eSBrian Somers 944b7c5748eSBrian Somers /* Make sure the name is unique ! */ 945b7c5748eSBrian Somers oname = NULL; 946b7c5748eSBrian Somers do { 947b7c5748eSBrian Somers for (cdl = bundle->links; cdl; cdl = cdl->next) 948b7c5748eSBrian Somers if (!strcasecmp(dl->name, cdl->name)) { 949b7c5748eSBrian Somers if (oname) 950b7c5748eSBrian Somers free(datalink_NextName(dl)); 951b7c5748eSBrian Somers else 952b7c5748eSBrian Somers oname = datalink_NextName(dl); 953b7c5748eSBrian Somers break; /* Keep renaming 'till we have no conflicts */ 954b7c5748eSBrian Somers } 955b7c5748eSBrian Somers } while (cdl); 956b7c5748eSBrian Somers 957b7c5748eSBrian Somers if (oname) { 958b7c5748eSBrian Somers log_Printf(LogPHASE, "Rename link %s to %s\n", oname, dl->name); 959b7c5748eSBrian Somers free(oname); 960b7c5748eSBrian Somers } else { 96196c9bb21SBrian Somers dl->name = strdup(dl->name); 962b7c5748eSBrian Somers free(iov[*niov].iov_base); 963b7c5748eSBrian Somers } 964b7c5748eSBrian Somers (*niov)++; 9656f384573SBrian Somers 9666f384573SBrian Somers dl->desc.type = DATALINK_DESCRIPTOR; 9676f384573SBrian Somers dl->desc.next = NULL; 9686f384573SBrian Somers dl->desc.UpdateSet = datalink_UpdateSet; 9696f384573SBrian Somers dl->desc.IsSet = datalink_IsSet; 9706f384573SBrian Somers dl->desc.Read = datalink_Read; 9716f384573SBrian Somers dl->desc.Write = datalink_Write; 9726f384573SBrian Somers 9736f384573SBrian Somers mp_linkInit(&dl->mp); 9746f384573SBrian Somers *dl->phone.list = '\0'; 9756f384573SBrian Somers dl->phone.next = NULL; 9766f384573SBrian Somers dl->phone.alt = NULL; 9776f384573SBrian Somers dl->phone.chosen = "N/A"; 9786f384573SBrian Somers 9796f384573SBrian Somers dl->bundle = bundle; 9806f384573SBrian Somers dl->next = NULL; 9816f384573SBrian Somers memset(&dl->dial_timer, '\0', sizeof dl->dial_timer); 9826f384573SBrian Somers dl->dial_tries = 0; 9836f384573SBrian Somers dl->reconnect_tries = 0; 9846f384573SBrian Somers dl->parent = &bundle->fsm; 9856f384573SBrian Somers dl->fsmp.LayerStart = datalink_LayerStart; 9866f384573SBrian Somers dl->fsmp.LayerUp = datalink_LayerUp; 9876f384573SBrian Somers dl->fsmp.LayerDown = datalink_LayerDown; 9886f384573SBrian Somers dl->fsmp.LayerFinish = datalink_LayerFinish; 9896f384573SBrian Somers dl->fsmp.object = dl; 9906f384573SBrian Somers 9916f384573SBrian Somers retry = dl->pap.cfg.fsmretry; 992dd7e2610SBrian Somers auth_Init(&dl->pap); 9936f384573SBrian Somers dl->pap.cfg.fsmretry = retry; 9946f384573SBrian Somers 9956f384573SBrian Somers retry = dl->chap.auth.cfg.fsmretry; 996dd7e2610SBrian Somers auth_Init(&dl->chap.auth); 9976f384573SBrian Somers dl->chap.auth.cfg.fsmretry = retry; 9986f384573SBrian Somers 99996c9bb21SBrian Somers dl->physical = iov2modem(dl, iov, niov, maxiov, fd); 100096c9bb21SBrian Somers 100196c9bb21SBrian Somers if (!dl->physical) { 10026f384573SBrian Somers free(dl->name); 10036f384573SBrian Somers free(dl); 10046f384573SBrian Somers dl = NULL; 10059ae58882SBrian Somers } else { 10066f384573SBrian Somers chat_Init(&dl->chat, dl->physical, NULL, 1, NULL); 10076f384573SBrian Somers 10089ae58882SBrian Somers log_Printf(LogPHASE, "%s: Transferred in %s state\n", 10099ae58882SBrian Somers dl->name, datalink_State(dl)); 10109ae58882SBrian Somers } 10119ae58882SBrian Somers 10126f384573SBrian Somers return dl; 10136f384573SBrian Somers } 10146f384573SBrian Somers 10156f384573SBrian Somers int 101696c9bb21SBrian Somers datalink2iov(struct datalink *dl, struct iovec *iov, int *niov, int maxiov) 10176f384573SBrian Somers { 101896c9bb21SBrian Somers /* If `dl' is NULL, we're allocating before a Fromiov() */ 101996c9bb21SBrian Somers int link_fd; 10206f384573SBrian Somers 102196c9bb21SBrian Somers if (dl) { 1022dd7e2610SBrian Somers timer_Stop(&dl->dial_timer); 1023dd7e2610SBrian Somers timer_Stop(&dl->pap.authtimer); 1024dd7e2610SBrian Somers timer_Stop(&dl->chap.auth.authtimer); 10256f384573SBrian Somers } 10266f384573SBrian Somers 102796c9bb21SBrian Somers if (*niov >= maxiov - 1) { 102896c9bb21SBrian Somers log_Printf(LogERROR, "Toiov: No room for datalink !\n"); 102996c9bb21SBrian Somers if (dl) { 10306f384573SBrian Somers free(dl->name); 10316f384573SBrian Somers free(dl); 103296c9bb21SBrian Somers } 103396c9bb21SBrian Somers return -1; 103496c9bb21SBrian Somers } 103596c9bb21SBrian Somers 103696c9bb21SBrian Somers iov[*niov].iov_base = dl ? dl : malloc(sizeof *dl); 103796c9bb21SBrian Somers iov[(*niov)++].iov_len = sizeof *dl; 103896c9bb21SBrian Somers iov[*niov].iov_base = 103996c9bb21SBrian Somers dl ? realloc(dl->name, DATALINK_MAXNAME) : malloc(DATALINK_MAXNAME); 104096c9bb21SBrian Somers iov[(*niov)++].iov_len = DATALINK_MAXNAME; 104196c9bb21SBrian Somers 104296c9bb21SBrian Somers link_fd = modem2iov(dl ? dl->physical : NULL, iov, niov, maxiov); 104396c9bb21SBrian Somers 104496c9bb21SBrian Somers if (link_fd == -1 && dl) { 104596c9bb21SBrian Somers free(dl->name); 104696c9bb21SBrian Somers free(dl); 104796c9bb21SBrian Somers } 10486f384573SBrian Somers 10496f384573SBrian Somers return link_fd; 10506f384573SBrian Somers } 10516f384573SBrian Somers 105284917b87SBrian Somers char * 105384917b87SBrian Somers datalink_NextName(struct datalink *dl) 10546f384573SBrian Somers { 10556f384573SBrian Somers int f, n; 105684917b87SBrian Somers char *name, *oname; 10576f384573SBrian Somers 10586f384573SBrian Somers n = strlen(dl->name); 10596f384573SBrian Somers name = (char *)malloc(n+3); 10606f384573SBrian Somers for (f = n - 1; f >= 0; f--) 10616f384573SBrian Somers if (!isdigit(dl->name[f])) 10626f384573SBrian Somers break; 10636f384573SBrian Somers n = sprintf(name, "%.*s-", dl->name[f] == '-' ? f : f + 1, dl->name); 10646f384573SBrian Somers sprintf(name + n, "%d", atoi(dl->name + f + 1) + 1); 106584917b87SBrian Somers oname = dl->name; 10666f384573SBrian Somers dl->physical->link.name = dl->name = name; 106784917b87SBrian Somers return oname; 10686f384573SBrian Somers } 1069