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 * 265945a079SBrian Somers * $Id: datalink.c,v 1.35 1999/03/04 17:42:15 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); 14792b09558SBrian Somers } else if (dl->bundle->CleaningUp || 1486f384573SBrian Somers (dl->physical->type == PHYS_DIRECT) || 149c11e57a3SBrian Somers ((!dl->dial.tries || (dl->dial.tries < 0 && !dl->reconnect_tries)) && 15081358fa3SBrian Somers !(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)))) { 1519ae58882SBrian Somers datalink_NewState(dl, DATALINK_CLOSED); 152c11e57a3SBrian Somers dl->dial.tries = -1; 153c11e57a3SBrian Somers dl->dial.incs = 0; 1543006ec67SBrian Somers dl->reconnect_tries = 0; 1553006ec67SBrian Somers bundle_LinkClosed(dl->bundle, dl); 1563b0f8d2eSBrian Somers if (!dl->bundle->CleaningUp) 157c11e57a3SBrian Somers datalink_StartDialTimer(dl, datalink_GetDialTimeout(dl)); 1583006ec67SBrian Somers } else { 1599ae58882SBrian Somers datalink_NewState(dl, DATALINK_OPENING); 160c11e57a3SBrian Somers if (dl->dial.tries < 0) { 161565e35e5SBrian Somers datalink_StartDialTimer(dl, dl->cfg.reconnect.timeout); 162c11e57a3SBrian Somers dl->dial.tries = dl->cfg.dial.max; 163c11e57a3SBrian Somers dl->dial.incs = 0; 164abff9baeSBrian Somers dl->reconnect_tries--; 165abff9baeSBrian Somers } else { 166f9545805SBrian Somers if (dl->phone.next == NULL) 167c11e57a3SBrian Somers datalink_StartDialTimer(dl, datalink_GetDialTimeout(dl)); 1683006ec67SBrian Somers else 169565e35e5SBrian Somers datalink_StartDialTimer(dl, dl->cfg.dial.next_timeout); 1703006ec67SBrian Somers } 171abff9baeSBrian Somers } 172abff9baeSBrian Somers } 1733006ec67SBrian Somers 174f9545805SBrian Somers static const char * 175f9545805SBrian Somers datalink_ChoosePhoneNumber(struct datalink *dl) 176f9545805SBrian Somers { 177f9545805SBrian Somers char *phone; 178f9545805SBrian Somers 179f9545805SBrian Somers if (dl->phone.alt == NULL) { 180f9545805SBrian Somers if (dl->phone.next == NULL) { 181f9545805SBrian Somers strncpy(dl->phone.list, dl->cfg.phone.list, sizeof dl->phone.list - 1); 182f9545805SBrian Somers dl->phone.list[sizeof dl->phone.list - 1] = '\0'; 183f9545805SBrian Somers dl->phone.next = dl->phone.list; 184f9545805SBrian Somers } 185f9545805SBrian Somers dl->phone.alt = strsep(&dl->phone.next, ":"); 186f9545805SBrian Somers } 187f9545805SBrian Somers phone = strsep(&dl->phone.alt, "|"); 188f9545805SBrian Somers dl->phone.chosen = *phone ? phone : "[NONE]"; 189f9545805SBrian Somers if (*phone) 190dd7e2610SBrian Somers log_Printf(LogPHASE, "Phone: %s\n", phone); 191f9545805SBrian Somers return phone; 192f9545805SBrian Somers } 193f9545805SBrian Somers 194c5a5a6caSBrian Somers static void 195c5a5a6caSBrian Somers datalink_LoginDone(struct datalink *dl) 196c5a5a6caSBrian Somers { 197d345321bSBrian Somers if (!dl->script.packetmode) { 198c11e57a3SBrian Somers dl->dial.tries = -1; 199c11e57a3SBrian Somers dl->dial.incs = 0; 2009ae58882SBrian Somers datalink_NewState(dl, DATALINK_READY); 201d345321bSBrian Somers } else if (modem_Raw(dl->physical, dl->bundle) < 0) { 202c11e57a3SBrian Somers dl->dial.tries = 0; 203dd7e2610SBrian Somers log_Printf(LogWARN, "datalink_LoginDone: Not connected.\n"); 204c5a5a6caSBrian Somers if (dl->script.run) { 2059ae58882SBrian Somers datalink_NewState(dl, DATALINK_HANGUP); 206c5a5a6caSBrian Somers modem_Offline(dl->physical); 207f9545805SBrian Somers chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL); 208030e4ebbSBrian Somers } else { 209d4af231cSBrian Somers timer_Stop(&dl->physical->Timer); 210030e4ebbSBrian Somers if (dl->physical->type == PHYS_DEDICATED) 211030e4ebbSBrian Somers /* force a redial timeout */ 212030e4ebbSBrian Somers modem_Close(dl->physical); 213c5a5a6caSBrian Somers datalink_HangupDone(dl); 214030e4ebbSBrian Somers } 215c5a5a6caSBrian Somers } else { 216c11e57a3SBrian Somers dl->dial.tries = -1; 217c11e57a3SBrian Somers dl->dial.incs = 0; 218c7cc5030SBrian Somers 219643f4904SBrian Somers hdlc_Init(&dl->physical->hdlc, &dl->physical->link.lcp); 2203b0f8d2eSBrian Somers async_Init(&dl->physical->async); 2213b0f8d2eSBrian Somers 222cd9647a1SBrian Somers lcp_Setup(&dl->physical->link.lcp, dl->state == DATALINK_READY ? 223cd9647a1SBrian Somers 0 : dl->physical->link.lcp.cfg.openmode); 2243b0f8d2eSBrian Somers ccp_Setup(&dl->physical->link.ccp); 225503a7782SBrian Somers 2269ae58882SBrian Somers datalink_NewState(dl, DATALINK_LCP); 227dd7e2610SBrian Somers fsm_Up(&dl->physical->link.lcp.fsm); 228dd7e2610SBrian Somers fsm_Open(&dl->physical->link.lcp.fsm); 229c5a5a6caSBrian Somers } 230c5a5a6caSBrian Somers } 231c5a5a6caSBrian Somers 2323006ec67SBrian Somers static int 2333006ec67SBrian Somers datalink_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e, 2343006ec67SBrian Somers int *n) 2353006ec67SBrian Somers { 2363006ec67SBrian Somers struct datalink *dl = descriptor2datalink(d); 2373006ec67SBrian Somers int result; 2383006ec67SBrian Somers 239310c3babSBrian Somers result = 0; 2403006ec67SBrian Somers switch (dl->state) { 2413006ec67SBrian Somers case DATALINK_CLOSED: 24281358fa3SBrian Somers if ((dl->physical->type & 24381358fa3SBrian Somers (PHYS_DIRECT|PHYS_DEDICATED|PHYS_BACKGROUND|PHYS_DDIAL)) && 244565e35e5SBrian Somers !bundle_IsDead(dl->bundle)) 245565e35e5SBrian Somers /* 24681358fa3SBrian Somers * Our first time in - DEDICATED & DDIAL never come down, and 24781358fa3SBrian Somers * DIRECT & BACKGROUND get deleted when they enter DATALINK_CLOSED. 24881358fa3SBrian Somers * Go to DATALINK_OPENING via datalink_Up() and fall through. 249565e35e5SBrian Somers */ 250565e35e5SBrian Somers datalink_Up(dl, 1, 1); 251565e35e5SBrian Somers else 252310c3babSBrian Somers break; 253565e35e5SBrian Somers /* fall through */ 2543006ec67SBrian Somers 2553006ec67SBrian Somers case DATALINK_OPENING: 256c11e57a3SBrian Somers if (dl->dial.timer.state != TIMER_RUNNING) { 257c11e57a3SBrian Somers if (--dl->dial.tries < 0) 258c11e57a3SBrian Somers dl->dial.tries = 0; 2593006ec67SBrian Somers if (modem_Open(dl->physical, dl->bundle) >= 0) { 260bf1d3ff6SBrian Somers log_WritePrompts(dl, "%s: Entering terminal mode on %s\r\n" 261bf1d3ff6SBrian Somers "Type `~?' for help\r\n", dl->name, 262bf1d3ff6SBrian Somers dl->physical->name.full); 263c5a5a6caSBrian Somers if (dl->script.run) { 2649ae58882SBrian Somers datalink_NewState(dl, DATALINK_DIAL); 265f9545805SBrian Somers chat_Init(&dl->chat, dl->physical, dl->cfg.script.dial, 1, 266f9545805SBrian Somers datalink_ChoosePhoneNumber(dl)); 26781358fa3SBrian Somers if (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) && 268565e35e5SBrian Somers dl->cfg.dial.max) 269dd7e2610SBrian Somers log_Printf(LogCHAT, "%s: Dial attempt %u of %d\n", 270c11e57a3SBrian Somers dl->name, dl->cfg.dial.max - dl->dial.tries, 271565e35e5SBrian Somers dl->cfg.dial.max); 272c5a5a6caSBrian Somers } else 273c5a5a6caSBrian Somers datalink_LoginDone(dl); 2748b09cf1cSBrian Somers return datalink_UpdateSet(d, r, w, e, n); 2753006ec67SBrian Somers } else { 27681358fa3SBrian Somers if (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) && 277565e35e5SBrian Somers dl->cfg.dial.max) 278dd7e2610SBrian Somers log_Printf(LogCHAT, "Failed to open modem (attempt %u of %d)\n", 279c11e57a3SBrian Somers dl->cfg.dial.max - dl->dial.tries, dl->cfg.dial.max); 2803006ec67SBrian Somers else 281dd7e2610SBrian Somers log_Printf(LogCHAT, "Failed to open modem\n"); 2823006ec67SBrian Somers 2833b0f8d2eSBrian Somers if (dl->bundle->CleaningUp || 28481358fa3SBrian Somers (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) && 285c11e57a3SBrian Somers dl->cfg.dial.max && dl->dial.tries == 0)) { 2869ae58882SBrian Somers datalink_NewState(dl, DATALINK_CLOSED); 2873006ec67SBrian Somers dl->reconnect_tries = 0; 288c11e57a3SBrian Somers dl->dial.tries = -1; 289bf1d3ff6SBrian Somers log_WritePrompts(dl, "Failed to open %s\n", 290bf1d3ff6SBrian Somers dl->physical->name.full); 2915b8b8060SBrian Somers bundle_LinkClosed(dl->bundle, dl); 292c5a5a6caSBrian Somers } 293bf1d3ff6SBrian Somers if (!dl->bundle->CleaningUp) { 294c11e57a3SBrian Somers int timeout; 295c11e57a3SBrian Somers 296c11e57a3SBrian Somers timeout = datalink_StartDialTimer(dl, datalink_GetDialTimeout(dl)); 297bf1d3ff6SBrian Somers log_WritePrompts(dl, "Failed to open %s, pause %d seconds\n", 298b5c347a3SBrian Somers dl->physical->name.full, timeout); 2993006ec67SBrian Somers } 3003006ec67SBrian Somers } 301bf1d3ff6SBrian Somers } 302310c3babSBrian Somers break; 3033006ec67SBrian Somers 3043006ec67SBrian Somers case DATALINK_HANGUP: 3053006ec67SBrian Somers case DATALINK_DIAL: 3063006ec67SBrian Somers case DATALINK_LOGIN: 3073006ec67SBrian Somers result = descriptor_UpdateSet(&dl->chat.desc, r, w, e, n); 3083006ec67SBrian Somers switch (dl->chat.state) { 3093006ec67SBrian Somers case CHAT_DONE: 3103006ec67SBrian Somers /* script succeeded */ 31139d94652SBrian Somers chat_Destroy(&dl->chat); 3123006ec67SBrian Somers switch(dl->state) { 3133006ec67SBrian Somers case DATALINK_HANGUP: 3143006ec67SBrian Somers datalink_HangupDone(dl); 3153006ec67SBrian Somers break; 3163006ec67SBrian Somers case DATALINK_DIAL: 3179ae58882SBrian Somers datalink_NewState(dl, DATALINK_LOGIN); 318f9545805SBrian Somers chat_Init(&dl->chat, dl->physical, dl->cfg.script.login, 0, NULL); 3191342caedSBrian Somers return datalink_UpdateSet(d, r, w, e, n); 3203006ec67SBrian Somers case DATALINK_LOGIN: 32147dd77c1SBrian Somers dl->phone.alt = NULL; 322c5a5a6caSBrian Somers datalink_LoginDone(dl); 323b51a60ccSBrian Somers return datalink_UpdateSet(d, r, w, e, n); 3243006ec67SBrian Somers } 3253006ec67SBrian Somers break; 3263006ec67SBrian Somers case CHAT_FAILED: 3273006ec67SBrian Somers /* Going down - script failed */ 328dd7e2610SBrian Somers log_Printf(LogWARN, "Chat script failed\n"); 32939d94652SBrian Somers chat_Destroy(&dl->chat); 3303006ec67SBrian Somers switch(dl->state) { 3313006ec67SBrian Somers case DATALINK_HANGUP: 3323006ec67SBrian Somers datalink_HangupDone(dl); 3333006ec67SBrian Somers break; 3343006ec67SBrian Somers case DATALINK_DIAL: 3353006ec67SBrian Somers case DATALINK_LOGIN: 3369ae58882SBrian Somers datalink_NewState(dl, DATALINK_HANGUP); 337d4af231cSBrian Somers modem_Offline(dl->physical); /* Is this required ? */ 338f9545805SBrian Somers chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL); 3391342caedSBrian Somers return datalink_UpdateSet(d, r, w, e, n); 3403006ec67SBrian Somers } 3413006ec67SBrian Somers break; 3423006ec67SBrian Somers } 3433006ec67SBrian Somers break; 344c7cc5030SBrian Somers 345c7cc5030SBrian Somers case DATALINK_READY: 346e2ebb036SBrian Somers case DATALINK_LCP: 347e2ebb036SBrian Somers case DATALINK_AUTH: 34892b09558SBrian Somers case DATALINK_CBCP: 3493006ec67SBrian Somers case DATALINK_OPEN: 35058330d7bSBrian Somers result = descriptor_UpdateSet(&dl->chap.desc, r, w, e, n) + 35158330d7bSBrian Somers descriptor_UpdateSet(&dl->physical->desc, r, w, e, n); 3523006ec67SBrian Somers break; 3533006ec67SBrian Somers } 3543006ec67SBrian Somers return result; 3553006ec67SBrian Somers } 3563006ec67SBrian Somers 357ea722969SBrian Somers int 358ea722969SBrian Somers datalink_RemoveFromSet(struct datalink *dl, fd_set *r, fd_set *w, fd_set *e) 359ea722969SBrian Somers { 360ea722969SBrian Somers return physical_RemoveFromSet(dl->physical, r, w, e); 361ea722969SBrian Somers } 362ea722969SBrian Somers 3633006ec67SBrian Somers static int 3642f786681SBrian Somers datalink_IsSet(struct descriptor *d, const fd_set *fdset) 3653006ec67SBrian Somers { 3663006ec67SBrian Somers struct datalink *dl = descriptor2datalink(d); 3673006ec67SBrian Somers 3683006ec67SBrian Somers switch (dl->state) { 3693006ec67SBrian Somers case DATALINK_CLOSED: 370c7cc5030SBrian Somers case DATALINK_OPENING: 3713006ec67SBrian Somers break; 372c7cc5030SBrian Somers 3733006ec67SBrian Somers case DATALINK_HANGUP: 3743006ec67SBrian Somers case DATALINK_DIAL: 3753006ec67SBrian Somers case DATALINK_LOGIN: 3763006ec67SBrian Somers return descriptor_IsSet(&dl->chat.desc, fdset); 377c7cc5030SBrian Somers 378c7cc5030SBrian Somers case DATALINK_READY: 379e2ebb036SBrian Somers case DATALINK_LCP: 380e2ebb036SBrian Somers case DATALINK_AUTH: 38192b09558SBrian Somers case DATALINK_CBCP: 3823006ec67SBrian Somers case DATALINK_OPEN: 38358330d7bSBrian Somers return descriptor_IsSet(&dl->chap.desc, fdset) ? 1 : 38458330d7bSBrian Somers descriptor_IsSet(&dl->physical->desc, fdset); 3853006ec67SBrian Somers } 3863006ec67SBrian Somers return 0; 3873006ec67SBrian Somers } 3883006ec67SBrian Somers 3893006ec67SBrian Somers static void 3903006ec67SBrian Somers datalink_Read(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) 3913006ec67SBrian Somers { 3923006ec67SBrian Somers struct datalink *dl = descriptor2datalink(d); 3933006ec67SBrian Somers 3943006ec67SBrian Somers switch (dl->state) { 3953006ec67SBrian Somers case DATALINK_CLOSED: 396c7cc5030SBrian Somers case DATALINK_OPENING: 3973006ec67SBrian Somers break; 398c7cc5030SBrian Somers 3993006ec67SBrian Somers case DATALINK_HANGUP: 4003006ec67SBrian Somers case DATALINK_DIAL: 4013006ec67SBrian Somers case DATALINK_LOGIN: 4023006ec67SBrian Somers descriptor_Read(&dl->chat.desc, bundle, fdset); 4033006ec67SBrian Somers break; 404c7cc5030SBrian Somers 405c7cc5030SBrian Somers case DATALINK_READY: 406e2ebb036SBrian Somers case DATALINK_LCP: 407e2ebb036SBrian Somers case DATALINK_AUTH: 40892b09558SBrian Somers case DATALINK_CBCP: 4093006ec67SBrian Somers case DATALINK_OPEN: 41058330d7bSBrian Somers if (descriptor_IsSet(&dl->chap.desc, fdset)) 41158330d7bSBrian Somers descriptor_Read(&dl->chap.desc, bundle, fdset); 41258330d7bSBrian Somers if (descriptor_IsSet(&dl->physical->desc, fdset)) 4133006ec67SBrian Somers descriptor_Read(&dl->physical->desc, bundle, fdset); 4143006ec67SBrian Somers break; 4153006ec67SBrian Somers } 4163006ec67SBrian Somers } 4173006ec67SBrian Somers 4181af29a6eSBrian Somers static int 419f4768038SBrian Somers datalink_Write(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) 4203006ec67SBrian Somers { 4213006ec67SBrian Somers struct datalink *dl = descriptor2datalink(d); 4221af29a6eSBrian Somers int result = 0; 4233006ec67SBrian Somers 4243006ec67SBrian Somers switch (dl->state) { 4253006ec67SBrian Somers case DATALINK_CLOSED: 426c7cc5030SBrian Somers case DATALINK_OPENING: 4273006ec67SBrian Somers break; 428c7cc5030SBrian Somers 4293006ec67SBrian Somers case DATALINK_HANGUP: 4303006ec67SBrian Somers case DATALINK_DIAL: 4313006ec67SBrian Somers case DATALINK_LOGIN: 4321af29a6eSBrian Somers result = descriptor_Write(&dl->chat.desc, bundle, fdset); 4333006ec67SBrian Somers break; 434c7cc5030SBrian Somers 435c7cc5030SBrian Somers case DATALINK_READY: 436e2ebb036SBrian Somers case DATALINK_LCP: 437e2ebb036SBrian Somers case DATALINK_AUTH: 43892b09558SBrian Somers case DATALINK_CBCP: 4393006ec67SBrian Somers case DATALINK_OPEN: 44058330d7bSBrian Somers if (descriptor_IsSet(&dl->chap.desc, fdset)) 44158330d7bSBrian Somers result += descriptor_Write(&dl->chap.desc, bundle, fdset); 44258330d7bSBrian Somers if (descriptor_IsSet(&dl->physical->desc, fdset)) 44358330d7bSBrian Somers result += descriptor_Write(&dl->physical->desc, bundle, fdset); 4443006ec67SBrian Somers break; 4453006ec67SBrian Somers } 4461af29a6eSBrian Somers 4471af29a6eSBrian Somers return result; 4483006ec67SBrian Somers } 4493006ec67SBrian Somers 4506d666775SBrian Somers static void 4519c81b87dSBrian Somers datalink_ComeDown(struct datalink *dl, int how) 452e2ebb036SBrian Somers { 4539c81b87dSBrian Somers if (how != CLOSE_NORMAL) { 454c11e57a3SBrian Somers dl->dial.tries = -1; 455e2ebb036SBrian Somers dl->reconnect_tries = 0; 4567729a182SBrian Somers if (dl->state >= DATALINK_READY && how == CLOSE_LCP) 4579c81b87dSBrian Somers dl->stayonline = 1; 458e2ebb036SBrian Somers } 459e2ebb036SBrian Somers 4607729a182SBrian Somers if (dl->state >= DATALINK_READY && dl->stayonline) { 4619c81b87dSBrian Somers dl->stayonline = 0; 462d4af231cSBrian Somers timer_Stop(&dl->physical->Timer); 4639c81b87dSBrian Somers datalink_NewState(dl, DATALINK_READY); 4649c81b87dSBrian Somers } else if (dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP) { 465e2ebb036SBrian Somers modem_Offline(dl->physical); 466b6f5f442SBrian Somers chat_Destroy(&dl->chat); 467e2ebb036SBrian Somers if (dl->script.run && dl->state != DATALINK_OPENING) { 4689ae58882SBrian Somers datalink_NewState(dl, DATALINK_HANGUP); 469f9545805SBrian Somers chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL); 470e2ebb036SBrian Somers } else 471e2ebb036SBrian Somers datalink_HangupDone(dl); 472e2ebb036SBrian Somers } 473e2ebb036SBrian Somers } 474e2ebb036SBrian Somers 475e2ebb036SBrian Somers static void 4766d666775SBrian Somers datalink_LayerStart(void *v, struct fsm *fp) 4776d666775SBrian Somers { 4786d666775SBrian Somers /* The given FSM is about to start up ! */ 4796d666775SBrian Somers struct datalink *dl = (struct datalink *)v; 480a611cad6SBrian Somers 48192e872e7SBrian Somers if (fp->proto == PROTO_LCP) 482e2ebb036SBrian Somers (*dl->parent->LayerStart)(dl->parent->object, fp); 483e2ebb036SBrian Somers } 4846d666775SBrian Somers 4856d666775SBrian Somers static void 4866d666775SBrian Somers datalink_LayerUp(void *v, struct fsm *fp) 4876d666775SBrian Somers { 4886d666775SBrian Somers /* The given fsm is now up */ 4896d666775SBrian Somers struct datalink *dl = (struct datalink *)v; 4905e315498SBrian Somers struct lcp *lcp = &dl->physical->link.lcp; 4916d666775SBrian Somers 49292e872e7SBrian Somers if (fp->proto == PROTO_LCP) { 493f0cdd9c0SBrian Somers datalink_GotAuthname(dl, ""); 4945e315498SBrian Somers lcp->auth_ineed = lcp->want_auth; 4955e315498SBrian Somers lcp->auth_iwait = lcp->his_auth; 4965e315498SBrian Somers if (lcp->his_auth || lcp->want_auth) { 4975945a079SBrian Somers if (bundle_Phase(dl->bundle) != PHASE_NETWORK) 4985563ebdeSBrian Somers bundle_NewPhase(dl->bundle, PHASE_AUTHENTICATE); 499dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: his = %s, mine = %s\n", dl->name, 5005e315498SBrian Somers Auth2Nam(lcp->his_auth, lcp->his_authtype), 5015e315498SBrian Somers Auth2Nam(lcp->want_auth, lcp->want_authtype)); 5025e315498SBrian Somers if (lcp->his_auth == PROTO_PAP) 503f0cdd9c0SBrian Somers auth_StartReq(&dl->pap); 5045e315498SBrian Somers if (lcp->want_auth == PROTO_CHAP) 505f0cdd9c0SBrian Somers auth_StartReq(&dl->chap.auth); 506e2ebb036SBrian Somers } else 507e2ebb036SBrian Somers datalink_AuthOk(dl); 508e2ebb036SBrian Somers } 509e2ebb036SBrian Somers } 510e2ebb036SBrian Somers 51164cfdfc6SBrian Somers static void 51264cfdfc6SBrian Somers datalink_AuthReInit(struct datalink *dl) 51364cfdfc6SBrian Somers { 51464cfdfc6SBrian Somers auth_StopTimer(&dl->pap); 51564cfdfc6SBrian Somers auth_StopTimer(&dl->chap.auth); 51664cfdfc6SBrian Somers chap_ReInit(&dl->chap); 51764cfdfc6SBrian Somers } 51864cfdfc6SBrian Somers 519e2ebb036SBrian Somers void 520f0cdd9c0SBrian Somers datalink_GotAuthname(struct datalink *dl, const char *name) 521643f4904SBrian Somers { 522f0cdd9c0SBrian Somers strncpy(dl->peer.authname, name, sizeof dl->peer.authname - 1); 523f0cdd9c0SBrian Somers dl->peer.authname[sizeof dl->peer.authname - 1] = '\0'; 524643f4904SBrian Somers } 525643f4904SBrian Somers 526643f4904SBrian Somers void 52792b09558SBrian Somers datalink_NCPUp(struct datalink *dl) 528e2ebb036SBrian Somers { 52906337856SBrian Somers int ccpok = ccp_SetOpenMode(&dl->physical->link.ccp); 5301df0a3b9SBrian Somers 531dbf60d74SBrian Somers if (dl->physical->link.lcp.want_mrru && dl->physical->link.lcp.his_mrru) { 5321fa665f5SBrian Somers /* we've authenticated in multilink mode ! */ 5331fa665f5SBrian Somers switch (mp_Up(&dl->bundle->ncp.mp, dl)) { 5341fa665f5SBrian Somers case MP_LINKSENT: 535ea722969SBrian Somers /* We've handed the link off to another ppp (well, we will soon) ! */ 5361fa665f5SBrian Somers return; 5371fa665f5SBrian Somers case MP_UP: 5380a1b5c9dSBrian Somers /* First link in the bundle */ 53992b09558SBrian Somers auth_Select(dl->bundle, dl->peer.authname); 5400a1b5c9dSBrian Somers /* fall through */ 5411fa665f5SBrian Somers case MP_ADDED: 5420a1b5c9dSBrian Somers /* We're in multilink mode ! */ 5431df0a3b9SBrian Somers dl->physical->link.ccp.fsm.open_mode = OPEN_PASSIVE; /* override */ 5441fa665f5SBrian Somers break; 5451fa665f5SBrian Somers case MP_FAILED: 54649052c95SBrian Somers datalink_AuthNotOk(dl); 54749052c95SBrian Somers return; 54849052c95SBrian Somers } 54949052c95SBrian Somers } else if (bundle_Phase(dl->bundle) == PHASE_NETWORK) { 550dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: Already in NETWORK phase\n", dl->name); 551897f9429SBrian Somers datalink_NewState(dl, DATALINK_OPEN); 552897f9429SBrian Somers (*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.lcp.fsm); 55349052c95SBrian Somers return; 55450abd4c8SBrian Somers } else { 55550abd4c8SBrian Somers dl->bundle->ncp.mp.peer = dl->peer; 556ce828a6eSBrian Somers ipcp_SetLink(&dl->bundle->ncp.ipcp, &dl->physical->link); 55792b09558SBrian Somers auth_Select(dl->bundle, dl->peer.authname); 55850abd4c8SBrian Somers } 55949052c95SBrian Somers 56006337856SBrian Somers if (ccpok) { 561dd7e2610SBrian Somers fsm_Up(&dl->physical->link.ccp.fsm); 562dd7e2610SBrian Somers fsm_Open(&dl->physical->link.ccp.fsm); 56306337856SBrian Somers } 5649ae58882SBrian Somers datalink_NewState(dl, DATALINK_OPEN); 5653b0f8d2eSBrian Somers bundle_NewPhase(dl->bundle, PHASE_NETWORK); 5663b0f8d2eSBrian Somers (*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.lcp.fsm); 5676d666775SBrian Somers } 568e2ebb036SBrian Somers 569e2ebb036SBrian Somers void 57092b09558SBrian Somers datalink_CBCPComplete(struct datalink *dl) 57192b09558SBrian Somers { 57292b09558SBrian Somers datalink_NewState(dl, DATALINK_LCP); 57364cfdfc6SBrian Somers datalink_AuthReInit(dl); 57492b09558SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 57592b09558SBrian Somers } 57692b09558SBrian Somers 57792b09558SBrian Somers void 57892b09558SBrian Somers datalink_CBCPFailed(struct datalink *dl) 57992b09558SBrian Somers { 58092b09558SBrian Somers cbcp_Down(&dl->cbcp); 58192b09558SBrian Somers datalink_CBCPComplete(dl); 58292b09558SBrian Somers } 58392b09558SBrian Somers 58492b09558SBrian Somers void 58592b09558SBrian Somers datalink_AuthOk(struct datalink *dl) 58692b09558SBrian Somers { 5875165af6fSBrian Somers if ((dl->physical->link.lcp.his_callback.opmask & 58892b09558SBrian Somers CALLBACK_BIT(CALLBACK_CBCP) || 5895165af6fSBrian Somers dl->physical->link.lcp.want_callback.opmask & 5905165af6fSBrian Somers CALLBACK_BIT(CALLBACK_CBCP)) && 5915165af6fSBrian Somers !(dl->physical->link.lcp.want_callback.opmask & 5925165af6fSBrian Somers CALLBACK_BIT(CALLBACK_AUTH))) { 5935165af6fSBrian Somers /* We must have agreed CBCP if AUTH isn't there any more */ 59492b09558SBrian Somers datalink_NewState(dl, DATALINK_CBCP); 59592b09558SBrian Somers cbcp_Up(&dl->cbcp); 59692b09558SBrian Somers } else if (dl->physical->link.lcp.want_callback.opmask) { 5975165af6fSBrian Somers /* It's not CBCP */ 59892b09558SBrian Somers log_Printf(LogPHASE, "%s: Shutdown and await peer callback\n", dl->name); 59992b09558SBrian Somers datalink_NewState(dl, DATALINK_LCP); 60064cfdfc6SBrian Somers datalink_AuthReInit(dl); 60192b09558SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 60292b09558SBrian Somers } else 60392b09558SBrian Somers switch (dl->physical->link.lcp.his_callback.opmask) { 60492b09558SBrian Somers case 0: 60592b09558SBrian Somers datalink_NCPUp(dl); 60692b09558SBrian Somers break; 60792b09558SBrian Somers 60892b09558SBrian Somers case CALLBACK_BIT(CALLBACK_AUTH): 60992b09558SBrian Somers auth_SetPhoneList(dl->peer.authname, dl->cbcp.fsm.phone, 61092b09558SBrian Somers sizeof dl->cbcp.fsm.phone); 61192b09558SBrian Somers if (*dl->cbcp.fsm.phone == '\0' || !strcmp(dl->cbcp.fsm.phone, "*")) { 61292b09558SBrian Somers log_Printf(LogPHASE, "%s: %s cannot be called back\n", dl->name, 61392b09558SBrian Somers dl->peer.authname); 61492b09558SBrian Somers *dl->cbcp.fsm.phone = '\0'; 61592b09558SBrian Somers } else { 61692b09558SBrian Somers char *ptr = strchr(dl->cbcp.fsm.phone, ','); 61792b09558SBrian Somers if (ptr) 61892b09558SBrian Somers *ptr = '\0'; /* Call back on the first number */ 61992b09558SBrian Somers log_Printf(LogPHASE, "%s: Calling peer back on %s\n", dl->name, 62092b09558SBrian Somers dl->cbcp.fsm.phone); 62192b09558SBrian Somers dl->cbcp.required = 1; 62292b09558SBrian Somers } 62392b09558SBrian Somers dl->cbcp.fsm.delay = 0; 62492b09558SBrian Somers datalink_NewState(dl, DATALINK_LCP); 62564cfdfc6SBrian Somers datalink_AuthReInit(dl); 62692b09558SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 62792b09558SBrian Somers break; 62892b09558SBrian Somers 62992b09558SBrian Somers case CALLBACK_BIT(CALLBACK_E164): 63092b09558SBrian Somers strncpy(dl->cbcp.fsm.phone, dl->physical->link.lcp.his_callback.msg, 63192b09558SBrian Somers sizeof dl->cbcp.fsm.phone - 1); 63292b09558SBrian Somers dl->cbcp.fsm.phone[sizeof dl->cbcp.fsm.phone - 1] = '\0'; 63392b09558SBrian Somers log_Printf(LogPHASE, "%s: Calling peer back on %s\n", dl->name, 63492b09558SBrian Somers dl->cbcp.fsm.phone); 63592b09558SBrian Somers dl->cbcp.required = 1; 63692b09558SBrian Somers dl->cbcp.fsm.delay = 0; 63792b09558SBrian Somers datalink_NewState(dl, DATALINK_LCP); 63864cfdfc6SBrian Somers datalink_AuthReInit(dl); 63992b09558SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 64092b09558SBrian Somers break; 64192b09558SBrian Somers 64292b09558SBrian Somers default: 64392b09558SBrian Somers log_Printf(LogPHASE, "%s: Oops - Should have NAK'd peer callback !\n", 64492b09558SBrian Somers dl->name); 64592b09558SBrian Somers datalink_NewState(dl, DATALINK_LCP); 64664cfdfc6SBrian Somers datalink_AuthReInit(dl); 64792b09558SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 64892b09558SBrian Somers break; 64992b09558SBrian Somers } 65092b09558SBrian Somers } 65192b09558SBrian Somers 65292b09558SBrian Somers void 653e2ebb036SBrian Somers datalink_AuthNotOk(struct datalink *dl) 654e2ebb036SBrian Somers { 6559ae58882SBrian Somers datalink_NewState(dl, DATALINK_LCP); 65664cfdfc6SBrian Somers datalink_AuthReInit(dl); 657dd7e2610SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 6586d666775SBrian Somers } 6596d666775SBrian Somers 6606d666775SBrian Somers static void 6616d666775SBrian Somers datalink_LayerDown(void *v, struct fsm *fp) 6626d666775SBrian Somers { 6636d666775SBrian Somers /* The given FSM has been told to come down */ 6646d666775SBrian Somers struct datalink *dl = (struct datalink *)v; 665a611cad6SBrian Somers 66692e872e7SBrian Somers if (fp->proto == PROTO_LCP) { 667e2ebb036SBrian Somers switch (dl->state) { 668e2ebb036SBrian Somers case DATALINK_OPEN: 669643f4904SBrian Somers peerid_Init(&dl->peer); 67009206a6fSBrian Somers fsm2initial(&dl->physical->link.ccp.fsm); 671ff0f9439SBrian Somers datalink_NewState(dl, DATALINK_LCP); /* before parent TLD */ 672e2ebb036SBrian Somers (*dl->parent->LayerDown)(dl->parent->object, fp); 67392b09558SBrian Somers /* fall through (just in case) */ 67492b09558SBrian Somers 67592b09558SBrian Somers case DATALINK_CBCP: 67692b09558SBrian Somers if (!dl->cbcp.required) 67792b09558SBrian Somers cbcp_Down(&dl->cbcp); 67892b09558SBrian Somers /* fall through (just in case) */ 679e2ebb036SBrian Somers 680e2ebb036SBrian Somers case DATALINK_AUTH: 681dd7e2610SBrian Somers timer_Stop(&dl->pap.authtimer); 682dd7e2610SBrian Somers timer_Stop(&dl->chap.auth.authtimer); 6836d666775SBrian Somers } 6849ae58882SBrian Somers datalink_NewState(dl, DATALINK_LCP); 68564cfdfc6SBrian Somers datalink_AuthReInit(dl); 686e2ebb036SBrian Somers } 6876d666775SBrian Somers } 6886d666775SBrian Somers 6896d666775SBrian Somers static void 6906d666775SBrian Somers datalink_LayerFinish(void *v, struct fsm *fp) 6916d666775SBrian Somers { 6926d666775SBrian Somers /* The given fsm is now down */ 6936d666775SBrian Somers struct datalink *dl = (struct datalink *)v; 6946d666775SBrian Somers 69592e872e7SBrian Somers if (fp->proto == PROTO_LCP) { 69609206a6fSBrian Somers fsm2initial(fp); 6976d666775SBrian Somers (*dl->parent->LayerFinish)(dl->parent->object, fp); 6989c81b87dSBrian Somers datalink_ComeDown(dl, CLOSE_NORMAL); 6990a1b5c9dSBrian Somers } else if (fp->state == ST_CLOSED && fp->open_mode == OPEN_PASSIVE) 7000a1b5c9dSBrian Somers fsm_Open(fp); /* CCP goes to ST_STOPPED */ 7016d666775SBrian Somers } 7026d666775SBrian Somers 7033006ec67SBrian Somers struct datalink * 7046f384573SBrian Somers datalink_Create(const char *name, struct bundle *bundle, int type) 7053006ec67SBrian Somers { 7063006ec67SBrian Somers struct datalink *dl; 7073006ec67SBrian Somers 7083006ec67SBrian Somers dl = (struct datalink *)malloc(sizeof(struct datalink)); 7093006ec67SBrian Somers if (dl == NULL) 7103006ec67SBrian Somers return dl; 7113006ec67SBrian Somers 7123006ec67SBrian Somers dl->desc.type = DATALINK_DESCRIPTOR; 7133006ec67SBrian Somers dl->desc.UpdateSet = datalink_UpdateSet; 7143006ec67SBrian Somers dl->desc.IsSet = datalink_IsSet; 7153006ec67SBrian Somers dl->desc.Read = datalink_Read; 7163006ec67SBrian Somers dl->desc.Write = datalink_Write; 7175b8b8060SBrian Somers 718e718d1d7SBrian Somers dl->state = DATALINK_CLOSED; 719e718d1d7SBrian Somers 72073a13b5cSBrian Somers *dl->cfg.script.dial = '\0'; 72173a13b5cSBrian Somers *dl->cfg.script.login = '\0'; 72273a13b5cSBrian Somers *dl->cfg.script.hangup = '\0'; 723f9545805SBrian Somers *dl->cfg.phone.list = '\0'; 724f9545805SBrian Somers *dl->phone.list = '\0'; 725f9545805SBrian Somers dl->phone.next = NULL; 726f9545805SBrian Somers dl->phone.alt = NULL; 727f9545805SBrian Somers dl->phone.chosen = "N/A"; 7289c81b87dSBrian Somers dl->stayonline = 0; 729c7cc5030SBrian Somers dl->script.run = 1; 730c7cc5030SBrian Somers dl->script.packetmode = 1; 7313b0f8d2eSBrian Somers mp_linkInit(&dl->mp); 7325b8b8060SBrian Somers 7333006ec67SBrian Somers dl->bundle = bundle; 7343006ec67SBrian Somers dl->next = NULL; 735e718d1d7SBrian Somers 736c11e57a3SBrian Somers memset(&dl->dial.timer, '\0', sizeof dl->dial.timer); 737e718d1d7SBrian Somers 738c11e57a3SBrian Somers dl->dial.tries = 0; 739565e35e5SBrian Somers dl->cfg.dial.max = 1; 740565e35e5SBrian Somers dl->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT; 741565e35e5SBrian Somers dl->cfg.dial.timeout = DIAL_TIMEOUT; 742c11e57a3SBrian Somers dl->cfg.dial.inc = 0; 743c11e57a3SBrian Somers dl->cfg.dial.maxinc = 10; 744e718d1d7SBrian Somers 745abff9baeSBrian Somers dl->reconnect_tries = 0; 746565e35e5SBrian Somers dl->cfg.reconnect.max = 0; 747565e35e5SBrian Somers dl->cfg.reconnect.timeout = RECONNECT_TIMEOUT; 748abff9baeSBrian Somers 74992b09558SBrian Somers dl->cfg.callback.opmask = 0; 75092b09558SBrian Somers dl->cfg.cbcp.delay = 0; 75192b09558SBrian Somers *dl->cfg.cbcp.phone = '\0'; 75292b09558SBrian Somers dl->cfg.cbcp.fsmretry = DEF_FSMRETRY; 75392b09558SBrian Somers 7543006ec67SBrian Somers dl->name = strdup(name); 755643f4904SBrian Somers peerid_Init(&dl->peer); 7566f384573SBrian Somers dl->parent = &bundle->fsm; 7573b0f8d2eSBrian Somers dl->fsmp.LayerStart = datalink_LayerStart; 7583b0f8d2eSBrian Somers dl->fsmp.LayerUp = datalink_LayerUp; 7593b0f8d2eSBrian Somers dl->fsmp.LayerDown = datalink_LayerDown; 7603b0f8d2eSBrian Somers dl->fsmp.LayerFinish = datalink_LayerFinish; 7613b0f8d2eSBrian Somers dl->fsmp.object = dl; 7623b0f8d2eSBrian Somers 763565e35e5SBrian Somers if ((dl->physical = modem_Create(dl, type)) == NULL) { 7643006ec67SBrian Somers free(dl->name); 7653006ec67SBrian Somers free(dl); 7663006ec67SBrian Somers return NULL; 7673006ec67SBrian Somers } 768f0cdd9c0SBrian Somers 769f0cdd9c0SBrian Somers pap_Init(&dl->pap, dl->physical); 770f0cdd9c0SBrian Somers chap_Init(&dl->chap, dl->physical); 77192b09558SBrian Somers cbcp_Init(&dl->cbcp, dl->physical); 772f9545805SBrian Somers chat_Init(&dl->chat, dl->physical, NULL, 1, NULL); 7733006ec67SBrian Somers 7749ae58882SBrian Somers log_Printf(LogPHASE, "%s: Created in %s state\n", 7759ae58882SBrian Somers dl->name, datalink_State(dl)); 7763006ec67SBrian Somers 7773006ec67SBrian Somers return dl; 7783006ec67SBrian Somers } 7793006ec67SBrian Somers 7803006ec67SBrian Somers struct datalink * 781cd7bd93aSBrian Somers datalink_Clone(struct datalink *odl, const char *name) 782cd7bd93aSBrian Somers { 783cd7bd93aSBrian Somers struct datalink *dl; 784cd7bd93aSBrian Somers 785cd7bd93aSBrian Somers dl = (struct datalink *)malloc(sizeof(struct datalink)); 786cd7bd93aSBrian Somers if (dl == NULL) 787cd7bd93aSBrian Somers return dl; 788cd7bd93aSBrian Somers 789cd7bd93aSBrian Somers dl->desc.type = DATALINK_DESCRIPTOR; 790cd7bd93aSBrian Somers dl->desc.UpdateSet = datalink_UpdateSet; 791cd7bd93aSBrian Somers dl->desc.IsSet = datalink_IsSet; 792cd7bd93aSBrian Somers dl->desc.Read = datalink_Read; 793cd7bd93aSBrian Somers dl->desc.Write = datalink_Write; 794cd7bd93aSBrian Somers 795cd7bd93aSBrian Somers dl->state = DATALINK_CLOSED; 796cd7bd93aSBrian Somers 797cd7bd93aSBrian Somers memcpy(&dl->cfg, &odl->cfg, sizeof dl->cfg); 798cd7bd93aSBrian Somers mp_linkInit(&dl->mp); 799cd7bd93aSBrian Somers *dl->phone.list = '\0'; 800643f4904SBrian Somers dl->phone.next = NULL; 801643f4904SBrian Somers dl->phone.alt = NULL; 802643f4904SBrian Somers dl->phone.chosen = "N/A"; 803cd7bd93aSBrian Somers dl->bundle = odl->bundle; 804cd7bd93aSBrian Somers dl->next = NULL; 805c11e57a3SBrian Somers memset(&dl->dial.timer, '\0', sizeof dl->dial.timer); 806c11e57a3SBrian Somers dl->dial.tries = 0; 807cd7bd93aSBrian Somers dl->reconnect_tries = 0; 808cd7bd93aSBrian Somers dl->name = strdup(name); 809643f4904SBrian Somers peerid_Init(&dl->peer); 810cd7bd93aSBrian Somers dl->parent = odl->parent; 811cd7bd93aSBrian Somers memcpy(&dl->fsmp, &odl->fsmp, sizeof dl->fsmp); 812643f4904SBrian Somers dl->fsmp.object = dl; 813cd7bd93aSBrian Somers 81481358fa3SBrian Somers if ((dl->physical = modem_Create(dl, PHYS_INTERACTIVE)) == NULL) { 815cd7bd93aSBrian Somers free(dl->name); 816cd7bd93aSBrian Somers free(dl); 817cd7bd93aSBrian Somers return NULL; 818cd7bd93aSBrian Somers } 819f0cdd9c0SBrian Somers pap_Init(&dl->pap, dl->physical); 820479508cfSBrian Somers dl->pap.cfg = odl->pap.cfg; 821f0cdd9c0SBrian Somers 822f0cdd9c0SBrian Somers chap_Init(&dl->chap, dl->physical); 823479508cfSBrian Somers dl->chap.auth.cfg = odl->chap.auth.cfg; 824f0cdd9c0SBrian Somers 825cd7bd93aSBrian Somers memcpy(&dl->physical->cfg, &odl->physical->cfg, sizeof dl->physical->cfg); 826cd7bd93aSBrian Somers memcpy(&dl->physical->link.lcp.cfg, &odl->physical->link.lcp.cfg, 827cd7bd93aSBrian Somers sizeof dl->physical->link.lcp.cfg); 828cd7bd93aSBrian Somers memcpy(&dl->physical->link.ccp.cfg, &odl->physical->link.ccp.cfg, 829cd7bd93aSBrian Somers sizeof dl->physical->link.ccp.cfg); 830cd7bd93aSBrian Somers memcpy(&dl->physical->async.cfg, &odl->physical->async.cfg, 831cd7bd93aSBrian Somers sizeof dl->physical->async.cfg); 832cd7bd93aSBrian Somers 83392b09558SBrian Somers cbcp_Init(&dl->cbcp, dl->physical); 834cd7bd93aSBrian Somers chat_Init(&dl->chat, dl->physical, NULL, 1, NULL); 835cd7bd93aSBrian Somers 8369ae58882SBrian Somers log_Printf(LogPHASE, "%s: Cloned in %s state\n", 8379ae58882SBrian Somers dl->name, datalink_State(dl)); 838cd7bd93aSBrian Somers 839cd7bd93aSBrian Somers return dl; 840cd7bd93aSBrian Somers } 841cd7bd93aSBrian Somers 842cd7bd93aSBrian Somers struct datalink * 8433006ec67SBrian Somers datalink_Destroy(struct datalink *dl) 8443006ec67SBrian Somers { 8453006ec67SBrian Somers struct datalink *result; 8463006ec67SBrian Somers 84739d94652SBrian Somers if (dl->state != DATALINK_CLOSED) { 848dd7e2610SBrian Somers log_Printf(LogERROR, "Oops, destroying a datalink in state %s\n", 849c7cc5030SBrian Somers datalink_State(dl)); 85039d94652SBrian Somers switch (dl->state) { 85139d94652SBrian Somers case DATALINK_HANGUP: 85239d94652SBrian Somers case DATALINK_DIAL: 85339d94652SBrian Somers case DATALINK_LOGIN: 85439d94652SBrian Somers chat_Destroy(&dl->chat); /* Gotta blat the timers ! */ 85539d94652SBrian Somers break; 85639d94652SBrian Somers } 85739d94652SBrian Somers } 8583006ec67SBrian Somers 859c11e57a3SBrian Somers timer_Stop(&dl->dial.timer); 8603006ec67SBrian Somers result = dl->next; 8613b0f8d2eSBrian Somers modem_Destroy(dl->physical); 8623006ec67SBrian Somers free(dl->name); 8633006ec67SBrian Somers free(dl); 8643006ec67SBrian Somers 8653006ec67SBrian Somers return result; 8663006ec67SBrian Somers } 8673006ec67SBrian Somers 8683006ec67SBrian Somers void 869c5a5a6caSBrian Somers datalink_Up(struct datalink *dl, int runscripts, int packetmode) 8703006ec67SBrian Somers { 8716f384573SBrian Somers if (dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED)) 872565e35e5SBrian Somers /* Ignore scripts */ 873565e35e5SBrian Somers runscripts = 0; 874565e35e5SBrian Somers 875c7cc5030SBrian Somers switch (dl->state) { 876c7cc5030SBrian Somers case DATALINK_CLOSED: 8773b0f8d2eSBrian Somers if (bundle_Phase(dl->bundle) == PHASE_DEAD || 8783b0f8d2eSBrian Somers bundle_Phase(dl->bundle) == PHASE_TERMINATE) 8793b0f8d2eSBrian Somers bundle_NewPhase(dl->bundle, PHASE_ESTABLISH); 8809ae58882SBrian Somers datalink_NewState(dl, DATALINK_OPENING); 881565e35e5SBrian Somers dl->reconnect_tries = 8826f384573SBrian Somers dl->physical->type == PHYS_DIRECT ? 0 : dl->cfg.reconnect.max; 883c11e57a3SBrian Somers dl->dial.tries = dl->cfg.dial.max; 884c5a5a6caSBrian Somers dl->script.run = runscripts; 885c5a5a6caSBrian Somers dl->script.packetmode = packetmode; 886c7cc5030SBrian Somers break; 887c7cc5030SBrian Somers 888c7cc5030SBrian Somers case DATALINK_OPENING: 889c7cc5030SBrian Somers if (!dl->script.run && runscripts) 890c7cc5030SBrian Somers dl->script.run = 1; 891c7cc5030SBrian Somers /* fall through */ 892c7cc5030SBrian Somers 893c7cc5030SBrian Somers case DATALINK_DIAL: 894c7cc5030SBrian Somers case DATALINK_LOGIN: 895c7cc5030SBrian Somers case DATALINK_READY: 896c7cc5030SBrian Somers if (!dl->script.packetmode && packetmode) { 897c7cc5030SBrian Somers dl->script.packetmode = 1; 898c7cc5030SBrian Somers if (dl->state == DATALINK_READY) 899c7cc5030SBrian Somers datalink_LoginDone(dl); 900c7cc5030SBrian Somers } 901c7cc5030SBrian Somers break; 9023006ec67SBrian Somers } 9033006ec67SBrian Somers } 9043006ec67SBrian Somers 9053006ec67SBrian Somers void 9069c81b87dSBrian Somers datalink_Close(struct datalink *dl, int how) 907c7cc5030SBrian Somers { 908c7cc5030SBrian Somers /* Please close */ 909e2ebb036SBrian Somers switch (dl->state) { 910e2ebb036SBrian Somers case DATALINK_OPEN: 911643f4904SBrian Somers peerid_Init(&dl->peer); 91209206a6fSBrian Somers fsm2initial(&dl->physical->link.ccp.fsm); 913e2ebb036SBrian Somers /* fall through */ 914e2ebb036SBrian Somers 91592b09558SBrian Somers case DATALINK_CBCP: 916e2ebb036SBrian Somers case DATALINK_AUTH: 917e2ebb036SBrian Somers case DATALINK_LCP: 91864cfdfc6SBrian Somers datalink_AuthReInit(dl); 919dd7e2610SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 9209c81b87dSBrian Somers if (how != CLOSE_NORMAL) { 921c11e57a3SBrian Somers dl->dial.tries = -1; 922c7cc5030SBrian Somers dl->reconnect_tries = 0; 9239c81b87dSBrian Somers if (how == CLOSE_LCP) 9249c81b87dSBrian Somers dl->stayonline = 1; 925c7cc5030SBrian Somers } 926e2ebb036SBrian Somers break; 927e2ebb036SBrian Somers 928e2ebb036SBrian Somers default: 9299c81b87dSBrian Somers datalink_ComeDown(dl, how); 930c7cc5030SBrian Somers } 931e2ebb036SBrian Somers } 932c7cc5030SBrian Somers 933c7cc5030SBrian Somers void 9349c81b87dSBrian Somers datalink_Down(struct datalink *dl, int how) 935c7cc5030SBrian Somers { 936c7cc5030SBrian Somers /* Carrier is lost */ 937e2ebb036SBrian Somers switch (dl->state) { 938e2ebb036SBrian Somers case DATALINK_OPEN: 939643f4904SBrian Somers peerid_Init(&dl->peer); 94009206a6fSBrian Somers fsm2initial(&dl->physical->link.ccp.fsm); 941e2ebb036SBrian Somers /* fall through */ 942e2ebb036SBrian Somers 94392b09558SBrian Somers case DATALINK_CBCP: 944e2ebb036SBrian Somers case DATALINK_AUTH: 945e2ebb036SBrian Somers case DATALINK_LCP: 94609206a6fSBrian Somers fsm2initial(&dl->physical->link.lcp.fsm); 947e2ebb036SBrian Somers /* fall through */ 948c7cc5030SBrian Somers 949e2ebb036SBrian Somers default: 9509c81b87dSBrian Somers datalink_ComeDown(dl, how); 951c7cc5030SBrian Somers } 952e2ebb036SBrian Somers } 953c7cc5030SBrian Somers 954c7cc5030SBrian Somers void 9553006ec67SBrian Somers datalink_StayDown(struct datalink *dl) 9563006ec67SBrian Somers { 9573006ec67SBrian Somers dl->reconnect_tries = 0; 9583006ec67SBrian Somers } 959c7cc5030SBrian Somers 9609c81b87dSBrian Somers void 9619c81b87dSBrian Somers datalink_DontHangup(struct datalink *dl) 9629c81b87dSBrian Somers { 9637729a182SBrian Somers if (dl->state >= DATALINK_LCP) 9649c81b87dSBrian Somers dl->stayonline = 1; 9659c81b87dSBrian Somers } 9669c81b87dSBrian Somers 967643f4904SBrian Somers int 968643f4904SBrian Somers datalink_Show(struct cmdargs const *arg) 969c7cc5030SBrian Somers { 970643f4904SBrian Somers prompt_Printf(arg->prompt, "Name: %s\n", arg->cx->name); 971643f4904SBrian Somers prompt_Printf(arg->prompt, " State: %s\n", 972643f4904SBrian Somers datalink_State(arg->cx)); 973643f4904SBrian Somers prompt_Printf(arg->prompt, " Peer name: "); 974643f4904SBrian Somers if (*arg->cx->peer.authname) 975643f4904SBrian Somers prompt_Printf(arg->prompt, "%s\n", arg->cx->peer.authname); 976643f4904SBrian Somers else if (arg->cx->state == DATALINK_OPEN) 977643f4904SBrian Somers prompt_Printf(arg->prompt, "None requested\n"); 978565e35e5SBrian Somers else 979643f4904SBrian Somers prompt_Printf(arg->prompt, "N/A\n"); 980643f4904SBrian Somers prompt_Printf(arg->prompt, " Discriminator: %s\n", 981643f4904SBrian Somers mp_Enddisc(arg->cx->peer.enddisc.class, 982643f4904SBrian Somers arg->cx->peer.enddisc.address, 983643f4904SBrian Somers arg->cx->peer.enddisc.len)); 984643f4904SBrian Somers 985643f4904SBrian Somers prompt_Printf(arg->prompt, "\nDefaults:\n"); 986643f4904SBrian Somers prompt_Printf(arg->prompt, " Phone List: %s\n", 987643f4904SBrian Somers arg->cx->cfg.phone.list); 988643f4904SBrian Somers if (arg->cx->cfg.dial.max) 989643f4904SBrian Somers prompt_Printf(arg->prompt, " Dial tries: %d, delay ", 990643f4904SBrian Somers arg->cx->cfg.dial.max); 991565e35e5SBrian Somers else 992643f4904SBrian Somers prompt_Printf(arg->prompt, " Dial tries: infinite, delay "); 993b5c347a3SBrian Somers if (arg->cx->cfg.dial.next_timeout >= 0) 994643f4904SBrian Somers prompt_Printf(arg->prompt, "%ds/", arg->cx->cfg.dial.next_timeout); 995565e35e5SBrian Somers else 996643f4904SBrian Somers prompt_Printf(arg->prompt, "random/"); 997b5c347a3SBrian Somers if (arg->cx->cfg.dial.timeout >= 0) 998643f4904SBrian Somers prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.dial.timeout); 999565e35e5SBrian Somers else 1000643f4904SBrian Somers prompt_Printf(arg->prompt, "random\n"); 1001643f4904SBrian Somers prompt_Printf(arg->prompt, " Reconnect tries: %d, delay ", 1002643f4904SBrian Somers arg->cx->cfg.reconnect.max); 1003643f4904SBrian Somers if (arg->cx->cfg.reconnect.timeout > 0) 1004643f4904SBrian Somers prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.reconnect.timeout); 1005643f4904SBrian Somers else 1006643f4904SBrian Somers prompt_Printf(arg->prompt, "random\n"); 100792b09558SBrian Somers prompt_Printf(arg->prompt, " Callback %s ", arg->cx->physical->type == 100892b09558SBrian Somers PHYS_DIRECT ? "accepted: " : "requested:"); 100992b09558SBrian Somers if (!arg->cx->cfg.callback.opmask) 101092b09558SBrian Somers prompt_Printf(arg->prompt, "none\n"); 101192b09558SBrian Somers else { 101292b09558SBrian Somers int comma = 0; 101392b09558SBrian Somers 101492b09558SBrian Somers if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_NONE)) { 101592b09558SBrian Somers prompt_Printf(arg->prompt, "none"); 101692b09558SBrian Somers comma = 1; 101792b09558SBrian Somers } 101892b09558SBrian Somers if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_AUTH)) { 101992b09558SBrian Somers prompt_Printf(arg->prompt, "%sauth", comma ? ", " : ""); 102092b09558SBrian Somers comma = 1; 102192b09558SBrian Somers } 102292b09558SBrian Somers if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_E164)) { 102392b09558SBrian Somers prompt_Printf(arg->prompt, "%sE.164", comma ? ", " : ""); 102492b09558SBrian Somers if (arg->cx->physical->type != PHYS_DIRECT) 102592b09558SBrian Somers prompt_Printf(arg->prompt, " (%s)", arg->cx->cfg.callback.msg); 102692b09558SBrian Somers comma = 1; 102792b09558SBrian Somers } 102892b09558SBrian Somers if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_CBCP)) { 102992b09558SBrian Somers prompt_Printf(arg->prompt, "%scbcp\n", comma ? ", " : ""); 103092b09558SBrian Somers prompt_Printf(arg->prompt, " CBCP: delay: %ds\n", 103192b09558SBrian Somers arg->cx->cfg.cbcp.delay); 1032cf784a89SBrian Somers prompt_Printf(arg->prompt, " phone: "); 1033cf784a89SBrian Somers if (!strcmp(arg->cx->cfg.cbcp.phone, "*")) { 1034cf784a89SBrian Somers if (arg->cx->physical->type & PHYS_DIRECT) 1035cf784a89SBrian Somers prompt_Printf(arg->prompt, "Caller decides\n"); 1036cf784a89SBrian Somers else 1037cf784a89SBrian Somers prompt_Printf(arg->prompt, "Dialback server decides\n"); 1038cf784a89SBrian Somers } else 1039cf784a89SBrian Somers prompt_Printf(arg->prompt, "%s\n", arg->cx->cfg.cbcp.phone); 104092b09558SBrian Somers prompt_Printf(arg->prompt, " timeout: %lds\n", 104192b09558SBrian Somers arg->cx->cfg.cbcp.fsmretry); 104292b09558SBrian Somers } else 104392b09558SBrian Somers prompt_Printf(arg->prompt, "\n"); 104492b09558SBrian Somers } 104592b09558SBrian Somers 1046643f4904SBrian Somers prompt_Printf(arg->prompt, " Dial Script: %s\n", 1047643f4904SBrian Somers arg->cx->cfg.script.dial); 1048643f4904SBrian Somers prompt_Printf(arg->prompt, " Login Script: %s\n", 1049643f4904SBrian Somers arg->cx->cfg.script.login); 1050643f4904SBrian Somers prompt_Printf(arg->prompt, " Hangup Script: %s\n", 1051643f4904SBrian Somers arg->cx->cfg.script.hangup); 1052643f4904SBrian Somers return 0; 1053565e35e5SBrian Somers } 1054565e35e5SBrian Somers 1055565e35e5SBrian Somers int 1056565e35e5SBrian Somers datalink_SetReconnect(struct cmdargs const *arg) 1057565e35e5SBrian Somers { 105825092092SBrian Somers if (arg->argc == arg->argn+2) { 105925092092SBrian Somers arg->cx->cfg.reconnect.timeout = atoi(arg->argv[arg->argn]); 106025092092SBrian Somers arg->cx->cfg.reconnect.max = atoi(arg->argv[arg->argn+1]); 1061565e35e5SBrian Somers return 0; 1062565e35e5SBrian Somers } 1063565e35e5SBrian Somers return -1; 1064565e35e5SBrian Somers } 1065565e35e5SBrian Somers 1066565e35e5SBrian Somers int 1067565e35e5SBrian Somers datalink_SetRedial(struct cmdargs const *arg) 1068565e35e5SBrian Somers { 1069c11e57a3SBrian Somers const char *sep, *osep; 1070c11e57a3SBrian Somers int timeout, inc, maxinc, tries; 1071565e35e5SBrian Somers 107225092092SBrian Somers if (arg->argc == arg->argn+1 || arg->argc == arg->argn+2) { 107325092092SBrian Somers if (strncasecmp(arg->argv[arg->argn], "random", 6) == 0 && 107425092092SBrian Somers (arg->argv[arg->argn][6] == '\0' || arg->argv[arg->argn][6] == '.')) { 1075565e35e5SBrian Somers arg->cx->cfg.dial.timeout = -1; 1076565e35e5SBrian Somers randinit(); 1077565e35e5SBrian Somers } else { 107825092092SBrian Somers timeout = atoi(arg->argv[arg->argn]); 1079565e35e5SBrian Somers 1080565e35e5SBrian Somers if (timeout >= 0) 1081565e35e5SBrian Somers arg->cx->cfg.dial.timeout = timeout; 1082565e35e5SBrian Somers else { 1083dd7e2610SBrian Somers log_Printf(LogWARN, "Invalid redial timeout\n"); 1084565e35e5SBrian Somers return -1; 1085565e35e5SBrian Somers } 1086565e35e5SBrian Somers } 1087565e35e5SBrian Somers 1088c11e57a3SBrian Somers sep = strchr(arg->argv[arg->argn], '+'); 1089c11e57a3SBrian Somers if (sep) { 1090c11e57a3SBrian Somers inc = atoi(++sep); 1091c11e57a3SBrian Somers osep = sep; 1092c11e57a3SBrian Somers if (inc >= 0) 1093c11e57a3SBrian Somers arg->cx->cfg.dial.inc = inc; 1094c11e57a3SBrian Somers else { 1095c11e57a3SBrian Somers log_Printf(LogWARN, "Invalid timeout increment\n"); 1096c11e57a3SBrian Somers return -1; 1097c11e57a3SBrian Somers } 1098c11e57a3SBrian Somers sep = strchr(sep, '-'); 1099c11e57a3SBrian Somers if (sep) { 1100c11e57a3SBrian Somers maxinc = atoi(++sep); 1101c11e57a3SBrian Somers if (maxinc >= 0) 1102c11e57a3SBrian Somers arg->cx->cfg.dial.maxinc = maxinc; 1103c11e57a3SBrian Somers else { 1104c11e57a3SBrian Somers log_Printf(LogWARN, "Invalid maximum timeout increments\n"); 1105c11e57a3SBrian Somers return -1; 1106c11e57a3SBrian Somers } 1107c11e57a3SBrian Somers } else { 1108c11e57a3SBrian Somers /* Default timeout increment */ 1109c11e57a3SBrian Somers arg->cx->cfg.dial.maxinc = 10; 1110c11e57a3SBrian Somers sep = osep; 1111c11e57a3SBrian Somers } 1112c11e57a3SBrian Somers } else { 1113c11e57a3SBrian Somers /* Default timeout increment & max increment */ 1114c11e57a3SBrian Somers arg->cx->cfg.dial.inc = 0; 1115c11e57a3SBrian Somers arg->cx->cfg.dial.maxinc = 10; 1116c11e57a3SBrian Somers sep = arg->argv[arg->argn]; 1117c11e57a3SBrian Somers } 1118c11e57a3SBrian Somers 1119c11e57a3SBrian Somers sep = strchr(sep, '.'); 1120c11e57a3SBrian Somers if (sep) { 1121c11e57a3SBrian Somers if (strcasecmp(++sep, "random") == 0) { 1122565e35e5SBrian Somers arg->cx->cfg.dial.next_timeout = -1; 1123565e35e5SBrian Somers randinit(); 1124565e35e5SBrian Somers } else { 1125c11e57a3SBrian Somers timeout = atoi(sep); 1126565e35e5SBrian Somers if (timeout >= 0) 1127565e35e5SBrian Somers arg->cx->cfg.dial.next_timeout = timeout; 1128565e35e5SBrian Somers else { 1129dd7e2610SBrian Somers log_Printf(LogWARN, "Invalid next redial timeout\n"); 1130565e35e5SBrian Somers return -1; 1131565e35e5SBrian Somers } 1132565e35e5SBrian Somers } 1133565e35e5SBrian Somers } else 1134565e35e5SBrian Somers /* Default next timeout */ 1135565e35e5SBrian Somers arg->cx->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT; 1136565e35e5SBrian Somers 113725092092SBrian Somers if (arg->argc == arg->argn+2) { 113825092092SBrian Somers tries = atoi(arg->argv[arg->argn+1]); 1139565e35e5SBrian Somers 1140565e35e5SBrian Somers if (tries >= 0) { 1141565e35e5SBrian Somers arg->cx->cfg.dial.max = tries; 1142565e35e5SBrian Somers } else { 1143dd7e2610SBrian Somers log_Printf(LogWARN, "Invalid retry value\n"); 1144565e35e5SBrian Somers return 1; 1145565e35e5SBrian Somers } 1146565e35e5SBrian Somers } 1147565e35e5SBrian Somers return 0; 1148565e35e5SBrian Somers } 1149c11e57a3SBrian Somers 1150565e35e5SBrian Somers return -1; 1151c7cc5030SBrian Somers } 1152c7cc5030SBrian Somers 1153cdbbb6b5SBrian Somers static const char *states[] = { 1154565e35e5SBrian Somers "closed", 1155565e35e5SBrian Somers "opening", 1156565e35e5SBrian Somers "hangup", 1157565e35e5SBrian Somers "dial", 1158565e35e5SBrian Somers "login", 1159565e35e5SBrian Somers "ready", 1160565e35e5SBrian Somers "lcp", 1161565e35e5SBrian Somers "auth", 116292b09558SBrian Somers "cbcp", 1163565e35e5SBrian Somers "open" 1164c7cc5030SBrian Somers }; 1165c7cc5030SBrian Somers 1166643f4904SBrian Somers const char * 1167c7cc5030SBrian Somers datalink_State(struct datalink *dl) 1168c7cc5030SBrian Somers { 1169c7cc5030SBrian Somers if (dl->state < 0 || dl->state >= sizeof states / sizeof states[0]) 1170c7cc5030SBrian Somers return "unknown"; 1171c7cc5030SBrian Somers return states[dl->state]; 1172c7cc5030SBrian Somers } 11736f384573SBrian Somers 11749ae58882SBrian Somers static void 11759ae58882SBrian Somers datalink_NewState(struct datalink *dl, int state) 11769ae58882SBrian Somers { 11779ae58882SBrian Somers if (state != dl->state) { 11789ae58882SBrian Somers if (state >= 0 && state < sizeof states / sizeof states[0]) { 11799ae58882SBrian Somers log_Printf(LogPHASE, "%s: %s -> %s\n", dl->name, datalink_State(dl), 11809ae58882SBrian Somers states[state]); 11819ae58882SBrian Somers dl->state = state; 11829ae58882SBrian Somers } else 11839ae58882SBrian Somers log_Printf(LogERROR, "%s: Can't enter state %d !\n", dl->name, state); 11849ae58882SBrian Somers } 11859ae58882SBrian Somers } 11869ae58882SBrian Somers 11876f384573SBrian Somers struct datalink * 118896c9bb21SBrian Somers iov2datalink(struct bundle *bundle, struct iovec *iov, int *niov, int maxiov, 118996c9bb21SBrian Somers int fd) 11906f384573SBrian Somers { 1191b7c5748eSBrian Somers struct datalink *dl, *cdl; 1192479508cfSBrian Somers struct fsm_retry copy; 1193b7c5748eSBrian Somers char *oname; 11946f384573SBrian Somers 119596c9bb21SBrian Somers dl = (struct datalink *)iov[(*niov)++].iov_base; 119696c9bb21SBrian Somers dl->name = iov[*niov].iov_base; 11976f384573SBrian Somers 119896c9bb21SBrian Somers if (dl->name[DATALINK_MAXNAME-1]) { 119996c9bb21SBrian Somers dl->name[DATALINK_MAXNAME-1] = '\0'; 120096c9bb21SBrian Somers if (strlen(dl->name) == DATALINK_MAXNAME - 1) 120196c9bb21SBrian Somers log_Printf(LogWARN, "Datalink name truncated to \"%s\"\n", dl->name); 12026f384573SBrian Somers } 1203b7c5748eSBrian Somers 1204b7c5748eSBrian Somers /* Make sure the name is unique ! */ 1205b7c5748eSBrian Somers oname = NULL; 1206b7c5748eSBrian Somers do { 1207b7c5748eSBrian Somers for (cdl = bundle->links; cdl; cdl = cdl->next) 1208b7c5748eSBrian Somers if (!strcasecmp(dl->name, cdl->name)) { 1209b7c5748eSBrian Somers if (oname) 1210b7c5748eSBrian Somers free(datalink_NextName(dl)); 1211b7c5748eSBrian Somers else 1212b7c5748eSBrian Somers oname = datalink_NextName(dl); 1213b7c5748eSBrian Somers break; /* Keep renaming 'till we have no conflicts */ 1214b7c5748eSBrian Somers } 1215b7c5748eSBrian Somers } while (cdl); 1216b7c5748eSBrian Somers 1217b7c5748eSBrian Somers if (oname) { 1218b7c5748eSBrian Somers log_Printf(LogPHASE, "Rename link %s to %s\n", oname, dl->name); 1219b7c5748eSBrian Somers free(oname); 1220b7c5748eSBrian Somers } else { 122196c9bb21SBrian Somers dl->name = strdup(dl->name); 1222b7c5748eSBrian Somers free(iov[*niov].iov_base); 1223b7c5748eSBrian Somers } 1224b7c5748eSBrian Somers (*niov)++; 12256f384573SBrian Somers 12266f384573SBrian Somers dl->desc.type = DATALINK_DESCRIPTOR; 12276f384573SBrian Somers dl->desc.UpdateSet = datalink_UpdateSet; 12286f384573SBrian Somers dl->desc.IsSet = datalink_IsSet; 12296f384573SBrian Somers dl->desc.Read = datalink_Read; 12306f384573SBrian Somers dl->desc.Write = datalink_Write; 12316f384573SBrian Somers 12326f384573SBrian Somers mp_linkInit(&dl->mp); 12336f384573SBrian Somers *dl->phone.list = '\0'; 12346f384573SBrian Somers dl->phone.next = NULL; 12356f384573SBrian Somers dl->phone.alt = NULL; 12366f384573SBrian Somers dl->phone.chosen = "N/A"; 12376f384573SBrian Somers 12386f384573SBrian Somers dl->bundle = bundle; 12396f384573SBrian Somers dl->next = NULL; 1240c11e57a3SBrian Somers memset(&dl->dial.timer, '\0', sizeof dl->dial.timer); 1241c11e57a3SBrian Somers dl->dial.tries = 0; 12426f384573SBrian Somers dl->reconnect_tries = 0; 12436f384573SBrian Somers dl->parent = &bundle->fsm; 12446f384573SBrian Somers dl->fsmp.LayerStart = datalink_LayerStart; 12456f384573SBrian Somers dl->fsmp.LayerUp = datalink_LayerUp; 12466f384573SBrian Somers dl->fsmp.LayerDown = datalink_LayerDown; 12476f384573SBrian Somers dl->fsmp.LayerFinish = datalink_LayerFinish; 12486f384573SBrian Somers dl->fsmp.object = dl; 12496f384573SBrian Somers 125096c9bb21SBrian Somers dl->physical = iov2modem(dl, iov, niov, maxiov, fd); 125196c9bb21SBrian Somers 125296c9bb21SBrian Somers if (!dl->physical) { 12536f384573SBrian Somers free(dl->name); 12546f384573SBrian Somers free(dl); 12556f384573SBrian Somers dl = NULL; 12569ae58882SBrian Somers } else { 1257479508cfSBrian Somers copy = dl->pap.cfg.fsm; 1258f0cdd9c0SBrian Somers pap_Init(&dl->pap, dl->physical); 1259479508cfSBrian Somers dl->pap.cfg.fsm = copy; 1260f0cdd9c0SBrian Somers 1261479508cfSBrian Somers copy = dl->chap.auth.cfg.fsm; 1262f0cdd9c0SBrian Somers chap_Init(&dl->chap, dl->physical); 1263479508cfSBrian Somers dl->chap.auth.cfg.fsm = copy; 1264f0cdd9c0SBrian Somers 126592b09558SBrian Somers cbcp_Init(&dl->cbcp, dl->physical); 12666f384573SBrian Somers chat_Init(&dl->chat, dl->physical, NULL, 1, NULL); 12676f384573SBrian Somers 12689ae58882SBrian Somers log_Printf(LogPHASE, "%s: Transferred in %s state\n", 12699ae58882SBrian Somers dl->name, datalink_State(dl)); 12709ae58882SBrian Somers } 12719ae58882SBrian Somers 12726f384573SBrian Somers return dl; 12736f384573SBrian Somers } 12746f384573SBrian Somers 12756f384573SBrian Somers int 127685fd273aSBrian Somers datalink2iov(struct datalink *dl, struct iovec *iov, int *niov, int maxiov, 127785fd273aSBrian Somers pid_t newpid) 12786f384573SBrian Somers { 127996c9bb21SBrian Somers /* If `dl' is NULL, we're allocating before a Fromiov() */ 128096c9bb21SBrian Somers int link_fd; 12816f384573SBrian Somers 128296c9bb21SBrian Somers if (dl) { 1283c11e57a3SBrian Somers timer_Stop(&dl->dial.timer); 128492b09558SBrian Somers /* The following is purely for the sake of paranoia */ 128592b09558SBrian Somers cbcp_Down(&dl->cbcp); 1286dd7e2610SBrian Somers timer_Stop(&dl->pap.authtimer); 1287dd7e2610SBrian Somers timer_Stop(&dl->chap.auth.authtimer); 12886f384573SBrian Somers } 12896f384573SBrian Somers 129096c9bb21SBrian Somers if (*niov >= maxiov - 1) { 129196c9bb21SBrian Somers log_Printf(LogERROR, "Toiov: No room for datalink !\n"); 129296c9bb21SBrian Somers if (dl) { 12936f384573SBrian Somers free(dl->name); 12946f384573SBrian Somers free(dl); 129596c9bb21SBrian Somers } 129696c9bb21SBrian Somers return -1; 129796c9bb21SBrian Somers } 129896c9bb21SBrian Somers 129996c9bb21SBrian Somers iov[*niov].iov_base = dl ? dl : malloc(sizeof *dl); 130096c9bb21SBrian Somers iov[(*niov)++].iov_len = sizeof *dl; 130196c9bb21SBrian Somers iov[*niov].iov_base = 130296c9bb21SBrian Somers dl ? realloc(dl->name, DATALINK_MAXNAME) : malloc(DATALINK_MAXNAME); 130396c9bb21SBrian Somers iov[(*niov)++].iov_len = DATALINK_MAXNAME; 130496c9bb21SBrian Somers 130585fd273aSBrian Somers link_fd = modem2iov(dl ? dl->physical : NULL, iov, niov, maxiov, newpid); 130696c9bb21SBrian Somers 130796c9bb21SBrian Somers if (link_fd == -1 && dl) { 130896c9bb21SBrian Somers free(dl->name); 130996c9bb21SBrian Somers free(dl); 131096c9bb21SBrian Somers } 13116f384573SBrian Somers 13126f384573SBrian Somers return link_fd; 13136f384573SBrian Somers } 13146f384573SBrian Somers 131558d55334SBrian Somers void 131658d55334SBrian Somers datalink_Rename(struct datalink *dl, const char *name) 131758d55334SBrian Somers { 131858d55334SBrian Somers free(dl->name); 131958d55334SBrian Somers dl->physical->link.name = dl->name = strdup(name); 132058d55334SBrian Somers } 132158d55334SBrian Somers 132284917b87SBrian Somers char * 132384917b87SBrian Somers datalink_NextName(struct datalink *dl) 13246f384573SBrian Somers { 13256f384573SBrian Somers int f, n; 132684917b87SBrian Somers char *name, *oname; 13276f384573SBrian Somers 13286f384573SBrian Somers n = strlen(dl->name); 13296f384573SBrian Somers name = (char *)malloc(n+3); 13306f384573SBrian Somers for (f = n - 1; f >= 0; f--) 13316f384573SBrian Somers if (!isdigit(dl->name[f])) 13326f384573SBrian Somers break; 13336f384573SBrian Somers n = sprintf(name, "%.*s-", dl->name[f] == '-' ? f : f + 1, dl->name); 13346f384573SBrian Somers sprintf(name + n, "%d", atoi(dl->name + f + 1) + 1); 133584917b87SBrian Somers oname = dl->name; 133654cd8e13SBrian Somers dl->name = name; 133754cd8e13SBrian Somers /* our physical link name isn't updated (it probably isn't created yet) */ 133884917b87SBrian Somers return oname; 13396f384573SBrian Somers } 1340dd0645c5SBrian Somers 1341dd0645c5SBrian Somers int 1342dd0645c5SBrian Somers datalink_SetMode(struct datalink *dl, int mode) 1343dd0645c5SBrian Somers { 1344dd0645c5SBrian Somers if (!physical_SetMode(dl->physical, mode)) 1345dd0645c5SBrian Somers return 0; 1346dd0645c5SBrian Somers if (dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED)) 1347dd0645c5SBrian Somers dl->script.run = 0; 1348dd0645c5SBrian Somers if (dl->physical->type == PHYS_DIRECT) 1349dd0645c5SBrian Somers dl->reconnect_tries = 0; 135081358fa3SBrian Somers if (mode & (PHYS_DDIAL|PHYS_BACKGROUND) && dl->state <= DATALINK_READY) 1351dd0645c5SBrian Somers datalink_Up(dl, 1, 1); 1352dd0645c5SBrian Somers return 1; 1353dd0645c5SBrian Somers } 1354c11e57a3SBrian Somers 1355c11e57a3SBrian Somers int 1356c11e57a3SBrian Somers datalink_GetDialTimeout(struct datalink *dl) 1357c11e57a3SBrian Somers { 1358c11e57a3SBrian Somers int result = dl->cfg.dial.timeout + dl->dial.incs * dl->cfg.dial.inc; 1359c11e57a3SBrian Somers 1360c11e57a3SBrian Somers if (dl->dial.incs < dl->cfg.dial.maxinc) 1361c11e57a3SBrian Somers dl->dial.incs++; 1362c11e57a3SBrian Somers 1363c11e57a3SBrian Somers return result; 1364c11e57a3SBrian Somers } 1365