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 * 26ff0f9439SBrian Somers * $Id: datalink.c,v 1.7 1998/05/29 18:32:10 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)) && 12281358fa3SBrian Somers !(dl->physical->type & (PHYS_DDIAL|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: 20981358fa3SBrian Somers if ((dl->physical->type & 21081358fa3SBrian Somers (PHYS_DIRECT|PHYS_DEDICATED|PHYS_BACKGROUND|PHYS_DDIAL)) && 211565e35e5SBrian Somers !bundle_IsDead(dl->bundle)) 212565e35e5SBrian Somers /* 21381358fa3SBrian Somers * Our first time in - DEDICATED & DDIAL never come down, and 21481358fa3SBrian Somers * DIRECT & BACKGROUND get deleted when they enter DATALINK_CLOSED. 21581358fa3SBrian Somers * Go to DATALINK_OPENING via datalink_Up() and fall through. 216565e35e5SBrian Somers */ 217565e35e5SBrian Somers datalink_Up(dl, 1, 1); 218565e35e5SBrian Somers else 219310c3babSBrian Somers break; 220565e35e5SBrian Somers /* fall through */ 2213006ec67SBrian Somers 2223006ec67SBrian Somers case DATALINK_OPENING: 2233006ec67SBrian Somers if (dl->dial_timer.state != TIMER_RUNNING) { 2243006ec67SBrian Somers if (--dl->dial_tries < 0) 2253006ec67SBrian Somers dl->dial_tries = 0; 2263006ec67SBrian Somers if (modem_Open(dl->physical, dl->bundle) >= 0) { 227c5a5a6caSBrian Somers if (dl->script.run) { 2289ae58882SBrian Somers datalink_NewState(dl, DATALINK_DIAL); 229f9545805SBrian Somers chat_Init(&dl->chat, dl->physical, dl->cfg.script.dial, 1, 230f9545805SBrian Somers datalink_ChoosePhoneNumber(dl)); 23181358fa3SBrian Somers if (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) && 232565e35e5SBrian Somers dl->cfg.dial.max) 233dd7e2610SBrian Somers log_Printf(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 { 24081358fa3SBrian Somers if (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) && 241565e35e5SBrian Somers dl->cfg.dial.max) 242dd7e2610SBrian Somers log_Printf(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 245dd7e2610SBrian Somers log_Printf(LogCHAT, "Failed to open modem\n"); 2463006ec67SBrian Somers 2473b0f8d2eSBrian Somers if (dl->bundle->CleaningUp || 24881358fa3SBrian Somers (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) && 249565e35e5SBrian Somers dl->cfg.dial.max && dl->dial_tries == 0)) { 2509ae58882SBrian Somers datalink_NewState(dl, DATALINK_CLOSED); 2513006ec67SBrian Somers dl->reconnect_tries = 0; 2523006ec67SBrian Somers dl->dial_tries = -1; 2535b8b8060SBrian Somers bundle_LinkClosed(dl->bundle, dl); 254c5a5a6caSBrian Somers } 2553b0f8d2eSBrian Somers if (!dl->bundle->CleaningUp) 256565e35e5SBrian Somers datalink_StartDialTimer(dl, dl->cfg.dial.timeout); 2573006ec67SBrian Somers } 2583006ec67SBrian Somers } 259310c3babSBrian Somers break; 2603006ec67SBrian Somers 2613006ec67SBrian Somers case DATALINK_HANGUP: 2623006ec67SBrian Somers case DATALINK_DIAL: 2633006ec67SBrian Somers case DATALINK_LOGIN: 2643006ec67SBrian Somers result = descriptor_UpdateSet(&dl->chat.desc, r, w, e, n); 2653006ec67SBrian Somers switch (dl->chat.state) { 2663006ec67SBrian Somers case CHAT_DONE: 2673006ec67SBrian Somers /* script succeeded */ 26839d94652SBrian Somers chat_Destroy(&dl->chat); 2693006ec67SBrian Somers switch(dl->state) { 2703006ec67SBrian Somers case DATALINK_HANGUP: 2713006ec67SBrian Somers datalink_HangupDone(dl); 2723006ec67SBrian Somers break; 2733006ec67SBrian Somers case DATALINK_DIAL: 2749ae58882SBrian Somers datalink_NewState(dl, DATALINK_LOGIN); 275f9545805SBrian Somers chat_Init(&dl->chat, dl->physical, dl->cfg.script.login, 0, NULL); 2761342caedSBrian Somers return datalink_UpdateSet(d, r, w, e, n); 2773006ec67SBrian Somers case DATALINK_LOGIN: 278c5a5a6caSBrian Somers datalink_LoginDone(dl); 2793006ec67SBrian Somers break; 2803006ec67SBrian Somers } 2813006ec67SBrian Somers break; 2823006ec67SBrian Somers case CHAT_FAILED: 2833006ec67SBrian Somers /* Going down - script failed */ 284dd7e2610SBrian Somers log_Printf(LogWARN, "Chat script failed\n"); 28539d94652SBrian Somers chat_Destroy(&dl->chat); 2863006ec67SBrian Somers switch(dl->state) { 2873006ec67SBrian Somers case DATALINK_HANGUP: 2883006ec67SBrian Somers datalink_HangupDone(dl); 2893006ec67SBrian Somers break; 2903006ec67SBrian Somers case DATALINK_DIAL: 2913006ec67SBrian Somers case DATALINK_LOGIN: 2929ae58882SBrian Somers datalink_NewState(dl, DATALINK_HANGUP); 2933006ec67SBrian Somers modem_Offline(dl->physical); 294f9545805SBrian Somers chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL); 2951342caedSBrian Somers return datalink_UpdateSet(d, r, w, e, n); 2963006ec67SBrian Somers } 2973006ec67SBrian Somers break; 2983006ec67SBrian Somers } 2993006ec67SBrian Somers break; 300c7cc5030SBrian Somers 301c7cc5030SBrian Somers case DATALINK_READY: 302e2ebb036SBrian Somers case DATALINK_LCP: 303e2ebb036SBrian Somers case DATALINK_AUTH: 3043006ec67SBrian Somers case DATALINK_OPEN: 3053006ec67SBrian Somers result = descriptor_UpdateSet(&dl->physical->desc, r, w, e, n); 3063006ec67SBrian Somers break; 3073006ec67SBrian Somers } 3083006ec67SBrian Somers return result; 3093006ec67SBrian Somers } 3103006ec67SBrian Somers 311ea722969SBrian Somers int 312ea722969SBrian Somers datalink_RemoveFromSet(struct datalink *dl, fd_set *r, fd_set *w, fd_set *e) 313ea722969SBrian Somers { 314ea722969SBrian Somers return physical_RemoveFromSet(dl->physical, r, w, e); 315ea722969SBrian Somers } 316ea722969SBrian Somers 3173006ec67SBrian Somers static int 3182f786681SBrian Somers datalink_IsSet(struct descriptor *d, const fd_set *fdset) 3193006ec67SBrian Somers { 3203006ec67SBrian Somers struct datalink *dl = descriptor2datalink(d); 3213006ec67SBrian Somers 3223006ec67SBrian Somers switch (dl->state) { 3233006ec67SBrian Somers case DATALINK_CLOSED: 324c7cc5030SBrian Somers case DATALINK_OPENING: 3253006ec67SBrian Somers break; 326c7cc5030SBrian Somers 3273006ec67SBrian Somers case DATALINK_HANGUP: 3283006ec67SBrian Somers case DATALINK_DIAL: 3293006ec67SBrian Somers case DATALINK_LOGIN: 3303006ec67SBrian Somers return descriptor_IsSet(&dl->chat.desc, fdset); 331c7cc5030SBrian Somers 332c7cc5030SBrian Somers case DATALINK_READY: 333e2ebb036SBrian Somers case DATALINK_LCP: 334e2ebb036SBrian Somers case DATALINK_AUTH: 3353006ec67SBrian Somers case DATALINK_OPEN: 3363006ec67SBrian Somers return descriptor_IsSet(&dl->physical->desc, fdset); 3373006ec67SBrian Somers } 3383006ec67SBrian Somers return 0; 3393006ec67SBrian Somers } 3403006ec67SBrian Somers 3413006ec67SBrian Somers static void 3423006ec67SBrian Somers datalink_Read(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) 3433006ec67SBrian Somers { 3443006ec67SBrian Somers struct datalink *dl = descriptor2datalink(d); 3453006ec67SBrian Somers 3463006ec67SBrian Somers switch (dl->state) { 3473006ec67SBrian Somers case DATALINK_CLOSED: 348c7cc5030SBrian Somers case DATALINK_OPENING: 3493006ec67SBrian Somers break; 350c7cc5030SBrian Somers 3513006ec67SBrian Somers case DATALINK_HANGUP: 3523006ec67SBrian Somers case DATALINK_DIAL: 3533006ec67SBrian Somers case DATALINK_LOGIN: 3543006ec67SBrian Somers descriptor_Read(&dl->chat.desc, bundle, fdset); 3553006ec67SBrian Somers break; 356c7cc5030SBrian Somers 357c7cc5030SBrian Somers case DATALINK_READY: 358e2ebb036SBrian Somers case DATALINK_LCP: 359e2ebb036SBrian Somers case DATALINK_AUTH: 3603006ec67SBrian Somers case DATALINK_OPEN: 3613006ec67SBrian Somers descriptor_Read(&dl->physical->desc, bundle, fdset); 3623006ec67SBrian Somers break; 3633006ec67SBrian Somers } 3643006ec67SBrian Somers } 3653006ec67SBrian Somers 3663006ec67SBrian Somers static void 367f4768038SBrian Somers datalink_Write(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) 3683006ec67SBrian Somers { 3693006ec67SBrian Somers struct datalink *dl = descriptor2datalink(d); 3703006ec67SBrian Somers 3713006ec67SBrian Somers switch (dl->state) { 3723006ec67SBrian Somers case DATALINK_CLOSED: 373c7cc5030SBrian Somers case DATALINK_OPENING: 3743006ec67SBrian Somers break; 375c7cc5030SBrian Somers 3763006ec67SBrian Somers case DATALINK_HANGUP: 3773006ec67SBrian Somers case DATALINK_DIAL: 3783006ec67SBrian Somers case DATALINK_LOGIN: 379f4768038SBrian Somers descriptor_Write(&dl->chat.desc, bundle, fdset); 3803006ec67SBrian Somers break; 381c7cc5030SBrian Somers 382c7cc5030SBrian Somers case DATALINK_READY: 383e2ebb036SBrian Somers case DATALINK_LCP: 384e2ebb036SBrian Somers case DATALINK_AUTH: 3853006ec67SBrian Somers case DATALINK_OPEN: 386f4768038SBrian Somers descriptor_Write(&dl->physical->desc, bundle, fdset); 3873006ec67SBrian Somers break; 3883006ec67SBrian Somers } 3893006ec67SBrian Somers } 3903006ec67SBrian Somers 3916d666775SBrian Somers static void 392e2ebb036SBrian Somers datalink_ComeDown(struct datalink *dl, int stay) 393e2ebb036SBrian Somers { 394e2ebb036SBrian Somers if (stay) { 395e2ebb036SBrian Somers dl->dial_tries = -1; 396e2ebb036SBrian Somers dl->reconnect_tries = 0; 397e2ebb036SBrian Somers } 398e2ebb036SBrian Somers 399e2ebb036SBrian Somers if (dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP) { 400e2ebb036SBrian Somers modem_Offline(dl->physical); 401e2ebb036SBrian Somers if (dl->script.run && dl->state != DATALINK_OPENING) { 4029ae58882SBrian Somers datalink_NewState(dl, DATALINK_HANGUP); 403f9545805SBrian Somers chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL); 404e2ebb036SBrian Somers } else 405e2ebb036SBrian Somers datalink_HangupDone(dl); 406e2ebb036SBrian Somers } 407e2ebb036SBrian Somers } 408e2ebb036SBrian Somers 409e2ebb036SBrian Somers static void 4106d666775SBrian Somers datalink_LayerStart(void *v, struct fsm *fp) 4116d666775SBrian Somers { 4126d666775SBrian Somers /* The given FSM is about to start up ! */ 4136d666775SBrian Somers struct datalink *dl = (struct datalink *)v; 414a611cad6SBrian Somers 41592e872e7SBrian Somers if (fp->proto == PROTO_LCP) 416e2ebb036SBrian Somers (*dl->parent->LayerStart)(dl->parent->object, fp); 417e2ebb036SBrian Somers } 4186d666775SBrian Somers 4196d666775SBrian Somers static void 4206d666775SBrian Somers datalink_LayerUp(void *v, struct fsm *fp) 4216d666775SBrian Somers { 4226d666775SBrian Somers /* The given fsm is now up */ 4236d666775SBrian Somers struct datalink *dl = (struct datalink *)v; 4246d666775SBrian Somers 42592e872e7SBrian Somers if (fp->proto == PROTO_LCP) { 426643f4904SBrian Somers datalink_GotAuthname(dl, "", 0); 4273b0f8d2eSBrian Somers dl->physical->link.lcp.auth_ineed = dl->physical->link.lcp.want_auth; 4283b0f8d2eSBrian Somers dl->physical->link.lcp.auth_iwait = dl->physical->link.lcp.his_auth; 4293b0f8d2eSBrian Somers if (dl->physical->link.lcp.his_auth || dl->physical->link.lcp.want_auth) { 4303b0f8d2eSBrian Somers if (bundle_Phase(dl->bundle) == PHASE_ESTABLISH) 4315563ebdeSBrian Somers bundle_NewPhase(dl->bundle, PHASE_AUTHENTICATE); 432dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: his = %s, mine = %s\n", dl->name, 4333b0f8d2eSBrian Somers Auth2Nam(dl->physical->link.lcp.his_auth), 4343b0f8d2eSBrian Somers Auth2Nam(dl->physical->link.lcp.want_auth)); 4353b0f8d2eSBrian Somers if (dl->physical->link.lcp.his_auth == PROTO_PAP) 436dd7e2610SBrian Somers auth_StartChallenge(&dl->pap, dl->physical, pap_SendChallenge); 4373b0f8d2eSBrian Somers if (dl->physical->link.lcp.want_auth == PROTO_CHAP) 438dd7e2610SBrian Somers auth_StartChallenge(&dl->chap.auth, dl->physical, chap_SendChallenge); 439e2ebb036SBrian Somers } else 440e2ebb036SBrian Somers datalink_AuthOk(dl); 441e2ebb036SBrian Somers } 442e2ebb036SBrian Somers } 443e2ebb036SBrian Somers 444e2ebb036SBrian Somers void 445643f4904SBrian Somers datalink_GotAuthname(struct datalink *dl, const char *name, int len) 446643f4904SBrian Somers { 447643f4904SBrian Somers if (len >= sizeof dl->peer.authname) 448643f4904SBrian Somers len = sizeof dl->peer.authname - 1; 449643f4904SBrian Somers strncpy(dl->peer.authname, name, len); 450643f4904SBrian Somers dl->peer.authname[len] = '\0'; 451643f4904SBrian Somers } 452643f4904SBrian Somers 453643f4904SBrian Somers void 454e2ebb036SBrian Somers datalink_AuthOk(struct datalink *dl) 455e2ebb036SBrian Somers { 4561df0a3b9SBrian Somers ccp_SetOpenMode(&dl->physical->link.ccp); 4571df0a3b9SBrian Somers 458dbf60d74SBrian Somers if (dl->physical->link.lcp.want_mrru && dl->physical->link.lcp.his_mrru) { 4591fa665f5SBrian Somers /* we've authenticated in multilink mode ! */ 4601fa665f5SBrian Somers switch (mp_Up(&dl->bundle->ncp.mp, dl)) { 4611fa665f5SBrian Somers case MP_LINKSENT: 462ea722969SBrian Somers /* We've handed the link off to another ppp (well, we will soon) ! */ 4631fa665f5SBrian Somers return; 4641fa665f5SBrian Somers case MP_UP: 4650a1b5c9dSBrian Somers /* First link in the bundle */ 466dd7e2610SBrian Somers auth_Select(dl->bundle, dl->peer.authname, dl->physical); 4670a1b5c9dSBrian Somers /* fall through */ 4681fa665f5SBrian Somers case MP_ADDED: 4690a1b5c9dSBrian Somers /* We're in multilink mode ! */ 4701df0a3b9SBrian Somers dl->physical->link.ccp.fsm.open_mode = OPEN_PASSIVE; /* override */ 4711fa665f5SBrian Somers break; 4721fa665f5SBrian Somers case MP_FAILED: 47349052c95SBrian Somers datalink_AuthNotOk(dl); 47449052c95SBrian Somers return; 47549052c95SBrian Somers } 47649052c95SBrian Somers } else if (bundle_Phase(dl->bundle) == PHASE_NETWORK) { 477dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: Already in NETWORK phase\n", dl->name); 47849052c95SBrian Somers datalink_AuthNotOk(dl); 47949052c95SBrian Somers return; 48050abd4c8SBrian Somers } else { 48150abd4c8SBrian Somers dl->bundle->ncp.mp.peer = dl->peer; 482ce828a6eSBrian Somers ipcp_SetLink(&dl->bundle->ncp.ipcp, &dl->physical->link); 483dd7e2610SBrian Somers auth_Select(dl->bundle, dl->peer.authname, dl->physical); 48450abd4c8SBrian Somers } 48549052c95SBrian Somers 486dd7e2610SBrian Somers fsm_Up(&dl->physical->link.ccp.fsm); 487dd7e2610SBrian Somers fsm_Open(&dl->physical->link.ccp.fsm); 4889ae58882SBrian Somers datalink_NewState(dl, DATALINK_OPEN); 4893b0f8d2eSBrian Somers bundle_NewPhase(dl->bundle, PHASE_NETWORK); 4903b0f8d2eSBrian Somers (*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.lcp.fsm); 4916d666775SBrian Somers } 492e2ebb036SBrian Somers 493e2ebb036SBrian Somers void 494e2ebb036SBrian Somers datalink_AuthNotOk(struct datalink *dl) 495e2ebb036SBrian Somers { 4969ae58882SBrian Somers datalink_NewState(dl, DATALINK_LCP); 497dd7e2610SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 4986d666775SBrian Somers } 4996d666775SBrian Somers 5006d666775SBrian Somers static void 5016d666775SBrian Somers datalink_LayerDown(void *v, struct fsm *fp) 5026d666775SBrian Somers { 5036d666775SBrian Somers /* The given FSM has been told to come down */ 5046d666775SBrian Somers struct datalink *dl = (struct datalink *)v; 505a611cad6SBrian Somers 50692e872e7SBrian Somers if (fp->proto == PROTO_LCP) { 507e2ebb036SBrian Somers switch (dl->state) { 508e2ebb036SBrian Somers case DATALINK_OPEN: 509643f4904SBrian Somers peerid_Init(&dl->peer); 510dd7e2610SBrian Somers fsm_Down(&dl->physical->link.ccp.fsm); 511dd7e2610SBrian Somers fsm_Close(&dl->physical->link.ccp.fsm); 512ff0f9439SBrian Somers datalink_NewState(dl, DATALINK_LCP); /* before parent TLD */ 513e2ebb036SBrian Somers (*dl->parent->LayerDown)(dl->parent->object, fp); 514e2ebb036SBrian Somers /* fall through */ 515e2ebb036SBrian Somers 516e2ebb036SBrian Somers case DATALINK_AUTH: 517dd7e2610SBrian Somers timer_Stop(&dl->pap.authtimer); 518dd7e2610SBrian Somers timer_Stop(&dl->chap.auth.authtimer); 5196d666775SBrian Somers } 5209ae58882SBrian Somers datalink_NewState(dl, DATALINK_LCP); 521e2ebb036SBrian Somers } 5226d666775SBrian Somers } 5236d666775SBrian Somers 5246d666775SBrian Somers static void 5256d666775SBrian Somers datalink_LayerFinish(void *v, struct fsm *fp) 5266d666775SBrian Somers { 5276d666775SBrian Somers /* The given fsm is now down */ 5286d666775SBrian Somers struct datalink *dl = (struct datalink *)v; 5296d666775SBrian Somers 53092e872e7SBrian Somers if (fp->proto == PROTO_LCP) { 53154cd8e13SBrian Somers if (fp->state == ST_STOPPED) 53254cd8e13SBrian Somers fsm_Close(fp); /* back to CLOSED */ 533dd7e2610SBrian Somers fsm_Down(fp); /* Bring us to INITIAL or STARTING */ 5346d666775SBrian Somers (*dl->parent->LayerFinish)(dl->parent->object, fp); 535e2ebb036SBrian Somers datalink_ComeDown(dl, 0); 5360a1b5c9dSBrian Somers } else if (fp->state == ST_CLOSED && fp->open_mode == OPEN_PASSIVE) 5370a1b5c9dSBrian Somers fsm_Open(fp); /* CCP goes to ST_STOPPED */ 5386d666775SBrian Somers } 5396d666775SBrian Somers 5403006ec67SBrian Somers struct datalink * 5416f384573SBrian Somers datalink_Create(const char *name, struct bundle *bundle, int type) 5423006ec67SBrian Somers { 5433006ec67SBrian Somers struct datalink *dl; 5443006ec67SBrian Somers 5453006ec67SBrian Somers dl = (struct datalink *)malloc(sizeof(struct datalink)); 5463006ec67SBrian Somers if (dl == NULL) 5473006ec67SBrian Somers return dl; 5483006ec67SBrian Somers 5493006ec67SBrian Somers dl->desc.type = DATALINK_DESCRIPTOR; 5503006ec67SBrian Somers dl->desc.UpdateSet = datalink_UpdateSet; 5513006ec67SBrian Somers dl->desc.IsSet = datalink_IsSet; 5523006ec67SBrian Somers dl->desc.Read = datalink_Read; 5533006ec67SBrian Somers dl->desc.Write = datalink_Write; 5545b8b8060SBrian Somers 555e718d1d7SBrian Somers dl->state = DATALINK_CLOSED; 556e718d1d7SBrian Somers 55773a13b5cSBrian Somers *dl->cfg.script.dial = '\0'; 55873a13b5cSBrian Somers *dl->cfg.script.login = '\0'; 55973a13b5cSBrian Somers *dl->cfg.script.hangup = '\0'; 560f9545805SBrian Somers *dl->cfg.phone.list = '\0'; 561f9545805SBrian Somers *dl->phone.list = '\0'; 562f9545805SBrian Somers dl->phone.next = NULL; 563f9545805SBrian Somers dl->phone.alt = NULL; 564f9545805SBrian Somers dl->phone.chosen = "N/A"; 565c7cc5030SBrian Somers dl->script.run = 1; 566c7cc5030SBrian Somers dl->script.packetmode = 1; 5673b0f8d2eSBrian Somers mp_linkInit(&dl->mp); 5685b8b8060SBrian Somers 5693006ec67SBrian Somers dl->bundle = bundle; 5703006ec67SBrian Somers dl->next = NULL; 571e718d1d7SBrian Somers 5723006ec67SBrian Somers memset(&dl->dial_timer, '\0', sizeof dl->dial_timer); 573e718d1d7SBrian Somers 5743006ec67SBrian Somers dl->dial_tries = 0; 575565e35e5SBrian Somers dl->cfg.dial.max = 1; 576565e35e5SBrian Somers dl->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT; 577565e35e5SBrian Somers dl->cfg.dial.timeout = DIAL_TIMEOUT; 578e718d1d7SBrian Somers 579abff9baeSBrian Somers dl->reconnect_tries = 0; 580565e35e5SBrian Somers dl->cfg.reconnect.max = 0; 581565e35e5SBrian Somers dl->cfg.reconnect.timeout = RECONNECT_TIMEOUT; 582abff9baeSBrian Somers 5833006ec67SBrian Somers dl->name = strdup(name); 584643f4904SBrian Somers peerid_Init(&dl->peer); 5856f384573SBrian Somers dl->parent = &bundle->fsm; 5863b0f8d2eSBrian Somers dl->fsmp.LayerStart = datalink_LayerStart; 5873b0f8d2eSBrian Somers dl->fsmp.LayerUp = datalink_LayerUp; 5883b0f8d2eSBrian Somers dl->fsmp.LayerDown = datalink_LayerDown; 5893b0f8d2eSBrian Somers dl->fsmp.LayerFinish = datalink_LayerFinish; 5903b0f8d2eSBrian Somers dl->fsmp.object = dl; 5913b0f8d2eSBrian Somers 592dd7e2610SBrian Somers auth_Init(&dl->pap); 593dd7e2610SBrian Somers auth_Init(&dl->chap.auth); 5943b0f8d2eSBrian Somers 595565e35e5SBrian Somers if ((dl->physical = modem_Create(dl, type)) == NULL) { 5963006ec67SBrian Somers free(dl->name); 5973006ec67SBrian Somers free(dl); 5983006ec67SBrian Somers return NULL; 5993006ec67SBrian Somers } 600f9545805SBrian Somers chat_Init(&dl->chat, dl->physical, NULL, 1, NULL); 6013006ec67SBrian Somers 6029ae58882SBrian Somers log_Printf(LogPHASE, "%s: Created in %s state\n", 6039ae58882SBrian Somers dl->name, datalink_State(dl)); 6043006ec67SBrian Somers 6053006ec67SBrian Somers return dl; 6063006ec67SBrian Somers } 6073006ec67SBrian Somers 6083006ec67SBrian Somers struct datalink * 609cd7bd93aSBrian Somers datalink_Clone(struct datalink *odl, const char *name) 610cd7bd93aSBrian Somers { 611cd7bd93aSBrian Somers struct datalink *dl; 612cd7bd93aSBrian Somers 613cd7bd93aSBrian Somers dl = (struct datalink *)malloc(sizeof(struct datalink)); 614cd7bd93aSBrian Somers if (dl == NULL) 615cd7bd93aSBrian Somers return dl; 616cd7bd93aSBrian Somers 617cd7bd93aSBrian Somers dl->desc.type = DATALINK_DESCRIPTOR; 618cd7bd93aSBrian Somers dl->desc.UpdateSet = datalink_UpdateSet; 619cd7bd93aSBrian Somers dl->desc.IsSet = datalink_IsSet; 620cd7bd93aSBrian Somers dl->desc.Read = datalink_Read; 621cd7bd93aSBrian Somers dl->desc.Write = datalink_Write; 622cd7bd93aSBrian Somers 623cd7bd93aSBrian Somers dl->state = DATALINK_CLOSED; 624cd7bd93aSBrian Somers 625cd7bd93aSBrian Somers memcpy(&dl->cfg, &odl->cfg, sizeof dl->cfg); 626cd7bd93aSBrian Somers mp_linkInit(&dl->mp); 627cd7bd93aSBrian Somers *dl->phone.list = '\0'; 628643f4904SBrian Somers dl->phone.next = NULL; 629643f4904SBrian Somers dl->phone.alt = NULL; 630643f4904SBrian Somers dl->phone.chosen = "N/A"; 631cd7bd93aSBrian Somers dl->bundle = odl->bundle; 632cd7bd93aSBrian Somers dl->next = NULL; 633cd7bd93aSBrian Somers memset(&dl->dial_timer, '\0', sizeof dl->dial_timer); 634cd7bd93aSBrian Somers dl->dial_tries = 0; 635cd7bd93aSBrian Somers dl->reconnect_tries = 0; 636cd7bd93aSBrian Somers dl->name = strdup(name); 637643f4904SBrian Somers peerid_Init(&dl->peer); 638cd7bd93aSBrian Somers dl->parent = odl->parent; 639cd7bd93aSBrian Somers memcpy(&dl->fsmp, &odl->fsmp, sizeof dl->fsmp); 640643f4904SBrian Somers dl->fsmp.object = dl; 641dd7e2610SBrian Somers auth_Init(&dl->pap); 642cd7bd93aSBrian Somers dl->pap.cfg.fsmretry = odl->pap.cfg.fsmretry; 643cd7bd93aSBrian Somers 644dd7e2610SBrian Somers auth_Init(&dl->chap.auth); 645cd7bd93aSBrian Somers dl->chap.auth.cfg.fsmretry = odl->chap.auth.cfg.fsmretry; 646cd7bd93aSBrian Somers 64781358fa3SBrian Somers if ((dl->physical = modem_Create(dl, PHYS_INTERACTIVE)) == NULL) { 648cd7bd93aSBrian Somers free(dl->name); 649cd7bd93aSBrian Somers free(dl); 650cd7bd93aSBrian Somers return NULL; 651cd7bd93aSBrian Somers } 652cd7bd93aSBrian Somers memcpy(&dl->physical->cfg, &odl->physical->cfg, sizeof dl->physical->cfg); 653cd7bd93aSBrian Somers memcpy(&dl->physical->link.lcp.cfg, &odl->physical->link.lcp.cfg, 654cd7bd93aSBrian Somers sizeof dl->physical->link.lcp.cfg); 655cd7bd93aSBrian Somers memcpy(&dl->physical->link.ccp.cfg, &odl->physical->link.ccp.cfg, 656cd7bd93aSBrian Somers sizeof dl->physical->link.ccp.cfg); 657cd7bd93aSBrian Somers memcpy(&dl->physical->async.cfg, &odl->physical->async.cfg, 658cd7bd93aSBrian Somers sizeof dl->physical->async.cfg); 659cd7bd93aSBrian Somers 660cd7bd93aSBrian Somers chat_Init(&dl->chat, dl->physical, NULL, 1, NULL); 661cd7bd93aSBrian Somers 6629ae58882SBrian Somers log_Printf(LogPHASE, "%s: Cloned in %s state\n", 6639ae58882SBrian Somers dl->name, datalink_State(dl)); 664cd7bd93aSBrian Somers 665cd7bd93aSBrian Somers return dl; 666cd7bd93aSBrian Somers } 667cd7bd93aSBrian Somers 668cd7bd93aSBrian Somers struct datalink * 6693006ec67SBrian Somers datalink_Destroy(struct datalink *dl) 6703006ec67SBrian Somers { 6713006ec67SBrian Somers struct datalink *result; 6723006ec67SBrian Somers 67339d94652SBrian Somers if (dl->state != DATALINK_CLOSED) { 674dd7e2610SBrian Somers log_Printf(LogERROR, "Oops, destroying a datalink in state %s\n", 675c7cc5030SBrian Somers datalink_State(dl)); 67639d94652SBrian Somers switch (dl->state) { 67739d94652SBrian Somers case DATALINK_HANGUP: 67839d94652SBrian Somers case DATALINK_DIAL: 67939d94652SBrian Somers case DATALINK_LOGIN: 68039d94652SBrian Somers chat_Destroy(&dl->chat); /* Gotta blat the timers ! */ 68139d94652SBrian Somers break; 68239d94652SBrian Somers } 68339d94652SBrian Somers } 6843006ec67SBrian Somers 6853006ec67SBrian Somers result = dl->next; 6863b0f8d2eSBrian Somers modem_Destroy(dl->physical); 6873006ec67SBrian Somers free(dl->name); 6883006ec67SBrian Somers free(dl); 6893006ec67SBrian Somers 6903006ec67SBrian Somers return result; 6913006ec67SBrian Somers } 6923006ec67SBrian Somers 6933006ec67SBrian Somers void 694c5a5a6caSBrian Somers datalink_Up(struct datalink *dl, int runscripts, int packetmode) 6953006ec67SBrian Somers { 6966f384573SBrian Somers if (dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED)) 697565e35e5SBrian Somers /* Ignore scripts */ 698565e35e5SBrian Somers runscripts = 0; 699565e35e5SBrian Somers 700c7cc5030SBrian Somers switch (dl->state) { 701c7cc5030SBrian Somers case DATALINK_CLOSED: 7023b0f8d2eSBrian Somers if (bundle_Phase(dl->bundle) == PHASE_DEAD || 7033b0f8d2eSBrian Somers bundle_Phase(dl->bundle) == PHASE_TERMINATE) 7043b0f8d2eSBrian Somers bundle_NewPhase(dl->bundle, PHASE_ESTABLISH); 7059ae58882SBrian Somers datalink_NewState(dl, DATALINK_OPENING); 706565e35e5SBrian Somers dl->reconnect_tries = 7076f384573SBrian Somers dl->physical->type == PHYS_DIRECT ? 0 : dl->cfg.reconnect.max; 708565e35e5SBrian Somers dl->dial_tries = dl->cfg.dial.max; 709c5a5a6caSBrian Somers dl->script.run = runscripts; 710c5a5a6caSBrian Somers dl->script.packetmode = packetmode; 711c7cc5030SBrian Somers break; 712c7cc5030SBrian Somers 713c7cc5030SBrian Somers case DATALINK_OPENING: 714c7cc5030SBrian Somers if (!dl->script.run && runscripts) 715c7cc5030SBrian Somers dl->script.run = 1; 716c7cc5030SBrian Somers /* fall through */ 717c7cc5030SBrian Somers 718c7cc5030SBrian Somers case DATALINK_DIAL: 719c7cc5030SBrian Somers case DATALINK_LOGIN: 720c7cc5030SBrian Somers case DATALINK_READY: 721c7cc5030SBrian Somers if (!dl->script.packetmode && packetmode) { 722c7cc5030SBrian Somers dl->script.packetmode = 1; 723c7cc5030SBrian Somers if (dl->state == DATALINK_READY) 724c7cc5030SBrian Somers datalink_LoginDone(dl); 725c7cc5030SBrian Somers } 726c7cc5030SBrian Somers break; 7273006ec67SBrian Somers } 7283006ec67SBrian Somers } 7293006ec67SBrian Somers 7303006ec67SBrian Somers void 731c7cc5030SBrian Somers datalink_Close(struct datalink *dl, int stay) 732c7cc5030SBrian Somers { 733c7cc5030SBrian Somers /* Please close */ 734e2ebb036SBrian Somers switch (dl->state) { 735e2ebb036SBrian Somers case DATALINK_OPEN: 736643f4904SBrian Somers peerid_Init(&dl->peer); 737dd7e2610SBrian Somers fsm_Down(&dl->physical->link.ccp.fsm); 738dd7e2610SBrian Somers fsm_Close(&dl->physical->link.ccp.fsm); 739e2ebb036SBrian Somers /* fall through */ 740e2ebb036SBrian Somers 741e2ebb036SBrian Somers case DATALINK_AUTH: 742e2ebb036SBrian Somers case DATALINK_LCP: 743dd7e2610SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 744c7cc5030SBrian Somers if (stay) { 745c7cc5030SBrian Somers dl->dial_tries = -1; 746c7cc5030SBrian Somers dl->reconnect_tries = 0; 747c7cc5030SBrian Somers } 748e2ebb036SBrian Somers break; 749e2ebb036SBrian Somers 750e2ebb036SBrian Somers default: 751c7cc5030SBrian Somers datalink_ComeDown(dl, stay); 752c7cc5030SBrian Somers } 753e2ebb036SBrian Somers } 754c7cc5030SBrian Somers 755c7cc5030SBrian Somers void 756c7cc5030SBrian Somers datalink_Down(struct datalink *dl, int stay) 757c7cc5030SBrian Somers { 758c7cc5030SBrian Somers /* Carrier is lost */ 759e2ebb036SBrian Somers switch (dl->state) { 760e2ebb036SBrian Somers case DATALINK_OPEN: 761643f4904SBrian Somers peerid_Init(&dl->peer); 762dd7e2610SBrian Somers fsm_Down(&dl->physical->link.ccp.fsm); 763dd7e2610SBrian Somers fsm_Close(&dl->physical->link.ccp.fsm); 764e2ebb036SBrian Somers /* fall through */ 765e2ebb036SBrian Somers 766e2ebb036SBrian Somers case DATALINK_AUTH: 767e2ebb036SBrian Somers case DATALINK_LCP: 76854cd8e13SBrian Somers if (dl->physical->link.lcp.fsm.state == ST_STOPPED) 76954cd8e13SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); /* back to CLOSED */ 770dd7e2610SBrian Somers fsm_Down(&dl->physical->link.lcp.fsm); 771c7cc5030SBrian Somers if (stay) 772dd7e2610SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 773c7cc5030SBrian Somers else 774dd7e2610SBrian Somers fsm_Open(&dl->physical->link.ccp.fsm); 775e2ebb036SBrian Somers /* fall through */ 776c7cc5030SBrian Somers 777e2ebb036SBrian Somers default: 778c7cc5030SBrian Somers datalink_ComeDown(dl, stay); 779c7cc5030SBrian Somers } 780e2ebb036SBrian Somers } 781c7cc5030SBrian Somers 782c7cc5030SBrian Somers void 7833006ec67SBrian Somers datalink_StayDown(struct datalink *dl) 7843006ec67SBrian Somers { 7853006ec67SBrian Somers dl->reconnect_tries = 0; 7863006ec67SBrian Somers } 787c7cc5030SBrian Somers 788643f4904SBrian Somers int 789643f4904SBrian Somers datalink_Show(struct cmdargs const *arg) 790c7cc5030SBrian Somers { 791643f4904SBrian Somers prompt_Printf(arg->prompt, "Name: %s\n", arg->cx->name); 792643f4904SBrian Somers prompt_Printf(arg->prompt, " State: %s\n", 793643f4904SBrian Somers datalink_State(arg->cx)); 794643f4904SBrian Somers prompt_Printf(arg->prompt, " CHAP Encryption: %s\n", 795643f4904SBrian Somers arg->cx->chap.using_MSChap ? "MSChap" : "MD5" ); 796643f4904SBrian Somers prompt_Printf(arg->prompt, " Peer name: "); 797643f4904SBrian Somers if (*arg->cx->peer.authname) 798643f4904SBrian Somers prompt_Printf(arg->prompt, "%s\n", arg->cx->peer.authname); 799643f4904SBrian Somers else if (arg->cx->state == DATALINK_OPEN) 800643f4904SBrian Somers prompt_Printf(arg->prompt, "None requested\n"); 801565e35e5SBrian Somers else 802643f4904SBrian Somers prompt_Printf(arg->prompt, "N/A\n"); 803643f4904SBrian Somers prompt_Printf(arg->prompt, " Discriminator: %s\n", 804643f4904SBrian Somers mp_Enddisc(arg->cx->peer.enddisc.class, 805643f4904SBrian Somers arg->cx->peer.enddisc.address, 806643f4904SBrian Somers arg->cx->peer.enddisc.len)); 807643f4904SBrian Somers 808643f4904SBrian Somers prompt_Printf(arg->prompt, "\nDefaults:\n"); 809643f4904SBrian Somers prompt_Printf(arg->prompt, " Phone List: %s\n", 810643f4904SBrian Somers arg->cx->cfg.phone.list); 811643f4904SBrian Somers if (arg->cx->cfg.dial.max) 812643f4904SBrian Somers prompt_Printf(arg->prompt, " Dial tries: %d, delay ", 813643f4904SBrian Somers arg->cx->cfg.dial.max); 814565e35e5SBrian Somers else 815643f4904SBrian Somers prompt_Printf(arg->prompt, " Dial tries: infinite, delay "); 816643f4904SBrian Somers if (arg->cx->cfg.dial.next_timeout > 0) 817643f4904SBrian Somers prompt_Printf(arg->prompt, "%ds/", arg->cx->cfg.dial.next_timeout); 818565e35e5SBrian Somers else 819643f4904SBrian Somers prompt_Printf(arg->prompt, "random/"); 820643f4904SBrian Somers if (arg->cx->cfg.dial.timeout > 0) 821643f4904SBrian Somers prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.dial.timeout); 822565e35e5SBrian Somers else 823643f4904SBrian Somers prompt_Printf(arg->prompt, "random\n"); 824643f4904SBrian Somers prompt_Printf(arg->prompt, " Reconnect tries: %d, delay ", 825643f4904SBrian Somers arg->cx->cfg.reconnect.max); 826643f4904SBrian Somers if (arg->cx->cfg.reconnect.timeout > 0) 827643f4904SBrian Somers prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.reconnect.timeout); 828643f4904SBrian Somers else 829643f4904SBrian Somers prompt_Printf(arg->prompt, "random\n"); 830643f4904SBrian Somers prompt_Printf(arg->prompt, " Dial Script: %s\n", 831643f4904SBrian Somers arg->cx->cfg.script.dial); 832643f4904SBrian Somers prompt_Printf(arg->prompt, " Login Script: %s\n", 833643f4904SBrian Somers arg->cx->cfg.script.login); 834643f4904SBrian Somers prompt_Printf(arg->prompt, " Hangup Script: %s\n", 835643f4904SBrian Somers arg->cx->cfg.script.hangup); 836643f4904SBrian Somers return 0; 837565e35e5SBrian Somers } 838565e35e5SBrian Somers 839565e35e5SBrian Somers int 840565e35e5SBrian Somers datalink_SetReconnect(struct cmdargs const *arg) 841565e35e5SBrian Somers { 84225092092SBrian Somers if (arg->argc == arg->argn+2) { 84325092092SBrian Somers arg->cx->cfg.reconnect.timeout = atoi(arg->argv[arg->argn]); 84425092092SBrian Somers arg->cx->cfg.reconnect.max = atoi(arg->argv[arg->argn+1]); 845565e35e5SBrian Somers return 0; 846565e35e5SBrian Somers } 847565e35e5SBrian Somers return -1; 848565e35e5SBrian Somers } 849565e35e5SBrian Somers 850565e35e5SBrian Somers int 851565e35e5SBrian Somers datalink_SetRedial(struct cmdargs const *arg) 852565e35e5SBrian Somers { 853565e35e5SBrian Somers int timeout; 854565e35e5SBrian Somers int tries; 855565e35e5SBrian Somers char *dot; 856565e35e5SBrian Somers 85725092092SBrian Somers if (arg->argc == arg->argn+1 || arg->argc == arg->argn+2) { 85825092092SBrian Somers if (strncasecmp(arg->argv[arg->argn], "random", 6) == 0 && 85925092092SBrian Somers (arg->argv[arg->argn][6] == '\0' || arg->argv[arg->argn][6] == '.')) { 860565e35e5SBrian Somers arg->cx->cfg.dial.timeout = -1; 861565e35e5SBrian Somers randinit(); 862565e35e5SBrian Somers } else { 86325092092SBrian Somers timeout = atoi(arg->argv[arg->argn]); 864565e35e5SBrian Somers 865565e35e5SBrian Somers if (timeout >= 0) 866565e35e5SBrian Somers arg->cx->cfg.dial.timeout = timeout; 867565e35e5SBrian Somers else { 868dd7e2610SBrian Somers log_Printf(LogWARN, "Invalid redial timeout\n"); 869565e35e5SBrian Somers return -1; 870565e35e5SBrian Somers } 871565e35e5SBrian Somers } 872565e35e5SBrian Somers 87325092092SBrian Somers dot = strchr(arg->argv[arg->argn], '.'); 874565e35e5SBrian Somers if (dot) { 875565e35e5SBrian Somers if (strcasecmp(++dot, "random") == 0) { 876565e35e5SBrian Somers arg->cx->cfg.dial.next_timeout = -1; 877565e35e5SBrian Somers randinit(); 878565e35e5SBrian Somers } else { 879565e35e5SBrian Somers timeout = atoi(dot); 880565e35e5SBrian Somers if (timeout >= 0) 881565e35e5SBrian Somers arg->cx->cfg.dial.next_timeout = timeout; 882565e35e5SBrian Somers else { 883dd7e2610SBrian Somers log_Printf(LogWARN, "Invalid next redial timeout\n"); 884565e35e5SBrian Somers return -1; 885565e35e5SBrian Somers } 886565e35e5SBrian Somers } 887565e35e5SBrian Somers } else 888565e35e5SBrian Somers /* Default next timeout */ 889565e35e5SBrian Somers arg->cx->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT; 890565e35e5SBrian Somers 89125092092SBrian Somers if (arg->argc == arg->argn+2) { 89225092092SBrian Somers tries = atoi(arg->argv[arg->argn+1]); 893565e35e5SBrian Somers 894565e35e5SBrian Somers if (tries >= 0) { 895565e35e5SBrian Somers arg->cx->cfg.dial.max = tries; 896565e35e5SBrian Somers } else { 897dd7e2610SBrian Somers log_Printf(LogWARN, "Invalid retry value\n"); 898565e35e5SBrian Somers return 1; 899565e35e5SBrian Somers } 900565e35e5SBrian Somers } 901565e35e5SBrian Somers return 0; 902565e35e5SBrian Somers } 903565e35e5SBrian Somers return -1; 904c7cc5030SBrian Somers } 905c7cc5030SBrian Somers 906cdbbb6b5SBrian Somers static const char *states[] = { 907565e35e5SBrian Somers "closed", 908565e35e5SBrian Somers "opening", 909565e35e5SBrian Somers "hangup", 910565e35e5SBrian Somers "dial", 911565e35e5SBrian Somers "login", 912565e35e5SBrian Somers "ready", 913565e35e5SBrian Somers "lcp", 914565e35e5SBrian Somers "auth", 915565e35e5SBrian Somers "open" 916c7cc5030SBrian Somers }; 917c7cc5030SBrian Somers 918643f4904SBrian Somers const char * 919c7cc5030SBrian Somers datalink_State(struct datalink *dl) 920c7cc5030SBrian Somers { 921c7cc5030SBrian Somers if (dl->state < 0 || dl->state >= sizeof states / sizeof states[0]) 922c7cc5030SBrian Somers return "unknown"; 923c7cc5030SBrian Somers return states[dl->state]; 924c7cc5030SBrian Somers } 9256f384573SBrian Somers 9269ae58882SBrian Somers static void 9279ae58882SBrian Somers datalink_NewState(struct datalink *dl, int state) 9289ae58882SBrian Somers { 9299ae58882SBrian Somers if (state != dl->state) { 9309ae58882SBrian Somers if (state >= 0 && state < sizeof states / sizeof states[0]) { 9319ae58882SBrian Somers log_Printf(LogPHASE, "%s: %s -> %s\n", dl->name, datalink_State(dl), 9329ae58882SBrian Somers states[state]); 9339ae58882SBrian Somers dl->state = state; 9349ae58882SBrian Somers } else 9359ae58882SBrian Somers log_Printf(LogERROR, "%s: Can't enter state %d !\n", dl->name, state); 9369ae58882SBrian Somers } 9379ae58882SBrian Somers } 9389ae58882SBrian Somers 9396f384573SBrian Somers struct datalink * 94096c9bb21SBrian Somers iov2datalink(struct bundle *bundle, struct iovec *iov, int *niov, int maxiov, 94196c9bb21SBrian Somers int fd) 9426f384573SBrian Somers { 943b7c5748eSBrian Somers struct datalink *dl, *cdl; 9446f384573SBrian Somers u_int retry; 945b7c5748eSBrian Somers char *oname; 9466f384573SBrian Somers 94796c9bb21SBrian Somers dl = (struct datalink *)iov[(*niov)++].iov_base; 94896c9bb21SBrian Somers dl->name = iov[*niov].iov_base; 9496f384573SBrian Somers 95096c9bb21SBrian Somers if (dl->name[DATALINK_MAXNAME-1]) { 95196c9bb21SBrian Somers dl->name[DATALINK_MAXNAME-1] = '\0'; 95296c9bb21SBrian Somers if (strlen(dl->name) == DATALINK_MAXNAME - 1) 95396c9bb21SBrian Somers log_Printf(LogWARN, "Datalink name truncated to \"%s\"\n", dl->name); 9546f384573SBrian Somers } 955b7c5748eSBrian Somers 956b7c5748eSBrian Somers /* Make sure the name is unique ! */ 957b7c5748eSBrian Somers oname = NULL; 958b7c5748eSBrian Somers do { 959b7c5748eSBrian Somers for (cdl = bundle->links; cdl; cdl = cdl->next) 960b7c5748eSBrian Somers if (!strcasecmp(dl->name, cdl->name)) { 961b7c5748eSBrian Somers if (oname) 962b7c5748eSBrian Somers free(datalink_NextName(dl)); 963b7c5748eSBrian Somers else 964b7c5748eSBrian Somers oname = datalink_NextName(dl); 965b7c5748eSBrian Somers break; /* Keep renaming 'till we have no conflicts */ 966b7c5748eSBrian Somers } 967b7c5748eSBrian Somers } while (cdl); 968b7c5748eSBrian Somers 969b7c5748eSBrian Somers if (oname) { 970b7c5748eSBrian Somers log_Printf(LogPHASE, "Rename link %s to %s\n", oname, dl->name); 971b7c5748eSBrian Somers free(oname); 972b7c5748eSBrian Somers } else { 97396c9bb21SBrian Somers dl->name = strdup(dl->name); 974b7c5748eSBrian Somers free(iov[*niov].iov_base); 975b7c5748eSBrian Somers } 976b7c5748eSBrian Somers (*niov)++; 9776f384573SBrian Somers 9786f384573SBrian Somers dl->desc.type = DATALINK_DESCRIPTOR; 9796f384573SBrian Somers dl->desc.UpdateSet = datalink_UpdateSet; 9806f384573SBrian Somers dl->desc.IsSet = datalink_IsSet; 9816f384573SBrian Somers dl->desc.Read = datalink_Read; 9826f384573SBrian Somers dl->desc.Write = datalink_Write; 9836f384573SBrian Somers 9846f384573SBrian Somers mp_linkInit(&dl->mp); 9856f384573SBrian Somers *dl->phone.list = '\0'; 9866f384573SBrian Somers dl->phone.next = NULL; 9876f384573SBrian Somers dl->phone.alt = NULL; 9886f384573SBrian Somers dl->phone.chosen = "N/A"; 9896f384573SBrian Somers 9906f384573SBrian Somers dl->bundle = bundle; 9916f384573SBrian Somers dl->next = NULL; 9926f384573SBrian Somers memset(&dl->dial_timer, '\0', sizeof dl->dial_timer); 9936f384573SBrian Somers dl->dial_tries = 0; 9946f384573SBrian Somers dl->reconnect_tries = 0; 9956f384573SBrian Somers dl->parent = &bundle->fsm; 9966f384573SBrian Somers dl->fsmp.LayerStart = datalink_LayerStart; 9976f384573SBrian Somers dl->fsmp.LayerUp = datalink_LayerUp; 9986f384573SBrian Somers dl->fsmp.LayerDown = datalink_LayerDown; 9996f384573SBrian Somers dl->fsmp.LayerFinish = datalink_LayerFinish; 10006f384573SBrian Somers dl->fsmp.object = dl; 10016f384573SBrian Somers 10026f384573SBrian Somers retry = dl->pap.cfg.fsmretry; 1003dd7e2610SBrian Somers auth_Init(&dl->pap); 10046f384573SBrian Somers dl->pap.cfg.fsmretry = retry; 10056f384573SBrian Somers 10066f384573SBrian Somers retry = dl->chap.auth.cfg.fsmretry; 1007dd7e2610SBrian Somers auth_Init(&dl->chap.auth); 10086f384573SBrian Somers dl->chap.auth.cfg.fsmretry = retry; 10096f384573SBrian Somers 101096c9bb21SBrian Somers dl->physical = iov2modem(dl, iov, niov, maxiov, fd); 101196c9bb21SBrian Somers 101296c9bb21SBrian Somers if (!dl->physical) { 10136f384573SBrian Somers free(dl->name); 10146f384573SBrian Somers free(dl); 10156f384573SBrian Somers dl = NULL; 10169ae58882SBrian Somers } else { 10176f384573SBrian Somers chat_Init(&dl->chat, dl->physical, NULL, 1, NULL); 10186f384573SBrian Somers 10199ae58882SBrian Somers log_Printf(LogPHASE, "%s: Transferred in %s state\n", 10209ae58882SBrian Somers dl->name, datalink_State(dl)); 10219ae58882SBrian Somers } 10229ae58882SBrian Somers 10236f384573SBrian Somers return dl; 10246f384573SBrian Somers } 10256f384573SBrian Somers 10266f384573SBrian Somers int 102785fd273aSBrian Somers datalink2iov(struct datalink *dl, struct iovec *iov, int *niov, int maxiov, 102885fd273aSBrian Somers pid_t newpid) 10296f384573SBrian Somers { 103096c9bb21SBrian Somers /* If `dl' is NULL, we're allocating before a Fromiov() */ 103196c9bb21SBrian Somers int link_fd; 10326f384573SBrian Somers 103396c9bb21SBrian Somers if (dl) { 1034dd7e2610SBrian Somers timer_Stop(&dl->dial_timer); 1035dd7e2610SBrian Somers timer_Stop(&dl->pap.authtimer); 1036dd7e2610SBrian Somers timer_Stop(&dl->chap.auth.authtimer); 10376f384573SBrian Somers } 10386f384573SBrian Somers 103996c9bb21SBrian Somers if (*niov >= maxiov - 1) { 104096c9bb21SBrian Somers log_Printf(LogERROR, "Toiov: No room for datalink !\n"); 104196c9bb21SBrian Somers if (dl) { 10426f384573SBrian Somers free(dl->name); 10436f384573SBrian Somers free(dl); 104496c9bb21SBrian Somers } 104596c9bb21SBrian Somers return -1; 104696c9bb21SBrian Somers } 104796c9bb21SBrian Somers 104896c9bb21SBrian Somers iov[*niov].iov_base = dl ? dl : malloc(sizeof *dl); 104996c9bb21SBrian Somers iov[(*niov)++].iov_len = sizeof *dl; 105096c9bb21SBrian Somers iov[*niov].iov_base = 105196c9bb21SBrian Somers dl ? realloc(dl->name, DATALINK_MAXNAME) : malloc(DATALINK_MAXNAME); 105296c9bb21SBrian Somers iov[(*niov)++].iov_len = DATALINK_MAXNAME; 105396c9bb21SBrian Somers 105485fd273aSBrian Somers link_fd = modem2iov(dl ? dl->physical : NULL, iov, niov, maxiov, newpid); 105596c9bb21SBrian Somers 105696c9bb21SBrian Somers if (link_fd == -1 && dl) { 105796c9bb21SBrian Somers free(dl->name); 105896c9bb21SBrian Somers free(dl); 105996c9bb21SBrian Somers } 10606f384573SBrian Somers 10616f384573SBrian Somers return link_fd; 10626f384573SBrian Somers } 10636f384573SBrian Somers 106458d55334SBrian Somers void 106558d55334SBrian Somers datalink_Rename(struct datalink *dl, const char *name) 106658d55334SBrian Somers { 106758d55334SBrian Somers free(dl->name); 106858d55334SBrian Somers dl->physical->link.name = dl->name = strdup(name); 106958d55334SBrian Somers } 107058d55334SBrian Somers 107184917b87SBrian Somers char * 107284917b87SBrian Somers datalink_NextName(struct datalink *dl) 10736f384573SBrian Somers { 10746f384573SBrian Somers int f, n; 107584917b87SBrian Somers char *name, *oname; 10766f384573SBrian Somers 10776f384573SBrian Somers n = strlen(dl->name); 10786f384573SBrian Somers name = (char *)malloc(n+3); 10796f384573SBrian Somers for (f = n - 1; f >= 0; f--) 10806f384573SBrian Somers if (!isdigit(dl->name[f])) 10816f384573SBrian Somers break; 10826f384573SBrian Somers n = sprintf(name, "%.*s-", dl->name[f] == '-' ? f : f + 1, dl->name); 10836f384573SBrian Somers sprintf(name + n, "%d", atoi(dl->name + f + 1) + 1); 108484917b87SBrian Somers oname = dl->name; 108554cd8e13SBrian Somers dl->name = name; 108654cd8e13SBrian Somers /* our physical link name isn't updated (it probably isn't created yet) */ 108784917b87SBrian Somers return oname; 10886f384573SBrian Somers } 1089dd0645c5SBrian Somers 1090dd0645c5SBrian Somers int 1091dd0645c5SBrian Somers datalink_SetMode(struct datalink *dl, int mode) 1092dd0645c5SBrian Somers { 1093dd0645c5SBrian Somers if (!physical_SetMode(dl->physical, mode)) 1094dd0645c5SBrian Somers return 0; 1095dd0645c5SBrian Somers if (dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED)) 1096dd0645c5SBrian Somers dl->script.run = 0; 1097dd0645c5SBrian Somers if (dl->physical->type == PHYS_DIRECT) 1098dd0645c5SBrian Somers dl->reconnect_tries = 0; 109981358fa3SBrian Somers if (mode & (PHYS_DDIAL|PHYS_BACKGROUND) && dl->state <= DATALINK_READY) 1100dd0645c5SBrian Somers datalink_Up(dl, 1, 1); 1101dd0645c5SBrian Somers return 1; 1102dd0645c5SBrian Somers } 1103