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 * 268b09cf1cSBrian Somers * $Id: datalink.c,v 1.21 1998/12/10 18:36:53 brian Exp $ 273006ec67SBrian Somers */ 283006ec67SBrian Somers 292764b86aSBrian Somers #include <sys/types.h> 303006ec67SBrian Somers #include <netinet/in.h> 31eaa4df37SBrian Somers #include <netinet/in_systm.h> 32eaa4df37SBrian Somers #include <netinet/ip.h> 331fa665f5SBrian Somers #include <sys/un.h> 343006ec67SBrian Somers 356f384573SBrian Somers #include <ctype.h> 36c7cc5030SBrian Somers #include <stdio.h> 373006ec67SBrian Somers #include <stdlib.h> 383006ec67SBrian Somers #include <string.h> 3996c9bb21SBrian Somers #include <sys/uio.h> 403006ec67SBrian Somers #include <termios.h> 413006ec67SBrian Somers 423006ec67SBrian Somers #include "mbuf.h" 433006ec67SBrian Somers #include "log.h" 443006ec67SBrian Somers #include "defs.h" 453006ec67SBrian Somers #include "timer.h" 463006ec67SBrian Somers #include "fsm.h" 473006ec67SBrian Somers #include "lcp.h" 483006ec67SBrian Somers #include "descriptor.h" 49879ed6faSBrian Somers #include "lqr.h" 503006ec67SBrian Somers #include "hdlc.h" 513006ec67SBrian Somers #include "async.h" 523006ec67SBrian Somers #include "throughput.h" 533b0f8d2eSBrian Somers #include "ccp.h" 543006ec67SBrian Somers #include "link.h" 553006ec67SBrian Somers #include "physical.h" 565828db6dSBrian Somers #include "iplist.h" 57eaa4df37SBrian Somers #include "slcompress.h" 585828db6dSBrian Somers #include "ipcp.h" 595ca5389aSBrian Somers #include "filter.h" 603b0f8d2eSBrian Somers #include "mp.h" 613006ec67SBrian Somers #include "bundle.h" 623006ec67SBrian Somers #include "chat.h" 63e2ebb036SBrian Somers #include "auth.h" 643006ec67SBrian Somers #include "modem.h" 65c7cc5030SBrian Somers #include "prompt.h" 66e2ebb036SBrian Somers #include "lcpproto.h" 67e2ebb036SBrian Somers #include "pap.h" 68e2ebb036SBrian Somers #include "chap.h" 69565e35e5SBrian Somers #include "command.h" 7092b09558SBrian Somers #include "cbcp.h" 71e2ebb036SBrian Somers #include "datalink.h" 72c7cc5030SBrian Somers 73030e4ebbSBrian Somers static void datalink_LoginDone(struct datalink *); 749ae58882SBrian Somers static void datalink_NewState(struct datalink *, int); 753006ec67SBrian Somers 763006ec67SBrian Somers static void 773006ec67SBrian Somers datalink_OpenTimeout(void *v) 783006ec67SBrian Somers { 793006ec67SBrian Somers struct datalink *dl = (struct datalink *)v; 803006ec67SBrian Somers 81dd7e2610SBrian Somers timer_Stop(&dl->dial_timer); 823006ec67SBrian Somers if (dl->state == DATALINK_OPENING) 83dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: Redial timer expired.\n", dl->name); 843006ec67SBrian Somers } 853006ec67SBrian Somers 863006ec67SBrian Somers static void 873006ec67SBrian Somers datalink_StartDialTimer(struct datalink *dl, int Timeout) 883006ec67SBrian Somers { 89dd7e2610SBrian Somers timer_Stop(&dl->dial_timer); 903006ec67SBrian Somers 913006ec67SBrian Somers if (Timeout) { 923006ec67SBrian Somers if (Timeout > 0) 933006ec67SBrian Somers dl->dial_timer.load = Timeout * SECTICKS; 943006ec67SBrian Somers else 95e718d1d7SBrian Somers dl->dial_timer.load = (random() % DIAL_TIMEOUT) * SECTICKS; 963006ec67SBrian Somers dl->dial_timer.func = datalink_OpenTimeout; 973b0f8d2eSBrian Somers dl->dial_timer.name = "dial"; 983006ec67SBrian Somers dl->dial_timer.arg = dl; 99dd7e2610SBrian Somers timer_Start(&dl->dial_timer); 1003006ec67SBrian Somers if (dl->state == DATALINK_OPENING) 101dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: Enter pause (%d) for redialing.\n", 1023006ec67SBrian Somers dl->name, Timeout); 1033006ec67SBrian Somers } 1043006ec67SBrian Somers } 1053006ec67SBrian Somers 1063006ec67SBrian Somers static void 1073006ec67SBrian Somers datalink_HangupDone(struct datalink *dl) 1083006ec67SBrian Somers { 109030e4ebbSBrian Somers if (dl->physical->type == PHYS_DEDICATED && !dl->bundle->CleaningUp && 110dd7e2610SBrian Somers physical_GetFD(dl->physical) != -1) { 111030e4ebbSBrian Somers /* Don't close our modem if the link is dedicated */ 112030e4ebbSBrian Somers datalink_LoginDone(dl); 113030e4ebbSBrian Somers return; 114030e4ebbSBrian Somers } 115030e4ebbSBrian Somers 1163006ec67SBrian Somers modem_Close(dl->physical); 117565e35e5SBrian Somers dl->phone.chosen = "N/A"; 1183006ec67SBrian Somers 11992b09558SBrian Somers if (dl->cbcp.required) { 12092b09558SBrian Somers log_Printf(LogPHASE, "Call peer back on %s\n", dl->cbcp.fsm.phone); 12192b09558SBrian Somers dl->cfg.callback.opmask = 0; 12292b09558SBrian Somers strncpy(dl->cfg.phone.list, dl->cbcp.fsm.phone, 12392b09558SBrian Somers sizeof dl->cfg.phone.list - 1); 12492b09558SBrian Somers dl->cfg.phone.list[sizeof dl->cfg.phone.list - 1] = '\0'; 12592b09558SBrian Somers dl->phone.alt = dl->phone.next = NULL; 12692b09558SBrian Somers dl->reconnect_tries = dl->cfg.reconnect.max; 12792b09558SBrian Somers dl->dial_tries = dl->cfg.dial.max; 12892b09558SBrian Somers dl->script.run = 1; 12992b09558SBrian Somers dl->script.packetmode = 1; 13092b09558SBrian Somers if (!physical_SetMode(dl->physical, PHYS_BACKGROUND)) 13192b09558SBrian Somers log_Printf(LogERROR, "Oops - can't change mode to BACKGROUND (gulp) !\n"); 13292b09558SBrian Somers bundle_LinksRemoved(dl->bundle); 13392b09558SBrian Somers if (dl->cbcp.fsm.delay < dl->cfg.dial.timeout) 13492b09558SBrian Somers dl->cbcp.fsm.delay = dl->cfg.dial.timeout; 13592b09558SBrian Somers datalink_StartDialTimer(dl, dl->cbcp.fsm.delay); 13692b09558SBrian Somers cbcp_Down(&dl->cbcp); 13792b09558SBrian Somers datalink_NewState(dl, DATALINK_OPENING); 13892b09558SBrian Somers } else if (dl->bundle->CleaningUp || 1396f384573SBrian Somers (dl->physical->type == PHYS_DIRECT) || 1403b0f8d2eSBrian Somers ((!dl->dial_tries || (dl->dial_tries < 0 && !dl->reconnect_tries)) && 14181358fa3SBrian Somers !(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)))) { 1429ae58882SBrian Somers datalink_NewState(dl, DATALINK_CLOSED); 1433006ec67SBrian Somers dl->dial_tries = -1; 1443006ec67SBrian Somers dl->reconnect_tries = 0; 1453006ec67SBrian Somers bundle_LinkClosed(dl->bundle, dl); 1463b0f8d2eSBrian Somers if (!dl->bundle->CleaningUp) 147565e35e5SBrian Somers datalink_StartDialTimer(dl, dl->cfg.dial.timeout); 1483006ec67SBrian Somers } else { 1499ae58882SBrian Somers datalink_NewState(dl, DATALINK_OPENING); 150abff9baeSBrian Somers if (dl->dial_tries < 0) { 151565e35e5SBrian Somers datalink_StartDialTimer(dl, dl->cfg.reconnect.timeout); 152565e35e5SBrian Somers dl->dial_tries = dl->cfg.dial.max; 153abff9baeSBrian Somers dl->reconnect_tries--; 154abff9baeSBrian Somers } else { 155f9545805SBrian Somers if (dl->phone.next == NULL) 156565e35e5SBrian Somers datalink_StartDialTimer(dl, dl->cfg.dial.timeout); 1573006ec67SBrian Somers else 158565e35e5SBrian Somers datalink_StartDialTimer(dl, dl->cfg.dial.next_timeout); 1593006ec67SBrian Somers } 160abff9baeSBrian Somers } 161abff9baeSBrian Somers } 1623006ec67SBrian Somers 163f9545805SBrian Somers static const char * 164f9545805SBrian Somers datalink_ChoosePhoneNumber(struct datalink *dl) 165f9545805SBrian Somers { 166f9545805SBrian Somers char *phone; 167f9545805SBrian Somers 168f9545805SBrian Somers if (dl->phone.alt == NULL) { 169f9545805SBrian Somers if (dl->phone.next == NULL) { 170f9545805SBrian Somers strncpy(dl->phone.list, dl->cfg.phone.list, sizeof dl->phone.list - 1); 171f9545805SBrian Somers dl->phone.list[sizeof dl->phone.list - 1] = '\0'; 172f9545805SBrian Somers dl->phone.next = dl->phone.list; 173f9545805SBrian Somers } 174f9545805SBrian Somers dl->phone.alt = strsep(&dl->phone.next, ":"); 175f9545805SBrian Somers } 176f9545805SBrian Somers phone = strsep(&dl->phone.alt, "|"); 177f9545805SBrian Somers dl->phone.chosen = *phone ? phone : "[NONE]"; 178f9545805SBrian Somers if (*phone) 179dd7e2610SBrian Somers log_Printf(LogPHASE, "Phone: %s\n", phone); 180f9545805SBrian Somers return phone; 181f9545805SBrian Somers } 182f9545805SBrian Somers 183c5a5a6caSBrian Somers static void 184c5a5a6caSBrian Somers datalink_LoginDone(struct datalink *dl) 185c5a5a6caSBrian Somers { 186d345321bSBrian Somers if (!dl->script.packetmode) { 187d345321bSBrian Somers dl->dial_tries = -1; 1889ae58882SBrian Somers datalink_NewState(dl, DATALINK_READY); 189d345321bSBrian Somers } else if (modem_Raw(dl->physical, dl->bundle) < 0) { 190c5a5a6caSBrian Somers dl->dial_tries = 0; 191dd7e2610SBrian Somers log_Printf(LogWARN, "datalink_LoginDone: Not connected.\n"); 192c5a5a6caSBrian Somers if (dl->script.run) { 1939ae58882SBrian Somers datalink_NewState(dl, DATALINK_HANGUP); 194c5a5a6caSBrian Somers modem_Offline(dl->physical); 195f9545805SBrian Somers chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL); 196030e4ebbSBrian Somers } else { 197d4af231cSBrian Somers timer_Stop(&dl->physical->Timer); 198030e4ebbSBrian Somers if (dl->physical->type == PHYS_DEDICATED) 199030e4ebbSBrian Somers /* force a redial timeout */ 200030e4ebbSBrian Somers modem_Close(dl->physical); 201c5a5a6caSBrian Somers datalink_HangupDone(dl); 202030e4ebbSBrian Somers } 203c5a5a6caSBrian Somers } else { 204c7cc5030SBrian Somers dl->dial_tries = -1; 205c7cc5030SBrian Somers 206643f4904SBrian Somers hdlc_Init(&dl->physical->hdlc, &dl->physical->link.lcp); 2073b0f8d2eSBrian Somers async_Init(&dl->physical->async); 2083b0f8d2eSBrian Somers 209cd9647a1SBrian Somers lcp_Setup(&dl->physical->link.lcp, dl->state == DATALINK_READY ? 210cd9647a1SBrian Somers 0 : dl->physical->link.lcp.cfg.openmode); 2113b0f8d2eSBrian Somers ccp_Setup(&dl->physical->link.ccp); 212503a7782SBrian Somers 2139ae58882SBrian Somers datalink_NewState(dl, DATALINK_LCP); 214dd7e2610SBrian Somers fsm_Up(&dl->physical->link.lcp.fsm); 215dd7e2610SBrian Somers fsm_Open(&dl->physical->link.lcp.fsm); 216c5a5a6caSBrian Somers } 217c5a5a6caSBrian Somers } 218c5a5a6caSBrian Somers 2193006ec67SBrian Somers static int 2203006ec67SBrian Somers datalink_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e, 2213006ec67SBrian Somers int *n) 2223006ec67SBrian Somers { 2233006ec67SBrian Somers struct datalink *dl = descriptor2datalink(d); 2243006ec67SBrian Somers int result; 2253006ec67SBrian Somers 226310c3babSBrian Somers result = 0; 2273006ec67SBrian Somers switch (dl->state) { 2283006ec67SBrian Somers case DATALINK_CLOSED: 22981358fa3SBrian Somers if ((dl->physical->type & 23081358fa3SBrian Somers (PHYS_DIRECT|PHYS_DEDICATED|PHYS_BACKGROUND|PHYS_DDIAL)) && 231565e35e5SBrian Somers !bundle_IsDead(dl->bundle)) 232565e35e5SBrian Somers /* 23381358fa3SBrian Somers * Our first time in - DEDICATED & DDIAL never come down, and 23481358fa3SBrian Somers * DIRECT & BACKGROUND get deleted when they enter DATALINK_CLOSED. 23581358fa3SBrian Somers * Go to DATALINK_OPENING via datalink_Up() and fall through. 236565e35e5SBrian Somers */ 237565e35e5SBrian Somers datalink_Up(dl, 1, 1); 238565e35e5SBrian Somers else 239310c3babSBrian Somers break; 240565e35e5SBrian Somers /* fall through */ 2413006ec67SBrian Somers 2423006ec67SBrian Somers case DATALINK_OPENING: 2433006ec67SBrian Somers if (dl->dial_timer.state != TIMER_RUNNING) { 2443006ec67SBrian Somers if (--dl->dial_tries < 0) 2453006ec67SBrian Somers dl->dial_tries = 0; 2463006ec67SBrian Somers if (modem_Open(dl->physical, dl->bundle) >= 0) { 247bf1d3ff6SBrian Somers log_WritePrompts(dl, "%s: Entering terminal mode on %s\r\n" 248bf1d3ff6SBrian Somers "Type `~?' for help\r\n", dl->name, 249bf1d3ff6SBrian Somers dl->physical->name.full); 250c5a5a6caSBrian Somers if (dl->script.run) { 2519ae58882SBrian Somers datalink_NewState(dl, DATALINK_DIAL); 252f9545805SBrian Somers chat_Init(&dl->chat, dl->physical, dl->cfg.script.dial, 1, 253f9545805SBrian Somers datalink_ChoosePhoneNumber(dl)); 25481358fa3SBrian Somers if (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) && 255565e35e5SBrian Somers dl->cfg.dial.max) 256dd7e2610SBrian Somers log_Printf(LogCHAT, "%s: Dial attempt %u of %d\n", 257565e35e5SBrian Somers dl->name, dl->cfg.dial.max - dl->dial_tries, 258565e35e5SBrian Somers dl->cfg.dial.max); 259c5a5a6caSBrian Somers } else 260c5a5a6caSBrian Somers datalink_LoginDone(dl); 2618b09cf1cSBrian Somers return datalink_UpdateSet(d, r, w, e, n); 2623006ec67SBrian Somers } else { 26381358fa3SBrian Somers if (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) && 264565e35e5SBrian Somers dl->cfg.dial.max) 265dd7e2610SBrian Somers log_Printf(LogCHAT, "Failed to open modem (attempt %u of %d)\n", 266565e35e5SBrian Somers dl->cfg.dial.max - dl->dial_tries, dl->cfg.dial.max); 2673006ec67SBrian Somers else 268dd7e2610SBrian Somers log_Printf(LogCHAT, "Failed to open modem\n"); 2693006ec67SBrian Somers 2703b0f8d2eSBrian Somers if (dl->bundle->CleaningUp || 27181358fa3SBrian Somers (!(dl->physical->type & (PHYS_DDIAL|PHYS_DEDICATED)) && 272565e35e5SBrian Somers dl->cfg.dial.max && dl->dial_tries == 0)) { 2739ae58882SBrian Somers datalink_NewState(dl, DATALINK_CLOSED); 2743006ec67SBrian Somers dl->reconnect_tries = 0; 2753006ec67SBrian Somers dl->dial_tries = -1; 276bf1d3ff6SBrian Somers log_WritePrompts(dl, "Failed to open %s\n", 277bf1d3ff6SBrian Somers dl->physical->name.full); 2785b8b8060SBrian Somers bundle_LinkClosed(dl->bundle, dl); 279c5a5a6caSBrian Somers } 280bf1d3ff6SBrian Somers if (!dl->bundle->CleaningUp) { 281bf1d3ff6SBrian Somers log_WritePrompts(dl, "Failed to open %s, pause %d seconds\n", 282bf1d3ff6SBrian Somers dl->physical->name.full, dl->cfg.dial.timeout); 283565e35e5SBrian Somers datalink_StartDialTimer(dl, dl->cfg.dial.timeout); 2843006ec67SBrian Somers } 2853006ec67SBrian Somers } 286bf1d3ff6SBrian Somers } 287310c3babSBrian Somers break; 2883006ec67SBrian Somers 2893006ec67SBrian Somers case DATALINK_HANGUP: 2903006ec67SBrian Somers case DATALINK_DIAL: 2913006ec67SBrian Somers case DATALINK_LOGIN: 2923006ec67SBrian Somers result = descriptor_UpdateSet(&dl->chat.desc, r, w, e, n); 2933006ec67SBrian Somers switch (dl->chat.state) { 2943006ec67SBrian Somers case CHAT_DONE: 2953006ec67SBrian Somers /* script succeeded */ 29639d94652SBrian Somers chat_Destroy(&dl->chat); 2973006ec67SBrian Somers switch(dl->state) { 2983006ec67SBrian Somers case DATALINK_HANGUP: 2993006ec67SBrian Somers datalink_HangupDone(dl); 3003006ec67SBrian Somers break; 3013006ec67SBrian Somers case DATALINK_DIAL: 3029ae58882SBrian Somers datalink_NewState(dl, DATALINK_LOGIN); 303f9545805SBrian Somers chat_Init(&dl->chat, dl->physical, dl->cfg.script.login, 0, NULL); 3041342caedSBrian Somers return datalink_UpdateSet(d, r, w, e, n); 3053006ec67SBrian Somers case DATALINK_LOGIN: 306c5a5a6caSBrian Somers datalink_LoginDone(dl); 3073006ec67SBrian Somers break; 3083006ec67SBrian Somers } 3093006ec67SBrian Somers break; 3103006ec67SBrian Somers case CHAT_FAILED: 3113006ec67SBrian Somers /* Going down - script failed */ 312dd7e2610SBrian Somers log_Printf(LogWARN, "Chat script failed\n"); 31339d94652SBrian Somers chat_Destroy(&dl->chat); 3143006ec67SBrian Somers switch(dl->state) { 3153006ec67SBrian Somers case DATALINK_HANGUP: 3163006ec67SBrian Somers datalink_HangupDone(dl); 3173006ec67SBrian Somers break; 3183006ec67SBrian Somers case DATALINK_DIAL: 3193006ec67SBrian Somers case DATALINK_LOGIN: 3209ae58882SBrian Somers datalink_NewState(dl, DATALINK_HANGUP); 321d4af231cSBrian Somers modem_Offline(dl->physical); /* Is this required ? */ 322f9545805SBrian Somers chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL); 3231342caedSBrian Somers return datalink_UpdateSet(d, r, w, e, n); 3243006ec67SBrian Somers } 3253006ec67SBrian Somers break; 3263006ec67SBrian Somers } 3273006ec67SBrian Somers break; 328c7cc5030SBrian Somers 329c7cc5030SBrian Somers case DATALINK_READY: 330e2ebb036SBrian Somers case DATALINK_LCP: 331e2ebb036SBrian Somers case DATALINK_AUTH: 33292b09558SBrian Somers case DATALINK_CBCP: 3333006ec67SBrian Somers case DATALINK_OPEN: 3343006ec67SBrian Somers result = descriptor_UpdateSet(&dl->physical->desc, r, w, e, n); 3353006ec67SBrian Somers break; 3363006ec67SBrian Somers } 3373006ec67SBrian Somers return result; 3383006ec67SBrian Somers } 3393006ec67SBrian Somers 340ea722969SBrian Somers int 341ea722969SBrian Somers datalink_RemoveFromSet(struct datalink *dl, fd_set *r, fd_set *w, fd_set *e) 342ea722969SBrian Somers { 343ea722969SBrian Somers return physical_RemoveFromSet(dl->physical, r, w, e); 344ea722969SBrian Somers } 345ea722969SBrian Somers 3463006ec67SBrian Somers static int 3472f786681SBrian Somers datalink_IsSet(struct descriptor *d, const fd_set *fdset) 3483006ec67SBrian Somers { 3493006ec67SBrian Somers struct datalink *dl = descriptor2datalink(d); 3503006ec67SBrian Somers 3513006ec67SBrian Somers switch (dl->state) { 3523006ec67SBrian Somers case DATALINK_CLOSED: 353c7cc5030SBrian Somers case DATALINK_OPENING: 3543006ec67SBrian Somers break; 355c7cc5030SBrian Somers 3563006ec67SBrian Somers case DATALINK_HANGUP: 3573006ec67SBrian Somers case DATALINK_DIAL: 3583006ec67SBrian Somers case DATALINK_LOGIN: 3593006ec67SBrian Somers return descriptor_IsSet(&dl->chat.desc, fdset); 360c7cc5030SBrian Somers 361c7cc5030SBrian Somers case DATALINK_READY: 362e2ebb036SBrian Somers case DATALINK_LCP: 363e2ebb036SBrian Somers case DATALINK_AUTH: 36492b09558SBrian Somers case DATALINK_CBCP: 3653006ec67SBrian Somers case DATALINK_OPEN: 3663006ec67SBrian Somers return descriptor_IsSet(&dl->physical->desc, fdset); 3673006ec67SBrian Somers } 3683006ec67SBrian Somers return 0; 3693006ec67SBrian Somers } 3703006ec67SBrian Somers 3713006ec67SBrian Somers static void 3723006ec67SBrian Somers datalink_Read(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) 3733006ec67SBrian Somers { 3743006ec67SBrian Somers struct datalink *dl = descriptor2datalink(d); 3753006ec67SBrian Somers 3763006ec67SBrian Somers switch (dl->state) { 3773006ec67SBrian Somers case DATALINK_CLOSED: 378c7cc5030SBrian Somers case DATALINK_OPENING: 3793006ec67SBrian Somers break; 380c7cc5030SBrian Somers 3813006ec67SBrian Somers case DATALINK_HANGUP: 3823006ec67SBrian Somers case DATALINK_DIAL: 3833006ec67SBrian Somers case DATALINK_LOGIN: 3843006ec67SBrian Somers descriptor_Read(&dl->chat.desc, bundle, fdset); 3853006ec67SBrian Somers break; 386c7cc5030SBrian Somers 387c7cc5030SBrian Somers case DATALINK_READY: 388e2ebb036SBrian Somers case DATALINK_LCP: 389e2ebb036SBrian Somers case DATALINK_AUTH: 39092b09558SBrian Somers case DATALINK_CBCP: 3913006ec67SBrian Somers case DATALINK_OPEN: 3923006ec67SBrian Somers descriptor_Read(&dl->physical->desc, bundle, fdset); 3933006ec67SBrian Somers break; 3943006ec67SBrian Somers } 3953006ec67SBrian Somers } 3963006ec67SBrian Somers 3971af29a6eSBrian Somers static int 398f4768038SBrian Somers datalink_Write(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) 3993006ec67SBrian Somers { 4003006ec67SBrian Somers struct datalink *dl = descriptor2datalink(d); 4011af29a6eSBrian Somers int result = 0; 4023006ec67SBrian Somers 4033006ec67SBrian Somers switch (dl->state) { 4043006ec67SBrian Somers case DATALINK_CLOSED: 405c7cc5030SBrian Somers case DATALINK_OPENING: 4063006ec67SBrian Somers break; 407c7cc5030SBrian Somers 4083006ec67SBrian Somers case DATALINK_HANGUP: 4093006ec67SBrian Somers case DATALINK_DIAL: 4103006ec67SBrian Somers case DATALINK_LOGIN: 4111af29a6eSBrian Somers result = descriptor_Write(&dl->chat.desc, bundle, fdset); 4123006ec67SBrian Somers break; 413c7cc5030SBrian Somers 414c7cc5030SBrian Somers case DATALINK_READY: 415e2ebb036SBrian Somers case DATALINK_LCP: 416e2ebb036SBrian Somers case DATALINK_AUTH: 41792b09558SBrian Somers case DATALINK_CBCP: 4183006ec67SBrian Somers case DATALINK_OPEN: 4191af29a6eSBrian Somers result = descriptor_Write(&dl->physical->desc, bundle, fdset); 4203006ec67SBrian Somers break; 4213006ec67SBrian Somers } 4221af29a6eSBrian Somers 4231af29a6eSBrian Somers return result; 4243006ec67SBrian Somers } 4253006ec67SBrian Somers 4266d666775SBrian Somers static void 4279c81b87dSBrian Somers datalink_ComeDown(struct datalink *dl, int how) 428e2ebb036SBrian Somers { 4299c81b87dSBrian Somers if (how != CLOSE_NORMAL) { 430e2ebb036SBrian Somers dl->dial_tries = -1; 431e2ebb036SBrian Somers dl->reconnect_tries = 0; 4327729a182SBrian Somers if (dl->state >= DATALINK_READY && how == CLOSE_LCP) 4339c81b87dSBrian Somers dl->stayonline = 1; 434e2ebb036SBrian Somers } 435e2ebb036SBrian Somers 4367729a182SBrian Somers if (dl->state >= DATALINK_READY && dl->stayonline) { 4379c81b87dSBrian Somers dl->stayonline = 0; 438d4af231cSBrian Somers timer_Stop(&dl->physical->Timer); 4399c81b87dSBrian Somers datalink_NewState(dl, DATALINK_READY); 4409c81b87dSBrian Somers } else if (dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP) { 441e2ebb036SBrian Somers modem_Offline(dl->physical); 442b6f5f442SBrian Somers chat_Destroy(&dl->chat); 443e2ebb036SBrian Somers if (dl->script.run && dl->state != DATALINK_OPENING) { 4449ae58882SBrian Somers datalink_NewState(dl, DATALINK_HANGUP); 445f9545805SBrian Somers chat_Init(&dl->chat, dl->physical, dl->cfg.script.hangup, 1, NULL); 446e2ebb036SBrian Somers } else 447e2ebb036SBrian Somers datalink_HangupDone(dl); 448e2ebb036SBrian Somers } 449e2ebb036SBrian Somers } 450e2ebb036SBrian Somers 451e2ebb036SBrian Somers static void 4526d666775SBrian Somers datalink_LayerStart(void *v, struct fsm *fp) 4536d666775SBrian Somers { 4546d666775SBrian Somers /* The given FSM is about to start up ! */ 4556d666775SBrian Somers struct datalink *dl = (struct datalink *)v; 456a611cad6SBrian Somers 45792e872e7SBrian Somers if (fp->proto == PROTO_LCP) 458e2ebb036SBrian Somers (*dl->parent->LayerStart)(dl->parent->object, fp); 459e2ebb036SBrian Somers } 4606d666775SBrian Somers 4616d666775SBrian Somers static void 4626d666775SBrian Somers datalink_LayerUp(void *v, struct fsm *fp) 4636d666775SBrian Somers { 4646d666775SBrian Somers /* The given fsm is now up */ 4656d666775SBrian Somers struct datalink *dl = (struct datalink *)v; 4666d666775SBrian Somers 46792e872e7SBrian Somers if (fp->proto == PROTO_LCP) { 468643f4904SBrian Somers datalink_GotAuthname(dl, "", 0); 4693b0f8d2eSBrian Somers dl->physical->link.lcp.auth_ineed = dl->physical->link.lcp.want_auth; 4703b0f8d2eSBrian Somers dl->physical->link.lcp.auth_iwait = dl->physical->link.lcp.his_auth; 4713b0f8d2eSBrian Somers if (dl->physical->link.lcp.his_auth || dl->physical->link.lcp.want_auth) { 4723b0f8d2eSBrian Somers if (bundle_Phase(dl->bundle) == PHASE_ESTABLISH) 4735563ebdeSBrian Somers bundle_NewPhase(dl->bundle, PHASE_AUTHENTICATE); 474dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: his = %s, mine = %s\n", dl->name, 4753b0f8d2eSBrian Somers Auth2Nam(dl->physical->link.lcp.his_auth), 4763b0f8d2eSBrian Somers Auth2Nam(dl->physical->link.lcp.want_auth)); 4773b0f8d2eSBrian Somers if (dl->physical->link.lcp.his_auth == PROTO_PAP) 478dd7e2610SBrian Somers auth_StartChallenge(&dl->pap, dl->physical, pap_SendChallenge); 4793b0f8d2eSBrian Somers if (dl->physical->link.lcp.want_auth == PROTO_CHAP) 480dd7e2610SBrian Somers auth_StartChallenge(&dl->chap.auth, dl->physical, chap_SendChallenge); 481e2ebb036SBrian Somers } else 482e2ebb036SBrian Somers datalink_AuthOk(dl); 483e2ebb036SBrian Somers } 484e2ebb036SBrian Somers } 485e2ebb036SBrian Somers 486e2ebb036SBrian Somers void 487643f4904SBrian Somers datalink_GotAuthname(struct datalink *dl, const char *name, int len) 488643f4904SBrian Somers { 489643f4904SBrian Somers if (len >= sizeof dl->peer.authname) 490643f4904SBrian Somers len = sizeof dl->peer.authname - 1; 491643f4904SBrian Somers strncpy(dl->peer.authname, name, len); 492643f4904SBrian Somers dl->peer.authname[len] = '\0'; 493643f4904SBrian Somers } 494643f4904SBrian Somers 495643f4904SBrian Somers void 49692b09558SBrian Somers datalink_NCPUp(struct datalink *dl) 497e2ebb036SBrian Somers { 49806337856SBrian Somers int ccpok = ccp_SetOpenMode(&dl->physical->link.ccp); 4991df0a3b9SBrian Somers 500dbf60d74SBrian Somers if (dl->physical->link.lcp.want_mrru && dl->physical->link.lcp.his_mrru) { 5011fa665f5SBrian Somers /* we've authenticated in multilink mode ! */ 5021fa665f5SBrian Somers switch (mp_Up(&dl->bundle->ncp.mp, dl)) { 5031fa665f5SBrian Somers case MP_LINKSENT: 504ea722969SBrian Somers /* We've handed the link off to another ppp (well, we will soon) ! */ 5051fa665f5SBrian Somers return; 5061fa665f5SBrian Somers case MP_UP: 5070a1b5c9dSBrian Somers /* First link in the bundle */ 50892b09558SBrian Somers auth_Select(dl->bundle, dl->peer.authname); 5090a1b5c9dSBrian Somers /* fall through */ 5101fa665f5SBrian Somers case MP_ADDED: 5110a1b5c9dSBrian Somers /* We're in multilink mode ! */ 5121df0a3b9SBrian Somers dl->physical->link.ccp.fsm.open_mode = OPEN_PASSIVE; /* override */ 5131fa665f5SBrian Somers break; 5141fa665f5SBrian Somers case MP_FAILED: 51549052c95SBrian Somers datalink_AuthNotOk(dl); 51649052c95SBrian Somers return; 51749052c95SBrian Somers } 51849052c95SBrian Somers } else if (bundle_Phase(dl->bundle) == PHASE_NETWORK) { 519dd7e2610SBrian Somers log_Printf(LogPHASE, "%s: Already in NETWORK phase\n", dl->name); 520897f9429SBrian Somers datalink_NewState(dl, DATALINK_OPEN); 521897f9429SBrian Somers (*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.lcp.fsm); 52249052c95SBrian Somers return; 52350abd4c8SBrian Somers } else { 52450abd4c8SBrian Somers dl->bundle->ncp.mp.peer = dl->peer; 525ce828a6eSBrian Somers ipcp_SetLink(&dl->bundle->ncp.ipcp, &dl->physical->link); 52692b09558SBrian Somers auth_Select(dl->bundle, dl->peer.authname); 52750abd4c8SBrian Somers } 52849052c95SBrian Somers 52906337856SBrian Somers if (ccpok) { 530dd7e2610SBrian Somers fsm_Up(&dl->physical->link.ccp.fsm); 531dd7e2610SBrian Somers fsm_Open(&dl->physical->link.ccp.fsm); 53206337856SBrian Somers } 5339ae58882SBrian Somers datalink_NewState(dl, DATALINK_OPEN); 5343b0f8d2eSBrian Somers bundle_NewPhase(dl->bundle, PHASE_NETWORK); 5353b0f8d2eSBrian Somers (*dl->parent->LayerUp)(dl->parent->object, &dl->physical->link.lcp.fsm); 5366d666775SBrian Somers } 537e2ebb036SBrian Somers 538e2ebb036SBrian Somers void 53992b09558SBrian Somers datalink_CBCPComplete(struct datalink *dl) 54092b09558SBrian Somers { 54192b09558SBrian Somers datalink_NewState(dl, DATALINK_LCP); 54292b09558SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 54392b09558SBrian Somers } 54492b09558SBrian Somers 54592b09558SBrian Somers void 54692b09558SBrian Somers datalink_CBCPFailed(struct datalink *dl) 54792b09558SBrian Somers { 54892b09558SBrian Somers cbcp_Down(&dl->cbcp); 54992b09558SBrian Somers datalink_CBCPComplete(dl); 55092b09558SBrian Somers } 55192b09558SBrian Somers 55292b09558SBrian Somers void 55392b09558SBrian Somers datalink_AuthOk(struct datalink *dl) 55492b09558SBrian Somers { 55592b09558SBrian Somers if (dl->physical->link.lcp.his_callback.opmask == 55692b09558SBrian Somers CALLBACK_BIT(CALLBACK_CBCP) || 55792b09558SBrian Somers dl->physical->link.lcp.want_callback.opmask == 55892b09558SBrian Somers CALLBACK_BIT(CALLBACK_CBCP)) { 55992b09558SBrian Somers datalink_NewState(dl, DATALINK_CBCP); 56092b09558SBrian Somers cbcp_Up(&dl->cbcp); 56192b09558SBrian Somers } else if (dl->physical->link.lcp.want_callback.opmask) { 56292b09558SBrian Somers log_Printf(LogPHASE, "%s: Shutdown and await peer callback\n", dl->name); 56392b09558SBrian Somers datalink_NewState(dl, DATALINK_LCP); 56492b09558SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 56592b09558SBrian Somers } else 56692b09558SBrian Somers switch (dl->physical->link.lcp.his_callback.opmask) { 56792b09558SBrian Somers case 0: 56892b09558SBrian Somers datalink_NCPUp(dl); 56992b09558SBrian Somers break; 57092b09558SBrian Somers 57192b09558SBrian Somers case CALLBACK_BIT(CALLBACK_AUTH): 57292b09558SBrian Somers auth_SetPhoneList(dl->peer.authname, dl->cbcp.fsm.phone, 57392b09558SBrian Somers sizeof dl->cbcp.fsm.phone); 57492b09558SBrian Somers if (*dl->cbcp.fsm.phone == '\0' || !strcmp(dl->cbcp.fsm.phone, "*")) { 57592b09558SBrian Somers log_Printf(LogPHASE, "%s: %s cannot be called back\n", dl->name, 57692b09558SBrian Somers dl->peer.authname); 57792b09558SBrian Somers *dl->cbcp.fsm.phone = '\0'; 57892b09558SBrian Somers } else { 57992b09558SBrian Somers char *ptr = strchr(dl->cbcp.fsm.phone, ','); 58092b09558SBrian Somers if (ptr) 58192b09558SBrian Somers *ptr = '\0'; /* Call back on the first number */ 58292b09558SBrian Somers log_Printf(LogPHASE, "%s: Calling peer back on %s\n", dl->name, 58392b09558SBrian Somers dl->cbcp.fsm.phone); 58492b09558SBrian Somers dl->cbcp.required = 1; 58592b09558SBrian Somers } 58692b09558SBrian Somers dl->cbcp.fsm.delay = 0; 58792b09558SBrian Somers datalink_NewState(dl, DATALINK_LCP); 58892b09558SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 58992b09558SBrian Somers break; 59092b09558SBrian Somers 59192b09558SBrian Somers case CALLBACK_BIT(CALLBACK_E164): 59292b09558SBrian Somers strncpy(dl->cbcp.fsm.phone, dl->physical->link.lcp.his_callback.msg, 59392b09558SBrian Somers sizeof dl->cbcp.fsm.phone - 1); 59492b09558SBrian Somers dl->cbcp.fsm.phone[sizeof dl->cbcp.fsm.phone - 1] = '\0'; 59592b09558SBrian Somers log_Printf(LogPHASE, "%s: Calling peer back on %s\n", dl->name, 59692b09558SBrian Somers dl->cbcp.fsm.phone); 59792b09558SBrian Somers dl->cbcp.required = 1; 59892b09558SBrian Somers dl->cbcp.fsm.delay = 0; 59992b09558SBrian Somers datalink_NewState(dl, DATALINK_LCP); 60092b09558SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 60192b09558SBrian Somers break; 60292b09558SBrian Somers 60392b09558SBrian Somers default: 60492b09558SBrian Somers log_Printf(LogPHASE, "%s: Oops - Should have NAK'd peer callback !\n", 60592b09558SBrian Somers dl->name); 60692b09558SBrian Somers datalink_NewState(dl, DATALINK_LCP); 60792b09558SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 60892b09558SBrian Somers break; 60992b09558SBrian Somers } 61092b09558SBrian Somers } 61192b09558SBrian Somers 61292b09558SBrian Somers void 613e2ebb036SBrian Somers datalink_AuthNotOk(struct datalink *dl) 614e2ebb036SBrian Somers { 6159ae58882SBrian Somers datalink_NewState(dl, DATALINK_LCP); 616dd7e2610SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 6176d666775SBrian Somers } 6186d666775SBrian Somers 6196d666775SBrian Somers static void 6206d666775SBrian Somers datalink_LayerDown(void *v, struct fsm *fp) 6216d666775SBrian Somers { 6226d666775SBrian Somers /* The given FSM has been told to come down */ 6236d666775SBrian Somers struct datalink *dl = (struct datalink *)v; 624a611cad6SBrian Somers 62592e872e7SBrian Somers if (fp->proto == PROTO_LCP) { 626e2ebb036SBrian Somers switch (dl->state) { 627e2ebb036SBrian Somers case DATALINK_OPEN: 628643f4904SBrian Somers peerid_Init(&dl->peer); 62909206a6fSBrian Somers fsm2initial(&dl->physical->link.ccp.fsm); 630ff0f9439SBrian Somers datalink_NewState(dl, DATALINK_LCP); /* before parent TLD */ 631e2ebb036SBrian Somers (*dl->parent->LayerDown)(dl->parent->object, fp); 63292b09558SBrian Somers /* fall through (just in case) */ 63392b09558SBrian Somers 63492b09558SBrian Somers case DATALINK_CBCP: 63592b09558SBrian Somers if (!dl->cbcp.required) 63692b09558SBrian Somers cbcp_Down(&dl->cbcp); 63792b09558SBrian Somers /* fall through (just in case) */ 638e2ebb036SBrian Somers 639e2ebb036SBrian Somers case DATALINK_AUTH: 640dd7e2610SBrian Somers timer_Stop(&dl->pap.authtimer); 641dd7e2610SBrian Somers timer_Stop(&dl->chap.auth.authtimer); 6426d666775SBrian Somers } 6439ae58882SBrian Somers datalink_NewState(dl, DATALINK_LCP); 644e2ebb036SBrian Somers } 6456d666775SBrian Somers } 6466d666775SBrian Somers 6476d666775SBrian Somers static void 6486d666775SBrian Somers datalink_LayerFinish(void *v, struct fsm *fp) 6496d666775SBrian Somers { 6506d666775SBrian Somers /* The given fsm is now down */ 6516d666775SBrian Somers struct datalink *dl = (struct datalink *)v; 6526d666775SBrian Somers 65392e872e7SBrian Somers if (fp->proto == PROTO_LCP) { 65409206a6fSBrian Somers fsm2initial(fp); 6556d666775SBrian Somers (*dl->parent->LayerFinish)(dl->parent->object, fp); 6569c81b87dSBrian Somers datalink_ComeDown(dl, CLOSE_NORMAL); 6570a1b5c9dSBrian Somers } else if (fp->state == ST_CLOSED && fp->open_mode == OPEN_PASSIVE) 6580a1b5c9dSBrian Somers fsm_Open(fp); /* CCP goes to ST_STOPPED */ 6596d666775SBrian Somers } 6606d666775SBrian Somers 6613006ec67SBrian Somers struct datalink * 6626f384573SBrian Somers datalink_Create(const char *name, struct bundle *bundle, int type) 6633006ec67SBrian Somers { 6643006ec67SBrian Somers struct datalink *dl; 6653006ec67SBrian Somers 6663006ec67SBrian Somers dl = (struct datalink *)malloc(sizeof(struct datalink)); 6673006ec67SBrian Somers if (dl == NULL) 6683006ec67SBrian Somers return dl; 6693006ec67SBrian Somers 6703006ec67SBrian Somers dl->desc.type = DATALINK_DESCRIPTOR; 6713006ec67SBrian Somers dl->desc.UpdateSet = datalink_UpdateSet; 6723006ec67SBrian Somers dl->desc.IsSet = datalink_IsSet; 6733006ec67SBrian Somers dl->desc.Read = datalink_Read; 6743006ec67SBrian Somers dl->desc.Write = datalink_Write; 6755b8b8060SBrian Somers 676e718d1d7SBrian Somers dl->state = DATALINK_CLOSED; 677e718d1d7SBrian Somers 67873a13b5cSBrian Somers *dl->cfg.script.dial = '\0'; 67973a13b5cSBrian Somers *dl->cfg.script.login = '\0'; 68073a13b5cSBrian Somers *dl->cfg.script.hangup = '\0'; 681f9545805SBrian Somers *dl->cfg.phone.list = '\0'; 682f9545805SBrian Somers *dl->phone.list = '\0'; 683f9545805SBrian Somers dl->phone.next = NULL; 684f9545805SBrian Somers dl->phone.alt = NULL; 685f9545805SBrian Somers dl->phone.chosen = "N/A"; 6869c81b87dSBrian Somers dl->stayonline = 0; 687c7cc5030SBrian Somers dl->script.run = 1; 688c7cc5030SBrian Somers dl->script.packetmode = 1; 6893b0f8d2eSBrian Somers mp_linkInit(&dl->mp); 6905b8b8060SBrian Somers 6913006ec67SBrian Somers dl->bundle = bundle; 6923006ec67SBrian Somers dl->next = NULL; 693e718d1d7SBrian Somers 6943006ec67SBrian Somers memset(&dl->dial_timer, '\0', sizeof dl->dial_timer); 695e718d1d7SBrian Somers 6963006ec67SBrian Somers dl->dial_tries = 0; 697565e35e5SBrian Somers dl->cfg.dial.max = 1; 698565e35e5SBrian Somers dl->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT; 699565e35e5SBrian Somers dl->cfg.dial.timeout = DIAL_TIMEOUT; 700e718d1d7SBrian Somers 701abff9baeSBrian Somers dl->reconnect_tries = 0; 702565e35e5SBrian Somers dl->cfg.reconnect.max = 0; 703565e35e5SBrian Somers dl->cfg.reconnect.timeout = RECONNECT_TIMEOUT; 704abff9baeSBrian Somers 70592b09558SBrian Somers dl->cfg.callback.opmask = 0; 70692b09558SBrian Somers dl->cfg.cbcp.delay = 0; 70792b09558SBrian Somers *dl->cfg.cbcp.phone = '\0'; 70892b09558SBrian Somers dl->cfg.cbcp.fsmretry = DEF_FSMRETRY; 70992b09558SBrian Somers 7103006ec67SBrian Somers dl->name = strdup(name); 711643f4904SBrian Somers peerid_Init(&dl->peer); 7126f384573SBrian Somers dl->parent = &bundle->fsm; 7133b0f8d2eSBrian Somers dl->fsmp.LayerStart = datalink_LayerStart; 7143b0f8d2eSBrian Somers dl->fsmp.LayerUp = datalink_LayerUp; 7153b0f8d2eSBrian Somers dl->fsmp.LayerDown = datalink_LayerDown; 7163b0f8d2eSBrian Somers dl->fsmp.LayerFinish = datalink_LayerFinish; 7173b0f8d2eSBrian Somers dl->fsmp.object = dl; 7183b0f8d2eSBrian Somers 719dd7e2610SBrian Somers auth_Init(&dl->pap); 720dd7e2610SBrian Somers auth_Init(&dl->chap.auth); 7213b0f8d2eSBrian Somers 722565e35e5SBrian Somers if ((dl->physical = modem_Create(dl, type)) == NULL) { 7233006ec67SBrian Somers free(dl->name); 7243006ec67SBrian Somers free(dl); 7253006ec67SBrian Somers return NULL; 7263006ec67SBrian Somers } 72792b09558SBrian Somers cbcp_Init(&dl->cbcp, dl->physical); 728f9545805SBrian Somers chat_Init(&dl->chat, dl->physical, NULL, 1, NULL); 7293006ec67SBrian Somers 7309ae58882SBrian Somers log_Printf(LogPHASE, "%s: Created in %s state\n", 7319ae58882SBrian Somers dl->name, datalink_State(dl)); 7323006ec67SBrian Somers 7333006ec67SBrian Somers return dl; 7343006ec67SBrian Somers } 7353006ec67SBrian Somers 7363006ec67SBrian Somers struct datalink * 737cd7bd93aSBrian Somers datalink_Clone(struct datalink *odl, const char *name) 738cd7bd93aSBrian Somers { 739cd7bd93aSBrian Somers struct datalink *dl; 740cd7bd93aSBrian Somers 741cd7bd93aSBrian Somers dl = (struct datalink *)malloc(sizeof(struct datalink)); 742cd7bd93aSBrian Somers if (dl == NULL) 743cd7bd93aSBrian Somers return dl; 744cd7bd93aSBrian Somers 745cd7bd93aSBrian Somers dl->desc.type = DATALINK_DESCRIPTOR; 746cd7bd93aSBrian Somers dl->desc.UpdateSet = datalink_UpdateSet; 747cd7bd93aSBrian Somers dl->desc.IsSet = datalink_IsSet; 748cd7bd93aSBrian Somers dl->desc.Read = datalink_Read; 749cd7bd93aSBrian Somers dl->desc.Write = datalink_Write; 750cd7bd93aSBrian Somers 751cd7bd93aSBrian Somers dl->state = DATALINK_CLOSED; 752cd7bd93aSBrian Somers 753cd7bd93aSBrian Somers memcpy(&dl->cfg, &odl->cfg, sizeof dl->cfg); 754cd7bd93aSBrian Somers mp_linkInit(&dl->mp); 755cd7bd93aSBrian Somers *dl->phone.list = '\0'; 756643f4904SBrian Somers dl->phone.next = NULL; 757643f4904SBrian Somers dl->phone.alt = NULL; 758643f4904SBrian Somers dl->phone.chosen = "N/A"; 759cd7bd93aSBrian Somers dl->bundle = odl->bundle; 760cd7bd93aSBrian Somers dl->next = NULL; 761cd7bd93aSBrian Somers memset(&dl->dial_timer, '\0', sizeof dl->dial_timer); 762cd7bd93aSBrian Somers dl->dial_tries = 0; 763cd7bd93aSBrian Somers dl->reconnect_tries = 0; 764cd7bd93aSBrian Somers dl->name = strdup(name); 765643f4904SBrian Somers peerid_Init(&dl->peer); 766cd7bd93aSBrian Somers dl->parent = odl->parent; 767cd7bd93aSBrian Somers memcpy(&dl->fsmp, &odl->fsmp, sizeof dl->fsmp); 768643f4904SBrian Somers dl->fsmp.object = dl; 769dd7e2610SBrian Somers auth_Init(&dl->pap); 770cd7bd93aSBrian Somers dl->pap.cfg.fsmretry = odl->pap.cfg.fsmretry; 771cd7bd93aSBrian Somers 772dd7e2610SBrian Somers auth_Init(&dl->chap.auth); 773cd7bd93aSBrian Somers dl->chap.auth.cfg.fsmretry = odl->chap.auth.cfg.fsmretry; 774cd7bd93aSBrian Somers 77581358fa3SBrian Somers if ((dl->physical = modem_Create(dl, PHYS_INTERACTIVE)) == NULL) { 776cd7bd93aSBrian Somers free(dl->name); 777cd7bd93aSBrian Somers free(dl); 778cd7bd93aSBrian Somers return NULL; 779cd7bd93aSBrian Somers } 780cd7bd93aSBrian Somers memcpy(&dl->physical->cfg, &odl->physical->cfg, sizeof dl->physical->cfg); 781cd7bd93aSBrian Somers memcpy(&dl->physical->link.lcp.cfg, &odl->physical->link.lcp.cfg, 782cd7bd93aSBrian Somers sizeof dl->physical->link.lcp.cfg); 783cd7bd93aSBrian Somers memcpy(&dl->physical->link.ccp.cfg, &odl->physical->link.ccp.cfg, 784cd7bd93aSBrian Somers sizeof dl->physical->link.ccp.cfg); 785cd7bd93aSBrian Somers memcpy(&dl->physical->async.cfg, &odl->physical->async.cfg, 786cd7bd93aSBrian Somers sizeof dl->physical->async.cfg); 787cd7bd93aSBrian Somers 78892b09558SBrian Somers cbcp_Init(&dl->cbcp, dl->physical); 789cd7bd93aSBrian Somers chat_Init(&dl->chat, dl->physical, NULL, 1, NULL); 790cd7bd93aSBrian Somers 7919ae58882SBrian Somers log_Printf(LogPHASE, "%s: Cloned in %s state\n", 7929ae58882SBrian Somers dl->name, datalink_State(dl)); 793cd7bd93aSBrian Somers 794cd7bd93aSBrian Somers return dl; 795cd7bd93aSBrian Somers } 796cd7bd93aSBrian Somers 797cd7bd93aSBrian Somers struct datalink * 7983006ec67SBrian Somers datalink_Destroy(struct datalink *dl) 7993006ec67SBrian Somers { 8003006ec67SBrian Somers struct datalink *result; 8013006ec67SBrian Somers 80239d94652SBrian Somers if (dl->state != DATALINK_CLOSED) { 803dd7e2610SBrian Somers log_Printf(LogERROR, "Oops, destroying a datalink in state %s\n", 804c7cc5030SBrian Somers datalink_State(dl)); 80539d94652SBrian Somers switch (dl->state) { 80639d94652SBrian Somers case DATALINK_HANGUP: 80739d94652SBrian Somers case DATALINK_DIAL: 80839d94652SBrian Somers case DATALINK_LOGIN: 80939d94652SBrian Somers chat_Destroy(&dl->chat); /* Gotta blat the timers ! */ 81039d94652SBrian Somers break; 81139d94652SBrian Somers } 81239d94652SBrian Somers } 8133006ec67SBrian Somers 814f1e8dfb2SBrian Somers timer_Stop(&dl->dial_timer); 8153006ec67SBrian Somers result = dl->next; 8163b0f8d2eSBrian Somers modem_Destroy(dl->physical); 8173006ec67SBrian Somers free(dl->name); 8183006ec67SBrian Somers free(dl); 8193006ec67SBrian Somers 8203006ec67SBrian Somers return result; 8213006ec67SBrian Somers } 8223006ec67SBrian Somers 8233006ec67SBrian Somers void 824c5a5a6caSBrian Somers datalink_Up(struct datalink *dl, int runscripts, int packetmode) 8253006ec67SBrian Somers { 8266f384573SBrian Somers if (dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED)) 827565e35e5SBrian Somers /* Ignore scripts */ 828565e35e5SBrian Somers runscripts = 0; 829565e35e5SBrian Somers 830c7cc5030SBrian Somers switch (dl->state) { 831c7cc5030SBrian Somers case DATALINK_CLOSED: 8323b0f8d2eSBrian Somers if (bundle_Phase(dl->bundle) == PHASE_DEAD || 8333b0f8d2eSBrian Somers bundle_Phase(dl->bundle) == PHASE_TERMINATE) 8343b0f8d2eSBrian Somers bundle_NewPhase(dl->bundle, PHASE_ESTABLISH); 8359ae58882SBrian Somers datalink_NewState(dl, DATALINK_OPENING); 836565e35e5SBrian Somers dl->reconnect_tries = 8376f384573SBrian Somers dl->physical->type == PHYS_DIRECT ? 0 : dl->cfg.reconnect.max; 838565e35e5SBrian Somers dl->dial_tries = dl->cfg.dial.max; 839c5a5a6caSBrian Somers dl->script.run = runscripts; 840c5a5a6caSBrian Somers dl->script.packetmode = packetmode; 841c7cc5030SBrian Somers break; 842c7cc5030SBrian Somers 843c7cc5030SBrian Somers case DATALINK_OPENING: 844c7cc5030SBrian Somers if (!dl->script.run && runscripts) 845c7cc5030SBrian Somers dl->script.run = 1; 846c7cc5030SBrian Somers /* fall through */ 847c7cc5030SBrian Somers 848c7cc5030SBrian Somers case DATALINK_DIAL: 849c7cc5030SBrian Somers case DATALINK_LOGIN: 850c7cc5030SBrian Somers case DATALINK_READY: 851c7cc5030SBrian Somers if (!dl->script.packetmode && packetmode) { 852c7cc5030SBrian Somers dl->script.packetmode = 1; 853c7cc5030SBrian Somers if (dl->state == DATALINK_READY) 854c7cc5030SBrian Somers datalink_LoginDone(dl); 855c7cc5030SBrian Somers } 856c7cc5030SBrian Somers break; 8573006ec67SBrian Somers } 8583006ec67SBrian Somers } 8593006ec67SBrian Somers 8603006ec67SBrian Somers void 8619c81b87dSBrian Somers datalink_Close(struct datalink *dl, int how) 862c7cc5030SBrian Somers { 863c7cc5030SBrian Somers /* Please close */ 864e2ebb036SBrian Somers switch (dl->state) { 865e2ebb036SBrian Somers case DATALINK_OPEN: 866643f4904SBrian Somers peerid_Init(&dl->peer); 86709206a6fSBrian Somers fsm2initial(&dl->physical->link.ccp.fsm); 868e2ebb036SBrian Somers /* fall through */ 869e2ebb036SBrian Somers 87092b09558SBrian Somers case DATALINK_CBCP: 871e2ebb036SBrian Somers case DATALINK_AUTH: 872e2ebb036SBrian Somers case DATALINK_LCP: 873dd7e2610SBrian Somers fsm_Close(&dl->physical->link.lcp.fsm); 8749c81b87dSBrian Somers if (how != CLOSE_NORMAL) { 875c7cc5030SBrian Somers dl->dial_tries = -1; 876c7cc5030SBrian Somers dl->reconnect_tries = 0; 8779c81b87dSBrian Somers if (how == CLOSE_LCP) 8789c81b87dSBrian Somers dl->stayonline = 1; 879c7cc5030SBrian Somers } 880e2ebb036SBrian Somers break; 881e2ebb036SBrian Somers 882e2ebb036SBrian Somers default: 8839c81b87dSBrian Somers datalink_ComeDown(dl, how); 884c7cc5030SBrian Somers } 885e2ebb036SBrian Somers } 886c7cc5030SBrian Somers 887c7cc5030SBrian Somers void 8889c81b87dSBrian Somers datalink_Down(struct datalink *dl, int how) 889c7cc5030SBrian Somers { 890c7cc5030SBrian Somers /* Carrier is lost */ 891e2ebb036SBrian Somers switch (dl->state) { 892e2ebb036SBrian Somers case DATALINK_OPEN: 893643f4904SBrian Somers peerid_Init(&dl->peer); 89409206a6fSBrian Somers fsm2initial(&dl->physical->link.ccp.fsm); 895e2ebb036SBrian Somers /* fall through */ 896e2ebb036SBrian Somers 89792b09558SBrian Somers case DATALINK_CBCP: 898e2ebb036SBrian Somers case DATALINK_AUTH: 899e2ebb036SBrian Somers case DATALINK_LCP: 90009206a6fSBrian Somers fsm2initial(&dl->physical->link.lcp.fsm); 901e2ebb036SBrian Somers /* fall through */ 902c7cc5030SBrian Somers 903e2ebb036SBrian Somers default: 9049c81b87dSBrian Somers datalink_ComeDown(dl, how); 905c7cc5030SBrian Somers } 906e2ebb036SBrian Somers } 907c7cc5030SBrian Somers 908c7cc5030SBrian Somers void 9093006ec67SBrian Somers datalink_StayDown(struct datalink *dl) 9103006ec67SBrian Somers { 9113006ec67SBrian Somers dl->reconnect_tries = 0; 9123006ec67SBrian Somers } 913c7cc5030SBrian Somers 9149c81b87dSBrian Somers void 9159c81b87dSBrian Somers datalink_DontHangup(struct datalink *dl) 9169c81b87dSBrian Somers { 9177729a182SBrian Somers if (dl->state >= DATALINK_LCP) 9189c81b87dSBrian Somers dl->stayonline = 1; 9199c81b87dSBrian Somers } 9209c81b87dSBrian Somers 921643f4904SBrian Somers int 922643f4904SBrian Somers datalink_Show(struct cmdargs const *arg) 923c7cc5030SBrian Somers { 924643f4904SBrian Somers prompt_Printf(arg->prompt, "Name: %s\n", arg->cx->name); 925643f4904SBrian Somers prompt_Printf(arg->prompt, " State: %s\n", 926643f4904SBrian Somers datalink_State(arg->cx)); 927643f4904SBrian Somers prompt_Printf(arg->prompt, " CHAP Encryption: %s\n", 928643f4904SBrian Somers arg->cx->chap.using_MSChap ? "MSChap" : "MD5" ); 929643f4904SBrian Somers prompt_Printf(arg->prompt, " Peer name: "); 930643f4904SBrian Somers if (*arg->cx->peer.authname) 931643f4904SBrian Somers prompt_Printf(arg->prompt, "%s\n", arg->cx->peer.authname); 932643f4904SBrian Somers else if (arg->cx->state == DATALINK_OPEN) 933643f4904SBrian Somers prompt_Printf(arg->prompt, "None requested\n"); 934565e35e5SBrian Somers else 935643f4904SBrian Somers prompt_Printf(arg->prompt, "N/A\n"); 936643f4904SBrian Somers prompt_Printf(arg->prompt, " Discriminator: %s\n", 937643f4904SBrian Somers mp_Enddisc(arg->cx->peer.enddisc.class, 938643f4904SBrian Somers arg->cx->peer.enddisc.address, 939643f4904SBrian Somers arg->cx->peer.enddisc.len)); 940643f4904SBrian Somers 941643f4904SBrian Somers prompt_Printf(arg->prompt, "\nDefaults:\n"); 942643f4904SBrian Somers prompt_Printf(arg->prompt, " Phone List: %s\n", 943643f4904SBrian Somers arg->cx->cfg.phone.list); 944643f4904SBrian Somers if (arg->cx->cfg.dial.max) 945643f4904SBrian Somers prompt_Printf(arg->prompt, " Dial tries: %d, delay ", 946643f4904SBrian Somers arg->cx->cfg.dial.max); 947565e35e5SBrian Somers else 948643f4904SBrian Somers prompt_Printf(arg->prompt, " Dial tries: infinite, delay "); 949643f4904SBrian Somers if (arg->cx->cfg.dial.next_timeout > 0) 950643f4904SBrian Somers prompt_Printf(arg->prompt, "%ds/", arg->cx->cfg.dial.next_timeout); 951565e35e5SBrian Somers else 952643f4904SBrian Somers prompt_Printf(arg->prompt, "random/"); 953643f4904SBrian Somers if (arg->cx->cfg.dial.timeout > 0) 954643f4904SBrian Somers prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.dial.timeout); 955565e35e5SBrian Somers else 956643f4904SBrian Somers prompt_Printf(arg->prompt, "random\n"); 957643f4904SBrian Somers prompt_Printf(arg->prompt, " Reconnect tries: %d, delay ", 958643f4904SBrian Somers arg->cx->cfg.reconnect.max); 959643f4904SBrian Somers if (arg->cx->cfg.reconnect.timeout > 0) 960643f4904SBrian Somers prompt_Printf(arg->prompt, "%ds\n", arg->cx->cfg.reconnect.timeout); 961643f4904SBrian Somers else 962643f4904SBrian Somers prompt_Printf(arg->prompt, "random\n"); 96392b09558SBrian Somers prompt_Printf(arg->prompt, " Callback %s ", arg->cx->physical->type == 96492b09558SBrian Somers PHYS_DIRECT ? "accepted: " : "requested:"); 96592b09558SBrian Somers if (!arg->cx->cfg.callback.opmask) 96692b09558SBrian Somers prompt_Printf(arg->prompt, "none\n"); 96792b09558SBrian Somers else { 96892b09558SBrian Somers int comma = 0; 96992b09558SBrian Somers 97092b09558SBrian Somers if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_NONE)) { 97192b09558SBrian Somers prompt_Printf(arg->prompt, "none"); 97292b09558SBrian Somers comma = 1; 97392b09558SBrian Somers } 97492b09558SBrian Somers if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_AUTH)) { 97592b09558SBrian Somers prompt_Printf(arg->prompt, "%sauth", comma ? ", " : ""); 97692b09558SBrian Somers comma = 1; 97792b09558SBrian Somers } 97892b09558SBrian Somers if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_E164)) { 97992b09558SBrian Somers prompt_Printf(arg->prompt, "%sE.164", comma ? ", " : ""); 98092b09558SBrian Somers if (arg->cx->physical->type != PHYS_DIRECT) 98192b09558SBrian Somers prompt_Printf(arg->prompt, " (%s)", arg->cx->cfg.callback.msg); 98292b09558SBrian Somers comma = 1; 98392b09558SBrian Somers } 98492b09558SBrian Somers if (arg->cx->cfg.callback.opmask & CALLBACK_BIT(CALLBACK_CBCP)) { 98592b09558SBrian Somers prompt_Printf(arg->prompt, "%scbcp\n", comma ? ", " : ""); 98692b09558SBrian Somers prompt_Printf(arg->prompt, " CBCP: delay: %ds\n", 98792b09558SBrian Somers arg->cx->cfg.cbcp.delay); 988cf784a89SBrian Somers prompt_Printf(arg->prompt, " phone: "); 989cf784a89SBrian Somers if (!strcmp(arg->cx->cfg.cbcp.phone, "*")) { 990cf784a89SBrian Somers if (arg->cx->physical->type & PHYS_DIRECT) 991cf784a89SBrian Somers prompt_Printf(arg->prompt, "Caller decides\n"); 992cf784a89SBrian Somers else 993cf784a89SBrian Somers prompt_Printf(arg->prompt, "Dialback server decides\n"); 994cf784a89SBrian Somers } else 995cf784a89SBrian Somers prompt_Printf(arg->prompt, "%s\n", arg->cx->cfg.cbcp.phone); 99692b09558SBrian Somers prompt_Printf(arg->prompt, " timeout: %lds\n", 99792b09558SBrian Somers arg->cx->cfg.cbcp.fsmretry); 99892b09558SBrian Somers } else 99992b09558SBrian Somers prompt_Printf(arg->prompt, "\n"); 100092b09558SBrian Somers } 100192b09558SBrian Somers 1002643f4904SBrian Somers prompt_Printf(arg->prompt, " Dial Script: %s\n", 1003643f4904SBrian Somers arg->cx->cfg.script.dial); 1004643f4904SBrian Somers prompt_Printf(arg->prompt, " Login Script: %s\n", 1005643f4904SBrian Somers arg->cx->cfg.script.login); 1006643f4904SBrian Somers prompt_Printf(arg->prompt, " Hangup Script: %s\n", 1007643f4904SBrian Somers arg->cx->cfg.script.hangup); 1008643f4904SBrian Somers return 0; 1009565e35e5SBrian Somers } 1010565e35e5SBrian Somers 1011565e35e5SBrian Somers int 1012565e35e5SBrian Somers datalink_SetReconnect(struct cmdargs const *arg) 1013565e35e5SBrian Somers { 101425092092SBrian Somers if (arg->argc == arg->argn+2) { 101525092092SBrian Somers arg->cx->cfg.reconnect.timeout = atoi(arg->argv[arg->argn]); 101625092092SBrian Somers arg->cx->cfg.reconnect.max = atoi(arg->argv[arg->argn+1]); 1017565e35e5SBrian Somers return 0; 1018565e35e5SBrian Somers } 1019565e35e5SBrian Somers return -1; 1020565e35e5SBrian Somers } 1021565e35e5SBrian Somers 1022565e35e5SBrian Somers int 1023565e35e5SBrian Somers datalink_SetRedial(struct cmdargs const *arg) 1024565e35e5SBrian Somers { 1025565e35e5SBrian Somers int timeout; 1026565e35e5SBrian Somers int tries; 1027565e35e5SBrian Somers char *dot; 1028565e35e5SBrian Somers 102925092092SBrian Somers if (arg->argc == arg->argn+1 || arg->argc == arg->argn+2) { 103025092092SBrian Somers if (strncasecmp(arg->argv[arg->argn], "random", 6) == 0 && 103125092092SBrian Somers (arg->argv[arg->argn][6] == '\0' || arg->argv[arg->argn][6] == '.')) { 1032565e35e5SBrian Somers arg->cx->cfg.dial.timeout = -1; 1033565e35e5SBrian Somers randinit(); 1034565e35e5SBrian Somers } else { 103525092092SBrian Somers timeout = atoi(arg->argv[arg->argn]); 1036565e35e5SBrian Somers 1037565e35e5SBrian Somers if (timeout >= 0) 1038565e35e5SBrian Somers arg->cx->cfg.dial.timeout = timeout; 1039565e35e5SBrian Somers else { 1040dd7e2610SBrian Somers log_Printf(LogWARN, "Invalid redial timeout\n"); 1041565e35e5SBrian Somers return -1; 1042565e35e5SBrian Somers } 1043565e35e5SBrian Somers } 1044565e35e5SBrian Somers 104525092092SBrian Somers dot = strchr(arg->argv[arg->argn], '.'); 1046565e35e5SBrian Somers if (dot) { 1047565e35e5SBrian Somers if (strcasecmp(++dot, "random") == 0) { 1048565e35e5SBrian Somers arg->cx->cfg.dial.next_timeout = -1; 1049565e35e5SBrian Somers randinit(); 1050565e35e5SBrian Somers } else { 1051565e35e5SBrian Somers timeout = atoi(dot); 1052565e35e5SBrian Somers if (timeout >= 0) 1053565e35e5SBrian Somers arg->cx->cfg.dial.next_timeout = timeout; 1054565e35e5SBrian Somers else { 1055dd7e2610SBrian Somers log_Printf(LogWARN, "Invalid next redial timeout\n"); 1056565e35e5SBrian Somers return -1; 1057565e35e5SBrian Somers } 1058565e35e5SBrian Somers } 1059565e35e5SBrian Somers } else 1060565e35e5SBrian Somers /* Default next timeout */ 1061565e35e5SBrian Somers arg->cx->cfg.dial.next_timeout = DIAL_NEXT_TIMEOUT; 1062565e35e5SBrian Somers 106325092092SBrian Somers if (arg->argc == arg->argn+2) { 106425092092SBrian Somers tries = atoi(arg->argv[arg->argn+1]); 1065565e35e5SBrian Somers 1066565e35e5SBrian Somers if (tries >= 0) { 1067565e35e5SBrian Somers arg->cx->cfg.dial.max = tries; 1068565e35e5SBrian Somers } else { 1069dd7e2610SBrian Somers log_Printf(LogWARN, "Invalid retry value\n"); 1070565e35e5SBrian Somers return 1; 1071565e35e5SBrian Somers } 1072565e35e5SBrian Somers } 1073565e35e5SBrian Somers return 0; 1074565e35e5SBrian Somers } 1075565e35e5SBrian Somers return -1; 1076c7cc5030SBrian Somers } 1077c7cc5030SBrian Somers 1078cdbbb6b5SBrian Somers static const char *states[] = { 1079565e35e5SBrian Somers "closed", 1080565e35e5SBrian Somers "opening", 1081565e35e5SBrian Somers "hangup", 1082565e35e5SBrian Somers "dial", 1083565e35e5SBrian Somers "login", 1084565e35e5SBrian Somers "ready", 1085565e35e5SBrian Somers "lcp", 1086565e35e5SBrian Somers "auth", 108792b09558SBrian Somers "cbcp", 1088565e35e5SBrian Somers "open" 1089c7cc5030SBrian Somers }; 1090c7cc5030SBrian Somers 1091643f4904SBrian Somers const char * 1092c7cc5030SBrian Somers datalink_State(struct datalink *dl) 1093c7cc5030SBrian Somers { 1094c7cc5030SBrian Somers if (dl->state < 0 || dl->state >= sizeof states / sizeof states[0]) 1095c7cc5030SBrian Somers return "unknown"; 1096c7cc5030SBrian Somers return states[dl->state]; 1097c7cc5030SBrian Somers } 10986f384573SBrian Somers 10999ae58882SBrian Somers static void 11009ae58882SBrian Somers datalink_NewState(struct datalink *dl, int state) 11019ae58882SBrian Somers { 11029ae58882SBrian Somers if (state != dl->state) { 11039ae58882SBrian Somers if (state >= 0 && state < sizeof states / sizeof states[0]) { 11049ae58882SBrian Somers log_Printf(LogPHASE, "%s: %s -> %s\n", dl->name, datalink_State(dl), 11059ae58882SBrian Somers states[state]); 11069ae58882SBrian Somers dl->state = state; 11079ae58882SBrian Somers } else 11089ae58882SBrian Somers log_Printf(LogERROR, "%s: Can't enter state %d !\n", dl->name, state); 11099ae58882SBrian Somers } 11109ae58882SBrian Somers } 11119ae58882SBrian Somers 11126f384573SBrian Somers struct datalink * 111396c9bb21SBrian Somers iov2datalink(struct bundle *bundle, struct iovec *iov, int *niov, int maxiov, 111496c9bb21SBrian Somers int fd) 11156f384573SBrian Somers { 1116b7c5748eSBrian Somers struct datalink *dl, *cdl; 11176f384573SBrian Somers u_int retry; 1118b7c5748eSBrian Somers char *oname; 11196f384573SBrian Somers 112096c9bb21SBrian Somers dl = (struct datalink *)iov[(*niov)++].iov_base; 112196c9bb21SBrian Somers dl->name = iov[*niov].iov_base; 11226f384573SBrian Somers 112396c9bb21SBrian Somers if (dl->name[DATALINK_MAXNAME-1]) { 112496c9bb21SBrian Somers dl->name[DATALINK_MAXNAME-1] = '\0'; 112596c9bb21SBrian Somers if (strlen(dl->name) == DATALINK_MAXNAME - 1) 112696c9bb21SBrian Somers log_Printf(LogWARN, "Datalink name truncated to \"%s\"\n", dl->name); 11276f384573SBrian Somers } 1128b7c5748eSBrian Somers 1129b7c5748eSBrian Somers /* Make sure the name is unique ! */ 1130b7c5748eSBrian Somers oname = NULL; 1131b7c5748eSBrian Somers do { 1132b7c5748eSBrian Somers for (cdl = bundle->links; cdl; cdl = cdl->next) 1133b7c5748eSBrian Somers if (!strcasecmp(dl->name, cdl->name)) { 1134b7c5748eSBrian Somers if (oname) 1135b7c5748eSBrian Somers free(datalink_NextName(dl)); 1136b7c5748eSBrian Somers else 1137b7c5748eSBrian Somers oname = datalink_NextName(dl); 1138b7c5748eSBrian Somers break; /* Keep renaming 'till we have no conflicts */ 1139b7c5748eSBrian Somers } 1140b7c5748eSBrian Somers } while (cdl); 1141b7c5748eSBrian Somers 1142b7c5748eSBrian Somers if (oname) { 1143b7c5748eSBrian Somers log_Printf(LogPHASE, "Rename link %s to %s\n", oname, dl->name); 1144b7c5748eSBrian Somers free(oname); 1145b7c5748eSBrian Somers } else { 114696c9bb21SBrian Somers dl->name = strdup(dl->name); 1147b7c5748eSBrian Somers free(iov[*niov].iov_base); 1148b7c5748eSBrian Somers } 1149b7c5748eSBrian Somers (*niov)++; 11506f384573SBrian Somers 11516f384573SBrian Somers dl->desc.type = DATALINK_DESCRIPTOR; 11526f384573SBrian Somers dl->desc.UpdateSet = datalink_UpdateSet; 11536f384573SBrian Somers dl->desc.IsSet = datalink_IsSet; 11546f384573SBrian Somers dl->desc.Read = datalink_Read; 11556f384573SBrian Somers dl->desc.Write = datalink_Write; 11566f384573SBrian Somers 11576f384573SBrian Somers mp_linkInit(&dl->mp); 11586f384573SBrian Somers *dl->phone.list = '\0'; 11596f384573SBrian Somers dl->phone.next = NULL; 11606f384573SBrian Somers dl->phone.alt = NULL; 11616f384573SBrian Somers dl->phone.chosen = "N/A"; 11626f384573SBrian Somers 11636f384573SBrian Somers dl->bundle = bundle; 11646f384573SBrian Somers dl->next = NULL; 11656f384573SBrian Somers memset(&dl->dial_timer, '\0', sizeof dl->dial_timer); 11666f384573SBrian Somers dl->dial_tries = 0; 11676f384573SBrian Somers dl->reconnect_tries = 0; 11686f384573SBrian Somers dl->parent = &bundle->fsm; 11696f384573SBrian Somers dl->fsmp.LayerStart = datalink_LayerStart; 11706f384573SBrian Somers dl->fsmp.LayerUp = datalink_LayerUp; 11716f384573SBrian Somers dl->fsmp.LayerDown = datalink_LayerDown; 11726f384573SBrian Somers dl->fsmp.LayerFinish = datalink_LayerFinish; 11736f384573SBrian Somers dl->fsmp.object = dl; 11746f384573SBrian Somers 11756f384573SBrian Somers retry = dl->pap.cfg.fsmretry; 1176dd7e2610SBrian Somers auth_Init(&dl->pap); 11776f384573SBrian Somers dl->pap.cfg.fsmretry = retry; 11786f384573SBrian Somers 11796f384573SBrian Somers retry = dl->chap.auth.cfg.fsmretry; 1180dd7e2610SBrian Somers auth_Init(&dl->chap.auth); 11816f384573SBrian Somers dl->chap.auth.cfg.fsmretry = retry; 11826f384573SBrian Somers 118396c9bb21SBrian Somers dl->physical = iov2modem(dl, iov, niov, maxiov, fd); 118496c9bb21SBrian Somers 118596c9bb21SBrian Somers if (!dl->physical) { 11866f384573SBrian Somers free(dl->name); 11876f384573SBrian Somers free(dl); 11886f384573SBrian Somers dl = NULL; 11899ae58882SBrian Somers } else { 119092b09558SBrian Somers cbcp_Init(&dl->cbcp, dl->physical); 11916f384573SBrian Somers chat_Init(&dl->chat, dl->physical, NULL, 1, NULL); 11926f384573SBrian Somers 11939ae58882SBrian Somers log_Printf(LogPHASE, "%s: Transferred in %s state\n", 11949ae58882SBrian Somers dl->name, datalink_State(dl)); 11959ae58882SBrian Somers } 11969ae58882SBrian Somers 11976f384573SBrian Somers return dl; 11986f384573SBrian Somers } 11996f384573SBrian Somers 12006f384573SBrian Somers int 120185fd273aSBrian Somers datalink2iov(struct datalink *dl, struct iovec *iov, int *niov, int maxiov, 120285fd273aSBrian Somers pid_t newpid) 12036f384573SBrian Somers { 120496c9bb21SBrian Somers /* If `dl' is NULL, we're allocating before a Fromiov() */ 120596c9bb21SBrian Somers int link_fd; 12066f384573SBrian Somers 120796c9bb21SBrian Somers if (dl) { 1208dd7e2610SBrian Somers timer_Stop(&dl->dial_timer); 120992b09558SBrian Somers /* The following is purely for the sake of paranoia */ 121092b09558SBrian Somers cbcp_Down(&dl->cbcp); 1211dd7e2610SBrian Somers timer_Stop(&dl->pap.authtimer); 1212dd7e2610SBrian Somers timer_Stop(&dl->chap.auth.authtimer); 12136f384573SBrian Somers } 12146f384573SBrian Somers 121596c9bb21SBrian Somers if (*niov >= maxiov - 1) { 121696c9bb21SBrian Somers log_Printf(LogERROR, "Toiov: No room for datalink !\n"); 121796c9bb21SBrian Somers if (dl) { 12186f384573SBrian Somers free(dl->name); 12196f384573SBrian Somers free(dl); 122096c9bb21SBrian Somers } 122196c9bb21SBrian Somers return -1; 122296c9bb21SBrian Somers } 122396c9bb21SBrian Somers 122496c9bb21SBrian Somers iov[*niov].iov_base = dl ? dl : malloc(sizeof *dl); 122596c9bb21SBrian Somers iov[(*niov)++].iov_len = sizeof *dl; 122696c9bb21SBrian Somers iov[*niov].iov_base = 122796c9bb21SBrian Somers dl ? realloc(dl->name, DATALINK_MAXNAME) : malloc(DATALINK_MAXNAME); 122896c9bb21SBrian Somers iov[(*niov)++].iov_len = DATALINK_MAXNAME; 122996c9bb21SBrian Somers 123085fd273aSBrian Somers link_fd = modem2iov(dl ? dl->physical : NULL, iov, niov, maxiov, newpid); 123196c9bb21SBrian Somers 123296c9bb21SBrian Somers if (link_fd == -1 && dl) { 123396c9bb21SBrian Somers free(dl->name); 123496c9bb21SBrian Somers free(dl); 123596c9bb21SBrian Somers } 12366f384573SBrian Somers 12376f384573SBrian Somers return link_fd; 12386f384573SBrian Somers } 12396f384573SBrian Somers 124058d55334SBrian Somers void 124158d55334SBrian Somers datalink_Rename(struct datalink *dl, const char *name) 124258d55334SBrian Somers { 124358d55334SBrian Somers free(dl->name); 124458d55334SBrian Somers dl->physical->link.name = dl->name = strdup(name); 124558d55334SBrian Somers } 124658d55334SBrian Somers 124784917b87SBrian Somers char * 124884917b87SBrian Somers datalink_NextName(struct datalink *dl) 12496f384573SBrian Somers { 12506f384573SBrian Somers int f, n; 125184917b87SBrian Somers char *name, *oname; 12526f384573SBrian Somers 12536f384573SBrian Somers n = strlen(dl->name); 12546f384573SBrian Somers name = (char *)malloc(n+3); 12556f384573SBrian Somers for (f = n - 1; f >= 0; f--) 12566f384573SBrian Somers if (!isdigit(dl->name[f])) 12576f384573SBrian Somers break; 12586f384573SBrian Somers n = sprintf(name, "%.*s-", dl->name[f] == '-' ? f : f + 1, dl->name); 12596f384573SBrian Somers sprintf(name + n, "%d", atoi(dl->name + f + 1) + 1); 126084917b87SBrian Somers oname = dl->name; 126154cd8e13SBrian Somers dl->name = name; 126254cd8e13SBrian Somers /* our physical link name isn't updated (it probably isn't created yet) */ 126384917b87SBrian Somers return oname; 12646f384573SBrian Somers } 1265dd0645c5SBrian Somers 1266dd0645c5SBrian Somers int 1267dd0645c5SBrian Somers datalink_SetMode(struct datalink *dl, int mode) 1268dd0645c5SBrian Somers { 1269dd0645c5SBrian Somers if (!physical_SetMode(dl->physical, mode)) 1270dd0645c5SBrian Somers return 0; 1271dd0645c5SBrian Somers if (dl->physical->type & (PHYS_DIRECT|PHYS_DEDICATED)) 1272dd0645c5SBrian Somers dl->script.run = 0; 1273dd0645c5SBrian Somers if (dl->physical->type == PHYS_DIRECT) 1274dd0645c5SBrian Somers dl->reconnect_tries = 0; 127581358fa3SBrian Somers if (mode & (PHYS_DDIAL|PHYS_BACKGROUND) && dl->state <= DATALINK_READY) 1276dd0645c5SBrian Somers datalink_Up(dl, 1, 1); 1277dd0645c5SBrian Somers return 1; 1278dd0645c5SBrian Somers } 1279