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 * 2606337856SBrian Somers * $Id: datalink.c,v 1.14 1998/06/27 14:18:04 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> 413006ec67SBrian Somers 423006ec67SBrian Somers #include "mbuf.h" 433006ec67SBrian Somers #include "log.h" 443006ec67SBrian Somers #include "defs.h" 453006ec67SBrian Somers #include "timer.h" 463006ec67SBrian Somers #include "fsm.h" 473006ec67SBrian Somers #include "lcp.h" 483006ec67SBrian Somers #include "descriptor.h" 49879ed6faSBrian Somers #include "lqr.h" 503006ec67SBrian Somers #include "hdlc.h" 513006ec67SBrian Somers #include "async.h" 523006ec67SBrian Somers #include "throughput.h" 533b0f8d2eSBrian Somers #include "ccp.h" 543006ec67SBrian Somers #include "link.h" 553006ec67SBrian Somers #include "physical.h" 565828db6dSBrian Somers #include "iplist.h" 57eaa4df37SBrian Somers #include "slcompress.h" 585828db6dSBrian Somers #include "ipcp.h" 595ca5389aSBrian Somers #include "filter.h" 603b0f8d2eSBrian Somers #include "mp.h" 613006ec67SBrian Somers #include "bundle.h" 623006ec67SBrian Somers #include "chat.h" 63e2ebb036SBrian Somers #include "auth.h" 643006ec67SBrian Somers #include "modem.h" 65c7cc5030SBrian Somers #include "prompt.h" 66e2ebb036SBrian Somers #include "lcpproto.h" 67e2ebb036SBrian Somers #include "pap.h" 68e2ebb036SBrian Somers #include "chap.h" 69565e35e5SBrian Somers #include "command.h" 70e2ebb036SBrian Somers #include "datalink.h" 71c7cc5030SBrian Somers 72030e4ebbSBrian Somers static void datalink_LoginDone(struct datalink *); 739ae58882SBrian Somers static void datalink_NewState(struct datalink *, int); 743006ec67SBrian Somers 753006ec67SBrian Somers static void 763006ec67SBrian Somers datalink_OpenTimeout(void *v) 773006ec67SBrian Somers { 783006ec67SBrian Somers struct datalink *dl = (struct datalink *)v; 793006ec67SBrian Somers 80dd7e2610SBrian Somers timer_Stop(&dl->dial_timer); 813006ec67SBrian Somers if (dl->state == DATALINK_OPENING) 82dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: Redial timer expired.\n", dl->name); 833006ec67SBrian Somers } 843006ec67SBrian Somers 853006ec67SBrian Somers static void 863006ec67SBrian Somers datalink_StartDialTimer(struct datalink *dl, int Timeout) 873006ec67SBrian Somers { 88dd7e2610SBrian Somers timer_Stop(&dl->dial_timer); 893006ec67SBrian Somers 903006ec67SBrian Somers if (Timeout) { 913006ec67SBrian Somers if (Timeout > 0) 923006ec67SBrian Somers dl->dial_timer.load = Timeout * SECTICKS; 933006ec67SBrian Somers else 94e718d1d7SBrian Somers dl->dial_timer.load = (random() % DIAL_TIMEOUT) * SECTICKS; 953006ec67SBrian Somers dl->dial_timer.func = datalink_OpenTimeout; 963b0f8d2eSBrian Somers dl->dial_timer.name = "dial"; 973006ec67SBrian Somers dl->dial_timer.arg = dl; 98dd7e2610SBrian Somers timer_Start(&dl->dial_timer); 993006ec67SBrian Somers if (dl->state == DATALINK_OPENING) 100dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: Enter pause (%d) for redialing.\n", 1013006ec67SBrian Somers dl->name, Timeout); 1023006ec67SBrian Somers } 1033006ec67SBrian Somers } 1043006ec67SBrian Somers 1053006ec67SBrian Somers static void 1063006ec67SBrian Somers datalink_HangupDone(struct datalink *dl) 1073006ec67SBrian Somers { 108030e4ebbSBrian Somers if (dl->physical->type == PHYS_DEDICATED && !dl->bundle->CleaningUp && 109dd7e2610SBrian Somers physical_GetFD(dl->physical) != -1) { 110030e4ebbSBrian Somers /* Don't close our modem if the link is dedicated */ 111030e4ebbSBrian Somers datalink_LoginDone(dl); 112030e4ebbSBrian Somers return; 113030e4ebbSBrian Somers } 114030e4ebbSBrian Somers 1153006ec67SBrian Somers modem_Close(dl->physical); 116565e35e5SBrian Somers dl->phone.chosen = "N/A"; 1173006ec67SBrian Somers 1183b0f8d2eSBrian Somers if (dl->bundle->CleaningUp || 1196f384573SBrian Somers (dl->physical->type == PHYS_DIRECT) || 1203b0f8d2eSBrian Somers ((!dl->dial_tries || (dl->dial_tries < 0 && !dl->reconnect_tries)) && 12181358fa3SBrian Somers !(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)))) { 1229ae58882SBrian Somers datalink_NewState(dl, DATALINK_CLOSED); 1233006ec67SBrian Somers dl->dial_tries = -1; 1243006ec67SBrian Somers dl->reconnect_tries = 0; 1253006ec67SBrian Somers bundle_LinkClosed(dl->bundle, dl); 1263b0f8d2eSBrian Somers if (!dl->bundle->CleaningUp) 127565e35e5SBrian Somers datalink_StartDialTimer(dl, dl->cfg.dial.timeout); 1283006ec67SBrian Somers } else { 1299ae58882SBrian Somers datalink_NewState(dl, DATALINK_OPENING); 130abff9baeSBrian Somers if (dl->dial_tries < 0) { 131565e35e5SBrian Somers datalink_StartDialTimer(dl, dl->cfg.reconnect.timeout); 132565e35e5SBrian Somers dl->dial_tries = dl->cfg.dial.max; 133abff9baeSBrian Somers dl->reconnect_tries--; 134abff9baeSBrian Somers } else { 135f9545805SBrian Somers if (dl->phone.next == NULL) 136565e35e5SBrian Somers datalink_StartDialTimer(dl, dl->cfg.dial.timeout); 1373006ec67SBrian Somers else 138565e35e5SBrian Somers datalink_StartDialTimer(dl, dl->cfg.dial.next_timeout); 1393006ec67SBrian Somers } 140abff9baeSBrian Somers } 141abff9baeSBrian Somers } 1423006ec67SBrian Somers 143f9545805SBrian Somers static const char * 144f9545805SBrian Somers datalink_ChoosePhoneNumber(struct datalink *dl) 145f9545805SBrian Somers { 146f9545805SBrian Somers char *phone; 147f9545805SBrian Somers 148f9545805SBrian Somers if (dl->phone.alt == NULL) { 149f9545805SBrian Somers if (dl->phone.next == NULL) { 150f9545805SBrian Somers strncpy(dl->phone.list, dl->cfg.phone.list, sizeof dl->phone.list - 1); 151f9545805SBrian Somers dl->phone.list[sizeof dl->phone.list - 1] = '\0'; 152f9545805SBrian Somers dl->phone.next = dl->phone.list; 153f9545805SBrian Somers } 154f9545805SBrian Somers dl->phone.alt = strsep(&dl->phone.next, ":"); 155f9545805SBrian Somers } 156f9545805SBrian Somers phone = strsep(&dl->phone.alt, "|"); 157f9545805SBrian Somers dl->phone.chosen = *phone ? phone : "[NONE]"; 158f9545805SBrian Somers if (*phone) 159dd7e2610SBrian Somers log_Printf(LogPHASE, "Phone: %s\n", phone); 160f9545805SBrian Somers return phone; 161f9545805SBrian Somers } 162f9545805SBrian Somers 163c5a5a6caSBrian Somers static void 164c5a5a6caSBrian Somers datalink_LoginDone(struct datalink *dl) 165c5a5a6caSBrian Somers { 166d345321bSBrian Somers if (!dl->script.packetmode) { 167d345321bSBrian Somers dl->dial_tries = -1; 1689ae58882SBrian Somers datalink_NewState(dl, DATALINK_READY); 169d345321bSBrian Somers } else if (modem_Raw(dl->physical, dl->bundle) < 0) { 170c5a5a6caSBrian Somers dl->dial_tries = 0; 171dd7e2610SBrian Somers log_Printf(LogWARN, "datalink_LoginDone: Not connected.\n"); 172c5a5a6caSBrian Somers if (dl->script.run) { 1739ae58882SBrian Somers datalink_NewState(dl, DATALINK_HANGUP); 174c5a5a6caSBrian Somers modem_Offline(dl->physical); 175f9545805SBrian Somers chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL); 176030e4ebbSBrian Somers } else { 177030e4ebbSBrian Somers if (dl->physical->type == PHYS_DEDICATED) 178030e4ebbSBrian Somers /* force a redial timeout */ 179030e4ebbSBrian Somers modem_Close(dl->physical); 180c5a5a6caSBrian Somers datalink_HangupDone(dl); 181030e4ebbSBrian Somers } 182c5a5a6caSBrian Somers } else { 183c7cc5030SBrian Somers dl->dial_tries = -1; 184c7cc5030SBrian Somers 185643f4904SBrian Somers hdlc_Init(&dl->physical->hdlc, &dl->physical->link.lcp); 1863b0f8d2eSBrian Somers async_Init(&dl->physical->async); 1873b0f8d2eSBrian Somers 188cd9647a1SBrian Somers lcp_Setup(&dl->physical->link.lcp, dl->state == DATALINK_READY ? 189cd9647a1SBrian Somers 0 : dl->physical->link.lcp.cfg.openmode); 1903b0f8d2eSBrian Somers ccp_Setup(&dl->physical->link.ccp); 191503a7782SBrian Somers 1929ae58882SBrian Somers datalink_NewState(dl, DATALINK_LCP); 193dd7e2610SBrian Somers fsm_Up(&dl->physical->link.lcp.fsm); 194dd7e2610SBrian Somers fsm_Open(&dl->physical->link.lcp.fsm); 195c5a5a6caSBrian Somers } 196c5a5a6caSBrian Somers } 197c5a5a6caSBrian Somers 1983006ec67SBrian Somers static int 1993006ec67SBrian Somers datalink_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e, 2003006ec67SBrian Somers int *n) 2013006ec67SBrian Somers { 2023006ec67SBrian Somers struct datalink *dl = descriptor2datalink(d); 2033006ec67SBrian Somers int result; 2043006ec67SBrian Somers 205310c3babSBrian Somers result = 0; 2063006ec67SBrian Somers switch (dl->state) { 2073006ec67SBrian Somers case DATALINK_CLOSED: 20881358fa3SBrian Somers if ((dl->physical->type & 20981358fa3SBrian Somers (PHYS_DIRECT|PHYS_DEDICATED|PHYS_BACKGROUND|PHYS_DDIAL)) && 210565e35e5SBrian Somers !bundle_IsDead(dl->bundle)) 211565e35e5SBrian Somers /* 21281358fa3SBrian Somers * Our first time in - DEDICATED & DDIAL never come down, and 21381358fa3SBrian Somers * DIRECT & BACKGROUND get deleted when they enter DATALINK_CLOSED. 21481358fa3SBrian Somers * Go to 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)); 23081358fa3SBrian Somers if (!(dl->physical->type & (PHYS_DDIAL|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 { 23981358fa3SBrian Somers if (!(dl->physical->type & (PHYS_DDIAL|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 || 24781358fa3SBrian Somers (!(dl->physical->type & (PHYS_DDIAL|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: 3043006ec67SBrian Somers result = descriptor_UpdateSet(&dl->physical->desc, r, w, e, n); 3053006ec67SBrian Somers break; 3063006ec67SBrian Somers } 3073006ec67SBrian Somers return result; 3083006ec67SBrian Somers } 3093006ec67SBrian Somers 310ea722969SBrian Somers int 311ea722969SBrian Somers datalink_RemoveFromSet(struct datalink *dl, fd_set *r, fd_set *w, fd_set *e) 312ea722969SBrian Somers { 313ea722969SBrian Somers return physical_RemoveFromSet(dl->physical, r, w, e); 314ea722969SBrian Somers } 315ea722969SBrian Somers 3163006ec67SBrian Somers static int 3172f786681SBrian Somers datalink_IsSet(struct descriptor *d, const fd_set *fdset) 3183006ec67SBrian Somers { 3193006ec67SBrian Somers struct datalink *dl = descriptor2datalink(d); 3203006ec67SBrian Somers 3213006ec67SBrian Somers switch (dl->state) { 3223006ec67SBrian Somers case DATALINK_CLOSED: 323c7cc5030SBrian Somers case DATALINK_OPENING: 3243006ec67SBrian Somers break; 325c7cc5030SBrian Somers 3263006ec67SBrian Somers case DATALINK_HANGUP: 3273006ec67SBrian Somers case DATALINK_DIAL: 3283006ec67SBrian Somers case DATALINK_LOGIN: 3293006ec67SBrian Somers return descriptor_IsSet(&dl->chat.desc, fdset); 330c7cc5030SBrian Somers 331c7cc5030SBrian Somers case DATALINK_READY: 332e2ebb036SBrian Somers case DATALINK_LCP: 333e2ebb036SBrian Somers case DATALINK_AUTH: 3343006ec67SBrian Somers case DATALINK_OPEN: 3353006ec67SBrian Somers return descriptor_IsSet(&dl->physical->desc, fdset); 3363006ec67SBrian Somers } 3373006ec67SBrian Somers return 0; 3383006ec67SBrian Somers } 3393006ec67SBrian Somers 3403006ec67SBrian Somers static void 3413006ec67SBrian Somers datalink_Read(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) 3423006ec67SBrian Somers { 3433006ec67SBrian Somers struct datalink *dl = descriptor2datalink(d); 3443006ec67SBrian Somers 3453006ec67SBrian Somers switch (dl->state) { 3463006ec67SBrian Somers case DATALINK_CLOSED: 347c7cc5030SBrian Somers case DATALINK_OPENING: 3483006ec67SBrian Somers break; 349c7cc5030SBrian Somers 3503006ec67SBrian Somers case DATALINK_HANGUP: 3513006ec67SBrian Somers case DATALINK_DIAL: 3523006ec67SBrian Somers case DATALINK_LOGIN: 3533006ec67SBrian Somers descriptor_Read(&dl->chat.desc, bundle, fdset); 3543006ec67SBrian Somers break; 355c7cc5030SBrian Somers 356c7cc5030SBrian Somers case DATALINK_READY: 357e2ebb036SBrian Somers case DATALINK_LCP: 358e2ebb036SBrian Somers case DATALINK_AUTH: 3593006ec67SBrian Somers case DATALINK_OPEN: 3603006ec67SBrian Somers descriptor_Read(&dl->physical->desc, bundle, fdset); 3613006ec67SBrian Somers break; 3623006ec67SBrian Somers } 3633006ec67SBrian Somers } 3643006ec67SBrian Somers 3651af29a6eSBrian Somers static int 366f4768038SBrian Somers datalink_Write(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) 3673006ec67SBrian Somers { 3683006ec67SBrian Somers struct datalink *dl = descriptor2datalink(d); 3691af29a6eSBrian Somers int result = 0; 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: 3791af29a6eSBrian Somers result = 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: 3861af29a6eSBrian Somers result = descriptor_Write(&dl->physical->desc, bundle, fdset); 3873006ec67SBrian Somers break; 3883006ec67SBrian Somers } 3891af29a6eSBrian Somers 3901af29a6eSBrian Somers return result; 3913006ec67SBrian Somers } 3923006ec67SBrian Somers 3936d666775SBrian Somers static void 3949c81b87dSBrian Somers datalink_ComeDown(struct datalink *dl, int how) 395e2ebb036SBrian Somers { 3969c81b87dSBrian Somers if (how != CLOSE_NORMAL) { 397e2ebb036SBrian Somers dl->dial_tries = -1; 398e2ebb036SBrian Somers dl->reconnect_tries = 0; 3997729a182SBrian Somers if (dl->state >= DATALINK_READY && how == CLOSE_LCP) 4009c81b87dSBrian Somers dl->stayonline = 1; 401e2ebb036SBrian Somers } 402e2ebb036SBrian Somers 4037729a182SBrian Somers if (dl->state >= DATALINK_READY && dl->stayonline) { 4049c81b87dSBrian Somers dl->stayonline = 0; 4059c81b87dSBrian Somers datalink_NewState(dl, DATALINK_READY); 4069c81b87dSBrian Somers } else if (dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP) { 407e2ebb036SBrian Somers modem_Offline(dl->physical); 408e2ebb036SBrian Somers if (dl->script.run && dl->state != DATALINK_OPENING) { 4099ae58882SBrian Somers datalink_NewState(dl, DATALINK_HANGUP); 410f9545805SBrian Somers chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL); 411e2ebb036SBrian Somers } else 412e2ebb036SBrian Somers datalink_HangupDone(dl); 413e2ebb036SBrian Somers } 414e2ebb036SBrian Somers } 415e2ebb036SBrian Somers 416e2ebb036SBrian Somers static void 4176d666775SBrian Somers datalink_LayerStart(void *v, struct fsm *fp) 4186d666775SBrian Somers { 4196d666775SBrian Somers /* The given FSM is about to start up ! */ 4206d666775SBrian Somers struct datalink *dl = (struct datalink *)v; 421a611cad6SBrian Somers 42292e872e7SBrian Somers if (fp->proto == PROTO_LCP) 423e2ebb036SBrian Somers (*dl->parent->LayerStart)(dl->parent->object, fp); 424e2ebb036SBrian Somers } 4256d666775SBrian Somers 4266d666775SBrian Somers static void 4276d666775SBrian Somers datalink_LayerUp(void *v, struct fsm *fp) 4286d666775SBrian Somers { 4296d666775SBrian Somers /* The given fsm is now up */ 4306d666775SBrian Somers struct datalink *dl = (struct datalink *)v; 4316d666775SBrian Somers 43292e872e7SBrian Somers if (fp->proto == PROTO_LCP) { 433643f4904SBrian Somers datalink_GotAuthname(dl, "", 0); 4343b0f8d2eSBrian Somers dl->physical->link.lcp.auth_ineed = dl->physical->link.lcp.want_auth; 4353b0f8d2eSBrian Somers dl->physical->link.lcp.auth_iwait = dl->physical->link.lcp.his_auth; 4363b0f8d2eSBrian Somers if (dl->physical->link.lcp.his_auth || dl->physical->link.lcp.want_auth) { 4373b0f8d2eSBrian Somers if (bundle_Phase(dl->bundle) == PHASE_ESTABLISH) 4385563ebdeSBrian Somers bundle_NewPhase(dl->bundle, PHASE_AUTHENTICATE); 439dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: his = %s, mine = %s\n", dl->name, 4403b0f8d2eSBrian Somers Auth2Nam(dl->physical->link.lcp.his_auth), 4413b0f8d2eSBrian Somers Auth2Nam(dl->physical->link.lcp.want_auth)); 4423b0f8d2eSBrian Somers if (dl->physical->link.lcp.his_auth == PROTO_PAP) 443dd7e2610SBrian Somers auth_StartChallenge(&dl->pap, dl->physical, pap_SendChallenge); 4443b0f8d2eSBrian Somers if (dl->physical->link.lcp.want_auth == PROTO_CHAP) 445dd7e2610SBrian Somers auth_StartChallenge(&dl->chap.auth, dl->physical, chap_SendChallenge); 446e2ebb036SBrian Somers } else 447e2ebb036SBrian Somers datalink_AuthOk(dl); 448e2ebb036SBrian Somers } 449e2ebb036SBrian Somers } 450e2ebb036SBrian Somers 451e2ebb036SBrian Somers void 452643f4904SBrian Somers datalink_GotAuthname(struct datalink *dl, const char *name, int len) 453643f4904SBrian Somers { 454643f4904SBrian Somers if (len >= sizeof dl->peer.authname) 455643f4904SBrian Somers len = sizeof dl->peer.authname - 1; 456643f4904SBrian Somers strncpy(dl->peer.authname, name, len); 457643f4904SBrian Somers dl->peer.authname[len] = '\0'; 458643f4904SBrian Somers } 459643f4904SBrian Somers 460643f4904SBrian Somers void 461e2ebb036SBrian Somers datalink_AuthOk(struct datalink *dl) 462e2ebb036SBrian Somers { 46306337856SBrian Somers int ccpok = ccp_SetOpenMode(&dl->physical->link.ccp); 4641df0a3b9SBrian Somers 465dbf60d74SBrian Somers if (dl->physical->link.lcp.want_mrru && dl->physical->link.lcp.his_mrru) { 4661fa665f5SBrian Somers /* we've authenticated in multilink mode ! */ 4671fa665f5SBrian Somers switch (mp_Up(&dl->bundle->ncp.mp, dl)) { 4681fa665f5SBrian Somers case MP_LINKSENT: 469ea722969SBrian Somers /* We've handed the link off to another ppp (well, we will soon) ! */ 4701fa665f5SBrian Somers return; 4711fa665f5SBrian Somers case MP_UP: 4720a1b5c9dSBrian Somers /* First link in the bundle */ 473dd7e2610SBrian Somers auth_Select(dl->bundle, dl->peer.authname, dl->physical); 4740a1b5c9dSBrian Somers /* fall through */ 4751fa665f5SBrian Somers case MP_ADDED: 4760a1b5c9dSBrian Somers /* We're in multilink mode ! */ 4771df0a3b9SBrian Somers dl->physical->link.ccp.fsm.open_mode = OPEN_PASSIVE; /* override */ 4781fa665f5SBrian Somers break; 4791fa665f5SBrian Somers case MP_FAILED: 48049052c95SBrian Somers datalink_AuthNotOk(dl); 48149052c95SBrian Somers return; 48249052c95SBrian Somers } 48349052c95SBrian Somers } else if (bundle_Phase(dl->bundle) == PHASE_NETWORK) { 484dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: Already in NETWORK phase\n", dl->name); 485897f9429SBrian Somers datalink_NewState(dl, DATALINK_OPEN); 486897f9429SBrian Somers (*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.lcp.fsm); 48749052c95SBrian Somers return; 48850abd4c8SBrian Somers } else { 48950abd4c8SBrian Somers dl->bundle->ncp.mp.peer = dl->peer; 490ce828a6eSBrian Somers ipcp_SetLink(&dl->bundle->ncp.ipcp, &dl->physical->link); 491dd7e2610SBrian Somers auth_Select(dl->bundle, dl->peer.authname, dl->physical); 49250abd4c8SBrian Somers } 49349052c95SBrian Somers 49406337856SBrian Somers if (ccpok) { 495dd7e2610SBrian Somers fsm_Up(&dl->physical->link.ccp.fsm); 496dd7e2610SBrian Somers fsm_Open(&dl->physical->link.ccp.fsm); 49706337856SBrian Somers } 4989ae58882SBrian Somers datalink_NewState(dl, DATALINK_OPEN); 4993b0f8d2eSBrian Somers bundle_NewPhase(dl->bundle, PHASE_NETWORK); 5003b0f8d2eSBrian Somers (*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.lcp.fsm); 5016d666775SBrian Somers } 502e2ebb036SBrian Somers 503e2ebb036SBrian Somers void 504e2ebb036SBrian Somers datalink_AuthNotOk(struct datalink *dl) 505e2ebb036SBrian Somers { 5069ae58882SBrian Somers datalink_NewState(dl, DATALINK_LCP); 507dd7e2610SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 5086d666775SBrian Somers } 5096d666775SBrian Somers 5106d666775SBrian Somers static void 5116d666775SBrian Somers datalink_LayerDown(void *v, struct fsm *fp) 5126d666775SBrian Somers { 5136d666775SBrian Somers /* The given FSM has been told to come down */ 5146d666775SBrian Somers struct datalink *dl = (struct datalink *)v; 515a611cad6SBrian Somers 51692e872e7SBrian Somers if (fp->proto == PROTO_LCP) { 517e2ebb036SBrian Somers switch (dl->state) { 518e2ebb036SBrian Somers case DATALINK_OPEN: 519643f4904SBrian Somers peerid_Init(&dl->peer); 52009206a6fSBrian Somers fsm2initial(&dl->physical->link.ccp.fsm); 521ff0f9439SBrian Somers datalink_NewState(dl, DATALINK_LCP); /* before parent TLD */ 522e2ebb036SBrian Somers (*dl->parent->LayerDown)(dl->parent->object, fp); 523e2ebb036SBrian Somers /* fall through */ 524e2ebb036SBrian Somers 525e2ebb036SBrian Somers case DATALINK_AUTH: 526dd7e2610SBrian Somers timer_Stop(&dl->pap.authtimer); 527dd7e2610SBrian Somers timer_Stop(&dl->chap.auth.authtimer); 5286d666775SBrian Somers } 5299ae58882SBrian Somers datalink_NewState(dl, DATALINK_LCP); 530e2ebb036SBrian Somers } 5316d666775SBrian Somers } 5326d666775SBrian Somers 5336d666775SBrian Somers static void 5346d666775SBrian Somers datalink_LayerFinish(void *v, struct fsm *fp) 5356d666775SBrian Somers { 5366d666775SBrian Somers /* The given fsm is now down */ 5376d666775SBrian Somers struct datalink *dl = (struct datalink *)v; 5386d666775SBrian Somers 53992e872e7SBrian Somers if (fp->proto == PROTO_LCP) { 54009206a6fSBrian Somers fsm2initial(fp); 5416d666775SBrian Somers (*dl->parent->LayerFinish)(dl->parent->object, fp); 5429c81b87dSBrian Somers datalink_ComeDown(dl, CLOSE_NORMAL); 5430a1b5c9dSBrian Somers } else if (fp->state == ST_CLOSED && fp->open_mode == OPEN_PASSIVE) 5440a1b5c9dSBrian Somers fsm_Open(fp); /* CCP goes to ST_STOPPED */ 5456d666775SBrian Somers } 5466d666775SBrian Somers 5473006ec67SBrian Somers struct datalink * 5486f384573SBrian Somers datalink_Create(const char *name, struct bundle *bundle, int type) 5493006ec67SBrian Somers { 5503006ec67SBrian Somers struct datalink *dl; 5513006ec67SBrian Somers 5523006ec67SBrian Somers dl = (struct datalink *)malloc(sizeof(struct datalink)); 5533006ec67SBrian Somers if (dl == NULL) 5543006ec67SBrian Somers return dl; 5553006ec67SBrian Somers 5563006ec67SBrian Somers dl->desc.type = DATALINK_DESCRIPTOR; 5573006ec67SBrian Somers dl->desc.UpdateSet = datalink_UpdateSet; 5583006ec67SBrian Somers dl->desc.IsSet = datalink_IsSet; 5593006ec67SBrian Somers dl->desc.Read = datalink_Read; 5603006ec67SBrian Somers dl->desc.Write = datalink_Write; 5615b8b8060SBrian Somers 562e718d1d7SBrian Somers dl->state = DATALINK_CLOSED; 563e718d1d7SBrian Somers 56473a13b5cSBrian Somers *dl->cfg.script.dial = '\0'; 56573a13b5cSBrian Somers *dl->cfg.script.login = '\0'; 56673a13b5cSBrian Somers *dl->cfg.script.hangup = '\0'; 567f9545805SBrian Somers *dl->cfg.phone.list = '\0'; 568f9545805SBrian Somers *dl->phone.list = '\0'; 569f9545805SBrian Somers dl->phone.next = NULL; 570f9545805SBrian Somers dl->phone.alt = NULL; 571f9545805SBrian Somers dl->phone.chosen = "N/A"; 5729c81b87dSBrian Somers dl->stayonline = 0; 573c7cc5030SBrian Somers dl->script.run = 1; 574c7cc5030SBrian Somers dl->script.packetmode = 1; 5753b0f8d2eSBrian Somers mp_linkInit(&dl->mp); 5765b8b8060SBrian Somers 5773006ec67SBrian Somers dl->bundle = bundle; 5783006ec67SBrian Somers dl->next = NULL; 579e718d1d7SBrian Somers 5803006ec67SBrian Somers memset(&dl->dial_timer, '\0', sizeof dl->dial_timer); 581e718d1d7SBrian Somers 5823006ec67SBrian Somers dl->dial_tries = 0; 583565e35e5SBrian Somers dl->cfg.dial.max = 1; 584565e35e5SBrian Somers dl->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT; 585565e35e5SBrian Somers dl->cfg.dial.timeout = DIAL_TIMEOUT; 586e718d1d7SBrian Somers 587abff9baeSBrian Somers dl->reconnect_tries = 0; 588565e35e5SBrian Somers dl->cfg.reconnect.max = 0; 589565e35e5SBrian Somers dl->cfg.reconnect.timeout = RECONNECT_TIMEOUT; 590abff9baeSBrian Somers 5913006ec67SBrian Somers dl->name = strdup(name); 592643f4904SBrian Somers peerid_Init(&dl->peer); 5936f384573SBrian Somers dl->parent = &bundle->fsm; 5943b0f8d2eSBrian Somers dl->fsmp.LayerStart = datalink_LayerStart; 5953b0f8d2eSBrian Somers dl->fsmp.LayerUp = datalink_LayerUp; 5963b0f8d2eSBrian Somers dl->fsmp.LayerDown = datalink_LayerDown; 5973b0f8d2eSBrian Somers dl->fsmp.LayerFinish = datalink_LayerFinish; 5983b0f8d2eSBrian Somers dl->fsmp.object = dl; 5993b0f8d2eSBrian Somers 600dd7e2610SBrian Somers auth_Init(&dl->pap); 601dd7e2610SBrian Somers auth_Init(&dl->chap.auth); 6023b0f8d2eSBrian Somers 603565e35e5SBrian Somers if ((dl->physical = modem_Create(dl, type)) == NULL) { 6043006ec67SBrian Somers free(dl->name); 6053006ec67SBrian Somers free(dl); 6063006ec67SBrian Somers return NULL; 6073006ec67SBrian Somers } 608f9545805SBrian Somers chat_Init(&dl->chat, dl->physical, NULL, 1, NULL); 6093006ec67SBrian Somers 6109ae58882SBrian Somers log_Printf(LogPHASE, "%s: Created in %s state\n", 6119ae58882SBrian Somers dl->name, datalink_State(dl)); 6123006ec67SBrian Somers 6133006ec67SBrian Somers return dl; 6143006ec67SBrian Somers } 6153006ec67SBrian Somers 6163006ec67SBrian Somers struct datalink * 617cd7bd93aSBrian Somers datalink_Clone(struct datalink *odl, const char *name) 618cd7bd93aSBrian Somers { 619cd7bd93aSBrian Somers struct datalink *dl; 620cd7bd93aSBrian Somers 621cd7bd93aSBrian Somers dl = (struct datalink *)malloc(sizeof(struct datalink)); 622cd7bd93aSBrian Somers if (dl == NULL) 623cd7bd93aSBrian Somers return dl; 624cd7bd93aSBrian Somers 625cd7bd93aSBrian Somers dl->desc.type = DATALINK_DESCRIPTOR; 626cd7bd93aSBrian Somers dl->desc.UpdateSet = datalink_UpdateSet; 627cd7bd93aSBrian Somers dl->desc.IsSet = datalink_IsSet; 628cd7bd93aSBrian Somers dl->desc.Read = datalink_Read; 629cd7bd93aSBrian Somers dl->desc.Write = datalink_Write; 630cd7bd93aSBrian Somers 631cd7bd93aSBrian Somers dl->state = DATALINK_CLOSED; 632cd7bd93aSBrian Somers 633cd7bd93aSBrian Somers memcpy(&dl->cfg, &odl->cfg, sizeof dl->cfg); 634cd7bd93aSBrian Somers mp_linkInit(&dl->mp); 635cd7bd93aSBrian Somers *dl->phone.list = '\0'; 636643f4904SBrian Somers dl->phone.next = NULL; 637643f4904SBrian Somers dl->phone.alt = NULL; 638643f4904SBrian Somers dl->phone.chosen = "N/A"; 639cd7bd93aSBrian Somers dl->bundle = odl->bundle; 640cd7bd93aSBrian Somers dl->next = NULL; 641cd7bd93aSBrian Somers memset(&dl->dial_timer, '\0', sizeof dl->dial_timer); 642cd7bd93aSBrian Somers dl->dial_tries = 0; 643cd7bd93aSBrian Somers dl->reconnect_tries = 0; 644cd7bd93aSBrian Somers dl->name = strdup(name); 645643f4904SBrian Somers peerid_Init(&dl->peer); 646cd7bd93aSBrian Somers dl->parent = odl->parent; 647cd7bd93aSBrian Somers memcpy(&dl->fsmp, &odl->fsmp, sizeof dl->fsmp); 648643f4904SBrian Somers dl->fsmp.object = dl; 649dd7e2610SBrian Somers auth_Init(&dl->pap); 650cd7bd93aSBrian Somers dl->pap.cfg.fsmretry = odl->pap.cfg.fsmretry; 651cd7bd93aSBrian Somers 652dd7e2610SBrian Somers auth_Init(&dl->chap.auth); 653cd7bd93aSBrian Somers dl->chap.auth.cfg.fsmretry = odl->chap.auth.cfg.fsmretry; 654cd7bd93aSBrian Somers 65581358fa3SBrian Somers if ((dl->physical = modem_Create(dl, PHYS_INTERACTIVE)) == NULL) { 656cd7bd93aSBrian Somers free(dl->name); 657cd7bd93aSBrian Somers free(dl); 658cd7bd93aSBrian Somers return NULL; 659cd7bd93aSBrian Somers } 660cd7bd93aSBrian Somers memcpy(&dl->physical->cfg, &odl->physical->cfg, sizeof dl->physical->cfg); 661cd7bd93aSBrian Somers memcpy(&dl->physical->link.lcp.cfg, &odl->physical->link.lcp.cfg, 662cd7bd93aSBrian Somers sizeof dl->physical->link.lcp.cfg); 663cd7bd93aSBrian Somers memcpy(&dl->physical->link.ccp.cfg, &odl->physical->link.ccp.cfg, 664cd7bd93aSBrian Somers sizeof dl->physical->link.ccp.cfg); 665cd7bd93aSBrian Somers memcpy(&dl->physical->async.cfg, &odl->physical->async.cfg, 666cd7bd93aSBrian Somers sizeof dl->physical->async.cfg); 667cd7bd93aSBrian Somers 668cd7bd93aSBrian Somers chat_Init(&dl->chat, dl->physical, NULL, 1, NULL); 669cd7bd93aSBrian Somers 6709ae58882SBrian Somers log_Printf(LogPHASE, "%s: Cloned in %s state\n", 6719ae58882SBrian Somers dl->name, datalink_State(dl)); 672cd7bd93aSBrian Somers 673cd7bd93aSBrian Somers return dl; 674cd7bd93aSBrian Somers } 675cd7bd93aSBrian Somers 676cd7bd93aSBrian Somers struct datalink * 6773006ec67SBrian Somers datalink_Destroy(struct datalink *dl) 6783006ec67SBrian Somers { 6793006ec67SBrian Somers struct datalink *result; 6803006ec67SBrian Somers 68139d94652SBrian Somers if (dl->state != DATALINK_CLOSED) { 682dd7e2610SBrian Somers log_Printf(LogERROR, "Oops, destroying a datalink in state %s\n", 683c7cc5030SBrian Somers datalink_State(dl)); 68439d94652SBrian Somers switch (dl->state) { 68539d94652SBrian Somers case DATALINK_HANGUP: 68639d94652SBrian Somers case DATALINK_DIAL: 68739d94652SBrian Somers case DATALINK_LOGIN: 68839d94652SBrian Somers chat_Destroy(&dl->chat); /* Gotta blat the timers ! */ 68939d94652SBrian Somers break; 69039d94652SBrian Somers } 69139d94652SBrian Somers } 6923006ec67SBrian Somers 6933006ec67SBrian Somers result = dl->next; 6943b0f8d2eSBrian Somers modem_Destroy(dl->physical); 6953006ec67SBrian Somers free(dl->name); 6963006ec67SBrian Somers free(dl); 6973006ec67SBrian Somers 6983006ec67SBrian Somers return result; 6993006ec67SBrian Somers } 7003006ec67SBrian Somers 7013006ec67SBrian Somers void 702c5a5a6caSBrian Somers datalink_Up(struct datalink *dl, int runscripts, int packetmode) 7033006ec67SBrian Somers { 7046f384573SBrian Somers if (dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED)) 705565e35e5SBrian Somers /* Ignore scripts */ 706565e35e5SBrian Somers runscripts = 0; 707565e35e5SBrian Somers 708c7cc5030SBrian Somers switch (dl->state) { 709c7cc5030SBrian Somers case DATALINK_CLOSED: 7103b0f8d2eSBrian Somers if (bundle_Phase(dl->bundle) == PHASE_DEAD || 7113b0f8d2eSBrian Somers bundle_Phase(dl->bundle) == PHASE_TERMINATE) 7123b0f8d2eSBrian Somers bundle_NewPhase(dl->bundle, PHASE_ESTABLISH); 7139ae58882SBrian Somers datalink_NewState(dl, DATALINK_OPENING); 714565e35e5SBrian Somers dl->reconnect_tries = 7156f384573SBrian Somers dl->physical->type == PHYS_DIRECT ? 0 : dl->cfg.reconnect.max; 716565e35e5SBrian Somers dl->dial_tries = dl->cfg.dial.max; 717c5a5a6caSBrian Somers dl->script.run = runscripts; 718c5a5a6caSBrian Somers dl->script.packetmode = packetmode; 719c7cc5030SBrian Somers break; 720c7cc5030SBrian Somers 721c7cc5030SBrian Somers case DATALINK_OPENING: 722c7cc5030SBrian Somers if (!dl->script.run && runscripts) 723c7cc5030SBrian Somers dl->script.run = 1; 724c7cc5030SBrian Somers /* fall through */ 725c7cc5030SBrian Somers 726c7cc5030SBrian Somers case DATALINK_DIAL: 727c7cc5030SBrian Somers case DATALINK_LOGIN: 728c7cc5030SBrian Somers case DATALINK_READY: 729c7cc5030SBrian Somers if (!dl->script.packetmode && packetmode) { 730c7cc5030SBrian Somers dl->script.packetmode = 1; 731c7cc5030SBrian Somers if (dl->state == DATALINK_READY) 732c7cc5030SBrian Somers datalink_LoginDone(dl); 733c7cc5030SBrian Somers } 734c7cc5030SBrian Somers break; 7353006ec67SBrian Somers } 7363006ec67SBrian Somers } 7373006ec67SBrian Somers 7383006ec67SBrian Somers void 7399c81b87dSBrian Somers datalink_Close(struct datalink *dl, int how) 740c7cc5030SBrian Somers { 741c7cc5030SBrian Somers /* Please close */ 742e2ebb036SBrian Somers switch (dl->state) { 743e2ebb036SBrian Somers case DATALINK_OPEN: 744643f4904SBrian Somers peerid_Init(&dl->peer); 74509206a6fSBrian Somers fsm2initial(&dl->physical->link.ccp.fsm); 746e2ebb036SBrian Somers /* fall through */ 747e2ebb036SBrian Somers 748e2ebb036SBrian Somers case DATALINK_AUTH: 749e2ebb036SBrian Somers case DATALINK_LCP: 750dd7e2610SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 7519c81b87dSBrian Somers if (how != CLOSE_NORMAL) { 752c7cc5030SBrian Somers dl->dial_tries = -1; 753c7cc5030SBrian Somers dl->reconnect_tries = 0; 7549c81b87dSBrian Somers if (how == CLOSE_LCP) 7559c81b87dSBrian Somers dl->stayonline = 1; 756c7cc5030SBrian Somers } 757e2ebb036SBrian Somers break; 758e2ebb036SBrian Somers 759e2ebb036SBrian Somers default: 7609c81b87dSBrian Somers datalink_ComeDown(dl, how); 761c7cc5030SBrian Somers } 762e2ebb036SBrian Somers } 763c7cc5030SBrian Somers 764c7cc5030SBrian Somers void 7659c81b87dSBrian Somers datalink_Down(struct datalink *dl, int how) 766c7cc5030SBrian Somers { 767c7cc5030SBrian Somers /* Carrier is lost */ 768e2ebb036SBrian Somers switch (dl->state) { 769e2ebb036SBrian Somers case DATALINK_OPEN: 770643f4904SBrian Somers peerid_Init(&dl->peer); 77109206a6fSBrian Somers fsm2initial(&dl->physical->link.ccp.fsm); 772e2ebb036SBrian Somers /* fall through */ 773e2ebb036SBrian Somers 774e2ebb036SBrian Somers case DATALINK_AUTH: 775e2ebb036SBrian Somers case DATALINK_LCP: 77609206a6fSBrian Somers fsm2initial(&dl->physical->link.lcp.fsm); 777e2ebb036SBrian Somers /* fall through */ 778c7cc5030SBrian Somers 779e2ebb036SBrian Somers default: 7809c81b87dSBrian Somers datalink_ComeDown(dl, how); 781c7cc5030SBrian Somers } 782e2ebb036SBrian Somers } 783c7cc5030SBrian Somers 784c7cc5030SBrian Somers void 7853006ec67SBrian Somers datalink_StayDown(struct datalink *dl) 7863006ec67SBrian Somers { 7873006ec67SBrian Somers dl->reconnect_tries = 0; 7883006ec67SBrian Somers } 789c7cc5030SBrian Somers 7909c81b87dSBrian Somers void 7919c81b87dSBrian Somers datalink_DontHangup(struct datalink *dl) 7929c81b87dSBrian Somers { 7937729a182SBrian Somers if (dl->state >= DATALINK_LCP) 7949c81b87dSBrian Somers dl->stayonline = 1; 7959c81b87dSBrian Somers } 7969c81b87dSBrian Somers 797643f4904SBrian Somers int 798643f4904SBrian Somers datalink_Show(struct cmdargs const *arg) 799c7cc5030SBrian Somers { 800643f4904SBrian Somers prompt_Printf(arg->prompt, "Name: %s\n", arg->cx->name); 801643f4904SBrian Somers prompt_Printf(arg->prompt, " State: %s\n", 802643f4904SBrian Somers datalink_State(arg->cx)); 803643f4904SBrian Somers prompt_Printf(arg->prompt, " CHAP Encryption: %s\n", 804643f4904SBrian Somers arg->cx->chap.using_MSChap ? "MSChap" : "MD5" ); 805643f4904SBrian Somers prompt_Printf(arg->prompt, " Peer name: "); 806643f4904SBrian Somers if (*arg->cx->peer.authname) 807643f4904SBrian Somers prompt_Printf(arg->prompt, "%s\n", arg->cx->peer.authname); 808643f4904SBrian Somers else if (arg->cx->state == DATALINK_OPEN) 809643f4904SBrian Somers prompt_Printf(arg->prompt, "None requested\n"); 810565e35e5SBrian Somers else 811643f4904SBrian Somers prompt_Printf(arg->prompt, "N/A\n"); 812643f4904SBrian Somers prompt_Printf(arg->prompt, " Discriminator: %s\n", 813643f4904SBrian Somers mp_Enddisc(arg->cx->peer.enddisc.class, 814643f4904SBrian Somers arg->cx->peer.enddisc.address, 815643f4904SBrian Somers arg->cx->peer.enddisc.len)); 816643f4904SBrian Somers 817643f4904SBrian Somers prompt_Printf(arg->prompt, "\nDefaults:\n"); 818643f4904SBrian Somers prompt_Printf(arg->prompt, " Phone List: %s\n", 819643f4904SBrian Somers arg->cx->cfg.phone.list); 820643f4904SBrian Somers if (arg->cx->cfg.dial.max) 821643f4904SBrian Somers prompt_Printf(arg->prompt, " Dial tries: %d, delay ", 822643f4904SBrian Somers arg->cx->cfg.dial.max); 823565e35e5SBrian Somers else 824643f4904SBrian Somers prompt_Printf(arg->prompt, " Dial tries: infinite, delay "); 825643f4904SBrian Somers if (arg->cx->cfg.dial.next_timeout > 0) 826643f4904SBrian Somers prompt_Printf(arg->prompt, "%ds/", arg->cx->cfg.dial.next_timeout); 827565e35e5SBrian Somers else 828643f4904SBrian Somers prompt_Printf(arg->prompt, "random/"); 829643f4904SBrian Somers if (arg->cx->cfg.dial.timeout > 0) 830643f4904SBrian Somers prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.dial.timeout); 831565e35e5SBrian Somers else 832643f4904SBrian Somers prompt_Printf(arg->prompt, "random\n"); 833643f4904SBrian Somers prompt_Printf(arg->prompt, " Reconnect tries: %d, delay ", 834643f4904SBrian Somers arg->cx->cfg.reconnect.max); 835643f4904SBrian Somers if (arg->cx->cfg.reconnect.timeout > 0) 836643f4904SBrian Somers prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.reconnect.timeout); 837643f4904SBrian Somers else 838643f4904SBrian Somers prompt_Printf(arg->prompt, "random\n"); 839643f4904SBrian Somers prompt_Printf(arg->prompt, " Dial Script: %s\n", 840643f4904SBrian Somers arg->cx->cfg.script.dial); 841643f4904SBrian Somers prompt_Printf(arg->prompt, " Login Script: %s\n", 842643f4904SBrian Somers arg->cx->cfg.script.login); 843643f4904SBrian Somers prompt_Printf(arg->prompt, " Hangup Script: %s\n", 844643f4904SBrian Somers arg->cx->cfg.script.hangup); 845643f4904SBrian Somers return 0; 846565e35e5SBrian Somers } 847565e35e5SBrian Somers 848565e35e5SBrian Somers int 849565e35e5SBrian Somers datalink_SetReconnect(struct cmdargs const *arg) 850565e35e5SBrian Somers { 85125092092SBrian Somers if (arg->argc == arg->argn+2) { 85225092092SBrian Somers arg->cx->cfg.reconnect.timeout = atoi(arg->argv[arg->argn]); 85325092092SBrian Somers arg->cx->cfg.reconnect.max = atoi(arg->argv[arg->argn+1]); 854565e35e5SBrian Somers return 0; 855565e35e5SBrian Somers } 856565e35e5SBrian Somers return -1; 857565e35e5SBrian Somers } 858565e35e5SBrian Somers 859565e35e5SBrian Somers int 860565e35e5SBrian Somers datalink_SetRedial(struct cmdargs const *arg) 861565e35e5SBrian Somers { 862565e35e5SBrian Somers int timeout; 863565e35e5SBrian Somers int tries; 864565e35e5SBrian Somers char *dot; 865565e35e5SBrian Somers 86625092092SBrian Somers if (arg->argc == arg->argn+1 || arg->argc == arg->argn+2) { 86725092092SBrian Somers if (strncasecmp(arg->argv[arg->argn], "random", 6) == 0 && 86825092092SBrian Somers (arg->argv[arg->argn][6] == '\0' || arg->argv[arg->argn][6] == '.')) { 869565e35e5SBrian Somers arg->cx->cfg.dial.timeout = -1; 870565e35e5SBrian Somers randinit(); 871565e35e5SBrian Somers } else { 87225092092SBrian Somers timeout = atoi(arg->argv[arg->argn]); 873565e35e5SBrian Somers 874565e35e5SBrian Somers if (timeout >= 0) 875565e35e5SBrian Somers arg->cx->cfg.dial.timeout = timeout; 876565e35e5SBrian Somers else { 877dd7e2610SBrian Somers log_Printf(LogWARN, "Invalid redial timeout\n"); 878565e35e5SBrian Somers return -1; 879565e35e5SBrian Somers } 880565e35e5SBrian Somers } 881565e35e5SBrian Somers 88225092092SBrian Somers dot = strchr(arg->argv[arg->argn], '.'); 883565e35e5SBrian Somers if (dot) { 884565e35e5SBrian Somers if (strcasecmp(++dot, "random") == 0) { 885565e35e5SBrian Somers arg->cx->cfg.dial.next_timeout = -1; 886565e35e5SBrian Somers randinit(); 887565e35e5SBrian Somers } else { 888565e35e5SBrian Somers timeout = atoi(dot); 889565e35e5SBrian Somers if (timeout >= 0) 890565e35e5SBrian Somers arg->cx->cfg.dial.next_timeout = timeout; 891565e35e5SBrian Somers else { 892dd7e2610SBrian Somers log_Printf(LogWARN, "Invalid next redial timeout\n"); 893565e35e5SBrian Somers return -1; 894565e35e5SBrian Somers } 895565e35e5SBrian Somers } 896565e35e5SBrian Somers } else 897565e35e5SBrian Somers /* Default next timeout */ 898565e35e5SBrian Somers arg->cx->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT; 899565e35e5SBrian Somers 90025092092SBrian Somers if (arg->argc == arg->argn+2) { 90125092092SBrian Somers tries = atoi(arg->argv[arg->argn+1]); 902565e35e5SBrian Somers 903565e35e5SBrian Somers if (tries >= 0) { 904565e35e5SBrian Somers arg->cx->cfg.dial.max = tries; 905565e35e5SBrian Somers } else { 906dd7e2610SBrian Somers log_Printf(LogWARN, "Invalid retry value\n"); 907565e35e5SBrian Somers return 1; 908565e35e5SBrian Somers } 909565e35e5SBrian Somers } 910565e35e5SBrian Somers return 0; 911565e35e5SBrian Somers } 912565e35e5SBrian Somers return -1; 913c7cc5030SBrian Somers } 914c7cc5030SBrian Somers 915cdbbb6b5SBrian Somers static const char *states[] = { 916565e35e5SBrian Somers "closed", 917565e35e5SBrian Somers "opening", 918565e35e5SBrian Somers "hangup", 919565e35e5SBrian Somers "dial", 920565e35e5SBrian Somers "login", 921565e35e5SBrian Somers "ready", 922565e35e5SBrian Somers "lcp", 923565e35e5SBrian Somers "auth", 924565e35e5SBrian Somers "open" 925c7cc5030SBrian Somers }; 926c7cc5030SBrian Somers 927643f4904SBrian Somers const char * 928c7cc5030SBrian Somers datalink_State(struct datalink *dl) 929c7cc5030SBrian Somers { 930c7cc5030SBrian Somers if (dl->state < 0 || dl->state >= sizeof states / sizeof states[0]) 931c7cc5030SBrian Somers return "unknown"; 932c7cc5030SBrian Somers return states[dl->state]; 933c7cc5030SBrian Somers } 9346f384573SBrian Somers 9359ae58882SBrian Somers static void 9369ae58882SBrian Somers datalink_NewState(struct datalink *dl, int state) 9379ae58882SBrian Somers { 9389ae58882SBrian Somers if (state != dl->state) { 9399ae58882SBrian Somers if (state >= 0 && state < sizeof states / sizeof states[0]) { 9409ae58882SBrian Somers log_Printf(LogPHASE, "%s: %s -> %s\n", dl->name, datalink_State(dl), 9419ae58882SBrian Somers states[state]); 9429ae58882SBrian Somers dl->state = state; 9439ae58882SBrian Somers } else 9449ae58882SBrian Somers log_Printf(LogERROR, "%s: Can't enter state %d !\n", dl->name, state); 9459ae58882SBrian Somers } 9469ae58882SBrian Somers } 9479ae58882SBrian Somers 9486f384573SBrian Somers struct datalink * 94996c9bb21SBrian Somers iov2datalink(struct bundle *bundle, struct iovec *iov, int *niov, int maxiov, 95096c9bb21SBrian Somers int fd) 9516f384573SBrian Somers { 952b7c5748eSBrian Somers struct datalink *dl, *cdl; 9536f384573SBrian Somers u_int retry; 954b7c5748eSBrian Somers char *oname; 9556f384573SBrian Somers 95696c9bb21SBrian Somers dl = (struct datalink *)iov[(*niov)++].iov_base; 95796c9bb21SBrian Somers dl->name = iov[*niov].iov_base; 9586f384573SBrian Somers 95996c9bb21SBrian Somers if (dl->name[DATALINK_MAXNAME-1]) { 96096c9bb21SBrian Somers dl->name[DATALINK_MAXNAME-1] = '\0'; 96196c9bb21SBrian Somers if (strlen(dl->name) == DATALINK_MAXNAME - 1) 96296c9bb21SBrian Somers log_Printf(LogWARN, "Datalink name truncated to \"%s\"\n", dl->name); 9636f384573SBrian Somers } 964b7c5748eSBrian Somers 965b7c5748eSBrian Somers /* Make sure the name is unique ! */ 966b7c5748eSBrian Somers oname = NULL; 967b7c5748eSBrian Somers do { 968b7c5748eSBrian Somers for (cdl = bundle->links; cdl; cdl = cdl->next) 969b7c5748eSBrian Somers if (!strcasecmp(dl->name, cdl->name)) { 970b7c5748eSBrian Somers if (oname) 971b7c5748eSBrian Somers free(datalink_NextName(dl)); 972b7c5748eSBrian Somers else 973b7c5748eSBrian Somers oname = datalink_NextName(dl); 974b7c5748eSBrian Somers break; /* Keep renaming 'till we have no conflicts */ 975b7c5748eSBrian Somers } 976b7c5748eSBrian Somers } while (cdl); 977b7c5748eSBrian Somers 978b7c5748eSBrian Somers if (oname) { 979b7c5748eSBrian Somers log_Printf(LogPHASE, "Rename link %s to %s\n", oname, dl->name); 980b7c5748eSBrian Somers free(oname); 981b7c5748eSBrian Somers } else { 98296c9bb21SBrian Somers dl->name = strdup(dl->name); 983b7c5748eSBrian Somers free(iov[*niov].iov_base); 984b7c5748eSBrian Somers } 985b7c5748eSBrian Somers (*niov)++; 9866f384573SBrian Somers 9876f384573SBrian Somers dl->desc.type = DATALINK_DESCRIPTOR; 9886f384573SBrian Somers dl->desc.UpdateSet = datalink_UpdateSet; 9896f384573SBrian Somers dl->desc.IsSet = datalink_IsSet; 9906f384573SBrian Somers dl->desc.Read = datalink_Read; 9916f384573SBrian Somers dl->desc.Write = datalink_Write; 9926f384573SBrian Somers 9936f384573SBrian Somers mp_linkInit(&dl->mp); 9946f384573SBrian Somers *dl->phone.list = '\0'; 9956f384573SBrian Somers dl->phone.next = NULL; 9966f384573SBrian Somers dl->phone.alt = NULL; 9976f384573SBrian Somers dl->phone.chosen = "N/A"; 9986f384573SBrian Somers 9996f384573SBrian Somers dl->bundle = bundle; 10006f384573SBrian Somers dl->next = NULL; 10016f384573SBrian Somers memset(&dl->dial_timer, '\0', sizeof dl->dial_timer); 10026f384573SBrian Somers dl->dial_tries = 0; 10036f384573SBrian Somers dl->reconnect_tries = 0; 10046f384573SBrian Somers dl->parent = &bundle->fsm; 10056f384573SBrian Somers dl->fsmp.LayerStart = datalink_LayerStart; 10066f384573SBrian Somers dl->fsmp.LayerUp = datalink_LayerUp; 10076f384573SBrian Somers dl->fsmp.LayerDown = datalink_LayerDown; 10086f384573SBrian Somers dl->fsmp.LayerFinish = datalink_LayerFinish; 10096f384573SBrian Somers dl->fsmp.object = dl; 10106f384573SBrian Somers 10116f384573SBrian Somers retry = dl->pap.cfg.fsmretry; 1012dd7e2610SBrian Somers auth_Init(&dl->pap); 10136f384573SBrian Somers dl->pap.cfg.fsmretry = retry; 10146f384573SBrian Somers 10156f384573SBrian Somers retry = dl->chap.auth.cfg.fsmretry; 1016dd7e2610SBrian Somers auth_Init(&dl->chap.auth); 10176f384573SBrian Somers dl->chap.auth.cfg.fsmretry = retry; 10186f384573SBrian Somers 101996c9bb21SBrian Somers dl->physical = iov2modem(dl, iov, niov, maxiov, fd); 102096c9bb21SBrian Somers 102196c9bb21SBrian Somers if (!dl->physical) { 10226f384573SBrian Somers free(dl->name); 10236f384573SBrian Somers free(dl); 10246f384573SBrian Somers dl = NULL; 10259ae58882SBrian Somers } else { 10266f384573SBrian Somers chat_Init(&dl->chat, dl->physical, NULL, 1, NULL); 10276f384573SBrian Somers 10289ae58882SBrian Somers log_Printf(LogPHASE, "%s: Transferred in %s state\n", 10299ae58882SBrian Somers dl->name, datalink_State(dl)); 10309ae58882SBrian Somers } 10319ae58882SBrian Somers 10326f384573SBrian Somers return dl; 10336f384573SBrian Somers } 10346f384573SBrian Somers 10356f384573SBrian Somers int 103685fd273aSBrian Somers datalink2iov(struct datalink *dl, struct iovec *iov, int *niov, int maxiov, 103785fd273aSBrian Somers pid_t newpid) 10386f384573SBrian Somers { 103996c9bb21SBrian Somers /* If `dl' is NULL, we're allocating before a Fromiov() */ 104096c9bb21SBrian Somers int link_fd; 10416f384573SBrian Somers 104296c9bb21SBrian Somers if (dl) { 1043dd7e2610SBrian Somers timer_Stop(&dl->dial_timer); 1044dd7e2610SBrian Somers timer_Stop(&dl->pap.authtimer); 1045dd7e2610SBrian Somers timer_Stop(&dl->chap.auth.authtimer); 10466f384573SBrian Somers } 10476f384573SBrian Somers 104896c9bb21SBrian Somers if (*niov >= maxiov - 1) { 104996c9bb21SBrian Somers log_Printf(LogERROR, "Toiov: No room for datalink !\n"); 105096c9bb21SBrian Somers if (dl) { 10516f384573SBrian Somers free(dl->name); 10526f384573SBrian Somers free(dl); 105396c9bb21SBrian Somers } 105496c9bb21SBrian Somers return -1; 105596c9bb21SBrian Somers } 105696c9bb21SBrian Somers 105796c9bb21SBrian Somers iov[*niov].iov_base = dl ? dl : malloc(sizeof *dl); 105896c9bb21SBrian Somers iov[(*niov)++].iov_len = sizeof *dl; 105996c9bb21SBrian Somers iov[*niov].iov_base = 106096c9bb21SBrian Somers dl ? realloc(dl->name, DATALINK_MAXNAME) : malloc(DATALINK_MAXNAME); 106196c9bb21SBrian Somers iov[(*niov)++].iov_len = DATALINK_MAXNAME; 106296c9bb21SBrian Somers 106385fd273aSBrian Somers link_fd = modem2iov(dl ? dl->physical : NULL, iov, niov, maxiov, newpid); 106496c9bb21SBrian Somers 106596c9bb21SBrian Somers if (link_fd == -1 && dl) { 106696c9bb21SBrian Somers free(dl->name); 106796c9bb21SBrian Somers free(dl); 106896c9bb21SBrian Somers } 10696f384573SBrian Somers 10706f384573SBrian Somers return link_fd; 10716f384573SBrian Somers } 10726f384573SBrian Somers 107358d55334SBrian Somers void 107458d55334SBrian Somers datalink_Rename(struct datalink *dl, const char *name) 107558d55334SBrian Somers { 107658d55334SBrian Somers free(dl->name); 107758d55334SBrian Somers dl->physical->link.name = dl->name = strdup(name); 107858d55334SBrian Somers } 107958d55334SBrian Somers 108084917b87SBrian Somers char * 108184917b87SBrian Somers datalink_NextName(struct datalink *dl) 10826f384573SBrian Somers { 10836f384573SBrian Somers int f, n; 108484917b87SBrian Somers char *name, *oname; 10856f384573SBrian Somers 10866f384573SBrian Somers n = strlen(dl->name); 10876f384573SBrian Somers name = (char *)malloc(n+3); 10886f384573SBrian Somers for (f = n - 1; f >= 0; f--) 10896f384573SBrian Somers if (!isdigit(dl->name[f])) 10906f384573SBrian Somers break; 10916f384573SBrian Somers n = sprintf(name, "%.*s-", dl->name[f] == '-' ? f : f + 1, dl->name); 10926f384573SBrian Somers sprintf(name + n, "%d", atoi(dl->name + f + 1) + 1); 109384917b87SBrian Somers oname = dl->name; 109454cd8e13SBrian Somers dl->name = name; 109554cd8e13SBrian Somers /* our physical link name isn't updated (it probably isn't created yet) */ 109684917b87SBrian Somers return oname; 10976f384573SBrian Somers } 1098dd0645c5SBrian Somers 1099dd0645c5SBrian Somers int 1100dd0645c5SBrian Somers datalink_SetMode(struct datalink *dl, int mode) 1101dd0645c5SBrian Somers { 1102dd0645c5SBrian Somers if (!physical_SetMode(dl->physical, mode)) 1103dd0645c5SBrian Somers return 0; 1104dd0645c5SBrian Somers if (dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED)) 1105dd0645c5SBrian Somers dl->script.run = 0; 1106dd0645c5SBrian Somers if (dl->physical->type == PHYS_DIRECT) 1107dd0645c5SBrian Somers dl->reconnect_tries = 0; 110881358fa3SBrian Somers if (mode & (PHYS_DDIAL|PHYS_BACKGROUND) && dl->state <= DATALINK_READY) 1109dd0645c5SBrian Somers datalink_Up(dl, 1, 1); 1110dd0645c5SBrian Somers return 1; 1111dd0645c5SBrian Somers } 1112