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 * 260ca6f91bSBrian Somers * $Id: datalink.c,v 1.36 1999/04/05 21:52:10 brian Exp $ 273006ec67SBrian Somers */ 283006ec67SBrian Somers 29972a1bcfSBrian Somers #include <sys/param.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" 61972a1bcfSBrian Somers #ifndef NORADIUS 62972a1bcfSBrian Somers #include "radius.h" 63972a1bcfSBrian Somers #endif 643006ec67SBrian Somers #include "bundle.h" 653006ec67SBrian Somers #include "chat.h" 66e2ebb036SBrian Somers #include "auth.h" 673006ec67SBrian Somers #include "modem.h" 68c7cc5030SBrian Somers #include "prompt.h" 69e2ebb036SBrian Somers #include "lcpproto.h" 70e2ebb036SBrian Somers #include "pap.h" 71e2ebb036SBrian Somers #include "chap.h" 72565e35e5SBrian Somers #include "command.h" 7392b09558SBrian Somers #include "cbcp.h" 74e2ebb036SBrian Somers #include "datalink.h" 75c7cc5030SBrian Somers 76030e4ebbSBrian Somers static void datalink_LoginDone(struct datalink *); 779ae58882SBrian Somers static void datalink_NewState(struct datalink *, int); 783006ec67SBrian Somers 793006ec67SBrian Somers static void 803006ec67SBrian Somers datalink_OpenTimeout(void *v) 813006ec67SBrian Somers { 823006ec67SBrian Somers struct datalink *dl = (struct datalink *)v; 833006ec67SBrian Somers 84c11e57a3SBrian Somers timer_Stop(&dl->dial.timer); 853006ec67SBrian Somers if (dl->state == DATALINK_OPENING) 86dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: Redial timer expired.\n", dl->name); 873006ec67SBrian Somers } 883006ec67SBrian Somers 89b5c347a3SBrian Somers static int 903006ec67SBrian Somers datalink_StartDialTimer(struct datalink *dl, int Timeout) 913006ec67SBrian Somers { 92b5c347a3SBrian Somers int result = Timeout; 933006ec67SBrian Somers 94c11e57a3SBrian Somers timer_Stop(&dl->dial.timer); 953006ec67SBrian Somers if (Timeout) { 963006ec67SBrian Somers if (Timeout > 0) 97c11e57a3SBrian Somers dl->dial.timer.load = Timeout * SECTICKS; 98b5c347a3SBrian Somers else { 99b5c347a3SBrian Somers result = (random() % DIAL_TIMEOUT) + 1; 100c11e57a3SBrian Somers dl->dial.timer.load = result * SECTICKS; 101b5c347a3SBrian Somers } 102c11e57a3SBrian Somers dl->dial.timer.func = datalink_OpenTimeout; 103c11e57a3SBrian Somers dl->dial.timer.name = "dial"; 104c11e57a3SBrian Somers dl->dial.timer.arg = dl; 105c11e57a3SBrian Somers timer_Start(&dl->dial.timer); 1063006ec67SBrian Somers if (dl->state == DATALINK_OPENING) 107dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: Enter pause (%d) for redialing.\n", 1083006ec67SBrian Somers dl->name, Timeout); 1093006ec67SBrian Somers } 110b5c347a3SBrian Somers return result; 1113006ec67SBrian Somers } 1123006ec67SBrian Somers 1133006ec67SBrian Somers static void 1143006ec67SBrian Somers datalink_HangupDone(struct datalink *dl) 1153006ec67SBrian Somers { 116030e4ebbSBrian Somers if (dl->physical->type == PHYS_DEDICATED && !dl->bundle->CleaningUp && 117dd7e2610SBrian Somers physical_GetFD(dl->physical) != -1) { 118030e4ebbSBrian Somers /* Don't close our modem if the link is dedicated */ 119030e4ebbSBrian Somers datalink_LoginDone(dl); 120030e4ebbSBrian Somers return; 121030e4ebbSBrian Somers } 122030e4ebbSBrian Somers 1233006ec67SBrian Somers modem_Close(dl->physical); 124565e35e5SBrian Somers dl->phone.chosen = "N/A"; 1253006ec67SBrian Somers 12692b09558SBrian Somers if (dl->cbcp.required) { 12792b09558SBrian Somers log_Printf(LogPHASE, "Call peer back on %s\n", dl->cbcp.fsm.phone); 12892b09558SBrian Somers dl->cfg.callback.opmask = 0; 12992b09558SBrian Somers strncpy(dl->cfg.phone.list, dl->cbcp.fsm.phone, 13092b09558SBrian Somers sizeof dl->cfg.phone.list - 1); 13192b09558SBrian Somers dl->cfg.phone.list[sizeof dl->cfg.phone.list - 1] = '\0'; 13292b09558SBrian Somers dl->phone.alt = dl->phone.next = NULL; 13392b09558SBrian Somers dl->reconnect_tries = dl->cfg.reconnect.max; 134c11e57a3SBrian Somers dl->dial.tries = dl->cfg.dial.max; 135c11e57a3SBrian Somers dl->dial.incs = 0; 13692b09558SBrian Somers dl->script.run = 1; 13792b09558SBrian Somers dl->script.packetmode = 1; 13892b09558SBrian Somers if (!physical_SetMode(dl->physical, PHYS_BACKGROUND)) 13992b09558SBrian Somers log_Printf(LogERROR, "Oops - can't change mode to BACKGROUND (gulp) !\n"); 14092b09558SBrian Somers bundle_LinksRemoved(dl->bundle); 141c11e57a3SBrian Somers /* if dial.timeout is < 0 (random), we don't override fsm.delay */ 14292b09558SBrian Somers if (dl->cbcp.fsm.delay < dl->cfg.dial.timeout) 14392b09558SBrian Somers dl->cbcp.fsm.delay = dl->cfg.dial.timeout; 14492b09558SBrian Somers datalink_StartDialTimer(dl, dl->cbcp.fsm.delay); 14592b09558SBrian Somers cbcp_Down(&dl->cbcp); 14692b09558SBrian Somers datalink_NewState(dl, DATALINK_OPENING); 1470ca6f91bSBrian Somers if (bundle_Phase(dl->bundle) != PHASE_TERMINATE) 1480ca6f91bSBrian Somers bundle_NewPhase(dl->bundle, PHASE_ESTABLISH); 14992b09558SBrian Somers } else if (dl->bundle->CleaningUp || 1506f384573SBrian Somers (dl->physical->type == PHYS_DIRECT) || 151c11e57a3SBrian Somers ((!dl->dial.tries || (dl->dial.tries < 0 && !dl->reconnect_tries)) && 15281358fa3SBrian Somers !(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)))) { 1539ae58882SBrian Somers datalink_NewState(dl, DATALINK_CLOSED); 154c11e57a3SBrian Somers dl->dial.tries = -1; 155c11e57a3SBrian Somers dl->dial.incs = 0; 1563006ec67SBrian Somers dl->reconnect_tries = 0; 1573006ec67SBrian Somers bundle_LinkClosed(dl->bundle, dl); 1583b0f8d2eSBrian Somers if (!dl->bundle->CleaningUp) 159c11e57a3SBrian Somers datalink_StartDialTimer(dl, datalink_GetDialTimeout(dl)); 1603006ec67SBrian Somers } else { 1619ae58882SBrian Somers datalink_NewState(dl, DATALINK_OPENING); 1620ca6f91bSBrian Somers if (bundle_Phase(dl->bundle) != PHASE_TERMINATE) 1630ca6f91bSBrian Somers bundle_NewPhase(dl->bundle, PHASE_ESTABLISH); 164c11e57a3SBrian Somers if (dl->dial.tries < 0) { 165565e35e5SBrian Somers datalink_StartDialTimer(dl, dl->cfg.reconnect.timeout); 166c11e57a3SBrian Somers dl->dial.tries = dl->cfg.dial.max; 167c11e57a3SBrian Somers dl->dial.incs = 0; 168abff9baeSBrian Somers dl->reconnect_tries--; 169abff9baeSBrian Somers } else { 170f9545805SBrian Somers if (dl->phone.next == NULL) 171c11e57a3SBrian Somers datalink_StartDialTimer(dl, datalink_GetDialTimeout(dl)); 1723006ec67SBrian Somers else 173565e35e5SBrian Somers datalink_StartDialTimer(dl, dl->cfg.dial.next_timeout); 1743006ec67SBrian Somers } 175abff9baeSBrian Somers } 176abff9baeSBrian Somers } 1773006ec67SBrian Somers 178f9545805SBrian Somers static const char * 179f9545805SBrian Somers datalink_ChoosePhoneNumber(struct datalink *dl) 180f9545805SBrian Somers { 181f9545805SBrian Somers char *phone; 182f9545805SBrian Somers 183f9545805SBrian Somers if (dl->phone.alt == NULL) { 184f9545805SBrian Somers if (dl->phone.next == NULL) { 185f9545805SBrian Somers strncpy(dl->phone.list, dl->cfg.phone.list, sizeof dl->phone.list - 1); 186f9545805SBrian Somers dl->phone.list[sizeof dl->phone.list - 1] = '\0'; 187f9545805SBrian Somers dl->phone.next = dl->phone.list; 188f9545805SBrian Somers } 189f9545805SBrian Somers dl->phone.alt = strsep(&dl->phone.next, ":"); 190f9545805SBrian Somers } 191f9545805SBrian Somers phone = strsep(&dl->phone.alt, "|"); 192f9545805SBrian Somers dl->phone.chosen = *phone ? phone : "[NONE]"; 193f9545805SBrian Somers if (*phone) 194dd7e2610SBrian Somers log_Printf(LogPHASE, "Phone: %s\n", phone); 195f9545805SBrian Somers return phone; 196f9545805SBrian Somers } 197f9545805SBrian Somers 198c5a5a6caSBrian Somers static void 199c5a5a6caSBrian Somers datalink_LoginDone(struct datalink *dl) 200c5a5a6caSBrian Somers { 201d345321bSBrian Somers if (!dl->script.packetmode) { 202c11e57a3SBrian Somers dl->dial.tries = -1; 203c11e57a3SBrian Somers dl->dial.incs = 0; 2049ae58882SBrian Somers datalink_NewState(dl, DATALINK_READY); 205d345321bSBrian Somers } else if (modem_Raw(dl->physical, dl->bundle) < 0) { 206c11e57a3SBrian Somers dl->dial.tries = 0; 207dd7e2610SBrian Somers log_Printf(LogWARN, "datalink_LoginDone: Not connected.\n"); 208c5a5a6caSBrian Somers if (dl->script.run) { 2099ae58882SBrian Somers datalink_NewState(dl, DATALINK_HANGUP); 210c5a5a6caSBrian Somers modem_Offline(dl->physical); 211f9545805SBrian Somers chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL); 212030e4ebbSBrian Somers } else { 213d4af231cSBrian Somers timer_Stop(&dl->physical->Timer); 214030e4ebbSBrian Somers if (dl->physical->type == PHYS_DEDICATED) 215030e4ebbSBrian Somers /* force a redial timeout */ 216030e4ebbSBrian Somers modem_Close(dl->physical); 217c5a5a6caSBrian Somers datalink_HangupDone(dl); 218030e4ebbSBrian Somers } 219c5a5a6caSBrian Somers } else { 220c11e57a3SBrian Somers dl->dial.tries = -1; 221c11e57a3SBrian Somers dl->dial.incs = 0; 222c7cc5030SBrian Somers 223643f4904SBrian Somers hdlc_Init(&dl->physical->hdlc, &dl->physical->link.lcp); 2243b0f8d2eSBrian Somers async_Init(&dl->physical->async); 2253b0f8d2eSBrian Somers 226cd9647a1SBrian Somers lcp_Setup(&dl->physical->link.lcp, dl->state == DATALINK_READY ? 227cd9647a1SBrian Somers 0 : dl->physical->link.lcp.cfg.openmode); 2283b0f8d2eSBrian Somers ccp_Setup(&dl->physical->link.ccp); 229503a7782SBrian Somers 2309ae58882SBrian Somers datalink_NewState(dl, DATALINK_LCP); 231dd7e2610SBrian Somers fsm_Up(&dl->physical->link.lcp.fsm); 232dd7e2610SBrian Somers fsm_Open(&dl->physical->link.lcp.fsm); 233c5a5a6caSBrian Somers } 234c5a5a6caSBrian Somers } 235c5a5a6caSBrian Somers 2363006ec67SBrian Somers static int 2373006ec67SBrian Somers datalink_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e, 2383006ec67SBrian Somers int *n) 2393006ec67SBrian Somers { 2403006ec67SBrian Somers struct datalink *dl = descriptor2datalink(d); 2413006ec67SBrian Somers int result; 2423006ec67SBrian Somers 243310c3babSBrian Somers result = 0; 2443006ec67SBrian Somers switch (dl->state) { 2453006ec67SBrian Somers case DATALINK_CLOSED: 24681358fa3SBrian Somers if ((dl->physical->type & 24781358fa3SBrian Somers (PHYS_DIRECT|PHYS_DEDICATED|PHYS_BACKGROUND|PHYS_DDIAL)) && 248565e35e5SBrian Somers !bundle_IsDead(dl->bundle)) 249565e35e5SBrian Somers /* 25081358fa3SBrian Somers * Our first time in - DEDICATED & DDIAL never come down, and 25181358fa3SBrian Somers * DIRECT & BACKGROUND get deleted when they enter DATALINK_CLOSED. 25281358fa3SBrian Somers * Go to DATALINK_OPENING via datalink_Up() and fall through. 253565e35e5SBrian Somers */ 254565e35e5SBrian Somers datalink_Up(dl, 1, 1); 255565e35e5SBrian Somers else 256310c3babSBrian Somers break; 257565e35e5SBrian Somers /* fall through */ 2583006ec67SBrian Somers 2593006ec67SBrian Somers case DATALINK_OPENING: 260c11e57a3SBrian Somers if (dl->dial.timer.state != TIMER_RUNNING) { 261c11e57a3SBrian Somers if (--dl->dial.tries < 0) 262c11e57a3SBrian Somers dl->dial.tries = 0; 2633006ec67SBrian Somers if (modem_Open(dl->physical, dl->bundle) >= 0) { 264bf1d3ff6SBrian Somers log_WritePrompts(dl, "%s: Entering terminal mode on %s\r\n" 265bf1d3ff6SBrian Somers "Type `~?' for help\r\n", dl->name, 266bf1d3ff6SBrian Somers dl->physical->name.full); 267c5a5a6caSBrian Somers if (dl->script.run) { 2689ae58882SBrian Somers datalink_NewState(dl, DATALINK_DIAL); 269f9545805SBrian Somers chat_Init(&dl->chat, dl->physical, dl->cfg.script.dial, 1, 270f9545805SBrian Somers datalink_ChoosePhoneNumber(dl)); 27181358fa3SBrian Somers if (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) && 272565e35e5SBrian Somers dl->cfg.dial.max) 273dd7e2610SBrian Somers log_Printf(LogCHAT, "%s: Dial attempt %u of %d\n", 274c11e57a3SBrian Somers dl->name, dl->cfg.dial.max - dl->dial.tries, 275565e35e5SBrian Somers dl->cfg.dial.max); 276c5a5a6caSBrian Somers } else 277c5a5a6caSBrian Somers datalink_LoginDone(dl); 2788b09cf1cSBrian Somers return datalink_UpdateSet(d, r, w, e, n); 2793006ec67SBrian Somers } else { 28081358fa3SBrian Somers if (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) && 281565e35e5SBrian Somers dl->cfg.dial.max) 282dd7e2610SBrian Somers log_Printf(LogCHAT, "Failed to open modem (attempt %u of %d)\n", 283c11e57a3SBrian Somers dl->cfg.dial.max - dl->dial.tries, dl->cfg.dial.max); 2843006ec67SBrian Somers else 285dd7e2610SBrian Somers log_Printf(LogCHAT, "Failed to open modem\n"); 2863006ec67SBrian Somers 2873b0f8d2eSBrian Somers if (dl->bundle->CleaningUp || 28881358fa3SBrian Somers (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) && 289c11e57a3SBrian Somers dl->cfg.dial.max && dl->dial.tries == 0)) { 2909ae58882SBrian Somers datalink_NewState(dl, DATALINK_CLOSED); 2913006ec67SBrian Somers dl->reconnect_tries = 0; 292c11e57a3SBrian Somers dl->dial.tries = -1; 293bf1d3ff6SBrian Somers log_WritePrompts(dl, "Failed to open %s\n", 294bf1d3ff6SBrian Somers dl->physical->name.full); 2955b8b8060SBrian Somers bundle_LinkClosed(dl->bundle, dl); 296c5a5a6caSBrian Somers } 297bf1d3ff6SBrian Somers if (!dl->bundle->CleaningUp) { 298c11e57a3SBrian Somers int timeout; 299c11e57a3SBrian Somers 300c11e57a3SBrian Somers timeout = datalink_StartDialTimer(dl, datalink_GetDialTimeout(dl)); 301bf1d3ff6SBrian Somers log_WritePrompts(dl, "Failed to open %s, pause %d seconds\n", 302b5c347a3SBrian Somers dl->physical->name.full, timeout); 3033006ec67SBrian Somers } 3043006ec67SBrian Somers } 305bf1d3ff6SBrian Somers } 306310c3babSBrian Somers break; 3073006ec67SBrian Somers 3083006ec67SBrian Somers case DATALINK_HANGUP: 3093006ec67SBrian Somers case DATALINK_DIAL: 3103006ec67SBrian Somers case DATALINK_LOGIN: 3113006ec67SBrian Somers result = descriptor_UpdateSet(&dl->chat.desc, r, w, e, n); 3123006ec67SBrian Somers switch (dl->chat.state) { 3133006ec67SBrian Somers case CHAT_DONE: 3143006ec67SBrian Somers /* script succeeded */ 31539d94652SBrian Somers chat_Destroy(&dl->chat); 3163006ec67SBrian Somers switch(dl->state) { 3173006ec67SBrian Somers case DATALINK_HANGUP: 3183006ec67SBrian Somers datalink_HangupDone(dl); 3193006ec67SBrian Somers break; 3203006ec67SBrian Somers case DATALINK_DIAL: 3219ae58882SBrian Somers datalink_NewState(dl, DATALINK_LOGIN); 322f9545805SBrian Somers chat_Init(&dl->chat, dl->physical, dl->cfg.script.login, 0, NULL); 3231342caedSBrian Somers return datalink_UpdateSet(d, r, w, e, n); 3243006ec67SBrian Somers case DATALINK_LOGIN: 32547dd77c1SBrian Somers dl->phone.alt = NULL; 326c5a5a6caSBrian Somers datalink_LoginDone(dl); 327b51a60ccSBrian Somers return datalink_UpdateSet(d, r, w, e, n); 3283006ec67SBrian Somers } 3293006ec67SBrian Somers break; 3303006ec67SBrian Somers case CHAT_FAILED: 3313006ec67SBrian Somers /* Going down - script failed */ 332dd7e2610SBrian Somers log_Printf(LogWARN, "Chat script failed\n"); 33339d94652SBrian Somers chat_Destroy(&dl->chat); 3343006ec67SBrian Somers switch(dl->state) { 3353006ec67SBrian Somers case DATALINK_HANGUP: 3363006ec67SBrian Somers datalink_HangupDone(dl); 3373006ec67SBrian Somers break; 3383006ec67SBrian Somers case DATALINK_DIAL: 3393006ec67SBrian Somers case DATALINK_LOGIN: 3409ae58882SBrian Somers datalink_NewState(dl, DATALINK_HANGUP); 341d4af231cSBrian Somers modem_Offline(dl->physical); /* Is this required ? */ 342f9545805SBrian Somers chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL); 3431342caedSBrian Somers return datalink_UpdateSet(d, r, w, e, n); 3443006ec67SBrian Somers } 3453006ec67SBrian Somers break; 3463006ec67SBrian Somers } 3473006ec67SBrian Somers break; 348c7cc5030SBrian Somers 349c7cc5030SBrian Somers case DATALINK_READY: 350e2ebb036SBrian Somers case DATALINK_LCP: 351e2ebb036SBrian Somers case DATALINK_AUTH: 35292b09558SBrian Somers case DATALINK_CBCP: 3533006ec67SBrian Somers case DATALINK_OPEN: 35458330d7bSBrian Somers result = descriptor_UpdateSet(&dl->chap.desc, r, w, e, n) + 35558330d7bSBrian Somers descriptor_UpdateSet(&dl->physical->desc, r, w, e, n); 3563006ec67SBrian Somers break; 3573006ec67SBrian Somers } 3583006ec67SBrian Somers return result; 3593006ec67SBrian Somers } 3603006ec67SBrian Somers 361ea722969SBrian Somers int 362ea722969SBrian Somers datalink_RemoveFromSet(struct datalink *dl, fd_set *r, fd_set *w, fd_set *e) 363ea722969SBrian Somers { 364ea722969SBrian Somers return physical_RemoveFromSet(dl->physical, r, w, e); 365ea722969SBrian Somers } 366ea722969SBrian Somers 3673006ec67SBrian Somers static int 3682f786681SBrian Somers datalink_IsSet(struct descriptor *d, const fd_set *fdset) 3693006ec67SBrian Somers { 3703006ec67SBrian Somers struct datalink *dl = descriptor2datalink(d); 3713006ec67SBrian Somers 3723006ec67SBrian Somers switch (dl->state) { 3733006ec67SBrian Somers case DATALINK_CLOSED: 374c7cc5030SBrian Somers case DATALINK_OPENING: 3753006ec67SBrian Somers break; 376c7cc5030SBrian Somers 3773006ec67SBrian Somers case DATALINK_HANGUP: 3783006ec67SBrian Somers case DATALINK_DIAL: 3793006ec67SBrian Somers case DATALINK_LOGIN: 3803006ec67SBrian Somers return descriptor_IsSet(&dl->chat.desc, fdset); 381c7cc5030SBrian Somers 382c7cc5030SBrian Somers case DATALINK_READY: 383e2ebb036SBrian Somers case DATALINK_LCP: 384e2ebb036SBrian Somers case DATALINK_AUTH: 38592b09558SBrian Somers case DATALINK_CBCP: 3863006ec67SBrian Somers case DATALINK_OPEN: 38758330d7bSBrian Somers return descriptor_IsSet(&dl->chap.desc, fdset) ? 1 : 38858330d7bSBrian Somers descriptor_IsSet(&dl->physical->desc, fdset); 3893006ec67SBrian Somers } 3903006ec67SBrian Somers return 0; 3913006ec67SBrian Somers } 3923006ec67SBrian Somers 3933006ec67SBrian Somers static void 3943006ec67SBrian Somers datalink_Read(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) 3953006ec67SBrian Somers { 3963006ec67SBrian Somers struct datalink *dl = descriptor2datalink(d); 3973006ec67SBrian Somers 3983006ec67SBrian Somers switch (dl->state) { 3993006ec67SBrian Somers case DATALINK_CLOSED: 400c7cc5030SBrian Somers case DATALINK_OPENING: 4013006ec67SBrian Somers break; 402c7cc5030SBrian Somers 4033006ec67SBrian Somers case DATALINK_HANGUP: 4043006ec67SBrian Somers case DATALINK_DIAL: 4053006ec67SBrian Somers case DATALINK_LOGIN: 4063006ec67SBrian Somers descriptor_Read(&dl->chat.desc, bundle, fdset); 4073006ec67SBrian Somers break; 408c7cc5030SBrian Somers 409c7cc5030SBrian Somers case DATALINK_READY: 410e2ebb036SBrian Somers case DATALINK_LCP: 411e2ebb036SBrian Somers case DATALINK_AUTH: 41292b09558SBrian Somers case DATALINK_CBCP: 4133006ec67SBrian Somers case DATALINK_OPEN: 41458330d7bSBrian Somers if (descriptor_IsSet(&dl->chap.desc, fdset)) 41558330d7bSBrian Somers descriptor_Read(&dl->chap.desc, bundle, fdset); 41658330d7bSBrian Somers if (descriptor_IsSet(&dl->physical->desc, fdset)) 4173006ec67SBrian Somers descriptor_Read(&dl->physical->desc, bundle, fdset); 4183006ec67SBrian Somers break; 4193006ec67SBrian Somers } 4203006ec67SBrian Somers } 4213006ec67SBrian Somers 4221af29a6eSBrian Somers static int 423f4768038SBrian Somers datalink_Write(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) 4243006ec67SBrian Somers { 4253006ec67SBrian Somers struct datalink *dl = descriptor2datalink(d); 4261af29a6eSBrian Somers int result = 0; 4273006ec67SBrian Somers 4283006ec67SBrian Somers switch (dl->state) { 4293006ec67SBrian Somers case DATALINK_CLOSED: 430c7cc5030SBrian Somers case DATALINK_OPENING: 4313006ec67SBrian Somers break; 432c7cc5030SBrian Somers 4333006ec67SBrian Somers case DATALINK_HANGUP: 4343006ec67SBrian Somers case DATALINK_DIAL: 4353006ec67SBrian Somers case DATALINK_LOGIN: 4361af29a6eSBrian Somers result = descriptor_Write(&dl->chat.desc, bundle, fdset); 4373006ec67SBrian Somers break; 438c7cc5030SBrian Somers 439c7cc5030SBrian Somers case DATALINK_READY: 440e2ebb036SBrian Somers case DATALINK_LCP: 441e2ebb036SBrian Somers case DATALINK_AUTH: 44292b09558SBrian Somers case DATALINK_CBCP: 4433006ec67SBrian Somers case DATALINK_OPEN: 44458330d7bSBrian Somers if (descriptor_IsSet(&dl->chap.desc, fdset)) 44558330d7bSBrian Somers result += descriptor_Write(&dl->chap.desc, bundle, fdset); 44658330d7bSBrian Somers if (descriptor_IsSet(&dl->physical->desc, fdset)) 44758330d7bSBrian Somers result += descriptor_Write(&dl->physical->desc, bundle, fdset); 4483006ec67SBrian Somers break; 4493006ec67SBrian Somers } 4501af29a6eSBrian Somers 4511af29a6eSBrian Somers return result; 4523006ec67SBrian Somers } 4533006ec67SBrian Somers 4546d666775SBrian Somers static void 4559c81b87dSBrian Somers datalink_ComeDown(struct datalink *dl, int how) 456e2ebb036SBrian Somers { 4579c81b87dSBrian Somers if (how != CLOSE_NORMAL) { 458c11e57a3SBrian Somers dl->dial.tries = -1; 459e2ebb036SBrian Somers dl->reconnect_tries = 0; 4607729a182SBrian Somers if (dl->state >= DATALINK_READY && how == CLOSE_LCP) 4619c81b87dSBrian Somers dl->stayonline = 1; 462e2ebb036SBrian Somers } 463e2ebb036SBrian Somers 4647729a182SBrian Somers if (dl->state >= DATALINK_READY && dl->stayonline) { 4659c81b87dSBrian Somers dl->stayonline = 0; 466d4af231cSBrian Somers timer_Stop(&dl->physical->Timer); 4679c81b87dSBrian Somers datalink_NewState(dl, DATALINK_READY); 4689c81b87dSBrian Somers } else if (dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP) { 469e2ebb036SBrian Somers modem_Offline(dl->physical); 470b6f5f442SBrian Somers chat_Destroy(&dl->chat); 471e2ebb036SBrian Somers if (dl->script.run && dl->state != DATALINK_OPENING) { 4729ae58882SBrian Somers datalink_NewState(dl, DATALINK_HANGUP); 473f9545805SBrian Somers chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL); 474e2ebb036SBrian Somers } else 475e2ebb036SBrian Somers datalink_HangupDone(dl); 476e2ebb036SBrian Somers } 477e2ebb036SBrian Somers } 478e2ebb036SBrian Somers 479e2ebb036SBrian Somers static void 4806d666775SBrian Somers datalink_LayerStart(void *v, struct fsm *fp) 4816d666775SBrian Somers { 4826d666775SBrian Somers /* The given FSM is about to start up ! */ 4836d666775SBrian Somers struct datalink *dl = (struct datalink *)v; 484a611cad6SBrian Somers 48592e872e7SBrian Somers if (fp->proto == PROTO_LCP) 486e2ebb036SBrian Somers (*dl->parent->LayerStart)(dl->parent->object, fp); 487e2ebb036SBrian Somers } 4886d666775SBrian Somers 4896d666775SBrian Somers static void 4906d666775SBrian Somers datalink_LayerUp(void *v, struct fsm *fp) 4916d666775SBrian Somers { 4926d666775SBrian Somers /* The given fsm is now up */ 4936d666775SBrian Somers struct datalink *dl = (struct datalink *)v; 4945e315498SBrian Somers struct lcp *lcp = &dl->physical->link.lcp; 4956d666775SBrian Somers 49692e872e7SBrian Somers if (fp->proto == PROTO_LCP) { 497f0cdd9c0SBrian Somers datalink_GotAuthname(dl, ""); 4985e315498SBrian Somers lcp->auth_ineed = lcp->want_auth; 4995e315498SBrian Somers lcp->auth_iwait = lcp->his_auth; 5005e315498SBrian Somers if (lcp->his_auth || lcp->want_auth) { 5015945a079SBrian Somers if (bundle_Phase(dl->bundle) != PHASE_NETWORK) 5025563ebdeSBrian Somers bundle_NewPhase(dl->bundle, PHASE_AUTHENTICATE); 503dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: his = %s, mine = %s\n", dl->name, 5045e315498SBrian Somers Auth2Nam(lcp->his_auth, lcp->his_authtype), 5055e315498SBrian Somers Auth2Nam(lcp->want_auth, lcp->want_authtype)); 5065e315498SBrian Somers if (lcp->his_auth == PROTO_PAP) 507f0cdd9c0SBrian Somers auth_StartReq(&dl->pap); 5085e315498SBrian Somers if (lcp->want_auth == PROTO_CHAP) 509f0cdd9c0SBrian Somers auth_StartReq(&dl->chap.auth); 510e2ebb036SBrian Somers } else 511e2ebb036SBrian Somers datalink_AuthOk(dl); 512e2ebb036SBrian Somers } 513e2ebb036SBrian Somers } 514e2ebb036SBrian Somers 51564cfdfc6SBrian Somers static void 51664cfdfc6SBrian Somers datalink_AuthReInit(struct datalink *dl) 51764cfdfc6SBrian Somers { 51864cfdfc6SBrian Somers auth_StopTimer(&dl->pap); 51964cfdfc6SBrian Somers auth_StopTimer(&dl->chap.auth); 52064cfdfc6SBrian Somers chap_ReInit(&dl->chap); 52164cfdfc6SBrian Somers } 52264cfdfc6SBrian Somers 523e2ebb036SBrian Somers void 524f0cdd9c0SBrian Somers datalink_GotAuthname(struct datalink *dl, const char *name) 525643f4904SBrian Somers { 526f0cdd9c0SBrian Somers strncpy(dl->peer.authname, name, sizeof dl->peer.authname - 1); 527f0cdd9c0SBrian Somers dl->peer.authname[sizeof dl->peer.authname - 1] = '\0'; 528643f4904SBrian Somers } 529643f4904SBrian Somers 530643f4904SBrian Somers void 53192b09558SBrian Somers datalink_NCPUp(struct datalink *dl) 532e2ebb036SBrian Somers { 53306337856SBrian Somers int ccpok = ccp_SetOpenMode(&dl->physical->link.ccp); 5341df0a3b9SBrian Somers 535dbf60d74SBrian Somers if (dl->physical->link.lcp.want_mrru && dl->physical->link.lcp.his_mrru) { 5361fa665f5SBrian Somers /* we've authenticated in multilink mode ! */ 5371fa665f5SBrian Somers switch (mp_Up(&dl->bundle->ncp.mp, dl)) { 5381fa665f5SBrian Somers case MP_LINKSENT: 539ea722969SBrian Somers /* We've handed the link off to another ppp (well, we will soon) ! */ 5401fa665f5SBrian Somers return; 5411fa665f5SBrian Somers case MP_UP: 5420a1b5c9dSBrian Somers /* First link in the bundle */ 54392b09558SBrian Somers auth_Select(dl->bundle, dl->peer.authname); 5440a1b5c9dSBrian Somers /* fall through */ 5451fa665f5SBrian Somers case MP_ADDED: 5460a1b5c9dSBrian Somers /* We're in multilink mode ! */ 5471df0a3b9SBrian Somers dl->physical->link.ccp.fsm.open_mode = OPEN_PASSIVE; /* override */ 5481fa665f5SBrian Somers break; 5491fa665f5SBrian Somers case MP_FAILED: 55049052c95SBrian Somers datalink_AuthNotOk(dl); 55149052c95SBrian Somers return; 55249052c95SBrian Somers } 55349052c95SBrian Somers } else if (bundle_Phase(dl->bundle) == PHASE_NETWORK) { 554dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: Already in NETWORK phase\n", dl->name); 555897f9429SBrian Somers datalink_NewState(dl, DATALINK_OPEN); 556897f9429SBrian Somers (*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.lcp.fsm); 55749052c95SBrian Somers return; 55850abd4c8SBrian Somers } else { 55950abd4c8SBrian Somers dl->bundle->ncp.mp.peer = dl->peer; 560ce828a6eSBrian Somers ipcp_SetLink(&dl->bundle->ncp.ipcp, &dl->physical->link); 56192b09558SBrian Somers auth_Select(dl->bundle, dl->peer.authname); 56250abd4c8SBrian Somers } 56349052c95SBrian Somers 56406337856SBrian Somers if (ccpok) { 565dd7e2610SBrian Somers fsm_Up(&dl->physical->link.ccp.fsm); 566dd7e2610SBrian Somers fsm_Open(&dl->physical->link.ccp.fsm); 56706337856SBrian Somers } 5689ae58882SBrian Somers datalink_NewState(dl, DATALINK_OPEN); 5693b0f8d2eSBrian Somers bundle_NewPhase(dl->bundle, PHASE_NETWORK); 5703b0f8d2eSBrian Somers (*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.lcp.fsm); 5716d666775SBrian Somers } 572e2ebb036SBrian Somers 573e2ebb036SBrian Somers void 57492b09558SBrian Somers datalink_CBCPComplete(struct datalink *dl) 57592b09558SBrian Somers { 57692b09558SBrian Somers datalink_NewState(dl, DATALINK_LCP); 57764cfdfc6SBrian Somers datalink_AuthReInit(dl); 57892b09558SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 57992b09558SBrian Somers } 58092b09558SBrian Somers 58192b09558SBrian Somers void 58292b09558SBrian Somers datalink_CBCPFailed(struct datalink *dl) 58392b09558SBrian Somers { 58492b09558SBrian Somers cbcp_Down(&dl->cbcp); 58592b09558SBrian Somers datalink_CBCPComplete(dl); 58692b09558SBrian Somers } 58792b09558SBrian Somers 58892b09558SBrian Somers void 58992b09558SBrian Somers datalink_AuthOk(struct datalink *dl) 59092b09558SBrian Somers { 5915165af6fSBrian Somers if ((dl->physical->link.lcp.his_callback.opmask & 59292b09558SBrian Somers CALLBACK_BIT(CALLBACK_CBCP) || 5935165af6fSBrian Somers dl->physical->link.lcp.want_callback.opmask & 5945165af6fSBrian Somers CALLBACK_BIT(CALLBACK_CBCP)) && 5955165af6fSBrian Somers !(dl->physical->link.lcp.want_callback.opmask & 5965165af6fSBrian Somers CALLBACK_BIT(CALLBACK_AUTH))) { 5975165af6fSBrian Somers /* We must have agreed CBCP if AUTH isn't there any more */ 59892b09558SBrian Somers datalink_NewState(dl, DATALINK_CBCP); 59992b09558SBrian Somers cbcp_Up(&dl->cbcp); 60092b09558SBrian Somers } else if (dl->physical->link.lcp.want_callback.opmask) { 6015165af6fSBrian Somers /* It's not CBCP */ 60292b09558SBrian Somers log_Printf(LogPHASE, "%s: Shutdown and await peer callback\n", dl->name); 60392b09558SBrian Somers datalink_NewState(dl, DATALINK_LCP); 60464cfdfc6SBrian Somers datalink_AuthReInit(dl); 60592b09558SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 60692b09558SBrian Somers } else 60792b09558SBrian Somers switch (dl->physical->link.lcp.his_callback.opmask) { 60892b09558SBrian Somers case 0: 60992b09558SBrian Somers datalink_NCPUp(dl); 61092b09558SBrian Somers break; 61192b09558SBrian Somers 61292b09558SBrian Somers case CALLBACK_BIT(CALLBACK_AUTH): 61392b09558SBrian Somers auth_SetPhoneList(dl->peer.authname, dl->cbcp.fsm.phone, 61492b09558SBrian Somers sizeof dl->cbcp.fsm.phone); 61592b09558SBrian Somers if (*dl->cbcp.fsm.phone == '\0' || !strcmp(dl->cbcp.fsm.phone, "*")) { 61692b09558SBrian Somers log_Printf(LogPHASE, "%s: %s cannot be called back\n", dl->name, 61792b09558SBrian Somers dl->peer.authname); 61892b09558SBrian Somers *dl->cbcp.fsm.phone = '\0'; 61992b09558SBrian Somers } else { 62092b09558SBrian Somers char *ptr = strchr(dl->cbcp.fsm.phone, ','); 62192b09558SBrian Somers if (ptr) 62292b09558SBrian Somers *ptr = '\0'; /* Call back on the first number */ 62392b09558SBrian Somers log_Printf(LogPHASE, "%s: Calling peer back on %s\n", dl->name, 62492b09558SBrian Somers dl->cbcp.fsm.phone); 62592b09558SBrian Somers dl->cbcp.required = 1; 62692b09558SBrian Somers } 62792b09558SBrian Somers dl->cbcp.fsm.delay = 0; 62892b09558SBrian Somers datalink_NewState(dl, DATALINK_LCP); 62964cfdfc6SBrian Somers datalink_AuthReInit(dl); 63092b09558SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 63192b09558SBrian Somers break; 63292b09558SBrian Somers 63392b09558SBrian Somers case CALLBACK_BIT(CALLBACK_E164): 63492b09558SBrian Somers strncpy(dl->cbcp.fsm.phone, dl->physical->link.lcp.his_callback.msg, 63592b09558SBrian Somers sizeof dl->cbcp.fsm.phone - 1); 63692b09558SBrian Somers dl->cbcp.fsm.phone[sizeof dl->cbcp.fsm.phone - 1] = '\0'; 63792b09558SBrian Somers log_Printf(LogPHASE, "%s: Calling peer back on %s\n", dl->name, 63892b09558SBrian Somers dl->cbcp.fsm.phone); 63992b09558SBrian Somers dl->cbcp.required = 1; 64092b09558SBrian Somers dl->cbcp.fsm.delay = 0; 64192b09558SBrian Somers datalink_NewState(dl, DATALINK_LCP); 64264cfdfc6SBrian Somers datalink_AuthReInit(dl); 64392b09558SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 64492b09558SBrian Somers break; 64592b09558SBrian Somers 64692b09558SBrian Somers default: 64792b09558SBrian Somers log_Printf(LogPHASE, "%s: Oops - Should have NAK'd peer callback !\n", 64892b09558SBrian Somers dl->name); 64992b09558SBrian Somers datalink_NewState(dl, DATALINK_LCP); 65064cfdfc6SBrian Somers datalink_AuthReInit(dl); 65192b09558SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 65292b09558SBrian Somers break; 65392b09558SBrian Somers } 65492b09558SBrian Somers } 65592b09558SBrian Somers 65692b09558SBrian Somers void 657e2ebb036SBrian Somers datalink_AuthNotOk(struct datalink *dl) 658e2ebb036SBrian Somers { 6599ae58882SBrian Somers datalink_NewState(dl, DATALINK_LCP); 66064cfdfc6SBrian Somers datalink_AuthReInit(dl); 661dd7e2610SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 6626d666775SBrian Somers } 6636d666775SBrian Somers 6646d666775SBrian Somers static void 6656d666775SBrian Somers datalink_LayerDown(void *v, struct fsm *fp) 6666d666775SBrian Somers { 6676d666775SBrian Somers /* The given FSM has been told to come down */ 6686d666775SBrian Somers struct datalink *dl = (struct datalink *)v; 669a611cad6SBrian Somers 67092e872e7SBrian Somers if (fp->proto == PROTO_LCP) { 671e2ebb036SBrian Somers switch (dl->state) { 672e2ebb036SBrian Somers case DATALINK_OPEN: 673643f4904SBrian Somers peerid_Init(&dl->peer); 67409206a6fSBrian Somers fsm2initial(&dl->physical->link.ccp.fsm); 675ff0f9439SBrian Somers datalink_NewState(dl, DATALINK_LCP); /* before parent TLD */ 676e2ebb036SBrian Somers (*dl->parent->LayerDown)(dl->parent->object, fp); 67792b09558SBrian Somers /* fall through (just in case) */ 67892b09558SBrian Somers 67992b09558SBrian Somers case DATALINK_CBCP: 68092b09558SBrian Somers if (!dl->cbcp.required) 68192b09558SBrian Somers cbcp_Down(&dl->cbcp); 68292b09558SBrian Somers /* fall through (just in case) */ 683e2ebb036SBrian Somers 684e2ebb036SBrian Somers case DATALINK_AUTH: 685dd7e2610SBrian Somers timer_Stop(&dl->pap.authtimer); 686dd7e2610SBrian Somers timer_Stop(&dl->chap.auth.authtimer); 6876d666775SBrian Somers } 6889ae58882SBrian Somers datalink_NewState(dl, DATALINK_LCP); 68964cfdfc6SBrian Somers datalink_AuthReInit(dl); 690e2ebb036SBrian Somers } 6916d666775SBrian Somers } 6926d666775SBrian Somers 6936d666775SBrian Somers static void 6946d666775SBrian Somers datalink_LayerFinish(void *v, struct fsm *fp) 6956d666775SBrian Somers { 6966d666775SBrian Somers /* The given fsm is now down */ 6976d666775SBrian Somers struct datalink *dl = (struct datalink *)v; 6986d666775SBrian Somers 69992e872e7SBrian Somers if (fp->proto == PROTO_LCP) { 70009206a6fSBrian Somers fsm2initial(fp); 7016d666775SBrian Somers (*dl->parent->LayerFinish)(dl->parent->object, fp); 7029c81b87dSBrian Somers datalink_ComeDown(dl, CLOSE_NORMAL); 7030a1b5c9dSBrian Somers } else if (fp->state == ST_CLOSED && fp->open_mode == OPEN_PASSIVE) 7040a1b5c9dSBrian Somers fsm_Open(fp); /* CCP goes to ST_STOPPED */ 7056d666775SBrian Somers } 7066d666775SBrian Somers 7073006ec67SBrian Somers struct datalink * 7086f384573SBrian Somers datalink_Create(const char *name, struct bundle *bundle, int type) 7093006ec67SBrian Somers { 7103006ec67SBrian Somers struct datalink *dl; 7113006ec67SBrian Somers 7123006ec67SBrian Somers dl = (struct datalink *)malloc(sizeof(struct datalink)); 7133006ec67SBrian Somers if (dl == NULL) 7143006ec67SBrian Somers return dl; 7153006ec67SBrian Somers 7163006ec67SBrian Somers dl->desc.type = DATALINK_DESCRIPTOR; 7173006ec67SBrian Somers dl->desc.UpdateSet = datalink_UpdateSet; 7183006ec67SBrian Somers dl->desc.IsSet = datalink_IsSet; 7193006ec67SBrian Somers dl->desc.Read = datalink_Read; 7203006ec67SBrian Somers dl->desc.Write = datalink_Write; 7215b8b8060SBrian Somers 722e718d1d7SBrian Somers dl->state = DATALINK_CLOSED; 723e718d1d7SBrian Somers 72473a13b5cSBrian Somers *dl->cfg.script.dial = '\0'; 72573a13b5cSBrian Somers *dl->cfg.script.login = '\0'; 72673a13b5cSBrian Somers *dl->cfg.script.hangup = '\0'; 727f9545805SBrian Somers *dl->cfg.phone.list = '\0'; 728f9545805SBrian Somers *dl->phone.list = '\0'; 729f9545805SBrian Somers dl->phone.next = NULL; 730f9545805SBrian Somers dl->phone.alt = NULL; 731f9545805SBrian Somers dl->phone.chosen = "N/A"; 7329c81b87dSBrian Somers dl->stayonline = 0; 733c7cc5030SBrian Somers dl->script.run = 1; 734c7cc5030SBrian Somers dl->script.packetmode = 1; 7353b0f8d2eSBrian Somers mp_linkInit(&dl->mp); 7365b8b8060SBrian Somers 7373006ec67SBrian Somers dl->bundle = bundle; 7383006ec67SBrian Somers dl->next = NULL; 739e718d1d7SBrian Somers 740c11e57a3SBrian Somers memset(&dl->dial.timer, '\0', sizeof dl->dial.timer); 741e718d1d7SBrian Somers 742c11e57a3SBrian Somers dl->dial.tries = 0; 743565e35e5SBrian Somers dl->cfg.dial.max = 1; 744565e35e5SBrian Somers dl->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT; 745565e35e5SBrian Somers dl->cfg.dial.timeout = DIAL_TIMEOUT; 746c11e57a3SBrian Somers dl->cfg.dial.inc = 0; 747c11e57a3SBrian Somers dl->cfg.dial.maxinc = 10; 748e718d1d7SBrian Somers 749abff9baeSBrian Somers dl->reconnect_tries = 0; 750565e35e5SBrian Somers dl->cfg.reconnect.max = 0; 751565e35e5SBrian Somers dl->cfg.reconnect.timeout = RECONNECT_TIMEOUT; 752abff9baeSBrian Somers 75392b09558SBrian Somers dl->cfg.callback.opmask = 0; 75492b09558SBrian Somers dl->cfg.cbcp.delay = 0; 75592b09558SBrian Somers *dl->cfg.cbcp.phone = '\0'; 75692b09558SBrian Somers dl->cfg.cbcp.fsmretry = DEF_FSMRETRY; 75792b09558SBrian Somers 7583006ec67SBrian Somers dl->name = strdup(name); 759643f4904SBrian Somers peerid_Init(&dl->peer); 7606f384573SBrian Somers dl->parent = &bundle->fsm; 7613b0f8d2eSBrian Somers dl->fsmp.LayerStart = datalink_LayerStart; 7623b0f8d2eSBrian Somers dl->fsmp.LayerUp = datalink_LayerUp; 7633b0f8d2eSBrian Somers dl->fsmp.LayerDown = datalink_LayerDown; 7643b0f8d2eSBrian Somers dl->fsmp.LayerFinish = datalink_LayerFinish; 7653b0f8d2eSBrian Somers dl->fsmp.object = dl; 7663b0f8d2eSBrian Somers 767565e35e5SBrian Somers if ((dl->physical = modem_Create(dl, type)) == NULL) { 7683006ec67SBrian Somers free(dl->name); 7693006ec67SBrian Somers free(dl); 7703006ec67SBrian Somers return NULL; 7713006ec67SBrian Somers } 772f0cdd9c0SBrian Somers 773f0cdd9c0SBrian Somers pap_Init(&dl->pap, dl->physical); 774f0cdd9c0SBrian Somers chap_Init(&dl->chap, dl->physical); 77592b09558SBrian Somers cbcp_Init(&dl->cbcp, dl->physical); 776f9545805SBrian Somers chat_Init(&dl->chat, dl->physical, NULL, 1, NULL); 7773006ec67SBrian Somers 7789ae58882SBrian Somers log_Printf(LogPHASE, "%s: Created in %s state\n", 7799ae58882SBrian Somers dl->name, datalink_State(dl)); 7803006ec67SBrian Somers 7813006ec67SBrian Somers return dl; 7823006ec67SBrian Somers } 7833006ec67SBrian Somers 7843006ec67SBrian Somers struct datalink * 785cd7bd93aSBrian Somers datalink_Clone(struct datalink *odl, const char *name) 786cd7bd93aSBrian Somers { 787cd7bd93aSBrian Somers struct datalink *dl; 788cd7bd93aSBrian Somers 789cd7bd93aSBrian Somers dl = (struct datalink *)malloc(sizeof(struct datalink)); 790cd7bd93aSBrian Somers if (dl == NULL) 791cd7bd93aSBrian Somers return dl; 792cd7bd93aSBrian Somers 793cd7bd93aSBrian Somers dl->desc.type = DATALINK_DESCRIPTOR; 794cd7bd93aSBrian Somers dl->desc.UpdateSet = datalink_UpdateSet; 795cd7bd93aSBrian Somers dl->desc.IsSet = datalink_IsSet; 796cd7bd93aSBrian Somers dl->desc.Read = datalink_Read; 797cd7bd93aSBrian Somers dl->desc.Write = datalink_Write; 798cd7bd93aSBrian Somers 799cd7bd93aSBrian Somers dl->state = DATALINK_CLOSED; 800cd7bd93aSBrian Somers 801cd7bd93aSBrian Somers memcpy(&dl->cfg, &odl->cfg, sizeof dl->cfg); 802cd7bd93aSBrian Somers mp_linkInit(&dl->mp); 803cd7bd93aSBrian Somers *dl->phone.list = '\0'; 804643f4904SBrian Somers dl->phone.next = NULL; 805643f4904SBrian Somers dl->phone.alt = NULL; 806643f4904SBrian Somers dl->phone.chosen = "N/A"; 807cd7bd93aSBrian Somers dl->bundle = odl->bundle; 808cd7bd93aSBrian Somers dl->next = NULL; 809c11e57a3SBrian Somers memset(&dl->dial.timer, '\0', sizeof dl->dial.timer); 810c11e57a3SBrian Somers dl->dial.tries = 0; 811cd7bd93aSBrian Somers dl->reconnect_tries = 0; 812cd7bd93aSBrian Somers dl->name = strdup(name); 813643f4904SBrian Somers peerid_Init(&dl->peer); 814cd7bd93aSBrian Somers dl->parent = odl->parent; 815cd7bd93aSBrian Somers memcpy(&dl->fsmp, &odl->fsmp, sizeof dl->fsmp); 816643f4904SBrian Somers dl->fsmp.object = dl; 817cd7bd93aSBrian Somers 81881358fa3SBrian Somers if ((dl->physical = modem_Create(dl, PHYS_INTERACTIVE)) == NULL) { 819cd7bd93aSBrian Somers free(dl->name); 820cd7bd93aSBrian Somers free(dl); 821cd7bd93aSBrian Somers return NULL; 822cd7bd93aSBrian Somers } 823f0cdd9c0SBrian Somers pap_Init(&dl->pap, dl->physical); 824479508cfSBrian Somers dl->pap.cfg = odl->pap.cfg; 825f0cdd9c0SBrian Somers 826f0cdd9c0SBrian Somers chap_Init(&dl->chap, dl->physical); 827479508cfSBrian Somers dl->chap.auth.cfg = odl->chap.auth.cfg; 828f0cdd9c0SBrian Somers 829cd7bd93aSBrian Somers memcpy(&dl->physical->cfg, &odl->physical->cfg, sizeof dl->physical->cfg); 830cd7bd93aSBrian Somers memcpy(&dl->physical->link.lcp.cfg, &odl->physical->link.lcp.cfg, 831cd7bd93aSBrian Somers sizeof dl->physical->link.lcp.cfg); 832cd7bd93aSBrian Somers memcpy(&dl->physical->link.ccp.cfg, &odl->physical->link.ccp.cfg, 833cd7bd93aSBrian Somers sizeof dl->physical->link.ccp.cfg); 834cd7bd93aSBrian Somers memcpy(&dl->physical->async.cfg, &odl->physical->async.cfg, 835cd7bd93aSBrian Somers sizeof dl->physical->async.cfg); 836cd7bd93aSBrian Somers 83792b09558SBrian Somers cbcp_Init(&dl->cbcp, dl->physical); 838cd7bd93aSBrian Somers chat_Init(&dl->chat, dl->physical, NULL, 1, NULL); 839cd7bd93aSBrian Somers 8409ae58882SBrian Somers log_Printf(LogPHASE, "%s: Cloned in %s state\n", 8419ae58882SBrian Somers dl->name, datalink_State(dl)); 842cd7bd93aSBrian Somers 843cd7bd93aSBrian Somers return dl; 844cd7bd93aSBrian Somers } 845cd7bd93aSBrian Somers 846cd7bd93aSBrian Somers struct datalink * 8473006ec67SBrian Somers datalink_Destroy(struct datalink *dl) 8483006ec67SBrian Somers { 8493006ec67SBrian Somers struct datalink *result; 8503006ec67SBrian Somers 85139d94652SBrian Somers if (dl->state != DATALINK_CLOSED) { 852dd7e2610SBrian Somers log_Printf(LogERROR, "Oops, destroying a datalink in state %s\n", 853c7cc5030SBrian Somers datalink_State(dl)); 85439d94652SBrian Somers switch (dl->state) { 85539d94652SBrian Somers case DATALINK_HANGUP: 85639d94652SBrian Somers case DATALINK_DIAL: 85739d94652SBrian Somers case DATALINK_LOGIN: 85839d94652SBrian Somers chat_Destroy(&dl->chat); /* Gotta blat the timers ! */ 85939d94652SBrian Somers break; 86039d94652SBrian Somers } 86139d94652SBrian Somers } 8623006ec67SBrian Somers 863c11e57a3SBrian Somers timer_Stop(&dl->dial.timer); 8643006ec67SBrian Somers result = dl->next; 8653b0f8d2eSBrian Somers modem_Destroy(dl->physical); 8663006ec67SBrian Somers free(dl->name); 8673006ec67SBrian Somers free(dl); 8683006ec67SBrian Somers 8693006ec67SBrian Somers return result; 8703006ec67SBrian Somers } 8713006ec67SBrian Somers 8723006ec67SBrian Somers void 873c5a5a6caSBrian Somers datalink_Up(struct datalink *dl, int runscripts, int packetmode) 8743006ec67SBrian Somers { 8756f384573SBrian Somers if (dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED)) 876565e35e5SBrian Somers /* Ignore scripts */ 877565e35e5SBrian Somers runscripts = 0; 878565e35e5SBrian Somers 879c7cc5030SBrian Somers switch (dl->state) { 880c7cc5030SBrian Somers case DATALINK_CLOSED: 8813b0f8d2eSBrian Somers if (bundle_Phase(dl->bundle) == PHASE_DEAD || 8823b0f8d2eSBrian Somers bundle_Phase(dl->bundle) == PHASE_TERMINATE) 8833b0f8d2eSBrian Somers bundle_NewPhase(dl->bundle, PHASE_ESTABLISH); 8849ae58882SBrian Somers datalink_NewState(dl, DATALINK_OPENING); 885565e35e5SBrian Somers dl->reconnect_tries = 8866f384573SBrian Somers dl->physical->type == PHYS_DIRECT ? 0 : dl->cfg.reconnect.max; 887c11e57a3SBrian Somers dl->dial.tries = dl->cfg.dial.max; 888c5a5a6caSBrian Somers dl->script.run = runscripts; 889c5a5a6caSBrian Somers dl->script.packetmode = packetmode; 890c7cc5030SBrian Somers break; 891c7cc5030SBrian Somers 892c7cc5030SBrian Somers case DATALINK_OPENING: 893c7cc5030SBrian Somers if (!dl->script.run && runscripts) 894c7cc5030SBrian Somers dl->script.run = 1; 895c7cc5030SBrian Somers /* fall through */ 896c7cc5030SBrian Somers 897c7cc5030SBrian Somers case DATALINK_DIAL: 898c7cc5030SBrian Somers case DATALINK_LOGIN: 899c7cc5030SBrian Somers case DATALINK_READY: 900c7cc5030SBrian Somers if (!dl->script.packetmode && packetmode) { 901c7cc5030SBrian Somers dl->script.packetmode = 1; 902c7cc5030SBrian Somers if (dl->state == DATALINK_READY) 903c7cc5030SBrian Somers datalink_LoginDone(dl); 904c7cc5030SBrian Somers } 905c7cc5030SBrian Somers break; 9063006ec67SBrian Somers } 9073006ec67SBrian Somers } 9083006ec67SBrian Somers 9093006ec67SBrian Somers void 9109c81b87dSBrian Somers datalink_Close(struct datalink *dl, int how) 911c7cc5030SBrian Somers { 912c7cc5030SBrian Somers /* Please close */ 913e2ebb036SBrian Somers switch (dl->state) { 914e2ebb036SBrian Somers case DATALINK_OPEN: 915643f4904SBrian Somers peerid_Init(&dl->peer); 91609206a6fSBrian Somers fsm2initial(&dl->physical->link.ccp.fsm); 917e2ebb036SBrian Somers /* fall through */ 918e2ebb036SBrian Somers 91992b09558SBrian Somers case DATALINK_CBCP: 920e2ebb036SBrian Somers case DATALINK_AUTH: 921e2ebb036SBrian Somers case DATALINK_LCP: 92264cfdfc6SBrian Somers datalink_AuthReInit(dl); 923dd7e2610SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 9249c81b87dSBrian Somers if (how != CLOSE_NORMAL) { 925c11e57a3SBrian Somers dl->dial.tries = -1; 926c7cc5030SBrian Somers dl->reconnect_tries = 0; 9279c81b87dSBrian Somers if (how == CLOSE_LCP) 9289c81b87dSBrian Somers dl->stayonline = 1; 929c7cc5030SBrian Somers } 930e2ebb036SBrian Somers break; 931e2ebb036SBrian Somers 932e2ebb036SBrian Somers default: 9339c81b87dSBrian Somers datalink_ComeDown(dl, how); 934c7cc5030SBrian Somers } 935e2ebb036SBrian Somers } 936c7cc5030SBrian Somers 937c7cc5030SBrian Somers void 9389c81b87dSBrian Somers datalink_Down(struct datalink *dl, int how) 939c7cc5030SBrian Somers { 940c7cc5030SBrian Somers /* Carrier is lost */ 941e2ebb036SBrian Somers switch (dl->state) { 942e2ebb036SBrian Somers case DATALINK_OPEN: 943643f4904SBrian Somers peerid_Init(&dl->peer); 94409206a6fSBrian Somers fsm2initial(&dl->physical->link.ccp.fsm); 945e2ebb036SBrian Somers /* fall through */ 946e2ebb036SBrian Somers 94792b09558SBrian Somers case DATALINK_CBCP: 948e2ebb036SBrian Somers case DATALINK_AUTH: 949e2ebb036SBrian Somers case DATALINK_LCP: 95009206a6fSBrian Somers fsm2initial(&dl->physical->link.lcp.fsm); 951e2ebb036SBrian Somers /* fall through */ 952c7cc5030SBrian Somers 953e2ebb036SBrian Somers default: 9549c81b87dSBrian Somers datalink_ComeDown(dl, how); 955c7cc5030SBrian Somers } 956e2ebb036SBrian Somers } 957c7cc5030SBrian Somers 958c7cc5030SBrian Somers void 9593006ec67SBrian Somers datalink_StayDown(struct datalink *dl) 9603006ec67SBrian Somers { 9613006ec67SBrian Somers dl->reconnect_tries = 0; 9623006ec67SBrian Somers } 963c7cc5030SBrian Somers 9649c81b87dSBrian Somers void 9659c81b87dSBrian Somers datalink_DontHangup(struct datalink *dl) 9669c81b87dSBrian Somers { 9677729a182SBrian Somers if (dl->state >= DATALINK_LCP) 9689c81b87dSBrian Somers dl->stayonline = 1; 9699c81b87dSBrian Somers } 9709c81b87dSBrian Somers 971643f4904SBrian Somers int 972643f4904SBrian Somers datalink_Show(struct cmdargs const *arg) 973c7cc5030SBrian Somers { 974643f4904SBrian Somers prompt_Printf(arg->prompt, "Name: %s\n", arg->cx->name); 975643f4904SBrian Somers prompt_Printf(arg->prompt, " State: %s\n", 976643f4904SBrian Somers datalink_State(arg->cx)); 977643f4904SBrian Somers prompt_Printf(arg->prompt, " Peer name: "); 978643f4904SBrian Somers if (*arg->cx->peer.authname) 979643f4904SBrian Somers prompt_Printf(arg->prompt, "%s\n", arg->cx->peer.authname); 980643f4904SBrian Somers else if (arg->cx->state == DATALINK_OPEN) 981643f4904SBrian Somers prompt_Printf(arg->prompt, "None requested\n"); 982565e35e5SBrian Somers else 983643f4904SBrian Somers prompt_Printf(arg->prompt, "N/A\n"); 984643f4904SBrian Somers prompt_Printf(arg->prompt, " Discriminator: %s\n", 985643f4904SBrian Somers mp_Enddisc(arg->cx->peer.enddisc.class, 986643f4904SBrian Somers arg->cx->peer.enddisc.address, 987643f4904SBrian Somers arg->cx->peer.enddisc.len)); 988643f4904SBrian Somers 989643f4904SBrian Somers prompt_Printf(arg->prompt, "\nDefaults:\n"); 990643f4904SBrian Somers prompt_Printf(arg->prompt, " Phone List: %s\n", 991643f4904SBrian Somers arg->cx->cfg.phone.list); 992643f4904SBrian Somers if (arg->cx->cfg.dial.max) 993643f4904SBrian Somers prompt_Printf(arg->prompt, " Dial tries: %d, delay ", 994643f4904SBrian Somers arg->cx->cfg.dial.max); 995565e35e5SBrian Somers else 996643f4904SBrian Somers prompt_Printf(arg->prompt, " Dial tries: infinite, delay "); 997b5c347a3SBrian Somers if (arg->cx->cfg.dial.next_timeout >= 0) 998643f4904SBrian Somers prompt_Printf(arg->prompt, "%ds/", arg->cx->cfg.dial.next_timeout); 999565e35e5SBrian Somers else 1000643f4904SBrian Somers prompt_Printf(arg->prompt, "random/"); 1001b5c347a3SBrian Somers if (arg->cx->cfg.dial.timeout >= 0) 1002643f4904SBrian Somers prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.dial.timeout); 1003565e35e5SBrian Somers else 1004643f4904SBrian Somers prompt_Printf(arg->prompt, "random\n"); 1005643f4904SBrian Somers prompt_Printf(arg->prompt, " Reconnect tries: %d, delay ", 1006643f4904SBrian Somers arg->cx->cfg.reconnect.max); 1007643f4904SBrian Somers if (arg->cx->cfg.reconnect.timeout > 0) 1008643f4904SBrian Somers prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.reconnect.timeout); 1009643f4904SBrian Somers else 1010643f4904SBrian Somers prompt_Printf(arg->prompt, "random\n"); 101192b09558SBrian Somers prompt_Printf(arg->prompt, " Callback %s ", arg->cx->physical->type == 101292b09558SBrian Somers PHYS_DIRECT ? "accepted: " : "requested:"); 101392b09558SBrian Somers if (!arg->cx->cfg.callback.opmask) 101492b09558SBrian Somers prompt_Printf(arg->prompt, "none\n"); 101592b09558SBrian Somers else { 101692b09558SBrian Somers int comma = 0; 101792b09558SBrian Somers 101892b09558SBrian Somers if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_NONE)) { 101992b09558SBrian Somers prompt_Printf(arg->prompt, "none"); 102092b09558SBrian Somers comma = 1; 102192b09558SBrian Somers } 102292b09558SBrian Somers if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_AUTH)) { 102392b09558SBrian Somers prompt_Printf(arg->prompt, "%sauth", comma ? ", " : ""); 102492b09558SBrian Somers comma = 1; 102592b09558SBrian Somers } 102692b09558SBrian Somers if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_E164)) { 102792b09558SBrian Somers prompt_Printf(arg->prompt, "%sE.164", comma ? ", " : ""); 102892b09558SBrian Somers if (arg->cx->physical->type != PHYS_DIRECT) 102992b09558SBrian Somers prompt_Printf(arg->prompt, " (%s)", arg->cx->cfg.callback.msg); 103092b09558SBrian Somers comma = 1; 103192b09558SBrian Somers } 103292b09558SBrian Somers if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_CBCP)) { 103392b09558SBrian Somers prompt_Printf(arg->prompt, "%scbcp\n", comma ? ", " : ""); 103492b09558SBrian Somers prompt_Printf(arg->prompt, " CBCP: delay: %ds\n", 103592b09558SBrian Somers arg->cx->cfg.cbcp.delay); 1036cf784a89SBrian Somers prompt_Printf(arg->prompt, " phone: "); 1037cf784a89SBrian Somers if (!strcmp(arg->cx->cfg.cbcp.phone, "*")) { 1038cf784a89SBrian Somers if (arg->cx->physical->type & PHYS_DIRECT) 1039cf784a89SBrian Somers prompt_Printf(arg->prompt, "Caller decides\n"); 1040cf784a89SBrian Somers else 1041cf784a89SBrian Somers prompt_Printf(arg->prompt, "Dialback server decides\n"); 1042cf784a89SBrian Somers } else 1043cf784a89SBrian Somers prompt_Printf(arg->prompt, "%s\n", arg->cx->cfg.cbcp.phone); 104492b09558SBrian Somers prompt_Printf(arg->prompt, " timeout: %lds\n", 104592b09558SBrian Somers arg->cx->cfg.cbcp.fsmretry); 104692b09558SBrian Somers } else 104792b09558SBrian Somers prompt_Printf(arg->prompt, "\n"); 104892b09558SBrian Somers } 104992b09558SBrian Somers 1050643f4904SBrian Somers prompt_Printf(arg->prompt, " Dial Script: %s\n", 1051643f4904SBrian Somers arg->cx->cfg.script.dial); 1052643f4904SBrian Somers prompt_Printf(arg->prompt, " Login Script: %s\n", 1053643f4904SBrian Somers arg->cx->cfg.script.login); 1054643f4904SBrian Somers prompt_Printf(arg->prompt, " Hangup Script: %s\n", 1055643f4904SBrian Somers arg->cx->cfg.script.hangup); 1056643f4904SBrian Somers return 0; 1057565e35e5SBrian Somers } 1058565e35e5SBrian Somers 1059565e35e5SBrian Somers int 1060565e35e5SBrian Somers datalink_SetReconnect(struct cmdargs const *arg) 1061565e35e5SBrian Somers { 106225092092SBrian Somers if (arg->argc == arg->argn+2) { 106325092092SBrian Somers arg->cx->cfg.reconnect.timeout = atoi(arg->argv[arg->argn]); 106425092092SBrian Somers arg->cx->cfg.reconnect.max = atoi(arg->argv[arg->argn+1]); 1065565e35e5SBrian Somers return 0; 1066565e35e5SBrian Somers } 1067565e35e5SBrian Somers return -1; 1068565e35e5SBrian Somers } 1069565e35e5SBrian Somers 1070565e35e5SBrian Somers int 1071565e35e5SBrian Somers datalink_SetRedial(struct cmdargs const *arg) 1072565e35e5SBrian Somers { 1073c11e57a3SBrian Somers const char *sep, *osep; 1074c11e57a3SBrian Somers int timeout, inc, maxinc, tries; 1075565e35e5SBrian Somers 107625092092SBrian Somers if (arg->argc == arg->argn+1 || arg->argc == arg->argn+2) { 107725092092SBrian Somers if (strncasecmp(arg->argv[arg->argn], "random", 6) == 0 && 107825092092SBrian Somers (arg->argv[arg->argn][6] == '\0' || arg->argv[arg->argn][6] == '.')) { 1079565e35e5SBrian Somers arg->cx->cfg.dial.timeout = -1; 1080565e35e5SBrian Somers randinit(); 1081565e35e5SBrian Somers } else { 108225092092SBrian Somers timeout = atoi(arg->argv[arg->argn]); 1083565e35e5SBrian Somers 1084565e35e5SBrian Somers if (timeout >= 0) 1085565e35e5SBrian Somers arg->cx->cfg.dial.timeout = timeout; 1086565e35e5SBrian Somers else { 1087dd7e2610SBrian Somers log_Printf(LogWARN, "Invalid redial timeout\n"); 1088565e35e5SBrian Somers return -1; 1089565e35e5SBrian Somers } 1090565e35e5SBrian Somers } 1091565e35e5SBrian Somers 1092c11e57a3SBrian Somers sep = strchr(arg->argv[arg->argn], '+'); 1093c11e57a3SBrian Somers if (sep) { 1094c11e57a3SBrian Somers inc = atoi(++sep); 1095c11e57a3SBrian Somers osep = sep; 1096c11e57a3SBrian Somers if (inc >= 0) 1097c11e57a3SBrian Somers arg->cx->cfg.dial.inc = inc; 1098c11e57a3SBrian Somers else { 1099c11e57a3SBrian Somers log_Printf(LogWARN, "Invalid timeout increment\n"); 1100c11e57a3SBrian Somers return -1; 1101c11e57a3SBrian Somers } 1102c11e57a3SBrian Somers sep = strchr(sep, '-'); 1103c11e57a3SBrian Somers if (sep) { 1104c11e57a3SBrian Somers maxinc = atoi(++sep); 1105c11e57a3SBrian Somers if (maxinc >= 0) 1106c11e57a3SBrian Somers arg->cx->cfg.dial.maxinc = maxinc; 1107c11e57a3SBrian Somers else { 1108c11e57a3SBrian Somers log_Printf(LogWARN, "Invalid maximum timeout increments\n"); 1109c11e57a3SBrian Somers return -1; 1110c11e57a3SBrian Somers } 1111c11e57a3SBrian Somers } else { 1112c11e57a3SBrian Somers /* Default timeout increment */ 1113c11e57a3SBrian Somers arg->cx->cfg.dial.maxinc = 10; 1114c11e57a3SBrian Somers sep = osep; 1115c11e57a3SBrian Somers } 1116c11e57a3SBrian Somers } else { 1117c11e57a3SBrian Somers /* Default timeout increment & max increment */ 1118c11e57a3SBrian Somers arg->cx->cfg.dial.inc = 0; 1119c11e57a3SBrian Somers arg->cx->cfg.dial.maxinc = 10; 1120c11e57a3SBrian Somers sep = arg->argv[arg->argn]; 1121c11e57a3SBrian Somers } 1122c11e57a3SBrian Somers 1123c11e57a3SBrian Somers sep = strchr(sep, '.'); 1124c11e57a3SBrian Somers if (sep) { 1125c11e57a3SBrian Somers if (strcasecmp(++sep, "random") == 0) { 1126565e35e5SBrian Somers arg->cx->cfg.dial.next_timeout = -1; 1127565e35e5SBrian Somers randinit(); 1128565e35e5SBrian Somers } else { 1129c11e57a3SBrian Somers timeout = atoi(sep); 1130565e35e5SBrian Somers if (timeout >= 0) 1131565e35e5SBrian Somers arg->cx->cfg.dial.next_timeout = timeout; 1132565e35e5SBrian Somers else { 1133dd7e2610SBrian Somers log_Printf(LogWARN, "Invalid next redial timeout\n"); 1134565e35e5SBrian Somers return -1; 1135565e35e5SBrian Somers } 1136565e35e5SBrian Somers } 1137565e35e5SBrian Somers } else 1138565e35e5SBrian Somers /* Default next timeout */ 1139565e35e5SBrian Somers arg->cx->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT; 1140565e35e5SBrian Somers 114125092092SBrian Somers if (arg->argc == arg->argn+2) { 114225092092SBrian Somers tries = atoi(arg->argv[arg->argn+1]); 1143565e35e5SBrian Somers 1144565e35e5SBrian Somers if (tries >= 0) { 1145565e35e5SBrian Somers arg->cx->cfg.dial.max = tries; 1146565e35e5SBrian Somers } else { 1147dd7e2610SBrian Somers log_Printf(LogWARN, "Invalid retry value\n"); 1148565e35e5SBrian Somers return 1; 1149565e35e5SBrian Somers } 1150565e35e5SBrian Somers } 1151565e35e5SBrian Somers return 0; 1152565e35e5SBrian Somers } 1153c11e57a3SBrian Somers 1154565e35e5SBrian Somers return -1; 1155c7cc5030SBrian Somers } 1156c7cc5030SBrian Somers 1157cdbbb6b5SBrian Somers static const char *states[] = { 1158565e35e5SBrian Somers "closed", 1159565e35e5SBrian Somers "opening", 1160565e35e5SBrian Somers "hangup", 1161565e35e5SBrian Somers "dial", 1162565e35e5SBrian Somers "login", 1163565e35e5SBrian Somers "ready", 1164565e35e5SBrian Somers "lcp", 1165565e35e5SBrian Somers "auth", 116692b09558SBrian Somers "cbcp", 1167565e35e5SBrian Somers "open" 1168c7cc5030SBrian Somers }; 1169c7cc5030SBrian Somers 1170643f4904SBrian Somers const char * 1171c7cc5030SBrian Somers datalink_State(struct datalink *dl) 1172c7cc5030SBrian Somers { 1173c7cc5030SBrian Somers if (dl->state < 0 || dl->state >= sizeof states / sizeof states[0]) 1174c7cc5030SBrian Somers return "unknown"; 1175c7cc5030SBrian Somers return states[dl->state]; 1176c7cc5030SBrian Somers } 11776f384573SBrian Somers 11789ae58882SBrian Somers static void 11799ae58882SBrian Somers datalink_NewState(struct datalink *dl, int state) 11809ae58882SBrian Somers { 11819ae58882SBrian Somers if (state != dl->state) { 11829ae58882SBrian Somers if (state >= 0 && state < sizeof states / sizeof states[0]) { 11839ae58882SBrian Somers log_Printf(LogPHASE, "%s: %s -> %s\n", dl->name, datalink_State(dl), 11849ae58882SBrian Somers states[state]); 11859ae58882SBrian Somers dl->state = state; 11869ae58882SBrian Somers } else 11879ae58882SBrian Somers log_Printf(LogERROR, "%s: Can't enter state %d !\n", dl->name, state); 11889ae58882SBrian Somers } 11899ae58882SBrian Somers } 11909ae58882SBrian Somers 11916f384573SBrian Somers struct datalink * 119296c9bb21SBrian Somers iov2datalink(struct bundle *bundle, struct iovec *iov, int *niov, int maxiov, 119396c9bb21SBrian Somers int fd) 11946f384573SBrian Somers { 1195b7c5748eSBrian Somers struct datalink *dl, *cdl; 1196479508cfSBrian Somers struct fsm_retry copy; 1197b7c5748eSBrian Somers char *oname; 11986f384573SBrian Somers 119996c9bb21SBrian Somers dl = (struct datalink *)iov[(*niov)++].iov_base; 120096c9bb21SBrian Somers dl->name = iov[*niov].iov_base; 12016f384573SBrian Somers 120296c9bb21SBrian Somers if (dl->name[DATALINK_MAXNAME-1]) { 120396c9bb21SBrian Somers dl->name[DATALINK_MAXNAME-1] = '\0'; 120496c9bb21SBrian Somers if (strlen(dl->name) == DATALINK_MAXNAME - 1) 120596c9bb21SBrian Somers log_Printf(LogWARN, "Datalink name truncated to \"%s\"\n", dl->name); 12066f384573SBrian Somers } 1207b7c5748eSBrian Somers 1208b7c5748eSBrian Somers /* Make sure the name is unique ! */ 1209b7c5748eSBrian Somers oname = NULL; 1210b7c5748eSBrian Somers do { 1211b7c5748eSBrian Somers for (cdl = bundle->links; cdl; cdl = cdl->next) 1212b7c5748eSBrian Somers if (!strcasecmp(dl->name, cdl->name)) { 1213b7c5748eSBrian Somers if (oname) 1214b7c5748eSBrian Somers free(datalink_NextName(dl)); 1215b7c5748eSBrian Somers else 1216b7c5748eSBrian Somers oname = datalink_NextName(dl); 1217b7c5748eSBrian Somers break; /* Keep renaming 'till we have no conflicts */ 1218b7c5748eSBrian Somers } 1219b7c5748eSBrian Somers } while (cdl); 1220b7c5748eSBrian Somers 1221b7c5748eSBrian Somers if (oname) { 1222b7c5748eSBrian Somers log_Printf(LogPHASE, "Rename link %s to %s\n", oname, dl->name); 1223b7c5748eSBrian Somers free(oname); 1224b7c5748eSBrian Somers } else { 122596c9bb21SBrian Somers dl->name = strdup(dl->name); 1226b7c5748eSBrian Somers free(iov[*niov].iov_base); 1227b7c5748eSBrian Somers } 1228b7c5748eSBrian Somers (*niov)++; 12296f384573SBrian Somers 12306f384573SBrian Somers dl->desc.type = DATALINK_DESCRIPTOR; 12316f384573SBrian Somers dl->desc.UpdateSet = datalink_UpdateSet; 12326f384573SBrian Somers dl->desc.IsSet = datalink_IsSet; 12336f384573SBrian Somers dl->desc.Read = datalink_Read; 12346f384573SBrian Somers dl->desc.Write = datalink_Write; 12356f384573SBrian Somers 12366f384573SBrian Somers mp_linkInit(&dl->mp); 12376f384573SBrian Somers *dl->phone.list = '\0'; 12386f384573SBrian Somers dl->phone.next = NULL; 12396f384573SBrian Somers dl->phone.alt = NULL; 12406f384573SBrian Somers dl->phone.chosen = "N/A"; 12416f384573SBrian Somers 12426f384573SBrian Somers dl->bundle = bundle; 12436f384573SBrian Somers dl->next = NULL; 1244c11e57a3SBrian Somers memset(&dl->dial.timer, '\0', sizeof dl->dial.timer); 1245c11e57a3SBrian Somers dl->dial.tries = 0; 12466f384573SBrian Somers dl->reconnect_tries = 0; 12476f384573SBrian Somers dl->parent = &bundle->fsm; 12486f384573SBrian Somers dl->fsmp.LayerStart = datalink_LayerStart; 12496f384573SBrian Somers dl->fsmp.LayerUp = datalink_LayerUp; 12506f384573SBrian Somers dl->fsmp.LayerDown = datalink_LayerDown; 12516f384573SBrian Somers dl->fsmp.LayerFinish = datalink_LayerFinish; 12526f384573SBrian Somers dl->fsmp.object = dl; 12536f384573SBrian Somers 125496c9bb21SBrian Somers dl->physical = iov2modem(dl, iov, niov, maxiov, fd); 125596c9bb21SBrian Somers 125696c9bb21SBrian Somers if (!dl->physical) { 12576f384573SBrian Somers free(dl->name); 12586f384573SBrian Somers free(dl); 12596f384573SBrian Somers dl = NULL; 12609ae58882SBrian Somers } else { 1261479508cfSBrian Somers copy = dl->pap.cfg.fsm; 1262f0cdd9c0SBrian Somers pap_Init(&dl->pap, dl->physical); 1263479508cfSBrian Somers dl->pap.cfg.fsm = copy; 1264f0cdd9c0SBrian Somers 1265479508cfSBrian Somers copy = dl->chap.auth.cfg.fsm; 1266f0cdd9c0SBrian Somers chap_Init(&dl->chap, dl->physical); 1267479508cfSBrian Somers dl->chap.auth.cfg.fsm = copy; 1268f0cdd9c0SBrian Somers 126992b09558SBrian Somers cbcp_Init(&dl->cbcp, dl->physical); 12706f384573SBrian Somers chat_Init(&dl->chat, dl->physical, NULL, 1, NULL); 12716f384573SBrian Somers 12729ae58882SBrian Somers log_Printf(LogPHASE, "%s: Transferred in %s state\n", 12739ae58882SBrian Somers dl->name, datalink_State(dl)); 12749ae58882SBrian Somers } 12759ae58882SBrian Somers 12766f384573SBrian Somers return dl; 12776f384573SBrian Somers } 12786f384573SBrian Somers 12796f384573SBrian Somers int 128085fd273aSBrian Somers datalink2iov(struct datalink *dl, struct iovec *iov, int *niov, int maxiov, 128185fd273aSBrian Somers pid_t newpid) 12826f384573SBrian Somers { 128396c9bb21SBrian Somers /* If `dl' is NULL, we're allocating before a Fromiov() */ 128496c9bb21SBrian Somers int link_fd; 12856f384573SBrian Somers 128696c9bb21SBrian Somers if (dl) { 1287c11e57a3SBrian Somers timer_Stop(&dl->dial.timer); 128892b09558SBrian Somers /* The following is purely for the sake of paranoia */ 128992b09558SBrian Somers cbcp_Down(&dl->cbcp); 1290dd7e2610SBrian Somers timer_Stop(&dl->pap.authtimer); 1291dd7e2610SBrian Somers timer_Stop(&dl->chap.auth.authtimer); 12926f384573SBrian Somers } 12936f384573SBrian Somers 129496c9bb21SBrian Somers if (*niov >= maxiov - 1) { 129596c9bb21SBrian Somers log_Printf(LogERROR, "Toiov: No room for datalink !\n"); 129696c9bb21SBrian Somers if (dl) { 12976f384573SBrian Somers free(dl->name); 12986f384573SBrian Somers free(dl); 129996c9bb21SBrian Somers } 130096c9bb21SBrian Somers return -1; 130196c9bb21SBrian Somers } 130296c9bb21SBrian Somers 130396c9bb21SBrian Somers iov[*niov].iov_base = dl ? dl : malloc(sizeof *dl); 130496c9bb21SBrian Somers iov[(*niov)++].iov_len = sizeof *dl; 130596c9bb21SBrian Somers iov[*niov].iov_base = 130696c9bb21SBrian Somers dl ? realloc(dl->name, DATALINK_MAXNAME) : malloc(DATALINK_MAXNAME); 130796c9bb21SBrian Somers iov[(*niov)++].iov_len = DATALINK_MAXNAME; 130896c9bb21SBrian Somers 130985fd273aSBrian Somers link_fd = modem2iov(dl ? dl->physical : NULL, iov, niov, maxiov, newpid); 131096c9bb21SBrian Somers 131196c9bb21SBrian Somers if (link_fd == -1 && dl) { 131296c9bb21SBrian Somers free(dl->name); 131396c9bb21SBrian Somers free(dl); 131496c9bb21SBrian Somers } 13156f384573SBrian Somers 13166f384573SBrian Somers return link_fd; 13176f384573SBrian Somers } 13186f384573SBrian Somers 131958d55334SBrian Somers void 132058d55334SBrian Somers datalink_Rename(struct datalink *dl, const char *name) 132158d55334SBrian Somers { 132258d55334SBrian Somers free(dl->name); 132358d55334SBrian Somers dl->physical->link.name = dl->name = strdup(name); 132458d55334SBrian Somers } 132558d55334SBrian Somers 132684917b87SBrian Somers char * 132784917b87SBrian Somers datalink_NextName(struct datalink *dl) 13286f384573SBrian Somers { 13296f384573SBrian Somers int f, n; 133084917b87SBrian Somers char *name, *oname; 13316f384573SBrian Somers 13326f384573SBrian Somers n = strlen(dl->name); 13336f384573SBrian Somers name = (char *)malloc(n+3); 13346f384573SBrian Somers for (f = n - 1; f >= 0; f--) 13356f384573SBrian Somers if (!isdigit(dl->name[f])) 13366f384573SBrian Somers break; 13376f384573SBrian Somers n = sprintf(name, "%.*s-", dl->name[f] == '-' ? f : f + 1, dl->name); 13386f384573SBrian Somers sprintf(name + n, "%d", atoi(dl->name + f + 1) + 1); 133984917b87SBrian Somers oname = dl->name; 134054cd8e13SBrian Somers dl->name = name; 134154cd8e13SBrian Somers /* our physical link name isn't updated (it probably isn't created yet) */ 134284917b87SBrian Somers return oname; 13436f384573SBrian Somers } 1344dd0645c5SBrian Somers 1345dd0645c5SBrian Somers int 1346dd0645c5SBrian Somers datalink_SetMode(struct datalink *dl, int mode) 1347dd0645c5SBrian Somers { 1348dd0645c5SBrian Somers if (!physical_SetMode(dl->physical, mode)) 1349dd0645c5SBrian Somers return 0; 1350dd0645c5SBrian Somers if (dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED)) 1351dd0645c5SBrian Somers dl->script.run = 0; 1352dd0645c5SBrian Somers if (dl->physical->type == PHYS_DIRECT) 1353dd0645c5SBrian Somers dl->reconnect_tries = 0; 135481358fa3SBrian Somers if (mode & (PHYS_DDIAL|PHYS_BACKGROUND) && dl->state <= DATALINK_READY) 1355dd0645c5SBrian Somers datalink_Up(dl, 1, 1); 1356dd0645c5SBrian Somers return 1; 1357dd0645c5SBrian Somers } 1358c11e57a3SBrian Somers 1359c11e57a3SBrian Somers int 1360c11e57a3SBrian Somers datalink_GetDialTimeout(struct datalink *dl) 1361c11e57a3SBrian Somers { 1362c11e57a3SBrian Somers int result = dl->cfg.dial.timeout + dl->dial.incs * dl->cfg.dial.inc; 1363c11e57a3SBrian Somers 1364c11e57a3SBrian Somers if (dl->dial.incs < dl->cfg.dial.maxinc) 1365c11e57a3SBrian Somers dl->dial.incs++; 1366c11e57a3SBrian Somers 1367c11e57a3SBrian Somers return result; 1368c11e57a3SBrian Somers } 1369